Project

General

Profile

RE: Setting the ARM as a USB bulk device » usbstring.c

Michael Williamson, 10/18/2017 11:17 AM

 
1
/*
2
 * Copyright (C) 2003 David Brownell
3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU Lesser General Public License as published
6
 * by the Free Software Foundation; either version 2.1 of the License, or
7
 * (at your option) any later version.
8
 */
9

    
10
#include <errno.h>
11
#include <string.h>
12

    
13
#include <linux/types.h>
14
#include <linux/usb/ch9.h>
15

    
16
#include "usbstring.h"
17

    
18
static inline void put_unaligned_le16(__u16 val, __u16 *cp)
19
{
20
	__u8	*p = (void *)cp;
21

    
22
	*p++ = (__u8) val;
23
	*p++ = (__u8) (val >> 8);
24
}
25

    
26
static int utf8_to_utf16le(const char *s, __u16 *cp, unsigned len)
27
{
28
	int	count = 0;
29
	__u8	c;
30
	__u16	uchar;
31

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

    
43
				c = (__u8) *s++;
44
				if ((c & 0xc0) != 0xc0)
45
					goto fail;
46
				c &= 0x3f;
47
				uchar |= c;
48

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

    
54
				c = (__u8) *s++;
55
				if ((c & 0xc0) != 0xc0)
56
					goto fail;
57
				c &= 0x3f;
58
				uchar |= c << 6;
59

    
60
				c = (__u8) *s++;
61
				if ((c & 0xc0) != 0xc0)
62
					goto fail;
63
				c &= 0x3f;
64
				uchar |= c;
65

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

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

    
76
			} else
77
				goto fail;
78
		} else
79
			uchar = c;
80
		put_unaligned_le16 (uchar, cp++);
81
		count++;
82
		len--;
83
	}
84
	return count;
85
fail:
86
	return -1;
87
}
88

    
89

    
90
/**
91
 * usb_gadget_get_string - fill out a string descriptor 
92
 * @table: of c strings encoded using UTF-8
93
 * @id: string id, from low byte of wValue in get string descriptor
94
 * @buf: at least 256 bytes
95
 *
96
 * Finds the UTF-8 string matching the ID, and converts it into a
97
 * string descriptor in utf16-le.
98
 * Returns length of descriptor (always even) or negative errno
99
 *
100
 * If your driver needs strings in multiple languages, you'll probably
101
 * "switch (wIndex) { ... }"  in your ep0 string descriptor logic,
102
 * using this routine after choosing which set of UTF-8 strings to use.
103
 *
104
 * Note that US-ASCII is a strict subset of UTF-8; any string bytes with
105
 * the eighth bit set will be multibyte UTF-8 characters, not ISO-8859/1
106
 * characters.
107
 */
108
int
109
usb_gadget_get_string (struct usb_gadget_strings *table, int id, __u8 *buf)
110
{
111
	struct usb_string	*s;
112
	int			len;
113

    
114
	/* descriptor 0 has the language id */
115
	if (id == 0) {
116
		buf [0] = 4;
117
		buf [1] = USB_DT_STRING;
118
		buf [2] = (__u8) table->language;
119
		buf [3] = (__u8) (table->language >> 8);
120
		return 4;
121
	}
122
	for (s = table->strings; s && s->s; s++)
123
		if (s->id == id)
124
			break;
125

    
126
	/* unrecognized: stall. */
127
	if (!s || !s->s)
128
		return -EINVAL;
129

    
130
	/* string descriptors have length, tag, then UTF16-LE text */
131
	len = strlen (s->s);
132
	if (len > 126)
133
		len = 126;
134
	memset (buf + 2, 0, 2 * len);	/* zero all the bytes */
135
	len = utf8_to_utf16le(s->s, (__u16 *)&buf[2], len);
136
	if (len < 0)
137
		return -EINVAL;
138
	buf [0] = (len + 1) * 2;
139
	buf [1] = USB_DT_STRING;
140
	return buf [0];
141
}
142

    
(3-3/4) Go to top
Add picture from clipboard (Maximum size: 1 GB)