APM:Libraries
usbcfg.c
Go to the documentation of this file.
1 /*
2  ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
3  Licensed under the Apache License, Version 2.0 (the "License");
4  you may not use this file except in compliance with the License.
5  You may obtain a copy of the License at
6  http://www.apache.org/licenses/LICENSE-2.0
7  Unless required by applicable law or agreed to in writing, software
8  distributed under the License is distributed on an "AS IS" BASIS,
9  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10  See the License for the specific language governing permissions and
11  limitations under the License.
12 */
13 /*
14  * This file is free software: you can redistribute it and/or modify it
15  * under the terms of the GNU General Public License as published by the
16  * Free Software Foundation, either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * This file is distributed in the hope that it will be useful, but
20  * WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22  * See the GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License along
25  * with this program. If not, see <http://www.gnu.org/licenses/>.
26  *
27  * Modified for use in AP_HAL by Andrew Tridgell and Siddharth Bharat Purohit
28  */
29 #include "hal.h"
30 #include "hwdef.h"
31 
32 #include <stdlib.h>
33 #include <string.h>
34 
35 // #pragma GCC optimize("O0")
36 
37 #ifdef HAL_USB_PRODUCT_ID
38 
39 /* Virtual serial port over USB.*/
40 SerialUSBDriver SDU1;
41 
42 /*
43  * Endpoints to be used for USBD1.
44  */
45 #define USBD1_DATA_REQUEST_EP 1
46 #define USBD1_DATA_AVAILABLE_EP 1
47 #define USBD1_INTERRUPT_REQUEST_EP 2
48 
49 /*
50  * USB Device Descriptor.
51  */
52 static const uint8_t vcom_device_descriptor_data[18] = {
53  USB_DESC_DEVICE(
54  0x0110, /* bcdUSB (1.1). */
55  0x02, /* bDeviceClass (CDC). */
56  0x00, /* bDeviceSubClass. */
57  0x00, /* bDeviceProtocol. */
58  0x40, /* bMaxPacketSize. */
59  HAL_USB_VENDOR_ID, /* idVendor (ST). */
60  HAL_USB_PRODUCT_ID, /* idProduct. */
61  0x0200, /* bcdDevice. */
62  1, /* iManufacturer. */
63  2, /* iProduct. */
64  3, /* iSerialNumber. */
65  1) /* bNumConfigurations. */
66 };
67 
68 /*
69  * Device Descriptor wrapper.
70  */
71 static const USBDescriptor vcom_device_descriptor = {
72  sizeof vcom_device_descriptor_data,
73  vcom_device_descriptor_data
74 };
75 
76 /* Configuration Descriptor tree for a CDC.*/
77 static const uint8_t vcom_configuration_descriptor_data[67] = {
78  /* Configuration Descriptor.*/
79  USB_DESC_CONFIGURATION(67, /* wTotalLength. */
80  0x02, /* bNumInterfaces. */
81  0x01, /* bConfigurationValue. */
82  0, /* iConfiguration. */
83  0xC0, /* bmAttributes (self powered). */
84  50), /* bMaxPower (100mA). */
85  /* Interface Descriptor.*/
86  USB_DESC_INTERFACE (0x00, /* bInterfaceNumber. */
87  0x00, /* bAlternateSetting. */
88  0x01, /* bNumEndpoints. */
89  0x02, /* bInterfaceClass (Communications
90  Interface Class, CDC section
91  4.2). */
92  0x02, /* bInterfaceSubClass (Abstract
93  Control Model, CDC section 4.3). */
94  0x01, /* bInterfaceProtocol (AT commands,
95  CDC section 4.4). */
96  0), /* iInterface. */
97  /* Header Functional Descriptor (CDC section 5.2.3).*/
98  USB_DESC_BYTE (5), /* bLength. */
99  USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */
100  USB_DESC_BYTE (0x00), /* bDescriptorSubtype (Header
101  Functional Descriptor. */
102  USB_DESC_BCD (0x0110), /* bcdCDC. */
103  /* Call Management Functional Descriptor. */
104  USB_DESC_BYTE (5), /* bFunctionLength. */
105  USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */
106  USB_DESC_BYTE (0x01), /* bDescriptorSubtype (Call Management
107  Functional Descriptor). */
108  USB_DESC_BYTE (0x00), /* bmCapabilities (D0+D1). */
109  USB_DESC_BYTE (0x01), /* bDataInterface. */
110  /* ACM Functional Descriptor.*/
111  USB_DESC_BYTE (4), /* bFunctionLength. */
112  USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */
113  USB_DESC_BYTE (0x02), /* bDescriptorSubtype (Abstract
114  Control Management Descriptor). */
115  USB_DESC_BYTE (0x02), /* bmCapabilities. */
116  /* Union Functional Descriptor.*/
117  USB_DESC_BYTE (5), /* bFunctionLength. */
118  USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */
119  USB_DESC_BYTE (0x06), /* bDescriptorSubtype (Union
120  Functional Descriptor). */
121  USB_DESC_BYTE (0x00), /* bMasterInterface (Communication
122  Class Interface). */
123  USB_DESC_BYTE (0x01), /* bSlaveInterface0 (Data Class
124  Interface). */
125  /* Endpoint 2 Descriptor.*/
126  USB_DESC_ENDPOINT (USBD1_INTERRUPT_REQUEST_EP|0x80,
127  0x03, /* bmAttributes (Interrupt). */
128  0x0008, /* wMaxPacketSize. */
129  0xFF), /* bInterval. */
130  /* Interface Descriptor.*/
131  USB_DESC_INTERFACE (0x01, /* bInterfaceNumber. */
132  0x00, /* bAlternateSetting. */
133  0x02, /* bNumEndpoints. */
134  0x0A, /* bInterfaceClass (Data Class
135  Interface, CDC section 4.5). */
136  0x00, /* bInterfaceSubClass (CDC section
137  4.6). */
138  0x00, /* bInterfaceProtocol (CDC section
139  4.7). */
140  0x00), /* iInterface. */
141  /* Endpoint 3 Descriptor.*/
142  USB_DESC_ENDPOINT (USBD1_DATA_AVAILABLE_EP, /* bEndpointAddress.*/
143  0x02, /* bmAttributes (Bulk). */
144  0x0040, /* wMaxPacketSize. */
145  0x00), /* bInterval. */
146  /* Endpoint 1 Descriptor.*/
147  USB_DESC_ENDPOINT (USBD1_DATA_REQUEST_EP|0x80, /* bEndpointAddress.*/
148  0x02, /* bmAttributes (Bulk). */
149  0x0040, /* wMaxPacketSize. */
150  0x00) /* bInterval. */
151 };
152 
153 /*
154  * Configuration Descriptor wrapper.
155  */
156 static const USBDescriptor vcom_configuration_descriptor = {
157  sizeof vcom_configuration_descriptor_data,
158  vcom_configuration_descriptor_data
159 };
160 
161 /*
162  * U.S. English language identifier.
163  */
164 static const uint8_t vcom_string0[] = {
165  USB_DESC_BYTE(4), /* bLength. */
166  USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */
167  USB_DESC_WORD(0x0409) /* wLANGID (U.S. English). */
168 };
169 
170 /*
171  * Strings wrappers array. The strings are created dynamically to
172  * allow them to be setup with apj_tool
173  */
174 static USBDescriptor vcom_strings[] = {
175  {sizeof vcom_string0, vcom_string0},
176  {0, NULL}, // manufacturer
177  {0, NULL}, // product
178  {0, NULL}, // version
179 };
180 
181 
182 // start of 12 byte CPU ID
183 #ifndef UDID_START
184 #define UDID_START 0x1FFF7A10
185 #endif
186 
187 /*
188  handle substitution of variables in strings for USB descriptors
189  */
190 static char *string_substitute(const char *str)
191 {
192  uint8_t new_len = strlen(str);
193  if (strstr(str, "%BOARD%")) {
194  new_len += strlen(HAL_BOARD_NAME) - 7;
195  }
196  if (strstr(str, "%SERIAL%")) {
197  new_len += 24 - 8;
198  }
199  char *str2 = malloc(new_len+1);
200  char *p = str2;
201  while (*str) {
202  char c = *str;
203  if (c == '%') {
204  if (strcmp(str, "%BOARD%") == 0) {
205  memcpy(p, HAL_BOARD_NAME, strlen(HAL_BOARD_NAME));
206  str += 7;
207  p += strlen(HAL_BOARD_NAME);
208  continue;
209  }
210  if (strcmp(str, "%SERIAL%") == 0) {
211  const char *hex = "0123456789ABCDEF";
212  const uint8_t *cpu_id = (const uint8_t *)UDID_START;
213  uint8_t i;
214  for (i=0; i<12; i++) {
215  *p++ = hex[(cpu_id[i]>>4)&0xF];
216  *p++ = hex[cpu_id[i]&0xF];
217  }
218  str += 8;
219  continue;
220  }
221  }
222  *p++ = *str++;
223  }
224  *p = 0;
225  return str2;
226 }
227 
228 
229 /*
230  dynamically allocate a USB descriptor string
231  */
232 static void setup_usb_string(USBDescriptor *desc, const char *str)
233 {
234  char *str2 = string_substitute(str);
235  uint8_t len = strlen(str2);
236  desc->ud_size = 2+2*len;
237  uint8_t *b = (uint8_t *)calloc(1, desc->ud_size);
238  desc->ud_string = (const uint8_t *)b;
239  b[0] = USB_DESC_BYTE(desc->ud_size);
240  b[1] = USB_DESC_BYTE(USB_DESCRIPTOR_STRING);
241  uint8_t i;
242  for (i=0; i<len; i++) {
243  b[2+i*2] = str2[i];
244  b[2+i*2+1] = 0;
245  }
246  if (str2 != str) {
247  free(str2);
248  }
249 }
250 
251 /*
252  dynamically allocate a USB descriptor strings
253  */
254 void setup_usb_strings(void)
255 {
256  setup_usb_string(&vcom_strings[1], HAL_USB_STRING_MANUFACTURER);
257  setup_usb_string(&vcom_strings[2], HAL_USB_STRING_PRODUCT);
258  setup_usb_string(&vcom_strings[3], HAL_USB_STRING_SERIAL);
259 }
260 
261 /*
262  * Handles the GET_DESCRIPTOR callback. All required descriptors must be
263  * handled here.
264  */
265 static const USBDescriptor *get_descriptor(USBDriver *usbp,
266  uint8_t dtype,
267  uint8_t dindex,
268  uint16_t lang) {
269 
270  (void)usbp;
271  (void)lang;
272  switch (dtype) {
273  case USB_DESCRIPTOR_DEVICE:
274  return &vcom_device_descriptor;
275  case USB_DESCRIPTOR_CONFIGURATION:
276  return &vcom_configuration_descriptor;
278  if (dindex < 4) {
279  return &vcom_strings[dindex];
280  }
281  }
282  return NULL;
283 }
284 
288 static USBInEndpointState ep1instate;
289 
293 static USBOutEndpointState ep1outstate;
294 
298 static const USBEndpointConfig ep1config = {
299  USB_EP_MODE_TYPE_BULK,
300  NULL,
301  sduDataTransmitted,
302  sduDataReceived,
303  0x0040,
304  0x0040,
305  &ep1instate,
306  &ep1outstate,
307  2,
308  NULL
309 };
310 
314 static USBInEndpointState ep2instate;
315 
319 static const USBEndpointConfig ep2config = {
320  USB_EP_MODE_TYPE_INTR,
321  NULL,
322  sduInterruptTransmitted,
323  NULL,
324  0x0010,
325  0x0000,
326  &ep2instate,
327  NULL,
328  1,
329  NULL
330 };
331 
332 /*
333  * Handles the USB driver global events.
334  */
335 static void usb_event(USBDriver *usbp, usbevent_t event) {
336  extern SerialUSBDriver SDU1;
337 
338  switch (event) {
339  case USB_EVENT_ADDRESS:
340  return;
341  case USB_EVENT_CONFIGURED:
342  chSysLockFromISR();
343 
344  /* Enables the endpoints specified into the configuration.
345  Note, this callback is invoked from an ISR so I-Class functions
346  must be used.*/
347  usbInitEndpointI(usbp, USBD1_DATA_REQUEST_EP, &ep1config);
348  usbInitEndpointI(usbp, USBD1_INTERRUPT_REQUEST_EP, &ep2config);
349 
350  /* Resetting the state of the CDC subsystem.*/
351  sduConfigureHookI(&SDU1);
352 
353  chSysUnlockFromISR();
354  return;
355  case USB_EVENT_RESET:
356  /* Falls into.*/
357  case USB_EVENT_UNCONFIGURED:
358  /* Falls into.*/
359  case USB_EVENT_SUSPEND:
360  chSysLockFromISR();
361 
362  /* Disconnection event on suspend.*/
363  sduSuspendHookI(&SDU1);
364 
365  chSysUnlockFromISR();
366  return;
367  case USB_EVENT_WAKEUP:
368  chSysLockFromISR();
369 
370  /* Disconnection event on suspend.*/
371  sduWakeupHookI(&SDU1);
372 
373  chSysUnlockFromISR();
374  return;
375  case USB_EVENT_STALLED:
376  return;
377  }
378  return;
379 }
380 
381 /*
382  * Handles the USB driver global events.
383  */
384 static void sof_handler(USBDriver *usbp) {
385 
386  (void)usbp;
387 
388  osalSysLockFromISR();
389  sduSOFHookI(&SDU1);
390  osalSysUnlockFromISR();
391 }
392 
393 /*
394  * USB driver configuration.
395  */
396 const USBConfig usbcfg = {
397  usb_event,
398  get_descriptor,
399  sduRequestsHook,
400  sof_handler
401 };
402 
403 /*
404  * Serial over USB driver configuration.
405  */
406 const SerialUSBConfig serusbcfg = {
407  &USBD1,
408  USBD1_DATA_REQUEST_EP,
409  USBD1_DATA_AVAILABLE_EP,
410  USBD1_INTERRUPT_REQUEST_EP
411 };
412 
413 #endif // HAL_USB_PRODUCT_ID
void * calloc(size_t nmemb, size_t size)
Definition: malloc.c:76
#define UDID_START
Definition: syscalls.c:216
#define HAL_BOARD_NAME
Definition: chibios.h:5
void * malloc(size_t size)
Definition: malloc.c:61
#define NULL
Definition: hal_types.h:59
void free(void *ptr)
Definition: malloc.c:81
#define USB_DESCRIPTOR_STRING(len)
Definition: usb.h:218
void setup_usb_strings(void)