Subversion Repositories HelenOS-historic

Compare Revisions

Ignore whitespace Rev 532 → Rev 534

/kernel/trunk/arch/ia32/src/drivers/i8042.c
0,0 → 1,332
/*
* Copyright (C) 2001-2004 Jakub Jermar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
#include <arch/i8042.h>
#include <arch/i8259.h>
#include <arch/interrupt.h>
#include <cpu.h>
#include <arch/asm.h>
#include <arch.h>
#include <print.h>
#include <synch/spinlock.h>
#include <typedefs.h>
#include <console/chardev.h>
#include <console/console.h>
#include <macros.h>
 
/**
* i8042 processor driver.
* It takes care of low-level keyboard functions.
*/
 
#define i8042_DATA 0x60
#define i8042_STATUS 0x64
 
/** Keyboard commands. */
#define KBD_ENABLE 0xf4
#define KBD_DISABLE 0xf5
#define KBD_ACK 0xfa
 
#define SPECIAL '?'
#define KEY_RELEASE 0x80
 
static void key_released(__u8 sc);
static void key_pressed(__u8 sc);
 
#define PRESSED_SHIFT (1<<0)
#define PRESSED_CAPSLOCK (1<<1)
#define LOCKED_CAPSLOCK (1<<0)
 
static spinlock_t keylock; /**< keylock protects keyflags and lockflags. */
static volatile int keyflags; /**< Tracking of multiple keypresses. */
static volatile int lockflags; /**< Tracking of multiple keys lockings. */
 
static void i8042_suspend(void);
static void i8042_resume(void);
 
static chardev_t kbrd;
static chardev_operations_t ops = {
.suspend = i8042_suspend,
.resume = i8042_resume
};
 
/** Primary meaning of scancodes. */
static char sc_primary_map[] = {
SPECIAL, /* 0x00 */
SPECIAL, /* 0x01 - Esc */
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=',
SPECIAL, /* 0x0e - Backspace */
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
SPECIAL, /* 0x1d - LCtrl */
'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'',
'`',
SPECIAL, /* 0x2a - LShift */
'\\',
'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/',
SPECIAL, /* 0x36 - RShift */
'*',
SPECIAL, /* 0x38 - LAlt */
' ',
SPECIAL, /* 0x3a - CapsLock */
SPECIAL, /* 0x3b - F1 */
SPECIAL, /* 0x3c - F2 */
SPECIAL, /* 0x3d - F3 */
SPECIAL, /* 0x3e - F4 */
SPECIAL, /* 0x3f - F5 */
SPECIAL, /* 0x40 - F6 */
SPECIAL, /* 0x41 - F7 */
SPECIAL, /* 0x42 - F8 */
SPECIAL, /* 0x43 - F9 */
SPECIAL, /* 0x44 - F10 */
SPECIAL, /* 0x45 - NumLock */
SPECIAL, /* 0x46 - ScrollLock */
'7', '8', '9', '-',
'4', '5', '6', '+',
'1', '2', '3',
'0', '.',
SPECIAL, /* 0x54 - Alt-SysRq */
SPECIAL, /* 0x55 - F11/F12/PF1/FN */
SPECIAL, /* 0x56 - unlabelled key next to LAlt */
SPECIAL, /* 0x57 - F11 */
SPECIAL, /* 0x58 - F12 */
SPECIAL, /* 0x59 */
SPECIAL, /* 0x5a */
SPECIAL, /* 0x5b */
SPECIAL, /* 0x5c */
SPECIAL, /* 0x5d */
SPECIAL, /* 0x5e */
SPECIAL, /* 0x5f */
SPECIAL, /* 0x60 */
SPECIAL, /* 0x61 */
SPECIAL, /* 0x62 */
SPECIAL, /* 0x63 */
SPECIAL, /* 0x64 */
SPECIAL, /* 0x65 */
SPECIAL, /* 0x66 */
SPECIAL, /* 0x67 */
SPECIAL, /* 0x68 */
SPECIAL, /* 0x69 */
SPECIAL, /* 0x6a */
SPECIAL, /* 0x6b */
SPECIAL, /* 0x6c */
SPECIAL, /* 0x6d */
SPECIAL, /* 0x6e */
SPECIAL, /* 0x6f */
SPECIAL, /* 0x70 */
SPECIAL, /* 0x71 */
SPECIAL, /* 0x72 */
SPECIAL, /* 0x73 */
SPECIAL, /* 0x74 */
SPECIAL, /* 0x75 */
SPECIAL, /* 0x76 */
SPECIAL, /* 0x77 */
SPECIAL, /* 0x78 */
SPECIAL, /* 0x79 */
SPECIAL, /* 0x7a */
SPECIAL, /* 0x7b */
SPECIAL, /* 0x7c */
SPECIAL, /* 0x7d */
SPECIAL, /* 0x7e */
SPECIAL, /* 0x7f */
};
 
/** Secondary meaning of scancodes. */
static char sc_secondary_map[] = {
SPECIAL, /* 0x00 */
SPECIAL, /* 0x01 - Esc */
'!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+',
SPECIAL, /* 0x0e - Backspace */
'\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n',
SPECIAL, /* 0x1d - LCtrl */
'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"',
'~',
SPECIAL, /* 0x2a - LShift */
'|',
'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?',
SPECIAL, /* 0x36 - RShift */
'*',
SPECIAL, /* 0x38 - LAlt */
' ',
SPECIAL, /* 0x3a - CapsLock */
SPECIAL, /* 0x3b - F1 */
SPECIAL, /* 0x3c - F2 */
SPECIAL, /* 0x3d - F3 */
SPECIAL, /* 0x3e - F4 */
SPECIAL, /* 0x3f - F5 */
SPECIAL, /* 0x40 - F6 */
SPECIAL, /* 0x41 - F7 */
SPECIAL, /* 0x42 - F8 */
SPECIAL, /* 0x43 - F9 */
SPECIAL, /* 0x44 - F10 */
SPECIAL, /* 0x45 - NumLock */
SPECIAL, /* 0x46 - ScrollLock */
'7', '8', '9', '-',
'4', '5', '6', '+',
'1', '2', '3',
'0', '.',
SPECIAL, /* 0x54 - Alt-SysRq */
SPECIAL, /* 0x55 - F11/F12/PF1/FN */
SPECIAL, /* 0x56 - unlabelled key next to LAlt */
SPECIAL, /* 0x57 - F11 */
SPECIAL, /* 0x58 - F12 */
SPECIAL, /* 0x59 */
SPECIAL, /* 0x5a */
SPECIAL, /* 0x5b */
SPECIAL, /* 0x5c */
SPECIAL, /* 0x5d */
SPECIAL, /* 0x5e */
SPECIAL, /* 0x5f */
SPECIAL, /* 0x60 */
SPECIAL, /* 0x61 */
SPECIAL, /* 0x62 */
SPECIAL, /* 0x63 */
SPECIAL, /* 0x64 */
SPECIAL, /* 0x65 */
SPECIAL, /* 0x66 */
SPECIAL, /* 0x67 */
SPECIAL, /* 0x68 */
SPECIAL, /* 0x69 */
SPECIAL, /* 0x6a */
SPECIAL, /* 0x6b */
SPECIAL, /* 0x6c */
SPECIAL, /* 0x6d */
SPECIAL, /* 0x6e */
SPECIAL, /* 0x6f */
SPECIAL, /* 0x70 */
SPECIAL, /* 0x71 */
SPECIAL, /* 0x72 */
SPECIAL, /* 0x73 */
SPECIAL, /* 0x74 */
SPECIAL, /* 0x75 */
SPECIAL, /* 0x76 */
SPECIAL, /* 0x77 */
SPECIAL, /* 0x78 */
SPECIAL, /* 0x79 */
SPECIAL, /* 0x7a */
SPECIAL, /* 0x7b */
SPECIAL, /* 0x7c */
SPECIAL, /* 0x7d */
SPECIAL, /* 0x7e */
SPECIAL, /* 0x7f */
};
 
/** Initialize i8042. */
void i8042_init(void)
{
trap_register(VECTOR_KBD, i8042_interrupt);
trap_virtual_enable_irqs(1<<IRQ_KBD);
spinlock_initialize(&keylock);
chardev_initialize(&kbrd, &ops);
stdin = &kbrd;
}
 
/** Process i8042 interrupt.
*
* @param n Interrupt vector.
* @param stack Interrupted stack.
*/
void i8042_interrupt(__u8 n, __native stack[])
{
__u8 x;
 
trap_virtual_eoi();
x = inb(i8042_DATA);
if (x & KEY_RELEASE)
key_released(x ^ KEY_RELEASE);
else
key_pressed(x);
}
 
/** Process release of key.
*
* @param sc Scancode of the key being released.
*/
void key_released(__u8 sc)
{
spinlock_lock(&keylock);
switch (sc) {
case SC_LSHIFT:
case SC_RSHIFT:
keyflags &= ~PRESSED_SHIFT;
break;
case SC_CAPSLOCK:
keyflags &= ~PRESSED_CAPSLOCK;
if (lockflags & LOCKED_CAPSLOCK)
lockflags &= ~LOCKED_CAPSLOCK;
else
lockflags |= LOCKED_CAPSLOCK;
break;
default:
break;
}
spinlock_unlock(&keylock);
}
 
/** Process keypress.
*
* @param sc Scancode of the key being pressed.
*/
void key_pressed(__u8 sc)
{
char *map = sc_primary_map;
char ascii = sc_primary_map[sc];
bool shift, capslock;
bool letter = false;
 
spinlock_lock(&keylock);
switch (sc) {
case SC_LSHIFT:
case SC_RSHIFT:
keyflags |= PRESSED_SHIFT;
break;
case SC_CAPSLOCK:
keyflags |= PRESSED_CAPSLOCK;
break;
default:
letter = is_lower(ascii);
capslock = (keyflags & PRESSED_CAPSLOCK) || (lockflags & LOCKED_CAPSLOCK);
shift = keyflags & PRESSED_SHIFT;
if (letter && capslock)
shift = !shift;
if (shift)
map = sc_secondary_map;
chardev_push_character(&kbrd, map[sc]);
break;
}
spinlock_unlock(&keylock);
}
 
/* Called from getc(). */
void i8042_resume(void)
{
}
 
/* Called from getc(). */
void i8042_suspend(void)
{
}
/kernel/trunk/arch/ia32/src/drivers/i8254.c
0,0 → 1,129
/*
* Copyright (C) 2001-2004 Jakub Jermar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
#include <arch/types.h>
#include <time/clock.h>
#include <time/delay.h>
#include <arch/interrupt.h>
#include <arch/i8259.h>
#include <arch/i8254.h>
#include <cpu.h>
#include <config.h>
#include <arch/pm.h>
#include <arch/asm.h>
#include <arch/cpuid.h>
#include <arch.h>
#include <time/delay.h>
 
/*
* i8254 chip driver.
* Low level time functions.
*/
 
#define CLK_PORT1 0x40
#define CLK_PORT4 0x43
 
 
#define CLK_CONST 1193180
#define MAGIC_NUMBER 1194
 
void i8254_init(void)
{
i8254_normal_operation();
}
 
void i8254_normal_operation(void)
{
outb(CLK_PORT4, 0x36);
pic_disable_irqs(1<<IRQ_CLK);
outb(CLK_PORT1, (CLK_CONST/HZ) & 0xf);
outb(CLK_PORT1, (CLK_CONST/HZ) >> 8);
pic_enable_irqs(1<<IRQ_CLK);
trap_register(VECTOR_CLK, i8254_interrupt);
}
 
#define LOOPS 150000
#define SHIFT 11
void i8254_calibrate_delay_loop(void)
{
__u64 clk1, clk2;
__u32 t1, t2, o1, o2;
__u8 not_ok;
 
 
/*
* One-shot timer. Count-down from 0xffff at 1193180Hz
* MAGIC_NUMBER is the magic value for 1ms.
*/
outb(CLK_PORT4, 0x30);
outb(CLK_PORT1, 0xff);
outb(CLK_PORT1, 0xff);
 
do {
/* will read both status and count */
outb(CLK_PORT4, 0xc2);
not_ok = (inb(CLK_PORT1)>>6)&1;
t1 = inb(CLK_PORT1);
t1 |= inb(CLK_PORT1) << 8;
} while (not_ok);
 
asm_delay_loop(LOOPS);
 
outb(CLK_PORT4, 0xd2);
t2 = inb(CLK_PORT1);
t2 |= inb(CLK_PORT1) << 8;
 
/*
* We want to determine the overhead of the calibrating mechanism.
*/
outb(CLK_PORT4, 0xd2);
o1 = inb(CLK_PORT1);
o1 |= inb(CLK_PORT1) << 8;
 
asm_fake_loop(LOOPS);
 
outb(CLK_PORT4, 0xd2);
o2 = inb(CLK_PORT1);
o2 |= inb(CLK_PORT1) << 8;
 
CPU->delay_loop_const = ((MAGIC_NUMBER*LOOPS)/1000) / ((t1-t2)-(o1-o2)) + (((MAGIC_NUMBER*LOOPS)/1000) % ((t1-t2)-(o1-o2)) ? 1 : 0);
 
clk1 = rdtsc();
delay(1<<SHIFT);
clk2 = rdtsc();
CPU->frequency_mhz = (clk2-clk1)>>SHIFT;
 
return;
}
 
void i8254_interrupt(__u8 n, __native stack[])
{
trap_virtual_eoi();
clock();
}
/kernel/trunk/arch/ia32/src/drivers/ega.c
0,0 → 1,118
/*
* Copyright (C) 2001-2004 Jakub Jermar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
#include <arch/ega.h>
#include <putchar.h>
#include <mm/page.h>
#include <arch/mm/page.h>
#include <synch/spinlock.h>
#include <arch/types.h>
#include <arch/asm.h>
#include <memstr.h>
 
/*
* The EGA driver.
* Simple and short. Function for displaying characters and "scrolling".
*/
 
static spinlock_t egalock;
static __u32 ega_cursor;
 
void ega_move_cursor(void);
 
void ega_init(void)
{
__u8 hi, lo;
 
page_mapping_insert(PA2KA(VIDEORAM), VIDEORAM, PAGE_NOT_CACHEABLE, 0);
outb(0x3d4,0xe);
hi = inb(0x3d5);
outb(0x3d4,0xf);
lo = inb(0x3d5);
ega_cursor = (hi<<8)|lo;
ega_putchar('\n');
}
 
static void ega_display_char(char ch)
{
__u8 *vram = (__u8 *) PA2KA(VIDEORAM);
vram[ega_cursor*2] = ch;
}
 
/*
* This function takes care of scrolling.
*/
static void ega_check_cursor(void)
{
if (ega_cursor < SCREEN)
return;
 
memcpy((void *)PA2KA(VIDEORAM), (void *)(PA2KA(VIDEORAM) + ROW*2), (SCREEN - ROW)*2);
memsetw(PA2KA(VIDEORAM) + (SCREEN - ROW)*2, ROW, 0x0720);
ega_cursor = ega_cursor - ROW;
}
 
void ega_putchar(const char ch)
{
ipl_t ipl;
 
ipl = interrupts_disable();
spinlock_lock(&egalock);
 
switch (ch) {
case '\n':
ega_cursor = (ega_cursor + ROW) - ega_cursor % ROW;
break;
case '\t':
ega_cursor = (ega_cursor + 8) - ega_cursor % 8;
break;
default:
ega_display_char(ch);
ega_cursor++;
break;
}
ega_check_cursor();
ega_move_cursor();
 
spinlock_unlock(&egalock);
interrupts_restore(ipl);
}
 
void ega_move_cursor(void)
{
outb(0x3d4,0xe);
outb(0x3d5,(ega_cursor>>8)&0xff);
outb(0x3d4,0xf);
outb(0x3d5,ega_cursor&0xff);
}
 
void putchar(const char ch)
{
ega_putchar(ch);
}
/kernel/trunk/arch/ia32/src/drivers/i8259.c
0,0 → 1,121
/*
* Copyright (C) 2001-2004 Jakub Jermar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
#include <arch/i8259.h>
#include <cpu.h>
#include <arch/types.h>
#include <arch/asm.h>
#include <arch.h>
#include <print.h>
 
/*
* This is the PIC driver.
* Programmable Interrupt Controller for UP systems.
*/
 
void i8259_init(void)
{
/* ICW1: this is ICW1, ICW4 to follow */
outb(PIC_PIC0PORT1, PIC_ICW1 | PIC_NEEDICW4);
 
/* ICW2: IRQ 0 maps to INT IRQBASE */
outb(PIC_PIC0PORT2, IVT_IRQBASE);
 
/* ICW3: pic1 using IRQ IRQ_PIC1 */
outb(PIC_PIC0PORT2, 1 << IRQ_PIC1);
 
/* ICW4: i8086 mode */
outb(PIC_PIC0PORT2, 1);
 
/* ICW1: ICW1, ICW4 to follow */
outb(PIC_PIC1PORT1, PIC_ICW1 | PIC_NEEDICW4);
 
/* ICW2: IRQ 8 maps to INT (IVT_IRQBASE + 8) */
outb(PIC_PIC1PORT2, IVT_IRQBASE + 8);
 
/* ICW3: pic1 is known as IRQ_PIC1 */
outb(PIC_PIC1PORT2, IRQ_PIC1);
 
/* ICW4: i8086 mode */
outb(PIC_PIC1PORT2, 1);
 
/*
* Register interrupt handler for the PIC spurious interrupt.
*/
trap_register(VECTOR_PIC_SPUR, pic_spurious);
 
/*
* Set the enable/disable IRQs handlers.
* Set the End-of-Interrupt handler.
*/
enable_irqs_function = pic_enable_irqs;
disable_irqs_function = pic_disable_irqs;
eoi_function = pic_eoi;
 
pic_disable_irqs(0xffff); /* disable all irq's */
pic_enable_irqs(1<<IRQ_PIC1); /* but enable pic1 */
}
 
void pic_enable_irqs(__u16 irqmask)
{
__u8 x;
 
if (irqmask & 0xff) {
x = inb(PIC_PIC0PORT2);
outb(PIC_PIC0PORT2, x & (~(irqmask & 0xff)));
}
if (irqmask >> 8) {
x = inb(PIC_PIC1PORT2);
outb(PIC_PIC1PORT2, x & (~(irqmask >> 8)));
}
}
 
void pic_disable_irqs(__u16 irqmask)
{
__u8 x;
 
if (irqmask & 0xff) {
x = inb(PIC_PIC0PORT2);
outb(PIC_PIC0PORT2, x | (irqmask & 0xff));
}
if (irqmask >> 8) {
x = inb(PIC_PIC1PORT2);
outb(PIC_PIC1PORT2, x | (irqmask >> 8));
}
}
 
void pic_eoi(void)
{
outb(0x20,0x20);
outb(0xa0,0x20);
}
 
void pic_spurious(__u8 n, __native stack[])
{
printf("cpu%d: PIC spurious interrupt\n", CPU->id);
}