--- linux-ac7/drivers/usb/devio.c	Sun Jun  4 14:13:40 2000
+++ linux/drivers/usb/devio.c	Tue Jun  6 04:06:40 2000
@@ -514,6 +514,7 @@
 
 extern struct list_head usb_driver_list;
 
+#if 0
 static int finddriver(struct usb_driver **driver, char *name)
 {
 	struct list_head *tmp;
@@ -533,6 +534,7 @@
 
 	return -EINVAL;
 }
+#endif
 
 /*
  * file operations
@@ -1001,6 +1003,61 @@
 	return releaseintf(ps, intf);
 }
 
+static int proc_ioctl (struct dev_state *ps, void *arg)
+{
+	struct usbdevfs_ioctl	ctrl;
+	int			size;
+	void			*buf = 0;
+	int			retval = 0;
+
+	// get input parameters
+	copy_from_user_ret (&ctrl, (void *) arg, sizeof (ctrl), -EFAULT);
+	if ((size = _IOC_SIZE (ctrl.ioctl_code)) > 0) {
+		buf = kmalloc (size, GFP_KERNEL);
+		if ((_IOC_DIR (ctrl.ioctl_code) & _IOC_WRITE) != 0
+				&& copy_from_user (buf, ctrl.data, size) != 0) {
+			kfree (buf);
+			return -EFAULT;
+		}
+	}
+
+	// ioctl to device
+	if (ctrl.ifno < 0) {
+		switch (ctrl.ioctl_code) {
+		// access/release token for issuing control messages
+		// ask a particular driver to bind
+		// ... etc
+		}
+		retval = -ENOSYS;
+
+	// ioctl to the driver which has claimed a given interface
+	} else {
+		struct usb_interface	*ifp = 0;
+		if (!ps->dev)
+			retval = -ENODEV;
+		else if (ctrl.ifno >= ps->dev->actconfig->bNumInterfaces)
+			retval = -EINVAL;
+		else {
+			ifp = &ps->dev->actconfig->interface [ctrl.ifno];
+			if (ifp->driver == 0 || ifp->driver->ioctl == 0)
+				retval = -ENOSYS;
+		}
+		if (retval == 0)
+			// ifno might usefully be passed ...
+			retval = ifp->driver->ioctl (ps->dev, ctrl.ioctl_code, buf);
+	}
+
+	// cleanup and return
+	if (retval >= 0
+			&& (_IOC_DIR (ctrl.ioctl_code) & _IOC_READ) != 0
+			&& size > 0
+			&& copy_to_user (ctrl.data, buf, size) != 0)
+		retval = -EFAULT;
+	if (buf != 0)
+		kfree (buf);
+	return retval;
+}
+
 static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	struct dev_state *ps = (struct dev_state *)file->private_data;
@@ -1078,6 +1135,9 @@
 		ret = proc_releaseinterface(ps, (void *)arg);
 		break;
 
+	case USBDEVFS_IOCTL:
+		ret = proc_ioctl(ps, (void *) arg);
+		break;
 	}
 	up_read(&ps->devsem);
 	if (ret >= 0)
--- linux-ac7/include/linux/usb.h	Sun Jun  4 14:11:16 2000
+++ linux/include/linux/usb.h	Mon Jun  5 20:43:39 2000
@@ -309,6 +309,8 @@
 	int minor;
 
 	struct semaphore serialize;
+
+	int (*ioctl)(struct usb_device *dev, unsigned int code, void *buf);
 };
 
 /*
--- linux-ac10/drivers/usb/hub.c	Tue Jun  6 12:48:10 2000
+++ linux/drivers/usb/hub.c	Tue Jun  6 13:48:49 2000
@@ -18,6 +18,7 @@
 	#undef DEBUG
 #endif
 #include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
 
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
@@ -335,6 +336,34 @@
 	kfree(hub);
 }
 
+static int hub_ioctl (struct usb_device *hub, unsigned int code, void *user_data)
+{
+	// assert ifno == 0 (part of hub spec)
+
+	switch (code) {
+	case USBDEVFS_HUB_PORTINFO: {
+		struct usbdevfs_hub_portinfo *info = user_data;
+		unsigned long flags;
+		int i;
+
+		spin_lock_irqsave (&hub_event_lock, flags);
+		info->nports = hub->maxchild;
+		for (i = 0; i < info->nports; i++) {
+			if (hub->children [i] == NULL)
+				info->port [i] = 0;
+			else
+				info->port [i] = hub->children [i]->devnum;
+		}
+		spin_unlock_irqrestore (&hub_event_lock, flags);
+
+		return info->nports + 1;
+		}
+
+	default:
+		return -ENOSYS;
+	}
+}
+
 static void usb_hub_port_connect_change(struct usb_device *hub, int port)
 {
 	struct usb_device *usb;
@@ -572,6 +603,7 @@
 static struct usb_driver hub_driver = {
 	name:		"hub",
 	probe:		hub_probe,
+	ioctl:		hub_ioctl,
 	disconnect:	hub_disconnect
 };
 
--- linux-ac7/include/linux/usbdevice_fs.h	Sun Jun  4 14:11:17 2000
+++ linux/include/linux/usbdevice_fs.h	Mon Jun  5 18:44:06 2000
@@ -108,6 +108,12 @@
 	struct usbdevfs_iso_packet_desc iso_frame_desc[0];
 };
 
+struct usbdevfs_ioctl {
+	int	ifno;		// interface 0..N ; negative numbers reserved
+	int	ioctl_code;	// encodes size direction of data
+	void	*data;		// param buffer (in, or out)
+};
+
 #define USBDEVFS_CONTROL           _IOWR('U', 0, struct usbdevfs_ctrltransfer)
 #define USBDEVFS_BULK              _IOWR('U', 2, struct usbdevfs_bulktransfer)
 #define USBDEVFS_RESETEP           _IOR('U', 3, unsigned int)
@@ -122,6 +128,20 @@
 #define USBDEVFS_CLAIMINTERFACE    _IOR('U', 15, unsigned int)
 #define USBDEVFS_RELEASEINTERFACE  _IOR('U', 16, unsigned int)
 #define USBDEVFS_CONNECTINFO       _IOW('U', 17, struct usbdevfs_connectinfo)
+#define USBDEVFS_IOCTL             _IOWR('U', 18, struct usbdevfs_ioctl)
+
+/* --------------------------------------------------------------------- */
+
+// ioctls for talking to drivers in the usbcore module:
+
+// You can do most things with hubs just through control messages,
+// except find out what device connects to what port.
+struct usbdevfs_hub_portinfo {
+	char nports;		// ports in this controller
+	char port [127];	// e.g. port 3 connects to device 27
+};
+#define USBDEVFS_HUB_PORTINFO	   _IOR('U', 19, struct usbdevfs_hub_portinfo)
+
 
 /* --------------------------------------------------------------------- */
 
