$NetBSD: patch-ab,v 1.5 2011/07/24 18:00:07 jmcneill Exp $

--- usbctl.c.orig	2002-02-24 19:50:55.000000000 -0500
+++ usbctl.c	2011-07-24 09:56:59.000000000 -0400
@@ -27,12 +27,18 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/types.h>
+#include <sys/ioctl.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <err.h>
 #include <errno.h>
+#ifdef __DragonFly__
+#include <bus/usb/usb.h>
+#include <bus/usb/usbhid.h>
+#else
 #include <dev/usb/usb.h>
 #include <dev/usb/usbhid.h>
+#endif
 
 #ifndef USB_STACK_VERSION
 #define ucr_addr addr
@@ -52,6 +58,21 @@
 #define UICLASS_HUB UCLASS_HUB
 #endif
 
+#ifndef UDESC_INTERFACE_ASSOC
+#define UDESC_INTERFACE_ASSOC 0x0b
+typedef struct {
+	uByte		bLength;
+	uByte		bDescriptorType;
+	uByte		bFirstInterface;
+	uByte		bInterfaceCount;
+	uByte		bFunctionClass;
+	uByte		bFunctionSubClass;
+	uByte		bFunctionProtocol;
+	uByte		iFunction
+} UPACKED usb_interface_assoc_descriptor_t;
+#define USB_INTERFACE_ASSOC_DESCRIPTOR_SIZE 8
+#endif
+
 #define USBDEV "/dev/usb0"
 
 /* Backwards compatibility */
@@ -62,6 +83,7 @@
 #endif
 
 #define NSTRINGS
+#define STRINGLANG
 
 int num = 0;
 
@@ -80,17 +102,43 @@ getstring(int si, char *s)
 	int r, i, n;
 	u_int16_t c;
 	usb_string_descriptor_t us;
+	int lang = 0;
 
 	if (si == 0 || num) {
 		*s = 0;
 		return;
 	}
+
+#ifdef STRINGLANG
 	req.ucr_addr = usbaddr;
 	req.ucr_request.bmRequestType = UT_READ_DEVICE;
 	req.ucr_request.bRequest = UR_GET_DESCRIPTOR;
 	req.ucr_data = &us;
-	USETW2(req.ucr_request.wValue, UDESC_STRING, si);
+	USETW2(req.ucr_request.wValue, UDESC_STRING, 0);
 	USETW(req.ucr_request.wIndex, 0);
+	USETW(req.ucr_request.wLength, sizeof(usb_string_descriptor_t));
+	req.ucr_flags = USBD_SHORT_XFER_OK;
+	r = ioctl(usbf, USB_REQUEST, &req);
+	if (r < 0) {
+		fprintf(stderr, "get lang tbl failed (error=%d)\n", errno);
+		*s = 0;
+		return;
+	}
+	if (req.ucr_actlen > 0 && us.bLength >= 4) {
+		lang = UGETW(us.bString[0]);
+#if 0
+		printf("getstring: %d langs, using %d\n",
+		       (us.bLength - 2) / 2, lang);
+#endif
+	}
+#endif
+
+	req.ucr_addr = usbaddr;
+	req.ucr_request.bmRequestType = UT_READ_DEVICE;
+	req.ucr_request.bRequest = UR_GET_DESCRIPTOR;
+	req.ucr_data = &us;
+	USETW2(req.ucr_request.wValue, UDESC_STRING, si);
+	USETW(req.ucr_request.wIndex, lang);
 #ifdef NSTRINGS
 	USETW(req.ucr_request.wLength, sizeof(usb_string_descriptor_t));
 	req.ucr_flags = USBD_SHORT_XFER_OK;
@@ -154,6 +202,7 @@ descTypeName(int t)
 	case UDESC_STRING: p = "string"; break;
 	case UDESC_INTERFACE: p = "interface"; break;
 	case UDESC_ENDPOINT: p = "endpoint"; break;
+	case UDESC_INTERFACE_ASSOC: p = "iad"; break;
 	case 0x20: p = "cs_undefined"; break;
 	case UDESC_CS_DEVICE: p = "cs_device"; break;
 	case UDESC_CS_CONFIG: p = "cs_config"; break;
@@ -278,6 +327,21 @@ bInterfaceProtocol=%d iInterface=%d(%s)\
 	       d->iInterface, ifc);
 }
 
+void
+priad(usb_interface_assoc_descriptor_t *d)
+{
+	char func[MAXSTR];
+	getstring(d->iFunction, func);
+	if (d->bDescriptorType != UDESC_INTERFACE_ASSOC) printf("weird descriptorType, should be %d\n", UDESC_INTERFACE_ASSOC);
+	printf("\
+bLength=%d bDescriptorType=%s bFirstInterface=%d bInterfaceCount=%d\n\
+bFunctionClass=%d bFunctionSubClass=%d bFunctionProtocol=%d\n\
+iFunction=%d(%s)\n",
+	    d->bLength, descTypeName(d->bDescriptorType), d->bFirstInterface,
+	    d->bInterfaceCount, d->bFunctionClass, d->bFunctionSubClass,
+	    d->bFunctionProtocol, d->iFunction, func);
+}
+
 char *xfernames[] = { "control", "isochronous", "bulk", "interrupt" };
 char *xfertypes[] = { "", "-async", "-adaptive", "-sync" };
 
@@ -384,7 +448,7 @@ struct usb_cdc_union_descriptor {
 };
 
 void
-prcdcd(usb_descriptor_t *ud)
+prcdcd(struct usb_cdc_header_descriptor *ud)
 {
 	if (ud->bDescriptorType != UDESC_CS_INTERFACE)
 		printf("prcdcd: strange bDescriptorType=%d\n", 
@@ -630,7 +694,7 @@ gethubdesc(int f, usb_hub_descriptor_t *
 	req.ucr_addr = addr;
 	req.ucr_request.bmRequestType = UT_READ_CLASS_DEVICE;
 	req.ucr_request.bRequest = UR_GET_DESCRIPTOR;
-	USETW(req.ucr_request.wValue, 0);
+	USETW2(req.ucr_request.wValue, UDESC_HUB, 0);
 	USETW(req.ucr_request.wIndex, 0);
 	USETW(req.ucr_request.wLength, USB_HUB_DESCRIPTOR_SIZE);
 	req.ucr_data = d;
@@ -1145,6 +1209,11 @@ prdesc(void *p, int *class, int *subclas
 		prhubd(p);
 		break;
 #endif
+	case UDESC_INTERFACE_ASSOC:
+		printf("INTERFACE ASSOCIATION descriptor:\n");
+		priad(p);
+		break;
+		break;
 	case UDESC_CS_DEVICE:
 		if (*class == UICLASS_HID) {
 			usb_hid_descriptor_t *hid = p;
@@ -1155,10 +1224,14 @@ prdesc(void *p, int *class, int *subclas
 			printf("\n");
 			for(k = 0; k < hid->bNumDescriptors; k++) {
 				int type, len;
-				u_char buf[256];
+				u_char *buf;
 
 				type = hid->descrs[k].bDescriptorType;
 				len = UGETW(hid->descrs[k].wDescriptorLength);
+				buf = malloc(len);
+				if (buf == NULL) {
+					errx(1, "malloc failed (size=%d)\n", len);
+				}
 				if (type == UDESC_REPORT) {
 					getreportdesc(globf, *iface, k, buf, len, globaddr);
 					printf("Report descriptor\n");
@@ -1169,6 +1242,7 @@ prdesc(void *p, int *class, int *subclas
 					printf("Unknown HID descriptor type %d\n", type);
 				}
 				printf("\n");
+				free(buf);
 			}
 		} else
 			goto def;
@@ -1243,8 +1317,8 @@ prdesc(void *p, int *class, int *subclas
 	default:
 	def:
 		printf("Unknown descriptor (class %d/%d):\n", *class, *subclass);
-		printf("bLength=%d bDescriptorType=%d bDescriptorSubtype=%d ...\n", d->bLength, 
-		       d->bDescriptorType, d->bDescriptorSubtype
+		printf("bLength=%d bDescriptorType=%d ...\n", d->bLength, 
+		       d->bDescriptorType
 		       );
 		break;
 	}
@@ -1321,6 +1395,7 @@ main(int argc, char **argv)
 
 	if (!doaddr)
 		prunits(f);
+#ifndef __NetBSD__
 	if (!nodisc) {
 		r = ioctl(f, USB_DISCOVER);
 		if (r < 0)
@@ -1329,6 +1404,7 @@ main(int argc, char **argv)
 		if (disconly)
 			exit(0);
 	}
+#endif
 
 	for(addr = 0; addr < USB_MAX_DEVICES; addr++) {
 		if (doaddr != -1 && addr != doaddr)
