aboutsummaryrefslogtreecommitdiff
path: root/example-fs-bb48
diff options
context:
space:
mode:
authorNIIBE Yutaka <gniibe@fsij.org>2016-04-18 11:46:14 +0900
committerNIIBE Yutaka <gniibe@fsij.org>2016-04-18 11:46:14 +0900
commit82749ab97af6ec1de605f0638d44999c3b50eadf (patch)
tree214b4b33294e68d8f1853553f93f74b232a961d5 /example-fs-bb48
parent92e17d3bdf2371031967f949659edb91b72fb63f (diff)
Add support for FS-BB48
Diffstat (limited to 'example-fs-bb48')
-rw-r--r--example-fs-bb48/Makefile31
l---------example-fs-bb48/board.h1
-rw-r--r--example-fs-bb48/reset.c114
-rw-r--r--example-fs-bb48/sample.c228
-rw-r--r--example-fs-bb48/sample.ld135
-rw-r--r--example-fs-bb48/stream.h24
-rw-r--r--example-fs-bb48/usb-cdc.c506
-rw-r--r--example-fs-bb48/usb_kl27z.c1035
-rw-r--r--example-fs-bb48/usb_lld.h115
9 files changed, 2189 insertions, 0 deletions
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);