⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usbd_udp.c

📁 Atmel的AT91SAM9263芯片的usb HID设备keyboard的源程序
💻 C
📖 第 1 页 / 共 3 页
字号:
    Transfer *transfer = &(endpoint->transfer);

    // Check if it is a Control endpoint
    //  -> Control endpoint must always finish their transfer with a zero-length
    //     packet
    if ((AT91C_BASE_UDP->UDP_CSR[eptnum] & AT91C_UDP_EPTYPE)
        == AT91C_UDP_EPTYPE_CTRL) {

        return (transfer->buffered < endpoint->size);
    }
    // Other endpoints only need to transfer all the data
    else {

        return (transfer->buffered <= endpoint->size)
               && (transfer->remaining == 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_LOG(trace_INFO, "Ept%d ", eptnum);

    // Handle interrupts
    // IN packet sent
    if ((status & AT91C_UDP_TXCOMP) != 0) {

        trace_LOG(trace_INFO, "Wr ");

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

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

                trace_LOG(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);
            }
            else {

                // Transfer remaining data
                trace_LOG(trace_INFO, "%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);
                }
                else {

                    // Double buffering
                    SET_CSR(eptnum, AT91C_UDP_TXPKTRDY);
                    UDP_WritePayload(eptnum);
                }
            }
        }

        // Acknowledge interrupt
        CLEAR_CSR(eptnum, AT91C_UDP_TXCOMP);
    }

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

        trace_LOG(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_LOG(trace_INFO, "Ack ");
                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_LOG(trace_INFO, "Disc ");
                UDP_ClearRxFlag(eptnum);
            }
            // NAK the data
            else {

                trace_LOG(trace_INFO, "Nak ");
                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_LOG(trace_INFO, "%d ", size);
            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_LOG(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_LOG(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);
        }
    }
}

//------------------------------------------------------------------------------
//      Exported functions
//------------------------------------------------------------------------------
/*
    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_LOG(trace_INFO, "CfgEpt%d ", eptnum);
}

/*
    Function: USBD_InterruptHandler
        UDP interrupt handler. Manages device status changes.
*/
void USBD_InterruptHandler()
{
    // Get interrupt status
    // Some interrupts may get masked depending on the device state
    unsigned int status = AT91C_BASE_UDP->UDP_ISR & AT91C_BASE_UDP->UDP_IMR;
    if (deviceState < USBD_STATE_POWERED) {

        status &= AT91C_UDP_WAKEUP | AT91C_UDP_RXRSM;
        AT91C_BASE_UDP->UDP_ICR = ~status;
    }

    // Return immediately if there is no interrupt to service
    if (status == 0) {

        return;
    }

    // Toggle USB LED if the device is active
    trace_LOG(trace_INFO, "Hlr ");
    if (deviceState >= USBD_STATE_POWERED) {

        LED_Set(USBD_LEDUSB);
    }

    // Service interrupts

    //// Start Of Frame (SOF)
    //if (ISSET(dStatus, AT91C_UDP_SOFINT)) {
    //
    //    trace_LOG(trace_DEBUG, "SOF");
    //
    //    // Invoke the SOF callback
    //    USB_StartOfFrameCallback(pUsb);
    //
    //    // Acknowledge interrupt
    //    AT91C_BASE_UDP->UDP_ICR |= AT91C_UDP_SOFINT;
    //    dStatus &= ~AT91C_UDP_SOFINT;
    //}

    // Suspend
    // This interrupt is always treated last (hence the '==')
    if (status == AT91C_UDP_RXSUSP) {

        trace_LOG(trace_INFO, "Susp ");

        // Don't do anything if the device is already suspended
        if (deviceState != USBD_STATE_SUSPENDED) {

            // The device enters the Suspended state
            // Enable wakeup
            AT91C_BASE_UDP->UDP_IER |= AT91C_UDP_WAKEUP | AT91C_UDP_RXRSM;

            // Acknowledge interrupt
            AT91C_BASE_UDP->UDP_ICR |= AT91C_UDP_RXSUSP;

            // Switch to the Suspended state
            previousDeviceState = deviceState;
            deviceState = USBD_STATE_SUSPENDED;
            UDP_DisableTransceiver();
            UDP_DisablePeripheralClock();
            UDP_DisableUsbClock();

            // Invoke the Suspended callback
            USBDCallbacks_Suspended();
        }
    }
    // Resume
    else if ((status & (AT91C_UDP_WAKEUP | AT91C_UDP_RXRSM)) != 0) {

        trace_LOG(trace_INFO, "Res ");

        // Invoke the Resume callback
        USBDCallbacks_Resumed();

        // Don't do anything if the device was not suspended
        if (deviceState == USBD_STATE_SUSPENDED) {

            // The device enters its previous state
            UDP_EnablePeripheralClock();
            UDP_EnableUsbClock();

            // Enable the transceiver if the device was past the Default
            // state
            deviceState = previousDeviceState;
            if (deviceState >= USBD_STATE_DEFAULT) {

                UDP_EnableTransceiver();
            }
        }
        
        // Clear and disable resume interrupts
        AT91C_BASE_UDP->UDP_ICR = AT91C_UDP_WAKEUP 
                                  | AT91C_UDP_RXRSM
                                  | AT91C_UDP_RXSUSP;
        AT91C_BASE_UDP->UDP_IDR = AT91C_UDP_WAKEUP | AT91C_UDP_RXRSM;
    }
    // End of bus reset
    else if ((status & AT91C_UDP_ENDBUSRES) != 0) {

        trace_LOG(trace_INFO, "EoBRes ");

        // The device enters the Default state
        deviceState = USBD_STATE_DEFAULT;
        UDP_EnableTransceiver();
        UDP_ResetEndpoints();
        UDP_DisableEndpoints();
        USBD_ConfigureEndpoint(0);

        // Flush and enable the Suspend interrupt
        AT91C_BASE_UDP->UDP_ICR = AT91C_UDP_WAKEUP
                                  | AT91C_UDP_RXRSM
                                  | AT91C_UDP_RXSUSP;
        AT91C_BASE_UDP->UDP_IER = AT91C_UDP_RXSUSP;

        //// Enable the Start Of Frame (SOF) interrupt if needed
        //if (pUsb->pCallbacks->startOfFrame != 0) {
        //
        //    AT91C_BASE_UDP->UDP_IER |= AT91C_UDP_SOFINT;
        //}

        // Invoke the Reset callback
        USBDCallbacks_Reset();

        // Acknowledge end of bus reset interrupt
        AT91C_BASE_UDP->UDP_ICR |= AT91C_UDP_ENDBUSRES;
    }
    // Endpoint interrupts
    else {

        int eptnum = 0;
        while (status != 0) {

            // Check if endpoint has a pending interrupt
            if ((status & (1 << eptnum)) != 0) {
            
                UDP_EndpointHandler(eptnum);
                status &= ~(1 << eptnum);
                
                if (status != 0) {
                
                    trace_LOG(trace_INFO, "\n\r  - ");
                }
            }
            eptnum++;
        }
    }

    // Toggle LED back to its previous state
    trace_LOG(trace_INFO, "\n\r");
    if (deviceState >= USBD_STATE_POWERED) {

        LED_Clear(USBD_LEDUSB);
    }
}

/*
    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).

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -