[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

usb hid stuff



The following diff brings the usb hid stuff up to date.  This includes
mods to uhid, ukbd, and ums.  It also includes a new notion of a uhidev.
This is kinda like a uhid bus.  This is for devices which represent
themselves as more than one hid device.  Some keyboards do this.  I also
have a ps/2 kbd+mouse converter that does this as well.

This affects i386, macppc, sparc64, and alpha.  Since I've moved, I only
really have access to i386 for a while.  Can others please try this out?

Thanks,
  Nate

Index: arch/alpha/conf/GENERIC
===================================================================
RCS file: /cvs/src/sys/arch/alpha/conf/GENERIC,v
retrieving revision 1.106
diff -u -r1.106 GENERIC
--- arch/alpha/conf/GENERIC	2 May 2002 22:56:06 -0000	1.106
+++ arch/alpha/conf/GENERIC	6 May 2002 01:36:43 -0000
@@ -53,7 +53,12 @@

 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 @@
 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
Index: arch/i386/conf/GENERIC
===================================================================
RCS file: /cvs/src/sys/arch/i386/conf/GENERIC,v
retrieving revision 1.295
diff -u -r1.295 GENERIC
--- arch/i386/conf/GENERIC	25 Apr 2002 04:56:59 -0000	1.295
+++ arch/i386/conf/GENERIC	6 May 2002 01:36:43 -0000
@@ -91,7 +91,6 @@

 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 @@

 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
Index: arch/macppc/conf/GENERIC
===================================================================
RCS file: /cvs/src/sys/arch/macppc/conf/GENERIC,v
retrieving revision 1.22
diff -u -r1.22 GENERIC
--- arch/macppc/conf/GENERIC	8 Apr 2002 17:02:44 -0000	1.22
+++ arch/macppc/conf/GENERIC	6 May 2002 01:36:43 -0000
@@ -143,9 +143,10 @@
 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
Index: arch/sparc64/conf/GENERIC
===================================================================
RCS file: /cvs/src/sys/arch/sparc64/conf/GENERIC,v
retrieving revision 1.58
diff -u -r1.58 GENERIC
--- arch/sparc64/conf/GENERIC	18 Apr 2002 14:15:11 -0000	1.58
+++ arch/sparc64/conf/GENERIC	6 May 2002 01:36:43 -0000
@@ -60,11 +60,12 @@
 # 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
Index: dev/usb/files.usb
===================================================================
RCS file: /cvs/src/sys/dev/usb/files.usb,v
retrieving revision 1.21
diff -u -r1.21 files.usb
--- dev/usb/files.usb	2 Oct 2001 01:37:36 -0000	1.21
+++ dev/usb/files.usb	6 May 2002 01:36:43 -0000
@@ -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 @@
 attach	ugen at uhub
 file	dev/usb/ugen.c			ugen		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
-attach	uhid at uhub
-file	dev/usb/uhid.c			uhid		needs-flag
-
+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
@@ -70,11 +88,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
Index: dev/usb/hid.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/hid.c,v
retrieving revision 1.9
diff -u -r1.9 hid.c
--- dev/usb/hid.c	8 Nov 2000 18:10:37 -0000	1.9
+++ dev/usb/hid.c	6 May 2002 01:36:43 -0000
@@ -1,5 +1,5 @@
 /*	$OpenBSD: hid.c,v 1.9 2000/11/08 18:10:37 aaron Exp $ */
-/*	$NetBSD: hid.c,v 1.16 2000/06/01 14:28:57 augustss 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 @@

 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 @@
 	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 @@
 }

 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 @@
 	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 @@
 			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 @@
 			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 @@
 					}
 					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 @@
 				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 @@
 				break;
 			case 8:
 				c->report_ID = dval;
+				c->loc.pos = 0;
 				break;
 			case 9:
 				c->loc.count = dval;
@@ -367,35 +378,51 @@
 }

 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 @@
 }

 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);
 }
Index: dev/usb/hid.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/hid.h,v
retrieving revision 1.4
diff -u -r1.4 hid.h
--- dev/usb/hid.h	8 Nov 2000 18:10:37 -0000	1.4
+++ dev/usb/hid.h	6 May 2002 01:36:43 -0000
@@ -1,5 +1,5 @@
 /*	$OpenBSD: hid.h,v 1.4 2000/11/08 18:10:37 aaron Exp $ */
-/*	$NetBSD: hid.h,v 1.6 2000/06/01 14:28:57 augustss 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 *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);
Index: dev/usb/uhid.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/uhid.c,v
retrieving revision 1.16
diff -u -r1.16 uhid.c
--- dev/usb/uhid.c	2 May 2002 20:08:04 -0000	1.16
+++ dev/usb/uhid.c	6 May 2002 01:36:43 -0000
@@ -1,6 +1,5 @@
 /*	$OpenBSD: uhid.c,v 1.16 2002/05/02 20:08:04 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 $	*/
+/*	$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 @@
 #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 @@
 #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_hdev.sc_intr = uhid_intr;
+	sc->sc_hdev.sc_parent = uha->parent;
+	sc->sc_hdev.sc_report_id = uha->reportid;
+
+	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);

-	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_repdesc = desc;
-	sc->sc_repdesc_size = size;
-
-#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 @@
 	}
 	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 @@
 	/* 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 @@
 }

 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 @@
 	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 @@

 	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 @@
 {
 	int s;
 	int error = 0;
+	int extra;
 	size_t length;
 	u_char buffer[UHID_CHUNK];
 	usbd_status err;
@@ -462,12 +291,12 @@
 	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 @@
 			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 @@
 	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 @@
 		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 @@
 	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 @@
 		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 @@
 		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 @@
 		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 @@
 }

 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 @@
 	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 @@
 	splx(s);
 	return (revents);
 }
-
-#if defined(__FreeBSD__)
-DRIVER_MODULE(uhid, uhub, uhid_driver, uhid_devclass, usbd_driver_load, 0);
-#endif
Index: dev/usb/uhidev.c
===================================================================
RCS file: dev/usb/uhidev.c
diff -N dev/usb/uhidev.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ dev/usb/uhidev.c	6 May 2002 01:36:43 -0000
@@ -0,0 +1,513 @@
+/*	$OpenBSD$	*/
+/*	$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);
+}
Index: dev/usb/uhidev.h
===================================================================
RCS file: dev/usb/uhidev.h
diff -N dev/usb/uhidev.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ dev/usb/uhidev.h	6 May 2002 01:36:43 -0000
@@ -0,0 +1,91 @@
+/*	$OpenBSD$	*/
+/*	$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);
Index: dev/usb/ukbd.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/ukbd.c,v
retrieving revision 1.11
diff -u -r1.11 ukbd.c
--- dev/usb/ukbd.c	3 Apr 2002 17:27:58 -0000	1.11
+++ dev/usb/ukbd.c	6 May 2002 01:36:44 -0000
@@ -1,5 +1,5 @@
 /*	$OpenBSD: ukbd.c,v 1.11 2002/04/03 17:27:58 jason Exp $	*/
-/*      $NetBSD: ukbd.c,v 1.69 2001/10/24 21:02:18 augustss 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 @@
 #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 @@
 	int sc_polling;
 	int sc_npollchar;
 	u_int16_t sc_pollchars[MAXKEYS];
-#endif

 	u_char sc_dying;
 };
@@ -254,22 +231,21 @@
 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 @@
 	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 @@
 	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 @@
 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 @@
 		 * 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 @@
 		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 @@
 		 * 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 @@
 		 * 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 @@
 	 */
 	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 @@
 	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 @@
 		}

 		/* 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 @@
 	}
 #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 @@
 		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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	*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 @@

 	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);
 }

@@ -855,4 +770,65 @@
 	 */
 	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);
 }
Index: dev/usb/ums.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/ums.c,v
retrieving revision 1.6
diff -u -r1.6 ums.c
--- dev/usb/ums.c	31 Oct 2001 04:24:44 -0000	1.6
+++ dev/usb/ums.c	6 May 2002 01:36:44 -0000
@@ -1,5 +1,5 @@
 /*	$OpenBSD: ums.c,v 1.6 2001/10/31 04:24:44 nate Exp $ */
-/*	$NetBSD: ums.c,v 1.49 2001/10/26 17:58:21 augustss 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 @@
 #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 @@
 #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 @@
 #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_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 @@
 	/* 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 @@
 		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 @@
 	/* 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 @@
 {
 	struct ums_softc *sc = v;

-	usbd_status err;
-
 	DPRINTFN(1,("ums_enable: sc=%p\n", sc));

 	if (sc->sc_dying)
@@ -423,17 +327,7 @@
 	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 @@
 	}
 #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) {
Index: dev/usb/usb.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/usb.h,v
retrieving revision 1.15
diff -u -r1.15 usb.h
--- dev/usb/usb.h	2 May 2002 20:08:04 -0000	1.15
+++ dev/usb/usb.h	6 May 2002 01:36:44 -0000
@@ -588,6 +588,7 @@
 #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)
Index: dev/usb/usb_port.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/usb_port.h,v
retrieving revision 1.33
diff -u -r1.33 usb_port.h
--- dev/usb/usb_port.h	1 Apr 2002 21:47:07 -0000	1.33
+++ dev/usb/usb_port.h	6 May 2002 01:36:44 -0000
@@ -190,6 +190,7 @@
  */
 #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 @@
 #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)
@@ -276,6 +279,7 @@
 #define realloc usb_realloc
 void *usb_realloc(void *, u_int, int, int);

+typedef struct proc *usb_proc_ptr;
 typedef struct device *device_ptr_t;
 #define USBBASEDEVICE struct device
 #define USBDEV(bdev) (&(bdev))
Index: dev/usb/usbhid.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/usbhid.h,v
retrieving revision 1.4
diff -u -r1.4 usbhid.h
--- dev/usb/usbhid.h	8 Nov 2000 18:10:39 -0000	1.4
+++ dev/usb/usbhid.h	6 May 2002 01:36:44 -0000
@@ -1,5 +1,5 @@
 /*	$OpenBSD: usbhid.h,v 1.4 2000/11/08 18:10:39 aaron Exp $ */
-/*	$NetBSD: usbhid.h,v 1.9 2000/09/03 19:09:14 augustss 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,11 +165,24 @@
 #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