libnx  v4.6.0
usbhs.h
Go to the documentation of this file.
1 /**
2  * @file usbhs.h
3  * @brief USB (usb:hs) devices service IPC wrapper.
4  * @author yellows8
5  * @copyright libnx Authors
6  */
7 #pragma once
8 #include "../types.h"
9 #include "../sf/service.h"
10 #include "../services/usb.h"
11 #include "../kernel/event.h"
12 #include "../kernel/tmem.h"
13 
14 typedef enum {
15  ///< These use \ref usb_device_descriptor. Bit2..6 require [6.0.0+], these are ignored on eariler versions.
17  UsbHsInterfaceFilterFlags_idProduct = BIT(1),
18  UsbHsInterfaceFilterFlags_bcdDevice_Min = BIT(2),
19  UsbHsInterfaceFilterFlags_bcdDevice_Max = BIT(3),
20  UsbHsInterfaceFilterFlags_bDeviceClass = BIT(4),
21  UsbHsInterfaceFilterFlags_bDeviceSubClass = BIT(5),
23 
24  ///< These use \ref usb_interface_descriptor.
25  UsbHsInterfaceFilterFlags_bInterfaceClass = BIT(7),
26  UsbHsInterfaceFilterFlags_bInterfaceSubClass = BIT(8),
27  UsbHsInterfaceFilterFlags_bInterfaceProtocol = BIT(9),
29 
30 /// Interface filtering struct. When the associated flag bit is set, the associated descriptor field and struct field are compared, on mismatch the interface is filtered out.
31 /// [7.0.0+]: The filter struct has to be unique, it can't be used by anything else (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 against a blacklist.
32 typedef struct {
33  u16 Flags; ///< See \ref UsbHsInterfaceFilterFlags. Setting this to 0 is equivalent to disabling filtering.
34  u16 idVendor;
35  u16 idProduct;
36  u16 bcdDevice_Min; ///< Descriptor value must be >= bcdDevice_Min.
37  u16 bcdDevice_Max; ///< Descriptor value must be <= bcdDevice_Max.
38  u8 bDeviceClass;
39  u8 bDeviceSubClass;
40  u8 bDeviceProtocol;
41  u8 bInterfaceClass;
42  u8 bInterfaceSubClass;
43  u8 bInterfaceProtocol;
45 
46 /// Descriptors which are not available are set to all-zero.
47 /// The INPUT/OUTPUT endpoint descriptors were swapped with [8.0.0+], libnx converts this struct to the newer layout when running on pre-8.0.0.
48 typedef struct {
49  s32 ID;
50  u32 deviceID_2;
51  u32 unk_x8;
52 
53  struct usb_interface_descriptor interface_desc;
54  u8 pad_x15[0x7];
55  struct usb_endpoint_descriptor input_endpoint_descs[15];
56  u8 pad_x85[0x7];
57  struct usb_endpoint_descriptor output_endpoint_descs[15];
58  u8 pad_xf5[0x6];
59  struct usb_ss_endpoint_companion_descriptor input_ss_endpoint_companion_descs[15]; ///< ?
60  u8 pad_x155[0x6];
61  struct usb_ss_endpoint_companion_descriptor output_ss_endpoint_companion_descs[15]; ///< ?
62  u8 pad_x1b5[0x3];
64 
65 /// Interface struct. Note that devices have a seperate \ref UsbHsInterface for each interface.
66 typedef struct {
68 
69  char pathstr[0x40];
70  u32 busID;
71  u32 deviceID;
72 
73  struct usb_device_descriptor device_desc;
74  struct usb_config_descriptor config_desc;
75  u8 pad_x21b[0x5];
76 
77  u64 timestamp; ///< Unknown u64 timestamp for when the device was inserted?
79 
80 typedef struct {
81  u32 xferId;
82  Result res;
83  u32 requestedSize;
84  u32 transferredSize;
85  u64 id; ///< id from \ref usbHsEpPostBufferAsync.
87 
88 typedef struct {
89  vu64 write_index;
90  vu64 read_index;
92 
93 /// The interface service object. These Events have autoclear=false.
94 typedef struct {
95  Service s;
96  Event event0; ///< Unknown.
97  Event eventCtrlXfer; ///< [2.0.0+] Signaled when CtrlXferAsync finishes.
98  s32 ID;
99 
100  UsbHsInterface inf; ///< Initialized with the input interface from \ref usbHsAcquireUsbIf, then overwritten with the cmd output. Pre-3.0.0 this only overwrites the first 0x1B8-bytes (data before pathstr).
102 
103 typedef struct {
104  Service s;
105  Event eventXfer; ///< [2.0.0+] Signaled when PostBufferAsync finishes.
106  u32 maxUrbCount;
107  u64 max_reports;
108  void* ringbuf;
109 
110  struct usb_endpoint_descriptor desc;
112 
113 /// Initialize usb:hs.
115 
116 /// Exit usb:hs.
117 void usbHsExit(void);
118 
119 /// Gets the Service object for the actual usb:hs service session.
121 
122 /// Returns the Event loaded during init with autoclear=false.
123 /// Signaled when a device was removed.
124 /// When signaled, the user should use \ref usbHsQueryAcquiredInterfaces and cleanup state for all interfaces which are not listed in the output interfaces (none of the IDs match \ref usbHsIfGetID output).
126 
127 /**
128  * @brief Returns an array of all \ref UsbHsInterface. Internally this loads the same interfaces as \ref usbHsQueryAvailableInterfaces, followed by \ref usbHsQueryAcquiredInterfaces. However, ID in \ref UsbHsInterface is set to -1, hence the output from this should not be used with \ref usbHsAcquireUsbIf.
129  * @param[in] filter \ref UsbHsInterfaceFilter.
130  * @param[out] interfaces Array of output interfaces.
131  * @param[in] interfaces_maxsize Max byte-size of the interfaces buffer.
132  * @param[out] total_entries Total number of output interfaces.
133  */
134 Result usbHsQueryAllInterfaces(const UsbHsInterfaceFilter* filter, UsbHsInterface* interfaces, size_t interfaces_maxsize, s32* total_entries);
135 
136 /**
137  * @brief Returns an array of \ref UsbHsInterface which are available.
138  * @param[in] filter \ref UsbHsInterfaceFilter.
139  * @param[out] interfaces Array of output interfaces.
140  * @param[in] interfaces_maxsize Max byte-size of the interfaces buffer.
141  * @param[out] total_entries Total number of output interfaces.
142  */
143 Result usbHsQueryAvailableInterfaces(const UsbHsInterfaceFilter* filter, UsbHsInterface* interfaces, size_t interfaces_maxsize, s32* total_entries);
144 
145 /**
146  * @brief Returns an array of \ref UsbHsInterface which were previously acquired.
147  * @param[out] interfaces Array of output interfaces.
148  * @param[in] interfaces_maxsize Max byte-size of the interfaces buffer.
149  * @param[out] total_entries Total number of output interfaces.
150  */
151 Result usbHsQueryAcquiredInterfaces(UsbHsInterface* interfaces, size_t interfaces_maxsize, s32* total_entries);
152 
153 /**
154  * @brief Creates an event which is signaled when an interface is available which passes the filtering checks.
155  * @param[out] out_event Event object.
156  * @param[in] autoclear Event autoclear.
157  * @param[in] index Event index, must be 0..2.
158  * @param[in] filter \ref UsbHsInterfaceFilter.
159  */
160 Result usbHsCreateInterfaceAvailableEvent(Event* out_event, bool autoclear, u8 index, const UsbHsInterfaceFilter* filter);
161 
162 /**
163  * @brief Destroys an event setup by \ref usbHsCreateInterfaceAvailableEvent. This *must* be used at some point during cleanup.
164  * @param[in] event Event object to close.
165  * @param[in] index Event index, must be 0..2.
166  */
168 
169 /**
170  * @brief Acquires/opens the specified interface. This returns an error if the interface was already acquired by another process.
171  * @param[in] s The service object.
172  * @param[in] interface Interface to use.
173  */
175 
176 /// UsbHsClientIfSession
177 
178 /// Closes the specified interface session.
180 
181 /// Returns whether the specified interface session was initialized.
182 static inline bool usbHsIfIsActive(UsbHsClientIfSession* s) {
183  return serviceIsActive(&s->s);
184 }
185 
186 /// Returns the ID which can be used for comparing with the ID in the output interfaces from \ref usbHsQueryAcquiredInterfaces.
188  return s->ID;
189 }
190 
191 /**
192  * @brief Selects an interface.
193  * @param[in] s The service object.
194  * @param[out] inf The output interface info. If NULL, the output is stored within s instead.
195  * @param[in] id ID
196  */
198 
199 /**
200  * @brief Gets an interface.
201  * @param[in] s The service object.
202  * @param[out] inf The output interface info. If NULL, the output is stored within s instead.
203  */
205 
206 /**
207  * @brief Gets an alternate interface.
208  * @param[in] s The service object.
209  * @param[out] inf The output interface info. If NULL, the output is stored within s instead.
210  * @param[in] id ID
211  */
213 
214 /// On [1.0.0] this is stubbed, just returns 0 with out=0.
216 
217 /// Uses a control transfer, this will block until the transfer finishes. The buffer address and size should be aligned to 0x1000-bytes, where wLength is the original size.
218 Result usbHsIfCtrlXfer(UsbHsClientIfSession* s, u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, void* buffer, u32* transferredSize);
219 
220 /**
221  * @brief Opens an endpoint. maxUrbCount*maxXferSize must be non-zero.
222  * @param[in] s The interface object.
223  * @param[out] ep The endpoint object.
224  * @param[in] maxUrbCount maxUrbCount, must be <0x11.
225  * @param[in] maxXferSize Max transfer size for a packet. This can be desc->wMaxPacketSize. Must be <=0xFF0000.
226  * @param[in] desc Endpoint descriptor.
227  */
229 
230 /// Resets the device: has the same affect as unplugging the device and plugging it back in.
232 
233 /// UsbHsClientEpSession
234 
235 /// Closes the specified endpoint session.
237 
238 /// Gets the Xfer Event which is signaled when PostBufferAsync finishes. This is only valid for [2.0.0+]. If using \ref eventWait with this, then \ref eventClear should be used if the event was signaled (since the autoclear is false).
240  return &s->eventXfer;
241 }
242 
243 /// Gets the buffer size to use with \ref usbHsEpShareReportRing.
245  u64 max_reports = s->maxUrbCount * 0x21;
246  u32 size = sizeof(UsbHsRingHeader) + max_reports*sizeof(UsbHsXferReport);
247  size = (size+0xFFF) & ~0xFFF;
248  return size;
249 }
250 
251 /**
252  * @brief Starts an async data transfer with the specified endpoint. The Event from \ref usbHsEpGetXferEvent can be used to determine when the transfer finished. If you don't need async, \ref usbHsEpPostBuffer can be used instead.
253  * @note Only available on [2.0.0+].
254  * @param[in] s The endpoint object.
255  * @param buffer Data buffer. The buffer address and size should be aligned to 0x1000-bytes.
256  * @param[in] size The actual data size.
257  * @param[in] id This is an arbitrary value which will be later returned in \ref UsbHsXferReport. For example a value starting at 0 can be used, then if sending multiple requests at once this value can be incremented each time (with 0 for the first request in this set of requests).
258  * @param[out] xferId Output xferId.
259  */
260 Result usbHsEpPostBufferAsync(UsbHsClientEpSession* s, void* buffer, u32 size, u64 id, u32* xferId);
261 
262 /**
263  * @brief Gets an array of \ref UsbHsXferReport for the specified endpoint. This should be used after waiting on the Event from \ref usbHsEpGetXferEvent.
264  * @note Only available on [2.0.0+].
265  * @param[in] s The endpoint object.
266  * @param[out] reports Output array of \ref UsbHsXferReport.
267  * @param[in] max_reports Size of the reports array in entries.
268  * @param[out] count Number of entries written to the array.
269  */
271 
272 /**
273  * @brief Uses a data transfer with the specified endpoint, this will block until the transfer finishes. This wraps \ref usbHsEpPostBufferAsync and \ref usbHsEpGetXferReport, and also handles the Event (on pre-2.0.0 this handles using the relevant cmds instead). If async is needed, use \ref usbHsEpPostBufferAsync instead.
274  * @param[in] s The endpoint object.
275  * @param buffer Data buffer. The buffer address and size should be aligned to 0x1000-bytes.
276  * @param[in] size The actual data size.
277  * @param[out] transferredSize Output transferred size.
278  */
279 Result usbHsEpPostBuffer(UsbHsClientEpSession* s, void* buffer, u32 size, u32* transferredSize);
280 
281 /**
282  * @brief This uses the same functionality internally as \ref usbHsEpPostBufferAsync except the urbs array and unk1/unk2 are specified by the user instead.
283  * @note Only available on [2.0.0+].
284  * @param[in] s The endpoint object.
285  * @param buffer Data buffer. The buffer address and size should be aligned to 0x1000-bytes.
286  * @param[in] urbs Input array of u32s for the size of each urb.
287  * @param[in] urbCount Total entries in the urbs array.
288  * @param[in] id Same as \ref usbHsEpPostBufferAsync.
289  * @param[in] unk1 \ref usbHsEpPostBufferAsync would internally pass value 0 here.
290  * @param[in] unk2 \ref usbHsEpPostBufferAsync would internally pass value 0 here.
291  * @param[out] xferId Output xferId.
292  */
293 Result usbHsEpBatchBufferAsync(UsbHsClientEpSession* s, void* buffer, u32* urbs, u32 urbCount, u64 id, u32 unk1, u32 unk2, u32* xferId);
294 
295 /**
296  * @brief This can be used to map the specified buffer as devicemem, which can then be used with \ref usbHsEpPostBufferAsync / \ref usbHsEpPostBuffer / \ref usbHsEpBatchBufferAsync. If the buffer address passed to those funcs is within this SmmuSpace, the specified buffer must be within the bounds of the SmmuSpace buffer.
297  * @note Only available on [4.0.0+].
298  * @note A buffer from usbHsEpCreateSmmuSpace can't be reused by another endpoint with the aforementioned funcs.
299  * @note This can only be used once per UsbHsClientEpSession object.
300  * @param[in] s The endpoint object.
301  * @param buffer Buffer address, this must be aligned to 0x1000-bytes.
302  * @param[in] size Buffer size, this must be aligned to 0x1000-bytes.
303  */
305 
306 /**
307  * @brief This creates TransferMemory which is used to read \ref UsbHsXferReport when \ref usbHsEpGetXferReport is used, instead of using the service cmd.
308  * @note Only available on [4.0.0+].
309  * @param buffer Buffer, must be 0x1000-byte aligned.
310  * @param[in] size Buffer size, \ref usbHsEpGetReportRingSize can be used to calculate this.
311  */
312 Result usbHsEpShareReportRing(UsbHsClientEpSession* s, void* buffer, size_t size);
313 
static bool serviceIsActive(Service *s)
Returns whether a service has been initialized.
Definition: service.h:92
Kernel-mode event structure.
Definition: event.h:13
Service object structure.
Definition: service.h:14
Definition: usbhs.h:103
Event eventXfer
[2.0.0+] Signaled when PostBufferAsync finishes.
Definition: usbhs.h:105
The interface service object. These Events have autoclear=false.
Definition: usbhs.h:94
UsbHsInterface inf
Initialized with the input interface from usbHsAcquireUsbIf, then overwritten with the cmd output....
Definition: usbhs.h:100
Event eventCtrlXfer
[2.0.0+] Signaled when CtrlXferAsync finishes.
Definition: usbhs.h:97
Event event0
Unknown.
Definition: usbhs.h:96
Interface filtering struct.
Definition: usbhs.h:32
u16 Flags
See UsbHsInterfaceFilterFlags. Setting this to 0 is equivalent to disabling filtering.
Definition: usbhs.h:33
u16 bcdDevice_Min
Descriptor value must be >= bcdDevice_Min.
Definition: usbhs.h:36
u16 bcdDevice_Max
Descriptor value must be <= bcdDevice_Max.
Definition: usbhs.h:37
Descriptors which are not available are set to all-zero.
Definition: usbhs.h:48
Interface struct. Note that devices have a seperate UsbHsInterface for each interface.
Definition: usbhs.h:66
u64 timestamp
Unknown u64 timestamp for when the device was inserted?
Definition: usbhs.h:77
Definition: usbhs.h:88
Definition: usbhs.h:80
u64 id
id from usbHsEpPostBufferAsync.
Definition: usbhs.h:85
Imported from libusb, with some adjustments.
Definition: usb.h:66
Imported from libusb, with some adjustments.
Definition: usb.h:48
Imported from libusb, with some adjustments.
Definition: usb.h:25
Imported from libusb, with some adjustments.
Definition: usb.h:35
Imported from libusb, with some adjustments.
Definition: usb.h:78
#define BIT(n)
Creates a bitmask from a bit number.
Definition: types.h:54
uint64_t u64
64-bit unsigned integer.
Definition: types.h:22
uint8_t u8
8-bit unsigned integer.
Definition: types.h:19
#define NX_PACKED
Packs a struct so that it won't include padding bytes.
Definition: types.h:63
volatile u64 vu64
64-bit volatile unsigned integer.
Definition: types.h:34
uint16_t u16
16-bit unsigned integer.
Definition: types.h:20
u32 Result
Function error code result type.
Definition: types.h:44
#define NX_CONSTEXPR
Flags a function as constexpr in C++14 and above; or as (always) inline otherwise.
Definition: types.h:92
int32_t s32
32-bit signed integer.
Definition: types.h:27
uint32_t u32
32-bit unsigned integer.
Definition: types.h:21
Result usbHsDestroyInterfaceAvailableEvent(Event *event, u8 index)
Destroys an event setup by usbHsCreateInterfaceAvailableEvent.
void usbHsExit(void)
Exit usb:hs.
UsbHsInterfaceFilterFlags
Definition: usbhs.h:14
@ UsbHsInterfaceFilterFlags_idVendor
These use usb_device_descriptor. Bit2..6 require [6.0.0+], these are ignored on eariler versions.
Definition: usbhs.h:16
@ UsbHsInterfaceFilterFlags_bDeviceProtocol
These use usb_interface_descriptor.
Definition: usbhs.h:22
Result usbHsEpPostBufferAsync(UsbHsClientEpSession *s, void *buffer, u32 size, u64 id, u32 *xferId)
Starts an async data transfer with the specified endpoint.
Result usbHsInitialize(void)
Initialize usb:hs.
Result usbHsIfResetDevice(UsbHsClientIfSession *s)
Resets the device: has the same affect as unplugging the device and plugging it back in.
Result usbHsQueryAcquiredInterfaces(UsbHsInterface *interfaces, size_t interfaces_maxsize, s32 *total_entries)
Returns an array of UsbHsInterface which were previously acquired.
Result usbHsIfGetAlternateInterface(UsbHsClientIfSession *s, UsbHsInterfaceInfo *inf, u8 id)
Gets an alternate interface.
Result usbHsIfSetInterface(UsbHsClientIfSession *s, UsbHsInterfaceInfo *inf, u8 id)
Selects an interface.
Result usbHsEpCreateSmmuSpace(UsbHsClientEpSession *s, void *buffer, u32 size)
This can be used to map the specified buffer as devicemem, which can then be used with usbHsEpPostBuf...
static u32 usbHsEpGetReportRingSize(UsbHsClientEpSession *s)
Gets the buffer size to use with usbHsEpShareReportRing.
Definition: usbhs.h:244
Result usbHsAcquireUsbIf(UsbHsClientIfSession *s, UsbHsInterface *interface)
Acquires/opens the specified interface.
Result usbHsIfGetCurrentFrame(UsbHsClientIfSession *s, u32 *out)
On [1.0.0] this is stubbed, just returns 0 with out=0.
Result usbHsEpPostBuffer(UsbHsClientEpSession *s, void *buffer, u32 size, u32 *transferredSize)
Uses a data transfer with the specified endpoint, this will block until the transfer finishes.
void usbHsIfClose(UsbHsClientIfSession *s)
UsbHsClientIfSession.
Result usbHsQueryAvailableInterfaces(const UsbHsInterfaceFilter *filter, UsbHsInterface *interfaces, size_t interfaces_maxsize, s32 *total_entries)
Returns an array of UsbHsInterface which are available.
Result usbHsIfOpenUsbEp(UsbHsClientIfSession *s, UsbHsClientEpSession *ep, u16 maxUrbCount, u32 maxXferSize, struct usb_endpoint_descriptor *desc)
Opens an endpoint.
static s32 usbHsIfGetID(UsbHsClientIfSession *s)
Returns the ID which can be used for comparing with the ID in the output interfaces from usbHsQueryAc...
Definition: usbhs.h:187
static bool usbHsIfIsActive(UsbHsClientIfSession *s)
Returns whether the specified interface session was initialized.
Definition: usbhs.h:182
void usbHsEpClose(UsbHsClientEpSession *s)
UsbHsClientEpSession.
Result usbHsCreateInterfaceAvailableEvent(Event *out_event, bool autoclear, u8 index, const UsbHsInterfaceFilter *filter)
Creates an event which is signaled when an interface is available which passes the filtering checks.
Result usbHsEpBatchBufferAsync(UsbHsClientEpSession *s, void *buffer, u32 *urbs, u32 urbCount, u64 id, u32 unk1, u32 unk2, u32 *xferId)
This uses the same functionality internally as usbHsEpPostBufferAsync except the urbs array and unk1/...
static Event * usbHsEpGetXferEvent(UsbHsClientEpSession *s)
Gets the Xfer Event which is signaled when PostBufferAsync finishes. This is only valid for [2....
Definition: usbhs.h:239
Result usbHsEpGetXferReport(UsbHsClientEpSession *s, UsbHsXferReport *reports, u32 max_reports, u32 *count)
Gets an array of UsbHsXferReport for the specified endpoint.
Result usbHsEpShareReportRing(UsbHsClientEpSession *s, void *buffer, size_t size)
This creates TransferMemory which is used to read UsbHsXferReport when usbHsEpGetXferReport is used,...
Result usbHsQueryAllInterfaces(const UsbHsInterfaceFilter *filter, UsbHsInterface *interfaces, size_t interfaces_maxsize, s32 *total_entries)
Returns an array of all UsbHsInterface.
Result usbHsIfCtrlXfer(UsbHsClientIfSession *s, u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, void *buffer, u32 *transferredSize)
Uses a control transfer, this will block until the transfer finishes. The buffer address and size sho...
Service * usbHsGetServiceSession(void)
Gets the Service object for the actual usb:hs service session.
Result usbHsIfGetInterface(UsbHsClientIfSession *s, UsbHsInterfaceInfo *inf)
Gets an interface.
Event * usbHsGetInterfaceStateChangeEvent(void)
Returns the Event loaded during init with autoclear=false.