Skip to content

Commit

Permalink
namespaces rearrangement
Browse files Browse the repository at this point in the history
  • Loading branch information
Arkadiusz Wójcik committed Jun 12, 2024
1 parent b2e95af commit 247f13d
Show file tree
Hide file tree
Showing 9 changed files with 255 additions and 230 deletions.
42 changes: 20 additions & 22 deletions bsp/raspberrypi/rp2040/src/hal/usb.zig
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const peripherals = microzig.chip.peripherals;

/// Human Interface Device (HID)
pub const usb = microzig.core.usb;
pub const prim = usb.hid;
pub const desc = usb.desc;
pub const hid = usb.hid;

Expand All @@ -29,25 +30,22 @@ pub const EP0_IN_IDX = 1;
/// are used by the abstract USB impl of microzig.
pub const Usb = usb.Usb(F);

pub const utils = usb.ConfigUtils;
pub const templates = usb.DescriptorsConfigTemplates;
pub const DeviceConfiguration = usb.DeviceConfiguration;
pub const DeviceDescriptor = usb.DeviceDescriptor;
pub const DescType = desc.DescType;
pub const InterfaceDescriptor = usb.InterfaceDescriptor;
pub const ConfigurationDescriptor = usb.ConfigurationDescriptor;
pub const EndpointDescriptor = usb.EndpointDescriptor;
pub const EndpointConfiguration = usb.EndpointConfiguration;
pub const utils = usb.config.ConfigUtils;
pub const templates = usb.config.DescriptorsConfigTemplates;

pub const DeviceConfiguration = usb.config.DeviceConfiguration;
pub const DescType = usb.prim.DescType;
pub const EndpointDescriptor = usb.desc.EndpointDescriptor;
pub const EndpointConfiguration = usb.config.EndpointConfiguration;
pub const Dir = usb.Dir;
pub const TransferType = usb.TransferType;
pub const TransferType = usb.prim.TransferType;

pub const utf8ToUtf16Le = usb.utf8Toutf16Le;

pub var EP0_OUT_CFG: usb.EndpointConfiguration = .{
.descriptor = &desc.EndpointDescriptor{
pub var EP0_OUT_CFG: EndpointConfiguration = .{
.descriptor = &EndpointDescriptor{
.descriptor_type = DescType.Endpoint,
.endpoint_address = usb.EP0_OUT_ADDR,
.attributes = @intFromEnum(usb.TransferType.Control),
.attributes = @intFromEnum(TransferType.Control),
.max_packet_size = 64,
.interval = 0,
},
Expand All @@ -57,11 +55,11 @@ pub var EP0_OUT_CFG: usb.EndpointConfiguration = .{
.next_pid_1 = false,
};

pub var EP0_IN_CFG: usb.EndpointConfiguration = .{
.descriptor = &desc.EndpointDescriptor{
pub var EP0_IN_CFG: EndpointConfiguration = .{
.descriptor = &EndpointDescriptor{
.descriptor_type = DescType.Endpoint,
.endpoint_address = usb.EP0_IN_ADDR,
.attributes = @intFromEnum(usb.TransferType.Control),
.attributes = @intFromEnum(TransferType.Control),
.max_packet_size = 64,
.interval = 0,
},
Expand Down Expand Up @@ -153,7 +151,7 @@ pub const F = struct {
// We now have the stable 48MHz reference clock required for USB:
}

pub fn usb_init_device(device_config: *usb.DeviceConfiguration) void {
pub fn usb_init_device(device_config: *DeviceConfiguration) void {
// Bring USB out of reset
resets.reset(.{ .usbctrl = true });

Expand Down Expand Up @@ -307,7 +305,7 @@ pub const F = struct {
/// reuse `buffer` immediately after this returns. No need to wait for the
/// packet to be sent.
pub fn usb_start_tx(
ep: *usb.EndpointConfiguration,
ep: *EndpointConfiguration,
buffer: []const u8,
) void {
// It is technically possible to support longer buffers but this demo
Expand Down Expand Up @@ -352,7 +350,7 @@ pub const F = struct {
}

pub fn usb_start_rx(
ep: *usb.EndpointConfiguration,
ep: *EndpointConfiguration,
len: usize,
) void {
// It is technically possible to support longer buffers but this demo
Expand Down Expand Up @@ -428,7 +426,7 @@ pub const F = struct {
peripherals.USBCTRL_REGS.ADDR_ENDP.modify(.{ .ADDRESS = addr });
}

pub fn get_EPBIter(dc: *const usb.DeviceConfiguration) usb.EPBIter {
pub fn get_EPBIter(dc: *const DeviceConfiguration) usb.EPBIter {
return .{
.bufbits = peripherals.USBCTRL_REGS.BUFF_STATUS.raw,
.device_config = dc,
Expand Down Expand Up @@ -610,7 +608,7 @@ pub fn next(self: *usb.EPBIter) ?usb.EPB {
// corresponds to this address. We could use a smarter
// method here, but in practice, the number of endpoints is
// small so a linear scan doesn't kill us.
var endpoint: ?*usb.EndpointConfiguration = null;
var endpoint: ?*EndpointConfiguration = null;
for (self.device_config.endpoints) |ep| {
if (ep.descriptor.endpoint_address == ep_addr) {
endpoint = ep;
Expand Down
186 changes: 10 additions & 176 deletions core/src/core/usb.zig
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,22 @@
const std = @import("std");
const buffers = @import("buffers.zig");

/// USB primitive types
pub const prim = @import("usb/primitives.zig");
/// USB common descriptors
pub const desc = @import("usb/descriptors.zig");
/// USB Human Interface Device (HID)
pub const hid = @import("usb/hid.zig");
/// USB Communications Device Class (CDC)
pub const cdc = @import("usb/cdc.zig");
/// Configuration
pub const config = @import("usb/config.zig");

const DescType = desc.DescType;
const DescType = prim.DescType;
const BufferReader = buffers.BufferReader;
const BufferWriter = buffers.BufferWriter;
const DeviceConfiguration = config.DeviceConfiguration;
const EndpointConfiguration = config.EndpointConfiguration;

/// Create a USB device
///
Expand Down Expand Up @@ -195,8 +201,8 @@ pub fn Usb(comptime f: anytype) type {
if (debug) std.log.info(" Config", .{});

var bw = BufferWriter { .buffer = &S.tmp };
for (usb_config.?.config_descriptors) |config| {
try config.serialize(&bw);
for (usb_config.?.config_descriptors) |config_desc| {
try config_desc.serialize(&bw);
}

CmdEndpoint.send_cmd_response(bw.get_written_slice(), setup.length);
Expand Down Expand Up @@ -427,15 +433,6 @@ pub fn Usb(comptime f: anytype) type {
// | HID Descriptor |
// ---------------------

/// Types of transfer that can be indicated by the `attributes` field on
/// `EndpointDescriptor`.
pub const TransferType = enum(u2) {
Control = 0,
Isochronous = 1,
Bulk = 2,
Interrupt = 3,
};

/// The types of USB SETUP requests that we understand.
pub const SetupRequest = enum(u8) {
/// Asks the device to send a certain descriptor back to the host. Always
Expand Down Expand Up @@ -495,154 +492,6 @@ pub const SetupPacket = extern struct {
// Driver support stuctures
// +++++++++++++++++++++++++++++++++++++++++++++++++

pub const EndpointConfiguration = struct {
descriptor: *const desc.EndpointDescriptor,
/// Index of this endpoint's control register in the `ep_control` array.
///
/// TODO: this can be derived from the endpoint address, perhaps it should
/// be.
endpoint_control_index: ?usize,
/// Index of this endpoint's buffer control register in the
/// `ep_buffer_control` array.
///
/// TODO this, too, can be derived.
buffer_control_index: usize,

/// Index of this endpoint's data buffer in the array of data buffers
/// allocated from DPRAM. This can be arbitrary, and endpoints can even
/// share buffers if you're careful.
data_buffer_index: usize,

/// Keeps track of which DATA PID (DATA0/DATA1) is expected on this endpoint
/// next. If `true`, we're expecting `DATA1`, otherwise `DATA0`.
next_pid_1: bool,

/// Optional callback for custom OUT endpoints. This function will be called
/// if the device receives data on the corresponding endpoint.
callback: ?*const fn (dc: *DeviceConfiguration, data: []const u8) void = null,
};

pub const DescriptorConfig = union(enum) {
configuration: *const desc.ConfigurationDescriptor,
endpoint: *const desc.EndpointDescriptor,
interface: *const desc.InterfaceDescriptor,
interface_association: *const desc.InterfaceAssociationDescriptor,
hid: *const HidDescriptorConfig,
cdc: *const CdcDescriptorConfig,

pub fn serialize(self: *const @This(), buff: *BufferWriter) BufferWriter.Error!void {
switch (self.*) {
inline else => |case| try case.serialize(buff),
}
}
};

pub const HidDescriptorConfig = union(enum) {
hid: *const hid.HidDescriptor,

pub fn serialize(self: *const @This(), buff: *BufferWriter) BufferWriter.Error!void {
switch (self.*) {
inline else => |case| try case.serialize(buff),
}
}
};

pub const CdcDescriptorConfig = union(enum) {
cdc_header: *const cdc.CdcHeaderDescriptor,
cdc_call_management: *const cdc.CdcCallManagementDescriptor,
cdc_acm: *const cdc.CdcAcmDescriptor,
cdc_union: *const cdc.CdcUnionDescriptor,

pub fn serialize(self: *const @This(), buff: *BufferWriter) BufferWriter.Error!void {
switch (self.*) {
inline else => |case| try case.serialize(buff),
}
}
};

pub const DescriptorsConfigTemplates = struct {
pub const config_descriptor_len = 9;

pub fn config_descriptor(config_num: u8, interfaces_num: u8, string_index: u8, total_len: u16, attributes: u8, max_power_ma: u9) [1]DescriptorConfig {
return [1]DescriptorConfig {
.{ .configuration = &.{ .total_length = total_len, .num_interfaces = interfaces_num, .configuration_value = config_num, .configuration_s = string_index, .attributes = 0b01000000 | attributes, .max_power = max_power_ma/2 } }
};
}

pub const cdc_descriptor_len = 8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 7 + 7;

pub fn cdc_descriptor(interface_number: u8, string_index: u8, endpoint_notifi_address: u8, endpoint_notifi_size: u16, endpoint_out_address: u8, endpoint_in_address: u8, endpoint_size: u16) [10]DescriptorConfig {
return [10]DescriptorConfig {
.{ .interface_association = &.{ .first_interface = interface_number, .interface_count = 2, .function_class = 2, .function_subclass = 2, .function_protocol = 0, .function = 0 } },
.{ .interface = &.{ .interface_number = interface_number, .alternate_setting = 0, .num_endpoints = 1, .interface_class = 2, .interface_subclass = 2, .interface_protocol = 0, .interface_s = string_index } },
.{ .cdc = &.{ .cdc_header = &.{ .descriptor_type = .CsInterface, .descriptor_subtype = .Header, .bcd_cdc = 0x0120 } } },
.{ .cdc = &.{ .cdc_call_management = &.{ .descriptor_type = .CsInterface, .descriptor_subtype = .CallManagement, .capabilities = 0, .data_interface = interface_number + 1 } } },
.{ .cdc = &.{ .cdc_acm = &.{ .descriptor_type = .CsInterface, .descriptor_subtype = .ACM, .capabilities = 6 } } },
.{ .cdc = &.{ .cdc_union = &.{ .descriptor_type = .CsInterface, .descriptor_subtype = .Union, .master_interface = interface_number, .slave_interface_0 = interface_number + 1 } } },
.{ .endpoint = &.{ .endpoint_address = endpoint_notifi_address, .attributes = @intFromEnum(TransferType.Interrupt), .max_packet_size = endpoint_notifi_size, .interval = 16 } },
.{ .interface = &.{ .interface_number = interface_number + 1, .alternate_setting = 0, .num_endpoints = 2, .interface_class = 10, .interface_subclass = 0, .interface_protocol = 0, .interface_s = 0 } },
.{ .endpoint = &.{ .endpoint_address = endpoint_out_address, .attributes = @intFromEnum(TransferType.Bulk), .max_packet_size = endpoint_size, .interval = 0 } },
.{ .endpoint = &.{ .endpoint_address = endpoint_in_address, .attributes = @intFromEnum(TransferType.Bulk), .max_packet_size = endpoint_size, .interval = 0 } },
};
}

pub const hid_in_descriptor_len = 9 + 9 + 7;

pub fn hid_in_descriptor(interface_number: u8, string_index: u8, boot_protocol: u8, report_desc_len: u16, endpoint_in_address: u8, endpoint_size: u16, endpoint_interval: u16) [3]DescriptorConfig {
return [3]DescriptorConfig {
.{ .interface = &.{ .interface_number = interface_number, .alternate_setting = 0, .num_endpoints = 1, .interface_class = 3, .interface_subclass = if (boot_protocol > 0) 1 else 0, .interface_protocol = boot_protocol, .interface_s = string_index } },
.{ .hid = &.{ .hid = &.{ .bcd_hid = 0x0111, .country_code = 0, .num_descriptors = 1, .report_length = report_desc_len } } },
.{ .endpoint = &.{ .endpoint_address = endpoint_in_address, .attributes = @intFromEnum(TransferType.Interrupt), .max_packet_size = endpoint_size, .interval = endpoint_interval } },
};
}

pub const hid_inout_descriptor_len = 9 + 9 + 7 + 7;

pub fn hid_inout_descriptor(interface_number: u8, string_index: u8, boot_protocol: u8, report_desc_len: u16, endpoint_out_address: u8, endpoint_in_address: u8, endpoint_size: u16, endpoint_interval: u16) [4]DescriptorConfig {
return [4]DescriptorConfig {
.{ .interface = &.{ .interface_number = interface_number, .alternate_setting = 0, .num_endpoints = 2, .interface_class = 3, .interface_subclass = if (boot_protocol > 0) 1 else 0, .interface_protocol = boot_protocol, .interface_s = string_index } },
.{ .hid = &.{ .hid = &.{ .bcd_hid = 0x0111, .country_code = 0, .num_descriptors = 1, .report_length = report_desc_len } } },
.{ .endpoint = &.{ .endpoint_address = endpoint_out_address, .attributes = @intFromEnum(TransferType.Interrupt), .max_packet_size = endpoint_size, .interval = endpoint_interval } },
.{ .endpoint = &.{ .endpoint_address = endpoint_in_address, .attributes = @intFromEnum(TransferType.Interrupt), .max_packet_size = endpoint_size, .interval = endpoint_interval } },
};
}

pub const vendor_descriptor_len = 9 + 7 + 7;

pub fn vendor_descriptor(interface_number: u8, string_index: u8, endpoint_out_address: u8, endpoint_in_address: u8, endpoint_size: u16) [3]DescriptorConfig {
return [3]DescriptorConfig {
.{ .interface = &.{ .interface_number = interface_number, .alternate_setting = 0, .num_endpoints = 2, .interface_class = 0xff, .interface_subclass = 0, .interface_protocol = 0, .interface_s = string_index } },
.{ .endpoint = &.{ .endpoint_address = endpoint_out_address, .attributes = @intFromEnum(TransferType.Bulk), .max_packet_size = endpoint_size, .interval = 0 } },
.{ .endpoint = &.{ .endpoint_address = endpoint_in_address, .attributes = @intFromEnum(TransferType.Bulk), .max_packet_size = endpoint_size, .interval = 0 } },
};
}
};

pub const ConfigUtils = struct {
pub fn get_enpoint_descriptor(comptime endpoint_address: u8, comptime N: usize, array: [N]DescriptorConfig) *const desc.EndpointDescriptor {
for (array) |config| {
switch (config) {
.endpoint => |endpoint| {
if (endpoint.endpoint_address == endpoint_address) return endpoint;
},
else => {}
}
}
@compileError("Can't find endpoint descriptor");
}
};

pub const DeviceConfiguration = struct {
device_descriptor: *const desc.DeviceDescriptor,
config_descriptors: []const DescriptorConfig,
lang_descriptor: []const u8,
descriptor_strings: []const []const u8,
hid: ?struct {
report_descriptor: []const u8,
} = null,
endpoints: [4]*EndpointConfiguration,
};

/// Buffer pointers, once they're prepared and initialized.
pub const Buffers = struct {
/// Fixed EP0 Buffer0, defined by the hardware
Expand Down Expand Up @@ -715,22 +564,7 @@ pub const EPBIter = struct {
next: *const fn (self: *@This()) ?EPB,
};

/// Convert an utf8 into an utf16 (little endian) string
pub fn utf8Toutf16Le(comptime s: []const u8) [s.len << 1]u8 {
const l = s.len << 1;
var ret: [l]u8 = .{0} ** l;
var i: usize = 0;
while (i < s.len) : (i += 1) {
ret[i << 1] = s[i];
}
return ret;
}

test "tests" {
_ = hid;
}

test "utf8 to utf16" {
try std.testing.expectEqualSlices(u8, "M\x00y\x00 \x00V\x00e\x00n\x00d\x00o\x00r\x00", &utf8Toutf16Le("My Vendor"));
try std.testing.expectEqualSlices(u8, "R\x00a\x00s\x00p\x00b\x00e\x00r\x00r\x00y\x00 \x00P\x00i\x00", &utf8Toutf16Le("Raspberry Pi"));
}
}
5 changes: 3 additions & 2 deletions core/src/core/usb/cdc.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
const std = @import("std");
const buffers = @import("../buffers.zig");

pub const desc = @import("descriptors.zig");
const prim = @import("primitives.zig");
const desc = @import("descriptors.zig");

const BufferWriter = buffers.BufferWriter;
const DescType = desc.DescType;
const DescType = prim.DescType;

pub const DescSubType = enum(u8) {
Header = 0x00,
Expand Down
Loading

0 comments on commit 247f13d

Please sign in to comment.