Esempio n. 1
0
/*
    Function: USBD_Stall
        Causes the given endpoint to acknowledge the next packet it receives
        with a STALL handshake.

    Parameters:
        eptnum - Endpoint number.

    Returns:
        USBD_STATUS_SUCCESS or USBD_STATUS_LOCKED.
*/
unsigned char USBD_Stall(unsigned char eptnum)
{
    Endpoint *endpoint = &(endpoints[eptnum]);

    // Check that endpoint is in Idle state
    if (endpoint->state != UDP_ENDPOINT_IDLE) {

        TRACE_WARNING( "USBD_Stall: Endpoint%d locked\n\r", eptnum);
        return USBD_STATUS_LOCKED;
    }

    TRACE_INFO( "iStall%d ", eptnum);
    SET_CSR(eptnum, AT91C_UDP_FORCESTALL);

    return USBD_STATUS_SUCCESS;
}
Esempio n. 2
0
/*
    Function: USBD_ConfigureEndpoint
        Configures an endpoint according to its Endpoint Descriptor.

    Parameters:
        descriptor - Pointer to an Endpoint descriptor.
*/
void USBD_ConfigureEndpoint(const USBEndpointDescriptor *descriptor)
{
    Endpoint *endpoint;
    unsigned char eptnum;
    unsigned char type;
    unsigned char direction;

    // NULL descriptor -> Control endpoint 0
    if (descriptor == 0) {

        eptnum = 0;
        endpoint = &(endpoints[eptnum]);
        type = USBEndpointDescriptor_CONTROL;
        direction = 0;
        endpoint->size = BOARD_USB_ENDPOINTS_MAXPACKETSIZE(0);
    }
    else {

        eptnum = USBEndpointDescriptor_GetNumber(descriptor);
        endpoint = &(endpoints[eptnum]);
        type = USBEndpointDescriptor_GetType(descriptor);
        direction = USBEndpointDescriptor_GetDirection(descriptor);
        endpoint->size = USBEndpointDescriptor_GetMaxPacketSize(descriptor);
    }

    // Abort the current transfer is the endpoint was configured and in
    // Write or Read state
    if ((endpoint->state == UDP_ENDPOINT_RECEIVING)
        || (endpoint->state == UDP_ENDPOINT_SENDING)) {

        UDP_EndOfTransfer(eptnum, USBD_STATUS_RESET);
    }
    endpoint->state = UDP_ENDPOINT_IDLE;

    // Reset Endpoint Fifos
    AT91C_BASE_UDP->UDP_RSTEP |= (1 << eptnum);
    AT91C_BASE_UDP->UDP_RSTEP &= ~(1 << eptnum);

    // Configure endpoint
    SET_CSR(eptnum, AT91C_UDP_EPEDS | (type << 8) | (direction << 10));
    if (type == USBEndpointDescriptor_CONTROL) {

        AT91C_BASE_UDP->UDP_IER = (1 << eptnum);
    }

    TRACE_INFO( "\r\n# CfgEpt%d ", eptnum);
}
Esempio n. 3
0
/*
    Function: USBD_Write
        Sends data through a USB endpoint. Sets up the transfer descriptor,
        writes one or two data payloads (depending on the number of FIFO bank
        for the endpoint) and then starts the actual transfer. The operation is
        complete when all the data has been sent.

         *If the size of the buffer is greater than the size of the endpoint
         (or twice the size if the endpoint has two FIFO banks), then the buffer
         must be kept allocated until the transfer is finished*. This means that
         it is not possible to declare it on the stack (i.e. as a local variable
         of a function which returns after starting a transfer).

    Parameters:
        eptnum - Endpoint number.
        data - Pointer to a buffer with the data to send.
        size - Size of the data buffer.
        callback - Optional callback function to invoke when the transfer is
                   complete.
        argument - Optional argument to the callback function.

    Returns:
        USBD_STATUS_SUCCESS if the transfer has been started; otherwise, the
        corresponding error status code.
*/
char USBD_Write(unsigned char eptnum,
                const void *data,
                unsigned int size,
                TransferCallback callback,
                void *argument)
{
    Endpoint *endpoint = &(endpoints[eptnum]);
    Transfer *transfer = &(endpoint->transfer);

    // Check that the endpoint is in Idle state
    if (endpoint->state != UDP_ENDPOINT_IDLE) {

        return USBD_STATUS_LOCKED;
    }

    //TRACE_INFO( "Write%d(%u) ", eptnum, size);

    // Setup the transfer descriptor
    transfer->data = (void *) data;
    transfer->remaining = size;
    transfer->buffered = 0;
    transfer->transferred = 0;
    transfer->callback = callback;
    transfer->argument = argument;

    // Send the first packet
    endpoint->state = UDP_ENDPOINT_SENDING;
    while((AT91C_BASE_UDP->UDP_CSR[eptnum]&AT91C_UDP_TXPKTRDY)==AT91C_UDP_TXPKTRDY);
    UDP_WritePayload(eptnum);
    SET_CSR(eptnum, AT91C_UDP_TXPKTRDY);

    // If double buffering is enabled and there is data remaining,
    // prepare another packet
    if ((BOARD_USB_ENDPOINTS_BANKS(eptnum) > 1) && (transfer->remaining > 0)) {

        UDP_WritePayload(eptnum);
    }

    // Enable interrupt on endpoint
    AT91C_BASE_UDP->UDP_IER = 1 << eptnum;

    return USBD_STATUS_SUCCESS;
}
Esempio n. 4
0
/*
    Function: USBD_Halt
        Sets the HALT feature on the given endpoint (if not already in this
        state).

    Parameters:
        eptnum - Endpoint number.
*/
void USBD_Halt(unsigned char eptnum)
{
    Endpoint *endpoint = &(endpoints[eptnum]);
    
    // Check that endpoint is enabled and not already in Halt state
    if ((endpoint->state != UDP_ENDPOINT_DISABLED)
        && (endpoint->state != UDP_ENDPOINT_HALTED)) {

        TRACE_INFO( "Halt%d ", eptnum);

        // Abort the current transfer if necessary
        UDP_EndOfTransfer(eptnum, USBD_STATUS_ABORTED);

        // Put endpoint into Halt state
        SET_CSR(eptnum, AT91C_UDP_FORCESTALL);
        endpoint->state = UDP_ENDPOINT_HALTED;

        // Enable the endpoint interrupt
        AT91C_BASE_UDP->UDP_IER = 1 << eptnum;
    }
}
Esempio n. 5
0
//-----------------------------------------------------------------------------
void usb_svc_halt_hook(USB_DRV_INFO drv_info, HANDLE hnd)
{
	USB_DRIVER_DATA* drv_data = drv_info->drv_data;
	Udp* pUDP = drv_info->hw_base;
	unsigned int eptnum = hnd->src.as_int;
    Endpoint *endpoint = &drv_data->endpoints[eptnum];

	TRACE_USB(" Halt%d", eptnum);

    // Check that endpoint is enabled and not already in Halt state
    if (endpoint->state >= ENDPOINT_STATE_IDLE)
   	{
        // Abort the current transfer if necessary
    	usb_drv_end_transfers(endpoint, USBD_STATUS_ABORTED);

        // Put endpoint into Halt state
        SET_CSR(&pUDP->UDP_CSR[eptnum], UDP_CSR_FORCESTALL);
        endpoint->state = ENDPOINT_STATE_HALTED;

        // Enable the endpoint interrupt
        pUDP->UDP_IER |= 1 << eptnum;
    }
}
Esempio n. 6
0
/*
    Function: UDP_EndpointHandler
        Endpoint interrupt handler. Manages IN, OUT & SETUP transaction, as well
        as the STALL condition.

    Parameters:
        eptnum - Number of the endpoint to handle interrupt for.
*/
static void UDP_EndpointHandler(unsigned char eptnum)
{
    Endpoint *endpoint = &(endpoints[eptnum]);
    Transfer *transfer = &(endpoint->transfer);
    unsigned int status = AT91C_BASE_UDP->UDP_CSR[eptnum];

    //TRACE_INFO( "Ept%d ", eptnum);
    //TRACE_INFO( "[");
    // Handle interrupts
    
    // IN packet sent
    if ((status & AT91C_UDP_TXCOMP) != 0) {

        //TRACE_INFO( "Wr ");

        // Check that endpoint was in Sending state
        if (endpoint->state == UDP_ENDPOINT_SENDING) {

            // End of transfer ?
            if (UDP_IsTransferFinished(eptnum)) {

               // TRACE_INFO( "%d ", transfer->buffered);

                transfer->transferred += transfer->buffered;
                transfer->buffered = 0;

                // Disable interrupt if this is not a control endpoint
                if ((status & AT91C_UDP_EPTYPE) != AT91C_UDP_EPTYPE_CTRL) {

                    AT91C_BASE_UDP->UDP_IDR = 1 << eptnum;
                }

                UDP_EndOfTransfer(eptnum, USBD_STATUS_SUCCESS);
                CLEAR_CSR(eptnum, AT91C_UDP_TXCOMP);
            }
            else {

                // Transfer remaining data
              //TRACE_INFO( "PQ:%d ", endpoint->size);

                transfer->transferred += endpoint->size;
                transfer->buffered -= endpoint->size;

                // Send next packet
                if (BOARD_USB_ENDPOINTS_BANKS(eptnum) == 1) {

                    // No double buffering
                    UDP_WritePayload(eptnum);
                    SET_CSR(eptnum, AT91C_UDP_TXPKTRDY);
                    CLEAR_CSR(eptnum, AT91C_UDP_TXCOMP);
                }
                else {
                    // Double buffering
                    SET_CSR(eptnum, AT91C_UDP_TXPKTRDY);
                    CLEAR_CSR(eptnum, AT91C_UDP_TXCOMP);
                    UDP_WritePayload(eptnum);
                }
            }
        }
        else {
            // Acknowledge interrupt
            CLEAR_CSR(eptnum, AT91C_UDP_TXCOMP);
        }
    }

    // OUT packet received
    if ((status & UDP_RXDATA) != 0) {

        //TRACE_INFO( "Rd ");

        // Check that the endpoint is in Receiving state
        if (endpoint->state != UDP_ENDPOINT_RECEIVING) {

            // Check if an ACK has been received on a Control endpoint
            if (((status & AT91C_UDP_EPTYPE) == AT91C_UDP_EPTYPE_CTRL)
                && ((status & AT91C_UDP_RXBYTECNT) == 0)) {

                // Acknowledge the data and finish the current transfer
                ///TRACE_INFO( "[%d]Ack ",eptnum);
                UDP_ClearRxFlag(eptnum);
                UDP_EndOfTransfer(eptnum, USBD_STATUS_SUCCESS);
            }
            // Check if the data has been STALLed
            else if ((status & AT91C_UDP_FORCESTALL) != 0) {

                // Discard STALLed data
                TRACE_INFO( "[%d]Disc ",eptnum);
                UDP_ClearRxFlag(eptnum);
            }
            // NAK the data
            else {

                TRACE_INFO( "[%d]Nak ",eptnum);
                AT91C_BASE_UDP->UDP_IDR = 1 << eptnum;
            }
        }
        // Endpoint is in Read state
        else {

            // Retrieve data and store it into the current transfer buffer
            unsigned short size = (unsigned short) (status >> 16);
            //TRACE_INFO( "-[%d]-", size);
            //TRACE_INFO( "Rec ");
            UDP_ReadPayload(eptnum, size);
            UDP_ClearRxFlag(eptnum);

            // Check if the transfer is finished
            if ((transfer->remaining == 0) || (size < endpoint->size)) {

                // Disable interrupt if this is not a control endpoint
                if ((status & AT91C_UDP_EPTYPE) != AT91C_UDP_EPTYPE_CTRL) {

                    AT91C_BASE_UDP->UDP_IDR = 1 << eptnum;
                }

                UDP_EndOfTransfer(eptnum, USBD_STATUS_SUCCESS);
            }
        }
    }

    // SETUP packet received
    if ((status & AT91C_UDP_RXSETUP) != 0) {

        //TRACE_INFO( "Stp ");

        // If a transfer was pending, complete it
        // Handles the case where during the status phase of a control write
        // transfer, the host receives the device ZLP and ack it, but the ack
        // is not received by the device
        if ((endpoint->state == UDP_ENDPOINT_RECEIVING)
            || (endpoint->state == UDP_ENDPOINT_SENDING)) {

            UDP_EndOfTransfer(eptnum, USBD_STATUS_SUCCESS);
        }
        USBGenericRequest request;
        UDP_ReadRequest(&request);

        // Set the DIR bit before clearing RXSETUP in Control IN sequence
        if (USBGenericRequest_GetDirection(&request) == USBGenericRequest_IN) {

            SET_CSR(eptnum, AT91C_UDP_DIR);
        }
        CLEAR_CSR(eptnum, AT91C_UDP_RXSETUP);

        // Forward the request to the upper layer
        USBDCallbacks_RequestReceived(&request);//------------------------------------
    }

    // STALL sent
    if ((status & AT91C_UDP_STALLSENT) != 0) {

        TRACE_INFO( "STA ");

        // If the endpoint is not halted, clear the STALL condition
        CLEAR_CSR(eptnum, AT91C_UDP_STALLSENT);
        if (endpoint->state != UDP_ENDPOINT_HALTED) {

            CLEAR_CSR(eptnum, AT91C_UDP_FORCESTALL);
        }
        
    }
    //TRACE_INFO( "]");
}
Esempio n. 7
0
/**
 * Sends data frames through a USB endpoint. Sets up the transfer descriptor
 * list, writes one or two data payloads (depending on the number of FIFO bank
 * for the endpoint) and then starts the actual transfer. The operation is
 * complete when all the data has been sent.
 *
 * *If the size of the frame is greater than the size of the endpoint
 *  (or twice the size if the endpoint has two FIFO banks), then the buffer
 *  must be kept allocated until the frame is finished*. This means that
 *  it is not possible to declare it on the stack (i.e. as a local variable
 *  of a function which returns after starting a transfer).
 *
 * \param bEndpoint Endpoint number.
 * \param pMbl Pointer to a frame (USBDTransferBuffer) list that describes
 *             the buffer list to send.
 * \param wListSize Size of the frame list.
 * \param bCircList Circle the list.
 * \param wStartNdx For circled list only, the first buffer index to transfer.
 * \param fCallback Optional callback function to invoke when the transfer is
 *        complete.
 * \param pArgument Optional argument to the callback function.
 * \return USBD_STATUS_SUCCESS if the transfer has been started;
 *         otherwise, the corresponding error status code.
 * \see USBDTransferBuffer, MblTransferCallback, USBD_MblReuse
 */
uint8_t USBD_MblWrite( uint8_t       bEndpoint,
                    void                *pMbl,
                    uint16_t      wListSize,
                    uint8_t       bCircList,
                    uint16_t      wStartNdx,
                    MblTransferCallback fCallback,
                    void                *pArgument )
{
    Endpoint    *pEndpoint = &(endpoints[bEndpoint]);
    MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer);
    uint16_t i;

    /* EP0 is not suitable for Mbl */

    if (bEndpoint == 0) {

        return USBD_STATUS_INVALID_PARAMETER;
    }

    /* Check that the endpoint is in Idle state */

    if (pEndpoint->state != UDP_ENDPOINT_IDLE) {

        return USBD_STATUS_LOCKED;
    }
    pEndpoint->state = UDP_ENDPOINT_SENDINGM;

    TRACE_DEBUG_WP("WriteM%d(0x%x,%d) ", bEndpoint, pMbl, wListSize);

    /* Start from first if not circled list */

    if (!bCircList) wStartNdx = 0;

    /* Setup the transfer descriptor */

    pTransfer->pMbl        = (USBDTransferBuffer*)pMbl;
    pTransfer->listSize    = wListSize;
    pTransfer->fCallback   = fCallback;
    pTransfer->pArgument   = pArgument;
    pTransfer->currBuffer  = wStartNdx;
    pTransfer->freedBuffer = 0;
    pTransfer->pLastLoaded = &(((USBDTransferBuffer*)pMbl)[wStartNdx]);
    pTransfer->circList    = bCircList;
    pTransfer->allUsed     = 0;

    /* Clear all buffer */

    for (i = 0; i < wListSize; i ++) {

        pTransfer->pMbl[i].transferred = 0;
        pTransfer->pMbl[i].buffered   = 0;
        pTransfer->pMbl[i].remaining   = pTransfer->pMbl[i].size;
    }

    /* Send the first packet */

    while((UDP->UDP_CSR[bEndpoint]&UDP_CSR_TXPKTRDY)==UDP_CSR_TXPKTRDY);
    UDP_MblWriteFifo(bEndpoint);
    SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY);

    /* If double buffering is enabled and there is data remaining, */

    /* prepare another packet */

    if ((CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1)
        && (pTransfer->pMbl[pTransfer->currBuffer].remaining > 0)) {

        UDP_MblWriteFifo(bEndpoint);
    }

    /* Enable interrupt on endpoint */

    UDP->UDP_IER = 1 << bEndpoint;

    return USBD_STATUS_SUCCESS;
}