Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: LGPL-2.1+
0002 /*
0003  * Copyright (C) 2003 David Brownell
0004  */
0005 
0006 #include <linux/errno.h>
0007 #include <linux/kernel.h>
0008 #include <linux/module.h>
0009 #include <linux/list.h>
0010 #include <linux/string.h>
0011 #include <linux/device.h>
0012 #include <linux/nls.h>
0013 
0014 #include <linux/usb/ch9.h>
0015 #include <linux/usb/gadget.h>
0016 
0017 
0018 /**
0019  * usb_gadget_get_string - fill out a string descriptor 
0020  * @table: of c strings encoded using UTF-8
0021  * @id: string id, from low byte of wValue in get string descriptor
0022  * @buf: at least 256 bytes, must be 16-bit aligned
0023  *
0024  * Finds the UTF-8 string matching the ID, and converts it into a
0025  * string descriptor in utf16-le.
0026  * Returns length of descriptor (always even) or negative errno
0027  *
0028  * If your driver needs stings in multiple languages, you'll probably
0029  * "switch (wIndex) { ... }"  in your ep0 string descriptor logic,
0030  * using this routine after choosing which set of UTF-8 strings to use.
0031  * Note that US-ASCII is a strict subset of UTF-8; any string bytes with
0032  * the eighth bit set will be multibyte UTF-8 characters, not ISO-8859/1
0033  * characters (which are also widely used in C strings).
0034  */
0035 int
0036 usb_gadget_get_string (const struct usb_gadget_strings *table, int id, u8 *buf)
0037 {
0038     struct usb_string   *s;
0039     int         len;
0040 
0041     /* descriptor 0 has the language id */
0042     if (id == 0) {
0043         buf [0] = 4;
0044         buf [1] = USB_DT_STRING;
0045         buf [2] = (u8) table->language;
0046         buf [3] = (u8) (table->language >> 8);
0047         return 4;
0048     }
0049     for (s = table->strings; s && s->s; s++)
0050         if (s->id == id)
0051             break;
0052 
0053     /* unrecognized: stall. */
0054     if (!s || !s->s)
0055         return -EINVAL;
0056 
0057     /* string descriptors have length, tag, then UTF16-LE text */
0058     len = min((size_t)USB_MAX_STRING_LEN, strlen(s->s));
0059     len = utf8s_to_utf16s(s->s, len, UTF16_LITTLE_ENDIAN,
0060             (wchar_t *) &buf[2], USB_MAX_STRING_LEN);
0061     if (len < 0)
0062         return -EINVAL;
0063     buf [0] = (len + 1) * 2;
0064     buf [1] = USB_DT_STRING;
0065     return buf [0];
0066 }
0067 EXPORT_SYMBOL_GPL(usb_gadget_get_string);
0068 
0069 /**
0070  * usb_validate_langid - validate usb language identifiers
0071  * @langid: usb language identifier
0072  *
0073  * Returns true for valid language identifier, otherwise false.
0074  */
0075 bool usb_validate_langid(u16 langid)
0076 {
0077     u16 primary_lang = langid & 0x3ff;  /* bit [9:0] */
0078     u16 sub_lang = langid >> 10;        /* bit [15:10] */
0079 
0080     switch (primary_lang) {
0081     case 0:
0082     case 0x62 ... 0xfe:
0083     case 0x100 ... 0x3ff:
0084         return false;
0085     }
0086     if (!sub_lang)
0087         return false;
0088 
0089     return true;
0090 }
0091 EXPORT_SYMBOL_GPL(usb_validate_langid);