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