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

Annotation of sys/dev/usb/uts.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: uts.c,v 1.17 2007/06/14 10:11:16 mbalmer Exp $ */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2007 Robert Nagy <robert@openbsd.org>
        !             5:  *
        !             6:  * Permission to use, copy, modify, and distribute this software for any
        !             7:  * purpose with or without fee is hereby granted, provided that the above
        !             8:  * copyright notice and this permission notice appear in all copies.
        !             9:  *
        !            10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            17:  */
        !            18:
        !            19: #include <sys/param.h>
        !            20: #include <sys/sockio.h>
        !            21: #include <sys/mbuf.h>
        !            22: #include <sys/kernel.h>
        !            23: #include <sys/socket.h>
        !            24: #include <sys/systm.h>
        !            25: #include <sys/malloc.h>
        !            26: #include <sys/timeout.h>
        !            27: #include <sys/conf.h>
        !            28: #include <sys/device.h>
        !            29:
        !            30: #include <machine/bus.h>
        !            31: #include <machine/endian.h>
        !            32: #include <machine/intr.h>
        !            33:
        !            34: #include <dev/usb/usb.h>
        !            35: #include <dev/usb/usbdi.h>
        !            36: #include <dev/usb/usbdi_util.h>
        !            37: #include <dev/usb/usbdevs.h>
        !            38:
        !            39: #include <dev/wscons/wsconsio.h>
        !            40: #include <dev/wscons/wsmousevar.h>
        !            41:
        !            42: #ifdef USB_DEBUG
        !            43: #define UTS_DEBUG
        !            44: #endif
        !            45:
        !            46: #ifdef UTS_DEBUG
        !            47: #define DPRINTF(x)             do { printf x; } while (0)
        !            48: #else
        !            49: #define DPRINTF(x)
        !            50: #endif
        !            51:
        !            52: #define UTS_CONFIG_INDEX 0
        !            53:
        !            54: struct tsscale {
        !            55:        int     minx, maxx;
        !            56:        int     miny, maxy;
        !            57:        int     swapxy;
        !            58:        int     resx, resy;
        !            59: } def_scale = {
        !            60:        67, 1931, 102, 1937, 0, 1024, 768
        !            61: };
        !            62:
        !            63: struct uts_softc {
        !            64:        struct device           sc_dev;
        !            65:        usbd_device_handle      sc_udev;
        !            66:        usbd_interface_handle   sc_iface;
        !            67:        int                     sc_iface_number;
        !            68:        int                     sc_product;
        !            69:        int                     sc_vendor;
        !            70:
        !            71:        int                     sc_intr_number;
        !            72:        usbd_pipe_handle        sc_intr_pipe;
        !            73:        u_char                  *sc_ibuf;
        !            74:        int                     sc_isize;
        !            75:        u_int8_t                sc_pkts;
        !            76:
        !            77:        struct device           *sc_wsmousedev;
        !            78:
        !            79:        int     sc_enabled;
        !            80:        int     sc_buttons;
        !            81:        int     sc_dying;
        !            82:        int     sc_oldx;
        !            83:        int     sc_oldy;
        !            84:        int     sc_rawmode;
        !            85:
        !            86:        struct tsscale sc_tsscale;
        !            87: };
        !            88:
        !            89: struct uts_pos {
        !            90:        int     x;
        !            91:        int     y;
        !            92:        int     z;      /* touch pressure */
        !            93: };
        !            94:
        !            95: const struct usb_devno uts_devs[] = {
        !            96:        { USB_VENDOR_FTDI,              USB_PRODUCT_FTDI_ITM_TOUCH },
        !            97:        { USB_VENDOR_EGALAX,            USB_PRODUCT_EGALAX_TPANEL },
        !            98:        { USB_VENDOR_EGALAX,            USB_PRODUCT_EGALAX_TPANEL2 },
        !            99:        { USB_VENDOR_GUNZE,             USB_PRODUCT_GUNZE_TOUCHPANEL }
        !           100: };
        !           101:
        !           102: void uts_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
        !           103: struct uts_pos uts_get_pos(usbd_private_handle addr, struct uts_pos tp);
        !           104:
        !           105: int    uts_enable(void *);
        !           106: void   uts_disable(void *);
        !           107: int    uts_ioctl(void *, u_long, caddr_t, int, struct proc *);
        !           108:
        !           109: const struct wsmouse_accessops uts_accessops = {
        !           110:        uts_enable,
        !           111:        uts_ioctl,
        !           112:        uts_disable,
        !           113: };
        !           114:
        !           115: int uts_match(struct device *, void *, void *);
        !           116: void uts_attach(struct device *, struct device *, void *);
        !           117: int uts_detach(struct device *, int);
        !           118: int uts_activate(struct device *, enum devact);
        !           119:
        !           120: struct cfdriver uts_cd = {
        !           121:        NULL, "uts", DV_DULL
        !           122: };
        !           123:
        !           124: const struct cfattach uts_ca = {
        !           125:        sizeof(struct uts_softc),
        !           126:        uts_match,
        !           127:        uts_attach,
        !           128:        uts_detach,
        !           129:        uts_activate,
        !           130: };
        !           131:
        !           132: int
        !           133: uts_match(struct device *parent, void *match, void *aux)
        !           134: {
        !           135:        struct usb_attach_arg *uaa = aux;
        !           136:
        !           137:        if (uaa->iface == NULL)
        !           138:                return UMATCH_NONE;
        !           139:
        !           140:        return (usb_lookup(uts_devs, uaa->vendor, uaa->product) != NULL) ?
        !           141:                UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
        !           142: }
        !           143:
        !           144: void
        !           145: uts_attach(struct device *parent, struct device *self, void *aux)
        !           146: {
        !           147:        struct uts_softc *sc = (struct uts_softc *)self;
        !           148:        struct usb_attach_arg *uaa = aux;
        !           149:        usb_config_descriptor_t *cdesc;
        !           150:        usb_interface_descriptor_t *id;
        !           151:        usb_endpoint_descriptor_t *ed;
        !           152:        struct wsmousedev_attach_args a;
        !           153:        char *devinfop;
        !           154:        int i, found;
        !           155:
        !           156:        sc->sc_udev = uaa->device;
        !           157:        sc->sc_product = uaa->product;
        !           158:        sc->sc_vendor = uaa->vendor;
        !           159:        sc->sc_intr_number = -1;
        !           160:        sc->sc_intr_pipe = NULL;
        !           161:        sc->sc_enabled = sc->sc_isize = 0;
        !           162:
        !           163:        /* Copy the default scalue values to each softc */
        !           164:        bcopy(&def_scale, &sc->sc_tsscale, sizeof(sc->sc_tsscale));
        !           165:
        !           166:        /* Display device info string */
        !           167:        printf("\n");
        !           168:        devinfop = usbd_devinfo_alloc(uaa->device, 0);
        !           169:        printf("%s: %s\n", sc->sc_dev.dv_xname, devinfop);
        !           170:        usbd_devinfo_free(devinfop);
        !           171:
        !           172:        /* Move the device into the configured state. */
        !           173:        if (usbd_set_config_index(uaa->device, UTS_CONFIG_INDEX, 1) != 0) {
        !           174:                printf("%s: could not set configuartion no\n",
        !           175:                        sc->sc_dev.dv_xname);
        !           176:                sc->sc_dying = 1;
        !           177:                return;
        !           178:        }
        !           179:
        !           180:        /* get the config descriptor */
        !           181:        cdesc = usbd_get_config_descriptor(sc->sc_udev);
        !           182:        if (cdesc == NULL) {
        !           183:                printf("%s: failed to get configuration descriptor\n",
        !           184:                        sc->sc_dev.dv_xname);
        !           185:                sc->sc_dying = 1;
        !           186:                return;
        !           187:        }
        !           188:
        !           189:        /* get the interface */
        !           190:        if (usbd_device2interface_handle(uaa->device, 0, &sc->sc_iface) != 0) {
        !           191:                printf("%s: failed to get interface\n",
        !           192:                        sc->sc_dev.dv_xname);
        !           193:                sc->sc_dying = 1;
        !           194:                return;
        !           195:        }
        !           196:
        !           197:        /* Find the interrupt endpoint */
        !           198:        id = usbd_get_interface_descriptor(sc->sc_iface);
        !           199:        sc->sc_iface_number = id->bInterfaceNumber;
        !           200:        found = 0;
        !           201:
        !           202:        for (i = 0; i < id->bNumEndpoints; i++) {
        !           203:                ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
        !           204:                if (ed == NULL) {
        !           205:                        printf("%s: no endpoint descriptor for %d\n",
        !           206:                                sc->sc_dev.dv_xname, i);
        !           207:                        sc->sc_dying = 1;
        !           208:                        return;
        !           209:                }
        !           210:
        !           211:                if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
        !           212:                    UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
        !           213:                        sc->sc_intr_number = ed->bEndpointAddress;
        !           214:                        sc->sc_isize = UGETW(ed->wMaxPacketSize);
        !           215:                }
        !           216:        }
        !           217:
        !           218:        if (sc->sc_intr_number== -1) {
        !           219:                printf("%s: Could not find interrupt in\n",
        !           220:                        sc->sc_dev.dv_xname);
        !           221:                sc->sc_dying = 1;
        !           222:                return;
        !           223:        }
        !           224:
        !           225:        usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
        !           226:                           &sc->sc_dev);
        !           227:
        !           228:        a.accessops = &uts_accessops;
        !           229:        a.accesscookie = sc;
        !           230:
        !           231:        sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
        !           232: }
        !           233:
        !           234: int
        !           235: uts_detach(struct device *self, int flags)
        !           236: {
        !           237:        struct uts_softc *sc = (struct uts_softc *)self;
        !           238:        int rv = 0;
        !           239:
        !           240:        if (sc->sc_intr_pipe != NULL) {
        !           241:                usbd_abort_pipe(sc->sc_intr_pipe);
        !           242:                usbd_close_pipe(sc->sc_intr_pipe);
        !           243:                sc->sc_intr_pipe = NULL;
        !           244:        }
        !           245:
        !           246:        sc->sc_dying = 1;
        !           247:
        !           248:        if (sc->sc_wsmousedev != NULL) {
        !           249:                rv = config_detach(sc->sc_wsmousedev, flags);
        !           250:                sc->sc_wsmousedev = NULL;
        !           251:        }
        !           252:
        !           253:        usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
        !           254:                           &sc->sc_dev);
        !           255:
        !           256:        return (rv);
        !           257: }
        !           258:
        !           259: int
        !           260: uts_activate(struct device *self, enum devact act)
        !           261: {
        !           262:        struct uts_softc *sc = (struct uts_softc *)self;
        !           263:        int rv = 0;
        !           264:
        !           265:        switch (act) {
        !           266:        case DVACT_ACTIVATE:
        !           267:                break;
        !           268:
        !           269:        case DVACT_DEACTIVATE:
        !           270:                if (sc->sc_wsmousedev != NULL)
        !           271:                        rv = config_deactivate(sc->sc_wsmousedev);
        !           272:                sc->sc_dying = 1;
        !           273:                break;
        !           274:        }
        !           275:
        !           276:        return (rv);
        !           277: }
        !           278:
        !           279: int
        !           280: uts_enable(void *v)
        !           281: {
        !           282:        struct uts_softc *sc = v;
        !           283:        int err;
        !           284:
        !           285:        if (sc->sc_dying)
        !           286:                return (EIO);
        !           287:
        !           288:        if (sc->sc_enabled)
        !           289:                return (EBUSY);
        !           290:
        !           291:        if (sc->sc_isize == 0)
        !           292:                return 0;
        !           293:        sc->sc_ibuf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
        !           294:        err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_intr_number,
        !           295:                USBD_SHORT_XFER_OK, &sc->sc_intr_pipe, sc, sc->sc_ibuf,
        !           296:                sc->sc_isize, uts_intr, USBD_DEFAULT_INTERVAL);
        !           297:        if (err) {
        !           298:                free(sc->sc_ibuf, M_USBDEV);
        !           299:                sc->sc_intr_pipe = NULL;
        !           300:                return EIO;
        !           301:        }
        !           302:
        !           303:        sc->sc_enabled = 1;
        !           304:        sc->sc_buttons = 0;
        !           305:
        !           306:        return (0);
        !           307: }
        !           308:
        !           309: void
        !           310: uts_disable(void *v)
        !           311: {
        !           312:        struct uts_softc *sc = v;
        !           313:
        !           314:        if (!sc->sc_enabled) {
        !           315:                printf("uts_disable: already disabled!\n");
        !           316:                return;
        !           317:        }
        !           318:
        !           319:        /* Disable interrupts. */
        !           320:        if (sc->sc_intr_pipe != NULL) {
        !           321:                usbd_abort_pipe(sc->sc_intr_pipe);
        !           322:                usbd_close_pipe(sc->sc_intr_pipe);
        !           323:                sc->sc_intr_pipe = NULL;
        !           324:        }
        !           325:
        !           326:        if (sc->sc_ibuf != NULL) {
        !           327:                free(sc->sc_ibuf, M_USBDEV);
        !           328:                sc->sc_ibuf = NULL;
        !           329:        }
        !           330:
        !           331:        sc->sc_enabled = 0;
        !           332: }
        !           333:
        !           334: int
        !           335: uts_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *l)
        !           336: {
        !           337:        int error = 0;
        !           338:        struct uts_softc *sc = v;
        !           339:        struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
        !           340:
        !           341:        DPRINTF(("uts_ioctl(%d, '%c', %d)\n",
        !           342:            IOCPARM_LEN(cmd), IOCGROUP(cmd), cmd & 0xff));
        !           343:
        !           344:        switch (cmd) {
        !           345:        case WSMOUSEIO_SCALIBCOORDS:
        !           346:                if (!(wsmc->minx >= 0 && wsmc->maxx >= 0 &&
        !           347:                    wsmc->miny >= 0 && wsmc->maxy >= 0 &&
        !           348:                    wsmc->resx >= 0 && wsmc->resy >= 0 &&
        !           349:                    wsmc->minx < 32768 && wsmc->maxx < 32768 &&
        !           350:                    wsmc->miny < 32768 && wsmc->maxy < 32768 &&
        !           351:                    wsmc->resx < 32768 && wsmc->resy < 32768 &&
        !           352:                    wsmc->swapxy >= 0 && wsmc->swapxy <= 1 &&
        !           353:                    wsmc->samplelen >= 0 && wsmc->samplelen <= 1))
        !           354:                        return (EINVAL);
        !           355:
        !           356:                sc->sc_tsscale.minx = wsmc->minx;
        !           357:                sc->sc_tsscale.maxx = wsmc->maxx;
        !           358:                sc->sc_tsscale.miny = wsmc->miny;
        !           359:                sc->sc_tsscale.maxy = wsmc->maxy;
        !           360:                sc->sc_tsscale.swapxy = wsmc->swapxy;
        !           361:                sc->sc_tsscale.resx = wsmc->resx;
        !           362:                sc->sc_tsscale.resy = wsmc->resy;
        !           363:                sc->sc_rawmode = wsmc->samplelen;
        !           364:                break;
        !           365:        case WSMOUSEIO_GCALIBCOORDS:
        !           366:                wsmc->minx = sc->sc_tsscale.minx;
        !           367:                wsmc->maxx = sc->sc_tsscale.maxx;
        !           368:                wsmc->miny = sc->sc_tsscale.miny;
        !           369:                wsmc->maxy = sc->sc_tsscale.maxy;
        !           370:                wsmc->swapxy = sc->sc_tsscale.swapxy;
        !           371:                wsmc->resx = sc->sc_tsscale.resx;
        !           372:                wsmc->resy = sc->sc_tsscale.resy;
        !           373:                wsmc->samplelen = sc->sc_rawmode;
        !           374:                break;
        !           375:        case WSMOUSEIO_GTYPE:
        !           376:                *(u_int *)data = WSMOUSE_TYPE_TPANEL;
        !           377:                break;
        !           378:        default:
        !           379:                error = ENOTTY;
        !           380:                break;
        !           381:        }
        !           382:
        !           383:        return (error);
        !           384: }
        !           385:
        !           386: struct uts_pos
        !           387: uts_get_pos(usbd_private_handle addr, struct uts_pos tp)
        !           388: {
        !           389:        struct uts_softc *sc = addr;
        !           390:        u_char *p = sc->sc_ibuf;
        !           391:        int down, x, y;
        !           392:
        !           393:        switch (sc->sc_product) {
        !           394:        case USB_PRODUCT_FTDI_ITM_TOUCH:
        !           395:                down = (~p[7] & 0x20);
        !           396:                x = ((p[0] & 0x1f) << 7) | (p[3] & 0x7f);
        !           397:                /* Invert the Y coordinate */
        !           398:                y = 0x0fff - abs(((p[1] & 0x1f) << 7) | (p[4] & 0x7f));
        !           399:                sc->sc_pkts = 0x8;
        !           400:                break;
        !           401:        case USB_PRODUCT_EGALAX_TPANEL:
        !           402:        case USB_PRODUCT_EGALAX_TPANEL2:
        !           403:                /*
        !           404:                 * eGalax and Gunze USB touch panels have the same device ID,
        !           405:                 * so decide upon the vendor ID.
        !           406:                 */
        !           407:                switch (sc->sc_vendor) {
        !           408:                case USB_VENDOR_EGALAX:
        !           409:                        down = (p[0] & 0x01);
        !           410:                        /* Invert the X coordiate */
        !           411:                        x = 0x07ff - abs(((p[3] & 0x0f) << 7) | (p[4] & 0x7f));
        !           412:                        y = ((p[1] & 0x0f) << 7) | (p[2] & 0x7f);
        !           413:                        sc->sc_pkts = 0x5;
        !           414:                        break;
        !           415:                case USB_VENDOR_GUNZE:
        !           416:                        down = (~p[7] & 0x20);
        !           417:                        /* Invert the X coordinate */
        !           418:                        x = 0x0fff - abs(((p[0] & 0x1f) << 7) | (p[2] & 0x7f));
        !           419:                        y = ((p[1] & 0x1f) << 7) | (p[3] & 0x7f);
        !           420:                        sc->sc_pkts = 0x4;
        !           421:                        break;
        !           422:                }
        !           423:                break;
        !           424:        }
        !           425:
        !           426:        DPRINTF(("%s: down = 0x%x, sc->sc_pkts = 0x%x\n",
        !           427:            sc->sc_dev.dv_xname, down, sc->sc_pkts));
        !           428:
        !           429:        /* x/y values are not reliable if there is no pressure */
        !           430:        if (down) {
        !           431:                if (sc->sc_tsscale.swapxy) {    /* Swap X/Y-Axis */
        !           432:                        tp.y = x;
        !           433:                        tp.x = y;
        !           434:                } else {
        !           435:                        tp.x = x;
        !           436:                        tp.y = y;
        !           437:                }
        !           438:
        !           439:                if (!sc->sc_rawmode) {
        !           440:                        /* Scale down to the screen resolution. */
        !           441:                        tp.x = ((tp.x - sc->sc_tsscale.minx) *
        !           442:                            sc->sc_tsscale.resx) /
        !           443:                            (sc->sc_tsscale.maxx - sc->sc_tsscale.minx);
        !           444:                        tp.y = ((tp.y - sc->sc_tsscale.miny) *
        !           445:                            sc->sc_tsscale.resy) /
        !           446:                            (sc->sc_tsscale.maxy - sc->sc_tsscale.miny);
        !           447:                }
        !           448:                tp.z = 1;
        !           449:        } else {
        !           450:                tp.x = sc->sc_oldx;
        !           451:                tp.y = sc->sc_oldy;
        !           452:                tp.z = 0;
        !           453:        }
        !           454:
        !           455:        return (tp);
        !           456: }
        !           457:
        !           458: void
        !           459: uts_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status)
        !           460: {
        !           461:        struct uts_softc *sc = addr;
        !           462:        u_int32_t len;
        !           463:        int s;
        !           464:        struct uts_pos tp;
        !           465:
        !           466:        usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL);
        !           467:
        !           468:        s = spltty();
        !           469:
        !           470:        if (status == USBD_CANCELLED)
        !           471:                return;
        !           472:
        !           473:        if (status != USBD_NORMAL_COMPLETION) {
        !           474:                printf("%s: status %d\n", sc->sc_dev.dv_xname, status);
        !           475:                usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
        !           476:                return;
        !           477:        }
        !           478:
        !           479:        tp = uts_get_pos(sc, tp);
        !           480:
        !           481:        if (len != sc->sc_pkts) {
        !           482:                DPRINTF(("%s: bad input length %d != %d\n",
        !           483:                        sc->sc_dev.dv_xname, len, sc->sc_isize));
        !           484:                return;
        !           485:        }
        !           486:
        !           487:        DPRINTF(("%s: tp.z = %d, tp.x = %d, tp.y = %d\n",
        !           488:            sc->sc_dev.dv_xname, tp.z, tp.x, tp.y));
        !           489:
        !           490:        wsmouse_input(sc->sc_wsmousedev, tp.z, tp.x, tp.y, 0, 0,
        !           491:                WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y |
        !           492:                WSMOUSE_INPUT_ABSOLUTE_Z);
        !           493:        sc->sc_oldy = tp.y;
        !           494:        sc->sc_oldx = tp.x;
        !           495:
        !           496:        splx(s);
        !           497: }

CVSweb