usbs_sa11x0.c

来自「开放源码实时操作系统源码.」· C语言 代码 · 共 1,380 行 · 第 1/5 页

C
1,380
字号
//==========================================================================
//
//      usbs_sa11x0.c
//
//      Device driver for the SA11x0 USB port.
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):    bartv
// Contributors: bartv
// Date:         2000-10-04
//
// This code implements support for the on-chip USB port on the SA11x0
// family of processors. The code has been developed on the SA1110 and
// may or may not work on other members of the SA11x0 family. There
// have problems with the USB support on certain revisions of the silicon,
// so the errata sheet appropriate to the specific processor being used
// should be consulted. There also appear to be problems which do not
// appear on any errata, which this code attempts to work around.
//
//####DESCRIPTIONEND####
//==========================================================================

#include <cyg/infra/cyg_type.h>
#include <cyg/infra/cyg_ass.h>
#include <cyg/infra/cyg_trac.h>
#include <cyg/infra/diag.h>

#include <pkgconf/hal_arm.h>
#include <pkgconf/devs_usb_sa11x0.h>

#include <cyg/hal/drv_api.h>
#include <cyg/hal/hal_arch.h>
#include <cyg/hal/hal_io.h>
#include <cyg/hal/hal_cache.h>
#include <cyg/hal/hal_sa11x0.h>
#include <cyg/error/codes.h>

#include <cyg/io/usb/usb.h>
#include <cyg/io/usb/usbs.h>

// Debugging support. By default this driver operates mostly at
// DSR level, with the ISR doing a minimal amount of processing.
// However is also possible to run most of the code at thread-level,
// This is subject to some restrictions because the USB standard
// imposes timing constraints, e.g. some control operations such
// as SET-ADDRESS have to complete within 50ms. However it is
// very useful for debugging, specifically it allows you to put
// printf()'s in various places.
//
// Right now these configuration options are not exported to the
// user because running at DSR level is likely to be good enough
// for everybody not actively debugging this code. The options
// could be exported if necessary.
//#define CYGPKG_DEVS_USB_SA11X0_THREAD
#undef CYGPKG_DEVS_USB_SA11X0_THREAD
#ifdef CYGPKG_DEVS_USB_SA11X0_THREAD
  // Default stack size should be CYGNUM_HAL_STACK_SIZE_TYPICAL
# define CYGNUM_DEVS_USB_SA11X0_THREAD_STACK_SIZE       4096
# define CYGNUM_DEVS_USB_SA11X0_THREAD_PRIORITY         7
# include <cyg/kernel/kapi.h>
#endif

#if 0
# define DBG(a) diag_printf a
#else
# define DBG(a)
#endif

#undef FAILURES
#ifdef FAILURES
static volatile int ep1_failure = 7;
#endif

#undef STATS
#ifdef STATS
int ep1_receives = 0;
int ep1_errors = 0;
int ep2_transmits = 0;
int ep2_errors = 0;
# define INCR_STAT(a) (a) += 1
# define SET_STAT(a, b) (a) = (b)
#else
# define INCR_STAT(a)
# define SET_STAT(a, b)
#endif

// ----------------------------------------------------------------------------
// Serial port 0 on the SA11x0 provides a USB slave connection (aka a
// USB device controller or UDC). The functionality is somewhat
// limited, there are just three endpoints.
//
// Endpoint 0 can only be used for control messages. It has an 8 byte
// fifo which cannot be connected to a DMA engine. Hence incoming
// control packets have to be limited to 8 bytes by the enumeration
// data. The endpoint has to be managed at a low-level, i.e. the
// incoming request has to be extracted from the fifo, processed, and
// any response put back into the fifo within the permitted USB
// response times.
//
// Endpoint 1 can only be used for host->slave bulk OUT transfers. It
// has a 20 byte receive fifo, and it can be hooked up to any of the
// six DMA engines. Since bulk transfers will typically involve 64
// byte packets, most applications will require the use of DMA.
//
// Endpoint 2 can only be used for slave-host bulk IN transfers. There
// is a 16 byte transmit fifo so small messages can be transferred in
// software. The fifo can also be hooked up to DMA, which is a more
// likely scenario.
//
// Start with definitions of the hardware. The use of a structure and
// a const base pointer should allow the compiler to do base/offset
// addressing and keep the hardware base address in a register. This
// is better than defining each hardware register via a separate
// address. Although the registers are only a byte wide, the peripheral
// bus only supports word accesses.
//
// The USBS_CONTROL etc. macros allow for an alternative way of
// accessing the hardware if a better approach is presented, without
// having to rewrite all the code. Macros that correspond to registers
// are actually addresses, making it easier in the code to distinguish
// them from bit values: the & and * operators will just cancel out.

typedef struct usbs_sa11x0_hardware {
    volatile int control;
    volatile int address;
    volatile int out_size;
    volatile int in_size;
    volatile int ep0_control;
    volatile int ep1_control;
    volatile int ep2_control;
    volatile int ep0_data;
    volatile int ep0_write_count;
             int dummy1;
    volatile int fifo;
             int dummy2;
    volatile int status;
} usbs_sa11x0_hardware;

static usbs_sa11x0_hardware* const usbs_sa11x0_base = (usbs_sa11x0_hardware* const) 0x80000000;
#define USBS_CONTROL    (&(usbs_sa11x0_base->control))
#define USBS_ADDRESS    (&(usbs_sa11x0_base->address))
#define USBS_OUT_SIZE   (&(usbs_sa11x0_base->out_size))
#define USBS_IN_SIZE    (&(usbs_sa11x0_base->in_size))
#define EP0_CONTROL     (&(usbs_sa11x0_base->ep0_control))
#define EP1_CONTROL     (&(usbs_sa11x0_base->ep1_control))
#define EP2_CONTROL     (&(usbs_sa11x0_base->ep2_control))
#define EP0_DATA        (&(usbs_sa11x0_base->ep0_data))
#define EP0_WRITE_COUNT (&(usbs_sa11x0_base->ep0_write_count))
#define EP1_DATA        (&(usbs_sa11x0_base->fifo))
#define EP2_DATA        (&(usbs_sa11x0_base->fifo))
#define USBS_STATUS     (&(usbs_sa11x0_base->status))

#define CONTROL_DISABLE                 (1 << 0)
#define CONTROL_ACTIVE                  (1 << 1)
// The meaning of bit 2 changed, see errata
#define CONTROL_RESUME_INTR             (1 << 2)
#define CONTROL_EP0_INTR                (1 << 3)
#define CONTROL_EP1_INTR                (1 << 4)
#define CONTROL_EP2_INTR                (1 << 5)
// The meaning of bit 6 also changed, see errata
#define CONTROL_SUSPEND_INTR            (1 << 6)
#define CONTROL_RESET_INTR              (1 << 7)

// Getting the control register settings right is a little bit tricky.
// Bit 0 is the disable bit so touching that is dangerous, and the
// other bits have inverted meanings i.e. 0 enables interrupts. The
// following macro encapsulates this.
#define CONTROL_ALL_INTR                0x00FC
#define CONTROL_INTR_ENABLE(bits)  ((~(bits)) & CONTROL_ALL_INTR)
#define CONTROL_INTR_CLEAR(bits)   ((bits) & CONTROL_ALL_INTR)

// All the endpoint interrupt numbers can be handled en masse,
// but some of the endpoints may be disabled.
#if defined(CYGPKG_DEVS_USB_SA11X0_EP1) && defined(CYGPKG_DEVS_USB_SA11X0_EP2)
# define CONTROL_EP_INTR_BITS      (CONTROL_EP0_INTR | CONTROL_EP1_INTR | CONTROL_EP2_INTR)
#elif defined(CYGPKG_DEVS_USB_SA11X0_EP1)
# define CONTROL_EP_INTR_BITS      (CONTROL_EP0_INTR | CONTROL_EP1_INTR)
#elif defined(CYGPKG_DEVS_USB_SA11X0_EP2)
# define CONTROL_EP_INTR_BITS      (CONTROL_EP0_INTR | CONTROL_EP2_INTR)
#else
# define CONTROL_EP_INTR_BITS      (CONTROL_EP0_INTR)
#endif

#define EP0_OUT_READY                   (1 << 0)
#define EP0_IN_READY                    (1 << 1)
#define EP0_SENT_STALL                  (1 << 2)
#define EP0_FORCE_STALL                 (1 << 3)
#define EP0_DATA_END                    (1 << 4)
#define EP0_SETUP_END                   (1 << 5)
#define EP0_SERVICED_OPR                (1 << 6)
#define EP0_SERVICED_SETUP_END          (1 << 7)

#define EP1_FIFO_SERVICE                (1 << 0)
#define EP1_PACKET_COMPLETE             (1 << 1)
#define EP1_PACKET_ERROR                (1 << 2)
#define EP1_SENT_STALL                  (1 << 3)
#define EP1_FORCE_STALL                 (1 << 4)
#define EP1_FIFO_NOT_EMPTY              (1 << 5)

#define EP2_FIFO_SERVICE                (1 << 0)
#define EP2_PACKET_COMPLETE             (1 << 1)
#define EP2_PACKET_ERROR                (1 << 2)
#define EP2_PACKET_UNDERRUN             (1 << 3)
#define EP2_SENT_STALL                  (1 << 4)
#define EP2_FORCE_STALL                 (1 << 5)

#define STATUS_EP0_INTR                 (1 << 0)
#define STATUS_EP1_INTR                 (1 << 1)
#define STATUS_EP2_INTR                 (1 << 2)
#define STATUS_SUSPEND_INTR             (1 << 3)
#define STATUS_RESUME_INTR              (1 << 4)
#define STATUS_RESET_INTR               (1 << 5)

#define EP0_FIFO_SIZE                     8
#define EP0_MTU                           8

#define EP1_FIFO_SIZE                   20
#ifdef CYGNUM_DEVS_USB_SA11X0_EP1_DMA_CHANNEL
# define EP1_MTU                        64
#else
# define EP1_MTU                        16
#endif

#define EP2_FIFO_SIZE                   16
#ifdef CYGNUM_DEVS_USB_SA11X0_EP2_DMA_CHANNEL
# define EP2_MTU                        64
#else
# define EP2_MTU                        16
#endif

#if defined(CYGNUM_DEVS_USB_SA11X0_EP1_DMA_CHANNEL) || defined(CYGNUM_DEVS_USB_SA11X0_EP2_DMA_CHANNEL)
typedef struct usbs_sa11x0_dma {
    volatile int                address;
    volatile int                control_set;
    volatile int                control_clear;
    volatile int                status;
    volatile int                buf_a_address;  // Absolute, not remapped
    volatile int                buf_a_size;
    volatile int                buf_b_address;  // Absolute, not remapped
    volatile int                buf_b_size;
} usbs_sa11x0_dma;

⌨️ 快捷键说明

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