import t, c import mm.mm as mm import viperstring as 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 USB_DESC_DEVICE: t.CDefine = 1 USB_DESC_CONFIG: t.CDefine = 2 USB_DESC_STRING: t.CDefine = 3 USB_DESC_INTERFACE: t.CDefine = 4 USB_DESC_ENDPOINT: t.CDefine = 5 USB_REQ_GET_STATUS: t.CDefine = 0 USB_REQ_CLEAR_FEATURE: t.CDefine = 1 USB_REQ_SET_FEATURE: t.CDefine = 3 USB_REQ_SET_ADDRESS: t.CDefine = 5 USB_REQ_GET_DESCRIPTOR: t.CDefine = 6 USB_REQ_SET_DESCRIPTOR: t.CDefine = 7 USB_REQ_GET_CONFIGURATION: t.CDefine = 8 USB_REQ_SET_CONFIGURATION: t.CDefine = 9 USB_REQ_SET_INTERFACE: t.CDefine = 11 HID_CLASS: t.CDefine = 0x03 HID_SUBCLASS_BOOT: t.CDefine = 0x01 HID_PROTO_KEYBOARD: t.CDefine = 0x01 HID_PROTO_MOUSE: t.CDefine = 0x02 HID_REQ_SET_PROTOCOL: t.CDefine = 0x0B HID_REQ_SET_IDLE: t.CDefine = 0x0A HID_REQ_GET_REPORT: t.CDefine = 0x01 USB_MAX_DEVICES: t.CDefine = 8 class usb_dev_desc(t.CStruct): bLength: t.CUInt8T bDescriptorType: t.CUInt8T bcdUSB: t.CUInt16T bDeviceClass: t.CUInt8T bDeviceSubClass: t.CUInt8T bDeviceProtocol: t.CUInt8T bMaxPacketSize0: t.CUInt8T idVendor: t.CUInt16T idProduct: t.CUInt16T bcdDevice: t.CUInt16T iManufacturer: t.CUInt8T iProduct: t.CUInt8T iSerialNumber: t.CUInt8T bNumConfigurations: t.CUInt8T class usb_config_desc(t.CStruct): bLength: t.CUInt8T bDescriptorType: t.CUInt8T wTotalLength: t.CUInt16T bNumInterfaces: t.CUInt8T bConfigurationValue: t.CUInt8T iConfiguration: t.CUInt8T bmAttributes: t.CUInt8T bMaxPower: t.CUInt8T class usb_iface_desc(t.CStruct): bLength: t.CUInt8T bDescriptorType: t.CUInt8T bInterfaceNumber: t.CUInt8T bAlternateSetting: t.CUInt8T bNumEndpoints: t.CUInt8T bInterfaceClass: t.CUInt8T bInterfaceSubClass: t.CUInt8T bInterfaceProtocol: t.CUInt8T iInterface: t.CUInt8T class usb_ep_desc(t.CStruct): bLength: t.CUInt8T bDescriptorType: t.CUInt8T bEndpointAddress: t.CUInt8T bmAttributes: t.CUInt8T wMaxPacketSize: t.CUInt16T bInterval: t.CUInt8T class usb_setup_pkt(t.CStruct): bmRequestType: t.CUInt8T bRequest: t.CUInt8T wValue: t.CUInt16T wIndex: t.CUInt16T wLength: t.CUInt16T class usb_device(t.CStruct): addr: t.CUInt8T ls: t.CInt max_pkt0: t.CUInt8T iface_class: t.CUInt8T iface_subclass: t.CUInt8T iface_protocol: t.CUInt8T iface_num: t.CUInt8T ep_in: t.CUInt8T ep_in_max: t.CUInt16T ep_in_interval: t.CUInt8T ep_in_toggle: t.CUInt8T configured: t.CInt _devices: t.CArray[usb_device, USB_MAX_DEVICES] _device_count: t.CInt = 0 def _setup_packet(bmRequestType: t.CUInt8T, bRequest: t.CUInt8T, wValue: t.CUInt16T, wIndex: t.CUInt16T, wLength: t.CUInt16T, buf: usb_setup_pkt | t.CPtr): buf.bmRequestType = bmRequestType buf.bRequest = bRequest buf.wValue = wValue buf.wIndex = wIndex buf.wLength = wLength def _send_control(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, setup: usb_setup_pkt | t.CPtr, data_buf: t.CVoid | t.CPtr, data_len: t.CUInt16T, data_in: t.CInt) -> t.CInt: return uhci.control_transfer(dev_addr, 0, ls, max_pkt, c.Addr(setup), data_buf, data_len, data_in) def get_descriptor(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, desc_type: t.CUInt8T, desc_idx: t.CUInt8T, buf: t.CVoid | t.CPtr, length: t.CUInt16T) -> t.CInt: setup: usb_setup_pkt _setup_packet(0x80, USB_REQ_GET_DESCRIPTOR, (t.CUInt16T(desc_type) << 8) | desc_idx, 0, length, c.Addr(setup)) return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), buf, length, 1) def set_address(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, new_addr: t.CUInt8T) -> t.CInt: setup: usb_setup_pkt _setup_packet(0x00, USB_REQ_SET_ADDRESS, new_addr, 0, 0, c.Addr(setup)) return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), None, 0, 0) def set_configuration(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, config_val: t.CUInt8T) -> t.CInt: setup: usb_setup_pkt _setup_packet(0x00, USB_REQ_SET_CONFIGURATION, config_val, 0, 0, c.Addr(setup)) return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), None, 0, 0) def hid_set_protocol(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, iface: t.CUInt8T, protocol: t.CUInt8T) -> t.CInt: setup: usb_setup_pkt _setup_packet(0x21, HID_REQ_SET_PROTOCOL, protocol, t.CUInt16T(iface), 0, c.Addr(setup)) return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), None, 0, 0) def hid_set_idle(dev_addr: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, iface: t.CUInt8T, duration: t.CUInt8T) -> t.CInt: setup: usb_setup_pkt _setup_packet(0x21, HID_REQ_SET_IDLE, t.CUInt16T(duration) << 8, t.CUInt16T(iface), 0, c.Addr(setup)) return _send_control(dev_addr, ls, max_pkt, c.Addr(setup), None, 0, 0) def _parse_config(dev: usb_device | t.CPtr, config_buf: t.CVoid | t.CPtr, total_len: t.CUInt16T): offset: t.CInt = 0 found_hid: t.CInt = 0 while offset < t.CInt(total_len): p: t.CUInt8T | t.CPtr = config_buf + t.CUInt64T(offset) desc_len: t.CUInt8T = c.Deref(p) p2: t.CUInt8T | t.CPtr = config_buf + t.CUInt64T(offset) + 1 desc_type: t.CUInt8T = c.Deref(p2) if desc_len == 0: break if desc_type == USB_DESC_INTERFACE: iface: usb_iface_desc | t.CPtr = config_buf + t.CUInt64T(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: ep: usb_ep_desc | t.CPtr = config_buf + t.CUInt64T(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 + t.CInt(desc_len) def enumerate_port(port: t.CInt) -> t.CInt: global _device_count if _device_count >= USB_MAX_DEVICES: return -1 ls: t.CInt = uhci.port_is_low_speed(port) reset_ok: t.CInt = -1 reset_retry: t.CInt 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: t.CVoid | t.CPtr = mm.malloc(usb_dev_desc.__sizeof__()) if dev_buf is None: return -3 string.memset(dev_buf, 0, usb_dev_desc.__sizeof__()) result: t.CInt = get_descriptor(0, ls, 8, USB_DESC_DEVICE, 0, dev_buf, 8) retry: t.CInt 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 | t.CPtr = dev_buf max_pkt: t.CUInt8T = desc.bMaxPacketSize0 if max_pkt < 8: max_pkt = 8 new_addr: t.CUInt8T = t.CUInt8T(_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 | t.CPtr = c.Addr(_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: t.CVoid | t.CPtr = 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 | t.CPtr = config_buf total_len: t.CUInt16T = 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) 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 t.CInt(new_addr) def init() -> t.CInt: global _device_count _device_count = 0 io_base: t.CUInt16T = pci.find_uhci() if io_base == 0: serial.puts("[usb] UHCI controller not found\n") return -1 buf: t.CArray[t.CChar, 64] viperlib.snprintf(c.Addr(buf), 64, "[usb] UHCI at I/O 0x%04X\n", t.CUInt32T(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) port: t.CInt for port in range(2): if uhci.port_is_connected(port): viperlib.snprintf(c.Addr(buf), 64, "[usb] port %d connected\n", t.CUInt32T(port)) serial.puts(buf) dev_id: t.CInt = enumerate_port(port) if dev_id > 0: dev: usb_device | t.CPtr = c.Addr(_devices[dev_id - 1]) viperlib.snprintf(c.Addr(buf), 64, "[usb] device addr=%d class=%02X proto=%02X ep=%d\n", t.CUInt32T(dev.addr), t.CUInt32T(dev.iface_class), t.CUInt32T(dev.iface_protocol), t.CUInt32T(dev.ep_in)) serial.puts(buf) else: viperlib.snprintf(c.Addr(buf), 64, "[usb] enumerate port %d failed: %d\n", t.CUInt32T(port), t.CInt32T(dev_id)) serial.puts(buf) return _device_count def find_hid_device(protocol: t.CUInt8T) -> usb_device | t.CPtr: i: t.CInt for i in range(_device_count): dev: usb_device | t.CPtr = c.Addr(_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 | t.CPtr, buf: t.CVoid | t.CPtr) -> t.CInt: return 0