6602f888309a1b93315b58f2445b21fac885e2c6
[gnuk/neug.git] / src / main.c
1 /*
2  * main.c - main routine of neug
3  *
4  * Main routine:
5  * Copyright (C) 2011, 2012, 2013, 2015, 2016
6  *               Free Software Initiative of Japan
7  * Author: NIIBE Yutaka <gniibe@fsij.org>
8  *
9  * This file is a part of NeuG, a True Random Number Generator
10  * implementation.
11  *
12  * NeuG is free software: you can redistribute it and/or modify it
13  * under the terms of the GNU General Public License as published by
14  * the Free Software Foundation, either version 3 of the License, or
15  * (at your option) any later version.
16  *
17  * NeuG is distributed in the hope that it will be useful, but WITHOUT
18  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
20  * License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
24  *
25  */
26
27
28 #include <stdint.h>
29 #include <string.h>
30 #include <chopstx.h>
31
32 #include "config.h"
33 #include "neug.h"
34 #include "usb_lld.h"
35 #include "sys.h"
36 #include "stm32f103.h"
37 #include "adc.h"
38
39 enum {
40   FSIJ_DEVICE_RUNNING = 0,
41   FSIJ_DEVICE_EXITED,
42   FSIJ_DEVICE_EXEC_REQUESTED,
43   /**/
44   FSIJ_DEVICE_NEUG_FRAUCHEKY_REQUESTED = 254,
45   FSIJ_DEVICE_NEUG_EXIT_REQUESTED = 255
46 };
47
48 #ifdef FRAUCHEKY_SUPPORT
49 static uint8_t running_neug;
50 #endif
51
52 static chopstx_mutex_t usb_mtx;
53 static chopstx_cond_t usb_cnd;
54 static uint32_t bDeviceState = UNCONNECTED; /* USB device status */
55 static uint8_t fsij_device_state = FSIJ_DEVICE_RUNNING;
56 static uint8_t connected;
57
58
59 #define ENDP0_RXADDR        (0x40)
60 #define ENDP0_TXADDR        (0x80)
61 #define ENDP1_TXADDR        (0xc0)
62 #define ENDP2_TXADDR        (0x100)
63 #define ENDP3_RXADDR        (0x140)
64
65 #define USB_CDC_REQ_SET_LINE_CODING             0x20
66 #define USB_CDC_REQ_GET_LINE_CODING             0x21
67 #define USB_CDC_REQ_SET_CONTROL_LINE_STATE      0x22
68 #define USB_CDC_REQ_SEND_BREAK                  0x23
69
70 /* USB Device Descriptor */
71 static const uint8_t vcom_device_desc[18] = {
72   18,   /* bLength */
73   DEVICE_DESCRIPTOR,            /* bDescriptorType */
74   0x10, 0x01,                   /* bcdUSB = 1.1 */
75   0x02,                         /* bDeviceClass (CDC).              */
76   0x00,                         /* bDeviceSubClass.                 */
77   0x00,                         /* bDeviceProtocol.                 */
78   0x40,                         /* bMaxPacketSize.                  */
79 #include "usb-vid-pid-ver.c.inc"
80   1,                            /* iManufacturer.                   */
81   2,                            /* iProduct.                        */
82   3,                            /* iSerialNumber.                   */
83   1                             /* bNumConfigurations.              */
84 };
85
86 #define VCOM_FEATURE_BUS_POWERED        0x80
87
88 /* Configuration Descriptor tree for a CDC.*/
89 static const uint8_t vcom_config_desc[67] = {
90   9,
91   CONFIG_DESCRIPTOR,            /* bDescriptorType: Configuration   */
92   /* Configuration Descriptor.*/
93   67, 0x00,                     /* wTotalLength.                    */
94   0x02,                         /* bNumInterfaces.                  */
95   0x01,                         /* bConfigurationValue.             */
96   0,                            /* iConfiguration.                  */
97   VCOM_FEATURE_BUS_POWERED,     /* bmAttributes.                    */
98   50,                           /* bMaxPower (100mA).               */
99   /* Interface Descriptor.*/
100   9,
101   INTERFACE_DESCRIPTOR,
102   0x00,            /* bInterfaceNumber.                */
103   0x00,            /* bAlternateSetting.               */
104   0x01,            /* bNumEndpoints.                   */
105   0x02,            /* bInterfaceClass (Communications Interface Class,
106                       CDC section 4.2).  */
107   0x02,            /* bInterfaceSubClass (Abstract Control Model, CDC
108                       section 4.3).  */
109   0x01,            /* bInterfaceProtocol (AT commands, CDC section
110                       4.4).  */
111   0,               /* iInterface.                      */
112   /* Header Functional Descriptor (CDC section 5.2.3).*/
113   5,          /* bLength.                         */
114   0x24,       /* bDescriptorType (CS_INTERFACE).  */
115   0x00,       /* bDescriptorSubtype (Header Functional Descriptor). */
116   0x10, 0x01, /* bcdCDC.                          */
117   /* Call Management Functional Descriptor. */
118   5,            /* bFunctionLength.                 */
119   0x24,         /* bDescriptorType (CS_INTERFACE).  */
120   0x01,         /* bDescriptorSubtype (Call Management Functional
121                    Descriptor). */
122   0x03,         /* bmCapabilities (D0+D1).          */
123   0x01,         /* bDataInterface.                  */
124   /* ACM Functional Descriptor.*/
125   4,            /* bFunctionLength.                 */
126   0x24,         /* bDescriptorType (CS_INTERFACE).  */
127   0x02,         /* bDescriptorSubtype (Abstract Control Management
128                    Descriptor).  */
129   0x02,         /* bmCapabilities.                  */
130   /* Union Functional Descriptor.*/
131   5,            /* bFunctionLength.                 */
132   0x24,         /* bDescriptorType (CS_INTERFACE).  */
133   0x06,         /* bDescriptorSubtype (Union Functional
134                    Descriptor).  */
135   0x00,         /* bMasterInterface (Communication Class
136                    Interface).  */
137   0x01,         /* bSlaveInterface0 (Data Class Interface).  */
138   /* Endpoint 2 Descriptor.*/
139   7,
140   ENDPOINT_DESCRIPTOR,
141   ENDP2|0x80,    /* bEndpointAddress.    */
142   0x03,          /* bmAttributes (Interrupt).        */
143   0x08, 0x00,    /* wMaxPacketSize.                  */
144   0xFF,          /* bInterval.                       */
145   /* Interface Descriptor.*/
146   9,
147   INTERFACE_DESCRIPTOR,          /* bDescriptorType: */
148   0x01,          /* bInterfaceNumber.                */
149   0x00,          /* bAlternateSetting.               */
150   0x02,          /* bNumEndpoints.                   */
151   0x0A,          /* bInterfaceClass (Data Class Interface, CDC section 4.5). */
152   0x00,          /* bInterfaceSubClass (CDC section 4.6). */
153   0x00,          /* bInterfaceProtocol (CDC section 4.7). */
154   0x00,          /* iInterface.                      */
155   /* Endpoint 3 Descriptor.*/
156   7,
157   ENDPOINT_DESCRIPTOR,          /* bDescriptorType: Endpoint */
158   ENDP3,    /* bEndpointAddress. */
159   0x02,                         /* bmAttributes (Bulk).             */
160   0x40, 0x00,                   /* wMaxPacketSize.                  */
161   0x00,                         /* bInterval.                       */
162   /* Endpoint 1 Descriptor.*/
163   7,
164   ENDPOINT_DESCRIPTOR,          /* bDescriptorType: Endpoint */
165   ENDP1|0x80,                   /* bEndpointAddress. */
166   0x02,                         /* bmAttributes (Bulk).             */
167   0x40, 0x00,                   /* wMaxPacketSize.                  */
168   0x00                          /* bInterval.                       */
169 };
170
171
172 /*
173  * U.S. English language identifier.
174  */
175 static const uint8_t vcom_string0[4] = {
176   4,                            /* bLength */
177   STRING_DESCRIPTOR,
178   0x09, 0x04                    /* LangID = 0x0409: US-English */
179 };
180
181 #include "usb-strings.c.inc"
182
183 static void neug_setup_endpoints_for_interface (uint16_t interface, int stop);
184 #ifdef FRAUCHEKY_SUPPORT
185 extern int fraucheky_enabled (void);
186 extern void fraucheky_main (void);
187
188 extern void fraucheky_setup_endpoints_for_interface (int stop);
189 extern int fraucheky_setup (uint8_t req, uint8_t req_no,
190                             struct req_args *detail);
191 extern int fraucheky_get_descriptor (uint8_t rcp, uint8_t desc_type,
192                                      uint8_t desc_index,
193                                      struct req_args *detail);
194 #endif
195
196 #define NUM_INTERFACES 2
197
198 void
199 usb_cb_device_reset (void)
200 {
201   int i;
202
203   usb_lld_reset (VCOM_FEATURE_BUS_POWERED);
204
205   /* Initialize Endpoint 0.  */
206   usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR, 64);
207
208   /* Stop the interface */
209   for (i = 0; i < NUM_INTERFACES; i++)
210     neug_setup_endpoints_for_interface (i, 1);
211
212   /* Notify upper layer.  */
213   chopstx_mutex_lock (&usb_mtx);
214   bDeviceState = ATTACHED;
215   connected = 0;
216   chopstx_cond_signal (&usb_cnd);
217   chopstx_mutex_unlock (&usb_mtx);
218 }
219
220 extern uint8_t _regnual_start, __heap_end__;
221
222 static const uint8_t *const mem_info[] = { &_regnual_start,  &__heap_end__, };
223
224 /* USB vendor requests to control pipe */
225 #define USB_FSIJ_MEMINFO          0
226 #define USB_FSIJ_DOWNLOAD         1
227 #define USB_FSIJ_EXEC             2
228 #define USB_NEUG_SET_PASSWD     253
229 #define USB_NEUG_GET_INFO       254
230 #define USB_NEUG_EXIT           255 /* Ask to exit and to receive reGNUal */
231
232 uint8_t neug_passwd[33] __attribute__ ((section(".passwd"))) = {
233   0xff,
234   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
235   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
236   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
237 };
238 static uint8_t usbbuf[64];
239
240 #define DEFAULT_PASSWD "12345678"
241 #define DEFAULT_PASSWD_LEN 8
242
243 static void set_passwd (void)
244 {
245   flash_unlock ();
246   if (neug_passwd[0] != 0xff)
247     flash_erase_page ((uint32_t)neug_passwd);
248   if (usbbuf[0] == DEFAULT_PASSWD_LEN
249       && !memcmp (usbbuf + 1, DEFAULT_PASSWD, DEFAULT_PASSWD_LEN))
250     return;
251   flash_write ((uint32_t)neug_passwd, usbbuf, usbbuf[0] + 1);
252 }
253
254 static uint32_t rbit (uint32_t v)
255 {
256   uint32_t r;
257
258   asm ("rbit    %0, %1" : "=r" (r) : "r" (v));
259   return r;
260 }
261
262 /* After calling this function, CRC module remain enabled.  */
263 static int download_check_crc32 (const uint32_t *end_p)
264 {
265   uint32_t crc32 = *end_p;
266   const uint32_t *p;
267
268   RCC->AHBENR |= RCC_AHBENR_CRCEN;
269   CRC->CR = CRC_CR_RESET;
270
271   for (p = (const uint32_t *)&_regnual_start; p < end_p; p++)
272     CRC->DR = rbit (*p);
273
274   if ((rbit (CRC->DR) ^ crc32) == 0xffffffff)
275     return USB_SUCCESS;
276
277   return USB_UNSUPPORT;
278 }
279
280
281 #define NEUG_SPECIAL_BITRATE 110
282
283 struct line_coding
284 {
285   uint32_t bitrate;
286   uint8_t format;
287   uint8_t paritytype;
288   uint8_t datatype;
289 } __attribute__((packed));
290
291 static struct line_coding line_coding = {
292   115200, /* baud rate: 115200    */
293   0x00,   /* stop bits: 1         */
294   0x00,   /* parity:    none      */
295   0x08    /* bits:      8         */
296 };
297
298 #define CDC_CTRL_DTR            0x0001
299
300 void
301 usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, struct req_args *arg)
302 {
303   uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
304
305   if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT) && USB_SETUP_SET (req))
306     {
307       if (req_no == USB_FSIJ_EXEC)
308         {
309           chopstx_mutex_lock (&usb_mtx);
310           if (fsij_device_state == FSIJ_DEVICE_EXITED)
311             {
312               usb_lld_prepare_shutdown (); /* No further USB communication */
313               fsij_device_state = FSIJ_DEVICE_EXEC_REQUESTED;
314             }
315           chopstx_mutex_unlock (&usb_mtx);
316         }
317       else if (req_no == USB_NEUG_SET_PASSWD)
318         set_passwd ();
319       else if (req_no == USB_NEUG_EXIT)
320         {
321           if ((neug_passwd[0] == 0xff && usbbuf[0] == DEFAULT_PASSWD_LEN
322                && !memcmp (usbbuf + 1, DEFAULT_PASSWD, DEFAULT_PASSWD_LEN))
323               || (neug_passwd[0] == usbbuf[0]
324                   && !memcmp (neug_passwd+1, usbbuf+1, neug_passwd[0])))
325             {
326               chopstx_mutex_lock (&usb_mtx);
327               fsij_device_state = FSIJ_DEVICE_NEUG_EXIT_REQUESTED;
328               chopstx_cond_signal (&usb_cnd);
329               chopstx_mutex_unlock (&usb_mtx);
330             }
331         }
332     }
333   else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT) && arg->index == 0
334            && USB_SETUP_SET (req))
335     {
336       if (req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
337         {
338           /* Open/close the connection.  */
339           chopstx_mutex_lock (&usb_mtx);
340           connected = (arg->value & CDC_CTRL_DTR)? 1 : 0;
341           chopstx_cond_signal (&usb_cnd);
342           chopstx_mutex_unlock (&usb_mtx);
343         }
344 #ifdef FRAUCHEKY_SUPPORT
345       else if (req_no == USB_CDC_REQ_SET_LINE_CODING)
346         {
347           chopstx_mutex_lock (&usb_mtx);
348           if (line_coding.bitrate == NEUG_SPECIAL_BITRATE)
349             {
350               fsij_device_state = FSIJ_DEVICE_NEUG_FRAUCHEKY_REQUESTED;
351               chopstx_cond_signal (&usb_cnd);
352             }
353           else if (fsij_device_state == FSIJ_DEVICE_NEUG_FRAUCHEKY_REQUESTED)
354             fsij_device_state = FSIJ_DEVICE_RUNNING;
355           chopstx_mutex_unlock (&usb_mtx);
356         }
357 #endif
358     }
359 }
360
361
362 static int
363 vcom_port_data_setup (uint8_t req, uint8_t req_no, struct req_args *arg)
364 {
365   if (USB_SETUP_GET (req))
366     {
367       if (req_no == USB_CDC_REQ_GET_LINE_CODING)
368         return usb_lld_reply_request (&line_coding, sizeof(line_coding), arg);
369     }
370   else  /* USB_SETUP_SET (req) */
371     {
372       if (req_no == USB_CDC_REQ_SET_LINE_CODING
373           && arg->len == sizeof (line_coding))
374         {
375           usb_lld_set_data_to_recv (&line_coding, sizeof (line_coding));
376           return USB_SUCCESS;
377         }
378       else if (req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
379         return USB_SUCCESS;
380     }
381
382   return USB_UNSUPPORT;
383 }
384
385 int
386 usb_cb_setup (uint8_t req, uint8_t req_no, struct req_args *arg)
387 {
388   uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
389
390   if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
391     {
392       if (USB_SETUP_GET (req))
393         {
394           if (req_no == USB_FSIJ_MEMINFO)
395             {
396               chopstx_mutex_lock (&usb_mtx);
397               if (fsij_device_state != FSIJ_DEVICE_EXITED)
398                 {
399                   chopstx_mutex_unlock (&usb_mtx);
400                   return USB_UNSUPPORT;
401                 }
402               chopstx_mutex_unlock (&usb_mtx);
403               usb_lld_reply_request (mem_info, sizeof (mem_info), arg);
404               return USB_SUCCESS;
405             }
406           else if (req_no == USB_NEUG_GET_INFO)
407             {
408               if (arg->index == 0)
409                 usb_lld_reply_request (&neug_mode, sizeof (uint8_t), arg);
410               else if (arg->index == 1)
411                 usb_lld_reply_request (&neug_err_cnt, sizeof (uint16_t), arg);
412               else if (arg->index == 2)
413                 usb_lld_reply_request (&neug_err_cnt_rc, sizeof (uint16_t), arg);
414               else if (arg->index == 3)
415                 usb_lld_reply_request (&neug_err_cnt_p64, sizeof (uint16_t), arg);
416               else if (arg->index == 4)
417                 usb_lld_reply_request (&neug_err_cnt_p4k, sizeof (uint16_t), arg);
418               else if (arg->index == 5)
419                 usb_lld_reply_request (&neug_rc_max, sizeof (uint16_t), arg);
420               else if (arg->index == 6)
421                 usb_lld_reply_request (&neug_p64_max, sizeof (uint16_t), arg);
422               else if (arg->index == 7)
423                 usb_lld_reply_request (&neug_p4k_max, sizeof (uint16_t), arg);
424               else
425                 return USB_UNSUPPORT;
426
427               return USB_SUCCESS;
428             }
429         }
430       else /* SETUP_SET */
431         {
432           uint8_t *addr = (uint8_t *)(0x20000000 + arg->value * 0x100 + arg->index);
433
434           if (req_no == USB_FSIJ_DOWNLOAD)
435             {
436               chopstx_mutex_lock (&usb_mtx);
437               if (fsij_device_state != FSIJ_DEVICE_EXITED)
438                 {
439                   chopstx_mutex_unlock (&usb_mtx);
440                   return USB_UNSUPPORT;
441                 }
442               chopstx_mutex_unlock (&usb_mtx);
443
444               if (addr < &_regnual_start || addr + arg->len > &__heap_end__)
445                 return USB_UNSUPPORT;
446
447               if (arg->index + arg->len < 256)
448                 memset (addr + arg->index + arg->len, 0, 256 - (arg->index + arg->len));
449
450               usb_lld_set_data_to_recv (addr, arg->len);
451               return USB_SUCCESS;
452             }
453           else if (req_no == USB_FSIJ_EXEC && arg->len == 0)
454             {
455               chopstx_mutex_lock (&usb_mtx);
456               if (fsij_device_state != FSIJ_DEVICE_EXITED)
457                 {
458                   chopstx_mutex_unlock (&usb_mtx);
459                   return USB_UNSUPPORT;
460                 }
461               chopstx_mutex_unlock (&usb_mtx);
462
463               if (((uint32_t)addr & 0x03))
464                 return USB_UNSUPPORT;
465
466               return download_check_crc32 ((uint32_t *)addr);
467             }
468           else if (req_no == USB_NEUG_SET_PASSWD && arg->len <= 32)
469             {
470               usbbuf[0] = arg->len;
471               usb_lld_set_data_to_recv (usbbuf + 1, arg->len);
472               return USB_SUCCESS;
473             }
474           else if (req_no == USB_NEUG_EXIT && arg->len <= 32)
475             {
476               chopstx_mutex_lock (&usb_mtx);
477               if (fsij_device_state != FSIJ_DEVICE_RUNNING)
478                 {
479                   chopstx_mutex_unlock (&usb_mtx);
480                   return USB_UNSUPPORT;
481                 }
482               chopstx_mutex_unlock (&usb_mtx);
483
484               usbbuf[0] = arg->len;
485               usb_lld_set_data_to_recv (usbbuf + 1, arg->len);
486               return USB_SUCCESS;
487             }
488         }
489     }
490   else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT)
491            && arg->index == 0)
492     {
493 #ifdef FRAUCHEKY_SUPPORT
494       if (running_neug)
495         return vcom_port_data_setup (req, req_no, arg);
496       else
497         fraucheky_setup (req, req_no, arg);
498 #else
499       return vcom_port_data_setup (req, req_no, arg);
500 #endif
501     }
502
503   return USB_UNSUPPORT;
504 }
505
506 int
507 usb_cb_get_descriptor (uint8_t rcp, uint8_t desc_type, uint8_t desc_index,
508                        struct req_args *arg)
509 {
510 #ifdef FRAUCHEKY_SUPPORT
511   if (!running_neug)
512     return fraucheky_get_descriptor (rcp, desc_type, desc_index, arg);
513 #endif
514
515   if (rcp != DEVICE_RECIPIENT)
516     return USB_UNSUPPORT;
517
518   if (desc_type == DEVICE_DESCRIPTOR)
519     return usb_lld_reply_request (vcom_device_desc, sizeof (vcom_device_desc),
520                                   arg);
521   else if (desc_type == CONFIG_DESCRIPTOR)
522     return usb_lld_reply_request (vcom_config_desc, sizeof (vcom_config_desc),
523                                   arg);
524   else if (desc_type == STRING_DESCRIPTOR)
525     {
526       const uint8_t *str;
527       int size;
528
529       switch (desc_index)
530         {
531         case 0:
532           str = vcom_string0;
533           size = sizeof (vcom_string0);
534           break;
535         case 1:
536           str = neug_string_vendor;
537           size = sizeof (neug_string_vendor);
538           break;
539         case 2:
540           str = neug_string_product;
541           size = sizeof (neug_string_product);
542           break;
543         case 3:
544           str = neug_string_serial;
545           size = sizeof (neug_string_serial);
546           break;
547         case 4:
548           str = neug_revision_detail;
549           size = sizeof (neug_revision_detail);
550           break;
551         case 5:
552           str = neug_config_options;
553           size = sizeof (neug_config_options);
554           break;
555         case 6:
556           str = sys_version;
557           size = sizeof (sys_version);
558           break;
559         case 7:
560           {
561             int i;
562             str = usbbuf;
563             for (i = 0; i < (int)sizeof (usbbuf)/2 - 2; i++)
564               {
565                 if (sys_board_name[i] == 0)
566                   break;
567
568                 usbbuf[i*2+2] = sys_board_name[i];
569                 usbbuf[i*2+3] = 0;
570               }
571             usbbuf[0] = i*2 + 2;
572             usbbuf[1] = STRING_DESCRIPTOR;
573             size = i*2 + 2;
574           }
575           break;
576         default:
577           return USB_UNSUPPORT;
578         }
579
580       return usb_lld_reply_request (str, size, arg);
581     }
582
583   return USB_UNSUPPORT;
584 }
585
586 static void
587 neug_setup_endpoints_for_interface (uint16_t interface, int stop)
588 {
589   if (interface == 0)
590     {
591 #ifdef FRAUCHEKY_SUPPORT
592       if (running_neug)
593         {
594           if (!stop)
595             usb_lld_setup_endpoint (ENDP2, EP_INTERRUPT, 0, 0, ENDP2_TXADDR, 0);
596           else
597             usb_lld_stall_tx (ENDP2);
598         }
599       else
600         fraucheky_setup_endpoints_for_interface (stop);
601 #else
602       if (!stop)
603         usb_lld_setup_endpoint (ENDP2, EP_INTERRUPT, 0, 0, ENDP2_TXADDR, 0);
604       else
605         usb_lld_stall_tx (ENDP2);
606 #endif
607     }
608   else if (interface == 1)
609     {
610       if (!stop)
611         {
612           usb_lld_setup_endpoint (ENDP1, EP_BULK, 0, 0, ENDP1_TXADDR, 0);
613           usb_lld_setup_endpoint (ENDP3, EP_BULK, 0, ENDP3_RXADDR, 0, 64);
614           /* Start with no data receiving (ENDP3 not enabled) */
615         }
616       else
617         {
618           usb_lld_stall_tx (ENDP1);
619           usb_lld_stall_rx (ENDP3);
620         }
621     }
622 }
623
624 int usb_cb_handle_event (uint8_t event_type, uint16_t value)
625 {
626   int i;
627   uint8_t current_conf;
628
629   switch (event_type)
630     {
631     case USB_EVENT_ADDRESS:
632       chopstx_mutex_lock (&usb_mtx);
633       bDeviceState = ADDRESSED;
634       chopstx_mutex_unlock (&usb_mtx);
635       return USB_SUCCESS;
636     case USB_EVENT_CONFIG:
637       current_conf = usb_lld_current_configuration ();
638       if (current_conf == 0)
639         {
640           if (value != 1)
641             return USB_UNSUPPORT;
642
643           usb_lld_set_configuration (1);
644           for (i = 0; i < NUM_INTERFACES; i++)
645             neug_setup_endpoints_for_interface (i, 0);
646           chopstx_mutex_lock (&usb_mtx);
647           bDeviceState = CONFIGURED;
648           chopstx_mutex_unlock (&usb_mtx);
649         }
650       else if (current_conf != value)
651         {
652           if (value != 0)
653             return USB_UNSUPPORT;
654
655           usb_lld_set_configuration (0);
656           for (i = 0; i < NUM_INTERFACES; i++)
657             neug_setup_endpoints_for_interface (i, 1);
658           chopstx_mutex_lock (&usb_mtx);
659           bDeviceState = ADDRESSED;
660           chopstx_mutex_unlock (&usb_mtx);
661         }
662       /* Do nothing when current_conf == value */
663       return USB_SUCCESS;
664     default:
665       break;
666     }
667
668   return USB_UNSUPPORT;
669 }
670
671
672 int usb_cb_interface (uint8_t cmd, struct req_args *arg)
673 {
674   const uint8_t zero = 0;
675   uint16_t interface = arg->index;
676   uint16_t alt = arg->value;
677
678   if (interface >= NUM_INTERFACES)
679     return USB_UNSUPPORT;
680
681   switch (cmd)
682     {
683     case USB_SET_INTERFACE:
684       if (alt != 0)
685         return USB_UNSUPPORT;
686       else
687         {
688           neug_setup_endpoints_for_interface (interface, 0);
689           return USB_SUCCESS;
690         }
691
692     case USB_GET_INTERFACE:
693       return usb_lld_reply_request (&zero, 1, arg);
694
695     default:
696     case USB_QUERY_INTERFACE:
697       return USB_SUCCESS;
698     }
699 }
700
701 #define INTR_REQ_USB 20
702 #define PRIO_USB 3
703
704 static void *
705 usb_intr (void *arg)
706 {
707   chopstx_intr_t interrupt;
708
709   (void)arg;
710   usb_lld_init (VCOM_FEATURE_BUS_POWERED);
711   chopstx_claim_irq (&interrupt, INTR_REQ_USB);
712   usb_interrupt_handler ();     /* For old SYS < 3.0 */
713
714   while (1)
715     {
716       chopstx_poll (NULL, 1, &interrupt);
717
718       /* Process interrupt. */
719       usb_interrupt_handler ();
720     }
721
722   return NULL;
723 }
724
725 #define ID_OFFSET (2+SERIALNO_STR_LEN*2)
726 static void fill_serial_no_by_unique_id (void)
727 {
728   extern const uint8_t * unique_device_id (void);
729   uint8_t *p = &neug_string_serial[ID_OFFSET];
730   const uint8_t *u = unique_device_id () + 8;
731   int i;
732
733   for (i = 0; i < 4; i++)
734     {
735       uint8_t b = u[3-i];
736       uint8_t nibble;
737
738       nibble = (b >> 4);
739       nibble += (nibble >= 10 ? ('A' - 10) : '0');
740       p[i*4] = nibble;
741       p[i*4+1] = 0;
742       nibble = (b & 0x0f);
743       nibble += (nibble >= 10 ? ('A' - 10) : '0');
744       p[i*4+2] = nibble;
745       p[i*4+3] = 0;
746     }
747 }
748
749
750 void
751 usb_cb_tx_done (uint8_t ep_num)
752 {
753   if (ep_num == ENDP1)
754     {
755       chopstx_mutex_lock (&usb_mtx);
756       chopstx_cond_signal (&usb_cnd);
757       chopstx_mutex_unlock (&usb_mtx);
758     }
759   else if (ep_num == ENDP2)
760     {
761       /* INTERRUPT Transfer done */
762     }
763 }
764
765 void
766 usb_cb_rx_ready (uint8_t ep_num)
767 {
768   if (ep_num == ENDP3)
769     usb_lld_rx_enable (ENDP3);
770 }
771 \f
772 typedef uint32_t eventmask_t;
773 #define ALL_EVENTS (~0)
774
775 struct event_flag {
776   chopstx_mutex_t mutex;
777   chopstx_cond_t cond;
778   eventmask_t flag;
779 };
780
781 static void event_flag_init (struct event_flag *ev)
782 {
783   ev->flag = 0;
784   chopstx_mutex_init (&ev->mutex);
785   chopstx_cond_init (&ev->cond);
786 }
787
788
789 static eventmask_t event_flag_waitone (struct event_flag *ev, eventmask_t m)
790 {
791   int n;
792
793   chopstx_mutex_lock (&ev->mutex);
794   while (!(ev->flag & m))
795     chopstx_cond_wait (&ev->cond, &ev->mutex);
796
797   n = __builtin_ffs ((ev->flag & m));
798   ev->flag &= ~(1 << (n - 1));
799   chopstx_mutex_unlock (&ev->mutex);
800
801   return (1 << (n - 1));
802 }
803
804 static void event_flag_signal (struct event_flag *ev, eventmask_t m)
805 {
806   chopstx_mutex_lock (&ev->mutex);
807   ev->flag |= m;
808   chopstx_cond_signal (&ev->cond);
809   chopstx_mutex_unlock (&ev->mutex);
810 }
811
812 extern uint8_t __process1_stack_base__, __process1_stack_size__;
813 extern uint8_t __process3_stack_base__, __process3_stack_size__;
814
815 const uint32_t __stackaddr_led = (uint32_t)&__process1_stack_base__;
816 const size_t __stacksize_led = (size_t)&__process1_stack_size__;
817 const uint32_t __stackaddr_usb = (uint32_t)&__process3_stack_base__;
818 const size_t __stacksize_usb = (size_t)&__process3_stack_size__;
819
820
821 #define PRIO_LED 3
822 static struct event_flag led_event;
823
824 #define LED_ONESHOT_SHORT       ((eventmask_t)1)
825 #define LED_TWOSHOTS            ((eventmask_t)2)
826 #define LED_ONESHOT_LONG        ((eventmask_t)4)
827
828 /*
829  * LED blinker: When notified, let LED emit for 100ms.
830  */
831 static void *
832 led_blinker (void *arg)
833 {
834   (void)arg;
835
836   set_led (0);
837
838   while (1)
839     {
840       eventmask_t m;
841
842       m = event_flag_waitone (&led_event, ALL_EVENTS);
843
844       set_led (1);
845       if (m == LED_ONESHOT_SHORT)
846         chopstx_usec_wait (100*1000);
847       else if (m == LED_TWOSHOTS)
848         {
849           chopstx_usec_wait (50*1000);
850           set_led (0);
851           chopstx_usec_wait (50*1000);
852           set_led (1);
853           chopstx_usec_wait (50*1000);
854         }
855       else
856         chopstx_usec_wait (250*1000);
857       set_led (0);
858     }
859
860   return NULL;
861 }
862 \f
863 #define RANDOM_BYTES_LENGTH 64
864 static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)];
865
866 static void copy_to_tx (uint32_t v, int i)
867 {
868   usb_lld_txcpy (&v, ENDP1, i * 4, 4);
869 }
870
871 /*
872  * In Gnuk 1.0.[12], reGNUal was not relocatable.
873  * Now, it's relocatable, but we need to calculate its entry address
874  * based on it's pre-defined address.
875  */
876 #define REGNUAL_START_ADDRESS_COMPATIBLE 0x20001400
877 static uint32_t
878 calculate_regnual_entry_address (const uint8_t *addr)
879 {
880   const uint8_t *p = addr + 4;
881   uint32_t v = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24);
882
883   v -= REGNUAL_START_ADDRESS_COMPATIBLE;
884   v += (uint32_t)addr;
885   return v;
886 }
887
888
889 static int
890 check_usb_status (void *arg)
891 {
892   (void)arg;
893
894   return (connected || bDeviceState != CONFIGURED
895           || fsij_device_state != FSIJ_DEVICE_RUNNING);
896 }
897
898 /*
899  * Entry point.
900  *
901  * NOTE: the main function is already a thread in the system on entry.
902  */
903 int
904 main (int argc, char **argv)
905 {
906   uint32_t entry;
907   chopstx_t led_thread, usb_thd;
908   unsigned int count;
909
910   (void)argc;
911   (void)argv;
912
913   fill_serial_no_by_unique_id ();
914
915   adc_init ();
916
917   event_flag_init (&led_event);
918
919   chopstx_mutex_init (&usb_mtx);
920   chopstx_cond_init (&usb_cnd);
921
922 #ifdef FRAUCHEKY_SUPPORT
923   if (fraucheky_enabled ())
924     {
925     go_fraucheky:
926       running_neug = 0;
927       usb_thd = chopstx_create (PRIO_USB, __stackaddr_usb, __stacksize_usb,
928                                 usb_intr, NULL);
929       set_led (1);
930       fraucheky_main ();
931       chopstx_cancel (usb_thd);
932       chopstx_join (usb_thd, NULL);
933       usb_lld_shutdown ();
934     }
935
936   running_neug = 1;
937 #endif
938
939   led_thread = chopstx_create (PRIO_LED, __stackaddr_led, __stacksize_led,
940                                led_blinker, NULL);
941
942   usb_thd = chopstx_create (PRIO_USB, __stackaddr_usb, __stacksize_usb,
943                             usb_intr, NULL);
944
945   neug_init (random_word, RANDOM_BYTES_LENGTH/sizeof (uint32_t));
946
947   chopstx_mutex_lock (&usb_mtx);
948
949  not_configured:
950   count = 0;
951   /* Initial run-up */
952   while (count < NEUG_PRE_LOOP || bDeviceState != CONFIGURED)
953     {
954       if (fsij_device_state != FSIJ_DEVICE_RUNNING)
955         break;
956
957       chopstx_mutex_unlock (&usb_mtx);
958       neug_wait_full ();
959       neug_flush ();
960
961       if ((count & 0x0007) == 0)
962         event_flag_signal (&led_event, LED_ONESHOT_SHORT);
963       chopstx_usec_wait (25*1000);
964       count++;
965       chopstx_mutex_lock (&usb_mtx);
966     }
967
968   /* Holding USB_MTX...  */
969   while (1)
970     {
971       int last_was_fullsizepacket = 0;
972
973       if (fsij_device_state != FSIJ_DEVICE_RUNNING)
974         break;
975
976       chopstx_mutex_unlock (&usb_mtx);
977       while (1)
978         {
979           chopstx_poll_cond_t poll_desc;
980           uint32_t usec = 5000*1000;
981
982           poll_desc.type = CHOPSTX_POLL_COND;
983           poll_desc.ready = 0;
984           poll_desc.cond = &usb_cnd;
985           poll_desc.mutex = &usb_mtx;
986           poll_desc.check = check_usb_status;
987           poll_desc.arg = NULL;
988
989           if (chopstx_poll (&usec, 1, &poll_desc))
990             break;
991
992           /* Timeout */
993           neug_flush ();
994           neug_mode_select (line_coding.paritytype);
995           event_flag_signal (&led_event, LED_TWOSHOTS);
996         }
997
998       chopstx_mutex_lock (&usb_mtx);
999       if (bDeviceState != CONFIGURED)
1000         goto not_configured;
1001
1002       /* The connection opened.  */
1003       count = 0;
1004
1005       while (1)
1006         {
1007           int i;
1008
1009           chopstx_mutex_unlock (&usb_mtx);
1010           /*
1011            * No parity is standard.  It means providing conditioned output.
1012            * When parity enabled, it means to provide raw output
1013            * (CRC32 filtered when odd, direct sample of ADC when even).
1014            *
1015            * line_coding.paritytype:
1016            *   0: None, 1: Odd, 2: Even
1017            */
1018           neug_mode_select (line_coding.paritytype);
1019
1020           if ((count & 0x03ff) == 0)
1021             event_flag_signal (&led_event, LED_ONESHOT_SHORT);
1022
1023           i = neug_consume_random (copy_to_tx);
1024
1025           if (i == 0 && !last_was_fullsizepacket)
1026             {    /* Only send ZLP when the last packet was fullsize.  */
1027               neug_wait_full ();
1028
1029               chopstx_mutex_lock (&usb_mtx);
1030               if (bDeviceState != CONFIGURED || !connected
1031                   || fsij_device_state != FSIJ_DEVICE_RUNNING)
1032                 break;
1033             }
1034           else
1035             {
1036               if (i == 64/4)
1037                 last_was_fullsizepacket = 1;
1038               else
1039                 last_was_fullsizepacket = 0;
1040
1041               chopstx_mutex_lock (&usb_mtx);
1042               if (bDeviceState != CONFIGURED || !connected
1043                   || fsij_device_state != FSIJ_DEVICE_RUNNING)
1044                 break;
1045
1046               /* Prepare sending random data.  */
1047               usb_lld_tx_enable (ENDP1, i * 4);
1048               chopstx_cond_wait (&usb_cnd, &usb_mtx);
1049               count++;
1050             }
1051         }
1052     }
1053
1054   chopstx_mutex_unlock (&usb_mtx);
1055
1056   chopstx_cancel (led_thread);
1057   chopstx_join (led_thread, NULL);
1058
1059   /*
1060    * We come here, because of FSIJ_DEVICE_NEUG_EXIT_REQUESTED
1061    * or FSIJ_DEVICE_NEUG_FRAUCHEKY_REQUESTED.
1062    */
1063   neug_fini ();
1064
1065   chopstx_mutex_lock (&usb_mtx);
1066 #ifdef FRAUCHEKY_SUPPORT
1067   if (line_coding.bitrate == NEUG_SPECIAL_BITRATE)
1068     {
1069       while (fsij_device_state == FSIJ_DEVICE_NEUG_FRAUCHEKY_REQUESTED)
1070         {
1071           chopstx_mutex_unlock (&usb_mtx);
1072           set_led (1);
1073           chopstx_usec_wait (500*1000);
1074           set_led (0);
1075           chopstx_usec_wait (500*1000);
1076           chopstx_mutex_lock (&usb_mtx);
1077         }
1078
1079       usb_lld_prepare_shutdown ();
1080       chopstx_mutex_unlock (&usb_mtx);
1081       chopstx_cancel (usb_thd);
1082       chopstx_join (usb_thd, NULL);
1083       usb_lld_shutdown ();
1084       goto go_fraucheky;
1085     }
1086 #endif
1087
1088   fsij_device_state = FSIJ_DEVICE_EXITED;
1089
1090   while (fsij_device_state == FSIJ_DEVICE_EXITED)
1091     {
1092       chopstx_mutex_unlock (&usb_mtx);
1093       chopstx_usec_wait (500*1000);
1094       chopstx_mutex_lock (&usb_mtx);
1095     }
1096   chopstx_mutex_unlock (&usb_mtx);
1097
1098   flash_unlock ();              /* Flash unlock should be done here */
1099   set_led (1);
1100   usb_lld_shutdown ();
1101
1102   /* Finish application.  */
1103   chopstx_cancel (usb_thd);
1104   chopstx_join (usb_thd, NULL);
1105
1106   /* Set vector */
1107   SCB->VTOR = (uint32_t)&_regnual_start;
1108   entry = calculate_regnual_entry_address (&_regnual_start);
1109 #ifdef DFU_SUPPORT
1110 #define FLASH_SYS_START_ADDR 0x08000000
1111 #define FLASH_SYS_END_ADDR (0x08000000+0x1000)
1112 #define CHIP_ID_REG ((uint32_t *)0xE0042000)
1113   {
1114     extern uint8_t _sys;
1115     uint32_t addr;
1116     handler *new_vector = (handler *)FLASH_SYS_START_ADDR;
1117     void (*func) (void (*)(void)) = (void (*)(void (*)(void)))new_vector[9];
1118     uint32_t flash_page_size = 1024; /* 1KiB default */
1119
1120    if ((*CHIP_ID_ADDR)&0x07 == 0x04) /* High dencity device.  */
1121      flash_page_size += 0x0400; /* It's 2KiB. */
1122
1123     /* Kill DFU */
1124     for (addr = FLASH_SYS_START_ADDR; addr < FLASH_SYS_END_ADDR;
1125          addr += flash_page_size)
1126       flash_erase_page (addr);
1127
1128     /* copy system service routines */
1129     flash_write (FLASH_SYS_START_ADDR, &_sys, 0x1000);
1130
1131     /* Leave NeuG to exec reGNUal */
1132     (*func) ((void (*)(void))entry);
1133     for (;;);
1134   }
1135 #else
1136   /* Leave NeuG to exec reGNUal */
1137   flash_erase_all_and_exec ((void (*)(void))entry);
1138 #endif
1139
1140   /* Never reached */
1141   return 0;
1142 }