Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 86dc243c authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman
Browse files

USB: remove homegrown UTF conversion routine for gadgets



This patch (as1502) removes the UTF8-to-UTF16 conversion routine in
the USB gadget library and replaces it with a call to the equivalent
function in the NLS library.

The only downside worth noting is that the NLS library routine
requires the output buffer to be 16-bit aligned.  This is always true
in the gadget code, because the output buffer is always a
usb_request buffer being used to send a string descriptor.

Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 0720a06a
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -15,6 +15,7 @@


menuconfig USB_GADGET
menuconfig USB_GADGET
	tristate "USB Gadget Support"
	tristate "USB Gadget Support"
	select NLS
	help
	help
	   USB is a master/slave protocol, organized with one master
	   USB is a master/slave protocol, organized with one master
	   host (such as a PC) controlling up to 127 peripheral devices.
	   host (such as a PC) controlling up to 127 peripheral devices.
+4 −69
Original line number Original line Diff line number Diff line
@@ -13,82 +13,17 @@
#include <linux/string.h>
#include <linux/string.h>
#include <linux/device.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/init.h>
#include <linux/nls.h>


#include <linux/usb/ch9.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/gadget.h>


#include <asm/unaligned.h>


static int utf8_to_utf16le(const char *s, __le16 *cp, unsigned len)
{
	int	count = 0;
	u8	c;
	u16	uchar;

	/* this insists on correct encodings, though not minimal ones.
	 * BUT it currently rejects legit 4-byte UTF-8 code points,
	 * which need surrogate pairs.  (Unicode 3.1 can use them.)
	 */
	while (len != 0 && (c = (u8) *s++) != 0) {
		if (unlikely(c & 0x80)) {
			// 2-byte sequence:
			// 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
			if ((c & 0xe0) == 0xc0) {
				uchar = (c & 0x1f) << 6;

				c = (u8) *s++;
				if ((c & 0xc0) != 0x80)
					goto fail;
				c &= 0x3f;
				uchar |= c;

			// 3-byte sequence (most CJKV characters):
			// zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
			} else if ((c & 0xf0) == 0xe0) {
				uchar = (c & 0x0f) << 12;

				c = (u8) *s++;
				if ((c & 0xc0) != 0x80)
					goto fail;
				c &= 0x3f;
				uchar |= c << 6;

				c = (u8) *s++;
				if ((c & 0xc0) != 0x80)
					goto fail;
				c &= 0x3f;
				uchar |= c;

				/* no bogus surrogates */
				if (0xd800 <= uchar && uchar <= 0xdfff)
					goto fail;

			// 4-byte sequence (surrogate pairs, currently rare):
			// 11101110wwwwzzzzyy + 110111yyyyxxxxxx
			//     = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
			// (uuuuu = wwww + 1)
			// FIXME accept the surrogate code points (only)

			} else
				goto fail;
		} else
			uchar = c;
		put_unaligned_le16(uchar, cp++);
		count++;
		len--;
	}
	return count;
fail:
	return -1;
}



/**
/**
 * usb_gadget_get_string - fill out a string descriptor 
 * usb_gadget_get_string - fill out a string descriptor 
 * @table: of c strings encoded using UTF-8
 * @table: of c strings encoded using UTF-8
 * @id: string id, from low byte of wValue in get string descriptor
 * @id: string id, from low byte of wValue in get string descriptor
 * @buf: at least 256 bytes
 * @buf: at least 256 bytes, must be 16-bit aligned
 *
 *
 * Finds the UTF-8 string matching the ID, and converts it into a
 * Finds the UTF-8 string matching the ID, and converts it into a
 * string descriptor in utf16-le.
 * string descriptor in utf16-le.
@@ -125,8 +60,8 @@ usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf)


	/* string descriptors have length, tag, then UTF16-LE text */
	/* string descriptors have length, tag, then UTF16-LE text */
	len = min ((size_t) 126, strlen (s->s));
	len = min ((size_t) 126, strlen (s->s));
	memset (buf + 2, 0, 2 * len);	/* zero all the bytes */
	len = utf8s_to_utf16s(s->s, len, UTF16_LITTLE_ENDIAN,
	len = utf8_to_utf16le(s->s, (__le16 *)&buf[2], len);
			(wchar_t *) &buf[2], 126);
	if (len < 0)
	if (len < 0)
		return -EINVAL;
		return -EINVAL;
	buf [0] = (len + 1) * 2;
	buf [0] = (len + 1) * 2;