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