?? sndsintrctl.c
字號(hào):
/* sndsIntrCtl.c - Samsung SNDS100 interrupt controller driver */
/*
modification history
--------------------
01b,27sep99,nb updated documentation
01a,20aug99,knp adapted from WRS template
*/
/*
DESCRIPTION
This module implements interrupt controller driver for Samsung's SNDS100
evaluation board. This board is an evaluation board for their KS32C50100
microprocessor. This is an ARM based processor with several integrated
peripherals. It has an interrupt controller, two 32-bit timers, one
Ethernet controller, two HDLC controllers, one IIC controller, general
purpose I/O ports, and a 2-channel DMA controller.
The SNDS interrupt controller is a simple, generic interrupt controller
that manages 21 levels of interrupts from various sources internal to the
microprocessor and external to it. For external interrupts are supported.
The interrupt controller has control and pending status registers, mask
register and supports level-sensitive interrupts. This library provides
the routines to manage interrupts multiplexed by the SNDS interrupt controller.
The SNDS interrupt controller registers used by this driver are described
below under the symbolic names used herein.
SNDS_INT_CSR_ENB (write): this is the mask register described in the
KS32C50100 Users' Manual. When this register is written, each data bit
that is clear (0) causes the corresponding interrupt to be enabled.
Each bit that is set (1) causes the corresponding interrupt to be disabled.
SNDS_INT_CSR_PEND (read): this is the interrupt pending register.
When this register is read, each data bit that is set (1) indicates that
an interrupt is pending from the corresponsing source. Level 20 is the
highest priority and level 0 is the lowest.
SNDS_INT_CSR_MODE (write): this register is used to configure the interrupts
in FIQ or IRQ mode. Each bit set in this register configures the corresponding
interrupt as FIQ. Otherwise the interrupt is treated as IRQ. VxWorks
does not support the high priority FIQ mode of interrupts. Hence all the
interrupts have to be configured in IRQ mode.
The interrupt priority registers can be used to change the priorities
of the interrupts from the default settings. This feature is not
supported in this driver. All the interrupts are set with the default
priority ordering.
The number of interrupts supported by the device i.e. the number of
valid bits in the SNDS_INT_CSR_PEND register (21), is specified by
SNDS_INT_NUM_LEVELS.
snds100.h has defined the addresses of the controller chips registers:
SNDS_INT_CSR_ENB, SNDS_INT_CSR_DIS and SNDS_INT_CSR_PEND and also the
driver constants SNDS_INT_CSR_MASK, SNDS_INT_NUM_LEVELS.
The chip registers are memory-mapped at specified addresses internal to
the processor. 32-bit accesses can be made to these register locations.
The macros SNDS_INT_REG_READ and SNDS_INT_REG_WRITE are used to
access these registers.
The BSP will initialize this driver in sysHwInit2(), after initializing
the main interrupt library, usually intLibInit(). The initialization
routine, sndsIntDevInit() will setup the interrupt controller device,
it will mask off all individual interrupt sources and then set the
interrupt level to enable all interrupts. See sndsIntDevInit for more
information.
All of the functions in this library are global. This allows them to
be used by the BSP if it is necessary to create wrapper routines or to
incorporate several drivers together as one.
*/
#include "vxWorks.h"
#include "config.h"
#include "intLib.h"
/* Defines from snds100.h */
#if !defined (SNDS_INT_CSR_PEND) || !defined (SNDS_INT_CSR_ENB) || \
!defined (SNDS_INT_CSR_MASK) || !defined (SNDS_INT_NUM_LEVELS) || \
!defined (SNDS_INT_CSR_DIS)
# error missing SNDS interrupt definitions
#endif
#define SNDS_INT_VEC_BASE (0x0)
/* hardware access methods */
#ifndef SNDS_INT_REG_READ
# define SNDS_INT_REG_READ(x,result) \
((result) = *(volatile UINT32 *)(x))
#endif /*SNDS_INT_REG_READ*/
#ifndef SNDS_INT_REG_WRITE
# define SNDS_INT_REG_WRITE(x,data) \
(*((volatile UINT32 *)(x)) = (data))
#endif /*SNDS_INT_REG_WRITE*/
/* Convert level number to vector number */
#ifndef SNDS_INT_LVL_VEC_MAP
# define SNDS_INT_LVL_VEC_MAP(level, vector) \
((vector) = ((level) + SNDS_INT_VEC_BASE))
#endif
/* Convert pending register value, to a level number */
#ifndef SNDS_INT_PEND_LVL_MAP
# define SNDS_INT_PEND_LVL_MAP(pendReg, level) \
((level) = (pendReg))
#endif
/* driver constants */
#define SNDS_INT_ALL_ENABLED (SNDS_INT_NUM_LEVELS)
#define SNDS_INT_ALL_DISABLED (SNDS_INT_NUM_LEVELS-1)
/* Local data */
/*
* A mask word. Bits are set in this word when a specific level
* is enabled. It is used to mask off individual levels that have
* not been explicitly enabled.
*/
LOCAL UINT32 sndsIntLvlEnabled;
/* forward declarations */
STATUS sndsIntLvlVecChk (int*, int*);
STATUS sndsIntLvlEnable (int);
STATUS sndsIntLvlDisable (int);
/*******************************************************************************
*
* sndsIntDevInit - initialize the interrupt controller
*
* This routine will initialize the interrupt controller device, disabling all
* interrupt sources. It will also connect the device driver specific routines
* into the architecture level hooks. If the BSP needs to create a wrapper
* routine around any of the arhitecture level routines, it should install the
* pointer to the wrapper routine after calling this routine.
*
* RETURNS: N/A
*/
void sndsIntDevInit (void)
{
/* install the driver routines in the architecture hooks */
sysIntLvlVecChkRtn = sndsIntLvlVecChk;
sysIntLvlEnableRtn = sndsIntLvlEnable;
sysIntLvlDisableRtn = sndsIntLvlDisable;
sndsIntLvlEnabled = 0x0; /* all sources disabled */
SNDS_INT_REG_WRITE (SNDS_INT_CSR_ENB, ((~sndsIntLvlEnabled) & SNDS_INT_CSR_MASK));
SNDS_INT_REG_WRITE (SNDS_INT_CSR_PEND, SNDS_INT_CSR_MASK);
SNDS_INT_REG_WRITE(SNDS_INT_CSR_MODE,SNDS_INT_MODE_IRQ);
}
/*******************************************************************************
*
* sndsIntLvlVecChk - check for and return any pending interrupts
*
* This routine interrogates the hardware to determine the highest priority
* interrupt pending. It returns the vector associated with that interrupt, and
* also the interrupt priority level prior to the interrupt (not the
* level of the interrupt). The current interrupt priority level is then
* raised to the level of the current interrupt so that only higher priority
* interrupts will be accepted until this interrupt is finished.
*
* The return value ERROR indicates that no pending interrupt was found and
* that the level and vector values were not returned.
*
* RETURNS: OK or ERROR if no interrupt is pending.
*/
STATUS sndsIntLvlVecChk
(
int* pLevel, /* ptr to receive old interrupt level */
int* pVector /* ptr to receive current interrupt vector */
)
{
int newLevel;
int intPendMask = 0x100000;
int count;
UINT32 isr;
/* Read pending interrupt register and mask undefined bits */
SNDS_INT_REG_READ (SNDS_INT_CSR_PEND, newLevel);
if ((newLevel & SNDS_INT_CSR_MASK) == 0)
return ERROR;
/*
* Step through the bits looking for a 1. This *will* terminate.
* We could use ffsLsb() for this if we don't mind the function call
* overhead
*/
for (count = 0, isr = 20; count < SNDS_INT_NUM_LEVELS; count++)
{
if (intPendMask & newLevel)
break;
isr--;
intPendMask >>= 1;
}
*pVector = isr;
/* Acknowledge the interrupt as given in SNDS100 sample code */
SNDS_INT_REG_WRITE(SNDS_INT_CSR_PEND,(1 << isr));
return OK;
}
/*******************************************************************************
*
* sndsIntLvlEnable - enable a single interrupt level
*
* Enable a specific interrupt level. The enabled level will be allowed to
* generate an interrupt, when the overall interrupt level is set below the
* specified level. Without being enabled, the interrupt is blocked regardless
* of the overall interrupt level setting.
*
* RETURNS: OK or ERROR if the specified level cannot be enabled.
*/
STATUS sndsIntLvlEnable
(
int level /* level to be enabled */
)
{
int key;
if (level < 0 ||
level >= SNDS_INT_NUM_LEVELS)
return ERROR;
/* clear bit in mask register */
key = intLock ();
sndsIntLvlEnabled |= ((1 << level));
intUnlock (key);
SNDS_INT_REG_WRITE (SNDS_INT_CSR_ENB, ((~sndsIntLvlEnabled) & SNDS_INT_CSR_MASK));
return OK;
}
/*******************************************************************************
*
* sndsIntLvlDisable - disable a single interrupt level
*
* Disable a specific interrupt level. The disabled level is prevented
* from generating an interrupt even if the overall interrupt level is set
* below the specified level.
*
* RETURNS: OK or ERROR, if the specified interrupt level cannot be disabled.
*/
STATUS sndsIntLvlDisable
(
int level /* level to be disabled */
)
{
int key;
if (level < 0 ||
level >= SNDS_INT_NUM_LEVELS)
return ERROR;
/* set bit in mask register */
key = intLock ();
sndsIntLvlEnabled &= ~(1 << level);
intUnlock (key);
SNDS_INT_REG_WRITE (SNDS_INT_CSR_ENB, ((~sndsIntLvlEnabled) & SNDS_INT_CSR_MASK));
return OK;
}
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -