うおーるぼっと用プログラム Wiiリモコンからのダイレクト操作モードのみ BlueUSBをベースに使用しています。
Dependencies: BD6211F mbed SimpleFilter
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 }
Generated on Thu Jul 14 2022 13:01:38 by 1.7.2