-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathkernel.patch
More file actions
189 lines (183 loc) · 5.03 KB
/
Copy pathkernel.patch
File metadata and controls
189 lines (183 loc) · 5.03 KB
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
181
182
183
184
185
186
187
188
189
--- a/drivers/input/mouse/synaptics.c 2026-04-08 12:31:17.223831588 +0000
+++ b/drivers/input/mouse/synaptics.c 2026-04-08 12:35:17.369332769 +0000
@@ -26,6 +26,7 @@
#include <linux/input/mt.h>
#include <linux/serio.h>
#include <linux/libps2.h>
+#include <linux/leds.h>
#include <linux/rmi.h>
#include <linux/i2c.h>
#include <linux/slab.h>
@@ -731,6 +732,141 @@
serio_register_port(serio);
}
+#if 1
+/*
+ * LED handling:
+ * Some Synaptics devices have an embeded LED at the top-left corner.
+ */
+
+struct synaptics_led {
+ struct psmouse *psmouse;
+ struct work_struct work;
+ struct led_classdev cdev;
+};
+
+static void synaptics_set_led(struct psmouse *psmouse, int on)
+{
+ int i;
+ unsigned char cmd = on ? 0x88 : 0x10;
+
+ ps2_begin_command(&psmouse->ps2dev);
+ if (__ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11))
+ goto out;
+ for (i = 6; i >= 0; i -= 2) {
+ unsigned char d = (cmd >> i) & 3;
+ if (__ps2_command(&psmouse->ps2dev, &d, PSMOUSE_CMD_SETRES))
+ goto out;
+ }
+ cmd = 0x0a;
+ __ps2_command(&psmouse->ps2dev, &cmd, PSMOUSE_CMD_SETRATE);
+ out:
+ ps2_end_command(&psmouse->ps2dev);
+}
+
+static void synaptics_led_work(struct work_struct *work)
+{
+ struct synaptics_led *led;
+
+ led = container_of(work, struct synaptics_led, work);
+ synaptics_set_led(led->psmouse, led->cdev.brightness);
+}
+
+static void synaptics_led_cdev_brightness_set(struct led_classdev *cdev,
+ enum led_brightness value)
+{
+ struct synaptics_led *led;
+
+ led = container_of(cdev, struct synaptics_led, cdev);
+ schedule_work(&led->work);
+}
+
+static void synaptics_sync_led(struct psmouse *psmouse)
+{
+ struct synaptics_data *priv = psmouse->private;
+
+ if (priv->led)
+ synaptics_set_led(psmouse, priv->led->cdev.brightness);
+}
+
+static bool synaptics_has_led(struct synaptics_data *priv)
+{
+ printk(KERN_NOTICE "synaptics: led: checking for led\n");
+
+ if (!priv->info.ext_cap_0c) {
+ printk(KERN_NOTICE "synaptics: led: !priv->ext_cap_0c is true... no led\n");
+ return false;
+ }
+
+ printk(KERN_NOTICE "synaptics: led: your product ID is %2lx\n", SYN_CAP_PRODUCT_ID(priv->info.ext_cap));
+
+ /* FIXME: LED is supposedly detectable in cap0c[1] 0x20, but it seems
+ * not working on real machines.
+ * So we check the product id to be sure.
+ * Added ID 0x24 experimental.
+ */
+
+ if (SYN_CAP_PRODUCT_ID(priv->info.ext_cap) != 0x24 &&
+ SYN_CAP_PRODUCT_ID(priv->info.ext_cap) != 0xe4 &&
+ SYN_CAP_PRODUCT_ID(priv->info.ext_cap) != 0x64 &&
+ SYN_CAP_PRODUCT_ID(priv->info.ext_cap) != 0x84) {
+ printk(KERN_NOTICE "synaptics: led: your product ID is not in the whitelist\n");
+ return false;
+ }
+
+ if (!(priv->info.ext_cap_0c & 0x2000) &&
+ (priv->info.capabilities & 0xd000fd) != 0xd00071) {
+ printk(KERN_NOTICE "synaptics: led: failed capabilities check\n");
+ return false;
+ }
+
+ printk(KERN_NOTICE "synaptics: led: looks like you have one\n");
+
+ return true;
+}
+
+static int synaptics_init_led(struct psmouse *psmouse)
+{
+ struct synaptics_data *priv = psmouse->private;
+ struct synaptics_led *led;
+ int err;
+
+ if (!synaptics_has_led(priv))
+ return 0;
+ printk(KERN_INFO "synaptics: support LED control\n");
+ led = kzalloc(sizeof(struct synaptics_led), GFP_KERNEL);
+ if (!led)
+ return -ENOMEM;
+ led->psmouse = psmouse;
+ INIT_WORK(&led->work, synaptics_led_work);
+ led->cdev.name = "psmouse::synaptics";
+ led->cdev.brightness_set = synaptics_led_cdev_brightness_set;
+ led->cdev.flags = LED_CORE_SUSPENDRESUME;
+ err = led_classdev_register(NULL, &led->cdev);
+ if (err < 0) {
+ kfree(led);
+ return err;
+ }
+ priv->led = led;
+ return 0;
+}
+
+static void synaptics_free_led(struct psmouse *psmouse)
+{
+ struct synaptics_data *priv = psmouse->private;
+
+ if (!priv->led)
+ return;
+ cancel_work_sync(&priv->led->work);
+ synaptics_set_led(psmouse, 0);
+ led_classdev_unregister(&priv->led->cdev);
+ kfree(priv->led);
+}
+#else
+#define synaptics_init_led(ps) 0
+#define synaptics_free_led(ps) do {} while (0)
+#define synaptics_sync_led(ps) do {} while (0)
+#endif
+
/*****************************************************************************
* Functions to interpret the absolute mode packets
****************************************************************************/
@@ -1418,6 +1554,7 @@
device_remove_file(&psmouse->ps2dev.serio->dev,
&psmouse_attr_disable_gesture.dattr);
+ synaptics_free_led(psmouse);
synaptics_reset(psmouse);
kfree(priv);
psmouse->private = NULL;
@@ -1478,6 +1615,8 @@
return -ENXIO;
}
+ synaptics_sync_led(psmouse);
+
return 0;
}
@@ -1596,6 +1735,9 @@
info->capabilities, info->ext_cap, info->ext_cap_0c,
info->ext_cap_10, info->board_id, info->firmware_id);
+ if (synaptics_init_led(psmouse) < 0)
+ goto init_fail;
+
err = set_input_params(psmouse, priv);
if (err) {
psmouse_err(psmouse,
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -203,6 +203,7 @@ struct synaptics_data {
bool press;
bool report_press;
bool is_forcepad;
+ struct synaptics_led *led;
};
void synaptics_module_init(void);