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/usb.h> 14 #include "usb.h" 15 16 /* endpoint stuff */ 17 18 struct 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 26 struct 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) \ 35 static ssize_t show_ep_##field(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 } \ 42 static DEVICE_ATTR(field, S_IRUGO, show_ep_##field, NULL); 43 44 usb_ep_attr(bLength, "%02x\n") 45 usb_ep_attr(bEndpointAddress, "%02x\n") 46 usb_ep_attr(bmAttributes, "%02x\n") 47 usb_ep_attr(bInterval, "%02x\n") 48 49 static ssize_t show_ep_wMaxPacketSize(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 le16_to_cpu(ep->desc->wMaxPacketSize) & 0x07ff); 55 } 56 static DEVICE_ATTR(wMaxPacketSize, S_IRUGO, show_ep_wMaxPacketSize, NULL); 57 58 static ssize_t show_ep_type(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 (ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { 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 } 80 static DEVICE_ATTR(type, S_IRUGO, show_ep_type, NULL); 81 82 static ssize_t show_ep_interval(struct device *dev, 83 struct device_attribute *attr, 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 (ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { 93 case USB_ENDPOINT_XFER_CONTROL: 94 if (ep->udev->speed == USB_SPEED_HIGH) /* uframes per NAK */ 95 interval = ep->desc->bInterval; 96 break; 97 case USB_ENDPOINT_XFER_ISOC: 98 interval = 1 << (ep->desc->bInterval - 1); 99 break; 100 case USB_ENDPOINT_XFER_BULK: 101 if (ep->udev->speed == USB_SPEED_HIGH && !in) /* uframes per NAK */ 102 interval = ep->desc->bInterval; 103 break; 104 case USB_ENDPOINT_XFER_INT: 105 if (ep->udev->speed == USB_SPEED_HIGH) 106 interval = 1 << (ep->desc->bInterval - 1); 107 else 108 interval = ep->desc->bInterval; 109 break; 110 } 111 interval *= (ep->udev->speed == USB_SPEED_HIGH) ? 125 : 1000; 112 if (interval % 1000) 113 unit = 'u'; 114 else { 115 unit = 'm'; 116 interval /= 1000; 117 } 118 119 return sprintf(buf, "%d%cs\n", interval, unit); 120 } 121 static DEVICE_ATTR(interval, S_IRUGO, show_ep_interval, NULL); 122 123 static ssize_t show_ep_direction(struct device *dev, 124 struct device_attribute *attr, char *buf) 125 { 126 struct ep_device *ep = to_ep_device(dev); 127 char *direction; 128 129 if ((ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == 130 USB_ENDPOINT_XFER_CONTROL) 131 direction = "both"; 132 else if (ep->desc->bEndpointAddress & USB_DIR_IN) 133 direction = "in"; 134 else 135 direction = "out"; 136 return sprintf(buf, "%s\n", direction); 137 } 138 static DEVICE_ATTR(direction, S_IRUGO, show_ep_direction, NULL); 139 140 static struct attribute *ep_dev_attrs[] = { 141 &dev_attr_bLength.attr, 142 &dev_attr_bEndpointAddress.attr, 143 &dev_attr_bmAttributes.attr, 144 &dev_attr_bInterval.attr, 145 &dev_attr_wMaxPacketSize.attr, 146 &dev_attr_interval.attr, 147 &dev_attr_type.attr, 148 &dev_attr_direction.attr, 149 NULL, 150 }; 151 static struct attribute_group ep_dev_attr_grp = { 152 .attrs = ep_dev_attrs, 153 }; 154 155 static struct endpoint_class { 156 struct kref kref; 157 struct class *class; 158 } *ep_class; 159 160 static int init_endpoint_class(void) 161 { 162 int result = 0; 163 164 if (ep_class != NULL) { 165 kref_get(&ep_class->kref); 166 goto exit; 167 } 168 169 ep_class = kmalloc(sizeof(*ep_class), GFP_KERNEL); 170 if (!ep_class) { 171 result = -ENOMEM; 172 goto exit; 173 } 174 175 kref_init(&ep_class->kref); 176 ep_class->class = class_create(THIS_MODULE, "usb_endpoint"); 177 if (IS_ERR(ep_class->class)) { 178 result = IS_ERR(ep_class->class); 179 kfree(ep_class); 180 ep_class = NULL; 181 goto exit; 182 } 183 184 exit: 185 return result; 186 } 187 188 static void release_endpoint_class(struct kref *kref) 189 { 190 /* Ok, we cheat as we know we only have one ep_class */ 191 class_destroy(ep_class->class); 192 kfree(ep_class); 193 ep_class = NULL; 194 } 195 196 static void destroy_endpoint_class(void) 197 { 198 if (ep_class) 199 kref_put(&ep_class->kref, release_endpoint_class); 200 } 201 202 static void ep_device_release(struct device *dev) 203 { 204 struct ep_device *ep_dev = to_ep_device(dev); 205 206 dev_dbg(dev, "%s called for %s\n", __FUNCTION__, dev->bus_id); 207 kfree(ep_dev); 208 } 209 210 void usb_create_ep_files(struct device *parent, 211 struct usb_host_endpoint *endpoint, 212 struct usb_device *udev) 213 { 214 char name[8]; 215 struct ep_device *ep_dev; 216 int minor; 217 int retval; 218 219 retval = init_endpoint_class(); 220 if (retval) 221 goto exit; 222 223 ep_dev = kzalloc(sizeof(*ep_dev), GFP_KERNEL); 224 if (!ep_dev) { 225 retval = -ENOMEM; 226 goto exit; 227 } 228 229 /* fun calculation to determine the minor of this endpoint */ 230 minor = (((udev->bus->busnum - 1) * 128) * 16) + (udev->devnum - 1); 231 232 ep_dev->desc = &endpoint->desc; 233 ep_dev->udev = udev; 234 ep_dev->dev.devt = MKDEV(442, minor); // FIXME fake number... 235 ep_dev->dev.class = ep_class->class; 236 ep_dev->dev.parent = parent; 237 ep_dev->dev.release = ep_device_release; 238 snprintf(ep_dev->dev.bus_id, BUS_ID_SIZE, "usbdev%d.%d_ep%02x", 239 udev->bus->busnum, udev->devnum, 240 endpoint->desc.bEndpointAddress); 241 242 retval = device_register(&ep_dev->dev); 243 if (retval) 244 goto error; 245 sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp); 246 247 endpoint->ep_dev = ep_dev; 248 249 /* create the symlink to the old-style "ep_XX" directory */ 250 sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress); 251 sysfs_create_link(&parent->kobj, &endpoint->ep_dev->dev.kobj, name); 252 253 exit: 254 return; 255 error: 256 kfree(ep_dev); 257 return; 258 } 259 260 void usb_remove_ep_files(struct usb_host_endpoint *endpoint) 261 { 262 263 if (endpoint->ep_dev) { 264 char name[8]; 265 266 sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress); 267 sysfs_remove_link(&endpoint->ep_dev->dev.parent->kobj, name); 268 sysfs_remove_group(&endpoint->ep_dev->dev.kobj, &ep_dev_attr_grp); 269 device_unregister(&endpoint->ep_dev->dev); 270 endpoint->ep_dev = NULL; 271 } 272 destroy_endpoint_class(); 273 } 274 275 276