diff options
Diffstat (limited to 'drivers/usb/core/sysfs.c')
-rw-r--r-- | drivers/usb/core/sysfs.c | 319 |
1 files changed, 268 insertions, 51 deletions
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 00297f113849..edd83e014452 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c | |||
@@ -22,9 +22,207 @@ | |||
22 | 22 | ||
23 | #include "usb.h" | 23 | #include "usb.h" |
24 | 24 | ||
25 | /* endpoint stuff */ | ||
26 | struct ep_object { | ||
27 | struct usb_endpoint_descriptor *desc; | ||
28 | struct usb_device *udev; | ||
29 | struct kobject kobj; | ||
30 | }; | ||
31 | #define to_ep_object(_kobj) \ | ||
32 | container_of(_kobj, struct ep_object, kobj) | ||
33 | |||
34 | struct ep_attribute { | ||
35 | struct attribute attr; | ||
36 | ssize_t (*show)(struct usb_device *, | ||
37 | struct usb_endpoint_descriptor *, char *); | ||
38 | }; | ||
39 | #define to_ep_attribute(_attr) \ | ||
40 | container_of(_attr, struct ep_attribute, attr) | ||
41 | |||
42 | #define EP_ATTR(_name) \ | ||
43 | struct ep_attribute ep_##_name = { \ | ||
44 | .attr = {.name = #_name, .owner = THIS_MODULE, \ | ||
45 | .mode = S_IRUGO}, \ | ||
46 | .show = show_ep_##_name} | ||
47 | |||
48 | #define usb_ep_attr(field, format_string) \ | ||
49 | static ssize_t show_ep_##field(struct usb_device *udev, \ | ||
50 | struct usb_endpoint_descriptor *desc, \ | ||
51 | char *buf) \ | ||
52 | { \ | ||
53 | return sprintf(buf, format_string, desc->field); \ | ||
54 | } \ | ||
55 | static EP_ATTR(field); | ||
56 | |||
57 | usb_ep_attr(bLength, "%02x\n") | ||
58 | usb_ep_attr(bEndpointAddress, "%02x\n") | ||
59 | usb_ep_attr(bmAttributes, "%02x\n") | ||
60 | usb_ep_attr(bInterval, "%02x\n") | ||
61 | |||
62 | static ssize_t show_ep_wMaxPacketSize(struct usb_device *udev, | ||
63 | struct usb_endpoint_descriptor *desc, char *buf) | ||
64 | { | ||
65 | return sprintf(buf, "%04x\n", | ||
66 | le16_to_cpu(desc->wMaxPacketSize) & 0x07ff); | ||
67 | } | ||
68 | static EP_ATTR(wMaxPacketSize); | ||
69 | |||
70 | static ssize_t show_ep_type(struct usb_device *udev, | ||
71 | struct usb_endpoint_descriptor *desc, char *buf) | ||
72 | { | ||
73 | char *type = "unknown"; | ||
74 | |||
75 | switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { | ||
76 | case USB_ENDPOINT_XFER_CONTROL: | ||
77 | type = "Control"; | ||
78 | break; | ||
79 | case USB_ENDPOINT_XFER_ISOC: | ||
80 | type = "Isoc"; | ||
81 | break; | ||
82 | case USB_ENDPOINT_XFER_BULK: | ||
83 | type = "Bulk"; | ||
84 | break; | ||
85 | case USB_ENDPOINT_XFER_INT: | ||
86 | type = "Interrupt"; | ||
87 | break; | ||
88 | } | ||
89 | return sprintf(buf, "%s\n", type); | ||
90 | } | ||
91 | static EP_ATTR(type); | ||
92 | |||
93 | static ssize_t show_ep_interval(struct usb_device *udev, | ||
94 | struct usb_endpoint_descriptor *desc, char *buf) | ||
95 | { | ||
96 | char unit; | ||
97 | unsigned interval = 0; | ||
98 | unsigned in; | ||
99 | |||
100 | in = (desc->bEndpointAddress & USB_DIR_IN); | ||
101 | |||
102 | switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { | ||
103 | case USB_ENDPOINT_XFER_CONTROL: | ||
104 | if (udev->speed == USB_SPEED_HIGH) /* uframes per NAK */ | ||
105 | interval = desc->bInterval; | ||
106 | break; | ||
107 | case USB_ENDPOINT_XFER_ISOC: | ||
108 | interval = 1 << (desc->bInterval - 1); | ||
109 | break; | ||
110 | case USB_ENDPOINT_XFER_BULK: | ||
111 | if (udev->speed == USB_SPEED_HIGH && !in) /* uframes per NAK */ | ||
112 | interval = desc->bInterval; | ||
113 | break; | ||
114 | case USB_ENDPOINT_XFER_INT: | ||
115 | if (udev->speed == USB_SPEED_HIGH) | ||
116 | interval = 1 << (desc->bInterval - 1); | ||
117 | else | ||
118 | interval = desc->bInterval; | ||
119 | break; | ||
120 | } | ||
121 | interval *= (udev->speed == USB_SPEED_HIGH) ? 125 : 1000; | ||
122 | if (interval % 1000) | ||
123 | unit = 'u'; | ||
124 | else { | ||
125 | unit = 'm'; | ||
126 | interval /= 1000; | ||
127 | } | ||
128 | |||
129 | return sprintf(buf, "%d%cs\n", interval, unit); | ||
130 | } | ||
131 | static EP_ATTR(interval); | ||
132 | |||
133 | static ssize_t show_ep_direction(struct usb_device *udev, | ||
134 | struct usb_endpoint_descriptor *desc, char *buf) | ||
135 | { | ||
136 | char *direction; | ||
137 | |||
138 | if ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == | ||
139 | USB_ENDPOINT_XFER_CONTROL) | ||
140 | direction = "both"; | ||
141 | else if (desc->bEndpointAddress & USB_DIR_IN) | ||
142 | direction = "in"; | ||
143 | else | ||
144 | direction = "out"; | ||
145 | return sprintf(buf, "%s\n", direction); | ||
146 | } | ||
147 | static EP_ATTR(direction); | ||
148 | |||
149 | static struct attribute *ep_attrs[] = { | ||
150 | &ep_bLength.attr, | ||
151 | &ep_bEndpointAddress.attr, | ||
152 | &ep_bmAttributes.attr, | ||
153 | &ep_bInterval.attr, | ||
154 | &ep_wMaxPacketSize.attr, | ||
155 | &ep_type.attr, | ||
156 | &ep_interval.attr, | ||
157 | &ep_direction.attr, | ||
158 | NULL, | ||
159 | }; | ||
160 | |||
161 | static void ep_object_release(struct kobject *kobj) | ||
162 | { | ||
163 | kfree(to_ep_object(kobj)); | ||
164 | } | ||
165 | |||
166 | static ssize_t ep_object_show(struct kobject *kobj, struct attribute *attr, | ||
167 | char *buf) | ||
168 | { | ||
169 | struct ep_object *ep_obj = to_ep_object(kobj); | ||
170 | struct ep_attribute *ep_attr = to_ep_attribute(attr); | ||
171 | |||
172 | return (ep_attr->show)(ep_obj->udev, ep_obj->desc, buf); | ||
173 | } | ||
174 | |||
175 | static struct sysfs_ops ep_object_sysfs_ops = { | ||
176 | .show = ep_object_show, | ||
177 | }; | ||
178 | |||
179 | static struct kobj_type ep_object_ktype = { | ||
180 | .release = ep_object_release, | ||
181 | .sysfs_ops = &ep_object_sysfs_ops, | ||
182 | .default_attrs = ep_attrs, | ||
183 | }; | ||
184 | |||
185 | static void usb_create_ep_files(struct kobject *parent, | ||
186 | struct usb_host_endpoint *endpoint, | ||
187 | struct usb_device *udev) | ||
188 | { | ||
189 | struct ep_object *ep_obj; | ||
190 | struct kobject *kobj; | ||
191 | |||
192 | ep_obj = kzalloc(sizeof(struct ep_object), GFP_KERNEL); | ||
193 | if (!ep_obj) | ||
194 | return; | ||
195 | |||
196 | ep_obj->desc = &endpoint->desc; | ||
197 | ep_obj->udev = udev; | ||
198 | |||
199 | kobj = &ep_obj->kobj; | ||
200 | kobject_set_name(kobj, "ep_%02x", endpoint->desc.bEndpointAddress); | ||
201 | kobj->parent = parent; | ||
202 | kobj->ktype = &ep_object_ktype; | ||
203 | |||
204 | /* Don't use kobject_register, because it generates a hotplug event */ | ||
205 | kobject_init(kobj); | ||
206 | if (kobject_add(kobj) == 0) | ||
207 | endpoint->kobj = kobj; | ||
208 | else | ||
209 | kobject_put(kobj); | ||
210 | } | ||
211 | |||
212 | static void usb_remove_ep_files(struct usb_host_endpoint *endpoint) | ||
213 | { | ||
214 | |||
215 | if (endpoint->kobj) { | ||
216 | kobject_del(endpoint->kobj); | ||
217 | kobject_put(endpoint->kobj); | ||
218 | endpoint->kobj = NULL; | ||
219 | } | ||
220 | } | ||
221 | |||
25 | /* Active configuration fields */ | 222 | /* Active configuration fields */ |
26 | #define usb_actconfig_show(field, multiplier, format_string) \ | 223 | #define usb_actconfig_show(field, multiplier, format_string) \ |
27 | static ssize_t show_##field (struct device *dev, struct device_attribute *attr, char *buf) \ | 224 | static ssize_t show_##field (struct device *dev, \ |
225 | struct device_attribute *attr, char *buf) \ | ||
28 | { \ | 226 | { \ |
29 | struct usb_device *udev; \ | 227 | struct usb_device *udev; \ |
30 | struct usb_host_config *actconfig; \ | 228 | struct usb_host_config *actconfig; \ |
@@ -46,22 +244,17 @@ usb_actconfig_attr (bNumInterfaces, 1, "%2d\n") | |||
46 | usb_actconfig_attr (bmAttributes, 1, "%2x\n") | 244 | usb_actconfig_attr (bmAttributes, 1, "%2x\n") |
47 | usb_actconfig_attr (bMaxPower, 2, "%3dmA\n") | 245 | usb_actconfig_attr (bMaxPower, 2, "%3dmA\n") |
48 | 246 | ||
49 | static ssize_t show_configuration_string(struct device *dev, struct device_attribute *attr, char *buf) | 247 | static ssize_t show_configuration_string(struct device *dev, |
248 | struct device_attribute *attr, char *buf) | ||
50 | { | 249 | { |
51 | struct usb_device *udev; | 250 | struct usb_device *udev; |
52 | struct usb_host_config *actconfig; | 251 | struct usb_host_config *actconfig; |
53 | int len; | ||
54 | 252 | ||
55 | udev = to_usb_device (dev); | 253 | udev = to_usb_device (dev); |
56 | actconfig = udev->actconfig; | 254 | actconfig = udev->actconfig; |
57 | if ((!actconfig) || (!actconfig->string)) | 255 | if ((!actconfig) || (!actconfig->string)) |
58 | return 0; | 256 | return 0; |
59 | len = sprintf(buf, actconfig->string, PAGE_SIZE); | 257 | return sprintf(buf, "%s\n", actconfig->string); |
60 | if (len < 0) | ||
61 | return 0; | ||
62 | buf[len] = '\n'; | ||
63 | buf[len+1] = 0; | ||
64 | return len+1; | ||
65 | } | 258 | } |
66 | static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL); | 259 | static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL); |
67 | 260 | ||
@@ -69,7 +262,8 @@ static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL); | |||
69 | usb_actconfig_show(bConfigurationValue, 1, "%u\n"); | 262 | usb_actconfig_show(bConfigurationValue, 1, "%u\n"); |
70 | 263 | ||
71 | static ssize_t | 264 | static ssize_t |
72 | set_bConfigurationValue (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 265 | set_bConfigurationValue (struct device *dev, struct device_attribute *attr, |
266 | const char *buf, size_t count) | ||
73 | { | 267 | { |
74 | struct usb_device *udev = udev = to_usb_device (dev); | 268 | struct usb_device *udev = udev = to_usb_device (dev); |
75 | int config, value; | 269 | int config, value; |
@@ -87,18 +281,13 @@ static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR, | |||
87 | 281 | ||
88 | /* String fields */ | 282 | /* String fields */ |
89 | #define usb_string_attr(name) \ | 283 | #define usb_string_attr(name) \ |
90 | static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \ | 284 | static ssize_t show_##name(struct device *dev, \ |
285 | struct device_attribute *attr, char *buf) \ | ||
91 | { \ | 286 | { \ |
92 | struct usb_device *udev; \ | 287 | struct usb_device *udev; \ |
93 | int len; \ | ||
94 | \ | 288 | \ |
95 | udev = to_usb_device (dev); \ | 289 | udev = to_usb_device (dev); \ |
96 | len = snprintf(buf, 256, "%s", udev->name); \ | 290 | return sprintf(buf, "%s\n", udev->name); \ |
97 | if (len < 0) \ | ||
98 | return 0; \ | ||
99 | buf[len] = '\n'; \ | ||
100 | buf[len+1] = 0; \ | ||
101 | return len+1; \ | ||
102 | } \ | 291 | } \ |
103 | static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); | 292 | static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); |
104 | 293 | ||
@@ -167,7 +356,8 @@ static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL); | |||
167 | /* Descriptor fields */ | 356 | /* Descriptor fields */ |
168 | #define usb_descriptor_attr_le16(field, format_string) \ | 357 | #define usb_descriptor_attr_le16(field, format_string) \ |
169 | static ssize_t \ | 358 | static ssize_t \ |
170 | show_##field (struct device *dev, struct device_attribute *attr, char *buf) \ | 359 | show_##field (struct device *dev, struct device_attribute *attr, \ |
360 | char *buf) \ | ||
171 | { \ | 361 | { \ |
172 | struct usb_device *udev; \ | 362 | struct usb_device *udev; \ |
173 | \ | 363 | \ |
@@ -183,7 +373,8 @@ usb_descriptor_attr_le16(bcdDevice, "%04x\n") | |||
183 | 373 | ||
184 | #define usb_descriptor_attr(field, format_string) \ | 374 | #define usb_descriptor_attr(field, format_string) \ |
185 | static ssize_t \ | 375 | static ssize_t \ |
186 | show_##field (struct device *dev, struct device_attribute *attr, char *buf) \ | 376 | show_##field (struct device *dev, struct device_attribute *attr, \ |
377 | char *buf) \ | ||
187 | { \ | 378 | { \ |
188 | struct usb_device *udev; \ | 379 | struct usb_device *udev; \ |
189 | \ | 380 | \ |
@@ -236,19 +427,21 @@ void usb_create_sysfs_dev_files (struct usb_device *udev) | |||
236 | if (udev->serial) | 427 | if (udev->serial) |
237 | device_create_file (dev, &dev_attr_serial); | 428 | device_create_file (dev, &dev_attr_serial); |
238 | device_create_file (dev, &dev_attr_configuration); | 429 | device_create_file (dev, &dev_attr_configuration); |
430 | usb_create_ep_files(&dev->kobj, &udev->ep0, udev); | ||
239 | } | 431 | } |
240 | 432 | ||
241 | void usb_remove_sysfs_dev_files (struct usb_device *udev) | 433 | void usb_remove_sysfs_dev_files (struct usb_device *udev) |
242 | { | 434 | { |
243 | struct device *dev = &udev->dev; | 435 | struct device *dev = &udev->dev; |
244 | 436 | ||
437 | usb_remove_ep_files(&udev->ep0); | ||
245 | sysfs_remove_group(&dev->kobj, &dev_attr_grp); | 438 | sysfs_remove_group(&dev->kobj, &dev_attr_grp); |
246 | 439 | ||
247 | if (udev->descriptor.iManufacturer) | 440 | if (udev->manufacturer) |
248 | device_remove_file(dev, &dev_attr_manufacturer); | 441 | device_remove_file(dev, &dev_attr_manufacturer); |
249 | if (udev->descriptor.iProduct) | 442 | if (udev->product) |
250 | device_remove_file(dev, &dev_attr_product); | 443 | device_remove_file(dev, &dev_attr_product); |
251 | if (udev->descriptor.iSerialNumber) | 444 | if (udev->serial) |
252 | device_remove_file(dev, &dev_attr_serial); | 445 | device_remove_file(dev, &dev_attr_serial); |
253 | device_remove_file (dev, &dev_attr_configuration); | 446 | device_remove_file (dev, &dev_attr_configuration); |
254 | } | 447 | } |
@@ -256,11 +449,13 @@ void usb_remove_sysfs_dev_files (struct usb_device *udev) | |||
256 | /* Interface fields */ | 449 | /* Interface fields */ |
257 | #define usb_intf_attr(field, format_string) \ | 450 | #define usb_intf_attr(field, format_string) \ |
258 | static ssize_t \ | 451 | static ssize_t \ |
259 | show_##field (struct device *dev, struct device_attribute *attr, char *buf) \ | 452 | show_##field (struct device *dev, struct device_attribute *attr, \ |
453 | char *buf) \ | ||
260 | { \ | 454 | { \ |
261 | struct usb_interface *intf = to_usb_interface (dev); \ | 455 | struct usb_interface *intf = to_usb_interface (dev); \ |
262 | \ | 456 | \ |
263 | return sprintf (buf, format_string, intf->cur_altsetting->desc.field); \ | 457 | return sprintf (buf, format_string, \ |
458 | intf->cur_altsetting->desc.field); \ | ||
264 | } \ | 459 | } \ |
265 | static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); | 460 | static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); |
266 | 461 | ||
@@ -271,7 +466,8 @@ usb_intf_attr (bInterfaceClass, "%02x\n") | |||
271 | usb_intf_attr (bInterfaceSubClass, "%02x\n") | 466 | usb_intf_attr (bInterfaceSubClass, "%02x\n") |
272 | usb_intf_attr (bInterfaceProtocol, "%02x\n") | 467 | usb_intf_attr (bInterfaceProtocol, "%02x\n") |
273 | 468 | ||
274 | static ssize_t show_interface_string(struct device *dev, struct device_attribute *attr, char *buf) | 469 | static ssize_t show_interface_string(struct device *dev, |
470 | struct device_attribute *attr, char *buf) | ||
275 | { | 471 | { |
276 | struct usb_interface *intf; | 472 | struct usb_interface *intf; |
277 | struct usb_device *udev; | 473 | struct usb_device *udev; |
@@ -288,34 +484,28 @@ static ssize_t show_interface_string(struct device *dev, struct device_attribute | |||
288 | } | 484 | } |
289 | static DEVICE_ATTR(interface, S_IRUGO, show_interface_string, NULL); | 485 | static DEVICE_ATTR(interface, S_IRUGO, show_interface_string, NULL); |
290 | 486 | ||
291 | static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, char *buf) | 487 | static ssize_t show_modalias(struct device *dev, |
488 | struct device_attribute *attr, char *buf) | ||
292 | { | 489 | { |
293 | struct usb_interface *intf; | 490 | struct usb_interface *intf; |
294 | struct usb_device *udev; | 491 | struct usb_device *udev; |
295 | int len; | 492 | struct usb_host_interface *alt; |
296 | 493 | ||
297 | intf = to_usb_interface(dev); | 494 | intf = to_usb_interface(dev); |
298 | udev = interface_to_usbdev(intf); | 495 | udev = interface_to_usbdev(intf); |
299 | 496 | alt = intf->cur_altsetting; | |
300 | len = sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic", | 497 | |
301 | le16_to_cpu(udev->descriptor.idVendor), | 498 | return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X" |
302 | le16_to_cpu(udev->descriptor.idProduct), | 499 | "ic%02Xisc%02Xip%02X\n", |
303 | le16_to_cpu(udev->descriptor.bcdDevice), | 500 | le16_to_cpu(udev->descriptor.idVendor), |
304 | udev->descriptor.bDeviceClass, | 501 | le16_to_cpu(udev->descriptor.idProduct), |
305 | udev->descriptor.bDeviceSubClass, | 502 | le16_to_cpu(udev->descriptor.bcdDevice), |
306 | udev->descriptor.bDeviceProtocol); | 503 | udev->descriptor.bDeviceClass, |
307 | buf += len; | 504 | udev->descriptor.bDeviceSubClass, |
308 | 505 | udev->descriptor.bDeviceProtocol, | |
309 | if (udev->descriptor.bDeviceClass == 0) { | 506 | alt->desc.bInterfaceClass, |
310 | struct usb_host_interface *alt = intf->cur_altsetting; | 507 | alt->desc.bInterfaceSubClass, |
311 | 508 | alt->desc.bInterfaceProtocol); | |
312 | return len + sprintf(buf, "%02Xisc%02Xip%02X\n", | ||
313 | alt->desc.bInterfaceClass, | ||
314 | alt->desc.bInterfaceSubClass, | ||
315 | alt->desc.bInterfaceProtocol); | ||
316 | } else { | ||
317 | return len + sprintf(buf, "*isc*ip*\n"); | ||
318 | } | ||
319 | } | 509 | } |
320 | static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL); | 510 | static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL); |
321 | 511 | ||
@@ -333,20 +523,47 @@ static struct attribute_group intf_attr_grp = { | |||
333 | .attrs = intf_attrs, | 523 | .attrs = intf_attrs, |
334 | }; | 524 | }; |
335 | 525 | ||
526 | static inline void usb_create_intf_ep_files(struct usb_interface *intf, | ||
527 | struct usb_device *udev) | ||
528 | { | ||
529 | struct usb_host_interface *iface_desc; | ||
530 | int i; | ||
531 | |||
532 | iface_desc = intf->cur_altsetting; | ||
533 | for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) | ||
534 | usb_create_ep_files(&intf->dev.kobj, &iface_desc->endpoint[i], | ||
535 | udev); | ||
536 | } | ||
537 | |||
538 | static inline void usb_remove_intf_ep_files(struct usb_interface *intf) | ||
539 | { | ||
540 | struct usb_host_interface *iface_desc; | ||
541 | int i; | ||
542 | |||
543 | iface_desc = intf->cur_altsetting; | ||
544 | for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) | ||
545 | usb_remove_ep_files(&iface_desc->endpoint[i]); | ||
546 | } | ||
547 | |||
336 | void usb_create_sysfs_intf_files (struct usb_interface *intf) | 548 | void usb_create_sysfs_intf_files (struct usb_interface *intf) |
337 | { | 549 | { |
550 | struct usb_device *udev = interface_to_usbdev(intf); | ||
551 | struct usb_host_interface *alt = intf->cur_altsetting; | ||
552 | |||
338 | sysfs_create_group(&intf->dev.kobj, &intf_attr_grp); | 553 | sysfs_create_group(&intf->dev.kobj, &intf_attr_grp); |
339 | 554 | ||
340 | if (intf->cur_altsetting->string) | 555 | if (alt->string == NULL) |
556 | alt->string = usb_cache_string(udev, alt->desc.iInterface); | ||
557 | if (alt->string) | ||
341 | device_create_file(&intf->dev, &dev_attr_interface); | 558 | device_create_file(&intf->dev, &dev_attr_interface); |
342 | 559 | usb_create_intf_ep_files(intf, udev); | |
343 | } | 560 | } |
344 | 561 | ||
345 | void usb_remove_sysfs_intf_files (struct usb_interface *intf) | 562 | void usb_remove_sysfs_intf_files (struct usb_interface *intf) |
346 | { | 563 | { |
564 | usb_remove_intf_ep_files(intf); | ||
347 | sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp); | 565 | sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp); |
348 | 566 | ||
349 | if (intf->cur_altsetting->string) | 567 | if (intf->cur_altsetting->string) |
350 | device_remove_file(&intf->dev, &dev_attr_interface); | 568 | device_remove_file(&intf->dev, &dev_attr_interface); |
351 | |||
352 | } | 569 | } |