usb: add the concept of default authorization to USB hosts
authorInaky Perez-Gonzalez <inaky@linux.intel.com>
Wed, 1 Aug 2007 03:33:58 +0000 (20:33 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 12 Oct 2007 21:55:04 +0000 (14:55 -0700)
This introduces /sys/bus/devices/usb*/authorized_default; it dictates
what is going to be the default authorization state for devices
connected to the host. User space can set that using the sysfs file.

We hook to the root hub instead of to the device controller as it is
quite easy to get to it in sysfs from the device structure (device
5-4.3 is usb5) vs. backtracking to the controller device.

By default it is set to be 'authorized' (!0) for normal, wired USB
devices and 'unauthorized' (0) for Wireless USB devices.

As suggested by Adrian Bunk, make authorized_default static

Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/core/hcd.c
drivers/usb/core/hcd.h

index eb2121788264f82bbdbff97bcaff3bdde50537dd..875e2476c1f5eaa99ade6127f989f9985907b05e 100644 (file)
@@ -679,6 +679,66 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
        return 0;
 }
 
+
+
+/*
+ * Show & store the current value of authorized_default
+ */
+static ssize_t usb_host_authorized_default_show(struct device *dev,
+                                               struct device_attribute *attr,
+                                               char *buf)
+{
+       struct usb_device *rh_usb_dev = to_usb_device(dev);
+       struct usb_bus *usb_bus = rh_usb_dev->bus;
+       struct usb_hcd *usb_hcd;
+
+       if (usb_bus == NULL)    /* FIXME: not sure if this case is possible */
+               return -ENODEV;
+       usb_hcd = bus_to_hcd(usb_bus);
+       return snprintf(buf, PAGE_SIZE, "%u\n", usb_hcd->authorized_default);
+}
+
+static ssize_t usb_host_authorized_default_store(struct device *dev,
+                                                struct device_attribute *attr,
+                                                const char *buf, size_t size)
+{
+       ssize_t result;
+       unsigned val;
+       struct usb_device *rh_usb_dev = to_usb_device(dev);
+       struct usb_bus *usb_bus = rh_usb_dev->bus;
+       struct usb_hcd *usb_hcd;
+
+       if (usb_bus == NULL)    /* FIXME: not sure if this case is possible */
+               return -ENODEV;
+       usb_hcd = bus_to_hcd(usb_bus);
+       result = sscanf(buf, "%u\n", &val);
+       if (result == 1) {
+               usb_hcd->authorized_default = val? 1 : 0;
+               result = size;
+       }
+       else
+               result = -EINVAL;
+       return result;
+}
+
+static DEVICE_ATTR(authorized_default, 0644,
+           usb_host_authorized_default_show,
+           usb_host_authorized_default_store);
+
+
+/* Group all the USB bus attributes */
+static struct attribute *usb_bus_attrs[] = {
+               &dev_attr_authorized_default.attr,
+               NULL,
+};
+
+static struct attribute_group usb_bus_attr_group = {
+       .name = NULL,   /* we want them in the same directory */
+       .attrs = usb_bus_attrs,
+};
+
+
+
 /*-------------------------------------------------------------------------*/
 
 static struct class *usb_host_class;
@@ -1542,7 +1602,6 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
        hcd->driver = driver;
        hcd->product_desc = (driver->product_desc) ? driver->product_desc :
                        "USB Host Controller";
-
        return hcd;
 }
 EXPORT_SYMBOL (usb_create_hcd);
@@ -1587,6 +1646,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
 
        dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
 
+       hcd->authorized_default = hcd->wireless? 0 : 1;
        set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
 
        /* HC is in reset state, but accessible.  Now do the one-time init,
@@ -1663,10 +1723,20 @@ int usb_add_hcd(struct usb_hcd *hcd,
        if ((retval = register_root_hub(hcd)) != 0)
                goto err_register_root_hub;
 
+       retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group);
+       if (retval < 0) {
+               printk(KERN_ERR "Cannot register USB bus sysfs attributes: %d\n",
+                      retval);
+               goto error_create_attr_group;
+       }
        if (hcd->uses_new_polling && hcd->poll_rh)
                usb_hcd_poll_rh_status(hcd);
        return retval;
 
+error_create_attr_group:
+       mutex_lock(&usb_bus_list_lock);
+       usb_disconnect(&hcd->self.root_hub);
+       mutex_unlock(&usb_bus_list_lock);
 err_register_root_hub:
        hcd->driver->stop(hcd);
 err_hcd_driver_start:
@@ -1708,6 +1778,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
        cancel_work_sync(&hcd->wakeup_work);
 #endif
 
+       sysfs_remove_group(&hcd->self.root_hub->dev.kobj, &usb_bus_attr_group);
        mutex_lock(&usb_bus_list_lock);
        usb_disconnect(&hcd->self.root_hub);
        mutex_unlock(&usb_bus_list_lock);
index b5ebb73c23328cd5e65292f542d3d946e5ea9459..8683142e70e1f63a35efb438171a6e1bd96e548f 100644 (file)
  *
  * Since "struct usb_bus" is so thin, you can't share much code in it.
  * This framework is a layer over that, and should be more sharable.
+ *
+ * @authorized_default: Specifies if new devices are authorized to
+ *                      connect by default or they require explicit
+ *                      user space authorization; this bit is settable
+ *                      through /sys/class/usb_host/X/authorized_default.
+ *                      For the rest is RO, so we don't lock to r/w it.
  */
 
 /*-------------------------------------------------------------------------*/
@@ -90,6 +96,7 @@ struct usb_hcd {
        unsigned                poll_rh:1;      /* poll for rh status? */
        unsigned                poll_pending:1; /* status has changed? */
        unsigned                wireless:1;     /* Wireless USB HCD */
+       unsigned                authorized_default:1;
 
        int                     irq;            /* irq allocated */
        void __iomem            *regs;          /* device memory/io */