160b08185Syz147069 /* 260b08185Syz147069 * CDDL HEADER START 360b08185Syz147069 * 460b08185Syz147069 * The contents of this file are subject to the terms of the 5688b07c5Sgc161489 * Common Development and Distribution License (the "License"). 6688b07c5Sgc161489 * You may not use this file except in compliance with the License. 760b08185Syz147069 * 860b08185Syz147069 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 960b08185Syz147069 * or http://www.opensolaris.org/os/licensing. 1060b08185Syz147069 * See the License for the specific language governing permissions 1160b08185Syz147069 * and limitations under the License. 1260b08185Syz147069 * 1360b08185Syz147069 * When distributing Covered Code, include this CDDL HEADER in each 1460b08185Syz147069 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1560b08185Syz147069 * If applicable, add the following below this CDDL HEADER, with the 1660b08185Syz147069 * fields enclosed by brackets "[]" replaced with your own identifying 1760b08185Syz147069 * information: Portions Copyright [yyyy] [name of copyright owner] 1860b08185Syz147069 * 1960b08185Syz147069 * CDDL HEADER END 2060b08185Syz147069 */ 2160b08185Syz147069 /* 22688b07c5Sgc161489 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 2360b08185Syz147069 * Use is subject to license terms. 2460b08185Syz147069 */ 2560b08185Syz147069 2660b08185Syz147069 #pragma ident "%Z%%M% %I% %E% SMI" 2760b08185Syz147069 2860b08185Syz147069 /* 2960b08185Syz147069 * 3060b08185Syz147069 * keyspanport pipe routines (mostly device-neutral) 3160b08185Syz147069 * 3260b08185Syz147069 */ 3360b08185Syz147069 #include <sys/types.h> 3460b08185Syz147069 #include <sys/param.h> 3560b08185Syz147069 #include <sys/conf.h> 3660b08185Syz147069 #include <sys/stream.h> 3760b08185Syz147069 #include <sys/strsun.h> 3860b08185Syz147069 #include <sys/termio.h> 3960b08185Syz147069 #include <sys/ddi.h> 4060b08185Syz147069 #include <sys/sunddi.h> 4160b08185Syz147069 4260b08185Syz147069 #include <sys/usb/usba.h> 4360b08185Syz147069 #include <sys/usb/clients/usbser/usbser_keyspan/keyspan_var.h> 4460b08185Syz147069 #include <sys/usb/clients/usbser/usbser_keyspan/keyspan_pipe.h> 4560b08185Syz147069 4660b08185Syz147069 /* 4760b08185Syz147069 * initialize pipe structure with the given parameters 4860b08185Syz147069 */ 4960b08185Syz147069 static void 5060b08185Syz147069 keyspan_init_one_pipe(keyspan_state_t *ksp, keyspan_port_t *kp, 5160b08185Syz147069 keyspan_pipe_t *pipe) 5260b08185Syz147069 { 5360b08185Syz147069 usb_pipe_policy_t *policy; 5460b08185Syz147069 5560b08185Syz147069 USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, "keyspan_init_one_pipe: " 5660b08185Syz147069 "pipe = %p, pipe_stat %x", (void *)pipe, pipe->pipe_state); 5760b08185Syz147069 5860b08185Syz147069 /* init sync primitives */ 5960b08185Syz147069 mutex_init(&pipe->pipe_mutex, NULL, MUTEX_DRIVER, (void *)NULL); 6060b08185Syz147069 6160b08185Syz147069 /* init pipe policy */ 6260b08185Syz147069 policy = &pipe->pipe_policy; 6360b08185Syz147069 policy->pp_max_async_reqs = 2; 6460b08185Syz147069 6560b08185Syz147069 pipe->pipe_ksp = ksp; 6660b08185Syz147069 if (kp == NULL) { 6760b08185Syz147069 /* globle pipes should have device log handle */ 6860b08185Syz147069 pipe->pipe_lh = ksp->ks_lh; 6960b08185Syz147069 } else { 7060b08185Syz147069 /* port pipes should have port log handle */ 7160b08185Syz147069 pipe->pipe_lh = kp->kp_lh; 7260b08185Syz147069 } 7360b08185Syz147069 7460b08185Syz147069 pipe->pipe_state = KEYSPAN_PIPE_CLOSED; 7560b08185Syz147069 } 7660b08185Syz147069 7760b08185Syz147069 7860b08185Syz147069 static void 7960b08185Syz147069 keyspan_fini_one_pipe(keyspan_pipe_t *pipe) 8060b08185Syz147069 { 8160b08185Syz147069 USB_DPRINTF_L4(DPRINT_OPEN, pipe->pipe_ksp->ks_lh, 8260b08185Syz147069 "keyspan_fini_one_pipe: pipe_stat %x", pipe->pipe_state); 8360b08185Syz147069 8460b08185Syz147069 if (pipe->pipe_state != KEYSPAN_PIPE_NOT_INIT) { 8560b08185Syz147069 mutex_destroy(&pipe->pipe_mutex); 8660b08185Syz147069 pipe->pipe_state = KEYSPAN_PIPE_NOT_INIT; 8760b08185Syz147069 } 8860b08185Syz147069 } 8960b08185Syz147069 9060b08185Syz147069 /* 9160b08185Syz147069 * Lookup the endpoints defined in the spec; 9260b08185Syz147069 * Allocate resources, initialize pipe structures. 9360b08185Syz147069 * All are bulk pipes, including data in/out, cmd/status pipes. 9460b08185Syz147069 */ 9560b08185Syz147069 int 9660b08185Syz147069 keyspan_init_pipes(keyspan_state_t *ksp) 9760b08185Syz147069 { 9860b08185Syz147069 usb_client_dev_data_t *dev_data = ksp->ks_dev_data; 9960b08185Syz147069 int ifc, alt, i, j, k = 0; 10060b08185Syz147069 uint8_t port_cnt = ksp->ks_dev_spec.port_cnt; 10160b08185Syz147069 uint8_t ep_addr, ep_cnt; 10260b08185Syz147069 usb_ep_data_t *dataout[KEYSPAN_MAX_PORT_NUM], 10360b08185Syz147069 *datain[KEYSPAN_MAX_PORT_NUM], 10460b08185Syz147069 *status = NULL, *ctrl = NULL, *tmp_ep; 10560b08185Syz147069 usb_alt_if_data_t *alt_data; 10660b08185Syz147069 usb_if_data_t *if_data; 10760b08185Syz147069 10860b08185Syz147069 10960b08185Syz147069 ifc = dev_data->dev_curr_if; 11060b08185Syz147069 alt = 0; 11160b08185Syz147069 if_data = &dev_data->dev_curr_cfg->cfg_if[ifc]; 11260b08185Syz147069 alt_data = &if_data->if_alt[alt]; 11360b08185Syz147069 11460b08185Syz147069 /* 11560b08185Syz147069 * The actual EP number (indicated by bNumEndpoints) is more than 11660b08185Syz147069 * those defined in spec. We have to match those we need according 11760b08185Syz147069 * to EP addresses. And we'll lookup In EPs and Out EPs separately. 11860b08185Syz147069 */ 11960b08185Syz147069 ep_cnt = (alt_data->altif_descr.bNumEndpoints + 1) / 2; 12060b08185Syz147069 12160b08185Syz147069 /* 12260b08185Syz147069 * get DIR_IN EP descriptors, and then match with EP addresses. 12360b08185Syz147069 * Different keyspan devices may has different EP addresses. 12460b08185Syz147069 */ 12560b08185Syz147069 for (i = 0; i < ep_cnt; i++) { 12660b08185Syz147069 tmp_ep = usb_lookup_ep_data(ksp->ks_dip, dev_data, ifc, alt, i, 12760b08185Syz147069 USB_EP_ATTR_BULK, USB_EP_DIR_IN); 12860b08185Syz147069 if (tmp_ep == NULL) { 12960b08185Syz147069 USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh, 13060b08185Syz147069 "keyspan_init_pipes: can't find bulk in ep, i=%d," 13160b08185Syz147069 "ep_cnt=%d", i, ep_cnt); 13260b08185Syz147069 13360b08185Syz147069 continue; 13460b08185Syz147069 } 13560b08185Syz147069 ep_addr = tmp_ep->ep_descr.bEndpointAddress; 13660b08185Syz147069 13760b08185Syz147069 USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh, "keyspan_init_pipes: " 13860b08185Syz147069 "ep_addr =%x, stat_ep_addr=%x, i=%d", ep_addr, 13960b08185Syz147069 ksp->ks_dev_spec.stat_ep_addr, i); 14060b08185Syz147069 14160b08185Syz147069 /* match the status EP */ 14260b08185Syz147069 if (ep_addr == ksp->ks_dev_spec.stat_ep_addr) { 14360b08185Syz147069 status = tmp_ep; 14460b08185Syz147069 14560b08185Syz147069 continue; 14660b08185Syz147069 } 14760b08185Syz147069 14860b08185Syz147069 /* match the EPs of the ports */ 14960b08185Syz147069 for (j = 0; j < port_cnt; j++) { 15060b08185Syz147069 USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh, 15160b08185Syz147069 "keyspan_init_pipes: try to match bulk in data ep," 15260b08185Syz147069 " j=%d", j); 15360b08185Syz147069 if (ep_addr == ksp->ks_dev_spec.datain_ep_addr[j]) { 15460b08185Syz147069 datain[j] = tmp_ep; 15560b08185Syz147069 k++; 15660b08185Syz147069 USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh, 15760b08185Syz147069 "keyspan_init_pipes: matched a bulk in" 15860b08185Syz147069 " data ep"); 15960b08185Syz147069 16060b08185Syz147069 break; 16160b08185Syz147069 } 16260b08185Syz147069 } 16360b08185Syz147069 16460b08185Syz147069 /* if have matched all the necessary endpoints, break out */ 16560b08185Syz147069 if (k >= port_cnt && status != NULL) { 16660b08185Syz147069 16760b08185Syz147069 break; 16860b08185Syz147069 } 16960b08185Syz147069 17060b08185Syz147069 USB_DPRINTF_L4(DPRINT_ATTACH, ksp->ks_lh, "keyspan_init_pipes: " 17160b08185Syz147069 "try to match bulk in data ep, j=%d", j); 17260b08185Syz147069 17360b08185Syz147069 if (j == port_cnt) { 17460b08185Syz147069 /* this ep can't be matched by any addr */ 17560b08185Syz147069 USB_DPRINTF_L4(DPRINT_ATTACH, ksp->ks_lh, 17660b08185Syz147069 "keyspan_init_pipes: can't match bulk in ep," 17760b08185Syz147069 " addr =%x,", ep_addr); 17860b08185Syz147069 } 17960b08185Syz147069 } 18060b08185Syz147069 18160b08185Syz147069 if (k != port_cnt || status == NULL) { 18260b08185Syz147069 18360b08185Syz147069 /* Some of the necessary IN endpoints are not matched */ 18460b08185Syz147069 USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh, 18560b08185Syz147069 "keyspan_init_pipes: matched %d data in endpoints," 18660b08185Syz147069 " not enough", k); 18760b08185Syz147069 18860b08185Syz147069 return (USB_FAILURE); 18960b08185Syz147069 } 19060b08185Syz147069 19160b08185Syz147069 k = 0; 19260b08185Syz147069 19360b08185Syz147069 /* 19460b08185Syz147069 * get DIR_OUT EP descriptors, and then match with ep addrs. 19560b08185Syz147069 * different keyspan devices may has different ep addresses. 19660b08185Syz147069 */ 19760b08185Syz147069 for (i = 0; i < ep_cnt; i++) { 19860b08185Syz147069 tmp_ep = usb_lookup_ep_data(ksp->ks_dip, dev_data, ifc, alt, i, 19960b08185Syz147069 USB_EP_ATTR_BULK, USB_EP_DIR_OUT); 20060b08185Syz147069 if (tmp_ep == NULL) { 20160b08185Syz147069 USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh, 20260b08185Syz147069 "keyspan_init_pipes: can't find bulk out ep, i=%d," 20360b08185Syz147069 "ep_cnt=%d", i, ep_cnt); 20460b08185Syz147069 20560b08185Syz147069 continue; 20660b08185Syz147069 } 20760b08185Syz147069 ep_addr = tmp_ep->ep_descr.bEndpointAddress; 20860b08185Syz147069 20960b08185Syz147069 /* match the status ep */ 21060b08185Syz147069 if (ep_addr == ksp->ks_dev_spec.ctrl_ep_addr) { 21160b08185Syz147069 ctrl = tmp_ep; 21260b08185Syz147069 21360b08185Syz147069 continue; 21460b08185Syz147069 } 21560b08185Syz147069 21660b08185Syz147069 /* match the ep of the ports */ 21760b08185Syz147069 for (j = 0; j < port_cnt; j++) { 21860b08185Syz147069 if (ep_addr == ksp->ks_dev_spec.dataout_ep_addr[j]) { 21960b08185Syz147069 dataout[j] = tmp_ep; 22060b08185Syz147069 k++; 22160b08185Syz147069 22260b08185Syz147069 break; 22360b08185Syz147069 } 22460b08185Syz147069 } 22560b08185Syz147069 /* if have matched all the necessary endpoints, break out */ 22660b08185Syz147069 if (k >= port_cnt && ctrl != NULL) { 22760b08185Syz147069 22860b08185Syz147069 break; 22960b08185Syz147069 } 23060b08185Syz147069 23160b08185Syz147069 if (j == port_cnt) { 23260b08185Syz147069 23360b08185Syz147069 /* this ep can't be matched by any addr */ 23460b08185Syz147069 USB_DPRINTF_L4(DPRINT_ATTACH, ksp->ks_lh, 23560b08185Syz147069 "keyspan_init_pipes: can't match bulk out ep," 23660b08185Syz147069 " ep_addr =%x", ep_addr); 23760b08185Syz147069 23860b08185Syz147069 } 23960b08185Syz147069 } 24060b08185Syz147069 24160b08185Syz147069 if (k != port_cnt || ctrl == NULL) { 24260b08185Syz147069 /* Not all the necessary OUT endpoints are matched */ 24360b08185Syz147069 USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh, 24460b08185Syz147069 "keyspan_init_pipes: matched %d data in endpoints," 24560b08185Syz147069 " not enough", k); 24660b08185Syz147069 24760b08185Syz147069 return (USB_FAILURE); 24860b08185Syz147069 } 24960b08185Syz147069 25060b08185Syz147069 mutex_enter(&ksp->ks_mutex); 25160b08185Syz147069 25260b08185Syz147069 /* 25360b08185Syz147069 * Device globle pipes: a bulk in pipe for status and a bulk out 25460b08185Syz147069 * pipe for controle cmd. 25560b08185Syz147069 */ 25660b08185Syz147069 ksp->ks_statin_pipe.pipe_ep_descr = status->ep_descr; 25760b08185Syz147069 keyspan_init_one_pipe(ksp, NULL, &ksp->ks_statin_pipe); 25860b08185Syz147069 25960b08185Syz147069 ksp->ks_ctrlout_pipe.pipe_ep_descr = ctrl->ep_descr; 26060b08185Syz147069 keyspan_init_one_pipe(ksp, NULL, &ksp->ks_ctrlout_pipe); 26160b08185Syz147069 26260b08185Syz147069 /* for data in/out pipes of each port */ 26360b08185Syz147069 for (i = 0; i < port_cnt; i++) { 26460b08185Syz147069 26560b08185Syz147069 ksp->ks_ports[i].kp_datain_pipe.pipe_ep_descr = 26660b08185Syz147069 datain[i]->ep_descr; 26760b08185Syz147069 keyspan_init_one_pipe(ksp, &ksp->ks_ports[i], 26860b08185Syz147069 &ksp->ks_ports[i].kp_datain_pipe); 26960b08185Syz147069 27060b08185Syz147069 ksp->ks_ports[i].kp_dataout_pipe.pipe_ep_descr = 27160b08185Syz147069 dataout[i]->ep_descr; 27260b08185Syz147069 keyspan_init_one_pipe(ksp, &ksp->ks_ports[i], 27360b08185Syz147069 &ksp->ks_ports[i].kp_dataout_pipe); 27460b08185Syz147069 } 27560b08185Syz147069 27660b08185Syz147069 mutex_exit(&ksp->ks_mutex); 27760b08185Syz147069 27860b08185Syz147069 return (USB_SUCCESS); 27960b08185Syz147069 } 280*02dd2108Slg150142 /* 281*02dd2108Slg150142 * For USA_49WG only. 282*02dd2108Slg150142 * Lookup the endpoints defined in the spec. 283*02dd2108Slg150142 * Allocate resources, initialize pipe structures. 284*02dd2108Slg150142 * There are 6 EPs, 3 bulk out Eps, 1 bulk in EP, 1 intr in EP, 1 intr out EP 285*02dd2108Slg150142 */ 286*02dd2108Slg150142 int 287*02dd2108Slg150142 keyspan_init_pipes_usa49wg(keyspan_state_t *ksp) 288*02dd2108Slg150142 { 289*02dd2108Slg150142 usb_client_dev_data_t *dev_data = ksp->ks_dev_data; 290*02dd2108Slg150142 int ifc, alt, i, j = 0; 291*02dd2108Slg150142 uint8_t port_cnt = ksp->ks_dev_spec.port_cnt; 292*02dd2108Slg150142 uint8_t ep_addr; 293*02dd2108Slg150142 usb_ep_data_t *dataout[KEYSPAN_MAX_PORT_NUM], 294*02dd2108Slg150142 *datain[KEYSPAN_MAX_PORT_NUM], 295*02dd2108Slg150142 *status = NULL, *tmp_ep; 296*02dd2108Slg150142 297*02dd2108Slg150142 ifc = dev_data->dev_curr_if; 298*02dd2108Slg150142 alt = 0; 299*02dd2108Slg150142 300*02dd2108Slg150142 /* 301*02dd2108Slg150142 * get intr out EP descriptor as port0 data out EP, and then 302*02dd2108Slg150142 * match with EP address. 303*02dd2108Slg150142 * Different keyspan devices may has different EP addresses. 304*02dd2108Slg150142 */ 305*02dd2108Slg150142 tmp_ep = usb_lookup_ep_data(ksp->ks_dip, dev_data, ifc, alt, 0, 306*02dd2108Slg150142 USB_EP_ATTR_INTR, USB_EP_DIR_OUT); 307*02dd2108Slg150142 if (tmp_ep == NULL) { 308*02dd2108Slg150142 USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh, 309*02dd2108Slg150142 "keyspan_init_pipes: can't find port1 data out ep"); 310*02dd2108Slg150142 311*02dd2108Slg150142 return (USB_FAILURE); 312*02dd2108Slg150142 } 313*02dd2108Slg150142 ep_addr = tmp_ep->ep_descr.bEndpointAddress; 314*02dd2108Slg150142 315*02dd2108Slg150142 /* match the port0 data out EP */ 316*02dd2108Slg150142 if (ep_addr == ksp->ks_dev_spec.dataout_ep_addr[0]) { 317*02dd2108Slg150142 dataout[0] = tmp_ep; 318*02dd2108Slg150142 } 319*02dd2108Slg150142 320*02dd2108Slg150142 /* 321*02dd2108Slg150142 * get bulk out EP descriptors as other port data out EPs, and then 322*02dd2108Slg150142 * match with EP addresses. 323*02dd2108Slg150142 */ 324*02dd2108Slg150142 for (j = 1; j < port_cnt; j++) { 325*02dd2108Slg150142 tmp_ep = usb_lookup_ep_data(ksp->ks_dip, dev_data, ifc, alt, 326*02dd2108Slg150142 j-1, USB_EP_ATTR_BULK, USB_EP_DIR_OUT); 327*02dd2108Slg150142 if (tmp_ep == NULL) { 328*02dd2108Slg150142 USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh, 329*02dd2108Slg150142 "keyspan_init_pipes: can't find port[%d] data out ep", 330*02dd2108Slg150142 j); 331*02dd2108Slg150142 return (USB_FAILURE); 332*02dd2108Slg150142 } 333*02dd2108Slg150142 334*02dd2108Slg150142 ep_addr = tmp_ep->ep_descr.bEndpointAddress; 335*02dd2108Slg150142 336*02dd2108Slg150142 /* match other port data out EPs */ 337*02dd2108Slg150142 if (ep_addr == ksp->ks_dev_spec.dataout_ep_addr[j]) { 338*02dd2108Slg150142 dataout[j] = tmp_ep; 339*02dd2108Slg150142 } 340*02dd2108Slg150142 } 341*02dd2108Slg150142 342*02dd2108Slg150142 /* 343*02dd2108Slg150142 * get intr in EP descriptor as status EP, and then match with EP addrs 344*02dd2108Slg150142 */ 345*02dd2108Slg150142 tmp_ep = usb_lookup_ep_data(ksp->ks_dip, dev_data, ifc, alt, 0, 346*02dd2108Slg150142 USB_EP_ATTR_INTR, USB_EP_DIR_IN); 347*02dd2108Slg150142 if (tmp_ep == NULL) { 348*02dd2108Slg150142 USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh, 349*02dd2108Slg150142 "keyspan_init_pipes: can't find status in ep"); 350*02dd2108Slg150142 351*02dd2108Slg150142 return (USB_FAILURE); 352*02dd2108Slg150142 } 353*02dd2108Slg150142 ep_addr = tmp_ep->ep_descr.bEndpointAddress; 354*02dd2108Slg150142 355*02dd2108Slg150142 /* match the status ep */ 356*02dd2108Slg150142 if (ep_addr == ksp->ks_dev_spec.stat_ep_addr) { 357*02dd2108Slg150142 status = tmp_ep; 358*02dd2108Slg150142 } 359*02dd2108Slg150142 360*02dd2108Slg150142 /* 361*02dd2108Slg150142 * get bulk in EP descriptors as data in EP, All the ports share one 362*02dd2108Slg150142 * data in EP. 363*02dd2108Slg150142 */ 364*02dd2108Slg150142 tmp_ep = usb_lookup_ep_data(ksp->ks_dip, dev_data, ifc, alt, 0, 365*02dd2108Slg150142 USB_EP_ATTR_BULK, USB_EP_DIR_IN); 366*02dd2108Slg150142 if (tmp_ep == NULL) { 367*02dd2108Slg150142 USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh, 368*02dd2108Slg150142 "keyspan_init_pipes: can't find bulk in ep"); 369*02dd2108Slg150142 370*02dd2108Slg150142 return (USB_FAILURE); 371*02dd2108Slg150142 } 372*02dd2108Slg150142 ep_addr = tmp_ep->ep_descr.bEndpointAddress; 373*02dd2108Slg150142 374*02dd2108Slg150142 /* match data in EPs */ 375*02dd2108Slg150142 if (ep_addr == ksp->ks_dev_spec.datain_ep_addr[0]) { 376*02dd2108Slg150142 datain[0] = tmp_ep; 377*02dd2108Slg150142 } 378*02dd2108Slg150142 379*02dd2108Slg150142 mutex_enter(&ksp->ks_mutex); 380*02dd2108Slg150142 381*02dd2108Slg150142 /* intr in pipe for status */ 382*02dd2108Slg150142 ksp->ks_statin_pipe.pipe_ep_descr = status->ep_descr; 383*02dd2108Slg150142 keyspan_init_one_pipe(ksp, NULL, &ksp->ks_statin_pipe); 384*02dd2108Slg150142 385*02dd2108Slg150142 /* for data in/out pipes of each port */ 386*02dd2108Slg150142 for (i = 0; i < port_cnt; i++) { 387*02dd2108Slg150142 ksp->ks_ports[i].kp_datain_pipe.pipe_ep_descr = 388*02dd2108Slg150142 datain[0]->ep_descr; 389*02dd2108Slg150142 keyspan_init_one_pipe(ksp, &ksp->ks_ports[i], 390*02dd2108Slg150142 &ksp->ks_ports[i].kp_datain_pipe); 391*02dd2108Slg150142 392*02dd2108Slg150142 ksp->ks_ports[i].kp_dataout_pipe.pipe_ep_descr = 393*02dd2108Slg150142 dataout[i]->ep_descr; 394*02dd2108Slg150142 keyspan_init_one_pipe(ksp, &ksp->ks_ports[i], 395*02dd2108Slg150142 &ksp->ks_ports[i].kp_dataout_pipe); 396*02dd2108Slg150142 } 397*02dd2108Slg150142 398*02dd2108Slg150142 mutex_exit(&ksp->ks_mutex); 399*02dd2108Slg150142 400*02dd2108Slg150142 return (USB_SUCCESS); 401*02dd2108Slg150142 } 40260b08185Syz147069 40360b08185Syz147069 void 40460b08185Syz147069 keyspan_fini_pipes(keyspan_state_t *ksp) 40560b08185Syz147069 { 40660b08185Syz147069 keyspan_port_t *kp; 40760b08185Syz147069 int i; 40860b08185Syz147069 40960b08185Syz147069 for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) { 41060b08185Syz147069 kp = &ksp->ks_ports[i]; 41160b08185Syz147069 keyspan_fini_one_pipe(&kp->kp_datain_pipe); 41260b08185Syz147069 keyspan_fini_one_pipe(&kp->kp_dataout_pipe); 41360b08185Syz147069 } 41460b08185Syz147069 415*02dd2108Slg150142 /* fini status pipe */ 41660b08185Syz147069 keyspan_fini_one_pipe(&ksp->ks_statin_pipe); 417*02dd2108Slg150142 /* 418*02dd2108Slg150142 * fini control pipe 419*02dd2108Slg150142 * If USA_49WG, don't need fini control pipe 420*02dd2108Slg150142 */ 421*02dd2108Slg150142 switch (ksp->ks_dev_spec.id_product) { 422*02dd2108Slg150142 case KEYSPAN_USA19HS_PID: 423*02dd2108Slg150142 case KEYSPAN_USA49WLC_PID: 42460b08185Syz147069 keyspan_fini_one_pipe(&ksp->ks_ctrlout_pipe); 42560b08185Syz147069 426*02dd2108Slg150142 break; 427*02dd2108Slg150142 case KEYSPAN_USA49WG_PID: 428*02dd2108Slg150142 429*02dd2108Slg150142 break; 430*02dd2108Slg150142 default: 431*02dd2108Slg150142 USB_DPRINTF_L2(DPRINT_CTLOP, ksp->ks_lh, 432*02dd2108Slg150142 "keyspan_fini_pipes: the device's product id" 433*02dd2108Slg150142 "can't be recognized"); 434*02dd2108Slg150142 } 435*02dd2108Slg150142 } 43660b08185Syz147069 43760b08185Syz147069 static int 43860b08185Syz147069 keyspan_open_one_pipe(keyspan_state_t *ksp, keyspan_pipe_t *pipe) 43960b08185Syz147069 { 44060b08185Syz147069 int rval; 44160b08185Syz147069 44260b08185Syz147069 /* don't open for the second time */ 44360b08185Syz147069 mutex_enter(&pipe->pipe_mutex); 44460b08185Syz147069 ASSERT(pipe->pipe_state != KEYSPAN_PIPE_NOT_INIT); 44560b08185Syz147069 if (pipe->pipe_state != KEYSPAN_PIPE_CLOSED) { 44660b08185Syz147069 mutex_exit(&pipe->pipe_mutex); 44760b08185Syz147069 44860b08185Syz147069 return (USB_SUCCESS); 44960b08185Syz147069 } 45060b08185Syz147069 mutex_exit(&pipe->pipe_mutex); 45160b08185Syz147069 45260b08185Syz147069 rval = usb_pipe_open(ksp->ks_dip, &pipe->pipe_ep_descr, 45360b08185Syz147069 &pipe->pipe_policy, USB_FLAGS_SLEEP, &pipe->pipe_handle); 45460b08185Syz147069 45560b08185Syz147069 if (rval == USB_SUCCESS) { 45660b08185Syz147069 mutex_enter(&pipe->pipe_mutex); 45760b08185Syz147069 pipe->pipe_state = KEYSPAN_PIPE_OPEN; 45860b08185Syz147069 mutex_exit(&pipe->pipe_mutex); 45960b08185Syz147069 } 46060b08185Syz147069 46160b08185Syz147069 return (rval); 46260b08185Syz147069 } 46360b08185Syz147069 464*02dd2108Slg150142 /* 465*02dd2108Slg150142 * Open shared datain pipe for USA_49WG 466*02dd2108Slg150142 */ 467*02dd2108Slg150142 static int 468*02dd2108Slg150142 keyspan_open_pipe_datain_usa49wg(keyspan_state_t *ksp, keyspan_pipe_t *pipe) 469*02dd2108Slg150142 { 470*02dd2108Slg150142 int rval = USB_SUCCESS; 471*02dd2108Slg150142 472*02dd2108Slg150142 /* don't open for the second time */ 473*02dd2108Slg150142 mutex_enter(&pipe->pipe_mutex); 474*02dd2108Slg150142 ASSERT(pipe->pipe_state != KEYSPAN_PIPE_NOT_INIT); 475*02dd2108Slg150142 if (pipe->pipe_state != KEYSPAN_PIPE_CLOSED) { 476*02dd2108Slg150142 mutex_exit(&pipe->pipe_mutex); 477*02dd2108Slg150142 478*02dd2108Slg150142 return (USB_SUCCESS); 479*02dd2108Slg150142 } 480*02dd2108Slg150142 mutex_exit(&pipe->pipe_mutex); 481*02dd2108Slg150142 482*02dd2108Slg150142 mutex_enter(&ksp->ks_mutex); 483*02dd2108Slg150142 ksp->ks_datain_open_cnt++; 484*02dd2108Slg150142 if (ksp->ks_datain_open_cnt == 1) { 485*02dd2108Slg150142 mutex_exit(&ksp->ks_mutex); 486*02dd2108Slg150142 487*02dd2108Slg150142 if ((rval = (usb_pipe_open(ksp->ks_dip, &pipe->pipe_ep_descr, 488*02dd2108Slg150142 &pipe->pipe_policy, USB_FLAGS_SLEEP, 489*02dd2108Slg150142 &pipe->pipe_handle))) == USB_SUCCESS) { 490*02dd2108Slg150142 mutex_enter(&pipe->pipe_mutex); 491*02dd2108Slg150142 pipe->pipe_state = KEYSPAN_PIPE_OPEN; 492*02dd2108Slg150142 mutex_exit(&pipe->pipe_mutex); 493*02dd2108Slg150142 494*02dd2108Slg150142 mutex_enter(&ksp->ks_mutex); 495*02dd2108Slg150142 ksp->ks_datain_pipe_handle = pipe->pipe_handle; 496*02dd2108Slg150142 mutex_exit(&ksp->ks_mutex); 497*02dd2108Slg150142 } else { 498*02dd2108Slg150142 mutex_enter(&ksp->ks_mutex); 499*02dd2108Slg150142 ksp->ks_datain_open_cnt--; 500*02dd2108Slg150142 mutex_exit(&ksp->ks_mutex); 501*02dd2108Slg150142 } 502*02dd2108Slg150142 503*02dd2108Slg150142 return (rval); 504*02dd2108Slg150142 } else { 505*02dd2108Slg150142 /* data in pipe has been opened by other port */ 506*02dd2108Slg150142 ASSERT(ksp->ks_datain_pipe_handle != NULL); 507*02dd2108Slg150142 508*02dd2108Slg150142 mutex_enter(&pipe->pipe_mutex); 509*02dd2108Slg150142 pipe->pipe_handle = ksp->ks_datain_pipe_handle; 510*02dd2108Slg150142 /* Set datain pipe state */ 511*02dd2108Slg150142 pipe->pipe_state = KEYSPAN_PIPE_OPEN; 512*02dd2108Slg150142 mutex_exit(&pipe->pipe_mutex); 513*02dd2108Slg150142 mutex_exit(&ksp->ks_mutex); 514*02dd2108Slg150142 515*02dd2108Slg150142 return (USB_SUCCESS); 516*02dd2108Slg150142 } 517*02dd2108Slg150142 } 51860b08185Syz147069 51960b08185Syz147069 /* 52060b08185Syz147069 * close one pipe if open 52160b08185Syz147069 */ 52260b08185Syz147069 static void 52360b08185Syz147069 keyspan_close_one_pipe(keyspan_pipe_t *pipe) 52460b08185Syz147069 { 52560b08185Syz147069 /* 52660b08185Syz147069 * pipe may already be closed, e.g. if device has been physically 52760b08185Syz147069 * disconnected and the driver immediately detached 52860b08185Syz147069 */ 52960b08185Syz147069 if (pipe->pipe_handle != NULL) { 53060b08185Syz147069 usb_pipe_close(pipe->pipe_ksp->ks_dip, pipe->pipe_handle, 53160b08185Syz147069 USB_FLAGS_SLEEP, NULL, NULL); 53260b08185Syz147069 mutex_enter(&pipe->pipe_mutex); 53360b08185Syz147069 pipe->pipe_handle = NULL; 53460b08185Syz147069 pipe->pipe_state = KEYSPAN_PIPE_CLOSED; 53560b08185Syz147069 mutex_exit(&pipe->pipe_mutex); 53660b08185Syz147069 } 53760b08185Syz147069 } 53860b08185Syz147069 53960b08185Syz147069 /* 540*02dd2108Slg150142 * close shared datain pipe if open for USA_49WG 541*02dd2108Slg150142 */ 542*02dd2108Slg150142 static void 543*02dd2108Slg150142 keyspan_close_pipe_datain_usa49wg(keyspan_pipe_t *pipe) 544*02dd2108Slg150142 { 545*02dd2108Slg150142 keyspan_state_t *ksp = pipe->pipe_ksp; 546*02dd2108Slg150142 /* 547*02dd2108Slg150142 * pipe may already be closed, e.g. if device has been physically 548*02dd2108Slg150142 * disconnected and the driver immediately detached 549*02dd2108Slg150142 */ 550*02dd2108Slg150142 if (pipe->pipe_handle != NULL) { 551*02dd2108Slg150142 mutex_enter(&ksp->ks_mutex); 552*02dd2108Slg150142 ksp->ks_datain_open_cnt--; 553*02dd2108Slg150142 if (!ksp->ks_datain_open_cnt) { 554*02dd2108Slg150142 mutex_exit(&ksp->ks_mutex); 555*02dd2108Slg150142 usb_pipe_close(pipe->pipe_ksp->ks_dip, 556*02dd2108Slg150142 pipe->pipe_handle, USB_FLAGS_SLEEP, 557*02dd2108Slg150142 NULL, NULL); 558*02dd2108Slg150142 } else { 559*02dd2108Slg150142 mutex_exit(&ksp->ks_mutex); 560*02dd2108Slg150142 } 561*02dd2108Slg150142 562*02dd2108Slg150142 mutex_enter(&pipe->pipe_mutex); 563*02dd2108Slg150142 pipe->pipe_handle = NULL; 564*02dd2108Slg150142 pipe->pipe_state = KEYSPAN_PIPE_CLOSED; 565*02dd2108Slg150142 mutex_exit(&pipe->pipe_mutex); 566*02dd2108Slg150142 } 567*02dd2108Slg150142 } 568*02dd2108Slg150142 569*02dd2108Slg150142 /* 570*02dd2108Slg150142 * For USA19HS and USA49WLC: 57160b08185Syz147069 * Open global pipes, a status pipe and a control pipe 57260b08185Syz147069 */ 57360b08185Syz147069 int 574*02dd2108Slg150142 keyspan_open_dev_pipes_usa49(keyspan_state_t *ksp) 57560b08185Syz147069 { 57660b08185Syz147069 int rval; 57760b08185Syz147069 578*02dd2108Slg150142 USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, 579*02dd2108Slg150142 "keyspan_open_dev_pipes_usa49"); 58060b08185Syz147069 58160b08185Syz147069 rval = keyspan_open_one_pipe(ksp, &ksp->ks_ctrlout_pipe); 58260b08185Syz147069 if (rval != USB_SUCCESS) { 58360b08185Syz147069 USB_DPRINTF_L2(DPRINT_OPEN, ksp->ks_lh, 584*02dd2108Slg150142 "keyspan_open_dev_pipes_usa49: open ctrl pipe failed %d", rval); 58560b08185Syz147069 58660b08185Syz147069 return (rval); 58760b08185Syz147069 } 58860b08185Syz147069 58960b08185Syz147069 rval = keyspan_open_one_pipe(ksp, &ksp->ks_statin_pipe); 59060b08185Syz147069 if (rval != USB_SUCCESS) { 59160b08185Syz147069 USB_DPRINTF_L2(DPRINT_OPEN, ksp->ks_lh, 592*02dd2108Slg150142 "keyspan_open_dev_pipes_usa49: open status pipe failed %d", 593*02dd2108Slg150142 rval); 59460b08185Syz147069 59560b08185Syz147069 /* close the first opened pipe here */ 59660b08185Syz147069 keyspan_close_one_pipe(&ksp->ks_ctrlout_pipe); 59760b08185Syz147069 59860b08185Syz147069 return (rval); 59960b08185Syz147069 } 60060b08185Syz147069 60160b08185Syz147069 /* start receive device status */ 60260b08185Syz147069 rval = keyspan_receive_status(ksp); 60360b08185Syz147069 if (rval != USB_SUCCESS) { 60460b08185Syz147069 USB_DPRINTF_L2(DPRINT_OPEN, ksp->ks_lh, 605*02dd2108Slg150142 "keyspan_open_dev_pipes_usa49: receive device status" 606*02dd2108Slg150142 " failed %d", rval); 60760b08185Syz147069 60860b08185Syz147069 /* close opened pipes here */ 60960b08185Syz147069 keyspan_close_one_pipe(&ksp->ks_statin_pipe); 61060b08185Syz147069 keyspan_close_one_pipe(&ksp->ks_ctrlout_pipe); 61160b08185Syz147069 61260b08185Syz147069 return (rval); 61360b08185Syz147069 } 61460b08185Syz147069 61560b08185Syz147069 return (rval); 61660b08185Syz147069 } 61760b08185Syz147069 618*02dd2108Slg150142 /* 619*02dd2108Slg150142 * For keyspan USA_49WG: 620*02dd2108Slg150142 * Open global pipes, a status pipe 621*02dd2108Slg150142 * Use default control pipe, don't need to open it. 622*02dd2108Slg150142 */ 623*02dd2108Slg150142 int 624*02dd2108Slg150142 keyspan_open_dev_pipes_usa49wg(keyspan_state_t *ksp) 625*02dd2108Slg150142 { 626*02dd2108Slg150142 int rval; 627*02dd2108Slg150142 628*02dd2108Slg150142 /* Open status pipe */ 629*02dd2108Slg150142 rval = keyspan_open_one_pipe(ksp, &ksp->ks_statin_pipe); 630*02dd2108Slg150142 if (rval != USB_SUCCESS) { 631*02dd2108Slg150142 USB_DPRINTF_L2(DPRINT_OPEN, ksp->ks_lh, 632*02dd2108Slg150142 "keyspan_open_dev_pipes_usa49wg: open status pipe failed %d", 633*02dd2108Slg150142 rval); 634*02dd2108Slg150142 635*02dd2108Slg150142 return (rval); 636*02dd2108Slg150142 } 637*02dd2108Slg150142 /* start device polling */ 638*02dd2108Slg150142 keyspan_pipe_start_polling(&ksp->ks_statin_pipe); 639*02dd2108Slg150142 640*02dd2108Slg150142 return (rval); 641*02dd2108Slg150142 } 642*02dd2108Slg150142 643*02dd2108Slg150142 /* 644*02dd2108Slg150142 * Open global pipes, status pipe and control pipe, 645*02dd2108Slg150142 */ 646*02dd2108Slg150142 int 647*02dd2108Slg150142 keyspan_open_dev_pipes(keyspan_state_t *ksp) 648*02dd2108Slg150142 { 649*02dd2108Slg150142 int rval = USB_SUCCESS; 650*02dd2108Slg150142 651*02dd2108Slg150142 USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, "keyspan_open_dev_pipes"); 652*02dd2108Slg150142 653*02dd2108Slg150142 switch (ksp->ks_dev_spec.id_product) { 654*02dd2108Slg150142 case KEYSPAN_USA19HS_PID: 655*02dd2108Slg150142 case KEYSPAN_USA49WLC_PID: 656*02dd2108Slg150142 rval = keyspan_open_dev_pipes_usa49(ksp); 657*02dd2108Slg150142 658*02dd2108Slg150142 break; 659*02dd2108Slg150142 case KEYSPAN_USA49WG_PID: 660*02dd2108Slg150142 rval = keyspan_open_dev_pipes_usa49wg(ksp); 661*02dd2108Slg150142 662*02dd2108Slg150142 break; 663*02dd2108Slg150142 default: 664*02dd2108Slg150142 USB_DPRINTF_L2(DPRINT_OPEN, ksp->ks_lh, 665*02dd2108Slg150142 "keyspan_open_dev_pipes: the device's product id can't" 666*02dd2108Slg150142 "be recognized"); 667*02dd2108Slg150142 668*02dd2108Slg150142 return (USB_FAILURE); 669*02dd2108Slg150142 } 670*02dd2108Slg150142 return (rval); 671*02dd2108Slg150142 } 67260b08185Syz147069 67360b08185Syz147069 /* 67460b08185Syz147069 * Reopen all pipes if the port had them open 67560b08185Syz147069 */ 67660b08185Syz147069 int 67760b08185Syz147069 keyspan_reopen_pipes(keyspan_state_t *ksp) 67860b08185Syz147069 { 67960b08185Syz147069 keyspan_port_t *kp; 68060b08185Syz147069 int i; 68160b08185Syz147069 68260b08185Syz147069 USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, "keyspan_reopen_pipes"); 68360b08185Syz147069 68460b08185Syz147069 if (keyspan_open_dev_pipes(ksp) != USB_SUCCESS) { 68560b08185Syz147069 68660b08185Syz147069 return (USB_FAILURE); 68760b08185Syz147069 } 68860b08185Syz147069 68960b08185Syz147069 for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) { 69060b08185Syz147069 kp = &ksp->ks_ports[i]; 69160b08185Syz147069 mutex_enter(&kp->kp_mutex); 69260b08185Syz147069 if (kp->kp_state == KEYSPAN_PORT_OPEN) { 69360b08185Syz147069 USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, 69460b08185Syz147069 "keyspan_reopen_pipes() reopen pipe #%d", i); 69560b08185Syz147069 mutex_exit(&kp->kp_mutex); 69660b08185Syz147069 if (keyspan_open_port_pipes(kp) != USB_SUCCESS) { 69760b08185Syz147069 69860b08185Syz147069 return (USB_FAILURE); 69960b08185Syz147069 } 70060b08185Syz147069 mutex_enter(&kp->kp_mutex); 70160b08185Syz147069 kp->kp_no_more_reads = B_FALSE; 70260b08185Syz147069 } 70360b08185Syz147069 mutex_exit(&kp->kp_mutex); 70460b08185Syz147069 } 70560b08185Syz147069 70660b08185Syz147069 return (USB_SUCCESS); 70760b08185Syz147069 } 70860b08185Syz147069 70960b08185Syz147069 void 71060b08185Syz147069 keyspan_close_port_pipes(keyspan_port_t *kp) 71160b08185Syz147069 { 712*02dd2108Slg150142 keyspan_state_t *ksp = kp->kp_ksp; 713*02dd2108Slg150142 71460b08185Syz147069 USB_DPRINTF_L4(DPRINT_CLOSE, kp->kp_lh, "keyspan_close_port_pipes"); 71560b08185Syz147069 716*02dd2108Slg150142 switch (ksp->ks_dev_spec.id_product) { 717*02dd2108Slg150142 case KEYSPAN_USA19HS_PID: 718*02dd2108Slg150142 case KEYSPAN_USA49WLC_PID: 71960b08185Syz147069 keyspan_close_one_pipe(&kp->kp_datain_pipe); 720*02dd2108Slg150142 721*02dd2108Slg150142 break; 722*02dd2108Slg150142 case KEYSPAN_USA49WG_PID: 723*02dd2108Slg150142 keyspan_close_pipe_datain_usa49wg(&kp->kp_datain_pipe); 724*02dd2108Slg150142 725*02dd2108Slg150142 break; 726*02dd2108Slg150142 default: 727*02dd2108Slg150142 USB_DPRINTF_L2(DPRINT_CLOSE, kp->kp_lh, 728*02dd2108Slg150142 "keyspan_close_port_pipes:" 729*02dd2108Slg150142 "the device's product id can't be recognized"); 730*02dd2108Slg150142 } 731*02dd2108Slg150142 keyspan_close_one_pipe(&kp->kp_dataout_pipe); 73260b08185Syz147069 } 73360b08185Syz147069 73460b08185Syz147069 /* 73560b08185Syz147069 * Close IN and OUT bulk pipes of all ports 73660b08185Syz147069 */ 73760b08185Syz147069 void 73860b08185Syz147069 keyspan_close_open_pipes(keyspan_state_t *ksp) 73960b08185Syz147069 { 74060b08185Syz147069 keyspan_port_t *kp; 74160b08185Syz147069 int i; 742*02dd2108Slg150142 int port_num = -1; 74360b08185Syz147069 74460b08185Syz147069 USB_DPRINTF_L4(DPRINT_CLOSE, ksp->ks_lh, "keyspan_close_open_pipes"); 74560b08185Syz147069 746*02dd2108Slg150142 switch (ksp->ks_dev_spec.id_product) { 747*02dd2108Slg150142 case KEYSPAN_USA19HS_PID: 748*02dd2108Slg150142 case KEYSPAN_USA49WLC_PID: 74960b08185Syz147069 for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) { 75060b08185Syz147069 kp = &ksp->ks_ports[i]; 75160b08185Syz147069 mutex_enter(&kp->kp_mutex); 75260b08185Syz147069 if (kp->kp_state == KEYSPAN_PORT_OPEN) { 75360b08185Syz147069 kp->kp_no_more_reads = B_TRUE; 75460b08185Syz147069 mutex_exit(&kp->kp_mutex); 75560b08185Syz147069 usb_pipe_reset(ksp->ks_dip, 756*02dd2108Slg150142 kp->kp_datain_pipe.pipe_handle, 757*02dd2108Slg150142 USB_FLAGS_SLEEP, NULL, NULL); 75860b08185Syz147069 keyspan_close_port_pipes(kp); 75960b08185Syz147069 } else { 76060b08185Syz147069 mutex_exit(&kp->kp_mutex); 76160b08185Syz147069 } 76260b08185Syz147069 } 763*02dd2108Slg150142 764*02dd2108Slg150142 break; 765*02dd2108Slg150142 766*02dd2108Slg150142 case KEYSPAN_USA49WG_PID: 767*02dd2108Slg150142 for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) { 768*02dd2108Slg150142 kp = &ksp->ks_ports[i]; 769*02dd2108Slg150142 mutex_enter(&kp->kp_mutex); 770*02dd2108Slg150142 if (kp->kp_state == KEYSPAN_PORT_OPEN) { 771*02dd2108Slg150142 kp->kp_no_more_reads = B_TRUE; 772*02dd2108Slg150142 port_num = i; 773*02dd2108Slg150142 } 774*02dd2108Slg150142 mutex_exit(&kp->kp_mutex); 775*02dd2108Slg150142 } 776*02dd2108Slg150142 if (port_num >= 0) { 777*02dd2108Slg150142 kp = &ksp->ks_ports[port_num]; 778*02dd2108Slg150142 usb_pipe_reset(ksp->ks_dip, 779*02dd2108Slg150142 kp->kp_datain_pipe.pipe_handle, 780*02dd2108Slg150142 USB_FLAGS_SLEEP, NULL, NULL); 78160b08185Syz147069 } 78260b08185Syz147069 783*02dd2108Slg150142 for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) { 784*02dd2108Slg150142 kp = &ksp->ks_ports[i]; 785*02dd2108Slg150142 mutex_enter(&kp->kp_mutex); 786*02dd2108Slg150142 if (kp->kp_state == KEYSPAN_PORT_OPEN) { 787*02dd2108Slg150142 mutex_exit(&kp->kp_mutex); 788*02dd2108Slg150142 keyspan_close_port_pipes(kp); 789*02dd2108Slg150142 } else { 790*02dd2108Slg150142 mutex_exit(&kp->kp_mutex); 791*02dd2108Slg150142 } 792*02dd2108Slg150142 } 793*02dd2108Slg150142 794*02dd2108Slg150142 break; 795*02dd2108Slg150142 default: 796*02dd2108Slg150142 USB_DPRINTF_L2(DPRINT_CLOSE, ksp->ks_lh, 797*02dd2108Slg150142 "keyspan_close_open_pipes:" 798*02dd2108Slg150142 "the device's product id can't be recognized"); 799*02dd2108Slg150142 800*02dd2108Slg150142 } 801*02dd2108Slg150142 } 80260b08185Syz147069 80360b08185Syz147069 /* 80460b08185Syz147069 * Close global pipes 80560b08185Syz147069 */ 80660b08185Syz147069 void 80760b08185Syz147069 keyspan_close_dev_pipes(keyspan_state_t *ksp) 80860b08185Syz147069 { 80960b08185Syz147069 USB_DPRINTF_L4(DPRINT_CLOSE, ksp->ks_lh, "keyspan_close_dev_pipes"); 81060b08185Syz147069 811*02dd2108Slg150142 switch (ksp->ks_dev_spec.id_product) { 812*02dd2108Slg150142 case KEYSPAN_USA19HS_PID: 813*02dd2108Slg150142 case KEYSPAN_USA49WLC_PID: 81460b08185Syz147069 keyspan_close_one_pipe(&ksp->ks_statin_pipe); 81560b08185Syz147069 keyspan_close_one_pipe(&ksp->ks_ctrlout_pipe); 816*02dd2108Slg150142 817*02dd2108Slg150142 break; 818*02dd2108Slg150142 819*02dd2108Slg150142 case KEYSPAN_USA49WG_PID: 820*02dd2108Slg150142 /* 821*02dd2108Slg150142 * USA_49WG use default control pipe, don't need close it 822*02dd2108Slg150142 * Stop polling before close status in pipe 823*02dd2108Slg150142 */ 824*02dd2108Slg150142 usb_pipe_stop_intr_polling(ksp->ks_statin_pipe.pipe_handle, 825*02dd2108Slg150142 USB_FLAGS_SLEEP); 826*02dd2108Slg150142 keyspan_close_one_pipe(&ksp->ks_statin_pipe); 827*02dd2108Slg150142 828*02dd2108Slg150142 break; 829*02dd2108Slg150142 default: 830*02dd2108Slg150142 USB_DPRINTF_L2(DPRINT_CLOSE, ksp->ks_lh, 831*02dd2108Slg150142 "keyspan_close_dev_pipes:" 832*02dd2108Slg150142 "the device's product id can't be recognized"); 83360b08185Syz147069 } 83460b08185Syz147069 835*02dd2108Slg150142 } 83660b08185Syz147069 83760b08185Syz147069 /* 83860b08185Syz147069 * Open bulk data IN and data OUT pipes for one port. 83960b08185Syz147069 * The status and control pipes are opened in attach because they are global. 84060b08185Syz147069 */ 84160b08185Syz147069 int 84260b08185Syz147069 keyspan_open_port_pipes(keyspan_port_t *kp) 84360b08185Syz147069 { 84460b08185Syz147069 keyspan_state_t *ksp = kp->kp_ksp; 84560b08185Syz147069 int rval; 84660b08185Syz147069 84760b08185Syz147069 USB_DPRINTF_L4(DPRINT_OPEN, kp->kp_lh, "keyspan_open_port_pipes"); 84860b08185Syz147069 849*02dd2108Slg150142 switch (ksp->ks_dev_spec.id_product) { 850*02dd2108Slg150142 case KEYSPAN_USA19HS_PID: 851*02dd2108Slg150142 case KEYSPAN_USA49WLC_PID: 85260b08185Syz147069 rval = keyspan_open_one_pipe(ksp, &kp->kp_datain_pipe); 853*02dd2108Slg150142 854*02dd2108Slg150142 break; 855*02dd2108Slg150142 case KEYSPAN_USA49WG_PID: 856*02dd2108Slg150142 rval = keyspan_open_pipe_datain_usa49wg(ksp, 857*02dd2108Slg150142 &kp->kp_datain_pipe); 858*02dd2108Slg150142 859*02dd2108Slg150142 break; 860*02dd2108Slg150142 default: 861*02dd2108Slg150142 USB_DPRINTF_L2(DPRINT_OPEN, kp->kp_lh, 862*02dd2108Slg150142 "keyspan_open_port_pipes:" 863*02dd2108Slg150142 "the device's product id can't be recognized"); 864*02dd2108Slg150142 } 865*02dd2108Slg150142 86660b08185Syz147069 if (rval != USB_SUCCESS) { 86760b08185Syz147069 86860b08185Syz147069 goto fail; 86960b08185Syz147069 } 87060b08185Syz147069 87160b08185Syz147069 rval = keyspan_open_one_pipe(ksp, &kp->kp_dataout_pipe); 87260b08185Syz147069 if (rval != USB_SUCCESS) { 87360b08185Syz147069 87460b08185Syz147069 goto fail; 87560b08185Syz147069 } 87660b08185Syz147069 87760b08185Syz147069 return (rval); 87860b08185Syz147069 87960b08185Syz147069 fail: 88060b08185Syz147069 USB_DPRINTF_L2(DPRINT_OPEN, kp->kp_lh, 88160b08185Syz147069 "keyspan_open_port_pipes: failed %d", rval); 88260b08185Syz147069 keyspan_close_port_pipes(kp); 88360b08185Syz147069 88460b08185Syz147069 return (rval); 88560b08185Syz147069 } 88660b08185Syz147069 88760b08185Syz147069 void 88860b08185Syz147069 keyspan_close_pipes(keyspan_state_t *ksp) 88960b08185Syz147069 { 89060b08185Syz147069 USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, "keyspan_close_pipes"); 89160b08185Syz147069 89260b08185Syz147069 /* close all ports' pipes first, and then device ctrl/status pipes. */ 89360b08185Syz147069 keyspan_close_open_pipes(ksp); 89460b08185Syz147069 keyspan_close_dev_pipes(ksp); 89560b08185Syz147069 } 89660b08185Syz147069 /* 89760b08185Syz147069 * bulk out common callback 89860b08185Syz147069 */ 89960b08185Syz147069 /*ARGSUSED*/ 90060b08185Syz147069 void 90160b08185Syz147069 keyspan_bulkout_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 90260b08185Syz147069 { 90360b08185Syz147069 keyspan_port_t *kp = (keyspan_port_t *)req->bulk_client_private; 90460b08185Syz147069 keyspan_pipe_t *bulkout = &kp->kp_dataout_pipe; 90560b08185Syz147069 mblk_t *data = req->bulk_data; 90660b08185Syz147069 int data_len; 90760b08185Syz147069 90860b08185Syz147069 data_len = (data) ? MBLKL(data) : 0; 90960b08185Syz147069 91060b08185Syz147069 USB_DPRINTF_L4(DPRINT_OUT_PIPE, bulkout->pipe_lh, 91160b08185Syz147069 "keyspan_bulkout_cb: len=%d cr=%d cb_flags=%x", 91260b08185Syz147069 data_len, req->bulk_completion_reason, req->bulk_cb_flags); 91360b08185Syz147069 914688b07c5Sgc161489 if (req->bulk_completion_reason && data) { 91560b08185Syz147069 91660b08185Syz147069 /* 91760b08185Syz147069 * Data wasn't transfered successfully. 91860b08185Syz147069 * Put data back on the queue. 91960b08185Syz147069 */ 92060b08185Syz147069 keyspan_put_head(&kp->kp_tx_mp, data, kp); 92160b08185Syz147069 92260b08185Syz147069 /* don't release mem in usb_free_bulk_req */ 92360b08185Syz147069 req->bulk_data = NULL; 92460b08185Syz147069 } 92560b08185Syz147069 92660b08185Syz147069 usb_free_bulk_req(req); 92760b08185Syz147069 92860b08185Syz147069 /* if more data available, kick off another transmit */ 92960b08185Syz147069 mutex_enter(&kp->kp_mutex); 93060b08185Syz147069 if (kp->kp_tx_mp == NULL) { 931688b07c5Sgc161489 /* 932688b07c5Sgc161489 * Attach a zero packet if data length is muliple of 64, 933688b07c5Sgc161489 * due to the specification of keyspan_usa19hs. 934688b07c5Sgc161489 */ 935688b07c5Sgc161489 if ((kp->kp_ksp->ks_dev_spec.id_product == 936688b07c5Sgc161489 KEYSPAN_USA19HS_PID) && (data_len == 64)) { 937688b07c5Sgc161489 kp->kp_tx_mp = allocb(0, BPRI_LO); 938688b07c5Sgc161489 if (kp->kp_tx_mp) { 939688b07c5Sgc161489 keyspan_tx_start(kp, NULL); 940688b07c5Sgc161489 mutex_exit(&kp->kp_mutex); 941688b07c5Sgc161489 942688b07c5Sgc161489 return; 943688b07c5Sgc161489 } 944688b07c5Sgc161489 } 945*02dd2108Slg150142 /* no more data, notify waiters */ 946*02dd2108Slg150142 cv_broadcast(&kp->kp_tx_cv); 947*02dd2108Slg150142 mutex_exit(&kp->kp_mutex); 948*02dd2108Slg150142 949*02dd2108Slg150142 /* tx callback for this port */ 950*02dd2108Slg150142 kp->kp_cb.cb_tx(kp->kp_cb.cb_arg); 951*02dd2108Slg150142 } else { 952*02dd2108Slg150142 keyspan_tx_start(kp, NULL); 953*02dd2108Slg150142 mutex_exit(&kp->kp_mutex); 954*02dd2108Slg150142 } 955*02dd2108Slg150142 } 956*02dd2108Slg150142 957*02dd2108Slg150142 /* 958*02dd2108Slg150142 * intr out common callback for USA_49WG port0 only 959*02dd2108Slg150142 */ 960*02dd2108Slg150142 /*ARGSUSED*/ 961*02dd2108Slg150142 void 962*02dd2108Slg150142 keyspan_introut_cb_usa49wg(usb_pipe_handle_t pipe, usb_intr_req_t *req) 963*02dd2108Slg150142 { 964*02dd2108Slg150142 keyspan_port_t *kp = (keyspan_port_t *)req->intr_client_private; 965*02dd2108Slg150142 keyspan_pipe_t *introut = &kp->kp_dataout_pipe; 966*02dd2108Slg150142 mblk_t *data = req->intr_data; 967*02dd2108Slg150142 int data_len; 968*02dd2108Slg150142 969*02dd2108Slg150142 data_len = (data) ? MBLKL(data) : 0; 970*02dd2108Slg150142 971*02dd2108Slg150142 USB_DPRINTF_L4(DPRINT_OUT_PIPE, introut->pipe_lh, 972*02dd2108Slg150142 "keyspan_introut_cb_usa49wg: len=%d cr=%d cb_flags=%x", 973*02dd2108Slg150142 data_len, req->intr_completion_reason, req->intr_cb_flags); 974*02dd2108Slg150142 975*02dd2108Slg150142 if (req->intr_completion_reason && (data_len > 0)) { 976*02dd2108Slg150142 977*02dd2108Slg150142 /* 978*02dd2108Slg150142 * Data wasn't transfered successfully. 979*02dd2108Slg150142 * Put data back on the queue. 980*02dd2108Slg150142 */ 981*02dd2108Slg150142 keyspan_put_head(&kp->kp_tx_mp, data, kp); 982*02dd2108Slg150142 983*02dd2108Slg150142 /* don't release mem in usb_free_bulk_req */ 984*02dd2108Slg150142 req->intr_data = NULL; 985*02dd2108Slg150142 } 986*02dd2108Slg150142 987*02dd2108Slg150142 usb_free_intr_req(req); 988*02dd2108Slg150142 989*02dd2108Slg150142 /* if more data available, kick off another transmit */ 990*02dd2108Slg150142 mutex_enter(&kp->kp_mutex); 991*02dd2108Slg150142 if (kp->kp_tx_mp == NULL) { 99260b08185Syz147069 99360b08185Syz147069 /* no more data, notify waiters */ 99460b08185Syz147069 cv_broadcast(&kp->kp_tx_cv); 99560b08185Syz147069 mutex_exit(&kp->kp_mutex); 99660b08185Syz147069 99760b08185Syz147069 /* tx callback for this port */ 99860b08185Syz147069 kp->kp_cb.cb_tx(kp->kp_cb.cb_arg); 99960b08185Syz147069 } else { 100060b08185Syz147069 keyspan_tx_start(kp, NULL); 100160b08185Syz147069 mutex_exit(&kp->kp_mutex); 100260b08185Syz147069 } 100360b08185Syz147069 } 100460b08185Syz147069 1005c138f478Syz147069 1006c138f478Syz147069 /* For incoming data only. Parse a status byte and return the err code */ 1007c138f478Syz147069 void 1008c138f478Syz147069 keyspan_parse_status(uchar_t *status, uchar_t *err) 1009c138f478Syz147069 { 1010c138f478Syz147069 if (*status & RXERROR_BREAK) { 1011c138f478Syz147069 /* 1012c138f478Syz147069 * Parity and Framing errors only count if they 1013c138f478Syz147069 * occur exclusive of a break being received. 1014c138f478Syz147069 */ 1015c138f478Syz147069 *status &= (uint8_t)(RXERROR_OVERRUN | RXERROR_BREAK); 1016c138f478Syz147069 } 1017c138f478Syz147069 *err |= (*status & RXERROR_OVERRUN) ? DS_OVERRUN_ERR : 0; 1018c138f478Syz147069 *err |= (*status & RXERROR_PARITY) ? DS_PARITY_ERR : 0; 1019c138f478Syz147069 *err |= (*status & RXERROR_FRAMING) ? DS_FRAMING_ERR : 0; 1020c138f478Syz147069 *err |= (*status & RXERROR_BREAK) ? DS_BREAK_ERR : 0; 1021c138f478Syz147069 } 1022c138f478Syz147069 1023*02dd2108Slg150142 /* Bulk in data process function, used by all models */ 102460b08185Syz147069 int 1025*02dd2108Slg150142 keyspan_bulkin_cb_process(keyspan_port_t *kp, 1026*02dd2108Slg150142 uint8_t data_len, uchar_t status, mblk_t *data) 102760b08185Syz147069 { 1028c138f478Syz147069 uchar_t err = 0; 1029c138f478Syz147069 mblk_t *mp; 103060b08185Syz147069 /* 1031c138f478Syz147069 * According to Keyspan spec, if 0x80 bit is clear, there is 1032c138f478Syz147069 * only one status byte at the head of the data buf; if 0x80 bit 1033c138f478Syz147069 * set, then data buf contains alternate status and data bytes; 1034c138f478Syz147069 * In the first case, only OVERRUN err can exist; In the second 1035c138f478Syz147069 * case, there are four kinds of err bits may appear in status. 103660b08185Syz147069 */ 1037c138f478Syz147069 1038c138f478Syz147069 /* if 0x80 bit AND overrun bit are clear, just send up data */ 1039c138f478Syz147069 if (!(status & 0x80) && !(status & RXERROR_OVERRUN)) { 104060b08185Syz147069 1041*02dd2108Slg150142 /* Get rid of the first status byte */ 104260b08185Syz147069 data->b_rptr++; 104360b08185Syz147069 data_len--; 104460b08185Syz147069 1045c138f478Syz147069 } else if (!(status & 0x80)) { 1046c138f478Syz147069 /* If 0x80 bit is clear and overrun bit is set */ 104760b08185Syz147069 1048c138f478Syz147069 keyspan_parse_status(&status, &err); 1049c138f478Syz147069 mutex_exit(&kp->kp_mutex); 1050c138f478Syz147069 if ((mp = allocb(2, BPRI_HI)) == NULL) { 1051c138f478Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, kp->kp_lh, 1052*02dd2108Slg150142 "keyspan_bulkin_cb_process: allocb failed"); 1053c138f478Syz147069 mutex_enter(&kp->kp_mutex); 105460b08185Syz147069 1055c138f478Syz147069 return (0); 1056c138f478Syz147069 } 1057c138f478Syz147069 DB_TYPE(mp) = M_BREAK; 1058c138f478Syz147069 *mp->b_wptr++ = err; 1059c138f478Syz147069 *mp->b_wptr++ = status; 1060c138f478Syz147069 mutex_enter(&kp->kp_mutex); 1061c138f478Syz147069 1062c138f478Syz147069 /* Add to the received list; Send up the err code. */ 1063c138f478Syz147069 keyspan_put_tail(&kp->kp_rx_mp, mp); 1064c138f478Syz147069 1065c138f478Syz147069 /* 1066c138f478Syz147069 * Don't send up the first byte because 1067c138f478Syz147069 * it is a status byte. 1068c138f478Syz147069 */ 1069c138f478Syz147069 data->b_rptr++; 1070c138f478Syz147069 data_len--; 1071c138f478Syz147069 1072c138f478Syz147069 } else { /* 0x80 bit set, there are some errs in the data */ 1073c138f478Syz147069 /* 1074c138f478Syz147069 * Usually, there are at least two bytes, 1075c138f478Syz147069 * one status and one data. 1076c138f478Syz147069 */ 107760b08185Syz147069 if (data_len > 1) { 107860b08185Syz147069 int i = 0; 107960b08185Syz147069 int j = 1; 1080c138f478Syz147069 /* 1081c138f478Syz147069 * In this case, there might be multi status 1082c138f478Syz147069 * bytes. Parse each status byte and move the 1083c138f478Syz147069 * data bytes together. 1084c138f478Syz147069 */ 108560b08185Syz147069 for (j = 1; j < data_len; j += 2) { 1086c138f478Syz147069 status = data->b_rptr[j-1]; 1087c138f478Syz147069 keyspan_parse_status(&status, &err); 1088c138f478Syz147069 1089c138f478Syz147069 /* move the data togeter */ 109060b08185Syz147069 data->b_rptr[i] = data->b_rptr[j]; 109160b08185Syz147069 i++; 109260b08185Syz147069 } 109360b08185Syz147069 data->b_wptr = data->b_rptr + i; 1094c138f478Syz147069 } else { /* There are only one byte in incoming buf */ 1095c138f478Syz147069 keyspan_parse_status(&status, &err); 1096c138f478Syz147069 } 1097c138f478Syz147069 mutex_exit(&kp->kp_mutex); 1098c138f478Syz147069 if ((mp = allocb(2, BPRI_HI)) == NULL) { 1099c138f478Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, kp->kp_lh, 1100*02dd2108Slg150142 "keyspan_bulkin_cb_process: allocb failed"); 1101c138f478Syz147069 mutex_enter(&kp->kp_mutex); 110260b08185Syz147069 1103c138f478Syz147069 return (0); 1104c138f478Syz147069 } 1105c138f478Syz147069 DB_TYPE(mp) = M_BREAK; 1106c138f478Syz147069 *mp->b_wptr++ = err; 1107c138f478Syz147069 if (data_len > 2) { 1108c138f478Syz147069 /* 1109c138f478Syz147069 * There are multiple status bytes in this case. 1110c138f478Syz147069 * Use err as status character since err is got 1111c138f478Syz147069 * by or in all status bytes. 1112c138f478Syz147069 */ 1113c138f478Syz147069 *mp->b_wptr++ = err; 1114c138f478Syz147069 } else { 1115c138f478Syz147069 *mp->b_wptr++ = status; 1116c138f478Syz147069 } 1117c138f478Syz147069 mutex_enter(&kp->kp_mutex); 1118c138f478Syz147069 1119c138f478Syz147069 /* Add to the received list; Send up the err code. */ 1120c138f478Syz147069 keyspan_put_tail(&kp->kp_rx_mp, mp); 1121c138f478Syz147069 1122c138f478Syz147069 if (data_len > 1) { 1123c138f478Syz147069 data_len = data->b_wptr - data->b_rptr; 1124c138f478Syz147069 } 1125c138f478Syz147069 } 112660b08185Syz147069 return (data_len); 112760b08185Syz147069 } 112860b08185Syz147069 112960b08185Syz147069 /* 113060b08185Syz147069 * pipe callbacks 113160b08185Syz147069 * -------------- 113260b08185Syz147069 * 1133*02dd2108Slg150142 * bulk in common callback for USA19HS and USA49WLC model 113460b08185Syz147069 */ 113560b08185Syz147069 /*ARGSUSED*/ 113660b08185Syz147069 int 113760b08185Syz147069 keyspan_bulkin_cb_usa49(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 113860b08185Syz147069 { 113960b08185Syz147069 keyspan_port_t *kp = (keyspan_port_t *)req->bulk_client_private; 114060b08185Syz147069 keyspan_pipe_t *bulkin = &kp->kp_datain_pipe; 114160b08185Syz147069 mblk_t *data = req->bulk_data; 114260b08185Syz147069 uint_t cr = req->bulk_completion_reason; 114360b08185Syz147069 int data_len; 114460b08185Syz147069 114560b08185Syz147069 ASSERT(mutex_owned(&kp->kp_mutex)); 114660b08185Syz147069 114760b08185Syz147069 data_len = (data) ? MBLKL(data) : 0; 114860b08185Syz147069 114960b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 115060b08185Syz147069 "keyspan_bulkin_cb_usa49: len=%d" 115160b08185Syz147069 " cr=%d flags=%x", data_len, cr, req->bulk_cb_flags); 115260b08185Syz147069 115360b08185Syz147069 /* put data on the read queue */ 115460b08185Syz147069 if ((data_len > 0) && (kp->kp_state != KEYSPAN_PORT_CLOSED) && 115560b08185Syz147069 (cr == USB_CR_OK)) { 1156c138f478Syz147069 uchar_t status = data->b_rptr[0]; 115760b08185Syz147069 1158*02dd2108Slg150142 if ((data_len = keyspan_bulkin_cb_process(kp, data_len, 1159*02dd2108Slg150142 status, data)) > 0) { 116060b08185Syz147069 keyspan_put_tail(&kp->kp_rx_mp, data); 116160b08185Syz147069 /* 1162c138f478Syz147069 * the data will not be freed and 116360b08185Syz147069 * will be sent up later. 116460b08185Syz147069 */ 116560b08185Syz147069 req->bulk_data = NULL; 116660b08185Syz147069 } 116760b08185Syz147069 } else { 116860b08185Syz147069 /* usb error happened, so don't send up data */ 116960b08185Syz147069 data_len = 0; 117060b08185Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh, 117160b08185Syz147069 "keyspan_bulkin_cb_usa49: port_state=%d" 117260b08185Syz147069 " b_rptr[0]=%c", kp->kp_state, data->b_rptr[0]); 1173c138f478Syz147069 } 117460b08185Syz147069 if (kp->kp_state != KEYSPAN_PORT_OPEN) { 117560b08185Syz147069 kp->kp_no_more_reads = B_TRUE; 117660b08185Syz147069 } 117760b08185Syz147069 117860b08185Syz147069 return (data_len); 117960b08185Syz147069 } 1180c138f478Syz147069 1181*02dd2108Slg150142 /* 1182*02dd2108Slg150142 * pipe callbacks 1183*02dd2108Slg150142 * -------------- 1184*02dd2108Slg150142 * 1185*02dd2108Slg150142 * bulk in common callback for USA_49WG model 1186*02dd2108Slg150142 */ 1187*02dd2108Slg150142 /*ARGSUSED*/ 1188*02dd2108Slg150142 void 1189*02dd2108Slg150142 keyspan_bulkin_cb_usa49wg(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 1190*02dd2108Slg150142 { 1191*02dd2108Slg150142 keyspan_port_t *kp = (keyspan_port_t *)req->bulk_client_private, 1192*02dd2108Slg150142 *kp_true; 1193*02dd2108Slg150142 keyspan_state_t *ksp = (keyspan_state_t *)kp->kp_ksp; 1194*02dd2108Slg150142 mblk_t *data = req->bulk_data, 1195*02dd2108Slg150142 *mp_data; 1196*02dd2108Slg150142 uint_t cr = req->bulk_completion_reason, 1197*02dd2108Slg150142 port_data_len; 1198*02dd2108Slg150142 int data_len, copy_len; 1199*02dd2108Slg150142 uint8_t port_num, 1200*02dd2108Slg150142 port_cnt = 0, 1201*02dd2108Slg150142 port[4], 1202*02dd2108Slg150142 receive_flag = 1; 1203*02dd2108Slg150142 uint16_t status; 1204*02dd2108Slg150142 unsigned char *old_rptr; 1205*02dd2108Slg150142 1206*02dd2108Slg150142 data_len = (data) ? MBLKL(data) : 0; 1207*02dd2108Slg150142 1208*02dd2108Slg150142 USB_DPRINTF_L2(DPRINT_IN_PIPE, ksp->ks_lh, 1209*02dd2108Slg150142 "keyspan_bulkin_cb_usa49wg: len=%d" 1210*02dd2108Slg150142 " cr=%d flags=%x", data_len, cr, req->bulk_cb_flags); 1211*02dd2108Slg150142 1212*02dd2108Slg150142 /* put data on the read queue */ 1213*02dd2108Slg150142 if ((data_len > 0) && (cr == USB_CR_OK)) { 1214*02dd2108Slg150142 old_rptr = data->b_rptr; 1215*02dd2108Slg150142 while (data->b_rptr < data->b_wptr) { 1216*02dd2108Slg150142 port_num = data->b_rptr[0]; 1217*02dd2108Slg150142 port_data_len = data->b_rptr[1]; 1218*02dd2108Slg150142 status = data->b_rptr[2]; 1219*02dd2108Slg150142 data->b_rptr += 2; 1220*02dd2108Slg150142 1221*02dd2108Slg150142 if (port_num > 3) { 1222*02dd2108Slg150142 USB_DPRINTF_L2(DPRINT_IN_PIPE, ksp->ks_lh, 1223*02dd2108Slg150142 "keyspan_bulkin_cb_usa49wg,port num is not" 1224*02dd2108Slg150142 " correct: port=%d, len=%d, status=%x", 1225*02dd2108Slg150142 port_num, port_data_len, status); 1226*02dd2108Slg150142 1227*02dd2108Slg150142 break; 1228*02dd2108Slg150142 } 1229*02dd2108Slg150142 1230*02dd2108Slg150142 kp_true = &ksp->ks_ports[port_num]; 1231*02dd2108Slg150142 port[++port_cnt] = port_num; 1232*02dd2108Slg150142 mutex_enter(&kp_true->kp_mutex); 1233*02dd2108Slg150142 1234*02dd2108Slg150142 if (kp_true->kp_state != KEYSPAN_PORT_OPEN) { 1235*02dd2108Slg150142 mutex_exit(&kp_true->kp_mutex); 1236*02dd2108Slg150142 1237*02dd2108Slg150142 USB_DPRINTF_L2(DPRINT_IN_PIPE, kp_true->kp_lh, 1238*02dd2108Slg150142 "keyspan_bulkin_cb_usa49wg,port isn't opened"); 1239*02dd2108Slg150142 data->b_rptr += port_data_len; 1240*02dd2108Slg150142 port_cnt--; 1241*02dd2108Slg150142 1242*02dd2108Slg150142 continue; 1243*02dd2108Slg150142 } 1244*02dd2108Slg150142 1245*02dd2108Slg150142 USB_DPRINTF_L2(DPRINT_IN_PIPE, kp_true->kp_lh, 1246*02dd2108Slg150142 "keyspan_bulkin_cb_usa49wg: status=0x%x, len=%d", 1247*02dd2108Slg150142 status, port_data_len); 1248*02dd2108Slg150142 1249*02dd2108Slg150142 if ((copy_len = keyspan_bulkin_cb_process(kp_true, 1250*02dd2108Slg150142 port_data_len, status, data)) > 0) { 1251*02dd2108Slg150142 1252*02dd2108Slg150142 mutex_exit(&kp_true->kp_mutex); 1253*02dd2108Slg150142 if ((mp_data = allocb(copy_len, BPRI_HI)) 1254*02dd2108Slg150142 == NULL) { 1255*02dd2108Slg150142 USB_DPRINTF_L2(DPRINT_IN_PIPE, 1256*02dd2108Slg150142 kp_true->kp_lh, "keyspan_bulkin_cb_" 1257*02dd2108Slg150142 "usa49wg: allocb failed"); 1258*02dd2108Slg150142 1259*02dd2108Slg150142 return; 1260*02dd2108Slg150142 } 1261*02dd2108Slg150142 mutex_enter(&kp_true->kp_mutex); 1262*02dd2108Slg150142 DB_TYPE(mp_data) = M_DATA; 1263*02dd2108Slg150142 bcopy(data->b_rptr, mp_data->b_wptr, copy_len); 1264*02dd2108Slg150142 mp_data->b_wptr += copy_len; 1265*02dd2108Slg150142 if (copy_len < port_data_len -1) { 1266*02dd2108Slg150142 /* 1267*02dd2108Slg150142 * data has multi status bytes, b_wptr 1268*02dd2108Slg150142 * has changed by 1269*02dd2108Slg150142 * keyspan_bulkin_process(), need to 1270*02dd2108Slg150142 * be recovered to old one 1271*02dd2108Slg150142 */ 1272*02dd2108Slg150142 data->b_rptr += port_data_len; 1273*02dd2108Slg150142 data->b_wptr = old_rptr + data_len; 1274*02dd2108Slg150142 } else { 1275*02dd2108Slg150142 data->b_rptr += copy_len; 1276*02dd2108Slg150142 } 1277*02dd2108Slg150142 1278*02dd2108Slg150142 keyspan_put_tail(&kp_true->kp_rx_mp, mp_data); 1279*02dd2108Slg150142 mutex_exit(&kp_true->kp_mutex); 1280*02dd2108Slg150142 } else { 1281*02dd2108Slg150142 mutex_exit(&kp_true->kp_mutex); 1282*02dd2108Slg150142 1283*02dd2108Slg150142 break; 1284*02dd2108Slg150142 } 1285*02dd2108Slg150142 } /* End of while loop */ 1286*02dd2108Slg150142 1287*02dd2108Slg150142 while (port_cnt) { 1288*02dd2108Slg150142 port_num = port[port_cnt--]; 1289*02dd2108Slg150142 kp_true = &ksp->ks_ports[port_num]; 1290*02dd2108Slg150142 mutex_enter(&kp_true->kp_mutex); 1291*02dd2108Slg150142 1292*02dd2108Slg150142 if (kp_true->kp_state != KEYSPAN_PORT_OPEN) { 1293*02dd2108Slg150142 kp_true->kp_no_more_reads = B_TRUE; 1294*02dd2108Slg150142 } 1295*02dd2108Slg150142 if (receive_flag && (!kp_true->kp_no_more_reads)) { 1296*02dd2108Slg150142 mutex_exit(&kp_true->kp_mutex); 1297*02dd2108Slg150142 /* kick off another read */ 1298*02dd2108Slg150142 (void) keyspan_receive_data( 1299*02dd2108Slg150142 &kp_true->kp_datain_pipe, 1300*02dd2108Slg150142 kp_true->kp_read_len, kp_true); 1301*02dd2108Slg150142 1302*02dd2108Slg150142 receive_flag = 0; 1303*02dd2108Slg150142 } else { 1304*02dd2108Slg150142 mutex_exit(&kp_true->kp_mutex); 1305*02dd2108Slg150142 } 1306*02dd2108Slg150142 /* setup rx callback for this port */ 1307*02dd2108Slg150142 kp_true->kp_cb.cb_rx(kp_true->kp_cb.cb_arg); 1308*02dd2108Slg150142 } 1309*02dd2108Slg150142 } else { 1310*02dd2108Slg150142 /* cr != USB_CR_OK, usb error happened */ 1311*02dd2108Slg150142 USB_DPRINTF_L2(DPRINT_IN_PIPE, ksp->ks_lh, 1312*02dd2108Slg150142 "keyspan_bulkin_cb_usa49wg: port=%d, len=%d, status=%x", 1313*02dd2108Slg150142 data->b_rptr[0], data->b_rptr[1], data->b_rptr[2]); 1314*02dd2108Slg150142 1315*02dd2108Slg150142 mutex_enter(&kp->kp_mutex); 1316*02dd2108Slg150142 if (kp->kp_state != KEYSPAN_PORT_OPEN) { 1317*02dd2108Slg150142 kp->kp_no_more_reads = B_TRUE; 1318*02dd2108Slg150142 } 1319*02dd2108Slg150142 if (!kp->kp_no_more_reads) { 1320*02dd2108Slg150142 mutex_exit(&kp->kp_mutex); 1321*02dd2108Slg150142 /* kick off another read */ 1322*02dd2108Slg150142 (void) keyspan_receive_data(&kp->kp_datain_pipe, 1323*02dd2108Slg150142 kp->kp_read_len, kp); 1324*02dd2108Slg150142 } else { 1325*02dd2108Slg150142 mutex_exit(&kp->kp_mutex); 1326*02dd2108Slg150142 } 1327*02dd2108Slg150142 } 1328*02dd2108Slg150142 1329*02dd2108Slg150142 freemsg(data); 1330*02dd2108Slg150142 req->bulk_data = NULL; 1331*02dd2108Slg150142 usb_free_bulk_req(req); 1332*02dd2108Slg150142 1333*02dd2108Slg150142 } 133460b08185Syz147069 133560b08185Syz147069 /* 133660b08185Syz147069 * pipe callbacks 133760b08185Syz147069 * -------------- 133860b08185Syz147069 * 1339*02dd2108Slg150142 * bulk in common callback for USA19HS and USA49WLC 134060b08185Syz147069 */ 134160b08185Syz147069 /*ARGSUSED*/ 134260b08185Syz147069 void 134360b08185Syz147069 keyspan_bulkin_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 134460b08185Syz147069 { 134560b08185Syz147069 keyspan_port_t *kp = (keyspan_port_t *)req->bulk_client_private; 134660b08185Syz147069 int data_len; 134760b08185Syz147069 boolean_t no_more_reads = B_FALSE; 134860b08185Syz147069 134960b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, (&kp->kp_datain_pipe)->pipe_lh, 135060b08185Syz147069 "keyspan_bulkin_cb"); 135160b08185Syz147069 135260b08185Syz147069 mutex_enter(&kp->kp_mutex); 135360b08185Syz147069 135460b08185Syz147069 /* put data on the read queue */ 135560b08185Syz147069 data_len = keyspan_bulkin_cb_usa49(pipe, req); 135660b08185Syz147069 no_more_reads = kp->kp_no_more_reads; 135760b08185Syz147069 135860b08185Syz147069 mutex_exit(&kp->kp_mutex); 135960b08185Syz147069 136060b08185Syz147069 usb_free_bulk_req(req); 136160b08185Syz147069 136260b08185Syz147069 /* kick off another read unless indicated otherwise */ 136360b08185Syz147069 if (!no_more_reads) { 136460b08185Syz147069 (void) keyspan_receive_data(&kp->kp_datain_pipe, 136560b08185Syz147069 kp->kp_read_len, kp); 136660b08185Syz147069 } 136760b08185Syz147069 136860b08185Syz147069 /* setup rx callback for this port */ 136960b08185Syz147069 if (data_len > 0) { 137060b08185Syz147069 kp->kp_cb.cb_rx(kp->kp_cb.cb_arg); 137160b08185Syz147069 } 137260b08185Syz147069 } 137360b08185Syz147069 137460b08185Syz147069 /* 137560b08185Syz147069 * pipe callbacks 137660b08185Syz147069 * -------------- 137760b08185Syz147069 * 137860b08185Syz147069 * bulk in status callback for usa19hs model 137960b08185Syz147069 */ 138060b08185Syz147069 /*ARGSUSED*/ 138160b08185Syz147069 void 138260b08185Syz147069 keyspan_status_cb_usa19hs(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 138360b08185Syz147069 { 138460b08185Syz147069 keyspan_state_t *ksp = (keyspan_state_t *)req->bulk_client_private; 138560b08185Syz147069 keyspan_pipe_t *bulkin = &ksp->ks_statin_pipe; 138660b08185Syz147069 mblk_t *data = req->bulk_data; 138760b08185Syz147069 usb_cr_t cr = req->bulk_completion_reason; 138860b08185Syz147069 int data_len; 138960b08185Syz147069 139060b08185Syz147069 data_len = (data) ? MBLKL(data) : 0; 139160b08185Syz147069 139260b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 139360b08185Syz147069 "keyspan_status_cb_usa19hs: len=%d" 139460b08185Syz147069 " cr=%d flags=%x", data_len, cr, req->bulk_cb_flags); 139560b08185Syz147069 139660b08185Syz147069 /* put data on the read queue */ 139760b08185Syz147069 if ((data_len == 14) && (cr == USB_CR_OK)) { 139860b08185Syz147069 keyspan_port_t *kp = &ksp->ks_ports[0]; 139960b08185Syz147069 keyspan_usa19hs_port_status_msg_t *status_msg = 140060b08185Syz147069 &(kp->kp_status_msg.usa19hs); 140160b08185Syz147069 140260b08185Syz147069 mutex_enter(&kp->kp_mutex); 140360b08185Syz147069 bcopy(data->b_rptr, status_msg, data_len); 140460b08185Syz147069 140560b08185Syz147069 if (status_msg->controlResponse) { 140660b08185Syz147069 kp->kp_status_flag |= KEYSPAN_PORT_CTRLRESP; 140760b08185Syz147069 } else { 140860b08185Syz147069 kp->kp_status_flag &= ~KEYSPAN_PORT_CTRLRESP; 140960b08185Syz147069 } 141060b08185Syz147069 141160b08185Syz147069 if (status_msg->portState & PORTSTATE_ENABLED) { 141260b08185Syz147069 kp->kp_status_flag |= KEYSPAN_PORT_ENABLE; 141360b08185Syz147069 } else { 141460b08185Syz147069 kp->kp_status_flag &= ~KEYSPAN_PORT_ENABLE; 141560b08185Syz147069 } 141660b08185Syz147069 141760b08185Syz147069 if (status_msg->portState & PORTSTATE_TXBREAK) { 141860b08185Syz147069 kp->kp_status_flag |= KEYSPAN_PORT_TXBREAK; 141960b08185Syz147069 } else { 142060b08185Syz147069 kp->kp_status_flag &= ~KEYSPAN_PORT_TXBREAK; 142160b08185Syz147069 } 142260b08185Syz147069 142360b08185Syz147069 if (status_msg->rxBreak) { 142460b08185Syz147069 kp->kp_status_flag |= KEYSPAN_PORT_RXBREAK; 142560b08185Syz147069 } else { 142660b08185Syz147069 kp->kp_status_flag &= ~KEYSPAN_PORT_RXBREAK; 142760b08185Syz147069 } 142860b08185Syz147069 142960b08185Syz147069 if (status_msg->portState & PORTSTATE_LOOPBACK) { 143060b08185Syz147069 kp->kp_status_flag |= KEYSPAN_PORT_LOOPBACK; 143160b08185Syz147069 } else { 143260b08185Syz147069 kp->kp_status_flag &= ~KEYSPAN_PORT_LOOPBACK; 143360b08185Syz147069 } 143460b08185Syz147069 143560b08185Syz147069 /* if msr status changed, then invoke status callback */ 143660b08185Syz147069 if (status_msg->msr & USA_MSR_dCTS || 143760b08185Syz147069 status_msg->msr & USA_MSR_dDSR || 143860b08185Syz147069 status_msg->msr & USA_MSR_dRI || 143960b08185Syz147069 status_msg->msr & USA_MSR_dDCD) { 144060b08185Syz147069 144160b08185Syz147069 mutex_exit(&kp->kp_mutex); 144260b08185Syz147069 kp->kp_cb.cb_status(kp->kp_cb.cb_arg); 144360b08185Syz147069 } else { 144460b08185Syz147069 mutex_exit(&kp->kp_mutex); 144560b08185Syz147069 } 144660b08185Syz147069 } else { 144760b08185Syz147069 144860b08185Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh, 144960b08185Syz147069 "keyspan_status_cb_usa19hs: get status failed, cr=%d" 145060b08185Syz147069 " data_len=%d", cr, data_len); 145160b08185Syz147069 } 145260b08185Syz147069 } 145360b08185Syz147069 1454c138f478Syz147069 145560b08185Syz147069 /* 145660b08185Syz147069 * pipe callbacks 145760b08185Syz147069 * -------------- 145860b08185Syz147069 * 145960b08185Syz147069 * bulk in status callback for usa49 model 146060b08185Syz147069 */ 146160b08185Syz147069 /*ARGSUSED*/ 146260b08185Syz147069 void 146360b08185Syz147069 keyspan_status_cb_usa49(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 146460b08185Syz147069 { 146560b08185Syz147069 keyspan_state_t *ksp = (keyspan_state_t *)req->bulk_client_private; 146660b08185Syz147069 keyspan_pipe_t *bulkin = &ksp->ks_statin_pipe; 146760b08185Syz147069 mblk_t *data = req->bulk_data; 146860b08185Syz147069 uint_t cr = req->bulk_completion_reason; 146960b08185Syz147069 int data_len; 147060b08185Syz147069 147160b08185Syz147069 data_len = (data) ? MBLKL(data) : 0; 147260b08185Syz147069 147360b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 147460b08185Syz147069 "keyspan_status_cb_usa49: len=%d" 147560b08185Syz147069 " cr=%d flags=%x", data_len, cr, req->bulk_cb_flags); 147660b08185Syz147069 147760b08185Syz147069 /* put data on the read queue */ 147860b08185Syz147069 if ((data_len == 11) && (cr == USB_CR_OK)) { 147960b08185Syz147069 keyspan_usa49_port_status_msg_t status_msg; 148060b08185Syz147069 keyspan_port_t *cur_kp; 148160b08185Syz147069 keyspan_usa49_port_status_msg_t *kp_status_msg; 148260b08185Syz147069 boolean_t need_cb = B_FALSE; 148360b08185Syz147069 148460b08185Syz147069 bcopy(data->b_rptr, &status_msg, data_len); 148560b08185Syz147069 if (status_msg.portNumber >= ksp->ks_dev_spec.port_cnt) { 148660b08185Syz147069 148760b08185Syz147069 return; 148860b08185Syz147069 } 148960b08185Syz147069 cur_kp = &ksp->ks_ports[status_msg.portNumber]; 149060b08185Syz147069 kp_status_msg = &(cur_kp->kp_status_msg.usa49); 149160b08185Syz147069 149260b08185Syz147069 mutex_enter(&cur_kp->kp_mutex); 149360b08185Syz147069 149460b08185Syz147069 /* if msr status changed, then need invoke status callback */ 149560b08185Syz147069 if (status_msg.cts != kp_status_msg->cts || 149660b08185Syz147069 status_msg.dsr != kp_status_msg->dsr || 149760b08185Syz147069 status_msg.ri != kp_status_msg->ri || 149860b08185Syz147069 status_msg.dcd != kp_status_msg->dcd) { 149960b08185Syz147069 150060b08185Syz147069 need_cb = B_TRUE; 150160b08185Syz147069 } 150260b08185Syz147069 150360b08185Syz147069 bcopy(&status_msg, kp_status_msg, data_len); 150460b08185Syz147069 150560b08185Syz147069 if (kp_status_msg->controlResponse) { 150660b08185Syz147069 cur_kp->kp_status_flag |= KEYSPAN_PORT_CTRLRESP; 150760b08185Syz147069 } else { 150860b08185Syz147069 cur_kp->kp_status_flag &= ~KEYSPAN_PORT_CTRLRESP; 150960b08185Syz147069 } 151060b08185Syz147069 151160b08185Syz147069 if (!kp_status_msg->rxEnabled) { 151260b08185Syz147069 cur_kp->kp_status_flag |= KEYSPAN_PORT_RXBREAK; 151360b08185Syz147069 } else { 151460b08185Syz147069 cur_kp->kp_status_flag &= ~KEYSPAN_PORT_RXBREAK; 151560b08185Syz147069 } 151660b08185Syz147069 151760b08185Syz147069 mutex_exit(&cur_kp->kp_mutex); 151860b08185Syz147069 151960b08185Syz147069 if (need_cb) { 152060b08185Syz147069 152160b08185Syz147069 cur_kp->kp_cb.cb_status(cur_kp->kp_cb.cb_arg); 152260b08185Syz147069 } 152360b08185Syz147069 } else { 152460b08185Syz147069 152560b08185Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh, 152660b08185Syz147069 "keyspan_status_cb_usa49: get status failed, cr=%d" 152760b08185Syz147069 " data_len=%d", cr, data_len); 152860b08185Syz147069 } 152960b08185Syz147069 } 1530c138f478Syz147069 153160b08185Syz147069 153260b08185Syz147069 /* 153360b08185Syz147069 * pipe callbacks 153460b08185Syz147069 * -------------- 153560b08185Syz147069 * 153660b08185Syz147069 * bulk in callback for status receiving 153760b08185Syz147069 */ 153860b08185Syz147069 /*ARGSUSED*/ 153960b08185Syz147069 void 154060b08185Syz147069 keyspan_status_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 154160b08185Syz147069 { 154260b08185Syz147069 keyspan_state_t *ksp = (keyspan_state_t *)req->bulk_client_private; 154360b08185Syz147069 usb_cr_t cr = req->bulk_completion_reason; 154460b08185Syz147069 154560b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, (&ksp->ks_statin_pipe)->pipe_lh, 154660b08185Syz147069 "keyspan_status_cb"); 154760b08185Syz147069 154860b08185Syz147069 /* put data on the read queue */ 154960b08185Syz147069 switch (ksp->ks_dev_spec.id_product) { 155060b08185Syz147069 case KEYSPAN_USA19HS_PID: 155160b08185Syz147069 keyspan_status_cb_usa19hs(pipe, req); 155260b08185Syz147069 155360b08185Syz147069 break; 155460b08185Syz147069 1555c138f478Syz147069 155660b08185Syz147069 case KEYSPAN_USA49WLC_PID: 155760b08185Syz147069 keyspan_status_cb_usa49(pipe, req); 155860b08185Syz147069 155960b08185Syz147069 break; 1560c138f478Syz147069 156160b08185Syz147069 default: 156260b08185Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, 156360b08185Syz147069 (&ksp->ks_statin_pipe)->pipe_lh, "keyspan_status_cb:" 156460b08185Syz147069 "the device's product id can't be recognized"); 156560b08185Syz147069 156660b08185Syz147069 return; 156760b08185Syz147069 } 156860b08185Syz147069 156960b08185Syz147069 usb_free_bulk_req(req); 157060b08185Syz147069 157160b08185Syz147069 /* kick off another read to receive status */ 157260b08185Syz147069 if ((cr != USB_CR_FLUSHED) && (cr != USB_CR_DEV_NOT_RESP) && 157360b08185Syz147069 keyspan_dev_is_online(ksp)) { 157460b08185Syz147069 if (keyspan_receive_status(ksp) != USB_SUCCESS) { 157560b08185Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, 157660b08185Syz147069 (&ksp->ks_statin_pipe)->pipe_lh, 157760b08185Syz147069 "keyspan_status_cb:" 157860b08185Syz147069 "receive status can't be restarted."); 157960b08185Syz147069 } 158060b08185Syz147069 } else { 158160b08185Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, 158260b08185Syz147069 (&ksp->ks_statin_pipe)->pipe_lh, "keyspan_status_cb:" 158360b08185Syz147069 "get status failed: cr=%d", cr); 158460b08185Syz147069 } 158560b08185Syz147069 } 158660b08185Syz147069 158760b08185Syz147069 /* 158860b08185Syz147069 * Submit data read request (asynchronous). If this function returns 158960b08185Syz147069 * USB_SUCCESS, pipe is acquired and request is sent, otherwise req is free. 159060b08185Syz147069 */ 159160b08185Syz147069 int 159260b08185Syz147069 keyspan_receive_data(keyspan_pipe_t *bulkin, int len, void *cb_arg) 159360b08185Syz147069 { 159460b08185Syz147069 keyspan_state_t *ksp = bulkin->pipe_ksp; 159560b08185Syz147069 usb_bulk_req_t *br; 1596*02dd2108Slg150142 int rval = USB_SUCCESS; 159760b08185Syz147069 159860b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, "keyspan_receive_data:" 159960b08185Syz147069 "len=%d", len); 160060b08185Syz147069 160160b08185Syz147069 ASSERT(!mutex_owned(&bulkin->pipe_mutex)); 160260b08185Syz147069 160360b08185Syz147069 br = usb_alloc_bulk_req(ksp->ks_dip, len, USB_FLAGS_SLEEP); 160460b08185Syz147069 br->bulk_len = len; 160560b08185Syz147069 160660b08185Syz147069 /* No timeout, just wait for data */ 160760b08185Syz147069 br->bulk_timeout = 0; 160860b08185Syz147069 br->bulk_client_private = cb_arg; 160960b08185Syz147069 br->bulk_attributes = USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING; 1610*02dd2108Slg150142 1611*02dd2108Slg150142 switch (ksp->ks_dev_spec.id_product) { 1612*02dd2108Slg150142 case KEYSPAN_USA19HS_PID: 1613*02dd2108Slg150142 case KEYSPAN_USA49WLC_PID: 161460b08185Syz147069 br->bulk_cb = keyspan_bulkin_cb; 161560b08185Syz147069 br->bulk_exc_cb = keyspan_bulkin_cb; 161660b08185Syz147069 1617*02dd2108Slg150142 break; 1618*02dd2108Slg150142 1619*02dd2108Slg150142 case KEYSPAN_USA49WG_PID: 1620*02dd2108Slg150142 br->bulk_cb = keyspan_bulkin_cb_usa49wg; 1621*02dd2108Slg150142 br->bulk_exc_cb = keyspan_bulkin_cb_usa49wg; 1622*02dd2108Slg150142 1623*02dd2108Slg150142 break; 1624*02dd2108Slg150142 1625*02dd2108Slg150142 default: 1626*02dd2108Slg150142 usb_free_bulk_req(br); 1627*02dd2108Slg150142 1628*02dd2108Slg150142 USB_DPRINTF_L2(DPRINT_IN_PIPE, 1629*02dd2108Slg150142 (&ksp->ks_statin_pipe)->pipe_lh, "keyspan_receive_data:" 1630*02dd2108Slg150142 "the device's product id can't be recognized"); 1631*02dd2108Slg150142 1632*02dd2108Slg150142 return (USB_FAILURE); 1633*02dd2108Slg150142 } 1634*02dd2108Slg150142 1635*02dd2108Slg150142 163660b08185Syz147069 rval = usb_pipe_bulk_xfer(bulkin->pipe_handle, br, 0); 163760b08185Syz147069 if (rval != USB_SUCCESS) { 163860b08185Syz147069 usb_free_bulk_req(br); 163960b08185Syz147069 } 164060b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 164160b08185Syz147069 "keyspan_receive_data: rval = %d", rval); 164260b08185Syz147069 return (rval); 164360b08185Syz147069 } 164460b08185Syz147069 164560b08185Syz147069 /* 164660b08185Syz147069 * submit device status read request (asynchronous). 164760b08185Syz147069 */ 164860b08185Syz147069 int 164960b08185Syz147069 keyspan_receive_status(keyspan_state_t *ksp) 165060b08185Syz147069 { 165160b08185Syz147069 keyspan_pipe_t *bulkin = &ksp->ks_statin_pipe; 165260b08185Syz147069 usb_bulk_req_t *br; 165360b08185Syz147069 int rval; 165460b08185Syz147069 165560b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 165660b08185Syz147069 "keyspan_receive_status"); 165760b08185Syz147069 165860b08185Syz147069 ASSERT(!mutex_owned(&bulkin->pipe_mutex)); 165960b08185Syz147069 166060b08185Syz147069 br = usb_alloc_bulk_req(ksp->ks_dip, 32, USB_FLAGS_SLEEP); 166160b08185Syz147069 br->bulk_len = KEYSPAN_STATIN_MAX_LEN; 166260b08185Syz147069 166360b08185Syz147069 /* No timeout, just wait for data */ 166460b08185Syz147069 br->bulk_timeout = 0; 166560b08185Syz147069 br->bulk_client_private = (void *)ksp; 166660b08185Syz147069 br->bulk_attributes = USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING; 166760b08185Syz147069 br->bulk_cb = keyspan_status_cb; 166860b08185Syz147069 br->bulk_exc_cb = keyspan_status_cb; 166960b08185Syz147069 167060b08185Syz147069 rval = usb_pipe_bulk_xfer(bulkin->pipe_handle, br, 0); 167160b08185Syz147069 if (rval != USB_SUCCESS) { 167260b08185Syz147069 usb_free_bulk_req(br); 167360b08185Syz147069 } 167460b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 167560b08185Syz147069 "keyspan_receive_status: rval = %d", rval); 167660b08185Syz147069 return (rval); 167760b08185Syz147069 } 167860b08185Syz147069 167960b08185Syz147069 /* 168060b08185Syz147069 * submit data for transfer (asynchronous) 168160b08185Syz147069 * 168260b08185Syz147069 * if data was sent successfully, 'mpp' will be nulled to indicate 168360b08185Syz147069 * that mblk is consumed by USBA and no longer belongs to the caller. 168460b08185Syz147069 * 168560b08185Syz147069 * if this function returns USB_SUCCESS, pipe is acquired and request 168660b08185Syz147069 * is sent, otherwise pipe is free. 168760b08185Syz147069 */ 168860b08185Syz147069 int 168960b08185Syz147069 keyspan_send_data(keyspan_pipe_t *bulkout, mblk_t **mpp, void *cb_arg) 169060b08185Syz147069 { 169160b08185Syz147069 keyspan_state_t *ksp = bulkout->pipe_ksp; 169260b08185Syz147069 usb_bulk_req_t *br; 169360b08185Syz147069 int rval; 169460b08185Syz147069 169560b08185Syz147069 ASSERT(!mutex_owned(&bulkout->pipe_mutex)); 169660b08185Syz147069 USB_DPRINTF_L4(DPRINT_OUT_PIPE, bulkout->pipe_lh, 169760b08185Syz147069 "keyspan_send_data"); 169860b08185Syz147069 169960b08185Syz147069 br = usb_alloc_bulk_req(ksp->ks_dip, 0, USB_FLAGS_SLEEP); 170060b08185Syz147069 br->bulk_len = MBLKL(*mpp); 170160b08185Syz147069 br->bulk_data = *mpp; 170260b08185Syz147069 br->bulk_timeout = KEYSPAN_BULK_TIMEOUT; 170360b08185Syz147069 br->bulk_client_private = cb_arg; 170460b08185Syz147069 br->bulk_attributes = USB_ATTRS_AUTOCLEARING; 170560b08185Syz147069 br->bulk_cb = keyspan_bulkout_cb; 170660b08185Syz147069 br->bulk_exc_cb = keyspan_bulkout_cb; 170760b08185Syz147069 170860b08185Syz147069 USB_DPRINTF_L3(DPRINT_OUT_PIPE, bulkout->pipe_lh, "keyspan_send_data:" 170960b08185Syz147069 "bulk_len = %d", br->bulk_len); 171060b08185Syz147069 171160b08185Syz147069 rval = usb_pipe_bulk_xfer(bulkout->pipe_handle, br, 0); 171260b08185Syz147069 if (rval == USB_SUCCESS) { 171360b08185Syz147069 171460b08185Syz147069 /* data consumed. The mem will be released in bulkout_cb */ 171560b08185Syz147069 *mpp = NULL; 171660b08185Syz147069 } else { 171760b08185Syz147069 171860b08185Syz147069 /* 171960b08185Syz147069 * Don't free it in usb_free_bulk_req because it will 172060b08185Syz147069 * be linked in keyspan_put_head 172160b08185Syz147069 */ 172260b08185Syz147069 br->bulk_data = NULL; 172360b08185Syz147069 172460b08185Syz147069 usb_free_bulk_req(br); 172560b08185Syz147069 } 172660b08185Syz147069 USB_DPRINTF_L4(DPRINT_OUT_PIPE, bulkout->pipe_lh, 172760b08185Syz147069 "keyspan_send_data: rval = %d", rval); 172860b08185Syz147069 172960b08185Syz147069 return (rval); 173060b08185Syz147069 } 1731*02dd2108Slg150142 1732*02dd2108Slg150142 /* 1733*02dd2108Slg150142 * submit data for transfer (asynchronous) for USA_49WG Port0 only 1734*02dd2108Slg150142 * 1735*02dd2108Slg150142 * if data was sent successfully, 'mpp' will be nulled to indicate 1736*02dd2108Slg150142 * that mblk is consumed by USBA and no longer belongs to the caller. 1737*02dd2108Slg150142 * 1738*02dd2108Slg150142 * if this function returns USB_SUCCESS, pipe is acquired and request 1739*02dd2108Slg150142 * is sent, otherwise pipe is free. 1740*02dd2108Slg150142 */ 1741*02dd2108Slg150142 int 1742*02dd2108Slg150142 keyspan_send_data_port0(keyspan_pipe_t *introut, mblk_t **mpp, void *cb_arg) 1743*02dd2108Slg150142 { 1744*02dd2108Slg150142 keyspan_state_t *ksp = introut->pipe_ksp; 1745*02dd2108Slg150142 usb_intr_req_t *br; 1746*02dd2108Slg150142 int rval; 1747*02dd2108Slg150142 1748*02dd2108Slg150142 ASSERT(!mutex_owned(&introut->pipe_mutex)); 1749*02dd2108Slg150142 USB_DPRINTF_L4(DPRINT_OUT_PIPE, introut->pipe_lh, 1750*02dd2108Slg150142 "keyspan_send_data_port0"); 1751*02dd2108Slg150142 1752*02dd2108Slg150142 br = usb_alloc_intr_req(ksp->ks_dip, 0, USB_FLAGS_SLEEP); 1753*02dd2108Slg150142 br->intr_len = MBLKL(*mpp); 1754*02dd2108Slg150142 br->intr_data = *mpp; 1755*02dd2108Slg150142 br->intr_timeout = KEYSPAN_BULK_TIMEOUT; 1756*02dd2108Slg150142 br->intr_client_private = cb_arg; 1757*02dd2108Slg150142 br->intr_cb = keyspan_introut_cb_usa49wg; 1758*02dd2108Slg150142 br->intr_exc_cb = keyspan_introut_cb_usa49wg; 1759*02dd2108Slg150142 1760*02dd2108Slg150142 USB_DPRINTF_L3(DPRINT_OUT_PIPE, introut->pipe_lh, 1761*02dd2108Slg150142 "keyspan_send_data_port0: intr_len = %d", 1762*02dd2108Slg150142 br->intr_len); 1763*02dd2108Slg150142 1764*02dd2108Slg150142 rval = usb_pipe_intr_xfer(introut->pipe_handle, br, 0); 1765*02dd2108Slg150142 if (rval == USB_SUCCESS) { 1766*02dd2108Slg150142 1767*02dd2108Slg150142 /* 1768*02dd2108Slg150142 * data consumed. The mem will be released in 1769*02dd2108Slg150142 * introut_cb_usa49wg 1770*02dd2108Slg150142 */ 1771*02dd2108Slg150142 *mpp = NULL; 1772*02dd2108Slg150142 } else { 1773*02dd2108Slg150142 br->intr_data = NULL; 1774*02dd2108Slg150142 1775*02dd2108Slg150142 usb_free_intr_req(br); 1776*02dd2108Slg150142 } 1777*02dd2108Slg150142 USB_DPRINTF_L4(DPRINT_OUT_PIPE, introut->pipe_lh, 1778*02dd2108Slg150142 "keyspan_send_data_port0: rval = %d", rval); 1779*02dd2108Slg150142 1780*02dd2108Slg150142 return (rval); 1781*02dd2108Slg150142 } 1782*02dd2108Slg150142 1783*02dd2108Slg150142 /* 1784*02dd2108Slg150142 * pipe callbacks 1785*02dd2108Slg150142 * -------------- 1786*02dd2108Slg150142 * 1787*02dd2108Slg150142 * bulk in status callback for USA_49WG model 1788*02dd2108Slg150142 */ 1789*02dd2108Slg150142 /*ARGSUSED*/ 1790*02dd2108Slg150142 void 1791*02dd2108Slg150142 keyspan_status_cb_usa49wg(usb_pipe_handle_t pipe, usb_intr_req_t *req) 1792*02dd2108Slg150142 { 1793*02dd2108Slg150142 keyspan_state_t *ksp = (keyspan_state_t *)req->intr_client_private; 1794*02dd2108Slg150142 keyspan_pipe_t *intr = &ksp->ks_statin_pipe; 1795*02dd2108Slg150142 mblk_t *data = req->intr_data; 1796*02dd2108Slg150142 uint_t cr = req->intr_completion_reason; 1797*02dd2108Slg150142 int data_len; 1798*02dd2108Slg150142 1799*02dd2108Slg150142 data_len = (data) ? MBLKL(data) : 0; 1800*02dd2108Slg150142 1801*02dd2108Slg150142 USB_DPRINTF_L4(DPRINT_IN_PIPE, intr->pipe_lh, 1802*02dd2108Slg150142 "keyspan_status_cb_usa49wg: len=%d" 1803*02dd2108Slg150142 " cr=%d flags=%x", data_len, cr, req->intr_cb_flags); 1804*02dd2108Slg150142 1805*02dd2108Slg150142 /* put data on the read queue */ 1806*02dd2108Slg150142 if ((data_len == 11) && (cr == USB_CR_OK)) { 1807*02dd2108Slg150142 keyspan_usa49_port_status_msg_t status_msg; 1808*02dd2108Slg150142 keyspan_port_t *cur_kp; 1809*02dd2108Slg150142 keyspan_usa49_port_status_msg_t *kp_status_msg; 1810*02dd2108Slg150142 boolean_t need_cb = B_FALSE; 1811*02dd2108Slg150142 1812*02dd2108Slg150142 bcopy(data->b_rptr, &status_msg, data_len); 1813*02dd2108Slg150142 if (status_msg.portNumber >= ksp->ks_dev_spec.port_cnt) { 1814*02dd2108Slg150142 1815*02dd2108Slg150142 return; 1816*02dd2108Slg150142 } 1817*02dd2108Slg150142 cur_kp = &ksp->ks_ports[status_msg.portNumber]; 1818*02dd2108Slg150142 kp_status_msg = &(cur_kp->kp_status_msg.usa49); 1819*02dd2108Slg150142 1820*02dd2108Slg150142 mutex_enter(&cur_kp->kp_mutex); 1821*02dd2108Slg150142 1822*02dd2108Slg150142 /* if msr status changed, then need invoke status callback */ 1823*02dd2108Slg150142 if (status_msg.cts != kp_status_msg->cts || 1824*02dd2108Slg150142 status_msg.dsr != kp_status_msg->dsr || 1825*02dd2108Slg150142 status_msg.ri != kp_status_msg->ri || 1826*02dd2108Slg150142 status_msg.dcd != kp_status_msg->dcd) { 1827*02dd2108Slg150142 1828*02dd2108Slg150142 need_cb = B_TRUE; 1829*02dd2108Slg150142 } 1830*02dd2108Slg150142 1831*02dd2108Slg150142 bcopy(&status_msg, kp_status_msg, data_len); 1832*02dd2108Slg150142 1833*02dd2108Slg150142 if (kp_status_msg->controlResponse) { 1834*02dd2108Slg150142 cur_kp->kp_status_flag |= KEYSPAN_PORT_CTRLRESP; 1835*02dd2108Slg150142 } else { 1836*02dd2108Slg150142 cur_kp->kp_status_flag &= ~KEYSPAN_PORT_CTRLRESP; 1837*02dd2108Slg150142 } 1838*02dd2108Slg150142 1839*02dd2108Slg150142 if (!kp_status_msg->rxEnabled) { 1840*02dd2108Slg150142 cur_kp->kp_status_flag |= KEYSPAN_PORT_RXBREAK; 1841*02dd2108Slg150142 } else { 1842*02dd2108Slg150142 cur_kp->kp_status_flag &= ~KEYSPAN_PORT_RXBREAK; 1843*02dd2108Slg150142 } 1844*02dd2108Slg150142 1845*02dd2108Slg150142 mutex_exit(&cur_kp->kp_mutex); 1846*02dd2108Slg150142 1847*02dd2108Slg150142 if (need_cb) { 1848*02dd2108Slg150142 1849*02dd2108Slg150142 cur_kp->kp_cb.cb_status(cur_kp->kp_cb.cb_arg); 1850*02dd2108Slg150142 } 1851*02dd2108Slg150142 } else { 1852*02dd2108Slg150142 1853*02dd2108Slg150142 USB_DPRINTF_L2(DPRINT_IN_PIPE, intr->pipe_lh, 1854*02dd2108Slg150142 "keyspan_status_cb_usa49wg: get status failed, cr=%d" 1855*02dd2108Slg150142 " data_len=%d", cr, data_len); 1856*02dd2108Slg150142 } 1857*02dd2108Slg150142 } 1858*02dd2108Slg150142 1859*02dd2108Slg150142 /* 1860*02dd2108Slg150142 * pipe callbacks 1861*02dd2108Slg150142 * -------------- 1862*02dd2108Slg150142 * 1863*02dd2108Slg150142 * intr in callback for status receiving for USA_49WG model only 1864*02dd2108Slg150142 */ 1865*02dd2108Slg150142 /*ARGSUSED*/ 1866*02dd2108Slg150142 void 1867*02dd2108Slg150142 keyspan_intr_cb_usa49wg(usb_pipe_handle_t pipe, usb_intr_req_t *req) 1868*02dd2108Slg150142 { 1869*02dd2108Slg150142 keyspan_state_t *ksp = (keyspan_state_t *)req->intr_client_private; 1870*02dd2108Slg150142 usb_cr_t cr = req->intr_completion_reason; 1871*02dd2108Slg150142 1872*02dd2108Slg150142 USB_DPRINTF_L4(DPRINT_IN_PIPE, (&ksp->ks_statin_pipe)->pipe_lh, 1873*02dd2108Slg150142 "keyspan_intr_cb_usa49wg: cr=%d", cr); 1874*02dd2108Slg150142 1875*02dd2108Slg150142 /* put data on the read queue */ 1876*02dd2108Slg150142 (void) keyspan_status_cb_usa49wg(pipe, req); 1877*02dd2108Slg150142 1878*02dd2108Slg150142 usb_free_intr_req(req); 1879*02dd2108Slg150142 } 1880*02dd2108Slg150142 1881*02dd2108Slg150142 /* 1882*02dd2108Slg150142 * pipe callbacks 1883*02dd2108Slg150142 * -------------- 1884*02dd2108Slg150142 * 1885*02dd2108Slg150142 * intr in exception callback for status receiving for USA_49WG model only 1886*02dd2108Slg150142 */ 1887*02dd2108Slg150142 /*ARGSUSED*/ 1888*02dd2108Slg150142 void 1889*02dd2108Slg150142 keyspan_intr_ex_cb_usa49wg(usb_pipe_handle_t pipe, usb_intr_req_t *req) 1890*02dd2108Slg150142 { 1891*02dd2108Slg150142 keyspan_state_t *ksp = (keyspan_state_t *)req->intr_client_private; 1892*02dd2108Slg150142 usb_cr_t cr = req->intr_completion_reason; 1893*02dd2108Slg150142 1894*02dd2108Slg150142 USB_DPRINTF_L4(DPRINT_IN_PIPE, (&ksp->ks_statin_pipe)->pipe_lh, 1895*02dd2108Slg150142 "keyspan_intr_ex_cb_usa49wg: cr=%d", cr); 1896*02dd2108Slg150142 1897*02dd2108Slg150142 usb_free_intr_req(req); 1898*02dd2108Slg150142 1899*02dd2108Slg150142 if ((cr != USB_CR_PIPE_CLOSING) && (cr != USB_CR_STOPPED_POLLING) && 1900*02dd2108Slg150142 (cr != USB_CR_FLUSHED) && (cr != USB_CR_DEV_NOT_RESP) && 1901*02dd2108Slg150142 (cr != USB_CR_PIPE_RESET) && keyspan_dev_is_online(ksp)) { 1902*02dd2108Slg150142 keyspan_pipe_start_polling(&ksp->ks_statin_pipe); 1903*02dd2108Slg150142 } else { 1904*02dd2108Slg150142 USB_DPRINTF_L2(DPRINT_IN_PIPE, 1905*02dd2108Slg150142 (&ksp->ks_statin_pipe)->pipe_lh, "keyspan_intr_ex_cb_usa49wg:" 1906*02dd2108Slg150142 "get status failed: cr=%d", cr); 1907*02dd2108Slg150142 } 1908*02dd2108Slg150142 } 1909*02dd2108Slg150142 1910*02dd2108Slg150142 /* 1911*02dd2108Slg150142 * start polling on the interrupt pipe for USA_49WG model only 1912*02dd2108Slg150142 */ 1913*02dd2108Slg150142 void 1914*02dd2108Slg150142 keyspan_pipe_start_polling(keyspan_pipe_t *intr) 1915*02dd2108Slg150142 { 1916*02dd2108Slg150142 usb_intr_req_t *br; 1917*02dd2108Slg150142 keyspan_state_t *ksp = intr->pipe_ksp; 1918*02dd2108Slg150142 int rval; 1919*02dd2108Slg150142 1920*02dd2108Slg150142 USB_DPRINTF_L4(DPRINT_IN_PIPE, ksp->ks_lh, 1921*02dd2108Slg150142 "keyspan_pipe_start_polling"); 1922*02dd2108Slg150142 1923*02dd2108Slg150142 br = usb_alloc_intr_req(ksp->ks_dip, 0, USB_FLAGS_SLEEP); 1924*02dd2108Slg150142 1925*02dd2108Slg150142 /* 1926*02dd2108Slg150142 * If it is in interrupt context, usb_alloc_intr_req will return NULL if 1927*02dd2108Slg150142 * called with SLEEP flag. 1928*02dd2108Slg150142 */ 1929*02dd2108Slg150142 if (!br) { 1930*02dd2108Slg150142 USB_DPRINTF_L2(DPRINT_IN_PIPE, ksp->ks_lh, 1931*02dd2108Slg150142 "keyspan_pipe_start_polling: alloc req failed."); 1932*02dd2108Slg150142 1933*02dd2108Slg150142 return; 1934*02dd2108Slg150142 } 1935*02dd2108Slg150142 br->intr_attributes = USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING; 1936*02dd2108Slg150142 br->intr_len = intr->pipe_ep_descr.wMaxPacketSize; 1937*02dd2108Slg150142 br->intr_client_private = (void *)ksp; 1938*02dd2108Slg150142 1939*02dd2108Slg150142 br->intr_cb = keyspan_intr_cb_usa49wg; 1940*02dd2108Slg150142 br->intr_exc_cb = keyspan_intr_ex_cb_usa49wg; 1941*02dd2108Slg150142 1942*02dd2108Slg150142 1943*02dd2108Slg150142 rval = usb_pipe_intr_xfer(intr->pipe_handle, br, USB_FLAGS_SLEEP); 1944*02dd2108Slg150142 1945*02dd2108Slg150142 mutex_enter(&intr->pipe_mutex); 1946*02dd2108Slg150142 if (rval != USB_SUCCESS) { 1947*02dd2108Slg150142 usb_free_intr_req(br); 1948*02dd2108Slg150142 intr->pipe_state = KEYSPAN_PIPE_CLOSED; 1949*02dd2108Slg150142 1950*02dd2108Slg150142 USB_DPRINTF_L3(DPRINT_IN_PIPE, ksp->ks_lh, 1951*02dd2108Slg150142 "keyspan_pipe_start_polling: failed (%d)", rval); 1952*02dd2108Slg150142 } else { 1953*02dd2108Slg150142 intr->pipe_state = KEYSPAN_PIPE_OPEN; 1954*02dd2108Slg150142 } 1955*02dd2108Slg150142 1956*02dd2108Slg150142 mutex_exit(&intr->pipe_mutex); 1957*02dd2108Slg150142 } 1958