Support --vidpid option for configure
[gnuk/neug.git] / src / main.c
1 /*
2  * main.c - main routine of neug
3  *
4  * Main routine:
5  * Copyright (C) 2011, 2012 Free Software Initiative of Japan
6  * Author: NIIBE Yutaka <gniibe@fsij.org>
7  *
8  * This file is a part of NeuG, a Random Number Generator
9  * implementation.
10  *
11  * NeuG is free software: you can redistribute it and/or modify it
12  * under the terms of the GNU General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * Gnuk is distributed in the hope that it will be useful, but WITHOUT
17  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
19  * License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23  *
24  */
25
26 #include "config.h"
27 #include "ch.h"
28 #include "hal.h"
29 #include "board.h"
30 #include "neug.h"
31 #include "usb_lld.h"
32 #include "sys.h"
33
34 /*
35  * We are trying to avoid dependency to C library. 
36  * GCC built-in function(s) are declared here.
37  */
38 extern void *memcpy(void *dest, const void *src, size_t n);
39 extern void *memset (void *s, int c, size_t n);
40
41 \f
42 #define ENDP0_RXADDR        (0x40)
43 #define ENDP0_TXADDR        (0x80)
44 #define ENDP1_TXADDR        (0xc0)
45 #define ENDP2_TXADDR        (0x100)
46 #define ENDP3_RXADDR        (0x140)
47
48 #define USB_CDC_REQ_SET_LINE_CODING             0x20
49 #define USB_CDC_REQ_GET_LINE_CODING             0x21
50 #define USB_CDC_REQ_SET_CONTROL_LINE_STATE      0x22
51 #define USB_CDC_REQ_SEND_BREAK                  0x23
52
53 /* USB Device Descriptor */
54 static const uint8_t vcom_device_desc[18] = {
55   18,   /* bLength */
56   USB_DEVICE_DESCRIPTOR_TYPE,   /* bDescriptorType */
57   0x10, 0x01,                   /* bcdUSB = 1.1 */
58   0x02,                         /* bDeviceClass (CDC).              */
59   0x00,                         /* bDeviceSubClass.                 */
60   0x00,                         /* bDeviceProtocol.                 */
61   0x40,                         /* bMaxPacketSize.                  */
62 #include "usb-vid-pid-ver.c.inc"
63   1,                            /* iManufacturer.                   */
64   2,                            /* iProduct.                        */
65   3,                            /* iSerialNumber.                   */
66   1                             /* bNumConfigurations.              */
67 };
68
69 /* Configuration Descriptor tree for a CDC.*/
70 static const uint8_t vcom_configuration_desc[67] = {
71   9,
72   USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
73   /* Configuration Descriptor.*/
74   67, 0x00,                     /* wTotalLength.                    */
75   0x02,                         /* bNumInterfaces.                  */
76   0x01,                         /* bConfigurationValue.             */
77   0,                            /* iConfiguration.                  */
78   0x80,                         /* bmAttributes (bus powered).      */
79   50,                           /* bMaxPower (100mA).               */
80   /* Interface Descriptor.*/
81   9,
82   USB_INTERFACE_DESCRIPTOR_TYPE,
83   0x00,            /* bInterfaceNumber.                */
84   0x00,            /* bAlternateSetting.               */
85   0x01,            /* bNumEndpoints.                   */
86   0x02,            /* bInterfaceClass (Communications Interface Class,
87                       CDC section 4.2).  */
88   0x02,            /* bInterfaceSubClass (Abstract Control Model, CDC
89                       section 4.3).  */
90   0x01,            /* bInterfaceProtocol (AT commands, CDC section
91                       4.4).  */
92   0,               /* iInterface.                      */
93   /* Header Functional Descriptor (CDC section 5.2.3).*/
94   5,          /* bLength.                         */
95   0x24,       /* bDescriptorType (CS_INTERFACE).  */
96   0x00,       /* bDescriptorSubtype (Header Functional Descriptor). */
97   0x10, 0x01, /* bcdCDC.                          */
98   /* Call Management Functional Descriptor. */
99   5,            /* bFunctionLength.                 */
100   0x24,         /* bDescriptorType (CS_INTERFACE).  */
101   0x01,         /* bDescriptorSubtype (Call Management Functional
102                    Descriptor). */
103   0x03,         /* bmCapabilities (D0+D1).          */
104   0x01,         /* bDataInterface.                  */
105   /* ACM Functional Descriptor.*/
106   4,            /* bFunctionLength.                 */
107   0x24,         /* bDescriptorType (CS_INTERFACE).  */
108   0x02,         /* bDescriptorSubtype (Abstract Control Management
109                    Descriptor).  */
110   0x02,         /* bmCapabilities.                  */
111   /* Union Functional Descriptor.*/
112   5,            /* bFunctionLength.                 */
113   0x24,         /* bDescriptorType (CS_INTERFACE).  */
114   0x06,         /* bDescriptorSubtype (Union Functional
115                    Descriptor).  */
116   0x00,         /* bMasterInterface (Communication Class
117                    Interface).  */
118   0x01,         /* bSlaveInterface0 (Data Class Interface).  */
119   /* Endpoint 2 Descriptor.*/
120   7,
121   USB_ENDPOINT_DESCRIPTOR_TYPE,
122   ENDP2|0x80,    /* bEndpointAddress.    */
123   0x03,          /* bmAttributes (Interrupt).        */
124   0x08, 0x00,    /* wMaxPacketSize.                  */
125   0xFF,          /* bInterval.                       */
126   /* Interface Descriptor.*/
127   9,
128   USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: */
129   0x01,          /* bInterfaceNumber.                */
130   0x00,          /* bAlternateSetting.               */
131   0x02,          /* bNumEndpoints.                   */
132   0x0A,          /* bInterfaceClass (Data Class Interface, CDC section 4.5). */
133   0x00,          /* bInterfaceSubClass (CDC section 4.6). */
134   0x00,          /* bInterfaceProtocol (CDC section 4.7). */
135   0x00,          /* iInterface.                      */
136   /* Endpoint 3 Descriptor.*/
137   7,
138   USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
139   ENDP3,    /* bEndpointAddress. */
140   0x02,                         /* bmAttributes (Bulk).             */
141   0x40, 0x00,                   /* wMaxPacketSize.                  */
142   0x00,                         /* bInterval.                       */
143   /* Endpoint 1 Descriptor.*/
144   7,
145   USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
146   ENDP1|0x80,                   /* bEndpointAddress. */
147   0x02,                         /* bmAttributes (Bulk).             */
148   0x40, 0x00,                   /* wMaxPacketSize.                  */
149   0x00                          /* bInterval.                       */
150 };
151
152
153 /*
154  * U.S. English language identifier.
155  */
156 static const uint8_t vcom_string0[4] = {
157   4,                            /* bLength */
158   USB_STRING_DESCRIPTOR_TYPE,
159   0x09, 0x04                    /* LangID = 0x0409: US-English */
160 };
161
162 #define USB_STRINGS_FOR_NEUG 1
163 #include "usb-strings.c.inc"
164
165 /*
166  * Serial Number string.  NOTE: This does not have CONST qualifier.
167  */
168 static uint8_t vcom_string3[28] = {
169   28,                    /* bLength.                         */
170   USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType.                 */
171   '0', 0,  '.', 0,  '0', 0, '2', 0,    /* Version number of NeuG.          */
172   '-', 0,
173   0, 0, 0, 0,   /* Filled by Unique device ID.      */
174   0, 0, 0, 0,
175   0, 0, 0, 0,
176   0, 0, 0, 0,
177 };
178
179 static const struct Descriptor device_desc = {
180   vcom_device_desc,
181   sizeof (vcom_device_desc)
182 };
183
184 static const struct Descriptor config_desc = {
185   vcom_configuration_desc,
186   sizeof (vcom_configuration_desc)
187 };
188
189 static const struct Descriptor string_descs[] = {
190   {vcom_string0, sizeof vcom_string0},
191   {neug_string_vendor, sizeof (neug_string_vendor)},
192   {neug_string_product, sizeof (neug_string_product)},
193   {vcom_string3, sizeof (vcom_string3)},
194   {neug_revision_detail, sizeof (neug_revision_detail)},
195   {neug_config_options, sizeof (neug_config_options)},
196   {sys_version, sizeof (sys_version)},
197 };
198
199 #define NUM_STRING_DESC (sizeof (string_descs)/sizeof (struct Descriptor))
200
201 #define NUM_INTERFACES 2
202
203 uint32_t bDeviceState = UNCONNECTED; /* USB device status */
204
205
206 static void
207 neug_device_reset (void)
208 {
209   /* Set DEVICE as not configured */
210   usb_lld_set_configuration (0);
211
212   /* Current Feature initialization */
213   usb_lld_set_feature (config_desc.Descriptor[7]);
214
215   usb_lld_reset ();
216
217   /* Initialize Endpoint 0 */
218   usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR, 64);
219 }
220
221 #define USB_REGNUAL_MEMINFO     0
222 #define USB_REGNUAL_SEND        1
223 #define USB_REGNUAL_RESULT      2
224 #define USB_REGNUAL_FLASH       3
225 #define USB_REGNUAL_PROTECT     4
226 #define USB_REGNUAL_FINISH      5
227
228 static uint8_t mem[256];
229 static uint32_t result;
230
231 extern uint8_t __flash_start__,  __flash_end__;
232 static const uint8_t *const mem_info[] = { &__flash_start__,  &__flash_end__ };
233
234
235 static uint32_t rbit (uint32_t v)
236 {
237   uint32_t r;
238
239   asm ("rbit    %0, %1" : "=r" (r) : "r" (v));
240   return r;
241 }
242
243 static uint32_t fetch (int i)
244 {
245   uint32_t v;
246
247   v = *(uint32_t *)(&mem[i*4]);
248   return rbit (v);
249 }
250
251 static uint32_t calc_crc32 (void)
252 {
253   int i;
254
255   CRC->CR = CRC_CR_RESET;
256
257   for (i = 0; i < 256/4; i++)
258     CRC->DR = fetch (i);
259
260   return rbit (CRC->DR);
261 }
262
263
264 static void neug_ctrl_write_finish (uint8_t req, uint8_t req_no,
265                                     uint16_t value, uint16_t index,
266                                     uint16_t len)
267 {
268   uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
269
270   if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT) && USB_SETUP_SET (req))
271     {
272       if (req_no == USB_REGNUAL_SEND && value == 0)
273         result = calc_crc32 ();
274       else if (req_no == USB_REGNUAL_FLASH && len == 0 && index == 0)
275         {
276           uint32_t dst_addr = (0x08000000 + value * 0x100);
277
278           result = flash_write (dst_addr, mem, 256);
279         }
280       else if (req_no == USB_REGNUAL_PROTECT && len == 0
281                && value == 0 && index == 0)
282         result = flash_protect ();
283       else if (req_no == USB_REGNUAL_FINISH && len == 0
284                && value == 0 && index == 0)
285         nvic_system_reset ();
286     }
287 }
288
289 struct line_coding
290 {
291   uint32_t bitrate;
292   uint8_t format;
293   uint8_t paritytype;
294   uint8_t datatype;
295 };
296
297 static struct line_coding line_coding = {
298   115200, /* baud rate: 115200    */
299   0x00,   /* stop bits: 1         */
300   0x00,   /* parity:    none      */
301   0x08    /* bits:      8         */
302 };
303
304 static uint8_t connected;
305
306 static int
307 vcom_port_data_setup (uint8_t req, uint8_t req_no, uint16_t value)
308 {
309   if (USB_SETUP_GET (req))
310     {
311       if (req_no == USB_CDC_REQ_GET_LINE_CODING)
312         {
313           usb_lld_set_data_to_send (&line_coding, sizeof(line_coding));
314           return USB_SUCCESS;
315         }
316     }
317   else  /* USB_SETUP_SET (req) */
318     {
319       if (req_no == USB_CDC_REQ_SET_LINE_CODING)
320         {
321           usb_lld_set_data_to_recv (&line_coding, sizeof(line_coding));
322           return USB_SUCCESS;
323         }
324       else if (req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
325         {
326           if (value != 0)
327             {
328               if ((connected & 1) == 0)
329                 /* It's Open call */
330                 connected++;
331             }
332           else
333             /* Close call */
334             connected++;
335
336           return USB_SUCCESS;
337         }
338     }
339
340   return USB_UNSUPPORT;
341 }
342
343 static int
344 neug_setup (uint8_t req, uint8_t req_no,
345                uint16_t value, uint16_t index, uint16_t len)
346 {
347   uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
348
349   if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
350     {
351       if (USB_SETUP_GET (req))
352         {
353           if (req_no == USB_REGNUAL_MEMINFO)
354             {
355               usb_lld_set_data_to_send (mem_info, sizeof (mem_info));
356               return USB_SUCCESS;
357             }
358           else if (req_no == USB_REGNUAL_RESULT)
359             {
360               usb_lld_set_data_to_send (&result, sizeof (uint32_t));
361               return USB_SUCCESS;
362             }
363         }
364       else /* SETUP_SET */
365         {
366           if (req_no == USB_REGNUAL_SEND)
367             {
368               if (value != 0 || index + len > 256)
369                 return USB_UNSUPPORT;
370
371               if (index + len < 256)
372                 memset (mem + index + len, 0xff, 256 - (index + len));
373
374               usb_lld_set_data_to_recv (mem + index, len);
375               return USB_SUCCESS;
376             }
377           else if (req_no == USB_REGNUAL_FLASH && len == 0 && index == 0)
378             {
379               uint32_t dst_addr = (0x08000000 + value * 0x100);
380
381               if (dst_addr + 256 <= (uint32_t)&__flash_end__)
382                 return USB_SUCCESS;
383             }
384           else if (req_no == USB_REGNUAL_PROTECT && len == 0
385                    && value == 0 && index == 0)
386             return USB_SUCCESS;
387           else if (req_no == USB_REGNUAL_FINISH && len == 0
388                    && value == 0 && index == 0)
389             return USB_SUCCESS;
390         }
391     }
392   else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT))
393     if (index == 0)
394       return vcom_port_data_setup (req, req_no, value);
395
396   return USB_UNSUPPORT;
397 }
398
399 static int
400 neug_get_descriptor (uint8_t desc_type, uint16_t index, uint16_t value)
401 {
402   (void)index;
403   if (desc_type == DEVICE_DESCRIPTOR)
404     {
405       usb_lld_set_data_to_send (device_desc.Descriptor,
406                                 device_desc.Descriptor_Size);
407       return USB_SUCCESS;
408     }
409   else if (desc_type == CONFIG_DESCRIPTOR)
410     {
411       usb_lld_set_data_to_send (config_desc.Descriptor,
412                                 config_desc.Descriptor_Size);
413       return USB_SUCCESS;
414     }
415   else if (desc_type == STRING_DESCRIPTOR)
416     {
417       uint8_t desc_index = value & 0xff;
418
419       if (desc_index < NUM_STRING_DESC)
420         {
421           usb_lld_set_data_to_send (string_descs[desc_index].Descriptor,
422                                     string_descs[desc_index].Descriptor_Size);
423           return USB_SUCCESS;
424         }
425     }
426
427   return USB_UNSUPPORT;
428 }
429
430 static void
431 neug_setup_endpoints_for_interface (uint16_t interface, int stop)
432 {
433   if (interface == 0)
434     {
435       if (!stop)
436         usb_lld_setup_endpoint (ENDP2, EP_INTERRUPT, 0, 0, ENDP2_TXADDR, 0);
437       else
438         usb_lld_stall_tx (ENDP2);
439     }
440   else if (interface == 1)
441     {
442       if (!stop)
443         {
444           usb_lld_setup_endpoint (ENDP1, EP_BULK, 0, 0, ENDP1_TXADDR, 0);
445           usb_lld_setup_endpoint (ENDP3, EP_BULK, 0, ENDP3_RXADDR, 0, 64);
446         }
447       else
448         {
449           usb_lld_stall_tx (ENDP1);
450           usb_lld_stall_rx (ENDP3);
451         }
452     }
453 }
454
455 static int neug_usb_event (uint8_t event_type, uint16_t value)
456 {
457   int i;
458   uint8_t current_conf;
459
460   switch (event_type)
461     {
462     case USB_EVENT_ADDRESS:
463       bDeviceState = ADDRESSED;
464       return USB_SUCCESS;
465     case USB_EVENT_CONFIG:
466       current_conf = usb_lld_current_configuration ();
467       if (current_conf == 0)
468         {
469           if (value != 1)
470             return USB_UNSUPPORT;
471
472           usb_lld_set_configuration (1);
473           for (i = 0; i < NUM_INTERFACES; i++)
474             neug_setup_endpoints_for_interface (i, 0);
475           bDeviceState = CONFIGURED;
476         }
477       else if (current_conf != value)
478         {
479           if (value != 0)
480             return USB_UNSUPPORT;
481
482           usb_lld_set_configuration (0);
483           for (i = 0; i < NUM_INTERFACES; i++)
484             neug_setup_endpoints_for_interface (i, 1);
485           bDeviceState = ADDRESSED;
486         }
487       /* Do nothing when current_conf == value */
488       return USB_SUCCESS;
489
490       return USB_SUCCESS;
491     default:
492       break;
493     }
494
495   return USB_UNSUPPORT;
496 }
497
498
499 static int neug_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
500 {
501   static uint8_t zero = 0;
502
503   if (interface >= NUM_INTERFACES)
504     return USB_UNSUPPORT;
505
506   switch (cmd)
507     {
508     case USB_SET_INTERFACE:
509       if (alt != 0)
510         return USB_UNSUPPORT;
511       else
512         {
513           neug_setup_endpoints_for_interface (interface, 0);
514           return USB_SUCCESS;
515         }
516
517     case USB_GET_INTERFACE:
518       usb_lld_set_data_to_send (&zero, 1);
519       return USB_SUCCESS;
520
521     default:
522     case USB_QUERY_INTERFACE:
523       return USB_SUCCESS;
524     }
525 }
526
527 const struct usb_device_method Device_Method = {
528   neug_device_reset,
529   neug_ctrl_write_finish,
530   neug_setup,
531   neug_get_descriptor,
532   neug_usb_event,
533   neug_interface,
534 };
535
536
537
538 static void fill_serial_no_by_unique_id (void)
539 {
540   extern const uint8_t * unique_device_id (void);
541   uint8_t *p = &vcom_string3[12];
542   const uint8_t *u = unique_device_id ();
543   int i;
544
545   for (i = 0; i < 4; i++)
546     {
547       uint8_t b = u[i];
548       uint8_t nibble; 
549
550       nibble = (b >> 4);
551       nibble += (nibble >= 10 ? ('A' - 10) : '0');
552       p[i*4] = nibble;
553       nibble = (b & 0x0f);
554       nibble += (nibble >= 10 ? ('A' - 10) : '0');
555       p[i*4+2] = nibble;
556     }
557 }
558 \f
559 static Thread *main_thread = NULL;
560
561 CH_IRQ_HANDLER (Vector90)
562 {
563   CH_IRQ_PROLOGUE();
564   chSysLockFromIsr();
565
566   usb_interrupt_handler ();
567
568   chSysUnlockFromIsr();
569   CH_IRQ_EPILOGUE();
570 }
571
572 void
573 EP1_IN_Callback (void)
574 {
575   if (main_thread != NULL)
576     {
577       chSysLockFromIsr ();
578       main_thread->p_u.rdymsg = RDY_OK;
579       chSchReadyI (main_thread);
580       chSysUnlockFromIsr ();
581     }
582 }
583
584 void
585 EP2_IN_Callback (void)
586 {
587 }
588
589 void
590 EP3_OUT_Callback (void)
591 {
592   usb_lld_rx_enable (ENDP3);
593 }
594 \f
595 static WORKING_AREA(wa_led, 64);
596
597 #define LED_ONESHOT_SHORT ((eventmask_t)1)
598 #define LED_ONESHOT_LONG  ((eventmask_t)2)
599 static Thread *led_thread;
600
601 /*
602  * LED blinker: When notified, let LED emit for 100ms.
603  */
604 static msg_t led_blinker (void *arg)
605 {
606   (void)arg;
607
608   led_thread = chThdSelf ();
609   set_led (0);
610
611   while (1)
612     {
613       eventmask_t m;
614
615       m = chEvtWaitOne (ALL_EVENTS);
616       set_led (1);
617       if (m == LED_ONESHOT_SHORT)
618         chThdSleep (MS2ST (100));
619       else
620         chThdSleep (MS2ST (250));
621       set_led (0);
622     }
623
624   return 0;
625 }
626 \f
627 #define RANDOM_BYTES_LENGTH 60
628 static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)];
629
630 /*
631  * Entry point.
632  *
633  * NOTE: the main function is already a thread in the system on entry.
634  */
635 int
636 main (int argc, char **argv)
637 {
638   (void)argc;
639   (void)argv;
640
641   fill_serial_no_by_unique_id ();
642
643   halInit();
644   chSysInit();
645
646   main_thread = chThdSelf ();
647
648   usb_lld_init (config_desc.Descriptor[7]);
649
650   chThdCreateStatic (wa_led, sizeof (wa_led), NORMALPRIO, led_blinker, NULL);
651
652   neug_init (random_word, RANDOM_BYTES_LENGTH/sizeof (uint32_t));
653
654   while (1)
655     {
656       unsigned int count = 0;
657
658       connected = 0;
659       while (count < NEUG_PRE_LOOP || bDeviceState != CONFIGURED)
660         {
661           (void)neug_get (NEUG_KICK_FILLING);
662           if ((count & 0x000f) == 0)
663             chEvtSignalFlags (led_thread, LED_ONESHOT_SHORT);
664           chThdSleep (MS2ST (25));
665           count++;
666         }
667
668     waiting_connection:
669       while ((connected & 1) == 0)
670         {
671           neug_flush ();
672           chEvtSignalFlags (led_thread, LED_ONESHOT_LONG);
673           chThdSleep (MS2ST (2500));
674         }
675
676       /* The connection opened.  */
677       count = 0;
678
679       while (1)
680         {
681           if ((connected & 1) == 0)
682             goto waiting_connection;
683
684           if (bDeviceState != CONFIGURED)
685             break;
686
687           neug_wait_full ();
688
689           if ((count & 0x00ff) == 0)
690             chEvtSignalFlags (led_thread, LED_ONESHOT_SHORT);
691
692           usb_lld_txcpy (random_word, ENDP1, 0, RANDOM_BYTES_LENGTH);
693           neug_flush ();
694
695           chSysLock ();
696           usb_lld_tx_enable (ENDP1, RANDOM_BYTES_LENGTH);
697           chSchGoSleepS (THD_STATE_SUSPENDED);
698           chSysUnlock();
699
700           count++;
701         }
702     }
703
704   return 0;
705 }