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 /* 22*77e51571Sgongtian zhao - Sun Microsystems - Beijing China * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 2360b08185Syz147069 * Use is subject to license terms. 2460b08185Syz147069 */ 2560b08185Syz147069 2660b08185Syz147069 2760b08185Syz147069 /* 2860b08185Syz147069 * 2960b08185Syz147069 * keyspanport pipe routines (mostly device-neutral) 3060b08185Syz147069 * 3160b08185Syz147069 */ 3260b08185Syz147069 #include <sys/types.h> 3360b08185Syz147069 #include <sys/param.h> 3460b08185Syz147069 #include <sys/conf.h> 3560b08185Syz147069 #include <sys/stream.h> 3660b08185Syz147069 #include <sys/strsun.h> 3760b08185Syz147069 #include <sys/termio.h> 3860b08185Syz147069 #include <sys/ddi.h> 3960b08185Syz147069 #include <sys/sunddi.h> 4060b08185Syz147069 4160b08185Syz147069 #include <sys/usb/usba.h> 4260b08185Syz147069 #include <sys/usb/clients/usbser/usbser_keyspan/keyspan_var.h> 4360b08185Syz147069 #include <sys/usb/clients/usbser/usbser_keyspan/keyspan_pipe.h> 4460b08185Syz147069 4560b08185Syz147069 /* 4660b08185Syz147069 * initialize pipe structure with the given parameters 4760b08185Syz147069 */ 4860b08185Syz147069 static void 4960b08185Syz147069 keyspan_init_one_pipe(keyspan_state_t *ksp, keyspan_port_t *kp, 5060b08185Syz147069 keyspan_pipe_t *pipe) 5160b08185Syz147069 { 5260b08185Syz147069 usb_pipe_policy_t *policy; 5360b08185Syz147069 5460b08185Syz147069 USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, "keyspan_init_one_pipe: " 5560b08185Syz147069 "pipe = %p, pipe_stat %x", (void *)pipe, pipe->pipe_state); 5660b08185Syz147069 5760b08185Syz147069 /* init sync primitives */ 5860b08185Syz147069 mutex_init(&pipe->pipe_mutex, NULL, MUTEX_DRIVER, (void *)NULL); 5960b08185Syz147069 6060b08185Syz147069 /* init pipe policy */ 6160b08185Syz147069 policy = &pipe->pipe_policy; 6260b08185Syz147069 policy->pp_max_async_reqs = 2; 6360b08185Syz147069 6460b08185Syz147069 pipe->pipe_ksp = ksp; 6560b08185Syz147069 if (kp == NULL) { 6660b08185Syz147069 /* globle pipes should have device log handle */ 6760b08185Syz147069 pipe->pipe_lh = ksp->ks_lh; 6860b08185Syz147069 } else { 6960b08185Syz147069 /* port pipes should have port log handle */ 7060b08185Syz147069 pipe->pipe_lh = kp->kp_lh; 7160b08185Syz147069 } 7260b08185Syz147069 7360b08185Syz147069 pipe->pipe_state = KEYSPAN_PIPE_CLOSED; 7460b08185Syz147069 } 7560b08185Syz147069 7660b08185Syz147069 7760b08185Syz147069 static void 7860b08185Syz147069 keyspan_fini_one_pipe(keyspan_pipe_t *pipe) 7960b08185Syz147069 { 8060b08185Syz147069 USB_DPRINTF_L4(DPRINT_OPEN, pipe->pipe_ksp->ks_lh, 8160b08185Syz147069 "keyspan_fini_one_pipe: pipe_stat %x", pipe->pipe_state); 8260b08185Syz147069 8360b08185Syz147069 if (pipe->pipe_state != KEYSPAN_PIPE_NOT_INIT) { 8460b08185Syz147069 mutex_destroy(&pipe->pipe_mutex); 8560b08185Syz147069 pipe->pipe_state = KEYSPAN_PIPE_NOT_INIT; 8660b08185Syz147069 } 8760b08185Syz147069 } 8860b08185Syz147069 8960b08185Syz147069 /* 9060b08185Syz147069 * Lookup the endpoints defined in the spec; 9160b08185Syz147069 * Allocate resources, initialize pipe structures. 9260b08185Syz147069 * All are bulk pipes, including data in/out, cmd/status pipes. 9360b08185Syz147069 */ 9460b08185Syz147069 int 9560b08185Syz147069 keyspan_init_pipes(keyspan_state_t *ksp) 9660b08185Syz147069 { 9760b08185Syz147069 usb_client_dev_data_t *dev_data = ksp->ks_dev_data; 9860b08185Syz147069 int ifc, alt, i, j, k = 0; 9960b08185Syz147069 uint8_t port_cnt = ksp->ks_dev_spec.port_cnt; 10060b08185Syz147069 uint8_t ep_addr, ep_cnt; 10160b08185Syz147069 usb_ep_data_t *dataout[KEYSPAN_MAX_PORT_NUM], 10260b08185Syz147069 *datain[KEYSPAN_MAX_PORT_NUM], 10360b08185Syz147069 *status = NULL, *ctrl = NULL, *tmp_ep; 10460b08185Syz147069 usb_alt_if_data_t *alt_data; 10560b08185Syz147069 usb_if_data_t *if_data; 10660b08185Syz147069 10760b08185Syz147069 10860b08185Syz147069 ifc = dev_data->dev_curr_if; 10960b08185Syz147069 alt = 0; 11060b08185Syz147069 if_data = &dev_data->dev_curr_cfg->cfg_if[ifc]; 11160b08185Syz147069 alt_data = &if_data->if_alt[alt]; 11260b08185Syz147069 11360b08185Syz147069 /* 11460b08185Syz147069 * The actual EP number (indicated by bNumEndpoints) is more than 11560b08185Syz147069 * those defined in spec. We have to match those we need according 11660b08185Syz147069 * to EP addresses. And we'll lookup In EPs and Out EPs separately. 11760b08185Syz147069 */ 11860b08185Syz147069 ep_cnt = (alt_data->altif_descr.bNumEndpoints + 1) / 2; 11960b08185Syz147069 12060b08185Syz147069 /* 12160b08185Syz147069 * get DIR_IN EP descriptors, and then match with EP addresses. 12260b08185Syz147069 * Different keyspan devices may has different EP addresses. 12360b08185Syz147069 */ 12460b08185Syz147069 for (i = 0; i < ep_cnt; i++) { 12560b08185Syz147069 tmp_ep = usb_lookup_ep_data(ksp->ks_dip, dev_data, ifc, alt, i, 12660b08185Syz147069 USB_EP_ATTR_BULK, USB_EP_DIR_IN); 12760b08185Syz147069 if (tmp_ep == NULL) { 12860b08185Syz147069 USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh, 12960b08185Syz147069 "keyspan_init_pipes: can't find bulk in ep, i=%d," 13060b08185Syz147069 "ep_cnt=%d", i, ep_cnt); 13160b08185Syz147069 13260b08185Syz147069 continue; 13360b08185Syz147069 } 13460b08185Syz147069 ep_addr = tmp_ep->ep_descr.bEndpointAddress; 13560b08185Syz147069 13660b08185Syz147069 USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh, "keyspan_init_pipes: " 13760b08185Syz147069 "ep_addr =%x, stat_ep_addr=%x, i=%d", ep_addr, 13860b08185Syz147069 ksp->ks_dev_spec.stat_ep_addr, i); 13960b08185Syz147069 14060b08185Syz147069 /* match the status EP */ 14160b08185Syz147069 if (ep_addr == ksp->ks_dev_spec.stat_ep_addr) { 14260b08185Syz147069 status = tmp_ep; 14360b08185Syz147069 14460b08185Syz147069 continue; 14560b08185Syz147069 } 14660b08185Syz147069 14760b08185Syz147069 /* match the EPs of the ports */ 14860b08185Syz147069 for (j = 0; j < port_cnt; j++) { 14960b08185Syz147069 USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh, 15060b08185Syz147069 "keyspan_init_pipes: try to match bulk in data ep," 15160b08185Syz147069 " j=%d", j); 15260b08185Syz147069 if (ep_addr == ksp->ks_dev_spec.datain_ep_addr[j]) { 15360b08185Syz147069 datain[j] = tmp_ep; 15460b08185Syz147069 k++; 15560b08185Syz147069 USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh, 15660b08185Syz147069 "keyspan_init_pipes: matched a bulk in" 15760b08185Syz147069 " data ep"); 15860b08185Syz147069 15960b08185Syz147069 break; 16060b08185Syz147069 } 16160b08185Syz147069 } 16260b08185Syz147069 16360b08185Syz147069 /* if have matched all the necessary endpoints, break out */ 16460b08185Syz147069 if (k >= port_cnt && status != NULL) { 16560b08185Syz147069 16660b08185Syz147069 break; 16760b08185Syz147069 } 16860b08185Syz147069 16960b08185Syz147069 USB_DPRINTF_L4(DPRINT_ATTACH, ksp->ks_lh, "keyspan_init_pipes: " 17060b08185Syz147069 "try to match bulk in data ep, j=%d", j); 17160b08185Syz147069 17260b08185Syz147069 if (j == port_cnt) { 17360b08185Syz147069 /* this ep can't be matched by any addr */ 17460b08185Syz147069 USB_DPRINTF_L4(DPRINT_ATTACH, ksp->ks_lh, 17560b08185Syz147069 "keyspan_init_pipes: can't match bulk in ep," 17660b08185Syz147069 " addr =%x,", ep_addr); 17760b08185Syz147069 } 17860b08185Syz147069 } 17960b08185Syz147069 18060b08185Syz147069 if (k != port_cnt || status == NULL) { 18160b08185Syz147069 18260b08185Syz147069 /* Some of the necessary IN endpoints are not matched */ 18360b08185Syz147069 USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh, 18460b08185Syz147069 "keyspan_init_pipes: matched %d data in endpoints," 18560b08185Syz147069 " not enough", k); 18660b08185Syz147069 18760b08185Syz147069 return (USB_FAILURE); 18860b08185Syz147069 } 18960b08185Syz147069 19060b08185Syz147069 k = 0; 19160b08185Syz147069 19260b08185Syz147069 /* 19360b08185Syz147069 * get DIR_OUT EP descriptors, and then match with ep addrs. 19460b08185Syz147069 * different keyspan devices may has different ep addresses. 19560b08185Syz147069 */ 19660b08185Syz147069 for (i = 0; i < ep_cnt; i++) { 19760b08185Syz147069 tmp_ep = usb_lookup_ep_data(ksp->ks_dip, dev_data, ifc, alt, i, 19860b08185Syz147069 USB_EP_ATTR_BULK, USB_EP_DIR_OUT); 19960b08185Syz147069 if (tmp_ep == NULL) { 20060b08185Syz147069 USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh, 20160b08185Syz147069 "keyspan_init_pipes: can't find bulk out ep, i=%d," 20260b08185Syz147069 "ep_cnt=%d", i, ep_cnt); 20360b08185Syz147069 20460b08185Syz147069 continue; 20560b08185Syz147069 } 20660b08185Syz147069 ep_addr = tmp_ep->ep_descr.bEndpointAddress; 20760b08185Syz147069 20860b08185Syz147069 /* match the status ep */ 20960b08185Syz147069 if (ep_addr == ksp->ks_dev_spec.ctrl_ep_addr) { 21060b08185Syz147069 ctrl = tmp_ep; 21160b08185Syz147069 21260b08185Syz147069 continue; 21360b08185Syz147069 } 21460b08185Syz147069 21560b08185Syz147069 /* match the ep of the ports */ 21660b08185Syz147069 for (j = 0; j < port_cnt; j++) { 21760b08185Syz147069 if (ep_addr == ksp->ks_dev_spec.dataout_ep_addr[j]) { 21860b08185Syz147069 dataout[j] = tmp_ep; 21960b08185Syz147069 k++; 22060b08185Syz147069 22160b08185Syz147069 break; 22260b08185Syz147069 } 22360b08185Syz147069 } 22460b08185Syz147069 /* if have matched all the necessary endpoints, break out */ 22560b08185Syz147069 if (k >= port_cnt && ctrl != NULL) { 22660b08185Syz147069 22760b08185Syz147069 break; 22860b08185Syz147069 } 22960b08185Syz147069 23060b08185Syz147069 if (j == port_cnt) { 23160b08185Syz147069 23260b08185Syz147069 /* this ep can't be matched by any addr */ 23360b08185Syz147069 USB_DPRINTF_L4(DPRINT_ATTACH, ksp->ks_lh, 23460b08185Syz147069 "keyspan_init_pipes: can't match bulk out ep," 23560b08185Syz147069 " ep_addr =%x", ep_addr); 23660b08185Syz147069 23760b08185Syz147069 } 23860b08185Syz147069 } 23960b08185Syz147069 24060b08185Syz147069 if (k != port_cnt || ctrl == NULL) { 24160b08185Syz147069 /* Not all the necessary OUT endpoints are matched */ 24260b08185Syz147069 USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh, 24360b08185Syz147069 "keyspan_init_pipes: matched %d data in endpoints," 24460b08185Syz147069 " not enough", k); 24560b08185Syz147069 24660b08185Syz147069 return (USB_FAILURE); 24760b08185Syz147069 } 24860b08185Syz147069 24960b08185Syz147069 mutex_enter(&ksp->ks_mutex); 25060b08185Syz147069 25160b08185Syz147069 /* 25260b08185Syz147069 * Device globle pipes: a bulk in pipe for status and a bulk out 25360b08185Syz147069 * pipe for controle cmd. 25460b08185Syz147069 */ 25560b08185Syz147069 ksp->ks_statin_pipe.pipe_ep_descr = status->ep_descr; 25660b08185Syz147069 keyspan_init_one_pipe(ksp, NULL, &ksp->ks_statin_pipe); 25760b08185Syz147069 25860b08185Syz147069 ksp->ks_ctrlout_pipe.pipe_ep_descr = ctrl->ep_descr; 25960b08185Syz147069 keyspan_init_one_pipe(ksp, NULL, &ksp->ks_ctrlout_pipe); 26060b08185Syz147069 26160b08185Syz147069 /* for data in/out pipes of each port */ 26260b08185Syz147069 for (i = 0; i < port_cnt; i++) { 26360b08185Syz147069 26460b08185Syz147069 ksp->ks_ports[i].kp_datain_pipe.pipe_ep_descr = 26560b08185Syz147069 datain[i]->ep_descr; 26660b08185Syz147069 keyspan_init_one_pipe(ksp, &ksp->ks_ports[i], 26760b08185Syz147069 &ksp->ks_ports[i].kp_datain_pipe); 26860b08185Syz147069 26960b08185Syz147069 ksp->ks_ports[i].kp_dataout_pipe.pipe_ep_descr = 27060b08185Syz147069 dataout[i]->ep_descr; 27160b08185Syz147069 keyspan_init_one_pipe(ksp, &ksp->ks_ports[i], 27260b08185Syz147069 &ksp->ks_ports[i].kp_dataout_pipe); 27360b08185Syz147069 } 27460b08185Syz147069 27560b08185Syz147069 mutex_exit(&ksp->ks_mutex); 27660b08185Syz147069 27760b08185Syz147069 return (USB_SUCCESS); 27860b08185Syz147069 } 27902dd2108Slg150142 /* 28002dd2108Slg150142 * For USA_49WG only. 28102dd2108Slg150142 * Lookup the endpoints defined in the spec. 28202dd2108Slg150142 * Allocate resources, initialize pipe structures. 28302dd2108Slg150142 * There are 6 EPs, 3 bulk out Eps, 1 bulk in EP, 1 intr in EP, 1 intr out EP 28402dd2108Slg150142 */ 28502dd2108Slg150142 int 28602dd2108Slg150142 keyspan_init_pipes_usa49wg(keyspan_state_t *ksp) 28702dd2108Slg150142 { 28802dd2108Slg150142 usb_client_dev_data_t *dev_data = ksp->ks_dev_data; 28902dd2108Slg150142 int ifc, alt, i, j = 0; 29002dd2108Slg150142 uint8_t port_cnt = ksp->ks_dev_spec.port_cnt; 29102dd2108Slg150142 uint8_t ep_addr; 29202dd2108Slg150142 usb_ep_data_t *dataout[KEYSPAN_MAX_PORT_NUM], 29302dd2108Slg150142 *datain[KEYSPAN_MAX_PORT_NUM], 29402dd2108Slg150142 *status = NULL, *tmp_ep; 29502dd2108Slg150142 29602dd2108Slg150142 ifc = dev_data->dev_curr_if; 29702dd2108Slg150142 alt = 0; 29802dd2108Slg150142 29902dd2108Slg150142 /* 30002dd2108Slg150142 * get intr out EP descriptor as port0 data out EP, and then 30102dd2108Slg150142 * match with EP address. 30202dd2108Slg150142 * Different keyspan devices may has different EP addresses. 30302dd2108Slg150142 */ 30402dd2108Slg150142 tmp_ep = usb_lookup_ep_data(ksp->ks_dip, dev_data, ifc, alt, 0, 30502dd2108Slg150142 USB_EP_ATTR_INTR, USB_EP_DIR_OUT); 30602dd2108Slg150142 if (tmp_ep == NULL) { 30702dd2108Slg150142 USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh, 30802dd2108Slg150142 "keyspan_init_pipes: can't find port1 data out ep"); 30902dd2108Slg150142 31002dd2108Slg150142 return (USB_FAILURE); 31102dd2108Slg150142 } 31202dd2108Slg150142 ep_addr = tmp_ep->ep_descr.bEndpointAddress; 31302dd2108Slg150142 31402dd2108Slg150142 /* match the port0 data out EP */ 31502dd2108Slg150142 if (ep_addr == ksp->ks_dev_spec.dataout_ep_addr[0]) { 31602dd2108Slg150142 dataout[0] = tmp_ep; 31702dd2108Slg150142 } 31802dd2108Slg150142 31902dd2108Slg150142 /* 32002dd2108Slg150142 * get bulk out EP descriptors as other port data out EPs, and then 32102dd2108Slg150142 * match with EP addresses. 32202dd2108Slg150142 */ 32302dd2108Slg150142 for (j = 1; j < port_cnt; j++) { 32402dd2108Slg150142 tmp_ep = usb_lookup_ep_data(ksp->ks_dip, dev_data, ifc, alt, 32502dd2108Slg150142 j-1, USB_EP_ATTR_BULK, USB_EP_DIR_OUT); 32602dd2108Slg150142 if (tmp_ep == NULL) { 32702dd2108Slg150142 USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh, 328*77e51571Sgongtian zhao - Sun Microsystems - Beijing China "keyspan_init_pipes: can't find port[%d] " 329*77e51571Sgongtian zhao - Sun Microsystems - Beijing China "data out ep", 33002dd2108Slg150142 j); 33102dd2108Slg150142 return (USB_FAILURE); 33202dd2108Slg150142 } 33302dd2108Slg150142 33402dd2108Slg150142 ep_addr = tmp_ep->ep_descr.bEndpointAddress; 33502dd2108Slg150142 33602dd2108Slg150142 /* match other port data out EPs */ 33702dd2108Slg150142 if (ep_addr == ksp->ks_dev_spec.dataout_ep_addr[j]) { 33802dd2108Slg150142 dataout[j] = tmp_ep; 33902dd2108Slg150142 } 34002dd2108Slg150142 } 34102dd2108Slg150142 34202dd2108Slg150142 /* 34302dd2108Slg150142 * get intr in EP descriptor as status EP, and then match with EP addrs 34402dd2108Slg150142 */ 34502dd2108Slg150142 tmp_ep = usb_lookup_ep_data(ksp->ks_dip, dev_data, ifc, alt, 0, 34602dd2108Slg150142 USB_EP_ATTR_INTR, USB_EP_DIR_IN); 34702dd2108Slg150142 if (tmp_ep == NULL) { 34802dd2108Slg150142 USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh, 34902dd2108Slg150142 "keyspan_init_pipes: can't find status in ep"); 35002dd2108Slg150142 35102dd2108Slg150142 return (USB_FAILURE); 35202dd2108Slg150142 } 35302dd2108Slg150142 ep_addr = tmp_ep->ep_descr.bEndpointAddress; 35402dd2108Slg150142 35502dd2108Slg150142 /* match the status ep */ 35602dd2108Slg150142 if (ep_addr == ksp->ks_dev_spec.stat_ep_addr) { 35702dd2108Slg150142 status = tmp_ep; 35802dd2108Slg150142 } 35902dd2108Slg150142 36002dd2108Slg150142 /* 36102dd2108Slg150142 * get bulk in EP descriptors as data in EP, All the ports share one 36202dd2108Slg150142 * data in EP. 36302dd2108Slg150142 */ 36402dd2108Slg150142 tmp_ep = usb_lookup_ep_data(ksp->ks_dip, dev_data, ifc, alt, 0, 36502dd2108Slg150142 USB_EP_ATTR_BULK, USB_EP_DIR_IN); 36602dd2108Slg150142 if (tmp_ep == NULL) { 36702dd2108Slg150142 USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh, 36802dd2108Slg150142 "keyspan_init_pipes: can't find bulk in ep"); 36902dd2108Slg150142 37002dd2108Slg150142 return (USB_FAILURE); 37102dd2108Slg150142 } 37202dd2108Slg150142 ep_addr = tmp_ep->ep_descr.bEndpointAddress; 37302dd2108Slg150142 37402dd2108Slg150142 /* match data in EPs */ 37502dd2108Slg150142 if (ep_addr == ksp->ks_dev_spec.datain_ep_addr[0]) { 37602dd2108Slg150142 datain[0] = tmp_ep; 37702dd2108Slg150142 } 37802dd2108Slg150142 37902dd2108Slg150142 mutex_enter(&ksp->ks_mutex); 38002dd2108Slg150142 38102dd2108Slg150142 /* intr in pipe for status */ 38202dd2108Slg150142 ksp->ks_statin_pipe.pipe_ep_descr = status->ep_descr; 38302dd2108Slg150142 keyspan_init_one_pipe(ksp, NULL, &ksp->ks_statin_pipe); 38402dd2108Slg150142 38502dd2108Slg150142 /* for data in/out pipes of each port */ 38602dd2108Slg150142 for (i = 0; i < port_cnt; i++) { 38702dd2108Slg150142 ksp->ks_ports[i].kp_datain_pipe.pipe_ep_descr = 38802dd2108Slg150142 datain[0]->ep_descr; 38902dd2108Slg150142 keyspan_init_one_pipe(ksp, &ksp->ks_ports[i], 39002dd2108Slg150142 &ksp->ks_ports[i].kp_datain_pipe); 39102dd2108Slg150142 39202dd2108Slg150142 ksp->ks_ports[i].kp_dataout_pipe.pipe_ep_descr = 39302dd2108Slg150142 dataout[i]->ep_descr; 39402dd2108Slg150142 keyspan_init_one_pipe(ksp, &ksp->ks_ports[i], 39502dd2108Slg150142 &ksp->ks_ports[i].kp_dataout_pipe); 39602dd2108Slg150142 } 39702dd2108Slg150142 39802dd2108Slg150142 mutex_exit(&ksp->ks_mutex); 39902dd2108Slg150142 40002dd2108Slg150142 return (USB_SUCCESS); 40102dd2108Slg150142 } 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 41502dd2108Slg150142 /* fini status pipe */ 41660b08185Syz147069 keyspan_fini_one_pipe(&ksp->ks_statin_pipe); 41702dd2108Slg150142 /* 41802dd2108Slg150142 * fini control pipe 41902dd2108Slg150142 * If USA_49WG, don't need fini control pipe 42002dd2108Slg150142 */ 42102dd2108Slg150142 switch (ksp->ks_dev_spec.id_product) { 42202dd2108Slg150142 case KEYSPAN_USA19HS_PID: 42302dd2108Slg150142 case KEYSPAN_USA49WLC_PID: 42460b08185Syz147069 keyspan_fini_one_pipe(&ksp->ks_ctrlout_pipe); 42560b08185Syz147069 42602dd2108Slg150142 break; 42702dd2108Slg150142 case KEYSPAN_USA49WG_PID: 42802dd2108Slg150142 42902dd2108Slg150142 break; 43002dd2108Slg150142 default: 43102dd2108Slg150142 USB_DPRINTF_L2(DPRINT_CTLOP, ksp->ks_lh, 43202dd2108Slg150142 "keyspan_fini_pipes: the device's product id" 43302dd2108Slg150142 "can't be recognized"); 43402dd2108Slg150142 } 43502dd2108Slg150142 } 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 46402dd2108Slg150142 /* 46502dd2108Slg150142 * Open shared datain pipe for USA_49WG 46602dd2108Slg150142 */ 46702dd2108Slg150142 static int 46802dd2108Slg150142 keyspan_open_pipe_datain_usa49wg(keyspan_state_t *ksp, keyspan_pipe_t *pipe) 46902dd2108Slg150142 { 47002dd2108Slg150142 int rval = USB_SUCCESS; 47102dd2108Slg150142 47202dd2108Slg150142 /* don't open for the second time */ 47302dd2108Slg150142 mutex_enter(&pipe->pipe_mutex); 47402dd2108Slg150142 ASSERT(pipe->pipe_state != KEYSPAN_PIPE_NOT_INIT); 47502dd2108Slg150142 if (pipe->pipe_state != KEYSPAN_PIPE_CLOSED) { 47602dd2108Slg150142 mutex_exit(&pipe->pipe_mutex); 47702dd2108Slg150142 47802dd2108Slg150142 return (USB_SUCCESS); 47902dd2108Slg150142 } 48002dd2108Slg150142 mutex_exit(&pipe->pipe_mutex); 48102dd2108Slg150142 48202dd2108Slg150142 mutex_enter(&ksp->ks_mutex); 48302dd2108Slg150142 ksp->ks_datain_open_cnt++; 48402dd2108Slg150142 if (ksp->ks_datain_open_cnt == 1) { 48502dd2108Slg150142 mutex_exit(&ksp->ks_mutex); 48602dd2108Slg150142 48702dd2108Slg150142 if ((rval = (usb_pipe_open(ksp->ks_dip, &pipe->pipe_ep_descr, 48802dd2108Slg150142 &pipe->pipe_policy, USB_FLAGS_SLEEP, 48902dd2108Slg150142 &pipe->pipe_handle))) == USB_SUCCESS) { 49002dd2108Slg150142 mutex_enter(&pipe->pipe_mutex); 49102dd2108Slg150142 pipe->pipe_state = KEYSPAN_PIPE_OPEN; 49202dd2108Slg150142 mutex_exit(&pipe->pipe_mutex); 49302dd2108Slg150142 49402dd2108Slg150142 mutex_enter(&ksp->ks_mutex); 49502dd2108Slg150142 ksp->ks_datain_pipe_handle = pipe->pipe_handle; 49602dd2108Slg150142 mutex_exit(&ksp->ks_mutex); 49702dd2108Slg150142 } else { 49802dd2108Slg150142 mutex_enter(&ksp->ks_mutex); 49902dd2108Slg150142 ksp->ks_datain_open_cnt--; 50002dd2108Slg150142 mutex_exit(&ksp->ks_mutex); 50102dd2108Slg150142 } 50202dd2108Slg150142 50302dd2108Slg150142 return (rval); 50402dd2108Slg150142 } else { 50502dd2108Slg150142 /* data in pipe has been opened by other port */ 50602dd2108Slg150142 ASSERT(ksp->ks_datain_pipe_handle != NULL); 50702dd2108Slg150142 50802dd2108Slg150142 mutex_enter(&pipe->pipe_mutex); 50902dd2108Slg150142 pipe->pipe_handle = ksp->ks_datain_pipe_handle; 51002dd2108Slg150142 /* Set datain pipe state */ 51102dd2108Slg150142 pipe->pipe_state = KEYSPAN_PIPE_OPEN; 51202dd2108Slg150142 mutex_exit(&pipe->pipe_mutex); 51302dd2108Slg150142 mutex_exit(&ksp->ks_mutex); 51402dd2108Slg150142 51502dd2108Slg150142 return (USB_SUCCESS); 51602dd2108Slg150142 } 51702dd2108Slg150142 } 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 /* 54002dd2108Slg150142 * close shared datain pipe if open for USA_49WG 54102dd2108Slg150142 */ 54202dd2108Slg150142 static void 54302dd2108Slg150142 keyspan_close_pipe_datain_usa49wg(keyspan_pipe_t *pipe) 54402dd2108Slg150142 { 54502dd2108Slg150142 keyspan_state_t *ksp = pipe->pipe_ksp; 54602dd2108Slg150142 /* 54702dd2108Slg150142 * pipe may already be closed, e.g. if device has been physically 54802dd2108Slg150142 * disconnected and the driver immediately detached 54902dd2108Slg150142 */ 55002dd2108Slg150142 if (pipe->pipe_handle != NULL) { 55102dd2108Slg150142 mutex_enter(&ksp->ks_mutex); 55202dd2108Slg150142 ksp->ks_datain_open_cnt--; 55302dd2108Slg150142 if (!ksp->ks_datain_open_cnt) { 55402dd2108Slg150142 mutex_exit(&ksp->ks_mutex); 55502dd2108Slg150142 usb_pipe_close(pipe->pipe_ksp->ks_dip, 55602dd2108Slg150142 pipe->pipe_handle, USB_FLAGS_SLEEP, 55702dd2108Slg150142 NULL, NULL); 55802dd2108Slg150142 } else { 55902dd2108Slg150142 mutex_exit(&ksp->ks_mutex); 56002dd2108Slg150142 } 56102dd2108Slg150142 56202dd2108Slg150142 mutex_enter(&pipe->pipe_mutex); 56302dd2108Slg150142 pipe->pipe_handle = NULL; 56402dd2108Slg150142 pipe->pipe_state = KEYSPAN_PIPE_CLOSED; 56502dd2108Slg150142 mutex_exit(&pipe->pipe_mutex); 56602dd2108Slg150142 } 56702dd2108Slg150142 } 56802dd2108Slg150142 56902dd2108Slg150142 /* 57002dd2108Slg150142 * For USA19HS and USA49WLC: 57160b08185Syz147069 * Open global pipes, a status pipe and a control pipe 57260b08185Syz147069 */ 57360b08185Syz147069 int 57402dd2108Slg150142 keyspan_open_dev_pipes_usa49(keyspan_state_t *ksp) 57560b08185Syz147069 { 57660b08185Syz147069 int rval; 57760b08185Syz147069 57802dd2108Slg150142 USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, 57902dd2108Slg150142 "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*77e51571Sgongtian zhao - Sun Microsystems - Beijing China "keyspan_open_dev_pipes_usa49: open ctrl pipe failed %d", 585*77e51571Sgongtian zhao - Sun Microsystems - Beijing China rval); 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, 59202dd2108Slg150142 "keyspan_open_dev_pipes_usa49: open status pipe failed %d", 59302dd2108Slg150142 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, 60502dd2108Slg150142 "keyspan_open_dev_pipes_usa49: receive device status" 60602dd2108Slg150142 " 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 61802dd2108Slg150142 /* 61902dd2108Slg150142 * For keyspan USA_49WG: 62002dd2108Slg150142 * Open global pipes, a status pipe 62102dd2108Slg150142 * Use default control pipe, don't need to open it. 62202dd2108Slg150142 */ 62302dd2108Slg150142 int 62402dd2108Slg150142 keyspan_open_dev_pipes_usa49wg(keyspan_state_t *ksp) 62502dd2108Slg150142 { 62602dd2108Slg150142 int rval; 62702dd2108Slg150142 62802dd2108Slg150142 /* Open status pipe */ 62902dd2108Slg150142 rval = keyspan_open_one_pipe(ksp, &ksp->ks_statin_pipe); 63002dd2108Slg150142 if (rval != USB_SUCCESS) { 63102dd2108Slg150142 USB_DPRINTF_L2(DPRINT_OPEN, ksp->ks_lh, 632*77e51571Sgongtian zhao - Sun Microsystems - Beijing China "keyspan_open_dev_pipes_usa49wg: " 633*77e51571Sgongtian zhao - Sun Microsystems - Beijing China "open status pipe failed %d", 63402dd2108Slg150142 rval); 63502dd2108Slg150142 63602dd2108Slg150142 return (rval); 63702dd2108Slg150142 } 63802dd2108Slg150142 /* start device polling */ 63902dd2108Slg150142 keyspan_pipe_start_polling(&ksp->ks_statin_pipe); 64002dd2108Slg150142 64102dd2108Slg150142 return (rval); 64202dd2108Slg150142 } 64302dd2108Slg150142 64402dd2108Slg150142 /* 64502dd2108Slg150142 * Open global pipes, status pipe and control pipe, 64602dd2108Slg150142 */ 64702dd2108Slg150142 int 64802dd2108Slg150142 keyspan_open_dev_pipes(keyspan_state_t *ksp) 64902dd2108Slg150142 { 65002dd2108Slg150142 int rval = USB_SUCCESS; 65102dd2108Slg150142 65202dd2108Slg150142 USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, "keyspan_open_dev_pipes"); 65302dd2108Slg150142 65402dd2108Slg150142 switch (ksp->ks_dev_spec.id_product) { 65502dd2108Slg150142 case KEYSPAN_USA19HS_PID: 65602dd2108Slg150142 case KEYSPAN_USA49WLC_PID: 65702dd2108Slg150142 rval = keyspan_open_dev_pipes_usa49(ksp); 65802dd2108Slg150142 65902dd2108Slg150142 break; 66002dd2108Slg150142 case KEYSPAN_USA49WG_PID: 66102dd2108Slg150142 rval = keyspan_open_dev_pipes_usa49wg(ksp); 66202dd2108Slg150142 66302dd2108Slg150142 break; 66402dd2108Slg150142 default: 66502dd2108Slg150142 USB_DPRINTF_L2(DPRINT_OPEN, ksp->ks_lh, 66602dd2108Slg150142 "keyspan_open_dev_pipes: the device's product id can't" 66702dd2108Slg150142 "be recognized"); 66802dd2108Slg150142 66902dd2108Slg150142 return (USB_FAILURE); 67002dd2108Slg150142 } 67102dd2108Slg150142 return (rval); 67202dd2108Slg150142 } 67360b08185Syz147069 67460b08185Syz147069 /* 67560b08185Syz147069 * Reopen all pipes if the port had them open 67660b08185Syz147069 */ 67760b08185Syz147069 int 67860b08185Syz147069 keyspan_reopen_pipes(keyspan_state_t *ksp) 67960b08185Syz147069 { 68060b08185Syz147069 keyspan_port_t *kp; 68160b08185Syz147069 int i; 68260b08185Syz147069 68360b08185Syz147069 USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, "keyspan_reopen_pipes"); 68460b08185Syz147069 68560b08185Syz147069 if (keyspan_open_dev_pipes(ksp) != USB_SUCCESS) { 68660b08185Syz147069 68760b08185Syz147069 return (USB_FAILURE); 68860b08185Syz147069 } 68960b08185Syz147069 69060b08185Syz147069 for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) { 69160b08185Syz147069 kp = &ksp->ks_ports[i]; 69260b08185Syz147069 mutex_enter(&kp->kp_mutex); 69360b08185Syz147069 if (kp->kp_state == KEYSPAN_PORT_OPEN) { 69460b08185Syz147069 USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, 69560b08185Syz147069 "keyspan_reopen_pipes() reopen pipe #%d", i); 69660b08185Syz147069 mutex_exit(&kp->kp_mutex); 69760b08185Syz147069 if (keyspan_open_port_pipes(kp) != USB_SUCCESS) { 69860b08185Syz147069 69960b08185Syz147069 return (USB_FAILURE); 70060b08185Syz147069 } 70160b08185Syz147069 mutex_enter(&kp->kp_mutex); 70260b08185Syz147069 kp->kp_no_more_reads = B_FALSE; 70360b08185Syz147069 } 70460b08185Syz147069 mutex_exit(&kp->kp_mutex); 70560b08185Syz147069 } 70660b08185Syz147069 70760b08185Syz147069 return (USB_SUCCESS); 70860b08185Syz147069 } 70960b08185Syz147069 71060b08185Syz147069 void 71160b08185Syz147069 keyspan_close_port_pipes(keyspan_port_t *kp) 71260b08185Syz147069 { 71302dd2108Slg150142 keyspan_state_t *ksp = kp->kp_ksp; 71402dd2108Slg150142 71560b08185Syz147069 USB_DPRINTF_L4(DPRINT_CLOSE, kp->kp_lh, "keyspan_close_port_pipes"); 71660b08185Syz147069 71702dd2108Slg150142 switch (ksp->ks_dev_spec.id_product) { 71802dd2108Slg150142 case KEYSPAN_USA19HS_PID: 71902dd2108Slg150142 case KEYSPAN_USA49WLC_PID: 72060b08185Syz147069 keyspan_close_one_pipe(&kp->kp_datain_pipe); 72102dd2108Slg150142 72202dd2108Slg150142 break; 72302dd2108Slg150142 case KEYSPAN_USA49WG_PID: 72402dd2108Slg150142 keyspan_close_pipe_datain_usa49wg(&kp->kp_datain_pipe); 72502dd2108Slg150142 72602dd2108Slg150142 break; 72702dd2108Slg150142 default: 72802dd2108Slg150142 USB_DPRINTF_L2(DPRINT_CLOSE, kp->kp_lh, 72902dd2108Slg150142 "keyspan_close_port_pipes:" 73002dd2108Slg150142 "the device's product id can't be recognized"); 73102dd2108Slg150142 } 73202dd2108Slg150142 keyspan_close_one_pipe(&kp->kp_dataout_pipe); 73360b08185Syz147069 } 73460b08185Syz147069 73560b08185Syz147069 /* 73660b08185Syz147069 * Close IN and OUT bulk pipes of all ports 73760b08185Syz147069 */ 73860b08185Syz147069 void 73960b08185Syz147069 keyspan_close_open_pipes(keyspan_state_t *ksp) 74060b08185Syz147069 { 74160b08185Syz147069 keyspan_port_t *kp; 74260b08185Syz147069 int i; 74302dd2108Slg150142 int port_num = -1; 74460b08185Syz147069 74560b08185Syz147069 USB_DPRINTF_L4(DPRINT_CLOSE, ksp->ks_lh, "keyspan_close_open_pipes"); 74660b08185Syz147069 74702dd2108Slg150142 switch (ksp->ks_dev_spec.id_product) { 74802dd2108Slg150142 case KEYSPAN_USA19HS_PID: 74902dd2108Slg150142 case KEYSPAN_USA49WLC_PID: 75060b08185Syz147069 for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) { 75160b08185Syz147069 kp = &ksp->ks_ports[i]; 75260b08185Syz147069 mutex_enter(&kp->kp_mutex); 75360b08185Syz147069 if (kp->kp_state == KEYSPAN_PORT_OPEN) { 75460b08185Syz147069 kp->kp_no_more_reads = B_TRUE; 75560b08185Syz147069 mutex_exit(&kp->kp_mutex); 75660b08185Syz147069 usb_pipe_reset(ksp->ks_dip, 75702dd2108Slg150142 kp->kp_datain_pipe.pipe_handle, 75802dd2108Slg150142 USB_FLAGS_SLEEP, NULL, NULL); 75960b08185Syz147069 keyspan_close_port_pipes(kp); 76060b08185Syz147069 } else { 76160b08185Syz147069 mutex_exit(&kp->kp_mutex); 76260b08185Syz147069 } 76360b08185Syz147069 } 76402dd2108Slg150142 76502dd2108Slg150142 break; 76602dd2108Slg150142 76702dd2108Slg150142 case KEYSPAN_USA49WG_PID: 76802dd2108Slg150142 for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) { 76902dd2108Slg150142 kp = &ksp->ks_ports[i]; 77002dd2108Slg150142 mutex_enter(&kp->kp_mutex); 77102dd2108Slg150142 if (kp->kp_state == KEYSPAN_PORT_OPEN) { 77202dd2108Slg150142 kp->kp_no_more_reads = B_TRUE; 77302dd2108Slg150142 port_num = i; 77402dd2108Slg150142 } 77502dd2108Slg150142 mutex_exit(&kp->kp_mutex); 77602dd2108Slg150142 } 77702dd2108Slg150142 if (port_num >= 0) { 77802dd2108Slg150142 kp = &ksp->ks_ports[port_num]; 77902dd2108Slg150142 usb_pipe_reset(ksp->ks_dip, 78002dd2108Slg150142 kp->kp_datain_pipe.pipe_handle, 78102dd2108Slg150142 USB_FLAGS_SLEEP, NULL, NULL); 78260b08185Syz147069 } 78360b08185Syz147069 78402dd2108Slg150142 for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) { 78502dd2108Slg150142 kp = &ksp->ks_ports[i]; 78602dd2108Slg150142 mutex_enter(&kp->kp_mutex); 78702dd2108Slg150142 if (kp->kp_state == KEYSPAN_PORT_OPEN) { 78802dd2108Slg150142 mutex_exit(&kp->kp_mutex); 78902dd2108Slg150142 keyspan_close_port_pipes(kp); 79002dd2108Slg150142 } else { 79102dd2108Slg150142 mutex_exit(&kp->kp_mutex); 79202dd2108Slg150142 } 79302dd2108Slg150142 } 79402dd2108Slg150142 79502dd2108Slg150142 break; 79602dd2108Slg150142 default: 79702dd2108Slg150142 USB_DPRINTF_L2(DPRINT_CLOSE, ksp->ks_lh, 79802dd2108Slg150142 "keyspan_close_open_pipes:" 79902dd2108Slg150142 "the device's product id can't be recognized"); 80002dd2108Slg150142 80102dd2108Slg150142 } 80202dd2108Slg150142 } 80360b08185Syz147069 80460b08185Syz147069 /* 80560b08185Syz147069 * Close global pipes 80660b08185Syz147069 */ 80760b08185Syz147069 void 80860b08185Syz147069 keyspan_close_dev_pipes(keyspan_state_t *ksp) 80960b08185Syz147069 { 81060b08185Syz147069 USB_DPRINTF_L4(DPRINT_CLOSE, ksp->ks_lh, "keyspan_close_dev_pipes"); 81160b08185Syz147069 81202dd2108Slg150142 switch (ksp->ks_dev_spec.id_product) { 81302dd2108Slg150142 case KEYSPAN_USA19HS_PID: 81402dd2108Slg150142 case KEYSPAN_USA49WLC_PID: 81560b08185Syz147069 keyspan_close_one_pipe(&ksp->ks_statin_pipe); 81660b08185Syz147069 keyspan_close_one_pipe(&ksp->ks_ctrlout_pipe); 81702dd2108Slg150142 81802dd2108Slg150142 break; 81902dd2108Slg150142 82002dd2108Slg150142 case KEYSPAN_USA49WG_PID: 82102dd2108Slg150142 /* 82202dd2108Slg150142 * USA_49WG use default control pipe, don't need close it 82302dd2108Slg150142 * Stop polling before close status in pipe 82402dd2108Slg150142 */ 82502dd2108Slg150142 usb_pipe_stop_intr_polling(ksp->ks_statin_pipe.pipe_handle, 82602dd2108Slg150142 USB_FLAGS_SLEEP); 82702dd2108Slg150142 keyspan_close_one_pipe(&ksp->ks_statin_pipe); 82802dd2108Slg150142 82902dd2108Slg150142 break; 83002dd2108Slg150142 default: 83102dd2108Slg150142 USB_DPRINTF_L2(DPRINT_CLOSE, ksp->ks_lh, 83202dd2108Slg150142 "keyspan_close_dev_pipes:" 83302dd2108Slg150142 "the device's product id can't be recognized"); 83460b08185Syz147069 } 83560b08185Syz147069 83602dd2108Slg150142 } 83760b08185Syz147069 83860b08185Syz147069 /* 83960b08185Syz147069 * Open bulk data IN and data OUT pipes for one port. 84060b08185Syz147069 * The status and control pipes are opened in attach because they are global. 84160b08185Syz147069 */ 84260b08185Syz147069 int 84360b08185Syz147069 keyspan_open_port_pipes(keyspan_port_t *kp) 84460b08185Syz147069 { 84560b08185Syz147069 keyspan_state_t *ksp = kp->kp_ksp; 84660b08185Syz147069 int rval; 84760b08185Syz147069 84860b08185Syz147069 USB_DPRINTF_L4(DPRINT_OPEN, kp->kp_lh, "keyspan_open_port_pipes"); 84960b08185Syz147069 85002dd2108Slg150142 switch (ksp->ks_dev_spec.id_product) { 85102dd2108Slg150142 case KEYSPAN_USA19HS_PID: 85202dd2108Slg150142 case KEYSPAN_USA49WLC_PID: 85360b08185Syz147069 rval = keyspan_open_one_pipe(ksp, &kp->kp_datain_pipe); 85402dd2108Slg150142 85502dd2108Slg150142 break; 85602dd2108Slg150142 case KEYSPAN_USA49WG_PID: 85702dd2108Slg150142 rval = keyspan_open_pipe_datain_usa49wg(ksp, 85802dd2108Slg150142 &kp->kp_datain_pipe); 85902dd2108Slg150142 86002dd2108Slg150142 break; 86102dd2108Slg150142 default: 86202dd2108Slg150142 USB_DPRINTF_L2(DPRINT_OPEN, kp->kp_lh, 86302dd2108Slg150142 "keyspan_open_port_pipes:" 86402dd2108Slg150142 "the device's product id can't be recognized"); 86502dd2108Slg150142 } 86602dd2108Slg150142 86760b08185Syz147069 if (rval != USB_SUCCESS) { 86860b08185Syz147069 86960b08185Syz147069 goto fail; 87060b08185Syz147069 } 87160b08185Syz147069 87260b08185Syz147069 rval = keyspan_open_one_pipe(ksp, &kp->kp_dataout_pipe); 87360b08185Syz147069 if (rval != USB_SUCCESS) { 87460b08185Syz147069 87560b08185Syz147069 goto fail; 87660b08185Syz147069 } 87760b08185Syz147069 87860b08185Syz147069 return (rval); 87960b08185Syz147069 88060b08185Syz147069 fail: 88160b08185Syz147069 USB_DPRINTF_L2(DPRINT_OPEN, kp->kp_lh, 88260b08185Syz147069 "keyspan_open_port_pipes: failed %d", rval); 88360b08185Syz147069 keyspan_close_port_pipes(kp); 88460b08185Syz147069 88560b08185Syz147069 return (rval); 88660b08185Syz147069 } 88760b08185Syz147069 88860b08185Syz147069 void 88960b08185Syz147069 keyspan_close_pipes(keyspan_state_t *ksp) 89060b08185Syz147069 { 89160b08185Syz147069 USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, "keyspan_close_pipes"); 89260b08185Syz147069 89360b08185Syz147069 /* close all ports' pipes first, and then device ctrl/status pipes. */ 89460b08185Syz147069 keyspan_close_open_pipes(ksp); 89560b08185Syz147069 keyspan_close_dev_pipes(ksp); 89660b08185Syz147069 } 89760b08185Syz147069 /* 89860b08185Syz147069 * bulk out common callback 89960b08185Syz147069 */ 90060b08185Syz147069 /*ARGSUSED*/ 90160b08185Syz147069 void 90260b08185Syz147069 keyspan_bulkout_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 90360b08185Syz147069 { 90460b08185Syz147069 keyspan_port_t *kp = (keyspan_port_t *)req->bulk_client_private; 90560b08185Syz147069 keyspan_pipe_t *bulkout = &kp->kp_dataout_pipe; 90660b08185Syz147069 mblk_t *data = req->bulk_data; 90760b08185Syz147069 int data_len; 90860b08185Syz147069 90960b08185Syz147069 data_len = (data) ? MBLKL(data) : 0; 91060b08185Syz147069 91160b08185Syz147069 USB_DPRINTF_L4(DPRINT_OUT_PIPE, bulkout->pipe_lh, 91260b08185Syz147069 "keyspan_bulkout_cb: len=%d cr=%d cb_flags=%x", 91360b08185Syz147069 data_len, req->bulk_completion_reason, req->bulk_cb_flags); 91460b08185Syz147069 915688b07c5Sgc161489 if (req->bulk_completion_reason && data) { 91660b08185Syz147069 91760b08185Syz147069 /* 91860b08185Syz147069 * Data wasn't transfered successfully. 91960b08185Syz147069 * Put data back on the queue. 92060b08185Syz147069 */ 92160b08185Syz147069 keyspan_put_head(&kp->kp_tx_mp, data, kp); 92260b08185Syz147069 92360b08185Syz147069 /* don't release mem in usb_free_bulk_req */ 92460b08185Syz147069 req->bulk_data = NULL; 92560b08185Syz147069 } 92660b08185Syz147069 92760b08185Syz147069 usb_free_bulk_req(req); 92860b08185Syz147069 92960b08185Syz147069 /* if more data available, kick off another transmit */ 93060b08185Syz147069 mutex_enter(&kp->kp_mutex); 93160b08185Syz147069 if (kp->kp_tx_mp == NULL) { 932688b07c5Sgc161489 /* 933688b07c5Sgc161489 * Attach a zero packet if data length is muliple of 64, 934688b07c5Sgc161489 * due to the specification of keyspan_usa19hs. 935688b07c5Sgc161489 */ 936688b07c5Sgc161489 if ((kp->kp_ksp->ks_dev_spec.id_product == 937688b07c5Sgc161489 KEYSPAN_USA19HS_PID) && (data_len == 64)) { 938688b07c5Sgc161489 kp->kp_tx_mp = allocb(0, BPRI_LO); 939688b07c5Sgc161489 if (kp->kp_tx_mp) { 940688b07c5Sgc161489 keyspan_tx_start(kp, NULL); 941688b07c5Sgc161489 mutex_exit(&kp->kp_mutex); 942688b07c5Sgc161489 943688b07c5Sgc161489 return; 944688b07c5Sgc161489 } 945688b07c5Sgc161489 } 94602dd2108Slg150142 /* no more data, notify waiters */ 94702dd2108Slg150142 cv_broadcast(&kp->kp_tx_cv); 94802dd2108Slg150142 mutex_exit(&kp->kp_mutex); 94902dd2108Slg150142 95002dd2108Slg150142 /* tx callback for this port */ 95102dd2108Slg150142 kp->kp_cb.cb_tx(kp->kp_cb.cb_arg); 95202dd2108Slg150142 } else { 95302dd2108Slg150142 keyspan_tx_start(kp, NULL); 95402dd2108Slg150142 mutex_exit(&kp->kp_mutex); 95502dd2108Slg150142 } 95602dd2108Slg150142 } 95702dd2108Slg150142 95802dd2108Slg150142 /* 95902dd2108Slg150142 * intr out common callback for USA_49WG port0 only 96002dd2108Slg150142 */ 96102dd2108Slg150142 /*ARGSUSED*/ 96202dd2108Slg150142 void 96302dd2108Slg150142 keyspan_introut_cb_usa49wg(usb_pipe_handle_t pipe, usb_intr_req_t *req) 96402dd2108Slg150142 { 96502dd2108Slg150142 keyspan_port_t *kp = (keyspan_port_t *)req->intr_client_private; 96602dd2108Slg150142 keyspan_pipe_t *introut = &kp->kp_dataout_pipe; 96702dd2108Slg150142 mblk_t *data = req->intr_data; 96802dd2108Slg150142 int data_len; 96902dd2108Slg150142 97002dd2108Slg150142 data_len = (data) ? MBLKL(data) : 0; 97102dd2108Slg150142 97202dd2108Slg150142 USB_DPRINTF_L4(DPRINT_OUT_PIPE, introut->pipe_lh, 97302dd2108Slg150142 "keyspan_introut_cb_usa49wg: len=%d cr=%d cb_flags=%x", 97402dd2108Slg150142 data_len, req->intr_completion_reason, req->intr_cb_flags); 97502dd2108Slg150142 97602dd2108Slg150142 if (req->intr_completion_reason && (data_len > 0)) { 97702dd2108Slg150142 97802dd2108Slg150142 /* 97902dd2108Slg150142 * Data wasn't transfered successfully. 98002dd2108Slg150142 * Put data back on the queue. 98102dd2108Slg150142 */ 98202dd2108Slg150142 keyspan_put_head(&kp->kp_tx_mp, data, kp); 98302dd2108Slg150142 98402dd2108Slg150142 /* don't release mem in usb_free_bulk_req */ 98502dd2108Slg150142 req->intr_data = NULL; 98602dd2108Slg150142 } 98702dd2108Slg150142 98802dd2108Slg150142 usb_free_intr_req(req); 98902dd2108Slg150142 99002dd2108Slg150142 /* if more data available, kick off another transmit */ 99102dd2108Slg150142 mutex_enter(&kp->kp_mutex); 99202dd2108Slg150142 if (kp->kp_tx_mp == NULL) { 99360b08185Syz147069 99460b08185Syz147069 /* no more data, notify waiters */ 99560b08185Syz147069 cv_broadcast(&kp->kp_tx_cv); 99660b08185Syz147069 mutex_exit(&kp->kp_mutex); 99760b08185Syz147069 99860b08185Syz147069 /* tx callback for this port */ 99960b08185Syz147069 kp->kp_cb.cb_tx(kp->kp_cb.cb_arg); 100060b08185Syz147069 } else { 100160b08185Syz147069 keyspan_tx_start(kp, NULL); 100260b08185Syz147069 mutex_exit(&kp->kp_mutex); 100360b08185Syz147069 } 100460b08185Syz147069 } 100560b08185Syz147069 1006c138f478Syz147069 1007c138f478Syz147069 /* For incoming data only. Parse a status byte and return the err code */ 1008c138f478Syz147069 void 1009c138f478Syz147069 keyspan_parse_status(uchar_t *status, uchar_t *err) 1010c138f478Syz147069 { 1011c138f478Syz147069 if (*status & RXERROR_BREAK) { 1012c138f478Syz147069 /* 1013c138f478Syz147069 * Parity and Framing errors only count if they 1014c138f478Syz147069 * occur exclusive of a break being received. 1015c138f478Syz147069 */ 1016c138f478Syz147069 *status &= (uint8_t)(RXERROR_OVERRUN | RXERROR_BREAK); 1017c138f478Syz147069 } 1018c138f478Syz147069 *err |= (*status & RXERROR_OVERRUN) ? DS_OVERRUN_ERR : 0; 1019c138f478Syz147069 *err |= (*status & RXERROR_PARITY) ? DS_PARITY_ERR : 0; 1020c138f478Syz147069 *err |= (*status & RXERROR_FRAMING) ? DS_FRAMING_ERR : 0; 1021c138f478Syz147069 *err |= (*status & RXERROR_BREAK) ? DS_BREAK_ERR : 0; 1022c138f478Syz147069 } 1023c138f478Syz147069 102402dd2108Slg150142 /* Bulk in data process function, used by all models */ 102560b08185Syz147069 int 102602dd2108Slg150142 keyspan_bulkin_cb_process(keyspan_port_t *kp, 102702dd2108Slg150142 uint8_t data_len, uchar_t status, mblk_t *data) 102860b08185Syz147069 { 1029c138f478Syz147069 uchar_t err = 0; 1030c138f478Syz147069 mblk_t *mp; 103160b08185Syz147069 /* 1032c138f478Syz147069 * According to Keyspan spec, if 0x80 bit is clear, there is 1033c138f478Syz147069 * only one status byte at the head of the data buf; if 0x80 bit 1034c138f478Syz147069 * set, then data buf contains alternate status and data bytes; 1035c138f478Syz147069 * In the first case, only OVERRUN err can exist; In the second 1036c138f478Syz147069 * case, there are four kinds of err bits may appear in status. 103760b08185Syz147069 */ 1038c138f478Syz147069 1039c138f478Syz147069 /* if 0x80 bit AND overrun bit are clear, just send up data */ 1040c138f478Syz147069 if (!(status & 0x80) && !(status & RXERROR_OVERRUN)) { 104160b08185Syz147069 104202dd2108Slg150142 /* Get rid of the first status byte */ 104360b08185Syz147069 data->b_rptr++; 104460b08185Syz147069 data_len--; 104560b08185Syz147069 1046c138f478Syz147069 } else if (!(status & 0x80)) { 1047c138f478Syz147069 /* If 0x80 bit is clear and overrun bit is set */ 104860b08185Syz147069 1049c138f478Syz147069 keyspan_parse_status(&status, &err); 1050c138f478Syz147069 mutex_exit(&kp->kp_mutex); 1051c138f478Syz147069 if ((mp = allocb(2, BPRI_HI)) == NULL) { 1052c138f478Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, kp->kp_lh, 105302dd2108Slg150142 "keyspan_bulkin_cb_process: allocb failed"); 1054c138f478Syz147069 mutex_enter(&kp->kp_mutex); 105560b08185Syz147069 1056c138f478Syz147069 return (0); 1057c138f478Syz147069 } 1058c138f478Syz147069 DB_TYPE(mp) = M_BREAK; 1059c138f478Syz147069 *mp->b_wptr++ = err; 1060c138f478Syz147069 *mp->b_wptr++ = status; 1061c138f478Syz147069 mutex_enter(&kp->kp_mutex); 1062c138f478Syz147069 1063c138f478Syz147069 /* Add to the received list; Send up the err code. */ 1064c138f478Syz147069 keyspan_put_tail(&kp->kp_rx_mp, mp); 1065c138f478Syz147069 1066c138f478Syz147069 /* 1067c138f478Syz147069 * Don't send up the first byte because 1068c138f478Syz147069 * it is a status byte. 1069c138f478Syz147069 */ 1070c138f478Syz147069 data->b_rptr++; 1071c138f478Syz147069 data_len--; 1072c138f478Syz147069 1073c138f478Syz147069 } else { /* 0x80 bit set, there are some errs in the data */ 1074c138f478Syz147069 /* 1075c138f478Syz147069 * Usually, there are at least two bytes, 1076c138f478Syz147069 * one status and one data. 1077c138f478Syz147069 */ 107860b08185Syz147069 if (data_len > 1) { 107960b08185Syz147069 int i = 0; 108060b08185Syz147069 int j = 1; 1081c138f478Syz147069 /* 1082c138f478Syz147069 * In this case, there might be multi status 1083c138f478Syz147069 * bytes. Parse each status byte and move the 1084c138f478Syz147069 * data bytes together. 1085c138f478Syz147069 */ 108660b08185Syz147069 for (j = 1; j < data_len; j += 2) { 1087c138f478Syz147069 status = data->b_rptr[j-1]; 1088c138f478Syz147069 keyspan_parse_status(&status, &err); 1089c138f478Syz147069 1090c138f478Syz147069 /* move the data togeter */ 109160b08185Syz147069 data->b_rptr[i] = data->b_rptr[j]; 109260b08185Syz147069 i++; 109360b08185Syz147069 } 109460b08185Syz147069 data->b_wptr = data->b_rptr + i; 1095c138f478Syz147069 } else { /* There are only one byte in incoming buf */ 1096c138f478Syz147069 keyspan_parse_status(&status, &err); 1097c138f478Syz147069 } 1098c138f478Syz147069 mutex_exit(&kp->kp_mutex); 1099c138f478Syz147069 if ((mp = allocb(2, BPRI_HI)) == NULL) { 1100c138f478Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, kp->kp_lh, 110102dd2108Slg150142 "keyspan_bulkin_cb_process: allocb failed"); 1102c138f478Syz147069 mutex_enter(&kp->kp_mutex); 110360b08185Syz147069 1104c138f478Syz147069 return (0); 1105c138f478Syz147069 } 1106c138f478Syz147069 DB_TYPE(mp) = M_BREAK; 1107c138f478Syz147069 *mp->b_wptr++ = err; 1108c138f478Syz147069 if (data_len > 2) { 1109c138f478Syz147069 /* 1110c138f478Syz147069 * There are multiple status bytes in this case. 1111c138f478Syz147069 * Use err as status character since err is got 1112c138f478Syz147069 * by or in all status bytes. 1113c138f478Syz147069 */ 1114c138f478Syz147069 *mp->b_wptr++ = err; 1115c138f478Syz147069 } else { 1116c138f478Syz147069 *mp->b_wptr++ = status; 1117c138f478Syz147069 } 1118c138f478Syz147069 mutex_enter(&kp->kp_mutex); 1119c138f478Syz147069 1120c138f478Syz147069 /* Add to the received list; Send up the err code. */ 1121c138f478Syz147069 keyspan_put_tail(&kp->kp_rx_mp, mp); 1122c138f478Syz147069 1123c138f478Syz147069 if (data_len > 1) { 1124c138f478Syz147069 data_len = data->b_wptr - data->b_rptr; 1125c138f478Syz147069 } 1126c138f478Syz147069 } 112760b08185Syz147069 return (data_len); 112860b08185Syz147069 } 112960b08185Syz147069 113060b08185Syz147069 /* 113160b08185Syz147069 * pipe callbacks 113260b08185Syz147069 * -------------- 113360b08185Syz147069 * 113402dd2108Slg150142 * bulk in common callback for USA19HS and USA49WLC model 113560b08185Syz147069 */ 113660b08185Syz147069 /*ARGSUSED*/ 113760b08185Syz147069 int 113860b08185Syz147069 keyspan_bulkin_cb_usa49(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 113960b08185Syz147069 { 114060b08185Syz147069 keyspan_port_t *kp = (keyspan_port_t *)req->bulk_client_private; 114160b08185Syz147069 keyspan_pipe_t *bulkin = &kp->kp_datain_pipe; 114260b08185Syz147069 mblk_t *data = req->bulk_data; 114360b08185Syz147069 uint_t cr = req->bulk_completion_reason; 114460b08185Syz147069 int data_len; 114560b08185Syz147069 114660b08185Syz147069 ASSERT(mutex_owned(&kp->kp_mutex)); 114760b08185Syz147069 114860b08185Syz147069 data_len = (data) ? MBLKL(data) : 0; 114960b08185Syz147069 115060b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 115160b08185Syz147069 "keyspan_bulkin_cb_usa49: len=%d" 115260b08185Syz147069 " cr=%d flags=%x", data_len, cr, req->bulk_cb_flags); 115360b08185Syz147069 115460b08185Syz147069 /* put data on the read queue */ 115560b08185Syz147069 if ((data_len > 0) && (kp->kp_state != KEYSPAN_PORT_CLOSED) && 115660b08185Syz147069 (cr == USB_CR_OK)) { 1157c138f478Syz147069 uchar_t status = data->b_rptr[0]; 115860b08185Syz147069 115902dd2108Slg150142 if ((data_len = keyspan_bulkin_cb_process(kp, data_len, 116002dd2108Slg150142 status, data)) > 0) { 116160b08185Syz147069 keyspan_put_tail(&kp->kp_rx_mp, data); 116260b08185Syz147069 /* 1163c138f478Syz147069 * the data will not be freed and 116460b08185Syz147069 * will be sent up later. 116560b08185Syz147069 */ 116660b08185Syz147069 req->bulk_data = NULL; 116760b08185Syz147069 } 116860b08185Syz147069 } else { 116960b08185Syz147069 /* usb error happened, so don't send up data */ 117060b08185Syz147069 data_len = 0; 117160b08185Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh, 117260b08185Syz147069 "keyspan_bulkin_cb_usa49: port_state=%d" 117360b08185Syz147069 " b_rptr[0]=%c", kp->kp_state, data->b_rptr[0]); 1174c138f478Syz147069 } 117560b08185Syz147069 if (kp->kp_state != KEYSPAN_PORT_OPEN) { 117660b08185Syz147069 kp->kp_no_more_reads = B_TRUE; 117760b08185Syz147069 } 117860b08185Syz147069 117960b08185Syz147069 return (data_len); 118060b08185Syz147069 } 1181c138f478Syz147069 118202dd2108Slg150142 /* 118302dd2108Slg150142 * pipe callbacks 118402dd2108Slg150142 * -------------- 118502dd2108Slg150142 * 118602dd2108Slg150142 * bulk in common callback for USA_49WG model 118702dd2108Slg150142 */ 118802dd2108Slg150142 /*ARGSUSED*/ 118902dd2108Slg150142 void 119002dd2108Slg150142 keyspan_bulkin_cb_usa49wg(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 119102dd2108Slg150142 { 119202dd2108Slg150142 keyspan_port_t *kp = (keyspan_port_t *)req->bulk_client_private, 119302dd2108Slg150142 *kp_true; 119402dd2108Slg150142 keyspan_state_t *ksp = (keyspan_state_t *)kp->kp_ksp; 119502dd2108Slg150142 mblk_t *data = req->bulk_data, 119602dd2108Slg150142 *mp_data; 119702dd2108Slg150142 uint_t cr = req->bulk_completion_reason, 119802dd2108Slg150142 port_data_len; 119902dd2108Slg150142 int data_len, copy_len; 120002dd2108Slg150142 uint8_t port_num, 120102dd2108Slg150142 port_cnt = 0, 120202dd2108Slg150142 port[4], 120302dd2108Slg150142 receive_flag = 1; 120402dd2108Slg150142 uint16_t status; 120502dd2108Slg150142 unsigned char *old_rptr; 120602dd2108Slg150142 120702dd2108Slg150142 data_len = (data) ? MBLKL(data) : 0; 120802dd2108Slg150142 120902dd2108Slg150142 USB_DPRINTF_L2(DPRINT_IN_PIPE, ksp->ks_lh, 121002dd2108Slg150142 "keyspan_bulkin_cb_usa49wg: len=%d" 121102dd2108Slg150142 " cr=%d flags=%x", data_len, cr, req->bulk_cb_flags); 121202dd2108Slg150142 121302dd2108Slg150142 /* put data on the read queue */ 121402dd2108Slg150142 if ((data_len > 0) && (cr == USB_CR_OK)) { 121502dd2108Slg150142 old_rptr = data->b_rptr; 121602dd2108Slg150142 while (data->b_rptr < data->b_wptr) { 121702dd2108Slg150142 port_num = data->b_rptr[0]; 121802dd2108Slg150142 port_data_len = data->b_rptr[1]; 121902dd2108Slg150142 status = data->b_rptr[2]; 122002dd2108Slg150142 data->b_rptr += 2; 122102dd2108Slg150142 122202dd2108Slg150142 if (port_num > 3) { 122302dd2108Slg150142 USB_DPRINTF_L2(DPRINT_IN_PIPE, ksp->ks_lh, 122402dd2108Slg150142 "keyspan_bulkin_cb_usa49wg,port num is not" 122502dd2108Slg150142 " correct: port=%d, len=%d, status=%x", 122602dd2108Slg150142 port_num, port_data_len, status); 122702dd2108Slg150142 122802dd2108Slg150142 break; 122902dd2108Slg150142 } 123002dd2108Slg150142 123102dd2108Slg150142 kp_true = &ksp->ks_ports[port_num]; 123202dd2108Slg150142 port[++port_cnt] = port_num; 123302dd2108Slg150142 mutex_enter(&kp_true->kp_mutex); 123402dd2108Slg150142 123502dd2108Slg150142 if (kp_true->kp_state != KEYSPAN_PORT_OPEN) { 123602dd2108Slg150142 mutex_exit(&kp_true->kp_mutex); 123702dd2108Slg150142 123802dd2108Slg150142 USB_DPRINTF_L2(DPRINT_IN_PIPE, kp_true->kp_lh, 1239*77e51571Sgongtian zhao - Sun Microsystems - Beijing China "keyspan_bulkin_cb_usa49wg, " 1240*77e51571Sgongtian zhao - Sun Microsystems - Beijing China "port isn't opened"); 124102dd2108Slg150142 data->b_rptr += port_data_len; 124202dd2108Slg150142 port_cnt--; 124302dd2108Slg150142 124402dd2108Slg150142 continue; 124502dd2108Slg150142 } 124602dd2108Slg150142 124702dd2108Slg150142 USB_DPRINTF_L2(DPRINT_IN_PIPE, kp_true->kp_lh, 124802dd2108Slg150142 "keyspan_bulkin_cb_usa49wg: status=0x%x, len=%d", 124902dd2108Slg150142 status, port_data_len); 125002dd2108Slg150142 125102dd2108Slg150142 if ((copy_len = keyspan_bulkin_cb_process(kp_true, 125202dd2108Slg150142 port_data_len, status, data)) > 0) { 125302dd2108Slg150142 125402dd2108Slg150142 mutex_exit(&kp_true->kp_mutex); 125502dd2108Slg150142 if ((mp_data = allocb(copy_len, BPRI_HI)) 125602dd2108Slg150142 == NULL) { 125702dd2108Slg150142 USB_DPRINTF_L2(DPRINT_IN_PIPE, 125802dd2108Slg150142 kp_true->kp_lh, "keyspan_bulkin_cb_" 125902dd2108Slg150142 "usa49wg: allocb failed"); 126002dd2108Slg150142 126102dd2108Slg150142 return; 126202dd2108Slg150142 } 126302dd2108Slg150142 mutex_enter(&kp_true->kp_mutex); 126402dd2108Slg150142 DB_TYPE(mp_data) = M_DATA; 126502dd2108Slg150142 bcopy(data->b_rptr, mp_data->b_wptr, copy_len); 126602dd2108Slg150142 mp_data->b_wptr += copy_len; 126702dd2108Slg150142 if (copy_len < port_data_len -1) { 126802dd2108Slg150142 /* 126902dd2108Slg150142 * data has multi status bytes, b_wptr 127002dd2108Slg150142 * has changed by 127102dd2108Slg150142 * keyspan_bulkin_process(), need to 127202dd2108Slg150142 * be recovered to old one 127302dd2108Slg150142 */ 127402dd2108Slg150142 data->b_rptr += port_data_len; 127502dd2108Slg150142 data->b_wptr = old_rptr + data_len; 127602dd2108Slg150142 } else { 127702dd2108Slg150142 data->b_rptr += copy_len; 127802dd2108Slg150142 } 127902dd2108Slg150142 128002dd2108Slg150142 keyspan_put_tail(&kp_true->kp_rx_mp, mp_data); 128102dd2108Slg150142 mutex_exit(&kp_true->kp_mutex); 128202dd2108Slg150142 } else { 128302dd2108Slg150142 mutex_exit(&kp_true->kp_mutex); 128402dd2108Slg150142 128502dd2108Slg150142 break; 128602dd2108Slg150142 } 128702dd2108Slg150142 } /* End of while loop */ 128802dd2108Slg150142 128902dd2108Slg150142 while (port_cnt) { 129002dd2108Slg150142 port_num = port[port_cnt--]; 129102dd2108Slg150142 kp_true = &ksp->ks_ports[port_num]; 129202dd2108Slg150142 mutex_enter(&kp_true->kp_mutex); 129302dd2108Slg150142 129402dd2108Slg150142 if (kp_true->kp_state != KEYSPAN_PORT_OPEN) { 129502dd2108Slg150142 kp_true->kp_no_more_reads = B_TRUE; 129602dd2108Slg150142 } 129702dd2108Slg150142 if (receive_flag && (!kp_true->kp_no_more_reads)) { 129802dd2108Slg150142 mutex_exit(&kp_true->kp_mutex); 129902dd2108Slg150142 /* kick off another read */ 130002dd2108Slg150142 (void) keyspan_receive_data( 130102dd2108Slg150142 &kp_true->kp_datain_pipe, 130202dd2108Slg150142 kp_true->kp_read_len, kp_true); 130302dd2108Slg150142 130402dd2108Slg150142 receive_flag = 0; 130502dd2108Slg150142 } else { 130602dd2108Slg150142 mutex_exit(&kp_true->kp_mutex); 130702dd2108Slg150142 } 130802dd2108Slg150142 /* setup rx callback for this port */ 130902dd2108Slg150142 kp_true->kp_cb.cb_rx(kp_true->kp_cb.cb_arg); 131002dd2108Slg150142 } 131102dd2108Slg150142 } else { 131202dd2108Slg150142 /* cr != USB_CR_OK, usb error happened */ 131302dd2108Slg150142 USB_DPRINTF_L2(DPRINT_IN_PIPE, ksp->ks_lh, 131402dd2108Slg150142 "keyspan_bulkin_cb_usa49wg: port=%d, len=%d, status=%x", 131502dd2108Slg150142 data->b_rptr[0], data->b_rptr[1], data->b_rptr[2]); 131602dd2108Slg150142 131702dd2108Slg150142 mutex_enter(&kp->kp_mutex); 131802dd2108Slg150142 if (kp->kp_state != KEYSPAN_PORT_OPEN) { 131902dd2108Slg150142 kp->kp_no_more_reads = B_TRUE; 132002dd2108Slg150142 } 132102dd2108Slg150142 if (!kp->kp_no_more_reads) { 132202dd2108Slg150142 mutex_exit(&kp->kp_mutex); 132302dd2108Slg150142 /* kick off another read */ 132402dd2108Slg150142 (void) keyspan_receive_data(&kp->kp_datain_pipe, 132502dd2108Slg150142 kp->kp_read_len, kp); 132602dd2108Slg150142 } else { 132702dd2108Slg150142 mutex_exit(&kp->kp_mutex); 132802dd2108Slg150142 } 132902dd2108Slg150142 } 133002dd2108Slg150142 133102dd2108Slg150142 freemsg(data); 133202dd2108Slg150142 req->bulk_data = NULL; 133302dd2108Slg150142 usb_free_bulk_req(req); 133402dd2108Slg150142 133502dd2108Slg150142 } 133660b08185Syz147069 133760b08185Syz147069 /* 133860b08185Syz147069 * pipe callbacks 133960b08185Syz147069 * -------------- 134060b08185Syz147069 * 134102dd2108Slg150142 * bulk in common callback for USA19HS and USA49WLC 134260b08185Syz147069 */ 134360b08185Syz147069 /*ARGSUSED*/ 134460b08185Syz147069 void 134560b08185Syz147069 keyspan_bulkin_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 134660b08185Syz147069 { 134760b08185Syz147069 keyspan_port_t *kp = (keyspan_port_t *)req->bulk_client_private; 134860b08185Syz147069 int data_len; 134960b08185Syz147069 boolean_t no_more_reads = B_FALSE; 135060b08185Syz147069 135160b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, (&kp->kp_datain_pipe)->pipe_lh, 135260b08185Syz147069 "keyspan_bulkin_cb"); 135360b08185Syz147069 135460b08185Syz147069 mutex_enter(&kp->kp_mutex); 135560b08185Syz147069 135660b08185Syz147069 /* put data on the read queue */ 135760b08185Syz147069 data_len = keyspan_bulkin_cb_usa49(pipe, req); 135860b08185Syz147069 no_more_reads = kp->kp_no_more_reads; 135960b08185Syz147069 136060b08185Syz147069 mutex_exit(&kp->kp_mutex); 136160b08185Syz147069 136260b08185Syz147069 usb_free_bulk_req(req); 136360b08185Syz147069 136460b08185Syz147069 /* kick off another read unless indicated otherwise */ 136560b08185Syz147069 if (!no_more_reads) { 136660b08185Syz147069 (void) keyspan_receive_data(&kp->kp_datain_pipe, 136760b08185Syz147069 kp->kp_read_len, kp); 136860b08185Syz147069 } 136960b08185Syz147069 137060b08185Syz147069 /* setup rx callback for this port */ 137160b08185Syz147069 if (data_len > 0) { 137260b08185Syz147069 kp->kp_cb.cb_rx(kp->kp_cb.cb_arg); 137360b08185Syz147069 } 137460b08185Syz147069 } 137560b08185Syz147069 137660b08185Syz147069 /* 137760b08185Syz147069 * pipe callbacks 137860b08185Syz147069 * -------------- 137960b08185Syz147069 * 138060b08185Syz147069 * bulk in status callback for usa19hs model 138160b08185Syz147069 */ 138260b08185Syz147069 /*ARGSUSED*/ 138360b08185Syz147069 void 138460b08185Syz147069 keyspan_status_cb_usa19hs(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 138560b08185Syz147069 { 138660b08185Syz147069 keyspan_state_t *ksp = (keyspan_state_t *)req->bulk_client_private; 138760b08185Syz147069 keyspan_pipe_t *bulkin = &ksp->ks_statin_pipe; 138860b08185Syz147069 mblk_t *data = req->bulk_data; 138960b08185Syz147069 usb_cr_t cr = req->bulk_completion_reason; 139060b08185Syz147069 int data_len; 139160b08185Syz147069 139260b08185Syz147069 data_len = (data) ? MBLKL(data) : 0; 139360b08185Syz147069 139460b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 139560b08185Syz147069 "keyspan_status_cb_usa19hs: len=%d" 139660b08185Syz147069 " cr=%d flags=%x", data_len, cr, req->bulk_cb_flags); 139760b08185Syz147069 139860b08185Syz147069 /* put data on the read queue */ 139960b08185Syz147069 if ((data_len == 14) && (cr == USB_CR_OK)) { 140060b08185Syz147069 keyspan_port_t *kp = &ksp->ks_ports[0]; 140160b08185Syz147069 keyspan_usa19hs_port_status_msg_t *status_msg = 140260b08185Syz147069 &(kp->kp_status_msg.usa19hs); 140360b08185Syz147069 140460b08185Syz147069 mutex_enter(&kp->kp_mutex); 140560b08185Syz147069 bcopy(data->b_rptr, status_msg, data_len); 140660b08185Syz147069 140760b08185Syz147069 if (status_msg->controlResponse) { 140860b08185Syz147069 kp->kp_status_flag |= KEYSPAN_PORT_CTRLRESP; 140960b08185Syz147069 } else { 141060b08185Syz147069 kp->kp_status_flag &= ~KEYSPAN_PORT_CTRLRESP; 141160b08185Syz147069 } 141260b08185Syz147069 141360b08185Syz147069 if (status_msg->portState & PORTSTATE_ENABLED) { 141460b08185Syz147069 kp->kp_status_flag |= KEYSPAN_PORT_ENABLE; 141560b08185Syz147069 } else { 141660b08185Syz147069 kp->kp_status_flag &= ~KEYSPAN_PORT_ENABLE; 141760b08185Syz147069 } 141860b08185Syz147069 141960b08185Syz147069 if (status_msg->portState & PORTSTATE_TXBREAK) { 142060b08185Syz147069 kp->kp_status_flag |= KEYSPAN_PORT_TXBREAK; 142160b08185Syz147069 } else { 142260b08185Syz147069 kp->kp_status_flag &= ~KEYSPAN_PORT_TXBREAK; 142360b08185Syz147069 } 142460b08185Syz147069 142560b08185Syz147069 if (status_msg->rxBreak) { 142660b08185Syz147069 kp->kp_status_flag |= KEYSPAN_PORT_RXBREAK; 142760b08185Syz147069 } else { 142860b08185Syz147069 kp->kp_status_flag &= ~KEYSPAN_PORT_RXBREAK; 142960b08185Syz147069 } 143060b08185Syz147069 143160b08185Syz147069 if (status_msg->portState & PORTSTATE_LOOPBACK) { 143260b08185Syz147069 kp->kp_status_flag |= KEYSPAN_PORT_LOOPBACK; 143360b08185Syz147069 } else { 143460b08185Syz147069 kp->kp_status_flag &= ~KEYSPAN_PORT_LOOPBACK; 143560b08185Syz147069 } 143660b08185Syz147069 143760b08185Syz147069 /* if msr status changed, then invoke status callback */ 143860b08185Syz147069 if (status_msg->msr & USA_MSR_dCTS || 143960b08185Syz147069 status_msg->msr & USA_MSR_dDSR || 144060b08185Syz147069 status_msg->msr & USA_MSR_dRI || 144160b08185Syz147069 status_msg->msr & USA_MSR_dDCD) { 144260b08185Syz147069 144360b08185Syz147069 mutex_exit(&kp->kp_mutex); 144460b08185Syz147069 kp->kp_cb.cb_status(kp->kp_cb.cb_arg); 144560b08185Syz147069 } else { 144660b08185Syz147069 mutex_exit(&kp->kp_mutex); 144760b08185Syz147069 } 144860b08185Syz147069 } else { 144960b08185Syz147069 145060b08185Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh, 145160b08185Syz147069 "keyspan_status_cb_usa19hs: get status failed, cr=%d" 145260b08185Syz147069 " data_len=%d", cr, data_len); 145360b08185Syz147069 } 145460b08185Syz147069 } 145560b08185Syz147069 1456c138f478Syz147069 145760b08185Syz147069 /* 145860b08185Syz147069 * pipe callbacks 145960b08185Syz147069 * -------------- 146060b08185Syz147069 * 146160b08185Syz147069 * bulk in status callback for usa49 model 146260b08185Syz147069 */ 146360b08185Syz147069 /*ARGSUSED*/ 146460b08185Syz147069 void 146560b08185Syz147069 keyspan_status_cb_usa49(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 146660b08185Syz147069 { 146760b08185Syz147069 keyspan_state_t *ksp = (keyspan_state_t *)req->bulk_client_private; 146860b08185Syz147069 keyspan_pipe_t *bulkin = &ksp->ks_statin_pipe; 146960b08185Syz147069 mblk_t *data = req->bulk_data; 147060b08185Syz147069 uint_t cr = req->bulk_completion_reason; 147160b08185Syz147069 int data_len; 147260b08185Syz147069 147360b08185Syz147069 data_len = (data) ? MBLKL(data) : 0; 147460b08185Syz147069 147560b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 147660b08185Syz147069 "keyspan_status_cb_usa49: len=%d" 147760b08185Syz147069 " cr=%d flags=%x", data_len, cr, req->bulk_cb_flags); 147860b08185Syz147069 147960b08185Syz147069 /* put data on the read queue */ 148060b08185Syz147069 if ((data_len == 11) && (cr == USB_CR_OK)) { 148160b08185Syz147069 keyspan_usa49_port_status_msg_t status_msg; 148260b08185Syz147069 keyspan_port_t *cur_kp; 148360b08185Syz147069 keyspan_usa49_port_status_msg_t *kp_status_msg; 148460b08185Syz147069 boolean_t need_cb = B_FALSE; 148560b08185Syz147069 148660b08185Syz147069 bcopy(data->b_rptr, &status_msg, data_len); 148760b08185Syz147069 if (status_msg.portNumber >= ksp->ks_dev_spec.port_cnt) { 148860b08185Syz147069 148960b08185Syz147069 return; 149060b08185Syz147069 } 149160b08185Syz147069 cur_kp = &ksp->ks_ports[status_msg.portNumber]; 149260b08185Syz147069 kp_status_msg = &(cur_kp->kp_status_msg.usa49); 149360b08185Syz147069 149460b08185Syz147069 mutex_enter(&cur_kp->kp_mutex); 149560b08185Syz147069 149660b08185Syz147069 /* if msr status changed, then need invoke status callback */ 149760b08185Syz147069 if (status_msg.cts != kp_status_msg->cts || 149860b08185Syz147069 status_msg.dsr != kp_status_msg->dsr || 149960b08185Syz147069 status_msg.ri != kp_status_msg->ri || 150060b08185Syz147069 status_msg.dcd != kp_status_msg->dcd) { 150160b08185Syz147069 150260b08185Syz147069 need_cb = B_TRUE; 150360b08185Syz147069 } 150460b08185Syz147069 150560b08185Syz147069 bcopy(&status_msg, kp_status_msg, data_len); 150660b08185Syz147069 150760b08185Syz147069 if (kp_status_msg->controlResponse) { 150860b08185Syz147069 cur_kp->kp_status_flag |= KEYSPAN_PORT_CTRLRESP; 150960b08185Syz147069 } else { 151060b08185Syz147069 cur_kp->kp_status_flag &= ~KEYSPAN_PORT_CTRLRESP; 151160b08185Syz147069 } 151260b08185Syz147069 151360b08185Syz147069 if (!kp_status_msg->rxEnabled) { 151460b08185Syz147069 cur_kp->kp_status_flag |= KEYSPAN_PORT_RXBREAK; 151560b08185Syz147069 } else { 151660b08185Syz147069 cur_kp->kp_status_flag &= ~KEYSPAN_PORT_RXBREAK; 151760b08185Syz147069 } 151860b08185Syz147069 151960b08185Syz147069 mutex_exit(&cur_kp->kp_mutex); 152060b08185Syz147069 152160b08185Syz147069 if (need_cb) { 152260b08185Syz147069 152360b08185Syz147069 cur_kp->kp_cb.cb_status(cur_kp->kp_cb.cb_arg); 152460b08185Syz147069 } 152560b08185Syz147069 } else { 152660b08185Syz147069 152760b08185Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh, 152860b08185Syz147069 "keyspan_status_cb_usa49: get status failed, cr=%d" 152960b08185Syz147069 " data_len=%d", cr, data_len); 153060b08185Syz147069 } 153160b08185Syz147069 } 1532c138f478Syz147069 153360b08185Syz147069 153460b08185Syz147069 /* 153560b08185Syz147069 * pipe callbacks 153660b08185Syz147069 * -------------- 153760b08185Syz147069 * 153860b08185Syz147069 * bulk in callback for status receiving 153960b08185Syz147069 */ 154060b08185Syz147069 /*ARGSUSED*/ 154160b08185Syz147069 void 154260b08185Syz147069 keyspan_status_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 154360b08185Syz147069 { 154460b08185Syz147069 keyspan_state_t *ksp = (keyspan_state_t *)req->bulk_client_private; 154560b08185Syz147069 usb_cr_t cr = req->bulk_completion_reason; 154660b08185Syz147069 154760b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, (&ksp->ks_statin_pipe)->pipe_lh, 154860b08185Syz147069 "keyspan_status_cb"); 154960b08185Syz147069 155060b08185Syz147069 /* put data on the read queue */ 155160b08185Syz147069 switch (ksp->ks_dev_spec.id_product) { 155260b08185Syz147069 case KEYSPAN_USA19HS_PID: 155360b08185Syz147069 keyspan_status_cb_usa19hs(pipe, req); 155460b08185Syz147069 155560b08185Syz147069 break; 155660b08185Syz147069 1557c138f478Syz147069 155860b08185Syz147069 case KEYSPAN_USA49WLC_PID: 155960b08185Syz147069 keyspan_status_cb_usa49(pipe, req); 156060b08185Syz147069 156160b08185Syz147069 break; 1562c138f478Syz147069 156360b08185Syz147069 default: 156460b08185Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, 156560b08185Syz147069 (&ksp->ks_statin_pipe)->pipe_lh, "keyspan_status_cb:" 156660b08185Syz147069 "the device's product id can't be recognized"); 156760b08185Syz147069 156860b08185Syz147069 return; 156960b08185Syz147069 } 157060b08185Syz147069 157160b08185Syz147069 usb_free_bulk_req(req); 157260b08185Syz147069 157360b08185Syz147069 /* kick off another read to receive status */ 157460b08185Syz147069 if ((cr != USB_CR_FLUSHED) && (cr != USB_CR_DEV_NOT_RESP) && 157560b08185Syz147069 keyspan_dev_is_online(ksp)) { 157660b08185Syz147069 if (keyspan_receive_status(ksp) != USB_SUCCESS) { 157760b08185Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, 157860b08185Syz147069 (&ksp->ks_statin_pipe)->pipe_lh, 157960b08185Syz147069 "keyspan_status_cb:" 158060b08185Syz147069 "receive status can't be restarted."); 158160b08185Syz147069 } 158260b08185Syz147069 } else { 158360b08185Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, 158460b08185Syz147069 (&ksp->ks_statin_pipe)->pipe_lh, "keyspan_status_cb:" 158560b08185Syz147069 "get status failed: cr=%d", cr); 158660b08185Syz147069 } 158760b08185Syz147069 } 158860b08185Syz147069 158960b08185Syz147069 /* 159060b08185Syz147069 * Submit data read request (asynchronous). If this function returns 159160b08185Syz147069 * USB_SUCCESS, pipe is acquired and request is sent, otherwise req is free. 159260b08185Syz147069 */ 159360b08185Syz147069 int 159460b08185Syz147069 keyspan_receive_data(keyspan_pipe_t *bulkin, int len, void *cb_arg) 159560b08185Syz147069 { 159660b08185Syz147069 keyspan_state_t *ksp = bulkin->pipe_ksp; 159760b08185Syz147069 usb_bulk_req_t *br; 159802dd2108Slg150142 int rval = USB_SUCCESS; 159960b08185Syz147069 160060b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, "keyspan_receive_data:" 160160b08185Syz147069 "len=%d", len); 160260b08185Syz147069 160360b08185Syz147069 ASSERT(!mutex_owned(&bulkin->pipe_mutex)); 160460b08185Syz147069 160560b08185Syz147069 br = usb_alloc_bulk_req(ksp->ks_dip, len, USB_FLAGS_SLEEP); 160660b08185Syz147069 br->bulk_len = len; 160760b08185Syz147069 160860b08185Syz147069 /* No timeout, just wait for data */ 160960b08185Syz147069 br->bulk_timeout = 0; 161060b08185Syz147069 br->bulk_client_private = cb_arg; 161160b08185Syz147069 br->bulk_attributes = USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING; 161202dd2108Slg150142 161302dd2108Slg150142 switch (ksp->ks_dev_spec.id_product) { 161402dd2108Slg150142 case KEYSPAN_USA19HS_PID: 161502dd2108Slg150142 case KEYSPAN_USA49WLC_PID: 161660b08185Syz147069 br->bulk_cb = keyspan_bulkin_cb; 161760b08185Syz147069 br->bulk_exc_cb = keyspan_bulkin_cb; 161860b08185Syz147069 161902dd2108Slg150142 break; 162002dd2108Slg150142 162102dd2108Slg150142 case KEYSPAN_USA49WG_PID: 162202dd2108Slg150142 br->bulk_cb = keyspan_bulkin_cb_usa49wg; 162302dd2108Slg150142 br->bulk_exc_cb = keyspan_bulkin_cb_usa49wg; 162402dd2108Slg150142 162502dd2108Slg150142 break; 162602dd2108Slg150142 162702dd2108Slg150142 default: 162802dd2108Slg150142 usb_free_bulk_req(br); 162902dd2108Slg150142 163002dd2108Slg150142 USB_DPRINTF_L2(DPRINT_IN_PIPE, 163102dd2108Slg150142 (&ksp->ks_statin_pipe)->pipe_lh, "keyspan_receive_data:" 163202dd2108Slg150142 "the device's product id can't be recognized"); 163302dd2108Slg150142 163402dd2108Slg150142 return (USB_FAILURE); 163502dd2108Slg150142 } 163602dd2108Slg150142 163702dd2108Slg150142 163860b08185Syz147069 rval = usb_pipe_bulk_xfer(bulkin->pipe_handle, br, 0); 163960b08185Syz147069 if (rval != USB_SUCCESS) { 164060b08185Syz147069 usb_free_bulk_req(br); 164160b08185Syz147069 } 164260b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 164360b08185Syz147069 "keyspan_receive_data: rval = %d", rval); 164460b08185Syz147069 return (rval); 164560b08185Syz147069 } 164660b08185Syz147069 164760b08185Syz147069 /* 164860b08185Syz147069 * submit device status read request (asynchronous). 164960b08185Syz147069 */ 165060b08185Syz147069 int 165160b08185Syz147069 keyspan_receive_status(keyspan_state_t *ksp) 165260b08185Syz147069 { 165360b08185Syz147069 keyspan_pipe_t *bulkin = &ksp->ks_statin_pipe; 165460b08185Syz147069 usb_bulk_req_t *br; 165560b08185Syz147069 int rval; 165660b08185Syz147069 165760b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 165860b08185Syz147069 "keyspan_receive_status"); 165960b08185Syz147069 166060b08185Syz147069 ASSERT(!mutex_owned(&bulkin->pipe_mutex)); 166160b08185Syz147069 166260b08185Syz147069 br = usb_alloc_bulk_req(ksp->ks_dip, 32, USB_FLAGS_SLEEP); 166360b08185Syz147069 br->bulk_len = KEYSPAN_STATIN_MAX_LEN; 166460b08185Syz147069 166560b08185Syz147069 /* No timeout, just wait for data */ 166660b08185Syz147069 br->bulk_timeout = 0; 166760b08185Syz147069 br->bulk_client_private = (void *)ksp; 166860b08185Syz147069 br->bulk_attributes = USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING; 166960b08185Syz147069 br->bulk_cb = keyspan_status_cb; 167060b08185Syz147069 br->bulk_exc_cb = keyspan_status_cb; 167160b08185Syz147069 167260b08185Syz147069 rval = usb_pipe_bulk_xfer(bulkin->pipe_handle, br, 0); 167360b08185Syz147069 if (rval != USB_SUCCESS) { 167460b08185Syz147069 usb_free_bulk_req(br); 167560b08185Syz147069 } 167660b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 167760b08185Syz147069 "keyspan_receive_status: rval = %d", rval); 167860b08185Syz147069 return (rval); 167960b08185Syz147069 } 168060b08185Syz147069 168160b08185Syz147069 /* 168260b08185Syz147069 * submit data for transfer (asynchronous) 168360b08185Syz147069 * 168460b08185Syz147069 * if data was sent successfully, 'mpp' will be nulled to indicate 168560b08185Syz147069 * that mblk is consumed by USBA and no longer belongs to the caller. 168660b08185Syz147069 * 168760b08185Syz147069 * if this function returns USB_SUCCESS, pipe is acquired and request 168860b08185Syz147069 * is sent, otherwise pipe is free. 168960b08185Syz147069 */ 169060b08185Syz147069 int 169160b08185Syz147069 keyspan_send_data(keyspan_pipe_t *bulkout, mblk_t **mpp, void *cb_arg) 169260b08185Syz147069 { 169360b08185Syz147069 keyspan_state_t *ksp = bulkout->pipe_ksp; 169460b08185Syz147069 usb_bulk_req_t *br; 169560b08185Syz147069 int rval; 169660b08185Syz147069 169760b08185Syz147069 ASSERT(!mutex_owned(&bulkout->pipe_mutex)); 169860b08185Syz147069 USB_DPRINTF_L4(DPRINT_OUT_PIPE, bulkout->pipe_lh, 169960b08185Syz147069 "keyspan_send_data"); 170060b08185Syz147069 170160b08185Syz147069 br = usb_alloc_bulk_req(ksp->ks_dip, 0, USB_FLAGS_SLEEP); 170260b08185Syz147069 br->bulk_len = MBLKL(*mpp); 170360b08185Syz147069 br->bulk_data = *mpp; 170460b08185Syz147069 br->bulk_timeout = KEYSPAN_BULK_TIMEOUT; 170560b08185Syz147069 br->bulk_client_private = cb_arg; 170660b08185Syz147069 br->bulk_attributes = USB_ATTRS_AUTOCLEARING; 170760b08185Syz147069 br->bulk_cb = keyspan_bulkout_cb; 170860b08185Syz147069 br->bulk_exc_cb = keyspan_bulkout_cb; 170960b08185Syz147069 171060b08185Syz147069 USB_DPRINTF_L3(DPRINT_OUT_PIPE, bulkout->pipe_lh, "keyspan_send_data:" 171160b08185Syz147069 "bulk_len = %d", br->bulk_len); 171260b08185Syz147069 171360b08185Syz147069 rval = usb_pipe_bulk_xfer(bulkout->pipe_handle, br, 0); 171460b08185Syz147069 if (rval == USB_SUCCESS) { 171560b08185Syz147069 171660b08185Syz147069 /* data consumed. The mem will be released in bulkout_cb */ 171760b08185Syz147069 *mpp = NULL; 171860b08185Syz147069 } else { 171960b08185Syz147069 172060b08185Syz147069 /* 172160b08185Syz147069 * Don't free it in usb_free_bulk_req because it will 172260b08185Syz147069 * be linked in keyspan_put_head 172360b08185Syz147069 */ 172460b08185Syz147069 br->bulk_data = NULL; 172560b08185Syz147069 172660b08185Syz147069 usb_free_bulk_req(br); 172760b08185Syz147069 } 172860b08185Syz147069 USB_DPRINTF_L4(DPRINT_OUT_PIPE, bulkout->pipe_lh, 172960b08185Syz147069 "keyspan_send_data: rval = %d", rval); 173060b08185Syz147069 173160b08185Syz147069 return (rval); 173260b08185Syz147069 } 173302dd2108Slg150142 173402dd2108Slg150142 /* 173502dd2108Slg150142 * submit data for transfer (asynchronous) for USA_49WG Port0 only 173602dd2108Slg150142 * 173702dd2108Slg150142 * if data was sent successfully, 'mpp' will be nulled to indicate 173802dd2108Slg150142 * that mblk is consumed by USBA and no longer belongs to the caller. 173902dd2108Slg150142 * 174002dd2108Slg150142 * if this function returns USB_SUCCESS, pipe is acquired and request 174102dd2108Slg150142 * is sent, otherwise pipe is free. 174202dd2108Slg150142 */ 174302dd2108Slg150142 int 174402dd2108Slg150142 keyspan_send_data_port0(keyspan_pipe_t *introut, mblk_t **mpp, void *cb_arg) 174502dd2108Slg150142 { 174602dd2108Slg150142 keyspan_state_t *ksp = introut->pipe_ksp; 174702dd2108Slg150142 usb_intr_req_t *br; 174802dd2108Slg150142 int rval; 174902dd2108Slg150142 175002dd2108Slg150142 ASSERT(!mutex_owned(&introut->pipe_mutex)); 175102dd2108Slg150142 USB_DPRINTF_L4(DPRINT_OUT_PIPE, introut->pipe_lh, 175202dd2108Slg150142 "keyspan_send_data_port0"); 175302dd2108Slg150142 175402dd2108Slg150142 br = usb_alloc_intr_req(ksp->ks_dip, 0, USB_FLAGS_SLEEP); 175502dd2108Slg150142 br->intr_len = MBLKL(*mpp); 175602dd2108Slg150142 br->intr_data = *mpp; 175702dd2108Slg150142 br->intr_timeout = KEYSPAN_BULK_TIMEOUT; 175802dd2108Slg150142 br->intr_client_private = cb_arg; 175902dd2108Slg150142 br->intr_cb = keyspan_introut_cb_usa49wg; 176002dd2108Slg150142 br->intr_exc_cb = keyspan_introut_cb_usa49wg; 176102dd2108Slg150142 176202dd2108Slg150142 USB_DPRINTF_L3(DPRINT_OUT_PIPE, introut->pipe_lh, 176302dd2108Slg150142 "keyspan_send_data_port0: intr_len = %d", 176402dd2108Slg150142 br->intr_len); 176502dd2108Slg150142 176602dd2108Slg150142 rval = usb_pipe_intr_xfer(introut->pipe_handle, br, 0); 176702dd2108Slg150142 if (rval == USB_SUCCESS) { 176802dd2108Slg150142 176902dd2108Slg150142 /* 177002dd2108Slg150142 * data consumed. The mem will be released in 177102dd2108Slg150142 * introut_cb_usa49wg 177202dd2108Slg150142 */ 177302dd2108Slg150142 *mpp = NULL; 177402dd2108Slg150142 } else { 177502dd2108Slg150142 br->intr_data = NULL; 177602dd2108Slg150142 177702dd2108Slg150142 usb_free_intr_req(br); 177802dd2108Slg150142 } 177902dd2108Slg150142 USB_DPRINTF_L4(DPRINT_OUT_PIPE, introut->pipe_lh, 178002dd2108Slg150142 "keyspan_send_data_port0: rval = %d", rval); 178102dd2108Slg150142 178202dd2108Slg150142 return (rval); 178302dd2108Slg150142 } 178402dd2108Slg150142 178502dd2108Slg150142 /* 178602dd2108Slg150142 * pipe callbacks 178702dd2108Slg150142 * -------------- 178802dd2108Slg150142 * 178902dd2108Slg150142 * bulk in status callback for USA_49WG model 179002dd2108Slg150142 */ 179102dd2108Slg150142 /*ARGSUSED*/ 179202dd2108Slg150142 void 179302dd2108Slg150142 keyspan_status_cb_usa49wg(usb_pipe_handle_t pipe, usb_intr_req_t *req) 179402dd2108Slg150142 { 179502dd2108Slg150142 keyspan_state_t *ksp = (keyspan_state_t *)req->intr_client_private; 179602dd2108Slg150142 keyspan_pipe_t *intr = &ksp->ks_statin_pipe; 179702dd2108Slg150142 mblk_t *data = req->intr_data; 179802dd2108Slg150142 uint_t cr = req->intr_completion_reason; 179902dd2108Slg150142 int data_len; 180002dd2108Slg150142 180102dd2108Slg150142 data_len = (data) ? MBLKL(data) : 0; 180202dd2108Slg150142 180302dd2108Slg150142 USB_DPRINTF_L4(DPRINT_IN_PIPE, intr->pipe_lh, 180402dd2108Slg150142 "keyspan_status_cb_usa49wg: len=%d" 180502dd2108Slg150142 " cr=%d flags=%x", data_len, cr, req->intr_cb_flags); 180602dd2108Slg150142 180702dd2108Slg150142 /* put data on the read queue */ 180802dd2108Slg150142 if ((data_len == 11) && (cr == USB_CR_OK)) { 180902dd2108Slg150142 keyspan_usa49_port_status_msg_t status_msg; 181002dd2108Slg150142 keyspan_port_t *cur_kp; 181102dd2108Slg150142 keyspan_usa49_port_status_msg_t *kp_status_msg; 181202dd2108Slg150142 boolean_t need_cb = B_FALSE; 181302dd2108Slg150142 181402dd2108Slg150142 bcopy(data->b_rptr, &status_msg, data_len); 181502dd2108Slg150142 if (status_msg.portNumber >= ksp->ks_dev_spec.port_cnt) { 181602dd2108Slg150142 181702dd2108Slg150142 return; 181802dd2108Slg150142 } 181902dd2108Slg150142 cur_kp = &ksp->ks_ports[status_msg.portNumber]; 182002dd2108Slg150142 kp_status_msg = &(cur_kp->kp_status_msg.usa49); 182102dd2108Slg150142 182202dd2108Slg150142 mutex_enter(&cur_kp->kp_mutex); 182302dd2108Slg150142 182402dd2108Slg150142 /* if msr status changed, then need invoke status callback */ 182502dd2108Slg150142 if (status_msg.cts != kp_status_msg->cts || 182602dd2108Slg150142 status_msg.dsr != kp_status_msg->dsr || 182702dd2108Slg150142 status_msg.ri != kp_status_msg->ri || 182802dd2108Slg150142 status_msg.dcd != kp_status_msg->dcd) { 182902dd2108Slg150142 183002dd2108Slg150142 need_cb = B_TRUE; 183102dd2108Slg150142 } 183202dd2108Slg150142 183302dd2108Slg150142 bcopy(&status_msg, kp_status_msg, data_len); 183402dd2108Slg150142 183502dd2108Slg150142 if (kp_status_msg->controlResponse) { 183602dd2108Slg150142 cur_kp->kp_status_flag |= KEYSPAN_PORT_CTRLRESP; 183702dd2108Slg150142 } else { 183802dd2108Slg150142 cur_kp->kp_status_flag &= ~KEYSPAN_PORT_CTRLRESP; 183902dd2108Slg150142 } 184002dd2108Slg150142 184102dd2108Slg150142 if (!kp_status_msg->rxEnabled) { 184202dd2108Slg150142 cur_kp->kp_status_flag |= KEYSPAN_PORT_RXBREAK; 184302dd2108Slg150142 } else { 184402dd2108Slg150142 cur_kp->kp_status_flag &= ~KEYSPAN_PORT_RXBREAK; 184502dd2108Slg150142 } 184602dd2108Slg150142 184702dd2108Slg150142 mutex_exit(&cur_kp->kp_mutex); 184802dd2108Slg150142 184902dd2108Slg150142 if (need_cb) { 185002dd2108Slg150142 185102dd2108Slg150142 cur_kp->kp_cb.cb_status(cur_kp->kp_cb.cb_arg); 185202dd2108Slg150142 } 185302dd2108Slg150142 } else { 185402dd2108Slg150142 185502dd2108Slg150142 USB_DPRINTF_L2(DPRINT_IN_PIPE, intr->pipe_lh, 185602dd2108Slg150142 "keyspan_status_cb_usa49wg: get status failed, cr=%d" 185702dd2108Slg150142 " data_len=%d", cr, data_len); 185802dd2108Slg150142 } 185902dd2108Slg150142 } 186002dd2108Slg150142 186102dd2108Slg150142 /* 186202dd2108Slg150142 * pipe callbacks 186302dd2108Slg150142 * -------------- 186402dd2108Slg150142 * 186502dd2108Slg150142 * intr in callback for status receiving for USA_49WG model only 186602dd2108Slg150142 */ 186702dd2108Slg150142 /*ARGSUSED*/ 186802dd2108Slg150142 void 186902dd2108Slg150142 keyspan_intr_cb_usa49wg(usb_pipe_handle_t pipe, usb_intr_req_t *req) 187002dd2108Slg150142 { 187102dd2108Slg150142 keyspan_state_t *ksp = (keyspan_state_t *)req->intr_client_private; 187202dd2108Slg150142 usb_cr_t cr = req->intr_completion_reason; 187302dd2108Slg150142 187402dd2108Slg150142 USB_DPRINTF_L4(DPRINT_IN_PIPE, (&ksp->ks_statin_pipe)->pipe_lh, 187502dd2108Slg150142 "keyspan_intr_cb_usa49wg: cr=%d", cr); 187602dd2108Slg150142 187702dd2108Slg150142 /* put data on the read queue */ 187802dd2108Slg150142 (void) keyspan_status_cb_usa49wg(pipe, req); 187902dd2108Slg150142 188002dd2108Slg150142 usb_free_intr_req(req); 188102dd2108Slg150142 } 188202dd2108Slg150142 188302dd2108Slg150142 /* 188402dd2108Slg150142 * pipe callbacks 188502dd2108Slg150142 * -------------- 188602dd2108Slg150142 * 188702dd2108Slg150142 * intr in exception callback for status receiving for USA_49WG model only 188802dd2108Slg150142 */ 188902dd2108Slg150142 /*ARGSUSED*/ 189002dd2108Slg150142 void 189102dd2108Slg150142 keyspan_intr_ex_cb_usa49wg(usb_pipe_handle_t pipe, usb_intr_req_t *req) 189202dd2108Slg150142 { 189302dd2108Slg150142 keyspan_state_t *ksp = (keyspan_state_t *)req->intr_client_private; 189402dd2108Slg150142 usb_cr_t cr = req->intr_completion_reason; 189502dd2108Slg150142 189602dd2108Slg150142 USB_DPRINTF_L4(DPRINT_IN_PIPE, (&ksp->ks_statin_pipe)->pipe_lh, 189702dd2108Slg150142 "keyspan_intr_ex_cb_usa49wg: cr=%d", cr); 189802dd2108Slg150142 189902dd2108Slg150142 usb_free_intr_req(req); 190002dd2108Slg150142 190102dd2108Slg150142 if ((cr != USB_CR_PIPE_CLOSING) && (cr != USB_CR_STOPPED_POLLING) && 190202dd2108Slg150142 (cr != USB_CR_FLUSHED) && (cr != USB_CR_DEV_NOT_RESP) && 190302dd2108Slg150142 (cr != USB_CR_PIPE_RESET) && keyspan_dev_is_online(ksp)) { 190402dd2108Slg150142 keyspan_pipe_start_polling(&ksp->ks_statin_pipe); 190502dd2108Slg150142 } else { 190602dd2108Slg150142 USB_DPRINTF_L2(DPRINT_IN_PIPE, 1907*77e51571Sgongtian zhao - Sun Microsystems - Beijing China (&ksp->ks_statin_pipe)->pipe_lh, 1908*77e51571Sgongtian zhao - Sun Microsystems - Beijing China "keyspan_intr_ex_cb_usa49wg:" 190902dd2108Slg150142 "get status failed: cr=%d", cr); 191002dd2108Slg150142 } 191102dd2108Slg150142 } 191202dd2108Slg150142 191302dd2108Slg150142 /* 191402dd2108Slg150142 * start polling on the interrupt pipe for USA_49WG model only 191502dd2108Slg150142 */ 191602dd2108Slg150142 void 191702dd2108Slg150142 keyspan_pipe_start_polling(keyspan_pipe_t *intr) 191802dd2108Slg150142 { 191902dd2108Slg150142 usb_intr_req_t *br; 192002dd2108Slg150142 keyspan_state_t *ksp = intr->pipe_ksp; 192102dd2108Slg150142 int rval; 192202dd2108Slg150142 192302dd2108Slg150142 USB_DPRINTF_L4(DPRINT_IN_PIPE, ksp->ks_lh, 192402dd2108Slg150142 "keyspan_pipe_start_polling"); 192502dd2108Slg150142 192602dd2108Slg150142 br = usb_alloc_intr_req(ksp->ks_dip, 0, USB_FLAGS_SLEEP); 192702dd2108Slg150142 192802dd2108Slg150142 /* 192902dd2108Slg150142 * If it is in interrupt context, usb_alloc_intr_req will return NULL if 193002dd2108Slg150142 * called with SLEEP flag. 193102dd2108Slg150142 */ 193202dd2108Slg150142 if (!br) { 193302dd2108Slg150142 USB_DPRINTF_L2(DPRINT_IN_PIPE, ksp->ks_lh, 193402dd2108Slg150142 "keyspan_pipe_start_polling: alloc req failed."); 193502dd2108Slg150142 193602dd2108Slg150142 return; 193702dd2108Slg150142 } 193802dd2108Slg150142 br->intr_attributes = USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING; 193902dd2108Slg150142 br->intr_len = intr->pipe_ep_descr.wMaxPacketSize; 194002dd2108Slg150142 br->intr_client_private = (void *)ksp; 194102dd2108Slg150142 194202dd2108Slg150142 br->intr_cb = keyspan_intr_cb_usa49wg; 194302dd2108Slg150142 br->intr_exc_cb = keyspan_intr_ex_cb_usa49wg; 194402dd2108Slg150142 194502dd2108Slg150142 194602dd2108Slg150142 rval = usb_pipe_intr_xfer(intr->pipe_handle, br, USB_FLAGS_SLEEP); 194702dd2108Slg150142 194802dd2108Slg150142 mutex_enter(&intr->pipe_mutex); 194902dd2108Slg150142 if (rval != USB_SUCCESS) { 195002dd2108Slg150142 usb_free_intr_req(br); 195102dd2108Slg150142 intr->pipe_state = KEYSPAN_PIPE_CLOSED; 195202dd2108Slg150142 195302dd2108Slg150142 USB_DPRINTF_L3(DPRINT_IN_PIPE, ksp->ks_lh, 195402dd2108Slg150142 "keyspan_pipe_start_polling: failed (%d)", rval); 195502dd2108Slg150142 } else { 195602dd2108Slg150142 intr->pipe_state = KEYSPAN_PIPE_OPEN; 195702dd2108Slg150142 } 195802dd2108Slg150142 195902dd2108Slg150142 mutex_exit(&intr->pipe_mutex); 196002dd2108Slg150142 } 1961