forked from Minki/linux
USB: make usbdevices export their device nodes instead of using a separate class
o The "real" usb-devices export now a device node which can populate /dev/bus/usb. o The usb_device class is optional now and can be disabled in the kernel config. Major/minor of the "real" devices and class devices are the same. o The environment of the usb-device event contains DEVNUM and BUSNUM to help udev and get rid of the ugly udev rule we need for the class devices. o The usb-devices and usb-interfaces share the same bus, so I used the new "struct device_type" to let these devices identify themselves. This also removes the current logic of using a magic platform-pointer. The name of the device_type is also added to the environment which makes it easier to distinguish the different kinds of devices on the same subsystem. It looks like this: add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1 ACTION=add DEVPATH=/devices/pci0000:00/0000:00:1d.1/usb2/2-1 SUBSYSTEM=usb SEQNUM=1533 MAJOR=189 MINOR=131 DEVTYPE=usb_device PRODUCT=46d/c03e/2000 TYPE=0/0/0 BUSNUM=002 DEVNUM=004 This udev rule works as a replacement for usb_device class devices: SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", \ NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0644" Updated patch, which needs the device_type patches in Greg's tree. I also got a bugzilla assigned for this. :) https://bugzilla.novell.com/show_bug.cgi?id=250659 Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
8784028963
commit
9f8b17e643
@ -31,7 +31,30 @@ config USB_DEVICEFS
|
|||||||
For the format of the various /proc/bus/usb/ files, please read
|
For the format of the various /proc/bus/usb/ files, please read
|
||||||
<file:Documentation/usb/proc_usb_info.txt>.
|
<file:Documentation/usb/proc_usb_info.txt>.
|
||||||
|
|
||||||
Most users want to say Y here.
|
Usbfs files can't handle Access Control Lists (ACL), which are the
|
||||||
|
default way to grant access to USB devices for untrusted users of a
|
||||||
|
desktop system. The usbfs functionality is replaced by real
|
||||||
|
device-nodes managed by udev. These nodes live in /dev/bus/usb and
|
||||||
|
are used by libusb.
|
||||||
|
|
||||||
|
config USB_DEVICE_CLASS
|
||||||
|
bool "USB device class-devices (DEPRECATED)"
|
||||||
|
depends on USB
|
||||||
|
default n
|
||||||
|
---help---
|
||||||
|
Userspace access to USB devices is granted by device-nodes exported
|
||||||
|
directly from the usbdev in sysfs. Old versions of the driver
|
||||||
|
core and udev needed additional class devices to export device nodes.
|
||||||
|
|
||||||
|
These additional devices are difficult to handle in userspace, if
|
||||||
|
information about USB interfaces must be available. One device contains
|
||||||
|
the device node, the other device contains the interface data. Both
|
||||||
|
devices are at the same level in sysfs (siblings) and one can't access
|
||||||
|
the other. The device node created directly by the usbdev is the parent
|
||||||
|
device of the interface and therefore easily accessible from the interface
|
||||||
|
event.
|
||||||
|
|
||||||
|
This option provides backward compatibility if needed.
|
||||||
|
|
||||||
config USB_DYNAMIC_MINORS
|
config USB_DYNAMIC_MINORS
|
||||||
bool "Dynamic USB minor allocation (EXPERIMENTAL)"
|
bool "Dynamic USB minor allocation (EXPERIMENTAL)"
|
||||||
|
@ -57,7 +57,6 @@
|
|||||||
|
|
||||||
#define USB_MAXBUS 64
|
#define USB_MAXBUS 64
|
||||||
#define USB_DEVICE_MAX USB_MAXBUS * 128
|
#define USB_DEVICE_MAX USB_MAXBUS * 128
|
||||||
static struct class *usb_device_class;
|
|
||||||
|
|
||||||
/* Mutual exclusion for removal, open, and release */
|
/* Mutual exclusion for removal, open, and release */
|
||||||
DEFINE_MUTEX(usbfs_mutex);
|
DEFINE_MUTEX(usbfs_mutex);
|
||||||
@ -514,22 +513,25 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct usb_device *usbdev_lookup_minor(int minor)
|
static int __match_minor(struct device *dev, void *data)
|
||||||
{
|
{
|
||||||
struct device *device;
|
int minor = *((int *)data);
|
||||||
struct usb_device *udev = NULL;
|
|
||||||
|
|
||||||
down(&usb_device_class->sem);
|
if (dev->devt == MKDEV(USB_DEVICE_MAJOR, minor))
|
||||||
list_for_each_entry(device, &usb_device_class->devices, node) {
|
return 1;
|
||||||
if (device->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
|
return 0;
|
||||||
udev = device->platform_data;
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
up(&usb_device_class->sem);
|
|
||||||
|
|
||||||
return udev;
|
static struct usb_device *usbdev_lookup_by_minor(int minor)
|
||||||
};
|
{
|
||||||
|
struct device *dev;
|
||||||
|
|
||||||
|
dev = bus_find_device(&usb_bus_type, NULL, &minor, __match_minor);
|
||||||
|
if (!dev)
|
||||||
|
return NULL;
|
||||||
|
put_device(dev);
|
||||||
|
return container_of(dev, struct usb_device, dev);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* file operations
|
* file operations
|
||||||
@ -548,11 +550,14 @@ static int usbdev_open(struct inode *inode, struct file *file)
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
/* check if we are called from a real node or usbfs */
|
/* usbdev device-node */
|
||||||
if (imajor(inode) == USB_DEVICE_MAJOR)
|
if (imajor(inode) == USB_DEVICE_MAJOR)
|
||||||
dev = usbdev_lookup_minor(iminor(inode));
|
dev = usbdev_lookup_by_minor(iminor(inode));
|
||||||
|
#ifdef CONFIG_USB_DEVICEFS
|
||||||
|
/* procfs file */
|
||||||
if (!dev)
|
if (!dev)
|
||||||
dev = inode->i_private;
|
dev = inode->i_private;
|
||||||
|
#endif
|
||||||
if (!dev)
|
if (!dev)
|
||||||
goto out;
|
goto out;
|
||||||
ret = usb_autoresume_device(dev);
|
ret = usb_autoresume_device(dev);
|
||||||
@ -1570,7 +1575,7 @@ static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wai
|
|||||||
return mask;
|
return mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct file_operations usbfs_device_file_operations = {
|
const struct file_operations usbdev_file_operations = {
|
||||||
.llseek = usbdev_lseek,
|
.llseek = usbdev_lseek,
|
||||||
.read = usbdev_read,
|
.read = usbdev_read,
|
||||||
.poll = usbdev_poll,
|
.poll = usbdev_poll,
|
||||||
@ -1579,50 +1584,53 @@ const struct file_operations usbfs_device_file_operations = {
|
|||||||
.release = usbdev_release,
|
.release = usbdev_release,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int usbdev_add(struct usb_device *dev)
|
#ifdef CONFIG_USB_DEVICE_CLASS
|
||||||
|
static struct class *usb_classdev_class;
|
||||||
|
|
||||||
|
static int usb_classdev_add(struct usb_device *dev)
|
||||||
{
|
{
|
||||||
int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1);
|
int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1);
|
||||||
|
|
||||||
dev->usbfs_dev = device_create(usb_device_class, &dev->dev,
|
dev->usb_classdev = device_create(usb_classdev_class, &dev->dev,
|
||||||
MKDEV(USB_DEVICE_MAJOR, minor),
|
MKDEV(USB_DEVICE_MAJOR, minor),
|
||||||
"usbdev%d.%d", dev->bus->busnum, dev->devnum);
|
"usbdev%d.%d", dev->bus->busnum, dev->devnum);
|
||||||
if (IS_ERR(dev->usbfs_dev))
|
if (IS_ERR(dev->usb_classdev))
|
||||||
return PTR_ERR(dev->usbfs_dev);
|
return PTR_ERR(dev->usb_classdev);
|
||||||
|
|
||||||
dev->usbfs_dev->platform_data = dev;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void usbdev_remove(struct usb_device *dev)
|
static void usb_classdev_remove(struct usb_device *dev)
|
||||||
{
|
{
|
||||||
device_unregister(dev->usbfs_dev);
|
device_unregister(dev->usb_classdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int usbdev_notify(struct notifier_block *self, unsigned long action,
|
static int usb_classdev_notify(struct notifier_block *self,
|
||||||
void *dev)
|
unsigned long action, void *dev)
|
||||||
{
|
{
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case USB_DEVICE_ADD:
|
case USB_DEVICE_ADD:
|
||||||
if (usbdev_add(dev))
|
if (usb_classdev_add(dev))
|
||||||
return NOTIFY_BAD;
|
return NOTIFY_BAD;
|
||||||
break;
|
break;
|
||||||
case USB_DEVICE_REMOVE:
|
case USB_DEVICE_REMOVE:
|
||||||
usbdev_remove(dev);
|
usb_classdev_remove(dev);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return NOTIFY_OK;
|
return NOTIFY_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct notifier_block usbdev_nb = {
|
static struct notifier_block usbdev_nb = {
|
||||||
.notifier_call = usbdev_notify,
|
.notifier_call = usb_classdev_notify,
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
static struct cdev usb_device_cdev = {
|
static struct cdev usb_device_cdev = {
|
||||||
.kobj = {.name = "usb_device", },
|
.kobj = {.name = "usb_device", },
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
};
|
};
|
||||||
|
|
||||||
int __init usbdev_init(void)
|
int __init usb_devio_init(void)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
@ -1632,38 +1640,38 @@ int __init usbdev_init(void)
|
|||||||
err("unable to register minors for usb_device");
|
err("unable to register minors for usb_device");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
cdev_init(&usb_device_cdev, &usbfs_device_file_operations);
|
cdev_init(&usb_device_cdev, &usbdev_file_operations);
|
||||||
retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX);
|
retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
err("unable to get usb_device major %d", USB_DEVICE_MAJOR);
|
err("unable to get usb_device major %d", USB_DEVICE_MAJOR);
|
||||||
goto error_cdev;
|
goto error_cdev;
|
||||||
}
|
}
|
||||||
usb_device_class = class_create(THIS_MODULE, "usb_device");
|
#ifdef CONFIG_USB_DEVICE_CLASS
|
||||||
if (IS_ERR(usb_device_class)) {
|
usb_classdev_class = class_create(THIS_MODULE, "usb_device");
|
||||||
|
if (IS_ERR(usb_classdev_class)) {
|
||||||
err("unable to register usb_device class");
|
err("unable to register usb_device class");
|
||||||
retval = PTR_ERR(usb_device_class);
|
retval = PTR_ERR(usb_classdev_class);
|
||||||
goto error_class;
|
cdev_del(&usb_device_cdev);
|
||||||
|
usb_classdev_class = NULL;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
usb_register_notify(&usbdev_nb);
|
usb_register_notify(&usbdev_nb);
|
||||||
|
#endif
|
||||||
out:
|
out:
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
error_class:
|
|
||||||
usb_device_class = NULL;
|
|
||||||
cdev_del(&usb_device_cdev);
|
|
||||||
|
|
||||||
error_cdev:
|
error_cdev:
|
||||||
unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
|
unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
void usbdev_cleanup(void)
|
void usb_devio_cleanup(void)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_USB_DEVICE_CLASS
|
||||||
usb_unregister_notify(&usbdev_nb);
|
usb_unregister_notify(&usbdev_nb);
|
||||||
class_destroy(usb_device_class);
|
class_destroy(usb_classdev_class);
|
||||||
|
#endif
|
||||||
cdev_del(&usb_device_cdev);
|
cdev_del(&usb_device_cdev);
|
||||||
unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
|
unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -574,23 +574,10 @@ static int usb_device_match(struct device *dev, struct device_driver *drv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_HOTPLUG
|
#ifdef CONFIG_HOTPLUG
|
||||||
|
|
||||||
/*
|
|
||||||
* This sends an uevent to userspace, typically helping to load driver
|
|
||||||
* or other modules, configure the device, and more. Drivers can provide
|
|
||||||
* a MODULE_DEVICE_TABLE to help with module loading subtasks.
|
|
||||||
*
|
|
||||||
* We're called either from khubd (the typical case) or from root hub
|
|
||||||
* (init, kapmd, modprobe, rmmod, etc), but the agents need to handle
|
|
||||||
* delays in event delivery. Use sysfs (and DEVPATH) to make sure the
|
|
||||||
* device (and this configuration!) are still present.
|
|
||||||
*/
|
|
||||||
static int usb_uevent(struct device *dev, char **envp, int num_envp,
|
static int usb_uevent(struct device *dev, char **envp, int num_envp,
|
||||||
char *buffer, int buffer_size)
|
char *buffer, int buffer_size)
|
||||||
{
|
{
|
||||||
struct usb_interface *intf;
|
|
||||||
struct usb_device *usb_dev;
|
struct usb_device *usb_dev;
|
||||||
struct usb_host_interface *alt;
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int length = 0;
|
int length = 0;
|
||||||
|
|
||||||
@ -600,13 +587,11 @@ static int usb_uevent(struct device *dev, char **envp, int num_envp,
|
|||||||
/* driver is often null here; dev_dbg() would oops */
|
/* driver is often null here; dev_dbg() would oops */
|
||||||
pr_debug ("usb %s: uevent\n", dev->bus_id);
|
pr_debug ("usb %s: uevent\n", dev->bus_id);
|
||||||
|
|
||||||
if (is_usb_device(dev)) {
|
if (is_usb_device(dev))
|
||||||
usb_dev = to_usb_device(dev);
|
usb_dev = to_usb_device(dev);
|
||||||
alt = NULL;
|
else {
|
||||||
} else {
|
struct usb_interface *intf = to_usb_interface(dev);
|
||||||
intf = to_usb_interface(dev);
|
|
||||||
usb_dev = interface_to_usbdev(intf);
|
usb_dev = interface_to_usbdev(intf);
|
||||||
alt = intf->cur_altsetting;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usb_dev->devnum < 0) {
|
if (usb_dev->devnum < 0) {
|
||||||
@ -621,9 +606,7 @@ static int usb_uevent(struct device *dev, char **envp, int num_envp,
|
|||||||
#ifdef CONFIG_USB_DEVICEFS
|
#ifdef CONFIG_USB_DEVICEFS
|
||||||
/* If this is available, userspace programs can directly read
|
/* If this is available, userspace programs can directly read
|
||||||
* all the device descriptors we don't tell them about. Or
|
* all the device descriptors we don't tell them about. Or
|
||||||
* even act as usermode drivers.
|
* act as usermode drivers.
|
||||||
*
|
|
||||||
* FIXME reduce hardwired intelligence here
|
|
||||||
*/
|
*/
|
||||||
if (add_uevent_var(envp, num_envp, &i,
|
if (add_uevent_var(envp, num_envp, &i,
|
||||||
buffer, buffer_size, &length,
|
buffer, buffer_size, &length,
|
||||||
@ -650,44 +633,29 @@ static int usb_uevent(struct device *dev, char **envp, int num_envp,
|
|||||||
usb_dev->descriptor.bDeviceProtocol))
|
usb_dev->descriptor.bDeviceProtocol))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (!is_usb_device(dev)) {
|
if (add_uevent_var(envp, num_envp, &i,
|
||||||
|
|
||||||
if (add_uevent_var(envp, num_envp, &i,
|
|
||||||
buffer, buffer_size, &length,
|
buffer, buffer_size, &length,
|
||||||
"INTERFACE=%d/%d/%d",
|
"BUSNUM=%03d",
|
||||||
alt->desc.bInterfaceClass,
|
usb_dev->bus->busnum))
|
||||||
alt->desc.bInterfaceSubClass,
|
return -ENOMEM;
|
||||||
alt->desc.bInterfaceProtocol))
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
if (add_uevent_var(envp, num_envp, &i,
|
if (add_uevent_var(envp, num_envp, &i,
|
||||||
buffer, buffer_size, &length,
|
buffer, buffer_size, &length,
|
||||||
"MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
|
"DEVNUM=%03d",
|
||||||
le16_to_cpu(usb_dev->descriptor.idVendor),
|
usb_dev->devnum))
|
||||||
le16_to_cpu(usb_dev->descriptor.idProduct),
|
return -ENOMEM;
|
||||||
le16_to_cpu(usb_dev->descriptor.bcdDevice),
|
|
||||||
usb_dev->descriptor.bDeviceClass,
|
|
||||||
usb_dev->descriptor.bDeviceSubClass,
|
|
||||||
usb_dev->descriptor.bDeviceProtocol,
|
|
||||||
alt->desc.bInterfaceClass,
|
|
||||||
alt->desc.bInterfaceSubClass,
|
|
||||||
alt->desc.bInterfaceProtocol))
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
envp[i] = NULL;
|
envp[i] = NULL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static int usb_uevent(struct device *dev, char **envp,
|
static int usb_uevent(struct device *dev, char **envp,
|
||||||
int num_envp, char *buffer, int buffer_size)
|
int num_envp, char *buffer, int buffer_size)
|
||||||
{
|
{
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_HOTPLUG */
|
#endif /* CONFIG_HOTPLUG */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1367,11 +1367,15 @@ int usb_new_device(struct usb_device *udev)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* export the usbdev device-node for libusb */
|
||||||
|
udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
|
||||||
|
(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
|
||||||
|
|
||||||
/* Register the device. The device driver is responsible
|
/* Register the device. The device driver is responsible
|
||||||
* for adding the device files to usbfs and sysfs and for
|
* for adding the device files to sysfs and for configuring
|
||||||
* configuring the device.
|
* the device.
|
||||||
*/
|
*/
|
||||||
err = device_add (&udev->dev);
|
err = device_add(&udev->dev);
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_err(&udev->dev, "can't device_add, error %d\n", err);
|
dev_err(&udev->dev, "can't device_add, error %d\n", err);
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -662,7 +662,7 @@ static void usbfs_add_device(struct usb_device *dev)
|
|||||||
sprintf (name, "%03d", dev->devnum);
|
sprintf (name, "%03d", dev->devnum);
|
||||||
dev->usbfs_dentry = fs_create_file (name, devmode | S_IFREG,
|
dev->usbfs_dentry = fs_create_file (name, devmode | S_IFREG,
|
||||||
dev->bus->usbfs_dentry, dev,
|
dev->bus->usbfs_dentry, dev,
|
||||||
&usbfs_device_file_operations,
|
&usbdev_file_operations,
|
||||||
devuid, devgid);
|
devuid, devgid);
|
||||||
if (dev->usbfs_dentry == NULL) {
|
if (dev->usbfs_dentry == NULL) {
|
||||||
err ("error creating usbfs device entry");
|
err ("error creating usbfs device entry");
|
||||||
|
@ -1305,7 +1305,7 @@ int usb_reset_configuration(struct usb_device *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void release_interface(struct device *dev)
|
void usb_release_interface(struct device *dev)
|
||||||
{
|
{
|
||||||
struct usb_interface *intf = to_usb_interface(dev);
|
struct usb_interface *intf = to_usb_interface(dev);
|
||||||
struct usb_interface_cache *intfc =
|
struct usb_interface_cache *intfc =
|
||||||
@ -1315,6 +1315,67 @@ static void release_interface(struct device *dev)
|
|||||||
kfree(intf);
|
kfree(intf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_HOTPLUG
|
||||||
|
static int usb_if_uevent(struct device *dev, char **envp, int num_envp,
|
||||||
|
char *buffer, int buffer_size)
|
||||||
|
{
|
||||||
|
struct usb_device *usb_dev;
|
||||||
|
struct usb_interface *intf;
|
||||||
|
struct usb_host_interface *alt;
|
||||||
|
int i = 0;
|
||||||
|
int length = 0;
|
||||||
|
|
||||||
|
if (!dev)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
/* driver is often null here; dev_dbg() would oops */
|
||||||
|
pr_debug ("usb %s: uevent\n", dev->bus_id);
|
||||||
|
|
||||||
|
intf = to_usb_interface(dev);
|
||||||
|
usb_dev = interface_to_usbdev(intf);
|
||||||
|
alt = intf->cur_altsetting;
|
||||||
|
|
||||||
|
if (add_uevent_var(envp, num_envp, &i,
|
||||||
|
buffer, buffer_size, &length,
|
||||||
|
"INTERFACE=%d/%d/%d",
|
||||||
|
alt->desc.bInterfaceClass,
|
||||||
|
alt->desc.bInterfaceSubClass,
|
||||||
|
alt->desc.bInterfaceProtocol))
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (add_uevent_var(envp, num_envp, &i,
|
||||||
|
buffer, buffer_size, &length,
|
||||||
|
"MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
|
||||||
|
le16_to_cpu(usb_dev->descriptor.idVendor),
|
||||||
|
le16_to_cpu(usb_dev->descriptor.idProduct),
|
||||||
|
le16_to_cpu(usb_dev->descriptor.bcdDevice),
|
||||||
|
usb_dev->descriptor.bDeviceClass,
|
||||||
|
usb_dev->descriptor.bDeviceSubClass,
|
||||||
|
usb_dev->descriptor.bDeviceProtocol,
|
||||||
|
alt->desc.bInterfaceClass,
|
||||||
|
alt->desc.bInterfaceSubClass,
|
||||||
|
alt->desc.bInterfaceProtocol))
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
envp[i] = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static int usb_if_uevent(struct device *dev, char **envp,
|
||||||
|
int num_envp, char *buffer, int buffer_size)
|
||||||
|
{
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_HOTPLUG */
|
||||||
|
|
||||||
|
struct device_type usb_if_device_type = {
|
||||||
|
.name = "usb_interface",
|
||||||
|
.release = usb_release_interface,
|
||||||
|
.uevent = usb_if_uevent,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* usb_set_configuration - Makes a particular device setting be current
|
* usb_set_configuration - Makes a particular device setting be current
|
||||||
* @dev: the device whose configuration is being updated
|
* @dev: the device whose configuration is being updated
|
||||||
@ -1478,8 +1539,8 @@ free_interfaces:
|
|||||||
intf->dev.parent = &dev->dev;
|
intf->dev.parent = &dev->dev;
|
||||||
intf->dev.driver = NULL;
|
intf->dev.driver = NULL;
|
||||||
intf->dev.bus = &usb_bus_type;
|
intf->dev.bus = &usb_bus_type;
|
||||||
|
intf->dev.type = &usb_if_device_type;
|
||||||
intf->dev.dma_mask = dev->dev.dma_mask;
|
intf->dev.dma_mask = dev->dev.dma_mask;
|
||||||
intf->dev.release = release_interface;
|
|
||||||
device_initialize (&intf->dev);
|
device_initialize (&intf->dev);
|
||||||
mark_quiesced(intf);
|
mark_quiesced(intf);
|
||||||
sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d",
|
sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d",
|
||||||
|
@ -197,6 +197,11 @@ static void usb_release_dev(struct device *dev)
|
|||||||
kfree(udev);
|
kfree(udev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct device_type usb_device_type = {
|
||||||
|
.name = "usb_device",
|
||||||
|
.release = usb_release_dev,
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
|
|
||||||
static int ksuspend_usb_init(void)
|
static int ksuspend_usb_init(void)
|
||||||
@ -247,13 +252,10 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
|
|||||||
|
|
||||||
device_initialize(&dev->dev);
|
device_initialize(&dev->dev);
|
||||||
dev->dev.bus = &usb_bus_type;
|
dev->dev.bus = &usb_bus_type;
|
||||||
|
dev->dev.type = &usb_device_type;
|
||||||
dev->dev.dma_mask = bus->controller->dma_mask;
|
dev->dev.dma_mask = bus->controller->dma_mask;
|
||||||
dev->dev.release = usb_release_dev;
|
|
||||||
dev->state = USB_STATE_ATTACHED;
|
dev->state = USB_STATE_ATTACHED;
|
||||||
|
|
||||||
/* This magic assignment distinguishes devices from interfaces */
|
|
||||||
dev->dev.platform_data = &usb_generic_driver;
|
|
||||||
|
|
||||||
INIT_LIST_HEAD(&dev->ep0.urb_list);
|
INIT_LIST_HEAD(&dev->ep0.urb_list);
|
||||||
dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
|
dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
|
||||||
dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
|
dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
|
||||||
@ -882,9 +884,9 @@ static int __init usb_init(void)
|
|||||||
retval = usb_register(&usbfs_driver);
|
retval = usb_register(&usbfs_driver);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto driver_register_failed;
|
goto driver_register_failed;
|
||||||
retval = usbdev_init();
|
retval = usb_devio_init();
|
||||||
if (retval)
|
if (retval)
|
||||||
goto usbdevice_init_failed;
|
goto usb_devio_init_failed;
|
||||||
retval = usbfs_init();
|
retval = usbfs_init();
|
||||||
if (retval)
|
if (retval)
|
||||||
goto fs_init_failed;
|
goto fs_init_failed;
|
||||||
@ -899,8 +901,8 @@ static int __init usb_init(void)
|
|||||||
hub_init_failed:
|
hub_init_failed:
|
||||||
usbfs_cleanup();
|
usbfs_cleanup();
|
||||||
fs_init_failed:
|
fs_init_failed:
|
||||||
usbdev_cleanup();
|
usb_devio_cleanup();
|
||||||
usbdevice_init_failed:
|
usb_devio_init_failed:
|
||||||
usb_deregister(&usbfs_driver);
|
usb_deregister(&usbfs_driver);
|
||||||
driver_register_failed:
|
driver_register_failed:
|
||||||
usb_major_cleanup();
|
usb_major_cleanup();
|
||||||
@ -927,7 +929,7 @@ static void __exit usb_exit(void)
|
|||||||
usb_major_cleanup();
|
usb_major_cleanup();
|
||||||
usbfs_cleanup();
|
usbfs_cleanup();
|
||||||
usb_deregister(&usbfs_driver);
|
usb_deregister(&usbfs_driver);
|
||||||
usbdev_cleanup();
|
usb_devio_cleanup();
|
||||||
usb_hub_cleanup();
|
usb_hub_cleanup();
|
||||||
usb_host_cleanup();
|
usb_host_cleanup();
|
||||||
bus_unregister(&usb_bus_type);
|
bus_unregister(&usb_bus_type);
|
||||||
|
@ -78,15 +78,13 @@ static inline int usb_autoresume_device(struct usb_device *udev)
|
|||||||
|
|
||||||
extern struct workqueue_struct *ksuspend_usb_wq;
|
extern struct workqueue_struct *ksuspend_usb_wq;
|
||||||
extern struct bus_type usb_bus_type;
|
extern struct bus_type usb_bus_type;
|
||||||
|
extern struct device_type usb_device_type;
|
||||||
|
extern struct device_type usb_if_device_type;
|
||||||
extern struct usb_device_driver usb_generic_driver;
|
extern struct usb_device_driver usb_generic_driver;
|
||||||
|
|
||||||
/* Here's how we tell apart devices and interfaces. Luckily there's
|
|
||||||
* no such thing as a platform USB device, so we can steal the use
|
|
||||||
* of the platform_data field. */
|
|
||||||
|
|
||||||
static inline int is_usb_device(const struct device *dev)
|
static inline int is_usb_device(const struct device *dev)
|
||||||
{
|
{
|
||||||
return dev->platform_data == &usb_generic_driver;
|
return dev->type == &usb_device_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do the same for device drivers and interface drivers. */
|
/* Do the same for device drivers and interface drivers. */
|
||||||
@ -122,11 +120,11 @@ extern const char *usbcore_name;
|
|||||||
extern struct mutex usbfs_mutex;
|
extern struct mutex usbfs_mutex;
|
||||||
extern struct usb_driver usbfs_driver;
|
extern struct usb_driver usbfs_driver;
|
||||||
extern const struct file_operations usbfs_devices_fops;
|
extern const struct file_operations usbfs_devices_fops;
|
||||||
extern const struct file_operations usbfs_device_file_operations;
|
extern const struct file_operations usbdev_file_operations;
|
||||||
extern void usbfs_conn_disc_event(void);
|
extern void usbfs_conn_disc_event(void);
|
||||||
|
|
||||||
extern int usbdev_init(void);
|
extern int usb_devio_init(void);
|
||||||
extern void usbdev_cleanup(void);
|
extern void usb_devio_cleanup(void);
|
||||||
|
|
||||||
struct dev_state {
|
struct dev_state {
|
||||||
struct list_head list; /* state list */
|
struct list_head list; /* state list */
|
||||||
|
@ -299,8 +299,9 @@ struct usb_bus {
|
|||||||
int bandwidth_int_reqs; /* number of Interrupt requests */
|
int bandwidth_int_reqs; /* number of Interrupt requests */
|
||||||
int bandwidth_isoc_reqs; /* number of Isoc. requests */
|
int bandwidth_isoc_reqs; /* number of Isoc. requests */
|
||||||
|
|
||||||
|
#ifdef CONFIG_USB_DEVICEFS
|
||||||
struct dentry *usbfs_dentry; /* usbfs dentry entry for the bus */
|
struct dentry *usbfs_dentry; /* usbfs dentry entry for the bus */
|
||||||
|
#endif
|
||||||
struct class_device *class_dev; /* class device for this bus */
|
struct class_device *class_dev; /* class device for this bus */
|
||||||
|
|
||||||
#if defined(CONFIG_USB_MON)
|
#if defined(CONFIG_USB_MON)
|
||||||
@ -373,9 +374,12 @@ struct usb_device {
|
|||||||
char *serial; /* iSerialNumber string, if present */
|
char *serial; /* iSerialNumber string, if present */
|
||||||
|
|
||||||
struct list_head filelist;
|
struct list_head filelist;
|
||||||
struct device *usbfs_dev;
|
#ifdef CONFIG_USB_DEVICE_CLASS
|
||||||
|
struct device *usb_classdev;
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_USB_DEVICEFS
|
||||||
struct dentry *usbfs_dentry; /* usbfs dentry entry for the device */
|
struct dentry *usbfs_dentry; /* usbfs dentry entry for the device */
|
||||||
|
#endif
|
||||||
/*
|
/*
|
||||||
* Child devices - these can be either new devices
|
* Child devices - these can be either new devices
|
||||||
* (if this is a hub device), or different instances
|
* (if this is a hub device), or different instances
|
||||||
|
Loading…
Reference in New Issue
Block a user