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 [[#UsbHsInterfaceFilter]] and a type-0x6 output buffer, returns an output s32 total_entries. | + | Takes an [[#DeviceFilter]] and a type-0x6 output buffer, returns an output s32 total_entries. |
| | | |
− | The output buffer contains an array of [[#UsbHsInterface]]. This returns the same interfaces as [[#QueryAvailableInterfaces]], followed by the interfaces also returned by [[#QueryAcquiredInterfaces]]. Except for the ID field in [[#UsbHsInterface]], which is set to -1. | + | 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 [[#UsbHsInterfaceFilter]] and a type-0x6 output buffer, returns an output s32 total_entries. | + | Takes an [[#DeviceFilter]] and a type-0x6 output buffer, returns an output s32 total_entries. |
| | | |
− | The output buffer contains an array of [[#UsbHsInterface]]. This only returns interfaces which are not acquired by any process. | + | 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 [[#UsbHsInterface]], for each interface which was acquired with [[#AcquireUsbIf]]. | + | The output buffer contains an array of [[#InterfaceQueryOutput]], for each interface which was acquired with [[#AcquireUsbIf]]. |
| | | |
| == CreateInterfaceAvailableEvent == | | == CreateInterfaceAvailableEvent == |
− | Takes an input u8 and an [[#UsbHsInterfaceFilter]], and returns an output handle. The input value must be 0..2. This is used as an index in a table. | + | 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 [[#UsbHsInterface]] +0x0. When total_entries is less than 1, this indicates that cleanup should be done for all currently open interfaces. | + | 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 [[#UsbHsInterface]]. | + | 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 first 0x1B8-bytes from [[#UsbHsInterface]]. | + | 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. |
| | | |
− | == Cmd8 == | + | == 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. |
| | | |
− | === Cmd0 === | + | === 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 the first 0x1B8-bytes from [[#UsbHsInterface]]. | + | 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 the first 0x1B8-bytes from [[#UsbHsInterface]]. | + | 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 the first 0x1B8-bytes from [[#UsbHsInterface]]. The buffer size must match 0x1B8. | + | 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: |
| |} | | |} |
| | | |
− | = UsbHsInterface = | + | = 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 |
− | |-
| |
− | | 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?
| |
| |} | | |} |
| | | |
− | This is a 0x228-byte struct (unofficial name). | + | = DeviceFilter = |
− | | + | This is "nn::usb::DeviceFilter". |
− | 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.
| |
| | | |
− | = UsbHsInterfaceFilter =
| |
| {| 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 [[#UsbHsInterface]], 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. | + | 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). |