Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2 | mjames | 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 "hal.h" |
||
18 | |||
19 | /* Virtual serial port over USB.*/ |
||
20 | SerialUSBDriver SDU1; |
||
21 | |||
22 | /* |
||
23 | * Endpoints to be used for USBD1. |
||
24 | */ |
||
25 | #define USBD1_DATA_REQUEST_EP 1 |
||
26 | #define USBD1_DATA_AVAILABLE_EP 1 |
||
27 | #define USBD1_INTERRUPT_REQUEST_EP 2 |
||
28 | |||
29 | /* |
||
30 | * USB Device Descriptor. |
||
31 | */ |
||
32 | static const uint8_t vcom_device_descriptor_data[18] = { |
||
33 | USB_DESC_DEVICE (0x0110, /* bcdUSB (1.1). */ |
||
34 | 0x02, /* bDeviceClass (CDC). */ |
||
35 | 0x00, /* bDeviceSubClass. */ |
||
36 | 0x00, /* bDeviceProtocol. */ |
||
37 | 0x40, /* bMaxPacketSize. */ |
||
38 | 0x0483, /* idVendor (ST). */ |
||
39 | 0x5740, /* idProduct. */ |
||
40 | 0x0200, /* bcdDevice. */ |
||
41 | 1, /* iManufacturer. */ |
||
42 | 2, /* iProduct. */ |
||
43 | 3, /* iSerialNumber. */ |
||
44 | 1) /* bNumConfigurations. */ |
||
45 | }; |
||
46 | |||
47 | /* |
||
48 | * Device Descriptor wrapper. |
||
49 | */ |
||
50 | static const USBDescriptor vcom_device_descriptor = { |
||
51 | sizeof vcom_device_descriptor_data, |
||
52 | vcom_device_descriptor_data |
||
53 | }; |
||
54 | |||
55 | /* Configuration Descriptor tree for a CDC.*/ |
||
56 | static const uint8_t vcom_configuration_descriptor_data[67] = { |
||
57 | /* Configuration Descriptor.*/ |
||
58 | USB_DESC_CONFIGURATION(67, /* wTotalLength. */ |
||
59 | 0x02, /* bNumInterfaces. */ |
||
60 | 0x01, /* bConfigurationValue. */ |
||
61 | 0, /* iConfiguration. */ |
||
62 | 0xC0, /* bmAttributes (self powered). */ |
||
63 | 50), /* bMaxPower (100mA). */ |
||
64 | /* Interface Descriptor.*/ |
||
65 | USB_DESC_INTERFACE (0x00, /* bInterfaceNumber. */ |
||
66 | 0x00, /* bAlternateSetting. */ |
||
67 | 0x01, /* bNumEndpoints. */ |
||
68 | 0x02, /* bInterfaceClass (Communications |
||
69 | Interface Class, CDC section |
||
70 | 4.2). */ |
||
71 | 0x02, /* bInterfaceSubClass (Abstract |
||
72 | Control Model, CDC section 4.3). */ |
||
73 | 0x01, /* bInterfaceProtocol (AT commands, |
||
74 | CDC section 4.4). */ |
||
75 | 0), /* iInterface. */ |
||
76 | /* Header Functional Descriptor (CDC section 5.2.3).*/ |
||
77 | USB_DESC_BYTE (5), /* bLength. */ |
||
78 | USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ |
||
79 | USB_DESC_BYTE (0x00), /* bDescriptorSubtype (Header |
||
80 | Functional Descriptor. */ |
||
81 | USB_DESC_BCD (0x0110), /* bcdCDC. */ |
||
82 | /* Call Management Functional Descriptor. */ |
||
83 | USB_DESC_BYTE (5), /* bFunctionLength. */ |
||
84 | USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ |
||
85 | USB_DESC_BYTE (0x01), /* bDescriptorSubtype (Call Management |
||
86 | Functional Descriptor). */ |
||
87 | USB_DESC_BYTE (0x00), /* bmCapabilities (D0+D1). */ |
||
88 | USB_DESC_BYTE (0x01), /* bDataInterface. */ |
||
89 | /* ACM Functional Descriptor.*/ |
||
90 | USB_DESC_BYTE (4), /* bFunctionLength. */ |
||
91 | USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ |
||
92 | USB_DESC_BYTE (0x02), /* bDescriptorSubtype (Abstract |
||
93 | Control Management Descriptor). */ |
||
94 | USB_DESC_BYTE (0x02), /* bmCapabilities. */ |
||
95 | /* Union Functional Descriptor.*/ |
||
96 | USB_DESC_BYTE (5), /* bFunctionLength. */ |
||
97 | USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ |
||
98 | USB_DESC_BYTE (0x06), /* bDescriptorSubtype (Union |
||
99 | Functional Descriptor). */ |
||
100 | USB_DESC_BYTE (0x00), /* bMasterInterface (Communication |
||
101 | Class Interface). */ |
||
102 | USB_DESC_BYTE (0x01), /* bSlaveInterface0 (Data Class |
||
103 | Interface). */ |
||
104 | /* Endpoint 2 Descriptor.*/ |
||
105 | USB_DESC_ENDPOINT (USBD1_INTERRUPT_REQUEST_EP|0x80, |
||
106 | 0x03, /* bmAttributes (Interrupt). */ |
||
107 | 0x0008, /* wMaxPacketSize. */ |
||
108 | 0xFF), /* bInterval. */ |
||
109 | /* Interface Descriptor.*/ |
||
110 | USB_DESC_INTERFACE (0x01, /* bInterfaceNumber. */ |
||
111 | 0x00, /* bAlternateSetting. */ |
||
112 | 0x02, /* bNumEndpoints. */ |
||
113 | 0x0A, /* bInterfaceClass (Data Class |
||
114 | Interface, CDC section 4.5). */ |
||
115 | 0x00, /* bInterfaceSubClass (CDC section |
||
116 | 4.6). */ |
||
117 | 0x00, /* bInterfaceProtocol (CDC section |
||
118 | 4.7). */ |
||
119 | 0x00), /* iInterface. */ |
||
120 | /* Endpoint 3 Descriptor.*/ |
||
121 | USB_DESC_ENDPOINT (USBD1_DATA_AVAILABLE_EP, /* bEndpointAddress.*/ |
||
122 | 0x02, /* bmAttributes (Bulk). */ |
||
123 | 0x0040, /* wMaxPacketSize. */ |
||
124 | 0x00), /* bInterval. */ |
||
125 | /* Endpoint 1 Descriptor.*/ |
||
126 | USB_DESC_ENDPOINT (USBD1_DATA_REQUEST_EP|0x80, /* bEndpointAddress.*/ |
||
127 | 0x02, /* bmAttributes (Bulk). */ |
||
128 | 0x0040, /* wMaxPacketSize. */ |
||
129 | 0x00) /* bInterval. */ |
||
130 | }; |
||
131 | |||
132 | /* |
||
133 | * Configuration Descriptor wrapper. |
||
134 | */ |
||
135 | static const USBDescriptor vcom_configuration_descriptor = { |
||
136 | sizeof vcom_configuration_descriptor_data, |
||
137 | vcom_configuration_descriptor_data |
||
138 | }; |
||
139 | |||
140 | /* |
||
141 | * U.S. English language identifier. |
||
142 | */ |
||
143 | static const uint8_t vcom_string0[] = { |
||
144 | USB_DESC_BYTE(4), /* bLength. */ |
||
145 | USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ |
||
146 | USB_DESC_WORD(0x0409) /* wLANGID (U.S. English). */ |
||
147 | }; |
||
148 | |||
149 | /* |
||
150 | * Vendor string. |
||
151 | */ |
||
152 | static const uint8_t vcom_string1[] = { |
||
153 | USB_DESC_BYTE(38), /* bLength. */ |
||
154 | USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ |
||
155 | 'S', 0, 'T', 0, 'M', 0, 'i', 0, 'c', 0, 'r', 0, 'o', 0, 'e', 0, |
||
156 | 'l', 0, 'e', 0, 'c', 0, 't', 0, 'r', 0, 'o', 0, 'n', 0, 'i', 0, |
||
157 | 'c', 0, 's', 0 |
||
158 | }; |
||
159 | |||
160 | /* |
||
161 | * Device Description string. |
||
162 | */ |
||
163 | static const uint8_t vcom_string2[] = { |
||
164 | USB_DESC_BYTE(56), /* bLength. */ |
||
165 | USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ |
||
166 | 'C', 0, 'h', 0, 'i', 0, 'b', 0, 'i', 0, 'O', 0, 'S', 0, '/', 0, |
||
167 | 'R', 0, 'T', 0, ' ', 0, 'V', 0, 'i', 0, 'r', 0, 't', 0, 'u', 0, |
||
168 | 'a', 0, 'l', 0, ' ', 0, 'C', 0, 'O', 0, 'M', 0, ' ', 0, 'P', 0, |
||
169 | 'o', 0, 'r', 0, 't', 0 |
||
170 | }; |
||
171 | |||
172 | /* |
||
173 | * Serial Number string. |
||
174 | */ |
||
175 | static const uint8_t vcom_string3[] = { |
||
176 | USB_DESC_BYTE(8), /* bLength. */ |
||
177 | USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ |
||
178 | '0' + CH_KERNEL_MAJOR, 0, |
||
179 | '0' + CH_KERNEL_MINOR, 0, |
||
180 | '0' + CH_KERNEL_PATCH, 0 |
||
181 | }; |
||
182 | |||
183 | /* |
||
184 | * Strings wrappers array. |
||
185 | */ |
||
186 | static const USBDescriptor vcom_strings[] = { |
||
187 | {sizeof vcom_string0, vcom_string0}, |
||
188 | {sizeof vcom_string1, vcom_string1}, |
||
189 | {sizeof vcom_string2, vcom_string2}, |
||
190 | {sizeof vcom_string3, vcom_string3} |
||
191 | }; |
||
192 | |||
193 | /* |
||
194 | * Handles the GET_DESCRIPTOR callback. All required descriptors must be |
||
195 | * handled here. |
||
196 | */ |
||
197 | static const USBDescriptor *get_descriptor(USBDriver *usbp, |
||
198 | uint8_t dtype, |
||
199 | uint8_t dindex, |
||
200 | uint16_t lang) { |
||
201 | |||
202 | (void)usbp; |
||
203 | (void)lang; |
||
204 | switch (dtype) { |
||
205 | case USB_DESCRIPTOR_DEVICE: |
||
206 | return &vcom_device_descriptor; |
||
207 | case USB_DESCRIPTOR_CONFIGURATION: |
||
208 | return &vcom_configuration_descriptor; |
||
209 | case USB_DESCRIPTOR_STRING: |
||
210 | if (dindex < 4) |
||
211 | return &vcom_strings[dindex]; |
||
212 | } |
||
213 | return NULL; |
||
214 | } |
||
215 | |||
216 | /** |
||
217 | * @brief IN EP1 state. |
||
218 | */ |
||
219 | static USBInEndpointState ep1instate; |
||
220 | |||
221 | /** |
||
222 | * @brief OUT EP1 state. |
||
223 | */ |
||
224 | static USBOutEndpointState ep1outstate; |
||
225 | |||
226 | /** |
||
227 | * @brief EP1 initialization structure (both IN and OUT). |
||
228 | */ |
||
229 | static const USBEndpointConfig ep1config = { |
||
230 | USB_EP_MODE_TYPE_BULK, |
||
231 | NULL, |
||
232 | sduDataTransmitted, |
||
233 | sduDataReceived, |
||
234 | 0x0040, |
||
235 | 0x0040, |
||
236 | &ep1instate, |
||
237 | &ep1outstate, |
||
238 | 2, |
||
239 | NULL |
||
240 | }; |
||
241 | |||
242 | /** |
||
243 | * @brief IN EP2 state. |
||
244 | */ |
||
245 | static USBInEndpointState ep2instate; |
||
246 | |||
247 | /** |
||
248 | * @brief EP2 initialization structure (IN only). |
||
249 | */ |
||
250 | static const USBEndpointConfig ep2config = { |
||
251 | USB_EP_MODE_TYPE_INTR, |
||
252 | NULL, |
||
253 | sduInterruptTransmitted, |
||
254 | NULL, |
||
255 | 0x0010, |
||
256 | 0x0000, |
||
257 | &ep2instate, |
||
258 | NULL, |
||
259 | 1, |
||
260 | NULL |
||
261 | }; |
||
262 | |||
263 | /* |
||
264 | * Handles the USB driver global events. |
||
265 | */ |
||
266 | static void usb_event(USBDriver *usbp, usbevent_t event) { |
||
267 | extern SerialUSBDriver SDU1; |
||
268 | |||
269 | switch (event) { |
||
270 | case USB_EVENT_ADDRESS: |
||
271 | return; |
||
272 | case USB_EVENT_CONFIGURED: |
||
273 | chSysLockFromISR(); |
||
274 | |||
275 | /* Enables the endpoints specified into the configuration. |
||
276 | Note, this callback is invoked from an ISR so I-Class functions |
||
277 | must be used.*/ |
||
278 | usbInitEndpointI(usbp, USBD1_DATA_REQUEST_EP, &ep1config); |
||
279 | usbInitEndpointI(usbp, USBD1_INTERRUPT_REQUEST_EP, &ep2config); |
||
280 | |||
281 | /* Resetting the state of the CDC subsystem.*/ |
||
282 | sduConfigureHookI(&SDU1); |
||
283 | |||
284 | chSysUnlockFromISR(); |
||
285 | return; |
||
286 | case USB_EVENT_RESET: |
||
287 | /* Falls into.*/ |
||
288 | case USB_EVENT_UNCONFIGURED: |
||
289 | /* Falls into.*/ |
||
290 | case USB_EVENT_SUSPEND: |
||
291 | chSysLockFromISR(); |
||
292 | |||
293 | /* Disconnection event on suspend.*/ |
||
294 | sduSuspendHookI(&SDU1); |
||
295 | |||
296 | chSysUnlockFromISR(); |
||
297 | return; |
||
298 | case USB_EVENT_WAKEUP: |
||
299 | chSysLockFromISR(); |
||
300 | |||
301 | /* Disconnection event on suspend.*/ |
||
302 | sduWakeupHookI(&SDU1); |
||
303 | |||
304 | chSysUnlockFromISR(); |
||
305 | return; |
||
306 | case USB_EVENT_STALLED: |
||
307 | return; |
||
308 | } |
||
309 | return; |
||
310 | } |
||
311 | |||
312 | /* |
||
313 | * Handles the USB driver global events. |
||
314 | */ |
||
315 | static void sof_handler(USBDriver *usbp) { |
||
316 | |||
317 | (void)usbp; |
||
318 | |||
319 | osalSysLockFromISR(); |
||
320 | sduSOFHookI(&SDU1); |
||
321 | osalSysUnlockFromISR(); |
||
322 | } |
||
323 | |||
324 | /* |
||
325 | * USB driver configuration. |
||
326 | */ |
||
327 | const USBConfig usbcfg = { |
||
328 | usb_event, |
||
329 | get_descriptor, |
||
330 | sduRequestsHook, |
||
331 | sof_handler |
||
332 | }; |
||
333 | |||
334 | /* |
||
335 | * Serial over USB driver configuration. |
||
336 | */ |
||
337 | const SerialUSBConfig serusbcfg = { |
||
338 | &USBD1, |
||
339 | USBD1_DATA_REQUEST_EP, |
||
340 | USBD1_DATA_AVAILABLE_EP, |
||
341 | USBD1_INTERRUPT_REQUEST_EP |
||
342 | }; |