Files
TermiNexus 3a497e38ec fix(usb): 控制传输短读判失败+描述符链完整性校验;CCB 读改写屏蔽 IRQ1;清理已验证探针
uhci.control_transfer:除错误位外再比对 DATA TD 的 Actual Length(bit10:0)。短读时错误位可能全 0(QEMU/硬件不把短包当错误),只查错误位会漏 —— 现场是 USB 鼠标的 25 字节配置描述符只落下前 9 字节 ⇒ 接口解析为 0 ⇒ [usb_mse] no USB mouse found。

usb._parse_config 改为返回实际走完的偏移,enumerate_port 要求恰好走完 total_len,否则重读、仍不完整即报错返回(fail-fast,不带着半截描述符继续);同时删除两条探针。

keyboard.init/mouse.init 读-改-写 CCB 全程 pic.setMask(1):读 CCB 的 0x20 会把 CCB 值放进 0x60 输出缓冲并拉高 IRQ1,IRQ1 handler 会把它当扫描码抢走(现场 sc=0x47),使回读拿到残留值。改为只在校验失败时打印错误,去掉全部 [kbd] 探针。

清理已验证调试输出:idt 的 IRQ1 handler 探针及其计数器、desktop 的 [dbg] back_fb/row_buf/bg_row_buf、main 的 [DBG] LAPIC/idt32/swint/pic_isr 与 [DB] BootInfo 转储、timer 的 [PIT] 与自旋打印及随之无用的 import。
2026-10-16 15:26:35 +08:00

148 lines
4.2 KiB
Plaintext
Raw Permalink 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
import drivers.serial.uart.serial as serial
import t, c
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
pack_head: static uint32 = 0
pack_tail: static uint32 = 0
pack_count: static uint32 = 0
mse_irq_cnt: static uint64 = 0
cycle: static uint8 = 0
byte1: static uint8 = 0
byte2: static uint8 = 0
byte3: static uint8 = 0
mouse_x: static int32 = 0
mouse_y: static int32 = 0
mouse_buttons: static 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")