diff options
author | George Spelvin <linux@horizon.com> | 2009-08-24 22:06:41 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-09-23 09:46:37 -0400 |
commit | 392ca68b401e0797115a08836642faad5778fdb2 (patch) | |
tree | 8215eb8d605a85d28581fd0ef29f978617a8468d /drivers/usb | |
parent | 48d316770bd4dcf3d21b53cfa91e358280c31d69 (diff) |
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: George Spelvin <linux@horizon.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/core/hcd.c | 111 |
1 files changed, 64 insertions, 47 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 95ccfa0b9fc5..34de475f016e 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c | |||
@@ -337,72 +337,89 @@ static const u8 ss_rh_config_descriptor[] = { | |||
337 | 337 | ||
338 | /*-------------------------------------------------------------------------*/ | 338 | /*-------------------------------------------------------------------------*/ |
339 | 339 | ||
340 | /* | 340 | /** |
341 | * helper routine for returning string descriptors in UTF-16LE | 341 | * ascii2desc() - Helper routine for producing UTF-16LE string descriptors |
342 | * input can actually be ISO-8859-1; ASCII is its 7-bit subset | 342 | * @s: Null-terminated ASCII (actually ISO-8859-1) string |
343 | * @buf: Buffer for USB string descriptor (header + UTF-16LE) | ||
344 | * @len: Length (in bytes; may be odd) of descriptor buffer. | ||
345 | * | ||
346 | * The return value is the number of bytes filled in: 2 + 2*strlen(s) or | ||
347 | * buflen, whichever is less. | ||
348 | * | ||
349 | * USB String descriptors can contain at most 126 characters; input | ||
350 | * strings longer than that are truncated. | ||
343 | */ | 351 | */ |
344 | static unsigned ascii2utf(char *s, u8 *utf, int utfmax) | 352 | static unsigned |
353 | ascii2desc(char const *s, u8 *buf, unsigned len) | ||
345 | { | 354 | { |
346 | unsigned retval; | 355 | unsigned n, t = 2 + 2*strlen(s); |
347 | 356 | ||
348 | for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) { | 357 | if (t > 254) |
349 | *utf++ = *s++; | 358 | t = 254; /* Longest possible UTF string descriptor */ |
350 | *utf++ = 0; | 359 | if (len > t) |
351 | } | 360 | len = t; |
352 | if (utfmax > 0) { | 361 | |
353 | *utf = *s; | 362 | t += USB_DT_STRING << 8; /* Now t is first 16 bits to store */ |
354 | ++retval; | 363 | |
364 | n = len; | ||
365 | while (n--) { | ||
366 | *buf++ = t; | ||
367 | if (!n--) | ||
368 | break; | ||
369 | *buf++ = t >> 8; | ||
370 | t = (unsigned char)*s++; | ||
355 | } | 371 | } |
356 | return retval; | 372 | return len; |
357 | } | 373 | } |
358 | 374 | ||
359 | /* | 375 | /** |
360 | * rh_string - provides manufacturer, product and serial strings for root hub | 376 | * rh_string() - provides string descriptors for root hub |
361 | * @id: the string ID number (1: serial number, 2: product, 3: vendor) | 377 | * @id: the string ID number (0: langids, 1: serial #, 2: product, 3: vendor) |
362 | * @hcd: the host controller for this root hub | 378 | * @hcd: the host controller for this root hub |
363 | * @data: return packet in UTF-16 LE | 379 | * @data: buffer for output packet |
364 | * @len: length of the return packet | 380 | * @len: length of the provided buffer |
365 | * | 381 | * |
366 | * Produces either a manufacturer, product or serial number string for the | 382 | * Produces either a manufacturer, product or serial number string for the |
367 | * virtual root hub device. | 383 | * virtual root hub device. |
384 | * Returns the number of bytes filled in: the length of the descriptor or | ||
385 | * of the provided buffer, whichever is less. | ||
368 | */ | 386 | */ |
369 | static unsigned rh_string(int id, struct usb_hcd *hcd, u8 *data, unsigned len) | 387 | static unsigned |
388 | rh_string(int id, struct usb_hcd const *hcd, u8 *data, unsigned len) | ||
370 | { | 389 | { |
371 | char buf [100]; | 390 | char buf[100]; |
391 | char const *s; | ||
392 | static char const langids[4] = {4, USB_DT_STRING, 0x09, 0x04}; | ||
372 | 393 | ||
373 | // language ids | 394 | // language ids |
374 | if (id == 0) { | 395 | switch (id) { |
375 | buf[0] = 4; buf[1] = 3; /* 4 bytes string data */ | 396 | case 0: |
376 | buf[2] = 0x09; buf[3] = 0x04; /* MSFT-speak for "en-us" */ | 397 | /* Array of LANGID codes (0x0409 is MSFT-speak for "en-us") */ |
377 | len = min_t(unsigned, len, 4); | 398 | /* See http://www.usb.org/developers/docs/USB_LANGIDs.pdf */ |
378 | memcpy (data, buf, len); | 399 | if (len > 4) |
400 | len = 4; | ||
401 | memcpy(data, langids, len); | ||
379 | return len; | 402 | return len; |
380 | 403 | case 1: | |
381 | // serial number | 404 | /* Serial number */ |
382 | } else if (id == 1) { | 405 | s = hcd->self.bus_name; |
383 | strlcpy (buf, hcd->self.bus_name, sizeof buf); | 406 | break; |
384 | 407 | case 2: | |
385 | // product description | 408 | /* Product name */ |
386 | } else if (id == 2) { | 409 | s = hcd->product_desc; |
387 | strlcpy (buf, hcd->product_desc, sizeof buf); | 410 | break; |
388 | 411 | case 3: | |
389 | // id 3 == vendor description | 412 | /* Manufacturer */ |
390 | } else if (id == 3) { | ||
391 | snprintf (buf, sizeof buf, "%s %s %s", init_utsname()->sysname, | 413 | snprintf (buf, sizeof buf, "%s %s %s", init_utsname()->sysname, |
392 | init_utsname()->release, hcd->driver->description); | 414 | init_utsname()->release, hcd->driver->description); |
393 | } | 415 | s = buf; |
394 | 416 | break; | |
395 | switch (len) { /* All cases fall through */ | ||
396 | default: | 417 | default: |
397 | len = 2 + ascii2utf (buf, data + 2, len - 2); | 418 | /* Can't happen; caller guarantees it */ |
398 | case 2: | 419 | return 0; |
399 | data [1] = 3; /* type == string */ | ||
400 | case 1: | ||
401 | data [0] = 2 * (strlen (buf) + 1); | ||
402 | case 0: | ||
403 | ; /* Compiler wants a statement here */ | ||
404 | } | 420 | } |
405 | return len; | 421 | |
422 | return ascii2desc(s, data, len); | ||
406 | } | 423 | } |
407 | 424 | ||
408 | 425 | ||