[BACK]Return to uhid.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / usb

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>