--- linux-ac11/drivers/usb/devio.c	Fri Jun  9 19:13:40 2000
+++ linux/drivers/usb/devio.c	Sun Jun 11 16:54:41 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,65 @@
 	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 and alloc buffer */
+	copy_from_user_ret (&ctrl, (void *) arg, sizeof (ctrl), -EFAULT);
+	if ((size = _IOC_SIZE (ctrl.ioctl_code)) > 0) {
+		if ((buf = kmalloc (size, GFP_KERNEL)) == 0)
+			return -ENOMEM;
+		if ((_IOC_DIR (ctrl.ioctl_code) & _IOC_WRITE) != 0
+				&& copy_from_user (buf, ctrl.data, size) != 0) {
+			kfree (buf);
+			return -EFAULT;
+		} else
+			memset (arg, size, 0);
+	}
+
+	/* ioctl to device */
+	if (ctrl.ifno < 0) {
+		switch (ctrl.ioctl_code) {
+		/* access/release token for issuing control messages
+		 * ask a particular driver to bind/unbind, ... 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 {
+			if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno)))
+				retval = -EINVAL;
+			else 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);
+			/* size = min (size, retval)? */
+	}
+
+	/* 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 +1139,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-ac11/drivers/usb/hub.c	Fri Jun  9 19:13:40 2000
+++ linux/drivers/usb/hub.c	Sun Jun 11 16:25:34 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,37 @@
 	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);
+		if (hub->devnum <= 0)
+			info->nports = 0;
+		else {
+			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 +604,7 @@
 static struct usb_driver hub_driver = {
 	name:		"hub",
 	probe:		hub_probe,
+	ioctl:		hub_ioctl,
 	disconnect:	hub_disconnect
 };
 
--- linux-ac11/include/linux/usb.h	Fri Jun  9 19:11:40 2000
+++ linux/include/linux/usb.h	Fri Jun  9 19:15:37 2000
@@ -309,6 +309,8 @@
 	int minor;
 
 	struct semaphore serialize;
+
+	int (*ioctl)(struct usb_device *dev, unsigned int code, void *buf);
 };
 
 /*
--- linux-ac11/include/linux/usbdevice_fs.h	Fri Jun  9 19:11:41 2000
+++ linux/include/linux/usbdevice_fs.h	Sun Jun 11 16:34:24 2000
@@ -108,6 +108,13 @@
 	struct usbdevfs_iso_packet_desc iso_frame_desc[0];
 };
 
+struct usbdevfs_ioctl {
+	int	ifno;		/* interface 0..N ; negative numbers reserved */
+	int	ioctl_code;	/* MUST encode size + direction of data so the
+				 * macros in <asm/ioctl.h> give correct values */
+	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 +129,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;		/* number of downstream ports in this hub */
+	char port [127];	/* e.g. port 3 connects to device 27 */
+};
+#define USBDEVFS_HUB_PORTINFO	   _IOR('U', 19, struct usbdevfs_hub_portinfo)
+
 
 /* --------------------------------------------------------------------- */
 

