Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * drivers/usb/core/sysfs.c | |
3 | * | |
4 | * (C) Copyright 2002 David Brownell | |
5 | * (C) Copyright 2002,2004 Greg Kroah-Hartman | |
6 | * (C) Copyright 2002,2004 IBM Corp. | |
7 | * | |
8 | * All of the sysfs file attributes for usb devices and interfaces. | |
9 | * | |
10 | */ | |
11 | ||
12 | ||
1da177e4 | 13 | #include <linux/kernel.h> |
1da177e4 | 14 | #include <linux/usb.h> |
1da177e4 LT |
15 | #include "usb.h" |
16 | ||
17 | /* Active configuration fields */ | |
18 | #define usb_actconfig_show(field, multiplier, format_string) \ | |
b724ae77 AS |
19 | static ssize_t show_##field (struct device *dev, \ |
20 | struct device_attribute *attr, char *buf) \ | |
1da177e4 LT |
21 | { \ |
22 | struct usb_device *udev; \ | |
23 | struct usb_host_config *actconfig; \ | |
24 | \ | |
25 | udev = to_usb_device (dev); \ | |
26 | actconfig = udev->actconfig; \ | |
27 | if (actconfig) \ | |
28 | return sprintf (buf, format_string, \ | |
29 | actconfig->desc.field * multiplier); \ | |
30 | else \ | |
31 | return 0; \ | |
32 | } \ | |
33 | ||
34 | #define usb_actconfig_attr(field, multiplier, format_string) \ | |
35 | usb_actconfig_show(field, multiplier, format_string) \ | |
36 | static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); | |
37 | ||
38 | usb_actconfig_attr (bNumInterfaces, 1, "%2d\n") | |
39 | usb_actconfig_attr (bmAttributes, 1, "%2x\n") | |
40 | usb_actconfig_attr (bMaxPower, 2, "%3dmA\n") | |
41 | ||
b724ae77 AS |
42 | static ssize_t show_configuration_string(struct device *dev, |
43 | struct device_attribute *attr, char *buf) | |
1da177e4 LT |
44 | { |
45 | struct usb_device *udev; | |
46 | struct usb_host_config *actconfig; | |
1da177e4 LT |
47 | |
48 | udev = to_usb_device (dev); | |
49 | actconfig = udev->actconfig; | |
50 | if ((!actconfig) || (!actconfig->string)) | |
51 | return 0; | |
4f62efe6 | 52 | return sprintf(buf, "%s\n", actconfig->string); |
1da177e4 LT |
53 | } |
54 | static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL); | |
55 | ||
56 | /* configuration value is always present, and r/w */ | |
57 | usb_actconfig_show(bConfigurationValue, 1, "%u\n"); | |
58 | ||
59 | static ssize_t | |
b724ae77 AS |
60 | set_bConfigurationValue (struct device *dev, struct device_attribute *attr, |
61 | const char *buf, size_t count) | |
1da177e4 LT |
62 | { |
63 | struct usb_device *udev = udev = to_usb_device (dev); | |
64 | int config, value; | |
65 | ||
66 | if (sscanf (buf, "%u", &config) != 1 || config > 255) | |
67 | return -EINVAL; | |
68 | usb_lock_device(udev); | |
69 | value = usb_set_configuration (udev, config); | |
70 | usb_unlock_device(udev); | |
71 | return (value < 0) ? value : count; | |
72 | } | |
73 | ||
74 | static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR, | |
75 | show_bConfigurationValue, set_bConfigurationValue); | |
76 | ||
77 | /* String fields */ | |
78 | #define usb_string_attr(name) \ | |
b724ae77 AS |
79 | static ssize_t show_##name(struct device *dev, \ |
80 | struct device_attribute *attr, char *buf) \ | |
1da177e4 LT |
81 | { \ |
82 | struct usb_device *udev; \ | |
1da177e4 LT |
83 | \ |
84 | udev = to_usb_device (dev); \ | |
4f62efe6 | 85 | return sprintf(buf, "%s\n", udev->name); \ |
1da177e4 LT |
86 | } \ |
87 | static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); | |
88 | ||
89 | usb_string_attr(product); | |
90 | usb_string_attr(manufacturer); | |
91 | usb_string_attr(serial); | |
92 | ||
93 | static ssize_t | |
10523b3b | 94 | show_speed (struct device *dev, struct device_attribute *attr, char *buf) |
1da177e4 LT |
95 | { |
96 | struct usb_device *udev; | |
97 | char *speed; | |
98 | ||
99 | udev = to_usb_device (dev); | |
100 | ||
101 | switch (udev->speed) { | |
102 | case USB_SPEED_LOW: | |
103 | speed = "1.5"; | |
104 | break; | |
105 | case USB_SPEED_UNKNOWN: | |
106 | case USB_SPEED_FULL: | |
107 | speed = "12"; | |
108 | break; | |
109 | case USB_SPEED_HIGH: | |
110 | speed = "480"; | |
111 | break; | |
112 | default: | |
113 | speed = "unknown"; | |
114 | } | |
115 | return sprintf (buf, "%s\n", speed); | |
116 | } | |
117 | static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL); | |
118 | ||
119 | static ssize_t | |
10523b3b | 120 | show_devnum (struct device *dev, struct device_attribute *attr, char *buf) |
1da177e4 LT |
121 | { |
122 | struct usb_device *udev; | |
123 | ||
124 | udev = to_usb_device (dev); | |
125 | return sprintf (buf, "%d\n", udev->devnum); | |
126 | } | |
127 | static DEVICE_ATTR(devnum, S_IRUGO, show_devnum, NULL); | |
128 | ||
129 | static ssize_t | |
10523b3b | 130 | show_version (struct device *dev, struct device_attribute *attr, char *buf) |
1da177e4 LT |
131 | { |
132 | struct usb_device *udev; | |
133 | u16 bcdUSB; | |
134 | ||
135 | udev = to_usb_device(dev); | |
136 | bcdUSB = le16_to_cpu(udev->descriptor.bcdUSB); | |
137 | return sprintf(buf, "%2x.%02x\n", bcdUSB >> 8, bcdUSB & 0xff); | |
138 | } | |
139 | static DEVICE_ATTR(version, S_IRUGO, show_version, NULL); | |
140 | ||
141 | static ssize_t | |
10523b3b | 142 | show_maxchild (struct device *dev, struct device_attribute *attr, char *buf) |
1da177e4 LT |
143 | { |
144 | struct usb_device *udev; | |
145 | ||
146 | udev = to_usb_device (dev); | |
147 | return sprintf (buf, "%d\n", udev->maxchild); | |
148 | } | |
149 | static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL); | |
150 | ||
151 | /* Descriptor fields */ | |
152 | #define usb_descriptor_attr_le16(field, format_string) \ | |
153 | static ssize_t \ | |
b724ae77 AS |
154 | show_##field (struct device *dev, struct device_attribute *attr, \ |
155 | char *buf) \ | |
1da177e4 LT |
156 | { \ |
157 | struct usb_device *udev; \ | |
158 | \ | |
159 | udev = to_usb_device (dev); \ | |
160 | return sprintf (buf, format_string, \ | |
161 | le16_to_cpu(udev->descriptor.field)); \ | |
162 | } \ | |
163 | static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); | |
164 | ||
165 | usb_descriptor_attr_le16(idVendor, "%04x\n") | |
166 | usb_descriptor_attr_le16(idProduct, "%04x\n") | |
167 | usb_descriptor_attr_le16(bcdDevice, "%04x\n") | |
168 | ||
169 | #define usb_descriptor_attr(field, format_string) \ | |
170 | static ssize_t \ | |
b724ae77 AS |
171 | show_##field (struct device *dev, struct device_attribute *attr, \ |
172 | char *buf) \ | |
1da177e4 LT |
173 | { \ |
174 | struct usb_device *udev; \ | |
175 | \ | |
176 | udev = to_usb_device (dev); \ | |
177 | return sprintf (buf, format_string, udev->descriptor.field); \ | |
178 | } \ | |
179 | static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); | |
180 | ||
181 | usb_descriptor_attr (bDeviceClass, "%02x\n") | |
182 | usb_descriptor_attr (bDeviceSubClass, "%02x\n") | |
183 | usb_descriptor_attr (bDeviceProtocol, "%02x\n") | |
184 | usb_descriptor_attr (bNumConfigurations, "%d\n") | |
cf5910bb | 185 | usb_descriptor_attr (bMaxPacketSize0, "%d\n") |
1da177e4 LT |
186 | |
187 | static struct attribute *dev_attrs[] = { | |
188 | /* current configuration's attributes */ | |
189 | &dev_attr_bNumInterfaces.attr, | |
190 | &dev_attr_bConfigurationValue.attr, | |
191 | &dev_attr_bmAttributes.attr, | |
192 | &dev_attr_bMaxPower.attr, | |
193 | /* device attributes */ | |
194 | &dev_attr_idVendor.attr, | |
195 | &dev_attr_idProduct.attr, | |
196 | &dev_attr_bcdDevice.attr, | |
197 | &dev_attr_bDeviceClass.attr, | |
198 | &dev_attr_bDeviceSubClass.attr, | |
199 | &dev_attr_bDeviceProtocol.attr, | |
200 | &dev_attr_bNumConfigurations.attr, | |
cf5910bb | 201 | &dev_attr_bMaxPacketSize0.attr, |
1da177e4 LT |
202 | &dev_attr_speed.attr, |
203 | &dev_attr_devnum.attr, | |
204 | &dev_attr_version.attr, | |
205 | &dev_attr_maxchild.attr, | |
206 | NULL, | |
207 | }; | |
208 | static struct attribute_group dev_attr_grp = { | |
209 | .attrs = dev_attrs, | |
210 | }; | |
211 | ||
212 | void usb_create_sysfs_dev_files (struct usb_device *udev) | |
213 | { | |
214 | struct device *dev = &udev->dev; | |
215 | ||
216 | sysfs_create_group(&dev->kobj, &dev_attr_grp); | |
217 | ||
218 | if (udev->manufacturer) | |
219 | device_create_file (dev, &dev_attr_manufacturer); | |
220 | if (udev->product) | |
221 | device_create_file (dev, &dev_attr_product); | |
222 | if (udev->serial) | |
223 | device_create_file (dev, &dev_attr_serial); | |
224 | device_create_file (dev, &dev_attr_configuration); | |
36679ea5 | 225 | usb_create_ep_files(dev, &udev->ep0, udev); |
1da177e4 LT |
226 | } |
227 | ||
228 | void usb_remove_sysfs_dev_files (struct usb_device *udev) | |
229 | { | |
230 | struct device *dev = &udev->dev; | |
231 | ||
be69e5b1 | 232 | usb_remove_ep_files(&udev->ep0); |
1da177e4 LT |
233 | sysfs_remove_group(&dev->kobj, &dev_attr_grp); |
234 | ||
4f62efe6 | 235 | if (udev->manufacturer) |
1da177e4 | 236 | device_remove_file(dev, &dev_attr_manufacturer); |
4f62efe6 | 237 | if (udev->product) |
1da177e4 | 238 | device_remove_file(dev, &dev_attr_product); |
4f62efe6 | 239 | if (udev->serial) |
1da177e4 LT |
240 | device_remove_file(dev, &dev_attr_serial); |
241 | device_remove_file (dev, &dev_attr_configuration); | |
242 | } | |
243 | ||
244 | /* Interface fields */ | |
245 | #define usb_intf_attr(field, format_string) \ | |
246 | static ssize_t \ | |
b724ae77 AS |
247 | show_##field (struct device *dev, struct device_attribute *attr, \ |
248 | char *buf) \ | |
1da177e4 LT |
249 | { \ |
250 | struct usb_interface *intf = to_usb_interface (dev); \ | |
251 | \ | |
b724ae77 AS |
252 | return sprintf (buf, format_string, \ |
253 | intf->cur_altsetting->desc.field); \ | |
1da177e4 LT |
254 | } \ |
255 | static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); | |
256 | ||
257 | usb_intf_attr (bInterfaceNumber, "%02x\n") | |
258 | usb_intf_attr (bAlternateSetting, "%2d\n") | |
259 | usb_intf_attr (bNumEndpoints, "%02x\n") | |
260 | usb_intf_attr (bInterfaceClass, "%02x\n") | |
261 | usb_intf_attr (bInterfaceSubClass, "%02x\n") | |
262 | usb_intf_attr (bInterfaceProtocol, "%02x\n") | |
263 | ||
b724ae77 AS |
264 | static ssize_t show_interface_string(struct device *dev, |
265 | struct device_attribute *attr, char *buf) | |
1da177e4 LT |
266 | { |
267 | struct usb_interface *intf; | |
268 | struct usb_device *udev; | |
269 | int len; | |
270 | ||
271 | intf = to_usb_interface (dev); | |
272 | udev = interface_to_usbdev (intf); | |
273 | len = snprintf(buf, 256, "%s", intf->cur_altsetting->string); | |
274 | if (len < 0) | |
275 | return 0; | |
276 | buf[len] = '\n'; | |
277 | buf[len+1] = 0; | |
278 | return len+1; | |
279 | } | |
280 | static DEVICE_ATTR(interface, S_IRUGO, show_interface_string, NULL); | |
281 | ||
b724ae77 AS |
282 | static ssize_t show_modalias(struct device *dev, |
283 | struct device_attribute *attr, char *buf) | |
360b52b0 GK |
284 | { |
285 | struct usb_interface *intf; | |
286 | struct usb_device *udev; | |
7521803d | 287 | struct usb_host_interface *alt; |
360b52b0 GK |
288 | |
289 | intf = to_usb_interface(dev); | |
290 | udev = interface_to_usbdev(intf); | |
7521803d GKH |
291 | alt = intf->cur_altsetting; |
292 | ||
293 | return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X" | |
294 | "ic%02Xisc%02Xip%02X\n", | |
295 | le16_to_cpu(udev->descriptor.idVendor), | |
296 | le16_to_cpu(udev->descriptor.idProduct), | |
297 | le16_to_cpu(udev->descriptor.bcdDevice), | |
298 | udev->descriptor.bDeviceClass, | |
299 | udev->descriptor.bDeviceSubClass, | |
300 | udev->descriptor.bDeviceProtocol, | |
301 | alt->desc.bInterfaceClass, | |
302 | alt->desc.bInterfaceSubClass, | |
303 | alt->desc.bInterfaceProtocol); | |
360b52b0 GK |
304 | } |
305 | static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL); | |
306 | ||
1da177e4 LT |
307 | static struct attribute *intf_attrs[] = { |
308 | &dev_attr_bInterfaceNumber.attr, | |
309 | &dev_attr_bAlternateSetting.attr, | |
310 | &dev_attr_bNumEndpoints.attr, | |
311 | &dev_attr_bInterfaceClass.attr, | |
312 | &dev_attr_bInterfaceSubClass.attr, | |
313 | &dev_attr_bInterfaceProtocol.attr, | |
360b52b0 | 314 | &dev_attr_modalias.attr, |
1da177e4 LT |
315 | NULL, |
316 | }; | |
317 | static struct attribute_group intf_attr_grp = { | |
318 | .attrs = intf_attrs, | |
319 | }; | |
320 | ||
4f62efe6 AS |
321 | static inline void usb_create_intf_ep_files(struct usb_interface *intf, |
322 | struct usb_device *udev) | |
094f1649 GKH |
323 | { |
324 | struct usb_host_interface *iface_desc; | |
325 | int i; | |
326 | ||
327 | iface_desc = intf->cur_altsetting; | |
328 | for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) | |
36679ea5 | 329 | usb_create_ep_files(&intf->dev, &iface_desc->endpoint[i], |
4f62efe6 | 330 | udev); |
094f1649 GKH |
331 | } |
332 | ||
be69e5b1 | 333 | static inline void usb_remove_intf_ep_files(struct usb_interface *intf) |
094f1649 GKH |
334 | { |
335 | struct usb_host_interface *iface_desc; | |
336 | int i; | |
337 | ||
338 | iface_desc = intf->cur_altsetting; | |
339 | for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) | |
be69e5b1 | 340 | usb_remove_ep_files(&iface_desc->endpoint[i]); |
094f1649 GKH |
341 | } |
342 | ||
1da177e4 LT |
343 | void usb_create_sysfs_intf_files (struct usb_interface *intf) |
344 | { | |
4f62efe6 AS |
345 | struct usb_device *udev = interface_to_usbdev(intf); |
346 | struct usb_host_interface *alt = intf->cur_altsetting; | |
347 | ||
1da177e4 LT |
348 | sysfs_create_group(&intf->dev.kobj, &intf_attr_grp); |
349 | ||
4f62efe6 AS |
350 | if (alt->string == NULL) |
351 | alt->string = usb_cache_string(udev, alt->desc.iInterface); | |
352 | if (alt->string) | |
1da177e4 | 353 | device_create_file(&intf->dev, &dev_attr_interface); |
4f62efe6 | 354 | usb_create_intf_ep_files(intf, udev); |
1da177e4 LT |
355 | } |
356 | ||
357 | void usb_remove_sysfs_intf_files (struct usb_interface *intf) | |
358 | { | |
094f1649 | 359 | usb_remove_intf_ep_files(intf); |
1da177e4 LT |
360 | sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp); |
361 | ||
362 | if (intf->cur_altsetting->string) | |
363 | device_remove_file(&intf->dev, &dev_attr_interface); | |
1da177e4 | 364 | } |