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

📄 usbs_sa11x0.c

📁 基于ecos的redboot
💻 C
📖 第 1 页 / 共 5 页
字号:
                                ep1_set_halted(&ep1.common, false);
                                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))) {
                                ep2_set_halted(&ep2.common, false);
                                result = USBS_CONTROL_RETURN_HANDLED;
                                    
                            }
#endif
                            else {
                                // Invalid endpoint or not in configured state.
                                result = USBS_CONTROL_RETURN_STALL;
                            }
                        }
                    }   // Endpoing or device clear-feature
                    
                } else if (USB_DEVREQ_SET_FEATURE == req->request) {

                    // SET_FEATURE also operates in much the same way as
                    // GET_STATUS
                    if (USB_DEVREQ_RECIPIENT_DEVICE == recipient) {
                        
                        // The only valid feature that can be set is remote-wakeup,
                        // which is not supported by the hardware.
                        result = USBS_CONTROL_RETURN_STALL;
                        
                    } else if (USB_DEVREQ_RECIPIENT_ENDPOINT == recipient) {

                        // Only the halt condition can be set, and no data should be transferred.
                        // Halting endpoint 0 should probably be disallowed although the
                        // standard does not explicitly say so.
                        if ((0 != length) ||
                            (USB_DEVREQ_FEATURE_ENDPOINT_HALT != req->value_lo) ||
                            (USBS_STATE_CONFIGURED != (ep0.common.state & USBS_STATE_MASK))) {
                            
                            result = USBS_CONTROL_RETURN_STALL;
                            
                        } else {
                            int endpoint = req->index_lo;
                            if (0) {
                            }
#ifdef CYGPKG_DEVS_USB_SA11X0_EP1
                            else if ((USB_DEVREQ_INDEX_DIRECTION_OUT | 1) == endpoint) {
                                ep1_set_halted(&ep1.common, true);
                                result = USBS_CONTROL_RETURN_HANDLED;
                            }
#endif                            
#ifdef CYGPKG_DEVS_USB_SA11X0_EP2
                            else if ((USB_DEVREQ_INDEX_DIRECTION_IN | 2) == endpoint) {
                                ep2_set_halted(&ep2.common, true);
                                result = USBS_CONTROL_RETURN_HANDLED;
                            }
#endif                            
                            else {
                                result = USBS_CONTROL_RETURN_STALL;
                            }
                        }
                    } // Endpoing or device set-feature
                }

                // If the result has not been handled yet, pass it to
                // the install callback function (if any).
                if (USBS_CONTROL_RETURN_UNKNOWN == result) {
                    if ((usbs_control_return (*)(usbs_control_endpoint*, void*))0 != ep0.common.standard_control_fn) {
                        result = (*ep0.common.standard_control_fn)(&ep0.common, ep0.common.standard_control_data);
                    }
                }

                // If the result has still not been handled, leave it to
                // the default implementation in the USB slave common place.
                if (USBS_CONTROL_RETURN_UNKNOWN == result) {
                    result = usbs_handle_standard_control(&ep0.common);
                }
                
            } else {
                // The other three types of control message can be
                // handled by similar code.
                usbs_control_return (*callback_fn)(usbs_control_endpoint*, void*);
                void* callback_arg;
                //DBG(("non-standard control request %x", req->request));
                
                if (USB_DEVREQ_TYPE_CLASS == protocol) {
                    callback_fn  = ep0.common.class_control_fn;
                    callback_arg = ep0.common.class_control_data;
                } else if (USB_DEVREQ_TYPE_VENDOR == protocol) {
                    callback_fn  = ep0.common.vendor_control_fn;
                    callback_arg = ep0.common.vendor_control_data;
                } else {
                    callback_fn  = ep0.common.reserved_control_fn;
                    callback_arg = ep0.common.reserved_control_data;
                }

                if ((usbs_control_return (*)(usbs_control_endpoint*, void*)) 0 == callback_fn) {
                    result = USBS_CONTROL_RETURN_STALL;
                } else {
                    result = (*callback_fn)(&ep0.common, callback_arg);
                }
            }
            //DBG(("Control request done, %d\n", result));

            if (USBS_CONTROL_RETURN_HANDLED != result) {
                // This control request cannot be handled. Generate a stall.
                usbs_sa11x0_poke(EP0_CONTROL,
                                 EP0_FORCE_STALL | EP0_SERVICED_OPR | EP0_DATA_END,
                                 EP0_FORCE_STALL,
                                 EP0_OUT_READY);
            } else {
                // The control request has been handled. Is there any more
                // data to be transferred?
                if (0 == length) {
                    usbs_sa11x0_poke(EP0_CONTROL,
                                     EP0_SERVICED_OPR | EP0_DATA_END,
                                     EP0_DATA_END,
                                     EP0_OUT_READY);
                } else {
                    // The endpoint should now go into IN or OUT mode while the
                    // remaining data is transferred.
                    ep0.transmitted     = 0;
                    ep0.length          = length;
                    if (USB_DEVREQ_DIRECTION_OUT == direction) {
                        // Wait for the next packet from the host.
                        ep0.ep_state = EP0_STATE_OUT;
                        CYG_ASSERT( (unsigned char*) 0 != ep0.common.buffer, "A receive buffer should have been provided");
                        CYG_ASSERT( (usbs_control_return (*)(usbs_control_endpoint*, int))0 != ep0.common.complete_fn, \
                                    "A completion function should be provided for OUT control messages");
                    } else {
                        ep0.ep_state = EP0_STATE_IN;
                        usbs_sa11x0_ep0_fill_fifo();
                    }
                }
            }   // Control message handled
        }       // Received 8-byte control message
    }           // Idle state, i.e. control message
}               // ep0_dsr

#ifdef CYGPKG_DEVS_USB_SA11X0_EP1
// ----------------------------------------------------------------------------
// Endpoint 1 is used for OUT transfers, i.e. receive operations. Only
// the bulk protocol is supported by the hardware. The semantics allow
// for two different modes of operation: higher-level code can ask for
// exactly one or more bulk packets of 64 bytes each, allowing buffer
// requirements to be determined from a header; alternatively the
// rx request can just supply a large buffer. Processing the first
// packet of a larger transfer separately does not introduce any
// special problems at the protocol level.
//
// It is not legal to receive just part of a packet and expect the
// hardware or the driver to buffer the rest. Not all hardware will
// be capable of doing this buffering, and there should not be
// a driver design requirement to provide buffering space.
//
//
// The hardware design for endpoint 1 is flawed in a number of
// respects. The receive fifo is only 20 bytes, less than the packet
// size, so it is essential to use DMA (there is a configuration
// option to allow for communication protocols where packets will
// never exceed 16 bytes, but that is not the normal case). The DMA
// engine is triggered by a receive-fifo-service high-water mark
// bit. DMA transfers operate in bursts of eight bytes. Therefore
// it would make sense if the high-water mark was set when the
// receive fifo contained eight bytes or more.
//
// Instead the high-water mark is set when the fifo contains twelve
// bytes or more. Worse, there is no way of measuring how many bytes
// there are left in the fifo without actually extracting those bytes.
//
// For a full-size 64-byte packet, the first 56 bytes will be
// transferred by DMA and the remainder will remain in the fifo. For a
// partial packet of between 56 and 63 bytes, the first 56 bytes will
// be transferred by DMA and the remainder will remain in the fifo. There
// is no way to distinguish between these scenarios without emptying
// the fifo.
//
// The result is that there is never any point in attempting a DMA
// transfer of more than 56 bytes, and for every endpoint 1 interrupt
// it is necessary to read the remainder from the fifo. This adds
// a lot of software overhead, and it is not clear that DMA is
// particularly useful. It is still necessary because of the limited
// fifo size.
//
//
// Because DMA involves the use of physical rather than virtual
// memory, there are also cache interaction problems. Specifically it
// would be necessary to invalidate cache lines after a DMA transfer
// has completed, but that only works sensibly if the buffer is
// aligned to a cache-line boundary and is a multiple of the
// cache-line size. Imposing such restrictions on higher-level code
// is undesirable. Also the DMA engines have an apparently undocumented
// restriction that the buffer must be eight-byte aligned.
//
// To work around all these problems, the receive code works in terms
// of a small private buffer. After a packet has been received, data
// will be copied from this private buffer to the destination. Obviously
// this copy operation is overhead and, because the code is expected
// to run at DSR level, However the copy operation is limited to at
// most 64 bytes, which is not good but not disastrous either.
//
// For data transfers the entry points are:
//
// 1) ep1_start_rx_packet() - prepare to receive another packet from
//    the host.
// 2) ep1_clear_error() - an error condition has occurred (CRC,
//    bit-stuffing, fifo overrun). It appears that the only way
//    to clear this is to clear the receive-packet-complete bit,
//    which unfortunately allows in another packet from the host
//    before we are ready for it. Doing anything else while
//    the error bit is set does not work, for example it is not
//    possible to empty the fifo by hand.
// 3) ep1_process_packet() - a whole packet has been received
//    and now needs to be moved into application space.
//
// These three routines are called by the start_rx() routine and
// by the DSR. There are different implementations for DMA and
// non-DMA.
//
// There is another hardware problem: the receive-packet-complete bit
// comes up with the wrong default value, allowing the host to start
// transmitting before the target is ready to receive. Unfortunately
// there is not much that can be done about this: the
// receive-packet-complete bit cannot be set by software and the OUT
// max register has a minimum size of eight bytes. Fortunately for
// many protocols the target-side code has a chance to start a receive
// before the host is allowed to send, so this problem is ignored for
// now.
//
// Another potential problem arises if the host sends more data than
// is expected for a given transfer. It would be possible to address
// this by manipulating the OUT max packet register and getting the
// hardware to generate protocol violation stalls. This would also
// eliminate the need to test for buffer overflows. For now it is
// left to higher-level code to sort it all out.

#ifdef CYGNUM_DEVS_USB_SA11X0_EP1_DMA_CHANNEL

// DMA needs an area of physical memory. To avoid conflicts with
// the cached shadow of this memory, this area needs to start at
// a cache line boundary and there must be padding at the end
// to the next cache line boundary, thus ensuring that the
// processor will not accidentally overwrite the physical
// memory because it is manipulating some other variable.
//
// NOTE: at the time of writing the toolchain has a problem with
// the aligned attribute, so instead the start alignment has
// to be handled in software.

# define EP1_DMA_MTU            56
# define EP1_DMA_BUFSIZE        ((EP1_DMA_MTU + HAL_DCACHE_LINE_SIZE - 1) - \
                                 ((EP1_DMA_MTU + HAL_DCACHE_LINE_SIZE - 1) % HAL_DCACHE_LINE_SIZE))
# define EP1_DMA_ALLOCSIZE      (EP1_DMA_BUFSIZE + HAL_DCACHE_LINE_SIZE - 1)

static unsigned char    ep1_dma_data[EP1_DMA_ALLOCSIZE];

// This variable cannot be initialized statically, instead it is
// set by ep1_init(). It corresponds to the physical address
// for the buffer.
static unsigned char*   ep1_dma_buf;

static void
ep1_start_rx_packet(void)
{
    int dma_size = EP1_DMA_MTU;

    // This assertion does not always hold: clearing an error condition
    // involves the packet-complete bit so another message may have
    // started to arrive.
    // CYG_ASSERT( 0 == (EP1_FIFO_NOT_EMPTY & *EP1_CONTROL), "The receive fifo should be empty");
    
    CYG_ASSERT( 0 == ((DMA_CONTROL_RUN | DMA_CONTROL_START_A) & *EP1_DMA_STATUS), "EP1 DMA should be inactive");

#ifdef FAILURES
    ep1_failure = (ep1_failure + 1) % 32;
    if (0 == ep1_failure) {
  

⌨️ 快捷键说明

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