Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
USBHost.cpp
00001 00002 /* 00003 I changed a bit the code but all credit goes to the amazing work of : 00004 00005 Copyright (c) 2010 Peter Barrett 00006 00007 Permission is hereby granted, free of charge, to any person obtaining a copy 00008 of this software and associated documentation files (the "Software"), to deal 00009 in the Software without restriction, including without limitation the rights 00010 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00011 copies of the Software, and to permit persons to whom the Software is 00012 furnished to do so, subject to the following conditions: 00013 00014 The above copyright notice and this permission notice shall be included in 00015 all copies or substantial portions of the Software. 00016 00017 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00018 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00019 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00020 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00021 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00022 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00023 THE SOFTWARE. 00024 */ 00025 00026 #include "mbed.h" 00027 #include "USBHost.h" 00028 00029 // Config (default uses x bytes) 00030 #define MAX_DEVICES 8 // Max number of devices 00031 #define MAX_ENDPOINTS_TOTAL 16 // Max number of endpoints total 00032 #define MAX_ENDPOINTS_PER_DEVICE 8 // Max number of endpoints for any one device 00033 00034 #define USBLOG 1 00035 #if USBLOG 00036 #define LOG(...) printf(__VA_ARGS__) 00037 #else 00038 #define LOG(...) do {} while(0) 00039 #endif 00040 00041 // USB host structures 00042 00043 #define USB_RAM_SIZE 16*1024 // AHB SRAM block 1 TODO MACHINE DEPENDENT 00044 #define USB_RAM_BASE 0x2007C000 00045 00046 #define TOKEN_SETUP 0 00047 #define TOKEN_IN 1 00048 #define TOKEN_OUT 2 00049 00050 // Status flags from hub 00051 #define PORT_CONNECTION 0 00052 #define PORT_ENABLE 1 00053 #define PORT_SUSPEND 2 00054 #define PORT_OVER_CURRENT 3 00055 #define PORT_RESET 4 00056 #define PORT_POWER 8 00057 #define PORT_LOW_SPEED 9 00058 00059 #define C_PORT_CONNECTION 16 00060 #define C_PORT_ENABLE 17 00061 #define C_PORT_SUSPEND 18 00062 #define C_PORT_OVER_CURRENT 19 00063 #define C_PORT_RESET 20 00064 00065 typedef struct { 00066 u8 bm_request_type; 00067 u8 b_request; 00068 u16 w_value; 00069 u16 w_index; 00070 u16 w_length; 00071 } Setup; 00072 00073 00074 // Hub stuff is kept private just to keep api simple 00075 int SetPortFeature(int device, int feature, int index); 00076 int ClearPortFeature(int device, int feature, int index); 00077 int SetPortPower(int device, int port); 00078 int SetPortReset(int device, int port); 00079 int GetPortStatus(int device, int port, u32* status); 00080 00081 //=================================================================== 00082 //=================================================================== 00083 // Hardware defines 00084 00085 // HcControl 00086 #define PeriodicListEnable 0x00000004 00087 #define IsochronousEnable 0x00000008 00088 #define ControlListEnable 0x00000010 00089 #define BulkListEnable 0x00000020 00090 #define OperationalMask 0x00000080 00091 #define HostControllerFunctionalState 0x000000C0 00092 00093 // HcCommandStatus 00094 #define HostControllerReset 0x00000001 00095 #define ControlListFilled 0x00000002 00096 #define BulkListFilled 0x00000004 00097 00098 // HcInterruptStatus Register 00099 #define WritebackDoneHead 0x00000002 00100 #define StartofFrame 0x00000004 00101 #define ResumeDetected 0x00000008 00102 #define UnrecoverableError 0x00000010 00103 #define FrameNumberOverflow 0x00000020 00104 #define RootHubStatusChange 0x00000040 00105 #define OwnershipChange 0x00000080 00106 #define MasterInterruptEnable 0x80000000 00107 00108 // HcRhStatus 00109 #define SetGlobalPower 0x00010000 00110 #define DeviceRemoteWakeupEnable 0x00008000 00111 00112 // HcRhPortStatus (hub 0, port 1) 00113 #define CurrentConnectStatus 0x00000001 00114 #define PortEnableStatus 0x00000002 00115 #define PortSuspendStatus 0x00000004 00116 #define PortOverCurrentIndicator 0x00000008 00117 #define PortResetStatus 0x00000010 00118 00119 #define PortPowerStatus 0x00000100 00120 #define LowspeedDevice 0x00000200 00121 #define HighspeedDevice 0x00000400 00122 00123 #define ConnectStatusChange (CurrentConnectStatus << 16) 00124 #define PortResetStatusChange (PortResetStatus << 16) 00125 00126 00127 #define TD_ROUNDING (u32)0x00040000 00128 #define TD_SETUP (u32)0x00000000 00129 #define TD_IN (u32)0x00100000 00130 #define TD_OUT (u32)0x00080000 00131 #define TD_DELAY_INT(x) (u32)((x) << 21) 00132 #define TD_TOGGLE_0 (u32)0x02000000 00133 #define TD_TOGGLE_1 (u32)0x03000000 00134 #define TD_CC (u32)0xF0000000 00135 00136 // HostController EndPoint Descriptor 00137 typedef struct { 00138 volatile u32 Control; 00139 volatile u32 TailTd; 00140 volatile u32 HeadTd; 00141 volatile u32 Next; 00142 } HCED; 00143 00144 // HostController Transfer Descriptor 00145 typedef struct { 00146 volatile u32 Control; 00147 volatile u32 CurrBufPtr; 00148 volatile u32 Next; 00149 volatile u32 BufEnd; 00150 } HCTD; 00151 00152 // Host Controller Communication Area 00153 typedef struct { 00154 volatile u32 InterruptTable[32]; 00155 volatile u16 FrameNumber; 00156 volatile u16 FrameNumberPad; 00157 volatile u32 DoneHead; 00158 volatile u8 Reserved[120]; 00159 } HCCA; 00160 00161 //==================================================================================== 00162 //==================================================================================== 00163 00164 class HostController; 00165 class Endpoint; 00166 class Device; 00167 00168 // must be 3*16 bytes long 00169 class Endpoint 00170 { 00171 public: 00172 HCED EndpointDescriptor; // Pointer to EndpointDescriptor == Pointer to Endpoint 00173 HCTD TDHead; 00174 00175 enum State 00176 { 00177 Free, 00178 NotQueued, 00179 Idle, 00180 SetupQueued, 00181 DataQueued, 00182 StatusQueued, 00183 CallbackPending 00184 }; 00185 00186 volatile u8 CurrentState; 00187 u8 Flags; // 0x80 In, 0x03 mask endpoint type 00188 00189 u16 Length; 00190 u8* Data; 00191 USBCallback Callback; // Must be a multiple of 16 bytes long 00192 void* UserData; 00193 00194 int Address() 00195 { 00196 int ep = (EndpointDescriptor.Control >> 7) & 0xF; 00197 if (ep) 00198 ep |= Flags & 0x80; 00199 return ep; 00200 } 00201 00202 int Device() 00203 { 00204 return EndpointDescriptor.Control & 0x7F; 00205 } 00206 00207 int Status() 00208 { 00209 return (TDHead.Control >> 28) & 0xF; 00210 } 00211 00212 u32 Enqueue(u32 head) 00213 { 00214 if (CurrentState == NotQueued) 00215 { 00216 EndpointDescriptor.Next = head; 00217 head = (u32)&EndpointDescriptor; 00218 CurrentState = Idle; 00219 } 00220 return head; 00221 } 00222 }; 00223 00224 class Device 00225 { 00226 public: 00227 u8 _endpointMap[MAX_ENDPOINTS_PER_DEVICE*2]; 00228 u8 Hub; 00229 u8 Port; 00230 u8 Addr; 00231 u8 Pad; 00232 00233 // Only if this device is a hub 00234 u8 HubPortCount; // nonzero if this is a hub 00235 u8 HubInterruptData; 00236 u8 HubMap; 00237 u8 HubMask; 00238 00239 int Flags; // 1 = Disconnected 00240 00241 Setup SetupBuffer; 00242 00243 // Allocate endpoint zero 00244 int Init(DeviceDescriptor* d, int hub, int port, int addr, int lowSpeed) 00245 { 00246 Hub = hub; 00247 Port = port; 00248 Addr = addr; 00249 Flags = lowSpeed; 00250 memset(_endpointMap,0xFF,sizeof(_endpointMap)); 00251 return 0; 00252 } 00253 00254 int SetEndpointIndex(int ep, int endpointIndex) 00255 { 00256 for (int i = 0; i < MAX_ENDPOINTS_PER_DEVICE*2; i += 2) 00257 { 00258 if (_endpointMap[i] == 0xFF) // Add endpoint to map 00259 { 00260 _endpointMap[i] = ep; 00261 _endpointMap[i+1] = endpointIndex; 00262 return 0; 00263 } 00264 } 00265 return ERR_ENDPOINT_NONE_LEFT; 00266 } 00267 00268 int GetEndpointIndex(int ep) 00269 { 00270 for (int i = 0; i < MAX_ENDPOINTS_PER_DEVICE*2; i += 2) 00271 { 00272 if (_endpointMap[i] == ep) 00273 return _endpointMap[i+1]; 00274 if (_endpointMap[i] == 0xFF) 00275 break; 00276 } 00277 return -1; 00278 } 00279 }; 00280 00281 class HostController 00282 { 00283 public: 00284 HCCA CommunicationArea; 00285 Endpoint Endpoints[MAX_ENDPOINTS_TOTAL]; // Multiple of 16 00286 00287 Endpoint EndpointZero; // For device enumeration 00288 HCTD _commonTail; 00289 Setup _setupZero; 00290 00291 Device Devices[MAX_DEVICES]; 00292 u32 _frameNumber; // 32 bit ms counter 00293 00294 u8 _callbacksPending; // Endpoints with callbacks are pending, set from ISR via ProcessDoneQueue 00295 u8 _rootHubStatusChange; // Root hub status has changed, set from ISR 00296 u8 _unused0; 00297 u8 _unused1; 00298 00299 u8 _connectPending; // Reset has initiated a connect 00300 u8 _connectCountdown; // Number of ms left after reset before we can connect 00301 u8 _connectHub; // Will connect on this hub 00302 u8 _connectPort; // ... and this port 00303 00304 u8 SRAM[0]; // Start of free SRAM 00305 00306 void Loop() 00307 { 00308 u16 elapsed = CommunicationArea.FrameNumber - (u16)_frameNumber; // extend to 32 bits 00309 _frameNumber += elapsed; 00310 00311 // Do callbacks, if any 00312 while (_callbacksPending) 00313 { 00314 for (int i = 0; i < MAX_ENDPOINTS_TOTAL; i++) 00315 { 00316 Endpoint* endpoint = Endpoints + i; 00317 if (endpoint->CurrentState == Endpoint::CallbackPending) 00318 { 00319 _callbacksPending--; 00320 endpoint->CurrentState = Endpoint::Idle; 00321 //remember: 00322 //typedef void (*USBCallback)(int device, int endpoint, int status, u8* data, int len, void* userData); 00323 endpoint->Callback(endpoint->Device(),endpoint->Address(),endpoint->Status(),endpoint->Data,endpoint->Length,endpoint->UserData); 00324 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 00342 // Connect after reset timeout 00343 if (_connectCountdown) 00344 { 00345 if (elapsed >= _connectCountdown) 00346 { 00347 _connectCountdown = 0; 00348 Connect(_connectHub,_connectPort & 0x7F,_connectPort & 0x80); 00349 } else 00350 _connectCountdown -= elapsed; 00351 } 00352 }// END OF VOID LOOP() 00353 00354 00355 // HubInterrupt - bitmap in dev->HubInterruptData 00356 void HubInterrupt(int device) 00357 { 00358 Device* dev = &Devices[device-1]; 00359 for (int i = 0; i < dev->HubPortCount; i++) 00360 { 00361 int port = i+1; 00362 if (dev->HubInterruptData & (1 << port)) 00363 { 00364 u32 status = 0; 00365 GetPortStatus(device,port,&status); 00366 if (status >> 16) 00367 { 00368 if (_connectPending && (status & ConnectStatusChange)) 00369 continue; // Don't connect again until previous device has been added and addressed 00370 00371 HubStatusChange(device,port,status); 00372 if (status & ConnectStatusChange) 00373 ClearPortFeature(device,C_PORT_CONNECTION,port); 00374 if (status & PortResetStatusChange) 00375 ClearPortFeature(device,C_PORT_RESET,port); 00376 } 00377 } 00378 } 00379 } 00380 00381 static void HubInterruptCallback(int device, int endpoint, int status, u8* data, int len, void* userData) 00382 { 00383 HostController* controller = (HostController*)userData; 00384 if (status == 0) 00385 controller->HubInterrupt(device); 00386 USBInterruptTransfer(device,endpoint,data,1,HubInterruptCallback,userData); 00387 } 00388 00389 int InitHub(int device) 00390 { 00391 u8 buf[16]; 00392 int r= USBControlTransfer(device,DEVICE_TO_HOST | REQUEST_TYPE_CLASS | RECIPIENT_DEVICE,GET_DESCRIPTOR,(DESCRIPTOR_TYPE_HUB << 8),0,buf,sizeof(buf)); 00393 if (r < 0) 00394 return ERR_HUB_INIT_FAILED; 00395 00396 // turn on power on the hubs ports 00397 Device* dev = &Devices[device-1]; 00398 int ports = buf[2]; 00399 dev->HubPortCount = ports; 00400 for (int i = 0; i < ports; i++) 00401 SetPortPower(device,i+1); 00402 00403 // Enable hub change interrupts 00404 return USBInterruptTransfer(device,0x81,&dev->HubInterruptData,1,HubInterruptCallback,this); 00405 } 00406 00407 int AddEndpoint(int device, int ep, int attributes, int maxPacketSize, int interval) 00408 { 00409 LOG("AddEndpoint D:%02X A:%02X T:%02X P:%04X I:%02X\n",device,ep,attributes,maxPacketSize,interval); 00410 Device* dev = &Devices[device-1]; 00411 Endpoint* endpoint = AllocateEndpoint(device,ep,attributes,maxPacketSize); 00412 if (!endpoint) 00413 return ERR_ENDPOINT_NONE_LEFT; 00414 dev->SetEndpointIndex(ep,endpoint - Endpoints); 00415 endpoint->EndpointDescriptor.Control |= dev->Flags; // Map in slow speed 00416 return 0; // TODO ed->bInterval 00417 } 00418 00419 int AddEndpoint(int device, EndpointDescriptor* ed) 00420 { 00421 return AddEndpoint(device,ed->bEndpointAddress,ed->bmAttributes,ed->wMaxPacketSize,ed->bInterval); 00422 } 00423 00424 // allocate a endpoint 00425 Endpoint* AllocateEndpoint(int device, int endpointAddress, int type, int maxPacketSize) 00426 { 00427 for (int i = 0; i < MAX_ENDPOINTS_TOTAL; i++) 00428 { 00429 Endpoint* ep = &Endpoints[i]; 00430 if (ep->CurrentState == 0) 00431 { 00432 //LOG("Allocated endpoint %d to %02X:%02X\n",i,device,endpointAddress); 00433 ep->Flags = (endpointAddress & 0x80) | (type & 3); 00434 ep->CurrentState = Endpoint::NotQueued; 00435 ep->EndpointDescriptor.Control = (maxPacketSize << 16) | ((endpointAddress & 0x7F) << 7) | device; 00436 return ep; 00437 } 00438 } 00439 return 0; 00440 } 00441 00442 Endpoint* GetEndpoint(int device, int ep) 00443 { 00444 if (device == 0) 00445 { 00446 //printf("WARNING: USING DEVICE 0\n"); 00447 return &EndpointZero; 00448 } 00449 if (device > MAX_DEVICES) 00450 return 0; 00451 int i = Devices[device-1].GetEndpointIndex(ep); 00452 if (i == -1) 00453 return 0; 00454 return Endpoints + i; 00455 } 00456 00457 int Transfer(Endpoint* endpoint, int token, u8* data, int len, int state) 00458 { 00459 #ifdef USBLOG 00460 LOG("Transfer EDaddres:%02X Token:%d Len:%d State:%d \n",endpoint->Address(),token,len,state); 00461 LOG("Data %s: ",(token==TOKEN_IN)? "in": "out"); 00462 00463 //print the data: 00464 //@BUG, little endian- bigendian ?? 00465 for (int i=0; i<len; i++) 00466 { 00467 if ( ((i%(int)8)==0) ) LOG("\n"); 00468 LOG("hx%02X ",data[i]); 00469 } 00470 LOG("\n"); 00471 00472 if ( token==TOKEN_IN && len<30 && len>8) 00473 { 00474 00475 LOG("bLength: %d d \n", data[0]); 00476 LOG("bDescriptorType: %d -",data[1]); 00477 /* 00478 bDescriptorType Descriptor Type Required? 00479 01h device Yes. 00480 02h configuration Yes. 00481 03h string No. Optional descriptive text. 00482 04h interface Yes. 00483 05h endpoint No, if the device uses only Endpoint 0. 00484 06h device_qualifier Yes, for devices that support both full and high 00485 speeds. Not allowed for other devices. 00486 07h other_speed_configuration Yes, for devices that support both full and high 00487 speeds. Not allowed for other devices. 00488 08h interface_power No. Supports interface-level power 00489 management. 00490 09h OTG For On-The-Go devices only. 00491 0Ah debug No. 00492 0Bh interface_association For composite devices. 00493 */ 00494 switch (data[1]) 00495 { 00496 case(1): { LOG("DEVICE"); break;} 00497 case(2): { LOG("CONFIGURATION"); break;} 00498 case(3): { LOG("STRING"); break;} 00499 case(4): { LOG("INTERFACE"); break;} 00500 case(5): { LOG("ENDPOINT"); break;} 00501 case(6): { LOG("DEVICE_QUALIFIER"); break;} 00502 case(7): { LOG("OTHER_SPEED_CONFIGURATION"); break;} 00503 case(8): { LOG("ON_the_GO"); break;} 00504 case(9): { LOG("DEBUG"); break;} 00505 case(10): { LOG("INTERFACE_ASSOCIATION"); break;} 00506 default: {LOG("?");} ; 00507 }//end switch data1; 00508 LOG("\n"); 00509 } 00510 00511 //the descriptor for device: 00512 if(data[1]==1) 00513 { 00514 u16 *aux; 00515 aux=(u16*) &data[2]; 00516 LOG("bcdUSB\t %04x\t",*aux); 00517 switch( *aux) 00518 { 00519 case(0x0200): {LOG("v2.0"); break;} 00520 case(0x0110): {LOG("v1.1"); break;} 00521 case(0x0100): {LOG("v1.0"); break;} 00522 default: {LOG("?");} 00523 } 00524 LOG("\n"); 00525 } 00526 00527 00528 00529 00530 #endif 00531 00532 int toggle = 0; 00533 if (endpoint->Address() == 0) 00534 toggle = (token == TOKEN_SETUP) ? TD_TOGGLE_0 : TD_TOGGLE_1; 00535 00536 if (token != TOKEN_SETUP) 00537 token = (token == TOKEN_IN ? TD_IN : TD_OUT); 00538 00539 HCTD* head = &endpoint->TDHead; 00540 HCTD* tail = &_commonTail; 00541 00542 head->Control = TD_ROUNDING | token | TD_DELAY_INT(0) | toggle | TD_CC; 00543 head->CurrBufPtr = (u32)data; //..data is a pointer. 00544 head->BufEnd = (u32)(data + len - 1); //pointers arithmetic :S 00545 head->Next = (u32)tail; 00546 00547 HCED* ed = &endpoint->EndpointDescriptor; 00548 ed->HeadTd = (u32)head | (ed->HeadTd & 0x00000002); // carry toggle 00549 ed->TailTd = (u32)tail; 00550 00551 //HCTD* td = head; 00552 //LOG("%04X TD %08X %08X %08X Next:%08X\n",CommunicationArea.FrameNumber,td->Control,td->CurrBufPtr,td->BufEnd,td->Next); 00553 //LOG("%04X ED %08X %08X %08X\n",CommunicationArea.FrameNumber,ed->Control,ed->HeadTd,ed->TailTd); 00554 00555 switch (endpoint->Flags & 3) 00556 { 00557 case ENDPOINT_CONTROL: 00558 LPC_USB->HcControlHeadED = endpoint->Enqueue(LPC_USB->HcControlHeadED); // May change state NotQueued->Idle 00559 endpoint->CurrentState = state; // Get in before an int 00560 LPC_USB->HcCommandStatus = LPC_USB->HcCommandStatus | ControlListFilled; 00561 LPC_USB->HcControl = LPC_USB->HcControl | ControlListEnable; 00562 break; 00563 00564 case ENDPOINT_BULK: 00565 LPC_USB->HcBulkHeadED = endpoint->Enqueue(LPC_USB->HcBulkHeadED); 00566 endpoint->CurrentState = state; 00567 LPC_USB->HcCommandStatus = LPC_USB->HcCommandStatus | BulkListFilled; 00568 LPC_USB->HcControl = LPC_USB->HcControl | BulkListEnable; 00569 break; 00570 00571 case ENDPOINT_INTERRUPT: 00572 CommunicationArea.InterruptTable[0] = endpoint->Enqueue(CommunicationArea.InterruptTable[0]); 00573 endpoint->CurrentState = state; 00574 LPC_USB->HcControl |= PeriodicListEnable; 00575 break; 00576 } 00577 return 0; 00578 }//end of transfer 00579 00580 // Remove an endpoint from an active queue 00581 bool Remove(HCED* ed, volatile HCED** queue) 00582 { 00583 if (*queue == 0) 00584 return false; 00585 if (*queue == (volatile HCED*)ed) 00586 { 00587 *queue = (volatile HCED*)ed->Next; // At head of queue 00588 return true; 00589 } 00590 00591 volatile HCED* head = *queue; 00592 while (head) 00593 { 00594 if (head->Next == (u32)ed) 00595 { 00596 head->Next = ed->Next; 00597 return true; 00598 } 00599 head = (volatile HCED*)head->Next; 00600 } 00601 return false; 00602 } 00603 00604 void Release(Endpoint* endpoint) 00605 { 00606 if (endpoint->CurrentState == Endpoint::NotQueued) 00607 { 00608 // Never event used it, nothing to do 00609 } 00610 else 00611 { 00612 HCED* ed = (HCED*)endpoint; 00613 ed->Control |= 0x4000; // SKIP 00614 switch (endpoint->Flags & 0x03) 00615 { 00616 case ENDPOINT_CONTROL: 00617 Remove(ed,(volatile HCED**)&LPC_USB->HcControlHeadED); 00618 break; 00619 case ENDPOINT_BULK: 00620 Remove(ed,(volatile HCED**)&LPC_USB->HcBulkHeadED); 00621 break; 00622 case ENDPOINT_INTERRUPT: 00623 for (int i = 0; i < 32; i++) 00624 Remove(ed,(volatile HCED**)&CommunicationArea.InterruptTable[i]); 00625 break; 00626 } 00627 00628 u16 fn = CommunicationArea.FrameNumber; 00629 while (fn == CommunicationArea.FrameNumber) 00630 ; // Wait for next frame 00631 00632 } 00633 00634 // In theory, the endpoint is now dead. 00635 // TODO: Will Callbacks ever be pending? BUGBUG 00636 memset(endpoint,0,sizeof(Endpoint)); 00637 } 00638 00639 // Pop the last TD from the list 00640 HCTD* Reverse(HCTD* current) 00641 { 00642 HCTD *result = NULL,*temp; 00643 while (current) 00644 { 00645 temp = (HCTD*)current->Next; 00646 current->Next = (u32)result; 00647 result = current; 00648 current = temp; 00649 } 00650 return result; 00651 } 00652 00653 // Called from interrupt... 00654 // Control endpoints use a state machine to progress through the transfers 00655 void ProcessDoneQueue(u32 tdList) 00656 { 00657 HCTD* list = Reverse((HCTD*)tdList); 00658 while (list) 00659 { 00660 Endpoint* endpoint = (Endpoint*)(list-1); 00661 list = (HCTD*)list->Next; 00662 int ep = endpoint->Address(); 00663 bool in = endpoint->Flags & 0x80; 00664 int status = (endpoint->TDHead.Control >> 28) & 0xF; 00665 00666 LOG("ProcessDoneQueue %02X %08X\n\n",ep,endpoint->TDHead.Control); 00667 00668 if (status != 0) 00669 { 00670 LOG("ProcessDoneQueue status %02X %d\n\n",ep,status); 00671 endpoint->CurrentState = Endpoint::Idle; 00672 } else { 00673 switch (endpoint->CurrentState) 00674 { 00675 case Endpoint::SetupQueued: 00676 if (endpoint->Length == 0) 00677 Transfer(endpoint,in ? TOKEN_OUT : TOKEN_IN,0,0,Endpoint::StatusQueued); // Skip Data Phase 00678 else 00679 Transfer(endpoint,in ? TOKEN_IN : TOKEN_OUT,endpoint->Data,endpoint->Length, Endpoint::DataQueued); // Setup is done, now Data 00680 break; 00681 00682 case Endpoint::DataQueued: 00683 if (endpoint->TDHead.CurrBufPtr) 00684 endpoint->Length = endpoint->TDHead.CurrBufPtr - (u32)endpoint->Data; 00685 00686 if (ep == 0) 00687 Transfer(endpoint,in ? TOKEN_OUT : TOKEN_IN,0,0,Endpoint::StatusQueued); // Data is done, now Status, Control only 00688 else 00689 endpoint->CurrentState = Endpoint::Idle; 00690 break; 00691 00692 case Endpoint::StatusQueued: // Transaction is done 00693 endpoint->CurrentState = Endpoint::Idle; 00694 break; 00695 } 00696 } 00697 00698 // Complete, flag if we need a callback 00699 if (endpoint->Callback && endpoint->CurrentState == Endpoint::Idle) 00700 { 00701 endpoint->CurrentState = Endpoint::CallbackPending; 00702 _callbacksPending++; 00703 } 00704 } 00705 } 00706 00707 // Hack to reset devices that don't want to connect 00708 int AddDevice(int hub, int port, bool isLowSpeed) 00709 { 00710 int device = AddDeviceCore(hub,port,isLowSpeed); 00711 if (device < 0) 00712 { 00713 LOG("========RETRY ADD DEVICE========\n"); // This will go for ever.. TODO power cycle root? 00714 Disconnect(hub,port); // Could not read descriptor at assigned address, reset this port and try again 00715 ResetPort(hub,port); // Cheap bluetooth dongles often need this on a hotplug 00716 return -1; 00717 } 00718 return device; 00719 } 00720 00721 int AddDeviceCore(int hub, int port, bool isLowSpeed) 00722 { 00723 int lowSpeed = isLowSpeed ? 0x2000 : 0; 00724 DeviceDescriptor desc; 00725 EndpointZero.EndpointDescriptor.Control = (8 << 16) | lowSpeed; // MaxPacketSize == 8 00726 int r = GetDescriptor(0,DESCRIPTOR_TYPE_DEVICE,0,(u8*)&desc,8); 00727 if (r < 0) 00728 { 00729 LOG("FAILED TO LOAD DESCRIPTOR FOR DEVICE 0\n"); 00730 return r; 00731 } 00732 00733 EndpointZero.EndpointDescriptor.Control = (desc.bMaxPacketSize << 16) | lowSpeed; // Actual MaxPacketSize 00734 r = GetDescriptor(0,DESCRIPTOR_TYPE_DEVICE,0,(u8*)&desc,sizeof(desc)); 00735 if (r < 0) 00736 return r; 00737 00738 LOG("\nClass %02X found %04X:%04X\n\n",desc.bDeviceClass,desc.idVendor,desc.idProduct); 00739 00740 00741 // Now assign the device an address, move off EndpointZero 00742 int device = 0; 00743 for (int i = 0; i < MAX_DEVICES; i++) 00744 { 00745 if (Devices[i].Port == 0) 00746 { 00747 device = i+1; 00748 break; 00749 } 00750 } 00751 if (!device) 00752 return ERR_DEVICE_NONE_LEFT; 00753 00754 r = SetAddress(0,device); 00755 if (r) 00756 return r; 00757 DelayMS(2); 00758 00759 // Now at a nonzero address, create control endpoint 00760 Device* dev = &Devices[device-1]; 00761 dev->Init(&desc,hub,port,device,lowSpeed); 00762 AddEndpoint(device,0,ENDPOINT_CONTROL,desc.bMaxPacketSize,0); 00763 _connectPending = 0; 00764 00765 // Verify this all works 00766 r = GetDescriptor(device,DESCRIPTOR_TYPE_DEVICE,0,(u8*)&desc,sizeof(desc)); 00767 if (r < 0) 00768 return r; 00769 00770 // Set to interface 0 by default 00771 // Calls LoadDevice if interface is found 00772 r = SetConfigurationAndInterface(device,1,0,&desc); 00773 00774 if (desc.bDeviceClass == CLASS_HUB) 00775 InitHub(device); // Handle hubs in this code 00776 00777 return device; 00778 } 00779 00780 // Walk descriptors and create endpoints for a given device 00781 // TODO configuration !=1, alternate settings etc. 00782 int SetConfigurationAndInterface(int device, int configuration, int interfaceNumber, DeviceDescriptor* desc) 00783 { 00784 LOG("SetConfiguration and Interface\n"); 00785 u8 buffer[255]; 00786 int err = GetDescriptor(device,DESCRIPTOR_TYPE_CONFIGURATION,0,buffer,sizeof(buffer)); 00787 if (err < 0) 00788 return err; 00789 00790 err = SetConfiguration(device,configuration); 00791 if (err < 0) 00792 return err; 00793 00794 // Add the endpoints for this interface 00795 int len = buffer[2] | (buffer[3] << 8); 00796 u8* d = buffer; 00797 u8* end = d + len; 00798 InterfaceDescriptor* found = 0; 00799 while (d < end) 00800 { 00801 if (d[1] == DESCRIPTOR_TYPE_INTERFACE) 00802 { 00803 InterfaceDescriptor* id = (InterfaceDescriptor*)d; 00804 if (id->bInterfaceNumber == interfaceNumber) 00805 { 00806 found = id; 00807 d += d[0]; 00808 while (d < end && d[1] != DESCRIPTOR_TYPE_INTERFACE) 00809 { 00810 switch (d[1]) 00811 { 00812 case DESCRIPTOR_TYPE_ENDPOINT: 00813 AddEndpoint(device,(EndpointDescriptor*)d); 00814 break; 00815 default: 00816 LOG("Skipping descriptor %02X (%d bytes)\n",d[1],d[0]); 00817 } 00818 d += d[0]; 00819 } 00820 } 00821 } 00822 d += d[0]; 00823 } 00824 00825 if (!found) 00826 return ERR_INTERFACE_NOT_FOUND; 00827 OnLoadDevice(device,desc,found); 00828 return 0; 00829 } 00830 00831 void Init() 00832 { 00833 LOG("USB INIT (Controller is %d bytes)\n",sizeof(*this)); 00834 memset(this,0,sizeof(HostController)); 00835 EndpointZero.CurrentState = Endpoint::NotQueued; 00836 HWInit(&CommunicationArea); 00837 DelayMS(10); 00838 } 00839 00840 void ResetPort(int hub, int port) 00841 { 00842 LOG("ResetPort Hub:%d Port:%d\n",hub,port); 00843 _connectPending++; // Only reset/add 1 device at a time 00844 if (hub == 0) 00845 LPC_USB->HcRhPortStatus1 = PortResetStatus; // Reset Root Hub, port 1 00846 else 00847 00848 SetPortReset(hub,port); // or reset other hub 00849 } 00850 00851 void Disconnect(int hub, int port) 00852 { 00853 LOG("Disconnect Hub:%d Port:%d\n",hub,port); // Mark a device for destruction 00854 for (int i = 0; i < MAX_DEVICES; i++) 00855 { 00856 Device* dev = Devices + i; 00857 if (dev->Port == port && dev->Hub == hub) 00858 { 00859 // Disconnect everything that is attached to this device if it is a hub 00860 for (int p = 0; p < dev->HubPortCount; p++) 00861 Disconnect(i+1,p+1); 00862 00863 // Now release endpoints 00864 for (int j = 1; j < MAX_ENDPOINTS_PER_DEVICE*2; j += 2) 00865 { 00866 u8 endpointIndex = dev->_endpointMap[j]; 00867 if (endpointIndex != 0xFF) 00868 Release(Endpoints + endpointIndex); 00869 } 00870 dev->Port = 0; // Device is now free 00871 dev->Flags = 0; 00872 return; 00873 } 00874 } 00875 } 00876 00877 // called after reset 00878 void Connect(int hub, int port, bool lowspeed) 00879 { 00880 LOG("Connect Hub:%d Port:%d %s\n\n",hub,port,lowspeed ? "slow-speed" : "full-speed"); 00881 AddDevice(hub,port,lowspeed); 00882 } 00883 00884 // Called from interrupt 00885 void HubStatusChange(int hub, int port, u32 status) 00886 { 00887 LOG("HubStatusChange Hub:%d Port:%d %08X\n",hub,port,status); 00888 if (status & ConnectStatusChange) 00889 { 00890 if (status & CurrentConnectStatus) // Connecting 00891 ResetPort(hub,port); // Reset to initiate connect (state machine?) 00892 else 00893 Disconnect(hub,port); 00894 } 00895 00896 if (status & PortResetStatusChange) 00897 { 00898 if (!(status & PortResetStatus)) 00899 { 00900 _connectCountdown = 200; // Schedule a connection in 200ms 00901 if (status & LowspeedDevice) 00902 port |= 0x80; 00903 _connectHub = hub; 00904 _connectPort = port; 00905 } 00906 } 00907 } 00908 00909 #define HOST_CLK_EN (1<<0) 00910 #define PORTSEL_CLK_EN (1<<3) 00911 #define AHB_CLK_EN (1<<4) 00912 #define CLOCK_MASK (HOST_CLK_EN | PORTSEL_CLK_EN | AHB_CLK_EN) 00913 00914 #define FRAMEINTERVAL (12000-1) // 1ms 00915 #define DEFAULT_FMINTERVAL ((((6 * (FRAMEINTERVAL - 210)) / 7) << 16) | FRAMEINTERVAL) 00916 00917 void DelayMS(int ms) 00918 { 00919 u16 f = ms + CommunicationArea.FrameNumber; 00920 while (f != CommunicationArea.FrameNumber) 00921 ; 00922 } 00923 00924 static void HWInit(HCCA* cca) 00925 { 00926 NVIC_DisableIRQ(USB_IRQn); //no interruptions 00927 00928 // turn on power for USB 00929 LPC_SC->PCONP |= (1UL<<31); 00930 // Enable USB host clock, port selection and AHB clock 00931 LPC_USB->USBClkCtrl |= CLOCK_MASK; 00932 // Wait for clocks to become available 00933 while ((LPC_USB->USBClkSt & CLOCK_MASK) != CLOCK_MASK) 00934 ; 00935 00936 // We are a Host 00937 LPC_USB->OTGStCtrl |= 1; 00938 LPC_USB->USBClkCtrl &= ~PORTSEL_CLK_EN; // we don't need port selection clock until we do OTG 00939 00940 // configure USB pins 00941 LPC_PINCON->PINSEL1 &= ~((3<<26)|(3<<28)); 00942 LPC_PINCON->PINSEL1 |= ((1<<26)|(1<<28)); // USB D+/D- 00943 00944 LPC_PINCON->PINSEL3 &= ~((3 << 6) | (3 << 22)); // USB_PPWR, USB_OVRCR 00945 LPC_PINCON->PINSEL3 |= ((2 << 6) | (2 << 22)); 00946 00947 LPC_PINCON->PINSEL4 &= ~(3 << 18); // USB_CONNECT 00948 LPC_PINCON->PINSEL4 |= (1 << 18); 00949 00950 // Reset OHCI block 00951 LPC_USB->HcControl = 0; //Defines the operating modes of the HC. 00952 00953 LPC_USB->HcControlHeadED = 0; //Contains the physical address of the first endpoint 00954 //descriptor of the control list. 00955 00956 LPC_USB->HcBulkHeadED = 0; //Contains the physical address of the first endpoint 00957 //descriptor of the bulk list. 00958 00959 LPC_USB->HcCommandStatus = HostControllerReset; //This register is used to receive the commands from the 00960 //Host Controller Driver (HCD). It also indicates the status 00961 //of the HC. 00962 00963 LPC_USB->HcFmInterval = DEFAULT_FMINTERVAL; 00964 LPC_USB->HcPeriodicStart = FRAMEINTERVAL*90/100; 00965 00966 LPC_USB->HcControl = (LPC_USB->HcControl & (~HostControllerFunctionalState)) | OperationalMask; 00967 LPC_USB->HcRhStatus = SetGlobalPower; 00968 00969 LPC_USB->HcHCCA = (u32)cca; //Contains the physical address of the host controller 00970 //communication area. 00971 00972 LPC_USB->HcInterruptStatus |= LPC_USB->HcInterruptStatus; //Indicates the status on various events that cause 00973 //hardware interrupts by setting the appropriate bits. 00974 LPC_USB->HcInterruptEnable = MasterInterruptEnable | WritebackDoneHead | RootHubStatusChange | FrameNumberOverflow; 00975 00976 NVIC_SetPriority(USB_IRQn, 0); //top-priority 00977 NVIC_EnableIRQ(USB_IRQn); //enable USB interruptions. 00978 LOG("\nHWini\n"); 00979 while (cca->FrameNumber < 10) 00980 ; // 10ms delay before diving in 00981 } 00982 }; 00983 00984 //==================================================================================== 00985 //==================================================================================== 00986 // Host controller instance and Interrupt handler 00987 00988 static HostController _controller __attribute__((at(USB_RAM_BASE))); 00989 00990 extern "C" void USB_IRQHandler(void) __irq; 00991 void USB_IRQHandler (void) __irq 00992 { 00993 u32 int_status = LPC_USB->HcInterruptStatus; //Indicates the status on various events that cause 00994 //hardware interrupts by setting the appropriate bits. 00995 00996 if (int_status & RootHubStatusChange) // Root hub status change 00997 _controller._rootHubStatusChange++; // Just flag the controller, will be processed in USBLoop 00998 00999 u32 head = 0; 01000 if (int_status & WritebackDoneHead) 01001 { 01002 head = _controller.CommunicationArea.DoneHead; // Writeback Done 01003 _controller.CommunicationArea.DoneHead = 0; 01004 } 01005 LPC_USB->HcInterruptStatus = int_status; 01006 01007 if (head) 01008 _controller.ProcessDoneQueue(head); // TODO - low bit can be set BUGBUG 01009 } 01010 01011 //==================================================================================== 01012 //==================================================================================== 01013 // API Methods 01014 01015 void USBInit() 01016 { 01017 return _controller.Init(); 01018 } 01019 01020 void USBLoop() 01021 { 01022 return _controller.Loop(); 01023 } 01024 01025 u8* USBGetBuffer(u32* len) 01026 { 01027 *len = USB_RAM_SIZE - sizeof(HostController); 01028 return _controller.SRAM; 01029 } 01030 01031 01032 static Setup* GetSetup(int device) 01033 { 01034 if (device == 0) 01035 return &_controller._setupZero; 01036 01037 if (device < 1 || device > MAX_DEVICES) 01038 return 0; 01039 return &_controller.Devices[device-1].SetupBuffer; 01040 } 01041 01042 // Loop until IO on endpoint is complete 01043 static int WaitIODone(Endpoint* endpoint) 01044 { 01045 if (endpoint->CurrentState == Endpoint::NotQueued) 01046 return 0; 01047 while (endpoint->CurrentState != Endpoint::Idle) 01048 USBLoop(); // May generate callbacks, mount or unmount devices etc 01049 int status = endpoint->Status(); 01050 if (status == 0) 01051 return endpoint->Length; 01052 return -status; 01053 } 01054 01055 int USBTransfer(int device, int ep, u8 flags, u8* data, int length, USBCallback callback, void* userData) 01056 { 01057 Endpoint* endpoint = _controller.GetEndpoint(device,ep); 01058 if (!endpoint) 01059 return ERR_ENDPOINT_NOT_FOUND; 01060 01061 WaitIODone(endpoint); 01062 endpoint->Flags = flags; 01063 endpoint->Data = data; 01064 endpoint->Length = length; 01065 endpoint->Callback = callback; 01066 endpoint->UserData = userData; 01067 if (ep == 0) 01068 _controller.Transfer(endpoint,TOKEN_SETUP,(u8*)GetSetup(device),8,Endpoint::SetupQueued); 01069 else 01070 _controller.Transfer(endpoint,flags & 0x80 ? TOKEN_IN : TOKEN_OUT,data,length,Endpoint::DataQueued); 01071 if (callback) 01072 return IO_PENDING; 01073 return WaitIODone(endpoint); 01074 } 01075 01076 int USBControlTransfer(int device, int request_type, int request, int value, int index, u8* data, int length, USBCallback callback, void * userData) 01077 { 01078 01079 01080 Setup* setup = GetSetup(device); 01081 if (!setup) 01082 return ERR_DEVICE_NOT_FOUND; 01083 01084 // Async control calls may overwrite setup buffer of previous call, so we need to wait before setting up next call 01085 WaitIODone(_controller.GetEndpoint(device,0)); 01086 01087 setup->bm_request_type = request_type; 01088 setup->b_request = request; 01089 setup->w_value = value; 01090 setup->w_index = index; 01091 setup->w_length = length; 01092 01093 01094 #ifdef USBLOG 01095 LOG("USBControlTransfer\n"); 01096 LOG("bm_request_type\t %02x h", request_type); 01097 LOG( "\t %d%d%d%d%d%d%d%d b \t", (((request_type)&(128))>>7), (((request_type)&(64))>>6), ((request_type)&(32))>>5, ((request_type)&(16))>>4,((request_type)&(8))>>2,((request_type)&(4))>>1,((request_type)&(2) )>>1, (request_type)&(1) ); 01098 if( request_type &1) LOG(" -> device-to-host"); 01099 if(!( request_type & 1)) LOG(" -> host-to-device"); 01100 LOG("\n"); 01101 LOG("b_request\t %02x h ",request); 01102 /* USB2.0 specs: table 9.4: 01103 GET_STATUS 0 01104 CLEAR_FEATURE 1 01105 Reserved for future use 2 01106 SET_FEATURE 3 01107 Reserved for future use 4 01108 SET_ADDRESS 5 01109 GET_DESCRIPTOR 6 01110 SET_DESCRIPTOR 7 01111 GET_CONFIGURATION 8 01112 SET_CONFIGURATION 9 01113 GET_INTERFACE 10 01114 SET_INTERFACE 11 01115 SYNCH_FRAME 12 01116 */ 01117 LOG("\t"); 01118 switch (request) 01119 { 01120 case (0) :{ LOG("GET_STATUS"); break; } 01121 case (1) :{ LOG("CLEAR_FEATURE"); break; } 01122 case (2) :{ LOG("reseved"); break; } 01123 case (3) :{ LOG("SET_FEATURE"); break; } 01124 case (6): { LOG("GET_DESCRIPTOR"); break; } 01125 case (5) :{ LOG("SET_ADDRESS"); break; } 01126 case (7): { LOG("SET_DESCRIPTOR"); break; } 01127 case (8) :{ LOG("GET_CONFIGURATION"); break; } 01128 case (9): { LOG("SET_CONFIGURATION"); break; } 01129 case (10): { LOG("GET_INTERFACE"); break; } 01130 case (11) :{ LOG("SET_INTERFACE"); break; } 01131 case (12): { LOG("SYNCH_FRAEM"); break; } 01132 01133 }//end switch (reques) 01134 LOG("\n"); 01135 LOG("w_value \t %04x h\t ",value); 01136 /* 01137 Descriptor Types Value 01138 DEVICE 1 01139 CONFIGURATION 2 01140 STRING 3 01141 INTERFACE 4 01142 ENDPOINT 5 01143 DEVICE_QUALIFIER 6 01144 OTHER_SPEED_CONFIGURATION 7 01145 INTERFACE_POWER1 8 01146 */ 01147 u8* pv=(u8*)&value; 01148 pv=pv+1; 01149 switch (request) 01150 { 01151 case (GET_DESCRIPTOR): 01152 { 01153 switch (*pv) 01154 { 01155 case(1): { LOG(" -> DEVICE"); break; } 01156 case(2): { LOG(" -> CONFIGURATION"); break;} 01157 case(3): { LOG(" -> STRING"); break;} 01158 case( 4): { LOG(" -> INTERFACE"); break;} 01159 case(5): { LOG(" -> ENDPOINT"); break;} 01160 case( 6): { LOG(" -> DEVICE_QUALIFIER"); break;} 01161 case( 7): { LOG(" -> OTHER SPEED_CONFIGURATION"); break;} 01162 case (8) :{ LOG("SET_INTERFACE"); break; } 01163 default: {LOG("->%x",*pv);} ; 01164 }//end switch(value) 01165 break; 01166 }//end case 6 01167 01168 case(SET_ADDRESS): 01169 { 01170 LOG("<-this value is the new adress"); break; 01171 }//end case set address. 01172 01173 default : 01174 { LOG("."); break; 01175 } 01176 } 01177 LOG("\n"); 01178 LOG("w_index = %04x h = %2d d \n",index, index); 01179 LOG("w_length = %04x h = %2d d ",length, length); 01180 if (request==6) LOG(" -> this should be the descriptor/answer length"); 01181 LOG("\n"); 01182 #endif 01183 01184 return USBTransfer(device,0,request_type & DEVICE_TO_HOST,data,length,callback,userData); 01185 } 01186 01187 int USBInterruptTransfer(int device, int ep, u8* data, int length, USBCallback callback, void* userData) 01188 { 01189 LOG("USBinterruptTransfer\n"); 01190 return USBTransfer(device,ep,(ep & 0x80) | ENDPOINT_INTERRUPT,data,length,callback,userData); 01191 } 01192 01193 int USBBulkTransfer(int device, int ep, u8* data, int length, USBCallback callback, void* userData) 01194 { 01195 LOG("USBBulkTransfer\n"); 01196 return USBTransfer(device,ep,(ep & 0x80) | ENDPOINT_BULK,data,length,callback,userData); 01197 } 01198 01199 int GetDescriptor(int device, int descType,int descIndex, u8* data, int length) 01200 { 01201 return USBControlTransfer(device,DEVICE_TO_HOST | RECIPIENT_DEVICE, GET_DESCRIPTOR,(descType << 8)|(descIndex), 0, data, length, 0); 01202 } 01203 01204 int GetString(int device, int index, char* dst, int length) 01205 { 01206 u8 buffer[255]; 01207 int le = GetDescriptor(device,DESCRIPTOR_TYPE_STRING,index,buffer,sizeof(buffer)); 01208 if (le < 0) 01209 return le; 01210 if (length < 1) 01211 return -1; 01212 length <<= 1; 01213 if (le > length) 01214 le = length; 01215 for (int j = 2; j < le; j += 2) 01216 *dst++ = buffer[j]; 01217 *dst = 0; 01218 return (le>>1)-1; 01219 } 01220 01221 int SetAddress(int device, int new_addr) 01222 { 01223 return USBControlTransfer(device,HOST_TO_DEVICE | RECIPIENT_DEVICE, SET_ADDRESS, new_addr, 0, 0, 0, 0); 01224 } 01225 01226 int SetConfiguration(int device, int configNum) 01227 { 01228 return USBControlTransfer(device,HOST_TO_DEVICE | RECIPIENT_DEVICE, SET_CONFIGURATION, configNum, 0, 0, 0, 0); 01229 } 01230 01231 int SetInterface(int device, int ifNum, int altNum) 01232 { 01233 return USBControlTransfer(device,HOST_TO_DEVICE | RECIPIENT_INTERFACE, SET_INTERFACE, altNum, ifNum, 0, 0, 0); 01234 } 01235 01236 // HUB stuff 01237 int SetPortFeature(int device, int feature, int index) 01238 { 01239 return USBControlTransfer(device,HOST_TO_DEVICE | REQUEST_TYPE_CLASS | RECIPIENT_OTHER,SET_FEATURE,feature,index,0,0); 01240 } 01241 01242 int ClearPortFeature(int device, int feature, int index) 01243 { 01244 return USBControlTransfer(device,HOST_TO_DEVICE | REQUEST_TYPE_CLASS | RECIPIENT_OTHER,CLEAR_FEATURE,feature,index,0,0); 01245 } 01246 01247 int SetPortPower(int device, int port) 01248 { 01249 int r = SetPortFeature(device,PORT_POWER,port); 01250 _controller.DelayMS(20); // 80ms to turn on a hubs power... DESCRIPTOR? todo 01251 return r; 01252 } 01253 01254 int SetPortReset(int device, int port) 01255 { 01256 return SetPortFeature(device,PORT_RESET,port); 01257 } 01258 01259 int GetPortStatus(int device, int port, u32* status) 01260 { 01261 return USBControlTransfer(device,DEVICE_TO_HOST | REQUEST_TYPE_CLASS | RECIPIENT_OTHER,GET_STATUS,0,port,(u8*)status,4); 01262 }
Generated on Thu Jul 14 2022 02:50:59 by
1.7.2