Files
ViperOS/VKernel/Kernel/drivers/usb/hid/usb_mouse.vp
T
TermiNexus 1c3fcd6e1e fix(vkernel): 推进中断 IN 传输的 DATA0/DATA1 翻转位
ep_in_toggle 此前全仓无任何回写,TD token 的 toggle 位恒为 DATA0,DATA toggle 永不交替。在两个中断完成回调重新排程前回写翻转,使下一次中断 IN 使用另一 PID;init 首排保持 DATA0(SET_CONFIGURATION 后端点默认值)。
2026-09-27 15:10:39 +08:00

88 lines
3.2 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 t, c
import drivers.usb.usb as usb
import drivers.usb.hid.hid as hid
import drivers.usb.uhci as uhci
import drivers.serial.uart.serial as serial
define MOUSE_BUF_SIZE = 1024
class usb_mouse_packet:
buttons: uint8
dx: int16
dy: int16
wheel: int8
mse_buf: [MOUSE_BUF_SIZE]usb_mouse_packet
mse_buf_head: int = 0
mse_buf_tail: int = 0
mse_buf_count: int = 0
mse_dev: usb.usb_device* = None
mse_report: hid.hid_mouse_report
mse_initialized: int = 0
mse_slot_id: int = -1
def init() -> int:
global mse_dev, mse_initialized, mse_slot_id
dev: usb.usb_device* = usb.find_hid_device(0x02)
if dev is None:
serial.puts("[usb_mse] no USB mouse found\n")
return -1
mse_dev = dev
if hid.init_mouse(dev) != 0:
serial.puts("[usb_mse] init failed\n")
return -2
mse_initialized = 1
serial.puts("[usb_mse] initialized\n")
mse_slot_id = uhci.register_int_callback(&_on_int_complete)
if mse_slot_id < 0:
serial.puts("[usb_mse] register callback failed\n")
mse_initialized = 0
return -3
# 中断传输长度不得超过 mse_report(4 字节),否则 DMA 越界写全局
mse_pkt_len: uint8 = 4
if dev.ep_in_max < 4: mse_pkt_len = uint8(dev.ep_in_max)
uhci.schedule_int_transfer(mse_slot_id, dev.addr, dev.ep_in, dev.ls, mse_pkt_len, dev.ep_in_toggle, &mse_report)
return 0
def _on_int_complete() -> int:
global mse_buf_head, mse_buf_tail, mse_buf_count
if mse_initialized == 0: return 0
if mse_report.dx != 0 or mse_report.dy != 0 or mse_report.buttons != 0:
if mse_buf_count < MOUSE_BUF_SIZE:
mse_buf[mse_buf_tail].buttons = mse_report.buttons
mse_buf[mse_buf_tail].dx = int16(mse_report.dx)
mse_buf[mse_buf_tail].dy = int16(mse_report.dy)
mse_buf[mse_buf_tail].wheel = mse_report.wheel
mse_buf_tail = mse_buf_tail + 1
if mse_buf_tail >= MOUSE_BUF_SIZE:
mse_buf_tail = 0
mse_buf_count += 1
dev: usb.usb_device* = mse_dev
if dev is not None and mse_slot_id >= 0:
mse_pkt_len2: uint8 = 4
if dev.ep_in_max < 4: mse_pkt_len2 = uint8(dev.ep_in_max)
# 推进 DATA0/DATA1 翻转位:本回调表示上一次中断 IN 事务已结束(IRQ 中 TD 不再
# ACTIVE),翻转后本次重排使用另一 PID。全仓仅此处推进 ep_in_toggle;不推进
# 则 TD token 的 toggle 位恒为 DATA0,DATA toggle 永不交替。
dev.ep_in_toggle = uint8(dev.ep_in_toggle ^ 1)
uhci.schedule_int_transfer(mse_slot_id, dev.addr, dev.ep_in, dev.ls, mse_pkt_len2, dev.ep_in_toggle, &mse_report)
return 0
def has_data() -> int:
if mse_buf_count > 0: return 1
return 0
def read_packet(out: usb_mouse_packet*) -> int:
global mse_buf_head, mse_buf_count
if mse_buf_count == 0: return -1
out.buttons = mse_buf[mse_buf_head].buttons
out.dx = mse_buf[mse_buf_head].dx
out.dy = mse_buf[mse_buf_head].dy
out.wheel = mse_buf[mse_buf_head].wheel
mse_buf_head = mse_buf_head + 1
if mse_buf_head >= MOUSE_BUF_SIZE:
mse_buf_head = 0
mse_buf_count -= 1
return 0