usb_host: deliver UTF-16 strings on request

Linux kernel static functions usb_string_sub() and usb_get_langid() were
made accessible to implement robust string rerieval.

Fixes #4756
Fixes #4757
Fixes #4772
This commit is contained in:
Roland Bär 2023-02-12 20:40:34 +01:00 committed by Christian Helmuth
parent ea2584e2fb
commit b9b18c92d0
4 changed files with 85 additions and 3 deletions

View File

@ -0,0 +1,19 @@
+++ src/linux/drivers/usb/core/message.c
@@ -869,7 +869,7 @@
}
}
-static int usb_string_sub(struct usb_device *dev, unsigned int langid,
+int usb_string_sub(struct usb_device *dev, unsigned int langid,
unsigned int index, unsigned char *buf)
{
int rc;
@@ -906,7 +906,7 @@
return rc;
}
-static int usb_get_langid(struct usb_device *dev, unsigned char *tbuf)
+int usb_get_langid(struct usb_device *dev, unsigned char *tbuf)
{
int err;

View File

@ -1 +1 @@
04e5e6e790ae0a41343fec197667cc94a1bc3f25
417db2da739fdf54788613353118bb904cc57ea9

View File

@ -12,7 +12,8 @@ DIR(linux) := src/linux
PATCH_FILES := i915_irq.patch i915_alderlake.patch xhci_fix_event_37.patch \
xhci_abort_ring.patch iwlwifi_enable_irq_before_pnvm.patch \
realloc-fix-gcc-12.patch \
workqueue_deadlock.patch
workqueue_deadlock.patch \
usb_message.patch
PATCHES += $(addprefix patches/,$(PATCH_FILES))
# i915

View File

@ -340,6 +340,68 @@ handle_return_code(struct genode_usb_request_urb req, void * data)
};
extern int usb_get_langid(struct usb_device *dev, unsigned char *tbuf);
extern int usb_string_sub(struct usb_device *dev, unsigned int langid, int index, unsigned char *tbuf);
/**
* usb_string_utf16 - returns the string descriptor
* @dev: the device whose string descriptor is being retrieved
* @index: the number of the descriptor
* @buf: where to put the string
* @size: how big is "buf"?
*
* Context: task context, might sleep.
*
* This returns the UTF-16LE encoded strings returned by devices, from
* usb_get_string_descriptor(). Note that this function
* chooses strings in the first language supported by the device.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Return: length of the string (>= 0) or usb_control_msg status (< 0).
*/
static int usb_string_utf16(struct usb_device *dev, int index, char *buf, size_t size)
{
unsigned char *tbuf;
int err;
size_t len;
if (dev->state == USB_STATE_SUSPENDED)
return -EHOSTUNREACH;
if (size <= 2 || buf == NULL)
return -EINVAL;
buf[0] = 0;
if (index <= 0 || index >= 256)
return -EINVAL;
tbuf = kmalloc(256, GFP_NOIO);
if (!tbuf)
return -ENOMEM;
err = usb_get_langid(dev, tbuf);
if (err < 0)
goto errout;
err = usb_string_sub(dev, dev->string_langid, index, tbuf);
if (err < 0)
goto errout;
len = min(size-2, (size_t)err);
memcpy(buf, tbuf+2, len);
buf[len] = 0;
buf[len+1] = 0;
err = len + 2;
if (tbuf[1] != USB_DT_STRING)
dev_dbg(&dev->dev,
"wrong descriptor type %02x for string %d (\"%s\")\n",
tbuf[1], index, buf);
errout:
kfree(tbuf);
return err;
}
static void
handle_string_request(struct genode_usb_request_string * req,
genode_usb_session_handle_t session,
@ -351,7 +413,7 @@ handle_string_request(struct genode_usb_request_string * req,
struct usb_device * udev = (struct usb_device *) data;
genode_usb_request_ret_t ret = UNKNOWN_ERROR;
int length = usb_string(udev, req->index, buf, size);
int length = usb_string_utf16(udev, req->index, buf, size);
if (length < 0) {
printk("Could not read string descriptor index: %u\n", req->index);
req->length = 0;