📄 sx2usbdrv.c
字号:
/*
sx2UsbDrv.c - Low level VxWorks driver for Cypress EZ-USB SX2 high speed
USB peripheral device.
*/
/*
modification history
--------------------
01a,05nov01,hab Created
*/
/*
DESCRIPTION
This module implements the low-level, chip-specific driver portion for the
Cypress SX2. The driver module is initialized through a call to sx2DrvInit().
The driver provides an API specified by Cypress Semiconductor. Refer to
sx2UsbDrv.h and the driver User's Guide for a list of externally callable
API functions.
Compile-time driver configuration is achieved through macros defined
in sx2HostCpu.h:
The macro SX2_BUS_WIDTH should be set to match the bus width used by
the SX2, i.e. if 8 or 16 SX2 data bits are wired to the host CPU.
The macro SX2_FIFO_WIDTH determines if the SX2 FIFOs are accessed in
8 or 16 bit mode. This macro is only effective if the data bus is
16 bits wide, i.e. SX2_BUS_WIDTH is set to SX2_BUS_16BIT.
Endianness is addressed by using appropriate byte swapping macros.
See sx2HostCpu.h for details.
The SX2 driver is designed to be host CPU and BSP independent. Calls to host
CPU and BSP specific routines are made through function pointers in the
HOST_CPU data structure. Refer to the host CPU specifc module sx2HostCpu.c
for more details.
Run-time flexibility and configurability is provided through hook mechanisms.
Hook functions can be registered for the main interrupt service routine,
in order to execute additional code at interrupt level.
Hooks can also be specified for notification purposes, upon read/write
completion. Refer to the driver User's Guide for more information.
*/
#include "vxWorks.h"
#include "intLib.h"
#include "taskLib.h"
#include "msgQLib.h"
#include "iv.h"
#include "stdio.h"
#include "logLib.h"
#include "sx2UsbDrv.h"
/* globals */
UINT16 sx2IntCause = 0;
/* prototypes for internal routines */
LOCAL VOID sx2Isr(UINT32 param);
LOCAL STATUS sx2WriteNibbles(UINT8 data);
LOCAL STATUS sx2DrvCleanup(VOID);
LOCAL STATUS sx2FlushFifos(VOID);
LOCAL STATUS sx2SetFifoWidth(VOID);
/* driver debug flag */
#undef SX2_DEBUG
/* include the host CPU specific driver module and default data defs */
#include "sx2HostCpu.c"
#include "sx2DataDefs.c"
/*******************************************************************************
*
* sx2DrvInit - Initialize the SX2 driver for operation.
*
* The options parameter allows selective initialization of the SX2 as follows
*
* SX2_REGS_INIT - initialize SX2 regs as defined in sx2Regs array (sx2UsbDrv.h)
* SX2_ENUMERATE - perform enumeration using standard descriptor (sx2UsbDrv.h)
* SX2_FLUSH_FIFOS - Flush all FIFOs
*
* RETURNS: OK or ERROR if initialization failed.
*/
STATUS sx2DrvInit(UINT32 options)
{
UINT32 timeout = 0;
UINT32 level;
/* call host CPU specific init routine */
if (sx2HostCpuInit() != OK)
return (ERROR);
/* connect main SX2 ISR and enable interrupt */
level = intLock();
if (intConnect (INUM_TO_IVEC(hostCpu.sx2IntVec), sx2Isr, 0) == ERROR)
{
intUnlock(level);
sx2DrvCleanup();
return (ERROR);
}
intEnable (hostCpu.sx2IntVec);
intUnlock(level);
/* Wait for the occurrence of the READY interrupt before proceeding.
This interrupt occurs after successful completion of the SX2's
self-test, and should have occurred long before the vxWorks boot
sequence completes. */
while ((!hostCpu.sx2Initialized) && (timeout++ < READY_TIMEOUT));
/* return ERROR if we timed out waiting for READY interrupt */
if (timeout == READY_TIMEOUT)
{
sx2DrvCleanup();
return (ERROR);
}
/* perform additional initialization based on options parameter */
/* if requested, set all SX2 registers to default values */
if (options & SX2_REGS_INIT)
{
if (sx2Configure(sx2Regs) == ERROR)
{
sx2DrvCleanup();
return (ERROR);
}
}
/* configure the FIFOs for correct access width */
if (sx2SetFifoWidth() == ERROR)
{
sx2DrvCleanup();
return (ERROR);
}
/* if requested, perform enumeration */
if (options & SX2_ENUMERATE)
{
if (sx2SetDescriptor ((UINT8 *)&sx2Descr, sizeof(sx2Descr)) == ERROR)
{
sx2DrvCleanup();
return (ERROR);
}
}
/* if requested, flush all FIFOs */
if (options & SX2_FLUSH_FIFOS)
{
if (sx2FlushFifos() == ERROR)
{
sx2DrvCleanup();
return (ERROR);
}
}
return (OK);
}
/*******************************************************************************
*
* sx2ReadReg - Read an SX2 register.
*
* RETURNS: OK or ERROR if register is invalid.
*/
STATUS sx2ReadReg(UINT8 reg, UINT8 *data)
{
UINT32 level;
/* check register for validity */
if ((reg < SX2_REG_BOTTOM) || (reg > SX2_REG_TOP))
return (ERROR);
/*
In order to read a register, we first need to issue a read rgister request.
The SX2 signals the availability of the data with a dedicated read interrupt
which does NOT have a bit in the IRQ reg. Therefore, the only way for the ISR
to know that it's dealing with a read interrupt, is to set a global flag,
right before the read request.
*/
level = intLock();
/* setup read interrupt sync flag */
if (intContext())
{
hostCpu.readSyncFlag = READER_IS_INT;
}
else
{
hostCpu.readSyncFlag = READER_IS_TASK;
}
/* initiate a register read request */
(*hostCpu._func_hostCpuWrite) (hostCpu.sx2Cmd,
SX2_WORD_SWAP(reg|SX2_CMD_ADDR|SX2_CMD_READ));
/* unlock interrupts */
intUnlock (level);
/* wait for read interrupt from SX2 */
if (intContext())
{
/* interrupt context, wait for ISR to clear flag */
while (hostCpu.readSyncFlag);
}
else
{
/* task context, wait for the ISR to give sync semaphore */
if (semTake (hostCpu.readSyncSem, WAIT_FOREVER) == ERROR)
return (ERROR);
}
/* read data */
*data = (UINT8)SX2_WORD_SWAP((*hostCpu._func_hostCpuRead) (hostCpu.sx2Cmd));
/* if a read register notification hook exists, invoked it.
sx2ReadReg() returns OK or ERROR as returned by the hook. */
if (hostCpu._func_readRegNotifyHook != NULL)
{
return ((*hostCpu._func_readRegNotifyHook)(0));
}
return (OK);
}
/*******************************************************************************
*
* sx2WriteReg - Write an SX2 register.
*
* RETURNS: OK or ERROR if register is invalid or write fails.
*/
STATUS sx2WriteReg(UINT8 reg, UINT8 data)
{
UINT32 level;
/* check register for validity */
if ((reg < SX2_REG_BOTTOM) || (reg > SX2_REG_TOP))
return (ERROR);
/* The entire write sequence has to be atomic to support writes by
multiple tasks and from interrupt context. We could use mutex semaphores
if sx2WriteReg were only called by tasks, not ISRs. For now, the assumption
is that both tasks and ISRs might be calling sx2WriteReg(). */
level = intLock();
/* wait for READY to go high */
if ((*hostCpu._func_waitReady)() != OK)
{
intUnlock(level);
return (ERROR);
}
/* initiate a register write request */
(*hostCpu._func_hostCpuWrite) (hostCpu.sx2Cmd,
SX2_WORD_SWAP((reg|SX2_CMD_ADDR)&SX2_CMD_WRITE));
/* write one nibble at a time */
if (sx2WriteNibbles(data) != OK)
{
intUnlock(level);
return (ERROR);
}
/* unlock interrupts */
intUnlock(level);
/* if a write register notification hook exists, invoked it.
sx2WriteReg() returns OK or ERROR as returned by the hook. */
if (hostCpu._func_writeRegNotifyHook != NULL)
{
return ((*hostCpu._func_writeRegNotifyHook)(0));
}
return (OK);
}
/*******************************************************************************
*
* sx2ReadFifo - Read data from specified FIFO into provided buffer.
*
* RETURNS: OK or ERROR.
*/
STATUS sx2ReadFifo(UINT8 fifo, UINT8 *buf, UINT32 numBytes)
{
UINT32 i;
#if (SX2_FIFO_WIDTH == SX2_FIFO_16BIT)
UINT16 val;
#endif
/* check validity of parameters */
if ((fifo != SX2_FIFO2) && (fifo != SX2_FIFO4)
&& (fifo != SX2_FIFO6) && (fifo != SX2_FIFO8))
return (ERROR);
/* read numBytes from the specified FIFO */
#if (SX2_FIFO_WIDTH == SX2_FIFO_16BIT)
/* 16 bit wide FIFOs */
for (i=0; i<numBytes/2; i++)
{
val = (UINT16)SX2_WORD_SWAP((*hostCpu._func_hostCpuRead)(SX2REG(fifo)));
buf[i*2] = val & 0x00FF;
buf[(i*2)+1] = (val >> 8) & 0x00FF;
}
/* account for odd number of bytes */
if (numBytes%2 != 0)
{
buf[numBytes-1] = (UINT8)SX2_WORD_SWAP((*hostCpu._func_hostCpuRead)(SX2REG(fifo)));
}
#else
{
/* 8 bit wide FIFOs */
for (i=0; i<numBytes; i++)
{
buf[i] = (UINT8)SX2_WORD_SWAP((*hostCpu._func_hostCpuRead)(SX2REG(fifo)));
}
}
#endif
/* if a read fifo notification hook exists, invoked it.
sx2ReadFifo() returns OK or ERROR as returned by the hook. */
if (hostCpu._func_readFifoNotifyHook != NULL)
{
return ((*hostCpu._func_readFifoNotifyHook)(0));
}
return (OK);
}
/*******************************************************************************
*
* sx2WriteFifo - Write data from buffer to specified FIFO.
*
* RETURNS: OK or ERROR.
*/
STATUS sx2WriteFifo(UINT8 fifo, UINT8 *buf, UINT32 numBytes)
{
UINT32 i;
#if (SX2_FIFO_WIDTH == SX2_FIFO_16BIT)
UINT16 val;
#endif
/* check validity of parameters */
if ((fifo != SX2_FIFO2) && (fifo != SX2_FIFO4)
&& (fifo != SX2_FIFO6) && (fifo != SX2_FIFO8))
return (ERROR);
/* write numBytes to specified FIFO */
#if (SX2_FIFO_WIDTH == SX2_FIFO_16BIT)
/* 16 bit wide FIFOs */
for (i=0; i<numBytes/2; i++)
{
val = (buf[(i*2)+1] << 8) | (buf[i*2]);
(*hostCpu._func_hostCpuWrite) (SX2REG(fifo), SX2_WORD_SWAP(val));
}
/* account for odd number of bytes */
if (numBytes%2 != 0)
{
(*hostCpu._func_hostCpuWrite) (SX2REG(fifo), SX2_WORD_SWAP(buf[numBytes-1]));
}
#else
{
/* 8 bit wide FIFOs */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -