linux/drivers/usb/core/endpoint.c
<<
>>
Prefs
   1/*
   2 * drivers/usb/core/endpoint.c
   3 *
   4 * (C) Copyright 2002,2004,2006 Greg Kroah-Hartman
   5 * (C) Copyright 2002,2004 IBM Corp.
   6 * (C) Copyright 2006 Novell Inc.
   7 *
   8 * Endpoint sysfs stuff
   9 *
  10 */
  11
  12#include <linux/kernel.h>
  13#include <linux/spinlock.h>
  14#include <linux/slab.h>
  15#include <linux/idr.h>
  16#include <linux/usb.h>
  17#include "usb.h"
  18
  19struct ep_device {
  20        struct usb_endpoint_descriptor *desc;
  21        struct usb_device *udev;
  22        struct device dev;
  23};
  24#define to_ep_device(_dev) \
  25        container_of(_dev, struct ep_device, dev)
  26
  27struct ep_attribute {
  28        struct attribute attr;
  29        ssize_t (*show)(struct usb_device *,
  30                        struct usb_endpoint_descriptor *, char *);
  31};
  32#define to_ep_attribute(_attr) \
  33        container_of(_attr, struct ep_attribute, attr)
  34
  35#define usb_ep_attr(field, format_string)                       \
  36static ssize_t show_ep_##field(struct device *dev,              \
  37                               struct device_attribute *attr,   \
  38                               char *buf)                       \
  39{                                                               \
  40        struct ep_device *ep = to_ep_device(dev);               \
  41        return sprintf(buf, format_string, ep->desc->field);    \
  42}                                                               \
  43static DEVICE_ATTR(field, S_IRUGO, show_ep_##field, NULL);
  44
  45usb_ep_attr(bLength, "%02x\n")
  46usb_ep_attr(bEndpointAddress, "%02x\n")
  47usb_ep_attr(bmAttributes, "%02x\n")
  48usb_ep_attr(bInterval, "%02x\n")
  49
  50static ssize_t show_ep_wMaxPacketSize(struct device *dev,
  51                                      struct device_attribute *attr, char *buf)
  52{
  53        struct ep_device *ep = to_ep_device(dev);
  54        return sprintf(buf, "%04x\n",
  55                        usb_endpoint_maxp(ep->desc) & 0x07ff);
  56}
  57static DEVICE_ATTR(wMaxPacketSize, S_IRUGO, show_ep_wMaxPacketSize, NULL);
  58
  59static ssize_t show_ep_type(struct device *dev, struct device_attribute *attr,
  60                            char *buf)
  61{
  62        struct ep_device *ep = to_ep_device(dev);
  63        char *type = "unknown";
  64
  65        switch (usb_endpoint_type(ep->desc)) {
  66        case USB_ENDPOINT_XFER_CONTROL:
  67                type = "Control";
  68                break;
  69        case USB_ENDPOINT_XFER_ISOC:
  70                type = "Isoc";
  71                break;
  72        case USB_ENDPOINT_XFER_BULK:
  73                type = "Bulk";
  74                break;
  75        case USB_ENDPOINT_XFER_INT:
  76                type = "Interrupt";
  77                break;
  78        }
  79        return sprintf(buf, "%s\n", type);
  80}
  81static DEVICE_ATTR(type, S_IRUGO, show_ep_type, NULL);
  82
  83static ssize_t show_ep_interval(struct device *dev,
  84                                struct device_attribute *attr, char *buf)
  85{
  86        struct ep_device *ep = to_ep_device(dev);
  87        char unit;
  88        unsigned interval = 0;
  89        unsigned in;
  90
  91        in = (ep->desc->bEndpointAddress & USB_DIR_IN);
  92
  93        switch (usb_endpoint_type(ep->desc)) {
  94        case USB_ENDPOINT_XFER_CONTROL:
  95                if (ep->udev->speed == USB_SPEED_HIGH)
  96                        /* uframes per NAK */
  97                        interval = ep->desc->bInterval;
  98                break;
  99
 100        case USB_ENDPOINT_XFER_ISOC:
 101                interval = 1 << (ep->desc->bInterval - 1);
 102                break;
 103
 104        case USB_ENDPOINT_XFER_BULK:
 105                if (ep->udev->speed == USB_SPEED_HIGH && !in)
 106                        /* uframes per NAK */
 107                        interval = ep->desc->bInterval;
 108                break;
 109
 110        case USB_ENDPOINT_XFER_INT:
 111                if (ep->udev->speed == USB_SPEED_HIGH)
 112                        interval = 1 << (ep->desc->bInterval - 1);
 113                else
 114                        interval = ep->desc->bInterval;
 115                break;
 116        }
 117        interval *= (ep->udev->speed == USB_SPEED_HIGH) ? 125 : 1000;
 118        if (interval % 1000)
 119                unit = 'u';
 120        else {
 121                unit = 'm';
 122                interval /= 1000;
 123        }
 124
 125        return sprintf(buf, "%d%cs\n", interval, unit);
 126}
 127static DEVICE_ATTR(interval, S_IRUGO, show_ep_interval, NULL);
 128
 129static ssize_t show_ep_direction(struct device *dev,
 130                                 struct device_attribute *attr, char *buf)
 131{
 132        struct ep_device *ep = to_ep_device(dev);
 133        char *direction;
 134
 135        if (usb_endpoint_xfer_control(ep->desc))
 136                direction = "both";
 137        else if (usb_endpoint_dir_in(ep->desc))
 138                direction = "in";
 139        else
 140                direction = "out";
 141        return sprintf(buf, "%s\n", direction);
 142}
 143static DEVICE_ATTR(direction, S_IRUGO, show_ep_direction, NULL);
 144
 145static struct attribute *ep_dev_attrs[] = {
 146        &dev_attr_bLength.attr,
 147        &dev_attr_bEndpointAddress.attr,
 148        &dev_attr_bmAttributes.attr,
 149        &dev_attr_bInterval.attr,
 150        &dev_attr_wMaxPacketSize.attr,
 151        &dev_attr_interval.attr,
 152        &dev_attr_type.attr,
 153        &dev_attr_direction.attr,
 154        NULL,
 155};
 156static struct attribute_group ep_dev_attr_grp = {
 157        .attrs = ep_dev_attrs,
 158};
 159static const struct attribute_group *ep_dev_groups[] = {
 160        &ep_dev_attr_grp,
 161        NULL
 162};
 163
 164static void ep_device_release(struct device *dev)
 165{
 166        struct ep_device *ep_dev = to_ep_device(dev);
 167
 168        kfree(ep_dev);
 169}
 170
 171struct device_type usb_ep_device_type = {
 172        .name =         "usb_endpoint",
 173        .release = ep_device_release,
 174};
 175
 176int usb_create_ep_devs(struct device *parent,
 177                        struct usb_host_endpoint *endpoint,
 178                        struct usb_device *udev)
 179{
 180        struct ep_device *ep_dev;
 181        int retval;
 182
 183        ep_dev = kzalloc(sizeof(*ep_dev), GFP_KERNEL);
 184        if (!ep_dev) {
 185                retval = -ENOMEM;
 186                goto exit;
 187        }
 188
 189        ep_dev->desc = &endpoint->desc;
 190        ep_dev->udev = udev;
 191        ep_dev->dev.groups = ep_dev_groups;
 192        ep_dev->dev.type = &usb_ep_device_type;
 193        ep_dev->dev.parent = parent;
 194        dev_set_name(&ep_dev->dev, "ep_%02x", endpoint->desc.bEndpointAddress);
 195
 196        retval = device_register(&ep_dev->dev);
 197        if (retval)
 198                goto error_register;
 199
 200        device_enable_async_suspend(&ep_dev->dev);
 201        endpoint->ep_dev = ep_dev;
 202        return retval;
 203
 204error_register:
 205        put_device(&ep_dev->dev);
 206exit:
 207        return retval;
 208}
 209
 210void usb_remove_ep_devs(struct usb_host_endpoint *endpoint)
 211{
 212        struct ep_device *ep_dev = endpoint->ep_dev;
 213
 214        if (ep_dev) {
 215                device_unregister(&ep_dev->dev);
 216                endpoint->ep_dev = NULL;
 217        }
 218}
 219