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

📄 i8259intr.c

📁 VxWorks实时系统中的中断控制器驱动程序源代码。
💻 C
📖 第 1 页 / 共 2 页
字号:
/* i8259Intr.c - Intel 8259A PIC (Programmable Interrupt Controller) driver *//* Copyright 1984-2002 Wind River Systems, Inc. */#include "copyright_wrs.h"/*modification history--------------------01p,16apr02,hdn  added support for the Special Fully Nested Mode, IRQ0 Early		 EOI Mode, IRQ0 Special Mask Mode, AEOI Mode (spr 76411)01o,29mar02,hdn  added forgotten back slash to the optimized code01n,21mar02,hdn  fixed doc build by removing comments in the optimized code01m,25feb02,hdn  updated i8259Init() for HTT (spr 73738)		 added optimized version of EOI routines01l,11sep01,hdn  updated comment regarding the spr-28547 fix.01k,27aug99,hdn  fixed a bug for stray interrupt in i8259IntBoi(SPR 28547).01j,11oct98,ms   fixed compiler warning via typecast01i,04jun98,hdn  changed a method to exit i8259IntBoi().01h,25may98,hdn  changed function name starting from "i8259".		 added i8259IntEoiMaster(), i8259IntEoiSlave(), i8259IntBoi().		 removed sysIntEOI().01g,17mar97,hdn  added sysIntLock(), sysIntUnlock() for the system mode.01f,25jun96,hdn  added sysIntLevel() for windview.01e,23may96,wlf  doc: cleanup.01d,14jun95,hdn  renamed sysEndOfInt to sysIntEOI.		 moved global function prototypes to sysLib.h.01c,08aug94,hdn  stopped toggling IRQ9 in enabling and disabling.01b,22apr94,hdn  made IRQ9 off in the initialization.		 moved sysVectorIRQ0 to sysLib.c.01a,05sep93,hdn  written.*//*DESCRIPTIONThis module is a driver for the Intel 8259A PIC (Programmable InterruptController).  The Intel 8259A handles up to 8 vectored priority interruptsfor the CPU.  It is cascadable for up to 64 vectored priority interrupts,though this driver assumes two cascaded 8259A.  It is initialized for"Fully Nested Mode", "Non-Specific EOI" mode.Fully Nested Mode.In this mode, interrupt requests are ordered in priorityfrom 0 through 7 (0 is the highest priority).  When an interrupt isacknowledged, the highest priority request is determined and its vector isplaced on the bus.  Additionally, a bit of the Interrupt Service (IS)register is set.  This bit remains set until the microprocessor issues anEOI command immediately before returning from the service routine.  Whilethe IS bit is set, all further interrupts of the same or lower priorityare inhibited, while higher level interrupts are allowed.  Thei8259IntEoiSlaveNfnm() routine is used to issue the EOI command.  The PICsin a PC typically operate in this mode (normal nested mode).  In this mode,while the slave PIC is being serviced by the master PIC, the slave PIC blocksall higher priority interrupt requests.  Alternatively, to allow interrupts ofa higher priority, enable the Special Fully Nested Mode.Special Fully Nested Mode: I8259_SPECIAL_FULLY_NESTED_MODE.This mode is similar to the Fully Nested Mode with the following exceptions:1) When an interrupt request from a slave PIC is in service, the slave isnot locked out from the master's priority logic and further interruptrequests from higher priority IRs within the slave will be recognized bythe master and will initiate interrupts to the processor.  2) When exitingthe interrupt service routine, the software must check whether or not theinterrupt serviced was the only interrupt request from the slave.  If itwas the only interrupt request, a non-specific EOI is sent to the master.If not, no EOI is sent.  This is implemented by the i8259EoiSlaveSfnm()routine.Non-Specific EOI: When the 8259A is operated in the Fully Nested Mode, itcan determine which IS bit to reset on EOI.  When a non-specific EOIcommand is issued, the 8259A will automatically reset the highest IS bit ofthose that are set, since in the fully nested mode the highest IS level isthe last level acknowledged and serviced.Spurious/Phantom Interrupt: The IR inputs must remain high until after thefalling edge of the first INTA.  If the IR input goes low before this time,a DEFAULT(Spurious/Phantom) IR7 will occur when the CPU acknowledges theinterrupt.  The interrupt handler should simply return without sendingan EOI command.The PIC(8259A) IRQ0 is hard wired to the PIT(8253) channel 0 in a PCmotherboard.  IRQ0 is the highest priority in the 8259A interruptcontroller.  Thus, the system clock interrupt handler blocks all lowerlevel interrupts.  This may cause a delay of the lower level interrupts insome situations even though the system clock interrupt handler finishes itsjob without any delay.  This is quite natural from the hardware point ofview, but may not be ideal from the application software standpoint.  Thefollowing modes are supplied to mitigate this situation by providingcorresponding configuration macros in the BSP.  The three modes are mutuallyexclusive.Early EOI Issue in IRQ0 ISR.In this mode, the EOI command is issued before the IRQ0 system clock interruptservice routine starts the kernel work.  This lowers the IRQ0 ISR blockinglevel to the next lower level.  If no IRQs are in service, the next lowerlevel is the lowest level.  If IRQn is in service, the next lower levelcorresponds to the next lower priority.  As a result, the kernel work in thesystem clock interrupt service routine can be interrupted by an interruptwith a higher priority than the blocking level.  The i8259IntBoiEem() routine is called before the interrupt service routine, and no EOI is sent after the interrupt service routine.Special Mask Mode in IRQ0 ISR.In this mode, the Special Mask Mode is used in the IRQ0 system clockservice routine.  This lowers the blocking level to the specified level(currently hard coded to the lowest level).  The i8259IntBoiSmm() routineis called before the interrupt service routine, and the i8259IntEoiSmm()routine is called after the interrupt service routine.Automatic EOI Mode: I8259_AUTO_EOI.This mode provides no nested multi-level interrupt structure in PIC1.  TheEOI command is automatically sent to the master PIC at the end of theinterrupt acknowledge cycle.  Thus, no software intervention is needed.  Thei8259IntBoi() routine is called before the IRQ7 and IRQ15 interrupt serviceroutines.  Either the i8259IntEoiSlaveNfnm() routine or thei8259IntEoiSlaveSfnm() routine is called after the slave PIC's interruptservice routine.SEE ALSO: pc386/target.nr*/#include "drv/intrCtl/i8259.h"/* externs */IMPORT void	intBoiExit ();IMPORT UINT32	sysStrayIntCount;IMPORT BOOL	sysBp;		/* TRUE(default) for BP, FALSE for AP *//* defines */#define	I8259_EOI_OPTIMIZED	/* use the optimized version *//* globals *//* local */#ifndef	SYMMETRIC_IO_MODELOCAL INT8	i8259IntMask1;		/* interrupt mask for PIC1 */LOCAL INT8	i8259IntMask2;		/* interrupt mask for PIC2 */LOCAL INT8	i8259Mask = 0;		/* interrupt mask for PIC1 */#endif	/* SYMMETRIC_IO_MODE *//* forward static functions *//********************************************************************************* i8259Init - initialize the PIC** This routine initializes the PIC.**/VOID i8259Init (void)    {    UINT8 icw4 = 0x01;    /* return if it is not the Boot Processor (BP) */    if (sysBp == FALSE)	return;    /* initialize the PIC (Programmable Interrupt Controller) */    sysOutByte (PIC_port1 (PIC1_BASE_ADR),0x11);        /* ICW1 */    sysOutByte (PIC_port2 (PIC1_BASE_ADR),INT_NUM_IRQ0); /* ICW2 */    sysOutByte (PIC_port2 (PIC1_BASE_ADR),0x04);        /* ICW3 */#ifdef	I8259_SPECIAL_FULLY_NESTED_MODE    icw4 |= 0x10;					/* SFNM */#endif	/* I8259_SPECIAL_FULLY_NESTED_MODE */#ifdef	I8259_AUTO_EOI    icw4 |= 0x02;					/* AEOI */#endif	/* I8259_AUTO_EOI */    sysOutByte (PIC_port2 (PIC1_BASE_ADR),icw4);        /* ICW4 */    sysOutByte (PIC_port1 (PIC2_BASE_ADR),0x11);        /* ICW1 */    sysOutByte (PIC_port2 (PIC2_BASE_ADR),INT_NUM_IRQ0+8); /* ICW2 */    sysOutByte (PIC_port2 (PIC2_BASE_ADR),0x02);        /* ICW3 */    sysOutByte (PIC_port2 (PIC2_BASE_ADR),0x01);        /* ICW4 */    /* disable interrupts */    sysOutByte (PIC_IMASK (PIC1_BASE_ADR),0xfb);    sysOutByte (PIC_IMASK (PIC2_BASE_ADR),0xff);    }#ifndef	SYMMETRIC_IO_MODE/********************************************************************************* i8259IntBoiEem - issue EOI before the IRQ0 interrupt handler** This routine is called before the IRQ0 interrupt handler that is PIT(8253)* channel 0 system clock interrupt handler in the Early EOI Mode.**/VOID i8259IntBoiEem    (    int irqNo		/* IRQ number of the interrupt */    )    {    INT32 oldLevel = intLock ();			/* LOCK INTERRUPT */    sysOutByte (PIC_IACK (PIC1_BASE_ADR), 0x20);	/* NS EOI to PIC1 */    intUnlock (oldLevel);				/* UNLOCK INTERRUPT */    }/********************************************************************************* i8259IntBoiSmm - enable Special Mask Mode before the IRQ0 interrupt handler** This routine is called before the IRQ0 interrupt handler that is PIT(8253)* channel 0 system clock interrupt handler, in the Special Mask Mode.**/VOID i8259IntBoiSmm    (    int irqNo		/* IRQ number of the interrupt */    )    {    INT32 oldLevel = intLock ();			/* LOCK INTERRUPT */    sysOutByte (PIC_port1 (PIC1_BASE_ADR), 0x68);	/* enable SMM PIC1 */    i8259Mask = sysInByte (PIC_IMASK (PIC1_BASE_ADR));	/* save int mask */    sysOutByte (PIC_IMASK (PIC1_BASE_ADR), 0x01);	/* unlock except IRQ0 */    intUnlock (oldLevel);				/* UNLOCK INTERRUPT */    }/********************************************************************************* i8259IntBoi - detect whether it is spurious interrupt or not** This routine is called before the user's interrupt handler to detect the* spurious interrupt.**/VOID i8259IntBoi    (    INT32 irqNo		/* IRQ number of the interrupt */    )    {    INT32 oldLevel;    INT8 inserviceReg;    /* we are interested in IRQ7 and IRQ15 */    if ((irqNo != 7) && (irqNo != 15))	return;    /* if ISR bit is not set, we change the return address */    oldLevel = intLock ();		/* LOCK INTERRUPT */    if (irqNo == 7)	{        sysOutByte (PIC_port1 (PIC1_BASE_ADR), 0x0b);        inserviceReg = sysInByte (PIC_port1 (PIC1_BASE_ADR));	}    else	{        sysOutByte (PIC_port1 (PIC2_BASE_ADR), 0x0b);        inserviceReg = sysInByte (PIC_port1 (PIC2_BASE_ADR));	}        intUnlock (oldLevel);		/* UNLOCK INTERRUPT */    /*     * another implementation idea...     *     * *((UINT32 *)&irqNo - 1) = (UINT32)intBoiExit;     * This changes the return addr on the stack.  This is architecture     * specific and tricky.  Thus making following change may be good idea.     *      * - let this routine return OK or ERROR     * - let interrupt stub code check the ret value and jump to intExit.     *     * New code would be like this:     * :     * if ((irqNo != 7) && (irqNo != 15))     *	return (OK);     * :     * if ((inserviceReg & 0x80) == 0)	* check bit7 for IRQ7 and IRQ15 *     *	{     *	sysStrayIntCount++;		* increment the counter *     *  return (ERROR);     *	}     * }	     *     * 00  e8 kk kk kk kk           call    _intEnt         * tell kernel     * 05  50                       pushl   %eax            * save regs     * 06  52                       pushl   %edx     * 07  51                       pushl   %ecx     * 08  68 pp pp pp pp           pushl   $_parameterBoi  * push BOI param     * 13  e8 rr rr rr rr           call    _routineBoi     * call BOI routine     *                              addl    $4, %esp     *                              cmpl    $0, %eax     *                              jne     intConnectCode0     * 18  68 pp pp pp pp           pushl   $_parameter     * push param     * 23  e8 rr rr rr rr           call    _routine        * call C routine     *                              addl    $4, %esp     * 28  68 pp pp pp pp           pushl   $_parameterEoi  * push EOI param     * 33  e8 rr rr rr rr           call    _routineEoi     * call EOI routine     * 38  83 c4 04                 addl    $4, %esp        * pop param     * intConnectCode0:     * 41  59                       popl    %ecx            * restore regs     * 42  5a                       popl    %edx     * 43  58                       popl    %eax     * 44  e9 kk kk kk kk           jmp     _intExit        *  exit via kernel     */         if ((inserviceReg & 0x80) == 0)	/* check bit7 for IRQ7 and IRQ15 */	{	sysStrayIntCount++;		/* increment the counter */        *((UINT32 *)&irqNo - 1) = (UINT32)intBoiExit;	/* change return addr */

⌨️ 快捷键说明

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