Commit 392ca68b authored by George Spelvin's avatar George Spelvin Committed by Greg Kroah-Hartman

USB: Clean up root hub string descriptors

The previous code had a bug that would add a trailing null byte to
the returned descriptor.
Signed-off-by: default avatarGeorge Spelvin <linux@horizon.com>
Acked-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 48d31677
...@@ -337,72 +337,89 @@ static const u8 ss_rh_config_descriptor[] = { ...@@ -337,72 +337,89 @@ static const u8 ss_rh_config_descriptor[] = {
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/* /**
* helper routine for returning string descriptors in UTF-16LE * ascii2desc() - Helper routine for producing UTF-16LE string descriptors
* input can actually be ISO-8859-1; ASCII is its 7-bit subset * @s: Null-terminated ASCII (actually ISO-8859-1) string
* @buf: Buffer for USB string descriptor (header + UTF-16LE)
* @len: Length (in bytes; may be odd) of descriptor buffer.
*
* The return value is the number of bytes filled in: 2 + 2*strlen(s) or
* buflen, whichever is less.
*
* USB String descriptors can contain at most 126 characters; input
* strings longer than that are truncated.
*/ */
static unsigned ascii2utf(char *s, u8 *utf, int utfmax) static unsigned
ascii2desc(char const *s, u8 *buf, unsigned len)
{ {
unsigned retval; unsigned n, t = 2 + 2*strlen(s);
for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) { if (t > 254)
*utf++ = *s++; t = 254; /* Longest possible UTF string descriptor */
*utf++ = 0; if (len > t)
} len = t;
if (utfmax > 0) {
*utf = *s; t += USB_DT_STRING << 8; /* Now t is first 16 bits to store */
++retval;
n = len;
while (n--) {
*buf++ = t;
if (!n--)
break;
*buf++ = t >> 8;
t = (unsigned char)*s++;
} }
return retval; return len;
} }
/* /**
* rh_string - provides manufacturer, product and serial strings for root hub * rh_string() - provides string descriptors for root hub
* @id: the string ID number (1: serial number, 2: product, 3: vendor) * @id: the string ID number (0: langids, 1: serial #, 2: product, 3: vendor)
* @hcd: the host controller for this root hub * @hcd: the host controller for this root hub
* @data: return packet in UTF-16 LE * @data: buffer for output packet
* @len: length of the return packet * @len: length of the provided buffer
* *
* Produces either a manufacturer, product or serial number string for the * Produces either a manufacturer, product or serial number string for the
* virtual root hub device. * virtual root hub device.
* Returns the number of bytes filled in: the length of the descriptor or
* of the provided buffer, whichever is less.
*/ */
static unsigned rh_string(int id, struct usb_hcd *hcd, u8 *data, unsigned len) static unsigned
rh_string(int id, struct usb_hcd const *hcd, u8 *data, unsigned len)
{ {
char buf [100]; char buf[100];
char const *s;
static char const langids[4] = {4, USB_DT_STRING, 0x09, 0x04};
// language ids // language ids
if (id == 0) { switch (id) {
buf[0] = 4; buf[1] = 3; /* 4 bytes string data */ case 0:
buf[2] = 0x09; buf[3] = 0x04; /* MSFT-speak for "en-us" */ /* Array of LANGID codes (0x0409 is MSFT-speak for "en-us") */
len = min_t(unsigned, len, 4); /* See http://www.usb.org/developers/docs/USB_LANGIDs.pdf */
memcpy (data, buf, len); if (len > 4)
len = 4;
memcpy(data, langids, len);
return len; return len;
case 1:
// serial number /* Serial number */
} else if (id == 1) { s = hcd->self.bus_name;
strlcpy (buf, hcd->self.bus_name, sizeof buf); break;
case 2:
// product description /* Product name */
} else if (id == 2) { s = hcd->product_desc;
strlcpy (buf, hcd->product_desc, sizeof buf); break;
case 3:
// id 3 == vendor description /* Manufacturer */
} else if (id == 3) {
snprintf (buf, sizeof buf, "%s %s %s", init_utsname()->sysname, snprintf (buf, sizeof buf, "%s %s %s", init_utsname()->sysname,
init_utsname()->release, hcd->driver->description); init_utsname()->release, hcd->driver->description);
} s = buf;
break;
switch (len) { /* All cases fall through */
default: default:
len = 2 + ascii2utf (buf, data + 2, len - 2); /* Can't happen; caller guarantees it */
case 2: return 0;
data [1] = 3; /* type == string */
case 1:
data [0] = 2 * (strlen (buf) + 1);
case 0:
; /* Compiler wants a statement here */
} }
return len;
return ascii2desc(s, data, len);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment