usbms.c revision 77e515715b61e28fcf0c3f30936492888cecfd8b
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/vuid_event.h>
#include <sys/vuid_wheel.h>
/* debugging information */
static usb_log_handle_t usbms_log_handle;
static struct streamtab usbms_streamtab;
"usbms",
};
/*
* Module linkage information for the kernel.
*/
static struct modlstrmod modlstrmod = {
"USB mouse streams",
&fsw
};
static struct modlinkage modlinkage = {
(void *)&modlstrmod,
};
int
_init(void)
{
if (rval == 0) {
}
return (rval);
}
int
_fini(void)
{
if (rval == 0) {
}
return (rval);
}
int
{
}
/* Function prototypes */
static void usbms_reioctl(void *);
static int usbms_open();
static int usbms_close();
static int usbms_wput();
static void usbms_rput();
static void usbms_mctl_receive(
register queue_t *q,
static void usbms_rserv(queue_t *q);
static void usbms_miocdata(
register queue_t *q,
static void usbms_resched(void *);
static int usbms_getparms(
static int usbms_setparms(
static int usbms_get_screen_parms(
register queue_t *q,
static void usbms_incr(void *);
static void usbms_input(
static void usbms_rserv_vuid_button(
queue_t *q,
struct usbmouseinfo *mi,
static void usbms_rserv_vuid_event_y(
queue_t *q,
struct usbmouseinfo *mi,
static void usbms_rserv_vuid_event_x(
queue_t *q,
struct usbmouseinfo *mi,
static void usbms_rserv_vuid_event_wheel(
queue_t *,
struct usbmouseinfo *,
mblk_t **,
static int usbms_check_for_wheels(usbms_state_t *);
static int usbms_make_copyreq(
mblk_t *,
static int usbms_service_wheel_info(
queue_t *,
mblk_t *);
static int usbms_service_wheel_state(
queue_t *,
mblk_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();
static int usbms_get_coordinate(
extern void uniqtime32();
/*
* Device driver qinit functions
*/
static struct module_info usbms_mod_info = {
0x0ffff, /* module id number */
"usbms", /* module name */
0, /* min packet size accepted */
INFPSZ, /* max packet size accepted */
512, /* hi-water mark */
128 /* lo-water mark */
};
/* read side queue information structure */
(int (*)())usbms_rput, /* put procedure not needed */
(int (*)())usbms_rserv, /* service procedure */
usbms_open, /* called on startup */
usbms_close, /* called on finish */
NULL, /* for future use */
&usbms_mod_info, /* module information structure */
NULL /* module statistics structure */
};
/* write side queue information structure */
usbms_wput, /* put procedure */
NULL, /* no service proecedure needed */
NULL, /* open not used on write side */
NULL, /* close not used on write side */
NULL, /* for future use */
&usbms_mod_info, /* module information structure */
NULL /* module statistics structure */
};
static struct streamtab usbms_streamtab = {
&rinit,
&winit,
NULL, /* not a MUX */
NULL /* not a MUX */
};
/*
* Message when overrun circular buffer
*/
static int overrun_msg;
/* Increment when overrun circular buffer */
static int overrun_cnt;
extern int hz;
/*
* Mouse buffer size in bytes. Place here as variable so that one could
* massage it using adb if it turns out to be too small.
*/
/*
* Regular STREAMS Entry points
*/
/*
* usbms_open() :
* open() entry point for the USB mouse module.
*/
/*ARGSUSED*/
static int
usbms_open(queue_t *q,
int flag,
int sflag,
{
register struct usbmousebuf *mousebufp;
/* Clone opens are not allowed */
return (EINVAL);
/* If the module is already open, just return */
if (q->q_ptr) {
return (0);
}
/* allocate usbms state structure */
usbmsp->usbms_rq_ptr = q;
qprocson(q);
/*
* Set up private data.
*/
/*
* Initially set the format to MS_VUID_FORMAT
*/
/*
* Allocate buffer and initialize data.
*/
KM_SLEEP);
/* Truncation will happen */
sizeof (struct usbmousebuf)) /
sizeof (struct usbmouseinfo));
sizeof (struct usbmousebuf));
/* request hid report descriptor from HID */
qprocsoff(q);
return (ENOMEM);
}
/*
* Now that signal has been sent, wait for report descriptor. Cleanup
* if user signals in the mean time (as when this gets opened in an
* inappropriate context and the user types a ^C).
*/
if (qwait_sig(q) == 0) {
qprocsoff(q);
return (EINTR);
}
}
0,
0,
usbms_log_handle, "Num of buttons is : %d",
} else {
"hidparser_get_usage_attribute failed : "
"Set to default number of buttons(3).");
}
} else {
usbms_log_handle, "Invalid HID "
"Descriptor Tree. Set to default value(3 buttons).");
}
/* check if this mouse has wheel */
"No wheels detected");
} else {
"Wheel detected");
}
/* get the data format from the hid descriptor */
qprocsoff(q);
return (EINVAL);
}
"usbms_open exiting");
return (0);
}
/*
* usbms_close() :
* close() entry point for the USB mouse module.
*/
/*ARGSUSED*/
static int
usbms_close(queue_t *q,
int flag,
{
"usbms_close entering");
qprocsoff(q);
if (usbmsp->usbms_jitter) {
(void) quntimeout(q,
usbmsp->usbms_jitter = 0;
}
if (usbmsp->usbms_reioctl_id) {
usbmsp->usbms_reioctl_id = 0;
}
if (usbmsp->usbms_resched_id) {
usbmsp->usbms_resched_id = 0;
}
/*
* We were holding an "ioctl" response pending the
* availability of an "mblk" to hold data to be passed up;
* another "ioctl" came through, which means that "ioctl"
* must have timed out or been aborted.
*/
}
/* Free mouse buffer */
}
"usbms_close exiting");
return (0);
}
/*
* usbms_rserv() :
* Read queue service routine.
* Turn buffered mouse events into stream messages.
*/
static void
usbms_rserv(queue_t *q)
{
struct usbmousebuf *b;
struct usbmouseinfo *mi;
"usbms_rserv entering");
switch (ms->ms_readformat) {
case MS_3BYTE_FORMAT: {
register char *cp;
"Can't set to 3 byte format. Length != 1");
return;
}
/* Update read buttons */
/* lower pri to avoid mouse droppings */
} else {
if (usbmsp->usbms_resched_id) {
qunbufcall(q,
}
(size_t)3,
(void (*)())usbms_resched,
(void *) usbmsp);
if (usbmsp->usbms_resched_id == 0)
return; /* try again later */
/* bufcall failed; just pitch this event */
/* or maybe flush queue? */
}
/* circular buffer wraparound */
}
break;
}
case MS_VUID_FORMAT:
default: {
do {
switch (ms->ms_eventstate) {
case EVENT_WHEEL:
1 : 0);
if (usbmsp->usbms_num_wheels) {
for (i = 0; i < loop; i++) {
}
}
break;
case EVENT_BUT8:
case EVENT_BUT7:
case EVENT_BUT6:
case EVENT_BUT5:
case EVENT_BUT4:
case EVENT_BUT3: /* Send right button */
case EVENT_BUT2: /* Send middle button */
case EVENT_BUT1: /* Send left button */
break;
case EVENT_Y:
break;
case EVENT_X:
break;
default:
/* start again */
break;
}
/* lower pri to avoid mouse droppings */
}
/* circular buffer wraparound */
}
} else
ms->ms_eventstate--;
}
}
}
"usbms_rserv exiting");
}
/*
* usbms_rserv_vuid_event_wheel
* convert wheel data to firm events
*/
static void
struct usbmouseinfo *mi,
{
return;
}
} else {
if (usbmsp->usbms_resched_id) {
qunbufcall(q,
}
(void (*)())usbms_resched, (void *) usbmsp);
if (usbmsp->usbms_resched_id == 0) {
/* try again later */
return;
}
/* flush the queue */
}
}
}
/*
* usbms_rserv_vuid_button() :
* Process a VUID button event
*/
static void
struct usbmouseinfo *mi,
{
int button_number;
/* Test button. Send an event if it changed. */
switch (button_number) {
case 2:
/* Right button */
hwbit = 0x01;
break;
case 1:
/*
* On two-button mice, the second button is the "right"
* button. There is no "middle". The vuidps2.c file has
* a bmap[] array in sendButtonEvent(). We do something
* equivalent here ONLY in the case of two-button mice.
*/
if (nbutt == 2) {
hwbit = 0x01;
/*
* Trick the vuid message into thinking it's a
* right-button click also.
*/
button_number = 2;
} else {
/* ... otherwise, it's just the middle button */
hwbit = 0x02;
}
break;
case 0:
/* Left button */
hwbit = 0x04;
break;
default :
/* Any other button */
ms->ms_eventstate);
break;
}
ms->ms_vuidaddr) |
+ button_number);
/*
* Update read buttons and set
* value
*/
ms->ms_prevbuttons |=
} else {
ms->ms_prevbuttons &=
~hwbit;
}
} else {
if (usbmsp->usbms_resched_id) {
qunbufcall(q,
}
qbufcall(q,
sizeof (Firm_event),
(void (*)())usbms_resched,
(void *) usbmsp);
if (usbmsp->usbms_resched_id == 0)
/* try again later */
return;
/*
* bufcall failed; just pitch
* this event
*/
/* or maybe flush queue? */
}
}
}
/*
* usbms_rserv_vuid_event_y() :
* Process a VUID y-event
*/
static void
usbms_rserv_vuid_event_y(register queue_t *q,
register struct usbmouseinfo *mi,
{
register Firm_event *fep;
/*
* The (max, 0) message and (0, max) message are always sent before
* the button click message is sent on the IBM Bladecenter. Stop
* their sending may prevent the coordinate from moving to the
* (max, max).
*/
return;
}
}
/* Send y if changed. */
ms->ms_vuidaddr) |
} else {
ms->ms_vuidaddr) |
usbmsp->usbms_logical_Ymax) >=
}
}
} else {
if (usbmsp->usbms_resched_id) {
qunbufcall(q,
}
qbufcall(q,
sizeof (Firm_event),
(void (*)())usbms_resched,
(void *)usbmsp);
if (usbmsp->usbms_resched_id == 0) {
/* try again later */
return;
}
/*
* bufcall failed; just pitch
* this event
*/
/* or maybe flush queue? */
}
}
}
/*
* usbms_rserv_vuid_event_x() :
* Process a VUID x-event
*/
static void
usbms_rserv_vuid_event_x(register queue_t *q,
register struct usbmouseinfo *mi,
{
register Firm_event *fep;
/*
* The (max, 0) message and (0, max) message are always sent before
* the button click message is sent on the IBM Bladecenter. Stop
* their sending may prevent the coordinate from moving to the
* (max, max).
*/
return;
}
}
/* Send x if changed. */
ms->ms_vuidaddr) |
} else {
usbmsp->usbms_logical_Xmax) >=
}
}
} else {
if (usbmsp->usbms_resched_id)
qunbufcall(q,
qbufcall(q,
sizeof (Firm_event),
(void (*)())usbms_resched,
(void *) usbmsp);
if (usbmsp->usbms_resched_id == 0)
/* try again later */
return;
/*
* bufcall failed; just
* pitch this event
*/
/* or maybe flush queue? */
}
}
}
/*
* usbms_resched() :
* Callback routine for the qbufcall() in case
* of allocb() failure. When buffer becomes
* available, this function is called and
* enables the queue.
*/
static void
usbms_resched(void * usbmsp)
{
register queue_t *q;
tmp_usbmsp->usbms_resched_id = 0;
if ((q = tmp_usbmsp->usbms_rq_ptr) != 0)
qenable(q); /* run the service procedure */
}
/*
* usbms_wput() :
* wput() routine for the mouse module.
* Module below : hid, module above : consms
*/
static int
usbms_wput(queue_t *q,
{
"usbms_wput entering");
case M_FLUSH: /* Canonical flush handling */
}
}
break;
case M_IOCTL:
usbms_ioctl(q, mp);
break;
case M_IOCDATA:
usbms_miocdata(q, mp);
break;
default:
}
"usbms_wput exiting");
return (0);
}
/*
* usbms_ioctl() :
* Process ioctls we recognize and own. Otherwise, NAK.
*/
static void
usbms_ioctl(register queue_t *q,
{
int err = 0;
ushort_t transparent = 0;
"usbms_ioctl entering");
return;
}
case VUIDSFORMAT:
if (err != 0)
break;
break;
}
/*
* Flush mouse buffer because the messages upstream of us
* are in the old format.
*/
break;
case VUIDGFORMAT:
ioctlrespsize = sizeof (int);
goto allocfailure;
}
break;
case VUIDGADDR:
case VUIDSADDR:
if (err != 0)
break;
break;
}
else
break;
case MSIOGETPARMS:
ioctlrespsize = sizeof (Ms_parms);
goto allocfailure;
}
break;
case MSIOSETPARMS:
if (err != 0)
break;
break;
case MSIOBUTTONS:
ioctlrespsize = sizeof (int);
goto allocfailure;
}
break;
case VUIDGWHEELCOUNT:
/*
* New IOCTL support. Since it's explicitly mentioned that
* you can't add more ioctls to stream head's hard coded
* list, we have to do the transparent ioctl processing
* which is heavy.
*/
/* Currently support for only one wheel */
transparent = 1;
0, M_COPYOUT)) {
break;
}
}
ioctlrespsize = sizeof (int);
goto allocfailure;
}
}
if (transparent) {
return;
}
break;
case VUIDGWHEELINFO:
sizeof (usbms_iocstate_t),
sizeof (wheel_info),
0,
M_COPYIN)) {
break;
}
/*
* If there is no b_cont the earlier func. will fail.
* Hence there is no need for an explicit check here.
*/
return;
}
sizeof (wheel_info)) {
break;
}
break;
case VUIDGWHEELSTATE:
sizeof (usbms_iocstate_t),
sizeof (wheel_state),
0,
M_COPYIN)) {
break;
}
return;
}
break;
}
break;
case VUIDSWHEELSTATE:
sizeof (usbms_iocstate_t),
sizeof (wheel_state),
0,
M_COPYIN)) {
break;
}
return;
}
break;
}
break;
case MSIOSRESOLUTION:
sizeof (usbms_iocstate_t),
sizeof (Ms_screen_resolution),
0,
M_COPYIN)) {
break;
}
return;
}
break;
}
/*
* Create the absolute mouse type event.
* It is used for the hotplug absolute mouse.
*/
report_abs = B_TRUE;
}
break;
default:
return;
} /* switch */
if (err != 0)
else {
if (report_abs == B_TRUE) {
/* send the abs mouse type event to the upper level */
}
}
}
return;
/*
* We needed to allocate something to handle this "ioctl", but
* couldn't; save this "ioctl" and arrange to get called back when
* it's more likely that we can get what we need.
* If there's already one being saved, throw it out, since it
* must have timed out.
*/
if (usbmsp->usbms_reioctl_id) {
}
(void (*)())usbms_reioctl,
(void *)usbmsp);
}
/*
* M_IOCDATA processing for IOCTL's: VUIDGWHEELCOUNT, VUIDGWHEELINFO,
* VUIDGWHEELSTATE, VUIDSWHEELSTATE & MSIOSRESOLUTION.
*/
static void
usbms_miocdata(register queue_t *q,
{
int err = 0;
goto err;
}
case VUIDGWHEELCOUNT:
break;
case VUIDGWHEELINFO:
break;
}
goto err;
}
sizeof (wheel_info), 0, M_COPYOUT)) {
goto err;
}
}
break;
case VUIDGWHEELSTATE:
break;
}
VUIDGWHEELSTATE)) {
goto err;
}
sizeof (wheel_state), 0, M_COPYOUT)) {
goto err;
}
}
break;
case VUIDSWHEELSTATE:
break;
}
VUIDSWHEELSTATE)) {
goto err;
}
break;
case MSIOSRESOLUTION:
break;
}
goto err;
}
break;
default:
break;
}
err:
if (err) {
}
if (copyresp->cp_private) {
}
}
}
/*
* usbms_reioctl() :
* This function is set up as call-back function should an ioctl fail.
* It retries the ioctl.
*/
static void
usbms_reioctl(void * usbms_addr)
{
register queue_t *q;
q = usbmsp->usbms_wq_ptr;
usbms_ioctl(q, mp);
}
}
/*
* usbms_getparms() :
* Called from MSIOGETPARMS ioctl to get the
* current jitter_thesh, speed_law and speed_limit
* values.
*/
static int
{
return (0);
}
/*
* usbms_setparms() :
* Called from MSIOSETPARMS ioctl to set the
* current jitter_thesh, speed_law and speed_limit
* values.
*/
static int
{
return (0);
}
/*
* usbms_flush() :
* Resets the ms_softc structure to default values
* and sends M_FLUSH above.
*/
static void
{
register queue_t *q;
"usbms_flush entering");
}
"usbms_flush exiting");
}
/*
* usbms_rput() :
* Put procedure for input from driver end of stream (read queue).
*/
static void
usbms_rput(queue_t *q,
{
/* Maintain the original mp */
if (usbmsp == 0) {
return;
}
case M_FLUSH:
return;
case M_BREAK:
/*
* We don't have to handle this
* because nothing is sent from the downstream
*/
return;
case M_DATA:
return;
}
break;
case M_CTL:
usbms_mctl_receive(q, mp);
return;
case M_ERROR:
return;
default:
return;
}
/*
* A data message, consisting of bytes from the mouse.
* Make sure there are atleast "limit" number of bytes.
*/
return;
}
do {
return;
} else {
/* We skip the report id prefix. */
}
}
}
/*
* usbms_mctl_receive() :
* Handle M_CTL messages from hid. If
* we don't understand the command, free message.
*/
static void
usbms_mctl_receive(register queue_t *q,
{
case HID_GET_PARSER_HANDLE:
*(hidparser_handle_t *)data;
} else {
}
break;
case HID_SET_PROTOCOL:
/* FALLTHRU */
default:
break;
}
}
/*
* usbms_input() :
*
* Mouse input routine; process a byte received from a mouse and
* assemble into a mouseinfo message for the window system.
*
* The USB mouse send a three-byte packet organized as
* button, dx, dy
* where dx and dy can be any signed byte value. The mouseinfo message
* is organized as
* dx, dy, button, timestamp
* Our strategy is to collect but, dx & dy three-byte packet, then
* send the mouseinfo message up.
*
* Basic algorithm: throw away bytes until we get a [potential]
* button byte. Collect button; Collect dx; Collect dy; Send button,
* dx, dy, timestamp.
*
* Watch out for overflow!
*/
static void
{
register struct usbmousebuf *b;
register struct usbmouseinfo *mi;
register int jitter_radius;
ushort_t i;
char c;
"usbms_input entering");
if (b == NULL) {
return;
}
/*
* Lower 3 bits are middle, right, left.
*/
"left button pressed");
}
"right button pressed");
}
"middle button pressed");
}
if (nbutt > 3) {
if (c & USBMS_BUT(i)) {
USB_BUT_PRESSED(i);
"%d button pressed", i);
}
}
}
/* get the delta X and Y from the sample */
/*
* Check the wheel data in the current event.
* If it exists, the wheel data is got from the sample.
*/
if (usbmsp->usbms_num_wheels) {
}
if (usbmsp->usbms_jitter) {
usbmsp->usbms_jitter = 0;
}
if (!usbmsp->usbms_num_wheels) {
}
/*
* If there is a wheel movement or a change in the button state,
* send the data up immediately.
*/
/*
* Buttons did not change; did position?
*/
/* no, position did not change */
return;
}
/*
* Did the mouse move more than the jitter threshhold?
*/
/*
* Mouse moved less than the jitter threshhold.
* Don't indicate an event; keep accumulating motions.
* After "jittertimeout" ticks expire, treat
* the accumulated delta as the real delta.
*/
(void (*)())usbms_incr,
(void *)usbmsp,
return;
}
}
"usbms_input exiting");
}
/*
* usbms_get_coordinate():
* get the X, Y, WHEEL coordinate values
*/
static int
{
int i, xyz;
/* get the unsigned int value from the bit stream */
utmp = 0;
}
/* convert the unsigned int value into int value */
if (xyz < 0)
else if (xyz == 0)
else
return (xyz);
}
/*
* usbms_incr() :
* Increment the mouse sample pointer.
* Called either immediately after a sample or after a jitter timeout.
*/
static void
usbms_incr(void *arg)
{
register struct usbmousebuf *b;
register struct usbmouseinfo *mi;
register int wake;
/*
* No longer waiting for jitter timeout
*/
usbmsp->usbms_jitter = 0;
"usbms_incr entering");
if (b == NULL) {
return;
}
if (usbmsp->usbms_speedlaw) {
}
}
}
}
/* See if we need to wake up anyone waiting for input */
/* Adjust circular buffer pointer */
b->mb_off = 0;
} else {
mi++;
}
/*
* If over-took read index then flush buffer so that mouse state
* is consistent.
*/
if (overrun_msg) {
"Mouse buffer flushed when overrun.");
}
overrun_cnt++;
}
/* Remember current buttons and fractional part of x & y */
if (wake) {
"usbms_incr run service");
}
"usbms_incr exiting");
}
/*
* usbms_check_for_wheels
* return SUCCESS if wheel is found, else return FAILURE
*/
static int
{
if (usbmsp->usbms_report_descr_handle) {
/* Get the report id that has mouse data */
0, /* Doesn't matter */
report_id = 0;
} else {
}
/* find no. of wheels in this report */
if (rval == HIDPARSER_SUCCESS) {
/*
* Found wheel. By default enable the wheel.
* Currently only enable only the first wheel.
*/
return (USB_SUCCESS);
}
}
usbmsp->usbms_num_wheels = 0;
return (USB_FAILURE);
}
/*
* usbms_make_copyreq
* helper function for usbms ioctls
*/
static int
{
}
return (EINVAL);
}
if (pvtsize) {
return (EAGAIN);
}
} else {
/*
* Here we need to set cq_private even if there's
* no private data, otherwise its value will be
* TRANSPARENT (-1) on 64bit systems because it
* overlaps iocp->ioc_count. If user address (cq_addr)
* is invalid, it would cause panic later in
* usbms_miocdata:
* freemsg((mblk_t *)copyresp->cp_private);
*/
}
if (state) {
if (pvtsize) { /* M_COPYIN */
} else {
}
}
if (contsize) {
return (EAGAIN);
}
}
}
return (USB_SUCCESS);
}
static int
{
wheel_info *wi;
return (err);
}
return (err);
}
return (USB_SUCCESS);
}
static int
usbms_service_wheel_state(register queue_t *q,
{
return (err);
}
return (err);
}
switch (cmd) {
case VUIDGWHEELSTATE:
break;
case VUIDSWHEELSTATE:
break;
default:
return (err);
}
return (USB_SUCCESS);
}
/*
* usbms_get_screen_parms() :
* Called from MSIOSRESOLUTION ioctl to get the
*/
static int
usbms_get_screen_parms(register queue_t *q,
{
return (USB_SUCCESS);
}
static void
{
}
}
/*
* usbms_setup_abs_mouse_event() :
* Called from MSIOSRESOLUTION ioctl to create
* the absolute mouse type firm event.
*/
static mblk_t *
{
} else {
"No resource to report ABS mouse event");
}
return (mb);
}
/*
* usbms_read_input_data_format() :
* Get the mouse packet length and usages' length.
* Check whether X and Y are relative or absolute.
*
* If they are absolute, the X and Y logical max values
* will be got. A firm event will be created and sent
* to the upper level.
*/
int
{
uint_t i, button_page;
register queue_t *q;
int rval;
/* allocate hidparser report structure */
/*
* Check what is the total length of the mouse packet
* and get the usages and their lengths in order
*/
ms_rpt);
if (rval != HIDPARSER_SUCCESS) {
return (USB_FAILURE);
}
button_page = 0;
for (i = 0; i < ms_rpt->no_of_usages; i++) {
HID_BUTTON_PAGE) && (!button_page)) {
button_page = 1;
continue;
}
case HID_GD_X:
break;
case HID_GD_Y:
break;
case HID_GD_Z:
/*
* z-axis not yet supported, just skip it.
*
* It would be ideal if the HID_GD_Z data would be
* reported as horizontal wheel, and HID_GD_WHEEL
* as vertical wheel.
*
* We can not use the default case, because
* that skips rptcnt*rptsz, but for an
* "Apple Might Mouse" rptsz must be used.
*/
break;
case HID_GD_WHEEL:
break;
default:
break;
}
}
/* get the length of sending data */
/* Check whether X and Y are relative or absolute */
if (rval != HIDPARSER_SUCCESS) {
return (USB_FAILURE);
}
/* For the time being assume that Y also has the same attr */
/* get the logical_maximum for X and Y respectively */
/* the data format can't be parsed correctly */
if (limit % 8) {
"Wrong data packet include %d bits", limit);
return (USB_FAILURE);
}
"fail to get X logical max.");
return (USB_FAILURE);
}
"fail to get Y logical max.");
return (USB_FAILURE);
}
if (usbmsp->usbms_logical_Xmax == 0) {
"X logical max value is zero");
return (USB_FAILURE);
}
if (usbmsp->usbms_logical_Ymax == 0) {
"Y logical max value is zero");
return (USB_FAILURE);
}
/* The wheel is not supported in current remote kvms. */
usbmsp->usbms_num_wheels = 0;
q = usbmsp->usbms_rq_ptr;
} else {
return (USB_NO_RESOURCES);
}
}
return (USB_SUCCESS);
}