diff options
Diffstat (limited to 'drivers/usb/core/endpoint.c')
| -rw-r--r-- | drivers/usb/core/endpoint.c | 172 |
1 files changed, 57 insertions, 115 deletions
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c index 247b5a4913a..39a24021fe4 100644 --- a/drivers/usb/core/endpoint.c +++ b/drivers/usb/core/endpoint.c @@ -10,11 +10,11 @@ */ #include <linux/kernel.h> +#include <linux/spinlock.h> +#include <linux/slab.h> #include <linux/usb.h> #include "usb.h" -/* endpoint stuff */ - struct ep_device { struct usb_endpoint_descriptor *desc; struct usb_device *udev; @@ -32,36 +32,36 @@ struct ep_attribute { container_of(_attr, struct ep_attribute, attr) #define usb_ep_attr(field, format_string) \ -static ssize_t show_ep_##field(struct device *dev, \ +static ssize_t field##_show(struct device *dev, \ struct device_attribute *attr, \ char *buf) \ { \ struct ep_device *ep = to_ep_device(dev); \ return sprintf(buf, format_string, ep->desc->field); \ } \ -static DEVICE_ATTR(field, S_IRUGO, show_ep_##field, NULL); +static DEVICE_ATTR_RO(field) -usb_ep_attr(bLength, "%02x\n") -usb_ep_attr(bEndpointAddress, "%02x\n") -usb_ep_attr(bmAttributes, "%02x\n") -usb_ep_attr(bInterval, "%02x\n") +usb_ep_attr(bLength, "%02x\n"); +usb_ep_attr(bEndpointAddress, "%02x\n"); +usb_ep_attr(bmAttributes, "%02x\n"); +usb_ep_attr(bInterval, "%02x\n"); -static ssize_t show_ep_wMaxPacketSize(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t wMaxPacketSize_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct ep_device *ep = to_ep_device(dev); return sprintf(buf, "%04x\n", - le16_to_cpu(ep->desc->wMaxPacketSize) & 0x07ff); + usb_endpoint_maxp(ep->desc) & 0x07ff); } -static DEVICE_ATTR(wMaxPacketSize, S_IRUGO, show_ep_wMaxPacketSize, NULL); +static DEVICE_ATTR_RO(wMaxPacketSize); -static ssize_t show_ep_type(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t type_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct ep_device *ep = to_ep_device(dev); char *type = "unknown"; - switch (ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + switch (usb_endpoint_type(ep->desc)) { case USB_ENDPOINT_XFER_CONTROL: type = "Control"; break; @@ -77,10 +77,10 @@ static ssize_t show_ep_type(struct device *dev, struct device_attribute *attr, } return sprintf(buf, "%s\n", type); } -static DEVICE_ATTR(type, S_IRUGO, show_ep_type, NULL); +static DEVICE_ATTR_RO(type); -static ssize_t show_ep_interval(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t interval_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct ep_device *ep = to_ep_device(dev); char unit; @@ -89,18 +89,23 @@ static ssize_t show_ep_interval(struct device *dev, in = (ep->desc->bEndpointAddress & USB_DIR_IN); - switch (ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + switch (usb_endpoint_type(ep->desc)) { case USB_ENDPOINT_XFER_CONTROL: - if (ep->udev->speed == USB_SPEED_HIGH) /* uframes per NAK */ + if (ep->udev->speed == USB_SPEED_HIGH) + /* uframes per NAK */ interval = ep->desc->bInterval; break; + case USB_ENDPOINT_XFER_ISOC: interval = 1 << (ep->desc->bInterval - 1); break; + case USB_ENDPOINT_XFER_BULK: - if (ep->udev->speed == USB_SPEED_HIGH && !in) /* uframes per NAK */ + if (ep->udev->speed == USB_SPEED_HIGH && !in) + /* uframes per NAK */ interval = ep->desc->bInterval; break; + case USB_ENDPOINT_XFER_INT: if (ep->udev->speed == USB_SPEED_HIGH) interval = 1 << (ep->desc->bInterval - 1); @@ -118,24 +123,23 @@ static ssize_t show_ep_interval(struct device *dev, return sprintf(buf, "%d%cs\n", interval, unit); } -static DEVICE_ATTR(interval, S_IRUGO, show_ep_interval, NULL); +static DEVICE_ATTR_RO(interval); -static ssize_t show_ep_direction(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t direction_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct ep_device *ep = to_ep_device(dev); char *direction; - if ((ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_CONTROL) + if (usb_endpoint_xfer_control(ep->desc)) direction = "both"; - else if (ep->desc->bEndpointAddress & USB_DIR_IN) + else if (usb_endpoint_dir_in(ep->desc)) direction = "in"; else direction = "out"; return sprintf(buf, "%s\n", direction); } -static DEVICE_ATTR(direction, S_IRUGO, show_ep_direction, NULL); +static DEVICE_ATTR_RO(direction); static struct attribute *ep_dev_attrs[] = { &dev_attr_bLength.attr, @@ -151,125 +155,63 @@ static struct attribute *ep_dev_attrs[] = { static struct attribute_group ep_dev_attr_grp = { .attrs = ep_dev_attrs, }; - -static struct endpoint_class { - struct kref kref; - struct class *class; -} *ep_class; - -static int init_endpoint_class(void) -{ - int result = 0; - - if (ep_class != NULL) { - kref_get(&ep_class->kref); - goto exit; - } - - ep_class = kmalloc(sizeof(*ep_class), GFP_KERNEL); - if (!ep_class) { - result = -ENOMEM; - goto exit; - } - - kref_init(&ep_class->kref); - ep_class->class = class_create(THIS_MODULE, "usb_endpoint"); - if (IS_ERR(ep_class->class)) { - result = IS_ERR(ep_class->class); - kfree(ep_class); - ep_class = NULL; - goto exit; - } - -exit: - return result; -} - -static void release_endpoint_class(struct kref *kref) -{ - /* Ok, we cheat as we know we only have one ep_class */ - class_destroy(ep_class->class); - kfree(ep_class); - ep_class = NULL; -} - -static void destroy_endpoint_class(void) -{ - if (ep_class) - kref_put(&ep_class->kref, release_endpoint_class); -} +static const struct attribute_group *ep_dev_groups[] = { + &ep_dev_attr_grp, + NULL +}; static void ep_device_release(struct device *dev) { struct ep_device *ep_dev = to_ep_device(dev); - dev_dbg(dev, "%s called for %s\n", __FUNCTION__, dev->bus_id); kfree(ep_dev); } -void usb_create_ep_files(struct device *parent, - struct usb_host_endpoint *endpoint, - struct usb_device *udev) +struct device_type usb_ep_device_type = { + .name = "usb_endpoint", + .release = ep_device_release, +}; + +int usb_create_ep_devs(struct device *parent, + struct usb_host_endpoint *endpoint, + struct usb_device *udev) { - char name[8]; struct ep_device *ep_dev; - int minor; int retval; - retval = init_endpoint_class(); - if (retval) - goto exit; - ep_dev = kzalloc(sizeof(*ep_dev), GFP_KERNEL); if (!ep_dev) { retval = -ENOMEM; goto exit; } - /* fun calculation to determine the minor of this endpoint */ - minor = (((udev->bus->busnum - 1) * 128) * 16) + (udev->devnum - 1); - ep_dev->desc = &endpoint->desc; ep_dev->udev = udev; - ep_dev->dev.devt = MKDEV(442, minor); // FIXME fake number... - ep_dev->dev.class = ep_class->class; + ep_dev->dev.groups = ep_dev_groups; + ep_dev->dev.type = &usb_ep_device_type; ep_dev->dev.parent = parent; - ep_dev->dev.release = ep_device_release; - snprintf(ep_dev->dev.bus_id, BUS_ID_SIZE, "usbdev%d.%d_ep%02x", - udev->bus->busnum, udev->devnum, - endpoint->desc.bEndpointAddress); + dev_set_name(&ep_dev->dev, "ep_%02x", endpoint->desc.bEndpointAddress); retval = device_register(&ep_dev->dev); if (retval) - goto error; - sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp); + goto error_register; + device_enable_async_suspend(&ep_dev->dev); endpoint->ep_dev = ep_dev; + return retval; - /* create the symlink to the old-style "ep_XX" directory */ - sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress); - sysfs_create_link(&parent->kobj, &endpoint->ep_dev->dev.kobj, name); - +error_register: + put_device(&ep_dev->dev); exit: - return; -error: - kfree(ep_dev); - return; + return retval; } -void usb_remove_ep_files(struct usb_host_endpoint *endpoint) +void usb_remove_ep_devs(struct usb_host_endpoint *endpoint) { + struct ep_device *ep_dev = endpoint->ep_dev; - if (endpoint->ep_dev) { - char name[8]; - - sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress); - sysfs_remove_link(&endpoint->ep_dev->dev.parent->kobj, name); - sysfs_remove_group(&endpoint->ep_dev->dev.kobj, &ep_dev_attr_grp); - device_unregister(&endpoint->ep_dev->dev); + if (ep_dev) { + device_unregister(&ep_dev->dev); endpoint->ep_dev = NULL; } - destroy_endpoint_class(); } - - |
