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