[PATCH v1 1/4] xhci: dbc: prepare to expose strings through sysfs
From: "Łukasz Bartosik" <ukaszb@chromium.org>
Date: 2025-09-29 09:02:12
Subsystem:
the rest, usb subsystem, usb xhci driver · Maintainers:
Linus Torvalds, Greg Kroah-Hartman, Mathias Nyman
From: Łukasz Bartosik <ukaszb@chromium.org> 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. Signed-off-by: Łukasz Bartosik <ukaszb@chromium.org> --- drivers/usb/host/xhci-dbgcap.c | 145 ++++++++++++++++++--------------- drivers/usb/host/xhci-dbgcap.h | 24 ++++-- 2 files changed, 94 insertions(+), 75 deletions(-)
diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c
index 63edf2d8f245..c2fecaffd6f3 100644
--- a/drivers/usb/host/xhci-dbgcap.c
+++ b/drivers/usb/host/xhci-dbgcap.c@@ -52,55 +52,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 +75,63 @@ 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 prepare_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 utf16_len; + + s_desc = (struct usb_string_descriptor *)desc; + utf16_len = utf8s_to_utf16s(src, strlen(src), UTF16_LITTLE_ENDIAN, + (wchar_t *)s_desc->wData, USB_MAX_STRING_LEN); + if (utf16_len < 0) + return utf16_len; + + s_desc->bLength = utf16_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 +142,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(prepare_len(dbc->str_descs)); /* Populate bulk in and out endpoint contexts: */ xhci_dbc_init_ep_contexts(dbc);
@@ -525,7 +532,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 +558,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 +572,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 +606,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;
@@ -1314,6 +1320,11 @@ 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 */ + memcpy(dbc->str.serial, DBC_STRING_SERIAL, strlen(DBC_STRING_SERIAL)+1); + memcpy(dbc->str.product, DBC_STRING_PRODUCT, strlen(DBC_STRING_PRODUCT)+1); + memcpy(dbc->str.manufacturer, DBC_STRING_MANUFACTURER, strlen(DBC_STRING_MANUFACTURER)+1); + if (readl(&dbc->regs->control) & DBC_CTRL_DBC_ENABLE) goto err;
diff --git a/drivers/usb/host/xhci-dbgcap.h b/drivers/usb/host/xhci-dbgcap.h
index 47ac72c2286d..0e6addafea6c 100644
--- a/drivers/usb/host/xhci-dbgcap.h
+++ b/drivers/usb/host/xhci-dbgcap.h@@ -47,7 +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"
@@ -63,11 +62,19 @@ struct dbc_info_context { #define DBC_PORTSC_LINK_CHANGE BIT(22) #define DBC_PORTSC_CONFIG_CHANGE BIT(23) +#define USB_MAX_STRING_DESC_LEN (USB_MAX_STRING_LEN + 2) + 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]; +}; + +struct dbc_str { + char manufacturer[USB_MAX_STRING_LEN/2+1]; + char product[USB_MAX_STRING_LEN/2+1]; + char serial[USB_MAX_STRING_LEN/2+1]; }; #define DBC_PROTOCOL 1 /* GNU Remote Debug Command */
@@ -132,9 +139,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;
--
2.51.0.536.g15c5d4f767-goog