mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-04 20:19:47 +08:00
usb: Export BOS descriptor to sysfs
Motivation ---------- The binary device object store (BOS) of a USB device consists of the BOS descriptor followed by a set of device capability descriptors. One that is of interest to users is the platform descriptor. This contains a 128-bit UUID and arbitrary data, and it allows parties outside of USB-IF to add additional metadata about a USB device in a standards-compliant manner. Notable examples include the WebUSB and Microsoft OS 2.0 descriptors. The kernel already retrieves and caches the BOS from USB devices if its bcdUSB is >= 0x0201. Because the BOS is flexible and extensible, we export the entire BOS to sysfs so users can retrieve whatever device capabilities they desire, without requiring USB I/O or elevated permissions. Implementation -------------- Add bos_descriptors attribute to sysfs. This is a binary file and it works the same way as the existing descriptors attribute. The file exists only if the BOS is present in the USB device. Also create a binary attribute group, so the driver core can handle the creation of both the descriptors and bos_descriptors attributes in sysfs. Signed-off-by: Elbert Mai <code@elbertmai.com> Link: https://lore.kernel.org/r/20240305002301.95323-1-code@elbertmai.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
a14e6fd1b6
commit
12fc84e8c4
@ -442,6 +442,16 @@ What: /sys/bus/usb/devices/usbX/descriptors
|
|||||||
Description:
|
Description:
|
||||||
Contains the interface descriptors, in binary.
|
Contains the interface descriptors, in binary.
|
||||||
|
|
||||||
|
What: /sys/bus/usb/devices/usbX/bos_descriptors
|
||||||
|
Date: March 2024
|
||||||
|
Contact: Elbert Mai <code@elbertmai.com>
|
||||||
|
Description:
|
||||||
|
Binary file containing the cached binary device object store (BOS)
|
||||||
|
of the device. This consists of the BOS descriptor followed by the
|
||||||
|
set of device capability descriptors. All descriptors read from
|
||||||
|
this file are in bus-endian format. Note that the kernel will not
|
||||||
|
request the BOS from a device if its bcdUSB is less than 0x0201.
|
||||||
|
|
||||||
What: /sys/bus/usb/devices/usbX/idProduct
|
What: /sys/bus/usb/devices/usbX/idProduct
|
||||||
Description:
|
Description:
|
||||||
Product ID, in hexadecimal.
|
Product ID, in hexadecimal.
|
||||||
|
@ -849,16 +849,10 @@ static const struct attribute_group dev_string_attr_grp = {
|
|||||||
.is_visible = dev_string_attrs_are_visible,
|
.is_visible = dev_string_attrs_are_visible,
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct attribute_group *usb_device_groups[] = {
|
|
||||||
&dev_attr_grp,
|
|
||||||
&dev_string_attr_grp,
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Binary descriptors */
|
/* Binary descriptors */
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
read_descriptors(struct file *filp, struct kobject *kobj,
|
descriptors_read(struct file *filp, struct kobject *kobj,
|
||||||
struct bin_attribute *attr,
|
struct bin_attribute *attr,
|
||||||
char *buf, loff_t off, size_t count)
|
char *buf, loff_t off, size_t count)
|
||||||
{
|
{
|
||||||
@ -880,7 +874,7 @@ read_descriptors(struct file *filp, struct kobject *kobj,
|
|||||||
srclen = sizeof(struct usb_device_descriptor);
|
srclen = sizeof(struct usb_device_descriptor);
|
||||||
} else {
|
} else {
|
||||||
src = udev->rawdescriptors[cfgno];
|
src = udev->rawdescriptors[cfgno];
|
||||||
srclen = __le16_to_cpu(udev->config[cfgno].desc.
|
srclen = le16_to_cpu(udev->config[cfgno].desc.
|
||||||
wTotalLength);
|
wTotalLength);
|
||||||
}
|
}
|
||||||
if (off < srclen) {
|
if (off < srclen) {
|
||||||
@ -895,11 +889,66 @@ read_descriptors(struct file *filp, struct kobject *kobj,
|
|||||||
}
|
}
|
||||||
return count - nleft;
|
return count - nleft;
|
||||||
}
|
}
|
||||||
|
static BIN_ATTR_RO(descriptors, 18 + 65535); /* dev descr + max-size raw descriptor */
|
||||||
|
|
||||||
static struct bin_attribute dev_bin_attr_descriptors = {
|
static ssize_t
|
||||||
.attr = {.name = "descriptors", .mode = 0444},
|
bos_descriptors_read(struct file *filp, struct kobject *kobj,
|
||||||
.read = read_descriptors,
|
struct bin_attribute *attr,
|
||||||
.size = 18 + 65535, /* dev descr + max-size raw descriptor */
|
char *buf, loff_t off, size_t count)
|
||||||
|
{
|
||||||
|
struct device *dev = kobj_to_dev(kobj);
|
||||||
|
struct usb_device *udev = to_usb_device(dev);
|
||||||
|
struct usb_host_bos *bos = udev->bos;
|
||||||
|
struct usb_bos_descriptor *desc;
|
||||||
|
size_t desclen, n = 0;
|
||||||
|
|
||||||
|
if (bos) {
|
||||||
|
desc = bos->desc;
|
||||||
|
desclen = le16_to_cpu(desc->wTotalLength);
|
||||||
|
if (off < desclen) {
|
||||||
|
n = min(count, desclen - (size_t) off);
|
||||||
|
memcpy(buf, (void *) desc + off, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
static BIN_ATTR_RO(bos_descriptors, 65535); /* max-size BOS */
|
||||||
|
|
||||||
|
/* When modifying this list, be sure to modify dev_bin_attrs_are_visible()
|
||||||
|
* accordingly.
|
||||||
|
*/
|
||||||
|
static struct bin_attribute *dev_bin_attrs[] = {
|
||||||
|
&bin_attr_descriptors,
|
||||||
|
&bin_attr_bos_descriptors,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static umode_t dev_bin_attrs_are_visible(struct kobject *kobj,
|
||||||
|
struct bin_attribute *a, int n)
|
||||||
|
{
|
||||||
|
struct device *dev = kobj_to_dev(kobj);
|
||||||
|
struct usb_device *udev = to_usb_device(dev);
|
||||||
|
|
||||||
|
/* All USB devices have a device descriptor, so the descriptors
|
||||||
|
* attribute always exists. No need to check for its visibility.
|
||||||
|
*/
|
||||||
|
if (a == &bin_attr_bos_descriptors) {
|
||||||
|
if (udev->bos == NULL)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return a->attr.mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct attribute_group dev_bin_attr_grp = {
|
||||||
|
.bin_attrs = dev_bin_attrs,
|
||||||
|
.is_bin_visible = dev_bin_attrs_are_visible,
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct attribute_group *usb_device_groups[] = {
|
||||||
|
&dev_attr_grp,
|
||||||
|
&dev_string_attr_grp,
|
||||||
|
&dev_bin_attr_grp,
|
||||||
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1017,10 +1066,6 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
|
|||||||
struct device *dev = &udev->dev;
|
struct device *dev = &udev->dev;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
retval = device_create_bin_file(dev, &dev_bin_attr_descriptors);
|
|
||||||
if (retval)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
retval = add_persist_attributes(dev);
|
retval = add_persist_attributes(dev);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto error;
|
goto error;
|
||||||
@ -1050,7 +1095,6 @@ void usb_remove_sysfs_dev_files(struct usb_device *udev)
|
|||||||
|
|
||||||
remove_power_attributes(dev);
|
remove_power_attributes(dev);
|
||||||
remove_persist_attributes(dev);
|
remove_persist_attributes(dev);
|
||||||
device_remove_bin_file(dev, &dev_bin_attr_descriptors);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Interface Association Descriptor fields */
|
/* Interface Association Descriptor fields */
|
||||||
|
Loading…
Reference in New Issue
Block a user