[PATCH] USB: real nodes instead of usbfs
authorKay Sievers <kay.sievers@vrfy.org>
Sat, 30 Jul 2005 23:05:53 +0000 (01:05 +0200)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 8 Sep 2005 23:22:29 +0000 (16:22 -0700)
This patch introduces a /sys/class/usb_device/ class
where every connected usb-device will show up:

  tree /sys/class/usb_device/
  /sys/class/usb_device/
  |-- usb1.1
  |   |-- dev
  |   `-- device -> ../../../devices/pci0000:00/0000:00:1d.0/usb1
  |-- usb2.1
  |   |-- dev
  |   `-- device -> ../../../devices/pci0000:00/0000:00:1d.1/usb2
  ...

The presence of the "dev" file lets udev create real device nodes.
  kay@pim:~/src/linux-2.6> tree /dev/bus/usb/
  /dev/bus/usb/
  |-- 1
  |   `-- 1
  |-- 2
  |   `-- 1
  ...

udev rule:
  SUBSYSTEM="usb_device", PROGRAM="/sbin/usb_device %k", NAME="%c"
  (echo $1 | /bin/sed 's/usb\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/')

This makes libusb pick up the real nodes instead of the mounted usbfs:
  export USB_DEVFS_PATH=/dev/bus/usb

Background:
  All this makes it possible to manage usb devices with udev instead of
  the devfs solution. We are currently working on a pam_console/resmgr
  replacement driven by udev and a pam-helper. It applies ACL's to device
  nodes, which is required for modern desktop functionalty like
  "Fast User Switching" or multiple local login support.

New patch with its own major. I've succesfully disabled usbfs and use real
nodes only on my box. With: "export USB_DEVFS_PATH=/dev/bus/usb" libusb picks
up the udev managed nodes instead of reading usbfs files.

This makes udev to provide symlinks for libusb to pick up:
  SUBSYSTEM="usb_device", PROGRAM="/sbin/usbdevice %k", SYMLINK="%c"

/sbin/usbdevice:
  #!/bin/sh
  echo $1 | /bin/sed 's/usbdev\([0-9]*\)\.\([0-9]*\)/bus\/usb\/\1\/\2/'

Signed-off-by: Kay Sievers <kay.sievers@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/core/Makefile
drivers/usb/core/devio.c
drivers/usb/core/hub.c
drivers/usb/core/inode.c
drivers/usb/core/usb.c
drivers/usb/core/usb.h
include/linux/usb.h

index 9e8c377b81612ab941339eb257178c64400a63e7..d5503cf0bf74c8586a5d7ed66b029014ec4b6d1f 100644 (file)
@@ -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
index f86bf1454e21e69259146c02ea543e1e2d83bfca..d12bc5e84a1a30b1d70bb501e83e4c9b2ea13f8e 100644 (file)
@@ -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>
 #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);
+}
+
index c9412daff682431a820d11c3595cde972929377d..a220a5e7f4a519d5946888c19d92c085685bb85e 100644 (file)
@@ -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;
 
index c3e3a95d3804ff8e48dd308f4272fdf2e9072a0a..640f41e470294d5911f04a2d7e4c92df4d225455 100644 (file)
@@ -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);
index 2cddd8a00437b8bede3f9814a66dc73a2190886a..bc966dbc60210a69f9d3fa87fcb91f789c5c8f5f 100644 (file)
@@ -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);
index 2c690f6d4c18b84dd83832f7aca4746dbd36d731..83d48c8133af5992913bfd33a8b94fd7a079423c 100644 (file)
@@ -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 */
index 72463779299659bd338c0008edb0547c636ce5eb..434e35120c650e58a90304bc1ee0b66d340cc937 100644 (file)
@@ -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 */
 
        /*