diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/alpha/conf/GENERIC | 13 | ||||
-rw-r--r-- | sys/arch/i386/conf/GENERIC | 11 | ||||
-rw-r--r-- | sys/arch/macppc/conf/GENERIC | 9 | ||||
-rw-r--r-- | sys/arch/sparc64/conf/GENERIC | 13 | ||||
-rw-r--r-- | sys/dev/usb/files.usb | 43 | ||||
-rw-r--r-- | sys/dev/usb/hid.c | 143 | ||||
-rw-r--r-- | sys/dev/usb/hid.h | 21 | ||||
-rw-r--r-- | sys/dev/usb/uhid.c | 349 | ||||
-rw-r--r-- | sys/dev/usb/uhidev.c | 513 | ||||
-rw-r--r-- | sys/dev/usb/uhidev.h | 91 | ||||
-rw-r--r-- | sys/dev/usb/ukbd.c | 492 | ||||
-rw-r--r-- | sys/dev/usb/ums.c | 197 | ||||
-rw-r--r-- | sys/dev/usb/usb.h | 3 | ||||
-rw-r--r-- | sys/dev/usb/usb_port.h | 5 | ||||
-rw-r--r-- | sys/dev/usb/usbhid.h | 19 |
15 files changed, 1146 insertions, 776 deletions
diff --git a/sys/arch/alpha/conf/GENERIC b/sys/arch/alpha/conf/GENERIC index 0554e38ec4d..dbb5409547f 100644 --- a/sys/arch/alpha/conf/GENERIC +++ b/sys/arch/alpha/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.106 2002/05/02 22:56:06 miod Exp $ +# $OpenBSD: GENERIC,v 1.107 2002/05/09 15:06:29 nate Exp $ # $NetBSD: GENERIC,v 1.31 1996/12/03 17:25:29 cgd Exp $ machine alpha @@ -53,7 +53,12 @@ usb* at ohci? uhub* at usb? # USB Hubs uhub* at uhub? port ? configuration ? # USB Hubs -uhid* at uhub? port ? configuration ? # USB Generic HID devices +uhidev* at uhub? port ? configuration ? interface ? +ums* at uhidev? reportid ? # USB Mice +wsmouse* at ums? mux 0 +ukbd* at uhidev? reportid ? # USB Keyboards +wskbd* at ukbd? console ? mux 1 +uhid* at uhidev? reportid ? # USB Generic HID devices umodem* at uhub? port ? configuration ? # USB Modems/Serial ucom* at umodem? uvisor* at uhub? port ? configuration ? # Handspring Visor @@ -62,12 +67,8 @@ uftdi* at uhub? port ? ucom* at uftdi? portno ? uaudio* at uhub? port ? configuration ? # USB Audio ulpt* at uhub? port ? configuration ? # USB Printers -ukbd* at uhub? port ? configuration ? # USB Keyboards -wskbd* at ukbd? console ? umass* at uhub? port ? configuration ? # USB Mass Storage devices scsibus* at umass? -ums* at uhub? port ? configuration ? # USB Mice -wsmouse* at ums? aue* at uhub? port ? # ADMtek AN986 Pegasus Ethernet cue* at uhub? port ? # CATC USB-EL1201A based Ethernet kue* at uhub? port ? # Kawasaki KL5KUSB101B based Ethernet diff --git a/sys/arch/i386/conf/GENERIC b/sys/arch/i386/conf/GENERIC index a4c67416c0f..7fd663c9d9e 100644 --- a/sys/arch/i386/conf/GENERIC +++ b/sys/arch/i386/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.297 2002/05/07 19:42:34 nate Exp $ +# $OpenBSD: GENERIC,v 1.298 2002/05/09 15:06:29 nate Exp $ # $NetBSD: GENERIC,v 1.48 1996/05/20 18:17:23 mrg Exp $ # # GENERIC -- everything that's currently supported @@ -91,7 +91,6 @@ usb* at ohci? uhub* at usb? # USB Hubs uhub* at uhub? port ? configuration ? # USB Hubs -uhid* at uhub? port ? configuration ? # USB Generic HID devices umodem* at uhub? port ? configuration ? # USB Modems/Serial ucom* at umodem? uvisor* at uhub? port ? configuration ? # Handspring Visor @@ -103,12 +102,14 @@ ucom* at uplcom? portno ? uaudio* at uhub? port ? configuration ? # USB Audio ulpt* at uhub? port ? configuration ? # USB Printers -ukbd* at uhub? port ? configuration ? # USB Keyboards -wskbd* at ukbd? console ? mux 1 umass* at uhub? port ? configuration ? # USB Mass Storage devices scsibus* at umass? -ums* at uhub? port ? configuration ? # USB Mice +uhidev* at uhub? port ? configuration ? interface ? +ums* at uhidev? reportid ? wsmouse* at ums? mux 0 +ukbd* at uhidev? reportid ? +wskbd* at ukbd? console ? mux 1 +uhid* at uhidev? reportid ? aue* at uhub? port ? # ADMtek AN986 Pegasus Ethernet cue* at uhub? port ? # CATC USB-EL1201A based Ethernet kue* at uhub? port ? # Kawasaki KL5KUSB101B based Ethernet diff --git a/sys/arch/macppc/conf/GENERIC b/sys/arch/macppc/conf/GENERIC index 7febcd75f87..13c4cce8b0b 100644 --- a/sys/arch/macppc/conf/GENERIC +++ b/sys/arch/macppc/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.22 2002/04/08 17:02:44 drahn Exp $g +# $OpenBSD: GENERIC,v 1.23 2002/05/09 15:06:29 nate Exp $g # # PPC GENERIC config file # @@ -143,9 +143,10 @@ usb* at ohci? flags 0x1 uhub* at usb? uhub* at uhub? port ? configuration ? interface ? -uhid* at uhub? port ? configuration ? # USB Generic HID devices -ukbd* at uhub? port ? configuration ? # USB HID Keyboard devices -ums* at uhub? port ? configuration ? # USB Mice +uhidev* at uhub? port ? configuration ? interface ? +uhid* at uhidev? reportid ? # USB Generic HID devices +ukbd* at uhidev? reportid ? # USB HID Keyboard devices +ums* at uhidev? reportid ? # USB Mice wsmouse* at ums? mux 0 uaudio* at uhub? port ? configuration ? # USB Audio ulpt* at uhub? port ? configuration ? # USB Printer diff --git a/sys/arch/sparc64/conf/GENERIC b/sys/arch/sparc64/conf/GENERIC index 8ace8ace53d..253578f0bcf 100644 --- a/sys/arch/sparc64/conf/GENERIC +++ b/sys/arch/sparc64/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.58 2002/04/18 14:15:11 jason Exp $ +# $OpenBSD: GENERIC,v 1.59 2002/05/09 15:06:29 nate Exp $ # $NetBSD: GENERIC32,v 1.18 2001/07/20 00:07:12 eeh Exp $ machine sparc64 @@ -60,11 +60,12 @@ usb* at ohci? flags 0x1 # USB devices uhub* at usb? uhub* at uhub? port ? configuration ? -ukbd* at uhub? # USB keyboard -wskbd* at ukbd? console ? -ums* at uhub? port ? configuration ? # USB mouse -wsmouse* at ums? -uhid* at uhub? port ? configuration ? # USB generic human interface +uhidev* at uhub? port ? configuration ? interface ? +ukbd* at uhidev? reportid ? +wskbd* at ukbd? console ? mux 1 +ums* at uhidev? reportid ? +wsmouse* at ums? mux 0 +uhid* at uhidev? reportid ? ugen* at uhub? port ? configuration ? # USB generic device #### Standard system devices -- all required for a given architecture diff --git a/sys/dev/usb/files.usb b/sys/dev/usb/files.usb index 5936f8fc971..f5fd7406e34 100644 --- a/sys/dev/usb/files.usb +++ b/sys/dev/usb/files.usb @@ -1,4 +1,4 @@ -# $OpenBSD: files.usb,v 1.24 2002/05/07 19:32:49 nate Exp $ +# $OpenBSD: files.usb,v 1.25 2002/05/09 15:06:29 nate Exp $ # $NetBSD: files.usb,v 1.16 2000/02/14 20:29:54 augustss Exp $ # # Config file and device description for machine-independent USB code. @@ -7,7 +7,6 @@ device usb { } attach usb at usbus -file dev/usb/hid.c usb file dev/usb/usb.c usb needs-flag file dev/usb/usbdi.c usb file dev/usb/usbdi_util.c usb @@ -45,16 +44,35 @@ device ugen attach ugen at uhub file dev/usb/ugen.c ugen needs-flag -# Generic HID devices -device uhid -attach uhid at uhub -file dev/usb/uhid.c uhid needs-flag +# HID +# HID "bus" +define uhidbus {[ reportid = -1 ]} + +# HID processing +define hid +file dev/usb/hid.c hid +# HID root device for multiple report IDs +device uhidev: hid, uhidbus +attach uhidev at uhub +file dev/usb/uhidev.c uhidev + +# Generic HID devices +device uhid: hid +attach uhid at uhidbus +file dev/usb/uhid.c uhid needs-flag + # Keyboards -device ukbd: wskbddev -attach ukbd at uhub -file dev/usb/ukbd.c ukbd needs-flag -file dev/usb/ukbdmap.c ukbd +device ukbd: hid, wskbddev +attach ukbd at uhidbus +file dev/usb/ukbd.c ukbd needs-flag +file dev/usb/ukbdmap.c ukbd + +# Mice +device ums: hid, wsmousedev +attach ums at uhidbus +file dev/usb/ums.c ums + # Printers device ulpt @@ -71,11 +89,6 @@ device umodem: ucombus attach umodem at uhub file dev/usb/umodem.c umodem -# Mice -device ums: wsmousedev -attach ums at uhub -file dev/usb/ums.c ums - # Diamond Multimedia Rio 500 device urio attach urio at uhub diff --git a/sys/dev/usb/hid.c b/sys/dev/usb/hid.c index d14721fe107..81deacbd866 100644 --- a/sys/dev/usb/hid.c +++ b/sys/dev/usb/hid.c @@ -1,5 +1,5 @@ -/* $OpenBSD: hid.c,v 1.11 2002/05/07 18:29:18 nate Exp $ */ -/* $NetBSD: hid.c,v 1.16 2000/06/01 14:28:57 augustss Exp $ */ +/* $OpenBSD: hid.c,v 1.12 2002/05/09 15:06:29 nate Exp $ */ +/* $NetBSD: hid.c,v 1.22 2002/01/12 17:11:03 tsutsui Exp $ */ /* $FreeBSD: src/sys/dev/usb/hid.c,v 1.11 1999/11/17 22:33:39 n_hibma Exp $ */ /* @@ -51,10 +51,10 @@ #include <dev/usb/hid.h> -#ifdef UHID_DEBUG -#define DPRINTF(x) if (usbdebug) logprintf x -#define DPRINTFN(n,x) if (usbdebug>(n)) logprintf x -extern int usbdebug; +#ifdef UHIDEV_DEBUG +#define DPRINTF(x) if (uhidevdebug) logprintf x +#define DPRINTFN(n,x) if (uhidevdebug>(n)) logprintf x +extern int uhidevdebug; #else #define DPRINTF(x) #define DPRINTFN(n,x) @@ -62,7 +62,7 @@ extern int usbdebug; Static void hid_clear_local(struct hid_item *); -#define MAXUSAGE 100 +#define MAXUSAGE 256 struct hid_data { u_char *start; u_char *end; @@ -73,13 +73,14 @@ struct hid_data { int minset; int multi; int multimax; - int kindset; + enum hid_kind kind; }; Static void hid_clear_local(struct hid_item *c) { + DPRINTFN(5,("hid_clear_local\n")); c->usage = 0; c->usage_minimum = 0; c->usage_maximum = 0; @@ -93,15 +94,18 @@ hid_clear_local(struct hid_item *c) } struct hid_data * -hid_start_parse(void *d, int len, int kindset) +hid_start_parse(void *d, int len, enum hid_kind kind) { struct hid_data *s; s = malloc(sizeof *s, M_TEMP, M_WAITOK); + if (s == NULL) + panic("hid_start_parse"); memset(s, 0, sizeof *s); + s->start = s->p = d; s->end = (char *)d + len; - s->kindset = kindset; + s->kind = kind; return (s); } @@ -128,15 +132,19 @@ hid_get_item(struct hid_data *s, struct hid_item *h) u_char *p; struct hid_item *hi; int i; + enum hid_kind retkind; top: + DPRINTFN(5,("hid_get_item: multi=%d multimax=%d\n", + s->multi, s->multimax)); if (s->multimax != 0) { if (s->multi < s->multimax) { c->usage = s->usages[min(s->multi, s->nu-1)]; s->multi++; *h = *c; c->loc.pos += c->loc.size; - h->next = 0; + h->next = NULL; + DPRINTFN(5,("return multi\n")); return (1); } else { c->loc.count = s->multimax; @@ -174,12 +182,12 @@ hid_get_item(struct hid_data *s, struct hid_item *h) dval = 0; break; case 1: - dval = (int8_t)*data++; + dval = /*(int8_t)*/ *data++; break; case 2: dval = *data++; dval |= *data++ << 8; - dval = (int16_t)dval; + dval = /*(int16_t)*/ dval; break; case 4: dval = *data++; @@ -192,15 +200,22 @@ hid_get_item(struct hid_data *s, struct hid_item *h) continue; } + DPRINTFN(5,("hid_get_item: bType=%d bTag=%d dval=%d\n", + bType, bTag, dval)); switch (bType) { case 0: /* Main */ switch (bTag) { case 8: /* Input */ - if (!(s->kindset & (1 << hid_input))) + retkind = hid_input; + ret: + if (s->kind != retkind) { + s->minset = 0; + s->nu = 0; + hid_clear_local(c); continue; - c->kind = hid_input; + } + c->kind = retkind; c->flags = dval; - ret: if (c->flags & HIO_VARIABLE) { s->multimax = c->loc.count; s->multi = 0; @@ -217,19 +232,18 @@ hid_get_item(struct hid_data *s, struct hid_item *h) } goto top; } else { + c->usage = c->_usage_page; /* XXX */ *h = *c; - h->next = 0; + h->next = NULL; c->loc.pos += - c->loc.size * c->loc.count; - hid_clear_local(c); + c->loc.size * c->loc.count; s->minset = 0; + s->nu = 0; + hid_clear_local(c); return (1); } case 9: /* Output */ - if (!(s->kindset & (1 << hid_output))) - continue; - c->kind = hid_output; - c->flags = dval; + retkind = hid_output; goto ret; case 10: /* Collection */ c->kind = hid_collection; @@ -240,16 +254,12 @@ hid_get_item(struct hid_data *s, struct hid_item *h) s->nu = 0; return (1); case 11: /* Feature */ - if (!(s->kindset & (1 << hid_feature))) - continue; - c->kind = hid_feature; - c->flags = dval; + retkind = hid_feature; goto ret; case 12: /* End collection */ c->kind = hid_endcollection; c->collevel--; *h = *c; - hid_clear_local(c); s->nu = 0; return (1); default: @@ -285,6 +295,7 @@ hid_get_item(struct hid_data *s, struct hid_item *h) break; case 8: c->report_ID = dval; + c->loc.pos = 0; break; case 9: c->loc.count = dval; @@ -367,35 +378,51 @@ hid_get_item(struct hid_data *s, struct hid_item *h) } int -hid_report_size(void *buf, int len, enum hid_kind k, u_int8_t *idp) +hid_report_size(void *buf, int len, enum hid_kind k, u_int8_t id) { struct hid_data *d; struct hid_item h; - int size, id; + int lo, hi; - id = 0; - for (d = hid_start_parse(buf, len, 1<<k); hid_get_item(d, &h); ) - if (h.report_ID != 0) - id = h.report_ID; + h.report_ID = 0; + lo = hi = -1; + DPRINTFN(2,("hid_report_size: kind=%d id=%d\n", k, id)); + for (d = hid_start_parse(buf, len, k); hid_get_item(d, &h); ) { + DPRINTFN(2,("hid_report_size: item kind=%d id=%d pos=%d " + "size=%d count=%d\n", + h.kind, h.report_ID, h.loc.pos, h.loc.size, + h.loc.count)); + if (h.report_ID == id && h.kind == k) { + if (lo < 0) { + lo = h.loc.pos; +#ifdef DIAGNOSTIC + if (lo != 0) { + printf("hid_report_size: lo != 0\n"); + } +#endif + } + hi = h.loc.pos + h.loc.size * h.loc.count; + DPRINTFN(2,("hid_report_size: lo=%d hi=%d\n", lo, hi)); + } + } hid_end_parse(d); - size = h.loc.pos; - if (id != 0) { - size += 8; - *idp = id; /* XXX wrong */ - } else - *idp = 0; - return ((size + 7) / 8); + return ((hi - lo + 7) / 8); } int -hid_locate(void *desc, int size, u_int32_t u, enum hid_kind k, +hid_locate(void *desc, int size, u_int32_t u, u_int8_t id, enum hid_kind k, struct hid_location *loc, u_int32_t *flags) { struct hid_data *d; struct hid_item h; - for (d = hid_start_parse(desc, size, 1<<k); hid_get_item(d, &h); ) { - if (h.kind == k && !(h.flags & HIO_CONST) && h.usage == u) { + h.report_ID = 0; + DPRINTFN(5,("hid_locate: enter usage=0x%x kind=%d id=%d\n", u, k, id)); + for (d = hid_start_parse(desc, size, k); hid_get_item(d, &h); ) { + DPRINTFN(5,("hid_locate: usage=0x%x kind=%d id=%d flags=0x%x\n", + h.usage, h.kind, h.report_ID, h.flags)); + if (h.kind == k && !(h.flags & HIO_CONST) && + h.usage == u && h.report_ID == id) { if (loc != NULL) *loc = h.loc; if (flags != NULL) @@ -437,19 +464,33 @@ hid_get_data(u_char *buf, struct hid_location *loc) } int -hid_is_collection(void *desc, int size, u_int32_t usage) +hid_is_collection(void *desc, int size, u_int8_t id, u_int32_t usage) { struct hid_data *hd; struct hid_item hi; - int err; + u_int32_t coll_usage = ~0; - hd = hid_start_parse(desc, size, hid_input); + hd = hid_start_parse(desc, size, hid_none); if (hd == NULL) return (0); - err = hid_get_item(hd, &hi) && - hi.kind == hid_collection && - hi.usage == usage; + DPRINTFN(2,("hid_is_collection: id=%d usage=0x%x\n", id, usage)); + while (hid_get_item(hd, &hi)) { + DPRINTFN(2,("hid_is_collection: kind=%d id=%d usage=0x%x" + "(0x%x)\n", + hi.kind, hi.report_ID, hi.usage, coll_usage)); + if (hi.kind == hid_collection && + hi.collection == HCOLL_APPLICATION) + coll_usage = hi.usage; + if (hi.kind == hid_endcollection && + coll_usage == usage && + hi.report_ID == id) { + DPRINTFN(2,("hid_is_collection: found\n")); + hid_end_parse(hd); + return (1); + } + } + DPRINTFN(2,("hid_is_collection: not found\n")); hid_end_parse(hd); - return (err); + return (0); } diff --git a/sys/dev/usb/hid.h b/sys/dev/usb/hid.h index 096a34e270f..18dac5988e5 100644 --- a/sys/dev/usb/hid.h +++ b/sys/dev/usb/hid.h @@ -1,5 +1,5 @@ -/* $OpenBSD: hid.h,v 1.6 2002/05/07 18:29:18 nate Exp $ */ -/* $NetBSD: hid.h,v 1.6 2000/06/01 14:28:57 augustss Exp $ */ +/* $OpenBSD: hid.h,v 1.7 2002/05/09 15:06:29 nate Exp $ */ +/* $NetBSD: hid.h,v 1.7 2001/12/28 17:32:36 augustss Exp $ */ /* $FreeBSD: src/sys/dev/usb/hid.h,v 1.7 1999/11/17 22:33:40 n_hibma Exp $ */ /* @@ -40,7 +40,12 @@ */ enum hid_kind { - hid_input, hid_output, hid_feature, hid_collection, hid_endcollection + hid_input, + hid_output, + hid_feature, + hid_collection, + hid_endcollection, + hid_none }; struct hid_location { @@ -81,11 +86,11 @@ struct hid_item { struct hid_item *next; }; -struct hid_data *hid_start_parse(void *d, int len, int kindset); +struct hid_data *hid_start_parse(void *d, int len, enum hid_kind kind); void hid_end_parse(struct hid_data *s); int hid_get_item(struct hid_data *s, struct hid_item *h); -int hid_report_size(void *buf, int len, enum hid_kind k, u_int8_t *id); -int hid_locate(void *desc, int size, u_int32_t usage, enum hid_kind kind, - struct hid_location *loc, u_int32_t *flags); +int hid_report_size(void *buf, int len, enum hid_kind k, u_int8_t id); +int hid_locate(void *desc, int size, u_int32_t usage, u_int8_t id, + enum hid_kind kind, struct hid_location *loc, u_int32_t *flags); u_long hid_get_data(u_char *buf, struct hid_location *loc); -int hid_is_collection(void *desc, int size, u_int32_t usage); +int hid_is_collection(void *desc, int size, u_int8_t id, u_int32_t usage); diff --git a/sys/dev/usb/uhid.c b/sys/dev/usb/uhid.c index 968af28c593..146a6ad44c7 100644 --- a/sys/dev/usb/uhid.c +++ b/sys/dev/usb/uhid.c @@ -1,6 +1,5 @@ -/* $OpenBSD: uhid.c,v 1.18 2002/05/07 18:29:18 nate Exp $ */ -/* $NetBSD: uhid.c,v 1.45 2001/10/26 17:58:21 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/uhid.c,v 1.22 1999/11/17 22:33:43 n_hibma Exp $ */ +/* $OpenBSD: uhid.c,v 1.19 2002/05/09 15:06:29 nate Exp $ */ +/* $NetBSD: uhid.c,v 1.51 2002/03/17 18:02:53 augustss Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -48,16 +47,8 @@ #include <sys/kernel.h> #include <sys/malloc.h> #include <sys/signalvar.h> -#if defined(__NetBSD__) || defined(__OpenBSD__) #include <sys/device.h> #include <sys/ioctl.h> -#elif defined(__FreeBSD__) -#include <sys/ioccom.h> -#include <sys/filio.h> -#include <sys/module.h> -#include <sys/bus.h> -#include <sys/ioccom.h> -#endif #include <sys/conf.h> #include <sys/tty.h> #include <sys/file.h> @@ -75,8 +66,7 @@ #include <dev/usb/hid.h> #include <dev/usb/usb_quirks.h> -/* Report descriptor for broken Wacom Graphire */ -#include <dev/usb/ugraphire_rdesc.h> +#include <dev/usb/uhidev.h> #ifdef UHID_DEBUG #define DPRINTF(x) if (uhiddebug) logprintf x @@ -88,33 +78,20 @@ int uhiddebug = 0; #endif struct uhid_softc { - USBBASEDEVICE sc_dev; /* base device */ - usbd_device_handle sc_udev; - usbd_interface_handle sc_iface; /* interface */ - usbd_pipe_handle sc_intrpipe; /* interrupt pipe */ - int sc_ep_addr; + struct uhidev sc_hdev; int sc_isize; int sc_osize; int sc_fsize; - u_int8_t sc_iid; - u_int8_t sc_oid; - u_int8_t sc_fid; - u_char *sc_ibuf; u_char *sc_obuf; - void *sc_repdesc; - int sc_repdesc_size; - struct clist sc_q; struct selinfo sc_rsel; - struct proc *sc_async; /* process that wants SIGIO */ + usb_proc_ptr sc_async; /* process that wants SIGIO */ u_char sc_state; /* driver state */ -#define UHID_OPEN 0x01 /* device is open */ -#define UHID_ASLP 0x02 /* waiting for device data */ -#define UHID_NEEDCLEAR 0x04 /* needs clearing endpoint stall */ -#define UHID_IMMED 0x08 /* return read data immediately */ +#define UHID_ASLP 0x01 /* waiting for device data */ +#define UHID_IMMED 0x02 /* return read data immediately */ int sc_refcnt; u_char sc_dying; @@ -124,153 +101,52 @@ struct uhid_softc { #define UHID_CHUNK 128 /* chunk size for read */ #define UHID_BSIZE 1020 /* buffer size */ -#if defined(__NetBSD__) || defined(__OpenBSD__) cdev_decl(uhid); -#elif defined(__FreeBSD__) -d_open_t uhidopen; -d_close_t uhidclose; -d_read_t uhidread; -d_write_t uhidwrite; -d_ioctl_t uhidioctl; -d_poll_t uhidpoll; - -#define UHID_CDEV_MAJOR 122 - -Static struct cdevsw uhid_cdevsw = { - /* open */ uhidopen, - /* close */ uhidclose, - /* read */ uhidread, - /* write */ uhidwrite, - /* ioctl */ uhidioctl, - /* poll */ uhidpoll, - /* mmap */ nommap, - /* strategy */ nostrategy, - /* name */ "uhid", - /* maj */ UHID_CDEV_MAJOR, - /* dump */ nodump, - /* psize */ nopsize, - /* flags */ 0, - /* bmaj */ -1 -}; -#endif -Static void uhid_intr(usbd_xfer_handle, usbd_private_handle, usbd_status); +Static void uhid_intr(struct uhidev *, void *, u_int len); Static int uhid_do_read(struct uhid_softc *, struct uio *uio, int); Static int uhid_do_write(struct uhid_softc *, struct uio *uio, int); -Static int uhid_do_ioctl(struct uhid_softc*, u_long, caddr_t, int,struct proc*); +Static int uhid_do_ioctl(struct uhid_softc*, u_long, caddr_t, int, + usb_proc_ptr); USB_DECLARE_DRIVER(uhid); USB_MATCH(uhid) { USB_MATCH_START(uhid, uaa); - usb_interface_descriptor_t *id; - - if (uaa->iface == NULL) - return (UMATCH_NONE); - id = usbd_get_interface_descriptor(uaa->iface); - if (id == NULL || id->bInterfaceClass != UICLASS_HID) - return (UMATCH_NONE); - if (uaa->matchlvl) - return (uaa->matchlvl); + struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa; + + DPRINTF(("uhid_match: report=%d\n", uha->reportid)); + + if (uha->matchlvl) + return (uha->matchlvl); return (UMATCH_IFACECLASS_GENERIC); } USB_ATTACH(uhid) { USB_ATTACH_START(uhid, sc, uaa); - usbd_interface_handle iface = uaa->iface; - usb_interface_descriptor_t *id; - usb_endpoint_descriptor_t *ed; - int size; + struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa; + int size, repid; void *desc; - usbd_status err; - char devinfo[1024]; - - sc->sc_udev = uaa->device; - sc->sc_iface = iface; - id = usbd_get_interface_descriptor(iface); - usbd_devinfo(uaa->device, 0, devinfo); - USB_ATTACH_SETUP; - printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev), - devinfo, id->bInterfaceClass, id->bInterfaceSubClass); - - ed = usbd_interface2endpoint_descriptor(iface, 0); - if (ed == NULL) { - printf("%s: could not read endpoint descriptor\n", - USBDEVNAME(sc->sc_dev)); - sc->sc_dying = 1; - USB_ATTACH_ERROR_RETURN; - } - - DPRINTFN(10,("uhid_attach: bLength=%d bDescriptorType=%d " - "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d" - " bInterval=%d\n", - ed->bLength, ed->bDescriptorType, - ed->bEndpointAddress & UE_ADDR, - UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out", - ed->bmAttributes & UE_XFERTYPE, - UGETW(ed->wMaxPacketSize), ed->bInterval)); - - if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN || - (ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) { - printf("%s: unexpected endpoint\n", USBDEVNAME(sc->sc_dev)); - sc->sc_dying = 1; - USB_ATTACH_ERROR_RETURN; - } - - sc->sc_ep_addr = ed->bEndpointAddress; - - if (uaa->vendor == USB_VENDOR_WACOM && - uaa->product == USB_PRODUCT_WACOM_GRAPHIRE /* && - uaa->revision == 0x???? */) { /* XXX should use revision */ - /* The report descriptor for the Wacom Graphire is broken. */ - size = sizeof uhid_graphire_report_descr; - desc = malloc(size, M_USBDEV, M_NOWAIT); - if (desc == NULL) - err = USBD_NOMEM; - else { - err = USBD_NORMAL_COMPLETION; - memcpy(desc, uhid_graphire_report_descr, size); - } - } else { - desc = NULL; - err = usbd_read_report_desc(uaa->iface, &desc, &size,M_USBDEV); - } - if (err) { - printf("%s: no report descriptor\n", USBDEVNAME(sc->sc_dev)); - sc->sc_dying = 1; - USB_ATTACH_ERROR_RETURN; - } - (void)usbd_set_idle(iface, 0, 0); - - sc->sc_isize = hid_report_size(desc, size, hid_input, &sc->sc_iid); - sc->sc_osize = hid_report_size(desc, size, hid_output, &sc->sc_oid); - sc->sc_fsize = hid_report_size(desc, size, hid_feature, &sc->sc_fid); + sc->sc_hdev.sc_intr = uhid_intr; + sc->sc_hdev.sc_parent = uha->parent; + sc->sc_hdev.sc_report_id = uha->reportid; - sc->sc_repdesc = desc; - sc->sc_repdesc_size = size; + uhidev_get_report_desc(uha->parent, &desc, &size); + repid = uha->reportid; + sc->sc_isize = hid_report_size(desc, size, hid_input, repid); + sc->sc_osize = hid_report_size(desc, size, hid_output, repid); + sc->sc_fsize = hid_report_size(desc, size, hid_feature, repid); -#ifdef __FreeBSD__ - { - static int global_init_done = 0; - - if (!global_init_done) { - cdevsw_add(&uhid_cdevsw); - global_init_done = 1; - } - } -#endif - - usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, - USBDEV(sc->sc_dev)); + printf(": input=%d, output=%d, feature=%d\n", + sc->sc_isize, sc->sc_osize, sc->sc_fsize); USB_ATTACH_SUCCESS_RETURN; } -#if defined(__NetBSD__) || defined(__OpenBSD__) int uhid_activate(device_ptr_t self, enum devact act) { @@ -287,36 +163,28 @@ uhid_activate(device_ptr_t self, enum devact act) } return (0); } -#endif USB_DETACH(uhid) { USB_DETACH_START(uhid, sc); int s; -#if defined(__NetBSD__) || defined(__OpenBSD__) int maj, mn; DPRINTF(("uhid_detach: sc=%p flags=%d\n", sc, flags)); -#else - DPRINTF(("uhid_detach: sc=%p\n", sc)); -#endif sc->sc_dying = 1; - if (sc->sc_intrpipe != NULL) - usbd_abort_pipe(sc->sc_intrpipe); - if (sc->sc_state & UHID_OPEN) { + if (sc->sc_hdev.sc_state & UHIDEV_OPEN) { s = splusb(); if (--sc->sc_refcnt >= 0) { /* Wake everyone */ wakeup(&sc->sc_q); /* Wait for processes to go away. */ - usb_detach_wait(USBDEV(sc->sc_dev)); + usb_detach_wait(USBDEV(sc->sc_hdev.sc_dev)); } splx(s); } -#if defined(__NetBSD__) || defined(__OpenBSD__) /* locate the major number */ for (maj = 0; maj < nchrdev; maj++) if (cdevsw[maj].d_open == uhidopen) @@ -325,47 +193,33 @@ USB_DETACH(uhid) /* Nuke the vnodes for any open instances (calls close). */ mn = self->dv_unit; vdevgone(maj, mn, mn, VCHR); -#elif defined(__FreeBSD__) - /* XXX not implemented yet */ -#endif - if (sc->sc_repdesc) - free(sc->sc_repdesc, M_USBDEV); - - usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, - USBDEV(sc->sc_dev)); +#if 0 + usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, + sc->sc_hdev.sc_parent->sc_udev, + USBDEV(sc->sc_hdev.sc_dev)); +#endif return (0); } void -uhid_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status) +uhid_intr(struct uhidev *addr, void *data, u_int len) { - struct uhid_softc *sc = addr; + struct uhid_softc *sc = (struct uhid_softc *)addr; #ifdef UHID_DEBUG if (uhiddebug > 5) { - u_int32_t cc, i; + u_int32_t i; - usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL); - DPRINTF(("uhid_intr: status=%d cc=%d\n", status, cc)); DPRINTF(("uhid_intr: data =")); - for (i = 0; i < cc; i++) - DPRINTF((" %02x", sc->sc_ibuf[i])); + for (i = 0; i < len; i++) + DPRINTF((" %02x", ((u_char *)data)[i])); DPRINTF(("\n")); } #endif - if (status == USBD_CANCELLED) - return; - - if (status != USBD_NORMAL_COMPLETION) { - DPRINTF(("uhid_intr: status=%d\n", status)); - sc->sc_state |= UHID_NEEDCLEAR; - return; - } - - (void) b_to_q(sc->sc_ibuf, sc->sc_isize, &sc->sc_q); + (void)b_to_q(data, len, &sc->sc_q); if (sc->sc_state & UHID_ASLP) { sc->sc_state &= ~UHID_ASLP; @@ -380,10 +234,10 @@ uhid_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status) } int -uhidopen(dev_t dev, int flag, int mode, struct proc *p) +uhidopen(dev_t dev, int flag, int mode, usb_proc_ptr p) { struct uhid_softc *sc; - usbd_status err; + int error; USB_GET_SC_OPEN(uhid, UHIDUNIT(dev), sc); @@ -392,40 +246,23 @@ uhidopen(dev_t dev, int flag, int mode, struct proc *p) if (sc->sc_dying) return (ENXIO); - if (sc->sc_state & UHID_OPEN) - return (EBUSY); - sc->sc_state |= UHID_OPEN; + error = uhidev_open(&sc->sc_hdev); + if (error) + return (error); if (clalloc(&sc->sc_q, UHID_BSIZE, 0) == -1) { - sc->sc_state &= ~UHID_OPEN; + uhidev_close(&sc->sc_hdev); return (ENOMEM); } - - sc->sc_ibuf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK); sc->sc_obuf = malloc(sc->sc_osize, M_USBDEV, M_WAITOK); - - /* Set up interrupt pipe. */ - err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ep_addr, - USBD_SHORT_XFER_OK, &sc->sc_intrpipe, sc, sc->sc_ibuf, - sc->sc_isize, uhid_intr, USBD_DEFAULT_INTERVAL); - if (err) { - DPRINTF(("uhidopen: usbd_open_pipe_intr failed, " - "error=%d\n",err)); - free(sc->sc_ibuf, M_USBDEV); - free(sc->sc_obuf, M_USBDEV); - sc->sc_state &= ~UHID_OPEN; - return (EIO); - } - sc->sc_state &= ~UHID_IMMED; - - sc->sc_async = 0; + sc->sc_async = NULL; return (0); } int -uhidclose(dev_t dev, int flag, int mode, struct proc *p) +uhidclose(dev_t dev, int flag, int mode, usb_proc_ptr p) { struct uhid_softc *sc; @@ -433,19 +270,10 @@ uhidclose(dev_t dev, int flag, int mode, struct proc *p) DPRINTF(("uhidclose: sc=%p\n", sc)); - /* Disable interrupts. */ - usbd_abort_pipe(sc->sc_intrpipe); - usbd_close_pipe(sc->sc_intrpipe); - sc->sc_intrpipe = 0; - clfree(&sc->sc_q); - - free(sc->sc_ibuf, M_USBDEV); free(sc->sc_obuf, M_USBDEV); - - sc->sc_state &= ~UHID_OPEN; - - sc->sc_async = 0; + sc->sc_async = NULL; + uhidev_close(&sc->sc_hdev); return (0); } @@ -455,6 +283,7 @@ uhid_do_read(struct uhid_softc *sc, struct uio *uio, int flag) { int s; int error = 0; + int extra; size_t length; u_char buffer[UHID_CHUNK]; usbd_status err; @@ -462,12 +291,12 @@ uhid_do_read(struct uhid_softc *sc, struct uio *uio, int flag) DPRINTFN(1, ("uhidread\n")); if (sc->sc_state & UHID_IMMED) { DPRINTFN(1, ("uhidread immed\n")); - - err = usbd_get_report(sc->sc_iface, UHID_INPUT_REPORT, - sc->sc_iid, buffer, sc->sc_isize); + extra = sc->sc_hdev.sc_report_id != 0; + err = uhidev_get_report(&sc->sc_hdev, UHID_INPUT_REPORT, + buffer, sc->sc_isize + extra); if (err) return (EIO); - return (uiomove(buffer, sc->sc_isize, uio)); + return (uiomove(buffer+extra, sc->sc_isize, uio)); } s = splusb(); @@ -486,11 +315,6 @@ uhid_do_read(struct uhid_softc *sc, struct uio *uio, int flag) sc->sc_state &= ~UHID_ASLP; break; } - if (sc->sc_state & UHID_NEEDCLEAR) { - DPRINTFN(-1,("uhidread: clearing stall\n")); - sc->sc_state &= ~UHID_NEEDCLEAR; - usbd_clear_endpoint_stall(sc->sc_intrpipe); - } } splx(s); @@ -523,7 +347,7 @@ uhidread(dev_t dev, struct uio *uio, int flag) sc->sc_refcnt++; error = uhid_do_read(sc, uio, flag); if (--sc->sc_refcnt < 0) - usb_detach_wakeup(USBDEV(sc->sc_dev)); + usb_detach_wakeup(USBDEV(sc->sc_hdev.sc_dev)); return (error); } @@ -545,12 +369,8 @@ uhid_do_write(struct uhid_softc *sc, struct uio *uio, int flag) return (EINVAL); error = uiomove(sc->sc_obuf, size, uio); if (!error) { - if (sc->sc_oid) - err = usbd_set_report(sc->sc_iface, UHID_OUTPUT_REPORT, - sc->sc_obuf[0], sc->sc_obuf+1, size-1); - else - err = usbd_set_report(sc->sc_iface, UHID_OUTPUT_REPORT, - 0, sc->sc_obuf, size); + err = uhidev_set_report(&sc->sc_hdev, UHID_OUTPUT_REPORT, + sc->sc_obuf, size); if (err) error = EIO; } @@ -569,18 +389,20 @@ uhidwrite(dev_t dev, struct uio *uio, int flag) sc->sc_refcnt++; error = uhid_do_write(sc, uio, flag); if (--sc->sc_refcnt < 0) - usb_detach_wakeup(USBDEV(sc->sc_dev)); + usb_detach_wakeup(USBDEV(sc->sc_hdev.sc_dev)); return (error); } int uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, caddr_t addr, - int flag, struct proc *p) + int flag, usb_proc_ptr p) { struct usb_ctl_report_desc *rd; struct usb_ctl_report *re; - int size, id; + u_char buffer[UHID_CHUNK]; + int size, extra; usbd_status err; + void *desc; DPRINTFN(2, ("uhidioctl: cmd=%lx\n", cmd)); @@ -611,17 +433,18 @@ uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, caddr_t addr, break; case USB_GET_REPORT_DESC: + uhidev_get_report_desc(sc->sc_hdev.sc_parent, &desc, &size); rd = (struct usb_ctl_report_desc *)addr; - size = min(sc->sc_repdesc_size, sizeof rd->ucrd_data); + size = min(size, sizeof rd->ucrd_data); rd->ucrd_size = size; - memcpy(rd->ucrd_data, sc->sc_repdesc, size); + memcpy(rd->ucrd_data, desc, size); break; case USB_SET_IMMED: if (*(int *)addr) { - /* XXX should read into ibuf, but does it matter? */ - err = usbd_get_report(sc->sc_iface, UHID_INPUT_REPORT, - sc->sc_iid, sc->sc_ibuf, sc->sc_isize); + extra = sc->sc_hdev.sc_report_id != 0; + err = uhidev_get_report(&sc->sc_hdev, UHID_INPUT_REPORT, + buffer, sc->sc_isize + extra); if (err) return (EOPNOTSUPP); @@ -635,21 +458,21 @@ uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, caddr_t addr, switch (re->ucr_report) { case UHID_INPUT_REPORT: size = sc->sc_isize; - id = sc->sc_iid; break; case UHID_OUTPUT_REPORT: size = sc->sc_osize; - id = sc->sc_oid; break; case UHID_FEATURE_REPORT: size = sc->sc_fsize; - id = sc->sc_fid; break; default: return (EINVAL); } - err = usbd_get_report(sc->sc_iface, re->ucr_report, id, - re->ucr_data, size); + extra = sc->sc_hdev.sc_report_id != 0; + err = uhidev_get_report(&sc->sc_hdev, re->ucr_report, + re->ucr_data, size + extra); + if (extra) + memcpy(re->ucr_data, re->ucr_data+1, size); if (err) return (EIO); break; @@ -659,26 +482,26 @@ uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, caddr_t addr, switch (re->ucr_report) { case UHID_INPUT_REPORT: size = sc->sc_isize; - id = sc->sc_iid; break; case UHID_OUTPUT_REPORT: size = sc->sc_osize; - id = sc->sc_oid; break; case UHID_FEATURE_REPORT: size = sc->sc_fsize; - id = sc->sc_fid; break; default: return (EINVAL); } - err = usbd_set_report(sc->sc_iface, re->ucr_report, id, - re->ucr_data, - size); + err = uhidev_set_report(&sc->sc_hdev, re->ucr_report, + re->ucr_data, size); if (err) return (EIO); break; + case USB_GET_REPORT_ID: + *(int *)addr = sc->sc_hdev.sc_report_id; + break; + default: return (EINVAL); } @@ -686,7 +509,7 @@ uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, caddr_t addr, } int -uhidioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) +uhidioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, usb_proc_ptr p) { struct uhid_softc *sc; int error; @@ -696,12 +519,12 @@ uhidioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) sc->sc_refcnt++; error = uhid_do_ioctl(sc, cmd, addr, flag, p); if (--sc->sc_refcnt < 0) - usb_detach_wakeup(USBDEV(sc->sc_dev)); + usb_detach_wakeup(USBDEV(sc->sc_hdev.sc_dev)); return (error); } int -uhidpoll(dev_t dev, int events, struct proc *p) +uhidpoll(dev_t dev, int events, usb_proc_ptr p) { struct uhid_softc *sc; int revents = 0; @@ -725,7 +548,3 @@ uhidpoll(dev_t dev, int events, struct proc *p) splx(s); return (revents); } - -#if defined(__FreeBSD__) -DRIVER_MODULE(uhid, uhub, uhid_driver, uhid_devclass, usbd_driver_load, 0); -#endif diff --git a/sys/dev/usb/uhidev.c b/sys/dev/usb/uhidev.c new file mode 100644 index 00000000000..c7af847f017 --- /dev/null +++ b/sys/dev/usb/uhidev.c @@ -0,0 +1,513 @@ +/* $OpenBSD: uhidev.c,v 1.3 2002/05/09 15:06:29 nate Exp $ */ +/* $NetBSD: uhidev.c,v 1.5 2002/02/27 01:30:50 augustss Exp $ */ + +/* + * Copyright (c) 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Lennart Augustsson (lennart@augustsson.net) at + * Carlstedt Research & Technology. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * HID spec: http://www.usb.org/developers/data/devclass/hid1_1.pdf + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/signalvar.h> +#include <sys/device.h> +#include <sys/ioctl.h> +#include <sys/conf.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbhid.h> + +#include <dev/usb/usbdevs.h> +#include <dev/usb/usbdi.h> +#include <dev/usb/usbdi_util.h> +#include <dev/usb/hid.h> +#include <dev/usb/usb_quirks.h> + +#include <dev/usb/uhidev.h> + +/* Report descriptor for broken Wacom Graphire */ +#include <dev/usb/ugraphire_rdesc.h> + +#ifdef UHIDEV_DEBUG +#define DPRINTF(x) if (uhidevdebug) logprintf x +#define DPRINTFN(n,x) if (uhidevdebug>(n)) logprintf x +int uhidevdebug = 0; +#else +#define DPRINTF(x) +#define DPRINTFN(n,x) +#endif + +Static void uhidev_intr(usbd_xfer_handle, usbd_private_handle, usbd_status); + +Static int uhidev_maxrepid(void *buf, int len); +Static int uhidevprint(void *aux, const char *pnp); +#if defined(__NetBSD__) +Static int uhidevsubmatch(struct device *parent, struct cfdata *cf, void *aux); +#else +Static int uhidevsubmatch(struct device *parent, void *cf, void *aux); +#endif + +USB_DECLARE_DRIVER(uhidev); + +USB_MATCH(uhidev) +{ + USB_MATCH_START(uhidev, uaa); + usb_interface_descriptor_t *id; + + if (uaa->iface == NULL) + return (UMATCH_NONE); + id = usbd_get_interface_descriptor(uaa->iface); + if (id == NULL || id->bInterfaceClass != UICLASS_HID) + return (UMATCH_NONE); + if (uaa->matchlvl) + return (uaa->matchlvl); + return (UMATCH_IFACECLASS_GENERIC); +} + +int repproto = 1; + +USB_ATTACH(uhidev) +{ + USB_ATTACH_START(uhidev, sc, uaa); + usbd_interface_handle iface = uaa->iface; + usb_interface_descriptor_t *id; + usb_endpoint_descriptor_t *ed; + struct uhidev_attach_arg uha; + struct uhidev *dev; + int size, nrepid, repid, repsz; + int repsizes[256]; + void *desc; + usbd_status err; + char devinfo[1024]; + + sc->sc_udev = uaa->device; + sc->sc_iface = iface; + id = usbd_get_interface_descriptor(iface); + usbd_devinfo(uaa->device, 0, devinfo); + USB_ATTACH_SETUP; + printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev), + devinfo, id->bInterfaceClass, id->bInterfaceSubClass); + + (void)usbd_set_idle(iface, 0, 0); +#if 0 + + qflags = usbd_get_quirks(sc->sc_udev)->uq_flags; + if ((qflags & UQ_NO_SET_PROTO) == 0 && + id->bInterfaceSubClass != UISUBCLASS_BOOT) + (void)usbd_set_protocol(iface, 1); +#endif + + ed = usbd_interface2endpoint_descriptor(iface, 0); + if (ed == NULL) { + printf("%s: could not read endpoint descriptor\n", + USBDEVNAME(sc->sc_dev)); + sc->sc_dying = 1; + USB_ATTACH_ERROR_RETURN; + } + + DPRINTFN(10,("uhidev_attach: bLength=%d bDescriptorType=%d " + "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d" + " bInterval=%d\n", + ed->bLength, ed->bDescriptorType, + ed->bEndpointAddress & UE_ADDR, + UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out", + ed->bmAttributes & UE_XFERTYPE, + UGETW(ed->wMaxPacketSize), ed->bInterval)); + + if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN || + (ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) { + printf("%s: unexpected endpoint\n", USBDEVNAME(sc->sc_dev)); + sc->sc_dying = 1; + USB_ATTACH_ERROR_RETURN; + } + + sc->sc_ep_addr = ed->bEndpointAddress; + + /* XXX need to extend this */ + if (uaa->vendor == USB_VENDOR_WACOM && + uaa->product == USB_PRODUCT_WACOM_GRAPHIRE /* && + uaa->revision == 0x???? */) { /* XXX should use revision */ + /* The report descriptor for the Wacom Graphire is broken. */ + size = sizeof uhid_graphire_report_descr; + desc = malloc(size, M_USBDEV, M_NOWAIT); + if (desc == NULL) + err = USBD_NOMEM; + else { + err = USBD_NORMAL_COMPLETION; + memcpy(desc, uhid_graphire_report_descr, size); + } + } else { + desc = NULL; + err = usbd_read_report_desc(uaa->iface, &desc, &size, M_USBDEV); + } + if (err) { + printf("%s: no report descriptor\n", USBDEVNAME(sc->sc_dev)); + sc->sc_dying = 1; + USB_ATTACH_ERROR_RETURN; + } + + sc->sc_repdesc = desc; + sc->sc_repdesc_size = size; + + uha.uaa = uaa; + nrepid = uhidev_maxrepid(desc, size); + if (nrepid < 0) + USB_ATTACH_SUCCESS_RETURN; + if (nrepid > 0) + printf("%s: %d report ids\n", USBDEVNAME(sc->sc_dev), nrepid); + nrepid++; + sc->sc_subdevs = malloc(nrepid * sizeof(device_ptr_t), + M_USBDEV, M_NOWAIT); + bzero(sc->sc_subdevs, nrepid * sizeof(device_ptr_t)); + if (sc->sc_subdevs == NULL) { + printf("%s: no memory\n", USBDEVNAME(sc->sc_dev)); + USB_ATTACH_ERROR_RETURN; + } + sc->sc_nrepid = nrepid; + sc->sc_isize = 0; + + usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, + USBDEV(sc->sc_dev)); + + for (repid = 0; repid < nrepid; repid++) { + repsz = hid_report_size(desc, size, hid_input, repid); + DPRINTF(("uhidev_match: repid=%d, repsz=%d\n", repid, repsz)); + repsizes[repid] = repsz; + if (repsz > 0) { + if (repsz > sc->sc_isize) + sc->sc_isize = repsz; + } + } + sc->sc_isize += nrepid != 1; /* space for report ID */ + DPRINTF(("uhidev_attach: isize=%d\n", sc->sc_isize)); + + uha.parent = sc; + for (repid = 0; repid < nrepid; repid++) { + DPRINTF(("uhidev_match: try repid=%d\n", repid)); + if (hid_report_size(desc, size, hid_input, repid) == 0 && + hid_report_size(desc, size, hid_output, repid) == 0 && + hid_report_size(desc, size, hid_feature, repid) == 0) { + ; /* already NULL in sc->sc_subdevs[repid] */ + } else { + uha.reportid = repid; + dev = (struct uhidev *)config_found_sm(self, &uha, + uhidevprint, uhidevsubmatch); + sc->sc_subdevs[repid] = dev; + if (dev != NULL) { + dev->sc_in_rep_size = repsizes[repid]; +#ifdef DIAGNOSTIC + DPRINTF(("uhidev_match: repid=%d dev=%p\n", + repid, dev)); + if (dev->sc_intr == NULL) { + printf("%s: sc_intr == NULL\n", + USBDEVNAME(sc->sc_dev)); + USB_ATTACH_ERROR_RETURN; + } +#endif + } + } + } + + USB_ATTACH_SUCCESS_RETURN; +} + +int +uhidev_maxrepid(void *buf, int len) +{ + struct hid_data *d; + struct hid_item h; + int maxid; + + maxid = -1; + h.report_ID = 0; + for (d = hid_start_parse(buf, len, hid_none); hid_get_item(d, &h); ) + if (h.report_ID > maxid) + maxid = h.report_ID; + hid_end_parse(d); + return (maxid); +} + +int +uhidevprint(void *aux, const char *pnp) +{ + struct uhidev_attach_arg *uha = aux; + + if (pnp) + printf("uhid at %s", pnp); + if (uha->reportid != 0) + printf(" reportid %d", uha->reportid); + return (UNCONF); +} + +#if defined(__NetBSD__) +Static int uhidevsubmatch(struct device *parent, struct cfdata *cf, void *aux) +#else +Static int uhidevsubmatch(struct device *parent, void *match, void *aux) +#endif +{ + struct uhidev_attach_arg *uha = aux; +#if defined(__OpenBSD__) + struct cfdata *cf = match; +#endif + + if (cf->uhidevcf_reportid != UHIDEV_UNK_REPORTID && + cf->uhidevcf_reportid != uha->reportid) + return (0); + if (cf->uhidevcf_reportid == uha->reportid) + uha->matchlvl = UMATCH_VENDOR_PRODUCT; + else + uha->matchlvl = 0; + return ((*cf->cf_attach->ca_match)(parent, cf, aux)); +} + +int +uhidev_activate(device_ptr_t self, enum devact act) +{ + struct uhidev_softc *sc = (struct uhidev_softc *)self; + int i, rv; + + switch (act) { + case DVACT_ACTIVATE: + return (EOPNOTSUPP); + break; + + case DVACT_DEACTIVATE: + rv = 0; + for (i = 0; i < sc->sc_nrepid; i++) + if (sc->sc_subdevs[i] != NULL) + rv |= config_deactivate( + &sc->sc_subdevs[i]->sc_dev); + sc->sc_dying = 1; + break; + } + return (rv); +} + +USB_DETACH(uhidev) +{ + USB_DETACH_START(uhidev, sc); + int i, rv; + + DPRINTF(("uhidev_detach: sc=%p flags=%d\n", sc, flags)); + + sc->sc_dying = 1; + if (sc->sc_intrpipe != NULL) + usbd_abort_pipe(sc->sc_intrpipe); + + if (sc->sc_repdesc != NULL) + free(sc->sc_repdesc, M_USBDEV); + + rv = 0; + for (i = 0; i < sc->sc_nrepid; i++) { + if (sc->sc_subdevs[i] != NULL) { + rv |= config_detach(&sc->sc_subdevs[i]->sc_dev, flags); + sc->sc_subdevs[i] = NULL; + } + } + + usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, + USBDEV(sc->sc_dev)); + + return (rv); +} + +void +uhidev_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status) +{ + struct uhidev_softc *sc = addr; + struct uhidev *scd; + u_char *p; + u_int rep; + u_int32_t cc; + + usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL); + +#ifdef UHIDEV_DEBUG + if (uhidevdebug > 5) { + u_int32_t i; + + DPRINTF(("uhidev_intr: status=%d cc=%d\n", status, cc)); + DPRINTF(("uhidev_intr: data =")); + for (i = 0; i < cc; i++) + DPRINTF((" %02x", sc->sc_ibuf[i])); + DPRINTF(("\n")); + } +#endif + + if (status == USBD_CANCELLED) + return; + + if (status != USBD_NORMAL_COMPLETION) { + DPRINTF(("%s: interrupt status=%d\n", USBDEVNAME(sc->sc_dev), + status)); + usbd_clear_endpoint_stall_async(sc->sc_intrpipe); + return; + } + + p = sc->sc_ibuf; + if (sc->sc_nrepid != 1) + rep = *p++, cc--; + else + rep = 0; + if (rep >= sc->sc_nrepid) { + printf("uhidev_intr: bad repid %d\n", rep); + return; + } + scd = sc->sc_subdevs[rep]; + DPRINTFN(5,("uhidev_intr: rep=%d, scd=%p state=0x%x\n", + rep, scd, scd ? scd->sc_state : 0)); + if (scd == NULL || !(scd->sc_state & UHIDEV_OPEN)) + return; +#ifdef DIAGNOSTIC + if (scd->sc_in_rep_size != cc) + printf("%s: bad input length %d != %d\n",USBDEVNAME(sc->sc_dev), + scd->sc_in_rep_size, cc); +#endif + scd->sc_intr(scd, p, cc); +} + +void +uhidev_get_report_desc(struct uhidev_softc *sc, void **desc, int *size) +{ + *desc = sc->sc_repdesc; + *size = sc->sc_repdesc_size; +} + +int +uhidev_open(struct uhidev *scd) +{ + struct uhidev_softc *sc = scd->sc_parent; + usbd_status err; + + DPRINTF(("uhidev_open: open pipe, state=%d refcnt=%d\n", + scd->sc_state, sc->sc_refcnt)); + + if (scd->sc_state & UHIDEV_OPEN) + return (EBUSY); + scd->sc_state |= UHIDEV_OPEN; + if (sc->sc_refcnt++) + return (0); + + if (sc->sc_isize == 0) + return (0); + + sc->sc_ibuf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK); + + /* Set up interrupt pipe. */ + DPRINTF(("uhidev_open: isize=%d, ep=0x%02x\n", sc->sc_isize, + sc->sc_ep_addr)); + err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ep_addr, + USBD_SHORT_XFER_OK, &sc->sc_intrpipe, sc, sc->sc_ibuf, + sc->sc_isize, uhidev_intr, USBD_DEFAULT_INTERVAL); + if (err) { + DPRINTF(("uhidopen: usbd_open_pipe_intr failed, " + "error=%d\n",err)); + free(sc->sc_ibuf, M_USBDEV); + scd->sc_state &= ~UHIDEV_OPEN; + sc->sc_refcnt = 0; + sc->sc_intrpipe = NULL; + return (EIO); + } + return (0); +} + +void +uhidev_close(struct uhidev *scd) +{ + struct uhidev_softc *sc = scd->sc_parent; + + if (!(scd->sc_state & UHIDEV_OPEN)) + return; + scd->sc_state &= ~UHIDEV_OPEN; + if (--sc->sc_refcnt) + return; + DPRINTF(("uhidev_close: close pipe\n")); + + /* Disable interrupts. */ + if (sc->sc_intrpipe != NULL) { + usbd_abort_pipe(sc->sc_intrpipe); + usbd_close_pipe(sc->sc_intrpipe); + sc->sc_intrpipe = NULL; + } + + if (sc->sc_ibuf != NULL) { + free(sc->sc_ibuf, M_USBDEV); + sc->sc_ibuf = NULL; + } +} + +usbd_status +uhidev_set_report(struct uhidev *scd, int type, void *data, int len) +{ + /* XXX */ + char buf[100]; + if (scd->sc_report_id) { + buf[0] = scd->sc_report_id; + memcpy(buf+1, data, len); + len++; + data = buf; + } + + return usbd_set_report(scd->sc_parent->sc_iface, type, + scd->sc_report_id, data, len); +} + +void +uhidev_set_report_async(struct uhidev *scd, int type, void *data, int len) +{ + /* XXX */ + char buf[100]; + if (scd->sc_report_id) { + buf[0] = scd->sc_report_id; + memcpy(buf+1, data, len); + len++; + data = buf; + } + + usbd_set_report_async(scd->sc_parent->sc_iface, type, + scd->sc_report_id, data, len); +} + +usbd_status +uhidev_get_report(struct uhidev *scd, int type, void *data, int len) +{ + return usbd_get_report(scd->sc_parent->sc_iface, type, + scd->sc_report_id, data, len); +} diff --git a/sys/dev/usb/uhidev.h b/sys/dev/usb/uhidev.h new file mode 100644 index 00000000000..360eae75784 --- /dev/null +++ b/sys/dev/usb/uhidev.h @@ -0,0 +1,91 @@ +/* $OpenBSD: uhidev.h,v 1.3 2002/05/09 15:06:29 nate Exp $ */ +/* $NetBSD: uhidev.h,v 1.2 2001/12/29 18:56:52 augustss Exp $ */ + +/* + * Copyright (c) 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Lennart Augustsson (lennart@augustsson.net) at + * Carlstedt Research & Technology. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(__NetBSD__) +#include "locators.h" +#endif + +#define uhidevcf_reportid cf_loc[UHIDBUSCF_REPORTID] +#define UHIDEV_UNK_REPORTID UHIDBUSCF_REPORTID_DEFAULT + +struct uhidev_softc { + USBBASEDEVICE sc_dev; /* base device */ + usbd_device_handle sc_udev; + usbd_interface_handle sc_iface; /* interface */ + usbd_pipe_handle sc_intrpipe; /* interrupt pipe */ + int sc_ep_addr; + + u_char *sc_ibuf; + u_int sc_isize; + + void *sc_repdesc; + int sc_repdesc_size; + + u_int sc_nrepid; + struct uhidev **sc_subdevs; + + int sc_refcnt; + u_char sc_dying; +}; + +struct uhidev { + USBBASEDEVICE sc_dev; /* base device */ + struct uhidev_softc *sc_parent; + uByte sc_report_id; + u_int8_t sc_state; + int sc_in_rep_size; +#define UHIDEV_OPEN 0x01 /* device is open */ + void (*sc_intr)(struct uhidev *, void *, u_int); +}; + +struct uhidev_attach_arg { + struct usb_attach_arg *uaa; + struct uhidev_softc *parent; + int reportid; + int reportsize; + int matchlvl; +}; + +void uhidev_get_report_desc(struct uhidev_softc *, void **, int *); +int uhidev_open(struct uhidev *); +void uhidev_close(struct uhidev *); +usbd_status uhidev_set_report(struct uhidev *scd, int type, void *data,int len); +void uhidev_set_report_async(struct uhidev *scd, int type, void *data, int len); +usbd_status uhidev_get_report(struct uhidev *scd, int type, void *data,int len); diff --git a/sys/dev/usb/ukbd.c b/sys/dev/usb/ukbd.c index 0843bd9392d..3c8c6ca9dec 100644 --- a/sys/dev/usb/ukbd.c +++ b/sys/dev/usb/ukbd.c @@ -1,5 +1,5 @@ -/* $OpenBSD: ukbd.c,v 1.13 2002/05/07 18:29:18 nate Exp $ */ -/* $NetBSD: ukbd.c,v 1.69 2001/10/24 21:02:18 augustss Exp $ */ +/* $OpenBSD: ukbd.c,v 1.14 2002/05/09 15:06:29 nate Exp $ */ +/* $NetBSD: ukbd.c,v 1.79 2001/12/30 19:37:43 augustss Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -66,6 +66,7 @@ #include <dev/usb/usbdi_util.h> #include <dev/usb/usbdevs.h> #include <dev/usb/usb_quirks.h> +#include <dev/usb/uhidev.h> #include <dev/usb/hid.h> #include <dev/usb/ukbdvar.h> @@ -88,119 +89,96 @@ int ukbddebug = 0; #define DPRINTFN(n,x) #endif -#define NKEYCODE 6 - -#define NUM_LOCK 0x01 -#define CAPS_LOCK 0x02 -#define SCROLL_LOCK 0x04 +#define MAXKEYCODE 6 +#define MAXMOD 8 /* max 32 */ struct ukbd_data { - u_int8_t modifiers; -#define MOD_CONTROL_L 0x01 -#define MOD_CONTROL_R 0x10 -#define MOD_SHIFT_L 0x02 -#define MOD_SHIFT_R 0x20 -#define MOD_ALT_L 0x04 -#define MOD_ALT_R 0x40 -#define MOD_WIN_L 0x08 -#define MOD_WIN_R 0x80 - u_int8_t reserved; - u_int8_t keycode[NKEYCODE]; + u_int32_t modifiers; + u_int8_t keycode[MAXKEYCODE]; }; #define PRESS 0x000 #define RELEASE 0x100 #define CODEMASK 0x0ff -/* Translate USB bitmap to USB keycode. */ -#define NMOD 8 -Static const struct { - int mask, key; -} ukbd_mods[NMOD] = { - { MOD_CONTROL_L, 224 }, - { MOD_CONTROL_R, 228 }, - { MOD_SHIFT_L, 225 }, - { MOD_SHIFT_R, 229 }, - { MOD_ALT_L, 226 }, - { MOD_ALT_R, 230 }, - { MOD_WIN_L, 227 }, - { MOD_WIN_R, 231 }, -}; - #if defined(WSDISPLAY_COMPAT_RAWKBD) #define NN 0 /* no translation */ /* * Translate USB keycodes to US keyboard XT scancodes. - * Scancodes >= 128 represent EXTENDED keycodes. + * Scancodes >= 0x80 represent EXTENDED keycodes. + * + * See http://www.microsoft.com/HWDEV/TECH/input/Scancode.asp */ Static const u_int8_t ukbd_trtab[256] = { - NN, NN, NN, NN, 30, 48, 46, 32, /* 00 - 07 */ - 18, 33, 34, 35, 23, 36, 37, 38, /* 08 - 0F */ - 50, 49, 24, 25, 16, 19, 31, 20, /* 10 - 17 */ - 22, 47, 17, 45, 21, 44, 2, 3, /* 18 - 1F */ - 4, 5, 6, 7, 8, 9, 10, 11, /* 20 - 27 */ - 28, 1, 14, 15, 57, 12, 13, 26, /* 28 - 2F */ - 27, 43, 43, 39, 40, 41, 51, 52, /* 30 - 37 */ - 53, 58, 59, 60, 61, 62, 63, 64, /* 38 - 3F */ - 65, 66, 67, 68, 87, 88, 170, 70, /* 40 - 47 */ - 127, 210, 199, 201, 211, 207, 209, 205, /* 48 - 4F */ - 203, 208, 200, 69, 181, 55, 74, 78, /* 50 - 57 */ - 156, 79, 80, 81, 75, 76, 77, 71, /* 58 - 5F */ - 72, 73, 82, 83, 86, 221, NN, NN, /* 60 - 67 */ - NN, NN, NN, NN, NN, NN, NN, NN, /* 68 - 6F */ - NN, NN, NN, NN, NN, NN, NN, NN, /* 70 - 77 */ - NN, NN, NN, NN, NN, NN, NN, NN, /* 78 - 7F */ - NN, NN, NN, NN, NN, NN, NN, NN, /* 80 - 87 */ - NN, NN, NN, NN, NN, NN, NN, NN, /* 88 - 8F */ - NN, NN, NN, NN, NN, NN, NN, NN, /* 90 - 97 */ - NN, NN, NN, NN, NN, NN, NN, NN, /* 98 - 9F */ - NN, NN, NN, NN, NN, NN, NN, NN, /* A0 - A7 */ - NN, NN, NN, NN, NN, NN, NN, NN, /* A8 - AF */ - NN, NN, NN, NN, NN, NN, NN, NN, /* B0 - B7 */ - NN, NN, NN, NN, NN, NN, NN, NN, /* B8 - BF */ - NN, NN, NN, NN, NN, NN, NN, NN, /* C0 - C7 */ - NN, NN, NN, NN, NN, NN, NN, NN, /* C8 - CF */ - NN, NN, NN, NN, NN, NN, NN, NN, /* D0 - D7 */ - NN, NN, NN, NN, NN, NN, NN, NN, /* D8 - DF */ - 29, 42, 56, 219, 157, 54, 184,220, /* E0 - E7 */ - NN, NN, NN, NN, NN, NN, NN, NN, /* E8 - EF */ - NN, NN, NN, NN, NN, NN, NN, NN, /* F0 - F7 */ - NN, NN, NN, NN, NN, NN, NN, NN, /* F8 - FF */ + NN, NN, NN, NN, 0x1e, 0x30, 0x2e, 0x20, /* 00 - 07 */ + 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, /* 08 - 0f */ + 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, /* 10 - 17 */ + 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x02, 0x03, /* 18 - 1f */ + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, /* 20 - 27 */ + 0x1c, 0x01, 0x0e, 0x0f, 0x39, 0x0c, 0x0d, 0x1a, /* 28 - 2f */ + 0x1b, 0x2b, 0x2b, 0x27, 0x28, 0x29, 0x33, 0x34, /* 30 - 37 */ + 0x35, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, /* 38 - 3f */ + 0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 0xaa, 0x46, /* 40 - 47 */ + 0x7f, 0xd2, 0xc7, 0xc9, 0xd3, 0xcf, 0xd1, 0xcd, /* 48 - 4f */ + 0xcb, 0xd0, 0xc8, 0x45, 0xb5, 0x37, 0x4a, 0x4e, /* 50 - 57 */ + 0x9c, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47, /* 58 - 5f */ + 0x48, 0x49, 0x52, 0x53, 0x56, 0xdd, NN, 0x59, /* 60 - 67 */ + 0x5d, 0x5e, 0x5f, NN, NN, NN, NN, NN, /* 68 - 6f */ + NN, NN, NN, NN, NN, NN, NN, NN, /* 70 - 77 */ + NN, NN, NN, NN, NN, NN, NN, NN, /* 78 - 7f */ + NN, NN, NN, NN, NN, 0x7e, NN, 0x73, /* 80 - 87 */ + 0x70, 0x7d, 0x79, 0x7b, 0x5c, NN, NN, NN, /* 88 - 8f */ + NN, NN, 0x78, 0x77, 0x76, NN, NN, NN, /* 90 - 97 */ + NN, NN, NN, NN, NN, NN, NN, NN, /* 98 - 9f */ + NN, NN, NN, NN, NN, NN, NN, NN, /* a0 - a7 */ + NN, NN, NN, NN, NN, NN, NN, NN, /* a8 - af */ + NN, NN, NN, NN, NN, NN, NN, NN, /* b0 - b7 */ + NN, NN, NN, NN, NN, NN, NN, NN, /* b8 - bf */ + NN, NN, NN, NN, NN, NN, NN, NN, /* c0 - c7 */ + NN, NN, NN, NN, NN, NN, NN, NN, /* c8 - cf */ + NN, NN, NN, NN, NN, NN, NN, NN, /* d0 - d7 */ + NN, NN, NN, NN, NN, NN, NN, NN, /* d8 - df */ + 0x1d, 0x2a, 0x38, 0xdb, 0x9d, 0x36, 0xb8, 0xdc, /* e0 - e7 */ + NN, NN, NN, NN, NN, NN, NN, NN, /* e8 - ef */ + NN, NN, NN, NN, NN, NN, NN, NN, /* f0 - f7 */ + NN, NN, NN, NN, NN, NN, NN, NN, /* f8 - ff */ }; #endif /* defined(WSDISPLAY_COMPAT_RAWKBD) */ #define KEY_ERROR 0x01 -#define MAXKEYS (NMOD+2*NKEYCODE) +#define MAXKEYS (MAXMOD+2*MAXKEYCODE) struct ukbd_softc { - USBBASEDEVICE sc_dev; /* base device */ - usbd_device_handle sc_udev; - usbd_interface_handle sc_iface; /* interface */ - usbd_pipe_handle sc_intrpipe; /* interrupt pipe */ - int sc_ep_addr; + struct uhidev sc_hdev; struct ukbd_data sc_ndata; struct ukbd_data sc_odata; + struct hid_location sc_modloc[MAXMOD]; + u_int sc_nmod; + struct { + u_int32_t mask; + u_int8_t key; + } sc_mods[MAXMOD]; + + struct hid_location sc_keycodeloc; + u_int sc_nkeycode; char sc_enabled; int sc_console_keyboard; /* we are the console keyboard */ char sc_debounce; /* for quirk handling */ + usb_callout_t sc_delay; /* for quirk handling */ struct ukbd_data sc_data; /* for quirk handling */ + struct hid_location sc_numloc; + struct hid_location sc_capsloc; + struct hid_location sc_scroloc; int sc_leds; -#if defined(__OpenBSD__) - struct timeout sc_delay; /* for quirk handling */ - struct timeout sc_rawrepeat_ch; -#else - struct callout sc_delay; /* for quirk handling */ - struct callout sc_rawrepeat_ch; -#endif + usb_callout_t sc_rawrepeat_ch; -#if defined(__NetBSD__) || defined(__OpenBSD__) struct device *sc_wskbddev; #if defined(WSDISPLAY_COMPAT_RAWKBD) #define REP_DELAY1 400 @@ -213,7 +191,6 @@ struct ukbd_softc { int sc_polling; int sc_npollchar; u_int16_t sc_pollchars[MAXKEYS]; -#endif u_char sc_dying; }; @@ -254,22 +231,21 @@ Static int ukbd_is_console; Static void ukbd_cngetc(void *, u_int *, int *); Static void ukbd_cnpollc(void *, int); -#if defined(__NetBSD__) || defined(__OpenBSD__) const struct wskbd_consops ukbd_consops = { ukbd_cngetc, ukbd_cnpollc, }; -#endif -Static void ukbd_intr(usbd_xfer_handle, usbd_private_handle, usbd_status); +Static const char *ukbd_parse_desc(struct ukbd_softc *sc); + +Static void ukbd_intr(struct uhidev *addr, void *ibuf, u_int len); Static void ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud); Static void ukbd_delayed_decode(void *addr); Static int ukbd_enable(void *, int); Static void ukbd_set_leds(void *, int); -#if defined(__NetBSD__) || defined(__OpenBSD__) -Static int ukbd_ioctl(void *, u_long, caddr_t, int, struct proc *); +Static int ukbd_ioctl(void *, u_long, caddr_t, int, usb_proc_ptr ); #ifdef WSDISPLAY_COMPAT_RAWKBD Static void ukbd_rawrepeat(void *v); #endif @@ -290,90 +266,53 @@ const struct wskbd_mapdata ukbd_keymapdata = { KB_US, #endif }; -#endif USB_DECLARE_DRIVER(ukbd); USB_MATCH(ukbd) { USB_MATCH_START(ukbd, uaa); - usb_interface_descriptor_t *id; + struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa; + int size; + void *desc; - /* Check that this is a keyboard that speaks the boot protocol. */ - if (uaa->iface == NULL) - return (UMATCH_NONE); - id = usbd_get_interface_descriptor(uaa->iface); - if (id == NULL || - id->bInterfaceClass != UICLASS_HID || - id->bInterfaceSubClass != UISUBCLASS_BOOT || - id->bInterfaceProtocol != UIPROTO_BOOT_KEYBOARD) + uhidev_get_report_desc(uha->parent, &desc, &size); + if (!hid_is_collection(desc, size, uha->reportid, + HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD))) return (UMATCH_NONE); - return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO); + + return (UMATCH_IFACECLASS); } USB_ATTACH(ukbd) { USB_ATTACH_START(ukbd, sc, uaa); - usbd_interface_handle iface = uaa->iface; - usb_interface_descriptor_t *id; - usb_endpoint_descriptor_t *ed; - usbd_status err; + struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa; u_int32_t qflags; - char devinfo[1024]; -#if defined(__NetBSD__) || defined(__OpenBSD__) + const char *parseerr; struct wskbddev_attach_args a; -#else - int i; -#endif - sc->sc_udev = uaa->device; - sc->sc_iface = iface; - id = usbd_get_interface_descriptor(iface); - usbd_devinfo(uaa->device, 0, devinfo); - USB_ATTACH_SETUP; - printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev), - devinfo, id->bInterfaceClass, id->bInterfaceSubClass); - - ed = usbd_interface2endpoint_descriptor(iface, 0); - if (ed == NULL) { - printf("%s: could not read endpoint descriptor\n", - USBDEVNAME(sc->sc_dev)); + sc->sc_hdev.sc_intr = ukbd_intr; + sc->sc_hdev.sc_parent = uha->parent; + sc->sc_hdev.sc_report_id = uha->reportid; + + parseerr = ukbd_parse_desc(sc); + if (parseerr != NULL) { + printf("\n%s: attach failed, %s\n", + sc->sc_hdev.sc_dev.dv_xname, parseerr); USB_ATTACH_ERROR_RETURN; } + +#ifdef DIAGNOSTIC + printf(": %d modifier keys, %d key codes", sc->sc_nmod, + sc->sc_nkeycode); +#endif + printf("\n"); - DPRINTFN(10,("ukbd_attach: bLength=%d bDescriptorType=%d " - "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d" - " bInterval=%d\n", - ed->bLength, ed->bDescriptorType, - ed->bEndpointAddress & UE_ADDR, - UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out", - ed->bmAttributes & UE_XFERTYPE, - UGETW(ed->wMaxPacketSize), ed->bInterval)); - - if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN || - (ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) { - printf("%s: unexpected endpoint\n", - USBDEVNAME(sc->sc_dev)); - USB_ATTACH_ERROR_RETURN; - } - qflags = usbd_get_quirks(uaa->device)->uq_flags; - if ((qflags & UQ_NO_SET_PROTO) == 0) { - err = usbd_set_protocol(iface, 0); - DPRINTFN(5, ("ukbd_attach: protocol set\n")); - if (err) { - printf("%s: set protocol failed\n", - USBDEVNAME(sc->sc_dev)); - USB_ATTACH_ERROR_RETURN; - } - } + qflags = usbd_get_quirks(uha->parent->sc_udev)->uq_flags; sc->sc_debounce = (qflags & UQ_SPUR_BUT_UP) != 0; - /* Ignore if SETIDLE fails since it is not crucial. */ - (void)usbd_set_idle(iface, 0, 0); - - sc->sc_ep_addr = ed->bEndpointAddress; - /* * Remember if we're the console keyboard. * @@ -398,26 +337,14 @@ USB_ATTACH(ukbd) a.accessops = &ukbd_accessops; a.accesscookie = sc; -#if defined(__OpenBSD__) -#ifdef WSDISPLAY_COMPAT_RAWKBD - timeout_set(&sc->sc_rawrepeat_ch, ukbd_rawrepeat, sc); -#endif - timeout_set(&sc->sc_delay, ukbd_delayed_decode, sc); -#endif - -#if defined(__NetBSD__) - callout_init(&sc->sc_rawrepeat_ch); - callout_init(&sc->sc_delay); -#endif + usb_callout_init(sc->sc_rawrepeat_ch); + usb_callout_init(sc->sc_delay); /* Flash the leds; no real purpose, just shows we're alive. */ ukbd_set_leds(sc, WSKBD_LED_SCROLL | WSKBD_LED_NUM | WSKBD_LED_CAPS); - usbd_delay_ms(uaa->device, 400); + usbd_delay_ms(uha->parent->sc_udev, 400); ukbd_set_leds(sc, 0); - usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, - USBDEV(sc->sc_dev)); - sc->sc_wskbddev = config_found(self, &a, wskbddevprint); USB_ATTACH_SUCCESS_RETURN; @@ -427,38 +354,27 @@ int ukbd_enable(void *v, int on) { struct ukbd_softc *sc = v; - usbd_status err; if (on && sc->sc_dying) return (EIO); /* Should only be called to change state */ if (sc->sc_enabled == on) { -#ifdef UKBD_DEBUG +#ifdef DIAGNOSTIC printf("ukbd_enable: %s: bad call on=%d\n", - USBDEVNAME(sc->sc_dev), on); + USBDEVNAME(sc->sc_hdev.sc_dev), on); #endif return (EBUSY); } DPRINTF(("ukbd_enable: sc=%p on=%d\n", sc, on)); + sc->sc_enabled = on; if (on) { - /* Set up interrupt pipe. */ - err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ep_addr, - USBD_SHORT_XFER_OK, &sc->sc_intrpipe, sc, - &sc->sc_ndata, sizeof(sc->sc_ndata), ukbd_intr, - USBD_DEFAULT_INTERVAL); - if (err) - return (EIO); + return (uhidev_open(&sc->sc_hdev)); } else { - /* Disable interrupts. */ - usbd_abort_pipe(sc->sc_intrpipe); - usbd_close_pipe(sc->sc_intrpipe); - sc->sc_intrpipe = NULL; + uhidev_close(&sc->sc_hdev); + return (0); } - sc->sc_enabled = on; - - return (0); } int @@ -507,7 +423,8 @@ USB_DETACH(ukbd) * XXX Should notify some other keyboard that it can be * XXX console, if there are any other keyboards. */ - printf("%s: was console keyboard\n", USBDEVNAME(sc->sc_dev)); + printf("%s: was console keyboard\n", + USBDEVNAME(sc->sc_hdev.sc_dev)); wskbd_cndetach(); ukbd_is_console = 1; #endif @@ -517,37 +434,34 @@ USB_DETACH(ukbd) rv = config_detach(sc->sc_wskbddev, flags); /* The console keyboard does not get a disable call, so check pipe. */ - if (sc->sc_intrpipe != NULL) { - usbd_abort_pipe(sc->sc_intrpipe); - usbd_close_pipe(sc->sc_intrpipe); - sc->sc_intrpipe = NULL; - } - - usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, - USBDEV(sc->sc_dev)); + if (sc->sc_hdev.sc_state & UHIDEV_OPEN) + uhidev_close(&sc->sc_hdev); return (rv); } void -ukbd_intr(xfer, addr, status) - usbd_xfer_handle xfer; - usbd_private_handle addr; - usbd_status status; +ukbd_intr(struct uhidev *addr, void *ibuf, u_int len) { - struct ukbd_softc *sc = addr; + struct ukbd_softc *sc = (struct ukbd_softc *)addr; struct ukbd_data *ud = &sc->sc_ndata; + int i; - DPRINTFN(5, ("ukbd_intr: status=%d\n", status)); - if (status == USBD_CANCELLED) - return; - - if (status) { - DPRINTF(("ukbd_intr: status=%d\n", status)); - if (status == USBD_STALLED) - usbd_clear_endpoint_stall_async(sc->sc_intrpipe); - return; +#ifdef UKBD_DEBUG + if (ukbddebug > 5) { + printf("ukbd_intr: data"); + for (i = 0; i < len; i++) + printf(" 0x%02x", ((u_char *)ibuf)[i]); + printf("\n"); } +#endif + + ud->modifiers = 0; + for (i = 0; i < sc->sc_nmod; i++) + if (hid_get_data(ibuf, &sc->sc_modloc[i])) + ud->modifiers |= sc->sc_mods[i].mask; + memcpy(ud->keycode, (char *)ibuf + sc->sc_keycodeloc.pos / 8, + sc->sc_nkeycode); if (sc->sc_debounce && !sc->sc_polling) { /* @@ -557,12 +471,8 @@ ukbd_intr(xfer, addr, status) * We avoid this bug by holding off decoding for 20 ms. */ sc->sc_data = *ud; -#if defined(__OpenBSD__) - timeout_add(&sc->sc_delay, hz / 50); -#else - callout_reset(&sc->sc_delay, hz / 50, ukbd_delayed_decode, sc); -#endif -#if DDB + usb_callout(sc->sc_delay, hz / 50, ukbd_delayed_decode, sc); +#ifdef DDB } else if (sc->sc_console_keyboard && !sc->sc_polling) { /* * For the console keyboard we can't deliver CTL-ALT-ESC @@ -571,11 +481,7 @@ ukbd_intr(xfer, addr, status) * loses bigtime. */ sc->sc_data = *ud; -#if defined(__OpenBSD__) - timeout_add(&sc->sc_delay, 1); /* NOT an immediate timeout */ -#else - callout_reset(&sc->sc_delay, 0, ukbd_delayed_decode, sc); -#endif + usb_callout(sc->sc_delay, 1, ukbd_delayed_decode, sc); #endif } else { ukbd_decode(sc, ud); @@ -607,7 +513,7 @@ ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud) */ if (ukbdtrace) { struct ukbdtraceinfo *p = &ukbdtracedata[ukbdtraceindex]; - p->unit = sc->sc_dev.dv_unit; + p->unit = sc->sc_hdev.sc_dev.dv_unit; microtime(&p->tv); p->ud = *ud; if (++ukbdtraceindex >= UKBDTRACESIZE) @@ -632,19 +538,19 @@ ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud) mod = ud->modifiers; omod = sc->sc_odata.modifiers; if (mod != omod) - for (i = 0; i < NMOD; i++) - if (( mod & ukbd_mods[i].mask) != - (omod & ukbd_mods[i].mask)) - ADDKEY(ukbd_mods[i].key | - (mod & ukbd_mods[i].mask + for (i = 0; i < sc->sc_nmod; i++) + if (( mod & sc->sc_mods[i].mask) != + (omod & sc->sc_mods[i].mask)) + ADDKEY(sc->sc_mods[i].key | + (mod & sc->sc_mods[i].mask ? PRESS : RELEASE)); - if (memcmp(ud->keycode, sc->sc_odata.keycode, NKEYCODE) != 0) { + if (memcmp(ud->keycode, sc->sc_odata.keycode, sc->sc_nkeycode) != 0) { /* Check for released keys. */ - for (i = 0; i < NKEYCODE; i++) { + for (i = 0; i < sc->sc_nkeycode; i++) { key = sc->sc_odata.keycode[i]; if (key == 0) continue; - for (j = 0; j < NKEYCODE; j++) + for (j = 0; j < sc->sc_nkeycode; j++) if (key == ud->keycode[j]) goto rfound; DPRINTFN(3,("ukbd_intr: relse key=0x%02x\n", key)); @@ -654,11 +560,11 @@ ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud) } /* Check for pressed keys. */ - for (i = 0; i < NKEYCODE; i++) { + for (i = 0; i < sc->sc_nkeycode; i++) { key = ud->keycode[i]; if (key == 0) continue; - for (j = 0; j < NKEYCODE; j++) + for (j = 0; j < sc->sc_nkeycode; j++) if (key == sc->sc_odata.keycode[j]) goto pfound; DPRINTFN(2,("ukbd_intr: press key=0x%02x\n", key)); @@ -680,7 +586,7 @@ ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud) } #ifdef WSDISPLAY_COMPAT_RAWKBD if (sc->sc_rawkbd) { - char cbuf[MAXKEYS * 2]; + u_char cbuf[MAXKEYS * 2]; int c; int npress; @@ -708,19 +614,11 @@ ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud) s = spltty(); wskbd_rawinput(sc->sc_wskbddev, cbuf, j); splx(s); -#if defined(__OpenBSD__) - timeout_del(&sc->sc_rawrepeat_ch); -#else - callout_stop(&sc->sc_rawrepeat_ch); -#endif + usb_uncallout(sc->sc_rawrepeat_ch, ukbd_rawrepeat, sc); if (npress != 0) { sc->sc_nrep = npress; -#if defined(__OpenBSD__) - timeout_add(&sc->sc_rawrepeat_ch, hz * REP_DELAY1/1000); -#else - callout_reset(&sc->sc_rawrepeat_ch, + usb_callout(sc->sc_rawrepeat_ch, hz * REP_DELAY1 / 1000, ukbd_rawrepeat, sc); -#endif } return; } @@ -742,21 +640,24 @@ ukbd_set_leds(void *v, int leds) struct ukbd_softc *sc = v; u_int8_t res; - DPRINTF(("ukbd_set_leds: sc=%p leds=%d\n", sc, leds)); + DPRINTF(("ukbd_set_leds: sc=%p leds=%d, sc_leds=%d\n", + sc, leds, sc->sc_leds)); if (sc->sc_dying) return; + if (sc->sc_leds == leds) + return; sc->sc_leds = leds; res = 0; - if (leds & WSKBD_LED_SCROLL) - res |= SCROLL_LOCK; - if (leds & WSKBD_LED_NUM) - res |= NUM_LOCK; - if (leds & WSKBD_LED_CAPS) - res |= CAPS_LOCK; - res |= leds & 0xf8; - usbd_set_report_async(sc->sc_iface, UHID_OUTPUT_REPORT, 0, &res, 1); + /* XXX not really right */ + if ((leds & WSKBD_LED_SCROLL) && sc->sc_scroloc.size == 1) + res |= 1 << sc->sc_scroloc.pos; + if ((leds & WSKBD_LED_NUM) && sc->sc_numloc.size == 1) + res |= 1 << sc->sc_numloc.pos; + if ((leds & WSKBD_LED_CAPS) && sc->sc_capsloc.size == 1) + res |= 1 << sc->sc_capsloc.pos; + uhidev_set_report_async(&sc->sc_hdev, UHID_OUTPUT_REPORT, &res, 1); } #ifdef WSDISPLAY_COMPAT_RAWKBD @@ -769,17 +670,13 @@ ukbd_rawrepeat(void *v) s = spltty(); wskbd_rawinput(sc->sc_wskbddev, sc->sc_rep, sc->sc_nrep); splx(s); -#if defined(__OpenBSD__) - timeout_add(&sc->sc_rawrepeat_ch, hz * REP_DELAYN / 1000); -#else - callout_reset(&sc->sc_rawrepeat_ch, hz * REP_DELAYN / 1000, + usb_callout(sc->sc_rawrepeat_ch, hz * REP_DELAYN / 1000, ukbd_rawrepeat, sc); -#endif } #endif int -ukbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) +ukbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, usb_proc_ptr p) { struct ukbd_softc *sc = v; @@ -797,17 +694,19 @@ ukbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) case WSKBDIO_SETMODE: DPRINTF(("ukbd_ioctl: set raw = %d\n", *(int *)data)); sc->sc_rawkbd = *(int *)data == WSKBD_RAW; -#if defined(__OpenBSD__) - timeout_del(&sc->sc_rawrepeat_ch); -#else - callout_stop(&sc->sc_rawrepeat_ch); -#endif + usb_uncallout(sc->sc_rawrepeat_ch, ukbd_rawrepeat, sc); return (0); #endif } return (-1); } +/* + * This is a hack to work around some broken ports that don't call + * cnpollc() before cngetc(). + */ +static int pollenter, warned; + /* Console interface. */ void ukbd_cngetc(void *v, u_int *type, int *data) @@ -815,12 +714,25 @@ ukbd_cngetc(void *v, u_int *type, int *data) struct ukbd_softc *sc = v; int s; int c; + int broken; + + if (pollenter == 0) { + if (!warned) { + printf("\n" +"This port is broken, it does not call cnpollc() before calling cngetc().\n" +"This should be fixed, but it will work anyway (for now).\n"); + warned = 1; + } + broken = 1; + ukbd_cnpollc(v, 1); + } else + broken = 0; DPRINTFN(0,("ukbd_cngetc: enter\n")); s = splusb(); sc->sc_polling = 1; while(sc->sc_npollchar <= 0) - usbd_dopoll(sc->sc_iface); + usbd_dopoll(sc->sc_hdev.sc_parent->sc_iface); sc->sc_polling = 0; c = sc->sc_pollchars[0]; sc->sc_npollchar--; @@ -830,6 +742,8 @@ ukbd_cngetc(void *v, u_int *type, int *data) *data = c & CODEMASK; splx(s); DPRINTFN(0,("ukbd_cngetc: return 0x%02x\n", c)); + if (broken) + ukbd_cnpollc(v, 0); } void @@ -840,7 +754,8 @@ ukbd_cnpollc(void *v, int on) DPRINTFN(2,("ukbd_cnpollc: sc=%p on=%d\n", v, on)); - (void)usbd_interface2device_handle(sc->sc_iface,&dev); + usbd_interface2device_handle(sc->sc_hdev.sc_parent->sc_iface, &dev); + if (on) pollenter++; else pollenter--; usbd_set_polling(dev, on); } @@ -856,3 +771,64 @@ ukbd_cnattach(void) ukbd_is_console = 1; return (0); } + +const char * +ukbd_parse_desc(struct ukbd_softc *sc) +{ + struct hid_data *d; + struct hid_item h; + int size; + void *desc; + int imod; + + uhidev_get_report_desc(sc->sc_hdev.sc_parent, &desc, &size); + imod = 0; + sc->sc_nkeycode = 0; + d = hid_start_parse(desc, size, hid_input); + while (hid_get_item(d, &h)) { + /*printf("ukbd: id=%d kind=%d usage=0x%x flags=0x%x pos=%d size=%d cnt=%d\n", + h.report_ID, h.kind, h.usage, h.flags, h.loc.pos, h.loc.size, h.loc.count);*/ + if (h.kind != hid_input || (h.flags & HIO_CONST) || + HID_GET_USAGE_PAGE(h.usage) != HUP_KEYBOARD || + h.report_ID != sc->sc_hdev.sc_report_id) + continue; + DPRINTF(("ukbd: imod=%d usage=0x%x flags=0x%x pos=%d size=%d " + "cnt=%d\n", imod, + h.usage, h.flags, h.loc.pos, h.loc.size, h.loc.count)); + if (h.flags & HIO_VARIABLE) { + if (h.loc.size != 1) + return ("bad modifier size"); + /* Single item */ + if (imod < MAXMOD) { + sc->sc_modloc[imod] = h.loc; + sc->sc_mods[imod].mask = 1 << imod; + sc->sc_mods[imod].key = HID_GET_USAGE(h.usage); + imod++; + } else + return ("too many modifier keys"); + } else { + /* Array */ + if (h.loc.size != 8) + return ("key code size != 8"); + if (h.loc.count > MAXKEYCODE) + return ("too many key codes"); + if (h.loc.pos % 8 != 0) + return ("key codes not on byte boundary"); + if (sc->sc_nkeycode != 0) + return ("multiple key code arrays\n"); + sc->sc_keycodeloc = h.loc; + sc->sc_nkeycode = h.loc.count; + } + } + sc->sc_nmod = imod; + hid_end_parse(d); + + hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_NUM_LOCK), + sc->sc_hdev.sc_report_id, hid_output, &sc->sc_numloc, NULL); + hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_CAPS_LOCK), + sc->sc_hdev.sc_report_id, hid_output, &sc->sc_capsloc, NULL); + hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_SCROLL_LOCK), + sc->sc_hdev.sc_report_id, hid_output, &sc->sc_scroloc, NULL); + + return (NULL); +} diff --git a/sys/dev/usb/ums.c b/sys/dev/usb/ums.c index 8bd88b43c81..324e5119a2c 100644 --- a/sys/dev/usb/ums.c +++ b/sys/dev/usb/ums.c @@ -1,5 +1,5 @@ -/* $OpenBSD: ums.c,v 1.8 2002/05/07 18:29:18 nate Exp $ */ -/* $NetBSD: ums.c,v 1.49 2001/10/26 17:58:21 augustss Exp $ */ +/* $OpenBSD: ums.c,v 1.9 2002/05/09 15:06:29 nate Exp $ */ +/* $NetBSD: ums.c,v 1.55 2001/12/31 12:15:22 augustss Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -42,8 +42,6 @@ * HID spec: http://www.usb.org/developers/data/devclass/hid1_1.pdf */ -/* XXX complete SPUR_UP change */ - #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> @@ -64,6 +62,7 @@ #include <dev/usb/usbdi_util.h> #include <dev/usb/usbdevs.h> #include <dev/usb/usb_quirks.h> +#include <dev/usb/uhidev.h> #include <dev/usb/hid.h> #include <dev/wscons/wsconsio.h> @@ -87,18 +86,13 @@ int umsdebug = 0; #define PS2MBUTMASK x04 #define PS2BUTMASK 0x0f +#define MAX_BUTTONS 7 /* must not exceed size of sc_buttons */ + struct ums_softc { - USBBASEDEVICE sc_dev; /* base device */ - usbd_device_handle sc_udev; - usbd_interface_handle sc_iface; /* interface */ - usbd_pipe_handle sc_intrpipe; /* interrupt pipe */ - int sc_ep_addr; - - u_char *sc_ibuf; - u_int8_t sc_iid; - int sc_isize; + struct uhidev sc_hdev; + struct hid_location sc_loc_x, sc_loc_y, sc_loc_z; - struct hid_location *sc_loc_btn; + struct hid_location sc_loc_btn[MAX_BUTTONS]; int sc_enabled; @@ -108,7 +102,6 @@ struct ums_softc { #define UMS_REVZ 0x04 /* Z-axis is reversed */ int nbuttons; -#define MAX_BUTTONS 31 /* chosen because sc_buttons is u_int32_t */ u_int32_t sc_buttons; /* mouse button status */ struct device *sc_wsmousedev; @@ -119,11 +112,11 @@ struct ums_softc { #define MOUSE_FLAGS_MASK (HIO_CONST|HIO_RELATIVE) #define MOUSE_FLAGS (HIO_RELATIVE) -Static void ums_intr(usbd_xfer_handle, usbd_private_handle, usbd_status); +Static void ums_intr(struct uhidev *addr, void *ibuf, u_int len); Static int ums_enable(void *); Static void ums_disable(void *); -Static int ums_ioctl(void *, u_long, caddr_t, int, struct proc *); +Static int ums_ioctl(void *, u_long, caddr_t, int, usb_proc_ptr); const struct wsmouse_accessops ums_accessops = { ums_enable, @@ -136,115 +129,72 @@ USB_DECLARE_DRIVER(ums); USB_MATCH(ums) { USB_MATCH_START(ums, uaa); - usb_interface_descriptor_t *id; - int size, ret; + struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa; + int size; void *desc; - usbd_status err; - if (uaa->iface == NULL) - return (UMATCH_NONE); - id = usbd_get_interface_descriptor(uaa->iface); - if (id == NULL || id->bInterfaceClass != UICLASS_HID) + uhidev_get_report_desc(uha->parent, &desc, &size); + if (!hid_is_collection(desc, size, uha->reportid, + HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))) return (UMATCH_NONE); - err = usbd_read_report_desc(uaa->iface, &desc, &size, M_TEMP); - if (err) - return (UMATCH_NONE); - - if (hid_is_collection(desc, size, - HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))) - ret = UMATCH_IFACECLASS; - else - ret = UMATCH_NONE; - - free(desc, M_TEMP); - return (ret); + return (UMATCH_IFACECLASS); } USB_ATTACH(ums) { USB_ATTACH_START(ums, sc, uaa); - usbd_interface_handle iface = uaa->iface; - usb_interface_descriptor_t *id; - usb_endpoint_descriptor_t *ed; + struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa; struct wsmousedev_attach_args a; int size; void *desc; - usbd_status err; - char devinfo[1024]; u_int32_t flags, quirks; int i, wheel; struct hid_location loc_btn; - - sc->sc_udev = uaa->device; - sc->sc_iface = iface; - id = usbd_get_interface_descriptor(iface); - usbd_devinfo(uaa->device, 0, devinfo); - USB_ATTACH_SETUP; - printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev), - devinfo, id->bInterfaceClass, id->bInterfaceSubClass); - ed = usbd_interface2endpoint_descriptor(iface, 0); - if (ed == NULL) { - printf("%s: could not read endpoint descriptor\n", - USBDEVNAME(sc->sc_dev)); - USB_ATTACH_ERROR_RETURN; - } - DPRINTFN(10,("ums_attach: bLength=%d bDescriptorType=%d " - "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d" - " bInterval=%d\n", - ed->bLength, ed->bDescriptorType, - ed->bEndpointAddress & UE_ADDR, - UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out", - ed->bmAttributes & UE_XFERTYPE, - UGETW(ed->wMaxPacketSize), ed->bInterval)); - - if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN || - (ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) { - printf("%s: unexpected endpoint\n", - USBDEVNAME(sc->sc_dev)); - USB_ATTACH_ERROR_RETURN; - } + sc->sc_hdev.sc_intr = ums_intr; + sc->sc_hdev.sc_parent = uha->parent; + sc->sc_hdev.sc_report_id = uha->reportid; - quirks = usbd_get_quirks(uaa->device)->uq_flags; + quirks = usbd_get_quirks(uha->parent->sc_udev)->uq_flags; if (quirks & UQ_MS_REVZ) sc->flags |= UMS_REVZ; if (quirks & UQ_SPUR_BUT_UP) sc->flags |= UMS_SPUR_BUT_UP; - err = usbd_read_report_desc(uaa->iface, &desc, &size, M_TEMP); - if (err) - USB_ATTACH_ERROR_RETURN; + uhidev_get_report_desc(uha->parent, &desc, &size); if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X), - hid_input, &sc->sc_loc_x, &flags)) { - printf("%s: mouse has no X report\n", USBDEVNAME(sc->sc_dev)); + uha->reportid, hid_input, &sc->sc_loc_x, &flags)) { + printf("\n%s: mouse has no X report\n", + USBDEVNAME(sc->sc_hdev.sc_dev)); USB_ATTACH_ERROR_RETURN; } if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) { - printf("%s: X report 0x%04x not supported\n", - USBDEVNAME(sc->sc_dev), flags); + printf("\n%s: X report 0x%04x not supported\n", + USBDEVNAME(sc->sc_hdev.sc_dev), flags); USB_ATTACH_ERROR_RETURN; } if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y), - hid_input, &sc->sc_loc_y, &flags)) { - printf("%s: mouse has no Y report\n", USBDEVNAME(sc->sc_dev)); + uha->reportid, hid_input, &sc->sc_loc_y, &flags)) { + printf("\n%s: mouse has no Y report\n", + USBDEVNAME(sc->sc_hdev.sc_dev)); USB_ATTACH_ERROR_RETURN; } if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) { - printf("%s: Y report 0x%04x not supported\n", - USBDEVNAME(sc->sc_dev), flags); + printf("\n%s: Y report 0x%04x not supported\n", + USBDEVNAME(sc->sc_hdev.sc_dev), flags); USB_ATTACH_ERROR_RETURN; } /* Try to guess the Z activator: first check Z, then WHEEL. */ wheel = 0; if (hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z), - hid_input, &sc->sc_loc_z, &flags) || + uha->reportid, hid_input, &sc->sc_loc_z, &flags) || (wheel = hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_WHEEL), - hid_input, &sc->sc_loc_z, &flags))) { + uha->reportid, hid_input, &sc->sc_loc_z, &flags))) { if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) { sc->sc_loc_z.size = 0; /* Bad Z coord, ignore it */ } else { @@ -258,34 +208,18 @@ USB_ATTACH(ums) /* figure out the number of buttons */ for (i = 1; i <= MAX_BUTTONS; i++) if (!hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i), - hid_input, &loc_btn, 0)) + uha->reportid, hid_input, &loc_btn, 0)) break; sc->nbuttons = i - 1; - sc->sc_loc_btn = malloc(sizeof(struct hid_location) * sc->nbuttons, - M_USBDEV, M_NOWAIT); - if (!sc->sc_loc_btn) { - printf("%s: no memory\n", USBDEVNAME(sc->sc_dev)); - USB_ATTACH_ERROR_RETURN; - } - printf("%s: %d button%s%s\n", USBDEVNAME(sc->sc_dev), + printf(": %d button%s%s\n", sc->nbuttons, sc->nbuttons == 1 ? "" : "s", sc->flags & UMS_Z ? " and Z dir." : ""); for (i = 1; i <= sc->nbuttons; i++) hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i), - hid_input, &sc->sc_loc_btn[i-1], 0); - - sc->sc_isize = hid_report_size(desc, size, hid_input, &sc->sc_iid); - sc->sc_ibuf = malloc(sc->sc_isize, M_USBDEV, M_NOWAIT); - if (sc->sc_ibuf == NULL) { - printf("%s: no memory\n", USBDEVNAME(sc->sc_dev)); - free(sc->sc_loc_btn, M_USBDEV); - USB_ATTACH_ERROR_RETURN; - } - - sc->sc_ep_addr = ed->bEndpointAddress; - free(desc, M_TEMP); + uha->reportid, hid_input, + &sc->sc_loc_btn[i-1], 0); #ifdef USB_DEBUG DPRINTF(("ums_attach: sc=%p\n", sc)); @@ -300,15 +234,11 @@ USB_ATTACH(ums) DPRINTF(("ums_attach: B%d\t%d/%d\n", i, sc->sc_loc_btn[i-1].pos,sc->sc_loc_btn[i-1].size)); } - DPRINTF(("ums_attach: size=%d, id=%d\n", sc->sc_isize, sc->sc_iid)); #endif a.accessops = &ums_accessops; a.accesscookie = sc; - usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, - USBDEV(sc->sc_dev)); - sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint); USB_ATTACH_SUCCESS_RETURN; @@ -344,45 +274,21 @@ USB_DETACH(ums) /* No need to do reference counting of ums, wsmouse has all the goo. */ if (sc->sc_wsmousedev != NULL) rv = config_detach(sc->sc_wsmousedev, flags); - if (rv == 0) { - free(sc->sc_loc_btn, M_USBDEV); - free(sc->sc_ibuf, M_USBDEV); - } - - usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, - USBDEV(sc->sc_dev)); return (rv); } void -ums_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status) +ums_intr(struct uhidev *addr, void *ibuf, u_int len) { - struct ums_softc *sc = addr; - u_char *ibuf; + struct ums_softc *sc = (struct ums_softc *)addr; int dx, dy, dz; u_int32_t buttons = 0; int i; int s; - DPRINTFN(5, ("ums_intr: sc=%p status=%d\n", sc, status)); - DPRINTFN(5, ("ums_intr: data = %02x %02x %02x\n", - sc->sc_ibuf[0], sc->sc_ibuf[1], sc->sc_ibuf[2])); - - if (status == USBD_CANCELLED) - return; - - if (status) { - DPRINTF(("ums_intr: status=%d\n", status)); - usbd_clear_endpoint_stall_async(sc->sc_intrpipe); - return; - } + DPRINTFN(5,("ums_intr: len=%d\n", len)); - ibuf = sc->sc_ibuf; - if (sc->sc_iid != 0) { - if (*ibuf++ != sc->sc_iid) - return; - } dx = hid_get_data(ibuf, &sc->sc_loc_x); dy = -hid_get_data(ibuf, &sc->sc_loc_y); dz = hid_get_data(ibuf, &sc->sc_loc_z); @@ -410,8 +316,6 @@ ums_enable(void *v) { struct ums_softc *sc = v; - usbd_status err; - DPRINTFN(1,("ums_enable: sc=%p\n", sc)); if (sc->sc_dying) @@ -423,17 +327,7 @@ ums_enable(void *v) sc->sc_enabled = 1; sc->sc_buttons = 0; - /* Set up interrupt pipe. */ - err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ep_addr, - USBD_SHORT_XFER_OK, &sc->sc_intrpipe, sc, - sc->sc_ibuf, sc->sc_isize, ums_intr, USBD_DEFAULT_INTERVAL); - if (err) { - DPRINTF(("ums_enable: usbd_open_pipe_intr failed, error=%d\n", - err)); - sc->sc_enabled = 0; - return (EIO); - } - return (0); + return (uhidev_open(&sc->sc_hdev)); } Static void @@ -449,15 +343,12 @@ ums_disable(void *v) } #endif - /* Disable interrupts. */ - usbd_abort_pipe(sc->sc_intrpipe); - usbd_close_pipe(sc->sc_intrpipe); - sc->sc_enabled = 0; + return (uhidev_close(&sc->sc_hdev)); } Static int -ums_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) +ums_ioctl(void *v, u_long cmd, caddr_t data, int flag, usb_proc_ptr p) { switch (cmd) { diff --git a/sys/dev/usb/usb.h b/sys/dev/usb/usb.h index 89121f65dec..8defac116a4 100644 --- a/sys/dev/usb/usb.h +++ b/sys/dev/usb/usb.h @@ -1,4 +1,4 @@ -/* $OpenBSD: usb.h,v 1.17 2002/05/07 18:29:18 nate Exp $ */ +/* $OpenBSD: usb.h,v 1.18 2002/05/09 15:06:29 nate Exp $ */ /* $NetBSD: usb.h,v 1.52 2001/07/23 15:17:50 nathanw Exp $ */ /* $FreeBSD: src/sys/dev/usb/usb.h,v 1.14 1999/11/17 22:33:46 n_hibma Exp $ */ @@ -588,6 +588,7 @@ struct usb_event { #define USB_SET_IMMED _IOW ('U', 22, int) #define USB_GET_REPORT _IOWR('U', 23, struct usb_ctl_report) #define USB_SET_REPORT _IOW ('U', 24, struct usb_ctl_report) +#define USB_GET_REPORT_ID _IOR ('U', 25, int) /* Generic USB device */ #define USB_GET_CONFIG _IOR ('U', 100, int) diff --git a/sys/dev/usb/usb_port.h b/sys/dev/usb/usb_port.h index bb15013ec29..1031618e4ab 100644 --- a/sys/dev/usb/usb_port.h +++ b/sys/dev/usb/usb_port.h @@ -1,4 +1,4 @@ -/* $OpenBSD: usb_port.h,v 1.37 2002/05/07 18:29:18 nate Exp $ */ +/* $OpenBSD: usb_port.h,v 1.38 2002/05/09 15:06:29 nate Exp $ */ /* $NetBSD: usb_port.h,v 1.44 2001/05/14 20:35:29 bouyer Exp $ */ /* $FreeBSD: src/sys/dev/usb/usb_port.h,v 1.21 1999/11/17 22:33:47 n_hibma Exp $ */ @@ -190,6 +190,7 @@ __CONCAT(dname,_detach)(self, flags) \ */ #ifdef USB_DEBUG #define UKBD_DEBUG 1 +#define UHIDEV_DEBUG 1 #define UHID_DEBUG 1 #define OHCI_DEBUG 1 #define UGEN_DEBUG 1 @@ -235,6 +236,8 @@ __CONCAT(dname,_detach)(self, flags) \ #define show_scsipi_cmd show_scsi_cmd #define xs_control flags #define xs_status status +#define UHIDBUSCF_REPORTID -1 +#define UHIDBUSCF_REPORTID_DEFAULT -1 #define bswap32(x) swap32(x) #define bswap16(x) swap16(x) diff --git a/sys/dev/usb/usbhid.h b/sys/dev/usb/usbhid.h index 695c1cdb925..d88c6d375ee 100644 --- a/sys/dev/usb/usbhid.h +++ b/sys/dev/usb/usbhid.h @@ -1,5 +1,5 @@ -/* $OpenBSD: usbhid.h,v 1.6 2002/05/07 18:29:19 nate Exp $ */ -/* $NetBSD: usbhid.h,v 1.9 2000/09/03 19:09:14 augustss Exp $ */ +/* $OpenBSD: usbhid.h,v 1.7 2002/05/09 15:06:29 nate Exp $ */ +/* $NetBSD: usbhid.h,v 1.11 2001/12/28 00:20:24 augustss Exp $ */ /* $FreeBSD: src/sys/dev/usb/usbhid.h,v 1.7 1999/11/17 22:33:51 n_hibma Exp $ */ /* @@ -165,12 +165,25 @@ typedef struct usb_hid_descriptor { #define HUD_ERASER 0x0045 #define HUD_TABLET_PICK 0x0046 -#define HID_USAGE2(p,u) (((p) << 16) | u) +/* Usages LEDs */ +#define HUD_LED_NUM_LOCK 0x0001 +#define HUD_LED_CAPS_LOCK 0x0002 +#define HUD_LED_SCROLL_LOCK 0x0003 +#define HUD_LED_COMPOSE 0x0004 +#define HUD_LED_KANA 0x0005 + +#define HID_USAGE2(p, u) (((p) << 16) | u) +#define HID_GET_USAGE(u) ((u) & 0xffff) +#define HID_GET_USAGE_PAGE(u) (((u) >> 16) & 0xffff) #define UHID_INPUT_REPORT 0x01 #define UHID_OUTPUT_REPORT 0x02 #define UHID_FEATURE_REPORT 0x03 +#define HCOLL_PHYSICAL 0 +#define HCOLL_APPLICATION 1 +#define HCOLL_LOGICAL 2 + /* Bits in the input/output/feature items */ #define HIO_CONST 0x001 #define HIO_VARIABLE 0x002 |