ums.c revision 1.17 1 /* $NetBSD: ums.c,v 1.17 1998/12/30 13:14:21 augustss Exp $ */
2
3 /*
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson (augustss (at) carlstedt.se) at
9 * Carlstedt Research & Technology.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/malloc.h>
44 #if defined(__NetBSD__)
45 #include <sys/device.h>
46 #include <sys/ioctl.h>
47 #elif defined(__FreeBSD__)
48 #include <sys/module.h>
49 #include <sys/bus.h>
50 #include <sys/ioccom.h>
51 #include <sys/conf.h>
52 #endif
53 #include <sys/tty.h>
54 #include <sys/file.h>
55 #include <sys/select.h>
56 #include <sys/proc.h>
57 #include <sys/vnode.h>
58 #include <sys/poll.h>
59
60 #include <dev/usb/usb.h>
61 #include <dev/usb/usbhid.h>
62
63 #include <dev/usb/usbdi.h>
64 #include <dev/usb/usbdivar.h>
65 #include <dev/usb/usbdi_util.h>
66 #include <dev/usb/usbdevs.h>
67 #include <dev/usb/usb_quirks.h>
68 #include <dev/usb/hid.h>
69
70 #if defined(__NetBSD__)
71 #include <dev/wscons/wsconsio.h>
72 #include <dev/wscons/wsmousevar.h>
73 #elif defined(__FreeBSD__)
74 #include <machine/mouse.h>
75 #endif
76
77 #ifdef USB_DEBUG
78 #define DPRINTF(x) if (umsdebug) printf x
79 #define DPRINTFN(n,x) if (umsdebug>(n)) printf x
80 int umsdebug = 0;
81 #else
82 #define DPRINTF(x)
83 #define DPRINTFN(n,x)
84 #endif
85
86 #define UMSUNIT(s) (minor(s)&0x1f)
87
88 #define PS2LBUTMASK x01
89 #define PS2RBUTMASK x02
90 #define PS2MBUTMASK x04
91 #define PS2BUTMASK 0x0f
92
93 #define QUEUE_BUFSIZE 240 /* MUST be divisible by 3 _and_ 4 */
94
95 struct ums_softc {
96 bdevice sc_dev; /* base device */
97 usbd_interface_handle sc_iface; /* interface */
98 usbd_pipe_handle sc_intrpipe; /* interrupt pipe */
99 int sc_ep_addr;
100
101 u_char *sc_ibuf;
102 u_int8_t sc_iid;
103 int sc_isize;
104 struct hid_location sc_loc_x, sc_loc_y, sc_loc_z;
105 struct hid_location *sc_loc_btn;
106
107 int sc_enabled;
108 int sc_disconnected; /* device is gone */
109
110 int flags; /* device configuration */
111 #define UMS_Z 0x01 /* z direction available */
112 int nbuttons;
113
114 #if defined(__NetBSD__)
115 u_char sc_buttons; /* mouse button status */
116 struct device *sc_wsmousedev;
117 #elif defined(__FreeBSD__)
118 u_char qbuf[QUEUE_BUFSIZE];
119 u_char dummy[100]; /* just for safety and for now */
120 int qcount, qhead, qtail;
121 mousehw_t hw;
122 mousemode_t mode;
123 mousestatus_t status;
124
125 int state;
126 # define UMS_ASLEEP 0x01 /* readFromDevice is waiting */
127 # define UMS_SELECT 0x02 /* select is waiting */
128 struct selinfo rsel; /* process waiting in select */
129 #endif
130 };
131
132 #define MOUSE_FLAGS_MASK (HIO_CONST|HIO_RELATIVE)
133 #define MOUSE_FLAGS (HIO_RELATIVE)
134
135 void ums_intr __P((usbd_request_handle, usbd_private_handle, usbd_status));
136 void ums_disco __P((void *));
137
138 static int ums_enable __P((void *));
139 static void ums_disable __P((void *));
140
141 #if defined(__NetBSD__)
142 static int ums_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
143
144 const struct wsmouse_accessops ums_accessops = {
145 ums_enable,
146 ums_ioctl,
147 ums_disable,
148 };
149
150 #elif defined(__FreeBSD__)
151 static d_open_t ums_open;
152 static d_close_t ums_close;
153 static d_read_t ums_read;
154 static d_ioctl_t ums_ioctl;
155 static d_poll_t ums_poll;
156
157 #define UMS_CDEV_MAJOR 138 /* XXX NWH should be requested */
158
159 static struct cdevsw ums_cdevsw = {
160 ums_open, ums_close, ums_read, nowrite,
161 ums_ioctl, nostop, nullreset, nodevtotty,
162 ums_poll, nommap,
163 NULL, "ums_", NULL, -1
164 };
165 #endif
166
167 USB_DECLARE_DRIVER(ums);
168
169 USB_MATCH(ums)
170 {
171 USB_MATCH_START(ums, uaa);
172 usb_interface_descriptor_t *id;
173 int size, ret;
174 void *desc;
175 usbd_status r;
176
177 if (!uaa->iface)
178 return (UMATCH_NONE);
179 id = usbd_get_interface_descriptor(uaa->iface);
180 if (!id || id->bInterfaceClass != UCLASS_HID)
181 return (UMATCH_NONE);
182
183 r = usbd_alloc_report_desc(uaa->iface, &desc, &size, M_TEMP);
184 if (r != USBD_NORMAL_COMPLETION)
185 return (UMATCH_NONE);
186
187 if (hid_is_collection(desc, size,
188 HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE)))
189 ret = UMATCH_IFACECLASS;
190 else
191 ret = UMATCH_NONE;
192
193 free(desc, M_TEMP);
194 return (ret);
195 }
196
197 USB_ATTACH(ums)
198 {
199 USB_ATTACH_START(ums, sc, uaa);
200 usbd_interface_handle iface = uaa->iface;
201 usb_interface_descriptor_t *id;
202 usb_endpoint_descriptor_t *ed;
203 struct wsmousedev_attach_args a;
204 int size;
205 void *desc;
206 usbd_status r;
207 char devinfo[1024];
208 u_int32_t flags;
209 int i;
210 struct hid_location loc_btn;
211
212 sc->sc_disconnected = 1;
213 sc->sc_iface = iface;
214 id = usbd_get_interface_descriptor(iface);
215 usbd_devinfo(uaa->device, 0, devinfo);
216 USB_ATTACH_SETUP;
217 printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev),
218 devinfo, id->bInterfaceClass, id->bInterfaceSubClass);
219 ed = usbd_interface2endpoint_descriptor(iface, 0);
220 if (!ed) {
221 printf("%s: could not read endpoint descriptor\n",
222 USBDEVNAME(sc->sc_dev));
223 USB_ATTACH_ERROR_RETURN;
224 }
225
226 DPRINTFN(10,("ums_attach: bLength=%d bDescriptorType=%d "
227 "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d"
228 " bInterval=%d\n",
229 ed->bLength, ed->bDescriptorType,
230 ed->bEndpointAddress & UE_ADDR,
231 ed->bEndpointAddress & UE_IN ? "in" : "out",
232 ed->bmAttributes & UE_XFERTYPE,
233 UGETW(ed->wMaxPacketSize), ed->bInterval));
234
235 if ((ed->bEndpointAddress & UE_IN) != UE_IN ||
236 (ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) {
237 printf("%s: unexpected endpoint\n",
238 USBDEVNAME(sc->sc_dev));
239 USB_ATTACH_ERROR_RETURN;
240 }
241
242 r = usbd_alloc_report_desc(uaa->iface, &desc, &size, M_TEMP);
243 if (r != USBD_NORMAL_COMPLETION)
244 USB_ATTACH_ERROR_RETURN;
245
246 if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X),
247 hid_input, &sc->sc_loc_x, &flags)) {
248 printf("%s: mouse has no X report\n", USBDEVNAME(sc->sc_dev));
249 USB_ATTACH_ERROR_RETURN;
250 }
251 if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) {
252 printf("%s: X report 0x%04x not supported\n",
253 USBDEVNAME(sc->sc_dev), flags);
254 USB_ATTACH_ERROR_RETURN;
255 }
256
257 if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y),
258 hid_input, &sc->sc_loc_y, &flags)) {
259 printf("%s: mouse has no Y report\n", USBDEVNAME(sc->sc_dev));
260 USB_ATTACH_ERROR_RETURN;
261 }
262 if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) {
263 printf("%s: Y report 0x%04x not supported\n",
264 USBDEVNAME(sc->sc_dev), flags);
265 USB_ATTACH_ERROR_RETURN;
266 }
267
268 /* try to guess the Z activator: first check Z, then WHEEL */
269 if (hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z),
270 hid_input, &sc->sc_loc_z, &flags) ||
271 hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_WHEEL),
272 hid_input, &sc->sc_loc_z, &flags)) {
273 if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) {
274 sc->sc_loc_z.size = 0; /* Bad Z coord, ignore it */
275 } else {
276 sc->flags |= UMS_Z;
277 }
278 }
279
280 /* figure out the number of buttons, 7 is an arbitrary limit */
281 for (i = 1; i <= 7; i++)
282 if (!hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i),
283 hid_input, &loc_btn, 0))
284 break;
285 sc->nbuttons = i - 1;
286 sc->sc_loc_btn = malloc(sizeof(struct hid_location)*sc->nbuttons,
287 M_USBDEV, M_NOWAIT);
288 if (!sc->sc_loc_btn)
289 USB_ATTACH_ERROR_RETURN;
290
291 printf("%s: %d buttons%s\n", USBDEVNAME(sc->sc_dev),
292 sc->nbuttons, (sc->flags & UMS_Z? " and Z dir." : ""));
293
294 for (i = 1; i <= sc->nbuttons; i++)
295 hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i),
296 hid_input, &sc->sc_loc_btn[i-1], 0);
297
298 sc->sc_isize = hid_report_size(desc, size, hid_input, &sc->sc_iid);
299 sc->sc_ibuf = malloc(sc->sc_isize, M_USB, M_NOWAIT);
300 if (!sc->sc_ibuf) {
301 free(sc->sc_loc_btn, M_USB);
302 USB_ATTACH_ERROR_RETURN;
303 }
304
305 sc->sc_ep_addr = ed->bEndpointAddress;
306 sc->sc_disconnected = 0;
307 free(desc, M_TEMP);
308
309 #ifdef USB_DEBUG
310 DPRINTF(("ums_attach: sc=%p\n", sc));
311 DPRINTF(("ums_attach: X\t%d/%d\n",
312 sc->sc_loc_x.pos, sc->sc_loc_x.size));
313 DPRINTF(("ums_attach: Y\t%d/%d\n",
314 sc->sc_loc_x.pos, sc->sc_loc_x.size));
315 if (sc->flags & UMS_Z)
316 DPRINTF(("ums_attach: Z\t%d/%d\n",
317 sc->sc_loc_z.pos, sc->sc_loc_z.size));
318 for (i = 1; i <= sc->nbuttons; i++) {
319 DPRINTF(("ums_attach: B%d\t%d/%d\n",
320 i, sc->sc_loc_btn[i-1].pos,sc->sc_loc_btn[i-1].size));
321 }
322 DPRINTF(("ums_attach: size=%d, id=%d\n", sc->sc_isize, sc->sc_iid));
323 #endif
324
325 #if defined(__NetBSD__)
326 a.accessops = &ums_accessops;
327 a.accesscookie = sc;
328
329 sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
330 #elif defined(__FreeBSD__)
331 sc->hw.buttons = 2; /* XXX hw&mode values are bogus */
332 sc->hw.iftype = MOUSE_IF_PS2;
333 sc->hw.type = MOUSE_MOUSE;
334 if (sc->flags & UMS_Z)
335 sc->hw.model = MOUSE_MODEL_INTELLI;
336 else
337 sc->hw.model = MOUSE_MODEL_GENERIC;
338 sc->hw.hwid = 0;
339 sc->mode.protocol = MOUSE_PROTO_PS2;
340 sc->mode.rate = -1;
341 sc->mode.resolution = MOUSE_RES_DEFAULT;
342 sc->mode.accelfactor = 1;
343 sc->mode.level = 0;
344 if (sc->flags & UMS_Z) {
345 sc->mode.packetsize = MOUSE_INTELLI_PACKETSIZE;
346 sc->mode.syncmask[0] = 0xc8;
347 } else {
348 sc->mode.packetsize = MOUSE_PS2_PACKETSIZE;
349 sc->mode.syncmask[0] = 0xc0;
350 }
351 sc->mode.syncmask[1] = 0;
352
353 sc->status.flags = 0;
354 sc->status.button = sc->status.obutton = 0;
355 sc->status.dx = sc->status.dy = sc->status.dz = 0;
356
357 sc->rsel.si_flags = 0;
358 sc->rsel.si_pid = 0;
359 #endif
360
361 USB_ATTACH_SUCCESS_RETURN;
362 }
363
364
365 #if defined(__FreeBSD__)
366 static int
367 ums_detach(device_t self)
368 {
369 struct ums_softc *sc = device_get_softc(self);
370 char *devinfo = (char *) device_get_desc(self);
371
372 if (devinfo) {
373 device_set_desc(self, NULL);
374 free(devinfo, M_USB);
375 }
376 free(sc->sc_loc_btn, M_USB);
377 free(sc->sc_ibuf, M_USB);
378
379 return 0;
380 }
381 #endif
382
383 void
384 ums_disco(p)
385 void *p;
386 {
387 struct ums_softc *sc = p;
388
389 DPRINTF(("ums_disco: sc=%p\n", sc));
390 usbd_abort_pipe(sc->sc_intrpipe);
391 sc->sc_disconnected = 1;
392 }
393
394 void
395 ums_intr(reqh, addr, status)
396 usbd_request_handle reqh;
397 usbd_private_handle addr;
398 usbd_status status;
399 {
400 struct ums_softc *sc = addr;
401 u_char *ibuf;
402 int dx, dy, dz;
403 u_char buttons = 0;
404 int i;
405 #if defined(__NetBSD__)
406 #define UMS_BUT(i) ((i) == 1 || (i) == 2 ? 3 - (i) : i)
407 #elif defined(__FreeBSD__)
408 #define UMS_BUT(i) (i)
409 #endif
410
411 DPRINTFN(5, ("ums_intr: sc=%p status=%d\n", sc, status));
412 DPRINTFN(5, ("ums_intr: data = %02x %02x %02x\n",
413 sc->sc_ibuf[0], sc->sc_ibuf[1], sc->sc_ibuf[2]));
414
415 if (status == USBD_CANCELLED)
416 return;
417
418 if (status != USBD_NORMAL_COMPLETION) {
419 DPRINTF(("ums_intr: status=%d\n", status));
420 usbd_clear_endpoint_stall_async(sc->sc_intrpipe);
421 return;
422 }
423
424 ibuf = sc->sc_ibuf;
425 if (sc->sc_iid) {
426 if (*ibuf++ != sc->sc_iid)
427 return;
428 }
429 dx = hid_get_data(ibuf, &sc->sc_loc_x);
430 dy = -hid_get_data(ibuf, &sc->sc_loc_y);
431 dz = hid_get_data(ibuf, &sc->sc_loc_z);
432 /* NWH Why are you modifying the button assignments here?
433 * That's the purpose of a high level mouse driver
434 */
435 for (i = 0; i < sc->nbuttons; i++)
436 if (hid_get_data(ibuf, &sc->sc_loc_btn[i]))
437 buttons |= (1 << UMS_BUT(i));
438
439 #if defined(__NetBSD__)
440 if (dx || dy || buttons != sc->sc_buttons) {
441 DPRINTFN(10, ("ums_intr: x:%d y:%d z:%d buttons:0x%x\n",
442 dx, dy, dz, buttons));
443 sc->sc_buttons = buttons;
444 if (sc->sc_wsmousedev)
445 wsmouse_input(sc->sc_wsmousedev, buttons, dx, dy, dz);
446 #elif defined(__FreeBSD__)
447 if (dx || dy || buttons != sc->status.button) {
448 DPRINTFN(10, ("ums_intr: x:%d y:%d z:%d buttons:0x%x\n",
449 dx, dy, dz, buttons));
450
451 sc->status.button = buttons;
452 sc->status.dx += dx;
453 sc->status.dy += dy;
454 sc->status.dz += dz;
455
456 /* Discard data in case of full buffer */
457 if (sc->qcount == sizeof(sc->qbuf)) {
458 DPRINTF(("Buffer full, discarded packet"));
459 return;
460 }
461
462 sc->qbuf[sc->qhead] = MOUSE_PS2_SYNC;
463 if (dx < 0)
464 sc->qbuf[sc->qhead] |= MOUSE_PS2_XNEG;
465 if (dx > 255 || dx < -255)
466 sc->qbuf[sc->qhead] |= MOUSE_PS2_XOVERFLOW;
467 if (dy < 0)
468 sc->qbuf[sc->qhead] |= MOUSE_PS2_YNEG;
469 if (dy > 255 || dy < -255)
470 sc->qbuf[sc->qhead] |= MOUSE_PS2_YOVERFLOW;
471 sc->qbuf[sc->qhead++] |= buttons;
472 sc->qbuf[sc->qhead++] = dx;
473 sc->qbuf[sc->qhead++] = dy;
474 sc->qcount += 3;
475 if (sc->flags & UMS_Z) {
476 sc->qbuf[sc->qhead++] = dz;
477 sc->qcount++;
478 }
479 #ifdef USB_DEBUG
480 if (sc->qhead > sizeof(sc->qbuf))
481 DPRINTF(("Buffer overrun! %d %d\n",
482 sc->qhead, sizeof(sc->qbuf)));
483 #endif
484 /* wrap round at end of buffer */
485 if (sc->qhead >= sizeof(sc->qbuf))
486 sc->qhead = 0;
487
488 /* someone waiting for data */
489 if (sc->state & UMS_ASLEEP)
490 wakeup(sc);
491 /* wake up any pending selects */
492 selwakeup(&sc->rsel);
493 sc->state &= ~UMS_SELECT;
494 #endif
495 }
496 }
497
498
499 static int
500 ums_enable(v)
501 void *v;
502 {
503 struct ums_softc *sc = v;
504
505 usbd_status r;
506
507 if (sc->sc_enabled)
508 return EBUSY;
509
510 sc->sc_enabled = 1;
511 #if defined(__NetBSD__)
512 sc->sc_buttons = 0;
513 #elif defined(__FreeBSD__)
514 sc->qcount = 0;
515 sc->qhead = sc->qtail = 0;
516 #ifdef USB_DEBUG
517 if (sizeof(sc->qbuf) % 4 || sizeof(sc->qbuf) % 3) {
518 DPRINTF(("Buffer size not divisible by 3 or 4\n"));
519 return ENXIO;
520 }
521 #endif
522 sc->status.flags = 0;
523 sc->status.button = sc->status.obutton = 0;
524 sc->status.dx = sc->status.dy = sc->status.dz = 0;
525 #endif
526
527 /* Set up interrupt pipe. */
528 r = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ep_addr,
529 USBD_SHORT_XFER_OK, &sc->sc_intrpipe, sc,
530 sc->sc_ibuf, sc->sc_isize, ums_intr);
531 if (r != USBD_NORMAL_COMPLETION) {
532 DPRINTF(("ums_enable: usbd_open_pipe_intr failed, error=%d\n",
533 r));
534 sc->sc_enabled = 0;
535 return (EIO);
536 }
537 usbd_set_disco(sc->sc_intrpipe, ums_disco, sc);
538 return (0);
539 }
540
541 static void
542 ums_disable(v)
543 void *v;
544 {
545 struct ums_softc *sc = v;
546
547 /* Disable interrupts. */
548 usbd_abort_pipe(sc->sc_intrpipe);
549 usbd_close_pipe(sc->sc_intrpipe);
550
551 sc->sc_enabled = 0;
552
553 #if defined(USBVERBOSE) && defined(__FreeBSD__)
554 if (sc->qcount != 0)
555 DPRINTF(("Discarded %d bytes in queue\n", sc->qcount));
556 #endif
557 }
558
559 #if defined(__NetBSD__)
560 static int
561 ums_ioctl(v, cmd, data, flag, p)
562 void *v;
563 u_long cmd;
564 caddr_t data;
565 int flag;
566 struct proc *p;
567
568 {
569 switch (cmd) {
570 case WSMOUSEIO_GTYPE:
571 *(u_int *)data = WSMOUSE_TYPE_USB;
572 return (0);
573 }
574
575 return (-1);
576 }
577
578 #elif defined(__FreeBSD__)
579 static int
580 ums_open(dev_t dev, int flag, int fmt, struct proc *p)
581 {
582 struct ums_softc *sc = devclass_get_softc(ums_devclass, UMSUNIT(dev));
583
584 if (!sc) {
585 DPRINTF(("sc not found at open"));
586 return EINVAL;
587 }
588
589 return ums_enable(sc);
590 }
591
592 static int
593 ums_close(dev_t dev, int flag, int fmt, struct proc *p)
594 {
595 struct ums_softc *sc = devclass_get_softc(ums_devclass, UMSUNIT(dev));
596
597 if (!sc) {
598 DPRINTF(("sc not found at close"));
599 return EINVAL;
600 }
601
602 if (sc->sc_enabled)
603 ums_disable(sc);
604 return 0;
605 }
606
607 static int
608 ums_read(dev_t dev, struct uio *uio, int flag)
609 {
610 struct ums_softc *sc = devclass_get_softc(ums_devclass, UMSUNIT(dev));
611 int s;
612 char buf[sizeof(sc->qbuf)];
613 int l = 0;
614 int error;
615
616 if (!sc || !sc->sc_enabled) {
617 DPRINTF(("sc not found at read"));
618 return EINVAL;
619 }
620
621 s = splusb();
622 while (sc->qcount == 0 ) {
623 /* NWH XXX non blocking I/O ??
624 if (non blocking I/O ) {
625 splx(s);
626 return EWOULDBLOCK;
627 } else {
628 */
629 sc->state |= UMS_ASLEEP;
630 error = tsleep(sc, PZERO | PCATCH, "umsrea", 0);
631 sc->state &= ~UMS_ASLEEP;
632 if (error) {
633 splx(s);
634 return error;
635 }
636 }
637
638 while ((sc->qcount > 0) && (uio->uio_resid > 0)) {
639 l = (sc->qcount < uio->uio_resid? sc->qcount:uio->uio_resid);
640 if (l > sizeof(buf))
641 l = sizeof(buf);
642 if (l > sizeof(sc->qbuf) - sc->qtail) /* transfer till end of buf */
643 l = sizeof(sc->qbuf) - sc->qtail;
644
645 splx(s);
646 uiomove(&sc->qbuf[sc->qtail], l, uio);
647 s = splusb();
648
649 if ( sc->qcount - l < 0 ) {
650 DPRINTF(("qcount below 0, count=%d l=%d\n", sc->qcount, l));
651 sc->qcount = l;
652 }
653 sc->qcount -= l; /* remove the bytes from the buffer */
654 sc->qtail = (sc->qtail + l) % sizeof(sc->qbuf);
655 }
656 splx(s);
657
658 return 0;
659 }
660
661 static int
662 ums_poll(dev_t dev, int events, struct proc *p)
663 {
664 struct ums_softc *sc = devclass_get_softc(ums_devclass, UMSUNIT(dev));
665 int revents = 0;
666 int s;
667
668 if (!sc) {
669 DPRINTF(("sc not found at poll"));
670 return 0; /* just to make sure */
671 }
672
673 s = splusb();
674 if (events & (POLLIN | POLLRDNORM))
675 if (sc->qcount) {
676 revents = events & (POLLIN | POLLRDNORM);
677 } else {
678 sc->state |= UMS_SELECT;
679 selrecord(p, &sc->rsel);
680 }
681 splx(s);
682
683 return revents;
684 }
685
686 int
687 ums_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
688 {
689 struct ums_softc *sc = devclass_get_softc(ums_devclass, UMSUNIT(dev));
690 int error = 0;
691 int s;
692
693 if (!sc) {
694 DPRINTF(("sc not found at ioctl"));
695 return ENOENT;
696 }
697
698 switch(cmd) {
699 case MOUSE_GETHWINFO:
700 *(mousehw_t *)addr = sc->hw;
701 break;
702 case MOUSE_GETMODE:
703 *(mousemode_t *)addr = sc->mode;
704 break;
705 case MOUSE_GETLEVEL:
706 *(int *)addr = sc->mode.level;
707 break;
708 case MOUSE_GETSTATUS: {
709 mousestatus_t *status = (mousestatus_t *) addr;
710
711 s = splusb();
712 *status = sc->status;
713 sc->status.obutton = sc->status.button;
714 sc->status.button = 0;
715 sc->status.dx = sc->status.dy = sc->status.dz = 0;
716 splx(s);
717
718 if (status->dx || status->dy || status->dz)
719 status->flags |= MOUSE_POSCHANGED;
720 if (status->button != status->obutton)
721 status->flags |= MOUSE_BUTTONSCHANGED;
722 break;
723 }
724 default:
725 error = ENOTTY;
726 }
727
728 return error;
729 }
730 #endif
731
732 #if defined(__FreeBSD__)
733 CDEV_DRIVER_MODULE(ums, usb, ums_driver, ums_devclass,
734 UMS_CDEV_MAJOR, ums_cdevsw, usb_driver_load, 0);
735 #endif
736
737