-
Notifications
You must be signed in to change notification settings - Fork 0
/
usb_descriptors.c
288 lines (267 loc) · 10.1 KB
/
usb_descriptors.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
/*
* USB Descriptors file
*
* This file may be used by anyone for any purpose and may be used as a
* starting point making your own application using M-Stack.
*
* It is worth noting that M-Stack itself is not under the same license as
* this file.
*
* M-Stack is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. For details, see sections 7, 8, and 9
* of the Apache License, version 2.0 which apply to this file. If you have
* purchased a commercial license for this software from Signal 11 Software,
* your commerical license superceeds the information in this header.
*
* Alan Ott
* Signal 11 Software
*/
#include "usb_config.h"
#include "usb.h"
#include "usb_ch9.h"
#include "usb_hid.h"
#ifdef __C18
#define ROMPTR rom
#else
#define ROMPTR
#endif
/* Configuration Packet
*
* This packet contains a configuration descriptor, one or more interface
* descriptors, class descriptors(optional), and endpoint descriptors for a
* single configuration of the device. This struct is specific to the
* device, so the application will need to add any interfaces, classes and
* endpoints it intends to use. It is sent to the host in response to a
* GET_DESCRIPTOR[CONFIGURATION] request.
*
* While Most devices will only have one configuration, a device can have as
* many configurations as it needs. To have more than one, simply make as
* many of these structs as are required, one for each configuration.
*
* An instance of each configuration packet must be put in the
* usb_application_config_descs[] array below (which is #defined in
* usb_config.h) so that the USB stack can find it.
*
* See Chapter 9 of the USB specification from usb.org for details.
*
* It's worth noting that adding endpoints here does not automatically
* enable them in the USB stack. To use an endpoint, it must be declared
* here and also in usb_config.h.
*
* The configuration packet below is for the mouse demo application.
* Yours will of course vary.
*/
struct configuration_1_packet {
struct configuration_descriptor config;
struct interface_descriptor interface;
struct hid_descriptor hid;
struct endpoint_descriptor ep;
struct endpoint_descriptor ep1_out;
};
/* Device Descriptor
*
* Each device has a single device descriptor describing the device. The
* format is described in Chapter 9 of the USB specification from usb.org.
* USB_DEVICE_DESCRIPTOR needs to be defined to the name of this object in
* usb_config.h. For more information, see USB_DEVICE_DESCRIPTOR in usb.h.
*/
const ROMPTR struct device_descriptor this_device_descriptor =
{
sizeof(struct device_descriptor), // bLength
DESC_DEVICE, // bDescriptorType
0x0200, // 0x0200 = USB 2.0, 0x0110 = USB 1.1
0x00, // Device class
0x00, // Device Subclass
0x00, // Protocol.
EP_0_LEN, // bMaxPacketSize0
0xA0A0, // Vendor
0x0003, // Product
0x0001, // device release (1.0)
1, // Manufacturer
2, // Product
0, // Serial
NUMBER_OF_CONFIGURATIONS // NumConfigurations
};
static const ROMPTR uint8_t keyboard_report_descriptor[] = {
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x06, // USAGE (Keyboard)
0xa1, 0x01, // COLLECTION (Application)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x08, // REPORT_COUNT (8)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x08, // REPORT_COUNT (8)
0x81, 0x03, // INPUT (Cnst,Var,Abs)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x06, // REPORT_COUNT (6)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
0x81, 0x00, // INPUT (Data,Ary,Abs)
0xc0 // END_COLLECTION
};
/* Configuration Packet Instance
*
* This is an instance of the configuration_packet struct containing all the
* data describing a single configuration of this device. It is wise to use
* as much C here as possible, such as sizeof() operators, and #defines from
* usb_config.h. When stuff is wrong here, it can be difficult to track
* down exactly why, so it's good to get the compiler to do as much of it
* for you as it can.
*/
static const ROMPTR struct configuration_1_packet configuration_1 =
{
{
// Members from struct configuration_descriptor
sizeof(struct configuration_descriptor),
DESC_CONFIGURATION,
sizeof(configuration_1), // wTotalLength (length of the whole packet)
1, // bNumInterfaces
1, // bConfigurationValue
2, // iConfiguration (index of string descriptor)
0b10000000,
100/2, // 100/2 indicates 100mA
},
{
// Members from struct interface_descriptor
sizeof(struct interface_descriptor), // bLength;
DESC_INTERFACE,
0x0, // InterfaceNumber
0x0, // AlternateSetting
0x2, // bNumEndpoints (num besides endpoint 0)
HID_INTERFACE_CLASS, // bInterfaceClass 3=HID, 0xFF=VendorDefined
0x00, // bInterfaceSubclass (0=NoBootInterface for HID)
0x00, // bInterfaceProtocol
0x02, // iInterface (index of string describing interface)
},
{
// Members from struct hid_descriptor
sizeof(struct hid_descriptor),
DESC_HID,
0x0101, // bcdHID
0x0, // bCountryCode
1, // bNumDescriptors
DESC_REPORT, // bDescriptorType2
sizeof(keyboard_report_descriptor), // wDescriptorLength
},
{
// Members of the Endpoint Descriptor (EP1 IN)
sizeof(struct endpoint_descriptor),
DESC_ENDPOINT,
0x01 | 0x80, // endpoint #1 0x80=IN
EP_INTERRUPT, // bmAttributes
EP_1_IN_LEN, // wMaxPacketSize
1, // bInterval in ms.
},
{
// Members of the Endpoint Descriptor (EP1 OUT)
sizeof(struct endpoint_descriptor),
DESC_ENDPOINT,
0x01 /*| 0x00*/, // endpoint #1 0x00=OUT
EP_INTERRUPT, // bmAttributes
EP_1_OUT_LEN, // wMaxPacketSize
1, // bInterval in ms.
},
};
/* String Descriptors
*
* String descriptors are optional. If strings are used, string #0 is
* required, and must contain the language ID of the other strings. See
* Chapter 9 of the USB specification from usb.org for more info.
*
* Strings are UTF-16 Unicode, and are not NULL-terminated, hence the
* unusual syntax.
*/
/* String index 0, only has one character in it, which is to be set to the
language ID of the language which the other strings are in. */
static const ROMPTR struct {uint8_t bLength;uint8_t bDescriptorType; uint16_t lang; } str00 = {
sizeof(str00),
DESC_STRING,
0x0409 // US English
};
static const ROMPTR struct {uint8_t bLength;uint8_t bDescriptorType; uint16_t chars[6]; } vendor_string = {
sizeof(vendor_string),
DESC_STRING,
{'V','o','x','h','u','b'}
};
static const ROMPTR struct {uint8_t bLength;uint8_t bDescriptorType; uint16_t chars[13]; } product_string = {
sizeof(product_string),
DESC_STRING,
{'S','i','l','v','i','u','s',' ','b','t','k','e','y'}
};
static const ROMPTR struct {uint8_t bLength;uint8_t bDescriptorType; uint16_t chars[8]; } interface_string = {
sizeof(interface_string),
DESC_STRING,
{'K','e','y','b','o','a','r','d'}
};
/* Get String function
*
* This function is called by the USB stack to get a pointer to a string
* descriptor. If using strings, USB_STRING_DESCRIPTOR_FUNC must be defined
* to the name of this function in usb_config.h. See
* USB_STRING_DESCRIPTOR_FUNC in usb.h for information about this function.
* This is a function, and not simply a list or map, because it is useful,
* and advisable, to have a serial number string which may be read from
* EEPROM or somewhere that's not part of static program memory.
*/
int16_t usb_application_get_string(uint8_t string_number, const void **ptr)
{
if (string_number == 0) {
*ptr = &str00;
return sizeof(str00);
}
else if (string_number == 1) {
*ptr = &vendor_string;
return sizeof(vendor_string);
}
else if (string_number == 2) {
*ptr = &product_string;
return sizeof(product_string);
}
else if (string_number == 3) {
/* This is where you might have code to do something like read
a serial number out of EEPROM and return it. */
return -1;
}
return -1;
}
/* Configuration Descriptor List
*
* This is the list of pointters to the device's configuration descriptors.
* The USB stack will read this array looking for descriptors which are
* requsted from the host. USB_CONFIG_DESCRIPTOR_MAP must be defined to the
* name of this array in usb_config.h. See USB_CONFIG_DESCRIPTOR_MAP in
* usb.h for information about this array. The order of the descriptors is
* not important, as the USB stack reads bConfigurationValue for each
* descriptor to know its index. Make sure NUMBER_OF_CONFIGURATIONS in
* usb_config.h matches the number of descriptors in this array.
*/
const struct configuration_descriptor *usb_application_config_descs[] =
{
(struct configuration_descriptor*) &configuration_1,
};
STATIC_SIZE_CHECK_EQUAL(USB_ARRAYLEN(USB_CONFIG_DESCRIPTOR_MAP), NUMBER_OF_CONFIGURATIONS);
STATIC_SIZE_CHECK_EQUAL(sizeof(USB_DEVICE_DESCRIPTOR), 18);
/* HID Descriptor Function */
int16_t usb_application_get_hid_descriptor(uint8_t interface, const void **ptr)
{
/* Only one interface in this demo. The two-step assignment avoids an
* incorrect error in XC8 on PIC16. */
const void *p = &configuration_1.hid;
*ptr = p;
return sizeof(configuration_1.hid);
}
/** HID Report Descriptor Function */
int16_t usb_application_get_hid_report_descriptor(uint8_t interface, const void **ptr)
{
*ptr = keyboard_report_descriptor;
return sizeof(keyboard_report_descriptor);
}