USB services: Difference between revisions
No edit summary |
|||
Line 465: | Line 465: | ||
| 8 ([1.0.0] 7) || [6.0.0+] ([1.0.0] [[#GetDescriptorString]]) | | 8 ([1.0.0] 7) || [6.0.0+] ([1.0.0] [[#GetDescriptorString]]) | ||
|- | |- | ||
| [1.0.0] 8 || | | [1.0.0] 8 || [[#ResetDevice]] | ||
|} | |} | ||
Line 476: | Line 476: | ||
== QueryAllInterfaces == | == QueryAllInterfaces == | ||
Takes an [[# | Takes an [[#DeviceFilter]] and a type-0x6 output buffer, returns an output s32 total_entries. | ||
The output buffer contains an array of [[# | The output buffer contains an array of [[#InterfaceQueryOutput]]. This returns the same interfaces as [[#QueryAvailableInterfaces]], followed by the interfaces also returned by [[#QueryAcquiredInterfaces]]. Except for the ID field in [[#InterfaceQueryOutput]], which is set to -1. | ||
== QueryAvailableInterfaces == | == QueryAvailableInterfaces == | ||
Takes an [[# | Takes an [[#DeviceFilter]] and a type-0x6 output buffer, returns an output s32 total_entries. | ||
The output buffer contains an array of [[# | The output buffer contains an array of [[#InterfaceQueryOutput]]. This only returns interfaces which are not acquired by any process. | ||
== QueryAcquiredInterfaces == | == QueryAcquiredInterfaces == | ||
Takes a type-0x6 output buffer and returns an output s32 total_entries. | Takes a type-0x6 output buffer and returns an output s32 total_entries. | ||
The output buffer contains an array of [[# | The output buffer contains an array of [[#InterfaceQueryOutput]], for each interface which was acquired with [[#AcquireUsbIf]]. | ||
== CreateInterfaceAvailableEvent == | == CreateInterfaceAvailableEvent == | ||
Takes an input u8 and an [[# | Takes an input u8 and an [[#DeviceFilter]], and returns an output handle. The input value must be 0..2. This is used as an index in a table. | ||
The struct is located at +2 from the u8 in IPC rawdata. | The struct is located at +2 from the u8 in IPC rawdata. | ||
Line 505: | Line 505: | ||
No input, returns an output event handle with autoclear disabled. | No input, returns an output event handle with autoclear disabled. | ||
When signaled, this indicates that the user-process should use [[#QueryAcquiredInterfaces]] and cleanup state for interfaces which were already initialized and don't have any matching ID in [[# | When signaled, this indicates that the user-process should use [[#QueryAcquiredInterfaces]] and cleanup state for interfaces which were already initialized and don't have any matching ID in [[#InterfaceProfile]] +0x0. When total_entries is less than 1, this indicates that cleanup should be done for all currently open interfaces. | ||
== AcquireUsbIf == | == AcquireUsbIf == | ||
Takes an input u32 and a type-0x6 output buffer, returns an [[#IClientIfSession]]. On [3.0.0+] this takes an additional type-0x6 output buffer, before the original buffer. On [3.0.0+] the first buffer is 0x70-bytes, while the second one is 0x1B8. The user-process has the second buffer address immediately after the first one, which allows getting a complete [[# | Takes an input u32 and a type-0x6 output buffer, returns an [[#IClientIfSession]]. On [3.0.0+] this takes an additional type-0x6 output buffer, before the original buffer. On [3.0.0+] the first buffer is 0x70-bytes, while the second one is 0x1B8. The user-process has the second buffer address immediately after the first one, which allows getting a complete [[#InterfaceProfile]]. | ||
The input u32 is from the u32 at entry+0 from the associated [[#QueryAvailableInterfaces]] output entry. User-processes use size 0x1B8 for the first output buffer. The first output buffer contains | The input u32 is from the u32 at entry+0 from the associated [[#QueryAvailableInterfaces]] output entry. User-processes use size 0x1B8 for the first output buffer. The first output buffer contains an [[#InterfaceProfile]]. | ||
This returns an error if the interface was already acquired by another process. | This returns an error if the interface was already acquired by another process. | ||
Line 525: | Line 525: | ||
Official sw doesn't use this, [[#SubmitControlInRequest]] is used instead. | Official sw doesn't use this, [[#SubmitControlInRequest]] is used instead. | ||
== | == ResetDevice == | ||
[1.0.0] Takes an input u32, no output. Stubbed, just returns 0. | [1.0.0] Takes an input u32, no output. Stubbed, just returns 0. | ||
Line 535: | Line 535: | ||
! Cmd || Name | ! Cmd || Name | ||
|- | |- | ||
| 0 || | | 0 || [[#GetStateChangeEvent]] | ||
|- | |- | ||
| 1 || [[#SetInterface]] | | 1 || [[#SetInterface]] | ||
Line 543: | Line 543: | ||
| 3 || [[#GetAlternateInterface]] | | 3 || [[#GetAlternateInterface]] | ||
|- | |- | ||
| 4 [1.0.0] 5) || [[#GetCurrentFrame]] | | 4 ([1.0.0] 5) || [[#GetCurrentFrame]] | ||
|- | |- | ||
| [2.0.0+] 5 || [[#CtrlXferAsync]] | | [2.0.0+] 5 || [[#CtrlXferAsync]] | ||
|- | |- | ||
| 6 || ([1.0.0] [[#SubmitControlInRequest]]) | | 6 || ([1.0.0] [[#SubmitControlInRequest]]) | ||
|- | |- | ||
| 7 || [[#GetCtrlXferReport]] ([1.0.0] [[#SubmitControlOutRequest]]) | | 7 || [[#GetCtrlXferReport]] ([1.0.0] [[#SubmitControlOutRequest]]) | ||
Line 560: | Line 560: | ||
Immediately after opening the session, official sw uses cmd0 and cmd6. | Immediately after opening the session, official sw uses cmd0 and cmd6. | ||
=== | === GetStateChangeEvent === | ||
No input, returns an output handle. | No input, returns an output handle. | ||
=== SetInterface === | === SetInterface === | ||
Takes an input u8 and a type-0x6 output buffer, no output. The output buffer contains | Takes an input u8 and a type-0x6 output buffer, no output. The output buffer contains an [[#InterfaceProfile]]. | ||
=== GetInterface === | === GetInterface === | ||
Takes a type-0x6 output buffer, no output. The output buffer contains | Takes a type-0x6 output buffer, no output. The output buffer contains an [[#InterfaceProfile]]. | ||
=== GetAlternateInterface === | === GetAlternateInterface === | ||
Takes an input u8 and a type-0x6 output buffer, no output. The output buffer contains | Takes an input u8 and a type-0x6 output buffer, no output. The output buffer contains an [[#InterfaceProfile]]. The buffer size must match 0x1B8. | ||
=== GetCurrentFrame === | === GetCurrentFrame === | ||
Line 625: | Line 625: | ||
| 1 || [[#Close]] ([1.0.0] [[#SubmitInRequest]]) | | 1 || [[#Close]] ([1.0.0] [[#SubmitInRequest]]) | ||
|- | |- | ||
| 2 || | | 2 || ([1.0.0] Reset) | ||
|- | |- | ||
| 3 || [[#Populate]] ([1.0.0] [[#Close]]) | | 3 || [[#Populate]] ([1.0.0] [[#Close]]) | ||
Line 901: | Line 901: | ||
|} | |} | ||
= | = InterfaceQueryOutput = | ||
This is "nn::usb::InterfaceQueryOutput". | |||
{| class="wikitable" border="1" | |||
|- | |||
! Offset || Size || Description | |||
|- | |||
| 0x0 || 0x1B8 || [[#InterfaceProfile|InterfaceProfile]] | |||
|- | |||
| 0x1B8 || 0x40 || "HsDevice-/L<unk0>/P<portnum>/A<unk1>" string (this is "FsDevice..." for the Dock USB 3.0 bus). | |||
|- | |||
| 0x1F8 || 0x4 || busID | |||
|- | |||
| 0x1FC || 0x4 || deviceID | |||
|- | |||
| 0x200 || 0x12+0x9(0x1B) || usb_device_descriptor, then usb_config_descriptor immediately afterwards. | |||
|- | |||
| 0x21B || 0x5 || Padding | |||
|- | |||
| 0x220 || 0x8 || Unknown u64 timestamp for when the device was inserted? | |||
|} | |||
The INPUT/OUTPUT endpoint descriptors (usb_endpoint_descriptors/usb_ss_endpoint_companion_descriptors) were swapped with [8.0.0+] (above layout has the pre-8.0.0 layout), however the sysmodule code which writes this output struct was basically unchanged. | |||
= InterfaceProfile = | |||
This is "nn::usb::InterfaceProfile". | |||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
Line 931: | Line 957: | ||
|- | |- | ||
| 0x1B5 || 0x3 || Padding | | 0x1B5 || 0x3 || Padding | ||
|} | |} | ||
This is | = DeviceFilter = | ||
This is "nn::usb::DeviceFilter". | |||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
Line 979: | Line 991: | ||
This is a 0x10-byte struct (unofficial name). | This is a 0x10-byte struct (unofficial name). | ||
This is used to filter [[# | This is used to filter [[#InterfaceQueryOutput]], the query commands will only return the interface when these checks pass. This is also used for events with [[#CreateInterfaceAvailableEvent]]. When a bit in Flags is set, the associated descriptor field and the field in this struct are compared, on mismatch the interface will be filtered out. Passing Flags=0 is equivalent to disabling filtering since none of these checks will run. | ||
[7.0.0+]: The filter struct has to be unique, it can't match any existing filter structs used by [[#CreateInterfaceAvailableEvent]] (including other processes). Hence, Flags has to be non-zero. When initialized with usb:hs:a and VID and/or PID filtering is enabled, the VID/PID will be checked [[#HidGamepad]], with an error being throw if a matching device is found with quirk "ApplicationBlacklist" ([[#usb:qdb|usb:qdb]] cmd1 is used internally for this with bcdDevice=0). | [7.0.0+]: The filter struct has to be unique, it can't match any existing filter structs used by [[#CreateInterfaceAvailableEvent]] (including other processes). Hence, Flags has to be non-zero. When initialized with usb:hs:a and VID and/or PID filtering is enabled, the VID/PID will be checked [[#HidGamepad]], with an error being throw if a matching device is found with quirk "ApplicationBlacklist" ([[#usb:qdb|usb:qdb]] cmd1 is used internally for this with bcdDevice=0). |