aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2005-10-25 15:56:06 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2005-10-28 19:47:50 -0400
commitbe69e5b1900a19a545becda822b18d6f09168ba5 (patch)
tree7730b17e403cc03ea7c7cee8fc56f06171af0ebe /drivers/usb
parente52783206ada0c0276c8dd74c0ecd0007ead7c00 (diff)
[PATCH] usbcore: Improve endpoint sysfs file handling
This revised patch (as587b) improves the implementation of USB endpoint sysfs files. Instead of storing a whole bunch of attributes for every single endpoint, each endpoint now gets its own kobject and they can share a static list of attributes. The number of extra fields added to struct usb_host_endpoint has been reduced from 4 to 1. The bEndpointAddress field is retained even though it is redundant (it repeats the same information as the attributes' directory name). The code avoids calling kobject_register, to prevent generating unwanted hotplug events. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/core/sysfs.c219
1 files changed, 124 insertions, 95 deletions
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 4bdbc9df6e03..f18317fb49ee 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -23,43 +23,56 @@
23#include "usb.h" 23#include "usb.h"
24 24
25/* endpoint stuff */ 25/* endpoint stuff */
26struct endpoint_attribute { 26struct ep_object {
27 struct device_attribute dev_attr; 27 struct usb_endpoint_descriptor *desc;
28 struct usb_endpoint_descriptor *endpoint;
29 struct usb_device *udev; 28 struct usb_device *udev;
29 struct kobject kobj;
30}; 30};
31#define to_endpoint_attr(_dev_attr) \ 31#define to_ep_object(_kobj) \
32 container_of(_dev_attr, struct endpoint_attribute, dev_attr) 32 container_of(_kobj, struct ep_object, kobj)
33 33
34#define usb_ep_attr(field, format_string) \ 34struct ep_attribute {
35static ssize_t show_ep_##field(struct device *dev, struct device_attribute *attr, \ 35 struct attribute attr;
36 char *buf) \ 36 ssize_t (*show)(struct usb_device *,
37{ \ 37 struct usb_endpoint_descriptor *, char *);
38 struct endpoint_attribute *endpoint_attr = to_endpoint_attr(attr); \ 38};
39 \ 39#define to_ep_attribute(_attr) \
40 return sprintf(buf, format_string, endpoint_attr->endpoint->field); \ 40 container_of(_attr, struct ep_attribute, attr)
41} 41
42#define EP_ATTR(_name) \
43struct 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) \
49static 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} \
55static EP_ATTR(field);
56
42usb_ep_attr(bLength, "%02x\n") 57usb_ep_attr(bLength, "%02x\n")
43usb_ep_attr(bDescriptorType, "%02x\n")
44usb_ep_attr(bEndpointAddress, "%02x\n") 58usb_ep_attr(bEndpointAddress, "%02x\n")
45usb_ep_attr(bmAttributes, "%02x\n") 59usb_ep_attr(bmAttributes, "%02x\n")
46usb_ep_attr(bInterval, "%02x\n") 60usb_ep_attr(bInterval, "%02x\n")
47 61
48static ssize_t show_ep_wMaxPacketSize(struct device *dev, 62static ssize_t show_ep_wMaxPacketSize(struct usb_device *udev,
49 struct device_attribute *attr, char *buf) 63 struct usb_endpoint_descriptor *desc, char *buf)
50{ 64{
51 struct endpoint_attribute *endpoint_attr = to_endpoint_attr(attr);
52
53 return sprintf(buf, "%04x\n", 65 return sprintf(buf, "%04x\n",
54 le16_to_cpu(endpoint_attr->endpoint->wMaxPacketSize) & 0x07ff); 66 le16_to_cpu(desc->wMaxPacketSize) & 0x07ff);
55} 67}
68static EP_ATTR(wMaxPacketSize);
56 69
57static ssize_t show_ep_type(struct device *dev, struct device_attribute *attr, char *buf) 70static ssize_t show_ep_type(struct usb_device *udev,
71 struct usb_endpoint_descriptor *desc, char *buf)
58{ 72{
59 struct endpoint_attribute *endpoint_attr = to_endpoint_attr(attr);
60 char *type = "unknown"; 73 char *type = "unknown";
61 74
62 switch (endpoint_attr->endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { 75 switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
63 case USB_ENDPOINT_XFER_CONTROL: 76 case USB_ENDPOINT_XFER_CONTROL:
64 type = "Control"; 77 type = "Control";
65 break; 78 break;
@@ -75,35 +88,34 @@ static ssize_t show_ep_type(struct device *dev, struct device_attribute *attr, c
75 } 88 }
76 return sprintf(buf, "%s\n", type); 89 return sprintf(buf, "%s\n", type);
77} 90}
91static EP_ATTR(type);
78 92
79static ssize_t show_ep_interval(struct device *dev, struct device_attribute *attr, char *buf) 93static ssize_t show_ep_interval(struct usb_device *udev,
94 struct usb_endpoint_descriptor *desc, char *buf)
80{ 95{
81 struct endpoint_attribute *endpoint_attr = to_endpoint_attr(attr);
82 struct usb_device *udev = endpoint_attr->udev;
83 struct usb_endpoint_descriptor *endpoint = endpoint_attr->endpoint;
84 char unit; 96 char unit;
85 unsigned interval = 0; 97 unsigned interval = 0;
86 unsigned in; 98 unsigned in;
87 99
88 in = (endpoint->bEndpointAddress & USB_DIR_IN); 100 in = (desc->bEndpointAddress & USB_DIR_IN);
89 101
90 switch (endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { 102 switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
91 case USB_ENDPOINT_XFER_CONTROL: 103 case USB_ENDPOINT_XFER_CONTROL:
92 if (udev->speed == USB_SPEED_HIGH) /* uframes per NAK */ 104 if (udev->speed == USB_SPEED_HIGH) /* uframes per NAK */
93 interval = endpoint->bInterval; 105 interval = desc->bInterval;
94 break; 106 break;
95 case USB_ENDPOINT_XFER_ISOC: 107 case USB_ENDPOINT_XFER_ISOC:
96 interval = 1 << (endpoint->bInterval - 1); 108 interval = 1 << (desc->bInterval - 1);
97 break; 109 break;
98 case USB_ENDPOINT_XFER_BULK: 110 case USB_ENDPOINT_XFER_BULK:
99 if (udev->speed == USB_SPEED_HIGH && !in) /* uframes per NAK */ 111 if (udev->speed == USB_SPEED_HIGH && !in) /* uframes per NAK */
100 interval = endpoint->bInterval; 112 interval = desc->bInterval;
101 break; 113 break;
102 case USB_ENDPOINT_XFER_INT: 114 case USB_ENDPOINT_XFER_INT:
103 if (udev->speed == USB_SPEED_HIGH) { 115 if (udev->speed == USB_SPEED_HIGH)
104 interval = 1 << (endpoint->bInterval - 1); 116 interval = 1 << (desc->bInterval - 1);
105 } else 117 else
106 interval = endpoint->bInterval; 118 interval = desc->bInterval;
107 break; 119 break;
108 } 120 }
109 interval *= (udev->speed == USB_SPEED_HIGH) ? 125 : 1000; 121 interval *= (udev->speed == USB_SPEED_HIGH) ? 125 : 1000;
@@ -116,78 +128,95 @@ static ssize_t show_ep_interval(struct device *dev, struct device_attribute *att
116 128
117 return sprintf(buf, "%d%cs\n", interval, unit); 129 return sprintf(buf, "%d%cs\n", interval, unit);
118} 130}
131static EP_ATTR(interval);
119 132
120static ssize_t show_ep_direction(struct device *dev, struct device_attribute *attr, char *buf) 133static ssize_t show_ep_direction(struct usb_device *udev,
134 struct usb_endpoint_descriptor *desc, char *buf)
121{ 135{
122 struct endpoint_attribute *endpoint_attr = to_endpoint_attr(attr);
123 char *direction; 136 char *direction;
124 137
125 if ((endpoint_attr->endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == 138 if ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
126 USB_ENDPOINT_XFER_CONTROL) 139 USB_ENDPOINT_XFER_CONTROL)
127 direction = "both"; 140 direction = "both";
128 else if (endpoint_attr->endpoint->bEndpointAddress & USB_DIR_IN) 141 else if (desc->bEndpointAddress & USB_DIR_IN)
129 direction = "in"; 142 direction = "in";
130 else 143 else
131 direction = "out"; 144 direction = "out";
132 return sprintf(buf, "%s\n", direction); 145 return sprintf(buf, "%s\n", direction);
133} 146}
147static EP_ATTR(direction);
148
149static 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};
134 160
135static struct endpoint_attribute *create_ep_attr(struct usb_endpoint_descriptor *endpoint, 161static void ep_object_release(struct kobject *kobj)
136 struct usb_device *udev, char *name,
137 ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf))
138{ 162{
139 struct endpoint_attribute *ep_attr; 163 kfree(to_ep_object(kobj));
140
141 ep_attr = kzalloc(sizeof(*ep_attr), GFP_KERNEL);
142 if (ep_attr) {
143 ep_attr->endpoint = endpoint;
144 ep_attr->udev = udev;
145 ep_attr->dev_attr.attr.name = name;
146 ep_attr->dev_attr.attr.mode = 0444;
147 ep_attr->dev_attr.attr.owner = THIS_MODULE;
148 ep_attr->dev_attr.show = show;
149 }
150 return ep_attr;
151} 164}
152 165
153static void usb_create_ep_files(struct kobject *kobj, struct usb_host_endpoint *endpoint, struct usb_device *udev) 166static ssize_t ep_object_show(struct kobject *kobj, struct attribute *attr,
167 char *buf)
154{ 168{
155 struct usb_endpoint_descriptor *ep; 169 struct ep_object *ep_obj = to_ep_object(kobj);
156 170 struct ep_attribute *ep_attr = to_ep_attribute(attr);
157 ep = &endpoint->desc; 171
158 172 return (ep_attr->show)(ep_obj->udev, ep_obj->desc, buf);
159 endpoint->attrs = kzalloc(sizeof(struct attribute *) * 10, GFP_KERNEL);
160 endpoint->attrs[0] = &(create_ep_attr(ep, udev, "direction", show_ep_direction)->dev_attr.attr);
161 endpoint->attrs[1] = &(create_ep_attr(ep, udev, "type", show_ep_type)->dev_attr.attr);
162 endpoint->attrs[2] = &(create_ep_attr(ep, udev, "bLength", show_ep_bLength)->dev_attr.attr);
163 endpoint->attrs[3] = &(create_ep_attr(ep, udev, "bDescriptorType", show_ep_bDescriptorType)->dev_attr.attr);
164 endpoint->attrs[4] = &(create_ep_attr(ep, udev, "bEndpointAddress", show_ep_bEndpointAddress)->dev_attr.attr);
165 endpoint->attrs[5] = &(create_ep_attr(ep, udev, "bmAttributes", show_ep_bmAttributes)->dev_attr.attr);
166 endpoint->attrs[6] = &(create_ep_attr(ep, udev, "wMaxPacketSize", show_ep_wMaxPacketSize)->dev_attr.attr);
167 endpoint->attrs[7] = &(create_ep_attr(ep, udev, "bInterval", show_ep_bInterval)->dev_attr.attr);
168 endpoint->attrs[8] = &(create_ep_attr(ep, udev, "interval", show_ep_interval)->dev_attr.attr);
169 endpoint->attrs[9] = NULL;
170 endpoint->num_attrs = 9;
171
172 endpoint->attr_group = kzalloc(sizeof(*endpoint->attr_group), GFP_KERNEL);
173 endpoint->attr_name = kzalloc(10, GFP_KERNEL);
174 sprintf(endpoint->attr_name, "ep_%02x", endpoint->desc.bEndpointAddress);
175
176 endpoint->attr_group->attrs = endpoint->attrs;
177 endpoint->attr_group->name = endpoint->attr_name;
178 sysfs_create_group(kobj, endpoint->attr_group);
179} 173}
180 174
181static void usb_remove_ep_files(struct kobject *kobj, struct usb_host_endpoint *endpoint) 175static struct sysfs_ops ep_object_sysfs_ops = {
176 .show = ep_object_show,
177};
178
179static 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
185static void usb_create_ep_files(struct kobject *parent,
186 struct usb_host_endpoint *endpoint,
187 struct usb_device *udev)
182{ 188{
183 int i; 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;
184 195
185 sysfs_remove_group(kobj, endpoint->attr_group); 196 ep_obj->desc = &endpoint->desc;
186 kfree(endpoint->attr_group); 197 ep_obj->udev = udev;
187 kfree(endpoint->attr_name); 198
188 for (i = 0; i < endpoint->num_attrs; ++i) 199 kobj = &ep_obj->kobj;
189 kfree(endpoint->attrs[i]); 200 kobject_set_name(kobj, "ep_%02x", endpoint->desc.bEndpointAddress);
190 kfree(endpoint->attrs); 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
212static 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 }
191} 220}
192 221
193/* Active configuration fields */ 222/* Active configuration fields */
@@ -411,7 +440,7 @@ void usb_remove_sysfs_dev_files (struct usb_device *udev)
411{ 440{
412 struct device *dev = &udev->dev; 441 struct device *dev = &udev->dev;
413 442
414 usb_remove_ep_files(&dev->kobj, &udev->ep0); 443 usb_remove_ep_files(&udev->ep0);
415 sysfs_remove_group(&dev->kobj, &dev_attr_grp); 444 sysfs_remove_group(&dev->kobj, &dev_attr_grp);
416 445
417 if (udev->descriptor.iManufacturer) 446 if (udev->descriptor.iManufacturer)
@@ -496,7 +525,7 @@ static struct attribute_group intf_attr_grp = {
496 .attrs = intf_attrs, 525 .attrs = intf_attrs,
497}; 526};
498 527
499static void usb_create_intf_ep_files(struct usb_interface *intf) 528static inline void usb_create_intf_ep_files(struct usb_interface *intf)
500{ 529{
501 struct usb_host_interface *iface_desc; 530 struct usb_host_interface *iface_desc;
502 int i; 531 int i;
@@ -504,17 +533,17 @@ static void usb_create_intf_ep_files(struct usb_interface *intf)
504 iface_desc = intf->cur_altsetting; 533 iface_desc = intf->cur_altsetting;
505 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) 534 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i)
506 usb_create_ep_files(&intf->dev.kobj, &iface_desc->endpoint[i], 535 usb_create_ep_files(&intf->dev.kobj, &iface_desc->endpoint[i],
507 interface_to_usbdev(intf)); 536 interface_to_usbdev(intf));
508} 537}
509 538
510static void usb_remove_intf_ep_files(struct usb_interface *intf) 539static inline void usb_remove_intf_ep_files(struct usb_interface *intf)
511{ 540{
512 struct usb_host_interface *iface_desc; 541 struct usb_host_interface *iface_desc;
513 int i; 542 int i;
514 543
515 iface_desc = intf->cur_altsetting; 544 iface_desc = intf->cur_altsetting;
516 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) 545 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i)
517 usb_remove_ep_files(&intf->dev.kobj, &iface_desc->endpoint[i]); 546 usb_remove_ep_files(&iface_desc->endpoint[i]);
518} 547}
519 548
520void usb_create_sysfs_intf_files (struct usb_interface *intf) 549void usb_create_sysfs_intf_files (struct usb_interface *intf)