#include <sys/usb/usba/usbai_version.h>
#include <sys/usb/usba.h>
#include <sys/usb/clients/hid/hid.h>
#include <sys/usb/clients/hidparser/hidparser.h>
#include <sys/stropts.h>
#include <sys/strsun.h>
#include <sys/systm.h>
#include <sys/vuid_event.h>
#include <sys/vuid_wheel.h>
#include <sys/termios.h>
#include <sys/termio.h>
#include <sys/strtty.h>
#include <sys/msreg.h>
#include <sys/msio.h>
#include <sys/usb/clients/usbms/usbms.h>
uint_t usbms_errmask = (uint_t)PRINT_MASK_ALL;
uint_t usbms_errlevel = USB_LOG_L2;
static usb_log_handle_t usbms_log_handle;
static struct streamtab usbms_streamtab;
static struct fmodsw fsw = {
"usbms",
&usbms_streamtab,
D_MP | D_MTPERMOD
};
static struct modlstrmod modlstrmod = {
&mod_strmodops,
"USB mouse streams",
&fsw
};
static struct modlinkage modlinkage = {
MODREV_1,
(void *)&modlstrmod,
NULL
};
int
_init(void)
{
int rval = mod_install(&modlinkage);
if (rval == 0) {
usbms_log_handle = usb_alloc_log_hdl(NULL, "usbms",
&usbms_errlevel, &usbms_errmask, NULL, 0);
}
return (rval);
}
int
_fini(void)
{
int rval = mod_remove(&modlinkage);
if (rval == 0) {
usb_free_log_hdl(usbms_log_handle);
}
return (rval);
}
int
_info(struct modinfo *modinfop)
{
return (mod_info(&modlinkage, modinfop));
}
static void usbms_reioctl(void *);
static void usbms_ioctl(queue_t *, mblk_t *);
static int usbms_open(queue_t *, dev_t *, int, int, cred_t *);
static int usbms_close(queue_t *, int, cred_t *);
static int usbms_wput(queue_t *, mblk_t *);
static int usbms_rput(queue_t *, mblk_t *);
static void usbms_mctl_receive(queue_t *, mblk_t *);
static int usbms_rserv(queue_t *);
static void usbms_miocdata(queue_t *, mblk_t *);
static void usbms_resched(void *);
static int usbms_getparms(Ms_parms *, usbms_state_t *);
static int usbms_setparms(Ms_parms *, usbms_state_t *);
static int usbms_get_screen_parms(queue_t *q, mblk_t *);
static void usbms_flush(usbms_state_t *);
static void usbms_incr(void *);
static void usbms_input(usbms_state_t *, mblk_t *);
static void usbms_rserv_vuid_button(queue_t *, struct usbmouseinfo *,
mblk_t **);
static void usbms_rserv_vuid_event_y(queue_t *, struct usbmouseinfo *,
mblk_t **);
static void usbms_rserv_vuid_event_x(queue_t *, struct usbmouseinfo *,
mblk_t **);
static void usbms_rserv_vuid_event_wheel(queue_t *, struct usbmouseinfo *,
mblk_t **, ushort_t);
static int usbms_check_for_wheels(usbms_state_t *);
static int usbms_make_copyreq(mblk_t *, uint_t, uint_t, uint_t, uint_t, uint_t);
static int usbms_service_wheel_info(queue_t *, mblk_t *);
static int usbms_service_wheel_state(queue_t *, mblk_t *, uint_t);
static void usbms_ack_ioctl(mblk_t *);
static int usbms_read_input_data_format(usbms_state_t *);
static mblk_t *usbms_setup_abs_mouse_event(void);
static int usbms_get_coordinate(uint_t, uint_t, mblk_t *);
static struct module_info usbms_mod_info = {
0x0ffff,
"usbms",
0,
INFPSZ,
512,
128
};
static struct qinit rinit = {
usbms_rput,
usbms_rserv,
usbms_open,
usbms_close,
NULL,
&usbms_mod_info,
NULL
};
static struct qinit winit = {
usbms_wput,
NULL,
NULL,
NULL,
NULL,
&usbms_mod_info,
NULL
};
static struct streamtab usbms_streamtab = {
&rinit,
&winit,
NULL,
NULL
};
static int overrun_msg;
static int overrun_cnt;
extern int hz;
static uint16_t usbms_buf_bytes = USBMS_BUF_BYTES;
static int
usbms_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
{
struct usbmousebuf *mousebufp;
struct ms_softc *msd_soft;
usbms_state_t *usbmsp;
struct iocblk mctlmsg;
mblk_t *mctl_ptr;
if (sflag != MODOPEN)
return (EINVAL);
if (q->q_ptr) {
return (0);
}
usbmsp = kmem_zalloc(sizeof (usbms_state_t), KM_SLEEP);
q->q_ptr = usbmsp;
WR(q)->q_ptr = usbmsp;
usbmsp->usbms_rq_ptr = q;
usbmsp->usbms_wq_ptr = WR(q);
qprocson(q);
usbmsp->usbms_state = USBMS_WAIT_BUTN;
usbmsp->usbms_iocpending = NULL;
usbmsp->usbms_jitter_thresh = USBMS_JITTER_THRESH;
usbmsp->usbms_speedlimit = USBMS_SPEEDLIMIT;
usbmsp->usbms_speedlaw = USBMS_SPEEDLAW;
usbmsp->usbms_speed_count = USBMS_SPEED_COUNT;
msd_soft = &usbmsp->usbms_softc;
msd_soft->ms_readformat = MS_VUID_FORMAT;
msd_soft->ms_bufbytes = usbms_buf_bytes;
mousebufp = kmem_zalloc(msd_soft->ms_bufbytes, KM_SLEEP);
mousebufp->mb_size = (uint16_t)((msd_soft->ms_bufbytes -
sizeof (struct usbmousebuf)) / sizeof (struct usbmouseinfo));
mousebufp->mb_info = (struct usbmouseinfo *)((char *)mousebufp +
sizeof (struct usbmousebuf));
usbmsp->usbms_buf = mousebufp;
msd_soft->ms_vuidaddr = VKEY_FIRST;
usbmsp->usbms_jittertimeout = JITTER_TIMEOUT;
mctlmsg.ioc_cmd = HID_GET_PARSER_HANDLE;
mctlmsg.ioc_count = 0;
mctl_ptr = usba_mk_mctl(mctlmsg, NULL, 0);
if (mctl_ptr == NULL) {
qprocsoff(q);
kmem_free(usbmsp->usbms_buf, msd_soft->ms_bufbytes);
kmem_free(usbmsp, sizeof (usbms_state_t));
return (ENOMEM);
}
usbmsp->usbms_flags |= USBMS_QWAIT;
putnext(usbmsp->usbms_wq_ptr, mctl_ptr);
while (usbmsp->usbms_flags & USBMS_QWAIT) {
if (qwait_sig(q) == 0) {
qprocsoff(q);
kmem_free(usbmsp->usbms_buf, msd_soft->ms_bufbytes);
kmem_free(usbmsp, sizeof (usbms_state_t));
return (EINTR);
}
}
if (usbmsp->usbms_report_descr_handle != NULL) {
if (hidparser_get_usage_attribute(
usbmsp->usbms_report_descr_handle,
0,
HIDPARSER_ITEM_INPUT,
USBMS_USAGE_PAGE_BUTTON,
0,
HIDPARSER_ITEM_REPORT_COUNT,
(int32_t *)&usbmsp->usbms_num_buttons) ==
HIDPARSER_SUCCESS) {
if (usbmsp->usbms_num_buttons > USB_MS_MAX_BUTTON_NO)
usbmsp->usbms_num_buttons =
USB_MS_MAX_BUTTON_NO;
USB_DPRINTF_L2(PRINT_MASK_ALL,
usbms_log_handle, "Num of buttons is : %d",
usbmsp->usbms_num_buttons);
} else {
USB_DPRINTF_L3(PRINT_MASK_OPEN,
usbms_log_handle,
"hidparser_get_usage_attribute failed : "
"Set to default number of buttons(3).");
usbmsp->usbms_num_buttons = USB_MS_DEFAULT_BUTTON_NO;
}
} else {
USB_DPRINTF_L1(PRINT_MASK_ALL,
usbms_log_handle, "Invalid HID "
"Descriptor Tree. Set to default value(3 buttons).");
usbmsp->usbms_num_buttons = USB_MS_DEFAULT_BUTTON_NO;
}
if (usbms_check_for_wheels(usbmsp) == USB_FAILURE) {
USB_DPRINTF_L2(PRINT_MASK_ALL, usbms_log_handle,
"No wheels detected");
} else {
USB_DPRINTF_L2(PRINT_MASK_ALL, usbms_log_handle,
"Wheel detected");
}
usbms_flush(usbmsp);
if (usbms_read_input_data_format(usbmsp) != USB_SUCCESS) {
qprocsoff(q);
kmem_free(usbmsp->usbms_buf, msd_soft->ms_bufbytes);
kmem_free(usbmsp, sizeof (usbms_state_t));
return (EINVAL);
}
usbmsp->usbms_flags |= USBMS_OPEN;
USB_DPRINTF_L3(PRINT_MASK_OPEN, usbms_log_handle,
"usbms_open exiting");
return (0);
}
static int
usbms_close(queue_t *q, int flag, cred_t *credp)
{
usbms_state_t *usbmsp = q->q_ptr;
struct ms_softc *ms = &usbmsp->usbms_softc;
USB_DPRINTF_L3(PRINT_MASK_CLOSE, usbms_log_handle,
"usbms_close entering");
qprocsoff(q);
if (usbmsp->usbms_jitter) {
(void) quntimeout(q,
(timeout_id_t)(long)usbmsp->usbms_timeout_id);
usbmsp->usbms_jitter = 0;
}
if (usbmsp->usbms_reioctl_id) {
qunbufcall(q, (bufcall_id_t)(long)usbmsp->usbms_reioctl_id);
usbmsp->usbms_reioctl_id = 0;
}
if (usbmsp->usbms_resched_id) {
qunbufcall(q, (bufcall_id_t)usbmsp->usbms_resched_id);
usbmsp->usbms_resched_id = 0;
}
if (usbmsp->usbms_iocpending != NULL) {
freemsg(usbmsp->usbms_iocpending);
usbmsp->usbms_iocpending = NULL;
}
if (usbmsp->usbms_buf != NULL) {
kmem_free(usbmsp->usbms_buf, ms->ms_bufbytes);
}
kmem_free(usbmsp, sizeof (usbms_state_t));
q->q_ptr = NULL;
WR(q)->q_ptr = NULL;
USB_DPRINTF_L3(PRINT_MASK_CLOSE, usbms_log_handle,
"usbms_close exiting");
return (0);
}
static int
usbms_rserv(queue_t *q)
{
usbms_state_t *usbmsp = q->q_ptr;
struct ms_softc *ms;
struct usbmousebuf *b;
struct usbmouseinfo *mi;
mblk_t *bp;
ushort_t i, loop;
uchar_t nbutt = (uchar_t)usbmsp->usbms_num_buttons;
ms = &usbmsp->usbms_softc;
b = usbmsp->usbms_buf;
USB_DPRINTF_L3(PRINT_MASK_SERV, usbms_log_handle,
"usbms_rserv entering");
while (canputnext(q) && ms->ms_oldoff != b->mb_off) {
mi = &b->mb_info[ms->ms_oldoff];
switch (ms->ms_readformat) {
case MS_3BYTE_FORMAT: {
char *cp;
if ((usbmsp->usbms_idf).xlen != 1) {
USB_DPRINTF_L3(PRINT_MASK_SERV,
usbms_log_handle,
"Can't set to 3 byte format. Length != 1");
return (0);
}
if ((bp = allocb(3, BPRI_HI)) != NULL) {
cp = (char *)bp->b_wptr;
*cp++ = 0x80 | (mi->mi_buttons & 0xFF);
ms->ms_prevbuttons = mi->mi_buttons;
*cp++ = (mi->mi_x & 0xFF);
*cp++ = ((-mi->mi_y) & 0xFF);
bp->b_wptr = (uchar_t *)cp;
putnext(q, bp);
} else {
if (usbmsp->usbms_resched_id) {
qunbufcall(q,
(bufcall_id_t)usbmsp->
usbms_resched_id);
}
usbmsp->usbms_resched_id = qbufcall(q,
(size_t)3,
(uint_t)BPRI_HI,
(void (*)())usbms_resched,
(void *) usbmsp);
if (usbmsp->usbms_resched_id == 0)
return (0);
}
ms->ms_oldoff++;
if (ms->ms_oldoff >= b->mb_size) {
ms->ms_oldoff = 0;
}
break;
}
case MS_VUID_FORMAT:
default: {
do {
bp = NULL;
switch (ms->ms_eventstate) {
case EVENT_WHEEL:
loop = (usbmsp->usbms_num_wheels ?
1 : 0);
if (usbmsp->usbms_num_wheels) {
for (i = 0; i < loop; i++) {
usbms_rserv_vuid_event_wheel
(q, mi, &bp, i);
}
}
break;
case EVENT_BUT8:
case EVENT_BUT7:
case EVENT_BUT6:
case EVENT_BUT5:
case EVENT_BUT4:
case EVENT_BUT3:
case EVENT_BUT2:
case EVENT_BUT1:
usbms_rserv_vuid_button(q, mi, &bp);
break;
case EVENT_Y:
usbms_rserv_vuid_event_y(q, mi, &bp);
break;
case EVENT_X:
usbms_rserv_vuid_event_x(q, mi, &bp);
break;
default:
ms->ms_eventstate = EVENT_WHEEL;
break;
}
if (bp != NULL) {
bp->b_wptr += sizeof (Firm_event);
putnext(q, bp);
}
if (ms->ms_eventstate == EVENT_X) {
ms->ms_eventstate = EVENT_WHEEL;
} else if (ms->ms_eventstate == EVENT_WHEEL) {
ms->ms_oldoff++;
if (ms->ms_oldoff >= b->mb_size) {
ms->ms_oldoff = 0;
}
ms->ms_eventstate = EVENT_BUT(nbutt);
} else
ms->ms_eventstate--;
} while (ms->ms_eventstate != EVENT_BUT(nbutt));
}
}
}
USB_DPRINTF_L3(PRINT_MASK_SERV, usbms_log_handle,
"usbms_rserv exiting");
return (0);
}
static void
usbms_rserv_vuid_event_wheel(queue_t *q, struct usbmouseinfo *mi,
mblk_t **bpaddr, ushort_t id)
{
Firm_event *fep;
mblk_t *tmp;
struct ms_softc *ms;
usbms_state_t *usbmsp = (usbms_state_t *)q->q_ptr;
if (!(usbmsp->usbms_wheel_state_bf & (1 << id))) {
return;
}
ms = &usbmsp->usbms_softc;
if (mi->mi_z) {
if ((tmp = allocb(sizeof (Firm_event), BPRI_HI)) != NULL) {
fep = (Firm_event *)tmp->b_wptr;
fep->id = vuid_id_addr(vuid_first(VUID_WHEEL)) |
vuid_id_offset(id);
fep->pair_type = FE_PAIR_NONE;
fep->pair = 0;
fep->value = mi->mi_z;
fep->time = mi->mi_time;
*bpaddr = tmp;
} else {
if (usbmsp->usbms_resched_id) {
qunbufcall(q,
(bufcall_id_t)usbmsp->usbms_resched_id);
}
usbmsp->usbms_resched_id =
qbufcall(q, sizeof (Firm_event), BPRI_HI,
(void (*)())usbms_resched, (void *) usbmsp);
if (usbmsp->usbms_resched_id == 0) {
return;
}
ms->ms_eventstate = EVENT_WHEEL;
}
}
}
static void
usbms_rserv_vuid_button(queue_t *q, struct usbmouseinfo *mi, mblk_t **bpaddr)
{
usbms_state_t *usbmsp = q->q_ptr;
struct ms_softc *ms;
int button_number;
uchar_t hwbit = 0x0;
Firm_event *fep;
mblk_t *bp;
uchar_t nbutt;
ms = &usbmsp->usbms_softc;
nbutt = (uchar_t)usbmsp->usbms_num_buttons;
button_number = nbutt - (EVENT_BUT(nbutt) - ms->ms_eventstate) - 1;
switch (button_number) {
case 2:
hwbit = 0x01;
break;
case 1:
if (nbutt == 2) {
hwbit = 0x01;
button_number = 2;
} else {
hwbit = 0x02;
}
break;
case 0:
hwbit = 0x04;
break;
default :
hwbit = USBMS_BUT(nbutt) >> (EVENT_BUT(nbutt) -
ms->ms_eventstate);
break;
}
if ((ms->ms_prevbuttons & hwbit) !=
(mi->mi_buttons & hwbit)) {
if ((bp = allocb(sizeof (Firm_event),
BPRI_HI)) != NULL) {
*bpaddr = bp;
fep = (Firm_event *)bp->b_wptr;
fep->id = vuid_id_addr(
ms->ms_vuidaddr) |
vuid_id_offset(BUT(1)
+ button_number);
fep->pair_type = FE_PAIR_NONE;
fep->pair = 0;
if (mi->mi_buttons & hwbit) {
fep->value = 0;
ms->ms_prevbuttons |=
hwbit;
} else {
fep->value = 1;
ms->ms_prevbuttons &=
~hwbit;
}
fep->time = mi->mi_time;
} else {
if (usbmsp->usbms_resched_id) {
qunbufcall(q,
(bufcall_id_t)usbmsp->usbms_resched_id);
}
usbmsp->usbms_resched_id =
qbufcall(q,
sizeof (Firm_event),
BPRI_HI,
(void (*)())usbms_resched,
(void *) usbmsp);
if (usbmsp->usbms_resched_id == 0)
return;
ms->ms_eventstate = EVENT_WHEEL;
}
}
}
static void
usbms_rserv_vuid_event_y(queue_t *q, struct usbmouseinfo *mi, mblk_t **bpaddr)
{
usbms_state_t *usbmsp = q->q_ptr;
struct ms_softc *ms;
Firm_event *fep;
mblk_t *bp;
ms = &usbmsp->usbms_softc;
if (!(((usbmsp->usbms_idf).yattr) & HID_MAIN_ITEM_RELATIVE)) {
if ((mi->mi_x == 0) &&
(mi->mi_y == usbmsp->usbms_logical_Ymax)) {
return;
}
}
if (mi->mi_y != 0) {
if ((bp = allocb(sizeof (Firm_event),
BPRI_HI)) != NULL) {
*bpaddr = bp;
fep = (Firm_event *)bp->b_wptr;
if (((usbmsp->usbms_idf).yattr) &
HID_MAIN_ITEM_RELATIVE) {
fep->id = vuid_id_addr(
ms->ms_vuidaddr) |
vuid_id_offset(
LOC_Y_DELTA);
fep->pair_type =
FE_PAIR_ABSOLUTE;
fep->pair =
(uchar_t)LOC_Y_ABSOLUTE;
fep->value = -(mi->mi_y);
} else {
fep->id = vuid_id_addr(
ms->ms_vuidaddr) |
vuid_id_offset(
LOC_Y_ABSOLUTE);
fep->pair_type = FE_PAIR_DELTA;
fep->pair = (uchar_t)LOC_Y_DELTA;
fep->value = (mi->mi_y *
((usbmsp->usbms_resolution).height) /
usbmsp->usbms_logical_Ymax);
if ((mi->mi_y *
((usbmsp->usbms_resolution).height) %
usbmsp->usbms_logical_Ymax) >=
(usbmsp->usbms_logical_Ymax / 2)) {
fep->value ++;
}
}
fep->time = mi->mi_time;
} else {
if (usbmsp->usbms_resched_id) {
qunbufcall(q,
(bufcall_id_t)usbmsp->usbms_resched_id);
}
usbmsp->usbms_resched_id =
qbufcall(q,
sizeof (Firm_event),
BPRI_HI,
(void (*)())usbms_resched,
(void *)usbmsp);
if (usbmsp->usbms_resched_id == 0) {
return;
}
ms->ms_eventstate = EVENT_WHEEL;
}
}
}
static void
usbms_rserv_vuid_event_x(queue_t *q, struct usbmouseinfo *mi, mblk_t **bpaddr)
{
usbms_state_t *usbmsp = q->q_ptr;
struct ms_softc *ms;
Firm_event *fep;
mblk_t *bp;
ms = &usbmsp->usbms_softc;
if (!(((usbmsp->usbms_idf).xattr) & HID_MAIN_ITEM_RELATIVE)) {
if ((mi->mi_y == 0) &&
(mi->mi_x == usbmsp->usbms_logical_Xmax)) {
return;
}
}
if (mi->mi_x != 0) {
if ((bp = allocb(sizeof (Firm_event),
BPRI_HI)) != NULL) {
*bpaddr = bp;
fep = (Firm_event *)bp->b_wptr;
if (((usbmsp->usbms_idf).xattr) &
HID_MAIN_ITEM_RELATIVE) {
fep->id = vuid_id_addr(
ms->ms_vuidaddr) |
vuid_id_offset(LOC_X_DELTA);
fep->pair_type =
FE_PAIR_ABSOLUTE;
fep->pair =
(uchar_t)LOC_X_ABSOLUTE;
fep->value = mi->mi_x;
} else {
fep->id = vuid_id_addr(ms->ms_vuidaddr) |
vuid_id_offset(LOC_X_ABSOLUTE);
fep->pair_type = FE_PAIR_DELTA;
fep->pair = (uchar_t)LOC_X_DELTA;
fep->value = (mi->mi_x *
((usbmsp->usbms_resolution).width) /
usbmsp->usbms_logical_Xmax);
if ((mi->mi_x *
((usbmsp->usbms_resolution).width) %
usbmsp->usbms_logical_Xmax) >=
(usbmsp->usbms_logical_Xmax / 2)) {
fep->value ++;
}
}
fep->time = mi->mi_time;
} else {
if (usbmsp->usbms_resched_id)
qunbufcall(q,
(bufcall_id_t)usbmsp->usbms_resched_id);
usbmsp->usbms_resched_id =
qbufcall(q,
sizeof (Firm_event),
BPRI_HI,
(void (*)())usbms_resched,
(void *) usbmsp);
if (usbmsp->usbms_resched_id == 0)
return;
ms->ms_eventstate = EVENT_WHEEL;
}
}
}
static void
usbms_resched(void *usbmsp)
{
queue_t *q;
usbms_state_t *tmp_usbmsp = (usbms_state_t *)usbmsp;
tmp_usbmsp->usbms_resched_id = 0;
if ((q = tmp_usbmsp->usbms_rq_ptr) != 0)
qenable(q);
}
static int
usbms_wput(queue_t *q, mblk_t *mp)
{
USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
"usbms_wput entering");
switch (mp->b_datap->db_type) {
case M_FLUSH:
if (*mp->b_rptr & FLUSHW) {
flushq(q, FLUSHDATA);
}
if (*mp->b_rptr & FLUSHR) {
flushq(RD(q), FLUSHDATA);
}
putnext(q, mp);
break;
case M_IOCTL:
usbms_ioctl(q, mp);
break;
case M_IOCDATA:
usbms_miocdata(q, mp);
break;
default:
putnext(q, mp);
}
USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
"usbms_wput exiting");
return (0);
}
static void
usbms_ioctl(queue_t *q, mblk_t *mp)
{
usbms_state_t *usbmsp = (usbms_state_t *)q->q_ptr;
struct ms_softc *ms;
struct iocblk *iocp;
Vuid_addr_probe *addr_probe;
uint_t ioctlrespsize;
int err = 0;
mblk_t *datap;
ushort_t transparent = 0;
boolean_t report_abs = B_FALSE;
mblk_t *mb;
USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbms_log_handle,
"usbms_ioctl entering");
if (usbmsp == NULL) {
miocnak(q, mp, 0, EINVAL);
return;
}
ms = &usbmsp->usbms_softc;
iocp = (struct iocblk *)mp->b_rptr;
switch (iocp->ioc_cmd) {
case VUIDSFORMAT:
err = miocpullup(mp, sizeof (int));
if (err != 0)
break;
if (*(int *)mp->b_cont->b_rptr == ms->ms_readformat) {
break;
}
ms->ms_readformat = *(int *)mp->b_cont->b_rptr;
usbms_flush(usbmsp);
break;
case VUIDGFORMAT:
if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
ioctlrespsize = sizeof (int);
goto allocfailure;
}
*(int *)datap->b_wptr = ms->ms_readformat;
datap->b_wptr += sizeof (int);
freemsg(mp->b_cont);
mp->b_cont = datap;
iocp->ioc_count = sizeof (int);
break;
case VUIDGADDR:
case VUIDSADDR:
err = miocpullup(mp, sizeof (Vuid_addr_probe));
if (err != 0)
break;
addr_probe = (Vuid_addr_probe *)mp->b_cont->b_rptr;
if (addr_probe->base != VKEY_FIRST) {
err = ENODEV;
break;
}
if (iocp->ioc_cmd == VUIDSADDR)
ms->ms_vuidaddr = addr_probe->data.next;
else
addr_probe->data.current = ms->ms_vuidaddr;
break;
case MSIOGETPARMS:
if ((datap = allocb(sizeof (Ms_parms), BPRI_HI)) == NULL) {
ioctlrespsize = sizeof (Ms_parms);
goto allocfailure;
}
err = usbms_getparms((Ms_parms *)datap->b_wptr, usbmsp);
datap->b_wptr += sizeof (Ms_parms);
freemsg(mp->b_cont);
mp->b_cont = datap;
iocp->ioc_count = sizeof (Ms_parms);
break;
case MSIOSETPARMS:
err = miocpullup(mp, sizeof (Ms_parms));
if (err != 0)
break;
err = usbms_setparms((Ms_parms *)mp->b_cont->b_rptr, usbmsp);
break;
case MSIOBUTTONS:
if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
ioctlrespsize = sizeof (int);
goto allocfailure;
}
*(int *)datap->b_wptr = (int)usbmsp->usbms_num_buttons;
datap->b_wptr += sizeof (int);
freemsg(mp->b_cont);
mp->b_cont = datap;
iocp->ioc_count = sizeof (int);
break;
case VUIDGWHEELCOUNT:
if (iocp->ioc_count == TRANSPARENT) {
transparent = 1;
if (err = usbms_make_copyreq(mp, 0, 0, sizeof (int),
0, M_COPYOUT)) {
break;
}
}
if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
ioctlrespsize = sizeof (int);
goto allocfailure;
}
*((int *)datap->b_wptr) = (usbmsp->usbms_num_wheels ? 1 : 0);
datap->b_wptr += sizeof (int);
if (mp->b_cont) {
freemsg(mp->b_cont);
mp->b_cont = NULL;
}
mp->b_cont = datap;
if (transparent) {
qreply(q, mp);
return;
}
break;
case VUIDGWHEELINFO:
if (iocp->ioc_count == TRANSPARENT) {
if (err = usbms_make_copyreq(mp,
sizeof (usbms_iocstate_t),
USBMS_GETSTRUCT,
sizeof (wheel_info),
0,
M_COPYIN)) {
break;
}
freemsg(mp->b_cont);
mp->b_cont = (mblk_t *)NULL;
qreply(q, mp);
return;
}
if (mp->b_cont == NULL || iocp->ioc_count !=
sizeof (wheel_info)) {
err = EINVAL;
break;
}
datap = mp->b_cont;
err = usbms_service_wheel_info(q, datap);
break;
case VUIDGWHEELSTATE:
if (iocp->ioc_count == TRANSPARENT) {
if (err = usbms_make_copyreq(mp,
sizeof (usbms_iocstate_t),
USBMS_GETSTRUCT,
sizeof (wheel_state),
0,
M_COPYIN)) {
break;
}
freemsg(mp->b_cont);
mp->b_cont = (mblk_t *)NULL;
qreply(q, mp);
return;
}
if ((mp->b_cont == NULL) ||
(iocp->ioc_count != sizeof (wheel_state))) {
err = EINVAL;
break;
}
datap = mp->b_cont;
err = usbms_service_wheel_state(q, datap, VUIDGWHEELSTATE);
break;
case VUIDSWHEELSTATE:
if (iocp->ioc_count == TRANSPARENT) {
if (err = usbms_make_copyreq(mp,
sizeof (usbms_iocstate_t),
USBMS_GETSTRUCT,
sizeof (wheel_state),
0,
M_COPYIN)) {
break;
}
freemsg(mp->b_cont);
mp->b_cont = (mblk_t *)NULL;
qreply(q, mp);
return;
}
if (mp->b_cont == NULL) {
err = EINVAL;
break;
}
datap = mp->b_cont;
err = usbms_service_wheel_state(q, datap, VUIDSWHEELSTATE);
break;
case MSIOSRESOLUTION:
if (iocp->ioc_count == TRANSPARENT) {
if (err = usbms_make_copyreq(mp,
sizeof (usbms_iocstate_t),
USBMS_GETSTRUCT,
sizeof (Ms_screen_resolution),
0,
M_COPYIN)) {
break;
}
freemsg(mp->b_cont);
mp->b_cont = (mblk_t *)NULL;
qreply(q, mp);
return;
}
if (mp->b_cont == NULL) {
err = EINVAL;
break;
}
datap = mp->b_cont;
err = usbms_get_screen_parms(q, datap);
if ((!((usbmsp->usbms_idf).xattr & HID_MAIN_ITEM_RELATIVE)) &&
(usbmsp->usbms_rpt_abs == B_FALSE)) {
report_abs = B_TRUE;
}
break;
default:
putnext(q, mp);
return;
}
if (err != 0)
miocnak(q, mp, 0, err);
else {
iocp->ioc_rval = 0;
iocp->ioc_error = 0;
mp->b_datap->db_type = M_IOCACK;
qreply(q, mp);
if (report_abs == B_TRUE) {
if ((mb = usbms_setup_abs_mouse_event()) != NULL) {
usbmsp->usbms_rpt_abs = B_TRUE;
qreply(q, mb);
}
}
}
return;
allocfailure:
freemsg(usbmsp->usbms_iocpending);
usbmsp->usbms_iocpending = mp;
if (usbmsp->usbms_reioctl_id) {
qunbufcall(q, (bufcall_id_t)usbmsp->usbms_reioctl_id);
}
usbmsp->usbms_reioctl_id = qbufcall(q, ioctlrespsize, BPRI_HI,
(void (*)())usbms_reioctl,
(void *)usbmsp);
}
static void
usbms_miocdata(queue_t *q, mblk_t *mp)
{
struct copyresp *copyresp;
struct iocblk *iocbp;
mblk_t *datap;
mblk_t *ioctmp;
usbms_iocstate_t *usbmsioc;
int err = 0;
copyresp = (struct copyresp *)mp->b_rptr;
iocbp = (struct iocblk *)mp->b_rptr;
if (copyresp->cp_rval) {
err = EAGAIN;
goto err;
}
switch (copyresp->cp_cmd) {
case VUIDGWHEELCOUNT:
usbms_ack_ioctl(mp);
break;
case VUIDGWHEELINFO:
ioctmp = copyresp->cp_private;
usbmsioc = (usbms_iocstate_t *)ioctmp->b_rptr;
if (usbmsioc->ioc_state == USBMS_GETSTRUCT) {
if (mp->b_cont == NULL) {
err = EINVAL;
break;
}
datap = (mblk_t *)mp->b_cont;
if (err = usbms_service_wheel_info(q, datap)) {
goto err;
}
if (err = usbms_make_copyreq(mp, 0, USBMS_GETRESULT,
sizeof (wheel_info), 0, M_COPYOUT)) {
goto err;
}
} else if (usbmsioc->ioc_state == USBMS_GETRESULT) {
freemsg(ioctmp);
usbms_ack_ioctl(mp);
}
break;
case VUIDGWHEELSTATE:
ioctmp = (mblk_t *)copyresp->cp_private;
usbmsioc = (usbms_iocstate_t *)ioctmp->b_rptr;
if (usbmsioc->ioc_state == USBMS_GETSTRUCT) {
if (mp->b_cont == NULL) {
err = EINVAL;
break;
}
if (err = usbms_service_wheel_state(q, mp->b_cont,
VUIDGWHEELSTATE)) {
goto err;
}
if (err = usbms_make_copyreq(mp, 0, USBMS_GETRESULT,
sizeof (wheel_state), 0, M_COPYOUT)) {
goto err;
}
} else if (usbmsioc->ioc_state == USBMS_GETRESULT) {
freemsg(ioctmp);
usbms_ack_ioctl(mp);
}
break;
case VUIDSWHEELSTATE:
ioctmp = (mblk_t *)copyresp->cp_private;
usbmsioc = (usbms_iocstate_t *)ioctmp->b_rptr;
if (mp->b_cont == NULL) {
err = EINVAL;
break;
}
if (err = usbms_service_wheel_state(q, mp->b_cont,
VUIDSWHEELSTATE)) {
goto err;
}
freemsg(ioctmp);
usbms_ack_ioctl(mp);
break;
case MSIOSRESOLUTION:
ioctmp = (mblk_t *)copyresp->cp_private;
usbmsioc = (usbms_iocstate_t *)ioctmp->b_rptr;
if (mp->b_cont == NULL) {
err = EINVAL;
break;
}
if (err = usbms_get_screen_parms(q, mp->b_cont)) {
goto err;
}
freemsg(ioctmp);
usbms_ack_ioctl(mp);
break;
default:
err = EINVAL;
break;
}
err:
if (err) {
mp->b_datap->db_type = M_IOCNAK;
if (mp->b_cont) {
freemsg(mp->b_cont);
mp->b_cont = (mblk_t *)NULL;
}
if (copyresp->cp_private) {
freemsg((mblk_t *)copyresp->cp_private);
copyresp->cp_private = (mblk_t *)NULL;
}
iocbp->ioc_count = 0;
iocbp->ioc_error = err;
}
qreply(q, mp);
}
static void
usbms_reioctl(void * usbms_addr)
{
usbms_state_t *usbmsp = (usbms_state_t *)usbms_addr;
queue_t *q;
mblk_t *mp;
q = usbmsp->usbms_wq_ptr;
if ((mp = usbmsp->usbms_iocpending) != NULL) {
usbmsp->usbms_iocpending = NULL;
usbms_ioctl(q, mp);
}
}
static int
usbms_getparms(Ms_parms *data, usbms_state_t *usbmsp)
{
data->jitter_thresh = usbmsp->usbms_jitter_thresh;
data->speed_law = usbmsp->usbms_speedlaw;
data->speed_limit = usbmsp->usbms_speedlimit;
return (0);
}
static int
usbms_setparms(Ms_parms *data, usbms_state_t *usbmsp)
{
usbmsp->usbms_jitter_thresh = data->jitter_thresh;
usbmsp->usbms_speedlaw = data->speed_law;
usbmsp->usbms_speedlimit = data->speed_limit;
return (0);
}
static void
usbms_flush(usbms_state_t *usbmsp)
{
struct ms_softc *ms = &usbmsp->usbms_softc;
queue_t *q;
USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
"usbms_flush entering");
ms->ms_oldoff = 0;
ms->ms_eventstate = EVENT_BUT(usbmsp->usbms_num_buttons);
usbmsp->usbms_buf->mb_off = 0;
ms->ms_prevbuttons = (char)USB_NO_BUT_PRESSED;
usbmsp->usbms_oldbutt = ms->ms_prevbuttons;
if ((q = usbmsp->usbms_rq_ptr) != NULL && q->q_next != NULL) {
(void) putnextctl1(q, M_FLUSH, FLUSHR);
}
USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
"usbms_flush exiting");
}
static int
usbms_rput(queue_t *q, mblk_t *mp)
{
usbms_state_t *usbmsp = q->q_ptr;
mblk_t *tmp_mp;
ushort_t limit = (usbmsp->usbms_idf).tlen;
tmp_mp = mp;
if (usbmsp == 0) {
freemsg(mp);
return (0);
}
switch (mp->b_datap->db_type) {
case M_FLUSH:
if (*mp->b_rptr & FLUSHW)
flushq(WR(q), FLUSHDATA);
if (*mp->b_rptr & FLUSHR)
flushq(q, FLUSHDATA);
freemsg(mp);
return (0);
case M_BREAK:
freemsg(mp);
return (0);
case M_DATA:
if (!(usbmsp->usbms_flags & USBMS_OPEN)) {
freemsg(mp);
return (0);
}
break;
case M_CTL:
usbms_mctl_receive(q, mp);
return (0);
case M_ERROR:
usbmsp->usbms_protoerr = 1;
usbmsp->usbms_flags &= ~USBMS_QWAIT;
if (*mp->b_rptr == ENODEV) {
putnext(q, mp);
} else {
freemsg(mp);
}
return (0);
default:
putnext(q, mp);
return (0);
}
if ((MBLKL(tmp_mp) < limit) || ((MBLKL(tmp_mp) == limit) &&
(usbmsp->usbms_rptid != HID_REPORT_ID_UNDEFINED))) {
freemsg(mp);
return (0);
}
do {
if (usbmsp->usbms_rptid != HID_REPORT_ID_UNDEFINED) {
if (*(tmp_mp->b_rptr) != usbmsp->usbms_rptid) {
freemsg(mp);
return (0);
} else {
tmp_mp->b_rptr++;
}
}
usbms_input(usbmsp, tmp_mp);
} while ((tmp_mp = tmp_mp->b_cont) != NULL);
freemsg(mp);
return (0);
}
static void
usbms_mctl_receive(queue_t *q, mblk_t *mp)
{
usbms_state_t *usbmsd = (usbms_state_t *)q->q_ptr;
struct iocblk *iocp;
caddr_t data;
iocp = (struct iocblk *)mp->b_rptr;
if (mp->b_cont != NULL)
data = (caddr_t)mp->b_cont->b_rptr;
switch (iocp->ioc_cmd) {
case HID_GET_PARSER_HANDLE:
if ((data != NULL) &&
(iocp->ioc_count == sizeof (hidparser_handle_t)) &&
(MBLKL(mp->b_cont) == iocp->ioc_count)) {
usbmsd->usbms_report_descr_handle =
*(hidparser_handle_t *)data;
} else {
usbmsd->usbms_report_descr_handle = NULL;
}
freemsg(mp);
usbmsd->usbms_flags &= ~USBMS_QWAIT;
break;
case HID_SET_PROTOCOL:
usbmsd->usbms_flags &= ~USBMS_QWAIT;
default:
freemsg(mp);
break;
}
}
static void
usbms_input(usbms_state_t *usbmsp, mblk_t *mp)
{
struct usbmousebuf *b;
struct usbmouseinfo *mi;
int jitter_radius;
int32_t nbutt;
ushort_t i;
char c;
nbutt = usbmsp->usbms_num_buttons;
b = usbmsp->usbms_buf;
USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle,
"usbms_input entering");
if (b == NULL) {
return;
}
mi = &b->mb_info[b->mb_off];
c = mp->b_rptr[(usbmsp->usbms_idf).bpos];
mi->mi_buttons = (char)USB_NO_BUT_PRESSED;
if (c & USBMS_BUT(1)) {
mi->mi_buttons = mi->mi_buttons & USB_LEFT_BUT_PRESSED;
USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR,
usbms_log_handle,
"left button pressed");
}
if (c & USBMS_BUT(2)) {
mi->mi_buttons = mi->mi_buttons & USB_RIGHT_BUT_PRESSED;
USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR,
usbms_log_handle,
"right button pressed");
}
if (c & USBMS_BUT(3)) {
mi->mi_buttons = mi->mi_buttons &
USB_MIDDLE_BUT_PRESSED;
USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR,
usbms_log_handle,
"middle button pressed");
}
if (nbutt > 3) {
for (i = 4; i < (nbutt + 1); i++) {
if (c & USBMS_BUT(i)) {
mi->mi_buttons = mi->mi_buttons &
USB_BUT_PRESSED(i);
USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR,
usbms_log_handle,
"%d button pressed", i);
}
}
}
mi->mi_x += usbms_get_coordinate((usbmsp->usbms_idf).xpos,
(usbmsp->usbms_idf).xlen, mp);
USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR,
usbms_log_handle, "x = %d", (int)mi->mi_x);
uniqtime32(&mi->mi_time);
mi->mi_y += usbms_get_coordinate((usbmsp->usbms_idf).ypos,
(usbmsp->usbms_idf).ylen, mp);
USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle,
"y = %d", (int)mi->mi_y);
if (usbmsp->usbms_num_wheels) {
mi->mi_z += usbms_get_coordinate((usbmsp->usbms_idf).zpos,
(usbmsp->usbms_idf).zlen, mp);
USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle,
"z = %d", (int)mi->mi_z);
}
if (usbmsp->usbms_jitter) {
(void) quntimeout(usbmsp->usbms_rq_ptr,
(timeout_id_t)usbmsp->usbms_timeout_id);
usbmsp->usbms_jitter = 0;
}
if (!usbmsp->usbms_num_wheels) {
mi->mi_z = 0;
}
if (!(mi->mi_z) && (mi->mi_buttons == usbmsp->usbms_oldbutt)) {
if (mi->mi_x == 0 && mi->mi_y == 0) {
return;
}
jitter_radius = usbmsp->usbms_jitter_thresh;
if (USB_ABS((int)mi->mi_x) <= jitter_radius &&
USB_ABS((int)mi->mi_y) <= jitter_radius) {
usbmsp->usbms_jitter = 1;
usbmsp->usbms_timeout_id =
qtimeout(usbmsp->usbms_rq_ptr,
(void (*)())usbms_incr,
(void *)usbmsp,
(clock_t)usbmsp->usbms_jittertimeout);
return;
}
}
usbmsp->usbms_oldbutt = mi->mi_buttons;
usbms_incr(usbmsp);
USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle,
"usbms_input exiting");
}
static int
usbms_get_coordinate(uint_t pos, uint_t len, mblk_t *mp)
{
uint_t utmp, bitval, val;
int i, xyz;
utmp = 0;
for (i = (pos + len - 1); i >= (int)pos; i--) {
bitval = (mp->b_rptr[i/8] & (1 << (i%8))) >> (i%8);
utmp = utmp * 2 + bitval;
}
val = 1 << (len - 1);
xyz = (int)(utmp - val);
if (xyz < 0)
xyz += val;
else if (xyz == 0)
xyz = -(val - 1);
else
xyz -= val;
return (xyz);
}
static void
usbms_incr(void *arg)
{
usbms_state_t *usbmsp = arg;
struct ms_softc *ms = &usbmsp->usbms_softc;
struct usbmousebuf *b;
struct usbmouseinfo *mi;
int xc, yc, zc;
int wake;
int speedl = usbmsp->usbms_speedlimit;
int xabs, yabs;
usbmsp->usbms_jitter = 0;
b = usbmsp->usbms_buf;
USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle,
"usbms_incr entering");
if (b == NULL) {
return;
}
mi = &b->mb_info[b->mb_off];
if (usbmsp->usbms_speedlaw) {
xabs = USB_ABS((int)mi->mi_x);
yabs = USB_ABS((int)mi->mi_y);
if (xabs > speedl || yabs > speedl) {
usbmsp->usbms_speed_count++;
}
if (xabs > speedl) {
mi->mi_x = 0;
}
if (yabs > speedl) {
mi->mi_y = 0;
}
}
xc = yc = zc = 0;
wake = b->mb_off == ms->ms_oldoff;
if (++b->mb_off >= b->mb_size) {
b->mb_off = 0;
mi = b->mb_info;
} else {
mi++;
}
if (b->mb_off == ms->ms_oldoff) {
if (overrun_msg) {
USB_DPRINTF_L1(PRINT_MASK_ALL, usbms_log_handle,
"Mouse buffer flushed when overrun.");
}
usbms_flush(usbmsp);
overrun_cnt++;
mi = b->mb_info;
}
mi->mi_buttons = (char)USB_NO_BUT_PRESSED;
mi->mi_x = xc;
mi->mi_y = yc;
mi->mi_z = zc;
if (wake) {
USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle,
"usbms_incr run service");
qenable(usbmsp->usbms_rq_ptr);
}
USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle,
"usbms_incr exiting");
}
static int
usbms_check_for_wheels(usbms_state_t *usbmsp)
{
int rval, report_id;
if (usbmsp->usbms_report_descr_handle) {
if (hidparser_get_usage_attribute(
usbmsp->usbms_report_descr_handle,
0,
HIDPARSER_ITEM_INPUT,
HID_GENERIC_DESKTOP,
HID_GD_X,
HIDPARSER_ITEM_REPORT_ID,
&usbmsp->usbms_rptid) == HIDPARSER_NOT_FOUND) {
usbmsp->usbms_rptid = HID_REPORT_ID_UNDEFINED;
report_id = 0;
} else {
report_id = usbmsp->usbms_rptid;
}
rval = hidparser_get_usage_attribute(
usbmsp->usbms_report_descr_handle,
report_id,
HIDPARSER_ITEM_INPUT,
HID_GENERIC_DESKTOP,
HID_GD_WHEEL,
HIDPARSER_ITEM_REPORT_COUNT,
&usbmsp->usbms_num_wheels);
if (rval == HIDPARSER_SUCCESS) {
usbmsp->usbms_wheel_state_bf |=
VUID_WHEEL_STATE_ENABLED;
return (USB_SUCCESS);
}
}
usbmsp->usbms_num_wheels = 0;
return (USB_FAILURE);
}
static int
usbms_make_copyreq(mblk_t *mp, uint_t pvtsize, uint_t state, uint_t reqsize,
uint_t contsize, uint_t copytype)
{
struct copyreq *cq;
struct copyresp *cr;
mblk_t *ioctmp;
mblk_t *conttmp;
usbms_iocstate_t *usbmsioc;
if ((!pvtsize) && state) {
cr = (struct copyresp *)mp->b_rptr;
ioctmp = cr->cp_private;
}
cq = (struct copyreq *)mp->b_rptr;
if (mp->b_cont == NULL) {
return (EINVAL);
}
cq->cq_addr = *((caddr_t *)mp->b_cont->b_rptr);
cq->cq_size = reqsize;
cq->cq_flag = 0;
if (pvtsize) {
ioctmp = (mblk_t *)allocb(pvtsize, BPRI_MED);
if (ioctmp == NULL) {
return (EAGAIN);
}
cq->cq_private = ioctmp;
ioctmp = cq->cq_private;
} else {
cq->cq_private = NULL;
}
if (state) {
usbmsioc = (usbms_iocstate_t *)ioctmp->b_rptr;
usbmsioc->ioc_state = state;
if (pvtsize) {
usbmsioc->u_addr = cq->cq_addr;
} else {
cq->cq_addr = usbmsioc->u_addr;
cq->cq_private = ioctmp;
}
ioctmp->b_wptr = ioctmp->b_rptr + sizeof (usbms_iocstate_t);
}
if (contsize) {
conttmp = (mblk_t *)allocb(contsize, BPRI_MED);
if (conttmp == NULL) {
return (EAGAIN);
}
if (mp->b_cont) {
freemsg(mp->b_cont);
mp->b_cont = conttmp;
}
}
mp->b_datap->db_type = (unsigned char)copytype;
mp->b_wptr = mp->b_rptr + sizeof (struct copyreq);
return (USB_SUCCESS);
}
static int
usbms_service_wheel_info(queue_t *q, mblk_t *datap)
{
wheel_info *wi;
usbms_state_t *usbmsp = (usbms_state_t *)q->q_ptr;
uint_t err;
wi = (wheel_info *)datap->b_rptr;
if (wi->vers != VUID_WHEEL_INFO_VERS) {
err = EINVAL;
return (err);
}
if (wi->id > (usbmsp->usbms_num_wheels - 1)) {
err = EINVAL;
return (err);
}
wi->format = (usbmsp->usbms_wheel_orient_bf & (1 << wi->id)) ?
VUID_WHEEL_FORMAT_HORIZONTAL : VUID_WHEEL_FORMAT_VERTICAL;
return (USB_SUCCESS);
}
static int
usbms_service_wheel_state(queue_t *q, mblk_t *datap, uint_t cmd)
{
wheel_state *ws;
uint_t err;
usbms_state_t *usbmsp = (usbms_state_t *)q->q_ptr;
ws = (wheel_state *)datap->b_rptr;
if (ws->vers != VUID_WHEEL_STATE_VERS) {
err = EINVAL;
return (err);
}
if (ws->id > (usbmsp->usbms_num_wheels - 1)) {
err = EINVAL;
return (err);
}
switch (cmd) {
case VUIDGWHEELSTATE:
ws->stateflags = (usbmsp->usbms_wheel_state_bf >> ws->id) &
VUID_WHEEL_STATE_ENABLED;
break;
case VUIDSWHEELSTATE:
usbmsp->usbms_wheel_state_bf = (ws->stateflags << ws->id) |
(~(1 << ws->id) & usbmsp->usbms_wheel_state_bf);
break;
default:
err = EINVAL;
return (err);
}
return (USB_SUCCESS);
}
static int
usbms_get_screen_parms(queue_t *q, mblk_t *datap)
{
usbms_state_t *usbmsp = (usbms_state_t *)q->q_ptr;
Ms_screen_resolution *res = &(usbmsp->usbms_resolution);
Ms_screen_resolution *data;
data = (Ms_screen_resolution *)datap->b_rptr;
res->height = data->height;
res->width = data->width;
return (USB_SUCCESS);
}
static void
usbms_ack_ioctl(mblk_t *mp)
{
struct iocblk *iocbp = (struct iocblk *)mp->b_rptr;
mp->b_datap->db_type = M_IOCACK;
mp->b_wptr = mp->b_rptr + sizeof (struct iocblk);
iocbp->ioc_error = 0;
iocbp->ioc_count = 0;
iocbp->ioc_rval = 0;
if (mp->b_cont != NULL) {
freemsg(mp->b_cont);
mp->b_cont = NULL;
}
}
static mblk_t *
usbms_setup_abs_mouse_event(void)
{
mblk_t *mb;
Firm_event *fep;
if ((mb = allocb(sizeof (Firm_event), BPRI_HI)) != NULL) {
fep = (Firm_event *)mb->b_wptr;
fep->id = MOUSE_TYPE_ABSOLUTE;
fep->pair_type = FE_PAIR_NONE;
fep->pair = 0;
fep->value = 0;
mb->b_wptr += sizeof (Firm_event);
} else {
USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
"No resource to report ABS mouse event");
}
return (mb);
}
int
usbms_read_input_data_format(usbms_state_t *usbmsp)
{
hidparser_rpt_t *ms_rpt;
uint_t i, button_page;
uint_t limit = 0;
uint32_t rptcnt, rptsz;
usbms_idf *idf = &(usbmsp->usbms_idf);
Ms_screen_resolution *res = &(usbmsp->usbms_resolution);
mblk_t *mb;
queue_t *q;
int rval;
usbmsp->usbms_rpt_abs = B_FALSE;
ms_rpt = kmem_zalloc(sizeof (hidparser_rpt_t), KM_SLEEP);
rval = hidparser_get_usage_list_in_order(
usbmsp->usbms_report_descr_handle,
usbmsp->usbms_rptid,
HIDPARSER_ITEM_INPUT,
ms_rpt);
if (rval != HIDPARSER_SUCCESS) {
kmem_free(ms_rpt, sizeof (hidparser_rpt_t));
return (USB_FAILURE);
}
button_page = 0;
for (i = 0; i < ms_rpt->no_of_usages; i++) {
rptcnt = ms_rpt->usage_descr[i].rptcnt;
rptsz = ms_rpt->usage_descr[i].rptsz;
if ((ms_rpt->usage_descr[i].usage_page ==
HID_BUTTON_PAGE) && (!button_page)) {
idf->bpos = limit;
limit += (rptcnt * rptsz);
button_page = 1;
continue;
}
switch (ms_rpt->usage_descr[i].usage_id) {
case HID_GD_X:
idf->xpos = limit;
idf->xlen = rptsz;
limit += rptsz;
break;
case HID_GD_Y:
idf->ypos = limit;
idf->ylen = rptsz;
limit += rptsz;
break;
case HID_GD_Z:
limit += rptsz;
break;
case HID_GD_WHEEL:
idf->zpos = limit;
idf->zlen = rptsz;
limit += rptsz;
break;
default:
limit += rptcnt * rptsz;
break;
}
}
kmem_free(ms_rpt, sizeof (hidparser_rpt_t));
idf->tlen = limit / 8;
rval = hidparser_get_main_item_data_descr(
usbmsp->usbms_report_descr_handle,
usbmsp->usbms_rptid,
HIDPARSER_ITEM_INPUT,
HID_GENERIC_DESKTOP,
HID_GD_X,
&idf->xattr);
if (rval != HIDPARSER_SUCCESS) {
return (USB_FAILURE);
}
idf->yattr = idf->xattr;
if (!(idf->xattr & HID_MAIN_ITEM_RELATIVE)) {
if (limit % 8) {
USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
"Wrong data packet include %d bits", limit);
return (USB_FAILURE);
}
if (hidparser_get_usage_attribute(
usbmsp->usbms_report_descr_handle,
usbmsp->usbms_rptid,
HIDPARSER_ITEM_INPUT,
HID_GENERIC_DESKTOP,
HID_GD_X,
HIDPARSER_ITEM_LOGICAL_MAXIMUM,
&usbmsp->usbms_logical_Xmax) != HIDPARSER_SUCCESS) {
USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
"fail to get X logical max.");
return (USB_FAILURE);
}
if (hidparser_get_usage_attribute(
usbmsp->usbms_report_descr_handle,
usbmsp->usbms_rptid,
HIDPARSER_ITEM_INPUT,
HID_GENERIC_DESKTOP,
HID_GD_Y,
HIDPARSER_ITEM_LOGICAL_MAXIMUM,
&usbmsp->usbms_logical_Ymax) != HIDPARSER_SUCCESS) {
USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
"fail to get Y logical max.");
return (USB_FAILURE);
}
if (usbmsp->usbms_logical_Xmax == 0) {
USB_DPRINTF_L3(PRINT_MASK_ALL,
usbms_log_handle,
"X logical max value is zero");
return (USB_FAILURE);
}
if (usbmsp->usbms_logical_Ymax == 0) {
USB_DPRINTF_L3(PRINT_MASK_ALL,
usbms_log_handle,
"Y logical max value is zero");
return (USB_FAILURE);
}
res->height = USBMS_DEFAULT_RES_HEIGHT;
res->width = USBMS_DEFAULT_RES_WIDTH;
usbmsp->usbms_num_wheels = 0;
q = usbmsp->usbms_rq_ptr;
if ((mb = usbms_setup_abs_mouse_event()) != NULL) {
putnext(q, mb);
} else {
return (USB_NO_RESOURCES);
}
}
return (USB_SUCCESS);
}