Commit 424befd7b14a74e1d3b50c1cb7575077dc00fc97
Committed by
Greg Kroah-Hartman
1 parent
74a0ac496f
Input: elantech - add more Fujtisu notebooks to force crc_enabled
commit 47c1ffb2b6b630894e9a16442611c056ab21c057 upstream. Add two more Fujitsu LIFEBOOK models that also ship with the Elantech touchpad and don't work with crc_disabled to the quirk list. Signed-off-by: Rainer Koenig <Rainer.Koenig@ts.fujitsu.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Showing 1 changed file with 16 additions and 0 deletions Inline Diff
drivers/input/mouse/elantech.c
1 | /* | 1 | /* |
2 | * Elantech Touchpad driver (v6) | 2 | * Elantech Touchpad driver (v6) |
3 | * | 3 | * |
4 | * Copyright (C) 2007-2009 Arjan Opmeer <arjan@opmeer.net> | 4 | * Copyright (C) 2007-2009 Arjan Opmeer <arjan@opmeer.net> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms of the GNU General Public License version 2 as published | 7 | * under the terms of the GNU General Public License version 2 as published |
8 | * by the Free Software Foundation. | 8 | * by the Free Software Foundation. |
9 | * | 9 | * |
10 | * Trademarks are the property of their respective owners. | 10 | * Trademarks are the property of their respective owners. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/delay.h> | 13 | #include <linux/delay.h> |
14 | #include <linux/dmi.h> | 14 | #include <linux/dmi.h> |
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/input.h> | 17 | #include <linux/input.h> |
18 | #include <linux/input/mt.h> | 18 | #include <linux/input/mt.h> |
19 | #include <linux/serio.h> | 19 | #include <linux/serio.h> |
20 | #include <linux/libps2.h> | 20 | #include <linux/libps2.h> |
21 | #include <asm/unaligned.h> | 21 | #include <asm/unaligned.h> |
22 | #include "psmouse.h" | 22 | #include "psmouse.h" |
23 | #include "elantech.h" | 23 | #include "elantech.h" |
24 | 24 | ||
25 | #define elantech_debug(fmt, ...) \ | 25 | #define elantech_debug(fmt, ...) \ |
26 | do { \ | 26 | do { \ |
27 | if (etd->debug) \ | 27 | if (etd->debug) \ |
28 | psmouse_printk(KERN_DEBUG, psmouse, \ | 28 | psmouse_printk(KERN_DEBUG, psmouse, \ |
29 | fmt, ##__VA_ARGS__); \ | 29 | fmt, ##__VA_ARGS__); \ |
30 | } while (0) | 30 | } while (0) |
31 | 31 | ||
32 | /* | 32 | /* |
33 | * Send a Synaptics style sliced query command | 33 | * Send a Synaptics style sliced query command |
34 | */ | 34 | */ |
35 | static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, | 35 | static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, |
36 | unsigned char *param) | 36 | unsigned char *param) |
37 | { | 37 | { |
38 | if (psmouse_sliced_command(psmouse, c) || | 38 | if (psmouse_sliced_command(psmouse, c) || |
39 | ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) { | 39 | ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) { |
40 | psmouse_err(psmouse, "%s query 0x%02x failed.\n", __func__, c); | 40 | psmouse_err(psmouse, "%s query 0x%02x failed.\n", __func__, c); |
41 | return -1; | 41 | return -1; |
42 | } | 42 | } |
43 | 43 | ||
44 | return 0; | 44 | return 0; |
45 | } | 45 | } |
46 | 46 | ||
47 | /* | 47 | /* |
48 | * V3 and later support this fast command | 48 | * V3 and later support this fast command |
49 | */ | 49 | */ |
50 | static int elantech_send_cmd(struct psmouse *psmouse, unsigned char c, | 50 | static int elantech_send_cmd(struct psmouse *psmouse, unsigned char c, |
51 | unsigned char *param) | 51 | unsigned char *param) |
52 | { | 52 | { |
53 | struct ps2dev *ps2dev = &psmouse->ps2dev; | 53 | struct ps2dev *ps2dev = &psmouse->ps2dev; |
54 | 54 | ||
55 | if (ps2_command(ps2dev, NULL, ETP_PS2_CUSTOM_COMMAND) || | 55 | if (ps2_command(ps2dev, NULL, ETP_PS2_CUSTOM_COMMAND) || |
56 | ps2_command(ps2dev, NULL, c) || | 56 | ps2_command(ps2dev, NULL, c) || |
57 | ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) { | 57 | ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) { |
58 | psmouse_err(psmouse, "%s query 0x%02x failed.\n", __func__, c); | 58 | psmouse_err(psmouse, "%s query 0x%02x failed.\n", __func__, c); |
59 | return -1; | 59 | return -1; |
60 | } | 60 | } |
61 | 61 | ||
62 | return 0; | 62 | return 0; |
63 | } | 63 | } |
64 | 64 | ||
65 | /* | 65 | /* |
66 | * A retrying version of ps2_command | 66 | * A retrying version of ps2_command |
67 | */ | 67 | */ |
68 | static int elantech_ps2_command(struct psmouse *psmouse, | 68 | static int elantech_ps2_command(struct psmouse *psmouse, |
69 | unsigned char *param, int command) | 69 | unsigned char *param, int command) |
70 | { | 70 | { |
71 | struct ps2dev *ps2dev = &psmouse->ps2dev; | 71 | struct ps2dev *ps2dev = &psmouse->ps2dev; |
72 | struct elantech_data *etd = psmouse->private; | 72 | struct elantech_data *etd = psmouse->private; |
73 | int rc; | 73 | int rc; |
74 | int tries = ETP_PS2_COMMAND_TRIES; | 74 | int tries = ETP_PS2_COMMAND_TRIES; |
75 | 75 | ||
76 | do { | 76 | do { |
77 | rc = ps2_command(ps2dev, param, command); | 77 | rc = ps2_command(ps2dev, param, command); |
78 | if (rc == 0) | 78 | if (rc == 0) |
79 | break; | 79 | break; |
80 | tries--; | 80 | tries--; |
81 | elantech_debug("retrying ps2 command 0x%02x (%d).\n", | 81 | elantech_debug("retrying ps2 command 0x%02x (%d).\n", |
82 | command, tries); | 82 | command, tries); |
83 | msleep(ETP_PS2_COMMAND_DELAY); | 83 | msleep(ETP_PS2_COMMAND_DELAY); |
84 | } while (tries > 0); | 84 | } while (tries > 0); |
85 | 85 | ||
86 | if (rc) | 86 | if (rc) |
87 | psmouse_err(psmouse, "ps2 command 0x%02x failed.\n", command); | 87 | psmouse_err(psmouse, "ps2 command 0x%02x failed.\n", command); |
88 | 88 | ||
89 | return rc; | 89 | return rc; |
90 | } | 90 | } |
91 | 91 | ||
92 | /* | 92 | /* |
93 | * Send an Elantech style special command to read a value from a register | 93 | * Send an Elantech style special command to read a value from a register |
94 | */ | 94 | */ |
95 | static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg, | 95 | static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg, |
96 | unsigned char *val) | 96 | unsigned char *val) |
97 | { | 97 | { |
98 | struct elantech_data *etd = psmouse->private; | 98 | struct elantech_data *etd = psmouse->private; |
99 | unsigned char param[3]; | 99 | unsigned char param[3]; |
100 | int rc = 0; | 100 | int rc = 0; |
101 | 101 | ||
102 | if (reg < 0x07 || reg > 0x26) | 102 | if (reg < 0x07 || reg > 0x26) |
103 | return -1; | 103 | return -1; |
104 | 104 | ||
105 | if (reg > 0x11 && reg < 0x20) | 105 | if (reg > 0x11 && reg < 0x20) |
106 | return -1; | 106 | return -1; |
107 | 107 | ||
108 | switch (etd->hw_version) { | 108 | switch (etd->hw_version) { |
109 | case 1: | 109 | case 1: |
110 | if (psmouse_sliced_command(psmouse, ETP_REGISTER_READ) || | 110 | if (psmouse_sliced_command(psmouse, ETP_REGISTER_READ) || |
111 | psmouse_sliced_command(psmouse, reg) || | 111 | psmouse_sliced_command(psmouse, reg) || |
112 | ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) { | 112 | ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) { |
113 | rc = -1; | 113 | rc = -1; |
114 | } | 114 | } |
115 | break; | 115 | break; |
116 | 116 | ||
117 | case 2: | 117 | case 2: |
118 | if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || | 118 | if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || |
119 | elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READ) || | 119 | elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READ) || |
120 | elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || | 120 | elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || |
121 | elantech_ps2_command(psmouse, NULL, reg) || | 121 | elantech_ps2_command(psmouse, NULL, reg) || |
122 | elantech_ps2_command(psmouse, param, PSMOUSE_CMD_GETINFO)) { | 122 | elantech_ps2_command(psmouse, param, PSMOUSE_CMD_GETINFO)) { |
123 | rc = -1; | 123 | rc = -1; |
124 | } | 124 | } |
125 | break; | 125 | break; |
126 | 126 | ||
127 | case 3 ... 4: | 127 | case 3 ... 4: |
128 | if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || | 128 | if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || |
129 | elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) || | 129 | elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) || |
130 | elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || | 130 | elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || |
131 | elantech_ps2_command(psmouse, NULL, reg) || | 131 | elantech_ps2_command(psmouse, NULL, reg) || |
132 | elantech_ps2_command(psmouse, param, PSMOUSE_CMD_GETINFO)) { | 132 | elantech_ps2_command(psmouse, param, PSMOUSE_CMD_GETINFO)) { |
133 | rc = -1; | 133 | rc = -1; |
134 | } | 134 | } |
135 | break; | 135 | break; |
136 | } | 136 | } |
137 | 137 | ||
138 | if (rc) | 138 | if (rc) |
139 | psmouse_err(psmouse, "failed to read register 0x%02x.\n", reg); | 139 | psmouse_err(psmouse, "failed to read register 0x%02x.\n", reg); |
140 | else if (etd->hw_version != 4) | 140 | else if (etd->hw_version != 4) |
141 | *val = param[0]; | 141 | *val = param[0]; |
142 | else | 142 | else |
143 | *val = param[1]; | 143 | *val = param[1]; |
144 | 144 | ||
145 | return rc; | 145 | return rc; |
146 | } | 146 | } |
147 | 147 | ||
148 | /* | 148 | /* |
149 | * Send an Elantech style special command to write a register with a value | 149 | * Send an Elantech style special command to write a register with a value |
150 | */ | 150 | */ |
151 | static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg, | 151 | static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg, |
152 | unsigned char val) | 152 | unsigned char val) |
153 | { | 153 | { |
154 | struct elantech_data *etd = psmouse->private; | 154 | struct elantech_data *etd = psmouse->private; |
155 | int rc = 0; | 155 | int rc = 0; |
156 | 156 | ||
157 | if (reg < 0x07 || reg > 0x26) | 157 | if (reg < 0x07 || reg > 0x26) |
158 | return -1; | 158 | return -1; |
159 | 159 | ||
160 | if (reg > 0x11 && reg < 0x20) | 160 | if (reg > 0x11 && reg < 0x20) |
161 | return -1; | 161 | return -1; |
162 | 162 | ||
163 | switch (etd->hw_version) { | 163 | switch (etd->hw_version) { |
164 | case 1: | 164 | case 1: |
165 | if (psmouse_sliced_command(psmouse, ETP_REGISTER_WRITE) || | 165 | if (psmouse_sliced_command(psmouse, ETP_REGISTER_WRITE) || |
166 | psmouse_sliced_command(psmouse, reg) || | 166 | psmouse_sliced_command(psmouse, reg) || |
167 | psmouse_sliced_command(psmouse, val) || | 167 | psmouse_sliced_command(psmouse, val) || |
168 | ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11)) { | 168 | ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11)) { |
169 | rc = -1; | 169 | rc = -1; |
170 | } | 170 | } |
171 | break; | 171 | break; |
172 | 172 | ||
173 | case 2: | 173 | case 2: |
174 | if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || | 174 | if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || |
175 | elantech_ps2_command(psmouse, NULL, ETP_REGISTER_WRITE) || | 175 | elantech_ps2_command(psmouse, NULL, ETP_REGISTER_WRITE) || |
176 | elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || | 176 | elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || |
177 | elantech_ps2_command(psmouse, NULL, reg) || | 177 | elantech_ps2_command(psmouse, NULL, reg) || |
178 | elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || | 178 | elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || |
179 | elantech_ps2_command(psmouse, NULL, val) || | 179 | elantech_ps2_command(psmouse, NULL, val) || |
180 | elantech_ps2_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) { | 180 | elantech_ps2_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) { |
181 | rc = -1; | 181 | rc = -1; |
182 | } | 182 | } |
183 | break; | 183 | break; |
184 | 184 | ||
185 | case 3: | 185 | case 3: |
186 | if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || | 186 | if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || |
187 | elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) || | 187 | elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) || |
188 | elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || | 188 | elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || |
189 | elantech_ps2_command(psmouse, NULL, reg) || | 189 | elantech_ps2_command(psmouse, NULL, reg) || |
190 | elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || | 190 | elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || |
191 | elantech_ps2_command(psmouse, NULL, val) || | 191 | elantech_ps2_command(psmouse, NULL, val) || |
192 | elantech_ps2_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) { | 192 | elantech_ps2_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) { |
193 | rc = -1; | 193 | rc = -1; |
194 | } | 194 | } |
195 | break; | 195 | break; |
196 | 196 | ||
197 | case 4: | 197 | case 4: |
198 | if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || | 198 | if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || |
199 | elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) || | 199 | elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) || |
200 | elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || | 200 | elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || |
201 | elantech_ps2_command(psmouse, NULL, reg) || | 201 | elantech_ps2_command(psmouse, NULL, reg) || |
202 | elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || | 202 | elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || |
203 | elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) || | 203 | elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READWRITE) || |
204 | elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || | 204 | elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || |
205 | elantech_ps2_command(psmouse, NULL, val) || | 205 | elantech_ps2_command(psmouse, NULL, val) || |
206 | elantech_ps2_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) { | 206 | elantech_ps2_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) { |
207 | rc = -1; | 207 | rc = -1; |
208 | } | 208 | } |
209 | break; | 209 | break; |
210 | } | 210 | } |
211 | 211 | ||
212 | if (rc) | 212 | if (rc) |
213 | psmouse_err(psmouse, | 213 | psmouse_err(psmouse, |
214 | "failed to write register 0x%02x with value 0x%02x.\n", | 214 | "failed to write register 0x%02x with value 0x%02x.\n", |
215 | reg, val); | 215 | reg, val); |
216 | 216 | ||
217 | return rc; | 217 | return rc; |
218 | } | 218 | } |
219 | 219 | ||
220 | /* | 220 | /* |
221 | * Dump a complete mouse movement packet to the syslog | 221 | * Dump a complete mouse movement packet to the syslog |
222 | */ | 222 | */ |
223 | static void elantech_packet_dump(struct psmouse *psmouse) | 223 | static void elantech_packet_dump(struct psmouse *psmouse) |
224 | { | 224 | { |
225 | int i; | 225 | int i; |
226 | 226 | ||
227 | psmouse_printk(KERN_DEBUG, psmouse, "PS/2 packet ["); | 227 | psmouse_printk(KERN_DEBUG, psmouse, "PS/2 packet ["); |
228 | for (i = 0; i < psmouse->pktsize; i++) | 228 | for (i = 0; i < psmouse->pktsize; i++) |
229 | printk("%s0x%02x ", i ? ", " : " ", psmouse->packet[i]); | 229 | printk("%s0x%02x ", i ? ", " : " ", psmouse->packet[i]); |
230 | printk("]\n"); | 230 | printk("]\n"); |
231 | } | 231 | } |
232 | 232 | ||
233 | /* | 233 | /* |
234 | * Interpret complete data packets and report absolute mode input events for | 234 | * Interpret complete data packets and report absolute mode input events for |
235 | * hardware version 1. (4 byte packets) | 235 | * hardware version 1. (4 byte packets) |
236 | */ | 236 | */ |
237 | static void elantech_report_absolute_v1(struct psmouse *psmouse) | 237 | static void elantech_report_absolute_v1(struct psmouse *psmouse) |
238 | { | 238 | { |
239 | struct input_dev *dev = psmouse->dev; | 239 | struct input_dev *dev = psmouse->dev; |
240 | struct elantech_data *etd = psmouse->private; | 240 | struct elantech_data *etd = psmouse->private; |
241 | unsigned char *packet = psmouse->packet; | 241 | unsigned char *packet = psmouse->packet; |
242 | int fingers; | 242 | int fingers; |
243 | 243 | ||
244 | if (etd->fw_version < 0x020000) { | 244 | if (etd->fw_version < 0x020000) { |
245 | /* | 245 | /* |
246 | * byte 0: D U p1 p2 1 p3 R L | 246 | * byte 0: D U p1 p2 1 p3 R L |
247 | * byte 1: f 0 th tw x9 x8 y9 y8 | 247 | * byte 1: f 0 th tw x9 x8 y9 y8 |
248 | */ | 248 | */ |
249 | fingers = ((packet[1] & 0x80) >> 7) + | 249 | fingers = ((packet[1] & 0x80) >> 7) + |
250 | ((packet[1] & 0x30) >> 4); | 250 | ((packet[1] & 0x30) >> 4); |
251 | } else { | 251 | } else { |
252 | /* | 252 | /* |
253 | * byte 0: n1 n0 p2 p1 1 p3 R L | 253 | * byte 0: n1 n0 p2 p1 1 p3 R L |
254 | * byte 1: 0 0 0 0 x9 x8 y9 y8 | 254 | * byte 1: 0 0 0 0 x9 x8 y9 y8 |
255 | */ | 255 | */ |
256 | fingers = (packet[0] & 0xc0) >> 6; | 256 | fingers = (packet[0] & 0xc0) >> 6; |
257 | } | 257 | } |
258 | 258 | ||
259 | if (etd->jumpy_cursor) { | 259 | if (etd->jumpy_cursor) { |
260 | if (fingers != 1) { | 260 | if (fingers != 1) { |
261 | etd->single_finger_reports = 0; | 261 | etd->single_finger_reports = 0; |
262 | } else if (etd->single_finger_reports < 2) { | 262 | } else if (etd->single_finger_reports < 2) { |
263 | /* Discard first 2 reports of one finger, bogus */ | 263 | /* Discard first 2 reports of one finger, bogus */ |
264 | etd->single_finger_reports++; | 264 | etd->single_finger_reports++; |
265 | elantech_debug("discarding packet\n"); | 265 | elantech_debug("discarding packet\n"); |
266 | return; | 266 | return; |
267 | } | 267 | } |
268 | } | 268 | } |
269 | 269 | ||
270 | input_report_key(dev, BTN_TOUCH, fingers != 0); | 270 | input_report_key(dev, BTN_TOUCH, fingers != 0); |
271 | 271 | ||
272 | /* | 272 | /* |
273 | * byte 2: x7 x6 x5 x4 x3 x2 x1 x0 | 273 | * byte 2: x7 x6 x5 x4 x3 x2 x1 x0 |
274 | * byte 3: y7 y6 y5 y4 y3 y2 y1 y0 | 274 | * byte 3: y7 y6 y5 y4 y3 y2 y1 y0 |
275 | */ | 275 | */ |
276 | if (fingers) { | 276 | if (fingers) { |
277 | input_report_abs(dev, ABS_X, | 277 | input_report_abs(dev, ABS_X, |
278 | ((packet[1] & 0x0c) << 6) | packet[2]); | 278 | ((packet[1] & 0x0c) << 6) | packet[2]); |
279 | input_report_abs(dev, ABS_Y, | 279 | input_report_abs(dev, ABS_Y, |
280 | etd->y_max - (((packet[1] & 0x03) << 8) | packet[3])); | 280 | etd->y_max - (((packet[1] & 0x03) << 8) | packet[3])); |
281 | } | 281 | } |
282 | 282 | ||
283 | input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); | 283 | input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); |
284 | input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); | 284 | input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); |
285 | input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); | 285 | input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); |
286 | input_report_key(dev, BTN_LEFT, packet[0] & 0x01); | 286 | input_report_key(dev, BTN_LEFT, packet[0] & 0x01); |
287 | input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); | 287 | input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); |
288 | 288 | ||
289 | if (etd->fw_version < 0x020000 && | 289 | if (etd->fw_version < 0x020000 && |
290 | (etd->capabilities[0] & ETP_CAP_HAS_ROCKER)) { | 290 | (etd->capabilities[0] & ETP_CAP_HAS_ROCKER)) { |
291 | /* rocker up */ | 291 | /* rocker up */ |
292 | input_report_key(dev, BTN_FORWARD, packet[0] & 0x40); | 292 | input_report_key(dev, BTN_FORWARD, packet[0] & 0x40); |
293 | /* rocker down */ | 293 | /* rocker down */ |
294 | input_report_key(dev, BTN_BACK, packet[0] & 0x80); | 294 | input_report_key(dev, BTN_BACK, packet[0] & 0x80); |
295 | } | 295 | } |
296 | 296 | ||
297 | input_sync(dev); | 297 | input_sync(dev); |
298 | } | 298 | } |
299 | 299 | ||
300 | static void elantech_set_slot(struct input_dev *dev, int slot, bool active, | 300 | static void elantech_set_slot(struct input_dev *dev, int slot, bool active, |
301 | unsigned int x, unsigned int y) | 301 | unsigned int x, unsigned int y) |
302 | { | 302 | { |
303 | input_mt_slot(dev, slot); | 303 | input_mt_slot(dev, slot); |
304 | input_mt_report_slot_state(dev, MT_TOOL_FINGER, active); | 304 | input_mt_report_slot_state(dev, MT_TOOL_FINGER, active); |
305 | if (active) { | 305 | if (active) { |
306 | input_report_abs(dev, ABS_MT_POSITION_X, x); | 306 | input_report_abs(dev, ABS_MT_POSITION_X, x); |
307 | input_report_abs(dev, ABS_MT_POSITION_Y, y); | 307 | input_report_abs(dev, ABS_MT_POSITION_Y, y); |
308 | } | 308 | } |
309 | } | 309 | } |
310 | 310 | ||
311 | /* x1 < x2 and y1 < y2 when two fingers, x = y = 0 when not pressed */ | 311 | /* x1 < x2 and y1 < y2 when two fingers, x = y = 0 when not pressed */ |
312 | static void elantech_report_semi_mt_data(struct input_dev *dev, | 312 | static void elantech_report_semi_mt_data(struct input_dev *dev, |
313 | unsigned int num_fingers, | 313 | unsigned int num_fingers, |
314 | unsigned int x1, unsigned int y1, | 314 | unsigned int x1, unsigned int y1, |
315 | unsigned int x2, unsigned int y2) | 315 | unsigned int x2, unsigned int y2) |
316 | { | 316 | { |
317 | elantech_set_slot(dev, 0, num_fingers != 0, x1, y1); | 317 | elantech_set_slot(dev, 0, num_fingers != 0, x1, y1); |
318 | elantech_set_slot(dev, 1, num_fingers == 2, x2, y2); | 318 | elantech_set_slot(dev, 1, num_fingers == 2, x2, y2); |
319 | } | 319 | } |
320 | 320 | ||
321 | /* | 321 | /* |
322 | * Interpret complete data packets and report absolute mode input events for | 322 | * Interpret complete data packets and report absolute mode input events for |
323 | * hardware version 2. (6 byte packets) | 323 | * hardware version 2. (6 byte packets) |
324 | */ | 324 | */ |
325 | static void elantech_report_absolute_v2(struct psmouse *psmouse) | 325 | static void elantech_report_absolute_v2(struct psmouse *psmouse) |
326 | { | 326 | { |
327 | struct elantech_data *etd = psmouse->private; | 327 | struct elantech_data *etd = psmouse->private; |
328 | struct input_dev *dev = psmouse->dev; | 328 | struct input_dev *dev = psmouse->dev; |
329 | unsigned char *packet = psmouse->packet; | 329 | unsigned char *packet = psmouse->packet; |
330 | unsigned int fingers, x1 = 0, y1 = 0, x2 = 0, y2 = 0; | 330 | unsigned int fingers, x1 = 0, y1 = 0, x2 = 0, y2 = 0; |
331 | unsigned int width = 0, pres = 0; | 331 | unsigned int width = 0, pres = 0; |
332 | 332 | ||
333 | /* byte 0: n1 n0 . . . . R L */ | 333 | /* byte 0: n1 n0 . . . . R L */ |
334 | fingers = (packet[0] & 0xc0) >> 6; | 334 | fingers = (packet[0] & 0xc0) >> 6; |
335 | 335 | ||
336 | switch (fingers) { | 336 | switch (fingers) { |
337 | case 3: | 337 | case 3: |
338 | /* | 338 | /* |
339 | * Same as one finger, except report of more than 3 fingers: | 339 | * Same as one finger, except report of more than 3 fingers: |
340 | * byte 3: n4 . w1 w0 . . . . | 340 | * byte 3: n4 . w1 w0 . . . . |
341 | */ | 341 | */ |
342 | if (packet[3] & 0x80) | 342 | if (packet[3] & 0x80) |
343 | fingers = 4; | 343 | fingers = 4; |
344 | /* pass through... */ | 344 | /* pass through... */ |
345 | case 1: | 345 | case 1: |
346 | /* | 346 | /* |
347 | * byte 1: . . . . x11 x10 x9 x8 | 347 | * byte 1: . . . . x11 x10 x9 x8 |
348 | * byte 2: x7 x6 x5 x4 x4 x2 x1 x0 | 348 | * byte 2: x7 x6 x5 x4 x4 x2 x1 x0 |
349 | */ | 349 | */ |
350 | x1 = ((packet[1] & 0x0f) << 8) | packet[2]; | 350 | x1 = ((packet[1] & 0x0f) << 8) | packet[2]; |
351 | /* | 351 | /* |
352 | * byte 4: . . . . y11 y10 y9 y8 | 352 | * byte 4: . . . . y11 y10 y9 y8 |
353 | * byte 5: y7 y6 y5 y4 y3 y2 y1 y0 | 353 | * byte 5: y7 y6 y5 y4 y3 y2 y1 y0 |
354 | */ | 354 | */ |
355 | y1 = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]); | 355 | y1 = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]); |
356 | 356 | ||
357 | pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4); | 357 | pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4); |
358 | width = ((packet[0] & 0x30) >> 2) | ((packet[3] & 0x30) >> 4); | 358 | width = ((packet[0] & 0x30) >> 2) | ((packet[3] & 0x30) >> 4); |
359 | break; | 359 | break; |
360 | 360 | ||
361 | case 2: | 361 | case 2: |
362 | /* | 362 | /* |
363 | * The coordinate of each finger is reported separately | 363 | * The coordinate of each finger is reported separately |
364 | * with a lower resolution for two finger touches: | 364 | * with a lower resolution for two finger touches: |
365 | * byte 0: . . ay8 ax8 . . . . | 365 | * byte 0: . . ay8 ax8 . . . . |
366 | * byte 1: ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0 | 366 | * byte 1: ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0 |
367 | */ | 367 | */ |
368 | x1 = (((packet[0] & 0x10) << 4) | packet[1]) << 2; | 368 | x1 = (((packet[0] & 0x10) << 4) | packet[1]) << 2; |
369 | /* byte 2: ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0 */ | 369 | /* byte 2: ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0 */ |
370 | y1 = etd->y_max - | 370 | y1 = etd->y_max - |
371 | ((((packet[0] & 0x20) << 3) | packet[2]) << 2); | 371 | ((((packet[0] & 0x20) << 3) | packet[2]) << 2); |
372 | /* | 372 | /* |
373 | * byte 3: . . by8 bx8 . . . . | 373 | * byte 3: . . by8 bx8 . . . . |
374 | * byte 4: bx7 bx6 bx5 bx4 bx3 bx2 bx1 bx0 | 374 | * byte 4: bx7 bx6 bx5 bx4 bx3 bx2 bx1 bx0 |
375 | */ | 375 | */ |
376 | x2 = (((packet[3] & 0x10) << 4) | packet[4]) << 2; | 376 | x2 = (((packet[3] & 0x10) << 4) | packet[4]) << 2; |
377 | /* byte 5: by7 by8 by5 by4 by3 by2 by1 by0 */ | 377 | /* byte 5: by7 by8 by5 by4 by3 by2 by1 by0 */ |
378 | y2 = etd->y_max - | 378 | y2 = etd->y_max - |
379 | ((((packet[3] & 0x20) << 3) | packet[5]) << 2); | 379 | ((((packet[3] & 0x20) << 3) | packet[5]) << 2); |
380 | 380 | ||
381 | /* Unknown so just report sensible values */ | 381 | /* Unknown so just report sensible values */ |
382 | pres = 127; | 382 | pres = 127; |
383 | width = 7; | 383 | width = 7; |
384 | break; | 384 | break; |
385 | } | 385 | } |
386 | 386 | ||
387 | input_report_key(dev, BTN_TOUCH, fingers != 0); | 387 | input_report_key(dev, BTN_TOUCH, fingers != 0); |
388 | if (fingers != 0) { | 388 | if (fingers != 0) { |
389 | input_report_abs(dev, ABS_X, x1); | 389 | input_report_abs(dev, ABS_X, x1); |
390 | input_report_abs(dev, ABS_Y, y1); | 390 | input_report_abs(dev, ABS_Y, y1); |
391 | } | 391 | } |
392 | elantech_report_semi_mt_data(dev, fingers, x1, y1, x2, y2); | 392 | elantech_report_semi_mt_data(dev, fingers, x1, y1, x2, y2); |
393 | input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); | 393 | input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); |
394 | input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); | 394 | input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); |
395 | input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); | 395 | input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); |
396 | input_report_key(dev, BTN_TOOL_QUADTAP, fingers == 4); | 396 | input_report_key(dev, BTN_TOOL_QUADTAP, fingers == 4); |
397 | input_report_key(dev, BTN_LEFT, packet[0] & 0x01); | 397 | input_report_key(dev, BTN_LEFT, packet[0] & 0x01); |
398 | input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); | 398 | input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); |
399 | if (etd->reports_pressure) { | 399 | if (etd->reports_pressure) { |
400 | input_report_abs(dev, ABS_PRESSURE, pres); | 400 | input_report_abs(dev, ABS_PRESSURE, pres); |
401 | input_report_abs(dev, ABS_TOOL_WIDTH, width); | 401 | input_report_abs(dev, ABS_TOOL_WIDTH, width); |
402 | } | 402 | } |
403 | 403 | ||
404 | input_sync(dev); | 404 | input_sync(dev); |
405 | } | 405 | } |
406 | 406 | ||
407 | static void elantech_report_trackpoint(struct psmouse *psmouse, | 407 | static void elantech_report_trackpoint(struct psmouse *psmouse, |
408 | int packet_type) | 408 | int packet_type) |
409 | { | 409 | { |
410 | /* | 410 | /* |
411 | * byte 0: 0 0 sx sy 0 M R L | 411 | * byte 0: 0 0 sx sy 0 M R L |
412 | * byte 1:~sx 0 0 0 0 0 0 0 | 412 | * byte 1:~sx 0 0 0 0 0 0 0 |
413 | * byte 2:~sy 0 0 0 0 0 0 0 | 413 | * byte 2:~sy 0 0 0 0 0 0 0 |
414 | * byte 3: 0 0 ~sy ~sx 0 1 1 0 | 414 | * byte 3: 0 0 ~sy ~sx 0 1 1 0 |
415 | * byte 4: x7 x6 x5 x4 x3 x2 x1 x0 | 415 | * byte 4: x7 x6 x5 x4 x3 x2 x1 x0 |
416 | * byte 5: y7 y6 y5 y4 y3 y2 y1 y0 | 416 | * byte 5: y7 y6 y5 y4 y3 y2 y1 y0 |
417 | * | 417 | * |
418 | * x and y are written in two's complement spread | 418 | * x and y are written in two's complement spread |
419 | * over 9 bits with sx/sy the relative top bit and | 419 | * over 9 bits with sx/sy the relative top bit and |
420 | * x7..x0 and y7..y0 the lower bits. | 420 | * x7..x0 and y7..y0 the lower bits. |
421 | * The sign of y is opposite to what the input driver | 421 | * The sign of y is opposite to what the input driver |
422 | * expects for a relative movement | 422 | * expects for a relative movement |
423 | */ | 423 | */ |
424 | 424 | ||
425 | struct elantech_data *etd = psmouse->private; | 425 | struct elantech_data *etd = psmouse->private; |
426 | struct input_dev *tp_dev = etd->tp_dev; | 426 | struct input_dev *tp_dev = etd->tp_dev; |
427 | unsigned char *packet = psmouse->packet; | 427 | unsigned char *packet = psmouse->packet; |
428 | int x, y; | 428 | int x, y; |
429 | u32 t; | 429 | u32 t; |
430 | 430 | ||
431 | t = get_unaligned_le32(&packet[0]); | 431 | t = get_unaligned_le32(&packet[0]); |
432 | 432 | ||
433 | switch (t & ~7U) { | 433 | switch (t & ~7U) { |
434 | case 0x06000030U: | 434 | case 0x06000030U: |
435 | case 0x16008020U: | 435 | case 0x16008020U: |
436 | case 0x26800010U: | 436 | case 0x26800010U: |
437 | case 0x36808000U: | 437 | case 0x36808000U: |
438 | x = packet[4] - (int)((packet[1]^0x80) << 1); | 438 | x = packet[4] - (int)((packet[1]^0x80) << 1); |
439 | y = (int)((packet[2]^0x80) << 1) - packet[5]; | 439 | y = (int)((packet[2]^0x80) << 1) - packet[5]; |
440 | 440 | ||
441 | input_report_key(tp_dev, BTN_LEFT, packet[0] & 0x01); | 441 | input_report_key(tp_dev, BTN_LEFT, packet[0] & 0x01); |
442 | input_report_key(tp_dev, BTN_RIGHT, packet[0] & 0x02); | 442 | input_report_key(tp_dev, BTN_RIGHT, packet[0] & 0x02); |
443 | input_report_key(tp_dev, BTN_MIDDLE, packet[0] & 0x04); | 443 | input_report_key(tp_dev, BTN_MIDDLE, packet[0] & 0x04); |
444 | 444 | ||
445 | input_report_rel(tp_dev, REL_X, x); | 445 | input_report_rel(tp_dev, REL_X, x); |
446 | input_report_rel(tp_dev, REL_Y, y); | 446 | input_report_rel(tp_dev, REL_Y, y); |
447 | 447 | ||
448 | input_sync(tp_dev); | 448 | input_sync(tp_dev); |
449 | 449 | ||
450 | break; | 450 | break; |
451 | 451 | ||
452 | default: | 452 | default: |
453 | /* Dump unexpected packet sequences if debug=1 (default) */ | 453 | /* Dump unexpected packet sequences if debug=1 (default) */ |
454 | if (etd->debug == 1) | 454 | if (etd->debug == 1) |
455 | elantech_packet_dump(psmouse); | 455 | elantech_packet_dump(psmouse); |
456 | 456 | ||
457 | break; | 457 | break; |
458 | } | 458 | } |
459 | } | 459 | } |
460 | 460 | ||
461 | /* | 461 | /* |
462 | * Interpret complete data packets and report absolute mode input events for | 462 | * Interpret complete data packets and report absolute mode input events for |
463 | * hardware version 3. (12 byte packets for two fingers) | 463 | * hardware version 3. (12 byte packets for two fingers) |
464 | */ | 464 | */ |
465 | static void elantech_report_absolute_v3(struct psmouse *psmouse, | 465 | static void elantech_report_absolute_v3(struct psmouse *psmouse, |
466 | int packet_type) | 466 | int packet_type) |
467 | { | 467 | { |
468 | struct input_dev *dev = psmouse->dev; | 468 | struct input_dev *dev = psmouse->dev; |
469 | struct elantech_data *etd = psmouse->private; | 469 | struct elantech_data *etd = psmouse->private; |
470 | unsigned char *packet = psmouse->packet; | 470 | unsigned char *packet = psmouse->packet; |
471 | unsigned int fingers = 0, x1 = 0, y1 = 0, x2 = 0, y2 = 0; | 471 | unsigned int fingers = 0, x1 = 0, y1 = 0, x2 = 0, y2 = 0; |
472 | unsigned int width = 0, pres = 0; | 472 | unsigned int width = 0, pres = 0; |
473 | 473 | ||
474 | /* byte 0: n1 n0 . . . . R L */ | 474 | /* byte 0: n1 n0 . . . . R L */ |
475 | fingers = (packet[0] & 0xc0) >> 6; | 475 | fingers = (packet[0] & 0xc0) >> 6; |
476 | 476 | ||
477 | switch (fingers) { | 477 | switch (fingers) { |
478 | case 3: | 478 | case 3: |
479 | case 1: | 479 | case 1: |
480 | /* | 480 | /* |
481 | * byte 1: . . . . x11 x10 x9 x8 | 481 | * byte 1: . . . . x11 x10 x9 x8 |
482 | * byte 2: x7 x6 x5 x4 x4 x2 x1 x0 | 482 | * byte 2: x7 x6 x5 x4 x4 x2 x1 x0 |
483 | */ | 483 | */ |
484 | x1 = ((packet[1] & 0x0f) << 8) | packet[2]; | 484 | x1 = ((packet[1] & 0x0f) << 8) | packet[2]; |
485 | /* | 485 | /* |
486 | * byte 4: . . . . y11 y10 y9 y8 | 486 | * byte 4: . . . . y11 y10 y9 y8 |
487 | * byte 5: y7 y6 y5 y4 y3 y2 y1 y0 | 487 | * byte 5: y7 y6 y5 y4 y3 y2 y1 y0 |
488 | */ | 488 | */ |
489 | y1 = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]); | 489 | y1 = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]); |
490 | break; | 490 | break; |
491 | 491 | ||
492 | case 2: | 492 | case 2: |
493 | if (packet_type == PACKET_V3_HEAD) { | 493 | if (packet_type == PACKET_V3_HEAD) { |
494 | /* | 494 | /* |
495 | * byte 1: . . . . ax11 ax10 ax9 ax8 | 495 | * byte 1: . . . . ax11 ax10 ax9 ax8 |
496 | * byte 2: ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0 | 496 | * byte 2: ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0 |
497 | */ | 497 | */ |
498 | etd->mt[0].x = ((packet[1] & 0x0f) << 8) | packet[2]; | 498 | etd->mt[0].x = ((packet[1] & 0x0f) << 8) | packet[2]; |
499 | /* | 499 | /* |
500 | * byte 4: . . . . ay11 ay10 ay9 ay8 | 500 | * byte 4: . . . . ay11 ay10 ay9 ay8 |
501 | * byte 5: ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0 | 501 | * byte 5: ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0 |
502 | */ | 502 | */ |
503 | etd->mt[0].y = etd->y_max - | 503 | etd->mt[0].y = etd->y_max - |
504 | (((packet[4] & 0x0f) << 8) | packet[5]); | 504 | (((packet[4] & 0x0f) << 8) | packet[5]); |
505 | /* | 505 | /* |
506 | * wait for next packet | 506 | * wait for next packet |
507 | */ | 507 | */ |
508 | return; | 508 | return; |
509 | } | 509 | } |
510 | 510 | ||
511 | /* packet_type == PACKET_V3_TAIL */ | 511 | /* packet_type == PACKET_V3_TAIL */ |
512 | x1 = etd->mt[0].x; | 512 | x1 = etd->mt[0].x; |
513 | y1 = etd->mt[0].y; | 513 | y1 = etd->mt[0].y; |
514 | x2 = ((packet[1] & 0x0f) << 8) | packet[2]; | 514 | x2 = ((packet[1] & 0x0f) << 8) | packet[2]; |
515 | y2 = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]); | 515 | y2 = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]); |
516 | break; | 516 | break; |
517 | } | 517 | } |
518 | 518 | ||
519 | pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4); | 519 | pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4); |
520 | width = ((packet[0] & 0x30) >> 2) | ((packet[3] & 0x30) >> 4); | 520 | width = ((packet[0] & 0x30) >> 2) | ((packet[3] & 0x30) >> 4); |
521 | 521 | ||
522 | input_report_key(dev, BTN_TOUCH, fingers != 0); | 522 | input_report_key(dev, BTN_TOUCH, fingers != 0); |
523 | if (fingers != 0) { | 523 | if (fingers != 0) { |
524 | input_report_abs(dev, ABS_X, x1); | 524 | input_report_abs(dev, ABS_X, x1); |
525 | input_report_abs(dev, ABS_Y, y1); | 525 | input_report_abs(dev, ABS_Y, y1); |
526 | } | 526 | } |
527 | elantech_report_semi_mt_data(dev, fingers, x1, y1, x2, y2); | 527 | elantech_report_semi_mt_data(dev, fingers, x1, y1, x2, y2); |
528 | input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); | 528 | input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); |
529 | input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); | 529 | input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); |
530 | input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); | 530 | input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); |
531 | 531 | ||
532 | /* For clickpads map both buttons to BTN_LEFT */ | 532 | /* For clickpads map both buttons to BTN_LEFT */ |
533 | if (etd->fw_version & 0x001000) { | 533 | if (etd->fw_version & 0x001000) { |
534 | input_report_key(dev, BTN_LEFT, packet[0] & 0x03); | 534 | input_report_key(dev, BTN_LEFT, packet[0] & 0x03); |
535 | } else { | 535 | } else { |
536 | input_report_key(dev, BTN_LEFT, packet[0] & 0x01); | 536 | input_report_key(dev, BTN_LEFT, packet[0] & 0x01); |
537 | input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); | 537 | input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); |
538 | } | 538 | } |
539 | 539 | ||
540 | input_report_abs(dev, ABS_PRESSURE, pres); | 540 | input_report_abs(dev, ABS_PRESSURE, pres); |
541 | input_report_abs(dev, ABS_TOOL_WIDTH, width); | 541 | input_report_abs(dev, ABS_TOOL_WIDTH, width); |
542 | 542 | ||
543 | input_sync(dev); | 543 | input_sync(dev); |
544 | } | 544 | } |
545 | 545 | ||
546 | static void elantech_input_sync_v4(struct psmouse *psmouse) | 546 | static void elantech_input_sync_v4(struct psmouse *psmouse) |
547 | { | 547 | { |
548 | struct input_dev *dev = psmouse->dev; | 548 | struct input_dev *dev = psmouse->dev; |
549 | struct elantech_data *etd = psmouse->private; | 549 | struct elantech_data *etd = psmouse->private; |
550 | unsigned char *packet = psmouse->packet; | 550 | unsigned char *packet = psmouse->packet; |
551 | 551 | ||
552 | /* For clickpads map both buttons to BTN_LEFT */ | 552 | /* For clickpads map both buttons to BTN_LEFT */ |
553 | if (etd->fw_version & 0x001000) { | 553 | if (etd->fw_version & 0x001000) { |
554 | input_report_key(dev, BTN_LEFT, packet[0] & 0x03); | 554 | input_report_key(dev, BTN_LEFT, packet[0] & 0x03); |
555 | } else { | 555 | } else { |
556 | input_report_key(dev, BTN_LEFT, packet[0] & 0x01); | 556 | input_report_key(dev, BTN_LEFT, packet[0] & 0x01); |
557 | input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); | 557 | input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); |
558 | input_report_key(dev, BTN_MIDDLE, packet[0] & 0x04); | 558 | input_report_key(dev, BTN_MIDDLE, packet[0] & 0x04); |
559 | } | 559 | } |
560 | 560 | ||
561 | input_mt_report_pointer_emulation(dev, true); | 561 | input_mt_report_pointer_emulation(dev, true); |
562 | input_sync(dev); | 562 | input_sync(dev); |
563 | } | 563 | } |
564 | 564 | ||
565 | static void process_packet_status_v4(struct psmouse *psmouse) | 565 | static void process_packet_status_v4(struct psmouse *psmouse) |
566 | { | 566 | { |
567 | struct input_dev *dev = psmouse->dev; | 567 | struct input_dev *dev = psmouse->dev; |
568 | unsigned char *packet = psmouse->packet; | 568 | unsigned char *packet = psmouse->packet; |
569 | unsigned fingers; | 569 | unsigned fingers; |
570 | int i; | 570 | int i; |
571 | 571 | ||
572 | /* notify finger state change */ | 572 | /* notify finger state change */ |
573 | fingers = packet[1] & 0x1f; | 573 | fingers = packet[1] & 0x1f; |
574 | for (i = 0; i < ETP_MAX_FINGERS; i++) { | 574 | for (i = 0; i < ETP_MAX_FINGERS; i++) { |
575 | if ((fingers & (1 << i)) == 0) { | 575 | if ((fingers & (1 << i)) == 0) { |
576 | input_mt_slot(dev, i); | 576 | input_mt_slot(dev, i); |
577 | input_mt_report_slot_state(dev, MT_TOOL_FINGER, false); | 577 | input_mt_report_slot_state(dev, MT_TOOL_FINGER, false); |
578 | } | 578 | } |
579 | } | 579 | } |
580 | 580 | ||
581 | elantech_input_sync_v4(psmouse); | 581 | elantech_input_sync_v4(psmouse); |
582 | } | 582 | } |
583 | 583 | ||
584 | static void process_packet_head_v4(struct psmouse *psmouse) | 584 | static void process_packet_head_v4(struct psmouse *psmouse) |
585 | { | 585 | { |
586 | struct input_dev *dev = psmouse->dev; | 586 | struct input_dev *dev = psmouse->dev; |
587 | struct elantech_data *etd = psmouse->private; | 587 | struct elantech_data *etd = psmouse->private; |
588 | unsigned char *packet = psmouse->packet; | 588 | unsigned char *packet = psmouse->packet; |
589 | int id = ((packet[3] & 0xe0) >> 5) - 1; | 589 | int id = ((packet[3] & 0xe0) >> 5) - 1; |
590 | int pres, traces; | 590 | int pres, traces; |
591 | 591 | ||
592 | if (id < 0) | 592 | if (id < 0) |
593 | return; | 593 | return; |
594 | 594 | ||
595 | etd->mt[id].x = ((packet[1] & 0x0f) << 8) | packet[2]; | 595 | etd->mt[id].x = ((packet[1] & 0x0f) << 8) | packet[2]; |
596 | etd->mt[id].y = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]); | 596 | etd->mt[id].y = etd->y_max - (((packet[4] & 0x0f) << 8) | packet[5]); |
597 | pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4); | 597 | pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4); |
598 | traces = (packet[0] & 0xf0) >> 4; | 598 | traces = (packet[0] & 0xf0) >> 4; |
599 | 599 | ||
600 | input_mt_slot(dev, id); | 600 | input_mt_slot(dev, id); |
601 | input_mt_report_slot_state(dev, MT_TOOL_FINGER, true); | 601 | input_mt_report_slot_state(dev, MT_TOOL_FINGER, true); |
602 | 602 | ||
603 | input_report_abs(dev, ABS_MT_POSITION_X, etd->mt[id].x); | 603 | input_report_abs(dev, ABS_MT_POSITION_X, etd->mt[id].x); |
604 | input_report_abs(dev, ABS_MT_POSITION_Y, etd->mt[id].y); | 604 | input_report_abs(dev, ABS_MT_POSITION_Y, etd->mt[id].y); |
605 | input_report_abs(dev, ABS_MT_PRESSURE, pres); | 605 | input_report_abs(dev, ABS_MT_PRESSURE, pres); |
606 | input_report_abs(dev, ABS_MT_TOUCH_MAJOR, traces * etd->width); | 606 | input_report_abs(dev, ABS_MT_TOUCH_MAJOR, traces * etd->width); |
607 | /* report this for backwards compatibility */ | 607 | /* report this for backwards compatibility */ |
608 | input_report_abs(dev, ABS_TOOL_WIDTH, traces); | 608 | input_report_abs(dev, ABS_TOOL_WIDTH, traces); |
609 | 609 | ||
610 | elantech_input_sync_v4(psmouse); | 610 | elantech_input_sync_v4(psmouse); |
611 | } | 611 | } |
612 | 612 | ||
613 | static void process_packet_motion_v4(struct psmouse *psmouse) | 613 | static void process_packet_motion_v4(struct psmouse *psmouse) |
614 | { | 614 | { |
615 | struct input_dev *dev = psmouse->dev; | 615 | struct input_dev *dev = psmouse->dev; |
616 | struct elantech_data *etd = psmouse->private; | 616 | struct elantech_data *etd = psmouse->private; |
617 | unsigned char *packet = psmouse->packet; | 617 | unsigned char *packet = psmouse->packet; |
618 | int weight, delta_x1 = 0, delta_y1 = 0, delta_x2 = 0, delta_y2 = 0; | 618 | int weight, delta_x1 = 0, delta_y1 = 0, delta_x2 = 0, delta_y2 = 0; |
619 | int id, sid; | 619 | int id, sid; |
620 | 620 | ||
621 | id = ((packet[0] & 0xe0) >> 5) - 1; | 621 | id = ((packet[0] & 0xe0) >> 5) - 1; |
622 | if (id < 0) | 622 | if (id < 0) |
623 | return; | 623 | return; |
624 | 624 | ||
625 | sid = ((packet[3] & 0xe0) >> 5) - 1; | 625 | sid = ((packet[3] & 0xe0) >> 5) - 1; |
626 | weight = (packet[0] & 0x10) ? ETP_WEIGHT_VALUE : 1; | 626 | weight = (packet[0] & 0x10) ? ETP_WEIGHT_VALUE : 1; |
627 | /* | 627 | /* |
628 | * Motion packets give us the delta of x, y values of specific fingers, | 628 | * Motion packets give us the delta of x, y values of specific fingers, |
629 | * but in two's complement. Let the compiler do the conversion for us. | 629 | * but in two's complement. Let the compiler do the conversion for us. |
630 | * Also _enlarge_ the numbers to int, in case of overflow. | 630 | * Also _enlarge_ the numbers to int, in case of overflow. |
631 | */ | 631 | */ |
632 | delta_x1 = (signed char)packet[1]; | 632 | delta_x1 = (signed char)packet[1]; |
633 | delta_y1 = (signed char)packet[2]; | 633 | delta_y1 = (signed char)packet[2]; |
634 | delta_x2 = (signed char)packet[4]; | 634 | delta_x2 = (signed char)packet[4]; |
635 | delta_y2 = (signed char)packet[5]; | 635 | delta_y2 = (signed char)packet[5]; |
636 | 636 | ||
637 | etd->mt[id].x += delta_x1 * weight; | 637 | etd->mt[id].x += delta_x1 * weight; |
638 | etd->mt[id].y -= delta_y1 * weight; | 638 | etd->mt[id].y -= delta_y1 * weight; |
639 | input_mt_slot(dev, id); | 639 | input_mt_slot(dev, id); |
640 | input_report_abs(dev, ABS_MT_POSITION_X, etd->mt[id].x); | 640 | input_report_abs(dev, ABS_MT_POSITION_X, etd->mt[id].x); |
641 | input_report_abs(dev, ABS_MT_POSITION_Y, etd->mt[id].y); | 641 | input_report_abs(dev, ABS_MT_POSITION_Y, etd->mt[id].y); |
642 | 642 | ||
643 | if (sid >= 0) { | 643 | if (sid >= 0) { |
644 | etd->mt[sid].x += delta_x2 * weight; | 644 | etd->mt[sid].x += delta_x2 * weight; |
645 | etd->mt[sid].y -= delta_y2 * weight; | 645 | etd->mt[sid].y -= delta_y2 * weight; |
646 | input_mt_slot(dev, sid); | 646 | input_mt_slot(dev, sid); |
647 | input_report_abs(dev, ABS_MT_POSITION_X, etd->mt[sid].x); | 647 | input_report_abs(dev, ABS_MT_POSITION_X, etd->mt[sid].x); |
648 | input_report_abs(dev, ABS_MT_POSITION_Y, etd->mt[sid].y); | 648 | input_report_abs(dev, ABS_MT_POSITION_Y, etd->mt[sid].y); |
649 | } | 649 | } |
650 | 650 | ||
651 | elantech_input_sync_v4(psmouse); | 651 | elantech_input_sync_v4(psmouse); |
652 | } | 652 | } |
653 | 653 | ||
654 | static void elantech_report_absolute_v4(struct psmouse *psmouse, | 654 | static void elantech_report_absolute_v4(struct psmouse *psmouse, |
655 | int packet_type) | 655 | int packet_type) |
656 | { | 656 | { |
657 | switch (packet_type) { | 657 | switch (packet_type) { |
658 | case PACKET_V4_STATUS: | 658 | case PACKET_V4_STATUS: |
659 | process_packet_status_v4(psmouse); | 659 | process_packet_status_v4(psmouse); |
660 | break; | 660 | break; |
661 | 661 | ||
662 | case PACKET_V4_HEAD: | 662 | case PACKET_V4_HEAD: |
663 | process_packet_head_v4(psmouse); | 663 | process_packet_head_v4(psmouse); |
664 | break; | 664 | break; |
665 | 665 | ||
666 | case PACKET_V4_MOTION: | 666 | case PACKET_V4_MOTION: |
667 | process_packet_motion_v4(psmouse); | 667 | process_packet_motion_v4(psmouse); |
668 | break; | 668 | break; |
669 | 669 | ||
670 | case PACKET_UNKNOWN: | 670 | case PACKET_UNKNOWN: |
671 | default: | 671 | default: |
672 | /* impossible to get here */ | 672 | /* impossible to get here */ |
673 | break; | 673 | break; |
674 | } | 674 | } |
675 | } | 675 | } |
676 | 676 | ||
677 | static int elantech_packet_check_v1(struct psmouse *psmouse) | 677 | static int elantech_packet_check_v1(struct psmouse *psmouse) |
678 | { | 678 | { |
679 | struct elantech_data *etd = psmouse->private; | 679 | struct elantech_data *etd = psmouse->private; |
680 | unsigned char *packet = psmouse->packet; | 680 | unsigned char *packet = psmouse->packet; |
681 | unsigned char p1, p2, p3; | 681 | unsigned char p1, p2, p3; |
682 | 682 | ||
683 | /* Parity bits are placed differently */ | 683 | /* Parity bits are placed differently */ |
684 | if (etd->fw_version < 0x020000) { | 684 | if (etd->fw_version < 0x020000) { |
685 | /* byte 0: D U p1 p2 1 p3 R L */ | 685 | /* byte 0: D U p1 p2 1 p3 R L */ |
686 | p1 = (packet[0] & 0x20) >> 5; | 686 | p1 = (packet[0] & 0x20) >> 5; |
687 | p2 = (packet[0] & 0x10) >> 4; | 687 | p2 = (packet[0] & 0x10) >> 4; |
688 | } else { | 688 | } else { |
689 | /* byte 0: n1 n0 p2 p1 1 p3 R L */ | 689 | /* byte 0: n1 n0 p2 p1 1 p3 R L */ |
690 | p1 = (packet[0] & 0x10) >> 4; | 690 | p1 = (packet[0] & 0x10) >> 4; |
691 | p2 = (packet[0] & 0x20) >> 5; | 691 | p2 = (packet[0] & 0x20) >> 5; |
692 | } | 692 | } |
693 | 693 | ||
694 | p3 = (packet[0] & 0x04) >> 2; | 694 | p3 = (packet[0] & 0x04) >> 2; |
695 | 695 | ||
696 | return etd->parity[packet[1]] == p1 && | 696 | return etd->parity[packet[1]] == p1 && |
697 | etd->parity[packet[2]] == p2 && | 697 | etd->parity[packet[2]] == p2 && |
698 | etd->parity[packet[3]] == p3; | 698 | etd->parity[packet[3]] == p3; |
699 | } | 699 | } |
700 | 700 | ||
701 | static int elantech_debounce_check_v2(struct psmouse *psmouse) | 701 | static int elantech_debounce_check_v2(struct psmouse *psmouse) |
702 | { | 702 | { |
703 | /* | 703 | /* |
704 | * When we encounter packet that matches this exactly, it means the | 704 | * When we encounter packet that matches this exactly, it means the |
705 | * hardware is in debounce status. Just ignore the whole packet. | 705 | * hardware is in debounce status. Just ignore the whole packet. |
706 | */ | 706 | */ |
707 | const u8 debounce_packet[] = { 0x84, 0xff, 0xff, 0x02, 0xff, 0xff }; | 707 | const u8 debounce_packet[] = { 0x84, 0xff, 0xff, 0x02, 0xff, 0xff }; |
708 | unsigned char *packet = psmouse->packet; | 708 | unsigned char *packet = psmouse->packet; |
709 | 709 | ||
710 | return !memcmp(packet, debounce_packet, sizeof(debounce_packet)); | 710 | return !memcmp(packet, debounce_packet, sizeof(debounce_packet)); |
711 | } | 711 | } |
712 | 712 | ||
713 | static int elantech_packet_check_v2(struct psmouse *psmouse) | 713 | static int elantech_packet_check_v2(struct psmouse *psmouse) |
714 | { | 714 | { |
715 | struct elantech_data *etd = psmouse->private; | 715 | struct elantech_data *etd = psmouse->private; |
716 | unsigned char *packet = psmouse->packet; | 716 | unsigned char *packet = psmouse->packet; |
717 | 717 | ||
718 | /* | 718 | /* |
719 | * V2 hardware has two flavors. Older ones that do not report pressure, | 719 | * V2 hardware has two flavors. Older ones that do not report pressure, |
720 | * and newer ones that reports pressure and width. With newer ones, all | 720 | * and newer ones that reports pressure and width. With newer ones, all |
721 | * packets (1, 2, 3 finger touch) have the same constant bits. With | 721 | * packets (1, 2, 3 finger touch) have the same constant bits. With |
722 | * older ones, 1/3 finger touch packets and 2 finger touch packets | 722 | * older ones, 1/3 finger touch packets and 2 finger touch packets |
723 | * have different constant bits. | 723 | * have different constant bits. |
724 | * With all three cases, if the constant bits are not exactly what I | 724 | * With all three cases, if the constant bits are not exactly what I |
725 | * expected, I consider them invalid. | 725 | * expected, I consider them invalid. |
726 | */ | 726 | */ |
727 | if (etd->reports_pressure) | 727 | if (etd->reports_pressure) |
728 | return (packet[0] & 0x0c) == 0x04 && | 728 | return (packet[0] & 0x0c) == 0x04 && |
729 | (packet[3] & 0x0f) == 0x02; | 729 | (packet[3] & 0x0f) == 0x02; |
730 | 730 | ||
731 | if ((packet[0] & 0xc0) == 0x80) | 731 | if ((packet[0] & 0xc0) == 0x80) |
732 | return (packet[0] & 0x0c) == 0x0c && | 732 | return (packet[0] & 0x0c) == 0x0c && |
733 | (packet[3] & 0x0e) == 0x08; | 733 | (packet[3] & 0x0e) == 0x08; |
734 | 734 | ||
735 | return (packet[0] & 0x3c) == 0x3c && | 735 | return (packet[0] & 0x3c) == 0x3c && |
736 | (packet[1] & 0xf0) == 0x00 && | 736 | (packet[1] & 0xf0) == 0x00 && |
737 | (packet[3] & 0x3e) == 0x38 && | 737 | (packet[3] & 0x3e) == 0x38 && |
738 | (packet[4] & 0xf0) == 0x00; | 738 | (packet[4] & 0xf0) == 0x00; |
739 | } | 739 | } |
740 | 740 | ||
741 | /* | 741 | /* |
742 | * We check the constant bits to determine what packet type we get, | 742 | * We check the constant bits to determine what packet type we get, |
743 | * so packet checking is mandatory for v3 and later hardware. | 743 | * so packet checking is mandatory for v3 and later hardware. |
744 | */ | 744 | */ |
745 | static int elantech_packet_check_v3(struct psmouse *psmouse) | 745 | static int elantech_packet_check_v3(struct psmouse *psmouse) |
746 | { | 746 | { |
747 | struct elantech_data *etd = psmouse->private; | 747 | struct elantech_data *etd = psmouse->private; |
748 | const u8 debounce_packet[] = { 0xc4, 0xff, 0xff, 0x02, 0xff, 0xff }; | 748 | const u8 debounce_packet[] = { 0xc4, 0xff, 0xff, 0x02, 0xff, 0xff }; |
749 | unsigned char *packet = psmouse->packet; | 749 | unsigned char *packet = psmouse->packet; |
750 | 750 | ||
751 | /* | 751 | /* |
752 | * check debounce first, it has the same signature in byte 0 | 752 | * check debounce first, it has the same signature in byte 0 |
753 | * and byte 3 as PACKET_V3_HEAD. | 753 | * and byte 3 as PACKET_V3_HEAD. |
754 | */ | 754 | */ |
755 | if (!memcmp(packet, debounce_packet, sizeof(debounce_packet))) | 755 | if (!memcmp(packet, debounce_packet, sizeof(debounce_packet))) |
756 | return PACKET_DEBOUNCE; | 756 | return PACKET_DEBOUNCE; |
757 | 757 | ||
758 | /* | 758 | /* |
759 | * If the hardware flag 'crc_enabled' is set the packets have | 759 | * If the hardware flag 'crc_enabled' is set the packets have |
760 | * different signatures. | 760 | * different signatures. |
761 | */ | 761 | */ |
762 | if (etd->crc_enabled) { | 762 | if (etd->crc_enabled) { |
763 | if ((packet[3] & 0x09) == 0x08) | 763 | if ((packet[3] & 0x09) == 0x08) |
764 | return PACKET_V3_HEAD; | 764 | return PACKET_V3_HEAD; |
765 | 765 | ||
766 | if ((packet[3] & 0x09) == 0x09) | 766 | if ((packet[3] & 0x09) == 0x09) |
767 | return PACKET_V3_TAIL; | 767 | return PACKET_V3_TAIL; |
768 | } else { | 768 | } else { |
769 | if ((packet[0] & 0x0c) == 0x04 && (packet[3] & 0xcf) == 0x02) | 769 | if ((packet[0] & 0x0c) == 0x04 && (packet[3] & 0xcf) == 0x02) |
770 | return PACKET_V3_HEAD; | 770 | return PACKET_V3_HEAD; |
771 | 771 | ||
772 | if ((packet[0] & 0x0c) == 0x0c && (packet[3] & 0xce) == 0x0c) | 772 | if ((packet[0] & 0x0c) == 0x0c && (packet[3] & 0xce) == 0x0c) |
773 | return PACKET_V3_TAIL; | 773 | return PACKET_V3_TAIL; |
774 | if ((packet[3] & 0x0f) == 0x06) | 774 | if ((packet[3] & 0x0f) == 0x06) |
775 | return PACKET_TRACKPOINT; | 775 | return PACKET_TRACKPOINT; |
776 | } | 776 | } |
777 | 777 | ||
778 | return PACKET_UNKNOWN; | 778 | return PACKET_UNKNOWN; |
779 | } | 779 | } |
780 | 780 | ||
781 | static int elantech_packet_check_v4(struct psmouse *psmouse) | 781 | static int elantech_packet_check_v4(struct psmouse *psmouse) |
782 | { | 782 | { |
783 | struct elantech_data *etd = psmouse->private; | 783 | struct elantech_data *etd = psmouse->private; |
784 | unsigned char *packet = psmouse->packet; | 784 | unsigned char *packet = psmouse->packet; |
785 | unsigned char packet_type = packet[3] & 0x03; | 785 | unsigned char packet_type = packet[3] & 0x03; |
786 | bool sanity_check; | 786 | bool sanity_check; |
787 | 787 | ||
788 | if (etd->tp_dev && (packet[3] & 0x0f) == 0x06) | 788 | if (etd->tp_dev && (packet[3] & 0x0f) == 0x06) |
789 | return PACKET_TRACKPOINT; | 789 | return PACKET_TRACKPOINT; |
790 | 790 | ||
791 | /* | 791 | /* |
792 | * Sanity check based on the constant bits of a packet. | 792 | * Sanity check based on the constant bits of a packet. |
793 | * The constant bits change depending on the value of | 793 | * The constant bits change depending on the value of |
794 | * the hardware flag 'crc_enabled' but are the same for | 794 | * the hardware flag 'crc_enabled' but are the same for |
795 | * every packet, regardless of the type. | 795 | * every packet, regardless of the type. |
796 | */ | 796 | */ |
797 | if (etd->crc_enabled) | 797 | if (etd->crc_enabled) |
798 | sanity_check = ((packet[3] & 0x08) == 0x00); | 798 | sanity_check = ((packet[3] & 0x08) == 0x00); |
799 | else | 799 | else |
800 | sanity_check = ((packet[0] & 0x0c) == 0x04 && | 800 | sanity_check = ((packet[0] & 0x0c) == 0x04 && |
801 | (packet[3] & 0x1c) == 0x10); | 801 | (packet[3] & 0x1c) == 0x10); |
802 | 802 | ||
803 | if (!sanity_check) | 803 | if (!sanity_check) |
804 | return PACKET_UNKNOWN; | 804 | return PACKET_UNKNOWN; |
805 | 805 | ||
806 | switch (packet_type) { | 806 | switch (packet_type) { |
807 | case 0: | 807 | case 0: |
808 | return PACKET_V4_STATUS; | 808 | return PACKET_V4_STATUS; |
809 | 809 | ||
810 | case 1: | 810 | case 1: |
811 | return PACKET_V4_HEAD; | 811 | return PACKET_V4_HEAD; |
812 | 812 | ||
813 | case 2: | 813 | case 2: |
814 | return PACKET_V4_MOTION; | 814 | return PACKET_V4_MOTION; |
815 | } | 815 | } |
816 | 816 | ||
817 | return PACKET_UNKNOWN; | 817 | return PACKET_UNKNOWN; |
818 | } | 818 | } |
819 | 819 | ||
820 | /* | 820 | /* |
821 | * Process byte stream from mouse and handle complete packets | 821 | * Process byte stream from mouse and handle complete packets |
822 | */ | 822 | */ |
823 | static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse) | 823 | static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse) |
824 | { | 824 | { |
825 | struct elantech_data *etd = psmouse->private; | 825 | struct elantech_data *etd = psmouse->private; |
826 | int packet_type; | 826 | int packet_type; |
827 | 827 | ||
828 | if (psmouse->pktcnt < psmouse->pktsize) | 828 | if (psmouse->pktcnt < psmouse->pktsize) |
829 | return PSMOUSE_GOOD_DATA; | 829 | return PSMOUSE_GOOD_DATA; |
830 | 830 | ||
831 | if (etd->debug > 1) | 831 | if (etd->debug > 1) |
832 | elantech_packet_dump(psmouse); | 832 | elantech_packet_dump(psmouse); |
833 | 833 | ||
834 | switch (etd->hw_version) { | 834 | switch (etd->hw_version) { |
835 | case 1: | 835 | case 1: |
836 | if (etd->paritycheck && !elantech_packet_check_v1(psmouse)) | 836 | if (etd->paritycheck && !elantech_packet_check_v1(psmouse)) |
837 | return PSMOUSE_BAD_DATA; | 837 | return PSMOUSE_BAD_DATA; |
838 | 838 | ||
839 | elantech_report_absolute_v1(psmouse); | 839 | elantech_report_absolute_v1(psmouse); |
840 | break; | 840 | break; |
841 | 841 | ||
842 | case 2: | 842 | case 2: |
843 | /* ignore debounce */ | 843 | /* ignore debounce */ |
844 | if (elantech_debounce_check_v2(psmouse)) | 844 | if (elantech_debounce_check_v2(psmouse)) |
845 | return PSMOUSE_FULL_PACKET; | 845 | return PSMOUSE_FULL_PACKET; |
846 | 846 | ||
847 | if (etd->paritycheck && !elantech_packet_check_v2(psmouse)) | 847 | if (etd->paritycheck && !elantech_packet_check_v2(psmouse)) |
848 | return PSMOUSE_BAD_DATA; | 848 | return PSMOUSE_BAD_DATA; |
849 | 849 | ||
850 | elantech_report_absolute_v2(psmouse); | 850 | elantech_report_absolute_v2(psmouse); |
851 | break; | 851 | break; |
852 | 852 | ||
853 | case 3: | 853 | case 3: |
854 | packet_type = elantech_packet_check_v3(psmouse); | 854 | packet_type = elantech_packet_check_v3(psmouse); |
855 | switch (packet_type) { | 855 | switch (packet_type) { |
856 | case PACKET_UNKNOWN: | 856 | case PACKET_UNKNOWN: |
857 | return PSMOUSE_BAD_DATA; | 857 | return PSMOUSE_BAD_DATA; |
858 | 858 | ||
859 | case PACKET_DEBOUNCE: | 859 | case PACKET_DEBOUNCE: |
860 | /* ignore debounce */ | 860 | /* ignore debounce */ |
861 | break; | 861 | break; |
862 | 862 | ||
863 | case PACKET_TRACKPOINT: | 863 | case PACKET_TRACKPOINT: |
864 | elantech_report_trackpoint(psmouse, packet_type); | 864 | elantech_report_trackpoint(psmouse, packet_type); |
865 | break; | 865 | break; |
866 | 866 | ||
867 | default: | 867 | default: |
868 | elantech_report_absolute_v3(psmouse, packet_type); | 868 | elantech_report_absolute_v3(psmouse, packet_type); |
869 | break; | 869 | break; |
870 | } | 870 | } |
871 | 871 | ||
872 | break; | 872 | break; |
873 | 873 | ||
874 | case 4: | 874 | case 4: |
875 | packet_type = elantech_packet_check_v4(psmouse); | 875 | packet_type = elantech_packet_check_v4(psmouse); |
876 | switch (packet_type) { | 876 | switch (packet_type) { |
877 | case PACKET_UNKNOWN: | 877 | case PACKET_UNKNOWN: |
878 | return PSMOUSE_BAD_DATA; | 878 | return PSMOUSE_BAD_DATA; |
879 | 879 | ||
880 | case PACKET_TRACKPOINT: | 880 | case PACKET_TRACKPOINT: |
881 | elantech_report_trackpoint(psmouse, packet_type); | 881 | elantech_report_trackpoint(psmouse, packet_type); |
882 | break; | 882 | break; |
883 | 883 | ||
884 | default: | 884 | default: |
885 | elantech_report_absolute_v4(psmouse, packet_type); | 885 | elantech_report_absolute_v4(psmouse, packet_type); |
886 | break; | 886 | break; |
887 | } | 887 | } |
888 | 888 | ||
889 | break; | 889 | break; |
890 | } | 890 | } |
891 | 891 | ||
892 | return PSMOUSE_FULL_PACKET; | 892 | return PSMOUSE_FULL_PACKET; |
893 | } | 893 | } |
894 | 894 | ||
895 | /* | 895 | /* |
896 | * Put the touchpad into absolute mode | 896 | * Put the touchpad into absolute mode |
897 | */ | 897 | */ |
898 | static int elantech_set_absolute_mode(struct psmouse *psmouse) | 898 | static int elantech_set_absolute_mode(struct psmouse *psmouse) |
899 | { | 899 | { |
900 | struct elantech_data *etd = psmouse->private; | 900 | struct elantech_data *etd = psmouse->private; |
901 | unsigned char val; | 901 | unsigned char val; |
902 | int tries = ETP_READ_BACK_TRIES; | 902 | int tries = ETP_READ_BACK_TRIES; |
903 | int rc = 0; | 903 | int rc = 0; |
904 | 904 | ||
905 | switch (etd->hw_version) { | 905 | switch (etd->hw_version) { |
906 | case 1: | 906 | case 1: |
907 | etd->reg_10 = 0x16; | 907 | etd->reg_10 = 0x16; |
908 | etd->reg_11 = 0x8f; | 908 | etd->reg_11 = 0x8f; |
909 | if (elantech_write_reg(psmouse, 0x10, etd->reg_10) || | 909 | if (elantech_write_reg(psmouse, 0x10, etd->reg_10) || |
910 | elantech_write_reg(psmouse, 0x11, etd->reg_11)) { | 910 | elantech_write_reg(psmouse, 0x11, etd->reg_11)) { |
911 | rc = -1; | 911 | rc = -1; |
912 | } | 912 | } |
913 | break; | 913 | break; |
914 | 914 | ||
915 | case 2: | 915 | case 2: |
916 | /* Windows driver values */ | 916 | /* Windows driver values */ |
917 | etd->reg_10 = 0x54; | 917 | etd->reg_10 = 0x54; |
918 | etd->reg_11 = 0x88; /* 0x8a */ | 918 | etd->reg_11 = 0x88; /* 0x8a */ |
919 | etd->reg_21 = 0x60; /* 0x00 */ | 919 | etd->reg_21 = 0x60; /* 0x00 */ |
920 | if (elantech_write_reg(psmouse, 0x10, etd->reg_10) || | 920 | if (elantech_write_reg(psmouse, 0x10, etd->reg_10) || |
921 | elantech_write_reg(psmouse, 0x11, etd->reg_11) || | 921 | elantech_write_reg(psmouse, 0x11, etd->reg_11) || |
922 | elantech_write_reg(psmouse, 0x21, etd->reg_21)) { | 922 | elantech_write_reg(psmouse, 0x21, etd->reg_21)) { |
923 | rc = -1; | 923 | rc = -1; |
924 | } | 924 | } |
925 | break; | 925 | break; |
926 | 926 | ||
927 | case 3: | 927 | case 3: |
928 | if (etd->set_hw_resolution) | 928 | if (etd->set_hw_resolution) |
929 | etd->reg_10 = 0x0b; | 929 | etd->reg_10 = 0x0b; |
930 | else | 930 | else |
931 | etd->reg_10 = 0x01; | 931 | etd->reg_10 = 0x01; |
932 | 932 | ||
933 | if (elantech_write_reg(psmouse, 0x10, etd->reg_10)) | 933 | if (elantech_write_reg(psmouse, 0x10, etd->reg_10)) |
934 | rc = -1; | 934 | rc = -1; |
935 | 935 | ||
936 | break; | 936 | break; |
937 | 937 | ||
938 | case 4: | 938 | case 4: |
939 | etd->reg_07 = 0x01; | 939 | etd->reg_07 = 0x01; |
940 | if (elantech_write_reg(psmouse, 0x07, etd->reg_07)) | 940 | if (elantech_write_reg(psmouse, 0x07, etd->reg_07)) |
941 | rc = -1; | 941 | rc = -1; |
942 | 942 | ||
943 | goto skip_readback_reg_10; /* v4 has no reg 0x10 to read */ | 943 | goto skip_readback_reg_10; /* v4 has no reg 0x10 to read */ |
944 | } | 944 | } |
945 | 945 | ||
946 | if (rc == 0) { | 946 | if (rc == 0) { |
947 | /* | 947 | /* |
948 | * Read back reg 0x10. For hardware version 1 we must make | 948 | * Read back reg 0x10. For hardware version 1 we must make |
949 | * sure the absolute mode bit is set. For hardware version 2 | 949 | * sure the absolute mode bit is set. For hardware version 2 |
950 | * the touchpad is probably initializing and not ready until | 950 | * the touchpad is probably initializing and not ready until |
951 | * we read back the value we just wrote. | 951 | * we read back the value we just wrote. |
952 | */ | 952 | */ |
953 | do { | 953 | do { |
954 | rc = elantech_read_reg(psmouse, 0x10, &val); | 954 | rc = elantech_read_reg(psmouse, 0x10, &val); |
955 | if (rc == 0) | 955 | if (rc == 0) |
956 | break; | 956 | break; |
957 | tries--; | 957 | tries--; |
958 | elantech_debug("retrying read (%d).\n", tries); | 958 | elantech_debug("retrying read (%d).\n", tries); |
959 | msleep(ETP_READ_BACK_DELAY); | 959 | msleep(ETP_READ_BACK_DELAY); |
960 | } while (tries > 0); | 960 | } while (tries > 0); |
961 | 961 | ||
962 | if (rc) { | 962 | if (rc) { |
963 | psmouse_err(psmouse, | 963 | psmouse_err(psmouse, |
964 | "failed to read back register 0x10.\n"); | 964 | "failed to read back register 0x10.\n"); |
965 | } else if (etd->hw_version == 1 && | 965 | } else if (etd->hw_version == 1 && |
966 | !(val & ETP_R10_ABSOLUTE_MODE)) { | 966 | !(val & ETP_R10_ABSOLUTE_MODE)) { |
967 | psmouse_err(psmouse, | 967 | psmouse_err(psmouse, |
968 | "touchpad refuses to switch to absolute mode.\n"); | 968 | "touchpad refuses to switch to absolute mode.\n"); |
969 | rc = -1; | 969 | rc = -1; |
970 | } | 970 | } |
971 | } | 971 | } |
972 | 972 | ||
973 | skip_readback_reg_10: | 973 | skip_readback_reg_10: |
974 | if (rc) | 974 | if (rc) |
975 | psmouse_err(psmouse, "failed to initialise registers.\n"); | 975 | psmouse_err(psmouse, "failed to initialise registers.\n"); |
976 | 976 | ||
977 | return rc; | 977 | return rc; |
978 | } | 978 | } |
979 | 979 | ||
980 | static int elantech_set_range(struct psmouse *psmouse, | 980 | static int elantech_set_range(struct psmouse *psmouse, |
981 | unsigned int *x_min, unsigned int *y_min, | 981 | unsigned int *x_min, unsigned int *y_min, |
982 | unsigned int *x_max, unsigned int *y_max, | 982 | unsigned int *x_max, unsigned int *y_max, |
983 | unsigned int *width) | 983 | unsigned int *width) |
984 | { | 984 | { |
985 | struct elantech_data *etd = psmouse->private; | 985 | struct elantech_data *etd = psmouse->private; |
986 | unsigned char param[3]; | 986 | unsigned char param[3]; |
987 | unsigned char traces; | 987 | unsigned char traces; |
988 | 988 | ||
989 | switch (etd->hw_version) { | 989 | switch (etd->hw_version) { |
990 | case 1: | 990 | case 1: |
991 | *x_min = ETP_XMIN_V1; | 991 | *x_min = ETP_XMIN_V1; |
992 | *y_min = ETP_YMIN_V1; | 992 | *y_min = ETP_YMIN_V1; |
993 | *x_max = ETP_XMAX_V1; | 993 | *x_max = ETP_XMAX_V1; |
994 | *y_max = ETP_YMAX_V1; | 994 | *y_max = ETP_YMAX_V1; |
995 | break; | 995 | break; |
996 | 996 | ||
997 | case 2: | 997 | case 2: |
998 | if (etd->fw_version == 0x020800 || | 998 | if (etd->fw_version == 0x020800 || |
999 | etd->fw_version == 0x020b00 || | 999 | etd->fw_version == 0x020b00 || |
1000 | etd->fw_version == 0x020030) { | 1000 | etd->fw_version == 0x020030) { |
1001 | *x_min = ETP_XMIN_V2; | 1001 | *x_min = ETP_XMIN_V2; |
1002 | *y_min = ETP_YMIN_V2; | 1002 | *y_min = ETP_YMIN_V2; |
1003 | *x_max = ETP_XMAX_V2; | 1003 | *x_max = ETP_XMAX_V2; |
1004 | *y_max = ETP_YMAX_V2; | 1004 | *y_max = ETP_YMAX_V2; |
1005 | } else { | 1005 | } else { |
1006 | int i; | 1006 | int i; |
1007 | int fixed_dpi; | 1007 | int fixed_dpi; |
1008 | 1008 | ||
1009 | i = (etd->fw_version > 0x020800 && | 1009 | i = (etd->fw_version > 0x020800 && |
1010 | etd->fw_version < 0x020900) ? 1 : 2; | 1010 | etd->fw_version < 0x020900) ? 1 : 2; |
1011 | 1011 | ||
1012 | if (etd->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) | 1012 | if (etd->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) |
1013 | return -1; | 1013 | return -1; |
1014 | 1014 | ||
1015 | fixed_dpi = param[1] & 0x10; | 1015 | fixed_dpi = param[1] & 0x10; |
1016 | 1016 | ||
1017 | if (((etd->fw_version >> 16) == 0x14) && fixed_dpi) { | 1017 | if (((etd->fw_version >> 16) == 0x14) && fixed_dpi) { |
1018 | if (etd->send_cmd(psmouse, ETP_SAMPLE_QUERY, param)) | 1018 | if (etd->send_cmd(psmouse, ETP_SAMPLE_QUERY, param)) |
1019 | return -1; | 1019 | return -1; |
1020 | 1020 | ||
1021 | *x_max = (etd->capabilities[1] - i) * param[1] / 2; | 1021 | *x_max = (etd->capabilities[1] - i) * param[1] / 2; |
1022 | *y_max = (etd->capabilities[2] - i) * param[2] / 2; | 1022 | *y_max = (etd->capabilities[2] - i) * param[2] / 2; |
1023 | } else if (etd->fw_version == 0x040216) { | 1023 | } else if (etd->fw_version == 0x040216) { |
1024 | *x_max = 819; | 1024 | *x_max = 819; |
1025 | *y_max = 405; | 1025 | *y_max = 405; |
1026 | } else if (etd->fw_version == 0x040219 || etd->fw_version == 0x040215) { | 1026 | } else if (etd->fw_version == 0x040219 || etd->fw_version == 0x040215) { |
1027 | *x_max = 900; | 1027 | *x_max = 900; |
1028 | *y_max = 500; | 1028 | *y_max = 500; |
1029 | } else { | 1029 | } else { |
1030 | *x_max = (etd->capabilities[1] - i) * 64; | 1030 | *x_max = (etd->capabilities[1] - i) * 64; |
1031 | *y_max = (etd->capabilities[2] - i) * 64; | 1031 | *y_max = (etd->capabilities[2] - i) * 64; |
1032 | } | 1032 | } |
1033 | } | 1033 | } |
1034 | break; | 1034 | break; |
1035 | 1035 | ||
1036 | case 3: | 1036 | case 3: |
1037 | if (etd->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) | 1037 | if (etd->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) |
1038 | return -1; | 1038 | return -1; |
1039 | 1039 | ||
1040 | *x_max = (0x0f & param[0]) << 8 | param[1]; | 1040 | *x_max = (0x0f & param[0]) << 8 | param[1]; |
1041 | *y_max = (0xf0 & param[0]) << 4 | param[2]; | 1041 | *y_max = (0xf0 & param[0]) << 4 | param[2]; |
1042 | break; | 1042 | break; |
1043 | 1043 | ||
1044 | case 4: | 1044 | case 4: |
1045 | if (etd->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) | 1045 | if (etd->send_cmd(psmouse, ETP_FW_ID_QUERY, param)) |
1046 | return -1; | 1046 | return -1; |
1047 | 1047 | ||
1048 | *x_max = (0x0f & param[0]) << 8 | param[1]; | 1048 | *x_max = (0x0f & param[0]) << 8 | param[1]; |
1049 | *y_max = (0xf0 & param[0]) << 4 | param[2]; | 1049 | *y_max = (0xf0 & param[0]) << 4 | param[2]; |
1050 | traces = etd->capabilities[1]; | 1050 | traces = etd->capabilities[1]; |
1051 | if ((traces < 2) || (traces > *x_max)) | 1051 | if ((traces < 2) || (traces > *x_max)) |
1052 | return -1; | 1052 | return -1; |
1053 | 1053 | ||
1054 | *width = *x_max / (traces - 1); | 1054 | *width = *x_max / (traces - 1); |
1055 | break; | 1055 | break; |
1056 | } | 1056 | } |
1057 | 1057 | ||
1058 | return 0; | 1058 | return 0; |
1059 | } | 1059 | } |
1060 | 1060 | ||
1061 | /* | 1061 | /* |
1062 | * (value from firmware) * 10 + 790 = dpi | 1062 | * (value from firmware) * 10 + 790 = dpi |
1063 | * we also have to convert dpi to dots/mm (*10/254 to avoid floating point) | 1063 | * we also have to convert dpi to dots/mm (*10/254 to avoid floating point) |
1064 | */ | 1064 | */ |
1065 | static unsigned int elantech_convert_res(unsigned int val) | 1065 | static unsigned int elantech_convert_res(unsigned int val) |
1066 | { | 1066 | { |
1067 | return (val * 10 + 790) * 10 / 254; | 1067 | return (val * 10 + 790) * 10 / 254; |
1068 | } | 1068 | } |
1069 | 1069 | ||
1070 | static int elantech_get_resolution_v4(struct psmouse *psmouse, | 1070 | static int elantech_get_resolution_v4(struct psmouse *psmouse, |
1071 | unsigned int *x_res, | 1071 | unsigned int *x_res, |
1072 | unsigned int *y_res) | 1072 | unsigned int *y_res) |
1073 | { | 1073 | { |
1074 | unsigned char param[3]; | 1074 | unsigned char param[3]; |
1075 | 1075 | ||
1076 | if (elantech_send_cmd(psmouse, ETP_RESOLUTION_QUERY, param)) | 1076 | if (elantech_send_cmd(psmouse, ETP_RESOLUTION_QUERY, param)) |
1077 | return -1; | 1077 | return -1; |
1078 | 1078 | ||
1079 | *x_res = elantech_convert_res(param[1] & 0x0f); | 1079 | *x_res = elantech_convert_res(param[1] & 0x0f); |
1080 | *y_res = elantech_convert_res((param[1] & 0xf0) >> 4); | 1080 | *y_res = elantech_convert_res((param[1] & 0xf0) >> 4); |
1081 | 1081 | ||
1082 | return 0; | 1082 | return 0; |
1083 | } | 1083 | } |
1084 | 1084 | ||
1085 | /* | 1085 | /* |
1086 | * Advertise INPUT_PROP_BUTTONPAD for clickpads. The testing of bit 12 in | 1086 | * Advertise INPUT_PROP_BUTTONPAD for clickpads. The testing of bit 12 in |
1087 | * fw_version for this is based on the following fw_version & caps table: | 1087 | * fw_version for this is based on the following fw_version & caps table: |
1088 | * | 1088 | * |
1089 | * Laptop-model: fw_version: caps: buttons: | 1089 | * Laptop-model: fw_version: caps: buttons: |
1090 | * Acer S3 0x461f00 10, 13, 0e clickpad | 1090 | * Acer S3 0x461f00 10, 13, 0e clickpad |
1091 | * Acer S7-392 0x581f01 50, 17, 0d clickpad | 1091 | * Acer S7-392 0x581f01 50, 17, 0d clickpad |
1092 | * Acer V5-131 0x461f02 01, 16, 0c clickpad | 1092 | * Acer V5-131 0x461f02 01, 16, 0c clickpad |
1093 | * Acer V5-551 0x461f00 ? clickpad | 1093 | * Acer V5-551 0x461f00 ? clickpad |
1094 | * Asus K53SV 0x450f01 78, 15, 0c 2 hw buttons | 1094 | * Asus K53SV 0x450f01 78, 15, 0c 2 hw buttons |
1095 | * Asus G46VW 0x460f02 00, 18, 0c 2 hw buttons | 1095 | * Asus G46VW 0x460f02 00, 18, 0c 2 hw buttons |
1096 | * Asus G750JX 0x360f00 00, 16, 0c 2 hw buttons | 1096 | * Asus G750JX 0x360f00 00, 16, 0c 2 hw buttons |
1097 | * Asus UX31 0x361f00 20, 15, 0e clickpad | 1097 | * Asus UX31 0x361f00 20, 15, 0e clickpad |
1098 | * Asus UX32VD 0x361f02 00, 15, 0e clickpad | 1098 | * Asus UX32VD 0x361f02 00, 15, 0e clickpad |
1099 | * Avatar AVIU-145A2 0x361f00 ? clickpad | 1099 | * Avatar AVIU-145A2 0x361f00 ? clickpad |
1100 | * Fujitsu LIFEBOOK E544 0x470f00 d0, 12, 09 2 hw buttons | ||
1101 | * Fujitsu LIFEBOOK E554 0x570f01 40, 14, 0c 2 hw buttons | ||
1100 | * Fujitsu H730 0x570f00 c0, 14, 0c 3 hw buttons (**) | 1102 | * Fujitsu H730 0x570f00 c0, 14, 0c 3 hw buttons (**) |
1101 | * Gigabyte U2442 0x450f01 58, 17, 0c 2 hw buttons | 1103 | * Gigabyte U2442 0x450f01 58, 17, 0c 2 hw buttons |
1102 | * Lenovo L430 0x350f02 b9, 15, 0c 2 hw buttons (*) | 1104 | * Lenovo L430 0x350f02 b9, 15, 0c 2 hw buttons (*) |
1103 | * Lenovo L530 0x350f02 b9, 15, 0c 2 hw buttons (*) | 1105 | * Lenovo L530 0x350f02 b9, 15, 0c 2 hw buttons (*) |
1104 | * Samsung NF210 0x150b00 78, 14, 0a 2 hw buttons | 1106 | * Samsung NF210 0x150b00 78, 14, 0a 2 hw buttons |
1105 | * Samsung NP770Z5E 0x575f01 10, 15, 0f clickpad | 1107 | * Samsung NP770Z5E 0x575f01 10, 15, 0f clickpad |
1106 | * Samsung NP700Z5B 0x361f06 21, 15, 0f clickpad | 1108 | * Samsung NP700Z5B 0x361f06 21, 15, 0f clickpad |
1107 | * Samsung NP900X3E-A02 0x575f03 ? clickpad | 1109 | * Samsung NP900X3E-A02 0x575f03 ? clickpad |
1108 | * Samsung NP-QX410 0x851b00 19, 14, 0c clickpad | 1110 | * Samsung NP-QX410 0x851b00 19, 14, 0c clickpad |
1109 | * Samsung RC512 0x450f00 08, 15, 0c 2 hw buttons | 1111 | * Samsung RC512 0x450f00 08, 15, 0c 2 hw buttons |
1110 | * Samsung RF710 0x450f00 ? 2 hw buttons | 1112 | * Samsung RF710 0x450f00 ? 2 hw buttons |
1111 | * System76 Pangolin 0x250f01 ? 2 hw buttons | 1113 | * System76 Pangolin 0x250f01 ? 2 hw buttons |
1112 | * (*) + 3 trackpoint buttons | 1114 | * (*) + 3 trackpoint buttons |
1113 | * (**) + 0 trackpoint buttons | 1115 | * (**) + 0 trackpoint buttons |
1114 | * Note: Lenovo L430 and Lenovo L430 have the same fw_version/caps | 1116 | * Note: Lenovo L430 and Lenovo L430 have the same fw_version/caps |
1115 | */ | 1117 | */ |
1116 | static void elantech_set_buttonpad_prop(struct psmouse *psmouse) | 1118 | static void elantech_set_buttonpad_prop(struct psmouse *psmouse) |
1117 | { | 1119 | { |
1118 | struct input_dev *dev = psmouse->dev; | 1120 | struct input_dev *dev = psmouse->dev; |
1119 | struct elantech_data *etd = psmouse->private; | 1121 | struct elantech_data *etd = psmouse->private; |
1120 | 1122 | ||
1121 | if (etd->fw_version & 0x001000) { | 1123 | if (etd->fw_version & 0x001000) { |
1122 | __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); | 1124 | __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); |
1123 | __clear_bit(BTN_RIGHT, dev->keybit); | 1125 | __clear_bit(BTN_RIGHT, dev->keybit); |
1124 | } | 1126 | } |
1125 | } | 1127 | } |
1126 | 1128 | ||
1127 | /* | 1129 | /* |
1128 | * Some hw_version 4 models do have a middle button | 1130 | * Some hw_version 4 models do have a middle button |
1129 | */ | 1131 | */ |
1130 | static const struct dmi_system_id elantech_dmi_has_middle_button[] = { | 1132 | static const struct dmi_system_id elantech_dmi_has_middle_button[] = { |
1131 | #if defined(CONFIG_DMI) && defined(CONFIG_X86) | 1133 | #if defined(CONFIG_DMI) && defined(CONFIG_X86) |
1132 | { | 1134 | { |
1133 | /* Fujitsu H730 has a middle button */ | 1135 | /* Fujitsu H730 has a middle button */ |
1134 | .matches = { | 1136 | .matches = { |
1135 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), | 1137 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), |
1136 | DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H730"), | 1138 | DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H730"), |
1137 | }, | 1139 | }, |
1138 | }, | 1140 | }, |
1139 | #endif | 1141 | #endif |
1140 | { } | 1142 | { } |
1141 | }; | 1143 | }; |
1142 | 1144 | ||
1143 | /* | 1145 | /* |
1144 | * Set the appropriate event bits for the input subsystem | 1146 | * Set the appropriate event bits for the input subsystem |
1145 | */ | 1147 | */ |
1146 | static int elantech_set_input_params(struct psmouse *psmouse) | 1148 | static int elantech_set_input_params(struct psmouse *psmouse) |
1147 | { | 1149 | { |
1148 | struct input_dev *dev = psmouse->dev; | 1150 | struct input_dev *dev = psmouse->dev; |
1149 | struct elantech_data *etd = psmouse->private; | 1151 | struct elantech_data *etd = psmouse->private; |
1150 | unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0, width = 0; | 1152 | unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0, width = 0; |
1151 | unsigned int x_res = 0, y_res = 0; | 1153 | unsigned int x_res = 0, y_res = 0; |
1152 | 1154 | ||
1153 | if (elantech_set_range(psmouse, &x_min, &y_min, &x_max, &y_max, &width)) | 1155 | if (elantech_set_range(psmouse, &x_min, &y_min, &x_max, &y_max, &width)) |
1154 | return -1; | 1156 | return -1; |
1155 | 1157 | ||
1156 | __set_bit(INPUT_PROP_POINTER, dev->propbit); | 1158 | __set_bit(INPUT_PROP_POINTER, dev->propbit); |
1157 | __set_bit(EV_KEY, dev->evbit); | 1159 | __set_bit(EV_KEY, dev->evbit); |
1158 | __set_bit(EV_ABS, dev->evbit); | 1160 | __set_bit(EV_ABS, dev->evbit); |
1159 | __clear_bit(EV_REL, dev->evbit); | 1161 | __clear_bit(EV_REL, dev->evbit); |
1160 | 1162 | ||
1161 | __set_bit(BTN_LEFT, dev->keybit); | 1163 | __set_bit(BTN_LEFT, dev->keybit); |
1162 | if (dmi_check_system(elantech_dmi_has_middle_button)) | 1164 | if (dmi_check_system(elantech_dmi_has_middle_button)) |
1163 | __set_bit(BTN_MIDDLE, dev->keybit); | 1165 | __set_bit(BTN_MIDDLE, dev->keybit); |
1164 | __set_bit(BTN_RIGHT, dev->keybit); | 1166 | __set_bit(BTN_RIGHT, dev->keybit); |
1165 | 1167 | ||
1166 | __set_bit(BTN_TOUCH, dev->keybit); | 1168 | __set_bit(BTN_TOUCH, dev->keybit); |
1167 | __set_bit(BTN_TOOL_FINGER, dev->keybit); | 1169 | __set_bit(BTN_TOOL_FINGER, dev->keybit); |
1168 | __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); | 1170 | __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); |
1169 | __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); | 1171 | __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); |
1170 | 1172 | ||
1171 | switch (etd->hw_version) { | 1173 | switch (etd->hw_version) { |
1172 | case 1: | 1174 | case 1: |
1173 | /* Rocker button */ | 1175 | /* Rocker button */ |
1174 | if (etd->fw_version < 0x020000 && | 1176 | if (etd->fw_version < 0x020000 && |
1175 | (etd->capabilities[0] & ETP_CAP_HAS_ROCKER)) { | 1177 | (etd->capabilities[0] & ETP_CAP_HAS_ROCKER)) { |
1176 | __set_bit(BTN_FORWARD, dev->keybit); | 1178 | __set_bit(BTN_FORWARD, dev->keybit); |
1177 | __set_bit(BTN_BACK, dev->keybit); | 1179 | __set_bit(BTN_BACK, dev->keybit); |
1178 | } | 1180 | } |
1179 | input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0); | 1181 | input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0); |
1180 | input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0); | 1182 | input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0); |
1181 | break; | 1183 | break; |
1182 | 1184 | ||
1183 | case 2: | 1185 | case 2: |
1184 | __set_bit(BTN_TOOL_QUADTAP, dev->keybit); | 1186 | __set_bit(BTN_TOOL_QUADTAP, dev->keybit); |
1185 | __set_bit(INPUT_PROP_SEMI_MT, dev->propbit); | 1187 | __set_bit(INPUT_PROP_SEMI_MT, dev->propbit); |
1186 | /* fall through */ | 1188 | /* fall through */ |
1187 | case 3: | 1189 | case 3: |
1188 | if (etd->hw_version == 3) | 1190 | if (etd->hw_version == 3) |
1189 | elantech_set_buttonpad_prop(psmouse); | 1191 | elantech_set_buttonpad_prop(psmouse); |
1190 | input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0); | 1192 | input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0); |
1191 | input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0); | 1193 | input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0); |
1192 | if (etd->reports_pressure) { | 1194 | if (etd->reports_pressure) { |
1193 | input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2, | 1195 | input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2, |
1194 | ETP_PMAX_V2, 0, 0); | 1196 | ETP_PMAX_V2, 0, 0); |
1195 | input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2, | 1197 | input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2, |
1196 | ETP_WMAX_V2, 0, 0); | 1198 | ETP_WMAX_V2, 0, 0); |
1197 | } | 1199 | } |
1198 | input_mt_init_slots(dev, 2, 0); | 1200 | input_mt_init_slots(dev, 2, 0); |
1199 | input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0); | 1201 | input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0); |
1200 | input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0); | 1202 | input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0); |
1201 | break; | 1203 | break; |
1202 | 1204 | ||
1203 | case 4: | 1205 | case 4: |
1204 | if (elantech_get_resolution_v4(psmouse, &x_res, &y_res)) { | 1206 | if (elantech_get_resolution_v4(psmouse, &x_res, &y_res)) { |
1205 | /* | 1207 | /* |
1206 | * if query failed, print a warning and leave the values | 1208 | * if query failed, print a warning and leave the values |
1207 | * zero to resemble synaptics.c behavior. | 1209 | * zero to resemble synaptics.c behavior. |
1208 | */ | 1210 | */ |
1209 | psmouse_warn(psmouse, "couldn't query resolution data.\n"); | 1211 | psmouse_warn(psmouse, "couldn't query resolution data.\n"); |
1210 | } | 1212 | } |
1211 | elantech_set_buttonpad_prop(psmouse); | 1213 | elantech_set_buttonpad_prop(psmouse); |
1212 | __set_bit(BTN_TOOL_QUADTAP, dev->keybit); | 1214 | __set_bit(BTN_TOOL_QUADTAP, dev->keybit); |
1213 | /* For X to recognize me as touchpad. */ | 1215 | /* For X to recognize me as touchpad. */ |
1214 | input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0); | 1216 | input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0); |
1215 | input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0); | 1217 | input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0); |
1216 | input_abs_set_res(dev, ABS_X, x_res); | 1218 | input_abs_set_res(dev, ABS_X, x_res); |
1217 | input_abs_set_res(dev, ABS_Y, y_res); | 1219 | input_abs_set_res(dev, ABS_Y, y_res); |
1218 | /* | 1220 | /* |
1219 | * range of pressure and width is the same as v2, | 1221 | * range of pressure and width is the same as v2, |
1220 | * report ABS_PRESSURE, ABS_TOOL_WIDTH for compatibility. | 1222 | * report ABS_PRESSURE, ABS_TOOL_WIDTH for compatibility. |
1221 | */ | 1223 | */ |
1222 | input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2, | 1224 | input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2, |
1223 | ETP_PMAX_V2, 0, 0); | 1225 | ETP_PMAX_V2, 0, 0); |
1224 | input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2, | 1226 | input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2, |
1225 | ETP_WMAX_V2, 0, 0); | 1227 | ETP_WMAX_V2, 0, 0); |
1226 | /* Multitouch capable pad, up to 5 fingers. */ | 1228 | /* Multitouch capable pad, up to 5 fingers. */ |
1227 | input_mt_init_slots(dev, ETP_MAX_FINGERS, 0); | 1229 | input_mt_init_slots(dev, ETP_MAX_FINGERS, 0); |
1228 | input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0); | 1230 | input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0); |
1229 | input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0); | 1231 | input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0); |
1230 | input_abs_set_res(dev, ABS_MT_POSITION_X, x_res); | 1232 | input_abs_set_res(dev, ABS_MT_POSITION_X, x_res); |
1231 | input_abs_set_res(dev, ABS_MT_POSITION_Y, y_res); | 1233 | input_abs_set_res(dev, ABS_MT_POSITION_Y, y_res); |
1232 | input_set_abs_params(dev, ABS_MT_PRESSURE, ETP_PMIN_V2, | 1234 | input_set_abs_params(dev, ABS_MT_PRESSURE, ETP_PMIN_V2, |
1233 | ETP_PMAX_V2, 0, 0); | 1235 | ETP_PMAX_V2, 0, 0); |
1234 | /* | 1236 | /* |
1235 | * The firmware reports how many trace lines the finger spans, | 1237 | * The firmware reports how many trace lines the finger spans, |
1236 | * convert to surface unit as Protocol-B requires. | 1238 | * convert to surface unit as Protocol-B requires. |
1237 | */ | 1239 | */ |
1238 | input_set_abs_params(dev, ABS_MT_TOUCH_MAJOR, 0, | 1240 | input_set_abs_params(dev, ABS_MT_TOUCH_MAJOR, 0, |
1239 | ETP_WMAX_V2 * width, 0, 0); | 1241 | ETP_WMAX_V2 * width, 0, 0); |
1240 | break; | 1242 | break; |
1241 | } | 1243 | } |
1242 | 1244 | ||
1243 | etd->y_max = y_max; | 1245 | etd->y_max = y_max; |
1244 | etd->width = width; | 1246 | etd->width = width; |
1245 | 1247 | ||
1246 | return 0; | 1248 | return 0; |
1247 | } | 1249 | } |
1248 | 1250 | ||
1249 | struct elantech_attr_data { | 1251 | struct elantech_attr_data { |
1250 | size_t field_offset; | 1252 | size_t field_offset; |
1251 | unsigned char reg; | 1253 | unsigned char reg; |
1252 | }; | 1254 | }; |
1253 | 1255 | ||
1254 | /* | 1256 | /* |
1255 | * Display a register value by reading a sysfs entry | 1257 | * Display a register value by reading a sysfs entry |
1256 | */ | 1258 | */ |
1257 | static ssize_t elantech_show_int_attr(struct psmouse *psmouse, void *data, | 1259 | static ssize_t elantech_show_int_attr(struct psmouse *psmouse, void *data, |
1258 | char *buf) | 1260 | char *buf) |
1259 | { | 1261 | { |
1260 | struct elantech_data *etd = psmouse->private; | 1262 | struct elantech_data *etd = psmouse->private; |
1261 | struct elantech_attr_data *attr = data; | 1263 | struct elantech_attr_data *attr = data; |
1262 | unsigned char *reg = (unsigned char *) etd + attr->field_offset; | 1264 | unsigned char *reg = (unsigned char *) etd + attr->field_offset; |
1263 | int rc = 0; | 1265 | int rc = 0; |
1264 | 1266 | ||
1265 | if (attr->reg) | 1267 | if (attr->reg) |
1266 | rc = elantech_read_reg(psmouse, attr->reg, reg); | 1268 | rc = elantech_read_reg(psmouse, attr->reg, reg); |
1267 | 1269 | ||
1268 | return sprintf(buf, "0x%02x\n", (attr->reg && rc) ? -1 : *reg); | 1270 | return sprintf(buf, "0x%02x\n", (attr->reg && rc) ? -1 : *reg); |
1269 | } | 1271 | } |
1270 | 1272 | ||
1271 | /* | 1273 | /* |
1272 | * Write a register value by writing a sysfs entry | 1274 | * Write a register value by writing a sysfs entry |
1273 | */ | 1275 | */ |
1274 | static ssize_t elantech_set_int_attr(struct psmouse *psmouse, | 1276 | static ssize_t elantech_set_int_attr(struct psmouse *psmouse, |
1275 | void *data, const char *buf, size_t count) | 1277 | void *data, const char *buf, size_t count) |
1276 | { | 1278 | { |
1277 | struct elantech_data *etd = psmouse->private; | 1279 | struct elantech_data *etd = psmouse->private; |
1278 | struct elantech_attr_data *attr = data; | 1280 | struct elantech_attr_data *attr = data; |
1279 | unsigned char *reg = (unsigned char *) etd + attr->field_offset; | 1281 | unsigned char *reg = (unsigned char *) etd + attr->field_offset; |
1280 | unsigned char value; | 1282 | unsigned char value; |
1281 | int err; | 1283 | int err; |
1282 | 1284 | ||
1283 | err = kstrtou8(buf, 16, &value); | 1285 | err = kstrtou8(buf, 16, &value); |
1284 | if (err) | 1286 | if (err) |
1285 | return err; | 1287 | return err; |
1286 | 1288 | ||
1287 | /* Do we need to preserve some bits for version 2 hardware too? */ | 1289 | /* Do we need to preserve some bits for version 2 hardware too? */ |
1288 | if (etd->hw_version == 1) { | 1290 | if (etd->hw_version == 1) { |
1289 | if (attr->reg == 0x10) | 1291 | if (attr->reg == 0x10) |
1290 | /* Force absolute mode always on */ | 1292 | /* Force absolute mode always on */ |
1291 | value |= ETP_R10_ABSOLUTE_MODE; | 1293 | value |= ETP_R10_ABSOLUTE_MODE; |
1292 | else if (attr->reg == 0x11) | 1294 | else if (attr->reg == 0x11) |
1293 | /* Force 4 byte mode always on */ | 1295 | /* Force 4 byte mode always on */ |
1294 | value |= ETP_R11_4_BYTE_MODE; | 1296 | value |= ETP_R11_4_BYTE_MODE; |
1295 | } | 1297 | } |
1296 | 1298 | ||
1297 | if (!attr->reg || elantech_write_reg(psmouse, attr->reg, value) == 0) | 1299 | if (!attr->reg || elantech_write_reg(psmouse, attr->reg, value) == 0) |
1298 | *reg = value; | 1300 | *reg = value; |
1299 | 1301 | ||
1300 | return count; | 1302 | return count; |
1301 | } | 1303 | } |
1302 | 1304 | ||
1303 | #define ELANTECH_INT_ATTR(_name, _register) \ | 1305 | #define ELANTECH_INT_ATTR(_name, _register) \ |
1304 | static struct elantech_attr_data elantech_attr_##_name = { \ | 1306 | static struct elantech_attr_data elantech_attr_##_name = { \ |
1305 | .field_offset = offsetof(struct elantech_data, _name), \ | 1307 | .field_offset = offsetof(struct elantech_data, _name), \ |
1306 | .reg = _register, \ | 1308 | .reg = _register, \ |
1307 | }; \ | 1309 | }; \ |
1308 | PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \ | 1310 | PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \ |
1309 | &elantech_attr_##_name, \ | 1311 | &elantech_attr_##_name, \ |
1310 | elantech_show_int_attr, \ | 1312 | elantech_show_int_attr, \ |
1311 | elantech_set_int_attr) | 1313 | elantech_set_int_attr) |
1312 | 1314 | ||
1313 | ELANTECH_INT_ATTR(reg_07, 0x07); | 1315 | ELANTECH_INT_ATTR(reg_07, 0x07); |
1314 | ELANTECH_INT_ATTR(reg_10, 0x10); | 1316 | ELANTECH_INT_ATTR(reg_10, 0x10); |
1315 | ELANTECH_INT_ATTR(reg_11, 0x11); | 1317 | ELANTECH_INT_ATTR(reg_11, 0x11); |
1316 | ELANTECH_INT_ATTR(reg_20, 0x20); | 1318 | ELANTECH_INT_ATTR(reg_20, 0x20); |
1317 | ELANTECH_INT_ATTR(reg_21, 0x21); | 1319 | ELANTECH_INT_ATTR(reg_21, 0x21); |
1318 | ELANTECH_INT_ATTR(reg_22, 0x22); | 1320 | ELANTECH_INT_ATTR(reg_22, 0x22); |
1319 | ELANTECH_INT_ATTR(reg_23, 0x23); | 1321 | ELANTECH_INT_ATTR(reg_23, 0x23); |
1320 | ELANTECH_INT_ATTR(reg_24, 0x24); | 1322 | ELANTECH_INT_ATTR(reg_24, 0x24); |
1321 | ELANTECH_INT_ATTR(reg_25, 0x25); | 1323 | ELANTECH_INT_ATTR(reg_25, 0x25); |
1322 | ELANTECH_INT_ATTR(reg_26, 0x26); | 1324 | ELANTECH_INT_ATTR(reg_26, 0x26); |
1323 | ELANTECH_INT_ATTR(debug, 0); | 1325 | ELANTECH_INT_ATTR(debug, 0); |
1324 | ELANTECH_INT_ATTR(paritycheck, 0); | 1326 | ELANTECH_INT_ATTR(paritycheck, 0); |
1325 | ELANTECH_INT_ATTR(crc_enabled, 0); | 1327 | ELANTECH_INT_ATTR(crc_enabled, 0); |
1326 | 1328 | ||
1327 | static struct attribute *elantech_attrs[] = { | 1329 | static struct attribute *elantech_attrs[] = { |
1328 | &psmouse_attr_reg_07.dattr.attr, | 1330 | &psmouse_attr_reg_07.dattr.attr, |
1329 | &psmouse_attr_reg_10.dattr.attr, | 1331 | &psmouse_attr_reg_10.dattr.attr, |
1330 | &psmouse_attr_reg_11.dattr.attr, | 1332 | &psmouse_attr_reg_11.dattr.attr, |
1331 | &psmouse_attr_reg_20.dattr.attr, | 1333 | &psmouse_attr_reg_20.dattr.attr, |
1332 | &psmouse_attr_reg_21.dattr.attr, | 1334 | &psmouse_attr_reg_21.dattr.attr, |
1333 | &psmouse_attr_reg_22.dattr.attr, | 1335 | &psmouse_attr_reg_22.dattr.attr, |
1334 | &psmouse_attr_reg_23.dattr.attr, | 1336 | &psmouse_attr_reg_23.dattr.attr, |
1335 | &psmouse_attr_reg_24.dattr.attr, | 1337 | &psmouse_attr_reg_24.dattr.attr, |
1336 | &psmouse_attr_reg_25.dattr.attr, | 1338 | &psmouse_attr_reg_25.dattr.attr, |
1337 | &psmouse_attr_reg_26.dattr.attr, | 1339 | &psmouse_attr_reg_26.dattr.attr, |
1338 | &psmouse_attr_debug.dattr.attr, | 1340 | &psmouse_attr_debug.dattr.attr, |
1339 | &psmouse_attr_paritycheck.dattr.attr, | 1341 | &psmouse_attr_paritycheck.dattr.attr, |
1340 | &psmouse_attr_crc_enabled.dattr.attr, | 1342 | &psmouse_attr_crc_enabled.dattr.attr, |
1341 | NULL | 1343 | NULL |
1342 | }; | 1344 | }; |
1343 | 1345 | ||
1344 | static struct attribute_group elantech_attr_group = { | 1346 | static struct attribute_group elantech_attr_group = { |
1345 | .attrs = elantech_attrs, | 1347 | .attrs = elantech_attrs, |
1346 | }; | 1348 | }; |
1347 | 1349 | ||
1348 | static bool elantech_is_signature_valid(const unsigned char *param) | 1350 | static bool elantech_is_signature_valid(const unsigned char *param) |
1349 | { | 1351 | { |
1350 | static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10 }; | 1352 | static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10 }; |
1351 | int i; | 1353 | int i; |
1352 | 1354 | ||
1353 | if (param[0] == 0) | 1355 | if (param[0] == 0) |
1354 | return false; | 1356 | return false; |
1355 | 1357 | ||
1356 | if (param[1] == 0) | 1358 | if (param[1] == 0) |
1357 | return true; | 1359 | return true; |
1358 | 1360 | ||
1359 | /* | 1361 | /* |
1360 | * Some models have a revision higher then 20. Meaning param[2] may | 1362 | * Some models have a revision higher then 20. Meaning param[2] may |
1361 | * be 10 or 20, skip the rates check for these. | 1363 | * be 10 or 20, skip the rates check for these. |
1362 | */ | 1364 | */ |
1363 | if (param[0] == 0x46 && (param[1] & 0xef) == 0x0f && param[2] < 40) | 1365 | if (param[0] == 0x46 && (param[1] & 0xef) == 0x0f && param[2] < 40) |
1364 | return true; | 1366 | return true; |
1365 | 1367 | ||
1366 | for (i = 0; i < ARRAY_SIZE(rates); i++) | 1368 | for (i = 0; i < ARRAY_SIZE(rates); i++) |
1367 | if (param[2] == rates[i]) | 1369 | if (param[2] == rates[i]) |
1368 | return false; | 1370 | return false; |
1369 | 1371 | ||
1370 | return true; | 1372 | return true; |
1371 | } | 1373 | } |
1372 | 1374 | ||
1373 | /* | 1375 | /* |
1374 | * Use magic knock to detect Elantech touchpad | 1376 | * Use magic knock to detect Elantech touchpad |
1375 | */ | 1377 | */ |
1376 | int elantech_detect(struct psmouse *psmouse, bool set_properties) | 1378 | int elantech_detect(struct psmouse *psmouse, bool set_properties) |
1377 | { | 1379 | { |
1378 | struct ps2dev *ps2dev = &psmouse->ps2dev; | 1380 | struct ps2dev *ps2dev = &psmouse->ps2dev; |
1379 | unsigned char param[3]; | 1381 | unsigned char param[3]; |
1380 | 1382 | ||
1381 | ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); | 1383 | ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); |
1382 | 1384 | ||
1383 | if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || | 1385 | if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || |
1384 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || | 1386 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || |
1385 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || | 1387 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || |
1386 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || | 1388 | ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || |
1387 | ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) { | 1389 | ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) { |
1388 | psmouse_dbg(psmouse, "sending Elantech magic knock failed.\n"); | 1390 | psmouse_dbg(psmouse, "sending Elantech magic knock failed.\n"); |
1389 | return -1; | 1391 | return -1; |
1390 | } | 1392 | } |
1391 | 1393 | ||
1392 | /* | 1394 | /* |
1393 | * Report this in case there are Elantech models that use a different | 1395 | * Report this in case there are Elantech models that use a different |
1394 | * set of magic numbers | 1396 | * set of magic numbers |
1395 | */ | 1397 | */ |
1396 | if (param[0] != 0x3c || param[1] != 0x03 || | 1398 | if (param[0] != 0x3c || param[1] != 0x03 || |
1397 | (param[2] != 0xc8 && param[2] != 0x00)) { | 1399 | (param[2] != 0xc8 && param[2] != 0x00)) { |
1398 | psmouse_dbg(psmouse, | 1400 | psmouse_dbg(psmouse, |
1399 | "unexpected magic knock result 0x%02x, 0x%02x, 0x%02x.\n", | 1401 | "unexpected magic knock result 0x%02x, 0x%02x, 0x%02x.\n", |
1400 | param[0], param[1], param[2]); | 1402 | param[0], param[1], param[2]); |
1401 | return -1; | 1403 | return -1; |
1402 | } | 1404 | } |
1403 | 1405 | ||
1404 | /* | 1406 | /* |
1405 | * Query touchpad's firmware version and see if it reports known | 1407 | * Query touchpad's firmware version and see if it reports known |
1406 | * value to avoid mis-detection. Logitech mice are known to respond | 1408 | * value to avoid mis-detection. Logitech mice are known to respond |
1407 | * to Elantech magic knock and there might be more. | 1409 | * to Elantech magic knock and there might be more. |
1408 | */ | 1410 | */ |
1409 | if (synaptics_send_cmd(psmouse, ETP_FW_VERSION_QUERY, param)) { | 1411 | if (synaptics_send_cmd(psmouse, ETP_FW_VERSION_QUERY, param)) { |
1410 | psmouse_dbg(psmouse, "failed to query firmware version.\n"); | 1412 | psmouse_dbg(psmouse, "failed to query firmware version.\n"); |
1411 | return -1; | 1413 | return -1; |
1412 | } | 1414 | } |
1413 | 1415 | ||
1414 | psmouse_dbg(psmouse, | 1416 | psmouse_dbg(psmouse, |
1415 | "Elantech version query result 0x%02x, 0x%02x, 0x%02x.\n", | 1417 | "Elantech version query result 0x%02x, 0x%02x, 0x%02x.\n", |
1416 | param[0], param[1], param[2]); | 1418 | param[0], param[1], param[2]); |
1417 | 1419 | ||
1418 | if (!elantech_is_signature_valid(param)) { | 1420 | if (!elantech_is_signature_valid(param)) { |
1419 | psmouse_dbg(psmouse, | 1421 | psmouse_dbg(psmouse, |
1420 | "Probably not a real Elantech touchpad. Aborting.\n"); | 1422 | "Probably not a real Elantech touchpad. Aborting.\n"); |
1421 | return -1; | 1423 | return -1; |
1422 | } | 1424 | } |
1423 | 1425 | ||
1424 | if (set_properties) { | 1426 | if (set_properties) { |
1425 | psmouse->vendor = "Elantech"; | 1427 | psmouse->vendor = "Elantech"; |
1426 | psmouse->name = "Touchpad"; | 1428 | psmouse->name = "Touchpad"; |
1427 | } | 1429 | } |
1428 | 1430 | ||
1429 | return 0; | 1431 | return 0; |
1430 | } | 1432 | } |
1431 | 1433 | ||
1432 | /* | 1434 | /* |
1433 | * Clean up sysfs entries when disconnecting | 1435 | * Clean up sysfs entries when disconnecting |
1434 | */ | 1436 | */ |
1435 | static void elantech_disconnect(struct psmouse *psmouse) | 1437 | static void elantech_disconnect(struct psmouse *psmouse) |
1436 | { | 1438 | { |
1437 | struct elantech_data *etd = psmouse->private; | 1439 | struct elantech_data *etd = psmouse->private; |
1438 | 1440 | ||
1439 | if (etd->tp_dev) | 1441 | if (etd->tp_dev) |
1440 | input_unregister_device(etd->tp_dev); | 1442 | input_unregister_device(etd->tp_dev); |
1441 | sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, | 1443 | sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, |
1442 | &elantech_attr_group); | 1444 | &elantech_attr_group); |
1443 | kfree(psmouse->private); | 1445 | kfree(psmouse->private); |
1444 | psmouse->private = NULL; | 1446 | psmouse->private = NULL; |
1445 | } | 1447 | } |
1446 | 1448 | ||
1447 | /* | 1449 | /* |
1448 | * Put the touchpad back into absolute mode when reconnecting | 1450 | * Put the touchpad back into absolute mode when reconnecting |
1449 | */ | 1451 | */ |
1450 | static int elantech_reconnect(struct psmouse *psmouse) | 1452 | static int elantech_reconnect(struct psmouse *psmouse) |
1451 | { | 1453 | { |
1452 | psmouse_reset(psmouse); | 1454 | psmouse_reset(psmouse); |
1453 | 1455 | ||
1454 | if (elantech_detect(psmouse, 0)) | 1456 | if (elantech_detect(psmouse, 0)) |
1455 | return -1; | 1457 | return -1; |
1456 | 1458 | ||
1457 | if (elantech_set_absolute_mode(psmouse)) { | 1459 | if (elantech_set_absolute_mode(psmouse)) { |
1458 | psmouse_err(psmouse, | 1460 | psmouse_err(psmouse, |
1459 | "failed to put touchpad back into absolute mode.\n"); | 1461 | "failed to put touchpad back into absolute mode.\n"); |
1460 | return -1; | 1462 | return -1; |
1461 | } | 1463 | } |
1462 | 1464 | ||
1463 | return 0; | 1465 | return 0; |
1464 | } | 1466 | } |
1465 | 1467 | ||
1466 | /* | 1468 | /* |
1467 | * Some hw_version 4 models do not work with crc_disabled | 1469 | * Some hw_version 4 models do not work with crc_disabled |
1468 | */ | 1470 | */ |
1469 | static const struct dmi_system_id elantech_dmi_force_crc_enabled[] = { | 1471 | static const struct dmi_system_id elantech_dmi_force_crc_enabled[] = { |
1470 | #if defined(CONFIG_DMI) && defined(CONFIG_X86) | 1472 | #if defined(CONFIG_DMI) && defined(CONFIG_X86) |
1471 | { | 1473 | { |
1472 | /* Fujitsu H730 does not work with crc_enabled == 0 */ | 1474 | /* Fujitsu H730 does not work with crc_enabled == 0 */ |
1473 | .matches = { | 1475 | .matches = { |
1474 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), | 1476 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), |
1475 | DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H730"), | 1477 | DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H730"), |
1478 | }, | ||
1479 | }, | ||
1480 | { | ||
1481 | /* Fujitsu LIFEBOOK E554 does not work with crc_enabled == 0 */ | ||
1482 | .matches = { | ||
1483 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), | ||
1484 | DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E554"), | ||
1485 | }, | ||
1486 | }, | ||
1487 | { | ||
1488 | /* Fujitsu LIFEBOOK E544 does not work with crc_enabled == 0 */ | ||
1489 | .matches = { | ||
1490 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), | ||
1491 | DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E544"), | ||
1476 | }, | 1492 | }, |
1477 | }, | 1493 | }, |
1478 | #endif | 1494 | #endif |
1479 | { } | 1495 | { } |
1480 | }; | 1496 | }; |
1481 | 1497 | ||
1482 | /* | 1498 | /* |
1483 | * Some hw_version 3 models go into error state when we try to set | 1499 | * Some hw_version 3 models go into error state when we try to set |
1484 | * bit 3 and/or bit 1 of r10. | 1500 | * bit 3 and/or bit 1 of r10. |
1485 | */ | 1501 | */ |
1486 | static const struct dmi_system_id no_hw_res_dmi_table[] = { | 1502 | static const struct dmi_system_id no_hw_res_dmi_table[] = { |
1487 | #if defined(CONFIG_DMI) && defined(CONFIG_X86) | 1503 | #if defined(CONFIG_DMI) && defined(CONFIG_X86) |
1488 | { | 1504 | { |
1489 | /* Gigabyte U2442 */ | 1505 | /* Gigabyte U2442 */ |
1490 | .matches = { | 1506 | .matches = { |
1491 | DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), | 1507 | DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), |
1492 | DMI_MATCH(DMI_PRODUCT_NAME, "U2442"), | 1508 | DMI_MATCH(DMI_PRODUCT_NAME, "U2442"), |
1493 | }, | 1509 | }, |
1494 | }, | 1510 | }, |
1495 | #endif | 1511 | #endif |
1496 | { } | 1512 | { } |
1497 | }; | 1513 | }; |
1498 | 1514 | ||
1499 | /* | 1515 | /* |
1500 | * determine hardware version and set some properties according to it. | 1516 | * determine hardware version and set some properties according to it. |
1501 | */ | 1517 | */ |
1502 | static int elantech_set_properties(struct elantech_data *etd) | 1518 | static int elantech_set_properties(struct elantech_data *etd) |
1503 | { | 1519 | { |
1504 | /* This represents the version of IC body. */ | 1520 | /* This represents the version of IC body. */ |
1505 | int ver = (etd->fw_version & 0x0f0000) >> 16; | 1521 | int ver = (etd->fw_version & 0x0f0000) >> 16; |
1506 | 1522 | ||
1507 | /* Early version of Elan touchpads doesn't obey the rule. */ | 1523 | /* Early version of Elan touchpads doesn't obey the rule. */ |
1508 | if (etd->fw_version < 0x020030 || etd->fw_version == 0x020600) | 1524 | if (etd->fw_version < 0x020030 || etd->fw_version == 0x020600) |
1509 | etd->hw_version = 1; | 1525 | etd->hw_version = 1; |
1510 | else { | 1526 | else { |
1511 | switch (ver) { | 1527 | switch (ver) { |
1512 | case 2: | 1528 | case 2: |
1513 | case 4: | 1529 | case 4: |
1514 | etd->hw_version = 2; | 1530 | etd->hw_version = 2; |
1515 | break; | 1531 | break; |
1516 | case 5: | 1532 | case 5: |
1517 | etd->hw_version = 3; | 1533 | etd->hw_version = 3; |
1518 | break; | 1534 | break; |
1519 | case 6: | 1535 | case 6: |
1520 | case 7: | 1536 | case 7: |
1521 | case 8: | 1537 | case 8: |
1522 | case 9: | 1538 | case 9: |
1523 | case 10: | 1539 | case 10: |
1524 | case 13: | 1540 | case 13: |
1525 | etd->hw_version = 4; | 1541 | etd->hw_version = 4; |
1526 | break; | 1542 | break; |
1527 | default: | 1543 | default: |
1528 | return -1; | 1544 | return -1; |
1529 | } | 1545 | } |
1530 | } | 1546 | } |
1531 | 1547 | ||
1532 | /* decide which send_cmd we're gonna use early */ | 1548 | /* decide which send_cmd we're gonna use early */ |
1533 | etd->send_cmd = etd->hw_version >= 3 ? elantech_send_cmd : | 1549 | etd->send_cmd = etd->hw_version >= 3 ? elantech_send_cmd : |
1534 | synaptics_send_cmd; | 1550 | synaptics_send_cmd; |
1535 | 1551 | ||
1536 | /* Turn on packet checking by default */ | 1552 | /* Turn on packet checking by default */ |
1537 | etd->paritycheck = 1; | 1553 | etd->paritycheck = 1; |
1538 | 1554 | ||
1539 | /* | 1555 | /* |
1540 | * This firmware suffers from misreporting coordinates when | 1556 | * This firmware suffers from misreporting coordinates when |
1541 | * a touch action starts causing the mouse cursor or scrolled page | 1557 | * a touch action starts causing the mouse cursor or scrolled page |
1542 | * to jump. Enable a workaround. | 1558 | * to jump. Enable a workaround. |
1543 | */ | 1559 | */ |
1544 | etd->jumpy_cursor = | 1560 | etd->jumpy_cursor = |
1545 | (etd->fw_version == 0x020022 || etd->fw_version == 0x020600); | 1561 | (etd->fw_version == 0x020022 || etd->fw_version == 0x020600); |
1546 | 1562 | ||
1547 | if (etd->hw_version > 1) { | 1563 | if (etd->hw_version > 1) { |
1548 | /* For now show extra debug information */ | 1564 | /* For now show extra debug information */ |
1549 | etd->debug = 1; | 1565 | etd->debug = 1; |
1550 | 1566 | ||
1551 | if (etd->fw_version >= 0x020800) | 1567 | if (etd->fw_version >= 0x020800) |
1552 | etd->reports_pressure = true; | 1568 | etd->reports_pressure = true; |
1553 | } | 1569 | } |
1554 | 1570 | ||
1555 | /* | 1571 | /* |
1556 | * The signatures of v3 and v4 packets change depending on the | 1572 | * The signatures of v3 and v4 packets change depending on the |
1557 | * value of this hardware flag. | 1573 | * value of this hardware flag. |
1558 | */ | 1574 | */ |
1559 | etd->crc_enabled = (etd->fw_version & 0x4000) == 0x4000 || | 1575 | etd->crc_enabled = (etd->fw_version & 0x4000) == 0x4000 || |
1560 | dmi_check_system(elantech_dmi_force_crc_enabled); | 1576 | dmi_check_system(elantech_dmi_force_crc_enabled); |
1561 | 1577 | ||
1562 | /* Enable real hardware resolution on hw_version 3 ? */ | 1578 | /* Enable real hardware resolution on hw_version 3 ? */ |
1563 | etd->set_hw_resolution = !dmi_check_system(no_hw_res_dmi_table); | 1579 | etd->set_hw_resolution = !dmi_check_system(no_hw_res_dmi_table); |
1564 | 1580 | ||
1565 | return 0; | 1581 | return 0; |
1566 | } | 1582 | } |
1567 | 1583 | ||
1568 | /* | 1584 | /* |
1569 | * Initialize the touchpad and create sysfs entries | 1585 | * Initialize the touchpad and create sysfs entries |
1570 | */ | 1586 | */ |
1571 | int elantech_init(struct psmouse *psmouse) | 1587 | int elantech_init(struct psmouse *psmouse) |
1572 | { | 1588 | { |
1573 | struct elantech_data *etd; | 1589 | struct elantech_data *etd; |
1574 | int i; | 1590 | int i; |
1575 | int error = -EINVAL; | 1591 | int error = -EINVAL; |
1576 | unsigned char param[3]; | 1592 | unsigned char param[3]; |
1577 | struct input_dev *tp_dev; | 1593 | struct input_dev *tp_dev; |
1578 | 1594 | ||
1579 | psmouse->private = etd = kzalloc(sizeof(struct elantech_data), GFP_KERNEL); | 1595 | psmouse->private = etd = kzalloc(sizeof(struct elantech_data), GFP_KERNEL); |
1580 | if (!etd) | 1596 | if (!etd) |
1581 | return -ENOMEM; | 1597 | return -ENOMEM; |
1582 | 1598 | ||
1583 | psmouse_reset(psmouse); | 1599 | psmouse_reset(psmouse); |
1584 | 1600 | ||
1585 | etd->parity[0] = 1; | 1601 | etd->parity[0] = 1; |
1586 | for (i = 1; i < 256; i++) | 1602 | for (i = 1; i < 256; i++) |
1587 | etd->parity[i] = etd->parity[i & (i - 1)] ^ 1; | 1603 | etd->parity[i] = etd->parity[i & (i - 1)] ^ 1; |
1588 | 1604 | ||
1589 | /* | 1605 | /* |
1590 | * Do the version query again so we can store the result | 1606 | * Do the version query again so we can store the result |
1591 | */ | 1607 | */ |
1592 | if (synaptics_send_cmd(psmouse, ETP_FW_VERSION_QUERY, param)) { | 1608 | if (synaptics_send_cmd(psmouse, ETP_FW_VERSION_QUERY, param)) { |
1593 | psmouse_err(psmouse, "failed to query firmware version.\n"); | 1609 | psmouse_err(psmouse, "failed to query firmware version.\n"); |
1594 | goto init_fail; | 1610 | goto init_fail; |
1595 | } | 1611 | } |
1596 | etd->fw_version = (param[0] << 16) | (param[1] << 8) | param[2]; | 1612 | etd->fw_version = (param[0] << 16) | (param[1] << 8) | param[2]; |
1597 | 1613 | ||
1598 | if (elantech_set_properties(etd)) { | 1614 | if (elantech_set_properties(etd)) { |
1599 | psmouse_err(psmouse, "unknown hardware version, aborting...\n"); | 1615 | psmouse_err(psmouse, "unknown hardware version, aborting...\n"); |
1600 | goto init_fail; | 1616 | goto init_fail; |
1601 | } | 1617 | } |
1602 | psmouse_info(psmouse, | 1618 | psmouse_info(psmouse, |
1603 | "assuming hardware version %d (with firmware version 0x%02x%02x%02x)\n", | 1619 | "assuming hardware version %d (with firmware version 0x%02x%02x%02x)\n", |
1604 | etd->hw_version, param[0], param[1], param[2]); | 1620 | etd->hw_version, param[0], param[1], param[2]); |
1605 | 1621 | ||
1606 | if (etd->send_cmd(psmouse, ETP_CAPABILITIES_QUERY, | 1622 | if (etd->send_cmd(psmouse, ETP_CAPABILITIES_QUERY, |
1607 | etd->capabilities)) { | 1623 | etd->capabilities)) { |
1608 | psmouse_err(psmouse, "failed to query capabilities.\n"); | 1624 | psmouse_err(psmouse, "failed to query capabilities.\n"); |
1609 | goto init_fail; | 1625 | goto init_fail; |
1610 | } | 1626 | } |
1611 | psmouse_info(psmouse, | 1627 | psmouse_info(psmouse, |
1612 | "Synaptics capabilities query result 0x%02x, 0x%02x, 0x%02x.\n", | 1628 | "Synaptics capabilities query result 0x%02x, 0x%02x, 0x%02x.\n", |
1613 | etd->capabilities[0], etd->capabilities[1], | 1629 | etd->capabilities[0], etd->capabilities[1], |
1614 | etd->capabilities[2]); | 1630 | etd->capabilities[2]); |
1615 | 1631 | ||
1616 | if (elantech_set_absolute_mode(psmouse)) { | 1632 | if (elantech_set_absolute_mode(psmouse)) { |
1617 | psmouse_err(psmouse, | 1633 | psmouse_err(psmouse, |
1618 | "failed to put touchpad into absolute mode.\n"); | 1634 | "failed to put touchpad into absolute mode.\n"); |
1619 | goto init_fail; | 1635 | goto init_fail; |
1620 | } | 1636 | } |
1621 | 1637 | ||
1622 | if (elantech_set_input_params(psmouse)) { | 1638 | if (elantech_set_input_params(psmouse)) { |
1623 | psmouse_err(psmouse, "failed to query touchpad range.\n"); | 1639 | psmouse_err(psmouse, "failed to query touchpad range.\n"); |
1624 | goto init_fail; | 1640 | goto init_fail; |
1625 | } | 1641 | } |
1626 | 1642 | ||
1627 | error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj, | 1643 | error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj, |
1628 | &elantech_attr_group); | 1644 | &elantech_attr_group); |
1629 | if (error) { | 1645 | if (error) { |
1630 | psmouse_err(psmouse, | 1646 | psmouse_err(psmouse, |
1631 | "failed to create sysfs attributes, error: %d.\n", | 1647 | "failed to create sysfs attributes, error: %d.\n", |
1632 | error); | 1648 | error); |
1633 | goto init_fail; | 1649 | goto init_fail; |
1634 | } | 1650 | } |
1635 | 1651 | ||
1636 | /* The MSB indicates the presence of the trackpoint */ | 1652 | /* The MSB indicates the presence of the trackpoint */ |
1637 | if ((etd->capabilities[0] & 0x80) == 0x80) { | 1653 | if ((etd->capabilities[0] & 0x80) == 0x80) { |
1638 | tp_dev = input_allocate_device(); | 1654 | tp_dev = input_allocate_device(); |
1639 | 1655 | ||
1640 | if (!tp_dev) { | 1656 | if (!tp_dev) { |
1641 | error = -ENOMEM; | 1657 | error = -ENOMEM; |
1642 | goto init_fail_tp_alloc; | 1658 | goto init_fail_tp_alloc; |
1643 | } | 1659 | } |
1644 | 1660 | ||
1645 | etd->tp_dev = tp_dev; | 1661 | etd->tp_dev = tp_dev; |
1646 | snprintf(etd->tp_phys, sizeof(etd->tp_phys), "%s/input1", | 1662 | snprintf(etd->tp_phys, sizeof(etd->tp_phys), "%s/input1", |
1647 | psmouse->ps2dev.serio->phys); | 1663 | psmouse->ps2dev.serio->phys); |
1648 | tp_dev->phys = etd->tp_phys; | 1664 | tp_dev->phys = etd->tp_phys; |
1649 | tp_dev->name = "Elantech PS/2 TrackPoint"; | 1665 | tp_dev->name = "Elantech PS/2 TrackPoint"; |
1650 | tp_dev->id.bustype = BUS_I8042; | 1666 | tp_dev->id.bustype = BUS_I8042; |
1651 | tp_dev->id.vendor = 0x0002; | 1667 | tp_dev->id.vendor = 0x0002; |
1652 | tp_dev->id.product = PSMOUSE_ELANTECH; | 1668 | tp_dev->id.product = PSMOUSE_ELANTECH; |
1653 | tp_dev->id.version = 0x0000; | 1669 | tp_dev->id.version = 0x0000; |
1654 | tp_dev->dev.parent = &psmouse->ps2dev.serio->dev; | 1670 | tp_dev->dev.parent = &psmouse->ps2dev.serio->dev; |
1655 | tp_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); | 1671 | tp_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); |
1656 | tp_dev->relbit[BIT_WORD(REL_X)] = | 1672 | tp_dev->relbit[BIT_WORD(REL_X)] = |
1657 | BIT_MASK(REL_X) | BIT_MASK(REL_Y); | 1673 | BIT_MASK(REL_X) | BIT_MASK(REL_Y); |
1658 | tp_dev->keybit[BIT_WORD(BTN_LEFT)] = | 1674 | tp_dev->keybit[BIT_WORD(BTN_LEFT)] = |
1659 | BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) | | 1675 | BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) | |
1660 | BIT_MASK(BTN_RIGHT); | 1676 | BIT_MASK(BTN_RIGHT); |
1661 | 1677 | ||
1662 | __set_bit(INPUT_PROP_POINTER, tp_dev->propbit); | 1678 | __set_bit(INPUT_PROP_POINTER, tp_dev->propbit); |
1663 | __set_bit(INPUT_PROP_POINTING_STICK, tp_dev->propbit); | 1679 | __set_bit(INPUT_PROP_POINTING_STICK, tp_dev->propbit); |
1664 | 1680 | ||
1665 | error = input_register_device(etd->tp_dev); | 1681 | error = input_register_device(etd->tp_dev); |
1666 | if (error < 0) | 1682 | if (error < 0) |
1667 | goto init_fail_tp_reg; | 1683 | goto init_fail_tp_reg; |
1668 | } | 1684 | } |
1669 | 1685 | ||
1670 | psmouse->protocol_handler = elantech_process_byte; | 1686 | psmouse->protocol_handler = elantech_process_byte; |
1671 | psmouse->disconnect = elantech_disconnect; | 1687 | psmouse->disconnect = elantech_disconnect; |
1672 | psmouse->reconnect = elantech_reconnect; | 1688 | psmouse->reconnect = elantech_reconnect; |
1673 | psmouse->pktsize = etd->hw_version > 1 ? 6 : 4; | 1689 | psmouse->pktsize = etd->hw_version > 1 ? 6 : 4; |
1674 | 1690 | ||
1675 | return 0; | 1691 | return 0; |
1676 | init_fail_tp_reg: | 1692 | init_fail_tp_reg: |
1677 | input_free_device(tp_dev); | 1693 | input_free_device(tp_dev); |
1678 | init_fail_tp_alloc: | 1694 | init_fail_tp_alloc: |
1679 | sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, | 1695 | sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, |
1680 | &elantech_attr_group); | 1696 | &elantech_attr_group); |
1681 | init_fail: | 1697 | init_fail: |
1682 | psmouse_reset(psmouse); | 1698 | psmouse_reset(psmouse); |
1683 | kfree(etd); | 1699 | kfree(etd); |
1684 | return error; | 1700 | return error; |
1685 | } | 1701 | } |
1686 | 1702 |