162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * drivers/usb/core/sysfs.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * (C) Copyright 2002 David Brownell
662306a36Sopenharmony_ci * (C) Copyright 2002,2004 Greg Kroah-Hartman
762306a36Sopenharmony_ci * (C) Copyright 2002,2004 IBM Corp.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * All of the sysfs file attributes for usb devices and interfaces.
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * Released under the GPLv2 only.
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/kernel.h>
1662306a36Sopenharmony_ci#include <linux/kstrtox.h>
1762306a36Sopenharmony_ci#include <linux/string.h>
1862306a36Sopenharmony_ci#include <linux/usb.h>
1962306a36Sopenharmony_ci#include <linux/usb/hcd.h>
2062306a36Sopenharmony_ci#include <linux/usb/quirks.h>
2162306a36Sopenharmony_ci#include <linux/of.h>
2262306a36Sopenharmony_ci#include "usb.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/* Active configuration fields */
2562306a36Sopenharmony_ci#define usb_actconfig_show(field, format_string)			\
2662306a36Sopenharmony_cistatic ssize_t field##_show(struct device *dev,				\
2762306a36Sopenharmony_ci			    struct device_attribute *attr, char *buf)	\
2862306a36Sopenharmony_ci{									\
2962306a36Sopenharmony_ci	struct usb_device *udev;					\
3062306a36Sopenharmony_ci	struct usb_host_config *actconfig;				\
3162306a36Sopenharmony_ci	ssize_t rc;							\
3262306a36Sopenharmony_ci									\
3362306a36Sopenharmony_ci	udev = to_usb_device(dev);					\
3462306a36Sopenharmony_ci	rc = usb_lock_device_interruptible(udev);			\
3562306a36Sopenharmony_ci	if (rc < 0)							\
3662306a36Sopenharmony_ci		return -EINTR;						\
3762306a36Sopenharmony_ci	actconfig = udev->actconfig;					\
3862306a36Sopenharmony_ci	if (actconfig)							\
3962306a36Sopenharmony_ci		rc = sysfs_emit(buf, format_string,			\
4062306a36Sopenharmony_ci				actconfig->desc.field);			\
4162306a36Sopenharmony_ci	usb_unlock_device(udev);					\
4262306a36Sopenharmony_ci	return rc;							\
4362306a36Sopenharmony_ci}									\
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#define usb_actconfig_attr(field, format_string)		\
4662306a36Sopenharmony_ci	usb_actconfig_show(field, format_string)		\
4762306a36Sopenharmony_ci	static DEVICE_ATTR_RO(field)
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ciusb_actconfig_attr(bNumInterfaces, "%2d\n");
5062306a36Sopenharmony_ciusb_actconfig_attr(bmAttributes, "%2x\n");
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic ssize_t bMaxPower_show(struct device *dev,
5362306a36Sopenharmony_ci		struct device_attribute *attr, char *buf)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	struct usb_device *udev;
5662306a36Sopenharmony_ci	struct usb_host_config *actconfig;
5762306a36Sopenharmony_ci	ssize_t rc;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	udev = to_usb_device(dev);
6062306a36Sopenharmony_ci	rc = usb_lock_device_interruptible(udev);
6162306a36Sopenharmony_ci	if (rc < 0)
6262306a36Sopenharmony_ci		return -EINTR;
6362306a36Sopenharmony_ci	actconfig = udev->actconfig;
6462306a36Sopenharmony_ci	if (actconfig)
6562306a36Sopenharmony_ci		rc = sysfs_emit(buf, "%dmA\n", usb_get_max_power(udev, actconfig));
6662306a36Sopenharmony_ci	usb_unlock_device(udev);
6762306a36Sopenharmony_ci	return rc;
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_cistatic DEVICE_ATTR_RO(bMaxPower);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic ssize_t configuration_show(struct device *dev,
7262306a36Sopenharmony_ci		struct device_attribute *attr, char *buf)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	struct usb_device *udev;
7562306a36Sopenharmony_ci	struct usb_host_config *actconfig;
7662306a36Sopenharmony_ci	ssize_t rc;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	udev = to_usb_device(dev);
7962306a36Sopenharmony_ci	rc = usb_lock_device_interruptible(udev);
8062306a36Sopenharmony_ci	if (rc < 0)
8162306a36Sopenharmony_ci		return -EINTR;
8262306a36Sopenharmony_ci	actconfig = udev->actconfig;
8362306a36Sopenharmony_ci	if (actconfig && actconfig->string)
8462306a36Sopenharmony_ci		rc = sysfs_emit(buf, "%s\n", actconfig->string);
8562306a36Sopenharmony_ci	usb_unlock_device(udev);
8662306a36Sopenharmony_ci	return rc;
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(configuration);
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci/* configuration value is always present, and r/w */
9162306a36Sopenharmony_ciusb_actconfig_show(bConfigurationValue, "%u\n");
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic ssize_t bConfigurationValue_store(struct device *dev,
9462306a36Sopenharmony_ci					 struct device_attribute *attr,
9562306a36Sopenharmony_ci					 const char *buf, size_t count)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	struct usb_device	*udev = to_usb_device(dev);
9862306a36Sopenharmony_ci	int			config, value, rc;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	if (sscanf(buf, "%d", &config) != 1 || config < -1 || config > 255)
10162306a36Sopenharmony_ci		return -EINVAL;
10262306a36Sopenharmony_ci	rc = usb_lock_device_interruptible(udev);
10362306a36Sopenharmony_ci	if (rc < 0)
10462306a36Sopenharmony_ci		return -EINTR;
10562306a36Sopenharmony_ci	value = usb_set_configuration(udev, config);
10662306a36Sopenharmony_ci	usb_unlock_device(udev);
10762306a36Sopenharmony_ci	return (value < 0) ? value : count;
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_cistatic DEVICE_ATTR_IGNORE_LOCKDEP(bConfigurationValue, S_IRUGO | S_IWUSR,
11062306a36Sopenharmony_ci		bConfigurationValue_show, bConfigurationValue_store);
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci#ifdef CONFIG_OF
11362306a36Sopenharmony_cistatic ssize_t devspec_show(struct device *dev, struct device_attribute *attr,
11462306a36Sopenharmony_ci			    char *buf)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	struct device_node *of_node = dev->of_node;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	return sysfs_emit(buf, "%pOF\n", of_node);
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(devspec);
12162306a36Sopenharmony_ci#endif
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci/* String fields */
12462306a36Sopenharmony_ci#define usb_string_attr(name)						\
12562306a36Sopenharmony_cistatic ssize_t  name##_show(struct device *dev,				\
12662306a36Sopenharmony_ci		struct device_attribute *attr, char *buf)		\
12762306a36Sopenharmony_ci{									\
12862306a36Sopenharmony_ci	struct usb_device *udev;					\
12962306a36Sopenharmony_ci	int retval;							\
13062306a36Sopenharmony_ci									\
13162306a36Sopenharmony_ci	udev = to_usb_device(dev);					\
13262306a36Sopenharmony_ci	retval = usb_lock_device_interruptible(udev);			\
13362306a36Sopenharmony_ci	if (retval < 0)							\
13462306a36Sopenharmony_ci		return -EINTR;						\
13562306a36Sopenharmony_ci	retval = sysfs_emit(buf, "%s\n", udev->name);			\
13662306a36Sopenharmony_ci	usb_unlock_device(udev);					\
13762306a36Sopenharmony_ci	return retval;							\
13862306a36Sopenharmony_ci}									\
13962306a36Sopenharmony_cistatic DEVICE_ATTR_RO(name)
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ciusb_string_attr(product);
14262306a36Sopenharmony_ciusb_string_attr(manufacturer);
14362306a36Sopenharmony_ciusb_string_attr(serial);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic ssize_t speed_show(struct device *dev, struct device_attribute *attr,
14662306a36Sopenharmony_ci			  char *buf)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	struct usb_device *udev;
14962306a36Sopenharmony_ci	char *speed;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	udev = to_usb_device(dev);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	switch (udev->speed) {
15462306a36Sopenharmony_ci	case USB_SPEED_LOW:
15562306a36Sopenharmony_ci		speed = "1.5";
15662306a36Sopenharmony_ci		break;
15762306a36Sopenharmony_ci	case USB_SPEED_UNKNOWN:
15862306a36Sopenharmony_ci	case USB_SPEED_FULL:
15962306a36Sopenharmony_ci		speed = "12";
16062306a36Sopenharmony_ci		break;
16162306a36Sopenharmony_ci	case USB_SPEED_HIGH:
16262306a36Sopenharmony_ci		speed = "480";
16362306a36Sopenharmony_ci		break;
16462306a36Sopenharmony_ci	case USB_SPEED_SUPER:
16562306a36Sopenharmony_ci		speed = "5000";
16662306a36Sopenharmony_ci		break;
16762306a36Sopenharmony_ci	case USB_SPEED_SUPER_PLUS:
16862306a36Sopenharmony_ci		if (udev->ssp_rate == USB_SSP_GEN_2x2)
16962306a36Sopenharmony_ci			speed = "20000";
17062306a36Sopenharmony_ci		else
17162306a36Sopenharmony_ci			speed = "10000";
17262306a36Sopenharmony_ci		break;
17362306a36Sopenharmony_ci	default:
17462306a36Sopenharmony_ci		speed = "unknown";
17562306a36Sopenharmony_ci	}
17662306a36Sopenharmony_ci	return sysfs_emit(buf, "%s\n", speed);
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(speed);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic ssize_t rx_lanes_show(struct device *dev, struct device_attribute *attr,
18162306a36Sopenharmony_ci			  char *buf)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	struct usb_device *udev;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	udev = to_usb_device(dev);
18662306a36Sopenharmony_ci	return sysfs_emit(buf, "%d\n", udev->rx_lanes);
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(rx_lanes);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic ssize_t tx_lanes_show(struct device *dev, struct device_attribute *attr,
19162306a36Sopenharmony_ci			  char *buf)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	struct usb_device *udev;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	udev = to_usb_device(dev);
19662306a36Sopenharmony_ci	return sysfs_emit(buf, "%d\n", udev->tx_lanes);
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(tx_lanes);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic ssize_t busnum_show(struct device *dev, struct device_attribute *attr,
20162306a36Sopenharmony_ci			   char *buf)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	struct usb_device *udev;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	udev = to_usb_device(dev);
20662306a36Sopenharmony_ci	return sysfs_emit(buf, "%d\n", udev->bus->busnum);
20762306a36Sopenharmony_ci}
20862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(busnum);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistatic ssize_t devnum_show(struct device *dev, struct device_attribute *attr,
21162306a36Sopenharmony_ci			   char *buf)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	struct usb_device *udev;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	udev = to_usb_device(dev);
21662306a36Sopenharmony_ci	return sysfs_emit(buf, "%d\n", udev->devnum);
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(devnum);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cistatic ssize_t devpath_show(struct device *dev, struct device_attribute *attr,
22162306a36Sopenharmony_ci			    char *buf)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	struct usb_device *udev;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	udev = to_usb_device(dev);
22662306a36Sopenharmony_ci	return sysfs_emit(buf, "%s\n", udev->devpath);
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(devpath);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic ssize_t version_show(struct device *dev, struct device_attribute *attr,
23162306a36Sopenharmony_ci			    char *buf)
23262306a36Sopenharmony_ci{
23362306a36Sopenharmony_ci	struct usb_device *udev;
23462306a36Sopenharmony_ci	u16 bcdUSB;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	udev = to_usb_device(dev);
23762306a36Sopenharmony_ci	bcdUSB = le16_to_cpu(udev->descriptor.bcdUSB);
23862306a36Sopenharmony_ci	return sysfs_emit(buf, "%2x.%02x\n", bcdUSB >> 8, bcdUSB & 0xff);
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(version);
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_cistatic ssize_t maxchild_show(struct device *dev, struct device_attribute *attr,
24362306a36Sopenharmony_ci			     char *buf)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	struct usb_device *udev;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	udev = to_usb_device(dev);
24862306a36Sopenharmony_ci	return sysfs_emit(buf, "%d\n", udev->maxchild);
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(maxchild);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic ssize_t quirks_show(struct device *dev, struct device_attribute *attr,
25362306a36Sopenharmony_ci			   char *buf)
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	struct usb_device *udev;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	udev = to_usb_device(dev);
25862306a36Sopenharmony_ci	return sysfs_emit(buf, "0x%x\n", udev->quirks);
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(quirks);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic ssize_t avoid_reset_quirk_show(struct device *dev,
26362306a36Sopenharmony_ci				      struct device_attribute *attr, char *buf)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	struct usb_device *udev;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	udev = to_usb_device(dev);
26862306a36Sopenharmony_ci	return sysfs_emit(buf, "%d\n", !!(udev->quirks & USB_QUIRK_RESET));
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic ssize_t avoid_reset_quirk_store(struct device *dev,
27262306a36Sopenharmony_ci				      struct device_attribute *attr,
27362306a36Sopenharmony_ci				      const char *buf, size_t count)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	struct usb_device	*udev = to_usb_device(dev);
27662306a36Sopenharmony_ci	int			val, rc;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	if (sscanf(buf, "%d", &val) != 1 || val < 0 || val > 1)
27962306a36Sopenharmony_ci		return -EINVAL;
28062306a36Sopenharmony_ci	rc = usb_lock_device_interruptible(udev);
28162306a36Sopenharmony_ci	if (rc < 0)
28262306a36Sopenharmony_ci		return -EINTR;
28362306a36Sopenharmony_ci	if (val)
28462306a36Sopenharmony_ci		udev->quirks |= USB_QUIRK_RESET;
28562306a36Sopenharmony_ci	else
28662306a36Sopenharmony_ci		udev->quirks &= ~USB_QUIRK_RESET;
28762306a36Sopenharmony_ci	usb_unlock_device(udev);
28862306a36Sopenharmony_ci	return count;
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_cistatic DEVICE_ATTR_RW(avoid_reset_quirk);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_cistatic ssize_t urbnum_show(struct device *dev, struct device_attribute *attr,
29362306a36Sopenharmony_ci			   char *buf)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	struct usb_device *udev;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	udev = to_usb_device(dev);
29862306a36Sopenharmony_ci	return sysfs_emit(buf, "%d\n", atomic_read(&udev->urbnum));
29962306a36Sopenharmony_ci}
30062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(urbnum);
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_cistatic ssize_t ltm_capable_show(struct device *dev,
30362306a36Sopenharmony_ci				struct device_attribute *attr, char *buf)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	if (usb_device_supports_ltm(to_usb_device(dev)))
30662306a36Sopenharmony_ci		return sysfs_emit(buf, "%s\n", "yes");
30762306a36Sopenharmony_ci	return sysfs_emit(buf, "%s\n", "no");
30862306a36Sopenharmony_ci}
30962306a36Sopenharmony_cistatic DEVICE_ATTR_RO(ltm_capable);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci#ifdef	CONFIG_PM
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_cistatic ssize_t persist_show(struct device *dev, struct device_attribute *attr,
31462306a36Sopenharmony_ci			    char *buf)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	struct usb_device *udev = to_usb_device(dev);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	return sysfs_emit(buf, "%d\n", udev->persist_enabled);
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_cistatic ssize_t persist_store(struct device *dev, struct device_attribute *attr,
32262306a36Sopenharmony_ci			     const char *buf, size_t count)
32362306a36Sopenharmony_ci{
32462306a36Sopenharmony_ci	struct usb_device *udev = to_usb_device(dev);
32562306a36Sopenharmony_ci	int value, rc;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	/* Hubs are always enabled for USB_PERSIST */
32862306a36Sopenharmony_ci	if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)
32962306a36Sopenharmony_ci		return -EPERM;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	if (sscanf(buf, "%d", &value) != 1)
33262306a36Sopenharmony_ci		return -EINVAL;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	rc = usb_lock_device_interruptible(udev);
33562306a36Sopenharmony_ci	if (rc < 0)
33662306a36Sopenharmony_ci		return -EINTR;
33762306a36Sopenharmony_ci	udev->persist_enabled = !!value;
33862306a36Sopenharmony_ci	usb_unlock_device(udev);
33962306a36Sopenharmony_ci	return count;
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_cistatic DEVICE_ATTR_RW(persist);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_cistatic int add_persist_attributes(struct device *dev)
34462306a36Sopenharmony_ci{
34562306a36Sopenharmony_ci	int rc = 0;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	if (is_usb_device(dev)) {
34862306a36Sopenharmony_ci		struct usb_device *udev = to_usb_device(dev);
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci		/* Hubs are automatically enabled for USB_PERSIST,
35162306a36Sopenharmony_ci		 * no point in creating the attribute file.
35262306a36Sopenharmony_ci		 */
35362306a36Sopenharmony_ci		if (udev->descriptor.bDeviceClass != USB_CLASS_HUB)
35462306a36Sopenharmony_ci			rc = sysfs_add_file_to_group(&dev->kobj,
35562306a36Sopenharmony_ci					&dev_attr_persist.attr,
35662306a36Sopenharmony_ci					power_group_name);
35762306a36Sopenharmony_ci	}
35862306a36Sopenharmony_ci	return rc;
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_cistatic void remove_persist_attributes(struct device *dev)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	sysfs_remove_file_from_group(&dev->kobj,
36462306a36Sopenharmony_ci			&dev_attr_persist.attr,
36562306a36Sopenharmony_ci			power_group_name);
36662306a36Sopenharmony_ci}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_cistatic ssize_t connected_duration_show(struct device *dev,
36962306a36Sopenharmony_ci				       struct device_attribute *attr, char *buf)
37062306a36Sopenharmony_ci{
37162306a36Sopenharmony_ci	struct usb_device *udev = to_usb_device(dev);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	return sysfs_emit(buf, "%u\n",
37462306a36Sopenharmony_ci			jiffies_to_msecs(jiffies - udev->connect_time));
37562306a36Sopenharmony_ci}
37662306a36Sopenharmony_cistatic DEVICE_ATTR_RO(connected_duration);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci/*
37962306a36Sopenharmony_ci * If the device is resumed, the last time the device was suspended has
38062306a36Sopenharmony_ci * been pre-subtracted from active_duration.  We add the current time to
38162306a36Sopenharmony_ci * get the duration that the device was actually active.
38262306a36Sopenharmony_ci *
38362306a36Sopenharmony_ci * If the device is suspended, the active_duration is up-to-date.
38462306a36Sopenharmony_ci */
38562306a36Sopenharmony_cistatic ssize_t active_duration_show(struct device *dev,
38662306a36Sopenharmony_ci				    struct device_attribute *attr, char *buf)
38762306a36Sopenharmony_ci{
38862306a36Sopenharmony_ci	struct usb_device *udev = to_usb_device(dev);
38962306a36Sopenharmony_ci	int duration;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	if (udev->state != USB_STATE_SUSPENDED)
39262306a36Sopenharmony_ci		duration = jiffies_to_msecs(jiffies + udev->active_duration);
39362306a36Sopenharmony_ci	else
39462306a36Sopenharmony_ci		duration = jiffies_to_msecs(udev->active_duration);
39562306a36Sopenharmony_ci	return sysfs_emit(buf, "%u\n", duration);
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_cistatic DEVICE_ATTR_RO(active_duration);
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_cistatic ssize_t autosuspend_show(struct device *dev,
40062306a36Sopenharmony_ci				struct device_attribute *attr, char *buf)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	return sysfs_emit(buf, "%d\n", dev->power.autosuspend_delay / 1000);
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_cistatic ssize_t autosuspend_store(struct device *dev,
40662306a36Sopenharmony_ci				 struct device_attribute *attr, const char *buf,
40762306a36Sopenharmony_ci				 size_t count)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	int value;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	if (sscanf(buf, "%d", &value) != 1 || value >= INT_MAX/1000 ||
41262306a36Sopenharmony_ci			value <= -INT_MAX/1000)
41362306a36Sopenharmony_ci		return -EINVAL;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	pm_runtime_set_autosuspend_delay(dev, value * 1000);
41662306a36Sopenharmony_ci	return count;
41762306a36Sopenharmony_ci}
41862306a36Sopenharmony_cistatic DEVICE_ATTR_RW(autosuspend);
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic const char on_string[] = "on";
42162306a36Sopenharmony_cistatic const char auto_string[] = "auto";
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_cistatic void warn_level(void)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	static int level_warned;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	if (!level_warned) {
42862306a36Sopenharmony_ci		level_warned = 1;
42962306a36Sopenharmony_ci		printk(KERN_WARNING "WARNING! power/level is deprecated; "
43062306a36Sopenharmony_ci				"use power/control instead\n");
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_cistatic ssize_t level_show(struct device *dev, struct device_attribute *attr,
43562306a36Sopenharmony_ci			  char *buf)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	struct usb_device *udev = to_usb_device(dev);
43862306a36Sopenharmony_ci	const char *p = auto_string;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	warn_level();
44162306a36Sopenharmony_ci	if (udev->state != USB_STATE_SUSPENDED && !udev->dev.power.runtime_auto)
44262306a36Sopenharmony_ci		p = on_string;
44362306a36Sopenharmony_ci	return sysfs_emit(buf, "%s\n", p);
44462306a36Sopenharmony_ci}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_cistatic ssize_t level_store(struct device *dev, struct device_attribute *attr,
44762306a36Sopenharmony_ci			   const char *buf, size_t count)
44862306a36Sopenharmony_ci{
44962306a36Sopenharmony_ci	struct usb_device *udev = to_usb_device(dev);
45062306a36Sopenharmony_ci	int len = count;
45162306a36Sopenharmony_ci	char *cp;
45262306a36Sopenharmony_ci	int rc = count;
45362306a36Sopenharmony_ci	int rv;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	warn_level();
45662306a36Sopenharmony_ci	cp = memchr(buf, '\n', count);
45762306a36Sopenharmony_ci	if (cp)
45862306a36Sopenharmony_ci		len = cp - buf;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	rv = usb_lock_device_interruptible(udev);
46162306a36Sopenharmony_ci	if (rv < 0)
46262306a36Sopenharmony_ci		return -EINTR;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	if (len == sizeof on_string - 1 &&
46562306a36Sopenharmony_ci			strncmp(buf, on_string, len) == 0)
46662306a36Sopenharmony_ci		usb_disable_autosuspend(udev);
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	else if (len == sizeof auto_string - 1 &&
46962306a36Sopenharmony_ci			strncmp(buf, auto_string, len) == 0)
47062306a36Sopenharmony_ci		usb_enable_autosuspend(udev);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	else
47362306a36Sopenharmony_ci		rc = -EINVAL;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	usb_unlock_device(udev);
47662306a36Sopenharmony_ci	return rc;
47762306a36Sopenharmony_ci}
47862306a36Sopenharmony_cistatic DEVICE_ATTR_RW(level);
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_cistatic ssize_t usb2_hardware_lpm_show(struct device *dev,
48162306a36Sopenharmony_ci				      struct device_attribute *attr, char *buf)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	struct usb_device *udev = to_usb_device(dev);
48462306a36Sopenharmony_ci	const char *p;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	if (udev->usb2_hw_lpm_allowed == 1)
48762306a36Sopenharmony_ci		p = "enabled";
48862306a36Sopenharmony_ci	else
48962306a36Sopenharmony_ci		p = "disabled";
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	return sysfs_emit(buf, "%s\n", p);
49262306a36Sopenharmony_ci}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_cistatic ssize_t usb2_hardware_lpm_store(struct device *dev,
49562306a36Sopenharmony_ci				       struct device_attribute *attr,
49662306a36Sopenharmony_ci				       const char *buf, size_t count)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	struct usb_device *udev = to_usb_device(dev);
49962306a36Sopenharmony_ci	bool value;
50062306a36Sopenharmony_ci	int ret;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	ret = usb_lock_device_interruptible(udev);
50362306a36Sopenharmony_ci	if (ret < 0)
50462306a36Sopenharmony_ci		return -EINTR;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	ret = kstrtobool(buf, &value);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	if (!ret) {
50962306a36Sopenharmony_ci		udev->usb2_hw_lpm_allowed = value;
51062306a36Sopenharmony_ci		if (value)
51162306a36Sopenharmony_ci			ret = usb_enable_usb2_hardware_lpm(udev);
51262306a36Sopenharmony_ci		else
51362306a36Sopenharmony_ci			ret = usb_disable_usb2_hardware_lpm(udev);
51462306a36Sopenharmony_ci	}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	usb_unlock_device(udev);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	if (!ret)
51962306a36Sopenharmony_ci		return count;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	return ret;
52262306a36Sopenharmony_ci}
52362306a36Sopenharmony_cistatic DEVICE_ATTR_RW(usb2_hardware_lpm);
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_cistatic ssize_t usb2_lpm_l1_timeout_show(struct device *dev,
52662306a36Sopenharmony_ci					struct device_attribute *attr,
52762306a36Sopenharmony_ci					char *buf)
52862306a36Sopenharmony_ci{
52962306a36Sopenharmony_ci	struct usb_device *udev = to_usb_device(dev);
53062306a36Sopenharmony_ci	return sysfs_emit(buf, "%d\n", udev->l1_params.timeout);
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_cistatic ssize_t usb2_lpm_l1_timeout_store(struct device *dev,
53462306a36Sopenharmony_ci					 struct device_attribute *attr,
53562306a36Sopenharmony_ci					 const char *buf, size_t count)
53662306a36Sopenharmony_ci{
53762306a36Sopenharmony_ci	struct usb_device *udev = to_usb_device(dev);
53862306a36Sopenharmony_ci	u16 timeout;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	if (kstrtou16(buf, 0, &timeout))
54162306a36Sopenharmony_ci		return -EINVAL;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	udev->l1_params.timeout = timeout;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	return count;
54662306a36Sopenharmony_ci}
54762306a36Sopenharmony_cistatic DEVICE_ATTR_RW(usb2_lpm_l1_timeout);
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_cistatic ssize_t usb2_lpm_besl_show(struct device *dev,
55062306a36Sopenharmony_ci				  struct device_attribute *attr, char *buf)
55162306a36Sopenharmony_ci{
55262306a36Sopenharmony_ci	struct usb_device *udev = to_usb_device(dev);
55362306a36Sopenharmony_ci	return sysfs_emit(buf, "%d\n", udev->l1_params.besl);
55462306a36Sopenharmony_ci}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_cistatic ssize_t usb2_lpm_besl_store(struct device *dev,
55762306a36Sopenharmony_ci				   struct device_attribute *attr,
55862306a36Sopenharmony_ci				   const char *buf, size_t count)
55962306a36Sopenharmony_ci{
56062306a36Sopenharmony_ci	struct usb_device *udev = to_usb_device(dev);
56162306a36Sopenharmony_ci	u8 besl;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	if (kstrtou8(buf, 0, &besl) || besl > 15)
56462306a36Sopenharmony_ci		return -EINVAL;
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	udev->l1_params.besl = besl;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	return count;
56962306a36Sopenharmony_ci}
57062306a36Sopenharmony_cistatic DEVICE_ATTR_RW(usb2_lpm_besl);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_cistatic ssize_t usb3_hardware_lpm_u1_show(struct device *dev,
57362306a36Sopenharmony_ci				      struct device_attribute *attr, char *buf)
57462306a36Sopenharmony_ci{
57562306a36Sopenharmony_ci	struct usb_device *udev = to_usb_device(dev);
57662306a36Sopenharmony_ci	const char *p;
57762306a36Sopenharmony_ci	int rc;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	rc = usb_lock_device_interruptible(udev);
58062306a36Sopenharmony_ci	if (rc < 0)
58162306a36Sopenharmony_ci		return -EINTR;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	if (udev->usb3_lpm_u1_enabled)
58462306a36Sopenharmony_ci		p = "enabled";
58562306a36Sopenharmony_ci	else
58662306a36Sopenharmony_ci		p = "disabled";
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	usb_unlock_device(udev);
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	return sysfs_emit(buf, "%s\n", p);
59162306a36Sopenharmony_ci}
59262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(usb3_hardware_lpm_u1);
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_cistatic ssize_t usb3_hardware_lpm_u2_show(struct device *dev,
59562306a36Sopenharmony_ci				      struct device_attribute *attr, char *buf)
59662306a36Sopenharmony_ci{
59762306a36Sopenharmony_ci	struct usb_device *udev = to_usb_device(dev);
59862306a36Sopenharmony_ci	const char *p;
59962306a36Sopenharmony_ci	int rc;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	rc = usb_lock_device_interruptible(udev);
60262306a36Sopenharmony_ci	if (rc < 0)
60362306a36Sopenharmony_ci		return -EINTR;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	if (udev->usb3_lpm_u2_enabled)
60662306a36Sopenharmony_ci		p = "enabled";
60762306a36Sopenharmony_ci	else
60862306a36Sopenharmony_ci		p = "disabled";
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	usb_unlock_device(udev);
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	return sysfs_emit(buf, "%s\n", p);
61362306a36Sopenharmony_ci}
61462306a36Sopenharmony_cistatic DEVICE_ATTR_RO(usb3_hardware_lpm_u2);
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_cistatic struct attribute *usb2_hardware_lpm_attr[] = {
61762306a36Sopenharmony_ci	&dev_attr_usb2_hardware_lpm.attr,
61862306a36Sopenharmony_ci	&dev_attr_usb2_lpm_l1_timeout.attr,
61962306a36Sopenharmony_ci	&dev_attr_usb2_lpm_besl.attr,
62062306a36Sopenharmony_ci	NULL,
62162306a36Sopenharmony_ci};
62262306a36Sopenharmony_cistatic const struct attribute_group usb2_hardware_lpm_attr_group = {
62362306a36Sopenharmony_ci	.name	= power_group_name,
62462306a36Sopenharmony_ci	.attrs	= usb2_hardware_lpm_attr,
62562306a36Sopenharmony_ci};
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_cistatic struct attribute *usb3_hardware_lpm_attr[] = {
62862306a36Sopenharmony_ci	&dev_attr_usb3_hardware_lpm_u1.attr,
62962306a36Sopenharmony_ci	&dev_attr_usb3_hardware_lpm_u2.attr,
63062306a36Sopenharmony_ci	NULL,
63162306a36Sopenharmony_ci};
63262306a36Sopenharmony_cistatic const struct attribute_group usb3_hardware_lpm_attr_group = {
63362306a36Sopenharmony_ci	.name	= power_group_name,
63462306a36Sopenharmony_ci	.attrs	= usb3_hardware_lpm_attr,
63562306a36Sopenharmony_ci};
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_cistatic struct attribute *power_attrs[] = {
63862306a36Sopenharmony_ci	&dev_attr_autosuspend.attr,
63962306a36Sopenharmony_ci	&dev_attr_level.attr,
64062306a36Sopenharmony_ci	&dev_attr_connected_duration.attr,
64162306a36Sopenharmony_ci	&dev_attr_active_duration.attr,
64262306a36Sopenharmony_ci	NULL,
64362306a36Sopenharmony_ci};
64462306a36Sopenharmony_cistatic const struct attribute_group power_attr_group = {
64562306a36Sopenharmony_ci	.name	= power_group_name,
64662306a36Sopenharmony_ci	.attrs	= power_attrs,
64762306a36Sopenharmony_ci};
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_cistatic int add_power_attributes(struct device *dev)
65062306a36Sopenharmony_ci{
65162306a36Sopenharmony_ci	int rc = 0;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	if (is_usb_device(dev)) {
65462306a36Sopenharmony_ci		struct usb_device *udev = to_usb_device(dev);
65562306a36Sopenharmony_ci		rc = sysfs_merge_group(&dev->kobj, &power_attr_group);
65662306a36Sopenharmony_ci		if (udev->usb2_hw_lpm_capable == 1)
65762306a36Sopenharmony_ci			rc = sysfs_merge_group(&dev->kobj,
65862306a36Sopenharmony_ci					&usb2_hardware_lpm_attr_group);
65962306a36Sopenharmony_ci		if ((udev->speed == USB_SPEED_SUPER ||
66062306a36Sopenharmony_ci		     udev->speed == USB_SPEED_SUPER_PLUS) &&
66162306a36Sopenharmony_ci				udev->lpm_capable == 1)
66262306a36Sopenharmony_ci			rc = sysfs_merge_group(&dev->kobj,
66362306a36Sopenharmony_ci					&usb3_hardware_lpm_attr_group);
66462306a36Sopenharmony_ci	}
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	return rc;
66762306a36Sopenharmony_ci}
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_cistatic void remove_power_attributes(struct device *dev)
67062306a36Sopenharmony_ci{
67162306a36Sopenharmony_ci	sysfs_unmerge_group(&dev->kobj, &usb2_hardware_lpm_attr_group);
67262306a36Sopenharmony_ci	sysfs_unmerge_group(&dev->kobj, &power_attr_group);
67362306a36Sopenharmony_ci}
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci#else
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci#define add_persist_attributes(dev)	0
67862306a36Sopenharmony_ci#define remove_persist_attributes(dev)	do {} while (0)
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci#define add_power_attributes(dev)	0
68162306a36Sopenharmony_ci#define remove_power_attributes(dev)	do {} while (0)
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci#endif	/* CONFIG_PM */
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci/* Descriptor fields */
68762306a36Sopenharmony_ci#define usb_descriptor_attr_le16(field, format_string)			\
68862306a36Sopenharmony_cistatic ssize_t								\
68962306a36Sopenharmony_cifield##_show(struct device *dev, struct device_attribute *attr,	\
69062306a36Sopenharmony_ci		char *buf)						\
69162306a36Sopenharmony_ci{									\
69262306a36Sopenharmony_ci	struct usb_device *udev;					\
69362306a36Sopenharmony_ci									\
69462306a36Sopenharmony_ci	udev = to_usb_device(dev);					\
69562306a36Sopenharmony_ci	return sysfs_emit(buf, format_string,				\
69662306a36Sopenharmony_ci			le16_to_cpu(udev->descriptor.field));		\
69762306a36Sopenharmony_ci}									\
69862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(field)
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ciusb_descriptor_attr_le16(idVendor, "%04x\n");
70162306a36Sopenharmony_ciusb_descriptor_attr_le16(idProduct, "%04x\n");
70262306a36Sopenharmony_ciusb_descriptor_attr_le16(bcdDevice, "%04x\n");
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci#define usb_descriptor_attr(field, format_string)			\
70562306a36Sopenharmony_cistatic ssize_t								\
70662306a36Sopenharmony_cifield##_show(struct device *dev, struct device_attribute *attr,	\
70762306a36Sopenharmony_ci		char *buf)						\
70862306a36Sopenharmony_ci{									\
70962306a36Sopenharmony_ci	struct usb_device *udev;					\
71062306a36Sopenharmony_ci									\
71162306a36Sopenharmony_ci	udev = to_usb_device(dev);					\
71262306a36Sopenharmony_ci	return sysfs_emit(buf, format_string, udev->descriptor.field);	\
71362306a36Sopenharmony_ci}									\
71462306a36Sopenharmony_cistatic DEVICE_ATTR_RO(field)
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ciusb_descriptor_attr(bDeviceClass, "%02x\n");
71762306a36Sopenharmony_ciusb_descriptor_attr(bDeviceSubClass, "%02x\n");
71862306a36Sopenharmony_ciusb_descriptor_attr(bDeviceProtocol, "%02x\n");
71962306a36Sopenharmony_ciusb_descriptor_attr(bNumConfigurations, "%d\n");
72062306a36Sopenharmony_ciusb_descriptor_attr(bMaxPacketSize0, "%d\n");
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci/* show if the device is authorized (1) or not (0) */
72462306a36Sopenharmony_cistatic ssize_t authorized_show(struct device *dev,
72562306a36Sopenharmony_ci			       struct device_attribute *attr, char *buf)
72662306a36Sopenharmony_ci{
72762306a36Sopenharmony_ci	struct usb_device *usb_dev = to_usb_device(dev);
72862306a36Sopenharmony_ci	return sysfs_emit(buf, "%u\n", usb_dev->authorized);
72962306a36Sopenharmony_ci}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci/*
73262306a36Sopenharmony_ci * Authorize a device to be used in the system
73362306a36Sopenharmony_ci *
73462306a36Sopenharmony_ci * Writing a 0 deauthorizes the device, writing a 1 authorizes it.
73562306a36Sopenharmony_ci */
73662306a36Sopenharmony_cistatic ssize_t authorized_store(struct device *dev,
73762306a36Sopenharmony_ci				struct device_attribute *attr, const char *buf,
73862306a36Sopenharmony_ci				size_t size)
73962306a36Sopenharmony_ci{
74062306a36Sopenharmony_ci	ssize_t result;
74162306a36Sopenharmony_ci	struct usb_device *usb_dev = to_usb_device(dev);
74262306a36Sopenharmony_ci	unsigned val;
74362306a36Sopenharmony_ci	result = sscanf(buf, "%u\n", &val);
74462306a36Sopenharmony_ci	if (result != 1)
74562306a36Sopenharmony_ci		result = -EINVAL;
74662306a36Sopenharmony_ci	else if (val == 0)
74762306a36Sopenharmony_ci		result = usb_deauthorize_device(usb_dev);
74862306a36Sopenharmony_ci	else
74962306a36Sopenharmony_ci		result = usb_authorize_device(usb_dev);
75062306a36Sopenharmony_ci	return result < 0 ? result : size;
75162306a36Sopenharmony_ci}
75262306a36Sopenharmony_cistatic DEVICE_ATTR_IGNORE_LOCKDEP(authorized, S_IRUGO | S_IWUSR,
75362306a36Sopenharmony_ci				  authorized_show, authorized_store);
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci/* "Safely remove a device" */
75662306a36Sopenharmony_cistatic ssize_t remove_store(struct device *dev, struct device_attribute *attr,
75762306a36Sopenharmony_ci			    const char *buf, size_t count)
75862306a36Sopenharmony_ci{
75962306a36Sopenharmony_ci	struct usb_device *udev = to_usb_device(dev);
76062306a36Sopenharmony_ci	int rc = 0;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	usb_lock_device(udev);
76362306a36Sopenharmony_ci	if (udev->state != USB_STATE_NOTATTACHED) {
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci		/* To avoid races, first unconfigure and then remove */
76662306a36Sopenharmony_ci		usb_set_configuration(udev, -1);
76762306a36Sopenharmony_ci		rc = usb_remove_device(udev);
76862306a36Sopenharmony_ci	}
76962306a36Sopenharmony_ci	if (rc == 0)
77062306a36Sopenharmony_ci		rc = count;
77162306a36Sopenharmony_ci	usb_unlock_device(udev);
77262306a36Sopenharmony_ci	return rc;
77362306a36Sopenharmony_ci}
77462306a36Sopenharmony_cistatic DEVICE_ATTR_IGNORE_LOCKDEP(remove, S_IWUSR, NULL, remove_store);
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_cistatic struct attribute *dev_attrs[] = {
77862306a36Sopenharmony_ci	/* current configuration's attributes */
77962306a36Sopenharmony_ci	&dev_attr_configuration.attr,
78062306a36Sopenharmony_ci	&dev_attr_bNumInterfaces.attr,
78162306a36Sopenharmony_ci	&dev_attr_bConfigurationValue.attr,
78262306a36Sopenharmony_ci	&dev_attr_bmAttributes.attr,
78362306a36Sopenharmony_ci	&dev_attr_bMaxPower.attr,
78462306a36Sopenharmony_ci	/* device attributes */
78562306a36Sopenharmony_ci	&dev_attr_urbnum.attr,
78662306a36Sopenharmony_ci	&dev_attr_idVendor.attr,
78762306a36Sopenharmony_ci	&dev_attr_idProduct.attr,
78862306a36Sopenharmony_ci	&dev_attr_bcdDevice.attr,
78962306a36Sopenharmony_ci	&dev_attr_bDeviceClass.attr,
79062306a36Sopenharmony_ci	&dev_attr_bDeviceSubClass.attr,
79162306a36Sopenharmony_ci	&dev_attr_bDeviceProtocol.attr,
79262306a36Sopenharmony_ci	&dev_attr_bNumConfigurations.attr,
79362306a36Sopenharmony_ci	&dev_attr_bMaxPacketSize0.attr,
79462306a36Sopenharmony_ci	&dev_attr_speed.attr,
79562306a36Sopenharmony_ci	&dev_attr_rx_lanes.attr,
79662306a36Sopenharmony_ci	&dev_attr_tx_lanes.attr,
79762306a36Sopenharmony_ci	&dev_attr_busnum.attr,
79862306a36Sopenharmony_ci	&dev_attr_devnum.attr,
79962306a36Sopenharmony_ci	&dev_attr_devpath.attr,
80062306a36Sopenharmony_ci	&dev_attr_version.attr,
80162306a36Sopenharmony_ci	&dev_attr_maxchild.attr,
80262306a36Sopenharmony_ci	&dev_attr_quirks.attr,
80362306a36Sopenharmony_ci	&dev_attr_avoid_reset_quirk.attr,
80462306a36Sopenharmony_ci	&dev_attr_authorized.attr,
80562306a36Sopenharmony_ci	&dev_attr_remove.attr,
80662306a36Sopenharmony_ci	&dev_attr_ltm_capable.attr,
80762306a36Sopenharmony_ci#ifdef CONFIG_OF
80862306a36Sopenharmony_ci	&dev_attr_devspec.attr,
80962306a36Sopenharmony_ci#endif
81062306a36Sopenharmony_ci	NULL,
81162306a36Sopenharmony_ci};
81262306a36Sopenharmony_cistatic const struct attribute_group dev_attr_grp = {
81362306a36Sopenharmony_ci	.attrs = dev_attrs,
81462306a36Sopenharmony_ci};
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci/* When modifying this list, be sure to modify dev_string_attrs_are_visible()
81762306a36Sopenharmony_ci * accordingly.
81862306a36Sopenharmony_ci */
81962306a36Sopenharmony_cistatic struct attribute *dev_string_attrs[] = {
82062306a36Sopenharmony_ci	&dev_attr_manufacturer.attr,
82162306a36Sopenharmony_ci	&dev_attr_product.attr,
82262306a36Sopenharmony_ci	&dev_attr_serial.attr,
82362306a36Sopenharmony_ci	NULL
82462306a36Sopenharmony_ci};
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_cistatic umode_t dev_string_attrs_are_visible(struct kobject *kobj,
82762306a36Sopenharmony_ci		struct attribute *a, int n)
82862306a36Sopenharmony_ci{
82962306a36Sopenharmony_ci	struct device *dev = kobj_to_dev(kobj);
83062306a36Sopenharmony_ci	struct usb_device *udev = to_usb_device(dev);
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	if (a == &dev_attr_manufacturer.attr) {
83362306a36Sopenharmony_ci		if (udev->manufacturer == NULL)
83462306a36Sopenharmony_ci			return 0;
83562306a36Sopenharmony_ci	} else if (a == &dev_attr_product.attr) {
83662306a36Sopenharmony_ci		if (udev->product == NULL)
83762306a36Sopenharmony_ci			return 0;
83862306a36Sopenharmony_ci	} else if (a == &dev_attr_serial.attr) {
83962306a36Sopenharmony_ci		if (udev->serial == NULL)
84062306a36Sopenharmony_ci			return 0;
84162306a36Sopenharmony_ci	}
84262306a36Sopenharmony_ci	return a->mode;
84362306a36Sopenharmony_ci}
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_cistatic const struct attribute_group dev_string_attr_grp = {
84662306a36Sopenharmony_ci	.attrs =	dev_string_attrs,
84762306a36Sopenharmony_ci	.is_visible =	dev_string_attrs_are_visible,
84862306a36Sopenharmony_ci};
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ciconst struct attribute_group *usb_device_groups[] = {
85162306a36Sopenharmony_ci	&dev_attr_grp,
85262306a36Sopenharmony_ci	&dev_string_attr_grp,
85362306a36Sopenharmony_ci	NULL
85462306a36Sopenharmony_ci};
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci/* Binary descriptors */
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_cistatic ssize_t
85962306a36Sopenharmony_ciread_descriptors(struct file *filp, struct kobject *kobj,
86062306a36Sopenharmony_ci		struct bin_attribute *attr,
86162306a36Sopenharmony_ci		char *buf, loff_t off, size_t count)
86262306a36Sopenharmony_ci{
86362306a36Sopenharmony_ci	struct device *dev = kobj_to_dev(kobj);
86462306a36Sopenharmony_ci	struct usb_device *udev = to_usb_device(dev);
86562306a36Sopenharmony_ci	size_t nleft = count;
86662306a36Sopenharmony_ci	size_t srclen, n;
86762306a36Sopenharmony_ci	int cfgno;
86862306a36Sopenharmony_ci	void *src;
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	/* The binary attribute begins with the device descriptor.
87162306a36Sopenharmony_ci	 * Following that are the raw descriptor entries for all the
87262306a36Sopenharmony_ci	 * configurations (config plus subsidiary descriptors).
87362306a36Sopenharmony_ci	 */
87462306a36Sopenharmony_ci	for (cfgno = -1; cfgno < udev->descriptor.bNumConfigurations &&
87562306a36Sopenharmony_ci			nleft > 0; ++cfgno) {
87662306a36Sopenharmony_ci		if (cfgno < 0) {
87762306a36Sopenharmony_ci			src = &udev->descriptor;
87862306a36Sopenharmony_ci			srclen = sizeof(struct usb_device_descriptor);
87962306a36Sopenharmony_ci		} else {
88062306a36Sopenharmony_ci			src = udev->rawdescriptors[cfgno];
88162306a36Sopenharmony_ci			srclen = __le16_to_cpu(udev->config[cfgno].desc.
88262306a36Sopenharmony_ci					wTotalLength);
88362306a36Sopenharmony_ci		}
88462306a36Sopenharmony_ci		if (off < srclen) {
88562306a36Sopenharmony_ci			n = min(nleft, srclen - (size_t) off);
88662306a36Sopenharmony_ci			memcpy(buf, src + off, n);
88762306a36Sopenharmony_ci			nleft -= n;
88862306a36Sopenharmony_ci			buf += n;
88962306a36Sopenharmony_ci			off = 0;
89062306a36Sopenharmony_ci		} else {
89162306a36Sopenharmony_ci			off -= srclen;
89262306a36Sopenharmony_ci		}
89362306a36Sopenharmony_ci	}
89462306a36Sopenharmony_ci	return count - nleft;
89562306a36Sopenharmony_ci}
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_cistatic struct bin_attribute dev_bin_attr_descriptors = {
89862306a36Sopenharmony_ci	.attr = {.name = "descriptors", .mode = 0444},
89962306a36Sopenharmony_ci	.read = read_descriptors,
90062306a36Sopenharmony_ci	.size = 18 + 65535,	/* dev descr + max-size raw descriptor */
90162306a36Sopenharmony_ci};
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci/*
90462306a36Sopenharmony_ci * Show & store the current value of authorized_default
90562306a36Sopenharmony_ci */
90662306a36Sopenharmony_cistatic ssize_t authorized_default_show(struct device *dev,
90762306a36Sopenharmony_ci				       struct device_attribute *attr, char *buf)
90862306a36Sopenharmony_ci{
90962306a36Sopenharmony_ci	struct usb_device *rh_usb_dev = to_usb_device(dev);
91062306a36Sopenharmony_ci	struct usb_bus *usb_bus = rh_usb_dev->bus;
91162306a36Sopenharmony_ci	struct usb_hcd *hcd;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	hcd = bus_to_hcd(usb_bus);
91462306a36Sopenharmony_ci	return sysfs_emit(buf, "%u\n", hcd->dev_policy);
91562306a36Sopenharmony_ci}
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_cistatic ssize_t authorized_default_store(struct device *dev,
91862306a36Sopenharmony_ci					struct device_attribute *attr,
91962306a36Sopenharmony_ci					const char *buf, size_t size)
92062306a36Sopenharmony_ci{
92162306a36Sopenharmony_ci	ssize_t result;
92262306a36Sopenharmony_ci	unsigned int val;
92362306a36Sopenharmony_ci	struct usb_device *rh_usb_dev = to_usb_device(dev);
92462306a36Sopenharmony_ci	struct usb_bus *usb_bus = rh_usb_dev->bus;
92562306a36Sopenharmony_ci	struct usb_hcd *hcd;
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	hcd = bus_to_hcd(usb_bus);
92862306a36Sopenharmony_ci	result = sscanf(buf, "%u\n", &val);
92962306a36Sopenharmony_ci	if (result == 1) {
93062306a36Sopenharmony_ci		hcd->dev_policy = val <= USB_DEVICE_AUTHORIZE_INTERNAL ?
93162306a36Sopenharmony_ci			val : USB_DEVICE_AUTHORIZE_ALL;
93262306a36Sopenharmony_ci		result = size;
93362306a36Sopenharmony_ci	} else {
93462306a36Sopenharmony_ci		result = -EINVAL;
93562306a36Sopenharmony_ci	}
93662306a36Sopenharmony_ci	return result;
93762306a36Sopenharmony_ci}
93862306a36Sopenharmony_cistatic DEVICE_ATTR_RW(authorized_default);
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci/*
94162306a36Sopenharmony_ci * interface_authorized_default_show - show default authorization status
94262306a36Sopenharmony_ci * for USB interfaces
94362306a36Sopenharmony_ci *
94462306a36Sopenharmony_ci * note: interface_authorized_default is the default value
94562306a36Sopenharmony_ci *       for initializing the authorized attribute of interfaces
94662306a36Sopenharmony_ci */
94762306a36Sopenharmony_cistatic ssize_t interface_authorized_default_show(struct device *dev,
94862306a36Sopenharmony_ci		struct device_attribute *attr, char *buf)
94962306a36Sopenharmony_ci{
95062306a36Sopenharmony_ci	struct usb_device *usb_dev = to_usb_device(dev);
95162306a36Sopenharmony_ci	struct usb_hcd *hcd = bus_to_hcd(usb_dev->bus);
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	return sysfs_emit(buf, "%u\n", !!HCD_INTF_AUTHORIZED(hcd));
95462306a36Sopenharmony_ci}
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci/*
95762306a36Sopenharmony_ci * interface_authorized_default_store - store default authorization status
95862306a36Sopenharmony_ci * for USB interfaces
95962306a36Sopenharmony_ci *
96062306a36Sopenharmony_ci * note: interface_authorized_default is the default value
96162306a36Sopenharmony_ci *       for initializing the authorized attribute of interfaces
96262306a36Sopenharmony_ci */
96362306a36Sopenharmony_cistatic ssize_t interface_authorized_default_store(struct device *dev,
96462306a36Sopenharmony_ci		struct device_attribute *attr, const char *buf, size_t count)
96562306a36Sopenharmony_ci{
96662306a36Sopenharmony_ci	struct usb_device *usb_dev = to_usb_device(dev);
96762306a36Sopenharmony_ci	struct usb_hcd *hcd = bus_to_hcd(usb_dev->bus);
96862306a36Sopenharmony_ci	int rc = count;
96962306a36Sopenharmony_ci	bool val;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	if (kstrtobool(buf, &val) != 0)
97262306a36Sopenharmony_ci		return -EINVAL;
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	if (val)
97562306a36Sopenharmony_ci		set_bit(HCD_FLAG_INTF_AUTHORIZED, &hcd->flags);
97662306a36Sopenharmony_ci	else
97762306a36Sopenharmony_ci		clear_bit(HCD_FLAG_INTF_AUTHORIZED, &hcd->flags);
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	return rc;
98062306a36Sopenharmony_ci}
98162306a36Sopenharmony_cistatic DEVICE_ATTR_RW(interface_authorized_default);
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci/* Group all the USB bus attributes */
98462306a36Sopenharmony_cistatic struct attribute *usb_bus_attrs[] = {
98562306a36Sopenharmony_ci		&dev_attr_authorized_default.attr,
98662306a36Sopenharmony_ci		&dev_attr_interface_authorized_default.attr,
98762306a36Sopenharmony_ci		NULL,
98862306a36Sopenharmony_ci};
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_cistatic const struct attribute_group usb_bus_attr_group = {
99162306a36Sopenharmony_ci	.name = NULL,	/* we want them in the same directory */
99262306a36Sopenharmony_ci	.attrs = usb_bus_attrs,
99362306a36Sopenharmony_ci};
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_cistatic int add_default_authorized_attributes(struct device *dev)
99762306a36Sopenharmony_ci{
99862306a36Sopenharmony_ci	int rc = 0;
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	if (is_usb_device(dev))
100162306a36Sopenharmony_ci		rc = sysfs_create_group(&dev->kobj, &usb_bus_attr_group);
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	return rc;
100462306a36Sopenharmony_ci}
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_cistatic void remove_default_authorized_attributes(struct device *dev)
100762306a36Sopenharmony_ci{
100862306a36Sopenharmony_ci	if (is_usb_device(dev)) {
100962306a36Sopenharmony_ci		sysfs_remove_group(&dev->kobj, &usb_bus_attr_group);
101062306a36Sopenharmony_ci	}
101162306a36Sopenharmony_ci}
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ciint usb_create_sysfs_dev_files(struct usb_device *udev)
101462306a36Sopenharmony_ci{
101562306a36Sopenharmony_ci	struct device *dev = &udev->dev;
101662306a36Sopenharmony_ci	int retval;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	retval = device_create_bin_file(dev, &dev_bin_attr_descriptors);
101962306a36Sopenharmony_ci	if (retval)
102062306a36Sopenharmony_ci		goto error;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	retval = add_persist_attributes(dev);
102362306a36Sopenharmony_ci	if (retval)
102462306a36Sopenharmony_ci		goto error;
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	retval = add_power_attributes(dev);
102762306a36Sopenharmony_ci	if (retval)
102862306a36Sopenharmony_ci		goto error;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	if (is_root_hub(udev)) {
103162306a36Sopenharmony_ci		retval = add_default_authorized_attributes(dev);
103262306a36Sopenharmony_ci		if (retval)
103362306a36Sopenharmony_ci			goto error;
103462306a36Sopenharmony_ci	}
103562306a36Sopenharmony_ci	return retval;
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_cierror:
103862306a36Sopenharmony_ci	usb_remove_sysfs_dev_files(udev);
103962306a36Sopenharmony_ci	return retval;
104062306a36Sopenharmony_ci}
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_civoid usb_remove_sysfs_dev_files(struct usb_device *udev)
104362306a36Sopenharmony_ci{
104462306a36Sopenharmony_ci	struct device *dev = &udev->dev;
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	if (is_root_hub(udev))
104762306a36Sopenharmony_ci		remove_default_authorized_attributes(dev);
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	remove_power_attributes(dev);
105062306a36Sopenharmony_ci	remove_persist_attributes(dev);
105162306a36Sopenharmony_ci	device_remove_bin_file(dev, &dev_bin_attr_descriptors);
105262306a36Sopenharmony_ci}
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci/* Interface Association Descriptor fields */
105562306a36Sopenharmony_ci#define usb_intf_assoc_attr(field, format_string)			\
105662306a36Sopenharmony_cistatic ssize_t								\
105762306a36Sopenharmony_ciiad_##field##_show(struct device *dev, struct device_attribute *attr,	\
105862306a36Sopenharmony_ci		char *buf)						\
105962306a36Sopenharmony_ci{									\
106062306a36Sopenharmony_ci	struct usb_interface *intf = to_usb_interface(dev);		\
106162306a36Sopenharmony_ci									\
106262306a36Sopenharmony_ci	return sysfs_emit(buf, format_string,				\
106362306a36Sopenharmony_ci			intf->intf_assoc->field); 			\
106462306a36Sopenharmony_ci}									\
106562306a36Sopenharmony_cistatic DEVICE_ATTR_RO(iad_##field)
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ciusb_intf_assoc_attr(bFirstInterface, "%02x\n");
106862306a36Sopenharmony_ciusb_intf_assoc_attr(bInterfaceCount, "%02d\n");
106962306a36Sopenharmony_ciusb_intf_assoc_attr(bFunctionClass, "%02x\n");
107062306a36Sopenharmony_ciusb_intf_assoc_attr(bFunctionSubClass, "%02x\n");
107162306a36Sopenharmony_ciusb_intf_assoc_attr(bFunctionProtocol, "%02x\n");
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci/* Interface fields */
107462306a36Sopenharmony_ci#define usb_intf_attr(field, format_string)				\
107562306a36Sopenharmony_cistatic ssize_t								\
107662306a36Sopenharmony_cifield##_show(struct device *dev, struct device_attribute *attr,		\
107762306a36Sopenharmony_ci		char *buf)						\
107862306a36Sopenharmony_ci{									\
107962306a36Sopenharmony_ci	struct usb_interface *intf = to_usb_interface(dev);		\
108062306a36Sopenharmony_ci									\
108162306a36Sopenharmony_ci	return sysfs_emit(buf, format_string,				\
108262306a36Sopenharmony_ci			intf->cur_altsetting->desc.field); 		\
108362306a36Sopenharmony_ci}									\
108462306a36Sopenharmony_cistatic DEVICE_ATTR_RO(field)
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ciusb_intf_attr(bInterfaceNumber, "%02x\n");
108762306a36Sopenharmony_ciusb_intf_attr(bAlternateSetting, "%2d\n");
108862306a36Sopenharmony_ciusb_intf_attr(bNumEndpoints, "%02x\n");
108962306a36Sopenharmony_ciusb_intf_attr(bInterfaceClass, "%02x\n");
109062306a36Sopenharmony_ciusb_intf_attr(bInterfaceSubClass, "%02x\n");
109162306a36Sopenharmony_ciusb_intf_attr(bInterfaceProtocol, "%02x\n");
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_cistatic ssize_t interface_show(struct device *dev, struct device_attribute *attr,
109462306a36Sopenharmony_ci			      char *buf)
109562306a36Sopenharmony_ci{
109662306a36Sopenharmony_ci	struct usb_interface *intf;
109762306a36Sopenharmony_ci	char *string;
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci	intf = to_usb_interface(dev);
110062306a36Sopenharmony_ci	string = READ_ONCE(intf->cur_altsetting->string);
110162306a36Sopenharmony_ci	if (!string)
110262306a36Sopenharmony_ci		return 0;
110362306a36Sopenharmony_ci	return sysfs_emit(buf, "%s\n", string);
110462306a36Sopenharmony_ci}
110562306a36Sopenharmony_cistatic DEVICE_ATTR_RO(interface);
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_cistatic ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
110862306a36Sopenharmony_ci			     char *buf)
110962306a36Sopenharmony_ci{
111062306a36Sopenharmony_ci	struct usb_interface *intf;
111162306a36Sopenharmony_ci	struct usb_device *udev;
111262306a36Sopenharmony_ci	struct usb_host_interface *alt;
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	intf = to_usb_interface(dev);
111562306a36Sopenharmony_ci	udev = interface_to_usbdev(intf);
111662306a36Sopenharmony_ci	alt = READ_ONCE(intf->cur_altsetting);
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	return sysfs_emit(buf,
111962306a36Sopenharmony_ci			"usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X"
112062306a36Sopenharmony_ci			"ic%02Xisc%02Xip%02Xin%02X\n",
112162306a36Sopenharmony_ci			le16_to_cpu(udev->descriptor.idVendor),
112262306a36Sopenharmony_ci			le16_to_cpu(udev->descriptor.idProduct),
112362306a36Sopenharmony_ci			le16_to_cpu(udev->descriptor.bcdDevice),
112462306a36Sopenharmony_ci			udev->descriptor.bDeviceClass,
112562306a36Sopenharmony_ci			udev->descriptor.bDeviceSubClass,
112662306a36Sopenharmony_ci			udev->descriptor.bDeviceProtocol,
112762306a36Sopenharmony_ci			alt->desc.bInterfaceClass,
112862306a36Sopenharmony_ci			alt->desc.bInterfaceSubClass,
112962306a36Sopenharmony_ci			alt->desc.bInterfaceProtocol,
113062306a36Sopenharmony_ci			alt->desc.bInterfaceNumber);
113162306a36Sopenharmony_ci}
113262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(modalias);
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_cistatic ssize_t supports_autosuspend_show(struct device *dev,
113562306a36Sopenharmony_ci					 struct device_attribute *attr,
113662306a36Sopenharmony_ci					 char *buf)
113762306a36Sopenharmony_ci{
113862306a36Sopenharmony_ci	int s;
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	s = device_lock_interruptible(dev);
114162306a36Sopenharmony_ci	if (s < 0)
114262306a36Sopenharmony_ci		return -EINTR;
114362306a36Sopenharmony_ci	/* Devices will be autosuspended even when an interface isn't claimed */
114462306a36Sopenharmony_ci	s = (!dev->driver || to_usb_driver(dev->driver)->supports_autosuspend);
114562306a36Sopenharmony_ci	device_unlock(dev);
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	return sysfs_emit(buf, "%u\n", s);
114862306a36Sopenharmony_ci}
114962306a36Sopenharmony_cistatic DEVICE_ATTR_RO(supports_autosuspend);
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci/*
115262306a36Sopenharmony_ci * interface_authorized_show - show authorization status of an USB interface
115362306a36Sopenharmony_ci * 1 is authorized, 0 is deauthorized
115462306a36Sopenharmony_ci */
115562306a36Sopenharmony_cistatic ssize_t interface_authorized_show(struct device *dev,
115662306a36Sopenharmony_ci		struct device_attribute *attr, char *buf)
115762306a36Sopenharmony_ci{
115862306a36Sopenharmony_ci	struct usb_interface *intf = to_usb_interface(dev);
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci	return sysfs_emit(buf, "%u\n", intf->authorized);
116162306a36Sopenharmony_ci}
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci/*
116462306a36Sopenharmony_ci * interface_authorized_store - authorize or deauthorize an USB interface
116562306a36Sopenharmony_ci */
116662306a36Sopenharmony_cistatic ssize_t interface_authorized_store(struct device *dev,
116762306a36Sopenharmony_ci		struct device_attribute *attr, const char *buf, size_t count)
116862306a36Sopenharmony_ci{
116962306a36Sopenharmony_ci	struct usb_interface *intf = to_usb_interface(dev);
117062306a36Sopenharmony_ci	bool val;
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci	if (kstrtobool(buf, &val) != 0)
117362306a36Sopenharmony_ci		return -EINVAL;
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	if (val)
117662306a36Sopenharmony_ci		usb_authorize_interface(intf);
117762306a36Sopenharmony_ci	else
117862306a36Sopenharmony_ci		usb_deauthorize_interface(intf);
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	return count;
118162306a36Sopenharmony_ci}
118262306a36Sopenharmony_cistatic struct device_attribute dev_attr_interface_authorized =
118362306a36Sopenharmony_ci		__ATTR(authorized, S_IRUGO | S_IWUSR,
118462306a36Sopenharmony_ci		interface_authorized_show, interface_authorized_store);
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_cistatic struct attribute *intf_attrs[] = {
118762306a36Sopenharmony_ci	&dev_attr_bInterfaceNumber.attr,
118862306a36Sopenharmony_ci	&dev_attr_bAlternateSetting.attr,
118962306a36Sopenharmony_ci	&dev_attr_bNumEndpoints.attr,
119062306a36Sopenharmony_ci	&dev_attr_bInterfaceClass.attr,
119162306a36Sopenharmony_ci	&dev_attr_bInterfaceSubClass.attr,
119262306a36Sopenharmony_ci	&dev_attr_bInterfaceProtocol.attr,
119362306a36Sopenharmony_ci	&dev_attr_modalias.attr,
119462306a36Sopenharmony_ci	&dev_attr_supports_autosuspend.attr,
119562306a36Sopenharmony_ci	&dev_attr_interface_authorized.attr,
119662306a36Sopenharmony_ci	NULL,
119762306a36Sopenharmony_ci};
119862306a36Sopenharmony_cistatic const struct attribute_group intf_attr_grp = {
119962306a36Sopenharmony_ci	.attrs = intf_attrs,
120062306a36Sopenharmony_ci};
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_cistatic struct attribute *intf_assoc_attrs[] = {
120362306a36Sopenharmony_ci	&dev_attr_iad_bFirstInterface.attr,
120462306a36Sopenharmony_ci	&dev_attr_iad_bInterfaceCount.attr,
120562306a36Sopenharmony_ci	&dev_attr_iad_bFunctionClass.attr,
120662306a36Sopenharmony_ci	&dev_attr_iad_bFunctionSubClass.attr,
120762306a36Sopenharmony_ci	&dev_attr_iad_bFunctionProtocol.attr,
120862306a36Sopenharmony_ci	NULL,
120962306a36Sopenharmony_ci};
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_cistatic umode_t intf_assoc_attrs_are_visible(struct kobject *kobj,
121262306a36Sopenharmony_ci		struct attribute *a, int n)
121362306a36Sopenharmony_ci{
121462306a36Sopenharmony_ci	struct device *dev = kobj_to_dev(kobj);
121562306a36Sopenharmony_ci	struct usb_interface *intf = to_usb_interface(dev);
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	if (intf->intf_assoc == NULL)
121862306a36Sopenharmony_ci		return 0;
121962306a36Sopenharmony_ci	return a->mode;
122062306a36Sopenharmony_ci}
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_cistatic const struct attribute_group intf_assoc_attr_grp = {
122362306a36Sopenharmony_ci	.attrs =	intf_assoc_attrs,
122462306a36Sopenharmony_ci	.is_visible =	intf_assoc_attrs_are_visible,
122562306a36Sopenharmony_ci};
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_cistatic ssize_t wireless_status_show(struct device *dev,
122862306a36Sopenharmony_ci				    struct device_attribute *attr, char *buf)
122962306a36Sopenharmony_ci{
123062306a36Sopenharmony_ci	struct usb_interface *intf;
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	intf = to_usb_interface(dev);
123362306a36Sopenharmony_ci	if (intf->wireless_status == USB_WIRELESS_STATUS_DISCONNECTED)
123462306a36Sopenharmony_ci		return sysfs_emit(buf, "%s\n", "disconnected");
123562306a36Sopenharmony_ci	return sysfs_emit(buf, "%s\n", "connected");
123662306a36Sopenharmony_ci}
123762306a36Sopenharmony_cistatic DEVICE_ATTR_RO(wireless_status);
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_cistatic struct attribute *intf_wireless_status_attrs[] = {
124062306a36Sopenharmony_ci	&dev_attr_wireless_status.attr,
124162306a36Sopenharmony_ci	NULL
124262306a36Sopenharmony_ci};
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_cistatic umode_t intf_wireless_status_attr_is_visible(struct kobject *kobj,
124562306a36Sopenharmony_ci		struct attribute *a, int n)
124662306a36Sopenharmony_ci{
124762306a36Sopenharmony_ci	struct device *dev = kobj_to_dev(kobj);
124862306a36Sopenharmony_ci	struct usb_interface *intf = to_usb_interface(dev);
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	if (a != &dev_attr_wireless_status.attr ||
125162306a36Sopenharmony_ci	    intf->wireless_status != USB_WIRELESS_STATUS_NA)
125262306a36Sopenharmony_ci		return a->mode;
125362306a36Sopenharmony_ci	return 0;
125462306a36Sopenharmony_ci}
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_cistatic const struct attribute_group intf_wireless_status_attr_grp = {
125762306a36Sopenharmony_ci	.attrs =	intf_wireless_status_attrs,
125862306a36Sopenharmony_ci	.is_visible =	intf_wireless_status_attr_is_visible,
125962306a36Sopenharmony_ci};
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ciint usb_update_wireless_status_attr(struct usb_interface *intf)
126262306a36Sopenharmony_ci{
126362306a36Sopenharmony_ci	struct device *dev = &intf->dev;
126462306a36Sopenharmony_ci	int ret;
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	ret = sysfs_update_group(&dev->kobj, &intf_wireless_status_attr_grp);
126762306a36Sopenharmony_ci	if (ret < 0)
126862306a36Sopenharmony_ci		return ret;
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	sysfs_notify(&dev->kobj, NULL, "wireless_status");
127162306a36Sopenharmony_ci	kobject_uevent(&dev->kobj, KOBJ_CHANGE);
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	return 0;
127462306a36Sopenharmony_ci}
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ciconst struct attribute_group *usb_interface_groups[] = {
127762306a36Sopenharmony_ci	&intf_attr_grp,
127862306a36Sopenharmony_ci	&intf_assoc_attr_grp,
127962306a36Sopenharmony_ci	&intf_wireless_status_attr_grp,
128062306a36Sopenharmony_ci	NULL
128162306a36Sopenharmony_ci};
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_civoid usb_create_sysfs_intf_files(struct usb_interface *intf)
128462306a36Sopenharmony_ci{
128562306a36Sopenharmony_ci	struct usb_device *udev = interface_to_usbdev(intf);
128662306a36Sopenharmony_ci	struct usb_host_interface *alt = intf->cur_altsetting;
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	if (intf->sysfs_files_created || intf->unregistering)
128962306a36Sopenharmony_ci		return;
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	if (!alt->string && !(udev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
129262306a36Sopenharmony_ci		alt->string = usb_cache_string(udev, alt->desc.iInterface);
129362306a36Sopenharmony_ci	if (alt->string && device_create_file(&intf->dev, &dev_attr_interface)) {
129462306a36Sopenharmony_ci		/* This is not a serious error */
129562306a36Sopenharmony_ci		dev_dbg(&intf->dev, "interface string descriptor file not created\n");
129662306a36Sopenharmony_ci	}
129762306a36Sopenharmony_ci	intf->sysfs_files_created = 1;
129862306a36Sopenharmony_ci}
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_civoid usb_remove_sysfs_intf_files(struct usb_interface *intf)
130162306a36Sopenharmony_ci{
130262306a36Sopenharmony_ci	if (!intf->sysfs_files_created)
130362306a36Sopenharmony_ci		return;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	device_remove_file(&intf->dev, &dev_attr_interface);
130662306a36Sopenharmony_ci	intf->sysfs_files_created = 0;
130762306a36Sopenharmony_ci}
1308