summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/core/Makefile4
-rw-r--r--drivers/usb/core/devio.c91
-rw-r--r--drivers/usb/core/hub.c2
-rw-r--r--drivers/usb/core/inode.c9
-rw-r--r--drivers/usb/core/usb.c15
-rw-r--r--drivers/usb/core/usb.h5
-rw-r--r--include/linux/usb.h2
7 files changed, 114 insertions, 14 deletions
diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
index 9e8c377b8161..d5503cf0bf74 100644
--- a/drivers/usb/core/Makefile
+++ b/drivers/usb/core/Makefile
@@ -3,14 +3,14 @@
 #
 
 usbcore-objs	:= usb.o hub.o hcd.o urb.o message.o \
-			config.o file.o buffer.o sysfs.o
+			config.o file.o buffer.o sysfs.o devio.o
 
 ifeq ($(CONFIG_PCI),y)
 	usbcore-objs	+= hcd-pci.o
 endif
 
 ifeq ($(CONFIG_USB_DEVICEFS),y)
-	usbcore-objs	+= devio.o inode.o devices.o
+	usbcore-objs	+= inode.o devices.o
 endif
 
 obj-$(CONFIG_USB)	+= usbcore.o
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index f86bf1454e21..d12bc5e84a1a 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -43,6 +43,7 @@
 #include <linux/module.h>
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
+#include <linux/cdev.h>
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 #include <linux/moduleparam.h>
@@ -50,6 +51,10 @@
 #include "hcd.h"	/* for usbcore internals */
 #include "usb.h"
 
+#define USB_MAXBUS			64
+#define USB_DEVICE_MAX			USB_MAXBUS * 128
+static struct class *usb_device_class;
+
 struct async {
 	struct list_head asynclist;
 	struct dev_state *ps;
@@ -487,7 +492,7 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig
  */
 static int usbdev_open(struct inode *inode, struct file *file)
 {
-	struct usb_device *dev;
+	struct usb_device *dev = NULL;
 	struct dev_state *ps;
 	int ret;
 
@@ -501,11 +506,16 @@ static int usbdev_open(struct inode *inode, struct file *file)
 
 	lock_kernel();
 	ret = -ENOENT;
-	dev = usb_get_dev(inode->u.generic_ip);
+	/* check if we are called from a real node or usbfs */
+	if (imajor(inode) == USB_DEVICE_MAJOR)
+		dev = usbdev_lookup_minor(iminor(inode));
+	if (!dev)
+		dev = inode->u.generic_ip;
 	if (!dev) {
 		kfree(ps);
 		goto out;
 	}
+	usb_get_dev(dev);
 	ret = 0;
 	ps->dev = dev;
 	ps->file = file;
@@ -1477,3 +1487,80 @@ struct file_operations usbfs_device_file_operations = {
 	.open =		usbdev_open,
 	.release =	usbdev_release,
 };
+
+struct usb_device *usbdev_lookup_minor(int minor)
+{
+	struct class_device *class_dev;
+	struct usb_device *dev = NULL;
+
+	down(&usb_device_class->sem);
+	list_for_each_entry(class_dev, &usb_device_class->children, node) {
+		if (class_dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
+			dev = class_dev->class_data;
+			break;
+		}
+	}
+	up(&usb_device_class->sem);
+
+	return dev;
+};
+
+void usbdev_add(struct usb_device *dev)
+{
+	int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1);
+
+	dev->class_dev = class_device_create(usb_device_class,
+				MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev,
+				"usbdev%d.%d", dev->bus->busnum, dev->devnum);
+
+	dev->class_dev->class_data = dev;
+}
+
+void usbdev_remove(struct usb_device *dev)
+{
+	class_device_unregister(dev->class_dev);
+}
+
+static struct cdev usb_device_cdev = {
+	.kobj   = {.name = "usb_device", },
+	.owner  = THIS_MODULE,
+};
+
+int __init usbdev_init(void)
+{
+	int retval;
+
+	retval = register_chrdev_region(MKDEV(USB_DEVICE_MAJOR, 0),
+				        USB_DEVICE_MAX, "usb_device");
+	if (retval) {
+		err("unable to register minors for usb_device");
+		goto out;
+	}
+	cdev_init(&usb_device_cdev, &usbfs_device_file_operations);
+	retval = cdev_add(&usb_device_cdev,
+			  MKDEV(USB_DEVICE_MAJOR, 0), USB_DEVICE_MAX);
+	if (retval) {
+		err("unable to get usb_device major %d", USB_DEVICE_MAJOR);
+		unregister_chrdev_region(USB_DEVICE_MAJOR, USB_DEVICE_MAX);
+		goto out;
+	}
+	usb_device_class = class_create(THIS_MODULE, "usb_device");
+	if (IS_ERR(usb_device_class)) {
+		err("unable to register usb_device class");
+		retval = PTR_ERR(usb_device_class);
+		usb_device_class = NULL;
+		cdev_del(&usb_device_cdev);
+		unregister_chrdev_region(USB_DEVICE_MAJOR, USB_DEVICE_MAX);
+	}
+
+out:
+	return retval;
+}
+
+void usbdev_cleanup(void)
+{
+	class_destroy(usb_device_class);
+	cdev_del(&usb_device_cdev);
+	unregister_chrdev_region(USB_DEVICE_MAJOR, USB_DEVICE_MAX);
+}
+
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index c9412daff682..a220a5e7f4a5 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1051,6 +1051,7 @@ void usb_disconnect(struct usb_device **pdev)
 	dev_dbg (&udev->dev, "unregistering device\n");
 	release_address(udev);
 	usbfs_remove_device(udev);
+	usbdev_remove(udev);
 	usb_remove_sysfs_dev_files(udev);
 
 	/* Avoid races with recursively_mark_NOTATTACHED() */
@@ -1290,6 +1291,7 @@ int usb_new_device(struct usb_device *udev)
 	/* USB device state == configured ... usable */
 
 	/* add a /proc/bus/usb entry */
+	usbdev_add(udev);
 	usbfs_add_device(udev);
 	return 0;
 
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index c3e3a95d3804..640f41e47029 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -728,15 +728,9 @@ int __init usbfs_init(void)
 {
 	int retval;
 
-	retval = usb_register(&usbfs_driver);
-	if (retval)
-		return retval;
-
 	retval = register_filesystem(&usb_fs_type);
-	if (retval) {
-		usb_deregister(&usbfs_driver);
+	if (retval)
 		return retval;
-	}
 
 	/* create mount point for usbfs */
 	usbdir = proc_mkdir("usb", proc_bus);
@@ -746,7 +740,6 @@ int __init usbfs_init(void)
 
 void usbfs_cleanup(void)
 {
-	usb_deregister(&usbfs_driver);
 	unregister_filesystem(&usb_fs_type);
 	if (usbdir)
 		remove_proc_entry("usb", proc_bus);
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 2cddd8a00437..bc966dbc6021 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -1478,13 +1478,18 @@ static int __init usb_init(void)
 	retval = usb_major_init();
 	if (retval)
 		goto major_init_failed;
+	retval = usb_register(&usbfs_driver);
+	if (retval)
+		goto driver_register_failed;
+	retval = usbdev_init();
+	if (retval)
+		goto usbdevice_init_failed;
 	retval = usbfs_init();
 	if (retval)
 		goto fs_init_failed;
 	retval = usb_hub_init();
 	if (retval)
 		goto hub_init_failed;
-
 	retval = driver_register(&usb_generic_driver);
 	if (!retval)
 		goto out;
@@ -1493,7 +1498,11 @@ static int __init usb_init(void)
 hub_init_failed:
 	usbfs_cleanup();
 fs_init_failed:
-	usb_major_cleanup();	
+	usbdev_cleanup();
+usbdevice_init_failed:
+	usb_deregister(&usbfs_driver);
+driver_register_failed:
+	usb_major_cleanup();
 major_init_failed:
 	usb_host_cleanup();
 host_init_failed:
@@ -1514,6 +1523,8 @@ static void __exit usb_exit(void)
 	driver_unregister(&usb_generic_driver);
 	usb_major_cleanup();
 	usbfs_cleanup();
+	usb_deregister(&usbfs_driver);
+	usbdev_cleanup();
 	usb_hub_cleanup();
 	usb_host_cleanup();
 	bus_unregister(&usb_bus_type);
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 2c690f6d4c18..83d48c8133af 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -37,6 +37,11 @@ extern struct file_operations usbfs_devices_fops;
 extern struct file_operations usbfs_device_file_operations;
 extern void usbfs_conn_disc_event(void);
 
+extern int usbdev_init(void);
+extern void usbdev_cleanup(void);
+extern void usbdev_add(struct usb_device *dev);
+extern void usbdev_remove(struct usb_device *dev);
+extern struct usb_device *usbdev_lookup_minor(int minor);
 
 struct dev_state {
 	struct list_head list;      /* state list */
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 724637792996..434e35120c65 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -5,6 +5,7 @@
 #include <linux/usb_ch9.h>
 
 #define USB_MAJOR			180
+#define USB_DEVICE_MAJOR		189
 
 
 #ifdef __KERNEL__
@@ -349,6 +350,7 @@ struct usb_device {
 	char *manufacturer;
 	char *serial;			/* static strings from the device */
 	struct list_head filelist;
+	struct class_device *class_dev;
 	struct dentry *usbfs_dentry;	/* usbfs dentry entry for the device */
 
 	/*