USB services: Difference between revisions
This shouldn't have been changed |
|||
(135 intermediate revisions by 4 users not shown) | |||
Line 1: | Line 1: | ||
USB provides services for interacting with the USB stack. | |||
= usb:ds = | = usb:ds = | ||
This is "nn::usb::ds::IDsService". | [1.0.0-10.2.0] This is "nn::usb::ds::IDsService". | ||
[11.0.0+] This is "nn::usb::ds::IDsRootSession". | |||
This service is used during [[Factory Setup|factory setup]] by [[Manu Services|manu]]. This is also used by [[Capmtp_services|capmtp]]. | |||
This service session is used as an IPC [[IPC_Marshalling|domain]] by [[Manu Services|manu]]. | |||
This service is used | |||
This service | This service can be used by multiple processes at the same time, with separate interfaces. However, if one process does usbds shutdown, usbds will reset to defaults even if there's a process still using it. | ||
This | {| class="wikitable" border="1" | ||
|- | |||
! Cmd || Name | |||
|- | |||
| 0 || [[#CreateDsService]] | |||
|} | |||
== CreateDsService == | |||
No input. Returns an [[#IDsService]]. | |||
== IDsService == | |||
This is "nn::usb::ds::IDsService". | |||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
Line 15: | Line 29: | ||
! Cmd || Name | ! Cmd || Name | ||
|- | |- | ||
| 0 || [[# | | 0 || [[#Initialize]] | ||
|- | |- | ||
| 1 || [[#BindClientProcess]] | | 1 || [11.0.0+] [[#RegisterInterface]] ([1.0.0-10.2.0] [[#BindClientProcess]])) | ||
|- | |- | ||
| 2 || [[# | | 2 || [11.0.0+] [[#GetStateChangeEvent]] ([1.0.0-10.2.0] [[#RegisterInterface]]) | ||
|- | |- | ||
| 3 || [[#GetStateChangeEvent]] | | 3 || [11.0.0+] [[#GetState]] ([1.0.0-10.2.0] [[#GetStateChangeEvent]]) | ||
|- | |- | ||
| 4 || [[#GetState]] | | 4 || [11.0.0+] ClearDeviceData ([1.0.0-10.2.0] [[#GetState]]) | ||
|- | |- | ||
| [2.0.0-4.1.0] | | 5 || [11.0.0+] AddUsbStringDescriptor ([5.0.0-10.2.0] ClearDeviceData, [2.0.0-4.1.0] [[#SetVidPidBcd]]) | ||
|- | |- | ||
| [ | | 6 || [11.0.0+] DeleteUsbStringDescriptor ([5.0.0-10.2.0] AddUsbStringDescriptor) | ||
|- | |- | ||
| | | 7 || [11.0.0+] SetUsbDeviceDescriptor ([5.0.0-10.2.0] DeleteUsbStringDescriptor) | ||
|- | |- | ||
| | | 8 || [11.0.0+] SetBinaryObjectStore ([5.0.0-10.2.0] SetUsbDeviceDescriptor) | ||
|- | |- | ||
| | | 9 || [11.0.0+] EnableDevice ([5.0.0-10.2.0] SetBinaryObjectStore) | ||
|- | |- | ||
| | | 10 || [11.0.0+] DisableDevice ([5.0.0-10.2.0] EnableDevice) | ||
|- | |- | ||
| | | 11 || [11.0.0+] [[#GetSpeed]] ([5.0.0-10.2.0] DisableDevice) | ||
|- | |- | ||
| | | 12 || [8.0.0-10.2.0] [[#GetSpeed]] | ||
|} | |} | ||
== Initialize == | |||
Takes an input u32 '''ComplexId'''. No output. | |||
== | |||
[11.0.0+] Now takes an additional input Process handle. | |||
[[Manu_Services|Manu]] uses '''ComplexId''' 0x02. | |||
Binding more than once with the current session is not allowed. Once this command is used, the USB device will not be listed with <code>lsusb</code> until [[#EnableInterface]] is used. | Binding more than once with the current session is not allowed. Once this command is used, the USB device will not be listed with <code>lsusb</code> until [[#EnableInterface]] is used. | ||
Returns a not-found error when | Returns a not-found error when '''ComplexId''' isn't 0x02, for values 0x0-0x4 at least. | ||
== BindClientProcess == | == BindClientProcess == | ||
Takes | Takes an input Process handle. No output. | ||
== | == RegisterInterface == | ||
Takes | Takes two type-0x5 input buffers containing an [[#UsbInterfaceDescriptor]] and an [[#UsbStringDescriptor]], respectively. Returns an output u8 '''InterfaceNumber''' and an [[#IDsInterface]]. | ||
[5.0.0+] This now only takes an input u8 and returns 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. | |||
Returns an error when [[#Initialize]] wasn't used. | |||
Up to 4 interfaces can be used and [[#EnableInterface|enabled]]. | |||
== GetStateChangeEvent == | == GetStateChangeEvent == | ||
Returns an | No input. Returns an output Event handle. | ||
Signalled when Switch<->host USB comms change between started/stopped. USB cable connected/disconnected while at least 1 interface was enabled, or interface enabled/disabled while the USB cable was connected which then caused USB-comms state to change. | |||
== GetState == | == GetState == | ||
No input. Returns an output | No input. Returns an output [[#UsbState]]. | ||
Returns | Returns an error when [[#Initialize]] wasn't used. | ||
== SetVidPidBcd == | == SetVidPidBcd == | ||
Takes a type- | Takes a type-0x5 input buffer containing an [[#UsbVidPidBcd]]. No output. | ||
== GetSpeed == | |||
No input. Returns an output [[#UsbDeviceSpeed]]. | |||
== IDsInterface == | == IDsInterface == | ||
Line 213: | Line 104: | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
! Cmd || Name | ! Cmd || Name | ||
|- | |- | ||
| 0 || [[# | | 0 || [[#RegisterEndpoint]] | ||
|- | |- | ||
| 1 || [[#GetSetupEvent]] | | 1 || [[#GetSetupEvent]] | ||
|- | |- | ||
| 2 || | | 2 || [[#GetSetupPacket]] | ||
|- | |- | ||
| 3 || [[# | | 3 || [11.0.0+] [[#CtrlInAsync]] ([1.0.0-10.2.0] [[#Enable]]) | ||
|- | |- | ||
| 4 || [[# | | 4 || [11.0.0+] [[#CtrlOutAsync]] ([1.0.0-10.2.0] [[#Disable]]) | ||
|- | |- | ||
| 5 || [[# | | 5 || [11.0.0+] [[#GetCtrlInCompletionEvent]] ([1.0.0-10.2.0] [[#CtrlInAsync]]) | ||
|- | |- | ||
| 6 || [[# | | 6 || [11.0.0+] [[#GetCtrlInUrbReport]] ([1.0.0-10.2.0] [[#CtrlOutAsync]]) | ||
|- | |- | ||
| 7 || [[#GetCtrlInCompletionEvent]] | | 7 || [11.0.0+] [[#GetCtrlOutCompletionEvent]] ([1.0.0-10.2.0] [[#GetCtrlInCompletionEvent]]) | ||
|- | |- | ||
| 8 || [[# | | 8 || [11.0.0+] [[#GetCtrlOutUrbReport]] ([1.0.0-10.2.0] [[#GetCtrlInUrbReport]]) | ||
|- | |- | ||
| 9 || [[#GetCtrlOutCompletionEvent]] | | 9 || [11.0.0+] [[#CtrlStall]] ([1.0.0-10.2.0] [[#GetCtrlOutCompletionEvent]]) | ||
|- | |- | ||
| 10 || [[# | | 10 || [11.0.0+] [[#AppendConfigurationData]] ([1.0.0-10.2.0] [[#GetCtrlOutUrbReport]]) | ||
|- | |- | ||
| 11 || [[# | | 11 || [13.0.0+] [[#SetGuid]] ([1.0.0-10.2.0] [[#CtrlStall]]) | ||
|- | |- | ||
| 12 || [5.0.0 | | 12 || [15.0.0+] [[#RegisterTransferMemory]] ([5.0.0-10.2.0] [[#AppendConfigurationData]]) | ||
|} | |} | ||
=== RegisterEndpoint === | |||
Takes a type-0x5 input buffer containing an [[#UsbEndpointDescriptor]]. Returns an output u8 '''EndpointNumber''' and an [[#IDsEndpoint]]. | |||
[5.0.0+] This now only takes an input u8 and returns 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 254: | Line 147: | ||
** bInterval=0 | ** bInterval=0 | ||
* Second endpoint: Same as above except byte2 is 0x00(bEndpointAddress=LIBUSB_ENDPOINT_OUT). | * Second endpoint: Same as above except byte2 is 0x00(bEndpointAddress=LIBUSB_ENDPOINT_OUT). | ||
The buffer size must be >=0x7. Only the first 0x7-bytes from the buffer are used. | The buffer size must be >=0x7. Only the first 0x7-bytes from the buffer are used. | ||
Line 265: | Line 154: | ||
From the Tegra datasheet: "The maximum packet size supported on any endpoint is 1024 bytes in high-speed mode, for both device and host modes." | From the Tegra datasheet: "The maximum packet size supported on any endpoint is 1024 bytes in high-speed mode, for both device and host modes." | ||
Throws an error if the interface is [[#EnableInterface|enabled]]. | |||
=== GetSetupEvent === | === GetSetupEvent === | ||
Returns an | No input. Returns an output Event handle. | ||
Unknown what triggers signalling, not signalled during interface-enable / device<>host USB-comms init. | |||
Only one interface can be enabled at a time per bInterfaceNumber. When bInterfaceNumber is auto-allocate(0x4) for [[# | === GetSetupPacket === | ||
Takes a type-0x6 output buffer. No output. | |||
Memcpys data to outbuf with outsize, uses size 0x8 if outsize is too large. | |||
Throws an error if the interface is not [[#EnableInterface|enabled]]. | |||
=== Enable === | |||
No input/output. | |||
Enables the current interface. | |||
Only one interface can be enabled at a time per bInterfaceNumber. When bInterfaceNumber is auto-allocate(0x4) for [[#RegisterEndpoint]] this isn't an issue since the final bInterfaceNumber will be unique. | |||
Once enabled, the device/interface can then actually be used over USB. | Once enabled, the device/interface can then actually be used over USB. | ||
=== | === Disable === | ||
No input/output. | |||
Disables the current interface. | |||
=== CtrlInAsync === | |||
Same as [[#PostBufferAsync]], except this uses control input endpoint 0x80. | |||
Throws an error if the interface is not [[#EnableInterface|enabled]]. | |||
=== | === CtrlOutAsync === | ||
Same as [[#PostBufferAsync]] | Same as [[#PostBufferAsync]], except this uses control output endpoint 0x00. | ||
Throws an error if the interface is not [[#EnableInterface|enabled]]. | |||
=== GetCtrlInCompletionEvent === | === GetCtrlInCompletionEvent === | ||
Same as [[#GetCompletionEvent]], except this uses control input endpoint 0x80. | |||
=== | === GetCtrlInUrbReport === | ||
Same as [[# | Same as [[#GetUrbReport]], except this uses control input endpoint 0x80. | ||
=== GetCtrlOutCompletionEvent === | === GetCtrlOutCompletionEvent === | ||
Same as [[#GetCompletionEvent]], except this uses control output endpoint 0x00. | |||
=== | === GetCtrlOutUrbReport === | ||
Same as [[# | Same as [[#GetUrbReport]], except this uses control output endpoint 0x00. | ||
=== | === CtrlStall === | ||
No input/output. | No input/output. | ||
Calls a function with both control endpoints(0x80 and 0x00) with the same function. From strings: "m_pProtocol->Stall(0x80)" "m_pProtocol->Stall(0x00)". | Calls a function with both control endpoints (0x80 and 0x00) with the same function. From strings: "m_pProtocol->Stall(0x80)" "m_pProtocol->Stall(0x00)". | ||
Throws an error if the interface is not [[#EnableInterface|enabled]]. | |||
=== AppendConfigurationData === | |||
Takes an input u32 '''InterfaceNumber''', an input [[#UsbDeviceSpeed]] and a type-0x5 input buffer. No output. | |||
[5.0.0+] This now only takes an input [[#UsbDeviceSpeed]] and a type-0x5 input buffer. | |||
=== SetGuid === | |||
Takes a type-0x5 input buffer. No output. | |||
=== RegisterTransferMemory === | |||
Takes an input u64 and an input handle. No output. | |||
Stubbed, just returns an error. | |||
=== IDsEndpoint === | === IDsEndpoint === | ||
Line 307: | Line 230: | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
! Cmd || Name || | ! Cmd || Name | ||
|- | |||
| 0 || [[#PostBufferAsync]] | |||
|- | |||
| 1 || [[#Cancel]] | |||
|- | |- | ||
| | | 2 || [[#GetCompletionEvent]] | ||
|- | |- | ||
| | | 3 || [[#GetUrbReport]] | ||
|- | |- | ||
| | | 4 || [[#Stall]] | ||
|- | |- | ||
| | | 5 || [[#SetZlt]] | ||
|- | |- | ||
| | | 6 || [7.0.0+] [[#IsStalled]] | ||
|- | |- | ||
| | | 7 || [7.0.0+] [[#GetStallClearedEvent]] | ||
|- | |||
| 8 || [11.0.0-14.1.2] | |||
|- | |||
| 9 || [11.0.0-14.1.2] | |||
|} | |} | ||
==== PostBufferAsync ==== | ==== PostBufferAsync ==== | ||
Takes an u32 | Takes an input u32 '''Size''' and an input u64 '''Buffer'''. Returns an output u32 '''UrbId'''. | ||
The output urbId can then be used while parsing the output of [[#GetUrbReport]], after waiting for the CompletionEvent to be signalled. | |||
The buffer address must be 0x1000-byte aligned. The input size doesn't matter. It helps to use svcSetMemoryAttribute to turn off caching on the buffer. | The buffer address must be 0x1000-byte aligned. The input size doesn't matter. It helps to use svcSetMemoryAttribute to turn off caching on the buffer. | ||
Line 334: | Line 267: | ||
For receiving data, if size is less than {actual received USB packet size} the rest of the packet will be discarded. Later PostBufferAsync cmd(s) will only return data from new packets, not the remainder of the earlier packet(s). | For receiving data, if size is less than {actual received USB packet size} the rest of the packet will be discarded. Later PostBufferAsync cmd(s) will only return data from new packets, not the remainder of the earlier packet(s). | ||
==== Cancel ==== | |||
No input/output. | |||
==== GetCompletionEvent ==== | ==== GetCompletionEvent ==== | ||
No input. Returns an output | No input. Returns an output Event handle. | ||
==== | ==== GetUrbReport ==== | ||
No input. Returns | No input. Returns an output [[#UrbReport]]. | ||
Seems to be eventually loaded from state, since this doesn't trigger any USB bus activity. All-zero before PostBufferAsync was used at least once. | |||
==== Stall ==== | ==== Stall ==== | ||
No input/output. | No input/output. | ||
Calls the same function used by [[# | Calls the same function used by [[#CtrlStall]], except this uses the endpoint associated with the current session. | ||
Stops in-progress data-transfer done by [[#PostBufferAsync]]. | Stops in-progress data-transfer done by [[#PostBufferAsync]]. | ||
= usb:hs = | ==== SetZlt ==== | ||
Takes an input bool. No output. | |||
==== IsStalled ==== | |||
No input. Returns an output bool. | |||
==== GetStallClearedEvent ==== | |||
No input. Returns an output Event handle. | |||
==== Cmd8 ==== | |||
Takes an input u64 and an input handle. No output. | |||
Stubbed, just returns an error. | |||
==== Cmd9 ==== | |||
Takes an input u32 '''Size''' and an input u64 '''Offset'''. Returns an u32 '''UrbId'''. | |||
Stubbed, just returns an error. | |||
= 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 379: | Line 314: | ||
! Cmd || Name | ! Cmd || Name | ||
|- | |- | ||
| 0 || [[#BindClientProcess_2|#BindClientProcess]] | | 0 || [2.0.0+] [[#BindClientProcess_2|#BindClientProcess]] ([1.0.0] [[#QueryAllInterfaces]]) | ||
|- | |- | ||
| 1 || [[#QueryAllInterfaces]] | | 1 || [[#QueryAllInterfaces]] ([1.0.0] [[#QueryAvailableInterfaces]]) | ||
|- | |- | ||
| 2 || [[#QueryAvailableInterfaces]] | | 2 || [[#QueryAvailableInterfaces]] ([1.0.0] [[#QueryAcquiredInterfaces]]) | ||
|- | |- | ||
| 3 || [[#QueryAcquiredInterfaces]] | | 3 || [[#QueryAcquiredInterfaces]] ([1.0.0] [[#CreateInterfaceAvailableEvent]]) | ||
|- | |- | ||
| 4 || [[#CreateInterfaceAvailableEvent]] | | 4 || [[#CreateInterfaceAvailableEvent]] ([1.0.0] [[#DestroyInterfaceAvailableEvent]]) | ||
|- | |- | ||
| 5 || [[#DestroyInterfaceAvailableEvent]] | | 5 || [[#DestroyInterfaceAvailableEvent]] ([1.0.0] [[#GetInterfaceStateChangeEvent]]) | ||
|- | |- | ||
| 6 || [[#GetInterfaceStateChangeEvent]] | | 6 || [[#GetInterfaceStateChangeEvent]] ([1.0.0] [[#AcquireUsbIf]]) | ||
|- | |- | ||
| 7 || [[#AcquireUsbIf]] | | 7 || [[#AcquireUsbIf]] ([1.0.0] [[#GetDescriptorString]]) | ||
|- | |- | ||
| 8 || [6.0.0+] | | 8 || [6.0.0+] SetTestMode ([1.0.0] [[#ResetDevice]]) | ||
|} | |} | ||
General USB devices usage, used by [[ | General USB devices usage, used by [[HID_services|hid]], [[Sockets_services|bsdsockets]], and [5.1.0+] [[Audio_services|audio]]. | ||
Get-service-handle will fail if the current process is already using usb:ds, however it's successful if it's done separately from the process using usb:ds. | |||
== BindClientProcess == | == BindClientProcess == | ||
Line 404: | Line 341: | ||
== QueryAllInterfaces == | == QueryAllInterfaces == | ||
Takes | Takes an [[#DeviceFilter]] and a type-0x6 output buffer, returns an output s32 total_entries. | ||
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 | Takes an [[#DeviceFilter]] and a type-0x6 output buffer, returns an output s32 total_entries. | ||
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 | Takes a type-0x6 output buffer and returns an output s32 total_entries. | ||
The output buffer contains an array of [[#InterfaceQueryOutput]], for each interface which was acquired with [[#AcquireUsbIf]]. | |||
== CreateInterfaceAvailableEvent == | == CreateInterfaceAvailableEvent == | ||
Takes an input u8 and returns an output handle. | 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. | |||
When signaled, this indicates that the user-process should use [[#QueryAvailableInterfaces]] and [[#AcquireUsbIf]] with the output interfaces (and the rest of interface setup). | |||
== DestroyInterfaceAvailableEvent == | == DestroyInterfaceAvailableEvent == | ||
Takes an input u8, no output. | Takes an input u8, no output. The input value must be 0..2. | ||
Clears state associated with the input index. This is the same state setup by [[#CreateInterfaceAvailableEvent]]. | |||
== GetInterfaceStateChangeEvent == | == GetInterfaceStateChangeEvent == | ||
No input, returns an output handle. | 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 [[#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]]. | 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 an [[#InterfaceProfile]]. | |||
This returns an error if the interface was already acquired by another process. | |||
== GetDescriptorString == | |||
Takes a type-0x6 output buffer, an input u8, an input u8 bool, and an u32. Returns an output u32. | |||
The u32 is located at +4 from the first u8 in the IPC rawdata. | |||
Gets a string from a string descriptor. | |||
The UTF-16 string from descriptor+2 is copied to descriptor/outbuf +0, where each character is transferred using u8 not u16. | |||
Official sw doesn't use this, [[#SubmitControlInRequest]] is used instead. | |||
== ResetDevice == | |||
Takes an input u32, no output. Stubbed, just returns 0. | |||
== IClientIfSession == | == IClientIfSession == | ||
Line 429: | Line 398: | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
! Cmd || Name | ! Cmd || Name | ||
|- | |- | ||
| 0 || | | 0 || [[#GetStateChangeEvent]] | ||
|- | |- | ||
| 1 || [[#SetInterface]] | | 1 || [[#SetInterface]] | ||
|- | |- | ||
| 2 || [[#GetInterface]] | | 2 || [[#GetInterface]] | ||
|- | |- | ||
| 3 || [[#GetAlternateInterface]] | | 3 || [[#GetAlternateInterface]] | ||
|- | |- | ||
| 4 || [[#GetCurrentFrame]] | | 4 || [[#GetCurrentFrame]] ([1.0.0] [[#CtrlXferAsync]]) | ||
|- | |- | ||
| 5 || [[#CtrlXferAsync]] | | 5 || [2.0.0+] [[#CtrlXferAsync]] | ||
|- | |- | ||
| 6 || | | 6 || [[#GetCtrlXferCompletionEvent]] ([1.0.0] [[#SubmitControlInRequest]]) | ||
|- | |- | ||
| 7 || [[#GetCtrlXferReport]] | | 7 || [[#GetCtrlXferReport]] ([1.0.0] [[#SubmitControlOutRequest]]) | ||
|- | |- | ||
| 8 || [[#ResetDevice]] | | 8 || [[#ResetDevice]] | ||
|- | |- | ||
| 9 || [[#OpenUsbEp]] | | 9 || [[#OpenUsbEp]] ([1.0.0] [[#GetCurrentFrame]]) | ||
|} | |} | ||
Official sw uses autoclear=false for the above events. | |||
Immediately after opening the session, official sw uses cmd0 and cmd6. | |||
=== GetStateChangeEvent === | |||
No input, returns an output handle. | |||
=== SetInterface === | === SetInterface === | ||
Takes an input u8 and a type-0x6 output buffer, no output. | 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. | 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. | 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 === | ||
No input, returns an output u32. | No input, returns an output u32. | ||
On 1.0.0 this stubbed: this returns 0 with output u32 = hard-coded 0. | |||
=== CtrlXferAsync === | === CtrlXferAsync === | ||
Takes 2 input u8s and 3 input u16s, no output. | Takes 2 input u8s ('''bmRequestType''' and '''bRequest'''), 3 input u16s ('''wValue''', '''wIndex''', and '''wLength'''), and an input u64 '''buffer''', no output. | ||
=== GetCtrlXferCompletionEvent === | |||
No input, returns an output handle. Signaled when [[#CtrlXferAsync]] finishes. | |||
=== GetCtrlXferReport === | === GetCtrlXferReport === | ||
Takes a type-0x6 output buffer, no output. | 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 === | ||
Takes an input u16 and 4 input u32s, returns a 0x7-byte output struct and an [[#IClientEpSession]]. | Takes an input u16 and 4 input u32s, returns a 0x7-byte output struct and an [[#IClientEpSession]]. | ||
The u16 is '''maxUrbCount'''. The u32s are: '''epType''', '''epNumber''', '''epDirection''', and '''maxXferSize'''. | |||
The user-process loads the input params from the endpoint descriptor. HID-sysmodule sets '''maxXferSize''' to wMaxPacketSize from the endpoint descriptor. However, other sysmodules pass hard-coded values for '''maxXferSize'''. | |||
HID-sysmodule passes hard-coded value 0x1 for '''maxUrbCount''', for bsd-sysmodule this is 0x2. For audio-sysmodule, this is 0x3 or 0x6. | |||
'''epType''' is <code>libusb_transfer_type+1</code>. '''epNumber''' is <code>bEndpointAddress & LIBUSB_ENDPOINT_ADDRESS_MASK</code>. '''epDirection''' is 0x1 for LIBUSB_ENDPOINT_OUT, and 0x2 for LIBUSB_ENDPOINT_IN. | |||
'''epType''', '''epNumber''', and '''epDirection''' must all match USB-sysmodule state for the associated endpoint. '''maxUrbCount''' must be <0x11. '''maxXferSize''' must be <=0xFF0000. <code>maxUrbCount*maxXferSize</code> must be non-zero. | |||
=== IClientEpSession === | === IClientEpSession === | ||
Line 481: | Line 484: | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
! Cmd || Name | ! Cmd || Name | ||
|- | |- | ||
| 0 || [[# | | 0 || [[#ReOpen]] ([1.0.0] [[#SubmitOutRequest]]) | ||
|- | |- | ||
| 1 || [[#Close]] | | 1 || [[#Close]] ([1.0.0] [[#SubmitInRequest]]) | ||
|- | |- | ||
| 2 || | | | 2 || [[#GetCompletionEvent_2|GetCompletionEvent]] ([1.0.0] Reset) | ||
|- | |- | ||
| 3 || [[# | | 3 || [[#PopulateRing]] ([1.0.0] [[#Close]]) | ||
|- | |- | ||
| 4 || [[#PostBufferAsync_2|#PostBufferAsync]] | | 4 || [2.0.0+] [[#PostBufferAsync_2|#PostBufferAsync]] | ||
|- | |- | ||
| 5 || [[#GetXferReport]] | | 5 || [2.0.0+] [[#GetXferReport]] | ||
|- | |- | ||
| 6 || | | 6 || [2.0.0+] [[#BatchBufferAsync]] | ||
|- | |- | ||
| 7 || [4.0.0+] | | 7 || [4.0.0+] [[#CreateSmmuSpace]] | ||
|- | |- | ||
| 8 || [4.0.0+] | | 8 || [4.0.0+] [[#ShareReportRing]] | ||
|} | |} | ||
==== | Official sw uses autoclear=false for the above event. | ||
Immediately after opening the endpoint session, official sw uses [[#Populate]] and cmd2. | |||
==== SubmitOutRequest ==== | |||
Takes an type-0x5 input buffer, an u32 '''size''', and an u32 '''unk'''. Returns an output u32 for the actual transferred size. | |||
Official user-processes uses a buffer where the buffer address/size is page-aligned, where '''size''' is the original size before alignment. The user-process also flushes dcache for this buffer using '''size''', before using this command. Official sw passes value 0 for '''unk'''. | |||
==== SubmitInRequest ==== | |||
Takes an type-0x6 output buffer, an u32 '''size''', and an u32 '''unk'''. Returns an output u32 for the actual transferred size. | |||
Official user-processes uses a buffer where the buffer address/size is page-aligned, where '''size''' is the original size before alignment. The user-process also flushes dcache for this buffer using '''size''', before/after using this command. Official sw passes value 0 for '''unk'''. | |||
==== ReOpen ==== | |||
No input/output. | No input/output. | ||
This is similar to [[#OpenUsbEp]] with the params being loaded from state instead. | |||
This is for re-opening after [[#Close]] was used. | |||
==== Close ==== | ==== Close ==== | ||
No input/output. | No input/output. | ||
==== | Used by official sw prior to closing the endpoint session. The func for this is also called automatically by the sysmodule during the IClientEpSession dtor. | ||
==== GetCompletionEvent ==== | |||
No input, returns an output handle. Signaled when [[#PostBufferAsync_2|#PostBufferAsync]] finishes. ([1.0.0] [[#Open]]) | |||
==== PopulateRing ==== | |||
No input/output. | No input/output. | ||
Used after opening the endpoint session (see above). | |||
==== PostBufferAsync ==== | ==== PostBufferAsync ==== | ||
Takes an input u32 and | Takes an input u32 '''size''', an input u64 '''buffer''', and an input u64 '''Id''', returns an output u32 '''xferId'''. | ||
Starts a data transfer with a single urb. | |||
The official sw func which uses this cmd and handles waiting on the Event passes value 0 for the '''Id'''. The async version which exposes this cmd directly uses '''Id''' from user input - the user funcs pass a value starting at 0 then increment it each time (for sending multiple requests at once, with 0 for the first request in this set of requests). Note that '''Id''' can be arbitrary, the sysmodule doesn't require a certain range for this. | |||
On newer sysvers the state fields setup by [[#CreateSmmuSpace]] are compared with '''buffer'''. If it's within bounds of the SmmuSpace (which won't be the case when [[#CreateSmmuSpace]] wasn't used), it will then verify that buffer+buffer_size is within bounds throwing an error otherwise. Note that a buffer from [[#CreateSmmuSpace]] can't be reused by another endpoint with PostBufferAsync. | |||
==== GetXferReport ==== | ==== GetXferReport ==== | ||
Takes an input u32 and a type-0x6 output buffer, returns an output u32. | 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 buffer contains an array of [[#XferReport]]. | |||
On newer sysvers this runs code which is the same as the user-process code handling the tmem from [[#ShareReportRing]]. This cmd can handle getting reports from that tmem as well, however normally user-processes would just access the tmem [[#ShareReportRing|directly]]. | |||
==== BatchBufferAsync ==== | |||
Takes 3 input u32s ('''urbCount''', '''unk1''', and '''unk2'''), an input u64 '''buffer''' and u64 '''Id''', and a type-0x5 ([3.0.0+] type-0x21) input buffer, returns an output u32 '''xferId'''. | |||
Where '''Id''' 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'''. | |||
==== CreateSmmuSpace ==== | |||
Takes an input u32 '''size''' and an u64 '''buffer''', no output. | |||
This validates that both input params are page-aligned. Official user-processes also validate this. | |||
This maps the specified buffer as devicemem and stores the fields for this in object state. If this was already used with this IClientEpSession object, an error is thrown. | |||
==== ShareReportRing ==== | |||
Takes an input u32 '''size''' and an input TransferMemory handle, no output. | |||
Official user-processes create the TransferMemory with permissions=RW. This validates that the input size is page-aligned, and this is also validated against data from state. Official user-processes also do this same validation. | |||
When this was used, official user-processes read data from this TransferMemory buffer instead of using [[#GetXferReport]]. | |||
This maps a TransferMemory buffer which is used for the [[#XferReport]] Ring, replacing the heap Ring buffer which was setup during [[#PopulateRing]]. | |||
Structure of the tmem: | |||
{| class="wikitable" border="1" | |||
|- | |||
! Offset || Size || Description | |||
|- | |||
| 0x0 || 0x8 || Write index | |||
|- | |||
| 0x8 || 0x8 || Read index | |||
|- | |||
| 0x10 || 0x18*count || Array of [[#XferReport]] | |||
|} | |||
write_index!=read_index indicates that report data is available. The index fields are updated with: <code>index = index+1 % count;</code> write_index is updated by sysmodule, read_index is updated by the user-process. If the index field being used is >=count, this will Abort. | |||
= usb:pd = | = usb:pd = | ||
Line 524: | Line 602: | ||
! Cmd || Name | ! Cmd || Name | ||
|- | |- | ||
| 0 || | | 0 || [[#OpenSession]] | ||
|} | |} | ||
Only system-titles with access to this are [[PTM_services|ptm]] and [[AM_services|am]]. | Only system-titles with access to this are [[PTM_services|ptm]] and [[AM_services|am]]. | ||
== OpenSession == | |||
No input. Returns an [[#IPdSession]]. | |||
== IPdSession == | == IPdSession == | ||
Line 538: | Line 619: | ||
| 0 || BindNoticeEvent | | 0 || BindNoticeEvent | ||
|- | |- | ||
| 1 || | | 1 || UnbindNoticeEvent | ||
|- | |- | ||
| 2 || GetStatus | | 2 || GetStatus | ||
Line 544: | Line 625: | ||
| 3 || GetNotice | | 3 || GetNotice | ||
|- | |- | ||
| 4 || | | 4 || EnablePowerRequestNotice | ||
|- | |- | ||
| 5 || | | 5 || DisablePowerRequestNotice | ||
|- | |- | ||
| 6 || ReplyPowerRequest | | 6 || ReplyPowerRequest | ||
Line 556: | Line 637: | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
! Cmd || Name | ! Cmd || Name | ||
|- | |- | ||
| 0 || | | 0 || [[#OpenCradleSession]] | ||
|} | |} | ||
USB-sysmodule symbols for this refer to "Cradle", which is the [[Dock]]. | USB-sysmodule symbols for this refer to "Cradle", which is the [[Dock]]. | ||
== OpenCradleSession == | |||
No input. Returns an [[#IPdCradleSession]]. | |||
== IPdCradleSession == | == IPdCradleSession == | ||
Line 568: | Line 652: | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
! Cmd || Name || | ! Cmd || Name | ||
|- | |||
| 0 || [[#SetCradleVdo]] | |||
|- | |||
| 1 || [[#GetCradleVdo]] | |||
|- | |- | ||
| | | 2 || [[#ResetCradleUsbHub]] | ||
|- | |- | ||
| | | 3 || [2.0.0+] [[#GetHostPdcFirmwareType]] | ||
|- | |- | ||
| | | 4 || [2.0.0+] [[#GetHostPdcFirmwareRevision]] | ||
|- | |- | ||
| | | 5 || [2.0.0+] [[#GetHostPdcManufactureId]] | ||
|- | |- | ||
| | | 6 || [2.0.0+] [[#GetHostPdcDeviceId]] | ||
|- | |- | ||
| | | 7 || [3.0.0+] [[#EnableCradleRecovery]] | ||
|- | |- | ||
| | | 8 || [3.0.0+] [[#DisableCradleRecovery]] | ||
|} | |||
=== SetCradleVdo === | |||
Takes an input u32 '''Value''' and a [[#CradleVdmCommand]]. No output. | |||
[[#CradleVdmCommand]] is translated to the actual [[#VdmCommand]] to send. | |||
=== GetCradleVdo === | |||
Takes an input [[#CradleVdmCommand]]. Returns an u32 '''Value'''. | |||
[[#CradleVdmCommand]] is translated to the actual [[#VdmCommand]] to send. | |||
=== ResetCradleUsbHub === | |||
No input/output. | |||
Sends [[#VdmCommand|VdmCommands]] 32 and 30. | |||
=== GetHostPdcFirmwareType === | |||
No input. Returns an output u16. | |||
=== GetHostPdcFirmwareRevision === | |||
No input. Returns an output u16. | |||
=== GetHostPdcManufactureId === | |||
No input. Returns an output u16. | |||
=== GetHostPdcDeviceId === | |||
No input. Returns an output u16. | |||
=== EnableCradleRecovery === | |||
No input. Returns an output u8. | |||
=== DisableCradleRecovery === | |||
No input. Returns an output u8. | |||
= usb:pd:m = | |||
This is "nn::usb::pd::detail::IPdManufactureManager". | |||
[2.0.0+] This service was merged into [[#usb:pd:c|usb:pd:c]]. | |||
{| class="wikitable" border="1" | |||
|- | |- | ||
! Cmd || Name | |||
|- | |- | ||
| | | 0 || [[#OpenManufactureSession]] | ||
|} | |} | ||
== OpenManufactureSession == | |||
No input. Returns an [[#IPdManufactureSession]]. | |||
== IPdManufactureSession == | |||
This is "nn::usb::pd::detail::IPdManufactureSession". | |||
{| class="wikitable" border="1" | |||
|- | |||
! Cmd || Name | |||
|- | |||
| 0 || [[#GetHostPdcFirmwareType]] | |||
|- | |||
| 1 || [[#GetHostPdcFirmwareRevision]] | |||
|- | |||
| 2 || [[#GetHostPdcManufactureId]] | |||
|- | |||
| 3 || [[#GetHostPdcDeviceId]] | |||
|} | |||
= usb:pm = | = usb:pm = | ||
This is "nn::usb::pm::IPmService". | This is "nn::usb::pm::IPmService". | ||
[8.0.0+] This is "nn::usb::pm::IPmMainService". | |||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
Line 601: | Line 746: | ||
! Cmd || Name | ! Cmd || Name | ||
|- | |- | ||
| 0 || | | 0 || [[#GetPowerEvent|GetPowerEvent]] | ||
|- | |- | ||
| 1 || | | 1 || [[#GetPowerState|GetPowerState]] | ||
|- | |- | ||
| 2 || | | 2 || [[#GetDataEvent|GetDataEvent]] | ||
|- | |- | ||
| 3 || | | 3 || [[#GetDataRole|GetDataRole]] | ||
|- | |- | ||
| 4 || | | 4 || [[#SetDiagData|SetDiagData]] | ||
|- | |- | ||
| 5 || | | 5 || [[#GetDiagData|GetDiagData]] | ||
|} | |} | ||
USB Port Manager, only system-title using this is [[PTM_services|ptm]]. | USB Port Manager, only system-title using this is [[PTM_services|ptm]]. | ||
== GetPowerEvent == | |||
No input. Returns an output Event handle. | |||
== GetPowerState == | |||
Takes a type-0x6 output buffer containing an [[#UsbPowerState]]. No output. | |||
== GetDataEvent == | |||
No input. Returns an output Event handle. | |||
== GetDataRole == | |||
No input. Returns an output [[#UsbDataRole]]. | |||
== SetDiagData == | |||
Takes two input u32s. No output. | |||
[8.0.0+] Stubbed, just returns 0. | |||
== GetDiagData == | |||
Takes an input u32. Returns an output u32. | |||
[8.0.0+] Stubbed, just returns 0. | |||
= usb:qdb = | |||
This is "nn::usb::qdb::IQdbManager". | |||
This was added with [7.0.0+]. | |||
{| class="wikitable" border="1" | |||
|- | |||
! Cmd || Name | |||
|- | |||
| 0 || [[#ImportQuirkDevices]] | |||
|- | |||
| 1 || [[#HasQuirk]] | |||
|} | |||
== ImportQuirkDevices == | |||
No input/output, takes a type-0x5 input buffer. | |||
This loads data for [[#HidGamepad]] with the input .json. | |||
== HasQuirk == | |||
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 = | |||
This is "nn::usb::pm::IPmObserverService". | |||
This was added with [8.0.0+]. | |||
{| class="wikitable" border="1" | |||
|- | |||
! Cmd || Name | |||
|- | |||
| 0 || GetTopologyChangeEvent | |||
|- | |||
| 1 || GetFlattenedTopology | |||
|} | |||
= UsbInterfaceDescriptor = | |||
This is "nn::usb::UsbInterfaceDescriptor". | |||
{| class="wikitable" border="1" | |||
|- | |||
! Offset || Size || Description | |||
|- | |||
| 0x0 || 0x1 || bLength | |||
|- | |||
| 0x1 || 0x1 || bDescriptorType | |||
|- | |||
| 0x2 || 0x1 || bInterfaceNumber | |||
|- | |||
| 0x3 || 0x1 || bAlternateSetting | |||
|- | |||
| 0x4 || 0x1 || bNumEndpoints | |||
|- | |||
| 0x5 || 0x1 || bInterfaceClass | |||
|- | |||
| 0x6 || 0x1 || bInterfaceSubClass | |||
|- | |||
| 0x7 || 0x1 || bInterfaceProtocol | |||
|- | |||
| 0x8 || 0x1 || iInterface | |||
|} | |||
= UsbStringDescriptor = | |||
This is "nn::usb::UsbStringDescriptor". This is a string. | |||
= UsbEndpointDescriptor = | |||
This is "nn::usb::UsbEndpointDescriptor". | |||
{| class="wikitable" border="1" | |||
|- | |||
! Offset || Size || Description | |||
|- | |||
| 0x0 || 0x1 || bLength | |||
|- | |||
| 0x1 || 0x1 || bDescriptorType | |||
|- | |||
| 0x2 || 0x1 || bEndpointAddress | |||
|- | |||
| 0x3 || 0x1 || bmAttributes | |||
|- | |||
| 0x4 || 0x2 || wMaxPacketSize | |||
|- | |||
| 0x6 || 0x1 || bInterval | |||
|- | |||
| 0x7 || 0x1 || bRefresh | |||
|- | |||
| 0x8 || 0x1 || bSynchAddress | |||
|} | |||
= UsbState = | |||
{| class="wikitable" border="1" | |||
|- | |||
! Value || Name || Description | |||
|- | |||
| 0 || Detached || Device is not attached to USB. | |||
|- | |||
| 1 || Attached || Device is attached, but is not powered. | |||
|- | |||
| 2 || Powered || Device is attached and powered, but has not been reset. | |||
|- | |||
| 3 || Default || Device is attached, powered, and has been reset, but does not have an address. | |||
|- | |||
| 4 || Address || Device is attached, powered, has been reset, has an address, but is not configured. | |||
|- | |||
| 5 || Configured || Device is attached, powered, has been reset, has an address, configured, and may be used. | |||
|- | |||
| 6 || Suspended || Device is attached and powered, but has not seen bus activity for 3ms. Device is suspended and cannot be used. | |||
|} | |||
= UsbVidPidBcd = | |||
{| class="wikitable" border="1" | |||
|- | |||
! Offset || Size || Description | |||
|- | |||
| 0x0 || 0x2 || Vid (idVendor) | |||
|- | |||
| 0x2 || 0x2 || Pid (idProduct) | |||
|- | |||
| 0x4 || 0x2 || bcdDevice | |||
|- | |||
| 0x6 || 0x20 || Manufacturer (ASCII string padded to 0x20 bytes) | |||
|- | |||
| 0x26 || 0x20 || Product (ASCII string padded to 0x20 bytes) | |||
|- | |||
| 0x46 || 0x20 || SerialNumber (ASCII string padded to 0x20 bytes) | |||
|} | |||
= UrbReport = | |||
{| class="wikitable" border="1" | |||
|- | |||
! Offset || Size || Description | |||
|- | |||
| 0x0 || 0x10 * 8 || Array of [[#UrbReportEntry]] | |||
|- | |||
| 0x80 || 0x4 || ReportEntryCount | |||
|} | |||
= UrbReportEntry = | |||
{| class="wikitable" border="1" | |||
|- | |||
! Offset || Size || Description | |||
|- | |||
| 0x0 || 0x4 || Id | |||
|- | |||
| 0x4 || 0x4 || RequestedSize | |||
|- | |||
| 0x8 || 0x4 || TransferredSize | |||
|- | |||
| 0xC || 0x4 || Status (converted to error-codes: 0x3 = success, 0x4 = 0x828c, 0x5 = 0x748c; all other values are invalid) | |||
|} | |||
= UsbDeviceSpeed = | |||
{| class="wikitable" border="1" | |||
|- | |||
! Value || Name | |||
|- | |||
| 0 || None | |||
|- | |||
| 1 || Low | |||
|- | |||
| 2 || Full | |||
|- | |||
| 3 || High | |||
|- | |||
| 4 || Super | |||
|} | |||
= 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" | |||
|- | |||
! Offset || Size || Description | |||
|- | |||
| 0x0 || 0x4 || ID value passed to other cmds. This is -1 with [[#QueryAllInterfaces]] output, hence this field is unused with that cmd. | |||
|- | |||
| 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. | |||
|- | |||
| 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 | |||
|} | |||
= DeviceFilter = | |||
This is "nn::usb::DeviceFilter". | |||
{| 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 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). | |||
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 = | |||
{| class="wikitable" border="1" | |||
|- | |||
! Offset || Size || Description | |||
|- | |||
| 0x0 || 0x4 || xferId (Only set for [[#GetXferReport]]) | |||
|- | |||
| 0x4 || 0x4 || Result | |||
|- | |||
| 0x8 || 0x4 || requestedSize | |||
|- | |||
| 0xC || 0x4 || transferredSize | |||
|- | |||
| 0x10 || 0x8 || [[#PostBufferAsync_2|Id]] | |||
|} | |||
This is a 0x18-byte struct. | |||
Official sw only uses the Result/size fields. | |||
= CradleVdmCommand = | |||
This is "nn::usb::pd::CradleVdmCommand". | |||
{| class="wikitable" border="1" | |||
|- | |||
! Value || Name | |||
|- | |||
| 0 || | |||
|- | |||
| 1 || | |||
|- | |||
| 2 || | |||
|- | |||
| 3 || | |||
|- | |||
| 4 || | |||
|- | |||
| 5 || | |||
|- | |||
| 6 || | |||
|- | |||
| 7 || | |||
|- | |||
| 8 || | |||
|- | |||
| 9 || | |||
|- | |||
| 10 || | |||
|} | |||
= VdmCommand = | |||
This is "nn::usb::pd::driver::detail::VdmCommand". | |||
{| class="wikitable" border="1" | |||
|- | |||
! Value || [[#CradleVdmCommand|CradleVdmCommand]] || [[#VdmCommandType|VdmCommandType]] || VdmCommandLength || Name | |||
|- | |||
| 0 || - || -1 || 0 || None | |||
|- | |||
| 1 || 0 || 0 || 3 || LedControlRequest | |||
|- | |||
| 2 || - || 1 || 3 || LedControlReply | |||
|- | |||
| 3 || 10 || 0 || 3 || DeviceTypeRequest | |||
|- | |||
| 4 || - || 1 || 3 || DeviceTypeReply | |||
|- | |||
| 5 || - || -1 || 0 || UsbPowerErrorNotice | |||
|- | |||
| 6 || 1 || 0 || 2 || Dp2HdmiFwVerRequest | |||
|- | |||
| 7 || - || 1 || 3 || Dp2HdmiFwVerReply | |||
|- | |||
| 8 || - || -1 || 0 || Dp2HdmiFwUpdateRequest | |||
|- | |||
| 9 || - || -1 || 0 || Dp2HdmiFwUpdateReply | |||
|- | |||
| 10 || - || -1 || 0 || Dp2HdmiFwUpdateNotice | |||
|- | |||
| 11 || 2 || 0 || 2 || PdcHFwVerRequest | |||
|- | |||
| 12 || - || 1 || 3 || PdcHFwVerReply | |||
|- | |||
| 13 || - || -1 || 0 || PdcHFwUpdateRequest | |||
|- | |||
| 14 || - || -1 || 0 || PdcHFwUpdateReply | |||
|- | |||
| 15 || - || -1 || 0 || PdcHFwUpdateNotice | |||
|- | |||
| 16 || 3 || 0 || 2 || PdcAFwVerRequest | |||
|- | |||
| 17 || - || 1 || 3 || PdcAFwVerReply | |||
|- | |||
| 18 || - || -1 || 0 || PdcAFwUpdateRequest | |||
|- | |||
| 19 || - || -1 || 0 || PdcAFwUpdateReply | |||
|- | |||
| 20 || - || -1 || 0 || PdcAFwUpdateNotice | |||
|- | |||
| 21 || - || 0 || 3 || DeviceErrorNotice | |||
|- | |||
| 22 || 4 || 0 || 2 || DeviceStateRequest | |||
|- | |||
| 23 || - || 1 || 3 || DeviceStateReply | |||
|- | |||
| 24 || 5 || 0 || 2 || McuFwVerRequest | |||
|- | |||
| 25 || - || 1 || 3 || McuFwVerReply | |||
|- | |||
| 26 || 6 || 0 || 2 || McuFwUpdateRequest | |||
|- | |||
| 27 || - || 1 || 2 || McuFwUpdateReply | |||
|- | |||
| 28 || 7 || 0 || 2 || UsbHubSleepRequest | |||
|- | |||
| 29 || - || 1 || 2 || UsbHubSleepReply | |||
|- | |||
| 30 || 8 || 0 || 2 || UsbHubResetRequest | |||
|- | |||
| 31 || - || 1 || 2 || UsbHubResetReply | |||
|- | |||
| 32 || 9 || 0 || 2 || UsbHubControlRequest | |||
|- | |||
| 33 || - || 1 || 2 || UsbHubControlReply | |||
|} | |||
= VdmCommandType = | |||
This is "nn::usb::pd::driver::detail::VdmCommandType". | |||
{| class="wikitable" border="1" | |||
|- | |||
! Value || Name | |||
|- | |||
| -1 || None | |||
|- | |||
| 0 || Initiator | |||
|- | |||
| 1 || Ack | |||
|- | |||
| 2 || Nak | |||
|- | |||
| 3 || Busy | |||
|} | |||
= UsbPowerState = | |||
This is "nn::usb::UsbPowerState". | |||
{| class="wikitable" border="1" | |||
|- | |||
! Offset || Size || Description | |||
|- | |||
| 0x0 || 0x4 || [[#UsbPowerRole|UsbPowerRole]] | |||
|- | |||
| 0x4 || 0x4 || [[#UsbChargerType|UsbChargerType]] | |||
|- | |||
| 0x8 || 0x4 || Voltage | |||
|- | |||
| 0xC || 0x4 || Current | |||
|- | |||
| 0x10 || 0x4 || [[#Pdo|Pdo]] | |||
|- | |||
| 0x14 || 0x4 || [[#Rdo|Rdo]] | |||
|} | |||
= UsbPowerRole = | |||
This is "nn::usb::UsbPowerRole". | |||
{| class="wikitable" border="1" | |||
|- | |||
! Value || Name | |||
|- | |||
| 0 || Unknown | |||
|- | |||
| 1 || Sink | |||
|- | |||
| 2 || Source | |||
|} | |||
= UsbChargerType = | |||
This is "nn::usb::UsbChargerType". | |||
{| class="wikitable" border="1" | |||
|- | |||
! Value || Name | |||
|- | |||
| 0 || Unknown | |||
|- | |||
| 1 || Pd | |||
|- | |||
| 2 || TypeC15 | |||
|- | |||
| 3 || TypeC30 | |||
|- | |||
| 4 || Dcp | |||
|- | |||
| 5 || Cdp | |||
|- | |||
| 6 || Sdp | |||
|- | |||
| 7 || Apple500 | |||
|- | |||
| 8 || Apple1000 | |||
|- | |||
| 9 || Apple2000 | |||
|} | |||
= SupplyType = | |||
{| class="wikitable" border="1" | |||
|- | |||
! Value || Name | |||
|- | |||
| 0 || Fixed | |||
|- | |||
| 1 || Battery | |||
|- | |||
| 2 || Variable | |||
|} | |||
= Pdo = | |||
When [[#SupplyType|SupplyType]] is Fixed this is: | |||
{| class="wikitable" border="1" | |||
! Bits | |||
! Description | |||
|- | |||
| 0-9 | |||
| MaximumCurrent | |||
|- | |||
| 10-19 | |||
| Voltage | |||
|- | |||
| 20-21 | |||
| PeakCurrent | |||
|- | |||
| 22-24 | |||
| Reserved | |||
|- | |||
| 25 | |||
| DataRoleSwap | |||
|- | |||
| 26 | |||
| UsbCommunicationsCapable | |||
|- | |||
| 27 | |||
| ExternallyPowered | |||
|- | |||
| 28 | |||
| UsbSuspendSupported | |||
|- | |||
| 29 | |||
| DualRolePower | |||
|- | |||
| 30-31 | |||
| [[#SupplyType|SupplyType]] | |||
|} | |||
When [[#SupplyType|SupplyType]] is Battery this is: | |||
{| class="wikitable" border="1" | |||
! Bits | |||
! Description | |||
|- | |||
| 0-9 | |||
| MaximumAllowablePower | |||
|- | |||
| 10-19 | |||
| MinimumVoltage | |||
|- | |||
| 20-29 | |||
| MaximumVoltage | |||
|- | |||
| 30-31 | |||
| [[#SupplyType|SupplyType]] | |||
|} | |||
When [[#SupplyType|SupplyType]] is Variable this is: | |||
{| class="wikitable" border="1" | |||
! Bits | |||
! Description | |||
|- | |||
| 0-9 | |||
| MaximumCurrent | |||
|- | |||
| 10-19 | |||
| MinimumVoltage | |||
|- | |||
| 20-29 | |||
| MaximumVoltage | |||
|- | |||
| 30-31 | |||
| [[#SupplyType|SupplyType]] | |||
|} | |||
= Rdo = | |||
When Pdo's [[#SupplyType|SupplyType]] is Fixed or Variable this is: | |||
{| class="wikitable" border="1" | |||
! Bits | |||
! Description | |||
|- | |||
| 0-9 | |||
| MaximumOperatingCurrent (GiveBackFlag is true) or MinimumOperatingCurrent (GiveBackFlag is false) | |||
|- | |||
| 10-19 | |||
| OperatingCurrent | |||
|- | |||
| 20-23 | |||
| Reserved | |||
|- | |||
| 24 | |||
| NoUsbSuspend | |||
|- | |||
| 25 | |||
| UsbCommunicationsCapable | |||
|- | |||
| 26 | |||
| CapabilityMismatch | |||
|- | |||
| 27 | |||
| GiveBackFlag | |||
|- | |||
| 28-30 | |||
| ObjectPosition | |||
|- | |||
| 31 | |||
| Reserved | |||
|} | |||
When Pdo's [[#SupplyType|SupplyType]] is Battery this is: | |||
{| class="wikitable" border="1" | |||
! Bits | |||
! Description | |||
|- | |||
| 0-9 | |||
| MaximumOperatingPower (GiveBackFlag is true) or MinimumOperatingPower (GiveBackFlag is false) | |||
|- | |||
| 10-19 | |||
| OperatingPower | |||
|- | |||
| 20-23 | |||
| Reserved | |||
|- | |||
| 24 | |||
| NoUsbSuspend | |||
|- | |||
| 25 | |||
| UsbCommunicationsCapable | |||
|- | |||
| 26 | |||
| CapabilityMismatch | |||
|- | |||
| 27 | |||
| GiveBackFlag | |||
|- | |||
| 28-30 | |||
| ObjectPosition | |||
|- | |||
| 31 | |||
| Reserved | |||
|} | |||
= UsbDataRole = | |||
This is "nn::usb::UsbDataRole". | |||
{| class="wikitable" border="1" | |||
|- | |||
! Value || Name | |||
|- | |||
| 0 || Unknown | |||
|- | |||
| 1 || DFP | |||
|- | |||
| 2 || UFP | |||
|} | |||
= 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> | |||
] | |||
[12.1.0+]: The following entries were added in this json, all of which have quirks set for "HidGamepadWhitelist". | |||
** vid "0F0D", where pid is "0200" - "022F". | |||
** vid "33DD", where pid is "0001" - "000B". | |||
= Configuration = | |||
The following is the default USB config strings, while the usbds service isn't being used. All of the below configuration will reset to the defaults when all usbds-related sessions are closed. These can be set with [[#SetVidPidBcd]]. The default string for Product is loaded from [[Settings_services|settings]] config. The default is referred to by usb-sysmodule as "Dummy". | |||
Product: Nintendo Switch | |||
Manufacturer: Nintendo | |||
SerialNumber: SerialNumber | |||
The following is the default <code>lsusb -v {...}</code> output when the usbds service wasn't used. | |||
pre-5.0.0: The endpoints are configured using [[#RegisterEndpoint]], the total number of endpoints is the number of open [[#IDsEndpoint]] sessions. bInterfaceNumber is {0-based index for the enabled [[#IDsInterface]] session.} Some of the interface fields are configured using [[#RegisterInterface]]. | |||
When usbds is in use where [[#SetVidPidBcd]] wasn't used, the VID/PID is 057e:3000. | |||
Bus 003 Device 006: ID 057e:2000 Nintendo Co., Ltd | |||
Couldn't open device, some information will be missing | |||
Device Descriptor: | |||
bLength 18 | |||
bDescriptorType 1 | |||
bcdUSB 2.00 | |||
bDeviceClass 0 (Defined at Interface level) | |||
bDeviceSubClass 0 | |||
bDeviceProtocol 0 | |||
bMaxPacketSize0 64 | |||
idVendor 0x057e Nintendo Co., Ltd | |||
idProduct 0x2000 | |||
bcdDevice 1.00 | |||
iManufacturer 1 | |||
iProduct 2 | |||
iSerial 3 | |||
bNumConfigurations 1 | |||
Configuration Descriptor: | |||
bLength 9 | |||
bDescriptorType 2 | |||
wTotalLength 34 | |||
bNumInterfaces 1 | |||
bConfigurationValue 1 | |||
iConfiguration 0 | |||
bmAttributes 0xc0 | |||
Self Powered | |||
MaxPower {...} | |||
Interface Descriptor: | |||
bLength 9 | |||
bDescriptorType 4 | |||
bInterfaceNumber 0 | |||
bAlternateSetting 0 | |||
bNumEndpoints 1 | |||
bInterfaceClass 3 Human Interface Device | |||
bInterfaceSubClass 0 No Subclass | |||
bInterfaceProtocol 0 None | |||
iInterface 0 | |||
HID Device Descriptor: | |||
bLength 9 | |||
bDescriptorType 33 | |||
bcdHID 2.00 | |||
bCountryCode 0 Not supported | |||
bNumDescriptors 1 | |||
bDescriptorType 34 Report | |||
wDescriptorLength 26 | |||
Report Descriptors: | |||
** UNAVAILABLE ** | |||
Endpoint Descriptor: | |||
bLength 7 | |||
bDescriptorType 5 | |||
bEndpointAddress 0x81 EP 1 IN | |||
bmAttributes 3 | |||
Transfer Type Interrupt | |||
Synch Type None | |||
Usage Type Data | |||
wMaxPacketSize 0x0001 1x 1 bytes | |||
bInterval 16 | |||
[[Category:Services]] | [[Category:Services]] |