-
Notifications
You must be signed in to change notification settings - Fork 152
Rework rp2xxx USB driver #658
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
piotrfila
wants to merge
35
commits into
ZigEmbeddedGroup:main
Choose a base branch
from
piotrfila:main
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from 22 commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
f327e4e
improve endpoint type safety
piotrfila e071ff1
moved clock initialization out of USB abstract device
piotrfila a93e6de
make debug a funcion argument
piotrfila 563d073
change usb write signature
piotrfila 59ef47f
change UsbClassDriver
piotrfila 5f15c82
redo iteration over endpoint buffers
piotrfila 00b1a62
separate some logic into HardwareBuffer and do various improvements
piotrfila b5fdd56
remove most global data from usb
piotrfila d2c8cd0
reduce use of global variables
piotrfila a875577
simplify usb controller and drivers
piotrfila 8871ecd
add more type safety and change usb controller config
piotrfila bd25ca3
remove usb driver interface
piotrfila 61b5291
use unserialized descriptors instead of parsing after serializing
piotrfila d826515
redo endpoint 0 control and remove unused functions
piotrfila fb803ef
make usb device own the controller, not vice versa
piotrfila 850e7c8
rework usb device task
piotrfila 7fe09ba
support multiple functions
piotrfila 06fcadb
cleanup
piotrfila 0331dcd
add documentation and simplify dpram allocation
piotrfila 34c11e4
revert examples build script
piotrfila 21a768e
Merge branch 'ZigEmbeddedGroup:main' into main
piotrfila cd1f282
allow longer evaluation for making string descriptors
piotrfila 3eae06e
fix typos
piotrfila 1bb5207
endpoint_open no longer returns an optional buffer
piotrfila 6d7c78e
replace std.mem.copyForwards with @memcpy
piotrfila 8a977b4
fix a bug around undefined only present in --release=fast
piotrfila 4d53dbf
change U16Le implementation
piotrfila d6713f8
revert back to using copyForwards
piotrfila c9d0c4e
Merge branch 'ZigEmbeddedGroup:main' into main
piotrfila 437eb6b
change endpoint interface
piotrfila 00a72e0
decouple endpoint polling from device polling
piotrfila 2688649
change dpram access
piotrfila 965bb96
minor cleanup
piotrfila 2e94a5c
change usb device interface... again
piotrfila a8b5eab
revert build script
piotrfila File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,297 @@ | ||
| pub const cdc = @import("descriptor/cdc.zig"); | ||
| pub const hid = @import("descriptor/hid.zig"); | ||
| pub const vendor = @import("descriptor/vendor.zig"); | ||
|
|
||
| test "descriptor tests" { | ||
| _ = cdc; | ||
| _ = hid; | ||
| _ = vendor; | ||
| } | ||
|
|
||
| const std = @import("std"); | ||
| const types = @import("types.zig"); | ||
| const assert = std.debug.assert; | ||
|
|
||
| pub const Type = enum(u8) { | ||
| Device = 0x01, | ||
| Configuration = 0x02, | ||
| String = 0x03, | ||
| Interface = 0x04, | ||
| Endpoint = 0x05, | ||
| DeviceQualifier = 0x06, | ||
| InterfaceAssociation = 0x0b, | ||
| CsDevice = 0x21, | ||
| CsConfig = 0x22, | ||
| CsString = 0x23, | ||
| CsInterface = 0x24, | ||
| CsEndpoint = 0x25, | ||
| _, | ||
| }; | ||
|
|
||
| /// Describes a device. This is the most broad description in USB and is | ||
| /// typically the first thing the host asks for. | ||
| pub const Device = extern struct { | ||
| /// Class, subclass and protocol of device. | ||
| pub const DeviceTriple = extern struct { | ||
| /// Class of device, giving a broad functional area. | ||
| class: types.ClassCode, | ||
| /// Subclass of device, refining the class. | ||
| subclass: u8, | ||
| /// Protocol within the subclass. | ||
| protocol: u8, | ||
|
|
||
| pub const unspecified: @This() = .{ | ||
| .class = .Unspecified, | ||
| .subclass = 0, | ||
| .protocol = 0, | ||
| }; | ||
| }; | ||
|
|
||
| /// USB Device Qualifier Descriptor | ||
| /// This descriptor is a subset of the DeviceDescriptor | ||
| pub const Qualifier = extern struct { | ||
| comptime { | ||
| assert(@alignOf(@This()) == 1); | ||
| assert(@sizeOf(@This()) == 10); | ||
| } | ||
|
|
||
| length: u8 = @sizeOf(@This()), | ||
| /// Type of this descriptor, must be `DeviceQualifier`. | ||
| descriptor_type: Type = .DeviceQualifier, | ||
| /// Specification version as Binary Coded Decimal | ||
| bcd_usb: types.U16Le, | ||
| /// Class, subclass and protocol of device. | ||
| device_triple: DeviceTriple, | ||
| /// Maximum unit of data this device can move. | ||
| max_packet_size0: u8, | ||
| /// Number of configurations supported by this device. | ||
| num_configurations: u8, | ||
| /// Reserved for future use; must be 0 | ||
| reserved: u8 = 0, | ||
|
|
||
| pub fn serialize(this: @This()) [@sizeOf(@This())]u8 { | ||
| return @bitCast(this); | ||
| } | ||
| }; | ||
|
|
||
| comptime { | ||
| assert(@alignOf(@This()) == 1); | ||
| assert(@sizeOf(@This()) == 18); | ||
| } | ||
|
|
||
| length: u8 = @sizeOf(@This()), | ||
| /// Type of this descriptor, must be `Device`. | ||
| descriptor_type: Type = .Device, | ||
| /// Specification version as Binary Coded Decimal | ||
| bcd_usb: types.U16Le, | ||
| /// Class, subclass and protocol of device. | ||
| device_triple: DeviceTriple, | ||
| /// Maximum length of data this device can move. | ||
| max_packet_size0: u8, | ||
| /// ID of product vendor. | ||
| vendor: types.U16Le, | ||
| /// ID of product. | ||
| product: types.U16Le, | ||
| /// Device version number as Binary Coded Decimal. | ||
| bcd_device: types.U16Le, | ||
| /// Index of manufacturer name in string descriptor table. | ||
| manufacturer_s: u8, | ||
| /// Index of product name in string descriptor table. | ||
| product_s: u8, | ||
| /// Index of serial number in string descriptor table. | ||
| serial_s: u8, | ||
| /// Number of configurations supported by this device. | ||
| num_configurations: u8, | ||
|
|
||
| pub fn serialize(this: @This()) [@sizeOf(@This())]u8 { | ||
| return @bitCast(this); | ||
| } | ||
|
|
||
| pub fn qualifier(this: @This()) Qualifier { | ||
| return .{ | ||
| .bcd_usb = this.bcd_usb, | ||
| .device_triple = this.device_triple, | ||
| .max_packet_size0 = this.max_packet_size0, | ||
| .num_configurations = this.num_configurations, | ||
| }; | ||
| } | ||
| }; | ||
|
|
||
| /// Description of a single available device configuration. | ||
| pub const Configuration = extern struct { | ||
| /// Maximum device current consumption. | ||
| pub const MaxCurrent = extern struct { | ||
| multiple_of_2ma: u8, | ||
|
|
||
| pub fn from_ma(ma: u9) @This() { | ||
| return .{ .multiple_of_2ma = @intCast((ma +| 1) >> 1) }; | ||
| } | ||
| }; | ||
|
|
||
| /// Bit set of device attributes: | ||
| /// | ||
| /// - Bit 7 should be set (indicates that device can be bus powered in USB | ||
| /// 1.0). | ||
| /// - Bit 6 indicates that the device can be self-powered. | ||
| /// - Bit 5 indicates that the device can signal remote wakeup of the host | ||
| /// (like a keyboard). | ||
| /// - The rest are reserved and should be zero. | ||
| pub const Attributes = packed struct(u8) { | ||
| reserved: u5 = 0, | ||
| can_remote_wakeup: bool = false, | ||
| self_powered: bool, | ||
| usb1_bus_powered: bool = true, | ||
| }; | ||
|
|
||
| comptime { | ||
| assert(@alignOf(@This()) == 1); | ||
| assert(@sizeOf(@This()) == 9); | ||
| } | ||
|
|
||
| length: u8 = @sizeOf(@This()), | ||
| /// Type of this descriptor, must be `Configuration`. | ||
| descriptor_type: Type = .Configuration, | ||
| /// Total length of all descriptors in this configuration, concatenated. | ||
| /// This will include this descriptor, plus at least one interface | ||
| /// descriptor, plus each interface descriptor's endpoint descriptors. | ||
| total_length: types.U16Le, | ||
| /// Number of interface descriptors in this configuration. | ||
| num_interfaces: u8, | ||
| /// Number to use when requesting this configuration via a | ||
| /// `SetConfiguration` request. | ||
| configuration_value: u8, | ||
| /// Index of this configuration's name in the string descriptor table. | ||
| configuration_s: u8, | ||
| /// Bit set of device attributes. | ||
| attributes: Attributes, | ||
| /// Maximum device power consumption in units of 2mA. | ||
| max_current: MaxCurrent, | ||
|
|
||
| pub fn serialize(this: @This()) [@sizeOf(@This())]u8 { | ||
| return @bitCast(this); | ||
| } | ||
| }; | ||
|
|
||
| pub fn string(comptime value: []const u8) []const u8 { | ||
| @setEvalBranchQuota(10000); | ||
| const encoded: []const u8 = @ptrCast(std.unicode.utf8ToUtf16LeStringLiteral(value)); | ||
| return &[2]u8{ encoded.len + 2, @intFromEnum(Type.String) } ++ encoded; | ||
| } | ||
|
|
||
| /// String descriptor 0. | ||
| pub const Language = extern struct { | ||
| comptime { | ||
| assert(@alignOf(@This()) == 1); | ||
| assert(@sizeOf(@This()) == 4); | ||
| } | ||
|
|
||
| length: u8 = @sizeOf(@This()), | ||
| /// Type of this descriptor, must be `String`. | ||
| descriptor_type: Type = .String, | ||
| /// See definitions below for possible values. | ||
| lang: types.U16Le, | ||
|
|
||
| pub const English: @This() = .{ .lang = .from(0x0409) }; | ||
|
|
||
| pub fn serialize(this: @This()) [@sizeOf(@This())]u8 { | ||
| return @bitCast(this); | ||
| } | ||
| }; | ||
|
|
||
| /// Describes an endpoint within an interface | ||
| pub const Endpoint = extern struct { | ||
| pub const Attributes = packed struct(u8) { | ||
| pub const Synchronisation = enum(u2) { | ||
| none = 0, | ||
| asynchronous = 1, | ||
| adaptive = 2, | ||
| synchronous = 3, | ||
| }; | ||
|
|
||
| pub const Usage = enum(u2) { | ||
| data = 0, | ||
| feedback = 1, | ||
| implicit_feedback = 2, | ||
| reserved = 3, | ||
| }; | ||
|
|
||
| transfer_type: types.TransferType, | ||
| synchronisation: Synchronisation = .none, | ||
| usage: Usage, | ||
| reserved: u2 = 0, | ||
| }; | ||
|
|
||
| comptime { | ||
| assert(@alignOf(@This()) == 1); | ||
| assert(@sizeOf(@This()) == 7); | ||
| } | ||
|
|
||
| length: u8 = @sizeOf(@This()), | ||
| /// Type of this descriptor, must be `Endpoint`. | ||
| descriptor_type: Type = .Endpoint, | ||
| /// Address of this endpoint, where the bottom 4 bits give the endpoint | ||
| /// number (0..15) and the top bit distinguishes IN (1) from OUT (0). | ||
| endpoint: types.Endpoint, | ||
| /// Endpoint attributes; the most relevant part is the bottom 2 bits, which | ||
| /// control the transfer type using the values from `TransferType`. | ||
| attributes: Attributes, | ||
| /// Maximum packet size this endpoint can accept/produce. | ||
| max_packet_size: types.U16Le, | ||
| /// Interval for polling interrupt/isochronous endpoints (which we don't | ||
| /// currently support) in milliseconds. | ||
| interval: u8, | ||
| }; | ||
|
|
||
| /// Description of an interface within a configuration. | ||
| pub const Interface = extern struct { | ||
| comptime { | ||
| assert(@alignOf(@This()) == 1); | ||
| assert(@sizeOf(@This()) == 9); | ||
| } | ||
|
|
||
| length: u8 = @sizeOf(@This()), | ||
| /// Type of this descriptor, must be `Interface`. | ||
| descriptor_type: Type = .Interface, | ||
| /// ID of this interface. | ||
| interface_number: u8, | ||
| /// Allows a single `interface_number` to have several alternate interface | ||
| /// settings, where each alternate increments this field. Normally there's | ||
| /// only one, and `alternate_setting` is zero. | ||
| alternate_setting: u8, | ||
| /// Number of endpoint descriptors in this interface. | ||
| num_endpoints: u8, | ||
| /// Interface class code, distinguishing the type of interface. | ||
| interface_class: u8, | ||
| /// Interface subclass code, refining the class of interface. | ||
| interface_subclass: u8, | ||
| /// Protocol within the interface class/subclass. | ||
| interface_protocol: u8, | ||
| /// Index of interface name within string descriptor table. | ||
| interface_s: u8, | ||
| }; | ||
|
|
||
| /// USB interface association descriptor (IAD) allows the device to group interfaces that belong to a function. | ||
| pub const InterfaceAssociation = extern struct { | ||
| comptime { | ||
| assert(@alignOf(@This()) == 1); | ||
| assert(@sizeOf(@This()) == 8); | ||
| } | ||
|
|
||
| length: u8 = @sizeOf(@This()), | ||
| // Type of this descriptor, must be `InterfaceAssociation`. | ||
| descriptor_type: Type = .InterfaceAssociation, | ||
| // First interface number of the set of interfaces that follow this | ||
| // descriptor. | ||
| first_interface: u8, | ||
| // The number of interfaces that follow this descriptor that are considered | ||
| // associated. | ||
| interface_count: u8, | ||
| // The interface class used for associated interfaces. | ||
| function_class: u8, | ||
| // The interface subclass used for associated interfaces. | ||
| function_subclass: u8, | ||
| // The interface protocol used for associated interfaces. | ||
| function_protocol: u8, | ||
| // Index of the string descriptor describing the associated interfaces. | ||
| function: u8, | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| const assert = @import("std").debug.assert; | ||
| const Type = @import("../descriptor.zig").Type; | ||
| const types = @import("../types.zig"); | ||
|
|
||
| pub const SubType = enum(u8) { | ||
| Header = 0x00, | ||
| CallManagement = 0x01, | ||
| AbstractControlModel = 0x02, | ||
| Union = 0x06, | ||
| }; | ||
|
|
||
| pub const Header = extern struct { | ||
| comptime { | ||
| assert(@alignOf(@This()) == 1); | ||
| assert(@sizeOf(@This()) == 5); | ||
| } | ||
|
|
||
| length: u8 = @sizeOf(@This()), | ||
| // Type of this descriptor, must be `ClassSpecific`. | ||
| descriptor_type: Type = .CsInterface, | ||
| // Subtype of this descriptor, must be `Header`. | ||
| descriptor_subtype: SubType = .Header, | ||
| // USB Class Definitions for Communication Devices Specification release | ||
| // number in binary-coded decimal. Typically 0x01_10. | ||
| bcd_cdc: types.U16Le, | ||
| }; | ||
|
|
||
| pub const CallManagement = extern struct { | ||
| comptime { | ||
| assert(@alignOf(@This()) == 1); | ||
| assert(@sizeOf(@This()) == 5); | ||
| } | ||
|
|
||
| length: u8 = 5, | ||
| // Type of this descriptor, must be `ClassSpecific`. | ||
| descriptor_type: Type = .CsInterface, | ||
| // Subtype of this descriptor, must be `CallManagement`. | ||
| descriptor_subtype: SubType = .CallManagement, | ||
| // Capabilities. Should be 0x00 for use as a serial device. | ||
| capabilities: u8, | ||
| // Data interface number. | ||
| data_interface: u8, | ||
| }; | ||
|
|
||
| pub const AbstractControlModel = extern struct { | ||
| comptime { | ||
| assert(@alignOf(@This()) == 1); | ||
| assert(@sizeOf(@This()) == 4); | ||
| } | ||
|
|
||
| length: u8 = @sizeOf(@This()), | ||
| // Type of this descriptor, must be `ClassSpecific`. | ||
| descriptor_type: Type = .CsInterface, | ||
| // Subtype of this descriptor, must be `AbstractControlModel`. | ||
| descriptor_subtype: SubType = .AbstractControlModel, | ||
| // Capabilities. Should be 0x02 for use as a serial device. | ||
| capabilities: u8, | ||
| }; | ||
|
|
||
| pub const Union = extern struct { | ||
| comptime { | ||
| assert(@alignOf(@This()) == 1); | ||
| assert(@sizeOf(@This()) == 5); | ||
| } | ||
|
|
||
| length: u8 = 5, | ||
mattnite marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // Type of this descriptor, must be `ClassSpecific`. | ||
| descriptor_type: Type = .CsInterface, | ||
| // Subtype of this descriptor, must be `Union`. | ||
| descriptor_subtype: SubType = .Union, | ||
| // The interface number of the communication or data class interface | ||
| // designated as the master or controlling interface for the union. | ||
| master_interface: u8, | ||
| // The interface number of the first slave or associated interface in the | ||
| // union. | ||
| slave_interface_0: u8, | ||
| }; | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.