Index: conf/files
===================================================================
RCS file: /home/ncvs/src/sys/conf/files,v
retrieving revision 1.1080
diff -u -p -r1.1080 files
--- conf/files	29 Dec 2005 01:43:46 -0000	1.1080
+++ conf/files	2 Jan 2006 19:59:41 -0000
@@ -969,6 +969,7 @@ dev/usb/ugen.c			optional ugen
 dev/usb/uhci.c			optional uhci
 dev/usb/uhci_pci.c		optional uhci pci
 dev/usb/uhid.c			optional uhid
+dev/usb/uhidev.c		optional uhid
 dev/usb/uhub.c			optional usb
 dev/usb/ukbd.c			optional ukbd
 dev/usb/ulpt.c			optional ulpt
Index: dev/usb/hid.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/usb/hid.c,v
retrieving revision 1.25
diff -u -p -r1.25 hid.c
--- dev/usb/hid.c	6 Feb 2005 12:41:00 -0000	1.25
+++ dev/usb/hid.c	2 Jan 2006 19:59:43 -0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: hid.c,v 1.17 2001/11/13 06:24:53 lukem Exp $	*/
+/*	$NetBSD: hid.c,v 1.23 2002/07/11 21:14:25 augustss Exp $	*/
 
 
 #include <sys/cdefs.h>
@@ -63,7 +63,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;
@@ -74,13 +74,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;
@@ -94,14 +95,14 @@ 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|M_ZERO);
 	s->start = s->p = d;
 	s->end = (char *)d + len;
-	s->kindset = kindset;
+	s->kind = kind;
 	return (s);
 }
 
@@ -128,15 +129,19 @@ hid_get_item(struct hid_data *s, struct 
 	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 +179,12 @@ hid_get_item(struct hid_data *s, struct 
 			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 +197,22 @@ hid_get_item(struct hid_data *s, struct 
 			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 +229,18 @@ hid_get_item(struct hid_data *s, struct 
 					}
 					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 +251,12 @@ hid_get_item(struct hid_data *s, struct 
 				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 +292,7 @@ hid_get_item(struct hid_data *s, struct 
 				break;
 			case 8:
 				c->report_ID = dval;
+				c->loc.pos = 0;
 				break;
 			case 9:
 				c->loc.count = dval;
@@ -367,35 +375,51 @@ hid_get_item(struct hid_data *s, struct 
 }
 
 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)
-			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 +461,33 @@ hid_get_data(u_char *buf, struct hid_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);
 }
Index: dev/usb/hid.h
===================================================================
RCS file: /home/ncvs/src/sys/dev/usb/hid.h,v
retrieving revision 1.13
diff -u -p -r1.13 hid.h
--- dev/usb/hid.h	6 Jan 2005 01:43:27 -0000	1.13
+++ dev/usb/hid.h	2 Jan 2006 19:59:43 -0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: hid.h,v 1.6 2000/06/01 14:28:57 augustss Exp $	*/
+/*	$NetBSD: hid.h,v 1.10 2005/12/11 12:24:00 christos Exp $	*/
 /*	$FreeBSD: src/sys/dev/usb/hid.h,v 1.13 2005/01/06 01:43:27 imp Exp $ */
 
 /*-
@@ -39,7 +39,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 {
@@ -80,12 +85,11 @@ struct hid_item {
 	struct hid_item *next;
 };
 
-struct hid_data *hid_start_parse(void *d, int len, int kindset);
-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);
-u_long hid_get_data(u_char *buf, struct hid_location *loc);
-int hid_is_collection(void *desc, int size, u_int32_t usage);
+struct hid_data *hid_start_parse(void *, int, enum hid_kind);
+void hid_end_parse(struct hid_data *);
+int hid_get_item(struct hid_data *, struct hid_item *);
+int hid_report_size(void *, int, enum hid_kind, u_int8_t);
+int hid_locate(void *, int, u_int32_t, u_int8_t, enum hid_kind,
+    struct hid_location *, u_int32_t *);
+u_long hid_get_data(u_char *, struct hid_location *);
+int hid_is_collection(void *, int, u_int8_t, u_int32_t);
Index: dev/usb/uhid.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/usb/uhid.c,v
retrieving revision 1.80
diff -u -p -r1.80 uhid.c
--- dev/usb/uhid.c	31 Dec 2005 04:38:50 -0000	1.80
+++ dev/usb/uhid.c	2 Jan 2006 19:59:43 -0000
@@ -89,9 +89,7 @@ __FBSDID("$FreeBSD: src/sys/dev/usb/uhid
 #include <dev/usb/usbdi_util.h>
 #include <dev/usb/hid.h>
 
-/* Replacement report descriptors for devices shipped with broken ones */
-#include <dev/usb/ugraphire_rdesc.h>
-#include <dev/usb/uxb360gp_rdesc.h>
+#include <dev/usb/uhidev.h>
 
 /* For hid blacklist quirk */
 #include <dev/usb/usb_quirks.h>
@@ -109,33 +107,20 @@ SYSCTL_INT(_hw_usb_uhid, OID_AUTO, debug
 #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 */
 	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;
@@ -145,10 +130,6 @@ struct uhid_softc {
 #endif
 };
 
-#define	UHIDUNIT(dev)	(minor(dev))
-#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__)
@@ -176,8 +157,11 @@ Static struct cdevsw uhid_cdevsw = {
 };
 #endif
 
-Static void uhid_intr(usbd_xfer_handle, usbd_private_handle,
-			   usbd_status);
+Static void uhid_intr(struct uhidev *, void *, u_int);
+
+#define	UHIDUNIT(dev)	(minor(dev))
+#define	UHID_CHUNK	128	/* chunk size for read */
+#define	UHID_BSIZE	1020	/* buffer size */
 
 Static int uhid_do_read(struct uhid_softc *, struct uio *uio, int);
 Static int uhid_do_write(struct uhid_softc *, struct uio *uio, int);
@@ -188,26 +172,9 @@ 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)
-		return (UMATCH_NONE);
-	if  (id->bInterfaceClass != UICLASS_HID) {
-		/* The Xbox 360 gamepad doesn't use the HID class. */
-		if (id->bInterfaceClass != UICLASS_VENDOR ||
-		    id->bInterfaceSubClass != UISUBCLASS_XBOX360_CONTROLLER ||
-		    id->bInterfaceProtocol != UIPROTO_XBOX360_GAMEPAD)
-			return (UMATCH_NONE);
-	}
-	if (usbd_get_quirks(uaa->device)->uq_flags & UQ_HID_IGNORE)
-		return (UMATCH_NONE);
-#if 0
-	if (uaa->matchlvl)
-		return (uaa->matchlvl);
+#ifdef USB_DEBUG
+	UHID_MATCH_START(uhid, uha);
+	DPRINTF(("uhid_match: report=%d\n", uha->reportid));
 #endif
 
 	return (UMATCH_IFACECLASS_GENERIC);
@@ -215,109 +182,29 @@ USB_MATCH(uhid)
 
 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;
+	UHID_ATTACH_START(uhid, sc, uha);
+	int size, repid;
 	void *desc;
-	const void *descptr;
-	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, USBD_SHOW_INTERFACE_CLASS, devinfo);
-	USB_ATTACH_SETUP;
-
-	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;
-
-	descptr = NULL;
-	if (uaa->vendor == USB_VENDOR_WACOM) {
-		/* The report descriptor for the Wacom Graphire is broken. */
-		if (uaa->product == USB_PRODUCT_WACOM_GRAPHIRE) {
-			size = sizeof uhid_graphire_report_descr;
-			descptr = uhid_graphire_report_descr;
-		} else if (uaa->product == USB_PRODUCT_WACOM_GRAPHIRE3_4X5) {
-			static uByte reportbuf[] = {2, 2, 2};
-
-			/*
-			 * The Graphire3 needs 0x0202 to be written to
-			 * feature report ID 2 before it'll start
-			 * returning digitizer data.
-			 */
-			usbd_set_report(uaa->iface, UHID_FEATURE_REPORT, 2,
-			    &reportbuf, sizeof reportbuf);
-
-			size = sizeof uhid_graphire3_4x5_report_descr;
-			descptr = uhid_graphire3_4x5_report_descr;
-		}
-	} else if (id->bInterfaceClass == UICLASS_VENDOR &&
-	    id->bInterfaceSubClass == UISUBCLASS_XBOX360_CONTROLLER &&
-	    id->bInterfaceProtocol == UIPROTO_XBOX360_GAMEPAD) {
-		/* The Xbox 360 gamepad has no report descriptor. */
-		size = sizeof uhid_xb360gp_report_descr;
-		descptr = uhid_xb360gp_report_descr;
-	}
-
-	if (descptr) {
-		desc = malloc(size, M_USBDEV, M_NOWAIT);
-		if (desc == NULL)
-			err = USBD_NOMEM;
-		else {
-			err = USBD_NORMAL_COMPLETION;
-			memcpy(desc, descptr, 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_repdesc = desc;
-	sc->sc_repdesc_size = size;
+	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);
 
 #if defined(__FreeBSD__)
 	sc->dev = make_dev(&uhid_cdevsw, device_get_unit(self),
 			UID_ROOT, GID_OPERATOR,
 			0644, "uhid%d", device_get_unit(self));
 #endif
+	printf("%s: input=%d, output=%d, feature=%d\n",
+	    USBDEVNAME(sc->sc_hdev->sc_dev), sc->sc_isize, sc->sc_osize,
+	    sc->sc_fsize);
 
 	USB_ATTACH_SUCCESS_RETURN;
 }
@@ -342,7 +229,7 @@ uhid_activate(device_ptr_t self, enum de
 
 USB_DETACH(uhid)
 {
-	USB_DETACH_START(uhid, sc);
+	struct uhid_softc *sc = device_get_softc(self);
 	int s;
 #if defined(__NetBSD__) || defined(__OpenBSD__)
 	int maj, mn;
@@ -355,16 +242,14 @@ USB_DETACH(uhid)
 #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);
 	}
@@ -382,41 +267,26 @@ USB_DETACH(uhid)
 	destroy_dev(sc->dev);
 #endif
 
-	if (sc->sc_repdesc)
-		free(sc->sc_repdesc, M_USBDEV);
-
 	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 = device_get_softc(addr->sc_dev);
 
 #ifdef USB_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));
-		if (status == USBD_STALLED)
-		    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;
@@ -436,7 +306,7 @@ int
 uhidopen(struct cdev *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);
 
@@ -445,36 +315,18 @@ uhidopen(struct cdev *dev, int flag, int
 	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_ibuf = sc->sc_obuf = NULL;
-
-		sc->sc_state &= ~UHID_OPEN;
-		return (EIO);
-	}
-
 	sc->sc_state &= ~UHID_IMMED;
-
-	sc->sc_async = 0;
+	sc->sc_async = NULL;
 
 	return (0);
 }
@@ -488,21 +340,12 @@ uhidclose(struct cdev *dev, int flag, in
 
 	DPRINTF(("uhidclose: sc=%p\n", sc));
 
-	/* Disable interrupts. */
-	usbd_abort_pipe(sc->sc_intrpipe);
-	usbd_close_pipe(sc->sc_intrpipe);
-	sc->sc_intrpipe = 0;
-
 	ndflush(&sc->sc_q, sc->sc_q.c_cc);
 	clfree(&sc->sc_q);
-
-	free(sc->sc_ibuf, M_USBDEV);
 	free(sc->sc_obuf, M_USBDEV);
-	sc->sc_ibuf = sc->sc_obuf = NULL;
-
-	sc->sc_state &= ~UHID_OPEN;
-
-	sc->sc_async = 0;
+	sc->sc_obuf = NULL;
+	sc->sc_async = NULL;
+	uhidev_close(sc->sc_hdev);
 
 	return (0);
 }
@@ -512,6 +355,7 @@ uhid_do_read(struct uhid_softc *sc, stru
 {
 	int s;
 	int error = 0;
+	int extra;
 	size_t length;
 	u_char buffer[UHID_CHUNK];
 	usbd_status err;
@@ -519,12 +363,12 @@ uhid_do_read(struct uhid_softc *sc, stru
 	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();
@@ -543,11 +387,6 @@ uhid_do_read(struct uhid_softc *sc, stru
 			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);
 
@@ -580,7 +419,7 @@ uhidread(struct cdev *dev, struct uio *u
 	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);
 }
 
@@ -602,12 +441,8 @@ uhid_do_write(struct uhid_softc *sc, str
 		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;
 	}
@@ -626,7 +461,7 @@ uhidwrite(struct cdev *dev, struct uio *
 	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);
 }
 
@@ -636,8 +471,10 @@ uhid_do_ioctl(struct uhid_softc *sc, u_l
 {
 	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));
 
@@ -672,17 +509,18 @@ uhid_do_ioctl(struct uhid_softc *sc, u_l
 		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);
 
@@ -696,21 +534,21 @@ uhid_do_ioctl(struct uhid_softc *sc, u_l
 		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;
@@ -720,27 +558,24 @@ uhid_do_ioctl(struct uhid_softc *sc, u_l
 		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 = 0;	/* XXX: we only support reportid 0? */
+		*(int *)addr = sc->sc_hdev->sc_report_id;
 		break;
 
 	default:
@@ -760,7 +595,7 @@ uhidioctl(struct cdev *dev, u_long cmd, 
 	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);
 }
 
@@ -791,5 +626,5 @@ uhidpoll(struct cdev *dev, int events, u
 }
 
 #if defined(__FreeBSD__)
-DRIVER_MODULE(uhid, uhub, uhid_driver, uhid_devclass, usbd_driver_load, 0);
+DRIVER_MODULE(uhid, uhidev, 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	2 Jan 2006 19:59:43 -0000
@@ -0,0 +1,742 @@
+/*	$NetBSD: uhidev.c,v 1.31 2005/11/23 08:54:48 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/devclass_docs/HID1_11.pdf
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/signalvar.h>
+#include <sys/sysctl.h>
+#include <sys/conf.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbhid.h>
+
+#include "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>
+
+/* Replacement report descriptors for devices shipped with broken ones */
+#include <dev/usb/ugraphire_rdesc.h>
+#include <dev/usb/uxb360gp_rdesc.h>
+
+#ifdef USB_DEBUG
+#define DPRINTF(x)	if (uhidevdebug) logprintf x
+#define DPRINTFN(n,x)	if (uhidevdebug>(n)) logprintf x
+int	uhidevdebug = 0;
+SYSCTL_NODE(_hw_usb, OID_AUTO, uhidev, CTLFLAG_RW, 0, "USB uhidev");
+SYSCTL_INT(_hw_usb_uhidev, OID_AUTO, debug, CTLFLAG_RW, &uhidevdebug, 0,
+    "uhidev debug level");
+#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 *, int);
+Static struct uhidev *uhidev_add_child(struct uhidev_softc *, int,
+				       struct usb_attach_arg *);
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+Static int uhidevprint(void *, const char *);
+Static int uhidevsubmatch(struct device *, struct cfdata *,
+			  const int *, void *);
+#endif
+
+Static bus_child_location_str_t uhidev_child_location_str;
+Static bus_child_pnpinfo_str_t uhidev_child_pnpinfo_str;
+
+USB_DECLARE_DRIVER_INIT(uhidev,
+	DEVMETHOD(bus_child_location_str, uhidev_child_location_str),
+	DEVMETHOD(bus_child_pnpinfo_str, uhidev_child_pnpinfo_str),
+	DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+	DEVMETHOD(device_suspend, bus_generic_suspend),
+	DEVMETHOD(device_resume, bus_generic_resume),
+	DEVMETHOD(device_shutdown, bus_generic_shutdown)
+);
+
+DRIVER_MODULE(uhidev, uhub, uhidev_driver, uhidev_devclass, usbd_driver_load, 0);
+
+Static int
+uhidev_child_location_str(device_t bus, device_t child, char *buf,
+    size_t buflen)
+{
+	struct uhidev_softc *sc = device_get_softc(bus);
+	struct uhidev *dev;
+	int i;
+
+	printf("%s: hello!\n", __func__);
+	for (i = 0; i < sc->sc_nrepid; i++) {
+		dev = sc->sc_subdevs[i];
+		if (dev != NULL && dev->sc_dev == child) {
+			snprintf(buf, buflen, "reportid=%d\n", i);
+			break;
+		}
+	}
+	return (0);
+}
+
+Static int
+uhidev_child_pnpinfo_str(device_t bus, device_t child, char *buf,
+    size_t buflen)
+{
+
+	printf("%s: hello!\n", __func__);
+	return (0);
+}
+
+Static struct uhidev *
+uhidev_add_child(struct uhidev_softc *sc, int repid, struct usb_attach_arg *uaa)
+{
+	struct uhidev *dev;
+	struct uhidev_attach_arg *uha;
+	int error;
+
+	dev = malloc(sizeof (struct uhidev), M_USBDEV, M_NOWAIT | M_ZERO);
+	if (dev == NULL)
+		return (NULL);
+	uha = &dev->sc_uha;
+	uha->reportid = repid;
+	uha->parent = sc;
+	uha->uaa = uaa;
+
+	dev->sc_parent = sc;
+	dev->sc_report_id = repid;
+	dev->sc_dev = device_add_child(sc->sc_dev, NULL, -1);
+	if (dev->sc_dev == NULL) {
+		free(dev, M_USBDEV);
+		return (NULL);
+	}
+	device_set_ivars(dev->sc_dev, dev);
+	error = device_probe_and_attach(dev->sc_dev);
+	if (error) {
+		device_delete_child(sc->sc_dev, dev->sc_dev);
+		free(dev, M_USBDEV);
+		return (NULL);
+	}
+	sc->sc_subdevs[repid] = dev;
+	return (dev);
+}
+
+Static void
+uhidev_delete_child(struct uhidev_softc *sc, struct uhidev *dev)
+{
+
+	device_delete_child(sc->sc_dev, dev->sc_dev);
+	free(dev, M_USBDEV);
+}
+
+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)
+		return (UMATCH_NONE);
+	if  (id->bInterfaceClass != UICLASS_HID) {
+		/* The Xbox 360 gamepad doesn't use the HID class. */
+		if (id->bInterfaceClass != UICLASS_VENDOR ||
+		    id->bInterfaceSubClass != UISUBCLASS_XBOX360_CONTROLLER ||
+		    id->bInterfaceProtocol != UIPROTO_XBOX360_GAMEPAD)
+			return (UMATCH_NONE);
+	}
+	return (UMATCH_IFACECLASS_GENERIC);
+}
+
+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 *dev;
+	int size, nrepid, repid, repsz;
+	int repsizes[256];
+	int i;
+	void *desc;
+	const void *descptr;
+	usbd_status err;
+	char devinfo[1024];
+
+	sc->sc_udev = uaa->device;
+	sc->sc_iface = iface;
+
+	if (usbd_get_quirks(sc->sc_udev)->uq_flags & UQ_HID_IGNORE)
+		return (UMATCH_NONE);
+
+	id = usbd_get_interface_descriptor(iface);
+
+	usbd_devinfo(uaa->device, USBD_SHOW_INTERFACE_CLASS, devinfo);
+	USB_ATTACH_SETUP;
+
+	(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
+
+	sc->sc_iep_addr = sc->sc_oep_addr = -1;
+	for (i = 0; i < id->bNumEndpoints; i++) {
+		ed = usbd_interface2endpoint_descriptor(iface, i);
+		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) {
+			sc->sc_iep_addr = ed->bEndpointAddress;
+		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
+		    (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) {
+			sc->sc_oep_addr = ed->bEndpointAddress;
+		} else {
+			printf("%s: endpoint %d: ignored\n", USBDEVNAME(sc->sc_dev), i);
+		}
+	}
+
+	/*
+	 * Check that we found an input interrupt endpoint. The output interrupt
+	 * endpoint is optional
+	 */
+	if (sc->sc_iep_addr == -1) {
+		printf("%s: no input interrupt endpoint\n", USBDEVNAME(sc->sc_dev));
+		sc->sc_dying = 1;
+		USB_ATTACH_ERROR_RETURN;
+	}
+
+	/* XXX need to extend this */
+	descptr = NULL;
+	if (uaa->vendor == USB_VENDOR_WACOM) {
+		static uByte reportbuf[] = {2, 2, 2};
+
+		/* The report descriptor for the Wacom Graphire is broken. */
+		switch (uaa->product) {
+		case USB_PRODUCT_WACOM_GRAPHIRE:
+			size = sizeof uhid_graphire_report_descr;
+			descptr = uhid_graphire_report_descr;
+			break;
+
+		case USB_PRODUCT_WACOM_GRAPHIRE3_4X5: /* The 6x8 too? */
+			/*
+			 * The Graphire3 needs 0x0202 to be written to
+			 * feature report ID 2 before it'll start
+			 * returning digitizer data.
+			 */
+			usbd_set_report(uaa->iface, UHID_FEATURE_REPORT, 2,
+			    &reportbuf, sizeof reportbuf);
+
+			size = sizeof uhid_graphire3_4x5_report_descr;
+			descptr = uhid_graphire3_4x5_report_descr;
+			break;
+		default:
+			/* Keep descriptor */
+			break;
+		}
+	} else if (id->bInterfaceClass == UICLASS_VENDOR &&
+	    id->bInterfaceSubClass == UISUBCLASS_XBOX360_CONTROLLER &&
+	    id->bInterfaceProtocol == UIPROTO_XBOX360_GAMEPAD) {
+		/* The Xbox 360 gamepad has no report descriptor. */
+		size = sizeof uhid_xb360gp_report_descr;
+		descptr = uhid_xb360gp_report_descr;
+	}
+
+	if (descptr) {
+		desc = malloc(size, M_USBDEV, M_NOWAIT);
+		if (desc == NULL)
+			err = USBD_NOMEM;
+		else {
+			err = USBD_NORMAL_COMPLETION;
+			memcpy(desc, descptr, 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;
+	}
+
+	if (uaa->vendor == USB_VENDOR_HOSIDEN && 
+	    uaa->product == USB_PRODUCT_HOSIDEN_PPP) {
+		static uByte reportbuf[] = { 1 };
+		/*
+		 *  This device was sold by Konami with its ParaParaParadise 
+		 *  game for PlayStation2.  It needs to be "turned on"
+		 *  before it will send any reports.
+		 */
+
+		usbd_set_report(uaa->iface, UHID_FEATURE_REPORT, 0,
+		    &reportbuf, sizeof reportbuf);
+	}
+
+	sc->sc_repdesc = desc;
+	sc->sc_repdesc_size = size;
+
+	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(struct uhidev *),
+				M_USBDEV, M_NOWAIT | M_ZERO);
+	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));
+
+	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 {
+			dev = uhidev_add_child(sc, repid, uaa);
+			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);
+}
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+int
+uhidevprint(void *aux, const char *pnp)
+{
+	struct uhidev_attach_arg *uha = aux;
+
+	if (pnp)
+		aprint_normal("uhid at %s", pnp);
+	if (uha->reportid != 0)
+		aprint_normal(" reportid %d", uha->reportid);
+	return (UNCONF);
+}
+
+int
+uhidevsubmatch(struct device *parent, struct cfdata *cf,
+	       const int *locs, void *aux)
+{
+	if (cf->cf_loc[UHIDBUSCF_REPORTID] != UHIDBUSCF_REPORTID_DEFAULT &&
+	    cf->cf_loc[UHIDBUSCF_REPORTID] != locs[UHIDBUSCF_REPORTID])
+		return (0);
+
+	return (config_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);
+
+	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;
+	default:
+		rv = 0;
+		break;
+	}
+	return (rv);
+}
+#endif
+
+USB_DETACH(uhidev)
+{
+	USB_DETACH_START(uhidev, sc);
+	int i, rv;
+
+	DPRINTF(("uhidev_detach: sc=%p\n", sc));
+
+	sc->sc_dying = 1;
+	if (sc->sc_ipipe != NULL)
+		usbd_abort_pipe(sc->sc_ipipe);
+
+	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) {
+#ifdef __FreeBSD__
+			uhidev_delete_child(sc, sc->sc_subdevs[i]);
+#else
+			rv |= config_detach(&sc->sc_subdevs[i]->sc_dev, flags);
+#endif
+			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_ipipe);
+		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;
+	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);
+		return;
+	}
+	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;
+	int error;
+
+	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 input interrupt pipe. */
+	DPRINTF(("uhidev_open: isize=%d, ep=0x%02x\n", sc->sc_isize,
+		 sc->sc_iep_addr));
+		
+	err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_iep_addr,
+		  USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_ibuf,
+		  sc->sc_isize, uhidev_intr, USBD_DEFAULT_INTERVAL);
+	if (err != USBD_NORMAL_COMPLETION) {
+		DPRINTF(("uhidopen: usbd_open_pipe_intr failed, "
+		    "error=%d\n", err));
+		error = EIO;
+		goto out1;
+	}
+
+	/*
+	 * Set up output interrupt pipe if an output interrupt endpoint
+	 * exists.
+	 */
+	if (sc->sc_oep_addr != -1) {
+		DPRINTF(("uhidev_open: oep=0x%02x\n", sc->sc_oep_addr));
+
+		err = usbd_open_pipe(sc->sc_iface, sc->sc_oep_addr,
+		    0, &sc->sc_opipe);
+
+		if (err != USBD_NORMAL_COMPLETION) {
+			DPRINTF(("uhidev_open: usbd_open_pipe failed, "
+			    "error=%d\n", err));
+			error = EIO;
+			goto out2;
+		}
+		DPRINTF(("uhidev_open: sc->sc_opipe=%p\n", sc->sc_opipe));
+
+		sc->sc_oxfer = usbd_alloc_xfer(sc->sc_udev);
+		if (sc->sc_oxfer == NULL) {
+			DPRINTF(("uhidev_open: couldn't allocate an xfer\n"));
+			error = ENOMEM;
+			goto out3;
+		}
+	}
+	
+	return (0);
+out3:
+	/* Abort output pipe */
+	usbd_close_pipe(sc->sc_opipe);
+out2:
+	/* Abort input pipe */
+	usbd_close_pipe(sc->sc_ipipe);
+out1:
+	DPRINTF(("uhidev_open: failed in someway"));
+	free(sc->sc_ibuf, M_USBDEV);
+	scd->sc_state &= ~UHIDEV_OPEN;
+	sc->sc_refcnt = 0;
+	sc->sc_ipipe = NULL;
+	sc->sc_opipe = NULL;
+	sc->sc_oxfer = NULL;
+	return error;
+}
+
+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"));
+
+	if (sc->sc_oxfer != NULL)
+		usbd_free_xfer(sc->sc_oxfer);
+	
+	/* Disable interrupts. */
+	if (sc->sc_opipe != NULL) {
+		usbd_abort_pipe(sc->sc_opipe);
+		usbd_close_pipe(sc->sc_opipe);
+		sc->sc_opipe = NULL;
+	}
+
+	if (sc->sc_ipipe != NULL) {
+		usbd_abort_pipe(sc->sc_ipipe);
+		usbd_close_pipe(sc->sc_ipipe);
+		sc->sc_ipipe = 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)
+{
+	char *buf;
+	usbd_status retstat;
+
+	if (scd->sc_report_id == 0)
+		return usbd_set_report(scd->sc_parent->sc_iface, type,
+				       scd->sc_report_id, data, len);
+
+	buf = malloc(len + 1, M_TEMP, M_WAITOK);
+	buf[0] = scd->sc_report_id;
+	memcpy(buf+1, data, len);
+
+	retstat = usbd_set_report(scd->sc_parent->sc_iface, type,
+				  scd->sc_report_id, buf, len + 1);
+
+	free(buf, M_TEMP);
+
+	return retstat;
+}
+
+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);
+}
+
+usbd_status
+uhidev_write(struct uhidev_softc *sc, void *data, int len)
+{
+
+	DPRINTF(("uhidev_write: data=%p, len=%d\n", data, len));
+
+	if (sc->sc_opipe == NULL)
+		return USBD_INVAL;
+
+#ifdef UHIDEV_DEBUG
+	if (uhidevdebug > 50) {
+
+		u_int32_t i;
+		u_int8_t *d = data;
+
+		DPRINTF(("uhidev_write: data ="));
+		for (i = 0; i < len; i++)
+			DPRINTF((" %02x", d[i]));
+		DPRINTF(("\n"));
+	}
+#endif
+	return usbd_intr_transfer(sc->sc_oxfer, sc->sc_opipe, 0,
+	    USBD_NO_TIMEOUT, data, &len, "uhidevwi");
+}
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	2 Jan 2006 19:59:43 -0000
@@ -0,0 +1,88 @@
+/*	$NetBSD: uhidev.h,v 1.6 2005/11/23 08:54:48 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.
+ */
+
+struct uhidev_softc {
+	USBBASEDEVICE sc_dev;		/* base device */
+	usbd_device_handle sc_udev;
+	usbd_interface_handle sc_iface;	/* interface */
+	usbd_pipe_handle sc_ipipe;	/* input interrupt pipe */
+	int sc_iep_addr;
+
+	u_char *sc_ibuf;
+	u_int sc_isize;
+
+	usbd_pipe_handle sc_opipe;	/* output interrupt pipe */
+	usbd_xfer_handle sc_oxfer;	/* write request */
+	int sc_oep_addr;
+
+	void *sc_repdesc;
+	int sc_repdesc_size;
+
+	u_int sc_nrepid;
+	struct uhidev **sc_subdevs;
+
+	int sc_refcnt;
+	u_char sc_dying;
+};
+
+struct uhidev_attach_arg {
+	struct usb_attach_arg *uaa;
+	struct uhidev_softc *parent;
+	int reportid;
+	int reportsize;
+};
+
+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 sc_uha;
+};
+
+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);
+usbd_status uhidev_write(struct uhidev_softc *, void *, int);
Index: dev/usb/ukbd.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/usb/ukbd.c,v
retrieving revision 1.52
diff -u -p -r1.52 ukbd.c
--- dev/usb/ukbd.c	30 Mar 2005 08:32:41 -0000	1.52
+++ dev/usb/ukbd.c	2 Jan 2006 19:59:43 -0000
@@ -75,6 +75,7 @@ __FBSDID("$FreeBSD: src/sys/dev/usb/ukbd
 #include "usbdevs.h"
 #include <dev/usb/usb_quirks.h>
 #include <dev/usb/hid.h>
+#include <dev/usb/uhidev.h>
 
 #include <sys/kbio.h>
 #include <dev/kbd/kbdreg.h>
@@ -99,34 +100,75 @@ SYSCTL_INT(_hw_usb_ukbd, OID_AUTO, debug
 
 #define UPROTO_BOOT_KEYBOARD 1
 
-#define NKEYCODE 6
+#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 MAXKEYS (NMOD+2*NKEYCODE)
+#define MAXKEYS (MAXMOD+2*MAXKEYCODE)
 
 typedef struct ukbd_softc {
 	device_t		sc_dev;		/* base device */
+	keyboard_t		*sc_kbd;	/* keyboard */
 } ukbd_softc_t;
 
+typedef struct ukbd_state {
+	struct uhidev *ks_hdev;
+
+	struct hid_location ks_modloc[MAXMOD];
+	u_int		ks_nmod;
+	struct {
+		u_int32_t mask;
+		u_int8_t key;
+	} ks_mods[MAXMOD];
+	u_int32_t	ks_modctrl;
+	u_int32_t	ks_modshift;
+
+	struct hid_location ks_keycodeloc;
+	u_int		ks_nkeycode;
+	struct hid_location ks_numloc;
+	struct hid_location ks_capsloc;
+	struct hid_location ks_scroloc;
+
+	struct ukbd_data ks_ndata;
+	struct ukbd_data ks_odata;
+	u_long		ks_ntime[MAXKEYCODE];
+	u_long		ks_otime[MAXKEYCODE];
+
+#define INPUTBUFSIZE	(MAXMOD + 2*MAXKEYCODE)
+	u_int		ks_input[INPUTBUFSIZE];	/* input buffer */
+	int		ks_inputs;
+	int		ks_inputhead;
+	int		ks_inputtail;
+
+	int		ks_ifstate;
+#define	INTRENABLED	(1 << 0)
+#define	DISCONNECTED	(1 << 1)
+
+	usb_callout_t ks_timeout_handle;
+
+	int		ks_mode;	/* input mode (K_XLATE,K_RAW,K_CODE) */
+	int		ks_flags;	/* flags */
+#define COMPOSE		(1 << 0)
+	int		ks_polling;
+	int		ks_state;	/* shift/lock key state */
+	int		ks_accents;	/* accent key index (> 0) */
+	u_int		ks_composed_char; /* composed char code (> 0) */
+#ifdef UKBD_EMULATE_ATSCANCODE
+	u_int		ks_buffered_char[2];
+#endif
+} ukbd_state_t;
+
 #define	UKBD_CHUNK	128	/* chunk size for read */
 #define	UKBD_BSIZE	1020	/* buffer size */
 
-typedef void usbd_intr_t(usbd_xfer_handle, usbd_private_handle, usbd_status);
+typedef void usbd_intr_t(struct uhidev *, void *, u_int);
 typedef void usbd_disco_t(void *);
 
+Static const char	*ukbd_parse_desc(ukbd_state_t *state);
 Static int		ukbd_resume(device_t self);
 Static usbd_intr_t	ukbd_intr;
 Static int		ukbd_driver_load(module_t mod, int what, void *arg);
@@ -135,33 +177,29 @@ USB_DECLARE_DRIVER_INIT(ukbd, DEVMETHOD(
 
 USB_MATCH(ukbd)
 {
-	USB_MATCH_START(ukbd, uaa);
+	UHID_MATCH_START(ukbd, uha);
 
 	keyboard_switch_t *sw;
-	void *arg[2];
 	int unit = device_get_unit(self);
 
 	sw = kbd_get_switch(DRIVER_NAME);
 	if (sw == NULL)
 		return (UMATCH_NONE);
 
-	arg[0] = (void *)uaa;
-	arg[1] = (void *)ukbd_intr;
-	if ((*sw->probe)(unit, (void *)arg, 0))
+	if ((*sw->probe)(unit, uha, 0))
 		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;
-	char devinfo[1024];
-
+	struct ukbd_softc *sc = device_get_softc(self);
+	struct uhidev *hdev = device_get_ivars(self);
+	struct uhidev_attach_arg *uha = &hdev->sc_uha;
 	keyboard_switch_t *sw;
 	keyboard_t *kbd;
+	const char *parseerr;
 	void *arg[2];
 	int unit = device_get_unit(self);
 
@@ -169,17 +207,26 @@ USB_ATTACH(ukbd)
 	if (sw == NULL)
 		USB_ATTACH_ERROR_RETURN;
 
-	id = usbd_get_interface_descriptor(iface);
-	usbd_devinfo(uaa->device, USBD_SHOW_INTERFACE_CLASS, devinfo);
-	USB_ATTACH_SETUP;
+	sc->sc_dev = self;
+	hdev->sc_intr = ukbd_intr;
+	hdev->sc_parent = uha->parent;
+	hdev->sc_report_id = uha->reportid;
 
-	arg[0] = (void *)uaa;
+	arg[0] = (void *)uha;
 	arg[1] = (void *)ukbd_intr;
+	arg[2] = (void *)hdev;
 	kbd = NULL;
-	if ((*sw->probe)(unit, (void *)arg, 0))
+	if ((*sw->probe)(unit, uha, 0))
 		USB_ATTACH_ERROR_RETURN;
 	if ((*sw->init)(unit, &kbd, (void *)arg, 0))
 		USB_ATTACH_ERROR_RETURN;
+
+	parseerr = ukbd_parse_desc((ukbd_state_t *)kbd->kb_data);
+	if (parseerr != NULL) {
+		device_printf(self, "%s\n", parseerr);
+		USB_ATTACH_ERROR_RETURN;
+	}
+
 	(*sw->enable)(kbd);
 
 #ifdef KBD_INSTALL_CDEV
@@ -188,6 +235,7 @@ USB_ATTACH(ukbd)
 #endif
 	if (bootverbose)
 		(*sw->diag)(kbd, bootverbose);
+	sc->sc_kbd = kbd;
 
 	USB_ATTACH_SUCCESS_RETURN;
 }
@@ -223,24 +271,28 @@ ukbd_detach(device_t self)
 Static int
 ukbd_resume(device_t self)
 {
+	struct ukbd_softc *sc = device_get_softc(self);
 	keyboard_t *kbd;
 
-	kbd = kbd_get_keyboard(kbd_find_keyboard(DRIVER_NAME,
-						 device_get_unit(self)));
+	kbd = sc->sc_kbd;
 	if (kbd)
 		(*kbdsw[kbd->kb_index]->clear_state)(kbd);
 	return (0);
 }
 
 void
-ukbd_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status)
+ukbd_intr(struct uhidev *addr, void *ibuf, u_int len)
 {
-	keyboard_t *kbd = (keyboard_t *)addr;
+	struct ukbd_softc *sc = device_get_softc(addr->sc_dev);
+	keyboard_t *kbd = sc->sc_kbd;
+	void *arg[2];
 
-	(*kbdsw[kbd->kb_index]->intr)(kbd, (void *)status);
+	arg[0] = ibuf;
+	arg[1] = (void *)(uintptr_t)len;
+	(*kbdsw[kbd->kb_index]->intr)(kbd, arg);
 }
 
-DRIVER_MODULE(ukbd, uhub, ukbd_driver, ukbd_devclass, ukbd_driver_load, 0);
+DRIVER_MODULE(ukbd, uhidev, ukbd_driver, ukbd_devclass, ukbd_driver_load, 0);
 
 
 #define UKBD_DEFAULT	0
@@ -261,20 +313,6 @@ DRIVER_MODULE(ukbd, uhub, ukbd_driver, u
 			 | SCAN_PREFIX_SHIFT)
 #define SCAN_CHAR(c)	((c) & 0x7f)
 
-#define NMOD 8
-Static struct {
-	int mask, key;
-} ukbd_mods[NMOD] = {
-	{ MOD_CONTROL_L, 0xe0 },
-	{ MOD_CONTROL_R, 0xe4 },
-	{ MOD_SHIFT_L,   0xe1 },
-	{ MOD_SHIFT_R,   0xe5 },
-	{ MOD_ALT_L,     0xe2 },
-	{ MOD_ALT_R,     0xe6 },
-	{ MOD_WIN_L,     0xe3 },
-	{ MOD_WIN_R,	 0xe7 },
-};
-
 #define NN 0			/* no translation */
 /*
  * Translate USB keycodes to AT keyboard scancodes.
@@ -323,41 +361,6 @@ Static u_int8_t ukbd_trtab[256] = {
           NN,  NN,  NN,  NN,  NN,  NN,  NN,  NN, /* F8 - FF */
 };
 
-typedef struct ukbd_state {
-	usbd_interface_handle ks_iface;	/* interface */
-	usbd_pipe_handle ks_intrpipe;	/* interrupt pipe */
-	struct usb_attach_arg *ks_uaa;
-	int ks_ep_addr;
-
-	struct ukbd_data ks_ndata;
-	struct ukbd_data ks_odata;
-	u_long		ks_ntime[NKEYCODE];
-	u_long		ks_otime[NKEYCODE];
-
-#define INPUTBUFSIZE	(NMOD + 2*NKEYCODE)
-	u_int		ks_input[INPUTBUFSIZE];	/* input buffer */
-	int		ks_inputs;
-	int		ks_inputhead;
-	int		ks_inputtail;
-
-	int		ks_ifstate;
-#define	INTRENABLED	(1 << 0)
-#define	DISCONNECTED	(1 << 1)
-
-	usb_callout_t ks_timeout_handle;
-
-	int		ks_mode;	/* input mode (K_XLATE,K_RAW,K_CODE) */
-	int		ks_flags;	/* flags */
-#define COMPOSE		(1 << 0)
-	int		ks_polling;
-	int		ks_state;	/* shift/lock key state */
-	int		ks_accents;	/* accent key index (> 0) */
-	u_int		ks_composed_char; /* composed char code (> 0) */
-#ifdef UKBD_EMULATE_ATSCANCODE
-	u_int		ks_buffered_char[2];
-#endif
-} ukbd_state_t;
-
 /* keyboard driver declaration */
 Static int		ukbd_configure(int flags);
 Static kbd_probe_t	ukbd_probe;
@@ -408,13 +411,15 @@ Static int		ukbd_enable_intr(keyboard_t 
 Static void		ukbd_timeout(void *arg);
 
 Static int		ukbd_getc(ukbd_state_t *state);
-Static int		probe_keyboard(struct usb_attach_arg *uaa, int flags);
-Static int		init_keyboard(ukbd_state_t *state, int *type,
-				      int flags);
+Static int		probe_keyboard(struct uhidev_attach_arg *uha,
+				       int flags);
+Static int		init_keyboard(ukbd_state_t *state, struct uhidev *hdev,
+				      int *type, int flags);
 Static void		set_leds(ukbd_state_t *state, int leds);
 Static int		set_typematic(keyboard_t *kbd, int code);
 #ifdef UKBD_EMULATE_ATSCANCODE
-Static int		keycode2scancode(int keycode, int shift, int up);
+Static int		keycode2scancode(ukbd_state_t *state, int keycode,
+					 int shift, int up);
 #endif
 
 /* local variables */
@@ -480,18 +485,16 @@ ukbd_configure(int flags)
 Static int
 ukbd_probe(int unit, void *arg, int flags)
 {
-	void **data;
-	struct usb_attach_arg *uaa;
+	struct uhidev_attach_arg *uha;
 
-	data = (void **)arg;
-	uaa = (struct usb_attach_arg *)data[0];
+	uha = (struct uhidev_attach_arg *)arg;
 
 	/* XXX */
 	if (unit == UKBD_DEFAULT) {
 		if (KBD_IS_PROBED(&default_kbd))
 			return 0;
 	}
-	if (probe_keyboard(uaa, flags))
+	if (probe_keyboard(uha, flags))
 		return ENXIO;
 	return 0;
 }
@@ -507,7 +510,7 @@ ukbd_init(int unit, keyboard_t **kbdp, v
 	fkeytab_t *fkeymap;
 	int fkeymap_size;
 	void **data = (void **)arg;
-	struct usb_attach_arg *uaa = (struct usb_attach_arg *)data[0];
+	struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)data[0];
 
 	/* XXX */
 	if (unit == UKBD_DEFAULT) {
@@ -564,14 +567,12 @@ ukbd_init(int unit, keyboard_t **kbdp, v
 		kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size);
 		kbd->kb_data = (void *)state;
 
-		if (probe_keyboard(uaa, flags))
+		if (probe_keyboard(uha, flags))
 			return ENXIO;
 		else
 			KBD_FOUND_DEVICE(kbd);
 		ukbd_clear_state(kbd);
 		state->ks_mode = K_XLATE;
-		state->ks_iface = uaa->iface;
-		state->ks_uaa = uaa;
 		state->ks_ifstate = 0;
 		usb_callout_init(state->ks_timeout_handle);
 		/*
@@ -582,7 +583,7 @@ ukbd_init(int unit, keyboard_t **kbdp, v
 	}
 	if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) {
 		if (KBD_HAS_DEVICE(kbd)
-		    && init_keyboard((ukbd_state_t *)kbd->kb_data,
+		    && init_keyboard((ukbd_state_t *)kbd->kb_data, data[2],
 				     &kbd->kb_type, kbd->kb_flags))
 			return ENXIO;
 		ukbd_ioctl(kbd, KDSETLED, (caddr_t)&(state->ks_state));
@@ -592,7 +593,7 @@ ukbd_init(int unit, keyboard_t **kbdp, v
 		if (kbd_register(kbd) < 0)
 			return ENXIO;
 		if (ukbd_enable_intr(kbd, TRUE, (usbd_intr_t *)data[1]) == 0)
-			ukbd_timeout((void *)kbd);
+			/* XXX MUX ukbd_timeout((void *)kbd); */
 		KBD_CONFIG_DONE(kbd);
 	}
 
@@ -603,27 +604,15 @@ Static int
 ukbd_enable_intr(keyboard_t *kbd, int on, usbd_intr_t *func)
 {
 	ukbd_state_t *state = (ukbd_state_t *)kbd->kb_data;
-	usbd_status err;
+	int error;
 
 	if (on) {
-		/* Set up interrupt pipe. */
-		if (state->ks_ifstate & INTRENABLED)
-			return EBUSY;
-
+		error = uhidev_open(state->ks_hdev);
+		if (error)
+			return (error);
 		state->ks_ifstate |= INTRENABLED;
-		err = usbd_open_pipe_intr(state->ks_iface, state->ks_ep_addr,
-					USBD_SHORT_XFER_OK,
-					&state->ks_intrpipe, kbd,
-					&state->ks_ndata,
-					sizeof(state->ks_ndata), func,
-					USBD_DEFAULT_INTERVAL);
-		if (err)
-			return (EIO);
 	} else {
-		/* Disable interrupts. */
-		usbd_abort_pipe(state->ks_intrpipe);
-		usbd_close_pipe(state->ks_intrpipe);
-
+		uhidev_close(state->ks_hdev);
 		state->ks_ifstate &= ~INTRENABLED;
 	}
 
@@ -643,7 +632,10 @@ ukbd_term(keyboard_t *kbd)
 	state = (ukbd_state_t *)kbd->kb_data;
 	DPRINTF(("ukbd_term: ks_ifstate=0x%x\n", state->ks_ifstate));
 
+/* XXX MUX */
+#if 0
 	usb_uncallout(state->ks_timeout_handle, ukbd_timeout, kbd);
+#endif
 
 	if (state->ks_ifstate & INTRENABLED)
 		ukbd_enable_intr(kbd, FALSE, NULL);
@@ -691,28 +683,29 @@ ukbd_timeout(void *arg)
 Static int
 ukbd_interrupt(keyboard_t *kbd, void *arg)
 {
-	usbd_status status = (usbd_status)arg;
 	ukbd_state_t *state;
 	struct ukbd_data *ud;
 	struct timeval tv;
+	void **data;
+	void *ibuf;
 	u_long now;
+	u_int len;
 	int mod, omod;
 	int key, c;
 	int i, j;
 
-	DPRINTFN(5, ("ukbd_intr: status=%d\n", status));
-	if (status == USBD_CANCELLED)
-		return 0;
-
+	data = (void **)arg;
+	ibuf = data[0];
+	len = (uintptr_t)data[1];
 	state = (ukbd_state_t *)kbd->kb_data;
 	ud = &state->ks_ndata;
 
-	if (status != USBD_NORMAL_COMPLETION) {
-		DPRINTF(("ukbd_intr: status=%d\n", status));
-		if (status == USBD_STALLED)
-		    usbd_clear_endpoint_stall_async(state->ks_intrpipe);
-		return 0;
-	}
+	ud->modifiers = 0;
+	for (i = 0; i < state->ks_nmod; i++)
+		if (hid_get_data(ibuf, &state->ks_modloc[i]))
+			ud->modifiers |= 1 << i;
+	memcpy(ud->keycode, (char *)ibuf + state->ks_keycodeloc.pos / 8,
+	    state->ks_nkeycode);
 
 	if (ud->keycode[0] == KEY_ERROR)
 		return 0;		/* ignore  */
@@ -730,20 +723,20 @@ ukbd_interrupt(keyboard_t *kbd, void *ar
 	mod = ud->modifiers;
 	omod = state->ks_odata.modifiers;
 	if (mod != omod) {
-		for (i = 0; i < NMOD; i++)
-			if (( mod & ukbd_mods[i].mask) !=
-			    (omod & ukbd_mods[i].mask))
-				ADDKEY1(ukbd_mods[i].key |
-				       (mod & ukbd_mods[i].mask
+		for (i = 0; i < state->ks_nmod; i++)
+			if (( mod & state->ks_mods[i].mask) !=
+			    (omod & state->ks_mods[i].mask))
+				ADDKEY1(state->ks_mods[i].key |
+				       (mod & state->ks_mods[i].mask
 					  ? KEY_PRESS : KEY_RELEASE));
 	}
 
 	/* Check for released keys. */
-	for (i = 0; i < NKEYCODE; i++) {
+	for (i = 0; i < state->ks_nkeycode; i++) {
 		key = state->ks_odata.keycode[i];
 		if (key == 0)
 			continue;
-		for (j = 0; j < NKEYCODE; j++) {
+		for (j = 0; j < state->ks_nkeycode; j++) {
 			if (ud->keycode[j] == 0)
 				continue;
 			if (key == ud->keycode[j])
@@ -755,12 +748,12 @@ ukbd_interrupt(keyboard_t *kbd, void *ar
 	}
 
 	/* Check for pressed keys. */
-	for (i = 0; i < NKEYCODE; i++) {
+	for (i = 0; i < state->ks_nkeycode; i++) {
 		key = ud->keycode[i];
 		if (key == 0)
 			continue;
 		state->ks_ntime[i] = now + kbd->kb_delay1;
-		for (j = 0; j < NKEYCODE; j++) {
+		for (j = 0; j < state->ks_nkeycode; j++) {
 			if (state->ks_odata.keycode[j] == 0)
 				continue;
 			if (key == state->ks_odata.keycode[j]) {
@@ -824,7 +817,7 @@ ukbd_getc(ukbd_state_t *state)
 		DPRINTFN(1,("ukbd_getc: polling\n"));
 		s = splusb();
 		while (state->ks_inputs <= 0)
-			usbd_dopoll(state->ks_iface);
+			usbd_dopoll(state->ks_hdev->sc_parent->sc_iface);
 		splx(s);
 	}
 	s = splusb();
@@ -909,7 +902,7 @@ ukbd_read(keyboard_t *kbd, int wait)
 	if (keycode == NN)
 		return -1;
 
-	scancode = keycode2scancode(keycode, state->ks_ndata.modifiers,
+	scancode = keycode2scancode(state, keycode, state->ks_ndata.modifiers,
 				    usbcode & KEY_RELEASE);
 	if (scancode & SCAN_PREFIX) {
 		if (scancode & SCAN_PREFIX_CTL) {
@@ -1005,8 +998,8 @@ next_code:
 
 	/* return an AT scan code for the K_RAW mode */
 	if (state->ks_mode == K_RAW) {
-		scancode = keycode2scancode(keycode, state->ks_ndata.modifiers,
-					    usbcode & KEY_RELEASE);
+		scancode = keycode2scancode(state, keycode,
+		    state->ks_ndata.modifiers, usbcode & KEY_RELEASE);
 		if (scancode & SCAN_PREFIX) {
 			if (scancode & SCAN_PREFIX_CTL) {
 				state->ks_buffered_char[0] =
@@ -1154,10 +1147,6 @@ ukbd_check_char(keyboard_t *kbd)
 Static int
 ukbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
 {
-	/* trasnlate LED_XXX bits into the device specific bits */
-	static u_char ledmap[8] = {
-		0, 2, 1, 3, 4, 6, 5, 7,
-	};
 	ukbd_state_t *state = kbd->kb_data;
 	int s;
 	int i;
@@ -1208,7 +1197,7 @@ ukbd_ioctl(keyboard_t *kbd, u_long cmd, 
 				i &= ~CLKED;
 		}
 		if (KBD_HAS_DEVICE(kbd)) {
-			set_leds(state, ledmap[i & LED_MASK]);
+			set_leds(state, i & LED_MASK);
 			/* XXX: error check? */
 		}
 		KBD_LED_VAL(kbd) = *(int *)arg;
@@ -1287,6 +1276,7 @@ ukbd_clear_state(keyboard_t *kbd)
 	state->ks_state &= LOCK_MASK;	/* preserve locking key state */
 	state->ks_accents = 0;
 	state->ks_composed_char = 0;
+	state->ks_hdev = NULL;
 #ifdef UKBD_EMULATE_ATSCANCODE
 	state->ks_buffered_char[0] = 0;
 	state->ks_buffered_char[1] = 0;
@@ -1327,7 +1317,7 @@ ukbd_poll(keyboard_t *kbd, int on)
 	int s;
 
 	state = (ukbd_state_t *)kbd->kb_data;
-	usbd_interface2device_handle(state->ks_iface, &dev);
+	usbd_interface2device_handle(state->ks_hdev->sc_parent->sc_iface, &dev);
 
 	s = splusb();
 	if (on) {
@@ -1346,66 +1336,25 @@ ukbd_poll(keyboard_t *kbd, int on)
 /* local functions */
 
 Static int
-probe_keyboard(struct usb_attach_arg *uaa, int flags)
+probe_keyboard(struct uhidev_attach_arg *uha, int flags)
 {
-	usb_interface_descriptor_t *id;
+	void *desc;
+	int size;
 
-	if (!uaa->iface)	/* we attach to ifaces only */
+	uhidev_get_report_desc(uha->parent, &desc, &size);
+	if (!hid_is_collection(desc, size, uha->reportid,
+			       HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD)))
 		return EINVAL;
 
-	/* Check that this is a keyboard that speaks the boot protocol. */
-	id = usbd_get_interface_descriptor(uaa->iface);
-	if (id
-	    && id->bInterfaceClass == UICLASS_HID
-	    && id->bInterfaceSubClass == UISUBCLASS_BOOT
-	    && id->bInterfaceProtocol == UPROTO_BOOT_KEYBOARD)
-		return 0;	/* found it */
-
-	return EINVAL;
+	return 0;
 }
 
 Static int
-init_keyboard(ukbd_state_t *state, int *type, int flags)
+init_keyboard(ukbd_state_t *state, struct uhidev *hdev, int *type, int flags)
 {
-	usb_endpoint_descriptor_t *ed;
-	usbd_status err;
 
 	*type = KB_OTHER;
-
-	state->ks_ifstate |= DISCONNECTED;
-
-	ed = usbd_interface2endpoint_descriptor(state->ks_iface, 0);
-	if (!ed) {
-		printf("ukbd: could not read endpoint descriptor\n");
-		return EIO;
-	}
-
-	DPRINTFN(10,("ukbd:init_keyboard: \
-bLength=%d bDescriptorType=%d bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d bInterval=%d\n",
-	       ed->bLength, ed->bDescriptorType,
-	       UE_GET_ADDR(ed->bEndpointAddress),
-	       UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN ? "in":"out",
-	       UE_GET_XFERTYPE(ed->bmAttributes),
-	       UGETW(ed->wMaxPacketSize), ed->bInterval));
-
-	if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN ||
-	    UE_GET_XFERTYPE(ed->bmAttributes) != UE_INTERRUPT) {
-		printf("ukbd: unexpected endpoint\n");
-		return EINVAL;
-	}
-
-	if ((usbd_get_quirks(state->ks_uaa->device)->uq_flags & UQ_NO_SET_PROTO) == 0) {
-		err = usbd_set_protocol(state->ks_iface, 0);
-		DPRINTFN(5, ("ukbd:init_keyboard: protocol set\n"));
-		if (err) {
-			printf("ukbd: set protocol failed\n");
-			return EIO;
-		}
-	}
-	/* Ignore if SETIDLE fails since it is not crucial. */
-	usbd_set_idle(state->ks_iface, 0, 0);
-
-	state->ks_ep_addr = ed->bEndpointAddress;
+	state->ks_hdev = hdev;
 	state->ks_ifstate &= ~DISCONNECTED;
 
 	return 0;
@@ -1414,11 +1363,19 @@ bLength=%d bDescriptorType=%d bEndpointA
 Static void
 set_leds(ukbd_state_t *state, int leds)
 {
-	u_int8_t res = leds;
+	u_int8_t res;
 
 	DPRINTF(("ukbd:set_leds: state=%p leds=%d\n", state, leds));
 
-	usbd_set_report_async(state->ks_iface, UHID_OUTPUT_REPORT, 0, &res, 1);
+	res = 0;
+	/* XXX not really right */
+	if ((leds & CLKED) && state->ks_scroloc.size == 1)
+		res |= 1 << state->ks_scroloc.pos;
+	if ((leds & NLKED) && state->ks_numloc.size == 1)
+		res |= 1 << state->ks_numloc.pos;
+	if ((leds & SLKED) && state->ks_capsloc.size == 1)
+		res |= 1 << state->ks_capsloc.pos;
+	uhidev_set_report_async(state->ks_hdev, UHID_OUTPUT_REPORT, &res, 1);
 }
 
 Static int
@@ -1439,7 +1396,7 @@ set_typematic(keyboard_t *kbd, int code)
 
 #ifdef UKBD_EMULATE_ATSCANCODE
 Static int
-keycode2scancode(int keycode, int shift, int up)
+keycode2scancode(ukbd_state_t *state, int keycode, int shift, int up)
 {
 	static int scan[] = {
 		0x1c, 0x1d, 0x35,
@@ -1459,9 +1416,9 @@ keycode2scancode(int keycode, int shift,
 	if ((keycode >= 89) && (keycode < 89 + sizeof(scan)/sizeof(scan[0])))
 		scancode = scan[keycode - 89] | SCAN_PREFIX_E0;
 	/* Pause/Break */
-	if ((keycode == 104) && !(shift & (MOD_CONTROL_L | MOD_CONTROL_R)))
+	if ((keycode == 104) && !(shift & state->ks_modctrl))
 		scancode = 0x45 | SCAN_PREFIX_E1 | SCAN_PREFIX_CTL;
-	if (shift & (MOD_SHIFT_L | MOD_SHIFT_R))
+	if (shift & state->ks_modshift)
 		scancode &= ~SCAN_PREFIX_SHIFT;
 	return (scancode | (up ? SCAN_RELEASE : SCAN_PRESS));
 }
@@ -1480,3 +1437,80 @@ ukbd_driver_load(module_t mod, int what,
 	}
 	return usbd_driver_load(mod, what, 0);
 }
+
+const char *
+ukbd_parse_desc(ukbd_state_t *state)
+{
+	struct hid_data *d;
+	struct hid_item h;
+	u_int32_t mask;
+	u_int8_t key;
+	int size;
+	void *desc;
+	int imod;
+
+	uhidev_get_report_desc(state->ks_hdev->sc_parent, &desc, &size);
+	imod = 0;
+	state->ks_modctrl = 0;
+	state->ks_modshift = 0;
+	state->ks_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 != state->ks_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) {
+				state->ks_modloc[imod] = h.loc;
+				mask = 1 << imod;
+				key = HID_GET_USAGE(h.usage);
+				state->ks_mods[imod].mask = mask;
+				state->ks_mods[imod].key = key;
+				/* For keycode2scancode() */
+				if (key == HUD_KBD_LEFT_CONTROL ||
+				    key == HUD_KBD_RIGHT_CONTROL)
+					state->ks_modctrl |= mask;
+				if (key == HUD_KBD_LEFT_SHIFT ||
+				    key == HUD_KBD_RIGHT_SHIFT)
+					state->ks_modshift |= mask;
+				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 (state->ks_nkeycode != 0)
+				return ("multiple key code arrays\n");
+			state->ks_keycodeloc = h.loc;
+			state->ks_nkeycode = h.loc.count;
+		}
+	}
+	state->ks_nmod = imod;
+	hid_end_parse(d);
+
+	hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_NUM_LOCK),
+		   state->ks_hdev->sc_report_id, hid_output, &state->ks_numloc,
+		   NULL);
+	hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_CAPS_LOCK),
+		   state->ks_hdev->sc_report_id, hid_output, &state->ks_capsloc,
+		   NULL);
+	hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_SCROLL_LOCK),
+		   state->ks_hdev->sc_report_id, hid_output, &state->ks_scroloc,
+		   NULL);
+
+	return (NULL);
+}
Index: dev/usb/ums.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/usb/ums.c,v
retrieving revision 1.80
diff -u -p -r1.80 ums.c
--- dev/usb/ums.c	29 Dec 2005 18:35:28 -0000	1.80
+++ dev/usb/ums.c	2 Jan 2006 19:59:43 -0000
@@ -69,6 +69,7 @@ __FBSDID("$FreeBSD: src/sys/dev/usb/ums.
 #include <dev/usb/usbdi_util.h>
 #include "usbdevs.h"
 #include <dev/usb/usb_quirks.h>
+#include <dev/usb/uhidev.h>
 #include <dev/usb/hid.h>
 
 #if __FreeBSD_version >= 500000
@@ -89,23 +90,26 @@ SYSCTL_INT(_hw_usb_ums, OID_AUTO, debug,
 #define DPRINTFN(n,x)
 #endif
 
+/* XXX What's the correct one? */
+#if defined(__FreeBSD__)
+#define UMS_BUT(i) ((i) < 3 ? (((i) + 2) % 3) : (i))
+#else
+#define UMS_BUT(i) ((i) == 1 || (i) == 2 ? 3 - (i) : i)
+#endif
+
 #define UMSUNIT(s)	(minor(s)&0x1f)
 
 #define MS_TO_TICKS(ms) ((ms) * hz / 1000)
 
 #define QUEUE_BUFSIZE	400	/* MUST be divisible by 5 _and_ 8 */
 
+#define MAX_BUTTONS	31	/* must not exceed size of sc_buttons */
+
 struct ums_softc {
-	device_t sc_dev;		/* base device */
-	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, sc_loc_t;
-	struct hid_location *sc_loc_btn;
+	struct hid_location sc_loc_btn[MAX_BUTTONS];
 
 	usb_callout_t callout_handle;	/* for spurious button ups */
 
@@ -117,7 +121,6 @@ struct ums_softc {
 #define UMS_SPUR_BUT_UP	0x02	/* spurious button up events */
 #define UMS_T		0x04	/* aa direction available (tilt) */
 	int nbuttons;
-#define MAX_BUTTONS	31	/* chosen because sc_buttons is int */
 
 	u_char		qbuf[QUEUE_BUFSIZE];	/* must be divisable by 3&4 */
 	u_char		dummy[100];	/* XXX just for safety and for now */
@@ -137,8 +140,7 @@ struct ums_softc {
 #define MOUSE_FLAGS_MASK (HIO_CONST|HIO_RELATIVE)
 #define MOUSE_FLAGS (HIO_RELATIVE)
 
-Static void ums_intr(usbd_xfer_handle xfer,
-			  usbd_private_handle priv, usbd_status status);
+Static void ums_intr(struct uhidev *addr, void *ibuf, u_int len);
 
 Static void ums_add_to_queue(struct ums_softc *sc,
 				int dx, int dy, int dz, int dt, int buttons);
@@ -172,107 +174,66 @@ USB_DECLARE_DRIVER(ums);
 
 USB_MATCH(ums)
 {
-	USB_MATCH_START(ums, uaa);
-	usb_interface_descriptor_t *id;
-	int size, ret;
+	UHID_MATCH_START(ums, uha);
+	int size;
 	void *desc;
-	usbd_status err;
 
-	if (!uaa->iface)
-		return (UMATCH_NONE);
-	id = usbd_get_interface_descriptor(uaa->iface);
-	if (!id || 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;
+	UHID_ATTACH_START(ums, sc, uha);
 	int size;
 	void *desc;
-	usbd_status err;
-	char devinfo[1024];
 	u_int32_t flags;
 	int i;
 	struct hid_location loc_btn;
 
-	sc->sc_disconnected = 1;
-	sc->sc_iface = iface;
-	id = usbd_get_interface_descriptor(iface);
-	usbd_devinfo(uaa->device, USBD_SHOW_INTERFACE_CLASS, devinfo);
-	USB_ATTACH_SETUP;
-	ed = usbd_interface2endpoint_descriptor(iface, 0);
-	if (!ed) {
-		printf("%s: could not read endpoint descriptor\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;
 
-	DPRINTFN(10,("ums_attach: bLength=%d bDescriptorType=%d "
-		     "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d"
-		     " bInterval=%d\n",
-		     ed->bLength, ed->bDescriptorType,
-		     UE_GET_ADDR(ed->bEndpointAddress),
-		     UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN ? "in":"out",
-		     UE_GET_XFERTYPE(ed->bmAttributes),
-		     UGETW(ed->wMaxPacketSize), ed->bInterval));
-
-	if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN ||
-	    UE_GET_XFERTYPE(ed->bmAttributes) != UE_INTERRUPT) {
-		printf("%s: unexpected endpoint\n",
-		       USBDEVNAME(sc->sc_dev));
-		USB_ATTACH_ERROR_RETURN;
-	}
+	sc->sc_disconnected = 1;
 
-	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("%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);
+		       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("%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);
+		       USBDEVNAME(sc->sc_hdev->sc_dev), flags);
 		USB_ATTACH_ERROR_RETURN;
 	}
 
 	/* try to guess the Z activator: first check Z, then WHEEL */
 	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) ||
 	    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) ||
 	    hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_TWHEEL),
-		       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 {
@@ -286,7 +247,7 @@ USB_ATTACH(ums)
 	 * There are no other HID axis descriptors other than X,Y and 
 	 * TWHEEL */
 	if (hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_TWHEEL),
-			hid_input, &sc->sc_loc_t, &flags)) {
+		uha->reportid, hid_input, &sc->sc_loc_t, &flags)) {
 			sc->sc_loc_t.pos = sc->sc_loc_t.pos + 8;
 			sc->flags |= UMS_T;
 	}
@@ -294,35 +255,19 @@ 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 buttons%s%s.\n", USBDEVNAME(sc->sc_dev),
+	printf("%s: %d buttons%s%s.\n", USBDEVNAME(sc->sc_hdev->sc_dev),
 	       sc->nbuttons, sc->flags & UMS_Z? " and Z dir" : "", 
 	       sc->flags & UMS_T?" and a TILT 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);
+			uha->reportid, 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_USB, M_NOWAIT);
-	if (!sc->sc_ibuf) {
-		printf("%s: no memory\n", USBDEVNAME(sc->sc_dev));
-		free(sc->sc_loc_btn, M_USB);
-		USB_ATTACH_ERROR_RETURN;
-	}
-
-	sc->sc_ep_addr = ed->bEndpointAddress;
 	sc->sc_disconnected = 0;
-	free(desc, M_TEMP);
 
 #ifdef USB_DEBUG
 	DPRINTF(("ums_attach: sc=%p\n", sc));
@@ -337,7 +282,6 @@ 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
 
 	if (sc->nbuttons > MOUSE_MSC_MAXBUTTON)
@@ -371,9 +315,9 @@ USB_ATTACH(ums)
 			0644, "ums%d", device_get_unit(self));
 
 	usb_callout_init(sc->callout_handle);
-	if (usbd_get_quirks(uaa->device)->uq_flags & UQ_SPUR_BUT_UP) {
+	if (usbd_get_quirks(uha->parent->sc_udev)->uq_flags & UQ_SPUR_BUT_UP) {
 		DPRINTF(("%s: Spurious button up events\n",
-			USBDEVNAME(sc->sc_dev)));
+			USBDEVNAME(sc->sc_hdev->sc_dev)));
 		sc->flags |= UMS_SPUR_BUT_UP;
 	}
 
@@ -391,8 +335,6 @@ ums_detach(device_t self)
 
 	DPRINTF(("%s: disconnected\n", USBDEVNAME(self)));
 
-	free(sc->sc_loc_btn, M_USB);
-	free(sc->sc_ibuf, M_USB);
 
 	/* someone waiting for data */
 	/*
@@ -417,59 +359,13 @@ ums_detach(device_t self)
 }
 
 void
-ums_intr(xfer, addr, status)
-	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 = device_get_softc(addr->sc_dev);
 	int dx, dy, dz, dt;
 	int buttons = 0;
 	int i;
 
-#define UMS_BUT(i) ((i) < 3 ? (((i) + 2) % 3) : (i))
-
-	DPRINTFN(5, ("ums_intr: sc=%p status=%d\n", sc, status));
-	DPRINTFN(5, ("ums_intr: data = %02x %02x %02x %02x %02x %02x\n",
-		     sc->sc_ibuf[0], sc->sc_ibuf[1], sc->sc_ibuf[2],
-		     sc->sc_ibuf[3], sc->sc_ibuf[4], sc->sc_ibuf[5]));
-
-	if (status == USBD_CANCELLED)
-		return;
-
-	if (status != USBD_NORMAL_COMPLETION) {
-		DPRINTF(("ums_intr: status=%d\n", status));
-		if (status == USBD_STALLED)
-		    usbd_clear_endpoint_stall_async(sc->sc_intrpipe);
-		if(status != USBD_IOERROR)
-			return;
-	}
-
-	ibuf = sc->sc_ibuf;
-	/*
-	 * The M$ Wireless Intellimouse 2.0 sends 1 extra leading byte of
-	 * data compared to most USB mice. This byte frequently switches
-	 * from 0x01 (usual state) to 0x02. I assume it is to allow
-	 * extra, non-standard, reporting (say battery-life). However
-	 * at the same time it generates a left-click message on the button
-	 * byte which causes spurious left-click's where there shouldn't be.
-	 * This should sort that.
-	 * Currently it's the only user of UMS_T so use it as an identifier.
-	 * We probably should switch to some more official quirk.
-	 */
-	if (sc->flags & UMS_T) {
-		if (sc->sc_iid) {
-			if (*ibuf++ == 0x02)
-				return;
-		}
-	} else {
-		if (sc->sc_iid) {
-			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);
@@ -577,14 +473,13 @@ ums_add_to_queue(struct ums_softc *sc, i
 		selwakeuppri(&sc->rsel, PZERO);
 	}
 }
+
 Static int
 ums_enable(v)
 	void *v;
 {
 	struct ums_softc *sc = v;
 
-	usbd_status err;
-
 	if (sc->sc_enabled)
 		return EBUSY;
 
@@ -596,19 +491,7 @@ ums_enable(v)
 	sc->status.dx = sc->status.dy = sc->status.dz /* = sc->status.dt */ = 0;
 
 	callout_handle_init((struct callout_handle *)&sc->callout_handle);
-
-	/* 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
@@ -619,14 +502,11 @@ ums_disable(priv)
 
 	usb_uncallout(sc->callout_handle, ums_add_to_queue_timeout, sc);
 
-	/* Disable interrupts. */
-	usbd_abort_pipe(sc->sc_intrpipe);
-	usbd_close_pipe(sc->sc_intrpipe);
-
 	sc->sc_enabled = 0;
 
 	if (sc->qcount != 0)
 		DPRINTF(("Discarded %d bytes in queue\n", sc->qcount));
+	uhidev_close(sc->sc_hdev);
 }
 
 Static int
@@ -867,4 +747,4 @@ ums_ioctl(struct cdev *dev, u_long cmd, 
 	return error;
 }
 
-DRIVER_MODULE(ums, uhub, ums_driver, ums_devclass, usbd_driver_load, 0);
+DRIVER_MODULE(ums, uhidev, ums_driver, ums_devclass, usbd_driver_load, 0);
Index: dev/usb/usb_port.h
===================================================================
RCS file: /home/ncvs/src/sys/dev/usb/usb_port.h,v
retrieving revision 1.75
diff -u -p -r1.75 usb_port.h
--- dev/usb/usb_port.h	18 Sep 2005 11:45:39 -0000	1.75
+++ dev/usb/usb_port.h	2 Jan 2006 19:59:44 -0000
@@ -473,6 +473,10 @@ __CONCAT(dname,_match)(device_t self)
 #define USB_MATCH_START(dname, uaa) \
         struct usb_attach_arg *uaa = device_get_ivars(self)
 
+#define UHID_MATCH_START(dname, uha) \
+	struct uhidev_attach_arg *uha = \
+	    &((struct uhidev *)device_get_ivars(self))->sc_uha
+
 #define USB_MATCH_SETUP \
 	sc->sc_dev = self
 
@@ -484,6 +488,12 @@ __CONCAT(dname,_attach)(device_t self)
         struct __CONCAT(dname,_softc) *sc = device_get_softc(self); \
         struct usb_attach_arg *uaa = device_get_ivars(self)
 
+#define UHID_ATTACH_START(dname, sc, uha) \
+        struct __CONCAT(dname,_softc) *sc = device_get_softc(self); \
+        struct uhidev_attach_arg *uha; \
+        sc->sc_hdev = device_get_ivars(self); \
+        uha = &sc->sc_hdev->sc_uha
+
 /* Returns from attach */
 #define USB_ATTACH_ERROR_RETURN	return ENXIO
 #define USB_ATTACH_SUCCESS_RETURN	return 0
Index: dev/usb/usbdevs
===================================================================
RCS file: /home/ncvs/src/sys/dev/usb/usbdevs,v
retrieving revision 1.246
diff -u -p -r1.246 usbdevs
--- dev/usb/usbdevs	31 Dec 2005 04:41:17 -0000	1.246
+++ dev/usb/usbdevs	2 Jan 2006 19:59:45 -0000
@@ -940,6 +940,9 @@ product HAUPPAUGE WINTV_USB_FM	0x4d12	Wi
 /* Hawking Technologies products */
 product HAWKING UF100		0x400c	10/100 USB Ethernet
 
+/* Hosiden Corporation products */
+product HOSIDEN PPP		0x0011	ParaParaParadise Controller
+
 /* Hitachi, Ltd. products */
 product HITACHI DVDCAM_USB	0x001e	DVDCAM USB HS Interface
 
Index: dev/usb/usbhid.h
===================================================================
RCS file: /home/ncvs/src/sys/dev/usb/usbhid.h,v
retrieving revision 1.15
diff -u -p -r1.15 usbhid.h
--- dev/usb/usbhid.h	6 Jan 2005 01:43:29 -0000	1.15
+++ dev/usb/usbhid.h	2 Jan 2006 19:59:45 -0000
@@ -1,4 +1,4 @@
-/*	$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.15 2005/01/06 01:43:29 imp Exp $ */
 
 /*-
@@ -165,12 +165,31 @@ typedef struct usb_hid_descriptor {
 #define HUD_ERASER		0x0045
 #define HUD_TABLET_PICK		0x0046
 
-#define HID_USAGE2(p,u) (((p) << 16) | u)
+/* Usages Keyboard */
+#define HUD_KBD_LEFT_CONTROL	0x00E0
+#define HUD_KBD_LEFT_SHIFT	0x00E1
+#define HUD_KBD_RIGHT_CONTROL	0x00E4
+#define HUD_KBD_RIGHT_SHIFT	0x00E5
+
+/* 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
