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.
  [EMAIL PROTECTED]:~/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.

What do you think?

Best,
Kay
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -487,7 +487,7 @@ static int check_ctrlrecip(struct dev_st
  */
 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 +501,15 @@ static int usbdev_open(struct inode *ino
 
        lock_kernel();
        ret = -ENOENT;
-       dev = usb_get_dev(inode->u.generic_ip);
+       if (imajor(inode))
+               dev = usb_dev_by_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;
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -31,7 +31,11 @@
 #include "usb.h"
 
 #define MAX_USB_MINORS 256
-static struct file_operations *usb_minors[MAX_USB_MINORS];
+static struct usb_minor {
+       struct file_operations *fops;
+       struct usb_device *dev;
+} usb_minors[MAX_USB_MINORS];
+
 static DEFINE_SPINLOCK(minor_lock);
 
 static int usb_open(struct inode * inode, struct file * file)
@@ -42,7 +46,7 @@ static int usb_open(struct inode * inode
        struct file_operations *old_fops, *new_fops = NULL;
 
        spin_lock (&minor_lock);
-       c = usb_minors[minor];
+       c = usb_minors[minor].fops;
 
        if (!c || !(new_fops = fops_get(c))) {
                spin_unlock(&minor_lock);
@@ -101,6 +105,31 @@ void usb_major_cleanup(void)
        unregister_chrdev(USB_MAJOR, "usb");
 }
 
+struct usb_device *usb_dev_by_minor(int minor)
+{
+       return usb_minors[minor].dev;
+}
+
+int usb_get_free_minor(int minor_base, struct file_operations *fops, struct 
usb_device *dev)
+{
+       int minor = -1;
+       int i;
+
+       spin_lock (&minor_lock);
+       for (i = minor_base; i < MAX_USB_MINORS; i++) {
+               if (usb_minors[i].fops)
+                       continue;
+
+               minor = i;
+               usb_minors[minor].fops = fops;
+               usb_minors[minor].dev = dev;
+               break;
+       }
+       spin_unlock (&minor_lock);
+
+       return minor;
+}
+
 /**
  * usb_register_dev - register a USB device, and ask for a minor number
  * @intf: pointer to the usb_interface that is being registered
@@ -145,19 +174,8 @@ int usb_register_dev(struct usb_interfac
        if (class_driver->fops == NULL)
                goto exit;
 
-       spin_lock (&minor_lock);
-       for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) {
-               if (usb_minors[minor])
-                       continue;
-
-               usb_minors[minor] = class_driver->fops;
-
-               retval = 0;
-               break;
-       }
-       spin_unlock (&minor_lock);
-
-       if (retval)
+       usb_get_free_minor(minor_base, class_driver->fops, NULL);
+       if (minor == -1)
                goto exit;
 
        intf->minor = minor;
@@ -175,7 +193,7 @@ int usb_register_dev(struct usb_interfac
        intf->class_dev = class_device_create(usb_class, MKDEV(USB_MAJOR, 
minor), &intf->dev, "%s", temp);
        if (IS_ERR(intf->class_dev)) {
                spin_lock (&minor_lock);
-               usb_minors[intf->minor] = NULL;
+               usb_minors[intf->minor].fops = NULL;
                spin_unlock (&minor_lock);
                devfs_remove (name);
                retval = PTR_ERR(intf->class_dev);
@@ -216,7 +234,7 @@ void usb_deregister_dev(struct usb_inter
        dbg ("removing %d minor", intf->minor);
 
        spin_lock (&minor_lock);
-       usb_minors[intf->minor] = NULL;
+       usb_minors[intf->minor].fops = NULL;
        spin_unlock (&minor_lock);
 
        snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - 
minor_base);
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -43,6 +43,7 @@
 #include "usb.h"
 #include "hcd.h"
 
+static struct class *usb_device_class;
 static struct super_operations usbfs_ops;
 static struct file_operations default_file_operations;
 static struct inode_operations usbfs_dir_inode_operations;
@@ -669,6 +670,7 @@ void usbfs_add_device(struct usb_device 
        char name[8];
        int i;
        int i_size;
+       int minor;
 
        sprintf (name, "%03d", dev->devnum);
        dev->usbfs_dentry = fs_create_file (name, devmode | S_IFREG,
@@ -693,6 +695,15 @@ void usbfs_add_device(struct usb_device 
 
        usbfs_update_special();
        usbfs_conn_disc_event();
+
+       minor = usb_get_free_minor(0, &usbfs_device_file_operations, dev);
+       if (minor == -1) {
+               err("error allocating minor");
+               return;
+       }
+       dev->class_dev = class_device_create(usb_device_class,
+                               MKDEV(USB_MAJOR, minor), &dev->dev,
+                               "usb%d.%d", dev->bus->busnum, dev->devnum);
 }
 
 void usbfs_remove_device(struct usb_device *dev)
@@ -700,6 +711,8 @@ void usbfs_remove_device(struct usb_devi
        struct dev_state *ds;
        struct siginfo sinfo;
 
+       class_device_destroy(usb_device_class, dev->class_dev->devt);
+
        if (dev->usbfs_dentry) {
                fs_remove_file (dev->usbfs_dentry);
                dev->usbfs_dentry = NULL;
@@ -728,6 +741,8 @@ int __init usbfs_init(void)
 {
        int retval;
 
+       usb_device_class = class_create(THIS_MODULE, "usb_device");
+
        retval = usb_register(&usbfs_driver);
        if (retval)
                return retval;
@@ -750,5 +765,7 @@ void usbfs_cleanup(void)
        unregister_filesystem(&usb_fs_type);
        if (usbdir)
                remove_proc_entry("usb", proc_bus);
+
+       class_destroy(usb_device_class);
 }
 
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -27,6 +27,8 @@ extern int usb_major_init(void);
 extern void usb_major_cleanup(void);
 extern int usb_host_init(void);
 extern void usb_host_cleanup(void);
+extern int usb_get_free_minor(int minor_base, struct file_operations *fops, 
struct usb_device *dev);
+extern struct usb_device *usb_dev_by_minor(int minor);
 
 /* for labeling diagnostics */
 extern const char *usbcore_name;

Reply via email to