160b08185Syz147069 /* 260b08185Syz147069 * CDDL HEADER START 360b08185Syz147069 * 460b08185Syz147069 * The contents of this file are subject to the terms of the 5*688b07c5Sgc161489 * Common Development and Distribution License (the "License"). 6*688b07c5Sgc161489 * 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*688b07c5Sgc161489 * 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 } 28060b08185Syz147069 28160b08185Syz147069 void 28260b08185Syz147069 keyspan_fini_pipes(keyspan_state_t *ksp) 28360b08185Syz147069 { 28460b08185Syz147069 keyspan_port_t *kp; 28560b08185Syz147069 int i; 28660b08185Syz147069 28760b08185Syz147069 for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) { 28860b08185Syz147069 kp = &ksp->ks_ports[i]; 28960b08185Syz147069 keyspan_fini_one_pipe(&kp->kp_datain_pipe); 29060b08185Syz147069 keyspan_fini_one_pipe(&kp->kp_dataout_pipe); 29160b08185Syz147069 } 29260b08185Syz147069 29360b08185Syz147069 /* fini global pipes */ 29460b08185Syz147069 keyspan_fini_one_pipe(&ksp->ks_statin_pipe); 29560b08185Syz147069 keyspan_fini_one_pipe(&ksp->ks_ctrlout_pipe); 29660b08185Syz147069 } 29760b08185Syz147069 29860b08185Syz147069 29960b08185Syz147069 static int 30060b08185Syz147069 keyspan_open_one_pipe(keyspan_state_t *ksp, keyspan_pipe_t *pipe) 30160b08185Syz147069 { 30260b08185Syz147069 int rval; 30360b08185Syz147069 30460b08185Syz147069 /* don't open for the second time */ 30560b08185Syz147069 mutex_enter(&pipe->pipe_mutex); 30660b08185Syz147069 ASSERT(pipe->pipe_state != KEYSPAN_PIPE_NOT_INIT); 30760b08185Syz147069 if (pipe->pipe_state != KEYSPAN_PIPE_CLOSED) { 30860b08185Syz147069 mutex_exit(&pipe->pipe_mutex); 30960b08185Syz147069 31060b08185Syz147069 return (USB_SUCCESS); 31160b08185Syz147069 } 31260b08185Syz147069 mutex_exit(&pipe->pipe_mutex); 31360b08185Syz147069 31460b08185Syz147069 rval = usb_pipe_open(ksp->ks_dip, &pipe->pipe_ep_descr, 31560b08185Syz147069 &pipe->pipe_policy, USB_FLAGS_SLEEP, &pipe->pipe_handle); 31660b08185Syz147069 31760b08185Syz147069 if (rval == USB_SUCCESS) { 31860b08185Syz147069 mutex_enter(&pipe->pipe_mutex); 31960b08185Syz147069 pipe->pipe_state = KEYSPAN_PIPE_OPEN; 32060b08185Syz147069 mutex_exit(&pipe->pipe_mutex); 32160b08185Syz147069 } 32260b08185Syz147069 32360b08185Syz147069 return (rval); 32460b08185Syz147069 } 32560b08185Syz147069 32660b08185Syz147069 32760b08185Syz147069 /* 32860b08185Syz147069 * close one pipe if open 32960b08185Syz147069 */ 33060b08185Syz147069 static void 33160b08185Syz147069 keyspan_close_one_pipe(keyspan_pipe_t *pipe) 33260b08185Syz147069 { 33360b08185Syz147069 /* 33460b08185Syz147069 * pipe may already be closed, e.g. if device has been physically 33560b08185Syz147069 * disconnected and the driver immediately detached 33660b08185Syz147069 */ 33760b08185Syz147069 if (pipe->pipe_handle != NULL) { 33860b08185Syz147069 usb_pipe_close(pipe->pipe_ksp->ks_dip, pipe->pipe_handle, 33960b08185Syz147069 USB_FLAGS_SLEEP, NULL, NULL); 34060b08185Syz147069 mutex_enter(&pipe->pipe_mutex); 34160b08185Syz147069 pipe->pipe_handle = NULL; 34260b08185Syz147069 pipe->pipe_state = KEYSPAN_PIPE_CLOSED; 34360b08185Syz147069 mutex_exit(&pipe->pipe_mutex); 34460b08185Syz147069 } 34560b08185Syz147069 } 34660b08185Syz147069 34760b08185Syz147069 /* 34860b08185Syz147069 * Open global pipes, a status pipe and a control pipe 34960b08185Syz147069 */ 35060b08185Syz147069 int 35160b08185Syz147069 keyspan_open_dev_pipes(keyspan_state_t *ksp) 35260b08185Syz147069 { 35360b08185Syz147069 int rval; 35460b08185Syz147069 35560b08185Syz147069 USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, "keyspan_open_dev_pipes"); 35660b08185Syz147069 35760b08185Syz147069 rval = keyspan_open_one_pipe(ksp, &ksp->ks_ctrlout_pipe); 35860b08185Syz147069 if (rval != USB_SUCCESS) { 35960b08185Syz147069 USB_DPRINTF_L2(DPRINT_OPEN, ksp->ks_lh, 36060b08185Syz147069 "keyspan_open_dev_pipes: open ctrl pipe failed %d", rval); 36160b08185Syz147069 36260b08185Syz147069 return (rval); 36360b08185Syz147069 } 36460b08185Syz147069 36560b08185Syz147069 rval = keyspan_open_one_pipe(ksp, &ksp->ks_statin_pipe); 36660b08185Syz147069 if (rval != USB_SUCCESS) { 36760b08185Syz147069 USB_DPRINTF_L2(DPRINT_OPEN, ksp->ks_lh, 36860b08185Syz147069 "keyspan_open_dev_pipes: open status pipe failed %d", rval); 36960b08185Syz147069 37060b08185Syz147069 /* close the first opened pipe here */ 37160b08185Syz147069 keyspan_close_one_pipe(&ksp->ks_ctrlout_pipe); 37260b08185Syz147069 37360b08185Syz147069 return (rval); 37460b08185Syz147069 } 37560b08185Syz147069 37660b08185Syz147069 /* start receive device status */ 37760b08185Syz147069 rval = keyspan_receive_status(ksp); 37860b08185Syz147069 if (rval != USB_SUCCESS) { 37960b08185Syz147069 USB_DPRINTF_L2(DPRINT_OPEN, ksp->ks_lh, 38060b08185Syz147069 "keyspan_open_dev_pipes: receive device status failed %d", 38160b08185Syz147069 rval); 38260b08185Syz147069 38360b08185Syz147069 /* close opened pipes here */ 38460b08185Syz147069 keyspan_close_one_pipe(&ksp->ks_statin_pipe); 38560b08185Syz147069 keyspan_close_one_pipe(&ksp->ks_ctrlout_pipe); 38660b08185Syz147069 38760b08185Syz147069 return (rval); 38860b08185Syz147069 } 38960b08185Syz147069 39060b08185Syz147069 return (rval); 39160b08185Syz147069 } 39260b08185Syz147069 39360b08185Syz147069 39460b08185Syz147069 /* 39560b08185Syz147069 * Reopen all pipes if the port had them open 39660b08185Syz147069 */ 39760b08185Syz147069 int 39860b08185Syz147069 keyspan_reopen_pipes(keyspan_state_t *ksp) 39960b08185Syz147069 { 40060b08185Syz147069 keyspan_port_t *kp; 40160b08185Syz147069 int i; 40260b08185Syz147069 40360b08185Syz147069 USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, "keyspan_reopen_pipes"); 40460b08185Syz147069 40560b08185Syz147069 if (keyspan_open_dev_pipes(ksp) != USB_SUCCESS) { 40660b08185Syz147069 40760b08185Syz147069 return (USB_FAILURE); 40860b08185Syz147069 } 40960b08185Syz147069 41060b08185Syz147069 for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) { 41160b08185Syz147069 kp = &ksp->ks_ports[i]; 41260b08185Syz147069 mutex_enter(&kp->kp_mutex); 41360b08185Syz147069 if (kp->kp_state == KEYSPAN_PORT_OPEN) { 41460b08185Syz147069 USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, 41560b08185Syz147069 "keyspan_reopen_pipes() reopen pipe #%d", i); 41660b08185Syz147069 mutex_exit(&kp->kp_mutex); 41760b08185Syz147069 if (keyspan_open_port_pipes(kp) != USB_SUCCESS) { 41860b08185Syz147069 41960b08185Syz147069 return (USB_FAILURE); 42060b08185Syz147069 } 42160b08185Syz147069 mutex_enter(&kp->kp_mutex); 42260b08185Syz147069 kp->kp_no_more_reads = B_FALSE; 42360b08185Syz147069 } 42460b08185Syz147069 mutex_exit(&kp->kp_mutex); 42560b08185Syz147069 } 42660b08185Syz147069 42760b08185Syz147069 return (USB_SUCCESS); 42860b08185Syz147069 } 42960b08185Syz147069 43060b08185Syz147069 void 43160b08185Syz147069 keyspan_close_port_pipes(keyspan_port_t *kp) 43260b08185Syz147069 { 43360b08185Syz147069 USB_DPRINTF_L4(DPRINT_CLOSE, kp->kp_lh, "keyspan_close_port_pipes"); 43460b08185Syz147069 43560b08185Syz147069 keyspan_close_one_pipe(&kp->kp_dataout_pipe); 43660b08185Syz147069 keyspan_close_one_pipe(&kp->kp_datain_pipe); 43760b08185Syz147069 } 43860b08185Syz147069 43960b08185Syz147069 /* 44060b08185Syz147069 * Close IN and OUT bulk pipes of all ports 44160b08185Syz147069 */ 44260b08185Syz147069 void 44360b08185Syz147069 keyspan_close_open_pipes(keyspan_state_t *ksp) 44460b08185Syz147069 { 44560b08185Syz147069 keyspan_port_t *kp; 44660b08185Syz147069 int i; 44760b08185Syz147069 44860b08185Syz147069 USB_DPRINTF_L4(DPRINT_CLOSE, ksp->ks_lh, "keyspan_close_open_pipes"); 44960b08185Syz147069 45060b08185Syz147069 for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) { 45160b08185Syz147069 kp = &ksp->ks_ports[i]; 45260b08185Syz147069 mutex_enter(&kp->kp_mutex); 45360b08185Syz147069 if (kp->kp_state == KEYSPAN_PORT_OPEN) { 45460b08185Syz147069 kp->kp_no_more_reads = B_TRUE; 45560b08185Syz147069 mutex_exit(&kp->kp_mutex); 45660b08185Syz147069 usb_pipe_reset(ksp->ks_dip, 45760b08185Syz147069 kp->kp_datain_pipe.pipe_handle, USB_FLAGS_SLEEP, 45860b08185Syz147069 NULL, NULL); 45960b08185Syz147069 keyspan_close_port_pipes(kp); 46060b08185Syz147069 } else { 46160b08185Syz147069 mutex_exit(&kp->kp_mutex); 46260b08185Syz147069 } 46360b08185Syz147069 } 46460b08185Syz147069 } 46560b08185Syz147069 46660b08185Syz147069 46760b08185Syz147069 /* 46860b08185Syz147069 * Close global pipes 46960b08185Syz147069 */ 47060b08185Syz147069 void 47160b08185Syz147069 keyspan_close_dev_pipes(keyspan_state_t *ksp) 47260b08185Syz147069 { 47360b08185Syz147069 USB_DPRINTF_L4(DPRINT_CLOSE, ksp->ks_lh, "keyspan_close_dev_pipes"); 47460b08185Syz147069 47560b08185Syz147069 keyspan_close_one_pipe(&ksp->ks_statin_pipe); 47660b08185Syz147069 keyspan_close_one_pipe(&ksp->ks_ctrlout_pipe); 47760b08185Syz147069 } 47860b08185Syz147069 47960b08185Syz147069 48060b08185Syz147069 /* 48160b08185Syz147069 * Open bulk data IN and data OUT pipes for one port. 48260b08185Syz147069 * The status and control pipes are opened in attach because they are global. 48360b08185Syz147069 */ 48460b08185Syz147069 int 48560b08185Syz147069 keyspan_open_port_pipes(keyspan_port_t *kp) 48660b08185Syz147069 { 48760b08185Syz147069 keyspan_state_t *ksp = kp->kp_ksp; 48860b08185Syz147069 int rval; 48960b08185Syz147069 49060b08185Syz147069 USB_DPRINTF_L4(DPRINT_OPEN, kp->kp_lh, "keyspan_open_port_pipes"); 49160b08185Syz147069 49260b08185Syz147069 rval = keyspan_open_one_pipe(ksp, &kp->kp_datain_pipe); 49360b08185Syz147069 if (rval != USB_SUCCESS) { 49460b08185Syz147069 49560b08185Syz147069 goto fail; 49660b08185Syz147069 } 49760b08185Syz147069 49860b08185Syz147069 rval = keyspan_open_one_pipe(ksp, &kp->kp_dataout_pipe); 49960b08185Syz147069 if (rval != USB_SUCCESS) { 50060b08185Syz147069 50160b08185Syz147069 goto fail; 50260b08185Syz147069 } 50360b08185Syz147069 50460b08185Syz147069 return (rval); 50560b08185Syz147069 50660b08185Syz147069 fail: 50760b08185Syz147069 USB_DPRINTF_L2(DPRINT_OPEN, kp->kp_lh, 50860b08185Syz147069 "keyspan_open_port_pipes: failed %d", rval); 50960b08185Syz147069 keyspan_close_port_pipes(kp); 51060b08185Syz147069 51160b08185Syz147069 return (rval); 51260b08185Syz147069 } 51360b08185Syz147069 51460b08185Syz147069 void 51560b08185Syz147069 keyspan_close_pipes(keyspan_state_t *ksp) 51660b08185Syz147069 { 51760b08185Syz147069 USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, "keyspan_close_pipes"); 51860b08185Syz147069 51960b08185Syz147069 /* close all ports' pipes first, and then device ctrl/status pipes. */ 52060b08185Syz147069 keyspan_close_open_pipes(ksp); 52160b08185Syz147069 keyspan_close_dev_pipes(ksp); 52260b08185Syz147069 52360b08185Syz147069 } 52460b08185Syz147069 52560b08185Syz147069 52660b08185Syz147069 /* 52760b08185Syz147069 * bulk out common callback 52860b08185Syz147069 */ 52960b08185Syz147069 /*ARGSUSED*/ 53060b08185Syz147069 void 53160b08185Syz147069 keyspan_bulkout_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 53260b08185Syz147069 { 53360b08185Syz147069 keyspan_port_t *kp = (keyspan_port_t *)req->bulk_client_private; 53460b08185Syz147069 keyspan_pipe_t *bulkout = &kp->kp_dataout_pipe; 53560b08185Syz147069 mblk_t *data = req->bulk_data; 53660b08185Syz147069 int data_len; 53760b08185Syz147069 53860b08185Syz147069 data_len = (data) ? MBLKL(data) : 0; 53960b08185Syz147069 54060b08185Syz147069 USB_DPRINTF_L4(DPRINT_OUT_PIPE, bulkout->pipe_lh, 54160b08185Syz147069 "keyspan_bulkout_cb: len=%d cr=%d cb_flags=%x", 54260b08185Syz147069 data_len, req->bulk_completion_reason, req->bulk_cb_flags); 54360b08185Syz147069 544*688b07c5Sgc161489 if (req->bulk_completion_reason && data) { 54560b08185Syz147069 54660b08185Syz147069 /* 54760b08185Syz147069 * Data wasn't transfered successfully. 54860b08185Syz147069 * Put data back on the queue. 54960b08185Syz147069 */ 55060b08185Syz147069 keyspan_put_head(&kp->kp_tx_mp, data, kp); 55160b08185Syz147069 55260b08185Syz147069 /* don't release mem in usb_free_bulk_req */ 55360b08185Syz147069 req->bulk_data = NULL; 55460b08185Syz147069 } 55560b08185Syz147069 55660b08185Syz147069 usb_free_bulk_req(req); 55760b08185Syz147069 55860b08185Syz147069 /* if more data available, kick off another transmit */ 55960b08185Syz147069 mutex_enter(&kp->kp_mutex); 56060b08185Syz147069 if (kp->kp_tx_mp == NULL) { 561*688b07c5Sgc161489 /* 562*688b07c5Sgc161489 * Attach a zero packet if data length is muliple of 64, 563*688b07c5Sgc161489 * due to the specification of keyspan_usa19hs. 564*688b07c5Sgc161489 */ 565*688b07c5Sgc161489 if ((kp->kp_ksp->ks_dev_spec.id_product == 566*688b07c5Sgc161489 KEYSPAN_USA19HS_PID) && (data_len == 64)) { 567*688b07c5Sgc161489 kp->kp_tx_mp = allocb(0, BPRI_LO); 568*688b07c5Sgc161489 if (kp->kp_tx_mp) { 569*688b07c5Sgc161489 keyspan_tx_start(kp, NULL); 570*688b07c5Sgc161489 mutex_exit(&kp->kp_mutex); 571*688b07c5Sgc161489 572*688b07c5Sgc161489 return; 573*688b07c5Sgc161489 } 574*688b07c5Sgc161489 } 57560b08185Syz147069 57660b08185Syz147069 /* no more data, notify waiters */ 57760b08185Syz147069 cv_broadcast(&kp->kp_tx_cv); 57860b08185Syz147069 mutex_exit(&kp->kp_mutex); 57960b08185Syz147069 58060b08185Syz147069 /* tx callback for this port */ 58160b08185Syz147069 kp->kp_cb.cb_tx(kp->kp_cb.cb_arg); 58260b08185Syz147069 } else { 58360b08185Syz147069 keyspan_tx_start(kp, NULL); 58460b08185Syz147069 mutex_exit(&kp->kp_mutex); 58560b08185Syz147069 } 58660b08185Syz147069 } 58760b08185Syz147069 588c138f478Syz147069 589c138f478Syz147069 /* For incoming data only. Parse a status byte and return the err code */ 590c138f478Syz147069 void 591c138f478Syz147069 keyspan_parse_status(uchar_t *status, uchar_t *err) 592c138f478Syz147069 { 593c138f478Syz147069 if (*status & RXERROR_BREAK) { 594c138f478Syz147069 /* 595c138f478Syz147069 * Parity and Framing errors only count if they 596c138f478Syz147069 * occur exclusive of a break being received. 597c138f478Syz147069 */ 598c138f478Syz147069 *status &= (uint8_t)(RXERROR_OVERRUN | RXERROR_BREAK); 599c138f478Syz147069 } 600c138f478Syz147069 *err |= (*status & RXERROR_OVERRUN) ? DS_OVERRUN_ERR : 0; 601c138f478Syz147069 *err |= (*status & RXERROR_PARITY) ? DS_PARITY_ERR : 0; 602c138f478Syz147069 *err |= (*status & RXERROR_FRAMING) ? DS_FRAMING_ERR : 0; 603c138f478Syz147069 *err |= (*status & RXERROR_BREAK) ? DS_BREAK_ERR : 0; 604c138f478Syz147069 } 605c138f478Syz147069 606c138f478Syz147069 60760b08185Syz147069 /* 60860b08185Syz147069 * pipe callbacks 60960b08185Syz147069 * -------------- 61060b08185Syz147069 * 61160b08185Syz147069 * bulk in common callback for usa19hs model 61260b08185Syz147069 */ 61360b08185Syz147069 /*ARGSUSED*/ 61460b08185Syz147069 int 61560b08185Syz147069 keyspan_bulkin_cb_usa19hs(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 61660b08185Syz147069 { 61760b08185Syz147069 keyspan_port_t *kp = (keyspan_port_t *)req->bulk_client_private; 61860b08185Syz147069 keyspan_pipe_t *bulkin = &kp->kp_datain_pipe; 61960b08185Syz147069 mblk_t *data = req->bulk_data; 62060b08185Syz147069 uint_t cr = req->bulk_completion_reason; 62160b08185Syz147069 int data_len; 62260b08185Syz147069 62360b08185Syz147069 ASSERT(mutex_owned(&kp->kp_mutex)); 62460b08185Syz147069 62560b08185Syz147069 data_len = (data) ? MBLKL(data) : 0; 62660b08185Syz147069 62760b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 62860b08185Syz147069 "keyspan_bulkin_cb_usa19hs: len=%d" 62960b08185Syz147069 " cr=%d flags=%x baud=%x", 63060b08185Syz147069 data_len, cr, req->bulk_cb_flags, kp->kp_baud); 63160b08185Syz147069 63260b08185Syz147069 /* put data on the read queue */ 63360b08185Syz147069 if ((data_len > 0) && (kp->kp_state != KEYSPAN_PORT_CLOSED) && 63460b08185Syz147069 (cr == USB_CR_OK)) { 635c138f478Syz147069 uchar_t status = data->b_rptr[0]; 636c138f478Syz147069 uchar_t err = 0; 637c138f478Syz147069 mblk_t *mp; 63860b08185Syz147069 /* 639c138f478Syz147069 * According to Keyspan spec, if 0x80 bit is clear, there is 640c138f478Syz147069 * only one status byte at the head of the data buf; if 0x80 bit 641c138f478Syz147069 * set, then data buf contains alternate status and data bytes; 642c138f478Syz147069 * In the first case, only OVERRUN err can exist; In the second 643c138f478Syz147069 * case, there are four kinds of err bits may appear in status. 64460b08185Syz147069 */ 645c138f478Syz147069 646c138f478Syz147069 /* if 0x80 bit AND overrun bit are clear, just send up data */ 647c138f478Syz147069 if (!(status & 0x80) && !(status & RXERROR_OVERRUN)) { 64860b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 64960b08185Syz147069 "keyspan_bulkin_cb_usa19hs: len=%d", 65060b08185Syz147069 data_len); 65160b08185Syz147069 652c138f478Syz147069 /* Get rid of the first status byte and send up data */ 65360b08185Syz147069 data->b_rptr++; 65460b08185Syz147069 data_len--; 65560b08185Syz147069 if (data_len > 0) { 65660b08185Syz147069 keyspan_put_tail(&kp->kp_rx_mp, data); 65760b08185Syz147069 65860b08185Syz147069 /* 65960b08185Syz147069 * the data will not be freed and 66060b08185Syz147069 * will be sent up later. 66160b08185Syz147069 */ 66260b08185Syz147069 req->bulk_data = NULL; 66360b08185Syz147069 } 664c138f478Syz147069 } else if (!(status & 0x80)) { 665c138f478Syz147069 /* If 0x80 bit is clear and overrun bit is set */ 666c138f478Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh, 667c138f478Syz147069 "keyspan_bulkin_cb_usa19hs: usb xfer is OK," 668c138f478Syz147069 " but there is overrun err in serial xfer"); 66960b08185Syz147069 670c138f478Syz147069 keyspan_parse_status(&status, &err); 671c138f478Syz147069 mutex_exit(&kp->kp_mutex); 672c138f478Syz147069 if ((mp = allocb(2, BPRI_HI)) == NULL) { 673c138f478Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, kp->kp_lh, 674c138f478Syz147069 "keyspan_bulkin_cb_usa19hs: allocb failed"); 675c138f478Syz147069 mutex_enter(&kp->kp_mutex); 67660b08185Syz147069 677c138f478Syz147069 return (0); 678c138f478Syz147069 } 679c138f478Syz147069 DB_TYPE(mp) = M_BREAK; 680c138f478Syz147069 *mp->b_wptr++ = err; 681c138f478Syz147069 *mp->b_wptr++ = status; 682c138f478Syz147069 mutex_enter(&kp->kp_mutex); 683c138f478Syz147069 684c138f478Syz147069 /* Add to the received list; Send up the err code. */ 685c138f478Syz147069 keyspan_put_tail(&kp->kp_rx_mp, mp); 686c138f478Syz147069 687c138f478Syz147069 /* 688c138f478Syz147069 * Don't send up the first byte because 689c138f478Syz147069 * it is a status byte. 690c138f478Syz147069 */ 691c138f478Syz147069 data->b_rptr++; 692c138f478Syz147069 data_len--; 693c138f478Syz147069 if (data_len > 0) { 694c138f478Syz147069 keyspan_put_tail(&kp->kp_rx_mp, data); 695c138f478Syz147069 696c138f478Syz147069 /* 697c138f478Syz147069 * the data will not be freed and 698c138f478Syz147069 * will be sent up later. 699c138f478Syz147069 */ 700c138f478Syz147069 req->bulk_data = NULL; 701c138f478Syz147069 } 702c138f478Syz147069 } else { /* 0x80 bit set, there are some errs in the data */ 703c138f478Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh, 704c138f478Syz147069 "keyspan_bulkin_cb_usa19hs: usb xfer is OK," 705c138f478Syz147069 " but there are errs in serial xfer"); 706c138f478Syz147069 /* 707c138f478Syz147069 * Usually, there are at least two bytes, 708c138f478Syz147069 * one status and one data. 709c138f478Syz147069 */ 71060b08185Syz147069 if (data_len > 1) { 71160b08185Syz147069 int i = 0; 71260b08185Syz147069 int j = 1; 713c138f478Syz147069 /* 714c138f478Syz147069 * In this case, there might be multi status 715c138f478Syz147069 * bytes. Parse each status byte and move the 716c138f478Syz147069 * data bytes together. 717c138f478Syz147069 */ 71860b08185Syz147069 for (j = 1; j < data_len; j += 2) { 719c138f478Syz147069 status = data->b_rptr[j-1]; 720c138f478Syz147069 keyspan_parse_status(&status, &err); 721c138f478Syz147069 722c138f478Syz147069 /* move the data togeter */ 72360b08185Syz147069 data->b_rptr[i] = data->b_rptr[j]; 72460b08185Syz147069 i++; 72560b08185Syz147069 } 72660b08185Syz147069 data->b_wptr = data->b_rptr + i; 727c138f478Syz147069 } else { /* There are only one byte in incoming buf */ 728c138f478Syz147069 keyspan_parse_status(&status, &err); 729c138f478Syz147069 } 730c138f478Syz147069 mutex_exit(&kp->kp_mutex); 731c138f478Syz147069 if ((mp = allocb(2, BPRI_HI)) == NULL) { 732c138f478Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, kp->kp_lh, 733c138f478Syz147069 "keyspan_bulkin_cb_usa19hs: allocb failed"); 734c138f478Syz147069 mutex_enter(&kp->kp_mutex); 73560b08185Syz147069 736c138f478Syz147069 return (0); 737c138f478Syz147069 } 738c138f478Syz147069 DB_TYPE(mp) = M_BREAK; 739c138f478Syz147069 *mp->b_wptr++ = err; 740c138f478Syz147069 if (data_len > 2) { 741c138f478Syz147069 /* 742c138f478Syz147069 * There are multiple status bytes in this case. 743c138f478Syz147069 * Use err as status character since err is got 744c138f478Syz147069 * by or in all status bytes. 745c138f478Syz147069 */ 746c138f478Syz147069 *mp->b_wptr++ = err; 747c138f478Syz147069 } else { 748c138f478Syz147069 *mp->b_wptr++ = status; 749c138f478Syz147069 } 750c138f478Syz147069 mutex_enter(&kp->kp_mutex); 751c138f478Syz147069 752c138f478Syz147069 /* Add to the received list; Send up the err code. */ 753c138f478Syz147069 keyspan_put_tail(&kp->kp_rx_mp, mp); 754c138f478Syz147069 755c138f478Syz147069 if (data_len > 1) { 756c138f478Syz147069 data_len = data->b_wptr - data->b_rptr; 757c138f478Syz147069 keyspan_put_tail(&kp->kp_rx_mp, data); 75860b08185Syz147069 /* 75960b08185Syz147069 * The data will not be freed and 76060b08185Syz147069 * will be sent up later. 76160b08185Syz147069 */ 76260b08185Syz147069 req->bulk_data = NULL; 763c138f478Syz147069 } 764c138f478Syz147069 } 765c138f478Syz147069 } else { /* usb error happened, so don't send up data */ 76660b08185Syz147069 data_len = 0; 76760b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 76860b08185Syz147069 "keyspan_bulkin_cb_usa19hs: error happened, len=%d, " 76960b08185Syz147069 "cr=0x%x, cb_flags=0x%x", data_len, cr, req->bulk_cb_flags); 770c138f478Syz147069 } 77160b08185Syz147069 if (kp->kp_state != KEYSPAN_PORT_OPEN) { 77260b08185Syz147069 kp->kp_no_more_reads = B_TRUE; 77360b08185Syz147069 } 77460b08185Syz147069 77560b08185Syz147069 return (data_len); 77660b08185Syz147069 } 77760b08185Syz147069 778c138f478Syz147069 77960b08185Syz147069 /* 78060b08185Syz147069 * pipe callbacks 78160b08185Syz147069 * -------------- 78260b08185Syz147069 * 78360b08185Syz147069 * bulk in common callback for usa49 model 78460b08185Syz147069 */ 78560b08185Syz147069 /*ARGSUSED*/ 78660b08185Syz147069 int 78760b08185Syz147069 keyspan_bulkin_cb_usa49(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 78860b08185Syz147069 { 78960b08185Syz147069 keyspan_port_t *kp = (keyspan_port_t *)req->bulk_client_private; 79060b08185Syz147069 keyspan_pipe_t *bulkin = &kp->kp_datain_pipe; 79160b08185Syz147069 mblk_t *data = req->bulk_data; 79260b08185Syz147069 uint_t cr = req->bulk_completion_reason; 79360b08185Syz147069 int data_len; 79460b08185Syz147069 79560b08185Syz147069 ASSERT(mutex_owned(&kp->kp_mutex)); 79660b08185Syz147069 79760b08185Syz147069 data_len = (data) ? MBLKL(data) : 0; 79860b08185Syz147069 79960b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 80060b08185Syz147069 "keyspan_bulkin_cb_usa49: len=%d" 80160b08185Syz147069 " cr=%d flags=%x", data_len, cr, req->bulk_cb_flags); 80260b08185Syz147069 80360b08185Syz147069 /* put data on the read queue */ 80460b08185Syz147069 if ((data_len > 0) && (kp->kp_state != KEYSPAN_PORT_CLOSED) && 80560b08185Syz147069 (cr == USB_CR_OK)) { 806c138f478Syz147069 uchar_t status = data->b_rptr[0]; 807c138f478Syz147069 uchar_t err = 0; 808c138f478Syz147069 mblk_t *mp; 80960b08185Syz147069 /* 810c138f478Syz147069 * According to Keyspan spec, if 0x80 bit is clear, there is 811c138f478Syz147069 * only one status byte at the head of the data buf; if 0x80 bit 812c138f478Syz147069 * set, then data buf contains alternate status and data bytes; 813c138f478Syz147069 * In the first case, only OVERRUN err can exist; In the second 814c138f478Syz147069 * case, there are four kinds of err bits may appear in status. 81560b08185Syz147069 */ 81660b08185Syz147069 817c138f478Syz147069 /* if 0x80 bit AND overrun bit are clear, just send up data */ 818c138f478Syz147069 if (!(status & 0x80) && !(status & RXERROR_OVERRUN)) { 819c138f478Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 820c138f478Syz147069 "keyspan_bulkin_cb_usa49: len=%d", 821c138f478Syz147069 data_len); 822c138f478Syz147069 823c138f478Syz147069 /* Get rid of the first status byte and send up data */ 82460b08185Syz147069 data->b_rptr++; 82560b08185Syz147069 data_len--; 82660b08185Syz147069 if (data_len > 0) { 82760b08185Syz147069 keyspan_put_tail(&kp->kp_rx_mp, data); 82860b08185Syz147069 82960b08185Syz147069 /* 830c138f478Syz147069 * the data will not be freed and 83160b08185Syz147069 * will be sent up later. 83260b08185Syz147069 */ 83360b08185Syz147069 req->bulk_data = NULL; 83460b08185Syz147069 } 835c138f478Syz147069 } else if (!(status & 0x80)) { 836c138f478Syz147069 /* If 0x80 bit is clear and overrun bit is set */ 837c138f478Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh, 838c138f478Syz147069 "keyspan_bulkin_cb_usa49: usb xfer is OK," 839c138f478Syz147069 " but there is overrun err in serial xfer"); 840c138f478Syz147069 841c138f478Syz147069 keyspan_parse_status(&status, &err); 842c138f478Syz147069 mutex_exit(&kp->kp_mutex); 843c138f478Syz147069 if ((mp = allocb(2, BPRI_HI)) == NULL) { 844c138f478Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, kp->kp_lh, 845c138f478Syz147069 "keyspan_bulkin_cb_usa49: allocb failed"); 846c138f478Syz147069 mutex_enter(&kp->kp_mutex); 847c138f478Syz147069 848c138f478Syz147069 return (0); 849c138f478Syz147069 } 850c138f478Syz147069 DB_TYPE(mp) = M_BREAK; 851c138f478Syz147069 *mp->b_wptr++ = err; 852c138f478Syz147069 *mp->b_wptr++ = status; 853c138f478Syz147069 mutex_enter(&kp->kp_mutex); 854c138f478Syz147069 855c138f478Syz147069 /* Add to the received list; Send up the err code. */ 856c138f478Syz147069 keyspan_put_tail(&kp->kp_rx_mp, mp); 857c138f478Syz147069 858c138f478Syz147069 /* 859c138f478Syz147069 * Don't send up the first byte because 860c138f478Syz147069 * it is a status byte. 861c138f478Syz147069 */ 862c138f478Syz147069 data->b_rptr++; 863c138f478Syz147069 data_len--; 864c138f478Syz147069 if (data_len > 0) { 865c138f478Syz147069 keyspan_put_tail(&kp->kp_rx_mp, data); 866c138f478Syz147069 867c138f478Syz147069 /* 868c138f478Syz147069 * the data will not be freed and 869c138f478Syz147069 * will be sent up later. 870c138f478Syz147069 */ 871c138f478Syz147069 req->bulk_data = NULL; 872c138f478Syz147069 } 873c138f478Syz147069 } else { /* 0x80 bit set, there are some errs in the data */ 874c138f478Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh, 875c138f478Syz147069 "keyspan_bulkin_cb_usa49: usb xfer is OK," 876c138f478Syz147069 " but there are errs in serial xfer"); 877c138f478Syz147069 /* 878c138f478Syz147069 * Usually, there are at least two bytes, 879c138f478Syz147069 * one status and one data. 880c138f478Syz147069 */ 88160b08185Syz147069 if (data_len > 1) { 88260b08185Syz147069 int i = 0; 88360b08185Syz147069 int j = 1; 884c138f478Syz147069 /* 885c138f478Syz147069 * In this case, there might be multi status 886c138f478Syz147069 * bytes. Parse each status byte and move the 887c138f478Syz147069 * data bytes together. 888c138f478Syz147069 */ 88960b08185Syz147069 for (j = 1; j < data_len; j += 2) { 890c138f478Syz147069 status = data->b_rptr[j-1]; 891c138f478Syz147069 keyspan_parse_status(&status, &err); 892c138f478Syz147069 893c138f478Syz147069 /* move the data togeter */ 89460b08185Syz147069 data->b_rptr[i] = data->b_rptr[j]; 89560b08185Syz147069 i++; 89660b08185Syz147069 } 89760b08185Syz147069 data->b_wptr = data->b_rptr + i; 898c138f478Syz147069 } else { /* There are only one byte in incoming buf */ 899c138f478Syz147069 keyspan_parse_status(&status, &err); 900c138f478Syz147069 } 901c138f478Syz147069 mutex_exit(&kp->kp_mutex); 902c138f478Syz147069 if ((mp = allocb(2, BPRI_HI)) == NULL) { 903c138f478Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, kp->kp_lh, 904c138f478Syz147069 "keyspan_bulkin_cb_usa49: allocb failed"); 905c138f478Syz147069 mutex_enter(&kp->kp_mutex); 90660b08185Syz147069 907c138f478Syz147069 return (0); 908c138f478Syz147069 } 909c138f478Syz147069 DB_TYPE(mp) = M_BREAK; 910c138f478Syz147069 *mp->b_wptr++ = err; 911c138f478Syz147069 if (data_len > 2) { 912c138f478Syz147069 /* 913c138f478Syz147069 * There are multiple status bytes in this case. 914c138f478Syz147069 * Use err as status character since err is got 915c138f478Syz147069 * by or in all status bytes. 916c138f478Syz147069 */ 917c138f478Syz147069 *mp->b_wptr++ = err; 918c138f478Syz147069 } else { 919c138f478Syz147069 *mp->b_wptr++ = status; 920c138f478Syz147069 } 921c138f478Syz147069 mutex_enter(&kp->kp_mutex); 922c138f478Syz147069 923c138f478Syz147069 /* Add to the received list; Send up the err code. */ 924c138f478Syz147069 keyspan_put_tail(&kp->kp_rx_mp, mp); 925c138f478Syz147069 926c138f478Syz147069 if (data_len > 1) { 927c138f478Syz147069 data_len = data->b_wptr - data->b_rptr; 928c138f478Syz147069 keyspan_put_tail(&kp->kp_rx_mp, data); 92960b08185Syz147069 /* 93060b08185Syz147069 * The data will not be freed and 93160b08185Syz147069 * will be sent up later. 93260b08185Syz147069 */ 93360b08185Syz147069 req->bulk_data = NULL; 93460b08185Syz147069 } 93560b08185Syz147069 } 93660b08185Syz147069 } else { 93760b08185Syz147069 /* usb error happened, so don't send up data */ 93860b08185Syz147069 data_len = 0; 93960b08185Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh, 94060b08185Syz147069 "keyspan_bulkin_cb_usa49: port_state=%d" 94160b08185Syz147069 " b_rptr[0]=%c", kp->kp_state, data->b_rptr[0]); 942c138f478Syz147069 } 94360b08185Syz147069 if (kp->kp_state != KEYSPAN_PORT_OPEN) { 94460b08185Syz147069 kp->kp_no_more_reads = B_TRUE; 94560b08185Syz147069 } 94660b08185Syz147069 94760b08185Syz147069 return (data_len); 94860b08185Syz147069 } 949c138f478Syz147069 95060b08185Syz147069 95160b08185Syz147069 /* 95260b08185Syz147069 * pipe callbacks 95360b08185Syz147069 * -------------- 95460b08185Syz147069 * 95560b08185Syz147069 * bulk in common callback 95660b08185Syz147069 */ 95760b08185Syz147069 /*ARGSUSED*/ 95860b08185Syz147069 void 95960b08185Syz147069 keyspan_bulkin_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 96060b08185Syz147069 { 96160b08185Syz147069 keyspan_port_t *kp = (keyspan_port_t *)req->bulk_client_private; 96260b08185Syz147069 keyspan_state_t *ksp = kp->kp_ksp; 96360b08185Syz147069 int data_len; 96460b08185Syz147069 boolean_t no_more_reads = B_FALSE; 96560b08185Syz147069 96660b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, (&kp->kp_datain_pipe)->pipe_lh, 96760b08185Syz147069 "keyspan_bulkin_cb"); 96860b08185Syz147069 96960b08185Syz147069 mutex_enter(&kp->kp_mutex); 97060b08185Syz147069 97160b08185Syz147069 /* put data on the read queue */ 97260b08185Syz147069 switch (ksp->ks_dev_spec.id_product) { 97360b08185Syz147069 case KEYSPAN_USA19HS_PID: 97460b08185Syz147069 data_len = keyspan_bulkin_cb_usa19hs(pipe, req); 97560b08185Syz147069 97660b08185Syz147069 break; 97760b08185Syz147069 978c138f478Syz147069 97960b08185Syz147069 case KEYSPAN_USA49WLC_PID: 98060b08185Syz147069 data_len = keyspan_bulkin_cb_usa49(pipe, req); 98160b08185Syz147069 98260b08185Syz147069 break; 983c138f478Syz147069 98460b08185Syz147069 default: 98560b08185Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, (&kp->kp_datain_pipe)->pipe_lh, 98660b08185Syz147069 "keyspan_bulkin_cb:" 98760b08185Syz147069 "the device's product id can't be recognized"); 98860b08185Syz147069 mutex_exit(&kp->kp_mutex); 98960b08185Syz147069 99060b08185Syz147069 return; 99160b08185Syz147069 } 99260b08185Syz147069 99360b08185Syz147069 no_more_reads = kp->kp_no_more_reads; 99460b08185Syz147069 99560b08185Syz147069 mutex_exit(&kp->kp_mutex); 99660b08185Syz147069 99760b08185Syz147069 usb_free_bulk_req(req); 99860b08185Syz147069 99960b08185Syz147069 /* kick off another read unless indicated otherwise */ 100060b08185Syz147069 if (!no_more_reads) { 100160b08185Syz147069 (void) keyspan_receive_data(&kp->kp_datain_pipe, 100260b08185Syz147069 kp->kp_read_len, kp); 100360b08185Syz147069 } 100460b08185Syz147069 100560b08185Syz147069 /* setup rx callback for this port */ 100660b08185Syz147069 if (data_len > 0) { 100760b08185Syz147069 kp->kp_cb.cb_rx(kp->kp_cb.cb_arg); 100860b08185Syz147069 } 100960b08185Syz147069 } 101060b08185Syz147069 101160b08185Syz147069 /* 101260b08185Syz147069 * pipe callbacks 101360b08185Syz147069 * -------------- 101460b08185Syz147069 * 101560b08185Syz147069 * bulk in status callback for usa19hs model 101660b08185Syz147069 */ 101760b08185Syz147069 /*ARGSUSED*/ 101860b08185Syz147069 void 101960b08185Syz147069 keyspan_status_cb_usa19hs(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 102060b08185Syz147069 { 102160b08185Syz147069 keyspan_state_t *ksp = (keyspan_state_t *)req->bulk_client_private; 102260b08185Syz147069 keyspan_pipe_t *bulkin = &ksp->ks_statin_pipe; 102360b08185Syz147069 mblk_t *data = req->bulk_data; 102460b08185Syz147069 usb_cr_t cr = req->bulk_completion_reason; 102560b08185Syz147069 int data_len; 102660b08185Syz147069 102760b08185Syz147069 data_len = (data) ? MBLKL(data) : 0; 102860b08185Syz147069 102960b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 103060b08185Syz147069 "keyspan_status_cb_usa19hs: len=%d" 103160b08185Syz147069 " cr=%d flags=%x", data_len, cr, req->bulk_cb_flags); 103260b08185Syz147069 103360b08185Syz147069 /* put data on the read queue */ 103460b08185Syz147069 if ((data_len == 14) && (cr == USB_CR_OK)) { 103560b08185Syz147069 keyspan_port_t *kp = &ksp->ks_ports[0]; 103660b08185Syz147069 keyspan_usa19hs_port_status_msg_t *status_msg = 103760b08185Syz147069 &(kp->kp_status_msg.usa19hs); 103860b08185Syz147069 103960b08185Syz147069 mutex_enter(&kp->kp_mutex); 104060b08185Syz147069 bcopy(data->b_rptr, status_msg, data_len); 104160b08185Syz147069 104260b08185Syz147069 if (status_msg->controlResponse) { 104360b08185Syz147069 kp->kp_status_flag |= KEYSPAN_PORT_CTRLRESP; 104460b08185Syz147069 } else { 104560b08185Syz147069 kp->kp_status_flag &= ~KEYSPAN_PORT_CTRLRESP; 104660b08185Syz147069 } 104760b08185Syz147069 104860b08185Syz147069 if (status_msg->portState & PORTSTATE_ENABLED) { 104960b08185Syz147069 kp->kp_status_flag |= KEYSPAN_PORT_ENABLE; 105060b08185Syz147069 } else { 105160b08185Syz147069 kp->kp_status_flag &= ~KEYSPAN_PORT_ENABLE; 105260b08185Syz147069 } 105360b08185Syz147069 105460b08185Syz147069 if (status_msg->portState & PORTSTATE_TXBREAK) { 105560b08185Syz147069 kp->kp_status_flag |= KEYSPAN_PORT_TXBREAK; 105660b08185Syz147069 } else { 105760b08185Syz147069 kp->kp_status_flag &= ~KEYSPAN_PORT_TXBREAK; 105860b08185Syz147069 } 105960b08185Syz147069 106060b08185Syz147069 if (status_msg->rxBreak) { 106160b08185Syz147069 kp->kp_status_flag |= KEYSPAN_PORT_RXBREAK; 106260b08185Syz147069 } else { 106360b08185Syz147069 kp->kp_status_flag &= ~KEYSPAN_PORT_RXBREAK; 106460b08185Syz147069 } 106560b08185Syz147069 106660b08185Syz147069 if (status_msg->portState & PORTSTATE_LOOPBACK) { 106760b08185Syz147069 kp->kp_status_flag |= KEYSPAN_PORT_LOOPBACK; 106860b08185Syz147069 } else { 106960b08185Syz147069 kp->kp_status_flag &= ~KEYSPAN_PORT_LOOPBACK; 107060b08185Syz147069 } 107160b08185Syz147069 107260b08185Syz147069 /* if msr status changed, then invoke status callback */ 107360b08185Syz147069 if (status_msg->msr & USA_MSR_dCTS || 107460b08185Syz147069 status_msg->msr & USA_MSR_dDSR || 107560b08185Syz147069 status_msg->msr & USA_MSR_dRI || 107660b08185Syz147069 status_msg->msr & USA_MSR_dDCD) { 107760b08185Syz147069 107860b08185Syz147069 mutex_exit(&kp->kp_mutex); 107960b08185Syz147069 kp->kp_cb.cb_status(kp->kp_cb.cb_arg); 108060b08185Syz147069 } else { 108160b08185Syz147069 mutex_exit(&kp->kp_mutex); 108260b08185Syz147069 } 108360b08185Syz147069 } else { 108460b08185Syz147069 108560b08185Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh, 108660b08185Syz147069 "keyspan_status_cb_usa19hs: get status failed, cr=%d" 108760b08185Syz147069 " data_len=%d", cr, data_len); 108860b08185Syz147069 } 108960b08185Syz147069 } 109060b08185Syz147069 1091c138f478Syz147069 109260b08185Syz147069 /* 109360b08185Syz147069 * pipe callbacks 109460b08185Syz147069 * -------------- 109560b08185Syz147069 * 109660b08185Syz147069 * bulk in status callback for usa49 model 109760b08185Syz147069 */ 109860b08185Syz147069 /*ARGSUSED*/ 109960b08185Syz147069 void 110060b08185Syz147069 keyspan_status_cb_usa49(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 110160b08185Syz147069 { 110260b08185Syz147069 keyspan_state_t *ksp = (keyspan_state_t *)req->bulk_client_private; 110360b08185Syz147069 keyspan_pipe_t *bulkin = &ksp->ks_statin_pipe; 110460b08185Syz147069 mblk_t *data = req->bulk_data; 110560b08185Syz147069 uint_t cr = req->bulk_completion_reason; 110660b08185Syz147069 int data_len; 110760b08185Syz147069 110860b08185Syz147069 data_len = (data) ? MBLKL(data) : 0; 110960b08185Syz147069 111060b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 111160b08185Syz147069 "keyspan_status_cb_usa49: len=%d" 111260b08185Syz147069 " cr=%d flags=%x", data_len, cr, req->bulk_cb_flags); 111360b08185Syz147069 111460b08185Syz147069 /* put data on the read queue */ 111560b08185Syz147069 if ((data_len == 11) && (cr == USB_CR_OK)) { 111660b08185Syz147069 keyspan_usa49_port_status_msg_t status_msg; 111760b08185Syz147069 keyspan_port_t *cur_kp; 111860b08185Syz147069 keyspan_usa49_port_status_msg_t *kp_status_msg; 111960b08185Syz147069 boolean_t need_cb = B_FALSE; 112060b08185Syz147069 112160b08185Syz147069 bcopy(data->b_rptr, &status_msg, data_len); 112260b08185Syz147069 if (status_msg.portNumber >= ksp->ks_dev_spec.port_cnt) { 112360b08185Syz147069 112460b08185Syz147069 return; 112560b08185Syz147069 } 112660b08185Syz147069 cur_kp = &ksp->ks_ports[status_msg.portNumber]; 112760b08185Syz147069 kp_status_msg = &(cur_kp->kp_status_msg.usa49); 112860b08185Syz147069 112960b08185Syz147069 mutex_enter(&cur_kp->kp_mutex); 113060b08185Syz147069 113160b08185Syz147069 /* if msr status changed, then need invoke status callback */ 113260b08185Syz147069 if (status_msg.cts != kp_status_msg->cts || 113360b08185Syz147069 status_msg.dsr != kp_status_msg->dsr || 113460b08185Syz147069 status_msg.ri != kp_status_msg->ri || 113560b08185Syz147069 status_msg.dcd != kp_status_msg->dcd) { 113660b08185Syz147069 113760b08185Syz147069 need_cb = B_TRUE; 113860b08185Syz147069 } 113960b08185Syz147069 114060b08185Syz147069 bcopy(&status_msg, kp_status_msg, data_len); 114160b08185Syz147069 114260b08185Syz147069 if (kp_status_msg->controlResponse) { 114360b08185Syz147069 cur_kp->kp_status_flag |= KEYSPAN_PORT_CTRLRESP; 114460b08185Syz147069 } else { 114560b08185Syz147069 cur_kp->kp_status_flag &= ~KEYSPAN_PORT_CTRLRESP; 114660b08185Syz147069 } 114760b08185Syz147069 114860b08185Syz147069 if (!kp_status_msg->rxEnabled) { 114960b08185Syz147069 cur_kp->kp_status_flag |= KEYSPAN_PORT_RXBREAK; 115060b08185Syz147069 } else { 115160b08185Syz147069 cur_kp->kp_status_flag &= ~KEYSPAN_PORT_RXBREAK; 115260b08185Syz147069 } 115360b08185Syz147069 115460b08185Syz147069 mutex_exit(&cur_kp->kp_mutex); 115560b08185Syz147069 115660b08185Syz147069 if (need_cb) { 115760b08185Syz147069 115860b08185Syz147069 cur_kp->kp_cb.cb_status(cur_kp->kp_cb.cb_arg); 115960b08185Syz147069 } 116060b08185Syz147069 } else { 116160b08185Syz147069 116260b08185Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh, 116360b08185Syz147069 "keyspan_status_cb_usa49: get status failed, cr=%d" 116460b08185Syz147069 " data_len=%d", cr, data_len); 116560b08185Syz147069 } 116660b08185Syz147069 } 1167c138f478Syz147069 116860b08185Syz147069 116960b08185Syz147069 /* 117060b08185Syz147069 * pipe callbacks 117160b08185Syz147069 * -------------- 117260b08185Syz147069 * 117360b08185Syz147069 * bulk in callback for status receiving 117460b08185Syz147069 */ 117560b08185Syz147069 /*ARGSUSED*/ 117660b08185Syz147069 void 117760b08185Syz147069 keyspan_status_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 117860b08185Syz147069 { 117960b08185Syz147069 keyspan_state_t *ksp = (keyspan_state_t *)req->bulk_client_private; 118060b08185Syz147069 usb_cr_t cr = req->bulk_completion_reason; 118160b08185Syz147069 118260b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, (&ksp->ks_statin_pipe)->pipe_lh, 118360b08185Syz147069 "keyspan_status_cb"); 118460b08185Syz147069 118560b08185Syz147069 /* put data on the read queue */ 118660b08185Syz147069 switch (ksp->ks_dev_spec.id_product) { 118760b08185Syz147069 case KEYSPAN_USA19HS_PID: 118860b08185Syz147069 keyspan_status_cb_usa19hs(pipe, req); 118960b08185Syz147069 119060b08185Syz147069 break; 119160b08185Syz147069 1192c138f478Syz147069 119360b08185Syz147069 case KEYSPAN_USA49WLC_PID: 119460b08185Syz147069 keyspan_status_cb_usa49(pipe, req); 119560b08185Syz147069 119660b08185Syz147069 break; 1197c138f478Syz147069 119860b08185Syz147069 default: 119960b08185Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, 120060b08185Syz147069 (&ksp->ks_statin_pipe)->pipe_lh, "keyspan_status_cb:" 120160b08185Syz147069 "the device's product id can't be recognized"); 120260b08185Syz147069 120360b08185Syz147069 return; 120460b08185Syz147069 } 120560b08185Syz147069 120660b08185Syz147069 usb_free_bulk_req(req); 120760b08185Syz147069 120860b08185Syz147069 /* kick off another read to receive status */ 120960b08185Syz147069 if ((cr != USB_CR_FLUSHED) && (cr != USB_CR_DEV_NOT_RESP) && 121060b08185Syz147069 keyspan_dev_is_online(ksp)) { 121160b08185Syz147069 if (keyspan_receive_status(ksp) != USB_SUCCESS) { 121260b08185Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, 121360b08185Syz147069 (&ksp->ks_statin_pipe)->pipe_lh, 121460b08185Syz147069 "keyspan_status_cb:" 121560b08185Syz147069 "receive status can't be restarted."); 121660b08185Syz147069 } 121760b08185Syz147069 } else { 121860b08185Syz147069 USB_DPRINTF_L2(DPRINT_IN_PIPE, 121960b08185Syz147069 (&ksp->ks_statin_pipe)->pipe_lh, "keyspan_status_cb:" 122060b08185Syz147069 "get status failed: cr=%d", cr); 122160b08185Syz147069 } 122260b08185Syz147069 } 122360b08185Syz147069 122460b08185Syz147069 /* 122560b08185Syz147069 * Submit data read request (asynchronous). If this function returns 122660b08185Syz147069 * USB_SUCCESS, pipe is acquired and request is sent, otherwise req is free. 122760b08185Syz147069 */ 122860b08185Syz147069 int 122960b08185Syz147069 keyspan_receive_data(keyspan_pipe_t *bulkin, int len, void *cb_arg) 123060b08185Syz147069 { 123160b08185Syz147069 keyspan_state_t *ksp = bulkin->pipe_ksp; 123260b08185Syz147069 usb_bulk_req_t *br; 123360b08185Syz147069 int rval; 123460b08185Syz147069 123560b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, "keyspan_receive_data:" 123660b08185Syz147069 "len=%d", len); 123760b08185Syz147069 123860b08185Syz147069 ASSERT(!mutex_owned(&bulkin->pipe_mutex)); 123960b08185Syz147069 124060b08185Syz147069 br = usb_alloc_bulk_req(ksp->ks_dip, len, USB_FLAGS_SLEEP); 124160b08185Syz147069 br->bulk_len = len; 124260b08185Syz147069 124360b08185Syz147069 /* No timeout, just wait for data */ 124460b08185Syz147069 br->bulk_timeout = 0; 124560b08185Syz147069 br->bulk_client_private = cb_arg; 124660b08185Syz147069 br->bulk_attributes = USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING; 124760b08185Syz147069 br->bulk_cb = keyspan_bulkin_cb; 124860b08185Syz147069 br->bulk_exc_cb = keyspan_bulkin_cb; 124960b08185Syz147069 125060b08185Syz147069 rval = usb_pipe_bulk_xfer(bulkin->pipe_handle, br, 0); 125160b08185Syz147069 if (rval != USB_SUCCESS) { 125260b08185Syz147069 usb_free_bulk_req(br); 125360b08185Syz147069 } 125460b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 125560b08185Syz147069 "keyspan_receive_data: rval = %d", rval); 125660b08185Syz147069 return (rval); 125760b08185Syz147069 } 125860b08185Syz147069 125960b08185Syz147069 /* 126060b08185Syz147069 * submit device status read request (asynchronous). 126160b08185Syz147069 */ 126260b08185Syz147069 int 126360b08185Syz147069 keyspan_receive_status(keyspan_state_t *ksp) 126460b08185Syz147069 { 126560b08185Syz147069 keyspan_pipe_t *bulkin = &ksp->ks_statin_pipe; 126660b08185Syz147069 usb_bulk_req_t *br; 126760b08185Syz147069 int rval; 126860b08185Syz147069 126960b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 127060b08185Syz147069 "keyspan_receive_status"); 127160b08185Syz147069 127260b08185Syz147069 ASSERT(!mutex_owned(&bulkin->pipe_mutex)); 127360b08185Syz147069 127460b08185Syz147069 br = usb_alloc_bulk_req(ksp->ks_dip, 32, USB_FLAGS_SLEEP); 127560b08185Syz147069 br->bulk_len = KEYSPAN_STATIN_MAX_LEN; 127660b08185Syz147069 127760b08185Syz147069 /* No timeout, just wait for data */ 127860b08185Syz147069 br->bulk_timeout = 0; 127960b08185Syz147069 br->bulk_client_private = (void *)ksp; 128060b08185Syz147069 br->bulk_attributes = USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING; 128160b08185Syz147069 br->bulk_cb = keyspan_status_cb; 128260b08185Syz147069 br->bulk_exc_cb = keyspan_status_cb; 128360b08185Syz147069 128460b08185Syz147069 rval = usb_pipe_bulk_xfer(bulkin->pipe_handle, br, 0); 128560b08185Syz147069 if (rval != USB_SUCCESS) { 128660b08185Syz147069 usb_free_bulk_req(br); 128760b08185Syz147069 } 128860b08185Syz147069 USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, 128960b08185Syz147069 "keyspan_receive_status: rval = %d", rval); 129060b08185Syz147069 return (rval); 129160b08185Syz147069 } 129260b08185Syz147069 129360b08185Syz147069 /* 129460b08185Syz147069 * submit data for transfer (asynchronous) 129560b08185Syz147069 * 129660b08185Syz147069 * if data was sent successfully, 'mpp' will be nulled to indicate 129760b08185Syz147069 * that mblk is consumed by USBA and no longer belongs to the caller. 129860b08185Syz147069 * 129960b08185Syz147069 * if this function returns USB_SUCCESS, pipe is acquired and request 130060b08185Syz147069 * is sent, otherwise pipe is free. 130160b08185Syz147069 */ 130260b08185Syz147069 int 130360b08185Syz147069 keyspan_send_data(keyspan_pipe_t *bulkout, mblk_t **mpp, void *cb_arg) 130460b08185Syz147069 { 130560b08185Syz147069 keyspan_state_t *ksp = bulkout->pipe_ksp; 130660b08185Syz147069 usb_bulk_req_t *br; 130760b08185Syz147069 int rval; 130860b08185Syz147069 130960b08185Syz147069 ASSERT(!mutex_owned(&bulkout->pipe_mutex)); 131060b08185Syz147069 USB_DPRINTF_L4(DPRINT_OUT_PIPE, bulkout->pipe_lh, 131160b08185Syz147069 "keyspan_send_data"); 131260b08185Syz147069 131360b08185Syz147069 br = usb_alloc_bulk_req(ksp->ks_dip, 0, USB_FLAGS_SLEEP); 131460b08185Syz147069 br->bulk_len = MBLKL(*mpp); 131560b08185Syz147069 br->bulk_data = *mpp; 131660b08185Syz147069 br->bulk_timeout = KEYSPAN_BULK_TIMEOUT; 131760b08185Syz147069 br->bulk_client_private = cb_arg; 131860b08185Syz147069 br->bulk_attributes = USB_ATTRS_AUTOCLEARING; 131960b08185Syz147069 br->bulk_cb = keyspan_bulkout_cb; 132060b08185Syz147069 br->bulk_exc_cb = keyspan_bulkout_cb; 132160b08185Syz147069 132260b08185Syz147069 USB_DPRINTF_L3(DPRINT_OUT_PIPE, bulkout->pipe_lh, "keyspan_send_data:" 132360b08185Syz147069 "bulk_len = %d", br->bulk_len); 132460b08185Syz147069 132560b08185Syz147069 rval = usb_pipe_bulk_xfer(bulkout->pipe_handle, br, 0); 132660b08185Syz147069 if (rval == USB_SUCCESS) { 132760b08185Syz147069 132860b08185Syz147069 /* data consumed. The mem will be released in bulkout_cb */ 132960b08185Syz147069 *mpp = NULL; 133060b08185Syz147069 } else { 133160b08185Syz147069 133260b08185Syz147069 /* 133360b08185Syz147069 * Don't free it in usb_free_bulk_req because it will 133460b08185Syz147069 * be linked in keyspan_put_head 133560b08185Syz147069 */ 133660b08185Syz147069 br->bulk_data = NULL; 133760b08185Syz147069 133860b08185Syz147069 usb_free_bulk_req(br); 133960b08185Syz147069 } 134060b08185Syz147069 USB_DPRINTF_L4(DPRINT_OUT_PIPE, bulkout->pipe_lh, 134160b08185Syz147069 "keyspan_send_data: rval = %d", rval); 134260b08185Syz147069 134360b08185Syz147069 return (rval); 134460b08185Syz147069 } 1345