15 changed files with 344 additions and 43 deletions
Binary file not shown.
Binary file not shown.
@ -0,0 +1,3 @@ |
|||
[section .text] |
|||
start: |
|||
incbin "limine.sys" |
@ -0,0 +1,24 @@ |
|||
; ps2 -> azerty |
|||
; translation table |
|||
|
|||
[section .rodata] |
|||
[global ps2_azerty_table_lowercase] |
|||
[global ps2_azerty_table_uppercase] |
|||
|
|||
ps2_azerty_table_lowercase: |
|||
db 0,0, "&e", '"', "'(-e_ca)=", 8 |
|||
db 9, "azertyuiop^$", 10 |
|||
db 0, "qsdfghjklmu", 0, 0, "*" |
|||
db "wxcvbn,;:!", 0,0 |
|||
db 0,0, ' ' |
|||
TIMES 80-53 db 0 |
|||
db "<" |
|||
|
|||
ps2_azerty_table_uppercase: |
|||
db 0,0, "1234567890)+", 8 |
|||
db 9, "AZERTYUIOP^$", 10 |
|||
db 0, "QSDFGHJKLM%", 0, 0, "*" |
|||
db "WXCVBN?./!", 0,0 |
|||
db 0,0, ' ' |
|||
TIMES 80-53 db 0 |
|||
db "<" |
@ -1,23 +0,0 @@ |
|||
|
|||
|
|||
/**
|
|||
* PCIE drivers interfaces: |
|||
* |
|||
* provide void init(void* config_space_base) |
|||
* |
|||
* functions to call: |
|||
* register_irq(unsigned) |
|||
* unregister_irq(unsigned) |
|||
* |
|||
* int register_timer(void callback(void), unsigned period) |
|||
* void unregister_timer(int timer_id) |
|||
* |
|||
*/ |
|||
|
|||
|
|||
|
|||
void |
|||
/**
|
|||
* return 0 if the irq was successfully installed |
|||
*/ |
|||
int register_irq(uint8_t irq_number, ); |
@ -0,0 +1,147 @@ |
|||
#include "ps2kb.h" |
|||
#include "../lib/logging.h" |
|||
#include "../lib/registers.h" |
|||
#include "../lib/sprintf.h" |
|||
#include "../int/idt.h" |
|||
#include "../int/pic.h" |
|||
#include "../lib/registers.h" |
|||
|
|||
static void kbevent_default_handler(const struct kbevent* event) { |
|||
(void) event; |
|||
} |
|||
|
|||
static kbevent_handler handler = kbevent_default_handler; |
|||
|
|||
static char lshift_state, rshift_state; |
|||
|
|||
static uint8_t get_byte(void) { |
|||
// wait for the output bufer
|
|||
// to be filled
|
|||
while((inb(0x64) & 1) == 0) { |
|||
asm volatile("pause"); |
|||
} |
|||
|
|||
return inb(0x60); |
|||
} |
|||
|
|||
// outputs a command to the controller
|
|||
static void command_byte(uint8_t b) { |
|||
|
|||
// wait for the input bufer
|
|||
// to be empty
|
|||
while((inb(0x64) & 2) == 1) { |
|||
asm volatile("pause"); |
|||
} |
|||
|
|||
outb(0x64, b); |
|||
} |
|||
|
|||
|
|||
|
|||
extern const char ps2_azerty_table_lowercase[]; |
|||
extern const char ps2_azerty_table_uppercase[]; |
|||
|
|||
|
|||
|
|||
static uint8_t leds_state = 0; |
|||
// by default, leds are disabled
|
|||
|
|||
|
|||
int is_caps(void) { |
|||
// 3rd bit = 3rd led = caps
|
|||
int s = (leds_state / 4) + (lshift_state | rshift_state); |
|||
return s % 2; |
|||
} |
|||
|
|||
|
|||
static int process_leds(uint8_t b) { |
|||
if(b == 0xba) {// caps lock
|
|||
// flush data buffer
|
|||
inb(0x60); |
|||
command_byte(0xED); |
|||
leds_state = leds_state ^ 4; |
|||
|
|||
command_byte(leds_state); |
|||
return 1; |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static void process_byte(uint8_t b) { |
|||
|
|||
if(b == 0xFA) // ACK
|
|||
return; |
|||
else if(b == 0xFE) { // resend
|
|||
// well shit
|
|||
log_warn("something went wrong with the keyboard"); |
|||
return; |
|||
} |
|||
else if(process_leds(b)) |
|||
return; |
|||
struct kbevent ev = { |
|||
.type = (b&0x80) ? KEYRELEASED : KEYPRESSED, |
|||
.keycode = b&0x7f, |
|||
}; |
|||
|
|||
if(ev.keycode == 0x2A) { |
|||
lshift_state = ev.type; |
|||
return; |
|||
} |
|||
else if(ev.keycode == 0x36) { |
|||
rshift_state = ev.type; |
|||
return; |
|||
} |
|||
|
|||
|
|||
if(is_caps()) |
|||
ev.scancode = ps2_azerty_table_uppercase[ev.keycode]; |
|||
else |
|||
ev.scancode = ps2_azerty_table_lowercase[ev.keycode]; |
|||
|
|||
printf("%c", ev.scancode); |
|||
|
|||
handler(&ev); |
|||
} |
|||
|
|||
|
|||
static void __attribute__((interrupt)) irq_handler(void* r) { |
|||
|
|||
process_byte(inb(0x60)); |
|||
|
|||
pic_eoi(1); |
|||
} |
|||
|
|||
void ps2kb_init(void) { |
|||
|
|||
log_debug("init ps/2 keyboard..."); |
|||
|
|||
unsigned status = inb(0x64); |
|||
if(status & 0xc0) { |
|||
// error
|
|||
log_warn("ps/2 controller error: %u", status); |
|||
return; |
|||
} |
|||
|
|||
// enable ps2 through config byte
|
|||
uint8_t config; |
|||
command_byte(0x20); // read config byte command
|
|||
config = get_byte(); |
|||
log_debug("zdf"); |
|||
|
|||
command_byte(0x6); |
|||
command_byte(config | 1); |
|||
|
|||
|
|||
set_irq_handler(17, irq_handler); |
|||
pic_mask_irq(1, 0); |
|||
|
|||
for(;;) |
|||
asm("hlt"); |
|||
//log_debug("dzdvf");
|
|||
} |
|||
|
|||
|
|||
void ps2kb_set_event_callback(kbevent_handler h) { |
|||
handler = h; |
|||
} |
@ -0,0 +1,19 @@ |
|||
#pragma once |
|||
|
|||
#include <stdint.h> |
|||
|
|||
void ps2kb_init(void); |
|||
|
|||
|
|||
struct kbevent { |
|||
enum { |
|||
KEYRELEASED = 0, |
|||
KEYPRESSED = 1 |
|||
} type; |
|||
uint32_t keycode; |
|||
uint32_t scancode; |
|||
}; |
|||
|
|||
typedef void (* kbevent_handler)(const struct kbevent* kbevent); |
|||
|
|||
void ps2kb_set_event_callback(kbevent_handler h); |
@ -0,0 +1,86 @@ |
|||
#include "../lib/registers.h" |
|||
#include "../lib/assert.h" |
|||
#include "pic.h" |
|||
|
|||
|
|||
|
|||
#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) */ |
|||
#define PIC_EOI 0x20 /* End-of-interrupt command code */ |
|||
#define PIC1 0x20 /* IO base address for master PIC */ |
|||
#define PIC2 0xA0 /* IO base address for slave PIC */ |
|||
#define PIC1_COMMAND PIC1 |
|||
#define PIC1_DATA (PIC1+1) |
|||
#define PIC2_COMMAND PIC2 |
|||
#define PIC2_DATA (PIC2+1) |
|||
|
|||
void pic_eoi(unsigned char irq) |
|||
{ |
|||
if(irq >= 8) |
|||
outb(PIC2_COMMAND,PIC_EOI); |
|||
|
|||
outb(PIC1_COMMAND,PIC_EOI); |
|||
} |
|||
|
|||
static void io_wait(void) { |
|||
outb(0x80,0); |
|||
} |
|||
|
|||
static uint16_t mask = 0xff; |
|||
|
|||
void pic_init(void) { |
|||
|
|||
outb(0x80, 0); |
|||
|
|||
outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4); |
|||
// starts the initialization sequence (in cascade mode)
|
|||
io_wait(); |
|||
outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4); |
|||
io_wait(); |
|||
outb(PIC1_DATA, 16); |
|||
// ICW2: Master PIC vector offset
|
|||
io_wait(); |
|||
|
|||
outb(PIC2_DATA, 24); |
|||
// ICW2: Slave PIC vector offset
|
|||
io_wait(); |
|||
outb(PIC1_DATA, 4); |
|||
// ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100)
|
|||
io_wait(); |
|||
|
|||
outb(PIC2_DATA, 2); |
|||
// ICW3: tell Slave PIC its cascade identity (0000 0010)
|
|||
io_wait(); |
|||
|
|||
outb(PIC1_DATA, ICW4_8086); |
|||
io_wait(); |
|||
outb(PIC2_DATA, ICW4_8086); |
|||
io_wait(); |
|||
|
|||
// mask all interrupts
|
|||
outb(PIC1_DATA, 0xff); |
|||
outb(PIC2_DATA, 0xff); |
|||
|
|||
|
|||
} |
|||
|
|||
void pic_mask_irq(unsigned number, int do_mask) { |
|||
assert(number < 16); |
|||
|
|||
if(do_mask) |
|||
mask |= 1 << number; |
|||
else |
|||
mask &= ~(1 << number); |
|||
|
|||
outb(PIC1_DATA, mask & 0xff); |
|||
outb(PIC2_DATA, mask << 8); |
|||
} |
@ -0,0 +1,8 @@ |
|||
#pragma once |
|||
|
|||
void pic_init(void); |
|||
|
|||
// mask = 1 => irq masked
|
|||
// mask = 0 => irq unmasked
|
|||
void pic_mask_irq(unsigned number, int mask); |
|||
void pic_eoi(unsigned char irq); |
@ -0,0 +1,12 @@ |
|||
#!/bin/sh |
|||
cd ./limine-bootloader/ |
|||
rm -rf * |
|||
rm -rf .* |
|||
|
|||
git clone https://github.com/limine-bootloader/limine.git . --branch=$V-binary |
|||
cp BOOTX64.EFI ../disk_root/EFI/BOOT/BOOTX64.EFI |
|||
cp limine.sys ../disk_root/boot/limine.sys |
|||
|
|||
cd .. |
|||
|
|||
make clean && make |
Loading…
Reference in new issue