1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * HID driver for OneXPlayer gamepad configuration devices.
4 *
5 * Copyright (c) 2026 Valve Corporation
6 */
7
8 #include <linux/array_size.h>
9 #include <linux/cleanup.h>
10 #include <linux/delay.h>
11 #include <linux/dev_printk.h>
12 #include <linux/device.h>
13 #include <linux/dmi.h>
14 #include <linux/hid.h>
15 #include <linux/jiffies.h>
16 #include <linux/kstrtox.h>
17 #include <linux/led-class-multicolor.h>
18 #include <linux/mutex.h>
19 #include <linux/sysfs.h>
20 #include <linux/types.h>
21 #include <linux/workqueue.h>
22
23 #include "hid-ids.h"
24
25 #define OXP_PACKET_SIZE 64
26
27 #define GEN1_MESSAGE_ID 0xff
28 #define GEN2_MESSAGE_ID 0x3f
29
30 #define GEN1_USAGE_PAGE 0xff01
31 #define GEN2_USAGE_PAGE 0xff00
32
33 enum oxp_function_index {
34 OXP_FID_GEN1_RGB_SET = 0x07,
35 OXP_FID_GEN1_RGB_REPLY = 0x0f,
36 OXP_FID_GEN2_TOGGLE_MODE = 0xb2,
37 OXP_FID_GEN2_RUMBLE_SET = 0xb3,
38 OXP_FID_GEN2_KEY_STATE = 0xb4,
39 OXP_FID_GEN2_STATUS_EVENT = 0xb8,
40 };
41
42 #define OXP_MAPPING_GAMEPAD 0x01
43 #define OXP_MAPPING_KEYBOARD 0x02
44
45 struct oxp_button_data {
46 u8 mode;
47 u8 index;
48 u8 key_id;
49 u8 padding[2];
50 } __packed;
51
52 struct oxp_button_entry {
53 struct oxp_button_data data;
54 const char *name;
55 };
56
57 static const struct oxp_button_entry oxp_button_table[] = {
58 /* Gamepad Buttons */
59 { { OXP_MAPPING_GAMEPAD, 0x01 }, "BTN_A" },
60 { { OXP_MAPPING_GAMEPAD, 0x02 }, "BTN_B" },
61 { { OXP_MAPPING_GAMEPAD, 0x03 }, "BTN_X" },
62 { { OXP_MAPPING_GAMEPAD, 0x04 }, "BTN_Y" },
63 { { OXP_MAPPING_GAMEPAD, 0x05 }, "BTN_LB" },
64 { { OXP_MAPPING_GAMEPAD, 0x06 }, "BTN_RB" },
65 { { OXP_MAPPING_GAMEPAD, 0x07 }, "BTN_LT" },
66 { { OXP_MAPPING_GAMEPAD, 0x08 }, "BTN_RT" },
67 { { OXP_MAPPING_GAMEPAD, 0x09 }, "BTN_START" },
68 { { OXP_MAPPING_GAMEPAD, 0x0a }, "BTN_SELECT" },
69 { { OXP_MAPPING_GAMEPAD, 0x0b }, "BTN_L3" },
70 { { OXP_MAPPING_GAMEPAD, 0x0c }, "BTN_R3" },
71 { { OXP_MAPPING_GAMEPAD, 0x0d }, "DPAD_UP" },
72 { { OXP_MAPPING_GAMEPAD, 0x0e }, "DPAD_DOWN" },
73 { { OXP_MAPPING_GAMEPAD, 0x0f }, "DPAD_LEFT" },
74 { { OXP_MAPPING_GAMEPAD, 0x10 }, "DPAD_RIGHT" },
75 { { OXP_MAPPING_GAMEPAD, 0x11 }, "JOY_L_UP" },
76 { { OXP_MAPPING_GAMEPAD, 0x12 }, "JOY_L_UP_RIGHT" },
77 { { OXP_MAPPING_GAMEPAD, 0x13 }, "JOY_L_RIGHT" },
78 { { OXP_MAPPING_GAMEPAD, 0x14 }, "JOY_L_DOWN_RIGHT" },
79 { { OXP_MAPPING_GAMEPAD, 0x15 }, "JOY_L_DOWN" },
80 { { OXP_MAPPING_GAMEPAD, 0x16 }, "JOY_L_DOWN_LEFT" },
81 { { OXP_MAPPING_GAMEPAD, 0x17 }, "JOY_L_LEFT" },
82 { { OXP_MAPPING_GAMEPAD, 0x18 }, "JOY_L_UP_LEFT" },
83 { { OXP_MAPPING_GAMEPAD, 0x19 }, "JOY_R_UP" },
84 { { OXP_MAPPING_GAMEPAD, 0x1a }, "JOY_R_UP_RIGHT" },
85 { { OXP_MAPPING_GAMEPAD, 0x1b }, "JOY_R_RIGHT" },
86 { { OXP_MAPPING_GAMEPAD, 0x1c }, "JOY_R_DOWN_RIGHT" },
87 { { OXP_MAPPING_GAMEPAD, 0x1d }, "JOY_R_DOWN" },
88 { { OXP_MAPPING_GAMEPAD, 0x1e }, "JOY_R_DOWN_LEFT" },
89 { { OXP_MAPPING_GAMEPAD, 0x1f }, "JOY_R_LEFT" },
90 { { OXP_MAPPING_GAMEPAD, 0x20 }, "JOY_R_UP_LEFT" },
91 { { OXP_MAPPING_GAMEPAD, 0x22 }, "BTN_GUIDE" },
92 /* Keyboard Keys */
93 { { OXP_MAPPING_KEYBOARD, 0x01, 0x5a }, "KEY_F1" },
94 { { OXP_MAPPING_KEYBOARD, 0x01, 0x5b }, "KEY_F2" },
95 { { OXP_MAPPING_KEYBOARD, 0x01, 0x5c }, "KEY_F3" },
96 { { OXP_MAPPING_KEYBOARD, 0x01, 0x5d }, "KEY_F4" },
97 { { OXP_MAPPING_KEYBOARD, 0x01, 0x5e }, "KEY_F5" },
98 { { OXP_MAPPING_KEYBOARD, 0x01, 0x5f }, "KEY_F6" },
99 { { OXP_MAPPING_KEYBOARD, 0x01, 0x60 }, "KEY_F7" },
100 { { OXP_MAPPING_KEYBOARD, 0x01, 0x61 }, "KEY_F8" },
101 { { OXP_MAPPING_KEYBOARD, 0x01, 0x62 }, "KEY_F9" },
102 { { OXP_MAPPING_KEYBOARD, 0x01, 0x63 }, "KEY_F10" },
103 { { OXP_MAPPING_KEYBOARD, 0x01, 0x64 }, "KEY_F11" },
104 { { OXP_MAPPING_KEYBOARD, 0x01, 0x65 }, "KEY_F12" },
105 { { OXP_MAPPING_KEYBOARD, 0x01, 0x66 }, "KEY_F13" },
106 { { OXP_MAPPING_KEYBOARD, 0x01, 0x67 }, "KEY_F14" },
107 { { OXP_MAPPING_KEYBOARD, 0x01, 0x68 }, "KEY_F15" },
108 { { OXP_MAPPING_KEYBOARD, 0x01, 0x69 }, "KEY_F16" },
109 { { OXP_MAPPING_KEYBOARD, 0x01, 0x6a }, "KEY_F17" },
110 { { OXP_MAPPING_KEYBOARD, 0x01, 0x6b }, "KEY_F18" },
111 { { OXP_MAPPING_KEYBOARD, 0x01, 0x6c }, "KEY_F19" },
112 { { OXP_MAPPING_KEYBOARD, 0x01, 0x6d }, "KEY_F20" },
113 { { OXP_MAPPING_KEYBOARD, 0x01, 0x6e }, "KEY_F21" },
114 { { OXP_MAPPING_KEYBOARD, 0x01, 0x6f }, "KEY_F22" },
115 { { OXP_MAPPING_KEYBOARD, 0x01, 0x70 }, "KEY_F23" },
116 { { OXP_MAPPING_KEYBOARD, 0x01, 0x71 }, "KEY_F24" },
117 };
118
119 enum oxp_joybutton_index {
120 BUTTON_A = 0x01,
121 BUTTON_B,
122 BUTTON_X,
123 BUTTON_Y,
124 BUTTON_LB,
125 BUTTON_RB,
126 BUTTON_LT,
127 BUTTON_RT,
128 BUTTON_START,
129 BUTTON_SELECT,
130 BUTTON_L3,
131 BUTTON_R3,
132 BUTTON_DUP,
133 BUTTON_DDOWN,
134 BUTTON_DLEFT,
135 BUTTON_DRIGHT,
136 BUTTON_M1 = 0x22,
137 BUTTON_M2,
138 /* These are unused currently, reserved for future devices */
139 BUTTON_M3,
140 BUTTON_M4,
141 BUTTON_M5,
142 BUTTON_M6,
143 };
144
145 struct oxp_button_idx {
146 enum oxp_joybutton_index button_idx;
147 u8 mapping_idx;
148 } __packed;
149
150 struct oxp_bmap_page_1 {
151 struct oxp_button_idx btn_a;
152 struct oxp_button_idx btn_b;
153 struct oxp_button_idx btn_x;
154 struct oxp_button_idx btn_y;
155 struct oxp_button_idx btn_lb;
156 struct oxp_button_idx btn_rb;
157 struct oxp_button_idx btn_lt;
158 struct oxp_button_idx btn_rt;
159 struct oxp_button_idx btn_start;
160 } __packed;
161
162 struct oxp_bmap_page_2 {
163 struct oxp_button_idx btn_select;
164 struct oxp_button_idx btn_l3;
165 struct oxp_button_idx btn_r3;
166 struct oxp_button_idx btn_dup;
167 struct oxp_button_idx btn_ddown;
168 struct oxp_button_idx btn_dleft;
169 struct oxp_button_idx btn_dright;
170 struct oxp_button_idx btn_m1;
171 struct oxp_button_idx btn_m2;
172 } __packed;
173
174 static struct oxp_hid_cfg {
175 struct delayed_work oxp_rgb_queue;
176 struct delayed_work oxp_btn_queue;
177 struct oxp_bmap_page_1 *bmap_1;
178 struct oxp_bmap_page_2 *bmap_2;
179 struct delayed_work oxp_mcu_init;
180 struct led_classdev_mc *led_mc;
181 struct hid_device *hdev;
182 struct mutex cfg_mutex; /*ensure single synchronous output report*/
183 u8 rgb_brightness;
184 u8 gamepad_mode;
185 u8 rumble_intensity;
186 u8 rgb_effect;
187 u8 rgb_speed;
188 u8 rgb_en;
189 } drvdata;
190
191 #define OXP_FILL_PAGE_SLOT(page, btn) \
192 { .button_idx = (page)->btn.button_idx, \
193 .mapping_idx = (page)->btn.mapping_idx }
194
195 enum oxp_gamepad_mode_index {
196 OXP_GP_MODE_XINPUT = 0x00,
197 OXP_GP_MODE_DEBUG = 0x03,
198 };
199
200 static const char *const oxp_gamepad_mode_text[] = {
201 [OXP_GP_MODE_XINPUT] = "xinput",
202 [OXP_GP_MODE_DEBUG] = "debug",
203 };
204
205 enum oxp_feature_en_index {
206 OXP_FEAT_DISABLED,
207 OXP_FEAT_ENABLED,
208 };
209
210 static const char *const oxp_feature_en_text[] = {
211 [OXP_FEAT_DISABLED] = "false",
212 [OXP_FEAT_ENABLED] = "true",
213 };
214
215 enum oxp_rgb_effect_index {
216 OXP_UNKNOWN,
217 OXP_EFFECT_AURORA,
218 OXP_EFFECT_BIRTHDAY,
219 OXP_EFFECT_FLOWING,
220 OXP_EFFECT_CHROMA_1,
221 OXP_EFFECT_NEON,
222 OXP_EFFECT_CHROMA_2,
223 OXP_EFFECT_DREAMY,
224 OXP_EFFECT_WARM,
225 OXP_EFFECT_CYBERPUNK,
226 OXP_EFFECT_SEA,
227 OXP_EFFECT_SUNSET,
228 OXP_EFFECT_COLORFUL,
229 OXP_EFFECT_MONSTER,
230 OXP_EFFECT_GREEN,
231 OXP_EFFECT_BLUE,
232 OXP_EFFECT_YELLOW,
233 OXP_EFFECT_TEAL,
234 OXP_EFFECT_PURPLE,
235 OXP_EFFECT_FOGGY,
236 OXP_EFFECT_MONO_LIST, /* placeholder for effect_index_show */
237 };
238
239 /* These belong to rgb_effect_index, but we want to hide them from
240 * rgb_effect_text
241 */
242
243 #define OXP_GET_PROPERTY 0xfc
244 #define OXP_SET_PROPERTY 0xfd
245 #define OXP_EFFECT_MONO_TRUE 0xfe /* actual index for monocolor */
246
247 static const char *const oxp_rgb_effect_text[] = {
248 [OXP_UNKNOWN] = "unknown",
249 [OXP_EFFECT_AURORA] = "aurora",
250 [OXP_EFFECT_BIRTHDAY] = "birthday_cake",
251 [OXP_EFFECT_FLOWING] = "flowing_light",
252 [OXP_EFFECT_CHROMA_1] = "chroma_popping",
253 [OXP_EFFECT_NEON] = "neon",
254 [OXP_EFFECT_CHROMA_2] = "chroma_breathing",
255 [OXP_EFFECT_DREAMY] = "dreamy",
256 [OXP_EFFECT_WARM] = "warm_sun",
257 [OXP_EFFECT_CYBERPUNK] = "cyberpunk",
258 [OXP_EFFECT_SEA] = "sea_foam",
259 [OXP_EFFECT_SUNSET] = "sunset_afterglow",
260 [OXP_EFFECT_COLORFUL] = "colorful",
261 [OXP_EFFECT_MONSTER] = "monster_woke",
262 [OXP_EFFECT_GREEN] = "green_breathing",
263 [OXP_EFFECT_BLUE] = "blue_breathing",
264 [OXP_EFFECT_YELLOW] = "yellow_breathing",
265 [OXP_EFFECT_TEAL] = "teal_breathing",
266 [OXP_EFFECT_PURPLE] = "purple_breathing",
267 [OXP_EFFECT_FOGGY] = "foggy_haze",
268 [OXP_EFFECT_MONO_LIST] = "monocolor",
269 };
270
271 enum oxp_rumble_side_index {
272 OXP_RUMBLE_LEFT = 0x00,
273 OXP_RUMBLE_RIGHT,
274 };
275
276 struct oxp_gen_1_rgb_report {
277 u8 report_id;
278 u8 message_id;
279 u8 padding_2[2];
280 u8 effect;
281 u8 enabled;
282 u8 speed;
283 u8 brightness;
284 u8 red;
285 u8 green;
286 u8 blue;
287 } __packed;
288
289 struct oxp_gen_2_rgb_report {
290 u8 report_id;
291 u8 header_id;
292 u8 padding_2;
293 u8 message_id;
294 u8 padding_4[2];
295 u8 enabled;
296 u8 speed;
297 u8 brightness;
298 u8 red;
299 u8 green;
300 u8 blue;
301 u8 padding_12[3];
302 u8 effect;
303 } __packed;
304
305 struct oxp_attr {
306 u8 index;
307 };
308
get_usage_page(struct hid_device * hdev)309 static u16 get_usage_page(struct hid_device *hdev)
310 {
311 return hdev->collection[0].usage >> 16;
312 }
313
oxp_hid_raw_event_gen_1(struct hid_device * hdev,struct hid_report * report,u8 * data,int size)314 static int oxp_hid_raw_event_gen_1(struct hid_device *hdev,
315 struct hid_report *report, u8 *data,
316 int size)
317 {
318 struct led_classdev_mc *led_mc = drvdata.led_mc;
319 struct oxp_gen_1_rgb_report *rgb_rep;
320
321 if (data[1] != OXP_FID_GEN1_RGB_REPLY)
322 return 0;
323
324 rgb_rep = (struct oxp_gen_1_rgb_report *)data;
325 /* Ensure we save monocolor as the list value */
326 drvdata.rgb_effect = rgb_rep->effect == OXP_EFFECT_MONO_TRUE ?
327 OXP_EFFECT_MONO_LIST :
328 rgb_rep->effect;
329 drvdata.rgb_speed = rgb_rep->speed;
330 drvdata.rgb_en = rgb_rep->enabled == 0 ? OXP_FEAT_DISABLED :
331 OXP_FEAT_ENABLED;
332 drvdata.rgb_brightness = rgb_rep->brightness;
333 led_mc->led_cdev.brightness = rgb_rep->brightness / 4 *
334 led_mc->led_cdev.max_brightness;
335 /* If monocolor had less than 100% brightness on the previous boot,
336 * there will be no reliable way to determine the real intensity.
337 * Since intensity scaling is used with a hardware brightness set at max,
338 * our brightness will always look like 100%. Use the last set value to
339 * prevent successive boots from lowering the brightness further.
340 * Brightness will be "wrong" but the effect will remain the same visually.
341 */
342 led_mc->subled_info[0].intensity = rgb_rep->red;
343 led_mc->subled_info[1].intensity = rgb_rep->green;
344 led_mc->subled_info[2].intensity = rgb_rep->blue;
345
346 return 0;
347 }
348
349 static int oxp_gen_2_property_out(enum oxp_function_index fid, u8 *data, u8 data_size);
350 static int oxp_set_buttons(void);
351 static int oxp_rumble_intensity_set(u8 intensity);
352
oxp_mcu_init_fn(struct work_struct * work)353 static void oxp_mcu_init_fn(struct work_struct *work)
354 {
355 u8 gp_mode_data[3] = { OXP_GP_MODE_DEBUG, 0x01, 0x02 };
356 int ret;
357
358 /* Re-apply the button mapping */
359 ret = oxp_set_buttons();
360 if (ret)
361 dev_err(&drvdata.hdev->dev,
362 "Error: Failed to set button mapping: %i\n", ret);
363
364 /* Cycle the gamepad mode */
365 ret = oxp_gen_2_property_out(OXP_FID_GEN2_TOGGLE_MODE, gp_mode_data, 3);
366 if (ret)
367 dev_err(&drvdata.hdev->dev,
368 "Error: Failed to set gamepad mode: %i\n", ret);
369
370 /* Remainder only applies for xinput mode */
371 if (drvdata.gamepad_mode == OXP_GP_MODE_DEBUG)
372 return;
373
374 gp_mode_data[0] = OXP_GP_MODE_XINPUT;
375 ret = oxp_gen_2_property_out(OXP_FID_GEN2_TOGGLE_MODE, gp_mode_data, 3);
376 if (ret)
377 dev_err(&drvdata.hdev->dev,
378 "Error: Failed to set gamepad mode: %i\n", ret);
379
380 /* Set vibration level */
381 ret = oxp_rumble_intensity_set(drvdata.rumble_intensity);
382 if (ret)
383 dev_err(&drvdata.hdev->dev,
384 "Error: Failed to set rumble intensity: %i\n", ret);
385 }
386
oxp_hid_raw_event_gen_2(struct hid_device * hdev,struct hid_report * report,u8 * data,int size)387 static int oxp_hid_raw_event_gen_2(struct hid_device *hdev,
388 struct hid_report *report, u8 *data,
389 int size)
390 {
391 struct led_classdev_mc *led_mc = drvdata.led_mc;
392 struct oxp_gen_2_rgb_report *rgb_rep;
393
394 if (data[0] != OXP_FID_GEN2_STATUS_EVENT)
395 return 0;
396
397 /* Sent ~6s after resume event, indicating the MCU has fully reset.
398 * Re-apply our settings after this has been received.
399 */
400 if (data[3] == OXP_EFFECT_MONO_TRUE) {
401 mod_delayed_work(system_dfl_wq, &drvdata.oxp_mcu_init, msecs_to_jiffies(50));
402 return 0;
403 }
404
405 if (data[3] != OXP_GET_PROPERTY)
406 return 0;
407
408 rgb_rep = (struct oxp_gen_2_rgb_report *)data;
409 /* Ensure we save monocolor as the list value */
410 drvdata.rgb_effect = rgb_rep->effect == OXP_EFFECT_MONO_TRUE ?
411 OXP_EFFECT_MONO_LIST :
412 rgb_rep->effect;
413 drvdata.rgb_speed = rgb_rep->speed;
414 drvdata.rgb_en = rgb_rep->enabled == 0 ? OXP_FEAT_DISABLED :
415 OXP_FEAT_ENABLED;
416 drvdata.rgb_brightness = rgb_rep->brightness;
417 led_mc->led_cdev.brightness = rgb_rep->brightness / 4 *
418 led_mc->led_cdev.max_brightness;
419 /* If monocolor had less than 100% brightness on the previous boot,
420 * there will be no reliable way to determine the real intensity.
421 * Since intensity scaling is used with a hardware brightness set at max,
422 * our brightness will always look like 100%. Use the last set value to
423 * prevent successive boots from lowering the brightness further.
424 * Brightness will be "wrong" but the effect will remain the same visually.
425 */
426 led_mc->subled_info[0].intensity = rgb_rep->red;
427 led_mc->subled_info[1].intensity = rgb_rep->green;
428 led_mc->subled_info[2].intensity = rgb_rep->blue;
429
430 return 0;
431 }
432
oxp_hid_raw_event(struct hid_device * hdev,struct hid_report * report,u8 * data,int size)433 static int oxp_hid_raw_event(struct hid_device *hdev, struct hid_report *report,
434 u8 *data, int size)
435 {
436 u16 up = get_usage_page(hdev);
437
438 dev_dbg(&hdev->dev, "raw event data: [%*ph]\n", OXP_PACKET_SIZE, data);
439
440 switch (up) {
441 case GEN1_USAGE_PAGE:
442 return oxp_hid_raw_event_gen_1(hdev, report, data, size);
443 case GEN2_USAGE_PAGE:
444 return oxp_hid_raw_event_gen_2(hdev, report, data, size);
445 default:
446 break;
447 }
448
449 return 0;
450 }
451
mcu_property_out(u8 * header,size_t header_size,u8 * data,size_t data_size,u8 * footer,size_t footer_size)452 static int mcu_property_out(u8 *header, size_t header_size, u8 *data,
453 size_t data_size, u8 *footer, size_t footer_size)
454 {
455 unsigned char *dmabuf __free(kfree) = kzalloc(OXP_PACKET_SIZE, GFP_KERNEL);
456 int ret;
457
458 if (!dmabuf)
459 return -ENOMEM;
460
461 if (header_size + data_size + footer_size > OXP_PACKET_SIZE)
462 return -EINVAL;
463
464 guard(mutex)(&drvdata.cfg_mutex);
465 memcpy(dmabuf, header, header_size);
466 memcpy(dmabuf + header_size, data, data_size);
467 if (footer_size)
468 memcpy(dmabuf + OXP_PACKET_SIZE - footer_size, footer, footer_size);
469
470 dev_dbg(&drvdata.hdev->dev, "raw data: [%*ph]\n", OXP_PACKET_SIZE, dmabuf);
471
472 ret = hid_hw_output_report(drvdata.hdev, dmabuf, OXP_PACKET_SIZE);
473 if (ret < 0)
474 return ret;
475
476 /* MCU takes 200ms to be ready for another command. */
477 msleep(200);
478 return ret == OXP_PACKET_SIZE ? 0 : -EIO;
479 }
480
oxp_gen_1_property_out(enum oxp_function_index fid,u8 * data,u8 data_size)481 static int oxp_gen_1_property_out(enum oxp_function_index fid, u8 *data,
482 u8 data_size)
483 {
484 u8 header[] = { fid, GEN1_MESSAGE_ID };
485 size_t header_size = ARRAY_SIZE(header);
486
487 return mcu_property_out(header, header_size, data, data_size, NULL, 0);
488 }
489
oxp_gen_2_property_out(enum oxp_function_index fid,u8 * data,u8 data_size)490 static int oxp_gen_2_property_out(enum oxp_function_index fid, u8 *data,
491 u8 data_size)
492 {
493 u8 header[] = { fid, GEN2_MESSAGE_ID, 0x01 };
494 u8 footer[] = { GEN2_MESSAGE_ID, fid };
495 size_t header_size = ARRAY_SIZE(header);
496 size_t footer_size = ARRAY_SIZE(footer);
497
498 return mcu_property_out(header, header_size, data, data_size, footer,
499 footer_size);
500 }
501
gamepad_mode_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)502 static ssize_t gamepad_mode_store(struct device *dev,
503 struct device_attribute *attr, const char *buf,
504 size_t count)
505 {
506 u16 up = get_usage_page(drvdata.hdev);
507 u8 data[3] = { 0x00, 0x01, 0x02 };
508 int ret = -EINVAL;
509 int i;
510
511 if (up != GEN2_USAGE_PAGE)
512 return ret;
513
514 for (i = 0; i < ARRAY_SIZE(oxp_gamepad_mode_text); i++) {
515 if (oxp_gamepad_mode_text[i] && sysfs_streq(buf, oxp_gamepad_mode_text[i])) {
516 ret = i;
517 break;
518 }
519 }
520 if (ret < 0)
521 return ret;
522
523 data[0] = ret;
524
525 ret = oxp_gen_2_property_out(OXP_FID_GEN2_TOGGLE_MODE, data, 3);
526 if (ret)
527 return ret;
528
529 drvdata.gamepad_mode = data[0];
530
531 if (drvdata.gamepad_mode == OXP_GP_MODE_DEBUG)
532 return count;
533
534 /* Re-apply rumble settings as switching gamepad mode will override */
535 ret = oxp_rumble_intensity_set(drvdata.rumble_intensity);
536 if (ret)
537 return ret;
538
539 return count;
540 }
541
gamepad_mode_show(struct device * dev,struct device_attribute * attr,char * buf)542 static ssize_t gamepad_mode_show(struct device *dev,
543 struct device_attribute *attr, char *buf)
544 {
545 return sysfs_emit(buf, "%s\n", oxp_gamepad_mode_text[drvdata.gamepad_mode]);
546 }
547 static DEVICE_ATTR_RW(gamepad_mode);
548
gamepad_mode_index_show(struct device * dev,struct device_attribute * attr,char * buf)549 static ssize_t gamepad_mode_index_show(struct device *dev,
550 struct device_attribute *attr,
551 char *buf)
552 {
553 ssize_t count = 0;
554 unsigned int i;
555
556 for (i = 0; i < ARRAY_SIZE(oxp_gamepad_mode_text); i++) {
557 if (!oxp_gamepad_mode_text[i] ||
558 oxp_gamepad_mode_text[i][0] == '\0')
559 continue;
560
561 count += sysfs_emit_at(buf, count, "%s ", oxp_gamepad_mode_text[i]);
562 }
563
564 if (count)
565 buf[count - 1] = '\n';
566
567 return count;
568 }
569 static DEVICE_ATTR_RO(gamepad_mode_index);
570
oxp_set_defaults_bmap_1(struct oxp_bmap_page_1 * bmap)571 static void oxp_set_defaults_bmap_1(struct oxp_bmap_page_1 *bmap)
572 {
573 bmap->btn_a.button_idx = BUTTON_A;
574 bmap->btn_a.mapping_idx = 0;
575 bmap->btn_b.button_idx = BUTTON_B;
576 bmap->btn_b.mapping_idx = 1;
577 bmap->btn_x.button_idx = BUTTON_X;
578 bmap->btn_x.mapping_idx = 2;
579 bmap->btn_y.button_idx = BUTTON_Y;
580 bmap->btn_y.mapping_idx = 3;
581 bmap->btn_lb.button_idx = BUTTON_LB;
582 bmap->btn_lb.mapping_idx = 4;
583 bmap->btn_rb.button_idx = BUTTON_RB;
584 bmap->btn_rb.mapping_idx = 5;
585 bmap->btn_lt.button_idx = BUTTON_LT;
586 bmap->btn_lt.mapping_idx = 6;
587 bmap->btn_rt.button_idx = BUTTON_RT;
588 bmap->btn_rt.mapping_idx = 7;
589 bmap->btn_start.button_idx = BUTTON_START;
590 bmap->btn_start.mapping_idx = 8;
591 }
592
oxp_set_defaults_bmap_2(struct oxp_bmap_page_2 * bmap)593 static void oxp_set_defaults_bmap_2(struct oxp_bmap_page_2 *bmap)
594 {
595 bmap->btn_select.button_idx = BUTTON_SELECT;
596 bmap->btn_select.mapping_idx = 9;
597 bmap->btn_l3.button_idx = BUTTON_L3;
598 bmap->btn_l3.mapping_idx = 10;
599 bmap->btn_r3.button_idx = BUTTON_R3;
600 bmap->btn_r3.mapping_idx = 11;
601 bmap->btn_dup.button_idx = BUTTON_DUP;
602 bmap->btn_dup.mapping_idx = 12;
603 bmap->btn_ddown.button_idx = BUTTON_DDOWN;
604 bmap->btn_ddown.mapping_idx = 13;
605 bmap->btn_dleft.button_idx = BUTTON_DLEFT;
606 bmap->btn_dleft.mapping_idx = 14;
607 bmap->btn_dright.button_idx = BUTTON_DRIGHT;
608 bmap->btn_dright.mapping_idx = 15;
609 bmap->btn_m1.button_idx = BUTTON_M1;
610 bmap->btn_m1.mapping_idx = 48; /* KEY_F15 */
611 bmap->btn_m2.button_idx = BUTTON_M2;
612 bmap->btn_m2.mapping_idx = 49; /* KEY_F16 */
613 }
614
oxp_page_fill_data(char * buf,const struct oxp_button_idx * buttons,size_t len)615 static void oxp_page_fill_data(char *buf, const struct oxp_button_idx *buttons,
616 size_t len)
617 {
618 size_t offset_increment = sizeof(u8) + sizeof(struct oxp_button_idx);
619 size_t offset = 5;
620 unsigned int i;
621
622 for (i = 0; i < len; i++, offset += offset_increment) {
623 buf[offset] = (u8)buttons[i].button_idx;
624 memcpy(buf + offset + 1,
625 &oxp_button_table[buttons[i].mapping_idx].data,
626 sizeof(struct oxp_button_data));
627 }
628 }
629
oxp_set_buttons(void)630 static int oxp_set_buttons(void)
631 {
632 u8 page_1[59] = { 0x02, 0x38, 0x20, 0x01, 0x01 };
633 u8 page_2[59] = { 0x02, 0x38, 0x20, 0x02, 0x01 };
634 u16 up = get_usage_page(drvdata.hdev);
635 int ret;
636
637 if (up != GEN2_USAGE_PAGE)
638 return -EINVAL;
639
640 const struct oxp_button_idx p1[] = {
641 OXP_FILL_PAGE_SLOT(drvdata.bmap_1, btn_a),
642 OXP_FILL_PAGE_SLOT(drvdata.bmap_1, btn_b),
643 OXP_FILL_PAGE_SLOT(drvdata.bmap_1, btn_x),
644 OXP_FILL_PAGE_SLOT(drvdata.bmap_1, btn_y),
645 OXP_FILL_PAGE_SLOT(drvdata.bmap_1, btn_lb),
646 OXP_FILL_PAGE_SLOT(drvdata.bmap_1, btn_rb),
647 OXP_FILL_PAGE_SLOT(drvdata.bmap_1, btn_lt),
648 OXP_FILL_PAGE_SLOT(drvdata.bmap_1, btn_rt),
649 OXP_FILL_PAGE_SLOT(drvdata.bmap_1, btn_start),
650 };
651
652 const struct oxp_button_idx p2[] = {
653 OXP_FILL_PAGE_SLOT(drvdata.bmap_2, btn_select),
654 OXP_FILL_PAGE_SLOT(drvdata.bmap_2, btn_l3),
655 OXP_FILL_PAGE_SLOT(drvdata.bmap_2, btn_r3),
656 OXP_FILL_PAGE_SLOT(drvdata.bmap_2, btn_dup),
657 OXP_FILL_PAGE_SLOT(drvdata.bmap_2, btn_ddown),
658 OXP_FILL_PAGE_SLOT(drvdata.bmap_2, btn_dleft),
659 OXP_FILL_PAGE_SLOT(drvdata.bmap_2, btn_dright),
660 OXP_FILL_PAGE_SLOT(drvdata.bmap_2, btn_m1),
661 OXP_FILL_PAGE_SLOT(drvdata.bmap_2, btn_m2),
662 };
663
664 oxp_page_fill_data(page_1, p1, ARRAY_SIZE(p1));
665 oxp_page_fill_data(page_2, p2, ARRAY_SIZE(p2));
666
667 ret = oxp_gen_2_property_out(OXP_FID_GEN2_KEY_STATE, page_1, ARRAY_SIZE(page_1));
668 if (ret)
669 return ret;
670
671 return oxp_gen_2_property_out(OXP_FID_GEN2_KEY_STATE, page_2, ARRAY_SIZE(page_2));
672 }
673
oxp_reset_buttons(void)674 static void oxp_reset_buttons(void)
675 {
676 oxp_set_defaults_bmap_1(drvdata.bmap_1);
677 oxp_set_defaults_bmap_2(drvdata.bmap_2);
678 }
679
reset_buttons_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)680 static ssize_t reset_buttons_store(struct device *dev,
681 struct device_attribute *attr, const char *buf,
682 size_t count)
683 {
684 int val, ret;
685
686 ret = kstrtoint(buf, 10, &val);
687 if (ret)
688 return ret;
689
690 if (val != 1)
691 return -EINVAL;
692
693 oxp_reset_buttons();
694 ret = oxp_set_buttons();
695 if (ret)
696 return ret;
697
698 return count;
699 }
700 static DEVICE_ATTR_WO(reset_buttons);
701
oxp_btn_queue_fn(struct work_struct * work)702 static void oxp_btn_queue_fn(struct work_struct *work)
703 {
704 int ret;
705
706 ret = oxp_set_buttons();
707 if (ret)
708 dev_err(&drvdata.hdev->dev,
709 "Error: Failed to write button mapping: %i\n", ret);
710 }
711
oxp_button_idx_from_str(const char * buf)712 static int oxp_button_idx_from_str(const char *buf)
713 {
714 int i;
715
716 for (i = 0; i < ARRAY_SIZE(oxp_button_table); i++)
717 if (sysfs_streq(buf, oxp_button_table[i].name))
718 return i;
719
720 return -EINVAL;
721 }
722
map_button_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count,u8 index)723 static ssize_t map_button_store(struct device *dev,
724 struct device_attribute *attr, const char *buf,
725 size_t count, u8 index)
726 {
727 int idx;
728
729 idx = oxp_button_idx_from_str(buf);
730 if (idx < 0)
731 return idx;
732
733 switch (index) {
734 case BUTTON_A:
735 drvdata.bmap_1->btn_a.mapping_idx = idx;
736 break;
737 case BUTTON_B:
738 drvdata.bmap_1->btn_b.mapping_idx = idx;
739 break;
740 case BUTTON_X:
741 drvdata.bmap_1->btn_x.mapping_idx = idx;
742 break;
743 case BUTTON_Y:
744 drvdata.bmap_1->btn_y.mapping_idx = idx;
745 break;
746 case BUTTON_LB:
747 drvdata.bmap_1->btn_lb.mapping_idx = idx;
748 break;
749 case BUTTON_RB:
750 drvdata.bmap_1->btn_rb.mapping_idx = idx;
751 break;
752 case BUTTON_LT:
753 drvdata.bmap_1->btn_lt.mapping_idx = idx;
754 break;
755 case BUTTON_RT:
756 drvdata.bmap_1->btn_rt.mapping_idx = idx;
757 break;
758 case BUTTON_START:
759 drvdata.bmap_1->btn_start.mapping_idx = idx;
760 break;
761 case BUTTON_SELECT:
762 drvdata.bmap_2->btn_select.mapping_idx = idx;
763 break;
764 case BUTTON_L3:
765 drvdata.bmap_2->btn_l3.mapping_idx = idx;
766 break;
767 case BUTTON_R3:
768 drvdata.bmap_2->btn_r3.mapping_idx = idx;
769 break;
770 case BUTTON_DUP:
771 drvdata.bmap_2->btn_dup.mapping_idx = idx;
772 break;
773 case BUTTON_DDOWN:
774 drvdata.bmap_2->btn_ddown.mapping_idx = idx;
775 break;
776 case BUTTON_DLEFT:
777 drvdata.bmap_2->btn_dleft.mapping_idx = idx;
778 break;
779 case BUTTON_DRIGHT:
780 drvdata.bmap_2->btn_dright.mapping_idx = idx;
781 break;
782 case BUTTON_M1:
783 drvdata.bmap_2->btn_m1.mapping_idx = idx;
784 break;
785 case BUTTON_M2:
786 drvdata.bmap_2->btn_m2.mapping_idx = idx;
787 break;
788 default:
789 return -EINVAL;
790 }
791 mod_delayed_work(system_dfl_wq, &drvdata.oxp_btn_queue, msecs_to_jiffies(50));
792 return count;
793 }
794
map_button_show(struct device * dev,struct device_attribute * attr,char * buf,u8 index)795 static ssize_t map_button_show(struct device *dev,
796 struct device_attribute *attr, char *buf,
797 u8 index)
798 {
799 u8 i;
800
801 switch (index) {
802 case BUTTON_A:
803 i = drvdata.bmap_1->btn_a.mapping_idx;
804 break;
805 case BUTTON_B:
806 i = drvdata.bmap_1->btn_b.mapping_idx;
807 break;
808 case BUTTON_X:
809 i = drvdata.bmap_1->btn_x.mapping_idx;
810 break;
811 case BUTTON_Y:
812 i = drvdata.bmap_1->btn_y.mapping_idx;
813 break;
814 case BUTTON_LB:
815 i = drvdata.bmap_1->btn_lb.mapping_idx;
816 break;
817 case BUTTON_RB:
818 i = drvdata.bmap_1->btn_rb.mapping_idx;
819 break;
820 case BUTTON_LT:
821 i = drvdata.bmap_1->btn_lt.mapping_idx;
822 break;
823 case BUTTON_RT:
824 i = drvdata.bmap_1->btn_rt.mapping_idx;
825 break;
826 case BUTTON_START:
827 i = drvdata.bmap_1->btn_start.mapping_idx;
828 break;
829 case BUTTON_SELECT:
830 i = drvdata.bmap_2->btn_select.mapping_idx;
831 break;
832 case BUTTON_L3:
833 i = drvdata.bmap_2->btn_l3.mapping_idx;
834 break;
835 case BUTTON_R3:
836 i = drvdata.bmap_2->btn_r3.mapping_idx;
837 break;
838 case BUTTON_DUP:
839 i = drvdata.bmap_2->btn_dup.mapping_idx;
840 break;
841 case BUTTON_DDOWN:
842 i = drvdata.bmap_2->btn_ddown.mapping_idx;
843 break;
844 case BUTTON_DLEFT:
845 i = drvdata.bmap_2->btn_dleft.mapping_idx;
846 break;
847 case BUTTON_DRIGHT:
848 i = drvdata.bmap_2->btn_dright.mapping_idx;
849 break;
850 case BUTTON_M1:
851 i = drvdata.bmap_2->btn_m1.mapping_idx;
852 break;
853 case BUTTON_M2:
854 i = drvdata.bmap_2->btn_m2.mapping_idx;
855 break;
856 default:
857 return -EINVAL;
858 }
859
860 if (i >= ARRAY_SIZE(oxp_button_table))
861 return -EINVAL;
862
863 return sysfs_emit(buf, "%s\n", oxp_button_table[i].name);
864 }
865
button_mapping_options_show(struct device * dev,struct device_attribute * attr,char * buf)866 static ssize_t button_mapping_options_show(struct device *dev,
867 struct device_attribute *attr, char *buf)
868 {
869 ssize_t count = 0;
870 unsigned int i;
871
872 for (i = 0; i < ARRAY_SIZE(oxp_button_table); i++)
873 count += sysfs_emit_at(buf, count, "%s ", oxp_button_table[i].name);
874
875 if (count)
876 buf[count - 1] = '\n';
877
878 return count;
879 }
880 static DEVICE_ATTR_RO(button_mapping_options);
881
oxp_rumble_intensity_set(u8 intensity)882 static int oxp_rumble_intensity_set(u8 intensity)
883 {
884 u8 header[15] = { 0x02, 0x38, 0x02, 0xe3, 0x39, 0xe3, 0x39, 0xe3,
885 0x39, 0x01, intensity, 0x05, 0xe3, 0x39, 0xe3 };
886 u8 footer[9] = { 0x39, 0xe3, 0x39, 0xe3, 0xe3, 0x02, 0x04, 0x39, 0x39 };
887 size_t footer_size = ARRAY_SIZE(footer);
888 size_t header_size = ARRAY_SIZE(header);
889 u8 data[59] = { 0x0 };
890 size_t data_size = ARRAY_SIZE(data);
891
892 memcpy(data, header, header_size);
893 memcpy(data + data_size - footer_size, footer, footer_size);
894
895 return oxp_gen_2_property_out(OXP_FID_GEN2_RUMBLE_SET, data, data_size);
896 }
897
rumble_intensity_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)898 static ssize_t rumble_intensity_store(struct device *dev,
899 struct device_attribute *attr, const char *buf,
900 size_t count)
901 {
902 int ret;
903 u8 val;
904
905 ret = kstrtou8(buf, 10, &val);
906 if (ret)
907 return ret;
908
909 if (val < 0 || val > 5)
910 return -EINVAL;
911
912 ret = oxp_rumble_intensity_set(val);
913 if (ret)
914 return ret;
915
916 drvdata.rumble_intensity = val;
917
918 return count;
919 }
920
rumble_intensity_show(struct device * dev,struct device_attribute * attr,char * buf)921 static ssize_t rumble_intensity_show(struct device *dev,
922 struct device_attribute *attr, char *buf)
923 {
924 return sysfs_emit(buf, "%i\n", drvdata.rumble_intensity);
925 }
926 static DEVICE_ATTR_RW(rumble_intensity);
927
rumble_intensity_range_show(struct device * dev,struct device_attribute * attr,char * buf)928 static ssize_t rumble_intensity_range_show(struct device *dev,
929 struct device_attribute *attr, char *buf)
930 {
931 return sysfs_emit(buf, "0-5\n");
932 }
933 static DEVICE_ATTR_RO(rumble_intensity_range);
934
935 #define OXP_DEVICE_ATTR_RW(_name, _group) \
936 static ssize_t _name##_store(struct device *dev, \
937 struct device_attribute *attr, \
938 const char *buf, size_t count) \
939 { \
940 return _group##_store(dev, attr, buf, count, _name.index); \
941 } \
942 static ssize_t _name##_show(struct device *dev, \
943 struct device_attribute *attr, char *buf) \
944 { \
945 return _group##_show(dev, attr, buf, _name.index); \
946 } \
947 static DEVICE_ATTR_RW(_name)
948
949 static struct oxp_attr button_a = { BUTTON_A };
950 OXP_DEVICE_ATTR_RW(button_a, map_button);
951
952 static struct oxp_attr button_b = { BUTTON_B };
953 OXP_DEVICE_ATTR_RW(button_b, map_button);
954
955 static struct oxp_attr button_x = { BUTTON_X };
956 OXP_DEVICE_ATTR_RW(button_x, map_button);
957
958 static struct oxp_attr button_y = { BUTTON_Y };
959 OXP_DEVICE_ATTR_RW(button_y, map_button);
960
961 static struct oxp_attr button_lb = { BUTTON_LB };
962 OXP_DEVICE_ATTR_RW(button_lb, map_button);
963
964 static struct oxp_attr button_rb = { BUTTON_RB };
965 OXP_DEVICE_ATTR_RW(button_rb, map_button);
966
967 static struct oxp_attr button_lt = { BUTTON_LT };
968 OXP_DEVICE_ATTR_RW(button_lt, map_button);
969
970 static struct oxp_attr button_rt = { BUTTON_RT };
971 OXP_DEVICE_ATTR_RW(button_rt, map_button);
972
973 static struct oxp_attr button_start = { BUTTON_START };
974 OXP_DEVICE_ATTR_RW(button_start, map_button);
975
976 static struct oxp_attr button_select = { BUTTON_SELECT };
977 OXP_DEVICE_ATTR_RW(button_select, map_button);
978
979 static struct oxp_attr button_l3 = { BUTTON_L3 };
980 OXP_DEVICE_ATTR_RW(button_l3, map_button);
981
982 static struct oxp_attr button_r3 = { BUTTON_R3 };
983 OXP_DEVICE_ATTR_RW(button_r3, map_button);
984
985 static struct oxp_attr button_d_up = { BUTTON_DUP };
986 OXP_DEVICE_ATTR_RW(button_d_up, map_button);
987
988 static struct oxp_attr button_d_down = { BUTTON_DDOWN };
989 OXP_DEVICE_ATTR_RW(button_d_down, map_button);
990
991 static struct oxp_attr button_d_left = { BUTTON_DLEFT };
992 OXP_DEVICE_ATTR_RW(button_d_left, map_button);
993
994 static struct oxp_attr button_d_right = { BUTTON_DRIGHT };
995 OXP_DEVICE_ATTR_RW(button_d_right, map_button);
996
997 static struct oxp_attr button_m1 = { BUTTON_M1 };
998 OXP_DEVICE_ATTR_RW(button_m1, map_button);
999
1000 static struct oxp_attr button_m2 = { BUTTON_M2 };
1001 OXP_DEVICE_ATTR_RW(button_m2, map_button);
1002
1003 static struct attribute *oxp_cfg_attrs[] = {
1004 &dev_attr_button_a.attr,
1005 &dev_attr_button_b.attr,
1006 &dev_attr_button_d_down.attr,
1007 &dev_attr_button_d_left.attr,
1008 &dev_attr_button_d_right.attr,
1009 &dev_attr_button_d_up.attr,
1010 &dev_attr_button_l3.attr,
1011 &dev_attr_button_lb.attr,
1012 &dev_attr_button_lt.attr,
1013 &dev_attr_button_m1.attr,
1014 &dev_attr_button_m2.attr,
1015 &dev_attr_button_mapping_options.attr,
1016 &dev_attr_button_r3.attr,
1017 &dev_attr_button_rb.attr,
1018 &dev_attr_button_rt.attr,
1019 &dev_attr_button_select.attr,
1020 &dev_attr_button_start.attr,
1021 &dev_attr_button_x.attr,
1022 &dev_attr_button_y.attr,
1023 &dev_attr_gamepad_mode.attr,
1024 &dev_attr_gamepad_mode_index.attr,
1025 &dev_attr_reset_buttons.attr,
1026 &dev_attr_rumble_intensity.attr,
1027 &dev_attr_rumble_intensity_range.attr,
1028 NULL,
1029 };
1030
1031 static const struct attribute_group oxp_cfg_attrs_group = {
1032 .attrs = oxp_cfg_attrs,
1033 };
1034
oxp_rgb_status_store(u8 enabled,u8 speed,u8 brightness)1035 static int oxp_rgb_status_store(u8 enabled, u8 speed, u8 brightness)
1036 {
1037 u16 up = get_usage_page(drvdata.hdev);
1038 u8 *data;
1039
1040 /* Always default to max brightness and use intensity scaling when in
1041 * monocolor mode.
1042 */
1043 switch (up) {
1044 case GEN1_USAGE_PAGE:
1045 data = (u8[4]) { OXP_SET_PROPERTY, enabled, speed, brightness };
1046 if (drvdata.rgb_effect == OXP_EFFECT_MONO_LIST)
1047 data[3] = 0x04;
1048 return oxp_gen_1_property_out(OXP_FID_GEN1_RGB_SET, data, 4);
1049 case GEN2_USAGE_PAGE:
1050 data = (u8[6]) { OXP_SET_PROPERTY, 0x00, 0x02, enabled, speed, brightness };
1051 if (drvdata.rgb_effect == OXP_EFFECT_MONO_LIST)
1052 data[5] = 0x04;
1053 return oxp_gen_2_property_out(OXP_FID_GEN2_STATUS_EVENT, data, 6);
1054 default:
1055 return -ENODEV;
1056 }
1057 }
1058
oxp_rgb_status_show(void)1059 static ssize_t oxp_rgb_status_show(void)
1060 {
1061 u16 up = get_usage_page(drvdata.hdev);
1062 u8 *data;
1063
1064 switch (up) {
1065 case GEN1_USAGE_PAGE:
1066 data = (u8[1]) { OXP_GET_PROPERTY };
1067 return oxp_gen_1_property_out(OXP_FID_GEN1_RGB_SET, data, 1);
1068 case GEN2_USAGE_PAGE:
1069 data = (u8[3]) { OXP_GET_PROPERTY, 0x00, 0x02 };
1070 return oxp_gen_2_property_out(OXP_FID_GEN2_STATUS_EVENT, data, 3);
1071 default:
1072 return -ENODEV;
1073 }
1074 }
1075
oxp_rgb_color_set(void)1076 static int oxp_rgb_color_set(void)
1077 {
1078 u8 max_br = drvdata.led_mc->led_cdev.max_brightness;
1079 u8 br = drvdata.led_mc->led_cdev.brightness;
1080 u16 up = get_usage_page(drvdata.hdev);
1081 u8 green, red, blue;
1082 size_t size;
1083 u8 *data;
1084 int i;
1085
1086 red = br * drvdata.led_mc->subled_info[0].intensity / max_br;
1087 green = br * drvdata.led_mc->subled_info[1].intensity / max_br;
1088 blue = br * drvdata.led_mc->subled_info[2].intensity / max_br;
1089
1090 switch (up) {
1091 case GEN1_USAGE_PAGE:
1092 size = 55;
1093 data = (u8[55]) { OXP_EFFECT_MONO_TRUE };
1094
1095 for (i = 0; i < (size - 1) / 3; i++) {
1096 data[3 * i + 1] = red;
1097 data[3 * i + 2] = green;
1098 data[3 * i + 3] = blue;
1099 }
1100 return oxp_gen_1_property_out(OXP_FID_GEN1_RGB_SET, data, size);
1101 case GEN2_USAGE_PAGE:
1102 size = 57;
1103 data = (u8[57]) { OXP_EFFECT_MONO_TRUE, 0x00, 0x02 };
1104
1105 for (i = 1; i < size / 3; i++) {
1106 data[3 * i] = red;
1107 data[3 * i + 1] = green;
1108 data[3 * i + 2] = blue;
1109 }
1110 return oxp_gen_2_property_out(OXP_FID_GEN2_STATUS_EVENT, data, size);
1111 default:
1112 return -ENODEV;
1113 }
1114 }
1115
oxp_rgb_effect_set(u8 effect)1116 static int oxp_rgb_effect_set(u8 effect)
1117 {
1118 u16 up = get_usage_page(drvdata.hdev);
1119 u8 *data;
1120 int ret;
1121
1122 switch (effect) {
1123 case OXP_EFFECT_AURORA:
1124 case OXP_EFFECT_BIRTHDAY:
1125 case OXP_EFFECT_FLOWING:
1126 case OXP_EFFECT_CHROMA_1:
1127 case OXP_EFFECT_NEON:
1128 case OXP_EFFECT_CHROMA_2:
1129 case OXP_EFFECT_DREAMY:
1130 case OXP_EFFECT_WARM:
1131 case OXP_EFFECT_CYBERPUNK:
1132 case OXP_EFFECT_SEA:
1133 case OXP_EFFECT_SUNSET:
1134 case OXP_EFFECT_COLORFUL:
1135 case OXP_EFFECT_MONSTER:
1136 case OXP_EFFECT_GREEN:
1137 case OXP_EFFECT_BLUE:
1138 case OXP_EFFECT_YELLOW:
1139 case OXP_EFFECT_TEAL:
1140 case OXP_EFFECT_PURPLE:
1141 case OXP_EFFECT_FOGGY:
1142 switch (up) {
1143 case GEN1_USAGE_PAGE:
1144 data = (u8[1]) { effect };
1145 ret = oxp_gen_1_property_out(OXP_FID_GEN1_RGB_SET, data, 1);
1146 break;
1147 case GEN2_USAGE_PAGE:
1148 data = (u8[3]) { effect, 0x00, 0x02 };
1149 ret = oxp_gen_2_property_out(OXP_FID_GEN2_STATUS_EVENT, data, 3);
1150 break;
1151 default:
1152 ret = -ENODEV;
1153 }
1154 break;
1155 case OXP_EFFECT_MONO_LIST:
1156 ret = oxp_rgb_color_set();
1157 break;
1158 default:
1159 return -EINVAL;
1160 }
1161
1162 if (ret)
1163 return ret;
1164
1165 drvdata.rgb_effect = effect;
1166
1167 return 0;
1168 }
1169
enabled_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1170 static ssize_t enabled_store(struct device *dev, struct device_attribute *attr,
1171 const char *buf, size_t count)
1172 {
1173 int ret;
1174 u8 val;
1175
1176 ret = sysfs_match_string(oxp_feature_en_text, buf);
1177 if (ret < 0)
1178 return ret;
1179 val = ret;
1180
1181 ret = oxp_rgb_status_store(val, drvdata.rgb_speed,
1182 drvdata.rgb_brightness);
1183 if (ret)
1184 return ret;
1185
1186 drvdata.rgb_en = val;
1187 return count;
1188 }
1189
enabled_show(struct device * dev,struct device_attribute * attr,char * buf)1190 static ssize_t enabled_show(struct device *dev, struct device_attribute *attr,
1191 char *buf)
1192 {
1193 int ret;
1194
1195 ret = oxp_rgb_status_show();
1196 if (ret)
1197 return ret;
1198
1199 if (drvdata.rgb_en >= ARRAY_SIZE(oxp_feature_en_text))
1200 return -EINVAL;
1201
1202 return sysfs_emit(buf, "%s\n", oxp_feature_en_text[drvdata.rgb_en]);
1203 }
1204 static DEVICE_ATTR_RW(enabled);
1205
enabled_index_show(struct device * dev,struct device_attribute * attr,char * buf)1206 static ssize_t enabled_index_show(struct device *dev,
1207 struct device_attribute *attr, char *buf)
1208 {
1209 size_t count = 0;
1210 unsigned int i;
1211
1212 for (i = 0; i < ARRAY_SIZE(oxp_feature_en_text); i++)
1213 count += sysfs_emit_at(buf, count, "%s ", oxp_feature_en_text[i]);
1214
1215 if (count)
1216 buf[count - 1] = '\n';
1217
1218 return count;
1219 }
1220 static DEVICE_ATTR_RO(enabled_index);
1221
effect_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1222 static ssize_t effect_store(struct device *dev, struct device_attribute *attr,
1223 const char *buf, size_t count)
1224 {
1225 int ret;
1226 u8 val;
1227
1228 ret = sysfs_match_string(oxp_rgb_effect_text, buf);
1229 if (ret < 0)
1230 return ret;
1231
1232 val = ret;
1233
1234 ret = oxp_rgb_status_store(drvdata.rgb_en, drvdata.rgb_speed,
1235 drvdata.rgb_brightness);
1236 if (ret)
1237 return ret;
1238
1239 ret = oxp_rgb_effect_set(val);
1240 if (ret)
1241 return ret;
1242
1243 return count;
1244 }
1245
effect_show(struct device * dev,struct device_attribute * attr,char * buf)1246 static ssize_t effect_show(struct device *dev, struct device_attribute *attr,
1247 char *buf)
1248 {
1249 int ret;
1250
1251 ret = oxp_rgb_status_show();
1252 if (ret)
1253 return ret;
1254
1255 if (drvdata.rgb_effect >= ARRAY_SIZE(oxp_rgb_effect_text))
1256 return -EINVAL;
1257
1258 return sysfs_emit(buf, "%s\n", oxp_rgb_effect_text[drvdata.rgb_effect]);
1259 }
1260
1261 static DEVICE_ATTR_RW(effect);
1262
effect_index_show(struct device * dev,struct device_attribute * attr,char * buf)1263 static ssize_t effect_index_show(struct device *dev,
1264 struct device_attribute *attr, char *buf)
1265 {
1266 size_t count = 0;
1267 unsigned int i;
1268
1269 for (i = 1; i < ARRAY_SIZE(oxp_rgb_effect_text); i++)
1270 count += sysfs_emit_at(buf, count, "%s ", oxp_rgb_effect_text[i]);
1271
1272 if (count)
1273 buf[count - 1] = '\n';
1274
1275 return count;
1276 }
1277 static DEVICE_ATTR_RO(effect_index);
1278
speed_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1279 static ssize_t speed_store(struct device *dev, struct device_attribute *attr,
1280 const char *buf, size_t count)
1281 {
1282 int ret;
1283 u8 val;
1284
1285 ret = kstrtou8(buf, 10, &val);
1286 if (ret)
1287 return ret;
1288
1289 if (val > 9)
1290 return -EINVAL;
1291
1292 ret = oxp_rgb_status_store(drvdata.rgb_en, val, drvdata.rgb_brightness);
1293 if (ret)
1294 return ret;
1295
1296 drvdata.rgb_speed = val;
1297 return count;
1298 }
1299
speed_show(struct device * dev,struct device_attribute * attr,char * buf)1300 static ssize_t speed_show(struct device *dev, struct device_attribute *attr,
1301 char *buf)
1302 {
1303 int ret;
1304
1305 ret = oxp_rgb_status_show();
1306 if (ret)
1307 return ret;
1308
1309 if (drvdata.rgb_speed > 9)
1310 return -EINVAL;
1311
1312 return sysfs_emit(buf, "%hhu\n", drvdata.rgb_speed);
1313 }
1314 static DEVICE_ATTR_RW(speed);
1315
speed_range_show(struct device * dev,struct device_attribute * attr,char * buf)1316 static ssize_t speed_range_show(struct device *dev,
1317 struct device_attribute *attr, char *buf)
1318 {
1319 return sysfs_emit(buf, "0-9\n");
1320 }
1321 static DEVICE_ATTR_RO(speed_range);
1322
oxp_rgb_queue_fn(struct work_struct * work)1323 static void oxp_rgb_queue_fn(struct work_struct *work)
1324 {
1325 unsigned int max_brightness = drvdata.led_mc->led_cdev.max_brightness;
1326 unsigned int brightness = drvdata.led_mc->led_cdev.brightness;
1327 u8 val = 4 * brightness / max_brightness;
1328 int ret;
1329
1330 if (drvdata.rgb_brightness != val) {
1331 ret = oxp_rgb_status_store(drvdata.rgb_en, drvdata.rgb_speed, val);
1332 if (ret)
1333 dev_err(drvdata.led_mc->led_cdev.dev,
1334 "Error: Failed to write RGB Status: %i\n", ret);
1335
1336 drvdata.rgb_brightness = val;
1337 }
1338
1339 if (drvdata.rgb_effect != OXP_EFFECT_MONO_LIST)
1340 return;
1341
1342 ret = oxp_rgb_effect_set(drvdata.rgb_effect);
1343 if (ret)
1344 dev_err(drvdata.led_mc->led_cdev.dev, "Error: Failed to write RGB color: %i\n",
1345 ret);
1346 }
1347
oxp_rgb_brightness_set(struct led_classdev * led_cdev,enum led_brightness brightness)1348 static void oxp_rgb_brightness_set(struct led_classdev *led_cdev,
1349 enum led_brightness brightness)
1350 {
1351 led_cdev->brightness = brightness;
1352 mod_delayed_work(system_dfl_wq, &drvdata.oxp_rgb_queue, msecs_to_jiffies(50));
1353 }
1354
1355 static struct attribute *oxp_rgb_attrs[] = {
1356 &dev_attr_effect.attr,
1357 &dev_attr_effect_index.attr,
1358 &dev_attr_enabled.attr,
1359 &dev_attr_enabled_index.attr,
1360 &dev_attr_speed.attr,
1361 &dev_attr_speed_range.attr,
1362 NULL,
1363 };
1364
1365 static const struct attribute_group oxp_rgb_attr_group = {
1366 .attrs = oxp_rgb_attrs,
1367 };
1368
1369 static struct mc_subled oxp_rgb_subled_info[] = {
1370 {
1371 .color_index = LED_COLOR_ID_RED,
1372 .intensity = 0x24,
1373 .channel = 0x1,
1374 },
1375 {
1376 .color_index = LED_COLOR_ID_GREEN,
1377 .intensity = 0x22,
1378 .channel = 0x2,
1379 },
1380 {
1381 .color_index = LED_COLOR_ID_BLUE,
1382 .intensity = 0x99,
1383 .channel = 0x3,
1384 },
1385 };
1386
1387 static struct led_classdev_mc oxp_cdev_rgb = {
1388 .led_cdev = {
1389 .name = "oxp:rgb:joystick_rings",
1390 .color = LED_COLOR_ID_RGB,
1391 .brightness = 0x64,
1392 .max_brightness = 0x64,
1393 .brightness_set = oxp_rgb_brightness_set,
1394 },
1395 .num_colors = ARRAY_SIZE(oxp_rgb_subled_info),
1396 .subled_info = oxp_rgb_subled_info,
1397 };
1398
1399 struct quirk_entry {
1400 bool hybrid_mcu;
1401 };
1402
1403 static struct quirk_entry quirk_hybrid_mcu = {
1404 .hybrid_mcu = true,
1405 };
1406
1407 static const struct dmi_system_id oxp_hybrid_mcu_list[] = {
1408 {
1409 .ident = "OneXPlayer Apex",
1410 .matches = {
1411 DMI_MATCH(DMI_SYS_VENDOR, "ONE-NETBOOK"),
1412 DMI_MATCH(DMI_PRODUCT_NAME, "ONEXPLAYER APEX"),
1413 },
1414 .driver_data = &quirk_hybrid_mcu,
1415 },
1416 {
1417 .ident = "OneXPlayer G1 AMD",
1418 .matches = {
1419 DMI_MATCH(DMI_SYS_VENDOR, "ONE-NETBOOK"),
1420 DMI_MATCH(DMI_PRODUCT_NAME, "ONEXPLAYER G1 A"),
1421 },
1422 .driver_data = &quirk_hybrid_mcu,
1423 },
1424 {
1425 .ident = "OneXPlayer G1 Intel",
1426 .matches = {
1427 DMI_MATCH(DMI_SYS_VENDOR, "ONE-NETBOOK"),
1428 DMI_MATCH(DMI_PRODUCT_NAME, "ONEXPLAYER G1 i"),
1429 },
1430 .driver_data = &quirk_hybrid_mcu,
1431 },
1432 {},
1433 };
1434
oxp_hybrid_mcu_device(void)1435 static bool oxp_hybrid_mcu_device(void)
1436 {
1437 const struct dmi_system_id *dmi_id;
1438 struct quirk_entry *quirks;
1439
1440 dmi_id = dmi_first_match(oxp_hybrid_mcu_list);
1441 if (!dmi_id)
1442 return false;
1443
1444 quirks = dmi_id->driver_data;
1445
1446 return quirks->hybrid_mcu;
1447 }
1448
oxp_cfg_probe(struct hid_device * hdev,u16 up)1449 static int oxp_cfg_probe(struct hid_device *hdev, u16 up)
1450 {
1451 struct oxp_bmap_page_1 *bmap_1;
1452 struct oxp_bmap_page_2 *bmap_2;
1453 int ret;
1454
1455 hid_set_drvdata(hdev, &drvdata);
1456 mutex_init(&drvdata.cfg_mutex);
1457 drvdata.hdev = hdev;
1458
1459 if (up == GEN2_USAGE_PAGE && oxp_hybrid_mcu_device())
1460 goto skip_rgb;
1461
1462 drvdata.led_mc = &oxp_cdev_rgb;
1463
1464 INIT_DELAYED_WORK(&drvdata.oxp_rgb_queue, oxp_rgb_queue_fn);
1465 ret = devm_led_classdev_multicolor_register(&hdev->dev, &oxp_cdev_rgb);
1466 if (ret)
1467 return dev_err_probe(&hdev->dev, ret,
1468 "Failed to create RGB device\n");
1469
1470 ret = devm_device_add_group(drvdata.led_mc->led_cdev.dev,
1471 &oxp_rgb_attr_group);
1472 if (ret)
1473 return dev_err_probe(drvdata.led_mc->led_cdev.dev, ret,
1474 "Failed to create RGB configuration attributes\n");
1475
1476 ret = oxp_rgb_status_show();
1477 if (ret)
1478 dev_warn(drvdata.led_mc->led_cdev.dev,
1479 "Failed to query RGB initial state: %i\n", ret);
1480
1481 /* Below features are only implemented in gen 2 */
1482 if (up != GEN2_USAGE_PAGE)
1483 return 0;
1484
1485 skip_rgb:
1486 bmap_1 = devm_kzalloc(&hdev->dev, sizeof(struct oxp_bmap_page_1), GFP_KERNEL);
1487 if (!bmap_1)
1488 return dev_err_probe(&hdev->dev, -ENOMEM,
1489 "Unable to allocate button map page 1\n");
1490
1491 bmap_2 = devm_kzalloc(&hdev->dev, sizeof(struct oxp_bmap_page_2), GFP_KERNEL);
1492 if (!bmap_2)
1493 return dev_err_probe(&hdev->dev, -ENOMEM,
1494 "Unable to allocate button map page 2\n");
1495
1496 drvdata.bmap_1 = bmap_1;
1497 drvdata.bmap_2 = bmap_2;
1498 oxp_reset_buttons();
1499 INIT_DELAYED_WORK(&drvdata.oxp_btn_queue, oxp_btn_queue_fn);
1500
1501 drvdata.gamepad_mode = OXP_GP_MODE_XINPUT;
1502 drvdata.rumble_intensity = 5;
1503
1504 INIT_DELAYED_WORK(&drvdata.oxp_mcu_init, oxp_mcu_init_fn);
1505 mod_delayed_work(system_dfl_wq, &drvdata.oxp_mcu_init, msecs_to_jiffies(50));
1506
1507 ret = devm_device_add_group(&hdev->dev, &oxp_cfg_attrs_group);
1508 if (ret)
1509 return dev_err_probe(&hdev->dev, ret,
1510 "Failed to attach configuration attributes\n");
1511
1512 return 0;
1513 }
1514
oxp_hid_probe(struct hid_device * hdev,const struct hid_device_id * id)1515 static int oxp_hid_probe(struct hid_device *hdev,
1516 const struct hid_device_id *id)
1517 {
1518 int ret;
1519 u16 up;
1520
1521 ret = hid_parse(hdev);
1522 if (ret)
1523 return dev_err_probe(&hdev->dev, ret, "Failed to parse HID device\n");
1524
1525 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
1526 if (ret)
1527 return dev_err_probe(&hdev->dev, ret, "Failed to start HID device\n");
1528
1529 ret = hid_hw_open(hdev);
1530 if (ret) {
1531 hid_hw_stop(hdev);
1532 return dev_err_probe(&hdev->dev, ret, "Failed to open HID device\n");
1533 }
1534
1535 up = get_usage_page(hdev);
1536 dev_dbg(&hdev->dev, "Got usage page %04x\n", up);
1537
1538 switch (up) {
1539 case GEN1_USAGE_PAGE:
1540 case GEN2_USAGE_PAGE:
1541 ret = oxp_cfg_probe(hdev, up);
1542 if (ret) {
1543 hid_hw_close(hdev);
1544 hid_hw_stop(hdev);
1545 }
1546
1547 return ret;
1548 default:
1549 return 0;
1550 }
1551 }
1552
oxp_hid_remove(struct hid_device * hdev)1553 static void oxp_hid_remove(struct hid_device *hdev)
1554 {
1555 cancel_delayed_work_sync(&drvdata.oxp_rgb_queue);
1556 cancel_delayed_work_sync(&drvdata.oxp_btn_queue);
1557 cancel_delayed_work_sync(&drvdata.oxp_mcu_init);
1558 hid_hw_close(hdev);
1559 hid_hw_stop(hdev);
1560 }
1561
1562 static const struct hid_device_id oxp_devices[] = {
1563 { HID_USB_DEVICE(USB_VENDOR_ID_CRSC, USB_DEVICE_ID_ONEXPLAYER_GEN1) },
1564 { HID_USB_DEVICE(USB_VENDOR_ID_WCH, USB_DEVICE_ID_ONEXPLAYER_GEN2) },
1565 {}
1566 };
1567
1568 MODULE_DEVICE_TABLE(hid, oxp_devices);
1569 static struct hid_driver hid_oxp = {
1570 .name = "hid-oxp",
1571 .id_table = oxp_devices,
1572 .probe = oxp_hid_probe,
1573 .remove = oxp_hid_remove,
1574 .raw_event = oxp_hid_raw_event,
1575 };
1576 module_hid_driver(hid_oxp);
1577
1578 MODULE_AUTHOR("Derek J. Clark <derekjohn.clark@gmail.com>");
1579 MODULE_DESCRIPTION("Driver for OneXPlayer HID Interfaces");
1580 MODULE_LICENSE("GPL");
1581