xref: /illumos-gate/usr/src/uts/common/io/usb/clients/usbser/usbser_keyspan/keyspan_pipe.c (revision 688b07c52de0fc886cce2e0a28a42a43d2dad06a)
160b08185Syz147069 /*
260b08185Syz147069  * CDDL HEADER START
360b08185Syz147069  *
460b08185Syz147069  * The contents of this file are subject to the terms of the
5*688b07c5Sgc161489  * Common Development and Distribution License (the "License").
6*688b07c5Sgc161489  * You may not use this file except in compliance with the License.
760b08185Syz147069  *
860b08185Syz147069  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
960b08185Syz147069  * or http://www.opensolaris.org/os/licensing.
1060b08185Syz147069  * See the License for the specific language governing permissions
1160b08185Syz147069  * and limitations under the License.
1260b08185Syz147069  *
1360b08185Syz147069  * When distributing Covered Code, include this CDDL HEADER in each
1460b08185Syz147069  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1560b08185Syz147069  * If applicable, add the following below this CDDL HEADER, with the
1660b08185Syz147069  * fields enclosed by brackets "[]" replaced with your own identifying
1760b08185Syz147069  * information: Portions Copyright [yyyy] [name of copyright owner]
1860b08185Syz147069  *
1960b08185Syz147069  * CDDL HEADER END
2060b08185Syz147069  */
2160b08185Syz147069 /*
22*688b07c5Sgc161489  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
2360b08185Syz147069  * Use is subject to license terms.
2460b08185Syz147069  */
2560b08185Syz147069 
2660b08185Syz147069 #pragma ident	"%Z%%M%	%I%	%E% SMI"
2760b08185Syz147069 
2860b08185Syz147069 /*
2960b08185Syz147069  *
3060b08185Syz147069  * keyspanport pipe routines (mostly device-neutral)
3160b08185Syz147069  *
3260b08185Syz147069  */
3360b08185Syz147069 #include <sys/types.h>
3460b08185Syz147069 #include <sys/param.h>
3560b08185Syz147069 #include <sys/conf.h>
3660b08185Syz147069 #include <sys/stream.h>
3760b08185Syz147069 #include <sys/strsun.h>
3860b08185Syz147069 #include <sys/termio.h>
3960b08185Syz147069 #include <sys/ddi.h>
4060b08185Syz147069 #include <sys/sunddi.h>
4160b08185Syz147069 
4260b08185Syz147069 #include <sys/usb/usba.h>
4360b08185Syz147069 #include <sys/usb/clients/usbser/usbser_keyspan/keyspan_var.h>
4460b08185Syz147069 #include <sys/usb/clients/usbser/usbser_keyspan/keyspan_pipe.h>
4560b08185Syz147069 
4660b08185Syz147069 /*
4760b08185Syz147069  * initialize pipe structure with the given parameters
4860b08185Syz147069  */
4960b08185Syz147069 static void
5060b08185Syz147069 keyspan_init_one_pipe(keyspan_state_t *ksp, keyspan_port_t *kp,
5160b08185Syz147069     keyspan_pipe_t *pipe)
5260b08185Syz147069 {
5360b08185Syz147069 	usb_pipe_policy_t	*policy;
5460b08185Syz147069 
5560b08185Syz147069 	USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, "keyspan_init_one_pipe: "
5660b08185Syz147069 	    "pipe = %p, pipe_stat %x", (void *)pipe, pipe->pipe_state);
5760b08185Syz147069 
5860b08185Syz147069 	/* init sync primitives */
5960b08185Syz147069 	mutex_init(&pipe->pipe_mutex, NULL, MUTEX_DRIVER, (void *)NULL);
6060b08185Syz147069 
6160b08185Syz147069 	/* init pipe policy */
6260b08185Syz147069 	policy = &pipe->pipe_policy;
6360b08185Syz147069 	policy->pp_max_async_reqs = 2;
6460b08185Syz147069 
6560b08185Syz147069 	pipe->pipe_ksp = ksp;
6660b08185Syz147069 	if (kp == NULL) {
6760b08185Syz147069 		/* globle pipes should have device log handle */
6860b08185Syz147069 		pipe->pipe_lh = ksp->ks_lh;
6960b08185Syz147069 	} else {
7060b08185Syz147069 		/* port pipes should have port log handle */
7160b08185Syz147069 		pipe->pipe_lh = kp->kp_lh;
7260b08185Syz147069 	}
7360b08185Syz147069 
7460b08185Syz147069 	pipe->pipe_state = KEYSPAN_PIPE_CLOSED;
7560b08185Syz147069 }
7660b08185Syz147069 
7760b08185Syz147069 
7860b08185Syz147069 static void
7960b08185Syz147069 keyspan_fini_one_pipe(keyspan_pipe_t *pipe)
8060b08185Syz147069 {
8160b08185Syz147069 	USB_DPRINTF_L4(DPRINT_OPEN, pipe->pipe_ksp->ks_lh,
8260b08185Syz147069 	    "keyspan_fini_one_pipe: pipe_stat %x", pipe->pipe_state);
8360b08185Syz147069 
8460b08185Syz147069 	if (pipe->pipe_state != KEYSPAN_PIPE_NOT_INIT) {
8560b08185Syz147069 		mutex_destroy(&pipe->pipe_mutex);
8660b08185Syz147069 		pipe->pipe_state = KEYSPAN_PIPE_NOT_INIT;
8760b08185Syz147069 	}
8860b08185Syz147069 }
8960b08185Syz147069 
9060b08185Syz147069 /*
9160b08185Syz147069  * Lookup the endpoints defined in the spec;
9260b08185Syz147069  * Allocate resources, initialize pipe structures.
9360b08185Syz147069  * All are bulk pipes, including data in/out, cmd/status pipes.
9460b08185Syz147069  */
9560b08185Syz147069 int
9660b08185Syz147069 keyspan_init_pipes(keyspan_state_t *ksp)
9760b08185Syz147069 {
9860b08185Syz147069 	usb_client_dev_data_t *dev_data = ksp->ks_dev_data;
9960b08185Syz147069 	int		ifc, alt, i, j, k = 0;
10060b08185Syz147069 	uint8_t		port_cnt = ksp->ks_dev_spec.port_cnt;
10160b08185Syz147069 	uint8_t		ep_addr, ep_cnt;
10260b08185Syz147069 	usb_ep_data_t	*dataout[KEYSPAN_MAX_PORT_NUM],
10360b08185Syz147069 			*datain[KEYSPAN_MAX_PORT_NUM],
10460b08185Syz147069 			*status = NULL, *ctrl = NULL, *tmp_ep;
10560b08185Syz147069 	usb_alt_if_data_t *alt_data;
10660b08185Syz147069 	usb_if_data_t *if_data;
10760b08185Syz147069 
10860b08185Syz147069 
10960b08185Syz147069 	ifc = dev_data->dev_curr_if;
11060b08185Syz147069 	alt = 0;
11160b08185Syz147069 	if_data = &dev_data->dev_curr_cfg->cfg_if[ifc];
11260b08185Syz147069 	alt_data = &if_data->if_alt[alt];
11360b08185Syz147069 
11460b08185Syz147069 	/*
11560b08185Syz147069 	 * The actual EP number (indicated by bNumEndpoints) is more than
11660b08185Syz147069 	 * those defined in spec. We have to match those we need according
11760b08185Syz147069 	 * to EP addresses. And we'll lookup In EPs and Out EPs separately.
11860b08185Syz147069 	 */
11960b08185Syz147069 	ep_cnt = (alt_data->altif_descr.bNumEndpoints + 1) / 2;
12060b08185Syz147069 
12160b08185Syz147069 	/*
12260b08185Syz147069 	 * get DIR_IN EP descriptors, and then match with EP addresses.
12360b08185Syz147069 	 * Different keyspan devices may has different EP addresses.
12460b08185Syz147069 	 */
12560b08185Syz147069 	for (i = 0; i < ep_cnt; i++) {
12660b08185Syz147069 		tmp_ep = usb_lookup_ep_data(ksp->ks_dip, dev_data, ifc, alt, i,
12760b08185Syz147069 			    USB_EP_ATTR_BULK, USB_EP_DIR_IN);
12860b08185Syz147069 		if (tmp_ep == NULL) {
12960b08185Syz147069 			USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh,
13060b08185Syz147069 			    "keyspan_init_pipes: can't find bulk in ep, i=%d,"
13160b08185Syz147069 			    "ep_cnt=%d", i, ep_cnt);
13260b08185Syz147069 
13360b08185Syz147069 			continue;
13460b08185Syz147069 		}
13560b08185Syz147069 		ep_addr = tmp_ep->ep_descr.bEndpointAddress;
13660b08185Syz147069 
13760b08185Syz147069 		USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh, "keyspan_init_pipes: "
13860b08185Syz147069 		    "ep_addr =%x, stat_ep_addr=%x, i=%d", ep_addr,
13960b08185Syz147069 		    ksp->ks_dev_spec.stat_ep_addr, i);
14060b08185Syz147069 
14160b08185Syz147069 		/* match the status EP */
14260b08185Syz147069 		if (ep_addr == ksp->ks_dev_spec.stat_ep_addr) {
14360b08185Syz147069 			status = tmp_ep;
14460b08185Syz147069 
14560b08185Syz147069 			continue;
14660b08185Syz147069 		}
14760b08185Syz147069 
14860b08185Syz147069 		/* match the EPs of the ports */
14960b08185Syz147069 		for (j = 0; j < port_cnt; j++) {
15060b08185Syz147069 			USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh,
15160b08185Syz147069 			    "keyspan_init_pipes: try to match bulk in data ep,"
15260b08185Syz147069 			    " j=%d", j);
15360b08185Syz147069 			if (ep_addr == ksp->ks_dev_spec.datain_ep_addr[j]) {
15460b08185Syz147069 				datain[j] = tmp_ep;
15560b08185Syz147069 				k++;
15660b08185Syz147069 				USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh,
15760b08185Syz147069 				    "keyspan_init_pipes: matched a bulk in"
15860b08185Syz147069 				    " data ep");
15960b08185Syz147069 
16060b08185Syz147069 				break;
16160b08185Syz147069 			}
16260b08185Syz147069 		}
16360b08185Syz147069 
16460b08185Syz147069 		/* if have matched all the necessary endpoints, break out */
16560b08185Syz147069 		if (k >= port_cnt && status != NULL) {
16660b08185Syz147069 
16760b08185Syz147069 			break;
16860b08185Syz147069 		}
16960b08185Syz147069 
17060b08185Syz147069 		USB_DPRINTF_L4(DPRINT_ATTACH, ksp->ks_lh, "keyspan_init_pipes: "
17160b08185Syz147069 		    "try to match bulk in data ep, j=%d", j);
17260b08185Syz147069 
17360b08185Syz147069 		if (j == port_cnt) {
17460b08185Syz147069 			/* this ep can't be matched by any addr */
17560b08185Syz147069 			USB_DPRINTF_L4(DPRINT_ATTACH, ksp->ks_lh,
17660b08185Syz147069 			    "keyspan_init_pipes: can't match bulk in ep,"
17760b08185Syz147069 			    " addr =%x,", ep_addr);
17860b08185Syz147069 		}
17960b08185Syz147069 	}
18060b08185Syz147069 
18160b08185Syz147069 	if (k != port_cnt || status == NULL) {
18260b08185Syz147069 
18360b08185Syz147069 		/* Some of the necessary IN endpoints are not matched */
18460b08185Syz147069 		USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
18560b08185Syz147069 		    "keyspan_init_pipes: matched %d data in endpoints,"
18660b08185Syz147069 		    " not enough", k);
18760b08185Syz147069 
18860b08185Syz147069 		return (USB_FAILURE);
18960b08185Syz147069 	}
19060b08185Syz147069 
19160b08185Syz147069 	k = 0;
19260b08185Syz147069 
19360b08185Syz147069 	/*
19460b08185Syz147069 	 * get DIR_OUT EP descriptors, and then match with ep addrs.
19560b08185Syz147069 	 * different keyspan devices may has different ep addresses.
19660b08185Syz147069 	 */
19760b08185Syz147069 	for (i = 0; i < ep_cnt; i++) {
19860b08185Syz147069 		tmp_ep = usb_lookup_ep_data(ksp->ks_dip, dev_data, ifc, alt, i,
19960b08185Syz147069 			    USB_EP_ATTR_BULK, USB_EP_DIR_OUT);
20060b08185Syz147069 		if (tmp_ep == NULL) {
20160b08185Syz147069 			USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh,
20260b08185Syz147069 			    "keyspan_init_pipes: can't find bulk out ep, i=%d,"
20360b08185Syz147069 			    "ep_cnt=%d", i, ep_cnt);
20460b08185Syz147069 
20560b08185Syz147069 			continue;
20660b08185Syz147069 		}
20760b08185Syz147069 		ep_addr = tmp_ep->ep_descr.bEndpointAddress;
20860b08185Syz147069 
20960b08185Syz147069 		/* match the status ep */
21060b08185Syz147069 		if (ep_addr == ksp->ks_dev_spec.ctrl_ep_addr) {
21160b08185Syz147069 			ctrl = tmp_ep;
21260b08185Syz147069 
21360b08185Syz147069 			continue;
21460b08185Syz147069 		}
21560b08185Syz147069 
21660b08185Syz147069 		/* match the ep of the ports */
21760b08185Syz147069 		for (j = 0; j < port_cnt; j++) {
21860b08185Syz147069 			if (ep_addr == ksp->ks_dev_spec.dataout_ep_addr[j]) {
21960b08185Syz147069 				dataout[j] = tmp_ep;
22060b08185Syz147069 				k++;
22160b08185Syz147069 
22260b08185Syz147069 				break;
22360b08185Syz147069 			}
22460b08185Syz147069 		}
22560b08185Syz147069 		/* if have matched all the necessary endpoints, break out */
22660b08185Syz147069 		if (k >= port_cnt && ctrl != NULL) {
22760b08185Syz147069 
22860b08185Syz147069 			break;
22960b08185Syz147069 		}
23060b08185Syz147069 
23160b08185Syz147069 		if (j == port_cnt) {
23260b08185Syz147069 
23360b08185Syz147069 			/* this ep can't be matched by any addr */
23460b08185Syz147069 			USB_DPRINTF_L4(DPRINT_ATTACH, ksp->ks_lh,
23560b08185Syz147069 			    "keyspan_init_pipes: can't match bulk out ep,"
23660b08185Syz147069 			    " ep_addr =%x", ep_addr);
23760b08185Syz147069 
23860b08185Syz147069 		}
23960b08185Syz147069 	}
24060b08185Syz147069 
24160b08185Syz147069 	if (k != port_cnt || ctrl == NULL) {
24260b08185Syz147069 		/* Not all the necessary OUT endpoints are matched */
24360b08185Syz147069 		USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
24460b08185Syz147069 		    "keyspan_init_pipes: matched %d data in endpoints,"
24560b08185Syz147069 		    " not enough", k);
24660b08185Syz147069 
24760b08185Syz147069 		return (USB_FAILURE);
24860b08185Syz147069 	}
24960b08185Syz147069 
25060b08185Syz147069 	mutex_enter(&ksp->ks_mutex);
25160b08185Syz147069 
25260b08185Syz147069 	/*
25360b08185Syz147069 	 * Device globle pipes: a bulk in pipe for status and a bulk out
25460b08185Syz147069 	 * pipe for controle cmd.
25560b08185Syz147069 	 */
25660b08185Syz147069 	ksp->ks_statin_pipe.pipe_ep_descr = status->ep_descr;
25760b08185Syz147069 	keyspan_init_one_pipe(ksp, NULL, &ksp->ks_statin_pipe);
25860b08185Syz147069 
25960b08185Syz147069 	ksp->ks_ctrlout_pipe.pipe_ep_descr = ctrl->ep_descr;
26060b08185Syz147069 	keyspan_init_one_pipe(ksp, NULL, &ksp->ks_ctrlout_pipe);
26160b08185Syz147069 
26260b08185Syz147069 	/* for data in/out pipes of each port */
26360b08185Syz147069 	for (i = 0; i < port_cnt; i++) {
26460b08185Syz147069 
26560b08185Syz147069 		ksp->ks_ports[i].kp_datain_pipe.pipe_ep_descr =
26660b08185Syz147069 		    datain[i]->ep_descr;
26760b08185Syz147069 		keyspan_init_one_pipe(ksp, &ksp->ks_ports[i],
26860b08185Syz147069 		    &ksp->ks_ports[i].kp_datain_pipe);
26960b08185Syz147069 
27060b08185Syz147069 		ksp->ks_ports[i].kp_dataout_pipe.pipe_ep_descr =
27160b08185Syz147069 		    dataout[i]->ep_descr;
27260b08185Syz147069 		keyspan_init_one_pipe(ksp, &ksp->ks_ports[i],
27360b08185Syz147069 		    &ksp->ks_ports[i].kp_dataout_pipe);
27460b08185Syz147069 	}
27560b08185Syz147069 
27660b08185Syz147069 	mutex_exit(&ksp->ks_mutex);
27760b08185Syz147069 
27860b08185Syz147069 	return (USB_SUCCESS);
27960b08185Syz147069 }
28060b08185Syz147069 
28160b08185Syz147069 void
28260b08185Syz147069 keyspan_fini_pipes(keyspan_state_t *ksp)
28360b08185Syz147069 {
28460b08185Syz147069 	keyspan_port_t	*kp;
28560b08185Syz147069 	int		i;
28660b08185Syz147069 
28760b08185Syz147069 	for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) {
28860b08185Syz147069 		kp = &ksp->ks_ports[i];
28960b08185Syz147069 		keyspan_fini_one_pipe(&kp->kp_datain_pipe);
29060b08185Syz147069 		keyspan_fini_one_pipe(&kp->kp_dataout_pipe);
29160b08185Syz147069 	}
29260b08185Syz147069 
29360b08185Syz147069 	/* fini global pipes */
29460b08185Syz147069 	keyspan_fini_one_pipe(&ksp->ks_statin_pipe);
29560b08185Syz147069 	keyspan_fini_one_pipe(&ksp->ks_ctrlout_pipe);
29660b08185Syz147069 }
29760b08185Syz147069 
29860b08185Syz147069 
29960b08185Syz147069 static int
30060b08185Syz147069 keyspan_open_one_pipe(keyspan_state_t *ksp, keyspan_pipe_t *pipe)
30160b08185Syz147069 {
30260b08185Syz147069 	int	rval;
30360b08185Syz147069 
30460b08185Syz147069 	/* don't open for the second time */
30560b08185Syz147069 	mutex_enter(&pipe->pipe_mutex);
30660b08185Syz147069 	ASSERT(pipe->pipe_state != KEYSPAN_PIPE_NOT_INIT);
30760b08185Syz147069 	if (pipe->pipe_state != KEYSPAN_PIPE_CLOSED) {
30860b08185Syz147069 		mutex_exit(&pipe->pipe_mutex);
30960b08185Syz147069 
31060b08185Syz147069 		return (USB_SUCCESS);
31160b08185Syz147069 	}
31260b08185Syz147069 	mutex_exit(&pipe->pipe_mutex);
31360b08185Syz147069 
31460b08185Syz147069 	rval = usb_pipe_open(ksp->ks_dip, &pipe->pipe_ep_descr,
31560b08185Syz147069 	    &pipe->pipe_policy, USB_FLAGS_SLEEP, &pipe->pipe_handle);
31660b08185Syz147069 
31760b08185Syz147069 	if (rval == USB_SUCCESS) {
31860b08185Syz147069 		mutex_enter(&pipe->pipe_mutex);
31960b08185Syz147069 		pipe->pipe_state = KEYSPAN_PIPE_OPEN;
32060b08185Syz147069 		mutex_exit(&pipe->pipe_mutex);
32160b08185Syz147069 	}
32260b08185Syz147069 
32360b08185Syz147069 	return (rval);
32460b08185Syz147069 }
32560b08185Syz147069 
32660b08185Syz147069 
32760b08185Syz147069 /*
32860b08185Syz147069  * close one pipe if open
32960b08185Syz147069  */
33060b08185Syz147069 static void
33160b08185Syz147069 keyspan_close_one_pipe(keyspan_pipe_t *pipe)
33260b08185Syz147069 {
33360b08185Syz147069 	/*
33460b08185Syz147069 	 * pipe may already be closed, e.g. if device has been physically
33560b08185Syz147069 	 * disconnected and the driver immediately detached
33660b08185Syz147069 	 */
33760b08185Syz147069 	if (pipe->pipe_handle != NULL) {
33860b08185Syz147069 		usb_pipe_close(pipe->pipe_ksp->ks_dip, pipe->pipe_handle,
33960b08185Syz147069 				USB_FLAGS_SLEEP, NULL, NULL);
34060b08185Syz147069 		mutex_enter(&pipe->pipe_mutex);
34160b08185Syz147069 		pipe->pipe_handle = NULL;
34260b08185Syz147069 		pipe->pipe_state = KEYSPAN_PIPE_CLOSED;
34360b08185Syz147069 		mutex_exit(&pipe->pipe_mutex);
34460b08185Syz147069 	}
34560b08185Syz147069 }
34660b08185Syz147069 
34760b08185Syz147069 /*
34860b08185Syz147069  * Open global pipes, a status pipe and a control pipe
34960b08185Syz147069  */
35060b08185Syz147069 int
35160b08185Syz147069 keyspan_open_dev_pipes(keyspan_state_t *ksp)
35260b08185Syz147069 {
35360b08185Syz147069 	int		rval;
35460b08185Syz147069 
35560b08185Syz147069 	USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, "keyspan_open_dev_pipes");
35660b08185Syz147069 
35760b08185Syz147069 	rval = keyspan_open_one_pipe(ksp, &ksp->ks_ctrlout_pipe);
35860b08185Syz147069 	if (rval != USB_SUCCESS) {
35960b08185Syz147069 		USB_DPRINTF_L2(DPRINT_OPEN, ksp->ks_lh,
36060b08185Syz147069 		    "keyspan_open_dev_pipes: open ctrl pipe failed %d", rval);
36160b08185Syz147069 
36260b08185Syz147069 		return (rval);
36360b08185Syz147069 	}
36460b08185Syz147069 
36560b08185Syz147069 	rval = keyspan_open_one_pipe(ksp, &ksp->ks_statin_pipe);
36660b08185Syz147069 	if (rval != USB_SUCCESS) {
36760b08185Syz147069 		USB_DPRINTF_L2(DPRINT_OPEN, ksp->ks_lh,
36860b08185Syz147069 		    "keyspan_open_dev_pipes: open status pipe failed %d", rval);
36960b08185Syz147069 
37060b08185Syz147069 		/* close the first opened pipe here */
37160b08185Syz147069 		keyspan_close_one_pipe(&ksp->ks_ctrlout_pipe);
37260b08185Syz147069 
37360b08185Syz147069 		return (rval);
37460b08185Syz147069 	}
37560b08185Syz147069 
37660b08185Syz147069 	/* start receive device status */
37760b08185Syz147069 	rval = keyspan_receive_status(ksp);
37860b08185Syz147069 	if (rval != USB_SUCCESS) {
37960b08185Syz147069 		USB_DPRINTF_L2(DPRINT_OPEN, ksp->ks_lh,
38060b08185Syz147069 		    "keyspan_open_dev_pipes: receive device status failed %d",
38160b08185Syz147069 		    rval);
38260b08185Syz147069 
38360b08185Syz147069 		/* close opened pipes here */
38460b08185Syz147069 		keyspan_close_one_pipe(&ksp->ks_statin_pipe);
38560b08185Syz147069 		keyspan_close_one_pipe(&ksp->ks_ctrlout_pipe);
38660b08185Syz147069 
38760b08185Syz147069 		return (rval);
38860b08185Syz147069 	}
38960b08185Syz147069 
39060b08185Syz147069 	return (rval);
39160b08185Syz147069 }
39260b08185Syz147069 
39360b08185Syz147069 
39460b08185Syz147069 /*
39560b08185Syz147069  * Reopen all pipes if the port had them open
39660b08185Syz147069  */
39760b08185Syz147069 int
39860b08185Syz147069 keyspan_reopen_pipes(keyspan_state_t *ksp)
39960b08185Syz147069 {
40060b08185Syz147069 	keyspan_port_t	*kp;
40160b08185Syz147069 	int		i;
40260b08185Syz147069 
40360b08185Syz147069 	USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, "keyspan_reopen_pipes");
40460b08185Syz147069 
40560b08185Syz147069 	if (keyspan_open_dev_pipes(ksp) != USB_SUCCESS) {
40660b08185Syz147069 
40760b08185Syz147069 		return (USB_FAILURE);
40860b08185Syz147069 	}
40960b08185Syz147069 
41060b08185Syz147069 	for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) {
41160b08185Syz147069 		kp = &ksp->ks_ports[i];
41260b08185Syz147069 		mutex_enter(&kp->kp_mutex);
41360b08185Syz147069 		if (kp->kp_state == KEYSPAN_PORT_OPEN) {
41460b08185Syz147069 			USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh,
41560b08185Syz147069 			    "keyspan_reopen_pipes() reopen pipe #%d", i);
41660b08185Syz147069 			mutex_exit(&kp->kp_mutex);
41760b08185Syz147069 			if (keyspan_open_port_pipes(kp) != USB_SUCCESS) {
41860b08185Syz147069 
41960b08185Syz147069 				return (USB_FAILURE);
42060b08185Syz147069 			}
42160b08185Syz147069 			mutex_enter(&kp->kp_mutex);
42260b08185Syz147069 			kp->kp_no_more_reads = B_FALSE;
42360b08185Syz147069 		}
42460b08185Syz147069 		mutex_exit(&kp->kp_mutex);
42560b08185Syz147069 	}
42660b08185Syz147069 
42760b08185Syz147069 	return (USB_SUCCESS);
42860b08185Syz147069 }
42960b08185Syz147069 
43060b08185Syz147069 void
43160b08185Syz147069 keyspan_close_port_pipes(keyspan_port_t *kp)
43260b08185Syz147069 {
43360b08185Syz147069 	USB_DPRINTF_L4(DPRINT_CLOSE, kp->kp_lh, "keyspan_close_port_pipes");
43460b08185Syz147069 
43560b08185Syz147069 	keyspan_close_one_pipe(&kp->kp_dataout_pipe);
43660b08185Syz147069 	keyspan_close_one_pipe(&kp->kp_datain_pipe);
43760b08185Syz147069 }
43860b08185Syz147069 
43960b08185Syz147069 /*
44060b08185Syz147069  * Close IN and OUT bulk pipes of all ports
44160b08185Syz147069  */
44260b08185Syz147069 void
44360b08185Syz147069 keyspan_close_open_pipes(keyspan_state_t *ksp)
44460b08185Syz147069 {
44560b08185Syz147069 	keyspan_port_t	*kp;
44660b08185Syz147069 	int		i;
44760b08185Syz147069 
44860b08185Syz147069 	USB_DPRINTF_L4(DPRINT_CLOSE, ksp->ks_lh, "keyspan_close_open_pipes");
44960b08185Syz147069 
45060b08185Syz147069 	for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) {
45160b08185Syz147069 		kp = &ksp->ks_ports[i];
45260b08185Syz147069 		mutex_enter(&kp->kp_mutex);
45360b08185Syz147069 		if (kp->kp_state == KEYSPAN_PORT_OPEN) {
45460b08185Syz147069 			kp->kp_no_more_reads = B_TRUE;
45560b08185Syz147069 			mutex_exit(&kp->kp_mutex);
45660b08185Syz147069 			usb_pipe_reset(ksp->ks_dip,
45760b08185Syz147069 			    kp->kp_datain_pipe.pipe_handle, USB_FLAGS_SLEEP,
45860b08185Syz147069 			    NULL, NULL);
45960b08185Syz147069 			keyspan_close_port_pipes(kp);
46060b08185Syz147069 		} else {
46160b08185Syz147069 			mutex_exit(&kp->kp_mutex);
46260b08185Syz147069 		}
46360b08185Syz147069 	}
46460b08185Syz147069 }
46560b08185Syz147069 
46660b08185Syz147069 
46760b08185Syz147069 /*
46860b08185Syz147069  * Close global pipes
46960b08185Syz147069  */
47060b08185Syz147069 void
47160b08185Syz147069 keyspan_close_dev_pipes(keyspan_state_t *ksp)
47260b08185Syz147069 {
47360b08185Syz147069 	USB_DPRINTF_L4(DPRINT_CLOSE, ksp->ks_lh, "keyspan_close_dev_pipes");
47460b08185Syz147069 
47560b08185Syz147069 	keyspan_close_one_pipe(&ksp->ks_statin_pipe);
47660b08185Syz147069 	keyspan_close_one_pipe(&ksp->ks_ctrlout_pipe);
47760b08185Syz147069 }
47860b08185Syz147069 
47960b08185Syz147069 
48060b08185Syz147069 /*
48160b08185Syz147069  * Open bulk data IN and data OUT pipes for one port.
48260b08185Syz147069  * The status and control pipes are opened in attach because they are global.
48360b08185Syz147069  */
48460b08185Syz147069 int
48560b08185Syz147069 keyspan_open_port_pipes(keyspan_port_t *kp)
48660b08185Syz147069 {
48760b08185Syz147069 	keyspan_state_t	*ksp = kp->kp_ksp;
48860b08185Syz147069 	int		rval;
48960b08185Syz147069 
49060b08185Syz147069 	USB_DPRINTF_L4(DPRINT_OPEN, kp->kp_lh, "keyspan_open_port_pipes");
49160b08185Syz147069 
49260b08185Syz147069 	rval = keyspan_open_one_pipe(ksp, &kp->kp_datain_pipe);
49360b08185Syz147069 	if (rval != USB_SUCCESS) {
49460b08185Syz147069 
49560b08185Syz147069 		goto fail;
49660b08185Syz147069 	}
49760b08185Syz147069 
49860b08185Syz147069 	rval = keyspan_open_one_pipe(ksp, &kp->kp_dataout_pipe);
49960b08185Syz147069 	if (rval != USB_SUCCESS) {
50060b08185Syz147069 
50160b08185Syz147069 		goto fail;
50260b08185Syz147069 	}
50360b08185Syz147069 
50460b08185Syz147069 	return (rval);
50560b08185Syz147069 
50660b08185Syz147069 fail:
50760b08185Syz147069 	USB_DPRINTF_L2(DPRINT_OPEN, kp->kp_lh,
50860b08185Syz147069 	    "keyspan_open_port_pipes: failed %d", rval);
50960b08185Syz147069 	keyspan_close_port_pipes(kp);
51060b08185Syz147069 
51160b08185Syz147069 	return (rval);
51260b08185Syz147069 }
51360b08185Syz147069 
51460b08185Syz147069 void
51560b08185Syz147069 keyspan_close_pipes(keyspan_state_t *ksp)
51660b08185Syz147069 {
51760b08185Syz147069 	USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, "keyspan_close_pipes");
51860b08185Syz147069 
51960b08185Syz147069 	/* close all ports' pipes first, and then device ctrl/status pipes. */
52060b08185Syz147069 	keyspan_close_open_pipes(ksp);
52160b08185Syz147069 	keyspan_close_dev_pipes(ksp);
52260b08185Syz147069 
52360b08185Syz147069 }
52460b08185Syz147069 
52560b08185Syz147069 
52660b08185Syz147069 /*
52760b08185Syz147069  * bulk out common callback
52860b08185Syz147069  */
52960b08185Syz147069 /*ARGSUSED*/
53060b08185Syz147069 void
53160b08185Syz147069 keyspan_bulkout_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
53260b08185Syz147069 {
53360b08185Syz147069 	keyspan_port_t	*kp = (keyspan_port_t *)req->bulk_client_private;
53460b08185Syz147069 	keyspan_pipe_t	*bulkout = &kp->kp_dataout_pipe;
53560b08185Syz147069 	mblk_t		*data = req->bulk_data;
53660b08185Syz147069 	int		data_len;
53760b08185Syz147069 
53860b08185Syz147069 	data_len = (data) ? MBLKL(data) : 0;
53960b08185Syz147069 
54060b08185Syz147069 	USB_DPRINTF_L4(DPRINT_OUT_PIPE, bulkout->pipe_lh,
54160b08185Syz147069 	    "keyspan_bulkout_cb: len=%d cr=%d cb_flags=%x",
54260b08185Syz147069 	    data_len, req->bulk_completion_reason, req->bulk_cb_flags);
54360b08185Syz147069 
544*688b07c5Sgc161489 	if (req->bulk_completion_reason && data) {
54560b08185Syz147069 
54660b08185Syz147069 		/*
54760b08185Syz147069 		 * Data wasn't transfered successfully.
54860b08185Syz147069 		 * Put data back on the queue.
54960b08185Syz147069 		 */
55060b08185Syz147069 		keyspan_put_head(&kp->kp_tx_mp, data, kp);
55160b08185Syz147069 
55260b08185Syz147069 		/* don't release mem in usb_free_bulk_req */
55360b08185Syz147069 		req->bulk_data = NULL;
55460b08185Syz147069 	}
55560b08185Syz147069 
55660b08185Syz147069 	usb_free_bulk_req(req);
55760b08185Syz147069 
55860b08185Syz147069 	/* if more data available, kick off another transmit */
55960b08185Syz147069 	mutex_enter(&kp->kp_mutex);
56060b08185Syz147069 	if (kp->kp_tx_mp == NULL) {
561*688b07c5Sgc161489 		/*
562*688b07c5Sgc161489 		 * Attach a zero packet if data length is muliple of 64,
563*688b07c5Sgc161489 		 * due to the specification of keyspan_usa19hs.
564*688b07c5Sgc161489 		 */
565*688b07c5Sgc161489 		if ((kp->kp_ksp->ks_dev_spec.id_product ==
566*688b07c5Sgc161489 			KEYSPAN_USA19HS_PID) && (data_len == 64)) {
567*688b07c5Sgc161489 			kp->kp_tx_mp = allocb(0, BPRI_LO);
568*688b07c5Sgc161489 			if (kp->kp_tx_mp) {
569*688b07c5Sgc161489 				keyspan_tx_start(kp, NULL);
570*688b07c5Sgc161489 				mutex_exit(&kp->kp_mutex);
571*688b07c5Sgc161489 
572*688b07c5Sgc161489 				return;
573*688b07c5Sgc161489 			}
574*688b07c5Sgc161489 		}
57560b08185Syz147069 
57660b08185Syz147069 		/* no more data, notify waiters */
57760b08185Syz147069 		cv_broadcast(&kp->kp_tx_cv);
57860b08185Syz147069 		mutex_exit(&kp->kp_mutex);
57960b08185Syz147069 
58060b08185Syz147069 		/* tx callback for this port */
58160b08185Syz147069 		kp->kp_cb.cb_tx(kp->kp_cb.cb_arg);
58260b08185Syz147069 	} else {
58360b08185Syz147069 		keyspan_tx_start(kp, NULL);
58460b08185Syz147069 		mutex_exit(&kp->kp_mutex);
58560b08185Syz147069 	}
58660b08185Syz147069 }
58760b08185Syz147069 
588c138f478Syz147069 
589c138f478Syz147069 /* For incoming data only. Parse a status byte and return the err code */
590c138f478Syz147069 void
591c138f478Syz147069 keyspan_parse_status(uchar_t *status, uchar_t *err)
592c138f478Syz147069 {
593c138f478Syz147069 	if (*status & RXERROR_BREAK) {
594c138f478Syz147069 		/*
595c138f478Syz147069 		 * Parity and Framing errors only count if they
596c138f478Syz147069 		 * occur exclusive of a break being received.
597c138f478Syz147069 		 */
598c138f478Syz147069 		*status &= (uint8_t)(RXERROR_OVERRUN | RXERROR_BREAK);
599c138f478Syz147069 	}
600c138f478Syz147069 	*err |= (*status & RXERROR_OVERRUN) ? DS_OVERRUN_ERR : 0;
601c138f478Syz147069 	*err |= (*status & RXERROR_PARITY) ? DS_PARITY_ERR : 0;
602c138f478Syz147069 	*err |= (*status & RXERROR_FRAMING) ? DS_FRAMING_ERR : 0;
603c138f478Syz147069 	*err |= (*status & RXERROR_BREAK) ? DS_BREAK_ERR : 0;
604c138f478Syz147069 }
605c138f478Syz147069 
606c138f478Syz147069 
60760b08185Syz147069 /*
60860b08185Syz147069  * pipe callbacks
60960b08185Syz147069  * --------------
61060b08185Syz147069  *
61160b08185Syz147069  * bulk in common callback for usa19hs model
61260b08185Syz147069  */
61360b08185Syz147069 /*ARGSUSED*/
61460b08185Syz147069 int
61560b08185Syz147069 keyspan_bulkin_cb_usa19hs(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
61660b08185Syz147069 {
61760b08185Syz147069 	keyspan_port_t	*kp = (keyspan_port_t *)req->bulk_client_private;
61860b08185Syz147069 	keyspan_pipe_t	*bulkin = &kp->kp_datain_pipe;
61960b08185Syz147069 	mblk_t		*data = req->bulk_data;
62060b08185Syz147069 	uint_t		cr = req->bulk_completion_reason;
62160b08185Syz147069 	int		data_len;
62260b08185Syz147069 
62360b08185Syz147069 	ASSERT(mutex_owned(&kp->kp_mutex));
62460b08185Syz147069 
62560b08185Syz147069 	data_len = (data) ? MBLKL(data) : 0;
62660b08185Syz147069 
62760b08185Syz147069 	USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh,
62860b08185Syz147069 	    "keyspan_bulkin_cb_usa19hs: len=%d"
62960b08185Syz147069 	    " cr=%d flags=%x baud=%x",
63060b08185Syz147069 	    data_len, cr, req->bulk_cb_flags, kp->kp_baud);
63160b08185Syz147069 
63260b08185Syz147069 	/* put data on the read queue */
63360b08185Syz147069 	if ((data_len > 0) && (kp->kp_state != KEYSPAN_PORT_CLOSED) &&
63460b08185Syz147069 	    (cr == USB_CR_OK)) {
635c138f478Syz147069 		uchar_t	status = data->b_rptr[0];
636c138f478Syz147069 		uchar_t	err = 0;
637c138f478Syz147069 		mblk_t	*mp;
63860b08185Syz147069 		/*
639c138f478Syz147069 		 * According to Keyspan spec, if 0x80 bit is clear, there is
640c138f478Syz147069 		 * only one status byte at the head of the data buf; if 0x80 bit
641c138f478Syz147069 		 * set, then data buf contains alternate status and data bytes;
642c138f478Syz147069 		 * In the first case, only OVERRUN err can exist; In the second
643c138f478Syz147069 		 * case, there are four kinds of err bits may appear in status.
64460b08185Syz147069 		 */
645c138f478Syz147069 
646c138f478Syz147069 		/* if 0x80 bit AND overrun bit are clear, just send up data */
647c138f478Syz147069 		if (!(status & 0x80) && !(status & RXERROR_OVERRUN)) {
64860b08185Syz147069 			USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh,
64960b08185Syz147069 			    "keyspan_bulkin_cb_usa19hs: len=%d",
65060b08185Syz147069 			    data_len);
65160b08185Syz147069 
652c138f478Syz147069 			/* Get rid of the first status byte and send up data */
65360b08185Syz147069 			data->b_rptr++;
65460b08185Syz147069 			data_len--;
65560b08185Syz147069 			if (data_len > 0) {
65660b08185Syz147069 				keyspan_put_tail(&kp->kp_rx_mp, data);
65760b08185Syz147069 
65860b08185Syz147069 				/*
65960b08185Syz147069 				 * the data will not be freed and
66060b08185Syz147069 				 * will be sent up later.
66160b08185Syz147069 				 */
66260b08185Syz147069 				req->bulk_data = NULL;
66360b08185Syz147069 			}
664c138f478Syz147069 		} else if (!(status & 0x80)) {
665c138f478Syz147069 			/* If 0x80 bit is clear and overrun bit is set */
666c138f478Syz147069 			USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh,
667c138f478Syz147069 			    "keyspan_bulkin_cb_usa19hs: usb xfer is OK,"
668c138f478Syz147069 			    " but there is overrun err in serial xfer");
66960b08185Syz147069 
670c138f478Syz147069 			keyspan_parse_status(&status, &err);
671c138f478Syz147069 			mutex_exit(&kp->kp_mutex);
672c138f478Syz147069 			if ((mp = allocb(2, BPRI_HI)) == NULL) {
673c138f478Syz147069 				USB_DPRINTF_L2(DPRINT_IN_PIPE, kp->kp_lh,
674c138f478Syz147069 				    "keyspan_bulkin_cb_usa19hs: allocb failed");
675c138f478Syz147069 				mutex_enter(&kp->kp_mutex);
67660b08185Syz147069 
677c138f478Syz147069 				return (0);
678c138f478Syz147069 			}
679c138f478Syz147069 			DB_TYPE(mp) = M_BREAK;
680c138f478Syz147069 			*mp->b_wptr++ = err;
681c138f478Syz147069 			*mp->b_wptr++ = status;
682c138f478Syz147069 			mutex_enter(&kp->kp_mutex);
683c138f478Syz147069 
684c138f478Syz147069 			/* Add to the received list; Send up the err code. */
685c138f478Syz147069 			keyspan_put_tail(&kp->kp_rx_mp, mp);
686c138f478Syz147069 
687c138f478Syz147069 			/*
688c138f478Syz147069 			 * Don't send up the first byte because
689c138f478Syz147069 			 * it is a status byte.
690c138f478Syz147069 			 */
691c138f478Syz147069 			data->b_rptr++;
692c138f478Syz147069 			data_len--;
693c138f478Syz147069 			if (data_len > 0) {
694c138f478Syz147069 				keyspan_put_tail(&kp->kp_rx_mp, data);
695c138f478Syz147069 
696c138f478Syz147069 				/*
697c138f478Syz147069 				 * the data will not be freed and
698c138f478Syz147069 				 * will be sent up later.
699c138f478Syz147069 				 */
700c138f478Syz147069 				req->bulk_data = NULL;
701c138f478Syz147069 			}
702c138f478Syz147069 		} else { /* 0x80 bit set, there are some errs in the data */
703c138f478Syz147069 			USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh,
704c138f478Syz147069 			    "keyspan_bulkin_cb_usa19hs: usb xfer is OK,"
705c138f478Syz147069 			    " but there are errs in serial xfer");
706c138f478Syz147069 			/*
707c138f478Syz147069 			 * Usually, there are at least two bytes,
708c138f478Syz147069 			 * one status and one data.
709c138f478Syz147069 			 */
71060b08185Syz147069 			if (data_len > 1) {
71160b08185Syz147069 				int i = 0;
71260b08185Syz147069 				int j = 1;
713c138f478Syz147069 				/*
714c138f478Syz147069 				 * In this case, there might be multi status
715c138f478Syz147069 				 * bytes. Parse each status byte and move the
716c138f478Syz147069 				 * data bytes together.
717c138f478Syz147069 				 */
71860b08185Syz147069 				for (j = 1; j < data_len; j += 2) {
719c138f478Syz147069 					status = data->b_rptr[j-1];
720c138f478Syz147069 					keyspan_parse_status(&status, &err);
721c138f478Syz147069 
722c138f478Syz147069 					/* move the data togeter */
72360b08185Syz147069 					data->b_rptr[i] = data->b_rptr[j];
72460b08185Syz147069 					i++;
72560b08185Syz147069 				}
72660b08185Syz147069 				data->b_wptr = data->b_rptr + i;
727c138f478Syz147069 			} else { /* There are only one byte in incoming buf */
728c138f478Syz147069 				keyspan_parse_status(&status, &err);
729c138f478Syz147069 			}
730c138f478Syz147069 			mutex_exit(&kp->kp_mutex);
731c138f478Syz147069 			if ((mp = allocb(2, BPRI_HI)) == NULL) {
732c138f478Syz147069 				USB_DPRINTF_L2(DPRINT_IN_PIPE, kp->kp_lh,
733c138f478Syz147069 				    "keyspan_bulkin_cb_usa19hs: allocb failed");
734c138f478Syz147069 				mutex_enter(&kp->kp_mutex);
73560b08185Syz147069 
736c138f478Syz147069 				return (0);
737c138f478Syz147069 			}
738c138f478Syz147069 			DB_TYPE(mp) = M_BREAK;
739c138f478Syz147069 			*mp->b_wptr++ = err;
740c138f478Syz147069 			if (data_len > 2) {
741c138f478Syz147069 				/*
742c138f478Syz147069 				 * There are multiple status bytes in this case.
743c138f478Syz147069 				 * Use err as status character since err is got
744c138f478Syz147069 				 * by or in all status bytes.
745c138f478Syz147069 				 */
746c138f478Syz147069 				*mp->b_wptr++ = err;
747c138f478Syz147069 			} else {
748c138f478Syz147069 				*mp->b_wptr++ = status;
749c138f478Syz147069 			}
750c138f478Syz147069 			mutex_enter(&kp->kp_mutex);
751c138f478Syz147069 
752c138f478Syz147069 			/* Add to the received list; Send up the err code. */
753c138f478Syz147069 			keyspan_put_tail(&kp->kp_rx_mp, mp);
754c138f478Syz147069 
755c138f478Syz147069 			if (data_len > 1) {
756c138f478Syz147069 				data_len = data->b_wptr - data->b_rptr;
757c138f478Syz147069 				keyspan_put_tail(&kp->kp_rx_mp, data);
75860b08185Syz147069 				/*
75960b08185Syz147069 				 * The data will not be freed and
76060b08185Syz147069 				 * will be sent up later.
76160b08185Syz147069 				 */
76260b08185Syz147069 				req->bulk_data = NULL;
763c138f478Syz147069 			}
764c138f478Syz147069 		}
765c138f478Syz147069 	} else { /* usb error happened, so don't send up data */
76660b08185Syz147069 		data_len = 0;
76760b08185Syz147069 		USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh,
76860b08185Syz147069 		    "keyspan_bulkin_cb_usa19hs: error happened, len=%d, "
76960b08185Syz147069 		    "cr=0x%x, cb_flags=0x%x", data_len, cr, req->bulk_cb_flags);
770c138f478Syz147069 	}
77160b08185Syz147069 	if (kp->kp_state != KEYSPAN_PORT_OPEN) {
77260b08185Syz147069 		kp->kp_no_more_reads = B_TRUE;
77360b08185Syz147069 	}
77460b08185Syz147069 
77560b08185Syz147069 	return (data_len);
77660b08185Syz147069 }
77760b08185Syz147069 
778c138f478Syz147069 
77960b08185Syz147069 /*
78060b08185Syz147069  * pipe callbacks
78160b08185Syz147069  * --------------
78260b08185Syz147069  *
78360b08185Syz147069  * bulk in common callback for usa49 model
78460b08185Syz147069  */
78560b08185Syz147069 /*ARGSUSED*/
78660b08185Syz147069 int
78760b08185Syz147069 keyspan_bulkin_cb_usa49(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
78860b08185Syz147069 {
78960b08185Syz147069 	keyspan_port_t	*kp = (keyspan_port_t *)req->bulk_client_private;
79060b08185Syz147069 	keyspan_pipe_t	*bulkin = &kp->kp_datain_pipe;
79160b08185Syz147069 	mblk_t		*data = req->bulk_data;
79260b08185Syz147069 	uint_t		cr = req->bulk_completion_reason;
79360b08185Syz147069 	int		data_len;
79460b08185Syz147069 
79560b08185Syz147069 	ASSERT(mutex_owned(&kp->kp_mutex));
79660b08185Syz147069 
79760b08185Syz147069 	data_len = (data) ? MBLKL(data) : 0;
79860b08185Syz147069 
79960b08185Syz147069 	USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh,
80060b08185Syz147069 	    "keyspan_bulkin_cb_usa49: len=%d"
80160b08185Syz147069 	    " cr=%d flags=%x", data_len, cr, req->bulk_cb_flags);
80260b08185Syz147069 
80360b08185Syz147069 	/* put data on the read queue */
80460b08185Syz147069 	if ((data_len > 0) && (kp->kp_state != KEYSPAN_PORT_CLOSED) &&
80560b08185Syz147069 	    (cr == USB_CR_OK)) {
806c138f478Syz147069 		uchar_t	status = data->b_rptr[0];
807c138f478Syz147069 		uchar_t	err = 0;
808c138f478Syz147069 		mblk_t	*mp;
80960b08185Syz147069 		/*
810c138f478Syz147069 		 * According to Keyspan spec, if 0x80 bit is clear, there is
811c138f478Syz147069 		 * only one status byte at the head of the data buf; if 0x80 bit
812c138f478Syz147069 		 * set, then data buf contains alternate status and data bytes;
813c138f478Syz147069 		 * In the first case, only OVERRUN err can exist; In the second
814c138f478Syz147069 		 * case, there are four kinds of err bits may appear in status.
81560b08185Syz147069 		 */
81660b08185Syz147069 
817c138f478Syz147069 		/* if 0x80 bit AND overrun bit are clear, just send up data */
818c138f478Syz147069 		if (!(status & 0x80) && !(status & RXERROR_OVERRUN)) {
819c138f478Syz147069 			USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh,
820c138f478Syz147069 			    "keyspan_bulkin_cb_usa49: len=%d",
821c138f478Syz147069 			    data_len);
822c138f478Syz147069 
823c138f478Syz147069 			/* Get rid of the first status byte and send up data */
82460b08185Syz147069 			data->b_rptr++;
82560b08185Syz147069 			data_len--;
82660b08185Syz147069 			if (data_len > 0) {
82760b08185Syz147069 				keyspan_put_tail(&kp->kp_rx_mp, data);
82860b08185Syz147069 
82960b08185Syz147069 				/*
830c138f478Syz147069 				 * the data will not be freed and
83160b08185Syz147069 				 * will be sent up later.
83260b08185Syz147069 				 */
83360b08185Syz147069 				req->bulk_data = NULL;
83460b08185Syz147069 			}
835c138f478Syz147069 		} else if (!(status & 0x80)) {
836c138f478Syz147069 			/* If 0x80 bit is clear and overrun bit is set */
837c138f478Syz147069 			USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh,
838c138f478Syz147069 			    "keyspan_bulkin_cb_usa49: usb xfer is OK,"
839c138f478Syz147069 			    " but there is overrun err in serial xfer");
840c138f478Syz147069 
841c138f478Syz147069 			keyspan_parse_status(&status, &err);
842c138f478Syz147069 			mutex_exit(&kp->kp_mutex);
843c138f478Syz147069 			if ((mp = allocb(2, BPRI_HI)) == NULL) {
844c138f478Syz147069 				USB_DPRINTF_L2(DPRINT_IN_PIPE, kp->kp_lh,
845c138f478Syz147069 				    "keyspan_bulkin_cb_usa49: allocb failed");
846c138f478Syz147069 				mutex_enter(&kp->kp_mutex);
847c138f478Syz147069 
848c138f478Syz147069 				return (0);
849c138f478Syz147069 			}
850c138f478Syz147069 			DB_TYPE(mp) = M_BREAK;
851c138f478Syz147069 			*mp->b_wptr++ = err;
852c138f478Syz147069 			*mp->b_wptr++ = status;
853c138f478Syz147069 			mutex_enter(&kp->kp_mutex);
854c138f478Syz147069 
855c138f478Syz147069 			/* Add to the received list; Send up the err code. */
856c138f478Syz147069 			keyspan_put_tail(&kp->kp_rx_mp, mp);
857c138f478Syz147069 
858c138f478Syz147069 			/*
859c138f478Syz147069 			 * Don't send up the first byte because
860c138f478Syz147069 			 * it is a status byte.
861c138f478Syz147069 			 */
862c138f478Syz147069 			data->b_rptr++;
863c138f478Syz147069 			data_len--;
864c138f478Syz147069 			if (data_len > 0) {
865c138f478Syz147069 				keyspan_put_tail(&kp->kp_rx_mp, data);
866c138f478Syz147069 
867c138f478Syz147069 				/*
868c138f478Syz147069 				 * the data will not be freed and
869c138f478Syz147069 				 * will be sent up later.
870c138f478Syz147069 				 */
871c138f478Syz147069 				req->bulk_data = NULL;
872c138f478Syz147069 			}
873c138f478Syz147069 		} else { /* 0x80 bit set, there are some errs in the data */
874c138f478Syz147069 			USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh,
875c138f478Syz147069 			    "keyspan_bulkin_cb_usa49: usb xfer is OK,"
876c138f478Syz147069 			    " but there are errs in serial xfer");
877c138f478Syz147069 			/*
878c138f478Syz147069 			 * Usually, there are at least two bytes,
879c138f478Syz147069 			 * one status and one data.
880c138f478Syz147069 			 */
88160b08185Syz147069 			if (data_len > 1) {
88260b08185Syz147069 				int i = 0;
88360b08185Syz147069 				int j = 1;
884c138f478Syz147069 				/*
885c138f478Syz147069 				 * In this case, there might be multi status
886c138f478Syz147069 				 * bytes. Parse each status byte and move the
887c138f478Syz147069 				 * data bytes together.
888c138f478Syz147069 				 */
88960b08185Syz147069 				for (j = 1; j < data_len; j += 2) {
890c138f478Syz147069 					status = data->b_rptr[j-1];
891c138f478Syz147069 					keyspan_parse_status(&status, &err);
892c138f478Syz147069 
893c138f478Syz147069 					/* move the data togeter */
89460b08185Syz147069 					data->b_rptr[i] = data->b_rptr[j];
89560b08185Syz147069 					i++;
89660b08185Syz147069 				}
89760b08185Syz147069 				data->b_wptr = data->b_rptr + i;
898c138f478Syz147069 			} else { /* There are only one byte in incoming buf */
899c138f478Syz147069 				keyspan_parse_status(&status, &err);
900c138f478Syz147069 			}
901c138f478Syz147069 			mutex_exit(&kp->kp_mutex);
902c138f478Syz147069 			if ((mp = allocb(2, BPRI_HI)) == NULL) {
903c138f478Syz147069 				USB_DPRINTF_L2(DPRINT_IN_PIPE, kp->kp_lh,
904c138f478Syz147069 				    "keyspan_bulkin_cb_usa49: allocb failed");
905c138f478Syz147069 				mutex_enter(&kp->kp_mutex);
90660b08185Syz147069 
907c138f478Syz147069 				return (0);
908c138f478Syz147069 			}
909c138f478Syz147069 			DB_TYPE(mp) = M_BREAK;
910c138f478Syz147069 			*mp->b_wptr++ = err;
911c138f478Syz147069 			if (data_len > 2) {
912c138f478Syz147069 				/*
913c138f478Syz147069 				 * There are multiple status bytes in this case.
914c138f478Syz147069 				 * Use err as status character since err is got
915c138f478Syz147069 				 * by or in all status bytes.
916c138f478Syz147069 				 */
917c138f478Syz147069 				*mp->b_wptr++ = err;
918c138f478Syz147069 			} else {
919c138f478Syz147069 				*mp->b_wptr++ = status;
920c138f478Syz147069 			}
921c138f478Syz147069 			mutex_enter(&kp->kp_mutex);
922c138f478Syz147069 
923c138f478Syz147069 			/* Add to the received list; Send up the err code. */
924c138f478Syz147069 			keyspan_put_tail(&kp->kp_rx_mp, mp);
925c138f478Syz147069 
926c138f478Syz147069 			if (data_len > 1) {
927c138f478Syz147069 				data_len = data->b_wptr - data->b_rptr;
928c138f478Syz147069 				keyspan_put_tail(&kp->kp_rx_mp, data);
92960b08185Syz147069 				/*
93060b08185Syz147069 				 * The data will not be freed and
93160b08185Syz147069 				 * will be sent up later.
93260b08185Syz147069 				 */
93360b08185Syz147069 				req->bulk_data = NULL;
93460b08185Syz147069 			}
93560b08185Syz147069 		}
93660b08185Syz147069 	} else {
93760b08185Syz147069 		/* usb error happened, so don't send up data */
93860b08185Syz147069 		data_len = 0;
93960b08185Syz147069 		USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh,
94060b08185Syz147069 		    "keyspan_bulkin_cb_usa49: port_state=%d"
94160b08185Syz147069 		    " b_rptr[0]=%c", kp->kp_state, data->b_rptr[0]);
942c138f478Syz147069 	}
94360b08185Syz147069 	if (kp->kp_state != KEYSPAN_PORT_OPEN) {
94460b08185Syz147069 		kp->kp_no_more_reads = B_TRUE;
94560b08185Syz147069 	}
94660b08185Syz147069 
94760b08185Syz147069 	return (data_len);
94860b08185Syz147069 }
949c138f478Syz147069 
95060b08185Syz147069 
95160b08185Syz147069 /*
95260b08185Syz147069  * pipe callbacks
95360b08185Syz147069  * --------------
95460b08185Syz147069  *
95560b08185Syz147069  * bulk in common callback
95660b08185Syz147069  */
95760b08185Syz147069 /*ARGSUSED*/
95860b08185Syz147069 void
95960b08185Syz147069 keyspan_bulkin_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
96060b08185Syz147069 {
96160b08185Syz147069 	keyspan_port_t	*kp = (keyspan_port_t *)req->bulk_client_private;
96260b08185Syz147069 	keyspan_state_t	*ksp = kp->kp_ksp;
96360b08185Syz147069 	int		data_len;
96460b08185Syz147069 	boolean_t	no_more_reads = B_FALSE;
96560b08185Syz147069 
96660b08185Syz147069 	USB_DPRINTF_L4(DPRINT_IN_PIPE, (&kp->kp_datain_pipe)->pipe_lh,
96760b08185Syz147069 	    "keyspan_bulkin_cb");
96860b08185Syz147069 
96960b08185Syz147069 	mutex_enter(&kp->kp_mutex);
97060b08185Syz147069 
97160b08185Syz147069 	/* put data on the read queue */
97260b08185Syz147069 	switch (ksp->ks_dev_spec.id_product) {
97360b08185Syz147069 	case KEYSPAN_USA19HS_PID:
97460b08185Syz147069 		data_len = keyspan_bulkin_cb_usa19hs(pipe, req);
97560b08185Syz147069 
97660b08185Syz147069 		break;
97760b08185Syz147069 
978c138f478Syz147069 
97960b08185Syz147069 	case KEYSPAN_USA49WLC_PID:
98060b08185Syz147069 		data_len = keyspan_bulkin_cb_usa49(pipe, req);
98160b08185Syz147069 
98260b08185Syz147069 		break;
983c138f478Syz147069 
98460b08185Syz147069 	default:
98560b08185Syz147069 		USB_DPRINTF_L2(DPRINT_IN_PIPE, (&kp->kp_datain_pipe)->pipe_lh,
98660b08185Syz147069 		    "keyspan_bulkin_cb:"
98760b08185Syz147069 		    "the device's product id can't be recognized");
98860b08185Syz147069 		mutex_exit(&kp->kp_mutex);
98960b08185Syz147069 
99060b08185Syz147069 		return;
99160b08185Syz147069 	}
99260b08185Syz147069 
99360b08185Syz147069 	no_more_reads = kp->kp_no_more_reads;
99460b08185Syz147069 
99560b08185Syz147069 	mutex_exit(&kp->kp_mutex);
99660b08185Syz147069 
99760b08185Syz147069 	usb_free_bulk_req(req);
99860b08185Syz147069 
99960b08185Syz147069 	/* kick off another read unless indicated otherwise */
100060b08185Syz147069 	if (!no_more_reads) {
100160b08185Syz147069 		(void) keyspan_receive_data(&kp->kp_datain_pipe,
100260b08185Syz147069 		    kp->kp_read_len, kp);
100360b08185Syz147069 	}
100460b08185Syz147069 
100560b08185Syz147069 	/* setup rx callback for this port */
100660b08185Syz147069 	if (data_len > 0)  {
100760b08185Syz147069 		kp->kp_cb.cb_rx(kp->kp_cb.cb_arg);
100860b08185Syz147069 	}
100960b08185Syz147069 }
101060b08185Syz147069 
101160b08185Syz147069 /*
101260b08185Syz147069  * pipe callbacks
101360b08185Syz147069  * --------------
101460b08185Syz147069  *
101560b08185Syz147069  * bulk in status callback for usa19hs model
101660b08185Syz147069  */
101760b08185Syz147069 /*ARGSUSED*/
101860b08185Syz147069 void
101960b08185Syz147069 keyspan_status_cb_usa19hs(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
102060b08185Syz147069 {
102160b08185Syz147069 	keyspan_state_t	*ksp = (keyspan_state_t *)req->bulk_client_private;
102260b08185Syz147069 	keyspan_pipe_t	*bulkin = &ksp->ks_statin_pipe;
102360b08185Syz147069 	mblk_t		*data = req->bulk_data;
102460b08185Syz147069 	usb_cr_t	cr = req->bulk_completion_reason;
102560b08185Syz147069 	int		data_len;
102660b08185Syz147069 
102760b08185Syz147069 	data_len = (data) ? MBLKL(data) : 0;
102860b08185Syz147069 
102960b08185Syz147069 	USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh,
103060b08185Syz147069 	    "keyspan_status_cb_usa19hs: len=%d"
103160b08185Syz147069 	    " cr=%d flags=%x", data_len, cr, req->bulk_cb_flags);
103260b08185Syz147069 
103360b08185Syz147069 	/* put data on the read queue */
103460b08185Syz147069 	if ((data_len == 14) && (cr == USB_CR_OK)) {
103560b08185Syz147069 		keyspan_port_t	*kp = &ksp->ks_ports[0];
103660b08185Syz147069 		keyspan_usa19hs_port_status_msg_t *status_msg =
103760b08185Syz147069 		    &(kp->kp_status_msg.usa19hs);
103860b08185Syz147069 
103960b08185Syz147069 		mutex_enter(&kp->kp_mutex);
104060b08185Syz147069 		bcopy(data->b_rptr, status_msg, data_len);
104160b08185Syz147069 
104260b08185Syz147069 		if (status_msg->controlResponse) {
104360b08185Syz147069 			kp->kp_status_flag |= KEYSPAN_PORT_CTRLRESP;
104460b08185Syz147069 		} else {
104560b08185Syz147069 			kp->kp_status_flag &= ~KEYSPAN_PORT_CTRLRESP;
104660b08185Syz147069 		}
104760b08185Syz147069 
104860b08185Syz147069 		if (status_msg->portState & PORTSTATE_ENABLED) {
104960b08185Syz147069 			kp->kp_status_flag |= KEYSPAN_PORT_ENABLE;
105060b08185Syz147069 		} else {
105160b08185Syz147069 			kp->kp_status_flag &= ~KEYSPAN_PORT_ENABLE;
105260b08185Syz147069 		}
105360b08185Syz147069 
105460b08185Syz147069 		if (status_msg->portState & PORTSTATE_TXBREAK) {
105560b08185Syz147069 			kp->kp_status_flag |= KEYSPAN_PORT_TXBREAK;
105660b08185Syz147069 		} else {
105760b08185Syz147069 			kp->kp_status_flag &= ~KEYSPAN_PORT_TXBREAK;
105860b08185Syz147069 		}
105960b08185Syz147069 
106060b08185Syz147069 		if (status_msg->rxBreak) {
106160b08185Syz147069 			kp->kp_status_flag |= KEYSPAN_PORT_RXBREAK;
106260b08185Syz147069 		} else {
106360b08185Syz147069 			kp->kp_status_flag &= ~KEYSPAN_PORT_RXBREAK;
106460b08185Syz147069 		}
106560b08185Syz147069 
106660b08185Syz147069 		if (status_msg->portState & PORTSTATE_LOOPBACK) {
106760b08185Syz147069 			kp->kp_status_flag |= KEYSPAN_PORT_LOOPBACK;
106860b08185Syz147069 		} else {
106960b08185Syz147069 			kp->kp_status_flag &= ~KEYSPAN_PORT_LOOPBACK;
107060b08185Syz147069 		}
107160b08185Syz147069 
107260b08185Syz147069 		/* if msr status changed, then invoke status callback */
107360b08185Syz147069 		if (status_msg->msr & USA_MSR_dCTS ||
107460b08185Syz147069 		    status_msg->msr & USA_MSR_dDSR ||
107560b08185Syz147069 		    status_msg->msr & USA_MSR_dRI ||
107660b08185Syz147069 		    status_msg->msr & USA_MSR_dDCD) {
107760b08185Syz147069 
107860b08185Syz147069 			mutex_exit(&kp->kp_mutex);
107960b08185Syz147069 			kp->kp_cb.cb_status(kp->kp_cb.cb_arg);
108060b08185Syz147069 		} else {
108160b08185Syz147069 			mutex_exit(&kp->kp_mutex);
108260b08185Syz147069 		}
108360b08185Syz147069 	} else {
108460b08185Syz147069 
108560b08185Syz147069 		USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh,
108660b08185Syz147069 		    "keyspan_status_cb_usa19hs: get status failed, cr=%d"
108760b08185Syz147069 		    " data_len=%d", cr, data_len);
108860b08185Syz147069 	}
108960b08185Syz147069 }
109060b08185Syz147069 
1091c138f478Syz147069 
109260b08185Syz147069 /*
109360b08185Syz147069  * pipe callbacks
109460b08185Syz147069  * --------------
109560b08185Syz147069  *
109660b08185Syz147069  * bulk in status callback for usa49 model
109760b08185Syz147069  */
109860b08185Syz147069 /*ARGSUSED*/
109960b08185Syz147069 void
110060b08185Syz147069 keyspan_status_cb_usa49(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
110160b08185Syz147069 {
110260b08185Syz147069 	keyspan_state_t	*ksp = (keyspan_state_t *)req->bulk_client_private;
110360b08185Syz147069 	keyspan_pipe_t	*bulkin = &ksp->ks_statin_pipe;
110460b08185Syz147069 	mblk_t		*data = req->bulk_data;
110560b08185Syz147069 	uint_t		cr = req->bulk_completion_reason;
110660b08185Syz147069 	int		data_len;
110760b08185Syz147069 
110860b08185Syz147069 	data_len = (data) ? MBLKL(data) : 0;
110960b08185Syz147069 
111060b08185Syz147069 	USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh,
111160b08185Syz147069 	    "keyspan_status_cb_usa49: len=%d"
111260b08185Syz147069 	    " cr=%d flags=%x", data_len, cr, req->bulk_cb_flags);
111360b08185Syz147069 
111460b08185Syz147069 	/* put data on the read queue */
111560b08185Syz147069 	if ((data_len == 11) && (cr == USB_CR_OK)) {
111660b08185Syz147069 		keyspan_usa49_port_status_msg_t status_msg;
111760b08185Syz147069 		keyspan_port_t *cur_kp;
111860b08185Syz147069 		keyspan_usa49_port_status_msg_t *kp_status_msg;
111960b08185Syz147069 		boolean_t need_cb = B_FALSE;
112060b08185Syz147069 
112160b08185Syz147069 		bcopy(data->b_rptr, &status_msg, data_len);
112260b08185Syz147069 		if (status_msg.portNumber >= ksp->ks_dev_spec.port_cnt) {
112360b08185Syz147069 
112460b08185Syz147069 			return;
112560b08185Syz147069 		}
112660b08185Syz147069 		cur_kp = &ksp->ks_ports[status_msg.portNumber];
112760b08185Syz147069 		kp_status_msg = &(cur_kp->kp_status_msg.usa49);
112860b08185Syz147069 
112960b08185Syz147069 		mutex_enter(&cur_kp->kp_mutex);
113060b08185Syz147069 
113160b08185Syz147069 		/* if msr status changed, then need invoke status callback */
113260b08185Syz147069 		if (status_msg.cts !=  kp_status_msg->cts ||
113360b08185Syz147069 		    status_msg.dsr != kp_status_msg->dsr ||
113460b08185Syz147069 		    status_msg.ri != kp_status_msg->ri ||
113560b08185Syz147069 		    status_msg.dcd != kp_status_msg->dcd) {
113660b08185Syz147069 
113760b08185Syz147069 			need_cb = B_TRUE;
113860b08185Syz147069 		}
113960b08185Syz147069 
114060b08185Syz147069 		bcopy(&status_msg, kp_status_msg, data_len);
114160b08185Syz147069 
114260b08185Syz147069 		if (kp_status_msg->controlResponse) {
114360b08185Syz147069 			cur_kp->kp_status_flag |= KEYSPAN_PORT_CTRLRESP;
114460b08185Syz147069 		} else {
114560b08185Syz147069 			cur_kp->kp_status_flag &= ~KEYSPAN_PORT_CTRLRESP;
114660b08185Syz147069 		}
114760b08185Syz147069 
114860b08185Syz147069 		if (!kp_status_msg->rxEnabled) {
114960b08185Syz147069 			cur_kp->kp_status_flag |= KEYSPAN_PORT_RXBREAK;
115060b08185Syz147069 		} else {
115160b08185Syz147069 			cur_kp->kp_status_flag &= ~KEYSPAN_PORT_RXBREAK;
115260b08185Syz147069 		}
115360b08185Syz147069 
115460b08185Syz147069 		mutex_exit(&cur_kp->kp_mutex);
115560b08185Syz147069 
115660b08185Syz147069 		if (need_cb) {
115760b08185Syz147069 
115860b08185Syz147069 			cur_kp->kp_cb.cb_status(cur_kp->kp_cb.cb_arg);
115960b08185Syz147069 		}
116060b08185Syz147069 	} else {
116160b08185Syz147069 
116260b08185Syz147069 		USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh,
116360b08185Syz147069 		    "keyspan_status_cb_usa49: get status failed, cr=%d"
116460b08185Syz147069 		    " data_len=%d", cr, data_len);
116560b08185Syz147069 	}
116660b08185Syz147069 }
1167c138f478Syz147069 
116860b08185Syz147069 
116960b08185Syz147069 /*
117060b08185Syz147069  * pipe callbacks
117160b08185Syz147069  * --------------
117260b08185Syz147069  *
117360b08185Syz147069  * bulk in callback for status receiving
117460b08185Syz147069  */
117560b08185Syz147069 /*ARGSUSED*/
117660b08185Syz147069 void
117760b08185Syz147069 keyspan_status_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
117860b08185Syz147069 {
117960b08185Syz147069 	keyspan_state_t	*ksp = (keyspan_state_t *)req->bulk_client_private;
118060b08185Syz147069 	usb_cr_t	cr = req->bulk_completion_reason;
118160b08185Syz147069 
118260b08185Syz147069 	USB_DPRINTF_L4(DPRINT_IN_PIPE, (&ksp->ks_statin_pipe)->pipe_lh,
118360b08185Syz147069 	    "keyspan_status_cb");
118460b08185Syz147069 
118560b08185Syz147069 	/* put data on the read queue */
118660b08185Syz147069 	switch (ksp->ks_dev_spec.id_product) {
118760b08185Syz147069 	case KEYSPAN_USA19HS_PID:
118860b08185Syz147069 		keyspan_status_cb_usa19hs(pipe, req);
118960b08185Syz147069 
119060b08185Syz147069 		break;
119160b08185Syz147069 
1192c138f478Syz147069 
119360b08185Syz147069 	case KEYSPAN_USA49WLC_PID:
119460b08185Syz147069 		keyspan_status_cb_usa49(pipe, req);
119560b08185Syz147069 
119660b08185Syz147069 		break;
1197c138f478Syz147069 
119860b08185Syz147069 	default:
119960b08185Syz147069 		USB_DPRINTF_L2(DPRINT_IN_PIPE,
120060b08185Syz147069 		    (&ksp->ks_statin_pipe)->pipe_lh, "keyspan_status_cb:"
120160b08185Syz147069 		    "the device's product id can't be recognized");
120260b08185Syz147069 
120360b08185Syz147069 		return;
120460b08185Syz147069 	}
120560b08185Syz147069 
120660b08185Syz147069 	usb_free_bulk_req(req);
120760b08185Syz147069 
120860b08185Syz147069 	/* kick off another read to receive status */
120960b08185Syz147069 	if ((cr != USB_CR_FLUSHED) && (cr != USB_CR_DEV_NOT_RESP) &&
121060b08185Syz147069 	    keyspan_dev_is_online(ksp)) {
121160b08185Syz147069 		if (keyspan_receive_status(ksp) != USB_SUCCESS) {
121260b08185Syz147069 			USB_DPRINTF_L2(DPRINT_IN_PIPE,
121360b08185Syz147069 			    (&ksp->ks_statin_pipe)->pipe_lh,
121460b08185Syz147069 			    "keyspan_status_cb:"
121560b08185Syz147069 			    "receive status can't be restarted.");
121660b08185Syz147069 		}
121760b08185Syz147069 	} else {
121860b08185Syz147069 		USB_DPRINTF_L2(DPRINT_IN_PIPE,
121960b08185Syz147069 		    (&ksp->ks_statin_pipe)->pipe_lh, "keyspan_status_cb:"
122060b08185Syz147069 		    "get status failed: cr=%d", cr);
122160b08185Syz147069 	}
122260b08185Syz147069 }
122360b08185Syz147069 
122460b08185Syz147069 /*
122560b08185Syz147069  * Submit data read request (asynchronous). If this function returns
122660b08185Syz147069  * USB_SUCCESS, pipe is acquired and request is sent, otherwise req is free.
122760b08185Syz147069  */
122860b08185Syz147069 int
122960b08185Syz147069 keyspan_receive_data(keyspan_pipe_t *bulkin, int len, void *cb_arg)
123060b08185Syz147069 {
123160b08185Syz147069 	keyspan_state_t	*ksp = bulkin->pipe_ksp;
123260b08185Syz147069 	usb_bulk_req_t	*br;
123360b08185Syz147069 	int		rval;
123460b08185Syz147069 
123560b08185Syz147069 	USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, "keyspan_receive_data:"
123660b08185Syz147069 	    "len=%d", len);
123760b08185Syz147069 
123860b08185Syz147069 	ASSERT(!mutex_owned(&bulkin->pipe_mutex));
123960b08185Syz147069 
124060b08185Syz147069 	br = usb_alloc_bulk_req(ksp->ks_dip, len, USB_FLAGS_SLEEP);
124160b08185Syz147069 	br->bulk_len = len;
124260b08185Syz147069 
124360b08185Syz147069 	/* No timeout, just wait for data */
124460b08185Syz147069 	br->bulk_timeout = 0;
124560b08185Syz147069 	br->bulk_client_private = cb_arg;
124660b08185Syz147069 	br->bulk_attributes = USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING;
124760b08185Syz147069 	br->bulk_cb = keyspan_bulkin_cb;
124860b08185Syz147069 	br->bulk_exc_cb = keyspan_bulkin_cb;
124960b08185Syz147069 
125060b08185Syz147069 	rval = usb_pipe_bulk_xfer(bulkin->pipe_handle, br, 0);
125160b08185Syz147069 	if (rval != USB_SUCCESS) {
125260b08185Syz147069 		usb_free_bulk_req(br);
125360b08185Syz147069 	}
125460b08185Syz147069 	USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh,
125560b08185Syz147069 	    "keyspan_receive_data: rval = %d", rval);
125660b08185Syz147069 	return (rval);
125760b08185Syz147069 }
125860b08185Syz147069 
125960b08185Syz147069 /*
126060b08185Syz147069  * submit device status read request (asynchronous).
126160b08185Syz147069  */
126260b08185Syz147069 int
126360b08185Syz147069 keyspan_receive_status(keyspan_state_t	*ksp)
126460b08185Syz147069 {
126560b08185Syz147069 	keyspan_pipe_t *bulkin = &ksp->ks_statin_pipe;
126660b08185Syz147069 	usb_bulk_req_t	*br;
126760b08185Syz147069 	int		rval;
126860b08185Syz147069 
126960b08185Syz147069 	USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh,
127060b08185Syz147069 	    "keyspan_receive_status");
127160b08185Syz147069 
127260b08185Syz147069 	ASSERT(!mutex_owned(&bulkin->pipe_mutex));
127360b08185Syz147069 
127460b08185Syz147069 	br = usb_alloc_bulk_req(ksp->ks_dip, 32, USB_FLAGS_SLEEP);
127560b08185Syz147069 	br->bulk_len = KEYSPAN_STATIN_MAX_LEN;
127660b08185Syz147069 
127760b08185Syz147069 	/* No timeout, just wait for data */
127860b08185Syz147069 	br->bulk_timeout = 0;
127960b08185Syz147069 	br->bulk_client_private = (void *)ksp;
128060b08185Syz147069 	br->bulk_attributes = USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING;
128160b08185Syz147069 	br->bulk_cb = keyspan_status_cb;
128260b08185Syz147069 	br->bulk_exc_cb = keyspan_status_cb;
128360b08185Syz147069 
128460b08185Syz147069 	rval = usb_pipe_bulk_xfer(bulkin->pipe_handle, br, 0);
128560b08185Syz147069 	if (rval != USB_SUCCESS) {
128660b08185Syz147069 		usb_free_bulk_req(br);
128760b08185Syz147069 	}
128860b08185Syz147069 	USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh,
128960b08185Syz147069 	    "keyspan_receive_status: rval = %d", rval);
129060b08185Syz147069 	return (rval);
129160b08185Syz147069 }
129260b08185Syz147069 
129360b08185Syz147069 /*
129460b08185Syz147069  * submit data for transfer (asynchronous)
129560b08185Syz147069  *
129660b08185Syz147069  * if data was sent successfully, 'mpp' will be nulled to indicate
129760b08185Syz147069  * that mblk is consumed by USBA and no longer belongs to the caller.
129860b08185Syz147069  *
129960b08185Syz147069  * if this function returns USB_SUCCESS, pipe is acquired and request
130060b08185Syz147069  * is sent, otherwise pipe is free.
130160b08185Syz147069  */
130260b08185Syz147069 int
130360b08185Syz147069 keyspan_send_data(keyspan_pipe_t *bulkout, mblk_t **mpp, void *cb_arg)
130460b08185Syz147069 {
130560b08185Syz147069 	keyspan_state_t	*ksp = bulkout->pipe_ksp;
130660b08185Syz147069 	usb_bulk_req_t	*br;
130760b08185Syz147069 	int		rval;
130860b08185Syz147069 
130960b08185Syz147069 	ASSERT(!mutex_owned(&bulkout->pipe_mutex));
131060b08185Syz147069 	USB_DPRINTF_L4(DPRINT_OUT_PIPE, bulkout->pipe_lh,
131160b08185Syz147069 	    "keyspan_send_data");
131260b08185Syz147069 
131360b08185Syz147069 	br = usb_alloc_bulk_req(ksp->ks_dip, 0, USB_FLAGS_SLEEP);
131460b08185Syz147069 	br->bulk_len = MBLKL(*mpp);
131560b08185Syz147069 	br->bulk_data = *mpp;
131660b08185Syz147069 	br->bulk_timeout = KEYSPAN_BULK_TIMEOUT;
131760b08185Syz147069 	br->bulk_client_private = cb_arg;
131860b08185Syz147069 	br->bulk_attributes = USB_ATTRS_AUTOCLEARING;
131960b08185Syz147069 	br->bulk_cb = keyspan_bulkout_cb;
132060b08185Syz147069 	br->bulk_exc_cb = keyspan_bulkout_cb;
132160b08185Syz147069 
132260b08185Syz147069 	USB_DPRINTF_L3(DPRINT_OUT_PIPE, bulkout->pipe_lh, "keyspan_send_data:"
132360b08185Syz147069 	    "bulk_len = %d", br->bulk_len);
132460b08185Syz147069 
132560b08185Syz147069 	rval = usb_pipe_bulk_xfer(bulkout->pipe_handle, br, 0);
132660b08185Syz147069 	if (rval == USB_SUCCESS) {
132760b08185Syz147069 
132860b08185Syz147069 		/* data consumed. The mem will be released in bulkout_cb */
132960b08185Syz147069 		*mpp = NULL;
133060b08185Syz147069 	} else {
133160b08185Syz147069 
133260b08185Syz147069 		/*
133360b08185Syz147069 		 * Don't free it in usb_free_bulk_req because it will
133460b08185Syz147069 		 * be linked in keyspan_put_head
133560b08185Syz147069 		 */
133660b08185Syz147069 		br->bulk_data = NULL;
133760b08185Syz147069 
133860b08185Syz147069 		usb_free_bulk_req(br);
133960b08185Syz147069 	}
134060b08185Syz147069 	USB_DPRINTF_L4(DPRINT_OUT_PIPE, bulkout->pipe_lh,
134160b08185Syz147069 	    "keyspan_send_data: rval = %d", rval);
134260b08185Syz147069 
134360b08185Syz147069 	return (rval);
134460b08185Syz147069 }
1345