mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-22 20:23:57 +08:00
USB: add remove_id sysfs attr for usb drivers
Accroding commit 0994375e
, which is adding remove_id sysfs attr
for pci drivers, for management tools dynamically bind/unbind
a pci/usb devices to a specified drivers; with this patch,
the management tools can be simplied.
And the original code didn't handle the failure of
usb_create_newid_file, fixed in this patch.
Signed-off-by: CHENG Renquan <rqcheng@smu.edu.sg>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
5791e10341
commit
0c7a2b7274
@ -144,3 +144,16 @@ Description:
|
|||||||
|
|
||||||
Write a 1 to force the device to disconnect
|
Write a 1 to force the device to disconnect
|
||||||
(equivalent to unplugging a wired USB device).
|
(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
|
||||||
|
@ -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);
|
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)
|
static int usb_create_newid_file(struct usb_driver *usb_drv)
|
||||||
{
|
{
|
||||||
int error = 0;
|
int error = 0;
|
||||||
@ -107,6 +148,21 @@ static void usb_remove_newid_file(struct usb_driver *usb_drv)
|
|||||||
&driver_attr_new_id);
|
&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)
|
static void usb_free_dynids(struct usb_driver *usb_drv)
|
||||||
{
|
{
|
||||||
struct usb_dynid *dynid, *n;
|
struct usb_dynid *dynid, *n;
|
||||||
@ -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)
|
static inline void usb_free_dynids(struct usb_driver *usb_drv)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -774,19 +840,34 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
|
|||||||
INIT_LIST_HEAD(&new_driver->dynids.list);
|
INIT_LIST_HEAD(&new_driver->dynids.list);
|
||||||
|
|
||||||
retval = driver_register(&new_driver->drvwrap.driver);
|
retval = driver_register(&new_driver->drvwrap.driver);
|
||||||
|
if (retval)
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (!retval) {
|
usbfs_update_special();
|
||||||
pr_info("%s: registered new interface driver %s\n",
|
|
||||||
|
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);
|
usbcore_name, new_driver->name);
|
||||||
usbfs_update_special();
|
|
||||||
usb_create_newid_file(new_driver);
|
out:
|
||||||
} else {
|
return retval;
|
||||||
printk(KERN_ERR "%s: error %d registering interface "
|
|
||||||
|
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",
|
" driver %s\n",
|
||||||
usbcore_name, retval, new_driver->name);
|
usbcore_name, retval, new_driver->name);
|
||||||
}
|
goto out;
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(usb_register_driver);
|
EXPORT_SYMBOL_GPL(usb_register_driver);
|
||||||
|
|
||||||
@ -806,6 +887,7 @@ void usb_deregister(struct usb_driver *driver)
|
|||||||
pr_info("%s: deregistering interface driver %s\n",
|
pr_info("%s: deregistering interface driver %s\n",
|
||||||
usbcore_name, driver->name);
|
usbcore_name, driver->name);
|
||||||
|
|
||||||
|
usb_remove_removeid_file(driver);
|
||||||
usb_remove_newid_file(driver);
|
usb_remove_newid_file(driver);
|
||||||
usb_free_dynids(driver);
|
usb_free_dynids(driver);
|
||||||
driver_unregister(&driver->drvwrap.driver);
|
driver_unregister(&driver->drvwrap.driver);
|
||||||
|
Loading…
Reference in New Issue
Block a user