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.
Dependents: UsbHostMAX3421E_Hello
usbhub.cpp
00001 /* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. 00002 00003 This software may be distributed and modified under the terms of the GNU 00004 General Public License version 2 (GPL2) as published by the Free Software 00005 Foundation and appearing in the file GPL2.TXT included in the packaging of 00006 this file. Please note that GPL2 Section 2[b] requires that all works based 00007 on this software must also be made publicly available under the terms of 00008 the GPL2 ("Copyleft"). 00009 00010 Contact information 00011 ------------------- 00012 00013 Circuits At Home, LTD 00014 Web : http://www.circuitsathome.com 00015 e-mail : support@circuitsathome.com 00016 */ 00017 #include "usbhub.h" 00018 00019 bool USBHub::bResetInitiated = false; 00020 00021 USBHub::USBHub(Usb *p) : 00022 pUsb(p), 00023 bAddress(0), 00024 bNbrPorts(0), 00025 //bInitState(0), 00026 qNextPollTime(0), 00027 bPollEnable(false) { 00028 epInfo[0].epAddr = 0; 00029 epInfo[0].maxPktSize = 8; 00030 epInfo[0].bmSndToggle = 0; 00031 epInfo[0].bmRcvToggle = 0; 00032 epInfo[0].bmNakPower = USB_NAK_MAX_POWER; 00033 00034 epInfo[1].epAddr = 1; 00035 epInfo[1].maxPktSize = 8; //kludge 00036 epInfo[1].bmSndToggle = 0; 00037 epInfo[1].bmRcvToggle = 0; 00038 epInfo[1].bmNakPower = USB_NAK_NOWAIT; 00039 00040 if(pUsb) 00041 pUsb->RegisterDeviceClass(this); 00042 } 00043 00044 uint8_t USBHub::Init(uint8_t parent, uint8_t port, bool lowspeed) { 00045 uint8_t buf[32]; 00046 USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf); 00047 HubDescriptor* hd = reinterpret_cast<HubDescriptor*>(buf); 00048 USB_CONFIGURATION_DESCRIPTOR * ucd = reinterpret_cast<USB_CONFIGURATION_DESCRIPTOR*>(buf); 00049 uint8_t rcode; 00050 UsbDevice *p = NULL; 00051 EpInfo *oldep_ptr = NULL; 00052 uint8_t len = 0; 00053 uint16_t cd_len = 0; 00054 00055 //USBTRACE("\r\nHub Init Start "); 00056 //D_PrintHex<uint8_t > (bInitState, 0x80); 00057 00058 AddressPool &addrPool = pUsb->GetAddressPool(); 00059 00060 //switch (bInitState) { 00061 // case 0: 00062 if(bAddress) 00063 return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; 00064 00065 // Get pointer to pseudo device with address 0 assigned 00066 p = addrPool.GetUsbDevicePtr(0); 00067 00068 if(!p) 00069 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; 00070 00071 if(!p->epinfo) 00072 return USB_ERROR_EPINFO_IS_NULL; 00073 00074 // Save old pointer to EP_RECORD of address 0 00075 oldep_ptr = p->epinfo; 00076 00077 // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence 00078 p->epinfo = epInfo; 00079 00080 p->lowspeed = lowspeed; 00081 00082 // Get device descriptor 00083 rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*)buf); 00084 00085 p->lowspeed = false; 00086 00087 if(!rcode) 00088 len = (buf[0] > 32) ? 32 : buf[0]; 00089 00090 if(rcode) { 00091 // Restore p->epinfo 00092 p->epinfo = oldep_ptr; 00093 return rcode; 00094 } 00095 00096 // Extract device class from device descriptor 00097 // If device class is not a hub return 00098 if(udd->bDeviceClass != 0x09) 00099 return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; 00100 00101 // Allocate new address according to device class 00102 bAddress = addrPool.AllocAddress(parent, (udd->bDeviceClass == 0x09) ? true : false, port); 00103 00104 if(!bAddress) 00105 return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; 00106 00107 // Extract Max Packet Size from the device descriptor 00108 epInfo[0].maxPktSize = udd->bMaxPacketSize0; 00109 00110 // Assign new address to the device 00111 rcode = pUsb->setAddr(0, 0, bAddress); 00112 00113 if(rcode) { 00114 // Restore p->epinfo 00115 p->epinfo = oldep_ptr; 00116 addrPool.FreeAddress(bAddress); 00117 bAddress = 0; 00118 return rcode; 00119 } 00120 00121 //USBTRACE2("\r\nHub address: ", bAddress ); 00122 00123 // Restore p->epinfo 00124 p->epinfo = oldep_ptr; 00125 00126 if(len) 00127 rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*)buf); 00128 00129 if(rcode) 00130 goto FailGetDevDescr; 00131 00132 // Assign epInfo to epinfo pointer 00133 rcode = pUsb->setEpInfoEntry(bAddress, 2, epInfo); 00134 00135 if(rcode) 00136 goto FailSetDevTblEntry; 00137 00138 // bInitState = 1; 00139 00140 // case 1: 00141 // Get hub descriptor 00142 rcode = GetHubDescriptor(0, 8, buf); 00143 00144 if(rcode) 00145 goto FailGetHubDescr; 00146 00147 // Save number of ports for future use 00148 bNbrPorts = hd->bNbrPorts; 00149 00150 // bInitState = 2; 00151 00152 // case 2: 00153 // Read configuration Descriptor in Order To Obtain Proper Configuration Value 00154 rcode = pUsb->getConfDescr(bAddress, 0, 8, 0, buf); 00155 00156 if(!rcode) { 00157 cd_len = ucd->wTotalLength; 00158 rcode = pUsb->getConfDescr(bAddress, 0, cd_len, 0, buf); 00159 } 00160 if(rcode) 00161 goto FailGetConfDescr; 00162 00163 // The following code is of no practical use in real life applications. 00164 // It only intended for the usb protocol sniffer to properly parse hub-class requests. 00165 { 00166 uint8_t buf2[24]; 00167 00168 rcode = pUsb->getConfDescr(bAddress, 0, buf[0], 0, buf2); 00169 00170 if(rcode) 00171 goto FailGetConfDescr; 00172 } 00173 00174 // Set Configuration Value 00175 rcode = pUsb->setConf(bAddress, 0, buf[5]); 00176 00177 if(rcode) 00178 goto FailSetConfDescr; 00179 00180 // bInitState = 3; 00181 00182 // case 3: 00183 // Power on all ports 00184 for(uint8_t j = 1; j <= bNbrPorts; j++) 00185 SetPortFeature(HUB_FEATURE_PORT_POWER, j, 0); //HubPortPowerOn(j); 00186 00187 pUsb->SetHubPreMask(); 00188 bPollEnable = true; 00189 // bInitState = 0; 00190 //} 00191 //bInitState = 0; 00192 //USBTRACE("...OK\r\n"); 00193 return 0; 00194 00195 // Oleg, No debugging?? -- xxxajk 00196 FailGetDevDescr: 00197 goto Fail; 00198 00199 FailSetDevTblEntry: 00200 goto Fail; 00201 00202 FailGetHubDescr: 00203 goto Fail; 00204 00205 FailGetConfDescr: 00206 goto Fail; 00207 00208 FailSetConfDescr: 00209 goto Fail; 00210 00211 Fail: 00212 USBTRACE("...FAIL\r\n"); 00213 return rcode; 00214 } 00215 00216 uint8_t USBHub::Release() { 00217 pUsb->GetAddressPool().FreeAddress(bAddress); 00218 00219 if(bAddress == 0x41) 00220 pUsb->SetHubPreMask(); 00221 00222 bAddress = 0; 00223 bNbrPorts = 0; 00224 qNextPollTime = 0; 00225 bPollEnable = false; 00226 return 0; 00227 } 00228 00229 uint8_t USBHub::Poll() { 00230 uint8_t rcode = 0; 00231 00232 if(!bPollEnable) 00233 return 0; 00234 00235 if(((int32_t)((uint32_t)millis() - qNextPollTime) >= 0L)) { 00236 rcode = CheckHubStatus(); 00237 qNextPollTime = (uint32_t)millis() + 100; 00238 } 00239 return rcode; 00240 } 00241 00242 uint8_t USBHub::CheckHubStatus() { 00243 uint8_t rcode; 00244 uint8_t buf[8]; 00245 uint16_t read = 1; 00246 00247 rcode = pUsb->inTransfer(bAddress, 1, &read, buf); 00248 00249 if(rcode) 00250 return rcode; 00251 00252 //if (buf[0] & 0x01) // Hub Status Change 00253 //{ 00254 // pUsb->PrintHubStatus(addr); 00255 // rcode = GetHubStatus(1, 0, 1, 4, buf); 00256 // if (rcode) 00257 // { 00258 // printf("GetHubStatus Error"); 00259 // USB_HOST_SERIAL.println(rcode, HEX); 00260 // return rcode; 00261 // } 00262 //} 00263 for(uint8_t port = 1, mask = 0x02; port < 8; mask <<= 1, port++) { 00264 if(buf[0] & mask) { 00265 HubEvent evt; 00266 evt.bmEvent = 0; 00267 00268 rcode = GetPortStatus(port, 4, evt.evtBuff); 00269 00270 if(rcode) 00271 continue; 00272 00273 rcode = PortStatusChange(port, evt); 00274 00275 if(rcode == HUB_ERROR_PORT_HAS_BEEN_RESET) 00276 return 0; 00277 00278 if(rcode) 00279 return rcode; 00280 } 00281 } // for 00282 00283 for(uint8_t port = 1; port <= bNbrPorts; port++) { 00284 HubEvent evt; 00285 evt.bmEvent = 0; 00286 00287 rcode = GetPortStatus(port, 4, evt.evtBuff); 00288 00289 if(rcode) 00290 continue; 00291 00292 if((evt.bmStatus & bmHUB_PORT_STATE_CHECK_DISABLED) != bmHUB_PORT_STATE_DISABLED) 00293 continue; 00294 00295 // Emulate connection event for the port 00296 evt.bmChange |= bmHUB_PORT_STATUS_C_PORT_CONNECTION; 00297 00298 rcode = PortStatusChange(port, evt); 00299 00300 if(rcode == HUB_ERROR_PORT_HAS_BEEN_RESET) 00301 return 0; 00302 00303 if(rcode) 00304 return rcode; 00305 } // for 00306 return 0; 00307 } 00308 00309 void USBHub::ResetHubPort(uint8_t port) { 00310 HubEvent evt; 00311 evt.bmEvent = 0; 00312 uint8_t rcode; 00313 00314 ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0); 00315 ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0); 00316 SetPortFeature(HUB_FEATURE_PORT_RESET, port, 0); 00317 00318 00319 for(int i = 0; i < 3; i++) { 00320 rcode = GetPortStatus(port, 4, evt.evtBuff); 00321 if(rcode) break; // Some kind of error, bail. 00322 if(evt.bmEvent == bmHUB_PORT_EVENT_RESET_COMPLETE || evt.bmEvent == bmHUB_PORT_EVENT_LS_RESET_COMPLETE) { 00323 break; 00324 } 00325 wait_ms(100); // simulate polling. 00326 } 00327 ClearPortFeature(HUB_FEATURE_C_PORT_RESET, port, 0); 00328 ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0); 00329 wait_ms(20); 00330 } 00331 00332 uint8_t USBHub::PortStatusChange(uint8_t port, HubEvent &evt) { 00333 switch(evt.bmEvent) { 00334 // Device connected event 00335 case bmHUB_PORT_EVENT_CONNECT: 00336 case bmHUB_PORT_EVENT_LS_CONNECT: 00337 if(bResetInitiated) 00338 return 0; 00339 00340 ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0); 00341 ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0); 00342 SetPortFeature(HUB_FEATURE_PORT_RESET, port, 0); 00343 bResetInitiated = true; 00344 return HUB_ERROR_PORT_HAS_BEEN_RESET; 00345 00346 // Device disconnected event 00347 case bmHUB_PORT_EVENT_DISCONNECT: 00348 ClearPortFeature(HUB_FEATURE_C_PORT_ENABLE, port, 0); 00349 ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0); 00350 bResetInitiated = false; 00351 00352 UsbDeviceAddress a; 00353 a.devAddress = 0; 00354 a.bmHub = 0; 00355 a.bmParent = bAddress; 00356 a.bmAddress = port; 00357 pUsb->releaseDevice(a.devAddress); 00358 return 0; 00359 00360 // Reset complete event 00361 case bmHUB_PORT_EVENT_RESET_COMPLETE: 00362 case bmHUB_PORT_EVENT_LS_RESET_COMPLETE: 00363 ClearPortFeature(HUB_FEATURE_C_PORT_RESET, port, 0); 00364 ClearPortFeature(HUB_FEATURE_C_PORT_CONNECTION, port, 0); 00365 00366 wait_ms(20); 00367 00368 a.devAddress = bAddress; 00369 00370 pUsb->configuring(a.bmAddress, port, (evt.bmStatus & bmHUB_PORT_STATUS_PORT_LOW_SPEED)); 00371 bResetInitiated = false; 00372 break; 00373 00374 } // switch (evt.bmEvent) 00375 return 0; 00376 } 00377 00378 void PrintHubPortStatus(USBHub *hubptr, uint8_t addr __attribute__((unused)), uint8_t port, bool print_changes) { 00379 uint8_t rcode = 0; 00380 HubEvent evt; 00381 00382 rcode = hubptr->GetPortStatus(port, 4, evt.evtBuff); 00383 00384 if(rcode) { 00385 printf("ERROR!\r\n"); 00386 return; 00387 } 00388 printf("\r\nPort %d\r\n", port); 00389 00390 printf("Status\r\n"); 00391 printf("CONNECTION:\t%d\r\n", (evt.bmStatus & bmHUB_PORT_STATUS_PORT_CONNECTION) > 0); 00392 printf("ENABLE:\t\t%d\r\n", (evt.bmStatus & bmHUB_PORT_STATUS_PORT_ENABLE) > 0); 00393 printf("SUSPEND:\t%d\r\n", (evt.bmStatus & bmHUB_PORT_STATUS_PORT_SUSPEND) > 0); 00394 printf("OVER_CURRENT:\t%d\r\n", (evt.bmStatus & bmHUB_PORT_STATUS_PORT_OVER_CURRENT) > 0); 00395 printf("RESET:\t\t%d\r\n", (evt.bmStatus & bmHUB_PORT_STATUS_PORT_RESET) > 0); 00396 printf("POWER:\t\t%d\r\n", (evt.bmStatus & bmHUB_PORT_STATUS_PORT_POWER) > 0); 00397 printf("LOW_SPEED:\t%d\r\n", (evt.bmStatus & bmHUB_PORT_STATUS_PORT_LOW_SPEED) > 0); 00398 printf("HIGH_SPEED:\t%d\r\n", (evt.bmStatus & bmHUB_PORT_STATUS_PORT_HIGH_SPEED) > 0); 00399 printf("TEST:\t\t%d\r\n", (evt.bmStatus & bmHUB_PORT_STATUS_PORT_TEST) > 0); 00400 printf("INDICATOR:\t%d\r\n", (evt.bmStatus & bmHUB_PORT_STATUS_PORT_INDICATOR) > 0); 00401 00402 if(!print_changes) 00403 return; 00404 00405 printf("\r\nChange\r\n"); 00406 printf("CONNECTION:\t%d\r\n", (evt.bmChange & bmHUB_PORT_STATUS_C_PORT_CONNECTION) > 0); 00407 printf("ENABLE:\t\t%d\r\n", (evt.bmChange & bmHUB_PORT_STATUS_C_PORT_ENABLE) > 0); 00408 printf("SUSPEND:\t%d\r\n", (evt.bmChange & bmHUB_PORT_STATUS_C_PORT_SUSPEND) > 0); 00409 printf("OVER_CURRENT:\t%d\r\n", (evt.bmChange & bmHUB_PORT_STATUS_C_PORT_OVER_CURRENT) > 0); 00410 printf("RESET:\t\t%d\r\n", (evt.bmChange & bmHUB_PORT_STATUS_C_PORT_RESET) > 0); 00411 }
Generated on Tue Jul 12 2022 18:12:05 by
1.7.2