On Wed, Jul 27, 2005 at 02:49:30PM -0700, Greg KH wrote:
> On Wed, Jul 27, 2005 at 09:36:13PM +0200, Kay Sievers wrote:
> > 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?
> 
> The idea's good, but the implementation seems a bit messy.  You are
> reusing the USB major number for things that it was not specified for.
> I know in a udev managed system that's not a big deal, but we can't go
> breaking people who use a static /dev, right?  With this patch, we just
> broke the /dev/usb/lp0 node, as that minor number was assigned to the
> root hub device.
> 
> How about we just use another major number?  I think I have a few free
> ones around here somewhere....
> 
> 189 is reserved for USB serial callout devices, and never used at all.
> I don't mind giving it up for this instead.

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 <[EMAIL PROTECTED]>
---

diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
--- 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
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -43,6 +36,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 +44,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 +485,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 +499,16 @@ static int usbdev_open(struct inode *ino
 
        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 +1480,80 @@ struct file_operations usbfs_device_file
        .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
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1051,6 +1051,7 @@ void usb_disconnect(struct usb_device **
        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 *ud
        /* 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
--- 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
--- 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
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -37,6 +37,11 @@ extern struct file_operations usbfs_devi
 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
--- 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 */
 
        /*



-------------------------------------------------------
SF.Net email is sponsored by: Discover Easy Linux Migration Strategies
from IBM. Find simple to follow Roadmaps, straightforward articles,
informative Webcasts and more! Get everything you need to get up to
speed, fast. http://ads.osdn.com/?ad_id=7477&alloc_id=16492&op=click
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to