Initial import of ViperOS
This commit is contained in:
37
VKernel/Kernel/drivers/usb/hid/hid.py
Normal file
37
VKernel/Kernel/drivers/usb/hid/hid.py
Normal file
@@ -0,0 +1,37 @@
|
||||
import t, c
|
||||
import drivers.usb.usb as usb
|
||||
|
||||
HID_BOOT_PROTOCOL: t.CDefine = 0
|
||||
HID_REPORT_PROTOCOL: t.CDefine = 1
|
||||
|
||||
HID_KBD_REPORT_SIZE: t.CDefine = 8
|
||||
HID_MOUSE_REPORT_SIZE: t.CDefine = 4
|
||||
|
||||
class hid_kbd_report(t.CStruct):
|
||||
modifier: t.CUInt8T
|
||||
reserved: t.CUInt8T
|
||||
keycode: t.CArray[t.CUInt8T, 6]
|
||||
|
||||
class hid_mouse_report(t.CStruct):
|
||||
buttons: t.CUInt8T
|
||||
dx: t.CInt8T
|
||||
dy: t.CInt8T
|
||||
wheel: t.CInt8T
|
||||
|
||||
def init_keyboard(dev: usb.usb_device | t.CPtr) -> t.CInt:
|
||||
if dev.iface_class != 0x03: return -1
|
||||
if dev.iface_protocol != 0x01: return -2
|
||||
if dev.ep_in == 0: return -3
|
||||
return 0
|
||||
|
||||
def init_mouse(dev: usb.usb_device | t.CPtr) -> t.CInt:
|
||||
if dev.iface_class != 0x03: return -1
|
||||
if dev.iface_protocol != 0x02: return -2
|
||||
if dev.ep_in == 0: return -3
|
||||
return 0
|
||||
|
||||
def read_keyboard(dev: usb.usb_device | t.CPtr, report: hid_kbd_report | t.CPtr) -> t.CInt:
|
||||
return usb.read_interrupt(dev, c.Addr(report))
|
||||
|
||||
def read_mouse(dev: usb.usb_device | t.CPtr, report: hid_mouse_report | t.CPtr) -> t.CInt:
|
||||
return usb.read_interrupt(dev, c.Addr(report))
|
||||
111
VKernel/Kernel/drivers/usb/hid/usb_kbd.py
Normal file
111
VKernel/Kernel/drivers/usb/hid/usb_kbd.py
Normal file
@@ -0,0 +1,111 @@
|
||||
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
|
||||
|
||||
KBD_BUF_SIZE: t.CDefine = 1024
|
||||
KBD_EVT_PRESS: t.CDefine = 0
|
||||
KBD_EVT_RELEASE: t.CDefine = 1
|
||||
|
||||
class usb_kbd_event(t.CStruct):
|
||||
modifier: t.CUInt8T
|
||||
keycode: t.CUInt8T
|
||||
event_type: t.CUInt8T
|
||||
|
||||
kbd_buf: t.CArray[usb_kbd_event, KBD_BUF_SIZE]
|
||||
kbd_buf_head: t.CInt = 0
|
||||
kbd_buf_tail: t.CInt = 0
|
||||
kbd_buf_count: t.CInt = 0
|
||||
kbd_dev: usb.usb_device | t.CPtr = None
|
||||
kbd_report: hid.hid_kbd_report
|
||||
kbd_prev_keycodes: t.CArray[t.CUInt8T, 6]
|
||||
kbd_initialized: t.CInt = 0
|
||||
kbd_slot_id: t.CInt = -1
|
||||
|
||||
def init() -> t.CInt:
|
||||
global kbd_dev, kbd_initialized, kbd_slot_id
|
||||
dev: usb.usb_device | t.CPtr = usb.find_hid_device(0x01)
|
||||
if dev is None:
|
||||
serial.puts("[usb_kbd] no USB keyboard found\n")
|
||||
return -1
|
||||
kbd_dev = dev
|
||||
if hid.init_keyboard(dev) != 0:
|
||||
serial.puts("[usb_kbd] init failed\n")
|
||||
return -2
|
||||
kbd_initialized = 1
|
||||
serial.puts("[usb_kbd] initialized\n")
|
||||
kbd_slot_id = uhci.register_int_callback(c.Addr(_on_int_complete))
|
||||
if kbd_slot_id < 0:
|
||||
serial.puts("[usb_kbd] register callback failed\n")
|
||||
kbd_initialized = 0
|
||||
return -3
|
||||
uhci.schedule_int_transfer(kbd_slot_id, dev.addr, dev.ep_in, dev.ls, t.CUInt8T(dev.ep_in_max), dev.ep_in_toggle, c.Addr(kbd_report))
|
||||
return 0
|
||||
|
||||
def _on_int_complete() -> t.CInt:
|
||||
global kbd_buf_head, kbd_buf_tail, kbd_buf_count, kbd_prev_keycodes
|
||||
if kbd_initialized == 0: return 0
|
||||
i: t.CInt
|
||||
j: t.CInt
|
||||
for i in range(6):
|
||||
code: t.CUInt8T = kbd_report.keycode[i]
|
||||
if code == 0: continue
|
||||
found: t.CInt = 0
|
||||
for j in range(6):
|
||||
if code == kbd_prev_keycodes[j]:
|
||||
found = 1
|
||||
break
|
||||
if found == 0:
|
||||
if kbd_buf_count < KBD_BUF_SIZE:
|
||||
kbd_buf[kbd_buf_tail].modifier = kbd_report.modifier
|
||||
kbd_buf[kbd_buf_tail].keycode = code
|
||||
kbd_buf[kbd_buf_tail].event_type = KBD_EVT_PRESS
|
||||
kbd_buf_tail = kbd_buf_tail + 1
|
||||
if kbd_buf_tail >= KBD_BUF_SIZE:
|
||||
kbd_buf_tail = 0
|
||||
kbd_buf_count += 1
|
||||
for i in range(6):
|
||||
prev: t.CUInt8T = kbd_prev_keycodes[i]
|
||||
if prev == 0: continue
|
||||
found2: t.CInt = 0
|
||||
for j in range(6):
|
||||
if prev == kbd_report.keycode[j]:
|
||||
found2 = 1
|
||||
break
|
||||
if found2 == 0:
|
||||
if kbd_buf_count < KBD_BUF_SIZE:
|
||||
kbd_buf[kbd_buf_tail].modifier = kbd_report.modifier
|
||||
kbd_buf[kbd_buf_tail].keycode = prev
|
||||
kbd_buf[kbd_buf_tail].event_type = KBD_EVT_RELEASE
|
||||
kbd_buf_tail = kbd_buf_tail + 1
|
||||
if kbd_buf_tail >= KBD_BUF_SIZE:
|
||||
kbd_buf_tail = 0
|
||||
kbd_buf_count += 1
|
||||
for i in range(6):
|
||||
kbd_prev_keycodes[i] = kbd_report.keycode[i]
|
||||
dev: usb.usb_device | t.CPtr = kbd_dev
|
||||
if dev is not None and kbd_slot_id >= 0:
|
||||
uhci.schedule_int_transfer(kbd_slot_id, dev.addr, dev.ep_in, dev.ls, t.CUInt8T(dev.ep_in_max), dev.ep_in_toggle, c.Addr(kbd_report))
|
||||
return 0
|
||||
|
||||
def has_data() -> t.CInt:
|
||||
if kbd_buf_count > 0: return 1
|
||||
return 0
|
||||
|
||||
def poll() -> t.CInt:
|
||||
if kbd_initialized == 0: return 0
|
||||
if kbd_buf_count > 0: return 1
|
||||
return 0
|
||||
|
||||
def read_event(out: usb_kbd_event | t.CPtr) -> t.CInt:
|
||||
global kbd_buf_head, kbd_buf_count
|
||||
if kbd_buf_count == 0: return -1
|
||||
out.modifier = kbd_buf[kbd_buf_head].modifier
|
||||
out.keycode = kbd_buf[kbd_buf_head].keycode
|
||||
out.event_type = kbd_buf[kbd_buf_head].event_type
|
||||
kbd_buf_head = kbd_buf_head + 1
|
||||
if kbd_buf_head >= KBD_BUF_SIZE:
|
||||
kbd_buf_head = 0
|
||||
kbd_buf_count -= 1
|
||||
return 0
|
||||
77
VKernel/Kernel/drivers/usb/hid/usb_mouse.py
Normal file
77
VKernel/Kernel/drivers/usb/hid/usb_mouse.py
Normal file
@@ -0,0 +1,77 @@
|
||||
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
|
||||
|
||||
MOUSE_BUF_SIZE: t.CDefine = 1024
|
||||
|
||||
class usb_mouse_packet(t.CStruct):
|
||||
buttons: t.CUInt8T
|
||||
dx: t.CInt16T
|
||||
dy: t.CInt16T
|
||||
wheel: t.CInt8T
|
||||
|
||||
mse_buf: t.CArray[usb_mouse_packet, MOUSE_BUF_SIZE]
|
||||
mse_buf_head: t.CInt = 0
|
||||
mse_buf_tail: t.CInt = 0
|
||||
mse_buf_count: t.CInt = 0
|
||||
mse_dev: usb.usb_device | t.CPtr = None
|
||||
mse_report: hid.hid_mouse_report
|
||||
mse_initialized: t.CInt = 0
|
||||
mse_slot_id: t.CInt = -1
|
||||
|
||||
def init() -> t.CInt:
|
||||
global mse_dev, mse_initialized, mse_slot_id
|
||||
dev: usb.usb_device | t.CPtr = 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(c.Addr(_on_int_complete))
|
||||
if mse_slot_id < 0:
|
||||
serial.puts("[usb_mse] register callback failed\n")
|
||||
mse_initialized = 0
|
||||
return -3
|
||||
uhci.schedule_int_transfer(mse_slot_id, dev.addr, dev.ep_in, dev.ls, t.CUInt8T(dev.ep_in_max), dev.ep_in_toggle, c.Addr(mse_report))
|
||||
return 0
|
||||
|
||||
def _on_int_complete() -> t.CInt:
|
||||
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 = t.CInt16T(mse_report.dx)
|
||||
mse_buf[mse_buf_tail].dy = t.CInt16T(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 | t.CPtr = mse_dev
|
||||
if dev is not None and mse_slot_id >= 0:
|
||||
uhci.schedule_int_transfer(mse_slot_id, dev.addr, dev.ep_in, dev.ls, t.CUInt8T(dev.ep_in_max), dev.ep_in_toggle, c.Addr(mse_report))
|
||||
return 0
|
||||
|
||||
def has_data() -> t.CInt:
|
||||
if mse_buf_count > 0: return 1
|
||||
return 0
|
||||
|
||||
def read_packet(out: usb_mouse_packet | t.CPtr) -> t.CInt:
|
||||
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
|
||||
93
VKernel/Kernel/drivers/usb/pci.py
Normal file
93
VKernel/Kernel/drivers/usb/pci.py
Normal file
@@ -0,0 +1,93 @@
|
||||
import t, c
|
||||
import asm
|
||||
|
||||
PCI_CONFIG_ADDR: t.CDefine = 0xCF8
|
||||
PCI_CONFIG_DATA: t.CDefine = 0xCFC
|
||||
|
||||
PCI_CLASS_SERIAL_USB: t.CDefine = 0x0C03
|
||||
PCI_CLASS_SERIAL_UHCI: t.CDefine = 0x0C0300
|
||||
PCI_CLASS_SERIAL_OHCI: t.CDefine = 0x0C0310
|
||||
PCI_CLASS_SERIAL_EHCI: t.CDefine = 0x0C0320
|
||||
PCI_CLASS_SERIAL_XHCI: t.CDefine = 0x0C0330
|
||||
|
||||
PCI_CMD_IO_SPACE: t.CDefine = 0x0001
|
||||
PCI_CMD_BUS_MASTER: t.CDefine = 0x0004
|
||||
|
||||
class pci_device(t.CStruct):
|
||||
bus: t.CUInt8T
|
||||
dev: t.CUInt8T
|
||||
func: t.CUInt8T
|
||||
vendor_id: t.CUInt16T
|
||||
device_id: t.CUInt16T
|
||||
class_code: t.CUInt32T
|
||||
irq: t.CUInt8T
|
||||
bar: t.CArray[t.CUInt32T, 6]
|
||||
|
||||
def pci_read32(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T, offset: t.CUInt8T) -> t.CUInt32T:
|
||||
addr: t.CUInt32T = 0x80000000 | (t.CUInt32T(bus) << 16) | (t.CUInt32T(dev) << 11) | (t.CUInt32T(func) << 8) | (t.CUInt32T(offset) & 0xFC)
|
||||
asm.outl(PCI_CONFIG_ADDR, addr)
|
||||
return asm.inl(PCI_CONFIG_DATA)
|
||||
|
||||
def pci_write32(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T, offset: t.CUInt8T, value: t.CUInt32T):
|
||||
addr: t.CUInt32T = 0x80000000 | (t.CUInt32T(bus) << 16) | (t.CUInt32T(dev) << 11) | (t.CUInt32T(func) << 8) | (t.CUInt32T(offset) & 0xFC)
|
||||
asm.outl(PCI_CONFIG_ADDR, addr)
|
||||
asm.outl(PCI_CONFIG_DATA, value)
|
||||
|
||||
def pci_read16(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T, offset: t.CUInt8T) -> t.CUInt16T:
|
||||
val: t.CUInt32T = pci_read32(bus, dev, func, offset)
|
||||
shift: t.CUInt32T = (t.CUInt32T(offset) & 0x02) * 8
|
||||
return t.CUInt16T((val >> shift) & 0xFFFF)
|
||||
|
||||
def pci_read8(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T, offset: t.CUInt8T) -> t.CUInt8T:
|
||||
val: t.CUInt32T = pci_read32(bus, dev, func, offset)
|
||||
shift: t.CUInt32T = (t.CUInt32T(offset) & 0x03) * 8
|
||||
return t.CUInt8T((val >> shift) & 0xFF)
|
||||
|
||||
def pci_get_class(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T) -> t.CUInt32T:
|
||||
cls: t.CUInt8T = pci_read8(bus, dev, func, 0x0B)
|
||||
sub: t.CUInt8T = pci_read8(bus, dev, func, 0x0A)
|
||||
proto: t.CUInt8T = pci_read8(bus, dev, func, 0x09)
|
||||
return (t.CUInt32T(cls) << 16) | (t.CUInt32T(sub) << 8) | t.CUInt32T(proto)
|
||||
|
||||
def pci_get_bar(bus: t.CUInt8T, dev: t.CUInt8T, func: t.CUInt8T, bar_idx: t.CUInt8T) -> t.CUInt32T:
|
||||
return pci_read32(bus, dev, func, 0x10 + bar_idx * 4)
|
||||
|
||||
def pci_enable_device(dev: pci_device | t.CPtr):
|
||||
cmd: t.CUInt16T = pci_read16(dev.bus, dev.dev, dev.func, 0x04)
|
||||
cmd = cmd | PCI_CMD_IO_SPACE | PCI_CMD_BUS_MASTER
|
||||
pci_write32(dev.bus, dev.dev, dev.func, 0x04, t.CUInt32T(cmd))
|
||||
|
||||
def pci_fill_device(bus: t.CUInt8T, dev_n: t.CUInt8T, func: t.CUInt8T, out: pci_device | t.CPtr):
|
||||
out.bus = bus
|
||||
out.dev = dev_n
|
||||
out.func = func
|
||||
out.vendor_id = pci_read16(bus, dev_n, func, 0x00)
|
||||
out.device_id = pci_read16(bus, dev_n, func, 0x02)
|
||||
out.class_code = pci_get_class(bus, dev_n, func)
|
||||
out.irq = pci_read8(bus, dev_n, func, 0x3C)
|
||||
i: t.CInt
|
||||
for i in range(6):
|
||||
out.bar[i] = pci_get_bar(bus, dev_n, func, t.CUInt8T(i))
|
||||
|
||||
_uhci_dev: pci_device
|
||||
_uhci_found: t.CInt = 0
|
||||
|
||||
def find_uhci() -> t.CUInt16T:
|
||||
global _uhci_dev, _uhci_found
|
||||
bus: t.CUInt8T
|
||||
dev_n: t.CUInt8T
|
||||
func: t.CUInt8T
|
||||
for bus in range(1):
|
||||
for dev_n in range(32):
|
||||
for func in range(8):
|
||||
vendor: t.CUInt16T = pci_read16(bus, dev_n, func, 0x00)
|
||||
if vendor == 0xFFFF: continue
|
||||
cls: t.CUInt32T = pci_get_class(bus, dev_n, func)
|
||||
if cls == PCI_CLASS_SERIAL_UHCI:
|
||||
pci_fill_device(bus, dev_n, func, c.Addr(_uhci_dev))
|
||||
pci_enable_device(c.Addr(_uhci_dev))
|
||||
_uhci_found = 1
|
||||
bar: t.CUInt32T = _uhci_dev.bar[4]
|
||||
io_base: t.CUInt16T = t.CUInt16T(bar & 0xFFFE)
|
||||
return io_base
|
||||
return 0
|
||||
415
VKernel/Kernel/drivers/usb/uhci.py
Normal file
415
VKernel/Kernel/drivers/usb/uhci.py
Normal file
@@ -0,0 +1,415 @@
|
||||
import t, c
|
||||
import asm
|
||||
import mm.mm as mm
|
||||
import viperstring as string
|
||||
import drivers.serial.uart.serial as serial
|
||||
import platform.pch.timer as timer
|
||||
import intr.idt as idt
|
||||
import platform.pch.pic as pic
|
||||
import drivers.usb.pci as pci
|
||||
|
||||
UHCI_USBCMD: t.CDefine = 0x00
|
||||
UHCI_USBSTS: t.CDefine = 0x02
|
||||
UHCI_USBINTR: t.CDefine = 0x04
|
||||
UHCI_FRNUM: t.CDefine = 0x06
|
||||
UHCI_FLBASEADD: t.CDefine = 0x08
|
||||
UHCI_SOFMOD: t.CDefine = 0x0C
|
||||
UHCI_PORTSC1: t.CDefine = 0x10
|
||||
UHCI_PORTSC2: t.CDefine = 0x12
|
||||
|
||||
UHCI_CMD_RUN: t.CDefine = 0x0001
|
||||
UHCI_CMD_HCRESET: t.CDefine = 0x0002
|
||||
UHCI_CMD_GRESET: t.CDefine = 0x0004
|
||||
UHCI_CMD_MAXPKT: t.CDefine = 0x0080
|
||||
UHCI_CMD_CF: t.CDefine = 0x0040
|
||||
|
||||
UHCI_STS_HCHALTED: t.CDefine = 0x0020
|
||||
UHCI_STS_USBINT: t.CDefine = 0x0001
|
||||
UHCI_STS_USBERRINT: t.CDefine = 0x0002
|
||||
UHCI_STS_RESUME: t.CDefine = 0x0004
|
||||
UHCI_INTR_TIMEOUT: t.CDefine = 0x0001
|
||||
UHCI_INTR_RESUME: t.CDefine = 0x0002
|
||||
UHCI_INTR_IOC: t.CDefine = 0x0004
|
||||
UHCI_INTR_SHORT: t.CDefine = 0x0008
|
||||
|
||||
UHCI_PORT_CONNECT: t.CDefine = 0x0001
|
||||
UHCI_PORT_CONNECT_CHANGE: t.CDefine = 0x0002
|
||||
UHCI_PORT_ENABLE: t.CDefine = 0x0004
|
||||
UHCI_PORT_ENABLE_CHANGE: t.CDefine = 0x0008
|
||||
UHCI_PORT_RESET: t.CDefine = 0x0200
|
||||
UHCI_PORT_LOW_SPEED: t.CDefine = 0x0100
|
||||
|
||||
TD_CTRL_ACTIVE: t.CDefine = 0x00800000
|
||||
TD_CTRL_IOC: t.CDefine = 0x01000000
|
||||
TD_CTRL_LS: t.CDefine = 0x04000000
|
||||
TD_CTRL_SPD: t.CDefine = 0x20000000
|
||||
TD_CTRL_CERR_SHIFT: t.CDefine = 27
|
||||
TD_CTRL_CERR_MASK: t.CDefine = 0x18000000
|
||||
|
||||
TD_TOKEN_SETUP: t.CDefine = 0x2D
|
||||
TD_TOKEN_IN: t.CDefine = 0x69
|
||||
TD_TOKEN_OUT: t.CDefine = 0xE1
|
||||
|
||||
TD_TOKEN_DATA0: t.CDefine = 0
|
||||
TD_TOKEN_DATA1: t.CDefine = 1
|
||||
|
||||
TD_LINK_TERMINATE: t.CDefine = 0x00000001
|
||||
TD_LINK_QH: t.CDefine = 0x00000002
|
||||
TD_LINK_DEPTH_FIRST: t.CDefine = 0x00000004
|
||||
|
||||
UHCI_NUM_FRAMES: t.CDefine = 1024
|
||||
UHCI_INT_SLOTS: t.CDefine = 4
|
||||
|
||||
class uhci_td(t.CStruct):
|
||||
link: t.CUInt32T
|
||||
ctrl_status: t.CUInt32T
|
||||
token: t.CUInt32T
|
||||
buffer: t.CUInt32T
|
||||
|
||||
class uhci_qh(t.CStruct):
|
||||
link: t.CUInt32T
|
||||
element: t.CUInt32T
|
||||
|
||||
class int_slot(t.CStruct):
|
||||
td: uhci_td | t.CPtr
|
||||
callback: t.CInt | t.CPtr
|
||||
active: t.CInt
|
||||
qh: uhci_qh | t.CPtr
|
||||
|
||||
_io_base: t.CUInt16T = 0
|
||||
_frame_list: t.CUInt32T | t.CPtr = None
|
||||
_ctrl_qh: uhci_qh | t.CPtr = None
|
||||
_bulk_qh: uhci_qh | t.CPtr = None
|
||||
_irq: t.CInt = -1
|
||||
_int_slots: t.CArray[int_slot, UHCI_INT_SLOTS]
|
||||
_int_slot_count: t.CInt = 0
|
||||
|
||||
def _reg_read16(offset: t.CUInt16T) -> t.CUInt16T:
|
||||
return asm.inw(_io_base + offset)
|
||||
|
||||
def _reg_write16(offset: t.CUInt16T, value: t.CUInt16T):
|
||||
asm.outw(_io_base + offset, value)
|
||||
|
||||
def _reg_read32(offset: t.CUInt16T) -> t.CUInt32T:
|
||||
return asm.inl(_io_base + offset)
|
||||
|
||||
def _reg_write32(offset: t.CUInt16T, value: t.CUInt32T):
|
||||
asm.outl(_io_base + offset, value)
|
||||
|
||||
def _uhci_irq_handler() -> t.CInt:
|
||||
sts: t.CUInt16T = _reg_read16(UHCI_USBSTS)
|
||||
_reg_write16(UHCI_USBSTS, sts)
|
||||
if (sts & (UHCI_STS_USBINT | UHCI_STS_USBERRINT)) == 0:
|
||||
return 0
|
||||
for si in range(_int_slot_count):
|
||||
slot: int_slot | t.CPtr = c.Addr(_int_slots[si])
|
||||
if slot.active and slot.td is not None and slot.callback is not None:
|
||||
status: t.CUInt32T = slot.td.ctrl_status
|
||||
if (status & TD_CTRL_ACTIVE) == 0:
|
||||
slot.active = 0
|
||||
c.Asm(f"""mov rbp, rsp
|
||||
and rsp, -16
|
||||
call {c.AsmInp(slot.callback, t.ASM_DESCR.REG_ANY)}
|
||||
mov rsp, rbp""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
|
||||
t.ASM_DESCR.CLOBBER_RBX,
|
||||
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
|
||||
t.ASM_DESCR.CLOBBER_RSI, t.ASM_DESCR.CLOBBER_RDI,
|
||||
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
|
||||
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11,
|
||||
t.ASM_DESCR.CLOBBER_RBP])
|
||||
return 0
|
||||
|
||||
def register_int_callback(cb: t.CInt | t.CPtr) -> t.CInt:
|
||||
global _int_slot_count
|
||||
if _int_slot_count >= UHCI_INT_SLOTS:
|
||||
return -1
|
||||
si: t.CInt = _int_slot_count
|
||||
qh: uhci_qh | t.CPtr = mm.malloc_direct(uhci_qh.__sizeof__())
|
||||
if qh is None:
|
||||
return -2
|
||||
string.memset(c.Addr(qh), 0, uhci_qh.__sizeof__())
|
||||
_qh_set_link(qh, 0, 0, 1)
|
||||
_qh_set_element(qh, 0, 1)
|
||||
td: uhci_td | t.CPtr = mm.malloc_direct(uhci_td.__sizeof__())
|
||||
if td is None:
|
||||
return -3
|
||||
string.memset(c.Addr(td), 0, uhci_td.__sizeof__())
|
||||
slot: int_slot | t.CPtr = c.Addr(_int_slots[si])
|
||||
slot.td = td
|
||||
slot.callback = cb
|
||||
slot.active = 0
|
||||
slot.qh = qh
|
||||
_int_slot_count = si + 1
|
||||
_rebuild_int_chain()
|
||||
return si
|
||||
|
||||
def schedule_int_transfer(slot_id: t.CInt, dev_addr: t.CUInt8T, endpoint: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, toggle_ptr: t.CUInt8T | t.CPtr, buf: t.CVoid | t.CPtr):
|
||||
if slot_id < 0 or slot_id >= _int_slot_count:
|
||||
return
|
||||
slot: int_slot | t.CPtr = c.Addr(_int_slots[slot_id])
|
||||
td: uhci_td | t.CPtr = slot.td
|
||||
qh: uhci_qh | t.CPtr = slot.qh
|
||||
if td is None or qh is None:
|
||||
return
|
||||
string.memset(c.Addr(td), 0, uhci_td.__sizeof__())
|
||||
_td_set_link(td, 0, 0, 1)
|
||||
_td_set_ctrl(td, ls, max_pkt)
|
||||
_td_set_token(td, TD_TOKEN_IN, dev_addr, endpoint, toggle_ptr, max_pkt)
|
||||
td.ctrl_status = td.ctrl_status | TD_CTRL_IOC
|
||||
td.buffer = t.CUInt32T(t.CUInt64T(buf))
|
||||
_qh_set_element(qh, t.CUInt32T(t.CUInt64T(td)), 0)
|
||||
slot.active = 1
|
||||
|
||||
def _rebuild_int_chain():
|
||||
if _int_slot_count == 0:
|
||||
return
|
||||
first_qh: uhci_qh | t.CPtr = None
|
||||
prev_qh: uhci_qh | t.CPtr = None
|
||||
for si in range(_int_slot_count):
|
||||
cur_qh: uhci_qh | t.CPtr = _int_slots[si].qh
|
||||
if cur_qh is not None:
|
||||
if first_qh is None:
|
||||
first_qh = cur_qh
|
||||
if prev_qh is not None:
|
||||
_qh_set_link(prev_qh, t.CUInt32T(t.CUInt64T(cur_qh)) | TD_LINK_QH, 1, 0)
|
||||
prev_qh = cur_qh
|
||||
if prev_qh is not None:
|
||||
_qh_set_link(prev_qh, t.CUInt32T(t.CUInt64T(_ctrl_qh)) | TD_LINK_QH, 1, 0)
|
||||
if first_qh is not None:
|
||||
qh_addr: t.CUInt32T = t.CUInt32T(t.CUInt64T(first_qh)) | TD_LINK_QH
|
||||
i: t.CInt
|
||||
for i in range(UHCI_NUM_FRAMES):
|
||||
entry_ptr: t.CUInt32T | t.CPtr = _frame_list + t.CUInt64T(i) * 4
|
||||
c.Set(c.Deref(entry_ptr), qh_addr)
|
||||
|
||||
def _td_set_link(td: uhci_td | t.CPtr, addr: t.CUInt32T, is_qh: t.CInt, terminate: t.CInt):
|
||||
val: t.CUInt32T = (addr & 0xFFFFFFF0)
|
||||
if is_qh: val = val | TD_LINK_QH
|
||||
if terminate: val = val | TD_LINK_TERMINATE
|
||||
td.link = val
|
||||
|
||||
def _td_set_token(td: uhci_td | t.CPtr, pid: t.CUInt8T, dev_addr: t.CUInt8T, endpoint: t.CUInt8T, toggle: t.CUInt8T, max_len: t.CUInt16T):
|
||||
len_bits: t.CUInt32T
|
||||
if max_len == 0:
|
||||
len_bits = 0x7FF
|
||||
else:
|
||||
len_bits = t.CUInt32T(max_len) - 1
|
||||
td.token = (t.CUInt32T(pid) << 0) | (t.CUInt32T(dev_addr) << 8) | (t.CUInt32T(endpoint & 0x0F) << 15) | (t.CUInt32T(toggle & 1) << 19) | (len_bits << 21)
|
||||
|
||||
def _td_set_ctrl(td: uhci_td | t.CPtr, ls: t.CInt, maxlen: t.CUInt16T):
|
||||
td.ctrl_status = TD_CTRL_ACTIVE | (3 << TD_CTRL_CERR_SHIFT)
|
||||
if ls: td.ctrl_status = td.ctrl_status | TD_CTRL_LS
|
||||
|
||||
def _qh_set_link(qh: uhci_qh | t.CPtr, addr: t.CUInt32T, is_qh: t.CInt, terminate: t.CInt):
|
||||
val: t.CUInt32T = (addr & 0xFFFFFFF0)
|
||||
if is_qh: val = val | TD_LINK_QH
|
||||
if terminate: val = val | TD_LINK_TERMINATE
|
||||
qh.link = val
|
||||
|
||||
def _qh_set_element(qh: uhci_qh | t.CPtr, addr: t.CUInt32T, terminate: t.CInt):
|
||||
val: t.CUInt32T = (addr & 0xFFFFFFF0)
|
||||
if terminate: val = val | TD_LINK_TERMINATE
|
||||
qh.element = val
|
||||
|
||||
def _wait_for_complete(td: uhci_td | t.CPtr, timeout_ms: t.CInt) -> t.CInt:
|
||||
start: t.CUInt64T = timer.timer_get_ticks()
|
||||
deadline: t.CUInt64T = start + t.CUInt64T(timeout_ms)
|
||||
poll_cnt: t.CInt = 0
|
||||
while timer.timer_get_ticks() < deadline:
|
||||
status: t.CUInt32T = td.ctrl_status
|
||||
if (status & TD_CTRL_ACTIVE) == 0:
|
||||
if (status & 0x00600000) != 0:
|
||||
return -1
|
||||
return 0
|
||||
poll_cnt += 1
|
||||
if poll_cnt >= 100:
|
||||
poll_cnt = 0
|
||||
asm.sti()
|
||||
asm.hlt()
|
||||
return -2
|
||||
|
||||
def reset(io_base: t.CUInt16T) -> t.CInt:
|
||||
global _io_base
|
||||
_io_base = io_base
|
||||
_reg_write16(UHCI_USBCMD, UHCI_CMD_HCRESET)
|
||||
i: t.CInt
|
||||
for i in range(1000):
|
||||
if (_reg_read16(UHCI_USBCMD) & UHCI_CMD_HCRESET) == 0:
|
||||
break
|
||||
_reg_write16(UHCI_USBSTS, 0xFFFF)
|
||||
_reg_write16(UHCI_USBINTR, 0x0000)
|
||||
return 0
|
||||
|
||||
def init(io_base: t.CUInt16T) -> t.CInt:
|
||||
global _io_base, _frame_list, _ctrl_qh, _bulk_qh, _int_slot_count
|
||||
_io_base = io_base
|
||||
_int_slot_count = 0
|
||||
|
||||
serial.puts("[uhci] resetting...\n")
|
||||
if reset(io_base) != 0:
|
||||
serial.puts("[uhci] reset failed\n")
|
||||
return -1
|
||||
|
||||
serial.puts("[uhci] allocating frame list...\n")
|
||||
_frame_list = mm.malloc(UHCI_NUM_FRAMES * 4)
|
||||
if _frame_list is None:
|
||||
serial.puts("[uhci] frame list alloc failed\n")
|
||||
return -2
|
||||
string.memset(_frame_list, 0, UHCI_NUM_FRAMES * 4)
|
||||
|
||||
_ctrl_qh = mm.malloc_direct(uhci_qh.__sizeof__())
|
||||
if _ctrl_qh is None:
|
||||
serial.puts("[uhci] ctrl_qh alloc failed\n")
|
||||
return -3
|
||||
string.memset(c.Addr(_ctrl_qh), 0, uhci_qh.__sizeof__())
|
||||
_qh_set_link(_ctrl_qh, 0, 0, 1)
|
||||
_qh_set_element(_ctrl_qh, 0, 1)
|
||||
|
||||
_bulk_qh = mm.malloc_direct(uhci_qh.__sizeof__())
|
||||
if _bulk_qh is None:
|
||||
serial.puts("[uhci] bulk_qh alloc failed\n")
|
||||
return -4
|
||||
string.memset(c.Addr(_bulk_qh), 0, uhci_qh.__sizeof__())
|
||||
_qh_set_link(_bulk_qh, 0, 0, 1)
|
||||
_qh_set_element(_bulk_qh, 0, 1)
|
||||
|
||||
serial.puts("[uhci] setting up frame list...\n")
|
||||
qh_addr: t.CUInt32T = t.CUInt32T(c.Addr(_ctrl_qh)) | TD_LINK_QH
|
||||
i: t.CInt
|
||||
for i in range(UHCI_NUM_FRAMES):
|
||||
entry_ptr: t.CUInt32T | t.CPtr = _frame_list + t.CUInt64T(i) * 4
|
||||
c.Set(c.Deref(entry_ptr), qh_addr)
|
||||
|
||||
_reg_write32(UHCI_FLBASEADD, t.CUInt32T(t.CUInt64T(_frame_list)))
|
||||
_reg_write16(UHCI_FRNUM, 0)
|
||||
_reg_write16(UHCI_SOFMOD, 64)
|
||||
|
||||
_reg_write16(UHCI_USBCMD, UHCI_CMD_CF | UHCI_CMD_MAXPKT | UHCI_CMD_RUN)
|
||||
|
||||
timer.timer_msleep(10)
|
||||
|
||||
_reg_write16(UHCI_USBSTS, 0xFFFF)
|
||||
_reg_write16(UHCI_USBINTR, UHCI_INTR_IOC | UHCI_INTR_SHORT)
|
||||
|
||||
_irq = t.CInt(pci._uhci_dev.irq)
|
||||
if _irq > 0 and _irq < 16:
|
||||
idt.irqInstallHandler(_irq, _uhci_irq_handler, "uhci")
|
||||
pic.clearMask(t.CUInt8T(_irq))
|
||||
|
||||
serial.puts("[uhci] started\n")
|
||||
return 0
|
||||
|
||||
def port_reset(port: t.CInt) -> t.CInt:
|
||||
sc: t.CUInt16T
|
||||
if port == 0:
|
||||
sc = _reg_read16(UHCI_PORTSC1)
|
||||
else:
|
||||
sc = _reg_read16(UHCI_PORTSC2)
|
||||
|
||||
if (sc & UHCI_PORT_CONNECT) == 0:
|
||||
return -1
|
||||
|
||||
if port == 0:
|
||||
_reg_write16(UHCI_PORTSC1, sc | UHCI_PORT_CONNECT_CHANGE | UHCI_PORT_ENABLE_CHANGE)
|
||||
else:
|
||||
_reg_write16(UHCI_PORTSC2, sc | UHCI_PORT_CONNECT_CHANGE | UHCI_PORT_ENABLE_CHANGE)
|
||||
|
||||
if port == 0:
|
||||
_reg_write16(UHCI_PORTSC1, UHCI_PORT_RESET)
|
||||
else:
|
||||
_reg_write16(UHCI_PORTSC2, UHCI_PORT_RESET)
|
||||
|
||||
timer.timer_msleep(50)
|
||||
|
||||
if port == 0:
|
||||
_reg_write16(UHCI_PORTSC1, 0x0000)
|
||||
else:
|
||||
_reg_write16(UHCI_PORTSC2, 0x0000)
|
||||
|
||||
timer.timer_msleep(10)
|
||||
|
||||
if port == 0:
|
||||
sc = _reg_read16(UHCI_PORTSC1)
|
||||
_reg_write16(UHCI_PORTSC1, sc | UHCI_PORT_ENABLE | UHCI_PORT_CONNECT_CHANGE | UHCI_PORT_ENABLE_CHANGE)
|
||||
else:
|
||||
sc = _reg_read16(UHCI_PORTSC2)
|
||||
_reg_write16(UHCI_PORTSC2, sc | UHCI_PORT_ENABLE | UHCI_PORT_CONNECT_CHANGE | UHCI_PORT_ENABLE_CHANGE)
|
||||
|
||||
timer.timer_msleep(10)
|
||||
|
||||
if port == 0:
|
||||
sc = _reg_read16(UHCI_PORTSC1)
|
||||
else:
|
||||
sc = _reg_read16(UHCI_PORTSC2)
|
||||
|
||||
if (sc & UHCI_PORT_ENABLE) == 0:
|
||||
return -2
|
||||
|
||||
return 0
|
||||
|
||||
def port_is_connected(port: t.CInt) -> t.CInt:
|
||||
sc: t.CUInt16T
|
||||
if port == 0:
|
||||
sc = _reg_read16(UHCI_PORTSC1)
|
||||
else:
|
||||
sc = _reg_read16(UHCI_PORTSC2)
|
||||
if sc & UHCI_PORT_CONNECT: return 1
|
||||
return 0
|
||||
|
||||
def port_is_low_speed(port: t.CInt) -> t.CInt:
|
||||
sc: t.CUInt16T
|
||||
if port == 0:
|
||||
sc = _reg_read16(UHCI_PORTSC1)
|
||||
else:
|
||||
sc = _reg_read16(UHCI_PORTSC2)
|
||||
if sc & UHCI_PORT_LOW_SPEED: return 1
|
||||
return 0
|
||||
|
||||
def control_transfer(dev_addr: t.CUInt8T, endpoint: t.CUInt8T, ls: t.CInt, max_pkt: t.CUInt8T, setup_buf: t.CVoid | t.CPtr, data_buf: t.CVoid | t.CPtr, data_len: t.CUInt16T, data_in: t.CInt) -> t.CInt:
|
||||
td_count: t.CInt = 2
|
||||
if data_len > 0:
|
||||
td_count = td_count + 1
|
||||
total: t.CUInt64T = t.CUInt64T(td_count) * uhci_td.__sizeof__()
|
||||
tds: uhci_td | t.CPtr = mm.malloc_direct(total)
|
||||
if tds is None: return -1
|
||||
string.memset(c.Addr(tds), 0, total)
|
||||
|
||||
setup_td: uhci_td | t.CPtr = tds
|
||||
_td_set_link(setup_td, t.CUInt32T(t.CUInt64T(tds) + uhci_td.__sizeof__()), 0, 0)
|
||||
_td_set_ctrl(setup_td, ls, 8)
|
||||
_td_set_token(setup_td, TD_TOKEN_SETUP, dev_addr, endpoint, TD_TOKEN_DATA0, 8)
|
||||
setup_td.buffer = t.CUInt32T(t.CUInt64T(setup_buf))
|
||||
|
||||
if data_len > 0:
|
||||
data_td: uhci_td | t.CPtr = t.CUInt64T(tds) + uhci_td.__sizeof__()
|
||||
_td_set_link(data_td, t.CUInt32T(t.CUInt64T(data_td) + uhci_td.__sizeof__()), 0, 0)
|
||||
_td_set_ctrl(data_td, ls, max_pkt)
|
||||
if data_in:
|
||||
_td_set_token(data_td, TD_TOKEN_IN, dev_addr, endpoint, TD_TOKEN_DATA1, data_len)
|
||||
else:
|
||||
_td_set_token(data_td, TD_TOKEN_OUT, dev_addr, endpoint, TD_TOKEN_DATA1, data_len)
|
||||
data_td.buffer = t.CUInt32T(t.CUInt64T(data_buf))
|
||||
|
||||
status_td: uhci_td | t.CPtr = t.CUInt64T(data_td) + uhci_td.__sizeof__()
|
||||
_td_set_link(status_td, 0, 0, 1)
|
||||
_td_set_ctrl(status_td, ls, max_pkt)
|
||||
if data_in:
|
||||
_td_set_token(status_td, TD_TOKEN_OUT, dev_addr, endpoint, TD_TOKEN_DATA1, 0)
|
||||
else:
|
||||
_td_set_token(status_td, TD_TOKEN_IN, dev_addr, endpoint, TD_TOKEN_DATA1, 0)
|
||||
status_td.buffer = 0
|
||||
else:
|
||||
status_td: uhci_td | t.CPtr = t.CUInt64T(tds) + uhci_td.__sizeof__()
|
||||
_td_set_link(status_td, 0, 0, 1)
|
||||
_td_set_ctrl(status_td, ls, max_pkt)
|
||||
_td_set_token(status_td, TD_TOKEN_IN, dev_addr, endpoint, TD_TOKEN_DATA1, 0)
|
||||
status_td.buffer = 0
|
||||
|
||||
_qh_set_element(_ctrl_qh, t.CUInt32T(t.CUInt64T(setup_td)), 0)
|
||||
|
||||
result: t.CInt = _wait_for_complete(status_td, 500)
|
||||
|
||||
_qh_set_element(_ctrl_qh, 0, 1)
|
||||
mm.free(tds)
|
||||
return result
|
||||
330
VKernel/Kernel/drivers/usb/usb.py
Normal file
330
VKernel/Kernel/drivers/usb/usb.py
Normal file
@@ -0,0 +1,330 @@
|
||||
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
|
||||
Reference in New Issue
Block a user