Delivered-To: crquan@gmail.com Received: by 10.220.74.15 with SMTP id s15cs226621vcj; Sat, 21 Nov 2009 09:26:22 -0800 (PST) Received: by 10.115.113.6 with SMTP id q6mr4272262wam.55.1258824382317; Sat, 21 Nov 2009 09:26:22 -0800 (PST) Return-Path: Received: from ieg04.smu.edu.sg (ieg02.smu.edu.sg [202.161.41.197]) by mx.google.com with ESMTP id 16si4804855pzk.108.2009.11.21.09.26.20; Sat, 21 Nov 2009 09:26:22 -0800 (PST) Received-SPF: softfail (google.com: domain of transitioning rqcheng@smu.edu.sg does not designate 202.161.41.197 as permitted sender) client-ip=202.161.41.197; Authentication-Results: mx.google.com; spf=softfail (google.com: domain of transitioning rqcheng@smu.edu.sg does not designate 202.161.41.197 as permitted sender) smtp.mail=rqcheng@smu.edu.sg X-AuditID: caa129d9-a55babb000001057-67-4b0822bb81d8 Received: from localhost.localdomain (unknown [10.4.8.57]) by ieg04.smu.edu.sg (Symantec Mail Security) with ESMTP id 9139A4DC002; Sun, 22 Nov 2009 01:26:19 +0800 (MYT) From: CHENG Renquan To: Greg KH , Greg Kroah-Hartman , linux-usb@vger.kernel.org Cc: crquan@gmail.com Subject: [PATCH] USB: add remove_id sysfs attr for usb drivers Date: Sun, 22 Nov 2009 01:28:52 +0800 Message-Id: <1258824532-3790-1-git-send-email-rqcheng@smu.edu.sg> X-Mailer: git-send-email 1.6.5 In-Reply-To: <20091120211017.GA32380@kroah.com> References: <20091120211017.GA32380@kroah.com> X-Brightmail-Tracker: AAAAAA== 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 --- Documentation/ABI/testing/sysfs-bus-usb | 13 ++++ drivers/usb/core/driver.c | 100 ++++++++++++++++++++++++++++--- 2 files changed, 104 insertions(+), 9 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb index 7772928..deb6b48 100644 --- a/Documentation/ABI/testing/sysfs-bus-usb +++ b/Documentation/ABI/testing/sysfs-bus-usb @@ -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 +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 diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 4f86447..5f45d0f 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -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; @@ -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; @@ -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) { } @@ -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); @@ -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); -- git 1.6.5 CHENG Renquan (程任全), from SMU (Singapore Management University)