2 * $FreeBSD: src/sys/dev/usb/ums.c,v 1.64 2003/11/09 09:17:22 tanimura Exp $
3 * $DragonFly: src/sys/dev/usbmisc/ums/ums.c,v 1.31 2008/08/14 20:55:54 hasso Exp $
7 * Copyright (c) 1998 The NetBSD Foundation, Inc.
10 * This code is derived from software contributed to The NetBSD Foundation
11 * by Lennart Augustsson (lennart@augustsson.net) at
12 * Carlstedt Research & Technology.
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 * 3. All advertising materials mentioning features or use of this software
23 * must display the following acknowledgement:
24 * This product includes software developed by the NetBSD
25 * Foundation, Inc. and its contributors.
26 * 4. Neither the name of The NetBSD Foundation nor the names of its
27 * contributors may be used to endorse or promote products derived
28 * from this software without specific prior written permission.
30 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
31 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
32 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
33 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
34 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
35 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
36 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
37 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
38 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
39 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
40 * POSSIBILITY OF SUCH DAMAGE.
44 * HID spec: http://www.usb.org/developers/data/devclass/hid1_1.pdf
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/kernel.h>
50 #include <sys/malloc.h>
51 #include <sys/module.h>
56 #include <sys/select.h>
57 #include <sys/vnode.h>
59 #include <sys/sysctl.h>
60 #include <sys/thread2.h>
62 #include <bus/usb/usb.h>
63 #include <bus/usb/usbhid.h>
65 #include <bus/usb/usbdi.h>
66 #include <bus/usb/usbdi_util.h>
67 #include <bus/usb/usb_quirks.h>
68 #include <bus/usb/hid.h>
70 #include <machine/mouse.h>
73 #define DPRINTF(x) if (umsdebug) kprintf x
74 #define DPRINTFN(n,x) if (umsdebug>(n)) kprintf x
76 SYSCTL_NODE(_hw_usb
, OID_AUTO
, ums
, CTLFLAG_RW
, 0, "USB ums");
77 SYSCTL_INT(_hw_usb_ums
, OID_AUTO
, debug
, CTLFLAG_RW
,
78 &umsdebug
, 0, "ums debug level");
84 #define UMSUNIT(s) (minor(s)&0x1f)
86 #define MS_TO_TICKS(ms) ((ms) * hz / 1000)
88 #define QUEUE_BUFSIZE 400 /* MUST be divisible by 5 _and_ 8 */
91 device_t sc_dev
; /* base device */
92 usbd_interface_handle sc_iface
; /* interface */
93 usbd_pipe_handle sc_intrpipe
; /* interrupt pipe */
99 struct hid_location sc_loc_x
, sc_loc_y
, sc_loc_z
;
100 struct hid_location
*sc_loc_btn
;
102 struct callout sc_timeout
; /* for spurious button ups */
105 int sc_disconnected
; /* device is gone */
107 int flags
; /* device configuration */
108 #define UMS_Z 0x01 /* z direction available */
109 #define UMS_SPUR_BUT_UP 0x02 /* spurious button up events */
111 #define MAX_BUTTONS 31 /* must not exceed size of sc_buttons */
113 u_char qbuf
[QUEUE_BUFSIZE
]; /* must be divisable by 3&4 */
114 u_char dummy
[100]; /* XXX just for safety and for now */
115 int qcount
, qhead
, qtail
;
118 mousestatus_t status
;
121 # define UMS_ASLEEP 0x01 /* readFromDevice is waiting */
122 # define UMS_SELECT 0x02 /* select is waiting */
123 struct selinfo rsel
; /* process waiting in select */
126 #define MOUSE_FLAGS_MASK (HIO_CONST|HIO_RELATIVE)
127 #define MOUSE_FLAGS (HIO_RELATIVE)
129 static void ums_intr(usbd_xfer_handle xfer
,
130 usbd_private_handle priv
, usbd_status status
);
132 static void ums_add_to_queue(struct ums_softc
*sc
,
133 int dx
, int dy
, int dz
, int buttons
);
134 static void ums_add_to_queue_timeout(void *priv
);
136 static int ums_enable(void *);
137 static void ums_disable(void *);
139 static d_open_t ums_open
;
140 static d_close_t ums_close
;
141 static d_read_t ums_read
;
142 static d_ioctl_t ums_ioctl
;
143 static d_poll_t ums_poll
;
145 #define UMS_CDEV_MAJOR 111
147 static struct dev_ops ums_ops
= {
148 { "ums", UMS_CDEV_MAJOR
, 0 },
150 .d_close
= ums_close
,
152 .d_ioctl
= ums_ioctl
,
156 static device_probe_t ums_match
;
157 static device_attach_t ums_attach
;
158 static device_detach_t ums_detach
;
160 static devclass_t ums_devclass
;
162 static kobj_method_t ums_methods
[] = {
163 DEVMETHOD(device_probe
, ums_match
),
164 DEVMETHOD(device_attach
, ums_attach
),
165 DEVMETHOD(device_detach
, ums_detach
),
169 static driver_t ums_driver
= {
172 sizeof(struct ums_softc
)
175 MODULE_DEPEND(ums
, usb
, 1, 1, 1);
178 ums_match(device_t self
)
180 struct usb_attach_arg
*uaa
= device_get_ivars(self
);
181 usb_interface_descriptor_t
*id
;
187 return (UMATCH_NONE
);
188 id
= usbd_get_interface_descriptor(uaa
->iface
);
189 if (!id
|| id
->bInterfaceClass
!= UICLASS_HID
)
190 return (UMATCH_NONE
);
192 err
= usbd_read_report_desc(uaa
->iface
, &desc
, &size
, M_TEMP
);
194 return (UMATCH_NONE
);
196 if (hid_is_collection(desc
, size
,
197 HID_USAGE2(HUP_GENERIC_DESKTOP
, HUG_MOUSE
)))
198 ret
= UMATCH_IFACECLASS
;
207 ums_attach(device_t self
)
209 struct ums_softc
*sc
= device_get_softc(self
);
210 struct usb_attach_arg
*uaa
= device_get_ivars(self
);
211 usbd_interface_handle iface
= uaa
->iface
;
212 usb_endpoint_descriptor_t
*ed
;
218 struct hid_location loc_btn
;
220 sc
->sc_disconnected
= 1;
221 sc
->sc_iface
= iface
;
223 ed
= usbd_interface2endpoint_descriptor(iface
, 0);
225 kprintf("%s: could not read endpoint descriptor\n",
226 device_get_nameunit(sc
->sc_dev
));
230 DPRINTFN(10,("ums_attach: bLength=%d bDescriptorType=%d "
231 "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d"
233 ed
->bLength
, ed
->bDescriptorType
,
234 UE_GET_ADDR(ed
->bEndpointAddress
),
235 UE_GET_DIR(ed
->bEndpointAddress
) == UE_DIR_IN
? "in":"out",
236 UE_GET_XFERTYPE(ed
->bmAttributes
),
237 UGETW(ed
->wMaxPacketSize
), ed
->bInterval
));
239 if (UE_GET_DIR(ed
->bEndpointAddress
) != UE_DIR_IN
||
240 UE_GET_XFERTYPE(ed
->bmAttributes
) != UE_INTERRUPT
) {
241 kprintf("%s: unexpected endpoint\n",
242 device_get_nameunit(sc
->sc_dev
));
246 err
= usbd_read_report_desc(uaa
->iface
, &desc
, &size
, M_TEMP
);
250 if (!hid_locate(desc
, size
, HID_USAGE2(HUP_GENERIC_DESKTOP
, HUG_X
),
251 hid_input
, &sc
->sc_loc_x
, &flags
)) {
252 kprintf("%s: mouse has no X report\n", device_get_nameunit(sc
->sc_dev
));
255 if ((flags
& MOUSE_FLAGS_MASK
) != MOUSE_FLAGS
) {
256 kprintf("%s: X report 0x%04x not supported\n",
257 device_get_nameunit(sc
->sc_dev
), flags
);
261 if (!hid_locate(desc
, size
, HID_USAGE2(HUP_GENERIC_DESKTOP
, HUG_Y
),
262 hid_input
, &sc
->sc_loc_y
, &flags
)) {
263 kprintf("%s: mouse has no Y report\n", device_get_nameunit(sc
->sc_dev
));
266 if ((flags
& MOUSE_FLAGS_MASK
) != MOUSE_FLAGS
) {
267 kprintf("%s: Y report 0x%04x not supported\n",
268 device_get_nameunit(sc
->sc_dev
), flags
);
272 /* try to guess the Z activator: first check Z, then WHEEL */
273 if (hid_locate(desc
, size
, HID_USAGE2(HUP_GENERIC_DESKTOP
, HUG_Z
),
274 hid_input
, &sc
->sc_loc_z
, &flags
) ||
275 hid_locate(desc
, size
, HID_USAGE2(HUP_GENERIC_DESKTOP
, HUG_WHEEL
),
276 hid_input
, &sc
->sc_loc_z
, &flags
)) {
277 if ((flags
& MOUSE_FLAGS_MASK
) != MOUSE_FLAGS
) {
278 sc
->sc_loc_z
.size
= 0; /* Bad Z coord, ignore it */
284 /* figure out the number of buttons */
285 for (i
= 1; i
<= MAX_BUTTONS
; i
++)
286 if (!hid_locate(desc
, size
, HID_USAGE2(HUP_BUTTON
, i
),
287 hid_input
, &loc_btn
, 0))
289 sc
->nbuttons
= i
- 1;
290 sc
->sc_loc_btn
= kmalloc(sizeof(struct hid_location
)*sc
->nbuttons
,
291 M_USBDEV
, M_INTWAIT
);
293 kprintf("%s: %d buttons%s\n", device_get_nameunit(sc
->sc_dev
),
294 sc
->nbuttons
, sc
->flags
& UMS_Z
? " and Z dir." : "");
296 for (i
= 1; i
<= sc
->nbuttons
; i
++)
297 hid_locate(desc
, size
, HID_USAGE2(HUP_BUTTON
, i
),
298 hid_input
, &sc
->sc_loc_btn
[i
-1], 0);
300 sc
->sc_isize
= hid_report_size(desc
, size
, hid_input
, &sc
->sc_iid
);
301 sc
->sc_ibuf
= kmalloc(sc
->sc_isize
, M_USB
, M_INTWAIT
);
302 sc
->sc_ep_addr
= ed
->bEndpointAddress
;
303 sc
->sc_disconnected
= 0;
307 DPRINTF(("ums_attach: sc=%p\n", sc
));
308 DPRINTF(("ums_attach: X\t%d/%d\n",
309 sc
->sc_loc_x
.pos
, sc
->sc_loc_x
.size
));
310 DPRINTF(("ums_attach: Y\t%d/%d\n",
311 sc
->sc_loc_y
.pos
, sc
->sc_loc_y
.size
));
312 if (sc
->flags
& UMS_Z
)
313 DPRINTF(("ums_attach: Z\t%d/%d\n",
314 sc
->sc_loc_z
.pos
, sc
->sc_loc_z
.size
));
315 for (i
= 1; i
<= sc
->nbuttons
; i
++) {
316 DPRINTF(("ums_attach: B%d\t%d/%d\n",
317 i
, sc
->sc_loc_btn
[i
-1].pos
,sc
->sc_loc_btn
[i
-1].size
));
319 DPRINTF(("ums_attach: size=%d, id=%d\n", sc
->sc_isize
, sc
->sc_iid
));
322 if (sc
->nbuttons
> MOUSE_MSC_MAXBUTTON
)
323 sc
->hw
.buttons
= MOUSE_MSC_MAXBUTTON
;
325 sc
->hw
.buttons
= sc
->nbuttons
;
326 sc
->hw
.iftype
= MOUSE_IF_USB
;
327 sc
->hw
.type
= MOUSE_MOUSE
;
328 sc
->hw
.model
= MOUSE_MODEL_GENERIC
;
330 sc
->mode
.protocol
= MOUSE_PROTO_MSC
;
332 sc
->mode
.resolution
= MOUSE_RES_UNKNOWN
;
333 sc
->mode
.accelfactor
= 0;
335 sc
->mode
.packetsize
= MOUSE_MSC_PACKETSIZE
;
336 sc
->mode
.syncmask
[0] = MOUSE_MSC_SYNCMASK
;
337 sc
->mode
.syncmask
[1] = MOUSE_MSC_SYNC
;
339 sc
->status
.flags
= 0;
340 sc
->status
.button
= sc
->status
.obutton
= 0;
341 sc
->status
.dx
= sc
->status
.dy
= sc
->status
.dz
= 0;
343 make_dev(&ums_ops
, device_get_unit(self
),
344 UID_ROOT
, GID_OPERATOR
,
345 0644, "ums%d", device_get_unit(self
));
347 if (usbd_get_quirks(uaa
->device
)->uq_flags
& UQ_SPUR_BUT_UP
) {
348 DPRINTF(("%s: Spurious button up events\n",
349 device_get_nameunit(sc
->sc_dev
)));
350 sc
->flags
|= UMS_SPUR_BUT_UP
;
358 ums_detach(device_t self
)
360 struct ums_softc
*sc
= device_get_softc(self
);
365 DPRINTF(("%s: disconnected\n", device_get_nameunit(self
)));
367 kfree(sc
->sc_loc_btn
, M_USB
);
368 kfree(sc
->sc_ibuf
, M_USB
);
370 /* someone waiting for data */
372 * XXX If we wakeup the process here, the device will be gone by
373 * the time the process gets a chance to notice. *_close and friends
374 * should be fixed to handle this case.
375 * Or we should do a delayed detach for this.
376 * Does this delay now force tsleep to exit with an error?
378 if (sc
->state
& UMS_ASLEEP
) {
379 sc
->state
&= ~UMS_ASLEEP
;
382 if (sc
->state
& UMS_SELECT
) {
383 sc
->state
&= ~UMS_SELECT
;
384 selwakeup(&sc
->rsel
);
386 dev_ops_remove_minor(&ums_ops
, /*-1, */device_get_unit(self
));
392 ums_intr(usbd_xfer_handle xfer
, usbd_private_handle addr
,
395 struct ums_softc
*sc
= addr
;
401 #define UMS_BUT(i) ((i) < 3 ? (((i) + 2) % 3) : (i))
403 DPRINTFN(5, ("ums_intr: sc=%p status=%d\n", sc
, status
));
404 DPRINTFN(5, ("ums_intr: data = %02x %02x %02x\n",
405 sc
->sc_ibuf
[0], sc
->sc_ibuf
[1], sc
->sc_ibuf
[2]));
407 if (status
== USBD_CANCELLED
)
410 if (status
!= USBD_NORMAL_COMPLETION
) {
411 DPRINTF(("ums_intr: status=%d\n", status
));
412 if (status
== USBD_STALLED
)
413 usbd_clear_endpoint_stall_async(sc
->sc_intrpipe
);
419 if (*ibuf
++ != sc
->sc_iid
)
423 dx
= hid_get_data(ibuf
, &sc
->sc_loc_x
);
424 dy
= -hid_get_data(ibuf
, &sc
->sc_loc_y
);
425 dz
= -hid_get_data(ibuf
, &sc
->sc_loc_z
);
426 for (i
= 0; i
< sc
->nbuttons
; i
++)
427 if (hid_get_data(ibuf
, &sc
->sc_loc_btn
[i
]))
428 buttons
|= (1 << UMS_BUT(i
));
430 if (dx
|| dy
|| dz
|| (sc
->flags
& UMS_Z
)
431 || buttons
!= sc
->status
.button
) {
432 DPRINTFN(5, ("ums_intr: x:%d y:%d z:%d buttons:0x%x\n",
433 dx
, dy
, dz
, buttons
));
435 sc
->status
.button
= buttons
;
440 /* Discard data in case of full buffer */
441 if (sc
->qcount
== sizeof(sc
->qbuf
)) {
442 DPRINTF(("Buffer full, discarded packet"));
447 * The Qtronix keyboard has a built in PS/2 port for a mouse.
448 * The firmware once in a while posts a spurious button up
449 * event. This event we ignore by doing a timeout for 50 msecs.
450 * If we receive dx=dy=dz=buttons=0 before we add the event to
452 * In any other case we delete the timeout event.
454 if (sc
->flags
& UMS_SPUR_BUT_UP
&&
455 dx
== 0 && dy
== 0 && dz
== 0 && buttons
== 0) {
456 callout_reset(&sc
->sc_timeout
, MS_TO_TICKS(50),
457 ums_add_to_queue_timeout
, (void *) sc
);
459 callout_stop(&sc
->sc_timeout
);
460 ums_add_to_queue(sc
, dx
, dy
, dz
, buttons
);
466 ums_add_to_queue_timeout(void *priv
)
468 struct ums_softc
*sc
= priv
;
471 ums_add_to_queue(sc
, 0, 0, 0, 0);
476 ums_add_to_queue(struct ums_softc
*sc
, int dx
, int dy
, int dz
, int buttons
)
478 /* Discard data in case of full buffer */
479 if (sc
->qhead
+sc
->mode
.packetsize
> sizeof(sc
->qbuf
)) {
480 DPRINTF(("Buffer full, discarded packet"));
484 if (dx
> 254) dx
= 254;
485 if (dx
< -256) dx
= -256;
486 if (dy
> 254) dy
= 254;
487 if (dy
< -256) dy
= -256;
488 if (dz
> 126) dz
= 126;
489 if (dz
< -128) dz
= -128;
491 sc
->qbuf
[sc
->qhead
] = sc
->mode
.syncmask
[1];
492 sc
->qbuf
[sc
->qhead
] |= ~buttons
& MOUSE_MSC_BUTTONS
;
493 sc
->qbuf
[sc
->qhead
+1] = dx
>> 1;
494 sc
->qbuf
[sc
->qhead
+2] = dy
>> 1;
495 sc
->qbuf
[sc
->qhead
+3] = dx
- (dx
>> 1);
496 sc
->qbuf
[sc
->qhead
+4] = dy
- (dy
>> 1);
498 if (sc
->mode
.level
== 1) {
499 sc
->qbuf
[sc
->qhead
+5] = dz
>> 1;
500 sc
->qbuf
[sc
->qhead
+6] = dz
- (dz
>> 1);
501 sc
->qbuf
[sc
->qhead
+7] = ((~buttons
>> 3)
502 & MOUSE_SYS_EXTBUTTONS
);
505 sc
->qhead
+= sc
->mode
.packetsize
;
506 sc
->qcount
+= sc
->mode
.packetsize
;
507 /* wrap round at end of buffer */
508 if (sc
->qhead
>= sizeof(sc
->qbuf
))
511 /* someone waiting for data */
512 if (sc
->state
& UMS_ASLEEP
) {
513 sc
->state
&= ~UMS_ASLEEP
;
516 if (sc
->state
& UMS_SELECT
) {
517 sc
->state
&= ~UMS_SELECT
;
518 selwakeup(&sc
->rsel
);
525 struct ums_softc
*sc
= v
;
534 sc
->qhead
= sc
->qtail
= 0;
535 sc
->status
.flags
= 0;
536 sc
->status
.button
= sc
->status
.obutton
= 0;
537 sc
->status
.dx
= sc
->status
.dy
= sc
->status
.dz
= 0;
539 callout_init(&sc
->sc_timeout
);
541 /* Set up interrupt pipe. */
542 err
= usbd_open_pipe_intr(sc
->sc_iface
, sc
->sc_ep_addr
,
543 USBD_SHORT_XFER_OK
, &sc
->sc_intrpipe
, sc
,
544 sc
->sc_ibuf
, sc
->sc_isize
, ums_intr
,
545 USBD_DEFAULT_INTERVAL
);
547 DPRINTF(("ums_enable: usbd_open_pipe_intr failed, error=%d\n",
556 ums_disable(void *priv
)
558 struct ums_softc
*sc
= priv
;
560 callout_stop(&sc
->sc_timeout
);
562 /* Disable interrupts. */
563 usbd_abort_pipe(sc
->sc_intrpipe
);
564 usbd_close_pipe(sc
->sc_intrpipe
);
569 DPRINTF(("Discarded %d bytes in queue\n", sc
->qcount
));
573 ums_open(struct dev_open_args
*ap
)
575 cdev_t dev
= ap
->a_head
.a_dev
;
576 struct ums_softc
*sc
;
578 sc
= devclass_get_softc(ums_devclass
, UMSUNIT(dev
));
582 return ums_enable(sc
);
586 ums_close(struct dev_close_args
*ap
)
588 cdev_t dev
= ap
->a_head
.a_dev
;
589 struct ums_softc
*sc
;
591 sc
= devclass_get_softc(ums_devclass
, UMSUNIT(dev
));
603 ums_read(struct dev_read_args
*ap
)
605 cdev_t dev
= ap
->a_head
.a_dev
;
606 struct uio
*uio
= ap
->a_uio
;
607 struct ums_softc
*sc
;
608 char buf
[sizeof(sc
->qbuf
)];
612 sc
= devclass_get_softc(ums_devclass
, UMSUNIT(dev
));
620 while (sc
->qcount
== 0 ) {
621 if (ap
->a_ioflag
& IO_NDELAY
) { /* non-blocking I/O */
626 sc
->state
|= UMS_ASLEEP
; /* blocking I/O */
627 error
= tsleep(sc
, PCATCH
, "umsrea", 0);
631 } else if (!sc
->sc_enabled
) {
635 /* check whether the device is still there */
637 sc
= devclass_get_softc(ums_devclass
, UMSUNIT(dev
));
645 * The writer process only extends qcount and qtail. We could copy
646 * them and use the copies to do the copying out of the queue.
649 while ((sc
->qcount
> 0) && (uio
->uio_resid
> 0)) {
650 l
= (sc
->qcount
< uio
->uio_resid
? sc
->qcount
:uio
->uio_resid
);
653 if (l
> sizeof(sc
->qbuf
) - sc
->qtail
) /* transfer till end of buf */
654 l
= sizeof(sc
->qbuf
) - sc
->qtail
;
657 uiomove(&sc
->qbuf
[sc
->qtail
], l
, uio
);
660 if ( sc
->qcount
- l
< 0 ) {
661 DPRINTF(("qcount below 0, count=%d l=%d\n", sc
->qcount
, l
));
664 sc
->qcount
-= l
; /* remove the bytes from the buffer */
665 sc
->qtail
= (sc
->qtail
+ l
) % sizeof(sc
->qbuf
);
673 ums_poll(struct dev_poll_args
*ap
)
675 cdev_t dev
= ap
->a_head
.a_dev
;
676 struct ums_softc
*sc
;
679 sc
= devclass_get_softc(ums_devclass
, UMSUNIT(dev
));
687 if (ap
->a_events
& (POLLIN
| POLLRDNORM
)) {
689 revents
= ap
->a_events
& (POLLIN
| POLLRDNORM
);
691 sc
->state
|= UMS_SELECT
;
692 selrecord(curthread
, &sc
->rsel
);
696 ap
->a_events
= revents
;
701 ums_ioctl(struct dev_ioctl_args
*ap
)
703 cdev_t dev
= ap
->a_head
.a_dev
;
704 struct ums_softc
*sc
;
708 sc
= devclass_get_softc(ums_devclass
, UMSUNIT(dev
));
714 case MOUSE_GETHWINFO
:
715 *(mousehw_t
*)ap
->a_data
= sc
->hw
;
718 *(mousemode_t
*)ap
->a_data
= sc
->mode
;
721 mode
= *(mousemode_t
*)ap
->a_data
;
723 if (mode
.level
== -1)
724 /* don't change the current setting */
726 else if ((mode
.level
< 0) || (mode
.level
> 1))
730 sc
->mode
.level
= mode
.level
;
732 if (sc
->mode
.level
== 0) {
733 if (sc
->nbuttons
> MOUSE_MSC_MAXBUTTON
)
734 sc
->hw
.buttons
= MOUSE_MSC_MAXBUTTON
;
736 sc
->hw
.buttons
= sc
->nbuttons
;
737 sc
->mode
.protocol
= MOUSE_PROTO_MSC
;
738 sc
->mode
.packetsize
= MOUSE_MSC_PACKETSIZE
;
739 sc
->mode
.syncmask
[0] = MOUSE_MSC_SYNCMASK
;
740 sc
->mode
.syncmask
[1] = MOUSE_MSC_SYNC
;
741 } else if (sc
->mode
.level
== 1) {
742 if (sc
->nbuttons
> MOUSE_SYS_MAXBUTTON
)
743 sc
->hw
.buttons
= MOUSE_SYS_MAXBUTTON
;
745 sc
->hw
.buttons
= sc
->nbuttons
;
746 sc
->mode
.protocol
= MOUSE_PROTO_SYSMOUSE
;
747 sc
->mode
.packetsize
= MOUSE_SYS_PACKETSIZE
;
748 sc
->mode
.syncmask
[0] = MOUSE_SYS_SYNCMASK
;
749 sc
->mode
.syncmask
[1] = MOUSE_SYS_SYNC
;
752 bzero(sc
->qbuf
, sizeof(sc
->qbuf
));
753 sc
->qhead
= sc
->qtail
= sc
->qcount
= 0;
758 *(int *)ap
->a_data
= sc
->mode
.level
;
761 if (*(int *)ap
->a_data
< 0 || *(int *)ap
->a_data
> 1)
765 sc
->mode
.level
= *(int *)ap
->a_data
;
767 if (sc
->mode
.level
== 0) {
768 if (sc
->nbuttons
> MOUSE_MSC_MAXBUTTON
)
769 sc
->hw
.buttons
= MOUSE_MSC_MAXBUTTON
;
771 sc
->hw
.buttons
= sc
->nbuttons
;
772 sc
->mode
.protocol
= MOUSE_PROTO_MSC
;
773 sc
->mode
.packetsize
= MOUSE_MSC_PACKETSIZE
;
774 sc
->mode
.syncmask
[0] = MOUSE_MSC_SYNCMASK
;
775 sc
->mode
.syncmask
[1] = MOUSE_MSC_SYNC
;
776 } else if (sc
->mode
.level
== 1) {
777 if (sc
->nbuttons
> MOUSE_SYS_MAXBUTTON
)
778 sc
->hw
.buttons
= MOUSE_SYS_MAXBUTTON
;
780 sc
->hw
.buttons
= sc
->nbuttons
;
781 sc
->mode
.protocol
= MOUSE_PROTO_SYSMOUSE
;
782 sc
->mode
.packetsize
= MOUSE_SYS_PACKETSIZE
;
783 sc
->mode
.syncmask
[0] = MOUSE_SYS_SYNCMASK
;
784 sc
->mode
.syncmask
[1] = MOUSE_SYS_SYNC
;
787 bzero(sc
->qbuf
, sizeof(sc
->qbuf
));
788 sc
->qhead
= sc
->qtail
= sc
->qcount
= 0;
792 case MOUSE_GETSTATUS
: {
793 mousestatus_t
*status
= (mousestatus_t
*) ap
->a_data
;
796 *status
= sc
->status
;
797 sc
->status
.obutton
= sc
->status
.button
;
798 sc
->status
.button
= 0;
799 sc
->status
.dx
= sc
->status
.dy
= sc
->status
.dz
= 0;
802 if (status
->dx
|| status
->dy
|| status
->dz
)
803 status
->flags
|= MOUSE_POSCHANGED
;
804 if (status
->button
!= status
->obutton
)
805 status
->flags
|= MOUSE_BUTTONSCHANGED
;
815 DRIVER_MODULE(ums
, uhub
, ums_driver
, ums_devclass
, usbd_driver_load
, 0);