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;