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

📄 usbs_sa11x0.c

📁 基于ecos的redboot
💻 C
📖 第 1 页 / 共 5 页
字号:

        for (retries = 0; !read && (retries < MAX_RETRIES); retries++) {
            if ((count - emptied) != *EP0_WRITE_COUNT) {
                DBG(("EP0_empty_fifo, inconsistency, read %d bytes of %d, but fifo count %d\n", emptied, count, *EP0_WRITE_COUNT));
                ok = false;
            } else {
                buf[emptied] = *EP0_DATA;
                for (checks = 0; !read && (checks < MAX_CHECKS); checks++) {
                    if ((count - emptied) > *EP0_WRITE_COUNT) {
                        //DBG(("Read %d byte (%x) after %d checks, %d retries\n", emptied, buf[emptied], checks, retries));
                        read = true;
                        emptied++;
                    }
                }
            }
        }
        if (ok && !read) {
            DBG(("EP0 empty fifo, failed to read byte from fifo\n"));
            ok = false;
        }
    }
    
    return emptied;
}

// This is where all the hard work happens. It is a very large routine
// for a DSR, but in practice nearly all of it is nested if's and very
// little code actually gets executed. Note that there may be
// invocations of callback functions and the driver has no control
// over how much time those will take, but those callbacks should be
// simple.
static void
usbs_sa11x0_ep0_dsr(void)
{
    int hw_state = *EP0_CONTROL;

    // Handle the stall bits.
    //
    // Force-stall should not be a problem. It is set by the code here
    // if the host needs to be told that the control message was
    // unacceptable and is cleared automatically by the hardware after
    // the stall is sent.
    //
    // Sent-stall is set by the hardware following a protocol
    // violation, e.g. if there is an IN token when a new control
    // message is expected. There is nothing the software can do about
    // this. However if we are in the middle of an IN or OUT transfer
    // then those are not going to complete successfully.
    if (0 != (hw_state & EP0_SENT_STALL)) {
        if (EP0_STATE_IDLE != ep0.ep_state) {
            if ((usbs_control_return (*)(usbs_control_endpoint*, int))0 != ep0.common.complete_fn) {
                (*ep0.common.complete_fn)(&ep0.common, -EIO);
            }
            ep0.ep_state                = EP0_STATE_IDLE;
            ep0.common.buffer           = (unsigned char*) 0;
            ep0.common.buffer_size      = 0;
            ep0.common.fill_buffer_fn   = 0;
            ep0.common.complete_fn      = (usbs_control_return (*)(usbs_control_endpoint*, int)) 0;
        }
        usbs_sa11x0_poke(EP0_CONTROL, EP0_SENT_STALL, 0, EP0_SENT_STALL);
    }   // STALL condition
    
    // Next, check whether we have received a new control message
    // while still busy processing an old one.
    if (0 != (hw_state & EP0_SETUP_END)) {
        if (EP0_STATE_IDLE != ep0.ep_state) {
            if ((usbs_control_return (*)(usbs_control_endpoint*, int)) 0 != ep0.common.complete_fn) {
                (*ep0.common.complete_fn)(&ep0.common, -EIO);
            }
            ep0.ep_state                = EP0_STATE_IDLE;
            ep0.common.buffer           = (unsigned char*) 0;
            ep0.common.buffer_size      = 0;
            ep0.common.fill_buffer_fn   = 0;
            ep0.common.complete_fn      = (usbs_control_return (*)(usbs_control_endpoint*, int)) 0;
        }
        // We are now back in idle state so the control message will be
        // extracted and processed.
        usbs_sa11x0_poke(EP0_CONTROL, EP0_SERVICED_SETUP_END, 0, EP0_SETUP_END);
    }   // Interrupted control transaction

    // The endpoint can be in one of three states: IN, OUT, or IDLE.
    // For the first two it should mean that there is more data to be
    // transferred, which is pretty straightforward. IDLE means
    // that a new control message has arrived.
    if ((EP0_STATE_IN == ep0.ep_state) && (0 == (EP0_IN_READY & hw_state)))  {
        
        usbs_sa11x0_ep0_fill_fifo();
        
    } else if ((EP0_STATE_OUT == ep0.ep_state) && (0 != (EP0_OUT_READY & hw_state))) {

        // A host->device transfer. Higher level code must have
        // provided a suitable buffer.
        CYG_ASSERT( (unsigned char*)0 != ep0.common.buffer, "A receive buffer should have been provided" );

        ep0.transmitted += usbs_sa11x0_ep0_empty_fifo(ep0.common.buffer + ep0.transmitted);

        if (ep0.transmitted != ep0.length) {
            // The host is not allowed to send more data than it
            // indicated in the original control message, and all
            // messages until the last one should be full size.
            CYG_ASSERT( ep0.transmitted < ep0.length, "The host must not send more data than expected");
            CYG_ASSERT( 0 == (ep0.transmitted % EP0_FIFO_SIZE), "All OUT packets until the last one should be full-size");

            usbs_sa11x0_poke(EP0_CONTROL, EP0_SERVICED_OPR, 0, EP0_OUT_READY);
        } else {
            // The whole transfer is now complete. Invoke the
            // completion function, and based on its return value
            // either generate a stall or complete the message.
            usbs_control_return result;
            
            CYG_ASSERT( (usbs_control_return (*)(usbs_control_endpoint*, int))0 != ep0.common.complete_fn, \
                        "A completion function should be provided for OUT control messages");

            result = (*ep0.common.complete_fn)(&ep0.common, 0);
            ep0.common.buffer           = (unsigned char*) 0;
            ep0.common.buffer_size      = 0;
            ep0.common.complete_fn      = (usbs_control_return (*)(usbs_control_endpoint*, int)) 0;
            
            if (USBS_CONTROL_RETURN_HANDLED == result) {
                usbs_sa11x0_poke(EP0_CONTROL,
                                 EP0_SERVICED_OPR | EP0_DATA_END,
                                 EP0_DATA_END,
                                 EP0_OUT_READY);
            } else {
                usbs_sa11x0_poke(EP0_CONTROL,
                                 EP0_SERVICED_OPR | EP0_DATA_END | EP0_FORCE_STALL,
                                 EP0_FORCE_STALL,
                                 EP0_OUT_READY);
            }
            // Also remember to switch back to IDLE state 
            ep0.ep_state = EP0_STATE_IDLE;
        }
        
    } else if (0 != (EP0_OUT_READY & hw_state)) {

        int emptied = usbs_sa11x0_ep0_empty_fifo(ep0.common.control_buffer);
        
        if (8 != emptied) {
            // This indicates a serious problem somewhere. Respond by
            // stalling. Hopefully the host will take some action that
            // sorts out the mess.
            usbs_sa11x0_poke(EP0_CONTROL,
                             EP0_SERVICED_OPR | EP0_DATA_END | EP0_FORCE_STALL,
                             EP0_FORCE_STALL,
                             EP0_OUT_READY);
            
        } else {
            usbs_control_return result  = USBS_CONTROL_RETURN_UNKNOWN;
            usb_devreq*         req     = (usb_devreq*) ep0.common.control_buffer;
            int length, direction, protocol, recipient;
            
            // Now we need to do some decoding of the data. A non-zero
            // length field indicates that there will be a subsequent
            // IN or OUT phase. The direction is controlled by the
            // top bit of the first byte. The protocol is determined
            // by other bits of the top byte.
            length      = (req->length_hi << 8) | req->length_lo;
            direction   = req->type & USB_DEVREQ_DIRECTION_MASK;
            protocol    = req->type & USB_DEVREQ_TYPE_MASK;
            recipient   = req->type & USB_DEVREQ_RECIPIENT_MASK;

#if 0
            DBG(("ep0, new control request: type %x, code %x\n", req->type, req->request));
            DBG(("     %s, length %d, value hi %x lo %x, index hi %x lo %x\n",
                 (USB_DEVREQ_DIRECTION_OUT == direction) ? "out" : "in",
                 length, req->value_hi, req->value_lo, req->index_hi, req->index_lo));
#endif            
            if (0 != length){
                // Clear the fifo straightaway. There is no harm in
                // doing this here. It may or may not do some good.
                usbs_sa11x0_poke(EP0_CONTROL, EP0_SERVICED_OPR, 0, EP0_OUT_READY);
            }
            
            if (USB_DEVREQ_TYPE_STANDARD == protocol) {
                
                // First see if the request can be handled entirely in
                // this module.
                if (USB_DEVREQ_SET_ADDRESS == req->request) {
                    // The USB device address should be in value_lo.
                    // No more data is expected. 
                    int address = req->value_lo;
                    if ((0 != length) || (address > 127)) {
                        result = USBS_CONTROL_RETURN_STALL;
                    } else {
                        // poke_value() cannot be used here because
                        // setting the address does not take effect
                        // until the status phase.
                        *USBS_ADDRESS = address;
                        result = USBS_CONTROL_RETURN_HANDLED;
                    }
                } else if (USB_DEVREQ_GET_STATUS == req->request) {
                    // GET_STATUS on the device as a whole is used to
                    // check the remote-wakeup and self-powered bits.
                    // GET_STATUS on an endpoint is used to determine
                    // the halted condition.
                    // GET_STATUS on anything else has to be left to
                    // other code.
                    if (USB_DEVREQ_RECIPIENT_DEVICE == recipient) {
                        // The host should expect two bytes back.
                        if ((2 == length) && (USB_DEVREQ_DIRECTION_IN == direction)) {
                            ep0.common.control_buffer[0] = 0;   // Not self-powered, no remote wakeup
                            ep0.common.control_buffer[1] = 0;
                            ep0.common.buffer            = ep0.common.control_buffer;
                            ep0.common.buffer_size       = 2;
                            result                       = USBS_CONTROL_RETURN_HANDLED;
                        } else {
                            result = USBS_CONTROL_RETURN_STALL;
                        }
                        
                    } else if (USB_DEVREQ_RECIPIENT_ENDPOINT == recipient) {
                        if ((2 == length) && (USB_DEVREQ_DIRECTION_IN == direction)) {
                            int endpoint = req->index_lo;
                            if (0 == endpoint) {
                                // get-status on endpoint 0 is either undefined or always valid.
                                // endpoint 0 is always up.
                                ep0.common.control_buffer[0] = 0;
                                result = USBS_CONTROL_RETURN_HANDLED;
                            }
#ifdef CYGPKG_DEVS_USB_SA11X0_EP1
                            else if (((USB_DEVREQ_INDEX_DIRECTION_OUT | 1) == endpoint) &&
                                       (USBS_STATE_CONFIGURED == (ep0.common.state & USBS_STATE_MASK))) {
                                
                                ep0.common.control_buffer[0] = ep1.common.halted;
                                result = USBS_CONTROL_RETURN_HANDLED;

                            }
#endif                            
#ifdef CYGPKG_DEVS_USB_SA11X0_EP2
                            else if (((USB_DEVREQ_INDEX_DIRECTION_IN | 2) == endpoint) &&
                                       (USBS_STATE_CONFIGURED == (ep0.common.state & USBS_STATE_MASK))) {

                                ep0.common.control_buffer[0] = ep2.common.halted;
                                result = USBS_CONTROL_RETURN_HANDLED;
                                
                            }
#endif                            
                            else {
                                // An invalid endpoint has been specified or the
                                // endpoint can only be examined in configured state.
                                result = USBS_CONTROL_RETURN_STALL;
                            }
                            if (USBS_CONTROL_RETURN_HANDLED == result) {
                                ep0.common.control_buffer[1] = 0;
                                ep0.common.buffer            = ep0.common.control_buffer;
                                ep0.common.buffer_size       = 2;
                            }
                        } else {
                            result = USBS_CONTROL_RETURN_STALL;
                        }
                    } // Endpoint or device get-status
                    
                } else if (USB_DEVREQ_CLEAR_FEATURE == req->request) {

                    // CLEAR_FEATURE operates in much the same way as
                    // GET_STATUS
                    if (USB_DEVREQ_RECIPIENT_DEVICE == recipient) {
                        
                        // No data should be transferred, and only remote-wakeup can be cleared.
                        if ((0 != length) || (USB_DEVREQ_FEATURE_DEVICE_REMOTE_WAKEUP != req->value_lo)) {
                            result = USBS_CONTROL_RETURN_STALL;
                        } else {
                            // Clearing remote-wakeup is a no-op.
                            result = USBS_CONTROL_RETURN_HANDLED;
                        }

                    } else if (USB_DEVREQ_RECIPIENT_ENDPOINT == recipient) {
                        // The only feature that can be cleared is endpoint-halt, no data should be transferred.
                        if ((0 != length) || (USB_DEVREQ_FEATURE_ENDPOINT_HALT != req->value_lo)) {
                            result = USBS_CONTROL_RETURN_STALL;
                        } else {
                            int endpoint = req->index_lo;
                            if (0 == endpoint) {
                                // Clearing halt on endpoint 0 is always a no-op since that endpoint cannot be halted
                            }
#ifdef CYGPKG_DEVS_USB_SA11X0_EP1
                            else if (((USB_DEVREQ_INDEX_DIRECTION_OUT | 1) == endpoint) &&
                                       (USBS_STATE_CONFIGURED == (ep0.common.state & USBS_STATE_MASK))) {

⌨️ 快捷键说明

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