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