keyspan_pipe.c revision 688b07c52de0fc886cce2e0a28a42a43d2dad06a
/*
* 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 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
*
* 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);
}
void
{
int i;
}
/* fini global pipes */
}
static int
{
int rval;
/* don't open for the second time */
return (USB_SUCCESS);
}
if (rval == USB_SUCCESS) {
}
return (rval);
}
/*
* 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
*/
}
}
/*
* Open global pipes, a status pipe and a control pipe
*/
int
{
int rval;
if (rval != USB_SUCCESS) {
"keyspan_open_dev_pipes: open ctrl pipe failed %d", rval);
return (rval);
}
if (rval != USB_SUCCESS) {
"keyspan_open_dev_pipes: 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: receive device status failed %d",
rval);
/* close opened pipes here */
return (rval);
}
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
{
}
/*
* Close IN and OUT bulk pipes of all ports
*/
void
{
int i;
} else {
}
}
}
/*
* Close global pipes
*/
void
{
}
/*
* 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;
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 {
}
}
/* 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.
*/
}
}
/*
* pipe callbacks
* --------------
*
* bulk in common callback for usa19hs model
*/
/*ARGSUSED*/
int
{
int data_len;
"keyspan_bulkin_cb_usa19hs: len=%d"
" cr=%d flags=%x baud=%x",
/* put data on the read queue */
/*
* 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 */
"keyspan_bulkin_cb_usa19hs: len=%d",
data_len);
/* Get rid of the first status byte and send up data */
data_len--;
if (data_len > 0) {
/*
* the data will not be freed and
* will be sent up later.
*/
}
} else if (!(status & 0x80)) {
/* If 0x80 bit is clear and overrun bit is set */
"keyspan_bulkin_cb_usa19hs: usb xfer is OK,"
" but there is overrun err in serial xfer");
"keyspan_bulkin_cb_usa19hs: 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--;
if (data_len > 0) {
/*
* the data will not be freed and
* will be sent up later.
*/
}
} else { /* 0x80 bit set, there are some errs in the data */
"keyspan_bulkin_cb_usa19hs: usb xfer is OK,"
" but there are errs in serial xfer");
/*
* 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_usa19hs: 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) {
/*
* 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_usa19hs: error happened, len=%d, "
}
}
return (data_len);
}
/*
* pipe callbacks
* --------------
*
* bulk in common callback for usa49 model
*/
/*ARGSUSED*/
int
{
int data_len;
"keyspan_bulkin_cb_usa49: len=%d"
/* put data on the read queue */
/*
* 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 */
"keyspan_bulkin_cb_usa49: len=%d",
data_len);
/* Get rid of the first status byte and send up data */
data_len--;
if (data_len > 0) {
/*
* the data will not be freed and
* will be sent up later.
*/
}
} else if (!(status & 0x80)) {
/* If 0x80 bit is clear and overrun bit is set */
"keyspan_bulkin_cb_usa49: usb xfer is OK,"
" but there is overrun err in serial xfer");
"keyspan_bulkin_cb_usa49: 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--;
if (data_len > 0) {
/*
* the data will not be freed and
* will be sent up later.
*/
}
} else { /* 0x80 bit set, there are some errs in the data */
"keyspan_bulkin_cb_usa49: usb xfer is OK,"
" but there are errs in serial xfer");
/*
* 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_usa49: 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) {
/*
* 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
*/
/*ARGSUSED*/
void
{
int data_len;
"keyspan_bulkin_cb");
/* put data on the read queue */
case KEYSPAN_USA19HS_PID:
break;
case KEYSPAN_USA49WLC_PID:
break;
default:
"keyspan_bulkin_cb:"
"the device's product id can't be recognized");
return;
}
/* 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
{
int rval;
"len=%d", len);
/* No timeout, just wait for data */
br->bulk_timeout = 0;
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);
}