KAMUI USB HOST MIDI-CV Example based on Peter Barrett's BlueUSB

Dependencies:   TextLCD mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers USBHost.cpp Source File

USBHost.cpp

00001 
00002 /*
00003 Copyright (c) 2010 Peter Barrett
00004 
00005 Permission is hereby granted, free of charge, to any person obtaining a copy
00006 of this software and associated documentation files (the "Software"), to deal
00007 in the Software without restriction, including without limitation the rights
00008 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00009 copies of the Software, and to permit persons to whom the Software is
00010 furnished to do so, subject to the following conditions:
00011 
00012 The above copyright notice and this permission notice shall be included in
00013 all copies or substantial portions of the Software.
00014 
00015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00018 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00019 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00020 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00021 THE SOFTWARE.
00022 */
00023 
00024 /* 
00025 May 11 2012 RadioJunkBox : added MIDI USB support
00026 */
00027 
00028 #include "mbed.h"
00029 #include "USBHost.h"
00030 
00031 //    Config (default uses x bytes)
00032 #define MAX_DEVICES 8                // Max number of devices
00033 #define MAX_ENDPOINTS_TOTAL 16        // Max number of endpoints total
00034 #define MAX_ENDPOINTS_PER_DEVICE 8    // Max number of endpoints for any one device
00035 
00036 #define  USBLOG 1
00037 #if USBLOG
00038 #define  LOG(...)       printf(__VA_ARGS__)
00039 #else 
00040 #define  LOG(...)       do {} while(0)
00041 #endif
00042 
00043 // USB host structures
00044 
00045 #define USB_RAM_SIZE 16*1024    // AHB SRAM block 1 TODO MACHINE DEPENDENT
00046 #define USB_RAM_BASE 0x2007C000
00047 
00048 #define TOKEN_SETUP 0
00049 #define TOKEN_IN  1
00050 #define TOKEN_OUT 2
00051 
00052 //    Status flags from hub
00053 #define PORT_CONNECTION 0
00054 #define PORT_ENABLE  1
00055 #define PORT_SUSPEND  2
00056 #define PORT_OVER_CURRENT 3
00057 #define PORT_RESET 4
00058 #define PORT_POWER 8
00059 #define PORT_LOW_SPEED 9
00060 
00061 #define C_PORT_CONNECTION 16
00062 #define C_PORT_ENABLE 17
00063 #define C_PORT_SUSPEND 18
00064 #define C_PORT_OVER_CURRENT 19
00065 #define C_PORT_RESET 20
00066 
00067 typedef struct {
00068     u8 bm_request_type;
00069     u8 b_request;
00070     u16 w_value;
00071     u16 w_index;
00072     u16 w_length;
00073 } Setup;
00074 
00075 
00076 //    Hub stuff is kept private just to keep api simple
00077 int SetPortFeature(int device, int feature, int index);
00078 int ClearPortFeature(int device, int feature, int index);
00079 int SetPortPower(int device, int port);
00080 int SetPortReset(int device, int port);
00081 int GetPortStatus(int device, int port, u32* status);
00082 
00083 //===================================================================
00084 //===================================================================
00085 //    Hardware defines
00086 
00087 //    HcControl
00088 #define PeriodicListEnable    0x00000004
00089 #define    IsochronousEnable    0x00000008
00090 #define    ControlListEnable    0x00000010
00091 #define    BulkListEnable        0x00000020
00092 #define    OperationalMask        0x00000080
00093 #define    HostControllerFunctionalState    0x000000C0
00094 
00095 //    HcCommandStatus
00096 #define HostControllerReset    0x00000001
00097 #define ControlListFilled    0x00000002
00098 #define BulkListFilled        0x00000004
00099 
00100 //    HcInterruptStatus Register
00101 #define    WritebackDoneHead        0x00000002
00102 #define    StartofFrame            0x00000004
00103 #define ResumeDetected            0x00000008
00104 #define UnrecoverableError        0x00000010
00105 #define FrameNumberOverflow        0x00000020
00106 #define RootHubStatusChange        0x00000040
00107 #define OwnershipChange            0x00000080
00108 #define MasterInterruptEnable    0x80000000
00109 
00110 //    HcRhStatus
00111 #define SetGlobalPower            0x00010000
00112 #define DeviceRemoteWakeupEnable    0x00008000
00113 
00114 //    HcRhPortStatus (hub 0, port 1)
00115 #define CurrentConnectStatus    0x00000001
00116 #define    PortEnableStatus        0x00000002
00117 #define PortSuspendStatus        0x00000004
00118 #define PortOverCurrentIndicator    0x00000008
00119 #define PortResetStatus            0x00000010
00120 
00121 #define PortPowerStatus            0x00000100
00122 #define LowspeedDevice            0x00000200
00123 #define HighspeedDevice            0x00000400
00124 
00125 #define ConnectStatusChange    (CurrentConnectStatus << 16)
00126 #define PortResetStatusChange    (PortResetStatus << 16)
00127 
00128 
00129 #define  TD_ROUNDING        (u32)0x00040000
00130 #define  TD_SETUP            (u32)0x00000000
00131 #define  TD_IN                (u32)0x00100000
00132 #define  TD_OUT                (u32)0x00080000
00133 #define  TD_DELAY_INT(x)    (u32)((x) << 21)
00134 #define  TD_TOGGLE_0        (u32)0x02000000
00135 #define  TD_TOGGLE_1        (u32)0x03000000
00136 #define  TD_CC                (u32)0xF0000000
00137 
00138 //    HostController EndPoint Descriptor
00139 typedef struct {
00140     volatile u32    Control;
00141     volatile u32    TailTd;
00142     volatile u32    HeadTd;
00143     volatile u32    Next;
00144 } HCED;
00145 
00146 // HostController Transfer Descriptor
00147 typedef struct {
00148     volatile u32    Control;
00149     volatile u32    CurrBufPtr;
00150     volatile u32    Next;
00151     volatile u32    BufEnd;
00152 } HCTD;
00153 
00154 // Host Controller Communication Area
00155 typedef struct {
00156     volatile u32    InterruptTable[32];
00157     volatile u16    FrameNumber;
00158     volatile u16    FrameNumberPad;
00159     volatile u32    DoneHead;
00160     volatile u8        Reserved[120];
00161 } HCCA;
00162 
00163 //====================================================================================
00164 //====================================================================================
00165 
00166 class HostController;
00167 class Endpoint;
00168 class Device;
00169 
00170 //      must be 3*16 bytes long
00171 class Endpoint
00172 {
00173 public:
00174     HCED    EndpointDescriptor;    // Pointer to EndpointDescriptor == Pointer to Endpoint
00175     HCTD    TDHead;
00176 
00177     enum State
00178     {
00179         Free,
00180         NotQueued,
00181         Idle,
00182         SetupQueued,
00183         DataQueued,
00184         StatusQueued,
00185         CallbackPending
00186     };
00187     
00188     volatile u8 CurrentState;
00189     u8        Flags;            // 0x80 In, 0x03 mask endpoint type
00190 
00191     u16        Length;
00192     u8*        Data;
00193     USBCallback Callback;     // Must be a multiple of 16 bytes long
00194     void*  UserData;
00195   
00196     int Address()
00197     {
00198         int ep = (EndpointDescriptor.Control >> 7) & 0xF;
00199         if (ep)
00200             ep |= Flags & 0x80;
00201         return ep;
00202     }
00203     
00204     int Device()
00205     {
00206         return EndpointDescriptor.Control & 0x7F;
00207     }
00208 
00209     int Status()
00210     {
00211         return (TDHead.Control >> 28) & 0xF;
00212     }
00213 
00214     u32 Enqueue(u32 head)
00215     {
00216         if (CurrentState == NotQueued)
00217         {
00218             EndpointDescriptor.Next = head;
00219             head = (u32)&EndpointDescriptor;
00220             CurrentState = Idle;
00221         }
00222         return head;
00223     }
00224 };
00225 
00226 class Device
00227 {
00228 public:
00229     u8    _endpointMap[MAX_ENDPOINTS_PER_DEVICE*2];
00230     u8    Hub;
00231     u8    Port;
00232     u8    Addr;
00233     u8    Pad;
00234 
00235     //    Only if this device is a hub
00236     u8    HubPortCount;    // nonzero if this is a hub
00237     u8    HubInterruptData;
00238     u8    HubMap;
00239     u8    HubMask;
00240 
00241     int Flags;        // 1 = Disconnected
00242 
00243     Setup    SetupBuffer;
00244 
00245     // Allocate endpoint zero
00246     int Init(DeviceDescriptor* d, int hub, int port, int addr, int lowSpeed)
00247     {
00248         Hub = hub;
00249         Port = port;
00250         Addr = addr;
00251         Flags = lowSpeed;
00252         memset(_endpointMap,0xFF,sizeof(_endpointMap));
00253         return 0;
00254     }
00255 
00256     int SetEndpointIndex(int ep, int endpointIndex)
00257     {
00258         for (int i = 0; i < MAX_ENDPOINTS_PER_DEVICE*2; i += 2)
00259         {
00260             if (_endpointMap[i] == 0xFF)    // Add endpoint to map
00261             {
00262                 _endpointMap[i] = ep;
00263                 _endpointMap[i+1] = endpointIndex;
00264                 return 0;
00265             }
00266         }
00267         return ERR_ENDPOINT_NONE_LEFT;
00268     }
00269 
00270     int GetEndpointIndex(int ep)
00271     {
00272         for (int i = 0; i < MAX_ENDPOINTS_PER_DEVICE*2; i += 2)
00273         {
00274             if (_endpointMap[i] == ep)
00275                 return _endpointMap[i+1];
00276             if (_endpointMap[i] == 0xFF)
00277                 break;
00278         }
00279         return -1;
00280     }
00281 };
00282 
00283 class HostController
00284 {
00285 public:
00286     HCCA        CommunicationArea;
00287     Endpoint    Endpoints[MAX_ENDPOINTS_TOTAL];    // Multiple of 16
00288     
00289     Endpoint    EndpointZero;                        // For device enumeration
00290     HCTD        _commonTail;
00291     Setup        _setupZero;
00292     
00293     Device    Devices[MAX_DEVICES];
00294     u32    _frameNumber;            // 32 bit ms counter
00295 
00296     u8    _callbacksPending;        //    Endpoints with callbacks are pending, set from ISR via ProcessDoneQueue
00297     u8    _rootHubStatusChange;    //    Root hub status has changed, set from ISR
00298     u8    _unused0;
00299     u8    _unused1;
00300 
00301     u8    _connectPending;    //    Reset has initiated a connect
00302     u8    _connectCountdown;    //    Number of ms left after reset before we can connect
00303     u8    _connectHub;        //    Will connect on this hub
00304     u8    _connectPort;        //    ... and this port
00305 
00306     u8    SRAM[0];            // Start of free SRAM
00307 
00308     void Loop()
00309     {
00310         u16 elapsed = CommunicationArea.FrameNumber - (u16)_frameNumber;    // extend to 32 bits
00311         _frameNumber += elapsed;
00312 
00313         // Do callbacks, if any
00314         while (_callbacksPending)
00315         {
00316             for (int i = 0; i < MAX_ENDPOINTS_TOTAL; i++)
00317             {
00318                 Endpoint* endpoint = Endpoints + i;
00319                 if (endpoint->CurrentState == Endpoint::CallbackPending)
00320                 {
00321                     _callbacksPending--;
00322                     endpoint->CurrentState = Endpoint::Idle;
00323                     endpoint->Callback(endpoint->Device(),endpoint->Address(),endpoint->Status(),endpoint->Data,endpoint->Length,endpoint->UserData);
00324                 }
00325             }
00326         }
00327 
00328         //    Deal with changes on the root hub
00329         if (_rootHubStatusChange)
00330         {
00331             u32 status = LPC_USB->HcRhPortStatus1;
00332             _rootHubStatusChange = 0;
00333             if (status >> 16)
00334             {
00335                 HubStatusChange(0,1,status);
00336                 LPC_USB->HcRhPortStatus1 = status & 0xFFFF0000;    // clear status changes
00337             }
00338         }
00339 
00340         //    Connect after reset timeout
00341         if (_connectCountdown)
00342         {
00343             if (elapsed >= _connectCountdown)
00344             {
00345                 _connectCountdown = 0;
00346                 Connect(_connectHub,_connectPort & 0x7F,_connectPort & 0x80);
00347             } else
00348                 _connectCountdown -= elapsed;
00349         }
00350     }
00351 
00352     //    HubInterrupt - bitmap in dev->HubInterruptData
00353     void HubInterrupt(int device)
00354     {
00355         Device* dev = &Devices[device-1];
00356         for (int i = 0; i < dev->HubPortCount; i++)
00357         {
00358             int port = i+1;
00359             if (dev->HubInterruptData & (1 << port))
00360             {
00361                 u32 status = 0;
00362                 GetPortStatus(device,port,&status);
00363                 if (status >> 16)
00364                 {
00365                     if (_connectPending && (status & ConnectStatusChange))
00366                         continue;    // Don't connect again until previous device has been added and addressed
00367 
00368                     HubStatusChange(device,port,status);
00369                     if (status & ConnectStatusChange)
00370                         ClearPortFeature(device,C_PORT_CONNECTION,port);
00371                     if (status & PortResetStatusChange)
00372                         ClearPortFeature(device,C_PORT_RESET,port);
00373                 }
00374             }
00375         }
00376     }
00377 
00378     static void HubInterruptCallback(int device, int endpoint, int status, u8* data, int len, void* userData)
00379     {
00380         HostController* controller = (HostController*)userData;
00381         if (status == 0)
00382             controller->HubInterrupt(device);
00383         USBInterruptTransfer(device,endpoint,data,1,HubInterruptCallback,userData);
00384     }
00385 
00386     int InitHub(int device)
00387     {
00388         u8 buf[16];
00389         int r= USBControlTransfer(device,DEVICE_TO_HOST | REQUEST_TYPE_CLASS | RECIPIENT_DEVICE,GET_DESCRIPTOR,(DESCRIPTOR_TYPE_HUB << 8),0,buf,sizeof(buf));
00390         if (r < 0)
00391             return ERR_HUB_INIT_FAILED;
00392         
00393         //    turn on power on the hubs ports
00394         Device* dev = &Devices[device-1];
00395         int ports = buf[2];
00396         dev->HubPortCount = ports;
00397         for (int i = 0; i < ports; i++)
00398             SetPortPower(device,i+1);
00399         
00400         // Enable hub change interrupts
00401         return USBInterruptTransfer(device,0x81,&dev->HubInterruptData,1,HubInterruptCallback,this);
00402     }
00403     
00404     int AddEndpoint(int device, int ep, int attributes, int maxPacketSize, int interval)
00405     {
00406         LOG("AddEndpoint D:%02X A:%02X T:%02X P:%04X I:%02X\n",device,ep,attributes,maxPacketSize,interval);
00407         Device* dev = &Devices[device-1];
00408         Endpoint* endpoint = AllocateEndpoint(device,ep,attributes,maxPacketSize);
00409         if (!endpoint)
00410             return ERR_ENDPOINT_NONE_LEFT;
00411         dev->SetEndpointIndex(ep,endpoint - Endpoints);
00412         endpoint->EndpointDescriptor.Control |= dev->Flags; // Map in slow speed
00413         return 0;  // TODO ed->bInterval
00414     }
00415     
00416     int AddEndpoint(int device, EndpointDescriptor* ed)
00417     {
00418         return AddEndpoint(device,ed->bEndpointAddress,ed->bmAttributes,ed->wMaxPacketSize,ed->bInterval);
00419     }
00420 
00421     //      allocate a endpoint
00422     Endpoint* AllocateEndpoint(int device, int endpointAddress, int type, int maxPacketSize)
00423     {
00424         for (int i = 0; i < MAX_ENDPOINTS_TOTAL; i++)
00425         {
00426             Endpoint* ep = &Endpoints[i];
00427             if (ep->CurrentState == 0)
00428             {
00429                 //LOG("Allocated endpoint %d to %02X:%02X\n",i,device,endpointAddress);
00430                 ep->Flags = (endpointAddress & 0x80) | (type & 3);
00431                 ep->CurrentState = Endpoint::NotQueued;
00432                 ep->EndpointDescriptor.Control = (maxPacketSize << 16) | ((endpointAddress & 0x7F) << 7) | device;
00433                 return ep;
00434             }
00435         }
00436         return 0;
00437     }
00438 
00439     Endpoint* GetEndpoint(int device, int ep)
00440     {
00441         if (device == 0)
00442         {
00443             //printf("WARNING: USING DEVICE 0\n");
00444             return &EndpointZero;
00445         }
00446         if (device > MAX_DEVICES)
00447             return 0;
00448         int i = Devices[device-1].GetEndpointIndex(ep);
00449         if (i == -1)
00450             return 0;
00451         return Endpoints + i;
00452     }
00453 
00454     int Transfer(Endpoint* endpoint, int token, u8* data, int len, int state)
00455     {
00456         //LOG("Transfer %02X T:%d Len:%d S:%d\n",endpoint->Address(),token,len,state);
00457     
00458         int toggle = 0;
00459         if (endpoint->Address() == 0)
00460             toggle = (token == TOKEN_SETUP) ? TD_TOGGLE_0 : TD_TOGGLE_1;
00461 
00462         if (token != TOKEN_SETUP)
00463             token = (token == TOKEN_IN ? TD_IN : TD_OUT);
00464 
00465         HCTD* head = &endpoint->TDHead;
00466         HCTD* tail = &_commonTail;
00467 
00468         head->Control = TD_ROUNDING | token | TD_DELAY_INT(0) | toggle | TD_CC; 
00469         head->CurrBufPtr = (u32)data;
00470         head->BufEnd = (u32)(data + len - 1);
00471         head->Next = (u32)tail;
00472 
00473         HCED* ed = &endpoint->EndpointDescriptor;
00474         ed->HeadTd = (u32)head | (ed->HeadTd & 0x00000002);    // carry toggle
00475         ed->TailTd = (u32)tail;
00476         
00477         //HCTD* td = head;
00478         //LOG("%04X TD %08X %08X %08X Next:%08X\n",CommunicationArea.FrameNumber,td->Control,td->CurrBufPtr,td->BufEnd,td->Next);
00479         //LOG("%04X ED %08X %08X %08X\n",CommunicationArea.FrameNumber,ed->Control,ed->HeadTd,ed->TailTd);
00480         
00481         switch (endpoint->Flags & 3)
00482         {
00483             case ENDPOINT_CONTROL:
00484                 LPC_USB->HcControlHeadED = endpoint->Enqueue(LPC_USB->HcControlHeadED);    // May change state NotQueued->Idle
00485                 endpoint->CurrentState = state;                                               // Get in before an int
00486                 LPC_USB->HcCommandStatus = LPC_USB->HcCommandStatus | ControlListFilled;
00487                 LPC_USB->HcControl = LPC_USB->HcControl | ControlListEnable;
00488                 break;
00489 
00490             case ENDPOINT_BULK:
00491                 LPC_USB->HcBulkHeadED = endpoint->Enqueue(LPC_USB->HcBulkHeadED);
00492                 endpoint->CurrentState = state;
00493                 LPC_USB->HcCommandStatus = LPC_USB->HcCommandStatus | BulkListFilled;
00494                 LPC_USB->HcControl = LPC_USB->HcControl | BulkListEnable;
00495                 break;
00496 
00497             case ENDPOINT_INTERRUPT:
00498                 CommunicationArea.InterruptTable[0] = endpoint->Enqueue(CommunicationArea.InterruptTable[0]);
00499                 endpoint->CurrentState = state;
00500                 LPC_USB->HcControl |= PeriodicListEnable;
00501                 break;
00502         }
00503         return 0;
00504     }
00505     
00506     //    Remove an endpoint from an active queue
00507     bool Remove(HCED* ed, volatile HCED** queue)
00508     {
00509         if (*queue == 0)
00510             return false;
00511         if (*queue == (volatile HCED*)ed)
00512         {
00513             *queue = (volatile HCED*)ed->Next;    // At head of queue
00514             return true;
00515         }
00516 
00517         volatile HCED* head = *queue;
00518         while (head)
00519         {
00520             if (head->Next == (u32)ed)
00521             {
00522                 head->Next = ed->Next;
00523                 return true;
00524             }
00525             head = (volatile HCED*)head->Next;
00526         }
00527         return false;
00528     }
00529 
00530     void Release(Endpoint* endpoint)
00531     {
00532         if (endpoint->CurrentState == Endpoint::NotQueued)
00533         {
00534             // Never event used it, nothing to do
00535         }
00536         else
00537         {
00538             HCED* ed = (HCED*)endpoint;
00539             ed->Control |= 0x4000;    // SKIP
00540             switch (endpoint->Flags & 0x03)
00541             {
00542                 case ENDPOINT_CONTROL:
00543                     Remove(ed,(volatile HCED**)&LPC_USB->HcControlHeadED);
00544                     break;
00545                 case ENDPOINT_BULK:
00546                     Remove(ed,(volatile HCED**)&LPC_USB->HcBulkHeadED);
00547                     break;
00548                 case ENDPOINT_INTERRUPT:
00549                     for (int i = 0; i < 32; i++)
00550                         Remove(ed,(volatile HCED**)&CommunicationArea.InterruptTable[i]);
00551                     break;
00552             }
00553 
00554             u16 fn = CommunicationArea.FrameNumber;
00555             while (fn == CommunicationArea.FrameNumber)
00556                 ;    // Wait for next frame
00557 
00558         }
00559 
00560         //    In theory, the endpoint is now dead.
00561         //    TODO: Will Callbacks ever be pending? BUGBUG
00562         memset(endpoint,0,sizeof(Endpoint));
00563     }
00564 
00565     //      Pop the last TD from the list
00566     HCTD* Reverse(HCTD* current) 
00567     { 
00568         HCTD *result = NULL,*temp; 
00569         while (current) 
00570         { 
00571             temp = (HCTD*)current->Next; 
00572             current->Next = (u32)result;
00573             result = current;
00574             current = temp;
00575         }
00576         return result;
00577     }
00578 
00579     //      Called from interrupt...
00580     //      Control endpoints use a state machine to progress through the transfers
00581     void ProcessDoneQueue(u32 tdList)
00582     {
00583         HCTD* list = Reverse((HCTD*)tdList);
00584         while (list)
00585         {
00586             Endpoint* endpoint = (Endpoint*)(list-1);
00587             list = (HCTD*)list->Next;
00588             int ep = endpoint->Address();
00589             bool in = endpoint->Flags & 0x80;
00590             int status = (endpoint->TDHead.Control >> 28) & 0xF;
00591 
00592             //LOG("ProcessDoneQueue %02X %08X\n",ep,endpoint->TDHead.Control);
00593 
00594             if (status != 0)
00595             {
00596                 LOG("ProcessDoneQueue status %02X %d\n",ep,status);
00597                 endpoint->CurrentState = Endpoint::Idle;
00598             } else {
00599                 switch (endpoint->CurrentState)
00600                 {
00601                     case Endpoint::SetupQueued:
00602                         if (endpoint->Length == 0)
00603                             Transfer(endpoint,in ? TOKEN_OUT : TOKEN_IN,0,0,Endpoint::StatusQueued);    // Skip Data Phase
00604                         else
00605                             Transfer(endpoint,in ? TOKEN_IN : TOKEN_OUT,endpoint->Data,endpoint->Length, Endpoint::DataQueued);    // Setup is done, now Data
00606                         break;
00607 
00608                     case Endpoint::DataQueued:
00609                         if (endpoint->TDHead.CurrBufPtr)
00610                             endpoint->Length = endpoint->TDHead.CurrBufPtr - (u32)endpoint->Data;
00611 
00612                         if (ep == 0)
00613                             Transfer(endpoint,in ? TOKEN_OUT : TOKEN_IN,0,0,Endpoint::StatusQueued);    // Data is done, now Status, Control only
00614                         else
00615                             endpoint->CurrentState = Endpoint::Idle;
00616                         break;
00617 
00618                     case Endpoint::StatusQueued:    // Transaction is done
00619                         endpoint->CurrentState = Endpoint::Idle;
00620                         break;
00621                 }
00622             }
00623 
00624             //      Complete, flag if we need a callback
00625             if (endpoint->Callback && endpoint->CurrentState == Endpoint::Idle)
00626             {
00627                 endpoint->CurrentState = Endpoint::CallbackPending;
00628                 _callbacksPending++;
00629             }
00630         }
00631     }
00632 
00633     //    Hack to reset devices that don't want to connect
00634     int AddDevice(int hub, int port, bool isLowSpeed)
00635     {
00636         int device = AddDeviceCore(hub,port,isLowSpeed);
00637         if (device < 0)
00638         {
00639             LOG("========RETRY ADD DEVICE========\n");    // This will go for ever.. TODO power cycle root?
00640             Disconnect(hub,port);    // Could not read descriptor at assigned address, reset this port and try again
00641             ResetPort(hub,port);    // Cheap bluetooth dongles often need this on a hotplug
00642             return -1;
00643         }
00644         return device;
00645     }
00646 
00647     int AddDeviceCore(int hub, int port, bool isLowSpeed)
00648     {
00649         int lowSpeed = isLowSpeed ? 0x2000 : 0;
00650         DeviceDescriptor desc;
00651         EndpointZero.EndpointDescriptor.Control = (8 << 16) | lowSpeed;               // MaxPacketSize == 8
00652         int r = GetDescriptor(0,DESCRIPTOR_TYPE_DEVICE,0,(u8*)&desc,8);
00653         if (r < 0)
00654         {
00655             LOG("FAILED TO LOAD DESCRIPTOR FOR DEVICE 0\n");
00656             return r;
00657         }
00658 
00659         EndpointZero.EndpointDescriptor.Control = (desc.bMaxPacketSize << 16) | lowSpeed;     // Actual MaxPacketSize
00660         r = GetDescriptor(0,DESCRIPTOR_TYPE_DEVICE,0,(u8*)&desc,sizeof(desc));
00661         if (r < 0)
00662             return r;
00663 
00664         LOG("\nClass %02X found %04X:%04X\n\n",desc.bDeviceClass,desc.idVendor,desc.idProduct);
00665 
00666         //      Now assign the device an address, move off EndpointZero
00667         int device = 0;
00668         for (int i = 0; i < MAX_DEVICES; i++)
00669         {
00670             if (Devices[i].Port == 0)
00671             {
00672                 device = i+1;
00673                 break;
00674             }
00675         }
00676         if (!device)
00677             return ERR_DEVICE_NONE_LEFT;
00678 
00679         r = SetAddress(0,device);
00680         if (r)
00681             return r;
00682         DelayMS(2);
00683         
00684         // Now at a nonzero address, create control endpoint
00685         Device* dev = &Devices[device-1];
00686         dev->Init(&desc,hub,port,device,lowSpeed);
00687         AddEndpoint(device,0,ENDPOINT_CONTROL,desc.bMaxPacketSize,0);
00688         _connectPending = 0;
00689 
00690         //    Verify this all works
00691         r = GetDescriptor(device,DESCRIPTOR_TYPE_DEVICE,0,(u8*)&desc,sizeof(desc));
00692         if (r < 0)
00693             return r;
00694 
00695         //    Set to interface 0 by default
00696         //    Calls LoadDevice if interface is found
00697         r = SetConfigurationAndInterface(device,1,0,&desc);
00698 
00699         if (desc.bDeviceClass == CLASS_HUB)
00700             InitHub(device);            // Handle hubs in this code
00701 
00702         return device;
00703     }
00704 
00705     // Walk descriptors and create endpoints for a given device
00706     // TODO configuration !=1, alternate settings etc.
00707     int SetConfigurationAndInterface(int device, int configuration, int interfaceNumber, DeviceDescriptor* desc)
00708     {
00709         u8 buffer[255];
00710         int err = GetDescriptor(device,DESCRIPTOR_TYPE_CONFIGURATION,0,buffer,sizeof(buffer));
00711         if (err < 0)
00712             return err;
00713 
00714         err = SetConfiguration(device,configuration);
00715         if (err < 0)
00716             return err;
00717 
00718         //    Add the endpoints for this interface
00719         int len = buffer[2] | (buffer[3] << 8);
00720         u8* d = buffer;
00721         u8* end = d + len;
00722         InterfaceDescriptor* found = 0;
00723         while (d < end)
00724         {
00725             if (d[1] == DESCRIPTOR_TYPE_INTERFACE)
00726             {
00727                 InterfaceDescriptor* id = (InterfaceDescriptor*)d;
00728 //  Modified by RadioJunkBox  ---------------------------------
00729                 if (id->bNumEndpoints != 0) 
00730 //                if (id->bInterfaceNumber == interfaceNumber)  
00731 //  -----------------------------------------------------------
00732                 {
00733                     found = id;
00734                     d += d[0];
00735                     while (d < end && d[1] != DESCRIPTOR_TYPE_INTERFACE)
00736                     {
00737                         switch (d[1])
00738                         {
00739                             case DESCRIPTOR_TYPE_ENDPOINT:
00740                                 AddEndpoint(device,(EndpointDescriptor*)d);
00741                                 break;
00742                             default:
00743                                 LOG("Skipping descriptor %02X (%d bytes)\n",d[1],d[0]);
00744                         }
00745                         d += d[0];
00746                     }
00747                 }
00748             }
00749             d += d[0];
00750         }
00751 
00752         if (!found)
00753             return ERR_INTERFACE_NOT_FOUND;
00754         OnLoadDevice(device,desc,found);
00755         return 0;
00756     }
00757 
00758     void Init()
00759     {
00760         LOG("USB INIT (Controller is %d bytes)\n",sizeof(*this));
00761         memset(this,0,sizeof(HostController));
00762         EndpointZero.CurrentState = Endpoint::NotQueued;
00763         HWInit(&CommunicationArea);
00764         DelayMS(10);
00765     }
00766 
00767     void ResetPort(int hub, int port)
00768     {
00769         LOG("ResetPort Hub:%d Port:%d\n",hub,port);
00770         _connectPending++;            // Only reset/add 1 device at a time
00771         if (hub == 0)
00772             LPC_USB->HcRhPortStatus1 = PortResetStatus;    // Reset Root Hub, port 1
00773         else
00774             SetPortReset(hub,port);    // or reset other hub
00775     }
00776 
00777     void Disconnect(int hub, int port)
00778     {
00779         LOG("Disconnect Hub:%d Port:%d\n",hub,port);    // Mark a device for destruction
00780         for (int i = 0; i < MAX_DEVICES; i++)
00781         {
00782             Device* dev = Devices + i;
00783             if (dev->Port == port && dev->Hub == hub)
00784             {
00785                 //    Disconnect everything that is attached to this device if it is a hub
00786                 for (int p = 0; p < dev->HubPortCount; p++)
00787                     Disconnect(i+1,p+1);
00788 
00789                 //    Now release endpoints
00790                 for (int j = 1; j < MAX_ENDPOINTS_PER_DEVICE*2; j += 2)
00791                 {
00792                     u8 endpointIndex = dev->_endpointMap[j];
00793                     if (endpointIndex != 0xFF)
00794                         Release(Endpoints + endpointIndex);
00795                 }
00796                 dev->Port = 0;    // Device is now free
00797                 dev->Flags = 0;
00798                 return;
00799             }
00800         }
00801     }
00802 
00803     // called after reset
00804     void Connect(int hub, int port, bool lowspeed)
00805     {
00806         LOG("Connect Hub:%d Port:%d %s\n",hub,port,lowspeed ? "slow" : "full");
00807         AddDevice(hub,port,lowspeed);
00808     }
00809 
00810     // Called from interrupt
00811     void HubStatusChange(int hub, int port, u32 status)
00812     {
00813         LOG("HubStatusChange Hub:%d Port:%d %08X\n",hub,port,status);
00814         if (status & ConnectStatusChange)
00815         {
00816             if (status & CurrentConnectStatus)    // Connecting
00817                 ResetPort(hub,port);            // Reset to initiate connect (state machine?)
00818             else
00819                 Disconnect(hub,port);
00820         }
00821 
00822         if (status & PortResetStatusChange)
00823         {
00824             if (!(status & PortResetStatus))
00825             {
00826                 _connectCountdown = 200;        // Schedule a connection in 200ms
00827                 if (status & LowspeedDevice)
00828                     port |= 0x80;
00829                 _connectHub = hub;
00830                 _connectPort = port;
00831             }
00832         }
00833     }
00834 
00835     #define HOST_CLK_EN        (1<<0)
00836     #define PORTSEL_CLK_EN    (1<<3)
00837     #define AHB_CLK_EN        (1<<4)
00838     #define CLOCK_MASK        (HOST_CLK_EN | PORTSEL_CLK_EN | AHB_CLK_EN)
00839 
00840     #define  FRAMEINTERVAL        (12000-1)    // 1ms
00841     #define  DEFAULT_FMINTERVAL    ((((6 * (FRAMEINTERVAL - 210)) / 7) << 16) | FRAMEINTERVAL)
00842 
00843     void DelayMS(int ms)
00844     {
00845         u16 f = ms + CommunicationArea.FrameNumber;
00846         while (f != CommunicationArea.FrameNumber)
00847             ;
00848     }
00849 
00850     static void HWInit(HCCA* cca)
00851     {
00852         NVIC_DisableIRQ(USB_IRQn);
00853         
00854         // turn on power for USB
00855         LPC_SC->PCONP        |= (1UL<<31);
00856         // Enable USB host clock, port selection and AHB clock
00857         LPC_USB->USBClkCtrl |= CLOCK_MASK;
00858         // Wait for clocks to become available
00859         while ((LPC_USB->USBClkSt & CLOCK_MASK) != CLOCK_MASK)
00860             ;
00861         
00862         //    We are a Host
00863         LPC_USB->OTGStCtrl |= 1;
00864         LPC_USB->USBClkCtrl &= ~PORTSEL_CLK_EN;                // we don't need port selection clock until we do OTG
00865         
00866         // configure USB pins
00867         LPC_PINCON->PINSEL1 &= ~((3<<26)|(3<<28));    
00868         LPC_PINCON->PINSEL1 |=    ((1<<26)|(1<<28));            // USB D+/D-
00869             
00870         LPC_PINCON->PINSEL3 &= ~((3 << 6) | (3 << 22));        // USB_PPWR, USB_OVRCR
00871         LPC_PINCON->PINSEL3 |= ((2 << 6) | (2 << 22));
00872         
00873         LPC_PINCON->PINSEL4 &= ~(3 << 18);                    // USB_CONNECT
00874         LPC_PINCON->PINSEL4 |= (1 << 18);
00875 
00876         //    Reset OHCI block
00877         LPC_USB->HcControl         = 0;
00878         LPC_USB->HcControlHeadED = 0;
00879         LPC_USB->HcBulkHeadED     = 0;
00880         
00881         LPC_USB->HcCommandStatus = HostControllerReset;
00882         LPC_USB->HcFmInterval     = DEFAULT_FMINTERVAL;
00883         LPC_USB->HcPeriodicStart = FRAMEINTERVAL*90/100;
00884 
00885         LPC_USB->HcControl    = (LPC_USB->HcControl & (~HostControllerFunctionalState)) | OperationalMask;
00886         LPC_USB->HcRhStatus = SetGlobalPower;
00887         
00888         LPC_USB->HcHCCA = (u32)cca;
00889         LPC_USB->HcInterruptStatus |= LPC_USB->HcInterruptStatus;
00890         LPC_USB->HcInterruptEnable = MasterInterruptEnable | WritebackDoneHead | RootHubStatusChange | FrameNumberOverflow;
00891 
00892         NVIC_SetPriority(USB_IRQn, 0);
00893         NVIC_EnableIRQ(USB_IRQn);
00894         while (cca->FrameNumber < 10)
00895             ;    // 10ms delay before diving in
00896     }
00897 };
00898 
00899 //====================================================================================
00900 //====================================================================================
00901 //      Host controller instance and Interrupt handler
00902 
00903 static HostController _controller __attribute__((at(USB_RAM_BASE)));
00904 
00905 extern "C" void USB_IRQHandler(void) __irq;
00906 void USB_IRQHandler (void) __irq
00907 {
00908     u32 int_status = LPC_USB->HcInterruptStatus;
00909 
00910     if (int_status & RootHubStatusChange)    //    Root hub status change
00911         _controller._rootHubStatusChange++;    //    Just flag the controller, will be processed in USBLoop
00912 
00913     u32 head = 0;
00914     if (int_status & WritebackDoneHead)
00915     {
00916         head = _controller.CommunicationArea.DoneHead;        // Writeback Done
00917         _controller.CommunicationArea.DoneHead = 0;
00918     }             
00919     LPC_USB->HcInterruptStatus = int_status;
00920 
00921     if (head)
00922        _controller.ProcessDoneQueue(head);     // TODO - low bit can be set BUGBUG
00923 }
00924 
00925 //====================================================================================
00926 //====================================================================================
00927 //      API Methods
00928 
00929 void USBInit()
00930 {
00931     return _controller.Init();
00932 }
00933 
00934 void USBLoop()
00935 {
00936     return _controller.Loop();
00937 }
00938 
00939 u8* USBGetBuffer(u32* len)
00940 {
00941     *len = USB_RAM_SIZE - sizeof(HostController);
00942     return _controller.SRAM;
00943 }
00944 
00945 static Setup* GetSetup(int device)
00946 {
00947     if (device == 0)
00948         return &_controller._setupZero;
00949     
00950     if (device < 1 || device > MAX_DEVICES)
00951         return 0;
00952     return &_controller.Devices[device-1].SetupBuffer;
00953 }
00954 
00955 //    Loop until IO on endpoint is complete
00956 static int WaitIODone(Endpoint* endpoint)
00957 {
00958     if (endpoint->CurrentState == Endpoint::NotQueued)
00959         return 0;
00960     while (endpoint->CurrentState != Endpoint::Idle)
00961         USBLoop();    // May generate callbacks, mount or unmount devices etc
00962     int status = endpoint->Status();
00963     if (status == 0)
00964         return endpoint->Length;
00965     return -status;
00966 }
00967 
00968 int USBTransfer(int device, int ep, u8 flags, u8* data, int length, USBCallback callback, void* userData)
00969 {
00970     Endpoint* endpoint = _controller.GetEndpoint(device,ep);
00971     if (!endpoint)
00972         return ERR_ENDPOINT_NOT_FOUND;
00973         
00974     WaitIODone(endpoint);
00975     endpoint->Flags = flags;
00976     endpoint->Data = data;
00977     endpoint->Length = length;
00978     endpoint->Callback = callback;
00979     endpoint->UserData = userData;
00980     if (ep == 0)
00981         _controller.Transfer(endpoint,TOKEN_SETUP,(u8*)GetSetup(device),8,Endpoint::SetupQueued);
00982     else
00983         _controller.Transfer(endpoint,flags & 0x80 ? TOKEN_IN : TOKEN_OUT,data,length,Endpoint::DataQueued);
00984     if (callback)
00985         return IO_PENDING;
00986     return WaitIODone(endpoint);
00987 }
00988 
00989 int USBControlTransfer(int device, int request_type, int request, int value, int index, u8* data, int length, USBCallback callback, void * userData)
00990 {
00991     Setup* setup = GetSetup(device);
00992     if (!setup)
00993         return ERR_DEVICE_NOT_FOUND;
00994         
00995     // Async control calls may overwrite setup buffer of previous call, so we need to wait before setting up next call
00996     WaitIODone(_controller.GetEndpoint(device,0));
00997     
00998     setup->bm_request_type = request_type;
00999     setup->b_request = request;
01000     setup->w_value = value;
01001     setup->w_index = index;
01002     setup->w_length = length;
01003     return USBTransfer(device,0,request_type & DEVICE_TO_HOST,data,length,callback,userData);
01004 }
01005 
01006 int  USBInterruptTransfer(int device, int ep, u8* data, int length, USBCallback callback, void* userData)
01007 {
01008     return USBTransfer(device,ep,(ep & 0x80) | ENDPOINT_INTERRUPT,data,length,callback,userData);
01009 }
01010 
01011 int  USBBulkTransfer(int device, int ep, u8* data, int length, USBCallback callback, void* userData)
01012 {
01013     return USBTransfer(device,ep,(ep & 0x80) | ENDPOINT_BULK,data,length,callback,userData);
01014 }
01015 
01016 int GetDescriptor(int device, int descType,int descIndex, u8* data, int length)
01017 {
01018     return USBControlTransfer(device,DEVICE_TO_HOST | RECIPIENT_DEVICE, GET_DESCRIPTOR,(descType << 8)|(descIndex), 0, data, length, 0);
01019 }
01020 
01021 int GetString(int device, int index, char* dst, int length)
01022 {
01023     u8 buffer[255];
01024     int le = GetDescriptor(device,DESCRIPTOR_TYPE_STRING,index,buffer,sizeof(buffer));
01025     if (le < 0)
01026         return le;
01027     if (length < 1)
01028         return -1;
01029     length <<= 1;
01030     if (le > length)
01031         le = length;
01032     for (int j = 2; j < le; j += 2)
01033         *dst++ = buffer[j];
01034     *dst = 0;
01035     return (le>>1)-1;
01036 }
01037 
01038 int SetAddress(int device, int new_addr)
01039 {
01040     return USBControlTransfer(device,HOST_TO_DEVICE | RECIPIENT_DEVICE, SET_ADDRESS, new_addr, 0, 0, 0, 0);
01041 }
01042 
01043 int SetConfiguration(int device, int configNum)
01044 {
01045     return USBControlTransfer(device,HOST_TO_DEVICE | RECIPIENT_DEVICE, SET_CONFIGURATION, configNum, 0, 0, 0, 0);
01046 }
01047 
01048 int SetInterface(int device, int ifNum, int altNum)
01049 {
01050     return USBControlTransfer(device,HOST_TO_DEVICE | RECIPIENT_INTERFACE, SET_INTERFACE, altNum, ifNum, 0, 0, 0);
01051 }
01052 
01053 //    HUB stuff
01054 int SetPortFeature(int device, int feature, int index)
01055 {
01056     return USBControlTransfer(device,HOST_TO_DEVICE | REQUEST_TYPE_CLASS | RECIPIENT_OTHER,SET_FEATURE,feature,index,0,0);
01057 }
01058 
01059 int ClearPortFeature(int device, int feature, int index)
01060 {
01061     return USBControlTransfer(device,HOST_TO_DEVICE | REQUEST_TYPE_CLASS | RECIPIENT_OTHER,CLEAR_FEATURE,feature,index,0,0);
01062 }
01063 
01064 int SetPortPower(int device, int port)
01065 {
01066     int r = SetPortFeature(device,PORT_POWER,port);
01067     _controller.DelayMS(20);    // 80ms to turn on a hubs power... DESCRIPTOR? todo
01068     return r;
01069 }
01070 
01071 int SetPortReset(int device, int port)
01072 {
01073     return SetPortFeature(device,PORT_RESET,port);
01074 }
01075 
01076 int GetPortStatus(int device, int port, u32* status)
01077 {
01078     return USBControlTransfer(device,DEVICE_TO_HOST | REQUEST_TYPE_CLASS | RECIPIENT_OTHER,GET_STATUS,0,port,(u8*)status,4);
01079 }