1*60b08185Syz147069 /* 2*60b08185Syz147069 * CDDL HEADER START 3*60b08185Syz147069 * 4*60b08185Syz147069 * The contents of this file are subject to the terms of the 5*60b08185Syz147069 * Common Development and Distribution License, Version 1.0 only 6*60b08185Syz147069 * (the "License"). You may not use this file except in compliance 7*60b08185Syz147069 * with the License. 8*60b08185Syz147069 * 9*60b08185Syz147069 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*60b08185Syz147069 * or http://www.opensolaris.org/os/licensing. 11*60b08185Syz147069 * See the License for the specific language governing permissions 12*60b08185Syz147069 * and limitations under the License. 13*60b08185Syz147069 * 14*60b08185Syz147069 * When distributing Covered Code, include this CDDL HEADER in each 15*60b08185Syz147069 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*60b08185Syz147069 * If applicable, add the following below this CDDL HEADER, with the 17*60b08185Syz147069 * fields enclosed by brackets "[]" replaced with your own identifying 18*60b08185Syz147069 * information: Portions Copyright [yyyy] [name of copyright owner] 19*60b08185Syz147069 * 20*60b08185Syz147069 * CDDL HEADER END 21*60b08185Syz147069 */ 22*60b08185Syz147069 /* 23*60b08185Syz147069 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*60b08185Syz147069 * Use is subject to license terms. 25*60b08185Syz147069 */ 26*60b08185Syz147069 27*60b08185Syz147069 #pragma ident "%Z%%M% %I% %E% SMI" 28*60b08185Syz147069 29*60b08185Syz147069 /* 30*60b08185Syz147069 * 31*60b08185Syz147069 * keyspanport pipe routines (mostly device-neutral) 32*60b08185Syz147069 * 33*60b08185Syz147069 */ 34*60b08185Syz147069 #include <sys/types.h> 35*60b08185Syz147069 #include <sys/param.h> 36*60b08185Syz147069 #include <sys/conf.h> 37*60b08185Syz147069 #include <sys/stream.h> 38*60b08185Syz147069 #include <sys/strsun.h> 39*60b08185Syz147069 #include <sys/termio.h> 40*60b08185Syz147069 #include <sys/ddi.h> 41*60b08185Syz147069 #include <sys/sunddi.h> 42*60b08185Syz147069 43*60b08185Syz147069 #include <sys/usb/usba.h> 44*60b08185Syz147069 #include <sys/usb/clients/usbser/usbser_keyspan/keyspan_var.h> 45*60b08185Syz147069 #include <sys/usb/clients/usbser/usbser_keyspan/keyspan_pipe.h> 46*60b08185Syz147069 47*60b08185Syz147069 /* 48*60b08185Syz147069 * initialize pipe structure with the given parameters 49*60b08185Syz147069 */ 50*60b08185Syz147069 static void 51*60b08185Syz147069 keyspan_init_one_pipe(keyspan_state_t *ksp, keyspan_port_t *kp, 52*60b08185Syz147069 keyspan_pipe_t *pipe) 53*60b08185Syz147069 { 54*60b08185Syz147069 usb_pipe_policy_t *policy; 55*60b08185Syz147069 56*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, "keyspan_init_one_pipe: " 57*60b08185Syz147069 "pipe = %p, pipe_stat %x", (void *)pipe, pipe->pipe_state); 58*60b08185Syz147069 59*60b08185Syz147069 /* init sync primitives */ 60*60b08185Syz147069 mutex_init(&pipe->pipe_mutex, NULL, MUTEX_DRIVER, (void *)NULL); 61*60b08185Syz147069 62*60b08185Syz147069 /* init pipe policy */ 63*60b08185Syz147069 policy = &pipe->pipe_policy; 64*60b08185Syz147069 policy->pp_max_async_reqs = 2; 65*60b08185Syz147069 66*60b08185Syz147069 pipe->pipe_ksp = ksp; 67*60b08185Syz147069 if (kp == NULL) { 68*60b08185Syz147069 /* globle pipes should have device log handle */ 69*60b08185Syz147069 pipe->pipe_lh = ksp->ks_lh; 70*60b08185Syz147069 } else { 71*60b08185Syz147069 /* port pipes should have port log handle */ 72*60b08185Syz147069 pipe->pipe_lh = kp->kp_lh; 73*60b08185Syz147069 } 74*60b08185Syz147069 75*60b08185Syz147069 pipe->pipe_state = KEYSPAN_PIPE_CLOSED; 76*60b08185Syz147069 } 77*60b08185Syz147069 78*60b08185Syz147069 79*60b08185Syz147069 static void 80*60b08185Syz147069 keyspan_fini_one_pipe(keyspan_pipe_t *pipe) 81*60b08185Syz147069 { 82*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_OPEN, pipe->pipe_ksp->ks_lh, 83*60b08185Syz147069 "keyspan_fini_one_pipe: pipe_stat %x", pipe->pipe_state); 84*60b08185Syz147069 85*60b08185Syz147069 if (pipe->pipe_state != KEYSPAN_PIPE_NOT_INIT) { 86*60b08185Syz147069 mutex_destroy(&pipe->pipe_mutex); 87*60b08185Syz147069 pipe->pipe_state = KEYSPAN_PIPE_NOT_INIT; 88*60b08185Syz147069 } 89*60b08185Syz147069 } 90*60b08185Syz147069 91*60b08185Syz147069 /* 92*60b08185Syz147069 * Lookup the endpoints defined in the spec; 93*60b08185Syz147069 * Allocate resources, initialize pipe structures. 94*60b08185Syz147069 * All are bulk pipes, including data in/out, cmd/status pipes. 95*60b08185Syz147069 */ 96*60b08185Syz147069 int 97*60b08185Syz147069 keyspan_init_pipes(keyspan_state_t *ksp) 98*60b08185Syz147069 { 99*60b08185Syz147069 usb_client_dev_data_t *dev_data = ksp->ks_dev_data; 100*60b08185Syz147069 int ifc, alt, i, j, k = 0; 101*60b08185Syz147069 uint8_t port_cnt = ksp->ks_dev_spec.port_cnt; 102*60b08185Syz147069 uint8_t ep_addr, ep_cnt; 103*60b08185Syz147069 usb_ep_data_t *dataout[KEYSPAN_MAX_PORT_NUM], 104*60b08185Syz147069 *datain[KEYSPAN_MAX_PORT_NUM], 105*60b08185Syz147069 *status = NULL, *ctrl = NULL, *tmp_ep; 106*60b08185Syz147069 usb_alt_if_data_t *alt_data; 107*60b08185Syz147069 usb_if_data_t *if_data; 108*60b08185Syz147069 109*60b08185Syz147069 110*60b08185Syz147069 ifc = dev_data->dev_curr_if; 111*60b08185Syz147069 alt = 0; 112*60b08185Syz147069 if_data = &dev_data->dev_curr_cfg->cfg_if[ifc]; 113*60b08185Syz147069 alt_data = &if_data->if_alt[alt]; 114*60b08185Syz147069 115*60b08185Syz147069 /* 116*60b08185Syz147069 * The actual EP number (indicated by bNumEndpoints) is more than 117*60b08185Syz147069 * those defined in spec. We have to match those we need according 118*60b08185Syz147069 * to EP addresses. And we'll lookup In EPs and Out EPs separately. 119*60b08185Syz147069 */ 120*60b08185Syz147069 ep_cnt = (alt_data->altif_descr.bNumEndpoints + 1) / 2; 121*60b08185Syz147069 122*60b08185Syz147069 /* 123*60b08185Syz147069 * get DIR_IN EP descriptors, and then match with EP addresses. 124*60b08185Syz147069 * Different keyspan devices may has different EP addresses. 125*60b08185Syz147069 */ 126*60b08185Syz147069 for (i = 0; i < ep_cnt; i++) { 127*60b08185Syz147069 tmp_ep = usb_lookup_ep_data(ksp->ks_dip, dev_data, ifc, alt, i, 128*60b08185Syz147069 USB_EP_ATTR_BULK, USB_EP_DIR_IN); 129*60b08185Syz147069 if (tmp_ep == NULL) { 130*60b08185Syz147069 USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh, 131*60b08185Syz147069 "keyspan_init_pipes: can't find bulk in ep, i=%d," 132*60b08185Syz147069 "ep_cnt=%d", i, ep_cnt); 133*60b08185Syz147069 134*60b08185Syz147069 continue; 135*60b08185Syz147069 } 136*60b08185Syz147069 ep_addr = tmp_ep->ep_descr.bEndpointAddress; 137*60b08185Syz147069 138*60b08185Syz147069 USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh, "keyspan_init_pipes: " 139*60b08185Syz147069 "ep_addr =%x, stat_ep_addr=%x, i=%d", ep_addr, 140*60b08185Syz147069 ksp->ks_dev_spec.stat_ep_addr, i); 141*60b08185Syz147069 142*60b08185Syz147069 /* match the status EP */ 143*60b08185Syz147069 if (ep_addr == ksp->ks_dev_spec.stat_ep_addr) { 144*60b08185Syz147069 status = tmp_ep; 145*60b08185Syz147069 146*60b08185Syz147069 continue; 147*60b08185Syz147069 } 148*60b08185Syz147069 149*60b08185Syz147069 /* match the EPs of the ports */ 150*60b08185Syz147069 for (j = 0; j < port_cnt; j++) { 151*60b08185Syz147069 USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh, 152*60b08185Syz147069 "keyspan_init_pipes: try to match bulk in data ep," 153*60b08185Syz147069 " j=%d", j); 154*60b08185Syz147069 if (ep_addr == ksp->ks_dev_spec.datain_ep_addr[j]) { 155*60b08185Syz147069 datain[j] = tmp_ep; 156*60b08185Syz147069 k++; 157*60b08185Syz147069 USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh, 158*60b08185Syz147069 "keyspan_init_pipes: matched a bulk in" 159*60b08185Syz147069 " data ep"); 160*60b08185Syz147069 161*60b08185Syz147069 break; 162*60b08185Syz147069 } 163*60b08185Syz147069 } 164*60b08185Syz147069 165*60b08185Syz147069 /* if have matched all the necessary endpoints, break out */ 166*60b08185Syz147069 if (k >= port_cnt && status != NULL) { 167*60b08185Syz147069 168*60b08185Syz147069 break; 169*60b08185Syz147069 } 170*60b08185Syz147069 171*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_ATTACH, ksp->ks_lh, "keyspan_init_pipes: " 172*60b08185Syz147069 "try to match bulk in data ep, j=%d", j); 173*60b08185Syz147069 174*60b08185Syz147069 if (j == port_cnt) { 175*60b08185Syz147069 /* this ep can't be matched by any addr */ 176*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_ATTACH, ksp->ks_lh, 177*60b08185Syz147069 "keyspan_init_pipes: can't match bulk in ep," 178*60b08185Syz147069 " addr =%x,", ep_addr); 179*60b08185Syz147069 } 180*60b08185Syz147069 } 181*60b08185Syz147069 182*60b08185Syz147069 if (k != port_cnt || status == NULL) { 183*60b08185Syz147069 184*60b08185Syz147069 /* Some of the necessary IN endpoints are not matched */ 185*60b08185Syz147069 USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh, 186*60b08185Syz147069 "keyspan_init_pipes: matched %d data in endpoints," 187*60b08185Syz147069 " not enough", k); 188*60b08185Syz147069 189*60b08185Syz147069 return (USB_FAILURE); 190*60b08185Syz147069 } 191*60b08185Syz147069 192*60b08185Syz147069 k = 0; 193*60b08185Syz147069 194*60b08185Syz147069 /* 195*60b08185Syz147069 * get DIR_OUT EP descriptors, and then match with ep addrs. 196*60b08185Syz147069 * different keyspan devices may has different ep addresses. 197*60b08185Syz147069 */ 198*60b08185Syz147069 for (i = 0; i < ep_cnt; i++) { 199*60b08185Syz147069 tmp_ep = usb_lookup_ep_data(ksp->ks_dip, dev_data, ifc, alt, i, 200*60b08185Syz147069 USB_EP_ATTR_BULK, USB_EP_DIR_OUT); 201*60b08185Syz147069 if (tmp_ep == NULL) { 202*60b08185Syz147069 USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh, 203*60b08185Syz147069 "keyspan_init_pipes: can't find bulk out ep, i=%d," 204*60b08185Syz147069 "ep_cnt=%d", i, ep_cnt); 205*60b08185Syz147069 206*60b08185Syz147069 continue; 207*60b08185Syz147069 } 208*60b08185Syz147069 ep_addr = tmp_ep->ep_descr.bEndpointAddress; 209*60b08185Syz147069 210*60b08185Syz147069 /* match the status ep */ 211*60b08185Syz147069 if (ep_addr == ksp->ks_dev_spec.ctrl_ep_addr) { 212*60b08185Syz147069 ctrl = tmp_ep; 213*60b08185Syz147069 214*60b08185Syz147069 continue; 215*60b08185Syz147069 } 216*60b08185Syz147069 217*60b08185Syz147069 /* match the ep of the ports */ 218*60b08185Syz147069 for (j = 0; j < port_cnt; j++) { 219*60b08185Syz147069 if (ep_addr == ksp->ks_dev_spec.dataout_ep_addr[j]) { 220*60b08185Syz147069 dataout[j] = tmp_ep; 221*60b08185Syz147069 k++; 222*60b08185Syz147069 223*60b08185Syz147069 break; 224*60b08185Syz147069 } 225*60b08185Syz147069 } 226*60b08185Syz147069 /* if have matched all the necessary endpoints, break out */ 227*60b08185Syz147069 if (k >= port_cnt && ctrl != NULL) { 228*60b08185Syz147069 229*60b08185Syz147069 break; 230*60b08185Syz147069 } 231*60b08185Syz147069 232*60b08185Syz147069 if (j == port_cnt) { 233*60b08185Syz147069 234*60b08185Syz147069 /* this ep can't be matched by any addr */ 235*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_ATTACH, ksp->ks_lh, 236*60b08185Syz147069 "keyspan_init_pipes: can't match bulk out ep," 237*60b08185Syz147069 " ep_addr =%x", ep_addr); 238*60b08185Syz147069 239*60b08185Syz147069 } 240*60b08185Syz147069 } 241*60b08185Syz147069 242*60b08185Syz147069 if (k != port_cnt || ctrl == NULL) { 243*60b08185Syz147069 /* Not all the necessary OUT endpoints are matched */ 244*60b08185Syz147069 USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh, 245*60b08185Syz147069 "keyspan_init_pipes: matched %d data in endpoints," 246*60b08185Syz147069 " not enough", k); 247*60b08185Syz147069 248*60b08185Syz147069 return (USB_FAILURE); 249*60b08185Syz147069 } 250*60b08185Syz147069 251*60b08185Syz147069 mutex_enter(&ksp->ks_mutex); 252*60b08185Syz147069 253*60b08185Syz147069 /* 254*60b08185Syz147069 * Device globle pipes: a bulk in pipe for status and a bulk out 255*60b08185Syz147069 * pipe for controle cmd. 256*60b08185Syz147069 */ 257*60b08185Syz147069 ksp->ks_statin_pipe.pipe_ep_descr = status->ep_descr; 258*60b08185Syz147069 keyspan_init_one_pipe(ksp, NULL, &ksp->ks_statin_pipe); 259*60b08185Syz147069 260*60b08185Syz147069 ksp->ks_ctrlout_pipe.pipe_ep_descr = ctrl->ep_descr; 261*60b08185Syz147069 keyspan_init_one_pipe(ksp, NULL, &ksp->ks_ctrlout_pipe); 262*60b08185Syz147069 263*60b08185Syz147069 /* for data in/out pipes of each port */ 264*60b08185Syz147069 for (i = 0; i < port_cnt; i++) { 265*60b08185Syz147069 266*60b08185Syz147069 ksp->ks_ports[i].kp_datain_pipe.pipe_ep_descr = 267*60b08185Syz147069 datain[i]->ep_descr; 268*60b08185Syz147069 keyspan_init_one_pipe(ksp, &ksp->ks_ports[i], 269*60b08185Syz147069 &ksp->ks_ports[i].kp_datain_pipe); 270*60b08185Syz147069 271*60b08185Syz147069 ksp->ks_ports[i].kp_dataout_pipe.pipe_ep_descr = 272*60b08185Syz147069 dataout[i]->ep_descr; 273*60b08185Syz147069 keyspan_init_one_pipe(ksp, &ksp->ks_ports[i], 274*60b08185Syz147069 &ksp->ks_ports[i].kp_dataout_pipe); 275*60b08185Syz147069 } 276*60b08185Syz147069 277*60b08185Syz147069 mutex_exit(&ksp->ks_mutex); 278*60b08185Syz147069 279*60b08185Syz147069 return (USB_SUCCESS); 280*60b08185Syz147069 } 281*60b08185Syz147069 282*60b08185Syz147069 void 283*60b08185Syz147069 keyspan_fini_pipes(keyspan_state_t *ksp) 284*60b08185Syz147069 { 285*60b08185Syz147069 keyspan_port_t *kp; 286*60b08185Syz147069 int i; 287*60b08185Syz147069 288*60b08185Syz147069 for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) { 289*60b08185Syz147069 kp = &ksp->ks_ports[i]; 290*60b08185Syz147069 keyspan_fini_one_pipe(&kp->kp_datain_pipe); 291*60b08185Syz147069 keyspan_fini_one_pipe(&kp->kp_dataout_pipe); 292*60b08185Syz147069 } 293*60b08185Syz147069 294*60b08185Syz147069 /* fini global pipes */ 295*60b08185Syz147069 keyspan_fini_one_pipe(&ksp->ks_statin_pipe); 296*60b08185Syz147069 keyspan_fini_one_pipe(&ksp->ks_ctrlout_pipe); 297*60b08185Syz147069 } 298*60b08185Syz147069 299*60b08185Syz147069 300*60b08185Syz147069 static int 301*60b08185Syz147069 keyspan_open_one_pipe(keyspan_state_t *ksp, keyspan_pipe_t *pipe) 302*60b08185Syz147069 { 303*60b08185Syz147069 int rval; 304*60b08185Syz147069 305*60b08185Syz147069 /* don't open for the second time */ 306*60b08185Syz147069 mutex_enter(&pipe->pipe_mutex); 307*60b08185Syz147069 ASSERT(pipe->pipe_state != KEYSPAN_PIPE_NOT_INIT); 308*60b08185Syz147069 if (pipe->pipe_state != KEYSPAN_PIPE_CLOSED) { 309*60b08185Syz147069 mutex_exit(&pipe->pipe_mutex); 310*60b08185Syz147069 311*60b08185Syz147069 return (USB_SUCCESS); 312*60b08185Syz147069 } 313*60b08185Syz147069 mutex_exit(&pipe->pipe_mutex); 314*60b08185Syz147069 315*60b08185Syz147069 rval = usb_pipe_open(ksp->ks_dip, &pipe->pipe_ep_descr, 316*60b08185Syz147069 &pipe->pipe_policy, USB_FLAGS_SLEEP, &pipe->pipe_handle); 317*60b08185Syz147069 318*60b08185Syz147069 if (rval == USB_SUCCESS) { 319*60b08185Syz147069 mutex_enter(&pipe->pipe_mutex); 320*60b08185Syz147069 pipe->pipe_state = KEYSPAN_PIPE_OPEN; 321*60b08185Syz147069 mutex_exit(&pipe->pipe_mutex); 322*60b08185Syz147069 } 323*60b08185Syz147069 324*60b08185Syz147069 return (rval); 325*60b08185Syz147069 } 326*60b08185Syz147069 327*60b08185Syz147069 328*60b08185Syz147069 /* 329*60b08185Syz147069 * close one pipe if open 330*60b08185Syz147069 */ 331*60b08185Syz147069 static void 332*60b08185Syz147069 keyspan_close_one_pipe(keyspan_pipe_t *pipe) 333*60b08185Syz147069 { 334*60b08185Syz147069 /* 335*60b08185Syz147069 * pipe may already be closed, e.g. if device has been physically 336*60b08185Syz147069 * disconnected and the driver immediately detached 337*60b08185Syz147069 */ 338*60b08185Syz147069 if (pipe->pipe_handle != NULL) { 339*60b08185Syz147069 usb_pipe_close(pipe->pipe_ksp->ks_dip, pipe->pipe_handle, 340*60b08185Syz147069 USB_FLAGS_SLEEP, NULL, NULL); 341*60b08185Syz147069 mutex_enter(&pipe->pipe_mutex); 342*60b08185Syz147069 pipe->pipe_handle = NULL; 343*60b08185Syz147069 pipe->pipe_state = KEYSPAN_PIPE_CLOSED; 344*60b08185Syz147069 mutex_exit(&pipe->pipe_mutex); 345*60b08185Syz147069 } 346*60b08185Syz147069 } 347*60b08185Syz147069 348*60b08185Syz147069 /* 349*60b08185Syz147069 * Open global pipes, a status pipe and a control pipe 350*60b08185Syz147069 */ 351*60b08185Syz147069 int 352*60b08185Syz147069 keyspan_open_dev_pipes(keyspan_state_t *ksp) 353*60b08185Syz147069 { 354*60b08185Syz147069 int rval; 355*60b08185Syz147069 356*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, "keyspan_open_dev_pipes"); 357*60b08185Syz147069 358*60b08185Syz147069 rval = keyspan_open_one_pipe(ksp, &ksp->ks_ctrlout_pipe); 359*60b08185Syz147069 if (rval != USB_SUCCESS) { 360*60b08185Syz147069 USB_DPRINTF_L2(DPRINT_OPEN, ksp->ks_lh, 361*60b08185Syz147069 "keyspan_open_dev_pipes: open ctrl pipe failed %d", rval); 362*60b08185Syz147069 363*60b08185Syz147069 return (rval); 364*60b08185Syz147069 } 365*60b08185Syz147069 366*60b08185Syz147069 rval = keyspan_open_one_pipe(ksp, &ksp->ks_statin_pipe); 367*60b08185Syz147069 if (rval != USB_SUCCESS) { 368*60b08185Syz147069 USB_DPRINTF_L2(DPRINT_OPEN, ksp->ks_lh, 369*60b08185Syz147069 "keyspan_open_dev_pipes: open status pipe failed %d", rval); 370*60b08185Syz147069 371*60b08185Syz147069 /* close the first opened pipe here */ 372*60b08185Syz147069 keyspan_close_one_pipe(&ksp->ks_ctrlout_pipe); 373*60b08185Syz147069 374*60b08185Syz147069 return (rval); 375*60b08185Syz147069 } 376*60b08185Syz147069 377*60b08185Syz147069 /* start receive device status */ 378*60b08185Syz147069 rval = keyspan_receive_status(ksp); 379*60b08185Syz147069 if (rval != USB_SUCCESS) { 380*60b08185Syz147069 USB_DPRINTF_L2(DPRINT_OPEN, ksp->ks_lh, 381*60b08185Syz147069 "keyspan_open_dev_pipes: receive device status failed %d", 382*60b08185Syz147069 rval); 383*60b08185Syz147069 384*60b08185Syz147069 /* close opened pipes here */ 385*60b08185Syz147069 keyspan_close_one_pipe(&ksp->ks_statin_pipe); 386*60b08185Syz147069 keyspan_close_one_pipe(&ksp->ks_ctrlout_pipe); 387*60b08185Syz147069 388*60b08185Syz147069 return (rval); 389*60b08185Syz147069 } 390*60b08185Syz147069 391*60b08185Syz147069 return (rval); 392*60b08185Syz147069 } 393*60b08185Syz147069 394*60b08185Syz147069 395*60b08185Syz147069 /* 396*60b08185Syz147069 * Reopen all pipes if the port had them open 397*60b08185Syz147069 */ 398*60b08185Syz147069 int 399*60b08185Syz147069 keyspan_reopen_pipes(keyspan_state_t *ksp) 400*60b08185Syz147069 { 401*60b08185Syz147069 keyspan_port_t *kp; 402*60b08185Syz147069 int i; 403*60b08185Syz147069 404*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, "keyspan_reopen_pipes"); 405*60b08185Syz147069 406*60b08185Syz147069 if (keyspan_open_dev_pipes(ksp) != USB_SUCCESS) { 407*60b08185Syz147069 408*60b08185Syz147069 return (USB_FAILURE); 409*60b08185Syz147069 } 410*60b08185Syz147069 411*60b08185Syz147069 for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) { 412*60b08185Syz147069 kp = &ksp->ks_ports[i]; 413*60b08185Syz147069 mutex_enter(&kp->kp_mutex); 414*60b08185Syz147069 if (kp->kp_state == KEYSPAN_PORT_OPEN) { 415*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, 416*60b08185Syz147069 "keyspan_reopen_pipes() reopen pipe #%d", i); 417*60b08185Syz147069 mutex_exit(&kp->kp_mutex); 418*60b08185Syz147069 if (keyspan_open_port_pipes(kp) != USB_SUCCESS) { 419*60b08185Syz147069 420*60b08185Syz147069 return (USB_FAILURE); 421*60b08185Syz147069 } 422*60b08185Syz147069 mutex_enter(&kp->kp_mutex); 423*60b08185Syz147069 kp->kp_no_more_reads = B_FALSE; 424*60b08185Syz147069 } 425*60b08185Syz147069 mutex_exit(&kp->kp_mutex); 426*60b08185Syz147069 } 427*60b08185Syz147069 428*60b08185Syz147069 return (USB_SUCCESS); 429*60b08185Syz147069 } 430*60b08185Syz147069 431*60b08185Syz147069 void 432*60b08185Syz147069 keyspan_close_port_pipes(keyspan_port_t *kp) 433*60b08185Syz147069 { 434*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_CLOSE, kp->kp_lh, "keyspan_close_port_pipes"); 435*60b08185Syz147069 436*60b08185Syz147069 keyspan_close_one_pipe(&kp->kp_dataout_pipe); 437*60b08185Syz147069 keyspan_close_one_pipe(&kp->kp_datain_pipe); 438*60b08185Syz147069 } 439*60b08185Syz147069 440*60b08185Syz147069 /* 441*60b08185Syz147069 * Close IN and OUT bulk pipes of all ports 442*60b08185Syz147069 */ 443*60b08185Syz147069 void 444*60b08185Syz147069 keyspan_close_open_pipes(keyspan_state_t *ksp) 445*60b08185Syz147069 { 446*60b08185Syz147069 keyspan_port_t *kp; 447*60b08185Syz147069 int i; 448*60b08185Syz147069 449*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_CLOSE, ksp->ks_lh, "keyspan_close_open_pipes"); 450*60b08185Syz147069 451*60b08185Syz147069 for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) { 452*60b08185Syz147069 kp = &ksp->ks_ports[i]; 453*60b08185Syz147069 mutex_enter(&kp->kp_mutex); 454*60b08185Syz147069 if (kp->kp_state == KEYSPAN_PORT_OPEN) { 455*60b08185Syz147069 kp->kp_no_more_reads = B_TRUE; 456*60b08185Syz147069 mutex_exit(&kp->kp_mutex); 457*60b08185Syz147069 usb_pipe_reset(ksp->ks_dip, 458*60b08185Syz147069 kp->kp_datain_pipe.pipe_handle, USB_FLAGS_SLEEP, 459*60b08185Syz147069 NULL, NULL); 460*60b08185Syz147069 keyspan_close_port_pipes(kp); 461*60b08185Syz147069 } else { 462*60b08185Syz147069 mutex_exit(&kp->kp_mutex); 463*60b08185Syz147069 } 464*60b08185Syz147069 } 465*60b08185Syz147069 } 466*60b08185Syz147069 467*60b08185Syz147069 468*60b08185Syz147069 /* 469*60b08185Syz147069 * Close global pipes 470*60b08185Syz147069 */ 471*60b08185Syz147069 void 472*60b08185Syz147069 keyspan_close_dev_pipes(keyspan_state_t *ksp) 473*60b08185Syz147069 { 474*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_CLOSE, ksp->ks_lh, "keyspan_close_dev_pipes"); 475*60b08185Syz147069 476*60b08185Syz147069 keyspan_close_one_pipe(&ksp->ks_statin_pipe); 477*60b08185Syz147069 keyspan_close_one_pipe(&ksp->ks_ctrlout_pipe); 478*60b08185Syz147069 } 479*60b08185Syz147069 480*60b08185Syz147069 481*60b08185Syz147069 /* 482*60b08185Syz147069 * Open bulk data IN and data OUT pipes for one port. 483*60b08185Syz147069 * The status and control pipes are opened in attach because they are global. 484*60b08185Syz147069 */ 485*60b08185Syz147069 int 486*60b08185Syz147069 keyspan_open_port_pipes(keyspan_port_t *kp) 487*60b08185Syz147069 { 488*60b08185Syz147069 keyspan_state_t *ksp = kp->kp_ksp; 489*60b08185Syz147069 int rval; 490*60b08185Syz147069 491*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_OPEN, kp->kp_lh, "keyspan_open_port_pipes"); 492*60b08185Syz147069 493*60b08185Syz147069 rval = keyspan_open_one_pipe(ksp, &kp->kp_datain_pipe); 494*60b08185Syz147069 if (rval != USB_SUCCESS) { 495*60b08185Syz147069 496*60b08185Syz147069 goto fail; 497*60b08185Syz147069 } 498*60b08185Syz147069 499*60b08185Syz147069 rval = keyspan_open_one_pipe(ksp, &kp->kp_dataout_pipe); 500*60b08185Syz147069 if (rval != USB_SUCCESS) { 501*60b08185Syz147069 502*60b08185Syz147069 goto fail; 503*60b08185Syz147069 } 504*60b08185Syz147069 505*60b08185Syz147069 return (rval); 506*60b08185Syz147069 507*60b08185Syz147069 fail: 508*60b08185Syz147069 USB_DPRINTF_L2(DPRINT_OPEN, kp->kp_lh, 509*60b08185Syz147069 "keyspan_open_port_pipes: failed %d", rval); 510*60b08185Syz147069 keyspan_close_port_pipes(kp); 511*60b08185Syz147069 512*60b08185Syz147069 return (rval); 513*60b08185Syz147069 } 514*60b08185Syz147069 515*60b08185Syz147069 void 516*60b08185Syz147069 keyspan_close_pipes(keyspan_state_t *ksp) 517*60b08185Syz147069 { 518*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, "keyspan_close_pipes"); 519*60b08185Syz147069 520*60b08185Syz147069 /* close all ports' pipes first, and then device ctrl/status pipes. */ 521*60b08185Syz147069 keyspan_close_open_pipes(ksp); 522*60b08185Syz147069 keyspan_close_dev_pipes(ksp); 523*60b08185Syz147069 524*60b08185Syz147069 } 525*60b08185Syz147069 526*60b08185Syz147069 527*60b08185Syz147069 /* 528*60b08185Syz147069 * bulk out common callback 529*60b08185Syz147069 */ 530*60b08185Syz147069 /*ARGSUSED*/ 531*60b08185Syz147069 void 532*60b08185Syz147069 keyspan_bulkout_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 533*60b08185Syz147069 { 534*60b08185Syz147069 keyspan_port_t *kp = (keyspan_port_t *)req->bulk_client_private; 535*60b08185Syz147069 keyspan_pipe_t *bulkout = &kp->kp_dataout_pipe; 536*60b08185Syz147069 mblk_t *data = req->bulk_data; 537*60b08185Syz147069 int data_len; 538*60b08185Syz147069 539*60b08185Syz147069 data_len = (data) ? MBLKL(data) : 0; 540*60b08185Syz147069 541*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_OUT_PIPE, bulkout->pipe_lh, 542*60b08185Syz147069 "keyspan_bulkout_cb: len=%d cr=%d cb_flags=%x", 543*60b08185Syz147069 data_len, req->bulk_completion_reason, req->bulk_cb_flags); 544*60b08185Syz147069 545*60b08185Syz147069 if (req->bulk_completion_reason && (data_len > 0)) { 546*60b08185Syz147069 547*60b08185Syz147069 /* 548*60b08185Syz147069 * Data wasn't transfered successfully. 549*60b08185Syz147069 * Put data back on the queue. 550*60b08185Syz147069 */ 551*60b08185Syz147069 keyspan_put_head(&kp->kp_tx_mp, data, kp); 552*60b08185Syz147069 553*60b08185Syz147069 /* don't release mem in usb_free_bulk_req */ 554*60b08185Syz147069 req->bulk_data = NULL; 555*60b08185Syz147069 } 556*60b08185Syz147069 557*60b08185Syz147069 usb_free_bulk_req(req); 558*60b08185Syz147069 559*60b08185Syz147069 /* if more data available, kick off another transmit */ 560*60b08185Syz147069 mutex_enter(&kp->kp_mutex); 561*60b08185Syz147069 if (kp->kp_tx_mp == NULL) { 562*60b08185Syz147069 563*60b08185Syz147069 /* no more data, notify waiters */ 564*60b08185Syz147069 cv_broadcast(&kp->kp_tx_cv); 565*60b08185Syz147069 mutex_exit(&kp->kp_mutex); 566*60b08185Syz147069 567*60b08185Syz147069 /* tx callback for this port */ 568*60b08185Syz147069 kp->kp_cb.cb_tx(kp->kp_cb.cb_arg); 569*60b08185Syz147069 } else { 570*60b08185Syz147069 keyspan_tx_start(kp, NULL); 571*60b08185Syz147069 mutex_exit(&kp->kp_mutex); 572*60b08185Syz147069 } 573*60b08185Syz147069 } 574*60b08185Syz147069 575*60b08185Syz147069 /* 576*60b08185Syz147069 * pipe callbacks 577*60b08185Syz147069 * -------------- 578*60b08185Syz147069 * 579*60b08185Syz147069 * bulk in common callback for usa19hs model 580*60b08185Syz147069 */ 581*60b08185Syz147069 /*ARGSUSED*/ 582*60b08185Syz147069 int 583*60b08185Syz147069 keyspan_bulkin_cb_usa19hs(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 584*60b08185Syz147069 { 585*60b08185Syz147069 keyspan_port_t *kp = (keyspan_port_t *)req->bulk_client_private; 586*60b08185Syz147069 keyspan_pipe_t *bulkin = &kp->kp_datain_pipe; 587*60b08185Syz147069 mblk_t *data = req->bulk_data; 588*60b08185Syz147069 uint_t cr = req->bulk_completion_reason; 589*60b08185Syz147069 int data_len; 590*60b08185Syz147069 591*60b08185Syz147069 ASSERT(mutex_owned(&kp->kp_mutex)); 592*60b08185Syz147069 593*60b08185Syz147069 data_len = (data) ? MBLKL(data) : 0; 594*60b08185Syz147069 595*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 596*60b08185Syz147069 "keyspan_bulkin_cb_usa19hs: len=%d" 597*60b08185Syz147069 " cr=%d flags=%x baud=%x", 598*60b08185Syz147069 data_len, cr, req->bulk_cb_flags, kp->kp_baud); 599*60b08185Syz147069 600*60b08185Syz147069 /* put data on the read queue */ 601*60b08185Syz147069 if ((data_len > 0) && (kp->kp_state != KEYSPAN_PORT_CLOSED) && 602*60b08185Syz147069 (cr == USB_CR_OK)) { 603*60b08185Syz147069 604*60b08185Syz147069 /* 605*60b08185Syz147069 * According to Keyspan spec, if 0x80 bit set, the data 606*60b08185Syz147069 * buf contains alternate status and data bytes; 607*60b08185Syz147069 * if 0x80 bit is clear, then there are no status bytes, 608*60b08185Syz147069 * so we put tail to send up data. 609*60b08185Syz147069 */ 610*60b08185Syz147069 if ((data->b_rptr[0] & 0x80) == 0) { 611*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 612*60b08185Syz147069 "keyspan_bulkin_cb_usa19hs: len=%d", 613*60b08185Syz147069 data_len); 614*60b08185Syz147069 615*60b08185Syz147069 data->b_rptr++; 616*60b08185Syz147069 data_len--; 617*60b08185Syz147069 if (data_len > 0) { 618*60b08185Syz147069 keyspan_put_tail(&kp->kp_rx_mp, data); 619*60b08185Syz147069 620*60b08185Syz147069 /* 621*60b08185Syz147069 * the data will not be freed and 622*60b08185Syz147069 * will be sent up later. 623*60b08185Syz147069 */ 624*60b08185Syz147069 req->bulk_data = NULL; 625*60b08185Syz147069 } 626*60b08185Syz147069 } else { /* there might be some errs in the data */ 627*60b08185Syz147069 628*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 629*60b08185Syz147069 "keyspan_bulkin_cb_usa19hs:" 630*60b08185Syz147069 " err in the data, len=%d", 631*60b08185Syz147069 data_len); 632*60b08185Syz147069 633*60b08185Syz147069 if (data_len > 1) { 634*60b08185Syz147069 int i = 0; 635*60b08185Syz147069 int j = 1; 636*60b08185Syz147069 637*60b08185Syz147069 /* get rid of status bytes. */ 638*60b08185Syz147069 for (j = 1; j < data_len; j += 2) { 639*60b08185Syz147069 data->b_rptr[i] = data->b_rptr[j]; 640*60b08185Syz147069 i++; 641*60b08185Syz147069 } 642*60b08185Syz147069 data->b_wptr = data->b_rptr + i; 643*60b08185Syz147069 keyspan_put_tail(&kp->kp_rx_mp, data); 644*60b08185Syz147069 645*60b08185Syz147069 /* 646*60b08185Syz147069 * The data will not be freed and 647*60b08185Syz147069 * will be sent up later. 648*60b08185Syz147069 */ 649*60b08185Syz147069 req->bulk_data = NULL; 650*60b08185Syz147069 } else { 651*60b08185Syz147069 /* 652*60b08185Syz147069 * When zero len returned, no data will 653*60b08185Syz147069 * be sent up and the data buf will be 654*60b08185Syz147069 * just freed. 655*60b08185Syz147069 */ 656*60b08185Syz147069 data_len = 0; 657*60b08185Syz147069 } 658*60b08185Syz147069 } 659*60b08185Syz147069 660*60b08185Syz147069 } else { 661*60b08185Syz147069 662*60b08185Syz147069 /* usb error happened, so don't send up data */ 663*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 664*60b08185Syz147069 "keyspan_bulkin_cb_usa19hs: error happened, len=%d, " 665*60b08185Syz147069 "cr=0x%x, cb_flags=0x%x", data_len, cr, req->bulk_cb_flags); 666*60b08185Syz147069 667*60b08185Syz147069 data_len = 0; 668*60b08185Syz147069 if (kp->kp_state != KEYSPAN_PORT_OPEN) { 669*60b08185Syz147069 kp->kp_no_more_reads = B_TRUE; 670*60b08185Syz147069 } 671*60b08185Syz147069 } 672*60b08185Syz147069 673*60b08185Syz147069 return (data_len); 674*60b08185Syz147069 } 675*60b08185Syz147069 676*60b08185Syz147069 #ifdef KEYSPAN_USA49WLC 677*60b08185Syz147069 /* 678*60b08185Syz147069 * pipe callbacks 679*60b08185Syz147069 * -------------- 680*60b08185Syz147069 * 681*60b08185Syz147069 * bulk in common callback for usa49 model 682*60b08185Syz147069 */ 683*60b08185Syz147069 /*ARGSUSED*/ 684*60b08185Syz147069 int 685*60b08185Syz147069 keyspan_bulkin_cb_usa49(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 686*60b08185Syz147069 { 687*60b08185Syz147069 keyspan_port_t *kp = (keyspan_port_t *)req->bulk_client_private; 688*60b08185Syz147069 keyspan_pipe_t *bulkin = &kp->kp_datain_pipe; 689*60b08185Syz147069 mblk_t *data = req->bulk_data; 690*60b08185Syz147069 uint_t cr = req->bulk_completion_reason; 691*60b08185Syz147069 int data_len; 692*60b08185Syz147069 693*60b08185Syz147069 ASSERT(mutex_owned(&kp->kp_mutex)); 694*60b08185Syz147069 695*60b08185Syz147069 data_len = (data) ? MBLKL(data) : 0; 696*60b08185Syz147069 697*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 698*60b08185Syz147069 "keyspan_bulkin_cb_usa49: len=%d" 699*60b08185Syz147069 " cr=%d flags=%x", data_len, cr, req->bulk_cb_flags); 700*60b08185Syz147069 701*60b08185Syz147069 /* put data on the read queue */ 702*60b08185Syz147069 if ((data_len > 0) && (kp->kp_state != KEYSPAN_PORT_CLOSED) && 703*60b08185Syz147069 (cr == USB_CR_OK)) { 704*60b08185Syz147069 705*60b08185Syz147069 /* 706*60b08185Syz147069 * According to Keyspan spec, if 0x80 bit set, the data 707*60b08185Syz147069 * buf contains alternate status and data bytes; 708*60b08185Syz147069 * if 0x80 bit is clear, then there are no status bytes, 709*60b08185Syz147069 * so we put tail to send up data. 710*60b08185Syz147069 */ 711*60b08185Syz147069 if ((data->b_rptr[0] & 0x80) == 0) { 712*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 713*60b08185Syz147069 "keyspan_bulkin_cb_usa49: len=%d" 714*60b08185Syz147069 "cr=%d", data_len, cr); 715*60b08185Syz147069 716*60b08185Syz147069 data->b_rptr++; 717*60b08185Syz147069 data_len--; 718*60b08185Syz147069 if (data_len > 0) { 719*60b08185Syz147069 keyspan_put_tail(&kp->kp_rx_mp, data); 720*60b08185Syz147069 721*60b08185Syz147069 /* 722*60b08185Syz147069 * The data will not be freed and 723*60b08185Syz147069 * will be sent up later. 724*60b08185Syz147069 */ 725*60b08185Syz147069 req->bulk_data = NULL; 726*60b08185Syz147069 } 727*60b08185Syz147069 } else { 728*60b08185Syz147069 if (data_len > 1) { 729*60b08185Syz147069 int i = 0; 730*60b08185Syz147069 int j = 1; 731*60b08185Syz147069 732*60b08185Syz147069 /* get rid of the status bytes in the data. */ 733*60b08185Syz147069 for (j = 1; j < data_len; j += 2) { 734*60b08185Syz147069 data->b_rptr[i] = data->b_rptr[j]; 735*60b08185Syz147069 i++; 736*60b08185Syz147069 } 737*60b08185Syz147069 data->b_wptr = data->b_rptr + i; 738*60b08185Syz147069 keyspan_put_tail(&kp->kp_rx_mp, data); 739*60b08185Syz147069 740*60b08185Syz147069 /* 741*60b08185Syz147069 * The data will not be freed and 742*60b08185Syz147069 * will be sent up later. 743*60b08185Syz147069 */ 744*60b08185Syz147069 req->bulk_data = NULL; 745*60b08185Syz147069 } else { 746*60b08185Syz147069 /* 747*60b08185Syz147069 * When zero len returned, no data will be sent 748*60b08185Syz147069 * up and the data buf will be just freed. 749*60b08185Syz147069 */ 750*60b08185Syz147069 data_len = 0; 751*60b08185Syz147069 } 752*60b08185Syz147069 } 753*60b08185Syz147069 } else { 754*60b08185Syz147069 755*60b08185Syz147069 /* usb error happened, so don't send up data */ 756*60b08185Syz147069 data_len = 0; 757*60b08185Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh, 758*60b08185Syz147069 "keyspan_bulkin_cb_usa49: port_state=%d" 759*60b08185Syz147069 " b_rptr[0]=%c", kp->kp_state, data->b_rptr[0]); 760*60b08185Syz147069 761*60b08185Syz147069 if (kp->kp_state != KEYSPAN_PORT_OPEN) { 762*60b08185Syz147069 kp->kp_no_more_reads = B_TRUE; 763*60b08185Syz147069 } 764*60b08185Syz147069 } 765*60b08185Syz147069 766*60b08185Syz147069 return (data_len); 767*60b08185Syz147069 } 768*60b08185Syz147069 #endif /* If KEYSPAN_USA49WLC defined */ 769*60b08185Syz147069 770*60b08185Syz147069 /* 771*60b08185Syz147069 * pipe callbacks 772*60b08185Syz147069 * -------------- 773*60b08185Syz147069 * 774*60b08185Syz147069 * bulk in common callback 775*60b08185Syz147069 */ 776*60b08185Syz147069 /*ARGSUSED*/ 777*60b08185Syz147069 void 778*60b08185Syz147069 keyspan_bulkin_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 779*60b08185Syz147069 { 780*60b08185Syz147069 keyspan_port_t *kp = (keyspan_port_t *)req->bulk_client_private; 781*60b08185Syz147069 keyspan_state_t *ksp = kp->kp_ksp; 782*60b08185Syz147069 int data_len; 783*60b08185Syz147069 boolean_t no_more_reads = B_FALSE; 784*60b08185Syz147069 785*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, (&kp->kp_datain_pipe)->pipe_lh, 786*60b08185Syz147069 "keyspan_bulkin_cb"); 787*60b08185Syz147069 788*60b08185Syz147069 mutex_enter(&kp->kp_mutex); 789*60b08185Syz147069 790*60b08185Syz147069 /* put data on the read queue */ 791*60b08185Syz147069 switch (ksp->ks_dev_spec.id_product) { 792*60b08185Syz147069 case KEYSPAN_USA19HS_PID: 793*60b08185Syz147069 data_len = keyspan_bulkin_cb_usa19hs(pipe, req); 794*60b08185Syz147069 795*60b08185Syz147069 break; 796*60b08185Syz147069 797*60b08185Syz147069 #ifdef KEYSPAN_USA49WLC 798*60b08185Syz147069 case KEYSPAN_USA49WLC_PID: 799*60b08185Syz147069 data_len = keyspan_bulkin_cb_usa49(pipe, req); 800*60b08185Syz147069 801*60b08185Syz147069 break; 802*60b08185Syz147069 #endif /* If KEYSPAN_USA49WLC defined */ 803*60b08185Syz147069 default: 804*60b08185Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, (&kp->kp_datain_pipe)->pipe_lh, 805*60b08185Syz147069 "keyspan_bulkin_cb:" 806*60b08185Syz147069 "the device's product id can't be recognized"); 807*60b08185Syz147069 mutex_exit(&kp->kp_mutex); 808*60b08185Syz147069 809*60b08185Syz147069 return; 810*60b08185Syz147069 } 811*60b08185Syz147069 812*60b08185Syz147069 no_more_reads = kp->kp_no_more_reads; 813*60b08185Syz147069 814*60b08185Syz147069 mutex_exit(&kp->kp_mutex); 815*60b08185Syz147069 816*60b08185Syz147069 usb_free_bulk_req(req); 817*60b08185Syz147069 818*60b08185Syz147069 /* kick off another read unless indicated otherwise */ 819*60b08185Syz147069 if (!no_more_reads) { 820*60b08185Syz147069 (void) keyspan_receive_data(&kp->kp_datain_pipe, 821*60b08185Syz147069 kp->kp_read_len, kp); 822*60b08185Syz147069 } 823*60b08185Syz147069 824*60b08185Syz147069 /* setup rx callback for this port */ 825*60b08185Syz147069 if (data_len > 0) { 826*60b08185Syz147069 kp->kp_cb.cb_rx(kp->kp_cb.cb_arg); 827*60b08185Syz147069 } 828*60b08185Syz147069 } 829*60b08185Syz147069 830*60b08185Syz147069 /* 831*60b08185Syz147069 * pipe callbacks 832*60b08185Syz147069 * -------------- 833*60b08185Syz147069 * 834*60b08185Syz147069 * bulk in status callback for usa19hs model 835*60b08185Syz147069 */ 836*60b08185Syz147069 /*ARGSUSED*/ 837*60b08185Syz147069 void 838*60b08185Syz147069 keyspan_status_cb_usa19hs(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 839*60b08185Syz147069 { 840*60b08185Syz147069 keyspan_state_t *ksp = (keyspan_state_t *)req->bulk_client_private; 841*60b08185Syz147069 keyspan_pipe_t *bulkin = &ksp->ks_statin_pipe; 842*60b08185Syz147069 mblk_t *data = req->bulk_data; 843*60b08185Syz147069 usb_cr_t cr = req->bulk_completion_reason; 844*60b08185Syz147069 int data_len; 845*60b08185Syz147069 846*60b08185Syz147069 data_len = (data) ? MBLKL(data) : 0; 847*60b08185Syz147069 848*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 849*60b08185Syz147069 "keyspan_status_cb_usa19hs: len=%d" 850*60b08185Syz147069 " cr=%d flags=%x", data_len, cr, req->bulk_cb_flags); 851*60b08185Syz147069 852*60b08185Syz147069 /* put data on the read queue */ 853*60b08185Syz147069 if ((data_len == 14) && (cr == USB_CR_OK)) { 854*60b08185Syz147069 keyspan_port_t *kp = &ksp->ks_ports[0]; 855*60b08185Syz147069 keyspan_usa19hs_port_status_msg_t *status_msg = 856*60b08185Syz147069 &(kp->kp_status_msg.usa19hs); 857*60b08185Syz147069 858*60b08185Syz147069 mutex_enter(&kp->kp_mutex); 859*60b08185Syz147069 bcopy(data->b_rptr, status_msg, data_len); 860*60b08185Syz147069 861*60b08185Syz147069 if (status_msg->controlResponse) { 862*60b08185Syz147069 kp->kp_status_flag |= KEYSPAN_PORT_CTRLRESP; 863*60b08185Syz147069 } else { 864*60b08185Syz147069 kp->kp_status_flag &= ~KEYSPAN_PORT_CTRLRESP; 865*60b08185Syz147069 } 866*60b08185Syz147069 867*60b08185Syz147069 if (status_msg->portState & PORTSTATE_ENABLED) { 868*60b08185Syz147069 kp->kp_status_flag |= KEYSPAN_PORT_ENABLE; 869*60b08185Syz147069 } else { 870*60b08185Syz147069 kp->kp_status_flag &= ~KEYSPAN_PORT_ENABLE; 871*60b08185Syz147069 } 872*60b08185Syz147069 873*60b08185Syz147069 if (status_msg->portState & PORTSTATE_TXBREAK) { 874*60b08185Syz147069 kp->kp_status_flag |= KEYSPAN_PORT_TXBREAK; 875*60b08185Syz147069 } else { 876*60b08185Syz147069 kp->kp_status_flag &= ~KEYSPAN_PORT_TXBREAK; 877*60b08185Syz147069 } 878*60b08185Syz147069 879*60b08185Syz147069 if (status_msg->rxBreak) { 880*60b08185Syz147069 kp->kp_status_flag |= KEYSPAN_PORT_RXBREAK; 881*60b08185Syz147069 } else { 882*60b08185Syz147069 kp->kp_status_flag &= ~KEYSPAN_PORT_RXBREAK; 883*60b08185Syz147069 } 884*60b08185Syz147069 885*60b08185Syz147069 if (status_msg->portState & PORTSTATE_LOOPBACK) { 886*60b08185Syz147069 kp->kp_status_flag |= KEYSPAN_PORT_LOOPBACK; 887*60b08185Syz147069 } else { 888*60b08185Syz147069 kp->kp_status_flag &= ~KEYSPAN_PORT_LOOPBACK; 889*60b08185Syz147069 } 890*60b08185Syz147069 891*60b08185Syz147069 /* if msr status changed, then invoke status callback */ 892*60b08185Syz147069 if (status_msg->msr & USA_MSR_dCTS || 893*60b08185Syz147069 status_msg->msr & USA_MSR_dDSR || 894*60b08185Syz147069 status_msg->msr & USA_MSR_dRI || 895*60b08185Syz147069 status_msg->msr & USA_MSR_dDCD) { 896*60b08185Syz147069 897*60b08185Syz147069 mutex_exit(&kp->kp_mutex); 898*60b08185Syz147069 kp->kp_cb.cb_status(kp->kp_cb.cb_arg); 899*60b08185Syz147069 } else { 900*60b08185Syz147069 mutex_exit(&kp->kp_mutex); 901*60b08185Syz147069 } 902*60b08185Syz147069 } else { 903*60b08185Syz147069 904*60b08185Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh, 905*60b08185Syz147069 "keyspan_status_cb_usa19hs: get status failed, cr=%d" 906*60b08185Syz147069 " data_len=%d", cr, data_len); 907*60b08185Syz147069 } 908*60b08185Syz147069 } 909*60b08185Syz147069 910*60b08185Syz147069 #ifdef KEYSPAN_USA49WLC 911*60b08185Syz147069 /* 912*60b08185Syz147069 * pipe callbacks 913*60b08185Syz147069 * -------------- 914*60b08185Syz147069 * 915*60b08185Syz147069 * bulk in status callback for usa49 model 916*60b08185Syz147069 */ 917*60b08185Syz147069 /*ARGSUSED*/ 918*60b08185Syz147069 void 919*60b08185Syz147069 keyspan_status_cb_usa49(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 920*60b08185Syz147069 { 921*60b08185Syz147069 keyspan_state_t *ksp = (keyspan_state_t *)req->bulk_client_private; 922*60b08185Syz147069 keyspan_pipe_t *bulkin = &ksp->ks_statin_pipe; 923*60b08185Syz147069 mblk_t *data = req->bulk_data; 924*60b08185Syz147069 uint_t cr = req->bulk_completion_reason; 925*60b08185Syz147069 int data_len; 926*60b08185Syz147069 927*60b08185Syz147069 data_len = (data) ? MBLKL(data) : 0; 928*60b08185Syz147069 929*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 930*60b08185Syz147069 "keyspan_status_cb_usa49: len=%d" 931*60b08185Syz147069 " cr=%d flags=%x", data_len, cr, req->bulk_cb_flags); 932*60b08185Syz147069 933*60b08185Syz147069 /* put data on the read queue */ 934*60b08185Syz147069 if ((data_len == 11) && (cr == USB_CR_OK)) { 935*60b08185Syz147069 keyspan_usa49_port_status_msg_t status_msg; 936*60b08185Syz147069 keyspan_port_t *cur_kp; 937*60b08185Syz147069 keyspan_usa49_port_status_msg_t *kp_status_msg; 938*60b08185Syz147069 boolean_t need_cb = B_FALSE; 939*60b08185Syz147069 940*60b08185Syz147069 bcopy(data->b_rptr, &status_msg, data_len); 941*60b08185Syz147069 if (status_msg.portNumber >= ksp->ks_dev_spec.port_cnt) { 942*60b08185Syz147069 943*60b08185Syz147069 return; 944*60b08185Syz147069 } 945*60b08185Syz147069 cur_kp = &ksp->ks_ports[status_msg.portNumber]; 946*60b08185Syz147069 kp_status_msg = &(cur_kp->kp_status_msg.usa49); 947*60b08185Syz147069 948*60b08185Syz147069 mutex_enter(&cur_kp->kp_mutex); 949*60b08185Syz147069 950*60b08185Syz147069 /* if msr status changed, then need invoke status callback */ 951*60b08185Syz147069 if (status_msg.cts != kp_status_msg->cts || 952*60b08185Syz147069 status_msg.dsr != kp_status_msg->dsr || 953*60b08185Syz147069 status_msg.ri != kp_status_msg->ri || 954*60b08185Syz147069 status_msg.dcd != kp_status_msg->dcd) { 955*60b08185Syz147069 956*60b08185Syz147069 need_cb = B_TRUE; 957*60b08185Syz147069 } 958*60b08185Syz147069 959*60b08185Syz147069 bcopy(&status_msg, kp_status_msg, data_len); 960*60b08185Syz147069 961*60b08185Syz147069 if (kp_status_msg->controlResponse) { 962*60b08185Syz147069 cur_kp->kp_status_flag |= KEYSPAN_PORT_CTRLRESP; 963*60b08185Syz147069 } else { 964*60b08185Syz147069 cur_kp->kp_status_flag &= ~KEYSPAN_PORT_CTRLRESP; 965*60b08185Syz147069 } 966*60b08185Syz147069 967*60b08185Syz147069 if (!kp_status_msg->rxEnabled) { 968*60b08185Syz147069 cur_kp->kp_status_flag |= KEYSPAN_PORT_RXBREAK; 969*60b08185Syz147069 } else { 970*60b08185Syz147069 cur_kp->kp_status_flag &= ~KEYSPAN_PORT_RXBREAK; 971*60b08185Syz147069 } 972*60b08185Syz147069 973*60b08185Syz147069 mutex_exit(&cur_kp->kp_mutex); 974*60b08185Syz147069 975*60b08185Syz147069 if (need_cb) { 976*60b08185Syz147069 977*60b08185Syz147069 cur_kp->kp_cb.cb_status(cur_kp->kp_cb.cb_arg); 978*60b08185Syz147069 } 979*60b08185Syz147069 } else { 980*60b08185Syz147069 981*60b08185Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh, 982*60b08185Syz147069 "keyspan_status_cb_usa49: get status failed, cr=%d" 983*60b08185Syz147069 " data_len=%d", cr, data_len); 984*60b08185Syz147069 } 985*60b08185Syz147069 } 986*60b08185Syz147069 #endif /* If KEYSPAN_USA49WLC defined */ 987*60b08185Syz147069 988*60b08185Syz147069 /* 989*60b08185Syz147069 * pipe callbacks 990*60b08185Syz147069 * -------------- 991*60b08185Syz147069 * 992*60b08185Syz147069 * bulk in callback for status receiving 993*60b08185Syz147069 */ 994*60b08185Syz147069 /*ARGSUSED*/ 995*60b08185Syz147069 void 996*60b08185Syz147069 keyspan_status_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 997*60b08185Syz147069 { 998*60b08185Syz147069 keyspan_state_t *ksp = (keyspan_state_t *)req->bulk_client_private; 999*60b08185Syz147069 usb_cr_t cr = req->bulk_completion_reason; 1000*60b08185Syz147069 1001*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, (&ksp->ks_statin_pipe)->pipe_lh, 1002*60b08185Syz147069 "keyspan_status_cb"); 1003*60b08185Syz147069 1004*60b08185Syz147069 /* put data on the read queue */ 1005*60b08185Syz147069 switch (ksp->ks_dev_spec.id_product) { 1006*60b08185Syz147069 case KEYSPAN_USA19HS_PID: 1007*60b08185Syz147069 keyspan_status_cb_usa19hs(pipe, req); 1008*60b08185Syz147069 1009*60b08185Syz147069 break; 1010*60b08185Syz147069 1011*60b08185Syz147069 #ifdef KEYSPAN_USA49WLC 1012*60b08185Syz147069 case KEYSPAN_USA49WLC_PID: 1013*60b08185Syz147069 keyspan_status_cb_usa49(pipe, req); 1014*60b08185Syz147069 1015*60b08185Syz147069 break; 1016*60b08185Syz147069 #endif /* If KEYSPAN_USA49WLC defined */ 1017*60b08185Syz147069 default: 1018*60b08185Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, 1019*60b08185Syz147069 (&ksp->ks_statin_pipe)->pipe_lh, "keyspan_status_cb:" 1020*60b08185Syz147069 "the device's product id can't be recognized"); 1021*60b08185Syz147069 1022*60b08185Syz147069 return; 1023*60b08185Syz147069 } 1024*60b08185Syz147069 1025*60b08185Syz147069 usb_free_bulk_req(req); 1026*60b08185Syz147069 1027*60b08185Syz147069 /* kick off another read to receive status */ 1028*60b08185Syz147069 if ((cr != USB_CR_FLUSHED) && (cr != USB_CR_DEV_NOT_RESP) && 1029*60b08185Syz147069 keyspan_dev_is_online(ksp)) { 1030*60b08185Syz147069 if (keyspan_receive_status(ksp) != USB_SUCCESS) { 1031*60b08185Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, 1032*60b08185Syz147069 (&ksp->ks_statin_pipe)->pipe_lh, 1033*60b08185Syz147069 "keyspan_status_cb:" 1034*60b08185Syz147069 "receive status can't be restarted."); 1035*60b08185Syz147069 } 1036*60b08185Syz147069 } else { 1037*60b08185Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, 1038*60b08185Syz147069 (&ksp->ks_statin_pipe)->pipe_lh, "keyspan_status_cb:" 1039*60b08185Syz147069 "get status failed: cr=%d", cr); 1040*60b08185Syz147069 } 1041*60b08185Syz147069 } 1042*60b08185Syz147069 1043*60b08185Syz147069 /* 1044*60b08185Syz147069 * Submit data read request (asynchronous). If this function returns 1045*60b08185Syz147069 * USB_SUCCESS, pipe is acquired and request is sent, otherwise req is free. 1046*60b08185Syz147069 */ 1047*60b08185Syz147069 int 1048*60b08185Syz147069 keyspan_receive_data(keyspan_pipe_t *bulkin, int len, void *cb_arg) 1049*60b08185Syz147069 { 1050*60b08185Syz147069 keyspan_state_t *ksp = bulkin->pipe_ksp; 1051*60b08185Syz147069 usb_bulk_req_t *br; 1052*60b08185Syz147069 int rval; 1053*60b08185Syz147069 1054*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, "keyspan_receive_data:" 1055*60b08185Syz147069 "len=%d", len); 1056*60b08185Syz147069 1057*60b08185Syz147069 ASSERT(!mutex_owned(&bulkin->pipe_mutex)); 1058*60b08185Syz147069 1059*60b08185Syz147069 br = usb_alloc_bulk_req(ksp->ks_dip, len, USB_FLAGS_SLEEP); 1060*60b08185Syz147069 br->bulk_len = len; 1061*60b08185Syz147069 1062*60b08185Syz147069 /* No timeout, just wait for data */ 1063*60b08185Syz147069 br->bulk_timeout = 0; 1064*60b08185Syz147069 br->bulk_client_private = cb_arg; 1065*60b08185Syz147069 br->bulk_attributes = USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING; 1066*60b08185Syz147069 br->bulk_cb = keyspan_bulkin_cb; 1067*60b08185Syz147069 br->bulk_exc_cb = keyspan_bulkin_cb; 1068*60b08185Syz147069 1069*60b08185Syz147069 rval = usb_pipe_bulk_xfer(bulkin->pipe_handle, br, 0); 1070*60b08185Syz147069 if (rval != USB_SUCCESS) { 1071*60b08185Syz147069 usb_free_bulk_req(br); 1072*60b08185Syz147069 } 1073*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 1074*60b08185Syz147069 "keyspan_receive_data: rval = %d", rval); 1075*60b08185Syz147069 return (rval); 1076*60b08185Syz147069 } 1077*60b08185Syz147069 1078*60b08185Syz147069 /* 1079*60b08185Syz147069 * submit device status read request (asynchronous). 1080*60b08185Syz147069 */ 1081*60b08185Syz147069 int 1082*60b08185Syz147069 keyspan_receive_status(keyspan_state_t *ksp) 1083*60b08185Syz147069 { 1084*60b08185Syz147069 keyspan_pipe_t *bulkin = &ksp->ks_statin_pipe; 1085*60b08185Syz147069 usb_bulk_req_t *br; 1086*60b08185Syz147069 int rval; 1087*60b08185Syz147069 1088*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 1089*60b08185Syz147069 "keyspan_receive_status"); 1090*60b08185Syz147069 1091*60b08185Syz147069 ASSERT(!mutex_owned(&bulkin->pipe_mutex)); 1092*60b08185Syz147069 1093*60b08185Syz147069 br = usb_alloc_bulk_req(ksp->ks_dip, 32, USB_FLAGS_SLEEP); 1094*60b08185Syz147069 br->bulk_len = KEYSPAN_STATIN_MAX_LEN; 1095*60b08185Syz147069 1096*60b08185Syz147069 /* No timeout, just wait for data */ 1097*60b08185Syz147069 br->bulk_timeout = 0; 1098*60b08185Syz147069 br->bulk_client_private = (void *)ksp; 1099*60b08185Syz147069 br->bulk_attributes = USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING; 1100*60b08185Syz147069 br->bulk_cb = keyspan_status_cb; 1101*60b08185Syz147069 br->bulk_exc_cb = keyspan_status_cb; 1102*60b08185Syz147069 1103*60b08185Syz147069 rval = usb_pipe_bulk_xfer(bulkin->pipe_handle, br, 0); 1104*60b08185Syz147069 if (rval != USB_SUCCESS) { 1105*60b08185Syz147069 usb_free_bulk_req(br); 1106*60b08185Syz147069 } 1107*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 1108*60b08185Syz147069 "keyspan_receive_status: rval = %d", rval); 1109*60b08185Syz147069 return (rval); 1110*60b08185Syz147069 } 1111*60b08185Syz147069 1112*60b08185Syz147069 /* 1113*60b08185Syz147069 * submit data for transfer (asynchronous) 1114*60b08185Syz147069 * 1115*60b08185Syz147069 * if data was sent successfully, 'mpp' will be nulled to indicate 1116*60b08185Syz147069 * that mblk is consumed by USBA and no longer belongs to the caller. 1117*60b08185Syz147069 * 1118*60b08185Syz147069 * if this function returns USB_SUCCESS, pipe is acquired and request 1119*60b08185Syz147069 * is sent, otherwise pipe is free. 1120*60b08185Syz147069 */ 1121*60b08185Syz147069 int 1122*60b08185Syz147069 keyspan_send_data(keyspan_pipe_t *bulkout, mblk_t **mpp, void *cb_arg) 1123*60b08185Syz147069 { 1124*60b08185Syz147069 keyspan_state_t *ksp = bulkout->pipe_ksp; 1125*60b08185Syz147069 usb_bulk_req_t *br; 1126*60b08185Syz147069 int rval; 1127*60b08185Syz147069 1128*60b08185Syz147069 ASSERT(!mutex_owned(&bulkout->pipe_mutex)); 1129*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_OUT_PIPE, bulkout->pipe_lh, 1130*60b08185Syz147069 "keyspan_send_data"); 1131*60b08185Syz147069 1132*60b08185Syz147069 br = usb_alloc_bulk_req(ksp->ks_dip, 0, USB_FLAGS_SLEEP); 1133*60b08185Syz147069 br->bulk_len = MBLKL(*mpp); 1134*60b08185Syz147069 br->bulk_data = *mpp; 1135*60b08185Syz147069 br->bulk_timeout = KEYSPAN_BULK_TIMEOUT; 1136*60b08185Syz147069 br->bulk_client_private = cb_arg; 1137*60b08185Syz147069 br->bulk_attributes = USB_ATTRS_AUTOCLEARING; 1138*60b08185Syz147069 br->bulk_cb = keyspan_bulkout_cb; 1139*60b08185Syz147069 br->bulk_exc_cb = keyspan_bulkout_cb; 1140*60b08185Syz147069 1141*60b08185Syz147069 USB_DPRINTF_L3(DPRINT_OUT_PIPE, bulkout->pipe_lh, "keyspan_send_data:" 1142*60b08185Syz147069 "bulk_len = %d", br->bulk_len); 1143*60b08185Syz147069 1144*60b08185Syz147069 rval = usb_pipe_bulk_xfer(bulkout->pipe_handle, br, 0); 1145*60b08185Syz147069 if (rval == USB_SUCCESS) { 1146*60b08185Syz147069 1147*60b08185Syz147069 /* data consumed. The mem will be released in bulkout_cb */ 1148*60b08185Syz147069 *mpp = NULL; 1149*60b08185Syz147069 } else { 1150*60b08185Syz147069 1151*60b08185Syz147069 /* 1152*60b08185Syz147069 * Don't free it in usb_free_bulk_req because it will 1153*60b08185Syz147069 * be linked in keyspan_put_head 1154*60b08185Syz147069 */ 1155*60b08185Syz147069 br->bulk_data = NULL; 1156*60b08185Syz147069 1157*60b08185Syz147069 usb_free_bulk_req(br); 1158*60b08185Syz147069 } 1159*60b08185Syz147069 USB_DPRINTF_L4(DPRINT_OUT_PIPE, bulkout->pipe_lh, 1160*60b08185Syz147069 "keyspan_send_data: rval = %d", rval); 1161*60b08185Syz147069 1162*60b08185Syz147069 return (rval); 1163*60b08185Syz147069 } 1164