#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/termiox.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#define USBDRV_MAJOR_VER 2
#define USBDRV_MINOR_VER 0
#include <sys/usb/usba.h>
#include <sys/usb/clients/usbser/usbser_dsdi.h>
#include <sys/usb/clients/usbser/usbser_keyspan/keyspan_var.h>
#include <sys/usb/clients/usbser/usbser_keyspan/keyspan_pipe.h>
#include <sys/usb/clients/usbser/usbser_keyspan/usa90msg.h>
#include <sys/usb/clients/usbser/usbser_keyspan/usa49msg.h>
static int keyspan_attach(ds_attach_info_t *);
static void keyspan_detach(ds_hdl_t);
static int keyspan_register_cb(ds_hdl_t, uint_t, ds_cb_t *);
static void keyspan_unregister_cb(ds_hdl_t, uint_t);
static int keyspan_open_port(ds_hdl_t, uint_t);
static int keyspan_close_port(ds_hdl_t, uint_t);
static int keyspan_usb_power(ds_hdl_t, int, int, int *);
static int keyspan_suspend(ds_hdl_t);
static int keyspan_resume(ds_hdl_t);
static int keyspan_disconnect(ds_hdl_t);
static int keyspan_reconnect(ds_hdl_t);
static int keyspan_set_port_params(ds_hdl_t, uint_t, ds_port_params_t *);
static int keyspan_set_modem_ctl(ds_hdl_t, uint_t, int, int);
static int keyspan_get_modem_ctl(ds_hdl_t, uint_t, int, int *);
static int keyspan_break_ctl(ds_hdl_t, uint_t, int);
static int keyspan_loopback(ds_hdl_t, uint_t, int);
static int keyspan_tx(ds_hdl_t, uint_t, mblk_t *);
static mblk_t *keyspan_rx(ds_hdl_t, uint_t);
static void keyspan_stop(ds_hdl_t, uint_t, int);
static void keyspan_start(ds_hdl_t, uint_t, int);
static int keyspan_fifo_flush(ds_hdl_t, uint_t, int);
static int keyspan_fifo_drain(ds_hdl_t, uint_t, int);
static void keyspan_free_soft_state(keyspan_state_t *);
static void keyspan_init_sync_objs(keyspan_state_t *);
static void keyspan_fini_sync_objs(keyspan_state_t *);
static int keyspan_usb_register(keyspan_state_t *);
static void keyspan_usb_unregister(keyspan_state_t *);
static int keyspan_attach_dev(keyspan_state_t *);
static void keyspan_attach_ports(keyspan_state_t *);
static void keyspan_detach_ports(keyspan_state_t *);
static void keyspan_init_port_params(keyspan_state_t *);
static void keyspan_free_descr_tree(keyspan_state_t *);
static int keyspan_register_events(keyspan_state_t *);
static void keyspan_unregister_events(keyspan_state_t *);
static void keyspan_set_dev_state_online(keyspan_state_t *);
static int keyspan_restore_device_state(keyspan_state_t *);
static int keyspan_restore_ports_state(keyspan_state_t *);
static int keyspan_create_pm_components(keyspan_state_t *);
static void keyspan_destroy_pm_components(keyspan_state_t *);
static int keyspan_pm_set_busy(keyspan_state_t *);
static void keyspan_pm_set_idle(keyspan_state_t *);
static int keyspan_pwrlvl0(keyspan_state_t *);
static int keyspan_pwrlvl1(keyspan_state_t *);
static int keyspan_pwrlvl2(keyspan_state_t *);
static int keyspan_pwrlvl3(keyspan_state_t *);
static int keyspan_attach_pipes(keyspan_state_t *);
static void keyspan_detach_pipes(keyspan_state_t *);
static void keyspan_disconnect_pipes(keyspan_state_t *);
static int keyspan_reconnect_pipes(keyspan_state_t *);
static int keyspan_wait_tx_drain(keyspan_port_t *, int);
static void keyspan_default_port_params(keyspan_port_t *);
static void keyspan_build_cmd_msg(keyspan_port_t *, ds_port_params_t *);
static void keyspan_save_port_params(keyspan_port_t *);
static void keyspan_build_cmd_msg_usa19hs(keyspan_port_t *,
ds_port_params_t *);
static void keyspan_default_port_params_usa19hs(keyspan_port_t *);
static void keyspan_save_port_params_usa19hs(keyspan_port_t *);
static void keyspan_build_cmd_msg_usa49(keyspan_port_t *,
ds_port_params_t *);
static void keyspan_default_port_params_usa49(keyspan_port_t *);
static void keyspan_save_port_params_usa49(keyspan_port_t *);
ds_ops_t keyspan_ds_ops = {
DS_OPS_VERSION,
keyspan_attach,
keyspan_detach,
keyspan_register_cb,
keyspan_unregister_cb,
keyspan_open_port,
keyspan_close_port,
keyspan_usb_power,
keyspan_suspend,
keyspan_resume,
keyspan_disconnect,
keyspan_reconnect,
keyspan_set_port_params,
keyspan_set_modem_ctl,
keyspan_get_modem_ctl,
keyspan_break_ctl,
keyspan_loopback,
keyspan_tx,
keyspan_rx,
keyspan_stop,
keyspan_start,
keyspan_fifo_flush,
keyspan_fifo_drain
};
static uint16_t keyspan_speedtab_usa19hs[] = {
0x0,
0x481d,
0x3013,
0x20c7,
0x1ae8,
0x1809,
0x1207,
0xc04,
0x602,
0x301,
0x200,
0x180,
0xc0,
0x60,
0x30,
0x18,
0x10,
0xc,
0x8,
0x6,
0x4,
};
static uint16_t keyspan_speedtab_usa49[] = {
0x0,
0x7530,
0x4e20,
0x3544,
0x2bba,
0x2710,
0x1d4c,
0x1388,
0x9c4,
0x4e2,
0x25e,
0x271,
0xfa,
0x7d,
0x19,
0x27,
0x1a,
0xd,
0xd,
0x6,
0x4,
};
static uint8_t keyspan_prescaler_49wlc[] = {
0x0,
0x8,
0x8,
0x8,
0x8,
0x8,
0x8,
0x8,
0x8,
0x8,
0xb,
0x8,
0xa,
0xa,
0x19,
0x8,
0x8,
0xc,
0x8,
0xd,
0xd,
};
static int keyspan_speed2baud[] = {
0,
50,
75,
110,
134,
150,
200,
300,
600,
1200,
1800,
2400,
4800,
9600,
19200,
38400,
57600,
76800,
115200,
153600,
230400,
};
static uint_t keyspan_errlevel = USB_LOG_L4;
static uint_t keyspan_errmask = DPRINT_MASK_ALL;
static uint_t keyspan_instance_debug = (uint_t)-1;
static int
keyspan_attach(ds_attach_info_t *aip)
{
keyspan_state_t *ksp;
int rval = USB_SUCCESS;
ksp = (keyspan_state_t *)kmem_zalloc(sizeof (keyspan_state_t),
KM_SLEEP);
ksp->ks_dip = aip->ai_dip;
ksp->ks_usb_events = aip->ai_usb_events;
*aip->ai_hdl = (ds_hdl_t)ksp;
if (keyspan_usb_register(ksp) != USB_SUCCESS) {
goto fail_register;
}
keyspan_init_sync_objs(ksp);
if (keyspan_attach_dev(ksp) != USB_SUCCESS) {
USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh, "fail attach dev ");
goto fail_attach_dev;
}
keyspan_attach_ports(ksp);
switch (ksp->ks_dev_spec.id_product) {
case KEYSPAN_USA19HS_PID:
case KEYSPAN_USA49WLC_PID:
rval = keyspan_init_pipes(ksp);
break;
case KEYSPAN_USA49WG_PID:
rval = keyspan_init_pipes_usa49wg(ksp);
break;
default:
USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh, "keyspan_attach:"
"the device's product id can't be recognized");
return (USB_FAILURE);
}
if (rval != USB_SUCCESS) {
USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
"keyspan_init_pipes: failed.");
goto fail_init_pipes;
}
keyspan_init_port_params(ksp);
keyspan_free_descr_tree(ksp);
keyspan_set_dev_state_online(ksp);
if (keyspan_create_pm_components(ksp) != USB_SUCCESS) {
USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
"keyspan_create_pm_components: failed.");
goto fail_pm;
}
if (keyspan_register_events(ksp) != USB_SUCCESS) {
goto fail_events;
}
if (keyspan_attach_pipes(ksp) != USB_SUCCESS) {
USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
"keyspan_attach_pipes: failed.");
goto fail_attach_pipes;
}
*aip->ai_port_cnt = ksp->ks_dev_spec.port_cnt;
return (USB_SUCCESS);
fail_attach_pipes:
keyspan_unregister_events(ksp);
fail_events:
keyspan_destroy_pm_components(ksp);
fail_pm:
keyspan_fini_pipes(ksp);
fail_init_pipes:
keyspan_detach_ports(ksp);
fail_attach_dev:
keyspan_fini_sync_objs(ksp);
keyspan_usb_unregister(ksp);
fail_register:
keyspan_free_soft_state(ksp);
return (USB_FAILURE);
}
static void
keyspan_detach(ds_hdl_t hdl)
{
keyspan_state_t *ksp = (keyspan_state_t *)hdl;
keyspan_detach_pipes(ksp);
keyspan_unregister_events(ksp);
keyspan_destroy_pm_components(ksp);
keyspan_fini_pipes(ksp);
keyspan_detach_ports(ksp);
keyspan_fini_sync_objs(ksp);
keyspan_usb_unregister(ksp);
keyspan_free_soft_state(ksp);
}
static int
keyspan_register_cb(ds_hdl_t hdl, uint_t port_num, ds_cb_t *cb)
{
keyspan_state_t *ksp = (keyspan_state_t *)hdl;
keyspan_port_t *kp;
if (port_num >= ksp->ks_dev_spec.port_cnt) {
return (USB_FAILURE);
}
kp = &ksp->ks_ports[port_num];
kp->kp_cb = *cb;
return (USB_SUCCESS);
}
static void
keyspan_unregister_cb(ds_hdl_t hdl, uint_t port_num)
{
keyspan_state_t *ksp = (keyspan_state_t *)hdl;
keyspan_port_t *kp;
if (port_num < ksp->ks_dev_spec.port_cnt) {
kp = &ksp->ks_ports[port_num];
bzero(&kp->kp_cb, sizeof (kp->kp_cb));
}
}
int
keyspan_open_hw_port(keyspan_port_t *kp, boolean_t open_pipes)
{
int rval;
keyspan_state_t *ksp = kp->kp_ksp;
USB_DPRINTF_L4(DPRINT_OPEN, kp->kp_lh,
"keyspan_open_hw_port: [%d]", kp->kp_port_num);
if (open_pipes) {
if ((rval = keyspan_open_port_pipes(kp)) != USB_SUCCESS) {
return (rval);
}
}
mutex_enter(&kp->kp_mutex);
kp->kp_state = KEYSPAN_PORT_OPEN;
mutex_exit(&kp->kp_mutex);
switch (ksp->ks_dev_spec.id_product) {
case KEYSPAN_USA19HS_PID:
case KEYSPAN_USA49WLC_PID:
if ((rval = keyspan_receive_data(&kp->kp_datain_pipe,
kp->kp_read_len, kp)) != USB_SUCCESS) {
goto fail;
}
break;
case KEYSPAN_USA49WG_PID:
mutex_enter(&ksp->ks_mutex);
if ((ksp->ks_datain_open_cnt == 1) && open_pipes) {
mutex_exit(&ksp->ks_mutex);
if ((rval = keyspan_receive_data(&kp->kp_datain_pipe,
kp->kp_read_len, kp)) != USB_SUCCESS) {
goto fail;
}
} else if ((ksp->ks_reconnect_flag) && (!open_pipes)) {
mutex_exit(&ksp->ks_mutex);
if ((rval = keyspan_receive_data(&kp->kp_datain_pipe,
kp->kp_read_len, kp)) != USB_SUCCESS) {
goto fail;
}
mutex_enter(&ksp->ks_mutex);
ksp->ks_reconnect_flag = 0;
mutex_exit(&ksp->ks_mutex);
} else {
mutex_exit(&ksp->ks_mutex);
}
break;
default:
USB_DPRINTF_L2(DPRINT_OPEN, ksp->ks_lh, "keyspan_open_hw_port:"
"the device's product id can't be recognized");
return (USB_FAILURE);
}
mutex_enter(&kp->kp_mutex);
keyspan_default_port_params(kp);
mutex_exit(&kp->kp_mutex);
(void) keyspan_send_cmd(kp);
USB_DPRINTF_L4(DPRINT_OPEN, kp->kp_lh,
"keyspan_open_hw_port: [%d] finished", kp->kp_port_num);
return (rval);
fail:
mutex_enter(&kp->kp_mutex);
kp->kp_state = KEYSPAN_PORT_CLOSED;
mutex_exit(&kp->kp_mutex);
if (open_pipes) {
keyspan_close_port_pipes(kp);
}
USB_DPRINTF_L2(DPRINT_OPEN, kp->kp_lh,
"keyspan_open_hw_port: failed. This port can't be used.");
return (rval);
}
static int
keyspan_open_port(ds_hdl_t hdl, uint_t port_num)
{
keyspan_state_t *ksp = (keyspan_state_t *)hdl;
keyspan_port_t *kp = &ksp->ks_ports[port_num];
int rval;
if (port_num >= ksp->ks_dev_spec.port_cnt) {
return (USB_FAILURE);
}
USB_DPRINTF_L4(DPRINT_OPEN, kp->kp_lh, "keyspan_open_port");
mutex_enter(&ksp->ks_mutex);
if (ksp->ks_dev_state == USB_DEV_DISCONNECTED) {
mutex_exit(&ksp->ks_mutex);
return (USB_FAILURE);
}
mutex_exit(&ksp->ks_mutex);
if (keyspan_pm_set_busy(ksp) != USB_SUCCESS) {
return (USB_FAILURE);
}
mutex_enter(&kp->kp_mutex);
ASSERT(kp->kp_state == KEYSPAN_PORT_CLOSED);
ASSERT((kp->kp_rx_mp == NULL) && (kp->kp_tx_mp == NULL));
kp->kp_state = KEYSPAN_PORT_OPENING;
kp->kp_flags = 0;
mutex_exit(&kp->kp_mutex);
sema_p(&ksp->ks_pipes_sema);
rval = keyspan_open_hw_port(kp, B_TRUE);
if (rval != USB_SUCCESS) {
keyspan_pm_set_idle(ksp);
}
sema_v(&ksp->ks_pipes_sema);
return (rval);
}
void
keyspan_close_hw_port(keyspan_port_t *kp)
{
keyspan_state_t *ksp = kp->kp_ksp;
ASSERT(!mutex_owned(&kp->kp_mutex));
USB_DPRINTF_L4(DPRINT_CLOSE, kp->kp_lh,
"keyspan_close_hw_port");
mutex_enter(&kp->kp_mutex);
if ((kp->kp_datain_pipe.pipe_handle == NULL) &&
(kp->kp_dataout_pipe.pipe_handle == NULL)) {
mutex_exit(&kp->kp_mutex);
return;
}
switch (ksp->ks_dev_spec.id_product) {
case KEYSPAN_USA19HS_PID:
keyspan_build_cmd_msg_usa19hs(kp, NULL);
kp->kp_ctrl_msg.usa19hs.portEnabled = 0;
kp->kp_ctrl_msg.usa19hs.rxFlush = 0;
kp->kp_ctrl_msg.usa19hs.txFlush = 0;
kp->kp_ctrl_msg.usa19hs.returnStatus = 0;
kp->kp_ctrl_msg.usa19hs.setRts = 1;
kp->kp_ctrl_msg.usa19hs.rts = 0;
kp->kp_ctrl_msg.usa19hs.setDtr = 1;
kp->kp_ctrl_msg.usa19hs.dtr = 0;
kp->kp_ctrl_msg.usa19hs.setTxFlowControl = 1;
kp->kp_ctrl_msg.usa19hs.txFlowControl = 0;
kp->kp_ctrl_msg.usa19hs.setRxFlowControl = 1;
kp->kp_ctrl_msg.usa19hs.rxFlowControl = 0;
kp->kp_ctrl_msg.usa19hs.rxForwardingTimeout = 0;
kp->kp_ctrl_msg.usa19hs.rxForwardingLength = 0;
break;
case KEYSPAN_USA49WLC_PID:
case KEYSPAN_USA49WG_PID:
keyspan_build_cmd_msg_usa49(kp, NULL);
kp->kp_ctrl_msg.usa49._txOn = 0;
kp->kp_ctrl_msg.usa49._txOff = 1;
kp->kp_ctrl_msg.usa49.txFlush = 0;
kp->kp_ctrl_msg.usa49.txBreak = 0;
kp->kp_ctrl_msg.usa49.rxOn = 0;
kp->kp_ctrl_msg.usa49.rxOff = 1;
kp->kp_ctrl_msg.usa49.rxFlush = 0;
kp->kp_ctrl_msg.usa49.rxForward = 0;
kp->kp_ctrl_msg.usa49.returnStatus = 0;
kp->kp_ctrl_msg.usa49.resetDataToggle = 0;
kp->kp_ctrl_msg.usa49.enablePort = 0;
kp->kp_ctrl_msg.usa49.disablePort = 1;
break;
default:
USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
"keyspan_close_hw_port:"
"the device's product id can't be recognized");
mutex_exit(&kp->kp_mutex);
return;
}
mutex_exit(&kp->kp_mutex);
if (keyspan_send_cmd(kp) != USB_SUCCESS) {
USB_DPRINTF_L2(DPRINT_CTLOP, kp->kp_lh,
"keyspan_close_hw_port: closing hw port, send cmd FAILED");
}
switch (ksp->ks_dev_spec.id_product) {
case KEYSPAN_USA19HS_PID:
case KEYSPAN_USA49WLC_PID:
usb_pipe_reset(ksp->ks_dip,
kp->kp_datain_pipe.pipe_handle,
USB_FLAGS_SLEEP, NULL, NULL);
break;
case KEYSPAN_USA49WG_PID:
mutex_enter(&ksp->ks_mutex);
if (ksp->ks_datain_open_cnt == 1) {
mutex_exit(&ksp->ks_mutex);
usb_pipe_reset(ksp->ks_dip,
kp->kp_datain_pipe.pipe_handle,
USB_FLAGS_SLEEP, NULL, NULL);
} else {
mutex_exit(&ksp->ks_mutex);
}
break;
default:
USB_DPRINTF_L2(DPRINT_CLOSE, kp->kp_lh,
"keyspan_close_hw_port: the device's"
" product id can't be recognized");
}
(void) keyspan_close_port_pipes(kp);
}
static int
keyspan_close_port(ds_hdl_t hdl, uint_t port_num)
{
keyspan_state_t *ksp = (keyspan_state_t *)hdl;
keyspan_port_t *kp = &ksp->ks_ports[port_num];
if (port_num >= ksp->ks_dev_spec.port_cnt) {
return (USB_FAILURE);
}
USB_DPRINTF_L4(DPRINT_CLOSE, kp->kp_lh, "keyspan_close_port");
sema_p(&ksp->ks_pipes_sema);
mutex_enter(&kp->kp_mutex);
kp->kp_no_more_reads = B_TRUE;
mutex_exit(&kp->kp_mutex);
keyspan_close_hw_port(kp);
mutex_enter(&kp->kp_mutex);
if (kp->kp_rx_mp) {
freemsg(kp->kp_rx_mp);
kp->kp_rx_mp = NULL;
}
if (kp->kp_tx_mp) {
freemsg(kp->kp_tx_mp);
kp->kp_tx_mp = NULL;
}
kp->kp_no_more_reads = B_FALSE;
kp->kp_state = KEYSPAN_PORT_CLOSED;
mutex_exit(&kp->kp_mutex);
keyspan_pm_set_idle(ksp);
sema_v(&ksp->ks_pipes_sema);
return (USB_SUCCESS);
}
static int
keyspan_usb_power(ds_hdl_t hdl, int comp, int level, int *new_state)
{
keyspan_state_t *ksp = (keyspan_state_t *)hdl;
keyspan_pm_t *pm = ksp->ks_pm;
int rval;
USB_DPRINTF_L4(DPRINT_PM, ksp->ks_lh, "keyspan_usb_power");
mutex_enter(&ksp->ks_mutex);
if (USB_DEV_PWRSTATE_OK(pm->pm_pwr_states, level)) {
USB_DPRINTF_L2(DPRINT_PM, ksp->ks_lh, "keyspan_usb_power:"
"illegal power level %d, pwr_states=%x",
level, pm->pm_pwr_states);
mutex_exit(&ksp->ks_mutex);
return (USB_FAILURE);
}
if (pm->pm_raise_power && (level < (int)pm->pm_cur_power)) {
mutex_exit(&ksp->ks_mutex);
return (USB_FAILURE);
}
switch (level) {
case USB_DEV_OS_PWR_OFF:
rval = keyspan_pwrlvl0(ksp);
break;
case USB_DEV_OS_PWR_1:
rval = keyspan_pwrlvl1(ksp);
break;
case USB_DEV_OS_PWR_2:
rval = keyspan_pwrlvl2(ksp);
break;
case USB_DEV_OS_FULL_PWR:
rval = keyspan_pwrlvl3(ksp);
if ((rval == USB_SUCCESS) &&
((*new_state == USB_DEV_DISCONNECTED) ||
(*new_state == USB_DEV_SUSPENDED))) {
ksp->ks_dev_state = *new_state;
}
break;
default:
ASSERT(0);
}
*new_state = ksp->ks_dev_state;
mutex_exit(&ksp->ks_mutex);
return (rval);
}
static int
keyspan_suspend(ds_hdl_t hdl)
{
keyspan_state_t *ksp = (keyspan_state_t *)hdl;
int state = USB_DEV_SUSPENDED;
USB_DPRINTF_L4(DPRINT_PM, ksp->ks_lh, "keyspan_suspend");
mutex_enter(&ksp->ks_mutex);
if (ksp->ks_dev_state != USB_DEV_PWRED_DOWN) {
ksp->ks_dev_state = USB_DEV_SUSPENDED;
}
mutex_exit(&ksp->ks_mutex);
keyspan_disconnect_pipes(ksp);
return (state);
}
static int
keyspan_resume(ds_hdl_t hdl)
{
keyspan_state_t *ksp = (keyspan_state_t *)hdl;
int current_state;
int rval;
USB_DPRINTF_L4(DPRINT_PM, ksp->ks_lh, "keyspan_resume");
mutex_enter(&ksp->ks_mutex);
current_state = ksp->ks_dev_state;
mutex_exit(&ksp->ks_mutex);
if (current_state != USB_DEV_ONLINE) {
rval = keyspan_restore_device_state(ksp);
} else {
rval = USB_SUCCESS;
}
return (rval);
}
static int
keyspan_disconnect(ds_hdl_t hdl)
{
keyspan_state_t *ksp = (keyspan_state_t *)hdl;
int state = USB_DEV_DISCONNECTED;
USB_DPRINTF_L4(DPRINT_HOTPLUG, ksp->ks_lh, "keyspan_disconnect");
mutex_enter(&ksp->ks_mutex);
if (ksp->ks_dev_state != USB_DEV_PWRED_DOWN) {
ksp->ks_dev_state = USB_DEV_DISCONNECTED;
}
mutex_exit(&ksp->ks_mutex);
keyspan_disconnect_pipes(ksp);
return (state);
}
static int
keyspan_reconnect(ds_hdl_t hdl)
{
keyspan_state_t *ksp = (keyspan_state_t *)hdl;
USB_DPRINTF_L4(DPRINT_HOTPLUG, ksp->ks_lh, "keyspan_reconnect");
return (keyspan_restore_device_state(ksp));
}
static int
keyspan_set_port_params(ds_hdl_t hdl, uint_t port_num, ds_port_params_t *tp)
{
int cnt = tp->tp_cnt;
keyspan_state_t *ksp = (keyspan_state_t *)hdl;
keyspan_port_t *kp = &ksp->ks_ports[port_num];
ASSERT(port_num < ksp->ks_dev_spec.port_cnt);
USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh,
"keyspan_set_port_params: port: %d params", cnt);
if (cnt <= 0) {
return (USB_SUCCESS);
}
mutex_enter(&kp->kp_mutex);
ASSERT((kp->kp_state == KEYSPAN_PORT_OPENING) ||
(kp->kp_state == KEYSPAN_PORT_OPEN));
keyspan_build_cmd_msg(kp, tp);
mutex_exit(&kp->kp_mutex);
if (keyspan_send_cmd(kp) != USB_SUCCESS) {
USB_DPRINTF_L2(DPRINT_CTLOP, kp->kp_lh,
"keyspan_send_cmd() FAILED");
return (USB_FAILURE);
}
return (USB_SUCCESS);
}
static int
keyspan_set_modem_ctl(ds_hdl_t hdl, uint_t port_num, int mask, int val)
{
keyspan_state_t *ksp = (keyspan_state_t *)hdl;
keyspan_port_t *kp = &ksp->ks_ports[port_num];
ASSERT(port_num < ksp->ks_dev_spec.port_cnt);
mutex_enter(&kp->kp_mutex);
USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh, "keyspan_set_modem_ctl: "
"mask=%x, val=%x", mask, val);
keyspan_build_cmd_msg(kp, NULL);
switch (ksp->ks_dev_spec.id_product) {
case KEYSPAN_USA19HS_PID:
if (mask & TIOCM_RTS) {
kp->kp_ctrl_msg.usa19hs.setRts = 0x01;
if (val & TIOCM_RTS) {
kp->kp_ctrl_msg.usa19hs.rts = 0x1;
} else {
kp->kp_ctrl_msg.usa19hs.rts = 0x0;
}
} else {
kp->kp_ctrl_msg.usa19hs.setRts = 0x0;
}
if (mask & TIOCM_DTR) {
kp->kp_ctrl_msg.usa19hs.setDtr = 0x01;
if (val & TIOCM_DTR) {
kp->kp_ctrl_msg.usa19hs.dtr = 0x1;
} else {
kp->kp_ctrl_msg.usa19hs.dtr = 0x0;
}
} else {
kp->kp_ctrl_msg.usa19hs.setDtr = 0x0;
}
break;
case KEYSPAN_USA49WLC_PID:
case KEYSPAN_USA49WG_PID:
if (mask & TIOCM_RTS) {
kp->kp_ctrl_msg.usa49.setRts = 0x1;
if (val & TIOCM_RTS) {
kp->kp_ctrl_msg.usa49.rts = 0x1;
} else {
kp->kp_ctrl_msg.usa49.rts = 0x0;
}
} else {
kp->kp_ctrl_msg.usa49.setRts = 0x0;
}
if (mask & TIOCM_DTR) {
kp->kp_ctrl_msg.usa49.setDtr = 0x1;
if (val & TIOCM_DTR) {
kp->kp_ctrl_msg.usa49.dtr = 0x1;
} else {
kp->kp_ctrl_msg.usa49.dtr = 0x0;
}
} else {
kp->kp_ctrl_msg.usa49.setDtr = 0x0;
}
break;
default:
USB_DPRINTF_L2(DPRINT_CTLOP, kp->kp_lh,
"keyspan_get_modem_ctl:"
"the device's product id can't be recognized");
mutex_exit(&kp->kp_mutex);
return (USB_FAILURE);
}
mutex_exit(&kp->kp_mutex);
if (keyspan_send_cmd(kp) != USB_SUCCESS) {
USB_DPRINTF_L2(DPRINT_CTLOP, kp->kp_lh,
"keyspan_send_cmd() FAILED");
return (USB_FAILURE);
}
return (USB_SUCCESS);
}
static int
keyspan_get_modem_ctl(ds_hdl_t hdl, uint_t port_num, int mask, int *valp)
{
keyspan_state_t *ksp = (keyspan_state_t *)hdl;
keyspan_port_t *kp = &ksp->ks_ports[port_num];
int val = 0;
ASSERT(port_num < ksp->ks_dev_spec.port_cnt);
mutex_enter(&kp->kp_mutex);
if (kp->kp_status_flag & KEYSPAN_PORT_RTS) {
val |= TIOCM_RTS;
}
if (kp->kp_status_flag & KEYSPAN_PORT_DTR) {
val |= TIOCM_DTR;
}
switch (ksp->ks_dev_spec.id_product) {
case KEYSPAN_USA19HS_PID:
if (kp->kp_status_msg.usa19hs.dcd) {
val |= TIOCM_CD;
}
if (kp->kp_status_msg.usa19hs.cts) {
val |= TIOCM_CTS;
}
if (kp->kp_status_msg.usa19hs.dsr) {
val |= TIOCM_DSR;
}
break;
case KEYSPAN_USA49WLC_PID:
case KEYSPAN_USA49WG_PID:
if (kp->kp_status_msg.usa49.dcd) {
val |= TIOCM_CD;
}
if (kp->kp_status_msg.usa49.cts) {
val |= TIOCM_CTS;
}
if (kp->kp_status_msg.usa49.dsr) {
val |= TIOCM_DSR;
}
break;
default:
USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
"keyspan_get_modem_ctl:"
"the device's product id can't be recognized");
mutex_exit(&kp->kp_mutex);
return (USB_FAILURE);
}
*valp = val & mask;
USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh, "keyspan_get_modem_ctl:"
"success. status_flag = %x, val=0%o",
kp->kp_status_flag, *valp);
mutex_exit(&kp->kp_mutex);
return (USB_SUCCESS);
}
static int
keyspan_break_ctl(ds_hdl_t hdl, uint_t port_num, int ctl)
{
keyspan_state_t *ksp = (keyspan_state_t *)hdl;
keyspan_port_t *kp = &ksp->ks_ports[port_num];
int is_break;
int rval = USB_SUCCESS;
ASSERT(port_num < ksp->ks_dev_spec.port_cnt);
USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh,
"keyspan_break_ctl: ctl = %s", (ctl == DS_ON) ? "on" : "off");
mutex_enter(&kp->kp_mutex);
ASSERT(kp->kp_state == KEYSPAN_PORT_OPEN);
ASSERT(ctl == DS_ON || ctl == DS_OFF);
is_break = kp->kp_status_flag & KEYSPAN_PORT_TXBREAK;
if ((ctl == DS_ON) && !is_break) {
keyspan_build_cmd_msg(kp, NULL);
switch (ksp->ks_dev_spec.id_product) {
case KEYSPAN_USA19HS_PID:
kp->kp_ctrl_msg.usa19hs.txBreak = 1;
break;
case KEYSPAN_USA49WLC_PID:
case KEYSPAN_USA49WG_PID:
kp->kp_ctrl_msg.usa49.txBreak = 1;
break;
default:
mutex_exit(&kp->kp_mutex);
USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
"keyspan_break_ctl:"
"the device's product id can't be recognized");
return (USB_FAILURE);
}
mutex_exit(&kp->kp_mutex);
rval = keyspan_send_cmd(kp);
return (rval);
}
if ((ctl == DS_OFF) && is_break) {
keyspan_build_cmd_msg(kp, NULL);
switch (ksp->ks_dev_spec.id_product) {
case KEYSPAN_USA19HS_PID:
kp->kp_ctrl_msg.usa19hs.txBreak = 0;
break;
case KEYSPAN_USA49WLC_PID:
case KEYSPAN_USA49WG_PID:
kp->kp_ctrl_msg.usa49._txOn = 1;
kp->kp_ctrl_msg.usa49.txBreak = 0;
break;
default:
mutex_exit(&kp->kp_mutex);
USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
"keyspan_break_ctl:"
"the device's product id can't be recognized");
return (USB_FAILURE);
}
mutex_exit(&kp->kp_mutex);
rval = keyspan_send_cmd(kp);
if (rval == USB_SUCCESS) {
mutex_enter(&kp->kp_mutex);
keyspan_tx_start(kp, NULL);
mutex_exit(&kp->kp_mutex);
}
return (rval);
}
mutex_exit(&kp->kp_mutex);
USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh,
"keyspan_break_ctl: not necessary to set break, is_break = %d",
is_break);
return (rval);
}
static int
keyspan_loopback(ds_hdl_t hdl, uint_t port_num, int ctl)
{
keyspan_state_t *ksp = (keyspan_state_t *)hdl;
keyspan_port_t *kp = &ksp->ks_ports[port_num];
int is_loop;
int rval = USB_SUCCESS;
ASSERT(port_num < ksp->ks_dev_spec.port_cnt);
USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh,
"keyspan_loopback: %s", (ctl == DS_ON) ? "on" : "off");
mutex_enter(&kp->kp_mutex);
ASSERT(kp->kp_state == KEYSPAN_PORT_OPEN);
ASSERT(ctl == DS_ON || ctl == DS_OFF);
is_loop = kp->kp_status_flag & KEYSPAN_PORT_LOOPBACK;
if ((ctl == DS_ON) && !is_loop) {
keyspan_build_cmd_msg(kp, NULL);
switch (ksp->ks_dev_spec.id_product) {
case KEYSPAN_USA19HS_PID:
kp->kp_ctrl_msg.usa19hs.loopbackMode = 0;
break;
case KEYSPAN_USA49WLC_PID:
case KEYSPAN_USA49WG_PID:
kp->kp_ctrl_msg.usa49.loopbackMode = 0;
break;
default:
mutex_exit(&kp->kp_mutex);
USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
"keyspan_loopback:"
"the device's product id can't be recognized");
return (USB_FAILURE);
}
mutex_exit(&kp->kp_mutex);
rval = keyspan_send_cmd(kp);
} else if ((ctl == DS_OFF) && is_loop) {
keyspan_build_cmd_msg(kp, NULL);
switch (ksp->ks_dev_spec.id_product) {
case KEYSPAN_USA19HS_PID:
kp->kp_ctrl_msg.usa19hs.loopbackMode = 1;
break;
case KEYSPAN_USA49WLC_PID:
case KEYSPAN_USA49WG_PID:
kp->kp_ctrl_msg.usa49.loopbackMode = 1;
break;
default:
mutex_exit(&kp->kp_mutex);
USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
"keyspan_loopback:"
"the device's product id can't be recognized");
return (USB_FAILURE);
}
mutex_exit(&kp->kp_mutex);
rval = keyspan_send_cmd(kp);
} else {
mutex_exit(&kp->kp_mutex);
USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh,
"keyspan_loopback: not necessary to set loopback,"
"is_loop = %d", is_loop);
}
return (rval);
}
static int
keyspan_tx(ds_hdl_t hdl, uint_t port_num, mblk_t *mp)
{
keyspan_state_t *ksp = (keyspan_state_t *)hdl;
keyspan_port_t *kp = &ksp->ks_ports[port_num];
int xferd;
ASSERT(port_num < ksp->ks_dev_spec.port_cnt);
USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh, "keyspan_tx");
if (mp == NULL) {
USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh, "keyspan_tx: mp=NULL");
return (USB_SUCCESS);
}
kp = &ksp->ks_ports[port_num];
mutex_enter(&kp->kp_mutex);
keyspan_put_tail(&kp->kp_tx_mp, mp);
keyspan_tx_start(kp, &xferd);
mutex_exit(&kp->kp_mutex);
return (USB_SUCCESS);
}
static mblk_t *
keyspan_rx(ds_hdl_t hdl, uint_t port_num)
{
keyspan_state_t *ksp = (keyspan_state_t *)hdl;
keyspan_port_t *kp = &ksp->ks_ports[port_num];
mblk_t *mp;
ASSERT(port_num < ksp->ks_dev_spec.port_cnt);
USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh, "keyspan_rx");
mutex_enter(&kp->kp_mutex);
mp = kp->kp_rx_mp;
kp->kp_rx_mp = NULL;
mutex_exit(&kp->kp_mutex);
return (mp);
}
static void
keyspan_stop(ds_hdl_t hdl, uint_t port_num, int dir)
{
keyspan_state_t *ksp = (keyspan_state_t *)hdl;
keyspan_port_t *kp = &ksp->ks_ports[port_num];
ASSERT(port_num < ksp->ks_dev_spec.port_cnt);
USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh, "keyspan_stop");
if (dir & DS_TX) {
mutex_enter(&kp->kp_mutex);
kp->kp_flags |= KEYSPAN_PORT_TX_STOPPED;
mutex_exit(&kp->kp_mutex);
}
}
static void
keyspan_start(ds_hdl_t hdl, uint_t port_num, int dir)
{
keyspan_state_t *ksp = (keyspan_state_t *)hdl;
keyspan_port_t *kp = &ksp->ks_ports[port_num];
ASSERT(port_num < ksp->ks_dev_spec.port_cnt);
USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh, "keyspan_start");
if (dir & DS_TX) {
mutex_enter(&kp->kp_mutex);
if (kp->kp_flags & KEYSPAN_PORT_TX_STOPPED) {
kp->kp_flags &= ~KEYSPAN_PORT_TX_STOPPED;
keyspan_tx_start(kp, NULL);
}
mutex_exit(&kp->kp_mutex);
}
}
static int
keyspan_fifo_flush(ds_hdl_t hdl, uint_t port_num, int dir)
{
keyspan_state_t *ksp = (keyspan_state_t *)hdl;
keyspan_port_t *kp = &ksp->ks_ports[port_num];
ASSERT(port_num < ksp->ks_dev_spec.port_cnt);
USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh,
"keyspan_fifo_flush: dir=%x", dir);
mutex_enter(&kp->kp_mutex);
ASSERT(kp->kp_state == KEYSPAN_PORT_OPEN);
if ((dir & DS_TX) && kp->kp_tx_mp) {
freemsg(kp->kp_tx_mp);
kp->kp_tx_mp = NULL;
}
if ((dir & DS_RX) && kp->kp_rx_mp) {
freemsg(kp->kp_rx_mp);
kp->kp_rx_mp = NULL;
}
mutex_exit(&kp->kp_mutex);
return (USB_SUCCESS);
}
static int
keyspan_fifo_drain(ds_hdl_t hdl, uint_t port_num, int timeout)
{
keyspan_state_t *ksp = (keyspan_state_t *)hdl;
keyspan_port_t *kp = &ksp->ks_ports[port_num];
int rval = USB_SUCCESS;
ASSERT(port_num < ksp->ks_dev_spec.port_cnt);
USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh,
"keyspan_fifo_drain, timeout = %d", timeout);
mutex_enter(&kp->kp_mutex);
ASSERT(kp->kp_state == KEYSPAN_PORT_OPEN);
if (keyspan_wait_tx_drain(kp, 0) != USB_SUCCESS) {
mutex_exit(&kp->kp_mutex);
return (USB_FAILURE);
}
mutex_exit(&kp->kp_mutex);
delay(drv_usectohz(500*1000));
return (rval);
}
static void
keyspan_free_soft_state(keyspan_state_t *ksp)
{
kmem_free(ksp, sizeof (keyspan_state_t));
}
static int
keyspan_usb_register(keyspan_state_t *ksp)
{
int rval;
rval = usb_client_attach(ksp->ks_dip, USBDRV_VERSION, 0);
if (rval == USB_SUCCESS) {
rval = usb_get_dev_data(ksp->ks_dip, &ksp->ks_dev_data,
USB_PARSE_LVL_IF, 0);
if (rval == USB_SUCCESS) {
ksp->ks_lh =
usb_alloc_log_hdl(ksp->ks_dip, "keyspan[*].",
&keyspan_errlevel, &keyspan_errmask,
&keyspan_instance_debug, 0);
ksp->ks_def_pipe.pipe_handle =
ksp->ks_dev_data->dev_default_ph;
ksp->ks_def_pipe.pipe_ksp = ksp;
ksp->ks_def_pipe.pipe_lh = ksp->ks_lh;
}
}
return (rval);
}
static void
keyspan_usb_unregister(keyspan_state_t *ksp)
{
usb_free_log_hdl(ksp->ks_lh);
ksp->ks_lh = NULL;
usb_client_detach(ksp->ks_dip, ksp->ks_dev_data);
ksp->ks_def_pipe.pipe_handle = NULL;
ksp->ks_dev_data = NULL;
}
static void
keyspan_init_sync_objs(keyspan_state_t *ksp)
{
mutex_init(&ksp->ks_mutex, NULL, MUTEX_DRIVER,
ksp->ks_dev_data->dev_iblock_cookie);
sema_init(&ksp->ks_pipes_sema, 1, NULL, SEMA_DRIVER, NULL);
}
static void
keyspan_fini_sync_objs(keyspan_state_t *ksp)
{
mutex_destroy(&ksp->ks_mutex);
sema_destroy(&ksp->ks_pipes_sema);
}
static int
keyspan_attach_dev(keyspan_state_t *ksp)
{
mutex_enter(&ksp->ks_mutex);
switch (ksp->ks_dev_data->dev_descr->idProduct) {
case KEYSPAN_USA19HS_PID:
ksp->ks_dev_spec.id_product = KEYSPAN_USA19HS_PID;
ksp->ks_dev_spec.port_cnt = 1;
ksp->ks_dev_spec.ctrl_ep_addr = 0x02;
ksp->ks_dev_spec.stat_ep_addr = 0x82;
ksp->ks_dev_spec.dataout_ep_addr[0] = 0x01;
ksp->ks_dev_spec.datain_ep_addr[0] = 0x81;
break;
case KEYSPAN_USA49WLC_PID:
ksp->ks_dev_spec.id_product = KEYSPAN_USA49WLC_PID;
ksp->ks_dev_spec.port_cnt = 4;
ksp->ks_dev_spec.ctrl_ep_addr = 0x07;
ksp->ks_dev_spec.stat_ep_addr = 0x87;
ksp->ks_dev_spec.dataout_ep_addr[0] = 0x01;
ksp->ks_dev_spec.dataout_ep_addr[1] = 0x02;
ksp->ks_dev_spec.dataout_ep_addr[2] = 0x03;
ksp->ks_dev_spec.dataout_ep_addr[3] = 0x04;
ksp->ks_dev_spec.datain_ep_addr[0] = 0x81;
ksp->ks_dev_spec.datain_ep_addr[1] = 0x82;
ksp->ks_dev_spec.datain_ep_addr[2] = 0x83;
ksp->ks_dev_spec.datain_ep_addr[3] = 0x84;
break;
case KEYSPAN_USA49WG_PID:
ksp->ks_dev_spec.id_product = KEYSPAN_USA49WG_PID;
ksp->ks_dev_spec.port_cnt = 4;
ksp->ks_dev_spec.stat_ep_addr = 0x81;
ksp->ks_dev_spec.dataout_ep_addr[0] = 0x01;
ksp->ks_dev_spec.dataout_ep_addr[1] = 0x02;
ksp->ks_dev_spec.dataout_ep_addr[2] = 0x04;
ksp->ks_dev_spec.dataout_ep_addr[3] = 0x06;
ksp->ks_dev_spec.datain_ep_addr[0] = 0x88;
ksp->ks_dev_spec.datain_ep_addr[1] = 0x88;
ksp->ks_dev_spec.datain_ep_addr[2] = 0x88;
ksp->ks_dev_spec.datain_ep_addr[3] = 0x88;
break;
default:
mutex_exit(&ksp->ks_mutex);
USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
"keyspan_attach_dev:"
"the device's product id can't be recognized");
return (USB_FAILURE);
}
mutex_exit(&ksp->ks_mutex);
return (USB_SUCCESS);
}
static void
keyspan_attach_ports(keyspan_state_t *ksp)
{
int i;
keyspan_port_t *kp;
ksp->ks_ports = kmem_zalloc(ksp->ks_dev_spec.port_cnt *
sizeof (keyspan_port_t), KM_SLEEP);
for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) {
kp = &ksp->ks_ports[i];
kp->kp_port_num = i;
kp->kp_ksp = ksp;
(void) sprintf(kp->kp_lh_name, "keyspan[%d].", i);
kp->kp_lh = usb_alloc_log_hdl(ksp->ks_dip, kp->kp_lh_name,
&keyspan_errlevel, &keyspan_errmask,
&keyspan_instance_debug, 0);
kp->kp_state = KEYSPAN_PORT_CLOSED;
mutex_init(&kp->kp_mutex, NULL, MUTEX_DRIVER,
ksp->ks_dev_data->dev_iblock_cookie);
cv_init(&kp->kp_tx_cv, NULL, CV_DRIVER, NULL);
}
}
static void
keyspan_detach_ports(keyspan_state_t *ksp)
{
int i;
keyspan_port_t *kp;
for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) {
kp = &ksp->ks_ports[i];
if (kp->kp_state != KEYSPAN_PORT_NOT_INIT) {
ASSERT(kp->kp_state == KEYSPAN_PORT_CLOSED);
mutex_destroy(&kp->kp_mutex);
cv_destroy(&kp->kp_tx_cv);
usb_free_log_hdl(kp->kp_lh);
}
}
kmem_free(ksp->ks_ports,
ksp->ks_dev_spec.port_cnt * sizeof (keyspan_port_t));
}
static void
keyspan_init_port_params(keyspan_state_t *ksp)
{
int i;
size_t sz;
uint_t read_len;
uint_t write_len;
if (usb_pipe_get_max_bulk_transfer_size(ksp->ks_dip, &sz) ==
USB_SUCCESS) {
if (ksp->ks_dev_spec.id_product == KEYSPAN_USA49WG_PID) {
read_len = (uint_t)min(sz, KEYSPAN_BULKIN_MAX_LEN_49WG);
} else {
read_len = (uint_t)min(sz, KEYSPAN_BULKIN_MAX_LEN);
}
} else {
if (ksp->ks_dev_spec.id_product == KEYSPAN_USA49WG_PID) {
read_len = KEYSPAN_BULKIN_MAX_LEN_49WG;
} else {
read_len = KEYSPAN_BULKIN_MAX_LEN;
}
}
for (i = 0; i < ksp->ks_dev_spec.port_cnt; i++) {
ksp->ks_ports[i].kp_read_len = read_len;
switch (ksp->ks_dev_spec.id_product) {
case KEYSPAN_USA19HS_PID:
ksp->ks_ports[i].kp_write_len =
KEYSPAN_BULKOUT_MAX_LEN_19HS;
break;
case KEYSPAN_USA49WLC_PID:
ksp->ks_ports[i].kp_write_len =
KEYSPAN_BULKOUT_MAX_LEN_49WLC;
break;
case KEYSPAN_USA49WG_PID:
write_len = ((i == 0) ? KEYSPAN_BULKOUT_MAX_LEN_49WLC :
KEYSPAN_BULKOUT_MAX_LEN_49WG);
ksp->ks_ports[i].kp_write_len = write_len;
break;
default:
USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
"keyspan_init_port_params:"
"the device's product id can't be recognized");
return;
}
}
}
static void
keyspan_free_descr_tree(keyspan_state_t *ksp)
{
usb_free_descr_tree(ksp->ks_dip, ksp->ks_dev_data);
}
static int
keyspan_register_events(keyspan_state_t *ksp)
{
return (usb_register_event_cbs(ksp->ks_dip, ksp->ks_usb_events, 0));
}
static void
keyspan_unregister_events(keyspan_state_t *ksp)
{
usb_unregister_event_cbs(ksp->ks_dip, ksp->ks_usb_events);
}
static void
keyspan_set_dev_state_online(keyspan_state_t *ksp)
{
ksp->ks_dev_state = USB_DEV_ONLINE;
}
int
keyspan_send_cmd_usa49(keyspan_port_t *kp)
{
keyspan_state_t *ksp = kp->kp_ksp;
mblk_t *mp;
int rval = USB_SUCCESS;
int size;
usb_bulk_req_t *br;
ASSERT(!mutex_owned(&kp->kp_mutex));
USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh, "keyspan_send_cmd_usa49");
switch (ksp->ks_dev_spec.id_product) {
case KEYSPAN_USA19HS_PID:
size = sizeof (keyspan_usa19hs_port_ctrl_msg_t);
break;
case KEYSPAN_USA49WLC_PID:
size = sizeof (keyspan_usa49_port_ctrl_msg_t);
break;
default:
USB_DPRINTF_L2(DPRINT_CTLOP, ksp->ks_lh,
"keyspan_send_cmd_usa49:"
"the device's product id can't be recognized");
return (USB_FAILURE);
}
if ((mp = allocb(size, BPRI_LO)) == NULL) {
return (USB_FAILURE);
}
bcopy(&kp->kp_ctrl_msg, mp->b_rptr, size);
br = usb_alloc_bulk_req(ksp->ks_dip, 0, USB_FLAGS_SLEEP);
br->bulk_len = size;
br->bulk_data = mp;
br->bulk_timeout = KEYSPAN_BULK_TIMEOUT;
br->bulk_client_private = (void *)kp;
br->bulk_attributes = USB_ATTRS_AUTOCLEARING;
rval = usb_pipe_bulk_xfer(ksp->ks_ctrlout_pipe.pipe_handle, br,
USB_FLAGS_SLEEP);
if (rval == USB_SUCCESS) {
mutex_enter(&kp->kp_mutex);
keyspan_save_port_params(kp);
mutex_exit(&kp->kp_mutex);
} else {
USB_DPRINTF_L2(DPRINT_CTLOP, kp->kp_lh, "keyspan_send_cmd_usa49"
": failure, rval=%d", rval);
}
usb_free_bulk_req(br);
return (rval);
}
int
keyspan_send_cmd_usa49wg(keyspan_port_t *kp)
{
keyspan_state_t *ksp = kp->kp_ksp;
mblk_t *mp;
int rval = USB_SUCCESS;
uint16_t size = sizeof (keyspan_usa49_port_ctrl_msg_t);
usb_cb_flags_t cb_flags;
usb_cr_t cr;
usb_ctrl_setup_t setup;
ASSERT(!mutex_owned(&kp->kp_mutex));
USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh, "keyspan_send_cmd_usa49wg");
if ((mp = allocb(size, BPRI_LO)) == NULL) {
return (USB_FAILURE);
}
bcopy(&kp->kp_ctrl_msg, mp->b_rptr, size);
setup.bmRequestType = USB_DEV_REQ_TYPE_VENDOR;
setup.bRequest = KEYSPAN_SET_CONTROL_REQUEST;
setup.wValue = 0;
setup.wIndex = 0;
setup.wLength = size;
setup.attrs = 0;
rval = usb_pipe_ctrl_xfer_wait(ksp->ks_def_pipe.pipe_handle, &setup,
&mp, &cr, &cb_flags, 0);
if (rval == USB_SUCCESS) {
mutex_enter(&kp->kp_mutex);
keyspan_save_port_params(kp);
mutex_exit(&kp->kp_mutex);
} else {
USB_DPRINTF_L2(DPRINT_CTLOP, kp->kp_lh,
"keyspan_send_cmd_usa49wg: failure, rval=%d", rval);
}
if (mp) {
freemsg(mp);
}
return (rval);
}
int
keyspan_send_cmd(keyspan_port_t *kp)
{
keyspan_state_t *ksp = kp->kp_ksp;
int rval = USB_FAILURE;
switch (ksp->ks_dev_spec.id_product) {
case KEYSPAN_USA19HS_PID:
case KEYSPAN_USA49WLC_PID:
rval = keyspan_send_cmd_usa49(kp);
break;
case KEYSPAN_USA49WG_PID:
rval = keyspan_send_cmd_usa49wg(kp);
break;
default:
USB_DPRINTF_L2(DPRINT_CTLOP, kp->kp_lh,
"keyspan_send_cmd: "
"the device's product id can't be recognized");
}
if (rval != USB_SUCCESS) {
USB_DPRINTF_L2(DPRINT_CTLOP, kp->kp_lh,
"keyspan_send_cmd() FAILED");
return (rval);
}
return (USB_SUCCESS);
}
static int
keyspan_restore_device_state(keyspan_state_t *ksp)
{
int state;
mutex_enter(&ksp->ks_mutex);
state = ksp->ks_dev_state;
mutex_exit(&ksp->ks_mutex);
if ((state != USB_DEV_DISCONNECTED) && (state != USB_DEV_SUSPENDED)) {
return (state);
}
if (usb_check_same_device(ksp->ks_dip, ksp->ks_lh, USB_LOG_L0,
DPRINT_MASK_ALL, USB_CHK_ALL, NULL) != USB_SUCCESS) {
mutex_enter(&ksp->ks_mutex);
state = ksp->ks_dev_state = USB_DEV_DISCONNECTED;
mutex_exit(&ksp->ks_mutex);
return (state);
}
if (state == USB_DEV_DISCONNECTED) {
USB_DPRINTF_L0(DPRINT_HOTPLUG, ksp->ks_lh,
"device has been reconnected but data may have been lost");
}
if (keyspan_reconnect_pipes(ksp) != USB_SUCCESS) {
return (state);
}
mutex_enter(&ksp->ks_mutex);
state = ksp->ks_dev_state = USB_DEV_ONLINE;
ksp->ks_reconnect_flag = 1;
mutex_exit(&ksp->ks_mutex);
(void) keyspan_restore_ports_state(ksp);
return (state);
}
static int
keyspan_restore_ports_state(keyspan_state_t *ksp)
{
keyspan_port_t *kp;
int rval = USB_SUCCESS;
int err;
int i;
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);
continue;
}
mutex_exit(&kp->kp_mutex);
sema_p(&ksp->ks_pipes_sema);
err = keyspan_open_hw_port(kp, B_FALSE);
sema_v(&ksp->ks_pipes_sema);
if (err != USB_SUCCESS) {
USB_DPRINTF_L2(DPRINT_HOTPLUG, kp->kp_lh,
"keyspan_restore_ports_state: failed");
rval = err;
}
}
return (rval);
}
static int
keyspan_create_pm_components(keyspan_state_t *ksp)
{
dev_info_t *dip = ksp->ks_dip;
keyspan_pm_t *pm;
uint_t pwr_states;
pm = ksp->ks_pm = kmem_zalloc(sizeof (keyspan_pm_t), KM_SLEEP);
pm->pm_cur_power = USB_DEV_OS_FULL_PWR;
if (usb_create_pm_components(dip, &pwr_states) != USB_SUCCESS) {
USB_DPRINTF_L2(DPRINT_PM, ksp->ks_lh,
"keyspan_create_pm_components: failed");
return (USB_SUCCESS);
}
pm->pm_wakeup_enabled = (usb_handle_remote_wakeup(dip,
USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS);
pm->pm_pwr_states = (uint8_t)pwr_states;
(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
return (USB_SUCCESS);
}
static void
keyspan_destroy_pm_components(keyspan_state_t *ksp)
{
keyspan_pm_t *pm = ksp->ks_pm;
dev_info_t *dip = ksp->ks_dip;
int rval;
if (ksp->ks_dev_state != USB_DEV_DISCONNECTED) {
if (pm->pm_wakeup_enabled) {
(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
rval = usb_handle_remote_wakeup(dip,
USB_REMOTE_WAKEUP_DISABLE);
if (rval != USB_SUCCESS) {
USB_DPRINTF_L2(DPRINT_PM, ksp->ks_lh,
"keyspan_destroy_pm_components: disable "
"remote wakeup failed, rval=%d", rval);
}
}
(void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
}
kmem_free(pm, sizeof (keyspan_pm_t));
ksp->ks_pm = NULL;
}
static int
keyspan_pm_set_busy(keyspan_state_t *ksp)
{
keyspan_pm_t *pm = ksp->ks_pm;
dev_info_t *dip = ksp->ks_dip;
USB_DPRINTF_L4(DPRINT_PM, ksp->ks_lh, "keyspan_pm_set_busy");
mutex_enter(&ksp->ks_mutex);
if (pm->pm_busy_cnt++ > 0) {
USB_DPRINTF_L3(DPRINT_PM, ksp->ks_lh, "keyspan_pm_set_busy:"
"already busy, busy_cnt = %d", pm->pm_busy_cnt);
mutex_exit(&ksp->ks_mutex);
return (USB_SUCCESS);
}
(void) pm_busy_component(dip, 0);
if (pm->pm_cur_power == USB_DEV_OS_FULL_PWR) {
mutex_exit(&ksp->ks_mutex);
return (USB_SUCCESS);
}
pm->pm_raise_power = B_TRUE;
mutex_exit(&ksp->ks_mutex);
USB_DPRINTF_L3(DPRINT_PM, ksp->ks_lh,
"keyspan_pm_set_busy: raise power");
(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
mutex_enter(&ksp->ks_mutex);
pm->pm_raise_power = B_FALSE;
mutex_exit(&ksp->ks_mutex);
return (USB_SUCCESS);
}
static void
keyspan_pm_set_idle(keyspan_state_t *ksp)
{
keyspan_pm_t *pm = ksp->ks_pm;
dev_info_t *dip = ksp->ks_dip;
USB_DPRINTF_L4(DPRINT_PM, ksp->ks_lh, "keyspan_pm_set_idle");
mutex_enter(&ksp->ks_mutex);
if (--pm->pm_busy_cnt > 0) {
mutex_exit(&ksp->ks_mutex);
return;
}
USB_DPRINTF_L4(DPRINT_PM, ksp->ks_lh, "keyspan_pm_set_idle: set idle");
(void) pm_idle_component(dip, 0);
mutex_exit(&ksp->ks_mutex);
}
static int
keyspan_pwrlvl0(keyspan_state_t *ksp)
{
int rval;
keyspan_pipe_t *statin = &ksp->ks_statin_pipe;
USB_DPRINTF_L4(DPRINT_PM, ksp->ks_lh, "keyspan_pwrlvl0");
switch (ksp->ks_dev_state) {
case USB_DEV_ONLINE:
rval = usb_set_device_pwrlvl3(ksp->ks_dip);
ASSERT(rval == USB_SUCCESS);
if (ksp->ks_dev_spec.id_product == KEYSPAN_USA49WG_PID) {
mutex_exit(&ksp->ks_mutex);
usb_pipe_stop_intr_polling(statin->pipe_handle,
USB_FLAGS_SLEEP);
mutex_enter(&ksp->ks_mutex);
mutex_enter(&statin->pipe_mutex);
statin->pipe_state = KEYSPAN_PIPE_CLOSED;
mutex_exit(&statin->pipe_mutex);
}
ksp->ks_dev_state = USB_DEV_PWRED_DOWN;
ksp->ks_pm->pm_cur_power = USB_DEV_OS_PWR_OFF;
case USB_DEV_DISCONNECTED:
case USB_DEV_SUSPENDED:
return (USB_SUCCESS);
case USB_DEV_PWRED_DOWN:
default:
USB_DPRINTF_L2(DPRINT_PM, ksp->ks_lh,
"keyspan_pwrlvl0: illegal device state");
return (USB_FAILURE);
}
}
static int
keyspan_pwrlvl1(keyspan_state_t *ksp)
{
USB_DPRINTF_L4(DPRINT_PM, ksp->ks_lh, "keyspan_pwrlvl1");
(void) usb_set_device_pwrlvl2(ksp->ks_dip);
return (USB_FAILURE);
}
static int
keyspan_pwrlvl2(keyspan_state_t *ksp)
{
USB_DPRINTF_L4(DPRINT_PM, ksp->ks_lh, "keyspan_pwrlvl2");
(void) usb_set_device_pwrlvl1(ksp->ks_dip);
return (USB_FAILURE);
}
static int
keyspan_pwrlvl3(keyspan_state_t *ksp)
{
int rval;
USB_DPRINTF_L4(DPRINT_PM, ksp->ks_lh, "keyspan_pwrlvl3");
switch (ksp->ks_dev_state) {
case USB_DEV_PWRED_DOWN:
rval = usb_set_device_pwrlvl0(ksp->ks_dip);
ASSERT(rval == USB_SUCCESS);
if (ksp->ks_dev_spec.id_product == KEYSPAN_USA49WG_PID) {
mutex_exit(&ksp->ks_mutex);
keyspan_pipe_start_polling(&ksp->ks_statin_pipe);
mutex_enter(&ksp->ks_mutex);
}
ksp->ks_dev_state = USB_DEV_ONLINE;
ksp->ks_pm->pm_cur_power = USB_DEV_OS_FULL_PWR;
case USB_DEV_ONLINE:
case USB_DEV_DISCONNECTED:
case USB_DEV_SUSPENDED:
return (USB_SUCCESS);
default:
USB_DPRINTF_L2(DPRINT_PM, ksp->ks_lh,
"keyspan_pwrlvl3: illegal device state");
return (USB_FAILURE);
}
}
static int
keyspan_attach_pipes(keyspan_state_t *ksp)
{
return (keyspan_open_dev_pipes(ksp));
}
void
keyspan_detach_pipes(keyspan_state_t *ksp)
{
if (ksp->ks_statin_pipe.pipe_handle) {
usb_pipe_stop_intr_polling(ksp->ks_statin_pipe.pipe_handle,
USB_FLAGS_SLEEP);
}
keyspan_close_dev_pipes(ksp);
}
static void
keyspan_disconnect_pipes(keyspan_state_t *ksp)
{
sema_p(&ksp->ks_pipes_sema);
keyspan_close_pipes(ksp);
sema_v(&ksp->ks_pipes_sema);
}
static int
keyspan_reconnect_pipes(keyspan_state_t *ksp)
{
int rval = USB_SUCCESS;
sema_p(&ksp->ks_pipes_sema);
rval = keyspan_reopen_pipes(ksp);
sema_v(&ksp->ks_pipes_sema);
return (rval);
}
void
keyspan_tx_start(keyspan_port_t *kp, int *xferd)
{
keyspan_state_t *ksp = kp->kp_ksp;
int len;
mblk_t *data;
int data_len = 0;
int tran_len;
int rval;
int status_len = 0;
ASSERT(!mutex_owned(&ksp->ks_mutex));
ASSERT(mutex_owned(&kp->kp_mutex));
ASSERT(kp->kp_state != KEYSPAN_PORT_CLOSED);
USB_DPRINTF_L4(DPRINT_OUT_PIPE, kp->kp_lh, "keyspan_tx_start");
if (xferd) {
*xferd = 0;
}
if ((kp->kp_flags & KEYSPAN_PORT_TX_STOPPED) ||
(kp->kp_tx_mp == NULL)) {
return;
}
len = min(msgdsize(kp->kp_tx_mp), kp->kp_write_len);
USB_DPRINTF_L4(DPRINT_OUT_PIPE, kp->kp_lh, "keyspan_tx_start:"
"len = %d, tx_mp_len = %d", len, (int)msgdsize(kp->kp_tx_mp));
mutex_exit(&kp->kp_mutex);
switch (ksp->ks_dev_spec.id_product) {
case KEYSPAN_USA19HS_PID:
if ((data = allocb(len, BPRI_LO)) == NULL) {
mutex_enter(&kp->kp_mutex);
return;
}
mutex_enter(&kp->kp_mutex);
data_len = keyspan_tx_copy_data(kp, data, len);
if (data_len <= 0) {
USB_DPRINTF_L3(DPRINT_OUT_PIPE, kp->kp_lh,
"keyspan_tx_start:keyspan_tx_copy_data copied"
" zero bytes");
}
break;
case KEYSPAN_USA49WLC_PID:
case KEYSPAN_USA49WG_PID:
status_len = len / 64 + 1;
if ((data = allocb(len + status_len, BPRI_LO)) == NULL) {
mutex_enter(&kp->kp_mutex);
return;
}
mutex_enter(&kp->kp_mutex);
while (data_len < len) {
*(data->b_wptr++) = 0;
tran_len = keyspan_tx_copy_data(kp, data, 63);
if (tran_len <= 0) {
USB_DPRINTF_L3(DPRINT_OUT_PIPE, kp->kp_lh,
"keyspan_tx_start:keyspan_tx_copy_data"
" copied zero bytes");
break;
}
data_len += tran_len;
}
break;
default:
mutex_enter(&kp->kp_mutex);
USB_DPRINTF_L2(DPRINT_OUT_PIPE, ksp->ks_lh, "keyspan_tx_start:"
"the device's product id can't be recognized");
return;
}
mutex_exit(&kp->kp_mutex);
if ((kp->kp_port_num == 0) &&
(ksp->ks_dev_spec.id_product == KEYSPAN_USA49WG_PID)) {
rval = keyspan_send_data_port0(&kp->kp_dataout_pipe, &data, kp);
} else {
rval = keyspan_send_data(&kp->kp_dataout_pipe, &data, kp);
}
mutex_enter(&kp->kp_mutex);
if (rval != USB_SUCCESS) {
ASSERT(data);
keyspan_put_head(&kp->kp_tx_mp, data, kp);
} else if (xferd) {
*xferd = data_len;
}
USB_DPRINTF_L4(DPRINT_OUT_PIPE, kp->kp_lh, "keyspan_tx_start[%d]: over"
"(%d) rval=%d", kp->kp_port_num, data_len, rval);
}
int
keyspan_tx_copy_data(keyspan_port_t *kp, mblk_t *data, int len)
{
mblk_t *mp;
int copylen;
int data_len = 0;
ASSERT(mutex_owned(&kp->kp_mutex));
if (msgdsize(kp->kp_tx_mp) == 0) {
data->b_wptr = data->b_rptr;
freeb(kp->kp_tx_mp);
kp->kp_tx_mp = NULL;
return (data_len);
}
while ((data_len < len) && kp->kp_tx_mp) {
mp = kp->kp_tx_mp;
copylen = min(MBLKL(mp), len - data_len);
bcopy(mp->b_rptr, data->b_wptr, copylen);
mp->b_rptr += copylen;
data->b_wptr += copylen;
data_len += copylen;
if (MBLKL(mp) < 1) {
kp->kp_tx_mp = unlinkb(mp);
freeb(mp);
} else {
ASSERT(data_len == len);
}
}
USB_DPRINTF_L3(DPRINT_OUT_DATA, kp->kp_lh, "keyspan_tx_copy_data:"
"copied data_len = %d", data_len);
return (data_len);
}
static int
keyspan_wait_tx_drain(keyspan_port_t *kp, int timeout)
{
clock_t until;
int over = 0;
USB_DPRINTF_L4(DPRINT_OUT_DATA, kp->kp_lh, "keyspan_wait_tx_drain:"
"timeout = %d", timeout);
until = ddi_get_lbolt() + drv_usectohz(1000000 * timeout);
while (kp->kp_tx_mp && !over) {
if (timeout > 0) {
over = (cv_timedwait_sig(&kp->kp_tx_cv,
&kp->kp_mutex, until) <= 0);
} else {
over = (cv_wait_sig(&kp->kp_tx_cv, &kp->kp_mutex) == 0);
}
}
return ((kp->kp_tx_mp == NULL) ? USB_SUCCESS : USB_FAILURE);
}
int
keyspan_dev_is_online(keyspan_state_t *ksp)
{
int rval;
mutex_enter(&ksp->ks_mutex);
rval = (ksp->ks_dev_state == USB_DEV_ONLINE);
mutex_exit(&ksp->ks_mutex);
return (rval);
}
void
keyspan_put_tail(mblk_t **mpp, mblk_t *bp)
{
if (*mpp) {
linkb(*mpp, bp);
} else {
*mpp = bp;
}
}
void
keyspan_put_head(mblk_t **mpp, mblk_t *bp, keyspan_port_t *kp)
{
switch (kp->kp_ksp->ks_dev_spec.id_product) {
case KEYSPAN_USA19HS_PID:
if (*mpp) {
linkb(bp, *mpp);
}
*mpp = bp;
break;
case KEYSPAN_USA49WLC_PID:
case KEYSPAN_USA49WG_PID:
if (*mpp) {
linkb(bp, *mpp);
}
bp->b_rptr = bp->b_datap->db_base + 1;
*mpp = bp;
break;
default:
USB_DPRINTF_L2(DPRINT_OUT_DATA, kp->kp_lh, "keyspan_put_head:"
"the device's product id can't be recognized");
return;
}
}
static void
keyspan_default_port_params(keyspan_port_t *kp)
{
keyspan_state_t *ksp = kp->kp_ksp;
ASSERT(mutex_owned(&kp->kp_mutex));
switch (ksp->ks_dev_spec.id_product) {
case KEYSPAN_USA19HS_PID:
keyspan_default_port_params_usa19hs(kp);
break;
case KEYSPAN_USA49WLC_PID:
case KEYSPAN_USA49WG_PID:
keyspan_default_port_params_usa49(kp);
break;
default:
USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
"keyspan_default_port_params:"
"the device's product id can't be recognized");
}
USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
"keyspan_default_port_params: setted.");
}
static void
keyspan_build_cmd_msg(keyspan_port_t *kp, ds_port_params_t *tp)
{
keyspan_state_t *ksp = kp->kp_ksp;
switch (ksp->ks_dev_spec.id_product) {
case KEYSPAN_USA19HS_PID:
keyspan_build_cmd_msg_usa19hs(kp, tp);
break;
case KEYSPAN_USA49WLC_PID:
case KEYSPAN_USA49WG_PID:
keyspan_build_cmd_msg_usa49(kp, tp);
break;
default:
USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
"keyspan_build_cmd_msg:"
"the device's product id can't be recognized");
}
}
static void
keyspan_save_port_params(keyspan_port_t *kp)
{
keyspan_state_t *ksp = kp->kp_ksp;
ASSERT(mutex_owned(&kp->kp_mutex));
switch (ksp->ks_dev_spec.id_product) {
case KEYSPAN_USA19HS_PID:
keyspan_save_port_params_usa19hs(kp);
break;
case KEYSPAN_USA49WLC_PID:
case KEYSPAN_USA49WG_PID:
keyspan_save_port_params_usa49(kp);
break;
default:
USB_DPRINTF_L2(DPRINT_ATTACH, ksp->ks_lh,
"keyspan_save_port_params:"
"the device's product id can't be recognized");
}
USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
"keyspan_save_port_params: baud = %x, lcr = %x,"
"status_flag = %x", kp->kp_baud, kp->kp_lcr, kp->kp_status_flag);
}
static void
keyspan_save_port_params_usa19hs(keyspan_port_t *kp)
{
keyspan_usa19hs_port_ctrl_msg_t *ctrl_msg = &(kp->kp_ctrl_msg.usa19hs);
ASSERT(mutex_owned(&kp->kp_mutex));
if (ctrl_msg->setClocking) {
kp->kp_baud = ctrl_msg->baudHi;
kp->kp_baud = (kp->kp_baud << 8);
kp->kp_baud |= ctrl_msg->baudLo;
}
if (ctrl_msg->setLcr) {
kp->kp_lcr = ctrl_msg->lcr;
}
if (ctrl_msg->setRts) {
if (ctrl_msg->rts) {
kp->kp_status_flag |= KEYSPAN_PORT_RTS;
} else {
kp->kp_status_flag &= ~KEYSPAN_PORT_RTS;
}
}
if (ctrl_msg->setDtr) {
if (ctrl_msg->dtr) {
kp->kp_status_flag |= KEYSPAN_PORT_DTR;
} else {
kp->kp_status_flag &= ~KEYSPAN_PORT_DTR;
}
}
if (ctrl_msg->portEnabled) {
kp->kp_status_flag |= KEYSPAN_PORT_ENABLE;
} else {
kp->kp_status_flag &= ~KEYSPAN_PORT_ENABLE;
}
USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
"keyspan_save_port_params: baud = %x, lcr = %x,"
"status_flag = %x", kp->kp_baud, kp->kp_lcr, kp->kp_status_flag);
}
static void
keyspan_default_port_params_usa19hs(keyspan_port_t *kp)
{
keyspan_usa19hs_port_ctrl_msg_t *ctrl_msg = &(kp->kp_ctrl_msg.usa19hs);
ASSERT(mutex_owned(&kp->kp_mutex));
keyspan_build_cmd_msg(kp, NULL);
ctrl_msg->setRts = 0x01;
ctrl_msg->rts = 0x1;
ctrl_msg->setDtr = 0x01;
ctrl_msg->dtr = 0x1;
ctrl_msg->setClocking = 1;
ctrl_msg->setRxMode = 1;
ctrl_msg->setTxMode = 1;
ctrl_msg->baudLo = keyspan_speedtab_usa19hs[13] & 0xff;
ctrl_msg->baudHi = (keyspan_speedtab_usa19hs[13] >> 8) & 0xff;
ctrl_msg->rxMode = RXMODE_BYHAND;
ctrl_msg->txMode = TXMODE_BYHAND;
ctrl_msg->lcr = 0x3;
ctrl_msg->setLcr = 0x1;
ctrl_msg->xonChar = CSTART;
ctrl_msg->xoffChar = CSTOP;
ctrl_msg->setTxFlowControl = 1;
ctrl_msg->txFlowControl = TXFLOW_CTS;
ctrl_msg->setRxFlowControl = 1;
ctrl_msg->rxFlowControl = RXFLOW_RTS;
ctrl_msg->rxFlush = 0;
}
static void
keyspan_build_cmd_msg_usa19hs(keyspan_port_t *kp, ds_port_params_t *tp)
{
int cnt, i;
uint_t ui;
ds_port_param_entry_t *pe;
keyspan_usa19hs_port_ctrl_msg_t *ctrl_msg = &(kp->kp_ctrl_msg.usa19hs);
USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh,
"keyspan_build_cmd_msg_usa19hs: tp = %p", (void *)tp);
ASSERT(mutex_owned(&kp->kp_mutex));
ASSERT(kp->kp_state == KEYSPAN_PORT_OPEN ||
kp->kp_state == KEYSPAN_PORT_OPENING);
bzero(ctrl_msg, sizeof (keyspan_usa19hs_port_ctrl_msg_t));
ctrl_msg->rxForwardingLength = 16;
ctrl_msg->rxForwardingTimeout = 16;
ctrl_msg->portEnabled = 1;
ctrl_msg->returnStatus = 1;
if (tp == NULL) {
return;
}
cnt = tp->tp_cnt;
pe = tp->tp_entries;
for (i = 0; i < cnt; i++, pe++) {
switch (pe->param) {
case DS_PARAM_BAUD:
ui = pe->val.ui;
if ((ui >= NELEM(keyspan_speedtab_usa19hs)) ||
((ui > 0) && (keyspan_speedtab_usa19hs[ui] == 0))) {
USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
"keyspan_build_cmd_msg_usa19hs:"
" bad baud %d", ui);
break;
}
if (kp->kp_baud == keyspan_speedtab_usa19hs[ui]) {
USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
"keyspan_build_cmd_msg_usa19hs:"
" same as old baud setting, baud = %d",
keyspan_speed2baud[ui]);
break;
}
ctrl_msg->setClocking = 1;
ctrl_msg->setRxMode = 1;
ctrl_msg->setTxMode = 1;
ctrl_msg->baudLo = keyspan_speedtab_usa19hs[ui] & 0xff;
ctrl_msg->baudHi = (keyspan_speedtab_usa19hs[ui] >> 8)
& 0xff;
ctrl_msg->rxMode = RXMODE_BYHAND;
ctrl_msg->txMode = TXMODE_BYHAND;
USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
"keyspan_build_cmd_msg_usa19hs: baud=%d",
keyspan_speed2baud[ui]);
break;
case DS_PARAM_PARITY:
if (pe->val.ui & PARENB) {
if (pe->val.ui & PARODD) {
ctrl_msg->lcr |= USA_PARITY_ODD;
} else {
ctrl_msg->lcr |= USA_PARITY_EVEN;
}
}
USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
"keyspan_build_cmd_msg_usa19hs: parity=%x,lcr = %x",
pe->val.ui, ctrl_msg->lcr);
break;
case DS_PARAM_STOPB:
if (pe->val.ui & CSTOPB) {
ctrl_msg->lcr |= STOPBITS_678_2;
} else {
USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
"keyspan_build_cmd_msg_usa19hs:"
" STOPBITS_5678_1");
}
USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
"keyspan_build_cmd_msg_usa19hs: stopb=%x, lcr = %x",
pe->val.ui, ctrl_msg->lcr);
break;
case DS_PARAM_CHARSZ:
switch (pe->val.ui) {
case CS5:
USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
"keyspan_build_cmd_msg_usa19hs:"
" USA_DATABITS_5");
break;
case CS6:
ctrl_msg->lcr |= USA_DATABITS_6;
break;
case CS7:
ctrl_msg->lcr |= USA_DATABITS_7;
break;
case CS8:
default:
ctrl_msg->lcr |= USA_DATABITS_8;
break;
}
USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
"keyspan_build_cmd_msg_usa19hs: cs=%x, lcr = %x",
pe->val.ui, ctrl_msg->lcr);
break;
case DS_PARAM_XON_XOFF:
ctrl_msg->xonChar = pe->val.uc[0];
ctrl_msg->xoffChar = pe->val.uc[1];
USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
"keyspan_build_cmd_msg_usa19hs: xonChar=%x, "
"xoffChar = %x", ctrl_msg->xonChar,
ctrl_msg->xoffChar);
break;
case DS_PARAM_FLOW_CTL:
if (pe->val.ui & CTSXON) {
ctrl_msg->txFlowControl = TXFLOW_CTS;
ctrl_msg->setTxFlowControl = 1;
} else {
ctrl_msg->txFlowControl = 0;
ctrl_msg->setTxFlowControl = 1;
}
if (pe->val.ui & RTSXOFF) {
ctrl_msg->rxFlowControl = RXFLOW_RTS;
ctrl_msg->setRxFlowControl = 1;
} else {
ctrl_msg->rxFlowControl = 0;
ctrl_msg->setRxFlowControl = 1;
}
USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
"keyspan_build_cmd_msg_usa19hs: txFlowControl = %x,"
"rxFlowControl = %x", ctrl_msg->txFlowControl,
ctrl_msg->rxFlowControl);
break;
default:
USB_DPRINTF_L2(DPRINT_CTLOP, kp->kp_lh,
"keyspan_build_cmd_msg_usa19hs: bad param %d",
pe->param);
break;
}
}
ctrl_msg->setLcr = (ctrl_msg->lcr == kp->kp_lcr) ? 0 : 1;
}
static void
keyspan_build_cmd_msg_usa49(keyspan_port_t *kp, ds_port_params_t *tp)
{
int cnt, i;
uint_t ui;
ds_port_param_entry_t *pe;
keyspan_usa49_port_ctrl_msg_t *ctrl_msg = &(kp->kp_ctrl_msg.usa49);
USB_DPRINTF_L4(DPRINT_CTLOP, kp->kp_lh,
"keyspan_build_cmd_msg_usa49: tp = %p", (void *)tp);
ASSERT(mutex_owned(&kp->kp_mutex));
ASSERT(kp->kp_state == KEYSPAN_PORT_OPEN ||
kp->kp_state == KEYSPAN_PORT_OPENING);
bzero(ctrl_msg, sizeof (keyspan_usa49_port_ctrl_msg_t));
ctrl_msg->portNumber = kp->kp_port_num;
ctrl_msg->forwardingLength = 16;
ctrl_msg->enablePort = 1;
ctrl_msg->returnStatus = 1;
if (tp == NULL) {
return;
}
cnt = tp->tp_cnt;
pe = tp->tp_entries;
for (i = 0; i < cnt; i++, pe++) {
switch (pe->param) {
case DS_PARAM_BAUD:
ui = pe->val.ui;
if ((ui >= NELEM(keyspan_speedtab_usa49)) ||
((ui > 0) && (keyspan_speedtab_usa49[ui] == 0))) {
USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
"keyspan_build_cmd_msg_usa49:"
" bad baud %d", ui);
break;
}
if (kp->kp_baud == keyspan_speedtab_usa49[ui]) {
USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
"keyspan_build_cmd_msg_usa49: "
"same as old baud setting, baud = %d",
keyspan_speed2baud[ui]);
break;
}
ctrl_msg->setClocking = 0xff;
ctrl_msg->baudLo = keyspan_speedtab_usa49[ui] & 0xff;
ctrl_msg->baudHi = (keyspan_speedtab_usa49[ui] >> 8)
& 0xff;
ctrl_msg->prescaler = keyspan_prescaler_49wlc[ui];
USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
"keyspan_build_cmd_msg_usa49: baud=%d",
keyspan_speed2baud[ui]);
break;
case DS_PARAM_PARITY:
if (pe->val.ui & PARENB) {
if (pe->val.ui & PARODD) {
ctrl_msg->lcr |= USA_PARITY_ODD;
} else {
ctrl_msg->lcr |= USA_PARITY_EVEN;
}
}
USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
"keyspan_build_cmd_msg_usa49: parity=%x, lcr = %x",
pe->val.ui, ctrl_msg->lcr);
break;
case DS_PARAM_STOPB:
if (pe->val.ui & CSTOPB) {
ctrl_msg->lcr |= STOPBITS_678_2;
} else {
USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
"keyspan_build_cmd_msg_usa49: "
"STOPBITS_5678_1");
}
USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
"keyspan_build_cmd_msg_usa49: stopb=%x, lcr = %x",
pe->val.ui, ctrl_msg->lcr);
break;
case DS_PARAM_CHARSZ:
switch (pe->val.ui) {
case CS5:
USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
"keyspan_build_cmd_msg_usa49:"
" USA_DATABITS_5");
break;
case CS6:
ctrl_msg->lcr |= USA_DATABITS_6;
break;
case CS7:
ctrl_msg->lcr |= USA_DATABITS_7;
break;
case CS8:
default:
ctrl_msg->lcr |= USA_DATABITS_8;
break;
}
USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
"keyspan_build_cmd_msg_usa49: cs=%x, lcr = %x",
pe->val.ui, ctrl_msg->lcr);
break;
case DS_PARAM_XON_XOFF:
ctrl_msg->xonChar = pe->val.uc[0];
ctrl_msg->xoffChar = pe->val.uc[1];
USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
"keyspan_build_cmd_msg_usa49: xonChar=%x, "
"xoffChar = %x", ctrl_msg->xonChar,
ctrl_msg->xoffChar);
break;
case DS_PARAM_FLOW_CTL:
if (pe->val.ui & CTSXON) {
ctrl_msg->ctsFlowControl = 1;
ctrl_msg->setFlowControl = 1;
} else {
ctrl_msg->ctsFlowControl = 0;
ctrl_msg->setFlowControl = 1;
}
if (pe->val.ui & RTSXOFF) {
USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
"keyspan_build_cmd_msg_usa49: "
"pe->val.ui = %x, flow_ctl: RTSXOFF, "
"no hardware support", pe->val.ui);
}
USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
"keyspan_build_cmd_msg_usa49: ctsFlowControl = %x,"
"dsrFlowControl = %x", ctrl_msg->ctsFlowControl,
ctrl_msg->dsrFlowControl);
break;
default:
USB_DPRINTF_L2(DPRINT_CTLOP, kp->kp_lh,
"keyspan_build_cmd_msg_usa49: bad param %d",
pe->param);
break;
}
}
ctrl_msg->setLcr = (ctrl_msg->lcr == kp->kp_lcr) ? 0 : 1;
}
static void
keyspan_default_port_params_usa49(keyspan_port_t *kp)
{
keyspan_usa49_port_ctrl_msg_t *ctrl_msg = &(kp->kp_ctrl_msg.usa49);
ASSERT(mutex_owned(&kp->kp_mutex));
keyspan_build_cmd_msg(kp, NULL);
ctrl_msg->setRts = 1;
ctrl_msg->rts = 1;
ctrl_msg->setDtr = 1;
ctrl_msg->dtr = 1;
ctrl_msg->_txOn = 1;
ctrl_msg->_txOff = 0;
ctrl_msg->txFlush = 0;
ctrl_msg->txBreak = 0;
ctrl_msg->rxOn = 1;
ctrl_msg->rxOff = 0;
ctrl_msg->rxFlush = 0;
ctrl_msg->rxForward = 0;
ctrl_msg->returnStatus = 1;
ctrl_msg->resetDataToggle = 0;
ctrl_msg->enablePort = 1;
ctrl_msg->disablePort = 0;
ctrl_msg->setClocking = 1;
ctrl_msg->baudLo = keyspan_speedtab_usa49[13] & 0xff;
ctrl_msg->baudHi = (keyspan_speedtab_usa49[13] >> 8) & 0xff;
ctrl_msg->prescaler = keyspan_prescaler_49wlc[13];
ctrl_msg->lcr = 0x3;
ctrl_msg->setLcr = 1;
ctrl_msg->xonChar = CSTART;
ctrl_msg->xoffChar = CSTOP;
ctrl_msg->ctsFlowControl = 1;
ctrl_msg->setFlowControl = 1;
}
static void
keyspan_save_port_params_usa49(keyspan_port_t *kp)
{
keyspan_usa49_port_ctrl_msg_t *ctrl_msg = &(kp->kp_ctrl_msg.usa49);
ASSERT(mutex_owned(&kp->kp_mutex));
if (ctrl_msg->setClocking) {
kp->kp_baud = ctrl_msg->baudHi;
kp->kp_baud = (kp->kp_baud << 8);
kp->kp_baud |= ctrl_msg->baudLo;
}
if (ctrl_msg->setLcr) {
kp->kp_lcr = ctrl_msg->lcr;
}
if (ctrl_msg->setRts) {
if (ctrl_msg->rts) {
kp->kp_status_flag |= KEYSPAN_PORT_RTS;
} else {
kp->kp_status_flag &= ~KEYSPAN_PORT_RTS;
}
}
if (ctrl_msg->setDtr) {
if (ctrl_msg->dtr) {
kp->kp_status_flag |= KEYSPAN_PORT_DTR;
} else {
kp->kp_status_flag &= ~KEYSPAN_PORT_DTR;
}
}
if (ctrl_msg->enablePort) {
kp->kp_status_flag |= KEYSPAN_PORT_ENABLE;
} else {
kp->kp_status_flag &= ~KEYSPAN_PORT_ENABLE;
}
if (ctrl_msg->txBreak) {
kp->kp_status_flag |= KEYSPAN_PORT_TXBREAK;
} else {
kp->kp_status_flag &= ~KEYSPAN_PORT_TXBREAK;
}
USB_DPRINTF_L3(DPRINT_CTLOP, kp->kp_lh,
"keyspan_save_port_params: baud = %x, lcr = %x,"
"status_flag = %x", kp->kp_baud, kp->kp_lcr, kp->kp_status_flag);
}