sysfs.c 18.2 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13
/*
 * drivers/usb/core/sysfs.c
 *
 * (C) Copyright 2002 David Brownell
 * (C) Copyright 2002,2004 Greg Kroah-Hartman
 * (C) Copyright 2002,2004 IBM Corp.
 *
 * All of the sysfs file attributes for usb devices and interfaces.
 *
 */


#include <linux/kernel.h>
14
#include <linux/string.h>
L
Linus Torvalds 已提交
15 16 17 18 19
#include <linux/usb.h>
#include "usb.h"

/* Active configuration fields */
#define usb_actconfig_show(field, multiplier, format_string)		\
20
static ssize_t  show_##field(struct device *dev,			\
21
		struct device_attribute *attr, char *buf)		\
L
Linus Torvalds 已提交
22 23 24 25
{									\
	struct usb_device *udev;					\
	struct usb_host_config *actconfig;				\
									\
26
	udev = to_usb_device(dev);					\
L
Linus Torvalds 已提交
27 28
	actconfig = udev->actconfig;					\
	if (actconfig)							\
29
		return sprintf(buf, format_string,			\
L
Linus Torvalds 已提交
30 31 32 33 34 35 36 37 38
				actconfig->desc.field * multiplier);	\
	else								\
		return 0;						\
}									\

#define usb_actconfig_attr(field, multiplier, format_string)		\
usb_actconfig_show(field, multiplier, format_string)			\
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);

39 40 41
usb_actconfig_attr(bNumInterfaces, 1, "%2d\n")
usb_actconfig_attr(bmAttributes, 1, "%2x\n")
usb_actconfig_attr(bMaxPower, 2, "%3dmA\n")
L
Linus Torvalds 已提交
42

43 44
static ssize_t show_configuration_string(struct device *dev,
		struct device_attribute *attr, char *buf)
L
Linus Torvalds 已提交
45 46 47 48
{
	struct usb_device *udev;
	struct usb_host_config *actconfig;

49
	udev = to_usb_device(dev);
L
Linus Torvalds 已提交
50 51 52
	actconfig = udev->actconfig;
	if ((!actconfig) || (!actconfig->string))
		return 0;
53
	return sprintf(buf, "%s\n", actconfig->string);
L
Linus Torvalds 已提交
54 55 56 57 58 59 60
}
static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL);

/* configuration value is always present, and r/w */
usb_actconfig_show(bConfigurationValue, 1, "%u\n");

static ssize_t
61
set_bConfigurationValue(struct device *dev, struct device_attribute *attr,
62
		const char *buf, size_t count)
L
Linus Torvalds 已提交
63
{
64
	struct usb_device	*udev = to_usb_device(dev);
L
Linus Torvalds 已提交
65 66
	int			config, value;

67
	if (sscanf(buf, "%d", &config) != 1 || config < -1 || config > 255)
L
Linus Torvalds 已提交
68 69
		return -EINVAL;
	usb_lock_device(udev);
70
	value = usb_set_configuration(udev, config);
L
Linus Torvalds 已提交
71 72 73 74 75 76 77 78 79
	usb_unlock_device(udev);
	return (value < 0) ? value : count;
}

static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR, 
		show_bConfigurationValue, set_bConfigurationValue);

/* String fields */
#define usb_string_attr(name)						\
80 81
static ssize_t  show_##name(struct device *dev,				\
		struct device_attribute *attr, char *buf)		\
L
Linus Torvalds 已提交
82 83 84
{									\
	struct usb_device *udev;					\
									\
85
	udev = to_usb_device(dev);					\
86
	return sprintf(buf, "%s\n", udev->name);			\
L
Linus Torvalds 已提交
87 88 89 90 91 92 93 94
}									\
static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);

usb_string_attr(product);
usb_string_attr(manufacturer);
usb_string_attr(serial);

static ssize_t
95
show_speed(struct device *dev, struct device_attribute *attr, char *buf)
L
Linus Torvalds 已提交
96 97 98 99
{
	struct usb_device *udev;
	char *speed;

100
	udev = to_usb_device(dev);
L
Linus Torvalds 已提交
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115

	switch (udev->speed) {
	case USB_SPEED_LOW:
		speed = "1.5";
		break;
	case USB_SPEED_UNKNOWN:
	case USB_SPEED_FULL:
		speed = "12";
		break;
	case USB_SPEED_HIGH:
		speed = "480";
		break;
	default:
		speed = "unknown";
	}
116
	return sprintf(buf, "%s\n", speed);
L
Linus Torvalds 已提交
117 118 119
}
static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL);

120 121 122 123 124 125 126 127 128 129
static ssize_t
show_busnum(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct usb_device *udev;

	udev = to_usb_device(dev);
	return sprintf(buf, "%d\n", udev->bus->busnum);
}
static DEVICE_ATTR(busnum, S_IRUGO, show_busnum, NULL);

L
Linus Torvalds 已提交
130
static ssize_t
131
show_devnum(struct device *dev, struct device_attribute *attr, char *buf)
L
Linus Torvalds 已提交
132 133 134
{
	struct usb_device *udev;

135 136
	udev = to_usb_device(dev);
	return sprintf(buf, "%d\n", udev->devnum);
L
Linus Torvalds 已提交
137 138 139 140
}
static DEVICE_ATTR(devnum, S_IRUGO, show_devnum, NULL);

static ssize_t
141
show_version(struct device *dev, struct device_attribute *attr, char *buf)
L
Linus Torvalds 已提交
142 143 144 145 146 147 148 149 150 151 152
{
	struct usb_device *udev;
	u16 bcdUSB;

	udev = to_usb_device(dev);
	bcdUSB = le16_to_cpu(udev->descriptor.bcdUSB);
	return sprintf(buf, "%2x.%02x\n", bcdUSB >> 8, bcdUSB & 0xff);
}
static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);

static ssize_t
153
show_maxchild(struct device *dev, struct device_attribute *attr, char *buf)
L
Linus Torvalds 已提交
154 155 156
{
	struct usb_device *udev;

157 158
	udev = to_usb_device(dev);
	return sprintf(buf, "%d\n", udev->maxchild);
L
Linus Torvalds 已提交
159 160 161
}
static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL);

162 163 164 165 166 167 168 169 170 171
static ssize_t
show_quirks(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct usb_device *udev;

	udev = to_usb_device(dev);
	return sprintf(buf, "0x%x\n", udev->quirks);
}
static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL);

172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238

#if defined(CONFIG_USB_PERSIST) || defined(CONFIG_USB_SUSPEND)
static const char power_group[] = "power";
#endif

#ifdef	CONFIG_USB_PERSIST

static ssize_t
show_persist(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct usb_device *udev = to_usb_device(dev);

	return sprintf(buf, "%d\n", udev->persist_enabled);
}

static ssize_t
set_persist(struct device *dev, struct device_attribute *attr,
		const char *buf, size_t count)
{
	struct usb_device *udev = to_usb_device(dev);
	int value;

	/* Hubs are always enabled for USB_PERSIST */
	if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)
		return -EPERM;

	if (sscanf(buf, "%d", &value) != 1)
		return -EINVAL;
	usb_pm_lock(udev);
	udev->persist_enabled = !!value;
	usb_pm_unlock(udev);
	return count;
}

static DEVICE_ATTR(persist, S_IRUGO | S_IWUSR, show_persist, set_persist);

static int add_persist_attributes(struct device *dev)
{
	int rc = 0;

	if (is_usb_device(dev)) {
		struct usb_device *udev = to_usb_device(dev);

		/* Hubs are automatically enabled for USB_PERSIST */
		if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)
			udev->persist_enabled = 1;
		rc = sysfs_add_file_to_group(&dev->kobj,
				&dev_attr_persist.attr,
				power_group);
	}
	return rc;
}

static void remove_persist_attributes(struct device *dev)
{
	sysfs_remove_file_from_group(&dev->kobj,
			&dev_attr_persist.attr,
			power_group);
}

#else

#define add_persist_attributes(dev)	0
#define remove_persist_attributes(dev)	do {} while (0)

#endif	/* CONFIG_USB_PERSIST */

239 240 241 242 243 244 245
#ifdef	CONFIG_USB_SUSPEND

static ssize_t
show_autosuspend(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct usb_device *udev = to_usb_device(dev);

246
	return sprintf(buf, "%d\n", udev->autosuspend_delay / HZ);
247 248 249 250 251 252 253
}

static ssize_t
set_autosuspend(struct device *dev, struct device_attribute *attr,
		const char *buf, size_t count)
{
	struct usb_device *udev = to_usb_device(dev);
254
	int value;
255

256 257
	if (sscanf(buf, "%d", &value) != 1 || value >= INT_MAX/HZ ||
			value <= - INT_MAX/HZ)
258 259 260 261
		return -EINVAL;
	value *= HZ;

	udev->autosuspend_delay = value;
262
	if (value >= 0)
263
		usb_try_autosuspend_device(udev);
264
	else {
265 266
		if (usb_autoresume_device(udev) == 0)
			usb_autosuspend_device(udev);
267
	}
268 269 270 271 272 273
	return count;
}

static DEVICE_ATTR(autosuspend, S_IRUGO | S_IWUSR,
		show_autosuspend, set_autosuspend);

274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
static const char on_string[] = "on";
static const char auto_string[] = "auto";
static const char suspend_string[] = "suspend";

static ssize_t
show_level(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct usb_device *udev = to_usb_device(dev);
	const char *p = auto_string;

	if (udev->state == USB_STATE_SUSPENDED) {
		if (udev->autoresume_disabled)
			p = suspend_string;
	} else {
		if (udev->autosuspend_disabled)
			p = on_string;
	}
	return sprintf(buf, "%s\n", p);
}

static ssize_t
set_level(struct device *dev, struct device_attribute *attr,
		const char *buf, size_t count)
{
	struct usb_device *udev = to_usb_device(dev);
	int len = count;
	char *cp;
	int rc = 0;
302
	int old_autosuspend_disabled, old_autoresume_disabled;
303 304 305 306 307 308

	cp = memchr(buf, '\n', count);
	if (cp)
		len = cp - buf;

	usb_lock_device(udev);
309 310
	old_autosuspend_disabled = udev->autosuspend_disabled;
	old_autoresume_disabled = udev->autoresume_disabled;
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335

	/* Setting the flags without calling usb_pm_lock is a subject to
	 * races, but who cares...
	 */
	if (len == sizeof on_string - 1 &&
			strncmp(buf, on_string, len) == 0) {
		udev->autosuspend_disabled = 1;
		udev->autoresume_disabled = 0;
		rc = usb_external_resume_device(udev);

	} else if (len == sizeof auto_string - 1 &&
			strncmp(buf, auto_string, len) == 0) {
		udev->autosuspend_disabled = 0;
		udev->autoresume_disabled = 0;
		rc = usb_external_resume_device(udev);

	} else if (len == sizeof suspend_string - 1 &&
			strncmp(buf, suspend_string, len) == 0) {
		udev->autosuspend_disabled = 0;
		udev->autoresume_disabled = 1;
		rc = usb_external_suspend_device(udev, PMSG_SUSPEND);

	} else
		rc = -EINVAL;

336 337 338 339
	if (rc) {
		udev->autosuspend_disabled = old_autosuspend_disabled;
		udev->autoresume_disabled = old_autoresume_disabled;
	}
340 341 342 343 344 345
	usb_unlock_device(udev);
	return (rc < 0 ? rc : count);
}

static DEVICE_ATTR(level, S_IRUGO | S_IWUSR, show_level, set_level);

346 347 348 349
static int add_power_attributes(struct device *dev)
{
	int rc = 0;

350
	if (is_usb_device(dev)) {
351 352 353
		rc = sysfs_add_file_to_group(&dev->kobj,
				&dev_attr_autosuspend.attr,
				power_group);
354 355 356 357 358
		if (rc == 0)
			rc = sysfs_add_file_to_group(&dev->kobj,
					&dev_attr_level.attr,
					power_group);
	}
359 360 361 362 363
	return rc;
}

static void remove_power_attributes(struct device *dev)
{
364 365 366
	sysfs_remove_file_from_group(&dev->kobj,
			&dev_attr_level.attr,
			power_group);
367 368 369 370 371 372 373 374 375 376 377 378
	sysfs_remove_file_from_group(&dev->kobj,
			&dev_attr_autosuspend.attr,
			power_group);
}

#else

#define add_power_attributes(dev)	0
#define remove_power_attributes(dev)	do {} while (0)

#endif	/* CONFIG_USB_SUSPEND */

379

L
Linus Torvalds 已提交
380 381 382
/* Descriptor fields */
#define usb_descriptor_attr_le16(field, format_string)			\
static ssize_t								\
383
show_##field(struct device *dev, struct device_attribute *attr,	\
384
		char *buf)						\
L
Linus Torvalds 已提交
385 386 387
{									\
	struct usb_device *udev;					\
									\
388 389
	udev = to_usb_device(dev);					\
	return sprintf(buf, format_string, 				\
L
Linus Torvalds 已提交
390 391 392 393 394 395 396 397 398 399
			le16_to_cpu(udev->descriptor.field));		\
}									\
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);

usb_descriptor_attr_le16(idVendor, "%04x\n")
usb_descriptor_attr_le16(idProduct, "%04x\n")
usb_descriptor_attr_le16(bcdDevice, "%04x\n")

#define usb_descriptor_attr(field, format_string)			\
static ssize_t								\
400
show_##field(struct device *dev, struct device_attribute *attr,	\
401
		char *buf)						\
L
Linus Torvalds 已提交
402 403 404
{									\
	struct usb_device *udev;					\
									\
405 406
	udev = to_usb_device(dev);					\
	return sprintf(buf, format_string, udev->descriptor.field);	\
L
Linus Torvalds 已提交
407 408 409
}									\
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);

410 411 412 413 414
usb_descriptor_attr(bDeviceClass, "%02x\n")
usb_descriptor_attr(bDeviceSubClass, "%02x\n")
usb_descriptor_attr(bDeviceProtocol, "%02x\n")
usb_descriptor_attr(bNumConfigurations, "%d\n")
usb_descriptor_attr(bMaxPacketSize0, "%d\n")
L
Linus Torvalds 已提交
415 416 417

static struct attribute *dev_attrs[] = {
	/* current configuration's attributes */
418
	&dev_attr_configuration.attr,
L
Linus Torvalds 已提交
419 420 421 422 423 424 425 426 427 428 429 430
	&dev_attr_bNumInterfaces.attr,
	&dev_attr_bConfigurationValue.attr,
	&dev_attr_bmAttributes.attr,
	&dev_attr_bMaxPower.attr,
	/* device attributes */
	&dev_attr_idVendor.attr,
	&dev_attr_idProduct.attr,
	&dev_attr_bcdDevice.attr,
	&dev_attr_bDeviceClass.attr,
	&dev_attr_bDeviceSubClass.attr,
	&dev_attr_bDeviceProtocol.attr,
	&dev_attr_bNumConfigurations.attr,
431
	&dev_attr_bMaxPacketSize0.attr,
L
Linus Torvalds 已提交
432
	&dev_attr_speed.attr,
433
	&dev_attr_busnum.attr,
L
Linus Torvalds 已提交
434 435 436
	&dev_attr_devnum.attr,
	&dev_attr_version.attr,
	&dev_attr_maxchild.attr,
437
	&dev_attr_quirks.attr,
L
Linus Torvalds 已提交
438 439 440 441 442 443
	NULL,
};
static struct attribute_group dev_attr_grp = {
	.attrs = dev_attrs,
};

444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
/* Binary descriptors */

static ssize_t
read_descriptors(struct kobject *kobj, struct bin_attribute *attr,
		char *buf, loff_t off, size_t count)
{
	struct usb_device *udev = to_usb_device(
			container_of(kobj, struct device, kobj));
	size_t nleft = count;
	size_t srclen, n;

	usb_lock_device(udev);

	/* The binary attribute begins with the device descriptor */
	srclen = sizeof(struct usb_device_descriptor);
	if (off < srclen) {
		n = min_t(size_t, nleft, srclen - off);
		memcpy(buf, off + (char *) &udev->descriptor, n);
		nleft -= n;
		buf += n;
		off = 0;
	} else {
		off -= srclen;
	}

	/* Then follows the raw descriptor entry for the current
	 * configuration (config plus subsidiary descriptors).
	 */
	if (udev->actconfig) {
		int cfgno = udev->actconfig - udev->config;

		srclen = __le16_to_cpu(udev->actconfig->desc.wTotalLength);
		if (off < srclen) {
			n = min_t(size_t, nleft, srclen - off);
			memcpy(buf, off + udev->rawdescriptors[cfgno], n);
			nleft -= n;
		}
	}
	usb_unlock_device(udev);
	return count - nleft;
}

static struct bin_attribute dev_bin_attr_descriptors = {
	.attr = {.name = "descriptors", .mode = 0444},
	.read = read_descriptors,
	.size = 18 + 65535,	/* dev descr + max-size raw descriptor */
};

492
int usb_create_sysfs_dev_files(struct usb_device *udev)
L
Linus Torvalds 已提交
493 494
{
	struct device *dev = &udev->dev;
495
	int retval;
L
Linus Torvalds 已提交
496

497 498 499
	retval = sysfs_create_group(&dev->kobj, &dev_attr_grp);
	if (retval)
		return retval;
L
Linus Torvalds 已提交
500

501 502 503 504
	retval = device_create_bin_file(dev, &dev_bin_attr_descriptors);
	if (retval)
		goto error;

505 506 507 508
	retval = add_persist_attributes(dev);
	if (retval)
		goto error;

509 510 511 512
	retval = add_power_attributes(dev);
	if (retval)
		goto error;

513
	if (udev->manufacturer) {
514
		retval = device_create_file(dev, &dev_attr_manufacturer);
515 516 517 518
		if (retval)
			goto error;
	}
	if (udev->product) {
519
		retval = device_create_file(dev, &dev_attr_product);
520 521 522 523
		if (retval)
			goto error;
	}
	if (udev->serial) {
524
		retval = device_create_file(dev, &dev_attr_serial);
525 526 527 528 529 530 531 532
		if (retval)
			goto error;
	}
	retval = usb_create_ep_files(dev, &udev->ep0, udev);
	if (retval)
		goto error;
	return 0;
error:
A
Alan Stern 已提交
533
	usb_remove_sysfs_dev_files(udev);
534
	return retval;
L
Linus Torvalds 已提交
535 536
}

537
void usb_remove_sysfs_dev_files(struct usb_device *udev)
L
Linus Torvalds 已提交
538 539 540
{
	struct device *dev = &udev->dev;

541
	usb_remove_ep_files(&udev->ep0);
A
Alan Stern 已提交
542 543 544
	device_remove_file(dev, &dev_attr_manufacturer);
	device_remove_file(dev, &dev_attr_product);
	device_remove_file(dev, &dev_attr_serial);
545
	remove_power_attributes(dev);
546
	remove_persist_attributes(dev);
547
	device_remove_bin_file(dev, &dev_bin_attr_descriptors);
L
Linus Torvalds 已提交
548 549 550
	sysfs_remove_group(&dev->kobj, &dev_attr_grp);
}

551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569
/* Interface Accociation Descriptor fields */
#define usb_intf_assoc_attr(field, format_string)			\
static ssize_t								\
show_iad_##field (struct device *dev, struct device_attribute *attr,	\
		char *buf)						\
{									\
	struct usb_interface *intf = to_usb_interface (dev);		\
									\
	return sprintf (buf, format_string,				\
			intf->intf_assoc->field); 		\
}									\
static DEVICE_ATTR(iad_##field, S_IRUGO, show_iad_##field, NULL);

usb_intf_assoc_attr (bFirstInterface, "%02x\n")
usb_intf_assoc_attr (bInterfaceCount, "%02d\n")
usb_intf_assoc_attr (bFunctionClass, "%02x\n")
usb_intf_assoc_attr (bFunctionSubClass, "%02x\n")
usb_intf_assoc_attr (bFunctionProtocol, "%02x\n")

L
Linus Torvalds 已提交
570 571 572
/* Interface fields */
#define usb_intf_attr(field, format_string)				\
static ssize_t								\
573
show_##field(struct device *dev, struct device_attribute *attr,	\
574
		char *buf)						\
L
Linus Torvalds 已提交
575
{									\
576
	struct usb_interface *intf = to_usb_interface(dev);		\
L
Linus Torvalds 已提交
577
									\
578
	return sprintf(buf, format_string,				\
579
			intf->cur_altsetting->desc.field); 		\
L
Linus Torvalds 已提交
580 581 582
}									\
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);

583 584 585 586 587 588
usb_intf_attr(bInterfaceNumber, "%02x\n")
usb_intf_attr(bAlternateSetting, "%2d\n")
usb_intf_attr(bNumEndpoints, "%02x\n")
usb_intf_attr(bInterfaceClass, "%02x\n")
usb_intf_attr(bInterfaceSubClass, "%02x\n")
usb_intf_attr(bInterfaceProtocol, "%02x\n")
L
Linus Torvalds 已提交
589

590 591
static ssize_t show_interface_string(struct device *dev,
		struct device_attribute *attr, char *buf)
L
Linus Torvalds 已提交
592 593 594 595 596
{
	struct usb_interface *intf;
	struct usb_device *udev;
	int len;

597 598
	intf = to_usb_interface(dev);
	udev = interface_to_usbdev(intf);
L
Linus Torvalds 已提交
599 600 601 602 603 604 605 606 607
	len = snprintf(buf, 256, "%s", intf->cur_altsetting->string);
	if (len < 0)
		return 0;
	buf[len] = '\n';
	buf[len+1] = 0;
	return len+1;
}
static DEVICE_ATTR(interface, S_IRUGO, show_interface_string, NULL);

608 609
static ssize_t show_modalias(struct device *dev,
		struct device_attribute *attr, char *buf)
610 611 612
{
	struct usb_interface *intf;
	struct usb_device *udev;
613
	struct usb_host_interface *alt;
614 615 616

	intf = to_usb_interface(dev);
	udev = interface_to_usbdev(intf);
617 618 619 620 621 622 623 624 625 626 627 628 629
	alt = intf->cur_altsetting;

	return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X"
			"ic%02Xisc%02Xip%02X\n",
			le16_to_cpu(udev->descriptor.idVendor),
			le16_to_cpu(udev->descriptor.idProduct),
			le16_to_cpu(udev->descriptor.bcdDevice),
			udev->descriptor.bDeviceClass,
			udev->descriptor.bDeviceSubClass,
			udev->descriptor.bDeviceProtocol,
			alt->desc.bInterfaceClass,
			alt->desc.bInterfaceSubClass,
			alt->desc.bInterfaceProtocol);
630 631 632
}
static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);

633 634 635 636 637 638 639 640 641 642 643 644
static struct attribute *intf_assoc_attrs[] = {
	&dev_attr_iad_bFirstInterface.attr,
	&dev_attr_iad_bInterfaceCount.attr,
	&dev_attr_iad_bFunctionClass.attr,
	&dev_attr_iad_bFunctionSubClass.attr,
	&dev_attr_iad_bFunctionProtocol.attr,
	NULL,
};
static struct attribute_group intf_assoc_attr_grp = {
	.attrs = intf_assoc_attrs,
};

L
Linus Torvalds 已提交
645 646 647 648 649 650 651
static struct attribute *intf_attrs[] = {
	&dev_attr_bInterfaceNumber.attr,
	&dev_attr_bAlternateSetting.attr,
	&dev_attr_bNumEndpoints.attr,
	&dev_attr_bInterfaceClass.attr,
	&dev_attr_bInterfaceSubClass.attr,
	&dev_attr_bInterfaceProtocol.attr,
652
	&dev_attr_modalias.attr,
L
Linus Torvalds 已提交
653 654 655 656 657 658
	NULL,
};
static struct attribute_group intf_attr_grp = {
	.attrs = intf_attrs,
};

659 660
static inline void usb_create_intf_ep_files(struct usb_interface *intf,
		struct usb_device *udev)
661 662 663 664 665 666
{
	struct usb_host_interface *iface_desc;
	int i;

	iface_desc = intf->cur_altsetting;
	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i)
667
		usb_create_ep_files(&intf->dev, &iface_desc->endpoint[i],
668
				udev);
669 670
}

671
static inline void usb_remove_intf_ep_files(struct usb_interface *intf)
672 673 674 675 676 677
{
	struct usb_host_interface *iface_desc;
	int i;

	iface_desc = intf->cur_altsetting;
	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i)
678
		usb_remove_ep_files(&iface_desc->endpoint[i]);
679 680
}

681
int usb_create_sysfs_intf_files(struct usb_interface *intf)
L
Linus Torvalds 已提交
682
{
A
Alan Stern 已提交
683
	struct device *dev = &intf->dev;
684 685
	struct usb_device *udev = interface_to_usbdev(intf);
	struct usb_host_interface *alt = intf->cur_altsetting;
686
	int retval;
687

A
Alan Stern 已提交
688
	retval = sysfs_create_group(&dev->kobj, &intf_attr_grp);
689
	if (retval)
A
Alan Stern 已提交
690
		return retval;
L
Linus Torvalds 已提交
691

692 693 694
	if (alt->string == NULL)
		alt->string = usb_cache_string(udev, alt->desc.iInterface);
	if (alt->string)
A
Alan Stern 已提交
695
		retval = device_create_file(dev, &dev_attr_interface);
696 697
	if (intf->intf_assoc)
		retval = sysfs_create_group(&dev->kobj, &intf_assoc_attr_grp);
698
	usb_create_intf_ep_files(intf, udev);
699
	return 0;
L
Linus Torvalds 已提交
700 701
}

702
void usb_remove_sysfs_intf_files(struct usb_interface *intf)
L
Linus Torvalds 已提交
703
{
A
Alan Stern 已提交
704
	struct device *dev = &intf->dev;
L
Linus Torvalds 已提交
705

A
Alan Stern 已提交
706 707 708
	usb_remove_intf_ep_files(intf);
	device_remove_file(dev, &dev_attr_interface);
	sysfs_remove_group(&dev->kobj, &intf_attr_grp);
709
	sysfs_remove_group(&intf->dev.kobj, &intf_assoc_attr_grp);
L
Linus Torvalds 已提交
710
}