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