mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-27 12:48:22 +00:00
ps2 mouse: initial implementation
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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();
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user