160b08185Syz /*
260b08185Syz  * CDDL HEADER START
360b08185Syz  *
460b08185Syz  * The contents of this file are subject to the terms of the
5688b07c5Sgc  * Common Development and Distribution License (the "License").
6688b07c5Sgc  * You may not use this file except in compliance with the License.
760b08185Syz  *
860b08185Syz  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
960b08185Syz  * or http://www.opensolaris.org/os/licensing.
1060b08185Syz  * See the License for the specific language governing permissions
1160b08185Syz  * and limitations under the License.
1260b08185Syz  *
1360b08185Syz  * When distributing Covered Code, include this CDDL HEADER in each
1460b08185Syz  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1560b08185Syz  * If applicable, add the following below this CDDL HEADER, with the
1660b08185Syz  * fields enclosed by brackets "[]" replaced with your own identifying
1760b08185Syz  * information: Portions Copyright [yyyy] [name of copyright owner]
1860b08185Syz  *
1960b08185Syz  * CDDL HEADER END
2060b08185Syz  */
2160b08185Syz /*
2277e51571Sgongtian zhao - Sun Microsystems - Beijing China  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
2360b08185Syz  * Use is subject to license terms.
2460b08185Syz  */
2560b08185Syz 
2660b08185Syz 
2760b08185Syz /*
2860b08185Syz  *
2960b08185Syz  * keyspanport pipe routines (mostly device-neutral)
3060b08185Syz  *
3160b08185Syz  */
3260b08185Syz #include <sys/types.h>
3360b08185Syz #include <sys/param.h>
3460b08185Syz #include <sys/conf.h>
3560b08185Syz #include <sys/stream.h>
3660b08185Syz #include <sys/strsun.h>
3760b08185Syz #include <sys/termio.h>
3860b08185Syz #include <sys/ddi.h>
3960b08185Syz #include <sys/sunddi.h>
4060b08185Syz 
4160b08185Syz #include <sys/usb/usba.h>
4260b08185Syz #include <sys/usb/clients/usbser/usbser_keyspan/keyspan_var.h>
4360b08185Syz #include <sys/usb/clients/usbser/usbser_keyspan/keyspan_pipe.h>
4460b08185Syz 
4560b08185Syz /*
4660b08185Syz  * initialize pipe structure with the given parameters
4760b08185Syz  */
4860b08185Syz static void
keyspan_init_one_pipe(keyspan_state_t * ksp,keyspan_port_t * kp,keyspan_pipe_t * pipe)4960b08185Syz keyspan_init_one_pipe(keyspan_state_t *ksp, keyspan_port_t *kp,
5060b08185Syz     keyspan_pipe_t *pipe)
5160b08185Syz {
5260b08185Syz 	usb_pipe_policy_t	*policy;
5360b08185Syz 
5460b08185Syz 	USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, "keyspan_init_one_pipe: "
5560b08185Syz 	    "pipe = %p, pipe_stat %x", (void *)pipe, pipe->pipe_state);
5660b08185Syz 
5760b08185Syz 	/* init sync primitives */
5860b08185Syz 	mutex_init(&pipe->pipe_mutex, NULL, MUTEX_DRIVER, (void *)NULL);
5960b08185Syz 
6060b08185Syz 	/* init pipe policy */
6160b08185Syz 	policy = &pipe->pipe_policy;
6260b08185Syz 	policy->pp_max_async_reqs = 2;
6360b08185Syz 
6460b08185Syz 	pipe->pipe_ksp = ksp;
6560b08185Syz 	if (kp == NULL) {
6660b08185Syz 		/* globle pipes should have device log handle */
6760b08185Syz 		pipe->pipe_lh = ksp->ks_lh;
6860b08185Syz 	} else {
6960b08185Syz 		/* port pipes should have port log handle */
7060b08185Syz 		pipe->pipe_lh = kp->kp_lh;
7160b08185Syz 	}
7260b08185Syz 
7360b08185Syz 	pipe->pipe_state = KEYSPAN_PIPE_CLOSED;
7460b08185Syz }
7560b08185Syz 
7660b08185Syz 
7760b08185Syz static void
keyspan_fini_one_pipe(keyspan_pipe_t * pipe)7860b08185Syz keyspan_fini_one_pipe(keyspan_pipe_t *pipe)
7960b08185Syz {
8060b08185Syz 	USB_DPRINTF_L4(DPRINT_OPEN, pipe->pipe_ksp->ks_lh,
8160b08185Syz 	    "keyspan_fini_one_pipe: pipe_stat %x", pipe->pipe_state);
8260b08185Syz 
8360b08185Syz 	if (pipe->pipe_state != KEYSPAN_PIPE_NOT_INIT) {
8460b08185Syz 		mutex_destroy(&pipe->pipe_mutex);
8560b08185Syz 		pipe->pipe_state = KEYSPAN_PIPE_NOT_INIT;
8660b08185Syz 	}
8760b08185Syz }
8860b08185Syz 
8960b08185Syz /*
9060b08185Syz  * Lookup the endpoints defined in the spec;
9160b08185Syz  * Allocate resources, initialize pipe structures.
9260b08185Syz  * All are bulk pipes, including data in/out, cmd/status pipes.
9360b08185Syz  */
9460b08185Syz int
keyspan_init_pipes(keyspan_state_t * ksp)9560b08185Syz keyspan_init_pipes(keyspan_state_t *ksp)
9660b08185Syz {
9760b08185Syz 	usb_client_dev_data_t *dev_data = ksp->ks_dev_data;
9860b08185Syz 	int		ifc, alt, i, j, k = 0;
9960b08185Syz 	uint8_t		port_cnt = ksp->ks_dev_spec.port_cnt;
10060b08185Syz 	uint8_t		ep_addr, ep_cnt;
10160b08185Syz 	usb_ep_data_t	*dataout[KEYSPAN_MAX_PORT_NUM],
10277e51571Sgongtian zhao - Sun Microsystems - Beijing China 	    *datain[KEYSPAN_MAX_PORT_NUM],
10377e51571Sgongtian zhao - Sun Microsystems - Beijing China 	    *status = NULL, *ctrl = NULL, *tmp_ep;
10460b08185Syz 	usb_alt_if_data_t *alt_data;
10560b08185Syz 	usb_if_data_t *if_data;
10660b08185Syz 
10760b08185Syz 
10860b08185Syz 	ifc = dev_data->dev_curr_if;
10960b08185Syz 	alt = 0;
11060b08185Syz 	if_data = &dev_data->dev_curr_cfg->cfg_if[ifc];
11160b08185Syz 	alt_data = &if_data->if_alt[alt];
11260b08185Syz 
11360b08185Syz 	/*
11460b08185Syz 	 * The actual EP number (indicated by bNumEndpoints) is more than
11560b08185Syz 	 * those defined in spec. We have to match those we need according
11660b08185Syz 	 * to EP addresses. And we'll lookup In EPs and Out EPs separately.
11760b08185Syz 	 */
11860b08185Syz 	ep_cnt = (alt_data->altif_descr.bNumEndpoints + 1) / 2;
11960b08185Syz 
12060b08185Syz 	/*
12160b08185Syz 	 * get DIR_IN EP descriptors, and then match with EP addresses.
12260b08185Syz 	 * Different keyspan devices may has different EP addresses.
12360b08185Syz 	 */
12460b08185Syz 	for (i = 0; i < ep_cnt; i++) {
12560b08185Syz 		tmp_ep = usb_lookup_ep_data(ksp->ks_dip, dev_data, ifc, alt, i,
12677e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    USB_EP_ATTR_BULK, USB_EP_DIR_IN);
12760b08185Syz 		if (tmp_ep == NULL) {
12860b08185Syz 			USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh,
12960b08185Syz 			    "keyspan_init_pipes: can't find bulk in ep, i=%d,"
13060b08185Syz 			    "ep_cnt=%d", i, ep_cnt);
13160b08185Syz 
13260b08185Syz 			continue;
13360b08185Syz 		}
13460b08185Syz 		ep_addr = tmp_ep->ep_descr.bEndpointAddress;
13560b08185Syz 
13660b08185Syz 		USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh, "keyspan_init_pipes: "
13760b08185Syz 		    "ep_addr =%x, stat_ep_addr=%x, i=%d", ep_addr,
13860b08185Syz 		    ksp->ks_dev_spec.stat_ep_addr, i);
13960b08185Syz 
14060b08185Syz 		/* match the status EP */
14160b08185Syz 		if (ep_addr == ksp->ks_dev_spec.stat_ep_addr) {
14260b08185Syz 			status = tmp_ep;
14360b08185Syz 
14460b08185Syz 			continue;
14560b08185Syz 		}
14660b08185Syz 
14760b08185Syz 		/* match the EPs of the ports */
14860b08185Syz 		for (j = 0; j < port_cnt; j++) {
14960b08185Syz 			USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh,
15060b08185Syz 			    "keyspan_init_pipes: try to match bulk in data ep,"
15160b08185Syz 			    " j=%d", j);
15260b08185Syz 			if (ep_addr == ksp->ks_dev_spec.datain_ep_addr[j]) {
15360b08185Syz 				datain[j] = tmp_ep;
15460b08185Syz 				k++;
15560b08185Syz 				USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh,
15660b08185Syz 				    "keyspan_init_pipes: matched a bulk in"
15760b08185Syz 				    " data ep");
15860b08185Syz 
15960b08185Syz 				break;
16060b08185Syz 			}
16160b08185Syz 		}
16260b08185Syz 
16360b08185Syz 		/* if have matched all the necessary endpoints, break out */
16460b08185Syz 		if (k >= port_cnt && status != NULL) {
16560b08185Syz 
16660b08185Syz 			break;
16760b08185Syz 		}
16860b08185Syz 
16960b08185Syz 		USB_DPRINTF_L4(DPRINT_ATTACH, ksp->ks_lh, "keyspan_init_pipes: "
17060b08185Syz 		    "try to match bulk in data ep, j=%d", j);
17160b08185Syz 
17260b08185Syz 		if (j == port_cnt) {
17360b08185Syz 			/* this ep can't be matched by any addr */
17460b08185Syz 			USB_DPRINTF_L4(DPRINT_ATTACH, ksp->ks_lh,
17560b08185Syz 			    "keyspan_init_pipes: can't match bulk in ep,"
17660b08185Syz 			    " addr =%x,", ep_addr);
17760b08185Syz 		}
17860b08185Syz 	}
17960b08185Syz 
18060b08185Syz 	if (k != port_cnt || status == NULL) {
18160b08185Syz 
18260b08185Syz 		/* Some of the necessary IN endpoints are not matched */
18360b08185Syz 		USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
18460b08185Syz 		    "keyspan_init_pipes: matched %d data in endpoints,"
18560b08185Syz 		    " not enough", k);
18660b08185Syz 
18760b08185Syz 		return (USB_FAILURE);
18860b08185Syz 	}
18960b08185Syz 
19060b08185Syz 	k = 0;
19160b08185Syz 
19260b08185Syz 	/*
19360b08185Syz 	 * get DIR_OUT EP descriptors, and then match with ep addrs.
19460b08185Syz 	 * different keyspan devices may has different ep addresses.
19560b08185Syz 	 */
19660b08185Syz 	for (i = 0; i < ep_cnt; i++) {
19760b08185Syz 		tmp_ep = usb_lookup_ep_data(ksp->ks_dip, dev_data, ifc, alt, i,
19877e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    USB_EP_ATTR_BULK, USB_EP_DIR_OUT);
19960b08185Syz 		if (tmp_ep == NULL) {
20060b08185Syz 			USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh,
20160b08185Syz 			    "keyspan_init_pipes: can't find bulk out ep, i=%d,"
20260b08185Syz 			    "ep_cnt=%d", i, ep_cnt);
20360b08185Syz 
20460b08185Syz 			continue;
20560b08185Syz 		}
20660b08185Syz 		ep_addr = tmp_ep->ep_descr.bEndpointAddress;
20760b08185Syz 
20860b08185Syz 		/* match the status ep */
20960b08185Syz 		if (ep_addr == ksp->ks_dev_spec.ctrl_ep_addr) {
21060b08185Syz 			ctrl = tmp_ep;
21160b08185Syz 
21260b08185Syz 			continue;
21360b08185Syz 		}
21460b08185Syz 
21560b08185Syz 		/* match the ep of the ports */
21660b08185Syz 		for (j = 0; j < port_cnt; j++) {
21760b08185Syz 			if (ep_addr == ksp->ks_dev_spec.dataout_ep_addr[j]) {
21860b08185Syz 				dataout[j] = tmp_ep;
21960b08185Syz 				k++;
22060b08185Syz 
22160b08185Syz 				break;
22260b08185Syz 			}
22360b08185Syz 		}
22460b08185Syz 		/* if have matched all the necessary endpoints, break out */
22560b08185Syz 		if (k >= port_cnt && ctrl != NULL) {
22660b08185Syz 
22760b08185Syz 			break;
22860b08185Syz 		}
22960b08185Syz 
23060b08185Syz 		if (j == port_cnt) {
23160b08185Syz 
23260b08185Syz 			/* this ep can't be matched by any addr */
23360b08185Syz 			USB_DPRINTF_L4(DPRINT_ATTACH, ksp->ks_lh,
23460b08185Syz 			    "keyspan_init_pipes: can't match bulk out ep,"
23560b08185Syz 			    " ep_addr =%x", ep_addr);
23660b08185Syz 
23760b08185Syz 		}
23860b08185Syz 	}
23960b08185Syz 
24060b08185Syz 	if (k != port_cnt || ctrl == NULL) {
24160b08185Syz 		/* Not all the necessary OUT endpoints are matched */
24260b08185Syz 		USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
24360b08185Syz 		    "keyspan_init_pipes: matched %d data in endpoints,"
24460b08185Syz 		    " not enough", k);
24560b08185Syz 
24660b08185Syz 		return (USB_FAILURE);
24760b08185Syz 	}
24860b08185Syz 
24960b08185Syz 	mutex_enter(&ksp->ks_mutex);
25060b08185Syz 
25160b08185Syz 	/*
25260b08185Syz 	 * Device globle pipes: a bulk in pipe for status and a bulk out
25360b08185Syz 	 * pipe for controle cmd.
25460b08185Syz 	 */
25560b08185Syz 	ksp->ks_statin_pipe.pipe_ep_descr = status->ep_descr;
25660b08185Syz 	keyspan_init_one_pipe(ksp, NULL, &ksp->ks_statin_pipe);
25760b08185Syz 
25860b08185Syz 	ksp->ks_ctrlout_pipe.pipe_ep_descr = ctrl->ep_descr;
25960b08185Syz 	keyspan_init_one_pipe(ksp, NULL, &ksp->ks_ctrlout_pipe);
26060b08185Syz 
26160b08185Syz 	/* for data in/out pipes of each port */
26260b08185Syz 	for (i = 0; i < port_cnt; i++) {
26360b08185Syz 
26460b08185Syz 		ksp->ks_ports[i].kp_datain_pipe.pipe_ep_descr =
26560b08185Syz 		    datain[i]->ep_descr;
26660b08185Syz 		keyspan_init_one_pipe(ksp, &ksp->ks_ports[i],
26760b08185Syz 		    &ksp->ks_ports[i].kp_datain_pipe);
26860b08185Syz 
26960b08185Syz 		ksp->ks_ports[i].kp_dataout_pipe.pipe_ep_descr =
27060b08185Syz 		    dataout[i]->ep_descr;
27160b08185Syz 		keyspan_init_one_pipe(ksp, &ksp->ks_ports[i],
27260b08185Syz 		    &ksp->ks_ports[i].kp_dataout_pipe);
27360b08185Syz 	}
27460b08185Syz 
27560b08185Syz 	mutex_exit(&ksp->ks_mutex);
27660b08185Syz 
27760b08185Syz 	return (USB_SUCCESS);
27860b08185Syz }
27902dd2108Slg /*
28002dd2108Slg  * For USA_49WG only.
28102dd2108Slg  * Lookup the endpoints defined in the spec.
28202dd2108Slg  * Allocate resources, initialize pipe structures.
28302dd2108Slg  * There are 6 EPs, 3 bulk out Eps, 1 bulk in EP, 1 intr in EP, 1 intr out EP
28402dd2108Slg  */
28502dd2108Slg int
keyspan_init_pipes_usa49wg(keyspan_state_t * ksp)28602dd2108Slg keyspan_init_pipes_usa49wg(keyspan_state_t *ksp)
28702dd2108Slg {
28802dd2108Slg 	usb_client_dev_data_t *dev_data = ksp->ks_dev_data;
28902dd2108Slg 	int		ifc, alt, i, j = 0;
29002dd2108Slg 	uint8_t		port_cnt = ksp->ks_dev_spec.port_cnt;
29102dd2108Slg 	uint8_t		ep_addr;
29202dd2108Slg 	usb_ep_data_t	*dataout[KEYSPAN_MAX_PORT_NUM],
29377e51571Sgongtian zhao - Sun Microsystems - Beijing China 	    *datain[KEYSPAN_MAX_PORT_NUM],
29477e51571Sgongtian zhao - Sun Microsystems - Beijing China 	    *status = NULL, *tmp_ep;
29502dd2108Slg 
29602dd2108Slg 	ifc = dev_data->dev_curr_if;
29702dd2108Slg 	alt = 0;
29802dd2108Slg 
29902dd2108Slg 	/*
30002dd2108Slg 	 * get intr out EP descriptor as port0 data out EP, and then
30102dd2108Slg 	 * match with EP address.
30202dd2108Slg 	 * Different keyspan devices may has different EP addresses.
30302dd2108Slg 	 */
30402dd2108Slg 	tmp_ep = usb_lookup_ep_data(ksp->ks_dip, dev_data, ifc, alt, 0,
30577e51571Sgongtian zhao - Sun Microsystems - Beijing China 	    USB_EP_ATTR_INTR, USB_EP_DIR_OUT);
30602dd2108Slg 	if (tmp_ep == NULL) {
30702dd2108Slg 		USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh,
30877e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    "keyspan_init_pipes: can't find port1 data out ep");
30902dd2108Slg 
31002dd2108Slg 		return (USB_FAILURE);
31102dd2108Slg 		}
31202dd2108Slg 	ep_addr = tmp_ep->ep_descr.bEndpointAddress;
31302dd2108Slg 
31402dd2108Slg 	/* match the port0 data out EP */
31502dd2108Slg 	if (ep_addr == ksp->ks_dev_spec.dataout_ep_addr[0]) {
31602dd2108Slg 		dataout[0] = tmp_ep;
31702dd2108Slg 	}
31802dd2108Slg 
31902dd2108Slg 	/*
32002dd2108Slg 	 * get bulk out EP descriptors as other port data out EPs, and then
32102dd2108Slg 	 * match with EP addresses.
32202dd2108Slg 	 */
32302dd2108Slg 	for (j = 1; j < port_cnt; j++) {
32402dd2108Slg 		tmp_ep = usb_lookup_ep_data(ksp->ks_dip, dev_data, ifc, alt,
32577e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    j-1, USB_EP_ATTR_BULK, USB_EP_DIR_OUT);
32602dd2108Slg 		if (tmp_ep == NULL) {
32702dd2108Slg 			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",
33077e51571Sgongtian zhao - Sun Microsystems - Beijing China 			    j);
33102dd2108Slg 			return (USB_FAILURE);
33202dd2108Slg 		}
33302dd2108Slg 
33402dd2108Slg 		ep_addr = tmp_ep->ep_descr.bEndpointAddress;
33502dd2108Slg 
33602dd2108Slg 		/* match other port data out EPs */
33702dd2108Slg 		if (ep_addr == ksp->ks_dev_spec.dataout_ep_addr[j]) {
33802dd2108Slg 			dataout[j] = tmp_ep;
33902dd2108Slg 		}
34002dd2108Slg 	}
34102dd2108Slg 
34202dd2108Slg 	/*
34302dd2108Slg 	 * get intr in EP descriptor as status EP, and then match with EP addrs
34402dd2108Slg 	 */
34502dd2108Slg 	tmp_ep = usb_lookup_ep_data(ksp->ks_dip, dev_data, ifc, alt, 0,
34677e51571Sgongtian zhao - Sun Microsystems - Beijing China 	    USB_EP_ATTR_INTR, USB_EP_DIR_IN);
34702dd2108Slg 	if (tmp_ep == NULL) {
34802dd2108Slg 		USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh,
34902dd2108Slg 		    "keyspan_init_pipes: can't find status in ep");
35002dd2108Slg 
35102dd2108Slg 		return (USB_FAILURE);
35202dd2108Slg 	}
35302dd2108Slg 	ep_addr = tmp_ep->ep_descr.bEndpointAddress;
35402dd2108Slg 
35502dd2108Slg 	/* match the status ep */
35602dd2108Slg 	if (ep_addr == ksp->ks_dev_spec.stat_ep_addr) {
35702dd2108Slg 		status = tmp_ep;
35802dd2108Slg 	}
35902dd2108Slg 
36002dd2108Slg 	/*
36102dd2108Slg 	 * get bulk in EP descriptors as data in EP, All the ports share one
36202dd2108Slg 	 * data in EP.
36302dd2108Slg 	 */
36402dd2108Slg 	tmp_ep = usb_lookup_ep_data(ksp->ks_dip, dev_data, ifc, alt, 0,
36577e51571Sgongtian zhao - Sun Microsystems - Beijing China 	    USB_EP_ATTR_BULK, USB_EP_DIR_IN);
36602dd2108Slg 	if (tmp_ep == NULL) {
36702dd2108Slg 		USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh,
36802dd2108Slg 		    "keyspan_init_pipes: can't find bulk in ep");
36902dd2108Slg 
37002dd2108Slg 		return (USB_FAILURE);
37102dd2108Slg 	}
37202dd2108Slg 	ep_addr = tmp_ep->ep_descr.bEndpointAddress;
37302dd2108Slg 
37402dd2108Slg 	/* match data in EPs */
37502dd2108Slg 	if (ep_addr == ksp->ks_dev_spec.datain_ep_addr[0]) {
37602dd2108Slg 		datain[0] = tmp_ep;
37702dd2108Slg 	}
37802dd2108Slg 
37902dd2108Slg 	mutex_enter(&ksp->ks_mutex);
38002dd2108Slg 
38102dd2108Slg 	/* intr in pipe for status */
38202dd2108Slg 	ksp->ks_statin_pipe.pipe_ep_descr = status->ep_descr;
38302dd2108Slg 	keyspan_init_one_pipe(ksp, NULL, &ksp->ks_statin_pipe);
38402dd2108Slg 
38502dd2108Slg 	/* for data in/out pipes of each port */
38602dd2108Slg 	for (i = 0; i < port_cnt; i++) {
38702dd2108Slg 		ksp->ks_ports[i].kp_datain_pipe.pipe_ep_descr =
38877e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    datain[0]->ep_descr;
38902dd2108Slg 		keyspan_init_one_pipe(ksp, &ksp->ks_ports[i],
39077e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    &ksp->ks_ports[i].kp_datain_pipe);
39102dd2108Slg 
39202dd2108Slg 		ksp->ks_ports[i].kp_dataout_pipe.pipe_ep_descr =
39302dd2108Slg 		    dataout[i]->ep_descr;
39402dd2108Slg 		keyspan_init_one_pipe(ksp, &ksp->ks_ports[i],
39577e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    &ksp->ks_ports[i].kp_dataout_pipe);
39602dd2108Slg 	}
39702dd2108Slg 
39802dd2108Slg 	mutex_exit(&ksp->ks_mutex);
39902dd2108Slg 
40002dd2108Slg 	return (USB_SUCCESS);
40102dd2108Slg }
40260b08185Syz 
40360b08185Syz void
keyspan_fini_pipes(keyspan_state_t * ksp)40460b08185Syz keyspan_fini_pipes(keyspan_state_t *ksp)
40560b08185Syz {
40660b08185Syz 	keyspan_port_t	*kp;
40760b08185Syz 	int		i;
40860b08185Syz 
40960b08185Syz 	for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) {
41060b08185Syz 		kp = &ksp->ks_ports[i];
41160b08185Syz 		keyspan_fini_one_pipe(&kp->kp_datain_pipe);
41260b08185Syz 		keyspan_fini_one_pipe(&kp->kp_dataout_pipe);
41360b08185Syz 	}
41460b08185Syz 
41502dd2108Slg 	/* fini status pipe */
41660b08185Syz 	keyspan_fini_one_pipe(&ksp->ks_statin_pipe);
41702dd2108Slg 	/*
41802dd2108Slg 	 * fini control pipe
41902dd2108Slg 	 * If USA_49WG, don't need fini control pipe
42002dd2108Slg 	 */
42102dd2108Slg 	switch (ksp->ks_dev_spec.id_product) {
42202dd2108Slg 		case KEYSPAN_USA19HS_PID:
42302dd2108Slg 		case KEYSPAN_USA49WLC_PID:
42402dd2108Slg 			keyspan_fini_one_pipe(&ksp->ks_ctrlout_pipe);
42560b08185Syz 
42602dd2108Slg 			break;
42702dd2108Slg 		case KEYSPAN_USA49WG_PID:
42802dd2108Slg 
42902dd2108Slg 			break;
43002dd2108Slg 		default:
43102dd2108Slg 			USB_DPRINTF_L2(DPRINT_CTLOP, ksp->ks_lh,
43277e51571Sgongtian zhao - Sun Microsystems - Beijing China 			    "keyspan_fini_pipes: the device's product id"
43377e51571Sgongtian zhao - Sun Microsystems - Beijing China 			    "can't be recognized");
43402dd2108Slg 	}
43502dd2108Slg }
43660b08185Syz 
43760b08185Syz static int
keyspan_open_one_pipe(keyspan_state_t * ksp,keyspan_pipe_t * pipe)43860b08185Syz keyspan_open_one_pipe(keyspan_state_t *ksp, keyspan_pipe_t *pipe)
43960b08185Syz {
44060b08185Syz 	int	rval;
44160b08185Syz 
44260b08185Syz 	/* don't open for the second time */
44360b08185Syz 	mutex_enter(&pipe->pipe_mutex);
44460b08185Syz 	ASSERT(pipe->pipe_state != KEYSPAN_PIPE_NOT_INIT);
44560b08185Syz 	if (pipe->pipe_state != KEYSPAN_PIPE_CLOSED) {
44660b08185Syz 		mutex_exit(&pipe->pipe_mutex);
44760b08185Syz 
44860b08185Syz 		return (USB_SUCCESS);
44960b08185Syz 	}
45060b08185Syz 	mutex_exit(&pipe->pipe_mutex);
45160b08185Syz 
45260b08185Syz 	rval = usb_pipe_open(ksp->ks_dip, &pipe->pipe_ep_descr,
45360b08185Syz 	    &pipe->pipe_policy, USB_FLAGS_SLEEP, &pipe->pipe_handle);
45460b08185Syz 
45560b08185Syz 	if (rval == USB_SUCCESS) {
45660b08185Syz 		mutex_enter(&pipe->pipe_mutex);
45760b08185Syz 		pipe->pipe_state = KEYSPAN_PIPE_OPEN;
45860b08185Syz 		mutex_exit(&pipe->pipe_mutex);
45960b08185Syz 	}
46060b08185Syz 
46160b08185Syz 	return (rval);
46260b08185Syz }
46360b08185Syz 
46402dd2108Slg /*
46502dd2108Slg  * Open shared datain pipe for USA_49WG
46602dd2108Slg  */
46702dd2108Slg static int
keyspan_open_pipe_datain_usa49wg(keyspan_state_t * ksp,keyspan_pipe_t * pipe)46802dd2108Slg keyspan_open_pipe_datain_usa49wg(keyspan_state_t *ksp, keyspan_pipe_t *pipe)
46902dd2108Slg {
47002dd2108Slg 	int	rval = USB_SUCCESS;
47102dd2108Slg 
47202dd2108Slg 	/* don't open for the second time */
47302dd2108Slg 	mutex_enter(&pipe->pipe_mutex);
47402dd2108Slg 	ASSERT(pipe->pipe_state != KEYSPAN_PIPE_NOT_INIT);
47502dd2108Slg 	if (pipe->pipe_state != KEYSPAN_PIPE_CLOSED) {
47602dd2108Slg 		mutex_exit(&pipe->pipe_mutex);
47702dd2108Slg 
47802dd2108Slg 		return (USB_SUCCESS);
47902dd2108Slg 	}
48002dd2108Slg 	mutex_exit(&pipe->pipe_mutex);
48102dd2108Slg 
48202dd2108Slg 	mutex_enter(&ksp->ks_mutex);
48302dd2108Slg 	ksp->ks_datain_open_cnt++;
48402dd2108Slg 	if (ksp->ks_datain_open_cnt == 1) {
48502dd2108Slg 		mutex_exit(&ksp->ks_mutex);
48602dd2108Slg 
48702dd2108Slg 		if ((rval = (usb_pipe_open(ksp->ks_dip, &pipe->pipe_ep_descr,
48877e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    &pipe->pipe_policy, USB_FLAGS_SLEEP,
48977e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    &pipe->pipe_handle))) == USB_SUCCESS) {
49002dd2108Slg 				mutex_enter(&pipe->pipe_mutex);
49102dd2108Slg 				pipe->pipe_state = KEYSPAN_PIPE_OPEN;
49202dd2108Slg 				mutex_exit(&pipe->pipe_mutex);
49302dd2108Slg 
49402dd2108Slg 				mutex_enter(&ksp->ks_mutex);
49502dd2108Slg 				ksp->ks_datain_pipe_handle = pipe->pipe_handle;
49602dd2108Slg 				mutex_exit(&ksp->ks_mutex);
49702dd2108Slg 		} else {
49802dd2108Slg 				mutex_enter(&ksp->ks_mutex);
49902dd2108Slg 				ksp->ks_datain_open_cnt--;
50002dd2108Slg 				mutex_exit(&ksp->ks_mutex);
50102dd2108Slg 		}
50202dd2108Slg 
50302dd2108Slg 		return (rval);
50402dd2108Slg 	} else {
50502dd2108Slg 		/* data in pipe has been opened by other port */
50602dd2108Slg 		ASSERT(ksp->ks_datain_pipe_handle != NULL);
50702dd2108Slg 
50802dd2108Slg 		mutex_enter(&pipe->pipe_mutex);
50902dd2108Slg 		pipe->pipe_handle = ksp->ks_datain_pipe_handle;
51002dd2108Slg 		/* Set datain pipe state */
51102dd2108Slg 		pipe->pipe_state = KEYSPAN_PIPE_OPEN;
51202dd2108Slg 		mutex_exit(&pipe->pipe_mutex);
51302dd2108Slg 		mutex_exit(&ksp->ks_mutex);
51402dd2108Slg 
51502dd2108Slg 		return (USB_SUCCESS);
51602dd2108Slg 	}
51702dd2108Slg }
51860b08185Syz 
51960b08185Syz /*
52060b08185Syz  * close one pipe if open
52160b08185Syz  */
52260b08185Syz static void
keyspan_close_one_pipe(keyspan_pipe_t * pipe)52360b08185Syz keyspan_close_one_pipe(keyspan_pipe_t *pipe)
52460b08185Syz {
52560b08185Syz 	/*
52660b08185Syz 	 * pipe may already be closed, e.g. if device has been physically
52760b08185Syz 	 * disconnected and the driver immediately detached
52860b08185Syz 	 */
52960b08185Syz 	if (pipe->pipe_handle != NULL) {
53060b08185Syz 		usb_pipe_close(pipe->pipe_ksp->ks_dip, pipe->pipe_handle,
53177e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    USB_FLAGS_SLEEP, NULL, NULL);
53260b08185Syz 		mutex_enter(&pipe->pipe_mutex);
53360b08185Syz 		pipe->pipe_handle = NULL;
53460b08185Syz 		pipe->pipe_state = KEYSPAN_PIPE_CLOSED;
53560b08185Syz 		mutex_exit(&pipe->pipe_mutex);
53660b08185Syz 	}
53760b08185Syz }
53860b08185Syz 
53960b08185Syz /*
54002dd2108Slg  * close shared datain pipe if open for USA_49WG
54102dd2108Slg  */
54202dd2108Slg static void
keyspan_close_pipe_datain_usa49wg(keyspan_pipe_t * pipe)54302dd2108Slg keyspan_close_pipe_datain_usa49wg(keyspan_pipe_t *pipe)
54402dd2108Slg {
54502dd2108Slg 	keyspan_state_t *ksp = pipe->pipe_ksp;
54602dd2108Slg 	/*
54702dd2108Slg 	 * pipe may already be closed, e.g. if device has been physically
54802dd2108Slg 	 * disconnected and the driver immediately detached
54902dd2108Slg 	 */
55002dd2108Slg 	if (pipe->pipe_handle != NULL) {
55102dd2108Slg 		mutex_enter(&ksp->ks_mutex);
55202dd2108Slg 		ksp->ks_datain_open_cnt--;
55302dd2108Slg 		if (!ksp->ks_datain_open_cnt) {
55402dd2108Slg 			mutex_exit(&ksp->ks_mutex);
55502dd2108Slg 			usb_pipe_close(pipe->pipe_ksp->ks_dip,
55677e51571Sgongtian zhao - Sun Microsystems - Beijing China 			    pipe->pipe_handle, USB_FLAGS_SLEEP,
55777e51571Sgongtian zhao - Sun Microsystems - Beijing China 			    NULL, NULL);
55802dd2108Slg 		} else {
55902dd2108Slg 			mutex_exit(&ksp->ks_mutex);
56002dd2108Slg 		}
56102dd2108Slg 
56202dd2108Slg 		mutex_enter(&pipe->pipe_mutex);
56302dd2108Slg 		pipe->pipe_handle = NULL;
56402dd2108Slg 		pipe->pipe_state = KEYSPAN_PIPE_CLOSED;
56502dd2108Slg 		mutex_exit(&pipe->pipe_mutex);
56602dd2108Slg 	}
56702dd2108Slg }
56802dd2108Slg 
56902dd2108Slg /*
57002dd2108Slg  * For USA19HS and USA49WLC:
57160b08185Syz  * Open global pipes, a status pipe and a control pipe
57260b08185Syz  */
57360b08185Syz int
keyspan_open_dev_pipes_usa49(keyspan_state_t * ksp)57402dd2108Slg keyspan_open_dev_pipes_usa49(keyspan_state_t *ksp)
57560b08185Syz {
57660b08185Syz 	int		rval;
57760b08185Syz 
57802dd2108Slg 	USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh,
57977e51571Sgongtian zhao - Sun Microsystems - Beijing China 	    "keyspan_open_dev_pipes_usa49");
58060b08185Syz 
58160b08185Syz 	rval = keyspan_open_one_pipe(ksp, &ksp->ks_ctrlout_pipe);
58260b08185Syz 	if (rval != USB_SUCCESS) {
58360b08185Syz 		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);
58660b08185Syz 		return (rval);
58760b08185Syz 	}
58860b08185Syz 
58960b08185Syz 	rval = keyspan_open_one_pipe(ksp, &ksp->ks_statin_pipe);
59060b08185Syz 	if (rval != USB_SUCCESS) {
59160b08185Syz 		USB_DPRINTF_L2(DPRINT_OPEN, ksp->ks_lh,
59277e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    "keyspan_open_dev_pipes_usa49: open status pipe failed %d",
59377e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    rval);
59460b08185Syz 
59560b08185Syz 		/* close the first opened pipe here */
59660b08185Syz 		keyspan_close_one_pipe(&ksp->ks_ctrlout_pipe);
59760b08185Syz 
59860b08185Syz 		return (rval);
59960b08185Syz 	}
60060b08185Syz 
60160b08185Syz 	/* start receive device status */
60260b08185Syz 	rval = keyspan_receive_status(ksp);
60360b08185Syz 	if (rval != USB_SUCCESS) {
60460b08185Syz 		USB_DPRINTF_L2(DPRINT_OPEN, ksp->ks_lh,
60577e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    "keyspan_open_dev_pipes_usa49: receive device status"
60602dd2108Slg 		    " failed %d", rval);
60760b08185Syz 
60860b08185Syz 		/* close opened pipes here */
60960b08185Syz 		keyspan_close_one_pipe(&ksp->ks_statin_pipe);
61060b08185Syz 		keyspan_close_one_pipe(&ksp->ks_ctrlout_pipe);
61160b08185Syz 
61260b08185Syz 		return (rval);
61360b08185Syz 	}
61460b08185Syz 
61560b08185Syz 	return (rval);
61660b08185Syz }
61760b08185Syz 
61802dd2108Slg /*
61902dd2108Slg  * For keyspan USA_49WG:
62002dd2108Slg  * Open global pipes, a status pipe
62102dd2108Slg  * Use default control pipe, don't need to open it.
62202dd2108Slg  */
62302dd2108Slg int
keyspan_open_dev_pipes_usa49wg(keyspan_state_t * ksp)62402dd2108Slg keyspan_open_dev_pipes_usa49wg(keyspan_state_t *ksp)
62502dd2108Slg {
62602dd2108Slg 	int		rval;
62702dd2108Slg 
62802dd2108Slg 	/* Open status pipe */
62902dd2108Slg 	rval = keyspan_open_one_pipe(ksp, &ksp->ks_statin_pipe);
63002dd2108Slg 	if (rval != USB_SUCCESS) {
63102dd2108Slg 		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",
63477e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    rval);
63502dd2108Slg 
63602dd2108Slg 		return (rval);
63702dd2108Slg 	}
63802dd2108Slg 	/* start device polling */
63902dd2108Slg 	keyspan_pipe_start_polling(&ksp->ks_statin_pipe);
64002dd2108Slg 
64102dd2108Slg 	return (rval);
64202dd2108Slg }
64302dd2108Slg 
64402dd2108Slg /*
64502dd2108Slg  * Open global pipes, status pipe and control pipe,
64602dd2108Slg  */
64702dd2108Slg int
keyspan_open_dev_pipes(keyspan_state_t * ksp)64802dd2108Slg keyspan_open_dev_pipes(keyspan_state_t *ksp)
64902dd2108Slg {
65002dd2108Slg 	int		rval = USB_SUCCESS;
65102dd2108Slg 
65202dd2108Slg 	USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, "keyspan_open_dev_pipes");
65302dd2108Slg 
65402dd2108Slg 	switch (ksp->ks_dev_spec.id_product) {
65502dd2108Slg 	case KEYSPAN_USA19HS_PID:
65602dd2108Slg 	case KEYSPAN_USA49WLC_PID:
65702dd2108Slg 		rval = keyspan_open_dev_pipes_usa49(ksp);
65802dd2108Slg 
65902dd2108Slg 		break;
66002dd2108Slg 	case KEYSPAN_USA49WG_PID:
66102dd2108Slg 		rval = keyspan_open_dev_pipes_usa49wg(ksp);
66202dd2108Slg 
66302dd2108Slg 		break;
66402dd2108Slg 	default:
66502dd2108Slg 		USB_DPRINTF_L2(DPRINT_OPEN, ksp->ks_lh,
66677e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    "keyspan_open_dev_pipes: the device's product id can't"
66777e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    "be recognized");
66802dd2108Slg 
66902dd2108Slg 		return (USB_FAILURE);
67002dd2108Slg 	}
67102dd2108Slg 	return (rval);
67202dd2108Slg }
67360b08185Syz 
67460b08185Syz /*
67560b08185Syz  * Reopen all pipes if the port had them open
67660b08185Syz  */
67760b08185Syz int
keyspan_reopen_pipes(keyspan_state_t * ksp)67860b08185Syz keyspan_reopen_pipes(keyspan_state_t *ksp)
67960b08185Syz {
68060b08185Syz 	keyspan_port_t	*kp;
68160b08185Syz 	int		i;
68260b08185Syz 
68360b08185Syz 	USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, "keyspan_reopen_pipes");
68460b08185Syz 
68560b08185Syz 	if (keyspan_open_dev_pipes(ksp) != USB_SUCCESS) {
68660b08185Syz 
68760b08185Syz 		return (USB_FAILURE);
68860b08185Syz 	}
68960b08185Syz 
69060b08185Syz 	for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) {
69160b08185Syz 		kp = &ksp->ks_ports[i];
69260b08185Syz 		mutex_enter(&kp->kp_mutex);
69360b08185Syz 		if (kp->kp_state == KEYSPAN_PORT_OPEN) {
69460b08185Syz 			USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh,
69560b08185Syz 			    "keyspan_reopen_pipes() reopen pipe #%d", i);
69660b08185Syz 			mutex_exit(&kp->kp_mutex);
69760b08185Syz 			if (keyspan_open_port_pipes(kp) != USB_SUCCESS) {
69860b08185Syz 
69960b08185Syz 				return (USB_FAILURE);
70060b08185Syz 			}
70160b08185Syz 			mutex_enter(&kp->kp_mutex);
70260b08185Syz 			kp->kp_no_more_reads = B_FALSE;
70360b08185Syz 		}
70460b08185Syz 		mutex_exit(&kp->kp_mutex);
70560b08185Syz 	}
70660b08185Syz 
70760b08185Syz 	return (USB_SUCCESS);
70860b08185Syz }
70960b08185Syz 
71060b08185Syz void
keyspan_close_port_pipes(keyspan_port_t * kp)71160b08185Syz keyspan_close_port_pipes(keyspan_port_t *kp)
71260b08185Syz {
71302dd2108Slg 	keyspan_state_t *ksp =	kp->kp_ksp;
71402dd2108Slg 
71560b08185Syz 	USB_DPRINTF_L4(DPRINT_CLOSE, kp->kp_lh, "keyspan_close_port_pipes");
71660b08185Syz 
71702dd2108Slg 	switch (ksp->ks_dev_spec.id_product) {
71802dd2108Slg 	case KEYSPAN_USA19HS_PID:
71902dd2108Slg 	case KEYSPAN_USA49WLC_PID:
72002dd2108Slg 		keyspan_close_one_pipe(&kp->kp_datain_pipe);
72102dd2108Slg 
72202dd2108Slg 		break;
72302dd2108Slg 	case KEYSPAN_USA49WG_PID:
72402dd2108Slg 		keyspan_close_pipe_datain_usa49wg(&kp->kp_datain_pipe);
72502dd2108Slg 
72602dd2108Slg 		break;
72702dd2108Slg 	default:
72802dd2108Slg 		USB_DPRINTF_L2(DPRINT_CLOSE, kp->kp_lh,
72977e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    "keyspan_close_port_pipes:"
73077e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    "the device's product id can't be recognized");
73102dd2108Slg 	}
73260b08185Syz 	keyspan_close_one_pipe(&kp->kp_dataout_pipe);
73360b08185Syz }
73460b08185Syz 
73560b08185Syz /*
73660b08185Syz  * Close IN and OUT bulk pipes of all ports
73760b08185Syz  */
73860b08185Syz void
keyspan_close_open_pipes(keyspan_state_t * ksp)73960b08185Syz keyspan_close_open_pipes(keyspan_state_t *ksp)
74060b08185Syz {
74160b08185Syz 	keyspan_port_t	*kp;
74260b08185Syz 	int		i;
74302dd2108Slg 	int		port_num = -1;
74460b08185Syz 
74560b08185Syz 	USB_DPRINTF_L4(DPRINT_CLOSE, ksp->ks_lh, "keyspan_close_open_pipes");
74660b08185Syz 
74702dd2108Slg 	switch (ksp->ks_dev_spec.id_product) {
74802dd2108Slg 	case KEYSPAN_USA19HS_PID:
74902dd2108Slg 	case KEYSPAN_USA49WLC_PID:
75002dd2108Slg 		for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) {
75102dd2108Slg 			kp = &ksp->ks_ports[i];
75202dd2108Slg 			mutex_enter(&kp->kp_mutex);
75302dd2108Slg 			if (kp->kp_state == KEYSPAN_PORT_OPEN) {
75402dd2108Slg 				kp->kp_no_more_reads = B_TRUE;
75502dd2108Slg 				mutex_exit(&kp->kp_mutex);
75602dd2108Slg 				usb_pipe_reset(ksp->ks_dip,
75777e51571Sgongtian zhao - Sun Microsystems - Beijing China 				    kp->kp_datain_pipe.pipe_handle,
75877e51571Sgongtian zhao - Sun Microsystems - Beijing China 				    USB_FLAGS_SLEEP, NULL, NULL);
75902dd2108Slg 				keyspan_close_port_pipes(kp);
76002dd2108Slg 			} else {
76102dd2108Slg 				mutex_exit(&kp->kp_mutex);
76202dd2108Slg 			}
76302dd2108Slg 		}
76402dd2108Slg 
76502dd2108Slg 		break;
76602dd2108Slg 
76702dd2108Slg 	case KEYSPAN_USA49WG_PID:
76802dd2108Slg 		for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) {
76902dd2108Slg 			kp = &ksp->ks_ports[i];
77002dd2108Slg 			mutex_enter(&kp->kp_mutex);
77102dd2108Slg 			if (kp->kp_state == KEYSPAN_PORT_OPEN) {
77202dd2108Slg 				kp->kp_no_more_reads = B_TRUE;
77302dd2108Slg 				port_num = i;
77402dd2108Slg 			}
77560b08185Syz 			mutex_exit(&kp->kp_mutex);
77602dd2108Slg 		}
77702dd2108Slg 		if (port_num >= 0) {
77802dd2108Slg 			kp = &ksp->ks_ports[port_num];
77960b08185Syz 			usb_pipe_reset(ksp->ks_dip,
78077e51571Sgongtian zhao - Sun Microsystems - Beijing China 			    kp->kp_datain_pipe.pipe_handle,
78177e51571Sgongtian zhao - Sun Microsystems - Beijing China 			    USB_FLAGS_SLEEP, NULL, NULL);
78260b08185Syz 		}
78302dd2108Slg 
78402dd2108Slg 		for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) {
78502dd2108Slg 			kp = &ksp->ks_ports[i];
78602dd2108Slg 			mutex_enter(&kp->kp_mutex);
78702dd2108Slg 			if (kp->kp_state == KEYSPAN_PORT_OPEN) {
78802dd2108Slg 				mutex_exit(&kp->kp_mutex);
78902dd2108Slg 				keyspan_close_port_pipes(kp);
79002dd2108Slg 			} else {
79102dd2108Slg 				mutex_exit(&kp->kp_mutex);
79202dd2108Slg 			}
79302dd2108Slg 		}
79402dd2108Slg 
79502dd2108Slg 		break;
79602dd2108Slg 	default:
79702dd2108Slg 		USB_DPRINTF_L2(DPRINT_CLOSE, ksp->ks_lh,
79877e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    "keyspan_close_open_pipes:"
79977e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    "the device's product id can't be recognized");
80002dd2108Slg 
80160b08185Syz 	}
80260b08185Syz }
80360b08185Syz 
80460b08185Syz /*
80560b08185Syz  * Close global pipes
80660b08185Syz  */
80760b08185Syz void
keyspan_close_dev_pipes(keyspan_state_t * ksp)80860b08185Syz keyspan_close_dev_pipes(keyspan_state_t *ksp)
80960b08185Syz {
81060b08185Syz 	USB_DPRINTF_L4(DPRINT_CLOSE, ksp->ks_lh, "keyspan_close_dev_pipes");
81160b08185Syz 
81202dd2108Slg 	switch (ksp->ks_dev_spec.id_product) {
81302dd2108Slg 	case KEYSPAN_USA19HS_PID:
81402dd2108Slg 	case KEYSPAN_USA49WLC_PID:
81502dd2108Slg 		keyspan_close_one_pipe(&ksp->ks_statin_pipe);
81602dd2108Slg 		keyspan_close_one_pipe(&ksp->ks_ctrlout_pipe);
81702dd2108Slg 
81802dd2108Slg 		break;
81902dd2108Slg 
82002dd2108Slg 	case KEYSPAN_USA49WG_PID:
82102dd2108Slg 		/*
82202dd2108Slg 		 * USA_49WG use default control pipe, don't need close it
82302dd2108Slg 		 * Stop polling before close status in pipe
82402dd2108Slg 		 */
82502dd2108Slg 		usb_pipe_stop_intr_polling(ksp->ks_statin_pipe.pipe_handle,
82677e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    USB_FLAGS_SLEEP);
82702dd2108Slg 		keyspan_close_one_pipe(&ksp->ks_statin_pipe);
82860b08185Syz 
82902dd2108Slg 		break;
83002dd2108Slg 	default:
83102dd2108Slg 		USB_DPRINTF_L2(DPRINT_CLOSE, ksp->ks_lh,
83277e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    "keyspan_close_dev_pipes:"
83377e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    "the device's product id can't be recognized");
83402dd2108Slg 	}
83502dd2108Slg 
83602dd2108Slg }
83760b08185Syz 
83860b08185Syz /*
83960b08185Syz  * Open bulk data IN and data OUT pipes for one port.
84060b08185Syz  * The status and control pipes are opened in attach because they are global.
84160b08185Syz  */
84260b08185Syz int
keyspan_open_port_pipes(keyspan_port_t * kp)84360b08185Syz keyspan_open_port_pipes(keyspan_port_t *kp)
84460b08185Syz {
84560b08185Syz 	keyspan_state_t	*ksp = kp->kp_ksp;
84660b08185Syz 	int		rval;
84760b08185Syz 
84860b08185Syz 	USB_DPRINTF_L4(DPRINT_OPEN, kp->kp_lh, "keyspan_open_port_pipes");
84960b08185Syz 
85002dd2108Slg 	switch (ksp->ks_dev_spec.id_product) {
85102dd2108Slg 	case KEYSPAN_USA19HS_PID:
85202dd2108Slg 	case KEYSPAN_USA49WLC_PID:
85302dd2108Slg 		rval = keyspan_open_one_pipe(ksp, &kp->kp_datain_pipe);
85402dd2108Slg 
85502dd2108Slg 		break;
85602dd2108Slg 	case KEYSPAN_USA49WG_PID:
85702dd2108Slg 		rval = keyspan_open_pipe_datain_usa49wg(ksp,
85877e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    &kp->kp_datain_pipe);
85902dd2108Slg 
86002dd2108Slg 		break;
86102dd2108Slg 	default:
86202dd2108Slg 		USB_DPRINTF_L2(DPRINT_OPEN, kp->kp_lh,
86377e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    "keyspan_open_port_pipes:"
86477e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    "the device's product id can't be recognized");
86502dd2108Slg 	}
86602dd2108Slg 
86760b08185Syz 	if (rval != USB_SUCCESS) {
86860b08185Syz 
86960b08185Syz 		goto fail;
87060b08185Syz 	}
87160b08185Syz 
87260b08185Syz 	rval = keyspan_open_one_pipe(ksp, &kp->kp_dataout_pipe);
87360b08185Syz 	if (rval != USB_SUCCESS) {
87460b08185Syz 
87560b08185Syz 		goto fail;
87660b08185Syz 	}
87760b08185Syz 
87860b08185Syz 	return (rval);
87960b08185Syz 
88060b08185Syz fail:
88160b08185Syz 	USB_DPRINTF_L2(DPRINT_OPEN, kp->kp_lh,
88260b08185Syz 	    "keyspan_open_port_pipes: failed %d", rval);
88360b08185Syz 	keyspan_close_port_pipes(kp);
88460b08185Syz 
88560b08185Syz 	return (rval);
88660b08185Syz }
88760b08185Syz 
88860b08185Syz void
keyspan_close_pipes(keyspan_state_t * ksp)88960b08185Syz keyspan_close_pipes(keyspan_state_t *ksp)
89060b08185Syz {
89160b08185Syz 	USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, "keyspan_close_pipes");
89260b08185Syz 
89360b08185Syz 	/* close all ports' pipes first, and then device ctrl/status pipes. */
89460b08185Syz 	keyspan_close_open_pipes(ksp);
89560b08185Syz 	keyspan_close_dev_pipes(ksp);
89660b08185Syz }
89760b08185Syz /*
89860b08185Syz  * bulk out common callback
89960b08185Syz  */
90060b08185Syz /*ARGSUSED*/
90160b08185Syz void
keyspan_bulkout_cb(usb_pipe_handle_t pipe,usb_bulk_req_t * req)90260b08185Syz keyspan_bulkout_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
90360b08185Syz {
90460b08185Syz 	keyspan_port_t	*kp = (keyspan_port_t *)req->bulk_client_private;
90560b08185Syz 	keyspan_pipe_t	*bulkout = &kp->kp_dataout_pipe;
90660b08185Syz 	mblk_t		*data = req->bulk_data;
90760b08185Syz 	int		data_len;
90860b08185Syz 
90960b08185Syz 	data_len = (data) ? MBLKL(data) : 0;
91060b08185Syz 
91160b08185Syz 	USB_DPRINTF_L4(DPRINT_OUT_PIPE, bulkout->pipe_lh,
91260b08185Syz 	    "keyspan_bulkout_cb: len=%d cr=%d cb_flags=%x",
91360b08185Syz 	    data_len, req->bulk_completion_reason, req->bulk_cb_flags);
91460b08185Syz 
915688b07c5Sgc 	if (req->bulk_completion_reason && data) {
91660b08185Syz 
91760b08185Syz 		/*
91860b08185Syz 		 * Data wasn't transfered successfully.
91960b08185Syz 		 * Put data back on the queue.
92060b08185Syz 		 */
92160b08185Syz 		keyspan_put_head(&kp->kp_tx_mp, data, kp);
92260b08185Syz 
92360b08185Syz 		/* don't release mem in usb_free_bulk_req */
92460b08185Syz 		req->bulk_data = NULL;
92560b08185Syz 	}
92660b08185Syz 
92760b08185Syz 	usb_free_bulk_req(req);
92860b08185Syz 
92960b08185Syz 	/* if more data available, kick off another transmit */
93060b08185Syz 	mutex_enter(&kp->kp_mutex);
93160b08185Syz 	if (kp->kp_tx_mp == NULL) {
932688b07c5Sgc 		/*
933688b07c5Sgc 		 * Attach a zero packet if data length is muliple of 64,
934688b07c5Sgc 		 * due to the specification of keyspan_usa19hs.
935688b07c5Sgc 		 */
936688b07c5Sgc 		if ((kp->kp_ksp->ks_dev_spec.id_product ==
93777e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    KEYSPAN_USA19HS_PID) && (data_len == 64)) {
938688b07c5Sgc 			kp->kp_tx_mp = allocb(0, BPRI_LO);
939688b07c5Sgc 			if (kp->kp_tx_mp) {
940688b07c5Sgc 				keyspan_tx_start(kp, NULL);
941688b07c5Sgc 				mutex_exit(&kp->kp_mutex);
942688b07c5Sgc 
943688b07c5Sgc 				return;
944688b07c5Sgc 			}
945688b07c5Sgc 		}
94602dd2108Slg 		/* no more data, notify waiters */
94702dd2108Slg 		cv_broadcast(&kp->kp_tx_cv);
94802dd2108Slg 		mutex_exit(&kp->kp_mutex);
94902dd2108Slg 
95002dd2108Slg 		/* tx callback for this port */
95102dd2108Slg 		kp->kp_cb.cb_tx(kp->kp_cb.cb_arg);
95202dd2108Slg 	} else {
95302dd2108Slg 		keyspan_tx_start(kp, NULL);
95402dd2108Slg 		mutex_exit(&kp->kp_mutex);
95502dd2108Slg 	}
95602dd2108Slg }
95702dd2108Slg 
95802dd2108Slg /*
95902dd2108Slg  * intr out common callback for USA_49WG port0 only
96002dd2108Slg  */
96102dd2108Slg /*ARGSUSED*/
96202dd2108Slg void
keyspan_introut_cb_usa49wg(usb_pipe_handle_t pipe,usb_intr_req_t * req)96302dd2108Slg keyspan_introut_cb_usa49wg(usb_pipe_handle_t pipe, usb_intr_req_t *req)
96402dd2108Slg {
96502dd2108Slg 	keyspan_port_t	*kp = (keyspan_port_t *)req->intr_client_private;
96602dd2108Slg 	keyspan_pipe_t	*introut = &kp->kp_dataout_pipe;
96702dd2108Slg 	mblk_t		*data = req->intr_data;
96802dd2108Slg 	int		data_len;
96902dd2108Slg 
97002dd2108Slg 	data_len = (data) ? MBLKL(data) : 0;
97102dd2108Slg 
97202dd2108Slg 	USB_DPRINTF_L4(DPRINT_OUT_PIPE, introut->pipe_lh,
97302dd2108Slg 	    "keyspan_introut_cb_usa49wg: len=%d cr=%d cb_flags=%x",
97402dd2108Slg 	    data_len, req->intr_completion_reason, req->intr_cb_flags);
97502dd2108Slg 
97602dd2108Slg 	if (req->intr_completion_reason && (data_len > 0)) {
97702dd2108Slg 
97802dd2108Slg 		/*
97902dd2108Slg 		 * Data wasn't transfered successfully.
98002dd2108Slg 		 * Put data back on the queue.
98102dd2108Slg 		 */
98202dd2108Slg 		keyspan_put_head(&kp->kp_tx_mp, data, kp);
98302dd2108Slg 
98402dd2108Slg 		/* don't release mem in usb_free_bulk_req */
98502dd2108Slg 		req->intr_data = NULL;
98602dd2108Slg 	}
98702dd2108Slg 
98802dd2108Slg 	usb_free_intr_req(req);
98902dd2108Slg 
99002dd2108Slg 	/* if more data available, kick off another transmit */
99102dd2108Slg 	mutex_enter(&kp->kp_mutex);
99202dd2108Slg 	if (kp->kp_tx_mp == NULL) {
99360b08185Syz 
994688b07c5Sgc 		/* no more data, notify waiters */
995688b07c5Sgc 		cv_broadcast(&kp->kp_tx_cv);
996688b07c5Sgc 		mutex_exit(&kp->kp_mutex);
99760b08185Syz 
998688b07c5Sgc 		/* tx callback for this port */
999688b07c5Sgc 		kp->kp_cb.cb_tx(kp->kp_cb.cb_arg);
100060b08185Syz 	} else {
100160b08185Syz 		keyspan_tx_start(kp, NULL);
100260b08185Syz 		mutex_exit(&kp->kp_mutex);
100360b08185Syz 	}
100460b08185Syz }
100560b08185Syz 
1006c138f478Syz 
1007c138f478Syz /* For incoming data only. Parse a status byte and return the err code */
1008c138f478Syz void
keyspan_parse_status(uchar_t * status,uchar_t * err)1009c138f478Syz keyspan_parse_status(uchar_t *status, uchar_t *err)
1010c138f478Syz {
1011c138f478Syz 	if (*status & RXERROR_BREAK) {
1012c138f478Syz 		/*
1013c138f478Syz 		 * Parity and Framing errors only count if they
1014c138f478Syz 		 * occur exclusive of a break being received.
1015c138f478Syz 		 */
1016c138f478Syz 		*status &= (uint8_t)(RXERROR_OVERRUN | RXERROR_BREAK);
1017c138f478Syz 	}
1018c138f478Syz 	*err |= (*status & RXERROR_OVERRUN) ? DS_OVERRUN_ERR : 0;
1019c138f478Syz 	*err |= (*status & RXERROR_PARITY) ? DS_PARITY_ERR : 0;
1020c138f478Syz 	*err |= (*status & RXERROR_FRAMING) ? DS_FRAMING_ERR : 0;
1021c138f478Syz 	*err |= (*status & RXERROR_BREAK) ? DS_BREAK_ERR : 0;
1022c138f478Syz }
1023c138f478Syz 
102402dd2108Slg /* Bulk in data process function, used by all models */
102502dd2108Slg int
keyspan_bulkin_cb_process(keyspan_port_t * kp,uint8_t data_len,uchar_t status,mblk_t * data)102602dd2108Slg keyspan_bulkin_cb_process(keyspan_port_t *kp,
102702dd2108Slg 		uint8_t data_len, uchar_t status, mblk_t *data)
102802dd2108Slg {
102902dd2108Slg 	uchar_t	err = 0;
103002dd2108Slg 	mblk_t	*mp;
103102dd2108Slg 	/*
103202dd2108Slg 	 * According to Keyspan spec, if 0x80 bit is clear, there is
103302dd2108Slg 	 * only one status byte at the head of the data buf; if 0x80 bit
103402dd2108Slg 	 * set, then data buf contains alternate status and data bytes;
103502dd2108Slg 	 * In the first case, only OVERRUN err can exist; In the second
103602dd2108Slg 	 * case, there are four kinds of err bits may appear in status.
103702dd2108Slg 	 */
103802dd2108Slg 
103902dd2108Slg 	/* if 0x80 bit AND overrun bit are clear, just send up data */
104002dd2108Slg 	if (!(status & 0x80) && !(status & RXERROR_OVERRUN)) {
104102dd2108Slg 
104202dd2108Slg 		/* Get rid of the first status byte */
104302dd2108Slg 		data->b_rptr++;
104402dd2108Slg 		data_len--;
104502dd2108Slg 
104602dd2108Slg 	} else if (!(status & 0x80)) {
104702dd2108Slg 		/* If 0x80 bit is clear and overrun bit is set */
104802dd2108Slg 
104902dd2108Slg 		keyspan_parse_status(&status, &err);
105002dd2108Slg 		mutex_exit(&kp->kp_mutex);
105102dd2108Slg 		if ((mp = allocb(2, BPRI_HI)) == NULL) {
105202dd2108Slg 			USB_DPRINTF_L2(DPRINT_IN_PIPE, kp->kp_lh,
105377e51571Sgongtian zhao - Sun Microsystems - Beijing China 			    "keyspan_bulkin_cb_process: allocb failed");
105402dd2108Slg 			mutex_enter(&kp->kp_mutex);
105502dd2108Slg 
105602dd2108Slg 			return (0);
105702dd2108Slg 		}
105802dd2108Slg 		DB_TYPE(mp) = M_BREAK;
105902dd2108Slg 		*mp->b_wptr++ = err;
106002dd2108Slg 		*mp->b_wptr++ = status;
106102dd2108Slg 		mutex_enter(&kp->kp_mutex);
106202dd2108Slg 
106302dd2108Slg 		/* Add to the received list; Send up the err code. */
106402dd2108Slg 		keyspan_put_tail(&kp->kp_rx_mp, mp);
106502dd2108Slg 
106602dd2108Slg 		/*
106702dd2108Slg 		 * Don't send up the first byte because
106802dd2108Slg 		 * it is a status byte.
106902dd2108Slg 		 */
107002dd2108Slg 		data->b_rptr++;
107102dd2108Slg 		data_len--;
107202dd2108Slg 
107302dd2108Slg 	} else { /* 0x80 bit set, there are some errs in the data */
107402dd2108Slg 		/*
107502dd2108Slg 		 * Usually, there are at least two bytes,
107602dd2108Slg 		 * one status and one data.
107702dd2108Slg 		 */
107802dd2108Slg 		if (data_len > 1) {
107902dd2108Slg 			int i = 0;
108002dd2108Slg 			int j = 1;
108102dd2108Slg 			/*
108202dd2108Slg 			 * In this case, there might be multi status
108302dd2108Slg 			 * bytes. Parse each status byte and move the
108402dd2108Slg 			 * data bytes together.
108502dd2108Slg 			 */
108602dd2108Slg 			for (j = 1; j < data_len; j += 2) {
108702dd2108Slg 				status = data->b_rptr[j-1];
108802dd2108Slg 				keyspan_parse_status(&status, &err);
108902dd2108Slg 
109002dd2108Slg 				/* move the data togeter */
109102dd2108Slg 				data->b_rptr[i] = data->b_rptr[j];
109202dd2108Slg 				i++;
109302dd2108Slg 			}
109402dd2108Slg 			data->b_wptr = data->b_rptr + i;
109502dd2108Slg 		} else { /* There are only one byte in incoming buf */
109602dd2108Slg 			keyspan_parse_status(&status, &err);
109702dd2108Slg 		}
109802dd2108Slg 		mutex_exit(&kp->kp_mutex);
109902dd2108Slg 		if ((mp = allocb(2, BPRI_HI)) == NULL) {
110002dd2108Slg 			USB_DPRINTF_L2(DPRINT_IN_PIPE, kp->kp_lh,
110177e51571Sgongtian zhao - Sun Microsystems - Beijing China 			    "keyspan_bulkin_cb_process: allocb failed");
110202dd2108Slg 			mutex_enter(&kp->kp_mutex);
110302dd2108Slg 
110402dd2108Slg 			return (0);
110502dd2108Slg 		}
110602dd2108Slg 		DB_TYPE(mp) = M_BREAK;
110702dd2108Slg 		*mp->b_wptr++ = err;
110802dd2108Slg 		if (data_len > 2) {
110902dd2108Slg 			/*
111002dd2108Slg 			 * There are multiple status bytes in this case.
111102dd2108Slg 			 * Use err as status character since err is got
111202dd2108Slg 			 * by or in all status bytes.
111302dd2108Slg 			 */
111402dd2108Slg 			*mp->b_wptr++ = err;
111502dd2108Slg 		} else {
111602dd2108Slg 			*mp->b_wptr++ = status;
111702dd2108Slg 		}
111802dd2108Slg 		mutex_enter(&kp->kp_mutex);
111902dd2108Slg 
112002dd2108Slg 		/* Add to the received list; Send up the err code. */
112102dd2108Slg 		keyspan_put_tail(&kp->kp_rx_mp, mp);
112202dd2108Slg 
112302dd2108Slg 		if (data_len > 1) {
1124*d29f5a71Szhigang lu - Sun Microsystems - Beijing China 			data_len = MBLKL(data);
112502dd2108Slg 		}
112602dd2108Slg 	}
112702dd2108Slg 	return (data_len);
112802dd2108Slg }
1129c138f478Syz 
113060b08185Syz /*
113160b08185Syz  * pipe callbacks
113260b08185Syz  * --------------
113360b08185Syz  *
113402dd2108Slg  * bulk in common callback for USA19HS and USA49WLC model
113560b08185Syz  */
113660b08185Syz /*ARGSUSED*/
113760b08185Syz int
keyspan_bulkin_cb_usa49(usb_pipe_handle_t pipe,usb_bulk_req_t * req)113802dd2108Slg keyspan_bulkin_cb_usa49(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
113960b08185Syz {
114060b08185Syz 	keyspan_port_t	*kp = (keyspan_port_t *)req->bulk_client_private;
114160b08185Syz 	keyspan_pipe_t	*bulkin = &kp->kp_datain_pipe;
114260b08185Syz 	mblk_t		*data = req->bulk_data;
114360b08185Syz 	uint_t		cr = req->bulk_completion_reason;
114460b08185Syz 	int		data_len;
114560b08185Syz 
114660b08185Syz 	ASSERT(mutex_owned(&kp->kp_mutex));
114760b08185Syz 
114860b08185Syz 	data_len = (data) ? MBLKL(data) : 0;
114960b08185Syz 
115060b08185Syz 	USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh,
115102dd2108Slg 	    "keyspan_bulkin_cb_usa49: len=%d"
115202dd2108Slg 	    " cr=%d flags=%x", data_len, cr, req->bulk_cb_flags);
115360b08185Syz 
115460b08185Syz 	/* put data on the read queue */
115560b08185Syz 	if ((data_len > 0) && (kp->kp_state != KEYSPAN_PORT_CLOSED) &&
115660b08185Syz 	    (cr == USB_CR_OK)) {
1157c138f478Syz 		uchar_t	status = data->b_rptr[0];
1158c138f478Syz 
115902dd2108Slg 		if ((data_len = keyspan_bulkin_cb_process(kp, data_len,
116077e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    status, data)) > 0) {
116102dd2108Slg 			keyspan_put_tail(&kp->kp_rx_mp, data);
1162c138f478Syz 			/*
116302dd2108Slg 			 * the data will not be freed and
116402dd2108Slg 			 * will be sent up later.
1165c138f478Syz 			 */
116602dd2108Slg 			req->bulk_data = NULL;
116760b08185Syz 		}
116802dd2108Slg 	} else {
116902dd2108Slg 		/* usb error happened, so don't send up data */
1170c138f478Syz 		data_len = 0;
117102dd2108Slg 		USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh,
117202dd2108Slg 		    "keyspan_bulkin_cb_usa49: port_state=%d"
117302dd2108Slg 		    " b_rptr[0]=%c", kp->kp_state, data->b_rptr[0]);
1174c138f478Syz 	}
1175c138f478Syz 	if (kp->kp_state != KEYSPAN_PORT_OPEN) {
1176c138f478Syz 		kp->kp_no_more_reads = B_TRUE;
117760b08185Syz 	}
117860b08185Syz 
117960b08185Syz 	return (data_len);
118060b08185Syz }
118160b08185Syz 
118260b08185Syz /*
118360b08185Syz  * pipe callbacks
118460b08185Syz  * --------------
118560b08185Syz  *
118602dd2108Slg  * bulk in common callback for USA_49WG model
118760b08185Syz  */
118860b08185Syz /*ARGSUSED*/
118902dd2108Slg void
keyspan_bulkin_cb_usa49wg(usb_pipe_handle_t pipe,usb_bulk_req_t * req)119002dd2108Slg keyspan_bulkin_cb_usa49wg(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
119160b08185Syz {
119202dd2108Slg 	keyspan_port_t	*kp = (keyspan_port_t *)req->bulk_client_private,
119377e51571Sgongtian zhao - Sun Microsystems - Beijing China 	    *kp_true;
119402dd2108Slg 	keyspan_state_t *ksp = (keyspan_state_t *)kp->kp_ksp;
119502dd2108Slg 	mblk_t		*data = req->bulk_data,
119677e51571Sgongtian zhao - Sun Microsystems - Beijing China 	    *mp_data;
119702dd2108Slg 	uint_t		cr = req->bulk_completion_reason,
119877e51571Sgongtian zhao - Sun Microsystems - Beijing China 	    port_data_len;
119902dd2108Slg 	int		data_len, copy_len;
120002dd2108Slg 	uint8_t		port_num,
120177e51571Sgongtian zhao - Sun Microsystems - Beijing China 	    port_cnt = 0,
120277e51571Sgongtian zhao - Sun Microsystems - Beijing China 	    port[4],
120377e51571Sgongtian zhao - Sun Microsystems - Beijing China 	    receive_flag = 1;
120402dd2108Slg 	uint16_t	status;
120502dd2108Slg 	unsigned char	*old_rptr;
120660b08185Syz 
120760b08185Syz 	data_len = (data) ? MBLKL(data) : 0;
120860b08185Syz 
120902dd2108Slg 	USB_DPRINTF_L2(DPRINT_IN_PIPE, ksp->ks_lh,
121002dd2108Slg 	    "keyspan_bulkin_cb_usa49wg: len=%d"
121160b08185Syz 	    " cr=%d flags=%x", data_len, cr, req->bulk_cb_flags);
121260b08185Syz 
121360b08185Syz 	/* put data on the read queue */
121402dd2108Slg 	if ((data_len > 0) && (cr == USB_CR_OK)) {
121502dd2108Slg 		old_rptr = data->b_rptr;
121602dd2108Slg 		while (data->b_rptr < data->b_wptr) {
121702dd2108Slg 			port_num = data->b_rptr[0];
121802dd2108Slg 			port_data_len = data->b_rptr[1];
121902dd2108Slg 			status = data->b_rptr[2];
122002dd2108Slg 			data->b_rptr += 2;
122102dd2108Slg 
122202dd2108Slg 			if (port_num > 3) {
122302dd2108Slg 				USB_DPRINTF_L2(DPRINT_IN_PIPE, ksp->ks_lh,
122477e51571Sgongtian zhao - Sun Microsystems - Beijing China 				    "keyspan_bulkin_cb_usa49wg,port num is not"
122577e51571Sgongtian zhao - Sun Microsystems - Beijing China 				    " correct: port=%d, len=%d, status=%x",
122677e51571Sgongtian zhao - Sun Microsystems - Beijing China 				    port_num, port_data_len, status);
1227c138f478Syz 
122802dd2108Slg 				break;
122960b08185Syz 			}
1230c138f478Syz 
123102dd2108Slg 			kp_true = &ksp->ks_ports[port_num];
123202dd2108Slg 			port[++port_cnt] = port_num;
123302dd2108Slg 			mutex_enter(&kp_true->kp_mutex);
1234c138f478Syz 
123502dd2108Slg 			if (kp_true->kp_state != KEYSPAN_PORT_OPEN) {
123602dd2108Slg 				mutex_exit(&kp_true->kp_mutex);
1237c138f478Syz 
123802dd2108Slg 				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");
124102dd2108Slg 				data->b_rptr += port_data_len;
124202dd2108Slg 				port_cnt--;
1243c138f478Syz 
124402dd2108Slg 				continue;
1245c138f478Syz 			}
124602dd2108Slg 
124702dd2108Slg 			USB_DPRINTF_L2(DPRINT_IN_PIPE, kp_true->kp_lh,
124802dd2108Slg 			    "keyspan_bulkin_cb_usa49wg: status=0x%x, len=%d",
124902dd2108Slg 			    status, port_data_len);
125002dd2108Slg 
125102dd2108Slg 			if ((copy_len = keyspan_bulkin_cb_process(kp_true,
125277e51571Sgongtian zhao - Sun Microsystems - Beijing China 			    port_data_len, status, data)) > 0) {
125302dd2108Slg 
125402dd2108Slg 				mutex_exit(&kp_true->kp_mutex);
125502dd2108Slg 				if ((mp_data = allocb(copy_len, BPRI_HI))
125677e51571Sgongtian zhao - Sun Microsystems - Beijing China 				    == NULL) {
125702dd2108Slg 					USB_DPRINTF_L2(DPRINT_IN_PIPE,
125877e51571Sgongtian zhao - Sun Microsystems - Beijing China 					    kp_true->kp_lh, "keyspan_bulkin_cb_"
125977e51571Sgongtian zhao - Sun Microsystems - Beijing China 					    "usa49wg: allocb failed");
126002dd2108Slg 
126102dd2108Slg 					return;
126202dd2108Slg 				}
126302dd2108Slg 				mutex_enter(&kp_true->kp_mutex);
126402dd2108Slg 				DB_TYPE(mp_data) = M_DATA;
126502dd2108Slg 				bcopy(data->b_rptr, mp_data->b_wptr, copy_len);
126602dd2108Slg 				mp_data->b_wptr += copy_len;
126702dd2108Slg 				if (copy_len < port_data_len -1) {
126802dd2108Slg 					/*
126902dd2108Slg 					 * data has multi status bytes, b_wptr
127002dd2108Slg 					 * has changed by
127102dd2108Slg 					 * keyspan_bulkin_process(), need to
127202dd2108Slg 					 * be recovered to old one
127302dd2108Slg 					 */
127402dd2108Slg 					data->b_rptr += port_data_len;
127502dd2108Slg 					data->b_wptr = old_rptr + data_len;
127602dd2108Slg 				} else {
127702dd2108Slg 					data->b_rptr += copy_len;
127860b08185Syz 				}
127960b08185Syz 
128002dd2108Slg 				keyspan_put_tail(&kp_true->kp_rx_mp, mp_data);
128102dd2108Slg 				mutex_exit(&kp_true->kp_mutex);
128260b08185Syz 			} else {
128302dd2108Slg 				mutex_exit(&kp_true->kp_mutex);
128402dd2108Slg 
128502dd2108Slg 				break;
1286c138f478Syz 			}
128702dd2108Slg 		} /* End of while loop */
128802dd2108Slg 
128902dd2108Slg 		while (port_cnt) {
129002dd2108Slg 			port_num = port[port_cnt--];
129102dd2108Slg 			kp_true = &ksp->ks_ports[port_num];
129202dd2108Slg 			mutex_enter(&kp_true->kp_mutex);
1293c138f478Syz 
129402dd2108Slg 			if (kp_true->kp_state != KEYSPAN_PORT_OPEN) {
129502dd2108Slg 				kp_true->kp_no_more_reads = B_TRUE;
129660b08185Syz 			}
129702dd2108Slg 			if (receive_flag && (!kp_true->kp_no_more_reads)) {
129802dd2108Slg 				mutex_exit(&kp_true->kp_mutex);
129902dd2108Slg 				/* kick off another read */
130002dd2108Slg 				(void) keyspan_receive_data(
130177e51571Sgongtian zhao - Sun Microsystems - Beijing China 				    &kp_true->kp_datain_pipe,
130277e51571Sgongtian zhao - Sun Microsystems - Beijing China 				    kp_true->kp_read_len, kp_true);
130302dd2108Slg 
130402dd2108Slg 				receive_flag = 0;
130502dd2108Slg 			} else {
130602dd2108Slg 				mutex_exit(&kp_true->kp_mutex);
130702dd2108Slg 			}
130802dd2108Slg 			/* setup rx callback for this port */
130902dd2108Slg 			kp_true->kp_cb.cb_rx(kp_true->kp_cb.cb_arg);
131060b08185Syz 		}
131160b08185Syz 	} else {
131202dd2108Slg 		/* cr != USB_CR_OK, usb error happened */
131302dd2108Slg 		USB_DPRINTF_L2(DPRINT_IN_PIPE, ksp->ks_lh,
131477e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    "keyspan_bulkin_cb_usa49wg: port=%d, len=%d, status=%x",
131577e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    data->b_rptr[0], data->b_rptr[1], data->b_rptr[2]);
131602dd2108Slg 
131702dd2108Slg 		mutex_enter(&kp->kp_mutex);
131802dd2108Slg 		if (kp->kp_state != KEYSPAN_PORT_OPEN) {
131902dd2108Slg 			kp->kp_no_more_reads = B_TRUE;
132002dd2108Slg 		}
132102dd2108Slg 		if (!kp->kp_no_more_reads) {
132202dd2108Slg 			mutex_exit(&kp->kp_mutex);
132302dd2108Slg 			/* kick off another read */
132402dd2108Slg 			(void) keyspan_receive_data(&kp->kp_datain_pipe,
132577e51571Sgongtian zhao - Sun Microsystems - Beijing China 			    kp->kp_read_len, kp);
132602dd2108Slg 		} else {
132702dd2108Slg 			mutex_exit(&kp->kp_mutex);
132802dd2108Slg 		}
132960b08185Syz 	}
133060b08185Syz 
133102dd2108Slg 	freemsg(data);
133202dd2108Slg 	req->bulk_data = NULL;
133302dd2108Slg 	usb_free_bulk_req(req);
1334c138f478Syz 
133502dd2108Slg }
133660b08185Syz 
133760b08185Syz /*
133860b08185Syz  * pipe callbacks
133960b08185Syz  * --------------
134060b08185Syz  *
134102dd2108Slg  * bulk in common callback for USA19HS and USA49WLC
134260b08185Syz  */
134360b08185Syz /*ARGSUSED*/
134460b08185Syz void
keyspan_bulkin_cb(usb_pipe_handle_t pipe,usb_bulk_req_t * req)134560b08185Syz keyspan_bulkin_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
134660b08185Syz {
134760b08185Syz 	keyspan_port_t	*kp = (keyspan_port_t *)req->bulk_client_private;
134860b08185Syz 	int		data_len;
134960b08185Syz 	boolean_t	no_more_reads = B_FALSE;
135060b08185Syz 
135160b08185Syz 	USB_DPRINTF_L4(DPRINT_IN_PIPE, (&kp->kp_datain_pipe)->pipe_lh,
135260b08185Syz 	    "keyspan_bulkin_cb");
135360b08185Syz 
135460b08185Syz 	mutex_enter(&kp->kp_mutex);
135560b08185Syz 
135660b08185Syz 	/* put data on the read queue */
135702dd2108Slg 	data_len = keyspan_bulkin_cb_usa49(pipe, req);
135860b08185Syz 	no_more_reads = kp->kp_no_more_reads;
135960b08185Syz 
136060b08185Syz 	mutex_exit(&kp->kp_mutex);
136160b08185Syz 
136260b08185Syz 	usb_free_bulk_req(req);
136360b08185Syz 
136460b08185Syz 	/* kick off another read unless indicated otherwise */
136560b08185Syz 	if (!no_more_reads) {
136660b08185Syz 		(void) keyspan_receive_data(&kp->kp_datain_pipe,
136760b08185Syz 		    kp->kp_read_len, kp);
136860b08185Syz 	}
136960b08185Syz 
137060b08185Syz 	/* setup rx callback for this port */
137160b08185Syz 	if (data_len > 0)  {
137260b08185Syz 		kp->kp_cb.cb_rx(kp->kp_cb.cb_arg);
137360b08185Syz 	}
137460b08185Syz }
137560b08185Syz 
137660b08185Syz /*
137760b08185Syz  * pipe callbacks
137860b08185Syz  * --------------
137960b08185Syz  *
138060b08185Syz  * bulk in status callback for usa19hs model
138160b08185Syz  */
138260b08185Syz /*ARGSUSED*/
138360b08185Syz void
keyspan_status_cb_usa19hs(usb_pipe_handle_t pipe,usb_bulk_req_t * req)138460b08185Syz keyspan_status_cb_usa19hs(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
138560b08185Syz {
138660b08185Syz 	keyspan_state_t	*ksp = (keyspan_state_t *)req->bulk_client_private;
138760b08185Syz 	keyspan_pipe_t	*bulkin = &ksp->ks_statin_pipe;
138860b08185Syz 	mblk_t		*data = req->bulk_data;
138960b08185Syz 	usb_cr_t	cr = req->bulk_completion_reason;
139060b08185Syz 	int		data_len;
139160b08185Syz 
139260b08185Syz 	data_len = (data) ? MBLKL(data) : 0;
139360b08185Syz 
139460b08185Syz 	USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh,
139560b08185Syz 	    "keyspan_status_cb_usa19hs: len=%d"
139660b08185Syz 	    " cr=%d flags=%x", data_len, cr, req->bulk_cb_flags);
139760b08185Syz 
139860b08185Syz 	/* put data on the read queue */
139960b08185Syz 	if ((data_len == 14) && (cr == USB_CR_OK)) {
140060b08185Syz 		keyspan_port_t	*kp = &ksp->ks_ports[0];
140160b08185Syz 		keyspan_usa19hs_port_status_msg_t *status_msg =
140260b08185Syz 		    &(kp->kp_status_msg.usa19hs);
140360b08185Syz 
140460b08185Syz 		mutex_enter(&kp->kp_mutex);
140560b08185Syz 		bcopy(data->b_rptr, status_msg, data_len);
140660b08185Syz 
140760b08185Syz 		if (status_msg->controlResponse) {
140860b08185Syz 			kp->kp_status_flag |= KEYSPAN_PORT_CTRLRESP;
140960b08185Syz 		} else {
141060b08185Syz 			kp->kp_status_flag &= ~KEYSPAN_PORT_CTRLRESP;
141160b08185Syz 		}
141260b08185Syz 
141360b08185Syz 		if (status_msg->portState & PORTSTATE_ENABLED) {
141460b08185Syz 			kp->kp_status_flag |= KEYSPAN_PORT_ENABLE;
141560b08185Syz 		} else {
141660b08185Syz 			kp->kp_status_flag &= ~KEYSPAN_PORT_ENABLE;
141760b08185Syz 		}
141860b08185Syz 
141960b08185Syz 		if (status_msg->portState & PORTSTATE_TXBREAK) {
142060b08185Syz 			kp->kp_status_flag |= KEYSPAN_PORT_TXBREAK;
142160b08185Syz 		} else {
142260b08185Syz 			kp->kp_status_flag &= ~KEYSPAN_PORT_TXBREAK;
142360b08185Syz 		}
142460b08185Syz 
142560b08185Syz 		if (status_msg->rxBreak) {
142660b08185Syz 			kp->kp_status_flag |= KEYSPAN_PORT_RXBREAK;
142760b08185Syz 		} else {
142860b08185Syz 			kp->kp_status_flag &= ~KEYSPAN_PORT_RXBREAK;
142960b08185Syz 		}
143060b08185Syz 
143160b08185Syz 		if (status_msg->portState & PORTSTATE_LOOPBACK) {
143260b08185Syz 			kp->kp_status_flag |= KEYSPAN_PORT_LOOPBACK;
143360b08185Syz 		} else {
143460b08185Syz 			kp->kp_status_flag &= ~KEYSPAN_PORT_LOOPBACK;
143560b08185Syz 		}
143660b08185Syz 
143760b08185Syz 		/* if msr status changed, then invoke status callback */
143860b08185Syz 		if (status_msg->msr & USA_MSR_dCTS ||
143960b08185Syz 		    status_msg->msr & USA_MSR_dDSR ||
144060b08185Syz 		    status_msg->msr & USA_MSR_dRI ||
144160b08185Syz 		    status_msg->msr & USA_MSR_dDCD) {
144260b08185Syz 
144360b08185Syz 			mutex_exit(&kp->kp_mutex);
144460b08185Syz 			kp->kp_cb.cb_status(kp->kp_cb.cb_arg);
144560b08185Syz 		} else {
144660b08185Syz 			mutex_exit(&kp->kp_mutex);
144760b08185Syz 		}
144860b08185Syz 	} else {
144960b08185Syz 
145060b08185Syz 		USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh,
145160b08185Syz 		    "keyspan_status_cb_usa19hs: get status failed, cr=%d"
145260b08185Syz 		    " data_len=%d", cr, data_len);
145360b08185Syz 	}
145460b08185Syz }
145560b08185Syz 
1456c138f478Syz 
145760b08185Syz /*
145860b08185Syz  * pipe callbacks
145960b08185Syz  * --------------
146060b08185Syz  *
146160b08185Syz  * bulk in status callback for usa49 model
146260b08185Syz  */
146360b08185Syz /*ARGSUSED*/
146460b08185Syz void
keyspan_status_cb_usa49(usb_pipe_handle_t pipe,usb_bulk_req_t * req)146560b08185Syz keyspan_status_cb_usa49(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
146660b08185Syz {
146760b08185Syz 	keyspan_state_t	*ksp = (keyspan_state_t *)req->bulk_client_private;
146860b08185Syz 	keyspan_pipe_t	*bulkin = &ksp->ks_statin_pipe;
146960b08185Syz 	mblk_t		*data = req->bulk_data;
147060b08185Syz 	uint_t		cr = req->bulk_completion_reason;
147160b08185Syz 	int		data_len;
147260b08185Syz 
147360b08185Syz 	data_len = (data) ? MBLKL(data) : 0;
147460b08185Syz 
147560b08185Syz 	USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh,
147660b08185Syz 	    "keyspan_status_cb_usa49: len=%d"
147760b08185Syz 	    " cr=%d flags=%x", data_len, cr, req->bulk_cb_flags);
147860b08185Syz 
147960b08185Syz 	/* put data on the read queue */
148060b08185Syz 	if ((data_len == 11) && (cr == USB_CR_OK)) {
148160b08185Syz 		keyspan_usa49_port_status_msg_t status_msg;
148260b08185Syz 		keyspan_port_t *cur_kp;
148360b08185Syz 		keyspan_usa49_port_status_msg_t *kp_status_msg;
148460b08185Syz 		boolean_t need_cb = B_FALSE;
148560b08185Syz 
148660b08185Syz 		bcopy(data->b_rptr, &status_msg, data_len);
148760b08185Syz 		if (status_msg.portNumber >= ksp->ks_dev_spec.port_cnt) {
148860b08185Syz 
148960b08185Syz 			return;
149060b08185Syz 		}
149160b08185Syz 		cur_kp = &ksp->ks_ports[status_msg.portNumber];
149260b08185Syz 		kp_status_msg = &(cur_kp->kp_status_msg.usa49);
149360b08185Syz 
149460b08185Syz 		mutex_enter(&cur_kp->kp_mutex);
149560b08185Syz 
149660b08185Syz 		/* if msr status changed, then need invoke status callback */
149760b08185Syz 		if (status_msg.cts !=  kp_status_msg->cts ||
149860b08185Syz 		    status_msg.dsr != kp_status_msg->dsr ||
149960b08185Syz 		    status_msg.ri != kp_status_msg->ri ||
150060b08185Syz 		    status_msg.dcd != kp_status_msg->dcd) {
150160b08185Syz 
150260b08185Syz 			need_cb = B_TRUE;
150360b08185Syz 		}
150460b08185Syz 
150560b08185Syz 		bcopy(&status_msg, kp_status_msg, data_len);
150660b08185Syz 
150760b08185Syz 		if (kp_status_msg->controlResponse) {
150860b08185Syz 			cur_kp->kp_status_flag |= KEYSPAN_PORT_CTRLRESP;
150960b08185Syz 		} else {
151060b08185Syz 			cur_kp->kp_status_flag &= ~KEYSPAN_PORT_CTRLRESP;
151160b08185Syz 		}
151260b08185Syz 
151360b08185Syz 		if (!kp_status_msg->rxEnabled) {
151460b08185Syz 			cur_kp->kp_status_flag |= KEYSPAN_PORT_RXBREAK;
151560b08185Syz 		} else {
151660b08185Syz 			cur_kp->kp_status_flag &= ~KEYSPAN_PORT_RXBREAK;
151760b08185Syz 		}
151860b08185Syz 
151960b08185Syz 		mutex_exit(&cur_kp->kp_mutex);
152060b08185Syz 
152160b08185Syz 		if (need_cb) {
152260b08185Syz 
152360b08185Syz 			cur_kp->kp_cb.cb_status(cur_kp->kp_cb.cb_arg);
152460b08185Syz 		}
152560b08185Syz 	} else {
152660b08185Syz 
152760b08185Syz 		USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh,
152860b08185Syz 		    "keyspan_status_cb_usa49: get status failed, cr=%d"
152960b08185Syz 		    " data_len=%d", cr, data_len);
153060b08185Syz 	}
153160b08185Syz }
1532c138f478Syz 
153360b08185Syz 
153460b08185Syz /*
153560b08185Syz  * pipe callbacks
153660b08185Syz  * --------------
153760b08185Syz  *
153860b08185Syz  * bulk in callback for status receiving
153960b08185Syz  */
154060b08185Syz /*ARGSUSED*/
154160b08185Syz void
keyspan_status_cb(usb_pipe_handle_t pipe,usb_bulk_req_t * req)154260b08185Syz keyspan_status_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
154360b08185Syz {
154460b08185Syz 	keyspan_state_t	*ksp = (keyspan_state_t *)req->bulk_client_private;
154560b08185Syz 	usb_cr_t	cr = req->bulk_completion_reason;
154660b08185Syz 
154760b08185Syz 	USB_DPRINTF_L4(DPRINT_IN_PIPE, (&ksp->ks_statin_pipe)->pipe_lh,
154860b08185Syz 	    "keyspan_status_cb");
154960b08185Syz 
155060b08185Syz 	/* put data on the read queue */
155160b08185Syz 	switch (ksp->ks_dev_spec.id_product) {
155260b08185Syz 	case KEYSPAN_USA19HS_PID:
155360b08185Syz 		keyspan_status_cb_usa19hs(pipe, req);
155460b08185Syz 
155560b08185Syz 		break;
155660b08185Syz 
1557c138f478Syz 
155860b08185Syz 	case KEYSPAN_USA49WLC_PID:
155960b08185Syz 		keyspan_status_cb_usa49(pipe, req);
156060b08185Syz 
156160b08185Syz 		break;
1562c138f478Syz 
156360b08185Syz 	default:
156460b08185Syz 		USB_DPRINTF_L2(DPRINT_IN_PIPE,
156560b08185Syz 		    (&ksp->ks_statin_pipe)->pipe_lh, "keyspan_status_cb:"
156660b08185Syz 		    "the device's product id can't be recognized");
156760b08185Syz 
156860b08185Syz 		return;
156960b08185Syz 	}
157060b08185Syz 
157160b08185Syz 	usb_free_bulk_req(req);
157260b08185Syz 
157360b08185Syz 	/* kick off another read to receive status */
157460b08185Syz 	if ((cr != USB_CR_FLUSHED) && (cr != USB_CR_DEV_NOT_RESP) &&
157560b08185Syz 	    keyspan_dev_is_online(ksp)) {
157660b08185Syz 		if (keyspan_receive_status(ksp) != USB_SUCCESS) {
157760b08185Syz 			USB_DPRINTF_L2(DPRINT_IN_PIPE,
157860b08185Syz 			    (&ksp->ks_statin_pipe)->pipe_lh,
157960b08185Syz 			    "keyspan_status_cb:"
158060b08185Syz 			    "receive status can't be restarted.");
158160b08185Syz 		}
158260b08185Syz 	} else {
158360b08185Syz 		USB_DPRINTF_L2(DPRINT_IN_PIPE,
158460b08185Syz 		    (&ksp->ks_statin_pipe)->pipe_lh, "keyspan_status_cb:"
158560b08185Syz 		    "get status failed: cr=%d", cr);
158660b08185Syz 	}
158760b08185Syz }
158860b08185Syz 
158960b08185Syz /*
159060b08185Syz  * Submit data read request (asynchronous). If this function returns
159160b08185Syz  * USB_SUCCESS, pipe is acquired and request is sent, otherwise req is free.
159260b08185Syz  */
159360b08185Syz int
keyspan_receive_data(keyspan_pipe_t * bulkin,int len,void * cb_arg)159460b08185Syz keyspan_receive_data(keyspan_pipe_t *bulkin, int len, void *cb_arg)
159560b08185Syz {
159660b08185Syz 	keyspan_state_t	*ksp = bulkin->pipe_ksp;
159760b08185Syz 	usb_bulk_req_t	*br;
159802dd2108Slg 	int		rval = USB_SUCCESS;
159960b08185Syz 
160060b08185Syz 	USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, "keyspan_receive_data:"
160160b08185Syz 	    "len=%d", len);
160260b08185Syz 
160360b08185Syz 	ASSERT(!mutex_owned(&bulkin->pipe_mutex));
160460b08185Syz 
160560b08185Syz 	br = usb_alloc_bulk_req(ksp->ks_dip, len, USB_FLAGS_SLEEP);
160660b08185Syz 	br->bulk_len = len;
160760b08185Syz 
160860b08185Syz 	/* No timeout, just wait for data */
160960b08185Syz 	br->bulk_timeout = 0;
161060b08185Syz 	br->bulk_client_private = cb_arg;
161160b08185Syz 	br->bulk_attributes = USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING;
161202dd2108Slg 
161302dd2108Slg 	switch (ksp->ks_dev_spec.id_product) {
161402dd2108Slg 	case KEYSPAN_USA19HS_PID:
161502dd2108Slg 	case KEYSPAN_USA49WLC_PID:
161602dd2108Slg 		br->bulk_cb = keyspan_bulkin_cb;
161702dd2108Slg 		br->bulk_exc_cb = keyspan_bulkin_cb;
161802dd2108Slg 
161902dd2108Slg 		break;
162002dd2108Slg 
162102dd2108Slg 	case KEYSPAN_USA49WG_PID:
162202dd2108Slg 		br->bulk_cb = keyspan_bulkin_cb_usa49wg;
162302dd2108Slg 		br->bulk_exc_cb = keyspan_bulkin_cb_usa49wg;
162402dd2108Slg 
162502dd2108Slg 		break;
162602dd2108Slg 
162702dd2108Slg 	default:
162802dd2108Slg 		usb_free_bulk_req(br);
162902dd2108Slg 
163002dd2108Slg 		USB_DPRINTF_L2(DPRINT_IN_PIPE,
163102dd2108Slg 		    (&ksp->ks_statin_pipe)->pipe_lh, "keyspan_receive_data:"
163202dd2108Slg 		    "the device's product id can't be recognized");
163302dd2108Slg 
163402dd2108Slg 		return (USB_FAILURE);
163502dd2108Slg 	}
163602dd2108Slg 
163760b08185Syz 
163860b08185Syz 	rval = usb_pipe_bulk_xfer(bulkin->pipe_handle, br, 0);
163960b08185Syz 	if (rval != USB_SUCCESS) {
164060b08185Syz 		usb_free_bulk_req(br);
164160b08185Syz 	}
164260b08185Syz 	USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh,
164360b08185Syz 	    "keyspan_receive_data: rval = %d", rval);
164460b08185Syz 	return (rval);
164560b08185Syz }
164660b08185Syz 
164760b08185Syz /*
164860b08185Syz  * submit device status read request (asynchronous).
164960b08185Syz  */
165060b08185Syz int
keyspan_receive_status(keyspan_state_t * ksp)165160b08185Syz keyspan_receive_status(keyspan_state_t	*ksp)
165260b08185Syz {
165360b08185Syz 	keyspan_pipe_t *bulkin = &ksp->ks_statin_pipe;
165460b08185Syz 	usb_bulk_req_t	*br;
165560b08185Syz 	int		rval;
165660b08185Syz 
165760b08185Syz 	USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh,
165860b08185Syz 	    "keyspan_receive_status");
165960b08185Syz 
166060b08185Syz 	ASSERT(!mutex_owned(&bulkin->pipe_mutex));
166160b08185Syz 
166260b08185Syz 	br = usb_alloc_bulk_req(ksp->ks_dip, 32, USB_FLAGS_SLEEP);
166360b08185Syz 	br->bulk_len = KEYSPAN_STATIN_MAX_LEN;
166460b08185Syz 
166560b08185Syz 	/* No timeout, just wait for data */
166660b08185Syz 	br->bulk_timeout = 0;
166760b08185Syz 	br->bulk_client_private = (void *)ksp;
166860b08185Syz 	br->bulk_attributes = USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING;
166960b08185Syz 	br->bulk_cb = keyspan_status_cb;
167060b08185Syz 	br->bulk_exc_cb = keyspan_status_cb;
167160b08185Syz 
167260b08185Syz 	rval = usb_pipe_bulk_xfer(bulkin->pipe_handle, br, 0);
167360b08185Syz 	if (rval != USB_SUCCESS) {
167460b08185Syz 		usb_free_bulk_req(br);
167560b08185Syz 	}
167660b08185Syz 	USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh,
167760b08185Syz 	    "keyspan_receive_status: rval = %d", rval);
167860b08185Syz 	return (rval);
167960b08185Syz }
168060b08185Syz 
168160b08185Syz /*
168260b08185Syz  * submit data for transfer (asynchronous)
168360b08185Syz  *
168460b08185Syz  * if data was sent successfully, 'mpp' will be nulled to indicate
168560b08185Syz  * that mblk is consumed by USBA and no longer belongs to the caller.
168660b08185Syz  *
168760b08185Syz  * if this function returns USB_SUCCESS, pipe is acquired and request
168860b08185Syz  * is sent, otherwise pipe is free.
168960b08185Syz  */
169060b08185Syz int
keyspan_send_data(keyspan_pipe_t * bulkout,mblk_t ** mpp,void * cb_arg)169160b08185Syz keyspan_send_data(keyspan_pipe_t *bulkout, mblk_t **mpp, void *cb_arg)
169260b08185Syz {
169360b08185Syz 	keyspan_state_t	*ksp = bulkout->pipe_ksp;
169460b08185Syz 	usb_bulk_req_t	*br;
169560b08185Syz 	int		rval;
169660b08185Syz 
169760b08185Syz 	ASSERT(!mutex_owned(&bulkout->pipe_mutex));
169860b08185Syz 	USB_DPRINTF_L4(DPRINT_OUT_PIPE, bulkout->pipe_lh,
169960b08185Syz 	    "keyspan_send_data");
170060b08185Syz 
170160b08185Syz 	br = usb_alloc_bulk_req(ksp->ks_dip, 0, USB_FLAGS_SLEEP);
170260b08185Syz 	br->bulk_len = MBLKL(*mpp);
170360b08185Syz 	br->bulk_data = *mpp;
170460b08185Syz 	br->bulk_timeout = KEYSPAN_BULK_TIMEOUT;
170560b08185Syz 	br->bulk_client_private = cb_arg;
170660b08185Syz 	br->bulk_attributes = USB_ATTRS_AUTOCLEARING;
170760b08185Syz 	br->bulk_cb = keyspan_bulkout_cb;
170860b08185Syz 	br->bulk_exc_cb = keyspan_bulkout_cb;
170960b08185Syz 
171060b08185Syz 	USB_DPRINTF_L3(DPRINT_OUT_PIPE, bulkout->pipe_lh, "keyspan_send_data:"
171160b08185Syz 	    "bulk_len = %d", br->bulk_len);
171260b08185Syz 
171360b08185Syz 	rval = usb_pipe_bulk_xfer(bulkout->pipe_handle, br, 0);
171460b08185Syz 	if (rval == USB_SUCCESS) {
171560b08185Syz 
171660b08185Syz 		/* data consumed. The mem will be released in bulkout_cb */
171760b08185Syz 		*mpp = NULL;
171860b08185Syz 	} else {
171960b08185Syz 
172060b08185Syz 		/*
172160b08185Syz 		 * Don't free it in usb_free_bulk_req because it will
172260b08185Syz 		 * be linked in keyspan_put_head
172360b08185Syz 		 */
172460b08185Syz 		br->bulk_data = NULL;
172560b08185Syz 
172660b08185Syz 		usb_free_bulk_req(br);
172760b08185Syz 	}
172860b08185Syz 	USB_DPRINTF_L4(DPRINT_OUT_PIPE, bulkout->pipe_lh,
172960b08185Syz 	    "keyspan_send_data: rval = %d", rval);
173060b08185Syz 
173160b08185Syz 	return (rval);
173260b08185Syz }
173302dd2108Slg 
173402dd2108Slg /*
173502dd2108Slg  * submit data for transfer (asynchronous) for USA_49WG Port0 only
173602dd2108Slg  *
173702dd2108Slg  * if data was sent successfully, 'mpp' will be nulled to indicate
173802dd2108Slg  * that mblk is consumed by USBA and no longer belongs to the caller.
173902dd2108Slg  *
174002dd2108Slg  * if this function returns USB_SUCCESS, pipe is acquired and request
174102dd2108Slg  * is sent, otherwise pipe is free.
174202dd2108Slg  */
174302dd2108Slg int
keyspan_send_data_port0(keyspan_pipe_t * introut,mblk_t ** mpp,void * cb_arg)174402dd2108Slg keyspan_send_data_port0(keyspan_pipe_t *introut, mblk_t **mpp, void *cb_arg)
174502dd2108Slg {
174602dd2108Slg 	keyspan_state_t	*ksp = introut->pipe_ksp;
174702dd2108Slg 	usb_intr_req_t	*br;
174802dd2108Slg 	int		rval;
174902dd2108Slg 
175002dd2108Slg 	ASSERT(!mutex_owned(&introut->pipe_mutex));
175102dd2108Slg 	USB_DPRINTF_L4(DPRINT_OUT_PIPE, introut->pipe_lh,
175202dd2108Slg 	    "keyspan_send_data_port0");
175302dd2108Slg 
175402dd2108Slg 	br = usb_alloc_intr_req(ksp->ks_dip, 0, USB_FLAGS_SLEEP);
175502dd2108Slg 	br->intr_len = MBLKL(*mpp);
175602dd2108Slg 	br->intr_data = *mpp;
175702dd2108Slg 	br->intr_timeout = KEYSPAN_BULK_TIMEOUT;
175802dd2108Slg 	br->intr_client_private = cb_arg;
175902dd2108Slg 	br->intr_cb = keyspan_introut_cb_usa49wg;
176002dd2108Slg 	br->intr_exc_cb = keyspan_introut_cb_usa49wg;
176102dd2108Slg 
176202dd2108Slg 	USB_DPRINTF_L3(DPRINT_OUT_PIPE, introut->pipe_lh,
176377e51571Sgongtian zhao - Sun Microsystems - Beijing China 	    "keyspan_send_data_port0: intr_len = %d",
176477e51571Sgongtian zhao - Sun Microsystems - Beijing China 	    br->intr_len);
176502dd2108Slg 
176602dd2108Slg 	rval = usb_pipe_intr_xfer(introut->pipe_handle, br, 0);
176702dd2108Slg 	if (rval == USB_SUCCESS) {
176802dd2108Slg 
176902dd2108Slg 		/*
177002dd2108Slg 		 * data consumed. The mem will be released in
177102dd2108Slg 		 * introut_cb_usa49wg
177202dd2108Slg 		 */
177302dd2108Slg 		*mpp = NULL;
177402dd2108Slg 	} else {
177502dd2108Slg 		br->intr_data = NULL;
177602dd2108Slg 
177702dd2108Slg 		usb_free_intr_req(br);
177802dd2108Slg 	}
177902dd2108Slg 	USB_DPRINTF_L4(DPRINT_OUT_PIPE, introut->pipe_lh,
178002dd2108Slg 	    "keyspan_send_data_port0: rval = %d", rval);
178102dd2108Slg 
178202dd2108Slg 	return (rval);
178302dd2108Slg }
178402dd2108Slg 
178502dd2108Slg /*
178602dd2108Slg  * pipe callbacks
178702dd2108Slg  * --------------
178802dd2108Slg  *
178902dd2108Slg  * bulk in status callback for USA_49WG model
179002dd2108Slg  */
179102dd2108Slg /*ARGSUSED*/
179202dd2108Slg void
keyspan_status_cb_usa49wg(usb_pipe_handle_t pipe,usb_intr_req_t * req)179302dd2108Slg keyspan_status_cb_usa49wg(usb_pipe_handle_t pipe, usb_intr_req_t *req)
179402dd2108Slg {
179502dd2108Slg 	keyspan_state_t	*ksp = (keyspan_state_t *)req->intr_client_private;
179602dd2108Slg 	keyspan_pipe_t	*intr = &ksp->ks_statin_pipe;
179702dd2108Slg 	mblk_t		*data = req->intr_data;
179802dd2108Slg 	uint_t		cr = req->intr_completion_reason;
179902dd2108Slg 	int		data_len;
180002dd2108Slg 
180102dd2108Slg 	data_len = (data) ? MBLKL(data) : 0;
180202dd2108Slg 
180302dd2108Slg 	USB_DPRINTF_L4(DPRINT_IN_PIPE, intr->pipe_lh,
180402dd2108Slg 	    "keyspan_status_cb_usa49wg: len=%d"
180502dd2108Slg 	    " cr=%d flags=%x", data_len, cr, req->intr_cb_flags);
180602dd2108Slg 
180702dd2108Slg 	/* put data on the read queue */
180802dd2108Slg 	if ((data_len == 11) && (cr == USB_CR_OK)) {
180902dd2108Slg 		keyspan_usa49_port_status_msg_t status_msg;
181002dd2108Slg 		keyspan_port_t *cur_kp;
181102dd2108Slg 		keyspan_usa49_port_status_msg_t *kp_status_msg;
181202dd2108Slg 		boolean_t need_cb = B_FALSE;
181302dd2108Slg 
181402dd2108Slg 		bcopy(data->b_rptr, &status_msg, data_len);
181502dd2108Slg 		if (status_msg.portNumber >= ksp->ks_dev_spec.port_cnt) {
181602dd2108Slg 
181702dd2108Slg 			return;
181802dd2108Slg 		}
181902dd2108Slg 		cur_kp = &ksp->ks_ports[status_msg.portNumber];
182002dd2108Slg 		kp_status_msg = &(cur_kp->kp_status_msg.usa49);
182102dd2108Slg 
182202dd2108Slg 		mutex_enter(&cur_kp->kp_mutex);
182302dd2108Slg 
182402dd2108Slg 		/* if msr status changed, then need invoke status callback */
182502dd2108Slg 		if (status_msg.cts !=  kp_status_msg->cts ||
182602dd2108Slg 		    status_msg.dsr != kp_status_msg->dsr ||
182702dd2108Slg 		    status_msg.ri != kp_status_msg->ri ||
182802dd2108Slg 		    status_msg.dcd != kp_status_msg->dcd) {
182902dd2108Slg 
183002dd2108Slg 			need_cb = B_TRUE;
183102dd2108Slg 		}
183202dd2108Slg 
183302dd2108Slg 		bcopy(&status_msg, kp_status_msg, data_len);
183402dd2108Slg 
183502dd2108Slg 		if (kp_status_msg->controlResponse) {
183602dd2108Slg 			cur_kp->kp_status_flag |= KEYSPAN_PORT_CTRLRESP;
183702dd2108Slg 		} else {
183802dd2108Slg 			cur_kp->kp_status_flag &= ~KEYSPAN_PORT_CTRLRESP;
183902dd2108Slg 		}
184002dd2108Slg 
184102dd2108Slg 		if (!kp_status_msg->rxEnabled) {
184202dd2108Slg 			cur_kp->kp_status_flag |= KEYSPAN_PORT_RXBREAK;
184302dd2108Slg 		} else {
184402dd2108Slg 			cur_kp->kp_status_flag &= ~KEYSPAN_PORT_RXBREAK;
184502dd2108Slg 		}
184602dd2108Slg 
184702dd2108Slg 		mutex_exit(&cur_kp->kp_mutex);
184802dd2108Slg 
184902dd2108Slg 		if (need_cb) {
185002dd2108Slg 
185102dd2108Slg 			cur_kp->kp_cb.cb_status(cur_kp->kp_cb.cb_arg);
185202dd2108Slg 		}
185302dd2108Slg 	} else {
185402dd2108Slg 
185502dd2108Slg 		USB_DPRINTF_L2(DPRINT_IN_PIPE, intr->pipe_lh,
185602dd2108Slg 		    "keyspan_status_cb_usa49wg: get status failed, cr=%d"
185702dd2108Slg 		    " data_len=%d", cr, data_len);
185802dd2108Slg 	}
185902dd2108Slg }
186002dd2108Slg 
186102dd2108Slg /*
186202dd2108Slg  * pipe callbacks
186302dd2108Slg  * --------------
186402dd2108Slg  *
186502dd2108Slg  * intr in callback for status receiving for USA_49WG model only
186602dd2108Slg  */
186702dd2108Slg /*ARGSUSED*/
186802dd2108Slg void
keyspan_intr_cb_usa49wg(usb_pipe_handle_t pipe,usb_intr_req_t * req)186902dd2108Slg keyspan_intr_cb_usa49wg(usb_pipe_handle_t pipe, usb_intr_req_t *req)
187002dd2108Slg {
187102dd2108Slg 	keyspan_state_t	*ksp = (keyspan_state_t *)req->intr_client_private;
187202dd2108Slg 	usb_cr_t	cr = req->intr_completion_reason;
187302dd2108Slg 
187402dd2108Slg 	USB_DPRINTF_L4(DPRINT_IN_PIPE, (&ksp->ks_statin_pipe)->pipe_lh,
187502dd2108Slg 	    "keyspan_intr_cb_usa49wg: cr=%d", cr);
187602dd2108Slg 
187702dd2108Slg 	/* put data on the read queue */
187802dd2108Slg 	(void) keyspan_status_cb_usa49wg(pipe, req);
187902dd2108Slg 
188002dd2108Slg 	usb_free_intr_req(req);
188102dd2108Slg }
188202dd2108Slg 
188302dd2108Slg /*
188402dd2108Slg  * pipe callbacks
188502dd2108Slg  * --------------
188602dd2108Slg  *
188702dd2108Slg  * intr in exception callback for status receiving for USA_49WG model only
188802dd2108Slg  */
188902dd2108Slg /*ARGSUSED*/
189002dd2108Slg void
keyspan_intr_ex_cb_usa49wg(usb_pipe_handle_t pipe,usb_intr_req_t * req)189102dd2108Slg keyspan_intr_ex_cb_usa49wg(usb_pipe_handle_t pipe, usb_intr_req_t *req)
189202dd2108Slg {
189302dd2108Slg 	keyspan_state_t	*ksp = (keyspan_state_t *)req->intr_client_private;
189402dd2108Slg 	usb_cr_t	cr = req->intr_completion_reason;
189502dd2108Slg 
189602dd2108Slg 	USB_DPRINTF_L4(DPRINT_IN_PIPE, (&ksp->ks_statin_pipe)->pipe_lh,
189702dd2108Slg 	    "keyspan_intr_ex_cb_usa49wg: cr=%d", cr);
189802dd2108Slg 
189902dd2108Slg 	usb_free_intr_req(req);
190002dd2108Slg 
190102dd2108Slg 	if ((cr != USB_CR_PIPE_CLOSING) && (cr != USB_CR_STOPPED_POLLING) &&
190277e51571Sgongtian zhao - Sun Microsystems - Beijing China 	    (cr != USB_CR_FLUSHED) && (cr != USB_CR_DEV_NOT_RESP) &&
190377e51571Sgongtian zhao - Sun Microsystems - Beijing China 	    (cr != USB_CR_PIPE_RESET) && keyspan_dev_is_online(ksp)) {
190402dd2108Slg 		keyspan_pipe_start_polling(&ksp->ks_statin_pipe);
190502dd2108Slg 	} else {
190602dd2108Slg 		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:"
190977e51571Sgongtian zhao - Sun Microsystems - Beijing China 		    "get status failed: cr=%d", cr);
191002dd2108Slg 	}
191102dd2108Slg }
191202dd2108Slg 
191302dd2108Slg /*
191402dd2108Slg  * start polling on the interrupt pipe for USA_49WG model only
191502dd2108Slg  */
191602dd2108Slg void
keyspan_pipe_start_polling(keyspan_pipe_t * intr)191702dd2108Slg keyspan_pipe_start_polling(keyspan_pipe_t *intr)
191802dd2108Slg {
191902dd2108Slg 	usb_intr_req_t	*br;
192002dd2108Slg 	keyspan_state_t	*ksp = intr->pipe_ksp;
192102dd2108Slg 	int		rval;
192202dd2108Slg 
192302dd2108Slg 	USB_DPRINTF_L4(DPRINT_IN_PIPE, ksp->ks_lh,
192477e51571Sgongtian zhao - Sun Microsystems - Beijing China 	    "keyspan_pipe_start_polling");
192502dd2108Slg 
192602dd2108Slg 	br = usb_alloc_intr_req(ksp->ks_dip, 0, USB_FLAGS_SLEEP);
192702dd2108Slg 
192802dd2108Slg 	/*
192902dd2108Slg 	 * If it is in interrupt context, usb_alloc_intr_req will return NULL if
193002dd2108Slg 	 * called with SLEEP flag.
193102dd2108Slg 	 */
193202dd2108Slg 	if (!br) {
193302dd2108Slg 		USB_DPRINTF_L2(DPRINT_IN_PIPE, ksp->ks_lh,
193402dd2108Slg 		    "keyspan_pipe_start_polling: alloc req failed.");
193502dd2108Slg 
193602dd2108Slg 		return;
193702dd2108Slg 	}
193802dd2108Slg 	br->intr_attributes = USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING;
193902dd2108Slg 	br->intr_len = intr->pipe_ep_descr.wMaxPacketSize;
194002dd2108Slg 	br->intr_client_private = (void *)ksp;
194102dd2108Slg 
194202dd2108Slg 	br->intr_cb = keyspan_intr_cb_usa49wg;
194302dd2108Slg 	br->intr_exc_cb = keyspan_intr_ex_cb_usa49wg;
194402dd2108Slg 
194502dd2108Slg 
194602dd2108Slg 	rval = usb_pipe_intr_xfer(intr->pipe_handle, br, USB_FLAGS_SLEEP);
194702dd2108Slg 
194802dd2108Slg 	mutex_enter(&intr->pipe_mutex);
194902dd2108Slg 	if (rval != USB_SUCCESS) {
195002dd2108Slg 		usb_free_intr_req(br);
195102dd2108Slg 		intr->pipe_state = KEYSPAN_PIPE_CLOSED;
195202dd2108Slg 
195302dd2108Slg 		USB_DPRINTF_L3(DPRINT_IN_PIPE, ksp->ks_lh,
195402dd2108Slg 		    "keyspan_pipe_start_polling: failed (%d)", rval);
195502dd2108Slg 	} else {
195602dd2108Slg 		intr->pipe_state = KEYSPAN_PIPE_OPEN;
195702dd2108Slg 	}
195802dd2108Slg 
195902dd2108Slg 	mutex_exit(&intr->pipe_mutex);
196002dd2108Slg }
1961