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