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