Annotation of src/sys/dev/usb/uhid.c, Revision 1.85
1.85 ! mrg 1: /* $NetBSD: uhid.c,v 1.84 2010/11/03 22:34:24 dyoung Exp $ */
1.1 augustss 2:
3: /*
1.80 ad 4: * Copyright (c) 1998, 2004, 2008 The NetBSD Foundation, Inc.
1.1 augustss 5: * All rights reserved.
6: *
1.6 augustss 7: * This code is derived from software contributed to The NetBSD Foundation
1.38 augustss 8: * by Lennart Augustsson (lennart@augustsson.net) at
1.6 augustss 9: * Carlstedt Research & Technology.
1.1 augustss 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: *
20: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30: * POSSIBILITY OF SUCH DAMAGE.
31: */
32:
1.15 augustss 33: /*
1.57 augustss 34: * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
1.15 augustss 35: */
1.46 lukem 36:
37: #include <sys/cdefs.h>
1.85 ! mrg 38: __KERNEL_RCSID(0, "$NetBSD: uhid.c,v 1.84 2010/11/03 22:34:24 dyoung Exp $");
1.73 pavel 39:
40: #include "opt_compat_netbsd.h"
1.1 augustss 41:
42: #include <sys/param.h>
43: #include <sys/systm.h>
44: #include <sys/kernel.h>
45: #include <sys/malloc.h>
1.37 augustss 46: #include <sys/signalvar.h>
1.14 augustss 47: #include <sys/device.h>
1.12 augustss 48: #include <sys/ioctl.h>
1.18 augustss 49: #include <sys/conf.h>
1.1 augustss 50: #include <sys/tty.h>
51: #include <sys/file.h>
52: #include <sys/select.h>
53: #include <sys/proc.h>
54: #include <sys/vnode.h>
55: #include <sys/poll.h>
1.80 ad 56: #include <sys/intr.h>
1.1 augustss 57:
58: #include <dev/usb/usb.h>
59: #include <dev/usb/usbhid.h>
60:
1.42 augustss 61: #include <dev/usb/usbdevs.h>
1.1 augustss 62: #include <dev/usb/usbdi.h>
63: #include <dev/usb/usbdi_util.h>
64: #include <dev/usb/hid.h>
65: #include <dev/usb/usb_quirks.h>
66:
1.47 augustss 67: #include <dev/usb/uhidev.h>
1.42 augustss 68:
1.26 augustss 69: #ifdef UHID_DEBUG
1.84 dyoung 70: #define DPRINTF(x) if (uhiddebug) printf x
71: #define DPRINTFN(n,x) if (uhiddebug>(n)) printf x
1.1 augustss 72: int uhiddebug = 0;
73: #else
74: #define DPRINTF(x)
75: #define DPRINTFN(n,x)
76: #endif
77:
78: struct uhid_softc {
1.47 augustss 79: struct uhidev sc_hdev;
1.1 augustss 80:
81: int sc_isize;
82: int sc_osize;
1.2 augustss 83: int sc_fsize;
1.1 augustss 84:
1.33 augustss 85: u_char *sc_obuf;
1.1 augustss 86:
87: struct clist sc_q;
88: struct selinfo sc_rsel;
1.84 dyoung 89: proc_t *sc_async; /* process that wants SIGIO */
1.80 ad 90: void *sc_sih;
1.1 augustss 91: u_char sc_state; /* driver state */
1.47 augustss 92: #define UHID_ASLP 0x01 /* waiting for device data */
93: #define UHID_IMMED 0x02 /* return read data immediately */
1.18 augustss 94:
95: int sc_refcnt;
96: u_char sc_dying;
1.1 augustss 97: };
98:
99: #define UHIDUNIT(dev) (minor(dev))
100: #define UHID_CHUNK 128 /* chunk size for read */
101: #define UHID_BSIZE 1020 /* buffer size */
102:
1.53 gehenna 103: dev_type_open(uhidopen);
104: dev_type_close(uhidclose);
105: dev_type_read(uhidread);
106: dev_type_write(uhidwrite);
107: dev_type_ioctl(uhidioctl);
108: dev_type_poll(uhidpoll);
1.55 jdolecek 109: dev_type_kqfilter(uhidkqfilter);
1.53 gehenna 110:
111: const struct cdevsw uhid_cdevsw = {
112: uhidopen, uhidclose, uhidread, uhidwrite, uhidioctl,
1.70 christos 113: nostop, notty, uhidpoll, nommap, uhidkqfilter, D_OTHER,
1.53 gehenna 114: };
1.19 augustss 115:
1.47 augustss 116: Static void uhid_intr(struct uhidev *, void *, u_int len);
1.80 ad 117: Static void uhid_softintr(void *);
1.18 augustss 118:
1.39 augustss 119: Static int uhid_do_read(struct uhid_softc *, struct uio *uio, int);
120: Static int uhid_do_write(struct uhid_softc *, struct uio *uio, int);
1.76 christos 121: Static int uhid_do_ioctl(struct uhid_softc*, u_long, void *, int, struct lwp *);
1.1 augustss 122:
1.84 dyoung 123: int uhid_match(device_t, cfdata_t, void *);
124: void uhid_attach(device_t, device_t, void *);
125: int uhid_detach(device_t, int);
126: int uhid_activate(device_t, enum devact);
127: extern struct cfdriver uhid_cd;
128: CFATTACH_DECL_NEW(uhid, sizeof(struct uhid_softc), uhid_match, uhid_attach, uhid_detach, uhid_activate);
1.1 augustss 129:
1.47 augustss 130: int
1.82 cube 131: uhid_match(device_t parent, cfdata_t match, void *aux)
1.1 augustss 132: {
1.66 tron 133: #ifdef UHID_DEBUG
1.47 augustss 134: struct uhidev_attach_arg *uha = aux;
1.66 tron 135: #endif
1.47 augustss 136:
137: DPRINTF(("uhid_match: report=%d\n", uha->reportid));
138:
1.65 augustss 139: if (match->cf_flags & 1)
1.67 augustss 140: return (UMATCH_HIGHEST);
141: else
142: return (UMATCH_IFACECLASS_GENERIC);
1.1 augustss 143: }
144:
1.47 augustss 145: void
1.82 cube 146: uhid_attach(device_t parent, device_t self, void *aux)
1.1 augustss 147: {
1.82 cube 148: struct uhid_softc *sc = device_private(self);
1.47 augustss 149: struct uhidev_attach_arg *uha = aux;
150: int size, repid;
1.1 augustss 151: void *desc;
1.52 augustss 152:
1.82 cube 153: sc->sc_hdev.sc_dev = self;
1.79 rmind 154: selinit(&sc->sc_rsel);
1.47 augustss 155: sc->sc_hdev.sc_intr = uhid_intr;
156: sc->sc_hdev.sc_parent = uha->parent;
157: sc->sc_hdev.sc_report_id = uha->reportid;
1.80 ad 158: sc->sc_sih = softint_establish(SOFTINT_MPSAFE | SOFTINT_CLOCK,
159: uhid_softintr, sc);
1.47 augustss 160:
161: uhidev_get_report_desc(uha->parent, &desc, &size);
162: repid = uha->reportid;
163: sc->sc_isize = hid_report_size(desc, size, hid_input, repid);
164: sc->sc_osize = hid_report_size(desc, size, hid_output, repid);
165: sc->sc_fsize = hid_report_size(desc, size, hid_feature, repid);
1.1 augustss 166:
1.82 cube 167: aprint_naive("\n");
168: aprint_normal(": input=%d, output=%d, feature=%d\n",
1.47 augustss 169: sc->sc_isize, sc->sc_osize, sc->sc_fsize);
1.32 augustss 170:
1.78 drochner 171: if (!pmf_device_register(self, NULL, NULL))
172: aprint_error_dev(self, "couldn't establish power handler\n");
173:
1.84 dyoung 174: return;
1.1 augustss 175: }
176:
1.18 augustss 177: int
1.84 dyoung 178: uhid_activate(device_t self, enum devact act)
1.18 augustss 179: {
1.82 cube 180: struct uhid_softc *sc = device_private(self);
1.21 augustss 181:
182: switch (act) {
183: case DVACT_DEACTIVATE:
184: sc->sc_dying = 1;
1.83 dyoung 185: return 0;
186: default:
187: return EOPNOTSUPP;
1.21 augustss 188: }
1.12 augustss 189: }
190:
1.47 augustss 191: int
1.82 cube 192: uhid_detach(device_t self, int flags)
1.1 augustss 193: {
1.82 cube 194: struct uhid_softc *sc = device_private(self);
1.26 augustss 195: int s;
1.18 augustss 196: int maj, mn;
197:
198: DPRINTF(("uhid_detach: sc=%p flags=%d\n", sc, flags));
1.3 augustss 199:
1.18 augustss 200: sc->sc_dying = 1;
201:
1.47 augustss 202: if (sc->sc_hdev.sc_state & UHIDEV_OPEN) {
1.18 augustss 203: s = splusb();
204: if (--sc->sc_refcnt >= 0) {
205: /* Wake everyone */
206: wakeup(&sc->sc_q);
207: /* Wait for processes to go away. */
1.84 dyoung 208: usb_detach_wait(sc->sc_hdev.sc_dev);
1.18 augustss 209: }
210: splx(s);
211: }
212:
213: /* locate the major number */
1.53 gehenna 214: maj = cdevsw_lookup_major(&uhid_cdevsw);
1.18 augustss 215:
216: /* Nuke the vnodes for any open instances (calls close). */
1.69 thorpej 217: mn = device_unit(self);
1.18 augustss 218: vdevgone(maj, mn, mn, VCHR);
1.47 augustss 219:
220: #if 0
1.52 augustss 221: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH,
1.47 augustss 222: sc->sc_hdev.sc_parent->sc_udev,
1.84 dyoung 223: sc->sc_hdev.sc_dev);
1.26 augustss 224: #endif
1.79 rmind 225: seldestroy(&sc->sc_rsel);
1.80 ad 226: softint_disestablish(sc->sc_sih);
1.18 augustss 227:
228: return (0);
1.1 augustss 229: }
230:
231: void
1.47 augustss 232: uhid_intr(struct uhidev *addr, void *data, u_int len)
1.1 augustss 233: {
1.47 augustss 234: struct uhid_softc *sc = (struct uhid_softc *)addr;
1.1 augustss 235:
1.33 augustss 236: #ifdef UHID_DEBUG
237: if (uhiddebug > 5) {
1.47 augustss 238: u_int32_t i;
1.52 augustss 239:
1.33 augustss 240: DPRINTF(("uhid_intr: data ="));
1.47 augustss 241: for (i = 0; i < len; i++)
1.51 augustss 242: DPRINTF((" %02x", ((u_char *)data)[i]));
1.33 augustss 243: DPRINTF(("\n"));
244: }
245: #endif
1.1 augustss 246:
1.47 augustss 247: (void)b_to_q(data, len, &sc->sc_q);
1.52 augustss 248:
1.1 augustss 249: if (sc->sc_state & UHID_ASLP) {
250: sc->sc_state &= ~UHID_ASLP;
1.44 yamt 251: DPRINTFN(5, ("uhid_intr: waking %p\n", &sc->sc_q));
1.18 augustss 252: wakeup(&sc->sc_q);
1.1 augustss 253: }
1.79 rmind 254: selnotify(&sc->sc_rsel, 0, 0);
1.37 augustss 255: if (sc->sc_async != NULL) {
256: DPRINTFN(3, ("uhid_intr: sending SIGIO %p\n", sc->sc_async));
1.80 ad 257: softint_schedule(sc->sc_sih);
1.37 augustss 258: }
1.1 augustss 259: }
260:
1.80 ad 261: void
262: uhid_softintr(void *cookie)
263: {
264: struct uhid_softc *sc;
265:
266: sc = cookie;
267:
268: mutex_enter(proc_lock);
269: if (sc->sc_async != NULL)
270: psignal(sc->sc_async, SIGIO);
271: mutex_exit(proc_lock);
272: }
273:
1.1 augustss 274: int
1.72 christos 275: uhidopen(dev_t dev, int flag, int mode,
276: struct lwp *l)
1.1 augustss 277: {
1.25 augustss 278: struct uhid_softc *sc;
1.47 augustss 279: int error;
1.25 augustss 280:
1.84 dyoung 281: sc = device_lookup_private(&uhid_cd, UHIDUNIT(dev));
282: if (sc == NULL)
283: return ENXIO;
1.1 augustss 284:
1.18 augustss 285: DPRINTF(("uhidopen: sc=%p\n", sc));
1.1 augustss 286:
1.18 augustss 287: if (sc->sc_dying)
288: return (ENXIO);
1.1 augustss 289:
1.47 augustss 290: error = uhidev_open(&sc->sc_hdev);
291: if (error)
292: return (error);
1.1 augustss 293:
1.17 augustss 294: if (clalloc(&sc->sc_q, UHID_BSIZE, 0) == -1) {
1.47 augustss 295: uhidev_close(&sc->sc_hdev);
1.12 augustss 296: return (ENOMEM);
1.17 augustss 297: }
1.18 augustss 298: sc->sc_obuf = malloc(sc->sc_osize, M_USBDEV, M_WAITOK);
1.17 augustss 299: sc->sc_state &= ~UHID_IMMED;
1.80 ad 300: mutex_enter(proc_lock);
1.47 augustss 301: sc->sc_async = NULL;
1.80 ad 302: mutex_exit(proc_lock);
1.37 augustss 303:
1.12 augustss 304: return (0);
1.1 augustss 305: }
306:
307: int
1.72 christos 308: uhidclose(dev_t dev, int flag, int mode,
309: struct lwp *l)
1.1 augustss 310: {
1.25 augustss 311: struct uhid_softc *sc;
312:
1.84 dyoung 313: sc = device_lookup_private(&uhid_cd, UHIDUNIT(dev));
1.1 augustss 314:
315: DPRINTF(("uhidclose: sc=%p\n", sc));
316:
317: clfree(&sc->sc_q);
1.18 augustss 318: free(sc->sc_obuf, M_USBDEV);
1.80 ad 319: mutex_enter(proc_lock);
1.47 augustss 320: sc->sc_async = NULL;
1.80 ad 321: mutex_exit(proc_lock);
1.47 augustss 322: uhidev_close(&sc->sc_hdev);
1.37 augustss 323:
1.12 augustss 324: return (0);
1.1 augustss 325: }
326:
327: int
1.39 augustss 328: uhid_do_read(struct uhid_softc *sc, struct uio *uio, int flag)
1.1 augustss 329: {
330: int s;
331: int error = 0;
1.47 augustss 332: int extra;
1.1 augustss 333: size_t length;
334: u_char buffer[UHID_CHUNK];
1.27 augustss 335: usbd_status err;
1.1 augustss 336:
337: DPRINTFN(1, ("uhidread\n"));
1.2 augustss 338: if (sc->sc_state & UHID_IMMED) {
339: DPRINTFN(1, ("uhidread immed\n"));
1.47 augustss 340: extra = sc->sc_hdev.sc_report_id != 0;
341: err = uhidev_get_report(&sc->sc_hdev, UHID_INPUT_REPORT,
342: buffer, sc->sc_isize + extra);
1.27 augustss 343: if (err)
1.2 augustss 344: return (EIO);
1.47 augustss 345: return (uiomove(buffer+extra, sc->sc_isize, uio));
1.2 augustss 346: }
347:
1.10 augustss 348: s = splusb();
1.1 augustss 349: while (sc->sc_q.c_cc == 0) {
350: if (flag & IO_NDELAY) {
351: splx(s);
1.18 augustss 352: return (EWOULDBLOCK);
1.1 augustss 353: }
354: sc->sc_state |= UHID_ASLP;
1.44 yamt 355: DPRINTFN(5, ("uhidread: sleep on %p\n", &sc->sc_q));
1.18 augustss 356: error = tsleep(&sc->sc_q, PZERO | PCATCH, "uhidrea", 0);
1.1 augustss 357: DPRINTFN(5, ("uhidread: woke, error=%d\n", error));
1.18 augustss 358: if (sc->sc_dying)
359: error = EIO;
1.1 augustss 360: if (error) {
361: sc->sc_state &= ~UHID_ASLP;
1.18 augustss 362: break;
1.1 augustss 363: }
364: }
365: splx(s);
366:
367: /* Transfer as many chunks as possible. */
1.18 augustss 368: while (sc->sc_q.c_cc > 0 && uio->uio_resid > 0 && !error) {
1.1 augustss 369: length = min(sc->sc_q.c_cc, uio->uio_resid);
370: if (length > sizeof(buffer))
371: length = sizeof(buffer);
372:
373: /* Remove a small chunk from the input queue. */
374: (void) q_to_b(&sc->sc_q, buffer, length);
1.29 augustss 375: DPRINTFN(5, ("uhidread: got %lu chars\n", (u_long)length));
1.1 augustss 376:
377: /* Copy the data to the user process. */
378: if ((error = uiomove(buffer, length, uio)) != 0)
379: break;
380: }
381:
382: return (error);
383: }
384:
385: int
1.39 augustss 386: uhidread(dev_t dev, struct uio *uio, int flag)
1.1 augustss 387: {
1.25 augustss 388: struct uhid_softc *sc;
389: int error;
390:
1.84 dyoung 391: sc = device_lookup_private(&uhid_cd, UHIDUNIT(dev));
1.18 augustss 392:
393: sc->sc_refcnt++;
394: error = uhid_do_read(sc, uio, flag);
395: if (--sc->sc_refcnt < 0)
1.84 dyoung 396: usb_detach_wakeup(sc->sc_hdev.sc_dev);
1.18 augustss 397: return (error);
398: }
399:
400: int
1.72 christos 401: uhid_do_write(struct uhid_softc *sc, struct uio *uio, int flag)
1.18 augustss 402: {
1.1 augustss 403: int error;
404: int size;
1.27 augustss 405: usbd_status err;
1.1 augustss 406:
1.18 augustss 407: DPRINTFN(1, ("uhidwrite\n"));
1.52 augustss 408:
1.18 augustss 409: if (sc->sc_dying)
1.1 augustss 410: return (EIO);
411:
412: size = sc->sc_osize;
413: error = 0;
1.18 augustss 414: if (uio->uio_resid != size)
415: return (EINVAL);
416: error = uiomove(sc->sc_obuf, size, uio);
417: if (!error) {
1.47 augustss 418: err = uhidev_set_report(&sc->sc_hdev, UHID_OUTPUT_REPORT,
419: sc->sc_obuf, size);
1.27 augustss 420: if (err)
1.1 augustss 421: error = EIO;
422: }
1.18 augustss 423:
1.1 augustss 424: return (error);
425: }
426:
427: int
1.39 augustss 428: uhidwrite(dev_t dev, struct uio *uio, int flag)
1.18 augustss 429: {
1.25 augustss 430: struct uhid_softc *sc;
431: int error;
432:
1.84 dyoung 433: sc = device_lookup_private(&uhid_cd, UHIDUNIT(dev));
1.18 augustss 434:
435: sc->sc_refcnt++;
436: error = uhid_do_write(sc, uio, flag);
437: if (--sc->sc_refcnt < 0)
1.84 dyoung 438: usb_detach_wakeup(sc->sc_hdev.sc_dev);
1.18 augustss 439: return (error);
440: }
441:
442: int
1.76 christos 443: uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, void *addr,
1.72 christos 444: int flag, struct lwp *l)
1.1 augustss 445: {
446: struct usb_ctl_report_desc *rd;
1.2 augustss 447: struct usb_ctl_report *re;
1.47 augustss 448: u_char buffer[UHID_CHUNK];
449: int size, extra;
1.27 augustss 450: usbd_status err;
1.47 augustss 451: void *desc;
1.1 augustss 452:
1.18 augustss 453: DPRINTFN(2, ("uhidioctl: cmd=%lx\n", cmd));
454:
455: if (sc->sc_dying)
1.1 augustss 456: return (EIO);
457:
458: switch (cmd) {
1.2 augustss 459: case FIONBIO:
460: /* All handled in the upper FS layer. */
1.37 augustss 461: break;
462:
463: case FIOASYNC:
1.80 ad 464: mutex_enter(proc_lock);
1.37 augustss 465: if (*(int *)addr) {
466: if (sc->sc_async != NULL)
467: return (EBUSY);
1.68 christos 468: sc->sc_async = l->l_proc;
469: DPRINTF(("uhid_do_ioctl: FIOASYNC %p\n", l->l_proc));
1.37 augustss 470: } else
471: sc->sc_async = NULL;
1.80 ad 472: mutex_exit(proc_lock);
1.37 augustss 473: break;
474:
475: /* XXX this is not the most general solution. */
476: case TIOCSPGRP:
1.80 ad 477: mutex_enter(proc_lock);
478: if (sc->sc_async == NULL) {
479: mutex_exit(proc_lock);
1.37 augustss 480: return (EINVAL);
1.80 ad 481: }
482: if (*(int *)addr != sc->sc_async->p_pgid) {
483: mutex_exit(proc_lock);
1.60 jdolecek 484: return (EPERM);
1.80 ad 485: }
486: mutex_exit(proc_lock);
1.60 jdolecek 487: break;
488:
489: case FIOSETOWN:
1.80 ad 490: mutex_enter(proc_lock);
491: if (sc->sc_async == NULL) {
492: mutex_exit(proc_lock);
1.60 jdolecek 493: return (EINVAL);
1.80 ad 494: }
1.60 jdolecek 495: if (-*(int *)addr != sc->sc_async->p_pgid
1.80 ad 496: && *(int *)addr != sc->sc_async->p_pid) {
497: mutex_exit(proc_lock);
1.37 augustss 498: return (EPERM);
1.80 ad 499: }
500: mutex_exit(proc_lock);
1.2 augustss 501: break;
502:
1.1 augustss 503: case USB_GET_REPORT_DESC:
1.47 augustss 504: uhidev_get_report_desc(sc->sc_hdev.sc_parent, &desc, &size);
1.1 augustss 505: rd = (struct usb_ctl_report_desc *)addr;
1.50 christos 506: size = min(size, sizeof rd->ucrd_data);
507: rd->ucrd_size = size;
508: memcpy(rd->ucrd_data, desc, size);
1.1 augustss 509: break;
1.2 augustss 510:
511: case USB_SET_IMMED:
1.9 augustss 512: if (*(int *)addr) {
1.47 augustss 513: extra = sc->sc_hdev.sc_report_id != 0;
514: err = uhidev_get_report(&sc->sc_hdev, UHID_INPUT_REPORT,
515: buffer, sc->sc_isize + extra);
1.27 augustss 516: if (err)
1.9 augustss 517: return (EOPNOTSUPP);
1.12 augustss 518:
1.2 augustss 519: sc->sc_state |= UHID_IMMED;
1.9 augustss 520: } else
1.2 augustss 521: sc->sc_state &= ~UHID_IMMED;
522: break;
523:
524: case USB_GET_REPORT:
525: re = (struct usb_ctl_report *)addr;
1.50 christos 526: switch (re->ucr_report) {
1.2 augustss 527: case UHID_INPUT_REPORT:
528: size = sc->sc_isize;
529: break;
530: case UHID_OUTPUT_REPORT:
531: size = sc->sc_osize;
532: break;
533: case UHID_FEATURE_REPORT:
534: size = sc->sc_fsize;
535: break;
536: default:
537: return (EINVAL);
538: }
1.47 augustss 539: extra = sc->sc_hdev.sc_report_id != 0;
1.50 christos 540: err = uhidev_get_report(&sc->sc_hdev, re->ucr_report,
541: re->ucr_data, size + extra);
1.47 augustss 542: if (extra)
1.50 christos 543: memcpy(re->ucr_data, re->ucr_data+1, size);
1.35 augustss 544: if (err)
545: return (EIO);
546: break;
547:
548: case USB_SET_REPORT:
549: re = (struct usb_ctl_report *)addr;
1.50 christos 550: switch (re->ucr_report) {
1.35 augustss 551: case UHID_INPUT_REPORT:
552: size = sc->sc_isize;
553: break;
554: case UHID_OUTPUT_REPORT:
555: size = sc->sc_osize;
556: break;
557: case UHID_FEATURE_REPORT:
558: size = sc->sc_fsize;
559: break;
560: default:
561: return (EINVAL);
562: }
1.50 christos 563: err = uhidev_set_report(&sc->sc_hdev, re->ucr_report,
564: re->ucr_data, size);
1.27 augustss 565: if (err)
1.2 augustss 566: return (EIO);
567: break;
568:
1.47 augustss 569: case USB_GET_REPORT_ID:
570: *(int *)addr = sc->sc_hdev.sc_report_id;
571: break;
572:
1.61 jdolecek 573: case USB_GET_DEVICEINFO:
574: usbd_fill_deviceinfo(sc->sc_hdev.sc_parent->sc_udev,
1.75 drochner 575: (struct usb_device_info *)addr, 0);
1.61 jdolecek 576: break;
1.73 pavel 577: #ifdef COMPAT_30
578: case USB_GET_DEVICEINFO_OLD:
579: usbd_fill_deviceinfo_old(sc->sc_hdev.sc_parent->sc_udev,
1.75 drochner 580: (struct usb_device_info_old *)addr, 0);
1.61 jdolecek 581:
1.73 pavel 582: break;
583: #endif
1.61 jdolecek 584: case USB_GET_STRING_DESC:
585: {
586: struct usb_string_desc *si = (struct usb_string_desc *)addr;
587: err = usbd_get_string_desc(sc->sc_hdev.sc_parent->sc_udev,
588: si->usd_string_index,
1.62 mycroft 589: si->usd_language_id, &si->usd_desc, &size);
1.61 jdolecek 590: if (err)
591: return (EINVAL);
592: break;
593: }
594:
1.1 augustss 595: default:
596: return (EINVAL);
597: }
598: return (0);
599: }
600:
601: int
1.76 christos 602: uhidioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
1.18 augustss 603: {
1.25 augustss 604: struct uhid_softc *sc;
605: int error;
606:
1.84 dyoung 607: sc = device_lookup_private(&uhid_cd, UHIDUNIT(dev));
1.18 augustss 608:
609: sc->sc_refcnt++;
1.68 christos 610: error = uhid_do_ioctl(sc, cmd, addr, flag, l);
1.18 augustss 611: if (--sc->sc_refcnt < 0)
1.84 dyoung 612: usb_detach_wakeup(sc->sc_hdev.sc_dev);
1.18 augustss 613: return (error);
614: }
615:
616: int
1.68 christos 617: uhidpoll(dev_t dev, int events, struct lwp *l)
1.1 augustss 618: {
1.25 augustss 619: struct uhid_softc *sc;
1.1 augustss 620: int revents = 0;
621: int s;
1.25 augustss 622:
1.84 dyoung 623: sc = device_lookup_private(&uhid_cd, UHIDUNIT(dev));
1.1 augustss 624:
1.18 augustss 625: if (sc->sc_dying)
1.64 ws 626: return (POLLHUP);
1.1 augustss 627:
1.10 augustss 628: s = splusb();
1.1 augustss 629: if (events & (POLLOUT | POLLWRNORM))
630: revents |= events & (POLLOUT | POLLWRNORM);
1.4 veego 631: if (events & (POLLIN | POLLRDNORM)) {
1.1 augustss 632: if (sc->sc_q.c_cc > 0)
633: revents |= events & (POLLIN | POLLRDNORM);
634: else
1.68 christos 635: selrecord(l, &sc->sc_rsel);
1.4 veego 636: }
1.1 augustss 637:
638: splx(s);
639: return (revents);
1.55 jdolecek 640: }
641:
642: static void
643: filt_uhidrdetach(struct knote *kn)
644: {
645: struct uhid_softc *sc = kn->kn_hook;
646: int s;
647:
648: s = splusb();
1.56 christos 649: SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext);
1.55 jdolecek 650: splx(s);
651: }
652:
653: static int
1.72 christos 654: filt_uhidread(struct knote *kn, long hint)
1.55 jdolecek 655: {
656: struct uhid_softc *sc = kn->kn_hook;
657:
658: kn->kn_data = sc->sc_q.c_cc;
659: return (kn->kn_data > 0);
660: }
661:
662: static const struct filterops uhidread_filtops =
663: { 1, NULL, filt_uhidrdetach, filt_uhidread };
664:
665: static const struct filterops uhid_seltrue_filtops =
666: { 1, NULL, filt_uhidrdetach, filt_seltrue };
667:
668: int
669: uhidkqfilter(dev_t dev, struct knote *kn)
670: {
671: struct uhid_softc *sc;
672: struct klist *klist;
673: int s;
674:
1.84 dyoung 675: sc = device_lookup_private(&uhid_cd, UHIDUNIT(dev));
1.55 jdolecek 676:
677: if (sc->sc_dying)
1.77 pooka 678: return (ENXIO);
1.55 jdolecek 679:
680: switch (kn->kn_filter) {
681: case EVFILT_READ:
1.56 christos 682: klist = &sc->sc_rsel.sel_klist;
1.55 jdolecek 683: kn->kn_fop = &uhidread_filtops;
684: break;
685:
686: case EVFILT_WRITE:
1.56 christos 687: klist = &sc->sc_rsel.sel_klist;
1.55 jdolecek 688: kn->kn_fop = &uhid_seltrue_filtops;
689: break;
690:
691: default:
1.77 pooka 692: return (EINVAL);
1.55 jdolecek 693: }
694:
695: kn->kn_hook = sc;
696:
697: s = splusb();
698: SLIST_INSERT_HEAD(klist, kn, kn_selnext);
699: splx(s);
700:
701: return (0);
1.1 augustss 702: }
CVSweb <webmaster@jp.NetBSD.org>