Revision 0:db1ba09e8bfa, committed 2012-07-10
- Comitter:
- hosei2
- Date:
- Tue Jul 10 11:36:47 2012 +0000
- Commit message:
- zzz
Changed in this revision
diff -r 000000000000 -r db1ba09e8bfa AutoEvents.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AutoEvents.cpp Tue Jul 10 11:36:47 2012 +0000
@@ -0,0 +1,161 @@
+
+/*
+Copyright (c) 2010 Peter Barrett
+
+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 "USBHost.h"
+#include "Utils.h"
+
+#define AUTOEVT(_class,_subclass,_protocol) (((_class) << 16) | ((_subclass) << 8) | _protocol)
+#define AUTO_KEYBOARD AUTOEVT(CLASS_HID,1,1)
+#define AUTO_MOUSE AUTOEVT(CLASS_HID,1,2)
+
+u8 auto_mouse[4]; // buttons,dx,dy,scroll
+u8 auto_keyboard[8]; // modifiers,reserved,keycode1..keycode6
+u8 auto_joystick[4]; // x,y,buttons,throttle
+
+void AutoEventCallback(int device, int endpoint, int status, u8* data, int len, void* userData)
+{
+ int evt = (int)userData;
+ switch (evt)
+ {
+ case AUTO_KEYBOARD:
+ printf("AUTO_KEYBOARD ");
+ break;
+ case AUTO_MOUSE:
+ printf("AUTO_MOUSE ");
+ break;
+ default:
+ printf("HUH ");
+ }
+ printfBytes("data",data,len);
+ USBInterruptTransfer(device,endpoint,data,len,AutoEventCallback,userData);
+}
+
+// Establish transfers for interrupt events
+void AddAutoEvent(int device, InterfaceDescriptor* id, EndpointDescriptor* ed)
+{
+ if ((ed->bmAttributes & 3) != ENDPOINT_INTERRUPT || !(ed->bEndpointAddress & 0x80))
+ return;
+
+ // Make automatic interrupt enpoints for known devices
+ u32 evt = AUTOEVT(id->bInterfaceClass,id->bInterfaceSubClass,id->bInterfaceProtocol);
+ u8* dst = 0;
+ int len;
+ switch (evt)
+ {
+ case AUTO_MOUSE:
+ dst = auto_mouse;
+ len = sizeof(auto_mouse);
+ break;
+ case AUTO_KEYBOARD:
+ dst = auto_keyboard;
+ len = sizeof(auto_keyboard);
+ break;
+ default:
+ printf("Interrupt endpoint %02X %08X\n",ed->bEndpointAddress,evt);
+ break;
+ }
+ if (dst)
+ {
+ printf("Auto Event for %02X %08X\n",ed->bEndpointAddress,evt);
+ USBInterruptTransfer(device,ed->bEndpointAddress,dst,len,AutoEventCallback,(void*)evt);
+ }
+}
+
+void PrintString(int device, int i)
+{
+ u8 buffer[256];
+ int le = GetDescriptor(device,DESCRIPTOR_TYPE_STRING,i,buffer,255);
+ if (le < 0)
+ return;
+ char* dst = (char*)buffer;
+ for (int j = 2; j < le; j += 2)
+ *dst++ = buffer[j];
+ *dst = 0;
+ printf("%d:%s\n",i,(const char*)buffer);
+ }
+
+// Walk descriptors and create endpoints for a given device
+int StartAutoEvent(int device, int configuration, int interfaceNumber)
+{
+ u8 buffer[255];
+ int err = GetDescriptor(device,DESCRIPTOR_TYPE_CONFIGURATION,0,buffer,255);
+ if (err < 0)
+ return err;
+
+ int len = buffer[2] | (buffer[3] << 8);
+ u8* d = buffer;
+ u8* end = d + len;
+ while (d < end)
+ {
+ if (d[1] == DESCRIPTOR_TYPE_INTERFACE)
+ {
+ InterfaceDescriptor* id = (InterfaceDescriptor*)d;
+ if (id->bInterfaceNumber == interfaceNumber)
+ {
+ d += d[0];
+ while (d < end && d[1] != DESCRIPTOR_TYPE_INTERFACE)
+ {
+ if (d[1] == DESCRIPTOR_TYPE_ENDPOINT)
+ AddAutoEvent(device,id,(EndpointDescriptor*)d);
+ d += d[0];
+ }
+ }
+ }
+ d += d[0];
+ }
+ return 0;
+}
+
+// Implemented in main.cpp
+int OnDiskInsert(int device);
+
+// Implemented in TestShell.cpp
+int OnBluetoothInsert(int device);
+
+void OnLoadDevice(int device, DeviceDescriptor* deviceDesc, InterfaceDescriptor* interfaceDesc)
+{
+ printf("LoadDevice %d %02X:%02X:%02X\n",device,interfaceDesc->bInterfaceClass,interfaceDesc->bInterfaceSubClass,interfaceDesc->bInterfaceProtocol);
+ char s[128];
+ for (int i = 1; i < 3; i++)
+ {
+ if (GetString(device,i,s,sizeof(s)) < 0)
+ break;
+ printf("%d: %s\n",i,s);
+ }
+
+ switch (interfaceDesc->bInterfaceClass)
+ {
+ case CLASS_MASS_STORAGE:
+ if (interfaceDesc->bInterfaceSubClass == 0x06 && interfaceDesc->bInterfaceProtocol == 0x50)
+ OnDiskInsert(device); // it's SCSI!
+ break;
+ case CLASS_WIRELESS_CONTROLLER:
+ if (interfaceDesc->bInterfaceSubClass == 0x01 && interfaceDesc->bInterfaceProtocol == 0x01)
+ OnBluetoothInsert(device); // it's bluetooth!
+ break;
+ default:
+ StartAutoEvent(device,1,0);
+ break;
+ }
+}
\ No newline at end of file
diff -r 000000000000 -r db1ba09e8bfa FATFileSystem.lib
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/FATFileSystem.lib Tue Jul 10 11:36:47 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_unsupported/code/FatFileSystem/
\ No newline at end of file
diff -r 000000000000 -r db1ba09e8bfa L2CAP.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/L2CAP.cpp Tue Jul 10 11:36:47 2012 +0000
@@ -0,0 +1,274 @@
+/*
+Copyright (c) 2010 Peter Barrett
+
+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 <stdio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "Utils.h"
+#include "hci.h"
+
+#define L2CAP_COMMAND_REJ 0x01
+#define L2CAP_CONN_REQ 0x02
+#define L2CAP_CONN_RSP 0x03
+#define L2CAP_CONF_REQ 0x04
+#define L2CAP_CONF_RSP 0x05
+#define L2CAP_DISCONN_REQ 0x06
+#define L2CAP_DISCONN_RSP 0x07
+#define L2CAP_ECHO_REQ 0x08
+#define L2CAP_ECHO_RSP 0x09
+#define L2CAP_INFO_REQ 0x0a
+#define L2CAP_INFO_RSP 0x0b
+
+
+ /* L2CAP command codes */
+ const char* L2CAP_ComandCodeStr(int c)
+ {
+ switch (c)
+ {
+ case L2CAP_COMMAND_REJ: return "L2CAP_COMMAND_REJ";
+ case L2CAP_CONN_REQ: return "L2CAP_CONN_REQ";
+ case L2CAP_CONN_RSP: return "L2CAP_CONN_RSP";
+ case L2CAP_CONF_REQ: return "L2CAP_CONF_REQ";
+ case L2CAP_CONF_RSP: return "L2CAP_CONF_RSP";
+ case L2CAP_DISCONN_REQ: return "L2CAP_DISCONN_REQ";
+ case L2CAP_DISCONN_RSP: return "L2CAP_DISCONN_RSP";
+ case L2CAP_ECHO_REQ: return "L2CAP_ECHO_REQ";
+ case L2CAP_ECHO_RSP: return "L2CAP_ECHO_RSP";
+ case L2CAP_INFO_REQ: return "L2CAP_INFO_REQ";
+ case L2CAP_INFO_RSP: return "L2CAP_INFO_RSP";
+ }
+ return "unknown";
+ }
+
+typedef struct
+{
+ u16 handle;
+ u16 length; // total
+ u16 l2capLength; // length -4
+ u16 cid; // Signaling packet CID = 1
+ u8 data[64]; // Largest thing to send!!! todo
+} L2CAPData;
+
+typedef struct
+{
+ u16 handle;
+ u16 length; // total
+ u16 l2capLength; // length -4
+ u16 cid; // Signaling packet CID = 1
+
+ // Payload
+ u8 cmd; //
+ u8 id;
+ u16 cmdLength; // total-8
+ u16 params[4]; // Params
+} L2CAPCmd;
+
+//
+void BTDevice::Init()
+{
+ memset(&_info,0,sizeof(inquiry_info));
+ _handle = 0;
+ _name[0] = 0;
+ _state = 0;
+}
+
+// virtual SocketHandler
+int BTDevice::Open(SocketInternal* sock, SocketAddrHdr* addr)
+{
+ L2CAPSocket* s = (L2CAPSocket*)sock;
+ L2CAPAddr* a = (L2CAPAddr*)addr;
+ s->scid = 0x40 + sock->ID-1; // are these reserved?
+ s->dcid = 0;
+ Connect(s->scid,a->psm);
+ return sock->ID;
+}
+
+// virtual SocketHandler
+int BTDevice::Send(SocketInternal* sock, const u8* data, int len)
+{
+ L2CAPData d;
+ L2CAPSocket* s = (L2CAPSocket*)sock;
+
+ d.handle = _handle | 0x2000;
+ d.length = 4 + len;
+ d.l2capLength = len;
+ d.cid = s->dcid;
+
+ if (len > 64)
+ return -1;
+ memcpy(d.data,data,len);
+ return Send((u8*)&d,len+8);
+}
+
+// virtual SocketHandler
+int BTDevice::Close(SocketInternal* sock)
+{
+ printf("L2CAP close %d\n",sock->ID);
+ L2CAPSocket* s = (L2CAPSocket*)sock;
+ return Disconnect(s->scid,s->dcid);
+}
+
+L2CAPSocket* BTDevice::SCIDToSocket(int scid)
+{
+ return (L2CAPSocket*)GetSocketInternal(scid-0x40+1);
+}
+
+int BTDevice::Send(const u8* data, int len)
+{
+ _transport->ACLSend(data,len);
+ return 0;
+}
+
+int BTDevice::Send(u8 c, u8 id, u16* params, int count)
+{
+ L2CAPCmd cmd;
+ cmd.handle = _handle | 0x2000;
+ cmd.length = 8 + count*2;
+
+ cmd.l2capLength = cmd.length-4;
+ cmd.cid = 1; // Signaling packet
+
+ cmd.cmd = c;
+ cmd.id = id;
+ cmd.cmdLength = count*2;
+ for (int i = 0; i < count; i++)
+ cmd.params[i] = params[i];
+ return Send((u8*)&cmd,cmd.length+4);
+}
+
+int BTDevice::Connect(int scid, int psm)
+{
+ u16 p[2];
+ p[0] = psm;
+ p[1] = scid;
+ return Send(L2CAP_CONN_REQ,_txid++,p,2);
+}
+
+int BTDevice::Disconnect(int scid, int dcid)
+{
+ u16 p[2];
+ p[0] = dcid;
+ p[1] = scid;
+ return Send(L2CAP_DISCONN_REQ,_txid++,p,2);
+}
+
+int BTDevice::ConfigureRequest(int dcid)
+{
+ u16 p[4];
+ p[0] = dcid;
+ p[1] = 0;
+ p[2] = 0x0201; // Options
+ p[3] = 0x02A0; // 672
+ return Send(L2CAP_CONF_REQ,_txid++,p,4);
+}
+
+int BTDevice::ConfigureResponse(u8 rxid, int dcid)
+{
+ u16 p[3];
+ p[0] = dcid;
+ p[1] = 0;
+ p[2] = 0;
+ return Send(L2CAP_CONF_RSP,rxid,p,3);
+}
+
+int BTDevice::DisconnectResponse(u8 rxid, int scid, int dcid)
+{
+ u16 p[2];
+ p[0] = dcid;
+ p[1] = scid;
+ return Send(L2CAP_DISCONN_RSP,rxid,p,2);
+}
+
+void BTDevice::Control(const u8* data, int len)
+{
+ int cc = data[8];
+ printf(L2CAP_ComandCodeStr(cc));
+ int result = LE16(data+16);
+ printf(" Result %d\n",result);
+ switch (cc)
+ {
+ case L2CAP_COMMAND_REJ:
+ break;
+ case L2CAP_CONN_REQ:
+ break;
+
+ // Response to our initial connect from Remote
+ case L2CAP_CONN_RSP:
+ {
+ if (result == 0)
+ {
+ int dcid = LE16(data+12);
+ int scid = LE16(data+14);
+ L2CAPSocket* s = SCIDToSocket(scid);
+ if (s)
+ {
+ s->dcid = dcid;
+ ConfigureRequest(dcid);
+ }
+ } else
+ printf("Connect failed?\n");
+ }
+ break;
+
+ case L2CAP_CONF_RSP:
+ {
+ int scid = LE16(data+12);
+ SocketInternal* s = (SocketInternal*)SCIDToSocket(scid);
+ if (s)
+ s->SetState(SocketState_Open);
+ }
+ break;
+
+ case L2CAP_CONF_REQ:
+ {
+ int scid = LE16(data+12);
+ L2CAPSocket* s = SCIDToSocket(scid);
+ if (s)
+ ConfigureResponse(data[9],s->dcid);
+ }
+ break;
+ }
+}
+
+void BTDevice::ACLRecv(const u8* data, int len)
+{
+ // printfBytes("L2CP",data,16);
+ int handle = LE16(data);
+ if (handle != (0x2000 | _handle))
+ return;
+
+ int cid = LE16(data+6);
+ if (cid == 1)
+ {
+ Control(data,len);
+ return;
+ }
+
+ SocketInternal* s = (SocketInternal*)SCIDToSocket(cid);
+ if (s)
+ s->Recv(data+8,LE16(data+2)-4);
+ else
+ printf("Bad event cid %d\n",cid);
+}
diff -r 000000000000 -r db1ba09e8bfa MassStorage.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MassStorage.cpp Tue Jul 10 11:36:47 2012 +0000
@@ -0,0 +1,180 @@
+
+/*
+Copyright (c) 2010 Peter Barrett
+
+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 "stdlib.h"
+#include "stdio.h"
+#include "string.h"
+
+#include "Utils.h"
+#include "USBHost.h"
+
+
+int MassStorage_ReadCapacity(int device, u32* blockCount, u32* blockSize);
+int MassStorage_ReadBlock(int device, u32 block, u8* dst);
+int MassStorage_WriteBlock(int device, u32 block, const u8* dst);
+
+
+#define ERR_BAD_CSW_SIGNATURE -200
+
+#define CBW_SIGNATURE 0x43425355
+#define CSW_SIGNATURE 0x53425355
+
+// Command Block
+typedef struct
+{
+ u32 Signature;
+ u32 Tag;
+ u32 TransferLength;
+ u8 Flags;
+ u8 LUN;
+ u8 CBLength;
+ u8 CB[16]; // only 6 really
+} CBW;
+
+// Status block
+typedef struct
+{
+ u32 Signature;
+ u32 Tag;
+ u32 DataResidue;
+ u8 Status;
+} CSW;
+
+int SCSIRequestSense(int device);
+
+int DoSCSI(int device, const u8* cmd, int cmdLen, int flags, u8* data, u32 transferLen)
+{
+ CBW cbw;
+ cbw.Signature = CBW_SIGNATURE;
+ cbw.Tag = 0;
+ cbw.TransferLength = transferLen;
+ cbw.Flags = flags;
+ cbw.LUN = 0;
+ cbw.CBLength = cmdLen;
+ memset(cbw.CB,0,sizeof(cbw.CB));
+ memcpy(cbw.CB,cmd,cmdLen);
+
+ int r;
+ r = USBBulkTransfer(device,0x01,(u8*)&cbw,31); // Send the command
+ if (r < 0)
+ return r;
+
+ if (data)
+ {
+ r = USBBulkTransfer(device,flags | 1,data,transferLen);
+ if (r < 0)
+ return r;
+ }
+
+ CSW csw;
+ csw.Signature = 0;
+ r = USBBulkTransfer(device,0x81,(u8*)&csw,13);
+ if (r < 0)
+ return r;
+
+ if (csw.Signature != CSW_SIGNATURE)
+ return ERR_BAD_CSW_SIGNATURE;
+
+ // ModeSense?
+ if (csw.Status == 1 && cmd[0] != 3)
+ return SCSIRequestSense(device);
+
+ return csw.Status;
+}
+
+int SCSITestUnitReady(int device)
+{
+ u8 cmd[6];
+ memset(cmd,0,6);
+ return DoSCSI(device,cmd,6,DEVICE_TO_HOST,0,0);
+}
+
+int SCSIRequestSense(int device)
+{
+ u8 cmd[6] = {0x03,0,0,0,18,0};
+ u8 result[18];
+ int r = DoSCSI(device,cmd,6,DEVICE_TO_HOST,result,18);
+ return r;
+}
+
+int SCSIInquiry(int device)
+{
+ u8 cmd[6] = {0x12,0,0,0,36,0};
+ u8 result[36+2];
+ result[36] = '\n';
+ result[37] = 0;
+ int r = DoSCSI(device,cmd,6,DEVICE_TO_HOST,result,36);
+ if (r == 0)
+ printf((const char*)result + 8);
+ return r;
+}
+
+int SCSIReadCapacity(int device, u32* blockCount, u32* blockSize)
+{
+ u8 cmd[10] = {0x25,0,0,0,8,0,0,0,0,0};
+ u8 result[8];
+ *blockSize = 0;
+ *blockCount = 0;
+ int r = DoSCSI(device,cmd,10,DEVICE_TO_HOST,result,8);
+ if (r == 0)
+ {
+ *blockCount = BE32(result);
+ *blockSize = BE32(result+4);
+ }
+ return r;
+}
+
+int SCSITransfer(int device, u32 blockAddr, u32 blockCount, u8* dst, u32 blockSize, int direction)
+{
+ // USB hardware will only do 4k per transfer
+ while (blockCount*blockSize > 4096)
+ {
+ int count = 4096/blockSize;
+ int r = SCSITransfer(device,blockAddr,count,dst,blockSize,direction);
+ dst += count*blockSize;
+ blockAddr += count;
+ blockCount -= count;
+ }
+
+ u8 cmd[10];
+ memset(cmd,0,10);
+ cmd[0] = (direction == DEVICE_TO_HOST) ? 0x28 : 0x2A;
+ BE32(blockAddr,cmd+2);
+ BE16(blockCount,cmd+7);
+ return DoSCSI(device,cmd,10,direction,dst,blockSize*blockCount);
+}
+
+int MassStorage_ReadCapacity(int device, u32* blockCount, u32* blockSize)
+{
+ return SCSIReadCapacity(device,blockCount,blockSize);
+}
+
+int MassStorage_Read(int device, u32 blockAddr, u32 blockCount, u8* dst, u32 blockSize = 512)
+{
+ return SCSITransfer(device,blockAddr,blockCount,dst,blockSize,DEVICE_TO_HOST);
+}
+
+int MassStorage_Write(int device, u32 blockAddr, u32 blockCount, u8* dst, u32 blockSize = 512)
+{
+ return SCSITransfer(device,blockAddr,blockCount,dst,blockSize,HOST_TO_DEVICE);
+}
diff -r 000000000000 -r db1ba09e8bfa Socket.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Socket.cpp Tue Jul 10 11:36:47 2012 +0000
@@ -0,0 +1,140 @@
+/*
+Copyright (c) 2010 Peter Barrett
+
+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 <stdio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "Utils.h"
+#include "Socket.h"
+
+#define MAX_SOCKET_HANDLERS 3
+#define MAX_SOCKETS 16
+
+class SocketInternalPad
+{
+ public:
+ SocketInternal si;
+ u8 pad[8];
+};
+
+class SocketManager
+{
+ SocketHandler* _handlers[MAX_SOCKET_HANDLERS];
+ SocketInternalPad _sockets[MAX_SOCKETS];
+
+ public:
+ SocketManager()
+ {
+ memset(_handlers,0,sizeof(_handlers));
+ memset(_sockets,0,sizeof(_sockets));
+ }
+
+ SocketHandler* GetHandler(int type)
+ {
+ if (type < 1 || type > MAX_SOCKET_HANDLERS)
+ return 0;
+ return _handlers[type - 1];
+ }
+
+ SocketInternal* GetInternal(int s)
+ {
+ if (s < 1 || s > MAX_SOCKETS)
+ return 0;
+ return &_sockets[s - 1].si;
+ }
+
+ int RegisterSocketHandler(int type, SocketHandler* handler)
+ {
+ if (type < 1 || type > MAX_SOCKET_HANDLERS)
+ return ERR_SOCKET_TYPE_NOT_FOUND;
+ _handlers[type - 1] = handler;
+ return 0;
+ }
+
+ int Open(int type, SocketAddrHdr* addr, SocketCallback callback, void* userData)
+ {
+ SocketHandler* h = GetHandler(type);
+ if (!h)
+ return ERR_SOCKET_TYPE_NOT_FOUND;
+
+ for (int i = 0; i < MAX_SOCKETS; i++)
+ {
+ SocketInternal* si = (SocketInternal*)(_sockets+i);
+ if (si->ID == 0)
+ {
+ si->ID = i+1;
+ si->Type = type;
+ si->Callback = callback;
+ si->userData = userData;
+ return h->Open(si,addr);
+ }
+ }
+ return ERR_SOCKET_NONE_LEFT;
+ }
+
+ int Send(int socket, const u8* data, int len)
+ {
+ SocketInternal* si = GetInternal(socket);
+ if (!si || si->ID != socket)
+ return ERR_SOCKET_NOT_FOUND;
+ return GetHandler(si->Type)->Send(si,data,len);
+ }
+
+ int Close(int socket)
+ {
+ SocketInternal* si = GetInternal(socket);
+ if (!si || si->ID != socket)
+ return ERR_SOCKET_NOT_FOUND;
+ si->ID = 0;
+ return GetHandler(si->Type)->Close(si);
+ }
+};
+
+SocketManager gSocketManager;
+
+int Socket_Open(int type, SocketAddrHdr* addr, SocketCallback callback, void* userData)
+{
+ return gSocketManager.Open(type,addr,callback,userData);
+}
+
+int Socket_Send(int socket, const u8* data, int len)
+{
+ return gSocketManager.Send(socket,data,len);
+}
+
+int Socket_Close(int socket)
+{
+ return gSocketManager.Close(socket);
+}
+
+int RegisterSocketHandler(int type, SocketHandler* handler)
+{
+ return gSocketManager.RegisterSocketHandler(type,handler);
+}
+
+SocketInternal* GetSocketInternal(int socket)
+{
+ return gSocketManager.GetInternal(socket);
+}
+
diff -r 000000000000 -r db1ba09e8bfa Socket.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Socket.h Tue Jul 10 11:36:47 2012 +0000
@@ -0,0 +1,96 @@
+/*
+Copyright (c) 2010 Peter Barrett
+
+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 SOCKET_H_INCLUDED
+#define SOCKET_H_INCLUDED
+
+#define SOCKET_HCI 1
+#define SOCKET_L2CAP 2
+#define SOCKET_RFCOM 3
+
+typedef struct
+{
+ u8 AddressSpecific[0]; // BDADDR,psm etc
+} SocketAddrHdr;
+
+enum SocketState
+{
+ SocketState_Unknown,
+ SocketState_Opening,
+ SocketState_Open,
+ SocketState_Closing,
+ SocketState_Closed
+};
+
+typedef void (*SocketCallback)(int socket, SocketState state, const u8* data, int len, void* userData);
+
+int Socket_Open(int type, SocketAddrHdr* addr, SocketCallback callback, void* userData); // Open a socket
+int Socket_Send(int socket, const u8* data, int len);
+int Socket_State(int socket);
+int Socket_Close(int socket);
+
+//===========================================================================
+//===========================================================================
+// Don't need to look at or use anything below this line:
+// Internal representation of socket
+
+class SocketHandler;
+class SocketInternal
+{
+ public:
+
+ u8 ID;
+ u8 State;
+ u8 Type;
+ u8 B0;
+ SocketCallback Callback;
+ void* userData;
+ u8 Data[0]; // Extra socket data starts here
+
+ void Recv(const u8* data, int len)
+ {
+ Callback(ID,(SocketState)State,data,len,userData);
+ }
+
+ void SetState(SocketState state)
+ {
+ State = state;
+ Callback(ID,(SocketState)State,0,0,userData);
+ }
+};
+
+class SocketHandler
+{
+ public:
+ virtual int Open(SocketInternal* sock, SocketAddrHdr* addr) = 0;
+ virtual int Send(SocketInternal* sock, const u8* data, int len) = 0;
+ virtual int Close(SocketInternal* sock) = 0;
+};
+
+int RegisterSocketHandler(int type, SocketHandler* handler);
+SocketInternal* GetSocketInternal(int socket);
+
+#define ERR_SOCKET_TYPE_NOT_FOUND -200
+#define ERR_SOCKET_NOT_FOUND -201
+#define ERR_SOCKET_NONE_LEFT -202
+
+#endif // SOCKET_H_INCLUDED
diff -r 000000000000 -r db1ba09e8bfa TestShell.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/TestShell.cpp Tue Jul 10 11:36:47 2012 +0000
@@ -0,0 +1,405 @@
+
+/*
+Copyright (c) 2010 Peter Barrett
+
+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 <stdio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "Utils.h"
+#include "USBHost.h"
+#include "hci.h"
+#include "mbed.h"
+
+DigitalOut L1(LED1);
+DigitalOut L2(LED2);
+
+void printf(const BD_ADDR* addr)
+{
+ const u8* a = addr->addr;
+ printf("%02X:%02X:%02X:%02X:%02X:%02X",a[5],a[4],a[3],a[2],a[1],a[0]);
+}
+
+#define MAX_HCL_SIZE 260
+#define MAX_ACL_SIZE 400
+
+class HCITransportUSB : public HCITransport
+{
+ int _device;
+ u8* _hciBuffer;
+ u8* _aclBuffer;
+
+ public:
+ void Open(int device, u8* hciBuffer, u8* aclBuffer)
+ {
+ _device = device;
+ _hciBuffer = hciBuffer;
+ _aclBuffer = aclBuffer;
+ USBInterruptTransfer(_device,0x81,_hciBuffer,MAX_HCL_SIZE,HciCallback,this);
+ USBBulkTransfer(_device,0x82,_aclBuffer,MAX_ACL_SIZE,AclCallback,this);
+ }
+
+ static void HciCallback(int device, int endpoint, int status, u8* data, int len, void* userData)
+ {
+ HCI* t = ((HCITransportUSB*)userData)->_target;
+ if (t)
+ t->HCIRecv(data,len);
+ USBInterruptTransfer(device,0x81,data,MAX_HCL_SIZE,HciCallback,userData);
+ }
+
+ static void AclCallback(int device, int endpoint, int status, u8* data, int len, void* userData)
+ {
+ HCI* t = ((HCITransportUSB*)userData)->_target;
+ if (t)
+ t->ACLRecv(data,len);
+ USBBulkTransfer(device,0x82,data,MAX_ACL_SIZE,AclCallback,userData);
+ }
+
+ virtual void HCISend(const u8* data, int len)
+ {
+ USBControlTransfer(_device,REQUEST_TYPE_CLASS, 0, 0, 0,(u8*)data,len);
+ }
+
+ virtual void ACLSend(const u8* data, int len)
+ {
+ USBBulkTransfer(_device,0x02,(u8*)data,len);
+ }
+};
+
+
+#define WII_REMOTE 0x042500
+
+class HIDBluetooth
+{
+ int _control; // Sockets for control (out) and interrupt (in)
+ int _interrupt;
+ int _devClass;
+ BD_ADDR _addr;
+ u8 _pad[2]; // Struct align
+
+public:
+ HIDBluetooth() : _control(0),_interrupt(0),_devClass(0) {};
+
+ bool InUse()
+ {
+ return _control != 0;
+ }
+
+ static void OnHidInterrupt(int socket, SocketState state, const u8* data, int len, void* userData)
+ {
+ HIDBluetooth* t = (HIDBluetooth*)userData;
+ if (data)
+ {
+ if (t->_devClass == WII_REMOTE && data[1] == 0x30)
+ {
+ printf("================wii====================\n");
+ t->Led();
+ t->Hid(); // ask for accelerometer
+ t->_devClass = 0;
+ }
+
+ const u8* d = data;
+ switch (d[1])
+ {
+ case 0x02:
+ {
+ int x = (signed char)d[3];
+ int y = (signed char)d[4];
+ printf("Mouse %2X dx:%d dy:%d\n",d[2],x,y);
+ }
+ break;
+
+ case 0x37: // Accelerometer http://wiki.wiimoteproject.com/Reports
+ {
+ int pad = (d[2] & 0x9F) | ((d[3] & 0x9F) << 8);
+ int x = (d[2] & 0x60) >> 5 | d[4] << 2;
+ int y = (d[3] & 0x20) >> 4 | d[5] << 2;
+ int z = (d[3] & 0x40) >> 5 | d[6] << 2;
+ printf("WII %04X %d %d %d\n",pad,x,y,z);
+
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////
+ L1 = (pad & 0x0800);
+ wait (0.1);
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////
+ }
+ break;
+ default:
+ printHex(data,len);
+ }
+ }
+ }
+
+ static void OnHidControl(int socket, SocketState state, const u8* data, int len, void* userData)
+ {
+ printf("OnHidControl\n");
+ if (data)
+ printHex(data,len);
+ }
+
+ void Open(BD_ADDR* bdAddr, inquiry_info* info)
+ {
+ printf("L2CAPAddr size %d\n",sizeof(L2CAPAddr));
+ _addr = *bdAddr;
+ L2CAPAddr sockAddr;
+ sockAddr.bdaddr = _addr;
+ sockAddr.psm = L2CAP_PSM_HID_INTR;
+ printf("Socket_Open size %d\n",sizeof(L2CAPAddr));
+ _interrupt = Socket_Open(SOCKET_L2CAP,&sockAddr.hdr,OnHidInterrupt,this);
+ sockAddr.psm = L2CAP_PSM_HID_CNTL;
+ _control = Socket_Open(SOCKET_L2CAP,&sockAddr.hdr,OnHidControl,this);
+
+ printfBytes("OPEN DEVICE CLASS",info->dev_class,3);
+ _devClass = (info->dev_class[0] << 16) | (info->dev_class[1] << 8) | info->dev_class[2];
+ }
+
+ void Close()
+ {
+ if (_control)
+ Socket_Close(_control);
+ if (_interrupt)
+ Socket_Close(_interrupt);
+ _control = _interrupt = 0;
+ }
+
+ void Led(int id = 0x10)
+ {
+ u8 led[3] = {0x52, 0x11, id};
+ if (_control)
+ Socket_Send(_control,led,3);
+ }
+
+ void Hid(int report = 0x37)
+ {
+ u8 hid[4] = { 0x52, 0x12, 0x00, report };
+ if (_control != -1)
+ Socket_Send(_control,hid,4);
+ }
+};
+
+
+HCI* gHCI = 0;
+
+#define MAX_HID_DEVICES 8
+
+int GetConsoleChar();
+class ShellApp
+{
+ char _line[64];
+ HIDBluetooth _hids[MAX_HID_DEVICES];
+
+public:
+ void Ready()
+ {
+ printf("HIDBluetooth %d\n",sizeof(HIDBluetooth));
+ memset(_hids,0,sizeof(_hids));
+ Inquiry();
+
+ }
+
+ // We have connected to a device
+ void ConnectionComplete(HCI* hci, connection_info* info)
+ {
+ printf("ConnectionComplete ");
+ BD_ADDR* a = &info->bdaddr;
+ printf(a);
+ BTDevice* bt = hci->Find(a);
+ HIDBluetooth* hid = NewHIDBluetooth();
+ printf("%08x %08x\n",bt,hid);
+ if (hid)
+ hid->Open(a,&bt->_info);
+ }
+
+ HIDBluetooth* NewHIDBluetooth()
+ {
+ for (int i = 0; i < MAX_HID_DEVICES; i++)
+ if (!_hids[i].InUse())
+ return _hids+i;
+ return 0;
+ }
+
+ void ConnectDevices()
+ {
+ BTDevice* devs[8];
+ int count = gHCI->GetDevices(devs,8);
+ for (int i = 0; i < count; i++)
+ {
+ printfBytes("DEVICE CLASS",devs[i]->_info.dev_class,3);
+ if (devs[i]->_handle == 0)
+ {
+ BD_ADDR* bd = &devs[i]->_info.bdaddr;
+ printf("Connecting to ");
+ printf(bd);
+ printf("\n");
+ gHCI->CreateConnection(bd);
+ }
+ }
+ }
+
+ const char* ReadLine()
+ {
+ int i;
+ for (i = 0; i < 255; )
+ {
+ USBLoop();
+ int c = GetConsoleChar();
+ if (c == -1)
+ continue;
+ if (c == '\n' || c == 13)
+ break;
+ _line[i++] = c;
+ }
+ _line[i] = 0;
+ return _line;
+ }
+
+ void Inquiry()
+ {
+ printf("Inquiry..\n");
+ gHCI->Inquiry();
+ }
+
+ void List()
+ {
+ #if 0
+ printf("%d devices\n",_deviceCount);
+ for (int i = 0; i < _deviceCount; i++)
+ {
+ printf(&_devices[i].info.bdaddr);
+ printf("\n");
+ }
+ #endif
+ }
+
+ void Connect()
+ {
+ ConnectDevices();
+ }
+
+ void Disconnect()
+ {
+ gHCI->DisconnectAll();
+ }
+
+ void CloseMouse()
+ {
+ }
+
+ void Quit()
+ {
+ CloseMouse();
+ }
+
+ void Run()
+ {
+ for(;;)
+ {
+ const char* cmd = ReadLine();
+ if (strcmp(cmd,"scan") == 0 || strcmp(cmd,"inquiry") == 0)
+ Inquiry();
+ else if (strcmp(cmd,"ls") == 0)
+ List();
+ else if (strcmp(cmd,"connect") == 0)
+ Connect();
+ else if (strcmp(cmd,"disconnect") == 0)
+ Disconnect();
+ else if (strcmp(cmd,"q")== 0)
+ {
+ Quit();
+ break;
+ } else {
+ printf("eh? %s\n",cmd);
+ }
+ }
+ }
+};
+
+// Instance
+ShellApp gApp;
+
+static int HciCallback(HCI* hci, HCI_CALLBACK_EVENT evt, const u8* data, int len)
+{
+ switch (evt)
+ {
+ case CALLBACK_READY:
+ printf("CALLBACK_READY\n");
+ gApp.Ready();
+ break;
+
+ case CALLBACK_INQUIRY_RESULT:
+ printf("CALLBACK_INQUIRY_RESULT ");
+ printf((BD_ADDR*)data);
+ printf("\n");
+ break;
+
+ case CALLBACK_INQUIRY_DONE:
+ printf("CALLBACK_INQUIRY_DONE\n");
+ gApp.ConnectDevices();
+ break;
+
+ case CALLBACK_REMOTE_NAME:
+ {
+ BD_ADDR* addr = (BD_ADDR*)data;
+ const char* name = (const char*)(data + 6);
+ printf(addr);
+ printf(" % s\n",name);
+ }
+ break;
+
+ case CALLBACK_CONNECTION_COMPLETE:
+ gApp.ConnectionComplete(hci,(connection_info*)data);
+ break;
+ };
+ return 0;
+}
+
+// these should be placed in the DMA SRAM
+typedef struct
+{
+ u8 _hciBuffer[MAX_HCL_SIZE];
+ u8 _aclBuffer[MAX_ACL_SIZE];
+} SRAMPlacement;
+
+HCITransportUSB _HCITransportUSB;
+HCI _HCI;
+
+u8* USBGetBuffer(u32* len);
+int OnBluetoothInsert(int device)
+{
+ printf("Bluetooth inserted of %d\n",device);
+ u32 sramLen;
+ u8* sram = USBGetBuffer(&sramLen);
+ sram = (u8*)(((u32)sram + 1023) & ~1023);
+ SRAMPlacement* s = (SRAMPlacement*)sram;
+ _HCITransportUSB.Open(device,s->_hciBuffer,s->_aclBuffer);
+ _HCI.Open(&_HCITransportUSB,HciCallback);
+ RegisterSocketHandler(SOCKET_L2CAP,&_HCI);
+ gHCI = &_HCI;
+ gApp.Inquiry();
+ return 0;
+}
+
+void TestShell()
+{
+ USBInit();
+ gApp.Run();
+}
diff -r 000000000000 -r db1ba09e8bfa USBHost.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost.cpp Tue Jul 10 11:36:47 2012 +0000
@@ -0,0 +1,1072 @@
+
+/*
+Copyright (c) 2010 Peter Barrett
+
+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 "USBHost.h"
+
+// Config (default uses x bytes)
+#define MAX_DEVICES 8 // Max number of devices
+#define MAX_ENDPOINTS_TOTAL 16 // Max number of endpoints total
+#define MAX_ENDPOINTS_PER_DEVICE 8 // Max number of endpoints for any one device
+
+#define USBLOG 1
+#if USBLOG
+#define LOG(...) printf(__VA_ARGS__)
+#else
+#define LOG(...) do {} while(0)
+#endif
+
+// USB host structures
+
+#define USB_RAM_SIZE 16*1024 // AHB SRAM block 1 TODO MACHINE DEPENDENT
+#define USB_RAM_BASE 0x2007C000
+
+#define TOKEN_SETUP 0
+#define TOKEN_IN 1
+#define TOKEN_OUT 2
+
+// Status flags from hub
+#define PORT_CONNECTION 0
+#define PORT_ENABLE 1
+#define PORT_SUSPEND 2
+#define PORT_OVER_CURRENT 3
+#define PORT_RESET 4
+#define PORT_POWER 8
+#define PORT_LOW_SPEED 9
+
+#define C_PORT_CONNECTION 16
+#define C_PORT_ENABLE 17
+#define C_PORT_SUSPEND 18
+#define C_PORT_OVER_CURRENT 19
+#define C_PORT_RESET 20
+
+typedef struct {
+ u8 bm_request_type;
+ u8 b_request;
+ u16 w_value;
+ u16 w_index;
+ u16 w_length;
+} Setup;
+
+
+// Hub stuff is kept private just to keep api simple
+int SetPortFeature(int device, int feature, int index);
+int ClearPortFeature(int device, int feature, int index);
+int SetPortPower(int device, int port);
+int SetPortReset(int device, int port);
+int GetPortStatus(int device, int port, u32* status);
+
+//===================================================================
+//===================================================================
+// Hardware defines
+
+// HcControl
+#define PeriodicListEnable 0x00000004
+#define IsochronousEnable 0x00000008
+#define ControlListEnable 0x00000010
+#define BulkListEnable 0x00000020
+#define OperationalMask 0x00000080
+#define HostControllerFunctionalState 0x000000C0
+
+// HcCommandStatus
+#define HostControllerReset 0x00000001
+#define ControlListFilled 0x00000002
+#define BulkListFilled 0x00000004
+
+// HcInterruptStatus Register
+#define WritebackDoneHead 0x00000002
+#define StartofFrame 0x00000004
+#define ResumeDetected 0x00000008
+#define UnrecoverableError 0x00000010
+#define FrameNumberOverflow 0x00000020
+#define RootHubStatusChange 0x00000040
+#define OwnershipChange 0x00000080
+#define MasterInterruptEnable 0x80000000
+
+// HcRhStatus
+#define SetGlobalPower 0x00010000
+#define DeviceRemoteWakeupEnable 0x00008000
+
+// HcRhPortStatus (hub 0, port 1)
+#define CurrentConnectStatus 0x00000001
+#define PortEnableStatus 0x00000002
+#define PortSuspendStatus 0x00000004
+#define PortOverCurrentIndicator 0x00000008
+#define PortResetStatus 0x00000010
+
+#define PortPowerStatus 0x00000100
+#define LowspeedDevice 0x00000200
+#define HighspeedDevice 0x00000400
+
+#define ConnectStatusChange (CurrentConnectStatus << 16)
+#define PortResetStatusChange (PortResetStatus << 16)
+
+
+#define TD_ROUNDING (u32)0x00040000
+#define TD_SETUP (u32)0x00000000
+#define TD_IN (u32)0x00100000
+#define TD_OUT (u32)0x00080000
+#define TD_DELAY_INT(x) (u32)((x) << 21)
+#define TD_TOGGLE_0 (u32)0x02000000
+#define TD_TOGGLE_1 (u32)0x03000000
+#define TD_CC (u32)0xF0000000
+
+// HostController EndPoint Descriptor
+typedef struct {
+ volatile u32 Control;
+ volatile u32 TailTd;
+ volatile u32 HeadTd;
+ volatile u32 Next;
+} HCED;
+
+// HostController Transfer Descriptor
+typedef struct {
+ volatile u32 Control;
+ volatile u32 CurrBufPtr;
+ volatile u32 Next;
+ volatile u32 BufEnd;
+} HCTD;
+
+// Host Controller Communication Area
+typedef struct {
+ volatile u32 InterruptTable[32];
+ volatile u16 FrameNumber;
+ volatile u16 FrameNumberPad;
+ volatile u32 DoneHead;
+ volatile u8 Reserved[120];
+} HCCA;
+
+//====================================================================================
+//====================================================================================
+
+class HostController;
+class Endpoint;
+class Device;
+
+// must be 3*16 bytes long
+class Endpoint
+{
+public:
+ HCED EndpointDescriptor; // Pointer to EndpointDescriptor == Pointer to Endpoint
+ HCTD TDHead;
+
+ enum State
+ {
+ Free,
+ NotQueued,
+ Idle,
+ SetupQueued,
+ DataQueued,
+ StatusQueued,
+ CallbackPending
+ };
+
+ volatile u8 CurrentState;
+ u8 Flags; // 0x80 In, 0x03 mask endpoint type
+
+ u16 Length;
+ u8* Data;
+ USBCallback Callback; // Must be a multiple of 16 bytes long
+ void* UserData;
+
+ int Address()
+ {
+ int ep = (EndpointDescriptor.Control >> 7) & 0xF;
+ if (ep)
+ ep |= Flags & 0x80;
+ return ep;
+ }
+
+ int Device()
+ {
+ return EndpointDescriptor.Control & 0x7F;
+ }
+
+ int Status()
+ {
+ return (TDHead.Control >> 28) & 0xF;
+ }
+
+ u32 Enqueue(u32 head)
+ {
+ if (CurrentState == NotQueued)
+ {
+ EndpointDescriptor.Next = head;
+ head = (u32)&EndpointDescriptor;
+ CurrentState = Idle;
+ }
+ return head;
+ }
+};
+
+class Device
+{
+public:
+ u8 _endpointMap[MAX_ENDPOINTS_PER_DEVICE*2];
+ u8 Hub;
+ u8 Port;
+ u8 Addr;
+ u8 Pad;
+
+ // Only if this device is a hub
+ u8 HubPortCount; // nonzero if this is a hub
+ u8 HubInterruptData;
+ u8 HubMap;
+ u8 HubMask;
+
+ int Flags; // 1 = Disconnected
+
+ Setup SetupBuffer;
+
+ // Allocate endpoint zero
+ int Init(DeviceDescriptor* d, int hub, int port, int addr, int lowSpeed)
+ {
+ Hub = hub;
+ Port = port;
+ Addr = addr;
+ Flags = lowSpeed;
+ memset(_endpointMap,0xFF,sizeof(_endpointMap));
+ return 0;
+ }
+
+ int SetEndpointIndex(int ep, int endpointIndex)
+ {
+ for (int i = 0; i < MAX_ENDPOINTS_PER_DEVICE*2; i += 2)
+ {
+ if (_endpointMap[i] == 0xFF) // Add endpoint to map
+ {
+ _endpointMap[i] = ep;
+ _endpointMap[i+1] = endpointIndex;
+ return 0;
+ }
+ }
+ return ERR_ENDPOINT_NONE_LEFT;
+ }
+
+ int GetEndpointIndex(int ep)
+ {
+ for (int i = 0; i < MAX_ENDPOINTS_PER_DEVICE*2; i += 2)
+ {
+ if (_endpointMap[i] == ep)
+ return _endpointMap[i+1];
+ if (_endpointMap[i] == 0xFF)
+ break;
+ }
+ return -1;
+ }
+};
+
+class HostController
+{
+public:
+ HCCA CommunicationArea;
+ Endpoint Endpoints[MAX_ENDPOINTS_TOTAL]; // Multiple of 16
+
+ Endpoint EndpointZero; // For device enumeration
+ HCTD _commonTail;
+ Setup _setupZero;
+
+ Device Devices[MAX_DEVICES];
+ u32 _frameNumber; // 32 bit ms counter
+
+ u8 _callbacksPending; // Endpoints with callbacks are pending, set from ISR via ProcessDoneQueue
+ u8 _rootHubStatusChange; // Root hub status has changed, set from ISR
+ u8 _unused0;
+ u8 _unused1;
+
+ u8 _connectPending; // Reset has initiated a connect
+ u8 _connectCountdown; // Number of ms left after reset before we can connect
+ u8 _connectHub; // Will connect on this hub
+ u8 _connectPort; // ... and this port
+
+ u8 SRAM[0]; // Start of free SRAM
+
+ void Loop()
+ {
+ u16 elapsed = CommunicationArea.FrameNumber - (u16)_frameNumber; // extend to 32 bits
+ _frameNumber += elapsed;
+
+ // Do callbacks, if any
+ while (_callbacksPending)
+ {
+ for (int i = 0; i < MAX_ENDPOINTS_TOTAL; i++)
+ {
+ Endpoint* endpoint = Endpoints + i;
+ if (endpoint->CurrentState == Endpoint::CallbackPending)
+ {
+ _callbacksPending--;
+ endpoint->CurrentState = Endpoint::Idle;
+ endpoint->Callback(endpoint->Device(),endpoint->Address(),endpoint->Status(),endpoint->Data,endpoint->Length,endpoint->UserData);
+ }
+ }
+ }
+
+ // Deal with changes on the root hub
+ if (_rootHubStatusChange)
+ {
+ u32 status = LPC_USB->HcRhPortStatus1;
+ _rootHubStatusChange = 0;
+ if (status >> 16)
+ {
+ HubStatusChange(0,1,status);
+ LPC_USB->HcRhPortStatus1 = status & 0xFFFF0000; // clear status changes
+ }
+ }
+
+ // Connect after reset timeout
+ if (_connectCountdown)
+ {
+ if (elapsed >= _connectCountdown)
+ {
+ _connectCountdown = 0;
+ Connect(_connectHub,_connectPort & 0x7F,_connectPort & 0x80);
+ } else
+ _connectCountdown -= elapsed;
+ }
+ }
+
+ // HubInterrupt - bitmap in dev->HubInterruptData
+ void HubInterrupt(int device)
+ {
+ Device* dev = &Devices[device-1];
+ for (int i = 0; i < dev->HubPortCount; i++)
+ {
+ int port = i+1;
+ if (dev->HubInterruptData & (1 << port))
+ {
+ u32 status = 0;
+ GetPortStatus(device,port,&status);
+ if (status >> 16)
+ {
+ if (_connectPending && (status & ConnectStatusChange))
+ continue; // Don't connect again until previous device has been added and addressed
+
+ HubStatusChange(device,port,status);
+ if (status & ConnectStatusChange)
+ ClearPortFeature(device,C_PORT_CONNECTION,port);
+ if (status & PortResetStatusChange)
+ ClearPortFeature(device,C_PORT_RESET,port);
+ }
+ }
+ }
+ }
+
+ static void HubInterruptCallback(int device, int endpoint, int status, u8* data, int len, void* userData)
+ {
+ HostController* controller = (HostController*)userData;
+ if (status == 0)
+ controller->HubInterrupt(device);
+ USBInterruptTransfer(device,endpoint,data,1,HubInterruptCallback,userData);
+ }
+
+ int InitHub(int device)
+ {
+ u8 buf[16];
+ int r= USBControlTransfer(device,DEVICE_TO_HOST | REQUEST_TYPE_CLASS | RECIPIENT_DEVICE,GET_DESCRIPTOR,(DESCRIPTOR_TYPE_HUB << 8),0,buf,sizeof(buf));
+ if (r < 0)
+ return ERR_HUB_INIT_FAILED;
+
+ // turn on power on the hubs ports
+ Device* dev = &Devices[device-1];
+ int ports = buf[2];
+ dev->HubPortCount = ports;
+ for (int i = 0; i < ports; i++)
+ SetPortPower(device,i+1);
+
+ // Enable hub change interrupts
+ return USBInterruptTransfer(device,0x81,&dev->HubInterruptData,1,HubInterruptCallback,this);
+ }
+
+ int AddEndpoint(int device, int ep, int attributes, int maxPacketSize, int interval)
+ {
+ LOG("AddEndpoint D:%02X A:%02X T:%02X P:%04X I:%02X\n",device,ep,attributes,maxPacketSize,interval);
+ Device* dev = &Devices[device-1];
+ Endpoint* endpoint = AllocateEndpoint(device,ep,attributes,maxPacketSize);
+ if (!endpoint)
+ return ERR_ENDPOINT_NONE_LEFT;
+ dev->SetEndpointIndex(ep,endpoint - Endpoints);
+ endpoint->EndpointDescriptor.Control |= dev->Flags; // Map in slow speed
+ return 0; // TODO ed->bInterval
+ }
+
+ int AddEndpoint(int device, EndpointDescriptor* ed)
+ {
+ return AddEndpoint(device,ed->bEndpointAddress,ed->bmAttributes,ed->wMaxPacketSize,ed->bInterval);
+ }
+
+ // allocate a endpoint
+ Endpoint* AllocateEndpoint(int device, int endpointAddress, int type, int maxPacketSize)
+ {
+ for (int i = 0; i < MAX_ENDPOINTS_TOTAL; i++)
+ {
+ Endpoint* ep = &Endpoints[i];
+ if (ep->CurrentState == 0)
+ {
+ //LOG("Allocated endpoint %d to %02X:%02X\n",i,device,endpointAddress);
+ ep->Flags = (endpointAddress & 0x80) | (type & 3);
+ ep->CurrentState = Endpoint::NotQueued;
+ ep->EndpointDescriptor.Control = (maxPacketSize << 16) | ((endpointAddress & 0x7F) << 7) | device;
+ return ep;
+ }
+ }
+ return 0;
+ }
+
+ Endpoint* GetEndpoint(int device, int ep)
+ {
+ if (device == 0)
+ {
+ //printf("WARNING: USING DEVICE 0\n");
+ return &EndpointZero;
+ }
+ if (device > MAX_DEVICES)
+ return 0;
+ int i = Devices[device-1].GetEndpointIndex(ep);
+ if (i == -1)
+ return 0;
+ return Endpoints + i;
+ }
+
+ int Transfer(Endpoint* endpoint, int token, u8* data, int len, int state)
+ {
+ //LOG("Transfer %02X T:%d Len:%d S:%d\n",endpoint->Address(),token,len,state);
+
+ int toggle = 0;
+ if (endpoint->Address() == 0)
+ toggle = (token == TOKEN_SETUP) ? TD_TOGGLE_0 : TD_TOGGLE_1;
+
+ if (token != TOKEN_SETUP)
+ token = (token == TOKEN_IN ? TD_IN : TD_OUT);
+
+ HCTD* head = &endpoint->TDHead;
+ HCTD* tail = &_commonTail;
+
+ head->Control = TD_ROUNDING | token | TD_DELAY_INT(0) | toggle | TD_CC;
+ head->CurrBufPtr = (u32)data;
+ head->BufEnd = (u32)(data + len - 1);
+ head->Next = (u32)tail;
+
+ HCED* ed = &endpoint->EndpointDescriptor;
+ ed->HeadTd = (u32)head | (ed->HeadTd & 0x00000002); // carry toggle
+ ed->TailTd = (u32)tail;
+
+ //HCTD* td = head;
+ //LOG("%04X TD %08X %08X %08X Next:%08X\n",CommunicationArea.FrameNumber,td->Control,td->CurrBufPtr,td->BufEnd,td->Next);
+ //LOG("%04X ED %08X %08X %08X\n",CommunicationArea.FrameNumber,ed->Control,ed->HeadTd,ed->TailTd);
+
+ switch (endpoint->Flags & 3)
+ {
+ case ENDPOINT_CONTROL:
+ LPC_USB->HcControlHeadED = endpoint->Enqueue(LPC_USB->HcControlHeadED); // May change state NotQueued->Idle
+ endpoint->CurrentState = state; // Get in before an int
+ LPC_USB->HcCommandStatus = LPC_USB->HcCommandStatus | ControlListFilled;
+ LPC_USB->HcControl = LPC_USB->HcControl | ControlListEnable;
+ break;
+
+ case ENDPOINT_BULK:
+ LPC_USB->HcBulkHeadED = endpoint->Enqueue(LPC_USB->HcBulkHeadED);
+ endpoint->CurrentState = state;
+ LPC_USB->HcCommandStatus = LPC_USB->HcCommandStatus | BulkListFilled;
+ LPC_USB->HcControl = LPC_USB->HcControl | BulkListEnable;
+ break;
+
+ case ENDPOINT_INTERRUPT:
+ CommunicationArea.InterruptTable[0] = endpoint->Enqueue(CommunicationArea.InterruptTable[0]);
+ endpoint->CurrentState = state;
+ LPC_USB->HcControl |= PeriodicListEnable;
+ break;
+ }
+ return 0;
+ }
+
+ // Remove an endpoint from an active queue
+ bool Remove(HCED* ed, volatile HCED** queue)
+ {
+ if (*queue == 0)
+ return false;
+ if (*queue == (volatile HCED*)ed)
+ {
+ *queue = (volatile HCED*)ed->Next; // At head of queue
+ return true;
+ }
+
+ volatile HCED* head = *queue;
+ while (head)
+ {
+ if (head->Next == (u32)ed)
+ {
+ head->Next = ed->Next;
+ return true;
+ }
+ head = (volatile HCED*)head->Next;
+ }
+ return false;
+ }
+
+ void Release(Endpoint* endpoint)
+ {
+ if (endpoint->CurrentState == Endpoint::NotQueued)
+ {
+ // Never event used it, nothing to do
+ }
+ else
+ {
+ HCED* ed = (HCED*)endpoint;
+ ed->Control |= 0x4000; // SKIP
+ switch (endpoint->Flags & 0x03)
+ {
+ case ENDPOINT_CONTROL:
+ Remove(ed,(volatile HCED**)&LPC_USB->HcControlHeadED);
+ break;
+ case ENDPOINT_BULK:
+ Remove(ed,(volatile HCED**)&LPC_USB->HcBulkHeadED);
+ break;
+ case ENDPOINT_INTERRUPT:
+ for (int i = 0; i < 32; i++)
+ Remove(ed,(volatile HCED**)&CommunicationArea.InterruptTable[i]);
+ break;
+ }
+
+ u16 fn = CommunicationArea.FrameNumber;
+ while (fn == CommunicationArea.FrameNumber)
+ ; // Wait for next frame
+
+ }
+
+ // In theory, the endpoint is now dead.
+ // TODO: Will Callbacks ever be pending? BUGBUG
+ memset(endpoint,0,sizeof(Endpoint));
+ }
+
+ // Pop the last TD from the list
+ HCTD* Reverse(HCTD* current)
+ {
+ HCTD *result = NULL,*temp;
+ while (current)
+ {
+ temp = (HCTD*)current->Next;
+ current->Next = (u32)result;
+ result = current;
+ current = temp;
+ }
+ return result;
+ }
+
+ // Called from interrupt...
+ // Control endpoints use a state machine to progress through the transfers
+ void ProcessDoneQueue(u32 tdList)
+ {
+ HCTD* list = Reverse((HCTD*)tdList);
+ while (list)
+ {
+ Endpoint* endpoint = (Endpoint*)(list-1);
+ list = (HCTD*)list->Next;
+ int ep = endpoint->Address();
+ bool in = endpoint->Flags & 0x80;
+ int status = (endpoint->TDHead.Control >> 28) & 0xF;
+
+ //LOG("ProcessDoneQueue %02X %08X\n",ep,endpoint->TDHead.Control);
+
+ if (status != 0)
+ {
+ LOG("ProcessDoneQueue status %02X %d\n",ep,status);
+ endpoint->CurrentState = Endpoint::Idle;
+ } else {
+ switch (endpoint->CurrentState)
+ {
+ case Endpoint::SetupQueued:
+ if (endpoint->Length == 0)
+ Transfer(endpoint,in ? TOKEN_OUT : TOKEN_IN,0,0,Endpoint::StatusQueued); // Skip Data Phase
+ else
+ Transfer(endpoint,in ? TOKEN_IN : TOKEN_OUT,endpoint->Data,endpoint->Length, Endpoint::DataQueued); // Setup is done, now Data
+ break;
+
+ case Endpoint::DataQueued:
+ if (endpoint->TDHead.CurrBufPtr)
+ endpoint->Length = endpoint->TDHead.CurrBufPtr - (u32)endpoint->Data;
+
+ if (ep == 0)
+ Transfer(endpoint,in ? TOKEN_OUT : TOKEN_IN,0,0,Endpoint::StatusQueued); // Data is done, now Status, Control only
+ else
+ endpoint->CurrentState = Endpoint::Idle;
+ break;
+
+ case Endpoint::StatusQueued: // Transaction is done
+ endpoint->CurrentState = Endpoint::Idle;
+ break;
+ }
+ }
+
+ // Complete, flag if we need a callback
+ if (endpoint->Callback && endpoint->CurrentState == Endpoint::Idle)
+ {
+ endpoint->CurrentState = Endpoint::CallbackPending;
+ _callbacksPending++;
+ }
+ }
+ }
+
+ // Hack to reset devices that don't want to connect
+ int AddDevice(int hub, int port, bool isLowSpeed)
+ {
+ int device = AddDeviceCore(hub,port,isLowSpeed);
+ if (device < 0)
+ {
+ LOG("========RETRY ADD DEVICE========\n"); // This will go for ever.. TODO power cycle root?
+ Disconnect(hub,port); // Could not read descriptor at assigned address, reset this port and try again
+ ResetPort(hub,port); // Cheap bluetooth dongles often need this on a hotplug
+ return -1;
+ }
+ return device;
+ }
+
+ int AddDeviceCore(int hub, int port, bool isLowSpeed)
+ {
+ int lowSpeed = isLowSpeed ? 0x2000 : 0;
+ DeviceDescriptor desc;
+ EndpointZero.EndpointDescriptor.Control = (8 << 16) | lowSpeed; // MaxPacketSize == 8
+ int r = GetDescriptor(0,DESCRIPTOR_TYPE_DEVICE,0,(u8*)&desc,8);
+ if (r < 0)
+ {
+ LOG("FAILED TO LOAD DESCRIPTOR FOR DEVICE 0\n");
+ return r;
+ }
+
+ EndpointZero.EndpointDescriptor.Control = (desc.bMaxPacketSize << 16) | lowSpeed; // Actual MaxPacketSize
+ r = GetDescriptor(0,DESCRIPTOR_TYPE_DEVICE,0,(u8*)&desc,sizeof(desc));
+ if (r < 0)
+ return r;
+
+ LOG("\nClass %02X found %04X:%04X\n\n",desc.bDeviceClass,desc.idVendor,desc.idProduct);
+
+ // Now assign the device an address, move off EndpointZero
+ int device = 0;
+ for (int i = 0; i < MAX_DEVICES; i++)
+ {
+ if (Devices[i].Port == 0)
+ {
+ device = i+1;
+ break;
+ }
+ }
+ if (!device)
+ return ERR_DEVICE_NONE_LEFT;
+
+ r = SetAddress(0,device);
+ if (r)
+ return r;
+ DelayMS(2);
+
+ // Now at a nonzero address, create control endpoint
+ Device* dev = &Devices[device-1];
+ dev->Init(&desc,hub,port,device,lowSpeed);
+ AddEndpoint(device,0,ENDPOINT_CONTROL,desc.bMaxPacketSize,0);
+ _connectPending = 0;
+
+ // Verify this all works
+ r = GetDescriptor(device,DESCRIPTOR_TYPE_DEVICE,0,(u8*)&desc,sizeof(desc));
+ if (r < 0)
+ return r;
+
+ // Set to interface 0 by default
+ // Calls LoadDevice if interface is found
+ r = SetConfigurationAndInterface(device,1,0,&desc);
+
+ if (desc.bDeviceClass == CLASS_HUB)
+ InitHub(device); // Handle hubs in this code
+
+ return device;
+ }
+
+ // Walk descriptors and create endpoints for a given device
+ // TODO configuration !=1, alternate settings etc.
+ int SetConfigurationAndInterface(int device, int configuration, int interfaceNumber, DeviceDescriptor* desc)
+ {
+ u8 buffer[255];
+ int err = GetDescriptor(device,DESCRIPTOR_TYPE_CONFIGURATION,0,buffer,sizeof(buffer));
+ if (err < 0)
+ return err;
+
+ err = SetConfiguration(device,configuration);
+ if (err < 0)
+ return err;
+
+ // Add the endpoints for this interface
+ int len = buffer[2] | (buffer[3] << 8);
+ u8* d = buffer;
+ u8* end = d + len;
+ InterfaceDescriptor* found = 0;
+ while (d < end)
+ {
+ if (d[1] == DESCRIPTOR_TYPE_INTERFACE)
+ {
+ InterfaceDescriptor* id = (InterfaceDescriptor*)d;
+ if (id->bInterfaceNumber == interfaceNumber)
+ {
+ found = id;
+ d += d[0];
+ while (d < end && d[1] != DESCRIPTOR_TYPE_INTERFACE)
+ {
+ switch (d[1])
+ {
+ case DESCRIPTOR_TYPE_ENDPOINT:
+ AddEndpoint(device,(EndpointDescriptor*)d);
+ break;
+ default:
+ LOG("Skipping descriptor %02X (%d bytes)\n",d[1],d[0]);
+ }
+ d += d[0];
+ }
+ }
+ }
+ d += d[0];
+ }
+
+ if (!found)
+ return ERR_INTERFACE_NOT_FOUND;
+ OnLoadDevice(device,desc,found);
+ return 0;
+ }
+
+ void Init()
+ {
+ LOG("USB INIT (Controller is %d bytes)\n",sizeof(*this));
+ memset(this,0,sizeof(HostController));
+ EndpointZero.CurrentState = Endpoint::NotQueued;
+ HWInit(&CommunicationArea);
+ DelayMS(10);
+ }
+
+ void ResetPort(int hub, int port)
+ {
+ LOG("ResetPort Hub:%d Port:%d\n",hub,port);
+ _connectPending++; // Only reset/add 1 device at a time
+ if (hub == 0)
+ LPC_USB->HcRhPortStatus1 = PortResetStatus; // Reset Root Hub, port 1
+ else
+ SetPortReset(hub,port); // or reset other hub
+ }
+
+ void Disconnect(int hub, int port)
+ {
+ LOG("Disconnect Hub:%d Port:%d\n",hub,port); // Mark a device for destruction
+ for (int i = 0; i < MAX_DEVICES; i++)
+ {
+ Device* dev = Devices + i;
+ if (dev->Port == port && dev->Hub == hub)
+ {
+ // Disconnect everything that is attached to this device if it is a hub
+ for (int p = 0; p < dev->HubPortCount; p++)
+ Disconnect(i+1,p+1);
+
+ // Now release endpoints
+ for (int j = 1; j < MAX_ENDPOINTS_PER_DEVICE*2; j += 2)
+ {
+ u8 endpointIndex = dev->_endpointMap[j];
+ if (endpointIndex != 0xFF)
+ Release(Endpoints + endpointIndex);
+ }
+ dev->Port = 0; // Device is now free
+ dev->Flags = 0;
+ return;
+ }
+ }
+ }
+
+ // called after reset
+ void Connect(int hub, int port, bool lowspeed)
+ {
+ LOG("Connect Hub:%d Port:%d %s\n",hub,port,lowspeed ? "slow" : "full");
+ AddDevice(hub,port,lowspeed);
+ }
+
+ // Called from interrupt
+ void HubStatusChange(int hub, int port, u32 status)
+ {
+ LOG("HubStatusChange Hub:%d Port:%d %08X\n",hub,port,status);
+ if (status & ConnectStatusChange)
+ {
+ if (status & CurrentConnectStatus) // Connecting
+ ResetPort(hub,port); // Reset to initiate connect (state machine?)
+ else
+ Disconnect(hub,port);
+ }
+
+ if (status & PortResetStatusChange)
+ {
+ if (!(status & PortResetStatus))
+ {
+ _connectCountdown = 200; // Schedule a connection in 200ms
+ if (status & LowspeedDevice)
+ port |= 0x80;
+ _connectHub = hub;
+ _connectPort = port;
+ }
+ }
+ }
+
+ #define HOST_CLK_EN (1<<0)
+ #define PORTSEL_CLK_EN (1<<3)
+ #define AHB_CLK_EN (1<<4)
+ #define CLOCK_MASK (HOST_CLK_EN | PORTSEL_CLK_EN | AHB_CLK_EN)
+
+ #define FRAMEINTERVAL (12000-1) // 1ms
+ #define DEFAULT_FMINTERVAL ((((6 * (FRAMEINTERVAL - 210)) / 7) << 16) | FRAMEINTERVAL)
+
+ void DelayMS(int ms)
+ {
+ u16 f = ms + CommunicationArea.FrameNumber;
+ while (f != CommunicationArea.FrameNumber)
+ ;
+ }
+
+ static void HWInit(HCCA* cca)
+ {
+ NVIC_DisableIRQ(USB_IRQn);
+
+ // 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)
+ ;
+
+ // We are a Host
+ LPC_USB->OTGStCtrl |= 1;
+ LPC_USB->USBClkCtrl &= ~PORTSEL_CLK_EN; // we don't need port selection clock until we do OTG
+
+ // configure USB pins
+ LPC_PINCON->PINSEL1 &= ~((3<<26)|(3<<28));
+ LPC_PINCON->PINSEL1 |= ((1<<26)|(1<<28)); // USB D+/D-
+
+ LPC_PINCON->PINSEL3 &= ~((3 << 6) | (3 << 22)); // USB_PPWR, USB_OVRCR
+ LPC_PINCON->PINSEL3 |= ((2 << 6) | (2 << 22));
+
+ LPC_PINCON->PINSEL4 &= ~(3 << 18); // USB_CONNECT
+ LPC_PINCON->PINSEL4 |= (1 << 18);
+
+ // Reset OHCI block
+ LPC_USB->HcControl = 0;
+ LPC_USB->HcControlHeadED = 0;
+ LPC_USB->HcBulkHeadED = 0;
+
+ LPC_USB->HcCommandStatus = HostControllerReset;
+ LPC_USB->HcFmInterval = DEFAULT_FMINTERVAL;
+ LPC_USB->HcPeriodicStart = FRAMEINTERVAL*90/100;
+
+ LPC_USB->HcControl = (LPC_USB->HcControl & (~HostControllerFunctionalState)) | OperationalMask;
+ LPC_USB->HcRhStatus = SetGlobalPower;
+
+ LPC_USB->HcHCCA = (u32)cca;
+ LPC_USB->HcInterruptStatus |= LPC_USB->HcInterruptStatus;
+ LPC_USB->HcInterruptEnable = MasterInterruptEnable | WritebackDoneHead | RootHubStatusChange | FrameNumberOverflow;
+
+ NVIC_SetPriority(USB_IRQn, 0);
+ NVIC_EnableIRQ(USB_IRQn);
+ while (cca->FrameNumber < 10)
+ ; // 10ms delay before diving in
+ }
+};
+
+//====================================================================================
+//====================================================================================
+// Host controller instance and Interrupt handler
+
+static HostController _controller __attribute__((at(USB_RAM_BASE)));
+
+extern "C" void USB_IRQHandler(void) __irq;
+void USB_IRQHandler (void) __irq
+{
+ u32 int_status = LPC_USB->HcInterruptStatus;
+
+ if (int_status & RootHubStatusChange) // Root hub status change
+ _controller._rootHubStatusChange++; // Just flag the controller, will be processed in USBLoop
+
+ u32 head = 0;
+ if (int_status & WritebackDoneHead)
+ {
+ head = _controller.CommunicationArea.DoneHead; // Writeback Done
+ _controller.CommunicationArea.DoneHead = 0;
+ }
+ LPC_USB->HcInterruptStatus = int_status;
+
+ if (head)
+ _controller.ProcessDoneQueue(head); // TODO - low bit can be set BUGBUG
+}
+
+//====================================================================================
+//====================================================================================
+// API Methods
+
+void USBInit()
+{
+ return _controller.Init();
+}
+
+void USBLoop()
+{
+ return _controller.Loop();
+}
+
+u8* USBGetBuffer(u32* len)
+{
+ *len = USB_RAM_SIZE - sizeof(HostController);
+ return _controller.SRAM;
+}
+
+static Setup* GetSetup(int device)
+{
+ if (device == 0)
+ return &_controller._setupZero;
+
+ if (device < 1 || device > MAX_DEVICES)
+ return 0;
+ return &_controller.Devices[device-1].SetupBuffer;
+}
+
+// Loop until IO on endpoint is complete
+static int WaitIODone(Endpoint* endpoint)
+{
+ if (endpoint->CurrentState == Endpoint::NotQueued)
+ return 0;
+ while (endpoint->CurrentState != Endpoint::Idle)
+ USBLoop(); // May generate callbacks, mount or unmount devices etc
+ int status = endpoint->Status();
+ if (status == 0)
+ return endpoint->Length;
+ return -status;
+}
+
+int USBTransfer(int device, int ep, u8 flags, u8* data, int length, USBCallback callback, void* userData)
+{
+ Endpoint* endpoint = _controller.GetEndpoint(device,ep);
+ if (!endpoint)
+ return ERR_ENDPOINT_NOT_FOUND;
+
+ WaitIODone(endpoint);
+ endpoint->Flags = flags;
+ endpoint->Data = data;
+ endpoint->Length = length;
+ endpoint->Callback = callback;
+ endpoint->UserData = userData;
+ if (ep == 0)
+ _controller.Transfer(endpoint,TOKEN_SETUP,(u8*)GetSetup(device),8,Endpoint::SetupQueued);
+ else
+ _controller.Transfer(endpoint,flags & 0x80 ? TOKEN_IN : TOKEN_OUT,data,length,Endpoint::DataQueued);
+ if (callback)
+ return IO_PENDING;
+ return WaitIODone(endpoint);
+}
+
+int USBControlTransfer(int device, int request_type, int request, int value, int index, u8* data, int length, USBCallback callback, void * userData)
+{
+ Setup* setup = GetSetup(device);
+ if (!setup)
+ return ERR_DEVICE_NOT_FOUND;
+
+ // Async control calls may overwrite setup buffer of previous call, so we need to wait before setting up next call
+ WaitIODone(_controller.GetEndpoint(device,0));
+
+ setup->bm_request_type = request_type;
+ setup->b_request = request;
+ setup->w_value = value;
+ setup->w_index = index;
+ setup->w_length = length;
+ return USBTransfer(device,0,request_type & DEVICE_TO_HOST,data,length,callback,userData);
+}
+
+int USBInterruptTransfer(int device, int ep, u8* data, int length, USBCallback callback, void* userData)
+{
+ return USBTransfer(device,ep,(ep & 0x80) | ENDPOINT_INTERRUPT,data,length,callback,userData);
+}
+
+int USBBulkTransfer(int device, int ep, u8* data, int length, USBCallback callback, void* userData)
+{
+ return USBTransfer(device,ep,(ep & 0x80) | ENDPOINT_BULK,data,length,callback,userData);
+}
+
+int GetDescriptor(int device, int descType,int descIndex, u8* data, int length)
+{
+ return USBControlTransfer(device,DEVICE_TO_HOST | RECIPIENT_DEVICE, GET_DESCRIPTOR,(descType << 8)|(descIndex), 0, data, length, 0);
+}
+
+int GetString(int device, int index, char* dst, int length)
+{
+ u8 buffer[255];
+ int le = GetDescriptor(device,DESCRIPTOR_TYPE_STRING,index,buffer,sizeof(buffer));
+ if (le < 0)
+ return le;
+ if (length < 1)
+ return -1;
+ length <<= 1;
+ if (le > length)
+ le = length;
+ for (int j = 2; j < le; j += 2)
+ *dst++ = buffer[j];
+ *dst = 0;
+ return (le>>1)-1;
+}
+
+int SetAddress(int device, int new_addr)
+{
+ return USBControlTransfer(device,HOST_TO_DEVICE | RECIPIENT_DEVICE, SET_ADDRESS, new_addr, 0, 0, 0, 0);
+}
+
+int SetConfiguration(int device, int configNum)
+{
+ return USBControlTransfer(device,HOST_TO_DEVICE | RECIPIENT_DEVICE, SET_CONFIGURATION, configNum, 0, 0, 0, 0);
+}
+
+int SetInterface(int device, int ifNum, int altNum)
+{
+ return USBControlTransfer(device,HOST_TO_DEVICE | RECIPIENT_INTERFACE, SET_INTERFACE, altNum, ifNum, 0, 0, 0);
+}
+
+// HUB stuff
+int SetPortFeature(int device, int feature, int index)
+{
+ return USBControlTransfer(device,HOST_TO_DEVICE | REQUEST_TYPE_CLASS | RECIPIENT_OTHER,SET_FEATURE,feature,index,0,0);
+}
+
+int ClearPortFeature(int device, int feature, int index)
+{
+ return USBControlTransfer(device,HOST_TO_DEVICE | REQUEST_TYPE_CLASS | RECIPIENT_OTHER,CLEAR_FEATURE,feature,index,0,0);
+}
+
+int SetPortPower(int device, int port)
+{
+ int r = SetPortFeature(device,PORT_POWER,port);
+ _controller.DelayMS(20); // 80ms to turn on a hubs power... DESCRIPTOR? todo
+ return r;
+}
+
+int SetPortReset(int device, int port)
+{
+ return SetPortFeature(device,PORT_RESET,port);
+}
+
+int GetPortStatus(int device, int port, u32* status)
+{
+ return USBControlTransfer(device,DEVICE_TO_HOST | REQUEST_TYPE_CLASS | RECIPIENT_OTHER,GET_STATUS,0,port,(u8*)status,4);
+}
\ No newline at end of file
diff -r 000000000000 -r db1ba09e8bfa USBHost.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost.h Tue Jul 10 11:36:47 2012 +0000
@@ -0,0 +1,200 @@
+
+/*
+Copyright (c) 2010 Peter Barrett
+
+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 USBHOST_H
+#define USBHOST_H
+
+#ifndef u8
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned long u32;
+
+typedef char s8;
+typedef short s16;
+typedef char s32;
+#endif
+
+#define ENDPOINT_CONTROL 0
+#define ENDPOINT_ISOCRONOUS 1
+#define ENDPOINT_BULK 2
+#define ENDPOINT_INTERRUPT 3
+
+#define DESCRIPTOR_TYPE_DEVICE 1
+#define DESCRIPTOR_TYPE_CONFIGURATION 2
+#define DESCRIPTOR_TYPE_STRING 3
+#define DESCRIPTOR_TYPE_INTERFACE 4
+#define DESCRIPTOR_TYPE_ENDPOINT 5
+
+#define DESCRIPTOR_TYPE_HID 0x21
+#define DESCRIPTOR_TYPE_REPORT 0x22
+#define DESCRIPTOR_TYPE_PHYSICAL 0x23
+#define DESCRIPTOR_TYPE_HUB 0x29
+
+enum USB_CLASS_CODE
+{
+ CLASS_DEVICE,
+ CLASS_AUDIO,
+ CLASS_COMM_AND_CDC_CONTROL,
+ CLASS_HID,
+ CLASS_PHYSICAL = 0x05,
+ CLASS_STILL_IMAGING,
+ CLASS_PRINTER,
+ CLASS_MASS_STORAGE,
+ CLASS_HUB,
+ CLASS_CDC_DATA,
+ CLASS_SMART_CARD,
+ CLASS_CONTENT_SECURITY = 0x0D,
+ CLASS_VIDEO = 0x0E,
+ CLASS_DIAGNOSTIC_DEVICE = 0xDC,
+ CLASS_WIRELESS_CONTROLLER = 0xE0,
+ CLASS_MISCELLANEOUS = 0xEF,
+ CLASS_APP_SPECIFIC = 0xFE,
+ CLASS_VENDOR_SPECIFIC = 0xFF
+};
+
+#define DEVICE_TO_HOST 0x80
+#define HOST_TO_DEVICE 0x00
+#define REQUEST_TYPE_CLASS 0x20
+#define RECIPIENT_DEVICE 0x00
+#define RECIPIENT_INTERFACE 0x01
+#define RECIPIENT_ENDPOINT 0x02
+#define RECIPIENT_OTHER 0x03
+
+#define GET_STATUS 0
+#define CLEAR_FEATURE 1
+#define SET_FEATURE 3
+#define SET_ADDRESS 5
+#define GET_DESCRIPTOR 6
+#define SET_DESCRIPTOR 7
+#define GET_CONFIGURATION 8
+#define SET_CONFIGURATION 9
+#define GET_INTERFACE 10
+#define SET_INTERFACE 11
+#define SYNCH_FRAME 11
+
+// -5 is nak
+/*
+0010 ACK Handshake
+1010 NAK Handshake
+1110 STALL Handshake
+0110 NYET (No Response Yet)
+*/
+
+#define IO_PENDING -100
+#define ERR_ENDPOINT_NONE_LEFT -101
+#define ERR_ENDPOINT_NOT_FOUND -102
+#define ERR_DEVICE_NOT_FOUND -103
+#define ERR_DEVICE_NONE_LEFT -104
+#define ERR_HUB_INIT_FAILED -105
+#define ERR_INTERFACE_NOT_FOUND -106
+
+typedef struct
+{
+ u8 bLength;
+ u8 bDescriptorType;
+ u16 bcdUSB;
+ u8 bDeviceClass;
+ u8 bDeviceSubClass;
+ u8 bDeviceProtocol;
+ u8 bMaxPacketSize;
+ u16 idVendor;
+ u16 idProduct;
+ u16 bcdDevice; // version
+ u8 iManufacturer;
+ u8 iProduct;
+ u8 iSerialNumber;
+ u8 bNumConfigurations;
+} DeviceDescriptor; // 16 bytes
+
+typedef struct
+{
+ u8 bLength;
+ u8 bDescriptorType;
+ u16 wTotalLength;
+ u8 bNumInterfaces;
+ u8 bConfigurationValue; // Value to use as an argument to select this configuration
+ u8 iConfiguration; // Index of String Descriptor describing this configuration
+ u8 bmAttributes; // Bitmap D7 Reserved, set to 1. (USB 1.0 Bus Powered),D6 Self Powered,D5 Remote Wakeup,D4..0 = 0
+ u8 bMaxPower; // Maximum Power Consumption in 2mA units
+} ConfigurationDescriptor;
+
+typedef struct
+{
+ u8 bLength;
+ u8 bDescriptorType;
+ u8 bInterfaceNumber;
+ u8 bAlternateSetting;
+ u8 bNumEndpoints;
+ u8 bInterfaceClass;
+ u8 bInterfaceSubClass;
+ u8 bInterfaceProtocol;
+ u8 iInterface; // Index of String Descriptor Describing this interface
+} InterfaceDescriptor;
+
+typedef struct
+{
+ u8 bLength;
+ u8 bDescriptorType;
+ u8 bEndpointAddress; // Bits 0:3 endpoint, Bits 7 Direction 0 = Out, 1 = In (Ignored for Control Endpoints)
+ u8 bmAttributes; // Bits 0:1 00 = Control, 01 = Isochronous, 10 = Bulk, 11 = Interrupt
+ u16 wMaxPacketSize;
+ u8 bInterval; // Interval for polling endpoint data transfers.
+} EndpointDescriptor;
+
+typedef struct {
+ u8 bLength;
+ u8 bDescriptorType;
+ u16 bcdHID;
+ u8 bCountryCode;
+ u8 bNumDescriptors;
+ u8 bDescriptorType2;
+ u16 wDescriptorLength;
+} HIDDescriptor;
+
+//============================================================================
+//============================================================================
+
+
+void USBInit();
+void USBLoop();
+u8* USBGetBuffer(u32* len);
+
+// Optional callback for transfers, called at interrupt time
+typedef void (*USBCallback)(int device, int endpoint, int status, u8* data, int len, void* userData);
+
+// Transfers
+int USBControlTransfer(int device, int request_type, int request, int value, int index, u8* data, int length, USBCallback callback = 0, void* userData = 0);
+int USBInterruptTransfer(int device, int ep, u8* data, int length, USBCallback callback = 0, void* userData = 0);
+int USBBulkTransfer(int device, int ep, u8* data, int length, USBCallback callback = 0, void* userData = 0);
+
+// Standard Device methods
+int GetDescriptor(int device, int descType, int descIndex, u8* data, int length);
+int GetString(int device, int index, char* dst, int length);
+int SetAddress(int device, int new_addr);
+int SetConfiguration(int device, int configNum);
+int SetInterface(int device, int ifNum, int altNum);
+
+// Implemented to notify app of the arrival of a device
+void OnLoadDevice(int device, DeviceDescriptor* deviceDesc, InterfaceDescriptor* interfaceDesc);
+
+#endif
\ No newline at end of file
diff -r 000000000000 -r db1ba09e8bfa Utils.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Utils.cpp Tue Jul 10 11:36:47 2012 +0000
@@ -0,0 +1,48 @@
+
+
+#include "mbed.h"
+#include "Utils.h"
+
+void printfBytes(const char* s, const u8* data, int len)
+{
+ printf("%s %d:",s,len);
+ if (len > 256)
+ len = 256;
+ while (len-- > 0)
+ printf(" %02X",*data++);
+ printf("\n");
+}
+
+void printHexLine(const u8* d, int addr, int len)
+{
+ printf("%04X ",addr);
+ int i;
+ for (i = 0; i < len; i++)
+ printf("%02X ",d[i]);
+ for (;i < 16; i++)
+ printf(" ");
+ char s[16+1];
+ memset(s,0,sizeof(s));
+ for (i = 0; i < len; i++)
+ {
+ int c = d[i];
+ if (c < 0x20 || c > 0x7E)
+ c = '.';
+ s[i] = c;
+ }
+ printf("%s\n",s);
+}
+
+void printHex(const u8* d, int len)
+{
+ int addr = 0;
+ while (len)
+ {
+ int count = len;
+ if (count > 16)
+ count = 16;
+ printHexLine(d+addr,addr,count);
+ addr += 16;
+ len -= count;
+ }
+}
diff -r 000000000000 -r db1ba09e8bfa Utils.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Utils.h Tue Jul 10 11:36:47 2012 +0000
@@ -0,0 +1,37 @@
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned long u32;
+
+void DelayMS(int ms);
+
+void printfBytes(const char* label,const u8* data, int len);
+void printHex(const u8* d, int len);
+
+#ifndef min
+#define min(_a,_b) ((_a) < (_b) ? (_a) : (_b))
+#endif
+
+inline int LE16(const u8* d)
+{
+ return d[0] | (d[1] << 8);
+}
+
+inline u32 BE32(const u8* d)
+{
+ return (d[0] << 24) | (d[1] << 16) | (d[2] << 8) | d[3];
+}
+
+inline void BE32(u32 n, u8* d)
+{
+ d[0] = (u8)(n >> 24);
+ d[1] = (u8)(n >> 16);
+ d[2] = (u8)(n >> 8);
+ d[3] = (u8)n;
+}
+
+inline void BE16(u32 n, u8* d)
+{
+ d[0] = (u8)(n >> 8);
+ d[1] = (u8)n;
+}
diff -r 000000000000 -r db1ba09e8bfa hci.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hci.cpp Tue Jul 10 11:36:47 2012 +0000
@@ -0,0 +1,426 @@
+
+/*
+Copyright (c) 2010 Peter Barrett
+
+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 <stdio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "Utils.h"
+#include "hci.h"
+#include "hci_private.h"
+
+enum hci_callback_evt
+{
+ NONE,
+ CONNECT,
+ DISCONECT,
+ INQUIRYRESULT
+};
+
+#define MAX_BLUETOOTH_ADAPTERS 1
+
+enum StateMask {
+ MASK_RESET = 1,
+ MASK_READ_BUFFER_SIZE = 2,
+ MASK_READ_BD_ADDR = 4,
+ MASK_INITED = 8,
+ MASK_INQUIRY = 16,
+ MASK_REMOTE_NAME = 32,
+ MASK_CREATE_CONNECTION = 64
+};
+
+int HCI::Open(HCITransport* transport, HCICallback callback)
+{
+ _transport = transport;
+ _transport->Set(this);
+ _callback = callback;
+ _state = 0;
+ for (int i = 0; i < MAX_BTDEVICES; i++)
+ {
+ _devices[i].Init();
+ _devices[i]._transport = transport;
+ }
+ return SendCmd(HCI_OP_RESET);
+}
+
+void printf(const BD_ADDR* addr);
+
+BTDevice* HCI::Find(const BD_ADDR* addr)
+{
+ for (int i = 0; i < MAX_BTDEVICES; i++)
+ if (_devices[i]._state != 0 && memcmp(addr,&_devices[i]._info.bdaddr,6) == 0)
+ return &_devices[i];
+ return 0;
+}
+
+BTDevice* HCI::Find(int handle)
+{
+ for (int i = 0; i < MAX_BTDEVICES; i++)
+ if (_devices[i]._state != 0 && handle == _devices[i]._handle)
+ return &_devices[i];
+ return 0;
+}
+//
+bool HCI::Busy()
+{
+ return (_state & (MASK_INQUIRY | MASK_REMOTE_NAME | MASK_CREATE_CONNECTION)) != 0;
+}
+
+int HCI::Inquiry(int duration)
+{
+ _state |= MASK_INQUIRY;
+ u8 buf[5];
+ buf[0] = 0x33;
+ buf[1] = 0x8B;
+ buf[2] = 0x9E;
+ buf[3] = duration;
+ buf[4] = 5; // 5 results
+ SendCmd(HCI_OP_INQUIRY,buf,sizeof(buf));
+ return 0;
+}
+
+int HCI::SendCmd(int cmd, const u8* params, int len)
+{
+ u8 b[32];
+ b[0] = cmd;
+ b[1] = (cmd >> 8);
+ b[2] = len;
+ if (params)
+ memcpy(b+3,params,len);
+ _transport->HCISend(b,len+3);
+ return 0;
+}
+
+void HCI::OnCommandComplete(int cmd, const u8* data, int len)
+{
+ // printf("%04X %s",cmd,CmdStr(cmd));
+ if (len < 0)
+ return;
+ //printfBytes(" complete",data,min(16,len));
+
+ switch (cmd)
+ {
+ // Init phase 0
+ case HCI_OP_RESET: // Reset done, init chain to HCI_OP_READ_LOCAL_NAME
+ SendCmd(HCI_OP_READ_BUFFER_SIZE);
+ _state |= MASK_RESET;
+ break;
+
+ // Init phase 1
+ case HCI_OP_READ_BUFFER_SIZE:
+ _acl_mtu = LE16(data);
+ _sco_mtu = data[2];
+ _acl_max_pkt = LE16(data+3);
+ _sco_max_pkt = LE16(data+5);
+ SendCmd(HCI_OP_READ_BD_ADDR);
+ _state |= MASK_READ_BUFFER_SIZE;
+ break;
+
+ // Init phase 2
+ case HCI_OP_READ_BD_ADDR:
+ _localAddr = *((BD_ADDR*)data); // Local Address
+ _state |= MASK_READ_BD_ADDR;
+ _state |= MASK_INITED;
+ Callback(CALLBACK_READY,data,6);
+ break;
+
+ // 0CXX
+ case HCI_OP_READ_LOCAL_NAME:
+ break;
+
+ case HCI_OP_READ_LOCAL_VERSION:
+ // params
+ //SendCmd(HCI_OP_READ_LOCAL_NAME);
+ break;
+
+ case HCI_OP_READ_LOCAL_COMMANDS:
+ break;
+
+ case HCI_OP_READ_LOCAL_FEATURES:
+ //SendCmd(HCI_OP_READ_LOCAL_VERSION);
+ break;
+
+ case HCI_OP_READ_LOCAL_EXT_FEATURES:
+ break;
+
+ case HCI_OP_PIN_CODE_REPLY:
+ printf("Got pin reply\n");
+ break;
+
+ default:
+ printf("Unrecognized Command %04X\n",cmd);
+ break;
+ }
+}
+
+void HCI::Callback(HCI_CALLBACK_EVENT c, const u8* data, int len)
+{
+ _callback(this,c,data,len);
+}
+
+int HCI::RemoteNameRequest(const BD_ADDR* addr)
+{
+ _state |= MASK_REMOTE_NAME;
+ u8 buf[6+4];
+ memset(buf,0,sizeof(buf));
+ memcpy(buf,addr,6);
+ buf[7] = 1;
+ return SendCmd(HCI_OP_REMOTE_NAME_REQ,buf,sizeof(buf));
+}
+
+int HCI::CreateConnection(const BD_ADDR* remoteAddr)
+{
+ _state |= MASK_CREATE_CONNECTION;
+ u8 buf[6+7];
+ memset(buf,0,sizeof(buf));
+ memcpy(buf,remoteAddr,6);
+ buf[6] = 0x18; // DM1,DH1
+ buf[7] = 0xCC; // DM3, DH3, DM5, DH5
+ buf[8] = 1; // Page Repetition R1
+ return SendCmd(HCI_OP_CREATE_CONN,buf,sizeof(buf));
+}
+
+int HCI::Disconnect(const BD_ADDR* bdaddr)
+{
+ BTDevice* d = Find(bdaddr);
+ if (!d)
+ return ERR_HCI_DEVICE_NOT_FOUND;
+ int handle = d->_handle;
+ printf("Disconnect from %d\n",handle);
+ _state |= MASK_CREATE_CONNECTION;
+ u8 buf[3];
+ buf[0] = handle;
+ buf[1] = (handle >> 8);
+ buf[2] = 0x13;
+ return SendCmd(HCI_OP_DISCONNECT,buf,sizeof(buf));
+}
+
+void HCI::DisconnectComplete(int handle)
+{
+ BTDevice* d = Find(handle);
+ if (!d)
+ return;
+ d->_handle = 0;
+}
+
+int HCI::DisconnectAll()
+{
+ BTDevice* devs[8];
+ int count = GetDevices(devs,8);
+ for (int i = 0; i < count; i++)
+ Disconnect(&devs[i]->_info.bdaddr);
+ return 0;
+}
+
+int HCI::PinCodeReply(const u8* data)
+{
+ u8 b[6+1+16];
+ memset(b,0,sizeof(b));
+ memcpy(b,data,6);
+ b[6] = 4;
+ b[7] = '0';
+ b[8] = '0';
+ b[9] = '0';
+ b[10] = '0';
+ return SendCmd(HCI_OP_PIN_CODE_REPLY,b,sizeof(b));
+}
+
+void HCI::InquiryResult(const inquiry_info* info)
+{
+ BTDevice* bt = Find(&info->bdaddr);
+ if (!bt) // new device
+ {
+ for (int i = 0; i < MAX_BTDEVICES; i++)
+ {
+ if (_devices[i]._state == 0)
+ {
+ bt = _devices + i;
+ bt->_state = 1;
+ break;
+ }
+ }
+ if (!bt)
+ {
+ printf("HCI::InquiryResult too many devices\n");
+ return; // Too many devices!
+ }
+ }
+
+ bt->_info = *info;
+}
+
+int HCI::GetDevices(BTDevice** devices, int maxDevices)
+{
+ int j = 0;
+ for (int i = 0; i < MAX_BTDEVICES; i++)
+ {
+ if (_devices[i]._state != 0)
+ {
+ devices[j++] = _devices + i;
+ if (j == maxDevices)
+ break;
+ }
+ }
+ return j;
+}
+
+void HCI::RemoteName(const BD_ADDR* addr, const char* name)
+{
+ BTDevice* d = Find(addr);
+ if (d)
+ {
+ strncpy(d->_name,name,sizeof(d->_name)-1);
+ d->_name[sizeof(d->_name)-1] = 0;
+ }
+}
+
+void HCI::ConnectComplete(const connection_info* info)
+{
+ BTDevice* d = Find(&info->bdaddr);
+ if (!d)
+ return;
+ if (info->status == 0)
+ {
+ d->_handle = info->handle;
+ printf("Connected on %04X\n",info->handle);
+ } else
+ printf("Connection failed with %d\n",info->status);
+}
+
+void HCI::HCIRecv(const u8* data, int len)
+{
+ // printfBytes(EvtStr(data[0]),data,min(len,16));
+ switch (data[0])
+ {
+ case HCI_EV_INQUIRY_COMPLETE:
+ printfBytes("Inquiry Complete",data,data[1]);
+ _state &= ~MASK_INQUIRY;
+ Callback(CALLBACK_INQUIRY_DONE,0,0);
+ break;
+
+ case HCI_EV_INQUIRY_RESULT:
+ {
+ const u8* end = data[1] + data + 2;
+ data += 3;
+ while (data < end)
+ {
+ inquiry_info align;
+ memcpy(&align,data,sizeof(inquiry_info));
+ InquiryResult(&align);
+ Callback(CALLBACK_INQUIRY_RESULT,(u8*)&align,sizeof(inquiry_info));
+ data += 14;
+ }
+ }
+ break;
+
+ case HCI_EV_CONN_COMPLETE:
+ _state &= ~MASK_CREATE_CONNECTION;
+ {
+ connection_info align;
+ memcpy(&align,data+2,sizeof(connection_info));
+ ConnectComplete(&align);
+ Callback(CALLBACK_CONNECTION_COMPLETE,(u8*)&align,sizeof(connection_info));
+ }
+ break;
+
+ case HCI_EV_CONN_REQUEST:
+ break;
+
+ case HCI_EV_DISCONN_COMPLETE:
+ DisconnectComplete(LE16(data+3));
+ break;
+
+ case HCI_EV_REMOTE_NAME:
+ {
+ BD_ADDR* addr = (BD_ADDR*)(data+3);
+ const char* name = (const char*)(data + 9);
+ RemoteName(addr,name);
+ }
+ Callback(CALLBACK_REMOTE_NAME,data+3,LE16(data+1)); // addr is in here too
+ _state &= ~MASK_REMOTE_NAME;
+ break;
+
+ case HCI_EV_CMD_STATUS:
+ {
+ const char* errs = HCIErrStr(data[2]);
+ printf("Status %s %s\n",CmdStr(LE16(data+4)),errs);
+ }
+ break;
+
+ case HCI_EV_CMD_COMPLETE:
+ OnCommandComplete(data[3] | (data[4] << 8),data+6,data[1]-4);
+ break;
+
+ case HCI_EV_PIN_CODE_REQ:
+ PinCodeReply(data+2);
+ break;
+
+ case HCI_EV_LINK_KEY_REQ:
+ SendCmd(HCI_OP_LINK_KEY_NEG_REPLY,data+2,6);
+ break;
+
+ default:
+ ;
+ // printfBytes(":",data,data[1]+2);
+ }
+}
+
+int HCI::Open(SocketInternal* sock, SocketAddrHdr* addr)
+{
+ L2CAPSocket* l2capsock = (L2CAPSocket*)sock;
+ L2CAPAddr* l2capaddr = (L2CAPAddr*)addr;
+ BTDevice* bt = Find(&l2capaddr->bdaddr);
+ if (!bt)
+ {
+ printf("Can't open l2cap %d on ",l2capaddr->psm);
+ printf(&l2capaddr->bdaddr);
+ printf("\n");
+ return ERR_HCI_DEVICE_NOT_FOUND;
+ }
+ l2capsock->btdevice = bt;
+ return bt->Open(sock,addr);
+}
+
+int HCI::Send(SocketInternal* sock, const u8* data, int len)
+{
+ L2CAPSocket* l2capsock = (L2CAPSocket*)sock;
+ return l2capsock->btdevice->Send(sock,data,len); // Pointless double dispatch
+}
+
+int HCI::Close(SocketInternal* sock)
+{
+ L2CAPSocket* l2capsock = (L2CAPSocket*)sock;
+ return l2capsock->btdevice->Close(sock); // Pointless double dispatch
+}
+
+void HCI::ACLRecv(const u8* data, int len)
+{
+ int handle = LE16(data);
+ BTDevice* d = Find(handle & 0x0FFF);
+ if (d)
+ d->ACLRecv(data,len);
+}
+
+//===================================================================
+//===================================================================
diff -r 000000000000 -r db1ba09e8bfa hci.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hci.h Tue Jul 10 11:36:47 2012 +0000
@@ -0,0 +1,224 @@
+/*
+Copyright (c) 2010 Peter Barrett
+
+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 HCI_H_INCLUDED
+#define HCI_H_INCLUDED
+
+#include "Socket.h"
+
+#pragma pack(1)
+
+#define ERR_HCI_DEVICE_NOT_FOUND -300
+
+class HCI;
+class HCITransport;
+class BTDevice;
+
+typedef struct
+{
+ u8 addr[6];
+} BD_ADDR;
+
+typedef struct
+{
+ BD_ADDR bdaddr;
+ u8 pscan_rep_mode;
+ u8 pscan_period_mode;
+ u8 pscan_mode;
+ u8 dev_class[3];
+ u16 clock_offset;
+} inquiry_info;
+
+typedef struct
+{
+ u8 status;
+ u16 handle;
+ BD_ADDR bdaddr;
+ u8 link_type;
+ u8 encr_mode;
+} connection_info;
+
+// Address struct for creating L2CAP sockets
+typedef struct {
+ SocketAddrHdr hdr;
+ BD_ADDR bdaddr;
+ u16 psm;
+} L2CAPAddr;
+
+#pragma pack(4)
+
+class BTDevice;
+typedef struct
+{
+ public:
+ SocketInternal si;
+ BTDevice* btdevice;
+ u16 scid;
+ u16 dcid;
+} L2CAPSocket;
+
+#define MAX_HCL_NAME_LENGTH 20 // TODO - BTDevice wants to be a multiple of 4
+
+// BTDevice encapsulates individual device state
+// It provides L2CAP layer sockets
+
+class BTDevice : public SocketHandler
+{
+ public:
+ HCITransport* _transport;
+ inquiry_info _info;
+ u16 _handle; // acl connection handle
+ u8 _state; // connection state
+ u8 _txid;
+ char _name[MAX_HCL_NAME_LENGTH];
+
+ void Init();
+
+ BD_ADDR* GetAddress() { return &_info.bdaddr; }
+
+ // Called from HCI
+ void ACLRecv(const u8* data, int len);
+
+ // SocketHandler
+ virtual int Open(SocketInternal* sock, SocketAddrHdr* addr);
+ virtual int Send(SocketInternal* sock, const u8* data, int len);
+ virtual int Close(SocketInternal* sock);
+
+private:
+ L2CAPSocket* SCIDToSocket(int scid);
+ int Send(const u8* data, int len);
+ int Send(u8 c, u8 id, u16* params, int count);
+ int Connect(int scid, int psm);
+ int Disconnect(int scid, int dcid);
+ int ConfigureRequest(int dcid);
+ int ConfigureResponse(u8 rxid, int dcid);
+ int DisconnectResponse(u8 rxid, int scid, int dcid);
+ void Control(const u8* data, int len);
+};
+
+enum HCI_CALLBACK_EVENT
+{
+ CALLBACK_NONE,
+ CALLBACK_READY,
+ CALLBACK_INQUIRY_RESULT,
+ CALLBACK_INQUIRY_DONE,
+ CALLBACK_REMOTE_NAME,
+ CALLBACK_CONNECTION_COMPLETE,
+ CALLBACK_CONNECTION_FAILED
+};
+
+// L2CAP Protocol/Service Multiplexor (PSM) values
+
+#define L2CAP_PSM_ANY 0x0000 /* Any/Invalid PSM */
+#define L2CAP_PSM_SDP 0x0001 /* Service Discovery Protocol */
+#define L2CAP_PSM_RFCOMM 0x0003 /* RFCOMM protocol */
+#define L2CAP_PSM_TCP 0x0005 /* Telephony Control Protocol */
+#define L2CAP_PSM_TCS 0x0007 /* TCS cordless */
+#define L2CAP_PSM_BNEP 0x000f /* Bluetooth Network Encapsulation Protocol*/
+#define L2CAP_PSM_HID_CNTL 0x0011 /* HID Control */
+#define L2CAP_PSM_HID_INTR 0x0013 /* HID Interrupt */
+#define L2CAP_PSM_ESDP 0x0015 /* Extended Service Discovery Profile */
+#define L2CAP_PSM_AVCTP 0x0017 /* Audio/Visual Control Transport Protocol */
+#define L2CAP_PSM_AVDTP 0x0019 /* Audio/Visual Distribution */
+
+// Callback from inquiry
+typedef int (*HCICallback)(HCI* hci, HCI_CALLBACK_EVENT evt, const u8* data, int len);
+
+#define MAX_BTDEVICES 8
+
+class HCITransport;
+class HCI : public SocketHandler
+{
+ HCITransport* _transport;
+ HCICallback _callback;
+ BD_ADDR _localAddr;
+
+ BTDevice _devices[MAX_BTDEVICES];
+ int _deviceCount;
+
+ int _acl_mtu;
+ int _acl_max_pkt;
+ int _sco_mtu;
+ int _sco_max_pkt;
+
+ int _state;
+
+ public:
+
+ // Open a local adapter
+ int Open(HCITransport* transport, HCICallback callback);
+
+ // Return list of discovered addreses
+ int GetDevices(BTDevice** devices, int maxDevices);
+
+ // Lookup a device by address or handle
+ BTDevice* Find(const BD_ADDR* addr);
+ BTDevice* Find(int handle);
+
+ // Disconnect from a remote device
+ int Disconnect(const BD_ADDR* addr);
+ int DisconnectAll();
+
+ // see what devies are in the system
+ int Inquiry(int duration = 10);
+
+ // get a name, delivered in callback
+ int RemoteNameRequest(const BD_ADDR* addr);
+
+ // Connect to a remote device
+ int CreateConnection(const BD_ADDR* remoteAddr);
+
+ bool Busy();
+
+ // called from transport
+ void HCIRecv(const u8* data, int len);
+
+ // called from transport
+ void ACLRecv(const u8* data, int len);
+
+ // SocketHandler methods for maintaining L2CAP sockets
+ virtual int Open(SocketInternal* sock, SocketAddrHdr* addr);
+ virtual int Send(SocketInternal* sock, const u8* data, int len);
+ virtual int Close(SocketInternal* sock);
+
+ private:
+ void InquiryResult(const inquiry_info* info);
+ void RemoteName(const BD_ADDR* addr, const char* name);
+ void ConnectComplete(const connection_info* info);
+ void DisconnectComplete(int handle);
+ int SendCmd(int cmd, const u8* params = 0, int len = 0);
+ void OnCommandComplete(int cmd, const u8* data, int len);
+ void Callback(HCI_CALLBACK_EVENT c, const u8* data, int len);
+ int PinCodeReply(const u8* data);
+};
+
+class HCITransport
+{
+protected:
+ HCI* _target;
+public:
+ void Set(HCI* target) { _target = target; };
+ virtual void HCISend(const u8* data, int len) = 0;
+ virtual void ACLSend(const u8* data, int len) = 0;
+};
+
+#endif
diff -r 000000000000 -r db1ba09e8bfa hci_private.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hci_private.h Tue Jul 10 11:36:47 2012 +0000
@@ -0,0 +1,323 @@
+/*
+Copyright (c) 2010 Peter Barrett
+
+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 HCI_PRIVATE_H_INCLUDED
+#define HCI_PRIVATE_H_INCLUDED
+
+#define HCI_OP_INQUIRY 0x0401
+#define HCI_OP_INQUIRY_CANCEL 0x0402
+#define HCI_OP_EXIT_PERIODIC_INQ 0x0404
+#define HCI_OP_CREATE_CONN 0x0405
+#define HCI_OP_DISCONNECT 0x0406
+#define HCI_OP_ADD_SCO 0x0407
+#define HCI_OP_CREATE_CONN_CANCEL 0x0408
+#define HCI_OP_ACCEPT_CONN_REQ 0x0409
+#define HCI_OP_REJECT_CONN_REQ 0x040a
+#define HCI_OP_LINK_KEY_REPLY 0x040b
+#define HCI_OP_LINK_KEY_NEG_REPLY 0x040c
+#define HCI_OP_PIN_CODE_REPLY 0x040d
+#define HCI_OP_PIN_CODE_NEG_REPLY 0x040e
+#define HCI_OP_CHANGE_CONN_PTYPE 0x040f
+#define HCI_OP_AUTH_REQUESTED 0x0411
+#define HCI_OP_SET_CONN_ENCRYPT 0x0413
+#define HCI_OP_CHANGE_CONN_LINK_KEY 0x0415
+#define HCI_OP_REMOTE_NAME_REQ 0x0419
+#define HCI_OP_REMOTE_NAME_REQ_CANCEL 0x041a
+#define HCI_OP_READ_REMOTE_FEATURES 0x041b
+#define HCI_OP_READ_REMOTE_EXT_FEATURES 0x041c
+#define HCI_OP_READ_REMOTE_VERSION 0x041d
+#define HCI_OP_SETUP_SYNC_CONN 0x0428
+#define HCI_OP_ACCEPT_SYNC_CONN_REQ 0x0429
+#define HCI_OP_REJECT_SYNC_CONN_REQ 0x042a
+
+#define HCI_OP_SNIFF_MODE 0x0803
+#define HCI_OP_EXIT_SNIFF_MODE 0x0804
+#define HCI_OP_ROLE_DISCOVERY 0x0809
+#define HCI_OP_SWITCH_ROLE 0x080b
+#define HCI_OP_READ_LINK_POLICY 0x080c
+#define HCI_OP_WRITE_LINK_POLICY 0x080d
+#define HCI_OP_READ_DEF_LINK_POLICY 0x080e
+#define HCI_OP_WRITE_DEF_LINK_POLICY 0x080f
+#define HCI_OP_SNIFF_SUBRATE 0x0811
+
+
+#define HCI_OP_SET_EVENT_MASK 0x0c01
+#define HCI_OP_RESET 0x0c03
+#define HCI_OP_SET_EVENT_FLT 0x0c05
+#define HCI_OP_WRITE_LOCAL_NAME 0x0c13
+#define HCI_OP_READ_LOCAL_NAME 0x0c14
+#define HCI_OP_WRITE_CA_TIMEOUT 0x0c16
+#define HCI_OP_WRITE_PG_TIMEOUT 0x0c18
+#define HCI_OP_WRITE_SCAN_ENABLE 0x0c1a
+#define HCI_OP_READ_AUTH_ENABLE 0x0c1f
+#define HCI_OP_WRITE_AUTH_ENABLE 0x0c20
+#define HCI_OP_READ_ENCRYPT_MODE 0x0c21
+#define HCI_OP_WRITE_ENCRYPT_MODE 0x0c22
+ #define ENCRYPT_DISABLED 0x00
+ #define ENCRYPT_P2P 0x01
+ #define ENCRYPT_BOTH 0x02
+#define HCI_OP_READ_CLASS_OF_DEV 0x0c23
+#define HCI_OP_WRITE_CLASS_OF_DEV 0x0c24
+#define HCI_OP_READ_VOICE_SETTING 0x0c25
+#define HCI_OP_WRITE_VOICE_SETTING 0x0c26
+#define HCI_OP_HOST_BUFFER_SIZE 0x0c33
+#define HCI_OP_READ_SSP_MODE 0x0c55
+#define HCI_OP_WRITE_SSP_MODE 0x0c56
+
+#define HCI_OP_READ_LOCAL_VERSION 0x1001
+#define HCI_OP_READ_LOCAL_COMMANDS 0x1002
+#define HCI_OP_READ_LOCAL_FEATURES 0x1003
+#define HCI_OP_READ_LOCAL_EXT_FEATURES 0x1004
+#define HCI_OP_READ_BUFFER_SIZE 0x1005
+#define HCI_OP_READ_BD_ADDR 0x1009
+
+// events
+#define HCI_EV_INQUIRY_COMPLETE 0x01
+#define HCI_EV_INQUIRY_RESULT 0x02
+#define HCI_EV_CONN_COMPLETE 0x03
+#define HCI_EV_CONN_REQUEST 0x04
+#define HCI_EV_DISCONN_COMPLETE 0x05
+#define HCI_EV_AUTH_COMPLETE 0x06
+#define HCI_EV_REMOTE_NAME 0x07
+#define HCI_EV_ENCRYPT_CHANGE 0x08
+#define HCI_EV_CHANGE_LINK_KEY_COMPLETE 0x09
+#define HCI_EV_REMOTE_FEATURES 0x0b
+#define HCI_EV_REMOTE_VERSION 0x0c
+#define HCI_EV_QOS_SETUP_COMPLETE 0x0d
+#define HCI_EV_CMD_COMPLETE 0x0e
+#define HCI_EV_CMD_STATUS 0x0f
+#define HCI_EV_ROLE_CHANGE 0x12
+#define HCI_EV_NUM_COMP_PKTS 0x13
+#define HCI_EV_MODE_CHANGE 0x14
+#define HCI_EV_PIN_CODE_REQ 0x16
+#define HCI_EV_LINK_KEY_REQ 0x17
+#define HCI_EV_LINK_KEY_NOTIFY 0x18
+#define HCI_EV_CLOCK_OFFSET 0x1c
+#define HCI_EV_PKT_TYPE_CHANGE 0x1d
+#define HCI_EV_PSCAN_REP_MODE 0x20
+#define HCI_EV_INQUIRY_RESULT_WITH_RSSI 0x22
+#define HCI_EV_REMOTE_EXT_FEATURES 0x23
+#define HCI_EV_SYNC_CONN_COMPLETE 0x2c
+#define HCI_EV_SYNC_CONN_CHANGED 0x2d
+#define HCI_EV_SNIFF_SUBRATE 0x2e
+#define HCI_EV_EXTENDED_INQUIRY_RESULT 0x2f
+#define HCI_EV_IO_CAPA_REQUEST 0x31
+#define HCI_EV_SIMPLE_PAIR_COMPLETE 0x36
+#define HCI_EV_REMOTE_HOST_FEATURES 0x3d
+
+/* Possible error codes */
+#define HCI_UNKNOWN_HCI_COMMAND 0x01
+#define HCI_NO_CONNECTION 0x02
+#define HCI_HW_FAILURE 0x03
+#define HCI_PAGE_TIMEOUT 0x04
+#define HCI_AUTHENTICATION_FAILURE 0x05
+#define HCI_KEY_MISSING 0x06
+#define HCI_MEMORY_FULL 0x07
+#define HCI_CONN_TIMEOUT 0x08
+#define HCI_MAX_NUMBER_OF_CONNECTIONS 0x09
+#define HCI_MAX_NUMBER_OF_SCO_CONNECTIONS_TO_DEVICE 0x0A
+#define HCI_ACL_CONNECTION_EXISTS 0x0B
+#define HCI_COMMAND_DISSALLOWED 0x0C
+#define HCI_HOST_REJECTED_DUE_TO_LIMITED_RESOURCES 0x0D
+#define HCI_HOST_REJECTED_DUE_TO_SECURITY_REASONS 0x0E
+#define HCI_HOST_REJECTED_DUE_TO_REMOTE_DEVICE_ONLY_PERSONAL_SERVICE 0x0F
+#define HCI_HOST_TIMEOUT 0x10
+#define HCI_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE 0x11
+#define HCI_INVALID_HCI_COMMAND_PARAMETERS 0x12
+#define HCI_OTHER_END_TERMINATED_CONN_USER_ENDED 0x13
+#define HCI_OTHER_END_TERMINATED_CONN_LOW_RESOURCES 0x14
+#define HCI_OTHER_END_TERMINATED_CONN_ABOUT_TO_POWER_OFF 0x15
+#define HCI_CONN_TERMINATED_BY_LOCAL_HOST 0x16
+#define HCI_REPETED_ATTEMPTS 0x17
+#define HCI_PAIRING_NOT_ALLOWED 0x18
+#define HCI_UNKNOWN_LMP_PDU 0x19
+#define HCI_UNSUPPORTED_REMOTE_FEATURE 0x1A
+#define HCI_SCO_OFFSET_REJECTED 0x1B
+#define HCI_SCO_INTERVAL_REJECTED 0x1C
+#define HCI_SCO_AIR_MODE_REJECTED 0x1D
+#define HCI_INVALID_LMP_PARAMETERS 0x1E
+#define HCI_UNSPECIFIED_ERROR 0x1F
+#define HCI_UNSUPPORTED_LMP_PARAMETER_VALUE 0x20
+#define HCI_ROLE_CHANGE_NOT_ALLOWED 0x21
+#define HCI_LMP_RESPONSE_TIMEOUT 0x22
+#define HCI_LMP_ERROR_TRANSACTION_COLLISION 0x23
+#define HCI_LMP_PDU_NOT_ALLOWED 0x24
+#define HCI_ENCRYPTION_MODE_NOT_ACCEPTABLE 0x25
+#define HCI_UNIT_KEY_USED 0x26
+#define HCI_QOS_NOT_SUPPORTED 0x27
+#define HCI_INSTANT_PASSED 0x28
+#define HCI_PAIRING_UNIT_KEY_NOT_SUPPORTED 0x29
+
+const char* EvtStr(int evt)
+{
+ switch (evt)
+ {
+ case HCI_EV_INQUIRY_COMPLETE: return "HCI_EV_INQUIRY_COMPLETE";
+ case HCI_EV_INQUIRY_RESULT: return "HCI_EV_INQUIRY_RESULT";
+ case HCI_EV_CONN_COMPLETE: return "HCI_EV_CONN_COMPLETE";
+ case HCI_EV_CONN_REQUEST: return "HCI_EV_CONN_REQUEST";
+ case HCI_EV_DISCONN_COMPLETE: return "HCI_EV_DISCONN_COMPLETE";
+ case HCI_EV_AUTH_COMPLETE: return "HCI_EV_AUTH_COMPLETE";
+ case HCI_EV_REMOTE_NAME: return "HCI_EV_REMOTE_NAME";
+ case HCI_EV_ENCRYPT_CHANGE: return "HCI_EV_ENCRYPT_CHANGE";
+ case HCI_EV_CHANGE_LINK_KEY_COMPLETE : return "HCI_EV_CHANGE_LINK_KEY_COMPLETE";
+ case HCI_EV_REMOTE_FEATURES: return "HCI_EV_REMOTE_FEATURES";
+ case HCI_EV_REMOTE_VERSION: return "HCI_EV_REMOTE_VERSION";
+ case HCI_EV_QOS_SETUP_COMPLETE : return "HCI_EV_QOS_SETUP_COMPLETE";
+ case HCI_EV_CMD_COMPLETE: return "HCI_EV_CMD_COMPLETE";
+ case HCI_EV_CMD_STATUS: return "HCI_EV_CMD_STATUS";
+ case HCI_EV_ROLE_CHANGE: return "HCI_EV_ROLE_CHANGE";
+ case HCI_EV_NUM_COMP_PKTS: return "HCI_EV_NUM_COMP_PKTS";
+ case HCI_EV_MODE_CHANGE: return "HCI_EV_MODE_CHANGE";
+ case HCI_EV_PIN_CODE_REQ: return "HCI_EV_PIN_CODE_REQ";
+ case HCI_EV_LINK_KEY_REQ: return "HCI_EV_LINK_KEY_REQ";
+ case HCI_EV_LINK_KEY_NOTIFY: return "HCI_EV_LINK_KEY_NOTIFY";
+ case HCI_EV_CLOCK_OFFSET: return "HCI_EV_CLOCK_OFFSET";
+ case HCI_EV_PKT_TYPE_CHANGE: return "HCI_EV_PKT_TYPE_CHANGE";
+ case HCI_EV_PSCAN_REP_MODE: return "HCI_EV_PSCAN_REP_MODE";
+ case HCI_EV_INQUIRY_RESULT_WITH_RSSI : return "HCI_EV_INQUIRY_RESULT_WITH_RSSI";
+ case HCI_EV_REMOTE_EXT_FEATURES: return "HCI_EV_REMOTE_EXT_FEATURES";
+ case HCI_EV_SYNC_CONN_COMPLETE: return "HCI_EV_SYNC_CONN_COMPLETE";
+ case HCI_EV_SYNC_CONN_CHANGED: return "HCI_EV_SYNC_CONN_CHANGED";
+ case HCI_EV_SNIFF_SUBRATE: return "HCI_EV_SNIFF_SUBRATE";
+ case HCI_EV_EXTENDED_INQUIRY_RESULT: return "HCI_EV_EXTENDED_INQUIRY_RESULT";
+ case HCI_EV_IO_CAPA_REQUEST: return "HCI_EV_IO_CAPA_REQUEST";
+ case HCI_EV_SIMPLE_PAIR_COMPLETE: return "HCI_EV_SIMPLE_PAIR_COMPLETE";
+ case HCI_EV_REMOTE_HOST_FEATURES: return "HCI_EV_REMOTE_HOST_FEATURES";
+ }
+ return "Unknown Event";
+}
+
+const char* CmdStr(int cmd)
+{
+ switch (cmd)
+ {
+ // 0x04XX
+ case HCI_OP_INQUIRY: return "HCI_OP_INQUIRY";
+ case HCI_OP_INQUIRY_CANCEL: return "HCI_OP_INQUIRY_CANCEL";
+ case HCI_OP_EXIT_PERIODIC_INQ: return "HCI_OP_EXIT_PERIODIC_INQ";
+ case HCI_OP_CREATE_CONN: return "HCI_OP_CREATE_CONN";
+ case HCI_OP_DISCONNECT: return "HCI_OP_DISCONNECT";
+ case HCI_OP_ADD_SCO: return "HCI_OP_ADD_SCO";
+ case HCI_OP_CREATE_CONN_CANCEL: return "HCI_OP_CREATE_CONN_CANCEL";
+ case HCI_OP_ACCEPT_CONN_REQ: return "HCI_OP_ACCEPT_CONN_REQ";
+ case HCI_OP_REJECT_CONN_REQ: return "HCI_OP_REJECT_CONN_REQ";
+ case HCI_OP_LINK_KEY_REPLY: return "HCI_OP_LINK_KEY_REPLY";
+ case HCI_OP_LINK_KEY_NEG_REPLY: return "HCI_OP_LINK_KEY_NEG_REPLY";
+ case HCI_OP_PIN_CODE_REPLY: return "HCI_OP_PIN_CODE_REPLY";
+ case HCI_OP_PIN_CODE_NEG_REPLY: return "HCI_OP_PIN_CODE_NEG_REPLY";
+ case HCI_OP_CHANGE_CONN_PTYPE: return "HCI_OP_CHANGE_CONN_PTYPE";
+ case HCI_OP_AUTH_REQUESTED: return "HCI_OP_AUTH_REQUESTED";
+ case HCI_OP_SET_CONN_ENCRYPT: return "HCI_OP_SET_CONN_ENCRYPT";
+ case HCI_OP_CHANGE_CONN_LINK_KEY: return "HCI_OP_CHANGE_CONN_LINK_KEY";
+ case HCI_OP_REMOTE_NAME_REQ: return "HCI_OP_REMOTE_NAME_REQ";
+ case HCI_OP_REMOTE_NAME_REQ_CANCEL: return "HCI_OP_REMOTE_NAME_REQ_CANCEL";
+ case HCI_OP_READ_REMOTE_FEATURES: return "HCI_OP_READ_REMOTE_FEATURES";
+ case HCI_OP_READ_REMOTE_EXT_FEATURES: return "HCI_OP_READ_REMOTE_EXT_FEATURES";
+ case HCI_OP_READ_REMOTE_VERSION: return "HCI_OP_READ_REMOTE_VERSION";
+ case HCI_OP_SETUP_SYNC_CONN: return "HCI_OP_SETUP_SYNC_CONN";
+ case HCI_OP_ACCEPT_SYNC_CONN_REQ: return "HCI_OP_ACCEPT_SYNC_CONN_REQ";
+ case HCI_OP_REJECT_SYNC_CONN_REQ: return "HCI_OP_REJECT_SYNC_CONN_REQ";
+ // 0x0CXX
+ case HCI_OP_SET_EVENT_MASK: return "HCI_OP_SET_EVENT_MASK";
+ case HCI_OP_RESET: return "HCI_OP_RESET";
+ case HCI_OP_SET_EVENT_FLT: return "HCI_OP_SET_EVENT_FLT";
+ case HCI_OP_WRITE_LOCAL_NAME: return "HCI_OP_WRITE_LOCAL_NAME";
+ case HCI_OP_READ_LOCAL_NAME: return "HCI_OP_READ_LOCAL_NAME";
+ case HCI_OP_WRITE_CA_TIMEOUT: return "HCI_OP_WRITE_CA_TIMEOUT";
+ case HCI_OP_WRITE_PG_TIMEOUT: return "HCI_OP_WRITE_PG_TIMEOUT";
+ case HCI_OP_WRITE_SCAN_ENABLE: return "HCI_OP_WRITE_SCAN_ENABLE";
+ case HCI_OP_READ_AUTH_ENABLE: return "HCI_OP_READ_AUTH_ENABLE";
+ case HCI_OP_WRITE_AUTH_ENABLE: return "HCI_OP_WRITE_AUTH_ENABLE";
+ case HCI_OP_READ_ENCRYPT_MODE: return "HCI_OP_READ_ENCRYPT_MODE";
+ case HCI_OP_WRITE_ENCRYPT_MODE: return "HCI_OP_WRITE_ENCRYPT_MODE";
+ case HCI_OP_READ_CLASS_OF_DEV: return "HCI_OP_READ_CLASS_OF_DEV";
+ case HCI_OP_WRITE_CLASS_OF_DEV: return "HCI_OP_WRITE_CLASS_OF_DEV";
+ case HCI_OP_READ_VOICE_SETTING: return "HCI_OP_READ_VOICE_SETTING";
+ case HCI_OP_WRITE_VOICE_SETTING: return "HCI_OP_WRITE_VOICE_SETTING";
+ case HCI_OP_HOST_BUFFER_SIZE: return "HCI_OP_HOST_BUFFER_SIZE";
+ case HCI_OP_READ_SSP_MODE: return "HCI_OP_READ_SSP_MODE";
+ case HCI_OP_WRITE_SSP_MODE: return "HCI_OP_WRITE_SSP_MODE";
+
+ // 10xx
+ case HCI_OP_READ_LOCAL_VERSION: return "HCI_OP_READ_LOCAL_VERSION";
+ case HCI_OP_READ_LOCAL_COMMANDS: return "HCI_OP_READ_LOCAL_COMMANDS";
+ case HCI_OP_READ_LOCAL_FEATURES: return "HCI_OP_READ_LOCAL_FEATURES";
+ case HCI_OP_READ_LOCAL_EXT_FEATURES: return "HCI_OP_READ_LOCAL_EXT_FEATURES";
+ case HCI_OP_READ_BUFFER_SIZE: return "HCI_OP_READ_BUFFER_SIZE";
+ case HCI_OP_READ_BD_ADDR: return "HCI_OP_READ_BD_ADDR";
+ }
+ return "Unknown Cmd";
+}
+
+const char* HCIErrStr(int err)
+{
+ switch (err)
+ {
+ case 0: return "OK";
+ case HCI_UNKNOWN_HCI_COMMAND: return "HCI_UNKNOWN_HCI_COMMAND";
+ case HCI_NO_CONNECTION: return "HCI_NO_CONNECTION";
+ case HCI_HW_FAILURE: return "HCI_HW_FAILURE";
+ case HCI_PAGE_TIMEOUT: return "HCI_PAGE_TIMEOUT";
+ case HCI_AUTHENTICATION_FAILURE: return "HCI_AUTHENTICATION_FAILURE";
+ case HCI_KEY_MISSING: return "HCI_KEY_MISSING";
+ case HCI_MEMORY_FULL: return "HCI_MEMORY_FULL";
+ case HCI_CONN_TIMEOUT: return "HCI_CONN_TIMEOUT";
+ case HCI_MAX_NUMBER_OF_CONNECTIONS: return "HCI_CONN_TIMEOUT";
+ case HCI_MAX_NUMBER_OF_SCO_CONNECTIONS_TO_DEVICE: return "HCI_MAX_NUMBER_OF_SCO_CONNECTIONS_TO_DEVICE";
+ case HCI_ACL_CONNECTION_EXISTS: return "HCI_ACL_CONNECTION_EXISTS";
+ case HCI_COMMAND_DISSALLOWED: return "HCI_COMMAND_DISSALLOWED";
+ case HCI_HOST_REJECTED_DUE_TO_LIMITED_RESOURCES: return "HCI_HOST_REJECTED_DUE_TO_LIMITED_RESOURCES";
+ case HCI_HOST_REJECTED_DUE_TO_SECURITY_REASONS: return "HCI_HOST_REJECTED_DUE_TO_SECURITY_REASONS";
+ case HCI_HOST_REJECTED_DUE_TO_REMOTE_DEVICE_ONLY_PERSONAL_SERVICE: return "HCI_HOST_REJECTED_DUE_TO_REMOTE_DEVICE_ONLY_PERSONAL_SERVICE";
+ case HCI_HOST_TIMEOUT: return "HCI_HOST_TIMEOUT";
+ case HCI_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE: return "HCI_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE";
+ case HCI_INVALID_HCI_COMMAND_PARAMETERS: return "HCI_INVALID_HCI_COMMAND_PARAMETERS";
+ case HCI_OTHER_END_TERMINATED_CONN_USER_ENDED: return "HCI_OTHER_END_TERMINATED_CONN_USER_ENDED";
+ case HCI_OTHER_END_TERMINATED_CONN_LOW_RESOURCES: return "HCI_OTHER_END_TERMINATED_CONN_LOW_RESOURCES";
+ case HCI_OTHER_END_TERMINATED_CONN_ABOUT_TO_POWER_OFF: return "HCI_OTHER_END_TERMINATED_CONN_ABOUT_TO_POWER_OFF";
+ case HCI_CONN_TERMINATED_BY_LOCAL_HOST: return "HCI_CONN_TERMINATED_BY_LOCAL_HOST";
+ case HCI_REPETED_ATTEMPTS: return "HCI_REPETED_ATTEMPTS";
+ case HCI_PAIRING_NOT_ALLOWED: return "HCI_PAIRING_NOT_ALLOWED";
+ case HCI_UNKNOWN_LMP_PDU: return "HCI_UNKNOWN_LMP_PDU";
+ case HCI_UNSUPPORTED_REMOTE_FEATURE: return "HCI_UNSUPPORTED_REMOTE_FEATURE";
+ case HCI_SCO_OFFSET_REJECTED: return "HCI_SCO_OFFSET_REJECTED";
+ case HCI_SCO_INTERVAL_REJECTED: return "HCI_SCO_INTERVAL_REJECTED";
+ case HCI_SCO_AIR_MODE_REJECTED: return "HCI_SCO_AIR_MODE_REJECTED";
+ case HCI_INVALID_LMP_PARAMETERS: return "HCI_INVALID_LMP_PARAMETERS";
+ case HCI_UNSPECIFIED_ERROR: return "HCI_UNSPECIFIED_ERROR";
+ case HCI_UNSUPPORTED_LMP_PARAMETER_VALUE: return "HCI_UNSUPPORTED_LMP_PARAMETER_VALUE";
+ case HCI_ROLE_CHANGE_NOT_ALLOWED: return "HCI_ROLE_CHANGE_NOT_ALLOWED";
+ case HCI_LMP_RESPONSE_TIMEOUT: return "HCI_LMP_RESPONSE_TIMEOUT";
+ case HCI_LMP_ERROR_TRANSACTION_COLLISION: return "HCI_LMP_ERROR_TRANSACTION_COLLISION";
+ case HCI_LMP_PDU_NOT_ALLOWED: return "HCI_LMP_PDU_NOT_ALLOWED";
+ case HCI_ENCRYPTION_MODE_NOT_ACCEPTABLE: return "HCI_ENCRYPTION_MODE_NOT_ACCEPTABLE";
+ case HCI_UNIT_KEY_USED: return "HCI_UNIT_KEY_USED";
+ case HCI_QOS_NOT_SUPPORTED: return "HCI_QOS_NOT_SUPPORTED";
+ case HCI_INSTANT_PASSED: return "HCI_INSTANT_PASSED";
+ case HCI_PAIRING_UNIT_KEY_NOT_SUPPORTED: return "HCI_PAIRING_UNIT_KEY_NOT_SUPPORTED";
+ };
+ return "Unknow HCI err";
+};
+
+
+#endif // HCI_PRIVATE_H_INCLUDED
diff -r 000000000000 -r db1ba09e8bfa main.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp Tue Jul 10 11:36:47 2012 +0000
@@ -0,0 +1,121 @@
+/*
+Copyright (c) 2010 Peter Barrett
+
+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 "USBHost.h"
+#include "Utils.h"
+#include "FATFileSystem.h"
+
+int MassStorage_ReadCapacity(int device, u32* blockCount, u32* blockSize);
+int MassStorage_Read(int device, u32 blockAddr, u32 blockCount, u8* dst, u32 blockSize);
+int MassStorage_Write(int device, u32 blockAddr, u32 blockCount, u8* dst, u32 blockSize);
+
+class USBFileSystem : public FATFileSystem
+{
+ int _device;
+ u32 _blockSize;
+ u32 _blockCount;
+
+public:
+ USBFileSystem() : FATFileSystem("usb"),_device(0),_blockSize(0),_blockCount(0)
+ {
+ }
+
+ void SetDevice(int device)
+ {
+ _device = device;
+ }
+
+ virtual int disk_initialize()
+ {
+ return MassStorage_ReadCapacity(_device,&_blockCount,&_blockSize);
+ }
+
+ virtual int disk_write(const char *buffer, int block_number)
+ {
+ return MassStorage_Write(_device,block_number,1,(u8*)buffer,_blockSize);
+ }
+
+ virtual int disk_read(char *buffer, int block_number)
+ {
+ return MassStorage_Read(_device,block_number,1,(u8*)buffer,_blockSize);
+ }
+
+ virtual int disk_sectors()
+ {
+ return _blockCount;
+ }
+};
+
+void DumpFS(int depth, int count)
+{
+ DIR *d = opendir("/usb");
+ if (!d)
+ {
+ printf("USB file system borked\n");
+ return;
+ }
+
+ printf("\nDumping root dir\n");
+ struct dirent *p;
+ for(;;)
+ {
+ p = readdir(d);
+ if (!p)
+ break;
+ int len = sizeof( dirent);
+ printf("%s %d\n", p->d_name, len);
+ }
+ closedir(d);
+}
+
+int OnDiskInsert(int device)
+{
+ USBFileSystem fs;
+ fs.SetDevice(device);
+ DumpFS(0,0);
+ return 0;
+}
+
+/*
+ Simple test shell to exercise mouse,keyboard,mass storage and hubs.
+ Add 2 15k pulldown resistors between D+/D- and ground, attach a usb socket and have at it.
+*/
+
+Serial pc(USBTX, USBRX);
+int GetConsoleChar()
+{
+ if (!pc.readable())
+ return -1;
+ char c = pc.getc();
+ pc.putc(c); // echo
+ return c;
+}
+
+void TestShell();
+
+int main()
+{
+ pc.baud(460800);
+ printf("BlueUSB\nNow get a bunch of usb or bluetooth things and plug them in\n");
+ TestShell();
+}
diff -r 000000000000 -r db1ba09e8bfa mbed.bld
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld Tue Jul 10 11:36:47 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/49a220cc26e0