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