From f634fdece74e840e4fc609be4876cedb09761c6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Quei=C3=9Fner?= Date: Fri, 14 Feb 2025 20:30:32 +0100 Subject: [PATCH 1/4] Adds build.zig for TinyUSB --- vendor/tinyusb/build.zig | 76 ++++++++++++++++++++++++++++++++++++ vendor/tinyusb/build.zig.zon | 16 ++++++++ 2 files changed, 92 insertions(+) create mode 100644 vendor/tinyusb/build.zig create mode 100644 vendor/tinyusb/build.zig.zon diff --git a/vendor/tinyusb/build.zig b/vendor/tinyusb/build.zig new file mode 100644 index 00000000..c656969d --- /dev/null +++ b/vendor/tinyusb/build.zig @@ -0,0 +1,76 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + const upstream = b.dependency("upstream", .{}); + const src_folder = upstream.path("src"); + const tinyusb_mod = b.addModule("tinyusb", .{}); + + const tinyusb_config_h = b.addConfigHeader(.{ + .style = .blank, + .include_path = "tusb_config.h", + }, .{ + .CFG_TUSB_MCU = "", + .CFG_TUSB_OS = "OPT_OS_NONE", + .CFG_TUSB_DEBUG = "0", // "1" + + .CFG_TUH_MEM_SECTION = "", // __attribute__ (( section(".usb_ram") )) + .CFG_TUH_MEM_ALIGN = "__attribute__ ((aligned(4)))", + + .CFG_TUH_ENABLED = "1", + .CFG_TUH_MAX_SPEED = "BOARD_TUH_MAX_SPEED", + + .BOARD_TUH_RHPORT = "0", + .BOARD_TUH_MAX_SPEED = "OPT_MODE_DEFAULT_SPEED", + + .CFG_TUH_ENUMERATION_BUFSIZE = "256", + .CFG_TUH_HUB = "1", // number of supported hubs + .CFG_TUH_CDC = "1", // CDC ACM + .CFG_TUH_CDC_FTDI = "1", // FTDI Serial. FTDI is not part of CDC class, only to re-use CDC driver API + .CFG_TUH_CDC_CP210X = "1", // CP210x Serial. CP210X is not part of CDC class, only to re-use CDC driver API + .CFG_TUH_CDC_CH34X = "1", // CH340 or CH341 Serial. CH34X is not part of CDC class, only to re-use CDC driver API + .CFG_TUH_HID = "4", // typical keyboard + mouse device can have 3-4 HID interfaces + .CFG_TUH_MSC = "2", + .CFG_TUH_VENDOR = "0", + .CFG_TUH_DEVICE_MAX = "8", + + .CFG_TUH_HID_EPIN_BUFSIZE = 64, + .CFG_TUH_HID_EPOUT_BUFSIZE = 64, + + .CFG_TUH_CDC_LINE_CONTROL_ON_ENUM = "0x03", + .CFG_TUH_CDC_LINE_CODING_ON_ENUM = "{ 115200, CDC_LINE_CODING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 }", + }); + + tinyusb_mod.addIncludePath(src_folder); + tinyusb_mod.addIncludePath(tinyusb_config_h.getOutput().dirname()); + + tinyusb_mod.addCSourceFiles(.{ + .root = src_folder, + .files = &tinyusb_sources, + }); +} + +const tinyusb_sources = [_][]const u8{ + "class/audio/audio_device.c", + "class/cdc/cdc_device.c", + "class/cdc/cdc_host.c", + "class/dfu/dfu_device.c", + "class/dfu/dfu_rt_device.c", + "class/hid/hid_device.c", + "class/hid/hid_host.c", + "class/midi/midi_device.c", + "class/msc/msc_device.c", + "class/msc/msc_host.c", + "class/net/ecm_rndis_device.c", + "class/net/ncm_device.c", + "class/usbtmc/usbtmc_device.c", + "class/vendor/vendor_device.c", + "class/vendor/vendor_host.c", + "class/video/video_device.c", + "common/tusb_fifo.c", + "device/usbd_control.c", + "device/usbd.c", + "host/hub.c", + "host/usbh.c", + "tusb.c", + "typec/usbc.c", +}; diff --git a/vendor/tinyusb/build.zig.zon b/vendor/tinyusb/build.zig.zon new file mode 100644 index 00000000..6e1495b3 --- /dev/null +++ b/vendor/tinyusb/build.zig.zon @@ -0,0 +1,16 @@ +.{ + .name = "tinyusb", + .version = "0.18.0", + + .dependencies = .{ + .upstream = .{ + .url = "git+https://github.com/hathach/tinyusb#0.18.0", + .hash = "1220d8ab111d7b1c3b45fa7d60436559bc250cf42ed1b09f2b1c2cf52c6a2fc6bea1", + }, + }, + + .paths = .{ + "build.zig", + "build.zig.zon", + }, +} From c5c016af41b50b9c2bcc79469ff809128d5ce91e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Quei=C3=9Fner?= Date: Fri, 14 Feb 2025 21:35:52 +0100 Subject: [PATCH 2/4] Makes TinyUSB compile into with the kernel. Won't link yet. --- justfile | 2 ++ src/kernel/build.zig | 15 ++++++++-- src/kernel/build.zig.zon | 4 +++ vendor/tinyusb/build.zig | 51 ++++++++++++++++++---------------- vendor/tinyusb/include/stdio.h | 2 ++ 5 files changed, 48 insertions(+), 26 deletions(-) create mode 100644 vendor/tinyusb/include/stdio.h diff --git a/justfile b/justfile index 481ed9bf..1ecbecff 100644 --- a/justfile +++ b/justfile @@ -1,5 +1,7 @@ build: + # just build a single os before building all, so we can fail faster + zig-ashet build arm-ashet-vhc zig-ashet build [working-directory: 'src/kernel'] diff --git a/src/kernel/build.zig b/src/kernel/build.zig index 3163e7e8..c46e4853 100644 --- a/src/kernel/build.zig +++ b/src/kernel/build.zig @@ -32,6 +32,7 @@ pub fn build(b: *std.Build) void { const args_dep = b.dependency("args", .{}); const network_dep = b.dependency("network", .{}); const vnc_dep = b.dependency("vnc", .{}); + const tinyusb_dep = b.dependency("tinyusb", .{}); const lwip_dep = b.dependency("lwip", .{ .target = kernel_target, .optimize = .ReleaseSafe }); const libc_dep = b.dependency("foundation-libc", .{ .target = kernel_target, @@ -75,6 +76,7 @@ pub fn build(b: *std.Build) void { const turtlefont_mod = turtlefont_dep.module("turtlefont"); const ashex_mod = ashex_dep.module("ashex"); const xcvt_mod = xcvt_dep.module("cvt"); + const tinyusb_mod = tinyusb_dep.module("tinyusb"); // Build: @@ -114,6 +116,7 @@ pub fn build(b: *std.Build) void { .{ .name = "turtlefont", .module = turtlefont_mod }, .{ .name = "ashex", .module = ashex_mod }, .{ .name = "cvt", .module = xcvt_mod }, + .{ .name = "tinyusb", .module = tinyusb_mod }, // resources: .{ @@ -127,6 +130,9 @@ pub fn build(b: *std.Build) void { }, }); + const tinyusb_headers = tinyusb_dep.namedWriteFiles("include"); + kernel_mod.addIncludePath(tinyusb_headers.getDirectory()); + kernel_mod.addImport("lwip", lwip_mod); kernel_mod.addIncludePath(b.path("components/network/include")); lwip_mod.addIncludePath(b.path("components/network/include")); @@ -222,6 +228,7 @@ pub fn build(b: *std.Build) void { kernel_exe.step.dependOn(machine_info_module.root_source_file.?.generated.file.step); kernel_exe.root_module.addImport("kernel", kernel_mod); + kernel_exe.step.dependOn(&tinyusb_headers.step); // TODO(fqu): kernel_exe.root_module.code_model = .small; kernel_exe.bundle_compiler_rt = true; @@ -252,10 +259,14 @@ pub fn build(b: *std.Build) void { } else { const libc = libc_dep.artifact("foundation"); - lwip_mod.addIncludePath(libc.getEmittedIncludeTree()); - zfat_mod.addIncludePath(libc.getEmittedIncludeTree()); + const libc_include_path = libc.getEmittedIncludeTree(); + + lwip_mod.addIncludePath(libc_include_path); + zfat_mod.addIncludePath(libc_include_path); + tinyusb_mod.addIncludePath(libc_include_path); kernel_exe.linkLibrary(libc); + kernel_exe.step.dependOn(&libc.step); } b.installArtifact(kernel_exe); diff --git a/src/kernel/build.zig.zon b/src/kernel/build.zig.zon index 654361a0..e13b1c5c 100644 --- a/src/kernel/build.zig.zon +++ b/src/kernel/build.zig.zon @@ -16,6 +16,10 @@ .path = "../../vendor/lwip", }, + .tinyusb = .{ + .path = "../../vendor/tinyusb", + }, + .ashet_fs = .{ .path = "../../vendor/ashet-fs", }, diff --git a/vendor/tinyusb/build.zig b/vendor/tinyusb/build.zig index c656969d..1d25984c 100644 --- a/vendor/tinyusb/build.zig +++ b/vendor/tinyusb/build.zig @@ -3,46 +3,49 @@ const std = @import("std"); pub fn build(b: *std.Build) void { const upstream = b.dependency("upstream", .{}); const src_folder = upstream.path("src"); - const tinyusb_mod = b.addModule("tinyusb", .{}); const tinyusb_config_h = b.addConfigHeader(.{ .style = .blank, .include_path = "tusb_config.h", }, .{ - .CFG_TUSB_MCU = "", - .CFG_TUSB_OS = "OPT_OS_NONE", - .CFG_TUSB_DEBUG = "0", // "1" + .CFG_TUSB_MCU = .OPT_MCU_NONE, + .CFG_TUSB_OS = .OPT_OS_NONE, + .CFG_TUSB_DEBUG = 0, // 1 - .CFG_TUH_MEM_SECTION = "", // __attribute__ (( section(".usb_ram") )) - .CFG_TUH_MEM_ALIGN = "__attribute__ ((aligned(4)))", + .CFG_TUH_MEM_SECTION = null, // __attribute__ (( section(".usb_ram") )) + .CFG_TUH_MEM_ALIGN = .@"__attribute__ ((aligned(4)))", - .CFG_TUH_ENABLED = "1", - .CFG_TUH_MAX_SPEED = "BOARD_TUH_MAX_SPEED", + .CFG_TUH_ENABLED = true, + .CFG_TUH_MAX_SPEED = .BOARD_TUH_MAX_SPEED, - .BOARD_TUH_RHPORT = "0", - .BOARD_TUH_MAX_SPEED = "OPT_MODE_DEFAULT_SPEED", + .BOARD_TUH_RHPORT = 0, + .BOARD_TUH_MAX_SPEED = .OPT_MODE_DEFAULT_SPEED, - .CFG_TUH_ENUMERATION_BUFSIZE = "256", - .CFG_TUH_HUB = "1", // number of supported hubs - .CFG_TUH_CDC = "1", // CDC ACM - .CFG_TUH_CDC_FTDI = "1", // FTDI Serial. FTDI is not part of CDC class, only to re-use CDC driver API - .CFG_TUH_CDC_CP210X = "1", // CP210x Serial. CP210X is not part of CDC class, only to re-use CDC driver API - .CFG_TUH_CDC_CH34X = "1", // CH340 or CH341 Serial. CH34X is not part of CDC class, only to re-use CDC driver API - .CFG_TUH_HID = "4", // typical keyboard + mouse device can have 3-4 HID interfaces - .CFG_TUH_MSC = "2", - .CFG_TUH_VENDOR = "0", - .CFG_TUH_DEVICE_MAX = "8", + .CFG_TUH_ENUMERATION_BUFSIZE = 256, + .CFG_TUH_HUB = 1, // number of supported hubs + .CFG_TUH_CDC = 1, // CDC ACM + .CFG_TUH_CDC_FTDI = 1, // FTDI Serial. FTDI is not part of CDC class, only to re-use CDC driver API + .CFG_TUH_CDC_CP210X = 1, // CP210x Serial. CP210X is not part of CDC class, only to re-use CDC driver API + .CFG_TUH_CDC_CH34X = 1, // CH340 or CH341 Serial. CH34X is not part of CDC class, only to re-use CDC driver API + .CFG_TUH_HID = 4, // typical keyboard + mouse device can have 3-4 HID interfaces + .CFG_TUH_MSC = 2, + .CFG_TUH_VENDOR = 0, + .CFG_TUH_DEVICE_MAX = 8, .CFG_TUH_HID_EPIN_BUFSIZE = 64, .CFG_TUH_HID_EPOUT_BUFSIZE = 64, - .CFG_TUH_CDC_LINE_CONTROL_ON_ENUM = "0x03", - .CFG_TUH_CDC_LINE_CODING_ON_ENUM = "{ 115200, CDC_LINE_CODING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 }", + .CFG_TUH_CDC_LINE_CONTROL_ON_ENUM = 0x03, + .CFG_TUH_CDC_LINE_CODING_ON_ENUM = .@"{ 115200, CDC_LINE_CODING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 }", }); - tinyusb_mod.addIncludePath(src_folder); - tinyusb_mod.addIncludePath(tinyusb_config_h.getOutput().dirname()); + const headers = b.addNamedWriteFiles("include"); + const deployed_config_h = headers.addCopyFile(tinyusb_config_h.getOutput(), "tusb_config.h"); + const tinyusb_mod = b.addModule("tinyusb", .{}); + tinyusb_mod.addIncludePath(src_folder); + tinyusb_mod.addIncludePath(deployed_config_h.dirname()); + tinyusb_mod.addIncludePath(b.path("include")); tinyusb_mod.addCSourceFiles(.{ .root = src_folder, .files = &tinyusb_sources, diff --git a/vendor/tinyusb/include/stdio.h b/vendor/tinyusb/include/stdio.h new file mode 100644 index 00000000..84a1624c --- /dev/null +++ b/vendor/tinyusb/include/stdio.h @@ -0,0 +1,2 @@ +#pragma once + From 367c9c7dfacadfdb80555c767257399af58d94c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Quei=C3=9Fner?= Date: Fri, 14 Feb 2025 21:41:29 +0100 Subject: [PATCH 3/4] Makes TinyUSB linker errors be gone. Will panic if ever used like this. --- src/kernel/components/usb.zig | 8 ++++ src/kernel/components/usb/tinyusb.zig | 62 +++++++++++++++++++++++++++ src/kernel/main.zig | 5 ++- 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 src/kernel/components/usb.zig create mode 100644 src/kernel/components/usb/tinyusb.zig diff --git a/src/kernel/components/usb.zig b/src/kernel/components/usb.zig new file mode 100644 index 00000000..9858f2ee --- /dev/null +++ b/src/kernel/components/usb.zig @@ -0,0 +1,8 @@ +const std = @import("std"); +const ashet = @import("../main.zig"); +const tinyusb = @import("usb/tinyusb.zig"); + +comptime { + // Ensure TinyUSB glue is compiled: + _ = tinyusb; +} diff --git a/src/kernel/components/usb/tinyusb.zig b/src/kernel/components/usb/tinyusb.zig new file mode 100644 index 00000000..277fc038 --- /dev/null +++ b/src/kernel/components/usb/tinyusb.zig @@ -0,0 +1,62 @@ +const std = @import("std"); +const ashet = @import("../../main.zig"); + +export fn hcd_device_close() void { + @panic("hcd_device_close not implemented yet!"); +} + +export fn hcd_edpt_abort_xfer() void { + @panic("hcd_edpt_abort_xfer not implemented yet!"); +} + +export fn hcd_edpt_open() void { + @panic("hcd_edpt_open not implemented yet!"); +} + +export fn hcd_edpt_xfer() void { + @panic("hcd_edpt_xfer not implemented yet!"); +} + +export fn hcd_init() void { + @panic("hcd_init not implemented yet!"); +} + +export fn hcd_int_disable() void { + @panic("hcd_int_disable not implemented yet!"); +} + +export fn hcd_int_enable() void { + @panic("hcd_int_enable not implemented yet!"); +} + +export fn hcd_int_handler() void { + @panic("hcd_int_handler not implemented yet!"); +} + +export fn hcd_port_connect_status() void { + @panic("hcd_port_connect_status not implemented yet!"); +} + +export fn hcd_port_reset() void { + @panic("hcd_port_reset not implemented yet!"); +} + +export fn hcd_port_reset_end() void { + @panic("hcd_port_reset_end not implemented yet!"); +} + +export fn hcd_port_speed_get() void { + @panic("hcd_port_speed_get not implemented yet!"); +} + +export fn hcd_setup_send() void { + @panic("hcd_setup_send not implemented yet!"); +} + +export fn tuh_hid_report_received_cb() void { + @panic("tuh_hid_report_received_cb not implemented yet!"); +} + +export fn tusb_time_millis_api() void { + @panic("tusb_time_millis_api not implemented yet!"); +} diff --git a/src/kernel/main.zig b/src/kernel/main.zig index 2da97b39..5896aa66 100644 --- a/src/kernel/main.zig +++ b/src/kernel/main.zig @@ -26,6 +26,7 @@ pub const random = @import("components/random.zig"); pub const sync = @import("components/sync.zig"); pub const pipes = @import("components/pipes.zig"); pub const ipc = @import("components/ipc.zig"); +pub const usb = @import("components/usb.zig"); pub const ports = @import("port/targets.zig"); @@ -129,8 +130,10 @@ comptime { } comptime { - // export the syscalls: + // the following all export symbols: _ = syscalls; + _ = usb; + _ = filesystem; } fn ashet_kernelMain() callconv(.C) noreturn { From 72cb4b040efebaf8d76d73edd3ce76b2519b9b86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Quei=C3=9Fner?= Date: Sun, 16 Feb 2025 20:55:07 +0100 Subject: [PATCH 4/4] adds type annotations to required tusb callbacks. --- src/kernel/components/usb/tinyusb.zig | 115 ++++++++++++++++++++++---- 1 file changed, 97 insertions(+), 18 deletions(-) diff --git a/src/kernel/components/usb/tinyusb.zig b/src/kernel/components/usb/tinyusb.zig index 277fc038..e4aa471a 100644 --- a/src/kernel/components/usb/tinyusb.zig +++ b/src/kernel/components/usb/tinyusb.zig @@ -1,62 +1,141 @@ const std = @import("std"); const ashet = @import("../../main.zig"); -export fn hcd_device_close() void { - @panic("hcd_device_close not implemented yet!"); -} +const c = @cImport({ + @cInclude("tusb.h"); +}); + +const tusb_desc_endpoint_t = c.tusb_desc_endpoint_t; +const tusb_rhport_init_t = c.tusb_rhport_init_t; +const tusb_speed_t = c.tusb_speed_t; + +pub const RHPort = enum(u8) { + first = 0, + _, +}; + +pub const DeviceAddr = enum(u8) { + _, +}; + +pub const EndPointAddr = enum(u8) { + _, +}; -export fn hcd_edpt_abort_xfer() void { +// Abort a queued transfer. Note: it can only abort transfer that has not been started +// Return true if a queued transfer is aborted, false if there is no transfer to abort +export fn hcd_edpt_abort_xfer(rhport: RHPort, dev_addr: DeviceAddr, ep_addr: EndPointAddr) bool { + _ = rhport; + _ = dev_addr; + _ = ep_addr; @panic("hcd_edpt_abort_xfer not implemented yet!"); } -export fn hcd_edpt_open() void { +// Open an endpoint +export fn hcd_edpt_open(rhport: RHPort, daddr: DeviceAddr, ep_desc: *const tusb_desc_endpoint_t) bool { + _ = rhport; + _ = daddr; + _ = ep_desc; @panic("hcd_edpt_open not implemented yet!"); } -export fn hcd_edpt_xfer() void { +// Submit a transfer, when complete hcd_event_xfer_complete() must be invoked +export fn hcd_edpt_xfer(rhport: RHPort, daddr: DeviceAddr, ep_addr: EndPointAddr, buffer: [*]u8, buflen: u16) bool { + _ = rhport; + _ = daddr; + _ = ep_addr; + _ = buffer; + _ = buflen; @panic("hcd_edpt_xfer not implemented yet!"); } -export fn hcd_init() void { +// Initialize controller to host mode +export fn hcd_init(rhport: RHPort, rh_init: *const tusb_rhport_init_t) bool { + _ = rhport; + _ = rh_init; @panic("hcd_init not implemented yet!"); } -export fn hcd_int_disable() void { +// HCD closes all opened endpoints belong to this device +export fn hcd_device_close(rhport: RHPort, dev_addr: DeviceAddr) void { + _ = rhport; + _ = dev_addr; + @panic("hcd_device_close not implemented yet!"); +} + +// Disable USB interrupt +export fn hcd_int_disable(rhport: RHPort) void { + _ = rhport; @panic("hcd_int_disable not implemented yet!"); } -export fn hcd_int_enable() void { +// Enable USB interrupt +export fn hcd_int_enable(rhport: RHPort) void { + _ = rhport; @panic("hcd_int_enable not implemented yet!"); } -export fn hcd_int_handler() void { +// Interrupt Handler +export fn hcd_int_handler(rhport: RHPort, in_isr: bool) void { + _ = rhport; + _ = in_isr; @panic("hcd_int_handler not implemented yet!"); } -export fn hcd_port_connect_status() void { +// Get the current connect status of roothub port +export fn hcd_port_connect_status(rhport: RHPort) bool { + _ = rhport; @panic("hcd_port_connect_status not implemented yet!"); } -export fn hcd_port_reset() void { +// Reset USB bus on the port. Return immediately, bus reset sequence may not be complete. +// Some port would require hcd_port_reset_end() to be invoked after 10ms to complete the reset sequence. +export fn hcd_port_reset(rhport: RHPort) void { + _ = rhport; @panic("hcd_port_reset not implemented yet!"); } -export fn hcd_port_reset_end() void { +// Complete bus reset sequence, may be required by some controllers +export fn hcd_port_reset_end(rhport: RHPort) void { + _ = rhport; @panic("hcd_port_reset_end not implemented yet!"); } -export fn hcd_port_speed_get() void { +// Get port link speed +export fn hcd_port_speed_get(rhport: RHPort) tusb_speed_t { + _ = rhport; @panic("hcd_port_speed_get not implemented yet!"); } -export fn hcd_setup_send() void { +// Submit a special transfer to send 8-byte Setup Packet, when complete hcd_event_xfer_complete() must be invoked +export fn hcd_setup_send(rhport: RHPort, daddr: DeviceAddr, setup_packet: *const [8]u8) void { + _ = rhport; + _ = daddr; + _ = setup_packet; @panic("hcd_setup_send not implemented yet!"); } -export fn tuh_hid_report_received_cb() void { +// Invoked when received report from device via interrupt endpoint +// Note: if there is report ID (composite), it is 1st byte of report +export fn tuh_hid_report_received_cb(dev_addr: DeviceAddr, idx: u8, report: [*]const u8, len: u16) void { + _ = dev_addr; + _ = idx; + _ = report; + _ = len; @panic("tuh_hid_report_received_cb not implemented yet!"); } -export fn tusb_time_millis_api() void { - @panic("tusb_time_millis_api not implemented yet!"); +// Get current milliseconds, required by some port/configuration without RTOS +export fn tusb_time_millis_api() u32 { + return ashet.time.Instant.now().ms_since_start(); +} + +// Delay in milliseconds, use tusb_time_millis_api() by default. required by some port/configuration with no RTOS +export fn tusb_time_delay_ms_api(ms: u32) void { + // TODO: Implement thread suspending here: + + const start = tusb_time_millis_api(); + while ((tusb_time_millis_api() - start) < ms) { + // + } }