local fix version of myBlueUSB (http://mbed.org/users/networker/code/myBlueUSB/). - merge deleted files which are required to compile. - enable echo back of received data via RFCOMM.
Dependencies: AvailableMemory FatFileSystem mbed myUSBHost
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 #include "Utils.h" 00027 00028 // Config (default uses x bytes) 00029 #define MAX_DEVICES 8 // Max number of devices 00030 #define MAX_ENDPOINTS_TOTAL 16 // Max number of endpoints total 00031 #define MAX_ENDPOINTS_PER_DEVICE 8 // Max number of endpoints for any one device 00032 00033 #define USBLOG 1 00034 #if USBLOG 00035 #define LOG(...) printf(__VA_ARGS__) 00036 #else 00037 #define LOG(...) do {} while(0) 00038 #endif 00039 00040 // USB host structures 00041 00042 #define USB_RAM_SIZE 16*1024 // AHB SRAM block 1 TODO MACHINE DEPENDENT 00043 #define USB_RAM_BASE 0x2007C000 00044 00045 #define TOKEN_SETUP 0 00046 #define TOKEN_IN 1 00047 #define TOKEN_OUT 2 00048 00049 // Status flags from hub 00050 #define PORT_CONNECTION 0 00051 #define PORT_ENABLE 1 00052 #define PORT_SUSPEND 2 00053 #define PORT_OVER_CURRENT 3 00054 #define PORT_RESET 4 00055 #define PORT_POWER 8 00056 #define PORT_LOW_SPEED 9 00057 00058 #define C_PORT_CONNECTION 16 00059 #define C_PORT_ENABLE 17 00060 #define C_PORT_SUSPEND 18 00061 #define C_PORT_OVER_CURRENT 19 00062 #define C_PORT_RESET 20 00063 00064 typedef struct { 00065 u8 bm_request_type; 00066 u8 b_request; 00067 u16 w_value; 00068 u16 w_index; 00069 u16 w_length; 00070 } Setup; 00071 00072 00073 // Hub stuff is kept private just to keep api simple 00074 int SetPortFeature(int device, int feature, int index); 00075 int ClearPortFeature(int device, int feature, int index); 00076 int SetPortPower(int device, int port); 00077 int SetPortReset(int device, int port); 00078 int GetPortStatus(int device, int port, u32* status); 00079 00080 //=================================================================== 00081 //=================================================================== 00082 // Hardware defines 00083 00084 // HcControl 00085 #define PeriodicListEnable 0x00000004 00086 #define IsochronousEnable 0x00000008 00087 #define ControlListEnable 0x00000010 00088 #define BulkListEnable 0x00000020 00089 #define OperationalMask 0x00000080 00090 #define HostControllerFunctionalState 0x000000C0 00091 00092 // HcCommandStatus 00093 #define HostControllerReset 0x00000001 00094 #define ControlListFilled 0x00000002 00095 #define BulkListFilled 0x00000004 00096 00097 // HcInterruptStatus Register 00098 #define WritebackDoneHead 0x00000002 00099 #define StartofFrame 0x00000004 00100 #define ResumeDetected 0x00000008 00101 #define UnrecoverableError 0x00000010 00102 #define FrameNumberOverflow 0x00000020 00103 #define RootHubStatusChange 0x00000040 00104 #define OwnershipChange 0x00000080 00105 #define MasterInterruptEnable 0x80000000 00106 00107 // HcRhStatus 00108 #define SetGlobalPower 0x00010000 00109 #define DeviceRemoteWakeupEnable 0x00008000 00110 00111 // HcRhPortStatus (hub 0, port 1) 00112 #define CurrentConnectStatus 0x00000001 00113 #define PortEnableStatus 0x00000002 00114 #define PortSuspendStatus 0x00000004 00115 #define PortOverCurrentIndicator 0x00000008 00116 #define PortResetStatus 0x00000010 00117 00118 #define PortPowerStatus 0x00000100 00119 #define LowspeedDevice 0x00000200 00120 #define HighspeedDevice 0x00000400 00121 00122 #define ConnectStatusChange (CurrentConnectStatus << 16) 00123 #define PortResetStatusChange (PortResetStatus << 16) 00124 00125 00126 #define TD_ROUNDING (u32)0x00040000 00127 #define TD_SETUP (u32)0x00000000 00128 #define TD_IN (u32)0x00100000 00129 #define TD_OUT (u32)0x00080000 00130 #define TD_DELAY_INT(x) (u32)((x) << 21) 00131 #define TD_TOGGLE_0 (u32)0x02000000 00132 #define TD_TOGGLE_1 (u32)0x03000000 00133 #define TD_CC (u32)0xF0000000 00134 00135 // HostController EndPoint Descriptor 00136 typedef struct { 00137 volatile u32 Control; 00138 volatile u32 TailTd; 00139 volatile u32 HeadTd; 00140 volatile u32 Next; 00141 } HCED; 00142 00143 // HostController Transfer Descriptor 00144 typedef struct { 00145 volatile u32 Control; 00146 volatile u32 CurrBufPtr; 00147 volatile u32 Next; 00148 volatile u32 BufEnd; 00149 } HCTD; 00150 00151 // Host Controller Communication Area 00152 typedef struct { 00153 volatile u32 InterruptTable[32]; 00154 volatile u16 FrameNumber; 00155 volatile u16 FrameNumberPad; 00156 volatile u32 DoneHead; 00157 volatile u8 Reserved[120]; 00158 } HCCA; 00159 00160 //==================================================================================== 00161 //==================================================================================== 00162 00163 class HostController; 00164 class Endpoint; 00165 class Device; 00166 00167 // must be 3*16 bytes long 00168 class Endpoint 00169 { 00170 public: 00171 HCED EndpointDescriptor; // Pointer to EndpointDescriptor == Pointer to Endpoint 00172 HCTD TDHead; 00173 00174 enum State 00175 { 00176 Free, 00177 NotQueued, 00178 Idle, 00179 SetupQueued, 00180 DataQueued, 00181 StatusQueued, 00182 CallbackPending 00183 }; 00184 00185 volatile u8 CurrentState; 00186 u8 Flags; // 0x80 In, 0x03 mask endpoint type 00187 00188 u16 Length; 00189 u8* Data; 00190 USBCallback Callback; // Must be a multiple of 16 bytes long 00191 void* UserData; 00192 00193 int Address() 00194 { 00195 int ep = (EndpointDescriptor.Control >> 7) & 0xF; 00196 if (ep) 00197 ep |= Flags & 0x80; 00198 return ep; 00199 } 00200 00201 int Device() 00202 { 00203 return EndpointDescriptor.Control & 0x7F; 00204 } 00205 00206 int Status() 00207 { 00208 return (TDHead.Control >> 28) & 0xF; 00209 } 00210 00211 u32 Enqueue(u32 head) 00212 { 00213 if (CurrentState == NotQueued) 00214 { 00215 EndpointDescriptor.Next = head; 00216 head = (u32)&EndpointDescriptor; 00217 CurrentState = Idle; 00218 } 00219 return head; 00220 } 00221 }; 00222 00223 class Device 00224 { 00225 public: 00226 u8 _endpointMap[MAX_ENDPOINTS_PER_DEVICE*2]; 00227 u8 Hub; 00228 u8 Port; 00229 u8 Addr; 00230 u8 Pad; 00231 00232 // Only if this device is a hub 00233 u8 HubPortCount; // nonzero if this is a hub 00234 u8 HubInterruptData; 00235 u8 HubMap; 00236 u8 HubMask; 00237 00238 int Flags; // 1 = Disconnected 00239 00240 Setup SetupBuffer; 00241 00242 // Allocate endpoint zero 00243 int Init(DeviceDescriptor* d, int hub, int port, int addr, int lowSpeed) 00244 { 00245 Hub = hub; 00246 Port = port; 00247 Addr = addr; 00248 Flags = lowSpeed; 00249 memset(_endpointMap,0xFF,sizeof(_endpointMap)); 00250 return 0; 00251 } 00252 00253 int SetEndpointIndex(int ep, int endpointIndex) 00254 { 00255 for (int i = 0; i < MAX_ENDPOINTS_PER_DEVICE*2; i += 2) 00256 { 00257 if (_endpointMap[i] == 0xFF) // Add endpoint to map 00258 { 00259 _endpointMap[i] = ep; 00260 _endpointMap[i+1] = endpointIndex; 00261 return 0; 00262 } 00263 } 00264 return ERR_ENDPOINT_NONE_LEFT; 00265 } 00266 00267 int GetEndpointIndex(int ep) 00268 { 00269 for (int i = 0; i < MAX_ENDPOINTS_PER_DEVICE*2; i += 2) 00270 { 00271 if (_endpointMap[i] == ep) 00272 return _endpointMap[i+1]; 00273 if (_endpointMap[i] == 0xFF) 00274 break; 00275 } 00276 return -1; 00277 } 00278 }; 00279 00280 class HostController 00281 { 00282 public: 00283 HCCA CommunicationArea; 00284 Endpoint Endpoints[MAX_ENDPOINTS_TOTAL]; // Multiple of 16 00285 00286 Endpoint EndpointZero; // For device enumeration 00287 HCTD _commonTail; 00288 Setup _setupZero; 00289 00290 Device Devices[MAX_DEVICES]; 00291 u32 _frameNumber; // 32 bit ms counter 00292 00293 u8 _callbacksPending; // Endpoints with callbacks are pending, set from ISR via ProcessDoneQueue 00294 u8 _rootHubStatusChange; // Root hub status has changed, set from ISR 00295 u8 _unused0; 00296 u8 _unused1; 00297 00298 u8 _connectPending; // Reset has initiated a connect 00299 u8 _connectCountdown; // Number of ms left after reset before we can connect 00300 u8 _connectHub; // Will connect on this hub 00301 u8 _connectPort; // ... and this port 00302 00303 u8 SRAM[0]; // Start of free SRAM 00304 00305 void Loop() 00306 { 00307 u16 elapsed = CommunicationArea.FrameNumber - (u16)_frameNumber; // extend to 32 bits 00308 _frameNumber += elapsed; 00309 00310 // Do callbacks, if any 00311 while (_callbacksPending) 00312 { 00313 for (int i = 0; i < MAX_ENDPOINTS_TOTAL; i++) 00314 { 00315 Endpoint* endpoint = Endpoints + i; 00316 if (endpoint->CurrentState == Endpoint::CallbackPending) 00317 { 00318 _callbacksPending--; 00319 endpoint->CurrentState = Endpoint::Idle; 00320 endpoint->Callback(endpoint->Device(),endpoint->Address(),endpoint->Status(),endpoint->Data,endpoint->Length,endpoint->UserData); 00321 } 00322 } 00323 } 00324 00325 // Deal with changes on the root hub 00326 if (_rootHubStatusChange) 00327 { 00328 u32 status = LPC_USB->HcRhPortStatus1; 00329 _rootHubStatusChange = 0; 00330 if (status >> 16) 00331 { 00332 HubStatusChange(0,1,status); 00333 LPC_USB->HcRhPortStatus1 = status & 0xFFFF0000; // clear status changes 00334 } 00335 } 00336 00337 // Connect after reset timeout 00338 if (_connectCountdown) 00339 { 00340 if (elapsed >= _connectCountdown) 00341 { 00342 _connectCountdown = 0; 00343 Connect(_connectHub,_connectPort & 0x7F,_connectPort & 0x80); 00344 } else 00345 _connectCountdown -= elapsed; 00346 } 00347 } 00348 00349 // HubInterrupt - bitmap in dev->HubInterruptData 00350 void HubInterrupt(int device) 00351 { 00352 Device* dev = &Devices[device-1]; 00353 for (int i = 0; i < dev->HubPortCount; i++) 00354 { 00355 int port = i+1; 00356 if (dev->HubInterruptData & (1 << port)) 00357 { 00358 u32 status = 0; 00359 GetPortStatus(device,port,&status); 00360 if (status >> 16) 00361 { 00362 if (_connectPending && (status & ConnectStatusChange)) 00363 continue; // Don't connect again until previous device has been added and addressed 00364 00365 HubStatusChange(device,port,status); 00366 if (status & ConnectStatusChange) 00367 ClearPortFeature(device,C_PORT_CONNECTION,port); 00368 if (status & PortResetStatusChange) 00369 ClearPortFeature(device,C_PORT_RESET,port); 00370 } 00371 } 00372 } 00373 } 00374 00375 static void HubInterruptCallback(int device, int endpoint, int status, u8* data, int len, void* userData) 00376 { 00377 HostController* controller = (HostController*)userData; 00378 if (status == 0) 00379 controller->HubInterrupt(device); 00380 USBInterruptTransfer(device,endpoint,data,1,HubInterruptCallback,userData); 00381 } 00382 00383 int InitHub(int device) 00384 { 00385 u8 buf[16]; 00386 int r= USBControlTransfer(device,DEVICE_TO_HOST | REQUEST_TYPE_CLASS | RECIPIENT_DEVICE,GET_DESCRIPTOR,(DESCRIPTOR_TYPE_HUB << 8),0,buf,sizeof(buf)); 00387 if (r < 0) 00388 return ERR_HUB_INIT_FAILED; 00389 00390 // turn on power on the hubs ports 00391 Device* dev = &Devices[device-1]; 00392 int ports = buf[2]; 00393 dev->HubPortCount = ports; 00394 for (int i = 0; i < ports; i++) 00395 SetPortPower(device,i+1); 00396 00397 // Enable hub change interrupts 00398 return USBInterruptTransfer(device,0x81,&dev->HubInterruptData,1,HubInterruptCallback,this); 00399 } 00400 00401 int AddEndpoint(int device, int ep, int attributes, int maxPacketSize, int interval) 00402 { 00403 LOG("AddEndpoint D:%02X A:%02X T:%02X P:%04X I:%02X\n",device,ep,attributes,maxPacketSize,interval); 00404 Device* dev = &Devices[device-1]; 00405 Endpoint* endpoint = AllocateEndpoint(device,ep,attributes,maxPacketSize); 00406 if (!endpoint) 00407 return ERR_ENDPOINT_NONE_LEFT; 00408 dev->SetEndpointIndex(ep,endpoint - Endpoints); 00409 endpoint->EndpointDescriptor.Control |= dev->Flags; // Map in slow speed 00410 return 0; // TODO ed->bInterval 00411 } 00412 00413 int AddEndpoint(int device, EndpointDescriptor* ed) 00414 { 00415 return AddEndpoint(device,ed->bEndpointAddress,ed->bmAttributes,ed->wMaxPacketSize,ed->bInterval); 00416 } 00417 00418 // allocate a endpoint 00419 Endpoint* AllocateEndpoint(int device, int endpointAddress, int type, int maxPacketSize) 00420 { 00421 for (int i = 0; i < MAX_ENDPOINTS_TOTAL; i++) 00422 { 00423 Endpoint* ep = &Endpoints[i]; 00424 if (ep->CurrentState == 0) 00425 { 00426 //LOG("Allocated endpoint %d to %02X:%02X\n",i,device,endpointAddress); 00427 ep->Flags = (endpointAddress & 0x80) | (type & 3); 00428 ep->CurrentState = Endpoint::NotQueued; 00429 ep->EndpointDescriptor.Control = (maxPacketSize << 16) | ((endpointAddress & 0x7F) << 7) | device; 00430 return ep; 00431 } 00432 } 00433 return 0; 00434 } 00435 00436 Endpoint* GetEndpoint(int device, int ep) 00437 { 00438 if (device == 0) 00439 { 00440 //printf("WARNING: USING DEVICE 0\n"); 00441 return &EndpointZero; 00442 } 00443 if (device > MAX_DEVICES) 00444 return 0; 00445 int i = Devices[device-1].GetEndpointIndex(ep); 00446 if (i == -1) 00447 return 0; 00448 return Endpoints + i; 00449 } 00450 00451 int Transfer(Endpoint* endpoint, int token, u8* data, int len, int state) 00452 { 00453 //LOG("Transfer %02X T:%d Len:%d S:%d\n",endpoint->Address(),token,len,state); 00454 00455 int toggle = 0; 00456 if (endpoint->Address() == 0) 00457 toggle = (token == TOKEN_SETUP) ? TD_TOGGLE_0 : TD_TOGGLE_1; 00458 00459 if (token != TOKEN_SETUP) 00460 token = (token == TOKEN_IN ? TD_IN : TD_OUT); 00461 00462 HCTD* head = &endpoint->TDHead; 00463 HCTD* tail = &_commonTail; 00464 00465 head->Control = TD_ROUNDING | token | TD_DELAY_INT(0) | toggle | TD_CC; 00466 head->CurrBufPtr = (u32)data; 00467 head->BufEnd = (u32)(data + len - 1); 00468 head->Next = (u32)tail; 00469 00470 HCED* ed = &endpoint->EndpointDescriptor; 00471 ed->HeadTd = (u32)head | (ed->HeadTd & 0x00000002); // carry toggle 00472 ed->TailTd = (u32)tail; 00473 00474 //HCTD* td = head; 00475 //LOG("%04X TD %08X %08X %08X Next:%08X\n",CommunicationArea.FrameNumber,td->Control,td->CurrBufPtr,td->BufEnd,td->Next); 00476 //LOG("%04X ED %08X %08X %08X\n",CommunicationArea.FrameNumber,ed->Control,ed->HeadTd,ed->TailTd); 00477 00478 switch (endpoint->Flags & 3) 00479 { 00480 case ENDPOINT_CONTROL: 00481 LPC_USB->HcControlHeadED = endpoint->Enqueue(LPC_USB->HcControlHeadED); // May change state NotQueued->Idle 00482 endpoint->CurrentState = state; // Get in before an int 00483 LPC_USB->HcCommandStatus = LPC_USB->HcCommandStatus | ControlListFilled; 00484 LPC_USB->HcControl = LPC_USB->HcControl | ControlListEnable; 00485 break; 00486 00487 case ENDPOINT_BULK: 00488 LPC_USB->HcBulkHeadED = endpoint->Enqueue(LPC_USB->HcBulkHeadED); 00489 endpoint->CurrentState = state; 00490 LPC_USB->HcCommandStatus = LPC_USB->HcCommandStatus | BulkListFilled; 00491 LPC_USB->HcControl = LPC_USB->HcControl | BulkListEnable; 00492 break; 00493 00494 case ENDPOINT_INTERRUPT: 00495 CommunicationArea.InterruptTable[0] = endpoint->Enqueue(CommunicationArea.InterruptTable[0]); 00496 endpoint->CurrentState = state; 00497 LPC_USB->HcControl |= PeriodicListEnable; 00498 break; 00499 } 00500 return 0; 00501 } 00502 00503 // Remove an endpoint from an active queue 00504 bool Remove(HCED* ed, volatile HCED** queue) 00505 { 00506 if (*queue == 0) 00507 return false; 00508 if (*queue == (volatile HCED*)ed) 00509 { 00510 *queue = (volatile HCED*)ed->Next; // At head of queue 00511 return true; 00512 } 00513 00514 volatile HCED* head = *queue; 00515 while (head) 00516 { 00517 if (head->Next == (u32)ed) 00518 { 00519 head->Next = ed->Next; 00520 return true; 00521 } 00522 head = (volatile HCED*)head->Next; 00523 } 00524 return false; 00525 } 00526 00527 void Release(Endpoint* endpoint) 00528 { 00529 if (endpoint->CurrentState == Endpoint::NotQueued) 00530 { 00531 // Never event used it, nothing to do 00532 } 00533 else 00534 { 00535 HCED* ed = (HCED*)endpoint; 00536 ed->Control |= 0x4000; // SKIP 00537 switch (endpoint->Flags & 0x03) 00538 { 00539 case ENDPOINT_CONTROL: 00540 Remove(ed,(volatile HCED**)&LPC_USB->HcControlHeadED); 00541 break; 00542 case ENDPOINT_BULK: 00543 Remove(ed,(volatile HCED**)&LPC_USB->HcBulkHeadED); 00544 break; 00545 case ENDPOINT_INTERRUPT: 00546 for (int i = 0; i < 32; i++) 00547 Remove(ed,(volatile HCED**)&CommunicationArea.InterruptTable[i]); 00548 break; 00549 } 00550 00551 u16 fn = CommunicationArea.FrameNumber; 00552 while (fn == CommunicationArea.FrameNumber) 00553 ; // Wait for next frame 00554 00555 } 00556 00557 // In theory, the endpoint is now dead. 00558 // TODO: Will Callbacks ever be pending? BUGBUG 00559 memset(endpoint,0,sizeof(Endpoint)); 00560 } 00561 00562 // Pop the last TD from the list 00563 HCTD* Reverse(HCTD* current) 00564 { //int n = 0; 00565 HCTD *result = NULL,*temp; 00566 while (current) 00567 { //n++; 00568 temp = (HCTD*)current->Next; 00569 current->Next = (u32)result; 00570 result = current; 00571 current = temp; 00572 } 00573 //if (n>1) printf("%d TD's on Done Queue\n", n); 00574 return result; 00575 } 00576 00577 // Called from interrupt... 00578 // Control endpoints use a state machine to progress through the transfers 00579 void ProcessDoneQueue(u32 tdList) 00580 { 00581 HCTD* list = Reverse((HCTD*)tdList);//because completed transfers were added to the head of the list 00582 while (list) 00583 {//horrible hack: an Endpoint starts with an HCED and an HCTD and apparently all HCTDs are contained in Endpoints this way 00584 //furthermore the sizeof an HCTD equeals the size of an HCED, hence the next expression gives indeed the Endpoint* for the HCTD 00585 Endpoint* endpoint = (Endpoint*)(list-1); 00586 list = (HCTD*)list->Next; 00587 int ep = endpoint->Address(); 00588 bool in = endpoint->Flags & 0x80; 00589 int status = (endpoint->TDHead.Control >> 28) & 0xF; 00590 //the printf below is essential for correct working !?!? remove it and some messages will be missed 00591 //LOG("ProcessDoneQueue %02X %08X\n",ep,endpoint->TDHead.Control); 00592 wait_us(0);//200, 100, 50, 20, 10, 5, 2, 1,0 works, deleting the statement does not work 00593 //I suspect it has to do with interrupt priorities rather than with delays 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 {//here is a potential deadlock 00605 //printf("Deadlock Avoidance, ep=%02x, in=%d\n", ep, in);//with printf before transfer -> no deadlock 00606 Transfer(endpoint,in ? TOKEN_IN : TOKEN_OUT,endpoint->Data,endpoint->Length, Endpoint::DataQueued); // Setup is done, now Data 00607 //printf("SetupQueued->DataQueued\n");//with printf after Transfer ->deadlock 00608 } 00609 break; 00610 00611 case Endpoint::DataQueued: 00612 if (endpoint->TDHead.CurrBufPtr) 00613 endpoint->Length = endpoint->TDHead.CurrBufPtr - (u32)endpoint->Data; 00614 00615 if (ep == 0){ 00616 Transfer(endpoint,in ? TOKEN_OUT : TOKEN_IN,0,0,Endpoint::StatusQueued); // Data is done, now Status, Control only 00617 } else 00618 endpoint->CurrentState = Endpoint::Idle; 00619 break; 00620 00621 case Endpoint::StatusQueued: // Transaction is done 00622 endpoint->CurrentState = Endpoint::Idle; 00623 break; 00624 } 00625 } 00626 00627 // Complete, flag if we need a callback 00628 if (endpoint->Callback && endpoint->CurrentState == Endpoint::Idle) 00629 { 00630 endpoint->CurrentState = Endpoint::CallbackPending; 00631 _callbacksPending++; 00632 } 00633 } 00634 } 00635 00636 // Hack to reset devices that don't want to connect 00637 int AddDevice(int hub, int port, bool isLowSpeed) 00638 { 00639 int device = AddDeviceCore(hub,port,isLowSpeed); 00640 if (device < 0) 00641 { 00642 LOG("========RETRY ADD DEVICE========\n"); // This will go for ever.. TODO power cycle root? 00643 Disconnect(hub,port); // Could not read descriptor at assigned address, reset this port and try again 00644 ResetPort(hub,port); // Cheap bluetooth dongles often need this on a hotplug 00645 return -1; 00646 } 00647 return device; 00648 } 00649 00650 int AddDeviceCore(int hub, int port, bool isLowSpeed) 00651 { 00652 int lowSpeed = isLowSpeed ? 0x2000 : 0; 00653 DeviceDescriptor desc; 00654 EndpointZero.EndpointDescriptor.Control = (8 << 16) | lowSpeed; // MaxPacketSize == 8 00655 int r = GetDescriptor(0,DESCRIPTOR_TYPE_DEVICE,0,(u8*)&desc,8); 00656 if (r < 0) 00657 { 00658 LOG("FAILED TO LOAD DESCRIPTOR FOR DEVICE 0\n"); 00659 return r; 00660 } 00661 00662 EndpointZero.EndpointDescriptor.Control = (desc.bMaxPacketSize << 16) | lowSpeed; // Actual MaxPacketSize 00663 r = GetDescriptor(0,DESCRIPTOR_TYPE_DEVICE,0,(u8*)&desc,sizeof(desc)); 00664 if (r < 0) 00665 return r; 00666 00667 LOG("\nClass %02X found %04X:%04X\n\n",desc.bDeviceClass,desc.idVendor,desc.idProduct); 00668 00669 // Now assign the device an address, move off EndpointZero 00670 int device = 0; 00671 for (int i = 0; i < MAX_DEVICES; i++) 00672 { 00673 if (Devices[i].Port == 0) 00674 { 00675 device = i+1; 00676 break; 00677 } 00678 } 00679 if (!device) 00680 return ERR_DEVICE_NONE_LEFT; 00681 00682 r = SetAddress(0,device); 00683 if (r) 00684 return r; 00685 DelayMS(2); 00686 00687 // Now at a nonzero address, create control endpoint 00688 Device* dev = &Devices[device-1]; 00689 dev->Init(&desc,hub,port,device,lowSpeed); 00690 AddEndpoint(device,0,ENDPOINT_CONTROL,desc.bMaxPacketSize,0); 00691 _connectPending = 0; 00692 00693 // Verify this all works 00694 r = GetDescriptor(device,DESCRIPTOR_TYPE_DEVICE,0,(u8*)&desc,sizeof(desc)); 00695 if (r < 0) 00696 return r; 00697 00698 // Set to interface 0 by default 00699 // Calls LoadDevice if interface is found 00700 r = SetConfigurationAndInterface(device,1,0,&desc); 00701 00702 if (desc.bDeviceClass == CLASS_HUB) 00703 InitHub(device); // Handle hubs in this code 00704 00705 return device; 00706 } 00707 00708 // Walk descriptors and create endpoints for a given device 00709 // TODO configuration !=1, alternate settings etc. 00710 int SetConfigurationAndInterface(int device, int configuration, int interfaceNumber, DeviceDescriptor* desc) 00711 { 00712 u8 buffer[255]; 00713 int err = GetDescriptor(device,DESCRIPTOR_TYPE_CONFIGURATION,0,buffer,sizeof(buffer)); 00714 if (err < 0) 00715 return err; 00716 00717 err = SetConfiguration(device,configuration); 00718 if (err < 0) 00719 return err; 00720 00721 // Add the endpoints for this interface 00722 int len = buffer[2] | (buffer[3] << 8); 00723 u8* d = buffer; 00724 u8* end = d + len; 00725 InterfaceDescriptor* found = 0; 00726 while (d < end) 00727 { 00728 if (d[1] == DESCRIPTOR_TYPE_INTERFACE) 00729 { 00730 InterfaceDescriptor* id = (InterfaceDescriptor*)d; 00731 if (id->bInterfaceNumber == interfaceNumber) 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 & ~1U); // TODO - low bit can be set BUGBUG 00923 if (head & 1) { 00924 int othercause = int_status ^ WritebackDoneHead; 00925 printf("HcInterruptStatus = %08X\n", int_status); 00926 } 00927 } 00928 else 00929 int othercause = int_status; 00930 LPC_USB->HcInterruptStatus = int_status; 00931 //See page 435 of OHCI Specification 00932 //if the LSb=1 int_status should be checked for other causes 00933 //if the head=0 there are no TDs on the DoneQueue and int_status should be checked to see what caused this interrupt 00934 } 00935 00936 //==================================================================================== 00937 //==================================================================================== 00938 // API Methods 00939 00940 void USBInit() 00941 { 00942 return _controller.Init(); 00943 } 00944 00945 void USBLoop() 00946 { 00947 return _controller.Loop(); 00948 } 00949 00950 u8* USBGetBuffer(u32* len) 00951 { 00952 *len = USB_RAM_SIZE - sizeof(HostController); 00953 return _controller.SRAM; 00954 } 00955 00956 static Setup* GetSetup(int device) 00957 { 00958 if (device == 0) 00959 return &_controller._setupZero; 00960 00961 if (device < 1 || device > MAX_DEVICES) 00962 return 0; 00963 return &_controller.Devices[device-1].SetupBuffer; 00964 } 00965 00966 // Loop until IO on endpoint is complete 00967 static int WaitIODone(Endpoint* endpoint) 00968 { 00969 if (endpoint->CurrentState == Endpoint::NotQueued) 00970 return 0; 00971 while (endpoint->CurrentState != Endpoint::Idle) 00972 USBLoop(); // May generate callbacks, mount or unmount devices etc 00973 int status = endpoint->Status(); 00974 if (status == 0) 00975 return endpoint->Length; 00976 return -status; 00977 } 00978 00979 int USBTransfer(int device, int ep, u8 flags, u8* data, int length, USBCallback callback, void* userData) 00980 { 00981 Endpoint* endpoint = _controller.GetEndpoint(device,ep); 00982 if (!endpoint) 00983 return ERR_ENDPOINT_NOT_FOUND; 00984 00985 WaitIODone(endpoint); 00986 endpoint->Flags = flags; 00987 endpoint->Data = data; 00988 endpoint->Length = length; 00989 endpoint->Callback = callback; 00990 endpoint->UserData = userData; 00991 if (ep == 0) 00992 _controller.Transfer(endpoint,TOKEN_SETUP,(u8*)GetSetup(device),8,Endpoint::SetupQueued); 00993 else 00994 _controller.Transfer(endpoint,flags & 0x80 ? TOKEN_IN : TOKEN_OUT,data,length,Endpoint::DataQueued); 00995 if (callback) 00996 return IO_PENDING; 00997 return WaitIODone(endpoint); 00998 } 00999 01000 int USBControlTransfer(int device, int request_type, int request, int value, int index, u8* data, int length, USBCallback callback, void * userData) 01001 { 01002 Setup* setup = GetSetup(device); 01003 if (!setup) 01004 return ERR_DEVICE_NOT_FOUND; 01005 01006 // Async control calls may overwrite setup buffer of previous call, so we need to wait before setting up next call 01007 WaitIODone(_controller.GetEndpoint(device,0)); 01008 01009 setup->bm_request_type = request_type; 01010 setup->b_request = request; 01011 setup->w_value = value; 01012 setup->w_index = index; 01013 setup->w_length = length; 01014 return USBTransfer(device,0,request_type & DEVICE_TO_HOST,data,length,callback,userData); 01015 } 01016 01017 int USBInterruptTransfer(int device, int ep, u8* data, int length, USBCallback callback, void* userData) 01018 { 01019 return USBTransfer(device,ep,(ep & 0x80) | ENDPOINT_INTERRUPT,data,length,callback,userData); 01020 } 01021 01022 int USBBulkTransfer(int device, int ep, u8* data, int length, USBCallback callback, void* userData) 01023 { 01024 return USBTransfer(device,ep,(ep & 0x80) | ENDPOINT_BULK,data,length,callback,userData); 01025 } 01026 01027 int GetDescriptor(int device, int descType,int descIndex, u8* data, int length) 01028 { 01029 return USBControlTransfer(device,DEVICE_TO_HOST | RECIPIENT_DEVICE, GET_DESCRIPTOR,(descType << 8)|(descIndex), 0, data, length, 0); 01030 } 01031 01032 int GetString(int device, int index, char* dst, int length) 01033 { 01034 u8 buffer[255]; 01035 int le = GetDescriptor(device,DESCRIPTOR_TYPE_STRING,index,buffer,sizeof(buffer)); 01036 if (le < 0) 01037 return le; 01038 if (length < 1) 01039 return -1; 01040 length <<= 1; 01041 if (le > length) 01042 le = length; 01043 for (int j = 2; j < le; j += 2) 01044 *dst++ = buffer[j]; 01045 *dst = 0; 01046 return (le>>1)-1; 01047 } 01048 01049 int SetAddress(int device, int new_addr) 01050 { 01051 return USBControlTransfer(device,HOST_TO_DEVICE | RECIPIENT_DEVICE, SET_ADDRESS, new_addr, 0, 0, 0, 0); 01052 } 01053 01054 int SetConfiguration(int device, int configNum) 01055 { 01056 return USBControlTransfer(device,HOST_TO_DEVICE | RECIPIENT_DEVICE, SET_CONFIGURATION, configNum, 0, 0, 0, 0); 01057 } 01058 01059 int SetInterface(int device, int ifNum, int altNum) 01060 { 01061 return USBControlTransfer(device,HOST_TO_DEVICE | RECIPIENT_INTERFACE, SET_INTERFACE, altNum, ifNum, 0, 0, 0); 01062 } 01063 01064 // HUB stuff 01065 int SetPortFeature(int device, int feature, int index) 01066 { 01067 return USBControlTransfer(device,HOST_TO_DEVICE | REQUEST_TYPE_CLASS | RECIPIENT_OTHER,SET_FEATURE,feature,index,0,0); 01068 } 01069 01070 int ClearPortFeature(int device, int feature, int index) 01071 { 01072 return USBControlTransfer(device,HOST_TO_DEVICE | REQUEST_TYPE_CLASS | RECIPIENT_OTHER,CLEAR_FEATURE,feature,index,0,0); 01073 } 01074 01075 int SetPortPower(int device, int port) 01076 { 01077 int r = SetPortFeature(device,PORT_POWER,port); 01078 _controller.DelayMS(20); // 80ms to turn on a hubs power... DESCRIPTOR? todo 01079 return r; 01080 } 01081 01082 int SetPortReset(int device, int port) 01083 { 01084 return SetPortFeature(device,PORT_RESET,port); 01085 } 01086 01087 int GetPortStatus(int device, int port, u32* status) 01088 { 01089 return USBControlTransfer(device,DEVICE_TO_HOST | REQUEST_TYPE_CLASS | RECIPIENT_OTHER,GET_STATUS,0,port,(u8*)status,4); 01090 }
Generated on Tue Jul 12 2022 18:48:53 by 1.7.2