blob: 3f49bf51cff75a6f4de11b7b2cd73bffbb52a931 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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
13#include <linux/config.h>
14#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/usb.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include "usb.h"
17
18/* Active configuration fields */
19#define usb_actconfig_show(field, multiplier, format_string) \
Alan Sternb724ae72005-10-24 15:36:00 -040020static ssize_t show_##field (struct device *dev, \
21 struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -070022{ \
23 struct usb_device *udev; \
24 struct usb_host_config *actconfig; \
25 \
26 udev = to_usb_device (dev); \
27 actconfig = udev->actconfig; \
28 if (actconfig) \
29 return sprintf (buf, format_string, \
30 actconfig->desc.field * multiplier); \
31 else \
32 return 0; \
33} \
34
35#define usb_actconfig_attr(field, multiplier, format_string) \
36usb_actconfig_show(field, multiplier, format_string) \
37static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
38
39usb_actconfig_attr (bNumInterfaces, 1, "%2d\n")
40usb_actconfig_attr (bmAttributes, 1, "%2x\n")
41usb_actconfig_attr (bMaxPower, 2, "%3dmA\n")
42
Alan Sternb724ae72005-10-24 15:36:00 -040043static ssize_t show_configuration_string(struct device *dev,
44 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070045{
46 struct usb_device *udev;
47 struct usb_host_config *actconfig;
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
49 udev = to_usb_device (dev);
50 actconfig = udev->actconfig;
51 if ((!actconfig) || (!actconfig->string))
52 return 0;
Alan Stern4f62efe2005-10-24 16:24:14 -040053 return sprintf(buf, "%s\n", actconfig->string);
Linus Torvalds1da177e2005-04-16 15:20:36 -070054}
55static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL);
56
57/* configuration value is always present, and r/w */
58usb_actconfig_show(bConfigurationValue, 1, "%u\n");
59
60static ssize_t
Alan Sternb724ae72005-10-24 15:36:00 -040061set_bConfigurationValue (struct device *dev, struct device_attribute *attr,
62 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -070063{
64 struct usb_device *udev = udev = to_usb_device (dev);
65 int config, value;
66
67 if (sscanf (buf, "%u", &config) != 1 || config > 255)
68 return -EINVAL;
69 usb_lock_device(udev);
70 value = usb_set_configuration (udev, config);
71 usb_unlock_device(udev);
72 return (value < 0) ? value : count;
73}
74
75static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR,
76 show_bConfigurationValue, set_bConfigurationValue);
77
78/* String fields */
79#define usb_string_attr(name) \
Alan Sternb724ae72005-10-24 15:36:00 -040080static ssize_t show_##name(struct device *dev, \
81 struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -070082{ \
83 struct usb_device *udev; \
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 \
85 udev = to_usb_device (dev); \
Alan Stern4f62efe2005-10-24 16:24:14 -040086 return sprintf(buf, "%s\n", udev->name); \
Linus Torvalds1da177e2005-04-16 15:20:36 -070087} \
88static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
89
90usb_string_attr(product);
91usb_string_attr(manufacturer);
92usb_string_attr(serial);
93
94static ssize_t
Yani Ioannou10523b32005-05-17 06:43:37 -040095show_speed (struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070096{
97 struct usb_device *udev;
98 char *speed;
99
100 udev = to_usb_device (dev);
101
102 switch (udev->speed) {
103 case USB_SPEED_LOW:
104 speed = "1.5";
105 break;
106 case USB_SPEED_UNKNOWN:
107 case USB_SPEED_FULL:
108 speed = "12";
109 break;
110 case USB_SPEED_HIGH:
111 speed = "480";
112 break;
113 default:
114 speed = "unknown";
115 }
116 return sprintf (buf, "%s\n", speed);
117}
118static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL);
119
120static ssize_t
Yani Ioannou10523b32005-05-17 06:43:37 -0400121show_devnum (struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122{
123 struct usb_device *udev;
124
125 udev = to_usb_device (dev);
126 return sprintf (buf, "%d\n", udev->devnum);
127}
128static DEVICE_ATTR(devnum, S_IRUGO, show_devnum, NULL);
129
130static ssize_t
Yani Ioannou10523b32005-05-17 06:43:37 -0400131show_version (struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132{
133 struct usb_device *udev;
134 u16 bcdUSB;
135
136 udev = to_usb_device(dev);
137 bcdUSB = le16_to_cpu(udev->descriptor.bcdUSB);
138 return sprintf(buf, "%2x.%02x\n", bcdUSB >> 8, bcdUSB & 0xff);
139}
140static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
141
142static ssize_t
Yani Ioannou10523b32005-05-17 06:43:37 -0400143show_maxchild (struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144{
145 struct usb_device *udev;
146
147 udev = to_usb_device (dev);
148 return sprintf (buf, "%d\n", udev->maxchild);
149}
150static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL);
151
152/* Descriptor fields */
153#define usb_descriptor_attr_le16(field, format_string) \
154static ssize_t \
Alan Sternb724ae72005-10-24 15:36:00 -0400155show_##field (struct device *dev, struct device_attribute *attr, \
156 char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157{ \
158 struct usb_device *udev; \
159 \
160 udev = to_usb_device (dev); \
161 return sprintf (buf, format_string, \
162 le16_to_cpu(udev->descriptor.field)); \
163} \
164static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
165
166usb_descriptor_attr_le16(idVendor, "%04x\n")
167usb_descriptor_attr_le16(idProduct, "%04x\n")
168usb_descriptor_attr_le16(bcdDevice, "%04x\n")
169
170#define usb_descriptor_attr(field, format_string) \
171static ssize_t \
Alan Sternb724ae72005-10-24 15:36:00 -0400172show_##field (struct device *dev, struct device_attribute *attr, \
173 char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174{ \
175 struct usb_device *udev; \
176 \
177 udev = to_usb_device (dev); \
178 return sprintf (buf, format_string, udev->descriptor.field); \
179} \
180static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
181
182usb_descriptor_attr (bDeviceClass, "%02x\n")
183usb_descriptor_attr (bDeviceSubClass, "%02x\n")
184usb_descriptor_attr (bDeviceProtocol, "%02x\n")
185usb_descriptor_attr (bNumConfigurations, "%d\n")
Greg Kroah-Hartmancf5910b2005-06-29 16:53:29 -0700186usb_descriptor_attr (bMaxPacketSize0, "%d\n")
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
188static struct attribute *dev_attrs[] = {
189 /* current configuration's attributes */
190 &dev_attr_bNumInterfaces.attr,
191 &dev_attr_bConfigurationValue.attr,
192 &dev_attr_bmAttributes.attr,
193 &dev_attr_bMaxPower.attr,
194 /* device attributes */
195 &dev_attr_idVendor.attr,
196 &dev_attr_idProduct.attr,
197 &dev_attr_bcdDevice.attr,
198 &dev_attr_bDeviceClass.attr,
199 &dev_attr_bDeviceSubClass.attr,
200 &dev_attr_bDeviceProtocol.attr,
201 &dev_attr_bNumConfigurations.attr,
Greg Kroah-Hartmancf5910b2005-06-29 16:53:29 -0700202 &dev_attr_bMaxPacketSize0.attr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 &dev_attr_speed.attr,
204 &dev_attr_devnum.attr,
205 &dev_attr_version.attr,
206 &dev_attr_maxchild.attr,
207 NULL,
208};
209static struct attribute_group dev_attr_grp = {
210 .attrs = dev_attrs,
211};
212
213void usb_create_sysfs_dev_files (struct usb_device *udev)
214{
215 struct device *dev = &udev->dev;
216
217 sysfs_create_group(&dev->kobj, &dev_attr_grp);
218
219 if (udev->manufacturer)
220 device_create_file (dev, &dev_attr_manufacturer);
221 if (udev->product)
222 device_create_file (dev, &dev_attr_product);
223 if (udev->serial)
224 device_create_file (dev, &dev_attr_serial);
225 device_create_file (dev, &dev_attr_configuration);
Greg Kroah-Hartman36679ea2006-06-14 12:14:34 -0700226 usb_create_ep_files(dev, &udev->ep0, udev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227}
228
229void usb_remove_sysfs_dev_files (struct usb_device *udev)
230{
231 struct device *dev = &udev->dev;
232
Alan Sternbe69e5b2005-10-25 15:56:06 -0400233 usb_remove_ep_files(&udev->ep0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 sysfs_remove_group(&dev->kobj, &dev_attr_grp);
235
Alan Stern4f62efe2005-10-24 16:24:14 -0400236 if (udev->manufacturer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 device_remove_file(dev, &dev_attr_manufacturer);
Alan Stern4f62efe2005-10-24 16:24:14 -0400238 if (udev->product)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 device_remove_file(dev, &dev_attr_product);
Alan Stern4f62efe2005-10-24 16:24:14 -0400240 if (udev->serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 device_remove_file(dev, &dev_attr_serial);
242 device_remove_file (dev, &dev_attr_configuration);
243}
244
245/* Interface fields */
246#define usb_intf_attr(field, format_string) \
247static ssize_t \
Alan Sternb724ae72005-10-24 15:36:00 -0400248show_##field (struct device *dev, struct device_attribute *attr, \
249 char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250{ \
251 struct usb_interface *intf = to_usb_interface (dev); \
252 \
Alan Sternb724ae72005-10-24 15:36:00 -0400253 return sprintf (buf, format_string, \
254 intf->cur_altsetting->desc.field); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255} \
256static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
257
258usb_intf_attr (bInterfaceNumber, "%02x\n")
259usb_intf_attr (bAlternateSetting, "%2d\n")
260usb_intf_attr (bNumEndpoints, "%02x\n")
261usb_intf_attr (bInterfaceClass, "%02x\n")
262usb_intf_attr (bInterfaceSubClass, "%02x\n")
263usb_intf_attr (bInterfaceProtocol, "%02x\n")
264
Alan Sternb724ae72005-10-24 15:36:00 -0400265static ssize_t show_interface_string(struct device *dev,
266 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267{
268 struct usb_interface *intf;
269 struct usb_device *udev;
270 int len;
271
272 intf = to_usb_interface (dev);
273 udev = interface_to_usbdev (intf);
274 len = snprintf(buf, 256, "%s", intf->cur_altsetting->string);
275 if (len < 0)
276 return 0;
277 buf[len] = '\n';
278 buf[len+1] = 0;
279 return len+1;
280}
281static DEVICE_ATTR(interface, S_IRUGO, show_interface_string, NULL);
282
Alan Sternb724ae72005-10-24 15:36:00 -0400283static ssize_t show_modalias(struct device *dev,
284 struct device_attribute *attr, char *buf)
Greg KH360b52b2005-05-10 06:45:10 -0700285{
286 struct usb_interface *intf;
287 struct usb_device *udev;
Greg Kroah-Hartman75218032005-06-20 21:15:16 -0700288 struct usb_host_interface *alt;
Greg KH360b52b2005-05-10 06:45:10 -0700289
290 intf = to_usb_interface(dev);
291 udev = interface_to_usbdev(intf);
Greg Kroah-Hartman75218032005-06-20 21:15:16 -0700292 alt = intf->cur_altsetting;
Greg KH360b52b2005-05-10 06:45:10 -0700293
Greg Kroah-Hartman75218032005-06-20 21:15:16 -0700294 return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X"
295 "ic%02Xisc%02Xip%02X\n",
296 le16_to_cpu(udev->descriptor.idVendor),
297 le16_to_cpu(udev->descriptor.idProduct),
298 le16_to_cpu(udev->descriptor.bcdDevice),
299 udev->descriptor.bDeviceClass,
300 udev->descriptor.bDeviceSubClass,
301 udev->descriptor.bDeviceProtocol,
302 alt->desc.bInterfaceClass,
303 alt->desc.bInterfaceSubClass,
304 alt->desc.bInterfaceProtocol);
Greg KH360b52b2005-05-10 06:45:10 -0700305}
306static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
307
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308static struct attribute *intf_attrs[] = {
309 &dev_attr_bInterfaceNumber.attr,
310 &dev_attr_bAlternateSetting.attr,
311 &dev_attr_bNumEndpoints.attr,
312 &dev_attr_bInterfaceClass.attr,
313 &dev_attr_bInterfaceSubClass.attr,
314 &dev_attr_bInterfaceProtocol.attr,
Greg KH360b52b2005-05-10 06:45:10 -0700315 &dev_attr_modalias.attr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 NULL,
317};
318static struct attribute_group intf_attr_grp = {
319 .attrs = intf_attrs,
320};
321
Alan Stern4f62efe2005-10-24 16:24:14 -0400322static inline void usb_create_intf_ep_files(struct usb_interface *intf,
323 struct usb_device *udev)
Greg Kroah-Hartman094f16492005-06-20 21:15:16 -0700324{
325 struct usb_host_interface *iface_desc;
326 int i;
327
328 iface_desc = intf->cur_altsetting;
329 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i)
Greg Kroah-Hartman36679ea2006-06-14 12:14:34 -0700330 usb_create_ep_files(&intf->dev, &iface_desc->endpoint[i],
Alan Stern4f62efe2005-10-24 16:24:14 -0400331 udev);
Greg Kroah-Hartman094f16492005-06-20 21:15:16 -0700332}
333
Alan Sternbe69e5b2005-10-25 15:56:06 -0400334static inline void usb_remove_intf_ep_files(struct usb_interface *intf)
Greg Kroah-Hartman094f16492005-06-20 21:15:16 -0700335{
336 struct usb_host_interface *iface_desc;
337 int i;
338
339 iface_desc = intf->cur_altsetting;
340 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i)
Alan Sternbe69e5b2005-10-25 15:56:06 -0400341 usb_remove_ep_files(&iface_desc->endpoint[i]);
Greg Kroah-Hartman094f16492005-06-20 21:15:16 -0700342}
343
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344void usb_create_sysfs_intf_files (struct usb_interface *intf)
345{
Alan Stern4f62efe2005-10-24 16:24:14 -0400346 struct usb_device *udev = interface_to_usbdev(intf);
347 struct usb_host_interface *alt = intf->cur_altsetting;
348
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 sysfs_create_group(&intf->dev.kobj, &intf_attr_grp);
350
Alan Stern4f62efe2005-10-24 16:24:14 -0400351 if (alt->string == NULL)
352 alt->string = usb_cache_string(udev, alt->desc.iInterface);
353 if (alt->string)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 device_create_file(&intf->dev, &dev_attr_interface);
Alan Stern4f62efe2005-10-24 16:24:14 -0400355 usb_create_intf_ep_files(intf, udev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356}
357
358void usb_remove_sysfs_intf_files (struct usb_interface *intf)
359{
Greg Kroah-Hartman094f16492005-06-20 21:15:16 -0700360 usb_remove_intf_ep_files(intf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp);
362
363 if (intf->cur_altsetting->string)
364 device_remove_file(&intf->dev, &dev_attr_interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365}