From 82749ab97af6ec1de605f0638d44999c3b50eadf Mon Sep 17 00:00:00 2001
From: NIIBE Yutaka <gniibe@fsij.org>
Date: Mon, 18 Apr 2016 11:46:14 +0900
Subject: Add support for FS-BB48

---
 ChangeLog                   |   11 +
 NEWS                        |   17 +
 README                      |    7 +-
 board/board-fs-bb48.h       |    5 +
 clk_gpio_init-kl.c          |  170 +++++++
 clk_gpio_init-stm32.c       |  368 +++++++++++++++
 clk_gpio_init.c             |  368 ---------------
 entry.c                     |    6 +-
 example-fs-bb48/Makefile    |   31 ++
 example-fs-bb48/board.h     |    1 +
 example-fs-bb48/reset.c     |  114 +++++
 example-fs-bb48/sample.c    |  228 ++++++++++
 example-fs-bb48/sample.ld   |  135 ++++++
 example-fs-bb48/stream.h    |   24 +
 example-fs-bb48/usb-cdc.c   |  506 +++++++++++++++++++++
 example-fs-bb48/usb_kl27z.c | 1035 +++++++++++++++++++++++++++++++++++++++++++
 example-fs-bb48/usb_lld.h   |  115 +++++
 example-fsm-55/sys.c        |   12 +-
 18 files changed, 2770 insertions(+), 383 deletions(-)
 create mode 100644 board/board-fs-bb48.h
 create mode 100644 clk_gpio_init-kl.c
 create mode 100644 clk_gpio_init-stm32.c
 delete mode 100644 clk_gpio_init.c
 create mode 100644 example-fs-bb48/Makefile
 create mode 120000 example-fs-bb48/board.h
 create mode 100644 example-fs-bb48/reset.c
 create mode 100644 example-fs-bb48/sample.c
 create mode 100644 example-fs-bb48/sample.ld
 create mode 100644 example-fs-bb48/stream.h
 create mode 100644 example-fs-bb48/usb-cdc.c
 create mode 100644 example-fs-bb48/usb_kl27z.c
 create mode 100644 example-fs-bb48/usb_lld.h

diff --git a/ChangeLog b/ChangeLog
index a0717af..564e047 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2016-04-18  Niibe Yutaka  <gniibe@fsij.org>
+
+	* example-fs-bb48: New directory for FS-BB48.
+
+	* clk_gpio_init-kl.c: New.
+	* clk_gpio_init-stm32.c: Rename from clk_gpio_init.c.
+
+2016-04-07  Niibe Yutaka  <gniibe@fsij.org>
+
+	* example-fsm-55/sys.c: Update for non-SVC Chopstx.
+
 2016-04-07  Niibe Yutaka  <gniibe@fsij.org>
 
 	* example-cdc/usb-cdc.c: Update.
diff --git a/NEWS b/NEWS
index fcc4df2..b6ca8f6 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,23 @@
 NEWS - Noteworthy changes
 
 
+* Major changes in Chopstx 0.11
+
+  Released 2016-0X-XX
+
+** FS-BB48: Kinetis L MCU
+Support for FS-BB48 board with Kinetis L MCU is added.
+
+** No HardFault at context switch on Cortex-M0
+By its design, Chopstx does context switch hodling scheduler lock.
+This is implemented with the feature of BASEPRI on Cortex-M3.  Because
+Cortex-M0 doesn't have support of BASEPRI, the context switch (before
+version 0.11) always caused HardFault exception.  Since Cortex-M0
+doesn't have complex exception mechism of ICI/IT (which is supported
+on Cortex-M3), it is actually possible to implement the context switch
+in user mode.  This is done.
+
+
 * Major changes in Chopstx 0.10
 
   Released 2015-09-15
diff --git a/README b/README
index b49b53e..2811ce9 100644
--- a/README
+++ b/README
@@ -1,6 +1,6 @@
 Chopstx - Threads and only Threads
-							Version 0.10
-							  2015-09-15
+							Version 0.11
+							  2016-04-XX
 							Niibe Yutaka
 					     Flying Stone Technology
 
@@ -46,6 +46,5 @@ Future Works
 ============
 
 Convenience function to determine bottom of thread stack, thread local
-storage and support of interface like poll/select would be next thing
-to be done.
+storage would be next thing to be done.
 -- 
diff --git a/board/board-fs-bb48.h b/board/board-fs-bb48.h
new file mode 100644
index 0000000..cdf1dfa
--- /dev/null
+++ b/board/board-fs-bb48.h
@@ -0,0 +1,5 @@
+#define BOARD_NAME "FS-BB48"
+#define BOARD_ID    0xd1f5119c
+/* echo -n "FST-01" | sha256sum | sed -e 's/^.*\(........\)  -$/\1/' */
+
+#define MCU_KINETIS_L      1
diff --git a/clk_gpio_init-kl.c b/clk_gpio_init-kl.c
new file mode 100644
index 0000000..b9c1c3e
--- /dev/null
+++ b/clk_gpio_init-kl.c
@@ -0,0 +1,170 @@
+/*
+ * clk_gpio_init-kl.c - Clock and GPIO initialization for Kinetis L.
+ *
+ * Copyright (C) 2016  Flying Stone Technology
+ * Author: NIIBE Yutaka <gniibe@fsij.org>
+ *
+ * This file is a part of Chopstx, a thread library for embedded.
+ *
+ * Chopstx 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.
+ *
+ * Chopstx 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/>.
+ *
+ * As additional permission under GNU GPL version 3 section 7, you may
+ * distribute non-source form of the Program without the copy of the
+ * GNU GPL normally required by section 4, provided you inform the
+ * receipents of GNU GPL by a written offer.
+ *
+ */
+
+/* System Integration Module.  */
+struct SIM {
+  volatile uint32_t SOPT1;    /* System Options Register 1               */
+  volatile uint32_t SOPT1CFG; /* SOPT1 Configuration Register            */
+  uint32_t reserved0[1023];   /*                                         */
+  volatile uint32_t SOPT2;    /* System Options Register 2               */
+  uint32_t reserved1[1];      /*                                         */
+  volatile uint32_t SOPT4;    /* System Options Register 4               */
+  volatile uint32_t SOPT5;    /* System Options Register 5               */
+  uint32_t reserved2[1];      /*                                         */
+  volatile uint32_t SOPT7;    /* System Options Register 7               */
+  uint32_t reserved3[2];       /*                                         */
+  volatile uint32_t SDID;     /* System Device Identification Register   */
+  uint32_t reserved4[3];      /*                                         */
+  volatile uint32_t SCGC4;    /* System Clock Gating Control Register 4  */
+  volatile uint32_t SCGC5;    /* System Clock Gating Control Register 5  */
+  volatile uint32_t SCGC6;    /* System Clock Gating Control Register 6  */
+  volatile uint32_t SCGC7;    /* System Clock Gating Control Register 7  */
+  volatile uint32_t CLKDIV1;  /* System Clock Divider Register 1         */
+  uint32_t reserved5[1];      /*                                         */
+  volatile uint32_t FCFG1;    /* Flash Configuration Register 1          */
+  volatile uint32_t FCFG2;    /* Flash Configuration Register 2          */
+  uint32_t reserved6[1];      /*                                         */
+  volatile uint32_t UIDMH;    /* Unique Identification Register Mid-High */
+  volatile uint32_t UIDML;    /* Unique Identification Register Mid Low  */
+  volatile uint32_t UIDL;     /* Unique Identification Register Low      */
+  uint32_t reserved7[39];     /*                                         */
+  volatile uint32_t COPC;     /* COP Control Register                    */
+  volatile uint32_t SRVCOP;   /* Service COP                             */
+};
+static struct SIM *const SIM = (struct SIM *const)0x40047000;
+
+struct MCG {
+  volatile uint8_t C1;   /* MCG Control Register 1             */
+  volatile uint8_t C2;   /* MCG Control Register 2             */
+  uint8_t reserved0[4];  /*                                    */
+  volatile uint8_t S;    /* MCG Status Register                */
+  uint8_t reserved1[1];  /*                                    */
+  volatile uint8_t SC;   /* MCG Status and Control Register    */
+  uint8_t reserved2[15]; /*                                    */
+  volatile uint8_t MC;   /* MCG Miscellaneous Control Register */
+};
+static struct MCG *const MCG = (struct MCG *const)0x40064000;
+
+struct USB_CLK_RECOVER {
+  volatile uint8_t CTRL;           /* USB Clock             */
+  uint8_t rsvd38[3];               /*     recovery control  */
+  volatile uint8_t IRC_EN;         /* IRC48M oscillator     */
+  uint8_t rsvd39[3];               /*     enable register   */
+  volatile uint8_t INT_EN;         /* Clock recovery        */
+  uint8_t rsvd40[3];               /*     interrupt enable  */
+  volatile uint8_t INT_STATUS;     /* Clock recovery        */
+                                   /*     interrupt status  */
+};
+static struct USB_CLK_RECOVER *const USB_CLK_RECOVER =
+  (struct USB_CLK_RECOVER *const)0x40072140;
+
+static void __attribute__((used))
+clock_init (void)
+{
+  SIM->CLKDIV1 = (SIM->CLKDIV1 & 0xF0070000)
+               | (1 << 16)	/* OUTDIV4 = 001: Divide-by-2 */
+               ;
+
+  MCG->MC = 0x80; /* HIRC Enable, LIRC_DIV2=000: Division factor=1 */
+  MCG->C1 = 0x00; /* Select HIRC clock, LIRC disabled. */
+  /* Make sure HIRC clock is selected.  */
+  while ((MCG->S & 0x0c) != 0)
+    ;
+
+  SIM->SOPT2 = 0x00040060;	/* USBSRC=IRC48, CLOKOUTSEL=LPO, RTC-clock */
+
+  SIM->SCGC4 = (1 << 18);	/* Enable USB FS clock         */
+  SIM->SCGC5 = (1 << 10);	/* Enable Port B clock        */
+  SIM->COPC = 0;		/* COP disabled               */
+
+  /* Crystal-less USB setup.  */
+  USB_CLK_RECOVER->IRC_EN = 0x02;
+  USB_CLK_RECOVER->CTRL = 0x80;
+}
+
+
+struct PORT {
+  volatile uint32_t PCR0;  volatile uint32_t PCR1;
+  volatile uint32_t PCR2;  volatile uint32_t PCR3;
+  volatile uint32_t PCR4;  volatile uint32_t PCR5;
+  volatile uint32_t PCR6;  volatile uint32_t PCR7;
+  volatile uint32_t PCR8;  volatile uint32_t PCR9;
+  volatile uint32_t PCR10; volatile uint32_t PCR11;
+  volatile uint32_t PCR12; volatile uint32_t PCR13;
+  volatile uint32_t PCR14; volatile uint32_t PCR15;
+  volatile uint32_t PCR16; volatile uint32_t PCR17;
+  volatile uint32_t PCR18; volatile uint32_t PCR19;
+  volatile uint32_t PCR20; volatile uint32_t PCR21;
+  volatile uint32_t PCR22; volatile uint32_t PCR23;
+  volatile uint32_t PCR24; volatile uint32_t PCR25;
+  volatile uint32_t PCR26; volatile uint32_t PCR27;
+  volatile uint32_t PCR28; volatile uint32_t PCR29;
+  volatile uint32_t PCR30; volatile uint32_t PCR31;
+  volatile uint32_t GPCLR; volatile uint32_t GPCHR;
+  uint32_t reserved[6];
+  volatile uint32_t ISFR;
+};
+static struct PORT *const PORTB = (struct PORT *const)0x4004A000;
+static struct PORT *const PORTD = (struct PORT *const)0x4004C000;
+static struct PORT *const PORTE = (struct PORT *const)0x4004D000;
+
+struct GPIO {
+  volatile uint32_t PDOR; /* Port Data Output Register    */
+  volatile uint32_t PSOR; /* Port Set Output Register     */
+  volatile uint32_t PCOR; /* Port Clear Output Register   */
+  volatile uint32_t PTOR; /* Port Toggle Output Register  */
+  volatile uint32_t PDIR; /* Port Data Input Register     */
+  volatile uint32_t PDDR; /* Port Data Direction Register */
+};
+static struct GPIO *const GPIOB = (struct GPIO *const)0x400FF040;
+static struct GPIO *const GPIOD = (struct GPIO *const)0x400FF0C0;
+static struct GPIO *const GPIOE = (struct GPIO *const)0x400FF100;
+
+
+static void __attribute__((used))
+gpio_init (void)
+{
+  PORTB->PCR0 = (1<<8) /* GPIO                  */
+              | (0<<6) /* DriveStrengthEnable=0 */
+              | (0<<4) /* PassiveFilterEnable=0 */
+              | (1<<2) /* SlewRateEnable = slow */
+              | (0<<1) /* pull enable = 0       */ 
+              | (0<<0) /* puddselect= 0         */
+              ;
+  PORTB->PCR1 = (1<<8) /* GPIO                  */
+              | (0<<6) /* DriveStrengthEnable=0 */
+              | (0<<4) /* PassiveFilterEnable=0 */
+              | (1<<2) /* SlewRateEnable = slow */
+              | (0<<1) /* pull enable = 0       */ 
+              | (0<<0) /* puddselect= 0         */
+              ;
+
+  GPIOB->PDDR = (1 << 1) | (1 << 0); /* PTB0, PTB1 : Output    */
+  GPIOB->PSOR = (1 << 0);            /* PTB0: Set  : Light off */
+  GPIOB->PCOR = (1 << 1);            /* PTB1: Clear: Output 0  */
+}
diff --git a/clk_gpio_init-stm32.c b/clk_gpio_init-stm32.c
new file mode 100644
index 0000000..50660ea
--- /dev/null
+++ b/clk_gpio_init-stm32.c
@@ -0,0 +1,368 @@
+/*
+ * clk_gpio_init-stm32.c - Clock and GPIO initialization for STM32.
+ *
+ * Copyright (C) 2015  Flying Stone Technology
+ * Author: NIIBE Yutaka <gniibe@fsij.org>
+ *
+ * This file is a part of Chopstx, a thread library for embedded.
+ *
+ * Chopstx 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.
+ *
+ * Chopstx 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/>.
+ *
+ * As additional permission under GNU GPL version 3 section 7, you may
+ * distribute non-source form of the Program without the copy of the
+ * GNU GPL normally required by section 4, provided you inform the
+ * receipents of GNU GPL by a written offer.
+ *
+ */
+
+#define STM32_SW_HSI		(0 << 0)
+#define STM32_SW_PLL		(2 << 0)
+#define STM32_PLLSRC_HSI	(0 << 16)
+#define STM32_PLLSRC_HSE	(1 << 16)
+
+#define STM32_PLLXTPRE_DIV1	(0 << 17)
+#define STM32_PLLXTPRE_DIV2	(1 << 17)
+
+#define STM32_HPRE_DIV1		(0 << 4)
+
+#define STM32_PPRE1_DIV1	(0 << 8)
+#define STM32_PPRE1_DIV2	(4 << 8)
+
+#define STM32_PPRE2_DIV1        (0 << 11)
+#define STM32_PPRE2_DIV2	(4 << 11)
+
+#define STM32_ADCPRE_DIV4	(1 << 14)
+#define STM32_ADCPRE_DIV6       (2 << 14)
+
+#define STM32_USBPRE_DIV1P5     (0 << 22)
+
+#define STM32_MCO_NOCLOCK	(0 << 24)
+
+#if defined(MCU_STM32F0)
+#define STM32_PPRE1		STM32_PPRE1_DIV1
+#define STM32_PLLSRC		STM32_PLLSRC_HSI
+#define STM32_FLASHBITS		0x00000011
+#define STM32_PLLCLKIN		(STM32_HSICLK / 2)
+#else
+#define STM32_PPRE1		STM32_PPRE1_DIV2
+#define STM32_PLLSRC		STM32_PLLSRC_HSE
+#define STM32_FLASHBITS		0x00000012
+#define STM32_PLLCLKIN		(STM32_HSECLK / 1)
+#endif
+
+#define STM32_SW		STM32_SW_PLL
+#define STM32_HPRE		STM32_HPRE_DIV1
+#define STM32_PPRE2		STM32_PPRE2_DIV1
+#define STM32_ADCPRE		STM32_ADCPRE_DIV6
+#define STM32_MCOSEL		STM32_MCO_NOCLOCK
+#define STM32_USBPRE            STM32_USBPRE_DIV1P5
+
+#define STM32_PLLMUL		((STM32_PLLMUL_VALUE - 2) << 18)
+#define STM32_PLLCLKOUT		(STM32_PLLCLKIN * STM32_PLLMUL_VALUE)
+#define STM32_SYSCLK		STM32_PLLCLKOUT
+#define STM32_HCLK		(STM32_SYSCLK / 1)
+
+
+#define PERIPH_BASE	0x40000000
+#define APBPERIPH_BASE   PERIPH_BASE
+#define APB2PERIPH_BASE	(PERIPH_BASE + 0x10000)
+#define AHBPERIPH_BASE	(PERIPH_BASE + 0x20000)
+#define AHB2PERIPH_BASE	(PERIPH_BASE + 0x08000000)
+
+struct RCC {
+  volatile uint32_t CR;
+  volatile uint32_t CFGR;
+  volatile uint32_t CIR;
+  volatile uint32_t APB2RSTR;
+  volatile uint32_t APB1RSTR;
+  volatile uint32_t AHBENR;
+  volatile uint32_t APB2ENR;
+  volatile uint32_t APB1ENR;
+  volatile uint32_t BDCR;
+  volatile uint32_t CSR;
+#if defined(MCU_STM32F0)
+  volatile uint32_t AHBRSTR;
+  volatile uint32_t CFGR2;
+  volatile uint32_t CFGR3;
+  volatile uint32_t CR2;
+#endif
+};
+
+#define RCC_BASE		(AHBPERIPH_BASE + 0x1000)
+static struct RCC *const RCC = ((struct RCC *const)RCC_BASE);
+
+#define RCC_APB1ENR_USBEN	0x00800000
+#define RCC_APB1RSTR_USBRST	0x00800000
+
+#define RCC_CR_HSION		0x00000001
+#define RCC_CR_HSIRDY		0x00000002
+#define RCC_CR_HSITRIM		0x000000F8
+#define RCC_CR_HSEON		0x00010000
+#define RCC_CR_HSERDY		0x00020000
+#define RCC_CR_PLLON		0x01000000
+#define RCC_CR_PLLRDY		0x02000000
+
+#define RCC_CFGR_SWS		0x0000000C
+#define RCC_CFGR_SWS_HSI	0x00000000
+
+#define RCC_AHBENR_CRCEN        0x0040
+
+#if defined(MCU_STM32F0)
+#define RCC_AHBRSTR_IOPARST	0x00020000
+#define RCC_AHBRSTR_IOPBRST	0x00040000
+#define RCC_AHBRSTR_IOPCRST	0x00080000
+#define RCC_AHBRSTR_IOPDRST	0x00100000
+#define RCC_AHBRSTR_IOPFRST	0x00400000
+
+#define RCC_AHBENR_IOPAEN	0x00020000
+#define RCC_AHBENR_IOPBEN	0x00040000
+#define RCC_AHBENR_IOPCEN	0x00080000
+#define RCC_AHBENR_IOPDEN	0x00100000
+#define RCC_AHBENR_IOPFEN	0x00400000
+
+#define RCC_APB2RSTR_SYSCFGRST	0x00000001
+#define RCC_APB2ENR_SYSCFGEN	0x00000001
+#else
+#define RCC_APB2RSTR_AFIORST	0x00000001
+#define RCC_APB2RSTR_IOPARST	0x00000004
+#define RCC_APB2RSTR_IOPBRST	0x00000008
+#define RCC_APB2RSTR_IOPCRST	0x00000010
+#define RCC_APB2RSTR_IOPDRST	0x00000020
+#define RCC_APB2RSTR_IOPERST	0x00000040
+#define RCC_APB2RSTR_IOPFRST	0x00000080
+#define RCC_APB2RSTR_IOPGRST	0x00000100
+
+#define RCC_APB2ENR_AFIOEN	0x00000001
+#define RCC_APB2ENR_IOPAEN	0x00000004
+#define RCC_APB2ENR_IOPBEN	0x00000008
+#define RCC_APB2ENR_IOPCEN	0x00000010
+#define RCC_APB2ENR_IOPDEN	0x00000020
+#define RCC_APB2ENR_IOPEEN	0x00000040
+#define RCC_APB2ENR_IOPFEN	0x00000080
+#define RCC_APB2ENR_IOPGEN	0x00000100
+#endif
+
+#if defined(MCU_STM32F0)
+struct SYSCFG {
+  volatile uint32_t CFGR1;
+  uint32_t dummy0;
+  volatile uint32_t EXTICR[4];
+  volatile uint32_t CFGR2;
+};
+#define SYSCFG_CFGR1_MEM_MODE 0x03
+
+#define SYSCFG_BASE	(APBPERIPH_BASE + 0x00010000)
+static struct SYSCFG *const SYSCFG = ((struct SYSCFG *const) SYSCFG_BASE);
+#endif
+
+struct FLASH {
+  volatile uint32_t ACR;
+  volatile uint32_t KEYR;
+  volatile uint32_t OPTKEYR;
+  volatile uint32_t SR;
+  volatile uint32_t CR;
+  volatile uint32_t AR;
+  volatile uint32_t RESERVED;
+  volatile uint32_t OBR;
+  volatile uint32_t WRPR;
+};
+
+#define FLASH_R_BASE	(AHBPERIPH_BASE + 0x2000)
+static struct FLASH *const FLASH = ((struct FLASH *const) FLASH_R_BASE);
+
+static void __attribute__((used))
+clock_init (void)
+{
+  /* HSI setup */
+  RCC->CR |= RCC_CR_HSION;
+  while (!(RCC->CR & RCC_CR_HSIRDY))
+    ;
+  /* Reset HSEON, HSEBYP, CSSON, and PLLON, not touching RCC_CR_HSITRIM */
+  RCC->CR &= (RCC_CR_HSITRIM | RCC_CR_HSION);
+  RCC->CFGR = 0;
+  while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI)
+    ;
+
+#if !defined(MCU_STM32F0)
+  /* HSE setup */
+  RCC->CR |= RCC_CR_HSEON;
+  while (!(RCC->CR & RCC_CR_HSERDY))
+    ;
+#endif
+
+  /* PLL setup */
+  RCC->CFGR |= STM32_PLLMUL | STM32_PLLXTPRE | STM32_PLLSRC;
+  RCC->CR   |= RCC_CR_PLLON;
+  while (!(RCC->CR & RCC_CR_PLLRDY))
+    ;
+
+  /* Clock settings */
+  RCC->CFGR = STM32_MCOSEL | STM32_USBPRE | STM32_PLLMUL | STM32_PLLXTPRE
+    | STM32_PLLSRC | STM32_ADCPRE | STM32_PPRE2 | STM32_PPRE1 | STM32_HPRE;
+
+  /*
+   * We don't touch RCC->CR2, RCC->CFGR2, RCC->CFGR3, and RCC->CIR.
+   */
+
+  /* Flash setup */
+  FLASH->ACR = STM32_FLASHBITS;
+
+  /* CRC */
+  RCC->AHBENR |= RCC_AHBENR_CRCEN;
+
+  /* Switching on the configured clock source. */
+  RCC->CFGR |= STM32_SW;
+  while ((RCC->CFGR & RCC_CFGR_SWS) != (STM32_SW << 2))
+    ;
+
+#if defined(MCU_STM32F0)
+  RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
+  RCC->APB2RSTR = RCC_APB2RSTR_SYSCFGRST;
+  RCC->APB2RSTR = 0;
+
+# if defined(HAVE_SYS_H)
+  /* Use vectors on RAM */
+  SYSCFG->CFGR1 = (SYSCFG->CFGR1 & ~SYSCFG_CFGR1_MEM_MODE) | 3;
+# endif
+#endif
+}
+
+
+#if defined(MCU_STM32F0)
+struct GPIO {
+  volatile uint32_t MODER;
+  volatile uint16_t OTYPER;
+  uint16_t dummy0;
+  volatile uint32_t OSPEEDR;
+  volatile uint32_t PUPDR;
+  volatile uint16_t IDR;
+  uint16_t dummy1;
+  volatile uint16_t ODR;
+  uint16_t dummy2;
+  volatile uint16_t BSRR;
+  uint16_t dummy3;
+  volatile uint32_t LCKR;
+  volatile uint32_t AFR[2];
+  volatile uint16_t BRR;
+  uint16_t dummy4;
+};
+
+#define GPIOA_BASE	(AHB2PERIPH_BASE + 0x0000)
+#define GPIOA		((struct GPIO *) GPIOA_BASE)
+#define GPIOB_BASE	(AHB2PERIPH_BASE + 0x0400)
+#define GPIOB		((struct GPIO *) GPIOB_BASE)
+#define GPIOC_BASE	(AHB2PERIPH_BASE + 0x0800)
+#define GPIOC		((struct GPIO *) GPIOC_BASE)
+#define GPIOD_BASE	(AHB2PERIPH_BASE + 0x0C00)
+#define GPIOD		((struct GPIO *) GPIOD_BASE)
+#define GPIOF_BASE	(AHB2PERIPH_BASE + 0x1400)
+#define GPIOF		((struct GPIO *) GPIOF_BASE)
+#else
+struct AFIO
+{
+  volatile uint32_t EVCR;
+  volatile uint32_t MAPR;
+  volatile uint32_t EXTICR[4];
+  uint32_t RESERVED0;
+  volatile uint32_t MAPR2;
+};
+
+#define AFIO_BASE 0x40010000
+static struct AFIO *const AFIO = (struct AFIO *const)AFIO_BASE;
+
+#define AFIO_MAPR_TIM3_REMAP_PARTIALREMAP 0x00000800
+#define AFIO_MAPR_SWJ_CFG_DISABLE         0x04000000
+#define AFIO_MAPR_SWJ_CFG_JTAGDISABLE     0x02000000
+
+
+struct GPIO {
+  volatile uint32_t CRL;
+  volatile uint32_t CRH;
+  volatile uint32_t IDR;
+  volatile uint32_t ODR;
+  volatile uint32_t BSRR;
+  volatile uint32_t BRR;
+  volatile uint32_t LCKR;
+};
+
+#define GPIOA_BASE	(APB2PERIPH_BASE + 0x0800)
+#define GPIOA		((struct GPIO *) GPIOA_BASE)
+#define GPIOB_BASE	(APB2PERIPH_BASE + 0x0C00)
+#define GPIOB		((struct GPIO *) GPIOB_BASE)
+#define GPIOC_BASE	(APB2PERIPH_BASE + 0x1000)
+#define GPIOC		((struct GPIO *) GPIOC_BASE)
+#define GPIOD_BASE	(APB2PERIPH_BASE + 0x1400)
+#define GPIOD		((struct GPIO *) GPIOD_BASE)
+#define GPIOE_BASE	(APB2PERIPH_BASE + 0x1800)
+#define GPIOE		((struct GPIO *) GPIOE_BASE)
+#endif
+
+static struct GPIO *const GPIO_LED = ((struct GPIO *const) GPIO_LED_BASE);
+#ifdef GPIO_USB_BASE
+static struct GPIO *const GPIO_USB = ((struct GPIO *const) GPIO_USB_BASE);
+#endif
+#ifdef GPIO_OTHER_BASE
+static struct GPIO *const GPIO_OTHER = ((struct GPIO *const) GPIO_OTHER_BASE);
+#endif
+
+static void __attribute__((used))
+gpio_init (void)
+{
+  /* Enable GPIO clock. */
+#if defined(MCU_STM32F0)
+  RCC->AHBENR |= RCC_ENR_IOP_EN;
+  RCC->AHBRSTR = RCC_RSTR_IOP_RST;
+  RCC->AHBRSTR = 0;
+#else
+  RCC->APB2ENR |= RCC_ENR_IOP_EN;
+  RCC->APB2RSTR = RCC_RSTR_IOP_RST;
+  RCC->APB2RSTR = 0;
+#endif
+
+#if defined(MCU_STM32F0)
+  GPIO_LED->OSPEEDR = VAL_GPIO_LED_OSPEEDR;
+  GPIO_LED->OTYPER  = VAL_GPIO_LED_OTYPER;
+  GPIO_LED->MODER   = VAL_GPIO_LED_MODER;
+  GPIO_LED->PUPDR   = VAL_GPIO_LED_PUPDR;
+
+#ifdef GPIO_OTHER_BASE
+  GPIO_OTHER->OSPEEDR = VAL_GPIO_OTHER_OSPEEDR;
+  GPIO_OTHER->OTYPER  = VAL_GPIO_OTHER_OTYPER;
+  GPIO_OTHER->MODER   = VAL_GPIO_OTHER_MODER;
+  GPIO_OTHER->PUPDR   = VAL_GPIO_OTHER_PUPDR;
+#endif
+#else
+#ifdef AFIO_MAPR_SOMETHING
+  AFIO->MAPR |= AFIO_MAPR_SOMETHING;
+#endif
+
+  /* LED is mandatory.  If it's on an independent port, we configure it.  */
+  GPIO_LED->ODR = VAL_GPIO_LED_ODR;
+  GPIO_LED->CRH = VAL_GPIO_LED_CRH;
+  GPIO_LED->CRL = VAL_GPIO_LED_CRL;
+
+  /* If there is USB enabler pin and it's independent, we configure it.  */
+#if defined(GPIO_USB_BASE) && GPIO_USB_BASE != GPIO_LED_BASE
+  GPIO_USB->ODR = VAL_GPIO_USB_ODR;
+  GPIO_USB->CRH = VAL_GPIO_USB_CRH;
+  GPIO_USB->CRL = VAL_GPIO_USB_CRL;
+#endif
+
+#ifdef GPIO_OTHER_BASE
+  GPIO_OTHER->ODR = VAL_GPIO_OTHER_ODR;
+  GPIO_OTHER->CRH = VAL_GPIO_OTHER_CRH;
+  GPIO_OTHER->CRL = VAL_GPIO_OTHER_CRL;
+#endif
+#endif
+}
diff --git a/clk_gpio_init.c b/clk_gpio_init.c
deleted file mode 100644
index e94c7ec..0000000
--- a/clk_gpio_init.c
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * clk_gpio_init.c - Clock and GPIO initialization.
- *
- * Copyright (C) 2015  Flying Stone Technology
- * Author: NIIBE Yutaka <gniibe@fsij.org>
- *
- * This file is a part of Chopstx, a thread library for embedded.
- *
- * Chopstx 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.
- *
- * Chopstx 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/>.
- *
- * As additional permission under GNU GPL version 3 section 7, you may
- * distribute non-source form of the Program without the copy of the
- * GNU GPL normally required by section 4, provided you inform the
- * receipents of GNU GPL by a written offer.
- *
- */
-
-#define STM32_SW_HSI		(0 << 0)
-#define STM32_SW_PLL		(2 << 0)
-#define STM32_PLLSRC_HSI	(0 << 16)
-#define STM32_PLLSRC_HSE	(1 << 16)
-
-#define STM32_PLLXTPRE_DIV1	(0 << 17)
-#define STM32_PLLXTPRE_DIV2	(1 << 17)
-
-#define STM32_HPRE_DIV1		(0 << 4)
-
-#define STM32_PPRE1_DIV1	(0 << 8)
-#define STM32_PPRE1_DIV2	(4 << 8)
-
-#define STM32_PPRE2_DIV1        (0 << 11)
-#define STM32_PPRE2_DIV2	(4 << 11)
-
-#define STM32_ADCPRE_DIV4	(1 << 14)
-#define STM32_ADCPRE_DIV6       (2 << 14)
-
-#define STM32_USBPRE_DIV1P5     (0 << 22)
-
-#define STM32_MCO_NOCLOCK	(0 << 24)
-
-#if defined(MCU_STM32F0)
-#define STM32_PPRE1		STM32_PPRE1_DIV1
-#define STM32_PLLSRC		STM32_PLLSRC_HSI
-#define STM32_FLASHBITS		0x00000011
-#define STM32_PLLCLKIN		(STM32_HSICLK / 2)
-#else
-#define STM32_PPRE1		STM32_PPRE1_DIV2
-#define STM32_PLLSRC		STM32_PLLSRC_HSE
-#define STM32_FLASHBITS		0x00000012
-#define STM32_PLLCLKIN		(STM32_HSECLK / 1)
-#endif
-
-#define STM32_SW		STM32_SW_PLL
-#define STM32_HPRE		STM32_HPRE_DIV1
-#define STM32_PPRE2		STM32_PPRE2_DIV1
-#define STM32_ADCPRE		STM32_ADCPRE_DIV6
-#define STM32_MCOSEL		STM32_MCO_NOCLOCK
-#define STM32_USBPRE            STM32_USBPRE_DIV1P5
-
-#define STM32_PLLMUL		((STM32_PLLMUL_VALUE - 2) << 18)
-#define STM32_PLLCLKOUT		(STM32_PLLCLKIN * STM32_PLLMUL_VALUE)
-#define STM32_SYSCLK		STM32_PLLCLKOUT
-#define STM32_HCLK		(STM32_SYSCLK / 1)
-
-
-#define PERIPH_BASE	0x40000000
-#define APBPERIPH_BASE   PERIPH_BASE
-#define APB2PERIPH_BASE	(PERIPH_BASE + 0x10000)
-#define AHBPERIPH_BASE	(PERIPH_BASE + 0x20000)
-#define AHB2PERIPH_BASE	(PERIPH_BASE + 0x08000000)
-
-struct RCC {
-  volatile uint32_t CR;
-  volatile uint32_t CFGR;
-  volatile uint32_t CIR;
-  volatile uint32_t APB2RSTR;
-  volatile uint32_t APB1RSTR;
-  volatile uint32_t AHBENR;
-  volatile uint32_t APB2ENR;
-  volatile uint32_t APB1ENR;
-  volatile uint32_t BDCR;
-  volatile uint32_t CSR;
-#if defined(MCU_STM32F0)
-  volatile uint32_t AHBRSTR;
-  volatile uint32_t CFGR2;
-  volatile uint32_t CFGR3;
-  volatile uint32_t CR2;
-#endif
-};
-
-#define RCC_BASE		(AHBPERIPH_BASE + 0x1000)
-static struct RCC *const RCC = ((struct RCC *const)RCC_BASE);
-
-#define RCC_APB1ENR_USBEN	0x00800000
-#define RCC_APB1RSTR_USBRST	0x00800000
-
-#define RCC_CR_HSION		0x00000001
-#define RCC_CR_HSIRDY		0x00000002
-#define RCC_CR_HSITRIM		0x000000F8
-#define RCC_CR_HSEON		0x00010000
-#define RCC_CR_HSERDY		0x00020000
-#define RCC_CR_PLLON		0x01000000
-#define RCC_CR_PLLRDY		0x02000000
-
-#define RCC_CFGR_SWS		0x0000000C
-#define RCC_CFGR_SWS_HSI	0x00000000
-
-#define RCC_AHBENR_CRCEN        0x0040
-
-#if defined(MCU_STM32F0)
-#define RCC_AHBRSTR_IOPARST	0x00020000
-#define RCC_AHBRSTR_IOPBRST	0x00040000
-#define RCC_AHBRSTR_IOPCRST	0x00080000
-#define RCC_AHBRSTR_IOPDRST	0x00100000
-#define RCC_AHBRSTR_IOPFRST	0x00400000
-
-#define RCC_AHBENR_IOPAEN	0x00020000
-#define RCC_AHBENR_IOPBEN	0x00040000
-#define RCC_AHBENR_IOPCEN	0x00080000
-#define RCC_AHBENR_IOPDEN	0x00100000
-#define RCC_AHBENR_IOPFEN	0x00400000
-
-#define RCC_APB2RSTR_SYSCFGRST	0x00000001
-#define RCC_APB2ENR_SYSCFGEN	0x00000001
-#else
-#define RCC_APB2RSTR_AFIORST	0x00000001
-#define RCC_APB2RSTR_IOPARST	0x00000004
-#define RCC_APB2RSTR_IOPBRST	0x00000008
-#define RCC_APB2RSTR_IOPCRST	0x00000010
-#define RCC_APB2RSTR_IOPDRST	0x00000020
-#define RCC_APB2RSTR_IOPERST	0x00000040
-#define RCC_APB2RSTR_IOPFRST	0x00000080
-#define RCC_APB2RSTR_IOPGRST	0x00000100
-
-#define RCC_APB2ENR_AFIOEN	0x00000001
-#define RCC_APB2ENR_IOPAEN	0x00000004
-#define RCC_APB2ENR_IOPBEN	0x00000008
-#define RCC_APB2ENR_IOPCEN	0x00000010
-#define RCC_APB2ENR_IOPDEN	0x00000020
-#define RCC_APB2ENR_IOPEEN	0x00000040
-#define RCC_APB2ENR_IOPFEN	0x00000080
-#define RCC_APB2ENR_IOPGEN	0x00000100
-#endif
-
-#if defined(MCU_STM32F0)
-struct SYSCFG {
-  volatile uint32_t CFGR1;
-  uint32_t dummy0;
-  volatile uint32_t EXTICR[4];
-  volatile uint32_t CFGR2;
-};
-#define SYSCFG_CFGR1_MEM_MODE 0x03
-
-#define SYSCFG_BASE	(APBPERIPH_BASE + 0x00010000)
-static struct SYSCFG *const SYSCFG = ((struct SYSCFG *const) SYSCFG_BASE);
-#endif
-
-struct FLASH {
-  volatile uint32_t ACR;
-  volatile uint32_t KEYR;
-  volatile uint32_t OPTKEYR;
-  volatile uint32_t SR;
-  volatile uint32_t CR;
-  volatile uint32_t AR;
-  volatile uint32_t RESERVED;
-  volatile uint32_t OBR;
-  volatile uint32_t WRPR;
-};
-
-#define FLASH_R_BASE	(AHBPERIPH_BASE + 0x2000)
-static struct FLASH *const FLASH = ((struct FLASH *const) FLASH_R_BASE);
-
-static void __attribute__((used))
-clock_init (void)
-{
-  /* HSI setup */
-  RCC->CR |= RCC_CR_HSION;
-  while (!(RCC->CR & RCC_CR_HSIRDY))
-    ;
-  /* Reset HSEON, HSEBYP, CSSON, and PLLON, not touching RCC_CR_HSITRIM */
-  RCC->CR &= (RCC_CR_HSITRIM | RCC_CR_HSION);
-  RCC->CFGR = 0;
-  while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI)
-    ;
-
-#if !defined(MCU_STM32F0)
-  /* HSE setup */
-  RCC->CR |= RCC_CR_HSEON;
-  while (!(RCC->CR & RCC_CR_HSERDY))
-    ;
-#endif
-
-  /* PLL setup */
-  RCC->CFGR |= STM32_PLLMUL | STM32_PLLXTPRE | STM32_PLLSRC;
-  RCC->CR   |= RCC_CR_PLLON;
-  while (!(RCC->CR & RCC_CR_PLLRDY))
-    ;
-
-  /* Clock settings */
-  RCC->CFGR = STM32_MCOSEL | STM32_USBPRE | STM32_PLLMUL | STM32_PLLXTPRE
-    | STM32_PLLSRC | STM32_ADCPRE | STM32_PPRE2 | STM32_PPRE1 | STM32_HPRE;
-
-  /*
-   * We don't touch RCC->CR2, RCC->CFGR2, RCC->CFGR3, and RCC->CIR.
-   */
-
-  /* Flash setup */
-  FLASH->ACR = STM32_FLASHBITS;
-
-  /* CRC */
-  RCC->AHBENR |= RCC_AHBENR_CRCEN;
-
-  /* Switching on the configured clock source. */
-  RCC->CFGR |= STM32_SW;
-  while ((RCC->CFGR & RCC_CFGR_SWS) != (STM32_SW << 2))
-    ;
-
-#if defined(MCU_STM32F0)
-  RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
-  RCC->APB2RSTR = RCC_APB2RSTR_SYSCFGRST;
-  RCC->APB2RSTR = 0;
-
-# if defined(HAVE_SYS_H)
-  /* Use vectors on RAM */
-  SYSCFG->CFGR1 = (SYSCFG->CFGR1 & ~SYSCFG_CFGR1_MEM_MODE) | 3;
-# endif
-#endif
-}
-
-
-#if defined(MCU_STM32F0)
-struct GPIO {
-  volatile uint32_t MODER;
-  volatile uint16_t OTYPER;
-  uint16_t dummy0;
-  volatile uint32_t OSPEEDR;
-  volatile uint32_t PUPDR;
-  volatile uint16_t IDR;
-  uint16_t dummy1;
-  volatile uint16_t ODR;
-  uint16_t dummy2;
-  volatile uint16_t BSRR;
-  uint16_t dummy3;
-  volatile uint32_t LCKR;
-  volatile uint32_t AFR[2];
-  volatile uint16_t BRR;
-  uint16_t dummy4;
-};
-
-#define GPIOA_BASE	(AHB2PERIPH_BASE + 0x0000)
-#define GPIOA		((struct GPIO *) GPIOA_BASE)
-#define GPIOB_BASE	(AHB2PERIPH_BASE + 0x0400)
-#define GPIOB		((struct GPIO *) GPIOB_BASE)
-#define GPIOC_BASE	(AHB2PERIPH_BASE + 0x0800)
-#define GPIOC		((struct GPIO *) GPIOC_BASE)
-#define GPIOD_BASE	(AHB2PERIPH_BASE + 0x0C00)
-#define GPIOD		((struct GPIO *) GPIOD_BASE)
-#define GPIOF_BASE	(AHB2PERIPH_BASE + 0x1400)
-#define GPIOF		((struct GPIO *) GPIOF_BASE)
-#else
-struct AFIO
-{
-  volatile uint32_t EVCR;
-  volatile uint32_t MAPR;
-  volatile uint32_t EXTICR[4];
-  uint32_t RESERVED0;
-  volatile uint32_t MAPR2;
-};
-
-#define AFIO_BASE 0x40010000
-static struct AFIO *const AFIO = (struct AFIO *const)AFIO_BASE;
-
-#define AFIO_MAPR_TIM3_REMAP_PARTIALREMAP 0x00000800
-#define AFIO_MAPR_SWJ_CFG_DISABLE         0x04000000
-#define AFIO_MAPR_SWJ_CFG_JTAGDISABLE     0x02000000
-
-
-struct GPIO {
-  volatile uint32_t CRL;
-  volatile uint32_t CRH;
-  volatile uint32_t IDR;
-  volatile uint32_t ODR;
-  volatile uint32_t BSRR;
-  volatile uint32_t BRR;
-  volatile uint32_t LCKR;
-};
-
-#define GPIOA_BASE	(APB2PERIPH_BASE + 0x0800)
-#define GPIOA		((struct GPIO *) GPIOA_BASE)
-#define GPIOB_BASE	(APB2PERIPH_BASE + 0x0C00)
-#define GPIOB		((struct GPIO *) GPIOB_BASE)
-#define GPIOC_BASE	(APB2PERIPH_BASE + 0x1000)
-#define GPIOC		((struct GPIO *) GPIOC_BASE)
-#define GPIOD_BASE	(APB2PERIPH_BASE + 0x1400)
-#define GPIOD		((struct GPIO *) GPIOD_BASE)
-#define GPIOE_BASE	(APB2PERIPH_BASE + 0x1800)
-#define GPIOE		((struct GPIO *) GPIOE_BASE)
-#endif
-
-static struct GPIO *const GPIO_LED = ((struct GPIO *const) GPIO_LED_BASE);
-#ifdef GPIO_USB_BASE
-static struct GPIO *const GPIO_USB = ((struct GPIO *const) GPIO_USB_BASE);
-#endif
-#ifdef GPIO_OTHER_BASE
-static struct GPIO *const GPIO_OTHER = ((struct GPIO *const) GPIO_OTHER_BASE);
-#endif
-
-static void __attribute__((used))
-gpio_init (void)
-{
-  /* Enable GPIO clock. */
-#if defined(MCU_STM32F0)
-  RCC->AHBENR |= RCC_ENR_IOP_EN;
-  RCC->AHBRSTR = RCC_RSTR_IOP_RST;
-  RCC->AHBRSTR = 0;
-#else
-  RCC->APB2ENR |= RCC_ENR_IOP_EN;
-  RCC->APB2RSTR = RCC_RSTR_IOP_RST;
-  RCC->APB2RSTR = 0;
-#endif
-
-#if defined(MCU_STM32F0)
-  GPIO_LED->OSPEEDR = VAL_GPIO_LED_OSPEEDR;
-  GPIO_LED->OTYPER  = VAL_GPIO_LED_OTYPER;
-  GPIO_LED->MODER   = VAL_GPIO_LED_MODER;
-  GPIO_LED->PUPDR   = VAL_GPIO_LED_PUPDR;
-
-#ifdef GPIO_OTHER_BASE
-  GPIO_OTHER->OSPEEDR = VAL_GPIO_OTHER_OSPEEDR;
-  GPIO_OTHER->OTYPER  = VAL_GPIO_OTHER_OTYPER;
-  GPIO_OTHER->MODER   = VAL_GPIO_OTHER_MODER;
-  GPIO_OTHER->PUPDR   = VAL_GPIO_OTHER_PUPDR;
-#endif
-#else
-#ifdef AFIO_MAPR_SOMETHING
-  AFIO->MAPR |= AFIO_MAPR_SOMETHING;
-#endif
-
-  /* LED is mandatory.  If it's on an independent port, we configure it.  */
-  GPIO_LED->ODR = VAL_GPIO_LED_ODR;
-  GPIO_LED->CRH = VAL_GPIO_LED_CRH;
-  GPIO_LED->CRL = VAL_GPIO_LED_CRL;
-
-  /* If there is USB enabler pin and it's independent, we configure it.  */
-#if defined(GPIO_USB_BASE) && GPIO_USB_BASE != GPIO_LED_BASE
-  GPIO_USB->ODR = VAL_GPIO_USB_ODR;
-  GPIO_USB->CRH = VAL_GPIO_USB_CRH;
-  GPIO_USB->CRL = VAL_GPIO_USB_CRL;
-#endif
-
-#ifdef GPIO_OTHER_BASE
-  GPIO_OTHER->ODR = VAL_GPIO_OTHER_ODR;
-  GPIO_OTHER->CRH = VAL_GPIO_OTHER_CRH;
-  GPIO_OTHER->CRL = VAL_GPIO_OTHER_CRL;
-#endif
-#endif
-}
diff --git a/entry.c b/entry.c
index ce3120b..473b138 100644
--- a/entry.c
+++ b/entry.c
@@ -38,7 +38,11 @@
 #undef STM32F10X_MD		/* Prepare for high density device, too.  */
 #else
 #include "board.h"
-#include "clk_gpio_init.c"
+#if defined (MCU_KINETIS_L)
+#include "clk_gpio_init-kl.c"
+#else
+#include "clk_gpio_init-stm32.c"
+#endif
 #endif
 
 
diff --git a/example-fs-bb48/Makefile b/example-fs-bb48/Makefile
new file mode 100644
index 0000000..b60cfde
--- /dev/null
+++ b/example-fs-bb48/Makefile
@@ -0,0 +1,31 @@
+# Makefile for example application of Chopstx
+
+PROJECT = sample
+
+### Currently, it's for FS-BB48.
+
+CHOPSTX = ..
+LDSCRIPT= sample.ld
+CSRC = sample.c reset.c usb_kl27z.c usb-cdc.c
+
+###################################
+CROSS = arm-none-eabi-
+CC   = $(CROSS)gcc
+LD   = $(CROSS)gcc
+OBJCOPY   = $(CROSS)objcopy
+
+MCU   = cortex-m0plus
+CWARN = -Wall -Wextra -Wstrict-prototypes
+DEFS  = -DMAKE_ENTRY_PUBLIC -DFREE_STANDING -DMHZ=48
+OPT   = -O3 -Os -g
+LIBS  =
+
+####################
+include ../rules.mk
+
+board.h:
+	@echo Please make a symbolic link \'board.h\' to a file in ../board;
+	@exit 1
+
+distclean: clean
+	rm -f board.h
diff --git a/example-fs-bb48/board.h b/example-fs-bb48/board.h
new file mode 120000
index 0000000..e6caddc
--- /dev/null
+++ b/example-fs-bb48/board.h
@@ -0,0 +1 @@
+../board/board-fs-bb48.h
\ No newline at end of file
diff --git a/example-fs-bb48/reset.c b/example-fs-bb48/reset.c
new file mode 100644
index 0000000..9af6f96
--- /dev/null
+++ b/example-fs-bb48/reset.c
@@ -0,0 +1,114 @@
+/*
+ * sys.c - No system routines, but only RESET handler for MKL27Z256.
+ *
+ * Copyright (C) 2016 Flying Stone Technology
+ * Author: NIIBE Yutaka <gniibe@fsij.org>
+ *
+ * Copying and distribution of this file, with or without modification,
+ * are permitted in any medium without royalty provided the copyright
+ * notice and this notice are preserved.  This file is offered as-is,
+ * without any warranty.
+ *
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+
+static void __attribute__ ((naked))
+reset (void)
+{
+  asm volatile ("cpsid	i\n\t"		/* Mask all interrupts. */
+		"mov	r0, pc\n\t"	/* r0 = PC & ~0x0fff */
+		"mov	r1, #0x10\n\t"
+		"lsl	r1, #8\n\t"
+		"sub	r1, r1, #1\n\t"
+		"bic	r0, r0, r1\n\t"
+		"ldr	r2, [r0]\n\t"
+		"msr	MSP, r2\n\t"	/* Main (exception handler) stack. */
+		"b	entry\n\t"
+		: /* no output */ : /* no input */ : "memory");
+  /* Never reach here. */
+}
+
+extern uint8_t __main_stack_end__;
+extern void preempt (void);
+extern void chx_timer_expired (void);
+extern void chx_handle_intr (void);
+
+static void nmi (void)
+{
+  for (;;);
+}
+
+static void __attribute__ ((naked))
+hard_fault (void)
+{
+  for (;;);
+}
+
+static void mem_manage (void)
+{
+  for (;;);
+}
+
+static void bus_fault (void)
+{
+  for (;;);
+}
+
+static void usage_fault (void)
+{
+  for (;;);
+}
+
+static void none (void)
+{
+}
+
+
+typedef void (*handler)(void);
+extern uint8_t __main_stack_end__;
+
+handler vector[] __attribute__ ((section(".vectors"))) = {
+  (handler)(&__main_stack_end__ - 32),
+  reset,
+  nmi,		/* nmi */
+  hard_fault,		/* hard fault */
+  /* 0x10 */
+  mem_manage,		/* mem manage */
+  bus_fault,		/* bus fault */
+  usage_fault,		/* usage fault */
+  none,
+  /* 0x20 */
+  none, none, none,		/* reserved */
+  none,				/* SVCall */
+  none,				/* Debug */
+  none,				/* reserved */
+  preempt,			/* PendSV */
+  chx_timer_expired,		/* SysTick */
+  /* 0x40 */
+  chx_handle_intr,  chx_handle_intr,  chx_handle_intr,  chx_handle_intr,
+  chx_handle_intr,  chx_handle_intr,  chx_handle_intr,  chx_handle_intr,
+  /* 0x60 */
+  chx_handle_intr,  chx_handle_intr,  chx_handle_intr,  chx_handle_intr,
+  chx_handle_intr,  chx_handle_intr,  chx_handle_intr,  chx_handle_intr,
+  /* 0x80 */
+  chx_handle_intr,  chx_handle_intr,  chx_handle_intr,  chx_handle_intr,
+  chx_handle_intr,  chx_handle_intr,  chx_handle_intr,  chx_handle_intr,
+  /* 0xA0 */
+  chx_handle_intr,  chx_handle_intr,  chx_handle_intr,  chx_handle_intr,
+  chx_handle_intr,  chx_handle_intr,  chx_handle_intr,  chx_handle_intr,
+  /* 0xc0 */
+};
+
+uint32_t flash_config[] __attribute__ ((section(".flash_config"))) = {
+  0xffffffff, 0xffffffff, /* Backdoor comparison key. */
+  0xffffffff, /* Protection bytes */
+  0xffff3ffe, /* FSEC=0xfe, FOPT=0x3f */
+  /* FOPT=0x3f:
+   * BOOTSRC_SEL=00: Boot from flash
+   */
+  /* FSEC=0xfe:
+   * unsecure
+   */
+};
diff --git a/example-fs-bb48/sample.c b/example-fs-bb48/sample.c
new file mode 100644
index 0000000..92ecc9b
--- /dev/null
+++ b/example-fs-bb48/sample.c
@@ -0,0 +1,228 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <chopstx.h>
+
+#include "usb_lld.h"
+#include "stream.h"
+#include "board.h"
+
+struct GPIO {
+  volatile uint32_t PDOR; /* Port Data Output Register    */
+  volatile uint32_t PSOR; /* Port Set Output Register     */
+  volatile uint32_t PCOR; /* Port Clear Output Register   */
+  volatile uint32_t PTOR; /* Port Toggle Output Register  */
+  volatile uint32_t PDIR; /* Port Data Input Register     */
+  volatile uint32_t PDDR; /* Port Data Direction Register */
+};
+static struct GPIO *const GPIOB = (struct GPIO *const)0x400FF040;
+static struct GPIO *const GPIOD = (struct GPIO *const)0x400FF0C0;
+static struct GPIO *const GPIOE = (struct GPIO *const)0x400FF100;
+
+static void
+set_led (int on)
+{
+  if (on)
+    GPIOB->PCOR = (1 << 0); /* PTB0: Clear: Light on  */
+  else
+    GPIOB->PSOR = (1 << 0); /* PTB0: Set  : Light off */
+}
+
+static chopstx_mutex_t mtx;
+static chopstx_cond_t cnd0;
+static chopstx_cond_t cnd1;
+
+uint8_t u;
+static uint8_t v;
+static uint8_t m;		/* 0..100 */
+
+static void
+wait_for (uint32_t usec)
+{
+#if defined(BUSY_LOOP)
+  uint32_t count = usec * 6;
+  uint32_t i;
+
+  for (i = 0; i < count; i++)
+    asm volatile ("" : : "r" (i) : "memory");
+#else
+  chopstx_usec_wait (usec);
+#endif
+}
+
+static void *
+pwm (void *arg)
+{
+  (void)arg;
+
+  chopstx_mutex_lock (&mtx);
+  chopstx_cond_wait (&cnd0, &mtx);
+  chopstx_mutex_unlock (&mtx);
+
+  while (1)
+    {
+      set_led (u&v);
+      wait_for (m);
+      set_led (0);
+      wait_for (100-m);
+    }
+
+  return NULL;
+}
+
+static void *
+blk (void *arg)
+{
+  (void)arg;
+
+  chopstx_mutex_lock (&mtx);
+  chopstx_cond_wait (&cnd1, &mtx);
+  chopstx_mutex_unlock (&mtx);
+
+  while (1)
+    {
+      v = 0;
+      wait_for (200*1000);
+      v = 1;
+      wait_for (200*1000);
+    }
+
+  return NULL;
+}
+
+#define INTR_REQ_USB 24
+
+static void *
+usb_intr (void *arg)
+{
+  extern void usb_lld_init (uint8_t feature);
+  extern void usb_interrupt_handler (void);
+
+  chopstx_intr_t interrupt;
+
+  (void)arg;
+  chopstx_claim_irq (&interrupt, INTR_REQ_USB);
+  usb_lld_init (0x80);		/* Bus powered. */
+
+  while (1)
+    {
+      chopstx_intr_wait (&interrupt);
+
+      /* Process interrupt. */
+      usb_interrupt_handler ();
+    }
+
+  chopstx_release_irq (&interrupt);
+  return NULL;
+}
+
+#if defined(BUSY_LOOP)
+#define PRIO_PWM (CHOPSTX_SCHED_RR|1)
+#define PRIO_BLK (CHOPSTX_SCHED_RR|1)
+#else
+#define PRIO_PWM 3
+#define PRIO_BLK 2
+#endif
+#define PRIO_INTR 4
+
+extern uint8_t __process1_stack_base__, __process1_stack_size__;
+extern uint8_t __process2_stack_base__, __process2_stack_size__;
+extern uint8_t __process3_stack_base__, __process3_stack_size__;
+
+const uint32_t __stackaddr_pwm = (uint32_t)&__process1_stack_base__;
+const size_t __stacksize_pwm = (size_t)&__process1_stack_size__;
+
+const uint32_t __stackaddr_blk = (uint32_t)&__process2_stack_base__;
+const size_t __stacksize_blk = (size_t)&__process2_stack_size__;
+
+const uint32_t __stackaddr_intr = (uint32_t)&__process3_stack_base__;
+const size_t __stacksize_intr = (size_t)&__process3_stack_size__;
+
+
+static char hexchar (uint8_t x)
+{
+  if (x <= 0x09)
+    return '0' + x;
+  else if (x <= 0x0f)
+    return 'a' + x - 10;
+  else
+    return '?';
+}
+
+int
+main (int argc, const char *argv[])
+{
+  struct stream *st;
+  uint8_t count;
+  extern uint32_t bDeviceState;
+
+  (void)argc;
+  (void)argv;
+
+  chopstx_mutex_init (&mtx);
+  chopstx_cond_init (&cnd0);
+  chopstx_cond_init (&cnd1);
+
+  st = stream_open ();
+
+  m = 10;
+
+  chopstx_create (PRIO_PWM, __stackaddr_pwm, __stacksize_pwm, pwm, NULL);
+  chopstx_create (PRIO_BLK, __stackaddr_blk, __stacksize_blk, blk, NULL);
+  chopstx_create (PRIO_INTR, __stackaddr_intr, __stacksize_intr,
+		  usb_intr, NULL);
+
+  chopstx_usec_wait (200*1000);
+
+  chopstx_mutex_lock (&mtx);
+  chopstx_cond_signal (&cnd0);
+  chopstx_cond_signal (&cnd1);
+  chopstx_mutex_unlock (&mtx);
+
+  u = 1;
+  while (bDeviceState != CONFIGURED)
+    chopstx_usec_wait (500*1000);
+
+  count = 0;
+  while (1)
+    {
+      uint8_t s[64];
+
+      if (stream_wait_connection (st) < 0)
+	{
+	  chopstx_usec_wait (1000*1000);
+	  continue;
+	}
+
+      chopstx_usec_wait (500*1000);
+
+      /* Send ZLP at the beginning.  */
+      stream_send (st, s, 0);
+
+      memcpy (s, "xx: Hello, World with Chopstx!\r\n\000", 32);
+      s[0] = hexchar (count >> 4);
+      s[1] = hexchar (count & 0x0f);
+      count++;
+
+      if (stream_send (st, s, 32) < 0)
+	continue;
+
+      while (1)
+	{
+	  int size = stream_recv (st, s);
+
+	  if (size < 0)
+	    break;
+
+	  if (size >= 0)
+	    {
+	      if (stream_send (st, s, size) < 0)
+		break;
+	    }
+
+	  u ^= 1;
+	}
+    }
+
+  return 0;
+}
diff --git a/example-fs-bb48/sample.ld b/example-fs-bb48/sample.ld
new file mode 100644
index 0000000..787bda9
--- /dev/null
+++ b/example-fs-bb48/sample.ld
@@ -0,0 +1,135 @@
+/*
+ * MK27Z memory setup.
+ */
+__main_stack_size__     = 0x0100;  /* Exception handlers     */
+__process0_stack_size__  = 0x0300; /* Main program           */
+__process1_stack_size__  = 0x0200; /* first thread program */
+__process2_stack_size__  = 0x0100; /* second thread program */
+__process3_stack_size__  = 0x0200; /* third thread program */
+
+MEMORY
+{
+    flash  : org = 0x00000000, len = 256k
+    ram : org = 0x1fffe000, len = 32k
+}
+
+__ram_start__           = ORIGIN(ram);
+__ram_size__            = 32k;
+__ram_end__             = __ram_start__ + __ram_size__;
+
+SECTIONS
+{
+    . = 0;
+
+    _text = .;
+
+    .text : ALIGN(16) SUBALIGN(16)
+    {
+	KEEP(*(.vectors))
+	. = ALIGN(1024);
+        KEEP(*(.flash_config))
+	. = ALIGN(16);
+        *(.text.svc)
+        *(.text.sched)
+        *(.text.preempt)
+        *(.text.startup.*)
+        *(.text)
+        *(.text.*)
+        *(.rodata)
+        *(.rodata.*)
+        *(.glue_7t)
+        *(.glue_7)
+        *(.gcc*)
+	. = ALIGN(8);
+    } > flash
+
+    /DISCARD/ :
+    {
+        *(.startup.vectors)
+        *(.bss.startup.0)
+    }
+
+    .ARM.extab : {*(.ARM.extab* .gnu.linkonce.armextab.*)} > flash
+
+    .ARM.exidx : {
+        PROVIDE(__exidx_start = .);
+        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+        PROVIDE(__exidx_end = .);
+     } > flash
+
+    .eh_frame_hdr : {*(.eh_frame_hdr)} > flash
+
+    .eh_frame : ONLY_IF_RO {*(.eh_frame)} > flash
+
+    .textalign : ONLY_IF_RO { . = ALIGN(8); } > flash
+
+    _etext = .;
+    _textdata = _etext;
+
+    .process_stack :
+    {
+        . = ALIGN(8);
+        __process3_stack_base__ = .;
+        . += __process3_stack_size__;
+        . = ALIGN(8);
+        __process3_stack_end__ = .;
+        __process2_stack_base__ = .;
+        . += __process2_stack_size__;
+        . = ALIGN(8);
+        __process2_stack_end__ = .;
+        __process1_stack_base__ = .;
+        . += __process1_stack_size__;
+        . = ALIGN(8);
+        __process1_stack_end__ = .;
+        __process0_stack_base__ = .;
+        . += __process0_stack_size__;
+        . = ALIGN(8);
+        __process0_stack_end__ = .;
+    } > ram
+
+    .main_stack :
+    {
+        . = ALIGN(8);
+        __main_stack_base__ = .;
+        . += __main_stack_size__;
+        . = ALIGN(8);
+        __main_stack_end__ = .;
+    } > ram
+
+    .data :
+    {
+        . = ALIGN(512);
+	__usb_bdt__ = .;
+        . += 512;
+	__usb_buf__ = .;
+        . += 8 /*control write*/ + 64 /*control read*/ + 64 + 64 + 8;
+        . = ALIGN(4);
+        PROVIDE(_data = .);
+        *(.data)
+        . = ALIGN(4);
+        *(.data.*)
+        . = ALIGN(4);
+        *(.ramtext)
+        . = ALIGN(4);
+        PROVIDE(_edata = .);
+    } > ram AT > flash
+
+    .bss :
+    {
+        . = ALIGN(4);
+        PROVIDE(_bss_start = .);
+        *(.bss)
+        . = ALIGN(4);
+        *(.bss.*)
+        . = ALIGN(4);
+        *(COMMON)
+        . = ALIGN(4);
+        PROVIDE(_bss_end = .);
+    } > ram
+
+    PROVIDE(end = .);
+    _end            = .;
+}
+
+__heap_base__   = _end;
+__heap_end__    = __ram_end__;
diff --git a/example-fs-bb48/stream.h b/example-fs-bb48/stream.h
new file mode 100644
index 0000000..15cbe63
--- /dev/null
+++ b/example-fs-bb48/stream.h
@@ -0,0 +1,24 @@
+#define BUFSIZE 128
+#define FLAG_CONNECTED   (1 << 0)
+#define FLAG_SEND_AVAIL  (1 << 1)
+#define FLAG_RECV_AVAIL  (1 << 2)
+
+/*
+ * Current implementation is synchronous and buffers are not yet used.
+ */
+struct stream {
+  chopstx_mutex_t mtx;
+  chopstx_cond_t cnd;
+  uint8_t buf_send[BUFSIZE];	/* Not yet used. */
+  uint8_t buf_recv[BUFSIZE];	/* Not yet used. */
+  uint8_t cnt_send_head;	/* Not yet used. */
+  uint8_t cnt_send_tail;	/* Not yet used. */
+  uint8_t cnt_recv_head;	/* Not yet used. */
+  uint8_t cnt_recv_tail;	/* Not yet used. */
+  uint32_t flags;
+};
+
+struct stream *stream_open (void);
+int stream_wait_connection (struct stream *st);
+int stream_send (struct stream *st, uint8_t *buf, uint8_t count);
+int stream_recv (struct stream *st, uint8_t *buf);
diff --git a/example-fs-bb48/usb-cdc.c b/example-fs-bb48/usb-cdc.c
new file mode 100644
index 0000000..290a4fd
--- /dev/null
+++ b/example-fs-bb48/usb-cdc.c
@@ -0,0 +1,506 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <chopstx.h>
+#include "usb_lld.h"
+#include "stream.h"
+
+static struct stream stream;
+
+#define USB_CDC_REQ_SET_LINE_CODING             0x20
+#define USB_CDC_REQ_GET_LINE_CODING             0x21
+#define USB_CDC_REQ_SET_CONTROL_LINE_STATE      0x22
+#define USB_CDC_REQ_SEND_BREAK                  0x23
+
+/* USB Device Descriptor */
+static const uint8_t vcom_device_desc[18] = {
+  18,   /* bLength */
+  DEVICE_DESCRIPTOR,		/* bDescriptorType */
+  0x10, 0x01,			/* bcdUSB = 1.1 */
+  0x02,				/* bDeviceClass (CDC).              */
+  0x00,				/* bDeviceSubClass.                 */
+  0x00,				/* bDeviceProtocol.                 */
+  0x40,				/* bMaxPacketSize.                  */
+  0xFF, 0xFF, /* idVendor  */
+  0x01, 0x00, /* idProduct */
+  0x00, 0x01, /* bcdDevice  */
+  1,				/* iManufacturer.                   */
+  2,				/* iProduct.                        */
+  3,				/* iSerialNumber.                   */
+  1				/* bNumConfigurations.              */
+};
+
+/* Configuration Descriptor tree for a CDC.*/
+static const uint8_t vcom_config_desc[67] = {
+  9,
+  CONFIG_DESCRIPTOR,		/* bDescriptorType: Configuration */
+  /* Configuration Descriptor.*/
+  67, 0x00,			/* wTotalLength.                    */
+  0x02,				/* bNumInterfaces.                  */
+  0x01,				/* bConfigurationValue.             */
+  0,				/* iConfiguration.                  */
+  0x80,				/* bmAttributes (bus powered).      */
+  50,				/* bMaxPower (100mA).               */
+  /* Interface Descriptor.*/
+  9,
+  INTERFACE_DESCRIPTOR,
+  0x00,		   /* bInterfaceNumber.                */
+  0x00,		   /* bAlternateSetting.               */
+  0x01,		   /* bNumEndpoints.                   */
+  0x02,		   /* bInterfaceClass (Communications Interface Class,
+		      CDC section 4.2).  */
+  0x02,		   /* bInterfaceSubClass (Abstract Control Model, CDC
+		      section 4.3).  */
+  0x01,		   /* bInterfaceProtocol (AT commands, CDC section
+		      4.4).  */
+  0,	           /* iInterface.                      */
+  /* Header Functional Descriptor (CDC section 5.2.3).*/
+  5,	      /* bLength.                         */
+  0x24,	      /* bDescriptorType (CS_INTERFACE).  */
+  0x00,	      /* bDescriptorSubtype (Header Functional Descriptor). */
+  0x10, 0x01, /* bcdCDC.                          */
+  /* Call Management Functional Descriptor. */
+  5,            /* bFunctionLength.                 */
+  0x24,         /* bDescriptorType (CS_INTERFACE).  */
+  0x01,         /* bDescriptorSubtype (Call Management Functional
+		   Descriptor). */
+  0x03,         /* bmCapabilities (D0+D1).          */
+  0x01,         /* bDataInterface.                  */
+  /* ACM Functional Descriptor.*/
+  4,            /* bFunctionLength.                 */
+  0x24,         /* bDescriptorType (CS_INTERFACE).  */
+  0x02,         /* bDescriptorSubtype (Abstract Control Management
+		   Descriptor).  */
+  0x02,         /* bmCapabilities.                  */
+  /* Union Functional Descriptor.*/
+  5,            /* bFunctionLength.                 */
+  0x24,         /* bDescriptorType (CS_INTERFACE).  */
+  0x06,         /* bDescriptorSubtype (Union Functional
+		   Descriptor).  */
+  0x00,         /* bMasterInterface (Communication Class
+		   Interface).  */
+  0x01,         /* bSlaveInterface0 (Data Class Interface).  */
+  /* Endpoint 2 Descriptor.*/
+  7,
+  ENDPOINT_DESCRIPTOR,
+  ENDP2|0x80,    /* bEndpointAddress.    */
+  0x03,          /* bmAttributes (Interrupt).        */
+  0x08, 0x00,	 /* wMaxPacketSize.                  */
+  0xFF,		 /* bInterval.                       */
+  /* Interface Descriptor.*/
+  9,
+  INTERFACE_DESCRIPTOR, /* bDescriptorType: */
+  0x01,          /* bInterfaceNumber.                */
+  0x00,          /* bAlternateSetting.               */
+  0x02,          /* bNumEndpoints.                   */
+  0x0A,          /* bInterfaceClass (Data Class Interface, CDC section 4.5). */
+  0x00,          /* bInterfaceSubClass (CDC section 4.6). */
+  0x00,          /* bInterfaceProtocol (CDC section 4.7). */
+  0x00,		 /* iInterface.                      */
+  /* Endpoint 3 Descriptor.*/
+  7,
+  ENDPOINT_DESCRIPTOR,		/* bDescriptorType: Endpoint */
+  ENDP3,    /* bEndpointAddress. */
+  0x02,				/* bmAttributes (Bulk).             */
+  0x40, 0x00,			/* wMaxPacketSize.                  */
+  0x00,				/* bInterval.                       */
+  /* Endpoint 1 Descriptor.*/
+  7,
+  ENDPOINT_DESCRIPTOR,		/* bDescriptorType: Endpoint */
+  ENDP1|0x80,			/* bEndpointAddress. */
+  0x02,				/* bmAttributes (Bulk).             */
+  0x40, 0x00,			/* wMaxPacketSize.                  */
+  0x00				/* bInterval.                       */
+};
+
+
+/*
+ * U.S. English language identifier.
+ */
+static const uint8_t vcom_string0[4] = {
+  4,				/* bLength */
+  STRING_DESCRIPTOR,
+  0x09, 0x04			/* LangID = 0x0409: US-English */
+};
+
+static const uint8_t vcom_string1[] = {
+  23*2+2,			/* bLength */
+  STRING_DESCRIPTOR,		/* bDescriptorType */
+  /* Manufacturer: "Flying Stone Technology" */
+  'F', 0, 'l', 0, 'y', 0, 'i', 0, 'n', 0, 'g', 0, ' ', 0, 'S', 0,
+  't', 0, 'o', 0, 'n', 0, 'e', 0, ' ', 0, 'T', 0, 'e', 0, 'c', 0,
+  'h', 0, 'n', 0, 'o', 0, 'l', 0, 'o', 0, 'g', 0, 'y', 0, 
+};
+
+static const uint8_t vcom_string2[] = {
+  14*2+2,			/* bLength */
+  STRING_DESCRIPTOR,		/* bDescriptorType */
+  /* Product name: "Chopstx Sample" */
+  'C', 0, 'h', 0, 'o', 0, 'p', 0, 's', 0, 't', 0, 'x', 0, ' ', 0,
+  'S', 0, 'a', 0, 'm', 0, 'p', 0, 'l', 0, 'e', 0,
+};
+
+/*
+ * Serial Number string.
+ */
+static const uint8_t vcom_string3[28] = {
+  28,				    /* bLength */
+  STRING_DESCRIPTOR,		    /* bDescriptorType */
+  '0', 0,  '.', 0,  '0', 0, '0', 0, /* Version number */
+};
+
+
+#define NUM_INTERFACES 2
+
+uint32_t bDeviceState = UNCONNECTED; /* USB device status */
+
+
+void
+usb_cb_device_reset (void)
+{
+  usb_lld_reset (vcom_config_desc[7]);
+
+  /* Initialize Endpoint 0 */
+  usb_lld_setup_endpoint (ENDP0, 1, 1);
+
+  chopstx_mutex_lock (&stream.mtx);
+  stream.flags = 0;
+  bDeviceState = ATTACHED;
+  chopstx_mutex_unlock (&stream.mtx);
+}
+
+
+#define CDC_CTRL_DTR            0x0001
+
+void
+usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, struct req_args *arg)
+{
+  uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
+
+  if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT)
+      && USB_SETUP_SET (req) && req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
+    {
+      /* Open/close the connection.  */
+      chopstx_mutex_lock (&stream.mtx);
+      stream.flags &= ~FLAG_CONNECTED;
+      stream.flags |= ((arg->value & CDC_CTRL_DTR) != 0)? FLAG_CONNECTED : 0;
+      chopstx_cond_signal (&stream.cnd);
+      chopstx_mutex_unlock (&stream.mtx);
+    }
+}
+
+struct line_coding
+{
+  uint32_t bitrate;
+  uint8_t format;
+  uint8_t paritytype;
+  uint8_t datatype;
+}  __attribute__((packed));
+
+static struct line_coding line_coding = {
+  115200, /* baud rate: 115200    */
+  0x00,   /* stop bits: 1         */
+  0x00,   /* parity:    none      */
+  0x08    /* bits:      8         */
+};
+
+
+static int
+vcom_port_data_setup (uint8_t req, uint8_t req_no, struct req_args *arg)
+{
+  if (USB_SETUP_GET (req))
+    {
+      if (req_no == USB_CDC_REQ_GET_LINE_CODING)
+	return usb_lld_reply_request (&line_coding, sizeof(line_coding), arg);
+    }
+  else  /* USB_SETUP_SET (req) */
+    {
+      if (req_no == USB_CDC_REQ_SET_LINE_CODING
+	  && arg->len == sizeof (line_coding))
+	{
+	  usb_lld_set_data_to_recv (&line_coding, sizeof (line_coding));
+	  return USB_SUCCESS;
+	}
+      else if (req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
+	return USB_SUCCESS;
+    }
+
+  return USB_UNSUPPORT;
+}
+
+int
+usb_cb_setup (uint8_t req, uint8_t req_no, struct req_args *arg)
+{
+  uint8_t type_rcp = req & (REQUEST_TYPE|RECIPIENT);
+
+  if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT) && arg->index == 0)
+    return vcom_port_data_setup (req, req_no, arg);
+
+  return USB_UNSUPPORT;
+}
+
+int
+usb_cb_get_descriptor (uint8_t rcp, uint8_t desc_type, uint8_t desc_index,
+		       struct req_args *arg)
+{
+  if (rcp != DEVICE_RECIPIENT)
+    return USB_UNSUPPORT;
+
+  if (desc_type == DEVICE_DESCRIPTOR)
+    return usb_lld_reply_request (vcom_device_desc, sizeof (vcom_device_desc),
+				  arg);
+  else if (desc_type == CONFIG_DESCRIPTOR)
+    return usb_lld_reply_request (vcom_config_desc, sizeof (vcom_config_desc),
+				  arg);
+  else if (desc_type == STRING_DESCRIPTOR)
+    {
+      const uint8_t *str;
+      int size;
+
+      switch (desc_index)
+	{
+	case 0:
+	  str = vcom_string0;
+	  size = sizeof (vcom_string0);
+	  break;
+	case 1:
+	  str = vcom_string1;
+	  size = sizeof (vcom_string1);
+	  break;
+	case 2:
+	  str = vcom_string2;
+	  size = sizeof (vcom_string2);
+	  break;
+	case 3:
+	  str = vcom_string3;
+	  size = sizeof (vcom_string3);
+	  break;
+	default:
+	  return USB_UNSUPPORT;
+	}
+
+      return usb_lld_reply_request (str, size, arg);
+    }
+
+  return USB_UNSUPPORT;
+}
+
+static void
+vcom_setup_endpoints_for_interface (uint16_t interface, int stop)
+{
+  if (interface == 0)
+    {
+      if (!stop)
+	usb_lld_setup_endpoint (ENDP2, 0, 1);
+      else
+	usb_lld_stall (ENDP2);
+    }
+  else if (interface == 1)
+    {
+      if (!stop)
+	{
+	  usb_lld_setup_endpoint (ENDP1, 0, 1);
+	  usb_lld_setup_endpoint (ENDP3, 1, 0);
+#if 0
+	  /* Start with no data receiving */
+	  usb_lld_stall (ENDP3);
+#endif
+	}
+      else
+	{
+	  usb_lld_stall (ENDP1);
+	  usb_lld_stall (ENDP3);
+	}
+    }
+}
+
+int
+usb_cb_handle_event (uint8_t event_type, uint16_t value)
+{
+  int i;
+  uint8_t current_conf;
+
+  switch (event_type)
+    {
+    case USB_EVENT_ADDRESS:
+      bDeviceState = ADDRESSED;
+      return USB_SUCCESS;
+    case USB_EVENT_CONFIG:
+      current_conf = usb_lld_current_configuration ();
+      if (current_conf == 0)
+	{
+	  if (value != 1)
+	    return USB_UNSUPPORT;
+
+	  usb_lld_set_configuration (1);
+	  for (i = 0; i < NUM_INTERFACES; i++)
+	    vcom_setup_endpoints_for_interface (i, 0);
+	  bDeviceState = CONFIGURED;
+	}
+      else if (current_conf != value)
+	{
+	  if (value != 0)
+	    return USB_UNSUPPORT;
+
+	  usb_lld_set_configuration (0);
+	  for (i = 0; i < NUM_INTERFACES; i++)
+	    vcom_setup_endpoints_for_interface (i, 1);
+	  bDeviceState = ADDRESSED;
+	}
+      /* Do nothing when current_conf == value */
+      return USB_SUCCESS;
+
+      return USB_SUCCESS;
+    default:
+      break;
+    }
+
+  return USB_UNSUPPORT;
+}
+
+
+int
+usb_cb_interface (uint8_t cmd, struct req_args *arg)
+{
+  const uint8_t zero = 0;
+  uint16_t interface = arg->index;
+  uint16_t alt = arg->value;
+
+  if (interface >= NUM_INTERFACES)
+    return USB_UNSUPPORT;
+
+  switch (cmd)
+    {
+    case USB_SET_INTERFACE:
+      if (alt != 0)
+	return USB_UNSUPPORT;
+      else
+	{
+	  vcom_setup_endpoints_for_interface (interface, 0);
+	  return USB_SUCCESS;
+	}
+
+    case USB_GET_INTERFACE:
+      return usb_lld_reply_request (&zero, 1, arg);
+
+    default:
+    case USB_QUERY_INTERFACE:
+      return USB_SUCCESS;
+    }
+}
+
+
+void
+usb_cb_tx_done (uint8_t ep_num)
+{
+  if (ep_num == ENDP1)
+    {
+      chopstx_mutex_lock (&stream.mtx);
+      if ((stream.flags & FLAG_SEND_AVAIL))
+	{
+	  stream.flags &= ~FLAG_SEND_AVAIL;
+	  chopstx_cond_signal (&stream.cnd);
+	}
+      chopstx_mutex_unlock (&stream.mtx);
+    }
+  else if (ep_num == ENDP2)
+    {
+    }
+}
+
+void
+usb_cb_rx_ready (uint8_t ep_num)
+{
+  if (ep_num == ENDP3)
+    {
+      chopstx_mutex_lock (&stream.mtx);
+      if ((stream.flags & FLAG_RECV_AVAIL) == 0)
+	{
+	  stream.flags |= FLAG_RECV_AVAIL;
+	  chopstx_cond_signal (&stream.cnd);
+	}
+      chopstx_mutex_unlock (&stream.mtx);
+    }
+}
+
+struct stream *
+stream_open (void)
+{
+  chopstx_mutex_init (&stream.mtx);
+  chopstx_cond_init (&stream.cnd);
+  return &stream;
+}
+
+int
+stream_wait_connection (struct stream *st)
+{
+  chopstx_mutex_lock (&st->mtx);
+  while ((stream.flags & FLAG_CONNECTED) == 0)
+    chopstx_cond_wait (&st->cnd, &st->mtx);
+  chopstx_mutex_unlock (&st->mtx);
+  stream.flags &= ~FLAG_SEND_AVAIL;
+  return 0;
+}
+
+
+int
+stream_send (struct stream *st, uint8_t *buf, uint8_t count)
+{
+  int r = 0;
+
+  chopstx_mutex_lock (&st->mtx);
+  if ((stream.flags & FLAG_CONNECTED) == 0)
+    r = -1;
+  else
+    {
+      usb_lld_tx_enable (ENDP1, buf, count);
+      stream.flags |= FLAG_SEND_AVAIL;
+      do
+	{
+	  chopstx_cond_wait (&st->cnd, &st->mtx);
+	  if ((stream.flags & FLAG_SEND_AVAIL) == 0)
+	    break;
+	  else if ((stream.flags & FLAG_CONNECTED) == 0)
+	    {
+	      r = -1;
+	      break;
+	    }
+	}
+      while (1);
+    }
+  chopstx_mutex_unlock (&st->mtx);
+  return r;
+}
+
+
+int
+stream_recv (struct stream *st, uint8_t *buf)
+{
+  int r;
+
+  chopstx_mutex_lock (&st->mtx);
+  if ((stream.flags & FLAG_CONNECTED) == 0)
+    r = -1;
+  else
+    {
+      usb_lld_rx_enable (ENDP3, buf, 64);
+      stream.flags &= ~FLAG_RECV_AVAIL;
+      do
+	{
+	  chopstx_cond_wait (&st->cnd, &st->mtx);
+	  if ((stream.flags & FLAG_RECV_AVAIL))
+	    {
+	      r = usb_lld_rx_data_len (ENDP3);
+	      break;
+	    }
+	  else if ((stream.flags & FLAG_CONNECTED) == 0)
+	    {
+	      r = -1;
+	      break;
+	    }
+	}
+      while (1);
+    }
+  chopstx_mutex_unlock (&st->mtx);
+
+  return r;
+}
diff --git a/example-fs-bb48/usb_kl27z.c b/example-fs-bb48/usb_kl27z.c
new file mode 100644
index 0000000..09a65f7
--- /dev/null
+++ b/example-fs-bb48/usb_kl27z.c
@@ -0,0 +1,1035 @@
+/*
+ * usb_kl27z.c - USB driver for KL27Z
+ *
+ * Copyright (C) 2016  Flying Stone Technology
+ * Author: NIIBE Yutaka <gniibe@fsij.org>
+ *
+ * This file is a part of Chopstx, a thread library for embedded.
+ *
+ * Chopstx 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.
+ *
+ * Chopstx 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/>.
+ *
+ * As additional permission under GNU GPL version 3 section 7, you may
+ * distribute non-source form of the Program without the copy of the
+ * GNU GPL normally required by section 4, provided you inform the
+ * receipents of GNU GPL by a written offer.
+ *
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "usb_lld.h"
+
+struct endpoint_ctl {
+  uint32_t rx_odd: 1;
+  uint32_t tx_odd: 1;
+};
+static struct endpoint_ctl ep[16];
+
+struct USB_CONF {
+  const uint8_t PERID;       /* Peripheral ID register              */
+  uint8_t rsvd0[3];          /*                                     */
+  const uint8_t IDCOMP;      /* Peripheral ID Complement register   */
+  uint8_t rsvd1[3];          /*                                     */
+  const uint8_t REV;         /* Peripheral Revision register        */
+  uint8_t rsvd2[3];          /*                                     */
+  volatile uint8_t ADDINFO;  /* Peripheral Additional Info register */
+};
+static struct USB_CONF *const USB_CONF = (struct USB_CONF *const) 0x40072000;
+
+struct USB_CTRL0 {
+  volatile uint8_t OTGCTL;   /* OTG Control register                */
+};
+static struct USB_CTRL0 *const USB_CTRL0 = (struct USB_CTRL0 *const)0x4007201c;
+
+struct USB_CTRL1 {
+  volatile uint8_t ISTAT;    /* Interrupt Status register           */
+  uint8_t rsvd5[3];          /*                                     */
+  volatile uint8_t INTEN;    /* Interrupt Enable register           */
+  uint8_t rsvd6[3];          /*                                     */
+  volatile uint8_t ERRSTAT;  /* Error Interrupt Status register     */
+  uint8_t rsvd7[3];          /*                                     */
+  volatile uint8_t ERREN;    /* Error Interrupt Enable register     */
+  uint8_t rsvd8[3];          /*                                     */
+  volatile uint8_t STAT;     /* Status register                     */
+  uint8_t rsvd9[3];          /*                                     */
+  volatile uint8_t CTL;      /* Control register                    */
+  uint8_t rsvd10[3];         /*                                     */
+  volatile uint8_t ADDR;     /* Address register                    */
+  uint8_t rsvd11[3];         /*                                     */
+  volatile uint8_t BDTPAGE1; /* BDT Page register 1                 */
+  uint8_t rsvd12[3];         /*                                     */
+  volatile uint8_t FRMNUML;  /* Frame Number register Low           */
+  uint8_t rsvd13[3];         /*                                     */
+  volatile uint8_t FRMNUMH;  /* Frame Number register High          */
+  uint8_t rsvd14[11];        /*                                     */
+  volatile uint8_t BDTPAGE2; /* BDT Page Register 2                 */
+  uint8_t rsvd15[3];         /*                                     */
+  volatile uint8_t BDTPAGE3; /* BDT Page Register 3                 */
+};
+static struct USB_CTRL1 *const USB_CTRL1 = (struct USB_CTRL1 *const)0x40072080;
+
+/* Interrupt source bits */
+#define USB_IS_STALL  (1 << 7)
+#define USB_IS_RESUME (1 << 5)
+#define USB_IS_SLEEP  (1 << 4)
+#define USB_IS_TOKDNE (1 << 3)
+#define USB_IS_SOFTOK (1 << 2)
+#define USB_IS_ERROR  (1 << 1)
+#define USB_IS_USBRST (1 << 0)
+
+
+struct USB_ENDPT {
+  volatile uint8_t EP;  /* Endpoint Control register */
+  uint8_t rsvd17[3];
+};
+static struct USB_ENDPT *const USB_ENDPT = (struct USB_ENDPT *const)0x400720c0;
+
+struct USB_CTRL2 {
+  volatile uint8_t USBCTRL;  /* USB Control register                */
+  uint8_t rsvd33[3];         /*                                     */
+  volatile uint8_t OBSERVE;  /* USB OTG Observe register            */
+  uint8_t rsvd34[3];         /*                                     */
+  volatile uint8_t CONTROL;  /* USB OTG Control register            */
+  uint8_t rsvd35[3];         /*                                     */
+  volatile uint8_t USBTRC0;  /* USB Transceiver Control register 0  */
+  uint8_t rsvd36[7];         /*                                     */
+  volatile uint8_t USBFRMADJUST;           /* Frame Adjut Register  */
+};
+static struct USB_CTRL2 *const USB_CTRL2 = (struct USB_CTRL2 *const)0x40072100;
+
+/* Buffer Descriptor */
+struct BD {
+  volatile uint32_t ctrl;
+  volatile void *buf; 
+};
+/*
+  uint32_t rsvd0 : 2;
+  volatile uint32_t STALL: 1;
+  volatile uint32_t DTS: 1;
+
+  volatile uint32_t NINC: 1;
+  volatile uint32_t KEEP: 1;
+  volatile uint32_t DATA01: 1;
+  volatile uint32_t OWN: 1;
+
+  uint32_t rsvd1: 8;
+  volatile uint32_t BC: 10;
+  uint32_t rsvd2: 6;
+*/
+#define TOK_PID(ctrl)   ((ctrl >> 2) & 0x0f)
+
+extern uint8_t __usb_bdt__;
+extern uint8_t __usb_buf__;
+
+static struct BD *const BD_table = (struct BD *const)&__usb_bdt__;
+
+static uint8_t setup[8];
+/* bmRequestType, bRequest */
+/* Value: 2-byte  */
+/* Index: 2-byte  */
+/* Length: 2-byte */
+
+static void
+kl27z_usb_init (void)
+{
+  int i;
+
+  memset (ep, 0, sizeof (ep));
+  memset (BD_table, 0, 10 * sizeof (struct BD));
+
+  /* D+ pull up */
+  USB_CTRL0->OTGCTL = 0x80;
+
+  USB_CTRL1->ERREN = 0xff;
+
+  USB_CTRL1->BDTPAGE1 = ((uint32_t)BD_table) >> 8;
+  USB_CTRL1->BDTPAGE2 = ((uint32_t)BD_table) >> 16;
+  USB_CTRL1->BDTPAGE3 = ((uint32_t)BD_table) >> 24;
+
+  /* Not suspended, Pull-down disabled.  */
+  USB_CTRL2->USBCTRL = 0x00;
+  /* DP Pullup in non-OTG device mode.  */
+  USB_CTRL2->CONTROL = 0x10;
+
+  /* Disable all endpoints.  */
+  for (i = 0; i < 16; i++)
+    USB_ENDPT[i].EP = 0;
+
+  /* 
+   * Enable USB FS communication module, clearing all ODD-bits
+   * for BDT.
+   */
+  USB_CTRL1->CTL = 0x03;    
+
+  /* ??? How we can ask re-enumeration?  Is only hard RESET enough? */
+}
+
+static void
+kl27z_set_daddr (uint8_t daddr)
+{
+  USB_CTRL1->ADDR = daddr;
+}
+
+static void
+kl27z_prepare_ep0_setup (void)
+{
+  /* Endpoint 0, TX=0. */
+  BD_table[ep[0].rx_odd].ctrl = 0x00080088; /* Len=8, OWN=1, DATA01=0, DTS=1 */
+  BD_table[ep[0].rx_odd].buf = setup;
+
+  BD_table[!ep[0].rx_odd].ctrl = 0x0000; /* OWN=0 */
+  BD_table[!ep[0].rx_odd].buf = NULL;
+}
+
+static void
+kl27z_prepare_ep0_in (const void *buf, uint8_t len, int data01)
+{
+  /* Endpoint 0, TX=1 *//* OWN=1, DTS=1 */
+  BD_table[2+ep[0].tx_odd].ctrl = (len << 16) | 0x0088 | (data01 << 6); 
+  BD_table[2+ep[0].tx_odd].buf = (void *)buf;
+}
+
+static void
+kl27z_prepare_ep0_out (void *buf, uint8_t len, int data01)
+{
+  /* Endpoint 0, TX=0 *//* OWN=1, DTS=1 */
+  BD_table[ep[0].rx_odd].ctrl = (len << 16) | 0x0088 | (data01 << 6);
+  BD_table[ep[0].rx_odd].buf = buf;
+}
+
+static int
+kl27z_ep_is_disabled (uint8_t n)
+{
+  return (USB_ENDPT[n].EP == 0);
+}
+
+static int
+kl27z_ep_is_stall (uint8_t n)
+{
+  return (USB_ENDPT[n].EP & 0x02) >> 1;
+}
+
+static void
+kl27z_ep_stall (uint8_t n)
+{
+  USB_ENDPT[n].EP |= 0x02;
+}
+
+static void
+kl27z_ep_clear_stall (uint8_t n)
+{
+  USB_ENDPT[n].EP &= ~0x02;
+}
+
+static void
+kl27z_ep_clear_dtog (int rx, uint8_t n)
+{
+  uint32_t config;
+
+  if (!kl27z_ep_is_stall (n))
+    /* Just in case, when the endpoint is active */
+    kl27z_ep_stall (n);
+
+  if (rx)
+    {
+      config = BD_table[4*n+ep[n].rx_odd].ctrl;
+
+      BD_table[4*n+!ep[n].rx_odd].ctrl &= ~(1 << 6);
+      if ((config & 0x0080)) /* OWN already? */
+	{
+	  /*
+	   * How to update BDT entry which is owned by USBFS seems to
+	   * be not clearly documented.  It would be just OK to update
+	   * it as long as the endpoint is stalled (BDT entry is
+	   * actually not in use).  We write 0 at first and then write
+	   * value with OWN, to avoid possible failure.
+	   */
+	  BD_table[4*n+ep[n].rx_odd].ctrl = 0;
+	  BD_table[4*n+ep[n].rx_odd].ctrl = (config & ~(1 << 6));
+	}
+    }
+  else
+    {
+      config = BD_table[4*n+2+ep[n].tx_odd].ctrl;
+
+      BD_table[4*n+2+!ep[n].tx_odd].ctrl &= ~(1 << 6);
+      if ((config & 0x0080)) /* OWN already? */
+	{
+	  BD_table[4*n+2+ep[n].tx_odd].ctrl = 0;
+	  BD_table[4*n+2+ep[n].tx_odd].ctrl = (config & ~(1 << 6));
+	}
+    }
+
+  kl27z_ep_clear_stall (n);
+}
+
+#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 */
+};
+
+
+enum FEATURE_SELECTOR {
+  ENDPOINT_STALL,
+  DEVICE_REMOTE_WAKEUP
+};
+
+
+struct data_ctl {
+  uint8_t *addr;
+  uint16_t len;
+  uint8_t require_zlp;
+};
+
+/* The state machine states of a control pipe */
+enum {
+  WAIT_SETUP,
+  IN_DATA,
+  OUT_DATA,
+  LAST_IN_DATA,
+  WAIT_STATUS_IN,
+  WAIT_STATUS_OUT,
+  STALLED,
+  PAUSE
+};
+
+struct device_ctl {
+  /* control pipe state */
+  uint8_t state;		
+
+  uint32_t tkdone;
+  uint32_t reset;
+  uint32_t error;
+  uint32_t stall;
+
+  uint32_t send;
+  uint32_t recv;
+
+  /* Device specific settings */
+  uint8_t configuration;
+  uint8_t feature;
+};
+
+static struct device_ctl device_ctl;
+static struct data_ctl data_ctl;
+
+static struct device_ctl *const dev_p = &device_ctl;
+static struct data_ctl *const data_p = &data_ctl;
+
+static void handle_transaction (uint8_t stat);
+
+void
+usb_lld_stall (int n)
+{
+  kl27z_ep_stall (n);
+}
+
+
+void
+usb_lld_init (uint8_t feature)
+{
+  dev_p->state = WAIT_SETUP;
+  dev_p->tkdone = 0;
+  dev_p->reset = 0;
+  dev_p->error = 0;
+  dev_p->stall = 0;
+
+  usb_lld_set_configuration (0);
+  dev_p->feature = feature;
+
+  kl27z_set_daddr (0);
+  kl27z_usb_init ();
+
+  /* Enable the endpoint 0.  */
+  USB_ENDPT[0].EP = 0x0d;
+
+  /* Clear Interrupt Status Register, and enable interrupt for USB */
+  USB_CTRL1->ISTAT = 0xff;		     /* All clear */
+
+  USB_CTRL1->INTEN = USB_IS_STALL | USB_IS_TOKDNE
+                   | USB_IS_ERROR | USB_IS_USBRST;
+}
+
+void
+usb_interrupt_handler (void)
+{
+  uint8_t istat_value = USB_CTRL1->ISTAT;
+  uint8_t stat = USB_CTRL1->STAT;
+
+  if ((istat_value & USB_IS_USBRST))
+    {
+      USB_CTRL1->ISTAT = USB_IS_USBRST;
+      usb_cb_device_reset ();
+      dev_p->reset++;
+    }
+  else if ((istat_value & USB_IS_ERROR))
+    { /* Clear Errors.  */
+      USB_CTRL1->ERRSTAT = USB_CTRL1->ERRSTAT;
+      USB_CTRL1->ISTAT = USB_IS_ERROR;
+      /*reset???*/
+      dev_p->error++;
+    }
+  else if ((istat_value & USB_IS_TOKDNE))
+    {
+      handle_transaction (stat);
+      dev_p->tkdone++;
+    }
+  else if ((istat_value & USB_IS_STALL))
+    {
+      /* ??? stat includes ep_num in this case ???: No, it doesn't  */
+
+      if (kl27z_ep_is_stall (0))
+	{ /* It's endpoint 0, recover from erorr.  */
+	  dev_p->state = WAIT_SETUP;
+	  kl27z_ep_clear_stall (0);
+	  kl27z_prepare_ep0_setup ();
+	}
+
+      USB_CTRL1->ISTAT = USB_IS_STALL;
+      dev_p->stall++;
+    }
+}
+
+#define DATA0 0
+#define DATA1 1
+
+static void
+handle_datastage_out (uint8_t stat)
+{
+  int odd = (stat >> 2)&1;
+  int data01 = !((BD_table[odd].ctrl >> 6)&1);
+  uint32_t len = (BD_table[odd].ctrl >> 16)&0x3ff;
+
+  data_p->len -= len;
+  data_p->addr += len;
+
+  len = data_p->len;
+  if (len > USB_MAX_PACKET_SIZE)
+    len = USB_MAX_PACKET_SIZE;
+
+  if (data_p->len == 0)
+    {
+      /* No more data to receive, proceed to send acknowledge for IN.  */
+      dev_p->state = WAIT_STATUS_IN;
+      kl27z_prepare_ep0_in (setup, 0, DATA1);
+    }
+  else
+    {
+      dev_p->state = OUT_DATA;
+      kl27z_prepare_ep0_out (data_p->addr, len, data01);
+    }
+}
+
+static void
+handle_datastage_in (uint8_t stat)
+{
+  int odd = (stat >> 2)&1;
+  int data01 = !((BD_table[2+odd].ctrl >> 6)&1);
+  uint32_t len = USB_MAX_PACKET_SIZE;
+
+  if ((data_p->len == 0) && (dev_p->state == LAST_IN_DATA))
+    {
+      if (data_p->require_zlp)
+	{
+	  data_p->require_zlp = 0;
+
+	  /* No more data to send.  Send empty packet */
+	  kl27z_prepare_ep0_in (setup, 0, data01);
+	}
+      else
+	{
+	  /* No more data to send, proceed to receive OUT acknowledge.  */
+	  dev_p->state = WAIT_STATUS_OUT;
+	  kl27z_prepare_ep0_out (setup, 8, DATA1);
+	}
+
+      return;
+    }
+
+  dev_p->state = (data_p->len <= len) ? LAST_IN_DATA : IN_DATA;
+
+  if (len > data_p->len)
+    len = data_p->len;
+
+  kl27z_prepare_ep0_in (data_p->addr, len, data01);
+  data_p->len -= len;
+  data_p->addr += len;
+}
+
+typedef int (*HANDLER) (uint8_t req, struct req_args *arg);
+
+static int
+std_none (uint8_t req, struct req_args *arg)
+{
+  (void)req; (void)arg;
+  return USB_UNSUPPORT;
+}
+
+static int
+std_get_status (uint8_t req, struct req_args *arg)
+{
+  uint8_t rcp = req & RECIPIENT;
+  uint16_t status_info = 0;
+
+  if (arg->value != 0 || arg->len != 2 || (arg->index >> 8) != 0
+      || USB_SETUP_SET (req))
+    return USB_UNSUPPORT;
+
+  if (rcp == DEVICE_RECIPIENT)
+    {
+      if (arg->index == 0)
+	{
+	  /* Get Device Status */
+	  uint8_t feature = dev_p->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;
+
+	  return usb_lld_reply_request (&status_info, 2, arg);
+	}
+    }
+  else if (rcp == INTERFACE_RECIPIENT)
+    {
+      int r;
+
+      if (dev_p->configuration == 0)
+	return USB_UNSUPPORT;
+
+      r = usb_cb_interface (USB_QUERY_INTERFACE, arg);
+      if (r != USB_SUCCESS)
+	return USB_UNSUPPORT;
+
+      return usb_lld_reply_request (&status_info, 2, arg);
+    }
+  else if (rcp == ENDPOINT_RECIPIENT)
+    {
+      uint8_t n = (arg->index & 0x0f);
+
+      if ((arg->index & 0x70) || n == ENDP0)
+	return USB_UNSUPPORT;
+
+      if (kl27z_ep_is_disabled (n))
+	return USB_UNSUPPORT;
+
+      status_info = kl27z_ep_is_stall (n);
+      return usb_lld_reply_request (&status_info, 2, arg);
+    }
+
+  return USB_UNSUPPORT;
+}
+
+static int
+std_clear_feature (uint8_t req, struct req_args *arg)
+{
+  uint8_t rcp = req & RECIPIENT;
+
+  if (USB_SETUP_GET (req))
+    return USB_UNSUPPORT;
+
+  if (rcp == DEVICE_RECIPIENT)
+    {
+      if (arg->len != 0 || arg->index != 0)
+	return USB_UNSUPPORT;
+
+      if (arg->value == DEVICE_REMOTE_WAKEUP)
+	{
+	  dev_p->feature &= ~(1 << 5);
+	  return USB_SUCCESS;
+	}
+    }
+  else if (rcp == ENDPOINT_RECIPIENT)
+    {
+      uint8_t n = (arg->index & 0x0f);
+
+      if (dev_p->configuration == 0)
+	return USB_UNSUPPORT;
+
+      if (arg->len != 0 || (arg->index >> 8) != 0
+	  || arg->value != ENDPOINT_STALL || n == ENDP0)
+	return USB_UNSUPPORT;
+
+      if (kl27z_ep_is_disabled (n))
+	return USB_UNSUPPORT;
+
+      kl27z_ep_clear_dtog ((arg->index & 0x80) == 0, n);
+
+      // event??
+      return USB_SUCCESS;
+    }
+
+  return USB_UNSUPPORT;
+}
+
+static int
+std_set_feature (uint8_t req, struct req_args *arg)
+{
+  uint8_t rcp = req & RECIPIENT;
+
+  if (USB_SETUP_GET (req))
+    return USB_UNSUPPORT;
+
+  if (rcp == DEVICE_RECIPIENT)
+    {
+      if (arg->len != 0 || arg->index != 0)
+	return USB_UNSUPPORT;
+
+      if (arg->value == DEVICE_REMOTE_WAKEUP)
+	{
+	  dev_p->feature |= 1 << 5;
+	  // event??
+	  return USB_SUCCESS;
+	}
+    }
+  else if (rcp == ENDPOINT_RECIPIENT)
+    {
+      uint8_t n = (arg->index & 0x0f);
+
+      if (dev_p->configuration == 0)
+	return USB_UNSUPPORT;
+
+      if (arg->len != 0 || (arg->index >> 8) != 0
+	  || arg->value != 0 || n == ENDP0)
+	return USB_UNSUPPORT;
+
+      if (kl27z_ep_is_disabled (n))
+	return USB_UNSUPPORT;
+
+      kl27z_ep_stall (n);
+
+      // event??
+      return USB_SUCCESS;
+    }
+
+  return USB_UNSUPPORT;
+}
+
+static int
+std_set_address (uint8_t req, struct req_args *arg)
+{
+  uint8_t rcp = req & RECIPIENT;
+
+  if (USB_SETUP_GET (req))
+    return USB_UNSUPPORT;
+
+  if (rcp == DEVICE_RECIPIENT && arg->len == 0 && arg->value <= 127
+      && arg->index == 0 && dev_p->configuration == 0)
+    return USB_SUCCESS;
+
+  return USB_UNSUPPORT;
+}
+
+static int
+std_get_descriptor (uint8_t req, struct req_args *arg)
+{
+  uint8_t rcp = req & RECIPIENT;
+
+  if (USB_SETUP_SET (req))
+    return USB_UNSUPPORT;
+
+  return usb_cb_get_descriptor (rcp, (arg->value >> 8),
+				(arg->value & 0xff), arg);
+}
+
+static int
+std_get_configuration (uint8_t req,  struct req_args *arg)
+{
+  uint8_t rcp = req & RECIPIENT;
+
+  (void)arg;
+  if (USB_SETUP_SET (req))
+    return USB_UNSUPPORT;
+
+  if (rcp == DEVICE_RECIPIENT)
+    return usb_lld_reply_request (&dev_p->configuration, 1, arg);
+
+  return USB_UNSUPPORT;
+}
+
+static int
+std_set_configuration (uint8_t req, struct req_args *arg)
+{
+  uint8_t rcp = req & RECIPIENT;
+
+  if (USB_SETUP_GET (req))
+    return USB_UNSUPPORT;
+
+  if (rcp == DEVICE_RECIPIENT && arg->index == 0 && arg->len == 0)
+    return usb_cb_handle_event (USB_EVENT_CONFIG, arg->value);
+
+  return USB_UNSUPPORT;
+}
+
+static int
+std_get_interface (uint8_t req, struct req_args *arg)
+{
+  uint8_t rcp = req & RECIPIENT;
+
+  if (USB_SETUP_SET (req))
+    return USB_UNSUPPORT;
+
+  if (rcp == INTERFACE_RECIPIENT)
+    {
+      if (arg->value != 0 || (arg->index >> 8) != 0 || arg->len != 1)
+	return USB_UNSUPPORT;
+
+      if (dev_p->configuration == 0)
+	return USB_UNSUPPORT;
+
+      return usb_cb_interface (USB_GET_INTERFACE, arg);
+    }
+
+  return USB_UNSUPPORT;
+}
+
+static int
+std_set_interface (uint8_t req, struct req_args *arg)
+{
+  uint8_t rcp = req & RECIPIENT;
+
+  if (USB_SETUP_GET (req) || rcp != INTERFACE_RECIPIENT
+      || arg->len != 0 || (arg->index >> 8) != 0
+      || (arg->value >> 8) != 0 || dev_p->configuration == 0)
+    return USB_UNSUPPORT;
+
+  return usb_cb_interface (USB_SET_INTERFACE, arg);
+}
+
+
+static void
+handle_setup0 (void)
+{
+  struct req_args *arg = (struct req_args *)&setup[2];
+  int r = USB_UNSUPPORT;
+  HANDLER handler;
+
+  data_p->addr = NULL;
+  data_p->len = 0;
+  data_p->require_zlp = 0;
+
+  if ((setup[0] & REQUEST_TYPE) == STANDARD_REQUEST)
+    {
+      if (setup[1] < TOTAL_REQUEST)
+	{
+	  switch (setup[1])
+	    {
+	    case 0: handler = std_get_status;  break;
+	    case 1: handler = std_clear_feature;  break;
+	    case 3: handler = std_set_feature;  break;
+	    case 5: handler = std_set_address;  break;
+	    case 6: handler = std_get_descriptor;  break;
+	    case 8: handler = std_get_configuration;  break;
+	    case 9: handler = std_set_configuration;  break;
+	    case 10: handler = std_get_interface;  break;
+	    case 11: handler = std_set_interface;  break;
+	    default: handler = std_none;  break;
+	    }
+
+	  r = (*handler) (setup[0], arg);
+	}
+    }
+  else
+    r = usb_cb_setup (setup[0], setup[1], arg);
+
+  if (r != USB_SUCCESS)
+    dev_p->state = STALLED;
+  else if (USB_SETUP_SET (setup[0]))
+    {
+      if (arg->len == 0)
+	{
+	  /* Zero length packet for ACK.  */
+	  kl27z_prepare_ep0_in (setup, 0, DATA1);
+	  dev_p->state = WAIT_STATUS_IN;
+	}
+    }
+}
+
+static void
+handle_in0 (uint8_t stat)
+{
+  if (dev_p->state == IN_DATA || dev_p->state == LAST_IN_DATA)
+    handle_datastage_in (stat);
+  else if (dev_p->state == WAIT_STATUS_IN)
+    { /* Control WRITE transfer done successfully.  */
+      uint16_t value = (setup[3]<<8) | setup[2];
+
+      if ((setup[1] == SET_ADDRESS) &&
+	  ((setup[0] & (REQUEST_TYPE | RECIPIENT))
+	   == (STANDARD_REQUEST | DEVICE_RECIPIENT)))
+	{
+	  kl27z_set_daddr (value);
+	  usb_cb_handle_event (USB_EVENT_ADDRESS, value);
+	  ep[0].rx_odd = 0;
+	}
+      else
+	usb_cb_ctrl_write_finish  (setup[0], setup[1],
+				   (struct req_args *)&setup[2]);
+
+      dev_p->state = WAIT_SETUP;
+      kl27z_prepare_ep0_setup ();
+    }
+  else
+    dev_p->state = STALLED;
+}
+
+static void
+handle_out0 (uint8_t stat)
+{
+  if (dev_p->state == IN_DATA || dev_p->state == LAST_IN_DATA)
+    /* Host aborts the control READ transfer before finish. */
+    dev_p->state = STALLED;
+  else if (dev_p->state == OUT_DATA)
+    /* It's normal control WRITE transfer.  */
+    handle_datastage_out (stat);
+  else if (dev_p->state == WAIT_STATUS_OUT)
+    { /* Control READ transfer done successfully.  */
+      dev_p->state = WAIT_SETUP;
+      kl27z_prepare_ep0_setup ();
+    }
+  else
+    dev_p->state = STALLED;
+}
+
+static void
+handle_transaction (uint8_t stat)
+{
+  int odd = (stat >> 2)&1;
+  uint8_t ep_num = (stat >> 4);
+
+  if (ep_num == 0)
+    {
+      if ((stat & 0x08) == 0)
+	{
+	  ep[0].rx_odd ^= 1;
+	  if (TOK_PID (BD_table[odd].ctrl) == 0x0d)
+	    {
+	      handle_setup0 ();
+	      USB_CTRL1->ISTAT = USB_IS_TOKDNE;
+	      USB_CTRL1->CTL = 0x01; /* Clear TXSUSPENDTOKENBUSY.  */
+	    }
+	  else
+	    {
+	      USB_CTRL1->ISTAT = USB_IS_TOKDNE;
+	      handle_out0 (stat);
+	    }
+	}
+      else
+	{
+	  ep[0].tx_odd ^= 1;
+	  USB_CTRL1->ISTAT = USB_IS_TOKDNE;
+	  handle_in0 (stat);
+	}
+
+      if (dev_p->state == STALLED)
+	kl27z_ep_stall (0);
+    }
+  else
+    {
+      if ((stat & 0x08) == 0)
+	{
+	  dev_p->recv++;
+	  usb_cb_rx_ready (ep_num);
+	  ep[ep_num].rx_odd ^= 1;
+	}
+      else
+	{
+	  /* XXX: Can be NAK.  Check BDT if it's NAK or not.  */
+
+	  dev_p->send++;
+	  ep[ep_num].tx_odd ^= 1;
+	  usb_cb_tx_done (ep_num);
+	}
+
+      USB_CTRL1->ISTAT = USB_IS_TOKDNE;
+    }
+}
+
+void
+usb_lld_reset (uint8_t feature)
+{
+  dev_p->feature = feature;
+  usb_lld_set_configuration (0);
+
+  /* Reset USB */
+  USB_CTRL2->USBTRC0 = 0xc0;
+
+  USB_CTRL1->CTL = 0x00;    /* Disable USB FS communication module */
+
+  dev_p->state = WAIT_SETUP;
+  dev_p->tkdone = 0;
+  dev_p->error = 0;
+  dev_p->stall = 0;
+
+  kl27z_set_daddr (0);
+  kl27z_usb_init ();
+
+  /* Clear Interrupt Status Register, and enable interrupt for USB */
+  USB_CTRL1->ISTAT = 0xff;		     /* All clear */
+
+  USB_CTRL1->INTEN = USB_IS_STALL | USB_IS_TOKDNE
+                   | USB_IS_ERROR | USB_IS_USBRST;
+}
+
+void
+usb_lld_setup_endpoint (int n, int rx_en, int tx_en)
+{
+  if (n == 0)
+    {
+      /* Enable the endpoint 0.  */
+      USB_ENDPT[0].EP = 0x0d;
+      kl27z_prepare_ep0_setup ();
+    }
+  else
+    {
+      /* Enable the endpoint.  */
+      USB_ENDPT[n].EP = (rx_en << 3)|(tx_en << 2)|0x11;
+
+      /* Configure BDT entry so that it starts with DATA0.  */
+
+      /* RX */
+      BD_table[4*n+ep[n].rx_odd].ctrl = 0x0000;
+      BD_table[4*n+ep[n].rx_odd].buf = NULL;
+      BD_table[4*n+!ep[n].rx_odd].ctrl = 0x0040;
+      BD_table[4*n+!ep[n].rx_odd].buf = NULL;
+
+      /* TX */
+      BD_table[4*n+2+ep[n].tx_odd].ctrl = 0x0000;
+      BD_table[4*n+2+ep[n].tx_odd].buf = NULL;
+      BD_table[4*n+2+!ep[n].tx_odd].ctrl = 0x0040;
+      BD_table[4*n+2+!ep[n].tx_odd].buf = NULL;
+    }
+}
+
+
+void
+usb_lld_set_configuration (uint8_t config)
+{
+  dev_p->configuration = config;
+}
+
+uint8_t
+usb_lld_current_configuration (void)
+{
+  return dev_p->configuration;
+}
+
+void
+usb_lld_set_data_to_recv (void *p, size_t len)
+{
+  data_p->addr = (uint8_t *)p;
+  data_p->len = len;
+  if (len > USB_MAX_PACKET_SIZE)
+    len = USB_MAX_PACKET_SIZE;
+
+  kl27z_prepare_ep0_out (p, len, DATA1);
+  dev_p->state = OUT_DATA;
+}
+
+/*
+ * BUF: Pointer to data memory.  Data memory should not be allocated
+ *      on stack when BUFLEN > USB_MAX_PACKET_SIZE.
+ *
+ * BUFLEN: size of the data.
+ */
+int
+usb_lld_reply_request (const void *buf, size_t buflen, struct req_args *a)
+{
+  uint32_t len_asked = a->len;
+  uint32_t len;
+
+  data_p->addr = (void *)buf;
+  data_p->len = buflen;
+
+  /* Restrict the data length to be the one host asks for */
+  if (data_p->len > len_asked)
+    data_p->len = len_asked;
+
+  data_p->require_zlp = (data_p->len != 0
+			 && (data_p->len % USB_MAX_PACKET_SIZE) == 0);
+
+  if (data_p->len < USB_MAX_PACKET_SIZE)
+    {
+      len = data_p->len;
+      dev_p->state = LAST_IN_DATA;
+    }
+  else
+    {
+      len = USB_MAX_PACKET_SIZE;
+      dev_p->state = IN_DATA;
+    }
+
+  if (len)
+    kl27z_prepare_ep0_in (data_p->addr, len, DATA1);
+
+  data_p->len -= len;
+  data_p->addr += len;
+
+  return USB_SUCCESS;
+}
+
+void
+usb_lld_rx_enable (int n, void *buf, size_t len)
+{
+  int data01 = !((BD_table[4*n+!ep[n].rx_odd].ctrl >> 6)&1);
+
+  BD_table[4*n+ep[n].rx_odd].ctrl = (len << 16) | 0x0088 | (data01 << 6);
+  BD_table[4*n+ep[n].rx_odd].buf = buf;
+}
+
+int
+usb_lld_rx_data_len (int n)
+{
+  return (BD_table[4*n+!ep[n].rx_odd].ctrl >> 16)&0x3ff;
+}
+
+
+void
+usb_lld_tx_enable (uint8_t n, const void *buf, size_t len)
+{
+  int data01 = !((BD_table[4*n+2+!ep[n].tx_odd].ctrl >> 6)&1);
+
+  BD_table[4*n+2+ep[n].tx_odd].ctrl = (len << 16) | 0x0088 | (data01 << 6); 
+  BD_table[4*n+2+ep[n].tx_odd].buf = (void *)buf;
+}
+
+int
+usb_lld_tx_result (int ep_num)
+{
+  (void)ep_num;
+  return 0; /* XXX: return -1 when NAK */
+}
diff --git a/example-fs-bb48/usb_lld.h b/example-fs-bb48/usb_lld.h
new file mode 100644
index 0000000..da694a6
--- /dev/null
+++ b/example-fs-bb48/usb_lld.h
@@ -0,0 +1,115 @@
+#define STANDARD_ENDPOINT_DESC_SIZE             0x09
+
+/* endpoints enumeration */
+#define ENDP0       ((uint8_t)0)
+#define ENDP1       ((uint8_t)1)
+#define ENDP2       ((uint8_t)2)
+#define ENDP3       ((uint8_t)3)
+#define ENDP4       ((uint8_t)4)
+#define ENDP5       ((uint8_t)5)
+#define ENDP6       ((uint8_t)6)
+#define ENDP7       ((uint8_t)7)
+
+/* EP_TYPE[1:0] EndPoint TYPE */
+#define EP_BULK        (0x0000) /* EndPoint BULK        */
+#define EP_CONTROL     (0x0200) /* EndPoint CONTROL     */
+#define EP_ISOCHRONOUS (0x0400) /* EndPoint ISOCHRONOUS */
+#define EP_INTERRUPT   (0x0600) /* EndPoint INTERRUPT   */
+
+enum RECIPIENT_TYPE
+{
+  DEVICE_RECIPIENT,     /* Recipient device    */
+  INTERFACE_RECIPIENT,  /* Recipient interface */
+  ENDPOINT_RECIPIENT,   /* Recipient endpoint  */
+  OTHER_RECIPIENT
+};
+
+enum DESCRIPTOR_TYPE
+{
+  DEVICE_DESCRIPTOR = 1,
+  CONFIG_DESCRIPTOR,
+  STRING_DESCRIPTOR,
+  INTERFACE_DESCRIPTOR,
+  ENDPOINT_DESCRIPTOR
+};
+
+#define REQUEST_DIR       0x80  /* Mask to get request dir  */
+#define REQUEST_TYPE      0x60  /* Mask to get request type */
+#define STANDARD_REQUEST  0x00  /* Standard request         */
+#define CLASS_REQUEST     0x20  /* Class request            */
+#define VENDOR_REQUEST    0x40  /* Vendor request           */
+#define RECIPIENT         0x1F  /* Mask to get recipient    */
+
+#define USB_SETUP_SET(req) ((req & REQUEST_DIR) == 0)
+#define USB_SETUP_GET(req) ((req & REQUEST_DIR) != 0)
+
+enum
+{
+  USB_UNSUPPORT = 0,
+  USB_SUCCESS = 1,
+};
+
+struct req_args {
+  uint16_t value;
+  uint16_t index;
+  uint16_t len;
+};
+
+void usb_cb_device_reset (void);
+int usb_cb_setup (uint8_t req, uint8_t req_no, struct req_args *arg);
+int usb_cb_interface (uint8_t cmd, struct req_args *arg);
+int usb_cb_get_descriptor (uint8_t rcp, uint8_t desc_type, uint8_t desc_index,
+			   struct req_args *arg);
+int usb_cb_handle_event (uint8_t event_type, uint16_t value);
+void usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no,
+			       struct req_args *arg);
+void usb_cb_tx_done (uint8_t ep_num);
+void usb_cb_rx_ready (uint8_t ep_num);
+
+enum {
+  USB_EVENT_ADDRESS,
+  USB_EVENT_CONFIG,
+  USB_EVENT_SUSPEND,
+  USB_EVENT_WAKEUP,
+  USB_EVENT_STALL,
+};
+
+enum {
+  USB_SET_INTERFACE,
+  USB_GET_INTERFACE,
+  USB_QUERY_INTERFACE,
+};
+
+enum DEVICE_STATE
+{
+  UNCONNECTED,
+  ATTACHED,
+  POWERED,
+  SUSPENDED,
+  ADDRESSED,
+  CONFIGURED
+};
+
+void usb_lld_init (uint8_t feature);
+
+int usb_lld_reply_request (const void *buf, size_t buflen,
+			   struct req_args *arg);
+void usb_lld_set_data_to_recv (void *p, size_t len);
+
+void usb_lld_tx_enable (uint8_t ep_num, const void *buf, size_t len);
+int usb_lld_tx_result (int ep_num);
+
+void usb_lld_rx_enable (int ep_num, void *buf, size_t len);
+int usb_lld_rx_data_len (int ep_num);
+
+void usb_lld_stall (int ep_num);
+
+void usb_lld_reset (uint8_t feature);
+void usb_lld_setup_endpoint (int n, int rx_en, int tx_en);
+void usb_lld_set_configuration (uint8_t config);
+uint8_t usb_lld_current_configuration (void);
+
+void usb_lld_prepare_shutdown (void);
+void usb_lld_shutdown (void);
+
+void usb_interrupt_handler (void);
diff --git a/example-fsm-55/sys.c b/example-fsm-55/sys.c
index 6f3813d..2b7784f 100644
--- a/example-fsm-55/sys.c
+++ b/example-fsm-55/sys.c
@@ -31,7 +31,6 @@ reset (void)
 }
 
 extern uint8_t __main_stack_end__;
-extern void svc (void);
 extern void preempt (void);
 extern void chx_timer_expired (void);
 extern void chx_handle_intr (void);
@@ -44,14 +43,7 @@ static void nmi (void)
 static void __attribute__ ((naked))
 hard_fault (void)
 {
-  register uint32_t primask;
-
-  asm ("mrs	%0, PRIMASK" : "=r" (primask));
-
-  if (primask)
-    asm volatile ("b	svc");
-  else
-    for (;;);
+  for (;;);
 }
 
 static void mem_manage (void)
@@ -89,7 +81,7 @@ handler vector[] __attribute__ ((section(".vectors"))) = {
   none,
   /* 0x20 */
   none, none, none,		/* reserved */
-  svc,				/* SVCall */
+  none,				/* SVCall */
   none,				/* Debug */
   none,				/* reserved */
   preempt,			/* PendSV */
-- 
cgit v1.2.3