fix reset handling
[gnuk/neug.git] / src / main.c
index 9bb31a1..1bba0b5 100644 (file)
@@ -2,7 +2,8 @@
  * main.c - main routine of neug
  *
  * Main routine:
- * Copyright (C) 2011, 2012, 2013 Free Software Initiative of Japan
+ * Copyright (C) 2011, 2012, 2013, 2015
+ *              Free Software Initiative of Japan
  * Author: NIIBE Yutaka <gniibe@fsij.org>
  *
  * This file is a part of NeuG, a True Random Number Generator
@@ -40,6 +41,7 @@ enum {
   FSIJ_DEVICE_EXITED,
   FSIJ_DEVICE_EXEC_REQUESTED,
   /**/
+  FSIJ_DEVICE_NEUG_FRAUCHEKY_REQUESTED = 254,
   FSIJ_DEVICE_NEUG_EXIT_REQUESTED = 255
 }; 
 
@@ -86,7 +88,7 @@ static const uint8_t vcom_device_desc[18] = {
 };
 
 /* Configuration Descriptor tree for a CDC.*/
-static const uint8_t vcom_configuration_desc[67] = {
+static const uint8_t vcom_config_desc[67] = {
   9,
   USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
   /* Configuration Descriptor.*/
@@ -185,10 +187,11 @@ extern int fraucheky_enabled (void);
 extern void fraucheky_main (void);
 
 extern void fraucheky_setup_endpoints_for_interface (int stop);
-extern int fraucheky_setup (uint8_t req, uint8_t req_no, uint16_t value,
-                           uint16_t len);
+extern int fraucheky_setup (uint8_t req, uint8_t req_no,
+                           struct control_info *detail);
 extern int fraucheky_get_descriptor (uint8_t rcp, uint8_t desc_type,
-                                    uint8_t desc_index, uint16_t index);
+                                    uint8_t desc_index,
+                                    struct control_info *detail);
 #endif
 
 #define NUM_INTERFACES 2
@@ -196,16 +199,24 @@ extern int fraucheky_get_descriptor (uint8_t rcp, uint8_t desc_type,
 void
 usb_cb_device_reset (void)
 {
-  /* Set DEVICE as not configured */
+  /* Set DEVICE as not configured */
   usb_lld_set_configuration (0);
 
-  /* Current Feature initialization */
-  usb_lld_set_feature (vcom_configuration_desc[7]);
+  /* Current Feature initialization */
+  usb_lld_set_feature (vcom_config_desc[7]);
 
   usb_lld_reset ();
 
-  /* Initialize Endpoint 0 */
+  /* Initialize Endpoint 0 */
   usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR, 64);
+
+  /* Notify upper layer.  */
+  chopstx_mutex_lock (&usb_mtx);
+  bDeviceState = ATTACHED;
+  connected = 0;
+  if (!wait_usb_connection)
+    chopstx_cond_signal (&cnd_usb);
+  chopstx_mutex_unlock (&usb_mtx);
 }
 
 extern uint8_t _regnual_start, __heap_end__;
@@ -226,7 +237,7 @@ uint8_t neug_passwd[33] __attribute__ ((section(".passwd"))) = {
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 };
-static uint8_t passwd_data[33];
+static uint8_t usbbuf[64];
 
 #define DEFAULT_PASSWD "12345678"
 #define DEFAULT_PASSWD_LEN 8
@@ -236,10 +247,10 @@ static void set_passwd (void)
   flash_unlock ();
   if (neug_passwd[0] != 0xff)
     flash_erase_page ((uint32_t)neug_passwd);
-  if (passwd_data[0] == DEFAULT_PASSWD_LEN
-      && !memcmp (passwd_data + 1, DEFAULT_PASSWD, DEFAULT_PASSWD_LEN))
+  if (usbbuf[0] == DEFAULT_PASSWD_LEN
+      && !memcmp (usbbuf + 1, DEFAULT_PASSWD, DEFAULT_PASSWD_LEN))
     return;
-  flash_write ((uint32_t)neug_passwd, passwd_data, passwd_data[0] + 1);
+  flash_write ((uint32_t)neug_passwd, usbbuf, usbbuf[0] + 1);
 }
 
 static uint32_t rbit (uint32_t v)
@@ -268,15 +279,34 @@ static int download_check_crc32 (const uint32_t *end_p)
   return USB_UNSUPPORT;
 }
 
+
+#define NEUG_SPECIAL_BITRATE 110
+
+struct line_coding
+{
+  uint32_t bitrate;
+  uint8_t format;
+  uint8_t paritytype;
+  uint8_t datatype;
+} __attribute__((packed));
+
+static struct line_coding line_coding = {
+  115200, /* baud rate: 115200    */
+  0x00,   /* stop bits: 1         */
+  0x00,   /* parity:    none      */
+  0x08    /* bits:      8         */
+};
+
+#define CDC_CTRL_DTR            0x0001
+
 void
-usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, uint16_t value,
-                         uint16_t index, uint16_t len)
+usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, uint16_t value)
 {
   uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
 
   if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT) && USB_SETUP_SET (req))
     {
-      if (req_no == USB_FSIJ_EXEC && len == 0)
+      if (req_no == USB_FSIJ_EXEC)
        {
          chopstx_mutex_lock (&usb_mtx);
          if (fsij_device_state == FSIJ_DEVICE_EXITED)
@@ -290,10 +320,10 @@ usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, uint16_t value,
        set_passwd ();
       else if (req_no == USB_NEUG_EXIT)
        {
-         if ((neug_passwd[0] == 0xff && passwd_data[0] == DEFAULT_PASSWD_LEN
-              && !memcmp (passwd_data + 1, DEFAULT_PASSWD, DEFAULT_PASSWD_LEN))
-             || (neug_passwd[0] == passwd_data[0]
-                 && !memcmp (neug_passwd+1, passwd_data+1, neug_passwd[0])))
+         if ((neug_passwd[0] == 0xff && usbbuf[0] == DEFAULT_PASSWD_LEN
+              && !memcmp (usbbuf + 1, DEFAULT_PASSWD, DEFAULT_PASSWD_LEN))
+             || (neug_passwd[0] == usbbuf[0]
+                 && !memcmp (neug_passwd+1, usbbuf+1, neug_passwd[0])))
            {
              chopstx_mutex_lock (&usb_mtx);
              fsij_device_state = FSIJ_DEVICE_NEUG_EXIT_REQUESTED;
@@ -304,57 +334,53 @@ usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, uint16_t value,
        }
     }
   else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT)
-          && index == 0 && USB_SETUP_SET (req)
-          && req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
+          && USB_SETUP_SET (req))
     {
-      /* Open/close the connection.  */
-      chopstx_mutex_lock (&usb_mtx);
-      connected = (value != 0)? 1 : 0;
-      if (wait_usb_connection)
-       {                       /* It is waiting a connection.  */
-         if (connected)        /* It's now connected.  */
-           chopstx_wakeup_usec_wait (main_thd);
+      if (req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
+       {
+         /* Open/close the connection.  */
+         chopstx_mutex_lock (&usb_mtx);
+         connected = (value & CDC_CTRL_DTR)? 1 : 0;
+         if (wait_usb_connection)
+           {                   /* It is waiting a connection.  */
+             if (connected)    /* It's now connected.  */
+               chopstx_wakeup_usec_wait (main_thd);
+           }
+         else
+           chopstx_cond_signal (&cnd_usb);
+         chopstx_mutex_unlock (&usb_mtx);
        }
-      else
-       chopstx_cond_signal (&cnd_usb);
-      chopstx_mutex_unlock (&usb_mtx);
+#ifdef FRAUCHEKY_SUPPORT
+      else if (req_no == USB_CDC_REQ_SET_LINE_CODING)
+       {
+         chopstx_mutex_lock (&usb_mtx);
+         if (line_coding.bitrate == NEUG_SPECIAL_BITRATE)
+           {
+             fsij_device_state = FSIJ_DEVICE_NEUG_FRAUCHEKY_REQUESTED;
+             chopstx_wakeup_usec_wait (main_thd);
+             chopstx_cond_signal (&cnd_usb);
+           }
+         else if (fsij_device_state == FSIJ_DEVICE_NEUG_FRAUCHEKY_REQUESTED)
+           fsij_device_state = FSIJ_DEVICE_RUNNING;
+         chopstx_mutex_unlock (&usb_mtx);
+       }
+#endif
     }
 }
 
-struct line_coding
-{
-  uint32_t bitrate;
-  uint8_t format;
-  uint8_t paritytype;
-  uint8_t datatype;
-} __attribute__((packed));
-
-static struct line_coding line_coding = {
-  115200, /* baud rate: 115200    */
-  0x00,   /* stop bits: 1         */
-  0x00,   /* parity:    none      */
-  0x08    /* bits:      8         */
-};
-
 
 static int
-vcom_port_data_setup (uint8_t req, uint8_t req_no, uint16_t value,
-                     uint16_t len)
+vcom_port_data_setup (uint8_t req, uint8_t req_no, struct control_info *detail)
 {
-  (void)value;
   if (USB_SETUP_GET (req))
     {
-      if (req_no == USB_CDC_REQ_GET_LINE_CODING
-         && len == sizeof (line_coding))
-       {
-         usb_lld_set_data_to_send (&line_coding, sizeof (line_coding));
-         return USB_SUCCESS;
-       }
+      if (req_no == USB_CDC_REQ_GET_LINE_CODING)
+       return usb_lld_reply_request (&line_coding, sizeof(line_coding), detail);
     }
   else  /* USB_SETUP_SET (req) */
     {
       if (req_no == USB_CDC_REQ_SET_LINE_CODING
-         && len == sizeof (line_coding))
+         && detail->len == sizeof (line_coding))
        {
          usb_lld_set_data_to_recv (&line_coding, sizeof (line_coding));
          return USB_SUCCESS;
@@ -367,8 +393,7 @@ vcom_port_data_setup (uint8_t req, uint8_t req_no, uint16_t value,
 }
 
 int
-usb_cb_setup (uint8_t req, uint8_t req_no,
-              uint16_t value, uint16_t index, uint16_t len)
+usb_cb_setup (uint8_t req, uint8_t req_no, struct control_info *detail)
 {
   uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
 
@@ -385,27 +410,27 @@ usb_cb_setup (uint8_t req, uint8_t req_no,
                  return USB_UNSUPPORT;
                }
              chopstx_mutex_unlock (&usb_mtx);
-             usb_lld_set_data_to_send (mem_info, sizeof (mem_info));
+             usb_lld_reply_request (mem_info, sizeof (mem_info), detail);
              return USB_SUCCESS;
            }
          else if (req_no == USB_NEUG_GET_INFO)
            {
-             if (index == 0)
-               usb_lld_set_data_to_send (&neug_mode, sizeof (uint8_t));
-             else if (index == 1)
-               usb_lld_set_data_to_send (&neug_err_cnt, sizeof (uint16_t));
-             else if (index == 2)
-               usb_lld_set_data_to_send (&neug_err_cnt_rc, sizeof (uint16_t));
-             else if (index == 3)
-               usb_lld_set_data_to_send (&neug_err_cnt_p64, sizeof (uint16_t));
-             else if (index == 4)
-               usb_lld_set_data_to_send (&neug_err_cnt_p4k, sizeof (uint16_t));
-             else if (index == 5)
-               usb_lld_set_data_to_send (&neug_rc_max, sizeof (uint16_t));
-             else if (index == 6)
-               usb_lld_set_data_to_send (&neug_p64_max, sizeof (uint16_t));
-             else if (index == 7)
-               usb_lld_set_data_to_send (&neug_p4k_max, sizeof (uint16_t));
+             if (detail->index == 0)
+               usb_lld_reply_request (&neug_mode, sizeof (uint8_t), detail);
+             else if (detail->index == 1)
+               usb_lld_reply_request (&neug_err_cnt, sizeof (uint16_t), detail);
+             else if (detail->index == 2)
+               usb_lld_reply_request (&neug_err_cnt_rc, sizeof (uint16_t), detail);
+             else if (detail->index == 3)
+               usb_lld_reply_request (&neug_err_cnt_p64, sizeof (uint16_t), detail);
+             else if (detail->index == 4)
+               usb_lld_reply_request (&neug_err_cnt_p4k, sizeof (uint16_t), detail);
+             else if (detail->index == 5)
+               usb_lld_reply_request (&neug_rc_max, sizeof (uint16_t), detail);
+             else if (detail->index == 6)
+               usb_lld_reply_request (&neug_p64_max, sizeof (uint16_t), detail);
+             else if (detail->index == 7)
+               usb_lld_reply_request (&neug_p4k_max, sizeof (uint16_t), detail);
              else
                return USB_UNSUPPORT;
 
@@ -414,7 +439,7 @@ usb_cb_setup (uint8_t req, uint8_t req_no,
        }
       else /* SETUP_SET */
        {
-         uint8_t *addr = (uint8_t *)(0x20000000 + value * 0x100 + index);
+         uint8_t *addr = (uint8_t *)(0x20000000 + detail->value * 0x100 + detail->index);
 
          if (req_no == USB_FSIJ_DOWNLOAD)
            {
@@ -426,16 +451,16 @@ usb_cb_setup (uint8_t req, uint8_t req_no,
                }
              chopstx_mutex_unlock (&usb_mtx);
 
-             if (addr < &_regnual_start || addr + len > &__heap_end__)
+             if (addr < &_regnual_start || addr + detail->len > &__heap_end__)
                return USB_UNSUPPORT;
 
-             if (index + len < 256)
-               memset (addr + index + len, 0, 256 - (index + len));
+             if (detail->index + detail->len < 256)
+               memset (addr + detail->index + detail->len, 0, 256 - (detail->index + detail->len));
 
-             usb_lld_set_data_to_recv (addr, len);
+             usb_lld_set_data_to_recv (addr, detail->len);
              return USB_SUCCESS;
            }
-         else if (req_no == USB_FSIJ_EXEC && len == 0)
+         else if (req_no == USB_FSIJ_EXEC && detail->len == 0)
            {
              chopstx_mutex_lock (&usb_mtx);
              if (fsij_device_state != FSIJ_DEVICE_EXITED)
@@ -450,13 +475,13 @@ usb_cb_setup (uint8_t req, uint8_t req_no,
 
              return download_check_crc32 ((uint32_t *)addr);
            }
-         else if (req_no == USB_NEUG_SET_PASSWD && len <= 32)
+         else if (req_no == USB_NEUG_SET_PASSWD && detail->len <= 32)
            {
-             passwd_data[0] = len;
-             usb_lld_set_data_to_recv (passwd_data + 1, len);
+             usbbuf[0] = detail->len;
+             usb_lld_set_data_to_recv (usbbuf + 1, detail->len);
              return USB_SUCCESS;
            }
-         else if (req_no == USB_NEUG_EXIT && len <= 32)
+         else if (req_no == USB_NEUG_EXIT && detail->len <= 32)
            {
              chopstx_mutex_lock (&usb_mtx);
              if (fsij_device_state != FSIJ_DEVICE_RUNNING)
@@ -466,25 +491,23 @@ usb_cb_setup (uint8_t req, uint8_t req_no,
                }
              chopstx_mutex_unlock (&usb_mtx);
 
-             passwd_data[0] = len;
-             usb_lld_set_data_to_recv (passwd_data + 1, len);
+             usbbuf[0] = detail->len;
+             usb_lld_set_data_to_recv (usbbuf + 1, detail->len);
              return USB_SUCCESS;
            }
        }
     }
-  else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT))
+  else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT)
+          && detail->index == 0)
     {
-      if (index == 0)
-       {
 #ifdef FRAUCHEKY_SUPPORT
-         if (running_neug)
-           return vcom_port_data_setup (req, req_no, value, len);
-         else
-           fraucheky_setup (req, req_no, value, len);
+      if (running_neug)
+       return vcom_port_data_setup (req, req_no, detail);
+      else
+       fraucheky_setup (req, req_no, detail);
 #else
-         return vcom_port_data_setup (req, req_no, value, len);
+      return vcom_port_data_setup (req, req_no, detail);
 #endif
-       }
     }
 
   return USB_UNSUPPORT;
@@ -492,29 +515,22 @@ usb_cb_setup (uint8_t req, uint8_t req_no,
 
 int
 usb_cb_get_descriptor (uint8_t rcp, uint8_t desc_type, uint8_t desc_index,
-                      uint16_t index)
+                      struct control_info *detail)
 {
 #ifdef FRAUCHEKY_SUPPORT
   if (!running_neug)
-    return fraucheky_get_descriptor (rcp, desc_type, desc_index, index);
-#else
-  (void)index;
+    return fraucheky_get_descriptor (rcp, desc_type, desc_index, detail);
 #endif
 
   if (rcp != DEVICE_RECIPIENT)
     return USB_UNSUPPORT;
 
   if (desc_type == DEVICE_DESCRIPTOR)
-    {
-      usb_lld_set_data_to_send (vcom_device_desc, sizeof (vcom_device_desc));
-      return USB_SUCCESS;
-    }
+    return usb_lld_reply_request (vcom_device_desc, sizeof (vcom_device_desc),
+                                 detail);
   else if (desc_type == CONFIG_DESCRIPTOR)
-    {
-      usb_lld_set_data_to_send (vcom_configuration_desc,
-                               sizeof (vcom_configuration_desc));
-      return USB_SUCCESS;
-    }
+    return usb_lld_reply_request (vcom_config_desc, sizeof (vcom_config_desc),
+                                 detail);
   else if (desc_type == STRING_DESCRIPTOR)
     {
       const uint8_t *str;
@@ -550,12 +566,28 @@ usb_cb_get_descriptor (uint8_t rcp, uint8_t desc_type, uint8_t desc_index,
          str = sys_version;
          size = sizeof (sys_version);
          break;
+       case 7:
+         {
+           int i;
+           str = usbbuf;
+           for (i = 0; i < (int)sizeof (usbbuf)/2 - 2; i++)
+             {
+               if (sys_board_name[i] == 0)
+                 break;
+
+               usbbuf[i*2+2] = sys_board_name[i];
+               usbbuf[i*2+3] = 0;
+             }
+           usbbuf[0] = i*2 + 2;
+           usbbuf[1] = USB_STRING_DESCRIPTOR_TYPE;
+           size = i*2 + 2;
+         }
+         break;
        default:
          return USB_UNSUPPORT;
        }
 
-      usb_lld_set_data_to_send (str, size);
-      return USB_SUCCESS;
+      return usb_lld_reply_request (str, size, detail);
     }
 
   return USB_UNSUPPORT;
@@ -648,9 +680,11 @@ int usb_cb_handle_event (uint8_t event_type, uint16_t value)
 }
 
 
-int usb_cb_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
+int usb_cb_interface (uint8_t cmd, struct control_info *detail)
 {
-  static uint8_t zero = 0;
+  const uint8_t zero = 0;
+  uint16_t interface = detail->index;
+  uint16_t alt = detail->value;
 
   if (interface >= NUM_INTERFACES)
     return USB_UNSUPPORT;
@@ -667,7 +701,7 @@ int usb_cb_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
        }
 
     case USB_GET_INTERFACE:
-      usb_lld_set_data_to_send (&zero, 1);
+      usb_lld_reply_request (&zero, 1, detail);
       return USB_SUCCESS;
 
     default:
@@ -685,7 +719,7 @@ usb_intr (void *arg)
   chopstx_intr_t interrupt;
 
   (void)arg;
-  usb_lld_init (vcom_configuration_desc[7]);
+  usb_lld_init (vcom_config_desc[7]);
   chopstx_claim_irq (&interrupt, INTR_REQ_USB);
   usb_interrupt_handler ();
 
@@ -814,8 +848,6 @@ led_blinker (void *arg)
       eventmask_t m;
 
       m = event_flag_waitone (&led_event, ALL_EVENTS);
-      if (fsij_device_state != FSIJ_DEVICE_RUNNING) /* No usb_mtx lock.  */
-       break;
 
       set_led (1);
       if (m == LED_ONESHOT_SHORT)
@@ -886,14 +918,14 @@ main (int argc, char **argv)
   chopstx_mutex_init (&usb_mtx);
   chopstx_cond_init (&cnd_usb);
 
-  led_thread = chopstx_create (PRIO_LED, __stackaddr_led, __stacksize_led,
-                              led_blinker, NULL);
-
 #ifdef FRAUCHEKY_SUPPORT
   if (fraucheky_enabled ())
     {
+    go_fraucheky:
+      running_neug = 0;
       usb_thd = chopstx_create (PRIO_USB, __stackaddr_usb, __stacksize_usb,
                                usb_intr, NULL);
+      set_led (1);
       fraucheky_main ();
       chopstx_cancel (usb_thd);
       chopstx_join (usb_thd, NULL);
@@ -903,6 +935,9 @@ main (int argc, char **argv)
   running_neug = 1;
 #endif
 
+  led_thread = chopstx_create (PRIO_LED, __stackaddr_led, __stacksize_led,
+                              led_blinker, NULL);
+
   usb_thd = chopstx_create (PRIO_USB, __stackaddr_usb, __stacksize_usb,
                            usb_intr, NULL);
 
@@ -1013,11 +1048,34 @@ main (int argc, char **argv)
   chopstx_join (led_thread, NULL);
 
   /*
-   * We come here, because of FSIJ_DEVICE_NEUG_EXIT_REQUESTED.
+   * We come here, because of FSIJ_DEVICE_NEUG_EXIT_REQUESTED
+   * or FSIJ_DEVICE_NEUG_FRAUCHEKY_REQUESTED.
    */
   neug_fini ();
 
   chopstx_mutex_lock (&usb_mtx);
+#ifdef FRAUCHEKY_SUPPORT
+  if (line_coding.bitrate == NEUG_SPECIAL_BITRATE)
+    {
+      while (fsij_device_state == FSIJ_DEVICE_NEUG_FRAUCHEKY_REQUESTED)
+       {
+         chopstx_mutex_unlock (&usb_mtx);
+         set_led (1);
+         chopstx_usec_wait (500*1000);
+         set_led (0);
+         chopstx_usec_wait (500*1000);
+         chopstx_mutex_lock (&usb_mtx);
+       }
+
+      usb_lld_prepare_shutdown ();
+      chopstx_mutex_unlock (&usb_mtx);
+      chopstx_cancel (usb_thd);
+      chopstx_join (usb_thd, NULL);
+      usb_lld_shutdown ();
+      goto go_fraucheky;
+    }
+#endif
+
   fsij_device_state = FSIJ_DEVICE_EXITED;
 
   while (fsij_device_state == FSIJ_DEVICE_EXITED)