[BACK]Return to ums.c CVS log [TXT][DIR] Up to [local] / sys / dev / usb

Annotation of sys/dev/usb/ums.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: ums.c,v 1.25 2007/06/14 10:11:16 mbalmer Exp $ */
                      2: /*     $NetBSD: ums.c,v 1.60 2003/03/11 16:44:00 augustss Exp $        */
                      3:
                      4: /*
                      5:  * Copyright (c) 1998 The NetBSD Foundation, Inc.
                      6:  * All rights reserved.
                      7:  *
                      8:  * This code is derived from software contributed to The NetBSD Foundation
                      9:  * by Lennart Augustsson (lennart@augustsson.net) at
                     10:  * Carlstedt Research & Technology.
                     11:  *
                     12:  * Redistribution and use in source and binary forms, with or without
                     13:  * modification, are permitted provided that the following conditions
                     14:  * are met:
                     15:  * 1. Redistributions of source code must retain the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer.
                     17:  * 2. Redistributions in binary form must reproduce the above copyright
                     18:  *    notice, this list of conditions and the following disclaimer in the
                     19:  *    documentation and/or other materials provided with the distribution.
                     20:  * 3. All advertising materials mentioning features or use of this software
                     21:  *    must display the following acknowledgement:
                     22:  *        This product includes software developed by the NetBSD
                     23:  *        Foundation, Inc. and its contributors.
                     24:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     25:  *    contributors may be used to endorse or promote products derived
                     26:  *    from this software without specific prior written permission.
                     27:  *
                     28:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     29:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     30:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     31:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     32:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     33:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     34:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     35:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     36:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     37:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     38:  * POSSIBILITY OF SUCH DAMAGE.
                     39:  */
                     40:
                     41: /*
                     42:  * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
                     43:  */
                     44:
                     45: #include <sys/param.h>
                     46: #include <sys/systm.h>
                     47: #include <sys/kernel.h>
                     48: #include <sys/malloc.h>
                     49: #include <sys/device.h>
                     50: #include <sys/ioctl.h>
                     51: #include <sys/tty.h>
                     52: #include <sys/file.h>
                     53: #include <sys/selinfo.h>
                     54: #include <sys/proc.h>
                     55: #include <sys/vnode.h>
                     56: #include <sys/poll.h>
                     57:
                     58: #include <dev/usb/usb.h>
                     59: #include <dev/usb/usbhid.h>
                     60:
                     61: #include <dev/usb/usbdi.h>
                     62: #include <dev/usb/usbdi_util.h>
                     63: #include <dev/usb/usbdevs.h>
                     64: #include <dev/usb/usb_quirks.h>
                     65: #include <dev/usb/uhidev.h>
                     66: #include <dev/usb/hid.h>
                     67:
                     68: #include <dev/wscons/wsconsio.h>
                     69: #include <dev/wscons/wsmousevar.h>
                     70:
                     71: #ifdef USB_DEBUG
                     72: #define DPRINTF(x)     do { if (umsdebug) printf x; } while (0)
                     73: #define DPRINTFN(n,x)  do { if (umsdebug>(n)) printf x; } while (0)
                     74: int    umsdebug = 0;
                     75: #else
                     76: #define DPRINTF(x)
                     77: #define DPRINTFN(n,x)
                     78: #endif
                     79:
                     80: #define UMS_BUT(i) ((i) == 1 || (i) == 2 ? 3 - (i) : i)
                     81:
                     82: #define UMSUNIT(s)     (minor(s))
                     83:
                     84: #define PS2LBUTMASK    x01
                     85: #define PS2RBUTMASK    x02
                     86: #define PS2MBUTMASK    x04
                     87: #define PS2BUTMASK 0x0f
                     88:
                     89: #define MAX_BUTTONS    16      /* must not exceed size of sc_buttons */
                     90:
                     91: struct ums_softc {
                     92:        struct uhidev sc_hdev;
                     93:
                     94:        struct hid_location sc_loc_x, sc_loc_y, sc_loc_z, sc_loc_w;
                     95:        struct hid_location sc_loc_btn[MAX_BUTTONS];
                     96:
                     97:        int sc_enabled;
                     98:
                     99:        int flags;              /* device configuration */
                    100: #define UMS_Z          0x01    /* z direction available */
                    101: #define UMS_SPUR_BUT_UP        0x02    /* spurious button up events */
                    102: #define UMS_REVZ       0x04    /* Z-axis is reversed */
                    103:
                    104:        int nbuttons;
                    105:
                    106:        u_int32_t sc_buttons;   /* mouse button status */
                    107:        struct device *sc_wsmousedev;
                    108:
                    109:        char                    sc_dying;
                    110: };
                    111:
                    112: #define MOUSE_FLAGS_MASK (HIO_CONST|HIO_RELATIVE)
                    113: #define MOUSE_FLAGS (HIO_RELATIVE)
                    114:
                    115: void ums_intr(struct uhidev *addr, void *ibuf, u_int len);
                    116:
                    117: int    ums_enable(void *);
                    118: void   ums_disable(void *);
                    119: int    ums_ioctl(void *, u_long, caddr_t, int, struct proc *);
                    120:
                    121: const struct wsmouse_accessops ums_accessops = {
                    122:        ums_enable,
                    123:        ums_ioctl,
                    124:        ums_disable,
                    125: };
                    126:
                    127: int ums_match(struct device *, void *, void *);
                    128: void ums_attach(struct device *, struct device *, void *);
                    129: int ums_detach(struct device *, int);
                    130: int ums_activate(struct device *, enum devact);
                    131:
                    132: struct cfdriver ums_cd = {
                    133:        NULL, "ums", DV_DULL
                    134: };
                    135:
                    136: const struct cfattach ums_ca = {
                    137:        sizeof(struct ums_softc),
                    138:        ums_match,
                    139:        ums_attach,
                    140:        ums_detach,
                    141:        ums_activate,
                    142: };
                    143:
                    144: int
                    145: ums_match(struct device *parent, void *match, void *aux)
                    146: {
                    147:        struct usb_attach_arg *uaa = aux;
                    148:        struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa;
                    149:        int size;
                    150:        void *desc;
                    151:
                    152:        uhidev_get_report_desc(uha->parent, &desc, &size);
                    153:        if (!hid_is_collection(desc, size, uha->reportid,
                    154:                               HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE)))
                    155:                return (UMATCH_NONE);
                    156:
                    157:        return (UMATCH_IFACECLASS);
                    158: }
                    159:
                    160: void
                    161: ums_attach(struct device *parent, struct device *self, void *aux)
                    162: {
                    163:        struct ums_softc *sc = (struct ums_softc *)self;
                    164:        struct usb_attach_arg *uaa = aux;
                    165:        struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa;
                    166:        struct wsmousedev_attach_args a;
                    167:        int size;
                    168:        void *desc;
                    169:        u_int32_t flags, quirks;
                    170:        int i;
                    171:        struct hid_location loc_btn;
                    172:
                    173:        sc->sc_hdev.sc_intr = ums_intr;
                    174:        sc->sc_hdev.sc_parent = uha->parent;
                    175:        sc->sc_hdev.sc_report_id = uha->reportid;
                    176:
                    177:        quirks = usbd_get_quirks(uha->parent->sc_udev)->uq_flags;
                    178:        if (quirks & UQ_MS_REVZ)
                    179:                sc->flags |= UMS_REVZ;
                    180:        if (quirks & UQ_SPUR_BUT_UP)
                    181:                sc->flags |= UMS_SPUR_BUT_UP;
                    182:
                    183:        uhidev_get_report_desc(uha->parent, &desc, &size);
                    184:
                    185:        if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X),
                    186:               uha->reportid, hid_input, &sc->sc_loc_x, &flags)) {
                    187:                printf("\n%s: mouse has no X report\n",
                    188:                       sc->sc_hdev.sc_dev.dv_xname);
                    189:                return;
                    190:        }
                    191:        if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) {
                    192:                printf("\n%s: X report 0x%04x not supported\n",
                    193:                       sc->sc_hdev.sc_dev.dv_xname, flags);
                    194:                return;
                    195:        }
                    196:
                    197:        if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y),
                    198:               uha->reportid, hid_input, &sc->sc_loc_y, &flags)) {
                    199:                printf("\n%s: mouse has no Y report\n",
                    200:                       sc->sc_hdev.sc_dev.dv_xname);
                    201:                return;
                    202:        }
                    203:        if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) {
                    204:                printf("\n%s: Y report 0x%04x not supported\n",
                    205:                       sc->sc_hdev.sc_dev.dv_xname, flags);
                    206:                return;
                    207:        }
                    208:
                    209:        /* Try the wheel as Z activator first */
                    210:        if (hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_WHEEL),
                    211:            uha->reportid, hid_input, &sc->sc_loc_z, &flags)) {
                    212:                if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) {
                    213:                        DPRINTF(("\n%s: Wheel report 0x%04x not supported\n",
                    214:                                sc->sc_hdev.sc_dev.dv_xname, flags));
                    215:                        sc->sc_loc_z.size = 0; /* Bad Z coord, ignore it */
                    216:                } else {
                    217:                        sc->flags |= UMS_Z;
                    218:                        /* Wheels need the Z axis reversed. */
                    219:                        sc->flags ^= UMS_REVZ;
                    220:                }
                    221:                /*
                    222:                 * We might have both a wheel and Z direction; in this case,
                    223:                 * report the Z direction on the W axis.
                    224:                */
                    225:                if (hid_locate(desc, size,
                    226:                    HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z),
                    227:                    uha->reportid, hid_input, &sc->sc_loc_w, &flags)) {
                    228:                        if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) {
                    229:                                DPRINTF(("\n%s: Z report 0x%04x not supported\n",
                    230:                                        sc->sc_hdev.sc_dev.dv_xname, flags));
                    231:                                /* Bad Z coord, ignore it */
                    232:                                sc->sc_loc_w.size = 0;
                    233:                        }
                    234:                }
                    235:        } else if (hid_locate(desc, size,
                    236:            HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z),
                    237:            uha->reportid, hid_input, &sc->sc_loc_z, &flags)) {
                    238:                if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) {
                    239:                        DPRINTF(("\n%s: Z report 0x%04x not supported\n",
                    240:                                sc->sc_hdev.sc_dev.dv_xname, flags));
                    241:                        sc->sc_loc_z.size = 0; /* Bad Z coord, ignore it */
                    242:                } else {
                    243:                        sc->flags |= UMS_Z;
                    244:                }
                    245:        }
                    246:
                    247:        /* figure out the number of buttons */
                    248:        for (i = 1; i <= MAX_BUTTONS; i++)
                    249:                if (!hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i),
                    250:                        uha->reportid, hid_input, &loc_btn, 0))
                    251:                        break;
                    252:        sc->nbuttons = i - 1;
                    253:
                    254:        printf(": %d button%s%s\n",
                    255:            sc->nbuttons, sc->nbuttons == 1 ? "" : "s",
                    256:            sc->flags & UMS_Z ? " and Z dir." : "");
                    257:
                    258:        for (i = 1; i <= sc->nbuttons; i++)
                    259:                hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i),
                    260:                           uha->reportid, hid_input,
                    261:                           &sc->sc_loc_btn[i-1], 0);
                    262:
                    263: #ifdef USB_DEBUG
                    264:        DPRINTF(("ums_attach: sc=%p\n", sc));
                    265:        DPRINTF(("ums_attach: X\t%d/%d\n",
                    266:                 sc->sc_loc_x.pos, sc->sc_loc_x.size));
                    267:        DPRINTF(("ums_attach: Y\t%d/%d\n",
                    268:                 sc->sc_loc_y.pos, sc->sc_loc_y.size));
                    269:        if (sc->flags & UMS_Z)
                    270:                DPRINTF(("ums_attach: Z\t%d/%d\n",
                    271:                         sc->sc_loc_z.pos, sc->sc_loc_z.size));
                    272:        for (i = 1; i <= sc->nbuttons; i++) {
                    273:                DPRINTF(("ums_attach: B%d\t%d/%d\n",
                    274:                         i, sc->sc_loc_btn[i-1].pos,sc->sc_loc_btn[i-1].size));
                    275:        }
                    276: #endif
                    277:
                    278:        a.accessops = &ums_accessops;
                    279:        a.accesscookie = sc;
                    280:
                    281:        sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
                    282: }
                    283:
                    284: int
                    285: ums_activate(struct device *self, enum devact act)
                    286: {
                    287:        struct ums_softc *sc = (struct ums_softc *)self;
                    288:        int rv = 0;
                    289:
                    290:        switch (act) {
                    291:        case DVACT_ACTIVATE:
                    292:                break;
                    293:
                    294:        case DVACT_DEACTIVATE:
                    295:                if (sc->sc_wsmousedev != NULL)
                    296:                        rv = config_deactivate(sc->sc_wsmousedev);
                    297:                sc->sc_dying = 1;
                    298:                break;
                    299:        }
                    300:        return (rv);
                    301: }
                    302:
                    303: int
                    304: ums_detach(struct device *self, int flags)
                    305: {
                    306:        struct ums_softc *sc = (struct ums_softc *)self;
                    307:        int rv = 0;
                    308:
                    309:        DPRINTF(("ums_detach: sc=%p flags=%d\n", sc, flags));
                    310:
                    311:        /* No need to do reference counting of ums, wsmouse has all the goo. */
                    312:        if (sc->sc_wsmousedev != NULL)
                    313:                rv = config_detach(sc->sc_wsmousedev, flags);
                    314:
                    315:        return (rv);
                    316: }
                    317:
                    318: void
                    319: ums_intr(struct uhidev *addr, void *ibuf, u_int len)
                    320: {
                    321:        struct ums_softc *sc = (struct ums_softc *)addr;
                    322:        int dx, dy, dz, dw;
                    323:        u_int32_t buttons = 0;
                    324:        int i;
                    325:        int s;
                    326:
                    327:        DPRINTFN(5,("ums_intr: len=%d\n", len));
                    328:
                    329:        dx =  hid_get_data(ibuf, &sc->sc_loc_x);
                    330:        dy = -hid_get_data(ibuf, &sc->sc_loc_y);
                    331:        dz =  hid_get_data(ibuf, &sc->sc_loc_z);
                    332:        dw =  hid_get_data(ibuf, &sc->sc_loc_w);
                    333:        if (sc->flags & UMS_REVZ)
                    334:                dz = -dz;
                    335:        for (i = 0; i < sc->nbuttons; i++)
                    336:                if (hid_get_data(ibuf, &sc->sc_loc_btn[i]))
                    337:                        buttons |= (1 << UMS_BUT(i));
                    338:
                    339:        if (dx != 0 || dy != 0 || dz != 0 || dw != 0 ||
                    340:            buttons != sc->sc_buttons) {
                    341:                DPRINTFN(10, ("ums_intr: x:%d y:%d z:%d w:%d buttons:0x%x\n",
                    342:                        dx, dy, dz, dw, buttons));
                    343:                sc->sc_buttons = buttons;
                    344:                if (sc->sc_wsmousedev != NULL) {
                    345:                        s = spltty();
                    346:                        wsmouse_input(sc->sc_wsmousedev, buttons,
                    347:                            dx, dy, dz, dw, WSMOUSE_INPUT_DELTA);
                    348:                        splx(s);
                    349:                }
                    350:        }
                    351: }
                    352:
                    353: int
                    354: ums_enable(void *v)
                    355: {
                    356:        struct ums_softc *sc = v;
                    357:
                    358:        DPRINTFN(1,("ums_enable: sc=%p\n", sc));
                    359:
                    360:        if (sc->sc_dying)
                    361:                return (EIO);
                    362:
                    363:        if (sc->sc_enabled)
                    364:                return (EBUSY);
                    365:
                    366:        sc->sc_enabled = 1;
                    367:        sc->sc_buttons = 0;
                    368:
                    369:        return (uhidev_open(&sc->sc_hdev));
                    370: }
                    371:
                    372: void
                    373: ums_disable(void *v)
                    374: {
                    375:        struct ums_softc *sc = v;
                    376:
                    377:        DPRINTFN(1,("ums_disable: sc=%p\n", sc));
                    378: #ifdef DIAGNOSTIC
                    379:        if (!sc->sc_enabled) {
                    380:                printf("ums_disable: not enabled\n");
                    381:                return;
                    382:        }
                    383: #endif
                    384:
                    385:        sc->sc_enabled = 0;
                    386:        uhidev_close(&sc->sc_hdev);
                    387: }
                    388:
                    389: int
                    390: ums_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
                    391:
                    392: {
                    393:        switch (cmd) {
                    394:        case WSMOUSEIO_GTYPE:
                    395:                *(u_int *)data = WSMOUSE_TYPE_USB;
                    396:                return (0);
                    397:        }
                    398:
                    399:        return (-1);
                    400: }

CVSweb