| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781 | /******************************************************************************** File Name: USBFS_drv.c* Version 2.60** Description:*  Endpoint 0 Driver for the USBFS Component.** Note:********************************************************************************** Copyright 2008-2013, Cypress Semiconductor Corporation.  All rights reserved.* You may use this file only in accordance with the license, terms, conditions,* disclaimers, and limitations in the end user license agreement accompanying* the software package with which this file was provided.*******************************************************************************/#include "USBFS.h"#include "USBFS_pvt.h"/**************************************** Global data allocation***************************************/volatile T_USBFS_EP_CTL_BLOCK USBFS_EP[USBFS_MAX_EP];volatile uint8 USBFS_configuration;volatile uint8 USBFS_interfaceNumber;volatile uint8 USBFS_configurationChanged;volatile uint8 USBFS_deviceAddress;volatile uint8 USBFS_deviceStatus;volatile uint8 USBFS_interfaceSetting[USBFS_MAX_INTERFACES_NUMBER];volatile uint8 USBFS_interfaceSetting_last[USBFS_MAX_INTERFACES_NUMBER];volatile uint8 USBFS_interfaceStatus[USBFS_MAX_INTERFACES_NUMBER];volatile uint8 USBFS_device;const uint8 CYCODE *USBFS_interfaceClass;/**************************************** Local data allocation***************************************/volatile uint8 USBFS_ep0Toggle;volatile uint8 USBFS_lastPacketSize;volatile uint8 USBFS_transferState;volatile T_USBFS_TD USBFS_currentTD;volatile uint8 USBFS_ep0Mode;volatile uint8 USBFS_ep0Count;volatile uint16 USBFS_transferByteCount;/******************************************************************************** Function Name: USBFS_ep_0_Interrupt********************************************************************************** Summary:*  This Interrupt Service Routine handles Endpoint 0 (Control Pipe) traffic.*  It dispatches setup requests and handles the data and status stages.** Parameters:*  None.** Return:*  None.********************************************************************************/CY_ISR(USBFS_EP_0_ISR){    uint8 bRegTemp;    uint8 modifyReg;    bRegTemp = CY_GET_REG8(USBFS_EP0_CR_PTR);    if ((bRegTemp & USBFS_MODE_ACKD) != 0u)    {        modifyReg = 1u;        if ((bRegTemp & USBFS_MODE_SETUP_RCVD) != 0u)        {            if((bRegTemp & USBFS_MODE_MASK) != USBFS_MODE_NAK_IN_OUT)            {                modifyReg = 0u;                                     /* When mode not NAK_IN_OUT => invalid setup */            }            else            {                USBFS_HandleSetup();                if((USBFS_ep0Mode & USBFS_MODE_SETUP_RCVD) != 0u)                {                    modifyReg = 0u;                         /* if SETUP bit set -> exit without modifying the mode */                }            }        }        else if ((bRegTemp & USBFS_MODE_IN_RCVD) != 0u)        {            USBFS_HandleIN();        }        else if ((bRegTemp & USBFS_MODE_OUT_RCVD) != 0u)        {            USBFS_HandleOUT();        }        else        {            modifyReg = 0u;        }        if(modifyReg != 0u)        {            bRegTemp = CY_GET_REG8(USBFS_EP0_CR_PTR);    /* unlock registers */            if((bRegTemp & USBFS_MODE_SETUP_RCVD) == 0u)  /* Check if SETUP bit is not set, otherwise exit */            {                /* Update the count register */                bRegTemp = USBFS_ep0Toggle | USBFS_ep0Count;                CY_SET_REG8(USBFS_EP0_CNT_PTR, bRegTemp);                if(bRegTemp == CY_GET_REG8(USBFS_EP0_CNT_PTR))   /* continue if writing was successful */                {                    do                    {                        modifyReg = USBFS_ep0Mode;       /* Init temporary variable */                        /* Unlock registers */                        bRegTemp = CY_GET_REG8(USBFS_EP0_CR_PTR) & USBFS_MODE_SETUP_RCVD;                        if(bRegTemp == 0u)                          /* Check if SETUP bit is not set */                        {                            /* Set the Mode Register  */                            CY_SET_REG8(USBFS_EP0_CR_PTR, USBFS_ep0Mode);                            /* Writing check */                            modifyReg = CY_GET_REG8(USBFS_EP0_CR_PTR) & USBFS_MODE_MASK;                        }                    }while(modifyReg != USBFS_ep0Mode);  /* Repeat if writing was not successful */                }            }        }    }}/******************************************************************************** Function Name: USBFS_HandleSetup********************************************************************************** Summary:*  This Routine dispatches requests for the four USB request types** Parameters:*  None.** Return:*  None.** Reentrant:*  No.********************************************************************************/void USBFS_HandleSetup(void) {    uint8 requestHandled;    requestHandled = CY_GET_REG8(USBFS_EP0_CR_PTR);      /* unlock registers */    CY_SET_REG8(USBFS_EP0_CR_PTR, requestHandled);       /* clear setup bit */    requestHandled = CY_GET_REG8(USBFS_EP0_CR_PTR);      /* reread register */    if((requestHandled & USBFS_MODE_SETUP_RCVD) != 0u)    {        USBFS_ep0Mode = requestHandled;        /* if SETUP bit set -> exit without modifying the mode */    }    else    {        /* In case the previous transfer did not complete, close it out */        USBFS_UpdateStatusBlock(USBFS_XFER_PREMATURE);        switch (CY_GET_REG8(USBFS_bmRequestType) & USBFS_RQST_TYPE_MASK)        {            case USBFS_RQST_TYPE_STD:                requestHandled = USBFS_HandleStandardRqst();                break;            case USBFS_RQST_TYPE_CLS:                requestHandled = USBFS_DispatchClassRqst();                break;            case USBFS_RQST_TYPE_VND:                requestHandled = USBFS_HandleVendorRqst();                break;            default:                requestHandled = USBFS_FALSE;                break;        }        if (requestHandled == USBFS_FALSE)        {            USBFS_ep0Mode = USBFS_MODE_STALL_IN_OUT;        }    }}/******************************************************************************** Function Name: USBFS_HandleIN********************************************************************************** Summary:*  This routine handles EP0 IN transfers.** Parameters:*  None.** Return:*  None.** Reentrant:*  No.********************************************************************************/void USBFS_HandleIN(void) {    switch (USBFS_transferState)    {        case USBFS_TRANS_STATE_IDLE:            break;        case USBFS_TRANS_STATE_CONTROL_READ:            USBFS_ControlReadDataStage();            break;        case USBFS_TRANS_STATE_CONTROL_WRITE:            USBFS_ControlWriteStatusStage();            break;        case USBFS_TRANS_STATE_NO_DATA_CONTROL:            USBFS_NoDataControlStatusStage();            break;        default:    /* there are no more states */            break;    }}/******************************************************************************** Function Name: USBFS_HandleOUT********************************************************************************** Summary:*  This routine handles EP0 OUT transfers.** Parameters:*  None.** Return:*  None.** Reentrant:*  No.********************************************************************************/void USBFS_HandleOUT(void) {    switch (USBFS_transferState)    {        case USBFS_TRANS_STATE_IDLE:            break;        case USBFS_TRANS_STATE_CONTROL_READ:            USBFS_ControlReadStatusStage();            break;        case USBFS_TRANS_STATE_CONTROL_WRITE:            USBFS_ControlWriteDataStage();            break;        case USBFS_TRANS_STATE_NO_DATA_CONTROL:            /* Update the completion block */            USBFS_UpdateStatusBlock(USBFS_XFER_ERROR);            /* We expect no more data, so stall INs and OUTs */            USBFS_ep0Mode = USBFS_MODE_STALL_IN_OUT;            break;        default:    /* There are no more states */            break;    }}/******************************************************************************** Function Name: USBFS_LoadEP0********************************************************************************** Summary:*  This routine loads the EP0 data registers for OUT transfers.  It uses the*  currentTD (previously initialized by the _InitControlWrite function and*  updated for each OUT transfer, and the bLastPacketSize) to determine how*  many uint8s to transfer on the current OUT.**  If the number of uint8s remaining is zero and the last transfer was full,*  we need to send a zero length packet.  Otherwise we send the minimum*  of the control endpoint size (8) or remaining number of uint8s for the*  transaction.** Parameters:*  None.** Return:*  None.** Global variables:*  USBFS_transferByteCount - Update the transfer byte count from the*     last transaction.*  USBFS_ep0Count - counts the data loaded to the SIE memory in*     current packet.*  USBFS_lastPacketSize - remembers the USBFS_ep0Count value for the*     next packet.*  USBFS_transferByteCount - sum of the previous bytes transferred*     on previous packets(sum of USBFS_lastPacketSize)*  USBFS_ep0Toggle - inverted*  USBFS_ep0Mode  - prepare for mode register content.*  USBFS_transferState - set to TRANS_STATE_CONTROL_READ** Reentrant:*  No.********************************************************************************/void USBFS_LoadEP0(void) {    uint8 ep0Count = 0u;    /* Update the transfer byte count from the last transaction */    USBFS_transferByteCount += USBFS_lastPacketSize;    /* Now load the next transaction */    while ((USBFS_currentTD.count > 0u) && (ep0Count < 8u))    {        CY_SET_REG8((reg8 *)(USBFS_EP0_DR0_IND + ep0Count), *USBFS_currentTD.pData);        USBFS_currentTD.pData = &USBFS_currentTD.pData[1u];        ep0Count++;        USBFS_currentTD.count--;    }    /* Support zero-length packet*/    if( (USBFS_lastPacketSize == 8u) || (ep0Count > 0u) )    {        /* Update the data toggle */        USBFS_ep0Toggle ^= USBFS_EP0_CNT_DATA_TOGGLE;        /* Set the Mode Register  */        USBFS_ep0Mode = USBFS_MODE_ACK_IN_STATUS_OUT;        /* Update the state (or stay the same) */        USBFS_transferState = USBFS_TRANS_STATE_CONTROL_READ;    }    else    {        /* Expect Status Stage Out */        USBFS_ep0Mode = USBFS_MODE_STATUS_OUT_ONLY;        /* Update the state (or stay the same) */        USBFS_transferState = USBFS_TRANS_STATE_CONTROL_READ;    }    /* Save the packet size for next time */    USBFS_lastPacketSize = ep0Count;    USBFS_ep0Count = ep0Count;}/******************************************************************************** Function Name: USBFS_InitControlRead********************************************************************************** Summary:*  Initialize a control read transaction, usable to send data to the host.*  The following global variables should be initialized before this function*  called. To send zero length packet use InitZeroLengthControlTransfer*  function.** Parameters:*  None.** Return:*  requestHandled state.** Global variables:*  USBFS_currentTD.count - counts of data to be sent.*  USBFS_currentTD.pData - data pointer.** Reentrant:*  No.********************************************************************************/uint8 USBFS_InitControlRead(void) {    uint16 xferCount;    if(USBFS_currentTD.count == 0u)    {        (void) USBFS_InitZeroLengthControlTransfer();    }    else    {        /* Set up the state machine */        USBFS_transferState = USBFS_TRANS_STATE_CONTROL_READ;        /* Set the toggle, it gets updated in LoadEP */        USBFS_ep0Toggle = 0u;        /* Initialize the Status Block */        USBFS_InitializeStatusBlock();        xferCount = (((uint16)CY_GET_REG8(USBFS_lengthHi) << 8u) | (CY_GET_REG8(USBFS_lengthLo)));        if (USBFS_currentTD.count > xferCount)        {            USBFS_currentTD.count = xferCount;        }        USBFS_LoadEP0();    }    return(USBFS_TRUE);}/******************************************************************************** Function Name: USBFS_InitZeroLengthControlTransfer********************************************************************************** Summary:*  Initialize a zero length data IN transfer.** Parameters:*  None.** Return:*  requestHandled state.** Global variables:*  USBFS_ep0Toggle - set to EP0_CNT_DATA_TOGGLE*  USBFS_ep0Mode  - prepare for mode register content.*  USBFS_transferState - set to TRANS_STATE_CONTROL_READ*  USBFS_ep0Count - cleared, means the zero-length packet.*  USBFS_lastPacketSize - cleared.** Reentrant:*  No.********************************************************************************/uint8 USBFS_InitZeroLengthControlTransfer(void)                                                {    /* Update the state */    USBFS_transferState = USBFS_TRANS_STATE_CONTROL_READ;    /* Set the data toggle */    USBFS_ep0Toggle = USBFS_EP0_CNT_DATA_TOGGLE;    /* Set the Mode Register  */    USBFS_ep0Mode = USBFS_MODE_ACK_IN_STATUS_OUT;    /* Save the packet size for next time */    USBFS_lastPacketSize = 0u;    USBFS_ep0Count = 0u;    return(USBFS_TRUE);}/******************************************************************************** Function Name: USBFS_ControlReadDataStage********************************************************************************** Summary:*  Handle the Data Stage of a control read transfer.** Parameters:*  None.** Return:*  None.** Reentrant:*  No.********************************************************************************/void USBFS_ControlReadDataStage(void) {    USBFS_LoadEP0();}/******************************************************************************** Function Name: USBFS_ControlReadStatusStage********************************************************************************** Summary:*  Handle the Status Stage of a control read transfer.** Parameters:*  None.** Return:*  None.** Global variables:*  USBFS_USBFS_transferByteCount - updated with last packet size.*  USBFS_transferState - set to TRANS_STATE_IDLE.*  USBFS_ep0Mode  - set to MODE_STALL_IN_OUT.** Reentrant:*  No.********************************************************************************/void USBFS_ControlReadStatusStage(void) {    /* Update the transfer byte count */    USBFS_transferByteCount += USBFS_lastPacketSize;    /* Go Idle */    USBFS_transferState = USBFS_TRANS_STATE_IDLE;    /* Update the completion block */    USBFS_UpdateStatusBlock(USBFS_XFER_STATUS_ACK);    /* We expect no more data, so stall INs and OUTs */    USBFS_ep0Mode =  USBFS_MODE_STALL_IN_OUT;}/******************************************************************************** Function Name: USBFS_InitControlWrite********************************************************************************** Summary:*  Initialize a control write transaction** Parameters:*  None.** Return:*  requestHandled state.** Global variables:*  USBFS_USBFS_transferState - set to TRANS_STATE_CONTROL_WRITE*  USBFS_ep0Toggle - set to EP0_CNT_DATA_TOGGLE*  USBFS_ep0Mode  - set to MODE_ACK_OUT_STATUS_IN** Reentrant:*  No.********************************************************************************/uint8 USBFS_InitControlWrite(void) {    uint16 xferCount;    /* Set up the state machine */    USBFS_transferState = USBFS_TRANS_STATE_CONTROL_WRITE;    /* This might not be necessary */    USBFS_ep0Toggle = USBFS_EP0_CNT_DATA_TOGGLE;    /* Initialize the Status Block */    USBFS_InitializeStatusBlock();    xferCount = (((uint16)CY_GET_REG8(USBFS_lengthHi) << 8u) | (CY_GET_REG8(USBFS_lengthLo)));    if (USBFS_currentTD.count > xferCount)    {        USBFS_currentTD.count = xferCount;    }    /* Expect Data or Status Stage */    USBFS_ep0Mode = USBFS_MODE_ACK_OUT_STATUS_IN;    return(USBFS_TRUE);}/******************************************************************************** Function Name: USBFS_ControlWriteDataStage********************************************************************************** Summary:*  Handle the Data Stage of a control write transfer*       1. Get the data (We assume the destination was validated previously)*       2. Update the count and data toggle*       3. Update the mode register for the next transaction** Parameters:*  None.** Return:*  None.** Global variables:*  USBFS_transferByteCount - Update the transfer byte count from the*    last transaction.*  USBFS_ep0Count - counts the data loaded from the SIE memory*    in current packet.*  USBFS_transferByteCount - sum of the previous bytes transferred*    on previous packets(sum of USBFS_lastPacketSize)*  USBFS_ep0Toggle - inverted*  USBFS_ep0Mode  - set to MODE_ACK_OUT_STATUS_IN.** Reentrant:*  No.********************************************************************************/void USBFS_ControlWriteDataStage(void) {    uint8 ep0Count;    uint8 regIndex = 0u;    ep0Count = (CY_GET_REG8(USBFS_EP0_CNT_PTR) & USBFS_EPX_CNT0_MASK) -               USBFS_EPX_CNTX_CRC_COUNT;    USBFS_transferByteCount += ep0Count;    while ((USBFS_currentTD.count > 0u) && (ep0Count > 0u))    {        *USBFS_currentTD.pData = CY_GET_REG8((reg8 *)(USBFS_EP0_DR0_IND + regIndex));        USBFS_currentTD.pData = &USBFS_currentTD.pData[1u];        regIndex++;        ep0Count--;        USBFS_currentTD.count--;    }    USBFS_ep0Count = ep0Count;    /* Update the data toggle */    USBFS_ep0Toggle ^= USBFS_EP0_CNT_DATA_TOGGLE;    /* Expect Data or Status Stage */    USBFS_ep0Mode = USBFS_MODE_ACK_OUT_STATUS_IN;}/******************************************************************************** Function Name: USBFS_ControlWriteStatusStage********************************************************************************** Summary:*  Handle the Status Stage of a control write transfer** Parameters:*  None.** Return:*  None.** Global variables:*  USBFS_transferState - set to TRANS_STATE_IDLE.*  USBFS_USBFS_ep0Mode  - set to MODE_STALL_IN_OUT.** Reentrant:*  No.********************************************************************************/void USBFS_ControlWriteStatusStage(void) {    /* Go Idle */    USBFS_transferState = USBFS_TRANS_STATE_IDLE;    /* Update the completion block */    USBFS_UpdateStatusBlock(USBFS_XFER_STATUS_ACK);    /* We expect no more data, so stall INs and OUTs */    USBFS_ep0Mode = USBFS_MODE_STALL_IN_OUT;}/******************************************************************************** Function Name: USBFS_InitNoDataControlTransfer********************************************************************************** Summary:*  Initialize a no data control transfer** Parameters:*  None.** Return:*  requestHandled state.** Global variables:*  USBFS_transferState - set to TRANS_STATE_NO_DATA_CONTROL.*  USBFS_ep0Mode  - set to MODE_STATUS_IN_ONLY.*  USBFS_ep0Count - cleared.*  USBFS_ep0Toggle - set to EP0_CNT_DATA_TOGGLE** Reentrant:*  No.********************************************************************************/uint8 USBFS_InitNoDataControlTransfer(void) {    USBFS_transferState = USBFS_TRANS_STATE_NO_DATA_CONTROL;    USBFS_ep0Mode = USBFS_MODE_STATUS_IN_ONLY;    USBFS_ep0Toggle = USBFS_EP0_CNT_DATA_TOGGLE;    USBFS_ep0Count = 0u;    return(USBFS_TRUE);}/******************************************************************************** Function Name: USBFS_NoDataControlStatusStage********************************************************************************* Summary:*  Handle the Status Stage of a no data control transfer.**  SET_ADDRESS is special, since we need to receive the status stage with*  the old address.** Parameters:*  None.** Return:*  None.** Global variables:*  USBFS_transferState - set to TRANS_STATE_IDLE.*  USBFS_ep0Mode  - set to MODE_STALL_IN_OUT.*  USBFS_ep0Toggle - set to EP0_CNT_DATA_TOGGLE*  USBFS_deviceAddress - used to set new address and cleared** Reentrant:*  No.********************************************************************************/void USBFS_NoDataControlStatusStage(void) {    /* Change the USB address register if we got a SET_ADDRESS. */    if (USBFS_deviceAddress != 0u)    {        CY_SET_REG8(USBFS_CR0_PTR, USBFS_deviceAddress | USBFS_CR0_ENABLE);        USBFS_deviceAddress = 0u;    }    /* Go Idle */    USBFS_transferState = USBFS_TRANS_STATE_IDLE;    /* Update the completion block */    USBFS_UpdateStatusBlock(USBFS_XFER_STATUS_ACK);     /* We expect no more data, so stall INs and OUTs */    USBFS_ep0Mode = USBFS_MODE_STALL_IN_OUT;}/******************************************************************************** Function Name: USBFS_UpdateStatusBlock********************************************************************************** Summary:*  Update the Completion Status Block for a Request.  The block is updated*  with the completion code the USBFS_transferByteCount.  The*  StatusBlock Pointer is set to NULL.** Parameters:*  completionCode - status.** Return:*  None.** Global variables:*  USBFS_currentTD.pStatusBlock->status - updated by the*    completionCode parameter.*  USBFS_currentTD.pStatusBlock->length - updated.*  USBFS_currentTD.pStatusBlock - cleared.** Reentrant:*  No.********************************************************************************/void USBFS_UpdateStatusBlock(uint8 completionCode) {    if (USBFS_currentTD.pStatusBlock != NULL)    {        USBFS_currentTD.pStatusBlock->status = completionCode;        USBFS_currentTD.pStatusBlock->length = USBFS_transferByteCount;        USBFS_currentTD.pStatusBlock = NULL;    }}/******************************************************************************** Function Name: USBFS_InitializeStatusBlock********************************************************************************** Summary:*  Initialize the Completion Status Block for a Request.  The completion*  code is set to USB_XFER_IDLE.**  Also, initializes USBFS_transferByteCount.  Save some space,*  this is the only consumer.** Parameters:*  None.** Return:*  None.** Global variables:*  USBFS_currentTD.pStatusBlock->status - set to XFER_IDLE.*  USBFS_currentTD.pStatusBlock->length - cleared.*  USBFS_transferByteCount - cleared.** Reentrant:*  No.********************************************************************************/void USBFS_InitializeStatusBlock(void) {    USBFS_transferByteCount = 0u;    if(USBFS_currentTD.pStatusBlock != NULL)    {        USBFS_currentTD.pStatusBlock->status = USBFS_XFER_IDLE;        USBFS_currentTD.pStatusBlock->length = 0u;    }}/* [] END OF FILE */
 |