]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
xhci: dbc: prepare to expose strings through sysfs
authorŁukasz Bartosik <ukaszb@chromium.org>
Tue, 20 Jan 2026 18:11:45 +0000 (20:11 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 23 Jan 2026 16:16:24 +0000 (17:16 +0100)
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>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Link: https://patch.msgid.link/20260120181148.128712-2-mathias.nyman@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/host/xhci-dbgcap.c
drivers/usb/host/xhci-dbgcap.h

index 9da4f3b452cb742e4ba2a2257b8c5ae6808c0b11..4ba8edb37e51749b11eda1aa49ac823102a4dadb 100644 (file)
 #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;
 
index 5426c971d2d39db681287d1a3df0fb12e32e690f..20ae4e7617f221963a1288f192e673aa6f7238a8 100644 (file)
@@ -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;