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