[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     ! 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