USB services: Difference between revisions
(40 intermediate revisions by 2 users not shown) | |||
Line 40: | Line 40: | ||
|- | |- | ||
| 11 || [5.0.0+] Disable | | 11 || [5.0.0+] Disable | ||
|- | |||
| 12 || [8.0.0+] | |||
|} | |} | ||
Line 137: | Line 139: | ||
== GetDsInterface == | == GetDsInterface == | ||
Takes 2 type-5 buffers and returns an [[#IDsInterface]]. [[Manu_Services|Manu]] sends a 0x09-byte | Takes 2 type-5 buffers and returns an output u8 and an [[#IDsInterface]]. [[Manu_Services|Manu]] sends a 0x09-byte descriptor (e.g.: 0x09, 0x04, 0x04, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00) in the first buffer and a string ("usb") in the second buffer. | ||
When the strlen output for the second buffer is >=0x40, size 0x40 is used instead for copying the string. This is the interface name, it's not sent over USB. | When the strlen output for the second buffer is >=0x40, size 0x40 is used instead for copying the string. This is the interface name, it's not sent over USB. | ||
Line 243: | Line 245: | ||
=== GetDsEndpoint === | === GetDsEndpoint === | ||
Takes a type-5 buffer and returns an [[#IDsEndpoint]]. [[Manu_Services|Manu]] uses this twice for getting two endpoint sessions, with the following 0x7-byte buffer data: | Takes a type-5 buffer and returns an output u8 and an [[#IDsEndpoint]]. [[Manu_Services|Manu]] uses this twice for getting two endpoint sessions, with the following 0x7-byte buffer data: | ||
* First endpoint: 0x07, 0x05, 0x80, 0x02, 0x00, 0x02, 0x00 | * First endpoint: 0x07, 0x05, 0x80, 0x02, 0x00, 0x02, 0x00 | ||
** bLength=0x7 | ** bLength=0x7 | ||
Line 318: | Line 320: | ||
|- | |- | ||
| 5 || || Takes an input u8, no output. | | 5 || || Takes an input u8, no output. | ||
|- | |||
| 6 || [7.0.0+] || No input, returns an output u8. | |||
|- | |||
| 7 || [7.0.0+] || No input, returns an output handle. | |||
|} | |} | ||
Line 370: | Line 376: | ||
Stops in-progress data-transfer done by [[#PostBufferAsync]]. | Stops in-progress data-transfer done by [[#PostBufferAsync]]. | ||
= usb:hs = | = usb:hs, usb:hs:a = | ||
This is "nn::usb::hs::IClientRootSession". | This is "nn::usb::hs::IClientRootSession". | ||
[7.0.0+] usb:hs:a opens an nn::usb::hs::IClientRootSession, but sets an "isSystemClient" field in the object (and in interfaces/eps opened by the session) to false. | |||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
Line 406: | Line 414: | ||
== QueryAllInterfaces == | == QueryAllInterfaces == | ||
Takes | Takes an [[#UsbHsInterfaceFilter]] and a type-0x6 output buffer, returns an output s32 total_entries. | ||
The output buffer contains an array of [[#UsbHsInterface]]. | 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. | ||
== QueryAvailableInterfaces == | == QueryAvailableInterfaces == | ||
Takes | Takes an [[#UsbHsInterfaceFilter]] 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. | |||
== QueryAcquiredInterfaces == | == QueryAcquiredInterfaces == | ||
Line 423: | Line 429: | ||
== CreateInterfaceAvailableEvent == | == CreateInterfaceAvailableEvent == | ||
Takes an input u8 and | 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. | ||
The struct is located at +2 from the u8 in IPC rawdata | The struct is located at +2 from the u8 in IPC rawdata. | ||
When signaled, this indicates that the user-process should use [[#QueryAvailableInterfaces]] and [[#AcquireUsbIf]] with the output interfaces (and the rest of interface setup). | When signaled, this indicates that the user-process should use [[#QueryAvailableInterfaces]] and [[#AcquireUsbIf]] with the output interfaces (and the rest of interface setup). | ||
Line 437: | Line 443: | ||
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 | 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. | ||
== AcquireUsbIf == | == AcquireUsbIf == | ||
Takes an input u32 and a type-0x6 output buffer, returns an [[#IClientIfSession]]. | 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]]. | ||
The input u32 is from the u32 at entry+0 from the associated [[#QueryAvailableInterfaces]] output entry. User-processes use size 0x1B8 for the output buffer. The 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 the first 0x1B8-bytes from [[#UsbHsInterface]]. | ||
This returns an error if the interface was already acquired by another process. | |||
== GetDescriptorString == | == GetDescriptorString == | ||
Line 494: | Line 502: | ||
=== GetAlternateInterface === | === GetAlternateInterface === | ||
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 the first 0x1B8-bytes from [[#UsbHsInterface]]. The buffer size must match 0x1B8. | ||
=== GetCurrentFrame === | === GetCurrentFrame === | ||
Line 506: | Line 514: | ||
=== GetCtrlXferReport === | === GetCtrlXferReport === | ||
Takes a type-0x6 output buffer, no output. The output buffer contains a [[#XferReport]]. | Takes a type-0x6 output buffer, no output. The output buffer contains a [[#XferReport]]. | ||
=== SubmitControlInRequest === | |||
Takes a type-0x6 output buffer, 2 input u8s ('''bRequest''' and '''bRequestType'''), 3 input u16s ('''wValue''', '''wIndex''', and '''wLength'''), and an input u32 '''timeoutInMs'''. Returns an output u32 for the actual transferred size. | |||
Official user-processes uses a buffer where the buffer address/size is page-aligned, where '''wLength''' is the original size before alignment. The user-process also flushes dcache for this buffer using '''wLength''', before/after using this command. Official sw passes value 0 for '''timeoutInMs'''. | |||
=== SubmitControlOutRequest === | |||
Takes a type-0x5 input buffer, 2 input u8s ('''bRequest''' and '''bRequestType'''), 3 input u16s ('''wValue''', '''wIndex''', and '''wLength'''), and an input u32 '''timeoutInMs'''. Returns an output u32 for the actual transferred size. | |||
Official user-processes uses a buffer where the buffer address/size is page-aligned, where '''wLength''' is the original size before alignment. The user-process also flushes dcache for this buffer using '''wLength''', before using this command. Official sw passes value 0 for '''timeoutInMs'''. | |||
=== ResetDevice === | === ResetDevice === | ||
No input/output. | No input/output. | ||
Resets the device: has the same affect as unplugging the device and plugging it back in. | |||
=== OpenUsbEp === | === OpenUsbEp === | ||
Line 542: | Line 562: | ||
| [2.0.0+] 5 || [[#GetXferReport]] || | | [2.0.0+] 5 || [[#GetXferReport]] || | ||
|- | |- | ||
| [2.0.0+] 6 || || | | [2.0.0+] 6 || [[#PostBufferMultiAsync]] || | ||
|- | |- | ||
| [4.0.0+] 7 || || | | [4.0.0+] 7 || || Takes a total of 0x10-bytes of input, no output. | ||
|- | |- | ||
| [4.0.0+] 8 || || | | [4.0.0+] 8 || || Takes a total of 0x4-bytes of input and an input handle, no output. | ||
|} | |} | ||
Line 581: | Line 601: | ||
==== PostBufferAsync ==== | ==== PostBufferAsync ==== | ||
Takes an input u32 '''size''', an input u64 '''buffer''', and an input u64, returns an output u32 '''xferId'''. | Takes an input u32 '''size''', an input u64 '''buffer''', and an input u64 '''unk''', returns an output u32 '''xferId'''. | ||
HID-sysmodule passes value 0 for the last u64. | HID-sysmodule passes value 0 for the last u64. | ||
Starts a data transfer with a single urb. | |||
==== GetXferReport ==== | ==== GetXferReport ==== | ||
Takes an input u32 and a type-0x6 output buffer, returns an output u32 '''count'''. | Takes an input u32 and a type-0x6 ([3.0.0+] type-0x22) output buffer, returns an output u32 '''count'''. | ||
The input u32 specifies the total number of entries to read, this must fit within the specified buffer size. The output u32 is the total actual output entries. | The input u32 specifies the total number of entries to read, this must fit within the specified buffer size. The output u32 is the total actual output entries. | ||
The buffer contains an array of [[#XferReport]]. | The buffer contains an array of [[#XferReport]]. | ||
==== PostBufferMultiAsync ==== | |||
Unofficial name. | |||
Takes 3 input u32s ('''urbCount''', '''unk1''', and '''unk2'''), an input u64 '''buffer''' and u64 '''unk''', and a type-0x5 ([3.0.0+] type-0x21) input buffer, returns an output u32 '''xferId'''. | |||
Where '''unk''' is the same as [[#PostBufferAsync_2|#PostBufferAsync]]. | |||
This uses the same func internally as [[#PostBufferAsync_2|#PostBufferAsync]] except multiple urbs are specified by the user: the input buffer contains an array of u32s for the size of each urb, where '''urbCount''' is the total number of entries in this array. With [[#PostBufferAsync_2|#PostBufferAsync]] the last 2 params passed to the internal func are hard-coded to 0, while with this command it's '''unk1''' and '''unk2'''. | |||
= UsbHsInterface = | = UsbHsInterface = | ||
Line 599: | Line 630: | ||
| 0x0 || 0x4 || ID value passed to other cmds. This is -1 with [[#QueryAllInterfaces]] output, hence this field is unused with that cmd. | | 0x0 || 0x4 || ID value passed to other cmds. This is -1 with [[#QueryAllInterfaces]] output, hence this field is unused with that cmd. | ||
|- | |- | ||
| 0x4 || 0x4? || | | 0x4 || 0x4 || deviceID | ||
|- | |||
| 0x8 || 0x4 || ? | |||
|- | |||
| 0xC || 0x9 || usb_interface_descriptor | |||
|- | |- | ||
| | | 0x15 || 0x7 || Padding | ||
|- | |- | ||
| | | 0x1C || 0x69 || OUTPUT usb_endpoint_descriptors, 15 max. | ||
|- | |- | ||
| | | 0x85 || 0x7 || Padding | ||
|- | |- | ||
| 0x8C || 0x69 || INPUT usb_endpoint_descriptors, 15 max. | | 0x8C || 0x69 || INPUT usb_endpoint_descriptors, 15 max. | ||
|- | |- | ||
| | | 0xF5 || 0x6 || Padding | ||
|- | |||
| 0xFB || 0x5A || OUTPUT usb_ss_endpoint_companion_descriptors(?), 15 max. | |||
|- | |||
| 0x155 || 0x6 || Padding | |||
|- | |||
| 0x15B || 0x5A || INPUT usb_ss_endpoint_companion_descriptors(?), 15 max. | |||
|- | |||
| 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 | ||
|- | |- | ||
| 0x200 || || usb_device_descriptor, then usb_config_descriptor immediately afterwards. | | 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? | | 0x220 || 0x8 || Unknown u64 timestamp for when the device was inserted? | ||
Line 621: | Line 668: | ||
This is a 0x228-byte struct (unofficial name). | This is a 0x228-byte struct (unofficial name). | ||
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" | |||
|- | |||
! Offset || Size || Description | |||
|- | |||
| 0x0 || 0x2 || Flags | |||
|- | |||
| 0x2 || 0x2 ||idVendor | |||
|- | |||
| 0x4 || 0x2 || idProduct | |||
|- | |||
| 0x6 || 0x2 || bcdDevice_Min | |||
|- | |||
| 0x8 || 0x2 || bcdDevice_Max | |||
|- | |||
| 0xA || 0x1 || bDeviceClass | |||
|- | |||
| 0xB || 0x1 || bDeviceSubClass | |||
|- | |||
| 0xC || 0x1 || bDeviceProtocol | |||
|- | |||
| 0xD || 0x1 || bInterfaceClass | |||
|- | |||
| 0xE || 0x1 || bInterfaceSubClass | |||
|- | |||
| 0xF || 0x1 || bInterfaceProtocol | |||
|} | |||
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. | |||
[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). | |||
Flags bits 0..6 use usb_device_descriptor, while 7..9 use usb_interface_descriptor. Support for bits 2..6 and the associated fields was added with [6.0.0+]. | |||
Flags bits: | |||
* 0: idVendor | |||
* 1: idProduct | |||
* 2: bcdDevice (Descriptor value must be >= struct bcdDevice_Min) | |||
* 3: bcdDevice (Descriptor value must be <= struct bcdDevice_Max) | |||
* 4: bDeviceClass | |||
* 5: bDeviceSubClass | |||
* 6: bDeviceProtocol | |||
* 7: bInterfaceClass | |||
* 8: bInterfaceSubClass | |||
* 9: bInterfaceProtocol | |||
HID-sysmodule uses the following for the input struct: <code>80 00 00 00 00 00 00 00 00 00 00 00 00 03 00 00</code> | |||
= XferReport = | = XferReport = | ||
Line 627: | Line 726: | ||
! Offset || Size || Description | ! Offset || Size || Description | ||
|- | |- | ||
| 0x0 || 0x4 || | | 0x0 || 0x4 || xferId (Only set for [[#GetXferReport]]) | ||
|- | |- | ||
| 0x4 || 0x4 || Result | | 0x4 || 0x4 || Result | ||
|- | |- | ||
| 0x8 || 0x4 || | | 0x8 || 0x4 || requestedSize | ||
|- | |- | ||
| 0xC || 0x4 || | | 0xC || 0x4 || transferredSize | ||
|- | |- | ||
| 0x10 || 0x8? || ? | | 0x10 || 0x8? || ? | ||
Line 769: | Line 868: | ||
USB Port Manager, only system-title using this is [[PTM_services|ptm]]. | USB Port Manager, only system-title using this is [[PTM_services|ptm]]. | ||
= usb:qdb = | |||
Added with [[7.0.0]]. | |||
{| class="wikitable" border="1" | |||
|- | |||
! Cmd || Name | |||
|- | |||
| 0 || | |||
|- | |||
| 1 || | |||
|} | |||
== Cmd0 == | |||
No input/output, takes a type-0x5 input buffer. | |||
This loads data for [[#HidGamepad]] with the input .json. | |||
== Cmd1 == | |||
Takes 6-bytes of input (u16s '''vid''', '''pid''', '''bcdDevice''') and a type-0x5 input buffer, returns an output u8 bool indicating success. | |||
Locates an entry in the [[#HidGamepad]] state with the input u16s, and checks for a '''quirks''' array entry where '''name''' matches the input buffer string. Returns 1 when found, 0 otherwise. | |||
= usb:obsv = | |||
Added with [8.0.0+]. | |||
{| class="wikitable" border="1" | |||
|- | |||
! Cmd || Name | |||
|- | |||
| 0 || | |||
|- | |||
| 1 || | |||
|} | |||
= HidGamepad = | |||
With [7.0.0+] usb-sysmodule now has .json data embedded in the codebin. | |||
This contains a list of USB devices' VID/PID, with the following structure: | |||
[ | |||
{ | |||
"vid" : "<VID>", | |||
"pid" : "<PID>", | |||
"quirks" : [ | |||
{ | |||
"name" : "<string>" //The .json has the following for <string> for various devices: "HidGamepadWhitelist", "ApplicationBlacklist", and "NoClearHaltOnEpInit". | |||
} | |||
//There can be multiple entries here. | |||
] | |||
}, | |||
<more entries> | |||
] | |||
[[Category:Services]] | [[Category:Services]] |