xhci feature for usb-next
Subsystems (2)
cover xhci feature for usb-next
Hi Greg
This series for usb-next allows users to modify the string descriptors presented by xHCI when running in DbC device mode.
Thanks
Mathias
Łukasz Bartosik (4):
xhci: dbc: prepare to expose strings through sysfs
xhci: dbc: allow setting device serial number through sysfs
xhci: dbc: allow setting product string through sysfs
xhci: dbc: allow setting manufacturer string through sysfs
.../testing/sysfs-bus-pci-drivers-xhci_hcd | 42 +++ drivers/usb/host/xhci-dbgcap.c | 259 +++++++++++++----- drivers/usb/host/xhci-dbgcap.h | 39 ++- 3 files changed, 262 insertions(+), 78 deletions(-)
Signature · 1 line
2.43.0
PATCH 1/4 xhci: dbc: prepare to expose strings through sysfs
From: Łukasz Bartosik <[email protected]>
Reorganize the code to prepare ground for setting serial number, product and manufacturer names through sysfs. This commit:
1. Introduces new buffers for storing serial number, product and manufacturer name in utf8. The buffers will be used by sysfs *_show and *_store functions.
2. Increases USB string descriptor data maximum length to the value from USB specification (126 bytes of data).
3. Adds new helper functions get_str_desc_len, prepare_len and xhci_dbc_populate_str_desc.
--- drivers/usb/host/xhci-dbgcap.c | 151 ++++++++++++++++++--------------- drivers/usb/host/xhci-dbgcap.h | 39 ++++++--- 2 files changed, 112 insertions(+), 78 deletions(-)
drivers/usb/host/xhci-dbgcap.c +84 -67
@@ -29,6 +29,12 @@#include "xhci-trace.h" #include "xhci-dbgcap.h" +static const struct dbc_str dbc_str_default = { + .manufacturer ="Linux Foundation" , + .product ="Linux USB Debug Target" , + .serial ="0001" , +}; +static void dbc_free_ctx (struct device *dev,struct xhci_container_ctx *ctx) {if (!ctx)
@@ -52,55 +58,6 @@ static void dbc_ring_free(struct device *dev, struct xhci_ring *ring)kfree (ring); } -static u32 xhci_dbc_populate_strings (struct dbc_str_descs *strings) -{ -struct usb_string_descriptor *s_desc; -u32 string_length; - -/* Serial string: */ - s_desc = (struct usb_string_descriptor *)strings->serial; -utf8s_to_utf16s (DBC_STRING_SERIAL ,strlen (DBC_STRING_SERIAL ), -UTF16_LITTLE_ENDIAN , (wchar_t *)s_desc->wData, -DBC_MAX_STRING_LENGTH ); - - s_desc->bLength = (strlen (DBC_STRING_SERIAL ) +1 ) *2 ; - s_desc->bDescriptorType =USB_DT_STRING ; - string_length = s_desc->bLength; - string_length <<=8 ; - -/* Product string: */ - s_desc = (struct usb_string_descriptor *)strings->product; -utf8s_to_utf16s (DBC_STRING_PRODUCT ,strlen (DBC_STRING_PRODUCT ), -UTF16_LITTLE_ENDIAN , (wchar_t *)s_desc->wData, -DBC_MAX_STRING_LENGTH ); - - s_desc->bLength = (strlen (DBC_STRING_PRODUCT ) +1 ) *2 ; - s_desc->bDescriptorType =USB_DT_STRING ; - string_length += s_desc->bLength; - string_length <<=8 ; - -/* Manufacture string: */ - s_desc = (struct usb_string_descriptor *)strings->manufacturer; -utf8s_to_utf16s (DBC_STRING_MANUFACTURER , -strlen (DBC_STRING_MANUFACTURER ), -UTF16_LITTLE_ENDIAN , (wchar_t *)s_desc->wData, -DBC_MAX_STRING_LENGTH ); - - s_desc->bLength = (strlen (DBC_STRING_MANUFACTURER ) +1 ) *2 ; - s_desc->bDescriptorType =USB_DT_STRING ; - string_length += s_desc->bLength; - string_length <<=8 ; - -/* String0: */ - strings->string0[0 ] =4 ; - strings->string0[1 ] =USB_DT_STRING ; - strings->string0[2 ] =0x09 ; - strings->string0[3 ] =0x04 ; - string_length +=4 ; - -return string_length; -} -static void xhci_dbc_init_ep_contexts (struct xhci_dbc *dbc) {struct xhci_ep_ctx *ep_ctx;
@@ -124,7 +81,65 @@ static void xhci_dbc_init_ep_contexts(struct xhci_dbc *dbc) ep_ctx->deq =cpu_to_le64 (deq | dbc->ring_in->cycle_state); } -static void xhci_dbc_init_contexts (struct xhci_dbc *dbc,u32 string_length) +static u8 get_str_desc_len (const char *desc) +{ +return ((struct usb_string_descriptor *)desc)->bLength; +} + +static u32 dbc_prepare_info_context_str_len (struct dbc_str_descs *descs) +{ +u32 len; + + len =get_str_desc_len (descs->serial); + len <<=8 ; + len +=get_str_desc_len (descs->product); + len <<=8 ; + len +=get_str_desc_len (descs->manufacturer); + len <<=8 ; + len +=get_str_desc_len (descs->string0); + +return len; +} + +static int xhci_dbc_populate_str_desc (char *desc,const char *src) +{ +struct usb_string_descriptor *s_desc; +int len; + + s_desc = (struct usb_string_descriptor *)desc; + +/* len holds number of 2 byte UTF-16 characters */ + len =utf8s_to_utf16s (src,strlen (src),UTF16_LITTLE_ENDIAN , + (wchar_t *)s_desc->wData,USB_MAX_STRING_LEN *2 ); +if (len <0 ) +return len; + + s_desc->bLength = len *2 +2 ; + s_desc->bDescriptorType =USB_DT_STRING ; + +return s_desc->bLength; +} + +static void xhci_dbc_populate_str_descs (struct dbc_str_descs *str_descs, +struct dbc_str *str) +{ +/* Serial string: */ +xhci_dbc_populate_str_desc (str_descs->serial, str->serial); + +/* Product string: */ +xhci_dbc_populate_str_desc (str_descs->product, str->product); + +/* Manufacturer string: */ +xhci_dbc_populate_str_desc (str_descs->manufacturer, str->manufacturer); + +/* String0: */ + str_descs->string0[0 ] =4 ; + str_descs->string0[1 ] =USB_DT_STRING ; + str_descs->string0[2 ] =0x09 ; + str_descs->string0[3 ] =0x04 ; +} + +static void xhci_dbc_init_contexts (struct xhci_dbc *dbc) {struct dbc_info_context *info;u32 dev_info;
@@ -135,12 +150,12 @@ static void xhci_dbc_init_contexts(struct xhci_dbc *dbc, u32 string_length)/* Populate info Context: */ info = (struct dbc_info_context *)dbc->ctx->bytes; - dma = dbc->string_dma; + dma = dbc->str_descs_dma; info->string0 =cpu_to_le64 (dma); - info->manufacturer =cpu_to_le64 (dma +DBC_MAX_STRING_LENGTH ); - info->product =cpu_to_le64 (dma +DBC_MAX_STRING_LENGTH *2 ); - info->serial =cpu_to_le64 (dma +DBC_MAX_STRING_LENGTH *3 ); - info->length =cpu_to_le32 (string_length); + info->manufacturer =cpu_to_le64 (dma +USB_MAX_STRING_DESC_LEN ); + info->product =cpu_to_le64 (dma +USB_MAX_STRING_DESC_LEN *2 ); + info->serial =cpu_to_le64 (dma +USB_MAX_STRING_DESC_LEN *3 ); + info->length =cpu_to_le32 (dbc_prepare_info_context_str_len (dbc->str_descs));/* Populate bulk in and out endpoint contexts: */ xhci_dbc_init_ep_contexts (dbc);
@@ -525,7 +540,6 @@ static int xhci_dbc_mem_init(struct xhci_dbc *dbc, gfp_t flags) {int ret;dma_addr_t deq; -u32 string_length;struct device *dev = dbc->dev;/* Allocate various rings for events and transfers: */
@@ -552,11 +566,11 @@ static int xhci_dbc_mem_init(struct xhci_dbc *dbc, gfp_t flags) goto ctx_fail;/* Allocate the string table: */ - dbc->string_size =sizeof (*dbc->string); - dbc->string =dma_alloc_coherent (dev, dbc->string_size, - &dbc->string_dma, flags); -if (!dbc->string) - goto string_fail; + dbc->str_descs_size =sizeof (*dbc->str_descs); + dbc->str_descs =dma_alloc_coherent (dev, dbc->str_descs_size, + &dbc->str_descs_dma, flags); +if (!dbc->str_descs) + goto str_descs_fail;/* Setup ERST register: */ writel (dbc->erst.num_entries, &dbc->regs->ersts);
@@ -566,16 +580,16 @@ static int xhci_dbc_mem_init(struct xhci_dbc *dbc, gfp_t flags) dbc->ring_evt->dequeue);lo_hi_writeq (deq, &dbc->regs->erdp); -/* Setup strings and contexts: */ - string_length =xhci_dbc_populate_strings (dbc->string); -xhci_dbc_init_contexts (dbc, string_length); +/* Setup string descriptors and contexts: */ +xhci_dbc_populate_str_descs (dbc->str_descs, &dbc->str); +xhci_dbc_init_contexts (dbc);xhci_dbc_eps_init (dbc); dbc->state =DS_INITIALIZED ;return 0 ; -string_fail: +str_descs_fail:dbc_free_ctx (dev, dbc->ctx); dbc->ctx =NULL ; ctx_fail:
@@ -600,8 +614,8 @@ static void xhci_dbc_mem_cleanup(struct xhci_dbc *dbc)xhci_dbc_eps_exit (dbc); -dma_free_coherent (dbc->dev, dbc->string_size, dbc->string, dbc->string_dma); - dbc->string =NULL ; +dma_free_coherent (dbc->dev, dbc->str_descs_size, dbc->str_descs, dbc->str_descs_dma); + dbc->str_descs =NULL ;dbc_free_ctx (dbc->dev, dbc->ctx); dbc->ctx =NULL ;
@@ -1316,6 +1330,9 @@ xhci_alloc_dbc(struct device *dev, void __iomem *base, const struct dbc_driver * dbc->bInterfaceProtocol =DBC_PROTOCOL ; dbc->poll_interval =DBC_POLL_INTERVAL_DEFAULT ; +/* initialize serial, product and manufacturer with default values */ + dbc->str = dbc_str_default; +if (readl (&dbc->regs->control) &DBC_CTRL_DBC_ENABLE ) goto err;
drivers/usb/host/xhci-dbgcap.h +28 -11
@@ -47,10 +47,6 @@ struct dbc_info_context {#define DBC_DOOR_BELL_TARGET (p) (((p) & 0xff) << 8)#define DBC_MAX_PACKET 1024 -#define DBC_MAX_STRING_LENGTH 64 -#define DBC_STRING_MANUFACTURER "Linux Foundation" -#define DBC_STRING_PRODUCT "Linux USB Debug Target" -#define DBC_STRING_SERIAL "0001"#define DBC_CONTEXT_SIZE 64/*
@@ -63,11 +59,31 @@ struct dbc_info_context {#define DBC_PORTSC_LINK_CHANGE BIT(22)#define DBC_PORTSC_CONFIG_CHANGE BIT(23) +/* +* The maximum length of a string descriptor is 255, because the bLength +* field in the usb_string_descriptor struct is __u8. In practice the +* maximum length is 254, because a string descriptor consists of a 2 byte +* header followed by UTF-16 characters (2 bytes each). This allows for +* only 126 characters (code points) in the string, which is where +* USB_MAX_STRING_LEN comes from. +*/ +#define USB_MAX_STRING_DESC_LEN 254 +struct dbc_str_descs { -char string0[DBC_MAX_STRING_LENGTH ]; -char manufacturer[DBC_MAX_STRING_LENGTH ]; -char product[DBC_MAX_STRING_LENGTH ]; -char serial[DBC_MAX_STRING_LENGTH ]; +char string0[USB_MAX_STRING_DESC_LEN ]; +char manufacturer[USB_MAX_STRING_DESC_LEN ]; +char product[USB_MAX_STRING_DESC_LEN ]; +char serial[USB_MAX_STRING_DESC_LEN ]; +}; + +/* +* NULL terminated UTF-8 strings used to create UTF-16 strings +* (with maxiumum USB_MAX_STRING_LEN 2 byte characters). +*/ +struct dbc_str { +char manufacturer[USB_MAX_STRING_LEN +1 ]; +char product[USB_MAX_STRING_LEN +1 ]; +char serial[USB_MAX_STRING_LEN +1 ]; };#define DBC_PROTOCOL 1/* GNU Remote Debug Command */
@@ -133,9 +149,10 @@ struct xhci_dbc {struct xhci_erst erst;struct xhci_container_ctx *ctx; -struct dbc_str_descs *string; -dma_addr_t string_dma; -size_t string_size; +struct dbc_str_descs *str_descs; +dma_addr_t str_descs_dma; +size_t str_descs_size; +struct dbc_str str;u16 idVendor;u16 idProduct;u16 bcdDevice;
Signature · 1 line
2.43.0
PATCH 2/4 xhci: dbc: allow setting device serial number through sysfs
In reply to Mathias NymanFrom: Łukasz Bartosik <[email protected]>
Add dbc_serial sysfs attribute to allow changing the serial number string descriptor presented by the debug device when a host requests a string descriptor with iSerialNumber index.
Value can only be changed while debug capability (DbC) is in disabled state to prevent USB device descriptor change while connected to a USB host.
The default value is "0001".
The field length can be from 1 to 126 characters.
String is terminated at null or newline, driver does not support empty string.
--- .../testing/sysfs-bus-pci-drivers-xhci_hcd | 15 ++++++++ drivers/usb/host/xhci-dbgcap.c | 36 +++++++++++++++++++ 2 files changed, 51 insertions(+)
Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd +15 -0
@@ -85,3 +85,18 @@ Description: up to 5000. The default value is 64 ms. This polling interval is used while DbC is enabled but has no active data transfers. + +What: /sys/bus/pci/drivers/xhci_hcd/.../dbc_serial +Date: January 2026 +Contact: Łukasz Bartosik <[email protected]> +Description: + The dbc_serial attribute allows to change the serial number + string descriptor presented by the debug device when a host + requests a string descriptor with iSerialNumber index. + Index is found in the iSerialNumber field in the device + descriptor. + Value can only be changed while debug capability (DbC) is in + disabled state to prevent USB device descriptor change while + connected to a USB host. + The default value is "0001". + The field length can be from 1 to 126 characters.
drivers/usb/host/xhci-dbgcap.c +36 -0
@@ -1210,6 +1210,40 @@ static ssize_t dbc_bcdDevice_store(struct device *dev,return size; } +static ssize_t dbc_serial_show (struct device *dev, +struct device_attribute *attr, +char *buf) +{ +struct xhci_hcd *xhci =hcd_to_xhci (dev_get_drvdata (dev)); +struct xhci_dbc *dbc = xhci->dbc; + +return sysfs_emit (buf,"%s\n" , dbc->str.serial); +} + +static ssize_t dbc_serial_store (struct device *dev, +struct device_attribute *attr, +const char *buf,size_t size) +{ +struct xhci_hcd *xhci =hcd_to_xhci (dev_get_drvdata (dev)); +struct xhci_dbc *dbc = xhci->dbc; +size_t len; + +if (dbc->state !=DS_DISABLED ) +return -EBUSY ; + + len =strcspn (buf,"\n" ); +if (!len) +return -EINVAL ; + +if (len >USB_MAX_STRING_LEN ) +return -E2BIG ; + +memcpy (dbc->str.serial, buf, len); + dbc->str.serial[len] ='\0' ; + +return size; +} +static ssize_t dbc_bInterfaceProtocol_show (struct device *dev,struct device_attribute *attr,char *buf)
@@ -1297,6 +1331,7 @@ static DEVICE_ATTR_RW(dbc);static DEVICE_ATTR_RW (dbc_idVendor);static DEVICE_ATTR_RW (dbc_idProduct);static DEVICE_ATTR_RW (dbc_bcdDevice); +static DEVICE_ATTR_RW (dbc_serial);static DEVICE_ATTR_RW (dbc_bInterfaceProtocol);static DEVICE_ATTR_RW (dbc_poll_interval_ms);
@@ -1305,6 +1340,7 @@ static struct attribute *dbc_dev_attrs[] = { &dev_attr_dbc_idVendor.attr, &dev_attr_dbc_idProduct.attr, &dev_attr_dbc_bcdDevice.attr, + &dev_attr_dbc_serial.attr, &dev_attr_dbc_bInterfaceProtocol.attr, &dev_attr_dbc_poll_interval_ms.attr,NULL
Signature · 1 line
2.43.0
PATCH 3/4 xhci: dbc: allow setting product string through sysfs
In reply to Mathias NymanFrom: Łukasz Bartosik <[email protected]>
Add dbc_product sysfs attribute to allow changing the product description presented by the debug device when a host requests a string descriptor with iProduct index.
Value can only be changed while debug capability (DbC) is in disabled state to prevent USB device descriptor change while connected to a USB host.
The default value is "Linux USB Debug Target".
The field length can be from 1 to 126 characters.
String is terminated at null or newline, driver does not support empty string.
--- .../testing/sysfs-bus-pci-drivers-xhci_hcd | 14 ++++++++ drivers/usb/host/xhci-dbgcap.c | 36 +++++++++++++++++++ 2 files changed, 50 insertions(+)
Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd +14 -0
@@ -100,3 +100,17 @@ Description: connected to a USB host. The default value is "0001". The field length can be from 1 to 126 characters. + +What: /sys/bus/pci/drivers/xhci_hcd/.../dbc_product +Date: January 2026 +Contact: Łukasz Bartosik <[email protected]> +Description: + The dbc_product attribute allows to change the product string + descriptor presented by the debug device when a host requests + a string descriptor with iProduct index. + Index is found in the iProduct field in the device descriptor. + Value can only be changed while debug capability (DbC) is in + disabled state to prevent USB device descriptor change while + connected to a USB host. + The default value is "Linux USB Debug Target". + The field length can be from 1 to 126 characters.
drivers/usb/host/xhci-dbgcap.c +36 -0
@@ -1210,6 +1210,40 @@ static ssize_t dbc_bcdDevice_store(struct device *dev,return size; } +static ssize_t dbc_product_show (struct device *dev, +struct device_attribute *attr, +char *buf) +{ +struct xhci_hcd *xhci =hcd_to_xhci (dev_get_drvdata (dev)); +struct xhci_dbc *dbc = xhci->dbc; + +return sysfs_emit (buf,"%s\n" , dbc->str.product); +} + +static ssize_t dbc_product_store (struct device *dev, +struct device_attribute *attr, +const char *buf,size_t size) +{ +struct xhci_hcd *xhci =hcd_to_xhci (dev_get_drvdata (dev)); +struct xhci_dbc *dbc = xhci->dbc; +size_t len; + +if (dbc->state !=DS_DISABLED ) +return -EBUSY ; + + len =strcspn (buf,"\n" ); +if (!len) +return -EINVAL ; + +if (len >USB_MAX_STRING_LEN ) +return -E2BIG ; + +memcpy (dbc->str.product, buf, len); + dbc->str.product[len] ='\0' ; + +return size; +} +static ssize_t dbc_serial_show (struct device *dev,struct device_attribute *attr,char *buf)
@@ -1332,6 +1366,7 @@ static DEVICE_ATTR_RW(dbc_idVendor);static DEVICE_ATTR_RW (dbc_idProduct);static DEVICE_ATTR_RW (dbc_bcdDevice);static DEVICE_ATTR_RW (dbc_serial); +static DEVICE_ATTR_RW (dbc_product);static DEVICE_ATTR_RW (dbc_bInterfaceProtocol);static DEVICE_ATTR_RW (dbc_poll_interval_ms);
@@ -1341,6 +1376,7 @@ static struct attribute *dbc_dev_attrs[] = { &dev_attr_dbc_idProduct.attr, &dev_attr_dbc_bcdDevice.attr, &dev_attr_dbc_serial.attr, + &dev_attr_dbc_product.attr, &dev_attr_dbc_bInterfaceProtocol.attr, &dev_attr_dbc_poll_interval_ms.attr,NULL
Signature · 1 line
2.43.0
PATCH 4/4 xhci: dbc: allow setting manufacturer string through sysfs
In reply to Mathias NymanFrom: Łukasz Bartosik <[email protected]>
Add dbc_manufacturer sysfs attribute to allow changing the manufacturer description presented by the debug device when a host requests a string descriptor with iManufacturer index.
Value can only be changed while debug capability (DbC) is in disabled state to prevent USB device descriptor change while connected to a USB host.
The default value is "Linux Foundation".
The string length can be from 1 to 126 characters.
String is terminated at null or newline, driver does not support empty string.
--- .../testing/sysfs-bus-pci-drivers-xhci_hcd | 13 +++++++ drivers/usb/host/xhci-dbgcap.c | 36 +++++++++++++++++++ 2 files changed, 49 insertions(+)
Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd +13 -0
@@ -114,3 +114,16 @@ Description: connected to a USB host. The default value is "Linux USB Debug Target". The field length can be from 1 to 126 characters. + +What: /sys/bus/pci/drivers/xhci_hcd/.../dbc_manufacturer +Date: January 2026 +Contact: Łukasz Bartosik <[email protected]> +Description: + The dbc_manufacturer attribute allows to change the manufacturer + string descriptor presented by the debug device when a host + requests a string descriptor with iManufacturer index. + Value can only be changed while debug capability (DbC) is in + disabled state to prevent USB device descriptor change while + connected to a USB host. + The default value is "Linux Foundation". + The field length can be from 1 to 126 characters.
drivers/usb/host/xhci-dbgcap.c +36 -0
@@ -1210,6 +1210,40 @@ static ssize_t dbc_bcdDevice_store(struct device *dev,return size; } +static ssize_t dbc_manufacturer_show (struct device *dev, +struct device_attribute *attr, +char *buf) +{ +struct xhci_hcd *xhci =hcd_to_xhci (dev_get_drvdata (dev)); +struct xhci_dbc *dbc = xhci->dbc; + +return sysfs_emit (buf,"%s\n" , dbc->str.manufacturer); +} + +static ssize_t dbc_manufacturer_store (struct device *dev, +struct device_attribute *attr, +const char *buf,size_t size) +{ +struct xhci_hcd *xhci =hcd_to_xhci (dev_get_drvdata (dev)); +struct xhci_dbc *dbc = xhci->dbc; +size_t len; + +if (dbc->state !=DS_DISABLED ) +return -EBUSY ; + + len =strcspn (buf,"\n" ); +if (!len) +return -EINVAL ; + +if (len >USB_MAX_STRING_LEN ) +return -E2BIG ; + +memcpy (dbc->str.manufacturer, buf, len); + dbc->str.manufacturer[len] ='\0' ; + +return size; +} +static ssize_t dbc_product_show (struct device *dev,struct device_attribute *attr,char *buf)
@@ -1367,6 +1401,7 @@ static DEVICE_ATTR_RW(dbc_idProduct);static DEVICE_ATTR_RW (dbc_bcdDevice);static DEVICE_ATTR_RW (dbc_serial);static DEVICE_ATTR_RW (dbc_product); +static DEVICE_ATTR_RW (dbc_manufacturer);static DEVICE_ATTR_RW (dbc_bInterfaceProtocol);static DEVICE_ATTR_RW (dbc_poll_interval_ms);
@@ -1377,6 +1412,7 @@ static struct attribute *dbc_dev_attrs[] = { &dev_attr_dbc_bcdDevice.attr, &dev_attr_dbc_serial.attr, &dev_attr_dbc_product.attr, + &dev_attr_dbc_manufacturer.attr, &dev_attr_dbc_bInterfaceProtocol.attr, &dev_attr_dbc_poll_interval_ms.attr,NULL
Signature · 1 line
2.43.0