home *** CD-ROM | disk | FTP | other *** search
- /* cintr.c -- code for interrupt management */
-
- /*****************************************************************************
- * Change Log
- * Date | Change
- *-----------+-----------------------------------------------------------------
- * 31-Dec-85 | Created changelog
- * 31-Dec-85 | Add c:\ to include directives
- * 31-Dec-85 | Save actual interrupt vector data; don't use constants
- * | (different on PC/AT and PC/XT)
- * 31-Dec-85 | Added intr_init
- * 31-Dec-85 | Handle secondary interrupt port for AT
- * 26-May-86 | Use cmdline.c to get debug switch
- * 6-Aug-86 | Modified for Lattice 3.0 -- use "void" to type some routines
- *****************************************************************************/
- /*
- * I think this came from Dale Amon, but we had some problems
- * getting it to work with Lattice C and hacked away to get
- * something to do the job.
- */
-
- #include "stdio.h"
- #include "dos.h"
- /* note: dos.h typedefs byte to unsigned char */
- /* cext.h #defines byte to unsigned char */
- #include "cext.h"
- #include "cmdline.h"
- #include "cintr.h"
- #include "atxt.h"
-
- /*
- * IBM-XT and IBM-AT interrupt information
- */
-
- #define NIRQS 16 /* Maximum number of IRQ levels */
-
- short defpc[NIRQS]; /* restore the vector to this PC */
- short defseg[NIRQS]; /* and this segment */
-
- #define VECTOR(irq) (0x20 + 4 * (irq))
- /* Maps interrupt request number
- to the address of the vector */
-
- /* CAUTION! CAUTION! CAUTION! CAUTION! CAUTION! CAUTION!
- The above "vector" computation DOES NOT WORK for a PC/AT for
- values higher than 7. IRQ8..15 are vectored starting at 70.
- The proper AT computation, should higher IRQ values be required,
- is
-
- (0x20 + ((irq) < 8 ? 0x20 + 4*(irq) : 0x70 + 4 * ((irq) - 8)))
-
- but that is much too complicated to want to do in the restricted
- case of having only an IRQ2 device. But you have now been warned.
-
- Note also that devices which on the PC or XT interrupt on IRQ2 will
- interrupt on the AT at IRQ9, but the software in the BIOS redirects
- this interrupt (PC/AT Tech Ref page 5-71) via the IRQ2 vector.
-
- *** HOWEVER ***
-
- If the program masks off interrupts by twiddling the mask bit for IRQ2
- it will also mask off the realtime clock interrupt, coprocessor
- interrupt, and *FIXED DISK INTERRUPT*. Therefore, any attempt to
- manipulate the interrupt masks must be done to the secondary 8259
- controller channel chip, located at locations 0xA0 and 0xA1.
-
- Mask bits in primary mask register:
-
- Bit XT* AT**
- 7 Printer Parallel Port 1
- 6 Diskette Diskette controller
- 5 Fixed Disk Parallel Port 2
- 4 Serial Port 1 Serial Port 1
- 3 Serial Port 2 Serial Port 2
- 2 IRQ2 IRQ2 (OR of IRQ8..IRQ15)
- 1 Keyboard Keyboard
- 0 Timer Timer
-
- Mask bits in secondary mask register (AT only)
-
- 7 IRQ15
- 6 Fixed disk controller
- 5 Coprocessor
- 4 IRQ12
- 3 IRQ11
- 2 IRQ10
- 1 IRQ9 (Bus IRQ2)
- 0 Realtime clock
-
- Source:
-
- * PC/XT Technical Ref page 1-9
- ** PC/AT Technical Ref page 1-11
-
- */
-
- #define INT_0_CONTROL_PORT 0x20 /* Interrupt chip I/0 port (PC, XT)*/
- #define INT_1_CONTROL_PORT 0x21 /* " " " " " */
- #define INT2_0_CONTROL_PORT 0xA0 /* Interrupt chip 2 I/O port (AT) */
- #define INT2_1_CONTROL_PORT 0xA1 /* " " " " " */
-
- #define EOI(irq) (0x60 | (irq))
- /* End of interrupt command to
- send to PORT1 */
-
- #define ndsw 2
- private char *dsw[ndsw] = { "-d", "-debug" };
-
- int enabled; /* flag to tell if interrupts are on */
- int debug_intr; /* set for debugging */
- int IsAT; /* AT or XT?, initialized here, read-only to others */
-
- /****************************************************************************
- * Routines local to this module
- ****************************************************************************/
- private void print_intr();
-
- /****************************************************************************
- * intr_init
- * Effect:
- * Initializes the interrupt routines
- ****************************************************************************/
-
- void intr_init()
- {
- int i;
- debug_intr = (cl_nswitch(dsw, ndsw) != NULL);
- IsAT = (ATXT() == ISAT);
- if (debug_intr) printf("IsAT is %d\n", IsAT);
- for (i = 0; i < NIRQS; i++) defpc[i] = defseg[i] = 0;
- }
-
- /****************************************************************************
- * intr_enable
- * Inputs:
- * int irq: Interrupt level to enable
- * Effect:
- * Enables the interrupt in the control port, sets enabled flag true
- ****************************************************************************/
-
- void intr_enable(irq)
- int irq;
- {
- int pv;
-
- if (IsAT && irq == 2) { /* AT on irq2 */
- pv = inp(INT2_1_CONTROL_PORT);
- if (debug_intr)
- printf("intr_enable/AT: (before) %02x = %02x\n",
- INT2_1_CONTROL_PORT, pv);
- pv &= ~(1<<1);
- outp(INT2_1_CONTROL_PORT, pv);
- if (debug_intr) { /* report */
- pv = inp(INT2_1_CONTROL_PORT);
- printf("intr_enable/AT: (after) %02x = %02x\n",
- INT2_1_CONTROL_PORT, pv);
- } /* report */
- } /* AT on irq2 */ else { /* PC or XT or AT not IRQ2 */
- pv = inp(INT_1_CONTROL_PORT);
- pv &= ~(1<<irq);
- outp(INT_1_CONTROL_PORT, pv);
- } /* PC or XT or AT not IRQ2 */
- enabled = true;
- }
-
- /****************************************************************************
- * intr_disable
- * Inputs:
- * int irq: irq level to disable
- * Effect:
- * Disables the interrupt in the control registers, sets enabled false
- ****************************************************************************/
-
- void intr_disable(irq)
- int irq;
- {
- int pv;
-
- if(IsAT && irq == 2)
- { /* AT */
- /* On the AT, we mask the interrupt in the secondary register */
- pv = inp(INT2_1_CONTROL_PORT);
- if(debug_intr)
- printf("intr_disable/AT: (before) %02x = %02x\n",INT2_1_CONTROL_PORT,pv);
- pv |= (1<<1);
- outp(INT2_1_CONTROL_PORT,pv);
- } /* AT */
- else
- { /* PC or XT */
- pv = inp(INT_1_CONTROL_PORT);
- pv |= (1<<irq);
- outp(INT_1_CONTROL_PORT, pv);
- if(debug_intr)
- { /* report */
- pv = inp(INT2_1_CONTROL_PORT);
- printf("intr_enable/XTAT: (after) %02x = %02x\n",INT2_1_CONTROL_PORT,pv);
- } /* report */
- } /* PC or XT */
- enabled = 0;
- }
-
- /****************************************************************************
- * intr_routine
- * Inputs:
- * int irq: interrupt level
- * Effect:
- * Set up vector and aintr (assembler code) globals so that
- * the function a_intr is called when an interrupt occurs
- * Notes:
- * Possible bug: The segment numbers (esp. ds) may not be correct and
- * probably should be passed as arguments
- ****************************************************************************/
-
- int a_irq, a_intr(), a_dsreg;
-
- void intr_routine(irq)
- int irq;
- {
- struct SREGS s;
-
- segread(&s);
- a_irq = irq;
- intr_set_vector(irq, s.cs, a_intr, 1);
- a_dsreg = s.ds;
- if (debug_intr) printf("cs = %x\tds = %x\n", s.cs, s.ds);
- }
-
- /****************************************************************************
- * intr_cleanup
- * Inputs:
- * int irq: irq level to restore interrupt for
- * Effect:
- * Restores the interrupt vector for the irq
- ****************************************************************************/
-
- void intr_cleanup(irq)
- int irq;
- {
- if (defseg[irq] != 0)
- intr_set_vector(irq, defseg[irq], defpc[irq],0);
- if (debug_intr)
- print_intr("After cleanup",irq);
- }
-
- /****************************************************************************
- * intr_eoi
- * Inputs:
- * int irq: interrupt level to do this to
- * Effect:
- * Sends end of interrupt command to the port for the indicated
- * interrupt level
- *
- * On the AT, the IRQ2 interrupt really came in on vector 71, but
- * EOI has been sent to the secondary I/O port and the interrupt has
- * been revectored to 0A. See BIOS listing for the AT page 5-71.
- ****************************************************************************/
-
- void intr_eoi(irq)
- int irq;
- {
- outp(INT_0_CONTROL_PORT, EOI(irq));
- }
-
- /****************************************************************************
- * intr_set_vector
- * Inputs:
- * int irq: interrupt vector level to set
- * short seg: segment value to store in interrupt level
- * short pc: pc value to store in interrupt level
- * boolean save: true to save the old value, false to just overwrite
- * it
- * Effect:
- * Sets the interrupt vector cs:ip to the indicated values
- ****************************************************************************/
-
- void intr_set_vector(irq, seg, pc, save)
- int irq;
- short seg;
- short pc;
- int save;
- {
- short s[2];
- short o[2];
-
- s[0] = pc;
- s[1] = seg;
- if (debug_intr)
- print_intr("Before poking new vector",irq);
- peek(0, VECTOR(irq), (char *) o, sizeof(o));
- poke(0, VECTOR(irq), (char *) s, sizeof(s));
- if (save) { /* save vector */
- defseg[irq] = o[1];
- defpc[irq] = o[0];
- } /* save vector */
- if (debug_intr) print_intr("After poking new vector",irq);
- }
-
- /****************************************************************************
- * print_intr
- * Inputs:
- * char * msg: Identifying message
- * int irq: Interrupt to print
- * Effect:
- * Prints the contents of the interrupt vector
- ****************************************************************************/
-
- private void print_intr(msg,irq)
- char * msg;
- int irq;
- {
- short s[2];
-
- peek(0, VECTOR(irq), (char *) s, sizeof(s));
- printf(
- "%s: vector %d, address %x, pc = %x, seg = %x, defpc=%x, defseg=%x\n",
- msg, irq, VECTOR(irq), s[0], s[1],defpc[irq],defseg[irq]);
- }
-