Skip to content

Commit

Permalink
[PATCH] USB: real nodes instead of usbfs
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Kay Sievers authored and Greg Kroah-Hartman committed Sep 8, 2005
1 parent 22af887 commit fbf82fd
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 14 deletions.
4 changes: 2 additions & 2 deletions drivers/usb/core/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
91 changes: 89 additions & 2 deletions drivers/usb/core/devio.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,18 @@
#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;
Expand Down Expand Up @@ -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;

Expand All @@ -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;
Expand Down Expand Up @@ -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);
}

2 changes: 2 additions & 0 deletions drivers/usb/core/hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -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() */
Expand Down Expand Up @@ -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;

Expand Down
9 changes: 1 addition & 8 deletions drivers/usb/core/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
15 changes: 13 additions & 2 deletions drivers/usb/core/usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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:
Expand All @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions drivers/usb/core/usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
2 changes: 2 additions & 0 deletions include/linux/usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <linux/usb_ch9.h>

#define USB_MAJOR 180
#define USB_DEVICE_MAJOR 189


#ifdef __KERNEL__
Expand Down Expand Up @@ -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 */

/*
Expand Down

0 comments on commit fbf82fd

Please sign in to comment.