/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
*
* keyspanport pipe routines (mostly device-neutral)
*
*/
/*
* initialize pipe structure with the given parameters
*/
static void
{
/* init sync primitives */
/* init pipe policy */
/* globle pipes should have device log handle */
} else {
/* port pipes should have port log handle */
}
}
static void
{
}
}
/*
* Lookup the endpoints defined in the spec;
* Allocate resources, initialize pipe structures.
*/
int
{
alt = 0;
/*
* The actual EP number (indicated by bNumEndpoints) is more than
* those defined in spec. We have to match those we need according
* to EP addresses. And we'll lookup In EPs and Out EPs separately.
*/
/*
* get DIR_IN EP descriptors, and then match with EP addresses.
* Different keyspan devices may has different EP addresses.
*/
for (i = 0; i < ep_cnt; i++) {
"keyspan_init_pipes: can't find bulk in ep, i=%d,"
"ep_cnt=%d", i, ep_cnt);
continue;
}
"ep_addr =%x, stat_ep_addr=%x, i=%d", ep_addr,
/* match the status EP */
continue;
}
/* match the EPs of the ports */
for (j = 0; j < port_cnt; j++) {
"keyspan_init_pipes: try to match bulk in data ep,"
" j=%d", j);
k++;
"keyspan_init_pipes: matched a bulk in"
" data ep");
break;
}
}
/* if have matched all the necessary endpoints, break out */
break;
}
"try to match bulk in data ep, j=%d", j);
if (j == port_cnt) {
/* this ep can't be matched by any addr */
"keyspan_init_pipes: can't match bulk in ep,"
" addr =%x,", ep_addr);
}
}
/* Some of the necessary IN endpoints are not matched */
"keyspan_init_pipes: matched %d data in endpoints,"
" not enough", k);
return (USB_FAILURE);
}
k = 0;
/*
* get DIR_OUT EP descriptors, and then match with ep addrs.
* different keyspan devices may has different ep addresses.
*/
for (i = 0; i < ep_cnt; i++) {
"keyspan_init_pipes: can't find bulk out ep, i=%d,"
"ep_cnt=%d", i, ep_cnt);
continue;
}
/* match the status ep */
continue;
}
/* match the ep of the ports */
for (j = 0; j < port_cnt; j++) {
k++;
break;
}
}
/* if have matched all the necessary endpoints, break out */
break;
}
if (j == port_cnt) {
/* this ep can't be matched by any addr */
"keyspan_init_pipes: can't match bulk out ep,"
" ep_addr =%x", ep_addr);
}
}
/* Not all the necessary OUT endpoints are matched */
"keyspan_init_pipes: matched %d data in endpoints,"
" not enough", k);
return (USB_FAILURE);
}
/*
* Device globle pipes: a bulk in pipe for status and a bulk out
* pipe for controle cmd.
*/
for (i = 0; i < port_cnt; i++) {
}
return (USB_SUCCESS);
}
/*
* For USA_49WG only.
* Lookup the endpoints defined in the spec.
* Allocate resources, initialize pipe structures.
* There are 6 EPs, 3 bulk out Eps, 1 bulk in EP, 1 intr in EP, 1 intr out EP
*/
int
{
alt = 0;
/*
* get intr out EP descriptor as port0 data out EP, and then
* match with EP address.
* Different keyspan devices may has different EP addresses.
*/
"keyspan_init_pipes: can't find port1 data out ep");
return (USB_FAILURE);
}
/* match the port0 data out EP */
}
/*
* get bulk out EP descriptors as other port data out EPs, and then
* match with EP addresses.
*/
for (j = 1; j < port_cnt; j++) {
"keyspan_init_pipes: can't find port[%d] "
"data out ep",
j);
return (USB_FAILURE);
}
/* match other port data out EPs */
}
}
/*
* get intr in EP descriptor as status EP, and then match with EP addrs
*/
"keyspan_init_pipes: can't find status in ep");
return (USB_FAILURE);
}
/* match the status ep */
}
/*
* get bulk in EP descriptors as data in EP, All the ports share one
* data in EP.
*/
"keyspan_init_pipes: can't find bulk in ep");
return (USB_FAILURE);
}
/* match data in EPs */
}
/* intr in pipe for status */
for (i = 0; i < port_cnt; i++) {
}
return (USB_SUCCESS);
}
void
{
int i;
}
/* fini status pipe */
/*
* fini control pipe
* If USA_49WG, don't need fini control pipe
*/
case KEYSPAN_USA19HS_PID:
case KEYSPAN_USA49WLC_PID:
break;
case KEYSPAN_USA49WG_PID:
break;
default:
"keyspan_fini_pipes: the device's product id"
"can't be recognized");
}
}
static int
{
int rval;
/* don't open for the second time */
return (USB_SUCCESS);
}
if (rval == USB_SUCCESS) {
}
return (rval);
}
/*
* Open shared datain pipe for USA_49WG
*/
static int
{
/* don't open for the second time */
return (USB_SUCCESS);
}
} else {
}
return (rval);
} else {
/* data in pipe has been opened by other port */
/* Set datain pipe state */
return (USB_SUCCESS);
}
}
/*
* close one pipe if open
*/
static void
{
/*
* pipe may already be closed, e.g. if device has been physically
* disconnected and the driver immediately detached
*/
}
}
/*
* close shared datain pipe if open for USA_49WG
*/
static void
{
/*
* pipe may already be closed, e.g. if device has been physically
* disconnected and the driver immediately detached
*/
if (!ksp->ks_datain_open_cnt) {
} else {
}
}
}
/*
* For USA19HS and USA49WLC:
* Open global pipes, a status pipe and a control pipe
*/
int
{
int rval;
"keyspan_open_dev_pipes_usa49");
if (rval != USB_SUCCESS) {
"keyspan_open_dev_pipes_usa49: open ctrl pipe failed %d",
rval);
return (rval);
}
if (rval != USB_SUCCESS) {
"keyspan_open_dev_pipes_usa49: open status pipe failed %d",
rval);
/* close the first opened pipe here */
return (rval);
}
/* start receive device status */
if (rval != USB_SUCCESS) {
"keyspan_open_dev_pipes_usa49: receive device status"
" failed %d", rval);
/* close opened pipes here */
return (rval);
}
return (rval);
}
/*
* For keyspan USA_49WG:
* Open global pipes, a status pipe
* Use default control pipe, don't need to open it.
*/
int
{
int rval;
/* Open status pipe */
if (rval != USB_SUCCESS) {
"keyspan_open_dev_pipes_usa49wg: "
"open status pipe failed %d",
rval);
return (rval);
}
/* start device polling */
return (rval);
}
/*
* Open global pipes, status pipe and control pipe,
*/
int
{
case KEYSPAN_USA19HS_PID:
case KEYSPAN_USA49WLC_PID:
break;
case KEYSPAN_USA49WG_PID:
break;
default:
"keyspan_open_dev_pipes: the device's product id can't"
"be recognized");
return (USB_FAILURE);
}
return (rval);
}
/*
* Reopen all pipes if the port had them open
*/
int
{
int i;
return (USB_FAILURE);
}
"keyspan_reopen_pipes() reopen pipe #%d", i);
return (USB_FAILURE);
}
}
}
return (USB_SUCCESS);
}
void
{
case KEYSPAN_USA19HS_PID:
case KEYSPAN_USA49WLC_PID:
break;
case KEYSPAN_USA49WG_PID:
break;
default:
"keyspan_close_port_pipes:"
"the device's product id can't be recognized");
}
}
/*
* Close IN and OUT bulk pipes of all ports
*/
void
{
int i;
case KEYSPAN_USA19HS_PID:
case KEYSPAN_USA49WLC_PID:
} else {
}
}
break;
case KEYSPAN_USA49WG_PID:
port_num = i;
}
}
if (port_num >= 0) {
}
} else {
}
}
break;
default:
"keyspan_close_open_pipes:"
"the device's product id can't be recognized");
}
}
/*
* Close global pipes
*/
void
{
case KEYSPAN_USA19HS_PID:
case KEYSPAN_USA49WLC_PID:
break;
case KEYSPAN_USA49WG_PID:
/*
* USA_49WG use default control pipe, don't need close it
* Stop polling before close status in pipe
*/
break;
default:
"keyspan_close_dev_pipes:"
"the device's product id can't be recognized");
}
}
/*
* Open bulk data IN and data OUT pipes for one port.
* The status and control pipes are opened in attach because they are global.
*/
int
{
int rval;
case KEYSPAN_USA19HS_PID:
case KEYSPAN_USA49WLC_PID:
break;
case KEYSPAN_USA49WG_PID:
&kp->kp_datain_pipe);
break;
default:
"keyspan_open_port_pipes:"
"the device's product id can't be recognized");
}
if (rval != USB_SUCCESS) {
goto fail;
}
if (rval != USB_SUCCESS) {
goto fail;
}
return (rval);
fail:
"keyspan_open_port_pipes: failed %d", rval);
return (rval);
}
void
{
}
/*
* bulk out common callback
*/
/*ARGSUSED*/
void
{
int data_len;
"keyspan_bulkout_cb: len=%d cr=%d cb_flags=%x",
/*
* Data wasn't transfered successfully.
* Put data back on the queue.
*/
/* don't release mem in usb_free_bulk_req */
}
/* if more data available, kick off another transmit */
/*
* Attach a zero packet if data length is muliple of 64,
* due to the specification of keyspan_usa19hs.
*/
return;
}
}
/* no more data, notify waiters */
/* tx callback for this port */
} else {
}
}
/*
* intr out common callback for USA_49WG port0 only
*/
/*ARGSUSED*/
void
{
int data_len;
"keyspan_introut_cb_usa49wg: len=%d cr=%d cb_flags=%x",
/*
* Data wasn't transfered successfully.
* Put data back on the queue.
*/
/* don't release mem in usb_free_bulk_req */
}
/* if more data available, kick off another transmit */
/* no more data, notify waiters */
/* tx callback for this port */
} else {
}
}
/* For incoming data only. Parse a status byte and return the err code */
void
{
if (*status & RXERROR_BREAK) {
/*
* Parity and Framing errors only count if they
* occur exclusive of a break being received.
*/
}
}
/* Bulk in data process function, used by all models */
int
{
/*
* According to Keyspan spec, if 0x80 bit is clear, there is
* only one status byte at the head of the data buf; if 0x80 bit
* set, then data buf contains alternate status and data bytes;
* In the first case, only OVERRUN err can exist; In the second
* case, there are four kinds of err bits may appear in status.
*/
/* if 0x80 bit AND overrun bit are clear, just send up data */
/* Get rid of the first status byte */
data_len--;
} else if (!(status & 0x80)) {
/* If 0x80 bit is clear and overrun bit is set */
"keyspan_bulkin_cb_process: allocb failed");
return (0);
}
/* Add to the received list; Send up the err code. */
/*
* Don't send up the first byte because
* it is a status byte.
*/
data_len--;
} else { /* 0x80 bit set, there are some errs in the data */
/*
* Usually, there are at least two bytes,
* one status and one data.
*/
if (data_len > 1) {
int i = 0;
int j = 1;
/*
* In this case, there might be multi status
* bytes. Parse each status byte and move the
* data bytes together.
*/
/* move the data togeter */
i++;
}
} else { /* There are only one byte in incoming buf */
}
"keyspan_bulkin_cb_process: allocb failed");
return (0);
}
if (data_len > 2) {
/*
* There are multiple status bytes in this case.
* Use err as status character since err is got
* by or in all status bytes.
*/
} else {
}
/* Add to the received list; Send up the err code. */
if (data_len > 1) {
}
}
return (data_len);
}
/*
* pipe callbacks
* --------------
*
* bulk in common callback for USA19HS and USA49WLC model
*/
/*ARGSUSED*/
int
{
int data_len;
"keyspan_bulkin_cb_usa49: len=%d"
/* put data on the read queue */
/*
* the data will not be freed and
* will be sent up later.
*/
}
} else {
/* usb error happened, so don't send up data */
data_len = 0;
"keyspan_bulkin_cb_usa49: port_state=%d"
}
}
return (data_len);
}
/*
* pipe callbacks
* --------------
*
* bulk in common callback for USA_49WG model
*/
/*ARGSUSED*/
void
{
*kp_true;
*mp_data;
port_cnt = 0,
unsigned char *old_rptr;
"keyspan_bulkin_cb_usa49wg: len=%d"
/* put data on the read queue */
if (port_num > 3) {
"keyspan_bulkin_cb_usa49wg,port num is not"
" correct: port=%d, len=%d, status=%x",
break;
}
"keyspan_bulkin_cb_usa49wg, "
"port isn't opened");
port_cnt--;
continue;
}
"keyspan_bulkin_cb_usa49wg: status=0x%x, len=%d",
== NULL) {
"usa49wg: allocb failed");
return;
}
/*
* data has multi status bytes, b_wptr
* has changed by
* keyspan_bulkin_process(), need to
* be recovered to old one
*/
} else {
}
} else {
break;
}
} /* End of while loop */
while (port_cnt) {
}
/* kick off another read */
(void) keyspan_receive_data(
receive_flag = 0;
} else {
}
/* setup rx callback for this port */
}
} else {
/* cr != USB_CR_OK, usb error happened */
"keyspan_bulkin_cb_usa49wg: port=%d, len=%d, status=%x",
}
if (!kp->kp_no_more_reads) {
/* kick off another read */
} else {
}
}
}
/*
* pipe callbacks
* --------------
*
* bulk in common callback for USA19HS and USA49WLC
*/
/*ARGSUSED*/
void
{
int data_len;
"keyspan_bulkin_cb");
/* put data on the read queue */
/* kick off another read unless indicated otherwise */
if (!no_more_reads) {
}
/* setup rx callback for this port */
if (data_len > 0) {
}
}
/*
* pipe callbacks
* --------------
*
* bulk in status callback for usa19hs model
*/
/*ARGSUSED*/
void
{
int data_len;
"keyspan_status_cb_usa19hs: len=%d"
/* put data on the read queue */
if (status_msg->controlResponse) {
} else {
}
} else {
}
} else {
}
if (status_msg->rxBreak) {
} else {
}
} else {
}
/* if msr status changed, then invoke status callback */
} else {
}
} else {
"keyspan_status_cb_usa19hs: get status failed, cr=%d"
}
}
/*
* pipe callbacks
* --------------
*
* bulk in status callback for usa49 model
*/
/*ARGSUSED*/
void
{
int data_len;
"keyspan_status_cb_usa49: len=%d"
/* put data on the read queue */
return;
}
/* if msr status changed, then need invoke status callback */
}
if (kp_status_msg->controlResponse) {
} else {
}
if (!kp_status_msg->rxEnabled) {
} else {
}
if (need_cb) {
}
} else {
"keyspan_status_cb_usa49: get status failed, cr=%d"
}
}
/*
* pipe callbacks
* --------------
*
* bulk in callback for status receiving
*/
/*ARGSUSED*/
void
{
"keyspan_status_cb");
/* put data on the read queue */
case KEYSPAN_USA19HS_PID:
break;
case KEYSPAN_USA49WLC_PID:
break;
default:
"the device's product id can't be recognized");
return;
}
/* kick off another read to receive status */
"keyspan_status_cb:"
"receive status can't be restarted.");
}
} else {
"get status failed: cr=%d", cr);
}
}
/*
* Submit data read request (asynchronous). If this function returns
* USB_SUCCESS, pipe is acquired and request is sent, otherwise req is free.
*/
int
{
"len=%d", len);
/* No timeout, just wait for data */
br->bulk_timeout = 0;
case KEYSPAN_USA19HS_PID:
case KEYSPAN_USA49WLC_PID:
break;
case KEYSPAN_USA49WG_PID:
break;
default:
"the device's product id can't be recognized");
return (USB_FAILURE);
}
if (rval != USB_SUCCESS) {
}
"keyspan_receive_data: rval = %d", rval);
return (rval);
}
/*
* submit device status read request (asynchronous).
*/
int
{
int rval;
"keyspan_receive_status");
/* No timeout, just wait for data */
br->bulk_timeout = 0;
if (rval != USB_SUCCESS) {
}
"keyspan_receive_status: rval = %d", rval);
return (rval);
}
/*
* submit data for transfer (asynchronous)
*
* if data was sent successfully, 'mpp' will be nulled to indicate
* that mblk is consumed by USBA and no longer belongs to the caller.
*
* if this function returns USB_SUCCESS, pipe is acquired and request
* is sent, otherwise pipe is free.
*/
int
{
int rval;
"keyspan_send_data");
if (rval == USB_SUCCESS) {
/* data consumed. The mem will be released in bulkout_cb */
} else {
/*
* Don't free it in usb_free_bulk_req because it will
* be linked in keyspan_put_head
*/
}
"keyspan_send_data: rval = %d", rval);
return (rval);
}
/*
* submit data for transfer (asynchronous) for USA_49WG Port0 only
*
* if data was sent successfully, 'mpp' will be nulled to indicate
* that mblk is consumed by USBA and no longer belongs to the caller.
*
* if this function returns USB_SUCCESS, pipe is acquired and request
* is sent, otherwise pipe is free.
*/
int
{
int rval;
"keyspan_send_data_port0");
"keyspan_send_data_port0: intr_len = %d",
if (rval == USB_SUCCESS) {
/*
* data consumed. The mem will be released in
* introut_cb_usa49wg
*/
} else {
}
"keyspan_send_data_port0: rval = %d", rval);
return (rval);
}
/*
* pipe callbacks
* --------------
*
* bulk in status callback for USA_49WG model
*/
/*ARGSUSED*/
void
{
int data_len;
"keyspan_status_cb_usa49wg: len=%d"
/* put data on the read queue */
return;
}
/* if msr status changed, then need invoke status callback */
}
if (kp_status_msg->controlResponse) {
} else {
}
if (!kp_status_msg->rxEnabled) {
} else {
}
if (need_cb) {
}
} else {
"keyspan_status_cb_usa49wg: get status failed, cr=%d"
}
}
/*
* pipe callbacks
* --------------
*
* intr in callback for status receiving for USA_49WG model only
*/
/*ARGSUSED*/
void
{
"keyspan_intr_cb_usa49wg: cr=%d", cr);
/* put data on the read queue */
}
/*
* pipe callbacks
* --------------
*
* intr in exception callback for status receiving for USA_49WG model only
*/
/*ARGSUSED*/
void
{
"keyspan_intr_ex_cb_usa49wg: cr=%d", cr);
} else {
"keyspan_intr_ex_cb_usa49wg:"
"get status failed: cr=%d", cr);
}
}
/*
* start polling on the interrupt pipe for USA_49WG model only
*/
void
{
int rval;
"keyspan_pipe_start_polling");
/*
* If it is in interrupt context, usb_alloc_intr_req will return NULL if
* called with SLEEP flag.
*/
if (!br) {
"keyspan_pipe_start_polling: alloc req failed.");
return;
}
if (rval != USB_SUCCESS) {
"keyspan_pipe_start_polling: failed (%d)", rval);
} else {
}
}