]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/usb/core/devio.c
USB: make usbdevices export their device nodes instead of using a separate class
[linux-2.6-omap-h63xx.git] / drivers / usb / core / devio.c
index 3ed4cb2d56d9286e6e8a828b69dcc9304aaf8e81..e023f3d562483cc2c7dfd1052d83b2eb7ca30b39 100644 (file)
@@ -57,7 +57,6 @@
 
 #define USB_MAXBUS                     64
 #define USB_DEVICE_MAX                 USB_MAXBUS * 128
-static struct class *usb_device_class;
 
 /* Mutual exclusion for removal, open, and release */
 DEFINE_MUTEX(usbfs_mutex);
@@ -421,14 +420,11 @@ static int claimintf(struct dev_state *ps, unsigned int ifnum)
        if (test_bit(ifnum, &ps->ifclaimed))
                return 0;
 
-       /* lock against other changes to driver bindings */
-       down_write(&usb_bus_type.subsys.rwsem);
        intf = usb_ifnum_to_if(dev, ifnum);
        if (!intf)
                err = -ENOENT;
        else
                err = usb_driver_claim_interface(&usbfs_driver, intf, ps);
-       up_write(&usb_bus_type.subsys.rwsem);
        if (err == 0)
                set_bit(ifnum, &ps->ifclaimed);
        return err;
@@ -444,8 +440,6 @@ static int releaseintf(struct dev_state *ps, unsigned int ifnum)
        if (ifnum >= 8*sizeof(ps->ifclaimed))
                return err;
        dev = ps->dev;
-       /* lock against other changes to driver bindings */
-       down_write(&usb_bus_type.subsys.rwsem);
        intf = usb_ifnum_to_if(dev, ifnum);
        if (!intf)
                err = -ENOENT;
@@ -453,7 +447,6 @@ static int releaseintf(struct dev_state *ps, unsigned int ifnum)
                usb_driver_release_interface(&usbfs_driver, intf);
                err = 0;
        }
-       up_write(&usb_bus_type.subsys.rwsem);
        return err;
 }
 
@@ -520,22 +513,25 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig
        return ret;
 }
 
-static struct usb_device *usbdev_lookup_minor(int minor)
+static int __match_minor(struct device *dev, void *data)
 {
-       struct class_device *class_dev;
-       struct usb_device *dev = NULL;
+       int minor = *((int *)data);
 
-       down(&usb_device_class->sem);
-       list_for_each_entry(class_dev, &usb_device_class->children, node) {
-               if (class_dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
-                       dev = class_dev->class_data;
-                       break;
-               }
-       }
-       up(&usb_device_class->sem);
+       if (dev->devt == MKDEV(USB_DEVICE_MAJOR, minor))
+               return 1;
+       return 0;
+}
 
-       return dev;
-};
+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
@@ -554,11 +550,14 @@ static int usbdev_open(struct inode *inode, struct file *file)
                goto out;
 
        ret = -ENOENT;
-       /* check if we are called from a real node or usbfs */
+       /* usbdev device-node */
        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)
                dev = inode->i_private;
+#endif
        if (!dev)
                goto out;
        ret = usb_autoresume_device(dev);
@@ -570,6 +569,7 @@ static int usbdev_open(struct inode *inode, struct file *file)
        ps->dev = dev;
        ps->file = file;
        spin_lock_init(&ps->lock);
+       INIT_LIST_HEAD(&ps->list);
        INIT_LIST_HEAD(&ps->async_pending);
        INIT_LIST_HEAD(&ps->async_completed);
        init_waitqueue_head(&ps->wait);
@@ -812,7 +812,6 @@ static int proc_getdriver(struct dev_state *ps, void __user *arg)
 
        if (copy_from_user(&gd, arg, sizeof(gd)))
                return -EFAULT;
-       down_read(&usb_bus_type.subsys.rwsem);
        intf = usb_ifnum_to_if(ps->dev, gd.interface);
        if (!intf || !intf->dev.driver)
                ret = -ENODATA;
@@ -821,7 +820,6 @@ static int proc_getdriver(struct dev_state *ps, void __user *arg)
                                sizeof(gd.driver));
                ret = (copy_to_user(arg, &gd, sizeof(gd)) ? -EFAULT : 0);
        }
-       up_read(&usb_bus_type.subsys.rwsem);
        return ret;
 }
 
@@ -856,11 +854,11 @@ static int proc_setintf(struct dev_state *ps, void __user *arg)
 
 static int proc_setconfig(struct dev_state *ps, void __user *arg)
 {
-       unsigned int u;
+       int u;
        int status = 0;
        struct usb_host_config *actconfig;
 
-       if (get_user(u, (unsigned int __user *)arg))
+       if (get_user(u, (int __user *)arg))
                return -EFAULT;
 
        actconfig = ps->dev->actconfig;
@@ -911,7 +909,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
        struct async *as;
        struct usb_ctrlrequest *dr = NULL;
        unsigned int u, totlen, isofrmlen;
-       int ret, interval = 0, ifnum = -1;
+       int ret, ifnum = -1;
 
        if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK|
                           URB_NO_FSBR|URB_ZERO_PACKET))
@@ -962,7 +960,11 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                        kfree(dr);
                        return -EFAULT;
                }
-               snoop(&ps->dev->dev, "control urb\n");
+               snoop(&ps->dev->dev, "control urb: bRequest=%02x "
+                       "bRrequestType=%02x wValue=%04x "
+                       "wIndex=%04x wLength=%04x\n",
+                       dr->bRequest, dr->bRequestType, dr->wValue,
+                       dr->wIndex, dr->wLength);
                break;
 
        case USBDEVFS_URB_TYPE_BULK:
@@ -987,7 +989,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
                                != USB_ENDPOINT_XFER_ISOC)
                        return -EINVAL;
-               interval = 1 << min (15, ep->desc.bInterval - 1);
                isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets;
                if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
                        return -ENOMEM;
@@ -1016,10 +1017,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
                                != USB_ENDPOINT_XFER_INT)
                        return -EINVAL;
-               if (ps->dev->speed == USB_SPEED_HIGH)
-                       interval = 1 << min (15, ep->desc.bInterval - 1);
-               else
-                       interval = ep->desc.bInterval;
                if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
                        return -EINVAL;
                if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
@@ -1048,7 +1045,11 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
        as->urb->setup_packet = (unsigned char*)dr;
        as->urb->start_frame = uurb->start_frame;
        as->urb->number_of_packets = uurb->number_of_packets;
-       as->urb->interval = interval;
+       if (uurb->type == USBDEVFS_URB_TYPE_ISO ||
+                       ps->dev->speed == USB_SPEED_HIGH)
+               as->urb->interval = 1 << min(15, ep->desc.bInterval - 1);
+       else
+               as->urb->interval = ep->desc.bInterval;
         as->urb->context = as;
         as->urb->complete = async_completed;
        for (totlen = u = 0; u < uurb->number_of_packets; u++) {
@@ -1347,15 +1348,12 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
 
        /* disconnect kernel driver from interface */
        case USBDEVFS_DISCONNECT:
-
-               down_write(&usb_bus_type.subsys.rwsem);
                if (intf->dev.driver) {
                        driver = to_usb_driver(intf->dev.driver);
                        dev_dbg (&intf->dev, "disconnect by usbfs\n");
                        usb_driver_release_interface(driver, intf);
                } else
                        retval = -ENODATA;
-               up_write(&usb_bus_type.subsys.rwsem);
                break;
 
        /* let kernel drivers try to (re)bind to the interface */
@@ -1367,7 +1365,6 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
 
        /* talk directly to the interface's driver */
        default:
-               down_read(&usb_bus_type.subsys.rwsem);
                if (intf->dev.driver)
                        driver = to_usb_driver(intf->dev.driver);
                if (driver == NULL || driver->ioctl == NULL) {
@@ -1377,7 +1374,6 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
                        if (retval == -ENOIOCTLCMD)
                                retval = -ENOTTY;
                }
-               up_read(&usb_bus_type.subsys.rwsem);
        }
 
        /* cleanup and return */
@@ -1579,7 +1575,7 @@ static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wai
        return mask;
 }
 
-const struct file_operations usbfs_device_file_operations = {
+const struct file_operations usbdev_file_operations = {
        .llseek =       usbdev_lseek,
        .read =         usbdev_read,
        .poll =         usbdev_poll,
@@ -1588,50 +1584,53 @@ const struct file_operations usbfs_device_file_operations = {
        .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);
 
-       dev->class_dev = class_device_create(usb_device_class, NULL,
-                               MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev,
+       dev->usb_classdev = device_create(usb_classdev_class, &dev->dev,
+                               MKDEV(USB_DEVICE_MAJOR, minor),
                                "usbdev%d.%d", dev->bus->busnum, dev->devnum);
-       if (IS_ERR(dev->class_dev))
-               return PTR_ERR(dev->class_dev);
+       if (IS_ERR(dev->usb_classdev))
+               return PTR_ERR(dev->usb_classdev);
 
-       dev->class_dev->class_data = dev;
        return 0;
 }
 
-static void usbdev_remove(struct usb_device *dev)
+static void usb_classdev_remove(struct usb_device *dev)
 {
-       class_device_unregister(dev->class_dev);
+       device_unregister(dev->usb_classdev);
 }
 
-static int usbdev_notify(struct notifier_block *self, unsigned long action,
-                        void *dev)
+static int usb_classdev_notify(struct notifier_block *self,
+                              unsigned long action, void *dev)
 {
        switch (action) {
        case USB_DEVICE_ADD:
-               if (usbdev_add(dev))
+               if (usb_classdev_add(dev))
                        return NOTIFY_BAD;
                break;
        case USB_DEVICE_REMOVE:
-               usbdev_remove(dev);
+               usb_classdev_remove(dev);
                break;
        }
        return NOTIFY_OK;
 }
 
 static struct notifier_block usbdev_nb = {
-       .notifier_call =        usbdev_notify,
+       .notifier_call =        usb_classdev_notify,
 };
+#endif
 
 static struct cdev usb_device_cdev = {
        .kobj   = {.name = "usb_device", },
        .owner  = THIS_MODULE,
 };
 
-int __init usbdev_init(void)
+int __init usb_devio_init(void)
 {
        int retval;
 
@@ -1641,38 +1640,38 @@ int __init usbdev_init(void)
                err("unable to register minors for usb_device");
                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);
        if (retval) {
                err("unable to get usb_device major %d", USB_DEVICE_MAJOR);
                goto error_cdev;
        }
-       usb_device_class = class_create(THIS_MODULE, "usb_device");
-       if (IS_ERR(usb_device_class)) {
+#ifdef CONFIG_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");
-               retval = PTR_ERR(usb_device_class);
-               goto error_class;
+               retval = PTR_ERR(usb_classdev_class);
+               cdev_del(&usb_device_cdev);
+               usb_classdev_class = NULL;
+               goto out;
        }
 
        usb_register_notify(&usbdev_nb);
-
+#endif
 out:
        return retval;
 
-error_class:
-       usb_device_class = NULL;
-       cdev_del(&usb_device_cdev);
-
 error_cdev:
        unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
        goto out;
 }
 
-void usbdev_cleanup(void)
+void usb_devio_cleanup(void)
 {
+#ifdef CONFIG_USB_DEVICE_CLASS
        usb_unregister_notify(&usbdev_nb);
-       class_destroy(usb_device_class);
+       class_destroy(usb_classdev_class);
+#endif
        cdev_del(&usb_device_cdev);
        unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
 }
-