diff options
Diffstat (limited to 'lib/chibios/demos/AVR/RT-ARDUINO-LEONARDO/usbcfg.c')
-rw-r--r-- | lib/chibios/demos/AVR/RT-ARDUINO-LEONARDO/usbcfg.c | 402 |
1 files changed, 402 insertions, 0 deletions
diff --git a/lib/chibios/demos/AVR/RT-ARDUINO-LEONARDO/usbcfg.c b/lib/chibios/demos/AVR/RT-ARDUINO-LEONARDO/usbcfg.c new file mode 100644 index 000000000..629a48f24 --- /dev/null +++ b/lib/chibios/demos/AVR/RT-ARDUINO-LEONARDO/usbcfg.c | |||
@@ -0,0 +1,402 @@ | |||
1 | /* | ||
2 | ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio | ||
3 | |||
4 | Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | you may not use this file except in compliance with the License. | ||
6 | You may obtain a copy of the License at | ||
7 | |||
8 | http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | |||
10 | Unless required by applicable law or agreed to in writing, software | ||
11 | distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | See the License for the specific language governing permissions and | ||
14 | limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #include "ch.h" | ||
18 | #include "hal.h" | ||
19 | #include "usbcfg.h" | ||
20 | |||
21 | /* | ||
22 | * Endpoints to be used for USBD1. | ||
23 | */ | ||
24 | #define USBD1_DATA_REQUEST_EP 1 | ||
25 | #define USBD1_DATA_AVAILABLE_EP 3 | ||
26 | #define USBD1_INTERRUPT_REQUEST_EP 2 | ||
27 | |||
28 | #if (AVR_USB_USE_NAMED_ADDRESS_SPACES == TRUE) && defined(__FLASH) | ||
29 | # undef ROMCONST | ||
30 | # define ROMCONST const __flash | ||
31 | #endif | ||
32 | |||
33 | /* Virtual serial port over USB.*/ | ||
34 | SerialUSBDriver SDU1; | ||
35 | |||
36 | /* | ||
37 | * USB Device Descriptor. | ||
38 | */ | ||
39 | static ROMCONST uint8_t vcom_device_descriptor_data[18] = { | ||
40 | USB_DESC_DEVICE (0x0110, /* bcdUSB (1.1). */ | ||
41 | 0x02, /* bDeviceClass (CDC). */ | ||
42 | 0x00, /* bDeviceSubClass. */ | ||
43 | 0x00, /* bDeviceProtocol. */ | ||
44 | 0x40, /* bMaxPacketSize. */ | ||
45 | 0x2341, /* idVendor (Arduino LLC). */ | ||
46 | 0x0036, /* idProduct. */ | ||
47 | 0x0200, /* bcdDevice. */ | ||
48 | 2, /* iManufacturer. */ | ||
49 | 1, /* iProduct. */ | ||
50 | 3, /* iSerialNumber. */ | ||
51 | 1) /* bNumConfigurations. */ | ||
52 | }; | ||
53 | |||
54 | /* | ||
55 | * Device Descriptor wrapper. | ||
56 | */ | ||
57 | static ROMCONST USBDescriptor vcom_device_descriptor = { | ||
58 | sizeof vcom_device_descriptor_data, | ||
59 | vcom_device_descriptor_data | ||
60 | }; | ||
61 | |||
62 | /* Configuration Descriptor tree for a CDC.*/ | ||
63 | static ROMCONST uint8_t vcom_configuration_descriptor_data[67] = { | ||
64 | /* Configuration Descriptor.*/ | ||
65 | USB_DESC_CONFIGURATION(67, /* wTotalLength. */ | ||
66 | 0x02, /* bNumInterfaces. */ | ||
67 | 0x01, /* bConfigurationValue. */ | ||
68 | 0, /* iConfiguration. */ | ||
69 | 0xC0, /* bmAttributes (self powered). */ | ||
70 | 50), /* bMaxPower (100mA). */ | ||
71 | /* Interface Descriptor.*/ | ||
72 | USB_DESC_INTERFACE (0x00, /* bInterfaceNumber. */ | ||
73 | 0x00, /* bAlternateSetting. */ | ||
74 | 0x01, /* bNumEndpoints. */ | ||
75 | 0x02, /* bInterfaceClass (Communications | ||
76 | Interface Class, CDC section | ||
77 | 4.2). */ | ||
78 | 0x02, /* bInterfaceSubClass (Abstract | ||
79 | Control Model, CDC section 4.3). */ | ||
80 | 0x01, /* bInterfaceProtocol (AT commands, | ||
81 | CDC section 4.4). */ | ||
82 | 0), /* iInterface. */ | ||
83 | /* Header Functional Descriptor (CDC section 5.2.3).*/ | ||
84 | USB_DESC_BYTE (5), /* bLength. */ | ||
85 | USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ | ||
86 | USB_DESC_BYTE (0x00), /* bDescriptorSubtype (Header | ||
87 | Functional Descriptor. */ | ||
88 | USB_DESC_BCD (0x0110), /* bcdCDC. */ | ||
89 | /* Call Management Functional Descriptor. */ | ||
90 | USB_DESC_BYTE (5), /* bFunctionLength. */ | ||
91 | USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ | ||
92 | USB_DESC_BYTE (0x01), /* bDescriptorSubtype (Call Management | ||
93 | Functional Descriptor). */ | ||
94 | USB_DESC_BYTE (0x00), /* bmCapabilities (D0+D1). */ | ||
95 | USB_DESC_BYTE (0x01), /* bDataInterface. */ | ||
96 | /* ACM Functional Descriptor.*/ | ||
97 | USB_DESC_BYTE (4), /* bFunctionLength. */ | ||
98 | USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ | ||
99 | USB_DESC_BYTE (0x02), /* bDescriptorSubtype (Abstract | ||
100 | Control Management Descriptor). */ | ||
101 | USB_DESC_BYTE (0x02), /* bmCapabilities. */ | ||
102 | /* Union Functional Descriptor.*/ | ||
103 | USB_DESC_BYTE (5), /* bFunctionLength. */ | ||
104 | USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ | ||
105 | USB_DESC_BYTE (0x06), /* bDescriptorSubtype (Union | ||
106 | Functional Descriptor). */ | ||
107 | USB_DESC_BYTE (0x00), /* bMasterInterface (Communication | ||
108 | Class Interface). */ | ||
109 | USB_DESC_BYTE (0x01), /* bSlaveInterface0 (Data Class | ||
110 | Interface). */ | ||
111 | /* Endpoint 2 Descriptor.*/ | ||
112 | USB_DESC_ENDPOINT (USBD1_INTERRUPT_REQUEST_EP|0x80, | ||
113 | 0x03, /* bmAttributes (Interrupt). */ | ||
114 | 0x0008, /* wMaxPacketSize. */ | ||
115 | 0xFF), /* bInterval. */ | ||
116 | /* Interface Descriptor.*/ | ||
117 | USB_DESC_INTERFACE (0x01, /* bInterfaceNumber. */ | ||
118 | 0x00, /* bAlternateSetting. */ | ||
119 | 0x02, /* bNumEndpoints. */ | ||
120 | 0x0A, /* bInterfaceClass (Data Class | ||
121 | Interface, CDC section 4.5). */ | ||
122 | 0x00, /* bInterfaceSubClass (CDC section | ||
123 | 4.6). */ | ||
124 | 0x00, /* bInterfaceProtocol (CDC section | ||
125 | 4.7). */ | ||
126 | 0x00), /* iInterface. */ | ||
127 | /* Endpoint 3 Descriptor.*/ | ||
128 | USB_DESC_ENDPOINT (USBD1_DATA_AVAILABLE_EP, /* bEndpointAddress.*/ | ||
129 | 0x02, /* bmAttributes (Bulk). */ | ||
130 | 0x0040, /* wMaxPacketSize. */ | ||
131 | 0x00), /* bInterval. */ | ||
132 | /* Endpoint 1 Descriptor.*/ | ||
133 | USB_DESC_ENDPOINT (USBD1_DATA_REQUEST_EP|0x80, /* bEndpointAddress.*/ | ||
134 | 0x02, /* bmAttributes (Bulk). */ | ||
135 | 0x0040, /* wMaxPacketSize. */ | ||
136 | 0x00) /* bInterval. */ | ||
137 | }; | ||
138 | |||
139 | /* | ||
140 | * Configuration Descriptor wrapper. | ||
141 | */ | ||
142 | static ROMCONST USBDescriptor vcom_configuration_descriptor = { | ||
143 | sizeof vcom_configuration_descriptor_data, | ||
144 | vcom_configuration_descriptor_data | ||
145 | }; | ||
146 | |||
147 | /* | ||
148 | * U.S. English language identifier. | ||
149 | */ | ||
150 | static ROMCONST uint8_t vcom_string0[] = { | ||
151 | USB_DESC_BYTE(4), /* bLength. */ | ||
152 | USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ | ||
153 | USB_DESC_WORD(0x0409) /* wLANGID (U.S. English). */ | ||
154 | }; | ||
155 | |||
156 | /* | ||
157 | * Vendor string. | ||
158 | */ | ||
159 | static ROMCONST uint8_t vcom_string1[] = { | ||
160 | USB_DESC_BYTE(24), /* bLength. */ | ||
161 | USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ | ||
162 | 'A', 0, 'r', 0, 'd', 0, 'u', 0, 'i', 0, 'n', 0, 'o', 0, | ||
163 | ' ', 0, 'L', 0, 'L', 0, 'C', 0 | ||
164 | }; | ||
165 | |||
166 | /* | ||
167 | * Device Description string. | ||
168 | */ | ||
169 | static ROMCONST uint8_t vcom_string2[] = { | ||
170 | USB_DESC_BYTE(56), /* bLength. */ | ||
171 | USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ | ||
172 | 'C', 0, 'h', 0, 'i', 0, 'b', 0, 'i', 0, 'O', 0, 'S', 0, '/', 0, | ||
173 | 'R', 0, 'T', 0, ' ', 0, 'V', 0, 'i', 0, 'r', 0, 't', 0, 'u', 0, | ||
174 | 'a', 0, 'l', 0, ' ', 0, 'C', 0, 'O', 0, 'M', 0, ' ', 0, 'P', 0, | ||
175 | 'o', 0, 'r', 0, 't', 0 | ||
176 | }; | ||
177 | |||
178 | /* | ||
179 | * Serial Number string. | ||
180 | */ | ||
181 | static ROMCONST uint8_t vcom_string3[] = { | ||
182 | USB_DESC_BYTE(8), /* bLength. */ | ||
183 | USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ | ||
184 | '0' + CH_KERNEL_MAJOR, 0, | ||
185 | '0' + CH_KERNEL_MINOR, 0, | ||
186 | '0' + CH_KERNEL_PATCH, 0 | ||
187 | }; | ||
188 | |||
189 | /* | ||
190 | * Strings wrappers array. | ||
191 | */ | ||
192 | static ROMCONST USBDescriptor vcom_strings[] = { | ||
193 | {sizeof vcom_string0, vcom_string0}, | ||
194 | {sizeof vcom_string1, vcom_string1}, | ||
195 | {sizeof vcom_string2, vcom_string2}, | ||
196 | {sizeof vcom_string3, vcom_string3} | ||
197 | }; | ||
198 | |||
199 | /* | ||
200 | * Handles the GET_DESCRIPTOR callback. All required descriptors must be | ||
201 | * handled here. | ||
202 | */ | ||
203 | static const USBDescriptor *get_descriptor(USBDriver *usbp, | ||
204 | uint8_t dtype, | ||
205 | uint8_t dindex, | ||
206 | uint16_t lang) { | ||
207 | |||
208 | (void)usbp; | ||
209 | (void)lang; | ||
210 | switch (dtype) { | ||
211 | case USB_DESCRIPTOR_DEVICE: | ||
212 | return &vcom_device_descriptor; | ||
213 | case USB_DESCRIPTOR_CONFIGURATION: | ||
214 | return &vcom_configuration_descriptor; | ||
215 | case USB_DESCRIPTOR_STRING: | ||
216 | if (dindex < 4) | ||
217 | return &vcom_strings[dindex]; | ||
218 | } | ||
219 | return NULL; | ||
220 | } | ||
221 | |||
222 | /** | ||
223 | * @brief IN EP1 state. | ||
224 | */ | ||
225 | static USBInEndpointState ep1state; | ||
226 | |||
227 | /** | ||
228 | * @brief EP1 initialization structure (IN). | ||
229 | */ | ||
230 | static const USBEndpointConfig ep1config = { | ||
231 | USB_EP_MODE_TYPE_BULK, | ||
232 | NULL, | ||
233 | sduDataTransmitted, | ||
234 | NULL, | ||
235 | 0x0040, | ||
236 | 0x0000, | ||
237 | &ep1state, | ||
238 | NULL, | ||
239 | }; | ||
240 | |||
241 | /** | ||
242 | * @brief INTR EP2 state. | ||
243 | */ | ||
244 | static USBInEndpointState ep2state; | ||
245 | |||
246 | /** | ||
247 | * @brief EP2 initialization structure. | ||
248 | */ | ||
249 | static const USBEndpointConfig ep2config = { | ||
250 | USB_EP_MODE_TYPE_INTR, | ||
251 | NULL, | ||
252 | sduInterruptTransmitted, | ||
253 | NULL, | ||
254 | 0x0010, | ||
255 | 0x0000, | ||
256 | &ep2state, | ||
257 | NULL | ||
258 | }; | ||
259 | |||
260 | /** | ||
261 | * @brief OUT EP3 state. | ||
262 | */ | ||
263 | static USBOutEndpointState ep3state; | ||
264 | |||
265 | /** | ||
266 | * @brief EP3 initialization structure (OUT). | ||
267 | */ | ||
268 | static const USBEndpointConfig ep3config = { | ||
269 | USB_EP_MODE_TYPE_BULK, | ||
270 | NULL, | ||
271 | NULL, | ||
272 | sduDataReceived, | ||
273 | 0x0000, | ||
274 | 0x0040, | ||
275 | NULL, | ||
276 | &ep3state, | ||
277 | }; | ||
278 | |||
279 | /* | ||
280 | * Handles the USB driver global events. | ||
281 | */ | ||
282 | static void usb_event(USBDriver *usbp, usbevent_t event) { | ||
283 | extern SerialUSBDriver SDU1; | ||
284 | |||
285 | switch (event) { | ||
286 | case USB_EVENT_ADDRESS: | ||
287 | return; | ||
288 | case USB_EVENT_CONFIGURED: | ||
289 | chSysLockFromISR(); | ||
290 | |||
291 | /* Enables the endpoints specified into the configuration. | ||
292 | Note, this callback is invoked from an ISR so I-Class functions | ||
293 | must be used.*/ | ||
294 | usbInitEndpointI(usbp, USBD1_DATA_REQUEST_EP, &ep1config); | ||
295 | usbInitEndpointI(usbp, USBD1_DATA_AVAILABLE_EP, &ep2config); | ||
296 | usbInitEndpointI(usbp, USBD1_INTERRUPT_REQUEST_EP, &ep3config); | ||
297 | |||
298 | /* Resetting the state of the CDC subsystem.*/ | ||
299 | sduConfigureHookI(&SDU1); | ||
300 | |||
301 | chSysUnlockFromISR(); | ||
302 | return; | ||
303 | case USB_EVENT_RESET: | ||
304 | /* Falls into.*/ | ||
305 | case USB_EVENT_UNCONFIGURED: | ||
306 | /* Falls into.*/ | ||
307 | case USB_EVENT_SUSPEND: | ||
308 | chSysLockFromISR(); | ||
309 | |||
310 | /* Disconnection event on suspend.*/ | ||
311 | sduSuspendHookI(&SDU1); | ||
312 | |||
313 | chSysUnlockFromISR(); | ||
314 | return; | ||
315 | case USB_EVENT_WAKEUP: | ||
316 | chSysLockFromISR(); | ||
317 | |||
318 | /* Connection event on wakeup.*/ | ||
319 | sduWakeupHookI(&SDU1); | ||
320 | |||
321 | chSysUnlockFromISR(); | ||
322 | return; | ||
323 | case USB_EVENT_STALLED: | ||
324 | return; | ||
325 | } | ||
326 | return; | ||
327 | } | ||
328 | |||
329 | bool usb_setup_hook(USBDriver *usbp) { | ||
330 | /* Override GET_DESCRIPTOR requests to return data from program memory */ | ||
331 | if ((usbp->setup[0] & (USB_RTYPE_RECIPIENT_MASK | USB_RTYPE_TYPE_MASK)) == | ||
332 | (USB_RTYPE_RECIPIENT_DEVICE | USB_RTYPE_TYPE_STD) && | ||
333 | usbp->setup[1] == USB_REQ_GET_DESCRIPTOR) { | ||
334 | const uint8_t dtype = usbp->setup[3]; | ||
335 | const uint8_t dindex = usbp->setup[2]; | ||
336 | const AVR_USB_TX_BUF_ADDRESS_SPACE uint8_t *ddata = NULL; | ||
337 | size_t dsize = 0; | ||
338 | switch (dtype) { | ||
339 | case USB_DESCRIPTOR_DEVICE: | ||
340 | dsize = sizeof(vcom_device_descriptor_data); | ||
341 | ddata = vcom_device_descriptor_data; | ||
342 | break; | ||
343 | case USB_DESCRIPTOR_CONFIGURATION: | ||
344 | dsize = sizeof(vcom_configuration_descriptor_data); | ||
345 | ddata = vcom_configuration_descriptor_data; | ||
346 | break; | ||
347 | case USB_DESCRIPTOR_STRING: | ||
348 | if (dindex == 0) { | ||
349 | dsize = sizeof(vcom_string0); | ||
350 | ddata = vcom_string0; | ||
351 | } else if (dindex == 1) { | ||
352 | dsize = sizeof(vcom_string1); | ||
353 | ddata = vcom_string1; | ||
354 | } else if (dindex == 2) { | ||
355 | dsize = sizeof(vcom_string2); | ||
356 | ddata = vcom_string2; | ||
357 | } else if (dindex == 3) { | ||
358 | dsize = sizeof(vcom_string3); | ||
359 | ddata = vcom_string3; | ||
360 | } | ||
361 | break; | ||
362 | } | ||
363 | if (ddata == NULL) { | ||
364 | return false; | ||
365 | } | ||
366 | |||
367 | usbSetupTransfer(usbp, ddata, dsize, NULL); | ||
368 | return true; | ||
369 | } | ||
370 | return sduRequestsHook(usbp); | ||
371 | } | ||
372 | |||
373 | /* | ||
374 | * Handles the USB driver start of frame event. | ||
375 | */ | ||
376 | static void sof_handler(USBDriver *usbp) { | ||
377 | (void)usbp; | ||
378 | |||
379 | osalSysLockFromISR(); | ||
380 | sduSOFHookI(&SDU1); | ||
381 | osalSysUnlockFromISR(); | ||
382 | } | ||
383 | |||
384 | /* | ||
385 | * USB driver configuration. | ||
386 | */ | ||
387 | const USBConfig usbcfg = { | ||
388 | usb_event, | ||
389 | get_descriptor, | ||
390 | usb_setup_hook, | ||
391 | sof_handler | ||
392 | }; | ||
393 | |||
394 | /* | ||
395 | * Serial over USB driver configuration. | ||
396 | */ | ||
397 | const SerialUSBConfig serusbcfg = { | ||
398 | &USBD1, | ||
399 | USBD1_DATA_REQUEST_EP, | ||
400 | USBD1_DATA_AVAILABLE_EP, | ||
401 | USBD1_INTERRUPT_REQUEST_EP | ||
402 | }; | ||