Update main.c for GNU/Linux emulation.
[gnuk/neug.git] / src / main.c
index 9b90fa5..f8a1e8d 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, 2016, 2017
+ *              Free Software Initiative of Japan
  * Author: NIIBE Yutaka <gniibe@fsij.org>
  *
  * This file is a part of NeuG, a True Random Number Generator
@@ -32,7 +33,9 @@
 #include "neug.h"
 #include "usb_lld.h"
 #include "sys.h"
-#include "stm32f103.h"
+#ifndef GNU_LINUX_EMULATION
+#include "mcu/stm32f103.h"
+#endif
 #include "adc.h"
 
 enum {
@@ -40,24 +43,23 @@ enum {
   FSIJ_DEVICE_EXITED,
   FSIJ_DEVICE_EXEC_REQUESTED,
   /**/
+  FSIJ_DEVICE_NEUG_FRAUCHEKY_REQUESTED = 254,
   FSIJ_DEVICE_NEUG_EXIT_REQUESTED = 255
-}; 
+};
 
 #ifdef FRAUCHEKY_SUPPORT
 static uint8_t running_neug;
+extern void EP6_IN_Callback (uint16_t len);
+extern void EP6_OUT_Callback (uint16_t len);
 #endif
 
 static chopstx_mutex_t usb_mtx;
-static chopstx_cond_t cnd_usb;
+static chopstx_cond_t usb_cnd;
 static uint32_t bDeviceState = UNCONNECTED; /* USB device status */
 static uint8_t fsij_device_state = FSIJ_DEVICE_RUNNING;
 static uint8_t connected;
-static uint32_t wait_usb_connection; /* Timer variable.  */
 
 
-extern uint8_t __process0_stack_end__;
-static chopstx_t main_thd = (uint32_t)(&__process0_stack_end__ - 60);
-
 #define ENDP0_RXADDR        (0x40)
 #define ENDP0_TXADDR        (0x80)
 #define ENDP1_TXADDR        (0xc0)
@@ -72,7 +74,7 @@ static chopstx_t main_thd = (uint32_t)(&__process0_stack_end__ - 60);
 /* USB Device Descriptor */
 static const uint8_t vcom_device_desc[18] = {
   18,   /* bLength */
-  USB_DEVICE_DESCRIPTOR_TYPE,  /* bDescriptorType */
+  DEVICE_DESCRIPTOR,           /* bDescriptorType */
   0x10, 0x01,                  /* bcdUSB = 1.1 */
   0x02,                                /* bDeviceClass (CDC).              */
   0x00,                                /* bDeviceSubClass.                 */
@@ -85,20 +87,22 @@ static const uint8_t vcom_device_desc[18] = {
   1                            /* bNumConfigurations.              */
 };
 
+#define VCOM_FEATURE_BUS_POWERED       0x80
+
 /* 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 */
+  CONFIG_DESCRIPTOR,            /* bDescriptorType: Configuration   */
   /* Configuration Descriptor.*/
   67, 0x00,                    /* wTotalLength.                    */
   0x02,                                /* bNumInterfaces.                  */
   0x01,                                /* bConfigurationValue.             */
   0,                           /* iConfiguration.                  */
-  0x80,                                /* bmAttributes (bus powered).      */
+  VCOM_FEATURE_BUS_POWERED,    /* bmAttributes.                    */
   50,                          /* bMaxPower (100mA).               */
   /* Interface Descriptor.*/
   9,
-  USB_INTERFACE_DESCRIPTOR_TYPE,
+  INTERFACE_DESCRIPTOR,
   0x00,                   /* bInterfaceNumber.                */
   0x00,                   /* bAlternateSetting.               */
   0x01,                   /* bNumEndpoints.                   */
@@ -137,14 +141,14 @@ static const uint8_t vcom_configuration_desc[67] = {
   0x01,         /* bSlaveInterface0 (Data Class Interface).  */
   /* Endpoint 2 Descriptor.*/
   7,
-  USB_ENDPOINT_DESCRIPTOR_TYPE,
+  ENDPOINT_DESCRIPTOR,
   ENDP2|0x80,    /* bEndpointAddress.    */
   0x03,          /* bmAttributes (Interrupt).        */
   0x08, 0x00,   /* wMaxPacketSize.                  */
   0xFF,                 /* bInterval.                       */
   /* Interface Descriptor.*/
   9,
-  USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: */
+  INTERFACE_DESCRIPTOR,          /* bDescriptorType: */
   0x01,          /* bInterfaceNumber.                */
   0x00,          /* bAlternateSetting.               */
   0x02,          /* bNumEndpoints.                   */
@@ -154,14 +158,14 @@ static const uint8_t vcom_configuration_desc[67] = {
   0x00,                 /* iInterface.                      */
   /* Endpoint 3 Descriptor.*/
   7,
-  USB_ENDPOINT_DESCRIPTOR_TYPE,        /* bDescriptorType: Endpoint */
+  ENDPOINT_DESCRIPTOR,         /* bDescriptorType: Endpoint */
   ENDP3,    /* bEndpointAddress. */
   0x02,                                /* bmAttributes (Bulk).             */
   0x40, 0x00,                  /* wMaxPacketSize.                  */
   0x00,                                /* bInterval.                       */
   /* Endpoint 1 Descriptor.*/
   7,
-  USB_ENDPOINT_DESCRIPTOR_TYPE,        /* bDescriptorType: Endpoint */
+  ENDPOINT_DESCRIPTOR,         /* bDescriptorType: Endpoint */
   ENDP1|0x80,                  /* bEndpointAddress. */
   0x02,                                /* bmAttributes (Bulk).             */
   0x40, 0x00,                  /* wMaxPacketSize.                  */
@@ -174,43 +178,57 @@ static const uint8_t vcom_configuration_desc[67] = {
  */
 static const uint8_t vcom_string0[4] = {
   4,                           /* bLength */
-  USB_STRING_DESCRIPTOR_TYPE,
+  STRING_DESCRIPTOR,
   0x09, 0x04                   /* LangID = 0x0409: US-English */
 };
 
 #include "usb-strings.c.inc"
 
+static void neug_setup_endpoints_for_interface (struct usb_dev *dev,
+                                               uint16_t interface, int stop);
 #ifdef FRAUCHEKY_SUPPORT
+#define MSC_MASS_STORAGE_RESET_COMMAND 0xFF
 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_get_descriptor (uint8_t rcp, uint8_t desc_type,
-                                    uint8_t desc_index, uint16_t index);
+extern int fraucheky_setup (struct usb_dev *dev);
+extern int fraucheky_get_descriptor (struct usb_dev *dev);
 #endif
 
 #define NUM_INTERFACES 2
 
-void
-usb_cb_device_reset (void)
+static void
+usb_device_reset (struct usb_dev *dev)
 {
-  /* Set DEVICE as not configured */
-  usb_lld_set_configuration (0);
-
-  /* Current Feature initialization */
-  usb_lld_set_feature (vcom_configuration_desc[7]);
+  int i;
 
-  usb_lld_reset ();
+  usb_lld_reset (dev, VCOM_FEATURE_BUS_POWERED);
 
-  /* Initialize Endpoint 0 */
+  /* Initialize Endpoint 0.  */
+#ifdef GNU_LINUX_EMULATION
+  usb_lld_setup_endp (dev, ENDP0, 1, 1);
+#else
   usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR, 64);
+#endif
+
+  /* Stop the interface */
+  for (i = 0; i < NUM_INTERFACES; i++)
+    neug_setup_endpoints_for_interface (dev, i, 1);
+
+  /* Notify upper layer.  */
+  chopstx_mutex_lock (&usb_mtx);
+  bDeviceState = ATTACHED;
+  connected = 0;
+  chopstx_cond_signal (&usb_cnd);
+  chopstx_mutex_unlock (&usb_mtx);
 }
 
+#ifndef GNU_LINUX_EMULATION
 extern uint8_t _regnual_start, __heap_end__;
 
 static const uint8_t *const mem_info[] = { &_regnual_start,  &__heap_end__, };
+#endif
 
 /* USB vendor requests to control pipe */
 #define USB_FSIJ_MEMINFO         0
@@ -220,6 +238,9 @@ static const uint8_t *const mem_info[] = { &_regnual_start,  &__heap_end__, };
 #define USB_NEUG_GET_INFO      254
 #define USB_NEUG_EXIT          255 /* Ask to exit and to receive reGNUal */
 
+#define DEFAULT_PASSWD "12345678"
+#define DEFAULT_PASSWD_LEN 8
+
 uint8_t neug_passwd[33] __attribute__ ((section(".passwd"))) = {
   0xff,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
@@ -228,55 +249,67 @@ uint8_t neug_passwd[33] __attribute__ ((section(".passwd"))) = {
 };
 static uint8_t usbbuf[64];
 
-#define DEFAULT_PASSWD "12345678"
-#define DEFAULT_PASSWD_LEN 8
-
+#ifndef GNU_LINUX_EMULATION
 static void set_passwd (void)
 {
   flash_unlock ();
   if (neug_passwd[0] != 0xff)
-    flash_erase_page ((uint32_t)neug_passwd);
+    flash_erase_page ((uintptr_t)neug_passwd);
   if (usbbuf[0] == DEFAULT_PASSWD_LEN
       && !memcmp (usbbuf + 1, DEFAULT_PASSWD, DEFAULT_PASSWD_LEN))
     return;
-  flash_write ((uint32_t)neug_passwd, usbbuf, usbbuf[0] + 1);
+  flash_write ((uintptr_t)neug_passwd, usbbuf, usbbuf[0] + 1);
 }
 
-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)
+static int download_check_crc32 (struct usb_dev *dev, const uint32_t *end_p)
 {
   uint32_t crc32 = *end_p;
   const uint32_t *p;
 
-  RCC->AHBENR |= RCC_AHBENR_CRCEN;
-  CRC->CR = CRC_CR_RESET;
+  crc32_rv_reset ();
 
   for (p = (const uint32_t *)&_regnual_start; p < end_p; p++)
-    CRC->DR = rbit (*p);
+    crc32_rv_step (rbit (*p));
 
-  if ((rbit (CRC->DR) ^ crc32) == 0xffffffff)
-    return USB_SUCCESS;
+  if ((rbit (crc32_rv_get ()) ^ crc32) == 0xffffffff)
+    return usb_lld_ctrl_ack (dev);
 
-  return USB_UNSUPPORT;
+  return -1;
 }
+#endif
+
 
-void
-usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, uint16_t value,
-                         uint16_t index, uint16_t len)
+#define NEUG_SPECIAL_BITRATE 110
+
+struct line_coding
 {
-  uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
+  uint32_t bitrate;
+  uint8_t format;
+  uint8_t paritytype;
+  uint8_t datatype;
+} __attribute__((packed));
 
-  if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT) && USB_SETUP_SET (req))
+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
+
+static void
+usb_ctrl_write_finish (struct usb_dev *dev)
+{
+  struct device_req *arg = &dev->dev_req;
+  uint8_t type_rcp = arg->type & (REQUEST_TYPE|RECIPIENT);
+
+  if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT)
+      && USB_SETUP_SET (arg->type))
     {
-      if (req_no == USB_FSIJ_EXEC && len == 0)
+      if (arg->request == USB_FSIJ_EXEC)
        {
          chopstx_mutex_lock (&usb_mtx);
          if (fsij_device_state == FSIJ_DEVICE_EXITED)
@@ -286,236 +319,230 @@ usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, uint16_t value,
            }
          chopstx_mutex_unlock (&usb_mtx);
        }
-      else if (req_no == USB_NEUG_SET_PASSWD)
+#ifndef GNU_LINUX_EMULATION
+      else if (arg->request == USB_NEUG_SET_PASSWD)
        set_passwd ();
-      else if (req_no == USB_NEUG_EXIT)
+#endif
+      else if (arg->request == USB_NEUG_EXIT)
        {
          if ((neug_passwd[0] == 0xff && usbbuf[0] == DEFAULT_PASSWD_LEN
               && !memcmp (usbbuf + 1, DEFAULT_PASSWD, DEFAULT_PASSWD_LEN))
+#ifndef GNU_LINUX_EMULATION
              || (neug_passwd[0] == usbbuf[0]
-                 && !memcmp (neug_passwd+1, usbbuf+1, neug_passwd[0])))
+                 && !memcmp (neug_passwd+1, usbbuf+1, neug_passwd[0]))
+#endif
+             )
            {
              chopstx_mutex_lock (&usb_mtx);
              fsij_device_state = FSIJ_DEVICE_NEUG_EXIT_REQUESTED;
-             chopstx_wakeup_usec_wait (main_thd);
-             chopstx_cond_signal (&cnd_usb);
+             chopstx_cond_signal (&usb_cnd);
              chopstx_mutex_unlock (&usb_mtx);
            }
        }
     }
-  else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT)
-          && index == 0 && USB_SETUP_SET (req)
-          && req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
+  else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT) && arg->index == 0
+          && USB_SETUP_SET (arg->type))
     {
-      /* 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 (arg->request == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
+       {
+         /* Open/close the connection.  */
+         chopstx_mutex_lock (&usb_mtx);
+         connected = (arg->value & CDC_CTRL_DTR)? 1 : 0;
+         chopstx_cond_signal (&usb_cnd);
+         chopstx_mutex_unlock (&usb_mtx);
        }
-      else
-       chopstx_cond_signal (&cnd_usb);
-      chopstx_mutex_unlock (&usb_mtx);
+#ifdef FRAUCHEKY_SUPPORT
+      else if (running_neug && arg->request == 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_cond_signal (&usb_cnd);
+           }
+         else if (fsij_device_state == FSIJ_DEVICE_NEUG_FRAUCHEKY_REQUESTED)
+           fsij_device_state = FSIJ_DEVICE_RUNNING;
+         chopstx_mutex_unlock (&usb_mtx);
+       }
+      else if (!running_neug && arg->request == MSC_MASS_STORAGE_RESET_COMMAND)
+       fraucheky_setup_endpoints_for_interface (0);
+#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 (struct usb_dev *dev)
 {
-  (void)value;
-  if (USB_SETUP_GET (req))
+  struct device_req *arg = &dev->dev_req;
+
+  if (USB_SETUP_GET (arg->type))
     {
-      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 (arg->request == USB_CDC_REQ_GET_LINE_CODING)
+       return usb_lld_ctrl_send (dev, &line_coding, sizeof(line_coding));
     }
   else  /* USB_SETUP_SET (req) */
     {
-      if (req_no == USB_CDC_REQ_SET_LINE_CODING
-         && len == sizeof (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)
-       return USB_SUCCESS;
+      if (arg->request == USB_CDC_REQ_SET_LINE_CODING
+         && arg->len == sizeof (line_coding))
+       return usb_lld_ctrl_recv (dev, &line_coding, sizeof (line_coding));
+      else if (arg->request == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
+       return usb_lld_ctrl_ack (dev);
     }
 
-  return USB_UNSUPPORT;
+  return -1;
 }
 
-int
-usb_cb_setup (uint8_t req, uint8_t req_no,
-              uint16_t value, uint16_t index, uint16_t len)
+static int
+usb_setup (struct usb_dev *dev)
 {
-  uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
+  struct device_req *arg = &dev->dev_req;
+  uint8_t type_rcp = arg->type & (REQUEST_TYPE|RECIPIENT);
 
   if (type_rcp == (VENDOR_REQUEST | DEVICE_RECIPIENT))
     {
-      if (USB_SETUP_GET (req))
+      if (USB_SETUP_GET (arg->type))
        {
-         if (req_no == USB_FSIJ_MEMINFO)
+         if (arg->request == USB_FSIJ_MEMINFO)
            {
+#ifdef GNU_LINUX_EMULATION
+             return -1;
+#else
              chopstx_mutex_lock (&usb_mtx);
              if (fsij_device_state != FSIJ_DEVICE_EXITED)
                {
                  chopstx_mutex_unlock (&usb_mtx);
-                 return USB_UNSUPPORT;
+                 return -1;
                }
              chopstx_mutex_unlock (&usb_mtx);
-             usb_lld_set_data_to_send (mem_info, sizeof (mem_info));
-             return USB_SUCCESS;
+             return usb_lld_ctrl_send (dev, mem_info, sizeof (mem_info));
+#endif
            }
-         else if (req_no == USB_NEUG_GET_INFO)
+         else if (arg->request == 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 (arg->index == 0)
+               return usb_lld_ctrl_send (dev, &neug_mode, sizeof (uint8_t));
+             else if (arg->index == 1)
+               return usb_lld_ctrl_send (dev, &neug_err_cnt, sizeof (uint16_t));
+             else if (arg->index == 2)
+               return usb_lld_ctrl_send (dev, &neug_err_cnt_rc, sizeof (uint16_t));
+             else if (arg->index == 3)
+               return usb_lld_ctrl_send (dev, &neug_err_cnt_p64, sizeof (uint16_t));
+             else if (arg->index == 4)
+               return usb_lld_ctrl_send (dev, &neug_err_cnt_p4k, sizeof (uint16_t));
+             else if (arg->index == 5)
+               return usb_lld_ctrl_send (dev, &neug_rc_max, sizeof (uint16_t));
+             else if (arg->index == 6)
+               return usb_lld_ctrl_send (dev, &neug_p64_max, sizeof (uint16_t));
+             else if (arg->index == 7)
+               return usb_lld_ctrl_send (dev, &neug_p4k_max, sizeof (uint16_t));
              else
-               return USB_UNSUPPORT;
-
-             return USB_SUCCESS;
+               return -1;
            }
        }
       else /* SETUP_SET */
        {
-         uint8_t *addr = (uint8_t *)(0x20000000 + value * 0x100 + index);
+         uint8_t *addr = (uint8_t *)(0x20000000UL + arg->value * 0x100 + arg->index);
 
-         if (req_no == USB_FSIJ_DOWNLOAD)
+         if (arg->request == USB_FSIJ_DOWNLOAD)
            {
+#ifdef GNU_LINUX_EMULATION
+             return -1;
+#else
              chopstx_mutex_lock (&usb_mtx);
              if (fsij_device_state != FSIJ_DEVICE_EXITED)
                {
                  chopstx_mutex_unlock (&usb_mtx);
-                 return USB_UNSUPPORT;
+                 return -1;
                }
              chopstx_mutex_unlock (&usb_mtx);
 
-             if (addr < &_regnual_start || addr + len > &__heap_end__)
-               return USB_UNSUPPORT;
+             if (addr < &_regnual_start || addr + arg->len > &__heap_end__)
+               return -1;
 
-             if (index + len < 256)
-               memset (addr + index + len, 0, 256 - (index + len));
+             if (arg->index + arg->len < 256)
+               memset (addr + arg->index + arg->len, 0, 256 - (arg->index + arg->len));
 
-             usb_lld_set_data_to_recv (addr, len);
-             return USB_SUCCESS;
+             return usb_lld_ctrl_recv (dev, addr, arg->len);
+#endif
            }
-         else if (req_no == USB_FSIJ_EXEC && len == 0)
+         else if (arg->request == USB_FSIJ_EXEC && arg->len == 0)
            {
+#ifdef GNU_LINUX_EMULATION
+             return -1;
+#else
              chopstx_mutex_lock (&usb_mtx);
              if (fsij_device_state != FSIJ_DEVICE_EXITED)
                {
                  chopstx_mutex_unlock (&usb_mtx);
-                 return USB_UNSUPPORT;
+                 return -1;
                }
              chopstx_mutex_unlock (&usb_mtx);
 
-             if (((uint32_t)addr & 0x03))
-               return USB_UNSUPPORT;
+             if (((uintptr_t)addr & 0x03))
+               return -1;
 
-             return download_check_crc32 ((uint32_t *)addr);
+             return download_check_crc32 (dev, (uint32_t *)addr);
+#endif
            }
-         else if (req_no == USB_NEUG_SET_PASSWD && len <= 32)
+         else if (arg->request == USB_NEUG_SET_PASSWD && arg->len <= 32)
            {
-             usbbuf[0] = len;
-             usb_lld_set_data_to_recv (usbbuf + 1, len);
-             return USB_SUCCESS;
+             usbbuf[0] = arg->len;
+             return usb_lld_ctrl_recv (dev, usbbuf + 1, arg->len);
            }
-         else if (req_no == USB_NEUG_EXIT && len <= 32)
+         else if (arg->request == USB_NEUG_EXIT && arg->len <= 32)
            {
              chopstx_mutex_lock (&usb_mtx);
              if (fsij_device_state != FSIJ_DEVICE_RUNNING)
                {
                  chopstx_mutex_unlock (&usb_mtx);
-                 return USB_UNSUPPORT;
+                 return -1;
                }
              chopstx_mutex_unlock (&usb_mtx);
 
-             usbbuf[0] = len;
-             usb_lld_set_data_to_recv (usbbuf + 1, len);
-             return USB_SUCCESS;
+             usbbuf[0] = arg->len;
+             return usb_lld_ctrl_recv (dev, usbbuf + 1, arg->len);
            }
        }
     }
-  else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT))
+  else if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT)
+          && arg->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 (dev);
+      else
+       return fraucheky_setup (dev);
 #else
-         return vcom_port_data_setup (req, req_no, value, len);
+      return vcom_port_data_setup (dev);
 #endif
-       }
     }
 
-  return USB_UNSUPPORT;
+  return -1;
 }
 
-int
-usb_cb_get_descriptor (uint8_t rcp, uint8_t desc_type, uint8_t desc_index,
-                      uint16_t index, uint16_t length)
+static int
+usb_get_descriptor (struct usb_dev *dev)
 {
-  (void)length;
+  struct device_req *arg = &dev->dev_req;
+  uint8_t rcp = arg->type & RECIPIENT;
+  uint8_t desc_type = (arg->value >> 8);
+  uint8_t desc_index = (arg->value & 0xff);
+
 #ifdef FRAUCHEKY_SUPPORT
   if (!running_neug)
-    return fraucheky_get_descriptor (rcp, desc_type, desc_index, index);
-#else
-  (void)index;
+    return fraucheky_get_descriptor (dev);
 #endif
 
   if (rcp != DEVICE_RECIPIENT)
-    return USB_UNSUPPORT;
+    return -1;
 
   if (desc_type == DEVICE_DESCRIPTOR)
-    {
-      usb_lld_set_data_to_send (vcom_device_desc, sizeof (vcom_device_desc));
-      return USB_SUCCESS;
-    }
+    return usb_lld_ctrl_send (dev,
+                             vcom_device_desc, sizeof (vcom_device_desc));
   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_ctrl_send (dev,
+                             vcom_config_desc, sizeof (vcom_config_desc));
   else if (desc_type == STRING_DESCRIPTOR)
     {
       const uint8_t *str;
@@ -551,6 +578,7 @@ usb_cb_get_descriptor (uint8_t rcp, uint8_t desc_type, uint8_t desc_index,
          str = sys_version;
          size = sizeof (sys_version);
          break;
+#ifdef USE_SYS3
        case 7:
          {
            int i;
@@ -564,31 +592,40 @@ usb_cb_get_descriptor (uint8_t rcp, uint8_t desc_type, uint8_t desc_index,
                usbbuf[i*2+3] = 0;
              }
            usbbuf[0] = i*2 + 2;
-           usbbuf[1] = USB_STRING_DESCRIPTOR_TYPE;
+           usbbuf[1] = STRING_DESCRIPTOR;
            size = i*2 + 2;
          }
          break;
+#endif
        default:
-         return USB_UNSUPPORT;
+         return -1;
        }
 
-      usb_lld_set_data_to_send (str, size);
-      return USB_SUCCESS;
+      return usb_lld_ctrl_send (dev, str, size);
     }
 
-  return USB_UNSUPPORT;
+  return -1;
 }
 
 static void
-neug_setup_endpoints_for_interface (uint16_t interface, int stop)
+neug_setup_endpoints_for_interface (struct usb_dev *dev,
+                                   uint16_t interface, int stop)
 {
+#if !defined(GNU_LINUX_EMULATION)
+  (void)dev;
+#endif
+  
   if (interface == 0)
     {
 #ifdef FRAUCHEKY_SUPPORT
       if (running_neug)
        {
          if (!stop)
+#ifdef GNU_LINUX_EMULATION
+           usb_lld_setup_endp (dev, ENDP2, 0, 1);
+#else
            usb_lld_setup_endpoint (ENDP2, EP_INTERRUPT, 0, 0, ENDP2_TXADDR, 0);
+#endif
          else
            usb_lld_stall_tx (ENDP2);
        }
@@ -596,7 +633,11 @@ neug_setup_endpoints_for_interface (uint16_t interface, int stop)
        fraucheky_setup_endpoints_for_interface (stop);
 #else
       if (!stop)
+#ifdef GNU_LINUX_EMULATION
+       usb_lld_setup_endp (dev, ENDP2, 0, 1);
+#else
        usb_lld_setup_endpoint (ENDP2, EP_INTERRUPT, 0, 0, ENDP2_TXADDR, 0);
+#endif
       else
        usb_lld_stall_tx (ENDP2);
 #endif
@@ -605,8 +646,14 @@ neug_setup_endpoints_for_interface (uint16_t interface, int stop)
     {
       if (!stop)
        {
+#ifdef GNU_LINUX_EMULATION
+         usb_lld_setup_endp (dev, ENDP1, 0, 1);
+         usb_lld_setup_endp (dev, ENDP3, 1, 0);
+#else
          usb_lld_setup_endpoint (ENDP1, EP_BULK, 0, 0, ENDP1_TXADDR, 0);
          usb_lld_setup_endpoint (ENDP3, EP_BULK, 0, ENDP3_RXADDR, 0, 64);
+#endif
+         /* Start with no data receiving (ENDP3 not enabled) */
        }
       else
        {
@@ -616,103 +663,188 @@ neug_setup_endpoints_for_interface (uint16_t interface, int stop)
     }
 }
 
-int usb_cb_handle_event (uint8_t event_type, uint16_t value)
+static int
+usb_set_configuration (struct usb_dev *dev)
 {
   int i;
   uint8_t current_conf;
 
-  switch (event_type)
+  current_conf = usb_lld_current_configuration (dev);
+  if (current_conf == 0)
+    {
+      if (dev->dev_req.value != 1)
+       return -1;
+
+      usb_lld_set_configuration (dev, 1);
+      for (i = 0; i < NUM_INTERFACES; i++)
+       neug_setup_endpoints_for_interface (dev, i, 0);
+      chopstx_mutex_lock (&usb_mtx);
+      bDeviceState = CONFIGURED;
+      chopstx_mutex_unlock (&usb_mtx);
+    }
+  else if (current_conf != dev->dev_req.value)
     {
-    case USB_EVENT_ADDRESS:
+      if (dev->dev_req.value != 0)
+       return -1;
+
+      usb_lld_set_configuration (dev, 0);
+      for (i = 0; i < NUM_INTERFACES; i++)
+       neug_setup_endpoints_for_interface (dev, i, 1);
       chopstx_mutex_lock (&usb_mtx);
       bDeviceState = ADDRESSED;
+      chopstx_cond_signal (&usb_cnd);
       chopstx_mutex_unlock (&usb_mtx);
-      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);
-         chopstx_mutex_lock (&usb_mtx);
-         bDeviceState = CONFIGURED;
-         chopstx_mutex_unlock (&usb_mtx);
-       }
-      else if (current_conf != value)
-       {
-         if (value != 0)
-           return USB_UNSUPPORT;
+  /* Do nothing when current_conf == value */
+  return usb_lld_ctrl_ack (dev);
+}
 
-         usb_lld_set_configuration (0);
-         for (i = 0; i < NUM_INTERFACES; i++)
-           neug_setup_endpoints_for_interface (i, 1);
-         chopstx_mutex_lock (&usb_mtx);
-         bDeviceState = ADDRESSED;
-         chopstx_mutex_unlock (&usb_mtx);
-       }
-      /* Do nothing when current_conf == value */
-      return USB_SUCCESS;
 
-      return USB_SUCCESS;
-    default:
-      break;
+static int
+usb_set_interface (struct usb_dev *dev)
+{
+  uint16_t interface = dev->dev_req.index;
+  uint16_t alt = dev->dev_req.value;
+
+  if (interface >= NUM_INTERFACES)
+    return -1;
+
+  if (alt != 0)
+    return -1;
+  else
+    {
+      neug_setup_endpoints_for_interface (dev, interface, 0);
+      return usb_lld_ctrl_ack (dev);
     }
+}
 
-  return USB_UNSUPPORT;
+static int
+usb_get_interface (struct usb_dev *dev)
+{
+  const uint8_t zero = 0;
+  uint16_t interface = dev->dev_req.index;
+
+  if (interface >= NUM_INTERFACES)
+    return -1;
+
+  return usb_lld_ctrl_send (dev, &zero, 1);
 }
 
 
-int usb_cb_interface (uint8_t cmd, uint16_t interface, uint16_t alt)
+static int
+usb_get_status_interface (struct usb_dev *dev)
 {
-  static uint8_t zero = 0;
+  const uint16_t status_info = 0;
+  uint16_t interface = dev->dev_req.index;
 
   if (interface >= NUM_INTERFACES)
-    return USB_UNSUPPORT;
+    return -1;
 
-  switch (cmd)
-    {
-    case USB_SET_INTERFACE:
-      if (alt != 0)
-       return USB_UNSUPPORT;
-      else
-       {
-         neug_setup_endpoints_for_interface (interface, 0);
-         return USB_SUCCESS;
-       }
+  return usb_lld_ctrl_send (dev, &status_info, 2);
+}
 
-    case USB_GET_INTERFACE:
-      usb_lld_set_data_to_send (&zero, 1);
-      return USB_SUCCESS;
+static void usb_tx_done (uint8_t ep_num, uint16_t len);
+static void usb_rx_ready (uint8_t ep_num, uint16_t len);
 
-    default:
-    case USB_QUERY_INTERFACE:
-      return USB_SUCCESS;
-    }
-}
 
 #define INTR_REQ_USB 20
 #define PRIO_USB 3
 
 static void *
-usb_intr (void *arg)
+usb_main (void *arg)
 {
   chopstx_intr_t interrupt;
+  struct usb_dev dev;
+  int e;
 
   (void)arg;
-  usb_lld_init (vcom_configuration_desc[7]);
+  usb_lld_init (&dev, VCOM_FEATURE_BUS_POWERED);
   chopstx_claim_irq (&interrupt, INTR_REQ_USB);
-  usb_interrupt_handler ();
+  goto event_handle;   /* For old SYS < 3.0 */
 
   while (1)
     {
       chopstx_intr_wait (&interrupt);
 
-      /* Process interrupt. */
-      usb_interrupt_handler ();
+      if (interrupt.ready)
+       {
+         uint8_t ep_num;
+
+       event_handle:
+         e = usb_lld_event_handler (&dev);
+         ep_num = USB_EVENT_ENDP (e);
+
+         if (ep_num != 0)
+           {
+             if (USB_EVENT_TXRX (e))
+               usb_tx_done (ep_num, USB_EVENT_LEN (e));
+             else
+               usb_rx_ready (ep_num, USB_EVENT_LEN (e));
+           }
+         else
+           switch (USB_EVENT_ID (e))
+             {
+             case USB_EVENT_DEVICE_RESET:
+               usb_device_reset (&dev);
+               continue;
+
+             case USB_EVENT_DEVICE_ADDRESSED:
+               chopstx_mutex_lock (&usb_mtx);
+               bDeviceState = ADDRESSED;
+               chopstx_cond_signal (&usb_cnd);
+               chopstx_mutex_unlock (&usb_mtx);
+               continue;
+
+             case USB_EVENT_GET_DESCRIPTOR:
+               if (usb_get_descriptor (&dev) < 0)
+                 usb_lld_ctrl_error (&dev);
+               continue;
+
+             case USB_EVENT_SET_CONFIGURATION:
+               if (usb_set_configuration (&dev) < 0)
+                 usb_lld_ctrl_error (&dev);
+               continue;
+
+             case USB_EVENT_SET_INTERFACE:
+               if (usb_set_interface (&dev) < 0)
+                 usb_lld_ctrl_error (&dev);
+               continue;
+
+             case USB_EVENT_CTRL_REQUEST:
+               /* Device specific device request.  */
+               if (usb_setup (&dev) < 0)
+                 usb_lld_ctrl_error (&dev);
+               continue;
+
+             case USB_EVENT_GET_STATUS_INTERFACE:
+               if (usb_get_status_interface (&dev) < 0)
+                 usb_lld_ctrl_error (&dev);
+               continue;
+
+             case USB_EVENT_GET_INTERFACE:
+               if (usb_get_interface (&dev) < 0)
+                 usb_lld_ctrl_error (&dev);
+               continue;
+
+             case USB_EVENT_SET_FEATURE_DEVICE:
+             case USB_EVENT_SET_FEATURE_ENDPOINT:
+             case USB_EVENT_CLEAR_FEATURE_DEVICE:
+             case USB_EVENT_CLEAR_FEATURE_ENDPOINT:
+               usb_lld_ctrl_ack (&dev);
+               continue;
+
+             case USB_EVENT_CTRL_WRITE_FINISH:
+               /* Control WRITE transfer finished.  */
+               usb_ctrl_write_finish (&dev);
+               continue;
+
+             case USB_EVENT_OK:
+             case USB_EVENT_DEVICE_SUSPEND:
+             default:
+               continue;
+             }
+       }
     }
 
   return NULL;
@@ -729,7 +861,7 @@ static void fill_serial_no_by_unique_id (void)
   for (i = 0; i < 4; i++)
     {
       uint8_t b = u[3-i];
-      uint8_t nibble; 
+      uint8_t nibble;
 
       nibble = (b >> 4);
       nibble += (nibble >= 10 ? ('A' - 10) : '0');
@@ -741,24 +873,48 @@ static void fill_serial_no_by_unique_id (void)
       p[i*4+3] = 0;
     }
 }
-\f
-void
-EP1_IN_Callback (void)
-{
-  chopstx_mutex_lock (&usb_mtx);
-  chopstx_cond_signal (&cnd_usb);
-  chopstx_mutex_unlock (&usb_mtx);
-}
 
-void
-EP2_IN_Callback (void)
+
+static void
+usb_tx_done (uint8_t ep_num, uint16_t len)
 {
+  if (ep_num == ENDP1)
+    {
+      chopstx_mutex_lock (&usb_mtx);
+      chopstx_cond_signal (&usb_cnd);
+      chopstx_mutex_unlock (&usb_mtx);
+    }
+  else if (ep_num == ENDP2)
+    {
+      /* INTERRUPT Transfer done */
+    }
+#ifdef FRAUCHEKY_SUPPORT
+  else if (ep_num == ENDP6)
+    EP6_IN_Callback (len);
+#else
+  (void)len;
+#endif
 }
 
-void
-EP3_OUT_Callback (void)
+#ifdef GNU_LINUX_EMULATION
+static uint8_t endp3_buf[64];
+#endif
+
+static void
+usb_rx_ready (uint8_t ep_num, uint16_t len)
 {
-  usb_lld_rx_enable (ENDP3);
+  if (ep_num == ENDP3)
+#ifdef GNU_LINUX_EMULATION
+    usb_lld_rx_enable_buf (ENDP3, endp3_buf, 64);
+#else
+    usb_lld_rx_enable (ENDP3);
+#endif
+#ifdef FRAUCHEKY_SUPPORT
+  else if (ep_num == ENDP6)
+    EP6_OUT_Callback (len);
+#else
+  (void)len;
+#endif
 }
 \f
 typedef uint32_t eventmask_t;
@@ -801,13 +957,20 @@ static void event_flag_signal (struct event_flag *ev, eventmask_t m)
   chopstx_mutex_unlock (&ev->mutex);
 }
 
-extern uint8_t __process1_stack_base__, __process1_stack_size__;
-extern uint8_t __process3_stack_base__, __process3_stack_size__;
+#ifdef GNU_LINUX_EMULATION
+static char __process1_stack_base__[4096];
+static char __process3_stack_base__[4096];
+#define STACK_SIZE_LED (sizeof __process1_stack_base__)
+#define STACK_SIZE_USB (sizeof __process3_stack_base__)
+#else
+extern uint8_t __process1_stack_base__[], __process1_stack_size__[];
+extern uint8_t __process3_stack_base__[], __process3_stack_size__[];
+#define STACK_SIZE_LED ((uintptr_t)__process1_stack_size__)
+#define STACK_SIZE_USB ((uintptr_t)__process3_stack_size__)
+#endif
 
-const uint32_t __stackaddr_led = (uint32_t)&__process1_stack_base__;
-const size_t __stacksize_led = (size_t)&__process1_stack_size__;
-const uint32_t __stackaddr_usb = (uint32_t)&__process3_stack_base__;
-const size_t __stacksize_usb = (size_t)&__process3_stack_size__;
+#define STACK_ADDR_LED ((uintptr_t)__process1_stack_base__)
+#define STACK_ADDR_USB ((uintptr_t)__process3_stack_base__)
 
 
 #define PRIO_LED 3
@@ -832,8 +995,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)
@@ -857,11 +1018,20 @@ led_blinker (void *arg)
 #define RANDOM_BYTES_LENGTH 64
 static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)];
 
+#ifdef GNU_LINUX_EMULATION
+static uint8_t endp1_buf[RANDOM_BYTES_LENGTH];
+#endif
+
 static void copy_to_tx (uint32_t v, int i)
 {
+#ifdef GNU_LINUX_EMULATION
+  memcpy (&endp1_buf[i], &v, 4);
+#else
   usb_lld_txcpy (&v, ENDP1, i * 4, 4);
+#endif
 }
 
+#ifndef GNU_LINUX_EMULATION
 /*
  * In Gnuk 1.0.[12], reGNUal was not relocatable.
  * Now, it's relocatable, but we need to calculate its entry address
@@ -872,14 +1042,31 @@ static uint32_t
 calculate_regnual_entry_address (const uint8_t *addr)
 {
   const uint8_t *p = addr + 4;
-  uint32_t v = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24);
+  uintptr_t v = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24);
 
   v -= REGNUAL_START_ADDRESS_COMPATIBLE;
-  v += (uint32_t)addr;
+  v += (uintptr_t)addr;
   return v;
 }
+#endif
 
 
+static int
+check_usb_status (void *arg)
+{
+  (void)arg;
+
+  return (connected || bDeviceState != CONFIGURED
+         || fsij_device_state != FSIJ_DEVICE_RUNNING);
+}
+
+
+#ifdef GNU_LINUX_EMULATION
+#include <stdlib.h>
+
+#define main emulated_main
+#endif
+
 /*
  * Entry point.
  *
@@ -888,7 +1075,9 @@ calculate_regnual_entry_address (const uint8_t *addr)
 int
 main (int argc, char **argv)
 {
-  uint32_t entry;
+#ifndef GNU_LINUX_EMULATION
+  uintptr_t entry;
+#endif
   chopstx_t led_thread, usb_thd;
   unsigned int count;
 
@@ -900,29 +1089,36 @@ main (int argc, char **argv)
   adc_init ();
 
   event_flag_init (&led_event);
-  
-  chopstx_mutex_init (&usb_mtx);
-  chopstx_cond_init (&cnd_usb);
 
-  led_thread = chopstx_create (PRIO_LED, __stackaddr_led, __stacksize_led,
-                              led_blinker, NULL);
+  chopstx_mutex_init (&usb_mtx);
+  chopstx_cond_init (&usb_cnd);
 
 #ifdef FRAUCHEKY_SUPPORT
   if (fraucheky_enabled ())
     {
-      usb_thd = chopstx_create (PRIO_USB, __stackaddr_usb, __stacksize_usb,
-                               usb_intr, NULL);
+    go_fraucheky:
+      bDeviceState = UNCONNECTED;
+      running_neug = 0;
+      usb_thd = chopstx_create (PRIO_USB, STACK_ADDR_USB, STACK_SIZE_USB,
+                               usb_main, NULL);
+      while (bDeviceState != CONFIGURED)
+       chopstx_usec_wait (250*1000);
+      set_led (1);
       fraucheky_main ();
       chopstx_cancel (usb_thd);
       chopstx_join (usb_thd, NULL);
       usb_lld_shutdown ();
+      bDeviceState = UNCONNECTED;
     }
 
   running_neug = 1;
 #endif
 
-  usb_thd = chopstx_create (PRIO_USB, __stackaddr_usb, __stacksize_usb,
-                           usb_intr, NULL);
+  led_thread = chopstx_create (PRIO_LED, STACK_ADDR_LED, STACK_SIZE_LED,
+                              led_blinker, NULL);
+
+  usb_thd = chopstx_create (PRIO_USB, STACK_ADDR_USB, STACK_SIZE_USB,
+                           usb_main, NULL);
 
   neug_init (random_word, RANDOM_BYTES_LENGTH/sizeof (uint32_t));
 
@@ -930,7 +1126,7 @@ main (int argc, char **argv)
 
  not_configured:
   count = 0;
-  /* A run-up */
+  /* Initial run-up */
   while (count < NEUG_PRE_LOOP || bDeviceState != CONFIGURED)
     {
       if (fsij_device_state != FSIJ_DEVICE_RUNNING)
@@ -947,7 +1143,7 @@ main (int argc, char **argv)
       chopstx_mutex_lock (&usb_mtx);
     }
 
-  /* Holding USB_MTX.  */
+  /* Holding USB_MTX...  */
   while (1)
     {
       int last_was_fullsizepacket = 0;
@@ -955,21 +1151,32 @@ main (int argc, char **argv)
       if (fsij_device_state != FSIJ_DEVICE_RUNNING)
        break;
 
+      chopstx_mutex_unlock (&usb_mtx);
       while (1)
        {
-         wait_usb_connection = 5000*1000;
-         if (connected || bDeviceState != CONFIGURED
-             || fsij_device_state != FSIJ_DEVICE_RUNNING)
+         uint32_t usec = 5000*1000;
+         chopstx_poll_cond_t poll_desc;
+         struct chx_poll_head *pd_array[1] = {
+           (struct chx_poll_head *)&poll_desc
+         };
+
+         poll_desc.type = CHOPSTX_POLL_COND;
+         poll_desc.ready = 0;
+         poll_desc.cond = &usb_cnd;
+         poll_desc.mutex = &usb_mtx;
+         poll_desc.check = check_usb_status;
+         poll_desc.arg = NULL;
+
+         if (chopstx_poll (&usec, 1, pd_array))
            break;
 
-         chopstx_mutex_unlock (&usb_mtx);
+         /* Timeout */
          neug_flush ();
          neug_mode_select (line_coding.paritytype);
          event_flag_signal (&led_event, LED_TWOSHOTS);
-         chopstx_usec_wait_var (&wait_usb_connection);
-         chopstx_mutex_lock (&usb_mtx);
        }
 
+      chopstx_mutex_lock (&usb_mtx);
       if (bDeviceState != CONFIGURED)
        goto not_configured;
 
@@ -1018,8 +1225,12 @@ main (int argc, char **argv)
                break;
 
              /* Prepare sending random data.  */
+#ifdef GNU_LINUX_EMULATION
+             usb_lld_tx_enable_buf (ENDP1, endp1_buf, i * 4);
+#else
              usb_lld_tx_enable (ENDP1, i * 4);
-             chopstx_cond_wait (&cnd_usb, &usb_mtx);
+#endif
+             chopstx_cond_wait (&usb_cnd, &usb_mtx);
              count++;
            }
        }
@@ -1031,11 +1242,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)
@@ -1054,8 +1288,11 @@ main (int argc, char **argv)
   chopstx_cancel (usb_thd);
   chopstx_join (usb_thd, NULL);
 
+#ifdef GNU_LINUX_EMULATION
+  exit (0);
+#else
   /* Set vector */
-  SCB->VTOR = (uint32_t)&_regnual_start;
+  SCB->VTOR = (uintptr_t)&_regnual_start;
   entry = calculate_regnual_entry_address (&_regnual_start);
 #ifdef DFU_SUPPORT
 #define FLASH_SYS_START_ADDR 0x08000000
@@ -1086,6 +1323,7 @@ main (int argc, char **argv)
 #else
   /* Leave NeuG to exec reGNUal */
   flash_erase_all_and_exec ((void (*)(void))entry);
+#endif
 #endif
 
   /* Never reached */