Files
ViperOS/VKernel/Kernel/drivers/input/mouse/mouse.vp
T
TermiNexus 3583f78efc refactor(kernel): 适配 ViperC 新语法
- 去掉不再需要的 import t, c
- class → struct(纯数据聚合)
- t.CArray[T, N] → [N]T
- static 修饰符移到类型前
- @__attribute(packed) → @__attribute__(packed)
- UHCI 中断回调参数改用 callable[[], int]
- 同步 CPUID 注释中的旧类型名
2026-10-26 22:39:56 +08:00

146 lines
4.1 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import asm
import intr.idt as idt
import platform.pch.pic as pic
define MOUSE_DATA = 0x60
define MOUSE_STATUS = 0x64
define MOUSE_COMMAND = 0x64
define MOUSE_BUF_SIZE = 1024
define MOUSE_LEFT = 0x01
define MOUSE_RIGHT = 0x02
define MOUSE_MIDDLE = 0x04
class mouse_packet:
flags: uint8
dx: uint8 # 原始幅值字节(符号在 flags.bit4)
dy: uint8 # 原始幅值字节(符号在 flags.bit5)
buttons: uint8
packets: [MOUSE_BUF_SIZE]mouse_packet
static pack_head: uint32 = 0
static pack_tail: uint32 = 0
static pack_count: uint32 = 0
static mse_irq_cnt: uint64 = 0
static cycle: uint8 = 0
static byte1: uint8 = 0
static byte2: uint8 = 0
static byte3: uint8 = 0
static mouse_x: int32 = 0
static mouse_y: int32 = 0
static mouse_buttons: uint8 = 0
def _wait_read():
timeout: uint32 = 100000
for _ in range(timeout, 0, -1):
if (asm.inb(MOUSE_STATUS) & 0x01) != 0: return
def _wait_write():
timeout: uint32 = 100000
for _ in range(timeout, 0, -1):
if (asm.inb(MOUSE_STATUS) & 0x02) == 0: return
def _write_cmd(cmd: uint8):
_wait_write()
asm.outb(MOUSE_COMMAND, 0xD4)
_wait_write()
asm.outb(MOUSE_DATA, cmd)
_wait_read()
asm.inb(MOUSE_DATA)
def irq_handler() -> int:
global cycle, byte1, byte2, byte3, pack_tail, pack_count, mse_irq_cnt
mse_irq_cnt += 1
status: uint8 = asm.inb(MOUSE_STATUS)
if (status & 0x20) == 0: return 0
data: uint8 = asm.inb(MOUSE_DATA)
if cycle == 0:
if (data & 0x08) != 0:
byte1 = data
cycle = 1
return 0
if cycle == 1:
byte2 = data
cycle = 2
return 0
byte3 = data
cycle = 0
# 丢弃带溢出位的包(bit6/bit7 = X/Y overflow):此时设备给的是饱和值,
# 直接采用会产生 ±127 级跳变(表现为光标“飞”)。
if (byte1 & 0xC0) != 0:
return 0
if pack_count < MOUSE_BUF_SIZE:
packets[pack_tail].flags = byte1
packets[pack_tail].dx = byte2
packets[pack_tail].dy = byte3
packets[pack_tail].buttons = byte1 & uint8(0x07)
pack_tail = pack_tail + 1
if pack_tail >= MOUSE_BUF_SIZE:
pack_tail = 0
pack_count += 1
return 0
def read_packet(out: mouse_packet*) -> int:
global pack_head, pack_count
asm.cli()
if pack_count == 0:
asm.sti()
out.flags = 0
out.dx = 0
out.dy = 0
out.buttons = 0
return -1
out.flags = packets[pack_head].flags
out.dx = packets[pack_head].dx
out.dy = packets[pack_head].dy
out.buttons = packets[pack_head].buttons
pack_head = pack_head + 1
if pack_head >= MOUSE_BUF_SIZE:
pack_head = 0
pack_count -= 1
asm.sti()
return 0
def has_data() -> int:
return pack_count
def get_x() -> int32:
return mouse_x
def get_y() -> int32:
return mouse_y
def get_buttons() -> uint8:
return mouse_buttons
def init():
_wait_write()
asm.outb(MOUSE_COMMAND, 0xA8)
# 读-改-写 CCB 期间屏蔽 IRQ1:与 keyboard.init 同理 —— 0x20 读 CCB 会把 CCB 值放进
# 0x60 输出缓冲并拉高 IRQ1,键盘 ISR 一旦运行就会把它当扫描码抢走(现场:sc=0x47
# 正是这里清 bit5 后的 CCB),于是下面的 inb(0x60) 只能拿到残留值 ⇒ 可能把错误 CCB 写回。
pic.setMask(1)
_wait_write()
asm.outb(MOUSE_COMMAND, 0x20)
_wait_read()
status: uint8 = asm.inb(MOUSE_DATA)
status = status | 0x02
status = status & 0xDF
_wait_write()
asm.outb(MOUSE_COMMAND, 0x60)
_wait_write()
asm.outb(MOUSE_DATA, status)
pic.clearMask(1)
_write_cmd(0xF6)
# 分辨率设为 8 counts/mm:0xF6(Set Defaults) 会把它重置为最粗的 4 counts/mm,
# 于是每个计数对应的位移偏大。设细一档后光标更稳、不易“飞”。
_write_cmd(0xE8)
_write_cmd(0x03)
_write_cmd(0xF4)
pic.clearMask(12)
idt.irqInstallHandler(12, irq_handler, "mouse")