aboutsummaryrefslogtreecommitdiffstats
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 9e8c377b81612a..d5503cf0bf74c8 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 f86bf1454e21e6..d12bc5e84a1a30 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 c9412daff68243..a220a5e7f4a519 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 c3e3a95d3804ff..640f41e470294d 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 2cddd8a00437b8..bc966dbc60210a 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 2c690f6d4c18b8..83d48c8133af59 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 72463779299659..434e35120c650e 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 */
/*