//------------------------------------------------------------------------------ /// Configures a TWI peripheral to operate in master mode, at the given /// frequency (in Hz). The duty cycle of the TWI clock is set to 50%. /// \param pTwi Pointer to an AT91S_TWI instance. /// \param twck Desired TWI clock frequency. /// \param mck Master clock frequency. //------------------------------------------------------------------------------ void TWI_Configure(AT91S_TWI *pTwi, unsigned int twck, unsigned int mck) { unsigned int ckdiv = 0; unsigned int cldiv; unsigned char ok = 0; trace_LOG(trace_DEBUG, "-D- TWI_Configure()\n\r"); SANITY_CHECK(pTwi); // Reset the TWI pTwi->TWI_CR = AT91C_TWI_SWRST; // Set master mode pTwi->TWI_CR = AT91C_TWI_MSEN; // Configure clock while (!ok) { cldiv = ((mck / (2 * twck)) - 3) / power(2, ckdiv); if (cldiv <= 255) { ok = 1; } else { ckdiv++; } } ASSERT(ckdiv < 8, "-F- Cannot find valid TWI clock parameters\n\r"); trace_LOG(trace_INFO, "-D- Using CKDIV = %u and CLDIV/CHDIV = %u\n\r", ckdiv, cldiv); pTwi->TWI_CWGR = (ckdiv << 16) | (cldiv << 8) | cldiv; }
//------------------------------------------------------------------------------ /// Handles all interrupts on the given PIO controller. /// \param id PIO controller ID. /// \param pBase PIO controller base address. //------------------------------------------------------------------------------ void PioInterruptHandler(unsigned int id, AT91S_PIO *pBase) { unsigned int status; unsigned int i; // Check PIO controller status status = pBase->PIO_ISR; status &= pBase->PIO_IMR; if (status != 0) { trace_LOG(trace_DEBUG, "-D- PIO interrupt on PIO controller #%d\n\r", id); // Check all sources i = 0; while (status != 0) { // There cannot be an unconfigured source enabled. SANITY_CHECK(i < numSources); // Source if configured on PIOA if (pSources[i].pPin->id == id) { // Source has PIOs which have changed if ((status & pSources[i].pPin->mask) != 0) { trace_LOG(trace_DEBUG, "-D- Interrupt source #%d triggered\n\r", i); pSources[i].handler(pSources[i].pPin); status &= ~(pSources[i].pPin->mask); } } i++; } } }
//----------------------------------------------------------------------------- /// Get the statstic information & reset it /// \param pStats Pointer to EmacStats structure to copy the informations /// \param reset Reset the statistics after copy it //----------------------------------------------------------------------------- void EMAC_GetStatistics(EmacStats *pStats, unsigned char reset) { unsigned int ncrBackup = 0; trace_LOG(trace_DEBUG, "EMAC_GetStatistics\n\r"); // Sanity check if (pStats == (EmacStats *) 0) { return; } ncrBackup = AT91C_BASE_EMAC->EMAC_NCR & (AT91C_EMAC_TE | AT91C_EMAC_RE); // Disable TX/RX AT91C_BASE_EMAC->EMAC_NCR = ncrBackup & ~(AT91C_EMAC_TE | AT91C_EMAC_RE); // Copy the informations memcpy(pStats, (void*)&EmacStatistics, sizeof(EmacStats)); // Reset the statistics if (reset) { memset((void*)&EmacStatistics, 0x00, sizeof(EmacStats)); AT91C_BASE_EMAC->EMAC_NCR = ncrBackup | AT91C_EMAC_CLRSTAT; } // restore NCR AT91C_BASE_EMAC->EMAC_NCR = ncrBackup; }
//------------------------------------------------------------------------------ /// Disables a given interrupt source. /// \param pPin Interrupt source to disable. //------------------------------------------------------------------------------ void PIO_DisableIt(const Pin *pPin) { SANITY_CHECK(pPin); trace_LOG(trace_DEBUG, "-D- PIO_DisableIt()\n\r"); pPin->pio->PIO_IDR = pPin->mask; }
//------------------------------------------------------------------------------ /// Sets the input data to encrypt/decrypt using TDES. /// \param pInput Pointer to the 64-bits input data. //------------------------------------------------------------------------------ void TDES_SetInputData(const unsigned int *pInput) { trace_LOG(trace_DEBUG, "-D- TDES_SetInputData()\n\r"); SANITY_CHECK(pInput); AT91C_BASE_TDES->TDES_IDATAxR[0] = pInput[0]; AT91C_BASE_TDES->TDES_IDATAxR[1] = pInput[1]; }
//------------------------------------------------------------------------------ /// Stores the output data from the last TDES operation into the given 64-bits /// buffers. /// \param pOutput Pointer to a 64-bits output buffer. //------------------------------------------------------------------------------ void TDES_GetOutputData(unsigned int *pOutput) { trace_LOG(trace_DEBUG, "-D- TDES_GetOutputData()\n\r"); SANITY_CHECK(pOutput); pOutput[0] = AT91C_BASE_TDES->TDES_ODATAxR[0]; pOutput[1] = AT91C_BASE_TDES->TDES_ODATAxR[1]; }
//------------------------------------------------------------------------------ /// Sets the initialization vector to use when the TDES algorithm is configured /// in a chained block mode (CBC, CFB or OFB). /// \param pVector Pointer to the 64-bits vector. //------------------------------------------------------------------------------ void TDES_SetVector(const unsigned int *pVector) { trace_LOG(trace_DEBUG, "-D- TDES_SetVector()\n\r"); SANITY_CHECK(pVector); AT91C_BASE_TDES->TDES_IVxR[0] = pVector[0]; AT91C_BASE_TDES->TDES_IVxR[1] = pVector[1]; }
//------------------------------------------------------------------------------ /// Configures an interrupt source. /// \param pPin Interrupt source. /// \param handler Desired interrupt handler for the source. //------------------------------------------------------------------------------ void PIO_ConfigureIt(const Pin *pPin, void (*handler)(const Pin *)) { InterruptSource *pSource; trace_LOG(trace_DEBUG, "-D- PIO_ConfigureIt()\n\r"); SANITY_CHECK(pPin); ASSERT(numSources < MAX_INTERRUPT_SOURCES, "-F- PIO_ConfigureIt: Increase MAX_INTERRUPT_SOURCES\n\r"); // Define new source trace_LOG(trace_DEBUG, "-D- PIO_ConfigureIt: Defining new source #%d.\n\r", numSources); pSource = &(pSources[numSources]); pSource->pPin = pPin; pSource->handler = handler; numSources++; }
//------------------------------------------------------------------------------ /// Sets the input data buffer to encrypt/decrypt when in PDC mode. /// \param pInput Pointer to the input data. /// \param size Size of buffer in bytes. //------------------------------------------------------------------------------ void TDES_SetInputBuffer(const unsigned int *pInput, unsigned int size) { trace_LOG(trace_DEBUG, "-D- TDES_SetInputBuffer()\n\r"); SANITY_CHECK(pInput); SANITY_CHECK((size > 0) && ((size % 8) == 0)); AT91C_BASE_TDES->TDES_TPR = (unsigned int) pInput; AT91C_BASE_TDES->TDES_TCR = size / 4; }
//------------------------------------------------------------------------------ /// Sets the output buffer which will receive the encrypted/decrypted data when /// using the PDC. /// \param pOutput Pointer to the output data. /// \param size Size of buffer in bytes. //------------------------------------------------------------------------------ void TDES_SetOutputBuffer(unsigned int *pOutput, unsigned int size) { trace_LOG(trace_DEBUG, "-D- TDES_SetOutputBuffer()\n\r"); SANITY_CHECK(pOutput); SANITY_CHECK((size > 0) && ((size % 8) == 0)); AT91C_BASE_TDES->TDES_RPR = (unsigned int) pOutput; AT91C_BASE_TDES->TDES_RCR = size / 4; }
//------------------------------------------------------------------------------ /// Starts the encryption or decryption process if the TDES peripheral is /// configured in manual or PDC mode. //------------------------------------------------------------------------------ void TDES_Start(void) { trace_LOG(trace_DEBUG, "-D- TDES_Start()\n\r"); SANITY_CHECK(((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_SMOD) == AT91C_TDES_SMOD_MANUAL) || ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_SMOD) == AT91C_TDES_SMOD_PDC)); // Manual mode if ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_SMOD) == AT91C_TDES_SMOD_MANUAL) { AT91C_BASE_TDES->TDES_CR = AT91C_TDES_START; } // PDC mode else { AT91C_BASE_TDES->TDES_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN; } }
//----------------------------------------------------------------------------- /// Write PHY register /// Return 1 if successfully, 0 if timeout. /// \param PhyAddress PHY Address /// \param Address Register Address /// \param Value Data to write ( Actually 16 bit data ) /// \param retry The retry times, 0 to wait forever until complete. //----------------------------------------------------------------------------- unsigned char EMAC_WritePhy(unsigned char PhyAddress, unsigned char Address, unsigned int Value, unsigned int retry) { AT91C_BASE_EMAC->EMAC_MAN = (AT91C_EMAC_SOF & (0x01 << 30)) | (AT91C_EMAC_CODE & (2 << 16)) | (AT91C_EMAC_RW & (1 << 28)) | (AT91C_EMAC_PHYA & ((PhyAddress & 0x1f) << 23)) | (AT91C_EMAC_REGA & (Address << 18)) | (AT91C_EMAC_DATA & Value) ; if ( EMAC_WaitPhy(retry) == 0 ) { trace_LOG(trace_ERROR, "TimeOut EMAC_WritePhy\n\r"); return 0; } return 1; }
//------------------------------------------------------------------------------ /// Sets the 64-bits keys (one, two or three depending on the configuration) /// that shall be used by the TDES algorithm. /// \param pKey1 Pointer to key #1. /// \param pKey2 Pointer to key #2 (shall be 0 in single-DES mode). /// \param pKey3 Pointer to key #3 (shall be 0 when using two keys). //------------------------------------------------------------------------------ void TDES_SetKeys( const unsigned int *pKey1, const unsigned int *pKey2, const unsigned int *pKey3) { trace_LOG(trace_DEBUG, "-D- TDES_SetKeys()\n\r"); SANITY_CHECK(pKey1); SANITY_CHECK((pKey2 && ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_TDESMOD) == AT91C_TDES_TDESMOD)) || (!pKey2 && ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_TDESMOD) == 0))); SANITY_CHECK((pKey3 && ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_TDESMOD) == AT91C_TDES_TDESMOD) && ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_KEYMOD) == 0)) || (!pKey3 && ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_TDESMOD) == AT91C_TDES_TDESMOD) && ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_KEYMOD) == AT91C_TDES_KEYMOD)) || (!pKey3 && ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_TDESMOD) == 0) && ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_KEYMOD) == 0))); // Write key #1 if (pKey1) { AT91C_BASE_TDES->TDES_KEY1WxR[0] = pKey1[0]; AT91C_BASE_TDES->TDES_KEY1WxR[1] = pKey1[1]; } // Write key #2 if (pKey1) { AT91C_BASE_TDES->TDES_KEY2WxR[0] = pKey2[0]; AT91C_BASE_TDES->TDES_KEY2WxR[1] = pKey2[1]; } // Write key #2 if (pKey1) { AT91C_BASE_TDES->TDES_KEY3WxR[0] = pKey3[0]; AT91C_BASE_TDES->TDES_KEY3WxR[1] = pKey3[1]; } }
//------------------------------------------------------------------------------ /// Configures the triple-DES peripheral to cipher/decipher, use single-DES or /// triple-DES, use two or three keys (when in triple-DES mode), start manually, /// automatically or via the PDC and use the given operating mode (ECB, CBC, /// CFB or OFB). /// \param cipher Encrypts if 1, decrypts if 0. /// \param tdesmod Single- or triple-DES mode. /// \param keymod Use two or three keys (must be 0 in single-DES mode). /// \param smod Start mode. /// \param opmod Encryption/decryption mode. //------------------------------------------------------------------------------ void TDES_Configure( unsigned char cipher, unsigned int tdesmod, unsigned int keymod, unsigned int smod, unsigned int opmod) { trace_LOG(trace_DEBUG, "-D- TDES_Configure()\n\r"); SANITY_CHECK((cipher & 0xFFFFFFFE) == 0); SANITY_CHECK((tdesmod & 0xFFFFFFFD) == 0); SANITY_CHECK((keymod & 0xFFFFFFEF) == 0); SANITY_CHECK((smod & 0xFFFFFCFF) == 0); SANITY_CHECK((opmod & 0xFFFFCFFF) == 0); // Reset peripheral AT91C_BASE_TDES->TDES_CR = AT91C_TDES_SWRST; // Configure mode register AT91C_BASE_TDES->TDES_MR = cipher | tdesmod | keymod | smod | opmod; }
//------------------------------------------------------------------------------ /// Starts a read operation on the TWI bus with the specified slave, and returns /// immediately. Data must then be read using TWI_ReadByte() whenever a byte is /// available (poll using TWI_ByteReceived()). /// \param pTwi Pointer to an AT91S_TWI instance. /// \param address Slave address on the bus. /// \param iaddress Optional internal address bytes. /// \param isize Number of internal address bytes. //----------------------------------------------------------------------------- void TWI_StartRead( AT91S_TWI *pTwi, unsigned char address, unsigned int iaddress, unsigned char isize) { trace_LOG(trace_DEBUG, "-D- TWI_StartRead()\n\r"); SANITY_CHECK(pTwi); SANITY_CHECK((address & 0x80) == 0); SANITY_CHECK((iaddress & 0xFF000000) == 0); SANITY_CHECK(isize < 4); // Set slave address and number of internal address bytes pTwi->TWI_MMR = (isize << 8) | AT91C_TWI_MREAD | (address << 16); // Set internal address bytes pTwi->TWI_IADR = iaddress; // Send START condition pTwi->TWI_CR = AT91C_TWI_START; }
//----------------------------------------------------------------------------- /// Starts a write operation on the TWI to access the selected slave, then /// returns immediately. A byte of data must be provided to start the write; /// other bytes are written next. /// \param pTwi Pointer to an AT91S_TWI instance. /// \param address Address of slave to acccess on the bus. /// \param iaddress Optional slave internal address. /// \param isize Number of internal address bytes. /// \param byte First byte to send. //----------------------------------------------------------------------------- void TWI_StartWrite( AT91S_TWI *pTwi, unsigned char address, unsigned int iaddress, unsigned char isize, unsigned char byte) { trace_LOG(trace_DEBUG, "-D- TWI_StartWrite()\n\r"); SANITY_CHECK(pTwi); SANITY_CHECK((address & 0x80) == 0); SANITY_CHECK((iaddress & 0xFF000000) == 0); SANITY_CHECK(isize < 4); // Set slave address and number of internal address bytes pTwi->TWI_MMR = (isize << 8) | (address << 16); // Set internal address bytes pTwi->TWI_IADR = iaddress; // Write first byte to send TWI_WriteByte(pTwi, byte); }
//------------------------------------------------------------------------------ /// Reads and return a packet of data on the specified USART peripheral. This /// function operates asynchronously, so it waits until some data has been /// received. /// \param usart Pointer to an USART peripheral. /// \param timeOut Time out value (0 -> no timeout). //------------------------------------------------------------------------------ unsigned short USART_Read( AT91S_USART *usart, volatile unsigned int timeOut) { if (timeOut == 0) { while ((usart->US_CSR & AT91C_US_RXRDY) == 0); } else { while ((usart->US_CSR & AT91C_US_RXRDY) == 0) { if (timeOut == 0) { trace_LOG(trace_ERROR, "-E- USART_Read: Timed out.\n\r"); return 0; } timeOut--; } } return usart->US_RHR; }
//------------------------------------------------------------------------------ /// Enables the given interrupt source if it has been configured. /// \param pPin Interrupt source to enable. //------------------------------------------------------------------------------ void PIO_EnableIt(const Pin *pPin) { trace_LOG(trace_DEBUG, "-D- PIO_EnableIt()\n\r"); SANITY_CHECK(pPin); #ifndef NOASSERT unsigned int i = 0; unsigned char found = 0; while ((i < numSources) && !found) { if (pSources[i].pPin == pPin) { found = 1; } i++; } ASSERT(found, "-F- PIO_EnableIt: Interrupt source has not been configured\n\r"); #endif pPin->pio->PIO_ISR; pPin->pio->PIO_IER = pPin->mask; }
//----------------------------------------------------------------------------- /// Wait PHY operation complete. /// Return 1 if the operation completed successfully. /// May be need to re-implemented to reduce CPU load. /// \param retry: the retry times, 0 to wait forever until complete. //----------------------------------------------------------------------------- static unsigned char EMAC_WaitPhy( unsigned int retry ) { unsigned int retry_count = 0; while((AT91C_BASE_EMAC->EMAC_NSR & AT91C_EMAC_IDLE) == 0) { // Dead LOOP! if (retry == 0) { continue; } // Timeout check retry_count++; if(retry_count >= retry) { trace_LOG(trace_ERROR, "E: Wait PHY time out\n\r"); return 0; } } return 1; }
//----------------------------------------------------------------------------- /// Set MDC clock according to current board clock. Per 802.3, MDC should be /// less then 2.5MHz. /// Return 1 if successfully, 0 if MDC clock not found. //----------------------------------------------------------------------------- unsigned char EMAC_SetMdcClock( unsigned int mck ) { int clock_dividor; if (mck <= 20000000) { clock_dividor = AT91C_EMAC_CLK_HCLK_8; /// MDC clock = MCK/8 } else if (mck <= 40000000) { clock_dividor = AT91C_EMAC_CLK_HCLK_16; /// MDC clock = MCK/16 } else if (mck <= 80000000) { clock_dividor = AT91C_EMAC_CLK_HCLK_32; /// MDC clock = MCK/32 } else if (mck <= 160000000) { clock_dividor = AT91C_EMAC_CLK_HCLK_64; /// MDC clock = MCK/64 } else { trace_LOG(trace_ERROR, "E: No valid MDC clock.\n\r"); return 0; } AT91C_BASE_EMAC->EMAC_NCFGR = (AT91C_BASE_EMAC->EMAC_NCFGR & (~AT91C_EMAC_CLK)) | clock_dividor; return 1; }
//------------------------------------------------------------------------------ /// Sends one packet of data through the specified USART peripheral. This /// function operates synchronously, so it only returns when the data has been /// actually sent. /// \param usart Pointer to an USART peripheral. /// \param data Data to send including 9nth bit and sync field if necessary (in /// the same format as the US_THR register in the datasheet). /// \param timeOut Time out value (0 = no timeout). //------------------------------------------------------------------------------ void USART_Write( AT91S_USART *usart, unsigned short data, volatile unsigned int timeOut) { if (timeOut == 0) { while ((usart->US_CSR & AT91C_US_TXEMPTY) == 0); } else { while ((usart->US_CSR & AT91C_US_TXEMPTY) == 0) { if (timeOut == 0) { trace_LOG(trace_ERROR, "-E- USART_Write: Timed out.\n\r"); return; } timeOut--; } } usart->US_THR = data; }
//------------------------------------------------------------------------------ /// Handles the given request if it is standard, otherwise STALLs it. /// \param pDriver Pointer to a USBDDriver instance. /// \param pRequest Pointer to a USBGenericRequest instance. //------------------------------------------------------------------------------ void USBDDriver_RequestHandler( USBDDriver *pDriver, const USBGenericRequest *pRequest) { unsigned char cfgnum; unsigned char infnum; unsigned char eptnum; unsigned char setting; unsigned char type; unsigned char index; unsigned int length; unsigned int address; trace_LOG(trace_INFO, "Std "); // Check request code switch (USBGenericRequest_GetRequest(pRequest)) { case USBGenericRequest_GETDESCRIPTOR: trace_LOG(trace_INFO, "gDesc "); // Send the requested descriptor type = USBGetDescriptorRequest_GetDescriptorType(pRequest); index = USBGetDescriptorRequest_GetDescriptorIndex(pRequest); length = USBGenericRequest_GetLength(pRequest); GetDescriptor(pDriver, type, index, length); break; case USBGenericRequest_SETADDRESS: trace_LOG(trace_INFO, "sAddr "); // Sends a zero-length packet and then set the device address address = USBSetAddressRequest_GetAddress(pRequest); if( USBD_IsHighSpeed() ) { USBD_SetAddress( address ); } else { USBD_Write(0, 0, 0, (TransferCallback) USBD_SetAddress, (void *) address); } break; case USBGenericRequest_SETCONFIGURATION: trace_LOG(trace_INFO, "sCfg "); // Set the requested configuration cfgnum = USBSetConfigurationRequest_GetConfiguration(pRequest); SetConfiguration(pDriver, cfgnum); break; case USBGenericRequest_GETCONFIGURATION: trace_LOG(trace_INFO, "gCfg "); // Send the current configuration number GetConfiguration(pDriver); break; case USBGenericRequest_GETSTATUS: trace_LOG(trace_INFO, "gSta "); // Check who is the recipient switch (USBGenericRequest_GetRecipient(pRequest)) { case USBGenericRequest_DEVICE: trace_LOG(trace_INFO, "Dev "); // Send the device status GetDeviceStatus(pDriver); break; case USBGenericRequest_ENDPOINT: trace_LOG(trace_INFO, "Ept "); // Send the endpoint status eptnum = USBGenericRequest_GetEndpointNumber(pRequest); GetEndpointStatus(eptnum); break; default: trace_LOG(trace_WARNING, "W: USBDDriver_RequestHandler: Unknown recipient (%d)\n\r", USBGenericRequest_GetRecipient(pRequest)); USBD_Stall(0); } break; case USBGenericRequest_CLEARFEATURE: trace_LOG(trace_INFO, "cFeat "); // Check which is the requested feature switch (USBFeatureRequest_GetFeatureSelector(pRequest)) { case USBFeatureRequest_ENDPOINTHALT: trace_LOG(trace_INFO, "Hlt "); // Unhalt endpoint and send a zero-length packet USBD_Unhalt(USBGenericRequest_GetEndpointNumber(pRequest)); USBD_Write(0, 0, 0, 0, 0); break; case USBFeatureRequest_DEVICEREMOTEWAKEUP: trace_LOG(trace_INFO, "RmWU "); // Disable remote wake-up and send a zero-length packet pDriver->isRemoteWakeUpEnabled = 0; USBD_Write(0, 0, 0, 0, 0); break; default: trace_LOG(trace_WARNING, "USBDDriver_RequestHandler: Unknown feature selector (%d)\n\r", USBFeatureRequest_GetFeatureSelector(pRequest)); USBD_Stall(0); } break; case USBGenericRequest_SETFEATURE: trace_LOG(trace_INFO, "sFeat "); // Check which is the selected feature switch (USBFeatureRequest_GetFeatureSelector(pRequest)) { case USBFeatureRequest_DEVICEREMOTEWAKEUP: trace_LOG(trace_INFO, "RmWU "); // Enable remote wake-up and send a ZLP pDriver->isRemoteWakeUpEnabled = 1; USBD_Write(0, 0, 0, 0, 0); break; case USBFeatureRequest_ENDPOINTHALT: trace_LOG(trace_INFO, "Ept "); // Halt endpoint USBD_Halt(USBGenericRequest_GetEndpointNumber(pRequest)); USBD_Write(0, 0, 0, 0, 0); break; #if defined(BOARD_USB_UDPHS) case USBFeatureRequest_TESTMODE: // 7.1.20 Test Mode Support if ((USBGenericRequest_GetType(pRequest) == USBGenericRequest_DEVICE) && ((USBGenericRequest_GetIndex(pRequest) & 0x000F) == 0)) { // Handle test request USBDDriver_Test(USBFeatureRequest_GetTestSelector(pRequest)); } else { USBD_Stall(0); } break; #endif default: trace_LOG(trace_WARNING, "USBDDriver_RequestHandler: Unknown feature selector (%d)\n\r", USBFeatureRequest_GetFeatureSelector(pRequest)); USBD_Stall(0); } break; case USBGenericRequest_SETINTERFACE: trace_LOG(trace_INFO, "sInterface "); infnum = USBInterfaceRequest_GetInterface(pRequest); setting = USBInterfaceRequest_GetAlternateSetting(pRequest); SetInterface(pDriver, infnum, setting); break; case USBGenericRequest_GETINTERFACE: trace_LOG(trace_INFO, "gInterface "); infnum = USBInterfaceRequest_GetInterface(pRequest); GetInterface(pDriver, infnum); break; default: trace_LOG(trace_WARNING, "USBDDriver_RequestHandler: Unknown request code (%d)\n\r", USBGenericRequest_GetRequest(pRequest)); USBD_Stall(0); } }
//------------------------------------------------------------------------------ /// Initializes the PIO interrupt management logic. /// \param priority PIO controller interrupts priority. //------------------------------------------------------------------------------ void PIO_InitializeInterrupts(unsigned int priority) { trace_LOG(trace_DEBUG, "-D- PIO_Initialize()\n\r"); SANITY_CHECK((priority & ~AT91C_AIC_PRIOR) == 0); // Reset sources numSources = 0; #ifdef AT91C_ID_PIOA // Configure PIO interrupt sources trace_LOG(trace_DEBUG, "-D- PIO_Initialize: Configuring PIOA\n\r"); AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOA; AT91C_BASE_PIOA->PIO_ISR; AT91C_BASE_PIOA->PIO_IDR = 0xFFFFFFFF; AIC_ConfigureIT(AT91C_ID_PIOA, priority, InterruptHandler); AIC_EnableIT(AT91C_ID_PIOA); #endif #ifdef AT91C_ID_PIOB trace_LOG(trace_DEBUG, "-D- PIO_Initialize: Configuring PIOB\n\r"); AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOB; AT91C_BASE_PIOB->PIO_ISR; AT91C_BASE_PIOB->PIO_IDR = 0xFFFFFFFF; AIC_ConfigureIT(AT91C_ID_PIOB, priority, InterruptHandler); AIC_EnableIT(AT91C_ID_PIOB); #endif #ifdef AT91C_ID_PIOC trace_LOG(trace_DEBUG, "-D- PIO_Initialize: Configuring PIOC\n\r"); AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOC; AT91C_BASE_PIOC->PIO_ISR; AT91C_BASE_PIOC->PIO_IDR = 0xFFFFFFFF; AIC_ConfigureIT(AT91C_ID_PIOC, priority, InterruptHandler); AIC_EnableIT(AT91C_ID_PIOC); #endif #ifdef AT91C_ID_PIOD trace_LOG(trace_DEBUG, "-D- PIO_Initialize: Configuring PIOD\n\r"); AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOD; AT91C_BASE_PIOC->PIO_ISR; AT91C_BASE_PIOC->PIO_IDR = 0xFFFFFFFF; AIC_ConfigureIT(AT91C_ID_PIOD, priority, InterruptHandler); AIC_EnableIT(AT91C_ID_PIOD); #endif #ifdef AT91C_ID_PIOE trace_LOG(trace_DEBUG, "-D- PIO_Initialize: Configuring PIOE\n\r"); AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOE; AT91C_BASE_PIOC->PIO_ISR; AT91C_BASE_PIOC->PIO_IDR = 0xFFFFFFFF; AIC_ConfigureIT(AT91C_ID_PIOE, priority, InterruptHandler); AIC_EnableIT(AT91C_ID_PIOE); #endif #if defined(AT91C_ID_PIOABCD) // Treat PIOABCD interrupts #if !defined(AT91C_ID_PIOA) \ && !defined(AT91C_ID_PIOB) \ && !defined(AT91C_ID_PIOC) \ && !defined(AT91C_ID_PIOD) trace_LOG(trace_DEBUG, "-D- PIO_Initialize: Configuring PIOABCD\n\r"); AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOABCD; AT91C_BASE_PIOA->PIO_ISR; AT91C_BASE_PIOA->PIO_IDR = 0xFFFFFFFF; AIC_ConfigureIT(AT91C_ID_PIOABCD, priority, InterruptHandler); AIC_EnableIT(AT91C_ID_PIOABCD); #endif #endif #if defined(AT91C_ID_PIOABCDE) // Treat PIOABCDE interrupts #if !defined(AT91C_ID_PIOA) \ && !defined(AT91C_ID_PIOB) \ && !defined(AT91C_ID_PIOC) \ && !defined(AT91C_ID_PIOD) \ && !defined(AT91C_ID_PIOE) trace_LOG(trace_DEBUG, "-D- PIO_Initialize: Configuring PIOABCDE\n\r"); AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOABCDE; AT91C_BASE_PIOA->PIO_ISR; AT91C_BASE_PIOA->PIO_IDR = 0xFFFFFFFF; AIC_ConfigureIT(AT91C_ID_PIOABCDE, priority, InterruptHandler); AIC_EnableIT(AT91C_ID_PIOABCDE); #endif #endif #if defined(AT91C_ID_PIOCDE) // Treat PIOCDE interrupts #if !defined(AT91C_ID_PIOC) \ && !defined(AT91C_ID_PIOD) \ && !defined(AT91C_ID_PIOE) trace_LOG(trace_DEBUG, "-D- PIO_Initialize: Configuring PIOC\n\r"); AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOCDE; AT91C_BASE_PIOC->PIO_ISR; AT91C_BASE_PIOC->PIO_IDR = 0xFFFFFFFF; AIC_ConfigureIT(AT91C_ID_PIOCDE, priority, InterruptHandler); AIC_EnableIT(AT91C_ID_PIOCDE); #endif #endif }
//------------------------------------------------------------------------------ /// Returns the current status register value of the TDES peripheral. //------------------------------------------------------------------------------ unsigned int TDES_GetStatus(void) { trace_LOG(trace_DEBUG, "-D- TDES_GetStatus()\n\r"); return AT91C_BASE_TDES->TDES_ISR; }
//----------------------------------------------------------------------------- /// Receive a packet with EMAC /// If not enough buffer for the packet, the remaining data is lost but right /// frame length is returned. /// \param pFrame Buffer to store the frame /// \param frameSize Size of the frame /// \param pRcvSize Received size /// \return OK, no data, or frame too small //----------------------------------------------------------------------------- unsigned char EMAC_Poll(unsigned char *pFrame, unsigned int frameSize, unsigned int *pRcvSize) { unsigned short bufferLength; unsigned int tmpFrameSize=0; unsigned char *pTmpFrame=0; unsigned int tmpIdx = rxTd.idx; volatile EmacRxTDescriptor *pRxTd = rxTd.td + rxTd.idx; ASSERT(pFrame, "F: EMAC_Poll\n\r"); char isFrame = 0; // Set the default return value *pRcvSize = 0; // Process received RxTd while ((pRxTd->addr & EMAC_RX_OWNERSHIP_BIT) == EMAC_RX_OWNERSHIP_BIT) { // A start of frame has been received, discard previous fragments if ((pRxTd->status & EMAC_RX_SOF_BIT) == EMAC_RX_SOF_BIT) { // Skip previous fragment while (tmpIdx != rxTd.idx) { pRxTd = rxTd.td + rxTd.idx; pRxTd->addr &= ~(EMAC_RX_OWNERSHIP_BIT); CIRC_INC(rxTd.idx, RX_BUFFERS); } // Reset the temporary frame pointer pTmpFrame = pFrame; tmpFrameSize = 0; // Start to gather buffers in a frame isFrame = 1; } // Increment the pointer CIRC_INC(tmpIdx, RX_BUFFERS); // Copy data in the frame buffer if (isFrame) { if (tmpIdx == rxTd.idx) { trace_LOG(trace_INFO, "I: no EOF (Invalid of buffers too small)\n\r"); do { pRxTd = rxTd.td + rxTd.idx; pRxTd->addr &= ~(EMAC_RX_OWNERSHIP_BIT); CIRC_INC(rxTd.idx, RX_BUFFERS); } while(tmpIdx != rxTd.idx); return EMAC_RX_NO_DATA; } // Copy the buffer into the application frame bufferLength = EMAC_RX_UNITSIZE; if ((tmpFrameSize + bufferLength) > frameSize) { bufferLength = frameSize - tmpFrameSize; } memcpy(pTmpFrame, (void*)(pRxTd->addr & EMAC_ADDRESS_MASK), bufferLength); pTmpFrame += bufferLength; tmpFrameSize += bufferLength; // An end of frame has been received, return the data if ((pRxTd->status & EMAC_RX_EOF_BIT) == EMAC_RX_EOF_BIT) { // Frame size from the EMAC *pRcvSize = (pRxTd->status & EMAC_LENGTH_FRAME); // Application frame buffer is too small all data have not been copied if (tmpFrameSize < *pRcvSize) { printf("size req %u size allocated %u\n\r", *pRcvSize, frameSize); return EMAC_RX_FRAME_SIZE_TOO_SMALL; } trace_LOG(trace_INFO, "packet %d-%u (%u)\n\r", rxTd.idx, tmpIdx, *pRcvSize); // All data have been copied in the application frame buffer => release TD while (rxTd.idx != tmpIdx) { pRxTd = rxTd.td + rxTd.idx; pRxTd->addr &= ~(EMAC_RX_OWNERSHIP_BIT); CIRC_INC(rxTd.idx, RX_BUFFERS); } EmacStatistics.rx_packets++; return EMAC_RX_OK; } } // SOF has not been detected, skip the fragment else { pRxTd->addr &= ~(EMAC_RX_OWNERSHIP_BIT); rxTd.idx = tmpIdx; } // Process the next buffer pRxTd = rxTd.td + tmpIdx; } //trace_LOG(trace_DEBUG, "E"); return EMAC_RX_NO_DATA; }
//----------------------------------------------------------------------------- /// Send a packet with EMAC. /// If the packet size is larger than transfer buffer size error returned. /// \param buffer The buffer to be send /// \param size The size of buffer to be send /// \param fEMAC_TxCallback Threshold Wakeup callback /// \param fWakeUpCb TX Wakeup /// \return OK, Busy or invalid packet //----------------------------------------------------------------------------- unsigned char EMAC_Send(void *pBuffer, unsigned int size, EMAC_TxCallback fEMAC_TxCallback) { volatile EmacTxTDescriptor *pTxTd; volatile EMAC_TxCallback *pTxCb; //trace_LOG(trace_DEBUG, "EMAC_Send\n\r"); // Check parameter if (size > EMAC_TX_UNITSIZE) { trace_LOG(trace_ERROR, "-E- EMAC driver does not split send packets."); trace_LOG(trace_ERROR, " It can send %d bytes max in one packet (%u bytes requested)\n\r", EMAC_TX_UNITSIZE, size); return EMAC_TX_INVALID_PACKET; } // If no free TxTd, buffer can't be sent, schedule the wakeup callback if( CIRC_SPACE(txTd.head, txTd.tail, TX_BUFFERS) == 0) { return EMAC_TX_BUFFER_BUSY; } // Pointers to the current TxTd pTxTd = txTd.td + txTd.head; pTxCb = txTd.txCb + txTd.head; // Sanity check ASSERT((pTxTd->status & EMAC_TX_USED_BIT) != 0, "-F- Buffer is still under EMAC control\n\r"); // Setup/Copy data to transmition buffer if (pBuffer && size) { // Driver manage the ring buffer memcpy((void *)pTxTd->addr, pBuffer, size); } // Tx Callback *pTxCb = fEMAC_TxCallback; // Update TD status // The buffer size defined is length of ethernet frame // so it's always the last buffer of the frame. if (txTd.head == TX_BUFFERS-1) { pTxTd->status = (size & EMAC_LENGTH_FRAME) | EMAC_TX_LAST_BUFFER_BIT | EMAC_TX_WRAP_BIT; } else { pTxTd->status = (size & EMAC_LENGTH_FRAME) | EMAC_TX_LAST_BUFFER_BIT; } CIRC_INC(txTd.head, TX_BUFFERS) // Tx packets count EmacStatistics.tx_packets++; // Now start to transmit if it is not already done AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_TSTART; return EMAC_TX_OK; }
//----------------------------------------------------------------------------- /// Initialize the EMAC with the emac controller address /// \param id HW ID for power management /// \param pTxWakeUpfct Thresold TX Wakeup Callback /// \param pRxfct RX Wakeup Callback /// \param pMacAddress Mac Address /// \param enableCAF enable AT91C_EMAC_CAF if needed by application /// \param enableNBC AT91C_EMAC_NBC if needed by application //----------------------------------------------------------------------------- void EMAC_Init( unsigned char id, const unsigned char *pMacAddress, unsigned char enableCAF, unsigned char enableNBC ) { int Index; unsigned int Address; // Check parameters ASSERT(RX_BUFFERS * EMAC_RX_UNITSIZE > EMAC_FRAME_LENTGH_MAX, "E: RX buffers too small\n\r"); trace_LOG(trace_DEBUG, "EMAC_Init\n\r"); // Power ON AT91C_BASE_PMC->PMC_PCER = 1 << id; // Disable TX & RX and more AT91C_BASE_EMAC->EMAC_NCR = 0; // disable AT91C_BASE_EMAC->EMAC_IDR = ~0; rxTd.idx = 0; CIRC_CLEAR(&txTd); // Setup the RX descriptors. for(Index = 0; Index < RX_BUFFERS; Index++) { Address = (unsigned int)(&(pRxBuffer[Index * EMAC_RX_UNITSIZE])); // Remove EMAC_RX_OWNERSHIP_BIT and EMAC_RX_WRAP_BIT rxTd.td[Index].addr = Address & EMAC_ADDRESS_MASK; rxTd.td[Index].status = 0; } rxTd.td[RX_BUFFERS - 1].addr |= EMAC_RX_WRAP_BIT; // Setup the TX descriptors. for(Index = 0; Index < TX_BUFFERS; Index++) { Address = (unsigned int)(&(pTxBuffer[Index * EMAC_TX_UNITSIZE])); txTd.td[Index].addr = Address; txTd.td[Index].status = EMAC_TX_USED_BIT; } txTd.td[TX_BUFFERS - 1].status = EMAC_TX_USED_BIT | EMAC_TX_WRAP_BIT; // Set the MAC address if( pMacAddress != (unsigned char *)0 ) { AT91C_BASE_EMAC->EMAC_SA1L = ( ((unsigned int)pMacAddress[3] << 24) | ((unsigned int)pMacAddress[2] << 16) | ((unsigned int)pMacAddress[1] << 8 ) | pMacAddress[0] ); AT91C_BASE_EMAC->EMAC_SA1H = ( ((unsigned int)pMacAddress[5] << 8 ) | pMacAddress[4] ); } // Now setup the descriptors // Receive Buffer Queue Pointer Register AT91C_BASE_EMAC->EMAC_RBQP = (unsigned int) (rxTd.td); // Transmit Buffer Queue Pointer Register AT91C_BASE_EMAC->EMAC_TBQP = (unsigned int) (txTd.td); AT91C_BASE_EMAC->EMAC_NCR = AT91C_EMAC_CLRSTAT; // Clear all status bits in the receive status register. AT91C_BASE_EMAC->EMAC_RSR = (AT91C_EMAC_OVR | AT91C_EMAC_REC | AT91C_EMAC_BNA); // Clear all status bits in the transmit status register AT91C_BASE_EMAC->EMAC_TSR = ( AT91C_EMAC_UBR | AT91C_EMAC_COL | AT91C_EMAC_RLES | AT91C_EMAC_BEX | AT91C_EMAC_COMP | AT91C_EMAC_UND ); // Clear interrupts AT91C_BASE_EMAC->EMAC_ISR; // Enable the copy of data into the buffers // ignore broadcasts, and don't copy FCS. AT91C_BASE_EMAC->EMAC_NCFGR |= (AT91C_EMAC_DRFCS | AT91C_EMAC_PAE); if( enableCAF == EMAC_CAF_ENABLE ) { AT91C_BASE_EMAC->EMAC_NCFGR |= AT91C_EMAC_CAF; } if( enableNBC == EMAC_NBC_ENABLE ) { AT91C_BASE_EMAC->EMAC_NCFGR |= AT91C_EMAC_NBC; } // Enable Rx and Tx, plus the stats register. AT91C_BASE_EMAC->EMAC_NCR |= (AT91C_EMAC_TE | AT91C_EMAC_RE | AT91C_EMAC_WESTAT); // Setup the interrupts for TX (and errors) AT91C_BASE_EMAC->EMAC_IER = AT91C_EMAC_RXUBR | AT91C_EMAC_TUNDR | AT91C_EMAC_RLEX | AT91C_EMAC_TXERR | AT91C_EMAC_TCOMP | AT91C_EMAC_ROVR | AT91C_EMAC_HRESP; }
//------------------------------------------------------------------------------ // Performs the selected test on the USB device (high-speed only). // \param test Test selector value. //------------------------------------------------------------------------------ static void USBDDriver_Test(unsigned char test) { trace_LOG(trace_DEBUG, "UDPHS_Test\n\r"); // the lower byte of wIndex must be zero // the most significant byte of wIndex is used to specify the specific test mode switch (test) { case USBFeatureRequest_TESTPACKET: //Test mode Test_Packet: //Upon command, a port must repetitively transmit the following test packet until //the exit action is taken. This enables the testing of rise and fall times, eye //patterns, jitter, and any other dynamic waveform specifications. //The test packet is made up by concatenating the following strings. //(Note: For J/K NRZI data, and for NRZ data, the bit on the left is the first one //transmitted. “S” indicates that a bit stuff occurs, which inserts an “extra” NRZI data bit. //“* N” is used to indicate N occurrences of a string of bits or symbols.) //A port in Test_Packet mode must send this packet repetitively. The inter-packet timing //must be no less than the minimum allowable inter-packet gap as defined in Section 7.1.18 and //no greater than 125 us. // Send ZLP USBD_Test(USBFeatureRequest_TESTSENDZLP); // Tst PACKET USBD_Test(USBFeatureRequest_TESTPACKET); while (1); break; case USBFeatureRequest_TESTJ: //Test mode Test_J: //Upon command, a port’s transceiver must enter the high-speed J state and remain in that //state until the exit action is taken. This enables the testing of the high output drive //level on the D+ line. // Send ZLP USBD_Test(USBFeatureRequest_TESTSENDZLP); // Tst J USBD_Test(USBFeatureRequest_TESTJ); while (1); break; case USBFeatureRequest_TESTK: //Test mode Test_K: //Upon command, a port’s transceiver must enter the high-speed K state and remain in //that state until the exit action is taken. This enables the testing of the high output drive //level on the D- line. // Send a ZLP USBD_Test(USBFeatureRequest_TESTSENDZLP); USBD_Test(USBFeatureRequest_TESTK); while (1); break; case USBFeatureRequest_TESTSE0NAK: //Test mode Test_SE0_NAK: //Upon command, a port’s transceiver must enter the high-speed receive mode //and remain in that mode until the exit action is taken. This enables the testing //of output impedance, low level output voltage, and loading characteristics. //In addition, while in this mode, upstream facing ports (and only upstream facing ports) //must respond to any IN token packet with a NAK handshake (only if the packet CRC is //determined to be correct) within the normal allowed device response time. This enables testing of //the device squelch level circuitry and, additionally, provides a general purpose stimulus/response //test for basic functional testing. USBD_Test(USBFeatureRequest_TESTSE0NAK); // Send a ZLP USBD_Test(USBFeatureRequest_TESTSENDZLP); while (1); break; default: USBD_Stall( 0 ); break; } // The exit action is to power cycle the device. // The device must be disconnected from the host }
//------------------------------------------------------------------------------ /// Processes pending events on the given MCI driver. /// \param pMci Pointer to a MCI driver instance. //------------------------------------------------------------------------------ void MCI_Handler(Mci *pMci) { AT91S_MCI *pMciHw = pMci->pMciHw; MciCmd *pCommand = pMci->pCommand; unsigned int status; unsigned char i; #if defined(at91rm9200) unsigned int mciCr, mciSdcr, mciMr, mciDtor; #endif SANITY_CHECK(pMci); SANITY_CHECK(pMciHw); SANITY_CHECK(pCommand); // Read the status register status = READ_MCI(pMciHw, MCI_SR) & READ_MCI(pMciHw, MCI_IMR); // trace_LOG(trace_DEBUG, "status %x\n\r", status); // Check if an error has occured if ((status & STATUS_ERRORS) != 0) { // Check error code if ((status & STATUS_ERRORS) == AT91C_MCI_RTOE) { pCommand->status = MCI_STATUS_NORESPONSE; } // if the command is SEND_OP_COND the CRC error flag is always present // (cf : R3 response) else if (((status & STATUS_ERRORS) != AT91C_MCI_RCRCE) || ((pCommand->cmd != SDCARD_APP_OP_COND_CMD) && (pCommand->cmd != MMC_SEND_OP_COND_CMD))) { pCommand->status = MCI_STATUS_ERROR; } } // Check if a transfer has been completed if (((status & AT91C_MCI_CMDRDY) != 0) || ((status & AT91C_MCI_ENDRX) != 0) || ((status & AT91C_MCI_RXBUFF) != 0) || ((status & AT91C_MCI_ENDTX) != 0) || ((status & AT91C_MCI_BLKE) != 0) || ((status & AT91C_MCI_RTOE) != 0)) { if (((status & AT91C_MCI_ENDRX) != 0) || ((status & AT91C_MCI_RXBUFF) != 0) || ((status & AT91C_MCI_ENDTX) != 0)) { MCI_Enable(pMci, DISABLE); } /// On AT91RM9200-EK, if stop transmission, software reset MCI. #if defined(at91rm9200) if ((pCommand->cmd & AT91C_MCI_TRCMD_STOP) != 0) { mciMr = READ_MCI(pMciHw, MCI_MR); mciSdcr = READ_MCI(pMciHw, MCI_SDCR); mciDtor = READ_MCI(pMciHw, MCI_DTOR); WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_SWRST); // trace_LOG(trace_DEBUG, "reset MCI\n\r"); WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_MCIDIS | AT91C_MCI_PWSDIS); WRITE_MCI(pMciHw, MCI_MR, mciMr); WRITE_MCI(pMciHw, MCI_SDCR, mciSdcr); WRITE_MCI(pMciHw, MCI_DTOR, mciDtor); } #endif // If no error occured, the transfer is successful if (pCommand->status == MCI_STATUS_PENDING) { pCommand->status = 0; } #if 0 if ((status & AT91C_MCI_CMDRDY) != 0) trace_LOG(trace_DEBUG, "."); if ((status & AT91C_MCI_ENDRX) != 0) trace_LOG(trace_DEBUG, "<"); if ((status & AT91C_MCI_ENDTX) != 0) trace_LOG(trace_DEBUG, "-"); if ((status & AT91C_MCI_BLKE) != 0) trace_LOG(trace_DEBUG, ">"); trace_LOG(trace_DEBUG, "\n\r"); #endif // Store the card response in the provided buffer if (pCommand->pResp) { for (i=0; i < pCommand->resSize; i++) { pCommand->pResp[i] = READ_MCI(pMciHw, MCI_RSPR[0]); } } // Disable interrupts WRITE_MCI(pMciHw, MCI_IDR, READ_MCI(pMciHw, MCI_IMR)); // Release the semaphore pMci->semaphore++; // Invoke the callback associated with the current command (if any) if (pCommand->callback) { (pCommand->callback)(pCommand->status, pCommand); } } }
//------------------------------------------------------------------------------ /// Sends the requested USB descriptor to the host if available, or STALLs the /// request. /// \param pDriver Pointer to a USBDDriver instance. /// \param type Type of the requested descriptor /// \param index Index of the requested descriptor. /// \param length Maximum number of bytes to return. //------------------------------------------------------------------------------ static void GetDescriptor( const USBDDriver *pDriver, unsigned char type, unsigned char index, unsigned int length) { const USBDeviceDescriptor *pDevice; const USBConfigurationDescriptor *pConfiguration; const USBDeviceQualifierDescriptor *pQualifier; const USBConfigurationDescriptor *pOtherSpeed; const USBGenericDescriptor **pStrings = (const USBGenericDescriptor **) pDriver->pDescriptors->pStrings; unsigned char numStrings = pDriver->pDescriptors->numStrings; const USBGenericDescriptor *pString; // Use different set of descriptors depending on device speed if (USBD_IsHighSpeed()) { trace_LOG(trace_DEBUG, "HS "); pDevice = pDriver->pDescriptors->pHsDevice; pConfiguration = pDriver->pDescriptors->pHsConfiguration; pQualifier = pDriver->pDescriptors->pHsQualifier; pOtherSpeed = pDriver->pDescriptors->pHsOtherSpeed; } else { trace_LOG(trace_DEBUG, "FS "); pDevice = pDriver->pDescriptors->pFsDevice; pConfiguration = pDriver->pDescriptors->pFsConfiguration; pQualifier = pDriver->pDescriptors->pFsQualifier; pOtherSpeed = pDriver->pDescriptors->pFsOtherSpeed; } // Check the descriptor type switch (type) { case USBGenericDescriptor_DEVICE: trace_LOG(trace_INFO, "Dev "); // Adjust length and send descriptor if (length > USBGenericDescriptor_GetLength((USBGenericDescriptor *) pDevice)) { length = USBGenericDescriptor_GetLength((USBGenericDescriptor *) pDevice); } USBD_Write(0, pDevice, length, 0, 0); break; case USBGenericDescriptor_CONFIGURATION: trace_LOG(trace_INFO, "Cfg "); // Adjust length and send descriptor if (length > USBConfigurationDescriptor_GetTotalLength(pConfiguration)) { length = USBConfigurationDescriptor_GetTotalLength(pConfiguration); } USBD_Write(0, pConfiguration, length, 0, 0); break; case USBGenericDescriptor_DEVICEQUALIFIER: trace_LOG(trace_INFO, "Qua "); // Check if descriptor exists if (!pQualifier) { USBD_Stall(0); } else { // Adjust length and send descriptor if (length > USBGenericDescriptor_GetLength((USBGenericDescriptor *) pQualifier)) { length = USBGenericDescriptor_GetLength((USBGenericDescriptor *) pQualifier); } USBD_Write(0, pQualifier, length, 0, 0); } break; case USBGenericDescriptor_OTHERSPEEDCONFIGURATION: trace_LOG(trace_INFO, "OSC "); // Check if descriptor exists if (!pOtherSpeed) { USBD_Stall(0); } else { // Adjust length and send descriptor if (length > USBConfigurationDescriptor_GetTotalLength(pOtherSpeed)) { length = USBConfigurationDescriptor_GetTotalLength(pOtherSpeed); } USBD_Write(0, pOtherSpeed, length, 0, 0); } break; case USBGenericDescriptor_STRING: trace_LOG(trace_INFO, "Str%d ", index); // Check if descriptor exists if (index > numStrings) { USBD_Stall(0); } else { pString = pStrings[index]; // Adjust length and send descriptor if (length > USBGenericDescriptor_GetLength(pString)) { length = USBGenericDescriptor_GetLength(pString); } USBD_Write(0, pString, length, 0, 0); } break; default: trace_LOG(trace_WARNING, "USBDDriver_GetDescriptor: Unknown descriptor type (%d)\n\r", type); USBD_Stall(0); } }