xref: /freebsd/sys/dev/hid/ps5dsense.c (revision d8e315ba975163a2050dd3d3e193f2472dbc2478)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2020 Vladimir Kondratyev <wulf@FreeBSD.org>
5  * Copyright (c) 2026 Christos Longros <chris.longros@gmail.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 /*
30  * Sony PS5 DualSense driver
31  * https://controllers.fandom.com/wiki/Sony_DualSense
32  * https://github.com/torvalds/linux/blob/master/drivers/hid/hid-playstation.c
33  *
34  * Touchpad and motion sensors are not supported yet.
35  */
36 
37 #include "opt_hid.h"
38 
39 #include <sys/param.h>
40 #include <sys/bus.h>
41 #include <sys/conf.h>
42 #include <sys/kernel.h>
43 #include <sys/lock.h>
44 #include <sys/module.h>
45 #include <sys/stat.h>
46 #include <sys/sx.h>
47 #include <sys/sysctl.h>
48 
49 #include <dev/evdev/input.h>
50 #include <dev/evdev/evdev.h>
51 
52 #define	HID_DEBUG_VAR	ps5ds_debug
53 #include <dev/hid/hgame.h>
54 #include <dev/hid/hid.h>
55 #include <dev/hid/hidbus.h>
56 #include <dev/hid/hidquirk.h>
57 #include <dev/hid/hidmap.h>
58 #include "usbdevs.h"
59 
60 #ifdef HID_DEBUG
61 static int ps5ds_debug = 1;
62 
63 static SYSCTL_NODE(_hw_hid, OID_AUTO, ps5dsense, CTLFLAG_RW, 0,
64 		"Sony PS5 DualSense Gamepad");
65 SYSCTL_INT(_hw_hid_ps5dsense, OID_AUTO, debug, CTLFLAG_RWTUN,
66 		&ps5ds_debug, 0, "Debug level");
67 #endif
68 
69 /*
70  * Fixed HID report descriptor.  Output is 62 bytes, not 47: shorter reports
71  * are ignored.
72  */
73 static const uint8_t	ps5ds_rdesc[] = {
74 	0x05, 0x01,		/* Usage Page (Generic Desktop Ctrls)	*/
75 	0x09, 0x05,		/* Usage (Game Pad)			*/
76 	0xA1, 0x01,		/* Collection (Application)		*/
77 	0x85, 0x01,		/*   Report ID (1)			*/
78 	0x09, 0x30,		/*   Usage (X)  - left stick X		*/
79 	0x09, 0x31,		/*   Usage (Y)  - left stick Y		*/
80 	0x09, 0x33,		/*   Usage (Rx) - right stick X		*/
81 	0x09, 0x34,		/*   Usage (Ry) - right stick Y		*/
82 	0x15, 0x00,		/*   Logical Minimum (0)		*/
83 	0x26, 0xFF, 0x00,	/*   Logical Maximum (255)		*/
84 	0x75, 0x08,		/*   Report Size (8)			*/
85 	0x95, 0x04,		/*   Report Count (4)			*/
86 	0x81, 0x02,		/*   Input (Data,Var,Abs)		*/
87 	0x09, 0x32,		/*   Usage (Z)  - L2 trigger		*/
88 	0x09, 0x35,		/*   Usage (Rz) - R2 trigger		*/
89 	0x15, 0x00,		/*   Logical Minimum (0)		*/
90 	0x26, 0xFF, 0x00,	/*   Logical Maximum (255)		*/
91 	0x75, 0x08,		/*   Report Size (8)			*/
92 	0x95, 0x02,		/*   Report Count (2)			*/
93 	0x81, 0x02,		/*   Input (Data,Var,Abs)		*/
94 	0x06, 0x00, 0xFF,	/*   Usage Page (Vendor Defined 0xFF00)	*/
95 	0x09, 0x20,		/*   Usage (0x20)			*/
96 	0x15, 0x00,		/*   Logical Minimum (0)		*/
97 	0x26, 0xFF, 0x00,	/*   Logical Maximum (255)		*/
98 	0x75, 0x08,		/*   Report Size (8)			*/
99 	0x95, 0x01,		/*   Report Count (1)			*/
100 	0x81, 0x02,		/*   Input (Data,Var,Abs) - counter	*/
101 	0x05, 0x01,		/*   Usage Page (Generic Desktop)	*/
102 	0x09, 0x39,		/*   Usage (Hat switch)			*/
103 	0x15, 0x00,		/*   Logical Minimum (0)		*/
104 	0x25, 0x07,		/*   Logical Maximum (7)		*/
105 	0x35, 0x00,		/*   Physical Minimum (0)		*/
106 	0x46, 0x3B, 0x01,	/*   Physical Maximum (315)		*/
107 	0x65, 0x14,		/*   Unit (Eng Rot: Degree)		*/
108 	0x75, 0x04,		/*   Report Size (4)			*/
109 	0x95, 0x01,		/*   Report Count (1)			*/
110 	0x81, 0x42,		/*   Input (Data,Var,Abs,Null State)	*/
111 	0x65, 0x00,		/*   Unit (None)			*/
112 	0x45, 0x00,		/*   Physical Maximum (0)		*/
113 	0x05, 0x09,		/*   Usage Page (Button)		*/
114 	0x19, 0x01,		/*   Usage Minimum (0x01)		*/
115 	0x29, 0x0F,		/*   Usage Maximum (0x0F)		*/
116 	0x15, 0x00,		/*   Logical Minimum (0)		*/
117 	0x25, 0x01,		/*   Logical Maximum (1)		*/
118 	0x75, 0x01,		/*   Report Size (1)			*/
119 	0x95, 0x0F,		/*   Report Count (15)			*/
120 	0x81, 0x02,		/*   Input (Data,Var,Abs)		*/
121 	0x06, 0x00, 0xFF,	/*   Usage Page (Vendor Defined 0xFF00)	*/
122 	0x09, 0x21,		/*   Usage (0x21)			*/
123 	0x75, 0x01,		/*   Report Size (1)			*/
124 	0x95, 0x0D,		/*   Report Count (13)			*/
125 	0x81, 0x03,		/*   Input (Const) - unused button bits	*/
126 	0x09, 0x22,		/*   Usage (0x22)			*/
127 	0x15, 0x00,		/*   Logical Minimum (0)		*/
128 	0x26, 0xFF, 0x00,	/*   Logical Maximum (255)		*/
129 	0x75, 0x08,		/*   Report Size (8)			*/
130 	0x95, 0x34,		/*   Report Count (52)			*/
131 	0x81, 0x03,		/*   Input (Const) - sensors, touchpad	*/
132 	/* Output report (63 bytes total) for LED and rumble control */
133 	0x85, 0x02,		/*   Report ID (2)			*/
134 	0x09, 0x23,		/*   Usage (0x23)			*/
135 	0x75, 0x08,		/*   Report Size (8)			*/
136 	0x95, 0x3E,		/*   Report Count (62)			*/
137 	0x91, 0x02,		/*   Output (Data,Var,Abs)		*/
138 	0xC0,			/* End Collection			*/
139 };
140 
141 #define	PS5DS_OUTPUT_REPORT2_SIZE	63
142 
143 struct ps5ds_out2 {
144 	uint8_t	valid_flag0;
145 	uint8_t	valid_flag1;
146 	uint8_t	rumble_right;
147 	uint8_t	rumble_left;
148 	uint8_t	reserved1[4];
149 	uint8_t	mute_button_led;
150 	uint8_t	power_save_control;
151 	uint8_t	reserved2[28];
152 	uint8_t	valid_flag2;
153 	uint8_t	reserved3[2];
154 	uint8_t	lightbar_setup;
155 	uint8_t	led_brightness;
156 	uint8_t	player_leds;
157 	uint8_t	led_color_r;
158 	uint8_t	led_color_g;
159 	uint8_t	led_color_b;
160 } __attribute__((packed));
161 
162 #define	PS5DS_FLAG1_LIGHTBAR		0x04
163 #define	PS5DS_FLAG1_PLAYER_LEDS		0x10
164 #define	PS5DS_FLAG2_LIGHTBAR_SETUP	0x02
165 #define	PS5DS_LIGHTBAR_FADE_OUT		0x02
166 
167 static const uint8_t ps5ds_player_leds[] = {
168 	0x04,	/* Player 1: --x-- */
169 	0x0A,	/* Player 2: -x-x- */
170 	0x15,	/* Player 3: x-x-x */
171 	0x1B,	/* Player 4: xx-xx */
172 	0x1F,	/* Player 5: xxxxx */
173 };
174 
175 static const struct ps5ds_led {
176 	int	r;
177 	int	g;
178 	int	b;
179 } ps5ds_leds[] = {
180 	/* The first 4 entries match the PS4, other from Linux driver */
181 	{ 0x00, 0x00, 0x40 },	/* Blue   */
182 	{ 0x40, 0x00, 0x00 },	/* Red    */
183 	{ 0x00, 0x40, 0x00 },	/* Green  */
184 	{ 0x20, 0x00, 0x20 },	/* Pink   */
185 	{ 0x02, 0x01, 0x00 },	/* Orange */
186 	{ 0x00, 0x01, 0x01 },	/* Teal   */
187 	{ 0x01, 0x01, 0x01 }	/* White  */
188 };
189 
190 enum ps5ds_led_state {
191 	PS5DS_LED_OFF,
192 	PS5DS_LED_ON,
193 	PS5DS_LED_CNT,
194 };
195 
196 struct ps5ds_softc {
197 	struct hidmap	hm;
198 
199 	struct sx	lock;
200 	enum ps5ds_led_state	led_state;
201 	struct ps5ds_led	led_color;
202 	int		player_leds;	/* 0-4: player number, -1: off */
203 };
204 
205 #define	PS5DS_OFFSET(field) offsetof(struct ps5ds_softc, field)
206 enum {
207 	PS5DS_SYSCTL_LED_STATE =	PS5DS_OFFSET(led_state),
208 	PS5DS_SYSCTL_LED_COLOR_R =	PS5DS_OFFSET(led_color.r),
209 	PS5DS_SYSCTL_LED_COLOR_G =	PS5DS_OFFSET(led_color.g),
210 	PS5DS_SYSCTL_LED_COLOR_B =	PS5DS_OFFSET(led_color.b),
211 	PS5DS_SYSCTL_PLAYER_LEDS =	PS5DS_OFFSET(player_leds),
212 #define	PS5DS_SYSCTL_LAST		PS5DS_SYSCTL_PLAYER_LEDS
213 };
214 
215 #define PS5DS_MAP_BTN(number, code)		\
216 	{ HIDMAP_KEY(HUP_BUTTON, number, code) }
217 #define PS5DS_MAP_ABS(usage, code)		\
218 	{ HIDMAP_ABS(HUP_GENERIC_DESKTOP, HUG_##usage, code) }
219 #define PS5DS_MAP_FLT(usage, code)		\
220 	{ HIDMAP_ABS(HUP_GENERIC_DESKTOP, HUG_##usage, code), .flat = 15 }
221 #define	PS5DS_MAP_GCB(usage, callback)		\
222 	{ HIDMAP_ANY_CB(HUP_GENERIC_DESKTOP, HUG_##usage, callback) }
223 #define	PS5DS_FINALCB(cb)			\
224 	{ HIDMAP_FINAL_CB(&cb) }
225 
226 static hidmap_cb_t	ps5ds_final_cb;
227 
228 static const struct hidmap_item ps5ds_map[] = {
229 	PS5DS_MAP_FLT(X,		ABS_X),
230 	PS5DS_MAP_FLT(Y,		ABS_Y),
231 	PS5DS_MAP_ABS(Z,		ABS_Z),
232 	PS5DS_MAP_ABS(RZ,		ABS_RZ),
233 	PS5DS_MAP_FLT(RX,		ABS_RX),
234 	PS5DS_MAP_FLT(RY,		ABS_RY),
235 	PS5DS_MAP_BTN(1,		BTN_WEST),
236 	PS5DS_MAP_BTN(2,		BTN_SOUTH),
237 	PS5DS_MAP_BTN(3,		BTN_EAST),
238 	PS5DS_MAP_BTN(4,		BTN_NORTH),
239 	PS5DS_MAP_BTN(5,		BTN_TL),
240 	PS5DS_MAP_BTN(6,		BTN_TR),
241 	PS5DS_MAP_BTN(7,		BTN_TL2),
242 	PS5DS_MAP_BTN(8,		BTN_TR2),
243 	PS5DS_MAP_BTN(9,		BTN_SELECT),
244 	PS5DS_MAP_BTN(10,		BTN_START),
245 	PS5DS_MAP_BTN(11,		BTN_THUMBL),
246 	PS5DS_MAP_BTN(12,		BTN_THUMBR),
247 	PS5DS_MAP_BTN(13,		BTN_MODE),
248 	/* Click button is handled by touchpad driver */
249 	/* PS5DS_MAP_BTN(14,	BTN_LEFT), */
250 	/* Linux mutes the microphone in hardware and emits no event */
251 	PS5DS_MAP_BTN(15,		KEY_MICMUTE),
252 	PS5DS_MAP_GCB(HAT_SWITCH,	hgame_hat_switch_cb),
253 	PS5DS_FINALCB(			ps5ds_final_cb),
254 };
255 
256 static const struct hid_device_id ps5ds_devs[] = {
257 	{ HID_BVP(BUS_USB, USB_VENDOR_SONY, 0x0ce6),
258 	  HID_TLC(HUP_GENERIC_DESKTOP, HUG_GAME_PAD) },
259 };
260 
261 static int
ps5ds_final_cb(HIDMAP_CB_ARGS)262 ps5ds_final_cb(HIDMAP_CB_ARGS)
263 {
264 	struct evdev_dev *evdev = HIDMAP_CB_GET_EVDEV();
265 
266 	if (HIDMAP_CB_GET_STATE() == HIDMAP_CB_IS_ATTACHING) {
267 		evdev_support_prop(evdev, INPUT_PROP_DIRECT);
268 		evdev_set_cdev_mode(evdev, UID_ROOT, GID_GAMES,
269 		    S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
270 	}
271 
272 	/* Do not execute callback at interrupt handler and detach */
273 	return (ENOSYS);
274 }
275 
276 static int
ps5ds_write(struct ps5ds_softc * sc)277 ps5ds_write(struct ps5ds_softc *sc)
278 {
279 	uint8_t buf[PS5DS_OUTPUT_REPORT2_SIZE];
280 	bool led_on;
281 
282 	sx_assert(&sc->lock, SA_XLOCKED);
283 
284 	memset(buf, 0, sizeof(buf));
285 	buf[0] = 0x02;
286 	led_on = sc->led_state != PS5DS_LED_OFF;
287 	*(struct ps5ds_out2 *)(buf + 1) = (struct ps5ds_out2) {
288 		.valid_flag1 = PS5DS_FLAG1_LIGHTBAR | PS5DS_FLAG1_PLAYER_LEDS,
289 		.player_leds = sc->player_leds < 0 ?
290 		    0 : ps5ds_player_leds[sc->player_leds],
291 		.led_color_r = led_on ? sc->led_color.r : 0,
292 		.led_color_g = led_on ? sc->led_color.g : 0,
293 		.led_color_b = led_on ? sc->led_color.b : 0,
294 	};
295 
296 	return (hid_write(sc->hm.dev, buf, sizeof(buf)));
297 }
298 
299 static int
ps5ds_blank(struct ps5ds_softc * sc)300 ps5ds_blank(struct ps5ds_softc *sc)
301 {
302 	uint8_t buf[PS5DS_OUTPUT_REPORT2_SIZE];
303 
304 	memset(buf, 0, sizeof(buf));
305 	buf[0] = 0x02;
306 	*(struct ps5ds_out2 *)(buf + 1) = (struct ps5ds_out2) {
307 		.valid_flag1 = PS5DS_FLAG1_LIGHTBAR | PS5DS_FLAG1_PLAYER_LEDS,
308 		.valid_flag2 = PS5DS_FLAG2_LIGHTBAR_SETUP,
309 		.lightbar_setup = PS5DS_LIGHTBAR_FADE_OUT,
310 	};
311 
312 	return (hid_write(sc->hm.dev, buf, sizeof(buf)));
313 }
314 
315 static int
ps5ds_sysctl(SYSCTL_HANDLER_ARGS)316 ps5ds_sysctl(SYSCTL_HANDLER_ARGS)
317 {
318 	struct ps5ds_softc *sc;
319 	int error, arg;
320 
321 	if (oidp->oid_arg1 == NULL || oidp->oid_arg2 < 0 ||
322 	    oidp->oid_arg2 > PS5DS_SYSCTL_LAST)
323 		return (EINVAL);
324 
325 	sc = oidp->oid_arg1;
326 	sx_xlock(&sc->lock);
327 
328 	arg = *(int *)((char *)sc + oidp->oid_arg2);
329 	error = sysctl_handle_int(oidp, &arg, 0, req);
330 
331 	if (error || !req->newptr)
332 		goto unlock;
333 
334 	switch (oidp->oid_arg2) {
335 	case PS5DS_SYSCTL_LED_STATE:
336 		if (arg < 0 || arg >= PS5DS_LED_CNT)
337 			error = EINVAL;
338 		break;
339 	case PS5DS_SYSCTL_LED_COLOR_R:
340 	case PS5DS_SYSCTL_LED_COLOR_G:
341 	case PS5DS_SYSCTL_LED_COLOR_B:
342 		if (arg < 0 || arg > UINT8_MAX)
343 			error = EINVAL;
344 		break;
345 	case PS5DS_SYSCTL_PLAYER_LEDS:
346 		if (arg < -1 || arg >= (int)nitems(ps5ds_player_leds))
347 			error = EINVAL;
348 		break;
349 	default:
350 		error = EINVAL;
351 	}
352 
353 	if (error == 0) {
354 		*(int *)((char *)sc + oidp->oid_arg2) = arg;
355 		ps5ds_write(sc);
356 	}
357 unlock:
358 	sx_unlock(&sc->lock);
359 
360 	return (error);
361 }
362 
363 static void
ps5ds_identify(driver_t * driver,device_t parent)364 ps5ds_identify(driver_t *driver, device_t parent)
365 {
366 
367 	/* Replace the gamepad's rudimentary report descriptor */
368 	if (HIDBUS_LOOKUP_ID(parent, ps5ds_devs) != NULL)
369 		hid_set_report_descr(parent, ps5ds_rdesc,
370 		    sizeof(ps5ds_rdesc));
371 }
372 
373 static int
ps5ds_probe(device_t dev)374 ps5ds_probe(device_t dev)
375 {
376 	struct ps5ds_softc *sc = device_get_softc(dev);
377 
378 	hidmap_set_debug_var(&sc->hm, &HID_DEBUG_VAR);
379 	return (
380 	    HIDMAP_PROBE(&sc->hm, dev, ps5ds_devs, ps5ds_map, NULL)
381 	);
382 }
383 
384 static int
ps5ds_attach(device_t dev)385 ps5ds_attach(device_t dev)
386 {
387 	struct ps5ds_softc *sc = device_get_softc(dev);
388 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
389 	struct sysctl_oid *tree = device_get_sysctl_tree(dev);
390 	int error, unit;
391 
392 	sx_init(&sc->lock, "ps5dsense");
393 
394 	unit = device_get_unit(dev);
395 	sc->led_state = PS5DS_LED_ON;
396 	sc->led_color = ps5ds_leds[unit % nitems(ps5ds_leds)];
397 	sc->player_leds = unit < (int)nitems(ps5ds_player_leds) ? unit : -1;
398 
399 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
400 	    "led_state", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, sc,
401 	    PS5DS_SYSCTL_LED_STATE, ps5ds_sysctl, "I",
402 	    "LED state: 0 - off, 1 - on.");
403 
404 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
405 	    "led_color_r", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, sc,
406 	    PS5DS_SYSCTL_LED_COLOR_R, ps5ds_sysctl, "I",
407 	    "Lightbar color. Red component.");
408 
409 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
410 	    "led_color_g", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, sc,
411 	    PS5DS_SYSCTL_LED_COLOR_G, ps5ds_sysctl, "I",
412 	    "Lightbar color. Green component.");
413 
414 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
415 	    "led_color_b", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, sc,
416 	    PS5DS_SYSCTL_LED_COLOR_B, ps5ds_sysctl, "I",
417 	    "Lightbar color. Blue component.");
418 
419 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
420 	    "player_leds", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, sc,
421 	    PS5DS_SYSCTL_PLAYER_LEDS, ps5ds_sysctl, "I",
422 	    "Player indicator LEDs: -1 - off, 0-4 - player number.");
423 
424 	error = hidmap_attach(&sc->hm);
425 	if (error) {
426 		sx_destroy(&sc->lock);
427 		return (error);
428 	}
429 
430 	sx_xlock(&sc->lock);
431 	ps5ds_write(sc);
432 	sx_xunlock(&sc->lock);
433 
434 	return (0);
435 }
436 
437 static int
ps5ds_detach(device_t dev)438 ps5ds_detach(device_t dev)
439 {
440 	struct ps5ds_softc *sc = device_get_softc(dev);
441 	int error;
442 
443 	error = hidmap_detach(&sc->hm);
444 	if (error)
445 		return (error);
446 
447 	ps5ds_blank(sc);
448 	sx_destroy(&sc->lock);
449 
450 	return (0);
451 }
452 
453 static device_method_t ps5ds_methods[] = {
454 	DEVMETHOD(device_identify,	ps5ds_identify),
455 	DEVMETHOD(device_probe,		ps5ds_probe),
456 	DEVMETHOD(device_attach,	ps5ds_attach),
457 	DEVMETHOD(device_detach,	ps5ds_detach),
458 
459 	DEVMETHOD_END
460 };
461 
462 DEFINE_CLASS_0(ps5dsense, ps5ds_driver, ps5ds_methods,
463     sizeof(struct ps5ds_softc));
464 DRIVER_MODULE(ps5dsense, hidbus, ps5ds_driver, NULL, NULL);
465 
466 MODULE_DEPEND(ps5dsense, hid, 1, 1, 1);
467 MODULE_DEPEND(ps5dsense, hidbus, 1, 1, 1);
468 MODULE_DEPEND(ps5dsense, hidmap, 1, 1, 1);
469 MODULE_DEPEND(ps5dsense, hgame, 1, 1, 1);
470 MODULE_DEPEND(ps5dsense, evdev, 1, 1, 1);
471 MODULE_VERSION(ps5dsense, 1);
472 HID_PNP_INFO(ps5ds_devs);
473