1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
|
From 2c922a46967bdb4ea6fce73391a443ae8c8d59d9 Mon Sep 17 00:00:00 2001
From: "Daniel J. Ogorchock" <djogorchock@gmail.com>
Date: Sat, 26 Jan 2019 21:25:41 -0600
Subject: [PATCH 02/14] HID: nintendo: add player led support
This patch adds led_classdev functionality to the switch controller
driver. It adds support for the 4 player LEDs. The Home Button LED still
needs to be supported on the pro controllers and right joy-con.
Signed-off-by: Daniel J. Ogorchock <djogorchock@gmail.com>
---
drivers/hid/Kconfig | 2 +
drivers/hid/hid-nintendo.c | 95 +++++++++++++++++++++++++++++++++++++-
2 files changed, 95 insertions(+), 2 deletions(-)
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index b5cd42ed3b04..af4d543c0ff9 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -713,6 +713,8 @@ config HID_MULTITOUCH
config HID_NINTENDO
tristate "Nintendo Joy-Con and Pro Controller support"
depends on HID
+ depends on NEW_LEDS
+ depends on LEDS_CLASS
help
Adds support for the Nintendo Switch Joy-Cons and Pro Controller.
All controllers support bluetooth, and the Pro Controller also supports
diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c
index 7273ddf033e2..c3eec9b7c99c 100644
--- a/drivers/hid/hid-nintendo.c
+++ b/drivers/hid/hid-nintendo.c
@@ -25,6 +25,7 @@
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/input.h>
+#include <linux/leds.h>
#include <linux/module.h>
#include <linux/spinlock.h>
@@ -183,11 +184,13 @@ struct joycon_input_report {
} __packed;
#define JC_MAX_RESP_SIZE (sizeof(struct joycon_input_report) + 35)
+#define JC_NUM_LEDS 4
/* Each physical controller is associated with a joycon_ctlr struct */
struct joycon_ctlr {
struct hid_device *hdev;
struct input_dev *input;
+ struct led_classdev leds[JC_NUM_LEDS];
enum joycon_ctlr_state ctlr_state;
/* The following members are used for synchronous sends/receives */
@@ -553,11 +556,9 @@ static const unsigned int joycon_dpad_inputs_jc[] = {
BTN_DPAD_UP, BTN_DPAD_DOWN, BTN_DPAD_LEFT, BTN_DPAD_RIGHT,
};
-static DEFINE_MUTEX(joycon_input_num_mutex);
static int joycon_input_create(struct joycon_ctlr *ctlr)
{
struct hid_device *hdev;
- static int input_num = 1;
const char *name;
int ret;
int i;
@@ -643,6 +644,66 @@ static int joycon_input_create(struct joycon_ctlr *ctlr)
if (ret)
return ret;
+ return 0;
+}
+
+static int joycon_player_led_brightness_set(struct led_classdev *led,
+ enum led_brightness brightness)
+{
+ struct device *dev = led->dev->parent;
+ struct hid_device *hdev = to_hid_device(dev);
+ struct joycon_ctlr *ctlr;
+ int val = 0;
+ int i;
+ int ret;
+ int num;
+
+ ctlr = hid_get_drvdata(hdev);
+ if (!ctlr) {
+ hid_err(hdev, "No controller data\n");
+ return -ENODEV;
+ }
+
+ /* determine which player led this is */
+ for (num = 0; num < JC_NUM_LEDS; num++) {
+ if (&ctlr->leds[num] == led)
+ break;
+ }
+ if (num >= JC_NUM_LEDS)
+ return -EINVAL;
+
+ mutex_lock(&ctlr->output_mutex);
+ for (i = 0; i < JC_NUM_LEDS; i++) {
+ if (i == num)
+ val |= brightness << i;
+ else
+ val |= ctlr->leds[i].brightness << i;
+ }
+ ret = joycon_set_player_leds(ctlr, 0, val);
+ mutex_unlock(&ctlr->output_mutex);
+
+ return ret;
+}
+
+static const char * const joycon_player_led_names[] = {
+ "player1",
+ "player2",
+ "player3",
+ "player4"
+};
+
+static DEFINE_MUTEX(joycon_input_num_mutex);
+static int joycon_player_leds_create(struct joycon_ctlr *ctlr)
+{
+ struct hid_device *hdev = ctlr->hdev;
+ struct device *dev = &hdev->dev;
+ const char *d_name = dev_name(dev);
+ struct led_classdev *led;
+ char *name;
+ int ret = 0;
+ int i;
+ static int input_num = 1;
+
/* Set the default controller player leds based on controller number */
mutex_lock(&joycon_input_num_mutex);
mutex_lock(&ctlr->output_mutex);
@@ -650,6 +711,29 @@ static int joycon_input_create(struct joycon_ctlr *ctlr)
if (ret)
hid_warn(ctlr->hdev, "Failed to set leds; ret=%d\n", ret);
mutex_unlock(&ctlr->output_mutex);
+
+ /* configure the player LEDs */
+ for (i = 0; i < JC_NUM_LEDS; i++) {
+ name = devm_kasprintf(dev, GFP_KERNEL, "%s:%s", d_name,
+ joycon_player_led_names[i]);
+ if (!name)
+ return -ENOMEM;
+
+ led = &ctlr->leds[i];
+ led->name = name;
+ led->brightness = ((i + 1) <= input_num) ? LED_ON : LED_OFF;
+ led->max_brightness = LED_ON;
+ led->brightness_set_blocking =
+ joycon_player_led_brightness_set;
+ led->flags = LED_CORE_SUSPENDRESUME | LED_HW_PLUGGABLE;
+
+ ret = devm_led_classdev_register(&hdev->dev, led);
+ if (ret) {
+ hid_err(hdev, "Failed registering %s LED\n", led->name);
+ break;
+ }
+ }
+
if (++input_num > 4)
input_num = 1;
mutex_unlock(&joycon_input_num_mutex);
@@ -815,6 +899,13 @@ static int nintendo_hid_probe(struct hid_device *hdev,
mutex_unlock(&ctlr->output_mutex);
+ /* Initialize the leds */
+ ret = joycon_player_leds_create(ctlr);
+ if (ret) {
+ hid_err(hdev, "Failed to create leds; ret=%d\n", ret);
+ goto err_close;
+ }
+
ret = joycon_input_create(ctlr);
if (ret) {
hid_err(hdev, "Failed to create input device; ret=%d\n", ret);
--
2.28.0
|