Files
ViperOS/VKernel/Kernel/drivers/usb/usb.vp
T
TermiNexus 1b2f6853fc fix(usb): uhci 控制传输逐 TD 校验并暴露错误位,补描述符落盘探针
- _wait_for_complete 原先只查 status TD 的 bit21|bit22,DATA 阶段的 CRC/超时(bit18)、bitstuff(bit17)、babble(bit20) 会被当成成功 ⇒ GET_DESCRIPTOR 拿到零字节缓冲区仍返回 0,最终表现为 [usb] device class=00 proto=00 ep=0、usb_kbd 找不到键盘(现场)。改为对齐 Linux usb-uhci.h:新增 TD_CTRL_ERR_MASK/NAK_MASK 与 _td_error(),control_transfer 收尾逐个校验 setup/data/status 三个 TD,失败时打印三个状态字。

- usb.vp 增加两条探针:[usb] devdesc blen/btype/maxpkt0 与 [usb] cfgdesc total/b0/t0/iface/proto/ep,用于区分数据未落盘与解析未命中。
2026-10-16 15:15:58 +08:00

347 lines
12 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 mm.mm as mm
import string
import drivers.serial.uart.serial as serial
import drivers.usb.uhci as uhci
import drivers.usb.pci as pci
import platform.pch.timer as timer
import viperlib
define USB_DESC_DEVICE = 1
define USB_DESC_CONFIG = 2
define USB_DESC_STRING = 3
define USB_DESC_INTERFACE = 4
define USB_DESC_ENDPOINT = 5
define USB_REQ_GET_STATUS = 0
define USB_REQ_CLEAR_FEATURE = 1
define USB_REQ_SET_FEATURE = 3
define USB_REQ_SET_ADDRESS = 5
define USB_REQ_GET_DESCRIPTOR = 6
define USB_REQ_SET_DESCRIPTOR = 7
define USB_REQ_GET_CONFIGURATION = 8
define USB_REQ_SET_CONFIGURATION = 9
define USB_REQ_SET_INTERFACE = 11
define HID_CLASS = 0x03
define HID_SUBCLASS_BOOT = 0x01
define HID_PROTO_KEYBOARD = 0x01
define HID_PROTO_MOUSE = 0x02
define HID_REQ_SET_PROTOCOL = 0x0B
define HID_REQ_SET_IDLE = 0x0A
define HID_REQ_GET_REPORT = 0x01
define USB_MAX_DEVICES = 8
class usb_dev_desc:
bLength: uint8
bDescriptorType: uint8
bcdUSB: uint16
bDeviceClass: uint8
bDeviceSubClass: uint8
bDeviceProtocol: uint8
bMaxPacketSize0: uint8
idVendor: uint16
idProduct: uint16
bcdDevice: uint16
iManufacturer: uint8
iProduct: uint8
iSerialNumber: uint8
bNumConfigurations: uint8
class usb_config_desc:
bLength: uint8
bDescriptorType: uint8
wTotalLength: uint16
bNumInterfaces: uint8
bConfigurationValue: uint8
iConfiguration: uint8
bmAttributes: uint8
bMaxPower: uint8
class usb_iface_desc:
bLength: uint8
bDescriptorType: uint8
bInterfaceNumber: uint8
bAlternateSetting: uint8
bNumEndpoints: uint8
bInterfaceClass: uint8
bInterfaceSubClass: uint8
bInterfaceProtocol: uint8
iInterface: uint8
class usb_ep_desc:
bLength: uint8
bDescriptorType: uint8
bEndpointAddress: uint8
bmAttributes: uint8
wMaxPacketSize: uint16
bInterval: uint8
class usb_setup_pkt:
bmRequestType: uint8
bRequest: uint8
wValue: uint16
wIndex: uint16
wLength: uint16
class usb_device:
addr: uint8
ls: int
max_pkt0: uint8
iface_class: uint8
iface_subclass: uint8
iface_protocol: uint8
iface_num: uint8
ep_in: uint8
ep_in_max: uint16
ep_in_interval: uint8
ep_in_toggle: uint8
configured: int
_devices: [USB_MAX_DEVICES]usb_device
_device_count: int = 0
def _setup_packet(bmRequestType: uint8, bRequest: uint8, wValue: uint16, wIndex: uint16, wLength: uint16, buf: usb_setup_pkt*):
buf.bmRequestType = bmRequestType
buf.bRequest = bRequest
buf.wValue = wValue
buf.wIndex = wIndex
buf.wLength = wLength
def _send_control(dev_addr: uint8, ls: int, max_pkt: uint8, setup: usb_setup_pkt*, data_buf: rawptr, data_len: uint16, data_in: int) -> int:
return uhci.control_transfer(dev_addr, 0, ls, max_pkt, setup, data_buf, data_len, data_in)
def get_descriptor(dev_addr: uint8, ls: int, max_pkt: uint8, desc_type: uint8, desc_idx: uint8, buf: rawptr, length: uint16) -> int:
setup: usb_setup_pkt
_setup_packet(0x80, USB_REQ_GET_DESCRIPTOR, (uint16(desc_type) << 8) | desc_idx, 0, length, &setup)
return _send_control(dev_addr, ls, max_pkt, &setup, buf, length, 1)
def set_address(dev_addr: uint8, ls: int, max_pkt: uint8, new_addr: uint8) -> int:
setup: usb_setup_pkt
_setup_packet(0x00, USB_REQ_SET_ADDRESS, new_addr, 0, 0, &setup)
return _send_control(dev_addr, ls, max_pkt, &setup, None, 0, 0)
def set_configuration(dev_addr: uint8, ls: int, max_pkt: uint8, config_val: uint8) -> int:
setup: usb_setup_pkt
_setup_packet(0x00, USB_REQ_SET_CONFIGURATION, config_val, 0, 0, &setup)
return _send_control(dev_addr, ls, max_pkt, &setup, None, 0, 0)
def hid_set_protocol(dev_addr: uint8, ls: int, max_pkt: uint8, iface: uint8, protocol: uint8) -> int:
setup: usb_setup_pkt
_setup_packet(0x21, HID_REQ_SET_PROTOCOL, protocol, uint16(iface), 0, &setup)
return _send_control(dev_addr, ls, max_pkt, &setup, None, 0, 0)
def hid_set_idle(dev_addr: uint8, ls: int, max_pkt: uint8, iface: uint8, duration: uint8) -> int:
setup: usb_setup_pkt
_setup_packet(0x21, HID_REQ_SET_IDLE, uint16(duration) << 8, uint16(iface), 0, &setup)
return _send_control(dev_addr, ls, max_pkt, &setup, None, 0, 0)
def _parse_config(dev: usb_device*, config_buf: rawptr, total_len: uint16):
offset: int = 0
found_hid: int = 0
while offset < int(total_len):
p: uint8* = config_buf + uint64(offset)
desc_len: uint8 = *p
p2: uint8* = config_buf + uint64(offset) + 1
desc_type: uint8 = *p2
if desc_len == 0: break
# 边界:描述符整体须落在 config_buf(total_len 字节)内,且不得短于
# 所访问的结构体(interface=9 / endpoint=7),否则越界读。
if offset + int(desc_len) > int(total_len): break
if desc_type == USB_DESC_INTERFACE and int(desc_len) >= 9:
iface: usb_iface_desc* = usb_iface_desc*(config_buf + uint64(offset))
if iface.bInterfaceClass == HID_CLASS:
found_hid = 1
dev.iface_class = HID_CLASS
dev.iface_subclass = iface.bInterfaceSubClass
dev.iface_protocol = iface.bInterfaceProtocol
dev.iface_num = iface.bInterfaceNumber
if desc_type == USB_DESC_ENDPOINT and found_hid and int(desc_len) >= 7:
ep: usb_ep_desc* = usb_ep_desc*(config_buf + uint64(offset))
if (ep.bEndpointAddress & 0x80) != 0:
dev.ep_in = ep.bEndpointAddress & 0x0F
dev.ep_in_max = ep.wMaxPacketSize
dev.ep_in_interval = ep.bInterval
found_hid = 0
offset = offset + int(desc_len)
def enumerate_port(port: int) -> int:
global _device_count
if _device_count >= USB_MAX_DEVICES: return -1
ls: int = uhci.port_is_low_speed(port)
reset_ok: int = -1
for reset_retry in range(3):
if uhci.port_reset(port) == 0:
reset_ok = 0
break
timer.timer_msleep(50)
if reset_ok != 0:
return -2
timer.timer_msleep(10)
dev_buf: rawptr = mm.malloc(usb_dev_desc.__sizeof__())
if dev_buf is None: return -3
string.memset(dev_buf, 0, usb_dev_desc.__sizeof__())
result: int = get_descriptor(0, ls, 8, USB_DESC_DEVICE, 0, dev_buf, 8)
retry: int
for retry in range(3):
if result == 0: break
timer.timer_msleep(50)
uhci.port_reset(port)
timer.timer_msleep(10)
result = get_descriptor(0, ls, 8, USB_DESC_DEVICE, 0, dev_buf, 8)
if result != 0:
mm.free(dev_buf)
return -4
desc: usb_dev_desc* = dev_buf
max_pkt: uint8 = desc.bMaxPacketSize0
if max_pkt < 8: max_pkt = 8
# 探针:设备描述符只要读回 18/8 字节,bLength 必为 18、bDescriptorType 必为 1。
# 全 0 ⇒ 控制传输的 DATA 阶段没落盘(而非解析问题)。
_db0: [96]char
viperlib.snprintf(&_db0, 96, "[usb] devdesc blen=%d btype=%d maxpkt0=%d\n",
int(desc.bLength), int(desc.bDescriptorType), int(desc.bMaxPacketSize0))
serial.puts(&_db0)
new_addr: uint8 = uint8(_device_count + 1)
result = set_address(0, ls, max_pkt, new_addr)
for retry in range(3):
if result == 0: break
timer.timer_msleep(20)
result = set_address(0, ls, max_pkt, new_addr)
if result != 0:
mm.free(dev_buf)
return -5
timer.timer_msleep(10)
dev: usb_device* = &_devices[_device_count]
dev.addr = new_addr
dev.ls = ls
dev.max_pkt0 = max_pkt
dev.configured = 0
dev.iface_class = 0
dev.iface_subclass = 0
dev.iface_protocol = 0
dev.ep_in = 0
dev.ep_in_max = 0
dev.ep_in_interval = 0
dev.ep_in_toggle = 0
config_buf: rawptr = mm.malloc(256)
if config_buf is None:
mm.free(dev_buf)
return -6
string.memset(config_buf, 0, 256)
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, 9)
for retry in range(3):
if result == 0: break
timer.timer_msleep(50)
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, 9)
if result != 0:
mm.free(config_buf)
mm.free(dev_buf)
return -7
cfg: usb_config_desc* = config_buf
total_len: uint16 = cfg.wTotalLength
if total_len > 256: total_len = 256
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, total_len)
for retry in range(3):
if result == 0: break
timer.timer_msleep(50)
result = get_descriptor(new_addr, ls, max_pkt, USB_DESC_CONFIG, 0, config_buf, total_len)
if result != 0:
mm.free(config_buf)
mm.free(dev_buf)
return -8
_parse_config(dev, config_buf, total_len)
# 探针:配置描述符读回后,wTotalLength 应为 0x22/0x23、首字节应为 09 02(bLength=9, CONFIG)。
# total=0 或首字节为 0 ⇒ DATA 阶段没传回来;有内容但 iface 仍为 0 ⇒ 解析/布局问题。
_cb: uint8* = config_buf
_db1: [128]char
viperlib.snprintf(&_db1, 128, "[usb] cfgdesc total=%d b0=%02X t0=%02X iface=%02X proto=%02X ep=%d\n",
int(total_len), int(_cb[0]), int(_cb[1]),
int(dev.iface_class), int(dev.iface_protocol), int(dev.ep_in))
serial.puts(&_db1)
result = set_configuration(new_addr, ls, max_pkt, cfg.bConfigurationValue)
if result != 0:
mm.free(config_buf)
mm.free(dev_buf)
return -9
dev.configured = 1
if dev.iface_class == HID_CLASS:
hid_set_protocol(new_addr, ls, max_pkt, dev.iface_num, 0)
hid_set_idle(new_addr, ls, max_pkt, dev.iface_num, 0)
_device_count = _device_count + 1
mm.free(config_buf)
mm.free(dev_buf)
return int(new_addr)
def init() -> int:
global _device_count
_device_count = 0
io_base: uint16 = pci.find_uhci()
if io_base == 0:
serial.puts("[usb] UHCI controller not found\n")
return -1
buf: [64]char
viperlib.snprintf(&buf, 64, "[usb] UHCI at I/O 0x%04X\n", uint32(io_base))
serial.puts(buf)
if uhci.init(io_base) != 0:
serial.puts("[usb] UHCI init failed\n")
return -2
serial.puts("[usb] UHCI initialized\n")
timer.timer_msleep(50)
for port in range(2):
if uhci.port_is_connected(port):
viperlib.snprintf(&buf, 64, "[usb] port %d connected\n", uint32(port))
serial.puts(buf)
dev_id: int = enumerate_port(port)
if dev_id > 0:
dev: usb_device* = &_devices[dev_id - 1]
viperlib.snprintf(&buf, 64, "[usb] device addr=%d class=%02X proto=%02X ep=%d\n",
uint32(dev.addr), uint32(dev.iface_class),
uint32(dev.iface_protocol), uint32(dev.ep_in))
serial.puts(buf)
else:
viperlib.snprintf(&buf, 64, "[usb] enumerate port %d failed: %d\n", uint32(port), int32(dev_id))
serial.puts(buf)
return _device_count
def find_hid_device(protocol: uint8) -> usb_device*:
i: int
for i in range(_device_count):
dev: usb_device* = &_devices[i]
if dev.iface_class == HID_CLASS:
if dev.iface_protocol == protocol:
if dev.configured != 0:
return dev
return None
def read_interrupt(dev: usb_device*, buf: rawptr) -> int:
return 0