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