Simons Wii controlled m3pi program

Dependencies:   mbed m3pi ID12RFIDIRQ

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