BLE demo for mbed Ported RunningElectronics's SBDBT firmware for BLE. It can communicate with iOS

Dependencies:   FatFileSystem mbed

Fork of BTstack by Norimasa Okamoto

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers UsbHostMgr.cpp Source File

UsbHostMgr.cpp

00001 
00002 /*
00003 Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
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 #include "UsbHostMgr.h"
00024 #include "usb_mem.h"
00025 #include "Usb_td.h"
00026 #include "string.h" //For memcpy, memmove, memset
00027 #include "netCfg.h"
00028 #if NET_USB
00029 //#define __DEBUG
00030 //#define __DEBUG3
00031 //#include "dbg/dbg.h"
00032 #include "mydbg.h"
00033 
00034 // bits of the USB/OTG clock control register
00035 #define HOST_CLK_EN     (1<<0)
00036 #define DEV_CLK_EN      (1<<1)
00037 #define PORTSEL_CLK_EN  (1<<3)
00038 #define AHB_CLK_EN      (1<<4)
00039 
00040 // bits of the USB/OTG clock status register
00041 #define HOST_CLK_ON     (1<<0)
00042 #define DEV_CLK_ON      (1<<1)
00043 #define PORTSEL_CLK_ON  (1<<3)
00044 #define AHB_CLK_ON      (1<<4)
00045 
00046 // we need host clock, OTG/portsel clock and AHB clock
00047 #define CLOCK_MASK (HOST_CLK_EN | PORTSEL_CLK_EN | AHB_CLK_EN)
00048 
00049 static UsbHostMgr* pMgr = NULL;
00050 
00051 extern "C" void sUsbIrqhandler(void) __irq
00052 {
00053   DBG("\n+Int\n");
00054   if(pMgr)
00055     pMgr->UsbIrqhandler();
00056   DBG("\n-Int\n");
00057   return;
00058 }
00059 
00060 UsbHostMgr::UsbHostMgr() : m_lpDevices()
00061 {
00062   /*if(!pMgr)*/ //Assume singleton
00063   pMgr = this;
00064   usb_mem_init();
00065   for(int i = 0; i < USB_HOSTMGR_MAX_DEVS; i++) {
00066       m_lpDevices[i] = NULL;
00067   }
00068   m_pHcca = (HCCA*) usb_get_hcca();
00069   memset((void*)m_pHcca, 0, 0x100);
00070   m_hardware_init = false;
00071   DBG("Host manager at %p\n", this);
00072   
00073   test_td(); // TD test program
00074 }
00075 
00076 UsbHostMgr::~UsbHostMgr()
00077 {
00078   if(pMgr == this)
00079     pMgr = NULL;
00080 }
00081 
00082 UsbErr UsbHostMgr::init() //Initialize host
00083 {
00084   DBG("m_hardware_init=%d\n", m_hardware_init);
00085   if(m_hardware_init) {
00086       return USBERR_OK;
00087   }
00088 
00089   NVIC_DisableIRQ(USB_IRQn);                           /* Disable the USB interrupt source           */
00090   
00091   LPC_SC->PCONP       &= ~(1UL<<31); //Cut power
00092   wait(1);
00093   
00094   
00095   // turn on power for USB
00096   LPC_SC->PCONP       |= (1UL<<31);
00097   // Enable USB host clock, port selection and AHB clock
00098   LPC_USB->USBClkCtrl |= CLOCK_MASK;
00099   // Wait for clocks to become available
00100   while ((LPC_USB->USBClkSt & CLOCK_MASK) != CLOCK_MASK)
00101       ;
00102   
00103   // it seems the bits[0:1] mean the following
00104   // 0: U1=device, U2=host
00105   // 1: U1=host, U2=host
00106   // 2: reserved
00107   // 3: U1=host, U2=device
00108   // NB: this register is only available if OTG clock (aka "port select") is enabled!!
00109   // since we don't care about port 2, set just bit 0 to 1 (U1=host)
00110   LPC_USB->OTGStCtrl |= 1;
00111   
00112   // now that we've configured the ports, we can turn off the portsel clock
00113   LPC_USB->USBClkCtrl &= ~PORTSEL_CLK_EN;
00114   
00115   // power pins are not connected on mbed, so we can skip them
00116   /* P1[18] = USB_UP_LED, 01 */
00117   /* P1[19] = /USB_PPWR,     10 */
00118   /* P1[22] = USB_PWRD, 10 */
00119   /* P1[27] = /USB_OVRCR, 10 */
00120   /*LPC_PINCON->PINSEL3 &= ~((3<<4) | (3<<6) | (3<<12) | (3<<22));  
00121   LPC_PINCON->PINSEL3 |=  ((1<<4)|(2<<6) | (2<<12) | (2<<22));   // 0x00802080
00122   */
00123 
00124   // configure USB D+/D- pins
00125   /* P0[29] = USB_D+, 01 */
00126   /* P0[30] = USB_D-, 01 */
00127   LPC_PINCON->PINSEL1 &= ~((3<<26) | (3<<28));  
00128   LPC_PINCON->PINSEL1 |=  ((1<<26)|(1<<28));     // 0x14000000
00129       
00130   DBG("Initializing Host Stack\n");
00131   
00132   wait_ms(100);                                   /* Wait 50 ms before apply reset              */
00133   LPC_USB->HcControl       = 0;                       /* HARDWARE RESET                             */
00134   LPC_USB->HcControlHeadED = 0;                       /* Initialize Control list head to Zero       */
00135   LPC_USB->HcBulkHeadED    = 0;                       /* Initialize Bulk list head to Zero          */
00136   
00137                                                       /* SOFTWARE RESET                             */
00138   LPC_USB->HcCommandStatus = OR_CMD_STATUS_HCR;
00139   LPC_USB->HcFmInterval    = DEFAULT_FMINTERVAL;      /* Write Fm Interval and Largest Data Packet Counter */
00140   LPC_USB->HcPeriodicStart = FI*90/100;
00141 
00142                                                       /* Put HC in operational state                */
00143   LPC_USB->HcControl  = (LPC_USB->HcControl & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER;
00144   LPC_USB->HcRhStatus = OR_RH_STATUS_LPSC;            /* Set Global Power                           */
00145   
00146   LPC_USB->HcHCCA = (uint32_t)(m_pHcca);
00147   LPC_USB->HcInterruptStatus |= LPC_USB->HcInterruptStatus;                   /* Clear Interrrupt Status                    */
00148 
00149 
00150   LPC_USB->HcInterruptEnable  = OR_INTR_ENABLE_MIE |
00151                        OR_INTR_ENABLE_WDH |
00152                        OR_INTR_ENABLE_RHSC;
00153 
00154   NVIC_SetPriority(USB_IRQn, 0);       /* highest priority */
00155   /* Enable the USB Interrupt */
00156   NVIC_SetVector(USB_IRQn, (uint32_t)(sUsbIrqhandler));
00157   LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC;
00158   LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC;
00159   
00160   
00161   /* Check for any connected devices */
00162   //if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS)  //Root device connected
00163   //{
00164   //  //Device connected
00165   //  wait(1);
00166   //  DBG("Device connected (%08x)\n", LPC_USB->HcRhPortStatus1);
00167   //  onUsbDeviceConnected(0, 1); //Hub 0 (root hub), Port 1 (count starts at 1)
00168   //}
00169     
00170   DBG("Enabling IRQ\n");
00171   NVIC_EnableIRQ(USB_IRQn);
00172   DBG("End of host stack initialization\n");
00173   m_hardware_init = true;
00174   return USBERR_OK;
00175 }
00176 
00177 UsbErr UsbHostMgr::poll() //Enumerate connected devices, etc
00178 {
00179   /* Check for any connected devices */
00180   if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS)  //Root device connected
00181   {
00182     //Device connected
00183     wait(1);
00184     DBG("Device connected (%08x)\n", LPC_USB->HcRhPortStatus1);
00185     onUsbDeviceConnected(0, 1); //Hub 0 (root hub), Port 1 (count starts at 1)
00186   }
00187   
00188   for(int i = 0; i < USB_HOSTMGR_MAX_DEVS; i++)
00189   {
00190     UsbDevice* dev = m_lpDevices[i];
00191     if (dev == NULL) {
00192       continue;
00193     }
00194     DBG3("%d dev=%p %d %d addr=%d\n", i, dev, dev->m_connected, dev->m_enumerated, dev->m_addr);
00195     if(dev->m_connected) {
00196       if (!dev->m_enumerated) {
00197           dev->enumerate();
00198           return USBERR_PROCESSING;
00199       }
00200     }
00201   }
00202   for(int i = 0; i < USB_HOSTMGR_MAX_DEVS; i++) {
00203     UsbDevice* dev = m_lpDevices[i];
00204     if (dev == NULL) {
00205       continue;
00206     }   
00207     if (dev->m_connected && dev->m_enumerated) {
00208       if (dev->m_DeviceClass == 0x09) { // HUB
00209         UsbErr rc = dev->hub_poll();
00210         if (rc == USBERR_PROCESSING) {
00211           return USBERR_PROCESSING;
00212         } 
00213       }
00214     }
00215   }
00216   return USBERR_OK;
00217 }
00218 
00219 int UsbHostMgr::devicesCount()
00220 {
00221   int i;
00222   for(i = 0; i < USB_HOSTMGR_MAX_DEVS; i++)
00223   {
00224     if (m_lpDevices[i] == NULL) {
00225       return i;
00226     }
00227   }
00228   return i;
00229 }
00230 
00231 UsbDevice* UsbHostMgr::getDevice(int item)
00232 {
00233   UsbDevice* pDev = m_lpDevices[item];
00234   if(!pDev)
00235     return NULL;
00236     
00237   pDev->m_refs++;
00238   return pDev;
00239 }
00240 
00241 void UsbHostMgr::releaseDevice(UsbDevice* pDev)
00242 {
00243   DBG_ASSERT(0);
00244 
00245   pDev->m_refs--;
00246   if(pDev->m_refs > 0)
00247     return;
00248   //If refs count = 0, delete
00249   //Find & remove from list
00250   int i;
00251   for(i = 0; i < USB_HOSTMGR_MAX_DEVS; i++)
00252   {
00253     if (m_lpDevices[i] == pDev)
00254       break;
00255   }
00256   if(i!=USB_HOSTMGR_MAX_DEVS)
00257     memmove(&m_lpDevices[i], &m_lpDevices[i+1], sizeof(UsbDevice*) * (USB_HOSTMGR_MAX_DEVS - (i + 1))); //Safer than memcpy because of overlapping mem
00258   m_lpDevices[USB_HOSTMGR_MAX_DEVS - 1] = NULL;
00259   delete pDev;
00260 }
00261 
00262 void UsbHostMgr::UsbIrqhandler()
00263 {
00264   uint32_t   int_status;
00265   uint32_t   ie_status;
00266   
00267   int_status    = LPC_USB->HcInterruptStatus;                          /* Read Interrupt Status                */
00268   ie_status     = LPC_USB->HcInterruptEnable;                          /* Read Interrupt enable status         */
00269 
00270   if (!(int_status & ie_status))
00271   {
00272     return;
00273   }
00274   else
00275   {
00276     int_status = int_status & ie_status;
00277     if (int_status & OR_INTR_STATUS_RHSC) /* Root hub status change interrupt     */
00278     {
00279       DBG("LPC_USB->HcRhPortStatus1 = %08x\n", LPC_USB->HcRhPortStatus1);
00280       if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CSC)
00281       {
00282         if (LPC_USB->HcRhStatus & OR_RH_STATUS_DRWE)
00283         {
00284             /*
00285              * When DRWE is on, Connect Status Change
00286              * means a remote wakeup event.
00287             */
00288             //HOST_RhscIntr = 1;// JUST SOMETHING FOR A BREAKPOINT
00289         }
00290         else
00291         {
00292           /*
00293            * When DRWE is off, Connect Status Change
00294            * is NOT a remote wakeup event
00295           */
00296           if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS)  //Root device connected
00297           {
00298             //Device connected
00299             DBG("Device connected (%08x)\n", LPC_USB->HcRhPortStatus1);
00300             onUsbDeviceConnected(0, 1); //Hub 0 (root hub), Port 1 (count starts at 1)
00301           }
00302           else //Root device disconnected
00303           {
00304             //Device disconnected
00305             DBG("Device disconnected\n");
00306             onUsbDeviceDisconnected(0, 1);
00307           }
00308           //TODO: HUBS
00309         }
00310         LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC;
00311       }
00312       if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRSC)
00313       {
00314         LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC;
00315       }
00316     }  
00317     if (int_status & OR_INTR_STATUS_WDH) /* Writeback Done Head interrupt        */
00318     {                  
00319       //UsbEndpoint::sOnCompletion((LPC_USB->HccaDoneHead) & 0xFE);
00320       if(m_pHcca->DoneHead)
00321       {
00322         UsbEndpoint::sOnCompletion(m_pHcca->DoneHead);
00323         m_pHcca->DoneHead = 0;
00324         LPC_USB->HcInterruptStatus = OR_INTR_STATUS_WDH;
00325         if(m_pHcca->DoneHead)
00326           DBG("??????????????????????????????\n\n\n");
00327       }
00328       else
00329       {
00330         //Probably an error
00331         int_status = LPC_USB->HcInterruptStatus;
00332         DBG("HcInterruptStatus = %08x\n", int_status);
00333         if (int_status & OR_INTR_STATUS_UE) //Unrecoverable error, disconnect devices and resume
00334         {
00335           onUsbDeviceDisconnected(0, 1);
00336           LPC_USB->HcInterruptStatus = OR_INTR_STATUS_UE;
00337           LPC_USB->HcCommandStatus = 0x01; //Host Controller Reset
00338         }
00339       }
00340     }
00341     LPC_USB->HcInterruptStatus = int_status; /* Clear interrupt status register      */
00342   }
00343   return;
00344 }
00345 
00346 void UsbHostMgr::onUsbDeviceDisconnected(int hub, int port)
00347 {
00348   for(int i = 0; i < devicesCount(); i++)
00349   {
00350      if( (m_lpDevices[i]->m_hub == hub)
00351      &&  (m_lpDevices[i]->m_port == port) )
00352      {
00353        m_lpDevices[i]->m_connected = false;
00354        if(!m_lpDevices[i]->m_enumerated)
00355        {
00356          delete m_lpDevices[i];
00357          m_lpDevices[i] = NULL;
00358        }
00359        return;
00360      }
00361   }
00362 }
00363 
00364 void UsbHostMgr::resetPort(int hub, int port)
00365 {
00366   DBG3("hub=%d port=%d\n", hub, port);
00367   if(hub == 0) //Root hub
00368   {
00369     wait_ms(100); /* USB 2.0 spec says at least 50ms delay before port reset */
00370     LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRS; // Initiate port reset
00371     DBG("Before loop\n");
00372     while (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRS)
00373       ;
00374     LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; // ...and clear port reset signal
00375     DBG("After loop\n");
00376     wait_ms(200); /* Wait for 100 MS after port reset  */
00377   }
00378   else
00379   {
00380     for(int i = 0; i < USB_HOSTMGR_MAX_DEVS; i++) {
00381       UsbDevice* dev = m_lpDevices[i];
00382       if (dev == NULL) {
00383         continue;
00384       }
00385       if (dev->m_addr == hub) {
00386         DBG("%d dev=%p\n", i, dev);
00387         dev->hub_PortReset(port);
00388         return;
00389       }
00390     }
00391     DBG_ASSERT(0);
00392   }
00393 }
00394 
00395 #endif