Details | 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 | }; |