うおーるぼっとをWiiリモコンでコントロールする新しいプログラムです。 以前のものより、Wiiリモコンが早く繋がる様になりました。 It is a program which controls A with the Wii remote. ※ A Bluetooth dongle and a Wii remote control are needed.

Dependencies:   USBHost mbed FATFileSystem mbed-rtos

Files at this revision

API Documentation at this revision

Comitter:
jksoft
Date:
Mon Jun 10 16:01:50 2013 +0000
Commit message:
1.0

Changed in this revision

TB6612FNG2/TB6612.cpp Show annotated file Show diff for this revision Revisions of this file
TB6612FNG2/TB6612.h Show annotated file Show diff for this revision Revisions of this file
USBHost.lib Show annotated file Show diff for this revision Revisions of this file
USBHost/FATFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
USBHost/FATFileSystem/ChaN/ccsbcs.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/FATFileSystem/ChaN/diskio.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/FATFileSystem/ChaN/diskio.h Show annotated file Show diff for this revision Revisions of this file
USBHost/FATFileSystem/ChaN/ff.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/FATFileSystem/ChaN/ff.h Show annotated file Show diff for this revision Revisions of this file
USBHost/FATFileSystem/ChaN/ffconf.h Show annotated file Show diff for this revision Revisions of this file
USBHost/FATFileSystem/ChaN/integer.h Show annotated file Show diff for this revision Revisions of this file
USBHost/FATFileSystem/FATDirHandle.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/FATFileSystem/FATDirHandle.h Show annotated file Show diff for this revision Revisions of this file
USBHost/FATFileSystem/FATFileHandle.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/FATFileSystem/FATFileHandle.h Show annotated file Show diff for this revision Revisions of this file
USBHost/FATFileSystem/FATFileSystem.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/FATFileSystem/FATFileSystem.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHost/IUSBEnumerator.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHost/USBDeviceConnected.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHost/USBDeviceConnected.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHost/USBEndpoint.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHost/USBEndpoint.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHost/USBHALHost.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHost/USBHALHost.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHost/USBHost.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHost/USBHost.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHost/USBHostConf.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHost/USBHostTypes.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHost/dbg.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHostHID/USBHostKeyboard.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHostHID/USBHostKeyboard.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHostHID/USBHostMouse.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHostHID/USBHostMouse.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHostHub/USBHostHub.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHostHub/USBHostHub.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHostMSD/USBHostMSD.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHostMSD/USBHostMSD.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHostSerial/MtxCircBuffer.h Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHostSerial/USBHostSerial.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/USBHostSerial/USBHostSerial.h Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos.lib Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtos/Mail.h Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtos/MemoryPool.h Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtos/Mutex.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtos/Mutex.h Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtos/Queue.h Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtos/RtosTimer.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtos/RtosTimer.h Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtos/Semaphore.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtos/Semaphore.h Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtos/Thread.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtos/Thread.h Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtos/rtos.h Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/HAL_CM.c Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/LPC11U24/GCC_ARM/HAL_CM0.s Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/LPC11U24/GCC_ARM/SVC_Table.s Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/LPC11U24/uARM/HAL_CM0.c Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/LPC11U24/uARM/SVC_Table.s Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/LPC1768/ARM/HAL_CM3.c Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/LPC1768/ARM/SVC_Table.s Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/LPC1768/GCC_ARM/HAL_CM3.s Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/LPC1768/GCC_ARM/SVC_Table.s Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/RTX_CM_lib.h Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/RTX_Conf_CM.c Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/RTX_Config.h Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/cmsis_os.h Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/os_tcb.h Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/rt_CMSIS.c Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/rt_Event.c Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/rt_Event.h Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/rt_HAL_CM.h Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/rt_List.c Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/rt_List.h Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/rt_Mailbox.c Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/rt_Mailbox.h Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/rt_MemBox.c Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/rt_MemBox.h Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/rt_Mutex.c Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/rt_Mutex.h Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/rt_Robin.c Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/rt_Robin.h Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/rt_Semaphore.c Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/rt_Semaphore.h Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/rt_System.c Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/rt_System.h Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/rt_Task.c Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/rt_Task.h Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/rt_Time.c Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/rt_Time.h Show annotated file Show diff for this revision Revisions of this file
USBHost/mbed-rtos/rtx/rt_TypeDef.h Show annotated file Show diff for this revision Revisions of this file
USBHostBTstack/USBHostBTstack.cpp Show annotated file Show diff for this revision Revisions of this file
USBHostBTstack/USBHostBTstack.h Show annotated file Show diff for this revision Revisions of this file
Wiimote/Wiimote.cpp Show annotated file Show diff for this revision Revisions of this file
Wiimote/Wiimote.h Show annotated file Show diff for this revision Revisions of this file
btstack/bt_control.h Show annotated file Show diff for this revision Revisions of this file
btstack/btstack.h Show annotated file Show diff for this revision Revisions of this file
btstack/btstack_memory.c Show annotated file Show diff for this revision Revisions of this file
btstack/btstack_memory.h Show annotated file Show diff for this revision Revisions of this file
btstack/config.h Show annotated file Show diff for this revision Revisions of this file
btstack/debug.h Show annotated file Show diff for this revision Revisions of this file
btstack/hal_cpu.h Show annotated file Show diff for this revision Revisions of this file
btstack/hal_mbed/hal_cpu.cpp Show annotated file Show diff for this revision Revisions of this file
btstack/hal_mbed/hal_tick.cpp Show annotated file Show diff for this revision Revisions of this file
btstack/hal_tick.h Show annotated file Show diff for this revision Revisions of this file
btstack/hci.c Show annotated file Show diff for this revision Revisions of this file
btstack/hci.h Show annotated file Show diff for this revision Revisions of this file
btstack/hci_cmds.c Show annotated file Show diff for this revision Revisions of this file
btstack/hci_cmds.h Show annotated file Show diff for this revision Revisions of this file
btstack/hci_dump.c Show annotated file Show diff for this revision Revisions of this file
btstack/hci_dump.h Show annotated file Show diff for this revision Revisions of this file
btstack/hci_transport.h Show annotated file Show diff for this revision Revisions of this file
btstack/hci_transport_usb.cpp Show annotated file Show diff for this revision Revisions of this file
btstack/l2cap.c Show annotated file Show diff for this revision Revisions of this file
btstack/l2cap.h Show annotated file Show diff for this revision Revisions of this file
btstack/l2cap_signaling.c Show annotated file Show diff for this revision Revisions of this file
btstack/l2cap_signaling.h Show annotated file Show diff for this revision Revisions of this file
btstack/linked_list.c Show annotated file Show diff for this revision Revisions of this file
btstack/linked_list.h Show annotated file Show diff for this revision Revisions of this file
btstack/memory_pool.h Show annotated file Show diff for this revision Revisions of this file
btstack/remote_device_db.h Show annotated file Show diff for this revision Revisions of this file
btstack/remote_device_db_memory.c Show annotated file Show diff for this revision Revisions of this file
btstack/rfcomm.c Show annotated file Show diff for this revision Revisions of this file
btstack/rfcomm.h Show annotated file Show diff for this revision Revisions of this file
btstack/run_loop.c Show annotated file Show diff for this revision Revisions of this file
btstack/run_loop.h Show annotated file Show diff for this revision Revisions of this file
btstack/run_loop_embedded.c Show annotated file Show diff for this revision Revisions of this file
btstack/run_loop_private.h Show annotated file Show diff for this revision Revisions of this file
btstack/sdp.c Show annotated file Show diff for this revision Revisions of this file
btstack/sdp.h Show annotated file Show diff for this revision Revisions of this file
btstack/sdp_util.c Show annotated file Show diff for this revision Revisions of this file
btstack/sdp_util.h Show annotated file Show diff for this revision Revisions of this file
btstack/utils.c Show annotated file Show diff for this revision Revisions of this file
btstack/utils.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
usbbt/bd_addr.cpp Show annotated file Show diff for this revision Revisions of this file
usbbt/bd_addr.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TB6612FNG2/TB6612.cpp	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,55 @@
+/**
+ * Motor Driver TB6612 Control Library
+ *
+ * -- TB6612 is a device of the TOSHIBA. 
+ *
+ * Copyright (C) 2012 Junichi Katsu (JKSOFT) 
+ */
+
+
+#include "TB6612.h"
+
+// TB6612 Class Constructor
+TB6612::TB6612(PinName pwm, PinName fwd, PinName rev):
+        _pwm(pwm), _fwd(fwd), _rev(rev) {
+
+    _fwd = 0;
+    _rev = 0;
+    _pwm = 0.0;
+    _pwm.period(0.001);
+}
+
+// Speed Control
+//  arg
+//   int speed -100 -- 0 -- 100
+void TB6612::speed(int speed) {
+        
+    if( speed > 0 )
+    {
+        _pwm = ((float)speed) / 100.0;
+        _fwd = 1;
+        _rev = 0;
+    }
+    else if( speed < 0 )
+    {
+        _pwm = -((float)speed) / 100.0;
+        _fwd = 0;
+        _rev = 1;
+    }
+    else
+    {
+        _fwd = 1;
+        _rev = 1;
+    }
+}
+
+
+// Speed Control with time-out
+//  arg
+//   int speed -100 -- 0 -- 100
+//   int time  0
+void TB6612::move(int sspeed , int time)
+{
+    speed(sspeed);
+    wait_ms(time);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TB6612FNG2/TB6612.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,30 @@
+/**
+ * Motor Driver TB6612 Control Library
+ *
+ * -- TB6612 is a device of the rohm. 
+ *
+ * Copyright (C) 2012 Junichi Katsu (JKSOFT) 
+ */
+
+#ifndef MBED_TB6612_H
+#define MBED_TB6612_H
+
+#include "mbed.h"
+
+class TB6612 {
+public:
+    TB6612(PinName pwm, PinName fwd, PinName rev);
+    void speed(int speed);
+    void move(int speed , int time);
+    void operator= ( int value )
+    {
+        speed(value);
+    }
+    
+protected:
+    PwmOut _pwm;
+    DigitalOut _fwd;
+    DigitalOut _rev;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost.lib	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/USBHost/#0c11cf1cc218
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/FATFileSystem.lib	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/FATFileSystem/#b6669c987c8e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/FATFileSystem/ChaN/ccsbcs.cpp	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,540 @@
+/*------------------------------------------------------------------------*/
+/* Unicode - Local code bidirectional converter  (C)ChaN, 2009            */
+/* (SBCS code pages)                                                      */
+/*------------------------------------------------------------------------*/
+/*  437   U.S. (OEM)
+/   720   Arabic (OEM)
+/   1256  Arabic (Windows)
+/   737   Greek (OEM)
+/   1253  Greek (Windows)
+/   1250  Central Europe (Windows)
+/   775   Baltic (OEM)
+/   1257  Baltic (Windows)
+/   850   Multilingual Latin 1 (OEM)
+/   852   Latin 2 (OEM)
+/   1252  Latin 1 (Windows)
+/   855   Cyrillic (OEM)
+/   1251  Cyrillic (Windows)
+/   866   Russian (OEM)
+/   857   Turkish (OEM)
+/   1254  Turkish (Windows)
+/   858   Multilingual Latin 1 + Euro (OEM)
+/   862   Hebrew (OEM)
+/   1255  Hebrew (Windows)
+/   874   Thai (OEM, Windows)
+/   1258  Vietnam (OEM, Windows)
+*/
+
+#include "ff.h"
+
+
+#if _CODE_PAGE == 437
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {   /*  CP437(0x80-0xFF) to Unicode conversion table */
+    0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+    0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
+    0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+    0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
+    0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+    0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+    0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+    0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+    0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+    0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4,
+    0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
+    0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
+    0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 720
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {   /*  CP720(0x80-0xFF) to Unicode conversion table */
+    0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7,
+    0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9,
+    0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627,
+    0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F,
+    0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB,
+    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+    0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+    0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+    0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+    0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642,
+    0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A,
+    0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0xO650, 0x2248,
+    0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 737
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {   /*  CP737(0x80-0xFF) to Unicode conversion table */
+    0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398,
+    0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0,
+    0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9,
+    0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8,
+    0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0,
+    0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8,
+    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+    0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+    0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+    0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+    0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD,
+    0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E,
+    0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248,
+    0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 775
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {   /*  CP775(0x80-0xFF) to Unicode conversion table */
+    0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107,
+    0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5,
+    0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A,
+    0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4,
+    0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6,
+    0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB,
+    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118,
+    0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510,
+    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A,
+    0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D,
+    0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B,
+    0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+    0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144,
+    0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019,
+    0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E,
+    0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 850
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {   /*  CP850(0x80-0xFF) to Unicode conversion table */
+    0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+    0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
+    0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+    0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
+    0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+    0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
+    0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
+    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3,
+    0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+    0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE,
+    0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
+    0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE,
+    0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,
+    0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8,
+    0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 852
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {   /*  CP852(0x80-0xFF) to Unicode conversion table */
+    0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7,
+    0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106,
+    0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A,
+    0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D,
+    0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E,
+    0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB,
+    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A,
+    0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510,
+    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103,
+    0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+    0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE,
+    0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580,
+    0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161,
+    0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4,
+    0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8,
+    0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 855
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {   /*  CP855(0x80-0xFF) to Unicode conversion table */
+    0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404,
+    0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408,
+    0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C,
+    0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A,
+    0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414,
+    0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB,
+    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438,
+    0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510,
+    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A,
+    0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+    0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E,
+    0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580,
+    0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443,
+    0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116,
+    0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D,
+    0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 857
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {   /*  CP857(0x80-0xFF) to Unicode conversion table */
+    0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+    0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5,
+    0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+    0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F,
+    0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F,
+    0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
+    0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
+    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3,
+    0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+    0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, 0x0000, 0x00CD, 0x00CE,
+    0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
+    0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000,
+    0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4,
+    0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8,
+    0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 858
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {   /*  CP858(0x80-0xFF) to Unicode conversion table */
+    0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+    0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
+    0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+    0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
+    0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+    0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
+    0x00A9, 0x2563, 0x2551, 0x2557, 0x2550, 0x00A2, 0x00A5, 0x2510,
+    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3,
+    0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+    0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x20AC, 0x00CD, 0x00CE,
+    0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00C6, 0x00CC, 0x2580,
+    0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE,
+    0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,
+    0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8,
+    0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 862
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {   /*  CP862(0x80-0xFF) to Unicode conversion table */
+    0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7,
+    0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
+    0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7,
+    0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
+    0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+    0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+    0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+    0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+    0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+    0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4,
+    0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
+    0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
+    0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 866
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {   /*  CP866(0x80-0xFF) to Unicode conversion table */
+    0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+    0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
+    0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+    0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
+    0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+    0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+    0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+    0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+    0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+    0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+    0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+    0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E,
+    0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 874
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {   /*  CP874(0x80-0xFF) to Unicode conversion table */
+    0x20AC, 0x0000, 0x0000, 0x0000, 0x0000, 0x2026, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x00A0, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07,
+    0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F,
+    0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17,
+    0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F,
+    0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27,
+    0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F,
+    0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37,
+    0x0E38, 0x0E39, 0x0E3A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0E3F,
+    0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47,
+    0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F,
+    0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57,
+    0x0E58, 0x0E59, 0x0E5A, 0x0E5B, 0x0000, 0x0000, 0x0000, 0x0000
+};
+
+#elif _CODE_PAGE == 1250
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {   /*  CP1250(0x80-0xFF) to Unicode conversion table */
+    0x20AC, 0x0000, 0x201A, 0x0000, 0x201E, 0x2026, 0x2020, 0x2021,
+    0x0000, 0x2030, 0x0160, 0x2039, 0x015A, 0x0164, 0x017D, 0x0179,
+    0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+    0x0000, 0x2122, 0x0161, 0x203A, 0x015B, 0x0165, 0x017E, 0x017A,
+    0x00A0, 0x02C7, 0x02D8, 0x0141, 0x00A4, 0x0104, 0x00A6, 0x00A7,
+    0x00A8, 0x00A9, 0x015E, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x017B,
+    0x00B0, 0x00B1, 0x02DB, 0x0142, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+    0x00B8, 0x0105, 0x015F, 0x00BB, 0x013D, 0x02DD, 0x013E, 0x017C,
+    0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7,
+    0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E,
+    0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7,
+    0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF,
+    0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7,
+    0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F,
+    0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7,
+    0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9
+};
+
+#elif _CODE_PAGE == 1251
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {   /*  CP1251(0x80-0xFF) to Unicode conversion table */
+    0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021,
+    0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F,
+    0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+    0x0000, 0x2111, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F,
+    0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7,
+    0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407,
+    0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7,
+    0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457,
+    0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+    0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
+    0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+    0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
+    0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+    0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+    0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+    0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F
+};
+
+#elif _CODE_PAGE == 1252
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {   /*  CP1252(0x80-0xFF) to Unicode conversion table */
+    0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+    0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x017D, 0x0000,
+    0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+    0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x0000, 0x017E, 0x0178,
+    0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+    0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+    0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+    0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+    0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+    0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+    0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+    0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
+    0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+    0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+    0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+    0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF
+};
+
+#elif _CODE_PAGE == 1253
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {   /*  CP1253(0x80-0xFF) to Unicode conversion table */
+    0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+    0x0000, 0x2030, 0x0000, 0x2039, 0x000C, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+    0x0000, 0x2122, 0x0000, 0x203A, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x00A0, 0x0385, 0x0386, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+    0x00A8, 0x00A9, 0x0000, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x2015,
+    0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x00B5, 0x00B6, 0x00B7,
+    0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F,
+    0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
+    0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
+    0x03A0, 0x03A1, 0x0000, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7,
+    0x03A8, 0x03A9, 0x03AA, 0x03AD, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
+    0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
+    0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+    0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
+    0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x0000
+};
+
+#elif _CODE_PAGE == 1254
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {   /*  CP1254(0x80-0xFF) to Unicode conversion table */
+    0x20AC, 0x0000, 0x210A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+    0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+    0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x0000, 0x0000, 0x0178,
+    0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+    0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+    0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+    0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+    0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+    0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+    0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+    0x00D8, 0x00D9, 0x00DA, 0x00BD, 0x00DC, 0x0130, 0x015E, 0x00DF,
+    0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+    0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+    0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+    0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF
+};
+
+#elif _CODE_PAGE == 1255
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {   /*  CP1255(0x80-0xFF) to Unicode conversion table */
+    0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+    0x02C6, 0x2030, 0x0000, 0x2039, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+    0x02DC, 0x2122, 0x0000, 0x203A, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+    0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+    0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+    0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+    0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7,
+    0x05B8, 0x05B9, 0x0000, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF,
+    0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05F0, 0x05F1, 0x05F2, 0x05F3,
+    0x05F4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7,
+    0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
+    0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7,
+    0x05E8, 0x05E9, 0x05EA, 0x0000, 0x0000, 0x200E, 0x200F, 0x0000
+};
+
+#elif _CODE_PAGE == 1256
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {   /*  CP1256(0x80-0xFF) to Unicode conversion table */
+    0x20AC, 0x067E, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+    0x02C6, 0x2030, 0x0679, 0x2039, 0x0152, 0x0686, 0x0698, 0x0688,
+    0x06AF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+    0x06A9, 0x2122, 0x0691, 0x203A, 0x0153, 0x200C, 0x200D, 0x06BA,
+    0x00A0, 0x060C, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+    0x00A8, 0x00A9, 0x06BE, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+    0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+    0x00B8, 0x00B9, 0x061B, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x061F,
+    0x06C1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627,
+    0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F,
+    0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00D7,
+    0x0637, 0x0638, 0x0639, 0x063A, 0x0640, 0x0640, 0x0642, 0x0643,
+    0x00E0, 0x0644, 0x00E2, 0x0645, 0x0646, 0x0647, 0x0648, 0x00E7,
+    0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0649, 0x064A, 0x00EE, 0x00EF,
+    0x064B, 0x064C, 0x064D, 0x064E, 0x00F4, 0x064F, 0x0650, 0x00F7,
+    0x0651, 0x00F9, 0x0652, 0x00FB, 0x00FC, 0x200E, 0x200F, 0x06D2
+}
+
+#elif _CODE_PAGE == 1257
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {   /*  CP1257(0x80-0xFF) to Unicode conversion table */
+    0x20AC, 0x0000, 0x201A, 0x0000, 0x201E, 0x2026, 0x2020, 0x2021,
+    0x0000, 0x2030, 0x0000, 0x2039, 0x0000, 0x00A8, 0x02C7, 0x00B8,
+    0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+    0x0000, 0x2122, 0x0000, 0x203A, 0x0000, 0x00AF, 0x02DB, 0x0000,
+    0x00A0, 0x0000, 0x00A2, 0x00A3, 0x00A4, 0x0000, 0x00A6, 0x00A7,
+    0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+    0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+    0x00B8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6,
+    0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112,
+    0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B,
+    0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7,
+    0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF,
+    0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113,
+    0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C,
+    0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7,
+    0x0173, 0x014E, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x02D9
+};
+
+#elif _CODE_PAGE == 1258
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {   /*  CP1258(0x80-0xFF) to Unicode conversion table */
+    0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+    0x02C6, 0x2030, 0x0000, 0x2039, 0x0152, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+    0x02DC, 0x2122, 0x0000, 0x203A, 0x0153, 0x0000, 0x0000, 0x0178,
+    0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+    0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+    0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+    0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+    0x00C0, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+    0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x0300, 0x00CD, 0x00CE, 0x00CF,
+    0x0110, 0x00D1, 0x0309, 0x00D3, 0x00D4, 0x01A0, 0x00D6, 0x00D7,
+    0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x01AF, 0x0303, 0x00DF,
+    0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+    0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0301, 0x00ED, 0x00EE, 0x00EF,
+    0x0111, 0x00F1, 0x0323, 0x00F3, 0x00F4, 0x01A1, 0x00F6, 0x00F7,
+    0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x01B0, 0x20AB, 0x00FF
+};
+
+#endif
+
+
+#if !_TBLDEF || !_USE_LFN
+#error This file is not needed in current configuration. Remove from the project.
+#endif
+
+
+WCHAR ff_convert (  /* Converted character, Returns zero on error */
+    WCHAR   src,    /* Character code to be converted */
+    UINT    dir     /* 0: Unicode to OEMCP, 1: OEMCP to Unicode */
+)
+{
+    WCHAR c;
+
+
+    if (src < 0x80) {   /* ASCII */
+        c = src;
+
+    } else {
+        if (dir) {      /* OEMCP to Unicode */
+            c = (src >= 0x100) ? 0 : Tbl[src - 0x80];
+
+        } else {        /* Unicode to OEMCP */
+            for (c = 0; c < 0x80; c++) {
+                if (src == Tbl[c]) break;
+            }
+            c = (c + 0x80) & 0xFF;
+        }
+    }
+
+    return c;
+}
+
+
+WCHAR ff_wtoupper ( /* Upper converted character */
+    WCHAR chr       /* Input character */
+)
+{
+    static const WCHAR tbl_lower[] = { 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0xA1, 0x00A2, 0x00A3, 0x00A5, 0x00AC, 0x00AF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0x0FF, 0x101, 0x103, 0x105, 0x107, 0x109, 0x10B, 0x10D, 0x10F, 0x111, 0x113, 0x115, 0x117, 0x119, 0x11B, 0x11D, 0x11F, 0x121, 0x123, 0x125, 0x127, 0x129, 0x12B, 0x12D, 0x12F, 0x131, 0x133, 0x135, 0x137, 0x13A, 0x13C, 0x13E, 0x140, 0x142, 0x144, 0x146, 0x148, 0x14B, 0x14D, 0x14F, 0x151, 0x153, 0x155, 0x157, 0x159, 0x15B, 0x15D, 0x15F, 0x161, 0x163, 0x165, 0x167, 0x169, 0x16B, 0x16D, 0x16F, 0x171, 0x173, 0x175, 0x177, 0x17A, 0x17C, 0x17E, 0x192, 0x3B1, 0x3B2, 0x3B3, 0x3B4, 0x3B5, 0x3B6, 0x3B7, 0x3B8, 0x3B9, 0x3BA, 0x3BB, 0x3BC, 0x3BD, 0x3BE, 0x3BF, 0x3C0, 0x3C1, 0x3C3, 0x3C4, 0x3C5, 0x3C6, 0x3C7, 0x3C8, 0x3C9, 0x3CA, 0x430, 0x431, 0x432, 0x433, 0x434, 0x435, 0x436, 0x437, 0x438, 0x439, 0x43A, 0x43B, 0x43C, 0x43D, 0x43E, 0x43F, 0x440, 0x441, 0x442, 0x443, 0x444, 0x445, 0x446, 0x447, 0x448, 0x449, 0x44A, 0x44B, 0x44C, 0x44D, 0x44E, 0x44F, 0x451, 0x452, 0x453, 0x454, 0x455, 0x456, 0x457, 0x458, 0x459, 0x45A, 0x45B, 0x45C, 0x45E, 0x45F, 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F, 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, 0xFF58, 0xFF59, 0xFF5A, 0 };
+    static const WCHAR tbl_upper[] = { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x21, 0xFFE0, 0xFFE1, 0xFFE5, 0xFFE2, 0xFFE3, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0x178, 0x100, 0x102, 0x104, 0x106, 0x108, 0x10A, 0x10C, 0x10E, 0x110, 0x112, 0x114, 0x116, 0x118, 0x11A, 0x11C, 0x11E, 0x120, 0x122, 0x124, 0x126, 0x128, 0x12A, 0x12C, 0x12E, 0x130, 0x132, 0x134, 0x136, 0x139, 0x13B, 0x13D, 0x13F, 0x141, 0x143, 0x145, 0x147, 0x14A, 0x14C, 0x14E, 0x150, 0x152, 0x154, 0x156, 0x158, 0x15A, 0x15C, 0x15E, 0x160, 0x162, 0x164, 0x166, 0x168, 0x16A, 0x16C, 0x16E, 0x170, 0x172, 0x174, 0x176, 0x179, 0x17B, 0x17D, 0x191, 0x391, 0x392, 0x393, 0x394, 0x395, 0x396, 0x397, 0x398, 0x399, 0x39A, 0x39B, 0x39C, 0x39D, 0x39E, 0x39F, 0x3A0, 0x3A1, 0x3A3, 0x3A4, 0x3A5, 0x3A6, 0x3A7, 0x3A8, 0x3A9, 0x3AA, 0x410, 0x411, 0x412, 0x413, 0x414, 0x415, 0x416, 0x417, 0x418, 0x419, 0x41A, 0x41B, 0x41C, 0x41D, 0x41E, 0x41F, 0x420, 0x421, 0x422, 0x423, 0x424, 0x425, 0x426, 0x427, 0x428, 0x429, 0x42A, 0x42B, 0x42C, 0x42D, 0x42E, 0x42F, 0x401, 0x402, 0x403, 0x404, 0x405, 0x406, 0x407, 0x408, 0x409, 0x40A, 0x40B, 0x40C, 0x40E, 0x40F, 0x2160, 0x2161, 0x2162, 0x2163, 0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0x216A, 0x216B, 0x216C, 0x216D, 0x216E, 0x216F, 0xFF21, 0xFF22, 0xFF23, 0xFF24, 0xFF25, 0xFF26, 0xFF27, 0xFF28, 0xFF29, 0xFF2A, 0xFF2B, 0xFF2C, 0xFF2D, 0xFF2E, 0xFF2F, 0xFF30, 0xFF31, 0xFF32, 0xFF33, 0xFF34, 0xFF35, 0xFF36, 0xFF37, 0xFF38, 0xFF39, 0xFF3A, 0 };
+    int i;
+
+
+    for (i = 0; tbl_lower[i] && chr != tbl_lower[i]; i++) ;
+
+    return tbl_lower[i] ? tbl_upper[i] : chr;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/FATFileSystem/ChaN/diskio.cpp	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,104 @@
+/*-----------------------------------------------------------------------*/
+/* Low level disk I/O module skeleton for FatFs     (C)ChaN, 2007        */
+/*-----------------------------------------------------------------------*/
+/* This is a stub disk I/O module that acts as front end of the existing */
+/* disk I/O modules and attach it to FatFs module with common interface. */
+/*-----------------------------------------------------------------------*/
+#include "ffconf.h"
+#include "diskio.h"
+
+#include "mbed_debug.h"
+#include "FATFileSystem.h"
+
+using namespace mbed;
+
+DSTATUS disk_initialize (
+    BYTE drv                /* Physical drive nmuber (0..) */
+) 
+{
+    debug_if(FFS_DBG, "disk_initialize on drv [%d]\n", drv);
+    return (DSTATUS)FATFileSystem::_ffs[drv]->disk_initialize();
+}
+
+DSTATUS disk_status (
+    BYTE drv        /* Physical drive nmuber (0..) */
+) 
+{
+    debug_if(FFS_DBG, "disk_status on drv [%d]\n", drv);
+    return (DSTATUS)FATFileSystem::_ffs[drv]->disk_status();
+}
+
+DRESULT disk_read (
+    BYTE drv,        /* Physical drive nmuber (0..) */
+    BYTE *buff,        /* Data buffer to store read data */
+    DWORD sector,    /* Sector address (LBA) */
+    BYTE count        /* Number of sectors to read (1..255) */
+)
+{
+    debug_if(FFS_DBG, "disk_read(sector %d, count %d) on drv [%d]\n", sector, count, drv);
+    for(DWORD s=sector; s<sector+count; s++) {
+        debug_if(FFS_DBG, " disk_read(sector %d)\n", s);
+        int res = FATFileSystem::_ffs[drv]->disk_read((uint8_t*)buff, s);
+        if(res) {
+            return RES_PARERR;
+        }
+        buff += 512;
+    }
+    return RES_OK;
+}
+
+#if _READONLY == 0
+DRESULT disk_write (
+    BYTE drv,            /* Physical drive nmuber (0..) */
+    const BYTE *buff,    /* Data to be written */
+    DWORD sector,        /* Sector address (LBA) */
+    BYTE count            /* Number of sectors to write (1..255) */
+)
+{
+    debug_if(FFS_DBG, "disk_write(sector %d, count %d) on drv [%d]\n", sector, count, drv);
+    for(DWORD s = sector; s < sector + count; s++) {
+        debug_if(FFS_DBG, " disk_write(sector %d)\n", s);
+        int res = FATFileSystem::_ffs[drv]->disk_write((uint8_t*)buff, s);
+        if(res) {
+            return RES_PARERR;
+        }
+        buff += 512;
+    }
+    return RES_OK;
+}
+#endif /* _READONLY */
+
+DRESULT disk_ioctl (
+    BYTE drv,        /* Physical drive nmuber (0..) */
+    BYTE ctrl,        /* Control code */
+    void *buff        /* Buffer to send/receive control data */
+)
+{
+    debug_if(FFS_DBG, "disk_ioctl(%d)\n", ctrl);
+    switch(ctrl) {
+        case CTRL_SYNC:
+            if(FATFileSystem::_ffs[drv] == NULL) {
+                return RES_NOTRDY;
+            } else if(FATFileSystem::_ffs[drv]->disk_sync()) {
+                return RES_ERROR;
+            }
+            return RES_OK;
+        case GET_SECTOR_COUNT:
+            if(FATFileSystem::_ffs[drv] == NULL) {
+                return RES_NOTRDY;
+            } else {
+                DWORD res = FATFileSystem::_ffs[drv]->disk_sectors();
+                if(res > 0) {
+                    *((DWORD*)buff) = res; // minimum allowed
+                    return RES_OK;
+                } else {
+                    return RES_ERROR;
+                }
+            }
+        case GET_BLOCK_SIZE:
+            *((DWORD*)buff) = 1; // default when not known
+            return RES_OK;
+
+    }
+    return RES_PARERR;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/FATFileSystem/ChaN/diskio.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,76 @@
+//-----------------------------------------------------------------------
+//  Low level disk interface modlue include file
+//-----------------------------------------------------------------------
+
+#ifndef _DISKIO
+
+#define _READONLY    0   // 1: Remove write functions
+#define _USE_IOCTL   1   // 1: Use disk_ioctl fucntion
+
+#include "integer.h"
+
+
+// Status of Disk Functions
+typedef BYTE    DSTATUS;
+
+// Results of Disk Functions
+typedef enum {
+    RES_OK = 0, // 0: Successful
+    RES_ERROR,  // 1: R/W Error
+    RES_WRPRT,  // 2: Write Protected
+    RES_NOTRDY, // 3: Not Ready
+    RES_PARERR  // 4: Invalid Parameter
+} DRESULT;
+
+
+// Prototypes for disk control functions
+
+int assign_drives (int, int);
+DSTATUS disk_initialize (BYTE);
+DSTATUS disk_status (BYTE);
+DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE);
+#if    _READONLY == 0
+DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE);
+#endif
+DRESULT disk_ioctl (BYTE, BYTE, void*);
+
+
+
+// Disk Status Bits (DSTATUS)
+#define STA_NOINIT  0x01    // Drive not initialized
+#define STA_NODISK  0x02    // No medium in the drive
+#define STA_PROTECT 0x04    // Write protected
+
+
+// Command code for disk_ioctrl fucntion
+
+// Generic command (defined for FatFs)
+#define CTRL_SYNC           0    // Flush disk cache (for write functions)
+#define GET_SECTOR_COUNT    1    // Get media size (for only f_mkfs())
+#define GET_SECTOR_SIZE     2    // Get sector size (for multiple sector size (_MAX_SS >= 1024))
+#define GET_BLOCK_SIZE      3    // Get erase block size (for only f_mkfs())
+#define CTRL_ERASE_SECTOR   4    // Force erased a block of sectors (for only _USE_ERASE)
+
+// Generic command
+#define CTRL_POWER          5    // Get/Set power status
+#define CTRL_LOCK           6    // Lock/Unlock media removal
+#define CTRL_EJECT          7    // Eject media
+
+// MMC/SDC specific ioctl command
+#define MMC_GET_TYPE        10    // Get card type
+#define MMC_GET_CSD         11    // Get CSD
+#define MMC_GET_CID         12    // Get CID
+#define MMC_GET_OCR         13    // Get OCR
+#define MMC_GET_SDSTAT      14    // Get SD status
+
+// ATA/CF specific ioctl command
+#define ATA_GET_REV         20    // Get F/W revision
+#define ATA_GET_MODEL       21    // Get model name
+#define ATA_GET_SN          22    // Get serial number
+
+// NAND specific ioctl command
+#define NAND_FORMAT         30    // Create physical format
+
+
+#define _DISKIO
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/FATFileSystem/ChaN/ff.cpp	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,4139 @@
+/*----------------------------------------------------------------------------/
+/  FatFs - FAT file system module  R0.09a                 (C)ChaN, 2012
+/-----------------------------------------------------------------------------/
+/ FatFs module is a generic FAT file system module for small embedded systems.
+/ This is a free software that opened for education, research and commercial
+/ developments under license policy of following terms.
+/
+/  Copyright (C) 2012, ChaN, all right reserved.
+/
+/ * The FatFs module is a free software and there is NO WARRANTY.
+/ * No restriction on use. You can use, modify and redistribute it for
+/   personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
+/ * Redistributions of source code must retain the above copyright notice.
+/
+/-----------------------------------------------------------------------------/
+/ Feb 26,'06 R0.00  Prototype.
+/
+/ Apr 29,'06 R0.01  First stable version.
+/
+/ Jun 01,'06 R0.02  Added FAT12 support.
+/                   Removed unbuffered mode.
+/                   Fixed a problem on small (<32M) partition.
+/ Jun 10,'06 R0.02a Added a configuration option (_FS_MINIMUM).
+/
+/ Sep 22,'06 R0.03  Added f_rename().
+/                   Changed option _FS_MINIMUM to _FS_MINIMIZE.
+/ Dec 11,'06 R0.03a Improved cluster scan algorithm to write files fast.
+/                   Fixed f_mkdir() creates incorrect directory on FAT32.
+/
+/ Feb 04,'07 R0.04  Supported multiple drive system.
+/                   Changed some interfaces for multiple drive system.
+/                   Changed f_mountdrv() to f_mount().
+/                   Added f_mkfs().
+/ Apr 01,'07 R0.04a Supported multiple partitions on a physical drive.
+/                   Added a capability of extending file size to f_lseek().
+/                   Added minimization level 3.
+/                   Fixed an endian sensitive code in f_mkfs().
+/ May 05,'07 R0.04b Added a configuration option _USE_NTFLAG.
+/                   Added FSInfo support.
+/                   Fixed DBCS name can result FR_INVALID_NAME.
+/                   Fixed short seek (<= csize) collapses the file object.
+/
+/ Aug 25,'07 R0.05  Changed arguments of f_read(), f_write() and f_mkfs().
+/                   Fixed f_mkfs() on FAT32 creates incorrect FSInfo.
+/                   Fixed f_mkdir() on FAT32 creates incorrect directory.
+/ Feb 03,'08 R0.05a Added f_truncate() and f_utime().
+/                   Fixed off by one error at FAT sub-type determination.
+/                   Fixed btr in f_read() can be mistruncated.
+/                   Fixed cached sector is not flushed when create and close without write.
+/
+/ Apr 01,'08 R0.06  Added fputc(), fputs(), fprintf() and fgets().
+/                   Improved performance of f_lseek() on moving to the same or following cluster.
+/
+/ Apr 01,'09 R0.07  Merged Tiny-FatFs as a configuration option. (_FS_TINY)
+/                   Added long file name feature.
+/                   Added multiple code page feature.
+/                   Added re-entrancy for multitask operation.
+/                   Added auto cluster size selection to f_mkfs().
+/                   Added rewind option to f_readdir().
+/                   Changed result code of critical errors.
+/                   Renamed string functions to avoid name collision.
+/ Apr 14,'09 R0.07a Separated out OS dependent code on reentrant cfg.
+/                   Added multiple sector size feature.
+/ Jun 21,'09 R0.07c Fixed f_unlink() can return FR_OK on error.
+/                   Fixed wrong cache control in f_lseek().
+/                   Added relative path feature.
+/                   Added f_chdir() and f_chdrive().
+/                   Added proper case conversion to extended char.
+/ Nov 03,'09 R0.07e Separated out configuration options from ff.h to ffconf.h.
+/                   Fixed f_unlink() fails to remove a sub-dir on _FS_RPATH.
+/                   Fixed name matching error on the 13 char boundary.
+/                   Added a configuration option, _LFN_UNICODE.
+/                   Changed f_readdir() to return the SFN with always upper case on non-LFN cfg.
+/
+/ May 15,'10 R0.08  Added a memory configuration option. (_USE_LFN = 3)
+/                   Added file lock feature. (_FS_SHARE)
+/                   Added fast seek feature. (_USE_FASTSEEK)
+/                   Changed some types on the API, XCHAR->TCHAR.
+/                   Changed fname member in the FILINFO structure on Unicode cfg.
+/                   String functions support UTF-8 encoding files on Unicode cfg.
+/ Aug 16,'10 R0.08a Added f_getcwd(). (_FS_RPATH = 2)
+/                   Added sector erase feature. (_USE_ERASE)
+/                   Moved file lock semaphore table from fs object to the bss.
+/                   Fixed a wrong directory entry is created on non-LFN cfg when the given name contains ';'.
+/                   Fixed f_mkfs() creates wrong FAT32 volume.
+/ Jan 15,'11 R0.08b Fast seek feature is also applied to f_read() and f_write().
+/                   f_lseek() reports required table size on creating CLMP.
+/                   Extended format syntax of f_printf function.
+/                   Ignores duplicated directory separators in given path name.
+/
+/ Sep 06,'11 R0.09  f_mkfs() supports multiple partition to finish the multiple partition feature.
+/                   Added f_fdisk(). (_MULTI_PARTITION = 2)
+/ Aug 27,'12 R0.09a Fixed assertion failure due to OS/2 EA on FAT12/16 volume.
+/                   Changed f_open() and f_opendir reject null object pointer to avoid crash.
+/                   Changed option name _FS_SHARE to _FS_LOCK.
+/---------------------------------------------------------------------------*/
+
+#include "ff.h"         /* FatFs configurations and declarations */
+#include "diskio.h"     /* Declarations of low level disk I/O functions */
+
+
+/*--------------------------------------------------------------------------
+
+   Module Private Definitions
+
+---------------------------------------------------------------------------*/
+
+#if _FATFS != 4004  /* Revision ID */
+#error Wrong include file (ff.h).
+#endif
+
+
+/* Definitions on sector size */
+#if _MAX_SS != 512 && _MAX_SS != 1024 && _MAX_SS != 2048 && _MAX_SS != 4096
+#error Wrong sector size.
+#endif
+#if _MAX_SS != 512
+#define SS(fs)  ((fs)->ssize)   /* Variable sector size */
+#else
+#define SS(fs)  512U            /* Fixed sector size */
+#endif
+
+
+/* Reentrancy related */
+#if _FS_REENTRANT
+#if _USE_LFN == 1
+#error Static LFN work area must not be used in re-entrant configuration.
+#endif
+#define ENTER_FF(fs)        { if (!lock_fs(fs)) return FR_TIMEOUT; }
+#define LEAVE_FF(fs, res)   { unlock_fs(fs, res); return res; }
+#else
+#define ENTER_FF(fs)
+#define LEAVE_FF(fs, res)   return res
+#endif
+
+#define ABORT(fs, res)      { fp->flag |= FA__ERROR; LEAVE_FF(fs, res); }
+
+
+/* File access control feature */
+#if _FS_LOCK
+#if _FS_READONLY
+#error _FS_LOCK must be 0 on read-only cfg.
+#endif
+typedef struct {
+    FATFS *fs;              /* File ID 1, volume (NULL:blank entry) */
+    DWORD clu;              /* File ID 2, directory */
+    WORD idx;               /* File ID 3, directory index */
+    WORD ctr;               /* File open counter, 0:none, 0x01..0xFF:read open count, 0x100:write mode */
+} FILESEM;
+#endif
+
+
+
+/* DBCS code ranges and SBCS extend char conversion table */
+
+#if _CODE_PAGE == 932   /* Japanese Shift-JIS */
+#define _DF1S   0x81    /* DBC 1st byte range 1 start */
+#define _DF1E   0x9F    /* DBC 1st byte range 1 end */
+#define _DF2S   0xE0    /* DBC 1st byte range 2 start */
+#define _DF2E   0xFC    /* DBC 1st byte range 2 end */
+#define _DS1S   0x40    /* DBC 2nd byte range 1 start */
+#define _DS1E   0x7E    /* DBC 2nd byte range 1 end */
+#define _DS2S   0x80    /* DBC 2nd byte range 2 start */
+#define _DS2E   0xFC    /* DBC 2nd byte range 2 end */
+
+#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */
+#define _DF1S   0x81
+#define _DF1E   0xFE
+#define _DS1S   0x40
+#define _DS1E   0x7E
+#define _DS2S   0x80
+#define _DS2E   0xFE
+
+#elif _CODE_PAGE == 949 /* Korean */
+#define _DF1S   0x81
+#define _DF1E   0xFE
+#define _DS1S   0x41
+#define _DS1E   0x5A
+#define _DS2S   0x61
+#define _DS2E   0x7A
+#define _DS3S   0x81
+#define _DS3E   0xFE
+
+#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */
+#define _DF1S   0x81
+#define _DF1E   0xFE
+#define _DS1S   0x40
+#define _DS1E   0x7E
+#define _DS2S   0xA1
+#define _DS2E   0xFE
+
+#elif _CODE_PAGE == 437 /* U.S. (OEM) */
+#define _DF1S   0
+#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F,0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+                0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 720 /* Arabic (OEM) */
+#define _DF1S   0
+#define _EXCVT {0x80,0x81,0x45,0x41,0x84,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x49,0x49,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+                0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 737 /* Greek (OEM) */
+#define _DF1S   0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \
+                0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xE7,0xE8,0xF1,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 775 /* Baltic (OEM) */
+#define _DF1S   0
+#define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
+                0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 850 /* Multilingual Latin 1 (OEM) */
+#define _DF1S   0
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
+                0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 852 /* Latin 2 (OEM) */
+#define _DF1S   0
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F,0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0x9F, \
+                0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF}
+
+#elif _CODE_PAGE == 855 /* Cyrillic (OEM) */
+#define _DF1S   0
+#define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F,0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \
+                0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \
+                0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 857 /* Turkish (OEM) */
+#define _DF1S   0
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x98,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \
+                0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0x59,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 858 /* Multilingual Latin 1 + Euro (OEM) */
+#define _DF1S   0
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
+                0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 862 /* Hebrew (OEM) */
+#define _DF1S   0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+                0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 866 /* Russian (OEM) */
+#define _DF1S   0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+                0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0x90,0x91,0x92,0x93,0x9d,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 874 /* Thai (OEM, Windows) */
+#define _DF1S   0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+                0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 1250 /* Central Europe (Windows) */
+#define _DF1S   0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \
+                0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xA3,0xB4,0xB5,0xB6,0xB7,0xB8,0xA5,0xAA,0xBB,0xBC,0xBD,0xBC,0xAF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF}
+
+#elif _CODE_PAGE == 1251 /* Cyrillic (Windows) */
+#define _DF1S   0
+#define _EXCVT {0x80,0x81,0x82,0x82,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x80,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \
+                0xA0,0xA2,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB2,0xA5,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xA3,0xBD,0xBD,0xAF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF}
+
+#elif _CODE_PAGE == 1252 /* Latin 1 (Windows) */
+#define _DF1S   0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0xAd,0x9B,0x8C,0x9D,0xAE,0x9F, \
+                0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F}
+
+#elif _CODE_PAGE == 1253 /* Greek (Windows) */
+#define _DF1S   0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+                0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xA2,0xB8,0xB9,0xBA, \
+                0xE0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xFB,0xBC,0xFD,0xBF,0xFF}
+
+#elif _CODE_PAGE == 1254 /* Turkish (Windows) */
+#define _DF1S   0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x9D,0x9E,0x9F, \
+                0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F}
+
+#elif _CODE_PAGE == 1255 /* Hebrew (Windows) */
+#define _DF1S   0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+                0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 1256 /* Arabic (Windows) */
+#define _DF1S   0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x8C,0x9D,0x9E,0x9F, \
+                0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0x41,0xE1,0x41,0xE3,0xE4,0xE5,0xE6,0x43,0x45,0x45,0x45,0x45,0xEC,0xED,0x49,0x49,0xF0,0xF1,0xF2,0xF3,0x4F,0xF5,0xF6,0xF7,0xF8,0x55,0xFA,0x55,0x55,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 1257 /* Baltic (Windows) */
+#define _DF1S   0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+                0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xBC,0xBD,0xBE,0xAF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF}
+
+#elif _CODE_PAGE == 1258 /* Vietnam (OEM, Windows) */
+#define _DF1S   0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0xAC,0x9D,0x9E,0x9F, \
+                0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xEC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xFE,0x9F}
+
+#elif _CODE_PAGE == 1   /* ASCII (for only non-LFN cfg) */
+#if _USE_LFN
+#error Cannot use LFN feature without valid code page.
+#endif
+#define _DF1S   0
+
+#else
+#error Unknown code page
+
+#endif
+
+
+/* Character code support macros */
+#define IsUpper(c)  (((c)>='A')&&((c)<='Z'))
+#define IsLower(c)  (((c)>='a')&&((c)<='z'))
+#define IsDigit(c)  (((c)>='0')&&((c)<='9'))
+
+#if _DF1S       /* Code page is DBCS */
+
+#ifdef _DF2S    /* Two 1st byte areas */
+#define IsDBCS1(c)  (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E))
+#else           /* One 1st byte area */
+#define IsDBCS1(c)  ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E)
+#endif
+
+#ifdef _DS3S    /* Three 2nd byte areas */
+#define IsDBCS2(c)  (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E))
+#else           /* Two 2nd byte areas */
+#define IsDBCS2(c)  (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E))
+#endif
+
+#else           /* Code page is SBCS */
+
+#define IsDBCS1(c)  0
+#define IsDBCS2(c)  0
+
+#endif /* _DF1S */
+
+
+/* Name status flags */
+#define NS          11      /* Index of name status byte in fn[] */
+#define NS_LOSS     0x01    /* Out of 8.3 format */
+#define NS_LFN      0x02    /* Force to create LFN entry */
+#define NS_LAST     0x04    /* Last segment */
+#define NS_BODY     0x08    /* Lower case flag (body) */
+#define NS_EXT      0x10    /* Lower case flag (ext) */
+#define NS_DOT      0x20    /* Dot entry */
+
+
+/* FAT sub-type boundaries */
+/* Note that the FAT spec by Microsoft says 4085 but Windows works with 4087! */
+#define MIN_FAT16   4086    /* Minimum number of clusters for FAT16 */
+#define MIN_FAT32   65526   /* Minimum number of clusters for FAT32 */
+
+
+/* FatFs refers the members in the FAT structures as byte array instead of
+/ structure member because the structure is not binary compatible between
+/ different platforms */
+
+#define BS_jmpBoot          0   /* Jump instruction (3) */
+#define BS_OEMName          3   /* OEM name (8) */
+#define BPB_BytsPerSec      11  /* Sector size [byte] (2) */
+#define BPB_SecPerClus      13  /* Cluster size [sector] (1) */
+#define BPB_RsvdSecCnt      14  /* Size of reserved area [sector] (2) */
+#define BPB_NumFATs         16  /* Number of FAT copies (1) */
+#define BPB_RootEntCnt      17  /* Number of root dir entries for FAT12/16 (2) */
+#define BPB_TotSec16        19  /* Volume size [sector] (2) */
+#define BPB_Media           21  /* Media descriptor (1) */
+#define BPB_FATSz16         22  /* FAT size [sector] (2) */
+#define BPB_SecPerTrk       24  /* Track size [sector] (2) */
+#define BPB_NumHeads        26  /* Number of heads (2) */
+#define BPB_HiddSec         28  /* Number of special hidden sectors (4) */
+#define BPB_TotSec32        32  /* Volume size [sector] (4) */
+#define BS_DrvNum           36  /* Physical drive number (2) */
+#define BS_BootSig          38  /* Extended boot signature (1) */
+#define BS_VolID            39  /* Volume serial number (4) */
+#define BS_VolLab           43  /* Volume label (8) */
+#define BS_FilSysType       54  /* File system type (1) */
+#define BPB_FATSz32         36  /* FAT size [sector] (4) */
+#define BPB_ExtFlags        40  /* Extended flags (2) */
+#define BPB_FSVer           42  /* File system version (2) */
+#define BPB_RootClus        44  /* Root dir first cluster (4) */
+#define BPB_FSInfo          48  /* Offset of FSInfo sector (2) */
+#define BPB_BkBootSec       50  /* Offset of backup boot sector (2) */
+#define BS_DrvNum32         64  /* Physical drive number (2) */
+#define BS_BootSig32        66  /* Extended boot signature (1) */
+#define BS_VolID32          67  /* Volume serial number (4) */
+#define BS_VolLab32         71  /* Volume label (8) */
+#define BS_FilSysType32     82  /* File system type (1) */
+#define FSI_LeadSig         0   /* FSI: Leading signature (4) */
+#define FSI_StrucSig        484 /* FSI: Structure signature (4) */
+#define FSI_Free_Count      488 /* FSI: Number of free clusters (4) */
+#define FSI_Nxt_Free        492 /* FSI: Last allocated cluster (4) */
+#define MBR_Table           446 /* MBR: Partition table offset (2) */
+#define SZ_PTE              16  /* MBR: Size of a partition table entry */
+#define BS_55AA             510 /* Boot sector signature (2) */
+
+#define DIR_Name            0   /* Short file name (11) */
+#define DIR_Attr            11  /* Attribute (1) */
+#define DIR_NTres           12  /* NT flag (1) */
+#define DIR_CrtTimeTenth    13  /* Created time sub-second (1) */
+#define DIR_CrtTime         14  /* Created time (2) */
+#define DIR_CrtDate         16  /* Created date (2) */
+#define DIR_LstAccDate      18  /* Last accessed date (2) */
+#define DIR_FstClusHI       20  /* Higher 16-bit of first cluster (2) */
+#define DIR_WrtTime         22  /* Modified time (2) */
+#define DIR_WrtDate         24  /* Modified date (2) */
+#define DIR_FstClusLO       26  /* Lower 16-bit of first cluster (2) */
+#define DIR_FileSize        28  /* File size (4) */
+#define LDIR_Ord            0   /* LFN entry order and LLE flag (1) */
+#define LDIR_Attr           11  /* LFN attribute (1) */
+#define LDIR_Type           12  /* LFN type (1) */
+#define LDIR_Chksum         13  /* Sum of corresponding SFN entry */
+#define LDIR_FstClusLO      26  /* Filled by zero (0) */
+#define SZ_DIR              32      /* Size of a directory entry */
+#define LLE                 0x40    /* Last long entry flag in LDIR_Ord */
+#define DDE                 0xE5    /* Deleted directory entry mark in DIR_Name[0] */
+#define NDDE                0x05    /* Replacement of the character collides with DDE */
+
+
+/*------------------------------------------------------------*/
+/* Module private work area                                   */
+/*------------------------------------------------------------*/
+/* Note that uninitialized variables with static duration are
+/  zeroed/nulled at start-up. If not, the compiler or start-up
+/  routine is out of ANSI-C standard.
+*/
+
+#if _VOLUMES
+static
+FATFS *FatFs[_VOLUMES]; /* Pointer to the file system objects (logical drives) */
+#else
+#error Number of volumes must not be 0.
+#endif
+
+static
+WORD Fsid;              /* File system mount ID */
+
+#if _FS_RPATH
+static
+BYTE CurrVol;           /* Current drive */
+#endif
+
+#if _FS_LOCK
+static
+FILESEM Files[_FS_LOCK];    /* File lock semaphores */
+#endif
+
+#if _USE_LFN == 0           /* No LFN feature */
+#define DEF_NAMEBUF         BYTE sfn[12]
+#define INIT_BUF(dobj)      (dobj).fn = sfn
+#define FREE_BUF()
+
+#elif _USE_LFN == 1         /* LFN feature with static working buffer */
+static WCHAR LfnBuf[_MAX_LFN+1];
+#define DEF_NAMEBUF         BYTE sfn[12]
+#define INIT_BUF(dobj)      { (dobj).fn = sfn; (dobj).lfn = LfnBuf; }
+#define FREE_BUF()
+
+#elif _USE_LFN == 2         /* LFN feature with dynamic working buffer on the stack */
+#define DEF_NAMEBUF         BYTE sfn[12]; WCHAR lbuf[_MAX_LFN+1]
+#define INIT_BUF(dobj)      { (dobj).fn = sfn; (dobj).lfn = lbuf; }
+#define FREE_BUF()
+
+#elif _USE_LFN == 3         /* LFN feature with dynamic working buffer on the heap */
+#define DEF_NAMEBUF         BYTE sfn[12]; WCHAR *lfn
+#define INIT_BUF(dobj)      { lfn = ff_memalloc((_MAX_LFN + 1) * 2); \
+                              if (!lfn) LEAVE_FF((dobj).fs, FR_NOT_ENOUGH_CORE); \
+                              (dobj).lfn = lfn; (dobj).fn = sfn; }
+#define FREE_BUF()          ff_memfree(lfn)
+
+#else
+#error Wrong LFN configuration.
+#endif
+
+
+
+
+/*--------------------------------------------------------------------------
+
+   Module Private Functions
+
+---------------------------------------------------------------------------*/
+
+
+/*-----------------------------------------------------------------------*/
+/* String functions                                                      */
+/*-----------------------------------------------------------------------*/
+
+/* Copy memory to memory */
+static
+void mem_cpy (void* dst, const void* src, UINT cnt) {
+    BYTE *d = (BYTE*)dst;
+    const BYTE *s = (const BYTE*)src;
+
+#if _WORD_ACCESS == 1
+    while (cnt >= sizeof (int)) {
+        *(int*)d = *(int*)s;
+        d += sizeof (int); s += sizeof (int);
+        cnt -= sizeof (int);
+    }
+#endif
+    while (cnt--)
+        *d++ = *s++;
+}
+
+/* Fill memory */
+static
+void mem_set (void* dst, int val, UINT cnt) {
+    BYTE *d = (BYTE*)dst;
+
+    while (cnt--)
+        *d++ = (BYTE)val;
+}
+
+/* Compare memory to memory */
+static
+int mem_cmp (const void* dst, const void* src, UINT cnt) {
+    const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src;
+    int r = 0;
+
+    while (cnt-- && (r = *d++ - *s++) == 0) ;
+    return r;
+}
+
+/* Check if chr is contained in the string */
+static
+int chk_chr (const char* str, int chr) {
+    while (*str && *str != chr) str++;
+    return *str;
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Request/Release grant to access the volume                            */
+/*-----------------------------------------------------------------------*/
+#if _FS_REENTRANT
+
+static
+int lock_fs (
+    FATFS *fs       /* File system object */
+)
+{
+    return ff_req_grant(fs->sobj);
+}
+
+
+static
+void unlock_fs (
+    FATFS *fs,      /* File system object */
+    FRESULT res     /* Result code to be returned */
+)
+{
+    if (fs &&
+        res != FR_NOT_ENABLED &&
+        res != FR_INVALID_DRIVE &&
+        res != FR_INVALID_OBJECT &&
+        res != FR_TIMEOUT) {
+        ff_rel_grant(fs->sobj);
+    }
+}
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* File lock control functions                                           */
+/*-----------------------------------------------------------------------*/
+#if _FS_LOCK
+
+static
+FRESULT chk_lock (  /* Check if the file can be accessed */
+    DIR* dj,        /* Directory object pointing the file to be checked */
+    int acc         /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */
+)
+{
+    UINT i, be;
+
+    /* Search file semaphore table */
+    for (i = be = 0; i < _FS_LOCK; i++) {
+        if (Files[i].fs) {  /* Existing entry */
+            if (Files[i].fs == dj->fs &&        /* Check if the file matched with an open file */
+                Files[i].clu == dj->sclust &&
+                Files[i].idx == dj->index) break;
+        } else {            /* Blank entry */
+            be++;
+        }
+    }
+    if (i == _FS_LOCK)  /* The file is not opened */
+        return (be || acc == 2) ? FR_OK : FR_TOO_MANY_OPEN_FILES;   /* Is there a blank entry for new file? */
+
+    /* The file has been opened. Reject any open against writing file and all write mode open */
+    return (acc || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK;
+}
+
+
+static
+int enq_lock (void) /* Check if an entry is available for a new file */
+{
+    UINT i;
+
+    for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ;
+    return (i == _FS_LOCK) ? 0 : 1;
+}
+
+
+static
+UINT inc_lock ( /* Increment file open counter and returns its index (0:int error) */
+    DIR* dj,    /* Directory object pointing the file to register or increment */
+    int acc     /* Desired access mode (0:Read, !0:Write) */
+)
+{
+    UINT i;
+
+
+    for (i = 0; i < _FS_LOCK; i++) {    /* Find the file */
+        if (Files[i].fs == dj->fs &&
+            Files[i].clu == dj->sclust &&
+            Files[i].idx == dj->index) break;
+    }
+
+    if (i == _FS_LOCK) {                /* Not opened. Register it as new. */
+        for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ;
+        if (i == _FS_LOCK) return 0;    /* No space to register (int err) */
+        Files[i].fs = dj->fs;
+        Files[i].clu = dj->sclust;
+        Files[i].idx = dj->index;
+        Files[i].ctr = 0;
+    }
+
+    if (acc && Files[i].ctr) return 0;  /* Access violation (int err) */
+
+    Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1;  /* Set semaphore value */
+
+    return i + 1;
+}
+
+
+static
+FRESULT dec_lock (  /* Decrement file open counter */
+    UINT i          /* Semaphore index */
+)
+{
+    WORD n;
+    FRESULT res;
+
+
+    if (--i < _FS_LOCK) {
+        n = Files[i].ctr;
+        if (n == 0x100) n = 0;
+        if (n) n--;
+        Files[i].ctr = n;
+        if (!n) Files[i].fs = 0;
+        res = FR_OK;
+    } else {
+        res = FR_INT_ERR;
+    }
+    return res;
+}
+
+
+static
+void clear_lock (   /* Clear lock entries of the volume */
+    FATFS *fs
+)
+{
+    UINT i;
+
+    for (i = 0; i < _FS_LOCK; i++) {
+        if (Files[i].fs == fs) Files[i].fs = 0;
+    }
+}
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change window offset                                                  */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT move_window (
+    FATFS *fs,      /* File system object */
+    DWORD sector    /* Sector number to make appearance in the fs->win[] */
+)                   /* Move to zero only writes back dirty window */
+{
+    DWORD wsect;
+
+
+    wsect = fs->winsect;
+    if (wsect != sector) {  /* Changed current window */
+#if !_FS_READONLY
+        if (fs->wflag) {    /* Write back dirty window if needed */
+            if (disk_write(fs->drv, fs->win, wsect, 1) != RES_OK)
+                return FR_DISK_ERR;
+            fs->wflag = 0;
+            if (wsect < (fs->fatbase + fs->fsize)) {    /* In FAT area */
+                BYTE nf;
+                for (nf = fs->n_fats; nf > 1; nf--) {   /* Reflect the change to all FAT copies */
+                    wsect += fs->fsize;
+                    disk_write(fs->drv, fs->win, wsect, 1);
+                }
+            }
+        }
+#endif
+        if (sector) {
+            if (disk_read(fs->drv, fs->win, sector, 1) != RES_OK)
+                return FR_DISK_ERR;
+            fs->winsect = sector;
+        }
+    }
+
+    return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Clean-up cached data                                                  */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+FRESULT sync (  /* FR_OK: successful, FR_DISK_ERR: failed */
+    FATFS *fs   /* File system object */
+)
+{
+    FRESULT res;
+
+
+    res = move_window(fs, 0);
+    if (res == FR_OK) {
+        /* Update FSInfo sector if needed */
+        if (fs->fs_type == FS_FAT32 && fs->fsi_flag) {
+            fs->winsect = 0;
+            /* Create FSInfo structure */
+            mem_set(fs->win, 0, 512);
+            ST_WORD(fs->win+BS_55AA, 0xAA55);
+            ST_DWORD(fs->win+FSI_LeadSig, 0x41615252);
+            ST_DWORD(fs->win+FSI_StrucSig, 0x61417272);
+            ST_DWORD(fs->win+FSI_Free_Count, fs->free_clust);
+            ST_DWORD(fs->win+FSI_Nxt_Free, fs->last_clust);
+            /* Write it into the FSInfo sector */
+            disk_write(fs->drv, fs->win, fs->fsi_sector, 1);
+            fs->fsi_flag = 0;
+        }
+        /* Make sure that no pending write process in the physical drive */
+        if (disk_ioctl(fs->drv, CTRL_SYNC, 0) != RES_OK)
+            res = FR_DISK_ERR;
+    }
+
+    return res;
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Get sector# from cluster#                                             */
+/*-----------------------------------------------------------------------*/
+
+
+DWORD clust2sect (  /* !=0: Sector number, 0: Failed - invalid cluster# */
+    FATFS *fs,      /* File system object */
+    DWORD clst      /* Cluster# to be converted */
+)
+{
+    clst -= 2;
+    if (clst >= (fs->n_fatent - 2)) return 0;       /* Invalid cluster# */
+    return clst * fs->csize + fs->database;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT access - Read value of a FAT entry                                */
+/*-----------------------------------------------------------------------*/
+
+
+DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, Else:Cluster status */
+    FATFS *fs,  /* File system object */
+    DWORD clst  /* Cluster# to get the link information */
+)
+{
+    UINT wc, bc;
+    BYTE *p;
+
+
+    if (clst < 2 || clst >= fs->n_fatent)   /* Check range */
+        return 1;
+
+    switch (fs->fs_type) {
+    case FS_FAT12 :
+        bc = (UINT)clst; bc += bc / 2;
+        if (move_window(fs, fs->fatbase + (bc / SS(fs)))) break;
+        wc = fs->win[bc % SS(fs)]; bc++;
+        if (move_window(fs, fs->fatbase + (bc / SS(fs)))) break;
+        wc |= fs->win[bc % SS(fs)] << 8;
+        return (clst & 1) ? (wc >> 4) : (wc & 0xFFF);
+
+    case FS_FAT16 :
+        if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2)))) break;
+        p = &fs->win[clst * 2 % SS(fs)];
+        return LD_WORD(p);
+
+    case FS_FAT32 :
+        if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)))) break;
+        p = &fs->win[clst * 4 % SS(fs)];
+        return LD_DWORD(p) & 0x0FFFFFFF;
+    }
+
+    return 0xFFFFFFFF;  /* An error occurred at the disk I/O layer */
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT access - Change value of a FAT entry                              */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+
+FRESULT put_fat (
+    FATFS *fs,  /* File system object */
+    DWORD clst, /* Cluster# to be changed in range of 2 to fs->n_fatent - 1 */
+    DWORD val   /* New value to mark the cluster */
+)
+{
+    UINT bc;
+    BYTE *p;
+    FRESULT res;
+
+
+    if (clst < 2 || clst >= fs->n_fatent) { /* Check range */
+        res = FR_INT_ERR;
+
+    } else {
+        switch (fs->fs_type) {
+        case FS_FAT12 :
+            bc = (UINT)clst; bc += bc / 2;
+            res = move_window(fs, fs->fatbase + (bc / SS(fs)));
+            if (res != FR_OK) break;
+            p = &fs->win[bc % SS(fs)];
+            *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val;
+            bc++;
+            fs->wflag = 1;
+            res = move_window(fs, fs->fatbase + (bc / SS(fs)));
+            if (res != FR_OK) break;
+            p = &fs->win[bc % SS(fs)];
+            *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F));
+            break;
+
+        case FS_FAT16 :
+            res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2)));
+            if (res != FR_OK) break;
+            p = &fs->win[clst * 2 % SS(fs)];
+            ST_WORD(p, (WORD)val);
+            break;
+
+        case FS_FAT32 :
+            res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)));
+            if (res != FR_OK) break;
+            p = &fs->win[clst * 4 % SS(fs)];
+            val |= LD_DWORD(p) & 0xF0000000;
+            ST_DWORD(p, val);
+            break;
+
+        default :
+            res = FR_INT_ERR;
+        }
+        fs->wflag = 1;
+    }
+
+    return res;
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT handling - Remove a cluster chain                                 */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+FRESULT remove_chain (
+    FATFS *fs,          /* File system object */
+    DWORD clst          /* Cluster# to remove a chain from */
+)
+{
+    FRESULT res;
+    DWORD nxt;
+#if _USE_ERASE
+    DWORD scl = clst, ecl = clst, rt[2];
+#endif
+
+    if (clst < 2 || clst >= fs->n_fatent) { /* Check range */
+        res = FR_INT_ERR;
+
+    } else {
+        res = FR_OK;
+        while (clst < fs->n_fatent) {           /* Not a last link? */
+            nxt = get_fat(fs, clst);            /* Get cluster status */
+            if (nxt == 0) break;                /* Empty cluster? */
+            if (nxt == 1) { res = FR_INT_ERR; break; }  /* Internal error? */
+            if (nxt == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }    /* Disk error? */
+            res = put_fat(fs, clst, 0);         /* Mark the cluster "empty" */
+            if (res != FR_OK) break;
+            if (fs->free_clust != 0xFFFFFFFF) { /* Update FSInfo */
+                fs->free_clust++;
+                fs->fsi_flag = 1;
+            }
+#if _USE_ERASE
+            if (ecl + 1 == nxt) {   /* Is next cluster contiguous? */
+                ecl = nxt;
+            } else {                /* End of contiguous clusters */
+                rt[0] = clust2sect(fs, scl);                    /* Start sector */
+                rt[1] = clust2sect(fs, ecl) + fs->csize - 1;    /* End sector */
+                disk_ioctl(fs->drv, CTRL_ERASE_SECTOR, rt);     /* Erase the block */
+                scl = ecl = nxt;
+            }
+#endif
+            clst = nxt; /* Next cluster */
+        }
+    }
+
+    return res;
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT handling - Stretch or Create a cluster chain                      */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+DWORD create_chain (    /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */
+    FATFS *fs,          /* File system object */
+    DWORD clst          /* Cluster# to stretch. 0 means create a new chain. */
+)
+{
+    DWORD cs, ncl, scl;
+    FRESULT res;
+
+
+    if (clst == 0) {        /* Create a new chain */
+        scl = fs->last_clust;           /* Get suggested start point */
+        if (!scl || scl >= fs->n_fatent) scl = 1;
+    }
+    else {                  /* Stretch the current chain */
+        cs = get_fat(fs, clst);         /* Check the cluster status */
+        if (cs < 2) return 1;           /* It is an invalid cluster */
+        if (cs < fs->n_fatent) return cs;   /* It is already followed by next cluster */
+        scl = clst;
+    }
+
+    ncl = scl;              /* Start cluster */
+    for (;;) {
+        ncl++;                          /* Next cluster */
+        if (ncl >= fs->n_fatent) {      /* Wrap around */
+            ncl = 2;
+            if (ncl > scl) return 0;    /* No free cluster */
+        }
+        cs = get_fat(fs, ncl);          /* Get the cluster status */
+        if (cs == 0) break;             /* Found a free cluster */
+        if (cs == 0xFFFFFFFF || cs == 1)/* An error occurred */
+            return cs;
+        if (ncl == scl) return 0;       /* No free cluster */
+    }
+
+    res = put_fat(fs, ncl, 0x0FFFFFFF); /* Mark the new cluster "last link" */
+    if (res == FR_OK && clst != 0) {
+        res = put_fat(fs, clst, ncl);   /* Link it to the previous one if needed */
+    }
+    if (res == FR_OK) {
+        fs->last_clust = ncl;           /* Update FSINFO */
+        if (fs->free_clust != 0xFFFFFFFF) {
+            fs->free_clust--;
+            fs->fsi_flag = 1;
+        }
+    } else {
+        ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1;
+    }
+
+    return ncl;     /* Return new cluster number or error code */
+}
+#endif /* !_FS_READONLY */
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT handling - Convert offset into cluster with link map table        */
+/*-----------------------------------------------------------------------*/
+
+#if _USE_FASTSEEK
+static
+DWORD clmt_clust (  /* <2:Error, >=2:Cluster number */
+    FIL* fp,        /* Pointer to the file object */
+    DWORD ofs       /* File offset to be converted to cluster# */
+)
+{
+    DWORD cl, ncl, *tbl;
+
+
+    tbl = fp->cltbl + 1;    /* Top of CLMT */
+    cl = ofs / SS(fp->fs) / fp->fs->csize;  /* Cluster order from top of the file */
+    for (;;) {
+        ncl = *tbl++;           /* Number of cluters in the fragment */
+        if (!ncl) return 0;     /* End of table? (error) */
+        if (cl < ncl) break;    /* In this fragment? */
+        cl -= ncl; tbl++;       /* Next fragment */
+    }
+    return cl + *tbl;   /* Return the cluster number */
+}
+#endif  /* _USE_FASTSEEK */
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Set directory index                              */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT dir_sdi (
+    FATFS_DIR *dj,        /* Pointer to directory object */
+    WORD idx        /* Index of directory table */
+)
+{
+    DWORD clst;
+    WORD ic;
+
+
+    dj->index = idx;
+    clst = dj->sclust;
+    if (clst == 1 || clst >= dj->fs->n_fatent)  /* Check start cluster range */
+        return FR_INT_ERR;
+    if (!clst && dj->fs->fs_type == FS_FAT32)   /* Replace cluster# 0 with root cluster# if in FAT32 */
+        clst = dj->fs->dirbase;
+
+    if (clst == 0) {    /* Static table (root-dir in FAT12/16) */
+        dj->clust = clst;
+        if (idx >= dj->fs->n_rootdir)       /* Index is out of range */
+            return FR_INT_ERR;
+        dj->sect = dj->fs->dirbase + idx / (SS(dj->fs) / SZ_DIR);   /* Sector# */
+    }
+    else {              /* Dynamic table (sub-dirs or root-dir in FAT32) */
+        ic = SS(dj->fs) / SZ_DIR * dj->fs->csize;   /* Entries per cluster */
+        while (idx >= ic) { /* Follow cluster chain */
+            clst = get_fat(dj->fs, clst);               /* Get next cluster */
+            if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */
+            if (clst < 2 || clst >= dj->fs->n_fatent)   /* Reached to end of table or int error */
+                return FR_INT_ERR;
+            idx -= ic;
+        }
+        dj->clust = clst;
+        dj->sect = clust2sect(dj->fs, clst) + idx / (SS(dj->fs) / SZ_DIR);  /* Sector# */
+    }
+
+    dj->dir = dj->fs->win + (idx % (SS(dj->fs) / SZ_DIR)) * SZ_DIR; /* Ptr to the entry in the sector */
+
+    return FR_OK;   /* Seek succeeded */
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Move directory table index next                  */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT dir_next (  /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:EOT and could not stretch */
+    FATFS_DIR *dj,        /* Pointer to directory object */
+    int stretch     /* 0: Do not stretch table, 1: Stretch table if needed */
+)
+{
+    DWORD clst;
+    WORD i;
+
+
+    stretch = stretch;      /* To suppress warning on read-only cfg. */
+    i = dj->index + 1;
+    if (!i || !dj->sect)    /* Report EOT when index has reached 65535 */
+        return FR_NO_FILE;
+
+    if (!(i % (SS(dj->fs) / SZ_DIR))) { /* Sector changed? */
+        dj->sect++;                 /* Next sector */
+
+        if (dj->clust == 0) {   /* Static table */
+            if (i >= dj->fs->n_rootdir) /* Report EOT when end of table */
+                return FR_NO_FILE;
+        }
+        else {                  /* Dynamic table */
+            if (((i / (SS(dj->fs) / SZ_DIR)) & (dj->fs->csize - 1)) == 0) { /* Cluster changed? */
+                clst = get_fat(dj->fs, dj->clust);              /* Get next cluster */
+                if (clst <= 1) return FR_INT_ERR;
+                if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
+                if (clst >= dj->fs->n_fatent) {                 /* When it reached end of dynamic table */
+#if !_FS_READONLY
+                    BYTE c;
+                    if (!stretch) return FR_NO_FILE;            /* When do not stretch, report EOT */
+                    clst = create_chain(dj->fs, dj->clust);     /* Stretch cluster chain */
+                    if (clst == 0) return FR_DENIED;            /* No free cluster */
+                    if (clst == 1) return FR_INT_ERR;
+                    if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
+                    /* Clean-up stretched table */
+                    if (move_window(dj->fs, 0)) return FR_DISK_ERR; /* Flush active window */
+                    mem_set(dj->fs->win, 0, SS(dj->fs));            /* Clear window buffer */
+                    dj->fs->winsect = clust2sect(dj->fs, clst); /* Cluster start sector */
+                    for (c = 0; c < dj->fs->csize; c++) {       /* Fill the new cluster with 0 */
+                        dj->fs->wflag = 1;
+                        if (move_window(dj->fs, 0)) return FR_DISK_ERR;
+                        dj->fs->winsect++;
+                    }
+                    dj->fs->winsect -= c;                       /* Rewind window address */
+#else
+                    return FR_NO_FILE;          /* Report EOT */
+#endif
+                }
+                dj->clust = clst;               /* Initialize data for new cluster */
+                dj->sect = clust2sect(dj->fs, clst);
+            }
+        }
+    }
+
+    dj->index = i;
+    dj->dir = dj->fs->win + (i % (SS(dj->fs) / SZ_DIR)) * SZ_DIR;
+
+    return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Load/Store start cluster number                  */
+/*-----------------------------------------------------------------------*/
+
+static
+DWORD ld_clust (
+    FATFS *fs,  /* Pointer to the fs object */
+    BYTE *dir   /* Pointer to the directory entry */
+)
+{
+    DWORD cl;
+
+    cl = LD_WORD(dir+DIR_FstClusLO);
+    if (fs->fs_type == FS_FAT32)
+        cl |= (DWORD)LD_WORD(dir+DIR_FstClusHI) << 16;
+
+    return cl;
+}
+
+
+#if !_FS_READONLY
+static
+void st_clust (
+    BYTE *dir,  /* Pointer to the directory entry */
+    DWORD cl    /* Value to be set */
+)
+{
+    ST_WORD(dir+DIR_FstClusLO, cl);
+    ST_WORD(dir+DIR_FstClusHI, cl >> 16);
+}
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* LFN handling - Test/Pick/Fit an LFN segment from/to directory entry   */
+/*-----------------------------------------------------------------------*/
+#if _USE_LFN
+static
+const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30};  /* Offset of LFN chars in the directory entry */
+
+
+static
+int cmp_lfn (           /* 1:Matched, 0:Not matched */
+    WCHAR *lfnbuf,      /* Pointer to the LFN to be compared */
+    BYTE *dir           /* Pointer to the directory entry containing a part of LFN */
+)
+{
+    UINT i, s;
+    WCHAR wc, uc;
+
+
+    i = ((dir[LDIR_Ord] & ~LLE) - 1) * 13;  /* Get offset in the LFN buffer */
+    s = 0; wc = 1;
+    do {
+        uc = LD_WORD(dir+LfnOfs[s]);    /* Pick an LFN character from the entry */
+        if (wc) {   /* Last char has not been processed */
+            wc = ff_wtoupper(uc);       /* Convert it to upper case */
+            if (i >= _MAX_LFN || wc != ff_wtoupper(lfnbuf[i++]))    /* Compare it */
+                return 0;               /* Not matched */
+        } else {
+            if (uc != 0xFFFF) return 0; /* Check filler */
+        }
+    } while (++s < 13);             /* Repeat until all chars in the entry are checked */
+
+    if ((dir[LDIR_Ord] & LLE) && wc && lfnbuf[i])   /* Last segment matched but different length */
+        return 0;
+
+    return 1;                       /* The part of LFN matched */
+}
+
+
+
+static
+int pick_lfn (          /* 1:Succeeded, 0:Buffer overflow */
+    WCHAR *lfnbuf,      /* Pointer to the Unicode-LFN buffer */
+    BYTE *dir           /* Pointer to the directory entry */
+)
+{
+    UINT i, s;
+    WCHAR wc, uc;
+
+
+    i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13;  /* Offset in the LFN buffer */
+
+    s = 0; wc = 1;
+    do {
+        uc = LD_WORD(dir+LfnOfs[s]);        /* Pick an LFN character from the entry */
+        if (wc) {   /* Last char has not been processed */
+            if (i >= _MAX_LFN) return 0;    /* Buffer overflow? */
+            lfnbuf[i++] = wc = uc;          /* Store it */
+        } else {
+            if (uc != 0xFFFF) return 0;     /* Check filler */
+        }
+    } while (++s < 13);                     /* Read all character in the entry */
+
+    if (dir[LDIR_Ord] & LLE) {              /* Put terminator if it is the last LFN part */
+        if (i >= _MAX_LFN) return 0;        /* Buffer overflow? */
+        lfnbuf[i] = 0;
+    }
+
+    return 1;
+}
+
+
+#if !_FS_READONLY
+static
+void fit_lfn (
+    const WCHAR *lfnbuf,    /* Pointer to the LFN buffer */
+    BYTE *dir,              /* Pointer to the directory entry */
+    BYTE ord,               /* LFN order (1-20) */
+    BYTE sum                /* SFN sum */
+)
+{
+    UINT i, s;
+    WCHAR wc;
+
+
+    dir[LDIR_Chksum] = sum;         /* Set check sum */
+    dir[LDIR_Attr] = AM_LFN;        /* Set attribute. LFN entry */
+    dir[LDIR_Type] = 0;
+    ST_WORD(dir+LDIR_FstClusLO, 0);
+
+    i = (ord - 1) * 13;             /* Get offset in the LFN buffer */
+    s = wc = 0;
+    do {
+        if (wc != 0xFFFF) wc = lfnbuf[i++]; /* Get an effective char */
+        ST_WORD(dir+LfnOfs[s], wc); /* Put it */
+        if (!wc) wc = 0xFFFF;       /* Padding chars following last char */
+    } while (++s < 13);
+    if (wc == 0xFFFF || !lfnbuf[i]) ord |= LLE; /* Bottom LFN part is the start of LFN sequence */
+    dir[LDIR_Ord] = ord;            /* Set the LFN order */
+}
+
+#endif
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Create numbered name                                                  */
+/*-----------------------------------------------------------------------*/
+#if _USE_LFN
+void gen_numname (
+    BYTE *dst,          /* Pointer to generated SFN */
+    const BYTE *src,    /* Pointer to source SFN to be modified */
+    const WCHAR *lfn,   /* Pointer to LFN */
+    WORD seq            /* Sequence number */
+)
+{
+    BYTE ns[8], c;
+    UINT i, j;
+
+
+    mem_cpy(dst, src, 11);
+
+    if (seq > 5) {  /* On many collisions, generate a hash number instead of sequential number */
+        do seq = (seq >> 1) + (seq << 15) + (WORD)*lfn++; while (*lfn);
+    }
+
+    /* itoa (hexdecimal) */
+    i = 7;
+    do {
+        c = (seq % 16) + '0';
+        if (c > '9') c += 7;
+        ns[i--] = c;
+        seq /= 16;
+    } while (seq);
+    ns[i] = '~';
+
+    /* Append the number */
+    for (j = 0; j < i && dst[j] != ' '; j++) {
+        if (IsDBCS1(dst[j])) {
+            if (j == i - 1) break;
+            j++;
+        }
+    }
+    do {
+        dst[j++] = (i < 8) ? ns[i++] : ' ';
+    } while (j < 8);
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Calculate sum of an SFN                                               */
+/*-----------------------------------------------------------------------*/
+#if _USE_LFN
+static
+BYTE sum_sfn (
+    const BYTE *dir     /* Ptr to directory entry */
+)
+{
+    BYTE sum = 0;
+    UINT n = 11;
+
+    do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n);
+    return sum;
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Find an object in the directory                  */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT dir_find (
+    FATFS_DIR *dj         /* Pointer to the directory object linked to the file name */
+)
+{
+    FRESULT res;
+    BYTE c, *dir;
+#if _USE_LFN
+    BYTE a, ord, sum;
+#endif
+
+    res = dir_sdi(dj, 0);           /* Rewind directory object */
+    if (res != FR_OK) return res;
+
+#if _USE_LFN
+    ord = sum = 0xFF;
+#endif
+    do {
+        res = move_window(dj->fs, dj->sect);
+        if (res != FR_OK) break;
+        dir = dj->dir;                  /* Ptr to the directory entry of current index */
+        c = dir[DIR_Name];
+        if (c == 0) { res = FR_NO_FILE; break; }    /* Reached to end of table */
+#if _USE_LFN    /* LFN configuration */
+        a = dir[DIR_Attr] & AM_MASK;
+        if (c == DDE || ((a & AM_VOL) && a != AM_LFN)) {    /* An entry without valid data */
+            ord = 0xFF;
+        } else {
+            if (a == AM_LFN) {          /* An LFN entry is found */
+                if (dj->lfn) {
+                    if (c & LLE) {      /* Is it start of LFN sequence? */
+                        sum = dir[LDIR_Chksum];
+                        c &= ~LLE; ord = c; /* LFN start order */
+                        dj->lfn_idx = dj->index;
+                    }
+                    /* Check validity of the LFN entry and compare it with given name */
+                    ord = (c == ord && sum == dir[LDIR_Chksum] && cmp_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF;
+                }
+            } else {                    /* An SFN entry is found */
+                if (!ord && sum == sum_sfn(dir)) break; /* LFN matched? */
+                ord = 0xFF; dj->lfn_idx = 0xFFFF;   /* Reset LFN sequence */
+                if (!(dj->fn[NS] & NS_LOSS) && !mem_cmp(dir, dj->fn, 11)) break;    /* SFN matched? */
+            }
+        }
+#else       /* Non LFN configuration */
+        if (!(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dj->fn, 11)) /* Is it a valid entry? */
+            break;
+#endif
+        res = dir_next(dj, 0);      /* Next entry */
+    } while (res == FR_OK);
+
+    return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read an object from the directory                                     */
+/*-----------------------------------------------------------------------*/
+#if _FS_MINIMIZE <= 1
+static
+FRESULT dir_read (
+    FATFS_DIR *dj         /* Pointer to the directory object that pointing the entry to be read */
+)
+{
+    FRESULT res;
+    BYTE c, *dir;
+#if _USE_LFN
+    BYTE a, ord = 0xFF, sum = 0xFF;
+#endif
+
+    res = FR_NO_FILE;
+    while (dj->sect) {
+        res = move_window(dj->fs, dj->sect);
+        if (res != FR_OK) break;
+        dir = dj->dir;                  /* Ptr to the directory entry of current index */
+        c = dir[DIR_Name];
+        if (c == 0) { res = FR_NO_FILE; break; }    /* Reached to end of table */
+#if _USE_LFN    /* LFN configuration */
+        a = dir[DIR_Attr] & AM_MASK;
+        if (c == DDE || (!_FS_RPATH && c == '.') || ((a & AM_VOL) && a != AM_LFN)) {    /* An entry without valid data */
+            ord = 0xFF;
+        } else {
+            if (a == AM_LFN) {          /* An LFN entry is found */
+                if (c & LLE) {          /* Is it start of LFN sequence? */
+                    sum = dir[LDIR_Chksum];
+                    c &= ~LLE; ord = c;
+                    dj->lfn_idx = dj->index;
+                }
+                /* Check LFN validity and capture it */
+                ord = (c == ord && sum == dir[LDIR_Chksum] && pick_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF;
+            } else {                    /* An SFN entry is found */
+                if (ord || sum != sum_sfn(dir)) /* Is there a valid LFN? */
+                    dj->lfn_idx = 0xFFFF;       /* It has no LFN. */
+                break;
+            }
+        }
+#else       /* Non LFN configuration */
+        if (c != DDE && (_FS_RPATH || c != '.') && !(dir[DIR_Attr] & AM_VOL))   /* Is it a valid entry? */
+            break;
+#endif
+        res = dir_next(dj, 0);              /* Next entry */
+        if (res != FR_OK) break;
+    }
+
+    if (res != FR_OK) dj->sect = 0;
+
+    return res;
+}
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Register an object to the directory                                   */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+FRESULT dir_register (  /* FR_OK:Successful, FR_DENIED:No free entry or too many SFN collision, FR_DISK_ERR:Disk error */
+    FATFS_DIR *dj             /* Target directory with object name to be created */
+)
+{
+    FRESULT res;
+    BYTE c, *dir;
+#if _USE_LFN    /* LFN configuration */
+    WORD n, ne, is;
+    BYTE sn[12], *fn, sum;
+    WCHAR *lfn;
+
+
+    fn = dj->fn; lfn = dj->lfn;
+    mem_cpy(sn, fn, 12);
+
+    if (_FS_RPATH && (sn[NS] & NS_DOT))     /* Cannot create dot entry */
+        return FR_INVALID_NAME;
+
+    if (sn[NS] & NS_LOSS) {         /* When LFN is out of 8.3 format, generate a numbered name */
+        fn[NS] = 0; dj->lfn = 0;            /* Find only SFN */
+        for (n = 1; n < 100; n++) {
+            gen_numname(fn, sn, lfn, n);    /* Generate a numbered name */
+            res = dir_find(dj);             /* Check if the name collides with existing SFN */
+            if (res != FR_OK) break;
+        }
+        if (n == 100) return FR_DENIED;     /* Abort if too many collisions */
+        if (res != FR_NO_FILE) return res;  /* Abort if the result is other than 'not collided' */
+        fn[NS] = sn[NS]; dj->lfn = lfn;
+    }
+
+    if (sn[NS] & NS_LFN) {          /* When LFN is to be created, reserve an SFN + LFN entries. */
+        for (ne = 0; lfn[ne]; ne++) ;
+        ne = (ne + 25) / 13;
+    } else {                        /* Otherwise reserve only an SFN entry. */
+        ne = 1;
+    }
+
+    /* Reserve contiguous entries */
+    res = dir_sdi(dj, 0);
+    if (res != FR_OK) return res;
+    n = is = 0;
+    do {
+        res = move_window(dj->fs, dj->sect);
+        if (res != FR_OK) break;
+        c = *dj->dir;               /* Check the entry status */
+        if (c == DDE || c == 0) {   /* Is it a blank entry? */
+            if (n == 0) is = dj->index; /* First index of the contiguous entry */
+            if (++n == ne) break;   /* A contiguous entry that required count is found */
+        } else {
+            n = 0;                  /* Not a blank entry. Restart to search */
+        }
+        res = dir_next(dj, 1);      /* Next entry with table stretch */
+    } while (res == FR_OK);
+
+    if (res == FR_OK && ne > 1) {   /* Initialize LFN entry if needed */
+        res = dir_sdi(dj, is);
+        if (res == FR_OK) {
+            sum = sum_sfn(dj->fn);  /* Sum of the SFN tied to the LFN */
+            ne--;
+            do {                    /* Store LFN entries in bottom first */
+                res = move_window(dj->fs, dj->sect);
+                if (res != FR_OK) break;
+                fit_lfn(dj->lfn, dj->dir, (BYTE)ne, sum);
+                dj->fs->wflag = 1;
+                res = dir_next(dj, 0);  /* Next entry */
+            } while (res == FR_OK && --ne);
+        }
+    }
+
+#else   /* Non LFN configuration */
+    res = dir_sdi(dj, 0);
+    if (res == FR_OK) {
+        do {    /* Find a blank entry for the SFN */
+            res = move_window(dj->fs, dj->sect);
+            if (res != FR_OK) break;
+            c = *dj->dir;
+            if (c == DDE || c == 0) break;  /* Is it a blank entry? */
+            res = dir_next(dj, 1);          /* Next entry with table stretch */
+        } while (res == FR_OK);
+    }
+#endif
+
+    if (res == FR_OK) {     /* Initialize the SFN entry */
+        res = move_window(dj->fs, dj->sect);
+        if (res == FR_OK) {
+            dir = dj->dir;
+            mem_set(dir, 0, SZ_DIR);    /* Clean the entry */
+            mem_cpy(dir, dj->fn, 11);   /* Put SFN */
+#if _USE_LFN
+            dir[DIR_NTres] = *(dj->fn+NS) & (NS_BODY | NS_EXT); /* Put NT flag */
+#endif
+            dj->fs->wflag = 1;
+        }
+    }
+
+    return res;
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Remove an object from the directory                                   */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY && !_FS_MINIMIZE
+static
+FRESULT dir_remove (    /* FR_OK: Successful, FR_DISK_ERR: A disk error */
+    FATFS_DIR *dj             /* Directory object pointing the entry to be removed */
+)
+{
+    FRESULT res;
+#if _USE_LFN    /* LFN configuration */
+    WORD i;
+
+    i = dj->index;  /* SFN index */
+    res = dir_sdi(dj, (WORD)((dj->lfn_idx == 0xFFFF) ? i : dj->lfn_idx));   /* Goto the SFN or top of the LFN entries */
+    if (res == FR_OK) {
+        do {
+            res = move_window(dj->fs, dj->sect);
+            if (res != FR_OK) break;
+            *dj->dir = DDE;         /* Mark the entry "deleted" */
+            dj->fs->wflag = 1;
+            if (dj->index >= i) break;  /* When reached SFN, all entries of the object has been deleted. */
+            res = dir_next(dj, 0);      /* Next entry */
+        } while (res == FR_OK);
+        if (res == FR_NO_FILE) res = FR_INT_ERR;
+    }
+
+#else           /* Non LFN configuration */
+    res = dir_sdi(dj, dj->index);
+    if (res == FR_OK) {
+        res = move_window(dj->fs, dj->sect);
+        if (res == FR_OK) {
+            *dj->dir = DDE;         /* Mark the entry "deleted" */
+            dj->fs->wflag = 1;
+        }
+    }
+#endif
+
+    return res;
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Pick a segment and create the object name in directory form           */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT create_name (
+    FATFS_DIR *dj,            /* Pointer to the directory object */
+    const TCHAR **path  /* Pointer to pointer to the segment in the path string */
+)
+{
+#ifdef _EXCVT
+    static const BYTE excvt[] = _EXCVT; /* Upper conversion table for extended chars */
+#endif
+
+#if _USE_LFN    /* LFN configuration */
+    BYTE b, cf;
+    WCHAR w, *lfn;
+    UINT i, ni, si, di;
+    const TCHAR *p;
+
+    /* Create LFN in Unicode */
+    for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Strip duplicated separator */
+    lfn = dj->lfn;
+    si = di = 0;
+    for (;;) {
+        w = p[si++];                    /* Get a character */
+        if (w < ' ' || w == '/' || w == '\\') break;    /* Break on end of segment */
+        if (di >= _MAX_LFN)             /* Reject too long name */
+            return FR_INVALID_NAME;
+#if !_LFN_UNICODE
+        w &= 0xFF;
+        if (IsDBCS1(w)) {               /* Check if it is a DBC 1st byte (always false on SBCS cfg) */
+            b = (BYTE)p[si++];          /* Get 2nd byte */
+            if (!IsDBCS2(b))
+                return FR_INVALID_NAME; /* Reject invalid sequence */
+            w = (w << 8) + b;           /* Create a DBC */
+        }
+        w = ff_convert(w, 1);           /* Convert ANSI/OEM to Unicode */
+        if (!w) return FR_INVALID_NAME; /* Reject invalid code */
+#endif
+        if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) /* Reject illegal chars for LFN */
+            return FR_INVALID_NAME;
+        lfn[di++] = w;                  /* Store the Unicode char */
+    }
+    *path = &p[si];                     /* Return pointer to the next segment */
+    cf = (w < ' ') ? NS_LAST : 0;       /* Set last segment flag if end of path */
+#if _FS_RPATH
+    if ((di == 1 && lfn[di-1] == '.') || /* Is this a dot entry? */
+        (di == 2 && lfn[di-1] == '.' && lfn[di-2] == '.')) {
+        lfn[di] = 0;
+        for (i = 0; i < 11; i++)
+            dj->fn[i] = (i < di) ? '.' : ' ';
+        dj->fn[i] = cf | NS_DOT;        /* This is a dot entry */
+        return FR_OK;
+    }
+#endif
+    while (di) {                        /* Strip trailing spaces and dots */
+        w = lfn[di-1];
+        if (w != ' ' && w != '.') break;
+        di--;
+    }
+    if (!di) return FR_INVALID_NAME;    /* Reject nul string */
+
+    lfn[di] = 0;                        /* LFN is created */
+
+    /* Create SFN in directory form */
+    mem_set(dj->fn, ' ', 11);
+    for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++) ;  /* Strip leading spaces and dots */
+    if (si) cf |= NS_LOSS | NS_LFN;
+    while (di && lfn[di - 1] != '.') di--;  /* Find extension (di<=si: no extension) */
+
+    b = i = 0; ni = 8;
+    for (;;) {
+        w = lfn[si++];                  /* Get an LFN char */
+        if (!w) break;                  /* Break on end of the LFN */
+        if (w == ' ' || (w == '.' && si != di)) {   /* Remove spaces and dots */
+            cf |= NS_LOSS | NS_LFN; continue;
+        }
+
+        if (i >= ni || si == di) {      /* Extension or end of SFN */
+            if (ni == 11) {             /* Long extension */
+                cf |= NS_LOSS | NS_LFN; break;
+            }
+            if (si != di) cf |= NS_LOSS | NS_LFN;   /* Out of 8.3 format */
+            if (si > di) break;         /* No extension */
+            si = di; i = 8; ni = 11;    /* Enter extension section */
+            b <<= 2; continue;
+        }
+
+        if (w >= 0x80) {                /* Non ASCII char */
+#ifdef _EXCVT
+            w = ff_convert(w, 0);       /* Unicode -> OEM code */
+            if (w) w = excvt[w - 0x80]; /* Convert extended char to upper (SBCS) */
+#else
+            w = ff_convert(ff_wtoupper(w), 0);  /* Upper converted Unicode -> OEM code */
+#endif
+            cf |= NS_LFN;               /* Force create LFN entry */
+        }
+
+        if (_DF1S && w >= 0x100) {      /* Double byte char (always false on SBCS cfg) */
+            if (i >= ni - 1) {
+                cf |= NS_LOSS | NS_LFN; i = ni; continue;
+            }
+            dj->fn[i++] = (BYTE)(w >> 8);
+        } else {                        /* Single byte char */
+            if (!w || chk_chr("+,;=[]", w)) {   /* Replace illegal chars for SFN */
+                w = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */
+            } else {
+                if (IsUpper(w)) {       /* ASCII large capital */
+                    b |= 2;
+                } else {
+                    if (IsLower(w)) {   /* ASCII small capital */
+                        b |= 1; w -= 0x20;
+                    }
+                }
+            }
+        }
+        dj->fn[i++] = (BYTE)w;
+    }
+
+    if (dj->fn[0] == DDE) dj->fn[0] = NDDE; /* If the first char collides with deleted mark, replace it with 0x05 */
+
+    if (ni == 8) b <<= 2;
+    if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03)   /* Create LFN entry when there are composite capitals */
+        cf |= NS_LFN;
+    if (!(cf & NS_LFN)) {                       /* When LFN is in 8.3 format without extended char, NT flags are created */
+        if ((b & 0x03) == 0x01) cf |= NS_EXT;   /* NT flag (Extension has only small capital) */
+        if ((b & 0x0C) == 0x04) cf |= NS_BODY;  /* NT flag (Filename has only small capital) */
+    }
+
+    dj->fn[NS] = cf;    /* SFN is created */
+
+    return FR_OK;
+
+
+#else   /* Non-LFN configuration */
+    BYTE b, c, d, *sfn;
+    UINT ni, si, i;
+    const char *p;
+
+    /* Create file name in directory form */
+    for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Strip duplicated separator */
+    sfn = dj->fn;
+    mem_set(sfn, ' ', 11);
+    si = i = b = 0; ni = 8;
+#if _FS_RPATH
+    if (p[si] == '.') { /* Is this a dot entry? */
+        for (;;) {
+            c = (BYTE)p[si++];
+            if (c != '.' || si >= 3) break;
+            sfn[i++] = c;
+        }
+        if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME;
+        *path = &p[si];                                 /* Return pointer to the next segment */
+        sfn[NS] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT;   /* Set last segment flag if end of path */
+        return FR_OK;
+    }
+#endif
+    for (;;) {
+        c = (BYTE)p[si++];
+        if (c <= ' ' || c == '/' || c == '\\') break;   /* Break on end of segment */
+        if (c == '.' || i >= ni) {
+            if (ni != 8 || c != '.') return FR_INVALID_NAME;
+            i = 8; ni = 11;
+            b <<= 2; continue;
+        }
+        if (c >= 0x80) {                /* Extended char? */
+            b |= 3;                     /* Eliminate NT flag */
+#ifdef _EXCVT
+            c = excvt[c - 0x80];        /* Upper conversion (SBCS) */
+#else
+#if !_DF1S  /* ASCII only cfg */
+            return FR_INVALID_NAME;
+#endif
+#endif
+        }
+        if (IsDBCS1(c)) {               /* Check if it is a DBC 1st byte (always false on SBCS cfg) */
+            d = (BYTE)p[si++];          /* Get 2nd byte */
+            if (!IsDBCS2(d) || i >= ni - 1) /* Reject invalid DBC */
+                return FR_INVALID_NAME;
+            sfn[i++] = c;
+            sfn[i++] = d;
+        } else {                        /* Single byte code */
+            if (chk_chr("\"*+,:;<=>\?[]|\x7F", c))  /* Reject illegal chrs for SFN */
+                return FR_INVALID_NAME;
+            if (IsUpper(c)) {           /* ASCII large capital? */
+                b |= 2;
+            } else {
+                if (IsLower(c)) {       /* ASCII small capital? */
+                    b |= 1; c -= 0x20;
+                }
+            }
+            sfn[i++] = c;
+        }
+    }
+    *path = &p[si];                     /* Return pointer to the next segment */
+    c = (c <= ' ') ? NS_LAST : 0;       /* Set last segment flag if end of path */
+
+    if (!i) return FR_INVALID_NAME;     /* Reject nul string */
+    if (sfn[0] == DDE) sfn[0] = NDDE;   /* When first char collides with DDE, replace it with 0x05 */
+
+    if (ni == 8) b <<= 2;
+    if ((b & 0x03) == 0x01) c |= NS_EXT;    /* NT flag (Name extension has only small capital) */
+    if ((b & 0x0C) == 0x04) c |= NS_BODY;   /* NT flag (Name body has only small capital) */
+
+    sfn[NS] = c;        /* Store NT flag, File name is created */
+
+    return FR_OK;
+#endif
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Get file information from directory entry                             */
+/*-----------------------------------------------------------------------*/
+#if _FS_MINIMIZE <= 1
+static
+void get_fileinfo (     /* No return code */
+    FATFS_DIR *dj,            /* Pointer to the directory object */
+    FILINFO *fno        /* Pointer to the file information to be filled */
+)
+{
+    UINT i;
+    BYTE nt, *dir;
+    TCHAR *p, c;
+
+
+    p = fno->fname;
+    if (dj->sect) {
+        dir = dj->dir;
+        nt = dir[DIR_NTres];        /* NT flag */
+        for (i = 0; i < 8; i++) {   /* Copy name body */
+            c = dir[i];
+            if (c == ' ') break;
+            if (c == NDDE) c = (TCHAR)DDE;
+            if (_USE_LFN && (nt & NS_BODY) && IsUpper(c)) c += 0x20;
+#if _LFN_UNICODE
+            if (IsDBCS1(c) && i < 7 && IsDBCS2(dir[i+1]))
+                c = (c << 8) | dir[++i];
+            c = ff_convert(c, 1);
+            if (!c) c = '?';
+#endif
+            *p++ = c;
+        }
+        if (dir[8] != ' ') {        /* Copy name extension */
+            *p++ = '.';
+            for (i = 8; i < 11; i++) {
+                c = dir[i];
+                if (c == ' ') break;
+                if (_USE_LFN && (nt & NS_EXT) && IsUpper(c)) c += 0x20;
+#if _LFN_UNICODE
+                if (IsDBCS1(c) && i < 10 && IsDBCS2(dir[i+1]))
+                    c = (c << 8) | dir[++i];
+                c = ff_convert(c, 1);
+                if (!c) c = '?';
+#endif
+                *p++ = c;
+            }
+        }
+        fno->fattrib = dir[DIR_Attr];               /* Attribute */
+        fno->fsize = LD_DWORD(dir+DIR_FileSize);    /* Size */
+        fno->fdate = LD_WORD(dir+DIR_WrtDate);      /* Date */
+        fno->ftime = LD_WORD(dir+DIR_WrtTime);      /* Time */
+    }
+    *p = 0;     /* Terminate SFN str by a \0 */
+
+#if _USE_LFN
+    if (fno->lfname && fno->lfsize) {
+        TCHAR *tp = fno->lfname;
+        WCHAR w, *lfn;
+
+        i = 0;
+        if (dj->sect && dj->lfn_idx != 0xFFFF) {/* Get LFN if available */
+            lfn = dj->lfn;
+            while ((w = *lfn++) != 0) {         /* Get an LFN char */
+#if !_LFN_UNICODE
+                w = ff_convert(w, 0);           /* Unicode -> OEM conversion */
+                if (!w) { i = 0; break; }       /* Could not convert, no LFN */
+                if (_DF1S && w >= 0x100)        /* Put 1st byte if it is a DBC (always false on SBCS cfg) */
+                    tp[i++] = (TCHAR)(w >> 8);
+#endif
+                if (i >= fno->lfsize - 1) { i = 0; break; } /* Buffer overflow, no LFN */
+                tp[i++] = (TCHAR)w;
+            }
+        }
+        tp[i] = 0;  /* Terminate the LFN str by a \0 */
+    }
+#endif
+}
+#endif /* _FS_MINIMIZE <= 1 */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Follow a file path                                                    */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT follow_path (   /* FR_OK(0): successful, !=0: error code */
+    FATFS_DIR *dj,            /* Directory object to return last directory and found object */
+    const TCHAR *path   /* Full-path string to find a file or directory */
+)
+{
+    FRESULT res;
+    BYTE *dir, ns;
+
+
+#if _FS_RPATH
+    if (*path == '/' || *path == '\\') { /* There is a heading separator */
+        path++; dj->sclust = 0;     /* Strip it and start from the root dir */
+    } else {                            /* No heading separator */
+        dj->sclust = dj->fs->cdir;  /* Start from the current dir */
+    }
+#else
+    if (*path == '/' || *path == '\\')  /* Strip heading separator if exist */
+        path++;
+    dj->sclust = 0;                     /* Start from the root dir */
+#endif
+
+    if ((UINT)*path < ' ') {            /* Nul path means the start directory itself */
+        res = dir_sdi(dj, 0);
+        dj->dir = 0;
+    } else {                            /* Follow path */
+        for (;;) {
+            res = create_name(dj, &path);   /* Get a segment */
+            if (res != FR_OK) break;
+            res = dir_find(dj);             /* Find it */
+            ns = *(dj->fn+NS);
+            if (res != FR_OK) {             /* Failed to find the object */
+                if (res != FR_NO_FILE) break;   /* Abort if any hard error occurred */
+                /* Object not found */
+                if (_FS_RPATH && (ns & NS_DOT)) {   /* If dot entry is not exit */
+                    dj->sclust = 0; dj->dir = 0;    /* It is the root dir */
+                    res = FR_OK;
+                    if (!(ns & NS_LAST)) continue;
+                } else {                            /* Could not find the object */
+                    if (!(ns & NS_LAST)) res = FR_NO_PATH;
+                }
+                break;
+            }
+            if (ns & NS_LAST) break;            /* Last segment match. Function completed. */
+            dir = dj->dir;                      /* There is next segment. Follow the sub directory */
+            if (!(dir[DIR_Attr] & AM_DIR)) {    /* Cannot follow because it is a file */
+                res = FR_NO_PATH; break;
+            }
+            dj->sclust = ld_clust(dj->fs, dir);
+        }
+    }
+
+    return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Load a sector and check if it is an FAT Volume Boot Record            */
+/*-----------------------------------------------------------------------*/
+
+static
+BYTE check_fs ( /* 0:FAT-VBR, 1:Any BR but not FAT, 2:Not a BR, 3:Disk error */
+    FATFS *fs,  /* File system object */
+    DWORD sect  /* Sector# (lba) to check if it is an FAT boot record or not */
+)
+{
+    if (disk_read(fs->drv, fs->win, sect, 1) != RES_OK) /* Load boot record */
+        return 3;
+    if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55)       /* Check record signature (always placed at offset 510 even if the sector size is >512) */
+        return 2;
+
+    if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */
+        return 0;
+    if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146)
+        return 0;
+
+    return 1;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Check if the file system object is valid or not                       */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT chk_mounted (   /* FR_OK(0): successful, !=0: any error occurred */
+    const TCHAR **path, /* Pointer to pointer to the path name (drive number) */
+    FATFS **rfs,        /* Pointer to pointer to the found file system object */
+    BYTE wmode          /* !=0: Check write protection for write access */
+)
+{
+    BYTE fmt, b, pi, *tbl;
+    UINT vol;
+    DSTATUS stat;
+    DWORD bsect, fasize, tsect, sysect, nclst, szbfat;
+    WORD nrsv;
+    const TCHAR *p = *path;
+    FATFS *fs;
+
+
+    /* Get logical drive number from the path name */
+    vol = p[0] - '0';                   /* Is there a drive number? */
+    if (vol <= 9 && p[1] == ':') {      /* Found a drive number, get and strip it */
+        p += 2; *path = p;              /* Return pointer to the path name */
+    } else {                            /* No drive number is given */
+#if _FS_RPATH
+        vol = CurrVol;                  /* Use current drive */
+#else
+        vol = 0;                        /* Use drive 0 */
+#endif
+    }
+
+    /* Check if the file system object is valid or not */
+    *rfs = 0;
+    if (vol >= _VOLUMES)                /* Is the drive number valid? */
+        return FR_INVALID_DRIVE;
+    fs = FatFs[vol];                    /* Get corresponding file system object */
+    if (!fs) return FR_NOT_ENABLED;     /* Is the file system object available? */
+
+    ENTER_FF(fs);                       /* Lock file system */
+
+    *rfs = fs;                          /* Return pointer to the corresponding file system object */
+    if (fs->fs_type) {                  /* If the volume has been mounted */
+        stat = disk_status(fs->drv);
+        if (!(stat & STA_NOINIT)) {     /* and the physical drive is kept initialized (has not been changed), */
+            if (!_FS_READONLY && wmode && (stat & STA_PROTECT)) /* Check write protection if needed */
+                return FR_WRITE_PROTECTED;
+            return FR_OK;               /* The file system object is valid */
+        }
+    }
+
+    /* The file system object is not valid. */
+    /* Following code attempts to mount the volume. (analyze BPB and initialize the fs object) */
+
+    fs->fs_type = 0;                    /* Clear the file system object */
+    fs->drv = LD2PD(vol);               /* Bind the logical drive and a physical drive */
+    stat = disk_initialize(fs->drv);    /* Initialize the physical drive */
+    if (stat & STA_NOINIT)              /* Check if the initialization succeeded */
+        return FR_NOT_READY;            /* Failed to initialize due to no medium or hard error */
+    if (!_FS_READONLY && wmode && (stat & STA_PROTECT)) /* Check disk write protection if needed */
+        return FR_WRITE_PROTECTED;
+#if _MAX_SS != 512                      /* Get disk sector size (variable sector size cfg only) */
+    if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &fs->ssize) != RES_OK)
+        return FR_DISK_ERR;
+#endif
+    /* Search FAT partition on the drive. Supports only generic partitions, FDISK and SFD. */
+    fmt = check_fs(fs, bsect = 0);      /* Load sector 0 and check if it is an FAT-VBR (in SFD) */
+    if (LD2PT(vol) && !fmt) fmt = 1;    /* Force non-SFD if the volume is forced partition */
+    if (fmt == 1) {                     /* Not an FAT-VBR, the physical drive can be partitioned */
+        /* Check the partition listed in the partition table */
+        pi = LD2PT(vol);
+        if (pi) pi--;
+        tbl = &fs->win[MBR_Table + pi * SZ_PTE];/* Partition table */
+        if (tbl[4]) {                       /* Is the partition existing? */
+            bsect = LD_DWORD(&tbl[8]);      /* Partition offset in LBA */
+            fmt = check_fs(fs, bsect);      /* Check the partition */
+        }
+    }
+    if (fmt == 3) return FR_DISK_ERR;
+    if (fmt) return FR_NO_FILESYSTEM;       /* No FAT volume is found */
+
+    /* An FAT volume is found. Following code initializes the file system object */
+
+    if (LD_WORD(fs->win+BPB_BytsPerSec) != SS(fs))      /* (BPB_BytsPerSec must be equal to the physical sector size) */
+        return FR_NO_FILESYSTEM;
+
+    fasize = LD_WORD(fs->win+BPB_FATSz16);              /* Number of sectors per FAT */
+    if (!fasize) fasize = LD_DWORD(fs->win+BPB_FATSz32);
+    fs->fsize = fasize;
+
+    fs->n_fats = b = fs->win[BPB_NumFATs];              /* Number of FAT copies */
+    if (b != 1 && b != 2) return FR_NO_FILESYSTEM;      /* (Must be 1 or 2) */
+    fasize *= b;                                        /* Number of sectors for FAT area */
+
+    fs->csize = b = fs->win[BPB_SecPerClus];            /* Number of sectors per cluster */
+    if (!b || (b & (b - 1))) return FR_NO_FILESYSTEM;   /* (Must be power of 2) */
+
+    fs->n_rootdir = LD_WORD(fs->win+BPB_RootEntCnt);    /* Number of root directory entries */
+    if (fs->n_rootdir % (SS(fs) / SZ_DIR)) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be sector aligned) */
+
+    tsect = LD_WORD(fs->win+BPB_TotSec16);              /* Number of sectors on the volume */
+    if (!tsect) tsect = LD_DWORD(fs->win+BPB_TotSec32);
+
+    nrsv = LD_WORD(fs->win+BPB_RsvdSecCnt);             /* Number of reserved sectors */
+    if (!nrsv) return FR_NO_FILESYSTEM;                 /* (BPB_RsvdSecCnt must not be 0) */
+
+    /* Determine the FAT sub type */
+    sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZ_DIR); /* RSV+FAT+DIR */
+    if (tsect < sysect) return FR_NO_FILESYSTEM;        /* (Invalid volume size) */
+    nclst = (tsect - sysect) / fs->csize;               /* Number of clusters */
+    if (!nclst) return FR_NO_FILESYSTEM;                /* (Invalid volume size) */
+    fmt = FS_FAT12;
+    if (nclst >= MIN_FAT16) fmt = FS_FAT16;
+    if (nclst >= MIN_FAT32) fmt = FS_FAT32;
+
+    /* Boundaries and Limits */
+    fs->n_fatent = nclst + 2;                           /* Number of FAT entries */
+    fs->database = bsect + sysect;                      /* Data start sector */
+    fs->fatbase = bsect + nrsv;                         /* FAT start sector */
+    if (fmt == FS_FAT32) {
+        if (fs->n_rootdir) return FR_NO_FILESYSTEM;     /* (BPB_RootEntCnt must be 0) */
+        fs->dirbase = LD_DWORD(fs->win+BPB_RootClus);   /* Root directory start cluster */
+        szbfat = fs->n_fatent * 4;                      /* (Required FAT size) */
+    } else {
+        if (!fs->n_rootdir) return FR_NO_FILESYSTEM;    /* (BPB_RootEntCnt must not be 0) */
+        fs->dirbase = fs->fatbase + fasize;             /* Root directory start sector */
+        szbfat = (fmt == FS_FAT16) ?                    /* (Required FAT size) */
+            fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1);
+    }
+    if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs))   /* (BPB_FATSz must not be less than required) */
+        return FR_NO_FILESYSTEM;
+
+#if !_FS_READONLY
+    /* Initialize cluster allocation information */
+    fs->free_clust = 0xFFFFFFFF;
+    fs->last_clust = 0;
+
+    /* Get fsinfo if available */
+    if (fmt == FS_FAT32) {
+        fs->fsi_flag = 0;
+        fs->fsi_sector = bsect + LD_WORD(fs->win+BPB_FSInfo);
+        if (disk_read(fs->drv, fs->win, fs->fsi_sector, 1) == RES_OK &&
+            LD_WORD(fs->win+BS_55AA) == 0xAA55 &&
+            LD_DWORD(fs->win+FSI_LeadSig) == 0x41615252 &&
+            LD_DWORD(fs->win+FSI_StrucSig) == 0x61417272) {
+                fs->last_clust = LD_DWORD(fs->win+FSI_Nxt_Free);
+                fs->free_clust = LD_DWORD(fs->win+FSI_Free_Count);
+        }
+    }
+#endif
+    fs->fs_type = fmt;      /* FAT sub-type */
+    fs->id = ++Fsid;        /* File system mount ID */
+    fs->winsect = 0;        /* Invalidate sector cache */
+    fs->wflag = 0;
+#if _FS_RPATH
+    fs->cdir = 0;           /* Current directory (root dir) */
+#endif
+#if _FS_LOCK                /* Clear file lock semaphores */
+    clear_lock(fs);
+#endif
+
+    return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Check if the file/dir object is valid or not                          */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT validate (  /* FR_OK(0): The object is valid, !=0: Invalid */
+    void* obj       /* Pointer to the object FIL/DIR to check validity */
+)
+{
+    FIL *fil;
+
+
+    fil = (FIL*)obj;    /* Assuming offset of fs and id in the FIL/DIR is identical */
+    if (!fil->fs || !fil->fs->fs_type || fil->fs->id != fil->id)
+        return FR_INVALID_OBJECT;
+
+    ENTER_FF(fil->fs);      /* Lock file system */
+
+    if (disk_status(fil->fs->drv) & STA_NOINIT)
+        return FR_NOT_READY;
+
+    return FR_OK;
+}
+
+
+
+
+/*--------------------------------------------------------------------------
+
+   Public Functions
+
+--------------------------------------------------------------------------*/
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Mount/Unmount a Logical Drive                                         */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_mount (
+    BYTE vol,       /* Logical drive number to be mounted/unmounted */
+    FATFS *fs       /* Pointer to new file system object (NULL for unmount)*/
+)
+{
+    FATFS *rfs;
+
+
+    if (vol >= _VOLUMES)        /* Check if the drive number is valid */
+        return FR_INVALID_DRIVE;
+    rfs = FatFs[vol];           /* Get current fs object */
+
+    if (rfs) {
+#if _FS_LOCK
+        clear_lock(rfs);
+#endif
+#if _FS_REENTRANT               /* Discard sync object of the current volume */
+        if (!ff_del_syncobj(rfs->sobj)) return FR_INT_ERR;
+#endif
+        rfs->fs_type = 0;       /* Clear old fs object */
+    }
+
+    if (fs) {
+        fs->fs_type = 0;        /* Clear new fs object */
+#if _FS_REENTRANT               /* Create sync object for the new volume */
+        if (!ff_cre_syncobj(vol, &fs->sobj)) return FR_INT_ERR;
+#endif
+    }
+    FatFs[vol] = fs;            /* Register new fs object */
+
+    return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Open or Create a File                                                 */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_open (
+    FIL *fp,            /* Pointer to the blank file object */
+    const TCHAR *path,  /* Pointer to the file name */
+    BYTE mode           /* Access mode and file open mode flags */
+)
+{
+    FRESULT res;
+    FATFS_DIR dj;
+    BYTE *dir;
+    DEF_NAMEBUF;
+
+
+    if (!fp) return FR_INVALID_OBJECT;
+    fp->fs = 0;         /* Clear file object */
+
+#if !_FS_READONLY
+    mode &= FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW;
+    res = chk_mounted(&path, &dj.fs, (BYTE)(mode & ~FA_READ));
+#else
+    mode &= FA_READ;
+    res = chk_mounted(&path, &dj.fs, 0);
+#endif
+    if (res == FR_OK) {
+        INIT_BUF(dj);
+        res = follow_path(&dj, path);   /* Follow the file path */
+        dir = dj.dir;
+#if !_FS_READONLY   /* R/W configuration */
+        if (res == FR_OK) {
+            if (!dir)   /* Current dir itself */
+                res = FR_INVALID_NAME;
+#if _FS_LOCK
+            else
+                res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0);
+#endif
+        }
+        /* Create or Open a file */
+        if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) {
+            DWORD dw, cl;
+
+            if (res != FR_OK) {                 /* No file, create new */
+                if (res == FR_NO_FILE)          /* There is no file to open, create a new entry */
+#if _FS_LOCK
+                    res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES;
+#else
+                    res = dir_register(&dj);
+#endif
+                mode |= FA_CREATE_ALWAYS;       /* File is created */
+                dir = dj.dir;                   /* New entry */
+            }
+            else {                              /* Any object is already existing */
+                if (dir[DIR_Attr] & (AM_RDO | AM_DIR)) {    /* Cannot overwrite it (R/O or DIR) */
+                    res = FR_DENIED;
+                } else {
+                    if (mode & FA_CREATE_NEW)   /* Cannot create as new file */
+                        res = FR_EXIST;
+                }
+            }
+            if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) {    /* Truncate it if overwrite mode */
+                dw = get_fattime();                 /* Created time */
+                ST_DWORD(dir+DIR_CrtTime, dw);
+                dir[DIR_Attr] = 0;                  /* Reset attribute */
+                ST_DWORD(dir+DIR_FileSize, 0);      /* size = 0 */
+                cl = ld_clust(dj.fs, dir);          /* Get start cluster */
+                st_clust(dir, 0);                   /* cluster = 0 */
+                dj.fs->wflag = 1;
+                if (cl) {                           /* Remove the cluster chain if exist */
+                    dw = dj.fs->winsect;
+                    res = remove_chain(dj.fs, cl);
+                    if (res == FR_OK) {
+                        dj.fs->last_clust = cl - 1; /* Reuse the cluster hole */
+                        res = move_window(dj.fs, dw);
+                    }
+                }
+            }
+        }
+        else {  /* Open an existing file */
+            if (res == FR_OK) {                     /* Follow succeeded */
+                if (dir[DIR_Attr] & AM_DIR) {       /* It is a directory */
+                    res = FR_NO_FILE;
+                } else {
+                    if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */
+                        res = FR_DENIED;
+                }
+            }
+        }
+        if (res == FR_OK) {
+            if (mode & FA_CREATE_ALWAYS)            /* Set file change flag if created or overwritten */
+                mode |= FA__WRITTEN;
+            fp->dir_sect = dj.fs->winsect;          /* Pointer to the directory entry */
+            fp->dir_ptr = dir;
+#if _FS_LOCK
+            fp->lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0);
+            if (!fp->lockid) res = FR_INT_ERR;
+#endif
+        }
+
+#else               /* R/O configuration */
+        if (res == FR_OK) {                 /* Follow succeeded */
+            dir = dj.dir;
+            if (!dir) {                     /* Current dir itself */
+                res = FR_INVALID_NAME;
+            } else {
+                if (dir[DIR_Attr] & AM_DIR) /* It is a directory */
+                    res = FR_NO_FILE;
+            }
+        }
+#endif
+        FREE_BUF();
+
+        if (res == FR_OK) {
+            fp->flag = mode;                    /* File access mode */
+            fp->sclust = ld_clust(dj.fs, dir);  /* File start cluster */
+            fp->fsize = LD_DWORD(dir+DIR_FileSize); /* File size */
+            fp->fptr = 0;                       /* File pointer */
+            fp->dsect = 0;
+#if _USE_FASTSEEK
+            fp->cltbl = 0;                      /* Normal seek mode */
+#endif
+            fp->fs = dj.fs; fp->id = dj.fs->id; /* Validate file object */
+        }
+    }
+
+    LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read File                                                             */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_read (
+    FIL *fp,        /* Pointer to the file object */
+    void *buff,     /* Pointer to data buffer */
+    UINT btr,       /* Number of bytes to read */
+    UINT *br        /* Pointer to number of bytes read */
+)
+{
+    FRESULT res;
+    DWORD clst, sect, remain;
+    UINT rcnt, cc;
+    BYTE csect, *rbuff = (BYTE *)buff;
+
+
+    *br = 0;    /* Clear read byte counter */
+
+    res = validate(fp);                         /* Check validity */
+    if (res != FR_OK) LEAVE_FF(fp->fs, res);
+    if (fp->flag & FA__ERROR)                   /* Aborted file? */
+        LEAVE_FF(fp->fs, FR_INT_ERR);
+    if (!(fp->flag & FA_READ))                  /* Check access mode */
+        LEAVE_FF(fp->fs, FR_DENIED);
+    remain = fp->fsize - fp->fptr;
+    if (btr > remain) btr = (UINT)remain;       /* Truncate btr by remaining bytes */
+
+    for ( ;  btr;                               /* Repeat until all data read */
+        rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {
+        if ((fp->fptr % SS(fp->fs)) == 0) {     /* On the sector boundary? */
+            csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1));    /* Sector offset in the cluster */
+            if (!csect) {                       /* On the cluster boundary? */
+                if (fp->fptr == 0) {            /* On the top of the file? */
+                    clst = fp->sclust;          /* Follow from the origin */
+                } else {                        /* Middle or end of the file */
+#if _USE_FASTSEEK
+                    if (fp->cltbl)
+                        clst = clmt_clust(fp, fp->fptr);    /* Get cluster# from the CLMT */
+                    else
+#endif
+                        clst = get_fat(fp->fs, fp->clust);  /* Follow cluster chain on the FAT */
+                }
+                if (clst < 2) ABORT(fp->fs, FR_INT_ERR);
+                if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+                fp->clust = clst;               /* Update current cluster */
+            }
+            sect = clust2sect(fp->fs, fp->clust);   /* Get current sector */
+            if (!sect) ABORT(fp->fs, FR_INT_ERR);
+            sect += csect;
+            cc = btr / SS(fp->fs);              /* When remaining bytes >= sector size, */
+            if (cc) {                           /* Read maximum contiguous sectors directly */
+                if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */
+                    cc = fp->fs->csize - csect;
+                if (disk_read(fp->fs->drv, rbuff, sect, (BYTE)cc) != RES_OK)
+                    ABORT(fp->fs, FR_DISK_ERR);
+#if !_FS_READONLY && _FS_MINIMIZE <= 2          /* Replace one of the read sectors with cached data if it contains a dirty sector */
+#if _FS_TINY
+                if (fp->fs->wflag && fp->fs->winsect - sect < cc)
+                    mem_cpy(rbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), fp->fs->win, SS(fp->fs));
+#else
+                if ((fp->flag & FA__DIRTY) && fp->dsect - sect < cc)
+                    mem_cpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs));
+#endif
+#endif
+                rcnt = SS(fp->fs) * cc;         /* Number of bytes transferred */
+                continue;
+            }
+#if !_FS_TINY
+            if (fp->dsect != sect) {            /* Load data sector if not in cache */
+#if !_FS_READONLY
+                if (fp->flag & FA__DIRTY) {     /* Write-back dirty sector cache */
+                    if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+                        ABORT(fp->fs, FR_DISK_ERR);
+                    fp->flag &= ~FA__DIRTY;
+                }
+#endif
+                if (disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK) /* Fill sector cache */
+                    ABORT(fp->fs, FR_DISK_ERR);
+            }
+#endif
+            fp->dsect = sect;
+        }
+        rcnt = SS(fp->fs) - ((UINT)fp->fptr % SS(fp->fs));  /* Get partial sector data from sector buffer */
+        if (rcnt > btr) rcnt = btr;
+#if _FS_TINY
+        if (move_window(fp->fs, fp->dsect))     /* Move sector window */
+            ABORT(fp->fs, FR_DISK_ERR);
+        mem_cpy(rbuff, &fp->fs->win[fp->fptr % SS(fp->fs)], rcnt);  /* Pick partial sector */
+#else
+        mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fp->fs)], rcnt);  /* Pick partial sector */
+#endif
+    }
+
+    LEAVE_FF(fp->fs, FR_OK);
+}
+
+
+
+
+#if !_FS_READONLY
+/*-----------------------------------------------------------------------*/
+/* Write File                                                            */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_write (
+    FIL *fp,            /* Pointer to the file object */
+    const void *buff,   /* Pointer to the data to be written */
+    UINT btw,           /* Number of bytes to write */
+    UINT *bw            /* Pointer to number of bytes written */
+)
+{
+    FRESULT res;
+    DWORD clst, sect;
+    UINT wcnt, cc;
+    const BYTE *wbuff = (const BYTE *)buff;
+    BYTE csect;
+
+
+    *bw = 0;    /* Clear write byte counter */
+
+    res = validate(fp);                     /* Check validity */
+    if (res != FR_OK) LEAVE_FF(fp->fs, res);
+    if (fp->flag & FA__ERROR)               /* Aborted file? */
+        LEAVE_FF(fp->fs, FR_INT_ERR);
+    if (!(fp->flag & FA_WRITE))             /* Check access mode */
+        LEAVE_FF(fp->fs, FR_DENIED);
+    if ((DWORD)(fp->fsize + btw) < fp->fsize) btw = 0;  /* File size cannot reach 4GB */
+
+    for ( ;  btw;                           /* Repeat until all data written */
+        wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) {
+        if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
+            csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1));    /* Sector offset in the cluster */
+            if (!csect) {                   /* On the cluster boundary? */
+                if (fp->fptr == 0) {        /* On the top of the file? */
+                    clst = fp->sclust;      /* Follow from the origin */
+                    if (clst == 0)          /* When no cluster is allocated, */
+                        fp->sclust = clst = create_chain(fp->fs, 0);    /* Create a new cluster chain */
+                } else {                    /* Middle or end of the file */
+#if _USE_FASTSEEK
+                    if (fp->cltbl)
+                        clst = clmt_clust(fp, fp->fptr);    /* Get cluster# from the CLMT */
+                    else
+#endif
+                        clst = create_chain(fp->fs, fp->clust); /* Follow or stretch cluster chain on the FAT */
+                }
+                if (clst == 0) break;       /* Could not allocate a new cluster (disk full) */
+                if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
+                if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+                fp->clust = clst;           /* Update current cluster */
+            }
+#if _FS_TINY
+            if (fp->fs->winsect == fp->dsect && move_window(fp->fs, 0)) /* Write-back sector cache */
+                ABORT(fp->fs, FR_DISK_ERR);
+#else
+            if (fp->flag & FA__DIRTY) {     /* Write-back sector cache */
+                if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+                    ABORT(fp->fs, FR_DISK_ERR);
+                fp->flag &= ~FA__DIRTY;
+            }
+#endif
+            sect = clust2sect(fp->fs, fp->clust);   /* Get current sector */
+            if (!sect) ABORT(fp->fs, FR_INT_ERR);
+            sect += csect;
+            cc = btw / SS(fp->fs);          /* When remaining bytes >= sector size, */
+            if (cc) {                       /* Write maximum contiguous sectors directly */
+                if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */
+                    cc = fp->fs->csize - csect;
+                if (disk_write(fp->fs->drv, wbuff, sect, (BYTE)cc) != RES_OK)
+                    ABORT(fp->fs, FR_DISK_ERR);
+#if _FS_TINY
+                if (fp->fs->winsect - sect < cc) {  /* Refill sector cache if it gets invalidated by the direct write */
+                    mem_cpy(fp->fs->win, wbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), SS(fp->fs));
+                    fp->fs->wflag = 0;
+                }
+#else
+                if (fp->dsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */
+                    mem_cpy(fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), SS(fp->fs));
+                    fp->flag &= ~FA__DIRTY;
+                }
+#endif
+                wcnt = SS(fp->fs) * cc;     /* Number of bytes transferred */
+                continue;
+            }
+#if _FS_TINY
+            if (fp->fptr >= fp->fsize) {    /* Avoid silly cache filling at growing edge */
+                if (move_window(fp->fs, 0)) ABORT(fp->fs, FR_DISK_ERR);
+                fp->fs->winsect = sect;
+            }
+#else
+            if (fp->dsect != sect) {        /* Fill sector cache with file data */
+                if (fp->fptr < fp->fsize &&
+                    disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK)
+                        ABORT(fp->fs, FR_DISK_ERR);
+            }
+#endif
+            fp->dsect = sect;
+        }
+        wcnt = SS(fp->fs) - ((UINT)fp->fptr % SS(fp->fs));/* Put partial sector into file I/O buffer */
+        if (wcnt > btw) wcnt = btw;
+#if _FS_TINY
+        if (move_window(fp->fs, fp->dsect)) /* Move sector window */
+            ABORT(fp->fs, FR_DISK_ERR);
+        mem_cpy(&fp->fs->win[fp->fptr % SS(fp->fs)], wbuff, wcnt);  /* Fit partial sector */
+        fp->fs->wflag = 1;
+#else
+        mem_cpy(&fp->buf[fp->fptr % SS(fp->fs)], wbuff, wcnt);  /* Fit partial sector */
+        fp->flag |= FA__DIRTY;
+#endif
+    }
+
+    if (fp->fptr > fp->fsize) fp->fsize = fp->fptr; /* Update file size if needed */
+    fp->flag |= FA__WRITTEN;                        /* Set file change flag */
+
+    LEAVE_FF(fp->fs, FR_OK);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Synchronize the File Object                                           */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_sync (
+    FIL *fp     /* Pointer to the file object */
+)
+{
+    FRESULT res;
+    DWORD tim;
+    BYTE *dir;
+
+
+    res = validate(fp);                 /* Check validity of the object */
+    if (res == FR_OK) {
+        if (fp->flag & FA__WRITTEN) {   /* Has the file been written? */
+#if !_FS_TINY   /* Write-back dirty buffer */
+            if (fp->flag & FA__DIRTY) {
+                if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+                    LEAVE_FF(fp->fs, FR_DISK_ERR);
+                fp->flag &= ~FA__DIRTY;
+            }
+#endif
+            /* Update the directory entry */
+            res = move_window(fp->fs, fp->dir_sect);
+            if (res == FR_OK) {
+                dir = fp->dir_ptr;
+                dir[DIR_Attr] |= AM_ARC;                    /* Set archive bit */
+                ST_DWORD(dir+DIR_FileSize, fp->fsize);      /* Update file size */
+                st_clust(dir, fp->sclust);                  /* Update start cluster */
+                tim = get_fattime();                        /* Update updated time */
+                ST_DWORD(dir+DIR_WrtTime, tim);
+                ST_WORD(dir+DIR_LstAccDate, 0);
+                fp->flag &= ~FA__WRITTEN;
+                fp->fs->wflag = 1;
+                res = sync(fp->fs);
+            }
+        }
+    }
+
+    LEAVE_FF(fp->fs, res);
+}
+
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Close File                                                            */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_close (
+    FIL *fp     /* Pointer to the file object to be closed */
+)
+{
+    FRESULT res;
+
+
+#if _FS_READONLY
+    res = validate(fp);
+    {
+#if _FS_REENTRANT
+        FATFS *fs = fp->fs;
+#endif
+        if (res == FR_OK) fp->fs = 0;   /* Discard file object */
+        LEAVE_FF(fs, res);
+    }
+#else
+    res = f_sync(fp);       /* Flush cached data */
+#if _FS_LOCK
+    if (res == FR_OK) {     /* Decrement open counter */
+#if _FS_REENTRANT
+        FATFS *fs = fp->fs;;
+        res = validate(fp);
+        if (res == FR_OK) {
+            res = dec_lock(fp->lockid);
+            unlock_fs(fs, FR_OK);
+        }
+#else
+        res = dec_lock(fp->lockid);
+#endif
+    }
+#endif
+    if (res == FR_OK) fp->fs = 0;   /* Discard file object */
+    return res;
+#endif
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Current Drive/Directory Handlings                                     */
+/*-----------------------------------------------------------------------*/
+
+#if _FS_RPATH >= 1
+
+FRESULT f_chdrive (
+    BYTE drv        /* Drive number */
+)
+{
+    if (drv >= _VOLUMES) return FR_INVALID_DRIVE;
+
+    CurrVol = drv;
+
+    return FR_OK;
+}
+
+
+
+FRESULT f_chdir (
+    const TCHAR *path   /* Pointer to the directory path */
+)
+{
+    FRESULT res;
+    DIR dj;
+    DEF_NAMEBUF;
+
+
+    res = chk_mounted(&path, &dj.fs, 0);
+    if (res == FR_OK) {
+        INIT_BUF(dj);
+        res = follow_path(&dj, path);       /* Follow the path */
+        FREE_BUF();
+        if (res == FR_OK) {                 /* Follow completed */
+            if (!dj.dir) {
+                dj.fs->cdir = dj.sclust;    /* Start directory itself */
+            } else {
+                if (dj.dir[DIR_Attr] & AM_DIR)  /* Reached to the directory */
+                    dj.fs->cdir = ld_clust(dj.fs, dj.dir);
+                else
+                    res = FR_NO_PATH;       /* Reached but a file */
+            }
+        }
+        if (res == FR_NO_FILE) res = FR_NO_PATH;
+    }
+
+    LEAVE_FF(dj.fs, res);
+}
+
+
+#if _FS_RPATH >= 2
+FRESULT f_getcwd (
+    TCHAR *path,    /* Pointer to the directory path */
+    UINT sz_path    /* Size of path */
+)
+{
+    FRESULT res;
+    DIR dj;
+    UINT i, n;
+    DWORD ccl;
+    TCHAR *tp;
+    FILINFO fno;
+    DEF_NAMEBUF;
+
+
+    *path = 0;
+    res = chk_mounted((const TCHAR**)&path, &dj.fs, 0); /* Get current volume */
+    if (res == FR_OK) {
+        INIT_BUF(dj);
+        i = sz_path;        /* Bottom of buffer (dir stack base) */
+        dj.sclust = dj.fs->cdir;            /* Start to follow upper dir from current dir */
+        while ((ccl = dj.sclust) != 0) {    /* Repeat while current dir is a sub-dir */
+            res = dir_sdi(&dj, 1);          /* Get parent dir */
+            if (res != FR_OK) break;
+            res = dir_read(&dj);
+            if (res != FR_OK) break;
+            dj.sclust = ld_clust(dj.fs, dj.dir);    /* Goto parent dir */
+            res = dir_sdi(&dj, 0);
+            if (res != FR_OK) break;
+            do {                            /* Find the entry links to the child dir */
+                res = dir_read(&dj);
+                if (res != FR_OK) break;
+                if (ccl == ld_clust(dj.fs, dj.dir)) break;  /* Found the entry */
+                res = dir_next(&dj, 0);
+            } while (res == FR_OK);
+            if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */
+            if (res != FR_OK) break;
+#if _USE_LFN
+            fno.lfname = path;
+            fno.lfsize = i;
+#endif
+            get_fileinfo(&dj, &fno);        /* Get the dir name and push it to the buffer */
+            tp = fno.fname;
+            if (_USE_LFN && *path) tp = path;
+            for (n = 0; tp[n]; n++) ;
+            if (i < n + 3) {
+                res = FR_NOT_ENOUGH_CORE; break;
+            }
+            while (n) path[--i] = tp[--n];
+            path[--i] = '/';
+        }
+        tp = path;
+        if (res == FR_OK) {
+            *tp++ = '0' + CurrVol;          /* Put drive number */
+            *tp++ = ':';
+            if (i == sz_path) {             /* Root-dir */
+                *tp++ = '/';
+            } else {                        /* Sub-dir */
+                do      /* Add stacked path str */
+                    *tp++ = path[i++];
+                while (i < sz_path);
+            }
+        }
+        *tp = 0;
+        FREE_BUF();
+    }
+
+    LEAVE_FF(dj.fs, res);
+}
+#endif /* _FS_RPATH >= 2 */
+#endif /* _FS_RPATH >= 1 */
+
+
+
+#if _FS_MINIMIZE <= 2
+/*-----------------------------------------------------------------------*/
+/* Seek File R/W Pointer                                                 */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_lseek (
+    FIL *fp,        /* Pointer to the file object */
+    DWORD ofs       /* File pointer from top of file */
+)
+{
+    FRESULT res;
+
+
+    res = validate(fp);                 /* Check validity of the object */
+    if (res != FR_OK) LEAVE_FF(fp->fs, res);
+    if (fp->flag & FA__ERROR)           /* Check abort flag */
+        LEAVE_FF(fp->fs, FR_INT_ERR);
+
+#if _USE_FASTSEEK
+    if (fp->cltbl) {    /* Fast seek */
+        DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl;
+
+        if (ofs == CREATE_LINKMAP) {    /* Create CLMT */
+            tbl = fp->cltbl;
+            tlen = *tbl++; ulen = 2;    /* Given table size and required table size */
+            cl = fp->sclust;            /* Top of the chain */
+            if (cl) {
+                do {
+                    /* Get a fragment */
+                    tcl = cl; ncl = 0; ulen += 2;   /* Top, length and used items */
+                    do {
+                        pcl = cl; ncl++;
+                        cl = get_fat(fp->fs, cl);
+                        if (cl <= 1) ABORT(fp->fs, FR_INT_ERR);
+                        if (cl == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+                    } while (cl == pcl + 1);
+                    if (ulen <= tlen) {     /* Store the length and top of the fragment */
+                        *tbl++ = ncl; *tbl++ = tcl;
+                    }
+                } while (cl < fp->fs->n_fatent);    /* Repeat until end of chain */
+            }
+            *fp->cltbl = ulen;  /* Number of items used */
+            if (ulen <= tlen)
+                *tbl = 0;       /* Terminate table */
+            else
+                res = FR_NOT_ENOUGH_CORE;   /* Given table size is smaller than required */
+
+        } else {                        /* Fast seek */
+            if (ofs > fp->fsize)        /* Clip offset at the file size */
+                ofs = fp->fsize;
+            fp->fptr = ofs;             /* Set file pointer */
+            if (ofs) {
+                fp->clust = clmt_clust(fp, ofs - 1);
+                dsc = clust2sect(fp->fs, fp->clust);
+                if (!dsc) ABORT(fp->fs, FR_INT_ERR);
+                dsc += (ofs - 1) / SS(fp->fs) & (fp->fs->csize - 1);
+                if (fp->fptr % SS(fp->fs) && dsc != fp->dsect) {    /* Refill sector cache if needed */
+#if !_FS_TINY
+#if !_FS_READONLY
+                    if (fp->flag & FA__DIRTY) {     /* Write-back dirty sector cache */
+                        if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+                            ABORT(fp->fs, FR_DISK_ERR);
+                        fp->flag &= ~FA__DIRTY;
+                    }
+#endif
+                    if (disk_read(fp->fs->drv, fp->buf, dsc, 1) != RES_OK)  /* Load current sector */
+                        ABORT(fp->fs, FR_DISK_ERR);
+#endif
+                    fp->dsect = dsc;
+                }
+            }
+        }
+    } else
+#endif
+
+    /* Normal Seek */
+    {
+        DWORD clst, bcs, nsect, ifptr;
+
+        if (ofs > fp->fsize                 /* In read-only mode, clip offset with the file size */
+#if !_FS_READONLY
+             && !(fp->flag & FA_WRITE)
+#endif
+            ) ofs = fp->fsize;
+
+        ifptr = fp->fptr;
+        fp->fptr = nsect = 0;
+        if (ofs) {
+            bcs = (DWORD)fp->fs->csize * SS(fp->fs);    /* Cluster size (byte) */
+            if (ifptr > 0 &&
+                (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */
+                fp->fptr = (ifptr - 1) & ~(bcs - 1);    /* start from the current cluster */
+                ofs -= fp->fptr;
+                clst = fp->clust;
+            } else {                                    /* When seek to back cluster, */
+                clst = fp->sclust;                      /* start from the first cluster */
+#if !_FS_READONLY
+                if (clst == 0) {                        /* If no cluster chain, create a new chain */
+                    clst = create_chain(fp->fs, 0);
+                    if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
+                    if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+                    fp->sclust = clst;
+                }
+#endif
+                fp->clust = clst;
+            }
+            if (clst != 0) {
+                while (ofs > bcs) {                     /* Cluster following loop */
+#if !_FS_READONLY
+                    if (fp->flag & FA_WRITE) {          /* Check if in write mode or not */
+                        clst = create_chain(fp->fs, clst);  /* Force stretch if in write mode */
+                        if (clst == 0) {                /* When disk gets full, clip file size */
+                            ofs = bcs; break;
+                        }
+                    } else
+#endif
+                        clst = get_fat(fp->fs, clst);   /* Follow cluster chain if not in write mode */
+                    if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+                    if (clst <= 1 || clst >= fp->fs->n_fatent) ABORT(fp->fs, FR_INT_ERR);
+                    fp->clust = clst;
+                    fp->fptr += bcs;
+                    ofs -= bcs;
+                }
+                fp->fptr += ofs;
+                if (ofs % SS(fp->fs)) {
+                    nsect = clust2sect(fp->fs, clst);   /* Current sector */
+                    if (!nsect) ABORT(fp->fs, FR_INT_ERR);
+                    nsect += ofs / SS(fp->fs);
+                }
+            }
+        }
+        if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) {  /* Fill sector cache if needed */
+#if !_FS_TINY
+#if !_FS_READONLY
+            if (fp->flag & FA__DIRTY) {         /* Write-back dirty sector cache */
+                if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+                    ABORT(fp->fs, FR_DISK_ERR);
+                fp->flag &= ~FA__DIRTY;
+            }
+#endif
+            if (disk_read(fp->fs->drv, fp->buf, nsect, 1) != RES_OK)    /* Fill sector cache */
+                ABORT(fp->fs, FR_DISK_ERR);
+#endif
+            fp->dsect = nsect;
+        }
+#if !_FS_READONLY
+        if (fp->fptr > fp->fsize) {         /* Set file change flag if the file size is extended */
+            fp->fsize = fp->fptr;
+            fp->flag |= FA__WRITTEN;
+        }
+#endif
+    }
+
+    LEAVE_FF(fp->fs, res);
+}
+
+
+
+#if _FS_MINIMIZE <= 1
+/*-----------------------------------------------------------------------*/
+/* Create a Directory Object                                             */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_opendir (
+    FATFS_DIR *dj,            /* Pointer to directory object to create */
+    const TCHAR *path   /* Pointer to the directory path */
+)
+{
+    FRESULT res;
+    FATFS *fs;
+    DEF_NAMEBUF;
+
+
+    if (!dj) return FR_INVALID_OBJECT;
+
+    res = chk_mounted(&path, &dj->fs, 0);
+    fs = dj->fs;
+    if (res == FR_OK) {
+        INIT_BUF(*dj);
+        res = follow_path(dj, path);            /* Follow the path to the directory */
+        FREE_BUF();
+        if (res == FR_OK) {                     /* Follow completed */
+            if (dj->dir) {                      /* It is not the root dir */
+                if (dj->dir[DIR_Attr] & AM_DIR) {   /* The object is a directory */
+                    dj->sclust = ld_clust(fs, dj->dir);
+                } else {                        /* The object is not a directory */
+                    res = FR_NO_PATH;
+                }
+            }
+            if (res == FR_OK) {
+                dj->id = fs->id;
+                res = dir_sdi(dj, 0);           /* Rewind dir */
+            }
+        }
+        if (res == FR_NO_FILE) res = FR_NO_PATH;
+        if (res != FR_OK) dj->fs = 0;           /* Invalidate the dir object if function faild */
+    } else {
+        dj->fs = 0;
+    }
+
+    LEAVE_FF(fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read Directory Entry in Sequence                                      */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_readdir (
+    FATFS_DIR *dj,            /* Pointer to the open directory object */
+    FILINFO *fno        /* Pointer to file information to return */
+)
+{
+    FRESULT res;
+    DEF_NAMEBUF;
+
+
+    res = validate(dj);                     /* Check validity of the object */
+    if (res == FR_OK) {
+        if (!fno) {
+            res = dir_sdi(dj, 0);           /* Rewind the directory object */
+        } else {
+            INIT_BUF(*dj);
+            res = dir_read(dj);             /* Read an directory item */
+            if (res == FR_NO_FILE) {        /* Reached end of dir */
+                dj->sect = 0;
+                res = FR_OK;
+            }
+            if (res == FR_OK) {             /* A valid entry is found */
+                get_fileinfo(dj, fno);      /* Get the object information */
+                res = dir_next(dj, 0);      /* Increment index for next */
+                if (res == FR_NO_FILE) {
+                    dj->sect = 0;
+                    res = FR_OK;
+                }
+            }
+            FREE_BUF();
+        }
+    }
+
+    LEAVE_FF(dj->fs, res);
+}
+
+
+
+#if _FS_MINIMIZE == 0
+/*-----------------------------------------------------------------------*/
+/* Get File Status                                                       */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_stat (
+    const TCHAR *path,  /* Pointer to the file path */
+    FILINFO *fno        /* Pointer to file information to return */
+)
+{
+    FRESULT res;
+    FATFS_DIR dj;
+    DEF_NAMEBUF;
+
+
+    res = chk_mounted(&path, &dj.fs, 0);
+    if (res == FR_OK) {
+        INIT_BUF(dj);
+        res = follow_path(&dj, path);   /* Follow the file path */
+        if (res == FR_OK) {             /* Follow completed */
+            if (dj.dir)     /* Found an object */
+                get_fileinfo(&dj, fno);
+            else            /* It is root dir */
+                res = FR_INVALID_NAME;
+        }
+        FREE_BUF();
+    }
+
+    LEAVE_FF(dj.fs, res);
+}
+
+
+
+#if !_FS_READONLY
+/*-----------------------------------------------------------------------*/
+/* Get Number of Free Clusters                                           */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_getfree (
+    const TCHAR *path,  /* Pointer to the logical drive number (root dir) */
+    DWORD *nclst,       /* Pointer to the variable to return number of free clusters */
+    FATFS **fatfs       /* Pointer to pointer to corresponding file system object to return */
+)
+{
+    FRESULT res;
+    FATFS *fs;
+    DWORD n, clst, sect, stat;
+    UINT i;
+    BYTE fat, *p;
+
+
+    /* Get drive number */
+    res = chk_mounted(&path, fatfs, 0);
+    fs = *fatfs;
+    if (res == FR_OK) {
+        /* If free_clust is valid, return it without full cluster scan */
+        if (fs->free_clust <= fs->n_fatent - 2) {
+            *nclst = fs->free_clust;
+        } else {
+            /* Get number of free clusters */
+            fat = fs->fs_type;
+            n = 0;
+            if (fat == FS_FAT12) {
+                clst = 2;
+                do {
+                    stat = get_fat(fs, clst);
+                    if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }
+                    if (stat == 1) { res = FR_INT_ERR; break; }
+                    if (stat == 0) n++;
+                } while (++clst < fs->n_fatent);
+            } else {
+                clst = fs->n_fatent;
+                sect = fs->fatbase;
+                i = 0; p = 0;
+                do {
+                    if (!i) {
+                        res = move_window(fs, sect++);
+                        if (res != FR_OK) break;
+                        p = fs->win;
+                        i = SS(fs);
+                    }
+                    if (fat == FS_FAT16) {
+                        if (LD_WORD(p) == 0) n++;
+                        p += 2; i -= 2;
+                    } else {
+                        if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) n++;
+                        p += 4; i -= 4;
+                    }
+                } while (--clst);
+            }
+            fs->free_clust = n;
+            if (fat == FS_FAT32) fs->fsi_flag = 1;
+            *nclst = n;
+        }
+    }
+    LEAVE_FF(fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Truncate File                                                         */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_truncate (
+    FIL *fp     /* Pointer to the file object */
+)
+{
+    FRESULT res;
+    DWORD ncl;
+
+
+    if (!fp) return FR_INVALID_OBJECT;
+
+    res = validate(fp);                     /* Check validity of the object */
+    if (res == FR_OK) {
+        if (fp->flag & FA__ERROR) {         /* Check abort flag */
+            res = FR_INT_ERR;
+        } else {
+            if (!(fp->flag & FA_WRITE))     /* Check access mode */
+                res = FR_DENIED;
+        }
+    }
+    if (res == FR_OK) {
+        if (fp->fsize > fp->fptr) {
+            fp->fsize = fp->fptr;   /* Set file size to current R/W point */
+            fp->flag |= FA__WRITTEN;
+            if (fp->fptr == 0) {    /* When set file size to zero, remove entire cluster chain */
+                res = remove_chain(fp->fs, fp->sclust);
+                fp->sclust = 0;
+            } else {                /* When truncate a part of the file, remove remaining clusters */
+                ncl = get_fat(fp->fs, fp->clust);
+                res = FR_OK;
+                if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR;
+                if (ncl == 1) res = FR_INT_ERR;
+                if (res == FR_OK && ncl < fp->fs->n_fatent) {
+                    res = put_fat(fp->fs, fp->clust, 0x0FFFFFFF);
+                    if (res == FR_OK) res = remove_chain(fp->fs, ncl);
+                }
+            }
+        }
+        if (res != FR_OK) fp->flag |= FA__ERROR;
+    }
+
+    LEAVE_FF(fp->fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Delete a File or Directory                                            */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_unlink (
+    const TCHAR *path       /* Pointer to the file or directory path */
+)
+{
+    FRESULT res;
+    FATFS_DIR dj, sdj;
+    BYTE *dir;
+    DWORD dclst;
+    DEF_NAMEBUF;
+
+
+    res = chk_mounted(&path, &dj.fs, 1);
+    if (res == FR_OK) {
+        INIT_BUF(dj);
+        res = follow_path(&dj, path);       /* Follow the file path */
+        if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
+            res = FR_INVALID_NAME;          /* Cannot remove dot entry */
+#if _FS_LOCK
+        if (res == FR_OK) res = chk_lock(&dj, 2);   /* Cannot remove open file */
+#endif
+        if (res == FR_OK) {                 /* The object is accessible */
+            dir = dj.dir;
+            if (!dir) {
+                res = FR_INVALID_NAME;      /* Cannot remove the start directory */
+            } else {
+                if (dir[DIR_Attr] & AM_RDO)
+                    res = FR_DENIED;        /* Cannot remove R/O object */
+            }
+            dclst = ld_clust(dj.fs, dir);
+            if (res == FR_OK && (dir[DIR_Attr] & AM_DIR)) { /* Is it a sub-dir? */
+                if (dclst < 2) {
+                    res = FR_INT_ERR;
+                } else {
+                    mem_cpy(&sdj, &dj, sizeof (FATFS_DIR));   /* Check if the sub-dir is empty or not */
+                    sdj.sclust = dclst;
+                    res = dir_sdi(&sdj, 2);     /* Exclude dot entries */
+                    if (res == FR_OK) {
+                        res = dir_read(&sdj);
+                        if (res == FR_OK        /* Not empty dir */
+#if _FS_RPATH
+                        || dclst == dj.fs->cdir /* Current dir */
+#endif
+                        ) res = FR_DENIED;
+                        if (res == FR_NO_FILE) res = FR_OK; /* Empty */
+                    }
+                }
+            }
+            if (res == FR_OK) {
+                res = dir_remove(&dj);      /* Remove the directory entry */
+                if (res == FR_OK) {
+                    if (dclst)              /* Remove the cluster chain if exist */
+                        res = remove_chain(dj.fs, dclst);
+                    if (res == FR_OK) res = sync(dj.fs);
+                }
+            }
+        }
+        FREE_BUF();
+    }
+    LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Create a Directory                                                    */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_mkdir (
+    const TCHAR *path       /* Pointer to the directory path */
+)
+{
+    FRESULT res;
+    FATFS_DIR dj;
+    BYTE *dir, n;
+    DWORD dsc, dcl, pcl, tim = get_fattime();
+    DEF_NAMEBUF;
+
+
+    res = chk_mounted(&path, &dj.fs, 1);
+    if (res == FR_OK) {
+        INIT_BUF(dj);
+        res = follow_path(&dj, path);           /* Follow the file path */
+        if (res == FR_OK) res = FR_EXIST;       /* Any object with same name is already existing */
+        if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NS] & NS_DOT))
+            res = FR_INVALID_NAME;
+        if (res == FR_NO_FILE) {                /* Can create a new directory */
+            dcl = create_chain(dj.fs, 0);       /* Allocate a cluster for the new directory table */
+            res = FR_OK;
+            if (dcl == 0) res = FR_DENIED;      /* No space to allocate a new cluster */
+            if (dcl == 1) res = FR_INT_ERR;
+            if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR;
+            if (res == FR_OK)                   /* Flush FAT */
+                res = move_window(dj.fs, 0);
+            if (res == FR_OK) {                 /* Initialize the new directory table */
+                dsc = clust2sect(dj.fs, dcl);
+                dir = dj.fs->win;
+                mem_set(dir, 0, SS(dj.fs));
+                mem_set(dir+DIR_Name, ' ', 8+3);    /* Create "." entry */
+                dir[DIR_Name] = '.';
+                dir[DIR_Attr] = AM_DIR;
+                ST_DWORD(dir+DIR_WrtTime, tim);
+                st_clust(dir, dcl);
+                mem_cpy(dir+SZ_DIR, dir, SZ_DIR);   /* Create ".." entry */
+                dir[33] = '.'; pcl = dj.sclust;
+                if (dj.fs->fs_type == FS_FAT32 && pcl == dj.fs->dirbase)
+                    pcl = 0;
+                st_clust(dir+SZ_DIR, pcl);
+                for (n = dj.fs->csize; n; n--) {    /* Write dot entries and clear following sectors */
+                    dj.fs->winsect = dsc++;
+                    dj.fs->wflag = 1;
+                    res = move_window(dj.fs, 0);
+                    if (res != FR_OK) break;
+                    mem_set(dir, 0, SS(dj.fs));
+                }
+            }
+            if (res == FR_OK) res = dir_register(&dj);  /* Register the object to the directoy */
+            if (res != FR_OK) {
+                remove_chain(dj.fs, dcl);           /* Could not register, remove cluster chain */
+            } else {
+                dir = dj.dir;
+                dir[DIR_Attr] = AM_DIR;             /* Attribute */
+                ST_DWORD(dir+DIR_WrtTime, tim);     /* Created time */
+                st_clust(dir, dcl);                 /* Table start cluster */
+                dj.fs->wflag = 1;
+                res = sync(dj.fs);
+            }
+        }
+        FREE_BUF();
+    }
+
+    LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change Attribute                                                      */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_chmod (
+    const TCHAR *path,  /* Pointer to the file path */
+    BYTE value,         /* Attribute bits */
+    BYTE mask           /* Attribute mask to change */
+)
+{
+    FRESULT res;
+    FATFS_DIR dj;
+    BYTE *dir;
+    DEF_NAMEBUF;
+
+
+    res = chk_mounted(&path, &dj.fs, 1);
+    if (res == FR_OK) {
+        INIT_BUF(dj);
+        res = follow_path(&dj, path);       /* Follow the file path */
+        FREE_BUF();
+        if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
+            res = FR_INVALID_NAME;
+        if (res == FR_OK) {
+            dir = dj.dir;
+            if (!dir) {                     /* Is it a root directory? */
+                res = FR_INVALID_NAME;
+            } else {                        /* File or sub directory */
+                mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC;    /* Valid attribute mask */
+                dir[DIR_Attr] = (value & mask) | (dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */
+                dj.fs->wflag = 1;
+                res = sync(dj.fs);
+            }
+        }
+    }
+
+    LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change Timestamp                                                      */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_utime (
+    const TCHAR *path,  /* Pointer to the file/directory name */
+    const FILINFO *fno  /* Pointer to the time stamp to be set */
+)
+{
+    FRESULT res;
+    FATFS_DIR dj;
+    BYTE *dir;
+    DEF_NAMEBUF;
+
+
+    res = chk_mounted(&path, &dj.fs, 1);
+    if (res == FR_OK) {
+        INIT_BUF(dj);
+        res = follow_path(&dj, path);   /* Follow the file path */
+        FREE_BUF();
+        if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
+            res = FR_INVALID_NAME;
+        if (res == FR_OK) {
+            dir = dj.dir;
+            if (!dir) {                 /* Root directory */
+                res = FR_INVALID_NAME;
+            } else {                    /* File or sub-directory */
+                ST_WORD(dir+DIR_WrtTime, fno->ftime);
+                ST_WORD(dir+DIR_WrtDate, fno->fdate);
+                dj.fs->wflag = 1;
+                res = sync(dj.fs);
+            }
+        }
+    }
+
+    LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Rename File/Directory                                                 */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_rename (
+    const TCHAR *path_old,  /* Pointer to the old name */
+    const TCHAR *path_new   /* Pointer to the new name */
+)
+{
+    FRESULT res;
+    FATFS_DIR djo, djn;
+    BYTE buf[21], *dir;
+    DWORD dw;
+    DEF_NAMEBUF;
+
+
+    res = chk_mounted(&path_old, &djo.fs, 1);
+    if (res == FR_OK) {
+        djn.fs = djo.fs;
+        INIT_BUF(djo);
+        res = follow_path(&djo, path_old);      /* Check old object */
+        if (_FS_RPATH && res == FR_OK && (djo.fn[NS] & NS_DOT))
+            res = FR_INVALID_NAME;
+#if _FS_LOCK
+        if (res == FR_OK) res = chk_lock(&djo, 2);
+#endif
+        if (res == FR_OK) {                     /* Old object is found */
+            if (!djo.dir) {                     /* Is root dir? */
+                res = FR_NO_FILE;
+            } else {
+                mem_cpy(buf, djo.dir+DIR_Attr, 21);     /* Save the object information except for name */
+                mem_cpy(&djn, &djo, sizeof (FATFS_DIR));      /* Check new object */
+                res = follow_path(&djn, path_new);
+                if (res == FR_OK) res = FR_EXIST;       /* The new object name is already existing */
+                if (res == FR_NO_FILE) {                /* Is it a valid path and no name collision? */
+/* Start critical section that an interruption or error can cause cross-link */
+                    res = dir_register(&djn);           /* Register the new entry */
+                    if (res == FR_OK) {
+                        dir = djn.dir;                  /* Copy object information except for name */
+                        mem_cpy(dir+13, buf+2, 19);
+                        dir[DIR_Attr] = buf[0] | AM_ARC;
+                        djo.fs->wflag = 1;
+                        if (djo.sclust != djn.sclust && (dir[DIR_Attr] & AM_DIR)) {     /* Update .. entry in the directory if needed */
+                            dw = clust2sect(djo.fs, ld_clust(djo.fs, dir));
+                            if (!dw) {
+                                res = FR_INT_ERR;
+                            } else {
+                                res = move_window(djo.fs, dw);
+                                dir = djo.fs->win+SZ_DIR;   /* .. entry */
+                                if (res == FR_OK && dir[1] == '.') {
+                                    dw = (djo.fs->fs_type == FS_FAT32 && djn.sclust == djo.fs->dirbase) ? 0 : djn.sclust;
+                                    st_clust(dir, dw);
+                                    djo.fs->wflag = 1;
+                                }
+                            }
+                        }
+                        if (res == FR_OK) {
+                            res = dir_remove(&djo);     /* Remove old entry */
+                            if (res == FR_OK)
+                                res = sync(djo.fs);
+                        }
+                    }
+/* End critical section */
+                }
+            }
+        }
+        FREE_BUF();
+    }
+    LEAVE_FF(djo.fs, res);
+}
+
+#endif /* !_FS_READONLY */
+#endif /* _FS_MINIMIZE == 0 */
+#endif /* _FS_MINIMIZE <= 1 */
+#endif /* _FS_MINIMIZE <= 2 */
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Forward data to the stream directly (available on only tiny cfg)      */
+/*-----------------------------------------------------------------------*/
+#if _USE_FORWARD && _FS_TINY
+
+FRESULT f_forward (
+    FIL *fp,                        /* Pointer to the file object */
+    UINT (*func)(const BYTE*,UINT), /* Pointer to the streaming function */
+    UINT btr,                       /* Number of bytes to forward */
+    UINT *bf                        /* Pointer to number of bytes forwarded */
+)
+{
+    FRESULT res;
+    DWORD remain, clst, sect;
+    UINT rcnt;
+    BYTE csect;
+
+
+    *bf = 0;    /* Clear transfer byte counter */
+
+    if (!fp) return FR_INVALID_OBJECT;
+
+    res = validate(fp);                             /* Check validity of the object */
+    if (res != FR_OK) LEAVE_FF(fp->fs, res);
+    if (fp->flag & FA__ERROR)                       /* Check error flag */
+        LEAVE_FF(fp->fs, FR_INT_ERR);
+    if (!(fp->flag & FA_READ))                      /* Check access mode */
+        LEAVE_FF(fp->fs, FR_DENIED);
+
+    remain = fp->fsize - fp->fptr;
+    if (btr > remain) btr = (UINT)remain;           /* Truncate btr by remaining bytes */
+
+    for ( ;  btr && (*func)(0, 0);                  /* Repeat until all data transferred or stream becomes busy */
+        fp->fptr += rcnt, *bf += rcnt, btr -= rcnt) {
+        csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1));    /* Sector offset in the cluster */
+        if ((fp->fptr % SS(fp->fs)) == 0) {         /* On the sector boundary? */
+            if (!csect) {                           /* On the cluster boundary? */
+                clst = (fp->fptr == 0) ?            /* On the top of the file? */
+                    fp->sclust : get_fat(fp->fs, fp->clust);
+                if (clst <= 1) ABORT(fp->fs, FR_INT_ERR);
+                if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+                fp->clust = clst;                   /* Update current cluster */
+            }
+        }
+        sect = clust2sect(fp->fs, fp->clust);       /* Get current data sector */
+        if (!sect) ABORT(fp->fs, FR_INT_ERR);
+        sect += csect;
+        if (move_window(fp->fs, sect))              /* Move sector window */
+            ABORT(fp->fs, FR_DISK_ERR);
+        fp->dsect = sect;
+        rcnt = SS(fp->fs) - (WORD)(fp->fptr % SS(fp->fs));  /* Forward data from sector window */
+        if (rcnt > btr) rcnt = btr;
+        rcnt = (*func)(&fp->fs->win[(WORD)fp->fptr % SS(fp->fs)], rcnt);
+        if (!rcnt) ABORT(fp->fs, FR_INT_ERR);
+    }
+
+    LEAVE_FF(fp->fs, FR_OK);
+}
+#endif /* _USE_FORWARD */
+
+
+
+#if _USE_MKFS && !_FS_READONLY
+/*-----------------------------------------------------------------------*/
+/* Create File System on the Drive                                       */
+/*-----------------------------------------------------------------------*/
+#define N_ROOTDIR   512     /* Number of root dir entries for FAT12/16 */
+#define N_FATS      1       /* Number of FAT copies (1 or 2) */
+
+
+FRESULT f_mkfs (
+    BYTE drv,       /* Logical drive number */
+    BYTE sfd,       /* Partitioning rule 0:FDISK, 1:SFD */
+    UINT au         /* Allocation unit size [bytes] */
+)
+{
+    static const WORD vst[] = { 1024,   512,  256,  128,   64,    32,   16,    8,    4,    2,   0};
+    static const WORD cst[] = {32768, 16384, 8192, 4096, 2048, 16384, 8192, 4096, 2048, 1024, 512};
+    BYTE fmt, md, sys, *tbl, pdrv, part;
+    DWORD n_clst, vs, n, wsect;
+    UINT i;
+    DWORD b_vol, b_fat, b_dir, b_data;  /* LBA */
+    DWORD n_vol, n_rsv, n_fat, n_dir;   /* Size */
+    FATFS *fs;
+    DSTATUS stat;
+
+
+    /* Check mounted drive and clear work area */
+    if (drv >= _VOLUMES) return FR_INVALID_DRIVE;
+    if (sfd > 1) return FR_INVALID_PARAMETER;
+    if (au & (au - 1)) return FR_INVALID_PARAMETER;
+    fs = FatFs[drv];
+    if (!fs) return FR_NOT_ENABLED;
+    fs->fs_type = 0;
+    pdrv = LD2PD(drv);  /* Physical drive */
+    part = LD2PT(drv);  /* Partition (0:auto detect, 1-4:get from partition table)*/
+
+    /* Get disk statics */
+    stat = disk_initialize(pdrv);
+    if (stat & STA_NOINIT) return FR_NOT_READY;
+    if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
+#if _MAX_SS != 512                  /* Get disk sector size */
+    if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS)
+        return FR_DISK_ERR;
+#endif
+    if (_MULTI_PARTITION && part) {
+        /* Get partition information from partition table in the MBR */
+        if (disk_read(pdrv, fs->win, 0, 1) != RES_OK) return FR_DISK_ERR;
+        if (LD_WORD(fs->win+BS_55AA) != 0xAA55) return FR_MKFS_ABORTED;
+        tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE];
+        if (!tbl[4]) return FR_MKFS_ABORTED;    /* No partition? */
+        b_vol = LD_DWORD(tbl+8);    /* Volume start sector */
+        n_vol = LD_DWORD(tbl+12);   /* Volume size */
+    } else {
+        /* Create a partition in this function */
+        if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < 128)
+            return FR_DISK_ERR;
+        b_vol = (sfd) ? 0 : 63;     /* Volume start sector */
+        n_vol -= b_vol;             /* Volume size */
+    }
+
+    if (!au) {              /* AU auto selection */
+        vs = n_vol / (2000 / (SS(fs) / 512));
+        for (i = 0; vs < vst[i]; i++) ;
+        au = cst[i];
+    }
+    au /= SS(fs);       /* Number of sectors per cluster */
+    if (au == 0) au = 1;
+    if (au > 128) au = 128;
+
+    /* Pre-compute number of clusters and FAT sub-type */
+    n_clst = n_vol / au;
+    fmt = FS_FAT12;
+    if (n_clst >= MIN_FAT16) fmt = FS_FAT16;
+    if (n_clst >= MIN_FAT32) fmt = FS_FAT32;
+
+    /* Determine offset and size of FAT structure */
+    if (fmt == FS_FAT32) {
+        n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs);
+        n_rsv = 32;
+        n_dir = 0;
+    } else {
+        n_fat = (fmt == FS_FAT12) ? (n_clst * 3 + 1) / 2 + 3 : (n_clst * 2) + 4;
+        n_fat = (n_fat + SS(fs) - 1) / SS(fs);
+        n_rsv = 1;
+        n_dir = (DWORD)N_ROOTDIR * SZ_DIR / SS(fs);
+    }
+    b_fat = b_vol + n_rsv;              /* FAT area start sector */
+    b_dir = b_fat + n_fat * N_FATS;     /* Directory area start sector */
+    b_data = b_dir + n_dir;             /* Data area start sector */
+    if (n_vol < b_data + au - b_vol) return FR_MKFS_ABORTED;    /* Too small volume */
+
+    /* Align data start sector to erase block boundary (for flash memory media) */
+    if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &n) != RES_OK || !n || n > 32768) n = 1;
+    n = (b_data + n - 1) & ~(n - 1);    /* Next nearest erase block from current data start */
+    n = (n - b_data) / N_FATS;
+    if (fmt == FS_FAT32) {      /* FAT32: Move FAT offset */
+        n_rsv += n;
+        b_fat += n;
+    } else {                    /* FAT12/16: Expand FAT size */
+        n_fat += n;
+    }
+
+    /* Determine number of clusters and final check of validity of the FAT sub-type */
+    n_clst = (n_vol - n_rsv - n_fat * N_FATS - n_dir) / au;
+    if (   (fmt == FS_FAT16 && n_clst < MIN_FAT16)
+        || (fmt == FS_FAT32 && n_clst < MIN_FAT32))
+        return FR_MKFS_ABORTED;
+
+    switch (fmt) {  /* Determine system ID for partition table */
+    case FS_FAT12:  sys = 0x01; break;
+    case FS_FAT16:  sys = (n_vol < 0x10000) ? 0x04 : 0x06; break;
+    default:        sys = 0x0C;
+    }
+
+    if (_MULTI_PARTITION && part) {
+        /* Update system ID in the partition table */
+        tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE];
+        tbl[4] = sys;
+        if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) return FR_DISK_ERR;
+        md = 0xF8;
+    } else {
+        if (sfd) {  /* No partition table (SFD) */
+            md = 0xF0;
+        } else {    /* Create partition table (FDISK) */
+            mem_set(fs->win, 0, SS(fs));
+            tbl = fs->win+MBR_Table;    /* Create partition table for single partition in the drive */
+            tbl[1] = 1;                     /* Partition start head */
+            tbl[2] = 1;                     /* Partition start sector */
+            tbl[3] = 0;                     /* Partition start cylinder */
+            tbl[4] = sys;                   /* System type */
+            tbl[5] = 254;                   /* Partition end head */
+            n = (b_vol + n_vol) / 63 / 255;
+            tbl[6] = (BYTE)((n >> 2) | 63); /* Partition end sector */
+            tbl[7] = (BYTE)n;               /* End cylinder */
+            ST_DWORD(tbl+8, 63);            /* Partition start in LBA */
+            ST_DWORD(tbl+12, n_vol);        /* Partition size in LBA */
+            ST_WORD(fs->win+BS_55AA, 0xAA55);   /* MBR signature */
+            if (disk_write(pdrv, fs->win, 0, 1) != RES_OK)  /* Write it to the MBR sector */
+                return FR_DISK_ERR;
+            md = 0xF8;
+        }
+    }
+
+    /* Create BPB in the VBR */
+    tbl = fs->win;                          /* Clear sector */
+    mem_set(tbl, 0, SS(fs));
+    mem_cpy(tbl, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code, OEM name */
+    i = SS(fs);                             /* Sector size */
+    ST_WORD(tbl+BPB_BytsPerSec, i);
+    tbl[BPB_SecPerClus] = (BYTE)au;         /* Sectors per cluster */
+    ST_WORD(tbl+BPB_RsvdSecCnt, n_rsv);     /* Reserved sectors */
+    tbl[BPB_NumFATs] = N_FATS;              /* Number of FATs */
+    i = (fmt == FS_FAT32) ? 0 : N_ROOTDIR;  /* Number of rootdir entries */
+    ST_WORD(tbl+BPB_RootEntCnt, i);
+    if (n_vol < 0x10000) {                  /* Number of total sectors */
+        ST_WORD(tbl+BPB_TotSec16, n_vol);
+    } else {
+        ST_DWORD(tbl+BPB_TotSec32, n_vol);
+    }
+    tbl[BPB_Media] = md;                    /* Media descriptor */
+    ST_WORD(tbl+BPB_SecPerTrk, 63);         /* Number of sectors per track */
+    ST_WORD(tbl+BPB_NumHeads, 255);         /* Number of heads */
+    ST_DWORD(tbl+BPB_HiddSec, b_vol);       /* Hidden sectors */
+    n = get_fattime();                      /* Use current time as VSN */
+    if (fmt == FS_FAT32) {
+        ST_DWORD(tbl+BS_VolID32, n);        /* VSN */
+        ST_DWORD(tbl+BPB_FATSz32, n_fat);   /* Number of sectors per FAT */
+        ST_DWORD(tbl+BPB_RootClus, 2);      /* Root directory start cluster (2) */
+        ST_WORD(tbl+BPB_FSInfo, 1);         /* FSInfo record offset (VBR+1) */
+        ST_WORD(tbl+BPB_BkBootSec, 6);      /* Backup boot record offset (VBR+6) */
+        tbl[BS_DrvNum32] = 0x80;            /* Drive number */
+        tbl[BS_BootSig32] = 0x29;           /* Extended boot signature */
+        mem_cpy(tbl+BS_VolLab32, "NO NAME    " "FAT32   ", 19); /* Volume label, FAT signature */
+    } else {
+        ST_DWORD(tbl+BS_VolID, n);          /* VSN */
+        ST_WORD(tbl+BPB_FATSz16, n_fat);    /* Number of sectors per FAT */
+        tbl[BS_DrvNum] = 0x80;              /* Drive number */
+        tbl[BS_BootSig] = 0x29;             /* Extended boot signature */
+        mem_cpy(tbl+BS_VolLab, "NO NAME    " "FAT     ", 19);   /* Volume label, FAT signature */
+    }
+    ST_WORD(tbl+BS_55AA, 0xAA55);           /* Signature (Offset is fixed here regardless of sector size) */
+    if (disk_write(pdrv, tbl, b_vol, 1) != RES_OK)  /* Write it to the VBR sector */
+        return FR_DISK_ERR;
+    if (fmt == FS_FAT32)                            /* Write backup VBR if needed (VBR+6) */
+        disk_write(pdrv, tbl, b_vol + 6, 1);
+
+    /* Initialize FAT area */
+    wsect = b_fat;
+    for (i = 0; i < N_FATS; i++) {      /* Initialize each FAT copy */
+        mem_set(tbl, 0, SS(fs));            /* 1st sector of the FAT  */
+        n = md;                             /* Media descriptor byte */
+        if (fmt != FS_FAT32) {
+            n |= (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00;
+            ST_DWORD(tbl+0, n);             /* Reserve cluster #0-1 (FAT12/16) */
+        } else {
+            n |= 0xFFFFFF00;
+            ST_DWORD(tbl+0, n);             /* Reserve cluster #0-1 (FAT32) */
+            ST_DWORD(tbl+4, 0xFFFFFFFF);
+            ST_DWORD(tbl+8, 0x0FFFFFFF);    /* Reserve cluster #2 for root dir */
+        }
+        if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
+            return FR_DISK_ERR;
+        mem_set(tbl, 0, SS(fs));            /* Fill following FAT entries with zero */
+        for (n = 1; n < n_fat; n++) {       /* This loop may take a time on FAT32 volume due to many single sector writes */
+            if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
+                return FR_DISK_ERR;
+        }
+    }
+
+    /* Initialize root directory */
+    i = (fmt == FS_FAT32) ? au : n_dir;
+    do {
+        if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
+            return FR_DISK_ERR;
+    } while (--i);
+
+#if _USE_ERASE  /* Erase data area if needed */
+    {
+        DWORD eb[2];
+
+        eb[0] = wsect; eb[1] = wsect + (n_clst - ((fmt == FS_FAT32) ? 1 : 0)) * au - 1;
+        disk_ioctl(pdrv, CTRL_ERASE_SECTOR, eb);
+    }
+#endif
+
+    /* Create FSInfo if needed */
+    if (fmt == FS_FAT32) {
+        ST_DWORD(tbl+FSI_LeadSig, 0x41615252);
+        ST_DWORD(tbl+FSI_StrucSig, 0x61417272);
+        ST_DWORD(tbl+FSI_Free_Count, n_clst - 1);   /* Number of free clusters */
+        ST_DWORD(tbl+FSI_Nxt_Free, 2);              /* Last allocated cluster# */
+        ST_WORD(tbl+BS_55AA, 0xAA55);
+        disk_write(pdrv, tbl, b_vol + 1, 1);    /* Write original (VBR+1) */
+        disk_write(pdrv, tbl, b_vol + 7, 1);    /* Write backup (VBR+7) */
+    }
+
+    return (disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR;
+}
+
+
+#if _MULTI_PARTITION == 2
+/*-----------------------------------------------------------------------*/
+/* Divide Physical Drive                                                 */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_fdisk (
+    BYTE pdrv,          /* Physical drive number */
+    const DWORD szt[],  /* Pointer to the size table for each partitions */
+    void* work          /* Pointer to the working buffer */
+)
+{
+    UINT i, n, sz_cyl, tot_cyl, b_cyl, e_cyl, p_cyl;
+    BYTE s_hd, e_hd, *p, *buf = (BYTE*)work;
+    DSTATUS stat;
+    DWORD sz_disk, sz_part, s_part;
+
+
+    stat = disk_initialize(pdrv);
+    if (stat & STA_NOINIT) return FR_NOT_READY;
+    if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
+    if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR;
+
+    /* Determine CHS in the table regardless of the drive geometry */
+    for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) ;
+    if (n == 256) n--;
+    e_hd = n - 1;
+    sz_cyl = 63 * n;
+    tot_cyl = sz_disk / sz_cyl;
+
+    /* Create partition table */
+    mem_set(buf, 0, _MAX_SS);
+    p = buf + MBR_Table; b_cyl = 0;
+    for (i = 0; i < 4; i++, p += SZ_PTE) {
+        p_cyl = (szt[i] <= 100) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl;
+        if (!p_cyl) continue;
+        s_part = (DWORD)sz_cyl * b_cyl;
+        sz_part = (DWORD)sz_cyl * p_cyl;
+        if (i == 0) {   /* Exclude first track of cylinder 0 */
+            s_hd = 1;
+            s_part += 63; sz_part -= 63;
+        } else {
+            s_hd = 0;
+        }
+        e_cyl = b_cyl + p_cyl - 1;
+        if (e_cyl >= tot_cyl) return FR_INVALID_PARAMETER;
+
+        /* Set partition table */
+        p[1] = s_hd;                        /* Start head */
+        p[2] = (BYTE)((b_cyl >> 2) + 1);    /* Start sector */
+        p[3] = (BYTE)b_cyl;                 /* Start cylinder */
+        p[4] = 0x06;                        /* System type (temporary setting) */
+        p[5] = e_hd;                        /* End head */
+        p[6] = (BYTE)((e_cyl >> 2) + 63);   /* End sector */
+        p[7] = (BYTE)e_cyl;                 /* End cylinder */
+        ST_DWORD(p + 8, s_part);            /* Start sector in LBA */
+        ST_DWORD(p + 12, sz_part);          /* Partition size */
+
+        /* Next partition */
+        b_cyl += p_cyl;
+    }
+    ST_WORD(p, 0xAA55);
+
+    /* Write it to the MBR */
+    return (disk_write(pdrv, buf, 0, 1) || disk_ioctl(pdrv, CTRL_SYNC, 0)) ? FR_DISK_ERR : FR_OK;
+}
+
+
+#endif /* _MULTI_PARTITION == 2 */
+#endif /* _USE_MKFS && !_FS_READONLY */
+
+
+
+
+#if _USE_STRFUNC
+/*-----------------------------------------------------------------------*/
+/* Get a string from the file                                            */
+/*-----------------------------------------------------------------------*/
+TCHAR* f_gets (
+    TCHAR* buff,    /* Pointer to the string buffer to read */
+    int len,        /* Size of string buffer (characters) */
+    FIL* fil        /* Pointer to the file object */
+)
+{
+    int n = 0;
+    TCHAR c, *p = buff;
+    BYTE s[2];
+    UINT rc;
+
+
+    while (n < len - 1) {           /* Read bytes until buffer gets filled */
+        f_read(fil, s, 1, &rc);
+        if (rc != 1) break;         /* Break on EOF or error */
+        c = s[0];
+#if _LFN_UNICODE                    /* Read a character in UTF-8 encoding */
+        if (c >= 0x80) {
+            if (c < 0xC0) continue; /* Skip stray trailer */
+            if (c < 0xE0) {         /* Two-byte sequence */
+                f_read(fil, s, 1, &rc);
+                if (rc != 1) break;
+                c = ((c & 0x1F) << 6) | (s[0] & 0x3F);
+                if (c < 0x80) c = '?';
+            } else {
+                if (c < 0xF0) {     /* Three-byte sequence */
+                    f_read(fil, s, 2, &rc);
+                    if (rc != 2) break;
+                    c = (c << 12) | ((s[0] & 0x3F) << 6) | (s[1] & 0x3F);
+                    if (c < 0x800) c = '?';
+                } else {            /* Reject four-byte sequence */
+                    c = '?';
+                }
+            }
+        }
+#endif
+#if _USE_STRFUNC >= 2
+        if (c == '\r') continue;    /* Strip '\r' */
+#endif
+        *p++ = c;
+        n++;
+        if (c == '\n') break;       /* Break on EOL */
+    }
+    *p = 0;
+    return n ? buff : 0;            /* When no data read (eof or error), return with error. */
+}
+
+
+
+#if !_FS_READONLY
+#include <stdarg.h>
+/*-----------------------------------------------------------------------*/
+/* Put a character to the file                                           */
+/*-----------------------------------------------------------------------*/
+int f_putc (
+    TCHAR c,    /* A character to be output */
+    FIL* fil    /* Pointer to the file object */
+)
+{
+    UINT bw, btw;
+    BYTE s[3];
+
+
+#if _USE_STRFUNC >= 2
+    if (c == '\n') f_putc ('\r', fil);  /* LF -> CRLF conversion */
+#endif
+
+#if _LFN_UNICODE    /* Write the character in UTF-8 encoding */
+    if (c < 0x80) {         /* 7-bit */
+        s[0] = (BYTE)c;
+        btw = 1;
+    } else {
+        if (c < 0x800) {    /* 11-bit */
+            s[0] = (BYTE)(0xC0 | (c >> 6));
+            s[1] = (BYTE)(0x80 | (c & 0x3F));
+            btw = 2;
+        } else {            /* 16-bit */
+            s[0] = (BYTE)(0xE0 | (c >> 12));
+            s[1] = (BYTE)(0x80 | ((c >> 6) & 0x3F));
+            s[2] = (BYTE)(0x80 | (c & 0x3F));
+            btw = 3;
+        }
+    }
+#else               /* Write the character without conversion */
+    s[0] = (BYTE)c;
+    btw = 1;
+#endif
+    f_write(fil, s, btw, &bw);      /* Write the char to the file */
+    return (bw == btw) ? 1 : EOF;   /* Return the result */
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Put a string to the file                                              */
+/*-----------------------------------------------------------------------*/
+int f_puts (
+    const TCHAR* str,   /* Pointer to the string to be output */
+    FIL* fil            /* Pointer to the file object */
+)
+{
+    int n;
+
+
+    for (n = 0; *str; str++, n++) {
+        if (f_putc(*str, fil) == EOF) return EOF;
+    }
+    return n;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Put a formatted string to the file                                    */
+/*-----------------------------------------------------------------------*/
+int f_printf (
+    FIL* fil,           /* Pointer to the file object */
+    const TCHAR* str,   /* Pointer to the format string */
+    ...                 /* Optional arguments... */
+)
+{
+    va_list arp;
+    BYTE f, r;
+    UINT i, j, w;
+    ULONG v;
+    TCHAR c, d, s[16], *p;
+    int res, chc, cc;
+
+
+    va_start(arp, str);
+
+    for (cc = res = 0; cc != EOF; res += cc) {
+        c = *str++;
+        if (c == 0) break;          /* End of string */
+        if (c != '%') {             /* Non escape character */
+            cc = f_putc(c, fil);
+            if (cc != EOF) cc = 1;
+            continue;
+        }
+        w = f = 0;
+        c = *str++;
+        if (c == '0') {             /* Flag: '0' padding */
+            f = 1; c = *str++;
+        } else {
+            if (c == '-') {         /* Flag: left justified */
+                f = 2; c = *str++;
+            }
+        }
+        while (IsDigit(c)) {        /* Precision */
+            w = w * 10 + c - '0';
+            c = *str++;
+        }
+        if (c == 'l' || c == 'L') { /* Prefix: Size is long int */
+            f |= 4; c = *str++;
+        }
+        if (!c) break;
+        d = c;
+        if (IsLower(d)) d -= 0x20;
+        switch (d) {                /* Type is... */
+        case 'S' :                  /* String */
+            p = va_arg(arp, TCHAR*);
+            for (j = 0; p[j]; j++) ;
+            chc = 0;
+            if (!(f & 2)) {
+                while (j++ < w) chc += (cc = f_putc(' ', fil));
+            }
+            chc += (cc = f_puts(p, fil));
+            while (j++ < w) chc += (cc = f_putc(' ', fil));
+            if (cc != EOF) cc = chc;
+            continue;
+        case 'C' :                  /* Character */
+            cc = f_putc((TCHAR)va_arg(arp, int), fil); continue;
+        case 'B' :                  /* Binary */
+            r = 2; break;
+        case 'O' :                  /* Octal */
+            r = 8; break;
+        case 'D' :                  /* Signed decimal */
+        case 'U' :                  /* Unsigned decimal */
+            r = 10; break;
+        case 'X' :                  /* Hexdecimal */
+            r = 16; break;
+        default:                    /* Unknown type (pass-through) */
+            cc = f_putc(c, fil); continue;
+        }
+
+        /* Get an argument and put it in numeral */
+        v = (f & 4) ? (ULONG)va_arg(arp, long) : ((d == 'D') ? (ULONG)(long)va_arg(arp, int) : (ULONG)va_arg(arp, unsigned int));
+        if (d == 'D' && (v & 0x80000000)) {
+            v = 0 - v;
+            f |= 8;
+        }
+        i = 0;
+        do {
+            d = (TCHAR)(v % r); v /= r;
+            if (d > 9) d += (c == 'x') ? 0x27 : 0x07;
+            s[i++] = d + '0';
+        } while (v && i < sizeof s / sizeof s[0]);
+        if (f & 8) s[i++] = '-';
+        j = i; d = (f & 1) ? '0' : ' ';
+        res = 0;
+        while (!(f & 2) && j++ < w) res += (cc = f_putc(d, fil));
+        do res += (cc = f_putc(s[--i], fil)); while(i);
+        while (j++ < w) res += (cc = f_putc(' ', fil));
+        if (cc != EOF) cc = res;
+    }
+
+    va_end(arp);
+    return (cc == EOF) ? cc : res;
+}
+
+#endif /* !_FS_READONLY */
+#endif /* _USE_STRFUNC */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/FATFileSystem/ChaN/ff.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,337 @@
+/*---------------------------------------------------------------------------/
+/  FatFs - FAT file system module include file  R0.09a    (C)ChaN, 2012
+/----------------------------------------------------------------------------/
+/ FatFs module is a generic FAT file system module for small embedded systems.
+/ This is a free software that opened for education, research and commercial
+/ developments under license policy of following terms.
+/
+/  Copyright (C) 2012, ChaN, all right reserved.
+/
+/ * The FatFs module is a free software and there is NO WARRANTY.
+/ * No restriction on use. You can use, modify and redistribute it for
+/   personal, non-profit or commercial product UNDER YOUR RESPONSIBILITY.
+/ * Redistributions of source code must retain the above copyright notice.
+/
+/----------------------------------------------------------------------------*/
+
+#ifndef _FATFS
+#define _FATFS  4004    /* Revision ID */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "integer.h"    /* Basic integer types */
+#include "ffconf.h"     /* FatFs configuration options */
+
+#if _FATFS != _FFCONF
+#error Wrong configuration file (ffconf.h).
+#endif
+
+
+
+/* Definitions of volume management */
+
+#if _MULTI_PARTITION        /* Multiple partition configuration */
+typedef struct {
+    BYTE pd;    /* Physical drive number */
+    BYTE pt;    /* Partition: 0:Auto detect, 1-4:Forced partition) */
+} PARTITION;
+extern PARTITION VolToPart[];   /* Volume - Partition resolution table */
+#define LD2PD(vol) (VolToPart[vol].pd)  /* Get physical drive number */
+#define LD2PT(vol) (VolToPart[vol].pt)  /* Get partition index */
+
+#else                           /* Single partition configuration */
+#define LD2PD(vol) (BYTE)(vol)  /* Each logical drive is bound to the same physical drive number */
+#define LD2PT(vol) 0            /* Always mounts the 1st partition or in SFD */
+
+#endif
+
+
+
+/* Type of path name strings on FatFs API */
+
+#if _LFN_UNICODE            /* Unicode string */
+#if !_USE_LFN
+#error _LFN_UNICODE must be 0 in non-LFN cfg.
+#endif
+#ifndef _INC_TCHAR
+typedef WCHAR TCHAR;
+#define _T(x) L ## x
+#define _TEXT(x) L ## x
+#endif
+
+#else                       /* ANSI/OEM string */
+#ifndef _INC_TCHAR
+typedef char TCHAR;
+#define _T(x) x
+#define _TEXT(x) x
+#endif
+
+#endif
+
+
+
+/* File system object structure (FATFS) */
+
+typedef struct {
+    BYTE    fs_type;        /* FAT sub-type (0:Not mounted) */
+    BYTE    drv;            /* Physical drive number */
+    BYTE    csize;          /* Sectors per cluster (1,2,4...128) */
+    BYTE    n_fats;         /* Number of FAT copies (1,2) */
+    BYTE    wflag;          /* win[] dirty flag (1:must be written back) */
+    BYTE    fsi_flag;       /* fsinfo dirty flag (1:must be written back) */
+    WORD    id;             /* File system mount ID */
+    WORD    n_rootdir;      /* Number of root directory entries (FAT12/16) */
+#if _MAX_SS != 512
+    WORD    ssize;          /* Bytes per sector (512, 1024, 2048 or 4096) */
+#endif
+#if _FS_REENTRANT
+    _SYNC_t sobj;           /* Identifier of sync object */
+#endif
+#if !_FS_READONLY
+    DWORD   last_clust;     /* Last allocated cluster */
+    DWORD   free_clust;     /* Number of free clusters */
+    DWORD   fsi_sector;     /* fsinfo sector (FAT32) */
+#endif
+#if _FS_RPATH
+    DWORD   cdir;           /* Current directory start cluster (0:root) */
+#endif
+    DWORD   n_fatent;       /* Number of FAT entries (= number of clusters + 2) */
+    DWORD   fsize;          /* Sectors per FAT */
+    DWORD   fatbase;        /* FAT start sector */
+    DWORD   dirbase;        /* Root directory start sector (FAT32:Cluster#) */
+    DWORD   database;       /* Data start sector */
+    DWORD   winsect;        /* Current sector appearing in the win[] */
+    BYTE    win[_MAX_SS];   /* Disk access window for Directory, FAT (and Data on tiny cfg) */
+} FATFS;
+
+
+
+/* File object structure (FIL) */
+
+typedef struct {
+    FATFS*  fs;             /* Pointer to the related file system object */
+    WORD    id;             /* File system mount ID of the related file system object */
+    BYTE    flag;           /* File status flags */
+    BYTE    pad1;
+    DWORD   fptr;           /* File read/write pointer (0ed on file open) */
+    DWORD   fsize;          /* File size */
+    DWORD   sclust;         /* File data start cluster (0:no data cluster, always 0 when fsize is 0) */
+    DWORD   clust;          /* Current cluster of fpter */
+    DWORD   dsect;          /* Current data sector of fpter */
+#if !_FS_READONLY
+    DWORD   dir_sect;       /* Sector containing the directory entry */
+    BYTE*   dir_ptr;        /* Pointer to the directory entry in the window */
+#endif
+#if _USE_FASTSEEK
+    DWORD*  cltbl;          /* Pointer to the cluster link map table (null on file open) */
+#endif
+#if _FS_LOCK
+    UINT    lockid;         /* File lock ID (index of file semaphore table Files[]) */
+#endif
+#if !_FS_TINY
+    BYTE    buf[_MAX_SS];   /* File data read/write buffer */
+#endif
+} FIL;
+
+
+
+/* Directory object structure (DIR) */
+
+typedef struct {
+    FATFS*  fs;             /* Pointer to the owner file system object */
+    WORD    id;             /* Owner file system mount ID */
+    WORD    index;          /* Current read/write index number */
+    DWORD   sclust;         /* Table start cluster (0:Root dir) */
+    DWORD   clust;          /* Current cluster */
+    DWORD   sect;           /* Current sector */
+    BYTE*   dir;            /* Pointer to the current SFN entry in the win[] */
+    BYTE*   fn;             /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
+#if _USE_LFN
+    WCHAR*  lfn;            /* Pointer to the LFN working buffer */
+    WORD    lfn_idx;        /* Last matched LFN index number (0xFFFF:No LFN) */
+#endif
+} FATFS_DIR;
+
+
+
+/* File status structure (FILINFO) */
+
+typedef struct {
+    DWORD   fsize;          /* File size */
+    WORD    fdate;          /* Last modified date */
+    WORD    ftime;          /* Last modified time */
+    BYTE    fattrib;        /* Attribute */
+    TCHAR   fname[13];      /* Short file name (8.3 format) */
+#if _USE_LFN
+    TCHAR*  lfname;         /* Pointer to the LFN buffer */
+    UINT    lfsize;         /* Size of LFN buffer in TCHAR */
+#endif
+} FILINFO;
+
+
+
+/* File function return code (FRESULT) */
+
+typedef enum {
+    FR_OK = 0,              /* (0) Succeeded */
+    FR_DISK_ERR,            /* (1) A hard error occurred in the low level disk I/O layer */
+    FR_INT_ERR,             /* (2) Assertion failed */
+    FR_NOT_READY,           /* (3) The physical drive cannot work */
+    FR_NO_FILE,             /* (4) Could not find the file */
+    FR_NO_PATH,             /* (5) Could not find the path */
+    FR_INVALID_NAME,        /* (6) The path name format is invalid */
+    FR_DENIED,              /* (7) Access denied due to prohibited access or directory full */
+    FR_EXIST,               /* (8) Access denied due to prohibited access */
+    FR_INVALID_OBJECT,      /* (9) The file/directory object is invalid */
+    FR_WRITE_PROTECTED,     /* (10) The physical drive is write protected */
+    FR_INVALID_DRIVE,       /* (11) The logical drive number is invalid */
+    FR_NOT_ENABLED,         /* (12) The volume has no work area */
+    FR_NO_FILESYSTEM,       /* (13) There is no valid FAT volume */
+    FR_MKFS_ABORTED,        /* (14) The f_mkfs() aborted due to any parameter error */
+    FR_TIMEOUT,             /* (15) Could not get a grant to access the volume within defined period */
+    FR_LOCKED,              /* (16) The operation is rejected according to the file sharing policy */
+    FR_NOT_ENOUGH_CORE,     /* (17) LFN working buffer could not be allocated */
+    FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_SHARE */
+    FR_INVALID_PARAMETER    /* (19) Given parameter is invalid */
+} FRESULT;
+
+
+
+/*--------------------------------------------------------------*/
+/* FatFs module application interface                           */
+
+FRESULT f_mount (BYTE, FATFS*);                     /* Mount/Unmount a logical drive */
+FRESULT f_open (FIL*, const TCHAR*, BYTE);          /* Open or create a file */
+FRESULT f_read (FIL*, void*, UINT, UINT*);          /* Read data from a file */
+FRESULT f_lseek (FIL*, DWORD);                      /* Move file pointer of a file object */
+FRESULT f_close (FIL*);                             /* Close an open file object */
+FRESULT f_opendir (FATFS_DIR*, const TCHAR*);             /* Open an existing directory */
+FRESULT f_readdir (FATFS_DIR*, FILINFO*);                 /* Read a directory item */
+FRESULT f_stat (const TCHAR*, FILINFO*);            /* Get file status */
+FRESULT f_write (FIL*, const void*, UINT, UINT*);   /* Write data to a file */
+FRESULT f_getfree (const TCHAR*, DWORD*, FATFS**);  /* Get number of free clusters on the drive */
+FRESULT f_truncate (FIL*);                          /* Truncate file */
+FRESULT f_sync (FIL*);                              /* Flush cached data of a writing file */
+FRESULT f_unlink (const TCHAR*);                    /* Delete an existing file or directory */
+FRESULT f_mkdir (const TCHAR*);                     /* Create a new directory */
+FRESULT f_chmod (const TCHAR*, BYTE, BYTE);         /* Change attribute of the file/dir */
+FRESULT f_utime (const TCHAR*, const FILINFO*);     /* Change times-tamp of the file/dir */
+FRESULT f_rename (const TCHAR*, const TCHAR*);      /* Rename/Move a file or directory */
+FRESULT f_chdrive (BYTE);                           /* Change current drive */
+FRESULT f_chdir (const TCHAR*);                     /* Change current directory */
+FRESULT f_getcwd (TCHAR*, UINT);                    /* Get current directory */
+FRESULT f_forward (FIL*, UINT(*)(const BYTE*,UINT), UINT, UINT*);   /* Forward data to the stream */
+FRESULT f_mkfs (BYTE, BYTE, UINT);                  /* Create a file system on the drive */
+FRESULT f_fdisk (BYTE, const DWORD[], void*);       /* Divide a physical drive into some partitions */
+int f_putc (TCHAR, FIL*);                           /* Put a character to the file */
+int f_puts (const TCHAR*, FIL*);                    /* Put a string to the file */
+int f_printf (FIL*, const TCHAR*, ...);             /* Put a formatted string to the file */
+TCHAR* f_gets (TCHAR*, int, FIL*);                  /* Get a string from the file */
+
+#define f_eof(fp) (((fp)->fptr == (fp)->fsize) ? 1 : 0)
+#define f_error(fp) (((fp)->flag & FA__ERROR) ? 1 : 0)
+#define f_tell(fp) ((fp)->fptr)
+#define f_size(fp) ((fp)->fsize)
+
+#ifndef EOF
+#define EOF (-1)
+#endif
+
+
+
+
+/*--------------------------------------------------------------*/
+/* Additional user defined functions                            */
+
+/* RTC function */
+#if !_FS_READONLY
+DWORD get_fattime (void);
+#endif
+
+/* Unicode support functions */
+#if _USE_LFN                        /* Unicode - OEM code conversion */
+WCHAR ff_convert (WCHAR, UINT);     /* OEM-Unicode bidirectional conversion */
+WCHAR ff_wtoupper (WCHAR);          /* Unicode upper-case conversion */
+#if _USE_LFN == 3                   /* Memory functions */
+void* ff_memalloc (UINT);           /* Allocate memory block */
+void ff_memfree (void*);            /* Free memory block */
+#endif
+#endif
+
+/* Sync functions */
+#if _FS_REENTRANT
+int ff_cre_syncobj (BYTE, _SYNC_t*);/* Create a sync object */
+int ff_req_grant (_SYNC_t);         /* Lock sync object */
+void ff_rel_grant (_SYNC_t);        /* Unlock sync object */
+int ff_del_syncobj (_SYNC_t);       /* Delete a sync object */
+#endif
+
+
+
+
+/*--------------------------------------------------------------*/
+/* Flags and offset address                                     */
+
+
+/* File access control and file status flags (FIL.flag) */
+
+#define FA_READ             0x01
+#define FA_OPEN_EXISTING    0x00
+#define FA__ERROR           0x80
+
+#if !_FS_READONLY
+#define FA_WRITE            0x02
+#define FA_CREATE_NEW       0x04
+#define FA_CREATE_ALWAYS    0x08
+#define FA_OPEN_ALWAYS      0x10
+#define FA__WRITTEN         0x20
+#define FA__DIRTY           0x40
+#endif
+
+
+/* FAT sub type (FATFS.fs_type) */
+
+#define FS_FAT12    1
+#define FS_FAT16    2
+#define FS_FAT32    3
+
+
+/* File attribute bits for directory entry */
+
+#define AM_RDO  0x01    /* Read only */
+#define AM_HID  0x02    /* Hidden */
+#define AM_SYS  0x04    /* System */
+#define AM_VOL  0x08    /* Volume label */
+#define AM_LFN  0x0F    /* LFN entry */
+#define AM_DIR  0x10    /* Directory */
+#define AM_ARC  0x20    /* Archive */
+#define AM_MASK 0x3F    /* Mask of defined bits */
+
+
+/* Fast seek feature */
+#define CREATE_LINKMAP  0xFFFFFFFF
+
+
+
+/*--------------------------------*/
+/* Multi-byte word access macros  */
+
+#if _WORD_ACCESS == 1   /* Enable word access to the FAT structure */
+#define LD_WORD(ptr)        (WORD)(*(WORD*)(BYTE*)(ptr))
+#define LD_DWORD(ptr)       (DWORD)(*(DWORD*)(BYTE*)(ptr))
+#define ST_WORD(ptr,val)    *(WORD*)(BYTE*)(ptr)=(WORD)(val)
+#define ST_DWORD(ptr,val)   *(DWORD*)(BYTE*)(ptr)=(DWORD)(val)
+#else                   /* Use byte-by-byte access to the FAT structure */
+#define LD_WORD(ptr)        (WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr))
+#define LD_DWORD(ptr)       (DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr))
+#define ST_WORD(ptr,val)    *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8)
+#define ST_DWORD(ptr,val)   *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8); *((BYTE*)(ptr)+2)=(BYTE)((DWORD)(val)>>16); *((BYTE*)(ptr)+3)=(BYTE)((DWORD)(val)>>24)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FATFS */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/FATFileSystem/ChaN/ffconf.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,191 @@
+/*---------------------------------------------------------------------------/
+/  FatFs - FAT file system module configuration file  R0.09a (C)ChaN, 2012
+/----------------------------------------------------------------------------/
+/
+/ CAUTION! Do not forget to make clean the project after any changes to
+/ the configuration options.
+/
+/----------------------------------------------------------------------------*/
+#ifndef _FFCONF
+#define _FFCONF 4004    /* Revision ID */
+
+#define FFS_DBG     0
+
+/*---------------------------------------------------------------------------/
+/ Functions and Buffer Configurations
+/----------------------------------------------------------------------------*/
+
+#define _FS_TINY        0   /* 0:Normal or 1:Tiny */
+/* When _FS_TINY is set to 1, FatFs uses the sector buffer in the file system
+/  object instead of the sector buffer in the individual file object for file
+/  data transfer. This reduces memory consumption 512 bytes each file object. */
+
+
+#define _FS_READONLY    0   /* 0:Read/Write or 1:Read only */
+/* Setting _FS_READONLY to 1 defines read only configuration. This removes
+/  writing functions, f_write, f_sync, f_unlink, f_mkdir, f_chmod, f_rename,
+/  f_truncate and useless f_getfree. */
+
+
+#define _FS_MINIMIZE    0   /* 0 to 3 */
+/* The _FS_MINIMIZE option defines minimization level to remove some functions.
+/
+/   0: Full function.
+/   1: f_stat, f_getfree, f_unlink, f_mkdir, f_chmod, f_truncate and f_rename
+/      are removed.
+/   2: f_opendir and f_readdir are removed in addition to 1.
+/   3: f_lseek is removed in addition to 2. */
+
+
+#define _USE_STRFUNC    0   /* 0:Disable or 1-2:Enable */
+/* To enable string functions, set _USE_STRFUNC to 1 or 2. */
+
+
+#define _USE_MKFS       1   /* 0:Disable or 1:Enable */
+/* To enable f_mkfs function, set _USE_MKFS to 1 and set _FS_READONLY to 0 */
+
+
+#define _USE_FORWARD    0   /* 0:Disable or 1:Enable */
+/* To enable f_forward function, set _USE_FORWARD to 1 and set _FS_TINY to 1. */
+
+
+#define _USE_FASTSEEK   0   /* 0:Disable or 1:Enable */
+/* To enable fast seek feature, set _USE_FASTSEEK to 1. */
+
+
+
+/*---------------------------------------------------------------------------/
+/ Locale and Namespace Configurations
+/----------------------------------------------------------------------------*/
+
+#define _CODE_PAGE  858
+/* The _CODE_PAGE specifies the OEM code page to be used on the target system.
+/  Incorrect setting of the code page can cause a file open failure.
+/
+/   932  - Japanese Shift-JIS (DBCS, OEM, Windows)
+/   936  - Simplified Chinese GBK (DBCS, OEM, Windows)
+/   949  - Korean (DBCS, OEM, Windows)
+/   950  - Traditional Chinese Big5 (DBCS, OEM, Windows)
+/   1250 - Central Europe (Windows)
+/   1251 - Cyrillic (Windows)
+/   1252 - Latin 1 (Windows)
+/   1253 - Greek (Windows)
+/   1254 - Turkish (Windows)
+/   1255 - Hebrew (Windows)
+/   1256 - Arabic (Windows)
+/   1257 - Baltic (Windows)
+/   1258 - Vietnam (OEM, Windows)
+/   437  - U.S. (OEM)
+/   720  - Arabic (OEM)
+/   737  - Greek (OEM)
+/   775  - Baltic (OEM)
+/   850  - Multilingual Latin 1 (OEM)
+/   858  - Multilingual Latin 1 + Euro (OEM)
+/   852  - Latin 2 (OEM)
+/   855  - Cyrillic (OEM)
+/   866  - Russian (OEM)
+/   857  - Turkish (OEM)
+/   862  - Hebrew (OEM)
+/   874  - Thai (OEM, Windows)
+/   1    - ASCII only (Valid for non LFN cfg.)
+*/
+
+
+#define _USE_LFN    1       /* 0 to 3 */
+#define _MAX_LFN    255     /* Maximum LFN length to handle (12 to 255) */
+/* The _USE_LFN option switches the LFN support.
+/
+/   0: Disable LFN feature. _MAX_LFN and _LFN_UNICODE have no effect.
+/   1: Enable LFN with static working buffer on the BSS. Always NOT reentrant.
+/   2: Enable LFN with dynamic working buffer on the STACK.
+/   3: Enable LFN with dynamic working buffer on the HEAP.
+/
+/  The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. To enable LFN,
+/  Unicode handling functions ff_convert() and ff_wtoupper() must be added
+/  to the project. When enable to use heap, memory control functions
+/  ff_memalloc() and ff_memfree() must be added to the project. */
+
+
+#define _LFN_UNICODE    0   /* 0:ANSI/OEM or 1:Unicode */
+/* To switch the character code set on FatFs API to Unicode,
+/  enable LFN feature and set _LFN_UNICODE to 1. */
+
+
+#define _FS_RPATH       0   /* 0 to 2 */
+/* The _FS_RPATH option configures relative path feature.
+/
+/   0: Disable relative path feature and remove related functions.
+/   1: Enable relative path. f_chdrive() and f_chdir() are available.
+/   2: f_getcwd() is available in addition to 1.
+/
+/  Note that output of the f_readdir fnction is affected by this option. */
+
+
+
+/*---------------------------------------------------------------------------/
+/ Physical Drive Configurations
+/----------------------------------------------------------------------------*/
+
+#define _VOLUMES    1
+/* Number of volumes (logical drives) to be used. */
+
+
+#define _MAX_SS     512     /* 512, 1024, 2048 or 4096 */
+/* Maximum sector size to be handled.
+/  Always set 512 for memory card and hard disk but a larger value may be
+/  required for on-board flash memory, floppy disk and optical disk.
+/  When _MAX_SS is larger than 512, it configures FatFs to variable sector size
+/  and GET_SECTOR_SIZE command must be implememted to the disk_ioctl function. */
+
+
+#define _MULTI_PARTITION    0   /* 0:Single partition, 1/2:Enable multiple partition */
+/* When set to 0, each volume is bound to the same physical drive number and
+/ it can mount only first primaly partition. When it is set to 1, each volume
+/ is tied to the partitions listed in VolToPart[]. */
+
+
+#define _USE_ERASE  0   /* 0:Disable or 1:Enable */
+/* To enable sector erase feature, set _USE_ERASE to 1. CTRL_ERASE_SECTOR command
+/  should be added to the disk_ioctl functio. */
+
+
+
+/*---------------------------------------------------------------------------/
+/ System Configurations
+/----------------------------------------------------------------------------*/
+
+#define _WORD_ACCESS    0   /* 0 or 1 */
+/* Set 0 first and it is always compatible with all platforms. The _WORD_ACCESS
+/  option defines which access method is used to the word data on the FAT volume.
+/
+/   0: Byte-by-byte access.
+/   1: Word access. Do not choose this unless following condition is met.
+/
+/  When the byte order on the memory is big-endian or address miss-aligned word
+/  access results incorrect behavior, the _WORD_ACCESS must be set to 0.
+/  If it is not the case, the value can also be set to 1 to improve the
+/  performance and code size.
+*/
+
+
+/* A header file that defines sync object types on the O/S, such as
+/  windows.h, ucos_ii.h and semphr.h, must be included prior to ff.h. */
+
+#define _FS_REENTRANT   0       /* 0:Disable or 1:Enable */
+#define _FS_TIMEOUT     1000    /* Timeout period in unit of time ticks */
+#define _SYNC_t         HANDLE  /* O/S dependent type of sync object. e.g. HANDLE, OS_EVENT*, ID and etc.. */
+
+/* The _FS_REENTRANT option switches the reentrancy (thread safe) of the FatFs module.
+/
+/   0: Disable reentrancy. _SYNC_t and _FS_TIMEOUT have no effect.
+/   1: Enable reentrancy. Also user provided synchronization handlers,
+/      ff_req_grant, ff_rel_grant, ff_del_syncobj and ff_cre_syncobj
+/      function must be added to the project. */
+
+
+#define _FS_LOCK    0   /* 0:Disable or >=1:Enable */
+/* To enable file lock control feature, set _FS_LOCK to 1 or greater.
+   The value defines how many files can be opened simultaneously. */
+
+
+#endif /* _FFCONFIG */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/FATFileSystem/ChaN/integer.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,37 @@
+/*-------------------------------------------*/
+/* Integer type definitions for FatFs module */
+/*-------------------------------------------*/
+
+#ifndef _INTEGER
+#define _INTEGER
+
+#ifdef _WIN32    /* FatFs development platform */
+
+#include <windows.h>
+#include <tchar.h>
+
+#else            /* Embedded platform */
+
+/* These types must be 16-bit, 32-bit or larger integer */
+typedef int             INT;
+typedef unsigned int    UINT;
+
+/* These types must be 8-bit integer */
+typedef char            CHAR;
+typedef unsigned char   UCHAR;
+typedef unsigned char   BYTE;
+
+/* These types must be 16-bit integer */
+typedef short           SHORT;
+typedef unsigned short  USHORT;
+typedef unsigned short  WORD;
+typedef unsigned short  WCHAR;
+
+/* These types must be 32-bit integer */
+typedef long            LONG;
+typedef unsigned long   ULONG;
+typedef unsigned long   DWORD;
+
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/FATFileSystem/FATDirHandle.cpp	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,78 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <string.h>
+#include "ff.h"
+#include "FATDirHandle.h"
+
+using namespace mbed;
+
+FATDirHandle::FATDirHandle(const FATFS_DIR &the_dir) {
+    dir = the_dir;
+}
+
+int FATDirHandle::closedir() {
+    delete this;
+    return 0;
+}
+
+struct dirent *FATDirHandle::readdir() {
+    FILINFO finfo;
+
+#if _USE_LFN
+    finfo.lfname = cur_entry.d_name;
+    finfo.lfsize = sizeof(cur_entry.d_name);
+#endif // _USE_LFN
+
+    FRESULT res = f_readdir(&dir, &finfo);
+
+#if _USE_LFN
+    if(res != 0 || finfo.fname[0]==0) {
+        return NULL;
+    } else {
+        if(cur_entry.d_name[0]==0) {
+            // No long filename so use short filename.
+            memcpy(cur_entry.d_name, finfo.fname, sizeof(finfo.fname));
+        }
+        return &cur_entry;
+    }
+#else
+    if(res != 0 || finfo.fname[0]==0) {
+        return NULL;
+    } else {
+        memcpy(cur_entry.d_name, finfo.fname, sizeof(finfo.fname));
+        return &cur_entry;
+    }
+#endif /* _USE_LFN */
+}
+
+void FATDirHandle::rewinddir() {
+    dir.index = 0;
+}
+
+off_t FATDirHandle::telldir() {
+    return dir.index;
+}
+
+void FATDirHandle::seekdir(off_t location) {
+    dir.index = location;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/FATFileSystem/FATDirHandle.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,45 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef MBED_FATDIRHANDLE_H
+#define MBED_FATDIRHANDLE_H
+
+#include "DirHandle.h"
+
+using namespace mbed;
+
+class FATDirHandle : public DirHandle {
+
+ public:
+    FATDirHandle(const FATFS_DIR &the_dir);
+    virtual int closedir();
+    virtual struct dirent *readdir();
+    virtual void rewinddir();
+    virtual off_t telldir();
+    virtual void seekdir(off_t location);
+
+ private:
+    FATFS_DIR dir;
+    struct dirent cur_entry;
+
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/FATFileSystem/FATFileHandle.cpp	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,90 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "ff.h"
+#include "ffconf.h"
+#include "mbed_debug.h"
+
+#include "FATFileHandle.h"
+
+FATFileHandle::FATFileHandle(FIL fh) {
+    _fh = fh;
+}
+
+int FATFileHandle::close() {
+    int retval = f_close(&_fh);
+    delete this;
+    return retval;
+}
+
+ssize_t FATFileHandle::write(const void* buffer, size_t length) {
+    UINT n;
+    FRESULT res = f_write(&_fh, buffer, length, &n);
+    if (res) { 
+        debug_if(FFS_DBG, "f_write() failed: %d", res);
+        return -1;
+    }
+    return n;
+}
+        
+ssize_t FATFileHandle::read(void* buffer, size_t length) {
+    debug_if(FFS_DBG, "read(%d)\n", length);
+    UINT n;
+    FRESULT res = f_read(&_fh, buffer, length, &n);
+    if (res) {
+        debug_if(FFS_DBG, "f_read() failed: %d\n", res);
+        return -1;
+    }
+    return n;
+}
+
+int FATFileHandle::isatty() {
+    return 0;
+}
+
+off_t FATFileHandle::lseek(off_t position, int whence) {
+    if (whence == SEEK_END) {
+        position += _fh.fsize;
+    } else if(whence==SEEK_CUR) {
+        position += _fh.fptr;
+    }
+    FRESULT res = f_lseek(&_fh, position);
+    if (res) {
+        debug_if(FFS_DBG, "lseek failed: %d\n", res);
+        return -1;
+    } else {
+        debug_if(FFS_DBG, "lseek OK, returning %i\n", _fh.fptr);
+        return _fh.fptr;
+    }
+}
+
+int FATFileHandle::fsync() {
+    FRESULT res = f_sync(&_fh);
+    if (res) {
+        debug_if(FFS_DBG, "f_sync() failed: %d\n", res);
+        return -1;
+    }
+    return 0;
+}
+
+off_t FATFileHandle::flen() {
+    return _fh.fsize;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/FATFileSystem/FATFileHandle.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,47 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef MBED_FATFILEHANDLE_H
+#define MBED_FATFILEHANDLE_H
+
+#include "FileHandle.h"
+
+using namespace mbed;
+
+class FATFileHandle : public FileHandle {
+public:
+
+    FATFileHandle(FIL fh);
+    virtual int close();
+    virtual ssize_t write(const void* buffer, size_t length);
+    virtual ssize_t read(void* buffer, size_t length);
+    virtual int isatty();
+    virtual off_t lseek(off_t position, int whence);
+    virtual int fsync();
+    virtual off_t flen();
+
+protected:
+
+    FIL _fh;
+
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/FATFileSystem/FATFileSystem.cpp	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,132 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "mbed.h"
+
+#include "ffconf.h"
+#include "mbed_debug.h"
+
+#include "FATFileSystem.h"
+#include "FATFileHandle.h"
+#include "FATDirHandle.h"
+
+DWORD get_fattime(void) {
+    time_t rawtime;
+    time(&rawtime);
+    struct tm *ptm = localtime(&rawtime);
+    return (DWORD)(ptm->tm_year - 80) << 25
+         | (DWORD)(ptm->tm_mon + 1  ) << 21
+         | (DWORD)(ptm->tm_mday     ) << 16
+         | (DWORD)(ptm->tm_hour     ) << 11
+         | (DWORD)(ptm->tm_min      ) << 5
+         | (DWORD)(ptm->tm_sec/2    );
+}
+
+FATFileSystem *FATFileSystem::_ffs[_VOLUMES] = {0};
+
+FATFileSystem::FATFileSystem(const char* n) : FileSystemLike(n) {
+    debug_if(FFS_DBG, "FATFileSystem(%s)\n", n);
+    for(int i=0; i<_VOLUMES; i++) {
+        if(_ffs[i] == 0) {
+            _ffs[i] = this;
+            _fsid = i;
+            debug_if(FFS_DBG, "Mounting [%s] on ffs drive [%d]\n", _name, _fsid);
+            f_mount(i, &_fs);
+            return;
+        }
+    }
+    error("Couldn't create %s in FATFileSystem::FATFileSystem\n", n);
+}
+
+FATFileSystem::~FATFileSystem() {
+    for (int i=0; i<_VOLUMES; i++) {
+        if (_ffs[i] == this) {
+            _ffs[i] = 0;
+            f_mount(i, NULL);
+        }
+    }
+}
+
+FileHandle *FATFileSystem::open(const char* name, int flags) {
+    debug_if(FFS_DBG, "open(%s) on filesystem [%s], drv [%d]\n", name, _name, _fsid);
+    char n[64];
+    sprintf(n, "%d:/%s", _fsid, name);
+    
+    /* POSIX flags -> FatFS open mode */
+    BYTE openmode;
+    if (flags & O_RDWR) {
+        openmode = FA_READ|FA_WRITE;
+    } else if(flags & O_WRONLY) {
+        openmode = FA_WRITE;
+    } else {
+        openmode = FA_READ;
+    }
+    if(flags & O_CREAT) {
+        if(flags & O_TRUNC) {
+            openmode |= FA_CREATE_ALWAYS;
+        } else {
+            openmode |= FA_OPEN_ALWAYS;
+        }
+    }
+    
+    FIL fh;
+    FRESULT res = f_open(&fh, n, openmode);
+    if (res) { 
+        debug_if(FFS_DBG, "f_open('w') failed: %d\n", res);
+        return NULL;
+    }
+    if (flags & O_APPEND) {
+        f_lseek(&fh, fh.fsize);
+    }
+    return new FATFileHandle(fh);
+}
+    
+int FATFileSystem::remove(const char *filename) {
+    FRESULT res = f_unlink(filename);
+    if (res) { 
+        debug_if(FFS_DBG, "f_unlink() failed: %d\n", res);
+        return -1;
+    }
+    return 0;
+}
+
+int FATFileSystem::format() {
+    FRESULT res = f_mkfs(_fsid, 0, 512); // Logical drive number, Partitioning rule, Allocation unit size (bytes per cluster)
+    if (res) {
+        debug_if(FFS_DBG, "f_mkfs() failed: %d\n", res);
+        return -1;
+    }
+    return 0;
+}
+
+DirHandle *FATFileSystem::opendir(const char *name) {
+    FATFS_DIR dir;
+    FRESULT res = f_opendir(&dir, name);
+    if (res != 0) {
+        return NULL;
+    }
+    return new FATDirHandle(dir);
+}
+
+int FATFileSystem::mkdir(const char *name, mode_t mode) {
+    FRESULT res = f_mkdir(name);
+    return res == 0 ? 0 : -1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/FATFileSystem/FATFileSystem.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,57 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef MBED_FATFILESYSTEM_H
+#define MBED_FATFILESYSTEM_H
+
+#include "FileSystemLike.h"
+#include "FileHandle.h"
+#include "ff.h"
+#include <stdint.h>
+
+using namespace mbed;
+
+class FATFileSystem : public FileSystemLike {
+public:
+
+    FATFileSystem(const char* n);
+    virtual ~FATFileSystem();
+
+    static FATFileSystem * _ffs[_VOLUMES];   // FATFileSystem objects, as parallel to FatFs drives array
+    FATFS _fs;                               // Work area (file system object) for logical drive
+    int _fsid;
+
+    virtual FileHandle *open(const char* name, int flags);
+    virtual int remove(const char *filename);
+    virtual int format();
+    virtual DirHandle *opendir(const char *name);
+    virtual int mkdir(const char *name, mode_t mode);
+
+    virtual int disk_initialize() { return 0; }
+    virtual int disk_status() { return 0; }
+    virtual int disk_read(uint8_t * buffer, uint64_t sector) = 0;
+    virtual int disk_write(const uint8_t * buffer, uint64_t sector) = 0;
+    virtual int disk_sync() { return 0; }
+    virtual uint64_t disk_sectors() = 0;
+
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost/IUSBEnumerator.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,36 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IUSBENUMERATOR_H_
+#define IUSBENUMERATOR_H_
+
+#include "stdint.h"
+#include "USBEndpoint.h"
+
+/*
+Generic interface to implement for "smart" USB enumeration
+*/
+
+class IUSBEnumerator
+{
+public:
+    virtual void setVidPid(uint16_t vid, uint16_t pid) = 0;
+    virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) = 0; //Must return true if the interface should be parsed
+    virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) = 0; //Must return true if the endpoint will be used
+};
+
+#endif /*IUSBENUMERATOR_H_*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost/USBDeviceConnected.cpp	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,124 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "USBDeviceConnected.h"
+#include "dbg.h"
+
+USBDeviceConnected::USBDeviceConnected() {
+    init();
+}
+
+void USBDeviceConnected::init() {
+    hub_nb = 0;
+    port = 0;
+    vid = 0;
+    pid = 0;
+    nb_interf = 0;
+    enumerated = false;
+    activeAddr = false;
+    sizeControlEndpoint = 8;
+    device_class = 0;
+    device_subclass = 0;
+    proto = 0;
+    speed = false;
+    for (int i = 0; i < MAX_INTF; i++) {
+        memset((void *)&intf[i], 0, sizeof(INTERFACE));
+        intf[i].in_use = false;
+        for (int j = 0; j < MAX_ENDPOINT_PER_INTERFACE; j++) {
+            intf[i].ep[j] = NULL;
+            strcpy(intf[i].name, "Unknown");
+        }
+    }
+    hub_parent = NULL;
+    hub = NULL;
+    nb_interf = 0;
+}
+
+INTERFACE * USBDeviceConnected::getInterface(uint8_t index) {
+    if (index >= MAX_INTF)
+        return NULL;
+    
+    if (intf[index].in_use)
+        return &intf[index];
+    
+    return NULL;
+}
+
+bool USBDeviceConnected::addInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) {
+    if ((intf_nb >= MAX_INTF) || (intf[intf_nb].in_use)) {
+        return false;
+    }
+    intf[intf_nb].in_use = true;
+    intf[intf_nb].intf_class = intf_class;
+    intf[intf_nb].intf_subclass = intf_subclass;
+    intf[intf_nb].intf_protocol = intf_protocol;
+    intf[intf_nb].nb_endpoint = 0;
+    return true;
+}
+
+bool USBDeviceConnected::addEndpoint(uint8_t intf_nb, USBEndpoint * ept) {
+    if ((intf_nb >= MAX_INTF) || (intf[intf_nb].in_use == false) || (intf[intf_nb].nb_endpoint >= MAX_ENDPOINT_PER_INTERFACE)) {
+        return false;
+    }
+    intf[intf_nb].nb_endpoint++;
+
+    for (int i = 0; i < MAX_ENDPOINT_PER_INTERFACE; i++) {
+        if (intf[intf_nb].ep[i] == NULL) {
+            intf[intf_nb].ep[i] = ept;
+            return true;
+        }
+    }
+    return false;
+}
+
+void USBDeviceConnected::init(uint8_t hub_, uint8_t port_, bool lowSpeed_) {
+    USB_DBG("init dev: %p", this);
+    init();
+    hub_nb = hub_;
+    port = port_;
+    speed = lowSpeed_;
+}
+
+void USBDeviceConnected::disconnect() {
+    for(int i = 0; i < MAX_INTF; i++) {
+        intf[i].detach.call();
+    }
+    init();
+}
+
+
+USBEndpoint * USBDeviceConnected::getEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint8_t index) {
+    if (intf_nb >= MAX_INTF) {
+        return NULL;
+    }
+    for (int i = 0; i < MAX_ENDPOINT_PER_INTERFACE; i++) {
+        if ((intf[intf_nb].ep[i]->getType() == type) && (intf[intf_nb].ep[i]->getDir() == dir)) {
+            if(index) {
+                index--;
+            } else {
+                return intf[intf_nb].ep[i];
+            }
+        }
+    }
+    return NULL;
+}
+
+USBEndpoint * USBDeviceConnected::getEndpoint(uint8_t intf_nb, uint8_t index) {
+    if ((intf_nb >= MAX_INTF) || (index >= MAX_ENDPOINT_PER_INTERFACE)) {
+        return NULL;
+    }
+    return intf[intf_nb].ep[index];
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost/USBDeviceConnected.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,185 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USBDEVICECONNECTED_H
+#define USBDEVICECONNECTED_H
+
+#include "stdint.h"
+#include "USBEndpoint.h"
+#include "USBHostConf.h"
+#include "rtos.h"
+
+class USBHostHub;
+
+typedef struct {
+    bool in_use;
+    uint8_t nb_endpoint;
+    uint8_t intf_class;
+    uint8_t intf_subclass;
+    uint8_t intf_protocol;
+    USBEndpoint * ep[MAX_ENDPOINT_PER_INTERFACE];
+    FunctionPointer detach;
+    char name[10];
+} INTERFACE; 
+
+/**
+* USBDeviceConnected class
+*/
+class USBDeviceConnected
+{
+public:
+
+    /**
+    * Constructor
+    */
+    USBDeviceConnected();
+
+    /**
+    * Attach an USBEndpoint to this device
+    *
+    * @param intf_nb interface number
+    * @param ep pointeur on the USBEndpoint which will be attached
+    * @returns true if successful, false otherwise
+    */
+    bool addEndpoint(uint8_t intf_nb, USBEndpoint * ep);
+
+    /**
+    * Retrieve an USBEndpoint by its TYPE and DIRECTION
+    *
+    * @param intf_nb the interface on which to lookup the USBEndpoint
+    * @param type type of the USBEndpoint looked for
+    * @param dir direction of the USBEndpoint looked for
+    * @param index the index of the USBEndpoint whitin the interface
+    * @returns pointer on the USBEndpoint if found, NULL otherwise
+    */
+    USBEndpoint * getEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint8_t index = 0);
+
+    /**
+    * Retrieve an USBEndpoint by its index
+    *
+    * @param intf_nb interface number
+    * @param index index of the USBEndpoint
+    * @returns pointer on the USBEndpoint if found, NULL otherwise
+    */
+    USBEndpoint * getEndpoint(uint8_t intf_nb, uint8_t index);
+
+    /**
+    * Add a new interface to this device
+    *
+    * @param intf_nb interface number
+    * @param intf_class interface class
+    * @param intf_subclass interface subclass
+    * @param intf_protocol interface protocol
+    * @returns true if successful, false otherwise
+    */
+    bool addInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol);
+
+    /**
+    * Get a specific interface
+    *
+    * @param index index of the interface to be fetched
+    * @returns interface
+    */
+    INTERFACE * getInterface(uint8_t index);
+
+    /**
+     *  Attach a member function to call when a the device has been disconnected
+     *
+     *  @param intf_nb interface number
+     *  @param tptr pointer to the object to call the member function on
+     *  @param mptr pointer to the member function to be called
+     */
+    template<typename T>
+    inline void onDisconnect(uint8_t intf_nb, T* tptr, void (T::*mptr)(void)) {
+        if ((mptr != NULL) && (tptr != NULL)) {
+            intf[intf_nb].detach.attach(tptr, mptr);
+        }
+    }
+
+    /**
+     * Attach a callback called when the device has been disconnected
+     *
+     *  @param intf_nb interface number
+     *  @param fn function pointer
+     */
+    inline void onDisconnect(uint8_t intf_nb, void (*fn)(void)) {
+        if (fn != NULL) {
+            intf[intf_nb].detach.attach(fn);
+        }
+    }
+
+    /**
+    * Disconnect the device by calling a callback function registered by a driver
+    */
+    void disconnect();
+
+    // setters
+    void init(uint8_t hub, uint8_t port, bool lowSpeed);
+    inline void setAddress(uint8_t addr_) { addr = addr_; };
+    inline void setVid(uint16_t vid_) { vid = vid_; };
+    inline void setPid(uint16_t pid_) { pid = pid_; };
+    inline void setClass(uint8_t device_class_) { device_class = device_class_; };
+    inline void setSubClass(uint8_t device_subclass_) { device_subclass = device_subclass_; };
+    inline void setProtocol(uint8_t pr) { proto = pr; };
+    inline void setSizeControlEndpoint(uint32_t size) { sizeControlEndpoint = size; };
+    inline void activeAddress(bool active) { activeAddr = active; };
+    inline void setEnumerated() { enumerated = true; };
+    inline void setNbIntf(uint8_t nb_intf) {nb_interf = nb_intf; };
+    inline void setHubParent(USBHostHub * hub) { hub_parent = hub; };
+    inline void setName(const char * name_, uint8_t intf_nb) { strcpy(intf[intf_nb].name, name_); };
+
+    //getters
+    inline uint8_t     getPort() { return port; };
+    inline uint8_t     getHub() { return hub_nb; };
+    inline uint8_t     getAddress() { return addr; };
+    inline uint16_t    getVid() { return vid; };
+    inline uint16_t    getPid() { return pid; };
+    inline uint8_t     getClass() { return device_class; };
+    inline uint8_t     getSubClass() { return device_subclass; };
+    inline uint8_t     getProtocol() { return proto; };
+    inline bool        getSpeed() { return speed; };
+    inline uint32_t    getSizeControlEndpoint() { return sizeControlEndpoint; };
+    inline bool        isActiveAddress() { return activeAddr; };
+    inline bool        isEnumerated() { return enumerated; };
+    inline USBHostHub * getHubParent() { return hub_parent; };
+    inline uint8_t      getNbIntf() { return nb_interf; };
+    inline const char * getName(uint8_t intf_nb) { return intf[intf_nb].name; };
+    
+    // in case this device is a hub
+    USBHostHub * hub;
+
+private:
+    USBHostHub * hub_parent;
+
+    INTERFACE intf[MAX_INTF];
+    uint32_t sizeControlEndpoint;
+    uint8_t hub_nb;
+    uint8_t port;
+    uint16_t vid;
+    uint16_t pid;
+    uint8_t addr;
+    uint8_t device_class;
+    uint8_t device_subclass;
+    uint8_t proto;
+    bool speed;
+    volatile bool activeAddr;
+    volatile bool enumerated;
+    uint8_t nb_interf;
+
+    void init();
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost/USBEndpoint.cpp	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,162 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "dbg.h"
+#include "USBEndpoint.h"
+
+void USBEndpoint::init(HCED * hced_, ENDPOINT_TYPE type_, ENDPOINT_DIRECTION dir_, uint32_t size, uint8_t ep_number, HCTD* td_list_[2])
+{
+    hced = hced_;
+    type = type_;
+    dir = dir_;
+    setup = (type == CONTROL_ENDPOINT) ? true : false;
+
+    //TDs have been allocated by the host
+    memcpy((HCTD**)td_list, td_list_, sizeof(HCTD*)*2); //TODO: Maybe should add a param for td_list size... at least a define
+    memcpy(td_list_[0], 0, sizeof(HCTD));
+    memcpy(td_list_[1], 0, sizeof(HCTD));
+    
+    td_list[0]->ep = this;
+    td_list[1]->ep = this;
+
+    hced->control = 0;
+    //Empty queue
+    hced->tailTD = td_list[0];
+    hced->headTD = td_list[0];
+    hced->nextED = 0;
+
+    address = (ep_number & 0x7F) | ((dir - 1) << 7);
+
+    hced->control = ((ep_number & 0x7F) << 7)                         // Endpoint address
+                    | (type != CONTROL_ENDPOINT ? ( dir << 11) : 0 )  // direction : Out = 1, 2 = In
+                    | ((size & 0x3ff) << 16);                         // MaxPkt Size
+
+    transfer_len = 0;
+    transferred = 0;
+    buf_start = 0;
+    nextEp = NULL;
+
+    td_current = td_list[0];
+    td_next = td_list[1];
+    
+    intf_nb = 0;
+
+    state = USB_TYPE_IDLE;
+}
+
+void USBEndpoint::setSize(uint32_t size)
+{
+    hced->control &= ~(0x3ff << 16);
+    hced->control |= (size << 16);
+}
+
+
+void USBEndpoint::setDeviceAddress(uint8_t addr)
+{
+    hced->control &= ~(0x7f);
+    hced->control |= (addr & 0x7F);
+}
+
+void USBEndpoint::setSpeed(uint8_t speed)
+{
+    hced->control &= ~(1 << 13);
+    hced->control |= (speed << 13);
+}
+
+//Only for control Eps
+void USBEndpoint::setNextToken(uint32_t token)
+{
+    switch (token) {
+        case TD_SETUP:
+            dir = OUT;
+            setup = true;
+            break;
+        case TD_IN:
+            dir = IN;
+            setup = false;
+            break;
+        case TD_OUT:
+            dir = OUT;
+            setup = false;
+            break;
+    }
+}
+
+struct {
+    USB_TYPE type;
+    const char * str;
+} static type_string[] = {
+/*0*/   {USB_TYPE_OK, "USB_TYPE_OK"},
+        {USB_TYPE_CRC_ERROR, "USB_TYPE_CRC_ERROR"},
+        {USB_TYPE_BIT_STUFFING_ERROR, "USB_TYPE_BIT_STUFFING_ERROR"},
+        {USB_TYPE_DATA_TOGGLE_MISMATCH_ERROR, "USB_TYPE_DATA_TOGGLE_MISMATCH_ERROR"},
+        {USB_TYPE_STALL_ERROR, "USB_TYPE_STALL_ERROR"},
+/*5*/   {USB_TYPE_DEVICE_NOT_RESPONDING_ERROR, "USB_TYPE_DEVICE_NOT_RESPONDING_ERROR"},
+        {USB_TYPE_PID_CHECK_FAILURE_ERROR, "USB_TYPE_PID_CHECK_FAILURE_ERROR"},
+        {USB_TYPE_UNEXPECTED_PID_ERROR, "USB_TYPE_UNEXPECTED_PID_ERROR"},
+        {USB_TYPE_DATA_OVERRUN_ERROR, "USB_TYPE_DATA_OVERRUN_ERROR"},
+        {USB_TYPE_DATA_UNDERRUN_ERROR, "USB_TYPE_DATA_UNDERRUN_ERROR"},
+/*10*/  {USB_TYPE_ERROR, "USB_TYPE_ERROR"},
+        {USB_TYPE_ERROR, "USB_TYPE_ERROR"},
+        {USB_TYPE_BUFFER_OVERRUN_ERROR, "USB_TYPE_BUFFER_OVERRUN_ERROR"},
+        {USB_TYPE_BUFFER_UNDERRUN_ERROR, "USB_TYPE_BUFFER_UNDERRUN_ERROR"},
+        {USB_TYPE_DISCONNECTED, "USB_TYPE_DISCONNECTED"},
+/*15*/  {USB_TYPE_FREE, "USB_TYPE_FREE"},
+        {USB_TYPE_IDLE, "USB_TYPE_IDLE"},
+        {USB_TYPE_PROCESSING, "USB_TYPE_PROCESSING"},
+        {USB_TYPE_ERROR, "USB_TYPE_ERROR"}
+};
+
+void USBEndpoint::setState(uint8_t st) {
+    if (st > 18)
+        return;
+    state = type_string[st].type;
+}
+
+
+const char * USBEndpoint::getStateString() {
+    return type_string[state].str;
+}
+
+void USBEndpoint::queueTransfer()
+{
+    transfer_len = (uint32_t)td_current->bufEnd - (uint32_t)td_current->currBufPtr + 1;
+    transferred = transfer_len;
+    buf_start = (uint8_t *)td_current->currBufPtr;
+
+    //Now add this free TD at this end of the queue
+    state = USB_TYPE_PROCESSING;
+    td_current->nextTD = td_next;
+    hced->tailTD = td_next;
+}
+
+void USBEndpoint::unqueueTransfer(volatile HCTD * td)
+{
+    td->control=0;
+    td->currBufPtr=0;
+    td->bufEnd=0;
+    td->nextTD=0;
+    hced->headTD = (HCTD *)((uint32_t)hced->tailTD | ((uint32_t)hced->headTD & 0x2)); //Carry bit
+    td_current = td_next;
+    td_next = td;
+}
+
+void USBEndpoint::queueEndpoint(USBEndpoint * ed)
+{
+    nextEp = ed;
+    hced->nextED = (ed == NULL) ? 0 : ed->getHCED();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost/USBEndpoint.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,171 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USBENDPOINT_H
+#define USBENDPOINT_H
+
+#include "FunctionPointer.h"
+#include "USBHostTypes.h"
+#include "rtos.h"
+
+class USBDeviceConnected;
+
+/**
+* USBEndpoint class
+*/
+class USBEndpoint
+{
+public:
+    /**
+    * Constructor
+    */
+    USBEndpoint() {
+        state = USB_TYPE_FREE;
+        nextEp = NULL;
+    };
+
+    /**
+    * Initialize an endpoint
+    *
+    * @param hced hced associated to the endpoint
+    * @param type endpoint type
+    * @param dir endpoint direction
+    * @param size endpoint size
+    * @param ep_number endpoint number
+    * @param td_list array of two allocated transfer descriptors
+    */
+    void init(HCED * hced, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint32_t size, uint8_t ep_number, HCTD* td_list[2]);
+
+    /**
+    * Set next token. Warning: only useful for the control endpoint
+    *
+    * @param token IN, OUT or SETUP token
+    */
+    void setNextToken(uint32_t token);
+
+    /**
+    * Queue an endpoint
+    *
+    * @param endpoint endpoint which will be queued in the linked list
+    */
+    void queueEndpoint(USBEndpoint * endpoint);
+
+
+    /**
+    * Queue a transfer on the endpoint
+    */
+    void queueTransfer();
+
+    /**
+    * Unqueue a transfer from the endpoint
+    *
+    * @param td hctd which will be unqueued
+    */
+    void unqueueTransfer(volatile HCTD * td);
+
+    /**
+     *  Attach a member function to call when a transfer is finished
+     *
+     *  @param tptr pointer to the object to call the member function on
+     *  @param mptr pointer to the member function to be called
+     */
+    template<typename T>
+    inline void attach(T* tptr, void (T::*mptr)(void)) {
+        if((mptr != NULL) && (tptr != NULL)) {
+            rx.attach(tptr, mptr);
+        }
+    }
+
+    /**
+     * Attach a callback called when a transfer is finished
+     *
+     * @param fptr function pointer
+     */
+    inline void attach(void (*fptr)(void)) {
+        if(fptr != NULL) {
+            rx.attach(fptr);
+        }
+    }
+
+    /**
+    * Call the handler associted to the end of a transfer
+    */
+    inline void call() {
+        rx.call();
+    };
+
+
+    // setters
+    inline void setState(USB_TYPE st) { state = st; }
+    void setState(uint8_t st);
+    void setDeviceAddress(uint8_t addr);
+    inline void setLengthTransferred(int len) { transferred = len; };
+    void setSpeed(uint8_t speed);
+    void setSize(uint32_t size);
+    inline void setDir(ENDPOINT_DIRECTION d) { dir = d; }
+    inline void setIntfNb(uint8_t intf_nb_) { intf_nb = intf_nb_; };
+
+    // getters
+    const char *                getStateString();
+    inline USB_TYPE             getState() { return state; }
+    inline ENDPOINT_TYPE        getType() { return type; };
+    inline uint8_t              getDeviceAddress() { return hced->control & 0x7f; };
+    inline int                  getLengthTransferred() { return transferred; }
+    inline uint8_t *            getBufStart() { return buf_start; }
+    inline uint8_t              getAddress(){ return address; };
+    inline uint32_t             getSize() { return (hced->control >> 16) & 0x3ff; };
+    inline volatile HCTD *      getHeadTD() { return (volatile HCTD*) ((uint32_t)hced->headTD & ~0xF); };
+    inline volatile HCTD**      getTDList() { return td_list; };
+    inline volatile HCED *      getHCED() { return hced; };
+    inline ENDPOINT_DIRECTION   getDir() { return dir; }
+    inline volatile HCTD *      getProcessedTD() { return td_current; };
+    inline volatile HCTD*       getNextTD() { return td_current; };
+    inline bool                 isSetup() { return setup; }
+    inline USBEndpoint *        nextEndpoint() { return (USBEndpoint*)nextEp; };
+    inline uint8_t              getIntfNb() { return intf_nb; };
+    
+    USBDeviceConnected * dev;
+    
+    Queue<uint8_t, 1> ep_queue;
+
+private:
+    ENDPOINT_TYPE type;
+    volatile USB_TYPE state;
+    ENDPOINT_DIRECTION dir;
+    bool setup;
+
+    uint8_t address;
+
+    int transfer_len;
+    int transferred;
+    uint8_t * buf_start;
+
+    FunctionPointer rx;
+
+    USBEndpoint* nextEp;
+
+    // USBEndpoint descriptor
+    volatile HCED * hced;
+
+    volatile HCTD * td_list[2];
+    volatile HCTD * td_current;
+    volatile HCTD * td_next;
+    
+    uint8_t intf_nb;
+
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost/USBHALHost.cpp	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,322 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mbed.h"
+#include "USBHALHost.h"
+#include "dbg.h"
+
+// bits of the USB/OTG clock control register
+#define HOST_CLK_EN     (1<<0)
+#define DEV_CLK_EN      (1<<1)
+#define PORTSEL_CLK_EN  (1<<3)
+#define AHB_CLK_EN      (1<<4)
+
+// bits of the USB/OTG clock status register
+#define HOST_CLK_ON     (1<<0)
+#define DEV_CLK_ON      (1<<1)
+#define PORTSEL_CLK_ON  (1<<3)
+#define AHB_CLK_ON      (1<<4)
+
+// we need host clock, OTG/portsel clock and AHB clock
+#define CLOCK_MASK (HOST_CLK_EN | PORTSEL_CLK_EN | AHB_CLK_EN)
+
+#define HCCA_SIZE sizeof(HCCA)
+#define ED_SIZE sizeof(HCED)
+#define TD_SIZE sizeof(HCTD)
+
+#define TOTAL_SIZE (HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE) + (MAX_TD*TD_SIZE))
+
+static volatile __align(256) uint8_t usb_buf[TOTAL_SIZE] __attribute((section("AHBSRAM1"),aligned));  //256 bytes aligned!
+
+USBHALHost * USBHALHost::instHost;
+
+USBHALHost::USBHALHost() {
+    instHost = this;
+    memInit();
+    memset((void*)usb_hcca, 0, HCCA_SIZE);
+    for (int i = 0; i < MAX_ENDPOINT; i++) {
+        edBufAlloc[i] = false;
+    }
+    for (int i = 0; i < MAX_TD; i++) {
+        tdBufAlloc[i] = false;
+    }
+}
+
+void USBHALHost::init() {
+    NVIC_DisableIRQ(USB_IRQn);
+    
+    //Cut power
+    LPC_SC->PCONP &= ~(1UL<<31);
+    wait_ms(100);
+
+    // turn on power for USB
+    LPC_SC->PCONP       |= (1UL<<31);
+
+    // Enable USB host clock, port selection and AHB clock
+    LPC_USB->USBClkCtrl |= CLOCK_MASK;
+
+    // Wait for clocks to become available
+    while ((LPC_USB->USBClkSt & CLOCK_MASK) != CLOCK_MASK);
+
+    // it seems the bits[0:1] mean the following
+    // 0: U1=device, U2=host
+    // 1: U1=host, U2=host
+    // 2: reserved
+    // 3: U1=host, U2=device
+    // NB: this register is only available if OTG clock (aka "port select") is enabled!!
+    // since we don't care about port 2, set just bit 0 to 1 (U1=host)
+    LPC_USB->OTGStCtrl |= 1;
+
+    // now that we've configured the ports, we can turn off the portsel clock
+    LPC_USB->USBClkCtrl &= ~PORTSEL_CLK_EN;
+
+    // configure USB D+/D- pins
+    // P0[29] = USB_D+, 01
+    // P0[30] = USB_D-, 01
+    LPC_PINCON->PINSEL1 &= ~((3<<26) | (3<<28));
+    LPC_PINCON->PINSEL1 |=  ((1<<26) | (1<<28));
+
+    LPC_USB->HcControl       = 0; // HARDWARE RESET
+    LPC_USB->HcControlHeadED = 0; // Initialize Control list head to Zero
+    LPC_USB->HcBulkHeadED    = 0; // Initialize Bulk list head to Zero
+
+    // Wait 100 ms before apply reset
+    wait_ms(100);
+
+    // software reset
+    LPC_USB->HcCommandStatus = OR_CMD_STATUS_HCR;
+    
+    // Write Fm Interval and Largest Data Packet Counter
+    LPC_USB->HcFmInterval    = DEFAULT_FMINTERVAL;
+    LPC_USB->HcPeriodicStart = FI * 90 / 100;
+
+    // Put HC in operational state
+    LPC_USB->HcControl  = (LPC_USB->HcControl & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER;
+    // Set Global Power
+    LPC_USB->HcRhStatus = OR_RH_STATUS_LPSC;
+
+    LPC_USB->HcHCCA = (uint32_t)(usb_hcca);
+    
+    // Clear Interrrupt Status
+    LPC_USB->HcInterruptStatus |= LPC_USB->HcInterruptStatus;
+
+    LPC_USB->HcInterruptEnable  = OR_INTR_ENABLE_MIE | OR_INTR_ENABLE_WDH | OR_INTR_ENABLE_RHSC;
+
+    // Enable the USB Interrupt
+    NVIC_SetVector(USB_IRQn, (uint32_t)(_usbisr));
+    LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC;
+    LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC;
+
+    NVIC_EnableIRQ(USB_IRQn);
+
+    // Check for any connected devices
+    if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS) {
+        //Device connected
+        wait_ms(150);
+        USB_DBG("Device connected (%08x)\n\r", LPC_USB->HcRhPortStatus1);
+        deviceConnected(0, 1, LPC_USB->HcRhPortStatus1 & OR_RH_PORT_LSDA);
+    }
+}
+
+uint32_t USBHALHost::controlHeadED() {
+    return LPC_USB->HcControlHeadED;
+}
+
+uint32_t USBHALHost::bulkHeadED() {
+    return LPC_USB->HcBulkHeadED;
+}
+
+uint32_t USBHALHost::interruptHeadED() {
+    return usb_hcca->IntTable[0];
+}
+
+void USBHALHost::updateBulkHeadED(uint32_t addr) {
+    LPC_USB->HcBulkHeadED = addr;
+}
+
+
+void USBHALHost::updateControlHeadED(uint32_t addr) {
+    LPC_USB->HcControlHeadED = addr;
+}
+
+void USBHALHost::updateInterruptHeadED(uint32_t addr) {
+    usb_hcca->IntTable[0] = addr;
+}
+
+
+void USBHALHost::enableList(ENDPOINT_TYPE type) {
+    switch(type) {
+        case CONTROL_ENDPOINT:
+            LPC_USB->HcCommandStatus = OR_CMD_STATUS_CLF;
+            LPC_USB->HcControl |= OR_CONTROL_CLE;
+            break;
+        case ISOCHRONOUS_ENDPOINT:
+            break;
+        case BULK_ENDPOINT:
+            LPC_USB->HcCommandStatus = OR_CMD_STATUS_BLF;
+            LPC_USB->HcControl |= OR_CONTROL_BLE;
+            break;
+        case INTERRUPT_ENDPOINT:
+            LPC_USB->HcControl |= OR_CONTROL_PLE;
+            break;
+    }
+}
+
+
+bool USBHALHost::disableList(ENDPOINT_TYPE type) {
+    switch(type) {
+        case CONTROL_ENDPOINT:
+            if(LPC_USB->HcControl & OR_CONTROL_CLE) {
+                LPC_USB->HcControl &= ~OR_CONTROL_CLE;
+                return true;
+            }
+            return false;
+        case ISOCHRONOUS_ENDPOINT:
+            return false;
+        case BULK_ENDPOINT:
+            if(LPC_USB->HcControl & OR_CONTROL_BLE){
+                LPC_USB->HcControl &= ~OR_CONTROL_BLE;
+                return true;
+            }
+            return false;
+        case INTERRUPT_ENDPOINT:
+            if(LPC_USB->HcControl & OR_CONTROL_PLE) {
+                LPC_USB->HcControl &= ~OR_CONTROL_PLE;
+                return true;
+            }
+            return false;
+    }
+    return false;
+}
+
+
+void USBHALHost::memInit() {
+    usb_hcca = (volatile HCCA *)usb_buf;
+    usb_edBuf = usb_buf + HCCA_SIZE;
+    usb_tdBuf = usb_buf + HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE);
+}
+
+volatile uint8_t * USBHALHost::getED() {
+    for (int i = 0; i < MAX_ENDPOINT; i++) {
+        if ( !edBufAlloc[i] ) {
+            edBufAlloc[i] = true;
+            return (volatile uint8_t *)(usb_edBuf + i*ED_SIZE);
+        }
+    }
+    perror("Could not allocate ED\r\n");
+    return NULL; //Could not alloc ED
+}
+
+volatile uint8_t * USBHALHost::getTD() {
+    int i;
+    for (i = 0; i < MAX_TD; i++) {
+        if ( !tdBufAlloc[i] ) {
+            tdBufAlloc[i] = true;
+            return (volatile uint8_t *)(usb_tdBuf + i*TD_SIZE);
+        }
+    }
+    perror("Could not allocate TD\r\n");
+    return NULL; //Could not alloc TD
+}
+
+
+void USBHALHost::freeED(volatile uint8_t * ed) {
+    int i;
+    i = (ed - usb_edBuf) / ED_SIZE;
+    edBufAlloc[i] = false;
+}
+
+void USBHALHost::freeTD(volatile uint8_t * td) {
+    int i;
+    i = (td - usb_tdBuf) / TD_SIZE;
+    tdBufAlloc[i] = false;
+}
+
+
+void USBHALHost::resetRootHub() {
+    // Initiate port reset
+    LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRS;
+    
+    while (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRS);
+    
+    // ...and clear port reset signal
+    LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC;
+}
+
+
+void USBHALHost::_usbisr(void) {
+    if (instHost) {
+        instHost->UsbIrqhandler();
+    }
+}
+
+void USBHALHost::UsbIrqhandler() {
+    if( LPC_USB->HcInterruptStatus & LPC_USB->HcInterruptEnable ) //Is there something to actually process?
+    {
+        
+        uint32_t int_status = LPC_USB->HcInterruptStatus & LPC_USB->HcInterruptEnable;
+
+        // Root hub status change interrupt
+        if (int_status & OR_INTR_STATUS_RHSC) { 
+            if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CSC) {
+                if (LPC_USB->HcRhStatus & OR_RH_STATUS_DRWE) {
+                    // When DRWE is on, Connect Status Change
+                    // means a remote wakeup event.
+                } else {
+
+                    //Root device connected
+                    if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS) { 
+                        
+                        // wait 150ms to avoid bounce
+                        wait_ms(150);
+                        
+                        //Hub 0 (root hub), Port 1 (count starts at 1), Low or High speed
+                        deviceConnected(0, 1, LPC_USB->HcRhPortStatus1 & OR_RH_PORT_LSDA); 
+                    } 
+                    
+                    //Root device disconnected
+                    else { 
+                        
+                        if (!(int_status & OR_INTR_STATUS_WDH)) {
+                            usb_hcca->DoneHead = 0;
+                        }
+                        
+                        // wait 200ms to avoid bounce
+                        wait_ms(200);
+                        
+                        deviceDisconnected(0, 1, NULL, usb_hcca->DoneHead & 0xFFFFFFFE);
+                        
+                        if (int_status & OR_INTR_STATUS_WDH) {
+                            usb_hcca->DoneHead = 0;
+                            LPC_USB->HcInterruptStatus = OR_INTR_STATUS_WDH;
+                        }
+                    }
+                }
+                LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC;
+            }
+            if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRSC) {
+                LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC;
+            }
+            LPC_USB->HcInterruptStatus = OR_INTR_STATUS_RHSC;
+        }
+
+        // Writeback Done Head interrupt
+        if (int_status & OR_INTR_STATUS_WDH) {
+            transferCompleted(usb_hcca->DoneHead & 0xFFFFFFFE);
+            LPC_USB->HcInterruptStatus = OR_INTR_STATUS_WDH;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost/USBHALHost.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,169 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USBHALHOST_H
+#define USBHALHOST_H
+
+#include "USBHostTypes.h"
+#include "USBHostConf.h"
+
+class USBHostHub;
+
+/**
+* USBHALHost class
+*/
+class USBHALHost {
+protected:
+
+    /**
+    * Constructor
+    * init variables and memory where will be stored HCCA, ED and TD
+    */
+    USBHALHost();
+    
+    /**
+    * Initialize host controller. Enable USB interrupts. This part is not in the constructor because, 
+    * this function calls a virtual method if a device is already connected
+    */
+    void init();
+    
+    /**
+    * reset the root hub
+    */
+    void resetRootHub();
+    
+    /**
+    * return the value contained in the control HEAD ED register
+    *
+    * @returns address of the control Head ED
+    */
+    uint32_t controlHeadED();
+    
+    /**
+    * return the value contained in the bulk HEAD ED register
+    *
+    * @returns address of the bulk head ED
+    */
+    uint32_t bulkHeadED();
+    
+    /**
+    * return the value of the head interrupt ED contained in the HCCA
+    *
+    * @returns address of the head interrupt ED contained in the HCCA
+    */
+    uint32_t interruptHeadED();
+    
+    /**
+    * Update the head ED for control transfers
+    */
+    void updateControlHeadED(uint32_t addr);
+    
+    /**
+    * Update the head ED for bulk transfers
+    */
+    void updateBulkHeadED(uint32_t addr);
+    
+    /**
+    * Update the head ED for interrupt transfers
+    */
+    void updateInterruptHeadED(uint32_t addr);
+    
+    /**
+    * Enable List for the specified endpoint type
+    *
+    * @param type enable the list of ENDPOINT_TYPE type
+    */
+    void enableList(ENDPOINT_TYPE type);
+    
+    /**
+    * Disable List for the specified endpoint type
+    *
+    * @param type disable the list of ENDPOINT_TYPE type
+    */
+    bool disableList(ENDPOINT_TYPE type);
+
+    /**
+    * Virtual method called when a device has been connected
+    *
+    * @param hub hub number of the device
+    * @param port port number of the device
+    * @param lowSpeed 1 if low speed, 0 otherwise
+    * @param hub_parent reference to the hub where the device is connected (NULL if the hub parent is the root hub)
+    */
+    virtual void deviceConnected(int hub, int port, bool lowSpeed, USBHostHub * hub_parent = NULL) = 0;
+    
+    /**
+    * Virtual method called when a device has been disconnected
+    *
+    * @param hub hub number of the device
+    * @param port port number of the device
+    * @param hub_parent reference to the hub where the device is connected (NULL if the hub parent is the root hub)
+    * @param addr list of the TDs which have been completed to dequeue freed TDs
+    */
+    virtual void deviceDisconnected(int hub, int port, USBHostHub * hub_parent, volatile uint32_t addr) = 0;
+    
+    /**
+    * Virtual method called when a transfer has been completed
+    *
+    * @param addr list of the TDs which have been completed
+    */
+    virtual void transferCompleted(volatile uint32_t addr) = 0;
+    
+    /**
+    * Find a memory section for a new ED
+    *
+    * @returns the address of the new ED
+    */
+    volatile uint8_t * getED();
+    
+    /**
+    * Find a memory section for a new TD
+    *
+    * @returns the address of the new TD
+    */
+    volatile uint8_t * getTD();
+    
+    /**
+    * Release a previous memory section reserved for an ED
+    *
+    * @param ed address of the ED
+    */
+    void freeED(volatile uint8_t * ed);
+    
+    /**
+    * Release a previous memory section reserved for an TD
+    *
+    * @param td address of the TD
+    */
+    void freeTD(volatile uint8_t * td);
+
+private:
+    static void _usbisr(void);
+    void UsbIrqhandler();
+
+    void memInit();
+
+    HCCA volatile * usb_hcca;           //256 bytes aligned
+    uint8_t volatile  * usb_edBuf;      //4 bytes aligned
+    uint8_t volatile  * usb_tdBuf;      //4 bytes aligned
+
+    static USBHALHost * instHost;
+    
+    bool volatile  edBufAlloc[MAX_ENDPOINT];
+    bool volatile tdBufAlloc[MAX_TD];
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost/USBHost.cpp	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,1161 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "USBHost.h"
+#include "USBHostHub.h"
+
+USBHost * USBHost::instHost = NULL;
+
+#define DEVICE_CONNECTED_EVENT      (1 << 0)
+#define DEVICE_DISCONNECTED_EVENT   (1 << 1)
+#define TD_PROCESSED_EVENT          (1 << 2)
+
+#define MAX_TRY_ENUMERATE_HUB       3
+
+#define MIN(a, b) ((a > b) ? b : a)
+
+/**
+* How interrupts are processed:
+*    - new device connected:
+*       - a message is queued in queue_usb_event with the id DEVICE_CONNECTED_EVENT
+*       - when the usb_thread receives the event, it:
+*           - resets the device
+*           - reads the device descriptor
+*           - sets the address of the device
+*           - if it is a hub, enumerates it
+*   - device disconnected:
+*       - a message is queued in queue_usb_event with the id DEVICE_DISCONNECTED_EVENT
+*       - when the usb_thread receives the event, it:
+*           - free the device and all its children (hub)
+*   - td processed
+*       - a message is queued in queue_usb_event with the id TD_PROCESSED_EVENT
+*       - when the usb_thread receives the event, it:
+*           - call the callback attached to the endpoint where the td is attached
+*/
+void USBHost::usb_process() {
+    
+    bool controlListState;
+    bool bulkListState;
+    bool interruptListState;
+    USBEndpoint * ep;
+    uint8_t i, j, res, timeout_set_addr = 10;
+    uint8_t buf[8];
+    bool too_many_hub;
+    int idx;
+
+#if DEBUG_TRANSFER
+    uint8_t * buf_transfer;
+#endif
+        
+#if MAX_HUB_NB
+    uint8_t k;
+#endif
+    
+    while(1) {
+        osEvent evt = mail_usb_event.get();
+        
+        if (evt.status == osEventMail) {
+            
+            message_t * usb_msg = (message_t*)evt.value.p;
+            
+            switch (usb_msg->event_id) {
+                
+                // a new device has been connected
+                case DEVICE_CONNECTED_EVENT:
+                    too_many_hub = false;
+                    buf[4] = 0;
+                
+                    usb_mutex.lock();
+                    
+                    for (i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+                        if (!deviceInUse[i]) {
+                            USB_DBG_EVENT("new device connected: %p\r\n", &devices[i]);
+                            devices[i].init(usb_msg->hub, usb_msg->port, usb_msg->lowSpeed);
+                            deviceReset[i] = false;
+                            deviceInited[i] = true;
+                            break;
+                        }
+                    }
+                    
+                    if (i == MAX_DEVICE_CONNECTED) {
+                        USB_ERR("Too many device connected!!\r\n");
+                        deviceInited[i] = false;
+                        usb_mutex.unlock();
+                        continue;
+                    }
+                    
+                    if (!controlEndpointAllocated) {
+                        control = newEndpoint(CONTROL_ENDPOINT, OUT, 0x08, 0x00);
+                        addEndpoint(NULL, 0, (USBEndpoint*)control);
+                        controlEndpointAllocated = true;
+                    }
+                    
+#if MAX_HUB_NB
+                    if (usb_msg->hub_parent)
+                        devices[i].setHubParent((USBHostHub *)(usb_msg->hub_parent));
+#endif
+                    
+                    for (j = 0; j < timeout_set_addr; j++) {
+                        
+                        resetDevice(&devices[i]);
+                        
+                        // set size of control endpoint
+                        devices[i].setSizeControlEndpoint(8);
+                        
+                        devices[i].activeAddress(false);
+                        
+                        // get first 8 bit of device descriptor
+                        // and check if we deal with a hub
+                        USB_DBG("usb_thread read device descriptor on dev: %p\r\n", &devices[i]);
+                        res = getDeviceDescriptor(&devices[i], buf, 8);
+                    
+                        if (res != USB_TYPE_OK) {
+                            USB_ERR("usb_thread could not read dev descr");
+                            continue;
+                        }
+                    
+                        // set size of control endpoint
+                        devices[i].setSizeControlEndpoint(buf[7]);
+                        
+                        // second step: set an address to the device
+                        res = setAddress(&devices[i], devices[i].getAddress());
+                    
+                        if (res != USB_TYPE_OK) {
+                            USB_ERR("SET ADDR FAILED");
+                            continue;
+                        }
+                        devices[i].activeAddress(true);
+                        USB_DBG("Address of %p: %d", &devices[i], devices[i].getAddress());
+                        
+                        // try to read again the device descriptor to check if the device
+                        // answers to its new address
+                        res = getDeviceDescriptor(&devices[i], buf, 8);
+                    
+                        if (res == USB_TYPE_OK) {
+                            break;
+                        }
+                        
+                        Thread::wait(100);
+                    }
+                    
+                    USB_INFO("New device connected: %p [hub: %d - port: %d]", &devices[i], usb_msg->hub, usb_msg->port);
+                    
+#if MAX_HUB_NB
+                    if (buf[4] == HUB_CLASS) {
+                        for (k = 0; k < MAX_HUB_NB; k++) {
+                            if (hub_in_use[k] == false) {
+                                for (uint8_t j = 0; j < MAX_TRY_ENUMERATE_HUB; j++) {
+                                    if (hubs[k].connect(&devices[i])) {
+                                        devices[i].hub = &hubs[k];
+                                        hub_in_use[k] = true;
+                                        break;
+                                    }
+                                }
+                                if (hub_in_use[k] == true)
+                                    break;
+                            }
+                        }
+                        
+                        if (k == MAX_HUB_NB) {
+                            USB_ERR("Too many hubs connected!!\r\n");
+                            too_many_hub = true;
+                        }
+                    }
+                    
+                    if (usb_msg->hub_parent)
+                        ((USBHostHub *)(usb_msg->hub_parent))->deviceConnected(&devices[i]);
+#endif
+                    
+                    if ((i < MAX_DEVICE_CONNECTED) && !too_many_hub) {
+                        deviceInUse[i] = true;
+                    }
+                    
+                    usb_mutex.unlock();
+                    
+                    break;
+                    
+                // a device has been disconnected
+                case DEVICE_DISCONNECTED_EVENT:
+                    
+                    usb_mutex.lock();
+                
+                    controlListState = disableList(CONTROL_ENDPOINT);
+                    bulkListState = disableList(BULK_ENDPOINT);
+                    interruptListState = disableList(INTERRUPT_ENDPOINT);
+                
+                    idx = findDevice(usb_msg->hub, usb_msg->port, (USBHostHub *)(usb_msg->hub_parent));
+                    if (idx != -1) {
+                        freeDevice((USBDeviceConnected*)&devices[idx]);
+                    }
+                    
+                    if (controlListState) enableList(CONTROL_ENDPOINT);
+                    if (bulkListState) enableList(BULK_ENDPOINT);
+                    if (interruptListState) enableList(INTERRUPT_ENDPOINT);
+                    
+                    usb_mutex.unlock();
+                    
+                    break;
+                    
+                // a td has been processed
+                // call callback on the ed associated to the td
+                // we are not in ISR -> users can use printf in their callback method
+                case TD_PROCESSED_EVENT:
+                    ep = (USBEndpoint *) ((HCTD *)usb_msg->td_addr)->ep;
+                    if (usb_msg->td_state == USB_TYPE_IDLE) {
+                        USB_DBG_EVENT("call callback on td %p [ep: %p state: %s - dev: %p - %s]", usb_msg->td_addr, ep, ep->getStateString(), ep->dev, ep->dev->getName(ep->getIntfNb()));
+
+#if DEBUG_TRANSFER
+                        if (ep->getDir() == IN) {
+                            buf_transfer = ep->getBufStart();
+                            printf("READ SUCCESS [%d bytes transferred - td: 0x%08X] on ep: [%p - addr: %02X]: ",  ep->getLengthTransferred(), usb_msg->td_addr, ep, ep->getAddress());
+                            for (int i = 0; i < ep->getLengthTransferred(); i++)
+                                printf("%02X ", buf_transfer[i]);
+                            printf("\r\n\r\n");
+                        }
+#endif
+                        ep->call();
+                    } else {
+                        idx = findDevice(ep->dev);
+                        if (idx != -1) {
+                            if (deviceInUse[idx]) {
+                                USB_WARN("td %p processed but not in idle state: %s [ep: %p - dev: %p - %s]", usb_msg->td_addr, ep->getStateString(), ep, ep->dev, ep->dev->getName(ep->getIntfNb()));
+                                ep->setState(USB_TYPE_IDLE);
+                            }
+                        }
+                    }
+                    break;
+            }
+            
+            mail_usb_event.free(usb_msg);
+        }
+    }
+}
+
+/* static */void USBHost::usb_process_static(void const * arg) {
+    ((USBHost *)arg)->usb_process();
+}
+
+USBHost::USBHost() : usbThread(USBHost::usb_process_static, (void *)this, osPriorityNormal, USB_THREAD_STACK)
+{
+    headControlEndpoint = NULL;
+    headBulkEndpoint = NULL;
+    headInterruptEndpoint = NULL;
+    tailControlEndpoint = NULL;
+    tailBulkEndpoint = NULL;
+    tailInterruptEndpoint = NULL;
+
+    lenReportDescr = 0;
+
+    controlEndpointAllocated = false;
+
+    for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+        deviceInUse[i] = false;
+        devices[i].setAddress(i + 1);
+        deviceReset[i] = false;
+        deviceInited[i] = false;
+        for (uint8_t j = 0; j < MAX_INTF; j++)
+            deviceAttachedDriver[i][j] = false;
+    }
+    
+#if MAX_HUB_NB
+    for (uint8_t i = 0; i < MAX_HUB_NB; i++) {
+        hubs[i].setHost(this);
+        hub_in_use[i] = false;
+    }
+#endif
+}
+
+
+void USBHost::transferCompleted(volatile uint32_t addr)
+{
+    uint8_t state;
+
+    if(addr == NULL)
+        return;
+
+    volatile HCTD* tdList = NULL;
+
+    //First we must reverse the list order and dequeue each TD
+    do {
+        volatile HCTD* td = (volatile HCTD*)addr;
+        addr = (uint32_t)td->nextTD; //Dequeue from physical list
+        td->nextTD = tdList; //Enqueue into reversed list
+        tdList = td;
+    } while(addr);
+
+    while(tdList != NULL) {
+        volatile HCTD* td = tdList;
+        tdList = (volatile HCTD*)td->nextTD; //Dequeue element now as it could be modified below
+        if (td->ep != NULL) {
+            USBEndpoint * ep = (USBEndpoint *)(td->ep);
+            
+            if (((HCTD *)td)->control >> 28) {
+                state = ((HCTD *)td)->control >> 28;
+            } else {
+                if (td->currBufPtr)
+                    ep->setLengthTransferred((uint32_t)td->currBufPtr - (uint32_t)ep->getBufStart());
+                state = 16 /*USB_TYPE_IDLE*/;
+            }
+            
+            ep->unqueueTransfer(td);
+            
+            if (ep->getType() != CONTROL_ENDPOINT) {
+                // callback on the processed td will be called from the usb_thread (not in ISR)
+                message_t * usb_msg = mail_usb_event.alloc();
+                usb_msg->event_id = TD_PROCESSED_EVENT;
+                usb_msg->td_addr = (void *)td;
+                usb_msg->td_state = state;
+                mail_usb_event.put(usb_msg);
+            }
+            ep->setState(state);
+            ep->ep_queue.put((uint8_t*)1);
+        }
+    }
+}
+
+USBHost * USBHost::getHostInst()
+{
+    if (instHost == NULL) {
+        instHost = new USBHost();
+        instHost->init();
+    }
+    return instHost;
+}
+
+
+/*
+ * Called when a device has been connected
+ * Called in ISR!!!! (no printf)
+ */
+/* virtual */ void USBHost::deviceConnected(int hub, int port, bool lowSpeed, USBHostHub * hub_parent)
+{
+    // be sure that the new device connected is not already connected...
+    int idx = findDevice(hub, port, hub_parent);
+    if (idx != -1) {
+        if (deviceInited[idx])
+            return;
+    }
+    
+    message_t * usb_msg = mail_usb_event.alloc();
+    usb_msg->event_id = DEVICE_CONNECTED_EVENT;
+    usb_msg->hub = hub;
+    usb_msg->port = port;
+    usb_msg->lowSpeed = lowSpeed;
+    usb_msg->hub_parent = hub_parent;
+    mail_usb_event.put(usb_msg);
+}
+
+/*
+ * Called when a device has been disconnected
+ * Called in ISR!!!! (no printf)
+ */
+/* virtual */ void USBHost::deviceDisconnected(int hub, int port, USBHostHub * hub_parent, volatile uint32_t addr)
+{
+    // be sure that the device disconnected is connected...
+    int idx = findDevice(hub, port, hub_parent);
+    if (idx != -1) {
+        if (!deviceInUse[idx])
+            return;
+    } else {
+        return;
+    }
+    
+    message_t * usb_msg = mail_usb_event.alloc();
+    usb_msg->event_id = DEVICE_DISCONNECTED_EVENT;
+    usb_msg->hub = hub;
+    usb_msg->port = port;
+    usb_msg->hub_parent = hub_parent;
+    mail_usb_event.put(usb_msg);
+}
+
+void USBHost::freeDevice(USBDeviceConnected * dev)
+{
+    USBEndpoint * ep = NULL;
+    HCED * ed = NULL;
+    
+#if MAX_HUB_NB
+    if (dev->getClass() == HUB_CLASS) {
+        if (dev->hub == NULL) {
+            USB_ERR("HUB NULL!!!!!\r\n");
+        } else {
+            dev->hub->hubDisconnected();
+            for (uint8_t i = 0; i < MAX_HUB_NB; i++) {
+                if (dev->hub == &hubs[i]) {
+                    hub_in_use[i] = false;
+                    break;
+                }
+            }
+        }
+    }
+    
+    // notify hub parent that this device has been disconnected
+    if (dev->getHubParent())
+        dev->getHubParent()->deviceDisconnected(dev);
+    
+#endif
+    
+    int idx = findDevice(dev);
+    if (idx != -1) {
+        deviceInUse[idx] = false;
+        deviceReset[idx] = false;
+
+        for (uint8_t j = 0; j < MAX_INTF; j++) {
+            deviceAttachedDriver[idx][j] = false;
+            if (dev->getInterface(j) != NULL) {
+                USB_DBG("FREE INTF %d on dev: %p, %p, nb_endpot: %d, %s", j, (void *)dev->getInterface(j), dev, dev->getInterface(j)->nb_endpoint, dev->getName(j));
+                for (int i = 0; i < dev->getInterface(j)->nb_endpoint; i++) {
+                    if ((ep = dev->getEndpoint(j, i)) != NULL) {
+                        ed = (HCED *)ep->getHCED();
+                        ed->control |= (1 << 14); //sKip bit
+                        unqueueEndpoint(ep);
+
+                        freeTD((volatile uint8_t*)ep->getTDList()[0]);
+                        freeTD((volatile uint8_t*)ep->getTDList()[1]);
+
+                        freeED((uint8_t *)ep->getHCED());
+                    }
+                    printList(BULK_ENDPOINT);
+                    printList(INTERRUPT_ENDPOINT);
+                }
+                USB_INFO("Device disconnected [%p - %s - hub: %d - port: %d]", dev, dev->getName(j), dev->getHub(), dev->getPort());
+            }
+        }
+        dev->disconnect();
+    }
+}
+
+
+void USBHost::unqueueEndpoint(USBEndpoint * ep)
+{
+    USBEndpoint * prec = NULL;
+    USBEndpoint * current = NULL;
+
+    for (int i = 0; i < 2; i++) {
+        current = (i == 0) ? (USBEndpoint*)headBulkEndpoint : (USBEndpoint*)headInterruptEndpoint;
+        prec = current;
+        while (current != NULL) {
+            if (current == ep) {
+                if (current->nextEndpoint() != NULL) {
+                    prec->queueEndpoint(current->nextEndpoint());
+                    if (current == headBulkEndpoint) {
+                        updateBulkHeadED((uint32_t)current->nextEndpoint()->getHCED());
+                        headBulkEndpoint = current->nextEndpoint();
+                    } else if (current == headInterruptEndpoint) {
+                        updateInterruptHeadED((uint32_t)current->nextEndpoint()->getHCED());
+                        headInterruptEndpoint = current->nextEndpoint();
+                    }
+                }
+                // here we are dequeuing the queue of ed
+                // we need to update the tail pointer
+                else {
+                    prec->queueEndpoint(NULL);
+                    if (current == headBulkEndpoint) {
+                        updateBulkHeadED(0);
+                        headBulkEndpoint = current->nextEndpoint();
+                    } else if (current == headInterruptEndpoint) {
+                        updateInterruptHeadED(0);
+                        headInterruptEndpoint = current->nextEndpoint();
+                    }
+                    
+                    // modify tail
+                    switch (current->getType()) {
+                        case BULK_ENDPOINT:
+                            tailBulkEndpoint = prec;
+                            break;
+                        case INTERRUPT_ENDPOINT:
+                            tailInterruptEndpoint = prec;
+                            break;
+                    }
+                }
+                current->setState(USB_TYPE_FREE);
+                return;
+            }
+            prec = current;
+            current = current->nextEndpoint();
+        }
+    }
+}
+
+
+USBDeviceConnected * USBHost::getDevice(uint8_t index)
+{
+    if ((index >= MAX_DEVICE_CONNECTED) || (!deviceInUse[index])) {
+        return NULL;
+    }
+    return (USBDeviceConnected*)&devices[index];
+}
+
+// create an USBEndpoint descriptor. the USBEndpoint is not linked
+USBEndpoint * USBHost::newEndpoint(ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint32_t size, uint8_t addr)
+{
+    int i = 0;
+    HCED * ed = (HCED *)getED();
+    HCTD* td_list[2] = { (HCTD*)getTD(), (HCTD*)getTD() };
+
+    memset((void *)td_list[0], 0x00, sizeof(HCTD));
+    memset((void *)td_list[1], 0x00, sizeof(HCTD));
+
+    // search a free USBEndpoint
+    for (i = 0; i < MAX_ENDPOINT; i++) {
+        if (endpoints[i].getState() == USB_TYPE_FREE) {
+            endpoints[i].init(ed, type, dir, size, addr, td_list);
+            USB_DBG("USBEndpoint created (%p): type: %d, dir: %d, size: %d, addr: %d, state: %s", &endpoints[i], type, dir, size, addr, endpoints[i].getStateString());
+            return &endpoints[i];
+        }
+    }
+    USB_ERR("could not allocate more endpoints!!!!");
+    return NULL;
+}
+
+
+USB_TYPE USBHost::resetDevice(USBDeviceConnected * dev)
+{
+    int index = findDevice(dev);
+    if (index != -1) {
+        USB_DBG("Resetting hub %d, port %d\n", dev->getHub(), dev->getPort());
+        Thread::wait(100);
+        if (dev->getHub() == 0) {
+            resetRootHub();
+        }
+#if MAX_HUB_NB
+        else {
+            dev->getHubParent()->portReset(dev->getPort());
+        }
+#endif
+        Thread::wait(100);
+        deviceReset[index] = true;
+        return USB_TYPE_OK;
+    }
+    
+    return USB_TYPE_ERROR;
+}
+
+// link the USBEndpoint to the linked list and attach an USBEndpoint to a device
+bool USBHost::addEndpoint(USBDeviceConnected * dev, uint8_t intf_nb, USBEndpoint * ep)
+{
+
+    if (ep == NULL) {
+        return false;
+    }
+
+    HCED * prevEd;
+
+    // set device address in the USBEndpoint descriptor
+    if (dev == NULL) {
+        ep->setDeviceAddress(0);
+    } else {
+        ep->setDeviceAddress(dev->getAddress());
+    }
+
+    if ((dev != NULL) && dev->getSpeed()) {
+        ep->setSpeed(dev->getSpeed());
+    }
+    
+    ep->setIntfNb(intf_nb);
+
+    // queue the new USBEndpoint on the ED list
+    switch (ep->getType()) {
+
+        case CONTROL_ENDPOINT:
+            prevEd = ( HCED*) controlHeadED();
+            if (!prevEd) {
+                updateControlHeadED((uint32_t) ep->getHCED());
+                USB_DBG_TRANSFER("First control USBEndpoint: %08X", (uint32_t) ep->getHCED());
+                headControlEndpoint = ep;
+                tailControlEndpoint = ep;
+                return true;
+            }
+            tailControlEndpoint->queueEndpoint(ep);
+            tailControlEndpoint = ep;
+            return true;
+
+        case BULK_ENDPOINT:
+            prevEd = ( HCED*) bulkHeadED();
+            if (!prevEd) {
+                updateBulkHeadED((uint32_t) ep->getHCED());
+                USB_DBG_TRANSFER("First bulk USBEndpoint: %08X\r\n", (uint32_t) ep->getHCED());
+                headBulkEndpoint = ep;
+                tailBulkEndpoint = ep;
+                break;
+            }
+            USB_DBG_TRANSFER("Queue BULK Ed %p after %p\r\n",ep->getHCED(), prevEd);
+            tailBulkEndpoint->queueEndpoint(ep);
+            tailBulkEndpoint = ep;
+            break;
+
+        case INTERRUPT_ENDPOINT:
+            prevEd = ( HCED*) interruptHeadED();
+            if (!prevEd) {
+                updateInterruptHeadED((uint32_t) ep->getHCED());
+                USB_DBG_TRANSFER("First interrupt USBEndpoint: %08X\r\n", (uint32_t) ep->getHCED());
+                headInterruptEndpoint = ep;
+                tailInterruptEndpoint = ep;
+                break;
+            }
+            USB_DBG_TRANSFER("Queue INTERRUPT Ed %p after %p\r\n",ep->getHCED(), prevEd);
+            tailInterruptEndpoint->queueEndpoint(ep);
+            tailInterruptEndpoint = ep;
+            break;
+        default:
+            return false;
+    }
+    
+    ep->dev = dev;
+    dev->addEndpoint(intf_nb, ep);
+
+    return true;
+}
+
+
+int USBHost::findDevice(USBDeviceConnected * dev)
+{
+    for (int i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+        if (dev == &devices[i]) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+int USBHost::findDevice(uint8_t hub, uint8_t port, USBHostHub * hub_parent)
+{
+    for (int i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+        if (devices[i].getHub() == hub && devices[i].getPort() == port) {
+            if (hub_parent != NULL) {
+                if (hub_parent == devices[i].getHubParent())
+                    return i;
+            } else {
+                return i;
+            }
+        }
+    }
+    return -1;
+}
+
+void USBHost::printList(ENDPOINT_TYPE type)
+{
+#if DEBUG_EP_STATE
+    volatile HCED * hced;
+    switch(type) {
+        case CONTROL_ENDPOINT:
+            hced = (HCED *)controlHeadED();
+            break;
+        case BULK_ENDPOINT:
+            hced = (HCED *)bulkHeadED();
+            break;
+        case INTERRUPT_ENDPOINT:
+            hced = (HCED *)interruptHeadED();
+            break;
+    }
+    volatile HCTD * hctd = NULL;
+    const char * type_str = (type == BULK_ENDPOINT) ? "BULK" :
+                            ((type == INTERRUPT_ENDPOINT) ? "INTERRUPT" :
+                            ((type == CONTROL_ENDPOINT) ? "CONTROL" : "ISOCHRONOUS"));
+    printf("State of %s:\r\n", type_str);
+    while (hced != NULL) {
+        uint8_t dir = ((hced->control & (3 << 11)) >> 11);
+        printf("hced: %p [ADDR: %d, DIR: %s, EP_NB: 0x%X]\r\n", hced,
+                                                   hced->control & 0x7f,
+                                                   (dir == 1) ? "OUT" : ((dir == 0) ? "FROM_TD":"IN"),
+                                                    (hced->control & (0xf << 7)) >> 7);
+        hctd = (HCTD *)((uint32_t)(hced->headTD) & ~(0xf));
+        while (hctd != hced->tailTD) {
+            printf("\thctd: %p [DIR: %s]\r\n", hctd, ((hctd->control & (3 << 19)) >> 19) == 1 ? "OUT" : "IN");
+            hctd = hctd->nextTD;
+        }
+        printf("\thctd: %p\r\n", hctd);
+        hced = hced->nextED;
+    }
+    printf("\r\n\r\n");
+#endif
+}
+
+
+// add a transfer on the TD linked list
+USB_TYPE USBHost::addTransfer(USBEndpoint * ed, uint8_t * buf, uint32_t len)
+{
+    td_mutex.lock();
+
+    // allocate a TD which will be freed in TDcompletion
+    volatile HCTD * td = ed->getNextTD();
+    if (td == NULL) {
+        return USB_TYPE_ERROR;
+    }
+
+    uint32_t token = (ed->isSetup() ? TD_SETUP : ( (ed->getDir() == IN) ? TD_IN : TD_OUT ));
+
+    uint32_t td_toggle;
+
+    if (ed->getType() == CONTROL_ENDPOINT) {
+        if (ed->isSetup()) {
+            td_toggle = TD_TOGGLE_0;
+        } else {
+            td_toggle = TD_TOGGLE_1;
+        }
+    } else {
+        td_toggle = 0;
+    }
+
+    td->control      = (TD_ROUNDING | token | TD_DELAY_INT(0) | td_toggle | TD_CC);
+    td->currBufPtr   = buf;
+    td->bufEnd       = (buf + (len - 1));
+
+    ENDPOINT_TYPE type = ed->getType();
+
+    disableList(type);
+    ed->queueTransfer();
+    printList(type);
+    enableList(type);
+    
+    td_mutex.unlock();
+
+    return USB_TYPE_PROCESSING;
+}
+
+
+
+USB_TYPE USBHost::getDeviceDescriptor(USBDeviceConnected * dev, uint8_t * buf, uint16_t max_len_buf, uint16_t * len_dev_descr)
+{
+    USB_TYPE t = controlRead(  dev,
+                         USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE,
+                         GET_DESCRIPTOR,
+                         (DEVICE_DESCRIPTOR << 8) | (0),
+                         0, buf, MIN(DEVICE_DESCRIPTOR_LENGTH, max_len_buf));
+    if (len_dev_descr)
+        *len_dev_descr = MIN(DEVICE_DESCRIPTOR_LENGTH, max_len_buf);
+    
+    return t;
+}
+
+USB_TYPE USBHost::getConfigurationDescriptor(USBDeviceConnected * dev, uint8_t * buf, uint16_t max_len_buf, uint16_t * len_conf_descr)
+{
+    USB_TYPE res;
+    uint16_t total_conf_descr_length = 0;
+
+    // fourth step: get the beginning of the configuration descriptor to have the total length of the conf descr
+    res = controlRead(  dev,
+                        USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE,
+                        GET_DESCRIPTOR,
+                        (CONFIGURATION_DESCRIPTOR << 8) | (0),
+                        0, buf, CONFIGURATION_DESCRIPTOR_LENGTH);
+
+    if (res != USB_TYPE_OK) {
+        USB_ERR("GET CONF 1 DESCR FAILED");
+        return res;
+    }
+    total_conf_descr_length = buf[2] | (buf[3] << 8);
+    total_conf_descr_length = MIN(max_len_buf, total_conf_descr_length);
+    
+    if (len_conf_descr)
+        *len_conf_descr = total_conf_descr_length;
+    
+    USB_DBG("TOTAL_LENGTH: %d \t NUM_INTERF: %d", total_conf_descr_length, buf[4]);
+
+    return controlRead(  dev,
+                         USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE,
+                         GET_DESCRIPTOR,
+                         (CONFIGURATION_DESCRIPTOR << 8) | (0),
+                         0, buf, total_conf_descr_length);
+}
+
+
+USB_TYPE USBHost::setAddress(USBDeviceConnected * dev, uint8_t address) {
+    return controlWrite(    dev,
+                            USB_HOST_TO_DEVICE | USB_RECIPIENT_DEVICE,
+                            SET_ADDRESS,
+                            address,
+                            0, NULL, 0);
+    
+}
+
+USB_TYPE USBHost::setConfiguration(USBDeviceConnected * dev, uint8_t conf)
+{
+    return controlWrite( dev,
+                         USB_HOST_TO_DEVICE | USB_RECIPIENT_DEVICE,
+                         SET_CONFIGURATION,
+                         conf,
+                         0, NULL, 0);
+}
+
+uint8_t USBHost::numberDriverAttached(USBDeviceConnected * dev) {
+    int index = findDevice(dev);
+    uint8_t cnt = 0;
+    if (index == -1)
+        return 0;
+    for (uint8_t i = 0; i < MAX_INTF; i++) {
+        if (deviceAttachedDriver[index][i])
+            cnt++;
+    }
+    return cnt;
+}
+
+// enumerate a device with the control USBEndpoint
+USB_TYPE USBHost::enumerate(USBDeviceConnected * dev, IUSBEnumerator* pEnumerator)
+{
+    uint16_t total_conf_descr_length = 0;
+    USB_TYPE res;
+    
+    usb_mutex.lock();
+    
+    // don't enumerate a device which all interfaces are registered to a specific driver
+    int index = findDevice(dev);
+    
+    if (index == -1) {
+        usb_mutex.unlock();
+        return USB_TYPE_ERROR;
+    }
+    
+    uint8_t nb_intf_attached = numberDriverAttached(dev);
+    USB_DBG("dev: %p nb_intf: %d", dev, dev->getNbIntf());
+    USB_DBG("dev: %p nb_intf_attached: %d", dev, nb_intf_attached);
+    if ((nb_intf_attached != 0) && (dev->getNbIntf() == nb_intf_attached)) {
+        USB_DBG("Don't enumerate dev: %p because all intf are registered with a driver", dev);
+        usb_mutex.unlock();
+        return USB_TYPE_OK;
+    }
+    
+    USB_DBG("Enumerate dev: %p", dev);
+    
+    // third step: get the whole device descriptor to see vid, pid
+    res = getDeviceDescriptor(dev, data, DEVICE_DESCRIPTOR_LENGTH);
+
+    if (res != USB_TYPE_OK) {
+        USB_DBG("GET DEV DESCR FAILED");
+        usb_mutex.unlock();
+        return res;
+    }
+    
+    dev->setClass(data[4]);
+    dev->setSubClass(data[5]);
+    dev->setProtocol(data[6]);
+    dev->setVid(data[8] | (data[9] << 8));
+    dev->setPid(data[10] | (data[11] << 8));
+    USB_DBG("CLASS: %02X \t VID: %04X \t PID: %04X", data[4], data[8] | (data[9] << 8), data[10] | (data[11] << 8));
+
+    pEnumerator->setVidPid( data[8] | (data[9] << 8), data[10] | (data[11] << 8) );
+
+    res = getConfigurationDescriptor(dev, data, 300, &total_conf_descr_length);
+    if (res != USB_TYPE_OK) {
+        usb_mutex.unlock();
+        return res;
+    }
+
+#if DEBUG
+    USB_DBG("CONFIGURATION DESCRIPTOR:\r\n");
+    for (int i = 0; i < total_conf_descr_length; i++)
+        printf("%02X ", data[i]);
+    printf("\r\n\r\n");
+#endif
+
+    // Parse the configuration descriptor
+    parseConfDescr(dev, data, total_conf_descr_length, pEnumerator);
+
+    // only set configuration if not enumerated before
+    if (!dev->isEnumerated()) {
+        
+        USB_DBG("Set configuration 1 on dev: %p", dev);
+        // sixth step: set configuration (only 1 supported)
+        res = setConfiguration(dev, 1);
+
+        if (res != USB_TYPE_OK) {
+            USB_DBG("SET CONF FAILED");
+            usb_mutex.unlock();
+            return res;
+        }
+    }
+    
+    dev->setEnumerated();
+
+    // Now the device is enumerated!
+    USB_DBG("dev %p is enumerated\r\n", dev);
+    usb_mutex.unlock();
+
+    // Some devices may require this delay
+    wait_ms(100);
+
+    return USB_TYPE_OK;
+}
+// this method fills the USBDeviceConnected object: class,.... . It also add endpoints found in the descriptor.
+void USBHost::parseConfDescr(USBDeviceConnected * dev, uint8_t * conf_descr, uint32_t len, IUSBEnumerator* pEnumerator)
+{
+    uint32_t index = 0;
+    uint32_t len_desc = 0;
+    uint8_t id = 0;
+    int nb_endpoints_used = 0;
+    USBEndpoint * ep = NULL;
+    uint8_t intf_nb = 0;
+    bool parsing_intf = false;
+    uint8_t current_intf = 0;
+
+    while (index < len) {
+        len_desc = conf_descr[index];
+        id = conf_descr[index+1];
+        switch (id) {
+            case CONFIGURATION_DESCRIPTOR:
+                USB_DBG("dev: %p has %d intf", dev, conf_descr[4]);
+                dev->setNbIntf(conf_descr[4]);
+                break;
+            case INTERFACE_DESCRIPTOR:
+                if(pEnumerator->parseInterface(conf_descr[index + 2], conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7])) {
+                    if (intf_nb++ <= MAX_INTF) {
+                        current_intf = conf_descr[index + 2];
+                        dev->addInterface(current_intf, conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7]);
+                        nb_endpoints_used = 0;
+                        USB_DBG("ADD INTF %d on device %p: class: %d, subclass: %d, proto: %d", current_intf, dev, conf_descr[index + 5],conf_descr[index + 6],conf_descr[index + 7]);
+                    } else {
+                        USB_DBG("Drop intf...");
+                    }
+                    parsing_intf = true;
+                } else {
+                    parsing_intf = false;
+                }
+                break;
+            case ENDPOINT_DESCRIPTOR:
+                if (parsing_intf && (intf_nb <= MAX_INTF) ) {
+                    if (nb_endpoints_used < MAX_ENDPOINT_PER_INTERFACE) {
+                        if( pEnumerator->useEndpoint(current_intf, (ENDPOINT_TYPE)(conf_descr[index + 3] & 0x03), (ENDPOINT_DIRECTION)((conf_descr[index + 2] >> 7) + 1)) ) {
+                            // if the USBEndpoint is isochronous -> skip it (TODO: fix this)
+                            if ((conf_descr[index + 3] & 0x03) != ISOCHRONOUS_ENDPOINT) {
+                                ep = newEndpoint((ENDPOINT_TYPE)(conf_descr[index+3] & 0x03),
+                                                 (ENDPOINT_DIRECTION)((conf_descr[index + 2] >> 7) + 1),
+                                                 conf_descr[index + 4] | (conf_descr[index + 5] << 8),
+                                                 conf_descr[index + 2] & 0x0f);
+                                USB_DBG("ADD USBEndpoint %p, on interf %d on device %p", ep, current_intf, dev);
+                                if (ep != NULL && dev != NULL) {
+                                    addEndpoint(dev, current_intf, ep);
+                                } else {
+                                    USB_DBG("EP NULL");
+                                }
+                                nb_endpoints_used++;
+                            } else {
+                                USB_DBG("ISO USBEndpoint NOT SUPPORTED");
+                            }
+                        }
+                    }
+                }
+                break;
+            case HID_DESCRIPTOR:
+                lenReportDescr = conf_descr[index + 7] | (conf_descr[index + 8] << 8);
+                break;
+            default:
+                break;
+        }
+        index += len_desc;
+    }
+}
+
+
+USB_TYPE USBHost::bulkWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking)
+{
+    return generalTransfer(dev, ep, buf, len, blocking, BULK_ENDPOINT, true);
+}
+
+USB_TYPE USBHost::bulkRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking)
+{
+    return generalTransfer(dev, ep, buf, len, blocking, BULK_ENDPOINT, false);
+}
+
+USB_TYPE USBHost::interruptWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking)
+{
+    return generalTransfer(dev, ep, buf, len, blocking, INTERRUPT_ENDPOINT, true);
+}
+
+USB_TYPE USBHost::interruptRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking)
+{
+    return generalTransfer(dev, ep, buf, len, blocking, INTERRUPT_ENDPOINT, false);
+}
+
+USB_TYPE USBHost::generalTransfer(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking, ENDPOINT_TYPE type, bool write) {
+    
+#if DEBUG_TRANSFER
+    const char * type_str = (type == BULK_ENDPOINT) ? "BULK" : ((type == INTERRUPT_ENDPOINT) ? "INTERRUPT" : "ISOCHRONOUS");
+    USB_DBG_TRANSFER("----- %s %s [dev: %p - %s - hub: %d - port: %d - addr: %d - ep: %02X]------", type_str, (write) ? "WRITE" : "READ", dev, dev->getName(ep->getIntfNb()), dev->getHub(), dev->getPort(), dev->getAddress(), ep->getAddress());
+#endif
+    
+    usb_mutex.lock();
+    
+    USB_TYPE res;
+    ENDPOINT_DIRECTION dir = (write) ? OUT : IN;
+    
+    if (dev == NULL) {
+        USB_ERR("dev NULL");
+        usb_mutex.unlock();
+        return USB_TYPE_ERROR;
+    }
+
+    if (ep == NULL) {
+        USB_ERR("ep NULL");
+        usb_mutex.unlock();
+        return USB_TYPE_ERROR;
+    }
+
+    if (ep->getState() != USB_TYPE_IDLE) {
+        USB_WARN("[ep: %p - dev: %p - %s] NOT IDLE: %s", ep, ep->dev, ep->dev->getName(ep->getIntfNb()), ep->getStateString());
+        usb_mutex.unlock();
+        return ep->getState();
+    }
+
+    if ((ep->getDir() != dir) || (ep->getType() != type)) {
+        USB_ERR("[ep: %p - dev: %p] wrong dir or bad USBEndpoint type", ep, ep->dev);
+        usb_mutex.unlock();
+        return USB_TYPE_ERROR;
+    }
+
+    if (dev->getAddress() != ep->getDeviceAddress()) {
+        USB_ERR("[ep: %p - dev: %p] USBEndpoint addr and device addr don't match", ep, ep->dev);
+        usb_mutex.unlock();
+        return USB_TYPE_ERROR;
+    }
+    
+#if DEBUG_TRANSFER
+    if (write) {
+        USB_DBG_TRANSFER("%s WRITE buffer", type_str);
+        for (int i = 0; i < ep->getLengthTransferred(); i++)
+            printf("%02X ", buf[i]);
+        printf("\r\n\r\n");
+    }
+#endif
+    addTransfer(ep, buf, len);
+
+    if (blocking) {
+        
+        ep->ep_queue.get();
+        res = ep->getState();
+        
+        USB_DBG_TRANSFER("%s TRANSFER res: %s on ep: %p\r\n", type_str, ep->getStateString(), ep);
+        
+        if (res != USB_TYPE_IDLE) {
+            usb_mutex.unlock();
+            return res;
+        }
+        
+        usb_mutex.unlock();
+        return USB_TYPE_OK;
+    }
+    
+    usb_mutex.unlock();
+    return USB_TYPE_PROCESSING;
+
+}
+
+
+USB_TYPE USBHost::controlRead(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) {
+    return controlTransfer(dev, requestType, request, value, index, buf, len, false);
+}
+
+USB_TYPE USBHost::controlWrite(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) {
+    return controlTransfer(dev, requestType, request, value, index, buf, len, true);
+}
+
+USB_TYPE USBHost::controlTransfer(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len, bool write)
+{
+    usb_mutex.lock();
+    USB_DBG_TRANSFER("----- CONTROL %s [dev: %p - hub: %d - port: %d] ------", (write) ? "WRITE" : "READ", dev, dev->getHub(), dev->getPort());
+
+    int length_transfer = len;
+    USB_TYPE res;
+    uint32_t token;
+
+    control->setSpeed(dev->getSpeed());
+    control->setSize(dev->getSizeControlEndpoint());
+    if (dev->isActiveAddress()) {
+        control->setDeviceAddress(dev->getAddress());
+    } else {
+        control->setDeviceAddress(0);
+    }
+
+    USB_DBG_TRANSFER("Control transfer on device: %d\r\n", control->getDeviceAddress());
+    fillControlBuf(requestType, request, value, index, len);
+
+#if DEBUG_TRANSFER
+    USB_DBG_TRANSFER("SETUP PACKET: ");
+    for (int i = 0; i < 8; i++)
+        printf("%01X ", setupPacket[i]);
+    printf("\r\n");
+#endif
+
+    control->setNextToken(TD_SETUP);
+    addTransfer(control, (uint8_t*)setupPacket, 8);
+
+    control->ep_queue.get();
+    res = control->getState();
+
+    USB_DBG_TRANSFER("CONTROL setup stage %s", control->getStateString());
+
+    if (res != USB_TYPE_IDLE) {
+        usb_mutex.unlock();
+        return res;
+    }
+
+    if (length_transfer) {
+        token = (write) ? TD_OUT : TD_IN;
+        control->setNextToken(token);
+        addTransfer(control, (uint8_t *)buf, length_transfer);
+
+        control->ep_queue.get();
+        res = control->getState();
+
+#if DEBUG_TRANSFER
+        USB_DBG_TRANSFER("CONTROL %s stage %s", (write) ? "WRITE" : "READ", control->getStateString());
+        if (write) {
+            USB_DBG_TRANSFER("CONTROL WRITE buffer");
+            for (int i = 0; i < control->getLengthTransferred(); i++)
+                printf("%02X ", buf[i]);
+            printf("\r\n\r\n");
+        } else {
+            USB_DBG_TRANSFER("CONTROL READ SUCCESS [%d bytes transferred]", control->getLengthTransferred());
+            for (int i = 0; i < control->getLengthTransferred(); i++)
+                printf("%02X ", buf[i]);
+            printf("\r\n\r\n");
+        }
+#endif
+
+        if (res != USB_TYPE_IDLE) {
+            usb_mutex.unlock();
+            return res;
+        }
+    }
+
+    token = (write) ? TD_IN : TD_OUT;
+    control->setNextToken(token);
+    addTransfer(control, NULL, 0);
+
+    control->ep_queue.get();
+    res = control->getState();
+
+    USB_DBG_TRANSFER("CONTROL ack stage %s", control->getStateString());
+    usb_mutex.unlock();
+
+    if (res != USB_TYPE_IDLE)
+        return res;
+
+    return USB_TYPE_OK;
+}
+
+
+void USBHost::fillControlBuf(uint8_t requestType, uint8_t request, uint16_t value, uint16_t index, int len)
+{
+#ifdef __BIG_ENDIAN
+#error "Must implement BE to LE conv here"
+#endif
+    setupPacket[0] = requestType;
+    setupPacket[1] = request;
+    //We are in LE so it's fine
+    *((uint16_t*)&setupPacket[2]) = value;
+    *((uint16_t*)&setupPacket[4]) = index;
+    *((uint16_t*)&setupPacket[6]) = (uint32_t) len;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost/USBHost.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,383 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USBHOST_H
+#define USBHOST_H
+
+#include "USBHALHost.h"
+#include "USBDeviceConnected.h"
+#include "IUSBEnumerator.h"
+#include "USBHostConf.h"
+#include "rtos.h"
+#include "dbg.h"
+#include "USBHostHub.h"
+
+/**
+* USBHost class
+*   This class is a singleton. All drivers have a reference on the static USBHost instance
+*/
+class USBHost : public USBHALHost {
+public:
+    /**
+    * Static method to create or retrieve the single USBHost instance
+    */
+    static USBHost * getHostInst();
+    
+    /**
+    * Control read: setup stage, data stage and status stage
+    *
+    * @param dev the control read will be done for this device
+    * @param requestType request type
+    * @param request request
+    * @param value value
+    * @param index index
+    * @param buf pointer on a buffer where will be store the data received
+    * @param len length of the transfer
+    *
+    * @returns status of the control read
+    */
+    USB_TYPE controlRead(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len);
+
+    /**
+    * Control write: setup stage, data stage and status stage
+    *
+    * @param dev the control write will be done for this device
+    * @param requestType request type
+    * @param request request
+    * @param value value
+    * @param index index
+    * @param buf pointer on a buffer which will be written
+    * @param len length of the transfer
+    *
+    * @returns status of the control write
+    */
+    USB_TYPE controlWrite(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len);
+
+    /**
+    * Bulk read
+    *
+    * @param dev the bulk transfer will be done for this device
+    * @param ep USBEndpoint which will be used to read a packet
+    * @param buf pointer on a buffer where will be store the data received
+    * @param len length of the transfer
+    * @param blocking if true, the read is blocking (wait for completion)
+    *
+    * @returns status of the bulk read
+    */
+    USB_TYPE bulkRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true);
+
+    /**
+    * Bulk write
+    *
+    * @param dev the bulk transfer will be done for this device
+    * @param ep USBEndpoint which will be used to write a packet
+    * @param buf pointer on a buffer which will be written
+    * @param len length of the transfer
+    * @param blocking if true, the write is blocking (wait for completion)
+    *
+    * @returns status of the bulk write
+    */
+    USB_TYPE bulkWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true);
+
+    /**
+    * Interrupt read
+    *
+    * @param dev the bulk transfer will be done for this device
+    * @param ep USBEndpoint which will be used to write a packet
+    * @param buf pointer on a buffer which will be written
+    * @param len length of the transfer
+    * @param blocking if true, the read is blocking (wait for completion)
+    *
+    * @returns status of the interrupt read
+    */
+    USB_TYPE interruptRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true);
+
+    /**
+    * Interrupt write
+    *
+    * @param dev the bulk transfer will be done for this device
+    * @param ep USBEndpoint which will be used to write a packet
+    * @param buf pointer on a buffer which will be written
+    * @param len length of the transfer
+    * @param blocking if true, the write is blocking (wait for completion)
+    *
+    * @returns status of the interrupt write
+    */
+    USB_TYPE interruptWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true);
+
+    /**
+    * Enumerate a device.
+    *
+    * @param dev device which will be enumerated
+    *
+    * @returns status of the enumeration
+    */
+    USB_TYPE enumerate(USBDeviceConnected * dev, IUSBEnumerator* pEnumerator);
+
+    /**
+    * reset a specific device
+    *
+    * @param dev device which will be resetted
+    */
+    USB_TYPE resetDevice(USBDeviceConnected * dev);
+
+    /**
+    * Get a device
+    *
+    * @param index index of the device which will be returned
+    *
+    * @returns pointer on the "index" device
+    */
+    USBDeviceConnected * getDevice(uint8_t index);
+
+    /*
+    * If there is a HID device connected, the host stores the length of the report descriptor.
+    * This avoid to the driver to re-ask the configuration descriptor to request the report descriptor
+    *
+    * @returns length of the report descriptor
+    */
+    inline uint16_t getLengthReportDescr() {
+        return lenReportDescr;
+    };
+
+    /**
+     *  register a driver into the host associated with a callback function called when the device is disconnected
+     *
+     *  @param dev device
+     *  @param intf interface number
+     *  @param tptr pointer to the object to call the member function on
+     *  @param mptr pointer to the member function to be called
+     */
+    template<typename T>
+    inline void registerDriver(USBDeviceConnected * dev, uint8_t intf, T* tptr, void (T::*mptr)(void)) {
+        int index = findDevice(dev);
+        if ((index != -1) && (mptr != NULL) && (tptr != NULL)) {
+            USB_DBG("register driver for dev: %p on intf: %d", dev, intf);
+            deviceAttachedDriver[index][intf] = true;
+            dev->onDisconnect(intf, tptr, mptr);
+        }
+    }
+
+    /**
+     * register a driver into the host associated with a callback function called when the device is disconnected
+     *
+     * @param dev device
+     * @param intf interface number
+     * @param fn callback called when the specified device has been disconnected
+     */
+    inline void registerDriver(USBDeviceConnected * dev, uint8_t intf, void (*fn)(void)) {
+        int index = findDevice(dev);
+        if ((index != -1) && (fn != NULL)) {
+            USB_DBG("register driver for dev: %p on intf: %d", dev, intf);
+            deviceAttachedDriver[index][intf] = true;
+            dev->onDisconnect(intf, fn);
+        }
+    }
+    
+    friend class USBHostHub;
+
+protected:
+
+    /**
+    * Virtual method called when a transfer has been completed
+    *
+    * @param addr list of the TDs which have been completed
+    */
+    virtual void transferCompleted(volatile uint32_t addr);
+
+    /**
+    * Virtual method called when a device has been connected
+    *
+    * @param hub hub number of the device
+    * @param port port number of the device
+    * @param lowSpeed 1 if low speed, 0 otherwise
+    * @param hub_parent reference on the parent hub
+    */
+    virtual void deviceConnected(int hub, int port, bool lowSpeed, USBHostHub * hub_parent = NULL);
+
+    /**
+    * Virtuel method called when a device has been disconnected
+    *
+    * @param hub hub number of the device
+    * @param port port number of the device
+    * @param addr list of the TDs which have been completed to dequeue freed TDs
+    */
+    virtual void deviceDisconnected(int hub, int port, USBHostHub * hub_parent, volatile uint32_t addr);
+
+
+private:
+    // singleton class -> constructor is private
+    USBHost();
+    static USBHost * instHost;
+    uint16_t  lenReportDescr;
+
+    // endpoints
+    void unqueueEndpoint(USBEndpoint * ep) ;
+    USBEndpoint  endpoints[MAX_ENDPOINT];
+    USBEndpoint* volatile  control;
+
+    USBEndpoint* volatile  headControlEndpoint;
+    USBEndpoint* volatile  headBulkEndpoint;
+    USBEndpoint* volatile  headInterruptEndpoint;
+
+    USBEndpoint* volatile  tailControlEndpoint;
+    USBEndpoint* volatile  tailBulkEndpoint;
+    USBEndpoint* volatile  tailInterruptEndpoint;
+
+    bool controlEndpointAllocated;
+
+    // devices connected
+    USBDeviceConnected devices[MAX_DEVICE_CONNECTED];
+    bool  deviceInUse[MAX_DEVICE_CONNECTED];
+    bool  deviceAttachedDriver[MAX_DEVICE_CONNECTED][MAX_INTF];
+    bool  deviceReset[MAX_DEVICE_CONNECTED];
+    bool  deviceInited[MAX_DEVICE_CONNECTED];
+    
+#if MAX_HUB_NB
+    USBHostHub hubs[MAX_HUB_NB];
+    bool hub_in_use[MAX_HUB_NB];
+#endif
+
+    // to store a setup packet
+    uint8_t  setupPacket[8];
+    
+    typedef struct {
+        uint8_t event_id;
+        void * td_addr;
+        uint8_t hub;
+        uint8_t port;
+        uint8_t lowSpeed;
+        uint8_t td_state;
+        void * hub_parent;
+    } message_t;
+    
+    Thread usbThread;
+    void usb_process();
+    static void usb_process_static(void const * arg);
+    Mail<message_t, 10> mail_usb_event;
+    Mutex usb_mutex;
+    Mutex td_mutex;
+    
+    // buffer for conf descriptor
+    uint8_t data[300];
+    
+    /**
+    * Add a transfer on the TD linked list associated to an ED
+    *
+    * @param ed the transfer is associated to this ed
+    * @param buf pointer on a buffer where will be read/write data to send or receive
+    * @param len transfer length
+    *
+    * @return status of the transfer
+    */
+    USB_TYPE addTransfer(USBEndpoint * ed, uint8_t * buf, uint32_t len) ;
+    
+    /**
+    * Link the USBEndpoint to the linked list and attach an USBEndpoint this USBEndpoint to a device
+    *
+    * @param dev pointer on a USBDeviceConnected object
+    * @param ep pointer on the USBEndpoint which will be added
+    *
+    * return true if successful
+    */
+    bool addEndpoint(USBDeviceConnected * dev, uint8_t intf_nb, USBEndpoint * ep) ;
+
+    /**
+    * Create an USBEndpoint descriptor. Warning: the USBEndpoint is not linked.
+    *
+    * @param type USBEndpoint type (CONTROL_ENDPOINT, BULK_ENDPOINT, INTERRUPT_ENDPOINT)
+    * @param dir USBEndpoint direction (no meaning for CONTROL_ENDPOINT)
+    * @param size USBEndpoint max packet size
+    * @param addr USBEndpoint address
+    *
+    * @returns pointer on the USBEndpoint created
+    */
+    USBEndpoint * newEndpoint(ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint32_t size, uint8_t addr) ;
+    
+    /**
+    * Request the device descriptor
+    *
+    * @param dev request the device descriptor on this device
+    * @param buf buffer to store the device descriptor
+    * @param max_len_buf maximum size of buf
+    * @param len_dev_descr pointer to store the length of the packet transferred
+    */
+    USB_TYPE getDeviceDescriptor(USBDeviceConnected * dev, uint8_t * buf, uint16_t max_len_buf, uint16_t * len_dev_descr = NULL);
+
+    /**
+    * Request the configuration descriptor
+    *
+    * @param dev request the configuration descriptor on this device
+    * @param buf buffer to store the configuration descriptor
+    * @param max_len_buf maximum size of buf
+    * @param len_conf_descr pointer to store the length of the packet transferred
+    */
+    USB_TYPE getConfigurationDescriptor(USBDeviceConnected * dev, uint8_t * buf, uint16_t max_len_buf, uint16_t * len_conf_descr = NULL);
+    
+    /**
+    * Set the address of a specific device
+    *
+    * @param dev device to set the address
+    * @param address address
+    */
+    USB_TYPE setAddress(USBDeviceConnected * dev, uint8_t address);
+
+    /**
+    * Set the configuration of a device
+    *
+    * @param dev device on which the specified configuration will be activated
+    * @param conf configuration number to activate (usually 1)
+    */
+    USB_TYPE setConfiguration(USBDeviceConnected * dev, uint8_t conf);
+    
+    /**
+    * Free a specific device
+    *
+    * @param dev device to be freed
+    */
+    void freeDevice(USBDeviceConnected * dev);
+
+    USB_TYPE controlTransfer(   USBDeviceConnected * dev,
+                                uint8_t requestType,
+                                uint8_t request,
+                                uint32_t value,
+                                uint32_t index,
+                                uint8_t * buf,
+                                uint32_t len,
+                                bool write);
+
+    USB_TYPE generalTransfer(   USBDeviceConnected * dev,
+                                USBEndpoint * ep,
+                                uint8_t * buf,
+                                uint32_t len,
+                                bool blocking,
+                                ENDPOINT_TYPE type,
+                                bool write) ;
+                                
+    void fillControlBuf(uint8_t requestType, uint8_t request, uint16_t value, uint16_t index, int len) ;
+    void parseConfDescr(USBDeviceConnected * dev, uint8_t * conf_descr, uint32_t len, IUSBEnumerator* pEnumerator) ;
+    int findDevice(USBDeviceConnected * dev) ;
+    int findDevice(uint8_t hub, uint8_t port, USBHostHub * hub_parent = NULL) ;
+    uint8_t numberDriverAttached(USBDeviceConnected * dev);
+
+    /////////////////////////
+    /// FOR DEBUG
+    /////////////////////////
+    void printList(ENDPOINT_TYPE type);
+
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost/USBHostConf.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,81 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USBHOST_CONF_H
+#define USBHOST_CONF_H
+
+/*
+* Maximum number of devices that can be connected
+* to the usb host
+*/
+#define MAX_DEVICE_CONNECTED        5
+
+/*
+* Maximum of Hub connected to the usb host
+*/
+#define MAX_HUB_NB                  2
+
+/*
+* Maximum number of ports on a USB hub
+*/
+#define MAX_HUB_PORT                4
+
+/*
+* Enable USBHostMSD
+*/
+#define USBHOST_MSD                 1
+
+/*
+* Enable USBHostKeyboard
+*/
+#define USBHOST_KEYBOARD            1
+
+/*
+* Enable USBHostMouse
+*/
+#define USBHOST_MOUSE               1
+
+/*
+* Enable USBHostSerial
+*/
+#define USBHOST_SERIAL              1
+
+/*
+* Maximum number of interfaces of a usb device
+*/
+#define MAX_INTF                    3
+
+/*
+* Maximum number of endpoints on each interface
+*/
+#define MAX_ENDPOINT_PER_INTERFACE  3
+
+/*
+* Maximum number of endpoint descriptors that can be allocated
+*/
+#define MAX_ENDPOINT                (MAX_DEVICE_CONNECTED * MAX_INTF * MAX_ENDPOINT_PER_INTERFACE)
+
+/*
+* Maximum number of transfer descriptors that can be allocated
+*/
+#define MAX_TD                      (MAX_ENDPOINT*2)
+
+/*
+* usb_thread stack size
+*/
+#define USB_THREAD_STACK            (256*4 + MAX_HUB_NB*256*4)
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost/USBHostTypes.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,225 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USB_INC_H
+#define USB_INC_H
+
+#include "mbed.h"
+
+enum USB_TYPE {
+    USB_TYPE_OK = 0,
+
+    // completion code
+    USB_TYPE_CRC_ERROR = 1,
+    USB_TYPE_BIT_STUFFING_ERROR = 2,
+    USB_TYPE_DATA_TOGGLE_MISMATCH_ERROR = 3,
+    USB_TYPE_STALL_ERROR = 4,
+    USB_TYPE_DEVICE_NOT_RESPONDING_ERROR = 5,
+    USB_TYPE_PID_CHECK_FAILURE_ERROR = 6,
+    USB_TYPE_UNEXPECTED_PID_ERROR = 7,
+    USB_TYPE_DATA_OVERRUN_ERROR = 8,
+    USB_TYPE_DATA_UNDERRUN_ERROR = 9,
+    USB_TYPE_RESERVED = 9,
+    USB_TYPE_RESERVED_ = 10,
+    USB_TYPE_BUFFER_OVERRUN_ERROR = 12,
+    USB_TYPE_BUFFER_UNDERRUN_ERROR = 13,
+
+    // general usb state
+    USB_TYPE_DISCONNECTED = 14,
+    USB_TYPE_FREE = 15,
+    USB_TYPE_IDLE = 16,
+    USB_TYPE_PROCESSING = 17,
+
+    USB_TYPE_ERROR = 18,
+};
+
+
+enum ENDPOINT_DIRECTION {
+    OUT = 1,
+    IN
+};
+
+enum ENDPOINT_TYPE {
+    CONTROL_ENDPOINT = 0,
+    ISOCHRONOUS_ENDPOINT,
+    BULK_ENDPOINT,
+    INTERRUPT_ENDPOINT
+};
+
+#define AUDIO_CLASS     0x01
+#define CDC_CLASS       0x02
+#define HID_CLASS       0x03
+#define MSD_CLASS       0x08
+#define HUB_CLASS       0x09
+#define SERIAL_CLASS    0x0A
+
+// ------------------ HcControl Register ---------------------  
+#define  OR_CONTROL_PLE                 0x00000004
+#define  OR_CONTROL_CLE                 0x00000010
+#define  OR_CONTROL_BLE                 0x00000020
+#define  OR_CONTROL_HCFS                0x000000C0
+#define  OR_CONTROL_HC_OPER             0x00000080
+// ----------------- HcCommandStatus Register ----------------- 
+#define  OR_CMD_STATUS_HCR              0x00000001
+#define  OR_CMD_STATUS_CLF              0x00000002
+#define  OR_CMD_STATUS_BLF              0x00000004
+// --------------- HcInterruptStatus Register ----------------- 
+#define  OR_INTR_STATUS_WDH             0x00000002
+#define  OR_INTR_STATUS_RHSC            0x00000040
+#define  OR_INTR_STATUS_UE              0x00000010
+// --------------- HcInterruptEnable Register ----------------- 
+#define  OR_INTR_ENABLE_WDH             0x00000002
+#define  OR_INTR_ENABLE_RHSC            0x00000040
+#define  OR_INTR_ENABLE_MIE             0x80000000
+// ---------------- HcRhDescriptorA Register ------------------ 
+#define  OR_RH_STATUS_LPSC              0x00010000
+#define  OR_RH_STATUS_DRWE              0x00008000
+// -------------- HcRhPortStatus[1:NDP] Register -------------- 
+#define  OR_RH_PORT_CCS                 0x00000001
+#define  OR_RH_PORT_PRS                 0x00000010
+#define  OR_RH_PORT_CSC                 0x00010000
+#define  OR_RH_PORT_PRSC                0x00100000
+#define  OR_RH_PORT_LSDA                0x00000200
+
+#define  FI                     0x2EDF           // 12000 bits per frame (-1)
+#define  DEFAULT_FMINTERVAL     ((((6 * (FI - 210)) / 7) << 16) | FI)
+
+#define  ED_SKIP            (uint32_t) (0x00001000)        // Skip this ep in queue
+
+#define  TD_ROUNDING        (uint32_t) (0x00040000)        // Buffer Rounding                             
+#define  TD_SETUP           (uint32_t)(0)                  // Direction of Setup Packet                   
+#define  TD_IN              (uint32_t)(0x00100000)         // Direction In                                
+#define  TD_OUT             (uint32_t)(0x00080000)         // Direction Out                               
+#define  TD_DELAY_INT(x)    (uint32_t)((x) << 21)          // Delay Interrupt                             
+#define  TD_TOGGLE_0        (uint32_t)(0x02000000)         // Toggle 0                                    
+#define  TD_TOGGLE_1        (uint32_t)(0x03000000)         // Toggle 1                                    
+#define  TD_CC              (uint32_t)(0xF0000000)         // Completion Code                             
+
+#define  DEVICE_DESCRIPTOR                     (1)
+#define  CONFIGURATION_DESCRIPTOR              (2)
+#define  INTERFACE_DESCRIPTOR                  (4)
+#define  ENDPOINT_DESCRIPTOR                   (5)
+#define  HID_DESCRIPTOR                        (33)
+
+//  ----------- Control RequestType Fields  ----------- 
+#define  USB_DEVICE_TO_HOST         0x80
+#define  USB_HOST_TO_DEVICE         0x00
+#define  USB_REQUEST_TYPE_CLASS     0x20
+#define  USB_REQUEST_TYPE_STANDARD  0x00
+#define  USB_RECIPIENT_DEVICE       0x00
+#define  USB_RECIPIENT_INTERFACE    0x01
+#define  USB_RECIPIENT_ENDPOINT     0x02
+
+// -------------- USB Standard Requests  -------------- 
+#define  SET_ADDRESS                0x05
+#define  GET_DESCRIPTOR             0x06
+#define  SET_CONFIGURATION          0x09
+#define  SET_INTERFACE              0x0b
+#define  CLEAR_FEATURE              0x01
+
+// -------------- USB Descriptor Length  -------------- 
+#define DEVICE_DESCRIPTOR_LENGTH            0x12
+#define CONFIGURATION_DESCRIPTOR_LENGTH     0x09
+
+// ------------ HostController Transfer Descriptor ------------
+typedef __packed struct HCTD {
+    __IO  uint32_t   control;        // Transfer descriptor control
+    __IO  uint8_t *  currBufPtr;    // Physical address of current buffer pointer
+    __IO  HCTD *     nextTD;         // Physical pointer to next Transfer Descriptor
+    __IO  uint8_t *  bufEnd;        // Physical address of end of buffer
+    void * ep;                      // ep address where a td is linked in
+    uint32_t dummy[3];              // padding
+} HCTD;
+
+// ----------- HostController EndPoint Descriptor ------------- 
+typedef __packed struct hcEd {
+    __IO  uint32_t  control;        // Endpoint descriptor control
+    __IO  HCTD *  tailTD;           // Physical address of tail in Transfer descriptor list
+    __IO  HCTD *  headTD;           // Physcial address of head in Transfer descriptor list
+    __IO  hcEd *  nextED;         // Physical address of next Endpoint descriptor
+} HCED;
+
+
+// ----------- Host Controller Communication Area ------------  
+typedef __packed struct hcca {
+    __IO  uint32_t  IntTable[32];   // Interrupt Table
+    __IO  uint32_t  FrameNumber;    // Frame Number
+    __IO  uint32_t  DoneHead;       // Done Head
+    volatile  uint8_t   Reserved[116];  // Reserved for future use                                  
+    volatile  uint8_t   Unknown[4];     // Unused                                                   
+} HCCA;
+
+typedef __packed struct {
+    uint8_t bLength;            
+    uint8_t bDescriptorType;    
+    uint16_t bcdUSB;            
+    uint8_t bDeviceClass;       
+    uint8_t bDeviceSubClass;    
+    uint8_t bDeviceProtocol;    
+    uint8_t bMaxPacketSize;     
+    uint16_t idVendor;          
+    uint16_t idProduct;         
+    uint16_t bcdDevice;         
+    uint8_t iManufacturer;      
+    uint8_t iProduct;           
+    uint8_t iSerialNumber;      
+    uint8_t bNumConfigurations; 
+} DeviceDescriptor;
+
+typedef __packed struct {
+    uint8_t bLength;               
+    uint8_t bDescriptorType;       
+    uint16_t wTotalLength;         
+    uint8_t bNumInterfaces;        
+    uint8_t bConfigurationValue;   
+    uint8_t iConfiguration;        
+    uint8_t bmAttributes;          
+    uint8_t bMaxPower;             
+} ConfigurationDescriptor; 
+
+typedef struct {
+    uint8_t bLength;                 
+    uint8_t bDescriptorType;   
+    uint8_t bInterfaceNumber;  
+    uint8_t bAlternateSetting; 
+    uint8_t bNumEndpoints;     
+    uint8_t bInterfaceClass;   
+    uint8_t bInterfaceSubClass;
+    uint8_t bInterfaceProtocol;
+    uint8_t iInterface;        
+} InterfaceDescriptor; 
+
+typedef struct {
+    uint8_t bLength;          
+    uint8_t bDescriptorType;  
+    uint8_t bEndpointAddress; 
+    uint8_t bmAttributes;     
+    uint16_t wMaxPacketSize;  
+    uint8_t bInterval;        
+} EndpointDescriptor;
+
+typedef struct {
+    uint8_t bDescLength;      
+    uint8_t bDescriptorType;  
+    uint8_t bNbrPorts;        
+    uint16_t wHubCharacteristics;
+    uint8_t bPwrOn2PwrGood;   
+    uint8_t bHubContrCurrent; 
+    uint8_t DeviceRemovable;  
+    uint8_t PortPweCtrlMak;   
+} HubDescriptor;              
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHost/dbg.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,51 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+#ifndef USB_DEBUG_H
+#define USB_DEBUG_H
+
+//Debug is disabled by default
+#define DEBUG 0
+#define DEBUG_TRANSFER 0
+#define DEBUG_EP_STATE 0
+#define DEBUG_EVENT 0
+
+#if (DEBUG)
+#define USB_DBG(x, ...) std::printf("[USB_DBG: %s:%d]"x"\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#else
+#define USB_DBG(x, ...)
+#endif
+
+#if (DEBUG_TRANSFER)
+#define USB_DBG_TRANSFER(x, ...) std::printf("[USB_TRANSFER: %s:%d]"x"\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#else
+#define USB_DBG_TRANSFER(x, ...)
+#endif
+
+#if (DEBUG_EVENT)
+#define USB_DBG_EVENT(x, ...) std::printf("[USB_EVENT: %s:%d]"x"\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#else
+#define USB_DBG_EVENT(x, ...)
+#endif
+
+#define USB_INFO(x, ...) std::printf("[USB_INFO: %s:%d]"x"\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#define USB_WARN(x, ...) std::printf("[USB_WARNING: %s:%d]"x"\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+#define USB_ERR(x, ...) std::printf("[USB_ERR: %s:%d]"x"\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
+
+#endif
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostHID/USBHostKeyboard.cpp	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,184 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "USBHostKeyboard.h"
+
+#if USBHOST_KEYBOARD
+
+static uint8_t keymap[4][0x39] = { 
+    { 0, 0, 0, 0, 'a', 'b' /*0x05*/,
+      'c', 'd', 'e', 'f', 'g' /*0x0a*/,
+      'h', 'i', 'j', 'k', 'l'/*0x0f*/,
+      'm', 'n', 'o', 'p', 'q'/*0x14*/,
+      'r', 's', 't', 'u', 'v'/*0x19*/,
+      'w', 'x', 'y', 'z', '1'/*0x1E*/,
+      '2', '3', '4', '5', '6'/*0x23*/,
+      '7', '8', '9', '0', 0x0A /*enter*/, /*0x28*/
+      0x1B /*escape*/, 0x08 /*backspace*/, 0x09/*tab*/, 0x20/*space*/, '-', /*0x2d*/
+      '=', '[', ']', '\\', '#', /*0x32*/
+      ';', '\'', 0, ',', '.', /*0x37*/
+      '/'},
+
+    /* CTRL MODIFIER */
+    { 0, 0, 0, 0, 0, 0 /*0x05*/,
+      0, 0, 0, 0, 0 /*0x0a*/,
+      0, 0, 0, 0, 0/*0x0f*/,
+      0, 0, 0, 0, 0/*0x14*/,
+      0, 0, 0, 0, 0/*0x19*/,
+      0, 0, 0, 0, 0/*0x1E*/,
+      0, 0, 0, 0, 0/*0x23*/,
+      0, 0, 0, 0, 0 /*enter*/, /*0x28*/
+      0, 0, 0, 0, 0, /*0x2d*/
+      0, 0, 0, 0, 0, /*0x32*/
+      0, 0, 0, 0, 0, /*0x37*/
+      0},
+
+    /* SHIFT MODIFIER */
+    { 0, 0, 0, 0, 'A', 'B' /*0x05*/,
+      'C', 'D', 'E', 'F', 'G' /*0x0a*/,
+      'H', 'I', 'J', 'K', 'L'/*0x0f*/,
+      'M', 'N', 'O', 'P', 'Q'/*0x14*/,
+      'R', 'S', 'T', 'U', 'V'/*0x19*/,
+      'W', 'X', 'Y', 'Z', '!'/*0x1E*/,
+      '@', '#', '$', '%', '^'/*0x23*/,
+      '&', '*', '(', ')', 0, /*0x28*/
+      0, 0, 0, 0, 0, /*0x2d*/
+      '+', '{', '}', '|', '~', /*0x32*/
+      ':', '"', 0, '<', '>', /*0x37*/
+      '?'},
+
+    /* ALT MODIFIER */
+    { 0, 0, 0, 0, 0, 0 /*0x05*/,
+      0, 0, 0, 0, 0 /*0x0a*/,
+      0, 0, 0, 0, 0/*0x0f*/,
+      0, 0, 0, 0, 0/*0x14*/,
+      0, 0, 0, 0, 0/*0x19*/,
+      0, 0, 0, 0, 0/*0x1E*/,
+      0, 0, 0, 0, 0/*0x23*/,
+      0, 0, 0, 0, 0 /*enter*/, /*0x28*/
+      0, 0, 0, 0, 0, /*0x2d*/
+      0, 0, 0, 0, 0, /*0x32*/
+      0, 0, 0, 0, 0, /*0x37*/
+      0}
+
+};
+
+
+USBHostKeyboard::USBHostKeyboard() {
+    host = USBHost::getHostInst();
+    init();
+}
+
+
+void USBHostKeyboard::init() {
+    dev = NULL;
+    int_in = NULL;
+    report_id = 0;
+    onKey = NULL;
+    onKeyCode = NULL;
+    dev_connected = false;
+    keyboard_intf = -1;
+    keyboard_device_found = false;
+}
+
+bool USBHostKeyboard::connected() {
+    return dev_connected;
+}
+
+
+bool USBHostKeyboard::connect() {
+    
+    if (dev_connected) {
+        return true;
+    }
+    
+    for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+        if ((dev = host->getDevice(i)) != NULL) {
+
+            if (host->enumerate(dev, this))
+                break;
+            
+            if (keyboard_device_found) {
+                int_in = dev->getEndpoint(keyboard_intf, INTERRUPT_ENDPOINT, IN);
+                
+                if (!int_in)
+                    break;
+                
+                USB_INFO("New Keyboard device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, keyboard_intf);
+                dev->setName("Keyboard", keyboard_intf);
+                host->registerDriver(dev, keyboard_intf, this, &USBHostKeyboard::init);
+                
+                int_in->attach(this, &USBHostKeyboard::rxHandler);
+                host->interruptRead(dev, int_in, report, int_in->getSize(), false);
+                
+                dev_connected = true;
+                return true;
+            }
+        }
+    }
+    init();
+    return false;
+}
+
+void USBHostKeyboard::rxHandler() {
+    int len = int_in->getLengthTransferred();
+    int index = (len == 9) ? 1 : 0;
+    int len_listen = int_in->getSize();
+    uint8_t key = 0;
+    if (len == 8 || len == 9) {
+        uint8_t modifier = (report[index] == 4) ? 3 : report[index];
+        len_listen = len;
+        key = keymap[modifier][report[index + 2]];
+        if (key && onKey) {
+            (*onKey)(key);
+        }
+        if ((report[index + 2] || modifier) && onKeyCode) {
+            (*onKeyCode)(report[index + 2], modifier);
+        }
+    }
+    if (dev && int_in)
+        host->interruptRead(dev, int_in, report, len_listen, false);
+}
+
+/*virtual*/ void USBHostKeyboard::setVidPid(uint16_t vid, uint16_t pid)
+{
+    // we don't check VID/PID for keyboard driver
+}
+
+/*virtual*/ bool USBHostKeyboard::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
+{
+    if ((keyboard_intf == -1) &&
+        (intf_class == HID_CLASS) &&
+        (intf_subclass == 0x01) &&
+        (intf_protocol == 0x01)) {
+        keyboard_intf = intf_nb;
+        return true;
+    }
+    return false;
+}
+
+/*virtual*/ bool USBHostKeyboard::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+    if (intf_nb == keyboard_intf) {
+        if (type == INTERRUPT_ENDPOINT && dir == IN) {
+            keyboard_device_found = true;
+            return true;
+        }
+    }
+    return false;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostHID/USBHostKeyboard.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,102 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USBHOSTKEYBOARD_H
+#define USBHOSTKEYBOARD_H
+
+#include "USBHostConf.h"
+
+#if USBHOST_KEYBOARD
+
+#include "USBHost.h"
+
+/** 
+ * A class to communicate a USB keyboard
+ */
+class USBHostKeyboard : public IUSBEnumerator {
+public:
+    
+    /**
+    * Constructor
+    */
+    USBHostKeyboard();
+
+    /**
+     * Try to connect a keyboard device
+     *
+     * @return true if connection was successful
+     */
+    bool connect();
+
+    /**
+    * Check if a keyboard is connected
+    *
+    * @returns true if a keyboard is connected
+    */
+    bool connected();
+
+    /**
+     * Attach a callback called when a keyboard event is received
+     *
+     * @param ptr function pointer
+     */
+    inline void attach(void (*ptr)(uint8_t key)) {
+        if (ptr != NULL) {
+            onKey = ptr;
+        }
+    }
+
+    /**
+     * Attach a callback called when a keyboard event is received
+     *
+     * @param ptr function pointer
+     */
+    inline void attach(void (*ptr)(uint8_t keyCode, uint8_t modifier)) {
+        if (ptr != NULL) {
+            onKeyCode = ptr;
+        }
+    }
+
+protected:
+    //From IUSBEnumerator
+    virtual void setVidPid(uint16_t vid, uint16_t pid);
+    virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
+    virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
+
+private:
+    USBHost * host;
+    USBDeviceConnected * dev;
+    USBEndpoint * int_in;
+    uint8_t report[9];
+    int keyboard_intf;
+    bool keyboard_device_found;
+    
+    bool dev_connected;
+
+    void rxHandler();
+
+    void (*onKey)(uint8_t key);
+    void (*onKeyCode)(uint8_t key, uint8_t modifier);
+
+    int report_id;
+    
+    void init();
+
+};
+
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostHID/USBHostMouse.cpp	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,145 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "USBHostMouse.h"
+
+#if USBHOST_MOUSE
+
+USBHostMouse::USBHostMouse() {
+    host = USBHost::getHostInst();
+    init();
+}
+
+void USBHostMouse::init() {
+    dev = NULL;
+    int_in = NULL;
+    onUpdate = NULL;
+    onButtonUpdate = NULL;
+    onXUpdate = NULL;
+    onYUpdate = NULL;
+    onZUpdate = NULL;
+    report_id = 0;
+    dev_connected = false;
+    mouse_device_found = false;
+    mouse_intf = -1;
+    
+    buttons = 0;
+    x = 0;
+    y = 0;
+    z = 0;
+}
+
+bool USBHostMouse::connected() {
+    return dev_connected;
+}
+
+bool USBHostMouse::connect() {
+
+    if (dev_connected) {
+        return true;
+    }
+    
+    for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+        if ((dev = host->getDevice(i)) != NULL) {
+
+            if(host->enumerate(dev, this))
+                break;
+            
+            if (mouse_device_found) {
+                
+                int_in = dev->getEndpoint(mouse_intf, INTERRUPT_ENDPOINT, IN);
+                if (!int_in)
+                    break;
+                
+                USB_INFO("New Mouse device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, mouse_intf);
+                dev->setName("Mouse", mouse_intf);
+                host->registerDriver(dev, mouse_intf, this, &USBHostMouse::init);
+                
+                int_in->attach(this, &USBHostMouse::rxHandler);
+                host->interruptRead(dev, int_in, report, int_in->getSize(), false);
+                
+                dev_connected = true;
+                return true;
+            }
+        }
+    }
+    init();
+    return false;
+}
+
+void USBHostMouse::rxHandler() {
+    int len_listen = int_in->getSize();
+    int len = int_in->getLengthTransferred();
+    
+    if (onUpdate) {
+        (*onUpdate)(report[0] & 0x07, report[1], report[2], report[3]);
+    }
+    
+    if (onButtonUpdate && (buttons != (report[0] & 0x07))) {
+        (*onButtonUpdate)(report[0] & 0x07);
+    }
+    
+    if (onXUpdate && (x != report[1])) {
+        (*onXUpdate)(report[1]);
+    }
+    
+    if (onYUpdate && (y != report[2])) {
+        (*onYUpdate)(report[2]);
+    }
+    
+    if (onZUpdate && (z != report[3])) {
+        (*onZUpdate)(report[3]);
+    }
+        
+    // update mouse state
+    buttons = report[0] & 0x07;
+    x = report[1];
+    y = report[2];
+    z = report[3];
+    
+    if (dev)
+        host->interruptRead(dev, int_in, report, len_listen, false);
+}
+
+/*virtual*/ void USBHostMouse::setVidPid(uint16_t vid, uint16_t pid)
+{
+    // we don't check VID/PID for mouse driver
+}
+
+/*virtual*/ bool USBHostMouse::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
+{
+    if ((mouse_intf == -1) &&
+        (intf_class == HID_CLASS) &&
+        (intf_subclass == 0x01) &&
+        (intf_protocol == 0x02)) {
+        mouse_intf = intf_nb;
+        return true;
+    }
+    return false;
+}
+
+/*virtual*/ bool USBHostMouse::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+    if (intf_nb == mouse_intf) {
+        if (type == INTERRUPT_ENDPOINT && dir == IN) {
+            mouse_device_found = true;
+            return true;
+        }
+    }
+    return false;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostHID/USBHostMouse.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,139 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USBHOSTMOUSE_H
+#define USBHOSTMOUSE_H
+
+#include "USBHostConf.h"
+
+#if USBHOST_MOUSE
+
+#include "USBHost.h"
+
+/** 
+ * A class to communicate a USB mouse
+ */
+class USBHostMouse : public IUSBEnumerator {
+public:
+
+    /**
+    * Constructor
+    */
+    USBHostMouse();
+
+    /**
+     * Try to connect a mouse device
+     *
+     * @return true if connection was successful
+     */
+    bool connect();
+
+    /**
+    * Check if a mouse is connected
+    *
+    * @returns true if a mouse is connected
+    */
+    bool connected();
+
+    /**
+     * Attach a callback called when a mouse event is received
+     *
+     * @param ptr function pointer
+     */
+    inline void attachEvent(void (*ptr)(uint8_t buttons, int8_t x, int8_t y, int8_t z)) {
+        if (ptr != NULL) {
+            onUpdate = ptr;
+        }
+    }
+    
+    /**
+     * Attach a callback called when the button state changes
+     *
+     * @param ptr function pointer
+     */
+    inline void attachButtonEvent(void (*ptr)(uint8_t buttons)) {
+        if (ptr != NULL) {
+            onButtonUpdate = ptr;
+        }
+    }
+    
+    /**
+     * Attach a callback called when the X axis value changes
+     *
+     * @param ptr function pointer
+     */
+    inline void attachXEvent(void (*ptr)(int8_t x)) {
+        if (ptr != NULL) {
+            onXUpdate = ptr;
+        }
+    }
+    
+    /**
+     * Attach a callback called when the Y axis value changes
+     *
+     * @param ptr function pointer
+     */
+    inline void attachYEvent(void (*ptr)(int8_t y)) {
+        if (ptr != NULL) {
+            onYUpdate = ptr;
+        }
+    }
+    
+    /**
+     * Attach a callback called when the Z axis value changes (scrolling)
+     *
+     * @param ptr function pointer
+     */
+    inline void attachZEvent(void (*ptr)(int8_t z)) {
+        if (ptr != NULL) {
+            onZUpdate = ptr;
+        }
+    }
+
+protected:
+    //From IUSBEnumerator
+    virtual void setVidPid(uint16_t vid, uint16_t pid);
+    virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
+    virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
+
+private:
+    USBHost * host;
+    USBDeviceConnected * dev;
+    USBEndpoint * int_in;
+    uint8_t report[4];
+    
+    bool dev_connected;
+    bool mouse_device_found;
+    int mouse_intf;
+
+    uint8_t buttons;
+    int8_t x;
+    int8_t y;
+    int8_t z;
+
+    void rxHandler();
+    void (*onUpdate)(uint8_t buttons, int8_t x, int8_t y, int8_t z);
+    void (*onButtonUpdate)(uint8_t buttons);
+    void (*onXUpdate)(int8_t x);
+    void (*onYUpdate)(int8_t y);
+    void (*onZUpdate)(int8_t z);
+    int report_id;
+    void init();
+};
+
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostHub/USBHostHub.cpp	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,271 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "USBHostHub.h"
+
+#if MAX_HUB_NB
+
+#include "USBHost.h"
+#include "dbg.h"
+
+#define GET_STATUS 0x00
+#define CLEAR_FEATURE 0x01
+#define GET_STATE 0x02
+#define SET_FEATURE 0x03
+#define GET_DESCRIPTOR 0x06
+
+#define PORT_CONNECTION_FEATURE     (0x00)
+#define PORT_ENABLE_FEATURE         (0x01)
+#define PORT_RESET_FEATURE          (0x04)
+#define PORT_POWER_FEATURE          (0x08)
+
+#define C_PORT_CONNECTION_FEATURE     (16)
+#define C_PORT_ENABLE_FEATURE         (17)
+#define C_PORT_RESET_FEATURE          (20)
+
+#define PORT_CONNECTION   (1 << 0)
+#define PORT_ENABLE       (1 << 1)
+#define PORT_SUSPEND      (1 << 2)
+#define PORT_OVER_CURRENT (1 << 3)
+#define PORT_RESET        (1 << 4)
+#define PORT_POWER        (1 << 8)
+#define PORT_LOW_SPEED    (1 << 9)
+
+#define C_PORT_CONNECTION   (1 << 16)
+#define C_PORT_ENABLE       (1 << 17)
+#define C_PORT_SUSPEND      (1 << 18)
+#define C_PORT_OVER_CURRENT (1 << 19)
+#define C_PORT_RESET        (1 << 20)
+
+USBHostHub::USBHostHub() {
+    host = NULL;
+    init();
+}
+
+void USBHostHub::init() {
+    dev_connected = false;
+    dev = NULL;
+    int_in = NULL;
+    dev_connected = false;
+    hub_intf = -1;
+    hub_device_found = false;
+    nb_port = 0;
+    hub_characteristics = 0;
+    
+    for (int i = 0; i < MAX_HUB_PORT; i++) {
+        device_children[i] = NULL;
+    }
+}
+
+void USBHostHub::setHost(USBHost * host_) {
+    host = host_;
+}
+
+bool USBHostHub::connected()
+{
+    return dev_connected;
+}
+
+bool USBHostHub::connect(USBDeviceConnected * dev)
+{   
+    if (dev_connected) {
+        return true;
+    }
+    
+    if(host->enumerate(dev, this)) {
+        init();
+        return false;
+    }
+    
+    if (hub_device_found) {
+        this->dev = dev;
+    
+        int_in = dev->getEndpoint(hub_intf, INTERRUPT_ENDPOINT, IN);
+        
+        if (!int_in) {
+            init();
+            return false;
+        }
+        
+        USB_INFO("New HUB: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, hub_intf);
+        dev->setName("Hub", hub_intf);
+        host->registerDriver(dev, hub_intf, this, &USBHostHub::disconnect);
+        
+        int_in->attach(this, &USBHostHub::rxHandler);
+        
+        // get HUB descriptor
+        host->controlRead(  dev, 
+                            USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS,
+                            GET_DESCRIPTOR,
+                            0x29 << 8, 0, buf, sizeof(HubDescriptor));
+        nb_port = buf[2];
+        hub_characteristics = buf[3];
+        
+        USB_DBG("Hub has %d port", nb_port);
+        
+        for (uint8_t j = 1; j <= nb_port; j++) {
+            setPortFeature(PORT_POWER_FEATURE, j);
+        }
+        wait_ms(buf[5]*2);
+        
+        host->interruptRead(dev, int_in, buf, 1, false);
+        dev_connected = true;
+        return true;
+    }
+    
+    return false;
+}
+
+void USBHostHub::disconnect() {
+    init();
+}
+
+/*virtual*/ void USBHostHub::setVidPid(uint16_t vid, uint16_t pid)
+{
+    // we don't check VID/PID for MSD driver
+}
+
+/*virtual*/ bool USBHostHub::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
+{
+    if ((hub_intf == -1) &&
+        (intf_class == HUB_CLASS) &&
+        (intf_subclass == 0) &&
+        (intf_protocol == 0)) {
+        hub_intf = intf_nb;
+        return true;
+    }
+    return false;
+}
+
+/*virtual*/ bool USBHostHub::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+    if (intf_nb == hub_intf) {
+        if ((type == INTERRUPT_ENDPOINT) && (dir == IN)) {
+            hub_device_found = true;
+            return true;
+        }
+    }
+    return false;
+}
+
+void USBHostHub::deviceConnected(USBDeviceConnected * dev) {
+    device_children[dev->getPort() - 1] = dev;
+}
+
+void USBHostHub::deviceDisconnected(USBDeviceConnected * dev) {
+    device_children[dev->getPort() - 1] = NULL;
+}
+
+void USBHostHub::hubDisconnected() {
+    for (uint8_t i = 0; i < MAX_HUB_PORT; i++) {
+        if (device_children[i] != NULL) {
+            host->freeDevice(device_children[i]);
+        }
+    }
+}
+
+void USBHostHub::rxHandler() {
+    uint32_t status;
+    if (int_in) {
+        if (int_in->getState() == USB_TYPE_IDLE) {
+            for (int port = 1; port <= nb_port; port++) {
+                status = getPortStatus(port);
+                USB_DBG("[hub handler hub: %d] status port %d [hub: %p]: 0x%X", dev->getHub(), port, dev, status);
+                
+                // if connection status has changed
+                if (status & C_PORT_CONNECTION) {
+                    if (status & PORT_CONNECTION) {
+                        USB_DBG("[hub handler hub: %d - port: %d] new device connected", dev->getHub(), port);
+                        host->deviceConnected(dev->getHub() + 1, port, status & PORT_LOW_SPEED, this);
+                    } else {
+                        USB_DBG("[hub handler hub: %d - port: %d] device disconnected", dev->getHub(), port);
+                        host->deviceDisconnected(dev->getHub() + 1, port, this, NULL);
+                    }
+                    
+                    clearPortFeature(C_PORT_CONNECTION_FEATURE, port);
+                }
+                
+                if (status & C_PORT_RESET) {
+                    clearPortFeature(C_PORT_RESET_FEATURE, port);
+                }
+                
+                if (status & C_PORT_ENABLE) {
+                    clearPortFeature(C_PORT_ENABLE_FEATURE, port);
+                }
+                
+                if ((status & PORT_OVER_CURRENT)) {
+                    USB_ERR("OVER CURRENT DETECTED\r\n");
+                    clearPortFeature(PORT_OVER_CURRENT, port);
+                    host->deviceDisconnected(dev->getHub() + 1, port, this, NULL);
+                }
+            }
+        }
+        host->interruptRead(dev, int_in, buf, 1, false);
+    }
+}
+
+void USBHostHub::portReset(uint8_t port) {
+    // reset port
+    uint32_t status;
+    USB_DBG("reset port %d on hub: %p [this: %p]", port, dev, this)
+    setPortFeature(PORT_RESET_FEATURE, port);
+    while(1) {
+        status = getPortStatus(port);
+        if (status & (PORT_ENABLE | PORT_RESET))
+            break;
+        if (status & PORT_OVER_CURRENT) {
+            USB_ERR("OVER CURRENT DETECTED\r\n");
+            clearPortFeature(PORT_OVER_CURRENT, port);
+            host->deviceDisconnected(dev->getHub() + 1, port, this, NULL);
+            break;
+        }
+        Thread::wait(10);
+    }
+}
+
+void USBHostHub::setPortFeature(uint32_t feature, uint8_t port) {
+    host->controlWrite( dev,
+                        USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE | USB_RECIPIENT_ENDPOINT,
+                        SET_FEATURE,
+                        feature,
+                        port,
+                        NULL,
+                        0);
+}
+
+void USBHostHub::clearPortFeature(uint32_t feature, uint8_t port) {
+    host->controlWrite( dev,
+                        USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE | USB_RECIPIENT_ENDPOINT,
+                        CLEAR_FEATURE,
+                        feature,
+                        port,
+                        NULL,
+                        0);
+}
+
+uint32_t USBHostHub::getPortStatus(uint8_t port) {
+    uint32_t st;
+    host->controlRead(  dev,
+                        USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE | USB_RECIPIENT_ENDPOINT,
+                        GET_STATUS,
+                        0,
+                        port,
+                        (uint8_t *)&st,
+                        4);
+    return st;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostHub/USBHostHub.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,125 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USBHOSTHUB_H
+#define USBHOSTHUB_H
+
+#include "USBHostConf.h"
+
+#if MAX_HUB_NB
+
+#include "USBHostTypes.h"
+#include "IUSBEnumerator.h"
+
+class USBHost;
+class USBDeviceConnected;
+class USBEndpoint;
+
+/** 
+ * A class to use a USB Hub
+ */
+class USBHostHub : public IUSBEnumerator {
+public:
+    /**
+    * Constructor
+    */
+    USBHostHub();
+
+    /**
+    * Check if a USB Hub is connected
+    *
+    * @return true if a serial device is connected
+    */
+    bool connected();
+
+    /**
+     * Try to connect device
+     *
+     * @param dev device to connect
+     * @return true if connection was successful
+     */
+    bool connect(USBDeviceConnected * dev);
+    
+    /**
+    * Automatically called by USBHost when a device
+    * has been enumerated by usb_thread
+    *
+    * @param dev device connected
+    */
+    void deviceConnected(USBDeviceConnected * dev);
+    
+    /**
+    * Automatically called by USBHost when a device
+    * has been disconnected from this hub
+    *
+    * @param dev device disconnected
+    */
+    void deviceDisconnected(USBDeviceConnected * dev);
+    
+    /**
+    * Rest a specific port
+    *
+    * @param port port number
+    */
+    void portReset(uint8_t port);
+    
+    /*
+    * Called by USBHost to set the instance of USBHost
+    *
+    * @param host host instance
+    */
+    void setHost(USBHost * host);
+    
+    /**
+    * Called by USBhost when a hub has been disconnected
+    */
+    void hubDisconnected();
+
+protected:
+    //From IUSBEnumerator
+    virtual void setVidPid(uint16_t vid, uint16_t pid);
+    virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
+    virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
+
+private:
+    USBHost * host;
+    USBDeviceConnected * dev;
+    bool dev_connected;
+    USBEndpoint * int_in;
+    uint8_t nb_port;
+    uint8_t hub_characteristics;
+
+    void rxHandler();
+
+    uint8_t buf[sizeof(HubDescriptor)];
+
+    int hub_intf;
+    bool hub_device_found;
+
+    void setPortFeature(uint32_t feature, uint8_t port);
+    void clearPortFeature(uint32_t feature, uint8_t port);
+    uint32_t getPortStatus(uint8_t port);
+
+    USBDeviceConnected * device_children[MAX_HUB_PORT];
+    
+    void init();
+    void disconnect();
+
+};
+
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostMSD/USBHostMSD.cpp	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,356 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "USBHostMSD.h"
+
+#if USBHOST_MSD
+
+#include "dbg.h"
+
+#define CBW_SIGNATURE   0x43425355
+#define CSW_SIGNATURE   0x53425355
+
+#define DEVICE_TO_HOST  0x80
+#define HOST_TO_DEVICE  0x00
+
+#define GET_MAX_LUN             (0xFE)
+#define BO_MASS_STORAGE_RESET   (0xFF)
+
+USBHostMSD::USBHostMSD(const char * rootdir) : FATFileSystem(rootdir)
+{
+    host = USBHost::getHostInst();
+    init();
+}
+
+void USBHostMSD::init() {
+    dev_connected = false;
+    dev = NULL;
+    bulk_in = NULL;
+    bulk_out = NULL;
+    dev_connected = false;
+    blockSize = 0;
+    blockCount = 0;
+    msd_intf = -1;
+    msd_device_found = false;
+    disk_init = false;
+    dev_connected = false;
+    nb_ep = 0;
+}
+
+
+bool USBHostMSD::connected()
+{
+    return dev_connected;
+}
+
+bool USBHostMSD::connect()
+{
+
+    if (dev_connected) {
+        return true;
+    }
+
+    for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+        if ((dev = host->getDevice(i)) != NULL) {
+            
+            USB_DBG("Trying to connect MSD device\r\n");
+            
+            if(host->enumerate(dev, this))
+                break;
+
+            if (msd_device_found) {
+                bulk_in = dev->getEndpoint(msd_intf, BULK_ENDPOINT, IN);
+                bulk_out = dev->getEndpoint(msd_intf, BULK_ENDPOINT, OUT);
+                
+                if (!bulk_in || !bulk_out)
+                    continue;
+                
+                USB_INFO("New MSD device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, msd_intf);
+                dev->setName("MSD", msd_intf);
+                host->registerDriver(dev, msd_intf, this, &USBHostMSD::init);
+
+                dev_connected = true;
+                return true;
+            }
+        } //if()
+    } //for()
+    init();
+    return false;
+}
+
+/*virtual*/ void USBHostMSD::setVidPid(uint16_t vid, uint16_t pid)
+{
+    // we don't check VID/PID for MSD driver
+}
+
+/*virtual*/ bool USBHostMSD::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
+{
+    if ((msd_intf == -1) &&
+        (intf_class == MSD_CLASS) &&
+        (intf_subclass == 0x06) &&
+        (intf_protocol == 0x50)) {
+        msd_intf = intf_nb;
+        return true;
+    }
+    return false;
+}
+
+/*virtual*/ bool USBHostMSD::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+    if (intf_nb == msd_intf) {
+        if (type == BULK_ENDPOINT) {
+            nb_ep++;
+            if (nb_ep == 2)
+                msd_device_found = true;
+            return true;
+        }
+    }
+    return false;
+}
+
+
+int USBHostMSD::testUnitReady() {
+    USB_DBG("Test unit ready");
+    return SCSITransfer(NULL, 6, DEVICE_TO_HOST, 0, 0);
+}
+
+
+int USBHostMSD::readCapacity() {
+    USB_DBG("Read capacity");
+    uint8_t cmd[10] = {0x25,0,0,0,0,0,0,0,0,0};
+    uint8_t result[8];
+    int status = SCSITransfer(cmd, 10, DEVICE_TO_HOST, result, 8);
+    if (status == 0) {
+        blockCount = (result[0] << 24) | (result[1] << 16) | (result[2] << 8) | result[3];
+        blockSize = (result[4] << 24) | (result[5] << 16) | (result[6] << 8) | result[7];
+        USB_INFO("MSD [dev: %p] - blockCount: %lld, blockSize: %d, Capacity: %lld\r\n", dev, blockCount, blockSize, blockCount*blockSize);
+    }
+    return status;
+}
+
+
+int USBHostMSD::SCSIRequestSense() {
+    USB_DBG("Request sense");
+    uint8_t cmd[6] = {0x03,0,0,0,18,0};
+    uint8_t result[18];
+    int status = SCSITransfer(cmd, 6, DEVICE_TO_HOST, result, 18);
+    return status;
+}
+
+
+int USBHostMSD::inquiry(uint8_t lun, uint8_t page_code) {
+    USB_DBG("Inquiry");
+    uint8_t evpd = (page_code == 0) ? 0 : 1;
+    uint8_t cmd[6] = {0x12, (lun << 5) | evpd, page_code, 0, 36, 0};
+    uint8_t result[36];
+    int status = SCSITransfer(cmd, 6, DEVICE_TO_HOST, result, 36);
+    if (status == 0) {
+        char vid_pid[17];
+        memcpy(vid_pid, &result[8], 8);
+        vid_pid[8] = 0;
+        USB_INFO("MSD [dev: %p] - Vendor ID: %s", dev, vid_pid);
+
+        memcpy(vid_pid, &result[16], 16);
+        vid_pid[16] = 0;
+        USB_INFO("MSD [dev: %p] - Product ID: %s", dev, vid_pid);
+
+        memcpy(vid_pid, &result[32], 4);
+        vid_pid[4] = 0;
+        USB_INFO("MSD [dev: %p] - Product rev: %s", dev, vid_pid);
+    }
+    return status;
+}
+
+int USBHostMSD::checkResult(uint8_t res, USBEndpoint * ep) {
+    // if ep stalled: send clear feature
+    if (res == USB_TYPE_STALL_ERROR) {
+        res = host->controlWrite(   dev,
+                                    USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD,
+                                    CLEAR_FEATURE,
+                                    0, ep->getAddress(), NULL, 0);
+        // set state to IDLE if clear feature successful
+        if (res == USB_TYPE_OK) {
+            ep->setState(USB_TYPE_IDLE);
+        }
+    }
+
+    if (res != USB_TYPE_OK)
+        return -1;
+
+    return 0;
+}
+
+
+int USBHostMSD::SCSITransfer(uint8_t * cmd, uint8_t cmd_len, int flags, uint8_t * data, uint32_t transfer_len) {
+
+    int res = 0;
+
+    cbw.Signature = CBW_SIGNATURE;
+    cbw.Tag = 0;
+    cbw.DataLength = transfer_len;
+    cbw.Flags = flags;
+    cbw.LUN = 0;
+    cbw.CBLength = cmd_len;
+    memset(cbw.CB,0,sizeof(cbw.CB));
+    if (cmd) {
+        memcpy(cbw.CB,cmd,cmd_len);
+    }
+
+    // send the cbw
+    USB_DBG("Send CBW");
+    res = host->bulkWrite(dev, bulk_out,(uint8_t *)&cbw, 31);
+    if (checkResult(res, bulk_out))
+        return -1;
+
+    // data stage if needed
+    if (data) {
+        USB_DBG("data stage");
+        if (flags == HOST_TO_DEVICE) {
+            
+            res = host->bulkWrite(dev, bulk_out, data, transfer_len);
+            if (checkResult(res, bulk_out))
+                return -1;
+
+        } else if (flags == DEVICE_TO_HOST) {
+
+            res = host->bulkRead(dev, bulk_in, data, transfer_len);
+            if (checkResult(res, bulk_in))
+                return -1;
+        }
+    }
+
+    // status stage
+    csw.Signature = 0;
+    USB_DBG("Read CSW");
+    res = host->bulkRead(dev, bulk_in,(uint8_t *)&csw, 13);
+    if (checkResult(res, bulk_in))
+        return -1;
+
+    if (csw.Signature != CSW_SIGNATURE) {
+        return -1;
+    }
+    
+    USB_DBG("recv csw: status: %d", csw.Status);
+
+    // ModeSense?
+    if ((csw.Status == 1) && (cmd[0] != 0x03)) {
+        USB_DBG("request mode sense");
+        return SCSIRequestSense();
+    }
+    
+    // perform reset recovery
+    if ((csw.Status == 2) && (cmd[0] != 0x03)) {
+        
+        // send Bulk-Only Mass Storage Reset request
+        res = host->controlWrite(   dev,
+                                    USB_RECIPIENT_INTERFACE | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS,
+                                    BO_MASS_STORAGE_RESET,
+                                    0, msd_intf, NULL, 0);
+        
+        // unstall both endpoints
+        res = host->controlWrite(   dev,
+                                    USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD,
+                                    CLEAR_FEATURE,
+                                    0, bulk_in->getAddress(), NULL, 0);
+        
+        res = host->controlWrite(   dev,
+                                    USB_RECIPIENT_ENDPOINT | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_STANDARD,
+                                    CLEAR_FEATURE,
+                                    0, bulk_out->getAddress(), NULL, 0);
+        
+    }
+
+    return csw.Status;
+}
+
+
+int USBHostMSD::dataTransfer(uint8_t * buf, uint32_t block, uint8_t nbBlock, int direction) {
+    uint8_t cmd[10];
+    memset(cmd,0,10);
+    cmd[0] = (direction == DEVICE_TO_HOST) ? 0x28 : 0x2A;
+
+    cmd[2] = (block >> 24) & 0xff;
+    cmd[3] = (block >> 16) & 0xff;
+    cmd[4] = (block >> 8) & 0xff;
+    cmd[5] =  block & 0xff;
+
+    cmd[7] = (nbBlock >> 8) & 0xff;
+    cmd[8] = nbBlock & 0xff;
+
+    return SCSITransfer(cmd, 10, direction, buf, blockSize*nbBlock);
+}
+
+int USBHostMSD::getMaxLun() {
+    uint8_t buf[1], res;
+    res = host->controlRead(    dev, USB_RECIPIENT_INTERFACE | USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS,
+                                0xfe, 0, msd_intf, buf, 1);
+    USB_DBG("max lun: %d", buf[0]);
+    return res;
+}
+
+int USBHostMSD::disk_initialize() {
+    USB_DBG("FILESYSTEM: init");
+    U16 i, timeout = 10;
+    
+    getMaxLun();
+    
+    for (i = 0; i < timeout; i++) {
+        Thread::wait(100);
+        if (!testUnitReady())
+            break;
+    }
+    
+    if (i == timeout) {
+        disk_init = false;
+        return -1;
+    }
+    
+    inquiry(0, 0);
+    disk_init = 1;
+    return readCapacity();
+}
+
+int USBHostMSD::disk_write(const uint8_t *buffer, uint64_t block_number) {
+    USB_DBG("FILESYSTEM: write block: %lld", block_number);
+    if (!disk_init) {
+        disk_initialize();
+    }
+    if (!disk_init)
+        return -1;
+    return dataTransfer((uint8_t *)buffer, block_number, 1, HOST_TO_DEVICE);
+}
+
+int USBHostMSD::disk_read(uint8_t * buffer, uint64_t block_number) {
+    USB_DBG("FILESYSTEM: read block %lld", block_number);
+    if (!disk_init) {
+        disk_initialize();
+    }
+    if (!disk_init)
+        return -1;
+    return dataTransfer((uint8_t *)buffer, block_number, 1, DEVICE_TO_HOST);
+}
+
+uint64_t USBHostMSD::disk_sectors() {
+    USB_DBG("FILESYSTEM: sectors");
+    if (!disk_init) {
+        disk_initialize();
+    }
+    if (!disk_init)
+        return 0;
+    return blockCount;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostMSD/USBHostMSD.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,119 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USBHOSTMSD_H
+#define USBHOSTMSD_H
+
+#include "USBHostConf.h"
+
+#if USBHOST_MSD
+
+#include "USBHost.h"
+#include "FATFileSystem.h"
+
+/** 
+ * A class to communicate a USB flash disk
+ */
+class USBHostMSD : public IUSBEnumerator, public FATFileSystem {
+public:
+    /**
+    * Constructor
+    *
+    * @param rootdir mount name
+    */
+    USBHostMSD(const char * rootdir);
+
+    /**
+    * Check if a MSD device is connected
+    *
+    * @return true if a MSD device is connected
+    */
+    bool connected();
+
+    /**
+     * Try to connect to a MSD device
+     *
+     * @return true if connection was successful
+     */
+    bool connect();
+
+protected:
+    //From IUSBEnumerator
+    virtual void setVidPid(uint16_t vid, uint16_t pid);
+    virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
+    virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
+
+    // From FATFileSystem
+    virtual int disk_initialize();
+    virtual int disk_status() {return 0;};
+    virtual int disk_read(uint8_t * buffer, uint64_t sector);
+    virtual int disk_write(const uint8_t * buffer, uint64_t sector);
+    virtual int disk_sync() {return 0;};
+    virtual uint64_t disk_sectors();
+
+private:
+    USBHost * host;
+    USBDeviceConnected * dev;
+    bool dev_connected;
+    USBEndpoint * bulk_in;
+    USBEndpoint * bulk_out;
+    uint8_t nb_ep;
+
+    // Bulk-only CBW
+    typedef __packed struct {
+        uint32_t Signature;
+        uint32_t Tag;
+        uint32_t DataLength;
+        uint8_t  Flags;
+        uint8_t  LUN;
+        uint8_t  CBLength;
+        uint8_t  CB[16];
+    } CBW;
+
+    // Bulk-only CSW
+    typedef __packed struct {
+        uint32_t Signature;
+        uint32_t Tag;
+        uint32_t DataResidue;
+        uint8_t  Status;
+    } CSW;
+
+    CBW cbw;
+    CSW csw;
+
+    int SCSITransfer(uint8_t * cmd, uint8_t cmd_len, int flags, uint8_t * data, uint32_t transfer_len);
+    int testUnitReady();
+    int readCapacity();
+    int inquiry(uint8_t lun, uint8_t page_code);
+    int SCSIRequestSense();
+    int dataTransfer(uint8_t * buf, uint32_t block, uint8_t nbBlock, int direction);
+    int checkResult(uint8_t res, USBEndpoint * ep);
+    int getMaxLun();
+
+    int blockSize;
+    uint64_t blockCount;
+
+    int msd_intf;
+    bool msd_device_found;
+    bool disk_init;
+    
+    void init();
+
+};
+
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostSerial/MtxCircBuffer.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,89 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MTXCIRCBUFFER_H
+#define MTXCIRCBUFFER_H
+
+#include "stdint.h"
+#include "rtos.h"
+
+//Mutex protected circular buffer
+template<typename T, int size>
+class MtxCircBuffer {
+public:
+    
+    MtxCircBuffer() {
+        write = 0;
+        read = 0;
+    }
+
+    bool isFull() {
+        mtx.lock();
+        bool r = (((write + 1) % size) == read);
+        mtx.unlock();
+        return r;
+    }
+
+    bool isEmpty() {
+        mtx.lock();
+        bool r = (read == write);
+        mtx.unlock();
+        return r;
+    }
+    
+    void flush() {
+        write = 0;
+        read = 0;
+    }
+
+    void queue(T k) {
+        mtx.lock();
+        while (((write + 1) % size) == read) {
+            mtx.unlock();
+            Thread::wait(10);
+            mtx.lock();
+        }
+        buf[write++] = k;
+        write %= size;
+        mtx.unlock();
+    }
+
+    uint16_t available() {
+        mtx.lock();
+        uint16_t a = (write >= read) ? (write - read) : (size - read + write);
+        mtx.unlock();
+        return a;
+    }
+
+    bool dequeue(T * c) {
+        mtx.lock();
+        bool empty = (read == write);
+        if (!empty) {
+            *c = buf[read++];
+            read %= size;
+        }
+        mtx.unlock();
+        return (!empty);
+    }
+
+private:
+    volatile uint16_t write;
+    volatile uint16_t read;
+    volatile T buf[size];
+    Mutex mtx;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostSerial/USBHostSerial.cpp	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,184 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "USBHostSerial.h"
+
+#if USBHOST_SERIAL
+
+#include "dbg.h"
+
+#define SET_LINE_CODING 0x20
+
+USBHostSerial::USBHostSerial(): circ_buf() {
+    host = USBHost::getHostInst();
+    size_bulk_in = 0;
+    size_bulk_out = 0;
+    init();
+}
+
+void USBHostSerial::init() {
+    dev = NULL;
+    bulk_in = NULL;
+    bulk_out = NULL;
+    dev_connected = false;
+    serial_intf = -1;
+    serial_device_found = false;
+    line_coding.baudrate = 9600;
+    line_coding.data_bits = 8;
+    line_coding.parity = None;
+    line_coding.stop_bits = 1;
+    circ_buf.flush();
+}
+
+bool USBHostSerial::connected()
+{
+    return dev_connected;
+}
+
+bool USBHostSerial::connect() {
+
+    if (dev_connected) {
+        return true;
+    }
+    for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+        if ((dev = host->getDevice(i)) != NULL) {
+            
+            USB_DBG("Trying to connect serial device\r\n");
+
+            if(host->enumerate(dev, this))
+                break;
+            
+            if (serial_device_found) {
+                bulk_in = dev->getEndpoint(serial_intf, BULK_ENDPOINT, IN);
+                bulk_out = dev->getEndpoint(serial_intf, BULK_ENDPOINT, OUT);
+                
+                if (!bulk_in || !bulk_out)
+                    break;
+                
+                USB_INFO("New Serial device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, serial_intf);
+                dev->setName("Serial", serial_intf);
+                host->registerDriver(dev, serial_intf, this, &USBHostSerial::init);
+                
+                baud(9600);
+                
+                size_bulk_in = bulk_in->getSize();
+                size_bulk_out = bulk_out->getSize();
+                
+                bulk_in->attach(this, &USBHostSerial::rxHandler);
+                bulk_out->attach(this, &USBHostSerial::txHandler);
+                
+                host->bulkRead(dev, bulk_in, buf, size_bulk_in, false);
+                dev_connected = true;
+                return true;
+            }
+        }
+    }
+    init();
+    return false;
+}
+
+void USBHostSerial::rxHandler() {
+    if (bulk_in) {
+        int len = bulk_in->getLengthTransferred();
+        if (bulk_in->getState() == USB_TYPE_IDLE) {
+            for (int i = 0; i < len; i++) {
+                circ_buf.queue(buf[i]);
+            }
+            rx.call();
+            host->bulkRead(dev, bulk_in, buf, size_bulk_in, false);
+        }
+    }
+}
+
+void USBHostSerial::txHandler() {
+    if (bulk_out) {
+        if (bulk_out->getState() == USB_TYPE_IDLE) {
+            tx.call();
+        }
+    }
+}
+
+int USBHostSerial::_putc(int c) {
+    if (bulk_out) {
+        if (host->bulkWrite(dev, bulk_out, (uint8_t *)&c, 1) == USB_TYPE_OK) {
+            return 1;
+        }
+    }
+    return -1;
+}
+
+void USBHostSerial::baud(int baudrate) {
+    line_coding.baudrate = baudrate;
+    format(line_coding.data_bits, (Parity)line_coding.parity, line_coding.stop_bits);
+}
+
+void USBHostSerial::format(int bits, Parity parity, int stop_bits) {
+    line_coding.data_bits = bits;
+    line_coding.parity = parity;
+    line_coding.stop_bits = (stop_bits == 1) ? 0 : 2;
+    
+    // set line coding
+    int res = host->controlWrite(   dev,
+                                    USB_RECIPIENT_INTERFACE | USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS,
+                                    SET_LINE_CODING,
+                                    0, serial_intf, (uint8_t *)&line_coding, 7);
+}
+
+int USBHostSerial::_getc() {
+    uint8_t c = 0;
+    if (bulk_in == NULL) {
+        init();
+        return -1;
+    }
+    while (circ_buf.isEmpty());
+    circ_buf.dequeue(&c);
+    return c;
+}
+
+
+uint8_t USBHostSerial::available() {
+    return circ_buf.available();
+}
+
+/*virtual*/ void USBHostSerial::setVidPid(uint16_t vid, uint16_t pid)
+{
+    // we don't check VID/PID for MSD driver
+}
+
+/*virtual*/ bool USBHostSerial::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
+{
+    if ((serial_intf == -1) &&
+        (intf_class == SERIAL_CLASS) &&
+        (intf_subclass == 0x00) &&
+        (intf_protocol == 0x00)) {
+        serial_intf = intf_nb;
+        return true;
+    }
+    return false;
+}
+
+/*virtual*/ bool USBHostSerial::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+    if (intf_nb == serial_intf) {
+        if (type == BULK_ENDPOINT) {
+            serial_device_found = true;
+            return true;
+        }
+    }
+    return false;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/USBHostSerial/USBHostSerial.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,166 @@
+/* mbed USBHost Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef USBHOSTSERIAL_H
+#define USBHOSTSERIAL_H
+
+#include "USBHostConf.h"
+
+#if USBHOST_SERIAL
+
+#include "USBHost.h"
+#include "Stream.h"
+#include "MtxCircBuffer.h"
+
+/** 
+ * A class to communicate a USB virtual serial port
+ */
+class USBHostSerial : public IUSBEnumerator, public Stream {
+public:
+    /**
+    * Constructor
+    */
+    USBHostSerial();
+
+    enum IrqType {
+        RxIrq,
+        TxIrq
+    };
+    
+    enum Parity {
+        None = 0,
+        Odd,
+        Even,
+        Mark,
+        Space
+    };
+
+    /**
+    * Check if a virtual serial port is connected
+    *
+    * @returns true if a serial device is connected
+    */
+    bool connected();
+    
+    /**
+     * Try to connect a serial device
+     *
+     * @return true if connection was successful
+     */
+    bool connect();
+    
+    /**
+    * Check the number of bytes available.
+    *
+    * @returns the number of bytes available
+    */
+    uint8_t available(); 
+
+    /**
+     *  Attach a member function to call when a packet is received.
+     *
+     *  @param tptr pointer to the object to call the member function on
+     *  @param mptr pointer to the member function to be called
+     *  @param irq irq type
+     */
+    template<typename T>
+    inline void attach(T* tptr, void (T::*mptr)(void), IrqType irq = RxIrq) {
+        if ((mptr != NULL) && (tptr != NULL)) {
+            if (irq == RxIrq) {
+                rx.attach(tptr, mptr);
+            } else {
+                tx.attach(tptr, mptr);
+            }
+        }
+    }
+
+    /**
+     * Attach a callback called when a packet is received
+     *
+     * @param ptr function pointer
+     */
+    inline void attach(void (*fn)(void), IrqType irq = RxIrq) {
+        if (fn != NULL) {
+            if (irq == RxIrq) {
+                rx.attach(fn);
+            } else {
+                tx.attach(fn);
+            }
+        }
+    }
+    
+    /** Set the baud rate of the serial port
+     *
+     *  @param baudrate The baudrate of the serial port (default = 9600).
+     */
+    void baud(int baudrate = 9600);
+    
+    /** Set the transmission format used by the Serial port
+     *
+     *  @param bits The number of bits in a word (default = 8)
+     *  @param parity The parity used (USBHostSerial::None, USBHostSerial::Odd, USBHostSerial::Even, USBHostSerial::Mark, USBHostSerial::Space; default = USBHostSerial::None)
+     *  @param stop The number of stop bits (1 or 2; default = 1)
+     */
+    void format(int bits = 8, Parity parity = USBHostSerial::None, int stop_bits = 1);
+
+
+protected:
+    //From IUSBEnumerator
+    virtual void setVidPid(uint16_t vid, uint16_t pid);
+    virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
+    virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
+
+    virtual int _getc();
+    virtual int _putc(int c);
+    
+private:
+    USBHost * host;
+    USBDeviceConnected * dev;
+    USBEndpoint * bulk_in;
+    USBEndpoint * bulk_out;
+    uint32_t size_bulk_in;
+    uint32_t size_bulk_out;
+
+    bool dev_connected;
+
+    void init();
+
+    MtxCircBuffer<uint8_t, 64> circ_buf;
+
+    uint8_t buf[64];
+
+    typedef __packed struct {
+        uint32_t baudrate;
+        uint8_t stop_bits;
+        uint8_t parity;
+        uint8_t data_bits;
+    } LINE_CODING;
+    
+    LINE_CODING line_coding;
+
+    void rxHandler();
+    void txHandler();
+    FunctionPointer rx;
+    FunctionPointer tx;
+
+    int serial_intf;
+    bool serial_device_found;
+
+};
+
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos.lib	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed-rtos/#53e6cccd8782
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtos/Mail.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,109 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef MAIL_H
+#define MAIL_H
+
+#include <stdint.h>
+#include <string.h>
+
+#include "cmsis_os.h"
+
+namespace rtos {
+
+/** The Mail class allow to control, send, receive, or wait for mail.
+ A mail is a memory block that is send to a thread or interrupt service routine.
+  @tparam  T         data type of a single message element.
+  @tparam  queue_sz  maximum number of messages in queue.
+*/
+template<typename T, uint32_t queue_sz>
+class Mail {
+public:
+    /** Create and Initialise Mail queue. */
+    Mail() {
+    #ifdef CMSIS_OS_RTX
+        memset(_mail_q, 0, sizeof(_mail_q));
+        _mail_p[0] = _mail_q;
+        
+        memset(_mail_m, 0, sizeof(_mail_m));
+        _mail_p[1] = _mail_m;
+        
+        _mail_def.pool = _mail_p;
+        _mail_def.queue_sz = queue_sz;
+        _mail_def.item_sz = sizeof(T);
+    #endif
+        _mail_id = osMailCreate(&_mail_def, NULL);
+    }
+    
+    /** Allocate a memory block of type T
+      @param   millisec  timeout value or 0 in case of no time-out. (default: 0).
+      @return  pointer to memory block that can be filled with mail or NULL in case error.
+    */
+    T* alloc(uint32_t millisec=0) {
+        return (T*)osMailAlloc(_mail_id, millisec);
+    }
+    
+    /** Allocate a memory block of type T and set memory block to zero. 
+      @param   millisec  timeout value or 0 in case of no time-out.  (default: 0).
+      @return  pointer to memory block that can be filled with mail or NULL in case error.
+    */
+    T* calloc(uint32_t millisec=0) {
+        return (T*)osMailCAlloc(_mail_id, millisec);
+    }
+    
+    /** Put a mail in the queue.
+      @param   mptr  memory block previously allocated with Mail::alloc or Mail::calloc.
+      @return  status code that indicates the execution status of the function. 
+    */
+    osStatus put(T *mptr) {
+        return osMailPut(_mail_id, (void*)mptr);
+    }
+    
+    /** Get a mail from a queue.
+      @param   millisec  timeout value or 0 in case of no time-out. (default: osWaitForever).
+      @return  event that contains mail information or error code.
+    */
+    osEvent get(uint32_t millisec=osWaitForever) {
+        return osMailGet(_mail_id, millisec);
+    }
+    
+    /** Free a memory block from a mail.
+      @param   mptr  pointer to the memory block that was obtained with Mail::get. 
+      @return  status code that indicates the execution status of the function.
+    */
+    osStatus free(T *mptr) {
+        return osMailFree(_mail_id, (void*)mptr);
+    }
+
+private:
+    osMailQId    _mail_id;
+    osMailQDef_t _mail_def;
+#ifdef CMSIS_OS_RTX
+    uint32_t     _mail_q[4+(queue_sz)];
+    uint32_t     _mail_m[3+((sizeof(T)+3)/4)*(queue_sz)];
+    void        *_mail_p[2];
+#endif
+};
+
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtos/MemoryPool.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,82 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef MEMORYPOOL_H
+#define MEMORYPOOL_H
+
+#include <stdint.h>
+#include <string.h>
+
+#include "cmsis_os.h"
+
+namespace rtos {
+
+/** Define and manage fixed-size memory pools of objects of a given type.
+  @tparam  T         data type of a single object (element).
+  @tparam  queue_sz  maximum number of objects (elements) in the memory pool.
+*/
+template<typename T, uint32_t pool_sz>
+class MemoryPool {
+public:
+    /** Create and Initialize a memory pool. */
+    MemoryPool() {
+    #ifdef CMSIS_OS_RTX
+        memset(_pool_m, 0, sizeof(_pool_m));
+        _pool_def.pool = _pool_m;
+        
+        _pool_def.pool_sz = pool_sz;
+        _pool_def.item_sz =  sizeof(T);
+    #endif
+        _pool_id = osPoolCreate(&_pool_def);
+    }
+    
+    /** Allocate a memory block of type T from a memory pool.
+      @return  address of the allocated memory block or NULL in case of no memory available.
+    */
+    T* alloc(void) {
+        return (T*)osPoolAlloc(_pool_id);
+    }
+    
+    /** Allocate a memory block of type T from a memory pool and set memory block to zero.
+      @return  address of the allocated memory block or NULL in case of no memory available. 
+    */
+    T* calloc(void) {
+        return (T*)osPoolCAlloc(_pool_id);
+    }
+    
+    /** Return an allocated memory block back to a specific memory pool.
+      @param   address of the allocated memory block that is returned to the memory pool.
+      @return  status code that indicates the execution status of the function. 
+    */
+    osStatus free(T *block) {
+        return osPoolFree(_pool_id, (void*)block);
+    }
+
+private:
+    osPoolId    _pool_id;
+    osPoolDef_t _pool_def;
+#ifdef CMSIS_OS_RTX
+    uint32_t    _pool_m[3+((sizeof(T)+3)/4)*(pool_sz)];
+#endif
+};
+
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtos/Mutex.cpp	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,56 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "Mutex.h"
+
+#include <string.h>
+#include "error.h"
+
+namespace rtos {
+
+Mutex::Mutex() {
+#ifdef CMSIS_OS_RTX
+    memset(_mutex_data, 0, sizeof(_mutex_data));
+    _osMutexDef.mutex = _mutex_data;
+#endif
+    _osMutexId = osMutexCreate(&_osMutexDef);
+    if (_osMutexId == NULL) {
+        error("Error initializing the mutex object\n");
+    }
+}
+
+osStatus Mutex::lock(uint32_t millisec) {
+    return osMutexWait(_osMutexId, millisec);
+}
+
+bool Mutex::trylock() {
+    return (osMutexWait(_osMutexId, 0) == osOK);
+}
+
+osStatus Mutex::unlock() {
+    return osMutexRelease(_osMutexId);
+}
+
+Mutex::~Mutex() {
+    osMutexDelete(_osMutexId);
+}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtos/Mutex.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,65 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef MUTEX_H
+#define MUTEX_H
+
+#include <stdint.h>
+#include "cmsis_os.h"
+
+namespace rtos {
+
+/** The Mutex class is used to synchronise the execution of threads.
+ This is for example used to protect access to a shared resource.
+*/
+class Mutex {
+public:
+    /** Create and Initialize a Mutex object */
+    Mutex();
+    
+    /** Wait until a Mutex becomes available.
+      @param   millisec  timeout value or 0 in case of no time-out. (default: osWaitForever)
+      @return  status code that indicates the execution status of the function.
+     */ 
+    osStatus lock(uint32_t millisec=osWaitForever);
+    
+    /** Try to lock the mutex, and return immediately
+      @return  true if the mutex was acquired, false otherwise.
+     */
+    bool trylock();
+    
+    /** Unlock the mutex that has previously been locked by the same thread
+      @return  status code that indicates the execution status of the function. 
+     */
+    osStatus unlock();
+    
+    ~Mutex();
+
+private:
+    osMutexId _osMutexId;
+    osMutexDef_t _osMutexDef;
+#ifdef CMSIS_OS_RTX
+    int32_t _mutex_data[3];
+#endif
+};
+
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtos/Queue.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,81 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef QUEUE_H
+#define QUEUE_H
+
+#include <stdint.h>
+#include <string.h>
+
+#include "cmsis_os.h"
+#include "error.h"
+
+namespace rtos {
+
+/** The Queue class allow to control, send, receive, or wait for messages.
+ A message can be a integer or pointer value  to a certain type T that is send
+ to a thread or interrupt service routine.
+  @tparam  T         data type of a single message element.
+  @tparam  queue_sz  maximum number of messages in queue.
+*/
+template<typename T, uint32_t queue_sz>
+class Queue {
+public:
+    /** Create and initialise a message Queue. */
+    Queue() {
+    #ifdef CMSIS_OS_RTX
+        memset(_queue_q, 0, sizeof(_queue_q));
+        _queue_def.pool = _queue_q;
+        _queue_def.queue_sz = queue_sz;
+    #endif
+        _queue_id = osMessageCreate(&_queue_def, NULL);
+        if (_queue_id == NULL) {
+            error("Error initialising the queue object\n");
+        }
+    }
+    
+    /** Put a message in a Queue.
+      @param   data      message pointer.
+      @param   millisec  timeout value or 0 in case of no time-out. (default: 0)
+      @return  status code that indicates the execution status of the function. 
+    */
+    osStatus put(T* data, uint32_t millisec=0) {
+        return osMessagePut(_queue_id, (uint32_t)data, millisec);
+    }
+    
+    /** Get a message or Wait for a message from a Queue.
+      @param   millisec  timeout value or 0 in case of no time-out. (default: osWaitForever).
+      @return  event information that includes the message and the status code.
+    */
+    osEvent get(uint32_t millisec=osWaitForever) {
+        return osMessageGet(_queue_id, millisec);
+    }
+
+private:
+    osMessageQId    _queue_id;
+    osMessageQDef_t _queue_def;
+#ifdef CMSIS_OS_RTX
+    uint32_t        _queue_q[4+(queue_sz)];
+#endif
+};
+
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtos/RtosTimer.cpp	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,53 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "RtosTimer.h"
+
+#include <string.h>
+
+#include "cmsis_os.h"
+#include "error.h"
+
+namespace rtos {
+
+RtosTimer::RtosTimer(void (*periodic_task)(void const *argument), os_timer_type type, void *argument) {
+#ifdef CMSIS_OS_RTX
+    _timer.ptimer = periodic_task;
+    
+    memset(_timer_data, 0, sizeof(_timer_data));
+    _timer.timer = _timer_data;
+#endif
+    _timer_id = osTimerCreate(&_timer, type, argument);
+}
+
+osStatus RtosTimer::start(uint32_t millisec) {
+    return osTimerStart(_timer_id, millisec);
+}
+
+osStatus RtosTimer::stop(void) {
+    return osTimerStop(_timer_id);
+}
+
+RtosTimer::~RtosTimer() {
+    osTimerDelete(_timer_id);
+}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtos/RtosTimer.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,71 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef RTOS_TIMER_H
+#define RTOS_TIMER_H
+
+#include <stdint.h>
+#include "cmsis_os.h"
+
+namespace rtos {
+
+/** The RtosTimer class allow creating and and controlling of timer functions in the system.
+ A timer function is called when a time period expires whereby both on-shot and
+ periodic timers are possible. A timer can be started, restarted, or stopped.
+
+ Timers are handled in the thread osTimerThread.
+ Callback functions run under control of this thread and may use CMSIS-RTOS API calls. 
+*/
+class RtosTimer {
+public:
+    /** Create and Start timer.
+      @param   task      name of the timer call back function.
+      @param   type      osTimerOnce for one-shot or osTimerPeriodic for periodic behaviour. (default: osTimerPeriodic)
+      @param   argument  argument to the timer call back function. (default: NULL)
+    */
+    RtosTimer(void (*task)(void const *argument),
+          os_timer_type type=osTimerPeriodic,
+          void *argument=NULL);
+    
+    /** Stop the timer.
+      @return  status code that indicates the execution status of the function. 
+    */
+    osStatus stop(void);
+    
+    /** start a timer.
+      @param   millisec  time delay value of the timer.
+      @return  status code that indicates the execution status of the function. 
+    */
+    osStatus start(uint32_t millisec);
+    
+    ~RtosTimer();
+
+private:
+    osTimerId _timer_id;
+    osTimerDef_t _timer;
+#ifdef CMSIS_OS_RTX
+    uint32_t _timer_data[5];
+#endif
+};
+
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtos/Semaphore.cpp	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,49 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "Semaphore.h"
+
+#include <string.h>
+#include "error.h"
+
+namespace rtos {
+
+Semaphore::Semaphore(int32_t count) {
+#ifdef CMSIS_OS_RTX
+    memset(_semaphore_data, 0, sizeof(_semaphore_data));
+    _osSemaphoreDef.semaphore = _semaphore_data;
+#endif
+    _osSemaphoreId = osSemaphoreCreate(&_osSemaphoreDef, count);
+}
+
+int32_t Semaphore::wait(uint32_t millisec) {
+    return osSemaphoreWait(_osSemaphoreId, millisec);
+}
+
+osStatus Semaphore::release(void) {
+    return osSemaphoreRelease(_osSemaphoreId);
+}
+
+Semaphore::~Semaphore() {
+    osSemaphoreDelete(_osSemaphoreId);
+}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtos/Semaphore.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,60 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef SEMAPHORE_H
+#define SEMAPHORE_H
+
+#include <stdint.h>
+#include "cmsis_os.h"
+
+namespace rtos {
+
+/** The Semaphore class is used to manage and protect access to a set of shared resources. */
+class Semaphore {
+public:
+    /** Create and Initialize a Semaphore object used for managing resources. 
+      @param number of available resources; maximum index value is (count-1).
+    */
+    Semaphore(int32_t count);
+    
+    /** Wait until a Semaphore resource becomes available. 
+      @param   millisec  timeout value or 0 in case of no time-out. (default: osWaitForever).
+      @return  number of available tokens, or -1 in case of incorrect parameters
+    */
+    int32_t wait(uint32_t millisec=osWaitForever);
+    
+    /** Release a Semaphore resource that was obtain with Semaphore::wait.
+      @return  status code that indicates the execution status of the function. 
+    */
+    osStatus release(void);
+    
+    ~Semaphore();
+
+private:
+    osSemaphoreId _osSemaphoreId;
+    osSemaphoreDef_t _osSemaphoreDef;
+#ifdef CMSIS_OS_RTX
+    uint32_t _semaphore_data[2];
+#endif
+};
+
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtos/Thread.cpp	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,90 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "Thread.h"
+
+#include "error.h"
+
+namespace rtos {
+
+Thread::Thread(void (*task)(void const *argument), void *argument,
+        osPriority priority, uint32_t stack_size, unsigned char *stack_pointer) {
+#ifdef CMSIS_OS_RTX
+    _thread_def.pthread = task;
+    _thread_def.tpriority = priority;
+    _thread_def.stacksize = stack_size;
+    if (stack_pointer != NULL) {
+        _thread_def.stack_pointer = stack_pointer;
+        _dynamic_stack = false;
+    } else {
+        _thread_def.stack_pointer = new unsigned char[stack_size];
+        if (_thread_def.stack_pointer == NULL)
+            error("Error allocating the stack memory");
+        _dynamic_stack = true;
+    }
+#endif
+    _tid = osThreadCreate(&_thread_def, argument);
+}
+
+osStatus Thread::terminate() {
+    return osThreadTerminate(_tid);
+}
+
+osStatus Thread::set_priority(osPriority priority) {
+    return osThreadSetPriority(_tid, priority);
+}
+
+osPriority Thread::get_priority() {
+    return osThreadGetPriority(_tid);
+}
+
+int32_t Thread::signal_set(int32_t signals) {
+    return osSignalSet(_tid, signals);
+}
+
+Thread::State Thread::get_state() {
+    return ((State)_thread_def.tcb.state);
+}
+
+osEvent Thread::signal_wait(int32_t signals, uint32_t millisec) {
+    return osSignalWait(signals, millisec);
+}
+
+osStatus Thread::wait(uint32_t millisec) {
+    return osDelay(millisec);
+}
+
+osStatus Thread::yield() {
+    return osThreadYield();
+}
+
+osThreadId Thread::gettid() {
+    return osThreadGetId();
+}
+
+Thread::~Thread() {
+    terminate();
+    if (_dynamic_stack) {
+        delete[] (_thread_def.stack_pointer);
+    }
+}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtos/Thread.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,118 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef THREAD_H
+#define THREAD_H
+
+#include <stdint.h>
+#include "cmsis_os.h"
+
+namespace rtos {
+
+/** The Thread class allow defining, creating, and controlling thread functions in the system. */
+class Thread {
+public:
+    /** Create a new thread, and start it executing the specified function.
+      @param   task           function to be executed by this thread.
+      @param   argument       pointer that is passed to the thread function as start argument. (default: NULL).
+      @param   priority       initial priority of the thread function. (default: osPriorityNormal).
+      @param   stack_size      stack size (in bytes) requirements for the thread function. (default: DEFAULT_STACK_SIZE).
+      @param   stack_pointer  pointer to the stack area to be used by this thread (default: NULL).
+    */
+    Thread(void (*task)(void const *argument), void *argument=NULL,
+           osPriority priority=osPriorityNormal,
+           uint32_t stack_size=DEFAULT_STACK_SIZE,
+           unsigned char *stack_pointer=NULL);
+    
+    /** Terminate execution of a thread and remove it from Active Threads
+      @return  status code that indicates the execution status of the function.
+    */
+    osStatus terminate();
+    
+    /** Set priority of an active thread
+      @param   priority  new priority value for the thread function.
+      @return  status code that indicates the execution status of the function.
+    */
+    osStatus set_priority(osPriority priority);
+    
+    /** Get priority of an active thread
+      @return  current priority value of the thread function.
+    */
+    osPriority get_priority();
+    
+    /** Set the specified Signal Flags of an active thread.
+      @param   signals  specifies the signal flags of the thread that should be set.
+      @return  previous signal flags of the specified thread or 0x80000000 in case of incorrect parameters.
+    */
+    int32_t signal_set(int32_t signals);
+    
+    /** State of the Thread */
+    enum State {
+        Inactive,           /**< Not created or terminated */
+        Ready,              /**< Ready to run */
+        Running,            /**< Running */
+        WaitingDelay,       /**< Waiting for a delay to occur */
+        WaitingInterval,    /**< Waiting for an interval to occur */
+        WaitingOr,          /**< Waiting for one event in a set to occur */
+        WaitingAnd,         /**< Waiting for multiple events in a set to occur */
+        WaitingSemaphore,   /**< Waiting for a semaphore event to occur */
+        WaitingMailbox,     /**< Waiting for a mailbox event to occur */
+        WaitingMutex,       /**< Waiting for a mutex event to occur */
+    };
+    
+    /** State of this Thread
+      @return  the State of this Thread
+    */
+    State get_state();
+    
+    /** Wait for one or more Signal Flags to become signaled for the current RUNNING thread. 
+      @param   signals   wait until all specified signal flags set or 0 for any single signal flag.
+      @param   millisec  timeout value or 0 in case of no time-out. (default: osWaitForever).
+      @return  event flag information or error code.
+    */
+    static osEvent signal_wait(int32_t signals, uint32_t millisec=osWaitForever);
+    
+    /** Wait for a specified time period in millisec:
+      @param   millisec  time delay value
+      @return  status code that indicates the execution status of the function. 
+    */
+    static osStatus wait(uint32_t millisec);
+    
+    /** Pass control to next thread that is in state READY.
+      @return  status code that indicates the execution status of the function.
+    */
+    static osStatus yield();
+    
+    /** Get the thread id of the current running thread.
+      @return  thread ID for reference by other functions or NULL in case of error.
+    */
+    static osThreadId gettid();
+    
+    virtual ~Thread();
+
+private:
+    osThreadId _tid;
+    osThreadDef_t _thread_def;
+    bool _dynamic_stack;
+};
+
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtos/rtos.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,35 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2012 ARM Limited
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef RTOS_H
+#define RTOS_H
+
+#include "Thread.h"
+#include "Mutex.h"
+#include "RtosTimer.h"
+#include "Semaphore.h"
+#include "Mail.h"
+#include "MemoryPool.h"
+#include "Queue.h"
+
+using namespace rtos;
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/HAL_CM.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,170 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    HAL_CM.C
+ *      Purpose: Hardware Abstraction Layer for Cortex-M
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#include "rt_TypeDef.h"
+#include "RTX_Config.h"
+#include "rt_HAL_CM.h"
+
+
+/*----------------------------------------------------------------------------
+ *      Global Variables
+ *---------------------------------------------------------------------------*/
+
+#ifdef DBG_MSG
+BIT dbg_msg;
+#endif
+
+/*----------------------------------------------------------------------------
+ *      Functions
+ *---------------------------------------------------------------------------*/
+
+
+/*--------------------------- rt_init_stack ---------------------------------*/
+
+void rt_init_stack (P_TCB p_TCB, FUNCP task_body) {
+  /* Prepare TCB and saved context for a first time start of a task. */
+  U32 *stk,i,size;
+
+  /* Prepare a complete interrupt frame for first task start */
+  size = p_TCB->priv_stack >> 2;
+  
+  /* Write to the top of stack. */
+  stk = &p_TCB->stack[size];
+
+  /* Auto correct to 8-byte ARM stack alignment. */
+  if ((U32)stk & 0x04) {
+    stk--;
+  }
+
+  stk -= 16;
+
+  /* Default xPSR and initial PC */
+  stk[15] = INITIAL_xPSR;
+  stk[14] = (U32)task_body;
+
+  /* Clear R4-R11,R0-R3,R12,LR registers. */
+  for (i = 0; i < 14; i++) {
+    stk[i] = 0;
+  }
+
+  /* Assign a void pointer to R0. */
+  stk[8] = (U32)p_TCB->msg;
+
+  /* Initial Task stack pointer. */
+  p_TCB->tsk_stack = (U32)stk;
+
+  /* Task entry point. */
+  p_TCB->ptask = task_body;
+
+  /* Set a magic word for checking of stack overflow.
+   For the main thread (ID: 0x01) the stack is in a memory area shared with the
+   heap, therefore the last word of the stack is a moving target.
+   We want to do stack/heap collision detection instead.
+  */
+  if (p_TCB->task_id != 0x01)
+      p_TCB->stack[0] = MAGIC_WORD;
+}
+
+
+/*--------------------------- rt_ret_val ----------------------------------*/
+
+static __inline U32 *rt_ret_regs (P_TCB p_TCB) {
+  /* Get pointer to task return value registers (R0..R3) in Stack */
+#if (__TARGET_FPU_VFP)
+  if (p_TCB->stack_frame) {
+    /* Extended Stack Frame: R4-R11,S16-S31,R0-R3,R12,LR,PC,xPSR,S0-S15,FPSCR */
+    return (U32 *)(p_TCB->tsk_stack + 8*4 + 16*4);
+  } else {
+    /* Basic Stack Frame: R4-R11,R0-R3,R12,LR,PC,xPSR */
+    return (U32 *)(p_TCB->tsk_stack + 8*4);
+  }
+#else
+  /* Stack Frame: R4-R11,R0-R3,R12,LR,PC,xPSR */
+  return (U32 *)(p_TCB->tsk_stack + 8*4);
+#endif
+}
+
+void rt_ret_val (P_TCB p_TCB, U32 v0) {
+  U32 *ret;
+
+  ret = rt_ret_regs(p_TCB);
+  ret[0] = v0;
+}
+
+void rt_ret_val2(P_TCB p_TCB, U32 v0, U32 v1) {
+  U32 *ret;
+
+  ret = rt_ret_regs(p_TCB);
+  ret[0] = v0;
+  ret[1] = v1;
+}
+
+
+/*--------------------------- dbg_init --------------------------------------*/
+
+#ifdef DBG_MSG
+void dbg_init (void) {
+  if ((DEMCR & DEMCR_TRCENA)     && 
+      (ITM_CONTROL & ITM_ITMENA) &&
+      (ITM_ENABLE & (1UL << 31))) {
+    dbg_msg = __TRUE;
+  }
+}
+#endif
+
+/*--------------------------- dbg_task_notify -------------------------------*/
+
+#ifdef DBG_MSG
+void dbg_task_notify (P_TCB p_tcb, BOOL create) {
+  while (ITM_PORT31_U32 == 0);
+  ITM_PORT31_U32 = (U32)p_tcb->ptask;
+  while (ITM_PORT31_U32 == 0);
+  ITM_PORT31_U16 = (create << 8) | p_tcb->task_id;
+}
+#endif
+
+/*--------------------------- dbg_task_switch -------------------------------*/
+
+#ifdef DBG_MSG
+void dbg_task_switch (U32 task_id) {
+  while (ITM_PORT31_U32 == 0);
+  ITM_PORT31_U8 = task_id;
+}
+#endif
+
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/LPC11U24/GCC_ARM/HAL_CM0.s	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,370 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    HAL_CM0.S
+ *      Purpose: Hardware Abstraction Layer for Cortex-M0
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+        .file   "HAL_CM0.S"
+        .syntax unified
+
+        .equ    TCB_TSTACK, 36
+
+
+/*----------------------------------------------------------------------------
+ *      Functions
+ *---------------------------------------------------------------------------*/
+
+        .thumb
+
+        .section ".text"
+        .align  2
+
+
+/*--------------------------- rt_set_PSP ------------------------------------*/
+
+#       void rt_set_PSP (U32 stack);
+
+        .thumb_func
+        .type   rt_set_PSP, %function
+        .global rt_set_PSP
+rt_set_PSP:
+        .fnstart
+        .cantunwind
+
+        MSR     PSP,R0
+        BX      LR
+
+        .fnend
+        .size   rt_set_PSP, .-rt_set_PSP
+
+
+/*--------------------------- rt_get_PSP ------------------------------------*/
+
+#       U32 rt_get_PSP (void);
+
+        .thumb_func
+        .type   rt_get_PSP, %function
+        .global rt_get_PSP
+rt_get_PSP:
+        .fnstart
+        .cantunwind
+
+        MRS     R0,PSP
+        BX      LR
+
+        .fnend
+        .size   rt_get_PSP, .-rt_get_PSP
+
+
+/*--------------------------- os_set_env ------------------------------------*/
+
+#       void os_set_env (void);
+        /* Switch to Unprivileged/Privileged Thread mode, use PSP. */
+
+        .thumb_func
+        .type   os_set_env, %function
+        .global os_set_env
+os_set_env:
+        .fnstart
+        .cantunwind
+
+        MOV     R0,SP                   /* PSP = MSP */
+        MSR     PSP,R0
+        LDR     R0,=os_flags
+        LDRB    R0,[R0]
+        LSLS    R0,#31
+        BNE     PrivilegedE
+        MOVS    R0,#0x03                /* Unprivileged Thread mode, use PSP */
+        MSR     CONTROL,R0
+        BX      LR
+PrivilegedE:
+        MOVS    R0,#0x02                /* Privileged Thread mode, use PSP */
+        MSR     CONTROL,R0
+        BX      LR
+
+        .fnend
+        .size   os_set_env, .-os_set_env
+
+
+/*--------------------------- _alloc_box ------------------------------------*/
+
+#      void *_alloc_box (void *box_mem);
+       /* Function wrapper for Unprivileged/Privileged mode. */
+
+        .thumb_func
+        .type   _alloc_box, %function
+        .global _alloc_box
+_alloc_box:
+        .fnstart
+        .cantunwind
+
+        LDR     R3,=rt_alloc_box
+        MOV     R12,R3
+        MRS     R3,IPSR
+        LSLS    R3,#24
+        BNE     PrivilegedA
+        MRS     R3,CONTROL
+        LSLS    R3,#31
+        BEQ     PrivilegedA
+        SVC     0
+        BX      LR
+PrivilegedA:
+        BX      R12
+
+        .fnend
+        .size   _alloc_box, .-_alloc_box
+
+
+/*--------------------------- _free_box -------------------------------------*/
+
+#       int _free_box (void *box_mem, void *box);
+        /* Function wrapper for Unprivileged/Privileged mode. */
+
+        .thumb_func
+        .type   _free_box, %function
+        .global _free_box
+_free_box:
+        .fnstart
+        .cantunwind
+
+        LDR     R3,=rt_free_box
+        MOV     R12,R3
+        MRS     R3,IPSR
+        LSLS    R3,#24
+        BNE     PrivilegedF
+        MRS     R3,CONTROL
+        LSLS    R3,#31
+        BEQ     PrivilegedF
+        SVC     0
+        BX      LR
+PrivilegedF:
+        BX      R12
+
+        .fnend
+        .size   _free_box, .-_free_box
+
+
+/*-------------------------- SVC_Handler ------------------------------------*/
+
+#       void SVC_Handler (void);
+
+        .thumb_func
+        .type   SVC_Handler, %function
+        .global SVC_Handler
+SVC_Handler:
+        .fnstart
+        .cantunwind
+
+        MRS     R0,PSP                  /* Read PSP */
+        LDR     R1,[R0,#24]             /* Read Saved PC from Stack */
+        SUBS    R1,R1,#2                /* Point to SVC Instruction */
+        LDRB    R1,[R1]                 /* Load SVC Number */
+        CMP     R1,#0
+        BNE     SVC_User                /* User SVC Number > 0 */
+
+        MOV     LR,R4
+        LDMIA   R0,{R0-R3,R4}           /* Read R0-R3,R12 from stack */
+        MOV     R12,R4
+        MOV     R4,LR
+        BLX     R12                     /* Call SVC Function */
+
+        MRS     R3,PSP                  /* Read PSP */
+        STMIA   R3!,{R0-R2}             /* Store return values */
+
+        LDR     R3,=os_tsk
+        LDMIA   R3!,{R1,R2}             /* os_tsk.run, os_tsk.new */
+        CMP     R1,R2
+        BEQ     SVC_Exit                /* no task switch */
+
+        SUBS    R3,#8
+        CMP     R1,#0                   /* Runtask deleted? */
+        BEQ     SVC_Next
+
+        MRS     R0,PSP                  /* Read PSP */
+        SUBS    R0,R0,#32               /* Adjust Start Address */
+        STR     R0,[R1,#TCB_TSTACK]     /* Update os_tsk.run->tsk_stack */       
+        STMIA   R0!,{R4-R7}             /* Save old context (R4-R7) */
+        MOV     R4,R8
+        MOV     R5,R9
+        MOV     R6,R10
+        MOV     R7,R11
+        STMIA   R0!,{R4-R7}             /* Save old context (R8-R11) */
+
+        PUSH    {R2,R3}
+        BL      rt_stk_check            /* Check for Stack overflow */
+        POP     {R2,R3}
+
+SVC_Next:
+        STR     R2,[R3]                 /* os_tsk.run = os_tsk.new */
+
+        LDR     R0,[R2,#TCB_TSTACK]     /* os_tsk.new->tsk_stack */
+        ADDS    R0,R0,#16               /* Adjust Start Address */
+        LDMIA   R0!,{R4-R7}             /* Restore new Context (R8-R11) */
+        MOV     R8,R4
+        MOV     R9,R5
+        MOV     R10,R6
+        MOV     R11,R7
+        MSR     PSP,R0                  /* Write PSP */
+        SUBS    R0,R0,#32               /* Adjust Start Address */
+        LDMIA   R0!,{R4-R7}             /* Restore new Context (R4-R7) */
+
+SVC_Exit:
+        MOVS    R0,#~0xFFFFFFFD         /* Set EXC_RETURN value */
+        MVNS    R0,R0
+        BX      R0                      /* RETI to Thread Mode, use PSP */
+
+        /*------------------- User SVC ------------------------------*/
+
+SVC_User:
+        PUSH    {R4,LR}                 /* Save Registers */
+        LDR     R2,=SVC_Count
+        LDR     R2,[R2]
+        CMP     R1,R2
+        BHI     SVC_Done                /* Overflow */
+
+        LDR     R4,=SVC_Table-4
+        LSLS    R1,R1,#2
+        LDR     R4,[R4,R1]              /* Load SVC Function Address */
+        MOV     LR,R4
+
+        LDMIA   R0,{R0-R3,R4}           /* Read R0-R3,R12 from stack */
+        MOV     R12,R4
+        BLX     LR                      /* Call SVC Function */
+
+        MRS     R4,PSP                  /* Read PSP */
+        STMIA   R4!,{R0-R3}             /* Function return values */
+SVC_Done:
+        POP     {R4,PC}                 /* RETI */
+
+        .fnend
+        .size   SVC_Handler, .-SVC_Handler
+        
+
+/*-------------------------- PendSV_Handler ---------------------------------*/
+
+#       void PendSV_Handler (void);
+
+        .thumb_func
+        .type   PendSV_Handler, %function
+        .global PendSV_Handler
+        .global Sys_Switch
+PendSV_Handler:
+        .fnstart
+        .cantunwind
+
+        BL      rt_pop_req
+
+Sys_Switch:
+        LDR     R3,=os_tsk
+        LDMIA   R3!,{R1,R2}             /* os_tsk.run, os_tsk.new */
+        CMP     R1,R2
+        BEQ     Sys_Exit                /* no task switch */
+
+        SUBS    R3,#8
+
+        MRS     R0,PSP                  /* Read PSP */
+        SUBS    R0,R0,#32               /* Adjust Start Address */
+        STR     R0,[R1,#TCB_TSTACK]     /* Update os_tsk.run->tsk_stack */
+        STMIA   R0!,{R4-R7}             /* Save old context (R4-R7) */
+        MOV     R4,R8
+        MOV     R5,R9
+        MOV     R6,R10
+        MOV     R7,R11
+        STMIA   R0!,{R4-R7}             /* Save old context (R8-R11) */
+
+        PUSH    {R2,R3}
+        BL      rt_stk_check            /* Check for Stack overflow */
+        POP     {R2,R3}
+
+        STR     R2,[R3]                 /* os_tsk.run = os_tsk.new */
+
+        LDR     R0,[R2,#TCB_TSTACK]     /* os_tsk.new->tsk_stack */
+        ADDS    R0,R0,#16               /* Adjust Start Address */
+        LDMIA   R0!,{R4-R7}             /* Restore new Context (R8-R11) */
+        MOV     R8,R4
+        MOV     R9,R5
+        MOV     R10,R6
+        MOV     R11,R7
+        MSR     PSP,R0                  /* Write PSP */
+        SUBS    R0,R0,#32               /* Adjust Start Address */
+        LDMIA   R0!,{R4-R7}             /* Restore new Context (R4-R7) */
+
+Sys_Exit:
+        MOVS    R0,#~0xFFFFFFFD         /* Set EXC_RETURN value */
+        MVNS    R0,R0
+        BX      R0                      /* RETI to Thread Mode, use PSP */
+
+        .fnend
+        .size   PendSV_Handler, .-PendSV_Handler
+
+
+/*-------------------------- SysTick_Handler --------------------------------*/
+
+#       void SysTick_Handler (void);
+
+        .thumb_func
+        .type   SysTick_Handler, %function
+        .global SysTick_Handler
+SysTick_Handler:
+        .fnstart
+        .cantunwind
+
+        BL      rt_systick
+        B       Sys_Switch
+
+        .fnend
+        .size   SysTick_Handler, .-SysTick_Handler
+
+
+/*-------------------------- OS_Tick_Handler --------------------------------*/
+
+#       void OS_Tick_Handler (void);
+
+        .thumb_func
+        .type   OS_Tick_Handler, %function
+        .global OS_Tick_Handler
+OS_Tick_Handler:
+        .fnstart
+        .cantunwind
+
+        BL      os_tick_irqack
+        BL      rt_systick
+        B       Sys_Switch
+
+        .fnend
+        .size   OS_Tick_Handler, .-OS_Tick_Handler
+
+
+        .end
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/LPC11U24/GCC_ARM/SVC_Table.s	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,56 @@
+;/*----------------------------------------------------------------------------
+; *      RL-ARM - RTX
+; *----------------------------------------------------------------------------
+; *      Name:    SVC_TABLE.S
+; *      Purpose: Pre-defined SVC Table for Cortex-M
+; *      Rev.:    V4.60
+; *----------------------------------------------------------------------------
+; *
+; * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+; * All rights reserved.
+; * Redistribution and use in source and binary forms, with or without
+; * modification, are permitted provided that the following conditions are met:
+; *  - Redistributions of source code must retain the above copyright
+; *    notice, this list of conditions and the following disclaimer.
+; *  - Redistributions in binary form must reproduce the above copyright
+; *    notice, this list of conditions and the following disclaimer in the
+; *    documentation and/or other materials provided with the distribution.
+; *  - Neither the name of ARM  nor the names of its contributors may be used 
+; *    to endorse or promote products derived from this software without 
+; *    specific prior written permission.
+; *
+; * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+; * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+; * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+; * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+; * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+; * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+; * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+; * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+; * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+; * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+; * POSSIBILITY OF SUCH DAMAGE.
+; *---------------------------------------------------------------------------*/
+
+
+        .file   "SVC_Table.S"
+
+
+        .section ".svc_table"
+
+        .global  SVC_Table
+SVC_Table:
+/* Insert user SVC functions here. SVC 0 used by RTL Kernel. */
+#       .long   __SVC_1                 /* user SVC function */
+SVC_End:
+
+        .global  SVC_Count
+SVC_Count:
+        .long   (SVC_End-SVC_Table)/4
+
+
+        .end
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/LPC11U24/uARM/HAL_CM0.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,301 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    HAL_CM0.C
+ *      Purpose: Hardware Abstraction Layer for Cortex-M0
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#include "rt_TypeDef.h"
+#include "RTX_Config.h"
+#include "rt_System.h"
+#include "rt_HAL_CM.h"
+#include "rt_Task.h"
+#include "rt_MemBox.h"
+
+
+/*----------------------------------------------------------------------------
+ *      Functions
+ *---------------------------------------------------------------------------*/
+
+
+/*--------------------------- rt_set_PSP ------------------------------------*/
+
+__asm void rt_set_PSP (U32 stack) {
+        MSR     PSP,R0
+        BX      LR
+}
+
+
+/*--------------------------- rt_get_PSP ------------------------------------*/
+
+__asm U32 rt_get_PSP (void) {
+        MRS     R0,PSP
+        BX      LR
+}
+
+
+/*--------------------------- os_set_env ------------------------------------*/
+
+__asm void os_set_env (void) {
+   /* Switch to Unprivileged/Privileged Thread mode, use PSP. */
+        MOV     R0,SP                   ; PSP = MSP
+        MSR     PSP,R0
+        LDR     R0,=__cpp(&os_flags)
+        LDRB    R0,[R0]
+        LSLS    R0,#31
+        BNE     PrivilegedE
+        MOVS    R0,#0x03                ; Unprivileged Thread mode, use PSP
+        MSR     CONTROL,R0
+        BX      LR
+PrivilegedE
+        MOVS    R0,#0x02                ; Privileged Thread mode, use PSP
+        MSR     CONTROL,R0
+        BX      LR
+
+        ALIGN
+}
+
+
+/*--------------------------- _alloc_box ------------------------------------*/
+
+__asm void *_alloc_box (void *box_mem) {
+   /* Function wrapper for Unprivileged/Privileged mode. */
+        LDR     R3,=__cpp(rt_alloc_box)
+        MOV     R12,R3
+        MRS     R3,IPSR
+        LSLS    R3,#24
+        BNE     PrivilegedA
+        MRS     R3,CONTROL
+        LSLS    R3,#31
+        BEQ     PrivilegedA
+        SVC     0
+        BX      LR
+PrivilegedA
+        BX      R12
+
+        ALIGN
+}
+
+
+/*--------------------------- _free_box -------------------------------------*/
+
+__asm int _free_box (void *box_mem, void *box) {
+   /* Function wrapper for Unprivileged/Privileged mode. */
+        LDR     R3,=__cpp(rt_free_box)
+        MOV     R12,R3
+        MRS     R3,IPSR
+        LSLS    R3,#24
+        BNE     PrivilegedF
+        MRS     R3,CONTROL
+        LSLS    R3,#31
+        BEQ     PrivilegedF
+        SVC     0
+        BX      LR
+PrivilegedF
+        BX      R12
+
+        ALIGN
+}
+
+
+/*-------------------------- SVC_Handler ------------------------------------*/
+
+__asm void SVC_Handler (void) {
+        PRESERVE8
+
+        IMPORT  SVC_Count
+        IMPORT  SVC_Table
+        IMPORT  rt_stk_check
+
+        MRS     R0,PSP                  ; Read PSP
+        LDR     R1,[R0,#24]             ; Read Saved PC from Stack
+        SUBS    R1,R1,#2                ; Point to SVC Instruction
+        LDRB    R1,[R1]                 ; Load SVC Number
+        CMP     R1,#0
+        BNE     SVC_User                ; User SVC Number > 0
+
+        MOV     LR,R4
+        LDMIA   R0,{R0-R3,R4}           ; Read R0-R3,R12 from stack
+        MOV     R12,R4
+        MOV     R4,LR
+        BLX     R12                     ; Call SVC Function 
+
+        MRS     R3,PSP                  ; Read PSP
+        STMIA   R3!,{R0-R2}             ; Store return values
+
+        LDR     R3,=__cpp(&os_tsk)
+        LDMIA   R3!,{R1,R2}             ; os_tsk.run, os_tsk.new
+        CMP     R1,R2
+        BEQ     SVC_Exit                ; no task switch
+
+        SUBS    R3,#8
+        CMP     R1,#0                   ; Runtask deleted?
+        BEQ     SVC_Next
+
+        MRS     R0,PSP                  ; Read PSP
+        SUBS    R0,R0,#32               ; Adjust Start Address
+        STR     R0,[R1,#TCB_TSTACK]     ; Update os_tsk.run->tsk_stack       
+        STMIA   R0!,{R4-R7}             ; Save old context (R4-R7)
+        MOV     R4,R8
+        MOV     R5,R9
+        MOV     R6,R10
+        MOV     R7,R11
+        STMIA   R0!,{R4-R7}             ; Save old context (R8-R11)
+        
+        PUSH    {R2,R3}
+        BL      rt_stk_check            ; Check for Stack overflow
+        POP     {R2,R3}
+
+SVC_Next
+        STR     R2,[R3]                 ; os_tsk.run = os_tsk.new
+
+        LDR     R0,[R2,#TCB_TSTACK]     ; os_tsk.new->tsk_stack
+        ADDS    R0,R0,#16               ; Adjust Start Address
+        LDMIA   R0!,{R4-R7}             ; Restore new Context (R8-R11)
+        MOV     R8,R4
+        MOV     R9,R5
+        MOV     R10,R6
+        MOV     R11,R7
+        MSR     PSP,R0                  ; Write PSP
+        SUBS    R0,R0,#32               ; Adjust Start Address
+        LDMIA   R0!,{R4-R7}             ; Restore new Context (R4-R7)
+
+SVC_Exit
+        MOVS    R0,#:NOT:0xFFFFFFFD     ; Set EXC_RETURN value
+        MVNS    R0,R0
+        BX      R0                      ; RETI to Thread Mode, use PSP
+
+        /*------------------- User SVC ------------------------------*/
+
+SVC_User
+        PUSH    {R4,LR}                 ; Save Registers
+        LDR     R2,=SVC_Count
+        LDR     R2,[R2]
+        CMP     R1,R2
+        BHI     SVC_Done                ; Overflow
+
+        LDR     R4,=SVC_Table-4
+        LSLS    R1,R1,#2
+        LDR     R4,[R4,R1]              ; Load SVC Function Address
+        MOV     LR,R4
+
+        LDMIA   R0,{R0-R3,R4}           ; Read R0-R3,R12 from stack
+        MOV     R12,R4
+        BLX     LR                      ; Call SVC Function
+
+        MRS     R4,PSP                  ; Read PSP
+        STMIA   R4!,{R0-R3}             ; Function return values
+SVC_Done
+        POP     {R4,PC}                 ; RETI
+
+        ALIGN
+}
+
+
+/*-------------------------- PendSV_Handler ---------------------------------*/
+
+__asm void PendSV_Handler (void) {
+        PRESERVE8
+
+        BL      __cpp(rt_pop_req)
+
+Sys_Switch
+        LDR     R3,=__cpp(&os_tsk)
+        LDMIA   R3!,{R1,R2}             ; os_tsk.run, os_tsk.new
+        CMP     R1,R2
+        BEQ     Sys_Exit                ; no task switch
+
+        SUBS    R3,#8
+
+        MRS     R0,PSP                  ; Read PSP
+        SUBS    R0,R0,#32               ; Adjust Start Address
+        STR     R0,[R1,#TCB_TSTACK]     ; Update os_tsk.run->tsk_stack
+        STMIA   R0!,{R4-R7}             ; Save old context (R4-R7)
+        MOV     R4,R8
+        MOV     R5,R9
+        MOV     R6,R10
+        MOV     R7,R11
+        STMIA   R0!,{R4-R7}             ; Save old context (R8-R11)
+        
+        PUSH    {R2,R3}
+        BL      rt_stk_check            ; Check for Stack overflow
+        POP     {R2,R3}
+
+        STR     R2,[R3]                 ; os_tsk.run = os_tsk.new
+
+        LDR     R0,[R2,#TCB_TSTACK]     ; os_tsk.new->tsk_stack
+        ADDS    R0,R0,#16               ; Adjust Start Address
+        LDMIA   R0!,{R4-R7}             ; Restore new Context (R8-R11)
+        MOV     R8,R4
+        MOV     R9,R5
+        MOV     R10,R6
+        MOV     R11,R7
+        MSR     PSP,R0                  ; Write PSP
+        SUBS    R0,R0,#32               ; Adjust Start Address
+        LDMIA   R0!,{R4-R7}             ; Restore new Context (R4-R7)
+
+Sys_Exit
+        MOVS    R0,#:NOT:0xFFFFFFFD     ; Set EXC_RETURN value
+        MVNS    R0,R0
+        BX      R0                      ; RETI to Thread Mode, use PSP
+
+        ALIGN
+}
+
+
+/*-------------------------- SysTick_Handler --------------------------------*/
+
+__asm void SysTick_Handler (void) {
+        PRESERVE8
+
+        BL      __cpp(rt_systick)
+        B       Sys_Switch
+
+        ALIGN
+}
+
+
+/*-------------------------- OS_Tick_Handler --------------------------------*/
+
+__asm void OS_Tick_Handler (void) {
+        PRESERVE8
+
+        BL      __cpp(os_tick_irqack)
+        BL      __cpp(rt_systick)
+        B       Sys_Switch
+
+        ALIGN
+}
+
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/LPC11U24/uARM/SVC_Table.s	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,57 @@
+;/*----------------------------------------------------------------------------
+; *      RL-ARM - RTX
+; *----------------------------------------------------------------------------
+; *      Name:    SVC_TABLE.S
+; *      Purpose: Pre-defined SVC Table for Cortex-M
+; *      Rev.:    V4.60
+; *----------------------------------------------------------------------------
+; *
+; * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+; * All rights reserved.
+; * Redistribution and use in source and binary forms, with or without
+; * modification, are permitted provided that the following conditions are met:
+; *  - Redistributions of source code must retain the above copyright
+; *    notice, this list of conditions and the following disclaimer.
+; *  - Redistributions in binary form must reproduce the above copyright
+; *    notice, this list of conditions and the following disclaimer in the
+; *    documentation and/or other materials provided with the distribution.
+; *  - Neither the name of ARM  nor the names of its contributors may be used 
+; *    to endorse or promote products derived from this software without 
+; *    specific prior written permission.
+; *
+; * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+; * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+; * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+; * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+; * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+; * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+; * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+; * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+; * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+; * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+; * POSSIBILITY OF SUCH DAMAGE.
+; *---------------------------------------------------------------------------*/
+
+
+                AREA    SVC_TABLE, CODE, READONLY
+
+                EXPORT  SVC_Count
+
+SVC_Cnt         EQU    (SVC_End-SVC_Table)/4
+SVC_Count       DCD     SVC_Cnt
+
+; Import user SVC functions here.
+;               IMPORT  __SVC_1
+
+                EXPORT  SVC_Table
+SVC_Table
+; Insert user SVC functions here. SVC 0 used by RTL Kernel.
+;               DCD     __SVC_1                 ; user SVC function
+
+SVC_End
+
+                END
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/LPC1768/ARM/HAL_CM3.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,249 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    HAL_CM3.C
+ *      Purpose: Hardware Abstraction Layer for Cortex-M3
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#include "rt_TypeDef.h"
+#include "RTX_Config.h"
+#include "rt_System.h"
+#include "rt_HAL_CM.h"
+#include "rt_Task.h"
+#include "rt_MemBox.h"
+
+
+/*----------------------------------------------------------------------------
+ *      Functions
+ *---------------------------------------------------------------------------*/
+
+
+/*--------------------------- rt_set_PSP ------------------------------------*/
+
+__asm void rt_set_PSP (U32 stack) {
+        MSR     PSP,R0
+        BX      LR
+}
+
+
+/*--------------------------- rt_get_PSP ------------------------------------*/
+
+__asm U32 rt_get_PSP (void) {
+        MRS     R0,PSP
+        BX      LR
+}
+
+
+/*--------------------------- os_set_env ------------------------------------*/
+
+__asm void os_set_env (void) {
+   /* Switch to Unprivileged/Privileged Thread mode, use PSP. */
+        MOV     R0,SP                   ; PSP = MSP
+        MSR     PSP,R0
+        LDR     R0,=__cpp(&os_flags)
+        LDRB    R0,[R0]
+        LSLS    R0,#31
+        MOVNE   R0,#0x02                ; Privileged Thread mode, use PSP
+        MOVEQ   R0,#0x03                ; Unprivileged Thread mode, use PSP
+        MSR     CONTROL,R0
+        BX      LR
+
+        ALIGN
+}
+
+
+/*--------------------------- _alloc_box ------------------------------------*/
+
+__asm void *_alloc_box (void *box_mem) {
+   /* Function wrapper for Unprivileged/Privileged mode. */
+        LDR     R12,=__cpp(rt_alloc_box)
+        MRS     R3,IPSR
+        LSLS    R3,#24
+        BXNE    R12
+        MRS     R3,CONTROL
+        LSLS    R3,#31
+        BXEQ    R12
+        SVC     0
+        BX      LR
+
+        ALIGN
+}
+
+
+/*--------------------------- _free_box -------------------------------------*/
+
+__asm int _free_box (void *box_mem, void *box) {
+   /* Function wrapper for Unprivileged/Privileged mode. */
+        LDR     R12,=__cpp(rt_free_box)
+        MRS     R3,IPSR
+        LSLS    R3,#24
+        BXNE    R12
+        MRS     R3,CONTROL
+        LSLS    R3,#31
+        BXEQ    R12
+        SVC     0
+        BX      LR
+
+        ALIGN
+}
+
+
+/*-------------------------- SVC_Handler ------------------------------------*/
+
+__asm void SVC_Handler (void) {
+        PRESERVE8
+
+        IMPORT  SVC_Count
+        IMPORT  SVC_Table
+        IMPORT  rt_stk_check
+
+        MRS     R0,PSP                  ; Read PSP
+        LDR     R1,[R0,#24]             ; Read Saved PC from Stack
+        LDRB    R1,[R1,#-2]             ; Load SVC Number
+        CBNZ    R1,SVC_User
+
+        LDM     R0,{R0-R3,R12}          ; Read R0-R3,R12 from stack
+        BLX     R12                     ; Call SVC Function 
+
+        MRS     R12,PSP                 ; Read PSP
+        STM     R12,{R0-R2}             ; Store return values
+
+        LDR     R3,=__cpp(&os_tsk)
+        LDM     R3,{R1,R2}              ; os_tsk.run, os_tsk.new
+        CMP     R1,R2
+        BEQ     SVC_Exit                ; no task switch
+
+        CBZ     R1,SVC_Next             ; Runtask deleted?
+        STMDB   R12!,{R4-R11}           ; Save Old context
+        STR     R12,[R1,#TCB_TSTACK]    ; Update os_tsk.run->tsk_stack
+
+        PUSH    {R2,R3}
+        BL      rt_stk_check            ; Check for Stack overflow
+        POP     {R2,R3}
+
+SVC_Next
+        STR     R2,[R3]                 ; os_tsk.run = os_tsk.new
+
+        LDR     R12,[R2,#TCB_TSTACK]    ; os_tsk.new->tsk_stack
+        LDMIA   R12!,{R4-R11}           ; Restore New Context
+        MSR     PSP,R12                 ; Write PSP
+
+SVC_Exit
+        MVN     LR,#:NOT:0xFFFFFFFD     ; set EXC_RETURN value
+        BX      LR
+
+        /*------------------- User SVC ------------------------------*/
+
+SVC_User
+        PUSH    {R4,LR}                 ; Save Registers
+        LDR     R2,=SVC_Count
+        LDR     R2,[R2]
+        CMP     R1,R2
+        BHI     SVC_Done                ; Overflow
+
+        LDR     R4,=SVC_Table-4
+        LDR     R4,[R4,R1,LSL #2]       ; Load SVC Function Address
+
+        LDM     R0,{R0-R3,R12}          ; Read R0-R3,R12 from stack
+        BLX     R4                      ; Call SVC Function
+
+        MRS     R12,PSP
+        STM     R12,{R0-R3}             ; Function return values
+SVC_Done
+        POP     {R4,PC}                 ; RETI
+
+        ALIGN
+}
+
+
+/*-------------------------- PendSV_Handler ---------------------------------*/
+
+__asm void PendSV_Handler (void) {
+        PRESERVE8
+
+        BL      __cpp(rt_pop_req)
+
+Sys_Switch
+        LDR     R3,=__cpp(&os_tsk)
+        LDM     R3,{R1,R2}              ; os_tsk.run, os_tsk.new
+        CMP     R1,R2
+        BEQ     Sys_Exit
+
+        MRS     R12,PSP                 ; Read PSP
+        STMDB   R12!,{R4-R11}           ; Save Old context
+        STR     R12,[R1,#TCB_TSTACK]    ; Update os_tsk.run->tsk_stack
+
+        PUSH    {R2,R3}
+        BL      rt_stk_check            ; Check for Stack overflow
+        POP     {R2,R3}
+
+        STR     R2,[R3]                 ; os_tsk.run = os_tsk.new
+
+        LDR     R12,[R2,#TCB_TSTACK]    ; os_tsk.new->tsk_stack
+        LDMIA   R12!,{R4-R11}           ; Restore New Context
+        MSR     PSP,R12                 ; Write PSP
+
+Sys_Exit
+        MVN     LR,#:NOT:0xFFFFFFFD     ; set EXC_RETURN value
+        BX      LR                      ; Return to Thread Mode
+
+        ALIGN
+}
+
+
+/*-------------------------- SysTick_Handler --------------------------------*/
+
+__asm void SysTick_Handler (void) {
+        PRESERVE8
+
+        BL      __cpp(rt_systick)
+        B       Sys_Switch
+
+        ALIGN
+}
+
+
+/*-------------------------- OS_Tick_Handler --------------------------------*/
+
+__asm void OS_Tick_Handler (void) {
+        PRESERVE8
+
+        BL      __cpp(os_tick_irqack)
+        BL      __cpp(rt_systick)
+        B       Sys_Switch
+
+        ALIGN
+}
+
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/LPC1768/ARM/SVC_Table.s	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,57 @@
+;/*----------------------------------------------------------------------------
+; *      RL-ARM - RTX
+; *----------------------------------------------------------------------------
+; *      Name:    SVC_TABLE.S
+; *      Purpose: Pre-defined SVC Table for Cortex-M
+; *      Rev.:    V4.60
+; *----------------------------------------------------------------------------
+; *
+; * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+; * All rights reserved.
+; * Redistribution and use in source and binary forms, with or without
+; * modification, are permitted provided that the following conditions are met:
+; *  - Redistributions of source code must retain the above copyright
+; *    notice, this list of conditions and the following disclaimer.
+; *  - Redistributions in binary form must reproduce the above copyright
+; *    notice, this list of conditions and the following disclaimer in the
+; *    documentation and/or other materials provided with the distribution.
+; *  - Neither the name of ARM  nor the names of its contributors may be used 
+; *    to endorse or promote products derived from this software without 
+; *    specific prior written permission.
+; *
+; * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+; * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+; * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+; * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+; * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+; * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+; * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+; * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+; * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+; * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+; * POSSIBILITY OF SUCH DAMAGE.
+; *---------------------------------------------------------------------------*/
+
+
+                AREA    SVC_TABLE, CODE, READONLY
+
+                EXPORT  SVC_Count
+
+SVC_Cnt         EQU    (SVC_End-SVC_Table)/4
+SVC_Count       DCD     SVC_Cnt
+
+; Import user SVC functions here.
+;               IMPORT  __SVC_1
+
+                EXPORT  SVC_Table
+SVC_Table
+; Insert user SVC functions here. SVC 0 used by RTL Kernel.
+;               DCD     __SVC_1                 ; user SVC function
+
+SVC_End
+
+                END
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/LPC1768/GCC_ARM/HAL_CM3.s	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,323 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    HAL_CM3.S
+ *      Purpose: Hardware Abstraction Layer for Cortex-M3
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+        .file   "HAL_CM3.S"
+        .syntax unified
+
+        .equ    TCB_TSTACK, 36
+
+
+/*----------------------------------------------------------------------------
+ *      Functions
+ *---------------------------------------------------------------------------*/
+
+        .thumb
+
+        .section ".text"
+        .align  2
+
+
+/*--------------------------- rt_set_PSP ------------------------------------*/
+
+#       void rt_set_PSP (U32 stack);
+
+        .thumb_func
+        .type   rt_set_PSP, %function
+        .global rt_set_PSP
+rt_set_PSP:
+        .fnstart
+        .cantunwind
+
+        MSR     PSP,R0
+        BX      LR
+
+        .fnend
+        .size   rt_set_PSP, .-rt_set_PSP
+
+
+/*--------------------------- rt_get_PSP ------------------------------------*/
+
+#       U32 rt_get_PSP (void);
+
+        .thumb_func
+        .type   rt_get_PSP, %function
+        .global rt_get_PSP
+rt_get_PSP:
+        .fnstart
+        .cantunwind
+
+        MRS     R0,PSP
+        BX      LR
+
+        .fnend
+        .size   rt_get_PSP, .-rt_get_PSP
+
+
+/*--------------------------- os_set_env ------------------------------------*/
+
+#       void os_set_env (void);
+        /* Switch to Unprivileged/Privileged Thread mode, use PSP. */
+
+        .thumb_func
+        .type   os_set_env, %function
+        .global os_set_env
+os_set_env:
+        .fnstart
+        .cantunwind
+
+        MOV     R0,SP                   /* PSP = MSP */
+        MSR     PSP,R0
+        LDR     R0,=os_flags
+        LDRB    R0,[R0]
+        LSLS    R0,#31
+        ITE     NE
+        MOVNE   R0,#0x02                /* Privileged Thread mode, use PSP */
+        MOVEQ   R0,#0x03                /* Unprivileged Thread mode, use PSP */
+        MSR     CONTROL,R0
+        BX      LR
+
+        .fnend
+        .size   os_set_env, .-os_set_env
+
+
+/*--------------------------- _alloc_box ------------------------------------*/
+
+#      void *_alloc_box (void *box_mem);
+       /* Function wrapper for Unprivileged/Privileged mode. */
+
+        .thumb_func
+        .type   _alloc_box, %function
+        .global _alloc_box
+_alloc_box:
+        .fnstart
+        .cantunwind
+
+        LDR     R12,=rt_alloc_box
+        MRS     R3,IPSR
+        LSLS    R3,#24
+        IT      NE
+        BXNE    R12
+        MRS     R3,CONTROL
+        LSLS    R3,#31
+        IT      EQ
+        BXEQ    R12
+        SVC     0
+        BX      LR
+
+        .fnend
+        .size   _alloc_box, .-_alloc_box
+
+
+/*--------------------------- _free_box -------------------------------------*/
+
+#       int _free_box (void *box_mem, void *box);
+        /* Function wrapper for Unprivileged/Privileged mode. */
+
+        .thumb_func
+        .type   _free_box, %function
+        .global _free_box
+_free_box:
+        .fnstart
+        .cantunwind
+
+        LDR     R12,=rt_free_box
+        MRS     R3,IPSR
+        LSLS    R3,#24
+        IT      NE
+        BXNE    R12
+        MRS     R3,CONTROL
+        LSLS    R3,#31
+        IT      EQ
+        BXEQ    R12
+        SVC     0
+        BX      LR
+
+        .fnend
+        .size   _free_box, .-_free_box
+
+
+/*-------------------------- SVC_Handler ------------------------------------*/
+
+#       void SVC_Handler (void);
+
+        .thumb_func
+        .type   SVC_Handler, %function
+        .global SVC_Handler
+SVC_Handler:
+        .fnstart
+        .cantunwind
+
+        MRS     R0,PSP                  /* Read PSP */
+        LDR     R1,[R0,#24]             /* Read Saved PC from Stack */
+        LDRB    R1,[R1,#-2]             /* Load SVC Number */
+        CBNZ    R1,SVC_User
+
+        LDM     R0,{R0-R3,R12}          /* Read R0-R3,R12 from stack */
+        BLX     R12                     /* Call SVC Function */
+
+        MRS     R12,PSP                 /* Read PSP */
+        STM     R12,{R0-R2}             /* Store return values */
+
+        LDR     R3,=os_tsk
+        LDM     R3,{R1,R2}              /* os_tsk.run, os_tsk.new */
+        CMP     R1,R2
+        BEQ     SVC_Exit                /* no task switch */
+
+        CBZ     R1,SVC_Next             /* Runtask deleted? */
+        STMDB   R12!,{R4-R11}           /* Save Old context */
+        STR     R12,[R1,#TCB_TSTACK]    /* Update os_tsk.run->tsk_stack */
+
+        PUSH    {R2,R3}
+        BL      rt_stk_check            /* Check for Stack overflow */
+        POP     {R2,R3}
+
+SVC_Next:
+        STR     R2,[R3]                 /* os_tsk.run = os_tsk.new */
+
+        LDR     R12,[R2,#TCB_TSTACK]    /* os_tsk.new->tsk_stack */
+        LDMIA   R12!,{R4-R11}           /* Restore New Context */
+        MSR     PSP,R12                 /* Write PSP */
+
+SVC_Exit:
+        MVN     LR,#~0xFFFFFFFD         /* set EXC_RETURN value */
+        BX      LR
+
+        /*------------------- User SVC ------------------------------*/
+
+SVC_User:
+        PUSH    {R4,LR}                 /* Save Registers */
+        LDR     R2,=SVC_Count
+        LDR     R2,[R2]
+        CMP     R1,R2
+        BHI     SVC_Done                /* Overflow */
+
+        LDR     R4,=SVC_Table-4
+        LDR     R4,[R4,R1,LSL #2]       /* Load SVC Function Address */
+
+        LDM     R0,{R0-R3,R12}          /* Read R0-R3,R12 from stack */
+        BLX     R4                      /* Call SVC Function */
+
+        MRS     R12,PSP
+        STM     R12,{R0-R3}             /* Function return values */
+SVC_Done:
+        POP     {R4,PC}                 /* RETI */
+
+        .fnend
+        .size   SVC_Handler, .-SVC_Handler
+        
+
+/*-------------------------- PendSV_Handler ---------------------------------*/
+
+#       void PendSV_Handler (void);
+
+        .thumb_func
+        .type   PendSV_Handler, %function
+        .global PendSV_Handler
+        .global Sys_Switch
+PendSV_Handler:
+        .fnstart
+        .cantunwind
+
+        BL      rt_pop_req
+
+Sys_Switch:
+        LDR     R3,=os_tsk
+        LDM     R3,{R1,R2}              /* os_tsk.run, os_tsk.new */
+        CMP     R1,R2
+        BEQ     Sys_Exit
+
+        MRS     R12,PSP                 /* Read PSP */
+        STMDB   R12!,{R4-R11}           /* Save Old context */
+        STR     R12,[R1,#TCB_TSTACK]    /* Update os_tsk.run->tsk_stack */
+
+        PUSH    {R2,R3}
+        BL      rt_stk_check            /* Check for Stack overflow */
+        POP     {R2,R3}
+
+        STR     R2,[R3]                 /* os_tsk.run = os_tsk.new */
+
+        LDR     R12,[R2,#TCB_TSTACK]    /* os_tsk.new->tsk_stack */
+        LDMIA   R12!,{R4-R11}           /* Restore New Context */
+        MSR     PSP,R12                 /* Write PSP */
+
+Sys_Exit:
+        MVN     LR,#~0xFFFFFFFD         /* set EXC_RETURN value */
+        BX      LR                      /* Return to Thread Mode */
+
+        .fnend
+        .size   PendSV_Handler, .-PendSV_Handler
+
+
+/*-------------------------- SysTick_Handler --------------------------------*/
+
+#       void SysTick_Handler (void);
+
+        .thumb_func
+        .type   SysTick_Handler, %function
+        .global SysTick_Handler
+SysTick_Handler:
+        .fnstart
+        .cantunwind
+
+        BL      rt_systick
+        B       Sys_Switch
+
+        .fnend
+        .size   SysTick_Handler, .-SysTick_Handler
+
+
+/*-------------------------- OS_Tick_Handler --------------------------------*/
+
+#       void OS_Tick_Handler (void);
+
+        .thumb_func
+        .type   OS_Tick_Handler, %function
+        .global OS_Tick_Handler
+OS_Tick_Handler:
+        .fnstart
+        .cantunwind
+
+        BL      os_tick_irqack
+        BL      rt_systick
+        B       Sys_Switch
+
+        .fnend
+        .size   OS_Tick_Handler, .-OS_Tick_Handler
+
+
+        .end
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/LPC1768/GCC_ARM/SVC_Table.s	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,56 @@
+;/*----------------------------------------------------------------------------
+; *      RL-ARM - RTX
+; *----------------------------------------------------------------------------
+; *      Name:    SVC_TABLE.S
+; *      Purpose: Pre-defined SVC Table for Cortex-M
+; *      Rev.:    V4.60
+; *----------------------------------------------------------------------------
+; *
+; * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+; * All rights reserved.
+; * Redistribution and use in source and binary forms, with or without
+; * modification, are permitted provided that the following conditions are met:
+; *  - Redistributions of source code must retain the above copyright
+; *    notice, this list of conditions and the following disclaimer.
+; *  - Redistributions in binary form must reproduce the above copyright
+; *    notice, this list of conditions and the following disclaimer in the
+; *    documentation and/or other materials provided with the distribution.
+; *  - Neither the name of ARM  nor the names of its contributors may be used 
+; *    to endorse or promote products derived from this software without 
+; *    specific prior written permission.
+; *
+; * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+; * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+; * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+; * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+; * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+; * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+; * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+; * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+; * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+; * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+; * POSSIBILITY OF SUCH DAMAGE.
+; *---------------------------------------------------------------------------*/
+
+
+        .file   "SVC_Table.S"
+
+
+        .section ".svc_table"
+
+        .global  SVC_Table
+SVC_Table:
+/* Insert user SVC functions here. SVC 0 used by RTL Kernel. */
+#       .long   __SVC_1                 /* user SVC function */
+SVC_End:
+
+        .global  SVC_Count
+SVC_Count:
+        .long   (SVC_End-SVC_Table)/4
+
+
+        .end
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/RTX_CM_lib.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,368 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    RTX_CM_LIB.H
+ *      Purpose: RTX Kernel System Configuration
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+#include "error.h"
+
+#if   defined (__CC_ARM)
+#pragma O3
+#define __USED __attribute__((used))
+#elif defined (__GNUC__)
+#pragma GCC optimize ("O3")
+#define __USED __attribute__((used))
+#elif defined (__ICCARM__)
+#define __USED __root
+#endif
+
+
+/*----------------------------------------------------------------------------
+ *      Definitions
+ *---------------------------------------------------------------------------*/
+
+#define _declare_box(pool,size,cnt)  uint32_t pool[(((size)+3)/4)*(cnt) + 3]
+#define _declare_box8(pool,size,cnt) uint64_t pool[(((size)+7)/8)*(cnt) + 2]
+
+#define OS_TCB_SIZE     48
+#define OS_TMR_SIZE     8
+
+#if defined (__CC_ARM) && !defined (__MICROLIB)
+
+typedef void    *OS_ID;
+typedef uint32_t OS_TID;
+typedef uint32_t OS_MUT[3];
+typedef uint32_t OS_RESULT;
+
+#define runtask_id()    rt_tsk_self()
+#define mutex_init(m)   rt_mut_init(m)
+#define mutex_wait(m)   os_mut_wait(m,0xFFFF)
+#define mutex_rel(m)    os_mut_release(m)
+
+extern OS_TID    rt_tsk_self    (void);
+extern void      rt_mut_init    (OS_ID mutex);
+extern OS_RESULT rt_mut_release (OS_ID mutex);
+extern OS_RESULT rt_mut_wait    (OS_ID mutex, uint16_t timeout);
+
+#define os_mut_wait(mutex,timeout) _os_mut_wait((uint32_t)rt_mut_wait,mutex,timeout)
+#define os_mut_release(mutex)      _os_mut_release((uint32_t)rt_mut_release,mutex)
+
+OS_RESULT _os_mut_release (uint32_t p, OS_ID mutex)                   __svc_indirect(0);
+OS_RESULT _os_mut_wait    (uint32_t p, OS_ID mutex, uint16_t timeout) __svc_indirect(0);
+
+#endif
+
+
+/*----------------------------------------------------------------------------
+ *      Global Variables
+ *---------------------------------------------------------------------------*/
+
+#if (OS_TIMERS != 0)
+#define OS_TASK_CNT (OS_TASKCNT + 1)
+#else
+#define OS_TASK_CNT  OS_TASKCNT
+#endif
+
+uint16_t const os_maxtaskrun = OS_TASK_CNT;
+uint32_t const os_rrobin     = (OS_ROBIN << 16) | OS_ROBINTOUT;
+uint32_t const os_trv        = OS_TRV;
+uint8_t  const os_flags      = OS_RUNPRIV;
+
+/* Export following defines to uVision debugger. */
+__USED uint32_t const os_clockrate = OS_TICK;
+__USED uint32_t const os_timernum  = 0;
+
+/* Stack for the os_idle_demon */
+unsigned int idle_task_stack[OS_IDLESTKSIZE];
+unsigned short const idle_task_stack_size = OS_IDLESTKSIZE;
+
+#ifndef OS_FIFOSZ
+ #define OS_FIFOSZ      16
+#endif
+
+/* Fifo Queue buffer for ISR requests.*/
+uint32_t       os_fifo[OS_FIFOSZ*2+1];
+uint8_t  const os_fifo_size = OS_FIFOSZ;
+
+/* An array of Active task pointers. */
+void *os_active_TCB[OS_TASK_CNT];
+
+/* User Timers Resources */
+#if (OS_TIMERS != 0)
+extern void osTimerThread (void const *argument);
+osThreadDef(osTimerThread, (osPriority)(OS_TIMERPRIO-3), 4*OS_TIMERSTKSZ);
+osThreadId osThreadId_osTimerThread;
+osMessageQDef(osTimerMessageQ, OS_TIMERCBQS, void *);
+osMessageQId osMessageQId_osTimerMessageQ;
+#else
+osThreadDef_t os_thread_def_osTimerThread = { NULL };
+osThreadId osThreadId_osTimerThread;
+osMessageQDef(osTimerMessageQ, 0, void *);
+osMessageQId osMessageQId_osTimerMessageQ;
+#endif
+
+
+/*----------------------------------------------------------------------------
+ *      RTX Optimizations (empty functions)
+ *---------------------------------------------------------------------------*/
+
+#if OS_ROBIN == 0
+ void rt_init_robin (void) {;}
+ void rt_chk_robin  (void) {;}
+#endif
+
+#if OS_STKCHECK == 0
+ void rt_stk_check  (void) {;}
+#endif
+
+
+/*----------------------------------------------------------------------------
+ *      Standard Library multithreading interface
+ *---------------------------------------------------------------------------*/
+
+#if defined (__CC_ARM) && !defined (__MICROLIB)
+ static OS_MUT   std_libmutex[OS_MUTEXCNT];
+ static uint32_t nr_mutex;
+
+ /*--------------------------- _mutex_initialize -----------------------------*/
+ 
+int _mutex_initialize (OS_ID *mutex) {
+  /* Allocate and initialize a system mutex. */
+
+  if (nr_mutex >= OS_MUTEXCNT) {
+    /* If you are here, you need to increase the number OS_MUTEXCNT. */
+    error("Not enough stdlib mutexes\n");
+  }
+  *mutex = &std_libmutex[nr_mutex++];
+  mutex_init (*mutex);
+  return (1);
+}
+
+
+/*--------------------------- _mutex_acquire --------------------------------*/
+
+__attribute__((used)) void _mutex_acquire (OS_ID *mutex) {
+  /* Acquire a system mutex, lock stdlib resources. */
+  if (runtask_id ()) {
+    /* RTX running, acquire a mutex. */
+    mutex_wait (*mutex);
+  }
+}
+
+
+/*--------------------------- _mutex_release --------------------------------*/
+
+__attribute__((used)) void _mutex_release (OS_ID *mutex) {
+  /* Release a system mutex, unlock stdlib resources. */
+  if (runtask_id ()) {
+    /* RTX running, release a mutex. */
+    mutex_rel (*mutex);
+  }
+}
+
+#endif
+
+
+/*----------------------------------------------------------------------------
+ *      RTX Startup
+ *---------------------------------------------------------------------------*/
+
+/* Main Thread definition */
+extern int main (void);
+osThreadDef_t os_thread_def_main = {(os_pthread)main, osPriorityNormal, 0, NULL};
+
+#if defined (__CC_ARM)
+
+// This define should be probably moved to the CMSIS layer
+#ifdef TARGET_LPC1768
+#define INITIAL_SP            (0x10008000UL)
+
+#elif TARGET_LPC11U24
+#define INITIAL_SP            (0x10001000UL)
+
+#endif
+
+extern unsigned char Image$$RW_IRAM1$$ZI$$Limit[];
+
+void set_main_stack(void) {
+    // Leave OS_SCHEDULERSTKSIZE words for the scheduler and interrupts
+    os_thread_def_main.stack_pointer = Image$$RW_IRAM1$$ZI$$Limit;
+    os_thread_def_main.stacksize = (INITIAL_SP - (unsigned int)Image$$RW_IRAM1$$ZI$$Limit) - (OS_SCHEDULERSTKSIZE * 4);
+}
+
+#ifdef __MICROLIB
+void _main_init (void) __attribute__((section(".ARM.Collect$$$$000000FF")));
+void _main_init (void) {
+  osKernelInitialize();
+  set_main_stack();
+  osThreadCreate(&os_thread_def_main, NULL);
+  osKernelStart();
+  for (;;);
+}
+#else
+
+/* The single memory model is checking for stack collision at run time, verifing
+   that the heap pointer is underneath the stack pointer.
+   
+   With the RTOS there is not only one stack above the heap, there are multiple
+   stacks and some of them are underneath the heap pointer.
+*/
+#pragma import(__use_two_region_memory)
+
+__asm void __rt_entry (void) {
+
+  IMPORT  __user_setup_stackheap
+  IMPORT  __rt_lib_init
+  IMPORT  os_thread_def_main
+  IMPORT  osKernelInitialize
+  IMPORT  set_main_stack
+  IMPORT  osKernelStart
+  IMPORT  osThreadCreate
+  IMPORT  exit
+
+  BL      __user_setup_stackheap
+  MOV     R1,R2
+  BL      __rt_lib_init
+  BL      osKernelInitialize
+  BL      set_main_stack
+  LDR     R0,=os_thread_def_main
+  MOVS    R1,#0
+  BL      osThreadCreate
+  BL      osKernelStart
+  BL      exit
+
+  ALIGN
+}
+#endif
+
+#elif defined (__GNUC__)
+
+#ifdef __CS3__
+
+/* CS3 start_c routine.
+ *
+ * Copyright (c) 2006, 2007 CodeSourcery Inc
+ *
+ * The authors hereby grant permission to use, copy, modify, distribute,
+ * and license this software and its documentation for any purpose, provided
+ * that existing copyright notices are retained in all copies and that this
+ * notice is included verbatim in any distributions. No written agreement,
+ * license, or royalty fee is required for any of the authorized uses.
+ * Modifications to this software may be copyrighted by their authors
+ * and need not follow the licensing terms described here, provided that
+ * the new terms are clearly indicated on the first page of each file where
+ * they apply.
+ */
+
+#include "cs3.h"
+
+extern void __libc_init_array (void);
+
+__attribute ((noreturn)) void __cs3_start_c (void){
+  unsigned regions = __cs3_region_num;
+  const struct __cs3_region *rptr = __cs3_regions;
+
+  /* Initialize memory */
+  for (regions = __cs3_region_num, rptr = __cs3_regions; regions--; rptr++) {
+    long long *src = (long long *)rptr->init;
+    long long *dst = (long long *)rptr->data;
+    unsigned limit = rptr->init_size;
+    unsigned count;
+
+    if (src != dst)
+      for (count = 0; count != limit; count += sizeof (long long))
+        *dst++ = *src++;
+    else 
+      dst = (long long *)((char *)dst + limit);
+    limit = rptr->zero_size;
+    for (count = 0; count != limit; count += sizeof (long long))
+      *dst++ = 0;
+  }
+
+  /* Run initializers.  */
+  __libc_init_array ();
+
+  osKernelInitialize();
+  osThreadCreate(&os_thread_def_main, NULL);
+  osKernelStart();
+  for (;;);
+}
+
+#else
+
+__attribute__((naked)) void software_init_hook (void) {
+  __asm (
+    ".syntax unified\n"
+    ".thumb\n"
+    "movs r0,#0\n"
+    "movs r1,#0\n"
+    "mov  r4,r0\n"
+    "mov  r5,r1\n"
+    "ldr  r0,= __libc_fini_array\n"
+    "bl   atexit\n"
+    "bl   __libc_init_array\n"
+    "mov  r0,r4\n"
+    "mov  r1,r5\n"
+    "bl   osKernelInitialize\n"
+    "ldr  r0,=os_thread_def_main\n"
+    "movs r1,#0\n"
+    "bl   osThreadCreate\n"
+    "bl   osKernelStart\n"
+    "bl   exit\n"
+  );
+}
+
+#endif
+
+#elif defined (__ICCARM__)
+
+extern int  __low_level_init(void);
+extern void __iar_data_init3(void);
+extern void exit(int arg);
+
+__noreturn __stackless void __cmain(void) {
+  int a;
+  
+  if (__low_level_init() != 0) {
+    __iar_data_init3();
+  }
+  osKernelInitialize();
+  osThreadCreate(&os_thread_def_main, NULL);
+  a = osKernelStart();
+  exit(a);
+}
+
+#endif
+
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/RTX_Conf_CM.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,241 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    RTX_Conf_CM.C
+ *      Purpose: Configuration of CMSIS RTX Kernel for Cortex-M
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#include "cmsis_os.h"
+
+
+/*----------------------------------------------------------------------------
+ *      RTX User configuration part BEGIN
+ *---------------------------------------------------------------------------*/
+
+//-------- <<< Use Configuration Wizard in Context Menu >>> -----------------
+//
+// <h>Thread Configuration
+// =======================
+//
+//   <o>Number of concurrent running threads <0-250>
+//   <i> Defines max. number of threads that will run at the same time.
+//       counting "main", but not counting "osTimerThread"
+//   <i> Default: 6
+#ifndef OS_TASKCNT
+#  if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
+#    define OS_TASKCNT         14
+#  elif defined(TARGET_LPC11U24)
+#    define OS_TASKCNT         6
+#  endif
+#endif
+
+//   <o>Scheduler (+ interrupts) stack size [bytes] <64-4096:8><#/4>
+#ifndef OS_SCHEDULERSTKSIZE
+#  if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
+#      define OS_SCHEDULERSTKSIZE    256
+#  elif defined(TARGET_LPC11U24)
+#      define OS_SCHEDULERSTKSIZE    128
+#  endif
+#endif
+
+//   <o>Idle stack size [bytes] <64-4096:8><#/4>
+//   <i> Defines default stack size for the Idle thread.
+#ifndef OS_IDLESTKSIZE
+ #define OS_IDLESTKSIZE         128
+#endif
+
+//   <o>Timer Thread stack size [bytes] <64-4096:8><#/4>
+//   <i> Defines stack size for Timer thread.
+//   <i> Default: 200
+#ifndef OS_TIMERSTKSZ
+ #define OS_TIMERSTKSZ  WORDS_STACK_SIZE
+#endif
+
+// <q>Check for stack overflow
+// <i> Includes the stack checking code for stack overflow.
+// <i> Note that additional code reduces the Kernel performance.
+#ifndef OS_STKCHECK
+ #define OS_STKCHECK    1
+#endif
+
+// <o>Processor mode for thread execution 
+//   <0=> Unprivileged mode 
+//   <1=> Privileged mode
+// <i> Default: Privileged mode
+#ifndef OS_RUNPRIV
+ #define OS_RUNPRIV     1
+#endif
+
+// </h>
+// <h>SysTick Timer Configuration
+// ==============================
+//
+//   <o>Timer clock value [Hz] <1-1000000000>
+//   <i> Defines the timer clock value.
+//   <i> Default: 6000000  (6MHz)
+#ifndef OS_CLOCK
+#  if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
+#    define OS_CLOCK       96000000
+#  elif defined(TARGET_LPC11U24)
+#    define OS_CLOCK       48000000
+#  endif
+#endif
+
+//   <o>Timer tick value [us] <1-1000000>
+//   <i> Defines the timer tick value.
+//   <i> Default: 1000  (1ms)
+#ifndef OS_TICK
+ #define OS_TICK        1000
+#endif
+
+// </h>
+
+// <h>System Configuration
+// =======================
+//
+// <e>Round-Robin Thread switching
+// ===============================
+//
+// <i> Enables Round-Robin Thread switching.
+#ifndef OS_ROBIN
+ #define OS_ROBIN       1
+#endif
+
+//   <o>Round-Robin Timeout [ticks] <1-1000>
+//   <i> Defines how long a thread will execute before a thread switch.
+//   <i> Default: 5
+#ifndef OS_ROBINTOUT
+ #define OS_ROBINTOUT   5
+#endif
+
+// </e>
+
+// <e>User Timers
+// ==============
+//   <i> Enables user Timers
+#ifndef OS_TIMERS
+ #define OS_TIMERS      1
+#endif
+
+//   <o>Timer Thread Priority
+//                        <1=> Low
+//                        <2=> Below Normal
+//                        <3=> Normal
+//                        <4=> Above Normal
+//                        <5=> High
+//                        <6=> Realtime (highest)
+//   <i> Defines priority for Timer Thread
+//   <i> Default: High
+#ifndef OS_TIMERPRIO
+ #define OS_TIMERPRIO   5
+#endif
+
+//   <o>Timer Callback Queue size <1-32>
+//   <i> Number of concurrent active timer callback functions.
+//   <i> Default: 4
+#ifndef OS_TIMERCBQSZ
+ #define OS_TIMERCBQS   4
+#endif
+
+// </e>
+
+//   <o>ISR FIFO Queue size<4=>   4 entries  <8=>   8 entries
+//                         <12=> 12 entries  <16=> 16 entries
+//                         <24=> 24 entries  <32=> 32 entries
+//                         <48=> 48 entries  <64=> 64 entries
+//                         <96=> 96 entries
+//   <i> ISR functions store requests to this buffer,
+//   <i> when they are called from the interrupt handler.
+//   <i> Default: 16 entries
+#ifndef OS_FIFOSZ
+ #define OS_FIFOSZ      16
+#endif
+
+// </h>
+
+//------------- <<< end of configuration section >>> -----------------------
+
+// Standard library system mutexes
+// ===============================
+//  Define max. number system mutexes that are used to protect 
+//  the arm standard runtime library. For microlib they are not used.
+#ifndef OS_MUTEXCNT
+ #define OS_MUTEXCNT    12
+#endif
+
+/*----------------------------------------------------------------------------
+ *      RTX User configuration part END
+ *---------------------------------------------------------------------------*/
+
+#define OS_TRV          ((uint32_t)(((double)OS_CLOCK*(double)OS_TICK)/1E6)-1)
+
+
+/*----------------------------------------------------------------------------
+ *      OS Idle daemon
+ *---------------------------------------------------------------------------*/
+void os_idle_demon (void) {
+  /* The idle demon is a system thread, running when no other thread is      */
+  /* ready to run.                                                           */
+  
+  /* Sleep: ideally, we should put the chip to sleep.
+     Unfortunately, this usually requires disconnecting the interface chip (debugger).
+     This can be done, but it would break the local file system.
+  */
+  for (;;) {
+      // sleep();
+  }
+}
+
+/*----------------------------------------------------------------------------
+ *      RTX Errors
+ *---------------------------------------------------------------------------*/
+extern void mbed_die(void);
+
+void os_error (uint32_t err_code) {
+    /* This function is called when a runtime error is detected. Parameter     */
+    /* 'err_code' holds the runtime error code (defined in RTX_Config.h).      */
+    mbed_die();
+}
+
+void sysThreadError(osStatus status) {
+    if (status != osOK) {
+        mbed_die();
+    }
+}
+
+/*----------------------------------------------------------------------------
+ *      RTX Configuration Functions
+ *---------------------------------------------------------------------------*/
+
+#include "RTX_CM_lib.h"
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/RTX_Config.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,72 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    RTX_CONFIG.H
+ *      Purpose: Exported functions of RTX_Config.c
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+
+/* Error Codes */
+#define OS_ERR_STK_OVF          1
+#define OS_ERR_FIFO_OVF         2
+#define OS_ERR_MBX_OVF          3
+
+/* Definitions */
+#define BOX_ALIGN_8                   0x80000000
+#define _declare_box(pool,size,cnt)   U32 pool[(((size)+3)/4)*(cnt) + 3]
+#define _declare_box8(pool,size,cnt)  U64 pool[(((size)+7)/8)*(cnt) + 2]
+#define _init_box8(pool,size,bsize)   _init_box (pool,size,(bsize) | BOX_ALIGN_8)
+
+/* Variables */
+extern U32 idle_task_stack[];
+extern U32 os_fifo[];
+extern void *os_active_TCB[];
+
+/* Constants */
+extern U16 const os_maxtaskrun;
+extern U32 const os_trv;
+extern U8  const os_flags;
+extern U32 const os_rrobin;
+extern U32 const os_clockrate;
+extern U32 const os_timernum;
+extern U16 const idle_task_stack_size;
+
+extern U8  const os_fifo_size;
+
+/* Functions */
+extern void os_idle_demon   (void);
+extern int  os_tick_init    (void);
+extern void os_tick_irqack  (void);
+extern void os_tmr_call     (U16  info);
+extern void os_error        (U32 err_code);
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/cmsis_os.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,774 @@
+/* ----------------------------------------------------------------------  
+ * Copyright (C) 2012 ARM Limited. All rights reserved.  
+ *  
+ * $Date:        5. June 2012
+ * $Revision:    V1.01
+ *  
+ * Project:      CMSIS-RTOS API
+ * Title:        cmsis_os.h RTX header file
+ *  
+ * Version 0.02
+ *    Initial Proposal Phase 
+ * Version 0.03
+ *    osKernelStart added, optional feature: main started as thread
+ *    osSemaphores have standard behavior
+ *    osTimerCreate does not start the timer, added osTimerStart
+ *    osThreadPass is renamed to osThreadYield
+ * Version 1.01
+ *    Support for C++ interface
+ *     - const attribute removed from the osXxxxDef_t typedef's 
+ *     - const attribute added to the osXxxxDef macros
+ *    Added: osTimerDelete, osMutexDelete, osSemaphoreDelete
+ *    Added: osKernelInitialize
+ * -------------------------------------------------------------------- */ 
+
+/**
+\page cmsis_os_h Header File Template: cmsis_os.h
+
+The file \b cmsis_os.h is a template header file for a CMSIS-RTOS compliant Real-Time Operating System (RTOS).
+Each RTOS that is compliant with CMSIS-RTOS shall provide a specific \b cmsis_os.h header file that represents
+its implementation.
+
+The file cmsis_os.h contains:
+ - CMSIS-RTOS API function definitions
+ - struct definitions for parameters and return types
+ - status and priority values used by CMSIS-RTOS API functions
+ - macros for defining threads and other kernel objects
+
+
+<b>Name conventions and header file modifications</b>
+
+All definitions are prefixed with \b os to give an unique name space for CMSIS-RTOS functions.
+Definitions that are prefixed \b os_ are not used in the application code but local to this header file.
+All definitions and functions that belong to a module are grouped and have a common prefix, i.e. \b osThread.
+ 
+Definitions that are marked with <b>CAN BE CHANGED</b> can be adapted towards the needs of the actual CMSIS-RTOS implementation. 
+These definitions can be specific to the underlying RTOS kernel.
+
+Definitions that are marked with <b>MUST REMAIN UNCHANGED</b> cannot be altered. Otherwise the CMSIS-RTOS implementation is no longer
+compliant to the standard. Note that some functions are optional and need not to be provided by every CMSIS-RTOS implementation.
+
+
+<b>Function calls from interrupt service routines</b>
+
+The following CMSIS-RTOS functions can be called from threads and interrupt service routines (ISR):
+  - \ref osSignalSet
+  - \ref osSemaphoreRelease
+  - \ref osPoolAlloc, \ref osPoolCAlloc, \ref osPoolFree
+  - \ref osMessagePut, \ref osMessageGet
+  - \ref osMailAlloc, \ref osMailCAlloc, \ref osMailGet, \ref osMailPut, \ref osMailFree
+
+Functions that cannot be called from an ISR are verifying the interrupt status and return in case that they are called 
+from an ISR context the status code \b osErrorISR. In some implementations this condition might be caught using the HARD FAULT vector.
+
+Some CMSIS-RTOS implementations support CMSIS-RTOS function calls from multiple ISR at the same time.
+If this is impossible, the CMSIS-RTOS rejects calls by nested ISR functions with the status code \b osErrorISRRecursive.
+
+
+<b>Define and reference object definitions</b>
+
+With <b>\#define osObjectsExternal</b> objects are defined as external symbols. This allows to create a consistent header file
+that is used throughout a project as shown below:
+
+<i>Header File</i>
+\code
+#include <cmsis_os.h>                                         // CMSIS RTOS header file
+
+// Thread definition
+extern void thread_sample (void const *argument);             // function prototype
+osThreadDef (thread_sample, osPriorityBelowNormal, 1, 100);
+
+// Pool definition
+osPoolDef(MyPool, 10, long);                      
+\endcode
+
+
+This header file defines all objects when included in a C/C++ source file. When <b>\#define osObjectsExternal</b> is 
+present before the header file, the objects are defined as external symbols. A single consistent header file can therefore be
+used throughout the whole project.
+
+<i>Example</i>
+\code
+#include "osObjects.h"     // Definition of the CMSIS-RTOS objects
+\endcode
+
+\code
+#define osObjectExternal   // Objects will be defined as external symbols
+#include "osObjects.h"     // Reference to the CMSIS-RTOS objects
+\endcode
+
+*/
+ 
+#ifndef _CMSIS_OS_H
+#define _CMSIS_OS_H
+
+/// \note MUST REMAIN UNCHANGED: \b osCMSIS identifies the CMSIS-RTOS API version.
+#define osCMSIS           0x10001      ///< API version (main [31:16] .sub [15:0])
+
+/// \note CAN BE CHANGED: \b osCMSIS_KERNEL identifies the underlying RTOS kernel and version number.
+#define osCMSIS_RTX     ((4<<16)|61)   ///< RTOS identification and version (main [31:16] .sub [15:0])
+
+/// \note MUST REMAIN UNCHANGED: \b osKernelSystemId shall be consistent in every CMSIS-RTOS.
+#define osKernelSystemId "RTX V4.61"   ///< RTOS identification string
+
+
+#define CMSIS_OS_RTX
+
+// The stack space occupied is mainly dependent on the underling C standard library
+#if defined(TOOLCHAIN_GCC_ARM) || defined(TOOLCHAIN_CS_ARM) || defined(TOOLCHAIN_CR_ARM)
+#    define WORDS_STACK_SIZE   512
+#elif defined(TOOLCHAIN_ARM)
+#    define WORDS_STACK_SIZE   512
+#elif defined(TOOLCHAIN_uARM)
+#    define WORDS_STACK_SIZE   128
+#endif
+
+#define DEFAULT_STACK_SIZE         (WORDS_STACK_SIZE*4)
+
+
+/// \note MUST REMAIN UNCHANGED: \b osFeature_xxx shall be consistent in every CMSIS-RTOS.
+#define osFeature_MainThread   1       ///< main thread      1=main can be thread, 0=not available
+#define osFeature_Pool         1       ///< Memory Pools:    1=available, 0=not available
+#define osFeature_MailQ        1       ///< Mail Queues:     1=available, 0=not available
+#define osFeature_MessageQ     1       ///< Message Queues:  1=available, 0=not available
+#define osFeature_Signals      16      ///< maximum number of Signal Flags available per thread
+#define osFeature_Semaphore    65535   ///< maximum count for \ref osSemaphoreCreate function
+#define osFeature_Wait         0       ///< osWait function: 1=available, 0=not available
+
+#if defined (__CC_ARM)
+#define os_InRegs __value_in_regs      // Compiler specific: force struct in registers
+#else
+#define os_InRegs
+#endif
+
+#include <stdint.h>
+#include <stddef.h>
+
+#ifdef  __cplusplus
+extern "C"
+{
+#endif
+
+#include "os_tcb.h"
+
+// ==== Enumeration, structures, defines ====
+
+/// Priority used for thread control.
+/// \note MUST REMAIN UNCHANGED: \b osPriority shall be consistent in every CMSIS-RTOS.
+typedef enum  {
+  osPriorityIdle          = -3,          ///< priority: idle (lowest)
+  osPriorityLow           = -2,          ///< priority: low
+  osPriorityBelowNormal   = -1,          ///< priority: below normal
+  osPriorityNormal        =  0,          ///< priority: normal (default)
+  osPriorityAboveNormal   = +1,          ///< priority: above normal
+  osPriorityHigh          = +2,          ///< priority: high 
+  osPriorityRealtime      = +3,          ///< priority: realtime (highest)
+  osPriorityError         =  0x84        ///< system cannot determine priority or thread has illegal priority
+} osPriority;
+
+/// Timeout value.
+/// \note MUST REMAIN UNCHANGED: \b osWaitForever shall be consistent in every CMSIS-RTOS.
+#define osWaitForever     0xFFFFFFFF     ///< wait forever timeout value
+
+/// Status code values returned by CMSIS-RTOS functions.
+/// \note MUST REMAIN UNCHANGED: \b osStatus shall be consistent in every CMSIS-RTOS.
+typedef enum  {
+  osOK                    =     0,       ///< function completed; no error or event occurred.
+  osEventSignal           =  0x08,       ///< function completed; signal event occurred.
+  osEventMessage          =  0x10,       ///< function completed; message event occurred.
+  osEventMail             =  0x20,       ///< function completed; mail event occurred.
+  osEventTimeout          =  0x40,       ///< function completed; timeout occurred.
+  osErrorParameter        =  0x80,       ///< parameter error: a mandatory parameter was missing or specified an incorrect object.
+  osErrorResource         =  0x81,       ///< resource not available: a specified resource was not available.
+  osErrorTimeoutResource  =  0xC1,       ///< resource not available within given time: a specified resource was not available within the timeout period.
+  osErrorISR              =  0x82,       ///< not allowed in ISR context: the function cannot be called from interrupt service routines.
+  osErrorISRRecursive     =  0x83,       ///< function called multiple times from ISR with same object.
+  osErrorPriority         =  0x84,       ///< system cannot determine priority or thread has illegal priority.
+  osErrorNoMemory         =  0x85,       ///< system is out of memory: it was impossible to allocate or reserve memory for the operation.
+  osErrorValue            =  0x86,       ///< value of a parameter is out of range.
+  osErrorOS               =  0xFF,       ///< unspecified RTOS error: run-time error but no other error message fits.
+  os_status_reserved      =  0x7FFFFFFF  ///< prevent from enum down-size compiler optimization.
+} osStatus; 
+
+
+/// Timer type value for the timer definition.
+/// \note MUST REMAIN UNCHANGED: \b os_timer_type shall be consistent in every CMSIS-RTOS.
+typedef enum  {
+  osTimerOnce             =     0,       ///< one-shot timer 
+  osTimerPeriodic         =     1        ///< repeating timer 
+} os_timer_type; 
+
+/// Entry point of a thread.
+/// \note MUST REMAIN UNCHANGED: \b os_pthread shall be consistent in every CMSIS-RTOS.
+typedef void (*os_pthread) (void const *argument); 
+
+/// Entry point of a timer call back function.
+/// \note MUST REMAIN UNCHANGED: \b os_ptimer shall be consistent in every CMSIS-RTOS.
+typedef void (*os_ptimer) (void const *argument); 
+
+// >>> the following data type definitions may shall adapted towards a specific RTOS
+
+/// Thread ID identifies the thread (pointer to a thread control block).
+/// \note CAN BE CHANGED: \b os_thread_cb is implementation specific in every CMSIS-RTOS.
+typedef struct os_thread_cb *osThreadId;
+
+/// Timer ID identifies the timer (pointer to a timer control block).
+/// \note CAN BE CHANGED: \b os_timer_cb is implementation specific in every CMSIS-RTOS.
+typedef struct os_timer_cb *osTimerId;
+
+/// Mutex ID identifies the mutex (pointer to a mutex control block).
+/// \note CAN BE CHANGED: \b os_mutex_cb is implementation specific in every CMSIS-RTOS.
+typedef struct os_mutex_cb *osMutexId;
+
+/// Semaphore ID identifies the semaphore (pointer to a semaphore control block).
+/// \note CAN BE CHANGED: \b os_semaphore_cb is implementation specific in every CMSIS-RTOS.
+typedef struct os_semaphore_cb *osSemaphoreId;
+
+/// Pool ID identifies the memory pool (pointer to a memory pool control block).
+/// \note CAN BE CHANGED: \b os_pool_cb is implementation specific in every CMSIS-RTOS.
+typedef struct os_pool_cb *osPoolId;
+
+/// Message ID identifies the message queue (pointer to a message queue control block).
+/// \note CAN BE CHANGED: \b os_messageQ_cb is implementation specific in every CMSIS-RTOS.
+typedef struct os_messageQ_cb *osMessageQId;
+
+/// Mail ID identifies the mail queue (pointer to a mail queue control block).
+/// \note CAN BE CHANGED: \b os_mailQ_cb is implementation specific in every CMSIS-RTOS.
+typedef struct os_mailQ_cb *osMailQId;
+
+
+/// Thread Definition structure contains startup information of a thread.
+/// \note CAN BE CHANGED: \b os_thread_def is implementation specific in every CMSIS-RTOS.
+typedef struct os_thread_def  {
+  os_pthread               pthread;      ///< start address of thread function
+  osPriority             tpriority;      ///< initial thread priority
+  uint32_t               stacksize;      ///< stack size requirements in bytes
+  unsigned char         *stack_pointer;  ///< pointer to the stack memory block
+  struct OS_TCB          tcb;
+} osThreadDef_t;
+
+/// Timer Definition structure contains timer parameters.
+/// \note CAN BE CHANGED: \b os_timer_def is implementation specific in every CMSIS-RTOS.
+typedef struct os_timer_def  {
+  os_ptimer                 ptimer;    ///< start address of a timer function
+  void                      *timer;    ///< pointer to internal data
+} osTimerDef_t;
+
+/// Mutex Definition structure contains setup information for a mutex.
+/// \note CAN BE CHANGED: \b os_mutex_def is implementation specific in every CMSIS-RTOS.
+typedef struct os_mutex_def  {
+  void                      *mutex;    ///< pointer to internal data
+} osMutexDef_t;
+
+/// Semaphore Definition structure contains setup information for a semaphore.
+/// \note CAN BE CHANGED: \b os_semaphore_def is implementation specific in every CMSIS-RTOS.
+typedef struct os_semaphore_def  {
+  void                  *semaphore;    ///< pointer to internal data
+} osSemaphoreDef_t;
+
+/// Definition structure for memory block allocation.
+/// \note CAN BE CHANGED: \b os_pool_def is implementation specific in every CMSIS-RTOS.
+typedef struct os_pool_def  {
+  uint32_t                 pool_sz;    ///< number of items (elements) in the pool
+  uint32_t                 item_sz;    ///< size of an item 
+  void                       *pool;    ///< pointer to memory for pool
+} osPoolDef_t;
+
+/// Definition structure for message queue.
+/// \note CAN BE CHANGED: \b os_messageQ_def is implementation specific in every CMSIS-RTOS.
+typedef struct os_messageQ_def  {
+  uint32_t                queue_sz;    ///< number of elements in the queue
+  void                       *pool;    ///< memory array for messages
+} osMessageQDef_t;
+
+/// Definition structure for mail queue.
+/// \note CAN BE CHANGED: \b os_mailQ_def is implementation specific in every CMSIS-RTOS.
+typedef struct os_mailQ_def  {
+  uint32_t                queue_sz;    ///< number of elements in the queue
+  uint32_t                 item_sz;    ///< size of an item 
+  void                       *pool;    ///< memory array for mail
+} osMailQDef_t;
+
+/// Event structure contains detailed information about an event. 
+/// \note MUST REMAIN UNCHANGED: \b os_event shall be consistent in every CMSIS-RTOS. 
+///       However the struct may be extended at the end.
+typedef struct  {
+  osStatus                 status;     ///< status code: event or error information
+  union  {
+    uint32_t                    v;     ///< message as 32-bit value 
+    void                       *p;     ///< message or mail as void pointer
+    int32_t               signals;     ///< signal flags 
+  } value;                             ///< event value
+  union  {
+    osMailQId             mail_id;     ///< mail id obtained by \ref osMailCreate 
+    osMessageQId       message_id;     ///< message id obtained by \ref osMessageCreate 
+  } def;                               ///< event definition
+} osEvent;
+
+
+//  ==== Kernel Control Functions ====
+
+/// Initialize the RTOS Kernel for creating objects.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osKernelInitialize shall be consistent in every CMSIS-RTOS. 
+osStatus osKernelInitialize (void);
+
+/// Start the RTOS Kernel.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osKernelStart shall be consistent in every CMSIS-RTOS. 
+osStatus osKernelStart (void);
+
+/// Check if the RTOS kernel is already started.
+/// \note MUST REMAIN UNCHANGED: \b osKernelRunning shall be consistent in every CMSIS-RTOS. 
+/// \return 0 RTOS is not started, 1 RTOS is started.
+int32_t osKernelRunning(void);
+
+
+//  ==== Thread Management ====
+
+/// Create a Thread Definition with function, priority, and stack requirements.
+/// \param         name         name of the thread function.
+/// \param         priority     initial priority of the thread function.
+/// \param         stacksz      stack size (in bytes) requirements for the thread function.
+/// \note CAN BE CHANGED: The parameters to \b osThreadDef shall be consistent but the 
+///       macro body is implementation specific in every CMSIS-RTOS.
+#if defined (osObjectsExternal)  // object is external
+#define osThreadDef(name, priority, stacksz)  \
+extern osThreadDef_t os_thread_def_##name
+#else                            // define the object
+#define osThreadDef(name, priority, stacksz)  \
+unsigned char os_thread_def_stack_##name [stacksz]; \
+osThreadDef_t os_thread_def_##name = \
+{ (name), (priority), (stacksz), (os_thread_def_stack_##name)}
+#endif
+
+/// Access a Thread definition.
+/// \param         name          name of the thread definition object.
+/// \note CAN BE CHANGED: The parameter to \b osThread shall be consistent but the 
+///       macro body is implementation specific in every CMSIS-RTOS.
+#define osThread(name)  \
+&os_thread_def_##name
+
+/// Create a thread and add it to Active Threads and set it to state READY.
+/// \param[in]     thread_def    thread definition referenced with \ref osThread.
+/// \param[in]     argument      pointer that is passed to the thread function as start argument.
+/// \return thread ID for reference by other functions or NULL in case of error.
+/// \note MUST REMAIN UNCHANGED: \b osThreadCreate shall be consistent in every CMSIS-RTOS.
+osThreadId osThreadCreate (osThreadDef_t *thread_def, void *argument);
+
+/// Return the thread ID of the current running thread.
+/// \return thread ID for reference by other functions or NULL in case of error.
+/// \note MUST REMAIN UNCHANGED: \b osThreadGetId shall be consistent in every CMSIS-RTOS.
+osThreadId osThreadGetId (void);
+
+/// Terminate execution of a thread and remove it from Active Threads.
+/// \param[in]     thread_id   thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osThreadTerminate shall be consistent in every CMSIS-RTOS.
+osStatus osThreadTerminate (osThreadId thread_id);
+
+/// Pass control to next thread that is in state \b READY.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osThreadYield shall be consistent in every CMSIS-RTOS.
+osStatus osThreadYield (void);
+
+/// Change priority of an active thread.  
+/// \param[in]     thread_id     thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
+/// \param[in]     priority      new priority value for the thread function.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osThreadSetPriority shall be consistent in every CMSIS-RTOS.
+osStatus osThreadSetPriority (osThreadId thread_id, osPriority priority);
+
+/// Get current priority of an active thread.
+/// \param[in]     thread_id     thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
+/// \return current priority value of the thread function.
+/// \note MUST REMAIN UNCHANGED: \b osThreadGetPriority shall be consistent in every CMSIS-RTOS.
+osPriority osThreadGetPriority (osThreadId thread_id);
+
+
+//  ==== Generic Wait Functions ====
+
+/// Wait for Timeout (Time Delay).
+/// \param[in]     millisec      time delay value 
+/// \return status code that indicates the execution status of the function.
+osStatus osDelay (uint32_t millisec);
+
+#if (defined (osFeature_Wait)  &&  (osFeature_Wait != 0))     // Generic Wait available
+
+/// Wait for Signal, Message, Mail, or Timeout.
+/// \param[in] millisec          timeout value or 0 in case of no time-out
+/// \return event that contains signal, message, or mail information or error code.
+/// \note MUST REMAIN UNCHANGED: \b osWait shall be consistent in every CMSIS-RTOS.
+os_InRegs osEvent osWait (uint32_t millisec);
+
+#endif  // Generic Wait available
+
+
+//  ==== Timer Management Functions ====
+/// Define a Timer object.
+/// \param         name          name of the timer object.
+/// \param         function      name of the timer call back function.
+/// \note CAN BE CHANGED: The parameter to \b osTimerDef shall be consistent but the 
+///       macro body is implementation specific in every CMSIS-RTOS.
+#if defined (osObjectsExternal)  // object is external
+#define osTimerDef(name, function)  \
+extern osTimerDef_t os_timer_def_##name
+#else                            // define the object
+#define osTimerDef(name, function)  \
+uint32_t os_timer_cb_##name[5]; \
+osTimerDef_t os_timer_def_##name = \
+{ (function), (os_timer_cb_##name) }
+#endif
+
+/// Access a Timer definition.
+/// \param         name          name of the timer object.
+/// \note CAN BE CHANGED: The parameter to \b osTimer shall be consistent but the 
+///       macro body is implementation specific in every CMSIS-RTOS.
+#define osTimer(name) \
+&os_timer_def_##name
+
+/// Create a timer.
+/// \param[in]     timer_def     timer object referenced with \ref osTimer.
+/// \param[in]     type          osTimerOnce for one-shot or osTimerPeriodic for periodic behavior.
+/// \param[in]     argument      argument to the timer call back function.
+/// \return timer ID for reference by other functions or NULL in case of error.
+/// \note MUST REMAIN UNCHANGED: \b osTimerCreate shall be consistent in every CMSIS-RTOS.
+osTimerId osTimerCreate (osTimerDef_t *timer_def, os_timer_type type, void *argument);
+
+/// Start or restart a timer.
+/// \param[in]     timer_id      timer ID obtained by \ref osTimerCreate.
+/// \param[in]     millisec      time delay value of the timer.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osTimerStart shall be consistent in every CMSIS-RTOS.
+osStatus osTimerStart (osTimerId timer_id, uint32_t millisec);
+
+/// Stop the timer.
+/// \param[in]     timer_id      timer ID obtained by \ref osTimerCreate.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osTimerStop shall be consistent in every CMSIS-RTOS.
+osStatus osTimerStop (osTimerId timer_id);
+
+/// Delete a timer that was created by \ref osTimerCreate.
+/// \param[in]     timer_id      timer ID obtained by \ref osTimerCreate.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osTimerDelete shall be consistent in every CMSIS-RTOS.
+osStatus osTimerDelete (osTimerId timer_id);
+
+
+//  ==== Signal Management ====
+
+/// Set the specified Signal Flags of an active thread.
+/// \param[in]     thread_id     thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
+/// \param[in]     signals       specifies the signal flags of the thread that should be set.
+/// \return previous signal flags of the specified thread or 0x80000000 in case of incorrect parameters.
+/// \note MUST REMAIN UNCHANGED: \b osSignalSet shall be consistent in every CMSIS-RTOS.
+int32_t osSignalSet (osThreadId thread_id, int32_t signals);
+
+/// Clear the specified Signal Flags of an active thread.
+/// \param[in]     thread_id     thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
+/// \param[in]     signals       specifies the signal flags of the thread that shall be cleared.
+/// \return previous signal flags of the specified thread or 0x80000000 in case of incorrect parameters.
+/// \note MUST REMAIN UNCHANGED: \b osSignalClear shall be consistent in every CMSIS-RTOS.
+int32_t osSignalClear (osThreadId thread_id, int32_t signals);
+
+/// Get Signal Flags status of an active thread.
+/// \param[in]     thread_id     thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
+/// \return previous signal flags of the specified thread or 0x80000000 in case of incorrect parameters.
+/// \note MUST REMAIN UNCHANGED: \b osSignalGet shall be consistent in every CMSIS-RTOS.
+int32_t osSignalGet (osThreadId thread_id);
+
+/// Wait for one or more Signal Flags to become signaled for the current \b RUNNING thread.
+/// \param[in]     signals       wait until all specified signal flags set or 0 for any single signal flag.
+/// \param[in]     millisec      timeout value or 0 in case of no time-out.
+/// \return event flag information or error code.
+/// \note MUST REMAIN UNCHANGED: \b osSignalWait shall be consistent in every CMSIS-RTOS.
+os_InRegs osEvent osSignalWait (int32_t signals, uint32_t millisec);
+
+
+//  ==== Mutex Management ====
+
+/// Define a Mutex.
+/// \param         name          name of the mutex object.
+/// \note CAN BE CHANGED: The parameter to \b osMutexDef shall be consistent but the 
+///       macro body is implementation specific in every CMSIS-RTOS.
+#if defined (osObjectsExternal)  // object is external
+#define osMutexDef(name)  \
+extern osMutexDef_t os_mutex_def_##name
+#else                            // define the object
+#define osMutexDef(name)  \
+uint32_t os_mutex_cb_##name[3]; \
+osMutexDef_t os_mutex_def_##name = { (os_mutex_cb_##name) }
+#endif
+
+/// Access a Mutex definition.
+/// \param         name          name of the mutex object.
+/// \note CAN BE CHANGED: The parameter to \b osMutex shall be consistent but the 
+///       macro body is implementation specific in every CMSIS-RTOS.
+#define osMutex(name)  \
+&os_mutex_def_##name
+
+/// Create and Initialize a Mutex object.
+/// \param[in]     mutex_def     mutex definition referenced with \ref osMutex.
+/// \return mutex ID for reference by other functions or NULL in case of error.
+/// \note MUST REMAIN UNCHANGED: \b osMutexCreate shall be consistent in every CMSIS-RTOS.
+osMutexId osMutexCreate (osMutexDef_t *mutex_def);
+
+/// Wait until a Mutex becomes available.
+/// \param[in]     mutex_id      mutex ID obtained by \ref osMutexCreate.
+/// \param[in]     millisec      timeout value or 0 in case of no time-out.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osMutexWait shall be consistent in every CMSIS-RTOS.
+osStatus osMutexWait (osMutexId mutex_id, uint32_t millisec);
+
+/// Release a Mutex that was obtained by \ref osMutexWait.
+/// \param[in]     mutex_id      mutex ID obtained by \ref osMutexCreate.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osMutexRelease shall be consistent in every CMSIS-RTOS.
+osStatus osMutexRelease (osMutexId mutex_id);
+
+/// Delete a Mutex that was created by \ref osMutexCreate.
+/// \param[in]     mutex_id      mutex ID obtained by \ref osMutexCreate.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osMutexDelete shall be consistent in every CMSIS-RTOS.
+osStatus osMutexDelete (osMutexId mutex_id);
+
+
+//  ==== Semaphore Management Functions ====
+
+#if (defined (osFeature_Semaphore)  &&  (osFeature_Semaphore != 0))     // Semaphore available
+
+/// Define a Semaphore object.
+/// \param         name          name of the semaphore object.
+/// \note CAN BE CHANGED: The parameter to \b osSemaphoreDef shall be consistent but the 
+///       macro body is implementation specific in every CMSIS-RTOS.
+#if defined (osObjectsExternal)  // object is external
+#define osSemaphoreDef(name)  \
+extern osSemaphoreDef_t os_semaphore_def_##name
+#else                            // define the object
+#define osSemaphoreDef(name)  \
+uint32_t os_semaphore_cb_##name[2]; \
+osSemaphoreDef_t os_semaphore_def_##name = { (os_semaphore_cb_##name) }
+#endif
+
+/// Access a Semaphore definition.
+/// \param         name          name of the semaphore object.
+/// \note CAN BE CHANGED: The parameter to \b osSemaphore shall be consistent but the 
+///       macro body is implementation specific in every CMSIS-RTOS.
+#define osSemaphore(name)  \
+&os_semaphore_def_##name
+
+/// Create and Initialize a Semaphore object used for managing resources.
+/// \param[in]     semaphore_def semaphore definition referenced with \ref osSemaphore.
+/// \param[in]     count         number of available resources.
+/// \return semaphore ID for reference by other functions or NULL in case of error.
+/// \note MUST REMAIN UNCHANGED: \b osSemaphoreCreate shall be consistent in every CMSIS-RTOS.
+osSemaphoreId osSemaphoreCreate (osSemaphoreDef_t *semaphore_def, int32_t count);
+
+/// Wait until a Semaphore token becomes available.
+/// \param[in]     semaphore_id  semaphore object referenced with \ref osSemaphoreCreate.
+/// \param[in]     millisec      timeout value or 0 in case of no time-out.
+/// \return number of available tokens, or -1 in case of incorrect parameters.
+/// \note MUST REMAIN UNCHANGED: \b osSemaphoreWait shall be consistent in every CMSIS-RTOS.
+int32_t osSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec);
+
+/// Release a Semaphore token.
+/// \param[in]     semaphore_id  semaphore object referenced with \ref osSemaphoreCreate.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osSemaphoreRelease shall be consistent in every CMSIS-RTOS.
+osStatus osSemaphoreRelease (osSemaphoreId semaphore_id);
+
+/// Delete a Semaphore that was created by \ref osSemaphoreCreate.
+/// \param[in]     semaphore_id  semaphore object referenced with \ref osSemaphoreCreate.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osSemaphoreDelete shall be consistent in every CMSIS-RTOS.
+osStatus osSemaphoreDelete (osSemaphoreId semaphore_id);
+
+#endif     // Semaphore available
+
+ 
+//  ==== Memory Pool Management Functions ====
+
+#if (defined (osFeature_Pool)  &&  (osFeature_Pool != 0))  // Memory Pool Management available
+
+/// \brief Define a Memory Pool.
+/// \param         name          name of the memory pool.
+/// \param         no            maximum number of blocks (objects) in the memory pool.
+/// \param         type          data type of a single block (object).
+/// \note CAN BE CHANGED: The parameter to \b osPoolDef shall be consistent but the 
+///       macro body is implementation specific in every CMSIS-RTOS.
+#if defined (osObjectsExternal)  // object is external
+#define osPoolDef(name, no, type)   \
+extern osPoolDef_t os_pool_def_##name
+#else                            // define the object
+#define osPoolDef(name, no, type)   \
+uint32_t os_pool_m_##name[3+((sizeof(type)+3)/4)*(no)]; \
+osPoolDef_t os_pool_def_##name = \
+{ (no), sizeof(type), (os_pool_m_##name) }
+#endif
+
+/// \brief Access a Memory Pool definition.
+/// \param         name          name of the memory pool
+/// \note CAN BE CHANGED: The parameter to \b osPool shall be consistent but the 
+///       macro body is implementation specific in every CMSIS-RTOS.
+#define osPool(name) \
+&os_pool_def_##name
+
+/// Create and Initialize a memory pool.
+/// \param[in]     pool_def      memory pool definition referenced with \ref osPool.
+/// \return memory pool ID for reference by other functions or NULL in case of error.
+/// \note MUST REMAIN UNCHANGED: \b osPoolCreate shall be consistent in every CMSIS-RTOS.
+osPoolId osPoolCreate (osPoolDef_t *pool_def);
+
+/// Allocate a memory block from a memory pool.
+/// \param[in]     pool_id       memory pool ID obtain referenced with \ref osPoolCreate.
+/// \return address of the allocated memory block or NULL in case of no memory available.
+/// \note MUST REMAIN UNCHANGED: \b osPoolAlloc shall be consistent in every CMSIS-RTOS.
+void *osPoolAlloc (osPoolId pool_id);
+
+/// Allocate a memory block from a memory pool and set memory block to zero.
+/// \param[in]     pool_id       memory pool ID obtain referenced with \ref osPoolCreate.
+/// \return address of the allocated memory block or NULL in case of no memory available.
+/// \note MUST REMAIN UNCHANGED: \b osPoolCAlloc shall be consistent in every CMSIS-RTOS.
+void *osPoolCAlloc (osPoolId pool_id);
+
+/// Return an allocated memory block back to a specific memory pool.
+/// \param[in]     pool_id       memory pool ID obtain referenced with \ref osPoolCreate.
+/// \param[in]     block         address of the allocated memory block that is returned to the memory pool.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osPoolFree shall be consistent in every CMSIS-RTOS.
+osStatus osPoolFree (osPoolId pool_id, void *block);
+
+#endif   // Memory Pool Management available
+
+
+//  ==== Message Queue Management Functions ====
+
+#if (defined (osFeature_MessageQ)  &&  (osFeature_MessageQ != 0))     // Message Queues available
+
+/// \brief Create a Message Queue Definition.
+/// \param         name          name of the queue.
+/// \param         queue_sz      maximum number of messages in the queue.
+/// \param         type          data type of a single message element (for debugger).
+/// \note CAN BE CHANGED: The parameter to \b osMessageQDef shall be consistent but the 
+///       macro body is implementation specific in every CMSIS-RTOS.
+#if defined (osObjectsExternal)  // object is external
+#define osMessageQDef(name, queue_sz, type)   \
+extern osMessageQDef_t os_messageQ_def_##name
+#else                            // define the object
+#define osMessageQDef(name, queue_sz, type)   \
+uint32_t os_messageQ_q_##name[4+(queue_sz)]; \
+osMessageQDef_t os_messageQ_def_##name = \
+{ (queue_sz), (os_messageQ_q_##name) }
+#endif
+
+/// \brief Access a Message Queue Definition.
+/// \param         name          name of the queue
+/// \note CAN BE CHANGED: The parameter to \b osMessageQ shall be consistent but the 
+///       macro body is implementation specific in every CMSIS-RTOS.
+#define osMessageQ(name) \
+&os_messageQ_def_##name
+
+/// Create and Initialize a Message Queue.
+/// \param[in]     queue_def     queue definition referenced with \ref osMessageQ.
+/// \param[in]     thread_id     thread ID (obtained by \ref osThreadCreate or \ref osThreadGetId) or NULL.
+/// \return message queue ID for reference by other functions or NULL in case of error.
+/// \note MUST REMAIN UNCHANGED: \b osMessageCreate shall be consistent in every CMSIS-RTOS.
+osMessageQId osMessageCreate (osMessageQDef_t *queue_def, osThreadId thread_id);
+
+/// Put a Message to a Queue.
+/// \param[in]     queue_id      message queue ID obtained with \ref osMessageCreate.
+/// \param[in]     info          message information.
+/// \param[in]     millisec      timeout value or 0 in case of no time-out.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osMessagePut shall be consistent in every CMSIS-RTOS.
+osStatus osMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec);
+
+/// Get a Message or Wait for a Message from a Queue.
+/// \param[in]     queue_id      message queue ID obtained with \ref osMessageCreate.
+/// \param[in]     millisec      timeout value or 0 in case of no time-out.
+/// \return event information that includes status code.
+/// \note MUST REMAIN UNCHANGED: \b osMessageGet shall be consistent in every CMSIS-RTOS.
+os_InRegs osEvent osMessageGet (osMessageQId queue_id, uint32_t millisec);
+
+#endif     // Message Queues available
+
+
+//  ==== Mail Queue Management Functions ====
+
+#if (defined (osFeature_MailQ)  &&  (osFeature_MailQ != 0))     // Mail Queues available
+
+/// \brief Create a Mail Queue Definition.
+/// \param         name          name of the queue
+/// \param         queue_sz      maximum number of messages in queue
+/// \param         type          data type of a single message element
+/// \note CAN BE CHANGED: The parameter to \b osMailQDef shall be consistent but the 
+///       macro body is implementation specific in every CMSIS-RTOS.
+#if defined (osObjectsExternal)  // object is external
+#define osMailQDef(name, queue_sz, type) \
+extern osMailQDef_t os_mailQ_def_##name
+#else                            // define the object
+#define osMailQDef(name, queue_sz, type) \
+uint32_t os_mailQ_q_##name[4+(queue_sz)]; \
+uint32_t os_mailQ_m_##name[3+((sizeof(type)+3)/4)*(queue_sz)]; \
+void *   os_mailQ_p_##name[2] = { (os_mailQ_q_##name), os_mailQ_m_##name }; \
+osMailQDef_t os_mailQ_def_##name =  \
+{ (queue_sz), sizeof(type), (os_mailQ_p_##name) }
+#endif
+     
+/// \brief Access a Mail Queue Definition.
+/// \param         name          name of the queue
+/// \note CAN BE CHANGED: The parameter to \b osMailQ shall be consistent but the 
+///       macro body is implementation specific in every CMSIS-RTOS.
+#define osMailQ(name)  \
+&os_mailQ_def_##name
+
+/// Create and Initialize mail queue.
+/// \param[in]     queue_def     reference to the mail queue definition obtain with \ref osMailQ
+/// \param[in]     thread_id     thread ID (obtained by \ref osThreadCreate or \ref osThreadGetId) or NULL.
+/// \return mail queue ID for reference by other functions or NULL in case of error.
+/// \note MUST REMAIN UNCHANGED: \b osMailCreate shall be consistent in every CMSIS-RTOS.
+osMailQId osMailCreate (osMailQDef_t *queue_def, osThreadId thread_id);
+
+/// Allocate a memory block from a mail.
+/// \param[in]     queue_id      mail queue ID obtained with \ref osMailCreate.
+/// \param[in]     millisec      timeout value or 0 in case of no time-out
+/// \return pointer to memory block that can be filled with mail or NULL in case of error.
+/// \note MUST REMAIN UNCHANGED: \b osMailAlloc shall be consistent in every CMSIS-RTOS.
+void *osMailAlloc (osMailQId queue_id, uint32_t millisec);
+
+/// Allocate a memory block from a mail and set memory block to zero.
+/// \param[in]     queue_id      mail queue ID obtained with \ref osMailCreate.
+/// \param[in]     millisec      timeout value or 0 in case of no time-out
+/// \return pointer to memory block that can be filled with mail or NULL in case of error.
+/// \note MUST REMAIN UNCHANGED: \b osMailCAlloc shall be consistent in every CMSIS-RTOS.
+void *osMailCAlloc (osMailQId queue_id, uint32_t millisec);
+
+/// Put a mail to a queue.
+/// \param[in]     queue_id      mail queue ID obtained with \ref osMailCreate.
+/// \param[in]     mail          memory block previously allocated with \ref osMailAlloc or \ref osMailCAlloc.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osMailPut shall be consistent in every CMSIS-RTOS.
+osStatus osMailPut (osMailQId queue_id, void *mail);
+
+/// Get a mail from a queue.
+/// \param[in]     queue_id      mail queue ID obtained with \ref osMailCreate.
+/// \param[in]     millisec      timeout value or 0 in case of no time-out
+/// \return event that contains mail information or error code.
+/// \note MUST REMAIN UNCHANGED: \b osMailGet shall be consistent in every CMSIS-RTOS.
+os_InRegs osEvent osMailGet (osMailQId queue_id, uint32_t millisec);
+
+/// Free a memory block from a mail.
+/// \param[in]     queue_id      mail queue ID obtained with \ref osMailCreate.
+/// \param[in]     mail          pointer to the memory block that was obtained with \ref osMailGet.
+/// \return status code that indicates the execution status of the function.
+/// \note MUST REMAIN UNCHANGED: \b osMailFree shall be consistent in every CMSIS-RTOS.
+osStatus osMailFree (osMailQId queue_id, void *mail);
+                            
+#endif  // Mail Queues available
+
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif  // _CMSIS_OS_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/os_tcb.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,50 @@
+#ifndef OS_TCB_H
+#define OS_TCB_H
+
+/* Types */
+typedef char               S8;
+typedef unsigned char      U8;
+typedef short              S16;
+typedef unsigned short     U16;
+typedef int                S32;
+typedef unsigned int       U32;
+typedef long long          S64;
+typedef unsigned long long U64;
+typedef unsigned char      BIT;
+typedef unsigned int       BOOL;
+typedef void               (*FUNCP)(void);
+
+typedef struct OS_TCB {
+  /* General part: identical for all implementations.                        */
+  U8     cb_type;                 /* Control Block Type                      */
+  U8     state;                   /* Task state                              */
+  U8     prio;                    /* Execution priority                      */
+  U8     task_id;                 /* Task ID value for optimized TCB access  */
+  struct OS_TCB *p_lnk;           /* Link pointer for ready/sem. wait list   */
+  struct OS_TCB *p_rlnk;          /* Link pointer for sem./mbx lst backwards */
+  struct OS_TCB *p_dlnk;          /* Link pointer for delay list             */
+  struct OS_TCB *p_blnk;          /* Link pointer for delay list backwards   */
+  U16    delta_time;              /* Time until time out                     */
+  U16    interval_time;           /* Time interval for periodic waits        */
+  U16    events;                  /* Event flags                             */
+  U16    waits;                   /* Wait flags                              */
+  void   **msg;                   /* Direct message passing when task waits  */
+
+  /* Hardware dependant part: specific for CM processor                      */
+  U8     stack_frame;             /* Stack frame: 0=Basic, 1=Extended        */
+  U8     reserved;
+  U16    priv_stack;              /* Private stack size in bytes             */
+  U32    tsk_stack;               /* Current task Stack pointer (R13)        */
+  U32    *stack;                  /* Pointer to Task Stack memory block      */
+  
+  /* Library dependant part                                                   */
+#if defined (__CC_ARM) && !defined (__MICROLIB)
+ /* A memory space for arm standard library. */
+  U32 std_libspace[96/4];
+#endif
+  
+  /* Task entry point used for uVision debugger                              */
+  FUNCP  ptask;                   /* Task entry address                      */
+} *P_TCB;
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/rt_CMSIS.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,1918 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    rt_CMSIS.c
+ *      Purpose: CMSIS RTOS API
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#define __CMSIS_GENERIC
+
+#if defined (__CORTEX_M4) || defined (__CORTEX_M4F)
+  #include "core_cm4.h"
+#elif defined (__CORTEX_M3)
+  #include "core_cm3.h"
+#elif defined (__CORTEX_M0)
+  #include "core_cm0.h"
+#else
+  #error "Missing __CORTEX_Mx definition"
+#endif
+
+#include "rt_TypeDef.h"
+#include "RTX_Config.h"
+#include "rt_System.h"
+#include "rt_Task.h"
+#include "rt_Event.h"
+#include "rt_List.h"
+#include "rt_Time.h"
+#include "rt_Mutex.h"
+#include "rt_Semaphore.h"
+#include "rt_Mailbox.h"
+#include "rt_MemBox.h"
+#include "rt_HAL_CM.h"
+
+#define os_thread_cb OS_TCB
+
+#include "cmsis_os.h"
+
+#if (osFeature_Signals != 16)
+#error Invalid "osFeature_Signals" value!
+#endif
+#if (osFeature_Semaphore > 65535)
+#error Invalid "osFeature_Semaphore" value!
+#endif
+#if (osFeature_Wait != 0)
+#error osWait not supported!
+#endif
+
+
+// ==== Enumeration, structures, defines ====
+
+// Service Calls defines
+
+#if defined (__CC_ARM)          /* ARM Compiler */
+
+#define __NO_RETURN __declspec(noreturn)
+
+#define osEvent_type       osEvent
+#define osEvent_ret_status ret
+#define osEvent_ret_value  ret
+#define osEvent_ret_msg    ret
+#define osEvent_ret_mail   ret
+
+#define osCallback_type    osCallback
+#define osCallback_ret     ret
+
+#define SVC_0_1(f,t,...)                                                       \
+__svc_indirect(0) t  _##f (t(*)());                                            \
+                  t     f (void);                                              \
+__attribute__((always_inline))                                                 \
+static __inline   t __##f (void) {                                             \
+  return _##f(f);                                                              \
+}
+
+#define SVC_1_1(f,t,t1,...)                                                    \
+__svc_indirect(0) t  _##f (t(*)(t1),t1);                                       \
+                  t     f (t1 a1);                                             \
+__attribute__((always_inline))                                                 \
+static __inline   t __##f (t1 a1) {                                            \
+  return _##f(f,a1);                                                           \
+}
+
+#define SVC_2_1(f,t,t1,t2,...)                                                 \
+__svc_indirect(0) t  _##f (t(*)(t1,t2),t1,t2);                                 \
+                  t     f (t1 a1, t2 a2);                                      \
+__attribute__((always_inline))                                                 \
+static __inline   t __##f (t1 a1, t2 a2) {                                     \
+  return _##f(f,a1,a2);                                                        \
+}
+
+#define SVC_3_1(f,t,t1,t2,t3,...)                                              \
+__svc_indirect(0) t  _##f (t(*)(t1,t2,t3),t1,t2,t3);                           \
+                  t     f (t1 a1, t2 a2, t3 a3);                               \
+__attribute__((always_inline))                                                 \
+static __inline   t __##f (t1 a1, t2 a2, t3 a3) {                              \
+  return _##f(f,a1,a2,a3);                                                     \
+}
+
+#define SVC_4_1(f,t,t1,t2,t3,t4,...)                                           \
+__svc_indirect(0) t  _##f (t(*)(t1,t2,t3,t4),t1,t2,t3,t4);                     \
+                  t     f (t1 a1, t2 a2, t3 a3, t4 a4);                        \
+__attribute__((always_inline))                                                 \
+static __inline   t __##f (t1 a1, t2 a2, t3 a3, t4 a4) {                       \
+  return _##f(f,a1,a2,a3,a4);                                                  \
+}
+
+#define SVC_1_2 SVC_1_1 
+#define SVC_1_3 SVC_1_1 
+#define SVC_2_3 SVC_2_1 
+
+#elif defined (__GNUC__)        /* GNU Compiler */
+
+#define __NO_RETURN __attribute__((noreturn))
+
+typedef uint32_t __attribute__((vector_size(8)))  ret64;
+typedef uint32_t __attribute__((vector_size(16))) ret128;
+
+#define RET_pointer    __r0
+#define RET_int32_t    __r0
+#define RET_osStatus   __r0
+#define RET_osPriority __r0
+#define RET_osEvent    {(osStatus)__r0, {(uint32_t)__r1}, {(void *)__r2}}
+#define RET_osCallback {(void *)__r0, (void *)__r1}
+
+#define osEvent_type        ret128
+#define osEvent_ret_status (ret128){ret.status}
+#define osEvent_ret_value  (ret128){ret.status, ret.value.v}
+#define osEvent_ret_msg    (ret128){ret.status, ret.value.v, (uint32_t)ret.def.message_id}
+#define osEvent_ret_mail   (ret128){ret.status, ret.value.v, (uint32_t)ret.def.mail_id}
+
+#define osCallback_type     ret64
+#define osCallback_ret     (ret64) {(uint32_t)ret.fp, (uint32_t)ret.arg}
+
+#define SVC_ArgN(n) \
+  register int __r##n __asm("r"#n);
+
+#define SVC_ArgR(n,t,a) \
+  register t   __r##n __asm("r"#n) = a;
+
+#define SVC_Arg0()                                                             \
+  SVC_ArgN(0)                                                                  \
+  SVC_ArgN(1)                                                                  \
+  SVC_ArgN(2)                                                                  \
+  SVC_ArgN(3)
+
+#define SVC_Arg1(t1)                                                           \
+  SVC_ArgR(0,t1,a1)                                                            \
+  SVC_ArgN(1)                                                                  \
+  SVC_ArgN(2)                                                                  \
+  SVC_ArgN(3)
+
+#define SVC_Arg2(t1,t2)                                                        \
+  SVC_ArgR(0,t1,a1)                                                            \
+  SVC_ArgR(1,t2,a2)                                                            \
+  SVC_ArgN(2)                                                                  \
+  SVC_ArgN(3)
+
+#define SVC_Arg3(t1,t2,t3)                                                     \
+  SVC_ArgR(0,t1,a1)                                                            \
+  SVC_ArgR(1,t2,a2)                                                            \
+  SVC_ArgR(2,t3,a3)                                                            \
+  SVC_ArgN(3)
+
+#define SVC_Arg4(t1,t2,t3,t4)                                                  \
+  SVC_ArgR(0,t1,a1)                                                            \
+  SVC_ArgR(1,t2,a2)                                                            \
+  SVC_ArgR(2,t3,a3)                                                            \
+  SVC_ArgR(3,t4,a4)
+
+#if (defined (__CORTEX_M0))
+#define SVC_Call(f)                                                            \
+  __asm volatile                                                                 \
+  (                                                                            \
+    "ldr r7,="#f"\n\t"                                                         \
+    "mov r12,r7\n\t"                                                           \
+    "svc 0"                                                                    \
+    :               "=r" (__r0), "=r" (__r1), "=r" (__r2), "=r" (__r3)         \
+    :                "r" (__r0),  "r" (__r1),  "r" (__r2),  "r" (__r3)         \
+    : "r7", "r12", "lr", "cc"                                                  \
+  );
+#else
+#define SVC_Call(f)                                                            \
+  __asm volatile                                                                 \
+  (                                                                            \
+    "ldr r12,="#f"\n\t"                                                        \
+    "svc 0"                                                                    \
+    :               "=r" (__r0), "=r" (__r1), "=r" (__r2), "=r" (__r3)         \
+    :                "r" (__r0),  "r" (__r1),  "r" (__r2),  "r" (__r3)         \
+    : "r12", "lr", "cc"                                                        \
+  );
+#endif
+
+#define SVC_0_1(f,t,rv)                                                        \
+__attribute__((always_inline))                                                 \
+static inline  t __##f (void) {                                                \
+  SVC_Arg0();                                                                  \
+  SVC_Call(f);                                                                 \
+  return (t) rv;                                                               \
+}
+
+#define SVC_1_1(f,t,t1,rv)                                                     \
+__attribute__((always_inline))                                                 \
+static inline  t __##f (t1 a1) {                                               \
+  SVC_Arg1(t1);                                                                \
+  SVC_Call(f);                                                                 \
+  return (t) rv;                                                               \
+}
+
+#define SVC_2_1(f,t,t1,t2,rv)                                                  \
+__attribute__((always_inline))                                                 \
+static inline  t __##f (t1 a1, t2 a2) {                                        \
+  SVC_Arg2(t1,t2);                                                             \
+  SVC_Call(f);                                                                 \
+  return (t) rv;                                                               \
+}
+
+#define SVC_3_1(f,t,t1,t2,t3,rv)                                               \
+__attribute__((always_inline))                                                 \
+static inline  t __##f (t1 a1, t2 a2, t3 a3) {                                 \
+  SVC_Arg3(t1,t2,t3);                                                          \
+  SVC_Call(f);                                                                 \
+  return (t) rv;                                                               \
+}
+
+#define SVC_4_1(f,t,t1,t2,t3,t4,rv)                                            \
+__attribute__((always_inline))                                                 \
+static inline  t __##f (t1 a1, t2 a2, t3 a3, t4 a4) {                          \
+  SVC_Arg4(t1,t2,t3,t4);                                                       \
+  SVC_Call(f);                                                                 \
+  return (t) rv;                                                               \
+}
+
+#define SVC_1_2 SVC_1_1 
+#define SVC_1_3 SVC_1_1 
+#define SVC_2_3 SVC_2_1 
+
+#elif defined (__ICCARM__)      /* IAR Compiler */
+
+#define __NO_RETURN __noreturn
+
+#define RET_osEvent        "=r"(ret.status), "=r"(ret.value), "=r"(ret.def)
+#define RET_osCallback     "=r"(ret.fp), "=r"(ret.arg)
+
+#define osEvent_type       osEvent
+#define osEvent_ret_status ret
+#define osEvent_ret_value  ret
+#define osEvent_ret_msg    ret
+#define osEvent_ret_mail   ret
+
+#define osCallback_type    uint64_t
+#define osCallback_ret     ((uint64_t)ret.fp | ((uint64_t)ret.arg)<<32)
+
+#define SVC_Setup(f)                                                           \
+  __asm(                                                                         \
+    "mov r12,%0\n"                                                             \
+    :: "r"(&f): "r12"                                                          \
+  );
+
+#define SVC_Ret3()                                                             \
+  __asm(                                                                         \
+    "ldr r0,[sp,#0]\n"                                                         \
+    "ldr r1,[sp,#4]\n"                                                         \
+    "ldr r2,[sp,#8]\n"                                                         \
+  );
+
+#define SVC_0_1(f,t,...)                                                       \
+t f (void);                                                                    \
+_Pragma("swi_number=0") __swi t _##f (void);                                   \
+static inline t __##f (void) {                                                 \
+  SVC_Setup(f);                                                                \
+  return _##f();                                                               \
+}
+
+#define SVC_1_1(f,t,t1,...)                                                    \
+t f (t1 a1);                                                                   \
+_Pragma("swi_number=0") __swi t _##f (t1 a1);                                  \
+static inline t __##f (t1 a1) {                                                \
+  SVC_Setup(f);                                                                \
+  return _##f(a1);                                                             \
+}
+
+#define SVC_2_1(f,t,t1,t2,...)                                                 \
+t f (t1 a1, t2 a2);                                                            \
+_Pragma("swi_number=0") __swi t _##f (t1 a1, t2 a2);                           \
+static inline t __##f (t1 a1, t2 a2) {                                         \
+  SVC_Setup(f);                                                                \
+  return _##f(a1,a2);                                                          \
+}
+
+#define SVC_3_1(f,t,t1,t2,t3,...)                                              \
+t f (t1 a1, t2 a2, t3 a3);                                                     \
+_Pragma("swi_number=0") __swi t _##f (t1 a1, t2 a2, t3 a3);                    \
+static inline t __##f (t1 a1, t2 a2, t3 a3) {                                  \
+  SVC_Setup(f);                                                                \
+  return _##f(a1,a2,a3);                                                       \
+}
+
+#define SVC_4_1(f,t,t1,t2,t3,t4,...)                                           \
+t f (t1 a1, t2 a2, t3 a3, t4 a4);                                              \
+_Pragma("swi_number=0") __swi t _##f (t1 a1, t2 a2, t3 a3, t4 a4);             \
+static inline t __##f (t1 a1, t2 a2, t3 a3, t4 a4) {                           \
+  SVC_Setup(f);                                                                \
+  return _##f(a1,a2,a3,a4);                                                    \
+}
+
+#define SVC_1_2(f,t,t1,rr)                                                     \
+uint64_t f (t1 a1);                                                            \
+_Pragma("swi_number=0") __swi uint64_t _##f (t1 a1);                           \
+static inline t __##f (t1 a1) {                                                \
+  t ret;                                                                       \
+  SVC_Setup(f);                                                                \
+  _##f(a1);                                                                    \
+  __asm("" : rr : :);                                                            \
+  return ret;                                                                  \
+}
+
+#define SVC_1_3(f,t,t1,rr)                                                     \
+t f (t1 a1);                                                                   \
+void f##_ (t1 a1) {                                                            \
+  f(a1);                                                                       \
+  SVC_Ret3();                                                                  \
+}                                                                              \
+_Pragma("swi_number=0") __swi void _##f (t1 a1);                               \
+static inline t __##f (t1 a1) {                                                \
+  t ret;                                                                       \
+  SVC_Setup(f##_);                                                             \
+  _##f(a1);                                                                    \
+  __asm("" : rr : :);                                                            \
+  return ret;                                                                  \
+}
+
+#define SVC_2_3(f,t,t1,t2,rr)                                                  \
+t f (t1 a1, t2 a2);                                                            \
+void f##_ (t1 a1, t2 a2) {                                                     \
+  f(a1,a2);                                                                    \
+  SVC_Ret3();                                                                  \
+}                                                                              \
+_Pragma("swi_number=0") __swi void _##f (t1 a1, t2 a2);                        \
+static inline t __##f (t1 a1, t2 a2) {                                         \
+  t ret;                                                                       \
+  SVC_Setup(f##_);                                                             \
+  _##f(a1,a2);                                                                 \
+  __asm("" : rr : :);                                                            \
+  return ret;                                                                  \
+}
+
+#endif
+
+
+// Callback structure
+typedef struct {
+  void *fp;             // Function pointer
+  void *arg;            // Function argument
+} osCallback;
+
+
+// OS Section definitions
+#ifdef OS_SECTIONS_LINK_INFO
+extern const uint32_t  os_section_id$$Base;
+extern const uint32_t  os_section_id$$Limit;
+#endif
+
+// OS Timers external resources
+extern osThreadDef_t   os_thread_def_osTimerThread;
+extern osThreadId      osThreadId_osTimerThread;
+extern osMessageQDef_t os_messageQ_def_osTimerMessageQ;
+extern osMessageQId    osMessageQId_osTimerMessageQ;
+
+
+// ==== Helper Functions ====
+
+/// Convert timeout in millisec to system ticks
+static uint32_t rt_ms2tick (uint32_t millisec) {
+  uint32_t tick;
+
+  if (millisec == osWaitForever) return 0xFFFF; // Indefinite timeout
+  if (millisec > 4000000) return 0xFFFE;        // Max ticks supported
+
+  tick = ((1000 * millisec) + os_clockrate - 1)  / os_clockrate;
+  if (tick > 0xFFFE) return 0xFFFE;
+  
+  return tick;
+}
+
+/// Convert Thread ID to TCB pointer
+static P_TCB rt_tid2ptcb (osThreadId thread_id) {
+  P_TCB ptcb;
+
+  if (thread_id == NULL) return NULL;
+
+  if ((uint32_t)thread_id & 3) return NULL;
+
+#ifdef OS_SECTIONS_LINK_INFO
+  if ((os_section_id$$Base != 0) && (os_section_id$$Limit != 0)) {
+    if (thread_id  < (osThreadId)os_section_id$$Base)  return NULL;
+    if (thread_id >= (osThreadId)os_section_id$$Limit) return NULL;
+  }
+#endif
+
+  ptcb = thread_id;
+
+  if (ptcb->cb_type != TCB) return NULL;
+
+  return ptcb;
+}
+
+/// Convert ID pointer to Object pointer
+static void *rt_id2obj (void *id) {
+
+  if ((uint32_t)id & 3) return NULL;
+
+#ifdef OS_SECTIONS_LINK_INFO
+  if ((os_section_id$$Base != 0) && (os_section_id$$Limit != 0)) {
+    if (id  < (void *)os_section_id$$Base)  return NULL;
+    if (id >= (void *)os_section_id$$Limit) return NULL;
+  }
+#endif
+
+  return id;
+}
+
+
+// ==== Kernel Control ====
+
+uint8_t os_initialized;                         // Kernel Initialized flag
+uint8_t os_running;                             // Kernel Running flag
+
+// Kernel Control Service Calls declarations
+SVC_0_1(svcKernelInitialize, osStatus, RET_osStatus)
+SVC_0_1(svcKernelStart,      osStatus, RET_osStatus)
+SVC_0_1(svcKernelRunning,    int32_t,  RET_int32_t)
+
+extern void  sysThreadError   (osStatus status);
+osThreadId   svcThreadCreate  (osThreadDef_t *thread_def, void *argument);
+osMessageQId svcMessageCreate (osMessageQDef_t *queue_def, osThreadId thread_id);
+
+// Kernel Control Service Calls
+
+/// Initialize the RTOS Kernel for creating objects
+osStatus svcKernelInitialize (void) {
+  if (os_initialized) return osOK;
+
+  rt_sys_init();                                // RTX System Initialization
+  os_tsk.run->prio = 255;                       // Highest priority
+
+  sysThreadError(osOK);
+
+  os_initialized = 1;
+
+  return osOK;
+}
+
+/// Start the RTOS Kernel
+osStatus svcKernelStart (void) {
+
+  if (os_running) return osOK;
+
+  // Create OS Timers resources (Message Queue & Thread)
+  osMessageQId_osTimerMessageQ = svcMessageCreate (&os_messageQ_def_osTimerMessageQ, NULL);
+  osThreadId_osTimerThread = svcThreadCreate(&os_thread_def_osTimerThread, NULL);
+
+  rt_tsk_prio(0, 0);                            // Lowest priority
+  __set_PSP(os_tsk.run->tsk_stack + 8*4);       // New context
+  os_tsk.run = NULL;                            // Force context switch
+
+  rt_sys_start();
+
+  os_running = 1;
+
+  return osOK;
+}
+
+/// Check if the RTOS kernel is already started
+int32_t svcKernelRunning(void) {
+  return os_running;
+}
+
+// Kernel Control Public API
+
+/// Initialize the RTOS Kernel for creating objects
+osStatus osKernelInitialize (void) {
+  if (__get_IPSR() != 0) return osErrorISR;     // Not allowed in ISR
+  if ((__get_CONTROL() & 1) == 0) {             // Privileged mode
+    return   svcKernelInitialize();
+  } else {
+    return __svcKernelInitialize();
+  }
+}
+
+/// Start the RTOS Kernel
+osStatus osKernelStart (void) {
+  uint32_t stack[8];
+  
+  if (__get_IPSR() != 0) return osErrorISR;     // Not allowed in ISR
+  switch (__get_CONTROL() & 0x03) {
+    case 0x00:                                  // Privileged Thread mode & MSP
+      __set_PSP((uint32_t)(stack + 8));         // Initial PSP
+      if (os_flags & 1) {                       
+        __set_CONTROL(0x02);                    // Set Privileged Thread mode & PSP
+      } else {
+        __set_CONTROL(0x03);                    // Set Unprivileged Thread mode & PSP
+      }
+      __DSB();
+      __ISB();
+      break;
+    case 0x01:                                  // Unprivileged Thread mode & MSP
+      return osErrorOS;
+    case 0x02:                                  // Privileged Thread mode & PSP
+      if ((os_flags & 1) == 0) {                // Unprivileged Thread mode requested
+        __set_CONTROL(0x03);                    // Set Unprivileged Thread mode & PSP
+        __DSB();
+        __ISB();
+      }
+      break;
+    case 0x03:                                  // Unprivileged Thread mode & PSP
+      if  (os_flags & 1) return osErrorOS;      // Privileged Thread mode requested
+      break;
+  }
+  return __svcKernelStart();
+}
+
+/// Check if the RTOS kernel is already started
+int32_t osKernelRunning(void) {
+  if ((__get_IPSR() != 0) || ((__get_CONTROL() & 1) == 0)) {
+    // in ISR or Privileged
+    return os_running;
+  } else {
+    return __svcKernelRunning();
+  }
+}
+
+
+// ==== Thread Management ====
+
+__NO_RETURN void osThreadExit (void);
+
+// Thread Service Calls declarations
+SVC_2_1(svcThreadCreate,      osThreadId, osThreadDef_t *, void *,     RET_pointer)
+SVC_0_1(svcThreadGetId,       osThreadId,                              RET_pointer)
+SVC_1_1(svcThreadTerminate,   osStatus,   osThreadId,                  RET_osStatus)
+SVC_0_1(svcThreadYield,       osStatus,                                RET_osStatus)
+SVC_2_1(svcThreadSetPriority, osStatus,   osThreadId,      osPriority, RET_osStatus)
+SVC_1_1(svcThreadGetPriority, osPriority, osThreadId,                  RET_osPriority)
+
+// Thread Service Calls
+extern OS_TID rt_get_TID (void);
+extern void   rt_init_context (P_TCB p_TCB, U8 priority, FUNCP task_body);
+
+/// Create a thread and add it to Active Threads and set it to state READY
+osThreadId svcThreadCreate (osThreadDef_t *thread_def, void *argument) {
+  P_TCB  ptcb;
+  
+  if ((thread_def == NULL) ||
+      (thread_def->pthread == NULL) ||
+      (thread_def->tpriority < osPriorityIdle) ||
+      (thread_def->tpriority > osPriorityRealtime) ||
+      (thread_def->stacksize == 0) ||
+      (thread_def->stack_pointer == NULL) ) {
+    sysThreadError(osErrorParameter); 
+    return NULL; 
+  }
+  
+  U8 priority = thread_def->tpriority - osPriorityIdle + 1;
+  P_TCB task_context = &thread_def->tcb;
+  
+  /* If "size != 0" use a private user provided stack. */
+  task_context->stack      = (U32*)thread_def->stack_pointer;
+  task_context->priv_stack = thread_def->stacksize;
+  /* Pass parameter 'argv' to 'rt_init_context' */
+  task_context->msg = argument;
+  /* For 'size == 0' system allocates the user stack from the memory pool. */
+  rt_init_context (task_context, priority, (FUNCP)thread_def->pthread);
+
+  /* Find a free entry in 'os_active_TCB' table. */
+  OS_TID tsk = rt_get_TID ();
+  os_active_TCB[tsk-1] = task_context;
+  task_context->task_id = tsk;
+  DBG_TASK_NOTIFY(task_context, __TRUE);
+  rt_dispatch (task_context);
+  
+  ptcb = (P_TCB)os_active_TCB[tsk - 1];         // TCB pointer
+
+  *((uint32_t *)ptcb->tsk_stack + 13) = (uint32_t)osThreadExit;
+
+  return ptcb;
+}
+
+/// Return the thread ID of the current running thread
+osThreadId svcThreadGetId (void) {
+  OS_TID tsk;
+
+  tsk = rt_tsk_self();
+  if (tsk == 0) return NULL;
+  return (P_TCB)os_active_TCB[tsk - 1];
+}
+
+/// Terminate execution of a thread and remove it from ActiveThreads
+osStatus svcThreadTerminate (osThreadId thread_id) {
+  OS_RESULT res;
+  P_TCB     ptcb;
+  
+  ptcb = rt_tid2ptcb(thread_id);                // Get TCB pointer
+  if (ptcb == NULL) return osErrorParameter;
+  
+  res = rt_tsk_delete(ptcb->task_id);           // Delete task
+
+  if (res == OS_R_NOK) return osErrorResource;  // Delete task failed
+  
+  return osOK;
+}
+
+/// Pass control to next thread that is in state READY
+osStatus svcThreadYield (void) {
+  rt_tsk_pass();                                // Pass control to next task
+  return osOK;
+}
+
+/// Change priority of an active thread
+osStatus svcThreadSetPriority (osThreadId thread_id, osPriority priority) {
+  OS_RESULT res;
+  P_TCB     ptcb;
+
+  ptcb = rt_tid2ptcb(thread_id);                // Get TCB pointer
+  if (ptcb == NULL) return osErrorParameter;
+
+  if ((priority < osPriorityIdle) || (priority > osPriorityRealtime)) {
+    return osErrorValue;
+  }
+
+  res = rt_tsk_prio(                            // Change task priority
+    ptcb->task_id,                              // Task ID
+    priority - osPriorityIdle + 1               // New task priority
+  );
+
+  if (res == OS_R_NOK) return osErrorResource;  // Change task priority failed
+
+  return osOK;
+}
+
+/// Get current priority of an active thread
+osPriority svcThreadGetPriority (osThreadId thread_id) {
+  P_TCB ptcb;
+
+  ptcb = rt_tid2ptcb(thread_id);                // Get TCB pointer
+  if (ptcb == NULL) return osPriorityError;
+
+  return (osPriority)(ptcb->prio - 1 + osPriorityIdle); 
+}
+
+
+// Thread Public API
+
+/// Create a thread and add it to Active Threads and set it to state READY
+osThreadId osThreadCreate (osThreadDef_t *thread_def, void *argument) {
+  if (__get_IPSR() != 0) return NULL;           // Not allowed in ISR
+  if (((__get_CONTROL() & 1) == 0) && (os_running == 0)) {
+    // Privileged and not running
+    return   svcThreadCreate(thread_def, argument);
+  } else {
+    return __svcThreadCreate(thread_def, argument);
+  }
+}
+
+/// Return the thread ID of the current running thread
+osThreadId osThreadGetId (void) {
+  if (__get_IPSR() != 0) return NULL;           // Not allowed in ISR
+  return __svcThreadGetId();
+}
+
+/// Terminate execution of a thread and remove it from ActiveThreads
+osStatus osThreadTerminate (osThreadId thread_id) {
+  if (__get_IPSR() != 0) return osErrorISR;     // Not allowed in ISR
+  return __svcThreadTerminate(thread_id);
+}
+
+/// Pass control to next thread that is in state READY
+osStatus osThreadYield (void) {
+  if (__get_IPSR() != 0) return osErrorISR;     // Not allowed in ISR
+  return __svcThreadYield();
+}
+
+/// Change priority of an active thread
+osStatus osThreadSetPriority (osThreadId thread_id, osPriority priority) {
+  if (__get_IPSR() != 0) return osErrorISR;     // Not allowed in ISR
+  return __svcThreadSetPriority(thread_id, priority);
+}
+
+/// Get current priority of an active thread
+osPriority osThreadGetPriority (osThreadId thread_id) {
+  if (__get_IPSR() != 0) return osPriorityError;// Not allowed in ISR
+  return __svcThreadGetPriority(thread_id);
+}
+
+/// INTERNAL - Not Public
+/// Auto Terminate Thread on exit (used implicitly when thread exists)
+__NO_RETURN void osThreadExit (void) { 
+  __svcThreadTerminate(__svcThreadGetId()); 
+  for (;;);                                     // Should never come here
+}
+
+
+// ==== Generic Wait Functions ====
+
+// Generic Wait Service Calls declarations
+SVC_1_1(svcDelay,           osStatus, uint32_t, RET_osStatus)
+#if osFeature_Wait != 0
+SVC_1_3(svcWait,  os_InRegs osEvent,  uint32_t, RET_osEvent)
+#endif
+
+// Generic Wait Service Calls
+
+/// Wait for Timeout (Time Delay)
+osStatus svcDelay (uint32_t millisec) {
+  if (millisec == 0) return osOK;
+  rt_dly_wait(rt_ms2tick(millisec));
+  return osEventTimeout;
+}
+
+/// Wait for Signal, Message, Mail, or Timeout
+#if osFeature_Wait != 0
+os_InRegs osEvent_type svcWait (uint32_t millisec) {
+  osEvent ret;
+
+  if (millisec == 0) {
+    ret.status = osOK;
+    return osEvent_ret_status;
+  }
+
+  /* To Do: osEventSignal, osEventMessage, osEventMail */
+  rt_dly_wait(rt_ms2tick(millisec));
+  ret.status = osEventTimeout;
+
+  return osEvent_ret_status;
+}
+#endif
+
+
+// Generic Wait API
+
+/// Wait for Timeout (Time Delay)
+osStatus osDelay (uint32_t millisec) {
+  if (__get_IPSR() != 0) return osErrorISR;     // Not allowed in ISR
+  return __svcDelay(millisec);
+}
+
+/// Wait for Signal, Message, Mail, or Timeout
+os_InRegs osEvent osWait (uint32_t millisec) {
+  osEvent ret;
+
+#if osFeature_Wait == 0
+  ret.status = osErrorOS;
+  return ret;
+#else
+  if (__get_IPSR() != 0) {                      // Not allowed in ISR
+    ret.status = osErrorISR;
+    return ret;
+  }
+  return __svcWait(millisec);
+#endif
+}
+
+
+// ==== Timer Management ====
+
+// Timer definitions
+#define osTimerInvalid  0
+#define osTimerStopped  1
+#define osTimerRunning  2
+
+// Timer structures 
+
+typedef struct os_timer_cb_ {                   // Timer Control Block
+  struct os_timer_cb_ *next;                    // Pointer to next active Timer
+  uint8_t             state;                    // Timer State
+  uint8_t              type;                    // Timer Type (Periodic/One-shot)
+  uint16_t         reserved;                    // Reserved
+  uint16_t             tcnt;                    // Timer Delay Count
+  uint16_t             icnt;                    // Timer Initial Count 
+  void                 *arg;                    // Timer Function Argument
+  osTimerDef_t       *timer;                    // Pointer to Timer definition
+} os_timer_cb;
+
+// Timer variables
+os_timer_cb *os_timer_head;                     // Pointer to first active Timer
+
+
+// Timer Helper Functions
+
+// Insert Timer into the list sorted by time
+static void rt_timer_insert (os_timer_cb *pt, uint32_t tcnt) {
+  os_timer_cb *p, *prev;
+
+  prev = NULL;
+  p = os_timer_head;
+  while (p != NULL) {
+    if (tcnt < p->tcnt) break;
+    tcnt -= p->tcnt;
+    prev = p;
+    p = p->next;
+  }
+  pt->next = p;
+  pt->tcnt = (uint16_t)tcnt;
+  if (p != NULL) {
+    p->tcnt -= pt->tcnt;
+  }
+  if (prev != NULL) {
+    prev->next = pt;
+  } else {
+    os_timer_head = pt;
+  }
+}
+
+// Remove Timer from the list
+static int rt_timer_remove (os_timer_cb *pt) {
+  os_timer_cb *p, *prev;
+
+  prev = NULL;
+  p = os_timer_head;
+  while (p != NULL) {
+    if (p == pt) break;
+    prev = p;
+    p = p->next;
+  }
+  if (p == NULL) return -1;
+  if (prev != NULL) {
+    prev->next = pt->next;
+  } else {
+    os_timer_head = pt->next;
+  }
+  if (pt->next != NULL) {
+    pt->next->tcnt += pt->tcnt;
+  }
+
+  return 0;
+}
+
+
+// Timer Service Calls declarations
+SVC_3_1(svcTimerCreate,           osTimerId,  osTimerDef_t *, os_timer_type, void *, RET_pointer)
+SVC_2_1(svcTimerStart,            osStatus,   osTimerId,      uint32_t,              RET_osStatus)
+SVC_1_1(svcTimerStop,             osStatus,   osTimerId,                             RET_osStatus)
+SVC_1_1(svcTimerDelete,           osStatus,   osTimerId,                             RET_osStatus)
+SVC_1_2(svcTimerCall,   os_InRegs osCallback, osTimerId,                             RET_osCallback)
+
+// Timer Management Service Calls
+
+/// Create timer
+osTimerId svcTimerCreate (osTimerDef_t *timer_def, os_timer_type type, void *argument) {
+  os_timer_cb *pt;
+
+  if ((timer_def == NULL) || (timer_def->ptimer == NULL)) {
+    sysThreadError(osErrorParameter);
+    return NULL;
+  }
+
+  pt = timer_def->timer;
+  if (pt == NULL) {
+    sysThreadError(osErrorParameter);
+    return NULL;
+  }
+
+  if ((type != osTimerOnce) && (type != osTimerPeriodic)) {
+    sysThreadError(osErrorValue);
+    return NULL;
+  }
+
+  if (osThreadId_osTimerThread == NULL) {
+    sysThreadError(osErrorResource);
+    return NULL;
+  }
+
+  if (pt->state != osTimerInvalid){
+    sysThreadError(osErrorResource);
+    return NULL;
+  }
+
+  pt->state = osTimerStopped;
+  pt->type  =  (uint8_t)type;
+  pt->arg   = argument;
+  pt->timer = timer_def;
+
+  return (osTimerId)pt;
+}
+
+/// Start or restart timer
+osStatus svcTimerStart (osTimerId timer_id, uint32_t millisec) {
+  os_timer_cb *pt;
+  uint32_t     tcnt;
+
+  pt = rt_id2obj(timer_id);
+  if (pt == NULL) return osErrorParameter;
+
+  tcnt = rt_ms2tick(millisec);
+  if (tcnt == 0) return osErrorValue;
+
+  switch (pt->state) {
+    case osTimerRunning:
+      if (rt_timer_remove(pt) != 0) {
+        return osErrorResource;
+      }
+      break;
+    case osTimerStopped:
+      pt->state = osTimerRunning;
+      pt->icnt  = (uint16_t)tcnt;
+      break;
+    default:
+      return osErrorResource;
+  }
+  
+  rt_timer_insert(pt, tcnt);
+
+  return osOK;
+}
+
+/// Stop timer
+osStatus svcTimerStop (osTimerId timer_id) {
+  os_timer_cb *pt;
+
+  pt = rt_id2obj(timer_id);
+  if (pt == NULL) return osErrorParameter;
+
+  if (pt->state != osTimerRunning) return osErrorResource;
+
+  pt->state = osTimerStopped;
+
+  if (rt_timer_remove(pt) != 0) {
+    return osErrorResource;
+  }
+
+  return osOK;
+}
+
+/// Delete timer
+osStatus svcTimerDelete (osTimerId timer_id) {
+  os_timer_cb *pt;
+
+  pt = rt_id2obj(timer_id);
+  if (pt == NULL) return osErrorParameter;
+
+  switch (pt->state) {
+    case osTimerRunning:
+      rt_timer_remove(pt);
+      break;
+    case osTimerStopped:
+      break;
+    default:
+      return osErrorResource;
+  }
+
+  pt->state = osTimerInvalid;
+
+  return osOK;
+}
+
+/// Get timer callback parameters
+os_InRegs osCallback_type svcTimerCall (osTimerId timer_id) {
+  os_timer_cb *pt;
+  osCallback   ret;
+
+  pt = rt_id2obj(timer_id);
+  if (pt == NULL) {
+    ret.fp  = NULL;
+    ret.arg = NULL;
+    return osCallback_ret;
+  }
+
+  ret.fp  = (void *)pt->timer->ptimer;
+  ret.arg = pt->arg;
+
+  return osCallback_ret;
+}
+
+static __INLINE osStatus isrMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec);
+
+/// Timer Tick (called each SysTick)
+void sysTimerTick (void) {
+  os_timer_cb *pt, *p;
+
+  p = os_timer_head;
+  if (p == NULL) return;
+
+  p->tcnt--;
+  while ((p != NULL) && (p->tcnt == 0)) {
+    pt = p;
+    p = p->next;
+    os_timer_head = p;
+    isrMessagePut(osMessageQId_osTimerMessageQ, (uint32_t)pt, 0);
+    if (pt->type == osTimerPeriodic) {
+      rt_timer_insert(pt, pt->icnt);
+    } else {
+      pt->state = osTimerStopped;
+    }
+  }
+}
+
+
+// Timer Management Public API
+
+/// Create timer
+osTimerId osTimerCreate (osTimerDef_t *timer_def, os_timer_type type, void *argument) {
+  if (__get_IPSR() != 0) return NULL;           // Not allowed in ISR
+  if (((__get_CONTROL() & 1) == 0) && (os_running == 0)) {
+    // Privileged and not running
+    return   svcTimerCreate(timer_def, type, argument);
+  } else {
+    return __svcTimerCreate(timer_def, type, argument);
+  }
+}
+
+/// Start or restart timer
+osStatus osTimerStart (osTimerId timer_id, uint32_t millisec) {
+  if (__get_IPSR() != 0) return osErrorISR;     // Not allowed in ISR
+  return __svcTimerStart(timer_id, millisec);
+}
+
+/// Stop timer
+osStatus osTimerStop (osTimerId timer_id) {
+  if (__get_IPSR() != 0) return osErrorISR;     // Not allowed in ISR
+  return __svcTimerStop(timer_id);
+}
+
+/// Delete timer
+osStatus osTimerDelete (osTimerId timer_id) {
+  if (__get_IPSR() != 0) return osErrorISR;     // Not allowed in ISR
+  return __svcTimerDelete(timer_id);
+}
+
+/// INTERNAL - Not Public
+/// Get timer callback parameters (used by OS Timer Thread)
+os_InRegs osCallback osTimerCall (osTimerId timer_id) { 
+  return __svcTimerCall(timer_id); 
+}
+
+
+// Timer Thread
+__NO_RETURN void osTimerThread (void const *argument) {
+  osCallback cb;
+  osEvent    evt;
+
+  for (;;) {
+    evt = osMessageGet(osMessageQId_osTimerMessageQ, osWaitForever);
+    if (evt.status == osEventMessage) {
+      cb = osTimerCall(evt.value.p);
+      if (cb.fp != NULL) {
+        (*(os_ptimer)cb.fp)(cb.arg);
+      }
+    }
+  }
+}
+
+
+// ==== Signal Management ====
+
+// Signal Service Calls declarations
+SVC_2_1(svcSignalSet,             int32_t, osThreadId, int32_t,  RET_int32_t)
+SVC_2_1(svcSignalClear,           int32_t, osThreadId, int32_t,  RET_int32_t)
+SVC_1_1(svcSignalGet,             int32_t, osThreadId,           RET_int32_t)
+SVC_2_3(svcSignalWait,  os_InRegs osEvent, int32_t,    uint32_t, RET_osEvent)
+
+// Signal Service Calls
+
+/// Set the specified Signal Flags of an active thread
+int32_t svcSignalSet (osThreadId thread_id, int32_t signals) {
+  P_TCB   ptcb;
+  int32_t sig;
+
+  ptcb = rt_tid2ptcb(thread_id);                // Get TCB pointer
+  if (ptcb == NULL) return 0x80000000;
+
+  if (signals & (0xFFFFFFFF << osFeature_Signals)) return 0x80000000;
+
+  sig = ptcb->events;                           // Previous signal flags
+
+  rt_evt_set(signals, ptcb->task_id);           // Set event flags
+
+  return sig;
+}
+
+/// Clear the specified Signal Flags of an active thread
+int32_t svcSignalClear (osThreadId thread_id, int32_t signals) {
+  P_TCB   ptcb;
+  int32_t sig;
+
+  ptcb = rt_tid2ptcb(thread_id);                // Get TCB pointer
+  if (ptcb == NULL) return 0x80000000;
+
+  if (signals & (0xFFFFFFFF << osFeature_Signals)) return 0x80000000;
+
+  sig = ptcb->events;                           // Previous signal flags
+
+  rt_evt_clr(signals, ptcb->task_id);           // Clear event flags
+
+  return sig;
+}
+
+/// Get Signal Flags status of an active thread
+int32_t svcSignalGet (osThreadId thread_id) {
+  P_TCB ptcb;
+
+  ptcb = rt_tid2ptcb(thread_id);                // Get TCB pointer
+  if (ptcb == NULL) return 0x80000000;
+
+  return ptcb->events;                          // Return event flags
+}
+
+/// Wait for one or more Signal Flags to become signaled for the current RUNNING thread
+os_InRegs osEvent_type svcSignalWait (int32_t signals, uint32_t millisec) {
+  OS_RESULT res;
+  osEvent   ret;
+
+  if (signals & (0xFFFFFFFF << osFeature_Signals)) {
+    ret.status = osErrorValue;
+    return osEvent_ret_status;
+  }
+
+  if (signals != 0) {                           // Wait for all specified signals
+    res = rt_evt_wait(signals, rt_ms2tick(millisec), __TRUE);
+  } else {                                      // Wait for any signal
+    res = rt_evt_wait(0xFFFF,  rt_ms2tick(millisec), __FALSE);
+  }
+
+  if (res == OS_R_EVT) {
+    ret.status = osEventSignal;
+    ret.value.signals = signals ? signals : os_tsk.run->waits;
+  } else {
+    ret.status = millisec ? osEventTimeout : osOK;
+    ret.value.signals = 0;
+  }
+
+  return osEvent_ret_value;
+}
+
+
+// Signal ISR Calls
+
+/// Set the specified Signal Flags of an active thread
+static __INLINE int32_t isrSignalSet (osThreadId thread_id, int32_t signals) {
+  P_TCB   ptcb;
+  int32_t sig;
+
+  ptcb = rt_tid2ptcb(thread_id);                // Get TCB pointer
+  if (ptcb == NULL) return 0x80000000;
+
+  if (signals & (0xFFFFFFFF << osFeature_Signals)) return 0x80000000;
+
+  sig = ptcb->events;                           // Previous signal flags
+
+  isr_evt_set(signals, ptcb->task_id);          // Set event flags
+
+  return sig;
+}
+
+
+// Signal Public API
+
+/// Set the specified Signal Flags of an active thread
+int32_t osSignalSet (osThreadId thread_id, int32_t signals) {
+  if (__get_IPSR() != 0) {                      // in ISR
+    return   isrSignalSet(thread_id, signals); 
+  } else {                                      // in Thread
+    return __svcSignalSet(thread_id, signals);
+  }
+}
+
+/// Clear the specified Signal Flags of an active thread
+int32_t osSignalClear (osThreadId thread_id, int32_t signals) {
+  if (__get_IPSR() != 0) return osErrorISR;     // Not allowed in ISR
+  return __svcSignalClear(thread_id, signals);
+}
+
+/// Get Signal Flags status of an active thread
+int32_t osSignalGet (osThreadId thread_id) {
+  if (__get_IPSR() != 0) return osErrorISR;     // Not allowed in ISR
+  return __svcSignalGet(thread_id);
+}
+
+/// Wait for one or more Signal Flags to become signaled for the current RUNNING thread
+os_InRegs osEvent osSignalWait (int32_t signals, uint32_t millisec) {
+  osEvent ret;
+
+  if (__get_IPSR() != 0) {                      // Not allowed in ISR
+    ret.status = osErrorISR;
+    return ret;
+  }
+  return __svcSignalWait(signals, millisec);
+}
+
+
+// ==== Mutex Management ====
+
+// Mutex Service Calls declarations
+SVC_1_1(svcMutexCreate,  osMutexId, osMutexDef_t *,           RET_pointer)
+SVC_2_1(svcMutexWait,    osStatus,  osMutexId,      uint32_t, RET_osStatus)
+SVC_1_1(svcMutexRelease, osStatus,  osMutexId,                RET_osStatus)
+SVC_1_1(svcMutexDelete,  osStatus,  osMutexId,                RET_osStatus)
+
+// Mutex Service Calls
+
+/// Create and Initialize a Mutex object
+osMutexId svcMutexCreate (osMutexDef_t *mutex_def) {
+  OS_ID mut;
+
+  if (mutex_def == NULL) {
+    sysThreadError(osErrorParameter);
+    return NULL;
+  }
+
+  mut = mutex_def->mutex;
+  if (mut == NULL) {
+    sysThreadError(osErrorParameter);
+    return NULL;
+  }
+
+  if (((P_MUCB)mut)->cb_type != 0) {
+    sysThreadError(osErrorParameter);
+    return NULL;
+  }
+
+  rt_mut_init(mut);                             // Initialize Mutex
+
+  return mut;
+}
+
+/// Wait until a Mutex becomes available
+osStatus svcMutexWait (osMutexId mutex_id, uint32_t millisec) {
+  OS_ID     mut;
+  OS_RESULT res;
+
+  mut = rt_id2obj(mutex_id);
+  if (mut == NULL) return osErrorParameter;
+
+  if (((P_MUCB)mut)->cb_type != MUCB) return osErrorParameter;
+
+  res = rt_mut_wait(mut, rt_ms2tick(millisec)); // Wait for Mutex
+
+  if (res == OS_R_TMO) {
+    return (millisec ? osErrorTimeoutResource : osErrorResource);
+  }
+
+  return osOK;
+}
+
+/// Release a Mutex that was obtained with osMutexWait
+osStatus svcMutexRelease (osMutexId mutex_id) {
+  OS_ID     mut;
+  OS_RESULT res;
+
+  mut = rt_id2obj(mutex_id);
+  if (mut == NULL) return osErrorParameter;
+
+  if (((P_MUCB)mut)->cb_type != MUCB) return osErrorParameter;
+
+  res = rt_mut_release(mut);                    // Release Mutex
+
+  if (res == OS_R_NOK) return osErrorResource;  // Thread not owner or Zero Counter
+
+  return osOK;
+}
+
+/// Delete a Mutex that was created by osMutexCreate
+osStatus svcMutexDelete (osMutexId mutex_id) {
+  OS_ID mut;
+
+  mut = rt_id2obj(mutex_id);
+  if (mut == NULL) return osErrorParameter;
+
+  if (((P_MUCB)mut)->cb_type != MUCB) return osErrorParameter;
+
+  rt_mut_delete(mut);                           // Release Mutex
+
+  return osOK;
+}
+
+
+// Mutex Public API
+
+/// Create and Initialize a Mutex object
+osMutexId osMutexCreate (osMutexDef_t *mutex_def) {
+  if (__get_IPSR() != 0) return NULL;           // Not allowed in ISR
+  if (((__get_CONTROL() & 1) == 0) && (os_running == 0)) {
+    // Privileged and not running
+    return    svcMutexCreate(mutex_def);
+  } else {
+    return __svcMutexCreate(mutex_def);
+  }
+}
+
+/// Wait until a Mutex becomes available
+osStatus osMutexWait (osMutexId mutex_id, uint32_t millisec) {
+  if (__get_IPSR() != 0) return osErrorISR;     // Not allowed in ISR
+  return __svcMutexWait(mutex_id, millisec);
+}
+
+/// Release a Mutex that was obtained with osMutexWait
+osStatus osMutexRelease (osMutexId mutex_id) {
+  if (__get_IPSR() != 0) return osErrorISR;     // Not allowed in ISR
+  return __svcMutexRelease(mutex_id);
+}
+
+/// Delete a Mutex that was created by osMutexCreate
+osStatus osMutexDelete (osMutexId mutex_id) {
+  if (__get_IPSR() != 0) return osErrorISR;     // Not allowed in ISR
+  return __svcMutexDelete(mutex_id);
+}
+
+
+// ==== Semaphore Management ====
+
+// Semaphore Service Calls declarations
+SVC_2_1(svcSemaphoreCreate,  osSemaphoreId, const osSemaphoreDef_t *,  int32_t, RET_pointer)
+SVC_2_1(svcSemaphoreWait,    int32_t,       osSemaphoreId,      uint32_t, RET_int32_t)
+SVC_1_1(svcSemaphoreRelease, osStatus,      osSemaphoreId,                RET_osStatus)
+SVC_1_1(svcSemaphoreDelete,  osStatus,            osSemaphoreId,                RET_osStatus)
+
+// Semaphore Service Calls
+
+/// Create and Initialize a Semaphore object
+osSemaphoreId svcSemaphoreCreate (const osSemaphoreDef_t *semaphore_def, int32_t count) {
+  OS_ID sem;
+
+  if (semaphore_def == NULL) {
+    sysThreadError(osErrorParameter);
+    return NULL;
+  }
+
+  sem = semaphore_def->semaphore;
+  if (sem == NULL) {
+    sysThreadError(osErrorParameter);
+    return NULL;
+  }
+
+  if (((P_SCB)sem)->cb_type != 0) {
+    sysThreadError(osErrorParameter);
+    return NULL;
+  }
+
+  if (count > osFeature_Semaphore) {
+    sysThreadError(osErrorValue);
+    return NULL;
+  }
+
+  rt_sem_init(sem, count);                      // Initialize Semaphore
+  
+  return sem;
+}
+
+/// Wait until a Semaphore becomes available
+int32_t svcSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec) {
+  OS_ID     sem;
+  OS_RESULT res;
+
+  sem = rt_id2obj(semaphore_id);
+  if (sem == NULL) return -1;
+
+  if (((P_SCB)sem)->cb_type != SCB) return -1;
+
+  res = rt_sem_wait(sem, rt_ms2tick(millisec)); // Wait for Semaphore
+
+  if (res == OS_R_TMO) return 0;                // Timeout
+
+  return (((P_SCB)sem)->tokens + 1);
+}
+
+/// Release a Semaphore
+osStatus svcSemaphoreRelease (osSemaphoreId semaphore_id) {
+  OS_ID sem;
+
+  sem = rt_id2obj(semaphore_id);
+  if (sem == NULL) return osErrorParameter;
+
+  if (((P_SCB)sem)->cb_type != SCB) return osErrorParameter;
+
+  if (((P_SCB)sem)->tokens == osFeature_Semaphore) return osErrorResource;
+  
+  rt_sem_send(sem);                             // Release Semaphore
+
+  return osOK;
+}
+
+/// Delete a Semaphore that was created by osSemaphoreCreate
+osStatus svcSemaphoreDelete (osSemaphoreId semaphore_id) {
+  OS_ID sem;
+
+  sem = rt_id2obj(semaphore_id);
+  if (sem == NULL) return osErrorParameter;
+
+  if (((P_SCB)sem)->cb_type != SCB) return osErrorParameter;
+
+  rt_sem_delete(sem);                           // Delete Semaphore
+
+  return osOK;
+}
+
+
+// Semaphore ISR Calls
+
+/// Release a Semaphore
+static __INLINE osStatus isrSemaphoreRelease (osSemaphoreId semaphore_id) {
+  OS_ID sem;
+
+  sem = rt_id2obj(semaphore_id);
+  if (sem == NULL) return osErrorParameter;
+
+  if (((P_SCB)sem)->cb_type != SCB) return osErrorParameter;
+
+  if (((P_SCB)sem)->tokens == osFeature_Semaphore) return osErrorResource;
+
+  isr_sem_send(sem);                            // Release Semaphore
+
+  return osOK;
+}
+
+
+// Semaphore Public API
+
+/// Create and Initialize a Semaphore object
+osSemaphoreId osSemaphoreCreate (osSemaphoreDef_t *semaphore_def, int32_t count) {
+  if (__get_IPSR() != 0) return NULL;           // Not allowed in ISR
+  if (((__get_CONTROL() & 1) == 0) && (os_running == 0)) {
+    // Privileged and not running
+    return   svcSemaphoreCreate(semaphore_def, count);
+  } else {
+    return __svcSemaphoreCreate(semaphore_def, count);
+  }
+}
+
+/// Wait until a Semaphore becomes available
+int32_t osSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec) {
+  if (__get_IPSR() != 0) return -1;             // Not allowed in ISR
+  return __svcSemaphoreWait(semaphore_id, millisec);
+}
+
+/// Release a Semaphore
+osStatus osSemaphoreRelease (osSemaphoreId semaphore_id) {
+  if (__get_IPSR() != 0) {                      // in ISR
+    return   isrSemaphoreRelease(semaphore_id);
+  } else {                                      // in Thread
+    return __svcSemaphoreRelease(semaphore_id);
+  }
+}
+
+/// Delete a Semaphore that was created by osSemaphoreCreate
+osStatus osSemaphoreDelete (osSemaphoreId semaphore_id) {
+  if (__get_IPSR() != 0) return osErrorISR;     // Not allowed in ISR
+  return __svcSemaphoreDelete(semaphore_id);
+}
+
+
+// ==== Memory Management Functions ====
+
+// Memory Management Helper Functions
+
+// Clear Memory Box (Zero init)
+static void rt_clr_box (void *box_mem, void *box) {
+  uint32_t *p, n;
+
+  if (box) {
+    p = box;
+    for (n = ((P_BM)box_mem)->blk_size; n; n -= 4) {
+      *p++ = 0;
+    }
+  }
+}
+
+// Memory Management Service Calls declarations
+SVC_1_1(svcPoolCreate, osPoolId, const osPoolDef_t *,           RET_pointer)
+SVC_2_1(sysPoolAlloc,  void *,   osPoolId,      uint32_t, RET_pointer)
+SVC_2_1(sysPoolFree,   osStatus, osPoolId,      void *,   RET_osStatus)
+
+// Memory Management Service & ISR Calls
+
+/// Create and Initialize memory pool
+osPoolId svcPoolCreate (const osPoolDef_t *pool_def) {
+  uint32_t blk_sz;
+
+  if ((pool_def == NULL) ||
+      (pool_def->pool_sz == 0) ||
+      (pool_def->item_sz == 0) ||
+      (pool_def->pool == NULL)) {
+    sysThreadError(osErrorParameter);
+    return NULL;
+  }
+
+  blk_sz = (pool_def->item_sz + 3) & ~3;
+
+  _init_box(pool_def->pool, sizeof(struct OS_BM) + pool_def->pool_sz * blk_sz, blk_sz);
+
+  return pool_def->pool;
+}
+
+/// Allocate a memory block from a memory pool
+void *sysPoolAlloc (osPoolId pool_id, uint32_t clr) {
+  void *ptr;
+
+  if (pool_id == NULL) return NULL;
+
+  ptr = rt_alloc_box(pool_id);
+  if (clr) {
+    rt_clr_box(pool_id, ptr);
+  }
+
+  return ptr;
+}
+
+/// Return an allocated memory block back to a specific memory pool
+osStatus sysPoolFree (osPoolId pool_id, void *block) {
+  int32_t res;
+    
+  if (pool_id == NULL) return osErrorParameter;
+
+  res = rt_free_box(pool_id, block);
+  if (res != 0) return osErrorValue;
+
+  return osOK;
+}
+
+
+// Memory Management Public API
+
+/// Create and Initialize memory pool
+osPoolId osPoolCreate (osPoolDef_t *pool_def) {
+  if (__get_IPSR() != 0) return NULL;           // Not allowed in ISR
+  if (((__get_CONTROL() & 1) == 0) && (os_running == 0)) {
+    // Privileged and not running
+    return   svcPoolCreate(pool_def);
+  } else {
+    return __svcPoolCreate(pool_def);
+  }
+}
+
+/// Allocate a memory block from a memory pool
+void *osPoolAlloc (osPoolId pool_id) {
+  if ((__get_IPSR() != 0) || ((__get_CONTROL() & 1) == 0)) {    // in ISR or Privileged
+    return   sysPoolAlloc(pool_id, 0);
+  } else {                                      // in Thread
+    return __sysPoolAlloc(pool_id, 0);
+  }
+}
+
+/// Allocate a memory block from a memory pool and set memory block to zero
+void *osPoolCAlloc (osPoolId pool_id) {
+  if ((__get_IPSR() != 0) || ((__get_CONTROL() & 1) == 0)) {    // in ISR or Privileged
+    return   sysPoolAlloc(pool_id, 1);
+  } else {                                      // in Thread
+    return __sysPoolAlloc(pool_id, 1);
+  }
+}
+
+/// Return an allocated memory block back to a specific memory pool
+osStatus osPoolFree (osPoolId pool_id, void *block) {
+  if ((__get_IPSR() != 0) || ((__get_CONTROL() & 1) == 0)) {    // in ISR or Privileged
+    return   sysPoolFree(pool_id, block);
+  } else {                                      // in Thread
+    return __sysPoolFree(pool_id, block);
+  }
+}
+
+
+// ==== Message Queue Management Functions ====
+
+// Message Queue Management Service Calls declarations
+SVC_2_1(svcMessageCreate,        osMessageQId,    osMessageQDef_t *, osThreadId,           RET_pointer)
+SVC_3_1(svcMessagePut,              osStatus,     osMessageQId,      uint32_t,   uint32_t, RET_osStatus)
+SVC_2_3(svcMessageGet,    os_InRegs osEvent,      osMessageQId,      uint32_t,             RET_osEvent)
+
+// Message Queue Service Calls
+
+/// Create and Initialize Message Queue
+osMessageQId svcMessageCreate (osMessageQDef_t *queue_def, osThreadId thread_id) {
+
+  if ((queue_def == NULL) ||
+      (queue_def->queue_sz == 0) ||
+      (queue_def->pool == NULL)) {
+    sysThreadError(osErrorParameter);
+    return NULL;
+  }
+  
+  if (((P_MCB)queue_def->pool)->cb_type != 0) {
+    sysThreadError(osErrorParameter);
+    return NULL;
+  }
+
+  rt_mbx_init(queue_def->pool, 4*(queue_def->queue_sz + 4));
+
+  return queue_def->pool;
+}
+
+/// Put a Message to a Queue
+osStatus svcMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec) {
+  OS_RESULT res;
+
+  if (queue_id == NULL) return osErrorParameter;
+
+  if (((P_MCB)queue_id)->cb_type != MCB) return osErrorParameter;
+
+  res = rt_mbx_send(queue_id, (void *)info, rt_ms2tick(millisec));
+
+  if (res == OS_R_TMO) {
+    return (millisec ? osErrorTimeoutResource : osErrorResource);
+  }
+
+  return osOK;
+}
+
+/// Get a Message or Wait for a Message from a Queue
+os_InRegs osEvent_type svcMessageGet (osMessageQId queue_id, uint32_t millisec) {
+  OS_RESULT res;
+  osEvent   ret;
+
+  if (queue_id == NULL) {
+    ret.status = osErrorParameter;
+    return osEvent_ret_status;
+  }
+
+  if (((P_MCB)queue_id)->cb_type != MCB) {
+    ret.status = osErrorParameter;
+    return osEvent_ret_status;
+  }
+
+  res = rt_mbx_wait(queue_id, &ret.value.p, rt_ms2tick(millisec));
+  
+  if (res == OS_R_TMO) {
+    ret.status = millisec ? osEventTimeout : osOK;
+    return osEvent_ret_value;
+  }
+
+  ret.status = osEventMessage;
+
+  return osEvent_ret_value;
+}
+
+
+// Message Queue ISR Calls
+
+/// Put a Message to a Queue
+static __INLINE osStatus isrMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec) {
+
+  if ((queue_id == NULL) || (millisec != 0)) {
+    return osErrorParameter;
+  }
+
+  if (((P_MCB)queue_id)->cb_type != MCB) return osErrorParameter;
+
+  if (rt_mbx_check(queue_id) == 0) {            // Check if Queue is full
+    return osErrorResource;
+  }
+
+  isr_mbx_send(queue_id, (void *)info);
+
+  return osOK;
+}
+
+/// Get a Message or Wait for a Message from a Queue
+static __INLINE os_InRegs osEvent isrMessageGet (osMessageQId queue_id, uint32_t millisec) {
+  OS_RESULT res;
+  osEvent   ret;
+
+  if ((queue_id == NULL) || (millisec != 0)) {
+    ret.status = osErrorParameter;
+    return ret;
+  }
+
+  if (((P_MCB)queue_id)->cb_type != MCB) {
+    ret.status = osErrorParameter;
+    return ret;
+  }
+
+  res = isr_mbx_receive(queue_id, &ret.value.p);
+  
+  if (res != OS_R_MBX) {
+    ret.status = osOK;
+    return ret;
+  }
+
+  ret.status = osEventMessage; 
+
+  return ret;
+}
+
+
+// Message Queue Management Public API
+
+/// Create and Initialize Message Queue
+osMessageQId osMessageCreate (osMessageQDef_t *queue_def, osThreadId thread_id) {
+  if (__get_IPSR() != 0) return NULL;           // Not allowed in ISR
+  if (((__get_CONTROL() & 1) == 0) && (os_running == 0)) {
+    // Privileged and not running
+    return   svcMessageCreate(queue_def, thread_id);
+  } else {
+    return __svcMessageCreate(queue_def, thread_id);
+  }
+}
+
+/// Put a Message to a Queue
+osStatus osMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec) {
+  if (__get_IPSR() != 0) {                      // in ISR
+    return   isrMessagePut(queue_id, info, millisec);
+  } else {                                      // in Thread
+    return __svcMessagePut(queue_id, info, millisec);
+  }
+}
+
+/// Get a Message or Wait for a Message from a Queue
+os_InRegs osEvent osMessageGet (osMessageQId queue_id, uint32_t millisec) {
+  if (__get_IPSR() != 0) {                      // in ISR
+    return   isrMessageGet(queue_id, millisec);
+  } else {                                      // in Thread
+    return __svcMessageGet(queue_id, millisec);
+  }
+}
+
+
+// ==== Mail Queue Management Functions ====
+
+// Mail Queue Management Service Calls declarations
+SVC_2_1(svcMailCreate, osMailQId, osMailQDef_t *, osThreadId,                   RET_pointer)
+SVC_4_1(sysMailAlloc,  void *,    osMailQId,      uint32_t, uint32_t, uint32_t, RET_pointer)
+SVC_3_1(sysMailFree,   osStatus,  osMailQId,      void *,   uint32_t,           RET_osStatus)
+
+// Mail Queue Management Service & ISR Calls
+
+/// Create and Initialize mail queue
+osMailQId svcMailCreate (osMailQDef_t *queue_def, osThreadId thread_id) {
+  uint32_t blk_sz;
+  P_MCB    pmcb;
+  void    *pool;
+
+  if ((queue_def == NULL) ||
+      (queue_def->queue_sz == 0) ||
+      (queue_def->item_sz  == 0) ||
+      (queue_def->pool == NULL)) {
+    sysThreadError(osErrorParameter);
+    return NULL;
+  }
+
+  pmcb = *(((void **)queue_def->pool) + 0);
+  pool = *(((void **)queue_def->pool) + 1);
+
+  if ((pool == NULL) || (pmcb == NULL) || (pmcb->cb_type != 0)) {
+    sysThreadError(osErrorParameter);
+    return NULL;
+  }
+
+  blk_sz = (queue_def->item_sz + 3) & ~3;
+
+  _init_box(pool, sizeof(struct OS_BM) + queue_def->queue_sz * blk_sz, blk_sz);
+
+  rt_mbx_init(pmcb, 4*(queue_def->queue_sz + 4));
+
+
+  return queue_def->pool;
+}
+
+/// Allocate a memory block from a mail
+void *sysMailAlloc (osMailQId queue_id, uint32_t millisec, uint32_t isr, uint32_t clr) {
+  P_MCB pmcb;
+  void *pool;
+  void *mem;
+
+  if (queue_id == NULL) return NULL;
+
+  pmcb = *(((void **)queue_id) + 0);
+  pool = *(((void **)queue_id) + 1);
+
+  if ((pool == NULL) || (pmcb == NULL)) return NULL;
+
+  if (isr && (millisec != 0)) return NULL;
+
+  mem = rt_alloc_box(pool);
+  if (clr) {
+    rt_clr_box(pool, mem);
+  }
+
+  if ((mem == NULL) && (millisec != 0)) {
+    // Put Task to sleep when Memory not available
+    if (pmcb->p_lnk != NULL) {
+      rt_put_prio((P_XCB)pmcb, os_tsk.run);
+    } else {
+      pmcb->p_lnk = os_tsk.run;
+      os_tsk.run->p_lnk = NULL;
+      os_tsk.run->p_rlnk = (P_TCB)pmcb;
+      // Task is waiting to allocate a message
+      pmcb->state = 3;
+    }
+    rt_block(rt_ms2tick(millisec), WAIT_MBX);
+  }
+
+  return mem;  
+}
+
+/// Free a memory block from a mail
+osStatus sysMailFree (osMailQId queue_id, void *mail, uint32_t isr) {
+  P_MCB   pmcb;
+  P_TCB   ptcb;
+  void   *pool;
+  void   *mem;
+  int32_t res;
+
+  if (queue_id == NULL) return osErrorParameter;
+
+  pmcb = *(((void **)queue_id) + 0);
+  pool = *(((void **)queue_id) + 1);
+
+  if ((pmcb == NULL) || (pool == NULL)) return osErrorParameter;
+
+  res = rt_free_box(pool, mail);
+
+  if (res != 0) return osErrorValue;
+
+  if (pmcb->state == 3) {
+    // Task is waiting to allocate a message
+    if (isr) {
+      rt_psq_enq (pmcb, (U32)pool);
+      rt_psh_req ();
+    } else {
+      mem = rt_alloc_box(pool);
+      if (mem != NULL) {
+        ptcb = rt_get_first((P_XCB)pmcb);
+        if (pmcb->p_lnk == NULL) {
+          pmcb->state = 0;
+        }
+        rt_ret_val(ptcb, (U32)mem);
+        rt_rmv_dly(ptcb);
+        rt_dispatch(ptcb);
+      }
+    }
+  }
+
+  return osOK;
+}
+
+
+// Mail Queue Management Public API
+
+/// Create and Initialize mail queue
+osMailQId osMailCreate (osMailQDef_t *queue_def, osThreadId thread_id) {
+  if (__get_IPSR() != 0) return NULL;           // Not allowed in ISR
+  if (((__get_CONTROL() & 1) == 0) && (os_running == 0)) {
+    // Privileged and not running
+    return   svcMailCreate(queue_def, thread_id);
+  } else {
+    return __svcMailCreate(queue_def, thread_id);
+  }
+}
+
+/// Allocate a memory block from a mail
+void *osMailAlloc (osMailQId queue_id, uint32_t millisec) {
+  if (__get_IPSR() != 0) {                      // in ISR
+    return   sysMailAlloc(queue_id, millisec, 1, 0);
+  } else {                                      // in Thread
+    return __sysMailAlloc(queue_id, millisec, 0, 0);
+  }
+}
+
+/// Allocate a memory block from a mail and set memory block to zero
+void *osMailCAlloc (osMailQId queue_id, uint32_t millisec) {
+  if (__get_IPSR() != 0) {                      // in ISR
+    return   sysMailAlloc(queue_id, millisec, 1, 1);
+  } else {                                      // in Thread
+    return __sysMailAlloc(queue_id, millisec, 0, 1);
+  }
+}
+
+/// Free a memory block from a mail
+osStatus osMailFree (osMailQId queue_id, void *mail) {
+  if (__get_IPSR() != 0) {                      // in ISR
+    return   sysMailFree(queue_id, mail, 1);
+  } else {                                      // in Thread
+    return __sysMailFree(queue_id, mail, 0);
+  }
+}
+
+/// Put a mail to a queue
+osStatus osMailPut (osMailQId queue_id, void *mail) {
+  if (queue_id == NULL) return osErrorParameter;
+  if (mail == NULL)     return osErrorValue;
+  return osMessagePut(*((void **)queue_id), (uint32_t)mail, 0);
+}
+
+/// Get a mail from a queue
+os_InRegs osEvent osMailGet (osMailQId queue_id, uint32_t millisec) {
+  osEvent ret;
+
+  if (queue_id == NULL) {
+    ret.status = osErrorParameter;
+    return ret;
+  }
+
+  ret = osMessageGet(*((void **)queue_id), millisec);
+  if (ret.status == osEventMessage) ret.status = osEventMail;
+
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/rt_Event.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,190 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    RT_EVENT.C
+ *      Purpose: Implements waits and wake-ups for event flags
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#include "rt_TypeDef.h"
+#include "RTX_Config.h"
+#include "rt_System.h"
+#include "rt_Event.h"
+#include "rt_List.h"
+#include "rt_Task.h"
+#include "rt_HAL_CM.h"
+
+
+/*----------------------------------------------------------------------------
+ *      Functions
+ *---------------------------------------------------------------------------*/
+
+
+/*--------------------------- rt_evt_wait -----------------------------------*/
+
+OS_RESULT rt_evt_wait (U16 wait_flags, U16 timeout, BOOL and_wait) {
+  /* Wait for one or more event flags with optional time-out.                */
+  /* "wait_flags" identifies the flags to wait for.                          */
+  /* "timeout" is the time-out limit in system ticks (0xffff if no time-out) */
+  /* "and_wait" specifies the AND-ing of "wait_flags" as condition to be met */
+  /* to complete the wait. (OR-ing if set to 0).                             */
+  U32 block_state;
+
+  if (and_wait) {
+    /* Check for AND-connected events */
+    if ((os_tsk.run->events & wait_flags) == wait_flags) {
+      os_tsk.run->events &= ~wait_flags;
+      return (OS_R_EVT);
+    }
+    block_state = WAIT_AND;
+  }
+  else {
+    /* Check for OR-connected events */
+    if (os_tsk.run->events & wait_flags) {
+      os_tsk.run->waits = os_tsk.run->events & wait_flags;
+      os_tsk.run->events &= ~wait_flags;
+      return (OS_R_EVT);
+    }
+    block_state = WAIT_OR;
+  }
+  /* Task has to wait */
+  os_tsk.run->waits = wait_flags;
+  rt_block (timeout, (U8)block_state);
+  return (OS_R_TMO);
+}
+
+
+/*--------------------------- rt_evt_set ------------------------------------*/
+
+void rt_evt_set (U16 event_flags, OS_TID task_id) {
+  /* Set one or more event flags of a selectable task. */
+  P_TCB p_tcb;
+
+  p_tcb = os_active_TCB[task_id-1];
+  if (p_tcb == NULL) {
+    return;
+  }
+  p_tcb->events |= event_flags;
+  event_flags    = p_tcb->waits;
+  /* If the task is not waiting for an event, it should not be put */
+  /* to ready state. */
+  if (p_tcb->state == WAIT_AND) {
+    /* Check for AND-connected events */
+    if ((p_tcb->events & event_flags) == event_flags) {
+      goto wkup;
+    }
+  }
+  if (p_tcb->state == WAIT_OR) {
+    /* Check for OR-connected events */
+    if (p_tcb->events & event_flags) {
+      p_tcb->waits  &= p_tcb->events;
+wkup: p_tcb->events &= ~event_flags;
+      rt_rmv_dly (p_tcb);
+      p_tcb->state   = READY;
+#ifdef __CMSIS_RTOS
+      rt_ret_val2(p_tcb, 0x08/*osEventSignal*/, p_tcb->waits); 
+#else
+      rt_ret_val (p_tcb, OS_R_EVT);
+#endif
+      rt_dispatch (p_tcb);
+    }
+  }
+}
+
+
+/*--------------------------- rt_evt_clr ------------------------------------*/
+
+void rt_evt_clr (U16 clear_flags, OS_TID task_id) {
+  /* Clear one or more event flags (identified by "clear_flags") of a */
+  /* selectable task (identified by "task"). */
+  P_TCB task = os_active_TCB[task_id-1];
+
+  if (task == NULL) {
+    return;
+  }
+  task->events &= ~clear_flags;
+}
+
+
+/*--------------------------- isr_evt_set -----------------------------------*/
+
+void isr_evt_set (U16 event_flags, OS_TID task_id) {
+  /* Same function as "os_evt_set", but to be called by ISRs. */
+  P_TCB p_tcb = os_active_TCB[task_id-1];
+
+  if (p_tcb == NULL) {
+    return;
+  }
+  rt_psq_enq (p_tcb, event_flags);
+  rt_psh_req ();
+}
+
+
+/*--------------------------- rt_evt_get ------------------------------------*/
+
+U16 rt_evt_get (void) {
+  /* Get events of a running task after waiting for OR connected events. */
+  return (os_tsk.run->waits);
+}
+
+
+/*--------------------------- rt_evt_psh ------------------------------------*/
+
+void rt_evt_psh (P_TCB p_CB, U16 set_flags) {
+  /* Check if task has to be waken up */
+  U16 event_flags;
+
+  p_CB->events |= set_flags;
+  event_flags = p_CB->waits;
+  if (p_CB->state == WAIT_AND) {
+    /* Check for AND-connected events */
+    if ((p_CB->events & event_flags) == event_flags) {
+      goto rdy;
+    }
+  }
+  if (p_CB->state == WAIT_OR) {
+    /* Check for OR-connected events */
+    if (p_CB->events & event_flags) {
+      p_CB->waits  &= p_CB->events;
+rdy:  p_CB->events &= ~event_flags;
+      rt_rmv_dly (p_CB);
+      p_CB->state   = READY;
+#ifdef __CMSIS_RTOS
+      rt_ret_val2(p_CB, 0x08/*osEventSignal*/, p_CB->waits); 
+#else
+      rt_ret_val (p_CB, OS_R_EVT);
+#endif
+      rt_put_prio (&os_rdy, p_CB);
+    }
+  }
+}
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/rt_Event.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,46 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    RT_EVENT.H
+ *      Purpose: Implements waits and wake-ups for event flags
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+/* Functions */
+extern OS_RESULT rt_evt_wait (U16 wait_flags,  U16 timeout, BOOL and_wait);
+extern void      rt_evt_set  (U16 event_flags, OS_TID task_id);
+extern void      rt_evt_clr  (U16 clear_flags, OS_TID task_id);
+extern void      isr_evt_set (U16 event_flags, OS_TID task_id);
+extern U16       rt_evt_get  (void);
+extern void      rt_evt_psh  (P_TCB p_CB, U16 set_flags);
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/rt_HAL_CM.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,276 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    RT_HAL_CM.H
+ *      Purpose: Hardware Abstraction Layer for Cortex-M definitions
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+/* Definitions */
+#define INITIAL_xPSR    0x01000000
+#define DEMCR_TRCENA    0x01000000
+#define ITM_ITMENA      0x00000001
+#define MAGIC_WORD      0xE25A2EA5
+
+#if defined (__CC_ARM)          /* ARM Compiler */
+
+#if ((__TARGET_ARCH_7_M || __TARGET_ARCH_7E_M) && !NO_EXCLUSIVE_ACCESS)
+ #define __USE_EXCLUSIVE_ACCESS
+#else
+ #undef  __USE_EXCLUSIVE_ACCESS
+#endif
+
+#elif defined (__GNUC__)        /* GNU Compiler */
+
+#undef  __USE_EXCLUSIVE_ACCESS
+
+#if defined (__CORTEX_M0)
+#define __TARGET_ARCH_6S_M 1
+#else
+#define __TARGET_ARCH_6S_M 0
+#endif
+
+#if defined (__VFP_FP__) && !defined(__SOFTFP__)
+#define __TARGET_FPU_VFP 1
+#else
+#define __TARGET_FPU_VFP 0
+#endif
+
+#define __inline inline
+#define __weak   __attribute__((weak))
+
+#ifndef __CMSIS_GENERIC
+
+__attribute__((always_inline)) static inline void __enable_irq(void)
+{
+  __asm volatile ("cpsie i");
+}
+
+__attribute__((always_inline)) static inline U32 __disable_irq(void)
+{
+  U32 result;
+
+  __asm volatile ("mrs %0, primask" : "=r" (result));
+  __asm volatile ("cpsid i");
+  return(result & 1);
+}
+
+#endif
+
+__attribute__(( always_inline)) static inline U8 __clz(U32 value)
+{
+  U8 result;
+  
+  __asm volatile ("clz %0, %1" : "=r" (result) : "r" (value));
+  return(result);
+}
+
+#elif defined (__ICCARM__)      /* IAR Compiler */
+
+#undef  __USE_EXCLUSIVE_ACCESS
+
+#if (__CORE__ == __ARM6M__)
+#define __TARGET_ARCH_6S_M 1
+#else
+#define __TARGET_ARCH_6S_M 0
+#endif
+
+#if defined __ARMVFP__
+#define __TARGET_FPU_VFP 1
+#else
+#define __TARGET_FPU_VFP 0
+#endif
+
+#define __inline inline
+
+#ifndef __CMSIS_GENERIC
+
+static inline void __enable_irq(void)
+{
+  __asm volatile ("cpsie i");
+}
+
+static inline U32 __disable_irq(void)
+{
+  U32 result;
+  
+  __asm volatile ("mrs %0, primask" : "=r" (result));
+  __asm volatile ("cpsid i");
+  return(result & 1);
+}
+
+#endif
+
+static inline U8 __clz(U32 value)
+{
+  U8 result;
+  
+  __asm volatile ("clz %0, %1" : "=r" (result) : "r" (value));
+  return(result);
+}
+
+#endif
+
+/* NVIC registers */
+#define NVIC_ST_CTRL    (*((volatile U32 *)0xE000E010))
+#define NVIC_ST_RELOAD  (*((volatile U32 *)0xE000E014))
+#define NVIC_ST_CURRENT (*((volatile U32 *)0xE000E018))
+#define NVIC_ISER         ((volatile U32 *)0xE000E100)
+#define NVIC_ICER         ((volatile U32 *)0xE000E180)
+#if (__TARGET_ARCH_6S_M)
+#define NVIC_IP           ((volatile U32 *)0xE000E400)
+#else
+#define NVIC_IP           ((volatile U8  *)0xE000E400)
+#endif
+#define NVIC_INT_CTRL   (*((volatile U32 *)0xE000ED04))
+#define NVIC_AIR_CTRL   (*((volatile U32 *)0xE000ED0C))
+#define NVIC_SYS_PRI2   (*((volatile U32 *)0xE000ED1C))
+#define NVIC_SYS_PRI3   (*((volatile U32 *)0xE000ED20))
+
+#define OS_PEND_IRQ()   NVIC_INT_CTRL  = (1<<28)
+#define OS_PENDING      ((NVIC_INT_CTRL >> 26) & (1<<2 | 1))
+#define OS_UNPEND(fl)   NVIC_INT_CTRL  = (*fl = OS_PENDING) << 25
+#define OS_PEND(fl,p)   NVIC_INT_CTRL  = (fl | p<<2) << 26
+#define OS_LOCK()       NVIC_ST_CTRL   =  0x0005
+#define OS_UNLOCK()     NVIC_ST_CTRL   =  0x0007
+
+#define OS_X_PENDING    ((NVIC_INT_CTRL >> 28) & 1)
+#define OS_X_UNPEND(fl) NVIC_INT_CTRL  = (*fl = OS_X_PENDING) << 27
+#define OS_X_PEND(fl,p) NVIC_INT_CTRL  = (fl | p) << 28
+#if (__TARGET_ARCH_6S_M)
+#define OS_X_INIT(n)    NVIC_IP[n>>2] |= 0xFF << (8*(n & 0x03)); \
+                        NVIC_ISER[n>>5] = 1 << (n & 0x1F)
+#else
+#define OS_X_INIT(n)    NVIC_IP[n] = 0xFF; \
+                        NVIC_ISER[n>>5] = 1 << (n & 0x1F)
+#endif
+#define OS_X_LOCK(n)    NVIC_ICER[n>>5] = 1 << (n & 0x1F)
+#define OS_X_UNLOCK(n)  NVIC_ISER[n>>5] = 1 << (n & 0x1F)
+
+/* Core Debug registers */
+#define DEMCR           (*((volatile U32 *)0xE000EDFC))
+
+/* ITM registers */
+#define ITM_CONTROL     (*((volatile U32 *)0xE0000E80))
+#define ITM_ENABLE      (*((volatile U32 *)0xE0000E00))
+#define ITM_PORT30_U32  (*((volatile U32 *)0xE0000078))
+#define ITM_PORT31_U32  (*((volatile U32 *)0xE000007C))
+#define ITM_PORT31_U16  (*((volatile U16 *)0xE000007C))
+#define ITM_PORT31_U8   (*((volatile U8  *)0xE000007C))
+
+/* Variables */
+extern BIT dbg_msg;
+
+/* Functions */
+#ifdef __USE_EXCLUSIVE_ACCESS
+ #define rt_inc(p)     while(__strex((__ldrex(p)+1),p))
+ #define rt_dec(p)     while(__strex((__ldrex(p)-1),p))
+#else
+ #define rt_inc(p)     __disable_irq();(*p)++;__enable_irq();
+ #define rt_dec(p)     __disable_irq();(*p)--;__enable_irq();
+#endif
+
+__inline static U32 rt_inc_qi (U32 size, U8 *count, U8 *first) {
+  U32 cnt,c2;
+#ifdef __USE_EXCLUSIVE_ACCESS
+  do {
+    if ((cnt = __ldrex(count)) == size) {
+      __clrex();
+      return (cnt); }
+  } while (__strex(cnt+1, count));
+  do {
+    c2 = (cnt = __ldrex(first)) + 1;
+    if (c2 == size) c2 = 0;
+  } while (__strex(c2, first));
+#else
+  __disable_irq();
+  if ((cnt = *count) < size) {
+    *count = cnt+1;
+    c2 = (cnt = *first) + 1;
+    if (c2 == size) c2 = 0;
+    *first = c2; 
+  }
+  __enable_irq ();
+#endif
+  return (cnt);
+}
+
+__inline static void rt_systick_init (void) {
+  NVIC_ST_RELOAD  = os_trv;
+  NVIC_ST_CURRENT = 0;
+  NVIC_ST_CTRL    = 0x0007;
+  NVIC_SYS_PRI3  |= 0xFF000000;
+}
+
+__inline static void rt_svc_init (void) {
+#if !(__TARGET_ARCH_6S_M)
+  int sh,prigroup;
+#endif
+  NVIC_SYS_PRI3 |= 0x00FF0000;
+#if (__TARGET_ARCH_6S_M)
+  NVIC_SYS_PRI2 |= (NVIC_SYS_PRI3<<(8+1)) & 0xFC000000;
+#else
+  sh       = 8 - __clz (~((NVIC_SYS_PRI3 << 8) & 0xFF000000));
+  prigroup = ((NVIC_AIR_CTRL >> 8) & 0x07);
+  if (prigroup >= sh) {
+    sh = prigroup + 1;
+  }
+  NVIC_SYS_PRI2 = ((0xFEFFFFFF << sh) & 0xFF000000) | (NVIC_SYS_PRI2 & 0x00FFFFFF);
+#endif
+}
+
+extern void rt_set_PSP (U32 stack);
+extern U32  rt_get_PSP (void);
+extern void os_set_env (void);
+extern void *_alloc_box (void *box_mem);
+extern int  _free_box (void *box_mem, void *box);
+
+extern void rt_init_stack (P_TCB p_TCB, FUNCP task_body);
+extern void rt_ret_val  (P_TCB p_TCB, U32 v0);
+extern void rt_ret_val2 (P_TCB p_TCB, U32 v0, U32 v1);
+
+extern void dbg_init (void);
+extern void dbg_task_notify (P_TCB p_tcb, BOOL create);
+extern void dbg_task_switch (U32 task_id);
+
+#ifdef DBG_MSG
+#define DBG_INIT() dbg_init()
+#define DBG_TASK_NOTIFY(p_tcb,create) if (dbg_msg) dbg_task_notify(p_tcb,create)
+#define DBG_TASK_SWITCH(task_id)      if (dbg_msg && (os_tsk.new_tsk != os_tsk.run)) \
+                                                   dbg_task_switch(task_id)
+#else
+#define DBG_INIT()
+#define DBG_TASK_NOTIFY(p_tcb,create)
+#define DBG_TASK_SWITCH(task_id)
+#endif
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/rt_List.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,320 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    RT_LIST.C
+ *      Purpose: Functions for the management of different lists
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#include "rt_TypeDef.h"
+#include "RTX_Config.h"
+#include "rt_System.h"
+#include "rt_List.h"
+#include "rt_Task.h"
+#include "rt_Time.h"
+#include "rt_HAL_CM.h"
+
+/*----------------------------------------------------------------------------
+ *      Global Variables
+ *---------------------------------------------------------------------------*/
+
+/* List head of chained ready tasks */
+struct OS_XCB  os_rdy;
+/* List head of chained delay tasks */
+struct OS_XCB  os_dly;
+
+
+/*----------------------------------------------------------------------------
+ *      Functions
+ *---------------------------------------------------------------------------*/
+
+
+/*--------------------------- rt_put_prio -----------------------------------*/
+
+void rt_put_prio (P_XCB p_CB, P_TCB p_task) {
+  /* Put task identified with "p_task" into list ordered by priority.       */
+  /* "p_CB" points to head of list; list has always an element at end with  */
+  /* a priority less than "p_task->prio".                                   */
+  P_TCB p_CB2;
+  U32 prio;
+  BOOL sem_mbx = __FALSE;
+
+  if (p_CB->cb_type == SCB || p_CB->cb_type == MCB || p_CB->cb_type == MUCB) {
+    sem_mbx = __TRUE;
+  }
+  prio = p_task->prio;
+  p_CB2 = p_CB->p_lnk;
+  /* Search for an entry in the list */
+  while (p_CB2 != NULL && prio <= p_CB2->prio) {
+    p_CB = (P_XCB)p_CB2;
+    p_CB2 = p_CB2->p_lnk;
+  }
+  /* Entry found, insert the task into the list */
+  p_task->p_lnk = p_CB2;
+  p_CB->p_lnk = p_task;
+  if (sem_mbx) {
+    if (p_CB2 != NULL) {
+      p_CB2->p_rlnk = p_task;
+    }
+    p_task->p_rlnk = (P_TCB)p_CB;
+  }
+  else {
+    p_task->p_rlnk = NULL;
+  }
+}
+
+
+/*--------------------------- rt_get_first ----------------------------------*/
+
+P_TCB rt_get_first (P_XCB p_CB) {
+  /* Get task at head of list: it is the task with highest priority. */
+  /* "p_CB" points to head of list. */
+  P_TCB p_first;
+
+  p_first = p_CB->p_lnk;
+  p_CB->p_lnk = p_first->p_lnk;
+  if (p_CB->cb_type == SCB || p_CB->cb_type == MCB || p_CB->cb_type == MUCB) {
+    if (p_first->p_lnk != NULL) {
+      p_first->p_lnk->p_rlnk = (P_TCB)p_CB;
+      p_first->p_lnk = NULL;
+    }
+    p_first->p_rlnk = NULL;
+  }
+  else {
+    p_first->p_lnk = NULL;
+  }
+  return (p_first);
+}
+
+
+/*--------------------------- rt_put_rdy_first ------------------------------*/
+
+void rt_put_rdy_first (P_TCB p_task) {
+  /* Put task identified with "p_task" at the head of the ready list. The   */
+  /* task must have at least a priority equal to highest priority in list.  */
+  p_task->p_lnk = os_rdy.p_lnk;
+  p_task->p_rlnk = NULL;
+  os_rdy.p_lnk = p_task;
+}
+
+
+/*--------------------------- rt_get_same_rdy_prio --------------------------*/
+
+P_TCB rt_get_same_rdy_prio (void) {
+  /* Remove a task of same priority from ready list if any exists. Other-   */
+  /* wise return NULL.                                                      */
+  P_TCB p_first;
+
+  p_first = os_rdy.p_lnk;
+  if (p_first->prio == os_tsk.run->prio) {
+    os_rdy.p_lnk = os_rdy.p_lnk->p_lnk;
+    return (p_first);
+  }
+  return (NULL);
+}
+
+
+/*--------------------------- rt_resort_prio --------------------------------*/
+
+void rt_resort_prio (P_TCB p_task) {
+  /* Re-sort ordered lists after the priority of 'p_task' has changed.      */
+  P_TCB p_CB;
+
+  if (p_task->p_rlnk == NULL) {
+    if (p_task->state == READY) {
+      /* Task is chained into READY list. */
+      p_CB = (P_TCB)&os_rdy;
+      goto res;
+    }
+  }
+  else {
+    p_CB = p_task->p_rlnk;
+    while (p_CB->cb_type == TCB) {
+      /* Find a header of this task chain list. */
+      p_CB = p_CB->p_rlnk;
+    }
+res:rt_rmv_list (p_task);
+    rt_put_prio ((P_XCB)p_CB, p_task);
+  }
+}
+
+
+/*--------------------------- rt_put_dly ------------------------------------*/
+
+void rt_put_dly (P_TCB p_task, U16 delay) {
+  /* Put a task identified with "p_task" into chained delay wait list using */
+  /* a delay value of "delay".                                              */
+  P_TCB p;
+  U32 delta,idelay = delay;
+
+  p = (P_TCB)&os_dly;
+  if (p->p_dlnk == NULL) {
+    /* Delay list empty */
+    delta = 0;
+    goto last;
+  }
+  delta = os_dly.delta_time;
+  while (delta < idelay) {
+    if (p->p_dlnk == NULL) {
+      /* End of list found */
+last: p_task->p_dlnk = NULL;
+      p->p_dlnk = p_task;
+      p_task->p_blnk = p;
+      p->delta_time = (U16)(idelay - delta);
+      p_task->delta_time = 0;
+      return;
+    }
+    p = p->p_dlnk;
+    delta += p->delta_time;
+  }
+  /* Right place found */
+  p_task->p_dlnk = p->p_dlnk;
+  p->p_dlnk = p_task;
+  p_task->p_blnk = p;
+  if (p_task->p_dlnk != NULL) {
+    p_task->p_dlnk->p_blnk = p_task;
+  }
+  p_task->delta_time = (U16)(delta - idelay);
+  p->delta_time -= p_task->delta_time;
+}
+
+
+/*--------------------------- rt_dec_dly ------------------------------------*/
+
+void rt_dec_dly (void) {
+  /* Decrement delta time of list head: remove tasks having a value of zero.*/
+  P_TCB p_rdy;
+
+  if (os_dly.p_dlnk == NULL) {
+    return;
+  }
+  os_dly.delta_time--;
+  while ((os_dly.delta_time == 0) && (os_dly.p_dlnk != NULL)) {
+    p_rdy = os_dly.p_dlnk;
+    if (p_rdy->p_rlnk != NULL) {
+      /* Task is really enqueued, remove task from semaphore/mailbox */
+      /* timeout waiting list. */
+      p_rdy->p_rlnk->p_lnk = p_rdy->p_lnk;
+      if (p_rdy->p_lnk != NULL) {
+        p_rdy->p_lnk->p_rlnk = p_rdy->p_rlnk;
+        p_rdy->p_lnk = NULL;
+      }
+      p_rdy->p_rlnk = NULL;
+    }
+    rt_put_prio (&os_rdy, p_rdy);
+    os_dly.delta_time = p_rdy->delta_time;
+    if (p_rdy->state == WAIT_ITV) {
+      /* Calculate the next time for interval wait. */
+      p_rdy->delta_time = p_rdy->interval_time + (U16)os_time;
+    }
+    p_rdy->state   = READY;
+    os_dly.p_dlnk = p_rdy->p_dlnk;
+    if (p_rdy->p_dlnk != NULL) {
+      p_rdy->p_dlnk->p_blnk =  (P_TCB)&os_dly;
+      p_rdy->p_dlnk = NULL;
+    }
+    p_rdy->p_blnk = NULL;
+  }
+}
+
+
+/*--------------------------- rt_rmv_list -----------------------------------*/
+
+void rt_rmv_list (P_TCB p_task) {
+  /* Remove task identified with "p_task" from ready, semaphore or mailbox  */
+  /* waiting list if enqueued.                                              */
+  P_TCB p_b;
+
+  if (p_task->p_rlnk != NULL) {
+    /* A task is enqueued in semaphore / mailbox waiting list. */
+    p_task->p_rlnk->p_lnk = p_task->p_lnk;
+    if (p_task->p_lnk != NULL) {
+      p_task->p_lnk->p_rlnk = p_task->p_rlnk;
+    }
+    return;
+  }
+
+  p_b = (P_TCB)&os_rdy;
+  while (p_b != NULL) {
+    /* Search the ready list for task "p_task" */
+    if (p_b->p_lnk == p_task) {
+      p_b->p_lnk = p_task->p_lnk;
+      return;
+    }
+    p_b = p_b->p_lnk;
+  }
+}
+
+
+/*--------------------------- rt_rmv_dly ------------------------------------*/
+
+void rt_rmv_dly (P_TCB p_task) {
+  /* Remove task identified with "p_task" from delay list if enqueued.      */
+  P_TCB p_b;
+
+  p_b = p_task->p_blnk;
+  if (p_b != NULL) {
+    /* Task is really enqueued */
+    p_b->p_dlnk = p_task->p_dlnk;
+    if (p_task->p_dlnk != NULL) {
+      /* 'p_task' is in the middle of list */
+      p_b->delta_time += p_task->delta_time;
+      p_task->p_dlnk->p_blnk = p_b;
+      p_task->p_dlnk = NULL;
+    }
+    else {
+      /* 'p_task' is at the end of list */
+      p_b->delta_time = 0;
+    }
+    p_task->p_blnk = NULL;
+  }
+}
+
+
+/*--------------------------- rt_psq_enq ------------------------------------*/
+
+void rt_psq_enq (OS_ID entry, U32 arg) {
+  /* Insert post service request "entry" into ps-queue. */
+  U32 idx;
+
+  idx = rt_inc_qi (os_psq->size, &os_psq->count, &os_psq->first);
+  if (idx < os_psq->size) {
+    os_psq->q[idx].id  = entry;
+    os_psq->q[idx].arg = arg;
+  }
+  else {
+    os_error (OS_ERR_FIFO_OVF);
+  }
+}
+
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/rt_List.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,67 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    RT_LIST.H
+ *      Purpose: Functions for the management of different lists
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+/* Definitions */
+
+/* Values for 'cb_type' */
+#define TCB             0
+#define MCB             1
+#define SCB             2
+#define MUCB            3
+#define HCB             4
+
+/* Variables */
+extern struct OS_XCB os_rdy;
+extern struct OS_XCB os_dly;
+
+/* Functions */
+extern void  rt_put_prio      (P_XCB p_CB, P_TCB p_task);
+extern P_TCB rt_get_first     (P_XCB p_CB);
+extern void  rt_put_rdy_first (P_TCB p_task);
+extern P_TCB rt_get_same_rdy_prio (void);
+extern void  rt_resort_prio   (P_TCB p_task);
+extern void  rt_put_dly       (P_TCB p_task, U16 delay);
+extern void  rt_dec_dly       (void);
+extern void  rt_rmv_list      (P_TCB p_task);
+extern void  rt_rmv_dly       (P_TCB p_task);
+extern void  rt_psq_enq       (OS_ID entry, U32 arg);
+
+/* This is a fast macro generating in-line code */
+#define rt_rdy_prio(void) (os_rdy.p_lnk->prio)
+
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/rt_Mailbox.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,292 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    RT_MAILBOX.C
+ *      Purpose: Implements waits and wake-ups for mailbox messages
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#include "rt_TypeDef.h"
+#include "RTX_Config.h"
+#include "rt_System.h"
+#include "rt_List.h"
+#include "rt_Mailbox.h"
+#include "rt_MemBox.h"
+#include "rt_Task.h"
+#include "rt_HAL_CM.h"
+
+
+/*----------------------------------------------------------------------------
+ *      Functions
+ *---------------------------------------------------------------------------*/
+
+
+/*--------------------------- rt_mbx_init -----------------------------------*/
+
+void rt_mbx_init (OS_ID mailbox, U16 mbx_size) {
+  /* Initialize a mailbox */
+  P_MCB p_MCB = mailbox;
+
+  p_MCB->cb_type = MCB;
+  p_MCB->state   = 0;
+  p_MCB->isr_st  = 0;
+  p_MCB->p_lnk   = NULL;
+  p_MCB->first   = 0;
+  p_MCB->last    = 0;
+  p_MCB->count   = 0;
+  p_MCB->size    = (mbx_size + sizeof(void *) - sizeof(struct OS_MCB)) /
+                                                     (U32)sizeof (void *);
+}
+
+
+/*--------------------------- rt_mbx_send -----------------------------------*/
+
+OS_RESULT rt_mbx_send (OS_ID mailbox, void *p_msg, U16 timeout) {
+  /* Send message to a mailbox */
+  P_MCB p_MCB = mailbox;
+  P_TCB p_TCB;
+
+  if ((p_MCB->p_lnk != NULL) && (p_MCB->state == 1)) {
+    /* A task is waiting for message */
+    p_TCB = rt_get_first ((P_XCB)p_MCB);
+#ifdef __CMSIS_RTOS
+    rt_ret_val2(p_TCB, 0x10/*osEventMessage*/, (U32)p_msg);
+#else
+    *p_TCB->msg = p_msg;
+    rt_ret_val (p_TCB, OS_R_MBX);
+#endif
+    rt_rmv_dly (p_TCB);
+    rt_dispatch (p_TCB);
+  }
+  else {
+    /* Store message in mailbox queue */
+    if (p_MCB->count == p_MCB->size) {
+      /* No free message entry, wait for one. If message queue is full, */
+      /* then no task is waiting for message. The 'p_MCB->p_lnk' list   */
+      /* pointer can now be reused for send message waits task list.    */
+      if (timeout == 0) {
+        return (OS_R_TMO);
+      }
+      if (p_MCB->p_lnk != NULL) {
+        rt_put_prio ((P_XCB)p_MCB, os_tsk.run);
+      }
+      else {
+        p_MCB->p_lnk = os_tsk.run;
+        os_tsk.run->p_lnk  = NULL;
+        os_tsk.run->p_rlnk = (P_TCB)p_MCB;
+        /* Task is waiting to send a message */      
+        p_MCB->state = 2;
+      }
+      os_tsk.run->msg = p_msg;
+      rt_block (timeout, WAIT_MBX);
+      return (OS_R_TMO);
+    }
+    /* Yes, there is a free entry in a mailbox. */
+    p_MCB->msg[p_MCB->first] = p_msg;
+    rt_inc (&p_MCB->count);
+    if (++p_MCB->first == p_MCB->size) {
+      p_MCB->first = 0;
+    }
+  }
+  return (OS_R_OK);
+}
+
+
+/*--------------------------- rt_mbx_wait -----------------------------------*/
+
+OS_RESULT rt_mbx_wait (OS_ID mailbox, void **message, U16 timeout) {
+  /* Receive a message; possibly wait for it */
+  P_MCB p_MCB = mailbox;
+  P_TCB p_TCB;
+
+  /* If a message is available in the fifo buffer */
+  /* remove it from the fifo buffer and return. */
+  if (p_MCB->count) {
+    *message = p_MCB->msg[p_MCB->last];
+    if (++p_MCB->last == p_MCB->size) {
+      p_MCB->last = 0;
+    }
+    if ((p_MCB->p_lnk != NULL) && (p_MCB->state == 2)) {
+      /* A task is waiting to send message */
+      p_TCB = rt_get_first ((P_XCB)p_MCB);
+#ifdef __CMSIS_RTOS
+      rt_ret_val(p_TCB, 0/*osOK*/);
+#else
+      rt_ret_val(p_TCB, OS_R_OK);
+#endif
+      p_MCB->msg[p_MCB->first] = p_TCB->msg;
+      if (++p_MCB->first == p_MCB->size) {
+        p_MCB->first = 0;
+      }
+      rt_rmv_dly (p_TCB);
+      rt_dispatch (p_TCB);
+    }
+    else {
+      rt_dec (&p_MCB->count);
+    }
+    return (OS_R_OK);
+  }
+  /* No message available: wait for one */
+  if (timeout == 0) {
+    return (OS_R_TMO);
+  }
+  if (p_MCB->p_lnk != NULL) {
+    rt_put_prio ((P_XCB)p_MCB, os_tsk.run);
+  }
+  else {
+    p_MCB->p_lnk = os_tsk.run;
+    os_tsk.run->p_lnk = NULL;
+    os_tsk.run->p_rlnk = (P_TCB)p_MCB;
+    /* Task is waiting to receive a message */      
+    p_MCB->state = 1;
+  }
+  rt_block(timeout, WAIT_MBX);
+#ifndef __CMSIS_RTOS
+  os_tsk.run->msg = message;
+#endif
+  return (OS_R_TMO);
+}
+
+
+/*--------------------------- rt_mbx_check ----------------------------------*/
+
+OS_RESULT rt_mbx_check (OS_ID mailbox) {
+  /* Check for free space in a mailbox. Returns the number of messages     */
+  /* that can be stored to a mailbox. It returns 0 when mailbox is full.   */
+  P_MCB p_MCB = mailbox;
+
+  return (p_MCB->size - p_MCB->count);
+}
+
+
+/*--------------------------- isr_mbx_send ----------------------------------*/
+
+void isr_mbx_send (OS_ID mailbox, void *p_msg) {
+  /* Same function as "os_mbx_send", but to be called by ISRs. */
+  P_MCB p_MCB = mailbox;
+
+  rt_psq_enq (p_MCB, (U32)p_msg);
+  rt_psh_req ();
+}
+
+
+/*--------------------------- isr_mbx_receive -------------------------------*/
+
+OS_RESULT isr_mbx_receive (OS_ID mailbox, void **message) {
+  /* Receive a message in the interrupt function. The interrupt function   */
+  /* should not wait for a message since this would block the rtx os.      */
+  P_MCB p_MCB = mailbox;
+
+  if (p_MCB->count) {
+    /* A message is available in the fifo buffer. */
+    *message = p_MCB->msg[p_MCB->last];
+    if (p_MCB->state == 2) {
+      /* A task is locked waiting to send message */
+      rt_psq_enq (p_MCB, 0);
+      rt_psh_req ();
+    }
+    rt_dec (&p_MCB->count);
+    if (++p_MCB->last == p_MCB->size) {
+      p_MCB->last = 0;
+    }
+    return (OS_R_MBX);
+  }
+  return (OS_R_OK);
+}
+
+
+/*--------------------------- rt_mbx_psh ------------------------------------*/
+
+void rt_mbx_psh (P_MCB p_CB, void *p_msg) {
+  /* Store the message to the mailbox queue or pass it to task directly. */
+  P_TCB p_TCB;
+  void *mem;
+
+  if (p_CB->p_lnk != NULL) switch (p_CB->state) {
+#ifdef __CMSIS_RTOS
+    case 3:
+      /* Task is waiting to allocate memory, remove it from the waiting list */
+      mem = rt_alloc_box(p_msg);
+      if (mem == NULL) break;
+      p_TCB = rt_get_first ((P_XCB)p_CB);
+      rt_ret_val(p_TCB, (U32)mem);
+      p_TCB->state = READY;
+      rt_rmv_dly (p_TCB);
+      rt_put_prio (&os_rdy, p_TCB);
+      break;
+#endif
+    case 2:
+      /* Task is waiting to send a message, remove it from the waiting list */
+      p_TCB = rt_get_first ((P_XCB)p_CB);
+#ifdef __CMSIS_RTOS
+      rt_ret_val(p_TCB, 0/*osOK*/);
+#else
+      rt_ret_val(p_TCB, OS_R_OK);
+#endif
+      p_CB->msg[p_CB->first] = p_TCB->msg;
+      rt_inc (&p_CB->count);
+      if (++p_CB->first == p_CB->size) {
+        p_CB->first = 0;
+      }
+      p_TCB->state = READY;
+      rt_rmv_dly (p_TCB);
+      rt_put_prio (&os_rdy, p_TCB);
+      break;
+    case 1:
+      /* Task is waiting for a message, pass the message to the task directly */
+      p_TCB = rt_get_first ((P_XCB)p_CB);
+#ifdef __CMSIS_RTOS
+      rt_ret_val2(p_TCB, 0x10/*osEventMessage*/, (U32)p_msg);
+#else
+      *p_TCB->msg = p_msg;
+      rt_ret_val (p_TCB, OS_R_MBX);
+#endif
+      p_TCB->state = READY;
+      rt_rmv_dly (p_TCB);
+      rt_put_prio (&os_rdy, p_TCB);
+      break;
+  } else {
+      /* No task is waiting for a message, store it to the mailbox queue */
+      if (p_CB->count < p_CB->size) {
+        p_CB->msg[p_CB->first] = p_msg;
+        rt_inc (&p_CB->count);
+        if (++p_CB->first == p_CB->size) {
+          p_CB->first = 0;
+        }
+      }
+      else {
+        os_error (OS_ERR_MBX_OVF);
+      }
+  }
+}
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/rt_Mailbox.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,48 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    RT_MAILBOX.H
+ *      Purpose: Implements waits and wake-ups for mailbox messages
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+/* Functions */
+extern void      rt_mbx_init  (OS_ID mailbox, U16 mbx_size);
+extern OS_RESULT rt_mbx_send  (OS_ID mailbox, void *p_msg,    U16 timeout);
+extern OS_RESULT rt_mbx_wait  (OS_ID mailbox, void **message, U16 timeout);
+extern OS_RESULT rt_mbx_check (OS_ID mailbox);
+extern void      isr_mbx_send (OS_ID mailbox, void *p_msg);
+extern OS_RESULT isr_mbx_receive (OS_ID mailbox, void **message);
+extern void      rt_mbx_psh   (P_MCB p_CB,    void *p_msg);
+
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/rt_MemBox.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,166 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    RT_MEMBOX.C
+ *      Purpose: Interface functions for fixed memory block management system
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#include "rt_TypeDef.h"
+#include "RTX_Config.h"
+#include "rt_System.h"
+#include "rt_MemBox.h"
+#include "rt_HAL_CM.h"
+
+/*----------------------------------------------------------------------------
+ *      Global Functions
+ *---------------------------------------------------------------------------*/
+
+
+/*--------------------------- _init_box -------------------------------------*/
+
+int _init_box  (void *box_mem, U32 box_size, U32 blk_size) {
+  /* Initialize memory block system, returns 0 if OK, 1 if fails. */
+  void *end;
+  void *blk;
+  void *next;
+  U32  sizeof_bm;
+
+  /* Create memory structure. */
+  if (blk_size & BOX_ALIGN_8) {
+    /* Memory blocks 8-byte aligned. */ 
+    blk_size = ((blk_size & ~BOX_ALIGN_8) + 7) & ~7;
+    sizeof_bm = (sizeof (struct OS_BM) + 7) & ~7;
+  }
+  else {
+    /* Memory blocks 4-byte aligned. */
+    blk_size = (blk_size + 3) & ~3;
+    sizeof_bm = sizeof (struct OS_BM);
+  }
+  if (blk_size == 0) {
+    return (1);
+  }
+  if ((blk_size + sizeof_bm) > box_size) {
+    return (1);
+  }
+  /* Create a Memory structure. */
+  blk = ((U8 *) box_mem) + sizeof_bm;
+  ((P_BM) box_mem)->free = blk;
+  end = ((U8 *) box_mem) + box_size;
+  ((P_BM) box_mem)->end      = end;
+  ((P_BM) box_mem)->blk_size = blk_size;
+
+  /* Link all free blocks using offsets. */
+  end = ((U8 *) end) - blk_size;
+  while (1)  {
+    next = ((U8 *) blk) + blk_size;
+    if (next > end)  break;
+    *((void **)blk) = next;
+    blk = next;
+  }
+  /* end marker */
+  *((void **)blk) = 0;
+  return (0);
+}
+
+/*--------------------------- rt_alloc_box ----------------------------------*/
+
+void *rt_alloc_box (void *box_mem) {
+  /* Allocate a memory block and return start address. */
+  void **free;
+#ifndef __USE_EXCLUSIVE_ACCESS
+  int  irq_dis;
+
+  irq_dis = __disable_irq ();
+  free = ((P_BM) box_mem)->free;
+  if (free) {
+    ((P_BM) box_mem)->free = *free;
+  }
+  if (!irq_dis) __enable_irq ();
+#else
+  do {
+    if ((free = (void **)__ldrex(&((P_BM) box_mem)->free)) == 0) {
+      __clrex();
+      break;
+    }
+  } while (__strex((U32)*free, &((P_BM) box_mem)->free));
+#endif
+  return (free);
+}
+
+
+/*--------------------------- _calloc_box -----------------------------------*/
+
+void *_calloc_box (void *box_mem)  {
+  /* Allocate a 0-initialized memory block and return start address. */
+  void *free;
+  U32 *p;
+  U32 i;
+
+  free = _alloc_box (box_mem);
+  if (free)  {
+    p = free;
+    for (i = ((P_BM) box_mem)->blk_size; i; i -= 4)  {
+      *p = 0;
+      p++;
+    }
+  }
+  return (free);
+}
+
+
+/*--------------------------- rt_free_box -----------------------------------*/
+
+int rt_free_box (void *box_mem, void *box) {
+  /* Free a memory block, returns 0 if OK, 1 if box does not belong to box_mem */
+#ifndef __USE_EXCLUSIVE_ACCESS
+  int irq_dis;
+#endif
+
+  if (box < box_mem || box >= ((P_BM) box_mem)->end) {
+    return (1);
+  }
+
+#ifndef __USE_EXCLUSIVE_ACCESS
+  irq_dis = __disable_irq ();
+  *((void **)box) = ((P_BM) box_mem)->free;
+  ((P_BM) box_mem)->free = box;
+  if (!irq_dis) __enable_irq ();
+#else
+  do {
+    *((void **)box) = (void *)__ldrex(&((P_BM) box_mem)->free);
+  } while (__strex ((U32)box, &((P_BM) box_mem)->free));
+#endif
+  return (0);
+}
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/rt_MemBox.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,46 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    RT_MEMBOX.H
+ *      Purpose: Interface functions for fixed memory block management system
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+/* Functions */
+#define rt_init_box     _init_box
+#define rt_calloc_box   _calloc_box
+extern int     _init_box   (void *box_mem, U32 box_size, U32 blk_size);
+extern void *rt_alloc_box  (void *box_mem);
+extern void *  _calloc_box (void *box_mem);
+extern int   rt_free_box   (void *box_mem, void *box);
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/rt_Mutex.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,197 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    RT_MUTEX.C
+ *      Purpose: Implements mutex synchronization objects
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#include "rt_TypeDef.h"
+#include "RTX_Config.h"
+#include "rt_List.h"
+#include "rt_Task.h"
+#include "rt_Mutex.h"
+#include "rt_HAL_CM.h"
+
+
+/*----------------------------------------------------------------------------
+ *      Functions
+ *---------------------------------------------------------------------------*/
+
+
+/*--------------------------- rt_mut_init -----------------------------------*/
+
+void rt_mut_init (OS_ID mutex) {
+  /* Initialize a mutex object */
+  P_MUCB p_MCB = mutex;
+
+  p_MCB->cb_type = MUCB;
+  p_MCB->prio    = 0;
+  p_MCB->level   = 0;
+  p_MCB->p_lnk   = NULL;
+  p_MCB->owner   = NULL;
+}
+
+
+/*--------------------------- rt_mut_delete ---------------------------------*/
+
+#ifdef __CMSIS_RTOS
+OS_RESULT rt_mut_delete (OS_ID mutex) {
+  /* Delete a mutex object */
+  P_MUCB p_MCB = mutex;
+  P_TCB  p_TCB;
+
+  /* Restore owner task's priority. */
+  if (p_MCB->level != 0) {
+    p_MCB->owner->prio = p_MCB->prio;
+    if (p_MCB->owner != os_tsk.run) {
+      rt_resort_prio (p_MCB->owner);
+    }
+  }
+
+  while (p_MCB->p_lnk != NULL) {
+    /* A task is waiting for mutex. */
+    p_TCB = rt_get_first ((P_XCB)p_MCB);
+    rt_ret_val(p_TCB, 0/*osOK*/);
+    rt_rmv_dly(p_TCB);
+    p_TCB->state = READY;
+    rt_put_prio (&os_rdy, p_TCB);
+  }
+
+  if (os_rdy.p_lnk && (os_rdy.p_lnk->prio > os_tsk.run->prio)) {
+    /* preempt running task */
+    rt_put_prio (&os_rdy, os_tsk.run);
+    os_tsk.run->state = READY;
+    rt_dispatch (NULL);
+  }
+
+  p_MCB->cb_type = 0;
+
+  return (OS_R_OK);
+}
+#endif
+
+
+/*--------------------------- rt_mut_release --------------------------------*/
+
+OS_RESULT rt_mut_release (OS_ID mutex) {
+  /* Release a mutex object */
+  P_MUCB p_MCB = mutex;
+  P_TCB  p_TCB;
+
+  if (p_MCB->level == 0 || p_MCB->owner != os_tsk.run) {
+    /* Unbalanced mutex release or task is not the owner */
+    return (OS_R_NOK);
+  }
+  if (--p_MCB->level != 0) {
+    return (OS_R_OK);
+  }
+  /* Restore owner task's priority. */
+  os_tsk.run->prio = p_MCB->prio;
+  if (p_MCB->p_lnk != NULL) {
+    /* A task is waiting for mutex. */
+    p_TCB = rt_get_first ((P_XCB)p_MCB);
+#ifdef __CMSIS_RTOS
+    rt_ret_val(p_TCB, 0/*osOK*/);
+#else
+    rt_ret_val(p_TCB, OS_R_MUT); 
+#endif
+    rt_rmv_dly (p_TCB);
+    /* A waiting task becomes the owner of this mutex. */
+    p_MCB->level     = 1;
+    p_MCB->owner     = p_TCB;
+    p_MCB->prio      = p_TCB->prio;
+    /* Priority inversion, check which task continues. */
+    if (os_tsk.run->prio >= rt_rdy_prio()) {
+      rt_dispatch (p_TCB);
+    }
+    else {
+      /* Ready task has higher priority than running task. */
+      rt_put_prio (&os_rdy, os_tsk.run);
+      rt_put_prio (&os_rdy, p_TCB);
+      os_tsk.run->state = READY;
+      p_TCB->state      = READY;
+      rt_dispatch (NULL);
+    }
+  }
+  else {
+    /* Check if own priority raised by priority inversion. */
+    if (rt_rdy_prio() > os_tsk.run->prio) {
+      rt_put_prio (&os_rdy, os_tsk.run);
+      os_tsk.run->state = READY;
+      rt_dispatch (NULL);
+    }
+  }
+  return (OS_R_OK);
+}
+
+
+/*--------------------------- rt_mut_wait -----------------------------------*/
+
+OS_RESULT rt_mut_wait (OS_ID mutex, U16 timeout) {
+  /* Wait for a mutex, continue when mutex is free. */
+  P_MUCB p_MCB = mutex;
+
+  if (p_MCB->level == 0) {
+    p_MCB->owner = os_tsk.run;
+    p_MCB->prio  = os_tsk.run->prio;
+    goto inc;
+  }
+  if (p_MCB->owner == os_tsk.run) {
+    /* OK, running task is the owner of this mutex. */
+inc:p_MCB->level++;
+    return (OS_R_OK);
+  }
+  /* Mutex owned by another task, wait until released. */
+  if (timeout == 0) {
+    return (OS_R_TMO);
+  }
+  /* Raise the owner task priority if lower than current priority. */
+  /* This priority inversion is called priority inheritance.       */
+  if (p_MCB->prio < os_tsk.run->prio) {
+    p_MCB->owner->prio = os_tsk.run->prio;
+    rt_resort_prio (p_MCB->owner);
+  }
+  if (p_MCB->p_lnk != NULL) {
+    rt_put_prio ((P_XCB)p_MCB, os_tsk.run);
+  }
+  else {
+    p_MCB->p_lnk = os_tsk.run;
+    os_tsk.run->p_lnk  = NULL;
+    os_tsk.run->p_rlnk = (P_TCB)p_MCB;
+  }
+  rt_block(timeout, WAIT_MUT);
+  return (OS_R_TMO);
+}
+
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/rt_Mutex.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,44 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    RT_MUTEX.H
+ *      Purpose: Implements mutex synchronization objects
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+/* Functions */
+extern void      rt_mut_init    (OS_ID mutex);
+extern OS_RESULT rt_mut_delete  (OS_ID mutex);
+extern OS_RESULT rt_mut_release (OS_ID mutex);
+extern OS_RESULT rt_mut_wait    (OS_ID mutex, U16 timeout);
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/rt_Robin.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,84 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    RT_ROBIN.C
+ *      Purpose: Round Robin Task switching
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#include "rt_TypeDef.h"
+#include "RTX_Config.h"
+#include "rt_List.h"
+#include "rt_Task.h"
+#include "rt_Time.h"
+#include "rt_Robin.h"
+#include "rt_HAL_CM.h"
+
+/*----------------------------------------------------------------------------
+ *      Global Variables
+ *---------------------------------------------------------------------------*/
+
+struct OS_ROBIN os_robin;
+
+
+/*----------------------------------------------------------------------------
+ *      Global Functions
+ *---------------------------------------------------------------------------*/
+
+/*--------------------------- rt_init_robin ---------------------------------*/
+
+__weak void rt_init_robin (void) {
+  /* Initialize Round Robin variables. */
+  os_robin.task = NULL;
+  os_robin.tout = (U16)os_rrobin;
+}
+
+/*--------------------------- rt_chk_robin ----------------------------------*/
+
+__weak void rt_chk_robin (void) {
+  /* Check if Round Robin timeout expired and switch to the next ready task.*/
+  P_TCB p_new;
+
+  if (os_robin.task != os_rdy.p_lnk) {
+    /* New task was suspended, reset Round Robin timeout. */
+    os_robin.task = os_rdy.p_lnk;
+    os_robin.time = (U16)os_time + os_robin.tout - 1;
+  }
+  if (os_robin.time == (U16)os_time) {
+    /* Round Robin timeout has expired, swap Robin tasks. */
+    os_robin.task = NULL;
+    p_new = rt_get_first (&os_rdy);
+    rt_put_prio ((P_XCB)&os_rdy, p_new);
+  }
+}
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/rt_Robin.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,45 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    RT_ROBIN.H
+ *      Purpose: Round Robin Task switching definitions
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+/* Variables */
+extern struct OS_ROBIN os_robin;
+
+/* Functions */
+extern void rt_init_robin (void);
+extern void rt_chk_robin  (void);
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/rt_Semaphore.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,183 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    RT_SEMAPHORE.C
+ *      Purpose: Implements binary and counting semaphores
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#include "rt_TypeDef.h"
+#include "RTX_Config.h"
+#include "rt_System.h"
+#include "rt_List.h"
+#include "rt_Task.h"
+#include "rt_Semaphore.h"
+#include "rt_HAL_CM.h"
+
+
+/*----------------------------------------------------------------------------
+ *      Functions
+ *---------------------------------------------------------------------------*/
+
+
+/*--------------------------- rt_sem_init -----------------------------------*/
+
+void rt_sem_init (OS_ID semaphore, U16 token_count) {
+  /* Initialize a semaphore */
+  P_SCB p_SCB = semaphore;
+
+  p_SCB->cb_type = SCB;
+  p_SCB->p_lnk  = NULL;
+  p_SCB->tokens = token_count;
+}
+
+
+/*--------------------------- rt_sem_delete ---------------------------------*/
+
+#ifdef __CMSIS_RTOS
+OS_RESULT rt_sem_delete (OS_ID semaphore) {
+  /* Delete semaphore */
+  P_SCB p_SCB = semaphore;
+  P_TCB p_TCB;
+
+  while (p_SCB->p_lnk != NULL) {
+    /* A task is waiting for token */
+    p_TCB = rt_get_first ((P_XCB)p_SCB);
+    rt_ret_val(p_TCB, 0);
+    rt_rmv_dly(p_TCB);
+    p_TCB->state = READY;
+    rt_put_prio (&os_rdy, p_TCB);
+  }
+
+  if (os_rdy.p_lnk && (os_rdy.p_lnk->prio > os_tsk.run->prio)) {
+    /* preempt running task */
+    rt_put_prio (&os_rdy, os_tsk.run);
+    os_tsk.run->state = READY;
+    rt_dispatch (NULL);
+  }
+
+  p_SCB->cb_type = 0;
+
+  return (OS_R_OK);
+}
+#endif
+
+
+/*--------------------------- rt_sem_send -----------------------------------*/
+
+OS_RESULT rt_sem_send (OS_ID semaphore) {
+  /* Return a token to semaphore */
+  P_SCB p_SCB = semaphore;
+  P_TCB p_TCB;
+
+  if (p_SCB->p_lnk != NULL) {
+    /* A task is waiting for token */
+    p_TCB = rt_get_first ((P_XCB)p_SCB);
+#ifdef __CMSIS_RTOS
+    rt_ret_val(p_TCB, 1);
+#else
+    rt_ret_val(p_TCB, OS_R_SEM);
+#endif
+    rt_rmv_dly (p_TCB);
+    rt_dispatch (p_TCB);
+  }
+  else {
+    /* Store token. */
+    p_SCB->tokens++;
+  }
+  return (OS_R_OK);
+}
+
+
+/*--------------------------- rt_sem_wait -----------------------------------*/
+
+OS_RESULT rt_sem_wait (OS_ID semaphore, U16 timeout) {
+  /* Obtain a token; possibly wait for it */
+  P_SCB p_SCB = semaphore;
+
+  if (p_SCB->tokens) {
+    p_SCB->tokens--;
+    return (OS_R_OK);
+  }
+  /* No token available: wait for one */
+  if (timeout == 0) {
+    return (OS_R_TMO);
+  }
+  if (p_SCB->p_lnk != NULL) {
+    rt_put_prio ((P_XCB)p_SCB, os_tsk.run);
+  }
+  else {
+    p_SCB->p_lnk = os_tsk.run;
+    os_tsk.run->p_lnk = NULL;
+    os_tsk.run->p_rlnk = (P_TCB)p_SCB;
+  }
+  rt_block(timeout, WAIT_SEM);
+  return (OS_R_TMO);
+}
+
+
+/*--------------------------- isr_sem_send ----------------------------------*/
+
+void isr_sem_send (OS_ID semaphore) {
+  /* Same function as "os_sem"send", but to be called by ISRs */
+  P_SCB p_SCB = semaphore;
+
+  rt_psq_enq (p_SCB, 0);
+  rt_psh_req ();
+}
+
+
+/*--------------------------- rt_sem_psh ------------------------------------*/
+
+void rt_sem_psh (P_SCB p_CB) {
+  /* Check if task has to be waken up */
+  P_TCB p_TCB;
+
+  if (p_CB->p_lnk != NULL) {
+    /* A task is waiting for token */
+    p_TCB = rt_get_first ((P_XCB)p_CB);
+    rt_rmv_dly (p_TCB);
+    p_TCB->state   = READY;
+#ifdef __CMSIS_RTOS
+    rt_ret_val(p_TCB, 1);
+#else
+    rt_ret_val(p_TCB, OS_R_SEM);
+#endif
+    rt_put_prio (&os_rdy, p_TCB);
+  }
+  else {
+    /* Store token */
+    p_CB->tokens++;
+  }
+}
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/rt_Semaphore.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,46 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    RT_SEMAPHORE.H
+ *      Purpose: Implements binary and counting semaphores
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+/* Functions */
+extern void      rt_sem_init  (OS_ID semaphore, U16 token_count);
+extern OS_RESULT rt_sem_delete(OS_ID semaphore);
+extern OS_RESULT rt_sem_send  (OS_ID semaphore);
+extern OS_RESULT rt_sem_wait  (OS_ID semaphore, U16 timeout);
+extern void      isr_sem_send (OS_ID semaphore);
+extern void      rt_sem_psh (P_SCB p_CB);
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/rt_System.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,299 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    RT_SYSTEM.C
+ *      Purpose: System Task Manager
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#include "rt_TypeDef.h"
+#include "RTX_Config.h"
+#include "rt_Task.h"
+#include "rt_System.h"
+#include "rt_Event.h"
+#include "rt_List.h"
+#include "rt_Mailbox.h"
+#include "rt_Semaphore.h"
+#include "rt_Time.h"
+#include "rt_Robin.h"
+#include "rt_HAL_CM.h"
+
+/*----------------------------------------------------------------------------
+ *      Global Variables
+ *---------------------------------------------------------------------------*/
+
+int os_tick_irqn;
+
+/*----------------------------------------------------------------------------
+ *      Local Variables
+ *---------------------------------------------------------------------------*/
+
+static volatile BIT os_lock;
+static volatile BIT os_psh_flag;
+static          U8  pend_flags;
+
+/*----------------------------------------------------------------------------
+ *      Global Functions
+ *---------------------------------------------------------------------------*/
+
+#if defined (__CC_ARM)
+__asm void $$RTX$$version (void) {
+   /* Export a version number symbol for a version control. */
+
+                EXPORT  __RL_RTX_VER
+
+__RL_RTX_VER    EQU     0x450
+}
+#endif
+
+
+/*--------------------------- rt_suspend ------------------------------------*/
+U32 rt_suspend (void) {
+  /* Suspend OS scheduler */
+  U32 delta = 0xFFFF;
+  
+  rt_tsk_lock();
+  
+  if (os_dly.p_dlnk) {
+    delta = os_dly.delta_time;
+  }
+#ifndef __CMSIS_RTOS
+  if (os_tmr.next) {
+    if (os_tmr.tcnt < delta) delta = os_tmr.tcnt;
+  }
+#endif
+  
+  return (delta);
+}
+
+
+/*--------------------------- rt_resume -------------------------------------*/
+void rt_resume (U32 sleep_time) {
+  /* Resume OS scheduler after suspend */
+  P_TCB next;
+  U32   delta;
+
+  os_tsk.run->state = READY;
+  rt_put_rdy_first (os_tsk.run);
+
+  os_robin.task = NULL;
+
+  /* Update delays. */
+  if (os_dly.p_dlnk) {
+    delta = sleep_time;
+    if (delta >= os_dly.delta_time) {
+      delta   -= os_dly.delta_time;
+      os_time += os_dly.delta_time;
+      os_dly.delta_time = 1;
+      while (os_dly.p_dlnk) {
+        rt_dec_dly();
+        if (delta == 0) break;
+        delta--;
+        os_time++;
+      }
+    } else {
+      os_time           += delta;
+      os_dly.delta_time -= delta;
+    }
+  } else {
+    os_time += sleep_time;
+  }
+  
+#ifndef __CMSIS_RTOS
+  /* Check the user timers. */
+  if (os_tmr.next) {
+    delta = sleep_time;
+    if (delta >= os_tmr.tcnt) {
+      delta   -= os_tmr.tcnt;
+      os_tmr.tcnt = 1;
+      while (os_tmr.next) {
+        rt_tmr_tick();
+        if (delta == 0) break;
+        delta--;
+      }
+    } else {
+      os_tmr.tcnt -= delta;
+    }
+  }
+#endif
+
+  /* Switch back to highest ready task */
+  next = rt_get_first (&os_rdy);
+  rt_switch_req (next);
+
+  rt_tsk_unlock();
+}
+
+
+/*--------------------------- rt_tsk_lock -----------------------------------*/
+
+void rt_tsk_lock (void) {
+  /* Prevent task switching by locking out scheduler */
+  if (os_tick_irqn < 0) {
+    OS_LOCK();
+    os_lock = __TRUE;
+    OS_UNPEND (&pend_flags);
+  } else {
+    OS_X_LOCK(os_tick_irqn);
+    os_lock = __TRUE;
+    OS_X_UNPEND (&pend_flags);
+  }
+}
+
+
+/*--------------------------- rt_tsk_unlock ---------------------------------*/
+
+void rt_tsk_unlock (void) {
+  /* Unlock scheduler and re-enable task switching */
+  if (os_tick_irqn < 0) {
+    OS_UNLOCK();
+    os_lock = __FALSE;
+    OS_PEND (pend_flags, os_psh_flag);
+    os_psh_flag = __FALSE;
+  } else {
+    OS_X_UNLOCK(os_tick_irqn);
+    os_lock = __FALSE;
+    OS_X_PEND (pend_flags, os_psh_flag);
+    os_psh_flag = __FALSE;
+  }
+}
+
+
+/*--------------------------- rt_psh_req ------------------------------------*/
+
+void rt_psh_req (void) {
+  /* Initiate a post service handling request if required. */
+  if (os_lock == __FALSE) {
+    OS_PEND_IRQ ();
+  }
+  else {
+    os_psh_flag = __TRUE;
+  }
+}
+
+
+/*--------------------------- rt_pop_req ------------------------------------*/
+
+void rt_pop_req (void) {
+  /* Process an ISR post service requests. */
+  struct OS_XCB *p_CB;
+  P_TCB next;
+  U32  idx;
+
+  os_tsk.run->state = READY;
+  rt_put_rdy_first (os_tsk.run);
+
+  idx = os_psq->last;
+  while (os_psq->count) {
+    p_CB = os_psq->q[idx].id;
+    if (p_CB->cb_type == TCB) {
+      /* Is of TCB type */
+      rt_evt_psh ((P_TCB)p_CB, (U16)os_psq->q[idx].arg);
+    }
+    else if (p_CB->cb_type == MCB) {
+      /* Is of MCB type */
+      rt_mbx_psh ((P_MCB)p_CB, (void *)os_psq->q[idx].arg);
+    }
+    else {
+      /* Must be of SCB type */
+      rt_sem_psh ((P_SCB)p_CB);
+    }
+    if (++idx == os_psq->size) idx = 0;
+    rt_dec (&os_psq->count);
+  }
+  os_psq->last = idx;
+
+  next = rt_get_first (&os_rdy);
+  rt_switch_req (next);
+}
+
+
+/*--------------------------- os_tick_init ----------------------------------*/
+
+__weak int os_tick_init (void) {
+  /* Initialize SysTick timer as system tick timer. */
+  rt_systick_init ();
+  return (-1);  /* Return IRQ number of SysTick timer */
+}
+
+
+/*--------------------------- os_tick_irqack --------------------------------*/
+
+__weak void os_tick_irqack (void) {
+  /* Acknowledge timer interrupt. */
+}
+
+
+/*--------------------------- rt_systick ------------------------------------*/
+
+extern void sysTimerTick(void);
+
+void rt_systick (void) {
+  /* Check for system clock update, suspend running task. */
+  P_TCB next;
+
+  os_tsk.run->state = READY;
+  rt_put_rdy_first (os_tsk.run);
+
+  /* Check Round Robin timeout. */
+  rt_chk_robin ();
+
+  /* Update delays. */
+  os_time++;
+  rt_dec_dly ();
+
+  /* Check the user timers. */
+#ifdef __CMSIS_RTOS
+  sysTimerTick();
+#else
+  rt_tmr_tick ();
+#endif
+  
+  /* Switch back to highest ready task */
+  next = rt_get_first (&os_rdy);
+  rt_switch_req (next);
+}
+
+/*--------------------------- rt_stk_check ----------------------------------*/
+__weak void rt_stk_check (void) {
+    /* Check for stack overflow. */
+    if (os_tsk.run->task_id == 0x01) {
+        // TODO: For the main thread the check should be done against the main heap pointer
+    } else {
+        if ((os_tsk.run->tsk_stack < (U32)os_tsk.run->stack) ||
+            (os_tsk.run->stack[0] != MAGIC_WORD)) {
+            os_error (OS_ERR_STK_OVF);
+        }
+    }
+}
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/rt_System.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,52 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    RT_SYSTEM.H
+ *      Purpose: System Task Manager definitions
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+/* Variables */
+#define os_psq  ((P_PSQ)&os_fifo)
+extern int os_tick_irqn;
+
+/* Functions */
+extern U32  rt_suspend    (void);
+extern void rt_resume     (U32 sleep_time);
+extern void rt_tsk_lock   (void);
+extern void rt_tsk_unlock (void);
+extern void rt_psh_req    (void);
+extern void rt_pop_req    (void);
+extern void rt_systick    (void);
+extern void rt_stk_check  (void);
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/rt_Task.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,339 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    RT_TASK.C
+ *      Purpose: Task functions and system start up.
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#include "rt_TypeDef.h"
+#include "RTX_Config.h"
+#include "rt_System.h"
+#include "rt_Task.h"
+#include "rt_List.h"
+#include "rt_MemBox.h"
+#include "rt_Robin.h"
+#include "rt_HAL_CM.h"
+
+/*----------------------------------------------------------------------------
+ *      Global Variables
+ *---------------------------------------------------------------------------*/
+
+/* Running and next task info. */
+struct OS_TSK os_tsk;
+
+/* Task Control Blocks of idle demon */
+struct OS_TCB os_idle_TCB;
+
+
+/*----------------------------------------------------------------------------
+ *      Local Functions
+ *---------------------------------------------------------------------------*/
+
+OS_TID rt_get_TID (void) {
+  U32 tid;
+
+  for (tid = 1; tid <= os_maxtaskrun; tid++) {
+    if (os_active_TCB[tid-1] == NULL) {
+      return ((OS_TID)tid);
+    }
+  }
+  return (0);
+}
+
+#if defined (__CC_ARM) && !defined (__MICROLIB)
+/*--------------------------- __user_perthread_libspace ---------------------*/
+extern void  *__libspace_start;
+
+void *__user_perthread_libspace (void) {
+  /* Provide a separate libspace for each task. */
+  if (os_tsk.run == NULL) {
+    /* RTX not running yet. */
+    return (&__libspace_start);
+  }
+  return (void *)(os_tsk.run->std_libspace);
+}
+#endif
+
+/*--------------------------- rt_init_context -------------------------------*/
+
+void rt_init_context (P_TCB p_TCB, U8 priority, FUNCP task_body) {
+  /* Initialize general part of the Task Control Block. */
+  p_TCB->cb_type = TCB;
+  p_TCB->state   = READY;
+  p_TCB->prio    = priority;
+  p_TCB->p_lnk   = NULL;
+  p_TCB->p_rlnk  = NULL;
+  p_TCB->p_dlnk  = NULL;
+  p_TCB->p_blnk  = NULL;
+  p_TCB->delta_time    = 0;
+  p_TCB->interval_time = 0;
+  p_TCB->events  = 0;
+  p_TCB->waits   = 0;
+  p_TCB->stack_frame = 0;
+
+  rt_init_stack (p_TCB, task_body);
+}
+
+
+/*--------------------------- rt_switch_req ---------------------------------*/
+
+void rt_switch_req (P_TCB p_new) {
+  /* Switch to next task (identified by "p_new"). */
+  os_tsk.new_tsk   = p_new;
+  p_new->state = RUNNING;
+  DBG_TASK_SWITCH(p_new->task_id);
+}
+
+
+/*--------------------------- rt_dispatch -----------------------------------*/
+
+void rt_dispatch (P_TCB next_TCB) {
+  /* Dispatch next task if any identified or dispatch highest ready task    */
+  /* "next_TCB" identifies a task to run or has value NULL (=no next task)  */
+  if (next_TCB == NULL) {
+    /* Running task was blocked: continue with highest ready task */
+    next_TCB = rt_get_first (&os_rdy);
+    rt_switch_req (next_TCB);
+  }
+  else {
+    /* Check which task continues */
+    if (next_TCB->prio > os_tsk.run->prio) {
+      /* preempt running task */
+      rt_put_rdy_first (os_tsk.run);
+      os_tsk.run->state = READY;
+      rt_switch_req (next_TCB);
+    }
+    else {
+      /* put next task into ready list, no task switch takes place */
+      next_TCB->state = READY;
+      rt_put_prio (&os_rdy, next_TCB);
+    }
+  }
+}
+
+
+/*--------------------------- rt_block --------------------------------------*/
+
+void rt_block (U16 timeout, U8 block_state) {
+  /* Block running task and choose next ready task.                         */
+  /* "timeout" sets a time-out value or is 0xffff (=no time-out).           */
+  /* "block_state" defines the appropriate task state */
+  P_TCB next_TCB;
+
+  if (timeout) {
+    if (timeout < 0xffff) {
+      rt_put_dly (os_tsk.run, timeout);
+    }
+    os_tsk.run->state = block_state;
+    next_TCB = rt_get_first (&os_rdy);
+    rt_switch_req (next_TCB);
+  }
+}
+
+
+/*--------------------------- rt_tsk_pass -----------------------------------*/
+
+void rt_tsk_pass (void) {
+  /* Allow tasks of same priority level to run cooperatively.*/
+  P_TCB p_new;
+
+  p_new = rt_get_same_rdy_prio();
+  if (p_new != NULL) {
+    rt_put_prio ((P_XCB)&os_rdy, os_tsk.run);
+    os_tsk.run->state = READY;
+    rt_switch_req (p_new);
+  }
+}
+
+
+/*--------------------------- rt_tsk_self -----------------------------------*/
+
+OS_TID rt_tsk_self (void) {
+  /* Return own task identifier value. */
+  if (os_tsk.run == NULL) {
+    return (0);
+  }
+  return (os_tsk.run->task_id);
+}
+
+
+/*--------------------------- rt_tsk_prio -----------------------------------*/
+
+OS_RESULT rt_tsk_prio (OS_TID task_id, U8 new_prio) {
+  /* Change execution priority of a task to "new_prio". */
+  P_TCB p_task;
+
+  if (task_id == 0) {
+    /* Change execution priority of calling task. */
+    os_tsk.run->prio = new_prio;
+run:if (rt_rdy_prio() > new_prio) {
+      rt_put_prio (&os_rdy, os_tsk.run);
+      os_tsk.run->state   = READY;
+      rt_dispatch (NULL);
+    }
+    return (OS_R_OK);
+  }
+
+  /* Find the task in the "os_active_TCB" array. */
+  if (task_id > os_maxtaskrun || os_active_TCB[task_id-1] == NULL) {
+    /* Task with "task_id" not found or not started. */
+    return (OS_R_NOK);
+  }
+  p_task = os_active_TCB[task_id-1];
+  p_task->prio = new_prio;
+  if (p_task == os_tsk.run) {
+    goto run;
+  }
+  rt_resort_prio (p_task);
+  if (p_task->state == READY) {
+    /* Task enqueued in a ready list. */
+    p_task = rt_get_first (&os_rdy);
+    rt_dispatch (p_task);
+  }
+  return (OS_R_OK);
+}
+
+/*--------------------------- rt_tsk_delete ---------------------------------*/
+
+OS_RESULT rt_tsk_delete (OS_TID task_id) {
+  /* Terminate the task identified with "task_id". */
+  P_TCB task_context;
+
+  if (task_id == 0 || task_id == os_tsk.run->task_id) {
+    /* Terminate itself. */
+    os_tsk.run->state     = INACTIVE;
+    os_tsk.run->tsk_stack = rt_get_PSP ();
+    rt_stk_check ();
+    os_active_TCB[os_tsk.run->task_id-1] = NULL;
+    
+    os_tsk.run->stack = NULL;
+    DBG_TASK_NOTIFY(os_tsk.run, __FALSE);
+    os_tsk.run = NULL;
+    rt_dispatch (NULL);
+    /* The program should never come to this point. */
+  }
+  else {
+    /* Find the task in the "os_active_TCB" array. */
+    if (task_id > os_maxtaskrun || os_active_TCB[task_id-1] == NULL) {
+      /* Task with "task_id" not found or not started. */
+      return (OS_R_NOK);
+    }
+    task_context = os_active_TCB[task_id-1];
+    rt_rmv_list (task_context);
+    rt_rmv_dly (task_context);
+    os_active_TCB[task_id-1] = NULL;
+    
+    task_context->stack = NULL;
+    DBG_TASK_NOTIFY(task_context, __FALSE);
+  }
+  return (OS_R_OK);
+}
+
+
+/*--------------------------- rt_sys_init -----------------------------------*/
+
+#ifdef __CMSIS_RTOS
+void rt_sys_init (void) {
+#else
+void rt_sys_init (FUNCP first_task, U32 prio_stksz, void *stk) {
+#endif
+  /* Initialize system and start up task declared with "first_task". */
+  U32 i;
+
+  DBG_INIT();
+
+  /* Initialize dynamic memory and task TCB pointers to NULL. */
+  for (i = 0; i < os_maxtaskrun; i++) {
+    os_active_TCB[i] = NULL;
+  }
+  
+  /* Set up TCB of idle demon */
+  os_idle_TCB.task_id = 255;
+  os_idle_TCB.priv_stack = idle_task_stack_size;
+  os_idle_TCB.stack = idle_task_stack;
+  rt_init_context (&os_idle_TCB, 0, os_idle_demon);
+
+  /* Set up ready list: initially empty */
+  os_rdy.cb_type = HCB;
+  os_rdy.p_lnk   = NULL;
+  /* Set up delay list: initially empty */
+  os_dly.cb_type = HCB;
+  os_dly.p_dlnk  = NULL;
+  os_dly.p_blnk  = NULL;
+  os_dly.delta_time = 0;
+
+  /* Fix SP and systemvariables to assume idle task is running  */
+  /* Transform main program into idle task by assuming idle TCB */
+#ifndef __CMSIS_RTOS
+  rt_set_PSP (os_idle_TCB.tsk_stack+32);
+#endif
+  os_tsk.run = &os_idle_TCB;
+  os_tsk.run->state = RUNNING;
+
+  /* Initialize ps queue */
+  os_psq->first = 0;
+  os_psq->last  = 0;
+  os_psq->size  = os_fifo_size;
+
+  rt_init_robin ();
+
+  /* Intitialize SVC and PendSV */
+  rt_svc_init ();
+
+#ifndef __CMSIS_RTOS
+  /* Intitialize and start system clock timer */
+  os_tick_irqn = os_tick_init ();
+  if (os_tick_irqn >= 0) {
+    OS_X_INIT(os_tick_irqn);
+  }
+
+  /* Start up first user task before entering the endless loop */
+  rt_tsk_create (first_task, prio_stksz, stk, NULL);
+#endif
+}
+
+
+/*--------------------------- rt_sys_start ----------------------------------*/
+
+#ifdef __CMSIS_RTOS
+void rt_sys_start (void) {
+  /* Start system */
+
+  /* Intitialize and start system clock timer */
+  os_tick_irqn = os_tick_init ();
+  if (os_tick_irqn >= 0) {
+    OS_X_INIT(os_tick_irqn);
+  }
+}
+#endif
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/rt_Task.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,73 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    RT_TASK.H
+ *      Purpose: Task functions and system start up.
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+/* Definitions */
+#define __CMSIS_RTOS    1
+
+/* Values for 'state'   */
+#define INACTIVE        0
+#define READY           1
+#define RUNNING         2
+#define WAIT_DLY        3
+#define WAIT_ITV        4
+#define WAIT_OR         5
+#define WAIT_AND        6
+#define WAIT_SEM        7
+#define WAIT_MBX        8
+#define WAIT_MUT        9
+
+/* Return codes */
+#define OS_R_TMO        0x01
+#define OS_R_EVT        0x02
+#define OS_R_SEM        0x03
+#define OS_R_MBX        0x04
+#define OS_R_MUT        0x05
+
+#define OS_R_OK         0x00
+#define OS_R_NOK        0xff
+
+/* Variables */
+extern struct OS_TSK os_tsk;
+extern struct OS_TCB os_idle_TCB;
+
+/* Functions */
+extern void      rt_switch_req (P_TCB p_new);
+extern void      rt_dispatch   (P_TCB next_TCB);
+extern void      rt_block      (U16 timeout, U8 block_state);
+extern void      rt_tsk_pass   (void);
+extern OS_TID    rt_tsk_self   (void);
+extern OS_RESULT rt_tsk_prio   (OS_TID task_id, U8 new_prio);
+extern OS_RESULT rt_tsk_delete (OS_TID task_id);
+extern void      rt_sys_init   (void);
+extern void      rt_sys_start  (void);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/rt_Time.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,94 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    RT_TIME.C
+ *      Purpose: Delay and interval wait functions
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#include "rt_TypeDef.h"
+#include "RTX_Config.h"
+#include "rt_Task.h"
+#include "rt_Time.h"
+
+/*----------------------------------------------------------------------------
+ *      Global Variables
+ *---------------------------------------------------------------------------*/
+
+/* Free running system tick counter */
+U32 os_time;
+
+
+/*----------------------------------------------------------------------------
+ *      Functions
+ *---------------------------------------------------------------------------*/
+
+
+/*--------------------------- rt_time_get -----------------------------------*/
+
+U32 rt_time_get (void) {
+  /* Get system time tick */
+  return (os_time);
+}
+
+
+/*--------------------------- rt_dly_wait -----------------------------------*/
+
+void rt_dly_wait (U16 delay_time) {
+  /* Delay task by "delay_time" */
+  rt_block (delay_time, WAIT_DLY);
+}
+
+
+/*--------------------------- rt_itv_set ------------------------------------*/
+
+void rt_itv_set (U16 interval_time) {
+  /* Set interval length and define start of first interval */
+  os_tsk.run->interval_time = interval_time;
+  os_tsk.run->delta_time = interval_time + (U16)os_time;
+}
+
+
+/*--------------------------- rt_itv_wait -----------------------------------*/
+
+void rt_itv_wait (void) {
+  /* Wait for interval end and define start of next one */
+  U16 delta;
+
+  delta = os_tsk.run->delta_time - (U16)os_time;
+  os_tsk.run->delta_time += os_tsk.run->interval_time;
+  if ((delta & 0x8000) == 0) {
+    rt_block (delta, WAIT_ITV);
+  }
+}
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/rt_Time.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,47 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    RT_TIME.H
+ *      Purpose: Delay and interval wait functions definitions
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+/* Variables */
+extern U32 os_time;
+
+/* Functions */
+extern U32  rt_time_get (void);
+extern void rt_dly_wait (U16 delay_time);
+extern void rt_itv_set  (U16 interval_time);
+extern void rt_itv_wait (void);
+
+/*----------------------------------------------------------------------------
+ * end of file
+ *---------------------------------------------------------------------------*/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost/mbed-rtos/rtx/rt_TypeDef.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,128 @@
+/*----------------------------------------------------------------------------
+ *      RL-ARM - RTX
+ *----------------------------------------------------------------------------
+ *      Name:    RT_TYPEDEF.H
+ *      Purpose: Type Definitions
+ *      Rev.:    V4.60
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *  - Neither the name of ARM  nor the names of its contributors may be used 
+ *    to endorse or promote products derived from this software without 
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+#ifndef RT_TYPE_DEF_H
+#define RT_TYPE_DEF_H
+
+#include "os_tcb.h"
+
+typedef U32     OS_TID;
+typedef void    *OS_ID;
+typedef U32     OS_RESULT;
+
+#define TCB_STACKF      32        /* 'stack_frame' offset                    */
+#define TCB_TSTACK      36        /* 'tsk_stack' offset                      */
+
+typedef struct OS_PSFE {          /* Post Service Fifo Entry                 */
+  void  *id;                      /* Object Identification                   */
+  U32    arg;                     /* Object Argument                         */
+} *P_PSFE;
+
+typedef struct OS_PSQ {           /* Post Service Queue                      */
+  U8     first;                   /* FIFO Head Index                         */
+  U8     last;                    /* FIFO Tail Index                         */
+  U8     count;                   /* Number of stored items in FIFO          */
+  U8     size;                    /* FIFO Size                               */
+  struct OS_PSFE q[1];            /* FIFO Content                            */
+} *P_PSQ;
+
+typedef struct OS_TSK {
+  P_TCB  run;                     /* Current running task                    */
+  P_TCB  new_tsk;                 /* Scheduled task to run                   */
+} *P_TSK;
+
+typedef struct OS_ROBIN {         /* Round Robin Control                     */
+  P_TCB  task;                    /* Round Robin task                        */
+  U16    time;                    /* Round Robin switch time                 */
+  U16    tout;                    /* Round Robin timeout                     */
+} *P_ROBIN;
+
+typedef struct OS_XCB {
+  U8     cb_type;                 /* Control Block Type                      */
+  struct OS_TCB *p_lnk;           /* Link pointer for ready/sem. wait list   */
+  struct OS_TCB *p_rlnk;          /* Link pointer for sem./mbx lst backwards */
+  struct OS_TCB *p_dlnk;          /* Link pointer for delay list             */
+  struct OS_TCB *p_blnk;          /* Link pointer for delay list backwards   */
+  U16    delta_time;              /* Time until time out                     */
+} *P_XCB;
+
+typedef struct OS_MCB {
+  U8     cb_type;                 /* Control Block Type                      */
+  U8     state;                   /* State flag variable                     */
+  U8     isr_st;                  /* State flag variable for isr functions   */
+  struct OS_TCB *p_lnk;           /* Chain of tasks waiting for message      */
+  U16    first;                   /* Index of the message list begin         */
+  U16    last;                    /* Index of the message list end           */
+  U16    count;                   /* Actual number of stored messages        */
+  U16    size;                    /* Maximum number of stored messages       */
+  void   *msg[1];                 /* FIFO for Message pointers 1st element   */
+} *P_MCB;
+
+typedef struct OS_SCB {
+  U8     cb_type;                 /* Control Block Type                      */
+  U8     mask;                    /* Semaphore token mask                    */
+  U16    tokens;                  /* Semaphore tokens                        */
+  struct OS_TCB *p_lnk;           /* Chain of tasks waiting for tokens       */
+} *P_SCB;
+
+typedef struct OS_MUCB {
+  U8     cb_type;                 /* Control Block Type                      */
+  U8     prio;                    /* Owner task default priority             */
+  U16    level;                   /* Call nesting level                      */
+  struct OS_TCB *p_lnk;           /* Chain of tasks waiting for mutex        */
+  struct OS_TCB *owner;           /* Mutex owner task                        */
+} *P_MUCB;
+
+typedef struct OS_XTMR {
+  struct OS_TMR  *next;
+  U16    tcnt;
+} *P_XTMR;
+
+typedef struct OS_TMR {
+  struct OS_TMR  *next;           /* Link pointer to Next timer              */
+  U16    tcnt;                    /* Timer delay count                       */
+  U16    info;                    /* User defined call info                  */
+} *P_TMR;
+
+typedef struct OS_BM {
+  void *free;                     /* Pointer to first free memory block      */
+  void *end;                      /* Pointer to memory block end             */
+  U32  blk_size;                  /* Memory block size                       */
+} *P_BM;
+
+/* Definitions */
+#define __TRUE          1
+#define __FALSE         0
+#define NULL            ((void *) 0)
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostBTstack/USBHostBTstack.cpp	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,215 @@
+// USBHostBTstack.cpp
+#include "USBHostBTstack.h"
+#include "dbg.h"
+
+//#define BTSTACK_DEBUG
+
+#ifdef BTSTACK_DEBUG
+#define BT_DBG(x, ...) std::printf("[%s:%d]"x"\r\n", __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
+#define BT_DBG_BYTES(STR,BUF,LEN) _debug_bytes(__PRETTY_FUNCTION__,__LINE__,STR,BUF,LEN)
+#else
+#define BT_DBG(...)  while(0);
+#define BT_DBG_BYTES(S,BUF,LEN) while(0);
+#endif
+
+#define HCI_COMMAND_DATA_PACKET 0x01
+#define HCI_ACL_DATA_PACKET     0x02
+#define HCI_SCO_DATA_PACKET     0x03
+#define HCI_EVENT_PACKET        0x04
+
+USBHostBTstack::USBHostBTstack()
+{
+    host = USBHost::getHostInst();
+    init();
+    m_pCb = NULL;
+}
+
+void USBHostBTstack::init()
+{
+    BT_DBG("");
+    dev = NULL;
+    int_in = NULL;
+    bulk_in = NULL;
+    bulk_out = NULL;
+    btstack_intf = -1;
+    btstack_device_found = false;
+    dev_connected = false;
+    ep_int_in = false;
+    ep_bulk_in = false;
+    ep_bulk_out = false;
+}
+
+bool USBHostBTstack::connected()
+{
+    return dev_connected;
+}
+
+bool USBHostBTstack::connect()
+{
+    if (dev_connected) {
+        return true;
+    }
+
+    for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+        if ((dev = host->getDevice(i)) != NULL) {
+            
+            BT_DBG("Trying to connect BTstack device\r\n");
+            
+            if(host->enumerate(dev, this)) {
+                break;
+            }
+            if (btstack_device_found) {
+                int_in = dev->getEndpoint(btstack_intf, INTERRUPT_ENDPOINT, IN);
+                bulk_in = dev->getEndpoint(btstack_intf, BULK_ENDPOINT, IN);
+                bulk_out = dev->getEndpoint(btstack_intf, BULK_ENDPOINT, OUT);
+                if (!int_in || !bulk_in || !bulk_out) {
+                    continue;
+                }
+                USB_INFO("New BTstack device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, btstack_intf);
+                dev->setName("BTstack", btstack_intf);
+                host->registerDriver(dev, btstack_intf, this, &USBHostBTstack::init);
+
+                int_in->attach(this, &USBHostBTstack::int_rxHandler);
+                host->interruptRead(dev, int_in, int_report, int_in->getSize(), false);
+
+                bulk_in->attach(this, &USBHostBTstack::bulk_rxHandler);
+                host->bulkRead(dev, bulk_in, bulk_report, bulk_in->getSize(), false);
+
+                dev_connected = true;
+                return true;
+            }
+        }
+    }
+    init();
+    return false;
+}
+
+void USBHostBTstack::int_rxHandler()
+{
+    int len = int_in->getLengthTransferred();
+    BT_DBG_BYTES("HCI_EVT:", int_report, len);
+    Packet* pkt = mail_box.alloc();
+    TEST_ASSERT(pkt);
+    pkt->type = HCI_EVENT_PACKET;
+    pkt->buf = int_report;
+    pkt->len = len;
+    mail_box.put(pkt);
+}
+
+void USBHostBTstack::bulk_rxHandler()
+{
+    int len = bulk_in->getLengthTransferred();
+    BT_DBG_BYTES("ACL_RCV:", bulk_report, len);
+    Packet* pkt = mail_box.alloc();
+    TEST_ASSERT(pkt);
+    pkt->type = HCI_ACL_DATA_PACKET;
+    pkt->buf = bulk_report;
+    pkt->len = len;
+    mail_box.put(pkt);
+}
+
+/*virtual*/ void USBHostBTstack::setVidPid(uint16_t vid, uint16_t pid)
+{
+    BT_DBG("vid:%04x,pid:%04x", vid, pid);
+}
+
+/*virtual*/ bool USBHostBTstack::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
+{
+    BT_DBG("intf_nb=%d,intf_class=%02X,intf_subclass=%d,intf_protocol=%d", intf_nb, intf_class, intf_subclass, intf_protocol);
+    if ((btstack_intf == -1) && intf_class == 0xe0) {
+        btstack_intf = intf_nb;
+        return true;
+    }
+    return false;
+}
+
+/*virtual*/ bool USBHostBTstack::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
+{
+    BT_DBG("intf_nb:%d,type:%d,dir:%d",intf_nb, type, dir);
+    if (intf_nb == btstack_intf) {
+        if (ep_int_in == false && type == INTERRUPT_ENDPOINT && dir == IN) {
+            ep_int_in = true;
+        } else if (ep_bulk_in == false && type == BULK_ENDPOINT && dir == IN) {
+            ep_bulk_in = true;
+        } else if (ep_bulk_out == false && type == BULK_ENDPOINT && dir == OUT) {
+            ep_bulk_out = true;
+        } else {
+            return false;
+        }
+        if (ep_int_in && ep_bulk_in && ep_bulk_out) {
+            btstack_device_found = true;
+        }
+        return true;
+    }
+    return false;
+}
+
+int USBHostBTstack::open()
+{
+    BT_DBG("%p", this);
+    while(!connected()) {
+        if (connect()) {
+            break;
+        }
+        Thread::wait(500);
+    }
+    return 0;
+}
+
+int USBHostBTstack::send_packet(uint8_t packet_type, uint8_t* packet, int size)
+{
+    USB_TYPE res;
+    switch(packet_type){
+        case HCI_COMMAND_DATA_PACKET:
+            BT_DBG_BYTES("HCI_CMD:", packet, size);
+            res = host->controlWrite(dev,
+                    USB_HOST_TO_DEVICE | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_DEVICE, 
+                    0, 0, 0, packet, size);
+            TEST_ASSERT(res == USB_TYPE_OK);
+            break;
+        case HCI_ACL_DATA_PACKET:
+            BT_DBG_BYTES("ACL_SND:", packet, size);
+            res = host->bulkWrite(dev, bulk_out, packet, size);
+            TEST_ASSERT(res == USB_TYPE_OK);
+            break;
+        default:
+            TEST_ASSERT(0);
+    }
+    return 0;
+}
+
+void USBHostBTstack::register_packet_handler(void (*pMethod)(uint8_t, uint8_t*, uint16_t) )
+{
+    BT_DBG("pMethod: %p", pMethod);
+    m_pCb = pMethod;
+}
+
+void USBHostBTstack::poll()
+{
+    osEvent evt = mail_box.get(0); // non-blocking
+    if (evt.status == osEventMail) {
+        Packet* pkt = reinterpret_cast<Packet*>(evt.value.p);
+        TEST_ASSERT(pkt);
+        //BT_DBG("type: %d, buf: %p, len: %d", pkt->type, pkt->buf, pkt->len);
+        if (m_pCb) {
+            m_pCb(pkt->type, pkt->buf, pkt->len);
+        }
+        if (dev) {
+            if (pkt->type == HCI_EVENT_PACKET) { 
+                host->interruptRead(dev, int_in, int_report, int_in->getSize(), false);
+            } else { // HCI_ACL_DATA_PACKET
+                host->bulkRead(dev, bulk_in, bulk_report, bulk_in->getSize(), false);
+            }
+        }
+        mail_box.free(pkt);
+    }
+}
+
+void _debug_bytes(const char* pretty, int line, const char* s, uint8_t* buf, int len)
+{
+    printf("[%s:%d]\n%s", pretty, line, s);
+    for(int i = 0; i < len; i++) {
+        printf(" %02x", buf[i]);
+    }
+    printf("\n");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostBTstack/USBHostBTstack.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,71 @@
+#include "USBHostConf.h"
+#include "USBHost.h"
+#pragma once
+
+#define TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);};
+
+struct Packet {
+    uint8_t type;
+    uint8_t* buf;
+    uint16_t len;
+};
+
+/** 
+ * A class to communicate a BTstack
+ */
+class USBHostBTstack : public IUSBEnumerator {
+public:
+    /**
+    * Constructor
+    *
+    */
+    USBHostBTstack();
+
+    /**
+    * Check if a BTstack device is connected
+    *
+    * @return true if a BTstack device is connected
+    */
+    bool connected();
+
+    /**
+     * Try to connect to a BTstack device
+     *
+     * @return true if connection was successful
+     */
+    bool connect();
+    
+    int open();
+    int send_packet(uint8_t packet_type, uint8_t* packet, int size);
+    void register_packet_handler( void (*pMethod)(uint8_t, uint8_t*, uint16_t));
+    void poll();
+
+protected:
+    //From IUSBEnumerator
+    virtual void setVidPid(uint16_t vid, uint16_t pid);
+    virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
+    virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
+
+private:
+    USBHost * host;
+    USBDeviceConnected * dev;
+    bool dev_connected;
+    uint8_t int_report[64];
+    uint8_t bulk_report[64];
+    USBEndpoint * int_in;
+    USBEndpoint * bulk_in;
+    USBEndpoint * bulk_out;
+    bool ep_int_in;
+    bool ep_bulk_in;
+    bool ep_bulk_out;
+    
+    bool btstack_device_found;
+    int btstack_intf;
+    void (*m_pCb)(uint8_t, uint8_t*, uint16_t);
+    Mail<Packet, 2> mail_box;
+    void int_rxHandler();
+    void bulk_rxHandler();
+    void init();
+};
+
+void _debug_bytes(const char* pretty, int line, const char* s, uint8_t* buf, int len);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Wiimote/Wiimote.cpp	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,101 @@
+/* Copyright (c) 2011, mbed
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *  
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *  
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+// Simple decode class for Wii Remote data
+
+#include "Wiimote.h" 
+
+// Wii Report Formats: 
+//  * http://wiibrew.org/wiki/Wiimote#0x37:_Core_Buttons_and_Accelerometer_with_10_IR_bytes_and_6_Extension_Bytes
+//  * http://wiki.wiimoteproject.com/Reports#0x37_BTN_.2B_XLR_.2B_IR_.2B_6_EXT
+
+// Input Report 0x37:
+// 
+// 0 [ ?    |    X(1:0)   | PLUS  | UP | DOWN | RIGHT | LEFT ]
+// 1 [ HOME | Z(1) | Y(1) | MINUS |  A |   B  |  ONE  |  TWO ]
+// 2 [                        X(9:2)                         ]
+// 3 [                        Y(9:2)                         ]
+// 4 [                        Z(9:2)                         ]
+//
+
+#include <stdio.h>
+#include <math.h>
+
+#define WII_ZERO 0x206
+#define WII_1G   0x6A
+
+void Wiimote::decode(char* data) {
+
+    // read buttons
+    left  = (data[0] >> 0) & 0x1;
+    right = (data[0] >> 1) & 0x1;
+    down  = (data[0] >> 2) & 0x1;
+    up    = (data[0] >> 3) & 0x1;
+    plus  = (data[0] >> 4) & 0x1;
+    two   = (data[1] >> 0) & 0x1;
+    one   = (data[1] >> 1) & 0x1;
+    b     = (data[1] >> 2) & 0x1;
+    a     = (data[1] >> 3) & 0x1;
+    minus = (data[1] >> 4) & 0x1;
+    home  = (data[1] >> 7) & 0x1;
+    
+    // read accelerometers
+    rawx = (data[2] << 2) | (data[0] & 0x60) >> 5;
+    rawy = (data[3] << 2) | (data[1] & 0x20) >> 4;
+    rawz = (data[4] << 2) | (data[1] & 0x40) >> 5;
+
+    // calculate accelerometer gravity
+    x = (float)((int)rawx - WII_ZERO) / (float)WII_1G;
+    y = (float)((int)rawy - WII_ZERO) / (float)WII_1G;
+    z = (float)((int)rawz - WII_ZERO) / (float)WII_1G;
+
+    // calculate wheel angle    
+    wheel = atan2(-y, -x) * (180.0 / 3.141592);
+} 
+
+void Wiimote::dump() {
+    printf("%d%d%d%d%d%d%d%d%d%d%d %.3f %.3f %.3f %.2f\n", left, right, down, up, plus, two, one, b, a, minus, home, x, y, z, wheel);
+}
+
+
+// Accelerometer data
+//      y-
+//     +---+               +--+
+//     | + |               +  B
+//     | A |               A  |
+//     |   |               |  |
+// x+  |   |  x-       z+  |  |  z-
+//     | 1 |               1  |
+//     | 2 |               2  |
+//     +---+               +--+
+//      y+
+//
+// x+ 0x19B
+// x0 0x205
+// x- 0x26E
+//
+// y+ 0x19C   0x6A
+// y0 0x206
+// y- 0x26E   0x68
+//
+// z+ 0x19C 
+// z0 0x208
+// z- 0x26E
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Wiimote/Wiimote.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,61 @@
+/* Copyright (c) 2011, mbed
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *  
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *  
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+ 
+// Simple decoder class for Wii Remote data
+
+#ifndef WIIMOTE_H
+#define WIIMOTE_H
+
+#include <stdint.h>
+
+class Wiimote {
+
+public: 
+
+    void decode(char *data);
+    void dump();
+    
+    // buttons
+    uint32_t left:1;
+    uint32_t right:1;
+    uint32_t down:1;
+    uint32_t up:1;
+    uint32_t plus:1;
+    uint32_t two:1;
+    uint32_t one:1;
+    uint32_t a:1;
+    uint32_t b:1;
+    uint32_t minus:1;
+    uint32_t home:1;
+
+    // accelerometers
+    uint16_t rawx;
+    uint16_t rawy;
+    uint16_t rawz;
+    
+    float x;
+    float y;
+    float z;
+    float wheel;
+};
+
+#endif
+     
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/bt_control.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  bt_control.h
+ *
+ *  BT Control API -- allows BT Daemon to initialize and control differnt hardware
+ *
+ *  Created by Matthias Ringwald on 5/19/09.
+ *
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+typedef enum {
+    POWER_WILL_SLEEP = 1,
+    POWER_WILL_WAKE_UP
+} POWER_NOTIFICATION_t;
+
+typedef struct {
+    int          (*on)   (void *config);  // <-- turn BT module on and configure
+    int          (*off)  (void *config);  // <-- turn BT module off
+    int          (*sleep)(void *config);  // <-- put BT module to sleep    - only to be called after ON
+    int          (*wake) (void *config);  // <-- wake BT module from sleep - only to be called after SLEEP
+    int          (*valid)(void *config);  // <-- test if hardware can be supported
+    const char * (*name) (void *config);  // <-- return hardware name
+
+    /** support for UART baud rate changes - cmd has to be stored in hci_cmd_buffer
+     * @return have command
+     */
+    int          (*baudrate_cmd)(void * config, uint32_t baudrate, uint8_t *hci_cmd_buffer); 
+    
+    /** support custom init sequences after RESET command - cmd has to be stored in hci_cmd_buffer
+      * @return have command
+      */
+    int          (*next_cmd)(void *config, uint8_t * hci_cmd_buffer); 
+
+    void         (*register_for_power_notifications)(void (*cb)(POWER_NOTIFICATION_t event));
+
+    void         (*hw_error)(void); 
+} bt_control_t;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/btstack.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2009 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ *  btstack.h
+ *
+ *  Created by Matthias Ringwald on 7/1/09.
+ *
+ *  BTstack client API
+ *  
+ */
+
+#pragma once
+
+#include <btstack/hci_cmds.h>
+#include <btstack/run_loop.h>
+#include <btstack/utils.h>
+
+#include <stdint.h>
+
+#if defined __cplusplus
+extern "C" {
+#endif
+    
+// Default TCP port for BTstack daemon
+#define BTSTACK_PORT            13333
+
+// UNIX domain socket for BTstack */
+#define BTSTACK_UNIX            "/tmp/BTstack"
+
+// packet handler
+typedef void (*btstack_packet_handler_t) (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
+
+// optional: if called before bt_open, TCP socket is used instead of local unix socket
+//           note: address is not copied and must be valid during bt_open
+void bt_use_tcp(const char * address, uint16_t port); 
+
+// init BTstack library
+int bt_open(void);
+
+// stop using BTstack library
+int bt_close(void);
+
+// send hci cmd packet
+int bt_send_cmd(const hci_cmd_t *cmd, ...);
+
+// register packet handler -- channel only valid for l2cap and rfcomm packets
+// @returns old packet handler
+btstack_packet_handler_t bt_register_packet_handler(btstack_packet_handler_t handler);
+
+void bt_send_acl(uint8_t * data, uint16_t len);
+
+void bt_send_l2cap(uint16_t local_cid, uint8_t *data, uint16_t len);
+void bt_send_rfcomm(uint16_t rfcom_cid, uint8_t *data, uint16_t len);
+
+#if defined __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/btstack_memory.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  btstsack_memory.h
+ *
+ *  @brief BTstack memory management via configurable memory pools
+ *
+ *  @note code semi-atuomatically generated by btstack_memory_generator.py
+ *
+ */
+
+#include "btstack_memory.h"
+#include <btstack/memory_pool.h>
+
+#include <stdlib.h>
+
+#include "config.h"
+#include "hci.h"
+#include "l2cap.h"
+#include "rfcomm.h"
+
+// MARK: hci_connection_t
+#ifdef MAX_NO_HCI_CONNECTIONS
+#if MAX_NO_HCI_CONNECTIONS > 0
+static hci_connection_t hci_connection_storage[MAX_NO_HCI_CONNECTIONS];
+static memory_pool_t hci_connection_pool;
+void * btstack_memory_hci_connection_get(void){
+    return memory_pool_get(&hci_connection_pool);
+}
+void btstack_memory_hci_connection_free(void *hci_connection){
+    memory_pool_free(&hci_connection_pool, hci_connection);
+}
+#else
+void * btstack_memory_hci_connection_get(void){
+    return NULL;
+}
+void btstack_memory_hci_connection_free(void *hci_connection){
+};
+#endif
+#elif defined(HAVE_MALLOC)
+void * btstack_memory_hci_connection_get(void){
+    return malloc(sizeof(hci_connection_t));
+}
+void  btstack_memory_hci_connection_free(void *hci_connection){
+    free(hci_connection);
+}
+#endif
+
+
+// MARK: l2cap_service_t
+#ifdef MAX_NO_L2CAP_SERVICES
+#if MAX_NO_L2CAP_SERVICES > 0
+static l2cap_service_t l2cap_service_storage[MAX_NO_L2CAP_SERVICES];
+static memory_pool_t l2cap_service_pool;
+void * btstack_memory_l2cap_service_get(void){
+    return memory_pool_get(&l2cap_service_pool);
+}
+void btstack_memory_l2cap_service_free(void *l2cap_service){
+    memory_pool_free(&l2cap_service_pool, l2cap_service);
+}
+#else
+void * btstack_memory_l2cap_service_get(void){
+    return NULL;
+}
+void btstack_memory_l2cap_service_free(void *l2cap_service){
+};
+#endif
+#elif defined(HAVE_MALLOC)
+void * btstack_memory_l2cap_service_get(void){
+    return malloc(sizeof(l2cap_service_t));
+}
+void  btstack_memory_l2cap_service_free(void *l2cap_service){
+    free(l2cap_service);
+}
+#endif
+
+
+// MARK: l2cap_channel_t
+#ifdef MAX_NO_L2CAP_CHANNELS
+#if MAX_NO_L2CAP_CHANNELS > 0
+static l2cap_channel_t l2cap_channel_storage[MAX_NO_L2CAP_CHANNELS];
+static memory_pool_t l2cap_channel_pool;
+void * btstack_memory_l2cap_channel_get(void){
+    return memory_pool_get(&l2cap_channel_pool);
+}
+void btstack_memory_l2cap_channel_free(void *l2cap_channel){
+    memory_pool_free(&l2cap_channel_pool, l2cap_channel);
+}
+#else
+void * btstack_memory_l2cap_channel_get(void){
+    return NULL;
+}
+void btstack_memory_l2cap_channel_free(void *l2cap_channel){
+};
+#endif
+#elif defined(HAVE_MALLOC)
+void * btstack_memory_l2cap_channel_get(void){
+    return malloc(sizeof(l2cap_channel_t));
+}
+void  btstack_memory_l2cap_channel_free(void *l2cap_channel){
+    free(l2cap_channel);
+}
+#endif
+
+
+// MARK: rfcomm_multiplexer_t
+#ifdef MAX_NO_RFCOMM_MULTIPLEXERS
+#if MAX_NO_RFCOMM_MULTIPLEXERS > 0
+static rfcomm_multiplexer_t rfcomm_multiplexer_storage[MAX_NO_RFCOMM_MULTIPLEXERS];
+static memory_pool_t rfcomm_multiplexer_pool;
+void * btstack_memory_rfcomm_multiplexer_get(void){
+    return memory_pool_get(&rfcomm_multiplexer_pool);
+}
+void btstack_memory_rfcomm_multiplexer_free(void *rfcomm_multiplexer){
+    memory_pool_free(&rfcomm_multiplexer_pool, rfcomm_multiplexer);
+}
+#else
+void * btstack_memory_rfcomm_multiplexer_get(void){
+    return NULL;
+}
+void btstack_memory_rfcomm_multiplexer_free(void *rfcomm_multiplexer){
+};
+#endif
+#elif defined(HAVE_MALLOC)
+void * btstack_memory_rfcomm_multiplexer_get(void){
+    return malloc(sizeof(rfcomm_multiplexer_t));
+}
+void  btstack_memory_rfcomm_multiplexer_free(void *rfcomm_multiplexer){
+    free(rfcomm_multiplexer);
+}
+#endif
+
+
+// MARK: rfcomm_service_t
+#ifdef MAX_NO_RFCOMM_SERVICES
+#if MAX_NO_RFCOMM_SERVICES > 0
+static rfcomm_service_t rfcomm_service_storage[MAX_NO_RFCOMM_SERVICES];
+static memory_pool_t rfcomm_service_pool;
+void * btstack_memory_rfcomm_service_get(void){
+    return memory_pool_get(&rfcomm_service_pool);
+}
+void btstack_memory_rfcomm_service_free(void *rfcomm_service){
+    memory_pool_free(&rfcomm_service_pool, rfcomm_service);
+}
+#else
+void * btstack_memory_rfcomm_service_get(void){
+    return NULL;
+}
+void btstack_memory_rfcomm_service_free(void *rfcomm_service){
+};
+#endif
+#elif defined(HAVE_MALLOC)
+void * btstack_memory_rfcomm_service_get(void){
+    return malloc(sizeof(rfcomm_service_t));
+}
+void  btstack_memory_rfcomm_service_free(void *rfcomm_service){
+    free(rfcomm_service);
+}
+#endif
+
+
+// MARK: rfcomm_channel_t
+#ifdef MAX_NO_RFCOMM_CHANNELS
+#if MAX_NO_RFCOMM_CHANNELS > 0
+static rfcomm_channel_t rfcomm_channel_storage[MAX_NO_RFCOMM_CHANNELS];
+static memory_pool_t rfcomm_channel_pool;
+void * btstack_memory_rfcomm_channel_get(void){
+    return memory_pool_get(&rfcomm_channel_pool);
+}
+void btstack_memory_rfcomm_channel_free(void *rfcomm_channel){
+    memory_pool_free(&rfcomm_channel_pool, rfcomm_channel);
+}
+#else
+void * btstack_memory_rfcomm_channel_get(void){
+    return NULL;
+}
+void btstack_memory_rfcomm_channel_free(void *rfcomm_channel){
+};
+#endif
+#elif defined(HAVE_MALLOC)
+void * btstack_memory_rfcomm_channel_get(void){
+    return malloc(sizeof(rfcomm_channel_t));
+}
+void  btstack_memory_rfcomm_channel_free(void *rfcomm_channel){
+    free(rfcomm_channel);
+}
+#endif
+
+
+// MARK: db_mem_device_name_t
+#ifdef MAX_NO_DB_MEM_DEVICE_NAMES
+#if MAX_NO_DB_MEM_DEVICE_NAMES > 0
+static db_mem_device_name_t db_mem_device_name_storage[MAX_NO_DB_MEM_DEVICE_NAMES];
+static memory_pool_t db_mem_device_name_pool;
+void * btstack_memory_db_mem_device_name_get(void){
+    return memory_pool_get(&db_mem_device_name_pool);
+}
+void btstack_memory_db_mem_device_name_free(void *db_mem_device_name){
+    memory_pool_free(&db_mem_device_name_pool, db_mem_device_name);
+}
+#else
+void * btstack_memory_db_mem_device_name_get(void){
+    return NULL;
+}
+void btstack_memory_db_mem_device_name_free(void *db_mem_device_name){
+};
+#endif
+#elif defined(HAVE_MALLOC)
+void * btstack_memory_db_mem_device_name_get(void){
+    return malloc(sizeof(db_mem_device_name_t));
+}
+void  btstack_memory_db_mem_device_name_free(void *db_mem_device_name){
+    free(db_mem_device_name);
+}
+#endif
+
+
+// MARK: db_mem_device_link_key_t
+#ifdef MAX_NO_DB_MEM_DEVICE_LINK_KEYS
+#if MAX_NO_DB_MEM_DEVICE_LINK_KEYS > 0
+static db_mem_device_link_key_t db_mem_device_link_key_storage[MAX_NO_DB_MEM_DEVICE_LINK_KEYS];
+static memory_pool_t db_mem_device_link_key_pool;
+void * btstack_memory_db_mem_device_link_key_get(void){
+    return memory_pool_get(&db_mem_device_link_key_pool);
+}
+void btstack_memory_db_mem_device_link_key_free(void *db_mem_device_link_key){
+    memory_pool_free(&db_mem_device_link_key_pool, db_mem_device_link_key);
+}
+#else
+void * btstack_memory_db_mem_device_link_key_get(void){
+    return NULL;
+}
+void btstack_memory_db_mem_device_link_key_free(void *db_mem_device_link_key){
+};
+#endif
+#elif defined(HAVE_MALLOC)
+void * btstack_memory_db_mem_device_link_key_get(void){
+    return malloc(sizeof(db_mem_device_link_key_t));
+}
+void  btstack_memory_db_mem_device_link_key_free(void *db_mem_device_link_key){
+    free(db_mem_device_link_key);
+}
+#endif
+
+
+// MARK: db_mem_service_t
+#ifdef MAX_NO_DB_MEM_SERVICES
+#if MAX_NO_DB_MEM_SERVICES > 0
+static db_mem_service_t db_mem_service_storage[MAX_NO_DB_MEM_SERVICES];
+static memory_pool_t db_mem_service_pool;
+void * btstack_memory_db_mem_service_get(void){
+    return memory_pool_get(&db_mem_service_pool);
+}
+void btstack_memory_db_mem_service_free(void *db_mem_service){
+    memory_pool_free(&db_mem_service_pool, db_mem_service);
+}
+#else
+void * btstack_memory_db_mem_service_get(void){
+    return NULL;
+}
+void btstack_memory_db_mem_service_free(void *db_mem_service){
+};
+#endif
+#elif defined(HAVE_MALLOC)
+void * btstack_memory_db_mem_service_get(void){
+    return malloc(sizeof(db_mem_service_t));
+}
+void  btstack_memory_db_mem_service_free(void *db_mem_service){
+    free(db_mem_service);
+}
+#endif
+
+// init
+void btstack_memory_init(void){
+#if MAX_NO_HCI_CONNECTIONS > 0
+    memory_pool_create(&hci_connection_pool, hci_connection_storage, MAX_NO_HCI_CONNECTIONS, sizeof(hci_connection_t));
+#endif
+#if MAX_NO_L2CAP_SERVICES > 0
+    memory_pool_create(&l2cap_service_pool, l2cap_service_storage, MAX_NO_L2CAP_SERVICES, sizeof(l2cap_service_t));
+#endif
+#if MAX_NO_L2CAP_CHANNELS > 0
+    memory_pool_create(&l2cap_channel_pool, l2cap_channel_storage, MAX_NO_L2CAP_CHANNELS, sizeof(l2cap_channel_t));
+#endif
+#if MAX_NO_RFCOMM_MULTIPLEXERS > 0
+    memory_pool_create(&rfcomm_multiplexer_pool, rfcomm_multiplexer_storage, MAX_NO_RFCOMM_MULTIPLEXERS, sizeof(rfcomm_multiplexer_t));
+#endif
+#if MAX_NO_RFCOMM_SERVICES > 0
+    memory_pool_create(&rfcomm_service_pool, rfcomm_service_storage, MAX_NO_RFCOMM_SERVICES, sizeof(rfcomm_service_t));
+#endif
+#if MAX_NO_RFCOMM_CHANNELS > 0
+    memory_pool_create(&rfcomm_channel_pool, rfcomm_channel_storage, MAX_NO_RFCOMM_CHANNELS, sizeof(rfcomm_channel_t));
+#endif
+#if MAX_NO_DB_MEM_DEVICE_NAMES > 0
+    memory_pool_create(&db_mem_device_name_pool, db_mem_device_name_storage, MAX_NO_DB_MEM_DEVICE_NAMES, sizeof(db_mem_device_name_t));
+#endif
+#if MAX_NO_DB_MEM_DEVICE_LINK_KEYS > 0
+    memory_pool_create(&db_mem_device_link_key_pool, db_mem_device_link_key_storage, MAX_NO_DB_MEM_DEVICE_LINK_KEYS, sizeof(db_mem_device_link_key_t));
+#endif
+#if MAX_NO_DB_MEM_SERVICES > 0
+    memory_pool_create(&db_mem_service_pool, db_mem_service_storage, MAX_NO_DB_MEM_SERVICES, sizeof(db_mem_service_t));
+#endif
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/btstack_memory.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  btstsack_memory.h
+ *
+ *  @brief BTstack memory management via configurable memory pools
+ *
+ */
+
+#pragma once
+
+#if defined __cplusplus
+extern "C" {
+#endif
+    
+void btstack_memory_init(void);
+
+void * btstack_memory_hci_connection_get(void);
+void   btstack_memory_hci_connection_free(void *hci_connection);
+void * btstack_memory_l2cap_service_get(void);
+void   btstack_memory_l2cap_service_free(void *l2cap_service);
+void * btstack_memory_l2cap_channel_get(void);
+void   btstack_memory_l2cap_channel_free(void *l2cap_channel);
+void * btstack_memory_rfcomm_multiplexer_get(void);
+void   btstack_memory_rfcomm_multiplexer_free(void *rfcomm_multiplexer);
+void * btstack_memory_rfcomm_service_get(void);
+void   btstack_memory_rfcomm_service_free(void *rfcomm_service);
+void * btstack_memory_rfcomm_channel_get(void);
+void   btstack_memory_rfcomm_channel_free(void *rfcomm_channel);
+void * btstack_memory_db_mem_device_name_get(void);
+void   btstack_memory_db_mem_device_name_free(void *db_mem_device_name);
+void * btstack_memory_db_mem_device_link_key_get(void);
+void   btstack_memory_db_mem_device_link_key_free(void *db_mem_device_link_key);
+void * btstack_memory_db_mem_service_get(void);
+void   btstack_memory_db_mem_service_free(void *db_mem_service);
+
+#if defined __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/config.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,24 @@
+#define EMBEDDED
+#define HAVE_TICK
+
+//#define HAVE_INIT_SCRIPT
+//#define HAVE_BZERO
+//#define HAVE_EHCILL
+
+#define ENABLE_LOG_INFO 
+#define ENABLE_LOG_ERROR
+
+#define HCI_ACL_PAYLOAD_SIZE 52
+
+#define HAVE_MALLOC
+
+//#define MAX_SPP_CONNECTIONS 1
+//#define MAX_NO_HCI_CONNECTIONS MAX_SPP_CONNECTIONS
+//#define MAX_NO_L2CAP_SERVICES  2
+//#define MAX_NO_L2CAP_CHANNELS  (1+MAX_SPP_CONNECTIONS)
+//#define MAX_NO_RFCOMM_MULTIPLEXERS MAX_SPP_CONNECTIONS
+//#define MAX_NO_RFCOMM_SERVICES 1
+//#define MAX_NO_RFCOMM_CHANNELS MAX_SPP_CONNECTIONS
+//#define MAX_NO_DB_MEM_DEVICE_LINK_KEYS  2
+//#define MAX_NO_DB_MEM_DEVICE_NAMES 0
+//#define MAX_NO_DB_MEM_SERVICES 1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/debug.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  debug.h
+ *
+ *  allow to funnel debug & error messages 
+ */
+
+#include "config.h"
+#include "hci_dump.h"
+
+#include <stdio.h>
+
+#ifdef ENABLE_LOG_DEBUG
+#ifdef HAVE_HCI_DUMP
+#define log_debug(format, ...)  hci_dump_log(format,  ## __VA_ARGS__)
+#else
+#define log_debug(format, ...)  printf(format,  ## __VA_ARGS__)
+#endif
+#else
+#define log_debug(...)
+#endif
+
+#ifdef ENABLE_LOG_INFO
+#ifdef HAVE_HCI_DUMP
+#define log_info(format, ...)  hci_dump_log(format,  ## __VA_ARGS__)
+#else
+#define log_info(format, ...)  printf(format,  ## __VA_ARGS__)
+#endif
+#else
+#define log_info(...)
+#endif
+
+#ifdef ENABLE_LOG_ERROR
+#ifdef HAVE_HCI_DUMP
+#define log_error(format, ...)  hci_dump_log(format,  ## __VA_ARGS__)
+#else
+#define log_error(format, ...)  printf(format,  ## __VA_ARGS__)
+#endif
+#else
+#define log_error(...)
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/hal_cpu.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2011 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ *  hal_cpu.h
+ *
+ *  Low power mode for MCU requires that IRQs can be first blocked 
+ *  and then unblocked while entering low power mode atomically
+ */
+#if defined __cplusplus
+extern "C" {
+#endif
+ 
+void hal_cpu_disable_irqs(void);
+void hal_cpu_enable_irqs(void);
+void hal_cpu_enable_irqs_and_sleep(void);
+
+#if defined __cplusplus
+}
+#endif
+ 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/hal_mbed/hal_cpu.cpp	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2011 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ *  hal_cpu.c
+ *
+ *  Implementation for mbed
+ *
+ */
+
+#include <btstack/hal_cpu.h>
+
+void hal_cpu_disable_irqs(){
+
+}
+
+void hal_cpu_enable_irqs(){
+
+}
+
+void hal_cpu_enable_irqs_and_sleep(){
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/hal_mbed/hal_tick.cpp	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2011 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ *  hal_tick.c
+ *
+ *  Implementation for mbed
+ *
+ */
+
+#include <btstack/hal_tick.h>
+#include "mbed.h"
+static Ticker tick;
+
+static void dummy_handler(void){};
+
+static void (*tick_handler)(void) = &dummy_handler;
+
+void hal_tick_init(void){
+
+}
+
+void hal_tick_set_handler(void (*handler)(void)){
+    if (handler == NULL){
+        tick_handler = &dummy_handler;
+        return;
+    }
+    tick_handler = handler;
+    tick.attach(tick_handler, 0.001);
+}
+
+int  hal_tick_get_tick_period_in_ms(void){
+    return 1;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/hal_tick.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2011 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ *  hal_tick.h
+ *
+ *  Hardware abstraction layer for periodic ticks
+ *
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+void hal_tick_init(void);
+void hal_tick_set_handler(void (*tick_handler)(void));
+int  hal_tick_get_tick_period_in_ms(void);
+
+#if defined __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/hci.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,1415 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  hci.c
+ *
+ *  Created by Matthias Ringwald on 4/29/09.
+ *
+ */
+
+#include "config.h"
+
+#include "hci.h"
+
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifndef EMBEDDED
+#include <unistd.h> // gethostbyname
+#include <btstack/version.h>
+#endif
+
+#include "btstack_memory.h"
+#include "debug.h"
+#include "hci_dump.h"
+
+#include <btstack/hci_cmds.h>
+
+#define HCI_CONNECTION_TIMEOUT_MS 10000
+
+#ifdef USE_BLUETOOL
+#include "bt_control_iphone.h"
+#endif
+
+static void hci_update_scan_enable(void);
+
+// the STACK is here
+static hci_stack_t       hci_stack;
+
+/**
+ * get connection for a given handle
+ *
+ * @return connection OR NULL, if not found
+ */
+hci_connection_t * connection_for_handle(hci_con_handle_t con_handle){
+    linked_item_t *it;
+    for (it = (linked_item_t *) hci_stack.connections; it ; it = it->next){
+        if ( ((hci_connection_t *) it)->con_handle == con_handle){
+            return (hci_connection_t *) it;
+        }
+    }
+    return NULL;
+}
+
+static void hci_connection_timeout_handler(timer_source_t *timer){
+    hci_connection_t * connection = (hci_connection_t *) linked_item_get_user(&timer->item);
+#ifdef HAVE_TIME
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    if (tv.tv_sec >= connection->timestamp.tv_sec + HCI_CONNECTION_TIMEOUT_MS/1000) {
+        // connections might be timed out
+        hci_emit_l2cap_check_timeout(connection);
+    }
+#endif
+#ifdef HAVE_TICK
+    if (embedded_get_ticks() > connection->timestamp + embedded_ticks_for_ms(HCI_CONNECTION_TIMEOUT_MS)){
+        // connections might be timed out
+        hci_emit_l2cap_check_timeout(connection);
+    }
+#endif
+    run_loop_set_timer(timer, HCI_CONNECTION_TIMEOUT_MS);
+    run_loop_add_timer(timer);
+}
+
+static void hci_connection_timestamp(hci_connection_t *connection){
+#ifdef HAVE_TIME
+    gettimeofday(&connection->timestamp, NULL);
+#endif
+#ifdef HAVE_TICK
+    connection->timestamp = embedded_get_ticks();
+#endif
+}
+
+/**
+ * create connection for given address
+ *
+ * @return connection OR NULL, if no memory left
+ */
+static hci_connection_t * create_connection_for_addr(bd_addr_t addr){
+    hci_connection_t * conn = (hci_connection_t *) btstack_memory_hci_connection_get();
+    if (!conn) return NULL;
+    BD_ADDR_COPY(conn->address, addr);
+    conn->con_handle = 0xffff;
+    conn->authentication_flags = AUTH_FLAGS_NONE;
+    linked_item_set_user(&conn->timeout.item, conn);
+    conn->timeout.process = hci_connection_timeout_handler;
+    hci_connection_timestamp(conn);
+    conn->acl_recombination_length = 0;
+    conn->acl_recombination_pos = 0;
+    conn->num_acl_packets_sent = 0;
+    linked_list_add(&hci_stack.connections, (linked_item_t *) conn);
+    return conn;
+}
+
+/**
+ * get connection for given address
+ *
+ * @return connection OR NULL, if not found
+ */
+static hci_connection_t * connection_for_address(bd_addr_t address){
+    linked_item_t *it;
+    for (it = (linked_item_t *) hci_stack.connections; it ; it = it->next){
+        if ( ! BD_ADDR_CMP( ((hci_connection_t *) it)->address, address) ){
+            return (hci_connection_t *) it;
+        }
+    }
+    return NULL;
+}
+
+inline static void connectionSetAuthenticationFlags(hci_connection_t * conn, hci_authentication_flags_t flags){
+    conn->authentication_flags = (hci_authentication_flags_t)(conn->authentication_flags | flags);
+}
+
+inline static void connectionClearAuthenticationFlags(hci_connection_t * conn, hci_authentication_flags_t flags){
+    conn->authentication_flags = (hci_authentication_flags_t)(conn->authentication_flags & ~flags);
+}
+
+
+/**
+ * add authentication flags and reset timer
+ */
+static void hci_add_connection_flags_for_flipped_bd_addr(uint8_t *bd_addr, hci_authentication_flags_t flags){
+    bd_addr_t addr;
+    bt_flip_addr(addr, *(bd_addr_t *) bd_addr);
+    hci_connection_t * conn = connection_for_address(addr);
+    if (conn) {
+        connectionSetAuthenticationFlags(conn, flags);
+        hci_connection_timestamp(conn);
+    }
+}
+
+int  hci_authentication_active_for_handle(hci_con_handle_t handle){
+    hci_connection_t * conn = connection_for_handle(handle);
+    if (!conn) return 0;
+    if (!conn->authentication_flags) return 0;
+    if (conn->authentication_flags & SENT_LINK_KEY_REPLY) return 0;
+    if (conn->authentication_flags & RECV_LINK_KEY_NOTIFICATION) return 0;
+    return 1;
+}
+
+void hci_drop_link_key_for_bd_addr(bd_addr_t *addr){
+    if (hci_stack.remote_device_db) {
+        hci_stack.remote_device_db->delete_link_key(addr);
+    }
+}
+
+
+/**
+ * count connections
+ */
+static int nr_hci_connections(void){
+    int count = 0;
+    linked_item_t *it;
+    for (it = (linked_item_t *) hci_stack.connections; it ; it = it->next, count++);
+    return count;
+}
+
+/** 
+ * Dummy handler called by HCI
+ */
+static void dummy_handler(uint8_t packet_type, uint8_t *packet, uint16_t size){
+}
+
+uint8_t hci_number_outgoing_packets(hci_con_handle_t handle){
+    hci_connection_t * connection = connection_for_handle(handle);
+    if (!connection) {
+        log_error("hci_number_outgoing_packets connectino for handle %u does not exist!\n", handle);
+        return 0;
+    }
+    return connection->num_acl_packets_sent;
+}
+
+uint8_t hci_number_free_acl_slots(){
+    uint8_t free_slots = hci_stack.total_num_acl_packets;
+    linked_item_t *it;
+    for (it = (linked_item_t *) hci_stack.connections; it ; it = it->next){
+        hci_connection_t * connection = (hci_connection_t *) it;
+        if (free_slots < connection->num_acl_packets_sent) {
+            log_error("hci_number_free_acl_slots: sum of outgoing packets > total acl packets!\n");
+            return 0;
+        }
+        free_slots -= connection->num_acl_packets_sent;
+    }
+    return free_slots;
+}
+
+int hci_can_send_packet_now(uint8_t packet_type){
+
+    // check for async hci transport implementations
+    if (hci_stack.hci_transport->can_send_packet_now){
+        if (!hci_stack.hci_transport->can_send_packet_now(packet_type)){
+            return 0;
+        }
+    }
+    
+    // check regular Bluetooth flow control
+    switch (packet_type) {
+        case HCI_ACL_DATA_PACKET:
+            return hci_number_free_acl_slots();
+        case HCI_COMMAND_DATA_PACKET:
+            return hci_stack.num_cmd_packets;
+        default:
+            return 0;
+    }
+}
+
+int hci_send_acl_packet(uint8_t *packet, int size){
+
+    // check for free places on BT module
+    if (!hci_number_free_acl_slots()) return BTSTACK_ACL_BUFFERS_FULL;
+    
+    hci_con_handle_t con_handle = READ_ACL_CONNECTION_HANDLE(packet);
+    hci_connection_t *connection = connection_for_handle( con_handle);
+    if (!connection) return 0;
+    hci_connection_timestamp(connection);
+    
+    // count packet
+    connection->num_acl_packets_sent++;
+    // log_info("hci_send_acl_packet - handle %u, sent %u\n", connection->con_handle, connection->num_acl_packets_sent);
+
+    // send packet 
+    int err = hci_stack.hci_transport->send_packet(HCI_ACL_DATA_PACKET, packet, size);
+    
+    return err;
+}
+
+static void acl_handler(uint8_t *packet, int size){
+
+    // get info
+    hci_con_handle_t con_handle = READ_ACL_CONNECTION_HANDLE(packet);
+    hci_connection_t *conn      = connection_for_handle(con_handle);
+    uint8_t  acl_flags          = READ_ACL_FLAGS(packet);
+    uint16_t acl_length         = READ_ACL_LENGTH(packet);
+
+    // ignore non-registered handle
+    if (!conn){
+        log_error( "hci.c: acl_handler called with non-registered handle %u!\n" , con_handle);
+        return;
+    }
+    
+    // update idle timestamp
+    hci_connection_timestamp(conn);
+    
+    // handle different packet types
+    switch (acl_flags & 0x03) {
+            
+        case 0x01: // continuation fragment
+            
+            // sanity check
+            if (conn->acl_recombination_pos == 0) {
+                log_error( "ACL Cont Fragment but no first fragment for handle 0x%02x\n", con_handle);
+                return;
+            }
+            
+            // append fragment payload (header already stored)
+            memcpy(&conn->acl_recombination_buffer[conn->acl_recombination_pos], &packet[4], acl_length );
+            conn->acl_recombination_pos += acl_length;
+            
+            // log_error( "ACL Cont Fragment: acl_len %u, combined_len %u, l2cap_len %u\n", acl_length,
+            //        conn->acl_recombination_pos, conn->acl_recombination_length);  
+            
+            // forward complete L2CAP packet if complete. 
+            if (conn->acl_recombination_pos >= conn->acl_recombination_length + 4 + 4){ // pos already incl. ACL header
+                
+                hci_stack.packet_handler(HCI_ACL_DATA_PACKET, conn->acl_recombination_buffer, conn->acl_recombination_pos);
+                // reset recombination buffer
+                conn->acl_recombination_length = 0;
+                conn->acl_recombination_pos = 0;
+            }
+            break;
+            
+        case 0x02: { // first fragment
+            
+            // sanity check
+            if (conn->acl_recombination_pos) {
+                log_error( "ACL First Fragment but data in buffer for handle 0x%02x\n", con_handle);
+                return;
+            }
+
+            // peek into L2CAP packet!
+            uint16_t l2cap_length = READ_L2CAP_LENGTH( packet );
+
+            // log_error( "ACL First Fragment: acl_len %u, l2cap_len %u\n", acl_length, l2cap_length);
+
+            // compare fragment size to L2CAP packet size
+            if (acl_length >= l2cap_length + 4){
+                
+                // forward fragment as L2CAP packet
+                hci_stack.packet_handler(HCI_ACL_DATA_PACKET, packet, acl_length + 4);
+            
+            } else {
+                // store first fragment and tweak acl length for complete package
+                memcpy(conn->acl_recombination_buffer, packet, acl_length + 4);
+                conn->acl_recombination_pos    = acl_length + 4;
+                conn->acl_recombination_length = l2cap_length;
+                bt_store_16(conn->acl_recombination_buffer, 2, l2cap_length +4);
+            }
+            break;
+            
+        } 
+        default:
+            log_error( "hci.c: acl_handler called with invalid packet boundary flags %u\n", acl_flags & 0x03);
+            return;
+    }
+    
+    // execute main loop
+    hci_run();
+}
+
+static void hci_shutdown_connection(hci_connection_t *conn){
+    log_info("Connection closed: handle %u, %s\n", conn->con_handle, bd_addr_to_str(conn->address));
+
+    // cancel all l2cap connections
+    hci_emit_disconnection_complete(conn->con_handle, 0x16);    // terminated by local host
+
+    run_loop_remove_timer(&conn->timeout);
+    
+    linked_list_remove(&hci_stack.connections, (linked_item_t *) conn);
+    btstack_memory_hci_connection_free( conn );
+    
+    // now it's gone
+    hci_emit_nr_connections_changed();
+}
+
+static const uint16_t packet_type_sizes[] = {
+    0, HCI_ACL_2DH1_SIZE, HCI_ACL_3DH1_SIZE, HCI_ACL_DM1_SIZE,
+    HCI_ACL_DH1_SIZE, 0, 0, 0,
+    HCI_ACL_2DH3_SIZE, HCI_ACL_3DH3_SIZE, HCI_ACL_DM3_SIZE, HCI_ACL_DH3_SIZE,
+    HCI_ACL_2DH5_SIZE, HCI_ACL_3DH5_SIZE, HCI_ACL_DM5_SIZE, HCI_ACL_DH5_SIZE
+};
+
+static uint16_t hci_acl_packet_types_for_buffer_size(uint16_t buffer_size){
+    uint16_t packet_types = 0;
+    int i;
+    for (i=0;i<16;i++){
+        if (packet_type_sizes[i] == 0) continue;
+        if (packet_type_sizes[i] <= buffer_size){
+            packet_types |= 1 << i;
+        }
+    }
+    // flip bits for "may not be used"
+    packet_types ^= 0x3306;
+    return packet_types;
+}
+
+uint16_t hci_usable_acl_packet_types(void){
+    return hci_stack.packet_types;
+}
+
+uint8_t* hci_get_outgoing_acl_packet_buffer(void){
+    // hci packet buffer is >= acl data packet length
+    return hci_stack.hci_packet_buffer;
+}
+
+uint16_t hci_max_acl_data_packet_length(){
+    return hci_stack.acl_data_packet_length;
+}
+
+// avoid huge local variables
+#ifndef EMBEDDED
+static device_name_t device_name;
+#endif
+static void event_handler(uint8_t *packet, int size){
+    bd_addr_t addr;
+    uint8_t link_type;
+    hci_con_handle_t handle;
+    hci_connection_t * conn;
+    int i;
+        
+    // printf("HCI:EVENT:%02x\n", packet[0]);
+    
+    switch (packet[0]) {
+                        
+        case HCI_EVENT_COMMAND_COMPLETE:
+            // get num cmd packets
+            // log_info("HCI_EVENT_COMMAND_COMPLETE cmds old %u - new %u\n", hci_stack.num_cmd_packets, packet[2]);
+            hci_stack.num_cmd_packets = packet[2];
+            
+            if (COMMAND_COMPLETE_EVENT(packet, hci_read_buffer_size)){
+                // from offset 5
+                // status 
+                // "The HC_ACL_Data_Packet_Length return parameter will be used to determine the size of the L2CAP segments contained in ACL Data Packets"
+                hci_stack.acl_data_packet_length = READ_BT_16(packet, 6);
+                // ignore: SCO data packet len (8)
+                hci_stack.total_num_acl_packets  = packet[9];
+                // ignore: total num SCO packets
+                if (hci_stack.state == HCI_STATE_INITIALIZING){
+                    // determine usable ACL payload size
+                    if (HCI_ACL_PAYLOAD_SIZE < hci_stack.acl_data_packet_length){
+                        hci_stack.acl_data_packet_length = HCI_ACL_PAYLOAD_SIZE;
+                    }
+                    // determine usable ACL packet types
+                    hci_stack.packet_types = hci_acl_packet_types_for_buffer_size(hci_stack.acl_data_packet_length);
+                    
+                    log_error("hci_read_buffer_size: used size %u, count %u, packet types %04x\n",
+                             hci_stack.acl_data_packet_length, hci_stack.total_num_acl_packets, hci_stack.packet_types); 
+                }
+            }
+            // Dump local address
+            if (COMMAND_COMPLETE_EVENT(packet, hci_read_bd_addr)) {
+                bd_addr_t addr;
+                bt_flip_addr(addr, &packet[OFFSET_OF_DATA_IN_COMMAND_COMPLETE + 1]);
+                log_info("Local Address, Status: 0x%02x: Addr: %s\n",
+                    packet[OFFSET_OF_DATA_IN_COMMAND_COMPLETE], bd_addr_to_str(addr));
+            }
+            if (COMMAND_COMPLETE_EVENT(packet, hci_write_scan_enable)){
+                hci_emit_discoverable_enabled(hci_stack.discoverable);
+            }
+            break;
+            
+        case HCI_EVENT_COMMAND_STATUS:
+            // get num cmd packets
+            // log_info("HCI_EVENT_COMMAND_STATUS cmds - old %u - new %u\n", hci_stack.num_cmd_packets, packet[3]);
+            hci_stack.num_cmd_packets = packet[3];
+            break;
+            
+        case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS:
+            for (i=0; i<packet[2];i++){
+#if    0
+                handle = READ_BT_16(packet, 3 + 2*i);
+                uint16_t num_packets = READ_BT_16(packet, 3 + packet[2]*2 + 2*i);
+#else
+                //sibu
+                handle = READ_BT_16(packet, 3 + 4*i);
+                uint16_t num_packets = READ_BT_16(packet, 3 + 2 + 4*i);
+#endif
+                conn = connection_for_handle(handle);
+                if (!conn){
+                    log_error("hci_number_completed_packet lists unused con handle %u\n", handle);
+                    continue;
+                }
+                conn->num_acl_packets_sent -= num_packets;
+                // log_info("hci_number_completed_packet %u processed for handle %u, outstanding %u\n", num_packets, handle, conn->num_acl_packets_sent);
+            }
+            break;
+            
+        case HCI_EVENT_CONNECTION_REQUEST:
+            bt_flip_addr(addr, &packet[2]);
+            // TODO: eval COD 8-10
+            link_type = packet[11];
+            log_info("Connection_incoming: %s, type %u\n", bd_addr_to_str(addr), link_type);
+            if (link_type == 1) { // ACL
+                conn = connection_for_address(addr);
+                if (!conn) {
+                    conn = create_connection_for_addr(addr);
+                }
+                if (!conn) {
+                    // CONNECTION REJECTED DUE TO LIMITED RESOURCES (0X0D)
+                    hci_stack.decline_reason = 0x0d;
+                    BD_ADDR_COPY(hci_stack.decline_addr, addr);
+                    break;
+                }
+                conn->state = RECEIVED_CONNECTION_REQUEST;
+                hci_run();
+            } else {
+                // SYNCHRONOUS CONNECTION LIMIT TO A DEVICE EXCEEDED (0X0A)
+                hci_stack.decline_reason = 0x0a;
+                BD_ADDR_COPY(hci_stack.decline_addr, addr);
+            }
+            break;
+            
+        case HCI_EVENT_CONNECTION_COMPLETE:
+            // Connection management
+            bt_flip_addr(addr, &packet[5]);
+            log_info("Connection_complete (status=%u) %s\n", packet[2], bd_addr_to_str(addr));
+            conn = connection_for_address(addr);
+            if (conn) {
+                if (!packet[2]){
+                    conn->state = OPEN;
+                    conn->con_handle = READ_BT_16(packet, 3);
+                    
+                    // restart timer
+                    run_loop_set_timer(&conn->timeout, HCI_CONNECTION_TIMEOUT_MS);
+                    run_loop_add_timer(&conn->timeout);
+                    
+                    log_info("New connection: handle %u, %s\n", conn->con_handle, bd_addr_to_str(conn->address));
+                    
+                    hci_emit_nr_connections_changed();
+                } else {
+                    // connection failed, remove entry
+                    linked_list_remove(&hci_stack.connections, (linked_item_t *) conn);
+                    btstack_memory_hci_connection_free( conn );
+                    
+                    // if authentication error, also delete link key
+                    if (packet[2] == 0x05) {
+                        hci_drop_link_key_for_bd_addr(&addr);
+                    }
+                }
+            }
+            break;
+
+        case HCI_EVENT_LINK_KEY_REQUEST:
+            log_info("HCI_EVENT_LINK_KEY_REQUEST\n");
+            hci_add_connection_flags_for_flipped_bd_addr(&packet[2], RECV_LINK_KEY_REQUEST);
+            if (!hci_stack.remote_device_db) break;
+            hci_add_connection_flags_for_flipped_bd_addr(&packet[2], HANDLE_LINK_KEY_REQUEST);
+            hci_run();
+            // request handled by hci_run() as HANDLE_LINK_KEY_REQUEST gets set
+            return;
+            
+        case HCI_EVENT_LINK_KEY_NOTIFICATION:
+            hci_add_connection_flags_for_flipped_bd_addr(&packet[2], RECV_LINK_KEY_NOTIFICATION);
+            if (!hci_stack.remote_device_db) break;
+            bt_flip_addr(addr, &packet[2]);
+            hci_stack.remote_device_db->put_link_key(&addr, (link_key_t *) &packet[8]);
+            // still forward event to allow dismiss of pairing dialog
+            break;
+            
+        case HCI_EVENT_PIN_CODE_REQUEST:
+            hci_add_connection_flags_for_flipped_bd_addr(&packet[2], RECV_PIN_CODE_REQUEST);
+            // PIN CODE REQUEST means the link key request didn't succee -> delete stored link key
+            if (!hci_stack.remote_device_db) break;
+            bt_flip_addr(addr, &packet[2]);
+            hci_stack.remote_device_db->delete_link_key(&addr);
+            break;
+            
+#ifndef EMBEDDED
+        case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE:
+            if (!hci_stack.remote_device_db) break;
+            if (packet[2]) break; // status not ok
+            bt_flip_addr(addr, &packet[3]);
+            // fix for invalid remote names - terminate on 0xff
+            for (i=0; i<248;i++){
+                if (packet[9+i] == 0xff){
+                    packet[9+i] = 0;
+                    break;
+                }
+            }
+            memset(&device_name, 0, sizeof(device_name_t));
+            strncpy((char*) device_name, (char*) &packet[9], 248);
+            hci_stack.remote_device_db->put_name(&addr, &device_name);
+            break;
+            
+        case HCI_EVENT_INQUIRY_RESULT:
+        case HCI_EVENT_INQUIRY_RESULT_WITH_RSSI:
+            if (!hci_stack.remote_device_db) break;
+            // first send inq result packet
+            hci_stack.packet_handler(HCI_EVENT_PACKET, packet, size);
+            // then send cached remote names
+            for (i=0; i<packet[2];i++){
+                bt_flip_addr(addr, &packet[3+i*6]);
+                if (hci_stack.remote_device_db->get_name(&addr, &device_name)){
+                    hci_emit_remote_name_cached(&addr, &device_name);
+                }
+            }
+            return;
+#endif
+            
+        case HCI_EVENT_DISCONNECTION_COMPLETE:
+            if (!packet[2]){
+                handle = READ_BT_16(packet, 3);
+                hci_connection_t * conn = connection_for_handle(handle);
+                if (conn) {
+                    hci_shutdown_connection(conn);
+                }
+            }
+            break;
+            
+        case HCI_EVENT_HARDWARE_ERROR:
+            if(hci_stack.control->hw_error){
+                (*hci_stack.control->hw_error)();
+            }
+            break;
+
+#ifdef HAVE_BLE
+        case HCI_EVENT_LE_META:
+            switch (packet[2]) {
+                case HCI_SUBEVENT_LE_CONNECTION_COMPLETE:
+                    // Connection management
+                    bt_flip_addr(addr, &packet[8]);
+                    log_info("LE Connection_complete (status=%u) %s\n", packet[3], bd_addr_to_str(addr));
+                    // LE connections are auto-accepted, so just create a connection if there isn't one already
+                    conn = connection_for_address(addr);
+                    if (packet[3]){
+                        if (conn){
+                            // outgoing connection failed, remove entry
+                            linked_list_remove(&hci_stack.connections, (linked_item_t *) conn);
+                            btstack_memory_hci_connection_free( conn );
+                            
+                        }
+                        // if authentication error, also delete link key
+                        if (packet[3] == 0x05) {
+                            hci_drop_link_key_for_bd_addr(&addr);
+                        }
+                        break;
+                    }
+                    if (!conn){
+                        conn = create_connection_for_addr(addr);
+                    }
+                    if (!conn){
+                        // no memory
+                        break;
+                    }
+                    
+                    conn->state = OPEN;
+                    conn->con_handle = READ_BT_16(packet, 4);
+                    
+                    // TODO: store - role, peer address type, conn_interval, conn_latency, supervision timeout, master clock
+
+                    // restart timer
+                    // run_loop_set_timer(&conn->timeout, HCI_CONNECTION_TIMEOUT_MS);
+                    // run_loop_add_timer(&conn->timeout);
+                    
+                    log_info("New connection: handle %u, %s\n", conn->con_handle, bd_addr_to_str(conn->address));
+                    
+                    hci_emit_nr_connections_changed();
+                    break;
+                    
+                default:
+                    break;
+            }
+            break;
+#endif            
+            
+        default:
+            break;
+    }
+
+    // handle BT initialization
+    if (hci_stack.state == HCI_STATE_INITIALIZING){
+        // handle H4 synchronization loss on restart
+        // if (hci_stack.substate == 1 && packet[0] == HCI_EVENT_HARDWARE_ERROR){
+        //    hci_stack.substate = 0;
+        // }
+        // handle normal init sequence
+        if (hci_stack.substate % 2){
+            // odd: waiting for event
+            if (packet[0] == HCI_EVENT_COMMAND_COMPLETE){
+                hci_stack.substate++;
+            }
+        }
+    }
+    
+    // help with BT sleep
+    if (hci_stack.state == HCI_STATE_FALLING_ASLEEP
+        && hci_stack.substate == 1
+        && COMMAND_COMPLETE_EVENT(packet, hci_write_scan_enable)){
+        hci_stack.substate++;
+    }
+    
+    hci_stack.packet_handler(HCI_EVENT_PACKET, packet, size);
+    
+    // execute main loop
+    hci_run();
+}
+
+void packet_handler(uint8_t packet_type, uint8_t *packet, uint16_t size){
+    switch (packet_type) {
+        case HCI_EVENT_PACKET:
+            event_handler(packet, size);
+            break;
+        case HCI_ACL_DATA_PACKET:
+            acl_handler(packet, size);
+            break;
+        default:
+            break;
+    }
+}
+
+/** Register HCI packet handlers */
+void hci_register_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size)){
+    hci_stack.packet_handler = handler;
+}
+
+void hci_init(hci_transport_t *transport, void *config, bt_control_t *control, remote_device_db_t const* remote_device_db){
+    
+    // reference to use transport layer implementation
+    hci_stack.hci_transport = transport;
+    
+    // references to used control implementation
+    hci_stack.control = control;
+    
+    // reference to used config
+    hci_stack.config = config;
+    
+    // no connections yet
+    hci_stack.connections = NULL;
+    hci_stack.discoverable = 0;
+    hci_stack.connectable = 0;
+    
+    // no pending cmds
+    hci_stack.decline_reason = 0;
+    hci_stack.new_scan_enable_value = 0xff;
+    
+    // higher level handler
+    hci_stack.packet_handler = dummy_handler;
+
+    // store and open remote device db
+    hci_stack.remote_device_db = remote_device_db;
+    if (hci_stack.remote_device_db) {
+        hci_stack.remote_device_db->open();
+    }
+    
+    // max acl payload size defined in config.h
+    hci_stack.acl_data_packet_length = HCI_ACL_PAYLOAD_SIZE;
+    
+    // register packet handlers with transport
+    transport->register_packet_handler(&packet_handler);
+
+    hci_stack.state = HCI_STATE_OFF;
+}
+
+void hci_close(){
+    // close remote device db
+    if (hci_stack.remote_device_db) {
+        hci_stack.remote_device_db->close();
+    }
+    while (hci_stack.connections) {
+        hci_shutdown_connection((hci_connection_t *) hci_stack.connections);
+}
+    hci_power_control(HCI_POWER_OFF);
+}
+
+// State-Module-Driver overview
+// state                    module  low-level 
+// HCI_STATE_OFF             off      close
+// HCI_STATE_INITIALIZING,   on       open
+// HCI_STATE_WORKING,        on       open
+// HCI_STATE_HALTING,        on       open
+// HCI_STATE_SLEEPING,    off/sleep   close
+// HCI_STATE_FALLING_ASLEEP  on       open
+
+static int hci_power_control_on(void){
+    
+    // power on
+    int err = 0;
+    if (hci_stack.control && hci_stack.control->on){
+        err = (*hci_stack.control->on)(hci_stack.config);
+    }
+    if (err){
+        log_error( "POWER_ON failed\n");
+        hci_emit_hci_open_failed();
+        return err;
+    }
+    
+    // open low-level device
+    err = hci_stack.hci_transport->open(hci_stack.config);
+    if (err){
+        log_error( "HCI_INIT failed, turning Bluetooth off again\n");
+        if (hci_stack.control && hci_stack.control->off){
+            (*hci_stack.control->off)(hci_stack.config);
+        }
+        hci_emit_hci_open_failed();
+        return err;
+    }
+    return 0;
+}
+
+static void hci_power_control_off(void){
+    
+    log_info("hci_power_control_off\n");
+
+    // close low-level device
+    hci_stack.hci_transport->close(hci_stack.config);
+
+    log_info("hci_power_control_off - hci_transport closed\n");
+    
+    // power off
+    if (hci_stack.control && hci_stack.control->off){
+        (*hci_stack.control->off)(hci_stack.config);
+    }
+    
+    log_info("hci_power_control_off - control closed\n");
+
+    hci_stack.state = HCI_STATE_OFF;
+}
+
+static void hci_power_control_sleep(void){
+    
+    log_info("hci_power_control_sleep\n");
+    
+#if 0
+    // don't close serial port during sleep
+    
+    // close low-level device
+    hci_stack.hci_transport->close(hci_stack.config);
+#endif
+    
+    // sleep mode
+    if (hci_stack.control && hci_stack.control->sleep){
+        (*hci_stack.control->sleep)(hci_stack.config);
+    }
+    
+    hci_stack.state = HCI_STATE_SLEEPING;
+}
+
+static int hci_power_control_wake(void){
+    
+    log_info("hci_power_control_wake\n");
+
+    // wake on
+    if (hci_stack.control && hci_stack.control->wake){
+        (*hci_stack.control->wake)(hci_stack.config);
+    }
+    
+#if 0
+    // open low-level device
+    int err = hci_stack.hci_transport->open(hci_stack.config);
+    if (err){
+        log_error( "HCI_INIT failed, turning Bluetooth off again\n");
+        if (hci_stack.control && hci_stack.control->off){
+            (*hci_stack.control->off)(hci_stack.config);
+        }
+        hci_emit_hci_open_failed();
+        return err;
+    }
+#endif
+    
+    return 0;
+}
+
+
+int hci_power_control(HCI_POWER_MODE power_mode){
+    
+    log_info("hci_power_control: %u, current mode %u\n", power_mode, hci_stack.state);
+    
+    int err = 0;
+    switch (hci_stack.state){
+            
+        case HCI_STATE_OFF:
+            switch (power_mode){
+                case HCI_POWER_ON:
+                    err = hci_power_control_on();
+                    if (err) return err;
+                    // set up state machine
+                    hci_stack.num_cmd_packets = 1; // assume that one cmd can be sent
+                    hci_stack.state = HCI_STATE_INITIALIZING;
+                    hci_stack.substate = 0;
+                    break;
+                case HCI_POWER_OFF:
+                    // do nothing
+                    break;  
+                case HCI_POWER_SLEEP:
+                    // do nothing (with SLEEP == OFF)
+                    break;
+            }
+            break;
+            
+        case HCI_STATE_INITIALIZING:
+            switch (power_mode){
+                case HCI_POWER_ON:
+                    // do nothing
+                    break;
+                case HCI_POWER_OFF:
+                    // no connections yet, just turn it off
+                    hci_power_control_off();
+                    break;  
+                case HCI_POWER_SLEEP:
+                    // no connections yet, just turn it off
+                    hci_power_control_sleep();
+                    break;
+            }
+            break;
+            
+        case HCI_STATE_WORKING:
+            switch (power_mode){
+                case HCI_POWER_ON:
+                    // do nothing
+                    break;
+                case HCI_POWER_OFF:
+                    // see hci_run
+                    hci_stack.state = HCI_STATE_HALTING;
+                    break;  
+                case HCI_POWER_SLEEP:
+                    // see hci_run
+                    hci_stack.state = HCI_STATE_FALLING_ASLEEP;
+                    hci_stack.substate = 0;
+                    break;
+            }
+            break;
+            
+        case HCI_STATE_HALTING:
+            switch (power_mode){
+                case HCI_POWER_ON:
+                    // set up state machine
+                    hci_stack.state = HCI_STATE_INITIALIZING;
+                    hci_stack.substate = 0;
+                    break;
+                case HCI_POWER_OFF:
+                    // do nothing
+                    break;  
+                case HCI_POWER_SLEEP:
+                    // see hci_run
+                    hci_stack.state = HCI_STATE_FALLING_ASLEEP;
+                    hci_stack.substate = 0;
+                    break;
+            }
+            break;
+            
+        case HCI_STATE_FALLING_ASLEEP:
+            switch (power_mode){
+                case HCI_POWER_ON:
+
+#if defined(USE_POWERMANAGEMENT) && defined(USE_BLUETOOL)
+                    // nothing to do, if H4 supports power management
+                    if (bt_control_iphone_power_management_enabled()){
+                        hci_stack.state = HCI_STATE_INITIALIZING;
+                        hci_stack.substate = 6;
+                        break;
+                    }
+#endif
+                    // set up state machine
+                    hci_stack.num_cmd_packets = 1; // assume that one cmd can be sent
+                    hci_stack.state = HCI_STATE_INITIALIZING;
+                    hci_stack.substate = 0;
+                    break;
+                case HCI_POWER_OFF:
+                    // see hci_run
+                    hci_stack.state = HCI_STATE_HALTING;
+                    break;  
+                case HCI_POWER_SLEEP:
+                    // do nothing
+                    break;
+            }
+            break;
+            
+        case HCI_STATE_SLEEPING:
+            switch (power_mode){
+                case HCI_POWER_ON:
+                    
+#if defined(USE_POWERMANAGEMENT) && defined(USE_BLUETOOL)
+                    // nothing to do, if H4 supports power management
+                    if (bt_control_iphone_power_management_enabled()){
+                        hci_stack.state = HCI_STATE_INITIALIZING;
+                        hci_stack.substate = 6;
+                        hci_update_scan_enable();
+                        break;
+                    }
+#endif
+                    err = hci_power_control_wake();
+                    if (err) return err;
+                    // set up state machine
+                    hci_stack.num_cmd_packets = 1; // assume that one cmd can be sent
+                    hci_stack.state = HCI_STATE_INITIALIZING;
+                    hci_stack.substate = 0;
+                    break;
+                case HCI_POWER_OFF:
+                    hci_stack.state = HCI_STATE_HALTING;
+                    break;  
+                case HCI_POWER_SLEEP:
+                    // do nothing
+                    break;
+            }
+            break;
+    }
+
+    // create internal event
+    hci_emit_state();
+    
+    // trigger next/first action
+    hci_run();
+    
+    return 0;
+}
+
+static void hci_update_scan_enable(void){
+    // 2 = page scan, 1 = inq scan
+    hci_stack.new_scan_enable_value  = hci_stack.connectable << 1 | hci_stack.discoverable;
+    hci_run();
+}
+
+void hci_discoverable_control(uint8_t enable){
+    if (enable) enable = 1; // normalize argument
+    
+    if (hci_stack.discoverable == enable){
+        hci_emit_discoverable_enabled(hci_stack.discoverable);
+        return;
+    }
+
+    hci_stack.discoverable = enable;
+    hci_update_scan_enable();
+}
+
+void hci_connectable_control(uint8_t enable){
+    if (enable) enable = 1; // normalize argument
+    
+    // don't emit event
+    if (hci_stack.connectable == enable) return;
+
+    hci_stack.connectable = enable;
+    hci_update_scan_enable();
+}
+
+void hci_run(){
+        
+    hci_connection_t * connection;
+    linked_item_t * it;
+    
+    if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
+
+    // global/non-connection oriented commands
+    
+    // decline incoming connections
+    if (hci_stack.decline_reason){
+        uint8_t reason = hci_stack.decline_reason;
+        hci_stack.decline_reason = 0;
+        hci_send_cmd(&hci_reject_connection_request, hci_stack.decline_addr, reason);
+    }
+
+    if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
+
+    // send scan enable
+    if (hci_stack.new_scan_enable_value != 0xff){
+        hci_send_cmd(&hci_write_scan_enable, hci_stack.new_scan_enable_value);
+        hci_stack.new_scan_enable_value = 0xff;
+    }
+    
+    // send pending HCI commands
+    for (it = (linked_item_t *) hci_stack.connections; it ; it = it->next){
+
+        if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
+
+        connection = (hci_connection_t *) it;
+        
+        if (connection->state == RECEIVED_CONNECTION_REQUEST){
+            log_info("sending hci_accept_connection_request\n");
+            hci_send_cmd(&hci_accept_connection_request, connection->address, 1);
+            connection->state = ACCEPTED_CONNECTION_REQUEST;
+        }
+
+        if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
+        
+        if (connection->authentication_flags & HANDLE_LINK_KEY_REQUEST){
+            link_key_t link_key;
+            log_info("responding to link key request\n");
+            if (hci_stack.remote_device_db->get_link_key( &connection->address, &link_key)){
+               hci_send_cmd(&hci_link_key_request_reply, connection->address, &link_key);
+            } else {
+               hci_send_cmd(&hci_link_key_request_negative_reply, connection->address);
+            }
+            connectionClearAuthenticationFlags(connection, HANDLE_LINK_KEY_REQUEST);
+        }
+    }
+
+    if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
+        
+    switch (hci_stack.state){
+        case HCI_STATE_INITIALIZING:
+            // log_info("hci_init: substate %u\n", hci_stack.substate);
+            if (hci_stack.substate % 2) {
+                // odd: waiting for command completion
+                return;
+            }
+            switch (hci_stack.substate >> 1){
+                case 0: // RESET
+                    hci_send_cmd(&hci_reset);
+                    if (hci_stack.config == 0 || ((hci_uart_config_t *)hci_stack.config)->baudrate_main == 0){
+                        // skip baud change
+                        hci_stack.substate = 4; // >> 1 = 2
+                    }
+                    break;
+                case 1: // SEND BAUD CHANGE
+                    hci_stack.control->baudrate_cmd(hci_stack.config, ((hci_uart_config_t *)hci_stack.config)->baudrate_main, hci_stack.hci_packet_buffer);
+                    hci_send_cmd_packet(hci_stack.hci_packet_buffer, 3 + hci_stack.hci_packet_buffer[2]);
+                    break;
+                case 2: // LOCAL BAUD CHANGE
+                    hci_stack.hci_transport->set_baudrate(((hci_uart_config_t *)hci_stack.config)->baudrate_main);
+                    hci_stack.substate += 2;
+                    // break missing here for fall through
+                    
+                case 3:
+                    // custom initialization
+                    if (hci_stack.control && hci_stack.control->next_cmd){
+                        int valid_cmd = (*hci_stack.control->next_cmd)(hci_stack.config, hci_stack.hci_packet_buffer);
+                        if (valid_cmd){
+                            int size = 3 + hci_stack.hci_packet_buffer[2];
+                            hci_stack.hci_transport->send_packet(HCI_COMMAND_DATA_PACKET, hci_stack.hci_packet_buffer, size);
+                            hci_stack.substate = 4; // more init commands
+                            break;
+                        }
+                        log_info("hci_run: init script done\n\r");
+                    }
+                    // otherwise continue
+                    hci_send_cmd(&hci_read_bd_addr);
+                    break;
+                case 4:
+                    hci_send_cmd(&hci_read_buffer_size);
+                    break;
+                case 5:
+                    // ca. 15 sec
+                    hci_send_cmd(&hci_write_page_timeout, 0x6000);
+                    break;
+                case 6:
+                    hci_send_cmd(&hci_write_scan_enable, (hci_stack.connectable << 1) | hci_stack.discoverable); // page scan
+                    break;
+                case 7:
+#ifndef EMBEDDED
+                {
+                    char hostname[30];
+                    gethostname(hostname, 30);
+                    hostname[29] = '\0';
+                    hci_send_cmd(&hci_write_local_name, hostname);
+                    break;
+                }
+                case 8:
+#ifdef USE_BLUETOOL
+                    hci_send_cmd(&hci_write_class_of_device, 0x007a020c); // Smartphone
+                    break;
+                    
+                case 9:
+#endif
+#endif
+                    // done.
+                    hci_stack.state = HCI_STATE_WORKING;
+                    hci_emit_state();
+                    break;
+                default:
+                    break;
+            }
+            hci_stack.substate++;
+            break;
+            
+        case HCI_STATE_HALTING:
+
+            log_info("HCI_STATE_HALTING\n");
+            // close all open connections
+            connection =  (hci_connection_t *) hci_stack.connections;
+            if (connection){
+                
+                // send disconnect
+                if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
+                
+                log_info("HCI_STATE_HALTING, connection %p, handle %u\n", connection, (uint16_t)connection->con_handle);
+                hci_send_cmd(&hci_disconnect, connection->con_handle, 0x13);  // remote closed connection
+
+                // send disconnected event right away - causes higher layer connections to get closed, too.
+                hci_shutdown_connection(connection);
+                return;
+            }
+            log_info("HCI_STATE_HALTING, calling off\n");
+            
+            // switch mode
+            hci_power_control_off();
+            
+            log_info("HCI_STATE_HALTING, emitting state\n");
+            hci_emit_state();
+            log_info("HCI_STATE_HALTING, done\n");
+            break;
+            
+        case HCI_STATE_FALLING_ASLEEP:
+            switch(hci_stack.substate) {
+                case 0:
+                    log_info("HCI_STATE_FALLING_ASLEEP\n");
+                    // close all open connections
+                    connection =  (hci_connection_t *) hci_stack.connections;
+
+#if defined(USE_POWERMANAGEMENT) && defined(USE_BLUETOOL)
+                    // don't close connections, if H4 supports power management
+                    if (bt_control_iphone_power_management_enabled()){
+                        connection = NULL;
+                    }
+#endif
+                    if (connection){
+                        
+                        // send disconnect
+                        if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
+
+                        log_info("HCI_STATE_FALLING_ASLEEP, connection %p, handle %u\n", connection, (uint16_t)connection->con_handle);
+                        hci_send_cmd(&hci_disconnect, connection->con_handle, 0x13);  // remote closed connection
+                        
+                        // send disconnected event right away - causes higher layer connections to get closed, too.
+                        hci_shutdown_connection(connection);
+                        return;
+                    }
+                    
+                    // disable page and inquiry scan
+                    if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
+                    
+                    log_info("HCI_STATE_HALTING, disabling inq cans\n");
+                    hci_send_cmd(&hci_write_scan_enable, hci_stack.connectable << 1); // drop inquiry scan but keep page scan
+                    
+                    // continue in next sub state
+                    hci_stack.substate++;
+                    break;
+                case 1:
+                    // wait for command complete "hci_write_scan_enable" in event_handler();
+                    break;
+                case 2:
+                    log_info("HCI_STATE_HALTING, calling sleep\n");
+#if defined(USE_POWERMANAGEMENT) && defined(USE_BLUETOOL)
+                    // don't actually go to sleep, if H4 supports power management
+                    if (bt_control_iphone_power_management_enabled()){
+                        // SLEEP MODE reached
+                        hci_stack.state = HCI_STATE_SLEEPING; 
+                        hci_emit_state();
+                        break;
+                    }
+#endif
+                    // switch mode
+                    hci_power_control_sleep();  // changes hci_stack.state to SLEEP
+                    hci_emit_state();
+                    break;
+                    
+                default:
+                    break;
+            }
+            break;
+            
+        default:
+            break;
+    }
+}
+
+int hci_send_cmd_packet(uint8_t *packet, int size){
+    bd_addr_t addr;
+    hci_connection_t * conn;
+    // house-keeping
+    
+    // create_connection?
+    if (IS_COMMAND(packet, hci_create_connection)){
+        bt_flip_addr(addr, &packet[3]);
+        log_info("Create_connection to %s\n", bd_addr_to_str(addr));
+        conn = connection_for_address(addr);
+        if (conn) {
+            // if connection exists
+            if (conn->state == OPEN) {
+                // and OPEN, emit connection complete command
+                hci_emit_connection_complete(conn, 0);
+            }
+            //    otherwise, just ignore as it is already in the open process
+            return 0; // don't sent packet to controller
+            
+        }
+        // create connection struct and register, state = SENT_CREATE_CONNECTION
+        conn = create_connection_for_addr(addr);
+        if (!conn){
+            // notify client that alloc failed
+            hci_emit_connection_complete(conn, BTSTACK_MEMORY_ALLOC_FAILED);
+            return 0; // don't sent packet to controller
+        }
+        conn->state = SENT_CREATE_CONNECTION;
+    }
+    
+    if (IS_COMMAND(packet, hci_link_key_request_reply)){
+        hci_add_connection_flags_for_flipped_bd_addr(&packet[3], SENT_LINK_KEY_REPLY);
+    }
+    if (IS_COMMAND(packet, hci_link_key_request_negative_reply)){
+        hci_add_connection_flags_for_flipped_bd_addr(&packet[3], SENT_LINK_KEY_NEGATIVE_REQUEST);
+    }
+    if (IS_COMMAND(packet, hci_pin_code_request_reply)){
+        hci_add_connection_flags_for_flipped_bd_addr(&packet[3], SENT_PIN_CODE_REPLY);
+    }
+    if (IS_COMMAND(packet, hci_pin_code_request_negative_reply)){
+        hci_add_connection_flags_for_flipped_bd_addr(&packet[3], SENT_PIN_CODE_NEGATIVE_REPLY);
+    }
+    
+    if (IS_COMMAND(packet, hci_delete_stored_link_key)){
+        if (hci_stack.remote_device_db){
+            bt_flip_addr(addr, &packet[3]);
+            hci_stack.remote_device_db->delete_link_key(&addr);
+        }
+    }
+    
+    hci_stack.num_cmd_packets--;
+    return hci_stack.hci_transport->send_packet(HCI_COMMAND_DATA_PACKET, packet, size);
+}
+
+/**
+ * pre: numcmds >= 0 - it's allowed to send a command to the controller
+ */
+int hci_send_cmd(const hci_cmd_t *cmd, ...){
+    va_list argptr;
+    va_start(argptr, cmd);
+    uint16_t size = hci_create_cmd_internal(hci_stack.hci_packet_buffer, cmd, argptr);
+    va_end(argptr);
+    return hci_send_cmd_packet(hci_stack.hci_packet_buffer, size);
+}
+
+// Create various non-HCI events. 
+// TODO: generalize, use table similar to hci_create_command
+
+void hci_emit_state(){
+    uint8_t event[3];
+    event[0] = BTSTACK_EVENT_STATE;
+    event[1] = sizeof(event) - 2;
+    event[2] = hci_stack.state;
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void hci_emit_connection_complete(hci_connection_t *conn, uint8_t status){
+    uint8_t event[13];
+    event[0] = HCI_EVENT_CONNECTION_COMPLETE;
+    event[1] = sizeof(event) - 2;
+    event[2] = status;
+    bt_store_16(event, 3, conn->con_handle);
+    bt_flip_addr(&event[5], conn->address);
+    event[11] = 1; // ACL connection
+    event[12] = 0; // encryption disabled
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void hci_emit_disconnection_complete(uint16_t handle, uint8_t reason){
+    uint8_t event[6];
+    event[0] = HCI_EVENT_DISCONNECTION_COMPLETE;
+    event[1] = sizeof(event) - 2;
+    event[2] = 0; // status = OK
+    bt_store_16(event, 3, handle);
+    event[5] = reason;
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void hci_emit_l2cap_check_timeout(hci_connection_t *conn){
+    uint8_t event[4];
+    event[0] = L2CAP_EVENT_TIMEOUT_CHECK;
+    event[1] = sizeof(event) - 2;
+    bt_store_16(event, 2, conn->con_handle);
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void hci_emit_nr_connections_changed(){
+    uint8_t event[3];
+    event[0] = BTSTACK_EVENT_NR_CONNECTIONS_CHANGED;
+    event[1] = sizeof(event) - 2;
+    event[2] = nr_hci_connections();
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void hci_emit_hci_open_failed(){
+    uint8_t event[2];
+    event[0] = BTSTACK_EVENT_POWERON_FAILED;
+    event[1] = sizeof(event) - 2;
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+#ifndef EMBEDDED
+void hci_emit_btstack_version() {
+    uint8_t event[6];
+    event[0] = BTSTACK_EVENT_VERSION;
+    event[1] = sizeof(event) - 2;
+    event[2] = BTSTACK_MAJOR;
+    event[3] = BTSTACK_MINOR;
+    bt_store_16(event, 4, BTSTACK_REVISION);
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
+#endif
+
+void hci_emit_system_bluetooth_enabled(uint8_t enabled){
+    uint8_t event[3];
+    event[0] = BTSTACK_EVENT_SYSTEM_BLUETOOTH_ENABLED;
+    event[1] = sizeof(event) - 2;
+    event[2] = enabled;
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void hci_emit_remote_name_cached(bd_addr_t *addr, device_name_t *name){
+    uint8_t event[2+1+6+248];
+    event[0] = BTSTACK_EVENT_REMOTE_NAME_CACHED;
+    event[1] = sizeof(event) - 2;
+    event[2] = 0;   // just to be compatible with HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE
+    bt_flip_addr(&event[3], *addr);
+    memcpy(&event[9], name, 248);
+    hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void hci_emit_discoverable_enabled(uint8_t enabled){
+    uint8_t event[3];
+    event[0] = BTSTACK_EVENT_DISCOVERABLE_ENABLED;
+    event[1] = sizeof(event) - 2;
+    event[2] = enabled;
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/hci.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  hci.h
+ *
+ *  Created by Matthias Ringwald on 4/29/09.
+ *
+ */
+
+#pragma once
+
+#include "config.h"
+
+#include <btstack/hci_cmds.h>
+#include <btstack/utils.h>
+#include "hci_transport.h"
+#include "bt_control.h"
+#include "remote_device_db.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#if defined __cplusplus
+extern "C" {
+#endif
+    
+// packet header sizes
+#define HCI_CMD_HEADER_SIZE          3
+#define HCI_ACL_HEADER_SIZE            4
+#define HCI_SCO_HEADER_SIZE           3
+#define HCI_EVENT_HEADER_SIZE        2
+
+// packet sizes (max payload)
+#define HCI_ACL_DM1_SIZE            17
+#define HCI_ACL_DH1_SIZE            27
+#define HCI_ACL_2DH1_SIZE           54
+#define HCI_ACL_3DH1_SIZE           83
+#define HCI_ACL_DM3_SIZE           121
+#define HCI_ACL_DH3_SIZE           183
+#define HCI_ACL_DM5_SIZE           224
+#define HCI_ACL_DH5_SIZE           339
+#define HCI_ACL_2DH3_SIZE          367
+#define HCI_ACL_3DH3_SIZE          552
+#define HCI_ACL_2DH5_SIZE          679
+#define HCI_ACL_3DH5_SIZE         1021
+       
+#define HCI_EVENT_PAYLOAD_SIZE     255
+#define HCI_CMD_PAYLOAD_SIZE       255
+    
+// packet buffer sizes
+// HCI_ACL_PAYLOAD_SIZE is configurable and defined in config.h
+#define HCI_EVENT_BUFFER_SIZE      (HCI_EVENT_HEADER_SIZE + HCI_EVENT_PAYLOAD_SIZE)
+#define HCI_CMD_BUFFER_SIZE        (HCI_CMD_HEADER_SIZE   + HCI_CMD_PAYLOAD_SIZE)
+#define HCI_ACL_BUFFER_SIZE        (HCI_ACL_HEADER_SIZE   + HCI_ACL_PAYLOAD_SIZE)
+    
+// size of hci buffers, big enough for command, event, or acl packet without H4 packet type
+// @note cmd buffer is bigger than event buffer
+#if HCI_ACL_BUFFER_SIZE > HCI_CMD_BUFFER_SIZE
+#define HCI_PACKET_BUFFER_SIZE HCI_ACL_BUFFER_SIZE
+#else
+#define HCI_PACKET_BUFFER_SIZE HCI_CMD_BUFFER_SIZE
+#endif
+    
+// OGFs
+#define OGF_STATUS_PARAMETERS     0x05  //sibu
+#define OGF_LINK_CONTROL          0x01
+#define OGF_LINK_POLICY           0x02
+#define OGF_CONTROLLER_BASEBAND   0x03
+#define OGF_INFORMATIONAL_PARAMETERS 0x04
+#define OGF_LE_CONTROLLER 0x08
+#define OGF_BTSTACK 0x3d
+#define OGF_VENDOR  0x3f
+
+// cmds for BTstack 
+// get state: @returns HCI_STATE
+#define BTSTACK_GET_STATE                                  0x01
+
+// set power mode: @param HCI_POWER_MODE
+#define BTSTACK_SET_POWER_MODE                             0x02
+
+// set capture mode: @param on
+#define BTSTACK_SET_ACL_CAPTURE_MODE                       0x03
+
+// get BTstack version
+#define BTSTACK_GET_VERSION                                0x04
+
+// get system Bluetooth state
+#define BTSTACK_GET_SYSTEM_BLUETOOTH_ENABLED               0x05
+
+// set system Bluetooth state
+#define BTSTACK_SET_SYSTEM_BLUETOOTH_ENABLED               0x06
+
+// enable inquiry scan for this client
+#define BTSTACK_SET_DISCOVERABLE                           0x07
+
+// set global Bluetooth state
+#define BTSTACK_SET_BLUETOOTH_ENABLED                      0x08
+
+// create l2cap channel: @param bd_addr(48), psm (16)
+#define L2CAP_CREATE_CHANNEL                               0x20
+
+// disconnect l2cap disconnect, @param channel(16), reason(8)
+#define L2CAP_DISCONNECT                                   0x21
+
+// register l2cap service: @param psm(16), mtu (16)
+#define L2CAP_REGISTER_SERVICE                             0x22
+
+// unregister l2cap disconnect, @param psm(16)
+#define L2CAP_UNREGISTER_SERVICE                           0x23
+
+// accept connection @param bd_addr(48), dest cid (16)
+#define L2CAP_ACCEPT_CONNECTION                            0x24
+
+// decline l2cap disconnect,@param bd_addr(48), dest cid (16), reason(8)
+#define L2CAP_DECLINE_CONNECTION                           0x25
+
+// create l2cap channel: @param bd_addr(48), psm (16), mtu (16)
+#define L2CAP_CREATE_CHANNEL_MTU                           0x26
+
+// register SDP Service Record: service record (size)
+#define SDP_REGISTER_SERVICE_RECORD                        0x30
+
+// unregister SDP Service Record
+#define SDP_UNREGISTER_SERVICE_RECORD                      0x31
+
+// RFCOMM "HCI" Commands
+#define RFCOMM_CREATE_CHANNEL       0x40
+#define RFCOMM_DISCONNECT            0x41
+#define RFCOMM_REGISTER_SERVICE     0x42
+#define RFCOMM_UNREGISTER_SERVICE   0x43
+#define RFCOMM_ACCEPT_CONNECTION    0x44
+#define RFCOMM_DECLINE_CONNECTION   0x45
+#define RFCOMM_PERSISTENT_CHANNEL   0x46
+#define RFCOMM_CREATE_CHANNEL_WITH_CREDITS   0x47
+#define RFCOMM_REGISTER_SERVICE_WITH_CREDITS 0x48
+#define RFCOMM_GRANT_CREDITS                 0x49
+    
+// 
+#define IS_COMMAND(packet, command) (READ_BT_16(packet,0) == command.opcode)
+
+// data: event(8)
+#define DAEMON_EVENT_CONNECTION_OPENED                     0x50
+
+// data: event(8)
+#define DAEMON_EVENT_CONNECTION_CLOSED                     0x51
+
+// data: event(8), nr_connections(8)
+#define DAEMON_NR_CONNECTIONS_CHANGED                      0x52
+
+// data: event(8)
+#define DAEMON_EVENT_NEW_RFCOMM_CREDITS                    0x53
+
+// data: event()
+#define DAEMON_EVENT_HCI_PACKET_SENT                       0x54
+    
+/**
+ * Connection State 
+ */
+typedef enum {
+    AUTH_FLAGS_NONE                = 0x00,
+    RECV_LINK_KEY_REQUEST          = 0x01,
+    HANDLE_LINK_KEY_REQUEST        = 0x02,
+    SENT_LINK_KEY_REPLY            = 0x04,
+    SENT_LINK_KEY_NEGATIVE_REQUEST = 0x08,
+    RECV_LINK_KEY_NOTIFICATION     = 0x10,
+    RECV_PIN_CODE_REQUEST          = 0x20,
+    SENT_PIN_CODE_REPLY            = 0x40, 
+    SENT_PIN_CODE_NEGATIVE_REPLY   = 0x80 
+} hci_authentication_flags_t;
+
+typedef enum {
+    SENT_CREATE_CONNECTION = 1,
+    RECEIVED_CONNECTION_REQUEST,
+    ACCEPTED_CONNECTION_REQUEST,
+    REJECTED_CONNECTION_REQUEST,
+    OPEN,
+    SENT_DISCONNECT
+} CONNECTION_STATE;
+
+typedef enum {
+    BLUETOOTH_OFF = 1,
+    BLUETOOTH_ON,
+    BLUETOOTH_ACTIVE
+} BLUETOOTH_STATE;
+
+typedef struct {
+    // linked list - assert: first field
+    linked_item_t    item;
+    
+    // remote side
+    bd_addr_t address;
+    
+    // module handle
+    hci_con_handle_t con_handle;
+
+    // state
+    CONNECTION_STATE state;
+    
+    // errands
+    hci_authentication_flags_t authentication_flags;
+
+    timer_source_t timeout;
+    
+#ifdef HAVE_TIME
+    // timer
+    struct timeval timestamp;
+#endif
+#ifdef HAVE_TICK
+    uint32_t timestamp; // timeout in system ticks
+#endif
+    
+    // ACL packet recombination - ACL Header + ACL payload
+    uint8_t  acl_recombination_buffer[4 + HCI_ACL_BUFFER_SIZE];
+    uint16_t acl_recombination_pos;
+    uint16_t acl_recombination_length;
+    
+    // number ACL packets sent to controller
+    uint8_t num_acl_packets_sent;
+    
+} hci_connection_t;
+
+/**
+ * main data structure
+ */
+typedef struct {
+    // transport component with configuration
+    hci_transport_t  * hci_transport;
+    void             * config;
+    
+    // hardware power controller
+    bt_control_t     * control;
+    
+    // list of existing baseband connections
+    linked_list_t     connections;
+
+    // single buffer for HCI Command assembly
+    uint8_t          hci_packet_buffer[HCI_PACKET_BUFFER_SIZE]; // opcode (16), len(8)
+    
+    /* host to controller flow control */
+    uint8_t  num_cmd_packets;
+    // uint8_t  total_num_cmd_packets;
+    uint8_t  total_num_acl_packets;
+    uint16_t acl_data_packet_length;
+
+    // usable packet types given acl_data_packet_length and HCI_ACL_BUFFER_SIZE
+    uint16_t packet_types;
+    
+    /* callback to L2CAP layer */
+    void (*packet_handler)(uint8_t packet_type, uint8_t *packet, uint16_t size);
+
+    /* remote device db */
+    remote_device_db_t const*remote_device_db;
+    
+    /* hci state machine */
+    HCI_STATE state;
+    uint8_t   substate;
+    uint8_t   cmds_ready;
+    
+    uint8_t   discoverable;
+    uint8_t   connectable;
+    
+    /* buffer for scan enable cmd - 0xff no change */
+    uint8_t   new_scan_enable_value;
+    
+    // buffer for single connection decline
+    uint8_t   decline_reason;
+    bd_addr_t decline_addr;
+    
+} hci_stack_t;
+
+// create and send hci command packets based on a template and a list of parameters
+uint16_t hci_create_cmd(uint8_t *hci_cmd_buffer, hci_cmd_t *cmd, ...);
+uint16_t hci_create_cmd_internal(uint8_t *hci_cmd_buffer, const hci_cmd_t *cmd, va_list argptr);
+
+// set up HCI
+void hci_init(hci_transport_t *transport, void *config, bt_control_t *control, remote_device_db_t const* remote_device_db);
+void hci_register_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size));
+void hci_close(void);
+
+// power and inquriy scan control
+int  hci_power_control(HCI_POWER_MODE mode);
+void hci_discoverable_control(uint8_t enable);
+void hci_connectable_control(uint8_t enable);
+
+/**
+ * run the hci control loop once
+ */
+void hci_run(void);
+
+// create and send hci command packets based on a template and a list of parameters
+int hci_send_cmd(const hci_cmd_t *cmd, ...);
+
+// send complete CMD packet
+int hci_send_cmd_packet(uint8_t *packet, int size);
+
+// send ACL packet
+int hci_send_acl_packet(uint8_t *packet, int size);
+
+// non-blocking UART driver needs
+int hci_can_send_packet_now(uint8_t packet_type);
+    
+hci_connection_t * connection_for_handle(hci_con_handle_t con_handle);
+uint8_t  hci_number_outgoing_packets(hci_con_handle_t handle);
+uint8_t  hci_number_free_acl_slots(void);
+int      hci_authentication_active_for_handle(hci_con_handle_t handle);
+void     hci_drop_link_key_for_bd_addr(bd_addr_t *addr);
+uint16_t hci_max_acl_data_packet_length(void);
+uint16_t hci_usable_acl_packet_types(void);
+uint8_t* hci_get_outgoing_acl_packet_buffer(void);
+
+// 
+void hci_emit_state(void);
+void hci_emit_connection_complete(hci_connection_t *conn, uint8_t status);
+void hci_emit_l2cap_check_timeout(hci_connection_t *conn);
+void hci_emit_disconnection_complete(uint16_t handle, uint8_t reason);
+void hci_emit_nr_connections_changed(void);
+void hci_emit_hci_open_failed(void);
+void hci_emit_btstack_version(void);
+void hci_emit_system_bluetooth_enabled(uint8_t enabled);
+void hci_emit_remote_name_cached(bd_addr_t *addr, device_name_t *name);
+void hci_emit_discoverable_enabled(uint8_t enabled);
+
+#if defined __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/hci_cmds.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,693 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  hci_cmds.c
+ *
+ *  Created by Matthias Ringwald on 7/23/09.
+ */
+
+#include <btstack/hci_cmds.h>
+
+#include <string.h>
+
+#include <btstack/sdp_util.h>
+#include "config.h"
+#include "hci.h"
+
+// calculate combined ogf/ocf value
+#define OPCODE(ogf, ocf) (ocf | ogf << 10)
+
+/**
+ * construct HCI Command based on template
+ *
+ * Format:
+ *   1,2,3,4: one to four byte value
+ *   H: HCI connection handle
+ *   B: Bluetooth Baseband Address (BD_ADDR)
+ *   E: Extended Inquiry Result
+ *   N: Name up to 248 chars, \0 terminated
+ *   P: 16 byte Pairing code
+ *   S: Service Record (Data Element Sequence)
+ */
+uint16_t hci_create_cmd_internal(uint8_t *hci_cmd_buffer, const hci_cmd_t *cmd, va_list argptr){
+    
+    hci_cmd_buffer[0] = cmd->opcode & 0xff;
+    hci_cmd_buffer[1] = cmd->opcode >> 8;
+    int pos = 3;
+    
+    const char *format = cmd->format;
+    uint16_t word;
+    uint32_t longword;
+    uint8_t * ptr;
+    while (*format) {
+        switch(*format) {
+            case '1': //  8 bit value
+            case '2': // 16 bit value
+            case 'H': // hci_handle
+                word = va_arg(argptr, int);  // minimal va_arg is int: 2 bytes on 8+16 bit CPUs
+                hci_cmd_buffer[pos++] = word & 0xff;
+                if (*format == '2') {
+                    hci_cmd_buffer[pos++] = word >> 8;
+                } else if (*format == 'H') {
+                    // TODO implement opaque client connection handles
+                    //      pass module handle for now
+                    hci_cmd_buffer[pos++] = word >> 8;
+                } 
+                break;
+            case '3':
+            case '4':
+                longword = va_arg(argptr, uint32_t);
+                // longword = va_arg(argptr, int);
+                hci_cmd_buffer[pos++] = longword;
+                hci_cmd_buffer[pos++] = longword >> 8;
+                hci_cmd_buffer[pos++] = longword >> 16;
+                if (*format == '4'){
+                    hci_cmd_buffer[pos++] = longword >> 24;
+                }
+                break;
+            case 'B': // bt-addr
+                ptr = va_arg(argptr, uint8_t *);
+                hci_cmd_buffer[pos++] = ptr[5];
+                hci_cmd_buffer[pos++] = ptr[4];
+                hci_cmd_buffer[pos++] = ptr[3];
+                hci_cmd_buffer[pos++] = ptr[2];
+                hci_cmd_buffer[pos++] = ptr[1];
+                hci_cmd_buffer[pos++] = ptr[0];
+                break;
+            case 'E': // Extended Inquiry Information 240 octets
+                ptr = va_arg(argptr, uint8_t *);
+                memcpy(&hci_cmd_buffer[pos], ptr, 240);
+                pos += 240;
+                break;
+            case 'N': { // UTF-8 string, null terminated
+                ptr = va_arg(argptr, uint8_t *);
+                uint16_t len = strlen((const char*) ptr);
+                if (len > 248) {
+                    len = 248;
+                }
+                memcpy(&hci_cmd_buffer[pos], ptr, len);
+                if (len < 248) {
+                    // fill remaining space with zeroes
+                    memset(&hci_cmd_buffer[pos+len], 0, 248-len);
+                }
+                pos += 248;
+                break;
+            }
+            case 'P': // 16 byte PIN code or link key
+                ptr = va_arg(argptr, uint8_t *);
+                memcpy(&hci_cmd_buffer[pos], ptr, 16);
+                pos += 16;
+                break;
+#ifdef HAVE_BLE
+            case 'A': // 31 bytes advertising data
+                ptr = va_arg(argptr, uint8_t *);
+                memcpy(&hci_cmd_buffer[pos], ptr, 31);
+                pos += 31;
+                break;
+#endif
+#ifdef HAVE_SDP
+            case 'S': { // Service Record (Data Element Sequence)
+                ptr = va_arg(argptr, uint8_t *);
+                uint16_t len = de_get_len(ptr);
+                memcpy(&hci_cmd_buffer[pos], ptr, len);
+                pos += len;
+                break;
+            }
+#endif
+            default:
+                break;
+        }
+        format++;
+    };
+    hci_cmd_buffer[2] = pos - 3;
+    return pos;
+}
+
+/**
+ * construct HCI Command based on template
+ *
+ * mainly calls hci_create_cmd_internal
+ */
+uint16_t hci_create_cmd(uint8_t *hci_cmd_buffer, hci_cmd_t *cmd, ...){
+    va_list argptr;
+    va_start(argptr, cmd);
+    uint16_t len = hci_create_cmd_internal(hci_cmd_buffer, cmd, argptr);
+    va_end(argptr);
+    return len;
+}
+
+
+/**
+ *  Link Control Commands 
+ */
+const hci_cmd_t hci_inquiry = {
+OPCODE(OGF_LINK_CONTROL, 0x01), "311"
+// LAP, Inquiry length, Num_responses
+};
+const hci_cmd_t hci_inquiry_cancel = {
+OPCODE(OGF_LINK_CONTROL, 0x02), ""
+// no params
+};
+const hci_cmd_t hci_create_connection = {
+OPCODE(OGF_LINK_CONTROL, 0x05), "B21121"
+// BD_ADDR, Packet_Type, Page_Scan_Repetition_Mode, Reserved, Clock_Offset, Allow_Role_Switch
+};
+const hci_cmd_t hci_disconnect = {
+OPCODE(OGF_LINK_CONTROL, 0x06), "H1"
+// Handle, Reason: 0x05, 0x13-0x15, 0x1a, 0x29
+// see Errors Codes in BT Spec Part D
+};
+const hci_cmd_t hci_create_connection_cancel = {
+OPCODE(OGF_LINK_CONTROL, 0x08), "B"
+// BD_ADDR
+};
+const hci_cmd_t hci_accept_connection_request = {
+OPCODE(OGF_LINK_CONTROL, 0x09), "B1"
+// BD_ADDR, Role: become master, stay slave
+};
+const hci_cmd_t hci_reject_connection_request = {
+OPCODE(OGF_LINK_CONTROL, 0x0a), "B1"
+// BD_ADDR, reason e.g. CONNECTION REJECTED DUE TO LIMITED RESOURCES (0x0d)
+};
+const hci_cmd_t hci_link_key_request_reply = {
+OPCODE(OGF_LINK_CONTROL, 0x0b), "BP"
+// BD_ADDR, LINK_KEY
+};
+const hci_cmd_t hci_link_key_request_negative_reply = {
+OPCODE(OGF_LINK_CONTROL, 0x0c), "B"
+// BD_ADDR
+};
+const hci_cmd_t hci_pin_code_request_reply = {
+OPCODE(OGF_LINK_CONTROL, 0x0d), "B1P"
+// BD_ADDR, pin length, PIN: c-string
+};
+const hci_cmd_t hci_pin_code_request_negative_reply = {
+OPCODE(OGF_LINK_CONTROL, 0x0e), "B"
+// BD_ADDR
+};
+const hci_cmd_t hci_authentication_requested = {
+OPCODE(OGF_LINK_CONTROL, 0x11), "H"
+// Handle
+};
+const hci_cmd_t hci_set_connection_encryption = {
+OPCODE(OGF_LINK_CONTROL, 0x13), "H1"
+// Handle, Encryption_Enable
+};
+const hci_cmd_t hci_change_connection_link_key = {
+OPCODE(OGF_LINK_CONTROL, 0x15), "H"
+// Handle
+};
+const hci_cmd_t hci_remote_name_request = {
+OPCODE(OGF_LINK_CONTROL, 0x19), "B112"
+// BD_ADDR, Page_Scan_Repetition_Mode, Reserved, Clock_Offset
+};
+const hci_cmd_t hci_remote_name_request_cancel = {
+OPCODE(OGF_LINK_CONTROL, 0x1A), "B"
+// BD_ADDR
+};
+
+/**
+ *  Link Policy Commands 
+ */
+const hci_cmd_t hci_sniff_mode = {
+OPCODE(OGF_LINK_POLICY, 0x03), "H2222"
+// handle, Sniff_Max_Interval, Sniff_Min_Interval, Sniff_Attempt, Sniff_Timeout:
+};
+const hci_cmd_t hci_qos_setup = {
+OPCODE(OGF_LINK_POLICY, 0x07), "H114444"
+// handle, flags, service_type, token rate (bytes/s), peak bandwith (bytes/s),
+// latency (us), delay_variation (us)
+};
+const hci_cmd_t hci_role_discovery = {
+OPCODE(OGF_LINK_POLICY, 0x09), "H"
+// handle
+};
+const hci_cmd_t hci_switch_role_command= {
+OPCODE(OGF_LINK_POLICY, 0x0b), "B1"
+// BD_ADDR, role: {0=master,1=slave}
+};
+const hci_cmd_t hci_read_link_policy_settings = {
+OPCODE(OGF_LINK_POLICY, 0x0c), "H"
+// handle 
+};
+const hci_cmd_t hci_write_link_policy_settings = {
+OPCODE(OGF_LINK_POLICY, 0x0d), "H2"
+// handle, settings
+};
+
+/**
+ *  Controller & Baseband Commands 
+ */
+const hci_cmd_t hci_set_event_mask = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x01), "44"
+// event_mask lower 4 octets, higher 4 bytes
+};
+const hci_cmd_t hci_reset = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x03), ""
+// no params
+};
+const hci_cmd_t hci_delete_stored_link_key = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x12), "B1"
+// BD_ADDR, Delete_All_Flag
+};
+const hci_cmd_t hci_write_local_name = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x13), "N"
+// Local name (UTF-8, Null Terminated, max 248 octets)
+};
+const hci_cmd_t hci_write_page_timeout = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x18), "2"
+// Page_Timeout * 0.625 ms
+};
+const hci_cmd_t hci_write_scan_enable = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x1A), "1"
+// Scan_enable: no, inq, page, inq+page
+};
+const hci_cmd_t hci_write_authentication_enable = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x20), "1"
+// Authentication_Enable
+};
+const hci_cmd_t hci_write_class_of_device = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x24), "3"
+// Class of Device
+};
+const hci_cmd_t hci_read_num_broadcast_retransmissions = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x29), ""
+};
+const hci_cmd_t hci_write_num_broadcast_retransmissions = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x2a), "1"
+// Num broadcast retransmissions (e.g. 0 for a single broadcast)
+};
+const hci_cmd_t hci_host_buffer_size = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x33), "2122"
+// Host_ACL_Data_Packet_Length:, Host_Synchronous_Data_Packet_Length:, Host_Total_Num_ACL_Data_Packets:, Host_Total_Num_Synchronous_Data_Packets:
+};
+const hci_cmd_t hci_read_link_supervision_timeout = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x36), "H"
+// handle
+};
+const hci_cmd_t hci_write_link_supervision_timeout = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x37), "H2"
+// handle, Range for N: 0x0001 Ð 0xFFFF Time (Range: 0.625ms Ð 40.9 sec)
+};
+const hci_cmd_t hci_write_inquiry_mode = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x45), "1"
+// Inquiry mode: 0x00 = standard, 0x01 = with RSSI, 0x02 = extended
+};
+const hci_cmd_t hci_write_extended_inquiry_response = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x52), "1E"
+// FEC_Required, Exstended Inquiry Response
+};
+const hci_cmd_t hci_write_simple_pairing_mode = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x56), "1"
+// mode: 0 = off, 1 = on
+};
+const hci_cmd_t hci_read_le_host_supported = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x6c), ""
+// params: none
+// return: status, le supported host, simultaneous le host
+};
+const hci_cmd_t hci_write_le_host_supported = {
+OPCODE(OGF_CONTROLLER_BASEBAND, 0x6d), "11"
+// param: le supported host, simultaneous le host
+// return: status
+};
+
+/**
+ * Informational Parameters
+ */
+const hci_cmd_t hci_read_local_supported_features = {
+OPCODE(OGF_INFORMATIONAL_PARAMETERS, 0x03), ""
+// no params
+};
+const hci_cmd_t hci_read_buffer_size = {
+OPCODE(OGF_INFORMATIONAL_PARAMETERS, 0x05), ""
+// no params
+};
+const hci_cmd_t hci_read_bd_addr = {
+OPCODE(OGF_INFORMATIONAL_PARAMETERS, 0x09), ""
+// no params
+};
+
+//sibu
+const hci_cmd_t hci_read_local_supprted_commands = {
+OPCODE(OGF_INFORMATIONAL_PARAMETERS, 0x02), ""
+// no params
+};
+/**
+ * Status Parameters
+ */
+const hci_cmd_t hci_read_rssi = {
+OPCODE(OGF_STATUS_PARAMETERS, 0x05), "H"
+// handle
+// return: handle,RSSI
+};
+
+#ifdef HAVE_BLE
+/**
+ * Low Energy Commands
+ */
+const hci_cmd_t hci_le_set_event_mask = {
+OPCODE(OGF_LE_CONTROLLER, 0x01), "44"
+// params: event_mask lower 4 octets, higher 4 bytes
+// return: status
+};
+const hci_cmd_t hci_le_read_buffer_size = {
+OPCODE(OGF_LE_CONTROLLER, 0x02), ""
+// params: none
+// return: status, le acl data packet len (16), total num le acl data packets(8)
+};
+const hci_cmd_t hci_le_read_supported_features = {
+OPCODE(OGF_LE_CONTROLLER, 0x03), ""
+// params: none
+// return: LE_Features See [Vol 6] Part B, Section 4.6
+};
+const hci_cmd_t hci_le_set_random_address = {
+OPCODE(OGF_LE_CONTROLLER, 0x05), "B"
+// params: random device address
+// return: status
+};
+const hci_cmd_t hci_le_set_advertising_parameters = {
+OPCODE(OGF_LE_CONTROLLER, 0x06), "22111B11"
+// param: min advertising interval, [0x0020,0x4000], default: 0x0800, unit: 0.625 msec
+// param: max advertising interval, [0x0020,0x4000], default: 0x0800, unit: 0.625 msec
+// param: advertising type (enum from 0): ADV_IND, ADC_DIRECT_IND, ADV_SCAN_IND, ADV_NONCONN_IND
+// param: own address type (enum from 0): public device address, random device address
+// param: direct address type (enum from 0): public device address, random device address
+// param: direct address - public or random address of device to be connecteed
+// param: advertising channel map (flags): chan_37(1), chan_38(2), chan_39(4)
+// param: advertising filter policy (enum from 0): scan any conn any, scan whitelist, con any, scan any conn whitelist, scan whitelist, con whitelist
+// return: status
+};
+const hci_cmd_t hci_le_read_advertising_channel_tx_power = {
+OPCODE(OGF_LE_CONTROLLER, 0x07), ""
+// params: none
+// return: status, level [-20,10] signed int (8), units dBm
+};
+const hci_cmd_t hci_le_set_advertising_data= {
+OPCODE(OGF_LE_CONTROLLER, 0x08), "1A"
+// param: advertising data len
+// param: advertising data (31 bytes)
+// return: status
+};
+const hci_cmd_t hci_le_set_scan_response_data= {
+OPCODE(OGF_LE_CONTROLLER, 0x09), "1A"
+// param: scan response data len
+// param: scan response data (31 bytes)
+// return: status
+};
+const hci_cmd_t hci_le_set_advertise_enable = {
+OPCODE(OGF_LE_CONTROLLER, 0x0a), "1"
+// params: avertise enable: off (0), on (1)
+// return: status
+};
+const hci_cmd_t hci_le_set_scan_parameters = {
+OPCODE(OGF_LE_CONTROLLER, 0x0b), "12211"
+// param: le scan type: passive (0), active (1)
+// param: le scan interval [0x0004,0x4000], unit: 0.625 msec
+// param: le scan window   [0x0004,0x4000], unit: 0.625 msec
+// param: own address type: public (0), random (1)
+// param: scanning filter policy: any (0), only whitelist (1)
+// return: status
+};
+const hci_cmd_t hci_le_set_scan_enable = {
+OPCODE(OGF_LE_CONTROLLER, 0x0c), "11"
+// param: le scan enable:  disabled (0), enabled (1)
+// param: filter duplices: disabled (0), enabled (1)
+// return: status
+};
+const hci_cmd_t hci_le_create_connection= {
+OPCODE(OGF_LE_CONTROLLER, 0x0d), "2211B1222222"
+// param: le scan interval, [0x0004, 0x4000], unit: 0.625 msec
+// param: le scan window, [0x0004, 0x4000], unit: 0.625 msec
+// param: initiator filter policy: peer address type + peer address (0), whitelist (1)
+// param: peer address type: public (0), random (1)
+// param: peer address
+// param: own address type: public (0), random (1)
+// param: conn interval min, [0x0006, 0x0c80], unit: 1.25 msec
+// param: conn interval max, [0x0006, 0x0c80], unit: 1.25 msec
+// param: conn latency, number of connection events [0x0000, 0x01f4]
+// param: supervision timeout, [0x000a, 0x0c80], unit: 10 msec
+// param: minimum CE length, [0x0000, 0xffff], unit: 0.625 msec
+// return: none -> le create connection complete event
+};
+const hci_cmd_t hci_le_create_connection_cancel = {
+OPCODE(OGF_LE_CONTROLLER, 0x0e), ""
+// params: none
+// return: status
+};
+const hci_cmd_t hci_le_read_white_list_size = {
+OPCODE(OGF_LE_CONTROLLER, 0x0f), ""
+// params: none
+// return: status, number of entries in controller whitelist
+};
+const hci_cmd_t hci_le_clear_white_list = {
+OPCODE(OGF_LE_CONTROLLER, 0x10), ""
+// params: none
+// return: status
+};
+const hci_cmd_t hci_le_add_device_to_whitelist = {
+OPCODE(OGF_LE_CONTROLLER, 0x11), "1B"
+// param: address type: public (0), random (1)
+// param: address
+// return: status
+};
+const hci_cmd_t hci_le_remove_device_from_whitelist = {
+OPCODE(OGF_LE_CONTROLLER, 0x12), "1B"
+// param: address type: public (0), random (1)
+// param: address
+// return: status
+};
+const hci_cmd_t hci_le_connection_update = {
+OPCODE(OGF_LE_CONTROLLER, 0x13), "H222222"
+// param: conn handle
+// param: conn interval min, [0x0006,0x0c80], unit: 1.25 msec
+// param: conn interval max, [0x0006,0x0c80], unit: 1.25 msec
+// param: conn latency, [0x0000,0x03e8], number of connection events
+// param: supervision timeout, [0x000a,0x0c80], unit: 10 msec
+// param: minimum CE length, [0x0000,0xffff], unit: 0.625 msec
+// param: maximum CE length, [0x0000,0xffff], unit: 0.625 msec
+// return: none -> le connection update complete event
+};
+const hci_cmd_t hci_le_set_host_channel_classification = {
+OPCODE(OGF_LE_CONTROLLER, 0x14), "41"
+// param: channel map 37 bit, split into first 32 and higher 5 bits
+// return: status
+};
+const hci_cmd_t hci_le_read_channel_map = {
+OPCODE(OGF_LE_CONTROLLER, 0x15), "H"
+// params: connection handle
+// return: status, connection handle, channel map (5 bytes, 37 used)
+};
+const hci_cmd_t hci_le_read_remote_used_features = {
+OPCODE(OGF_LE_CONTROLLER, 0x16), "H"
+// params: connection handle
+// return: none -> le read remote used features complete event
+};
+const hci_cmd_t hci_le_encrypt = {
+OPCODE(OGF_LE_CONTROLLER, 0x17), "PP"
+// param: key (128) for AES-128
+// param: plain text (128) 
+// return: status, encrypted data (128)
+};
+const hci_cmd_t hci_le_rand = {
+OPCODE(OGF_LE_CONTROLLER, 0x18), ""
+// params: none
+// return: status, random number (64)
+};
+const hci_cmd_t hci_le_start_encryption = {
+OPCODE(OGF_LE_CONTROLLER, 0x19), "H442P"
+// param: connection handle
+// param: 64 bit random number lower  32 bit
+// param: 64 bit random number higher 32 bit
+// param: encryption diversifier (16)
+// param: long term key (128)
+// return: none -> encryption changed or encryption key refresh complete event
+};
+const hci_cmd_t hci_le_long_term_key_request_reply = {
+OPCODE(OGF_LE_CONTROLLER, 0x1a), "HP"
+// param: connection handle
+// param: long term key (128)
+// return: status, connection handle
+};
+const hci_cmd_t hci_le_long_term_key_negative_reply = {
+OPCODE(OGF_LE_CONTROLLER, 0x1b), "H"
+// param: connection handle
+// return: status, connection handle
+};
+const hci_cmd_t hci_le_read_supported_states = {
+OPCODE(OGF_LE_CONTROLLER, 0x1c), "H"
+// param: none
+// return: status, LE states (64)
+};
+const hci_cmd_t hci_le_receiver_test = {
+OPCODE(OGF_LE_CONTROLLER, 0x1d), "1"
+// param: rx frequency, [0x00 0x27], frequency (MHz): 2420 + N*2
+// return: status
+};
+const hci_cmd_t hci_le_transmitter_test = {
+    OPCODE(OGF_LE_CONTROLLER, 0x1e), "111"
+    // param: tx frequency, [0x00 0x27], frequency (MHz): 2420 + N*2
+    // param: lengh of test payload [0x00,0x25]
+    // param: packet payload [0,7] different patterns
+    // return: status
+};
+const hci_cmd_t hci_le_test_end = {
+    OPCODE(OGF_LE_CONTROLLER, 0x1f), "1"
+    // params: none
+    // return: status, number of packets (8)
+};
+#endif
+
+// BTstack commands
+const hci_cmd_t btstack_get_state = {
+OPCODE(OGF_BTSTACK, BTSTACK_GET_STATE), ""
+// no params -> 
+};
+
+const hci_cmd_t btstack_set_power_mode = {
+OPCODE(OGF_BTSTACK, BTSTACK_SET_POWER_MODE), "1"
+// mode: 0 = off, 1 = on
+};
+
+const hci_cmd_t btstack_set_acl_capture_mode = {
+OPCODE(OGF_BTSTACK, BTSTACK_SET_ACL_CAPTURE_MODE), "1"
+// mode: 0 = off, 1 = on
+};
+
+const hci_cmd_t btstack_get_version = {
+OPCODE(OGF_BTSTACK, BTSTACK_GET_VERSION), ""
+};
+
+const hci_cmd_t btstack_get_system_bluetooth_enabled = {
+OPCODE(OGF_BTSTACK, BTSTACK_GET_SYSTEM_BLUETOOTH_ENABLED), ""
+};
+
+const hci_cmd_t btstack_set_system_bluetooth_enabled = {
+OPCODE(OGF_BTSTACK, BTSTACK_SET_SYSTEM_BLUETOOTH_ENABLED), "1"
+};
+
+const hci_cmd_t btstack_set_discoverable = {
+OPCODE(OGF_BTSTACK, BTSTACK_SET_DISCOVERABLE), "1"
+};
+
+const hci_cmd_t btstack_set_bluetooth_enabled = {
+// only used by btstack config
+OPCODE(OGF_BTSTACK, BTSTACK_SET_BLUETOOTH_ENABLED), "1"
+};
+
+const hci_cmd_t l2cap_create_channel = {
+OPCODE(OGF_BTSTACK, L2CAP_CREATE_CHANNEL), "B2"
+// @param bd_addr(48), psm (16)
+};
+const hci_cmd_t l2cap_create_channel_mtu = {
+OPCODE(OGF_BTSTACK, L2CAP_CREATE_CHANNEL_MTU), "B22"
+// @param bd_addr(48), psm (16), mtu (16)
+};
+const hci_cmd_t l2cap_disconnect = {
+OPCODE(OGF_BTSTACK, L2CAP_DISCONNECT), "21"
+// @param channel(16), reason(8)
+};
+const hci_cmd_t l2cap_register_service = {
+OPCODE(OGF_BTSTACK, L2CAP_REGISTER_SERVICE), "22"
+// @param psm (16), mtu (16)
+};
+const hci_cmd_t l2cap_unregister_service = {
+OPCODE(OGF_BTSTACK, L2CAP_UNREGISTER_SERVICE), "2"
+// @param psm (16)
+};
+const hci_cmd_t l2cap_accept_connection = {
+OPCODE(OGF_BTSTACK, L2CAP_ACCEPT_CONNECTION), "2"
+// @param source cid (16)
+};
+const hci_cmd_t l2cap_decline_connection = {
+OPCODE(OGF_BTSTACK, L2CAP_DECLINE_CONNECTION), "21"
+// @param source cid (16), reason(8)
+};
+const hci_cmd_t sdp_register_service_record = {
+OPCODE(OGF_BTSTACK, SDP_REGISTER_SERVICE_RECORD), "S"
+// @param service record handle (DES)
+};
+const hci_cmd_t sdp_unregister_service_record = {
+OPCODE(OGF_BTSTACK, SDP_UNREGISTER_SERVICE_RECORD), "4"
+// @param service record handle (32)
+};
+
+// create rfcomm channel: @param bd_addr(48), channel (8)
+const hci_cmd_t rfcomm_create_channel = {
+    OPCODE(OGF_BTSTACK, RFCOMM_CREATE_CHANNEL), "B1"
+};
+// create rfcomm channel: @param bd_addr(48), channel (8), mtu (16), credits (8)
+const hci_cmd_t rfcomm_create_channel_with_initial_credits = {
+    OPCODE(OGF_BTSTACK, RFCOMM_CREATE_CHANNEL_WITH_CREDITS), "B121"
+};
+// grant credits: @param rfcomm_cid(16), credits (8)
+const hci_cmd_t rfcomm_grants_credits= {
+    OPCODE(OGF_BTSTACK, RFCOMM_GRANT_CREDITS), "21"
+};
+// disconnect rfcomm disconnect, @param rfcomm_cid(16), reason(8)
+const  hci_cmd_t rfcomm_disconnect = {
+    OPCODE(OGF_BTSTACK, RFCOMM_DISCONNECT), "21"
+};
+
+// register rfcomm service: @param channel(8), mtu (16)
+const hci_cmd_t rfcomm_register_service = {
+    OPCODE(OGF_BTSTACK, RFCOMM_REGISTER_SERVICE), "12"
+};
+// register rfcomm service: @param channel(8), mtu (16), initial credits (8)
+const hci_cmd_t rfcomm_register_service_with_initial_credits = {
+    OPCODE(OGF_BTSTACK, RFCOMM_REGISTER_SERVICE_WITH_CREDITS), "121"
+};
+
+// unregister rfcomm service, @param service_channel(16)
+const hci_cmd_t rfcomm_unregister_service = {
+    OPCODE(OGF_BTSTACK, RFCOMM_UNREGISTER_SERVICE), "2"
+};
+// accept connection @param source cid (16)
+const hci_cmd_t rfcomm_accept_connection = {
+    OPCODE(OGF_BTSTACK, RFCOMM_ACCEPT_CONNECTION), "2"
+};
+// decline connection @param source cid (16)
+const hci_cmd_t rfcomm_decline_connection = {
+    OPCODE(OGF_BTSTACK, RFCOMM_DECLINE_CONNECTION), "21"
+};
+// request persisten rfcomm channel number for named service
+const hci_cmd_t rfcomm_persistent_channel_for_service = {
+    OPCODE(OGF_BTSTACK, RFCOMM_PERSISTENT_CHANNEL), "N"
+};
+
+// register rfcomm service: @param channel(8), mtu (16), initial credits (8)
+extern const hci_cmd_t rfcomm_register_service_with_initial_credits;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/hci_cmds.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2009 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ *  hci_cmds.h
+ *
+ *  Created by Matthias Ringwald on 7/23/09.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#if defined __cplusplus
+extern "C" {
+#endif
+    
+/**
+ * packet types - used in BTstack and over the H4 UART interface
+ */
+#define HCI_COMMAND_DATA_PACKET    0x01
+#define HCI_ACL_DATA_PACKET        0x02
+#define HCI_SCO_DATA_PACKET        0x03
+#define HCI_EVENT_PACKET        0x04
+
+// extension for client/server communication
+#define DAEMON_EVENT_PACKET     0x05
+    
+// L2CAP data
+#define L2CAP_DATA_PACKET       0x06
+
+// RFCOMM data
+#define RFCOMM_DATA_PACKET      0x07
+
+// Attribute protocol data
+#define ATT_DATA_PACKET         0x08
+
+// Security Manager protocol data
+#define SM_DATA_PACKET          0x09
+    
+// debug log messages
+#define LOG_MESSAGE_PACKET      0xfc
+
+    
+// Fixed PSM numbers
+#define PSM_SDP    0x01
+#define PSM_RFCOMM 0x03
+#define PSM_HID_CONTROL 0x11
+#define PSM_HID_INTERRUPT 0x13
+
+// Events from host controller to host
+#define HCI_EVENT_INQUIRY_COMPLETE                           0x01
+#define HCI_EVENT_INQUIRY_RESULT                           0x02
+#define HCI_EVENT_CONNECTION_COMPLETE                       0x03
+#define HCI_EVENT_CONNECTION_REQUEST                       0x04
+#define HCI_EVENT_DISCONNECTION_COMPLETE                     0x05
+#define HCI_EVENT_AUTHENTICATION_COMPLETE_EVENT            0x06
+#define HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE               0x07
+#define HCI_EVENT_ENCRYPTION_CHANGE                        0x08
+#define HCI_EVENT_CHANGE_CONNECTION_LINK_KEY_COMPLETE      0x09
+#define HCI_EVENT_MASTER_LINK_KEY_COMPLETE                 0x0A
+#define HCI_EVENT_READ_REMOTE_SUPPORTED_FEATURES_COMPLETE  0x0B
+#define HCI_EVENT_READ_REMOTE_VERSION_INFORMATION_COMPLETE 0x0C
+#define HCI_EVENT_QOS_SETUP_COMPLETE                       0x0D
+#define HCI_EVENT_COMMAND_COMPLETE                           0x0E
+#define HCI_EVENT_COMMAND_STATUS                           0x0F
+#define HCI_EVENT_HARDWARE_ERROR                           0x10
+#define HCI_EVENT_FLUSH_OCCURED                            0x11
+#define HCI_EVENT_ROLE_CHANGE                               0x12
+#define HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS                 0x13
+#define HCI_EVENT_MODE_CHANGE_EVENT                        0x14
+#define HCI_EVENT_RETURN_LINK_KEYS                         0x15
+#define HCI_EVENT_PIN_CODE_REQUEST                         0x16
+#define HCI_EVENT_LINK_KEY_REQUEST                         0x17
+#define HCI_EVENT_LINK_KEY_NOTIFICATION                    0x18
+#define HCI_EVENT_DATA_BUFFER_OVERFLOW                     0x1A
+#define HCI_EVENT_MAX_SLOTS_CHANGED                           0x1B
+#define HCI_EVENT_READ_CLOCK_OFFSET_COMPLETE               0x1C
+#define HCI_EVENT_PACKET_TYPE_CHANGED                      0x1D
+#define HCI_EVENT_INQUIRY_RESULT_WITH_RSSI                     0x22
+#define HCI_EVENT_EXTENDED_INQUIRY_RESPONSE                0x2F
+#define HCI_EVENT_LE_META                                  0x3E
+#define HCI_EVENT_VENDOR_SPECIFIC                           0xFF
+
+#define HCI_SUBEVENT_LE_CONNECTION_COMPLETE                0x01
+#define HCI_SUBEVENT_LE_ADVERTISING_REPORT                 0x02
+#define HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE         0x03
+#define HCI_SUBEVENT_LE_READ_REMOTE_USED_FEATURES_COMPLETE 0x04
+#define HCI_SUBEVENT_LE_LONG_TERM_KEY_REQUEST              0x05
+    
+// last used HCI_EVENT in 2.1 is 0x3d
+
+// events 0x50-0x5f are used internally
+
+// BTSTACK DAEMON EVENTS
+
+// events from BTstack for application/client lib
+#define BTSTACK_EVENT_STATE                                0x60
+
+// data: event(8), len(8), nr hci connections
+#define BTSTACK_EVENT_NR_CONNECTIONS_CHANGED               0x61
+
+// data: none
+#define BTSTACK_EVENT_POWERON_FAILED                       0x62
+
+// data: majot (8), minor (8), revision(16)
+#define BTSTACK_EVENT_VERSION                               0x63
+
+// data: system bluetooth on/off (bool)
+#define BTSTACK_EVENT_SYSTEM_BLUETOOTH_ENABLED               0x64
+
+// data: event (8), len(8), status (8) == 0, address (48), name (1984 bits = 248 bytes)
+#define BTSTACK_EVENT_REMOTE_NAME_CACHED                    0x65
+
+// data: discoverable enabled (bool)
+#define BTSTACK_EVENT_DISCOVERABLE_ENABLED                   0x66
+
+// L2CAP EVENTS
+    
+// data: event (8), len(8), status (8), address(48), handle (16), psm (16), local_cid(16), remote_cid (16), local_mtu(16), remote_mtu(16) 
+#define L2CAP_EVENT_CHANNEL_OPENED                         0x70
+
+// data: event (8), len(8), channel (16)
+#define L2CAP_EVENT_CHANNEL_CLOSED                         0x71
+
+// data: event (8), len(8), address(48), handle (16), psm (16), local_cid(16), remote_cid (16) 
+#define L2CAP_EVENT_INCOMING_CONNECTION                       0x72
+
+// data: event(8), len(8), handle(16)
+#define L2CAP_EVENT_TIMEOUT_CHECK                          0x73
+
+// data: event(8), len(8), local_cid(16), credits(8)
+#define L2CAP_EVENT_CREDITS                                   0x74
+
+// data: event(8), len(8), status (8), psm (16)
+#define L2CAP_EVENT_SERVICE_REGISTERED                     0x75
+
+
+// RFCOMM EVENTS
+    
+// data: event(8), len(8), status (8), address (48), handle (16), server channel(8), rfcomm_cid(16), max frame size(16)
+#define RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE                 0x80
+    
+// data: event(8), len(8), rfcomm_cid(16)
+#define RFCOMM_EVENT_CHANNEL_CLOSED                        0x81
+    
+// data: event (8), len(8), address(48), channel (8), rfcomm_cid (16)
+#define RFCOMM_EVENT_INCOMING_CONNECTION                   0x82
+    
+// data: event (8), len(8), rfcommid (16), ...
+#define RFCOMM_EVENT_REMOTE_LINE_STATUS                    0x83
+    
+// data: event(8), len(8), rfcomm_cid(16), credits(8)
+#define RFCOMM_EVENT_CREDITS                               0x84
+    
+// data: event(8), len(8), status (8), rfcomm server channel id (8) 
+#define RFCOMM_EVENT_SERVICE_REGISTERED                    0x85
+    
+// data: event(8), len(8), status (8), rfcomm server channel id (8) 
+#define RFCOMM_EVENT_PERSISTENT_CHANNEL                    0x86
+    
+    
+// data: event(8), len(8), status(8), service_record_handle(32)
+#define SDP_SERVICE_REGISTERED                             0x90
+
+    
+// last error code in 2.1 is 0x38 - we start with 0x50 for BTstack errors
+
+#define BTSTACK_CONNECTION_TO_BTDAEMON_FAILED              0x50
+#define BTSTACK_ACTIVATION_FAILED_SYSTEM_BLUETOOTH           0x51
+#define BTSTACK_ACTIVATION_POWERON_FAILED                  0x52
+#define BTSTACK_ACTIVATION_FAILED_UNKNOWN                  0x53
+#define BTSTACK_NOT_ACTIVATED                               0x54
+#define BTSTACK_BUSY                                       0x55
+#define BTSTACK_MEMORY_ALLOC_FAILED                        0x56
+#define BTSTACK_ACL_BUFFERS_FULL                           0x57
+
+// l2cap errors - enumeration by the command that created them
+#define L2CAP_COMMAND_REJECT_REASON_COMMAND_NOT_UNDERSTOOD 0x60
+#define L2CAP_COMMAND_REJECT_REASON_SIGNALING_MTU_EXCEEDED 0x61
+#define L2CAP_COMMAND_REJECT_REASON_INVALID_CID_IN_REQUEST 0x62
+
+#define L2CAP_CONNECTION_RESPONSE_RESULT_SUCCESSFUL        0x63
+#define L2CAP_CONNECTION_RESPONSE_RESULT_PENDING           0x64
+#define L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_PSM       0x65
+#define L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_SECURITY  0x66
+#define L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_RESOURCES 0x65
+
+#define L2CAP_CONFIG_RESPONSE_RESULT_SUCCESSFUL            0x66
+#define L2CAP_CONFIG_RESPONSE_RESULT_UNACCEPTABLE_PARAMS   0x67
+#define L2CAP_CONFIG_RESPONSE_RESULT_REJECTED              0x68
+#define L2CAP_CONFIG_RESPONSE_RESULT_UNKNOWN_OPTIONS       0x69
+#define L2CAP_SERVICE_ALREADY_REGISTERED                   0x6a
+    
+#define RFCOMM_MULTIPLEXER_STOPPED                         0x70
+#define RFCOMM_CHANNEL_ALREADY_REGISTERED                  0x71
+#define RFCOMM_NO_OUTGOING_CREDITS                         0x72
+
+#define SDP_HANDLE_ALREADY_REGISTERED                      0x80
+ 
+/**
+ * Default INQ Mode
+ */
+#define HCI_INQUIRY_LAP 0x9E8B33L  // 0x9E8B33: General/Unlimited Inquiry Access Code (GIAC)
+/**
+ *  Hardware state of Bluetooth controller 
+ */
+typedef enum {
+    HCI_POWER_OFF = 0,
+    HCI_POWER_ON,
+    HCI_POWER_SLEEP
+} HCI_POWER_MODE;
+
+/**
+ * State of BTstack 
+ */
+typedef enum {
+    HCI_STATE_OFF = 0,
+    HCI_STATE_INITIALIZING,
+    HCI_STATE_WORKING,
+    HCI_STATE_HALTING,
+    HCI_STATE_SLEEPING,
+    HCI_STATE_FALLING_ASLEEP
+} HCI_STATE;
+
+/** 
+ * compact HCI Command packet description
+ */
+ typedef struct {
+    uint16_t    opcode;
+    const char *format;
+} hci_cmd_t;
+
+
+// HCI Commands - see hci_cmds.c for info on parameters
+extern const hci_cmd_t btstack_get_state;
+extern const hci_cmd_t btstack_set_power_mode;
+extern const hci_cmd_t btstack_set_acl_capture_mode;
+extern const hci_cmd_t btstack_get_version;
+extern const hci_cmd_t btstack_get_system_bluetooth_enabled;
+extern const hci_cmd_t btstack_set_system_bluetooth_enabled;
+extern const hci_cmd_t btstack_set_discoverable;
+extern const hci_cmd_t btstack_set_bluetooth_enabled;    // only used by btstack config
+    
+extern const hci_cmd_t hci_accept_connection_request;
+extern const hci_cmd_t hci_authentication_requested;
+extern const hci_cmd_t hci_change_connection_link_key;
+extern const hci_cmd_t hci_create_connection;
+extern const hci_cmd_t hci_create_connection_cancel;
+extern const hci_cmd_t hci_delete_stored_link_key;
+extern const hci_cmd_t hci_disconnect;
+extern const hci_cmd_t hci_host_buffer_size;
+extern const hci_cmd_t hci_inquiry;
+extern const hci_cmd_t hci_inquiry_cancel;
+extern const hci_cmd_t hci_link_key_request_negative_reply;
+extern const hci_cmd_t hci_link_key_request_reply;
+extern const hci_cmd_t hci_pin_code_request_reply;
+extern const hci_cmd_t hci_pin_code_request_negative_reply;
+extern const hci_cmd_t hci_qos_setup;
+extern const hci_cmd_t hci_read_bd_addr;
+extern const hci_cmd_t hci_read_buffer_size;
+extern const hci_cmd_t hci_read_le_host_supported;
+extern const hci_cmd_t hci_read_link_policy_settings;
+extern const hci_cmd_t hci_read_link_supervision_timeout;
+extern const hci_cmd_t hci_read_local_supported_features;
+extern const hci_cmd_t hci_read_num_broadcast_retransmissions;
+extern const hci_cmd_t hci_reject_connection_request;
+extern const hci_cmd_t hci_remote_name_request;
+extern const hci_cmd_t hci_remote_name_request_cancel;
+extern const hci_cmd_t hci_reset;
+extern const hci_cmd_t hci_role_discovery;
+extern const hci_cmd_t hci_set_event_mask;
+extern const hci_cmd_t hci_set_connection_encryption;
+extern const hci_cmd_t hci_sniff_mode;
+extern const hci_cmd_t hci_switch_role_command;
+extern const hci_cmd_t hci_write_authentication_enable;
+extern const hci_cmd_t hci_write_class_of_device;
+extern const hci_cmd_t hci_write_extended_inquiry_response;
+extern const hci_cmd_t hci_write_inquiry_mode;
+extern const hci_cmd_t hci_write_le_host_supported;
+extern const hci_cmd_t hci_write_link_policy_settings;
+extern const hci_cmd_t hci_write_link_supervision_timeout;
+extern const hci_cmd_t hci_write_local_name;
+extern const hci_cmd_t hci_write_num_broadcast_retransmissions;
+extern const hci_cmd_t hci_write_page_timeout;
+extern const hci_cmd_t hci_write_scan_enable;
+extern const hci_cmd_t hci_write_simple_pairing_mode;
+
+extern const hci_cmd_t hci_le_add_device_to_whitelist;
+extern const hci_cmd_t hci_le_clear_white_list;
+extern const hci_cmd_t hci_le_connection_update;
+extern const hci_cmd_t hci_le_create_connection;
+extern const hci_cmd_t hci_le_create_connection_cancel;
+extern const hci_cmd_t hci_le_encrypt;
+extern const hci_cmd_t hci_le_long_term_key_negative_reply;
+extern const hci_cmd_t hci_le_long_term_key_request_reply;
+extern const hci_cmd_t hci_le_rand;
+extern const hci_cmd_t hci_le_read_advertising_channel_tx_power;
+extern const hci_cmd_t hci_le_read_buffer_size ;
+extern const hci_cmd_t hci_le_read_channel_map;
+extern const hci_cmd_t hci_le_read_remote_used_features;
+extern const hci_cmd_t hci_le_read_supported_features;
+extern const hci_cmd_t hci_le_read_supported_states;
+extern const hci_cmd_t hci_le_read_white_list_size;
+extern const hci_cmd_t hci_le_receiver_test;
+extern const hci_cmd_t hci_le_remove_device_from_whitelist;
+extern const hci_cmd_t hci_le_set_advertise_enable;
+extern const hci_cmd_t hci_le_set_advertising_data;
+extern const hci_cmd_t hci_le_set_advertising_parameters;
+extern const hci_cmd_t hci_le_set_event_mask;
+extern const hci_cmd_t hci_le_set_host_channel_classification;
+extern const hci_cmd_t hci_le_set_random_address;
+extern const hci_cmd_t hci_le_set_scan_enable;
+extern const hci_cmd_t hci_le_set_scan_parameters;
+extern const hci_cmd_t hci_le_set_scan_response_data;
+extern const hci_cmd_t hci_le_start_encryption;
+extern const hci_cmd_t hci_le_test_end;
+extern const hci_cmd_t hci_le_transmitter_test;
+    
+extern const hci_cmd_t l2cap_accept_connection;
+extern const hci_cmd_t l2cap_create_channel;
+extern const hci_cmd_t l2cap_create_channel_mtu;
+extern const hci_cmd_t l2cap_decline_connection;
+extern const hci_cmd_t l2cap_disconnect;
+extern const hci_cmd_t l2cap_register_service;
+extern const hci_cmd_t l2cap_unregister_service;
+
+extern const hci_cmd_t sdp_register_service_record;
+extern const hci_cmd_t sdp_unregister_service_record;
+
+// accept connection @param bd_addr(48), rfcomm_cid (16)
+extern const hci_cmd_t rfcomm_accept_connection;
+// create rfcomm channel: @param bd_addr(48), channel (8)
+extern const hci_cmd_t rfcomm_create_channel;
+// create rfcomm channel: @param bd_addr(48), channel (8), mtu (16), credits (8)
+extern const hci_cmd_t rfcomm_create_channel_with_initial_credits;
+// decline rfcomm disconnect,@param bd_addr(48), rfcomm cid (16), reason(8)
+extern const hci_cmd_t rfcomm_decline_connection;
+// disconnect rfcomm disconnect, @param rfcomm_cid(8), reason(8)
+extern const hci_cmd_t rfcomm_disconnect;
+// register rfcomm service: @param channel(8), mtu (16)
+extern const hci_cmd_t rfcomm_register_service;
+// register rfcomm service: @param channel(8), mtu (16), initial credits (8)
+extern const hci_cmd_t rfcomm_register_service_with_initial_credits;
+// unregister rfcomm service, @param service_channel(16)
+extern const hci_cmd_t rfcomm_unregister_service;
+// request persisten rfcomm channel for service name: serive name (char*) 
+extern const hci_cmd_t rfcomm_persistent_channel_for_service;
+
+//sibu
+extern const hci_cmd_t hci_read_local_supprted_commands;
+extern const hci_cmd_t hci_read_rssi;
+
+#if defined __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/hci_dump.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  hci_dump.c
+ *
+ *  Dump HCI trace in various formats:
+ *
+ *  - BlueZ's hcidump format
+ *  - Apple's PacketLogger
+ *  - stdout hexdump
+ *
+ *  Created by Matthias Ringwald on 5/26/09.
+ */
+
+#include "config.h"
+
+#include "hci_dump.h"
+#include "hci.h"
+#include "hci_transport.h"
+#include <btstack/hci_cmds.h>
+
+#ifndef EMBEDDED
+#include <fcntl.h>        // open
+#include <arpa/inet.h>    // hton..
+#include <unistd.h>       // write 
+#include <stdio.h>
+#include <time.h>
+#include <sys/time.h>     // for timestamps
+#include <sys/stat.h>     // for mode flags
+#include <stdarg.h>       // for va_list
+#endif
+
+// BLUEZ hcidump
+typedef struct {
+    uint16_t    len;
+    uint8_t        in;
+    uint8_t        pad;
+    uint32_t    ts_sec;
+    uint32_t    ts_usec;
+    uint8_t     packet_type;
+}
+#ifdef __GNUC__
+__attribute__ ((packed))
+#endif 
+hcidump_hdr;
+
+// APPLE PacketLogger
+typedef struct {
+    uint32_t    len;
+    uint32_t    ts_sec;
+    uint32_t    ts_usec;
+    uint8_t        type;   // 0xfc for note
+}
+#ifdef __GNUC__
+__attribute__ ((packed))
+#endif
+pktlog_hdr;
+
+#ifndef EMBEDDED
+static int dump_file = -1;
+static int dump_format;
+static hcidump_hdr header_bluez;
+static pktlog_hdr  header_packetlogger;
+static char time_string[40];
+static int  max_nr_packets = -1;
+static int  nr_packets = 0;
+static char log_message_buffer[256];
+#endif
+
+void hci_dump_open(char *filename, hci_dump_format_t format){
+#ifndef EMBEDDED
+    dump_format = format;
+    if (dump_format == HCI_DUMP_STDOUT) {
+        dump_file = fileno(stdout);
+    } else {
+        dump_file = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+    }
+#endif
+}
+
+#ifndef EMBEDDED
+void hci_dump_set_max_packets(int packets){
+    max_nr_packets = packets;
+}
+#endif
+
+void hci_dump_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len) {
+#ifndef EMBEDDED
+
+    if (dump_file < 0) return; // not activated yet
+
+    // don't grow bigger than max_nr_packets
+    if (dump_format != HCI_DUMP_STDOUT && max_nr_packets > 0){
+        if (nr_packets >= max_nr_packets){
+            lseek(dump_file, 0, SEEK_SET);
+            ftruncate(dump_file, 0);
+            nr_packets = 0;
+        }
+        nr_packets++;
+    }
+    
+    // get time
+    struct timeval curr_time;
+    struct tm* ptm;
+    gettimeofday(&curr_time, NULL);
+    
+    switch (dump_format){
+        case HCI_DUMP_STDOUT: {
+            /* Obtain the time of day, and convert it to a tm struct. */
+            ptm = localtime (&curr_time.tv_sec);
+            /* Format the date and time, down to a single second. */
+            strftime (time_string, sizeof (time_string), "[%Y-%m-%d %H:%M:%S", ptm);
+            /* Compute milliseconds from microseconds. */
+            uint16_t milliseconds = curr_time.tv_usec / 1000;
+            /* Print the formatted time, in seconds, followed by a decimal point
+             and the milliseconds. */
+            printf ("%s.%03u] ", time_string, milliseconds);
+            switch (packet_type){
+                case HCI_COMMAND_DATA_PACKET:
+                    printf("CMD => ");
+                    break;
+                case HCI_EVENT_PACKET:
+                    printf("EVT <= ");
+                    break;
+                case HCI_ACL_DATA_PACKET:
+                    if (in) {
+                        printf("ACL <= ");
+                    } else {
+                        printf("ACL => ");
+                    }
+                    break;
+                case LOG_MESSAGE_PACKET:
+                    // assume buffer is big enough
+                    packet[len] = 0;
+                    printf("LOG -- %s\n", (char*) packet);
+                    return;
+                default:
+                    return;
+            }
+            hexdump(packet, len);
+            break;
+        }
+            
+        case HCI_DUMP_BLUEZ:
+            bt_store_16( (uint8_t *) &header_bluez.len, 0, 1 + len);
+            header_bluez.in  = in;
+            header_bluez.pad = 0;
+            bt_store_32( (uint8_t *) &header_bluez.ts_sec,  0, curr_time.tv_sec);
+            bt_store_32( (uint8_t *) &header_bluez.ts_usec, 0, curr_time.tv_usec);
+            header_bluez.packet_type = packet_type;
+            write (dump_file, &header_bluez, sizeof(hcidump_hdr) );
+            write (dump_file, packet, len );
+            break;
+            
+        case HCI_DUMP_PACKETLOGGER:
+            header_packetlogger.len = htonl( sizeof(pktlog_hdr) - 4 + len);
+            header_packetlogger.ts_sec =  htonl(curr_time.tv_sec);
+            header_packetlogger.ts_usec = htonl(curr_time.tv_usec);
+            switch (packet_type){
+                case HCI_COMMAND_DATA_PACKET:
+                    header_packetlogger.type = 0x00;
+                    break;
+                case HCI_ACL_DATA_PACKET:
+                    if (in) {
+                        header_packetlogger.type = 0x03;
+                    } else {
+                        header_packetlogger.type = 0x02;
+                    }
+                    break;
+                case HCI_EVENT_PACKET:
+                    header_packetlogger.type = 0x01;
+                    break;
+                case LOG_MESSAGE_PACKET:
+                    header_packetlogger.type = 0xfc;
+                    break;
+                default:
+                    return;
+            }
+            write (dump_file, &header_packetlogger, sizeof(pktlog_hdr) );
+            write (dump_file, packet, len );
+            break;
+            
+        default:
+            break;
+    }
+#endif
+}
+
+void hci_dump_log(const char * format, ...){
+#ifndef EMBEDDED
+    va_list argptr;
+    va_start(argptr, format);
+    int len = vsnprintf(log_message_buffer, sizeof(log_message_buffer), format, argptr);
+    hci_dump_packet(LOG_MESSAGE_PACKET, 0, (uint8_t*) log_message_buffer, len);
+    va_end(argptr);
+#endif    
+}
+
+void hci_dump_close(){
+#ifndef EMBEDDED
+    close(dump_file);
+    dump_file = -1;
+#endif
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/hci_dump.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  hci_dump.h
+ *
+ *  Dump HCI trace as BlueZ's hcidump format, Apple's PacketLogger, or stdout
+ * 
+ *  Created by Matthias Ringwald on 5/26/09.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+typedef enum {
+    HCI_DUMP_BLUEZ = 0,
+    HCI_DUMP_PACKETLOGGER,
+    HCI_DUMP_STDOUT
+} hci_dump_format_t;
+
+void hci_dump_open(char *filename, hci_dump_format_t format);
+void hci_dump_set_max_packets(int packets); // -1 for unlimited
+void hci_dump_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len);
+void hci_dump_log(const char * format, ...);
+void hci_dump_close(void);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/hci_transport.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  hci_transport.h
+ *
+ *  HCI Transport API -- allows BT Daemon to use different transport protcols 
+ *
+ *  Created by Matthias Ringwald on 4/29/09.
+ *
+ */
+#pragma once
+
+#include <stdint.h>
+#include <btstack/run_loop.h>
+
+#if defined __cplusplus
+extern "C" {
+#endif
+    
+/* HCI packet types */
+typedef struct {
+    int    (*open)(void *transport_config);
+    int    (*close)(void *transport_config);
+    int    (*send_packet)(uint8_t packet_type, uint8_t *packet, int size);
+    void   (*register_packet_handler)(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size));
+    const char * (*get_transport_name)(void);
+    // custom extension for UART transport implementations
+    int    (*set_baudrate)(uint32_t baudrate);
+    // support async transport layers, e.g. IRQ driven without buffers
+    int    (*can_send_packet_now)(uint8_t packet_type);
+} hci_transport_t;
+
+typedef struct {
+    const char *device_name;
+    uint32_t   baudrate_init; // initial baud rate
+    uint32_t   baudrate_main; // = 0: same as initial baudrate
+    int   flowcontrol; // 
+} hci_uart_config_t;
+
+
+// inline various hci_transport_X.h files
+extern hci_transport_t * hci_transport_h4_instance(void);
+extern hci_transport_t * hci_transport_h4_dma_instance(void);
+extern hci_transport_t * hci_transport_h4_iphone_instance(void);
+extern hci_transport_t * hci_transport_h5_instance(void);
+extern hci_transport_t * hci_transport_usb_instance(void);
+
+// support for "enforece wake device" in h4 - used by iOS power management
+extern void hci_transport_h4_iphone_set_enforce_wake_device(char *path);
+    
+#if defined __cplusplus
+}
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/hci_transport_usb.cpp	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  hci_transport_usb.cpp
+ *
+ *  HCI Transport API implementation for USB
+ *
+ *  Created by Matthias Ringwald on 7/5/09.
+ */
+
+// delock bt class 2 - csr
+// 0a12:0001 (bus 27, device 2)
+
+// Interface Number - Alternate Setting - suggested Endpoint Address - Endpoint Type - Suggested Max Packet Size 
+// HCI Commands 0 0 0x00 Control 8/16/32/64 
+// HCI Events   0 0 0x81 Interrupt (IN) 16 
+// ACL Data     0 0 0x82 Bulk (IN) 32/64 
+// ACL Data     0 0 0x02 Bulk (OUT) 32/64 
+
+#include <stdio.h>
+#include <string.h>
+#include "config.h"
+#include "debug.h"
+#include "hci.h"
+#include "hci_transport.h"
+#include "hci_dump.h"
+#include "USBHostBTstack.h"
+
+enum {
+    LIB_USB_CLOSED = 0,
+    LIB_USB_OPENED,
+    LIB_USB_DEVICE_OPENDED,
+    LIB_USB_KERNEL_DETACHED,
+    LIB_USB_INTERFACE_CLAIMED,
+    LIB_USB_TRANSFERS_ALLOCATED
+} libusb_state = LIB_USB_CLOSED;
+
+// single instance
+static hci_transport_t * hci_transport_usb = NULL;
+static USBHostBTstack* bt = NULL;
+
+static int usb_process_ds(struct data_source *ds) {
+    if (bt) {
+        bt->poll();
+    }
+    return 0;
+}
+
+static int usb_open(void *transport_config){
+    log_info("usb_open\n");
+    data_source_t *ds = (data_source_t*)malloc(sizeof(data_source_t));
+    ds->process = usb_process_ds;
+    run_loop_add_data_source(ds);
+    if (bt) {
+        return bt->open();
+    }
+    return 0;
+}
+static int usb_close(void *transport_config){
+
+    return 0;
+}
+
+static int usb_send_packet(uint8_t packet_type, uint8_t * packet, int size){
+    //log_info("usb_send_packet\n");
+    if (bt) {
+        bt->send_packet(packet_type, packet, size);
+    }
+    return 0;
+}
+
+static void usb_register_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size)){
+    log_info("registering packet handler\n");
+    if (bt) {
+        bt->register_packet_handler(handler);
+    }
+}
+
+static const char * usb_get_transport_name(void){
+    return "USB";
+}
+
+// get usb singleton
+hci_transport_t * hci_transport_usb_instance() {
+    if (!bt) {
+        bt = new USBHostBTstack;
+    }
+    if (!hci_transport_usb) {
+        hci_transport_usb = (hci_transport_t*)malloc( sizeof(hci_transport_t));
+        hci_transport_usb->open                          = usb_open;
+        hci_transport_usb->close                         = usb_close;
+        hci_transport_usb->send_packet                   = usb_send_packet;
+        hci_transport_usb->register_packet_handler       = usb_register_packet_handler;
+        hci_transport_usb->get_transport_name            = usb_get_transport_name;
+        hci_transport_usb->set_baudrate                  = NULL;
+        hci_transport_usb->can_send_packet_now           = NULL;
+    }
+    return hci_transport_usb;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/l2cap.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,1138 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  l2cap.c
+ *
+ *  Logical Link Control and Adaption Protocl (L2CAP)
+ *
+ *  Created by Matthias Ringwald on 5/16/09.
+ */
+
+#include "l2cap.h"
+#include "hci.h"
+#include "hci_dump.h"
+#include "debug.h"
+#include "btstack_memory.h"
+
+#include <stdarg.h>
+#include <string.h>
+
+#include <stdio.h>
+
+// nr of buffered acl packets in outgoing queue to get max performance 
+#define NR_BUFFERED_ACL_PACKETS 3
+
+// used to cache l2cap rejects, echo, and informational requests
+#define NR_PENDING_SIGNALING_RESPONSES 3
+
+// offsets for L2CAP SIGNALING COMMANDS
+#define L2CAP_SIGNALING_COMMAND_CODE_OFFSET   0
+#define L2CAP_SIGNALING_COMMAND_SIGID_OFFSET  1
+#define L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET 2
+#define L2CAP_SIGNALING_COMMAND_DATA_OFFSET   4
+
+static void null_packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
+static void l2cap_packet_handler(uint8_t packet_type, uint8_t *packet, uint16_t size);
+
+// used to cache l2cap rejects, echo, and informational requests
+static l2cap_signaling_response_t signaling_responses[NR_PENDING_SIGNALING_RESPONSES];
+static int signaling_responses_pending;
+
+static linked_list_t l2cap_channels = NULL;
+static linked_list_t l2cap_services = NULL;
+static void (*packet_handler) (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) = null_packet_handler;
+static int new_credits_blocked = 0;
+
+static btstack_packet_handler_t attribute_protocol_packet_handler = NULL;
+static btstack_packet_handler_t security_protocol_packet_handler = NULL;
+
+// prototypes
+static void l2cap_finialize_channel_close(l2cap_channel_t *channel);
+static l2cap_service_t * l2cap_get_service(uint16_t psm);
+static void l2cap_emit_channel_opened(l2cap_channel_t *channel, uint8_t status);
+static void l2cap_emit_channel_closed(l2cap_channel_t *channel);
+static void l2cap_emit_connection_request(l2cap_channel_t *channel);
+static int l2cap_channel_ready_for_open(l2cap_channel_t *channel);
+
+
+void l2cap_init(){
+    new_credits_blocked = 0;
+    signaling_responses_pending = 0;
+    
+    l2cap_channels = NULL;
+    l2cap_services = NULL;
+
+    packet_handler = null_packet_handler;
+    
+    // 
+    // register callback with HCI
+    //
+    hci_register_packet_handler(&l2cap_packet_handler);
+    hci_connectable_control(0); // no services yet
+}
+
+
+/** Register L2CAP packet handlers */
+static void null_packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
+}
+void l2cap_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)){
+    packet_handler = handler;
+}
+
+//  notify client/protocol handler
+void l2cap_dispatch(l2cap_channel_t *channel, uint8_t type, uint8_t * data, uint16_t size){
+    if (channel->packet_handler) {
+        (* (channel->packet_handler))(type, channel->local_cid, data, size);
+    } else {
+        (*packet_handler)(channel->connection, type, channel->local_cid, data, size);
+    }
+}
+
+void l2cap_emit_channel_opened(l2cap_channel_t *channel, uint8_t status) {
+    uint8_t event[21];
+    event[0] = L2CAP_EVENT_CHANNEL_OPENED;
+    event[1] = sizeof(event) - 2;
+    event[2] = status;
+    bt_flip_addr(&event[3], channel->address);
+    bt_store_16(event,  9, channel->handle);
+    bt_store_16(event, 11, channel->psm);
+    bt_store_16(event, 13, channel->local_cid);
+    bt_store_16(event, 15, channel->remote_cid);
+    bt_store_16(event, 17, channel->local_mtu);
+    bt_store_16(event, 19, channel->remote_mtu); 
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    l2cap_dispatch(channel, HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void l2cap_emit_channel_closed(l2cap_channel_t *channel) {
+    uint8_t event[4];
+    event[0] = L2CAP_EVENT_CHANNEL_CLOSED;
+    event[1] = sizeof(event) - 2;
+    bt_store_16(event, 2, channel->local_cid);
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    l2cap_dispatch(channel, HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void l2cap_emit_connection_request(l2cap_channel_t *channel) {
+    uint8_t event[16];
+    event[0] = L2CAP_EVENT_INCOMING_CONNECTION;
+    event[1] = sizeof(event) - 2;
+    bt_flip_addr(&event[2], channel->address);
+    bt_store_16(event,  8, channel->handle);
+    bt_store_16(event, 10, channel->psm);
+    bt_store_16(event, 12, channel->local_cid);
+    bt_store_16(event, 14, channel->remote_cid);
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    l2cap_dispatch(channel, HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+static void l2cap_emit_service_registered(void *connection, uint8_t status, uint16_t psm){
+    uint8_t event[5];
+    event[0] = L2CAP_EVENT_SERVICE_REGISTERED;
+    event[1] = sizeof(event) - 2;
+    event[2] = status;
+    bt_store_16(event, 3, psm);
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    (*packet_handler)(connection, HCI_EVENT_PACKET, 0, event, sizeof(event));
+}
+
+void l2cap_emit_credits(l2cap_channel_t *channel, uint8_t credits) {
+    // track credits
+    channel->packets_granted += credits;
+    // log_info("l2cap_emit_credits for cid %u, credits given: %u (+%u)\n", channel->local_cid, channel->packets_granted, credits);
+    
+    uint8_t event[5];
+    event[0] = L2CAP_EVENT_CREDITS;
+    event[1] = sizeof(event) - 2;
+    bt_store_16(event, 2, channel->local_cid);
+    event[4] = credits;
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    l2cap_dispatch(channel, HCI_EVENT_PACKET, event, sizeof(event));
+}
+
+void l2cap_block_new_credits(uint8_t blocked){
+    new_credits_blocked = blocked;
+}
+
+void l2cap_hand_out_credits(void){
+
+    if (new_credits_blocked) return;    // we're told not to. used by daemon
+    
+    linked_item_t *it;
+    for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
+        if (!hci_number_free_acl_slots()) return;
+        l2cap_channel_t * channel = (l2cap_channel_t *) it;
+        if (channel->state != L2CAP_STATE_OPEN) continue;
+        if (hci_number_outgoing_packets(channel->handle) < NR_BUFFERED_ACL_PACKETS && channel->packets_granted == 0) {
+            l2cap_emit_credits(channel, 1);
+        }
+    }
+}
+
+l2cap_channel_t * l2cap_get_channel_for_local_cid(uint16_t local_cid){
+    linked_item_t *it;
+    for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
+        l2cap_channel_t * channel = (l2cap_channel_t *) it;
+        if ( channel->local_cid == local_cid) {
+            return channel;
+        }
+    }
+    return NULL;
+}
+
+int  l2cap_can_send_packet_now(uint16_t local_cid){
+    l2cap_channel_t *channel = l2cap_get_channel_for_local_cid(local_cid);
+    if (!channel) return 0;
+    if (!channel->packets_granted) return 0;
+    return hci_can_send_packet_now(HCI_ACL_DATA_PACKET);
+}
+
+uint16_t l2cap_get_remote_mtu_for_local_cid(uint16_t local_cid){
+    l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
+    if (channel) {
+        return channel->remote_mtu;
+    } 
+    return 0;
+}
+
+int l2cap_send_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, ...){
+
+    if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)){
+        log_info("l2cap_send_signaling_packet, cannot send\n");
+        return BTSTACK_ACL_BUFFERS_FULL;
+    }
+    
+    // log_info("l2cap_send_signaling_packet type %u\n", cmd);
+    uint8_t *acl_buffer = hci_get_outgoing_acl_packet_buffer();
+    va_list argptr;
+    va_start(argptr, identifier);
+    uint16_t len = l2cap_create_signaling_internal(acl_buffer, handle, cmd, identifier, argptr);
+    va_end(argptr);
+    // log_info("l2cap_send_signaling_packet con %u!\n", handle);
+    return hci_send_acl_packet(acl_buffer, len);
+}
+
+uint8_t *l2cap_get_outgoing_buffer(void){
+    return hci_get_outgoing_acl_packet_buffer() + COMPLETE_L2CAP_HEADER; // 8 bytes
+}
+
+int l2cap_send_prepared(uint16_t local_cid, uint16_t len){
+    
+    if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)){
+        log_info("l2cap_send_internal cid %u, cannot send\n", local_cid);
+        return BTSTACK_ACL_BUFFERS_FULL;
+    }
+    
+    l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
+    if (!channel) {
+        log_error("l2cap_send_internal no channel for cid %u\n", local_cid);
+        return -1;   // TODO: define error
+    }
+
+    if (channel->packets_granted == 0){
+        log_error("l2cap_send_internal cid %u, no credits!\n", local_cid);
+        return -1;  // TODO: define error
+    }
+    
+    --channel->packets_granted;
+
+    log_debug("l2cap_send_internal cid %u, handle %u, 1 credit used, credits left %u;\n",
+                  local_cid, channel->handle, channel->packets_granted);
+    
+    uint8_t *acl_buffer = hci_get_outgoing_acl_packet_buffer();
+
+    // 0 - Connection handle : PB=10 : BC=00 
+    bt_store_16(acl_buffer, 0, channel->handle | (2 << 12) | (0 << 14));
+    // 2 - ACL length
+    bt_store_16(acl_buffer, 2,  len + 4);
+    // 4 - L2CAP packet length
+    bt_store_16(acl_buffer, 4,  len + 0);
+    // 6 - L2CAP channel DEST
+    bt_store_16(acl_buffer, 6, channel->remote_cid);    
+    // send
+    int err = hci_send_acl_packet(acl_buffer, len+8);
+    
+    l2cap_hand_out_credits();
+    
+    return err;
+}
+
+int l2cap_send_prepared_connectionless(uint16_t handle, uint16_t cid, uint16_t len){
+    
+    if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)){
+        log_info("l2cap_send_prepared_to_handle cid %u, cannot send\n", cid);
+        return BTSTACK_ACL_BUFFERS_FULL;
+    }
+    
+    log_debug("l2cap_send_prepared_to_handle cid %u, handle %u\n", cid, handle);
+    
+    uint8_t *acl_buffer = hci_get_outgoing_acl_packet_buffer();
+    
+    // 0 - Connection handle : PB=10 : BC=00 
+    bt_store_16(acl_buffer, 0, handle | (2 << 12) | (0 << 14));
+    // 2 - ACL length
+    bt_store_16(acl_buffer, 2,  len + 4);
+    // 4 - L2CAP packet length
+    bt_store_16(acl_buffer, 4,  len + 0);
+    // 6 - L2CAP channel DEST
+    bt_store_16(acl_buffer, 6, cid);    
+    // send
+    int err = hci_send_acl_packet(acl_buffer, len+8);
+    
+    l2cap_hand_out_credits();
+
+    return err;
+}
+
+int l2cap_send_internal(uint16_t local_cid, uint8_t *data, uint16_t len){
+
+    if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)){
+        log_info("l2cap_send_internal cid %u, cannot send\n", local_cid);
+        return BTSTACK_ACL_BUFFERS_FULL;
+    }
+
+    uint8_t *acl_buffer = hci_get_outgoing_acl_packet_buffer();
+
+    memcpy(&acl_buffer[8], data, len);
+
+    return l2cap_send_prepared(local_cid, len);
+}
+
+int l2cap_send_connectionless(uint16_t handle, uint16_t cid, uint8_t *data, uint16_t len){
+    
+    if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)){
+        log_info("l2cap_send_internal cid %u, cannot send\n", cid);
+        return BTSTACK_ACL_BUFFERS_FULL;
+    }
+    
+    uint8_t *acl_buffer = hci_get_outgoing_acl_packet_buffer();
+    
+    memcpy(&acl_buffer[8], data, len);
+    
+    return l2cap_send_prepared_connectionless(handle, cid, len);
+}
+
+static inline void channelStateVarSetFlag(l2cap_channel_t *channel, L2CAP_CHANNEL_STATE_VAR flag){
+    channel->state_var = (L2CAP_CHANNEL_STATE_VAR) (channel->state_var | flag);
+}
+
+static inline void channelStateVarClearFlag(l2cap_channel_t *channel, L2CAP_CHANNEL_STATE_VAR flag){
+    channel->state_var = (L2CAP_CHANNEL_STATE_VAR) (channel->state_var & ~flag);
+}
+
+
+
+// MARK: L2CAP_RUN
+// process outstanding signaling tasks
+void l2cap_run(void){
+    
+    // check pending signaling responses
+    while (signaling_responses_pending){
+        
+        if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)) break;
+        
+        hci_con_handle_t handle = signaling_responses[0].handle;
+        uint8_t sig_id = signaling_responses[0].sig_id;
+        uint16_t infoType = signaling_responses[0].data;    // INFORMATION_REQUEST
+        uint16_t result   = signaling_responses[0].data;    // CONNECTION_REQUEST
+        
+        switch (signaling_responses[0].code){
+            case CONNECTION_REQUEST:
+                l2cap_send_signaling_packet(handle, CONNECTION_RESPONSE, sig_id, 0, 0, result, 0);
+                break;
+            case ECHO_REQUEST:
+                l2cap_send_signaling_packet(handle, ECHO_RESPONSE, sig_id, 0, NULL);
+                break;
+            case INFORMATION_REQUEST:
+                if (infoType == 2) {
+                    uint32_t features = 0;
+                    // extended features request supported, however no features present
+                    l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, infoType, 0, 4, &features);
+                } else {
+                    // all other types are not supported
+                    l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, infoType, 1, 0, NULL);
+                }
+                break;
+            default:
+                // should not happen
+                break;
+        }
+        
+        // remove first item
+        signaling_responses_pending--;
+        int i;
+        for (i=0; i < signaling_responses_pending; i++){
+            memcpy(&signaling_responses[i], &signaling_responses[i+1], sizeof(l2cap_signaling_response_t));
+        }
+    }
+    
+    uint8_t  config_options[4];
+    linked_item_t *it;
+    linked_item_t *next;
+    for (it = (linked_item_t *) l2cap_channels; it ; it = next){
+        next = it->next;    // cache next item as current item might get freed
+
+        if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) break;
+        if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)) break;
+        
+        l2cap_channel_t * channel = (l2cap_channel_t *) it;
+        
+        // log_info("l2cap_run: state %u, var 0x%02x\n", channel->state, channel->state_var);
+        
+        
+        switch (channel->state){
+
+            case L2CAP_STATE_WILL_SEND_CREATE_CONNECTION:
+                // send connection request - set state first
+                channel->state = L2CAP_STATE_WAIT_CONNECTION_COMPLETE;
+                // BD_ADDR, Packet_Type, Page_Scan_Repetition_Mode, Reserved, Clock_Offset, Allow_Role_Switch
+                hci_send_cmd(&hci_create_connection, channel->address, hci_usable_acl_packet_types(), 0, 0, 0, 1); 
+                break;
+                
+            case L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE:
+                l2cap_send_signaling_packet(channel->handle, CONNECTION_RESPONSE, channel->remote_sig_id, 0, 0, channel->reason, 0);
+                // discard channel - l2cap_finialize_channel_close without sending l2cap close event
+                linked_list_remove(&l2cap_channels, (linked_item_t *) channel); // -- remove from list
+                btstack_memory_l2cap_channel_free(channel); 
+                break;
+                
+            case L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_ACCEPT:
+                channel->state = L2CAP_STATE_CONFIG;
+                channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ);
+                l2cap_send_signaling_packet(channel->handle, CONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid, 0, 0);
+                break;
+                
+            case L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST:
+                // success, start l2cap handshake
+                channel->local_sig_id = l2cap_next_sig_id();
+                channel->state = L2CAP_STATE_WAIT_CONNECT_RSP;
+                l2cap_send_signaling_packet( channel->handle, CONNECTION_REQUEST, channel->local_sig_id, channel->psm, channel->local_cid);                   
+                break;
+            
+            case L2CAP_STATE_CONFIG:
+                if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP){
+                    channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP);
+                    channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP);
+                    l2cap_send_signaling_packet(channel->handle, CONFIGURE_RESPONSE, channel->remote_sig_id, channel->remote_cid, 0, 0, 0, NULL);
+                }
+                else if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ){
+                    channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ);
+                    channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_REQ);
+                    channel->local_sig_id = l2cap_next_sig_id();
+                    config_options[0] = 1; // MTU
+                    config_options[1] = 2; // len param
+                    bt_store_16( (uint8_t*)&config_options, 2, channel->local_mtu);
+                    l2cap_send_signaling_packet(channel->handle, CONFIGURE_REQUEST, channel->local_sig_id, channel->remote_cid, 0, 4, &config_options);
+                }
+                if (l2cap_channel_ready_for_open(channel)){
+                    channel->state = L2CAP_STATE_OPEN;
+                    l2cap_emit_channel_opened(channel, 0);  // success
+                    l2cap_emit_credits(channel, 1);
+                }
+                break;
+
+            case L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE:
+                l2cap_send_signaling_packet( channel->handle, DISCONNECTION_RESPONSE, channel->remote_sig_id, channel->local_cid, channel->remote_cid);   
+                l2cap_finialize_channel_close(channel);  // -- remove from list
+                break;
+                
+            case L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST:
+                channel->local_sig_id = l2cap_next_sig_id();
+                channel->state = L2CAP_STATE_WAIT_DISCONNECT;
+                l2cap_send_signaling_packet( channel->handle, DISCONNECTION_REQUEST, channel->local_sig_id, channel->remote_cid, channel->local_cid);   
+                break;
+            default:
+                break;
+        }
+    }
+}
+
+uint16_t l2cap_max_mtu(void){
+    return hci_max_acl_data_packet_length() - L2CAP_HEADER_SIZE;
+}
+
+// open outgoing L2CAP channel
+void l2cap_create_channel_internal(void * connection, btstack_packet_handler_t packet_handler,
+                                   bd_addr_t address, uint16_t psm, uint16_t mtu){
+    
+    // alloc structure
+    l2cap_channel_t * chan = (l2cap_channel_t*) btstack_memory_l2cap_channel_get();
+    if (!chan) {
+        // emit error event
+        l2cap_channel_t dummy_channel;
+        BD_ADDR_COPY(dummy_channel.address, address);
+        dummy_channel.psm = psm;
+        l2cap_emit_channel_opened(&dummy_channel, BTSTACK_MEMORY_ALLOC_FAILED);
+        return;
+    }
+    // limit local mtu to max acl packet length
+    if (mtu > l2cap_max_mtu()) {
+        mtu = l2cap_max_mtu();
+    }
+        
+    // fill in 
+    BD_ADDR_COPY(chan->address, address);
+    chan->psm = psm;
+    chan->handle = 0;
+    chan->connection = connection;
+    chan->packet_handler = packet_handler;
+    chan->remote_mtu = L2CAP_MINIMAL_MTU;
+    chan->local_mtu = mtu;
+    chan->packets_granted = 0;
+    
+    // set initial state
+    chan->state = L2CAP_STATE_WILL_SEND_CREATE_CONNECTION;
+    chan->state_var = L2CAP_CHANNEL_STATE_VAR_NONE;
+    chan->remote_sig_id = L2CAP_SIG_ID_INVALID;
+    chan->local_sig_id = L2CAP_SIG_ID_INVALID;
+    
+    // add to connections list
+    linked_list_add(&l2cap_channels, (linked_item_t *) chan);
+    
+    l2cap_run();
+}
+
+void l2cap_disconnect_internal(uint16_t local_cid, uint8_t reason){
+    // find channel for local_cid
+    l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
+    if (channel) {
+        channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
+    }
+    // process
+    l2cap_run();
+}
+
+static void l2cap_handle_connection_failed_for_addr(bd_addr_t address, uint8_t status){
+    linked_item_t *it = (linked_item_t *) &l2cap_channels;
+    while (it->next){
+        l2cap_channel_t * channel = (l2cap_channel_t *) it->next;
+        if ( ! BD_ADDR_CMP( channel->address, address) ){
+            if (channel->state == L2CAP_STATE_WAIT_CONNECTION_COMPLETE || channel->state == L2CAP_STATE_WILL_SEND_CREATE_CONNECTION) {
+                // failure, forward error code
+                l2cap_emit_channel_opened(channel, status);
+                // discard channel
+                it->next = it->next->next;
+                btstack_memory_l2cap_channel_free(channel);
+            }
+        } else {
+            it = it->next;
+        }
+    }
+}
+
+static void l2cap_handle_connection_success_for_addr(bd_addr_t address, hci_con_handle_t handle){
+    linked_item_t *it;
+    for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
+        l2cap_channel_t * channel = (l2cap_channel_t *) it;
+        if ( ! BD_ADDR_CMP( channel->address, address) ){
+            if (channel->state == L2CAP_STATE_WAIT_CONNECTION_COMPLETE || channel->state == L2CAP_STATE_WILL_SEND_CREATE_CONNECTION) {
+                // success, start l2cap handshake
+                channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST;
+                channel->handle = handle;
+                channel->local_cid = l2cap_next_local_cid();
+            }
+        }
+    }
+    // process
+    l2cap_run();
+}
+
+void l2cap_event_handler( uint8_t *packet, uint16_t size ){
+    
+    bd_addr_t address;
+    hci_con_handle_t handle;
+    l2cap_channel_t * channel;
+    linked_item_t *it;
+    int hci_con_used;
+    
+    switch(packet[0]){
+            
+        // handle connection complete events
+        case HCI_EVENT_CONNECTION_COMPLETE:
+            bt_flip_addr(address, &packet[5]);
+            if (packet[2] == 0){
+                handle = READ_BT_16(packet, 3);
+                l2cap_handle_connection_success_for_addr(address, handle);
+            } else {
+                l2cap_handle_connection_failed_for_addr(address, packet[2]);
+            }
+            break;
+            
+        // handle successful create connection cancel command
+        case HCI_EVENT_COMMAND_COMPLETE:
+            if ( COMMAND_COMPLETE_EVENT(packet, hci_create_connection_cancel) ) {
+                if (packet[5] == 0){
+                    bt_flip_addr(address, &packet[6]);
+                    // CONNECTION TERMINATED BY LOCAL HOST (0X16)
+                    l2cap_handle_connection_failed_for_addr(address, 0x16);
+                }
+            }
+            l2cap_run();    // try sending signaling packets first
+            break;
+            
+        case HCI_EVENT_COMMAND_STATUS:
+            l2cap_run();    // try sending signaling packets first
+            break;
+            
+        // handle disconnection complete events
+        case HCI_EVENT_DISCONNECTION_COMPLETE:
+            // send l2cap disconnect events for all channels on this handle
+            handle = READ_BT_16(packet, 3);
+            it = (linked_item_t *) &l2cap_channels;
+            while (it->next){
+                l2cap_channel_t * channel = (l2cap_channel_t *) it->next;
+                if ( channel->handle == handle ){
+                    // update prev item before free'ing next element - don't call l2cap_finalize_channel_close
+                    it->next = it->next->next;
+                    l2cap_emit_channel_closed(channel);
+                    btstack_memory_l2cap_channel_free(channel);
+                } else {
+                    it = it->next;
+                }
+            }
+            break;
+            
+        case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS:
+            l2cap_run();    // try sending signaling packets first
+            l2cap_hand_out_credits();
+            break;
+            
+        // HCI Connection Timeouts
+        case L2CAP_EVENT_TIMEOUT_CHECK:
+            handle = READ_BT_16(packet, 2);
+            if (hci_authentication_active_for_handle(handle)) break;
+            hci_con_used = 0;
+            for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
+                channel = (l2cap_channel_t *) it;
+                if (channel->handle == handle) {
+                    hci_con_used = 1;
+                }
+            }
+            if (hci_con_used) break;
+            if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) break;
+            hci_send_cmd(&hci_disconnect, handle, 0x13); // remote closed connection             
+            break;
+
+        case DAEMON_EVENT_HCI_PACKET_SENT:
+            for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
+                channel = (l2cap_channel_t *) it;
+                if (channel->packet_handler) {
+                    (* (channel->packet_handler))(HCI_EVENT_PACKET, channel->local_cid, packet, size);
+                } 
+            }
+            if (attribute_protocol_packet_handler) {
+                (*attribute_protocol_packet_handler)(HCI_EVENT_PACKET, 0, packet, size);
+            }
+            if (security_protocol_packet_handler) {
+                (*security_protocol_packet_handler)(HCI_EVENT_PACKET, 0, packet, size);
+            }
+            break;
+            
+        default:
+            break;
+    }
+    
+    // pass on
+    (*packet_handler)(NULL, HCI_EVENT_PACKET, 0, packet, size);
+}
+
+static void l2cap_handle_disconnect_request(l2cap_channel_t *channel, uint16_t identifier){
+    channel->remote_sig_id = identifier;
+    channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE;
+    l2cap_run();
+}
+
+static void l2cap_register_signaling_response(hci_con_handle_t handle, uint8_t code, uint8_t sig_id, uint16_t data){
+    // Vol 3, Part A, 4.3: "The DCID and SCID fields shall be ignored when the result field indi- cates the connection was refused."
+    if (signaling_responses_pending < NR_PENDING_SIGNALING_RESPONSES) {
+        signaling_responses[signaling_responses_pending].handle = handle;
+        signaling_responses[signaling_responses_pending].code = code;
+        signaling_responses[signaling_responses_pending].sig_id = sig_id;
+        signaling_responses[signaling_responses_pending].data = data;
+        signaling_responses_pending++;
+        l2cap_run();
+    }
+}
+
+static void l2cap_handle_connection_request(hci_con_handle_t handle, uint8_t sig_id, uint16_t psm, uint16_t source_cid){
+    
+    // log_info("l2cap_handle_connection_request for handle %u, psm %u cid %u\n", handle, psm, source_cid);
+    l2cap_service_t *service = l2cap_get_service(psm);
+    if (!service) {
+        // 0x0002 PSM not supported
+        l2cap_register_signaling_response(handle, CONNECTION_REQUEST, sig_id, 0x0002);
+        return;
+    }
+    
+    hci_connection_t * hci_connection = connection_for_handle( handle );
+    if (!hci_connection) {
+        // 
+        log_error("no hci_connection for handle %u\n", handle);
+        return;
+    }
+    // alloc structure
+    // log_info("l2cap_handle_connection_request register channel\n");
+    l2cap_channel_t * channel = (l2cap_channel_t*) btstack_memory_l2cap_channel_get();
+    if (!channel){
+        // 0x0004 No resources available
+        l2cap_register_signaling_response(handle, CONNECTION_REQUEST, sig_id, 0x0004);
+        return;
+    }
+    
+    // fill in 
+    BD_ADDR_COPY(channel->address, hci_connection->address);
+    channel->psm = psm;
+    channel->handle = handle;
+    channel->connection = service->connection;
+    channel->packet_handler = service->packet_handler;
+    channel->local_cid  = l2cap_next_local_cid();
+    channel->remote_cid = source_cid;
+    channel->local_mtu  = service->mtu;
+    channel->remote_mtu = L2CAP_DEFAULT_MTU;
+    channel->packets_granted = 0;
+    channel->remote_sig_id = sig_id; 
+
+    // limit local mtu to max acl packet length
+    if (channel->local_mtu > l2cap_max_mtu()) {
+        channel->local_mtu = l2cap_max_mtu();
+    }
+    
+    // set initial state
+    channel->state = L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT;
+    channel->state_var = L2CAP_CHANNEL_STATE_VAR_NONE;
+    
+    // add to connections list
+    linked_list_add(&l2cap_channels, (linked_item_t *) channel);
+    
+    // emit incoming connection request
+    l2cap_emit_connection_request(channel);
+}
+
+void l2cap_accept_connection_internal(uint16_t local_cid){
+    l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid);
+    if (!channel) {
+        log_error("l2cap_accept_connection_internal called but local_cid 0x%x not found", local_cid);
+        return;
+    }
+
+    channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_ACCEPT;
+
+    // process
+    l2cap_run();
+}
+
+void l2cap_decline_connection_internal(uint16_t local_cid, uint8_t reason){
+    l2cap_channel_t * channel = l2cap_get_channel_for_local_cid( local_cid);
+    if (!channel) {
+        log_error( "l2cap_decline_connection_internal called but local_cid 0x%x not found", local_cid);
+        return;
+    }
+    channel->state  = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE;
+    channel->reason = reason;
+    l2cap_run();
+}
+
+void l2cap_signaling_handle_configure_request(l2cap_channel_t *channel, uint8_t *command){
+
+    channel->remote_sig_id = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET];
+
+    // accept the other's configuration options
+    uint16_t end_pos = 4 + READ_BT_16(command, L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET);
+    uint16_t pos     = 8;
+    while (pos < end_pos){
+        uint8_t type   = command[pos++];
+        uint8_t length = command[pos++];
+        // MTU { type(8): 1, len(8):2, MTU(16) }
+        if ((type & 0x7f) == 1 && length == 2){
+            channel->remote_mtu = READ_BT_16(command, pos);
+            // log_info("l2cap cid %u, remote mtu %u\n", channel->local_cid, channel->remote_mtu);
+        }
+        pos += length;
+    }
+}
+
+static int l2cap_channel_ready_for_open(l2cap_channel_t *channel){
+    // log_info("l2cap_channel_ready_for_open 0x%02x\n", channel->state_var);
+    if ((channel->state_var & L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP) == 0) return 0;
+    if ((channel->state_var & L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP) == 0) return 0;
+    return 1;
+}
+
+
+void l2cap_signaling_handler_channel(l2cap_channel_t *channel, uint8_t *command){
+
+    uint8_t  code       = command[L2CAP_SIGNALING_COMMAND_CODE_OFFSET];
+    uint8_t  identifier = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET];
+    uint16_t result = 0;
+    
+    log_info("L2CAP signaling handler code %u, state %u\n", code, channel->state);
+    
+    // handle DISCONNECT REQUESTS seperately
+    if (code == DISCONNECTION_REQUEST){
+        switch (channel->state){
+            case L2CAP_STATE_CONFIG:
+            case L2CAP_STATE_OPEN:
+            case L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST:
+            case L2CAP_STATE_WAIT_DISCONNECT:
+                l2cap_handle_disconnect_request(channel, identifier);
+                break;
+
+            default:
+                // ignore in other states
+                break;
+        }
+        return;
+    }
+    
+    // @STATEMACHINE(l2cap)
+    switch (channel->state) {
+            
+        case L2CAP_STATE_WAIT_CONNECT_RSP:
+            switch (code){
+                case CONNECTION_RESPONSE:
+                    result = READ_BT_16 (command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+4);
+                    switch (result) {
+                        case 0:
+                            // successful connection
+                            channel->remote_cid = READ_BT_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
+                            channel->state = L2CAP_STATE_CONFIG;
+                            channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ);
+                            break;
+                        case 1:
+                            // connection pending. get some coffee
+                            break;
+                        default:
+                            // channel closed
+                            channel->state = L2CAP_STATE_CLOSED;
+
+                            // map l2cap connection response result to BTstack status enumeration
+                            l2cap_emit_channel_opened(channel, L2CAP_CONNECTION_RESPONSE_RESULT_SUCCESSFUL + result);
+                            
+                            // drop link key if security block
+                            if (L2CAP_CONNECTION_RESPONSE_RESULT_SUCCESSFUL + result == L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_SECURITY){
+                                hci_drop_link_key_for_bd_addr(&channel->address);
+                            }
+                            
+                            // discard channel
+                            linked_list_remove(&l2cap_channels, (linked_item_t *) channel);
+                            btstack_memory_l2cap_channel_free(channel);
+                            break;
+                    }
+                    break;
+                    
+                default:
+                    //@TODO: implement other signaling packets
+                    break;
+            }
+            break;
+
+        case L2CAP_STATE_CONFIG:
+            switch (code) {
+                case CONFIGURE_REQUEST:
+                    channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_REQ);
+                    channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP);
+                    l2cap_signaling_handle_configure_request(channel, command);
+                    break;
+                case CONFIGURE_RESPONSE:
+                    channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP);
+                    break;
+                default:
+                    break;
+            }
+            if (l2cap_channel_ready_for_open(channel)){
+                // for open:
+                channel->state = L2CAP_STATE_OPEN;
+                l2cap_emit_channel_opened(channel, 0);
+                l2cap_emit_credits(channel, 1);
+            }
+            break;
+            
+        case L2CAP_STATE_WAIT_DISCONNECT:
+            switch (code) {
+                case DISCONNECTION_RESPONSE:
+                    l2cap_finialize_channel_close(channel);
+                    break;
+                default:
+                    //@TODO: implement other signaling packets
+                    break;
+            }
+            break;
+            
+        case L2CAP_STATE_CLOSED:
+            // @TODO handle incoming requests
+            break;
+            
+        case L2CAP_STATE_OPEN:
+            //@TODO: implement other signaling packets, e.g. re-configure
+            break;
+        default:
+            break;
+    }
+    // log_info("new state %u\n", channel->state);
+}
+
+
+void l2cap_signaling_handler_dispatch( hci_con_handle_t handle, uint8_t * command){
+    
+    // get code, signalind identifier and command len
+    uint8_t code   = command[L2CAP_SIGNALING_COMMAND_CODE_OFFSET];
+    uint8_t sig_id = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET];
+    
+    // not for a particular channel, and not CONNECTION_REQUEST, ECHO_[REQUEST|RESPONSE], INFORMATION_REQUEST 
+    if (code < 1 || code == ECHO_RESPONSE || code > INFORMATION_REQUEST){
+        return;
+    }
+
+    // general commands without an assigned channel
+    switch(code) {
+            
+        case CONNECTION_REQUEST: {
+            uint16_t psm =        READ_BT_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
+            uint16_t source_cid = READ_BT_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+2);
+            l2cap_handle_connection_request(handle, sig_id, psm, source_cid);
+            return;
+        }
+            
+        case ECHO_REQUEST:
+            l2cap_register_signaling_response(handle, code, sig_id, 0);
+            return;
+            
+        case INFORMATION_REQUEST: {
+            uint16_t infoType = READ_BT_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
+            l2cap_register_signaling_response(handle, code, sig_id, infoType);
+            return;
+        }
+            
+        default:
+            break;
+    }
+    
+    
+    // Get potential destination CID
+    uint16_t dest_cid = READ_BT_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
+    
+    // Find channel for this sig_id and connection handle
+    linked_item_t *it;
+    for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
+        l2cap_channel_t * channel = (l2cap_channel_t *) it;
+        if (channel->handle == handle) {
+            if (code & 1) {
+                // match odd commands (responses) by previous signaling identifier 
+                if (channel->local_sig_id == sig_id) {
+                    l2cap_signaling_handler_channel(channel, command);
+                    break;
+                }
+            } else {
+                // match even commands (requests) by local channel id
+                if (channel->local_cid == dest_cid) {
+                    l2cap_signaling_handler_channel(channel, command);
+                    break;
+                }
+            }
+        }
+    }
+}
+
+void l2cap_acl_handler( uint8_t *packet, uint16_t size ){
+        
+    // Get Channel ID
+    uint16_t channel_id = READ_L2CAP_CHANNEL_ID(packet); 
+    hci_con_handle_t handle = READ_ACL_CONNECTION_HANDLE(packet);
+    
+    switch (channel_id) {
+            
+        case L2CAP_CID_SIGNALING: {
+            
+            uint16_t command_offset = 8;
+            while (command_offset < size) {                
+                
+                // handle signaling commands
+                l2cap_signaling_handler_dispatch(handle, &packet[command_offset]);
+                
+                // increment command_offset
+                command_offset += L2CAP_SIGNALING_COMMAND_DATA_OFFSET + READ_BT_16(packet, command_offset + L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET);
+            }
+            break;
+        }
+            
+        case L2CAP_CID_ATTRIBUTE_PROTOCOL:
+            if (attribute_protocol_packet_handler) {
+                (*attribute_protocol_packet_handler)(ATT_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
+            }
+            break;
+
+        case L2CAP_CID_SECURITY_MANAGER_PROTOCOL:
+            if (security_protocol_packet_handler) {
+                (*security_protocol_packet_handler)(SM_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
+            }
+            break;
+            
+        default: {
+            // Find channel for this channel_id and connection handle
+            l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(channel_id);
+            if (channel) {
+                l2cap_dispatch(channel, L2CAP_DATA_PACKET, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER);
+            }
+            break;
+        }
+    }
+    
+    l2cap_run();
+}
+
+static void l2cap_packet_handler(uint8_t packet_type, uint8_t *packet, uint16_t size){
+    switch (packet_type) {
+        case HCI_EVENT_PACKET:
+            l2cap_event_handler(packet, size);
+            break;
+        case HCI_ACL_DATA_PACKET:
+            l2cap_acl_handler(packet, size);
+            break;
+        default:
+            break;
+    }
+}
+
+// finalize closed channel - l2cap_handle_disconnect_request & DISCONNECTION_RESPONSE
+void l2cap_finialize_channel_close(l2cap_channel_t *channel){
+    channel->state = L2CAP_STATE_CLOSED;
+    l2cap_emit_channel_closed(channel);
+    // discard channel
+    linked_list_remove(&l2cap_channels, (linked_item_t *) channel);
+    btstack_memory_l2cap_channel_free(channel);
+}
+
+l2cap_service_t * l2cap_get_service(uint16_t psm){
+    linked_item_t *it;
+    
+    // close open channels
+    for (it = (linked_item_t *) l2cap_services; it ; it = it->next){
+        l2cap_service_t * service = ((l2cap_service_t *) it);
+        if ( service->psm == psm){
+            return service;
+        };
+    }
+    return NULL;
+}
+
+void l2cap_register_service_internal(void *connection, btstack_packet_handler_t packet_handler, uint16_t psm, uint16_t mtu){
+    // check for alread registered psm 
+    // TODO: emit error event
+    l2cap_service_t *service = l2cap_get_service(psm);
+    if (service) {
+        log_error("l2cap_register_service_internal: PSM %u already registered\n", psm);
+        l2cap_emit_service_registered(connection, L2CAP_SERVICE_ALREADY_REGISTERED, psm);
+        return;
+    }
+    
+    // alloc structure
+    // TODO: emit error event
+    service = (l2cap_service_t *) btstack_memory_l2cap_service_get();
+    if (!service) {
+        log_error("l2cap_register_service_internal: no memory for l2cap_service_t\n");
+        l2cap_emit_service_registered(connection, BTSTACK_MEMORY_ALLOC_FAILED, psm);
+        return;
+    }
+    
+    // fill in 
+    service->psm = psm;
+    service->mtu = mtu;
+    service->connection = connection;
+    service->packet_handler = packet_handler;
+
+    // add to services list
+    linked_list_add(&l2cap_services, (linked_item_t *) service);
+    
+    // enable page scan
+    hci_connectable_control(1);
+
+    // done
+    l2cap_emit_service_registered(connection, 0, psm);
+}
+
+void l2cap_unregister_service_internal(void *connection, uint16_t psm){
+    l2cap_service_t *service = l2cap_get_service(psm);
+    if (!service) return;
+    linked_list_remove(&l2cap_services, (linked_item_t *) service);
+    btstack_memory_l2cap_service_free(service);
+    
+    // disable page scan when no services registered
+    if (!linked_list_empty(&l2cap_services)) return;
+    hci_connectable_control(0);
+}
+
+//
+void l2cap_close_connection(void *connection){
+    linked_item_t *it;
+    
+    // close open channels - note to myself: no channel is freed, so no new for fancy iterator tricks
+    l2cap_channel_t * channel;
+    for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){
+        channel = (l2cap_channel_t *) it;
+        if (channel->connection == connection) {
+            channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST;
+        }
+    }   
+    
+    // unregister services
+    it = (linked_item_t *) &l2cap_services;
+    while (it->next) {
+        l2cap_service_t * service = (l2cap_service_t *) it->next;
+        if (service->connection == connection){
+            it->next = it->next->next;
+            btstack_memory_l2cap_service_free(service);
+        } else {
+            it = it->next;
+        }
+    }
+    
+    // process
+    l2cap_run();
+}
+
+// Bluetooth 4.0 - allows to register handler for Attribute Protocol and Security Manager Protocol
+void l2cap_register_fixed_channel(btstack_packet_handler_t packet_handler, uint16_t channel_id) {
+    switch(channel_id){
+        case L2CAP_CID_ATTRIBUTE_PROTOCOL:
+            attribute_protocol_packet_handler = packet_handler;
+            break;
+        case L2CAP_CID_SECURITY_MANAGER_PROTOCOL:
+            security_protocol_packet_handler = packet_handler;
+            break;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/l2cap.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  l2cap.h
+ *
+ *  Logical Link Control and Adaption Protocl (L2CAP)
+ *
+ *  Created by Matthias Ringwald on 5/16/09.
+ */
+
+#pragma once
+
+#include "hci.h"
+#include "l2cap_signaling.h"
+#include <btstack/utils.h>
+#include <btstack/btstack.h>
+
+#if defined __cplusplus
+extern "C" {
+#endif
+    
+#define L2CAP_SIG_ID_INVALID 0
+
+#define L2CAP_HEADER_SIZE 4
+
+// size of HCI ACL + L2CAP Header for regular data packets (8)
+#define COMPLETE_L2CAP_HEADER (HCI_ACL_HEADER_SIZE + L2CAP_HEADER_SIZE)
+    
+// minimum signaling MTU
+#define L2CAP_MINIMAL_MTU 48
+#define L2CAP_DEFAULT_MTU 672
+    
+// check L2CAP MTU
+#if (L2CAP_MINIMAL_MTU + L2CAP_HEADER_SIZE) > HCI_ACL_PAYLOAD_SIZE
+#error "HCI_ACL_PAYLOAD_SIZE too small for minimal L2CAP MTU of 48 bytes"
+#endif    
+    
+// L2CAP Fixed Channel IDs    
+#define L2CAP_CID_SIGNALING                 0x0001
+#define L2CAP_CID_CONNECTIONLESS_CHANNEL    0x0002
+#define L2CAP_CID_ATTRIBUTE_PROTOCOL        0x0004
+#define L2CAP_CID_SIGNALING_LE              0x0005
+#define L2CAP_CID_SECURITY_MANAGER_PROTOCOL 0x0006
+    
+void l2cap_init(void);
+void l2cap_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size));
+void l2cap_create_channel_internal(void * connection, btstack_packet_handler_t packet_handler, bd_addr_t address, uint16_t psm, uint16_t mtu);
+void l2cap_disconnect_internal(uint16_t local_cid, uint8_t reason);
+uint16_t l2cap_get_remote_mtu_for_local_cid(uint16_t local_cid);
+uint16_t l2cap_max_mtu(void);
+
+void l2cap_block_new_credits(uint8_t blocked);
+int  l2cap_can_send_packet_now(uint16_t local_cid);    // non-blocking UART write
+
+// get outgoing buffer and prepare data
+uint8_t *l2cap_get_outgoing_buffer(void);
+
+int  l2cap_send_prepared(uint16_t local_cid, uint16_t len);
+int l2cap_send_internal(uint16_t local_cid, uint8_t *data, uint16_t len);
+
+int  l2cap_send_prepared_connectionless(uint16_t handle, uint16_t cid, uint16_t len);
+int  l2cap_send_connectionless(uint16_t handle, uint16_t cid, uint8_t *data, uint16_t len);
+    
+void l2cap_close_connection(void *connection);
+
+void l2cap_register_service_internal(void *connection, btstack_packet_handler_t packet_handler, uint16_t psm, uint16_t mtu);
+void l2cap_unregister_service_internal(void *connection, uint16_t psm);
+
+void l2cap_accept_connection_internal(uint16_t local_cid);
+void l2cap_decline_connection_internal(uint16_t local_cid, uint8_t reason);
+
+// Bluetooth 4.0 - allows to register handler for Attribute Protocol and Security Manager Protocol
+void l2cap_register_fixed_channel(btstack_packet_handler_t packet_handler, uint16_t channel_id);
+
+
+// private structs
+typedef enum {
+    L2CAP_STATE_CLOSED = 1,           // no baseband
+    L2CAP_STATE_WILL_SEND_CREATE_CONNECTION,
+    L2CAP_STATE_WAIT_CONNECTION_COMPLETE,
+    L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT,
+    L2CAP_STATE_WAIT_CONNECT_RSP, // from peer
+    L2CAP_STATE_CONFIG,
+    L2CAP_STATE_OPEN,
+    L2CAP_STATE_WAIT_DISCONNECT,  // from application
+    L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST,
+    L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE,
+    L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_ACCEPT,   
+    L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST,
+    L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE,
+} L2CAP_STATE;
+
+typedef enum {
+    L2CAP_CHANNEL_STATE_VAR_NONE          = 0,
+    L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_REQ = 1 << 0,
+    L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP = 1 << 1,
+    L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ = 1 << 2,
+    L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP = 1 << 3,
+    L2CAP_CHANNEL_STATE_VAR_SENT_CONF_REQ = 1 << 4,
+    L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP = 1 << 5,
+} L2CAP_CHANNEL_STATE_VAR;
+
+// info regarding an actual coneection
+typedef struct {
+    // linked list - assert: first field
+    linked_item_t    item;
+    
+    L2CAP_STATE state;
+    L2CAP_CHANNEL_STATE_VAR state_var;
+    
+    bd_addr_t address;
+    hci_con_handle_t handle;
+    
+    uint8_t   remote_sig_id;    // used by other side, needed for delayed response
+    uint8_t   local_sig_id;     // own signaling identifier
+    
+    uint16_t  local_cid;
+    uint16_t  remote_cid;
+    
+    uint16_t  local_mtu;
+    uint16_t  remote_mtu;
+    
+    uint16_t  psm;
+    
+    uint8_t   packets_granted;    // number of L2CAP/ACL packets client is allowed to send
+    
+    uint8_t   reason; // used in decline internal
+    
+    // client connection
+    void * connection;
+    
+    // internal connection
+    btstack_packet_handler_t packet_handler;
+    
+} l2cap_channel_t;
+
+// info regarding potential connections
+typedef struct {
+    // linked list - assert: first field
+    linked_item_t    item;
+    
+    // service id
+    uint16_t  psm;
+    
+    // incoming MTU
+    uint16_t mtu;
+    
+    // client connection
+    void *connection;    
+    
+    // internal connection
+    btstack_packet_handler_t packet_handler;
+    
+} l2cap_service_t;
+
+
+typedef struct l2cap_signaling_response {
+    hci_con_handle_t handle;
+    uint8_t  sig_id;
+    uint8_t  code;
+    uint16_t data; // infoType for INFORMATION REQUEST, result for CONNECTION request
+} l2cap_signaling_response_t;
+    
+    
+#if defined __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/l2cap_signaling.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  l2cap_signaling.h
+ *
+ *  Created by Matthias Ringwald on 7/23/09.
+ */
+
+#include "l2cap_signaling.h"
+
+#include <string.h>
+
+static char *l2cap_signaling_commands_format[] = {
+"D",    // 0x01 command reject: reason {cmd not understood (0), sig MTU exceeded (2:max sig MTU), invalid CID (4:req CID)}, data len, data
+"22",   // 0x02 connection request: PSM, Source CID
+"2222", // 0x03 connection response: Dest CID, Source CID, Result, Status
+"22D",  // 0x04 config request: Dest CID, Flags, Configuration options
+"222D", // 0x05 config response: Source CID, Flags, Result, Configuration options
+"22",   // 0x06 disconection request: Dest CID, Source CID
+"22",   // 0x07 disconection response: Dest CID, Source CID
+"D",    // 0x08 echo request: Data
+"D",    // 0x09 echo response: Data
+"2",    // 0x0a information request: InfoType {1=Connectionless MTU, 2=Extended features supported}
+"22D",  // 0x0b information response: InfoType, Result, Data
+};
+
+uint8_t   sig_seq_nr  = 0xff;
+uint16_t  source_cid  = 0x40;
+
+uint8_t l2cap_next_sig_id(void){
+    if (sig_seq_nr == 0xff) {
+        sig_seq_nr = 1;
+    } else {
+        sig_seq_nr++;
+    }
+    return sig_seq_nr;
+}
+
+uint16_t l2cap_next_local_cid(void){
+    return source_cid++;
+}
+
+uint16_t l2cap_create_signaling_internal(uint8_t * acl_buffer, hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, va_list argptr){
+    
+    // 0 - Connection handle : PB=10 : BC=00 
+    bt_store_16(acl_buffer, 0, handle | (2 << 12) | (0 << 14));
+    // 6 - L2CAP channel = 1
+    bt_store_16(acl_buffer, 6, 1);
+    // 8 - Code
+    acl_buffer[8] = cmd;
+    // 9 - id (!= 0 sequentially)
+    acl_buffer[9] = identifier;
+    
+    // 12 - L2CAP signaling parameters
+    uint16_t pos = 12;
+    const char *format = l2cap_signaling_commands_format[cmd-1];
+    uint16_t word;
+    uint8_t * ptr;
+    while (*format) {
+        switch(*format) {
+            case '1': //  8 bit value
+            case '2': // 16 bit value
+                word = va_arg(argptr, int);
+                // minimal va_arg is int: 2 bytes on 8+16 bit CPUs
+                acl_buffer[pos++] = word & 0xff;
+                if (*format == '2') {
+                    acl_buffer[pos++] = word >> 8;
+                }
+                break;
+            case 'D': // variable data. passed: len, ptr
+                word = va_arg(argptr, int);
+                ptr  = va_arg(argptr, uint8_t *);
+                memcpy(&acl_buffer[pos], ptr, word);
+                pos += word;
+                break;
+            default:
+                break;
+        }
+        format++;
+    };
+    va_end(argptr);
+    
+    // Fill in various length fields: it's the number of bytes following for ACL lenght and l2cap parameter length
+    // - the l2cap payload length is counted after the following channel id (only payload) 
+    
+    // 2 - ACL length
+    bt_store_16(acl_buffer, 2,  pos - 4);
+    // 4 - L2CAP packet length
+    bt_store_16(acl_buffer, 4,  pos - 6 - 2);
+    // 10 - L2CAP signaling parameter length
+    bt_store_16(acl_buffer, 10, pos - 12);
+    
+    return pos;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/l2cap_signaling.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  l2cap_signaling.h
+ *
+ *  Created by Matthias Ringwald on 7/23/09.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdarg.h>
+#include <btstack/utils.h>
+#include <btstack/hci_cmds.h>
+
+typedef enum {
+    COMMAND_REJECT = 1,
+    CONNECTION_REQUEST,
+    CONNECTION_RESPONSE,
+    CONFIGURE_REQUEST,
+    CONFIGURE_RESPONSE,
+    DISCONNECTION_REQUEST,
+    DISCONNECTION_RESPONSE,
+    ECHO_REQUEST,
+    ECHO_RESPONSE,
+    INFORMATION_REQUEST,
+    INFORMATION_RESPONSE
+} L2CAP_SIGNALING_COMMANDS;
+
+uint16_t l2cap_create_signaling_internal(uint8_t * acl_buffer,hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, va_list argptr);
+uint8_t  l2cap_next_sig_id(void);
+uint16_t l2cap_next_local_cid(void);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/linked_list.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  linked_list.c
+ *
+ *  Created by Matthias Ringwald on 7/13/09.
+ */
+
+#include <btstack/linked_list.h>
+#include <stdlib.h>
+/**
+ * tests if list is empty
+ */
+int  linked_list_empty(linked_list_t * list){
+    return *list == (void *) 0;
+}
+
+/**
+ * linked_list_get_last_item
+ */
+linked_item_t * linked_list_get_last_item(linked_list_t * list){        // <-- find the last item in the list
+    linked_item_t *lastItem = NULL;
+    linked_item_t *it;
+    for (it = *list; it ; it = it->next){
+        if (it) {
+            lastItem = it;
+        }
+    }
+    return lastItem;
+}
+
+
+/**
+ * linked_list_add
+ */
+void linked_list_add(linked_list_t * list, linked_item_t *item){        // <-- add item to list
+    // check if already in list
+    linked_item_t *it;
+    for (it = *list; it ; it = it->next){
+        if (it == item) {
+            return;
+        }
+    }
+    // add first
+    item->next = *list;
+    *list = item;
+}
+
+void linked_list_add_tail(linked_list_t * list, linked_item_t *item){   // <-- add item to list as last element
+    // check if already in list
+    linked_item_t *it;
+    for (it = (linked_item_t *) list; it->next ; it = it->next){
+        if (it->next == item) {
+            return;
+        }
+    }
+    item->next = (linked_item_t*) 0;
+    it->next = item;
+}
+
+/**
+ * Remove data_source from run loop
+ *
+ * @note: assumes that data_source_t.next is first element in data_source
+ */
+int  linked_list_remove(linked_list_t * list, linked_item_t *item){    // <-- remove item from list
+    linked_item_t *it;
+    for (it = (linked_item_t *) list; it ; it = it->next){
+        if (it->next == item){
+            it->next =  item->next;
+            return 0;
+        }
+    }
+    return -1;
+}
+
+void linked_item_set_user(linked_item_t *item, void *user_data){
+    item->next = (linked_item_t *) 0;
+    item->user_data = user_data;
+}
+
+void * linked_item_get_user(linked_item_t *item) {
+    return item->user_data;
+}
+
+#if 0
+#include <stdio.h>
+void test_linked_list(){
+    linked_list_t testList = 0;
+    linked_item_t itemA;
+    linked_item_t itemB;
+    linked_item_t itemC;
+    linked_item_set_user(&itemA, (void *) 0);
+    linked_item_set_user(&itemB, (void *) 0);
+    linked_list_add(&testList, &itemA);
+    linked_list_add(&testList, &itemB);
+    linked_list_add_tail(&testList, &itemC);
+    // linked_list_remove(&testList, &itemB);
+    linked_item_t *it;
+    for (it = (linked_item_t *) &testList; it ; it = it->next){
+        if (it->next == &itemA) printf("Item A\n");
+        if (it->next == &itemB) printf("Item B\n");
+        if (it->next == &itemC) printf("Item C\n");
+        /* if (it->next == &itemB){
+            it->next =  it->next;
+            printf(" remove\n");
+        } else {
+            printf(" keep\n");
+        
+         */
+    }
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/linked_list.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2009 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ *  linked_list.h
+ *
+ *  Created by Matthias Ringwald on 7/13/09.
+ */
+
+#pragma once
+
+#if defined __cplusplus
+extern "C" {
+#endif
+    
+typedef struct linked_item {
+    struct linked_item *next; // <-- next element in list, or NULL
+    void *user_data;          // <-- pointer to struct base
+} linked_item_t;
+
+typedef linked_item_t * linked_list_t;
+
+void linked_item_set_user(linked_item_t *item, void *user_data);        // <-- set user data
+void * linked_item_get_user(linked_item_t *item);                       // <-- get user data
+int  linked_list_empty(linked_list_t * list);
+void linked_list_add(linked_list_t * list, linked_item_t *item);        // <-- add item to list as first element
+void linked_list_add_tail(linked_list_t * list, linked_item_t *item);   // <-- add item to list as last element
+int  linked_list_remove(linked_list_t * list, linked_item_t *item);     // <-- remove item from list
+linked_item_t * linked_list_get_last_item(linked_list_t * list);        // <-- find the last item in the list
+
+void test_linked_list(void);
+
+#if defined __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/memory_pool.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2011 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ *  memory_pool.h
+ *
+ *  @Brief Fixed-size block allocation
+ *
+ *  @Assumption block_size >= sizeof(void *)
+ *  @Assumption size of storage >= count * block_size
+ *
+ *  @Note minimal implementation, no error checking/handling
+ */
+
+#pragma once
+
+typedef void * memory_pool_t;
+
+// initialize memory pool with with given storage, block size and count
+void   memory_pool_create(memory_pool_t *pool, void * storage, int count, int block_size);
+
+// get free block from pool, @returns NULL or pointer to block
+void * memory_pool_get(memory_pool_t *pool);
+
+// return previously reserved block to memory pool
+void   memory_pool_free(memory_pool_t *pool, void * block);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/remote_device_db.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/**
+ * interface to provide link key and remote name storage
+ */
+
+#pragma once
+
+#include <btstack/utils.h>
+
+typedef struct {
+
+    // management
+    void (*open)(void);
+    void (*close)(void);
+    
+    // link key
+    int  (*get_link_key)(bd_addr_t *bd_addr, link_key_t *link_key);
+    void (*put_link_key)(bd_addr_t *bd_addr, link_key_t *key);
+    void (*delete_link_key)(bd_addr_t *bd_addr);
+    
+    // remote name
+    int  (*get_name)(bd_addr_t *bd_addr, device_name_t *device_name);
+    void (*put_name)(bd_addr_t *bd_addr, device_name_t *device_name);
+    void (*delete_name)(bd_addr_t *bd_addr);
+
+    // persistent rfcomm channel
+    uint8_t (*persistent_rfcomm_channel)(char *servicename);
+
+} remote_device_db_t;
+
+extern remote_device_db_t remote_device_db_iphone;
+extern const remote_device_db_t remote_device_db_memory;
+
+// MARK: non-persisten implementation
+#include <btstack/linked_list.h>
+#define MAX_NAME_LEN 32
+typedef struct {
+    // linked list - assert: first field
+    linked_item_t    item;
+    
+    bd_addr_t bd_addr;
+} db_mem_device_t;
+
+typedef struct {
+    db_mem_device_t device;
+    link_key_t link_key;
+} db_mem_device_link_key_t;
+
+typedef struct {
+    db_mem_device_t device;
+    char device_name[MAX_NAME_LEN];
+} db_mem_device_name_t;
+
+typedef struct {
+    // linked list - assert: first field
+    linked_item_t    item;
+    
+    char service_name[MAX_NAME_LEN];
+    uint8_t channel;
+} db_mem_service_t;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/remote_device_db_memory.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "remote_device_db.h"
+#include "btstack_memory.h"
+#include "debug.h"
+
+#include <btstack/utils.h>
+#include <btstack/linked_list.h>
+
+// This lists should be only accessed by tests.
+linked_list_t db_mem_link_keys = NULL;
+linked_list_t db_mem_names = NULL;
+static linked_list_t db_mem_services = NULL;
+
+// Device info
+static void db_open(void){
+}
+
+static void db_close(void){ 
+}
+
+static db_mem_device_t * get_item(linked_list_t list, bd_addr_t *bd_addr) {
+    linked_item_t *it;
+    for (it = (linked_item_t *) list; it ; it = it->next){
+        db_mem_device_t * item = (db_mem_device_t *) it;
+        if (BD_ADDR_CMP(item->bd_addr, *bd_addr) == 0) {
+            return item;
+        }
+    }
+    return NULL;
+}
+
+static int get_name(bd_addr_t *bd_addr, device_name_t *device_name) {
+    db_mem_device_name_t * item = (db_mem_device_name_t *) get_item(db_mem_names, bd_addr);
+    
+    if (!item) return 0;
+    
+    strncpy((char*)device_name, item->device_name, MAX_NAME_LEN);
+    
+    linked_list_remove(&db_mem_names, (linked_item_t *) item);
+    linked_list_add(&db_mem_names, (linked_item_t *) item);
+    
+    return 1;
+}
+
+static int get_link_key(bd_addr_t *bd_addr, link_key_t *link_key) {
+    db_mem_device_link_key_t * item = (db_mem_device_link_key_t *) get_item(db_mem_link_keys, bd_addr);
+    
+    if (!item) return 0;
+    
+    memcpy(link_key, item->link_key, LINK_KEY_LEN);
+    
+    linked_list_remove(&db_mem_link_keys, (linked_item_t *) item);
+    linked_list_add(&db_mem_link_keys, (linked_item_t *) item);
+
+    return 1;
+}
+
+static void delete_link_key(bd_addr_t *bd_addr){
+    db_mem_device_t * item = get_item(db_mem_link_keys, bd_addr);
+    
+    if (!item) return;
+    
+    linked_list_remove(&db_mem_link_keys, (linked_item_t *) item);
+    btstack_memory_db_mem_device_link_key_free(item);
+}
+
+
+static void put_link_key(bd_addr_t *bd_addr, link_key_t *link_key){
+    db_mem_device_link_key_t * existingRecord = (db_mem_device_link_key_t *) get_item(db_mem_link_keys, bd_addr);
+    
+    if (existingRecord){
+        memcpy(existingRecord->link_key, link_key, LINK_KEY_LEN);
+        return;
+    }
+    
+    // Record not found, create new one for this device
+    db_mem_device_link_key_t * newItem = (db_mem_device_link_key_t*) btstack_memory_db_mem_device_link_key_get();
+    if (!newItem){
+        newItem = (db_mem_device_link_key_t*)linked_list_get_last_item(&db_mem_link_keys);
+    }
+    
+    if (!newItem) return;
+    
+    memcpy(newItem->device.bd_addr, bd_addr, sizeof(bd_addr_t));
+    memcpy(newItem->link_key, link_key, LINK_KEY_LEN);
+    linked_list_add(&db_mem_link_keys, (linked_item_t *) newItem);
+}
+
+static void delete_name(bd_addr_t *bd_addr){
+    db_mem_device_t * item = get_item(db_mem_names, bd_addr);
+    
+    if (!item) return;
+    
+    linked_list_remove(&db_mem_names, (linked_item_t *) item);
+    btstack_memory_db_mem_device_name_free(item);    
+}
+
+static void put_name(bd_addr_t *bd_addr, device_name_t *device_name){
+    db_mem_device_name_t * existingRecord = (db_mem_device_name_t *) get_item(db_mem_names, bd_addr);
+    
+    if (existingRecord){
+        strncpy(existingRecord->device_name, (const char*) device_name, MAX_NAME_LEN);
+        return;
+    }
+    
+    // Record not found, create a new one for this device
+    db_mem_device_name_t * newItem = (db_mem_device_name_t *) btstack_memory_db_mem_device_name_get();
+    if (!newItem) {
+        newItem = (db_mem_device_name_t*)linked_list_get_last_item(&db_mem_names);
+    };
+
+    if (!newItem) return;
+    
+    memcpy(newItem->device.bd_addr, bd_addr, sizeof(bd_addr_t));
+    strncpy(newItem->device_name, (const char*) device_name, MAX_NAME_LEN);
+    linked_list_add(&db_mem_names, (linked_item_t *) newItem);
+}
+
+
+// MARK: PERSISTENT RFCOMM CHANNEL ALLOCATION
+
+static uint8_t persistent_rfcomm_channel(char *serviceName){
+    linked_item_t *it;
+    db_mem_service_t * item;
+    uint8_t max_channel = 1;
+
+    for (it = (linked_item_t *) db_mem_services; it ; it = it->next){
+        item = (db_mem_service_t *) it;
+        if (strncmp(item->service_name, serviceName, MAX_NAME_LEN) == 0) {
+            // Match found
+            return item->channel;
+        }
+
+        // TODO prevent overflow
+        if (item->channel >= max_channel) max_channel = item->channel + 1;
+    }
+
+    // Allocate new persistant channel
+    db_mem_service_t * newItem = (db_mem_service_t *) btstack_memory_db_mem_service_get();
+
+    if (!newItem) return 0;
+    
+    strncpy(newItem->service_name, serviceName, MAX_NAME_LEN);
+    newItem->channel = max_channel;
+    linked_list_add(&db_mem_services, (linked_item_t *) newItem);
+    return max_channel;
+}
+
+
+const remote_device_db_t remote_device_db_memory = {
+    db_open,
+    db_close,
+    get_link_key,
+    put_link_key,
+    delete_link_key,
+    get_name,
+    put_name,
+    delete_name,
+    persistent_rfcomm_channel
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/rfcomm.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,1869 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  rfcomm.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> // memcpy
+#include <stdint.h>
+
+#include <btstack/btstack.h>
+#include <btstack/hci_cmds.h>
+#include <btstack/utils.h>
+
+#include <btstack/utils.h>
+#include "btstack_memory.h"
+#include "hci.h"
+#include "hci_dump.h"
+#include "debug.h"
+#include "rfcomm.h"
+
+// workaround for missing PRIxPTR on mspgcc (16/20-bit MCU)
+#ifndef PRIxPTR
+#if defined(__MSP430X__)  &&  defined(__MSP430X_LARGE__)
+#define PRIxPTR "lx"
+#else
+#define PRIxPTR "x"
+#endif
+#endif
+
+
+// Control field values      bit no.       1 2 3 4 PF 6 7 8
+#define BT_RFCOMM_SABM       0x3F       // 1 1 1 1  1 1 0 0
+#define BT_RFCOMM_UA         0x73       // 1 1 0 0  1 1 1 0
+#define BT_RFCOMM_DM         0x0F       // 1 1 1 1  0 0 0 0
+#define BT_RFCOMM_DM_PF      0x1F        // 1 1 1 1  1 0 0 0
+#define BT_RFCOMM_DISC       0x53       // 1 1 0 0  1 0 1 0
+#define BT_RFCOMM_UIH        0xEF       // 1 1 1 1  0 1 1 1
+#define BT_RFCOMM_UIH_PF     0xFF       // 1 1 1 1  0 1 1 1
+
+// Multiplexer message types 
+#define BT_RFCOMM_CLD_CMD    0xC3
+#define BT_RFCOMM_FCON_CMD   0xA3
+#define BT_RFCOMM_FCON_RSP   0xA1
+#define BT_RFCOMM_FCOFF_CMD  0x63
+#define BT_RFCOMM_FCOFF_RSP  0x61
+#define BT_RFCOMM_MSC_CMD    0xE3
+#define BT_RFCOMM_MSC_RSP    0xE1
+#define BT_RFCOMM_NSC_RSP    0x11
+#define BT_RFCOMM_PN_CMD     0x83
+#define BT_RFCOMM_PN_RSP     0x81
+#define BT_RFCOMM_RLS_CMD    0x53
+#define BT_RFCOMM_RLS_RSP    0x51
+#define BT_RFCOMM_RPN_CMD    0x93
+#define BT_RFCOMM_RPN_RSP    0x91
+#define BT_RFCOMM_TEST_CMD   0x23
+#define BT_RFCOMM_TEST_RSP   0x21
+
+#define RFCOMM_MULIPLEXER_TIMEOUT_MS 60000
+
+// FCS calc 
+#define BT_RFCOMM_CODE_WORD         0xE0 // pol = x8+x2+x1+1
+#define BT_RFCOMM_CRC_CHECK_LEN     3
+#define BT_RFCOMM_UIHCRC_CHECK_LEN  2
+
+#include "l2cap.h"
+
+// used for debugging
+// #define RFCOMM_LOG_CREDITS
+
+// global rfcomm data
+static uint16_t      rfcomm_client_cid_generator;  // used for client channel IDs
+
+// linked lists for all
+static linked_list_t rfcomm_multiplexers = NULL;
+static linked_list_t rfcomm_channels = NULL;
+static linked_list_t rfcomm_services = NULL;
+
+static void (*app_packet_handler)(void * connection, uint8_t packet_type,
+                                  uint16_t channel, uint8_t *packet, uint16_t size);
+
+static void rfcomm_run(void);
+static void rfcomm_hand_out_credits(void);
+static void rfcomm_channel_state_machine(rfcomm_channel_t *channel, rfcomm_channel_event_t *event);
+static void rfcomm_channel_state_machine_2(rfcomm_multiplexer_t * multiplexer, uint8_t dlci, rfcomm_channel_event_t *event);
+static int rfcomm_channel_ready_for_open(rfcomm_channel_t *channel);
+static void rfcomm_multiplexer_state_machine(rfcomm_multiplexer_t * multiplexer, RFCOMM_MULTIPLEXER_EVENT event);
+
+
+// MARK: RFCOMM CLIENT EVENTS
+
+// data: event (8), len(8), address(48), channel (8), rfcomm_cid (16)
+static void rfcomm_emit_connection_request(rfcomm_channel_t *channel) {
+    uint8_t event[11];
+    event[0] = RFCOMM_EVENT_INCOMING_CONNECTION;
+    event[1] = sizeof(event) - 2;
+    bt_flip_addr(&event[2], channel->multiplexer->remote_addr);
+    event[8] = channel->dlci >> 1;
+    bt_store_16(event, 9, channel->rfcomm_cid);
+    hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
+    (*app_packet_handler)(channel->connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
+}
+
+// API Change: BTstack-0.3.50x uses
+// data: event(8), len(8), status (8), address (48), server channel(8), rfcomm_cid(16), max frame size(16)
+// next Cydia release will use SVN version of this
+// data: event(8), len(8), status (8), address (48), handle (16), server channel(8), rfcomm_cid(16), max frame size(16)
+static void rfcomm_emit_channel_opened(rfcomm_channel_t *channel, uint8_t status) {
+    uint8_t event[16];
+    uint8_t pos = 0;
+    event[pos++] = RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE;
+    event[pos++] = sizeof(event) - 2;
+    event[pos++] = status;
+    bt_flip_addr(&event[pos], channel->multiplexer->remote_addr); pos += 6;
+    bt_store_16(event,  pos, channel->multiplexer->con_handle);   pos += 2;
+    event[pos++] = channel->dlci >> 1;
+    bt_store_16(event, pos, channel->rfcomm_cid); pos += 2;       // channel ID
+    bt_store_16(event, pos, channel->max_frame_size); pos += 2;   // max frame size
+    hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
+    (*app_packet_handler)(channel->connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, pos);
+}
+
+static void rfcomm_emit_channel_open_failed_outgoing_memory(void * connection, bd_addr_t *addr, uint8_t server_channel){
+    uint8_t event[16];
+    uint8_t pos = 0;
+    event[pos++] = RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE;
+    event[pos++] = sizeof(event) - 2;
+    event[pos++] = BTSTACK_MEMORY_ALLOC_FAILED;
+    bt_flip_addr(&event[pos], *addr); pos += 6;
+    bt_store_16(event,  pos, 0);   pos += 2;
+    event[pos++] = server_channel;
+    bt_store_16(event, pos, 0); pos += 2;   // channel ID
+    bt_store_16(event, pos, 0); pos += 2;   // max frame size
+    hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
+    (*app_packet_handler)(connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, pos);
+}
+
+// data: event(8), len(8), creidts incoming(8), new credits incoming(8), credits outgoing(8)
+static inline void rfcomm_emit_credit_status(rfcomm_channel_t * channel) {
+#ifdef RFCOMM_LOG_CREDITS
+    uint8_t event[5];
+    event[0] = 0x88;
+    event[1] = sizeof(event) - 2;
+    event[2] = channel->credits_incoming;
+    event[3] = channel->new_credits_incoming;
+    event[4] = channel->credits_outgoing;
+    hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
+#endif
+}
+
+// data: event(8), len(8), rfcomm_cid(16)
+static void rfcomm_emit_channel_closed(rfcomm_channel_t * channel) {
+    uint8_t event[4];
+    event[0] = RFCOMM_EVENT_CHANNEL_CLOSED;
+    event[1] = sizeof(event) - 2;
+    bt_store_16(event, 2, channel->rfcomm_cid);
+    hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
+    (*app_packet_handler)(channel->connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
+}
+
+static void rfcomm_emit_credits(rfcomm_channel_t * channel, uint8_t credits) {
+    uint8_t event[5];
+    event[0] = RFCOMM_EVENT_CREDITS;
+    event[1] = sizeof(event) - 2;
+    bt_store_16(event, 2, channel->rfcomm_cid);
+    event[4] = credits;
+    hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
+    (*app_packet_handler)(channel->connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
+}
+
+static void rfcomm_emit_service_registered(void *connection, uint8_t status, uint8_t channel){
+    uint8_t event[4];
+    event[0] = RFCOMM_EVENT_SERVICE_REGISTERED;
+    event[1] = sizeof(event) - 2;
+    event[2] = status;
+    event[3] = channel;
+    hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
+    (*app_packet_handler)(connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
+}
+
+// MARK: RFCOMM MULTIPLEXER HELPER
+
+static uint16_t rfcomm_max_frame_size_for_l2cap_mtu(uint16_t l2cap_mtu){
+
+    // Assume RFCOMM header with credits and single byte length field
+    uint16_t max_frame_size = l2cap_mtu - 5;
+    
+    // single byte can denote len up to 127
+    if (max_frame_size > 127) {
+        max_frame_size--;
+    }
+
+    log_info("rfcomm_max_frame_size_for_l2cap_mtu:  %u -> %u\n", l2cap_mtu, max_frame_size);
+    return max_frame_size;
+}
+
+static void rfcomm_multiplexer_initialize(rfcomm_multiplexer_t *multiplexer){
+
+    memset(multiplexer, 0, sizeof(rfcomm_multiplexer_t));
+
+    multiplexer->state = RFCOMM_MULTIPLEXER_CLOSED;
+    multiplexer->l2cap_credits = 0;
+    multiplexer->send_dm_for_dlci = 0;
+    multiplexer->max_frame_size = rfcomm_max_frame_size_for_l2cap_mtu(l2cap_max_mtu());
+}
+
+static rfcomm_multiplexer_t * rfcomm_multiplexer_create_for_addr(bd_addr_t *addr){
+    
+    // alloc structure 
+    rfcomm_multiplexer_t * multiplexer = (rfcomm_multiplexer_t*)btstack_memory_rfcomm_multiplexer_get();
+    if (!multiplexer) return NULL;
+    
+    // fill in 
+    rfcomm_multiplexer_initialize(multiplexer);
+    BD_ADDR_COPY(&multiplexer->remote_addr, addr);
+
+    // add to services list
+    linked_list_add(&rfcomm_multiplexers, (linked_item_t *) multiplexer);
+    
+    return multiplexer;
+}
+
+static rfcomm_multiplexer_t * rfcomm_multiplexer_for_addr(bd_addr_t *addr){
+    linked_item_t *it;
+    for (it = (linked_item_t *) rfcomm_multiplexers; it ; it = it->next){
+        rfcomm_multiplexer_t * multiplexer = ((rfcomm_multiplexer_t *) it);
+        if (BD_ADDR_CMP(addr, multiplexer->remote_addr) == 0) {
+            return multiplexer;
+        };
+    }
+    return NULL;
+}
+
+static rfcomm_multiplexer_t * rfcomm_multiplexer_for_l2cap_cid(uint16_t l2cap_cid) {
+    linked_item_t *it;
+    for (it = (linked_item_t *) rfcomm_multiplexers; it ; it = it->next){
+        rfcomm_multiplexer_t * multiplexer = ((rfcomm_multiplexer_t *) it);
+        if (multiplexer->l2cap_cid == l2cap_cid) {
+            return multiplexer;
+        };
+    }
+    return NULL;
+}
+
+static int rfcomm_multiplexer_has_channels(rfcomm_multiplexer_t * multiplexer){
+    linked_item_t *it;
+    for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
+        rfcomm_channel_t * channel = ((rfcomm_channel_t *) it);
+        if (channel->multiplexer == multiplexer) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+// MARK: RFCOMM CHANNEL HELPER
+
+static void rfcomm_dump_channels(void){
+#ifndef EMBEDDED
+    linked_item_t * it;
+    int channels = 0;
+    for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
+        rfcomm_channel_t * channel = (rfcomm_channel_t *) it;
+        log_info("Channel #%u: addr %p, state %u\n", channels, channel, channel->state);
+        channels++;
+    }
+#endif
+}
+
+static void rfcomm_channel_initialize(rfcomm_channel_t *channel, rfcomm_multiplexer_t *multiplexer, 
+                               rfcomm_service_t *service, uint8_t server_channel){
+    
+    // don't use 0 as channel id
+    if (rfcomm_client_cid_generator == 0) ++rfcomm_client_cid_generator;
+    
+    // setup channel
+    memset(channel, 0, sizeof(rfcomm_channel_t));
+    
+    channel->state             = RFCOMM_CHANNEL_CLOSED;
+    channel->state_var         = RFCOMM_CHANNEL_STATE_VAR_NONE;
+    
+    channel->multiplexer      = multiplexer;
+    channel->service          = service;
+    channel->rfcomm_cid       = rfcomm_client_cid_generator++;
+    channel->max_frame_size   = multiplexer->max_frame_size;
+
+    channel->credits_incoming = 0;
+    channel->credits_outgoing = 0;
+    channel->packets_granted  = 0;
+
+    // incoming flow control not active
+    channel->new_credits_incoming  = 0x30;
+    channel->incoming_flow_control = 0;
+    
+    if (service) {
+        // incoming connection
+        channel->outgoing = 0;
+        channel->dlci = (server_channel << 1) |  multiplexer->outgoing;
+        if (channel->max_frame_size > service->max_frame_size) {
+            channel->max_frame_size = service->max_frame_size;
+        }
+        channel->incoming_flow_control = service->incoming_flow_control;
+        channel->new_credits_incoming  = service->incoming_initial_credits;
+    } else {
+        // outgoing connection
+        channel->outgoing = 1;
+        channel->dlci = (server_channel << 1) | (multiplexer->outgoing ^ 1);
+    }
+}
+
+// service == NULL -> outgoing channel
+static rfcomm_channel_t * rfcomm_channel_create(rfcomm_multiplexer_t * multiplexer,
+                                                rfcomm_service_t * service, uint8_t server_channel){
+
+    log_info("rfcomm_channel_create for service %p, channel %u --- begin\n", service, server_channel);
+    rfcomm_dump_channels();
+
+    // alloc structure 
+    rfcomm_channel_t * channel = (rfcomm_channel_t*)btstack_memory_rfcomm_channel_get();
+    if (!channel) return NULL;
+    
+    // fill in 
+    rfcomm_channel_initialize(channel, multiplexer, service, server_channel);
+    
+    // add to services list
+    linked_list_add(&rfcomm_channels, (linked_item_t *) channel);
+    
+    return channel;
+}
+
+static rfcomm_channel_t * rfcomm_channel_for_rfcomm_cid(uint16_t rfcomm_cid){
+    linked_item_t *it;
+    for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
+        rfcomm_channel_t * channel = ((rfcomm_channel_t *) it);
+        if (channel->rfcomm_cid == rfcomm_cid) {
+            return channel;
+        };
+    }
+    return NULL;
+}
+
+static rfcomm_channel_t * rfcomm_channel_for_multiplexer_and_dlci(rfcomm_multiplexer_t * multiplexer, uint8_t dlci){
+    linked_item_t *it;
+    for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
+        rfcomm_channel_t * channel = ((rfcomm_channel_t *) it);
+        if (channel->dlci == dlci && channel->multiplexer == multiplexer) {
+            return channel;
+        };
+    }
+    return NULL;
+}
+
+static rfcomm_service_t * rfcomm_service_for_channel(uint8_t server_channel){
+    linked_item_t *it;
+    for (it = (linked_item_t *) rfcomm_services; it ; it = it->next){
+        rfcomm_service_t * service = ((rfcomm_service_t *) it);
+        if ( service->server_channel == server_channel){
+            return service;
+        };
+    }
+    return NULL;
+}
+
+// MARK: RFCOMM SEND
+
+/**
+ * @param credits - only used for RFCOMM flow control in UIH wiht P/F = 1
+ */
+static int rfcomm_send_packet_for_multiplexer(rfcomm_multiplexer_t *multiplexer, uint8_t address, uint8_t control, uint8_t credits, uint8_t *data, uint16_t len){
+
+    if (!l2cap_can_send_packet_now(multiplexer->l2cap_cid)) return BTSTACK_ACL_BUFFERS_FULL;
+    
+    uint8_t * rfcomm_out_buffer = l2cap_get_outgoing_buffer();
+    
+    uint16_t pos = 0;
+    uint8_t crc_fields = 3;
+    
+    rfcomm_out_buffer[pos++] = address;
+    rfcomm_out_buffer[pos++] = control;
+    
+    // length field can be 1 or 2 octets
+    if (len < 128){
+        rfcomm_out_buffer[pos++] = (len << 1)| 1;     // bits 0-6
+    } else {
+        rfcomm_out_buffer[pos++] = (len & 0x7f) << 1; // bits 0-6
+        rfcomm_out_buffer[pos++] = len >> 7;          // bits 7-14
+        crc_fields++;
+    }
+
+    // add credits for UIH frames when PF bit is set
+    if (control == BT_RFCOMM_UIH_PF){
+        rfcomm_out_buffer[pos++] = credits;
+    }
+    
+    // copy actual data
+    if (len) {
+        memcpy(&rfcomm_out_buffer[pos], data, len);
+        pos += len;
+    }
+    
+    // UIH frames only calc FCS over address + control (5.1.1)
+    if ((control & 0xef) == BT_RFCOMM_UIH){
+        crc_fields = 2;
+    }
+    rfcomm_out_buffer[pos++] =  crc8_calc(rfcomm_out_buffer, crc_fields); // calc fcs
+
+    int credits_taken = 0;
+    if (multiplexer->l2cap_credits){
+        credits_taken++;
+        multiplexer->l2cap_credits--;
+    } else {
+        log_info( "rfcomm_send_packet addr %02x, ctrl %02x size %u without l2cap credits\n", address, control, pos);
+    }
+    
+    int err = l2cap_send_prepared(multiplexer->l2cap_cid, pos);
+    
+    if (err) {
+        // undo credit counting
+        multiplexer->l2cap_credits += credits_taken;
+    }
+    return err;
+}
+
+// C/R Flag in Address
+// - terms: initiator = station that creates multiplexer with SABM
+// - terms: responder = station that responds to multiplexer setup with UA
+// "For SABM, UA, DM and DISC frames C/R bit is set according to Table 1 in GSM 07.10, section 5.2.1.2"
+//    - command initiator = 1 /response responder = 1
+//    - command responder = 0 /response initiator = 0
+// "For UIH frames, the C/R bit is always set according to section 5.4.3.1 in GSM 07.10. 
+//  This applies independently of what is contained wthin the UIH frames, either data or control messages."
+//    - c/r = 1 for frames by initiating station, 0 = for frames by responding station
+
+// C/R Flag in Message
+// "In the message level, the C/R bit in the command type field is set as stated in section 5.4.6.2 in GSM 07.10." 
+//   - If the C/R bit is set to 1 the message is a command
+//   - if it is set to 0 the message is a response.
+
+// temp/old messge construction
+
+// new object oriented version
+static int rfcomm_send_sabm(rfcomm_multiplexer_t *multiplexer, uint8_t dlci){
+    uint8_t address = (1 << 0) | (multiplexer->outgoing << 1) | (dlci << 2);   // command
+    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_SABM, 0, NULL, 0);
+}
+
+static int rfcomm_send_disc(rfcomm_multiplexer_t *multiplexer, uint8_t dlci){
+    uint8_t address = (1 << 0) | (multiplexer->outgoing << 1) | (dlci << 2);  // command
+    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_DISC, 0, NULL, 0);
+}
+
+static int rfcomm_send_ua(rfcomm_multiplexer_t *multiplexer, uint8_t dlci){
+    uint8_t address = (1 << 0) | ((multiplexer->outgoing ^ 1) << 1) | (dlci << 2); // response
+    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UA, 0, NULL, 0);
+}
+
+static int rfcomm_send_dm_pf(rfcomm_multiplexer_t *multiplexer, uint8_t dlci){
+    uint8_t address = (1 << 0) | ((multiplexer->outgoing ^ 1) << 1) | (dlci << 2); // response
+    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_DM_PF, 0, NULL, 0);
+}
+
+static int rfcomm_send_uih_msc_cmd(rfcomm_multiplexer_t *multiplexer, uint8_t dlci, uint8_t signals) {
+    uint8_t address = (1 << 0) | (multiplexer->outgoing << 1);
+    uint8_t payload[4]; 
+    uint8_t pos = 0;
+    payload[pos++] = BT_RFCOMM_MSC_CMD;
+    payload[pos++] = 2 << 1 | 1;  // len
+    payload[pos++] = (1 << 0) | (1 << 1) | (dlci << 2); // CMD => C/R = 1
+    payload[pos++] = signals;
+    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos);
+}
+
+static int rfcomm_send_uih_msc_rsp(rfcomm_multiplexer_t *multiplexer, uint8_t dlci, uint8_t signals) {
+    uint8_t address = (1 << 0) | (multiplexer->outgoing<< 1);
+    uint8_t payload[4]; 
+    uint8_t pos = 0;
+    payload[pos++] = BT_RFCOMM_MSC_RSP;
+    payload[pos++] = 2 << 1 | 1;  // len
+    payload[pos++] = (1 << 0) | (1 << 1) | (dlci << 2); // CMD => C/R = 1
+    payload[pos++] = signals;
+    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos);
+}
+
+static int rfcomm_send_uih_pn_command(rfcomm_multiplexer_t *multiplexer, uint8_t dlci, uint16_t max_frame_size){
+    uint8_t payload[10];
+    uint8_t address = (1 << 0) | (multiplexer->outgoing << 1); 
+    uint8_t pos = 0;
+    payload[pos++] = BT_RFCOMM_PN_CMD;
+    payload[pos++] = 8 << 1 | 1;  // len
+    payload[pos++] = dlci;
+    payload[pos++] = 0xf0; // pre-defined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM
+    payload[pos++] = 0; // priority
+    payload[pos++] = 0; // max 60 seconds ack
+    payload[pos++] = max_frame_size & 0xff; // max framesize low
+    payload[pos++] = max_frame_size >> 8;   // max framesize high
+    payload[pos++] = 0x00; // number of retransmissions
+    payload[pos++] = 0x00; // (unused error recovery window) initial number of credits
+    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos);
+}
+
+// "The response may not change the DLCI, the priority, the convergence layer, or the timer value." RFCOMM-tutorial.pdf
+static int rfcomm_send_uih_pn_response(rfcomm_multiplexer_t *multiplexer, uint8_t dlci,
+                                       uint8_t priority, uint16_t max_frame_size){
+    uint8_t payload[10];
+    uint8_t address = (1 << 0) | (multiplexer->outgoing << 1); 
+    uint8_t pos = 0;
+    payload[pos++] = BT_RFCOMM_PN_RSP;
+    payload[pos++] = 8 << 1 | 1;  // len
+    payload[pos++] = dlci;
+    payload[pos++] = 0xe0; // pre defined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM
+    payload[pos++] = priority; // priority
+    payload[pos++] = 0; // max 60 seconds ack
+    payload[pos++] = max_frame_size & 0xff; // max framesize low
+    payload[pos++] = max_frame_size >> 8;   // max framesize high
+    payload[pos++] = 0x00; // number of retransmissions
+    payload[pos++] = 0x00; // (unused error recovery window) initial number of credits
+    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos);
+}
+
+static int rfcomm_send_uih_rpn_rsp(rfcomm_multiplexer_t *multiplexer, uint8_t dlci, rfcomm_rpn_data_t *rpn_data) {
+    uint8_t payload[10];
+    uint8_t address = (1 << 0) | (multiplexer->outgoing << 1); 
+    uint8_t pos = 0;
+    payload[pos++] = BT_RFCOMM_RPN_RSP;
+    payload[pos++] = 8 << 1 | 1;  // len
+    payload[pos++] = (1 << 0) | (1 << 1) | (dlci << 2); // CMD => C/R = 1
+    payload[pos++] = rpn_data->baud_rate;
+    payload[pos++] = rpn_data->flags;
+    payload[pos++] = rpn_data->flow_control;
+    payload[pos++] = rpn_data->xon;
+    payload[pos++] = rpn_data->xoff;
+    payload[pos++] = rpn_data->parameter_mask_0;
+    payload[pos++] = rpn_data->parameter_mask_1;
+    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos);
+}
+
+static int rfcomm_send_uih_data(rfcomm_multiplexer_t *multiplexer, uint8_t dlci, uint8_t *data, uint16_t len){
+    uint8_t address = (1 << 0) | (multiplexer->outgoing << 1) | (dlci << 2); 
+    return rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UIH, 0, data, len);
+}
+
+static void rfcomm_send_uih_credits(rfcomm_multiplexer_t *multiplexer, uint8_t dlci,  uint8_t credits){
+    uint8_t address = (1 << 0) | (multiplexer->outgoing << 1) |  (dlci << 2); 
+    rfcomm_send_packet_for_multiplexer(multiplexer, address, BT_RFCOMM_UIH_PF, credits, NULL, 0);
+}
+
+// MARK: RFCOMM MULTIPLEXER
+
+static void rfcomm_multiplexer_finalize(rfcomm_multiplexer_t * multiplexer){
+    
+    // remove (potential) timer
+    if (multiplexer->timer_active) {
+        run_loop_remove_timer(&multiplexer->timer);
+        multiplexer->timer_active = 0;
+    }
+    
+    // close and remove all channels
+    linked_item_t *it = (linked_item_t *) &rfcomm_channels;
+    while (it->next){
+        rfcomm_channel_t * channel = (rfcomm_channel_t *) it->next;
+        if (channel->multiplexer == multiplexer) {
+            // emit appropriate events
+            if (channel->state == RFCOMM_CHANNEL_OPEN) {
+                rfcomm_emit_channel_closed(channel);
+            } else {
+                rfcomm_emit_channel_opened(channel, RFCOMM_MULTIPLEXER_STOPPED); 
+            }
+            // remove from list
+            it->next = it->next->next;
+            // free channel struct
+            btstack_memory_rfcomm_channel_free(channel);
+        } else {
+            it = it->next;
+        }
+    }
+    
+    // keep reference to l2cap channel
+    uint16_t l2cap_cid = multiplexer->l2cap_cid;
+    
+    // remove mutliplexer
+    linked_list_remove( &rfcomm_multiplexers, (linked_item_t *) multiplexer);
+    btstack_memory_rfcomm_multiplexer_free(multiplexer);
+    
+    // close l2cap multiplexer channel, too
+    l2cap_disconnect_internal(l2cap_cid, 0x13);
+}
+
+static void rfcomm_multiplexer_timer_handler(timer_source_t *timer){
+    rfcomm_multiplexer_t * multiplexer = (rfcomm_multiplexer_t *) linked_item_get_user( (linked_item_t *) timer);
+    if (!rfcomm_multiplexer_has_channels(multiplexer)){
+        log_info( "rfcomm_multiplexer_timer_handler timeout: shutting down multiplexer!\n");
+        rfcomm_multiplexer_finalize(multiplexer);
+    }
+}
+
+static void rfcomm_multiplexer_prepare_idle_timer(rfcomm_multiplexer_t * multiplexer){
+    if (multiplexer->timer_active) {
+        run_loop_remove_timer(&multiplexer->timer);
+        multiplexer->timer_active = 0;
+    }
+    if (!rfcomm_multiplexer_has_channels(multiplexer)){
+        // start timer for multiplexer timeout check
+        run_loop_set_timer(&multiplexer->timer, RFCOMM_MULIPLEXER_TIMEOUT_MS);
+        multiplexer->timer.process = rfcomm_multiplexer_timer_handler;
+        linked_item_set_user((linked_item_t*) &multiplexer->timer, multiplexer);
+        run_loop_add_timer(&multiplexer->timer);
+        multiplexer->timer_active = 1;
+    }
+}
+
+static void rfcomm_multiplexer_opened(rfcomm_multiplexer_t *multiplexer){
+    log_info("Multiplexer up and running\n");
+    multiplexer->state = RFCOMM_MULTIPLEXER_OPEN;
+    
+    rfcomm_channel_event_t event = { CH_EVT_MULTIPLEXER_READY };
+    
+    // transition of channels that wait for multiplexer 
+    linked_item_t *it;
+    for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
+        rfcomm_channel_t * channel = ((rfcomm_channel_t *) it);
+        if (channel->multiplexer != multiplexer) continue;
+        rfcomm_channel_state_machine(channel, &event);
+    }        
+    
+    rfcomm_run();
+    rfcomm_multiplexer_prepare_idle_timer(multiplexer);
+}
+
+
+/**
+ * @return handled packet
+ */
+static int rfcomm_multiplexer_hci_event_handler(uint8_t *packet, uint16_t size){
+    bd_addr_t event_addr;
+    uint16_t  psm;
+    uint16_t l2cap_cid;
+    hci_con_handle_t con_handle;
+    rfcomm_multiplexer_t *multiplexer = NULL;
+    switch (packet[0]) {
+            
+        // accept incoming PSM_RFCOMM connection if no multiplexer exists yet
+        case L2CAP_EVENT_INCOMING_CONNECTION:
+            // data: event(8), len(8), address(48), handle (16),  psm (16), source cid(16) dest cid(16)
+            bt_flip_addr(event_addr, &packet[2]);
+            con_handle = READ_BT_16(packet,  8);
+            psm        = READ_BT_16(packet, 10); 
+            l2cap_cid  = READ_BT_16(packet, 12); 
+
+            if (psm != PSM_RFCOMM) break;
+
+            multiplexer = rfcomm_multiplexer_for_addr(&event_addr);
+            
+            if (multiplexer) {
+                log_info("INCOMING_CONNECTION (l2cap_cid 0x%02x) for PSM_RFCOMM => decline - multiplexer already exists", l2cap_cid);
+                l2cap_decline_connection_internal(l2cap_cid,  0x04);    // no resources available
+                return 1;
+            }
+            
+            // create and inititialize new multiplexer instance (incoming)
+            multiplexer = rfcomm_multiplexer_create_for_addr(&event_addr);
+            if (!multiplexer){
+                log_info("INCOMING_CONNECTION (l2cap_cid 0x%02x) for PSM_RFCOMM => decline - no memory left", l2cap_cid);
+                l2cap_decline_connection_internal(l2cap_cid,  0x04);    // no resources available
+                return 1;
+            }
+            
+            multiplexer->con_handle = con_handle;
+            multiplexer->l2cap_cid = l2cap_cid;
+            multiplexer->state = RFCOMM_MULTIPLEXER_W4_SABM_0;
+            
+            log_info("L2CAP_EVENT_INCOMING_CONNECTION (l2cap_cid 0x%02x) for PSM_RFCOMM => accept", l2cap_cid);
+            l2cap_accept_connection_internal(l2cap_cid);
+            return 1;
+            
+        // l2cap connection opened -> store l2cap_cid, remote_addr
+        case L2CAP_EVENT_CHANNEL_OPENED: 
+            if (READ_BT_16(packet, 11) != PSM_RFCOMM) break;
+            log_info("L2CAP_EVENT_CHANNEL_OPENED for PSM_RFCOMM\n");
+            // get multiplexer for remote addr
+            con_handle = READ_BT_16(packet, 9);
+            l2cap_cid = READ_BT_16(packet, 13);
+            bt_flip_addr(event_addr, &packet[3]);
+            multiplexer = rfcomm_multiplexer_for_addr(&event_addr);
+            if (!multiplexer) {
+                log_error("L2CAP_EVENT_CHANNEL_OPENED but no multiplexer prepared\n");
+                return 1;
+            }
+            if (multiplexer->state == RFCOMM_MULTIPLEXER_W4_CONNECT) {
+                log_info("L2CAP_EVENT_CHANNEL_OPENED: outgoing connection\n");
+                // wrong remote addr
+                if (BD_ADDR_CMP(event_addr, multiplexer->remote_addr)) break;
+                multiplexer->l2cap_cid = l2cap_cid;
+                multiplexer->con_handle = con_handle;
+                // send SABM #0
+                multiplexer->state = RFCOMM_MULTIPLEXER_SEND_SABM_0;
+            } else { // multiplexer->state == RFCOMM_MULTIPLEXER_W4_SABM_0
+                
+                // set max frame size based on l2cap MTU
+                multiplexer->max_frame_size = rfcomm_max_frame_size_for_l2cap_mtu(READ_BT_16(packet, 17));
+            }
+            return 1;
+            
+            // l2cap disconnect -> state = RFCOMM_MULTIPLEXER_CLOSED;
+            
+        case L2CAP_EVENT_CREDITS:
+            // data: event(8), len(8), local_cid(16), credits(8)
+            l2cap_cid = READ_BT_16(packet, 2);
+            multiplexer = rfcomm_multiplexer_for_l2cap_cid(l2cap_cid);
+            if (!multiplexer) break;
+            multiplexer->l2cap_credits += packet[4];
+            
+            // log_info("L2CAP_EVENT_CREDITS: %u (now %u)\n", packet[4], multiplexer->l2cap_credits);
+
+            // new credits, continue with signaling
+            rfcomm_run();
+            
+            if (multiplexer->state != RFCOMM_MULTIPLEXER_OPEN) break;
+            rfcomm_hand_out_credits();
+            return 1;
+        
+        case DAEMON_EVENT_HCI_PACKET_SENT:
+            // testing DMA done code
+            rfcomm_run();
+            break;
+            
+        case L2CAP_EVENT_CHANNEL_CLOSED:
+            // data: event (8), len(8), channel (16)
+            l2cap_cid = READ_BT_16(packet, 2);
+            multiplexer = rfcomm_multiplexer_for_l2cap_cid(l2cap_cid);
+            if (!multiplexer) break;
+            switch (multiplexer->state) {
+                case RFCOMM_MULTIPLEXER_W4_SABM_0:
+                case RFCOMM_MULTIPLEXER_W4_UA_0:
+                case RFCOMM_MULTIPLEXER_OPEN:
+                    rfcomm_multiplexer_finalize(multiplexer);
+                    return 1;
+                default:
+                    break;
+            }
+            break;
+        default:
+            break;
+    }
+    return 0;
+}
+
+static int rfcomm_multiplexer_l2cap_packet_handler(uint16_t channel, uint8_t *packet, uint16_t size){
+    
+    // get or create a multiplexer for a certain device
+    rfcomm_multiplexer_t *multiplexer = rfcomm_multiplexer_for_l2cap_cid(channel);
+    if (!multiplexer) return 0;
+    
+    // but only care for multiplexer control channel
+    uint8_t frame_dlci = packet[0] >> 2;
+    if (frame_dlci) return 0;
+    const uint8_t length_offset = (packet[2] & 1) ^ 1;  // to be used for pos >= 3
+    const uint8_t credit_offset = ((packet[1] & BT_RFCOMM_UIH_PF) == BT_RFCOMM_UIH_PF) ? 1 : 0;   // credits for uih_pf frames
+    const uint8_t payload_offset = 3 + length_offset + credit_offset;
+    switch (packet[1]){
+            
+        case BT_RFCOMM_SABM:
+            if (multiplexer->state == RFCOMM_MULTIPLEXER_W4_SABM_0){
+                log_info("Received SABM #0\n");
+                multiplexer->outgoing = 0;
+                multiplexer->state = RFCOMM_MULTIPLEXER_SEND_UA_0;
+                return 1;
+            }
+            break;
+            
+        case BT_RFCOMM_UA:
+            if (multiplexer->state == RFCOMM_MULTIPLEXER_W4_UA_0) {
+                // UA #0 -> send UA #0, state = RFCOMM_MULTIPLEXER_OPEN
+                log_info("Received UA #0 \n");
+                rfcomm_multiplexer_opened(multiplexer);
+                return 1;
+            }
+            break;
+            
+        case BT_RFCOMM_DISC:
+            // DISC #0 -> send UA #0, close multiplexer
+            log_info("Received DISC #0, (ougoing = %u)\n", multiplexer->outgoing);
+            multiplexer->state = RFCOMM_MULTIPLEXER_SEND_UA_0_AND_DISC;
+            return 1;
+            
+        case BT_RFCOMM_DM:
+            // DM #0 - we shouldn't get this, just give up
+            log_info("Received DM #0\n");
+            log_info("-> Closing down multiplexer\n");
+            rfcomm_multiplexer_finalize(multiplexer);
+            return 1;
+            
+        case BT_RFCOMM_UIH:
+            if (packet[payload_offset] == BT_RFCOMM_CLD_CMD){
+                // Multiplexer close down (CLD) -> close mutliplexer
+                log_info("Received Multiplexer close down command\n");
+                log_info("-> Closing down multiplexer\n");
+                rfcomm_multiplexer_finalize(multiplexer);
+                return 1;
+            }
+            break;
+            
+        default:
+            break;
+            
+    }
+    return 0;
+}
+
+static void rfcomm_multiplexer_state_machine(rfcomm_multiplexer_t * multiplexer, RFCOMM_MULTIPLEXER_EVENT event){
+    
+    // process stored DM responses
+    if (multiplexer->send_dm_for_dlci){
+        rfcomm_send_dm_pf(multiplexer, multiplexer->send_dm_for_dlci);
+        multiplexer->send_dm_for_dlci = 0;
+    }
+
+    switch (multiplexer->state) {
+        case RFCOMM_MULTIPLEXER_SEND_SABM_0:
+            switch (event) {
+                case MULT_EV_READY_TO_SEND:
+                    log_info("Sending SABM #0 - (multi 0x%p)\n", multiplexer);
+                    multiplexer->state = RFCOMM_MULTIPLEXER_W4_UA_0;
+                    rfcomm_send_sabm(multiplexer, 0);
+                    break;
+                default:
+                    break;
+            }
+            break;
+        case RFCOMM_MULTIPLEXER_SEND_UA_0:
+            switch (event) {
+                case MULT_EV_READY_TO_SEND:
+                    log_info("Sending UA #0\n");
+                    multiplexer->state = RFCOMM_MULTIPLEXER_OPEN;
+                    rfcomm_send_ua(multiplexer, 0);
+                    rfcomm_multiplexer_opened(multiplexer);
+                    break;
+                default:
+                    break;
+            }
+            break;
+        case RFCOMM_MULTIPLEXER_SEND_UA_0_AND_DISC:
+            switch (event) {
+                case MULT_EV_READY_TO_SEND:
+                    log_info("Sending UA #0\n");
+                    log_info("Closing down multiplexer\n");
+                    multiplexer->state = RFCOMM_MULTIPLEXER_CLOSED;
+                    rfcomm_send_ua(multiplexer, 0);
+                    rfcomm_multiplexer_finalize(multiplexer);
+                    // try to detect authentication errors: drop link key if multiplexer closed before first channel got opened
+                    if (!multiplexer->at_least_one_connection){
+                        log_info("TODO: no connections established - delete link key prophylactically\n");
+                        // hci_send_cmd(&hci_delete_stored_link_key, multiplexer->remote_addr);
+                    }
+                default:
+                    break;
+            }
+            break;
+        default:
+            break;
+    }
+}
+
+// MARK: RFCOMM CHANNEL
+
+static void rfcomm_hand_out_credits(void){
+    linked_item_t * it;
+    for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
+        rfcomm_channel_t * channel = (rfcomm_channel_t *) it;
+        if (channel->state != RFCOMM_CHANNEL_OPEN) {
+            // log_info("RFCOMM_EVENT_CREDITS: multiplexer not open\n");
+            continue;
+        }
+        if (channel->packets_granted) {
+            // log_info("RFCOMM_EVENT_CREDITS: already packets granted\n");
+            continue;
+        }
+        if (!channel->credits_outgoing) {
+            // log_info("RFCOMM_EVENT_CREDITS: no outgoing credits\n");
+            continue;
+        }
+        if (!channel->multiplexer->l2cap_credits){
+            // log_info("RFCOMM_EVENT_CREDITS: no l2cap credits\n");
+            continue;
+        }
+        // channel open, multiplexer has l2cap credits and we didn't hand out credit before -> go!
+        // log_info("RFCOMM_EVENT_CREDITS: 1\n");
+        channel->packets_granted += 1;
+        rfcomm_emit_credits(channel, 1);
+    }        
+}
+
+static void rfcomm_channel_send_credits(rfcomm_channel_t *channel, uint8_t credits){
+    rfcomm_send_uih_credits(channel->multiplexer, channel->dlci, credits);
+    channel->credits_incoming += credits;
+    
+    rfcomm_emit_credit_status(channel);
+}
+
+static void rfcomm_channel_opened(rfcomm_channel_t *rfChannel){
+    
+    log_info("rfcomm_channel_opened!\n");
+    
+    rfChannel->state = RFCOMM_CHANNEL_OPEN;
+    rfcomm_emit_channel_opened(rfChannel, 0);
+    rfcomm_hand_out_credits();
+
+    // remove (potential) timer
+    rfcomm_multiplexer_t *multiplexer = rfChannel->multiplexer;
+    if (multiplexer->timer_active) {
+        run_loop_remove_timer(&multiplexer->timer);
+        multiplexer->timer_active = 0;
+    }
+    // hack for problem detecting authentication failure
+    multiplexer->at_least_one_connection = 1;
+    
+    // start next connection request if pending
+    rfcomm_run();
+}
+
+static void rfcomm_channel_packet_handler_uih(rfcomm_multiplexer_t *multiplexer, uint8_t * packet, uint16_t size){
+    const uint8_t frame_dlci = packet[0] >> 2;
+    const uint8_t length_offset = (packet[2] & 1) ^ 1;  // to be used for pos >= 3
+    const uint8_t credit_offset = ((packet[1] & BT_RFCOMM_UIH_PF) == BT_RFCOMM_UIH_PF) ? 1 : 0;   // credits for uih_pf frames
+    const uint8_t payload_offset = 3 + length_offset + credit_offset;
+
+    rfcomm_channel_t * channel = rfcomm_channel_for_multiplexer_and_dlci(multiplexer, frame_dlci);
+    if (!channel) return;
+    
+    // handle new outgoing credits
+    if (packet[1] == BT_RFCOMM_UIH_PF) {
+        
+        // add them
+        uint16_t new_credits = packet[3+length_offset];
+        channel->credits_outgoing += new_credits;
+        log_info( "RFCOMM data UIH_PF, new credits: %u, now %u\n", new_credits, channel->credits_outgoing);
+
+        // notify channel statemachine 
+        rfcomm_channel_event_t channel_event = { CH_EVT_RCVD_CREDITS };
+        rfcomm_channel_state_machine(channel, &channel_event);
+    }
+    
+    // contains payload?
+    if (size - 1 > payload_offset){
+
+        // log_info( "RFCOMM data UIH_PF, size %u, channel %p\n", size-payload_offset-1, rfChannel->connection);
+
+        // decrease incoming credit counter
+        if (channel->credits_incoming > 0){
+            channel->credits_incoming--;
+        }
+        
+        // deliver payload
+        (*app_packet_handler)(channel->connection, RFCOMM_DATA_PACKET, channel->rfcomm_cid,
+                              &packet[payload_offset], size-payload_offset-1);
+    }
+    
+    // automatically provide new credits to remote device, if no incoming flow control
+    if (!channel->incoming_flow_control && channel->credits_incoming < 5){
+        channel->new_credits_incoming = 0x30;
+    }    
+    
+    rfcomm_emit_credit_status(channel);
+    
+    // we received new RFCOMM credits, hand them out if possible
+    rfcomm_hand_out_credits();
+}
+
+static void rfcomm_channel_accept_pn(rfcomm_channel_t *channel, rfcomm_channel_event_pn_t *event){
+    // priority of client request
+    channel->pn_priority = event->priority;
+    
+    // new credits
+    channel->credits_outgoing = event->credits_outgoing;
+    
+    // negotiate max frame size
+    if (channel->max_frame_size > channel->multiplexer->max_frame_size) {
+        channel->max_frame_size = channel->multiplexer->max_frame_size;
+    }
+    if (channel->max_frame_size > event->max_frame_size) {
+        channel->max_frame_size = event->max_frame_size;
+    }
+    
+}
+
+static void rfcomm_channel_finalize(rfcomm_channel_t *channel){
+
+    rfcomm_multiplexer_t *multiplexer = channel->multiplexer;
+
+    // remove from list
+    linked_list_remove( &rfcomm_channels, (linked_item_t *) channel);
+
+    // free channel
+    btstack_memory_rfcomm_channel_free(channel);
+    
+    // update multiplexer timeout after channel was removed from list
+    rfcomm_multiplexer_prepare_idle_timer(multiplexer);
+}
+
+static void rfcomm_channel_state_machine_2(rfcomm_multiplexer_t * multiplexer, uint8_t dlci, rfcomm_channel_event_t *event){
+
+    // TODO: if client max frame size is smaller than RFCOMM_DEFAULT_SIZE, send PN
+
+    
+    // lookup existing channel
+    rfcomm_channel_t * channel = rfcomm_channel_for_multiplexer_and_dlci(multiplexer, dlci);
+
+    // log_info("rfcomm_channel_state_machine_2 lookup dlci #%u = 0x%08x - event %u\n", dlci, (int) channel, event->type);
+
+    if (channel) {
+        rfcomm_channel_state_machine(channel, event);
+        return;
+    }
+    
+    // service registered?
+    rfcomm_service_t * service = rfcomm_service_for_channel(dlci >> 1);
+    // log_info("rfcomm_channel_state_machine_2 service dlci #%u = 0x%08x\n", dlci, (int) service);
+    if (!service) {
+        // discard request by sending disconnected mode
+        multiplexer->send_dm_for_dlci = dlci;
+        return;
+    }
+
+    // create channel for some events
+    switch (event->type) {
+        case CH_EVT_RCVD_SABM:
+        case CH_EVT_RCVD_PN:
+        case CH_EVT_RCVD_RPN_REQ:
+        case CH_EVT_RCVD_RPN_CMD:
+            // setup incoming channel
+            channel = rfcomm_channel_create(multiplexer, service, dlci >> 1);
+            if (!channel){
+                // discard request by sending disconnected mode
+                multiplexer->send_dm_for_dlci = dlci;
+            }
+            break;
+        default:
+            break;
+    }
+
+    if (!channel) {
+        // discard request by sending disconnected mode
+        multiplexer->send_dm_for_dlci = dlci;
+        return;
+    }
+    channel->connection = service->connection;
+    rfcomm_channel_state_machine(channel, event);
+}
+
+void rfcomm_channel_packet_handler(rfcomm_multiplexer_t * multiplexer,  uint8_t *packet, uint16_t size){
+    
+    // rfcomm: (0) addr [76543 server channel] [2 direction: initiator uses 1] [1 C/R: CMD by initiator = 1] [0 EA=1]
+    const uint8_t frame_dlci = packet[0] >> 2;
+    uint8_t message_dlci; // used by commands in UIH(_PF) packets 
+    uint8_t message_len;  //   "
+    
+    // rfcomm: (1) command/control
+    // -- credits_offset = 1 if command == BT_RFCOMM_UIH_PF
+    const uint8_t credit_offset = ((packet[1] & BT_RFCOMM_UIH_PF) == BT_RFCOMM_UIH_PF) ? 1 : 0;   // credits for uih_pf frames
+    // rfcomm: (2) length. if bit 0 is cleared, 2 byte length is used. (little endian)
+    const uint8_t length_offset = (packet[2] & 1) ^ 1;  // to be used for pos >= 3
+    // rfcomm: (3+length_offset) credits if credits_offset == 1
+    // rfcomm: (3+length_offest+credits_offset)
+    const uint8_t payload_offset = 3 + length_offset + credit_offset;
+    
+    rfcomm_channel_event_t event;
+    rfcomm_channel_event_pn_t event_pn;
+    rfcomm_channel_event_rpn_t event_rpn;
+
+    // switch by rfcomm message type
+    switch(packet[1]) {
+            
+        case BT_RFCOMM_SABM:
+            event.type = CH_EVT_RCVD_SABM;
+            log_info("Received SABM #%u\n", frame_dlci);
+            rfcomm_channel_state_machine_2(multiplexer, frame_dlci, &event);
+            break;
+            
+        case BT_RFCOMM_UA:
+            event.type = CH_EVT_RCVD_UA;
+            log_info("Received UA #%u - channel opened\n",frame_dlci);
+            rfcomm_channel_state_machine_2(multiplexer, frame_dlci, &event);
+            break;
+            
+        case BT_RFCOMM_DISC:
+            event.type = CH_EVT_RCVD_DISC;
+            rfcomm_channel_state_machine_2(multiplexer, frame_dlci, &event);
+            break;
+            
+        case BT_RFCOMM_DM:
+        case BT_RFCOMM_DM_PF:
+            event.type = CH_EVT_RCVD_DM;
+            rfcomm_channel_state_machine_2(multiplexer, frame_dlci, &event);
+            break;
+            
+        case BT_RFCOMM_UIH_PF:
+        case BT_RFCOMM_UIH:
+
+            message_len  = packet[payload_offset+1] >> 1;
+
+            switch (packet[payload_offset]) {
+                case BT_RFCOMM_PN_CMD:
+                    message_dlci = packet[payload_offset+2];
+                    event_pn.super.type = CH_EVT_RCVD_PN;
+                    event_pn.priority = packet[payload_offset+4];
+                    event_pn.max_frame_size = READ_BT_16(packet, payload_offset+6);
+                    event_pn.credits_outgoing = packet[payload_offset+9];
+                    log_info("Received UIH Parameter Negotiation Command for #%u\n", message_dlci);
+                    rfcomm_channel_state_machine_2(multiplexer, message_dlci, (rfcomm_channel_event_t*) &event_pn);
+                    break;
+                    
+                case BT_RFCOMM_PN_RSP:
+                    message_dlci = packet[payload_offset+2];
+                    event_pn.super.type = CH_EVT_RCVD_PN_RSP;
+                    event_pn.priority = packet[payload_offset+4];
+                    event_pn.max_frame_size = READ_BT_16(packet, payload_offset+6);
+                    event_pn.credits_outgoing = packet[payload_offset+9];
+                    log_info("UIH Parameter Negotiation Response max frame %u, credits %u\n",
+                            event_pn.max_frame_size, event_pn.credits_outgoing);
+                    rfcomm_channel_state_machine_2(multiplexer, message_dlci, (rfcomm_channel_event_t*) &event_pn);
+                    break;
+                    
+                case BT_RFCOMM_MSC_CMD: 
+                    message_dlci = packet[payload_offset+2] >> 2;
+                    event.type = CH_EVT_RCVD_MSC_CMD;
+                    log_info("Received MSC CMD for #%u, \n", message_dlci);
+                    rfcomm_channel_state_machine_2(multiplexer, message_dlci, &event);
+                    break;
+                    
+                case BT_RFCOMM_MSC_RSP:
+                    message_dlci = packet[payload_offset+2] >> 2;
+                    event.type = CH_EVT_RCVD_MSC_RSP;
+                    log_info("Received MSC RSP for #%u\n", message_dlci);
+                    rfcomm_channel_state_machine_2(multiplexer, message_dlci, &event);
+                    break;
+                    
+                case BT_RFCOMM_RPN_CMD:
+                    message_dlci = packet[payload_offset+2] >> 2;
+                    switch (message_len){
+                        case 1:
+                            log_info("Received Remote Port Negotiation for #%u\n", message_dlci);
+                            event.type = CH_EVT_RCVD_RPN_REQ;
+                            rfcomm_channel_state_machine_2(multiplexer, message_dlci, &event);
+                            break;
+                        case 8:
+                            log_info("Received Remote Port Negotiation (Info) for #%u\n", message_dlci);
+                            event_rpn.super.type = CH_EVT_RCVD_RPN_CMD;
+                            event_rpn.data.baud_rate = packet[payload_offset+3];
+                            event_rpn.data.flags = packet[payload_offset+4];
+                            event_rpn.data.flow_control = packet[payload_offset+5];
+                            event_rpn.data.xon  = packet[payload_offset+6];
+                            event_rpn.data.xoff = packet[payload_offset+7];
+                            event_rpn.data.parameter_mask_0 = packet[payload_offset+8];
+                            event_rpn.data.parameter_mask_1 = packet[payload_offset+9];
+                            rfcomm_channel_state_machine_2(multiplexer, message_dlci, (rfcomm_channel_event_t*) &event_rpn);
+                            break;
+                        default:
+                            break;
+                    }
+                    break;
+                    
+                default:
+                    log_error("Received unknown UIH packet - 0x%02x\n", packet[payload_offset]); 
+                    break;
+            }
+            break;
+            
+        default:
+            log_error("Received unknown RFCOMM message type %x\n", packet[1]);
+            break;
+    }
+    
+    // trigger next action - example W4_PN_RSP: transition to SEND_SABM which only depends on "can send"
+    rfcomm_run();
+}
+
+void rfcomm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
+    
+    // multiplexer handler
+    int handled = 0;
+    switch (packet_type) {
+        case HCI_EVENT_PACKET:
+            handled = rfcomm_multiplexer_hci_event_handler(packet, size);
+            break;
+        case L2CAP_DATA_PACKET:
+            handled = rfcomm_multiplexer_l2cap_packet_handler(channel, packet, size);
+            break;
+        default:
+            break;
+    }
+    
+    if (handled) {
+        rfcomm_run();
+        return;
+    }
+    
+    // we only handle l2cap packet over open multiplexer channel now
+    if (packet_type != L2CAP_DATA_PACKET) {
+        (*app_packet_handler)(NULL, packet_type, channel, packet, size);
+        return;
+    }
+    rfcomm_multiplexer_t * multiplexer = rfcomm_multiplexer_for_l2cap_cid(channel);
+    if (!multiplexer || multiplexer->state != RFCOMM_MULTIPLEXER_OPEN) {
+        (*app_packet_handler)(NULL, packet_type, channel, packet, size);
+        return;
+    }
+    
+    // channel data ?
+    // rfcomm: (0) addr [76543 server channel] [2 direction: initiator uses 1] [1 C/R: CMD by initiator = 1] [0 EA=1]
+    const uint8_t frame_dlci = packet[0] >> 2;
+    
+    if (frame_dlci && (packet[1] == BT_RFCOMM_UIH || packet[1] == BT_RFCOMM_UIH_PF)) {
+        rfcomm_channel_packet_handler_uih(multiplexer, packet, size);
+        rfcomm_run();
+        return;
+    }
+     
+    rfcomm_channel_packet_handler(multiplexer, packet, size);
+}
+
+static int rfcomm_channel_ready_for_open(rfcomm_channel_t *channel){
+    // log_info("rfcomm_channel_ready_for_open state %u, flags needed %04x, current %04x, rf credits %u, l2cap credits %u \n", channel->state, RFCOMM_CHANNEL_STATE_VAR_RCVD_MSC_RSP|RFCOMM_CHANNEL_STATE_VAR_SENT_MSC_RSP|RFCOMM_CHANNEL_STATE_VAR_SENT_CREDITS, channel->state_var, channel->credits_outgoing, channel->multiplexer->l2cap_credits);
+    if ((channel->state_var & RFCOMM_CHANNEL_STATE_VAR_RCVD_MSC_RSP) == 0) return 0;
+    if ((channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SENT_MSC_RSP) == 0) return 0;
+    if ((channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SENT_CREDITS) == 0) return 0;
+    if (channel->credits_outgoing == 0) return 0;
+    
+    return 1;
+}
+
+static void rfcomm_channel_state_machine(rfcomm_channel_t *channel, rfcomm_channel_event_t *event){
+    
+    // log_info("rfcomm_channel_state_machine: state %u, state_var %04x, event %u\n", channel->state, channel->state_var ,event->type);
+    
+    rfcomm_multiplexer_t *multiplexer = channel->multiplexer;
+    
+    // TODO: integrate in common switch
+    if (event->type == CH_EVT_RCVD_DISC){
+        rfcomm_emit_channel_closed(channel);
+        channel->state = RFCOMM_CHANNEL_SEND_UA_AFTER_DISC;
+        return;
+    }
+    
+    // TODO: integrate in common switch
+    if (event->type == CH_EVT_RCVD_DM){
+        log_info("Received DM message for #%u\n", channel->dlci);
+        log_info("-> Closing channel locally for #%u\n", channel->dlci);
+        rfcomm_emit_channel_closed(channel);
+        rfcomm_channel_finalize(channel);
+        return;
+    }
+    
+    // remote port negotiation command - just accept everything for now
+    //
+    // "The RPN command can be used before a new DLC is opened and should be used whenever the port settings change."
+    // "The RPN command is specified as optional in TS 07.10, but it is mandatory to recognize and respond to it in RFCOMM. 
+    //   (Although the handling of individual settings are implementation-dependent.)"
+    //
+    
+    // TODO: integrate in common switch
+    if (event->type == CH_EVT_RCVD_RPN_CMD){
+        // control port parameters
+        rfcomm_channel_event_rpn_t *event_rpn = (rfcomm_channel_event_rpn_t*) event;
+        memcpy(&channel->rpn_data, &event_rpn->data, sizeof(rfcomm_rpn_data_t));
+        channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_RPN_RSP;
+        return;
+    }
+    
+    // TODO: integrate in common switch
+    if (event->type == CH_EVT_RCVD_RPN_REQ){
+        // default rpn rsp
+        rfcomm_rpn_data_t rpn_data;
+        rpn_data.baud_rate = 0xa0;        /* 9600 bps */
+        rpn_data.flags = 0x03;            /* 8-n-1 */
+        rpn_data.flow_control = 0;        /* no flow control */
+        rpn_data.xon  = 0xd1;             /* XON */
+        rpn_data.xoff = 0xd3;             /* XOFF */
+        rpn_data.parameter_mask_0 = 0x7f; /* parameter mask, all values set */
+        rpn_data.parameter_mask_1 = 0x3f; /* parameter mask, all values set */
+        memcpy(&channel->rpn_data, &rpn_data, sizeof(rfcomm_rpn_data_t));
+        channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_RPN_RSP;
+        return;
+    }
+    
+    // TODO: integrate in common swich
+    if (event->type == CH_EVT_READY_TO_SEND){
+        if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SEND_RPN_RSP){
+            log_info("Sending Remote Port Negotiation RSP for #%u\n", channel->dlci);
+            channel->state_var &= ~RFCOMM_CHANNEL_STATE_VAR_SEND_RPN_RSP;
+            rfcomm_send_uih_rpn_rsp(multiplexer, channel->dlci, &channel->rpn_data);
+            return;
+        }
+    }
+    
+    rfcomm_channel_event_pn_t * event_pn = (rfcomm_channel_event_pn_t*) event;
+    
+    switch (channel->state) {
+        case RFCOMM_CHANNEL_CLOSED:
+            switch (event->type){
+                case CH_EVT_RCVD_SABM:
+                    log_info("-> Inform app\n");
+                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_RCVD_SABM;
+                    channel->state = RFCOMM_CHANNEL_INCOMING_SETUP;
+                    rfcomm_emit_connection_request(channel);
+                    break;
+                case CH_EVT_RCVD_PN:
+                    rfcomm_channel_accept_pn(channel, event_pn);
+                    log_info("-> Inform app\n");
+                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_RCVD_PN;
+                    channel->state = RFCOMM_CHANNEL_INCOMING_SETUP;
+                    rfcomm_emit_connection_request(channel);
+                    break;
+                default:
+                    break;
+            }
+            break;
+            
+        case RFCOMM_CHANNEL_INCOMING_SETUP:
+            switch (event->type){
+                case CH_EVT_RCVD_SABM:
+                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_RCVD_SABM;
+                    if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_CLIENT_ACCEPTED) {
+                        channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_UA;
+                    }
+                    break;
+                case CH_EVT_RCVD_PN:
+                    rfcomm_channel_accept_pn(channel, event_pn);
+                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_RCVD_PN;
+                    if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_CLIENT_ACCEPTED) {
+                        channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_PN_RSP;
+                    }
+                    break;
+                case CH_EVT_READY_TO_SEND:
+                    if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SEND_PN_RSP){
+                        log_info("Sending UIH Parameter Negotiation Respond for #%u\n", channel->dlci);
+                        channel->state_var &= ~RFCOMM_CHANNEL_STATE_VAR_SEND_PN_RSP;
+                        rfcomm_send_uih_pn_response(multiplexer, channel->dlci, channel->pn_priority, channel->max_frame_size);
+                    }
+                    else if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SEND_UA){
+                        log_info("Sending UA #%u\n", channel->dlci);
+                        channel->state_var &= ~RFCOMM_CHANNEL_STATE_VAR_SEND_UA;
+                        rfcomm_send_ua(multiplexer, channel->dlci);
+                    }
+                    if ((channel->state_var & RFCOMM_CHANNEL_STATE_VAR_CLIENT_ACCEPTED) && (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_RCVD_SABM)) {
+                        channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_CMD;
+                        channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_CREDITS;
+                        channel->state = RFCOMM_CHANNEL_DLC_SETUP;
+                    } 
+                    break;
+                    
+                default:
+                    break;
+            }
+            break;
+            
+        case RFCOMM_CHANNEL_W4_MULTIPLEXER:
+            switch (event->type) {
+                case CH_EVT_MULTIPLEXER_READY:
+                    log_info("Muliplexer opened, sending UIH PN next\n");
+                    channel->state = RFCOMM_CHANNEL_SEND_UIH_PN;
+                    break;
+                default:
+                    break;
+            }
+            break;
+            
+        case RFCOMM_CHANNEL_SEND_UIH_PN:
+            switch (event->type) {
+                case CH_EVT_READY_TO_SEND:
+                    log_info("Sending UIH Parameter Negotiation Command for #%u (channel 0x%p)\n", channel->dlci, channel );
+                    channel->state = RFCOMM_CHANNEL_W4_PN_RSP;
+                    rfcomm_send_uih_pn_command(multiplexer, channel->dlci, channel->max_frame_size);
+                    break;
+                default:
+                    break;
+            }
+            break;
+            
+        case RFCOMM_CHANNEL_W4_PN_RSP:
+            switch (event->type){
+                case CH_EVT_RCVD_PN_RSP:
+                    // update max frame size
+                    if (channel->max_frame_size > event_pn->max_frame_size) {
+                        channel->max_frame_size = event_pn->max_frame_size;
+                    }
+                    // new credits
+                    channel->credits_outgoing = event_pn->credits_outgoing;
+                    channel->state = RFCOMM_CHANNEL_SEND_SABM_W4_UA;
+                    break;
+                default:
+                    break;
+            }
+            break;
+
+        case RFCOMM_CHANNEL_SEND_SABM_W4_UA:
+            switch (event->type) {
+                case CH_EVT_READY_TO_SEND:
+                    log_info("Sending SABM #%u\n", channel->dlci);
+                    channel->state = RFCOMM_CHANNEL_W4_UA;
+                    rfcomm_send_sabm(multiplexer, channel->dlci);
+                    break;
+                default:
+                    break;
+            }
+            break;
+            
+        case RFCOMM_CHANNEL_W4_UA:
+            switch (event->type){
+                case CH_EVT_RCVD_UA:
+                    channel->state = RFCOMM_CHANNEL_DLC_SETUP;
+                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_CMD;
+                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_CREDITS;
+                    break;
+                default:
+                    break;
+            }
+            break;
+            
+        case RFCOMM_CHANNEL_DLC_SETUP:
+            switch (event->type){
+                case CH_EVT_RCVD_MSC_CMD:
+                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_RCVD_MSC_CMD;
+                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_RSP;
+                    break;
+                case CH_EVT_RCVD_MSC_RSP:
+                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_RCVD_MSC_RSP;
+                    break;
+                    
+                case CH_EVT_READY_TO_SEND:
+                    if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_CMD){
+                        log_info("Sending MSC CMD for #%u\n", channel->dlci);
+                        channel->state_var &= ~RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_CMD;
+                        channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SENT_MSC_CMD;
+                        rfcomm_send_uih_msc_cmd(multiplexer, channel->dlci , 0x8d);  // ea=1,fc=0,rtc=1,rtr=1,ic=0,dv=1
+                        break;
+                    }
+                    if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_RSP){
+                        log_info("Sending MSC RSP for #%u\n", channel->dlci);
+                        channel->state_var &= ~RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_RSP;
+                        channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SENT_MSC_RSP;
+                        rfcomm_send_uih_msc_rsp(multiplexer, channel->dlci, 0x8d);  // ea=1,fc=0,rtc=1,rtr=1,ic=0,dv=1
+                        break;
+                    }
+                    if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SEND_CREDITS){
+                        log_info("Providing credits for #%u\n", channel->dlci);
+                        channel->state_var &= ~RFCOMM_CHANNEL_STATE_VAR_SEND_CREDITS;
+                        channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SENT_CREDITS;
+                        if (channel->new_credits_incoming) {
+                            uint8_t new_credits = channel->new_credits_incoming;
+                            channel->new_credits_incoming = 0;
+                            rfcomm_channel_send_credits(channel, new_credits);
+                        }
+                        break;
+
+                    }
+                    break;
+                default:
+                    break;
+            }
+            // finally done?
+            if (rfcomm_channel_ready_for_open(channel)){
+                channel->state = RFCOMM_CHANNEL_OPEN;
+                rfcomm_channel_opened(channel);
+            }
+            break;
+        
+        case RFCOMM_CHANNEL_OPEN:
+            switch (event->type){
+                case CH_EVT_RCVD_MSC_CMD:
+                    channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_RSP;
+                    break;
+                case CH_EVT_READY_TO_SEND:
+                    if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_RSP){
+                        log_info("Sending MSC RSP for #%u\n", channel->dlci);
+                        channel->state_var &= ~RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_RSP;
+                        rfcomm_send_uih_msc_rsp(multiplexer, channel->dlci, 0x8d);  // ea=1,fc=0,rtc=1,rtr=1,ic=0,dv=1
+                        break;
+                    }
+                    if (channel->new_credits_incoming) {
+                        uint8_t new_credits = channel->new_credits_incoming;
+                        channel->new_credits_incoming = 0;
+                        rfcomm_channel_send_credits(channel, new_credits);
+                        break;
+                    }
+                    break;
+                case CH_EVT_RCVD_CREDITS: {
+                    // notify daemon -> might trigger re-try of parked connections
+                    uint8_t event[1] = { DAEMON_EVENT_NEW_RFCOMM_CREDITS };
+                    (*app_packet_handler)(channel->connection, DAEMON_EVENT_PACKET, channel->rfcomm_cid, event, sizeof(event));
+                    break;
+                }  
+                default:
+                    break;
+            }
+            break;
+            
+        case RFCOMM_CHANNEL_SEND_DM:
+            switch (event->type) {
+                case CH_EVT_READY_TO_SEND:
+                    log_info("Sending DM_PF for #%u\n", channel->dlci);
+                    // don't emit channel closed - channel was never open
+                    channel->state = RFCOMM_CHANNEL_CLOSED;
+                    rfcomm_send_dm_pf(multiplexer, channel->dlci);
+                    rfcomm_channel_finalize(channel);
+                    break;
+                default:
+                    break;
+            }
+            break;
+            
+        case RFCOMM_CHANNEL_SEND_DISC:
+            switch (event->type) {
+                case CH_EVT_READY_TO_SEND:
+                    channel->state = RFCOMM_CHANNEL_CLOSED;
+                    rfcomm_send_disc(multiplexer, channel->dlci);
+                    rfcomm_emit_channel_closed(channel);
+                    rfcomm_channel_finalize(channel);
+                    break;
+                default:
+                    break;
+            }
+            break;
+            
+        case RFCOMM_CHANNEL_SEND_UA_AFTER_DISC:
+            switch (event->type) {
+                case CH_EVT_READY_TO_SEND:
+                    log_info("Sending UA after DISC for #%u\n", channel->dlci);
+                    channel->state = RFCOMM_CHANNEL_CLOSED;
+                    rfcomm_send_ua(multiplexer, channel->dlci);
+                    rfcomm_channel_finalize(channel);
+                    break;
+                default:
+                    break;
+            }
+            break;
+            
+        default:
+            break;
+    }
+}
+
+
+// MARK: RFCOMM RUN
+// process outstanding signaling tasks
+static void rfcomm_run(void){
+    
+    linked_item_t *it;
+    linked_item_t *next;
+    
+    for (it = (linked_item_t *) rfcomm_multiplexers; it ; it = next){
+
+        next = it->next;    // be prepared for removal of channel in state machine
+        
+        rfcomm_multiplexer_t * multiplexer = ((rfcomm_multiplexer_t *) it);
+        
+        if (!l2cap_can_send_packet_now(multiplexer->l2cap_cid)) {
+            // log_info("rfcomm_run cannot send l2cap packet for #%u, credits %u\n", multiplexer->l2cap_cid, multiplexer->l2cap_credits);
+            continue;
+        }
+        // log_info("rfcomm_run: multi 0x%08x, state %u\n", (int) multiplexer, multiplexer->state);
+
+        rfcomm_multiplexer_state_machine(multiplexer, MULT_EV_READY_TO_SEND);
+    }
+
+    for (it = (linked_item_t *) rfcomm_channels; it ; it = next){
+
+        next = it->next;    // be prepared for removal of channel in state machine
+
+        rfcomm_channel_t * channel = ((rfcomm_channel_t *) it);
+        rfcomm_multiplexer_t * multiplexer = channel->multiplexer;
+        
+        if (!l2cap_can_send_packet_now(multiplexer->l2cap_cid)) continue;
+     
+        rfcomm_channel_event_t event = { CH_EVT_READY_TO_SEND };
+        rfcomm_channel_state_machine(channel, &event);
+    }
+}
+
+// MARK: RFCOMM BTstack API
+
+void rfcomm_init(void){
+    rfcomm_client_cid_generator = 0;
+    rfcomm_multiplexers = NULL;
+    rfcomm_services     = NULL;
+    rfcomm_channels     = NULL;
+}
+
+// register packet handler
+void rfcomm_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type,
+                                                    uint16_t channel, uint8_t *packet, uint16_t size)){
+    app_packet_handler = handler;
+}
+
+// send packet over specific channel
+int rfcomm_send_internal(uint16_t rfcomm_cid, uint8_t *data, uint16_t len){
+
+    rfcomm_channel_t * channel = rfcomm_channel_for_rfcomm_cid(rfcomm_cid);
+    if (!channel){
+        log_error("rfcomm_send_internal cid %u doesn't exist!\n", rfcomm_cid);
+        return 0;
+    }
+    
+    if (!channel->credits_outgoing){
+        log_info("rfcomm_send_internal cid %u, no rfcomm outgoing credits!\n", rfcomm_cid);
+        return RFCOMM_NO_OUTGOING_CREDITS;
+    }
+
+    if (!channel->packets_granted){
+        log_info("rfcomm_send_internal cid %u, no rfcomm credits granted!\n", rfcomm_cid);
+        return RFCOMM_NO_OUTGOING_CREDITS;
+    }
+    
+    // log_info("rfcomm_send_internal: len %u... outgoing credits %u, l2cap credit %us, granted %u\n",
+    //        len, channel->credits_outgoing, channel->multiplexer->l2cap_credits, channel->packets_granted);
+    
+
+    // send might cause l2cap to emit new credits, update counters first
+    channel->credits_outgoing--;
+    int packets_granted_decreased = 0;
+    if (channel->packets_granted) {
+        channel->packets_granted--;
+        packets_granted_decreased++;
+    }
+    
+    int result = rfcomm_send_uih_data(channel->multiplexer, channel->dlci, data, len);
+    
+    if (result != 0) {
+        channel->credits_outgoing++;
+        channel->packets_granted += packets_granted_decreased;
+        log_info("rfcomm_send_internal: error %d\n", result);
+        return result;
+    }
+    
+    // log_info("rfcomm_send_internal: now outgoing credits %u, l2cap credit %us, granted %u\n",
+    //        channel->credits_outgoing, channel->multiplexer->l2cap_credits, channel->packets_granted);
+
+    rfcomm_hand_out_credits();
+    
+    return result;
+}
+
+void rfcomm_create_channel2(void * connection, bd_addr_t *addr, uint8_t server_channel, uint8_t incoming_flow_control, uint8_t initial_credits){
+    log_info("rfcomm_create_channel_internal to %s, at channel #%02x, flow control %u, init credits %u\n",  bd_addr_to_str(*addr), server_channel,
+             incoming_flow_control, initial_credits);
+    
+    // create new multiplexer if necessary
+    rfcomm_multiplexer_t * multiplexer = rfcomm_multiplexer_for_addr(addr);
+    if (!multiplexer) {
+        multiplexer = rfcomm_multiplexer_create_for_addr(addr);
+        if (!multiplexer){
+            rfcomm_emit_channel_open_failed_outgoing_memory(connection, addr, server_channel);
+            return;
+        }
+        multiplexer->outgoing = 1;
+        multiplexer->state = RFCOMM_MULTIPLEXER_W4_CONNECT;
+    }
+    
+    // prepare channel
+    rfcomm_channel_t * channel = rfcomm_channel_create(multiplexer, NULL, server_channel);
+    if (!channel){
+        rfcomm_emit_channel_open_failed_outgoing_memory(connection, addr, server_channel);
+        return;
+    }
+    channel->connection = connection;
+    channel->incoming_flow_control = incoming_flow_control;
+    channel->new_credits_incoming  = initial_credits;
+    
+    // start multiplexer setup
+    if (multiplexer->state != RFCOMM_MULTIPLEXER_OPEN) {
+        
+        channel->state = RFCOMM_CHANNEL_W4_MULTIPLEXER;
+        
+        l2cap_create_channel_internal(connection, rfcomm_packet_handler, *addr, PSM_RFCOMM, l2cap_max_mtu());
+        
+        return;
+    }
+    
+    channel->state = RFCOMM_CHANNEL_SEND_UIH_PN;
+    
+    // start connecting, if multiplexer is already up and running
+    rfcomm_run();
+}
+
+void rfcomm_create_channel_with_initial_credits_internal(void * connection, bd_addr_t *addr, uint8_t server_channel, uint8_t initial_credits){
+    rfcomm_create_channel2(connection, addr, server_channel, 1, initial_credits);
+}
+
+void rfcomm_create_channel_internal(void * connection, bd_addr_t *addr, uint8_t server_channel){
+    rfcomm_create_channel2(connection, addr, server_channel, 0, 0x30);
+}
+
+void rfcomm_disconnect_internal(uint16_t rfcomm_cid){
+    rfcomm_channel_t * channel = rfcomm_channel_for_rfcomm_cid(rfcomm_cid);
+    if (channel) {
+        channel->state = RFCOMM_CHANNEL_SEND_DISC;
+    }
+    
+    // process
+    rfcomm_run();
+}
+
+
+void rfcomm_register_service2(void * connection, uint8_t channel, uint16_t max_frame_size, uint8_t incoming_flow_control, uint8_t initial_credits){
+    // check if already registered
+    rfcomm_service_t * service = rfcomm_service_for_channel(channel);
+    if (service){
+        rfcomm_emit_service_registered(connection, RFCOMM_CHANNEL_ALREADY_REGISTERED, channel);
+        return;
+    }
+    
+    // alloc structure
+    service = (rfcomm_service_t*)btstack_memory_rfcomm_service_get();
+    if (!service) {
+        rfcomm_emit_service_registered(connection, BTSTACK_MEMORY_ALLOC_FAILED, channel);
+        return;
+    }
+    
+    // register with l2cap if not registered before, max MTU
+    if (linked_list_empty(&rfcomm_services)){
+        l2cap_register_service_internal(NULL, rfcomm_packet_handler, PSM_RFCOMM, 0xffff);
+    }
+    
+    // fill in 
+    service->connection     = connection;
+    service->server_channel = channel;
+    service->max_frame_size = max_frame_size;
+    service->incoming_flow_control = incoming_flow_control;
+    service->incoming_initial_credits = initial_credits;
+    
+    // add to services list
+    linked_list_add(&rfcomm_services, (linked_item_t *) service);
+    
+    // done
+    rfcomm_emit_service_registered(connection, 0, channel);
+}
+
+void rfcomm_register_service_with_initial_credits_internal(void * connection, uint8_t channel, uint16_t max_frame_size, uint8_t initial_credits){
+    rfcomm_register_service2(connection, channel, max_frame_size, 1, initial_credits);
+}
+
+void rfcomm_register_service_internal(void * connection, uint8_t channel, uint16_t max_frame_size){
+    rfcomm_register_service2(connection, channel, max_frame_size, 0, 0x30);
+}
+
+void rfcomm_unregister_service_internal(uint8_t service_channel){
+    rfcomm_service_t *service = rfcomm_service_for_channel(service_channel);
+    if (!service) return;
+    linked_list_remove(&rfcomm_services, (linked_item_t *) service);
+    btstack_memory_rfcomm_service_free(service);
+    
+    // unregister if no services active
+    if (linked_list_empty(&rfcomm_services)){
+        // bt_send_cmd(&l2cap_unregister_service, PSM_RFCOMM);
+        l2cap_unregister_service_internal(NULL, PSM_RFCOMM);
+    }
+}
+
+void rfcomm_accept_connection_internal(uint16_t rfcomm_cid){
+    log_info("Received Accept Connction\n");
+    rfcomm_channel_t * channel = rfcomm_channel_for_rfcomm_cid(rfcomm_cid);
+    if (!channel) return;
+    switch (channel->state) {
+        case RFCOMM_CHANNEL_INCOMING_SETUP:
+            channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_CLIENT_ACCEPTED;
+            if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_RCVD_PN){
+                channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_PN_RSP;
+            }
+            if (channel->state_var & RFCOMM_CHANNEL_STATE_VAR_RCVD_SABM){
+                channel->state_var |= RFCOMM_CHANNEL_STATE_VAR_SEND_UA;
+            }
+            break;
+        default:
+            break;
+    }
+
+    // process
+    rfcomm_run();
+}
+
+void rfcomm_decline_connection_internal(uint16_t rfcomm_cid){
+    log_info("Received Decline Connction\n");
+    rfcomm_channel_t * channel = rfcomm_channel_for_rfcomm_cid(rfcomm_cid);
+    if (!channel) return;
+    switch (channel->state) {
+        case RFCOMM_CHANNEL_INCOMING_SETUP:
+            channel->state = RFCOMM_CHANNEL_SEND_DM;
+            break;
+        default:
+            break;
+    }
+
+    // process
+    rfcomm_run();
+}
+
+void rfcomm_grant_credits(uint16_t rfcomm_cid, uint8_t credits){
+    rfcomm_channel_t * channel = rfcomm_channel_for_rfcomm_cid(rfcomm_cid);
+    if (!channel) return;
+    if (!channel->incoming_flow_control) return;
+    channel->new_credits_incoming += credits;
+
+    // process
+    rfcomm_run();
+}
+
+//
+void rfcomm_close_connection(void *connection){
+    linked_item_t *it;
+    
+    // close open channels
+    for (it = (linked_item_t *) rfcomm_channels; it ; it = it->next){
+        rfcomm_channel_t * channel = (rfcomm_channel_t *)it;
+        if (channel->connection != connection) continue;
+        channel->state = RFCOMM_CHANNEL_SEND_DISC;
+    }
+    
+    // unregister services
+    it = (linked_item_t *) &rfcomm_services;
+    while (it->next) {
+        rfcomm_service_t * service = (rfcomm_service_t *) it->next;
+        if (service->connection == connection){
+            it->next = it->next->next;
+            btstack_memory_rfcomm_service_free(service);
+        } else {
+            it = it->next;
+        }
+    }
+
+    // process
+    rfcomm_run();
+}
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/rfcomm.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  RFCOMM.h
+ */
+
+#include <btstack/btstack.h>
+#include <btstack/utils.h>
+
+#include <stdint.h>
+
+#if defined __cplusplus
+extern "C" {
+#endif
+    
+void rfcomm_init(void);
+
+// register packet handler
+void rfcomm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
+void rfcomm_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type,
+                                                    uint16_t channel, uint8_t *packet, uint16_t size));
+
+// BTstack Internal RFCOMM API
+void rfcomm_create_channel_internal(void * connection, bd_addr_t *addr, uint8_t channel);
+void rfcomm_create_channel_with_initial_credits_internal(void * connection, bd_addr_t *addr, uint8_t server_channel, uint8_t initial_credits);
+void rfcomm_disconnect_internal(uint16_t rfcomm_cid);
+void rfcomm_register_service_internal(void * connection, uint8_t channel, uint16_t max_frame_size);
+void rfcomm_register_service_with_initial_credits_internal(void * connection, uint8_t channel, uint16_t max_frame_size, uint8_t initial_credits);
+void rfcomm_unregister_service_internal(uint8_t service_channel);
+void rfcomm_accept_connection_internal(uint16_t rfcomm_cid);
+void rfcomm_decline_connection_internal(uint16_t rfcomm_cid);
+void rfcomm_grant_credits(uint16_t rfcomm_cid, uint8_t credits);
+int  rfcomm_send_internal(uint16_t rfcomm_cid, uint8_t *data, uint16_t len);
+void rfcomm_close_connection(void *connection);
+
+#define UNLIMITED_INCOMING_CREDITS 0xff
+
+// private structs
+typedef enum {
+    RFCOMM_MULTIPLEXER_CLOSED = 1,
+    RFCOMM_MULTIPLEXER_W4_CONNECT,  // outgoing
+    RFCOMM_MULTIPLEXER_SEND_SABM_0,     //    "
+    RFCOMM_MULTIPLEXER_W4_UA_0,     //    "
+    RFCOMM_MULTIPLEXER_W4_SABM_0,   // incoming
+    RFCOMM_MULTIPLEXER_SEND_UA_0,
+    RFCOMM_MULTIPLEXER_OPEN,
+    RFCOMM_MULTIPLEXER_SEND_UA_0_AND_DISC
+} RFCOMM_MULTIPLEXER_STATE;
+
+typedef enum {
+    MULT_EV_READY_TO_SEND = 1,
+    
+} RFCOMM_MULTIPLEXER_EVENT;
+
+typedef enum {
+    RFCOMM_CHANNEL_CLOSED = 1,
+    RFCOMM_CHANNEL_W4_MULTIPLEXER,
+    RFCOMM_CHANNEL_SEND_UIH_PN,
+    RFCOMM_CHANNEL_W4_PN_RSP,
+    RFCOMM_CHANNEL_SEND_SABM_W4_UA,
+    RFCOMM_CHANNEL_W4_UA,
+    RFCOMM_CHANNEL_INCOMING_SETUP,
+    RFCOMM_CHANNEL_DLC_SETUP,
+    RFCOMM_CHANNEL_OPEN,
+    RFCOMM_CHANNEL_SEND_UA_AFTER_DISC,
+    RFCOMM_CHANNEL_SEND_DISC,
+    RFCOMM_CHANNEL_SEND_DM,
+    
+} RFCOMM_CHANNEL_STATE;
+
+/*
+typedef enum {
+    RFCOMM_CHANNEL_STATE_VAR_NONE            = 0,
+    RFCOMM_CHANNEL_STATE_VAR_CLIENT_ACCEPTED = 1 << 0,
+    RFCOMM_CHANNEL_STATE_VAR_RCVD_PN         = 1 << 1,
+    RFCOMM_CHANNEL_STATE_VAR_RCVD_RPN        = 1 << 2,
+    RFCOMM_CHANNEL_STATE_VAR_RCVD_SABM       = 1 << 3,
+    
+    RFCOMM_CHANNEL_STATE_VAR_RCVD_MSC_CMD    = 1 << 4,
+    RFCOMM_CHANNEL_STATE_VAR_RCVD_MSC_RSP    = 1 << 5,
+    RFCOMM_CHANNEL_STATE_VAR_SEND_PN_RSP     = 1 << 6,
+    RFCOMM_CHANNEL_STATE_VAR_SEND_RPN_INFO   = 1 << 7,
+    
+    RFCOMM_CHANNEL_STATE_VAR_SEND_RPN_RSP    = 1 << 8,
+    RFCOMM_CHANNEL_STATE_VAR_SEND_UA         = 1 << 9,
+    RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_CMD    = 1 << 10,
+    RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_RSP    = 1 << 11,
+    
+    RFCOMM_CHANNEL_STATE_VAR_SEND_CREDITS    = 1 << 12,
+    RFCOMM_CHANNEL_STATE_VAR_SENT_MSC_CMD    = 1 << 13,
+    RFCOMM_CHANNEL_STATE_VAR_SENT_MSC_RSP    = 1 << 14,
+    RFCOMM_CHANNEL_STATE_VAR_SENT_CREDITS    = 1 << 15,
+} RFCOMM_CHANNEL_STATE_VAR;
+*/
+
+enum {
+    RFCOMM_CHANNEL_STATE_VAR_NONE            = 0,
+    RFCOMM_CHANNEL_STATE_VAR_CLIENT_ACCEPTED = 1 << 0,
+    RFCOMM_CHANNEL_STATE_VAR_RCVD_PN         = 1 << 1,
+    RFCOMM_CHANNEL_STATE_VAR_RCVD_RPN        = 1 << 2,
+    RFCOMM_CHANNEL_STATE_VAR_RCVD_SABM       = 1 << 3,
+    
+    RFCOMM_CHANNEL_STATE_VAR_RCVD_MSC_CMD    = 1 << 4,
+    RFCOMM_CHANNEL_STATE_VAR_RCVD_MSC_RSP    = 1 << 5,
+    RFCOMM_CHANNEL_STATE_VAR_SEND_PN_RSP     = 1 << 6,
+    RFCOMM_CHANNEL_STATE_VAR_SEND_RPN_INFO   = 1 << 7,
+    
+    RFCOMM_CHANNEL_STATE_VAR_SEND_RPN_RSP    = 1 << 8,
+    RFCOMM_CHANNEL_STATE_VAR_SEND_UA         = 1 << 9,
+    RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_CMD    = 1 << 10,
+    RFCOMM_CHANNEL_STATE_VAR_SEND_MSC_RSP    = 1 << 11,
+    
+    RFCOMM_CHANNEL_STATE_VAR_SEND_CREDITS    = 1 << 12,
+    RFCOMM_CHANNEL_STATE_VAR_SENT_MSC_CMD    = 1 << 13,
+    RFCOMM_CHANNEL_STATE_VAR_SENT_MSC_RSP    = 1 << 14,
+    RFCOMM_CHANNEL_STATE_VAR_SENT_CREDITS    = 1 << 15,
+};
+typedef uint16_t RFCOMM_CHANNEL_STATE_VAR;
+
+typedef enum {
+    CH_EVT_RCVD_SABM = 1,
+    CH_EVT_RCVD_UA,
+    CH_EVT_RCVD_PN,
+    CH_EVT_RCVD_PN_RSP,
+    CH_EVT_RCVD_DISC,
+    CH_EVT_RCVD_DM,
+    CH_EVT_RCVD_MSC_CMD,
+    CH_EVT_RCVD_MSC_RSP,
+    CH_EVT_RCVD_RPN_CMD,
+    CH_EVT_RCVD_RPN_REQ,
+    CH_EVT_RCVD_CREDITS,
+    CH_EVT_MULTIPLEXER_READY,
+    CH_EVT_READY_TO_SEND,
+} RFCOMM_CHANNEL_EVENT;
+
+typedef struct rfcomm_channel_event {
+    RFCOMM_CHANNEL_EVENT type;
+} rfcomm_channel_event_t;
+
+typedef struct rfcomm_channel_event_pn {
+    rfcomm_channel_event_t super;
+    uint16_t max_frame_size;
+    uint8_t  priority;
+    uint8_t  credits_outgoing;
+} rfcomm_channel_event_pn_t;
+
+typedef struct rfcomm_rpn_data {
+    uint8_t baud_rate;
+    uint8_t flags;
+    uint8_t flow_control;
+    uint8_t xon;
+    uint8_t xoff;
+    uint8_t parameter_mask_0;   // first byte
+    uint8_t parameter_mask_1;   // second byte
+} rfcomm_rpn_data_t;
+
+typedef struct rfcomm_channel_event_rpn {
+    rfcomm_channel_event_t super;
+    rfcomm_rpn_data_t data;
+} rfcomm_channel_event_rpn_t;
+
+// info regarding potential connections
+typedef struct {
+    // linked list - assert: first field
+    linked_item_t    item;
+    
+    // server channel
+    uint8_t server_channel;
+    
+    // incoming max frame size
+    uint16_t max_frame_size;
+
+    // use incoming flow control
+    uint8_t incoming_flow_control;
+    
+    // initial incoming credits
+    uint8_t incoming_initial_credits;
+    
+    // client connection
+    void *connection;    
+    
+    // internal connection
+    btstack_packet_handler_t packet_handler;
+    
+} rfcomm_service_t;
+
+// info regarding multiplexer
+// note: spec mandates single multplexer per device combination
+typedef struct {
+    // linked list - assert: first field
+    linked_item_t    item;
+    
+    timer_source_t   timer;
+    int              timer_active;
+    
+    RFCOMM_MULTIPLEXER_STATE state;    
+    
+    uint16_t  l2cap_cid;
+    uint8_t   l2cap_credits;
+    
+    bd_addr_t remote_addr;
+    hci_con_handle_t con_handle;
+    
+    uint8_t   outgoing;
+    
+    // hack to deal with authentication failure only observed by remote side
+    uint8_t   at_least_one_connection;
+    
+    uint16_t max_frame_size;
+    
+    // send DM for DLCI != 0
+    uint8_t send_dm_for_dlci;
+    
+} rfcomm_multiplexer_t;
+
+// info regarding an actual coneection
+typedef struct {
+    // linked list - assert: first field
+    linked_item_t    item;
+    
+    rfcomm_multiplexer_t *multiplexer;
+    uint16_t rfcomm_cid;
+    uint8_t  outgoing;
+    uint8_t  dlci; 
+    
+    // number of packets granted to client
+    uint8_t packets_granted;
+
+    // credits for outgoing traffic
+    uint8_t credits_outgoing;
+    
+    // number of packets remote will be granted
+    uint8_t new_credits_incoming;
+
+    // credits for incoming traffic
+    uint8_t credits_incoming;
+    
+    // use incoming flow control
+    uint8_t incoming_flow_control;
+    
+    // channel state
+    RFCOMM_CHANNEL_STATE state;
+    
+    // state variables used in RFCOMM_CHANNEL_INCOMING
+    RFCOMM_CHANNEL_STATE_VAR state_var;
+    
+    // priority set by incoming side in PN
+    uint8_t pn_priority;
+    
+    // negotiated frame size
+    uint16_t max_frame_size;
+    
+    // rpn data
+    rfcomm_rpn_data_t rpn_data;
+    
+    // server channel (see rfcomm_service_t) - NULL => outgoing channel
+    rfcomm_service_t * service;
+    
+    // internal connection
+    btstack_packet_handler_t packet_handler;
+    
+    // client connection
+    void * connection;
+    
+} rfcomm_channel_t;
+
+
+#if defined __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/run_loop.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  run_loop.c
+ *
+ *  Created by Matthias Ringwald on 6/6/09.
+ */
+
+#include <btstack/run_loop.h>
+
+#include <stdio.h>
+#include <stdlib.h>  // exit()
+
+#include "run_loop_private.h"
+
+#include "debug.h"
+#include "config.h"
+
+static run_loop_t * the_run_loop = NULL;
+
+extern const run_loop_t run_loop_embedded;
+
+#ifdef USE_POSIX_RUN_LOOP
+extern run_loop_t run_loop_posix;
+#endif
+
+#ifdef USE_COCOA_RUN_LOOP
+extern run_loop_t run_loop_cocoa;
+#endif
+
+// assert run loop initialized
+void run_loop_assert(void){
+#ifndef EMBEDDED
+    if (!the_run_loop){
+        log_error("ERROR: run_loop function called before run_loop_init!\n");
+        exit(10);
+    }
+#endif
+}
+
+/**
+ * Add data_source to run_loop
+ */
+void run_loop_add_data_source(data_source_t *ds){
+    run_loop_assert();
+    the_run_loop->add_data_source(ds);
+}
+
+/**
+ * Remove data_source from run loop
+ */
+int run_loop_remove_data_source(data_source_t *ds){
+    run_loop_assert();
+    return the_run_loop->remove_data_source(ds);
+}
+
+/**
+ * Add timer to run_loop (keep list sorted)
+ */
+void run_loop_add_timer(timer_source_t *ts){
+    run_loop_assert();
+    the_run_loop->add_timer(ts);
+}
+
+/**
+ * Remove timer from run loop
+ */
+int run_loop_remove_timer(timer_source_t *ts){
+    run_loop_assert();
+    return the_run_loop->remove_timer(ts);
+}
+
+void run_loop_timer_dump(){
+    run_loop_assert();
+    the_run_loop->dump_timer();
+}
+
+/**
+ * Execute run_loop
+ */
+void run_loop_execute() {
+    run_loop_assert();
+    the_run_loop->execute();
+}
+
+// init must be called before any other run_loop call
+void run_loop_init(RUN_LOOP_TYPE type){
+#ifndef EMBEDDED
+    if (the_run_loop){
+        log_error("ERROR: run loop initialized twice!\n");
+        exit(10);
+    }
+#endif
+    switch (type) {
+#ifdef EMBEDDED
+        case RUN_LOOP_EMBEDDED:
+            the_run_loop = (run_loop_t*) &run_loop_embedded;
+            break;
+#endif
+#ifdef USE_POSIX_RUN_LOOP
+        case RUN_LOOP_POSIX:
+            the_run_loop = &run_loop_posix;
+            break;
+#endif
+#ifdef USE_COCOA_RUN_LOOP
+        case RUN_LOOP_COCOA:
+            the_run_loop = &run_loop_cocoa;
+            break;
+#endif
+        default:
+#ifndef EMBEDDED
+            log_error("ERROR: invalid run loop type %u selected!\n", type);
+            exit(10);
+#endif
+            break;
+    }
+    the_run_loop->init();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/run_loop.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2009 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ *  run_loop.h
+ *
+ *  Created by Matthias Ringwald on 6/6/09.
+ */
+
+#pragma once
+
+#include "config.h"
+
+#include <btstack/linked_list.h>
+
+#include <stdint.h>
+
+#ifdef HAVE_TIME
+#include <sys/time.h>
+#endif
+
+#if defined __cplusplus
+extern "C" {
+#endif
+    
+typedef enum {
+    RUN_LOOP_POSIX = 1,
+    RUN_LOOP_COCOA,
+    RUN_LOOP_EMBEDDED
+} RUN_LOOP_TYPE;
+
+typedef struct data_source {
+    linked_item_t item;
+    int  fd;                                 // <-- file descriptor to watch or 0
+    int  (*process)(struct data_source *ds); // <-- do processing
+} data_source_t;
+
+typedef struct timer {
+    linked_item_t item; 
+#ifdef HAVE_TIME
+    struct timeval timeout;                  // <-- next timeout
+#endif
+#ifdef HAVE_TICK
+    uint32_t timeout;                       // timeout in system ticks
+#endif
+    void  (*process)(struct timer *ts);      // <-- do processing
+} timer_source_t;
+
+
+// set timer based on current time
+void run_loop_set_timer(timer_source_t *a, uint32_t timeout_in_ms);
+
+// add/remove timer_source
+void run_loop_add_timer(timer_source_t *timer); 
+int  run_loop_remove_timer(timer_source_t *timer);
+
+// init must be called before any other run_loop call
+void run_loop_init(RUN_LOOP_TYPE type);
+
+// add/remove data_source
+void run_loop_add_data_source(data_source_t *dataSource);
+int  run_loop_remove_data_source(data_source_t *dataSource);
+
+
+// execute configured run_loop
+void run_loop_execute(void);
+
+// hack to fix HCI timer handling
+#ifdef HAVE_TICK
+uint32_t embedded_get_ticks(void);
+uint32_t embedded_ticks_for_ms(uint32_t time_in_ms);
+#endif
+#ifdef EMBEDDED
+void     embedded_trigger(void);    
+#endif
+#if defined __cplusplus
+}
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/run_loop_embedded.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  run_loop_embedded.c
+ *
+ *  For this run loop, we assume that there's no global way to wait for a list
+ *  of data sources to get ready. Instead, each data source has to queried
+ *  individually. Calling ds->isReady() before calling ds->process() doesn't 
+ *  make sense, so we just poll each data source round robin.
+ *
+ *  To support an idle state, where an MCU could go to sleep, the process function
+ *  has to return if it has to called again as soon as possible
+ *
+ *  After calling process() on every data source and evaluating the pending timers,
+ *  the idle hook gets called if no data source did indicate that it needs to be
+ *  called right away.
+ *
+ */
+
+
+#include <btstack/run_loop.h>
+#include <btstack/linked_list.h>
+#include <btstack/hal_tick.h>
+#include <btstack/hal_cpu.h>
+
+#include "run_loop_private.h"
+#include "debug.h"
+
+#include <stddef.h> // NULL
+
+// the run loop
+static linked_list_t data_sources;
+
+static linked_list_t timers;
+
+#ifdef HAVE_TICK
+static uint32_t system_ticks;
+#endif
+
+static int trigger_event_received = 0;
+
+/**
+ * trigger run loop iteration
+ */
+void embedded_trigger(void){
+    trigger_event_received = 1;
+}
+
+/**
+ * Add data_source to run_loop
+ */
+void embedded_add_data_source(data_source_t *ds){
+    linked_list_add(&data_sources, (linked_item_t *) ds);
+}
+
+/**
+ * Remove data_source from run loop
+ */
+int embedded_remove_data_source(data_source_t *ds){
+    return linked_list_remove(&data_sources, (linked_item_t *) ds);
+}
+
+/**
+ * Add timer to run_loop (keep list sorted)
+ */
+void embedded_add_timer(timer_source_t *ts){
+#ifdef HAVE_TICK
+    linked_item_t *it;
+    for (it = (linked_item_t *) &timers; it->next ; it = it->next){
+        if (ts->timeout < ((timer_source_t *) it->next)->timeout) {
+            break;
+        }
+    }
+    ts->item.next = it->next;
+    it->next = (linked_item_t *) ts;
+    // log_info("Added timer %x at %u\n", (int) ts, (unsigned int) ts->timeout.tv_sec);
+    // embedded_dump_timer();
+#endif
+}
+
+/**
+ * Remove timer from run loop
+ */
+int embedded_remove_timer(timer_source_t *ts){
+#ifdef HAVE_TICK    
+    // log_info("Removed timer %x at %u\n", (int) ts, (unsigned int) ts->timeout.tv_sec);
+    return linked_list_remove(&timers, (linked_item_t *) ts);
+#else
+    return 0;
+#endif
+}
+
+void embedded_dump_timer(void){
+#ifdef HAVE_TICK
+#ifdef ENABLE_LOG_INFO 
+    linked_item_t *it;
+    int i = 0;
+    for (it = (linked_item_t *) timers; it ; it = it->next){
+        timer_source_t *ts = (timer_source_t*) it;
+        log_info("timer %u, timeout %u\n", i, (unsigned int) ts->timeout);
+    }
+#endif
+#endif
+}
+
+/**
+ * Execute run_loop
+ */
+void embedded_execute(void) {
+    data_source_t *ds;
+
+    while (1) {
+
+        // process data sources
+        data_source_t *next;
+        for (ds = (data_source_t *) data_sources; ds != NULL ; ds = next){
+            next = (data_source_t *) ds->item.next; // cache pointer to next data_source to allow data source to remove itself
+            ds->process(ds);
+        }
+        
+#ifdef HAVE_TICK
+        // process timers
+        while (timers) {
+            timer_source_t *ts = (timer_source_t *) timers;
+            if (ts->timeout > system_ticks) break;
+            run_loop_remove_timer(ts);
+            ts->process(ts);
+        }
+#endif
+        
+        // disable IRQs and check if run loop iteration has been requested. if not, go to sleep
+        hal_cpu_disable_irqs();
+        if (trigger_event_received){
+            hal_cpu_enable_irqs_and_sleep();
+            continue;
+        }
+        hal_cpu_enable_irqs();
+    }
+}
+
+#ifdef HAVE_TICK
+static void embedded_tick_handler(void){
+    system_ticks++;
+    trigger_event_received = 1;
+}
+
+uint32_t embedded_get_ticks(void){
+    return system_ticks;
+}
+
+uint32_t embedded_ticks_for_ms(uint32_t time_in_ms){
+    return time_in_ms / hal_tick_get_tick_period_in_ms();
+}
+
+// set timer
+void run_loop_set_timer(timer_source_t *ts, uint32_t timeout_in_ms){
+    uint32_t ticks = embedded_ticks_for_ms(timeout_in_ms);
+    if (ticks == 0) ticks++;
+    ts->timeout = system_ticks + ticks; 
+}
+#endif
+
+void embedded_init(void){
+
+    data_sources = NULL;
+
+#ifdef HAVE_TICK
+    timers = NULL;
+    system_ticks = 0;
+    hal_tick_init();
+    hal_tick_set_handler(&embedded_tick_handler);
+#endif
+}
+
+extern const run_loop_t run_loop_embedded;
+const run_loop_t run_loop_embedded = {
+    &embedded_init,
+    &embedded_add_data_source,
+    &embedded_remove_data_source,
+    &embedded_add_timer,
+    &embedded_remove_timer,
+    &embedded_execute,
+    &embedded_dump_timer
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/run_loop_private.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  run_loop_private.h
+ *
+ *  Created by Matthias Ringwald on 6/6/09.
+ */
+
+#pragma once
+
+#include <btstack/run_loop.h>
+
+#ifdef HAVE_TIME
+#include <sys/time.h>
+
+// compare timeval or timers - NULL is assumed to be before the Big Bang
+int run_loop_timeval_compare(struct timeval *a, struct timeval *b);
+int run_loop_timer_compare(timer_source_t *a, timer_source_t *b);
+
+#endif
+
+// 
+void run_loop_timer_dump(void);
+
+// internal use only
+typedef struct {
+    void (*init)(void);
+    void (*add_data_source)(data_source_t *dataSource);
+    int  (*remove_data_source)(data_source_t *dataSource);
+    void (*add_timer)(timer_source_t *timer);
+    int  (*remove_timer)(timer_source_t *timer); 
+    void (*execute)(void);
+    void (*dump_timer)(void);
+} run_loop_t;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/sdp.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,662 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ * Implementation of the Service Discovery Protocol Server 
+ */
+
+#include "sdp.h"
+
+
+#include <stdio.h>
+#include <string.h>
+
+#include <btstack/sdp_util.h>
+
+#include "hci_dump.h"
+#include "l2cap.h"
+
+#include "debug.h"
+
+// max reserved ServiceRecordHandle
+#define maxReservedServiceRecordHandle 0xffff
+
+// max SDP response
+#define SDP_RESPONSE_BUFFER_SIZE (HCI_ACL_BUFFER_SIZE-HCI_ACL_HEADER_SIZE)
+
+static void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
+
+// registered service records
+static linked_list_t sdp_service_records = NULL;
+
+// our handles start after the reserved range
+static uint32_t sdp_next_service_record_handle = maxReservedServiceRecordHandle + 2;
+
+static uint8_t sdp_response_buffer[SDP_RESPONSE_BUFFER_SIZE];
+
+static void (*app_packet_handler)(void * connection, uint8_t packet_type,
+                                  uint16_t channel, uint8_t *packet, uint16_t size) = NULL;
+
+static uint16_t l2cap_cid = 0;
+static uint16_t sdp_response_size = 0;
+
+void sdp_init(){
+    // register with l2cap psm sevices - max MTU
+    l2cap_register_service_internal(NULL, sdp_packet_handler, PSM_SDP, 0xffff);
+}
+
+// register packet handler
+void sdp_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type,
+                                                 uint16_t channel, uint8_t *packet, uint16_t size)){
+    app_packet_handler = handler;
+    l2cap_cid = 0;
+}
+
+uint32_t sdp_get_service_record_handle(uint8_t * record){
+    uint8_t * serviceRecordHandleAttribute = sdp_get_attribute_value_for_attribute_id(record, SDP_ServiceRecordHandle);
+    if (!serviceRecordHandleAttribute) return 0;
+    if (de_get_element_type(serviceRecordHandleAttribute) != DE_UINT) return 0;
+    if (de_get_size_type(serviceRecordHandleAttribute) != DE_SIZE_32) return 0;
+    return READ_NET_32(serviceRecordHandleAttribute, 1); 
+}
+
+// data: event(8), len(8), status(8), service_record_handle(32)
+static void sdp_emit_service_registered(void *connection, uint32_t handle, uint8_t status) {
+    if (!app_packet_handler) return;
+    uint8_t event[7];
+    event[0] = SDP_SERVICE_REGISTERED;
+    event[1] = sizeof(event) - 2;
+    event[2] = status;
+    bt_store_32(event, 3, handle);
+    hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
+    (*app_packet_handler)(connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
+}
+
+service_record_item_t * sdp_get_record_for_handle(uint32_t handle){
+    linked_item_t *it;
+    for (it = (linked_item_t *) sdp_service_records; it ; it = it->next){
+        service_record_item_t * item = (service_record_item_t *) it;
+        if (item->service_record_handle == handle){
+            return item;
+        }
+    }
+    return NULL;
+}
+
+// get next free, unregistered service record handle
+uint32_t sdp_create_service_record_handle(void){
+    uint32_t handle = 0;
+    do {
+        handle = sdp_next_service_record_handle++;
+        if (sdp_get_record_for_handle(handle)) handle = 0;
+    } while (handle == 0);
+    return handle;
+}
+
+#ifdef EMBEDDED
+
+// register service record internally - this special version doesn't copy the record, it should not be freeed
+// pre: AttributeIDs are in ascending order
+// pre: ServiceRecordHandle is first attribute and valid
+// pre: record
+// @returns ServiceRecordHandle or 0 if registration failed
+uint32_t sdp_register_service_internal(void *connection, service_record_item_t * record_item){
+    // get user record handle
+    uint32_t record_handle = record_item->service_record_handle;
+    // get actual record
+    uint8_t *record = record_item->service_record;
+    
+    // check for ServiceRecordHandle attribute, returns pointer or null
+    uint8_t * req_record_handle = sdp_get_attribute_value_for_attribute_id(record, SDP_ServiceRecordHandle);
+    if (!req_record_handle) {
+        log_error("SDP Error - record does not contain ServiceRecordHandle attribute\n");
+        return 0;
+    }
+    
+    // validate service record handle is not in reserved range
+    if (record_handle <= maxReservedServiceRecordHandle) record_handle = 0;
+    
+    // check if already in use
+    if (record_handle) {
+        if (sdp_get_record_for_handle(record_handle)) {
+            record_handle = 0;
+        }
+    }
+    
+    // create new handle if needed
+    if (!record_handle){
+        record_handle = sdp_create_service_record_handle();
+        // Write the handle back into the record too
+        record_item->service_record_handle = record_handle;
+        sdp_set_attribute_value_for_attribute_id(record, SDP_ServiceRecordHandle, record_handle);
+    }
+    
+    // add to linked list
+    linked_list_add(&sdp_service_records, (linked_item_t *) record_item);
+    
+    sdp_emit_service_registered(connection, 0, record_item->service_record_handle);
+    
+    return record_handle;
+}
+
+#else
+
+// AttributeIDList used to remove ServiceRecordHandle
+static const uint8_t removeServiceRecordHandleAttributeIDList[] = { 0x36, 0x00, 0x05, 0x0A, 0x00, 0x01, 0xFF, 0xFF };
+
+// register service record internally - the normal version creates a copy of the record
+// pre: AttributeIDs are in ascending order => ServiceRecordHandle is first attribute if present
+// @returns ServiceRecordHandle or 0 if registration failed
+uint32_t sdp_register_service_internal(void *connection, uint8_t * record){
+
+    // dump for now
+    // printf("Register service record\n");
+    // de_dump_data_element(record);
+    
+    // get user record handle
+    uint32_t record_handle = sdp_get_service_record_handle(record);
+
+    // validate service record handle is not in reserved range
+    if (record_handle <= maxReservedServiceRecordHandle) record_handle = 0;
+    
+    // check if already in use
+    if (record_handle) {
+        if (sdp_get_record_for_handle(record_handle)) {
+            record_handle = 0;
+        }
+    }
+    
+    // create new handle if needed
+    if (!record_handle){
+        record_handle = sdp_create_service_record_handle();
+    }
+    
+    // calculate size of new service record: DES (2 byte len) 
+    // + ServiceRecordHandle attribute (UINT16 UINT32) + size of existing attributes
+    uint16_t recordSize =  3 + (3 + 5) + de_get_data_size(record);
+        
+    // alloc memory for new service_record_item
+    service_record_item_t * newRecordItem = (service_record_item_t *) malloc(recordSize + sizeof(service_record_item_t));
+    if (!newRecordItem) {
+        sdp_emit_service_registered(connection, 0, BTSTACK_MEMORY_ALLOC_FAILED);
+        return 0;
+    }
+    // link new service item to client connection
+    newRecordItem->connection = connection;
+    
+    // set new handle
+    newRecordItem->service_record_handle = record_handle;
+
+    // create updated service record
+    uint8_t * newRecord = (uint8_t *) &(newRecordItem->service_record);
+    
+    // create DES for new record
+    de_create_sequence(newRecord);
+    
+    // set service record handle
+    de_add_number(newRecord, DE_UINT, DE_SIZE_16, 0);
+    de_add_number(newRecord, DE_UINT, DE_SIZE_32, record_handle);
+    
+    // add other attributes
+    sdp_append_attributes_in_attributeIDList(record, (uint8_t *) removeServiceRecordHandleAttributeIDList, 0, recordSize, newRecord);
+    
+    // dump for now
+    // de_dump_data_element(newRecord);
+    // printf("reserved size %u, actual size %u\n", recordSize, de_get_len(newRecord));
+    
+    // add to linked list
+    linked_list_add(&sdp_service_records, (linked_item_t *) newRecordItem);
+    
+    sdp_emit_service_registered(connection, 0, newRecordItem->service_record_handle);
+
+    return record_handle;
+}
+
+#endif
+
+// unregister service record internally
+// 
+// makes sure one client cannot remove service records of other clients
+//
+void sdp_unregister_service_internal(void *connection, uint32_t service_record_handle){
+    service_record_item_t * record_item = sdp_get_record_for_handle(service_record_handle);
+    if (record_item && record_item->connection == connection) {
+        linked_list_remove(&sdp_service_records, (linked_item_t *) record_item);
+    }
+}
+
+// remove all service record for a client connection
+void sdp_unregister_services_for_connection(void *connection){
+    linked_item_t *it = (linked_item_t *) &sdp_service_records;
+    while (it->next){
+        service_record_item_t *record_item = (service_record_item_t *) it->next;
+        if (record_item->connection == connection){
+            it->next = it->next->next;
+#ifndef EMBEDDED
+            free(record_item);
+#endif
+        } else {
+            it = it->next;
+        }
+    }
+}
+
+// PDU
+// PDU ID (1), Transaction ID (2), Param Length (2), Param 1, Param 2, ..
+
+int sdp_create_error_response(uint16_t transaction_id, uint16_t error_code){
+    sdp_response_buffer[0] = SDP_ErrorResponse;
+    net_store_16(sdp_response_buffer, 1, transaction_id);
+    net_store_16(sdp_response_buffer, 3, 2);
+    net_store_16(sdp_response_buffer, 5, error_code); // invalid syntax
+    return 7;
+}
+
+int sdp_handle_service_search_request(uint8_t * packet, uint16_t remote_mtu){
+    
+    // get request details
+    uint16_t  transaction_id = READ_NET_16(packet, 1);
+    // not used yet - uint16_t  param_len = READ_NET_16(packet, 3);
+    uint8_t * serviceSearchPattern = &packet[5];
+    uint16_t  serviceSearchPatternLen = de_get_len(serviceSearchPattern);
+    uint16_t  maximumServiceRecordCount = READ_NET_16(packet, 5 + serviceSearchPatternLen);
+    uint8_t * continuationState = &packet[5+serviceSearchPatternLen+2];
+    
+    // calc maxumumServiceRecordCount based on remote MTU
+    uint16_t maxNrServiceRecordsPerResponse = (remote_mtu - (9+3))/4;
+    
+    // continuation state contains index of next service record to examine
+    int      continuation = 0;
+    uint16_t continuation_index = 0;
+    if (continuationState[0] == 2){
+        continuation_index = READ_NET_16(continuationState, 1);
+    }
+    
+    // get and limit total count
+    linked_item_t *it;
+    uint16_t total_service_count   = 0;
+    for (it = (linked_item_t *) sdp_service_records; it ; it = it->next){
+        service_record_item_t * item = (service_record_item_t *) it;
+        if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue;
+        total_service_count++;
+    }
+    if (total_service_count > maximumServiceRecordCount){
+        total_service_count = maximumServiceRecordCount;
+    }
+    
+    // ServiceRecordHandleList at 9
+    uint16_t pos = 9;
+    uint16_t current_service_count  = 0;
+    uint16_t current_service_index  = 0;
+    uint16_t matching_service_count = 0;
+    for (it = (linked_item_t *) sdp_service_records; it ; it = it->next, ++current_service_index){
+        service_record_item_t * item = (service_record_item_t *) it;
+
+        if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue;
+        matching_service_count++;
+        
+        if (current_service_index < continuation_index) continue;
+
+        net_store_32(sdp_response_buffer, pos, item->service_record_handle);
+        pos += 4;
+        current_service_count++;
+        
+        if (matching_service_count >= total_service_count) break;
+
+        if (current_service_count >= maxNrServiceRecordsPerResponse){
+            continuation = 1;
+            continuation_index = current_service_index + 1;
+            break;
+        }
+    }
+    
+    // Store continuation state
+    if (continuation) {
+        sdp_response_buffer[pos++] = 2;
+        net_store_16(sdp_response_buffer, pos, continuation_index);
+        pos += 2;
+    } else {
+        sdp_response_buffer[pos++] = 0;
+    }
+
+    // header
+    sdp_response_buffer[0] = SDP_ServiceSearchResponse;
+    net_store_16(sdp_response_buffer, 1, transaction_id);
+    net_store_16(sdp_response_buffer, 3, pos - 5); // size of variable payload
+    net_store_16(sdp_response_buffer, 5, total_service_count);
+    net_store_16(sdp_response_buffer, 7, current_service_count);
+    
+    return pos;
+}
+
+int sdp_handle_service_attribute_request(uint8_t * packet, uint16_t remote_mtu){
+    
+    // get request details
+    uint16_t  transaction_id = READ_NET_16(packet, 1);
+    // not used yet - uint16_t  param_len = READ_NET_16(packet, 3);
+    uint32_t  serviceRecordHandle = READ_NET_32(packet, 5);
+    uint16_t  maximumAttributeByteCount = READ_NET_16(packet, 9);
+    uint8_t * attributeIDList = &packet[11];
+    uint16_t  attributeIDListLen = de_get_len(attributeIDList);
+    uint8_t * continuationState = &packet[11+attributeIDListLen];
+    
+    // calc maximumAttributeByteCount based on remote MTU
+    uint16_t maximumAttributeByteCount2 = remote_mtu - (7+3);
+    if (maximumAttributeByteCount2 < maximumAttributeByteCount) {
+        maximumAttributeByteCount = maximumAttributeByteCount2;
+    }
+    
+    // continuation state contains the offset into the complete response
+    uint16_t continuation_offset = 0;
+    if (continuationState[0] == 2){
+        continuation_offset = READ_NET_16(continuationState, 1);
+    }
+    
+    // get service record
+    service_record_item_t * item = sdp_get_record_for_handle(serviceRecordHandle);
+    if (!item){
+        // service record handle doesn't exist
+        return sdp_create_error_response(transaction_id, 0x0002); /// invalid Service Record Handle
+    }
+    
+    
+    // AttributeList - starts at offset 7
+    uint16_t pos = 7;
+    
+    if (continuation_offset == 0){
+        
+        // get size of this record
+        uint16_t filtered_attributes_size = spd_get_filtered_size(item->service_record, attributeIDList);
+        
+        // store DES
+        de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, filtered_attributes_size);
+        maximumAttributeByteCount -= 3;
+        pos += 3;
+    }
+
+    // copy maximumAttributeByteCount from record
+    uint16_t bytes_used;
+    int complete = sdp_filter_attributes_in_attributeIDList(item->service_record, attributeIDList, continuation_offset, maximumAttributeByteCount, &bytes_used, &sdp_response_buffer[pos]);
+    pos += bytes_used;
+    
+    uint16_t attributeListByteCount = pos - 7;
+
+    if (complete) {
+        sdp_response_buffer[pos++] = 0;
+    } else {
+        continuation_offset += bytes_used;
+        sdp_response_buffer[pos++] = 2;
+        net_store_16(sdp_response_buffer, pos, continuation_offset);
+        pos += 2;
+    }
+
+    // header
+    sdp_response_buffer[0] = SDP_ServiceAttributeResponse;
+    net_store_16(sdp_response_buffer, 1, transaction_id);
+    net_store_16(sdp_response_buffer, 3, pos - 5);  // size of variable payload
+    net_store_16(sdp_response_buffer, 5, attributeListByteCount); 
+    
+    return pos;
+}
+
+static uint16_t sdp_get_size_for_service_search_attribute_response(uint8_t * serviceSearchPattern, uint8_t * attributeIDList){
+    uint16_t total_response_size = 0;
+    linked_item_t *it;
+    for (it = (linked_item_t *) sdp_service_records; it ; it = it->next){
+        service_record_item_t * item = (service_record_item_t *) it;
+        
+        if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue;
+        
+        // for all service records that match
+        total_response_size += 3 + spd_get_filtered_size(item->service_record, attributeIDList);
+    }
+    return total_response_size;
+}
+
+int sdp_handle_service_search_attribute_request(uint8_t * packet, uint16_t remote_mtu){
+    
+    // SDP header before attribute sevice list: 7
+    // Continuation, worst case: 5
+    
+    // get request details
+    uint16_t  transaction_id = READ_NET_16(packet, 1);
+    // not used yet - uint16_t  param_len = READ_NET_16(packet, 3);
+    uint8_t * serviceSearchPattern = &packet[5];
+    uint16_t  serviceSearchPatternLen = de_get_len(serviceSearchPattern);
+    uint16_t  maximumAttributeByteCount = READ_NET_16(packet, 5 + serviceSearchPatternLen);
+    uint8_t * attributeIDList = &packet[5+serviceSearchPatternLen+2];
+    uint16_t  attributeIDListLen = de_get_len(attributeIDList);
+    uint8_t * continuationState = &packet[5+serviceSearchPatternLen+2+attributeIDListLen];
+    
+    // calc maximumAttributeByteCount based on remote MTU, SDP header and reserved Continuation block
+    uint16_t maximumAttributeByteCount2 = remote_mtu - 12;
+    if (maximumAttributeByteCount2 < maximumAttributeByteCount) {
+        maximumAttributeByteCount = maximumAttributeByteCount2;
+    }
+    
+    // continuation state contains: index of next service record to examine
+    // continuation state contains: byte offset into this service record
+    uint16_t continuation_service_index = 0;
+    uint16_t continuation_offset = 0;
+    if (continuationState[0] == 4){
+        continuation_service_index = READ_NET_16(continuationState, 1);
+        continuation_offset = READ_NET_16(continuationState, 3);
+    }
+
+    // printf("--> sdp_handle_service_search_attribute_request, cont %u/%u, max %u\n", continuation_service_index, continuation_offset, maximumAttributeByteCount);
+    
+    // AttributeLists - starts at offset 7
+    uint16_t pos = 7;
+    
+    // add DES with total size for first request
+    if (continuation_service_index == 0 && continuation_offset == 0){
+        uint16_t total_response_size = sdp_get_size_for_service_search_attribute_response(serviceSearchPattern, attributeIDList);
+        de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, total_response_size);
+        // log_info("total response size %u\n", total_response_size);
+        pos += 3;
+        maximumAttributeByteCount -= 3;
+    }
+    
+    // create attribute list
+    int      first_answer = 1;
+    int      continuation = 0;
+    uint16_t current_service_index = 0;
+    linked_item_t *it = (linked_item_t *) sdp_service_records;
+    for ( ; it ; it = it->next, ++current_service_index){
+        service_record_item_t * item = (service_record_item_t *) it;
+        
+        if (current_service_index < continuation_service_index ) continue;
+        if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue;
+
+        if (continuation_offset == 0){
+            
+            // get size of this record
+            uint16_t filtered_attributes_size = spd_get_filtered_size(item->service_record, attributeIDList);
+            
+            // stop if complete record doesn't fits into response but we already have a partial response
+            if ((filtered_attributes_size + 3 > maximumAttributeByteCount) && !first_answer) {
+                continuation = 1;
+                break;
+            }
+            
+            // store DES
+            de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, filtered_attributes_size);
+            pos += 3;
+            maximumAttributeByteCount -= 3;
+        }
+        
+        first_answer = 0;
+    
+        // copy maximumAttributeByteCount from record
+        uint16_t bytes_used;
+        int complete = sdp_filter_attributes_in_attributeIDList(item->service_record, attributeIDList, continuation_offset, maximumAttributeByteCount, &bytes_used, &sdp_response_buffer[pos]);
+        pos += bytes_used;
+        maximumAttributeByteCount -= bytes_used;
+        
+        if (complete) {
+            continuation_offset = 0;
+            continue;
+        }
+        
+        continuation = 1;
+        continuation_offset += bytes_used;
+        break;
+    }
+    
+    uint16_t attributeListsByteCount = pos - 7;
+    
+    // Continuation State
+    if (continuation){
+        sdp_response_buffer[pos++] = 4;
+        net_store_16(sdp_response_buffer, pos, (uint16_t) current_service_index);
+        pos += 2;
+        net_store_16(sdp_response_buffer, pos, continuation_offset);
+        pos += 2;
+    } else {
+        // complete
+        sdp_response_buffer[pos++] = 0;
+    }
+        
+    // create SDP header
+    sdp_response_buffer[0] = SDP_ServiceSearchAttributeResponse;
+    net_store_16(sdp_response_buffer, 1, transaction_id);
+    net_store_16(sdp_response_buffer, 3, pos - 5);  // size of variable payload
+    net_store_16(sdp_response_buffer, 5, attributeListsByteCount);
+    
+    return pos;
+}
+
+static void sdp_try_respond(void){
+    if (!sdp_response_size ) return;
+    if (!l2cap_cid) return;
+    if (!l2cap_can_send_packet_now(l2cap_cid)) return;
+    
+    // update state before sending packet (avoid getting called when new l2cap credit gets emitted)
+    uint16_t size = sdp_response_size;
+    sdp_response_size = 0;
+    l2cap_send_internal(l2cap_cid, sdp_response_buffer, size);
+}
+
+// we assume that we don't get two requests in a row
+static void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
+    uint16_t transaction_id;
+    SDP_PDU_ID_t pdu_id;
+    uint16_t remote_mtu;
+    // uint16_t param_len;
+    
+    switch (packet_type) {
+            
+        case L2CAP_DATA_PACKET:
+            pdu_id = (SDP_PDU_ID_t) packet[0];
+            transaction_id = READ_NET_16(packet, 1);
+            // param_len = READ_NET_16(packet, 3);
+            remote_mtu = l2cap_get_remote_mtu_for_local_cid(channel);
+            // account for our buffer
+            if (remote_mtu > SDP_RESPONSE_BUFFER_SIZE){
+                remote_mtu = SDP_RESPONSE_BUFFER_SIZE;
+            }
+            
+            // printf("SDP Request: type %u, transaction id %u, len %u, mtu %u\n", pdu_id, transaction_id, param_len, remote_mtu);
+            switch (pdu_id){
+                    
+                case SDP_ServiceSearchRequest:
+                    sdp_response_size = sdp_handle_service_search_request(packet, remote_mtu);
+                    break;
+                                        
+                case SDP_ServiceAttributeRequest:
+                    sdp_response_size = sdp_handle_service_attribute_request(packet, remote_mtu);
+                    break;
+                    
+                case SDP_ServiceSearchAttributeRequest:
+                    sdp_response_size = sdp_handle_service_search_attribute_request(packet, remote_mtu);
+                    break;
+                    
+                default:
+                    sdp_response_size = sdp_create_error_response(transaction_id, 0x0003); // invalid syntax
+                    break;
+            }
+            
+            sdp_try_respond();
+            
+            break;
+            
+        case HCI_EVENT_PACKET:
+            
+            switch (packet[0]) {
+
+                case L2CAP_EVENT_INCOMING_CONNECTION:
+                    if (l2cap_cid) {
+                        // CONNECTION REJECTED DUE TO LIMITED RESOURCES 
+                        l2cap_decline_connection_internal(channel, 0x0d);
+                        break;
+                    }
+                    // accept
+                    l2cap_cid = channel;
+                    sdp_response_size = 0;
+                    l2cap_accept_connection_internal(channel);
+                    break;
+                    
+                case L2CAP_EVENT_CHANNEL_OPENED:
+                    if (packet[2]) {
+                        // open failed -> reset
+                        l2cap_cid = 0;
+                    }
+                    break;
+
+                case L2CAP_EVENT_CREDITS:
+                case DAEMON_EVENT_HCI_PACKET_SENT:
+                    sdp_try_respond();
+                    break;
+                
+                case L2CAP_EVENT_CHANNEL_CLOSED:
+                    if (channel == l2cap_cid){
+                        // reset
+                        l2cap_cid = 0;
+                    }
+                    break;
+                                        
+                default:
+                    // other event
+                    break;
+            }
+            break;
+            
+        default:
+            // other packet type
+            break;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/sdp.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+#pragma once
+
+#include <stdint.h>
+#include <btstack/linked_list.h>
+
+#include "config.h"
+
+typedef enum {
+    SDP_ErrorResponse = 1,
+    SDP_ServiceSearchRequest,
+    SDP_ServiceSearchResponse,
+    SDP_ServiceAttributeRequest,
+    SDP_ServiceAttributeResponse,
+    SDP_ServiceSearchAttributeRequest,
+    SDP_ServiceSearchAttributeResponse
+} SDP_PDU_ID_t;
+
+// service record
+// -- uses user_data field for actual
+typedef struct {
+    // linked list - assert: first field
+    linked_item_t   item;
+    
+    // client connection
+    void *  connection;
+    
+    // data is contained in same memory
+    uint32_t        service_record_handle;
+    uint8_t         service_record[0];
+} service_record_item_t;
+
+
+void sdp_init(void);
+
+void sdp_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type,
+                                                 uint16_t channel, uint8_t *packet, uint16_t size));
+
+#ifdef EMBEDDED
+// register service record internally - the normal version creates a copy of the record
+// pre: AttributeIDs are in ascending order => ServiceRecordHandle is first attribute if present
+// @returns ServiceRecordHandle or 0 if registration failed
+uint32_t sdp_register_service_internal(void *connection, service_record_item_t * record_item);
+#else
+// register service record internally - this special version doesn't copy the record, it cannot be freeed
+// pre: AttributeIDs are in ascending order
+// pre: ServiceRecordHandle is first attribute and valid
+// pre: record
+// @returns ServiceRecordHandle or 0 if registration failed
+uint32_t sdp_register_service_internal(void *connection, uint8_t * service_record);
+#endif
+
+// unregister service record internally
+void sdp_unregister_service_internal(void *connection, uint32_t service_record_handle);
+
+//
+void sdp_unregister_services_for_connection(void *connection);
+
+//
+int sdp_handle_service_search_request(uint8_t * packet, uint16_t remote_mtu);
+int sdp_handle_service_attribute_request(uint8_t * packet, uint16_t remote_mtu);
+int sdp_handle_service_search_attribute_request(uint8_t * packet, uint16_t remote_mtu);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/sdp_util.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,698 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  sdp_util.c
+ */
+
+#include <btstack/sdp_util.h>
+#include <btstack/utils.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>   // PRIx32
+
+// workaround for missing PRIx32 on mspgcc (16-bit MCU)
+#ifndef PRIx32
+#warning Using own: #define PRIx32 "lx"
+#define PRIx32 "lx"
+#endif
+
+// date element type names
+const char * const type_names[] = { "NIL", "UINT", "INT", "UUID", "STRING", "BOOL", "DES", "DEA", "URL"};
+
+// Bluetooth Base UUID: 00000000-0000-1000-8000- 00805F9B34FB
+const uint8_t sdp_bluetooth_base_uuid[] = { 0x00, 0x00, 0x00, 0x00, /* - */ 0x00, 0x00, /* - */ 0x10, 0x00, /* - */
+    0x80, 0x00, /* - */ 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB };
+
+void sdp_normalize_uuid(uint8_t *uuid, uint32_t shortUUID){
+    memcpy(uuid, sdp_bluetooth_base_uuid, 16);
+    net_store_32(uuid, 0, shortUUID);
+}
+
+// MARK: DataElement getter
+de_size_t de_get_size_type(uint8_t *header){
+    return (de_size_t) (header[0] & 7);
+}
+
+de_type_t de_get_element_type(uint8_t *header){
+    return (de_type_t) (header[0] >> 3);
+}
+
+int de_get_header_size(uint8_t * header){
+    de_size_t de_size = de_get_size_type(header);
+    if (de_size <= DE_SIZE_128) {
+        return 1;
+    }
+    return 1 + (1 << (de_size-DE_SIZE_VAR_8));
+}
+
+int de_get_data_size(uint8_t * header){
+    uint32_t result = 0;
+    de_type_t de_type = de_get_element_type(header);
+    de_size_t de_size = de_get_size_type(header);
+    switch (de_size){
+        case DE_SIZE_VAR_8:
+            result = header[1];
+            break;
+        case DE_SIZE_VAR_16:
+            result = READ_NET_16(header,1);
+            break;
+        case DE_SIZE_VAR_32:
+            result = READ_NET_32(header,1);
+            break;
+        default:
+        // case DE_SIZE_8:
+        // case DE_SIZE_16:
+        // case DE_SIZE_32:
+        // case DE_SIZE_64:
+        // case DE_SIZE_128:
+            if (de_type == DE_NIL) return 0;
+            return 1 << de_size;
+    }
+    return result;    
+}
+
+int de_get_len(uint8_t *header){
+    return de_get_header_size(header) + de_get_data_size(header); 
+}
+
+// @returns: element is valid UUID
+int de_get_normalized_uuid(uint8_t *uuid128, uint8_t *element){
+    de_type_t uuidType = de_get_element_type(element);
+    de_size_t uuidSize = de_get_size_type(element);
+    if (uuidType != DE_UUID) return 0;
+    uint32_t shortUUID;
+    switch (uuidSize){
+        case DE_SIZE_16:
+            shortUUID = READ_NET_16(element, 1);
+            break;
+        case DE_SIZE_32:
+            shortUUID = READ_NET_32(element, 1);
+            break;
+        case DE_SIZE_128:
+            memcpy(uuid128, element+1, 16);
+            return 1;
+        default:
+            return 0;
+    }
+    sdp_normalize_uuid(uuid128, shortUUID);
+    return 1;
+}
+
+// functions to create record
+static void de_store_descriptor(uint8_t * header, de_type_t type, de_size_t size){
+    header[0] = (type << 3) | size; 
+}
+
+void de_store_descriptor_with_len(uint8_t * header, de_type_t type, de_size_t size, uint32_t len){
+    header[0] = (type << 3) | size; 
+    switch (size){
+        case DE_SIZE_VAR_8:
+            header[1] = len;
+            break;
+        case DE_SIZE_VAR_16:
+            net_store_16(header, 1, len);
+            break;
+        case DE_SIZE_VAR_32:
+            net_store_32(header, 1, len);
+            break;
+        default:
+            break;
+    }
+}
+
+// MARK: DataElement creation
+
+/* starts a new sequence in empty buffer - first call */
+void de_create_sequence(uint8_t *header){
+    de_store_descriptor_with_len( header, DE_DES, DE_SIZE_VAR_16, 0); // DES, 2 Byte Length
+};
+
+/* starts a sub-sequence, @returns handle for sub-sequence */
+uint8_t * de_push_sequence(uint8_t *header){
+    int element_len = de_get_len(header);
+    de_store_descriptor_with_len(header+element_len, DE_DES, DE_SIZE_VAR_16, 0); // DES, 2 Byte Length
+    return header + element_len;
+}
+
+/* closes the current sequence and updates the parent sequence */
+void de_pop_sequence(uint8_t * parent, uint8_t * child){
+    int child_len = de_get_len(child);
+    int data_size_parent = READ_NET_16(parent,1);
+    net_store_16(parent, 1, data_size_parent + child_len);
+}
+
+/* adds a single number value and 16+32 bit UUID to the sequence */
+void de_add_number(uint8_t *seq, de_type_t type, de_size_t size, uint32_t value){
+    int data_size   = READ_NET_16(seq,1);
+    int element_size = 1;   // e.g. for DE_TYPE_NIL
+    de_store_descriptor(seq+3+data_size, type, size); 
+    switch (size){
+        case DE_SIZE_8:
+            if (type != DE_NIL){
+                seq[4+data_size] = value;
+                element_size = 2;
+            }
+            break;
+        case DE_SIZE_16:
+            net_store_16(seq, 4+data_size, value);
+            element_size = 3;
+            break;
+        case DE_SIZE_32:
+            net_store_32(seq, 4+data_size, value);
+            element_size = 5;
+            break;
+        default:
+            break;
+    }
+    net_store_16(seq, 1, data_size+element_size);
+}
+
+/* add a single block of data, e.g. as DE_STRING, DE_URL */
+void de_add_data( uint8_t *seq, de_type_t type, uint16_t size, uint8_t *data){
+    int data_size   = READ_NET_16(seq,1);
+    if (size > 0xff) {
+        // use 16-bit lengh information (3 byte header)
+        de_store_descriptor_with_len(seq+3+data_size, type, DE_SIZE_VAR_16, size); 
+        data_size += 3;
+    } else {
+        // use 8-bit lengh information (2 byte header)
+        de_store_descriptor_with_len(seq+3+data_size, type, DE_SIZE_VAR_8, size); 
+        data_size += 2;
+    }
+    memcpy( seq + 3 + data_size, data, size);
+    data_size += size;
+    net_store_16(seq, 1, data_size);
+}
+
+void de_add_uuid128(uint8_t * seq, uint8_t * uuid){
+    int data_size   = READ_NET_16(seq,1);
+    de_store_descriptor(seq+3+data_size, DE_UUID, DE_SIZE_128); 
+    memcpy( seq + 4 + data_size, uuid, 16);
+    net_store_16(seq, 1, data_size+1+16);
+}
+
+void sdp_add_attribute(uint8_t *seq, uint16_t attributeID, uint8_t attributeValue){
+}
+
+// MARK: DataElementSequence traversal
+typedef int (*de_traversal_callback_t)(uint8_t * element, de_type_t type, de_size_t size, void *context);
+static void de_traverse_sequence(uint8_t * element, de_traversal_callback_t handler, void *context){
+    de_type_t type = de_get_element_type(element);
+    if (type != DE_DES) return;
+    int pos = de_get_header_size(element);
+    int end_pos = de_get_len(element);
+    while (pos < end_pos){
+        de_type_t elemType = de_get_element_type(element + pos);
+        de_size_t elemSize = de_get_size_type(element + pos);
+        uint8_t done = (*handler)(element + pos, elemType, elemSize, context); 
+        if (done) break;
+        pos += de_get_len(element + pos);
+    }
+}
+
+// MARK: AttributeList traversal
+typedef int (*sdp_attribute_list_traversal_callback_t)(uint16_t attributeID, uint8_t * attributeValue, de_type_t type, de_size_t size, void *context);
+static void sdp_attribute_list_traverse_sequence(uint8_t * element, sdp_attribute_list_traversal_callback_t handler, void *context){
+    de_type_t type = de_get_element_type(element);
+    if (type != DE_DES) return;
+    int pos = de_get_header_size(element);
+    int end_pos = de_get_len(element);
+    while (pos < end_pos){
+        de_type_t idType = de_get_element_type(element + pos);
+        de_size_t idSize = de_get_size_type(element + pos);
+        if (idType != DE_UINT || idSize != DE_SIZE_16) break; // wrong type
+        uint16_t attribute_id = READ_NET_16(element, pos + 1);
+        pos += 3;
+        if (pos >= end_pos) break; // array out of bounds
+        de_type_t valueType = de_get_element_type(element + pos);
+        de_size_t valueSize = de_get_size_type(element + pos);
+        uint8_t done = (*handler)(attribute_id, element + pos, valueType, valueSize, context); 
+        if (done) break;
+        pos += de_get_len(element + pos);
+    }
+}
+
+// MARK: AttributeID in AttributeIDList 
+// attribute ID in AttributeIDList
+// context { result, attributeID }
+struct sdp_context_attributeID_search {
+    int result;
+    uint16_t attributeID;
+};
+static int sdp_traversal_attributeID_search(uint8_t * element, de_type_t type, de_size_t size, void *my_context){
+    struct sdp_context_attributeID_search * context = (struct sdp_context_attributeID_search *) my_context;
+    if (type != DE_UINT) return 0;
+    switch (size) {
+        case DE_SIZE_16:
+            if (READ_NET_16(element, 1) == context->attributeID) {
+                context->result = 1;
+                return 1;
+            }
+            break;
+        case DE_SIZE_32:
+            if (READ_NET_16(element, 1) <= context->attributeID
+            &&  context->attributeID <= READ_NET_16(element, 3)) {
+                context->result = 1;
+                return 1;
+            }
+            break;
+        default:
+            break;
+    }
+    return 0;
+}
+int sdp_attribute_list_constains_id(uint8_t *attributeIDList, uint16_t attributeID){
+    struct sdp_context_attributeID_search attributeID_search;
+    attributeID_search.result = 0;
+    attributeID_search.attributeID = attributeID;
+    de_traverse_sequence(attributeIDList, sdp_traversal_attributeID_search, &attributeID_search);
+    return attributeID_search.result;
+}
+
+// MARK: Append Attributes for AttributeIDList
+// pre: buffer contains DES with 2 byte length field
+struct sdp_context_append_attributes {
+    uint8_t * buffer;
+    uint16_t startOffset;     // offset of when to start copying
+    uint16_t maxBytes;
+    uint16_t usedBytes;
+    uint8_t *attributeIDList;
+};
+
+static int sdp_traversal_append_attributes(uint16_t attributeID, uint8_t * attributeValue, de_type_t type, de_size_t size, void *my_context){
+    struct sdp_context_append_attributes * context = (struct sdp_context_append_attributes *) my_context;
+    if (sdp_attribute_list_constains_id(context->attributeIDList, attributeID)) {
+        // DES_HEADER(3) + DES_DATA + (UINT16(3) + attribute)
+        uint16_t data_size = READ_NET_16(context->buffer, 1);
+        int attribute_len = de_get_len(attributeValue);
+        if (3 + data_size + (3 + attribute_len) <= context->maxBytes) {
+            // copy Attribute
+            de_add_number(context->buffer, DE_UINT, DE_SIZE_16, attributeID);   
+            data_size += 3; // 3 bytes
+            memcpy(context->buffer + 3 + data_size, attributeValue, attribute_len);
+            net_store_16(context->buffer,1,data_size+attribute_len);
+        } else {
+            // not enought space left -> continue with previous element
+            return 1;
+        }
+    }
+    return 0;
+}
+
+// maxBytes: maximal size of data element sequence
+uint16_t sdp_append_attributes_in_attributeIDList(uint8_t *record, uint8_t *attributeIDList, uint16_t startOffset, uint16_t maxBytes, uint8_t *buffer){
+    struct sdp_context_append_attributes context;
+    context.buffer = buffer;
+    context.maxBytes = maxBytes;
+    context.usedBytes = 0;
+    context.startOffset = startOffset;
+    context.attributeIDList = attributeIDList;
+    sdp_attribute_list_traverse_sequence(record, sdp_traversal_append_attributes, &context);
+    return context.usedBytes;
+}
+
+// MARK: Filter attributes that match attribute list from startOffset and a max nr bytes
+struct sdp_context_filter_attributes {
+    uint8_t * buffer;
+    uint16_t startOffset;     // offset of when to start copying
+    uint16_t maxBytes;
+    uint16_t usedBytes;
+    uint8_t *attributeIDList;
+    int      complete;
+};
+
+// copy data with given start offset and max bytes, returns OK if all data has been copied
+static int spd_append_range(struct sdp_context_filter_attributes* context, uint16_t len, uint8_t *data){
+    int ok = 1;
+    uint16_t remainder_len = len - context->startOffset;
+    if (context->maxBytes < remainder_len){
+        remainder_len = context->maxBytes;
+        ok = 0;
+    }
+    memcpy(context->buffer, &data[context->startOffset], remainder_len);
+    context->usedBytes += remainder_len;
+    context->buffer    += remainder_len;
+    context->maxBytes  -= remainder_len;
+    context->startOffset = 0;
+    return ok;
+}
+
+static int sdp_traversal_filter_attributes(uint16_t attributeID, uint8_t * attributeValue, de_type_t type, de_size_t size, void *my_context){
+    struct sdp_context_filter_attributes * context = (struct sdp_context_filter_attributes *) my_context;
+
+    if (!sdp_attribute_list_constains_id(context->attributeIDList, attributeID)) return 0;
+
+    // { Attribute ID (Descriptor, big endian 16-bit ID), AttributeValue (data)}
+
+    // handle Attribute ID
+    if (context->startOffset >= 3){
+        context->startOffset -= 3;
+    } else {
+        uint8_t idBuffer[3];
+        de_store_descriptor(idBuffer, DE_UINT,  DE_SIZE_16);
+        net_store_16(idBuffer,1,attributeID);
+        
+        int ok = spd_append_range(context, 3, idBuffer);
+        if (!ok) {
+            context->complete = 0;
+            return 1;
+        }
+    }
+    
+    // handle Attribute Value
+    int attribute_len = de_get_len(attributeValue);
+    if (context->startOffset >= attribute_len) {
+        context->startOffset -= attribute_len;
+        return 0;
+    }
+    
+    int ok = spd_append_range(context, attribute_len, attributeValue);
+    if (!ok) {
+        context->complete = 0;
+        return 1;
+    }
+    return 0;
+}
+
+int sdp_filter_attributes_in_attributeIDList(uint8_t *record, uint8_t *attributeIDList, uint16_t startOffset, uint16_t maxBytes, uint16_t *usedBytes, uint8_t *buffer){
+
+    struct sdp_context_filter_attributes context;
+    context.buffer = buffer;
+    context.maxBytes = maxBytes;
+    context.usedBytes = 0;
+    context.startOffset = startOffset;
+    context.attributeIDList = attributeIDList;
+    context.complete = 1;
+
+    sdp_attribute_list_traverse_sequence(record, sdp_traversal_filter_attributes, &context);
+
+    *usedBytes = context.usedBytes;
+    return context.complete;
+}
+
+// MARK: Get sum of attributes matching attribute list
+struct sdp_context_get_filtered_size {
+    uint8_t *attributeIDList;
+    uint16_t size;
+};
+
+static int sdp_traversal_get_filtered_size(uint16_t attributeID, uint8_t * attributeValue, de_type_t type, de_size_t size, void *my_context){
+    struct sdp_context_get_filtered_size * context = (struct sdp_context_get_filtered_size *) my_context;
+    if (sdp_attribute_list_constains_id(context->attributeIDList, attributeID)) {
+        context->size += 3 + de_get_len(attributeValue);
+    }
+    return 0;
+}
+
+int spd_get_filtered_size(uint8_t *record, uint8_t *attributeIDList){
+    struct sdp_context_get_filtered_size context;
+    context.size = 0;
+    context.attributeIDList = attributeIDList;
+    sdp_attribute_list_traverse_sequence(record, sdp_traversal_get_filtered_size, &context);
+    return context.size;
+}
+
+// MARK: Get AttributeValue for AttributeID
+// find attribute (ELEMENT) by ID
+struct sdp_context_attribute_by_id {
+    uint16_t  attributeID;
+    uint8_t * attributeValue;
+};
+static int sdp_traversal_attribute_by_id(uint16_t attributeID, uint8_t * attributeValue, de_type_t attributeType, de_size_t size, void *my_context){
+    struct sdp_context_attribute_by_id * context = (struct sdp_context_attribute_by_id *) my_context;
+    if (attributeID == context->attributeID) {
+        context->attributeValue = attributeValue;
+        return 1;
+    }
+    return 0;
+}
+
+uint8_t * sdp_get_attribute_value_for_attribute_id(uint8_t * record, uint16_t attributeID){
+    struct sdp_context_attribute_by_id context;
+    context.attributeValue = NULL;
+    context.attributeID = attributeID;
+    sdp_attribute_list_traverse_sequence(record, sdp_traversal_attribute_by_id, &context);
+    return context.attributeValue;
+}
+
+// MARK: Set AttributeValue for AttributeID
+struct sdp_context_set_attribute_for_id {
+    uint16_t  attributeID;
+    uint32_t  attributeValue;
+    uint8_t   attributeFound;
+};
+static int sdp_traversal_set_attribute_for_id(uint16_t attributeID, uint8_t * attributeValue, de_type_t attributeType, de_size_t size, void *my_context){
+    struct sdp_context_set_attribute_for_id * context = (struct sdp_context_set_attribute_for_id *) my_context;
+    if (attributeID == context->attributeID) {
+        context->attributeFound = 1;
+        switch (size){
+            case DE_SIZE_8:
+                if (attributeType != DE_NIL){
+                    attributeValue[1] = context->attributeValue;
+                }
+                break;
+            case DE_SIZE_16:
+                net_store_16(attributeValue, 1, context->attributeValue);
+                break;
+            case DE_SIZE_32:
+                net_store_32(attributeValue, 1, context->attributeValue);
+                break;
+                // Might want to support STRINGS to, copy upto original length
+            default:
+                break;
+        }        
+        return 1;
+    }
+    return 0;
+}
+uint8_t sdp_set_attribute_value_for_attribute_id(uint8_t * record, uint16_t attributeID, uint32_t value){
+    struct sdp_context_set_attribute_for_id context;
+    context.attributeID = attributeID;
+    context.attributeValue = value;
+    context.attributeFound = 0;
+    sdp_attribute_list_traverse_sequence(record, sdp_traversal_set_attribute_for_id, &context);
+    return context.attributeFound;
+}
+
+// MARK: ServiceRecord contains UUID
+// service record contains UUID
+// context { normalizedUUID }
+struct sdp_context_contains_uuid128 {
+    uint8_t * uuid128;
+    int result;
+};
+int sdp_record_contains_UUID128(uint8_t *record, uint8_t *uuid128);
+static int sdp_traversal_contains_UUID128(uint8_t * element, de_type_t type, de_size_t size, void *my_context){
+    struct sdp_context_contains_uuid128 * context = (struct sdp_context_contains_uuid128 *) my_context;
+    uint8_t normalizedUUID[16];
+    if (type == DE_UUID){
+        uint8_t uuidOK = de_get_normalized_uuid(normalizedUUID, element);
+        context->result = uuidOK && memcmp(context->uuid128, normalizedUUID, 16) == 0;
+    }
+    if (type == DE_DES){
+        context->result = sdp_record_contains_UUID128(element, context->uuid128);
+    }
+    return context->result;
+}
+int sdp_record_contains_UUID128(uint8_t *record, uint8_t *uuid128){
+    struct sdp_context_contains_uuid128 context;
+    context.uuid128 = uuid128;
+    context.result = 0;
+    de_traverse_sequence(record, sdp_traversal_contains_UUID128, &context);
+    return context.result;
+}
+    
+// MARK: ServiceRecord matches SearchServicePattern
+// if UUID in searchServicePattern is not found in record => false
+// context { result, record }
+struct sdp_context_match_pattern {
+    uint8_t * record;
+    int result;
+};
+int sdp_traversal_match_pattern(uint8_t * element, de_type_t attributeType, de_size_t size, void *my_context){
+    struct sdp_context_match_pattern * context = (struct sdp_context_match_pattern *) my_context;
+    uint8_t normalizedUUID[16];
+    uint8_t uuidOK = de_get_normalized_uuid(normalizedUUID, element);
+    if (!uuidOK || !sdp_record_contains_UUID128(context->record, normalizedUUID)){
+        context->result = 0;
+        return 1;
+    }
+    return 0;
+}
+int sdp_record_matches_service_search_pattern(uint8_t *record, uint8_t *serviceSearchPattern){
+    struct sdp_context_match_pattern context;
+    context.record = record;
+    context.result = 1;
+    de_traverse_sequence(serviceSearchPattern, sdp_traversal_match_pattern, &context);
+    return context.result;
+}
+
+// MARK: Dump DataElement
+// context { indent }
+static int de_traversal_dump_data(uint8_t * element, de_type_t de_type, de_size_t de_size, void *my_context){
+    int indent = *(int*) my_context;
+    int i;
+    for (i=0; i<indent;i++) printf("    ");
+    int pos     = de_get_header_size(element);
+    int end_pos = de_get_len(element);
+    printf("type %5s (%u), element len %2u ", type_names[de_type], de_type, end_pos);
+    if (de_type == DE_DES) {
+        printf("\n");
+        indent++;
+        de_traverse_sequence(element, de_traversal_dump_data, (void *)&indent);
+    } else if (de_type == DE_UUID && de_size == DE_SIZE_128) {
+        printf(", value: ");
+        printUUID(element+1);
+        printf("\n");
+    } else if (de_type == DE_STRING) {
+        int len = 0;
+        switch (de_size){
+            case DE_SIZE_VAR_8:
+                len = element[1];
+                break;
+            case DE_SIZE_VAR_16:
+                len = READ_NET_16(element, 1);
+                break;
+            default:
+                break;
+        }
+        printf("len %u (0x%02x)\n", len, len);
+        hexdump(&element[pos], len);
+    } else {
+        uint32_t value = 0;
+        switch (de_size) {
+            case DE_SIZE_8:
+                if (de_type != DE_NIL){
+                    value = element[pos];
+                }
+                break;
+            case DE_SIZE_16:
+                value = READ_NET_16(element,pos);
+                break;
+            case DE_SIZE_32:
+                value = READ_NET_32(element,pos);
+                break;
+            default:
+                break;
+        }
+        printf(", value: 0x%08" PRIx32 "\n", value);
+    }
+    return 0;
+}
+
+void de_dump_data_element(uint8_t * record){
+    int indent = 0;
+    // hack to get root DES, too.
+    de_type_t type = de_get_element_type(record);
+    de_size_t size = de_get_size_type(record);
+    de_traversal_dump_data(record, type, size, (void*) &indent);
+}
+
+void sdp_create_spp_service(uint8_t *service, int service_id, const char *name){
+    
+    uint8_t* attribute;
+    de_create_sequence(service);
+    
+    // 0x0000 "Service Record Handle"
+    de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ServiceRecordHandle);
+    de_add_number(service, DE_UINT, DE_SIZE_32, 0x10001);
+    
+    // 0x0001 "Service Class ID List"
+    de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_ServiceClassIDList);
+    attribute = de_push_sequence(service);
+    {
+        de_add_number(attribute,  DE_UUID, DE_SIZE_16, 0x1101 );
+    }
+    de_pop_sequence(service, attribute);
+    
+    // 0x0004 "Protocol Descriptor List"
+    de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_ProtocolDescriptorList);
+    attribute = de_push_sequence(service);
+    {
+        uint8_t* l2cpProtocol = de_push_sequence(attribute);
+        {
+            de_add_number(l2cpProtocol,  DE_UUID, DE_SIZE_16, 0x0100);
+        }
+        de_pop_sequence(attribute, l2cpProtocol);
+        
+        uint8_t* rfcomm = de_push_sequence(attribute);
+        {
+            de_add_number(rfcomm,  DE_UUID, DE_SIZE_16, 0x0003);  // rfcomm_service
+            de_add_number(rfcomm,  DE_UINT, DE_SIZE_8,  service_id);  // rfcomm channel
+        }
+        de_pop_sequence(attribute, rfcomm);
+    }
+    de_pop_sequence(service, attribute);
+    
+    // 0x0005 "Public Browse Group"
+    de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_BrowseGroupList); // public browse group
+    attribute = de_push_sequence(service);
+    {
+        de_add_number(attribute,  DE_UUID, DE_SIZE_16, 0x1002 );
+    }
+    de_pop_sequence(service, attribute);
+    
+    // 0x0006
+    de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_LanguageBaseAttributeIDList);
+    attribute = de_push_sequence(service);
+    {
+        de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x656e);
+        de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x006a);
+        de_add_number(attribute, DE_UINT, DE_SIZE_16, 0x0100);
+    }
+    de_pop_sequence(service, attribute);
+    
+    // 0x0009 "Bluetooth Profile Descriptor List"
+    de_add_number(service,  DE_UINT, DE_SIZE_16, SDP_BluetoothProfileDescriptorList);
+    attribute = de_push_sequence(service);
+    {
+        uint8_t *sppProfile = de_push_sequence(attribute);
+        {
+            de_add_number(sppProfile,  DE_UUID, DE_SIZE_16, 0x1101);
+            de_add_number(sppProfile,  DE_UINT, DE_SIZE_16, 0x0100);
+        }
+        de_pop_sequence(attribute, sppProfile);
+    }
+    de_pop_sequence(service, attribute);
+    
+    // 0x0100 "ServiceName"
+    de_add_number(service,  DE_UINT, DE_SIZE_16, 0x0100);
+    de_add_data(service,  DE_STRING, strlen(name), (uint8_t *) name);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/sdp_util.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2010 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ *  sdp_util.h
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#if defined __cplusplus
+extern "C" {
+#endif
+    
+typedef enum {
+    DE_NIL = 0,
+    DE_UINT,
+    DE_INT,
+    DE_UUID,
+    DE_STRING,
+    DE_BOOL,
+    DE_DES,
+    DE_DEA,
+    DE_URL
+} de_type_t;
+
+typedef enum {
+    DE_SIZE_8 = 0,
+    DE_SIZE_16,
+    DE_SIZE_32,
+    DE_SIZE_64,
+    DE_SIZE_128,
+    DE_SIZE_VAR_8,
+    DE_SIZE_VAR_16,
+    DE_SIZE_VAR_32
+} de_size_t;
+
+// UNIVERSAL ATTRIBUTE DEFINITIONS
+#define SDP_ServiceRecordHandle     0x0000
+#define SDP_ServiceClassIDList      0x0001
+#define SDP_ServiceRecordState      0x0002
+#define SDP_ServiceID               0x0003
+#define SDP_ProtocolDescriptorList  0x0004
+#define SDP_BrowseGroupList            0x0005
+#define SDP_LanguageBaseAttributeIDList 0x0006
+#define SDP_ServiceInfoTimeToLive    0x0007
+#define SDP_ServiceAvailability        0x0008
+#define SDP_BluetoothProfileDescriptorList 0x0009
+#define SDP_DocumentationURL        0x000a
+#define SDP_ClientExecutableURL     0x000b
+#define SDP_IconURL                 0x000c
+#define SDP_AdditionalProtocolDescriptorList 0x000d
+#define SDP_SupportedFormatsList    0x0303
+
+// SERVICE CLASSES
+#define SDP_OBEXObjectPush    0x1105
+#define SDP_OBEXFileTransfer  0x1106
+#define SDP_PublicBrowseGroup 0x1002
+
+// PROTOCOLS
+#define SDP_SDPProtocol       0x0001
+#define SDP_UDPProtocol       0x0002
+#define SDP_RFCOMMProtocol    0x0003
+#define SDP_OBEXProtocol      0x0008
+#define SDP_L2CAPProtocol     0x0100
+
+// OFFSETS FOR LOCALIZED ATTRIBUTES - SDP_LanguageBaseAttributeIDList
+#define SDP_Offest_ServiceName      0x0000
+#define SDP_Offest_ServiceDescription 0x0001
+#define SDP_Offest_ProviderName     0x0002
+
+// OBEX
+#define SDP_vCard_2_1       0x01
+#define SDP_vCard_3_0       0x02
+#define SDP_vCal_1_0        0x03
+#define SDP_iCal_2_0        0x04
+#define SDP_vNote           0x05
+#define SDP_vMessage        0x06
+#define SDP_OBEXFileTypeAny 0xFF
+
+// MARK: DateElement
+void de_dump_data_element(uint8_t * record);
+int de_get_len(uint8_t *header);
+de_size_t de_get_size_type(uint8_t *header);
+de_type_t de_get_element_type(uint8_t *header);
+int de_get_header_size(uint8_t * header);
+void de_create_sequence(uint8_t *header);
+void de_store_descriptor_with_len(uint8_t * header, de_type_t type, de_size_t size, uint32_t len);
+uint8_t * de_push_sequence(uint8_t *header);
+void de_pop_sequence(uint8_t * parent, uint8_t * child);
+void de_add_number(uint8_t *seq, de_type_t type, de_size_t size, uint32_t value);
+void de_add_data( uint8_t *seq, de_type_t type, uint16_t size, uint8_t *data);
+
+int de_get_data_size(uint8_t * header);
+void de_add_uuid128(uint8_t * seq, uint8_t * uuid);
+
+// MARK: SDP
+uint16_t  sdp_append_attributes_in_attributeIDList(uint8_t *record, uint8_t *attributeIDList, uint16_t startOffset, uint16_t maxBytes, uint8_t *buffer);
+uint8_t * sdp_get_attribute_value_for_attribute_id(uint8_t * record, uint16_t attributeID);
+uint8_t   sdp_set_attribute_value_for_attribute_id(uint8_t * record, uint16_t attributeID, uint32_t value);
+int       sdp_record_matches_service_search_pattern(uint8_t *record, uint8_t *serviceSearchPattern);
+int       spd_get_filtered_size(uint8_t *record, uint8_t *attributeIDList);
+int       sdp_filter_attributes_in_attributeIDList(uint8_t *record, uint8_t *attributeIDList, uint16_t startOffset, uint16_t maxBytes, uint16_t *usedBytes, uint8_t *buffer);  
+
+void      sdp_create_spp_service(uint8_t *service, int service_id, const char *name);
+
+#if defined __cplusplus
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/utils.c	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2009-2012 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ * 4. Any redistribution, use, or modification is done solely for
+ *    personal benefit and not for any commercial purpose or for
+ *    monetary gain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Please inquire about commercial licensing options at btstack@ringwald.ch
+ *
+ */
+
+/*
+ *  utils.c
+ *
+ *  General utility functions
+ *
+ *  Created by Matthias Ringwald on 7/23/09.
+ */
+
+#include "config.h"
+#include <btstack/utils.h>
+#include <stdio.h>
+#include "debug.h"
+
+void bt_store_16(uint8_t *buffer, uint16_t pos, uint16_t value){
+    buffer[pos++] = value;
+    buffer[pos++] = value >> 8;
+}
+
+void bt_store_32(uint8_t *buffer, uint16_t pos, uint32_t value){
+    buffer[pos++] = value;
+    buffer[pos++] = value >> 8;
+    buffer[pos++] = value >> 16;
+    buffer[pos++] = value >> 24;
+}
+
+void net_store_16(uint8_t *buffer, uint16_t pos, uint16_t value){
+    buffer[pos++] = value >> 8;
+    buffer[pos++] = value;
+}
+
+void net_store_32(uint8_t *buffer, uint16_t pos, uint32_t value){
+    buffer[pos++] = value >> 24;
+    buffer[pos++] = value >> 16;
+    buffer[pos++] = value >> 8;
+    buffer[pos++] = value;
+}
+
+void bt_flip_addr(bd_addr_t dest, bd_addr_t src){
+    dest[0] = src[5];
+    dest[1] = src[4];
+    dest[2] = src[3];
+    dest[3] = src[2];
+    dest[4] = src[1];
+    dest[5] = src[0];
+}
+
+void hexdump(void *data, int size){
+    int i;
+    for (i=0; i<size;i++){
+        log_info("%02X ", ((uint8_t *)data)[i]);
+    }
+    log_info("\n");
+}
+
+void printUUID(uint8_t *uuid) {
+    log_info("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+           uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
+           uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
+}
+
+static char bd_addr_to_str_buffer[6*3];  // 12:45:78:01:34:67\0
+char * bd_addr_to_str(bd_addr_t addr){
+    sprintf(bd_addr_to_str_buffer, "%02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+    return (char *) bd_addr_to_str_buffer;
+}
+
+void print_bd_addr( bd_addr_t addr){
+    log_info("%s", bd_addr_to_str(addr));
+}
+
+#ifndef EMBEDDED
+int sscan_bd_addr(uint8_t * addr_string, bd_addr_t addr){
+    unsigned int bd_addr_buffer[BD_ADDR_LEN];  //for sscanf, integer needed
+    // reset result buffer
+    int i;
+    for (i = 0; i < BD_ADDR_LEN; i++) {
+        bd_addr_buffer[i] = 0;
+    }
+    
+    // parse
+    int result = sscanf( (char *) addr_string, "%2x:%2x:%2x:%2x:%2x:%2x", &bd_addr_buffer[0], &bd_addr_buffer[1], &bd_addr_buffer[2],
+                        &bd_addr_buffer[3], &bd_addr_buffer[4], &bd_addr_buffer[5]);
+    // store
+    if (result == 6){
+        for (i = 0; i < BD_ADDR_LEN; i++) {
+            addr[i] = (uint8_t) bd_addr_buffer[i];
+        }
+    }
+    return (result == 6);
+}
+#endif
+
+/*  
+ * CRC (reversed crc) lookup table as calculated by the table generator in ETSI TS 101 369 V6.3.0.
+ */
+static const uint8_t crc8table[256] = {    /* reversed, 8-bit, poly=0x07 */
+    0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75, 0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B,
+    0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69, 0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67,
+    0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D, 0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43,
+    0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51, 0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F,
+    0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05, 0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B,
+    0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19, 0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17,
+    0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D, 0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33,
+    0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21, 0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F,
+    0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95, 0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B,
+    0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89, 0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87,
+    0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD, 0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3,
+    0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1, 0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF,
+    0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5, 0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB,
+    0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9, 0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7,
+    0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD, 0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3,
+    0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1, 0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF
+};
+
+#define CRC8_INIT  0xFF          // Initial FCS value 
+#define CRC8_OK    0xCF          // Good final FCS value 
+/*-----------------------------------------------------------------------------------*/
+uint8_t crc8(uint8_t *data, uint16_t len)
+{
+    uint16_t count;
+    uint8_t crc = CRC8_INIT;
+    for (count = 0; count < len; count++)
+        crc = crc8table[crc ^ data[count]];
+    return crc;
+}
+
+/*-----------------------------------------------------------------------------------*/
+uint8_t crc8_check(uint8_t *data, uint16_t len, uint8_t check_sum)
+{
+    uint8_t crc;
+    
+    crc = crc8(data, len);
+    
+    crc = crc8table[crc ^ check_sum];
+    if (crc == CRC8_OK) 
+        return 0;               /* Valid */
+    else 
+        return 1;               /* Failed */
+    
+}
+
+/*-----------------------------------------------------------------------------------*/
+uint8_t crc8_calc(uint8_t *data, uint16_t len)
+{
+    /* Ones complement */
+    return 0xFF - crc8(data, len);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/btstack/utils.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2009 by Matthias Ringwald
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
+ * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ *  utils.h
+ *
+ *  General utility functions
+ *
+ *  Created by Matthias Ringwald on 7/23/09.
+ */
+
+#pragma once
+
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+/**
+ * @brief hci connection handle type
+ */
+typedef uint16_t hci_con_handle_t;
+
+/**
+ * @brief Length of a bluetooth device address.
+ */
+#define BD_ADDR_LEN 6
+typedef uint8_t bd_addr_t[BD_ADDR_LEN];
+
+/**
+ * @brief The link key type
+ */
+#define LINK_KEY_LEN 16
+typedef uint8_t link_key_t[LINK_KEY_LEN]; 
+
+/**
+ * @brief The device name type
+ */
+#define DEVICE_NAME_LEN 248
+typedef uint8_t device_name_t[DEVICE_NAME_LEN+1]; 
+    
+    
+// helper for BT little endian format
+#define READ_BT_16( buffer, pos) ( ((uint16_t) buffer[pos]) | (((uint16_t)buffer[pos+1]) << 8))
+#define READ_BT_24( buffer, pos) ( ((uint32_t) buffer[pos]) | (((uint32_t)buffer[pos+1]) << 8) | (((uint32_t)buffer[pos+2]) << 16))
+#define READ_BT_32( buffer, pos) ( ((uint32_t) buffer[pos]) | (((uint32_t)buffer[pos+1]) << 8) | (((uint32_t)buffer[pos+2]) << 16) | (((uint32_t) buffer[pos+3])) << 24)
+
+// helper for SDP big endian format
+#define READ_NET_16( buffer, pos) ( ((uint16_t) buffer[pos+1]) | (((uint16_t)buffer[pos  ]) << 8))
+#define READ_NET_32( buffer, pos) ( ((uint32_t) buffer[pos+3]) | (((uint32_t)buffer[pos+2]) << 8) | (((uint32_t)buffer[pos+1]) << 16) | (((uint32_t) buffer[pos])) << 24)
+
+// HCI CMD OGF/OCF
+#define READ_CMD_OGF(buffer) (buffer[1] >> 2)
+#define READ_CMD_OCF(buffer) ((buffer[1] & 0x03) << 8 | buffer[0])
+
+// check if command complete event for given command
+#define COMMAND_COMPLETE_EVENT(event,cmd) ( event[0] == HCI_EVENT_COMMAND_COMPLETE && READ_BT_16(event,3) == cmd.opcode)
+#define COMMAND_STATUS_EVENT(event,cmd) ( event[0] == HCI_EVENT_COMMAND_STATUS && READ_BT_16(event,4) == cmd.opcode)
+
+// Code+Len=2, Pkts+Opcode=3; total=5
+#define OFFSET_OF_DATA_IN_COMMAND_COMPLETE 5
+
+// ACL Packet
+#define READ_ACL_CONNECTION_HANDLE( buffer ) ( READ_BT_16(buffer,0) & 0x0fff)
+#define READ_ACL_FLAGS( buffer )      ( buffer[1] >> 4 )
+#define READ_ACL_LENGTH( buffer )     (READ_BT_16(buffer, 2))
+
+// L2CAP Packet
+#define READ_L2CAP_LENGTH(buffer)     ( READ_BT_16(buffer, 4))
+#define READ_L2CAP_CHANNEL_ID(buffer) ( READ_BT_16(buffer, 6))
+
+void bt_store_16(uint8_t *buffer, uint16_t pos, uint16_t value);
+void bt_store_32(uint8_t *buffer, uint16_t pos, uint32_t value);
+void bt_flip_addr(bd_addr_t dest, bd_addr_t src);
+
+void net_store_16(uint8_t *buffer, uint16_t pos, uint16_t value);
+void net_store_32(uint8_t *buffer, uint16_t pos, uint32_t value);
+
+void hexdump(void *data, int size);
+void printUUID(uint8_t *uuid);
+
+// @deprecated please use more convenient bd_addr_to_str
+void print_bd_addr( bd_addr_t addr);
+char * bd_addr_to_str(bd_addr_t addr);
+
+int sscan_bd_addr(uint8_t * addr_string, bd_addr_t addr);
+    
+uint8_t crc8_check(uint8_t *data, uint16_t len, uint8_t check_sum);
+uint8_t crc8_calc(uint8_t *data, uint16_t len);
+
+#define BD_ADDR_CMP(a,b) memcmp(a,b, BD_ADDR_LEN)
+#define BD_ADDR_COPY(dest,src) memcpy(dest,src,BD_ADDR_LEN)
+
+#if defined __cplusplus
+}
+#endif
+        
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,382 @@
+
+#include "mbed.h"
+#include <btstack/hci_cmds.h>
+#include <btstack/run_loop.h>
+#include <btstack/sdp_util.h>
+#include "hci.h"
+#include "l2cap.h"
+#include "btstack_memory.h"
+#include "remote_device_db.h"
+#include "rfcomm.h"
+extern "C" {
+#include "sdp.h"
+}
+#include "config.h"
+#include "debug.h"
+#include "bd_addr.h"  // class bd_addr
+
+#include "Wiimote.h"
+#include "TB6612.h"
+
+// ----- Wallbot I/O Setting ----- 
+// Motor
+TB6612 right(p21,p12,p11);
+TB6612 left(p22,p14,p13);
+
+#define WII_REMOTE_CONNECTION_SYNC    0        // 0:old Wii Remote 1:New Wii Remote
+#define REPORTMODE_TT_BIT           0x00
+#define WII_REMOTE_REPORT_MODE       0x31
+#define MAX_SPEED 100
+
+#define HEARTBEAT_PERIOD_MS     1000
+#define INQUIRY_INTERVAL          15
+
+Serial pc(USBTX, USBRX);
+DigitalOut ActLED(LED1);
+
+
+
+static bd_addr_t keyboard;
+static int haveKeyboard = 0;
+static char                     lineBuffer[80];
+static short wii_remocon_channel_id=0;
+
+int DirectMode( Wiimote* wii, int stat )
+{
+    
+    if( wii->left )
+    {
+        right = -MAX_SPEED;
+        left = MAX_SPEED;
+    }
+    else if( wii->right )
+    {
+        right = MAX_SPEED;
+        left = -MAX_SPEED;
+    }    
+    else if( wii->up )
+    {
+        right = MAX_SPEED;
+        left = MAX_SPEED;
+    }
+    else if( wii->down )
+    {
+        right = -MAX_SPEED;
+        left = -MAX_SPEED;
+    }
+    else
+    {
+        right = 0;
+        left = 0;
+    }
+    
+    float factor = wii->wheel * 1.5f;
+    
+    if(factor > 100.0f )    factor = 100.0f; 
+    if(factor < -100.0f )    factor = -100.0f;
+    
+    printf("%f\t%f\r\n",wii->wheel,factor);
+    
+    int left_factor = (int)((factor <= 0.0) ? 100.0 : 100.0 - factor);
+    int right_factor = (int)((factor >= 0.0) ? 100.0 : 100.0 - (-factor));
+    
+    if( wii->one )
+    {
+        right = right_factor;
+        left = left_factor;
+    }
+    if( wii->two )
+    {
+        right = -left_factor;
+        left = -right_factor;
+    }
+    
+    return(stat);
+}
+
+int wall_bot_remote(char *c)
+{
+    Wiimote wii;
+    int ret = 0;
+    
+    wii.decode(c);
+    
+    ret = DirectMode( &wii ,ret );
+    
+    return(ret);
+}
+
+void wii_remote_report_mode(uint16_t channel,uint8_t tt,uint8_t mm)
+{
+    lineBuffer[0]=0xa2;
+    lineBuffer[1]=0x12;
+    lineBuffer[2]=tt;
+    lineBuffer[3]=mm;
+    l2cap_send_internal(channel,(uint8_t*)lineBuffer,4);
+}
+
+void wii_remote_request_status_report(uint16_t channel)
+{
+    lineBuffer[0]=0xa2;
+    lineBuffer[1]=0x15;
+    lineBuffer[2]=0x00;
+    l2cap_send_internal(channel,(uint8_t*)lineBuffer,3);
+}
+
+void hid_process_packet(uint16_t channel,unsigned char *hid_report,uint16_t size)
+{
+    if(hid_report[0]!=0xa1){
+        return;
+    }
+
+    if(hid_report[1]==0x30){
+        wii_remote_report_mode(channel,REPORTMODE_TT_BIT,WII_REMOTE_REPORT_MODE);
+        wii_remote_request_status_report(channel);
+    }
+
+    switch(hid_report[1]){
+    case    0x30:                                    //0x30:Core Buttons
+    case    0x31:                                    //0x31:Core Buttons and Accelerometer
+    case    0x35:                                    //0x35:Core Buttons and Accelerometer with 16 Extension Bytes
+        wall_bot_remote( (char*)&hid_report[2] );
+        break;
+    default:
+        break;
+    }
+    return;
+}
+
+static void l2cap_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
+{
+    if (packet_type == HCI_EVENT_PACKET){
+        switch(packet[0]){
+        case L2CAP_EVENT_INCOMING_CONNECTION:
+            log_info("L2CAP_EVENT_INCOMING_CONNECTION\n");
+            l2cap_accept_connection_internal(channel);
+            break;
+        case L2CAP_EVENT_CHANNEL_OPENED:
+            if (packet[2]) {
+                log_info("Connection failed\n");
+                return;
+            }
+            log_info("interrupt channel connected\n");
+            wii_remocon_channel_id=channel;
+             break;
+        case L2CAP_EVENT_CHANNEL_CLOSED:
+            wii_remocon_channel_id=0;
+        //    use_extension=0;
+            haveKeyboard = 0;
+            hci_send_cmd(&hci_inquiry, HCI_INQUIRY_LAP, INQUIRY_INTERVAL, 0);
+            break;
+        default:
+            break;
+        }    
+    }
+    if (packet_type == L2CAP_DATA_PACKET){
+        hid_process_packet(channel,packet,size);
+    }
+}
+
+//static uint16_t control_channel=0;
+static void l2cap_control_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
+{
+    if (packet_type == HCI_EVENT_PACKET){
+        switch(packet[0]){
+        case L2CAP_EVENT_INCOMING_CONNECTION:
+            log_info("L2CAP_EVENT_INCOMING_CONNECTION\n");
+            l2cap_accept_connection_internal(channel);
+            break;
+        case L2CAP_EVENT_CHANNEL_OPENED:
+            if (packet[2]) {
+               // xputs("control Connection failed\n");
+                return;
+            }
+          //  xputs("control channel connected\n");
+            l2cap_create_channel_internal(NULL, l2cap_packet_handler, keyboard, PSM_HID_INTERRUPT, 150);
+            //control_channel=channel;
+            break;
+        case L2CAP_EVENT_CHANNEL_CLOSED:
+            log_info("L2CAP_CHANNEL_CLOSED\n");
+            //control_channel=0;
+            break;
+        case L2CAP_EVENT_CREDITS:
+            break;
+        default:
+            log_info("l2cap:unknown(%02x)\n",packet[0]);
+            break;
+        }    
+    }
+}
+
+// Bluetooth logic
+static void packet_handler (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
+    bd_addr_t event_addr;
+    
+    switch (packet_type) {
+        case HCI_EVENT_PACKET:
+            switch (packet[0]) {
+                case BTSTACK_EVENT_STATE:
+                    // bt stack activated, get started - set local name
+                    if (packet[2] == HCI_STATE_WORKING) {
+                        hci_send_cmd(&hci_write_local_name, "mbed");
+                    }
+                    break;
+                
+                case HCI_EVENT_COMMAND_COMPLETE:
+                    if (COMMAND_COMPLETE_EVENT(packet, hci_read_bd_addr)){
+                        bt_flip_addr(event_addr, &packet[6]);
+                        log_info("BD-ADDR: %s\n", bd_addr_to_str(event_addr));
+                        break;
+                    }
+                    if (COMMAND_COMPLETE_EVENT(packet, hci_write_local_name)){
+//                        hci_discoverable_control(1);
+//                        hci_send_cmd(&hci_write_authentication_enable, 1);
+                        hci_send_cmd(&hci_write_authentication_enable, 0);
+                        break;
+                    }
+                    if (COMMAND_COMPLETE_EVENT(packet, hci_write_authentication_enable)){
+                    inquiry:
+
+                        log_info("Inquiry\n");
+                        hci_send_cmd(&hci_inquiry, HCI_INQUIRY_LAP, INQUIRY_INTERVAL, 0);
+
+                        break;
+                    }
+                    if (COMMAND_COMPLETE_EVENT(packet, hci_inquiry_cancel) ) {
+                        //l2cap_create_channel_internal(NULL, l2cap_packet_handler, keyboard, PSM_HID_INTERRUPT, 150);
+                        l2cap_create_channel_internal(NULL, l2cap_control_packet_handler, keyboard, PSM_HID_CONTROL, 150);
+                        break;
+                    }
+                    break;
+                case HCI_EVENT_INQUIRY_RESULT:
+                    
+                    // ignore further results
+                    if (haveKeyboard) break;
+                    
+                    // ignore none wii remocon
+                    if(
+                        !(packet[12]==0x04 && packet[13]==0x25 && packet[14]==0x00)
+                    &&    !(packet[12]==0x08 && packet[13]==0x05 && packet[14]==0x00)    //RVL-CNT-01-TR
+                    ){
+                        break;
+                    }
+
+                    // flip addr
+                    bt_flip_addr(keyboard, &packet[3]);
+                    
+                    // show
+                    log_info("found wii remocon:%s\n",bd_addr_to_str(keyboard));
+
+                    haveKeyboard = 1;
+                    hci_send_cmd(&hci_inquiry_cancel);
+                    break;
+                    
+                case HCI_EVENT_INQUIRY_COMPLETE:
+                    log_info("No wii remocon\n");
+                    goto inquiry;
+                    //break;
+                case HCI_EVENT_LINK_KEY_REQUEST:
+                    // deny link key request
+                    log_info("Link key request\n");
+                    bt_flip_addr(event_addr, &packet[2]);
+                    hci_send_cmd(&hci_link_key_request_negative_reply, &event_addr);
+                    break;
+                    
+                case HCI_EVENT_PIN_CODE_REQUEST:
+                    // inform about pin code request
+                    bt_flip_addr(event_addr, &packet[2]);
+                    //wii remocon
+#if    WII_REMOTE_CONNECTION_SYNC
+                    bt_flip_addr(packet+2, addr_global);
+#endif
+                    log_info("Pin code request - using %02x%02x%02x%02x%02x%02x\n",packet[2],packet[3],packet[4],packet[5],packet[6],packet[7]);
+                    memset(packet+2+6,0x00,10);
+                    hci_send_cmd(&hci_pin_code_request_reply, &event_addr, 6, &packet[2]);
+                    break;
+                case HCI_EVENT_CONNECTION_COMPLETE:
+                    //log_info("connection complete: status=%d\n",packet[2]);
+                    if(packet[2]){
+                        haveKeyboard=0;
+                        goto inquiry;
+                    }
+                    break;
+                default:
+                    break;
+            }
+            break;
+        default:
+            break;
+    }
+}
+
+static void  heartbeat_handler(struct timer *ts){
+    static int counter = 0;
+    counter++;
+
+    if(wii_remocon_channel_id){
+        lineBuffer[0]=0xa2;
+        lineBuffer[1]=0x11;
+        lineBuffer[2]=0x10<<(counter%4);        //LED Player1
+        if(l2cap_send_internal(wii_remocon_channel_id,(uint8_t*)lineBuffer,3)<0){
+            //error control init
+        }
+       ActLED = !ActLED;
+    }
+    run_loop_set_timer(ts, HEARTBEAT_PERIOD_MS);
+    run_loop_add_timer(ts);
+} 
+
+// main
+int main(void)
+{
+    pc.baud(921600);
+    log_info("%s\n", __FILE__);
+
+    // init LEDs
+    ActLED = 0;
+    
+    /// GET STARTED with BTstack ///
+    btstack_memory_init();
+    run_loop_init(RUN_LOOP_EMBEDDED);
+    
+    // init HCI
+    hci_transport_t* transport = hci_transport_usb_instance();
+    remote_device_db_t * remote_db = (remote_device_db_t *) &remote_device_db_memory;
+    hci_init(transport, NULL, NULL, remote_db);
+    
+    // init L2CAP
+    l2cap_init();
+    l2cap_register_packet_handler(packet_handler);
+    
+#if 0
+    // init RFCOMM
+    rfcomm_init();
+    rfcomm_register_packet_handler(packet_handler);
+    rfcomm_register_service_internal(NULL, rfcomm_channel_nr, 100);  // reserved channel, mtu=100
+
+
+    // init SDP, create record for SPP and register with SDP
+    sdp_init();
+    memset(spp_service_buffer, 0, sizeof(spp_service_buffer));
+    service_record_item_t * service_record_item = (service_record_item_t *) spp_service_buffer;
+    sdp_create_spp_service( (uint8_t*) &service_record_item->service_record, 1, "loopback");
+    log_info("SDP service buffer size: %u\n\r", (uint16_t) (sizeof(service_record_item_t) + de_get_len((uint8_t*) &service_record_item->service_record)));
+    sdp_register_service_internal(NULL, service_record_item);
+#endif
+    
+    // set one-shot timer
+    timer_source_t heartbeat;
+    heartbeat.process = &heartbeat_handler;
+    run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS);
+    run_loop_add_timer(&heartbeat);
+    
+    log_info("SPP loopback demo...\n\r");
+
+     // turn on!
+    hci_power_control(HCI_POWER_ON);
+
+    // go!
+    run_loop_execute();    
+
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/5e5da4a5990b
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usbbt/bd_addr.cpp	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,33 @@
+#include "mbed.h"
+#include "bd_addr.h"
+bd_addr::bd_addr()
+{
+
+}
+
+bd_addr::bd_addr(char* s)
+{
+    for(int i = 0; i <= 5; i++) {
+        ad[i] = strtol(s+i*3, NULL, 16);
+    }
+}
+
+uint8_t* bd_addr::data(uint8_t* addr)
+{
+    if (addr != NULL) {
+        ad[5] = addr[0];
+        ad[4] = addr[1];
+        ad[3] = addr[2];
+        ad[2] = addr[3];
+        ad[1] = addr[4];
+        ad[0] = addr[5];
+    }
+    return ad;
+}
+
+char* bd_addr::to_str()
+{
+    snprintf(ad_str, sizeof(ad_str), "%02X:%02X:%02X:%02X:%02X:%02X", 
+        ad[0], ad[1], ad[2], ad[3], ad[4], ad[5]);
+    return ad_str;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usbbt/bd_addr.h	Mon Jun 10 16:01:50 2013 +0000
@@ -0,0 +1,13 @@
+#ifndef BD_ADDR_H
+#define BD_ADDR_H
+class bd_addr {
+public:
+    bd_addr();
+    bd_addr(char* s);
+    uint8_t* data(uint8_t* addr = NULL);
+    char* to_str();
+private:
+    char ad_str[18];
+    uint8_t ad[6];
+};
+#endif //BD_ADDR_H