194 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			194 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /* This file contains routines for initializing the 8259 interrupt controller:
 | |
|  *	put_irq_handler: register an interrupt handler
 | |
|  *	rm_irq_handler: deregister an interrupt handler
 | |
|  *	intr_handle:	handle a hardware interrupt
 | |
|  *	intr_init:	initialize the interrupt controller(s)
 | |
|  */
 | |
| 
 | |
| #include "kernel.h"
 | |
| #include "proc.h"
 | |
| #include <minix/com.h>
 | |
| 
 | |
| #define ICW1_AT         0x11	/* edge triggered, cascade, need ICW4 */
 | |
| #define ICW1_PC         0x13	/* edge triggered, no cascade, need ICW4 */
 | |
| #define ICW1_PS         0x19	/* level triggered, cascade, need ICW4 */
 | |
| #define ICW4_AT_SLAVE   0x01	/* not SFNM, not buffered, normal EOI, 8086 */
 | |
| #define ICW4_AT_MASTER  0x05	/* not SFNM, not buffered, normal EOI, 8086 */
 | |
| #define ICW4_PC_SLAVE   0x09	/* not SFNM, buffered, normal EOI, 8086 */
 | |
| #define ICW4_PC_MASTER  0x0D	/* not SFNM, buffered, normal EOI, 8086 */
 | |
| 
 | |
| #if _WORD_SIZE == 2
 | |
| typedef _PROTOTYPE( void (*vecaddr_t), (void) );
 | |
| 
 | |
| FORWARD _PROTOTYPE( void set_vec, (int vec_nr, vecaddr_t addr) );
 | |
| 
 | |
| PRIVATE vecaddr_t int_vec[] = {
 | |
|   int00, int01, int02, int03, int04, int05, int06, int07,
 | |
| };
 | |
| 
 | |
| PRIVATE vecaddr_t irq_vec[] = {
 | |
|   hwint00, hwint01, hwint02, hwint03, hwint04, hwint05, hwint06, hwint07,
 | |
|   hwint08, hwint09, hwint10, hwint11, hwint12, hwint13, hwint14, hwint15,
 | |
| };
 | |
| #else
 | |
| #define set_vec(nr, addr)	((void)0)
 | |
| #endif
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				intr_init				     *
 | |
|  *===========================================================================*/
 | |
| PUBLIC void intr_init(mine)
 | |
| int mine;
 | |
| {
 | |
| /* Initialize the 8259s, finishing with all interrupts disabled.  This is
 | |
|  * only done in protected mode, in real mode we don't touch the 8259s, but
 | |
|  * use the BIOS locations instead.  The flag "mine" is set if the 8259s are
 | |
|  * to be programmed for MINIX, or to be reset to what the BIOS expects.
 | |
|  */
 | |
|   int i;
 | |
| 
 | |
|   intr_disable();
 | |
| 
 | |
|   if (machine.protected) {
 | |
|       /* The AT and newer PS/2 have two interrupt controllers, one master,
 | |
|        * one slaved at IRQ 2.  (We don't have to deal with the PC that
 | |
|        * has just one controller, because it must run in real mode.)
 | |
|        */
 | |
|       outb(INT_CTL, machine.ps_mca ? ICW1_PS : ICW1_AT);
 | |
|       outb(INT_CTLMASK, mine ? IRQ0_VECTOR : BIOS_IRQ0_VEC);
 | |
| 							/* ICW2 for master */
 | |
|       outb(INT_CTLMASK, (1 << CASCADE_IRQ));		/* ICW3 tells slaves */
 | |
|       outb(INT_CTLMASK, ICW4_AT_MASTER);
 | |
|       outb(INT_CTLMASK, ~(1 << CASCADE_IRQ));		/* IRQ 0-7 mask */
 | |
|       outb(INT2_CTL, machine.ps_mca ? ICW1_PS : ICW1_AT);
 | |
|       outb(INT2_CTLMASK, mine ? IRQ8_VECTOR : BIOS_IRQ8_VEC);
 | |
| 							/* ICW2 for slave */
 | |
|       outb(INT2_CTLMASK, CASCADE_IRQ);		/* ICW3 is slave nr */
 | |
|       outb(INT2_CTLMASK, ICW4_AT_SLAVE);
 | |
|       outb(INT2_CTLMASK, ~0);				/* IRQ 8-15 mask */
 | |
| 
 | |
|       /* Copy the BIOS vectors from the BIOS to the Minix location, so we
 | |
|        * can still make BIOS calls without reprogramming the i8259s.
 | |
|        */
 | |
| #if IRQ0_VECTOR != BIOS_IRQ0_VEC
 | |
|       phys_copy(BIOS_VECTOR(0) * 4L, VECTOR(0) * 4L, 8 * 4L);
 | |
| #endif
 | |
| #if IRQ8_VECTOR != BIOS_IRQ8_VEC
 | |
|       phys_copy(BIOS_VECTOR(8) * 4L, VECTOR(8) * 4L, 8 * 4L);
 | |
| #endif
 | |
|   } else {
 | |
|       /* Use the BIOS interrupt vectors in real mode.  We only reprogram the
 | |
|        * exceptions here, the interrupt vectors are reprogrammed on demand.
 | |
|        * SYS_VECTOR is the Minix system call for message passing.
 | |
|        */
 | |
|       for (i = 0; i < 8; i++) set_vec(i, int_vec[i]);
 | |
|       set_vec(SYS_VECTOR, s_call);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				put_irq_handler				     *
 | |
|  *===========================================================================*/
 | |
| PUBLIC void put_irq_handler(hook, irq, handler)
 | |
| irq_hook_t *hook;
 | |
| int irq;
 | |
| irq_handler_t handler;
 | |
| {
 | |
| /* Register an interrupt handler. */
 | |
|   int id;
 | |
|   irq_hook_t **line;
 | |
| 
 | |
|   if (irq < 0 || irq >= NR_IRQ_VECTORS)
 | |
|       panic("invalid call to put_irq_handler", irq);
 | |
| 
 | |
|   line = &irq_handlers[irq];
 | |
|   id = 1;
 | |
|   while (*line != NULL) {
 | |
|       if (hook == *line) return;	/* extra initialization */
 | |
|       line = &(*line)->next;
 | |
|       id <<= 1;
 | |
|   }
 | |
|   if (id == 0) panic("Too many handlers for irq", irq);
 | |
| 
 | |
|   hook->next = NULL;
 | |
|   hook->handler = handler;
 | |
|   hook->irq = irq;
 | |
|   hook->id = id;
 | |
|   *line = hook;
 | |
| 
 | |
|   irq_use |= 1 << irq;
 | |
| }
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				rm_irq_handler				     *
 | |
|  *===========================================================================*/
 | |
| PUBLIC void rm_irq_handler(hook)
 | |
| irq_hook_t *hook;
 | |
| {
 | |
| /* Unregister an interrupt handler. */
 | |
|   int irq = hook->irq; 
 | |
|   int id = hook->id;
 | |
|   irq_hook_t **line;
 | |
| 
 | |
|   if (irq < 0 || irq >= NR_IRQ_VECTORS) 
 | |
|       panic("invalid call to rm_irq_handler", irq);
 | |
| 
 | |
|   line = &irq_handlers[irq];
 | |
|   while (*line != NULL) {
 | |
|       if ((*line)->id == id) {
 | |
|           (*line) = (*line)->next;
 | |
|           if (! irq_handlers[irq]) irq_use &= ~(1 << irq);
 | |
|           return;
 | |
|       }
 | |
|       line = &(*line)->next;
 | |
|   }
 | |
|   /* When the handler is not found, normally return here. */
 | |
| }
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				intr_handle				     *
 | |
|  *===========================================================================*/
 | |
| PUBLIC void intr_handle(hook)
 | |
| irq_hook_t *hook;
 | |
| {
 | |
| /* Call the interrupt handlers for an interrupt with the given hook list.
 | |
|  * The assembly part of the handler has already masked the IRQ, reenabled the
 | |
|  * controller(s) and enabled interrupts.
 | |
|  */
 | |
| 
 | |
|   /* Call list of handlers for an IRQ. */
 | |
|   while (hook != NULL) {
 | |
|       /* For each handler in the list, mark it active by setting its ID bit,
 | |
|        * call the function, and unmark it if the function returns true.
 | |
|        */
 | |
|       irq_actids[hook->irq] |= hook->id;
 | |
|       if ((*hook->handler)(hook)) irq_actids[hook->irq] &= ~hook->id;
 | |
|       hook = hook->next;
 | |
|   }
 | |
| 
 | |
|   /* The assembly code will now disable interrupts, unmask the IRQ if and only
 | |
|    * if all active ID bits are cleared, and restart a process.
 | |
|    */
 | |
| }
 | |
| 
 | |
| #if _WORD_SIZE == 2
 | |
| /*===========================================================================*
 | |
|  *				set_vec                                      *
 | |
|  *===========================================================================*/
 | |
| PRIVATE void set_vec(vec_nr, addr)
 | |
| int vec_nr;			/* which vector */
 | |
| vecaddr_t addr;			/* where to start */
 | |
| {
 | |
| /* Set up a real mode interrupt vector. */
 | |
| 
 | |
|   u16_t vec[2];
 | |
| 
 | |
|   /* Build the vector in the array 'vec'. */
 | |
|   vec[0] = (u16_t) addr;
 | |
|   vec[1] = (u16_t) physb_to_hclick(code_base);
 | |
| 
 | |
|   /* Copy the vector into place. */
 | |
|   phys_copy(vir2phys(vec), vec_nr * 4L, 4L);
 | |
| }
 | |
| #endif /* _WORD_SIZE == 2 */
 | 
