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