Initial commit
This commit is contained in:
81
driver/irq/pic/int_handler.asm.S
Normal file
81
driver/irq/pic/int_handler.asm.S
Normal file
@ -0,0 +1,81 @@
|
||||
format elf64
|
||||
|
||||
extrn irq_pic_IntHandler
|
||||
|
||||
public irq_pic_IntHandler20h
|
||||
public irq_pic_IntHandler21h
|
||||
public irq_pic_IntHandler22h
|
||||
public irq_pic_IntHandler23h
|
||||
public irq_pic_IntHandler24h
|
||||
public irq_pic_IntHandler25h
|
||||
public irq_pic_IntHandler26h
|
||||
public irq_pic_IntHandler27h
|
||||
public irq_pic_IntHandler28h
|
||||
public irq_pic_IntHandler29h
|
||||
public irq_pic_IntHandler2ah
|
||||
public irq_pic_IntHandler2bh
|
||||
public irq_pic_IntHandler2ch
|
||||
public irq_pic_IntHandler2dh
|
||||
public irq_pic_IntHandler2eh
|
||||
public irq_pic_IntHandler2fh
|
||||
|
||||
|
||||
section '.text' executable
|
||||
|
||||
macro inth op1 {
|
||||
push rdi
|
||||
mov rdi, op1
|
||||
push rax
|
||||
push rsi
|
||||
push rdx
|
||||
push rcx
|
||||
push r8
|
||||
push r9
|
||||
push r10
|
||||
push r11
|
||||
call irq_pic_IntHandler
|
||||
pop r11
|
||||
pop r10
|
||||
pop r9
|
||||
pop r8
|
||||
pop rcx
|
||||
pop rdx
|
||||
pop rsi
|
||||
pop rax
|
||||
pop rdi
|
||||
iretq
|
||||
}
|
||||
|
||||
irq_pic_IntHandler20h:
|
||||
inth 0
|
||||
irq_pic_IntHandler21h:
|
||||
inth 1
|
||||
irq_pic_IntHandler22h:
|
||||
inth 2
|
||||
irq_pic_IntHandler23h:
|
||||
inth 3
|
||||
irq_pic_IntHandler24h:
|
||||
inth 4
|
||||
irq_pic_IntHandler25h:
|
||||
inth 5
|
||||
irq_pic_IntHandler26h:
|
||||
inth 6
|
||||
irq_pic_IntHandler27h:
|
||||
inth 7
|
||||
irq_pic_IntHandler28h:
|
||||
inth 8
|
||||
irq_pic_IntHandler29h:
|
||||
inth 9
|
||||
irq_pic_IntHandler2ah:
|
||||
inth 10
|
||||
irq_pic_IntHandler2bh:
|
||||
inth 11
|
||||
irq_pic_IntHandler2ch:
|
||||
inth 12
|
||||
irq_pic_IntHandler2dh:
|
||||
inth 13
|
||||
irq_pic_IntHandler2eh:
|
||||
inth 14
|
||||
irq_pic_IntHandler2fh:
|
||||
inth 15
|
||||
|
19
driver/irq/pic/int_handler.c
Normal file
19
driver/irq/pic/int_handler.c
Normal file
@ -0,0 +1,19 @@
|
||||
|
||||
#include "pic.h"
|
||||
#include "internal.h"
|
||||
#include "../../../runtime/stdio.h"
|
||||
|
||||
|
||||
SYSV_ABI void irq_pic_IntHandler(int irq) {
|
||||
if (irq >= 8)
|
||||
outb(PIC2_COMMAND, PIC_CMD_EOI);
|
||||
outb(PIC1_COMMAND, PIC_CMD_EOI);
|
||||
|
||||
if (irq_pic_IRQHandler[irq] == 0)
|
||||
// Text output is EXPENSIVE, do that only on unexpected IRQs
|
||||
io_Printf("INT %xh (IRQ %d) (no handler)\n", irq + IRQ_PIC_INT_OFFSET_MASTER, irq);
|
||||
else {
|
||||
//io_Printf("INT %xh (IRQ %d), handler%llx\n", irq + IRQ_PIC_INT_OFFSET_MASTER, irq, irq_pic_IRQHandler[irq]);
|
||||
irq_pic_IRQHandler[irq]();
|
||||
}
|
||||
}
|
86
driver/irq/pic/internal.h
Normal file
86
driver/irq/pic/internal.h
Normal file
@ -0,0 +1,86 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../../main.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
static inline void outb(uint16_t port, uint8_t val) {
|
||||
asm volatile("outb %0, %1" ::"a"(val), "Nd"(port));
|
||||
/*There's an outb %al, $imm8 encoding, for compile-time constant port numbers that fit in 8b. (N constraint).
|
||||
Wider immediate constants would be truncated at assemble-time (e.g. "i" constraint).
|
||||
The outb %al, %dx encoding is the only option for all other cases.
|
||||
%1 expands to %dx because port is a uint16_t. %w1 could be used if we had the port number a wider C type*/
|
||||
}
|
||||
|
||||
static inline uint8_t inb(uint16_t port) {
|
||||
uint8_t ret;
|
||||
asm volatile("inb %1, %0"
|
||||
: "=a"(ret)
|
||||
: "Nd"(port));
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Wait a very small amount of time (1 to 4 microseconds, generally).
|
||||
static inline void io_wait(void) {
|
||||
outb(0x80, 0);
|
||||
}
|
||||
|
||||
static inline void outb_wait(uint16_t port, uint8_t val) {
|
||||
asm volatile("outb %0, %1" ::"a"(val), "Nd"(port));
|
||||
/*There's an outb %al, $imm8 encoding, for compile-time constant port numbers that fit in 8b. (N constraint).
|
||||
Wider immediate constants would be truncated at assemble-time (e.g. "i" constraint).
|
||||
The outb %al, %dx encoding is the only option for all other cases.
|
||||
%1 expands to %dx because port is a uint16_t. %w1 could be used if we had the port number a wider C type*/
|
||||
asm volatile("outb %al, $0x80");
|
||||
}
|
||||
|
||||
|
||||
#define PIC1 0x20 // IO base address for master PIC
|
||||
#define PIC2 0xA0 // IO base address for slave PIC
|
||||
#define PIC1_COMMAND 0x20 // Port for Command for master PIC
|
||||
#define PIC1_DATA 0x21 // Port for Data for master PIC
|
||||
#define PIC2_COMMAND 0xA0 // Port for Command for slave PIC
|
||||
#define PIC2_DATA 0xA1 // Port for Data for slave PIC
|
||||
|
||||
#define PIC_CMD_EOI 0x20 // End-Of-Interrupt command
|
||||
|
||||
#define ICW1_ICW4 0x01 // ICW4 (not) needed
|
||||
#define ICW1_SINGLE 0x02 // Single (cascade) mode
|
||||
#define ICW1_INTERVAL4 0x04 // Call address interval 4 (8)
|
||||
#define ICW1_LEVEL 0x08 // Level triggered (edge) mode
|
||||
#define ICW1_INIT 0x10 // Initialization - required!
|
||||
|
||||
#define ICW4_8086 0x01 // 8086/88 (MCS-80/85) mode
|
||||
#define ICW4_AUTO 0x02 // Auto (normal) EOI
|
||||
#define ICW4_BUF_SLAVE 0x08 // Buffered mode/slave
|
||||
#define ICW4_BUF_MASTER 0x0C // Buffered mode/master
|
||||
#define ICW4_SFNM 0x10 // Special fully nested (not)
|
||||
|
||||
|
||||
SYSV_ABI void irq_pic_IntHandler(int irq);
|
||||
|
||||
SYSV_ABI void irq_pic_IntHandler20h();
|
||||
SYSV_ABI void irq_pic_IntHandler21h();
|
||||
SYSV_ABI void irq_pic_IntHandler22h();
|
||||
SYSV_ABI void irq_pic_IntHandler23h();
|
||||
SYSV_ABI void irq_pic_IntHandler24h();
|
||||
SYSV_ABI void irq_pic_IntHandler25h();
|
||||
SYSV_ABI void irq_pic_IntHandler26h();
|
||||
SYSV_ABI void irq_pic_IntHandler27h();
|
||||
SYSV_ABI void irq_pic_IntHandler28h();
|
||||
SYSV_ABI void irq_pic_IntHandler29h();
|
||||
SYSV_ABI void irq_pic_IntHandler2ah();
|
||||
SYSV_ABI void irq_pic_IntHandler2bh();
|
||||
SYSV_ABI void irq_pic_IntHandler2ch();
|
||||
SYSV_ABI void irq_pic_IntHandler2dh();
|
||||
SYSV_ABI void irq_pic_IntHandler2eh();
|
||||
SYSV_ABI void irq_pic_IntHandler2fh();
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
42
driver/irq/pic/pic.h
Normal file
42
driver/irq/pic/pic.h
Normal file
@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../../main.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
// Default location for PIC INT/IRQ remap
|
||||
#define IRQ_PIC_INT_OFFSET_MASTER 0x20 // INT20h...INT27h
|
||||
#define IRQ_PIC_INT_OFFSET_SLAVE 0x28 // INT28h...INT2fh
|
||||
|
||||
// Init PIC, mask all irqs
|
||||
void irq_pic_Init();
|
||||
|
||||
// remap Master PIC to INToff_master...+7, Slave to INToff_slave...+7
|
||||
void irq_pic_InitRemap(int offset_master, int offset_slave);
|
||||
|
||||
// Mask(disable) / Unmask(enable) certain IRQ line
|
||||
void irq_pic_Mask(uint8_t irq_line, bool masked);
|
||||
|
||||
// Disable legacy PIC (masks all IRQ lines)
|
||||
SYSV_ABI void irq_pic_Disable(); // defined in assembly
|
||||
|
||||
// Get the combined 16 bits of Interrupt-Request-Register and In-Service-Register
|
||||
uint16_t irq_pic_GetIRR();
|
||||
uint16_t irq_pic_GetISR();
|
||||
|
||||
|
||||
// void() for IRQ handlers, no need to call out8(OCW2, 0x6*)
|
||||
typedef SYSV_ABI void (*irq_pic_IRQHandlerType)();
|
||||
|
||||
// defined in pic_init.c
|
||||
extern irq_pic_IRQHandlerType irq_pic_IRQHandler[16];
|
||||
extern bool irq_pic_Enabled;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
12
driver/irq/pic/pic_asm.S
Normal file
12
driver/irq/pic/pic_asm.S
Normal file
@ -0,0 +1,12 @@
|
||||
format elf64
|
||||
|
||||
include 'pic_constants.incS'
|
||||
|
||||
public irq_pic_Disable
|
||||
|
||||
irq_pic_Disable:
|
||||
mov al, 0xff
|
||||
out PIC1_DATA, al
|
||||
out PIC2_DATA, al
|
||||
|
||||
|
25
driver/irq/pic/pic_constants.incS
Normal file
25
driver/irq/pic/pic_constants.incS
Normal file
@ -0,0 +1,25 @@
|
||||
|
||||
PIC1 equ 0x20 ; IO base for master PIC
|
||||
PIC2 equ 0xA0 ; IO base for slave PIC
|
||||
|
||||
PIC1_COMMAND equ PIC1 ; Port for Command for master PIC
|
||||
PIC1_DATA equ (PIC1+1) ; Port for Data for master PIC
|
||||
PIC2_COMMAND equ PIC2 ; Port for Command for slave PIC
|
||||
PIC2_DATA equ (PIC2+1) ; Port for Data for slave PIC
|
||||
|
||||
PIC_CMD_EOI equ 0x20 ; End-Of-Interrupt command
|
||||
|
||||
|
||||
ICW1_ICW4 equ 0x01 ; ICW4 (not) needed
|
||||
ICW1_SINGLE equ 0x02 ; Single (cascade) mode
|
||||
ICW1_INTERVAL4 equ 0x04 ; Call address interval 4 (8)
|
||||
ICW1_LEVEL equ 0x08 ; Level triggered (edge) mode
|
||||
ICW1_INIT equ 0x10 ; Initialization - required!
|
||||
|
||||
ICW4_8086 equ 0x01 ; 8086/88 (MCS-80/85) mode
|
||||
ICW4_AUTO equ 0x02 ; Auto (normal) EOI
|
||||
ICW4_BUF_SLAVE equ 0x08 ; Buffered mode/slave
|
||||
ICW4_BUF_MASTER equ 0x0C ; Buffered mode/master
|
||||
ICW4_SFNM equ 0x10 ; Special fully nested (not)
|
||||
|
||||
|
109
driver/irq/pic/pic_init.c
Normal file
109
driver/irq/pic/pic_init.c
Normal file
@ -0,0 +1,109 @@
|
||||
|
||||
#include "pic.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include "../../../runtime/panic_assert.h"
|
||||
#include "../../../interrupt/interrupt.h"
|
||||
#include "../../../runtime/stdio.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
irq_pic_IRQHandlerType irq_pic_IRQHandler[16];
|
||||
bool irq_pic_Enabled;
|
||||
|
||||
void irq_pic_Init() {
|
||||
assert(interrupt_Enabled && "Interrupt must be set up before PIC init");
|
||||
|
||||
INTERRUPT_DISABLE;
|
||||
|
||||
outb_wait(PIC1_DATA, 0xff); // mask all IRQs
|
||||
outb_wait(PIC2_DATA, 0xff);
|
||||
|
||||
outb_wait(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4);
|
||||
outb_wait(PIC1_DATA, IRQ_PIC_INT_OFFSET_MASTER); // ICW2: Master PIC interrupt vector offset
|
||||
outb_wait(PIC1_DATA, 4); // ICW3: tell Master PIC that there is a slave PIC at IRQ2
|
||||
outb_wait(PIC1_DATA, ICW4_8086);
|
||||
|
||||
outb_wait(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4);
|
||||
outb_wait(PIC2_DATA, IRQ_PIC_INT_OFFSET_SLAVE); // ICW2: Slave PIC interrupt vector offset
|
||||
outb_wait(PIC2_DATA, 2); // ICW3: tell Slave PIC its cascade identity
|
||||
outb_wait(PIC2_DATA, ICW4_8086);
|
||||
|
||||
outb_wait(PIC1_DATA, 0xfb); // mask all IRQs except IRQ2 (for slave)
|
||||
outb_wait(PIC2_DATA, 0xff);
|
||||
|
||||
memset(irq_pic_IRQHandler, 0, sizeof(irq_pic_IRQHandler)); // reset all IRQ handlers
|
||||
|
||||
// map the IRQ handlers
|
||||
interrupt_MapHandler(irq_pic_IntHandler20h, 0x20);
|
||||
interrupt_MapHandler(irq_pic_IntHandler21h, 0x21);
|
||||
interrupt_MapHandler(irq_pic_IntHandler22h, 0x22);
|
||||
interrupt_MapHandler(irq_pic_IntHandler23h, 0x23);
|
||||
interrupt_MapHandler(irq_pic_IntHandler24h, 0x24);
|
||||
interrupt_MapHandler(irq_pic_IntHandler25h, 0x25);
|
||||
interrupt_MapHandler(irq_pic_IntHandler26h, 0x26);
|
||||
interrupt_MapHandler(irq_pic_IntHandler27h, 0x27);
|
||||
interrupt_MapHandler(irq_pic_IntHandler28h, 0x28);
|
||||
interrupt_MapHandler(irq_pic_IntHandler29h, 0x29);
|
||||
interrupt_MapHandler(irq_pic_IntHandler2ah, 0x2a);
|
||||
interrupt_MapHandler(irq_pic_IntHandler2bh, 0x2b);
|
||||
interrupt_MapHandler(irq_pic_IntHandler2ch, 0x2c);
|
||||
interrupt_MapHandler(irq_pic_IntHandler2dh, 0x2d);
|
||||
interrupt_MapHandler(irq_pic_IntHandler2eh, 0x2e);
|
||||
interrupt_MapHandler(irq_pic_IntHandler2fh, 0x2f);
|
||||
|
||||
|
||||
irq_pic_Enabled = true;
|
||||
INTERRUPT_RESTORE;
|
||||
}
|
||||
|
||||
void irq_pic_InitRemap(int offset_master, int offset_slave) {
|
||||
uint8_t a1, a2; // existing PIC masks
|
||||
a1 = inb(PIC1_DATA);
|
||||
a2 = inb(PIC2_DATA);
|
||||
|
||||
outb_wait(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4);
|
||||
outb_wait(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4);
|
||||
outb_wait(PIC1_DATA, offset_master); // ICW2: Master PIC interrupt vector offset
|
||||
outb_wait(PIC2_DATA, offset_slave); // ICW2: Slave PIC interrupt vector offset
|
||||
outb_wait(PIC1_DATA, 4); // ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100)
|
||||
outb_wait(PIC2_DATA, 2); // ICW3: tell Slave PIC its cascade identity (0000 0010)
|
||||
outb_wait(PIC1_DATA, ICW4_8086);
|
||||
outb_wait(PIC2_DATA, ICW4_8086);
|
||||
|
||||
outb_wait(PIC1_DATA, a1); // restore saved masks
|
||||
outb_wait(PIC2_DATA, a1);
|
||||
}
|
||||
|
||||
void irq_pic_Mask(uint8_t irq_line, bool masked) {
|
||||
uint16_t port;
|
||||
|
||||
if (irq_line < 8)
|
||||
port = PIC1_DATA;
|
||||
else {
|
||||
port = PIC2_DATA;
|
||||
irq_line -= 8;
|
||||
}
|
||||
|
||||
if (masked)
|
||||
outb(port, inb(port) | (1 << irq_line));
|
||||
else
|
||||
outb(port, inb(port) & ~(1 << irq_line));
|
||||
}
|
||||
|
||||
|
||||
static inline uint16_t __irq_pic_GetRegister(uint8_t ocw3) {
|
||||
/* OCW3 to PIC CMD to get the register values. PIC2 is chained, and
|
||||
* represents IRQs 8-15. PIC1 is IRQs 0-7, with 2 being the chain */
|
||||
outb_wait(PIC1_COMMAND, ocw3);
|
||||
outb_wait(PIC2_COMMAND, ocw3);
|
||||
return ((uint16_t)inb(PIC2_COMMAND) << 8) | inb(PIC1_COMMAND);
|
||||
}
|
||||
|
||||
uint16_t irq_pic_GetIRR() {
|
||||
return __irq_pic_GetRegister(0x0a); // OCW3 Command: Read IRR
|
||||
}
|
||||
uint16_t irq_pic_GetISR() {
|
||||
return __irq_pic_GetRegister(0x0b); // OCW3 Command: Read ISR
|
||||
}
|
64
driver/irq/pic/ps2/internal.h
Normal file
64
driver/irq/pic/ps2/internal.h
Normal file
@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../../../main.h"
|
||||
#include "ps2.h"
|
||||
#include "../internal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
SYSV_ABI void irq_pic_ps2_IRQHandlerK(); // keyboard IRQ1
|
||||
SYSV_ABI void irq_pic_ps2_IRQHandlerM(); // mouse IRQ12
|
||||
|
||||
// waits until the Output Buffer Status (bit 0) of the Status Register is set
|
||||
// and port 0x60 is ready for data read
|
||||
static inline void __ps2_PollWait_ReadReady() {
|
||||
while ((inb(IRQ_PIC_PS2_STATUSPORT) & IRQ_PIC_PS2_STATUS_OUTPUT_BUFFER) == 0)
|
||||
asm("pause");
|
||||
}
|
||||
|
||||
// waits until the Input Buffer Status (bit 1) of the Status Register is clear
|
||||
// and ports 0x60/0x64 are ready for data write
|
||||
static inline void __ps2_PollWait_WriteReady() {
|
||||
while ((inb(IRQ_PIC_PS2_STATUSPORT) & IRQ_PIC_PS2_STATUS_INPUT_BUFFER) != 0)
|
||||
asm("pause");
|
||||
}
|
||||
|
||||
// waits until port 0x60 is ready and reads the byte in it
|
||||
static inline uint8_t __ps2_ReadData() {
|
||||
__ps2_PollWait_ReadReady();
|
||||
return inb(IRQ_PIC_PS2_IOPORT);
|
||||
}
|
||||
|
||||
// waits until port 0x64 is ready for write, OUTB to it.
|
||||
static inline void __ps2_WriteCommand(uint8_t cmd) {
|
||||
__ps2_PollWait_WriteReady();
|
||||
outb(IRQ_PIC_PS2_CMDPORT, cmd);
|
||||
}
|
||||
|
||||
// waits until port 0x64 is ready, OUTB to it, OUTB to 0x60 for data byte.
|
||||
static inline void __ps2_WriteCommandData(uint8_t cmd, uint8_t data) {
|
||||
__ps2_PollWait_WriteReady();
|
||||
outb(IRQ_PIC_PS2_CMDPORT, cmd);
|
||||
__ps2_PollWait_WriteReady();
|
||||
outb(IRQ_PIC_PS2_IOPORT, data);
|
||||
}
|
||||
|
||||
static inline void __ps2_ReadACK() {
|
||||
while (__ps2_ReadData() != IRQ_PIC_PS2_ACK) {}
|
||||
}
|
||||
|
||||
// sets the sample rate of the mouse
|
||||
static inline void __ps2_SetMouseRate(uint8_t rate) {
|
||||
__ps2_WriteCommandData(IRQ_PIC_PS2_CMD_SEND_MOUSE, 0xf3); // command to the mouse
|
||||
__ps2_ReadACK(); // read the ACK
|
||||
__ps2_WriteCommandData(IRQ_PIC_PS2_CMD_SEND_MOUSE, rate); // send the rate
|
||||
__ps2_ReadACK(); // read the ACK
|
||||
}
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
80
driver/irq/pic/ps2/ps2.c
Normal file
80
driver/irq/pic/ps2/ps2.c
Normal file
@ -0,0 +1,80 @@
|
||||
|
||||
#include "ps2.h"
|
||||
#include "../pic.h"
|
||||
#include "../internal.h"
|
||||
#include "internal.h"
|
||||
#include "../../../../interrupt/interrupt.h"
|
||||
#include "../../../../runtime/panic_assert.h"
|
||||
#include "../../../../runtime/stdio.h"
|
||||
#include "../../../../graphics/graphics.h"
|
||||
|
||||
|
||||
bool irq_pic_ps2_Mouse4Bytes; // the mouse has 4-byte data packages instead of 3
|
||||
|
||||
queue irq_pic_ps2_QueueKeyboard, irq_pic_ps2_QueueMouse;
|
||||
uint8_t __irq_pic_ps2_QueueBufferK[IRQ_PIC_PS2_QUEUESIZE_KEYBOARD], __irq_pic_ps2_QueueBufferM[IRQ_PIC_PS2_QUEUESIZE_MOUSE];
|
||||
|
||||
void irq_pic_ps2_Init() {
|
||||
assert(irq_pic_Enabled && "irq_pic_ps2_Init() requires PIC to be enabled");
|
||||
|
||||
// init the Keyboard and Mouse queues
|
||||
queue_InitBuffered(&irq_pic_ps2_QueueKeyboard, __irq_pic_ps2_QueueBufferK, IRQ_PIC_PS2_QUEUESIZE_KEYBOARD);
|
||||
queue_InitBuffered(&irq_pic_ps2_QueueMouse, __irq_pic_ps2_QueueBufferM, IRQ_PIC_PS2_QUEUESIZE_MOUSE);
|
||||
|
||||
uint8_t data;
|
||||
INTERRUPT_DISABLE;
|
||||
|
||||
irq_pic_IRQHandler[IRQ_PIC_PS2_KEYBOARD] = irq_pic_ps2_IRQHandlerK;
|
||||
irq_pic_IRQHandler[IRQ_PIC_PS2_MOUSE] = irq_pic_ps2_IRQHandlerM;
|
||||
irq_pic_Mask(IRQ_PIC_PS2_KEYBOARD, false);
|
||||
irq_pic_Mask(IRQ_PIC_PS2_MOUSE, false);
|
||||
|
||||
// enable second PS/2 port
|
||||
io_Printf("ENABLE_MOUSE... ");
|
||||
__ps2_WriteCommand(IRQ_PIC_PS2_CMD_ENABLE_MOUSE);
|
||||
|
||||
// write controller mode (EnablePort1Int | EnablePort2Int | SystemPOSTOk | Port1Translation)
|
||||
io_Printf("CONTROLLER_WRITE_CONFIGBYTE... ");
|
||||
__ps2_WriteCommandData(IRQ_PIC_PS2_CMD_WRITE_CONFIGBYTE, 0x47);
|
||||
|
||||
// reset mouse
|
||||
io_Printf("DEVICE_RESET... ");
|
||||
__ps2_WriteCommandData(IRQ_PIC_PS2_CMD_SEND_MOUSE, IRQ_PIC_PS2_CMD_DEVICE_RESET);
|
||||
while ((data = __ps2_ReadData()) != IRQ_PIC_PS2_RESET_OK) {
|
||||
io_Printf("%X ", data);
|
||||
}
|
||||
io_Printf("%X ", data);
|
||||
|
||||
|
||||
// enable mouse reporting
|
||||
io_Printf("MOUSE_ENABLE_REPORTING... ");
|
||||
__ps2_WriteCommandData(IRQ_PIC_PS2_CMD_SEND_MOUSE, IRQ_PIC_PS2_CMD_DEVICE_MOUSE_ENABLE_REPORTING);
|
||||
__ps2_ReadACK(); // receive ACK
|
||||
|
||||
// enable 4-byte mode for mouse, pure magic!
|
||||
irq_pic_ps2_Mouse4Bytes = false;
|
||||
__ps2_SetMouseRate(200);
|
||||
__ps2_SetMouseRate(100);
|
||||
__ps2_SetMouseRate(80);
|
||||
|
||||
io_Printf("SEND_MOUSE(PS2_DEVICE_ID)");
|
||||
__ps2_WriteCommandData(IRQ_PIC_PS2_CMD_SEND_MOUSE, 0xf2); // get device ID
|
||||
__ps2_ReadACK();
|
||||
uint8_t id = __ps2_ReadData(); // receive device ID
|
||||
io_Printf(", MOUSE PS/2 ID=%d\n", id);
|
||||
if (id == 3) // Z-axis is enabled
|
||||
irq_pic_ps2_Mouse4Bytes = true;
|
||||
|
||||
// set the actual mouse sample rate
|
||||
__ps2_SetMouseRate(IRQ_PIC_PS2_MOUSE_SAMPLERATE);
|
||||
|
||||
INTERRUPT_RESTORE;
|
||||
}
|
||||
|
||||
SYSV_ABI void irq_pic_ps2_IRQHandlerK() {
|
||||
queue_PushByte(&irq_pic_ps2_QueueKeyboard, inb(IRQ_PIC_PS2_IOPORT));
|
||||
}
|
||||
|
||||
SYSV_ABI void irq_pic_ps2_IRQHandlerM() {
|
||||
queue_PushByte(&irq_pic_ps2_QueueMouse, inb(IRQ_PIC_PS2_IOPORT));
|
||||
}
|
58
driver/irq/pic/ps2/ps2.h
Normal file
58
driver/irq/pic/ps2/ps2.h
Normal file
@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../../../util/queue.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#define IRQ_PIC_PS2_MOUSE_SAMPLERATE 60 // the sample rate of the mouse
|
||||
|
||||
|
||||
#define IRQ_PIC_PS2_KEYBOARD 1 // Keyboard IRQ number
|
||||
#define IRQ_PIC_PS2_MOUSE 12 // Mouse IRQ number
|
||||
|
||||
#define IRQ_PIC_PS2_IOPORT 0x0060
|
||||
#define IRQ_PIC_PS2_STATUSPORT 0x0064
|
||||
#define IRQ_PIC_PS2_CMDPORT 0x0064
|
||||
|
||||
#define IRQ_PIC_PS2_STATUS_OUTPUT_BUFFER (1 << 0)
|
||||
#define IRQ_PIC_PS2_STATUS_INPUT_BUFFER (1 << 1)
|
||||
#define IRQ_PIC_PS2_STATUS_SYSTEM_FLAG (1 << 2)
|
||||
#define IRQ_PIC_PS2_STATUS_INPUT_BUFFER_IS_COMMAND (1 << 3) // (0 = data written to input buffer is data for PS/2 device, 1 = data written to input buffer is data for PS/2 controller command)
|
||||
#define IRQ_PIC_PS2_STATUS_UNUSED_4 (1 << 4)
|
||||
#define IRQ_PIC_PS2_STATUS_UNUSED_5 (1 << 5)
|
||||
#define IRQ_PIC_PS2_STATUS_TIMEOUT_ERROR (1 << 6)
|
||||
#define IRQ_PIC_PS2_STATUS_PARITY_ERROR (1 << 7)
|
||||
|
||||
#define IRQ_PIC_PS2_ACK 0xfa // ACK code for keyboard and mouse (controller cmds have no ack)
|
||||
#define IRQ_PIC_PS2_RESET_OK 0xaa // the last output byte when a PS/2 device is reset
|
||||
|
||||
#define IRQ_PIC_PS2_CMD_READ_CONFIGBYTE 0x20 // Read byte 0 from controller RAM (configuration byte)
|
||||
#define IRQ_PIC_PS2_CMD_WRITE_CONFIGBYTE 0x60 // Write byte 0 to controller RAM (config byte)
|
||||
#define IRQ_PIC_PS2_CMD_DISABLE_MOUSE 0xa9 // Disable second PS/2 port (usually mouse)
|
||||
#define IRQ_PIC_PS2_CMD_ENABLE_MOUSE 0xa8 // Enable second PS/2 port (usually mouse)
|
||||
#define IRQ_PIC_PS2_CMD_SEND_MOUSE 0xd4 // Send a data byte to the second PS/2 port (usually mouse)
|
||||
|
||||
#define IRQ_PIC_PS2_CMD_DEVICE_GETID 0xf2
|
||||
#define IRQ_PIC_PS2_CMD_DEVICE_RESET 0xff
|
||||
#define IRQ_PIC_PS2_CMD_DEVICE_MOUSE_DISABLE_REPORTING 0xf5
|
||||
#define IRQ_PIC_PS2_CMD_DEVICE_MOUSE_ENABLE_REPORTING 0xf4
|
||||
|
||||
void irq_pic_ps2_Init();
|
||||
|
||||
extern bool irq_pic_ps2_Mouse4Bytes; // the mouse has 4-byte data packages instead of 3; mouse wheel enabled
|
||||
|
||||
|
||||
// size in bytes of the Keyboard/Mouse FIFO buffers
|
||||
#define IRQ_PIC_PS2_QUEUESIZE_KEYBOARD 64
|
||||
#define IRQ_PIC_PS2_QUEUESIZE_MOUSE 256
|
||||
|
||||
// data queue in bytes for the Keyboard and Mouse IRQs
|
||||
extern queue irq_pic_ps2_QueueKeyboard, irq_pic_ps2_QueueMouse;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
Reference in New Issue
Block a user