update ChibiOS/RT and NeuG
authorNIIBE Yutaka <gniibe@fsij.org>
Sun, 17 Feb 2013 15:21:35 +0000 (00:21 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Sun, 17 Feb 2013 15:21:35 +0000 (00:21 +0900)
21 files changed:
ChangeLog
boards/FST_01/board.c
boards/FST_01/board.h
boards/FST_01/mcuconf.h
boards/common/board-common.c [new file with mode: 0644]
boards/common/hwinit.c [deleted file]
boards/common/mcuconf-common.h
src/Makefile.in
src/adc.h [new file with mode: 0644]
src/adc_stm32f103.c [new file with mode: 0644]
src/chconf.h
src/gnuk.ld.in
src/halconf.h
src/main.c
src/neug.c
src/neug.h
src/openpgp.c
src/random.c
src/usb-icc.c
src/usb_lld.c [deleted file]
src/usb_stm32f103.c [new file with mode: 0644]

index 84b5bc6..efdf416 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2013-02-18  Niibe Yutaka  <gniibe@fsij.org>
+
+       * chibios: New submodule for ChibioS/RT 2.4.x.
+       * boards/*/*: Update for ChibiOS/RT 2.4.x.
+
+       * src/chconf.h, src/halconf.h, src/Makefile.in, src/gnuk.ld.in:
+       Update for ChibiOS/RT 2.4.x.
+
+       * src/main.c, src/openpgp.c, src/usb-icc.c: Follow the change of
+       ChibiOS/RT 2.4.x.
+       * boards/common/board-common.c: Rename from hwinit.c.
+       * src/usb_stm32f103.c: Rename from usb_lld.c.
+
+       * src/neug.h, src/neug.h: Update NeuG 0.05.
+       * src/adc_stm32f103.c, src/adc.h: New from NeuG 0.05.
+
+       * src/random.c: Follow the change of NeuG 0.05.
+
 2013-02-15  Niibe Yutaka  <gniibe@fsij.org>
 
        * Version 1.0.2.
index 7db9dee..78a6c85 100644 (file)
@@ -2,13 +2,11 @@
 #include "ch.h"
 #include "hal.h"
 
-#include "../common/hwinit.c"
-
-void
-hwinit1 (void)
+/*
+ * Board-specific initialization code.
+ */
+void boardInit(void)
 {
-  hwinit1_common ();
-
 #if defined(PINPAD_CIR_SUPPORT)
   /* PA0/TIM2_CH1 = 1 (pull up)   */
   /* PA1/TIM2_CH2 = 0 (pull down) */
index eafad06..4318711 100644 (file)
 #define GPIO_LED       GPIOB_LED
 #define IOPORT_LED     GPIOB
 
+/* NeuG settings for ADC2.  */
+#define NEUG_ADC_SETTING2_SMPR1 0
+#define NEUG_ADC_SETTING2_SMPR2 ADC_SMPR2_SMP_AN0(ADC_SAMPLE_1P5)    \
+                              | ADC_SMPR2_SMP_AN9(ADC_SAMPLE_1P5)
+#define NEUG_ADC_SETTING2_SQR3  ADC_SQR3_SQ1_N(ADC_CHANNEL_IN0)      \
+                              | ADC_SQR3_SQ2_N(ADC_CHANNEL_IN9)
+#define NEUG_ADC_SETTING2_NUM_CHANNELS 2
+
 /*
  * Board identifier.
  */
@@ -54,7 +62,6 @@
  * native STM32 HAL.
  */
 #define STM32F10X_MD
-#define CPU_WITH_NO_GPIOE      1
 
 /*
  * IO pins assignments.
 
 /*
  * Port A setup.
- * PA0  - input with pull-up (TIM2_CH1)
+ * PA0  - input with pull-up (TIM2_CH1): AN0 for NeuG
  * PA1  - input with pull-down (TIM2_CH2)
- * PA2  - input with pull-up (TIM2_CH3)
- * PA4  - Push pull output   (SPI1_NSS)
+ * PA2  - input with pull-up (TIM2_CH3) connected to CIR module
+ * PA3  - input with pull-up: external pin available to user
+ * PA4  - Push pull output           (SPI1_NSS)
  * PA5  - Alternate Push pull output (SPI1_SCK)
  * PA6  - Alternate Push pull output (SPI1_MISO)
  * PA7  - Alternate Push pull output (SPI1_MOSI)
 
 /*
  * Port B setup.
+ * PB1  - input with pull-up: AN9 for NeuG
  * Everything input with pull-up except:
  * PB0  - Push pull output   (LED 1:ON 0:OFF)
  */
 #define VAL_GPIOECRH            0x88888888      /* PE15...PE8 */
 #define VAL_GPIOEODR            0xFFFFFFFF
 
+#if !defined(_FROM_ASM_)
+#ifdef __cplusplus
+extern "C" {
+#endif
+  void boardInit(void);
+#ifdef __cplusplus
+}
+#endif
+#endif /* _FROM_ASM_ */
+
 #endif /* _BOARD_H_ */
index 56235c0..103aace 100644 (file)
@@ -7,9 +7,8 @@
 #define STM32_PLLMUL_VALUE          6
 #define STM32_HPRE                  STM32_HPRE_DIV1
 #define STM32_PPRE1                 STM32_PPRE1_DIV2
-#define STM32_PPRE2                 STM32_PPRE2_DIV2
-#define STM32_ADCPRE                STM32_ADCPRE_DIV4
-#define STM32_USBPRE                STM32_USBPRE_DIV1P5
-#define STM32_MCO                   STM32_MCO_NOCLOCK
+#define STM32_PPRE2                 STM32_PPRE2_DIV1
+#define STM32_ADCPRE                STM32_ADCPRE_DIV6
+#define STM32_RTCSEL                STM32_RTCSEL_NOCLOCK
 
 #include "mcuconf-common.h"
diff --git a/boards/common/board-common.c b/boards/common/board-common.c
new file mode 100644 (file)
index 0000000..80cf528
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+    ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+
+    This file is part of ChibiOS/RT.
+
+    ChibiOS/RT is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS/RT 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.
+
+    You should have received a copy of the GNU General Public License
+    along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+                                      ---
+
+    A special exception to the GPL can be applied should you wish to distribute
+    a combined work that includes ChibiOS/RT, without being obliged to provide
+    the source code for any proprietary components. See the file exception.txt
+    for full details of how and when the exception can be applied.
+*/
+
+#include "ch.h"
+#include "hal.h"
+#include "config.h"
+
+/**
+ * @brief   PAL setup.
+ * @details Digital I/O ports static configuration as defined in @p board.h.
+ *          This variable is used by the HAL when initializing the PAL driver.
+ */
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+const PALConfig pal_default_config =
+{
+  {VAL_GPIOAODR, VAL_GPIOACRL, VAL_GPIOACRH},
+  {VAL_GPIOBODR, VAL_GPIOBCRL, VAL_GPIOBCRH},
+  {VAL_GPIOCODR, VAL_GPIOCCRL, VAL_GPIOCCRH},
+  {VAL_GPIODODR, VAL_GPIODCRL, VAL_GPIODCRH},
+  {VAL_GPIOEODR, VAL_GPIOECRL, VAL_GPIOECRH},
+#if defined(STM32F10X_HD)
+  {VAL_GPIOFODR, VAL_GPIOFCRL, VAL_GPIOFCRH},
+  {VAL_GPIOGODR, VAL_GPIOGCRL, VAL_GPIOGCRH},
+#endif
+};
+#endif
+
+/*
+ * Early initialization code.
+ * This initialization must be performed just after stack setup and before
+ * any other initialization.
+ */
+void
+__early_init(void)
+{
+  stm32_clock_init();
+}
+
+const uint8_t *
+unique_device_id (void)
+{
+  /* STM32F103 has 96-bit unique device identifier */
+  const uint8_t *addr = (const uint8_t *)0x1ffff7e8;
+
+  return addr;
+}
diff --git a/boards/common/hwinit.c b/boards/common/hwinit.c
deleted file mode 100644 (file)
index e84788e..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
-    ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
-
-    This file is part of ChibiOS/RT.
-
-    ChibiOS/RT is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 3 of the License, or
-    (at your option) any later version.
-
-    ChibiOS/RT 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.
-
-    You should have received a copy of the GNU General Public License
-    along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-                                      ---
-
-    A special exception to the GPL can be applied should you wish to distribute
-    a combined work that includes ChibiOS/RT, without being obliged to provide
-    the source code for any proprietary components. See the file exception.txt
-    for full details of how and when the exception can be applied.
-*/
-
-/*
- * Early initialization code.
- * This initialization is performed just after reset before BSS and DATA
- * segments initialization.
- */
-void
-hwinit0 (void)
-{
-  stm32_clock_init();
-}
-
-/*
- * Late initialization code.
- * This initialization is performed after BSS and DATA segments initialization
- * and before invoking the main() function.
- */
-
-/*
- * Common code for hwinit1
- *
- */
-static void hwinit1_common (void)
-{
-  /*
-   * HAL initialization.
-   */
-  halInit();
-
-  /*
-   * ChibiOS/RT initialization.
-   */
-  chSysInit();
-}
index 7f77139..d162eef 100644 (file)
  * 0...3        Lowest...Highest.
  */
 
+/*
+ * HAL driver system settings.
+ */
+#define STM32_NO_INIT                       FALSE
+#define STM32_HSI_ENABLED                   TRUE
+#define STM32_LSI_ENABLED                   FALSE
+#define STM32_HSE_ENABLED                   TRUE
+#define STM32_LSE_ENABLED                   FALSE
+#define STM32_USB_CLOCK_REQUIRED            TRUE
+#define STM32_USBPRE                        STM32_USBPRE_DIV1P5
+#define STM32_MCOSEL                        STM32_MCOSEL_NOCLOCK
+#define STM32_PVD_ENABLE                    FALSE
+#define STM32_PLS                           STM32_PLS_LEV0
+
 /*
  * ADC driver system settings.
  */
 #define STM32_SPI1_IRQ_PRIORITY     10
 #define STM32_SPI2_IRQ_PRIORITY     10
 #define STM32_SPI1_DMA_ERROR_HOOK() chSysHalt()
+
+/*
+ * USB driver system settings.
+ */
+#define STM32_USB_USE_USB1                  TRUE
+#define STM32_USB_LOW_POWER_ON_SUSPEND      FALSE
+#define STM32_USB_USB1_HP_IRQ_PRIORITY      6
+#define STM32_USB_USB1_LP_IRQ_PRIORITY      14
index 3f5a094..d443375 100644 (file)
@@ -29,9 +29,9 @@ ifeq ($(USE_THUMB),)
   USE_THUMB = yes
 endif
 
-# Enable register caching optimization (read documentation).
-ifeq ($(USE_CURRP_CACHING),)
-  USE_CURRP_CACHING = no
+# Enable this if you want to see the full log while compiling.
+ifeq ($(USE_VERBOSE_COMPILE),)
+  USE_VERBOSE_COMPILE = no
 endif
 
 #
@@ -58,17 +58,17 @@ endif
 # Define project name here
 PROJECT = gnuk
 
-# Define linker script file here
-LDSCRIPT= gnuk.ld
-
 # Imported source files
-CHIBIOS = ../ChibiOS_2.0.8
-include $(CHIBIOS)/os/hal/platforms/STM32/platform.mk
+CHIBIOS = ../chibios
+include $(CHIBIOS)/os/hal/platforms/STM32F1xx/platform.mk
 include $(CHIBIOS)/os/hal/hal.mk
-include $(CHIBIOS)/os/ports/GCC/ARMCMx/STM32F10x/port.mk
+include $(CHIBIOS)/os/ports/GCC/ARMCMx/STM32F1xx/port.mk
 include $(CHIBIOS)/os/kernel/kernel.mk
 include crypt.mk
 
+# Define linker script file here
+LDSCRIPT= gnuk.ld
+
 # C sources that can be compiled in ARM or THUMB mode depending on the global
 # setting.
 CSRC = $(PORTSRC) \
@@ -76,11 +76,12 @@ CSRC = $(PORTSRC) \
        $(HALSRC) \
        $(PLATFORMSRC) \
        $(BOARDSRC) \
+       ../boards/common/board-common.c \
        $(BOARD_DIR)/board.c \
        $(CHIBIOS)/os/various/evtimer.c \
        $(CHIBIOS)/os/various/syscalls.c \
        $(CRYPTSRC) \
-       main.c usb_lld.c \
+       main.c usb_stm32f103.c adc_stm32f103.c \
        usb_desc.c usb_ctrl.c \
        usb-icc.c openpgp.c ac.c openpgp-do.c flash.c \
        random.c neug.c sys.c
@@ -98,8 +99,7 @@ CSRC += usb-msc.c
 endif
 
 # List ASM source files here
-ASMSRC = $(PORTASM) \
-         $(CHIBIOS)/os/ports/GCC/ARMCMx/STM32F10x/vectors.s
+ASMSRC = $(PORTASM)
 
 INCDIR = $(CRYPTINCDIR) \
         $(PORTINC) $(KERNINC) $(TESTINC) \
@@ -152,7 +152,7 @@ CPPWARN = -Wall -Wextra
 #
 
 # List all default C defines here, like -D_DEBUG=1
-DDEFS = -DCORTEX_USE_BASEPRI=TRUE
+DDEFS =
 
 # List all default ASM defines here, like -D_DEBUG=1
 DADEFS =
@@ -193,7 +193,7 @@ ULIBS =
 # End of user defines
 ##############################################################################
 
-include $(CHIBIOS)/os/ports/GCC/ARM/rules.mk
+include $(CHIBIOS)/os/ports/GCC/ARMCMx/rules.mk
 MCFLAGS= -mcpu=$(MCU) -mfix-cortex-m3-ldrd
 
 distclean: clean
diff --git a/src/adc.h b/src/adc.h
new file mode 100644 (file)
index 0000000..366f22e
--- /dev/null
+++ b/src/adc.h
@@ -0,0 +1,10 @@
+#define ADC_DATA_AVAILABLE ((eventmask_t)1)
+extern Thread *rng_thread;
+
+void adc_init (void);
+void adc_start (void);
+void adc_stop (void);
+
+#define ADC_SAMPLE_MODE 0
+#define ADC_CRC32_MODE       1
+void adc_start_conversion (int mode, uint32_t *p, int size);
diff --git a/src/adc_stm32f103.c b/src/adc_stm32f103.c
new file mode 100644 (file)
index 0000000..d8cd2d7
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ * adc_stm32f103.c - ADC driver for STM32F103
+ *
+ * Copyright (C) 2011, 2012 Free Software Initiative of Japan
+ * Author: NIIBE Yutaka <gniibe@fsij.org>
+ *
+ * This file is a part of NeuG, a True Random Number Generator
+ * implementation based on quantization error of ADC (for STM32F103).
+ *
+ * NeuG is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "ch.h"
+#include "hal.h"
+#include "neug.h"
+#include "adc.h"
+
+#define NEUG_CRC32_COUNTS 4
+
+#define STM32_ADC_ADC1_DMA_PRIORITY         2
+#define STM32_ADC_ADC1_IRQ_PRIORITY         5
+
+#define ADC_SMPR1_SMP_VREF(n)   ((n) << 21)
+#define ADC_SMPR1_SMP_SENSOR(n) ((n) << 18)
+
+#define ADC_SMPR1_SMP_AN10(n)   ((n) << 0)
+#define ADC_SMPR1_SMP_AN11(n)   ((n) << 3)
+
+#define ADC_SMPR2_SMP_AN0(n)    ((n) << 0)
+#define ADC_SMPR2_SMP_AN1(n)    ((n) << 3)
+#define ADC_SMPR2_SMP_AN2(n)    ((n) << 6)
+#define ADC_SMPR2_SMP_AN9(n)    ((n) << 27)
+
+#define ADC_SQR1_NUM_CH(n)      (((n) - 1) << 20)
+
+#define ADC_SQR3_SQ1_N(n)       ((n) << 0)
+#define ADC_SQR3_SQ2_N(n)       ((n) << 5)
+#define ADC_SQR3_SQ3_N(n)       ((n) << 10)
+#define ADC_SQR3_SQ4_N(n)       ((n) << 15)
+
+#define ADC_SAMPLE_1P5          0
+
+#define ADC_CHANNEL_IN0         0
+#define ADC_CHANNEL_IN1         1
+#define ADC_CHANNEL_IN9         9
+#define ADC_CHANNEL_IN2         2
+#define ADC_CHANNEL_IN10        10
+#define ADC_CHANNEL_IN11        11
+#define ADC_CHANNEL_SENSOR      16
+#define ADC_CHANNEL_VREFINT     17
+
+#define DELIBARATELY_DO_IT_WRONG_VREF_SAMPLE_TIME
+#define DELIBARATELY_DO_IT_WRONG_START_STOP
+
+#ifdef DELIBARATELY_DO_IT_WRONG_VREF_SAMPLE_TIME
+#define ADC_SAMPLE_VREF ADC_SAMPLE_1P5
+#define ADC_SAMPLE_SENSOR ADC_SAMPLE_1P5
+#else
+#define ADC_SAMPLE_VREF ADC_SAMPLE_239P5
+#define ADC_SAMPLE_SENSOR ADC_SAMPLE_239P5
+#endif
+
+#define NEUG_DMA_CHANNEL STM32_DMA1_STREAM1
+#define NEUG_DMA_MODE_SAMPLE                                            \
+  (  STM32_DMA_CR_PL (STM32_ADC_ADC1_DMA_PRIORITY)                     \
+     | STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_PSIZE_WORD               \
+     | STM32_DMA_CR_MINC       | STM32_DMA_CR_TCIE                     \
+     | STM32_DMA_CR_TEIE)
+
+#define NEUG_DMA_MODE_CRC32                                             \
+  (  STM32_DMA_CR_PL (STM32_ADC_ADC1_DMA_PRIORITY)                     \
+     | STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_PSIZE_WORD               \
+     | STM32_DMA_CR_TCIE       | STM32_DMA_CR_TEIE)
+
+#define NEUG_ADC_SETTING1_SMPR1 ADC_SMPR1_SMP_VREF(ADC_SAMPLE_VREF)     \
+                              | ADC_SMPR1_SMP_SENSOR(ADC_SAMPLE_SENSOR)
+#define NEUG_ADC_SETTING1_SMPR2 0
+#define NEUG_ADC_SETTING1_SQR3  ADC_SQR3_SQ1_N(ADC_CHANNEL_VREFINT)     \
+                              | ADC_SQR3_SQ2_N(ADC_CHANNEL_SENSOR)      \
+                              | ADC_SQR3_SQ3_N(ADC_CHANNEL_SENSOR)      \
+                              | ADC_SQR3_SQ4_N(ADC_CHANNEL_VREFINT)     
+#define NEUG_ADC_SETTING1_NUM_CHANNELS 4
+
+#if !defined(NEUG_ADC_SETTING2_SMPR1)
+#define NEUG_ADC_SETTING2_SMPR1 0
+#define NEUG_ADC_SETTING2_SMPR2 ADC_SMPR2_SMP_AN0(ADC_SAMPLE_1P5)    \
+                              | ADC_SMPR2_SMP_AN1(ADC_SAMPLE_1P5)
+#define NEUG_ADC_SETTING2_SQR3  ADC_SQR3_SQ1_N(ADC_CHANNEL_IN0)      \
+                              | ADC_SQR3_SQ2_N(ADC_CHANNEL_IN1)
+#define NEUG_ADC_SETTING2_NUM_CHANNELS 2
+#endif
+
+
+/*
+ * Do calibration for both of ADCs.
+ */
+void adc_init (void)
+{
+  chSysLock ();
+  rccEnableAPB2 (RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN, FALSE);
+  ADC1->CR1 = 0;
+  ADC1->CR2 = ADC_CR2_ADON;
+  ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_RSTCAL;
+  while ((ADC1->CR2 & ADC_CR2_RSTCAL) != 0)
+    ;
+  ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_CAL;
+  while ((ADC1->CR2 & ADC_CR2_CAL) != 0)
+    ;
+  ADC1->CR2 = 0;
+
+  ADC2->CR1 = 0;
+  ADC2->CR2 = ADC_CR2_ADON;
+  ADC2->CR2 = ADC_CR2_ADON | ADC_CR2_RSTCAL;
+  while ((ADC2->CR2 & ADC_CR2_RSTCAL) != 0)
+    ;
+  ADC2->CR2 = ADC_CR2_ADON | ADC_CR2_CAL;
+  while ((ADC2->CR2 & ADC_CR2_CAL) != 0)
+    ;
+  ADC2->CR2 = 0;
+  rccDisableAPB2 (RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN, FALSE);
+  chSysUnlock ();
+}
+
+static void adc_lld_serve_rx_interrupt (void *arg, uint32_t flags);
+
+void adc_start (void)
+{
+  dmaStreamAllocate (NEUG_DMA_CHANNEL, STM32_ADC_ADC1_IRQ_PRIORITY,
+                    adc_lld_serve_rx_interrupt, NULL);
+  dmaStreamSetPeripheral (NEUG_DMA_CHANNEL, &ADC1->DR);
+
+  chSysLock ();
+
+  rccEnableAPB2 (RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN, FALSE);
+
+  ADC1->CR1 = (ADC_CR1_DUALMOD_2 | ADC_CR1_DUALMOD_1 | ADC_CR1_DUALMOD_0
+              | ADC_CR1_SCAN);
+  ADC1->CR2 = (ADC_CR2_TSVREFE | ADC_CR2_EXTTRIG | ADC_CR2_SWSTART
+              | ADC_CR2_EXTSEL | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON);
+  ADC1->SMPR1 = NEUG_ADC_SETTING1_SMPR1;
+  ADC1->SMPR2 = NEUG_ADC_SETTING1_SMPR2;
+  ADC1->SQR1 = ADC_SQR1_NUM_CH(NEUG_ADC_SETTING1_NUM_CHANNELS);
+  ADC1->SQR2 = 0;
+  ADC1->SQR3 = NEUG_ADC_SETTING1_SQR3;
+
+  ADC2->CR1 = (ADC_CR1_DUALMOD_2 | ADC_CR1_DUALMOD_1 | ADC_CR1_DUALMOD_0
+              | ADC_CR1_SCAN);
+  ADC2->CR2 = ADC_CR2_EXTTRIG | ADC_CR2_CONT | ADC_CR2_ADON;
+  ADC2->SMPR1 = NEUG_ADC_SETTING2_SMPR1;
+  ADC2->SMPR2 = NEUG_ADC_SETTING2_SMPR2;
+  ADC2->SQR1 = ADC_SQR1_NUM_CH(NEUG_ADC_SETTING2_NUM_CHANNELS);
+  ADC2->SQR2 = 0;
+  ADC2->SQR3 = NEUG_ADC_SETTING2_SQR3;
+
+#ifdef DELIBARATELY_DO_IT_WRONG_START_STOP
+  ADC2->CR2 = 0;
+  ADC1->CR2 = 0;
+#endif
+
+  chSysUnlock ();
+}
+
+static int adc_mode;
+static uint32_t *adc_ptr;
+static int adc_size;
+
+static void adc_start_conversion_internal (void)
+{
+#ifdef DELIBARATELY_DO_IT_WRONG_START_STOP
+  /* Power on */
+  ADC2->CR2 = ADC_CR2_EXTTRIG | ADC_CR2_CONT | ADC_CR2_ADON;
+  ADC1->CR2 = (ADC_CR2_TSVREFE | ADC_CR2_EXTTRIG | ADC_CR2_SWSTART
+              | ADC_CR2_EXTSEL | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON);
+  /* Start conversion.  tSTAB is 1uS, but we don't follow the spec.  */
+  ADC2->CR2 = ADC_CR2_EXTTRIG | ADC_CR2_CONT | ADC_CR2_ADON;
+  ADC1->CR2 = (ADC_CR2_TSVREFE | ADC_CR2_EXTTRIG | ADC_CR2_SWSTART
+              | ADC_CR2_EXTSEL | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON);
+#else
+  ADC2->CR2 = ADC_CR2_EXTTRIG | ADC_CR2_CONT | ADC_CR2_ADON;
+  ADC1->CR2 = (ADC_CR2_TSVREFE | ADC_CR2_EXTTRIG | ADC_CR2_SWSTART
+              | ADC_CR2_EXTSEL | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON);
+#endif
+}
+
+void adc_start_conversion (int mode, uint32_t *p, int size)
+{
+  adc_mode = mode;
+  adc_ptr = p;
+  adc_size = size;
+
+ if (mode == ADC_SAMPLE_MODE)
+    {
+      dmaStreamSetMemory0 (NEUG_DMA_CHANNEL, p);
+      dmaStreamSetTransactionSize (NEUG_DMA_CHANNEL, size / 4);
+      dmaStreamSetMode (NEUG_DMA_CHANNEL, NEUG_DMA_MODE_SAMPLE);
+      dmaStreamEnable (NEUG_DMA_CHANNEL);
+    }
+  else
+    {
+      dmaStreamSetMemory0 (NEUG_DMA_CHANNEL, &CRC->DR);
+      dmaStreamSetTransactionSize (NEUG_DMA_CHANNEL, NEUG_CRC32_COUNTS);
+      dmaStreamSetMode (NEUG_DMA_CHANNEL, NEUG_DMA_MODE_CRC32);
+      dmaStreamEnable (NEUG_DMA_CHANNEL);
+    }
+
+ adc_start_conversion_internal ();
+}
+
+
+static void adc_stop_conversion (void)
+{
+  dmaStreamDisable (NEUG_DMA_CHANNEL);
+#ifdef DELIBARATELY_DO_IT_WRONG_START_STOP
+  ADC1->CR2 = 0;
+  ADC2->CR2 = 0;
+#else
+  ADC2->CR2 &= ~ADC_CR2_CONT;
+  ADC1->CR2 &= ~ADC_CR2_CONT;
+#endif
+}
+
+void adc_stop (void)
+{
+  ADC1->CR1 = 0;
+  ADC1->CR2 = 0;
+
+  ADC2->CR1 = 0;
+  ADC2->CR2 = 0;
+
+  dmaStreamRelease (NEUG_DMA_CHANNEL);
+  rccDisableAPB2 (RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN, FALSE);
+}
+
+
+static void adc_lld_serve_rx_interrupt (void *arg, uint32_t flags)
+{
+  (void)arg;
+
+  if ((flags & STM32_DMA_ISR_TEIF) != 0)  /* DMA errors  */
+    {
+      /* Should never happened.  If any, it's coding error. */
+      /* Access an unmapped address space or alignment violation.  */
+      adc_stop_conversion ();
+    }
+  else
+    {
+      if ((flags & STM32_DMA_ISR_TCIF) != 0) /* Transfer complete */
+       {
+         adc_stop_conversion ();
+
+         if (adc_mode != ADC_SAMPLE_MODE)
+           {
+             adc_size -= 4;
+             *adc_ptr++ = CRC->DR;
+
+             if (adc_size > 0)
+               {
+                 dmaStreamSetMemory0 (NEUG_DMA_CHANNEL, &CRC->DR);
+                 dmaStreamSetTransactionSize (NEUG_DMA_CHANNEL, NEUG_CRC32_COUNTS);
+                 dmaStreamSetMode (NEUG_DMA_CHANNEL, NEUG_DMA_MODE_CRC32);
+                 dmaStreamEnable (NEUG_DMA_CHANNEL);
+
+                 adc_start_conversion_internal ();
+               }
+           }
+
+         if (adc_mode == ADC_SAMPLE_MODE || adc_size <= 0)
+           {
+             chSysLockFromIsr();
+             if (rng_thread)
+               chEvtSignalFlagsI (rng_thread, ADC_DATA_AVAILABLE);
+             chSysUnlockFromIsr();
+           }
+       }
+    }
+}
index b4d2ddd..2e767f7 100644 (file)
@@ -3,10 +3,18 @@
 #ifndef _CHCONF_H_
 #define _CHCONF_H_
 
+#include <config.h>
+#ifdef DFU_SUPPORT
+#define CORTEX_VTOR_INIT (0x00003000+0x00001000)
+#else
+#define CORTEX_VTOR_INIT 0x00001000
+#endif
+
 #define CH_FREQUENCY                    1000
 #define CH_TIME_QUANTUM                 20
 #define CH_USE_NESTED_LOCKS             FALSE
 #define CH_MEMCORE_SIZE                 0 /* Whole RAM */
+#define CH_NO_IDLE_THREAD               FALSE
 #define CH_OPTIMIZE_SPEED               TRUE
 #define CH_USE_REGISTRY                 TRUE
 #define CH_USE_WAITEXIT                 TRUE
 #define CH_DBG_THREADS_PROFILING        FALSE
 
 #define THREAD_EXT_FIELDS                                               \
-struct {                                                                \
   /* Add threads custom fields here.*/                                  \
-};
 
 #define THREAD_EXT_INIT(tp) {                                           \
   /* Add threads initialization code here.*/                            \
 }
 
+#define THREAD_CONTEXT_SWITCH_HOOK(ntp, otp) {                              \
+  /* System halt code here.*/                                               \
+}
+
 #define THREAD_EXT_EXIT(tp) {                                           \
   /* Add threads finalization code here.*/                              \
 }
@@ -53,4 +63,12 @@ struct {                                                                \
   /* Idle loop code here.*/                                             \
 }
 
+#define SYSTEM_TICK_EVENT_HOOK() {                                          \
+  /* System tick event code here.*/                                         \
+}
+
+#define SYSTEM_HALT_HOOK() {                                                \
+  /* System halt code here.*/                                               \
+}
+
 #endif  /* _CHCONF_H_ */
index 1ab53e7..ca28f00 100644 (file)
  */
 __main_stack_size__     = 0x0400;
 __process_stack_size__  = 0x0200;
-__stacks_total_size__   = __main_stack_size__ + __process_stack_size__;
 
 MEMORY
 {
-    flash0 : org = @ORIGIN@, len = 4k
-    flash  : org = @ORIGIN@+0x1000, len = @FLASH_SIZE@k - 4k
+    flash0 : org = 0x08000000, len = 4k
+    flash  : org = 0x08000000+0x1000, len = 128k - 4k
     ram : org = 0x20000000, len = 20k
 }
 
@@ -56,20 +55,43 @@ SECTIONS
         KEEP(*(.vectors))
        . = ALIGN(16);
        *(.sys.version)
-       sys.o(.text)
-       sys.o(.text.*)
-        sys.o(.rodata)
-       sys.o(.rodata.*)
+       */sys.o(.text)
+       */sys.o(.text.*)
+        */sys.o(.rodata)
+       */sys.o(.rodata.*)
        . = ALIGN(1024);
        *(.sys.0)
        *(.sys.1)
        *(.sys.2)
     } > flash0
 
-    .text : ALIGN(16) SUBALIGN(16)
+    _text = .;
+
+    startup : ALIGN(16) SUBALIGN(16)
     {
-        _text = .;
         KEEP(*(vectors))
+        . = ALIGN (16);
+    } > flash =0xffffffff
+
+    constructors : ALIGN(4) SUBALIGN(4)
+    {
+        PROVIDE(__init_array_start = .);
+        KEEP(*(SORT(.init_array.*)))
+        KEEP(*(.init_array))
+        PROVIDE(__init_array_end = .);
+    } > flash
+
+    destructors : ALIGN(4) SUBALIGN(4)
+    {
+        PROVIDE(__fini_array_start = .);
+        KEEP(*(.fini_array))
+        KEEP(*(SORT(.fini_array.*)))
+        PROVIDE(__fini_array_end = .);
+    } > flash
+
+    .text : ALIGN(16) SUBALIGN(16)
+    {
+        *(.text.startup.*)
         *(.text)
         *(.text.*)
         *(.rodata)
@@ -79,64 +101,70 @@ SECTIONS
         *(.gcc*)
     } > flash
 
-    .ctors :
-    {
-        PROVIDE(_ctors_start_ = .);
-        KEEP(*(SORT(.ctors.*)))
-        KEEP(*(.ctors))
-        PROVIDE(_ctors_end_ = .);
-    } > flash
-
-    .dtors :
-    {
-        PROVIDE(_dtors_start_ = .);
-        KEEP(*(SORT(.dtors.*)))
-        KEEP(*(.dtors))
-        PROVIDE(_dtors_end_ = .);
-    } > flash
+    .ARM.extab : {*(.ARM.extab* .gnu.linkonce.armextab.*)} > flash
 
-    .ARM.extab : {*(.ARM.extab* .gnu.linkonce.armextab.*)}
+    .ARM.exidx : {
+        PROVIDE(__exidx_start = .);
+        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+        PROVIDE(__exidx_end = .);
+     } > flash
 
-    __exidx_start = .;
-    .ARM.exidx : {*(.ARM.exidx* .gnu.linkonce.armexidx.*)} > flash
-    __exidx_end = .;
+    .eh_frame_hdr : {*(.eh_frame_hdr)} > flash
 
-    .eh_frame_hdr : {*(.eh_frame_hdr)}
+    .eh_frame : ONLY_IF_RO {*(.eh_frame)} > flash
 
-    .eh_frame : ONLY_IF_RO {*(.eh_frame)}
+    .textalign : ONLY_IF_RO { . = ALIGN(8); } > flash
 
-    . = ALIGN(4);
     _etext = .;
     _textdata = _etext;
 
+    .stacks :
+    {
+        . = ALIGN(8);
+        __main_stack_base__ = .;
+        . += __main_stack_size__;
+        . = ALIGN(8);
+        __main_stack_end__ = .;
+        __process_stack_base__ = .;
+        __main_thread_stack_base__ = .;
+        . += __process_stack_size__;
+        . = ALIGN(8);
+        __process_stack_end__ = .;
+        __main_thread_stack_end__ = .;
+    } > ram
+
     .data :
     {
-        _data = .;
+        . = ALIGN(4);
+        PROVIDE(_data = .);
         *(.data)
         . = ALIGN(4);
         *(.data.*)
         . = ALIGN(4);
         *(.ramtext)
         . = ALIGN(4);
-        _edata = .;
+        PROVIDE(_edata = .);
     } > ram AT > flash
 
     .bss :
     {
-        _bss_start = .;
+        . = ALIGN(4);
+        PROVIDE(_bss_start = .);
         *(.bss)
         . = ALIGN(4);
         *(.bss.*)
         . = ALIGN(4);
         *(COMMON)
         . = ALIGN(4);
-        _bss_end = .;
+        PROVIDE(_bss_end = .);
     } > ram
 
     PROVIDE(end = .);
     _end            = .;
     . = ALIGN(512);
+
     _regnual_start = .;
+    /* It was __ram_start__ + 0x1a00 in 1.0.x */
 
 @CERTDO_SUPPORT_START@
     .gnuk_ch_certificate :
@@ -166,4 +194,4 @@ SECTIONS
 }
 
 __heap_base__   = _end;
-__heap_end__    = __ram_end__ - __stacks_total_size__;
+__heap_end__    = __ram_end__;
index 7214d3d..80a7475 100644 (file)
@@ -5,13 +5,25 @@
 
 #include "mcuconf.h"
 
-#define CH_HAL_USE_PAL              TRUE
-#define CH_HAL_USE_ADC              TRUE
-#define CH_HAL_USE_CAN              FALSE
-#define CH_HAL_USE_MAC              FALSE
-#define CH_HAL_USE_PWM              FALSE
-#define CH_HAL_USE_SERIAL           FALSE
-#define CH_HAL_USE_SPI              FALSE
-#define CH_HAL_USE_MMC_SPI          FALSE
+#define HAL_USE_PAL              TRUE
+#define HAL_USE_ADC              FALSE
+#define HAL_USE_CAN              FALSE
+#define HAL_USE_EXT              FALSE
+#define HAL_USE_GPT              FALSE
+#define HAL_USE_I2C              FALSE
+#define HAL_USE_ICU              FALSE
+#define HAL_USE_MAC              FALSE
+#define HAL_USE_MMC_SPI          FALSE
+#define HAL_USE_PWM              FALSE
+#define HAL_USE_RTC              FALSE
+#define HAL_USE_SDC              FALSE
+#define HAL_USE_SERIAL           FALSE
+#define HAL_USE_SERIAL_USB       FALSE
+#define HAL_USE_SPI              FALSE
+#define HAL_USE_UART             FALSE
+#define HAL_USE_USB              FALSE
+
+/* Define manually, as we implement ADC driver by ourselves.  */
+#define STM32_DMA_REQUIRED     1
 
 #endif /* _HALCONF_H_ */
index 4926244..88ee323 100644 (file)
@@ -147,7 +147,7 @@ void
 EP3_IN_Callback (void)
 {
   if (stdout_thread)
-    chEvtSignalI (stdout_thread, EV_TX_READY);
+    chEvtSignalFlagsI (stdout_thread, EV_TX_READY);
 }
 
 void
@@ -316,7 +316,7 @@ static eventmask_t display_status_code (void)
 void
 led_blink (int spec)
 {
-  chEvtSignal (main_thread, spec);
+  chEvtSignalFlags (main_thread, spec);
 }
 
 
@@ -463,7 +463,7 @@ void
 fatal (uint8_t code)
 {
   fatal_code = code;
-  chEvtSignal (main_thread, LED_FATAL);
+  chEvtSignalFlags (main_thread, LED_FATAL);
   _write ("fatal\r\n", 7);
   for (;;);
 }
index 5753094..91636ca 100644 (file)
@@ -1,18 +1,18 @@
 /*
  * neug.c - random number generation (from NeuG/src/random.c)
  *
- * 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
- * implementation (for STM32F103).
+ * This file is a part of NeuG, a True Random Number Generator
+ * implementation based on quantization error of ADC (for STM32F103).
  *
  * NeuG is free software: you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by
  * 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 <string.h>            /* for memcpy */
 #include "config.h"
 
 #include "ch.h"
 #include "hal.h"
+#include "sys.h"
+#include "neug.h"
+#include "adc.h"
+#include "sha256.h"
 
-static Thread *rng_thread;
+Thread *rng_thread;
 #define ADC_DATA_AVAILABLE ((eventmask_t)1)
 
-/* Total number of channels to be sampled by a single ADC operation.*/
-#define ADC_GRP1_NUM_CHANNELS   2
+static uint32_t adc_buf[SHA256_BLOCK_SIZE/sizeof (uint32_t)];
 
-/* Depth of the conversion buffer, channels are sampled one time each.*/
-#define ADC_GRP1_BUF_DEPTH      4
+static sha256_context sha256_ctx_data;
+static uint32_t sha256_output[SHA256_DIGEST_SIZE/sizeof (uint32_t)];
 
 /*
- * ADC samples buffer.
+ * To be a full entropy source, the requirement is to have N samples
+ * for output of 256-bit, where:
+ *
+ *      N = (256 * 2) / <min-entropy of a sample>
+ *
+ * For example, N should be more than 103 for min-entropy = 5.0.
+ *
+ * On the other hand, in the section 6.2 "Full Entropy Source
+ * Requirements", it says:
+ *
+ *     At least twice the block size of the underlying cryptographic
+ *     primitive shall be provided as input to the conditioning
+ *     function to produce full entropy output.
+ *
+ * For us, cryptographic primitive is SHA-256 and its blocksize is
+ * 512-bit (64-byte), thus, N >= 128.
+ *
+ * We chose N=140.  Note that we have "additional bits" of 16-byte for
+ * last block (feedback from previous output of SHA-256) to feed
+ * hash_df function of SHA-256, together with sample data of 140-byte.
+ *
+ * N=140 corresponds to min-entropy >= 3.68.
+ *
  */
-static adcsample_t samp[ADC_GRP1_NUM_CHANNELS * ADC_GRP1_BUF_DEPTH];
+#define NUM_NOISE_INPUTS 140
 
-static void adccb (adcsample_t *buffer, size_t n);
+#define EP_ROUND_0 0 /* initial-five-byte and 3-byte, then 56-byte-input */
+#define EP_ROUND_1 1 /* 64-byte-input */
+#define EP_ROUND_2 2 /* 17-byte-input */
+#define EP_ROUND_RAW      3 /* 32-byte-input */
+#define EP_ROUND_RAW_DATA 4 /* 32-byte-input */
 
-/*
- * ADC conversion group.
- * Mode:        Linear buffer, 4 samples of 2 channels, SW triggered.
- * Channels:    Vref   (1.5 cycles sample time, violating the spec.)
- *              Sensor (1.5 cycles sample time, violating the spec.)
- */
-static const ADCConversionGroup adcgrpcfg = {
-  FALSE,
-  ADC_GRP1_NUM_CHANNELS,
-  0,
-  ADC_CR2_EXTSEL_SWSTART | ADC_CR2_TSVREFE | ADC_CR2_CONT,
-  ADC_SMPR1_SMP_SENSOR(ADC_SAMPLE_1P5) | ADC_SMPR1_SMP_VREF(ADC_SAMPLE_1P5),
-  0,
-  ADC_SQR1_NUM_CH(ADC_GRP1_NUM_CHANNELS),
-  0,
-  ADC_SQR3_SQ2_N(ADC_CHANNEL_SENSOR) | ADC_SQR3_SQ1_N(ADC_CHANNEL_VREFINT)
-};
+#define EP_ROUND_0_INPUTS 56
+#define EP_ROUND_1_INPUTS 64
+#define EP_ROUND_2_INPUTS 17
+#define EP_ROUND_RAW_INPUTS 32
+#define EP_ROUND_RAW_DATA_INPUTS 32
 
-/*
- * ADC end conversion callback.
- */
-static void adccb (adcsample_t *buffer, size_t n)
-{
-  ADCDriver *adcp = &ADCD1;
+static uint8_t ep_round;
 
-  (void) buffer; (void) n;
-  if (adcp->ad_state == ADC_COMPLETE)
-    chEvtSignalI (rng_thread, ADC_DATA_AVAILABLE);
-}
-\f
 /*
- * TinyMT routines.
+ * Hash_df initial string:
  *
- * See
- * "Tiny Mersenne Twister (TinyMT): A small-sized variant of Mersenne Twister"
- * by Mutsuo Saito and Makoto Matsumoto
- *     http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/TINYMT/
+ *  1,          : counter = 1
+ *  0, 0, 1, 0  : no_of_bits_returned (in big endian)
  */
+static void ep_fill_initial_string (void)
+{
+  adc_buf[0] = 0x01000001; /* Regardless of endian */
+  adc_buf[1] = (CRC->DR & 0xffffff00);
+}
 
-/* Use the first example of TinyMT */
-#define TMT_MAT1 0x8f7011ee
-#define TMT_MAT2 0xfc78ff1f
-#define TMT_TMAT 0x3793fdff
+static void ep_init (int mode)
+{
+  chEvtClearFlags (ADC_DATA_AVAILABLE);
+  if (mode == NEUG_MODE_RAW)
+    {
+      ep_round = EP_ROUND_RAW;
+      adc_start_conversion (ADC_CRC32_MODE, adc_buf, EP_ROUND_RAW_INPUTS);
+    }
+  else if (mode == NEUG_MODE_RAW_DATA)
+    {
+      ep_round = EP_ROUND_RAW_DATA;
+      adc_start_conversion (ADC_SAMPLE_MODE, adc_buf, EP_ROUND_RAW_DATA_INPUTS);
+    }
+  else
+    {
+      ep_round = EP_ROUND_0;
+      ep_fill_initial_string ();
+      adc_start_conversion (ADC_CRC32_MODE,
+                           &adc_buf[2], EP_ROUND_0_INPUTS);
+    }
+}
 
-static uint32_t tmt[4];
+static void noise_source_continuous_test (uint8_t noise);
 
-static void tmt_one_step (void);
+static void ep_fill_wbuf (int i, int flip, int test)
+{
+  uint32_t v = adc_buf[i];
 
-#define TMT_INIT_MIN_LOOP 8
-#define TMT_INIT_PRE_LOOP 8
+  if (test)
+    {
+      uint8_t b0, b1, b2, b3;
 
-/**
- * @brief  TinyMT initialize function.
- */
-static void tmt_init (uint32_t seed)
-{
-  int i;
+      b3 = v >> 24;
+      b2 = v >> 16;
+      b1 = v >> 8;
+      b0 = v;
 
-  tmt[0] = seed;
-  tmt[1] = TMT_MAT1;
-  tmt[2] = TMT_MAT2;
-  tmt[3] = TMT_TMAT;
-
-  for (i = 1; i < TMT_INIT_MIN_LOOP; i++)
-    tmt[i & 3] ^= i + UINT32_C(1812433253) * (tmt[(i - 1) & 3]
-                                             ^ (tmt[(i - 1) & 3] >> 30));
-
-  if ((tmt[0] & 0x7fffffff) == 0 && tmt[1] == 0 && tmt[2] == 0 && tmt[3] == 0)
-    {                          /* Prevent all zero */
-      tmt[0] = 'T';
-      tmt[1] = 'I';
-      tmt[2] = 'N';
-      tmt[3] = 'Y';
+      noise_source_continuous_test (b0);
+      noise_source_continuous_test (b1);
+      noise_source_continuous_test (b2);
+      noise_source_continuous_test (b3);
     }
 
-  for (i = 0; i < TMT_INIT_PRE_LOOP; i++)
-    tmt_one_step ();
+  if (flip)
+    v = __builtin_bswap32 (v);
+
+  sha256_ctx_data.wbuf[i] = v;
 }
 
-/**
- * @brief  TinyMT one step function, call this every time before tmt_value.
- */
-static void tmt_one_step (void)
+/* Here assumes little endian architecture.  */
+static int ep_process (int mode)
 {
-  uint32_t x, y;
-
-  y = tmt[3];
-  x = (tmt[0] & 0x7fffffff) ^ tmt[1] ^ tmt[2];
-  x ^= (x << 1);
-  y ^= (y >> 1) ^ x;
-  tmt[0] = tmt[1];
-  tmt[1] = tmt[2];
-  tmt[2] = x ^ (y << 10);
-  tmt[3] = y;
-  if ((y & 1))
+  int i, n;
+
+  if (ep_round == EP_ROUND_RAW)
+    {
+      for (i = 0; i < EP_ROUND_RAW_INPUTS / 4; i++)
+       ep_fill_wbuf (i, 0, 1);
+
+      ep_init (mode);
+      return EP_ROUND_RAW_INPUTS / 4;
+    }
+  else if (ep_round == EP_ROUND_RAW_DATA)
+    {
+      for (i = 0; i < EP_ROUND_RAW_DATA_INPUTS / 4; i++)
+       ep_fill_wbuf (i, 0, 0);
+
+      ep_init (mode);
+      return EP_ROUND_RAW_DATA_INPUTS / 4;
+    }
+
+  if (ep_round == EP_ROUND_0)
+    {
+      for (i = 0; i < 64 / 4; i++)
+       ep_fill_wbuf (i, 1, 1);
+
+      adc_start_conversion (ADC_CRC32_MODE, adc_buf, EP_ROUND_1_INPUTS);
+      sha256_start (&sha256_ctx_data);
+      sha256_process (&sha256_ctx_data);
+      ep_round++;
+      return 0;
+    }
+  else if (ep_round == EP_ROUND_1)
+    {
+      for (i = 0; i < 64 / 4; i++)
+       ep_fill_wbuf (i, 1, 1);
+
+      adc_start_conversion (ADC_CRC32_MODE, adc_buf, EP_ROUND_2_INPUTS);
+      sha256_process (&sha256_ctx_data);
+      ep_round++;
+      return 0;
+    }
+  else
     {
-      tmt[1] ^= TMT_MAT1;
-      tmt[2] ^= TMT_MAT2;
+      for (i = 0; i < (EP_ROUND_2_INPUTS + 3) / 4; i++)
+       ep_fill_wbuf (i, 0, 1);
+
+      n = SHA256_DIGEST_SIZE / 2;
+      ep_init (NEUG_MODE_CONDITIONED); /* The three-byte is used here.  */
+      memcpy (((uint8_t *)sha256_ctx_data.wbuf)
+             + ((NUM_NOISE_INPUTS+5)%SHA256_BLOCK_SIZE),
+             sha256_output, n); /* Don't use the last three-byte.  */
+      sha256_ctx_data.total[0] = 5 + NUM_NOISE_INPUTS + n;
+      sha256_finish (&sha256_ctx_data, (uint8_t *)sha256_output);
+      return SHA256_DIGEST_SIZE / sizeof (uint32_t);
     }
 }
 
-/**
- * @brief  Get a random word (32-bit).
- */
-static uint32_t tmt_value (void)
+
+static const uint32_t *ep_output (int mode)
 {
-  uint32_t t0, t1;
-
-  t0 = tmt[3];
-  t1 = tmt[0] + (tmt[2] >> 8);
-  t0 ^= t1;
-  if ((t1 & 1))
-    t0 ^= TMT_TMAT;
-  return t0;
+  if (mode)
+    return sha256_ctx_data.wbuf;
+  else
+    return sha256_output;
 }
+\f
+#define REPETITION_COUNT           1
+#define ADAPTIVE_PROPORTION_64     2
+#define ADAPTIVE_PROPORTION_4096   4
 
-/* 8 parallel CRC-16 shift registers, with randomly rotated feedback */
-#define EPOOL_SIZE 16
-static uint8_t epool[EPOOL_SIZE];      /* Big-endian */
-static uint8_t ep_count;
+uint8_t neug_err_state;
+uint16_t neug_err_cnt;
+uint16_t neug_err_cnt_rc;
+uint16_t neug_err_cnt_p64;
+uint16_t neug_err_cnt_p4k;
 
-/*
- * Magic number seven.
- *
- * We did an experiment of measuring entropy of ADC output with MUST.
- * The entropy of a byte by raw sampling of LSBs has more than 6.0 bit/byte.
- * So, it is considered OK to get 4-byte from 7-byte (6x7 = 42 > 32).
- */
-#define NUM_NOISE_INPUTS 7
+uint16_t neug_rc_max;
+uint16_t neug_p64_max;
+uint16_t neug_p4k_max;
 
-#define SHIFT_RIGHT(f) ((f)>>1)
+#include "board.h"
 
-static void ep_add (uint8_t entropy_bits, uint8_t another_random_bit)
+static void noise_source_cnt_max_reset (void)
 {
-  uint8_t v = epool[ep_count];
-
-  /* CRC-16-CCITT's Polynomial is: x^16 + x^12 + x^5 + 1 */
-  epool[(ep_count - 12)& 0x0f] ^= v;
-  epool[(ep_count - 5)& 0x0f] ^= v;
-  epool[ep_count] = SHIFT_RIGHT (v) ^ entropy_bits;
+  neug_err_cnt = neug_err_cnt_rc = neug_err_cnt_p64 = neug_err_cnt_p4k = 0;
+  neug_rc_max = neug_p64_max = neug_p4k_max = 0;
+}
 
-  if ((v&1) || another_random_bit)
-    epool[ep_count] ^= 0xff;
+static void noise_source_error_reset (void)
+{
+  neug_err_state = 0;
+}
 
-  ep_count = (ep_count + 1) & 0x0f;
+static void noise_source_error (uint32_t err)
+{
+  neug_err_state |= err;
+  neug_err_cnt++;
+
+  if ((err & REPETITION_COUNT))
+    neug_err_cnt_rc++;
+  if ((err & ADAPTIVE_PROPORTION_64))
+    neug_err_cnt_p64++;
+  if ((err & ADAPTIVE_PROPORTION_4096))
+    neug_err_cnt_p4k++;
 }
 
-#define FNV_INIT       2166136261U
-#define FNV_PRIME      16777619
+/*
+ * For health tests, we assume that the device noise source has
+ * min-entropy >= 4.2.  Observing raw data stream (before CRC-32) has
+ * more than 4.2 bit/byte entropy.  When the data stream after CRC-32
+ * filter will be less than 4.2 bit/byte entropy, that must be
+ * something wrong.  Note that even we observe < 4.2, we still have
+ * some margin, since we use NUM_NOISE_INPUTS=140.
+ *
+ */
+
+/* Cuttoff = 9, when min-entropy = 4.2, W= 2^-30 */
+/* ceiling of (1+30/4.2) */
+#define REPITITION_COUNT_TEST_CUTOFF 9
 
-static uint32_t fnv32_hash (const uint8_t *buf, int len)
-{
-  uint32_t v = FNV_INIT;
-  int i;
+static uint8_t rct_a;
+static uint8_t rct_b;
 
-  for (i = 0; i < len; i++)
+static void repetition_count_test (uint8_t sample)
+{
+  if (rct_a == sample)
     {
-      v ^= buf[i];
-      v *= FNV_PRIME;
+      rct_b++;
+      if (rct_b >= REPITITION_COUNT_TEST_CUTOFF)
+       noise_source_error (REPETITION_COUNT);
+      if (rct_b > neug_rc_max)
+       neug_rc_max = rct_b;
+   }
+  else
+    {
+      rct_a = sample;
+      rct_b = 1;
     }
-
-  return v;
 }
 
-#define PROBABILITY_50_BY_TICK() ((SysTick->VAL & 0x02) != 0)
+/* Cuttoff = 18, when min-entropy = 4.2, W= 2^-30 */
+/* With R, qbinom(1-2^-30,64,2^-4.2) */
+#define ADAPTIVE_PROPORTION_64_TEST_CUTOFF 18
 
-static uint32_t ep_output (void)
-{
-  int i;
-  uint8_t buf[NUM_NOISE_INPUTS];
-  uint8_t *p = buf;
+static uint8_t ap64t_a;
+static uint8_t ap64t_b;
+static uint8_t ap64t_s;
 
-  /*
-   * NUM_NOISE_INPUTS is seven.
-   *
-   * There are sixteen bytes in the CRC-16 buffer.  We use seven
-   * outputs of CRC-16 buffer for final output.  There are two parts;
-   * former 4 outputs which will be used directly, and latter 3
-   * outputs which will be used with feedback loop.
-   */
+static void adaptive_proportion_64_test (uint8_t sample)
+{
+  if (ap64t_s >= 64)
+    {
+      ap64t_a = sample;
+      ap64t_s = 0;
+      ap64t_b = 0;
+    }
+  else
+    {
+      ap64t_s++;
+      if (ap64t_a == sample)
+       {
+         ap64t_b++;
+         if (ap64t_b > ADAPTIVE_PROPORTION_64_TEST_CUTOFF)
+           noise_source_error (ADAPTIVE_PROPORTION_64);
+         if (ap64t_b > neug_p64_max)
+           neug_p64_max = ap64t_b;
+       }
+    }
+}
 
-  /* At some probability, use latter 3 outputs of CRC-16 buffer */
-  for (i = NUM_NOISE_INPUTS - 1; i >= 4; i--)
-    if (PROBABILITY_50_BY_TICK ())
-      *p++ = epool[(ep_count+i) & 0x0f] ^ epool[(ep_count+i-4) & 0x0f];
+/* Cuttoff = 315, when min-entropy = 4.2, W= 2^-30 */
+/* With R, qbinom(1-2^-30,4096,2^-4.2) */
+#define ADAPTIVE_PROPORTION_4096_TEST_CUTOFF 315
 
-  /* Use former 4 outputs of CRC-16 buffer */
-  for (i = 3; i >= 0; i--)
-    *p++ = epool[(ep_count+i) & 0x0f];
+static uint8_t ap4096t_a;
+static uint16_t ap4096t_b;
+static uint16_t ap4096t_s;
 
-  return fnv32_hash (buf, p - buf);
+static void adaptive_proportion_4096_test (uint8_t sample)
+{
+  if (ap4096t_s >= 4096)
+    {
+      ap4096t_a = sample;
+      ap4096t_s = 0;
+      ap4096t_b = 0;
+    }
+  else
+    {
+      ap4096t_s++;
+      if (ap4096t_a == sample)
+       {
+         ap4096t_b++;
+         if (ap4096t_b > ADAPTIVE_PROPORTION_4096_TEST_CUTOFF)
+           noise_source_error (ADAPTIVE_PROPORTION_4096);
+         if (ap4096t_b > neug_p4k_max)
+           neug_p4k_max = ap4096t_b;
+       }
+    }
 }
 
-
+static void noise_source_continuous_test (uint8_t noise)
+{
+  repetition_count_test (noise);
+  adaptive_proportion_64_test (noise);
+  adaptive_proportion_4096_test (noise);
+}
+\f
 /*
  * Ring buffer, filled by generator, consumed by neug_get routine.
  */
@@ -286,55 +400,7 @@ static uint32_t rb_del (struct rng_rb *rb)
   return v;
 }
 
-/**
- * @brief  Random number generation from ADC sampling.
- * @param  RB: Pointer to ring buffer structure
- * @return -1 when failure, 0 otherwise.
- * @note   Called holding the mutex, with RB->full == 0.
- *         Keep generating until RB->full == 1.
- */
-static int rng_gen (struct rng_rb *rb)
-{
-  static uint8_t round = 0;
-  uint8_t b;
-
-  while (1)
-    {
-      chEvtWaitOne (ADC_DATA_AVAILABLE);
-
-      /* Got, ADC sampling data */
-      round++;
-      b = (((samp[0] & 0x01) << 0) | ((samp[1] & 0x01) << 1)
-          | ((samp[2] & 0x01) << 2) | ((samp[3] & 0x01) << 3)
-          | ((samp[4] & 0x01) << 4) | ((samp[5] & 0x01) << 5)
-          | ((samp[6] & 0x01) << 6) | ((samp[7] & 0x01) << 7));
-
-      adcStartConversion (&ADCD1, &adcgrpcfg, samp, ADC_GRP1_BUF_DEPTH, adccb);
-
-      /*
-       * Put a random byte to entropy pool.
-       */
-      ep_add (b, PROBABILITY_50_BY_TICK ());
-
-      if ((round % NUM_NOISE_INPUTS) == 0)
-       {                           /* We have enough entropy in the pool.  */
-         uint32_t v = ep_output (); /* Get the random bits from the pool.  */
-
-         /* Mix the random bits from the pool with the output of PRNG.  */
-         tmt_one_step ();
-         v ^= tmt_value ();
-
-         /* We got the final random bits, add it to the ring buffer.  */
-         rb_add (rb, v);
-         round = 0;
-         if (rb->full)
-           /* fully generated */
-           break;
-       }
-    }
-
-  return 0;                    /* success */
-}
+uint8_t neug_mode;
 
 /**
  * @brief Random number generation thread.
@@ -345,24 +411,56 @@ static msg_t rng (void *arg)
 
   rng_thread = chThdSelf ();
 
-  adcStart (&ADCD1, NULL);
-  adcStartConversion (&ADCD1, &adcgrpcfg, samp, ADC_GRP1_BUF_DEPTH, adccb);
+  /* Enable ADCs */
+  adc_start ();
 
-  while (1)
+  ep_init (NEUG_MODE_CONDITIONED);
+
+  while (!chThdShouldTerminate ())
     {
-      chMtxLock (&rb->m);
-      while (rb->full)
-       chCondWait (&rb->space_available);
-      rng_gen (rb);
-      chCondSignal (&rb->data_available);
-      chMtxUnlock ();
+      int n;
+      int mode = neug_mode;
+
+      chEvtWaitOne (ADC_DATA_AVAILABLE); /* Get ADC sampling.  */
+
+      if ((n = ep_process (mode)))
+       {
+         int i;
+         const uint32_t *vp;
+
+         if (neug_err_state != 0
+             && (mode == NEUG_MODE_CONDITIONED || mode == NEUG_MODE_RAW))
+           {
+             /* Don't use the result and do it again.  */
+             noise_source_error_reset ();
+             continue;
+           }
+
+         vp = ep_output (mode);
+
+         chMtxLock (&rb->m);
+         while (rb->full)
+           chCondWait (&rb->space_available);
+
+         for (i = 0; i < n; i++)
+           {
+             rb_add (rb, *vp++);
+             if (rb->full)
+               break;
+           }
+
+         chCondSignal (&rb->data_available);
+         chMtxUnlock ();
+       }
     }
 
+  adc_stop ();
+
   return 0;
 }
 
 static struct rng_rb the_ring_buffer;
-static WORKING_AREA(wa_rng, 128);
+static WORKING_AREA(wa_rng, 256);
 
 /**
  * @brief Initialize NeuG.
@@ -370,9 +468,21 @@ static WORKING_AREA(wa_rng, 128);
 void
 neug_init (uint32_t *buf, uint8_t size)
 {
+  const uint32_t *u = (const uint32_t *)unique_device_id ();
   struct rng_rb *rb = &the_ring_buffer;
+  int i;
+
+  RCC->AHBENR |= RCC_AHBENR_CRCEN;
+  CRC->CR = CRC_CR_RESET;
 
-  tmt_init (0);
+  /*
+   * This initialization ensures that it generates different sequence
+   * even if all physical conditions are same.
+   */
+  for (i = 0; i < 3; i++)
+    CRC->DR = *u++;
+
+  neug_mode = NEUG_MODE_CONDITIONED;
   rb_init (rb, buf, size);
   chThdCreateStatic (wa_rng, sizeof (wa_rng), NORMALPRIO, rng, rb);
 }
@@ -392,17 +502,6 @@ neug_flush (void)
   chMtxUnlock ();
 }
 
-/**
- * @breif Set seed to PRNG
- */
-void
-neug_prng_reseed (void)
-{
-  uint32_t seed = ep_output ();
-
-  tmt_init (seed);
-  neug_flush ();
-}
 
 /**
  * @brief  Wakes up RNG thread to generate random numbers.
@@ -441,6 +540,45 @@ neug_get (int kick)
   return v;
 }
 
+int
+neug_get_nonblock (uint32_t *p)
+{
+  struct rng_rb *rb = &the_ring_buffer;
+  int r = 0;
+
+  chMtxLock (&rb->m);
+  if (rb->empty)
+    {
+      r = -1;
+      chCondSignal (&rb->space_available);
+    }
+  else
+    *p = rb_del (rb);
+  chMtxUnlock ();
+
+  return r;
+}
+
+int neug_consume_random (void (*proc) (uint32_t, int))
+{
+  int i = 0;
+  struct rng_rb *rb = &the_ring_buffer;
+
+  chMtxLock (&rb->m);
+  while (!rb->empty)
+    {
+      uint32_t v;
+
+      v = rb_del (rb);
+      proc (v, i);
+      i++;
+    }
+  chCondSignal (&rb->space_available);
+  chMtxUnlock ();
+
+  return i;
+}
+
 void
 neug_wait_full (void)
 {
@@ -451,3 +589,32 @@ neug_wait_full (void)
     chCondWait (&rb->data_available);
   chMtxUnlock ();
 }
+
+void
+neug_fini (void)
+{
+  if (rng_thread)
+    {
+      chThdTerminate (rng_thread);
+      neug_get (1);
+      chThdWait (rng_thread);
+      rng_thread = NULL;
+    }
+}
+
+void
+neug_mode_select (uint8_t mode)
+{
+  if (neug_mode == mode)
+    return;
+
+  neug_wait_full ();
+
+  while (rng_thread->p_state != THD_STATE_WTCOND)
+    chThdSleep (MS2ST (1));
+
+  ep_init (mode);
+  noise_source_cnt_max_reset ();
+  neug_mode = mode;
+  neug_flush ();
+}
index 7d669f6..04a223b 100644 (file)
@@ -1,11 +1,28 @@
 #define NEUG_NO_KICK      0
 #define NEUG_KICK_FILLING 1
 
-#define NEUG_PRE_LOOP 16
+#define NEUG_PRE_LOOP 32
+
+#define NEUG_MODE_CONDITIONED 0
+#define NEUG_MODE_RAW         1
+#define NEUG_MODE_RAW_DATA    2
+
+extern uint8_t neug_mode;
+extern uint16_t neug_err_cnt;
+extern uint16_t neug_err_cnt_rc;
+extern uint16_t neug_err_cnt_p64;
+extern uint16_t neug_err_cnt_p4k;
+extern uint16_t neug_rc_max;
+extern uint16_t neug_p64_max;
+extern uint16_t neug_p4k_max;
 
 void neug_init (uint32_t *buf, uint8_t size);
-void neug_prng_reseed (void);
 uint32_t neug_get (int kick);
+int neug_get_nonblock (uint32_t *p);
 void neug_kick_filling (void);
 void neug_flush (void);
 void neug_wait_full (void);
+void neug_fini (void);
+void neug_mode_select (uint8_t mode);
+
+int neug_consume_random (void (*proc) (uint32_t, int));
index af0306f..ee97b04 100644 (file)
@@ -1118,7 +1118,7 @@ GPGthread (void *arg)
 
   gpg_init ();
 
-  chEvtClear (ALL_EVENTS);
+  chEvtClearFlags (ALL_EVENTS);
 
   while (!chThdShouldTerminate ())
     {
@@ -1216,7 +1216,7 @@ GPGthread (void *arg)
       process_command_apdu ();
       led_blink (LED_FINISH_COMMAND);
     done:
-      chEvtSignal (icc_thread, EV_EXEC_FINISHED);
+      chEvtSignalFlags (icc_thread, EV_EXEC_FINISHED);
     }
 
   gpg_fini ();
index 7f0b7bc..cc6dcd1 100644 (file)
@@ -38,8 +38,6 @@ random_init (void)
 
   for (i = 0; i < NEUG_PRE_LOOP; i++)
     (void)neug_get (NEUG_KICK_FILLING);
-
-  neug_prng_reseed ();
 }
 
 /*
index 8cd0ebc..48eea3c 100644 (file)
@@ -310,7 +310,7 @@ static void notify_tx (struct ep_in *epi)
   struct ccid *c = (struct ccid *)epi->priv;
 
   /* The sequence of Bulk-IN transactions finished */
-  chEvtSignalI (c->icc_thread, EV_TX_FINISHED);
+  chEvtSignalFlagsI (c->icc_thread, EV_TX_FINISHED);
 }
 
 static void no_buf (struct ep_in *epi, size_t len)
@@ -405,7 +405,7 @@ static void notify_icc (struct ep_out *epo)
   struct ccid *c = (struct ccid *)epo->priv;
 
   c->err = epo->err;
-  chEvtSignalI (c->icc_thread, EV_RX_DATA_READY);
+  chEvtSignalFlagsI (c->icc_thread, EV_RX_DATA_READY);
 }
 
 static int end_icc_rx (struct ep_out *epo, size_t orig_len)
@@ -815,7 +815,7 @@ icc_power_off (struct ccid *c)
   if (c->application)
     {
       chThdTerminate (c->application);
-      chEvtSignal (c->application, EV_NOP);
+      chEvtSignalFlags (c->application, EV_NOP);
       chThdWait (c->application);
       c->application = NULL;
     }
@@ -1140,7 +1140,7 @@ icc_handle_data (struct ccid *c)
                      c->a->res_apdu_data_len = 0;
                      c->a->res_apdu_data = &icc_buffer[5];
 
-                     chEvtSignal (c->application, EV_CMD_AVAILABLE);
+                     chEvtSignalFlags (c->application, EV_CMD_AVAILABLE);
                      next_state = ICC_STATE_EXECUTE;
                    }
                }
@@ -1199,7 +1199,7 @@ icc_handle_data (struct ccid *c)
              c->a->res_apdu_data_len = 0;
              c->a->res_apdu_data = &c->p[5];
 
-             chEvtSignal (c->application, EV_VERIFY_CMD_AVAILABLE);
+             chEvtSignalFlags (c->application, EV_VERIFY_CMD_AVAILABLE);
              next_state = ICC_STATE_EXECUTE;
            }
          else if (c->p[10-10] == 0x01) /* PIN Modification */
@@ -1233,7 +1233,7 @@ icc_handle_data (struct ccid *c)
              c->a->res_apdu_data_len = 0;
              c->a->res_apdu_data = &icc_buffer[5];
 
-             chEvtSignal (c->application, EV_MODIFY_CMD_AVAILABLE);
+             chEvtSignalFlags (c->application, EV_MODIFY_CMD_AVAILABLE);
              next_state = ICC_STATE_EXECUTE;
            }
          else
@@ -1307,7 +1307,7 @@ USBthread (void *arg)
   ccid_init (c, epi, epo, a, chThdSelf ());
   apdu_init (a);
 
-  chEvtClear (ALL_EVENTS);
+  chEvtClearFlags (ALL_EVENTS);
 
   icc_prepare_receive (c);
   while (1)
diff --git a/src/usb_lld.c b/src/usb_lld.c
deleted file mode 100644 (file)
index df0c2f9..0000000
+++ /dev/null
@@ -1,1213 +0,0 @@
-#ifdef FREE_STANDING
-#include "types.h"
-#else
-#include "ch.h"
-#include "hal.h"
-#endif
-#include "sys.h"
-#include "usb_lld.h"
-
-#define USB_MAX_PACKET_SIZE 64 /* For FS device */
-
-enum STANDARD_REQUESTS
-{
-  GET_STATUS = 0,
-  CLEAR_FEATURE,
-  RESERVED1,
-  SET_FEATURE,
-  RESERVED2,
-  SET_ADDRESS,
-  GET_DESCRIPTOR,
-  SET_DESCRIPTOR,
-  GET_CONFIGURATION,
-  SET_CONFIGURATION,
-  GET_INTERFACE,
-  SET_INTERFACE,
-  SYNCH_FRAME,
-  TOTAL_REQUEST  /* Total number of Standard request */
-};
-
-/* The state machine states of a control pipe */
-enum CONTROL_STATE
-{
-  WAIT_SETUP,
-  SETTING_UP,
-  IN_DATA,
-  OUT_DATA,
-  LAST_IN_DATA,
-  WAIT_STATUS_IN,
-  WAIT_STATUS_OUT,
-  STALLED,
-  PAUSE
-};
-
-enum FEATURE_SELECTOR
-{
-  ENDPOINT_STALL,
-  DEVICE_REMOTE_WAKEUP
-};
-
-struct DATA_INFO
-{
-  uint16_t len;
-  uint16_t offset;
-  uint8_t *addr;
-  uint8_t require_zlp;
-};
-
-struct CONTROL_INFO
-{
-  uint8_t bmRequestType;
-  uint8_t bRequest;
-  uint16_t wValue;
-  uint16_t wIndex;
-  uint16_t wLength;
-};
-
-struct DEVICE_INFO
-{
-  uint8_t current_configuration;
-  uint8_t current_feature;
-  uint8_t state;
-};
-
-static struct CONTROL_INFO control_info;
-static struct DEVICE_INFO device_info;
-static struct DATA_INFO data_info;
-extern const struct usb_device_method Device_Method;
-
-static struct CONTROL_INFO *const ctrl_p = &control_info;
-static struct DEVICE_INFO *const dev_p = &device_info;
-static struct DATA_INFO *const data_p = &data_info;
-static const struct usb_device_method *const method_p = &Device_Method;
-
-#define REG_BASE  (0x40005C00UL) /* USB_IP Peripheral Registers base address */
-#define PMA_ADDR  (0x40006000UL) /* USB_IP Packet Memory Area base address   */
-
-/* Control register */
-#define CNTR    ((__IO uint16_t *)(REG_BASE + 0x40))
-/* Interrupt status register */
-#define ISTR    ((__IO uint16_t *)(REG_BASE + 0x44))
-/* Frame number register */
-#define FNR     ((__IO uint16_t *)(REG_BASE + 0x48))
-/* Device address register */
-#define DADDR   ((__IO uint16_t *)(REG_BASE + 0x4C))
-/* Buffer Table address register */
-#define BTABLE  ((__IO uint16_t *)(REG_BASE + 0x50))
-
-#define ISTR_CTR    (0x8000) /* Correct TRansfer (clear-only bit) */
-#define ISTR_DOVR   (0x4000) /* DMA OVeR/underrun (clear-only bit) */
-#define ISTR_ERR    (0x2000) /* ERRor (clear-only bit) */
-#define ISTR_WKUP   (0x1000) /* WaKe UP (clear-only bit) */
-#define ISTR_SUSP   (0x0800) /* SUSPend (clear-only bit) */
-#define ISTR_RESET  (0x0400) /* RESET (clear-only bit) */
-#define ISTR_SOF    (0x0200) /* Start Of Frame (clear-only bit) */
-#define ISTR_ESOF   (0x0100) /* Expected Start Of Frame (clear-only bit) */
-
-#define ISTR_DIR    (0x0010)  /* DIRection of transaction (read-only bit)  */
-#define ISTR_EP_ID  (0x000F)  /* EndPoint IDentifier (read-only bit)  */
-
-#define CLR_CTR    (~ISTR_CTR)   /* clear Correct TRansfer bit */
-#define CLR_DOVR   (~ISTR_DOVR)  /* clear DMA OVeR/underrun bit*/
-#define CLR_ERR    (~ISTR_ERR)   /* clear ERRor bit */
-#define CLR_WKUP   (~ISTR_WKUP)  /* clear WaKe UP bit     */
-#define CLR_SUSP   (~ISTR_SUSP)  /* clear SUSPend bit     */
-#define CLR_RESET  (~ISTR_RESET) /* clear RESET bit      */
-#define CLR_SOF    (~ISTR_SOF)   /* clear Start Of Frame bit   */
-#define CLR_ESOF   (~ISTR_ESOF)  /* clear Expected Start Of Frame bit */
-
-#define CNTR_CTRM   (0x8000) /* Correct TRansfer Mask */
-#define CNTR_DOVRM  (0x4000) /* DMA OVeR/underrun Mask */
-#define CNTR_ERRM   (0x2000) /* ERRor Mask */
-#define CNTR_WKUPM  (0x1000) /* WaKe UP Mask */
-#define CNTR_SUSPM  (0x0800) /* SUSPend Mask */
-#define CNTR_RESETM (0x0400) /* RESET Mask   */
-#define CNTR_SOFM   (0x0200) /* Start Of Frame Mask */
-#define CNTR_ESOFM  (0x0100) /* Expected Start Of Frame Mask */
-
-#define CNTR_RESUME (0x0010) /* RESUME request */
-#define CNTR_FSUSP  (0x0008) /* Force SUSPend */
-#define CNTR_LPMODE (0x0004) /* Low-power MODE */
-#define CNTR_PDWN   (0x0002) /* Power DoWN */
-#define CNTR_FRES   (0x0001) /* Force USB RESet */
-
-#define DADDR_EF (0x80)
-#define DADDR_ADD (0x7F)
-
-#define EP_CTR_RX      (0x8000) /* EndPoint Correct TRansfer RX */
-#define EP_DTOG_RX     (0x4000) /* EndPoint Data TOGGLE RX */
-#define EPRX_STAT      (0x3000) /* EndPoint RX STATus bit field */
-#define EP_SETUP       (0x0800) /* EndPoint SETUP */
-#define EP_T_FIELD     (0x0600) /* EndPoint TYPE */
-#define EP_KIND        (0x0100) /* EndPoint KIND */
-#define EP_CTR_TX      (0x0080) /* EndPoint Correct TRansfer TX */
-#define EP_DTOG_TX     (0x0040) /* EndPoint Data TOGGLE TX */
-#define EPTX_STAT      (0x0030) /* EndPoint TX STATus bit field */
-#define EPADDR_FIELD   (0x000F) /* EndPoint ADDRess FIELD */
-
-#define EPREG_MASK     (EP_CTR_RX|EP_SETUP|EP_T_FIELD|EP_KIND|EP_CTR_TX|EPADDR_FIELD)
-
-/* STAT_TX[1:0] STATus for TX transfer */
-#define EP_TX_DIS      (0x0000) /* EndPoint TX DISabled */
-#define EP_TX_STALL    (0x0010) /* EndPoint TX STALLed */
-#define EP_TX_NAK      (0x0020) /* EndPoint TX NAKed */
-#define EP_TX_VALID    (0x0030) /* EndPoint TX VALID */
-#define EPTX_DTOG1     (0x0010) /* EndPoint TX Data TOGgle bit1 */
-#define EPTX_DTOG2     (0x0020) /* EndPoint TX Data TOGgle bit2 */
-
-/* STAT_RX[1:0] STATus for RX transfer */
-#define EP_RX_DIS      (0x0000) /* EndPoint RX DISabled */
-#define EP_RX_STALL    (0x1000) /* EndPoint RX STALLed */
-#define EP_RX_NAK      (0x2000) /* EndPoint RX NAKed */
-#define EP_RX_VALID    (0x3000) /* EndPoint RX VALID */
-#define EPRX_DTOG1     (0x1000) /* EndPoint RX Data TOGgle bit1 */
-#define EPRX_DTOG2     (0x2000) /* EndPoint RX Data TOGgle bit1 */
-
-static void usb_handle_transfer (void);
-
-static void st103_set_btable (void)
-{
-  *BTABLE = 0;
-}
-
-static uint16_t st103_get_istr (void)
-{
-  return *ISTR;
-}
-
-static void st103_set_istr (uint16_t istr)
-{
-  *ISTR = istr;
-}
-
-static void st103_set_cntr (uint16_t cntr)
-{
-  *CNTR = cntr;
-}
-
-static void st103_set_daddr (uint16_t daddr)
-{
-  *DADDR  = daddr | DADDR_EF;
-}
-
-static void st103_set_epreg (uint8_t ep_num, uint16_t value)
-{
-  uint16_t *reg_p = (uint16_t *)(REG_BASE + ep_num*4);
-
-  *reg_p = value;
-}
-
-static uint16_t st103_get_epreg (uint8_t ep_num)
-{
-  uint16_t *reg_p = (uint16_t *)(REG_BASE + ep_num*4);
-
-  return *reg_p;
-}
-
-static void st103_set_tx_addr (uint8_t ep_num, uint16_t addr)
-{
-  uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+0)*2);
-
-  *reg_p = addr;
-}
-
-static uint16_t st103_get_tx_addr (uint8_t ep_num)
-{
-  uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+0)*2);
-
-  return *reg_p;
-}
-
-
-static void st103_set_tx_count (uint8_t ep_num, uint16_t size)
-{
-  uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+2)*2);
-
-  *reg_p = size;
-}
-
-static uint16_t st103_get_tx_count (uint8_t ep_num)
-{
-  uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+2)*2);
-
-  return *reg_p  & 0x03ff;
-}
-
-
-static void st103_set_rx_addr (uint8_t ep_num, uint16_t addr)
-{
-  uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+4)*2);
-
-  *reg_p = addr;
-}
-
-static uint16_t st103_get_rx_addr (uint8_t ep_num)
-{
-  uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+4)*2);
-
-  return *reg_p;
-}
-
-
-static void st103_set_rx_buf_size (uint8_t ep_num, uint16_t size)
-{                              /* Assume size is even */
-  uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+6)*2);
-  uint16_t value;
-
-  if (size <= 62)
-    value = (size & 0x3e) << 9;
-  else
-    value = 0x8000 | (((size >> 5) - 1) << 10);
-
-  *reg_p = value;
-}
-
-static uint16_t st103_get_rx_count (uint8_t ep_num)
-{
-  uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+6)*2);
-
-  return *reg_p & 0x03ff;
-}
-
-
-static void st103_ep_clear_ctr_rx (uint8_t ep_num)
-{
-  uint16_t value = st103_get_epreg (ep_num) & ~EP_CTR_RX & EPREG_MASK;
-
-  st103_set_epreg (ep_num, value);
-}
-
-static void st103_ep_clear_ctr_tx (uint8_t ep_num)
-{
-  uint16_t value = st103_get_epreg (ep_num) & ~EP_CTR_TX & EPREG_MASK;
-
-  st103_set_epreg (ep_num, value);
-}
-
-static void st103_ep_set_rxtx_status (uint8_t ep_num, uint16_t st_rx,
-                                     uint16_t st_tx)
-{
-  uint16_t value = st103_get_epreg (ep_num);
-
-  value &= (EPREG_MASK|EPRX_STAT|EPTX_STAT);
-  value ^= (EPRX_DTOG1 & st_rx);
-  value ^= (EPRX_DTOG2 & st_rx);
-  value ^= (EPTX_DTOG1 & st_tx);
-  value ^= (EPTX_DTOG2 & st_tx);
-  value |= EP_CTR_RX | EP_CTR_TX;
-  st103_set_epreg (ep_num, value);
-}
-
-static void st103_ep_set_rx_status (uint8_t ep_num, uint16_t st_rx)
-{
-  uint16_t value = st103_get_epreg (ep_num);
-
-  value &= (EPREG_MASK|EPRX_STAT);
-  value ^= (EPRX_DTOG1 & st_rx);
-  value ^= (EPRX_DTOG2 & st_rx);
-  value |= EP_CTR_RX | EP_CTR_TX;
-  st103_set_epreg (ep_num, value);
-}
-
-static uint16_t st103_ep_get_rx_status (uint8_t ep_num)
-{
-  uint16_t value = st103_get_epreg (ep_num);
-
-  return value & EPRX_STAT;
-}
-
-static void st103_ep_set_tx_status (uint8_t ep_num, uint16_t st_tx)
-{
-  uint16_t value = st103_get_epreg (ep_num);
-
-  value &= (EPREG_MASK|EPTX_STAT);
-  value ^= (EPTX_DTOG1 & st_tx);
-  value ^= (EPTX_DTOG2 & st_tx);
-  value |= EP_CTR_RX | EP_CTR_TX;
-  st103_set_epreg (ep_num, value);
-}
-
-static uint16_t st103_ep_get_tx_status (uint8_t ep_num)
-{
-  uint16_t value = st103_get_epreg (ep_num);
-
-  return value & EPTX_STAT;
-}
-
-static void st103_ep_clear_dtog_rx (uint8_t ep_num)
-{
-  uint16_t value = st103_get_epreg (ep_num);
-
-  if ((value & EP_DTOG_RX))
-    {
-      value &= EPREG_MASK;
-      value |= EP_CTR_RX | EP_CTR_TX | EP_DTOG_RX;
-      st103_set_epreg (ep_num, value);
-    }
-}
-
-static void st103_ep_clear_dtog_tx (uint8_t ep_num)
-{
-  uint16_t value = st103_get_epreg (ep_num);
-
-  if ((value & EP_DTOG_TX))
-    {
-      value &= EPREG_MASK;
-      value |= EP_CTR_RX | EP_CTR_TX | EP_DTOG_TX;
-      st103_set_epreg (ep_num, value);
-    }
-}
-\f
-void usb_lld_init (uint8_t feature)
-{
-  usb_lld_sys_init ();
-
-  dev_p->state = IN_DATA;
-
-  usb_lld_set_configuration (0);
-  usb_lld_set_feature (feature);
-
-  /* Reset USB */
-  st103_set_cntr (CNTR_FRES);
-  st103_set_cntr (0);
-
-  /* Clear Interrupt Status Register, and enable interrupt for USB */
-  st103_set_istr (0);
-  st103_set_cntr (CNTR_CTRM | CNTR_RESETM);
-}
-
-void usb_lld_prepare_shutdown (void)
-{
-  st103_set_istr (0);
-  st103_set_cntr (0);
-}
-
-void usb_lld_shutdown (void)
-{
-  st103_set_cntr (CNTR_PDWN);
-  usb_lld_sys_shutdown ();
-}
-
-void
-usb_interrupt_handler (void)
-{
-  uint16_t istr_value = st103_get_istr ();
-
-  if (istr_value & ISTR_CTR)
-    usb_handle_transfer ();
-
-  if (istr_value & ISTR_RESET)
-    {
-      st103_set_istr (CLR_RESET);
-      method_p->reset ();
-    }
-
-  if (istr_value & ISTR_DOVR)
-    st103_set_istr (CLR_DOVR);
-
-  if (istr_value & ISTR_ERR)
-    st103_set_istr (CLR_ERR);
-}
-
-static void handle_datastage_out (void)
-{
-  if (data_p->addr && data_p->len)
-    {
-      uint8_t *buf;
-      uint32_t len = st103_get_rx_count (ENDP0);
-
-      if (len > data_p->len)
-       len = data_p->len;
-
-      buf = data_p->addr + data_p->offset;
-      usb_lld_from_pmabuf (buf, st103_get_rx_addr (ENDP0), len);
-      data_p->len -= len;
-      data_p->offset += len;
-    }
-
-  if (data_p->len == 0)
-    {
-      dev_p->state = WAIT_STATUS_IN;
-      st103_set_tx_count (ENDP0, 0);
-      st103_ep_set_rxtx_status (ENDP0, EP_RX_STALL, EP_TX_VALID);
-    }
-  else
-    {
-      dev_p->state = OUT_DATA;
-      st103_ep_set_rx_status (ENDP0, EP_RX_VALID);
-    }
-}
-
-static void handle_datastage_in (void)
-{
-  uint32_t len = USB_MAX_PACKET_SIZE;;
-  const uint8_t *buf;
-
-  if ((data_p->len == 0) && (dev_p->state == LAST_IN_DATA))
-    {
-      if (data_p->require_zlp == TRUE)
-       {
-         data_p->require_zlp = FALSE;
-
-         /* No more data to send.  Send empty packet */
-         st103_set_tx_count (ENDP0, 0);
-         st103_ep_set_rxtx_status (ENDP0, EP_RX_VALID, EP_TX_VALID);
-       }
-      else
-       {
-         /* No more data to send, proceed to receive OUT acknowledge.*/
-         dev_p->state = WAIT_STATUS_OUT;
-         st103_ep_set_rxtx_status (ENDP0, EP_RX_VALID, EP_TX_STALL);
-       }
-
-      return;
-    }
-
-  dev_p->state = (data_p->len <= len) ? LAST_IN_DATA : IN_DATA;
-
-  if (len > data_p->len)
-    len = data_p->len;
-
-  buf = (const uint8_t *)data_p->addr + data_p->offset;
-  usb_lld_to_pmabuf (buf, st103_get_tx_addr (ENDP0), len);
-  data_p->len -= len;
-  data_p->offset += len;
-  st103_set_tx_count (ENDP0, len);
-  st103_ep_set_tx_status (ENDP0, EP_TX_VALID);
-}
-
-typedef int (*HANDLER) (uint8_t req,
-                       uint16_t value, uint16_t index, uint16_t length);
-
-static int std_none (uint8_t req,
-                    uint16_t value, uint16_t index, uint16_t length)
-{
-  (void)req; (void)value; (void)index; (void)length;
-  return USB_UNSUPPORT;
-}
-
-static int std_get_status (uint8_t req,
-                          uint16_t value, uint16_t index, uint16_t length)
-{
-  static uint16_t status_info;
-  uint8_t rcp = req & RECIPIENT;
-
-  status_info = 0;             /* Reset Status Information */
-  data_p->addr = (uint8_t *)&status_info;
-
-  if (value != 0 || length != 2 || (index >> 8) != 0
-      || (req & REQUEST_DIR) == 0)
-    return USB_UNSUPPORT;
-
-  if (rcp == DEVICE_RECIPIENT)
-    {
-      if (index == 0)
-       {
-         /* Get Device Status */
-         uint8_t feature = dev_p->current_feature;
-
-         /* Remote Wakeup enabled */
-         if ((feature & (1 << 5)))
-           status_info |= 2;
-         else
-           status_info &= ~2;
-
-         /* Bus-powered */
-         if ((feature & (1 << 6)))
-           status_info |= 1;
-         else /* Self-powered */
-           status_info &= ~1;
-
-         data_p->len = 2;
-         return USB_SUCCESS;
-       }
-    }
-  else if (rcp == INTERFACE_RECIPIENT)
-    {
-      int r;
-
-      if (dev_p->current_configuration == 0)
-       return USB_UNSUPPORT;
-
-      r = (*method_p->interface) (USB_QUERY_INTERFACE, index, 0);
-      if (r != USB_SUCCESS)
-       return USB_UNSUPPORT;
-
-      data_p->len = 2;
-      return USB_SUCCESS;
-    }
-  else if (rcp == ENDPOINT_RECIPIENT)
-    {
-      uint8_t endpoint = (index & 0x0f);
-      uint16_t status;
-
-      if ((index & 0x70) != 0 || endpoint == ENDP0)
-       return USB_UNSUPPORT;
-
-      if ((index & 0x80))
-       {
-         status = st103_ep_get_tx_status (endpoint);
-         if (status == 0)              /* Disabled */
-           return USB_UNSUPPORT;
-         else if (status == EP_TX_STALL)
-           status_info |= 1; /* IN Endpoint stalled */
-       }
-      else
-       {
-         status = st103_ep_get_rx_status (endpoint);
-         if (status == 0)              /* Disabled */
-           return USB_UNSUPPORT;
-         else if (status == EP_RX_STALL)
-           status_info |= 1; /* OUT Endpoint stalled */
-       }
-
-       data_p->len = 2;
-       return USB_SUCCESS;
-    }
-
-  return USB_UNSUPPORT;
-}
-
-static int std_clear_feature (uint8_t req, uint16_t value,
-                             uint16_t index, uint16_t length)
-{
-  uint8_t rcp = req & RECIPIENT;
-
-  if ((req & REQUEST_DIR) == 1)
-    return USB_UNSUPPORT;
-
-  if (rcp == DEVICE_RECIPIENT)
-    {
-      if (length != 0 || index != 0)
-       return USB_UNSUPPORT;
-
-      if (value == DEVICE_REMOTE_WAKEUP)
-       {
-         dev_p->current_feature &= ~(1 << 5);
-         return USB_SUCCESS;
-       }
-    }
-  else if (rcp == ENDPOINT_RECIPIENT)
-    {
-      uint8_t endpoint = (index & 0x0f);
-      uint16_t status;
-
-      if (dev_p->current_configuration == 0)
-       return USB_UNSUPPORT;
-
-      if (length != 0 || (index >> 8) != 0 || value != ENDPOINT_STALL
-         || endpoint == ENDP0)
-       return USB_UNSUPPORT;
-
-      if ((index & 0x80))
-       status = st103_ep_get_tx_status (endpoint);
-      else
-       status = st103_ep_get_rx_status (endpoint);
-
-      if (status == 0)         /* Disabled */
-       return USB_UNSUPPORT;
-
-      if (index & 0x80)                /* IN endpoint */
-       st103_ep_clear_dtog_tx (endpoint);
-      else                     /* OUT endpoint */
-       st103_ep_clear_dtog_rx (endpoint);
-
-      // event??
-      return USB_SUCCESS;
-    }
-
-  return USB_UNSUPPORT;
-}
-
-static int std_set_feature (uint8_t req, uint16_t value,
-                           uint16_t index, uint16_t length)
-{
-  uint8_t rcp = req & RECIPIENT;
-
-  if ((req & REQUEST_DIR) == 1)
-    return USB_UNSUPPORT;
-
-  if (rcp == DEVICE_RECIPIENT)
-    {
-      if (length != 0 || index != 0)
-       return USB_UNSUPPORT;
-
-      if (value == DEVICE_REMOTE_WAKEUP)
-       {
-         dev_p->current_feature |= 1 << 5;
-         // event??
-         return USB_SUCCESS;
-       }
-    }
-  else if (rcp == ENDPOINT_RECIPIENT)
-    {
-      uint8_t endpoint = (index & 0x0f);
-      uint32_t status;
-
-      if (dev_p->current_configuration == 0)
-       return USB_UNSUPPORT;
-
-      if (length != 0 || (index >> 8) != 0 || value != 0 || endpoint == ENDP0)
-       return USB_UNSUPPORT;
-
-      if ((index & 0x80))
-       status = st103_ep_get_tx_status (endpoint);
-      else
-       status = st103_ep_get_rx_status (endpoint);
-
-      if (status == 0)         /* Disabled */
-       return USB_UNSUPPORT;
-
-      if (index & 0x80)
-       /* IN endpoint */
-       st103_ep_set_tx_status (endpoint, EP_TX_STALL);
-      else
-       /* OUT endpoint */
-       st103_ep_set_rx_status (endpoint, EP_RX_STALL);
-
-      // event??
-      return USB_SUCCESS;
-    }
-
-  return USB_UNSUPPORT;
-}
-
-static int std_set_address (uint8_t req, uint16_t value,
-                           uint16_t index, uint16_t length)
-{
-  uint8_t rcp = req & RECIPIENT;
-
-  if ((req & REQUEST_DIR) == 1)
-    return USB_UNSUPPORT;
-
-  if (rcp == DEVICE_RECIPIENT)
-    {
-      if (length == 0 && value <= 127 && index == 0
-         && dev_p->current_configuration == 0)
-       return USB_SUCCESS;
-    }
-
-  return USB_UNSUPPORT;
-}
-
-static int std_get_descriptor (uint8_t req, uint16_t value,
-                              uint16_t index, uint16_t length)
-{
-  uint8_t rcp = req & RECIPIENT;
-
-  if ((req & REQUEST_DIR) == 0)
-    return USB_UNSUPPORT;
-
-  (void)length;
-  if (rcp == DEVICE_RECIPIENT)
-    return (*method_p->get_descriptor) ((value >> 8), index, value);
-
-  return USB_UNSUPPORT;
-}
-
-static int std_get_configuration (uint8_t req, uint16_t value,
-                                 uint16_t index, uint16_t length)
-{
-  uint8_t rcp = req & RECIPIENT;
-
-  if ((req & REQUEST_DIR) == 0)
-    return USB_UNSUPPORT;
-
-  (void)value;  (void)index;  (void)length;
-  if (rcp == DEVICE_RECIPIENT)
-    {
-      data_p->addr = &dev_p->current_configuration;
-      data_p->len = 1;
-      return USB_SUCCESS;
-    }
-
-  return USB_UNSUPPORT;
-}
-
-static int std_set_configuration (uint8_t req, uint16_t value,
-                                 uint16_t index, uint16_t length)
-{
-  uint8_t rcp = req & RECIPIENT;
-
-  if ((req & REQUEST_DIR) == 1)
-    return USB_UNSUPPORT;
-
-  if (rcp == DEVICE_RECIPIENT && index == 0 && length == 0)
-    {
-      int r;
-
-      r = (*method_p->event) (USB_EVENT_CONFIG, value);
-      if (r == USB_SUCCESS)
-       return USB_SUCCESS;
-    }
-
-  return USB_UNSUPPORT;
-}
-
-static int std_get_interface (uint8_t req, uint16_t value,
-                             uint16_t index, uint16_t length)
-{
-  uint8_t rcp = req & RECIPIENT;
-
-  if ((req & REQUEST_DIR) == 0)
-    return USB_UNSUPPORT;
-
-  if (rcp == INTERFACE_RECIPIENT)
-    {
-      if (value != 0 || (index >> 8) != 0 || length != 1)
-       return USB_UNSUPPORT;
-
-      if (dev_p->current_configuration == 0)
-       return USB_UNSUPPORT;
-
-      return (*method_p->interface) (USB_GET_INTERFACE, index, 0);
-    }
-
-  return USB_UNSUPPORT;
-}
-
-static int std_set_interface (uint8_t req, uint16_t value,
-                             uint16_t index, uint16_t length)
-{
-  uint8_t rcp = req & RECIPIENT;
-
-  if ((req & REQUEST_DIR) == 1)
-    return USB_UNSUPPORT;
-
-  if (rcp == INTERFACE_RECIPIENT)
-    {
-      int r;
-
-      if (length != 0 || (index >> 8) != 0 || (value >> 8) != 0)
-       return  USB_UNSUPPORT;
-
-      if (dev_p->current_configuration != 0)
-       return USB_UNSUPPORT;
-
-      r = (*method_p->interface) (USB_SET_INTERFACE, index, value);
-      if (r == USB_SUCCESS)
-       return USB_SUCCESS;
-    }
-
-  return USB_UNSUPPORT;
-}
-
-static const HANDLER std_request_handler[TOTAL_REQUEST] = {
-  std_get_status,
-  std_clear_feature,
-  std_none,
-  std_set_feature,
-  std_none,
-  std_set_address,
-  std_get_descriptor,
-  std_none,                    /* set_descriptor is not supported */
-  std_get_configuration,
-  std_set_configuration,
-  std_get_interface,
-  std_set_interface,
-  std_none,                    /* sync_frame is not  supported (for now) */
-};
-
-static void handle_setup0 (void)
-{
-  const uint16_t *pw;
-  uint16_t w;
-  uint8_t req;
-  int r = USB_UNSUPPORT;
-  HANDLER handler;
-
-  pw = (uint16_t *)(PMA_ADDR + (uint8_t *)(st103_get_rx_addr (ENDP0) * 2));
-  w = *pw++;
-
-  ctrl_p->bmRequestType = w & 0xff;
-  ctrl_p->bRequest = req = w >> 8;
-  pw++;
-  ctrl_p->wValue = *pw++;
-  pw++;
-  ctrl_p->wIndex  = *pw++;
-  pw++;
-  ctrl_p->wLength = *pw;
-
-  data_p->addr = NULL;
-  data_p->len = 0;
-  data_p->offset = 0;
-
-  if ((ctrl_p->bmRequestType & REQUEST_TYPE) == STANDARD_REQUEST)
-    {
-      if (req < TOTAL_REQUEST)
-       {
-         handler = std_request_handler[req];
-         r = (*handler) (ctrl_p->bmRequestType,
-                         ctrl_p->wValue, ctrl_p->wIndex, ctrl_p->wLength);
-       }
-    }
-  else
-    r = (*method_p->setup) (ctrl_p->bmRequestType, req,
-                           ctrl_p->wValue, ctrl_p->wIndex, ctrl_p->wLength);
-
-  if (r != USB_SUCCESS)
-    dev_p->state = STALLED;
-  else
-    {
-      if (USB_SETUP_GET (ctrl_p->bmRequestType))
-       {
-         uint32_t len = ctrl_p->wLength;
-
-         /* Restrict the data length to be the one host asks for */
-         if (data_p->len > len)
-           data_p->len = len;
-
-         if ((data_p->len % USB_MAX_PACKET_SIZE) == 0)
-           data_p->require_zlp = TRUE;
-         else
-           data_p->require_zlp = FALSE;
-
-         dev_p->state = IN_DATA;
-         handle_datastage_in ();
-       }
-      else if (ctrl_p->wLength == 0)
-       {
-         dev_p->state = WAIT_STATUS_IN;
-         st103_set_tx_count (ENDP0, 0);
-         st103_ep_set_rxtx_status (ENDP0, EP_RX_STALL, EP_TX_VALID);
-       }
-      else
-       {
-         dev_p->state = OUT_DATA;
-         st103_ep_set_rx_status (ENDP0, EP_RX_VALID);
-       }
-    }
-}
-
-static void handle_in0 (void)
-{
-  if (dev_p->state == IN_DATA || dev_p->state == LAST_IN_DATA)
-    handle_datastage_in ();
-  else if (dev_p->state == WAIT_STATUS_IN)
-    {
-      if ((ctrl_p->bRequest == SET_ADDRESS) &&
-         ((ctrl_p->bmRequestType & (REQUEST_TYPE | RECIPIENT))
-          == (STANDARD_REQUEST | DEVICE_RECIPIENT)))
-       {
-         st103_set_daddr (ctrl_p->wValue);
-         (*method_p->event) (USB_EVENT_ADDRESS, ctrl_p->wValue);
-       }
-      else
-       (*method_p->ctrl_write_finish)  (ctrl_p->bmRequestType,
-                                        ctrl_p->bRequest, ctrl_p->wValue,
-                                        ctrl_p->wIndex, ctrl_p->wLength);
-
-      dev_p->state = STALLED;
-    }
-  else
-    dev_p->state = STALLED;
-}
-
-static void handle_out0 (void)
-{
-  if (dev_p->state == IN_DATA || dev_p->state == LAST_IN_DATA)
-    /* host aborts the transfer before finish */
-    dev_p->state = STALLED;
-  else if (dev_p->state == OUT_DATA)
-    handle_datastage_out ();
-  else if (dev_p->state == WAIT_STATUS_OUT)
-    dev_p->state = STALLED;
-  /* Unexpect state, STALL the endpoint */
-  else
-    dev_p->state = STALLED;
-}
-\f
-static void nop_proc (void)
-{
-}
-
-#define WEAK __attribute__ ((weak, alias ("nop_proc")))
-void WEAK EP1_IN_Callback (void);
-void WEAK EP2_IN_Callback (void);
-void WEAK EP3_IN_Callback (void);
-void WEAK EP4_IN_Callback (void);
-void WEAK EP5_IN_Callback (void);
-void WEAK EP6_IN_Callback (void);
-void WEAK EP7_IN_Callback (void);
-
-void WEAK EP1_OUT_Callback (void);
-void WEAK EP2_OUT_Callback (void);
-void WEAK EP3_OUT_Callback (void);
-void WEAK EP4_OUT_Callback (void);
-void WEAK EP5_OUT_Callback (void);
-void WEAK EP6_OUT_Callback (void);
-void WEAK EP7_OUT_Callback (void);
-
-void (*const ep_intr_handler_IN[7]) (void) = {
-  EP1_IN_Callback,
-  EP2_IN_Callback,
-  EP3_IN_Callback,
-  EP4_IN_Callback,
-  EP5_IN_Callback,
-  EP6_IN_Callback,
-  EP7_IN_Callback,
-};
-
-void (*const ep_intr_handler_OUT[7]) (void) = {
-  EP1_OUT_Callback,
-  EP2_OUT_Callback,
-  EP3_OUT_Callback,
-  EP4_OUT_Callback,
-  EP5_OUT_Callback,
-  EP6_OUT_Callback,
-  EP7_OUT_Callback,
-};
-
-static void
-usb_handle_transfer (void)
-{
-  uint16_t ep_value = 0;
-  uint16_t istr_value;
-  uint8_t ep_index;
-
-  while (((istr_value = st103_get_istr ()) & ISTR_CTR) != 0)
-    {
-      ep_index = (istr_value & ISTR_EP_ID);
-      if (ep_index == 0)
-       {
-         if ((istr_value & ISTR_DIR) == 0)
-           {                           /* DIR = 0 */
-             /* DIR = 0      => IN  int */
-             /* DIR = 0 implies that (EP_CTR_TX = 1) always  */
-
-             st103_ep_clear_ctr_tx (ENDP0);
-             handle_in0 ();
-           }
-         else
-           {                           /* DIR = 1 */
-             /* DIR = 1 & CTR_RX       => SETUP or OUT int */
-             /* DIR = 1 & (CTR_TX | CTR_RX) => 2 int pending */
-
-             ep_value = st103_get_epreg (ENDP0);
-             if ((ep_value & EP_SETUP) != 0)
-               {
-                 st103_ep_clear_ctr_rx (ENDP0);
-                 handle_setup0 ();
-               }
-             else if ((ep_value & EP_CTR_RX) != 0)
-               {
-                 st103_ep_clear_ctr_rx (ENDP0);
-                 handle_out0 ();
-               }
-           }
-
-         if (dev_p->state == STALLED)
-           st103_ep_set_rxtx_status (ENDP0, EP_RX_STALL, EP_TX_STALL);
-       }
-      else
-       {
-         /* Decode and service non control endpoints interrupt  */
-         /* process related endpoint register */
-         ep_value = st103_get_epreg (ep_index);
-
-         if ((ep_value & EP_CTR_RX) != 0)
-           {
-             st103_ep_clear_ctr_rx (ep_index);
-             (*ep_intr_handler_OUT[ep_index-1]) ();
-           }
-
-         if ((ep_value & EP_CTR_TX) != 0)
-           {
-             st103_ep_clear_ctr_tx (ep_index);
-             (*ep_intr_handler_IN[ep_index-1]) ();
-           }
-       }
-    }
-}
-\f
-void usb_lld_reset (void)
-{
-  st103_set_btable ();
-  st103_set_daddr (0);
-}
-
-void usb_lld_txcpy (const void *src,
-                   int ep_num, int offset, size_t len)
-{
-  usb_lld_to_pmabuf (src, st103_get_tx_addr (ep_num) + offset, len);
-}
-
-void usb_lld_write (uint8_t ep_num, const void *buf, size_t len)
-{
-  usb_lld_to_pmabuf (buf, st103_get_tx_addr (ep_num), len);
-  st103_set_tx_count (ep_num, len);
-  st103_ep_set_tx_status (ep_num, EP_TX_VALID);
-}
-
-void usb_lld_rxcpy (uint8_t *dst,
-                   int ep_num, int offset, size_t len)
-{
-  usb_lld_from_pmabuf (dst, st103_get_rx_addr (ep_num) + offset, len);
-}
-
-void usb_lld_tx_enable (int ep_num, size_t len)
-{
-  st103_set_tx_count (ep_num, len);
-  st103_ep_set_tx_status (ep_num, EP_TX_VALID);
-}
-
-int usb_lld_tx_data_len (int ep_num)
-{
-  return st103_get_tx_count (ep_num);
-}
-
-int usb_lld_rx_data_len (int ep_num)
-{
-  return st103_get_rx_count (ep_num);
-}
-
-void usb_lld_stall_tx (int ep_num)
-{
-  st103_ep_set_tx_status (ep_num, EP_TX_STALL);
-}
-
-void usb_lld_stall_rx (int ep_num)
-{
-  st103_ep_set_rx_status (ep_num, EP_RX_STALL);
-}
-
-void usb_lld_rx_enable (int ep_num)
-{
-  st103_ep_set_rx_status (ep_num, EP_RX_VALID);
-}
-
-void usb_lld_setup_endpoint (int ep_num, int ep_type, int ep_kind,
-                            int ep_rx_addr, int ep_tx_addr,
-                            int ep_rx_buf_size)
-{
-  uint16_t epreg_value = st103_get_epreg (ep_num);
-  uint16_t ep_rxtx_status = 0; /* Both disabled */
-
-  /* Clear: Write 1 if 1: EP_DTOG_RX, EP_DTOG_TX */
-  /* Set: Write:          EP_T_FIELD, EP_KIND, EPADDR_FIELD */
-  /* Set: Toggle:         EPRX_STAT, EPTX_STAT */
-  epreg_value &= (EPRX_STAT | EP_SETUP | EPTX_STAT | EP_DTOG_RX | EP_DTOG_TX);
-#if USB_KEEP_CORRECT_TRANSFER_FLAGS
-  /* Keep: Write 1:       EP_CTR_RX, EP_CTR_TX */
-  epreg_value |= (EP_CTR_RX|EP_CTR_TX);
-#else
-  /* Clear: Write 0:      EP_CTR_RX, EP_CTR_TX */
-#endif
-  epreg_value |= ep_type;
-  epreg_value |= ep_kind;
-  epreg_value |= ep_num;
-
-  if (ep_rx_addr)
-    {
-      ep_rxtx_status |= EP_RX_VALID;
-      st103_set_rx_addr (ep_num, ep_rx_addr);
-      st103_set_rx_buf_size (ep_num, ep_rx_buf_size);
-    }
-
-  if (ep_tx_addr)
-    {
-      ep_rxtx_status |= EP_TX_NAK;
-      st103_set_tx_addr (ep_num, ep_tx_addr);
-    }
-
-  epreg_value ^= (EPRX_DTOG1 & ep_rxtx_status);
-  epreg_value ^= (EPRX_DTOG2 & ep_rxtx_status);
-  epreg_value ^= (EPTX_DTOG1 & ep_rxtx_status);
-  epreg_value ^= (EPTX_DTOG2 & ep_rxtx_status);
-
-  st103_set_epreg (ep_num, epreg_value);
-}
-
-void usb_lld_set_configuration (uint8_t config)
-{
-  dev_p->current_configuration = config;
-}
-
-uint8_t usb_lld_current_configuration (void)
-{
-  return dev_p->current_configuration;
-}
-
-void usb_lld_set_feature (uint8_t feature)
-{
-  dev_p->current_feature = feature;
-}
-
-void usb_lld_set_data_to_send (const void *p, size_t len)
-{
-  data_p->addr = (uint8_t *)p;
-  data_p->len = len;
-}
-
-void usb_lld_to_pmabuf (const void *src, uint16_t addr, size_t n)
-{
-  const uint8_t *s = (const uint8_t *)src;
-  uint16_t *p;
-  uint16_t w;
-
-  if (n == 0)
-    return;
-
-  if ((addr & 1))
-    {
-      p = (uint16_t *)(PMA_ADDR + (addr - 1) * 2);
-      w = *p;
-      w = (w & 0xff) | (*s++) << 8;
-      *p = w;
-      p += 2;
-      n--;
-    }
-  else
-    p = (uint16_t *)(PMA_ADDR + addr * 2);
-
-  while (n >= 2)
-    {
-      w = *s++;
-      w |= (*s++) << 8;
-      *p = w;
-      p += 2;
-      n -= 2;
-    }
-
-  if (n > 0)
-    {
-      w = *s;
-      *p = w;
-    }
-}
-
-void usb_lld_from_pmabuf (void *dst, uint16_t addr, size_t n)
-{
-  uint8_t *d = (uint8_t *)dst;
-  uint16_t *p;
-  uint16_t w;
-
-  if (n == 0)
-    return;
-
-  if ((addr & 1))
-    {
-      p = (uint16_t *)(PMA_ADDR + (addr - 1) * 2);
-      w = *p;
-      *d++ = (w >> 8);
-      p += 2;
-      n--;
-    }
-  else
-    p = (uint16_t *)(PMA_ADDR + addr * 2);
-
-  while (n >= 2)
-    {
-      w = *p;
-      *d++ = (w & 0xff);
-      *d++ = (w >> 8);
-      p += 2;
-      n -= 2;
-    }
-
-  if (n > 0)
-    {
-      w = *p;
-      *d = (w & 0xff);
-    }
-}
diff --git a/src/usb_stm32f103.c b/src/usb_stm32f103.c
new file mode 100644 (file)
index 0000000..df0c2f9
--- /dev/null
@@ -0,0 +1,1213 @@
+#ifdef FREE_STANDING
+#include "types.h"
+#else
+#include "ch.h"
+#include "hal.h"
+#endif
+#include "sys.h"
+#include "usb_lld.h"
+
+#define USB_MAX_PACKET_SIZE 64 /* For FS device */
+
+enum STANDARD_REQUESTS
+{
+  GET_STATUS = 0,
+  CLEAR_FEATURE,
+  RESERVED1,
+  SET_FEATURE,
+  RESERVED2,
+  SET_ADDRESS,
+  GET_DESCRIPTOR,
+  SET_DESCRIPTOR,
+  GET_CONFIGURATION,
+  SET_CONFIGURATION,
+  GET_INTERFACE,
+  SET_INTERFACE,
+  SYNCH_FRAME,
+  TOTAL_REQUEST  /* Total number of Standard request */
+};
+
+/* The state machine states of a control pipe */
+enum CONTROL_STATE
+{
+  WAIT_SETUP,
+  SETTING_UP,
+  IN_DATA,
+  OUT_DATA,
+  LAST_IN_DATA,
+  WAIT_STATUS_IN,
+  WAIT_STATUS_OUT,
+  STALLED,
+  PAUSE
+};
+
+enum FEATURE_SELECTOR
+{
+  ENDPOINT_STALL,
+  DEVICE_REMOTE_WAKEUP
+};
+
+struct DATA_INFO
+{
+  uint16_t len;
+  uint16_t offset;
+  uint8_t *addr;
+  uint8_t require_zlp;
+};
+
+struct CONTROL_INFO
+{
+  uint8_t bmRequestType;
+  uint8_t bRequest;
+  uint16_t wValue;
+  uint16_t wIndex;
+  uint16_t wLength;
+};
+
+struct DEVICE_INFO
+{
+  uint8_t current_configuration;
+  uint8_t current_feature;
+  uint8_t state;
+};
+
+static struct CONTROL_INFO control_info;
+static struct DEVICE_INFO device_info;
+static struct DATA_INFO data_info;
+extern const struct usb_device_method Device_Method;
+
+static struct CONTROL_INFO *const ctrl_p = &control_info;
+static struct DEVICE_INFO *const dev_p = &device_info;
+static struct DATA_INFO *const data_p = &data_info;
+static const struct usb_device_method *const method_p = &Device_Method;
+
+#define REG_BASE  (0x40005C00UL) /* USB_IP Peripheral Registers base address */
+#define PMA_ADDR  (0x40006000UL) /* USB_IP Packet Memory Area base address   */
+
+/* Control register */
+#define CNTR    ((__IO uint16_t *)(REG_BASE + 0x40))
+/* Interrupt status register */
+#define ISTR    ((__IO uint16_t *)(REG_BASE + 0x44))
+/* Frame number register */
+#define FNR     ((__IO uint16_t *)(REG_BASE + 0x48))
+/* Device address register */
+#define DADDR   ((__IO uint16_t *)(REG_BASE + 0x4C))
+/* Buffer Table address register */
+#define BTABLE  ((__IO uint16_t *)(REG_BASE + 0x50))
+
+#define ISTR_CTR    (0x8000) /* Correct TRansfer (clear-only bit) */
+#define ISTR_DOVR   (0x4000) /* DMA OVeR/underrun (clear-only bit) */
+#define ISTR_ERR    (0x2000) /* ERRor (clear-only bit) */
+#define ISTR_WKUP   (0x1000) /* WaKe UP (clear-only bit) */
+#define ISTR_SUSP   (0x0800) /* SUSPend (clear-only bit) */
+#define ISTR_RESET  (0x0400) /* RESET (clear-only bit) */
+#define ISTR_SOF    (0x0200) /* Start Of Frame (clear-only bit) */
+#define ISTR_ESOF   (0x0100) /* Expected Start Of Frame (clear-only bit) */
+
+#define ISTR_DIR    (0x0010)  /* DIRection of transaction (read-only bit)  */
+#define ISTR_EP_ID  (0x000F)  /* EndPoint IDentifier (read-only bit)  */
+
+#define CLR_CTR    (~ISTR_CTR)   /* clear Correct TRansfer bit */
+#define CLR_DOVR   (~ISTR_DOVR)  /* clear DMA OVeR/underrun bit*/
+#define CLR_ERR    (~ISTR_ERR)   /* clear ERRor bit */
+#define CLR_WKUP   (~ISTR_WKUP)  /* clear WaKe UP bit     */
+#define CLR_SUSP   (~ISTR_SUSP)  /* clear SUSPend bit     */
+#define CLR_RESET  (~ISTR_RESET) /* clear RESET bit      */
+#define CLR_SOF    (~ISTR_SOF)   /* clear Start Of Frame bit   */
+#define CLR_ESOF   (~ISTR_ESOF)  /* clear Expected Start Of Frame bit */
+
+#define CNTR_CTRM   (0x8000) /* Correct TRansfer Mask */
+#define CNTR_DOVRM  (0x4000) /* DMA OVeR/underrun Mask */
+#define CNTR_ERRM   (0x2000) /* ERRor Mask */
+#define CNTR_WKUPM  (0x1000) /* WaKe UP Mask */
+#define CNTR_SUSPM  (0x0800) /* SUSPend Mask */
+#define CNTR_RESETM (0x0400) /* RESET Mask   */
+#define CNTR_SOFM   (0x0200) /* Start Of Frame Mask */
+#define CNTR_ESOFM  (0x0100) /* Expected Start Of Frame Mask */
+
+#define CNTR_RESUME (0x0010) /* RESUME request */
+#define CNTR_FSUSP  (0x0008) /* Force SUSPend */
+#define CNTR_LPMODE (0x0004) /* Low-power MODE */
+#define CNTR_PDWN   (0x0002) /* Power DoWN */
+#define CNTR_FRES   (0x0001) /* Force USB RESet */
+
+#define DADDR_EF (0x80)
+#define DADDR_ADD (0x7F)
+
+#define EP_CTR_RX      (0x8000) /* EndPoint Correct TRansfer RX */
+#define EP_DTOG_RX     (0x4000) /* EndPoint Data TOGGLE RX */
+#define EPRX_STAT      (0x3000) /* EndPoint RX STATus bit field */
+#define EP_SETUP       (0x0800) /* EndPoint SETUP */
+#define EP_T_FIELD     (0x0600) /* EndPoint TYPE */
+#define EP_KIND        (0x0100) /* EndPoint KIND */
+#define EP_CTR_TX      (0x0080) /* EndPoint Correct TRansfer TX */
+#define EP_DTOG_TX     (0x0040) /* EndPoint Data TOGGLE TX */
+#define EPTX_STAT      (0x0030) /* EndPoint TX STATus bit field */
+#define EPADDR_FIELD   (0x000F) /* EndPoint ADDRess FIELD */
+
+#define EPREG_MASK     (EP_CTR_RX|EP_SETUP|EP_T_FIELD|EP_KIND|EP_CTR_TX|EPADDR_FIELD)
+
+/* STAT_TX[1:0] STATus for TX transfer */
+#define EP_TX_DIS      (0x0000) /* EndPoint TX DISabled */
+#define EP_TX_STALL    (0x0010) /* EndPoint TX STALLed */
+#define EP_TX_NAK      (0x0020) /* EndPoint TX NAKed */
+#define EP_TX_VALID    (0x0030) /* EndPoint TX VALID */
+#define EPTX_DTOG1     (0x0010) /* EndPoint TX Data TOGgle bit1 */
+#define EPTX_DTOG2     (0x0020) /* EndPoint TX Data TOGgle bit2 */
+
+/* STAT_RX[1:0] STATus for RX transfer */
+#define EP_RX_DIS      (0x0000) /* EndPoint RX DISabled */
+#define EP_RX_STALL    (0x1000) /* EndPoint RX STALLed */
+#define EP_RX_NAK      (0x2000) /* EndPoint RX NAKed */
+#define EP_RX_VALID    (0x3000) /* EndPoint RX VALID */
+#define EPRX_DTOG1     (0x1000) /* EndPoint RX Data TOGgle bit1 */
+#define EPRX_DTOG2     (0x2000) /* EndPoint RX Data TOGgle bit1 */
+
+static void usb_handle_transfer (void);
+
+static void st103_set_btable (void)
+{
+  *BTABLE = 0;
+}
+
+static uint16_t st103_get_istr (void)
+{
+  return *ISTR;
+}
+
+static void st103_set_istr (uint16_t istr)
+{
+  *ISTR = istr;
+}
+
+static void st103_set_cntr (uint16_t cntr)
+{
+  *CNTR = cntr;
+}
+
+static void st103_set_daddr (uint16_t daddr)
+{
+  *DADDR  = daddr | DADDR_EF;
+}
+
+static void st103_set_epreg (uint8_t ep_num, uint16_t value)
+{
+  uint16_t *reg_p = (uint16_t *)(REG_BASE + ep_num*4);
+
+  *reg_p = value;
+}
+
+static uint16_t st103_get_epreg (uint8_t ep_num)
+{
+  uint16_t *reg_p = (uint16_t *)(REG_BASE + ep_num*4);
+
+  return *reg_p;
+}
+
+static void st103_set_tx_addr (uint8_t ep_num, uint16_t addr)
+{
+  uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+0)*2);
+
+  *reg_p = addr;
+}
+
+static uint16_t st103_get_tx_addr (uint8_t ep_num)
+{
+  uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+0)*2);
+
+  return *reg_p;
+}
+
+
+static void st103_set_tx_count (uint8_t ep_num, uint16_t size)
+{
+  uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+2)*2);
+
+  *reg_p = size;
+}
+
+static uint16_t st103_get_tx_count (uint8_t ep_num)
+{
+  uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+2)*2);
+
+  return *reg_p  & 0x03ff;
+}
+
+
+static void st103_set_rx_addr (uint8_t ep_num, uint16_t addr)
+{
+  uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+4)*2);
+
+  *reg_p = addr;
+}
+
+static uint16_t st103_get_rx_addr (uint8_t ep_num)
+{
+  uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+4)*2);
+
+  return *reg_p;
+}
+
+
+static void st103_set_rx_buf_size (uint8_t ep_num, uint16_t size)
+{                              /* Assume size is even */
+  uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+6)*2);
+  uint16_t value;
+
+  if (size <= 62)
+    value = (size & 0x3e) << 9;
+  else
+    value = 0x8000 | (((size >> 5) - 1) << 10);
+
+  *reg_p = value;
+}
+
+static uint16_t st103_get_rx_count (uint8_t ep_num)
+{
+  uint16_t *reg_p = (uint16_t *)(PMA_ADDR + (ep_num*8+6)*2);
+
+  return *reg_p & 0x03ff;
+}
+
+
+static void st103_ep_clear_ctr_rx (uint8_t ep_num)
+{
+  uint16_t value = st103_get_epreg (ep_num) & ~EP_CTR_RX & EPREG_MASK;
+
+  st103_set_epreg (ep_num, value);
+}
+
+static void st103_ep_clear_ctr_tx (uint8_t ep_num)
+{
+  uint16_t value = st103_get_epreg (ep_num) & ~EP_CTR_TX & EPREG_MASK;
+
+  st103_set_epreg (ep_num, value);
+}
+
+static void st103_ep_set_rxtx_status (uint8_t ep_num, uint16_t st_rx,
+                                     uint16_t st_tx)
+{
+  uint16_t value = st103_get_epreg (ep_num);
+
+  value &= (EPREG_MASK|EPRX_STAT|EPTX_STAT);
+  value ^= (EPRX_DTOG1 & st_rx);
+  value ^= (EPRX_DTOG2 & st_rx);
+  value ^= (EPTX_DTOG1 & st_tx);
+  value ^= (EPTX_DTOG2 & st_tx);
+  value |= EP_CTR_RX | EP_CTR_TX;
+  st103_set_epreg (ep_num, value);
+}
+
+static void st103_ep_set_rx_status (uint8_t ep_num, uint16_t st_rx)
+{
+  uint16_t value = st103_get_epreg (ep_num);
+
+  value &= (EPREG_MASK|EPRX_STAT);
+  value ^= (EPRX_DTOG1 & st_rx);
+  value ^= (EPRX_DTOG2 & st_rx);
+  value |= EP_CTR_RX | EP_CTR_TX;
+  st103_set_epreg (ep_num, value);
+}
+
+static uint16_t st103_ep_get_rx_status (uint8_t ep_num)
+{
+  uint16_t value = st103_get_epreg (ep_num);
+
+  return value & EPRX_STAT;
+}
+
+static void st103_ep_set_tx_status (uint8_t ep_num, uint16_t st_tx)
+{
+  uint16_t value = st103_get_epreg (ep_num);
+
+  value &= (EPREG_MASK|EPTX_STAT);
+  value ^= (EPTX_DTOG1 & st_tx);
+  value ^= (EPTX_DTOG2 & st_tx);
+  value |= EP_CTR_RX | EP_CTR_TX;
+  st103_set_epreg (ep_num, value);
+}
+
+static uint16_t st103_ep_get_tx_status (uint8_t ep_num)
+{
+  uint16_t value = st103_get_epreg (ep_num);
+
+  return value & EPTX_STAT;
+}
+
+static void st103_ep_clear_dtog_rx (uint8_t ep_num)
+{
+  uint16_t value = st103_get_epreg (ep_num);
+
+  if ((value & EP_DTOG_RX))
+    {
+      value &= EPREG_MASK;
+      value |= EP_CTR_RX | EP_CTR_TX | EP_DTOG_RX;
+      st103_set_epreg (ep_num, value);
+    }
+}
+
+static void st103_ep_clear_dtog_tx (uint8_t ep_num)
+{
+  uint16_t value = st103_get_epreg (ep_num);
+
+  if ((value & EP_DTOG_TX))
+    {
+      value &= EPREG_MASK;
+      value |= EP_CTR_RX | EP_CTR_TX | EP_DTOG_TX;
+      st103_set_epreg (ep_num, value);
+    }
+}
+\f
+void usb_lld_init (uint8_t feature)
+{
+  usb_lld_sys_init ();
+
+  dev_p->state = IN_DATA;
+
+  usb_lld_set_configuration (0);
+  usb_lld_set_feature (feature);
+
+  /* Reset USB */
+  st103_set_cntr (CNTR_FRES);
+  st103_set_cntr (0);
+
+  /* Clear Interrupt Status Register, and enable interrupt for USB */
+  st103_set_istr (0);
+  st103_set_cntr (CNTR_CTRM | CNTR_RESETM);
+}
+
+void usb_lld_prepare_shutdown (void)
+{
+  st103_set_istr (0);
+  st103_set_cntr (0);
+}
+
+void usb_lld_shutdown (void)
+{
+  st103_set_cntr (CNTR_PDWN);
+  usb_lld_sys_shutdown ();
+}
+
+void
+usb_interrupt_handler (void)
+{
+  uint16_t istr_value = st103_get_istr ();
+
+  if (istr_value & ISTR_CTR)
+    usb_handle_transfer ();
+
+  if (istr_value & ISTR_RESET)
+    {
+      st103_set_istr (CLR_RESET);
+      method_p->reset ();
+    }
+
+  if (istr_value & ISTR_DOVR)
+    st103_set_istr (CLR_DOVR);
+
+  if (istr_value & ISTR_ERR)
+    st103_set_istr (CLR_ERR);
+}
+
+static void handle_datastage_out (void)
+{
+  if (data_p->addr && data_p->len)
+    {
+      uint8_t *buf;
+      uint32_t len = st103_get_rx_count (ENDP0);
+
+      if (len > data_p->len)
+       len = data_p->len;
+
+      buf = data_p->addr + data_p->offset;
+      usb_lld_from_pmabuf (buf, st103_get_rx_addr (ENDP0), len);
+      data_p->len -= len;
+      data_p->offset += len;
+    }
+
+  if (data_p->len == 0)
+    {
+      dev_p->state = WAIT_STATUS_IN;
+      st103_set_tx_count (ENDP0, 0);
+      st103_ep_set_rxtx_status (ENDP0, EP_RX_STALL, EP_TX_VALID);
+    }
+  else
+    {
+      dev_p->state = OUT_DATA;
+      st103_ep_set_rx_status (ENDP0, EP_RX_VALID);
+    }
+}
+
+static void handle_datastage_in (void)
+{
+  uint32_t len = USB_MAX_PACKET_SIZE;;
+  const uint8_t *buf;
+
+  if ((data_p->len == 0) && (dev_p->state == LAST_IN_DATA))
+    {
+      if (data_p->require_zlp == TRUE)
+       {
+         data_p->require_zlp = FALSE;
+
+         /* No more data to send.  Send empty packet */
+         st103_set_tx_count (ENDP0, 0);
+         st103_ep_set_rxtx_status (ENDP0, EP_RX_VALID, EP_TX_VALID);
+       }
+      else
+       {
+         /* No more data to send, proceed to receive OUT acknowledge.*/
+         dev_p->state = WAIT_STATUS_OUT;
+         st103_ep_set_rxtx_status (ENDP0, EP_RX_VALID, EP_TX_STALL);
+       }
+
+      return;
+    }
+
+  dev_p->state = (data_p->len <= len) ? LAST_IN_DATA : IN_DATA;
+
+  if (len > data_p->len)
+    len = data_p->len;
+
+  buf = (const uint8_t *)data_p->addr + data_p->offset;
+  usb_lld_to_pmabuf (buf, st103_get_tx_addr (ENDP0), len);
+  data_p->len -= len;
+  data_p->offset += len;
+  st103_set_tx_count (ENDP0, len);
+  st103_ep_set_tx_status (ENDP0, EP_TX_VALID);
+}
+
+typedef int (*HANDLER) (uint8_t req,
+                       uint16_t value, uint16_t index, uint16_t length);
+
+static int std_none (uint8_t req,
+                    uint16_t value, uint16_t index, uint16_t length)
+{
+  (void)req; (void)value; (void)index; (void)length;
+  return USB_UNSUPPORT;
+}
+
+static int std_get_status (uint8_t req,
+                          uint16_t value, uint16_t index, uint16_t length)
+{
+  static uint16_t status_info;
+  uint8_t rcp = req & RECIPIENT;
+
+  status_info = 0;             /* Reset Status Information */
+  data_p->addr = (uint8_t *)&status_info;
+
+  if (value != 0 || length != 2 || (index >> 8) != 0
+      || (req & REQUEST_DIR) == 0)
+    return USB_UNSUPPORT;
+
+  if (rcp == DEVICE_RECIPIENT)
+    {
+      if (index == 0)
+       {
+         /* Get Device Status */
+         uint8_t feature = dev_p->current_feature;
+
+         /* Remote Wakeup enabled */
+         if ((feature & (1 << 5)))
+           status_info |= 2;
+         else
+           status_info &= ~2;
+
+         /* Bus-powered */
+         if ((feature & (1 << 6)))
+           status_info |= 1;
+         else /* Self-powered */
+           status_info &= ~1;
+
+         data_p->len = 2;
+         return USB_SUCCESS;
+       }
+    }
+  else if (rcp == INTERFACE_RECIPIENT)
+    {
+      int r;
+
+      if (dev_p->current_configuration == 0)
+       return USB_UNSUPPORT;
+
+      r = (*method_p->interface) (USB_QUERY_INTERFACE, index, 0);
+      if (r != USB_SUCCESS)
+       return USB_UNSUPPORT;
+
+      data_p->len = 2;
+      return USB_SUCCESS;
+    }
+  else if (rcp == ENDPOINT_RECIPIENT)
+    {
+      uint8_t endpoint = (index & 0x0f);
+      uint16_t status;
+
+      if ((index & 0x70) != 0 || endpoint == ENDP0)
+       return USB_UNSUPPORT;
+
+      if ((index & 0x80))
+       {
+         status = st103_ep_get_tx_status (endpoint);
+         if (status == 0)              /* Disabled */
+           return USB_UNSUPPORT;
+         else if (status == EP_TX_STALL)
+           status_info |= 1; /* IN Endpoint stalled */
+       }
+      else
+       {
+         status = st103_ep_get_rx_status (endpoint);
+         if (status == 0)              /* Disabled */
+           return USB_UNSUPPORT;
+         else if (status == EP_RX_STALL)
+           status_info |= 1; /* OUT Endpoint stalled */
+       }
+
+       data_p->len = 2;
+       return USB_SUCCESS;
+    }
+
+  return USB_UNSUPPORT;
+}
+
+static int std_clear_feature (uint8_t req, uint16_t value,
+                             uint16_t index, uint16_t length)
+{
+  uint8_t rcp = req & RECIPIENT;
+
+  if ((req & REQUEST_DIR) == 1)
+    return USB_UNSUPPORT;
+
+  if (rcp == DEVICE_RECIPIENT)
+    {
+      if (length != 0 || index != 0)
+       return USB_UNSUPPORT;
+
+      if (value == DEVICE_REMOTE_WAKEUP)
+       {
+         dev_p->current_feature &= ~(1 << 5);
+         return USB_SUCCESS;
+       }
+    }
+  else if (rcp == ENDPOINT_RECIPIENT)
+    {
+      uint8_t endpoint = (index & 0x0f);
+      uint16_t status;
+
+      if (dev_p->current_configuration == 0)
+       return USB_UNSUPPORT;
+
+      if (length != 0 || (index >> 8) != 0 || value != ENDPOINT_STALL
+         || endpoint == ENDP0)
+       return USB_UNSUPPORT;
+
+      if ((index & 0x80))
+       status = st103_ep_get_tx_status (endpoint);
+      else
+       status = st103_ep_get_rx_status (endpoint);
+
+      if (status == 0)         /* Disabled */
+       return USB_UNSUPPORT;
+
+      if (index & 0x80)                /* IN endpoint */
+       st103_ep_clear_dtog_tx (endpoint);
+      else                     /* OUT endpoint */
+       st103_ep_clear_dtog_rx (endpoint);
+
+      // event??
+      return USB_SUCCESS;
+    }
+
+  return USB_UNSUPPORT;
+}
+
+static int std_set_feature (uint8_t req, uint16_t value,
+                           uint16_t index, uint16_t length)
+{
+  uint8_t rcp = req & RECIPIENT;
+
+  if ((req & REQUEST_DIR) == 1)
+    return USB_UNSUPPORT;
+
+  if (rcp == DEVICE_RECIPIENT)
+    {
+      if (length != 0 || index != 0)
+       return USB_UNSUPPORT;
+
+      if (value == DEVICE_REMOTE_WAKEUP)
+       {
+         dev_p->current_feature |= 1 << 5;
+         // event??
+         return USB_SUCCESS;
+       }
+    }
+  else if (rcp == ENDPOINT_RECIPIENT)
+    {
+      uint8_t endpoint = (index & 0x0f);
+      uint32_t status;
+
+      if (dev_p->current_configuration == 0)
+       return USB_UNSUPPORT;
+
+      if (length != 0 || (index >> 8) != 0 || value != 0 || endpoint == ENDP0)
+       return USB_UNSUPPORT;
+
+      if ((index & 0x80))
+       status = st103_ep_get_tx_status (endpoint);
+      else
+       status = st103_ep_get_rx_status (endpoint);
+
+      if (status == 0)         /* Disabled */
+       return USB_UNSUPPORT;
+
+      if (index & 0x80)
+       /* IN endpoint */
+       st103_ep_set_tx_status (endpoint, EP_TX_STALL);
+      else
+       /* OUT endpoint */
+       st103_ep_set_rx_status (endpoint, EP_RX_STALL);
+
+      // event??
+      return USB_SUCCESS;
+    }
+
+  return USB_UNSUPPORT;
+}
+
+static int std_set_address (uint8_t req, uint16_t value,
+                           uint16_t index, uint16_t length)
+{
+  uint8_t rcp = req & RECIPIENT;
+
+  if ((req & REQUEST_DIR) == 1)
+    return USB_UNSUPPORT;
+
+  if (rcp == DEVICE_RECIPIENT)
+    {
+      if (length == 0 && value <= 127 && index == 0
+         && dev_p->current_configuration == 0)
+       return USB_SUCCESS;
+    }
+
+  return USB_UNSUPPORT;
+}
+
+static int std_get_descriptor (uint8_t req, uint16_t value,
+                              uint16_t index, uint16_t length)
+{
+  uint8_t rcp = req & RECIPIENT;
+
+  if ((req & REQUEST_DIR) == 0)
+    return USB_UNSUPPORT;
+
+  (void)length;
+  if (rcp == DEVICE_RECIPIENT)
+    return (*method_p->get_descriptor) ((value >> 8), index, value);
+
+  return USB_UNSUPPORT;
+}
+
+static int std_get_configuration (uint8_t req, uint16_t value,
+                                 uint16_t index, uint16_t length)
+{
+  uint8_t rcp = req & RECIPIENT;
+
+  if ((req & REQUEST_DIR) == 0)
+    return USB_UNSUPPORT;
+
+  (void)value;  (void)index;  (void)length;
+  if (rcp == DEVICE_RECIPIENT)
+    {
+      data_p->addr = &dev_p->current_configuration;
+      data_p->len = 1;
+      return USB_SUCCESS;
+    }
+
+  return USB_UNSUPPORT;
+}
+
+static int std_set_configuration (uint8_t req, uint16_t value,
+                                 uint16_t index, uint16_t length)
+{
+  uint8_t rcp = req & RECIPIENT;
+
+  if ((req & REQUEST_DIR) == 1)
+    return USB_UNSUPPORT;
+
+  if (rcp == DEVICE_RECIPIENT && index == 0 && length == 0)
+    {
+      int r;
+
+      r = (*method_p->event) (USB_EVENT_CONFIG, value);
+      if (r == USB_SUCCESS)
+       return USB_SUCCESS;
+    }
+
+  return USB_UNSUPPORT;
+}
+
+static int std_get_interface (uint8_t req, uint16_t value,
+                             uint16_t index, uint16_t length)
+{
+  uint8_t rcp = req & RECIPIENT;
+
+  if ((req & REQUEST_DIR) == 0)
+    return USB_UNSUPPORT;
+
+  if (rcp == INTERFACE_RECIPIENT)
+    {
+      if (value != 0 || (index >> 8) != 0 || length != 1)
+       return USB_UNSUPPORT;
+
+      if (dev_p->current_configuration == 0)
+       return USB_UNSUPPORT;
+
+      return (*method_p->interface) (USB_GET_INTERFACE, index, 0);
+    }
+
+  return USB_UNSUPPORT;
+}
+
+static int std_set_interface (uint8_t req, uint16_t value,
+                             uint16_t index, uint16_t length)
+{
+  uint8_t rcp = req & RECIPIENT;
+
+  if ((req & REQUEST_DIR) == 1)
+    return USB_UNSUPPORT;
+
+  if (rcp == INTERFACE_RECIPIENT)
+    {
+      int r;
+
+      if (length != 0 || (index >> 8) != 0 || (value >> 8) != 0)
+       return  USB_UNSUPPORT;
+
+      if (dev_p->current_configuration != 0)
+       return USB_UNSUPPORT;
+
+      r = (*method_p->interface) (USB_SET_INTERFACE, index, value);
+      if (r == USB_SUCCESS)
+       return USB_SUCCESS;
+    }
+
+  return USB_UNSUPPORT;
+}
+
+static const HANDLER std_request_handler[TOTAL_REQUEST] = {
+  std_get_status,
+  std_clear_feature,
+  std_none,
+  std_set_feature,
+  std_none,
+  std_set_address,
+  std_get_descriptor,
+  std_none,                    /* set_descriptor is not supported */
+  std_get_configuration,
+  std_set_configuration,
+  std_get_interface,
+  std_set_interface,
+  std_none,                    /* sync_frame is not  supported (for now) */
+};
+
+static void handle_setup0 (void)
+{
+  const uint16_t *pw;
+  uint16_t w;
+  uint8_t req;
+  int r = USB_UNSUPPORT;
+  HANDLER handler;
+
+  pw = (uint16_t *)(PMA_ADDR + (uint8_t *)(st103_get_rx_addr (ENDP0) * 2));
+  w = *pw++;
+
+  ctrl_p->bmRequestType = w & 0xff;
+  ctrl_p->bRequest = req = w >> 8;
+  pw++;
+  ctrl_p->wValue = *pw++;
+  pw++;
+  ctrl_p->wIndex  = *pw++;
+  pw++;
+  ctrl_p->wLength = *pw;
+
+  data_p->addr = NULL;
+  data_p->len = 0;
+  data_p->offset = 0;
+
+  if ((ctrl_p->bmRequestType & REQUEST_TYPE) == STANDARD_REQUEST)
+    {
+      if (req < TOTAL_REQUEST)
+       {
+         handler = std_request_handler[req];
+         r = (*handler) (ctrl_p->bmRequestType,
+                         ctrl_p->wValue, ctrl_p->wIndex, ctrl_p->wLength);
+       }
+    }
+  else
+    r = (*method_p->setup) (ctrl_p->bmRequestType, req,
+                           ctrl_p->wValue, ctrl_p->wIndex, ctrl_p->wLength);
+
+  if (r != USB_SUCCESS)
+    dev_p->state = STALLED;
+  else
+    {
+      if (USB_SETUP_GET (ctrl_p->bmRequestType))
+       {
+         uint32_t len = ctrl_p->wLength;
+
+         /* Restrict the data length to be the one host asks for */
+         if (data_p->len > len)
+           data_p->len = len;
+
+         if ((data_p->len % USB_MAX_PACKET_SIZE) == 0)
+           data_p->require_zlp = TRUE;
+         else
+           data_p->require_zlp = FALSE;
+
+         dev_p->state = IN_DATA;
+         handle_datastage_in ();
+       }
+      else if (ctrl_p->wLength == 0)
+       {
+         dev_p->state = WAIT_STATUS_IN;
+         st103_set_tx_count (ENDP0, 0);
+         st103_ep_set_rxtx_status (ENDP0, EP_RX_STALL, EP_TX_VALID);
+       }
+      else
+       {
+         dev_p->state = OUT_DATA;
+         st103_ep_set_rx_status (ENDP0, EP_RX_VALID);
+       }
+    }
+}
+
+static void handle_in0 (void)
+{
+  if (dev_p->state == IN_DATA || dev_p->state == LAST_IN_DATA)
+    handle_datastage_in ();
+  else if (dev_p->state == WAIT_STATUS_IN)
+    {
+      if ((ctrl_p->bRequest == SET_ADDRESS) &&
+         ((ctrl_p->bmRequestType & (REQUEST_TYPE | RECIPIENT))
+          == (STANDARD_REQUEST | DEVICE_RECIPIENT)))
+       {
+         st103_set_daddr (ctrl_p->wValue);
+         (*method_p->event) (USB_EVENT_ADDRESS, ctrl_p->wValue);
+       }
+      else
+       (*method_p->ctrl_write_finish)  (ctrl_p->bmRequestType,
+                                        ctrl_p->bRequest, ctrl_p->wValue,
+                                        ctrl_p->wIndex, ctrl_p->wLength);
+
+      dev_p->state = STALLED;
+    }
+  else
+    dev_p->state = STALLED;
+}
+
+static void handle_out0 (void)
+{
+  if (dev_p->state == IN_DATA || dev_p->state == LAST_IN_DATA)
+    /* host aborts the transfer before finish */
+    dev_p->state = STALLED;
+  else if (dev_p->state == OUT_DATA)
+    handle_datastage_out ();
+  else if (dev_p->state == WAIT_STATUS_OUT)
+    dev_p->state = STALLED;
+  /* Unexpect state, STALL the endpoint */
+  else
+    dev_p->state = STALLED;
+}
+\f
+static void nop_proc (void)
+{
+}
+
+#define WEAK __attribute__ ((weak, alias ("nop_proc")))
+void WEAK EP1_IN_Callback (void);
+void WEAK EP2_IN_Callback (void);
+void WEAK EP3_IN_Callback (void);
+void WEAK EP4_IN_Callback (void);
+void WEAK EP5_IN_Callback (void);
+void WEAK EP6_IN_Callback (void);
+void WEAK EP7_IN_Callback (void);
+
+void WEAK EP1_OUT_Callback (void);
+void WEAK EP2_OUT_Callback (void);
+void WEAK EP3_OUT_Callback (void);
+void WEAK EP4_OUT_Callback (void);
+void WEAK EP5_OUT_Callback (void);
+void WEAK EP6_OUT_Callback (void);
+void WEAK EP7_OUT_Callback (void);
+
+void (*const ep_intr_handler_IN[7]) (void) = {
+  EP1_IN_Callback,
+  EP2_IN_Callback,
+  EP3_IN_Callback,
+  EP4_IN_Callback,
+  EP5_IN_Callback,
+  EP6_IN_Callback,
+  EP7_IN_Callback,
+};
+
+void (*const ep_intr_handler_OUT[7]) (void) = {
+  EP1_OUT_Callback,
+  EP2_OUT_Callback,
+  EP3_OUT_Callback,
+  EP4_OUT_Callback,
+  EP5_OUT_Callback,
+  EP6_OUT_Callback,
+  EP7_OUT_Callback,
+};
+
+static void
+usb_handle_transfer (void)
+{
+  uint16_t ep_value = 0;
+  uint16_t istr_value;
+  uint8_t ep_index;
+
+  while (((istr_value = st103_get_istr ()) & ISTR_CTR) != 0)
+    {
+      ep_index = (istr_value & ISTR_EP_ID);
+      if (ep_index == 0)
+       {
+         if ((istr_value & ISTR_DIR) == 0)
+           {                           /* DIR = 0 */
+             /* DIR = 0      => IN  int */
+             /* DIR = 0 implies that (EP_CTR_TX = 1) always  */
+
+             st103_ep_clear_ctr_tx (ENDP0);
+             handle_in0 ();
+           }
+         else
+           {                           /* DIR = 1 */
+             /* DIR = 1 & CTR_RX       => SETUP or OUT int */
+             /* DIR = 1 & (CTR_TX | CTR_RX) => 2 int pending */
+
+             ep_value = st103_get_epreg (ENDP0);
+             if ((ep_value & EP_SETUP) != 0)
+               {
+                 st103_ep_clear_ctr_rx (ENDP0);
+                 handle_setup0 ();
+               }
+             else if ((ep_value & EP_CTR_RX) != 0)
+               {
+                 st103_ep_clear_ctr_rx (ENDP0);
+                 handle_out0 ();
+               }
+           }
+
+         if (dev_p->state == STALLED)
+           st103_ep_set_rxtx_status (ENDP0, EP_RX_STALL, EP_TX_STALL);
+       }
+      else
+       {
+         /* Decode and service non control endpoints interrupt  */
+         /* process related endpoint register */
+         ep_value = st103_get_epreg (ep_index);
+
+         if ((ep_value & EP_CTR_RX) != 0)
+           {
+             st103_ep_clear_ctr_rx (ep_index);
+             (*ep_intr_handler_OUT[ep_index-1]) ();
+           }
+
+         if ((ep_value & EP_CTR_TX) != 0)
+           {
+             st103_ep_clear_ctr_tx (ep_index);
+             (*ep_intr_handler_IN[ep_index-1]) ();
+           }
+       }
+    }
+}
+\f
+void usb_lld_reset (void)
+{
+  st103_set_btable ();
+  st103_set_daddr (0);
+}
+
+void usb_lld_txcpy (const void *src,
+                   int ep_num, int offset, size_t len)
+{
+  usb_lld_to_pmabuf (src, st103_get_tx_addr (ep_num) + offset, len);
+}
+
+void usb_lld_write (uint8_t ep_num, const void *buf, size_t len)
+{
+  usb_lld_to_pmabuf (buf, st103_get_tx_addr (ep_num), len);
+  st103_set_tx_count (ep_num, len);
+  st103_ep_set_tx_status (ep_num, EP_TX_VALID);
+}
+
+void usb_lld_rxcpy (uint8_t *dst,
+                   int ep_num, int offset, size_t len)
+{
+  usb_lld_from_pmabuf (dst, st103_get_rx_addr (ep_num) + offset, len);
+}
+
+void usb_lld_tx_enable (int ep_num, size_t len)
+{
+  st103_set_tx_count (ep_num, len);
+  st103_ep_set_tx_status (ep_num, EP_TX_VALID);
+}
+
+int usb_lld_tx_data_len (int ep_num)
+{
+  return st103_get_tx_count (ep_num);
+}
+
+int usb_lld_rx_data_len (int ep_num)
+{
+  return st103_get_rx_count (ep_num);
+}
+
+void usb_lld_stall_tx (int ep_num)
+{
+  st103_ep_set_tx_status (ep_num, EP_TX_STALL);
+}
+
+void usb_lld_stall_rx (int ep_num)
+{
+  st103_ep_set_rx_status (ep_num, EP_RX_STALL);
+}
+
+void usb_lld_rx_enable (int ep_num)
+{
+  st103_ep_set_rx_status (ep_num, EP_RX_VALID);
+}
+
+void usb_lld_setup_endpoint (int ep_num, int ep_type, int ep_kind,
+                            int ep_rx_addr, int ep_tx_addr,
+                            int ep_rx_buf_size)
+{
+  uint16_t epreg_value = st103_get_epreg (ep_num);
+  uint16_t ep_rxtx_status = 0; /* Both disabled */
+
+  /* Clear: Write 1 if 1: EP_DTOG_RX, EP_DTOG_TX */
+  /* Set: Write:          EP_T_FIELD, EP_KIND, EPADDR_FIELD */
+  /* Set: Toggle:         EPRX_STAT, EPTX_STAT */
+  epreg_value &= (EPRX_STAT | EP_SETUP | EPTX_STAT | EP_DTOG_RX | EP_DTOG_TX);
+#if USB_KEEP_CORRECT_TRANSFER_FLAGS
+  /* Keep: Write 1:       EP_CTR_RX, EP_CTR_TX */
+  epreg_value |= (EP_CTR_RX|EP_CTR_TX);
+#else
+  /* Clear: Write 0:      EP_CTR_RX, EP_CTR_TX */
+#endif
+  epreg_value |= ep_type;
+  epreg_value |= ep_kind;
+  epreg_value |= ep_num;
+
+  if (ep_rx_addr)
+    {
+      ep_rxtx_status |= EP_RX_VALID;
+      st103_set_rx_addr (ep_num, ep_rx_addr);
+      st103_set_rx_buf_size (ep_num, ep_rx_buf_size);
+    }
+
+  if (ep_tx_addr)
+    {
+      ep_rxtx_status |= EP_TX_NAK;
+      st103_set_tx_addr (ep_num, ep_tx_addr);
+    }
+
+  epreg_value ^= (EPRX_DTOG1 & ep_rxtx_status);
+  epreg_value ^= (EPRX_DTOG2 & ep_rxtx_status);
+  epreg_value ^= (EPTX_DTOG1 & ep_rxtx_status);
+  epreg_value ^= (EPTX_DTOG2 & ep_rxtx_status);
+
+  st103_set_epreg (ep_num, epreg_value);
+}
+
+void usb_lld_set_configuration (uint8_t config)
+{
+  dev_p->current_configuration = config;
+}
+
+uint8_t usb_lld_current_configuration (void)
+{
+  return dev_p->current_configuration;
+}
+
+void usb_lld_set_feature (uint8_t feature)
+{
+  dev_p->current_feature = feature;
+}
+
+void usb_lld_set_data_to_send (const void *p, size_t len)
+{
+  data_p->addr = (uint8_t *)p;
+  data_p->len = len;
+}
+
+void usb_lld_to_pmabuf (const void *src, uint16_t addr, size_t n)
+{
+  const uint8_t *s = (const uint8_t *)src;
+  uint16_t *p;
+  uint16_t w;
+
+  if (n == 0)
+    return;
+
+  if ((addr & 1))
+    {
+      p = (uint16_t *)(PMA_ADDR + (addr - 1) * 2);
+      w = *p;
+      w = (w & 0xff) | (*s++) << 8;
+      *p = w;
+      p += 2;
+      n--;
+    }
+  else
+    p = (uint16_t *)(PMA_ADDR + addr * 2);
+
+  while (n >= 2)
+    {
+      w = *s++;
+      w |= (*s++) << 8;
+      *p = w;
+      p += 2;
+      n -= 2;
+    }
+
+  if (n > 0)
+    {
+      w = *s;
+      *p = w;
+    }
+}
+
+void usb_lld_from_pmabuf (void *dst, uint16_t addr, size_t n)
+{
+  uint8_t *d = (uint8_t *)dst;
+  uint16_t *p;
+  uint16_t w;
+
+  if (n == 0)
+    return;
+
+  if ((addr & 1))
+    {
+      p = (uint16_t *)(PMA_ADDR + (addr - 1) * 2);
+      w = *p;
+      *d++ = (w >> 8);
+      p += 2;
+      n--;
+    }
+  else
+    p = (uint16_t *)(PMA_ADDR + addr * 2);
+
+  while (n >= 2)
+    {
+      w = *p;
+      *d++ = (w & 0xff);
+      *d++ = (w >> 8);
+      p += 2;
+      n -= 2;
+    }
+
+  if (n > 0)
+    {
+      w = *p;
+      *d = (w & 0xff);
+    }
+}