#include <sys/types.h>
#include <sys/param.h>
#include <sys/conf.h>
#include <sys/stream.h>
#include <sys/strsun.h>
#include <sys/termio.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/usb/usba.h>
#include <sys/usb/clients/usbser/usbser_keyspan/keyspan_var.h>
#include <sys/usb/clients/usbser/usbser_keyspan/keyspan_pipe.h>
static void
keyspan_init_one_pipe(keyspan_state_t *ksp, keyspan_port_t *kp,
keyspan_pipe_t *pipe)
{
usb_pipe_policy_t *policy;
USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, "keyspan_init_one_pipe: "
"pipe = %p, pipe_stat %x", (void *)pipe, pipe->pipe_state);
mutex_init(&pipe->pipe_mutex, NULL, MUTEX_DRIVER, (void *)NULL);
policy = &pipe->pipe_policy;
policy->pp_max_async_reqs = 2;
pipe->pipe_ksp = ksp;
if (kp == NULL) {
pipe->pipe_lh = ksp->ks_lh;
} else {
pipe->pipe_lh = kp->kp_lh;
}
pipe->pipe_state = KEYSPAN_PIPE_CLOSED;
}
static void
keyspan_fini_one_pipe(keyspan_pipe_t *pipe)
{
USB_DPRINTF_L4(DPRINT_OPEN, pipe->pipe_ksp->ks_lh,
"keyspan_fini_one_pipe: pipe_stat %x", pipe->pipe_state);
if (pipe->pipe_state != KEYSPAN_PIPE_NOT_INIT) {
mutex_destroy(&pipe->pipe_mutex);
pipe->pipe_state = KEYSPAN_PIPE_NOT_INIT;
}
}
int
keyspan_init_pipes(keyspan_state_t *ksp)
{
usb_client_dev_data_t *dev_data = ksp->ks_dev_data;
int ifc, alt, i, j, k = 0;
uint8_t port_cnt = ksp->ks_dev_spec.port_cnt;
uint8_t ep_addr, ep_cnt;
usb_ep_data_t *dataout[KEYSPAN_MAX_PORT_NUM],
*datain[KEYSPAN_MAX_PORT_NUM],
*status = NULL, *ctrl = NULL, *tmp_ep;
usb_alt_if_data_t *alt_data;
usb_if_data_t *if_data;
ifc = dev_data->dev_curr_if;
alt = 0;
if_data = &dev_data->dev_curr_cfg->cfg_if[ifc];
alt_data = &if_data->if_alt[alt];
ep_cnt = (alt_data->altif_descr.bNumEndpoints + 1) / 2;
for (i = 0; i < ep_cnt; i++) {
tmp_ep = usb_lookup_ep_data(ksp->ks_dip, dev_data, ifc, alt, i,
USB_EP_ATTR_BULK, USB_EP_DIR_IN);
if (tmp_ep == NULL) {
USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh,
"keyspan_init_pipes: can't find bulk in ep, i=%d,"
"ep_cnt=%d", i, ep_cnt);
continue;
}
ep_addr = tmp_ep->ep_descr.bEndpointAddress;
USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh, "keyspan_init_pipes: "
"ep_addr =%x, stat_ep_addr=%x, i=%d", ep_addr,
ksp->ks_dev_spec.stat_ep_addr, i);
if (ep_addr == ksp->ks_dev_spec.stat_ep_addr) {
status = tmp_ep;
continue;
}
for (j = 0; j < port_cnt; j++) {
USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh,
"keyspan_init_pipes: try to match bulk in data ep,"
" j=%d", j);
if (ep_addr == ksp->ks_dev_spec.datain_ep_addr[j]) {
datain[j] = tmp_ep;
k++;
USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh,
"keyspan_init_pipes: matched a bulk in"
" data ep");
break;
}
}
if (k >= port_cnt && status != NULL) {
break;
}
USB_DPRINTF_L4(DPRINT_ATTACH, ksp->ks_lh, "keyspan_init_pipes: "
"try to match bulk in data ep, j=%d", j);
if (j == port_cnt) {
USB_DPRINTF_L4(DPRINT_ATTACH, ksp->ks_lh,
"keyspan_init_pipes: can't match bulk in ep,"
" addr =%x,", ep_addr);
}
}
if (k != port_cnt || status == NULL) {
USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
"keyspan_init_pipes: matched %d data in endpoints,"
" not enough", k);
return (USB_FAILURE);
}
k = 0;
for (i = 0; i < ep_cnt; i++) {
tmp_ep = usb_lookup_ep_data(ksp->ks_dip, dev_data, ifc, alt, i,
USB_EP_ATTR_BULK, USB_EP_DIR_OUT);
if (tmp_ep == NULL) {
USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh,
"keyspan_init_pipes: can't find bulk out ep, i=%d,"
"ep_cnt=%d", i, ep_cnt);
continue;
}
ep_addr = tmp_ep->ep_descr.bEndpointAddress;
if (ep_addr == ksp->ks_dev_spec.ctrl_ep_addr) {
ctrl = tmp_ep;
continue;
}
for (j = 0; j < port_cnt; j++) {
if (ep_addr == ksp->ks_dev_spec.dataout_ep_addr[j]) {
dataout[j] = tmp_ep;
k++;
break;
}
}
if (k >= port_cnt && ctrl != NULL) {
break;
}
if (j == port_cnt) {
USB_DPRINTF_L4(DPRINT_ATTACH, ksp->ks_lh,
"keyspan_init_pipes: can't match bulk out ep,"
" ep_addr =%x", ep_addr);
}
}
if (k != port_cnt || ctrl == NULL) {
USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
"keyspan_init_pipes: matched %d data in endpoints,"
" not enough", k);
return (USB_FAILURE);
}
mutex_enter(&ksp->ks_mutex);
ksp->ks_statin_pipe.pipe_ep_descr = status->ep_descr;
keyspan_init_one_pipe(ksp, NULL, &ksp->ks_statin_pipe);
ksp->ks_ctrlout_pipe.pipe_ep_descr = ctrl->ep_descr;
keyspan_init_one_pipe(ksp, NULL, &ksp->ks_ctrlout_pipe);
for (i = 0; i < port_cnt; i++) {
ksp->ks_ports[i].kp_datain_pipe.pipe_ep_descr =
datain[i]->ep_descr;
keyspan_init_one_pipe(ksp, &ksp->ks_ports[i],
&ksp->ks_ports[i].kp_datain_pipe);
ksp->ks_ports[i].kp_dataout_pipe.pipe_ep_descr =
dataout[i]->ep_descr;
keyspan_init_one_pipe(ksp, &ksp->ks_ports[i],
&ksp->ks_ports[i].kp_dataout_pipe);
}
mutex_exit(&ksp->ks_mutex);
return (USB_SUCCESS);
}
int
keyspan_init_pipes_usa49wg(keyspan_state_t *ksp)
{
usb_client_dev_data_t *dev_data = ksp->ks_dev_data;
int ifc, alt, i, j = 0;
uint8_t port_cnt = ksp->ks_dev_spec.port_cnt;
uint8_t ep_addr;
usb_ep_data_t *dataout[KEYSPAN_MAX_PORT_NUM],
*datain[KEYSPAN_MAX_PORT_NUM],
*status = NULL, *tmp_ep;
ifc = dev_data->dev_curr_if;
alt = 0;
tmp_ep = usb_lookup_ep_data(ksp->ks_dip, dev_data, ifc, alt, 0,
USB_EP_ATTR_INTR, USB_EP_DIR_OUT);
if (tmp_ep == NULL) {
USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh,
"keyspan_init_pipes: can't find port1 data out ep");
return (USB_FAILURE);
}
ep_addr = tmp_ep->ep_descr.bEndpointAddress;
if (ep_addr == ksp->ks_dev_spec.dataout_ep_addr[0]) {
dataout[0] = tmp_ep;
}
for (j = 1; j < port_cnt; j++) {
tmp_ep = usb_lookup_ep_data(ksp->ks_dip, dev_data, ifc, alt,
j-1, USB_EP_ATTR_BULK, USB_EP_DIR_OUT);
if (tmp_ep == NULL) {
USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh,
"keyspan_init_pipes: can't find port[%d] "
"data out ep",
j);
return (USB_FAILURE);
}
ep_addr = tmp_ep->ep_descr.bEndpointAddress;
if (ep_addr == ksp->ks_dev_spec.dataout_ep_addr[j]) {
dataout[j] = tmp_ep;
}
}
tmp_ep = usb_lookup_ep_data(ksp->ks_dip, dev_data, ifc, alt, 0,
USB_EP_ATTR_INTR, USB_EP_DIR_IN);
if (tmp_ep == NULL) {
USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh,
"keyspan_init_pipes: can't find status in ep");
return (USB_FAILURE);
}
ep_addr = tmp_ep->ep_descr.bEndpointAddress;
if (ep_addr == ksp->ks_dev_spec.stat_ep_addr) {
status = tmp_ep;
}
tmp_ep = usb_lookup_ep_data(ksp->ks_dip, dev_data, ifc, alt, 0,
USB_EP_ATTR_BULK, USB_EP_DIR_IN);
if (tmp_ep == NULL) {
USB_DPRINTF_L3(DPRINT_ATTACH, ksp->ks_lh,
"keyspan_init_pipes: can't find bulk in ep");
return (USB_FAILURE);
}
ep_addr = tmp_ep->ep_descr.bEndpointAddress;
if (ep_addr == ksp->ks_dev_spec.datain_ep_addr[0]) {
datain[0] = tmp_ep;
}
mutex_enter(&ksp->ks_mutex);
ksp->ks_statin_pipe.pipe_ep_descr = status->ep_descr;
keyspan_init_one_pipe(ksp, NULL, &ksp->ks_statin_pipe);
for (i = 0; i < port_cnt; i++) {
ksp->ks_ports[i].kp_datain_pipe.pipe_ep_descr =
datain[0]->ep_descr;
keyspan_init_one_pipe(ksp, &ksp->ks_ports[i],
&ksp->ks_ports[i].kp_datain_pipe);
ksp->ks_ports[i].kp_dataout_pipe.pipe_ep_descr =
dataout[i]->ep_descr;
keyspan_init_one_pipe(ksp, &ksp->ks_ports[i],
&ksp->ks_ports[i].kp_dataout_pipe);
}
mutex_exit(&ksp->ks_mutex);
return (USB_SUCCESS);
}
void
keyspan_fini_pipes(keyspan_state_t *ksp)
{
keyspan_port_t *kp;
int i;
for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) {
kp = &ksp->ks_ports[i];
keyspan_fini_one_pipe(&kp->kp_datain_pipe);
keyspan_fini_one_pipe(&kp->kp_dataout_pipe);
}
keyspan_fini_one_pipe(&ksp->ks_statin_pipe);
switch (ksp->ks_dev_spec.id_product) {
case KEYSPAN_USA19HS_PID:
case KEYSPAN_USA49WLC_PID:
keyspan_fini_one_pipe(&ksp->ks_ctrlout_pipe);
break;
case KEYSPAN_USA49WG_PID:
break;
default:
USB_DPRINTF_L2(DPRINT_CTLOP, ksp->ks_lh,
"keyspan_fini_pipes: the device's product id"
"can't be recognized");
}
}
static int
keyspan_open_one_pipe(keyspan_state_t *ksp, keyspan_pipe_t *pipe)
{
int rval;
mutex_enter(&pipe->pipe_mutex);
ASSERT(pipe->pipe_state != KEYSPAN_PIPE_NOT_INIT);
if (pipe->pipe_state != KEYSPAN_PIPE_CLOSED) {
mutex_exit(&pipe->pipe_mutex);
return (USB_SUCCESS);
}
mutex_exit(&pipe->pipe_mutex);
rval = usb_pipe_open(ksp->ks_dip, &pipe->pipe_ep_descr,
&pipe->pipe_policy, USB_FLAGS_SLEEP, &pipe->pipe_handle);
if (rval == USB_SUCCESS) {
mutex_enter(&pipe->pipe_mutex);
pipe->pipe_state = KEYSPAN_PIPE_OPEN;
mutex_exit(&pipe->pipe_mutex);
}
return (rval);
}
static int
keyspan_open_pipe_datain_usa49wg(keyspan_state_t *ksp, keyspan_pipe_t *pipe)
{
int rval = USB_SUCCESS;
mutex_enter(&pipe->pipe_mutex);
ASSERT(pipe->pipe_state != KEYSPAN_PIPE_NOT_INIT);
if (pipe->pipe_state != KEYSPAN_PIPE_CLOSED) {
mutex_exit(&pipe->pipe_mutex);
return (USB_SUCCESS);
}
mutex_exit(&pipe->pipe_mutex);
mutex_enter(&ksp->ks_mutex);
ksp->ks_datain_open_cnt++;
if (ksp->ks_datain_open_cnt == 1) {
mutex_exit(&ksp->ks_mutex);
if ((rval = (usb_pipe_open(ksp->ks_dip, &pipe->pipe_ep_descr,
&pipe->pipe_policy, USB_FLAGS_SLEEP,
&pipe->pipe_handle))) == USB_SUCCESS) {
mutex_enter(&pipe->pipe_mutex);
pipe->pipe_state = KEYSPAN_PIPE_OPEN;
mutex_exit(&pipe->pipe_mutex);
mutex_enter(&ksp->ks_mutex);
ksp->ks_datain_pipe_handle = pipe->pipe_handle;
mutex_exit(&ksp->ks_mutex);
} else {
mutex_enter(&ksp->ks_mutex);
ksp->ks_datain_open_cnt--;
mutex_exit(&ksp->ks_mutex);
}
return (rval);
} else {
ASSERT(ksp->ks_datain_pipe_handle != NULL);
mutex_enter(&pipe->pipe_mutex);
pipe->pipe_handle = ksp->ks_datain_pipe_handle;
pipe->pipe_state = KEYSPAN_PIPE_OPEN;
mutex_exit(&pipe->pipe_mutex);
mutex_exit(&ksp->ks_mutex);
return (USB_SUCCESS);
}
}
static void
keyspan_close_one_pipe(keyspan_pipe_t *pipe)
{
if (pipe->pipe_handle != NULL) {
usb_pipe_close(pipe->pipe_ksp->ks_dip, pipe->pipe_handle,
USB_FLAGS_SLEEP, NULL, NULL);
mutex_enter(&pipe->pipe_mutex);
pipe->pipe_handle = NULL;
pipe->pipe_state = KEYSPAN_PIPE_CLOSED;
mutex_exit(&pipe->pipe_mutex);
}
}
static void
keyspan_close_pipe_datain_usa49wg(keyspan_pipe_t *pipe)
{
keyspan_state_t *ksp = pipe->pipe_ksp;
if (pipe->pipe_handle != NULL) {
mutex_enter(&ksp->ks_mutex);
ksp->ks_datain_open_cnt--;
if (!ksp->ks_datain_open_cnt) {
mutex_exit(&ksp->ks_mutex);
usb_pipe_close(pipe->pipe_ksp->ks_dip,
pipe->pipe_handle, USB_FLAGS_SLEEP,
NULL, NULL);
} else {
mutex_exit(&ksp->ks_mutex);
}
mutex_enter(&pipe->pipe_mutex);
pipe->pipe_handle = NULL;
pipe->pipe_state = KEYSPAN_PIPE_CLOSED;
mutex_exit(&pipe->pipe_mutex);
}
}
int
keyspan_open_dev_pipes_usa49(keyspan_state_t *ksp)
{
int rval;
USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh,
"keyspan_open_dev_pipes_usa49");
rval = keyspan_open_one_pipe(ksp, &ksp->ks_ctrlout_pipe);
if (rval != USB_SUCCESS) {
USB_DPRINTF_L2(DPRINT_OPEN, ksp->ks_lh,
"keyspan_open_dev_pipes_usa49: open ctrl pipe failed %d",
rval);
return (rval);
}
rval = keyspan_open_one_pipe(ksp, &ksp->ks_statin_pipe);
if (rval != USB_SUCCESS) {
USB_DPRINTF_L2(DPRINT_OPEN, ksp->ks_lh,
"keyspan_open_dev_pipes_usa49: open status pipe failed %d",
rval);
keyspan_close_one_pipe(&ksp->ks_ctrlout_pipe);
return (rval);
}
rval = keyspan_receive_status(ksp);
if (rval != USB_SUCCESS) {
USB_DPRINTF_L2(DPRINT_OPEN, ksp->ks_lh,
"keyspan_open_dev_pipes_usa49: receive device status"
" failed %d", rval);
keyspan_close_one_pipe(&ksp->ks_statin_pipe);
keyspan_close_one_pipe(&ksp->ks_ctrlout_pipe);
return (rval);
}
return (rval);
}
int
keyspan_open_dev_pipes_usa49wg(keyspan_state_t *ksp)
{
int rval;
rval = keyspan_open_one_pipe(ksp, &ksp->ks_statin_pipe);
if (rval != USB_SUCCESS) {
USB_DPRINTF_L2(DPRINT_OPEN, ksp->ks_lh,
"keyspan_open_dev_pipes_usa49wg: "
"open status pipe failed %d",
rval);
return (rval);
}
keyspan_pipe_start_polling(&ksp->ks_statin_pipe);
return (rval);
}
int
keyspan_open_dev_pipes(keyspan_state_t *ksp)
{
int rval = USB_SUCCESS;
USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, "keyspan_open_dev_pipes");
switch (ksp->ks_dev_spec.id_product) {
case KEYSPAN_USA19HS_PID:
case KEYSPAN_USA49WLC_PID:
rval = keyspan_open_dev_pipes_usa49(ksp);
break;
case KEYSPAN_USA49WG_PID:
rval = keyspan_open_dev_pipes_usa49wg(ksp);
break;
default:
USB_DPRINTF_L2(DPRINT_OPEN, ksp->ks_lh,
"keyspan_open_dev_pipes: the device's product id can't"
"be recognized");
return (USB_FAILURE);
}
return (rval);
}
int
keyspan_reopen_pipes(keyspan_state_t *ksp)
{
keyspan_port_t *kp;
int i;
USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, "keyspan_reopen_pipes");
if (keyspan_open_dev_pipes(ksp) != USB_SUCCESS) {
return (USB_FAILURE);
}
for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) {
kp = &ksp->ks_ports[i];
mutex_enter(&kp->kp_mutex);
if (kp->kp_state == KEYSPAN_PORT_OPEN) {
USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh,
"keyspan_reopen_pipes() reopen pipe #%d", i);
mutex_exit(&kp->kp_mutex);
if (keyspan_open_port_pipes(kp) != USB_SUCCESS) {
return (USB_FAILURE);
}
mutex_enter(&kp->kp_mutex);
kp->kp_no_more_reads = B_FALSE;
}
mutex_exit(&kp->kp_mutex);
}
return (USB_SUCCESS);
}
void
keyspan_close_port_pipes(keyspan_port_t *kp)
{
keyspan_state_t *ksp = kp->kp_ksp;
USB_DPRINTF_L4(DPRINT_CLOSE, kp->kp_lh, "keyspan_close_port_pipes");
switch (ksp->ks_dev_spec.id_product) {
case KEYSPAN_USA19HS_PID:
case KEYSPAN_USA49WLC_PID:
keyspan_close_one_pipe(&kp->kp_datain_pipe);
break;
case KEYSPAN_USA49WG_PID:
keyspan_close_pipe_datain_usa49wg(&kp->kp_datain_pipe);
break;
default:
USB_DPRINTF_L2(DPRINT_CLOSE, kp->kp_lh,
"keyspan_close_port_pipes:"
"the device's product id can't be recognized");
}
keyspan_close_one_pipe(&kp->kp_dataout_pipe);
}
void
keyspan_close_open_pipes(keyspan_state_t *ksp)
{
keyspan_port_t *kp;
int i;
int port_num = -1;
USB_DPRINTF_L4(DPRINT_CLOSE, ksp->ks_lh, "keyspan_close_open_pipes");
switch (ksp->ks_dev_spec.id_product) {
case KEYSPAN_USA19HS_PID:
case KEYSPAN_USA49WLC_PID:
for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) {
kp = &ksp->ks_ports[i];
mutex_enter(&kp->kp_mutex);
if (kp->kp_state == KEYSPAN_PORT_OPEN) {
kp->kp_no_more_reads = B_TRUE;
mutex_exit(&kp->kp_mutex);
usb_pipe_reset(ksp->ks_dip,
kp->kp_datain_pipe.pipe_handle,
USB_FLAGS_SLEEP, NULL, NULL);
keyspan_close_port_pipes(kp);
} else {
mutex_exit(&kp->kp_mutex);
}
}
break;
case KEYSPAN_USA49WG_PID:
for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) {
kp = &ksp->ks_ports[i];
mutex_enter(&kp->kp_mutex);
if (kp->kp_state == KEYSPAN_PORT_OPEN) {
kp->kp_no_more_reads = B_TRUE;
port_num = i;
}
mutex_exit(&kp->kp_mutex);
}
if (port_num >= 0) {
kp = &ksp->ks_ports[port_num];
usb_pipe_reset(ksp->ks_dip,
kp->kp_datain_pipe.pipe_handle,
USB_FLAGS_SLEEP, NULL, NULL);
}
for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) {
kp = &ksp->ks_ports[i];
mutex_enter(&kp->kp_mutex);
if (kp->kp_state == KEYSPAN_PORT_OPEN) {
mutex_exit(&kp->kp_mutex);
keyspan_close_port_pipes(kp);
} else {
mutex_exit(&kp->kp_mutex);
}
}
break;
default:
USB_DPRINTF_L2(DPRINT_CLOSE, ksp->ks_lh,
"keyspan_close_open_pipes:"
"the device's product id can't be recognized");
}
}
void
keyspan_close_dev_pipes(keyspan_state_t *ksp)
{
USB_DPRINTF_L4(DPRINT_CLOSE, ksp->ks_lh, "keyspan_close_dev_pipes");
switch (ksp->ks_dev_spec.id_product) {
case KEYSPAN_USA19HS_PID:
case KEYSPAN_USA49WLC_PID:
keyspan_close_one_pipe(&ksp->ks_statin_pipe);
keyspan_close_one_pipe(&ksp->ks_ctrlout_pipe);
break;
case KEYSPAN_USA49WG_PID:
usb_pipe_stop_intr_polling(ksp->ks_statin_pipe.pipe_handle,
USB_FLAGS_SLEEP);
keyspan_close_one_pipe(&ksp->ks_statin_pipe);
break;
default:
USB_DPRINTF_L2(DPRINT_CLOSE, ksp->ks_lh,
"keyspan_close_dev_pipes:"
"the device's product id can't be recognized");
}
}
int
keyspan_open_port_pipes(keyspan_port_t *kp)
{
keyspan_state_t *ksp = kp->kp_ksp;
int rval;
USB_DPRINTF_L4(DPRINT_OPEN, kp->kp_lh, "keyspan_open_port_pipes");
switch (ksp->ks_dev_spec.id_product) {
case KEYSPAN_USA19HS_PID:
case KEYSPAN_USA49WLC_PID:
rval = keyspan_open_one_pipe(ksp, &kp->kp_datain_pipe);
break;
case KEYSPAN_USA49WG_PID:
rval = keyspan_open_pipe_datain_usa49wg(ksp,
&kp->kp_datain_pipe);
break;
default:
USB_DPRINTF_L2(DPRINT_OPEN, kp->kp_lh,
"keyspan_open_port_pipes:"
"the device's product id can't be recognized");
}
if (rval != USB_SUCCESS) {
goto fail;
}
rval = keyspan_open_one_pipe(ksp, &kp->kp_dataout_pipe);
if (rval != USB_SUCCESS) {
goto fail;
}
return (rval);
fail:
USB_DPRINTF_L2(DPRINT_OPEN, kp->kp_lh,
"keyspan_open_port_pipes: failed %d", rval);
keyspan_close_port_pipes(kp);
return (rval);
}
void
keyspan_close_pipes(keyspan_state_t *ksp)
{
USB_DPRINTF_L4(DPRINT_OPEN, ksp->ks_lh, "keyspan_close_pipes");
keyspan_close_open_pipes(ksp);
keyspan_close_dev_pipes(ksp);
}
void
keyspan_bulkout_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
{
keyspan_port_t *kp = (keyspan_port_t *)req->bulk_client_private;
keyspan_pipe_t *bulkout = &kp->kp_dataout_pipe;
mblk_t *data = req->bulk_data;
int data_len;
data_len = (data) ? MBLKL(data) : 0;
USB_DPRINTF_L4(DPRINT_OUT_PIPE, bulkout->pipe_lh,
"keyspan_bulkout_cb: len=%d cr=%d cb_flags=%x",
data_len, req->bulk_completion_reason, req->bulk_cb_flags);
if (req->bulk_completion_reason && data) {
keyspan_put_head(&kp->kp_tx_mp, data, kp);
req->bulk_data = NULL;
}
usb_free_bulk_req(req);
mutex_enter(&kp->kp_mutex);
if (kp->kp_tx_mp == NULL) {
if ((kp->kp_ksp->ks_dev_spec.id_product ==
KEYSPAN_USA19HS_PID) && (data_len == 64)) {
kp->kp_tx_mp = allocb(0, BPRI_LO);
if (kp->kp_tx_mp) {
keyspan_tx_start(kp, NULL);
mutex_exit(&kp->kp_mutex);
return;
}
}
cv_broadcast(&kp->kp_tx_cv);
mutex_exit(&kp->kp_mutex);
kp->kp_cb.cb_tx(kp->kp_cb.cb_arg);
} else {
keyspan_tx_start(kp, NULL);
mutex_exit(&kp->kp_mutex);
}
}
void
keyspan_introut_cb_usa49wg(usb_pipe_handle_t pipe, usb_intr_req_t *req)
{
keyspan_port_t *kp = (keyspan_port_t *)req->intr_client_private;
keyspan_pipe_t *introut = &kp->kp_dataout_pipe;
mblk_t *data = req->intr_data;
int data_len;
data_len = (data) ? MBLKL(data) : 0;
USB_DPRINTF_L4(DPRINT_OUT_PIPE, introut->pipe_lh,
"keyspan_introut_cb_usa49wg: len=%d cr=%d cb_flags=%x",
data_len, req->intr_completion_reason, req->intr_cb_flags);
if (req->intr_completion_reason && (data_len > 0)) {
keyspan_put_head(&kp->kp_tx_mp, data, kp);
req->intr_data = NULL;
}
usb_free_intr_req(req);
mutex_enter(&kp->kp_mutex);
if (kp->kp_tx_mp == NULL) {
cv_broadcast(&kp->kp_tx_cv);
mutex_exit(&kp->kp_mutex);
kp->kp_cb.cb_tx(kp->kp_cb.cb_arg);
} else {
keyspan_tx_start(kp, NULL);
mutex_exit(&kp->kp_mutex);
}
}
void
keyspan_parse_status(uchar_t *status, uchar_t *err)
{
if (*status & RXERROR_BREAK) {
*status &= (uint8_t)(RXERROR_OVERRUN | RXERROR_BREAK);
}
*err |= (*status & RXERROR_OVERRUN) ? DS_OVERRUN_ERR : 0;
*err |= (*status & RXERROR_PARITY) ? DS_PARITY_ERR : 0;
*err |= (*status & RXERROR_FRAMING) ? DS_FRAMING_ERR : 0;
*err |= (*status & RXERROR_BREAK) ? DS_BREAK_ERR : 0;
}
int
keyspan_bulkin_cb_process(keyspan_port_t *kp,
uint8_t data_len, uchar_t status, mblk_t *data)
{
uchar_t err = 0;
mblk_t *mp;
if (!(status & 0x80) && !(status & RXERROR_OVERRUN)) {
data->b_rptr++;
data_len--;
} else if (!(status & 0x80)) {
keyspan_parse_status(&status, &err);
mutex_exit(&kp->kp_mutex);
if ((mp = allocb(2, BPRI_HI)) == NULL) {
USB_DPRINTF_L2(DPRINT_IN_PIPE, kp->kp_lh,
"keyspan_bulkin_cb_process: allocb failed");
mutex_enter(&kp->kp_mutex);
return (0);
}
DB_TYPE(mp) = M_BREAK;
*mp->b_wptr++ = err;
*mp->b_wptr++ = status;
mutex_enter(&kp->kp_mutex);
keyspan_put_tail(&kp->kp_rx_mp, mp);
data->b_rptr++;
data_len--;
} else {
if (data_len > 1) {
int i = 0;
int j = 1;
for (j = 1; j < data_len; j += 2) {
status = data->b_rptr[j-1];
keyspan_parse_status(&status, &err);
data->b_rptr[i] = data->b_rptr[j];
i++;
}
data->b_wptr = data->b_rptr + i;
} else {
keyspan_parse_status(&status, &err);
}
mutex_exit(&kp->kp_mutex);
if ((mp = allocb(2, BPRI_HI)) == NULL) {
USB_DPRINTF_L2(DPRINT_IN_PIPE, kp->kp_lh,
"keyspan_bulkin_cb_process: allocb failed");
mutex_enter(&kp->kp_mutex);
return (0);
}
DB_TYPE(mp) = M_BREAK;
*mp->b_wptr++ = err;
if (data_len > 2) {
*mp->b_wptr++ = err;
} else {
*mp->b_wptr++ = status;
}
mutex_enter(&kp->kp_mutex);
keyspan_put_tail(&kp->kp_rx_mp, mp);
if (data_len > 1) {
data_len = MBLKL(data);
}
}
return (data_len);
}
int
keyspan_bulkin_cb_usa49(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
{
keyspan_port_t *kp = (keyspan_port_t *)req->bulk_client_private;
keyspan_pipe_t *bulkin = &kp->kp_datain_pipe;
mblk_t *data = req->bulk_data;
uint_t cr = req->bulk_completion_reason;
int data_len;
ASSERT(mutex_owned(&kp->kp_mutex));
data_len = (data) ? MBLKL(data) : 0;
USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh,
"keyspan_bulkin_cb_usa49: len=%d"
" cr=%d flags=%x", data_len, cr, req->bulk_cb_flags);
if ((data_len > 0) && (kp->kp_state != KEYSPAN_PORT_CLOSED) &&
(cr == USB_CR_OK)) {
uchar_t status = data->b_rptr[0];
if ((data_len = keyspan_bulkin_cb_process(kp, data_len,
status, data)) > 0) {
keyspan_put_tail(&kp->kp_rx_mp, data);
req->bulk_data = NULL;
}
} else {
data_len = 0;
USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh,
"keyspan_bulkin_cb_usa49: port_state=%d"
" b_rptr[0]=%c", kp->kp_state, data->b_rptr[0]);
}
if (kp->kp_state != KEYSPAN_PORT_OPEN) {
kp->kp_no_more_reads = B_TRUE;
}
return (data_len);
}
void
keyspan_bulkin_cb_usa49wg(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
{
keyspan_port_t *kp = (keyspan_port_t *)req->bulk_client_private,
*kp_true;
keyspan_state_t *ksp = (keyspan_state_t *)kp->kp_ksp;
mblk_t *data = req->bulk_data,
*mp_data;
uint_t cr = req->bulk_completion_reason,
port_data_len;
int data_len, copy_len;
uint8_t port_num,
port_cnt = 0,
port[4],
receive_flag = 1;
uint16_t status;
unsigned char *old_rptr;
data_len = (data) ? MBLKL(data) : 0;
USB_DPRINTF_L2(DPRINT_IN_PIPE, ksp->ks_lh,
"keyspan_bulkin_cb_usa49wg: len=%d"
" cr=%d flags=%x", data_len, cr, req->bulk_cb_flags);
if ((data_len > 0) && (cr == USB_CR_OK)) {
old_rptr = data->b_rptr;
while (data->b_rptr < data->b_wptr) {
port_num = data->b_rptr[0];
port_data_len = data->b_rptr[1];
status = data->b_rptr[2];
data->b_rptr += 2;
if (port_num > 3) {
USB_DPRINTF_L2(DPRINT_IN_PIPE, ksp->ks_lh,
"keyspan_bulkin_cb_usa49wg,port num is not"
" correct: port=%d, len=%d, status=%x",
port_num, port_data_len, status);
break;
}
kp_true = &ksp->ks_ports[port_num];
port[++port_cnt] = port_num;
mutex_enter(&kp_true->kp_mutex);
if (kp_true->kp_state != KEYSPAN_PORT_OPEN) {
mutex_exit(&kp_true->kp_mutex);
USB_DPRINTF_L2(DPRINT_IN_PIPE, kp_true->kp_lh,
"keyspan_bulkin_cb_usa49wg, "
"port isn't opened");
data->b_rptr += port_data_len;
port_cnt--;
continue;
}
USB_DPRINTF_L2(DPRINT_IN_PIPE, kp_true->kp_lh,
"keyspan_bulkin_cb_usa49wg: status=0x%x, len=%d",
status, port_data_len);
if ((copy_len = keyspan_bulkin_cb_process(kp_true,
port_data_len, status, data)) > 0) {
mutex_exit(&kp_true->kp_mutex);
if ((mp_data = allocb(copy_len, BPRI_HI))
== NULL) {
USB_DPRINTF_L2(DPRINT_IN_PIPE,
kp_true->kp_lh, "keyspan_bulkin_cb_"
"usa49wg: allocb failed");
return;
}
mutex_enter(&kp_true->kp_mutex);
DB_TYPE(mp_data) = M_DATA;
bcopy(data->b_rptr, mp_data->b_wptr, copy_len);
mp_data->b_wptr += copy_len;
if (copy_len < port_data_len -1) {
data->b_rptr += port_data_len;
data->b_wptr = old_rptr + data_len;
} else {
data->b_rptr += copy_len;
}
keyspan_put_tail(&kp_true->kp_rx_mp, mp_data);
mutex_exit(&kp_true->kp_mutex);
} else {
mutex_exit(&kp_true->kp_mutex);
break;
}
}
while (port_cnt) {
port_num = port[port_cnt--];
kp_true = &ksp->ks_ports[port_num];
mutex_enter(&kp_true->kp_mutex);
if (kp_true->kp_state != KEYSPAN_PORT_OPEN) {
kp_true->kp_no_more_reads = B_TRUE;
}
if (receive_flag && (!kp_true->kp_no_more_reads)) {
mutex_exit(&kp_true->kp_mutex);
(void) keyspan_receive_data(
&kp_true->kp_datain_pipe,
kp_true->kp_read_len, kp_true);
receive_flag = 0;
} else {
mutex_exit(&kp_true->kp_mutex);
}
kp_true->kp_cb.cb_rx(kp_true->kp_cb.cb_arg);
}
} else {
USB_DPRINTF_L2(DPRINT_IN_PIPE, ksp->ks_lh,
"keyspan_bulkin_cb_usa49wg: port=%d, len=%d, status=%x",
data->b_rptr[0], data->b_rptr[1], data->b_rptr[2]);
mutex_enter(&kp->kp_mutex);
if (kp->kp_state != KEYSPAN_PORT_OPEN) {
kp->kp_no_more_reads = B_TRUE;
}
if (!kp->kp_no_more_reads) {
mutex_exit(&kp->kp_mutex);
(void) keyspan_receive_data(&kp->kp_datain_pipe,
kp->kp_read_len, kp);
} else {
mutex_exit(&kp->kp_mutex);
}
}
freemsg(data);
req->bulk_data = NULL;
usb_free_bulk_req(req);
}
void
keyspan_bulkin_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
{
keyspan_port_t *kp = (keyspan_port_t *)req->bulk_client_private;
int data_len;
boolean_t no_more_reads = B_FALSE;
USB_DPRINTF_L4(DPRINT_IN_PIPE, (&kp->kp_datain_pipe)->pipe_lh,
"keyspan_bulkin_cb");
mutex_enter(&kp->kp_mutex);
data_len = keyspan_bulkin_cb_usa49(pipe, req);
no_more_reads = kp->kp_no_more_reads;
mutex_exit(&kp->kp_mutex);
usb_free_bulk_req(req);
if (!no_more_reads) {
(void) keyspan_receive_data(&kp->kp_datain_pipe,
kp->kp_read_len, kp);
}
if (data_len > 0) {
kp->kp_cb.cb_rx(kp->kp_cb.cb_arg);
}
}
void
keyspan_status_cb_usa19hs(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
{
keyspan_state_t *ksp = (keyspan_state_t *)req->bulk_client_private;
keyspan_pipe_t *bulkin = &ksp->ks_statin_pipe;
mblk_t *data = req->bulk_data;
usb_cr_t cr = req->bulk_completion_reason;
int data_len;
data_len = (data) ? MBLKL(data) : 0;
USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh,
"keyspan_status_cb_usa19hs: len=%d"
" cr=%d flags=%x", data_len, cr, req->bulk_cb_flags);
if ((data_len == 14) && (cr == USB_CR_OK)) {
keyspan_port_t *kp = &ksp->ks_ports[0];
keyspan_usa19hs_port_status_msg_t *status_msg =
&(kp->kp_status_msg.usa19hs);
mutex_enter(&kp->kp_mutex);
bcopy(data->b_rptr, status_msg, data_len);
if (status_msg->controlResponse) {
kp->kp_status_flag |= KEYSPAN_PORT_CTRLRESP;
} else {
kp->kp_status_flag &= ~KEYSPAN_PORT_CTRLRESP;
}
if (status_msg->portState & PORTSTATE_ENABLED) {
kp->kp_status_flag |= KEYSPAN_PORT_ENABLE;
} else {
kp->kp_status_flag &= ~KEYSPAN_PORT_ENABLE;
}
if (status_msg->portState & PORTSTATE_TXBREAK) {
kp->kp_status_flag |= KEYSPAN_PORT_TXBREAK;
} else {
kp->kp_status_flag &= ~KEYSPAN_PORT_TXBREAK;
}
if (status_msg->rxBreak) {
kp->kp_status_flag |= KEYSPAN_PORT_RXBREAK;
} else {
kp->kp_status_flag &= ~KEYSPAN_PORT_RXBREAK;
}
if (status_msg->portState & PORTSTATE_LOOPBACK) {
kp->kp_status_flag |= KEYSPAN_PORT_LOOPBACK;
} else {
kp->kp_status_flag &= ~KEYSPAN_PORT_LOOPBACK;
}
if (status_msg->msr & USA_MSR_dCTS ||
status_msg->msr & USA_MSR_dDSR ||
status_msg->msr & USA_MSR_dRI ||
status_msg->msr & USA_MSR_dDCD) {
mutex_exit(&kp->kp_mutex);
kp->kp_cb.cb_status(kp->kp_cb.cb_arg);
} else {
mutex_exit(&kp->kp_mutex);
}
} else {
USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh,
"keyspan_status_cb_usa19hs: get status failed, cr=%d"
" data_len=%d", cr, data_len);
}
}
void
keyspan_status_cb_usa49(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
{
keyspan_state_t *ksp = (keyspan_state_t *)req->bulk_client_private;
keyspan_pipe_t *bulkin = &ksp->ks_statin_pipe;
mblk_t *data = req->bulk_data;
uint_t cr = req->bulk_completion_reason;
int data_len;
data_len = (data) ? MBLKL(data) : 0;
USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh,
"keyspan_status_cb_usa49: len=%d"
" cr=%d flags=%x", data_len, cr, req->bulk_cb_flags);
if ((data_len == 11) && (cr == USB_CR_OK)) {
keyspan_usa49_port_status_msg_t status_msg;
keyspan_port_t *cur_kp;
keyspan_usa49_port_status_msg_t *kp_status_msg;
boolean_t need_cb = B_FALSE;
bcopy(data->b_rptr, &status_msg, data_len);
if (status_msg.portNumber >= ksp->ks_dev_spec.port_cnt) {
return;
}
cur_kp = &ksp->ks_ports[status_msg.portNumber];
kp_status_msg = &(cur_kp->kp_status_msg.usa49);
mutex_enter(&cur_kp->kp_mutex);
if (status_msg.cts != kp_status_msg->cts ||
status_msg.dsr != kp_status_msg->dsr ||
status_msg.ri != kp_status_msg->ri ||
status_msg.dcd != kp_status_msg->dcd) {
need_cb = B_TRUE;
}
bcopy(&status_msg, kp_status_msg, data_len);
if (kp_status_msg->controlResponse) {
cur_kp->kp_status_flag |= KEYSPAN_PORT_CTRLRESP;
} else {
cur_kp->kp_status_flag &= ~KEYSPAN_PORT_CTRLRESP;
}
if (!kp_status_msg->rxEnabled) {
cur_kp->kp_status_flag |= KEYSPAN_PORT_RXBREAK;
} else {
cur_kp->kp_status_flag &= ~KEYSPAN_PORT_RXBREAK;
}
mutex_exit(&cur_kp->kp_mutex);
if (need_cb) {
cur_kp->kp_cb.cb_status(cur_kp->kp_cb.cb_arg);
}
} else {
USB_DPRINTF_L2(DPRINT_IN_PIPE, bulkin->pipe_lh,
"keyspan_status_cb_usa49: get status failed, cr=%d"
" data_len=%d", cr, data_len);
}
}
void
keyspan_status_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
{
keyspan_state_t *ksp = (keyspan_state_t *)req->bulk_client_private;
usb_cr_t cr = req->bulk_completion_reason;
USB_DPRINTF_L4(DPRINT_IN_PIPE, (&ksp->ks_statin_pipe)->pipe_lh,
"keyspan_status_cb");
switch (ksp->ks_dev_spec.id_product) {
case KEYSPAN_USA19HS_PID:
keyspan_status_cb_usa19hs(pipe, req);
break;
case KEYSPAN_USA49WLC_PID:
keyspan_status_cb_usa49(pipe, req);
break;
default:
USB_DPRINTF_L2(DPRINT_IN_PIPE,
(&ksp->ks_statin_pipe)->pipe_lh, "keyspan_status_cb:"
"the device's product id can't be recognized");
return;
}
usb_free_bulk_req(req);
if ((cr != USB_CR_FLUSHED) && (cr != USB_CR_DEV_NOT_RESP) &&
keyspan_dev_is_online(ksp)) {
if (keyspan_receive_status(ksp) != USB_SUCCESS) {
USB_DPRINTF_L2(DPRINT_IN_PIPE,
(&ksp->ks_statin_pipe)->pipe_lh,
"keyspan_status_cb:"
"receive status can't be restarted.");
}
} else {
USB_DPRINTF_L2(DPRINT_IN_PIPE,
(&ksp->ks_statin_pipe)->pipe_lh, "keyspan_status_cb:"
"get status failed: cr=%d", cr);
}
}
int
keyspan_receive_data(keyspan_pipe_t *bulkin, int len, void *cb_arg)
{
keyspan_state_t *ksp = bulkin->pipe_ksp;
usb_bulk_req_t *br;
int rval = USB_SUCCESS;
USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh, "keyspan_receive_data:"
"len=%d", len);
ASSERT(!mutex_owned(&bulkin->pipe_mutex));
br = usb_alloc_bulk_req(ksp->ks_dip, len, USB_FLAGS_SLEEP);
br->bulk_len = len;
br->bulk_timeout = 0;
br->bulk_client_private = cb_arg;
br->bulk_attributes = USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING;
switch (ksp->ks_dev_spec.id_product) {
case KEYSPAN_USA19HS_PID:
case KEYSPAN_USA49WLC_PID:
br->bulk_cb = keyspan_bulkin_cb;
br->bulk_exc_cb = keyspan_bulkin_cb;
break;
case KEYSPAN_USA49WG_PID:
br->bulk_cb = keyspan_bulkin_cb_usa49wg;
br->bulk_exc_cb = keyspan_bulkin_cb_usa49wg;
break;
default:
usb_free_bulk_req(br);
USB_DPRINTF_L2(DPRINT_IN_PIPE,
(&ksp->ks_statin_pipe)->pipe_lh, "keyspan_receive_data:"
"the device's product id can't be recognized");
return (USB_FAILURE);
}
rval = usb_pipe_bulk_xfer(bulkin->pipe_handle, br, 0);
if (rval != USB_SUCCESS) {
usb_free_bulk_req(br);
}
USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh,
"keyspan_receive_data: rval = %d", rval);
return (rval);
}
int
keyspan_receive_status(keyspan_state_t *ksp)
{
keyspan_pipe_t *bulkin = &ksp->ks_statin_pipe;
usb_bulk_req_t *br;
int rval;
USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh,
"keyspan_receive_status");
ASSERT(!mutex_owned(&bulkin->pipe_mutex));
br = usb_alloc_bulk_req(ksp->ks_dip, 32, USB_FLAGS_SLEEP);
br->bulk_len = KEYSPAN_STATIN_MAX_LEN;
br->bulk_timeout = 0;
br->bulk_client_private = (void *)ksp;
br->bulk_attributes = USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING;
br->bulk_cb = keyspan_status_cb;
br->bulk_exc_cb = keyspan_status_cb;
rval = usb_pipe_bulk_xfer(bulkin->pipe_handle, br, 0);
if (rval != USB_SUCCESS) {
usb_free_bulk_req(br);
}
USB_DPRINTF_L4(DPRINT_IN_PIPE, bulkin->pipe_lh,
"keyspan_receive_status: rval = %d", rval);
return (rval);
}
int
keyspan_send_data(keyspan_pipe_t *bulkout, mblk_t **mpp, void *cb_arg)
{
keyspan_state_t *ksp = bulkout->pipe_ksp;
usb_bulk_req_t *br;
int rval;
ASSERT(!mutex_owned(&bulkout->pipe_mutex));
USB_DPRINTF_L4(DPRINT_OUT_PIPE, bulkout->pipe_lh,
"keyspan_send_data");
br = usb_alloc_bulk_req(ksp->ks_dip, 0, USB_FLAGS_SLEEP);
br->bulk_len = MBLKL(*mpp);
br->bulk_data = *mpp;
br->bulk_timeout = KEYSPAN_BULK_TIMEOUT;
br->bulk_client_private = cb_arg;
br->bulk_attributes = USB_ATTRS_AUTOCLEARING;
br->bulk_cb = keyspan_bulkout_cb;
br->bulk_exc_cb = keyspan_bulkout_cb;
USB_DPRINTF_L3(DPRINT_OUT_PIPE, bulkout->pipe_lh, "keyspan_send_data:"
"bulk_len = %d", br->bulk_len);
rval = usb_pipe_bulk_xfer(bulkout->pipe_handle, br, 0);
if (rval == USB_SUCCESS) {
*mpp = NULL;
} else {
br->bulk_data = NULL;
usb_free_bulk_req(br);
}
USB_DPRINTF_L4(DPRINT_OUT_PIPE, bulkout->pipe_lh,
"keyspan_send_data: rval = %d", rval);
return (rval);
}
int
keyspan_send_data_port0(keyspan_pipe_t *introut, mblk_t **mpp, void *cb_arg)
{
keyspan_state_t *ksp = introut->pipe_ksp;
usb_intr_req_t *br;
int rval;
ASSERT(!mutex_owned(&introut->pipe_mutex));
USB_DPRINTF_L4(DPRINT_OUT_PIPE, introut->pipe_lh,
"keyspan_send_data_port0");
br = usb_alloc_intr_req(ksp->ks_dip, 0, USB_FLAGS_SLEEP);
br->intr_len = MBLKL(*mpp);
br->intr_data = *mpp;
br->intr_timeout = KEYSPAN_BULK_TIMEOUT;
br->intr_client_private = cb_arg;
br->intr_cb = keyspan_introut_cb_usa49wg;
br->intr_exc_cb = keyspan_introut_cb_usa49wg;
USB_DPRINTF_L3(DPRINT_OUT_PIPE, introut->pipe_lh,
"keyspan_send_data_port0: intr_len = %d",
br->intr_len);
rval = usb_pipe_intr_xfer(introut->pipe_handle, br, 0);
if (rval == USB_SUCCESS) {
*mpp = NULL;
} else {
br->intr_data = NULL;
usb_free_intr_req(br);
}
USB_DPRINTF_L4(DPRINT_OUT_PIPE, introut->pipe_lh,
"keyspan_send_data_port0: rval = %d", rval);
return (rval);
}
void
keyspan_status_cb_usa49wg(usb_pipe_handle_t pipe, usb_intr_req_t *req)
{
keyspan_state_t *ksp = (keyspan_state_t *)req->intr_client_private;
keyspan_pipe_t *intr = &ksp->ks_statin_pipe;
mblk_t *data = req->intr_data;
uint_t cr = req->intr_completion_reason;
int data_len;
data_len = (data) ? MBLKL(data) : 0;
USB_DPRINTF_L4(DPRINT_IN_PIPE, intr->pipe_lh,
"keyspan_status_cb_usa49wg: len=%d"
" cr=%d flags=%x", data_len, cr, req->intr_cb_flags);
if ((data_len == 11) && (cr == USB_CR_OK)) {
keyspan_usa49_port_status_msg_t status_msg;
keyspan_port_t *cur_kp;
keyspan_usa49_port_status_msg_t *kp_status_msg;
boolean_t need_cb = B_FALSE;
bcopy(data->b_rptr, &status_msg, data_len);
if (status_msg.portNumber >= ksp->ks_dev_spec.port_cnt) {
return;
}
cur_kp = &ksp->ks_ports[status_msg.portNumber];
kp_status_msg = &(cur_kp->kp_status_msg.usa49);
mutex_enter(&cur_kp->kp_mutex);
if (status_msg.cts != kp_status_msg->cts ||
status_msg.dsr != kp_status_msg->dsr ||
status_msg.ri != kp_status_msg->ri ||
status_msg.dcd != kp_status_msg->dcd) {
need_cb = B_TRUE;
}
bcopy(&status_msg, kp_status_msg, data_len);
if (kp_status_msg->controlResponse) {
cur_kp->kp_status_flag |= KEYSPAN_PORT_CTRLRESP;
} else {
cur_kp->kp_status_flag &= ~KEYSPAN_PORT_CTRLRESP;
}
if (!kp_status_msg->rxEnabled) {
cur_kp->kp_status_flag |= KEYSPAN_PORT_RXBREAK;
} else {
cur_kp->kp_status_flag &= ~KEYSPAN_PORT_RXBREAK;
}
mutex_exit(&cur_kp->kp_mutex);
if (need_cb) {
cur_kp->kp_cb.cb_status(cur_kp->kp_cb.cb_arg);
}
} else {
USB_DPRINTF_L2(DPRINT_IN_PIPE, intr->pipe_lh,
"keyspan_status_cb_usa49wg: get status failed, cr=%d"
" data_len=%d", cr, data_len);
}
}
void
keyspan_intr_cb_usa49wg(usb_pipe_handle_t pipe, usb_intr_req_t *req)
{
keyspan_state_t *ksp = (keyspan_state_t *)req->intr_client_private;
usb_cr_t cr = req->intr_completion_reason;
USB_DPRINTF_L4(DPRINT_IN_PIPE, (&ksp->ks_statin_pipe)->pipe_lh,
"keyspan_intr_cb_usa49wg: cr=%d", cr);
(void) keyspan_status_cb_usa49wg(pipe, req);
usb_free_intr_req(req);
}
void
keyspan_intr_ex_cb_usa49wg(usb_pipe_handle_t pipe, usb_intr_req_t *req)
{
keyspan_state_t *ksp = (keyspan_state_t *)req->intr_client_private;
usb_cr_t cr = req->intr_completion_reason;
USB_DPRINTF_L4(DPRINT_IN_PIPE, (&ksp->ks_statin_pipe)->pipe_lh,
"keyspan_intr_ex_cb_usa49wg: cr=%d", cr);
usb_free_intr_req(req);
if ((cr != USB_CR_PIPE_CLOSING) && (cr != USB_CR_STOPPED_POLLING) &&
(cr != USB_CR_FLUSHED) && (cr != USB_CR_DEV_NOT_RESP) &&
(cr != USB_CR_PIPE_RESET) && keyspan_dev_is_online(ksp)) {
keyspan_pipe_start_polling(&ksp->ks_statin_pipe);
} else {
USB_DPRINTF_L2(DPRINT_IN_PIPE,
(&ksp->ks_statin_pipe)->pipe_lh,
"keyspan_intr_ex_cb_usa49wg:"
"get status failed: cr=%d", cr);
}
}
void
keyspan_pipe_start_polling(keyspan_pipe_t *intr)
{
usb_intr_req_t *br;
keyspan_state_t *ksp = intr->pipe_ksp;
int rval;
USB_DPRINTF_L4(DPRINT_IN_PIPE, ksp->ks_lh,
"keyspan_pipe_start_polling");
br = usb_alloc_intr_req(ksp->ks_dip, 0, USB_FLAGS_SLEEP);
if (!br) {
USB_DPRINTF_L2(DPRINT_IN_PIPE, ksp->ks_lh,
"keyspan_pipe_start_polling: alloc req failed.");
return;
}
br->intr_attributes = USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING;
br->intr_len = intr->pipe_ep_descr.wMaxPacketSize;
br->intr_client_private = (void *)ksp;
br->intr_cb = keyspan_intr_cb_usa49wg;
br->intr_exc_cb = keyspan_intr_ex_cb_usa49wg;
rval = usb_pipe_intr_xfer(intr->pipe_handle, br, USB_FLAGS_SLEEP);
mutex_enter(&intr->pipe_mutex);
if (rval != USB_SUCCESS) {
usb_free_intr_req(br);
intr->pipe_state = KEYSPAN_PIPE_CLOSED;
USB_DPRINTF_L3(DPRINT_IN_PIPE, ksp->ks_lh,
"keyspan_pipe_start_polling: failed (%d)", rval);
} else {
intr->pipe_state = KEYSPAN_PIPE_OPEN;
}
mutex_exit(&intr->pipe_mutex);
}