Version 0.05
[gnuk/neug.git] / src / main.c
index 0499e24..1f2894c 100644 (file)
@@ -1,14 +1,11 @@
 /*
  * main.c - main routine of neug
  *
- * USB-CDC part:
- * ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,2011 Giovanni Di Sirio.
- *
  * Main routine:
- * Copyright (C) 2011 Free Software Initiative of Japan
+ * Copyright (C) 2011, 2012 Free Software Initiative of Japan
  * Author: NIIBE Yutaka <gniibe@fsij.org>
  *
- * This file is a part of NeuG, a Random Number Generator
+ * This file is a part of NeuG, a True Random Number Generator
  * implementation.
  *
  * NeuG is free software: you can redistribute it and/or modify it
@@ -16,7 +13,7 @@
  * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
  *
- * Gnuk is distributed in the hope that it will be useful, but WITHOUT
+ * NeuG is distributed in the hope that it will be useful, but WITHOUT
  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
  * License for more details.
  */
 
 #include "config.h"
-
 #include "ch.h"
 #include "hal.h"
 #include "board.h"
-#include "usb_cdc.h"
 #include "neug.h"
+#include "usb_lld.h"
+#include "sys.h"
+#include "adc.h"
 
 /*
  * We are trying to avoid dependency to C library. 
  * GCC built-in function(s) are declared here.
  */
-void *memcpy(void *dest, const void *src, size_t n);
+extern void *memcpy(void *dest, const void *src, size_t n);
+extern void *memset (void *s, int c, size_t n);
 
-\f
-/*
- * USB CDC stuff taken from ChibiOS/RT's testhal/STM32/USB_CDC/main.c,
- * and modified for NeuG.
- */
+static Thread *main_thread;
 
-/*
- * USB Driver structure.
- */
-static SerialUSBDriver SDU1;
-
-/*
- * USB Device Descriptor.
- */
-static const uint8_t vcom_device_descriptor_data[18] = {
-  USB_DESC_DEVICE       (0x0200,        /* bcdUSB (2.0).                    */
-                         0x02,          /* bDeviceClass (CDC).              */
-                         0x00,          /* bDeviceSubClass.                 */
-                         0x00,          /* bDeviceProtocol.                 */
-                         0x40,          /* bMaxPacketSize.                  */
-                         0x234b,        /* idVendor (FSIJ).                 */
-                         0x0001,        /* idProduct (NeoG).                */
-                         0x0100,        /* bcdDevice.                       */
-                         1,             /* iManufacturer.                   */
-                         2,             /* iProduct.                        */
-                         3,             /* iSerialNumber.                   */
-                         1)             /* bNumConfigurations.              */
-};
-
-/*
- * Device Descriptor wrapper.
- */
-static const USBDescriptor vcom_device_descriptor = {
-  sizeof vcom_device_descriptor_data,
-  vcom_device_descriptor_data
+\f
+#define ENDP0_RXADDR        (0x40)
+#define ENDP0_TXADDR        (0x80)
+#define ENDP1_TXADDR        (0xc0)
+#define ENDP2_TXADDR        (0x100)
+#define ENDP3_RXADDR        (0x140)
+
+#define USB_CDC_REQ_SET_LINE_CODING             0x20
+#define USB_CDC_REQ_GET_LINE_CODING             0x21
+#define USB_CDC_REQ_SET_CONTROL_LINE_STATE      0x22
+#define USB_CDC_REQ_SEND_BREAK                  0x23
+
+/* USB Device Descriptor */
+static const uint8_t vcom_device_desc[18] = {
+  18,   /* bLength */
+  USB_DEVICE_DESCRIPTOR_TYPE,  /* bDescriptorType */
+  0x10, 0x01,                  /* bcdUSB = 1.1 */
+  0x02,                                /* bDeviceClass (CDC).              */
+  0x00,                                /* bDeviceSubClass.                 */
+  0x00,                                /* bDeviceProtocol.                 */
+  0x40,                                /* bMaxPacketSize.                  */
+#include "usb-vid-pid-ver.c.inc"
+  1,                           /* iManufacturer.                   */
+  2,                           /* iProduct.                        */
+  3,                           /* iSerialNumber.                   */
+  1                            /* bNumConfigurations.              */
 };
 
 /* Configuration Descriptor tree for a CDC.*/
-static const uint8_t vcom_configuration_descriptor_data[67] = {
+static const uint8_t vcom_configuration_desc[67] = {
+  9,
+  USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
   /* Configuration Descriptor.*/
-  USB_DESC_CONFIGURATION(67,            /* wTotalLength.                    */
-                         0x02,          /* bNumInterfaces.                  */
-                         0x01,          /* bConfigurationValue.             */
-                         0,             /* iConfiguration.                  */
-                         0x80,          /* bmAttributes (bus powered).      */
-                         50),           /* bMaxPower (100mA).               */
+  67, 0x00,                    /* wTotalLength.                    */
+  0x02,                                /* bNumInterfaces.                  */
+  0x01,                                /* bConfigurationValue.             */
+  0,                           /* iConfiguration.                  */
+  0x80,                                /* bmAttributes (bus powered).      */
+  50,                          /* bMaxPower (100mA).               */
   /* Interface Descriptor.*/
-  USB_DESC_INTERFACE    (0x00,          /* bInterfaceNumber.                */
-                         0x00,          /* bAlternateSetting.               */
-                         0x01,          /* bNumEndpoints.                   */
-                         0x02,          /* bInterfaceClass (Communications
-                                           Interface Class, CDC section
-                                           4.2).                            */
-                         0x02,          /* bInterfaceSubClass (Abstract
-                                         Control Model, CDC section 4.3).   */
-                         0x01,          /* bInterfaceProtocol (AT commands,
-                                           CDC section 4.4).                */
-                         0),            /* iInterface.                      */
+  9,
+  USB_INTERFACE_DESCRIPTOR_TYPE,
+  0x00,                   /* bInterfaceNumber.                */
+  0x00,                   /* bAlternateSetting.               */
+  0x01,                   /* bNumEndpoints.                   */
+  0x02,                   /* bInterfaceClass (Communications Interface Class,
+                     CDC section 4.2).  */
+  0x02,                   /* bInterfaceSubClass (Abstract Control Model, CDC
+                     section 4.3).  */
+  0x01,                   /* bInterfaceProtocol (AT commands, CDC section
+                     4.4).  */
+  0,              /* iInterface.                      */
   /* Header Functional Descriptor (CDC section 5.2.3).*/
-  USB_DESC_BYTE         (5),            /* bLength.                         */
-  USB_DESC_BYTE         (0x24),         /* bDescriptorType (CS_INTERFACE).  */
-  USB_DESC_BYTE         (0x00),         /* bDescriptorSubtype (Header
-                                           Functional Descriptor.           */
-  USB_DESC_BCD          (0x0110),       /* bcdCDC.                          */
+  5,         /* bLength.                         */
+  0x24,              /* bDescriptorType (CS_INTERFACE).  */
+  0x00,              /* bDescriptorSubtype (Header Functional Descriptor). */
+  0x10, 0x01, /* bcdCDC.                          */
   /* Call Management Functional Descriptor. */
-  USB_DESC_BYTE         (5),            /* bFunctionLength.                 */
-  USB_DESC_BYTE         (0x24),         /* bDescriptorType (CS_INTERFACE).  */
-  USB_DESC_BYTE         (0x01),         /* bDescriptorSubtype (Call Management
-                                           Functional Descriptor).          */
-  USB_DESC_BYTE         (0x03),         /* bmCapabilities (D0+D1).          */
-  USB_DESC_BYTE         (0x01),         /* bDataInterface.                  */
+  5,            /* bFunctionLength.                 */
+  0x24,         /* bDescriptorType (CS_INTERFACE).  */
+  0x01,         /* bDescriptorSubtype (Call Management Functional
+                  Descriptor). */
+  0x03,         /* bmCapabilities (D0+D1).          */
+  0x01,         /* bDataInterface.                  */
   /* ACM Functional Descriptor.*/
-  USB_DESC_BYTE         (4),            /* bFunctionLength.                 */
-  USB_DESC_BYTE         (0x24),         /* bDescriptorType (CS_INTERFACE).  */
-  USB_DESC_BYTE         (0x02),         /* bDescriptorSubtype (Abstract
-                                           Control Management Descriptor).  */
-  USB_DESC_BYTE         (0x02),         /* bmCapabilities.                  */
+  4,            /* bFunctionLength.                 */
+  0x24,         /* bDescriptorType (CS_INTERFACE).  */
+  0x02,         /* bDescriptorSubtype (Abstract Control Management
+                  Descriptor).  */
+  0x02,         /* bmCapabilities.                  */
   /* Union Functional Descriptor.*/
-  USB_DESC_BYTE         (5),            /* bFunctionLength.                 */
-  USB_DESC_BYTE         (0x24),         /* bDescriptorType (CS_INTERFACE).  */
-  USB_DESC_BYTE         (0x06),         /* bDescriptorSubtype (Union
-                                           Functional Descriptor).          */
-  USB_DESC_BYTE         (0x00),         /* bMasterInterface (Communication
-                                           Class Interface).                */
-  USB_DESC_BYTE         (0x01),         /* bSlaveInterface0 (Data Class
-                                           Interface).                      */
+  5,            /* bFunctionLength.                 */
+  0x24,         /* bDescriptorType (CS_INTERFACE).  */
+  0x06,         /* bDescriptorSubtype (Union Functional
+                  Descriptor).  */
+  0x00,         /* bMasterInterface (Communication Class
+                  Interface).  */
+  0x01,         /* bSlaveInterface0 (Data Class Interface).  */
   /* Endpoint 2 Descriptor.*/
-  USB_DESC_ENDPOINT     (INTERRUPT_REQUEST_EP|0x80, /* bEndpointAddress.    */
-                         0x03,          /* bmAttributes (Interrupt).        */
-                         0x0008,        /* wMaxPacketSize.                  */
-                         0xFF),         /* bInterval.                       */
+  7,
+  USB_ENDPOINT_DESCRIPTOR_TYPE,
+  ENDP2|0x80,    /* bEndpointAddress.    */
+  0x03,          /* bmAttributes (Interrupt).        */
+  0x08, 0x00,   /* wMaxPacketSize.                  */
+  0xFF,                 /* bInterval.                       */
   /* Interface Descriptor.*/
-  USB_DESC_INTERFACE    (0x01,          /* bInterfaceNumber.                */
-                         0x00,          /* bAlternateSetting.               */
-                         0x02,          /* bNumEndpoints.                   */
-                         0x0A,          /* bInterfaceClass (Data Class
-                                           Interface, CDC section 4.5).     */
-                         0x00,          /* bInterfaceSubClass (CDC section
-                                           4.6).                            */
-                         0x00,          /* bInterfaceProtocol (CDC section
-                                           4.7).                            */
-                         0x00),         /* iInterface.                      */
+  9,
+  USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: */
+  0x01,          /* bInterfaceNumber.                */
+  0x00,          /* bAlternateSetting.               */
+  0x02,          /* bNumEndpoints.                   */
+  0x0A,          /* bInterfaceClass (Data Class Interface, CDC section 4.5). */
+  0x00,          /* bInterfaceSubClass (CDC section 4.6). */
+  0x00,          /* bInterfaceProtocol (CDC section 4.7). */
+  0x00,                 /* iInterface.                      */
   /* Endpoint 3 Descriptor.*/
-  USB_DESC_ENDPOINT     (DATA_AVAILABLE_EP,         /* bEndpointAddress.    */
-                         0x02,          /* bmAttributes (Bulk).             */
-                         0x0040,        /* wMaxPacketSize.                  */
-                         0x00),         /* bInterval.                       */
+  7,
+  USB_ENDPOINT_DESCRIPTOR_TYPE,        /* bDescriptorType: Endpoint */
+  ENDP3,    /* bEndpointAddress. */
+  0x02,                                /* bmAttributes (Bulk).             */
+  0x40, 0x00,                  /* wMaxPacketSize.                  */
+  0x00,                                /* bInterval.                       */
   /* Endpoint 1 Descriptor.*/
-  USB_DESC_ENDPOINT     (DATA_REQUEST_EP|0x80,      /* bEndpointAddress.    */
-                         0x02,          /* bmAttributes (Bulk).             */
-                         0x0040,        /* wMaxPacketSize.                  */
-                         0x00)          /* bInterval.                       */
+  7,
+  USB_ENDPOINT_DESCRIPTOR_TYPE,        /* bDescriptorType: Endpoint */
+  ENDP1|0x80,                  /* bEndpointAddress. */
+  0x02,                                /* bmAttributes (Bulk).             */
+  0x40, 0x00,                  /* wMaxPacketSize.                  */
+  0x00                         /* bInterval.                       */
 };
 
 
-/*
- * Configuration Descriptor wrapper.
- */
-static const USBDescriptor vcom_configuration_descriptor = {
-  sizeof vcom_configuration_descriptor_data,
-  vcom_configuration_descriptor_data
-};
-
 /*
  * U.S. English language identifier.
  */
-static const uint8_t vcom_string0[] = {
-  USB_DESC_BYTE(4),                     /* bLength.                         */
-  USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType.                 */
-  USB_DESC_WORD(0x0409)                 /* wLANGID (U.S. English).          */
+static const uint8_t vcom_string0[4] = {
+  4,                           /* bLength */
+  USB_STRING_DESCRIPTOR_TYPE,
+  0x09, 0x04                   /* LangID = 0x0409: US-English */
 };
 
+#define USB_STRINGS_FOR_NEUG 1
+#include "usb-strings.c.inc"
+
 /*
- * Vendor string.
+ * Serial Number string.  NOTE: This does not have CONST qualifier.
  */
-static const uint8_t vcom_string1[] = {
-  USB_DESC_BYTE(68),                    /* bLength.                         */
-  USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType.                 */
-  /* Manufacturer: "Free Software Initiative of Japan" */
-  'F', 0, 'r', 0, 'e', 0, 'e', 0, ' ', 0, 'S', 0, 'o', 0, 'f', 0,
-  't', 0, 'w', 0, 'a', 0, 'r', 0, 'e', 0, ' ', 0, 'I', 0, 'n', 0,
-  'i', 0, 't', 0, 'i', 0, 'a', 0, 't', 0, 'i', 0, 'v', 0, 'e', 0,
-  ' ', 0, 'o', 0, 'f', 0, ' ', 0, 'J', 0, 'a', 0, 'p', 0, 'a', 0,
-  'n', 0
+static uint8_t vcom_string3[28] = {
+  28,                    /* bLength.                         */
+  USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType.                 */
+  '0', 0,  '.', 0,  '0', 0, '5', 0,    /* Version number of NeuG.          */
+  '-', 0,
+  0, 0, 0, 0,  /* Filled by Unique device ID.      */
+  0, 0, 0, 0,
+  0, 0, 0, 0,
+  0, 0, 0, 0,
 };
 
-/*
- * Device Description string.
- */
-static const uint8_t vcom_string2[] = {
-  USB_DESC_BYTE(18),                    /* bLength.                         */
-  USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType.                 */
-  /* Product name: "NeuG RNG" */
-  'N', 0, 'e', 0, 'u', 0, 'G', 0, ' ', 0, 'R', 0, 'N', 0, 'G', 0,
+static const struct Descriptor device_desc = {
+  vcom_device_desc,
+  sizeof (vcom_device_desc)
 };
 
-/*
- * Serial Number string.  NOTE: This does not have CONST qualifier.
- */
-static uint8_t vcom_string3[] = {
-  USB_DESC_BYTE(28),                    /* bLength.                         */
-  USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType.                 */
-  '0', 0,  '.', 0,  '0', 0,  '0', 0,    /* Version number of NeuG.          */
-  '-', 0,
-  0, 0, 0, 0, 0, 0, 0, 0,              /* Filled by Unique device ID.      */
-  0, 0, 0, 0, 0, 0, 0, 0,
+static const struct Descriptor config_desc = {
+  vcom_configuration_desc,
+  sizeof (vcom_configuration_desc)
 };
 
-/*
- * Strings wrappers array.
- */
-static const USBDescriptor vcom_strings[] = {
-  {sizeof vcom_string0, vcom_string0},
-  {sizeof vcom_string1, vcom_string1},
-  {sizeof vcom_string2, vcom_string2},
-  {sizeof vcom_string3, vcom_string3}
+static const struct Descriptor string_descs[] = {
+  {vcom_string0, sizeof vcom_string0},
+  {neug_string_vendor, sizeof (neug_string_vendor)},
+  {neug_string_product, sizeof (neug_string_product)},
+  {vcom_string3, sizeof (vcom_string3)},
+  {neug_revision_detail, sizeof (neug_revision_detail)},
+  {neug_config_options, sizeof (neug_config_options)},
+  {sys_version, sizeof (sys_version)},
 };
 
-/*
- * Handles the GET_DESCRIPTOR callback. All required descriptors must be
- * handled here.
- */
-static const USBDescriptor *get_descriptor(USBDriver *usbp,
-                                           uint8_t dtype,
-                                           uint8_t dindex,
-                                           uint16_t lang) {
-
-  (void)usbp;
-  (void)lang;
-  switch (dtype) {
-  case USB_DESCRIPTOR_DEVICE:
-    return &vcom_device_descriptor;
-  case USB_DESCRIPTOR_CONFIGURATION:
-    return &vcom_configuration_descriptor;
-  case USB_DESCRIPTOR_STRING:
-    if (dindex < 4)
-      return &vcom_strings[dindex];
-  }
-  return NULL;
+#define NUM_STRING_DESC (sizeof (string_descs)/sizeof (struct Descriptor))
+
+#define NUM_INTERFACES 2
+
+uint32_t bDeviceState = UNCONNECTED; /* USB device status */
+
+static void
+neug_device_reset (void)
+{
+  /* Set DEVICE as not configured */
+  usb_lld_set_configuration (0);
+
+  /* Current Feature initialization */
+  usb_lld_set_feature (config_desc.Descriptor[7]);
+
+  usb_lld_reset ();
+
+  /* Initialize Endpoint 0 */
+  usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR, 64);
 }
 
-/**
- * @brief   EP1 initialization structure (IN only).
- */
-static const USBEndpointConfig ep1config = {
-  USB_EP_MODE_TYPE_BULK | USB_EP_MODE_PACKET,
-  NULL,
-  sduDataTransmitted,
-  NULL,
-  0x0040,
-  0x0000,
-  NULL,
-  NULL
-};
+extern uint8_t _regnual_start, __heap_end__;
 
-/**
- * @brief   EP2 initialization structure (IN only).
- */
-static const USBEndpointConfig ep2config = {
-  USB_EP_MODE_TYPE_INTR | USB_EP_MODE_PACKET,
-  NULL,
-  sduInterruptTransmitted,
-  NULL,
-  0x0010,
-  0x0000,
-  NULL,
-  NULL
+static const uint8_t *const mem_info[] = { &_regnual_start,  &__heap_end__, };
+
+/* USB vendor requests to control pipe */
+#define USB_FSIJ_MEMINFO         0
+#define USB_FSIJ_DOWNLOAD        1
+#define USB_FSIJ_EXEC            2
+#define USB_NEUG_GET_INFO      254
+#define USB_NEUG_EXIT          255 /* Ask to exit and to receive reGNUal */
+
+enum {
+  FSIJ_DEVICE_RUNNING = 0,
+  FSIJ_DEVICE_EXITED,
+  FSIJ_DEVICE_EXEC_REQUESTED,
+  /**/
+  FSIJ_DEVICE_NEUG_EXIT_REQUESTED = 255
+}; 
+
+static uint8_t fsij_device_state = FSIJ_DEVICE_RUNNING;
+
+static uint32_t rbit (uint32_t v)
+{
+  uint32_t r;
+
+  asm ("rbit   %0, %1" : "=r" (r) : "r" (v));
+  return r;
+}
+
+/* After calling this function, CRC module remain enabled.  */
+static int download_check_crc32 (const uint32_t *end_p)
+{
+  uint32_t crc32 = *end_p;
+  const uint32_t *p;
+
+  RCC->AHBENR |= RCC_AHBENR_CRCEN;
+  CRC->CR = CRC_CR_RESET;
+
+  for (p = (const uint32_t *)&_regnual_start; p < end_p; p++)
+    CRC->DR = rbit (*p);
+
+  if ((rbit (CRC->DR) ^ crc32) == 0xffffffff)
+    return USB_SUCCESS;
+
+  return USB_UNSUPPORT;
+}
+
+static void neug_ctrl_write_finish (uint8_t req, uint8_t req_no,
+                                   uint16_t value, uint16_t index,
+                                   uint16_t len)
+{
+  uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
+
+  if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT)
+      && USB_SETUP_SET (req) && len == 0)
+    {
+      if (req_no == USB_FSIJ_EXEC)
+       {
+         if (fsij_device_state != FSIJ_DEVICE_EXITED)
+           return;
+
+         (void)value; (void)index;
+         usb_lld_prepare_shutdown (); /* No further USB communication */
+         fsij_device_state = FSIJ_DEVICE_EXEC_REQUESTED;
+       }
+      else if (req_no == USB_NEUG_EXIT)
+       {
+         chSysLockFromIsr ();
+         if (main_thread->p_state == THD_STATE_SUSPENDED
+             || main_thread->p_state == THD_STATE_SLEEPING)
+           {
+             main_thread->p_u.rdymsg = RDY_OK;
+             chSchReadyI (main_thread);
+           }
+         chSysUnlockFromIsr ();
+       }
+    }
+}
+
+struct line_coding
+{
+  uint32_t bitrate;
+  uint8_t format;
+  uint8_t paritytype;
+  uint8_t datatype;
 };
 
-/**
- * @brief   EP3 initialization structure (OUT only).
- */
-static const USBEndpointConfig ep3config = {
-  USB_EP_MODE_TYPE_BULK | USB_EP_MODE_PACKET,
-  NULL,
-  NULL,
-  sduDataReceived,
-  0x0000,
-  0x0040,
-  NULL,
-  NULL
+static struct line_coding line_coding = {
+  115200, /* baud rate: 115200    */
+  0x00,   /* stop bits: 1         */
+  0x00,   /* parity:    none      */
+  0x08    /* bits:      8         */
 };
 
-/*
- * Handles the USB driver global events.
- */
-static void usb_event(USBDriver *usbp, usbevent_t event) {
-
-  switch (event) {
-  case USB_EVENT_RESET:
-    return;
-  case USB_EVENT_ADDRESS:
-    return;
-  case USB_EVENT_CONFIGURED:
-    /* Enables the endpoints specified into the configuration.
-       Note, this callback is invoked from an ISR so I-Class functions
-       must be used.*/
-    chSysLockFromIsr();
-    usbInitEndpointI(usbp, DATA_REQUEST_EP, &ep1config);
-    usbInitEndpointI(usbp, INTERRUPT_REQUEST_EP, &ep2config);
-    usbInitEndpointI(usbp, DATA_AVAILABLE_EP, &ep3config);
-    chSysUnlockFromIsr();
-    return;
-  case USB_EVENT_SUSPEND:
-    return;
-  case USB_EVENT_WAKEUP:
-    return;
-  case USB_EVENT_STALLED:
-    return;
-  }
-  return;
+static uint8_t connected;
+
+static int
+vcom_port_data_setup (uint8_t req, uint8_t req_no, uint16_t value)
+{
+  if (USB_SETUP_GET (req))
+    {
+      if (req_no == USB_CDC_REQ_GET_LINE_CODING)
+       {
+         usb_lld_set_data_to_send (&line_coding, sizeof(line_coding));
+         return USB_SUCCESS;
+       }
+    }
+  else  /* USB_SETUP_SET (req) */
+    {
+      if (req_no == USB_CDC_REQ_SET_LINE_CODING)
+       {
+         usb_lld_set_data_to_recv (&line_coding, sizeof(line_coding));
+         return USB_SUCCESS;
+       }
+      else if (req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
+       {
+         uint8_t connected_saved = connected;
+
+         if (value != 0)
+           {
+             if (connected == 0)
+               /* It's Open call */
+               connected++;
+           }
+         else
+           {
+             if (connected)
+               /* Close call */
+               connected = 0;
+           }
+
+         if (connected != connected_saved)
+           {
+             chSysLockFromIsr ();
+             if (main_thread->p_state == THD_STATE_SUSPENDED
+                 || main_thread->p_state == THD_STATE_SLEEPING)
+               {
+                 main_thread->p_u.rdymsg = RDY_OK;
+                 chSchReadyI (main_thread);
+               }
+             chSysUnlockFromIsr ();
+           }
+
+         return USB_SUCCESS;
+       }
+    }
+
+  return USB_UNSUPPORT;
 }
 
+static int
+neug_setup (uint8_t req, uint8_t req_no,
+              uint16_t value, uint16_t index, uint16_t len)
+{
+  uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
 
-/*
- * Serial over USB driver configuration.
- */
-static const SerialUSBConfig serusbcfg = {
-  &USBD1,
-  {
-    usb_event,
-    get_descriptor,
-    sduRequestsHook,
-    NULL
-  }
+  if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
+    {
+      if (USB_SETUP_GET (req))
+       {
+         if (req_no == USB_FSIJ_MEMINFO)
+           {
+             usb_lld_set_data_to_send (mem_info, sizeof (mem_info));
+             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));
+             else
+               return USB_UNSUPPORT;
+
+             return USB_SUCCESS;
+           }
+       }
+      else /* SETUP_SET */
+       {
+         uint8_t *addr = (uint8_t *)(0x20000000 + value * 0x100 + index);
+
+         if (req_no == USB_FSIJ_DOWNLOAD)
+           {
+             if (fsij_device_state != FSIJ_DEVICE_EXITED)
+               return USB_UNSUPPORT;
+
+             if (addr < &_regnual_start || addr + len > &__heap_end__)
+               return USB_UNSUPPORT;
+
+             if (index + len < 256)
+               memset (addr + index + len, 0, 256 - (index + len));
+
+             usb_lld_set_data_to_recv (addr, len);
+             return USB_SUCCESS;
+           }
+         else if (req_no == USB_FSIJ_EXEC && len == 0)
+           {
+             if (fsij_device_state != FSIJ_DEVICE_EXITED)
+               return USB_UNSUPPORT;
+
+             if (((uint32_t)addr & 0x03))
+               return USB_UNSUPPORT;
+
+             return download_check_crc32 ((uint32_t *)addr);
+           }
+         else if (req_no == USB_NEUG_EXIT && len == 0)
+           {
+             if (fsij_device_state != FSIJ_DEVICE_RUNNING)
+               return USB_UNSUPPORT;
+
+             fsij_device_state = FSIJ_DEVICE_NEUG_EXIT_REQUESTED;
+             return USB_SUCCESS;
+           }
+       }
+    }
+  else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT))
+    if (index == 0)
+      return vcom_port_data_setup (req, req_no, value);
+
+  return USB_UNSUPPORT;
+}
+
+static int
+neug_get_descriptor (uint8_t desc_type, uint16_t index, uint16_t value)
+{
+  (void)index;
+  if (desc_type == DEVICE_DESCRIPTOR)
+    {
+      usb_lld_set_data_to_send (device_desc.Descriptor,
+                               device_desc.Descriptor_Size);
+      return USB_SUCCESS;
+    }
+  else if (desc_type == CONFIG_DESCRIPTOR)
+    {
+      usb_lld_set_data_to_send (config_desc.Descriptor,
+                               config_desc.Descriptor_Size);
+      return USB_SUCCESS;
+    }
+  else if (desc_type == STRING_DESCRIPTOR)
+    {
+      uint8_t desc_index = value & 0xff;
+
+      if (desc_index < NUM_STRING_DESC)
+       {
+         usb_lld_set_data_to_send (string_descs[desc_index].Descriptor,
+                                   string_descs[desc_index].Descriptor_Size);
+         return USB_SUCCESS;
+       }
+    }
+
+  return USB_UNSUPPORT;
+}
+
+static void
+neug_setup_endpoints_for_interface (uint16_t interface, int stop)
+{
+  if (interface == 0)
+    {
+      if (!stop)
+       usb_lld_setup_endpoint (ENDP2, EP_INTERRUPT, 0, 0, ENDP2_TXADDR, 0);
+      else
+       usb_lld_stall_tx (ENDP2);
+    }
+  else if (interface == 1)
+    {
+      if (!stop)
+       {
+         usb_lld_setup_endpoint (ENDP1, EP_BULK, 0, 0, ENDP1_TXADDR, 0);
+         usb_lld_setup_endpoint (ENDP3, EP_BULK, 0, ENDP3_RXADDR, 0, 64);
+       }
+      else
+       {
+         usb_lld_stall_tx (ENDP1);
+         usb_lld_stall_rx (ENDP3);
+       }
+    }
+}
+
+static int neug_usb_event (uint8_t event_type, uint16_t value)
+{
+  int i;
+  uint8_t current_conf;
+
+  switch (event_type)
+    {
+    case USB_EVENT_ADDRESS:
+      bDeviceState = ADDRESSED;
+      return USB_SUCCESS;
+    case USB_EVENT_CONFIG:
+      current_conf = usb_lld_current_configuration ();
+      if (current_conf == 0)
+       {
+         if (value != 1)
+           return USB_UNSUPPORT;
+
+         usb_lld_set_configuration (1);
+         for (i = 0; i < NUM_INTERFACES; i++)
+           neug_setup_endpoints_for_interface (i, 0);
+         bDeviceState = CONFIGURED;
+       }
+      else if (current_conf != value)
+       {
+         if (value != 0)
+           return USB_UNSUPPORT;
+
+         usb_lld_set_configuration (0);
+         for (i = 0; i < NUM_INTERFACES; i++)
+           neug_setup_endpoints_for_interface (i, 1);
+         bDeviceState = ADDRESSED;
+       }
+      /* Do nothing when current_conf == value */
+      return USB_SUCCESS;
+
+      return USB_SUCCESS;
+    default:
+      break;
+    }
+
+  return USB_UNSUPPORT;
+}
+
+
+static int neug_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
+{
+  static uint8_t zero = 0;
+
+  if (interface >= NUM_INTERFACES)
+    return USB_UNSUPPORT;
+
+  switch (cmd)
+    {
+    case USB_SET_INTERFACE:
+      if (alt != 0)
+       return USB_UNSUPPORT;
+      else
+       {
+         neug_setup_endpoints_for_interface (interface, 0);
+         return USB_SUCCESS;
+       }
+
+    case USB_GET_INTERFACE:
+      usb_lld_set_data_to_send (&zero, 1);
+      return USB_SUCCESS;
+
+    default:
+    case USB_QUERY_INTERFACE:
+      return USB_SUCCESS;
+    }
+}
+
+const struct usb_device_method Device_Method = {
+  neug_device_reset,
+  neug_ctrl_write_finish,
+  neug_setup,
+  neug_get_descriptor,
+  neug_usb_event,
+  neug_interface,
 };
 
+
+
 static void fill_serial_no_by_unique_id (void)
 {
   extern const uint8_t * unique_device_id (void);
@@ -348,9 +614,41 @@ static void fill_serial_no_by_unique_id (void)
     }
 }
 \f
+CH_IRQ_HANDLER (Vector90)
+{
+  CH_IRQ_PROLOGUE();
+  usb_interrupt_handler ();
+  CH_IRQ_EPILOGUE();
+}
+
+void
+EP1_IN_Callback (void)
+{
+  chSysLockFromIsr ();
+  if (main_thread->p_state == THD_STATE_SUSPENDED)
+    {
+      main_thread->p_u.rdymsg = RDY_OK;
+      chSchReadyI (main_thread);
+    }
+  chSysUnlockFromIsr ();
+}
+
+void
+EP2_IN_Callback (void)
+{
+}
+
+void
+EP3_OUT_Callback (void)
+{
+  usb_lld_rx_enable (ENDP3);
+}
+\f
 static WORKING_AREA(wa_led, 64);
 
-#define LED_ONESHOT ((eventmask_t)1)
+#define LED_ONESHOT_SHORT      ((eventmask_t)1)
+#define LED_TWOSHOTS           ((eventmask_t)2)
+#define LED_ONESHOT_LONG       ((eventmask_t)4)
 static Thread *led_thread;
 
 /*
@@ -365,18 +663,39 @@ static msg_t led_blinker (void *arg)
 
   while (1)
     {
-      chEvtWaitOne (LED_ONESHOT);
+      eventmask_t m;
+
+      m = chEvtWaitOne (ALL_EVENTS);
+      if (fsij_device_state != FSIJ_DEVICE_RUNNING)
+       break;
+
       set_led (1);
-      chThdSleep (MS2ST (100));
+      if (m == LED_ONESHOT_SHORT)
+       chThdSleepMilliseconds (100);
+      else if (m == LED_TWOSHOTS)
+       {
+         chThdSleepMilliseconds (50);
+         set_led (0);
+         chThdSleepMilliseconds (50);
+         set_led (1);
+         chThdSleepMilliseconds (50);
+       }
+      else
+       chThdSleepMilliseconds (250);
       set_led (0);
     }
 
   return 0;
 }
 \f
-#define RANDOM_BYTES_LENGTH 32
+#define RANDOM_BYTES_LENGTH 64
 static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)];
 
+static void copy_to_tx (uint32_t v, int i)
+{
+  usb_lld_txcpy (&v, ENDP1, i * 4, 4);
+}
+
 /*
  * Entry point.
  *
@@ -385,62 +704,158 @@ static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)];
 int
 main (int argc, char **argv)
 {
-  unsigned int count = 0;
-
   (void)argc;
   (void)argv;
 
   fill_serial_no_by_unique_id ();
 
-  halInit();
-  chSysInit();
+  halInit ();
+  adc_init ();
+  chSysInit ();
 
-  /*
-   * Activates the USB driver and then the USB bus pull-up on D+.
-   */
-  sduObjectInit(&SDU1);
-  sduStart(&SDU1, &serusbcfg);
-  USB_Cable_Config (ENABLE);
+  main_thread = chThdSelf ();
 
   chThdCreateStatic (wa_led, sizeof (wa_led), NORMALPRIO, led_blinker, NULL);
 
   neug_init (random_word, RANDOM_BYTES_LENGTH/sizeof (uint32_t));
 
+  usb_lld_init (config_desc.Descriptor[7]);
+
   while (1)
     {
-      uint32_t v;
-      const uint8_t *s = (const uint8_t *)&v;
+      unsigned int count = 0;
+      int last_was_fullsizepacket = 0;
+
+      if (fsij_device_state != FSIJ_DEVICE_RUNNING)
+       break;
 
-      while (count < NEUG_PRE_LOOP || SDU1.config->usbp->state != USB_ACTIVE)
+      while (count < NEUG_PRE_LOOP || bDeviceState != CONFIGURED)
        {
-         v = neug_get (NEUG_KICK_FILLING);
-         if ((count & 0x000f) == 0)
-           chEvtSignalFlags (led_thread, LED_ONESHOT);
-         chThdSleep (MS2ST (25));
+         if (fsij_device_state != FSIJ_DEVICE_RUNNING)
+           break;
+
+         neug_wait_full ();
+         neug_flush ();
+
+         if ((count & 0x0007) == 0)
+           chEvtSignalFlags (led_thread, LED_ONESHOT_SHORT);
+         chThdSleepMilliseconds (25);
          count++;
        }
 
+    waiting_connection:
+      while (connected == 0)
+       {
+         if (fsij_device_state != FSIJ_DEVICE_RUNNING)
+           break;
+
+         neug_flush ();
+         chEvtSignalFlags (led_thread, LED_TWOSHOTS);
+         chThdSleepMilliseconds (5000);
+       }
+
+      if (fsij_device_state != FSIJ_DEVICE_RUNNING)
+       break;
+
+      /* The connection opened.  */
       count = 0;
-      neug_prng_reseed ();
+      /*
+       * No parity is standard.  It means to provide conditioned output.
+       * When parity enabled, it means to provide raw output.
+       */
+      neug_mode_select (line_coding.paritytype); /* 0: None, 1: Odd, 2: Even */
 
       while (1)
        {
-         count++;
+         int i;
 
-         if (SDU1.config->usbp->state != USB_ACTIVE)
+         if (fsij_device_state != FSIJ_DEVICE_RUNNING)
            break;
 
-         v = neug_get (NEUG_KICK_FILLING);
+         if (bDeviceState != CONFIGURED)
+           break;
+
+         if ((count & 0x03ff) == 0)
+           chEvtSignalFlags (led_thread, LED_ONESHOT_SHORT);
+
+         i = neug_consume_random (copy_to_tx);
+
+         if (i == 0 && !last_was_fullsizepacket)
+           {    /* Only send ZLP when the last packet was fullsize.  */
+             neug_wait_full ();
+             continue;
+           }
+
+         if (i == 64/4)
+           last_was_fullsizepacket = 1;
+         else
+           last_was_fullsizepacket = 0;
+
+         chSysLock ();
+         if (connected == 0)
+           {
+             chSysUnlock();
+             goto waiting_connection;
+           }
+         else
+           {
+             usb_lld_tx_enable (ENDP1, i * 4);
+             chSchGoSleepS (THD_STATE_SUSPENDED);
+           }
+         chSysUnlock ();
 
-         if ((count & 0x07ff) == 0)
-           chEvtSignalFlags (led_thread, LED_ONESHOT);
-         /*
-          * Ignore input, just in case /dev/ttyACM0 echos our output
-          */
-         chIQResetI (&(SDU1.iqueue));
-         chIOWriteTimeout (&SDU1, s, sizeof (v), TIME_INFINITE);
+         count++;
        }
     }
 
+  chEvtSignalFlags (led_thread, LED_ONESHOT_SHORT);
+  chThdWait (led_thread);
+
+  /*
+   * We come here, because of FSIJ_DEVICE_NEUG_EXIT_REQUESTED.
+   */
+  neug_fini ();
+
+  fsij_device_state = FSIJ_DEVICE_EXITED;
+
+  while (fsij_device_state == FSIJ_DEVICE_EXITED)
+    chThdSleepMilliseconds (500);
+
+  flash_unlock ();             /* Flash unlock should be done here */
+  set_led (1);
+  usb_lld_shutdown ();
+  /* Disable SysTick */
+  SysTick->CTRL = 0;
+  /* Disable all interrupts */
+  port_disable ();
+  /* Set vector */
+  SCB->VTOR = (uint32_t)&_regnual_start;
+#ifdef DFU_SUPPORT
+#define FLASH_SYS_START_ADDR 0x08000000
+#define FLASH_SYS_END_ADDR (0x08000000+0x1000)
+  {
+    extern uint8_t _sys;
+    uint32_t addr;
+    handler *new_vector = (handler *)FLASH_SYS_START_ADDR;
+    void (*func) (void (*)(void)) = (void (*)(void (*)(void)))new_vector[10];
+
+    /* Kill DFU */
+    for (addr = FLASH_SYS_START_ADDR; addr < FLASH_SYS_END_ADDR;
+        addr += FLASH_PAGE_SIZE)
+      flash_erase_page (addr);
+
+    /* copy system service routines */
+    flash_write (FLASH_SYS_START_ADDR, &_sys, 0x1000);
+
+    /* Leave NeuG to exec reGNUal */
+    (*func) (*((void (**)(void))(&_regnual_start+4)));
+    for (;;);
+  }
+#else
+  /* Leave NeuG to exec reGNUal */
+  flash_erase_all_and_exec (*((void (**)(void))(&_regnual_start+4)));
+#endif
+
+  /* Never reached */
   return 0;
 }