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