endpoint.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  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. #include <linux/kernel.h>
  12. #include <linux/usb.h>
  13. #include "usb.h"
  14. /* endpoint stuff */
  15. struct ep_device {
  16. struct usb_endpoint_descriptor *desc;
  17. struct usb_device *udev;
  18. struct device dev;
  19. };
  20. #define to_ep_device(_dev) \
  21. container_of(_dev, struct ep_device, dev)
  22. struct ep_attribute {
  23. struct attribute attr;
  24. ssize_t (*show)(struct usb_device *,
  25. struct usb_endpoint_descriptor *, char *);
  26. };
  27. #define to_ep_attribute(_attr) \
  28. container_of(_attr, struct ep_attribute, attr)
  29. #define usb_ep_attr(field, format_string) \
  30. static ssize_t show_ep_##field(struct device *dev, \
  31. struct device_attribute *attr, \
  32. char *buf) \
  33. { \
  34. struct ep_device *ep = to_ep_device(dev); \
  35. return sprintf(buf, format_string, ep->desc->field); \
  36. } \
  37. static DEVICE_ATTR(field, S_IRUGO, show_ep_##field, NULL);
  38. usb_ep_attr(bLength, "%02x\n")
  39. usb_ep_attr(bEndpointAddress, "%02x\n")
  40. usb_ep_attr(bmAttributes, "%02x\n")
  41. usb_ep_attr(bInterval, "%02x\n")
  42. static ssize_t show_ep_wMaxPacketSize(struct device *dev,
  43. struct device_attribute *attr, char *buf)
  44. {
  45. struct ep_device *ep = to_ep_device(dev);
  46. return sprintf(buf, "%04x\n",
  47. le16_to_cpu(ep->desc->wMaxPacketSize) & 0x07ff);
  48. }
  49. static DEVICE_ATTR(wMaxPacketSize, S_IRUGO, show_ep_wMaxPacketSize, NULL);
  50. static ssize_t show_ep_type(struct device *dev, struct device_attribute *attr,
  51. char *buf)
  52. {
  53. struct ep_device *ep = to_ep_device(dev);
  54. char *type = "unknown";
  55. switch (ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
  56. case USB_ENDPOINT_XFER_CONTROL:
  57. type = "Control";
  58. break;
  59. case USB_ENDPOINT_XFER_ISOC:
  60. type = "Isoc";
  61. break;
  62. case USB_ENDPOINT_XFER_BULK:
  63. type = "Bulk";
  64. break;
  65. case USB_ENDPOINT_XFER_INT:
  66. type = "Interrupt";
  67. break;
  68. }
  69. return sprintf(buf, "%s\n", type);
  70. }
  71. static DEVICE_ATTR(type, S_IRUGO, show_ep_type, NULL);
  72. static ssize_t show_ep_interval(struct device *dev,
  73. struct device_attribute *attr, char *buf)
  74. {
  75. struct ep_device *ep = to_ep_device(dev);
  76. char unit;
  77. unsigned interval = 0;
  78. unsigned in;
  79. in = (ep->desc->bEndpointAddress & USB_DIR_IN);
  80. switch (ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
  81. case USB_ENDPOINT_XFER_CONTROL:
  82. if (ep->udev->speed == USB_SPEED_HIGH) /* uframes per NAK */
  83. interval = ep->desc->bInterval;
  84. break;
  85. case USB_ENDPOINT_XFER_ISOC:
  86. interval = 1 << (ep->desc->bInterval - 1);
  87. break;
  88. case USB_ENDPOINT_XFER_BULK:
  89. if (ep->udev->speed == USB_SPEED_HIGH && !in) /* uframes per NAK */
  90. interval = ep->desc->bInterval;
  91. break;
  92. case USB_ENDPOINT_XFER_INT:
  93. if (ep->udev->speed == USB_SPEED_HIGH)
  94. interval = 1 << (ep->desc->bInterval - 1);
  95. else
  96. interval = ep->desc->bInterval;
  97. break;
  98. }
  99. interval *= (ep->udev->speed == USB_SPEED_HIGH) ? 125 : 1000;
  100. if (interval % 1000)
  101. unit = 'u';
  102. else {
  103. unit = 'm';
  104. interval /= 1000;
  105. }
  106. return sprintf(buf, "%d%cs\n", interval, unit);
  107. }
  108. static DEVICE_ATTR(interval, S_IRUGO, show_ep_interval, NULL);
  109. static ssize_t show_ep_direction(struct device *dev,
  110. struct device_attribute *attr, char *buf)
  111. {
  112. struct ep_device *ep = to_ep_device(dev);
  113. char *direction;
  114. if ((ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
  115. USB_ENDPOINT_XFER_CONTROL)
  116. direction = "both";
  117. else if (ep->desc->bEndpointAddress & USB_DIR_IN)
  118. direction = "in";
  119. else
  120. direction = "out";
  121. return sprintf(buf, "%s\n", direction);
  122. }
  123. static DEVICE_ATTR(direction, S_IRUGO, show_ep_direction, NULL);
  124. static struct attribute *ep_dev_attrs[] = {
  125. &dev_attr_bLength.attr,
  126. &dev_attr_bEndpointAddress.attr,
  127. &dev_attr_bmAttributes.attr,
  128. &dev_attr_bInterval.attr,
  129. &dev_attr_wMaxPacketSize.attr,
  130. &dev_attr_interval.attr,
  131. &dev_attr_type.attr,
  132. &dev_attr_direction.attr,
  133. NULL,
  134. };
  135. static struct attribute_group ep_dev_attr_grp = {
  136. .attrs = ep_dev_attrs,
  137. };
  138. static struct endpoint_class {
  139. struct kref kref;
  140. struct class *class;
  141. } *ep_class;
  142. static int init_endpoint_class(void)
  143. {
  144. int result = 0;
  145. if (ep_class != NULL) {
  146. kref_get(&ep_class->kref);
  147. goto exit;
  148. }
  149. ep_class = kmalloc(sizeof(*ep_class), GFP_KERNEL);
  150. if (!ep_class) {
  151. result = -ENOMEM;
  152. goto exit;
  153. }
  154. kref_init(&ep_class->kref);
  155. ep_class->class = class_create(THIS_MODULE, "usb_endpoint");
  156. if (IS_ERR(ep_class->class)) {
  157. result = IS_ERR(ep_class->class);
  158. kfree(ep_class);
  159. ep_class = NULL;
  160. goto exit;
  161. }
  162. exit:
  163. return result;
  164. }
  165. static void release_endpoint_class(struct kref *kref)
  166. {
  167. /* Ok, we cheat as we know we only have one ep_class */
  168. class_destroy(ep_class->class);
  169. kfree(ep_class);
  170. ep_class = NULL;
  171. }
  172. static void destroy_endpoint_class(void)
  173. {
  174. if (ep_class)
  175. kref_put(&ep_class->kref, release_endpoint_class);
  176. }
  177. static void ep_device_release(struct device *dev)
  178. {
  179. struct ep_device *ep_dev = to_ep_device(dev);
  180. dev_dbg(dev, "%s called for %s\n", __FUNCTION__, dev->bus_id);
  181. kfree(ep_dev);
  182. }
  183. int usb_create_ep_files(struct device *parent,
  184. struct usb_host_endpoint *endpoint,
  185. struct usb_device *udev)
  186. {
  187. char name[8];
  188. struct ep_device *ep_dev;
  189. int minor;
  190. int retval;
  191. retval = init_endpoint_class();
  192. if (retval)
  193. goto exit;
  194. ep_dev = kzalloc(sizeof(*ep_dev), GFP_KERNEL);
  195. if (!ep_dev) {
  196. retval = -ENOMEM;
  197. goto exit;
  198. }
  199. /* fun calculation to determine the minor of this endpoint */
  200. minor = (((udev->bus->busnum - 1) * 128) * 16) + (udev->devnum - 1);
  201. ep_dev->desc = &endpoint->desc;
  202. ep_dev->udev = udev;
  203. ep_dev->dev.devt = MKDEV(442, minor); // FIXME fake number...
  204. ep_dev->dev.class = ep_class->class;
  205. ep_dev->dev.parent = parent;
  206. ep_dev->dev.release = ep_device_release;
  207. snprintf(ep_dev->dev.bus_id, BUS_ID_SIZE, "usbdev%d.%d_ep%02x",
  208. udev->bus->busnum, udev->devnum,
  209. endpoint->desc.bEndpointAddress);
  210. retval = device_register(&ep_dev->dev);
  211. if (retval)
  212. goto error;
  213. retval = sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
  214. if (retval)
  215. goto error_group;
  216. endpoint->ep_dev = ep_dev;
  217. /* create the symlink to the old-style "ep_XX" directory */
  218. sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress);
  219. retval = sysfs_create_link(&parent->kobj,
  220. &endpoint->ep_dev->dev.kobj, name);
  221. if (retval)
  222. goto error_link;
  223. exit:
  224. return retval;
  225. error_link:
  226. sysfs_remove_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
  227. error_group:
  228. device_unregister(&ep_dev->dev);
  229. endpoint->ep_dev = NULL;
  230. destroy_endpoint_class();
  231. return retval;
  232. error:
  233. kfree(ep_dev);
  234. destroy_endpoint_class();
  235. return retval;
  236. }
  237. void usb_remove_ep_files(struct usb_host_endpoint *endpoint)
  238. {
  239. if (endpoint->ep_dev) {
  240. char name[8];
  241. sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress);
  242. sysfs_remove_link(&endpoint->ep_dev->dev.parent->kobj, name);
  243. sysfs_remove_group(&endpoint->ep_dev->dev.kobj, &ep_dev_attr_grp);
  244. device_unregister(&endpoint->ep_dev->dev);
  245. endpoint->ep_dev = NULL;
  246. destroy_endpoint_class();
  247. }
  248. }