Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 174987
b: refs/heads/master
c: 0c7a2b7
h: refs/heads/master
i:
  174985: d4f8b4e
  174983: 56adeb0
v: v3
  • Loading branch information
CHENG Renquan authored and Greg Kroah-Hartman committed Dec 11, 2009
1 parent c831ae9 commit 9f321f8
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 10 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 5791e10341f8bf284bd16eb0949cbeed91c9dac8
refs/heads/master: 0c7a2b72746a96f999fd2728520d03d94879be69
13 changes: 13 additions & 0 deletions trunk/Documentation/ABI/testing/sysfs-bus-usb
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,16 @@ Description:

Write a 1 to force the device to disconnect
(equivalent to unplugging a wired USB device).

What: /sys/bus/usb/drivers/.../remove_id
Date: November 2009
Contact: CHENG Renquan <rqcheng@smu.edu.sg>
Description:
Writing a device ID to this file will remove an ID
that was dynamically added via the new_id sysfs entry.
The format for the device ID is:
idVendor idProduct. After successfully
removing an ID, the driver will no longer support the
device. This is useful to ensure auto probing won't
match the driver to the device. For example:
# echo "046d c315" > /sys/bus/usb/drivers/foo/remove_id
100 changes: 91 additions & 9 deletions trunk/drivers/usb/core/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,47 @@ static ssize_t store_new_id(struct device_driver *driver,
}
static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);

/**
* store_remove_id - remove a USB device ID from this driver
* @driver: target device driver
* @buf: buffer for scanning device ID data
* @count: input size
*
* Removes a dynamic usb device ID from this driver.
*/
static ssize_t
store_remove_id(struct device_driver *driver, const char *buf, size_t count)
{
struct usb_dynid *dynid, *n;
struct usb_driver *usb_driver = to_usb_driver(driver);
u32 idVendor = 0;
u32 idProduct = 0;
int fields = 0;
int retval = 0;

fields = sscanf(buf, "%x %x", &idVendor, &idProduct);
if (fields < 2)
return -EINVAL;

spin_lock(&usb_driver->dynids.lock);
list_for_each_entry_safe(dynid, n, &usb_driver->dynids.list, node) {
struct usb_device_id *id = &dynid->id;
if ((id->idVendor == idVendor) &&
(id->idProduct == idProduct)) {
list_del(&dynid->node);
kfree(dynid);
retval = 0;
break;
}
}
spin_unlock(&usb_driver->dynids.lock);

if (retval)
return retval;
return count;
}
static DRIVER_ATTR(remove_id, S_IWUSR, NULL, store_remove_id);

static int usb_create_newid_file(struct usb_driver *usb_drv)
{
int error = 0;
Expand All @@ -107,6 +148,21 @@ static void usb_remove_newid_file(struct usb_driver *usb_drv)
&driver_attr_new_id);
}

static int
usb_create_removeid_file(struct usb_driver *drv)
{
int error = 0;
if (drv->probe != NULL)
error = driver_create_file(&drv->drvwrap.driver,
&driver_attr_remove_id);
return error;
}

static void usb_remove_removeid_file(struct usb_driver *drv)
{
driver_remove_file(&drv->drvwrap.driver, &driver_attr_remove_id);
}

static void usb_free_dynids(struct usb_driver *usb_drv)
{
struct usb_dynid *dynid, *n;
Expand All @@ -128,6 +184,16 @@ static void usb_remove_newid_file(struct usb_driver *usb_drv)
{
}

static int
usb_create_removeid_file(struct usb_driver *drv)
{
return 0;
}

static void usb_remove_removeid_file(struct usb_driver *drv)
{
}

static inline void usb_free_dynids(struct usb_driver *usb_drv)
{
}
Expand Down Expand Up @@ -774,19 +840,34 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
INIT_LIST_HEAD(&new_driver->dynids.list);

retval = driver_register(&new_driver->drvwrap.driver);
if (retval)
goto out;

if (!retval) {
pr_info("%s: registered new interface driver %s\n",
usbfs_update_special();

retval = usb_create_newid_file(new_driver);
if (retval)
goto out_newid;

retval = usb_create_removeid_file(new_driver);
if (retval)
goto out_removeid;

pr_info("%s: registered new interface driver %s\n",
usbcore_name, new_driver->name);
usbfs_update_special();
usb_create_newid_file(new_driver);
} else {
printk(KERN_ERR "%s: error %d registering interface "
" driver %s\n",
usbcore_name, retval, new_driver->name);
}

out:
return retval;

out_removeid:
usb_remove_newid_file(new_driver);
out_newid:
driver_unregister(&new_driver->drvwrap.driver);

printk(KERN_ERR "%s: error %d registering interface "
" driver %s\n",
usbcore_name, retval, new_driver->name);
goto out;
}
EXPORT_SYMBOL_GPL(usb_register_driver);

Expand All @@ -806,6 +887,7 @@ void usb_deregister(struct usb_driver *driver)
pr_info("%s: deregistering interface driver %s\n",
usbcore_name, driver->name);

usb_remove_removeid_file(driver);
usb_remove_newid_file(driver);
usb_free_dynids(driver);
driver_unregister(&driver->drvwrap.driver);
Expand Down

0 comments on commit 9f321f8

Please sign in to comment.