Zoltan Hudak / UsbHostMAX3421E

Dependents:   UsbHostMAX3421E_Hello

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers usbhub.cpp Source File

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 }