kernel/dev/mouse.c held the pointer inside literal 800x600 bounds. That was correct while 800x600 was the only mode the loader could set, which it was until the resolution became a boot-time choice. At 1280x800 the pointer simply stopped two thirds of the way across and would not go further -- which reads as the cursor drifting away from the host's rather than as a clamp. vga.c grows vga_get_width/vga_get_height for it. The mode is chosen at boot now, so nothing above the framebuffer may hardcode its size, and these are the first two callers that needed to ask. Verified that the system still builds and boots at 1280x800, and that bootcheck is 108 [ok] and schcom-test passes. I did not manage to photograph the pointer past the old limit in the time available -- there is no reader for /dev/mouse in the image and the screendump attempt did not resolve, so the fix rests on inspection rather than on a picture. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
224 lines
No EOL
4.5 KiB
C
224 lines
No EOL
4.5 KiB
C
#include "types.h"
|
|
#include "defs.h"
|
|
#include "irq.h"
|
|
#include "x86.h"
|
|
#include "traps.h"
|
|
#include "spinlock.h"
|
|
#include "sleeplock.h"
|
|
#include "fs.h"
|
|
#include "file.h"
|
|
|
|
#define KBD_S_STAT 0x64
|
|
#define KBD_S_DATA 0x60
|
|
#define KBD_C_WRITE 0xD4
|
|
#define MOUSE_ACK 0xFA
|
|
|
|
struct {
|
|
struct spinlock lock;
|
|
int x;
|
|
int y;
|
|
uint8 buttons;
|
|
} mouse_state;
|
|
|
|
static void
|
|
mouse_wait(int type)
|
|
{
|
|
int timeout = 100000;
|
|
if(type == 0){
|
|
while(timeout-- && !(inb(KBD_S_STAT) & 0x01));
|
|
} else {
|
|
while(timeout-- && (inb(KBD_S_STAT) & 0x02));
|
|
}
|
|
}
|
|
|
|
static void
|
|
mouse_write(uchar data)
|
|
{
|
|
mouse_wait(1);
|
|
outb(KBD_S_STAT, KBD_C_WRITE);
|
|
mouse_wait(1);
|
|
outb(KBD_S_DATA, data);
|
|
}
|
|
|
|
static uchar
|
|
mouse_read(void)
|
|
{
|
|
mouse_wait(0);
|
|
return inb(KBD_S_DATA);
|
|
}
|
|
|
|
static void
|
|
mouse_irq(void *arg)
|
|
{
|
|
(void)arg;
|
|
mouseintr();
|
|
}
|
|
|
|
// Move the pointer. Caller holds mouse_state.lock.
|
|
//
|
|
// Positive dy is *down*, matching both the screen and USB HID. The PS/2
|
|
// packet reports the opposite, which is why its caller negates first --
|
|
// there is one pointer and two protocols disagreeing about which way is up,
|
|
// and the conversion belongs at the edge rather than in here.
|
|
static void
|
|
mouse_move_locked(int dx, int dy)
|
|
{
|
|
mouse_state.x += dx;
|
|
mouse_state.y += dy;
|
|
|
|
// Clamp to the screen that actually exists. These were the literals 800 and
|
|
// 600, which was correct while that was the only mode the loader could set.
|
|
// It is a boot-time choice now (press R), and at 1280x800 the pointer simply
|
|
// stopped two thirds of the way across -- which reads as the cursor drifting
|
|
// away from the host's, rather than as a clamp.
|
|
int maxx = (int)vga_get_width();
|
|
int maxy = (int)vga_get_height();
|
|
if(maxx <= 0) maxx = 800;
|
|
if(maxy <= 0) maxy = 600;
|
|
|
|
if(mouse_state.x < 0) mouse_state.x = 0;
|
|
if(mouse_state.y < 0) mouse_state.y = 0;
|
|
if(mouse_state.x >= maxx) mouse_state.x = maxx - 1;
|
|
if(mouse_state.y >= maxy) mouse_state.y = maxy - 1;
|
|
}
|
|
|
|
// The same pointer, moved by something that is not the PS/2 port. USB HID
|
|
// uses this; anything else that produces motion events should too.
|
|
void
|
|
mouse_inject(int dx, int dy, int buttons)
|
|
{
|
|
acquire(&mouse_state.lock);
|
|
mouse_state.buttons = buttons;
|
|
mouse_move_locked(dx, dy);
|
|
release(&mouse_state.lock);
|
|
|
|
input_mouse(dx, dy, buttons);
|
|
}
|
|
|
|
void
|
|
mouseintr(void)
|
|
{
|
|
static uchar buf[3];
|
|
static int phase = 0;
|
|
uchar status;
|
|
|
|
status = inb(KBD_S_STAT);
|
|
|
|
if(!(status & 0x01) || !(status & 0x20)){
|
|
return;
|
|
}
|
|
|
|
uchar data = inb(KBD_S_DATA);
|
|
|
|
acquire(&mouse_state.lock);
|
|
|
|
if(phase == 0 && !(data & 0x08)){
|
|
release(&mouse_state.lock);
|
|
return;
|
|
}
|
|
|
|
buf[phase++] = data;
|
|
|
|
if(phase == 3){
|
|
phase = 0;
|
|
|
|
mouse_state.buttons = buf[0] & 0x07;
|
|
int dx = (buf[0] & 0x10) ? (int)buf[1] - 256 : buf[1];
|
|
int dy = (buf[0] & 0x20) ? (int)buf[2] - 256 : buf[2];
|
|
|
|
// The overflow bits mean the delta saturated and is meaningless; moving
|
|
// by it would throw the pointer across the screen.
|
|
if(!(buf[0] & 0x40) && !(buf[0] & 0x80))
|
|
mouse_move_locked(dx, -dy);
|
|
else
|
|
dx = dy = 0;
|
|
|
|
release(&mouse_state.lock);
|
|
|
|
// Outside the lock: input_report takes its own, and holding two at once
|
|
// is how a lock ordering rule gets invented by accident.
|
|
input_mouse(dx, -dy, buf[0] & 0x07);
|
|
return;
|
|
}
|
|
|
|
release(&mouse_state.lock);
|
|
}
|
|
|
|
int get_mouse_x(void) {
|
|
int x;
|
|
acquire(&mouse_state.lock);
|
|
x = mouse_state.x;
|
|
release(&mouse_state.lock);
|
|
return x;
|
|
}
|
|
|
|
int get_mouse_y(void) {
|
|
int y;
|
|
acquire(&mouse_state.lock);
|
|
y = mouse_state.y;
|
|
release(&mouse_state.lock);
|
|
return y;
|
|
}
|
|
|
|
uint8 get_mouse_buttons(void) {
|
|
uint8 b;
|
|
acquire(&mouse_state.lock);
|
|
b = mouse_state.buttons;
|
|
release(&mouse_state.lock);
|
|
return b;
|
|
}
|
|
|
|
int
|
|
mouseread(struct inode *ip, uint off, char *dst, int n)
|
|
{
|
|
struct mouse_data m;
|
|
int size = sizeof(struct mouse_data);
|
|
|
|
if(n < size) {
|
|
return -1;
|
|
}
|
|
|
|
m.x = get_mouse_x();
|
|
m.y = get_mouse_y();
|
|
m.buttons = get_mouse_buttons();
|
|
|
|
memmove(dst, &m, size);
|
|
|
|
return size;
|
|
}
|
|
|
|
void
|
|
mouseinit(void)
|
|
{
|
|
initlock(&mouse_state.lock, "mouse");
|
|
mouse_state.x = 400;
|
|
mouse_state.y = 300;
|
|
|
|
while(inb(KBD_S_STAT) & 0x01)
|
|
inb(KBD_S_DATA);
|
|
|
|
mouse_wait(1);
|
|
outb(KBD_S_STAT, 0xA8);
|
|
|
|
mouse_wait(1);
|
|
outb(KBD_S_STAT, 0x20);
|
|
mouse_wait(0);
|
|
uchar cb = inb(KBD_S_DATA);
|
|
|
|
cb |= 0x02;
|
|
cb |= 0x01;
|
|
cb &= ~0x20;
|
|
|
|
mouse_wait(1);
|
|
outb(KBD_S_STAT, 0x60);
|
|
mouse_wait(1);
|
|
outb(KBD_S_DATA, cb);
|
|
|
|
mouse_write(0xF6);
|
|
mouse_read();
|
|
|
|
mouse_write(0xF4);
|
|
mouse_read();
|
|
|
|
irq_register(IRQ_MOUSE, mouse_irq, 0, "ps2-mouse", 0);
|
|
} |