ps2 mouse: initial implementation

This commit is contained in:
Matheus
2023-01-05 22:58:23 -03:00
parent fc097489a1
commit 2b4e97735b
9 changed files with 236 additions and 105 deletions
+2
View File
@@ -68,6 +68,8 @@ void idt_bspinit(){
idt_setentry(&idt[VECTOR_TIMER], asmisr_timer, 0x28, FLAGS_PRESENT | FLAGS_TYPE_INTERRUPT, TIMER_IST);
idt_setentry(&idt[VECTOR_PS2MOUSE], asmisr_ps2mouse, 0x28, FLAGS_PRESENT | FLAGS_TYPE_INTERRUPT, 0);
idt_setentry(&idt[VECTOR_PS2KBD], asmisr_ps2kbd, 0x28, FLAGS_PRESENT | FLAGS_TYPE_INTERRUPT, 0);
idt_reload();
+1
View File
@@ -29,6 +29,7 @@
#define VECTOR_PANIC 0x20
#define VECTOR_LAPICNMI 0x21
#define VECTOR_MMUINVAL 0x22
#define VECTOR_PS2MOUSE 0x3F
#define VECTOR_PS2KBD 0x40
#define VECTOR_TIMER 0x80
+1
View File
@@ -10,6 +10,7 @@ extern void asmisr_pagefault();
extern void asmisr_panic();
extern void asmisr_lapicnmi();
extern void asmisr_mmuinval();
extern void asmisr_ps2mouse();
extern void asmisr_ps2kbd();
extern void asmisr_timer();
extern void asmisr_simd();
+108
View File
@@ -0,0 +1,108 @@
#ifndef _PS2_H_INCLUDE
#define _PS2_H_INCLUDE
#include <arch/timekeeper.h>
#include <arch/io.h>
#include <time.h>
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#define PS2_PORT_DATA 0x60
#define PS2_PORT_COMMAND 0x64
#define PS2_PORT_STATUS 0x64
#define RESEND 0xFE
#define ACK 0xFA
#define ECHO 0xEE
#define KEYBOARDIRQ 1
#define MOUSEIRQ 12
#define CTLR_CMD_SECONDPORTSELECT 0xD4
#define CTLR_CMD_DISABLEP1 0xAD
#define CTLR_CMD_DISABLEP2 0xA7
#define CTLR_CMD_READCFG 0x20
#define CTLR_CMD_WRITECFG 0x60
#define CTLR_CMD_SELFTEST 0xAA
#define CTLR_CMD_ENABLEP1 0xAE
#define CTLR_CMD_ENABLEP2 0xA8
#define CTLR_CMD_P1SELFTEST 0xAB
#define CTLR_CMD_P2SELFTEST 0xA9
#define CTLR_SELFTEST_OK 0x55
#define CONFIG_IRQP1 1
#define CONFIG_IRQP2 2
#define CONFIG_TRANSLATION 0x40
#define CONFIG_CLOCKP2 0x20
#define DEVICE_CMD_RESETSELFTEST 0xFF
#define DEVICE_CMD_IDENTIFY 0xF2
#define SELFTEST_OK 0xAA
static inline bool inbuffer_full(){
return (inb(PS2_PORT_STATUS) & 2) == 2;
}
static inline bool outbuffer_full(){
return (inb(PS2_PORT_STATUS) & 1) == 1;
}
static inline void write_command(uint8_t cmd){
while(inbuffer_full());
outb(PS2_PORT_COMMAND, cmd);
}
static inline void write_data(uint8_t cmd){
while(inbuffer_full());
outb(PS2_PORT_DATA, cmd);
}
static inline void device_command(int port, uint8_t command){
if(port == 2)
write_command(CTLR_CMD_SECONDPORTSELECT);
write_data(command);
}
static inline uint8_t read_data(){
while(!outbuffer_full());
return inb(PS2_PORT_DATA);
}
static inline uint8_t read_data_timeout(int ms, bool* timeout){
struct timespec initial = arch_timekeeper_gettimefromboot();
while(outbuffer_full() == false){
struct timespec current = arch_timekeeper_gettimefromboot();
if(time_diffms(initial, current) >= ms){
*timeout = true;
return 0;
}
}
*timeout = false;
return read_data();
}
static inline uint8_t device_write_response(int port, uint8_t command){
uint8_t r = RESEND;
int tries = 0;
while(r == RESEND && tries < 5){
device_command(port, command);
r = read_data();
++tries;
}
return r;
}
#endif
+1
View File
@@ -157,6 +157,7 @@ isr asmisr_general, isr_general, 0xFF
except asmisr_except, isr_except, 0xFF
isr asmisr_lapicnmi, isr_lapicnmi, 0x21
isr asmisr_mmuinval, isr_mmuinval, 0x22
isr asmisr_ps2mouse, isr_ps2mouse, 0x3F
isr asmisr_ps2kbd, isr_ps2kbd, 0x40
isr asmisr_timer, isr_timer, 0x80
isr asmisr_simd, isr_simd, 0x13
+5
View File
@@ -71,6 +71,11 @@ void isr_ps2kbd(arch_regs* reg){
apic_eoi();
}
void isr_ps2mouse(arch_regs* reg){
ps2mouse_irq();
apic_eoi();
}
void isr_timer(arch_regs* reg){
timer_irq(reg);
apic_eoi();
+4 -80
View File
@@ -10,86 +10,7 @@
#include <arch/timekeeper.h>
#include <arch/ps2kbd.h>
#define PS2_PORT_DATA 0x60
#define PS2_PORT_COMMAND 0x64
#define PS2_PORT_STATUS 0x64
#define RESEND 0xFE
#define ACK 0xFA
#define ECHO 0xEE
#define KEYBOARDIRQ 1
#define CTLR_CMD_SECONDPORTSELECT 0xD4
#define CTLR_CMD_DISABLEP1 0xAD
#define CTLR_CMD_DISABLEP2 0xA7
#define CTLR_CMD_READCFG 0x20
#define CTLR_CMD_WRITECFG 0x60
#define CTLR_CMD_SELFTEST 0xAA
#define CTLR_CMD_ENABLEP1 0xAE
#define CTLR_CMD_ENABLEP2 0xA8
#define CTLR_CMD_P1SELFTEST 0xAB
#define CTLR_CMD_P2SELFTEST 0xA9
#define CTLR_SELFTEST_OK 0x55
#define CONFIG_IRQP1 1
#define CONFIG_IRQP2 2
#define CONFIG_TRANSLATION 0x40
#define CONFIG_CLOCKP2 0x20
#define DEVICE_CMD_RESETSELFTEST 0xFF
#define SELFTEST_OK 0xAA
static inline bool inbuffer_full(){
return (inb(PS2_PORT_STATUS) & 2) == 2;
}
static inline bool outbuffer_full(){
return (inb(PS2_PORT_STATUS) & 1) == 1;
}
static inline void write_command(uint8_t cmd){
while(inbuffer_full());
outb(PS2_PORT_COMMAND, cmd);
}
static inline void write_data(uint8_t cmd){
while(inbuffer_full());
outb(PS2_PORT_DATA, cmd);
}
static inline void device_command(int port, uint8_t command){
if(port == 2)
write_command(CTLR_CMD_SECONDPORTSELECT);
write_data(command);
}
static inline uint8_t read_data(){
while(!outbuffer_full());
return inb(PS2_PORT_DATA);
}
static inline uint8_t read_data_timeout(int ms, bool* timeout){
struct timespec initial = arch_timekeeper_gettimefromboot();
while(outbuffer_full() == false){
struct timespec current = arch_timekeeper_gettimefromboot();
if(time_diffms(initial, current) >= ms){
printf("spinning!!! diff: %d\n", time_diffms(initial, current));
*timeout = true;
return 0;
}
}
*timeout = false;
return read_data();
}
#include <arch/ps2.h>
static bool reset_selftest(int port){
uint8_t r = RESEND;
@@ -221,5 +142,8 @@ void ps2_init(){
if(workingflag & 1)
ps2kbd_init();
if(workingflag & 2)
ps2mouse_init();
}
+2 -25
View File
@@ -16,24 +16,6 @@
static int kb;
static uint8_t ps2cmd(uint8_t cmd){
uint8_t response;
for(size_t i = 0; i < 3; ++i){
outb(PS2_PORT_DATA, cmd);
response = inb(PS2_PORT_DATA);
if(response != RESEND)
break;
}
return response;
}
static char codes[] = {
KEYCODE_RESERVED,
KEYCODE_ESCAPE,
@@ -176,13 +158,8 @@ void ps2kbd_irq(){
}
void ps2kbd_init(){
// maybe the ps/2 controller and keyboard should be initialised to a known state
// and not be assumed to be set up in a working manner by the firmware/bootloader
// this probably shouldn't assume the keyboard always being in the first port but oh well
// clear keyboard buffer data
// clear PS/2 buffer to make sure its empty
inb(PS2_PORT_DATA);
+112
View File
@@ -0,0 +1,112 @@
#include <arch/ps2.h>
#include <assert.h>
#include <arch/idt.h>
#include <arch/apic.h>
#include <arch/cls.h>
#define MOUSE_CMD_SAMPLERATE 0xF3
#define MOUSE_CMD_REPORTDATA 0xF4
#define MOUSE 0
#define MOUSE_Z 3
#define MOUSE_5B 4
static bool haswheel = false;
static bool fivebuttons = false;
static void mouse_setrate(int port, uint8_t rate){
device_write_response(port, MOUSE_CMD_SAMPLERATE);
device_write_response(port, rate);
}
static uint8_t identify(int port){
__assert(device_write_response(port, DEVICE_CMD_IDENTIFY) == ACK);
bool timeout;
uint8_t b = read_data_timeout(5, &timeout);
__assert(!timeout);
return b;
}
static int datac;
uint8_t data[4];
static inline bool enoughdata(){
if(!((haswheel && datac == 4) || (haswheel == false && datac == 3)))
return false;
else
return true;
}
void ps2mouse_irq(){
data[datac] = inb(PS2_PORT_DATA);
// check if the packet is bad
if((data[0] & 8) == 0){
datac = 0;
return;
}
++datac;
if(!enoughdata())
return;
datac = 0;
bool left = data[0] & 1;
bool right = data[0] & 2;
bool middle = data[0] & 4;
bool b4 = data[3] & 0x10;
bool b5 = data[3] & 0x20;
int xoffset = data[1] * (data[0] & 0x10 ? -1 : 1);
int yoffset = data[2] * (data[0] & 0x20 ? -1 : 1);
int zoffset = (data[3] & 0x7) * (data[3] & 0x8 ? -1 : 1);
}
void ps2mouse_init(){
if(identify(2) != MOUSE){
printf("Not a mouse!\n");
return;
}
mouse_setrate(2, 200);
mouse_setrate(2, 100);
mouse_setrate(2, 80);
if(identify(2) == MOUSE_Z){
haswheel = true;
mouse_setrate(2, 200);
mouse_setrate(2, 200);
mouse_setrate(2, 80);
if(identify(2) == MOUSE_5B)
fivebuttons = true;
}
mouse_setrate(2, 60); // TODO verify the best packet rate
__assert(device_write_response(2, MOUSE_CMD_REPORTDATA) == ACK);
ioapic_setlegacyirq(MOUSEIRQ, VECTOR_PS2MOUSE, arch_getcls()->lapicid, false);
}