aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorGeorge Spelvin <linux@horizon.com>2009-08-24 22:06:41 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-09-23 09:46:37 -0400
commit392ca68b401e0797115a08836642faad5778fdb2 (patch)
tree8215eb8d605a85d28581fd0ef29f978617a8468d /drivers/usb
parent48d316770bd4dcf3d21b53cfa91e358280c31d69 (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.c111
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 */
344static unsigned ascii2utf(char *s, u8 *utf, int utfmax) 352static unsigned
353ascii2desc(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 */
369static unsigned rh_string(int id, struct usb_hcd *hcd, u8 *data, unsigned len) 387static unsigned
388rh_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