#include "usb_lib.h" // Private variables DEVICE_INFO Device_Info; // Device information of current device // Public variables // Points to the DEVICE_INFO structure of current device // The purpose of this register is to speed up the execution DEVICE_INFO *pInformation; /* Points to the DEVICE_PROP structure of current device */ /* The purpose of this register is to speed up the execution */ DEVICE_PROP* pProperty; void (*pEpInt_IN[ 7])(void); // Handles IN interrupts void (*pEpInt_OUT[7])(void); // Handles OUT interrupts uint8_t EPindex; // The number of current endpoint, it will be used to specify an endpoint // Temporary save the state of Rx & Tx status. // Whenever the Rx or Tx state is changed, its value is saved // in this variable first and will be set to the EPRB or EPRA // at the end of interrupt process uint16_t SaveState; uint16_t wInterrupt_Mask; // Contains interrupt mask USER_STANDARD_REQUESTS *pUser_Standard_Requests; // __IO uint16_t SaveRState; // cells saving status during interrupt servicing __IO uint16_t SaveTState; // cells saving status during interrupt servicing // Functions /******************************************************************************* * Function Name : USB_Init * Description : USB system initialization * Input : None. * Output : None. * Return : None. *******************************************************************************/ void USB_Init(void) { pInformation = &Device_Info; pInformation->ControlState = 2; pProperty = &Device_Property; pUser_Standard_Requests = &User_Standard_Requests; // Initialize devices one by one pProperty->Init(); } /******************************************************************************* * Function Name : CTR_LP. * Description : Low priority Endpoint Correct Transfer interrupt's service * routine. * Input : None. * Output : None. * Return : None. *******************************************************************************/ void CTR_LP(void) { __IO uint16_t wEPVal = 0; // stay in loop while pending interrupts while ((wIstr = USB->ISTR) & ISTR_CTR) { // extract highest priority endpoint number EPindex = (uint8_t)(wIstr & ISTR_EP_ID); if (EPindex == 0) { // Decode and service control endpoint interrupt // calling related service routine // (Setup0_Process, In0_Process, Out0_Process) // save RX & TX status and set both to NAK SaveRState = _GetENDPOINT(ENDP0); SaveTState = SaveRState & EPTX_STAT; SaveRState &= EPRX_STAT; SetEPRxTxStatus(ENDP0,EP_RX_NAK,EP_TX_NAK); // DIR bit = origin of the interrupt if ((wIstr & ISTR_DIR) == 0) { // DIR = 0 => IN int // DIR = 0 implies that (EP_CTR_TX = 1) always ClearEP_CTR_TX(ENDP0); In0_Process(); // before terminate set Tx & Rx status SetEPRxTxStatus(ENDP0,SaveRState,SaveTState); return; } else { // DIR = 1 & CTR_RX => SETUP or OUT int // DIR = 1 & (CTR_TX | CTR_RX) => 2 int pending wEPVal = _GetENDPOINT(ENDP0); if ((wEPVal &EP_SETUP) != 0) { ClearEP_CTR_RX(ENDP0); // SETUP bit kept frozen while CTR_RX = 1 Setup0_Process(); // before terminate set Tx & Rx status SetEPRxTxStatus(ENDP0,SaveRState,SaveTState); return; } else if ((wEPVal & EP_CTR_RX) != 0) { ClearEP_CTR_RX(ENDP0); Out0_Process(); // before terminate set Tx & Rx status SetEPRxTxStatus(ENDP0,SaveRState,SaveTState); return; } } } else { // Decode and service non control endpoints interrupt // process related endpoint register wEPVal = _GetENDPOINT(EPindex); if ((wEPVal & EP_CTR_RX) != 0) { // clear int flag ClearEP_CTR_RX(EPindex); // call OUT service function (*pEpInt_OUT[EPindex-1])(); } if ((wEPVal & EP_CTR_TX) != 0) { // clear int flag ClearEP_CTR_TX(EPindex); // call IN service function (*pEpInt_IN[EPindex-1])(); } } } } /******************************************************************************* * Function Name : CTR_HP. * Description : High Priority Endpoint Correct Transfer interrupt's service * routine. * Input : None. * Output : None. * Return : None. *******************************************************************************/ void CTR_HP(void) { uint32_t wEPVal = 0; while (((wIstr = USB->ISTR) & ISTR_CTR) != 0) { USB->ISTR = (uint16_t)CLR_CTR; // clear CTR flag // extract highest priority endpoint number EPindex = (uint8_t)(wIstr & ISTR_EP_ID); // process related endpoint register wEPVal = _GetENDPOINT(EPindex); if ((wEPVal & EP_CTR_RX) != 0) { // clear int flag ClearEP_CTR_RX(EPindex); // call OUT service function (*pEpInt_OUT[EPindex-1])(); } else if ((wEPVal & EP_CTR_TX) != 0) { // clear int flag ClearEP_CTR_TX(EPindex); // call IN service function (*pEpInt_IN[EPindex-1])(); } } } /******************************************************************************* * Function Name : UserToPMABufferCopy * Description : Copy a buffer from user memory area to packet memory area (PMA) * Input : - pbUsrBuf: pointer to user memory area. * - wPMABufAddr: address into PMA. * - wNBytes: no. of bytes to be copied. * Output : None. * Return : None . *******************************************************************************/ void UserToPMABufferCopy(uint8_t *pbUsrBuf, uint16_t wPMABufAddr, uint16_t wNBytes) { uint32_t n = (wNBytes + 1) >> 1; /* n = (wNBytes + 1) / 2 */ uint32_t i,temp1,temp2; uint16_t *pdwVal; pdwVal = (uint16_t *)((wPMABufAddr << 1) + USB_PMAADDR); for (i = n; i != 0; i--) { temp1 = (uint16_t)*pbUsrBuf; pbUsrBuf++; temp2 = temp1 | (uint16_t)*pbUsrBuf << 8; *pdwVal++ = temp2; pdwVal++; pbUsrBuf++; } } /******************************************************************************* * Function Name : PMAToUserBufferCopy * Description : Copy a buffer from user memory area to packet memory area (PMA) * Input : - pbUsrBuf = pointer to user memory area. * - wPMABufAddr = address into PMA. * - wNBytes = no. of bytes to be copied. * Output : None. * Return : None. *******************************************************************************/ void PMAToUserBufferCopy(uint8_t *pbUsrBuf, uint16_t wPMABufAddr, uint16_t wNBytes) { uint32_t n = (wNBytes + 1) >> 1; uint32_t i; uint32_t *pdwVal; pdwVal = (uint32_t *)((wPMABufAddr << 1) + USB_PMAADDR); for (i = n; i != 0; i--) { *(uint16_t*)pbUsrBuf++ = *pdwVal++; pbUsrBuf++; } } /******************************************************************************* * Function Name : USB_SIL_Init * Description : Initialize the USB Device IP and the Endpoint 0. * Input : None. * Output : None. * Return : Status. *******************************************************************************/ uint32_t USB_SIL_Init(void) { // USB interrupts initialization // clear pending interrupts USB->ISTR = 0; wInterrupt_Mask = IMR_MSK; // set interrupts mask USB->CNTR = wInterrupt_Mask; return 0; } /******************************************************************************* * Function Name : USB_SIL_Write * Description : Write a buffer of data to a selected endpoint. * Input : - bEpAddr: The address of the non control endpoint. * - pBufferPointer: The pointer to the buffer of data to be written * to the endpoint. * - wBufferSize: Number of data to be written (in bytes). * Output : None. * Return : Status. *******************************************************************************/ uint32_t USB_SIL_Write(uint8_t bEpAddr, uint8_t* pBufferPointer, uint32_t wBufferSize) { uint8_t EP_addr = bEpAddr & 0x7F; if ((_GetENDPOINT(EP_addr) & (EP_TYPE_MASK | EP_KIND)) & (EP_BULK | EP_KIND)) { // Bulk endpoint and double buffer enabled // Write data to the selected endpoint and set buffer length if (_GetENDPOINT(EP_addr) & EP_DTOG_RX) { UserToPMABufferCopy(pBufferPointer,GetEPDblBuf0Addr(EP_addr),wBufferSize); SetEPDblBuf0Count(EP_addr,EP_DBUF_IN,wBufferSize); } else { UserToPMABufferCopy(pBufferPointer,GetEPDblBuf1Addr(EP_addr),wBufferSize); SetEPDblBuf1Count(EP_addr,EP_DBUF_IN,wBufferSize); } ToggleDTOG_RX(EP_addr); } else { // Use the memory interface function to write to the selected endpoint UserToPMABufferCopy(pBufferPointer,GetEPTxAddr(EP_addr),wBufferSize); // Update the data length in the control register SetEPTxCount(EP_addr,wBufferSize); } return 0; } /******************************************************************************* * Function Name : USB_SIL_Read * Description : Write a buffer of data to a selected endpoint. * Input : - bEpAddr: The address of the non control endpoint. * - pBufferPointer: The pointer to which will be saved the * received data buffer. * Output : None. * Return : Number of received data (in Bytes). *******************************************************************************/ uint32_t USB_SIL_Read(uint8_t bEpAddr, uint8_t* pBufferPointer) { uint8_t EP_addr = bEpAddr & 0x7F; uint32_t DataLength; if ((_GetENDPOINT(EP_addr) & (EP_TYPE_MASK | EP_KIND)) & (EP_BULK | EP_KIND)) { // Bulk endpoint and double buffer enabled // Get the number of received data on the selected endpoint // and read this data to user buffer if (_GetENDPOINT(EP_addr) & EP_DTOG_TX) { DataLength = GetEPDblBuf0Count(EP_addr); PMAToUserBufferCopy(pBufferPointer,GetEPDblBuf0Addr(EP_addr),DataLength); } else { DataLength = GetEPDblBuf1Count(EP_addr); PMAToUserBufferCopy(pBufferPointer,GetEPDblBuf1Addr(EP_addr),DataLength); } ToggleDTOG_TX(EP_addr); } else { // Get the number of received data on the selected Endpoint DataLength = GetEPRxCount(EP_addr); // Use the memory interface function to write to the selected endpoint PMAToUserBufferCopy(pBufferPointer,GetEPRxAddr(EP_addr),DataLength); } // Return the number of received data return DataLength; }