Commit fc69f4a6af49ee69475dc4217924d9edf77760e0
Committed by
Dmitry Torokhov
1 parent
3b72094409
Exists in
master
and in
4 other branches
Input: add new driver for Sentelic Finger Sensing Pad
This is the driver for Sentelic Finger Sensing Pad which can be found on MSI WIND Netbook. Signed-off-by: Tai-hwa Liang <avatar@sentelic.com> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Showing 9 changed files with 1488 additions and 4 deletions Side-by-side Diff
Documentation/input/sentelic.txt
1 | +Copyright (C) 2002-2008 Sentelic Corporation. | |
2 | +Last update: Oct-31-2008 | |
3 | + | |
4 | +============================================================================== | |
5 | +* Finger Sensing Pad Intellimouse Mode(scrolling wheel, 4th and 5th buttons) | |
6 | +============================================================================== | |
7 | +A) MSID 4: Scrolling wheel mode plus Forward page(4th button) and Backward | |
8 | + page (5th button) | |
9 | +@1. Set sample rate to 200; | |
10 | +@2. Set sample rate to 200; | |
11 | +@3. Set sample rate to 80; | |
12 | +@4. Issuing the "Get device ID" command (0xF2) and waits for the response; | |
13 | +@5. FSP will respond 0x04. | |
14 | + | |
15 | +Packet 1 | |
16 | + Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 | |
17 | +BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------| | |
18 | + 1 |Y|X|y|x|1|M|R|L| 2 |X|X|X|X|X|X|X|X| 3 |Y|Y|Y|Y|Y|Y|Y|Y| 4 | | |B|F|W|W|W|W| | |
19 | + |---------------| |---------------| |---------------| |---------------| | |
20 | + | |
21 | +Byte 1: Bit7 => Y overflow | |
22 | + Bit6 => X overflow | |
23 | + Bit5 => Y sign bit | |
24 | + Bit4 => X sign bit | |
25 | + Bit3 => 1 | |
26 | + Bit2 => Middle Button, 1 is pressed, 0 is not pressed. | |
27 | + Bit1 => Right Button, 1 is pressed, 0 is not pressed. | |
28 | + Bit0 => Left Button, 1 is pressed, 0 is not pressed. | |
29 | +Byte 2: X Movement(9-bit 2's complement integers) | |
30 | +Byte 3: Y Movement(9-bit 2's complement integers) | |
31 | +Byte 4: Bit3~Bit0 => the scrolling wheel's movement since the last data report. | |
32 | + valid values, -8 ~ +7 | |
33 | + Bit4 => 1 = 4th mouse button is pressed, Forward one page. | |
34 | + 0 = 4th mouse button is not pressed. | |
35 | + Bit5 => 1 = 5th mouse button is pressed, Backward one page. | |
36 | + 0 = 5th mouse button is not pressed. | |
37 | + | |
38 | +B) MSID 6: Horizontal and Vertical scrolling. | |
39 | +@ Set bit 1 in register 0x40 to 1 | |
40 | + | |
41 | +# FSP replaces scrolling wheel's movement as 4 bits to show horizontal and | |
42 | + vertical scrolling. | |
43 | + | |
44 | +Packet 1 | |
45 | + Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 | |
46 | +BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------| | |
47 | + 1 |Y|X|y|x|1|M|R|L| 2 |X|X|X|X|X|X|X|X| 3 |Y|Y|Y|Y|Y|Y|Y|Y| 4 | | |B|F|l|r|u|d| | |
48 | + |---------------| |---------------| |---------------| |---------------| | |
49 | + | |
50 | +Byte 1: Bit7 => Y overflow | |
51 | + Bit6 => X overflow | |
52 | + Bit5 => Y sign bit | |
53 | + Bit4 => X sign bit | |
54 | + Bit3 => 1 | |
55 | + Bit2 => Middle Button, 1 is pressed, 0 is not pressed. | |
56 | + Bit1 => Right Button, 1 is pressed, 0 is not pressed. | |
57 | + Bit0 => Left Button, 1 is pressed, 0 is not pressed. | |
58 | +Byte 2: X Movement(9-bit 2's complement integers) | |
59 | +Byte 3: Y Movement(9-bit 2's complement integers) | |
60 | +Byte 4: Bit0 => the Vertical scrolling movement downward. | |
61 | + Bit1 => the Vertical scrolling movement upward. | |
62 | + Bit2 => the Vertical scrolling movement rightward. | |
63 | + Bit3 => the Vertical scrolling movement leftward. | |
64 | + Bit4 => 1 = 4th mouse button is pressed, Forward one page. | |
65 | + 0 = 4th mouse button is not pressed. | |
66 | + Bit5 => 1 = 5th mouse button is pressed, Backward one page. | |
67 | + 0 = 5th mouse button is not pressed. | |
68 | + | |
69 | +C) MSID 7: | |
70 | +# FSP uses 2 packets(8 Bytes) data to represent Absolute Position | |
71 | + so we have PACKET NUMBER to identify packets. | |
72 | + If PACKET NUMBER is 0, the packet is Packet 1. | |
73 | + If PACKET NUMBER is 1, the packet is Packet 2. | |
74 | + Please count this number in program. | |
75 | + | |
76 | +# MSID6 special packet will be enable at the same time when enable MSID 7. | |
77 | + | |
78 | +============================================================================== | |
79 | +* Absolute position for STL3886-G0. | |
80 | +============================================================================== | |
81 | +@ Set bit 2 or 3 in register 0x40 to 1 | |
82 | +@ Set bit 6 in register 0x40 to 1 | |
83 | + | |
84 | +Packet 1 (ABSOLUTE POSITION) | |
85 | + Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 | |
86 | +BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------| | |
87 | + 1 |0|1|V|1|1|M|R|L| 2 |X|X|X|X|X|X|X|X| 3 |Y|Y|Y|Y|Y|Y|Y|Y| 4 |r|l|d|u|X|X|Y|Y| | |
88 | + |---------------| |---------------| |---------------| |---------------| | |
89 | + | |
90 | +Byte 1: Bit7~Bit6 => 00, Normal data packet | |
91 | + => 01, Absolute coordination packet | |
92 | + => 10, Notify packet | |
93 | + Bit5 => valid bit | |
94 | + Bit4 => 1 | |
95 | + Bit3 => 1 | |
96 | + Bit2 => Middle Button, 1 is pressed, 0 is not pressed. | |
97 | + Bit1 => Right Button, 1 is pressed, 0 is not pressed. | |
98 | + Bit0 => Left Button, 1 is pressed, 0 is not pressed. | |
99 | +Byte 2: X coordinate (xpos[9:2]) | |
100 | +Byte 3: Y coordinate (ypos[9:2]) | |
101 | +Byte 4: Bit1~Bit0 => Y coordinate (xpos[1:0]) | |
102 | + Bit3~Bit2 => X coordinate (ypos[1:0]) | |
103 | + Bit4 => scroll up | |
104 | + Bit5 => scroll down | |
105 | + Bit6 => scroll left | |
106 | + Bit7 => scroll right | |
107 | + | |
108 | +Notify Packet for G0 | |
109 | + Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 | |
110 | +BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------| | |
111 | + 1 |1|0|0|1|1|M|R|L| 2 |C|C|C|C|C|C|C|C| 3 |M|M|M|M|M|M|M|M| 4 |0|0|0|0|0|0|0|0| | |
112 | + |---------------| |---------------| |---------------| |---------------| | |
113 | + | |
114 | +Byte 1: Bit7~Bit6 => 00, Normal data packet | |
115 | + => 01, Absolute coordination packet | |
116 | + => 10, Notify packet | |
117 | + Bit5 => 0 | |
118 | + Bit4 => 1 | |
119 | + Bit3 => 1 | |
120 | + Bit2 => Middle Button, 1 is pressed, 0 is not pressed. | |
121 | + Bit1 => Right Button, 1 is pressed, 0 is not pressed. | |
122 | + Bit0 => Left Button, 1 is pressed, 0 is not pressed. | |
123 | +Byte 2: Message Type => 0x5A (Enable/Disable status packet) | |
124 | + Mode Type => 0xA5 (Normal/Icon mode status) | |
125 | +Byte 3: Message Type => 0x00 (Disabled) | |
126 | + => 0x01 (Enabled) | |
127 | + Mode Type => 0x00 (Normal) | |
128 | + => 0x01 (Icon) | |
129 | +Byte 4: Bit7~Bit0 => Don't Care | |
130 | + | |
131 | +============================================================================== | |
132 | +* Absolute position for STL3888-A0. | |
133 | +============================================================================== | |
134 | +Packet 1 (ABSOLUTE POSITION) | |
135 | + Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 | |
136 | +BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------| | |
137 | + 1 |0|1|V|A|1|L|0|1| 2 |X|X|X|X|X|X|X|X| 3 |Y|Y|Y|Y|Y|Y|Y|Y| 4 |x|x|y|y|X|X|Y|Y| | |
138 | + |---------------| |---------------| |---------------| |---------------| | |
139 | + | |
140 | +Byte 1: Bit7~Bit6 => 00, Normal data packet | |
141 | + => 01, Absolute coordination packet | |
142 | + => 10, Notify packet | |
143 | + Bit5 => Valid bit, 0 means that the coordinate is invalid or finger up. | |
144 | + When both fingers are up, the last two reports have zero valid | |
145 | + bit. | |
146 | + Bit4 => arc | |
147 | + Bit3 => 1 | |
148 | + Bit2 => Left Button, 1 is pressed, 0 is released. | |
149 | + Bit1 => 0 | |
150 | + Bit0 => 1 | |
151 | +Byte 2: X coordinate (xpos[9:2]) | |
152 | +Byte 3: Y coordinate (ypos[9:2]) | |
153 | +Byte 4: Bit1~Bit0 => Y coordinate (xpos[1:0]) | |
154 | + Bit3~Bit2 => X coordinate (ypos[1:0]) | |
155 | + Bit5~Bit4 => y1_g | |
156 | + Bit7~Bit6 => x1_g | |
157 | + | |
158 | +Packet 2 (ABSOLUTE POSITION) | |
159 | + Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 | |
160 | +BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------| | |
161 | + 1 |0|1|V|A|1|R|1|0| 2 |X|X|X|X|X|X|X|X| 3 |Y|Y|Y|Y|Y|Y|Y|Y| 4 |x|x|y|y|X|X|Y|Y| | |
162 | + |---------------| |---------------| |---------------| |---------------| | |
163 | + | |
164 | +Byte 1: Bit7~Bit6 => 00, Normal data packet | |
165 | + => 01, Absolute coordinates packet | |
166 | + => 10, Notify packet | |
167 | + Bit5 => Valid bit, 0 means that the coordinate is invalid or finger up. | |
168 | + When both fingers are up, the last two reports have zero valid | |
169 | + bit. | |
170 | + Bit4 => arc | |
171 | + Bit3 => 1 | |
172 | + Bit2 => Right Button, 1 is pressed, 0 is released. | |
173 | + Bit1 => 1 | |
174 | + Bit0 => 0 | |
175 | +Byte 2: X coordinate (xpos[9:2]) | |
176 | +Byte 3: Y coordinate (ypos[9:2]) | |
177 | +Byte 4: Bit1~Bit0 => Y coordinate (xpos[1:0]) | |
178 | + Bit3~Bit2 => X coordinate (ypos[1:0]) | |
179 | + Bit5~Bit4 => y2_g | |
180 | + Bit7~Bit6 => x2_g | |
181 | + | |
182 | +Notify Packet for STL3888-A0 | |
183 | + Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 | |
184 | +BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------| | |
185 | + 1 |1|0|1|P|1|M|R|L| 2 |C|C|C|C|C|C|C|C| 3 |0|0|F|F|0|0|0|i| 4 |r|l|d|u|0|0|0|0| | |
186 | + |---------------| |---------------| |---------------| |---------------| | |
187 | + | |
188 | +Byte 1: Bit7~Bit6 => 00, Normal data packet | |
189 | + => 01, Absolute coordination packet | |
190 | + => 10, Notify packet | |
191 | + Bit5 => 1 | |
192 | + Bit4 => when in absolute coordinates mode (valid when EN_PKT_GO is 1): | |
193 | + 0: left button is generated by the on-pad command | |
194 | + 1: left button is generated by the external button | |
195 | + Bit3 => 1 | |
196 | + Bit2 => Middle Button, 1 is pressed, 0 is not pressed. | |
197 | + Bit1 => Right Button, 1 is pressed, 0 is not pressed. | |
198 | + Bit0 => Left Button, 1 is pressed, 0 is not pressed. | |
199 | +Byte 2: Message Type => 0xB7 (Multi Finger, Multi Coordinate mode) | |
200 | +Byte 3: Bit7~Bit6 => Don't care | |
201 | + Bit5~Bit4 => Number of fingers | |
202 | + Bit3~Bit1 => Reserved | |
203 | + Bit0 => 1: enter gesture mode; 0: leaving gesture mode | |
204 | +Byte 4: Bit7 => scroll right button | |
205 | + Bit6 => scroll left button | |
206 | + Bit5 => scroll down button | |
207 | + Bit4 => scroll up button | |
208 | + * Note that if gesture and additional button (Bit4~Bit7) | |
209 | + happen at the same time, the button information will not | |
210 | + be sent. | |
211 | + Bit3~Bit0 => Reserved | |
212 | + | |
213 | +Sample sequence of Multi-finger, Multi-coordinate mode: | |
214 | + | |
215 | + notify packet (valid bit == 1), abs pkt 1, abs pkt 2, abs pkt 1, | |
216 | + abs pkt 2, ..., notify packet(valid bit == 0) | |
217 | + | |
218 | +============================================================================== | |
219 | +* FSP Enable/Disable packet | |
220 | +============================================================================== | |
221 | + Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 | |
222 | +BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------| | |
223 | + 1 |Y|X|0|0|1|M|R|L| 2 |0|1|0|1|1|0|1|E| 3 | | | | | | | | | 4 | | | | | | | | | | |
224 | + |---------------| |---------------| |---------------| |---------------| | |
225 | + | |
226 | +FSP will send out enable/disable packet when FSP receive PS/2 enable/disable | |
227 | +command. Host will receive the packet which Middle, Right, Left button will | |
228 | +be set. The packet only use byte 0 and byte 1 as a pattern of original packet. | |
229 | +Ignore the other bytes of the packet. | |
230 | + | |
231 | +Byte 1: Bit7 => 0, Y overflow | |
232 | + Bit6 => 0, X overflow | |
233 | + Bit5 => 0, Y sign bit | |
234 | + Bit4 => 0, X sign bit | |
235 | + Bit3 => 1 | |
236 | + Bit2 => 1, Middle Button | |
237 | + Bit1 => 1, Right Button | |
238 | + Bit0 => 1, Left Button | |
239 | +Byte 2: Bit7~1 => (0101101b) | |
240 | + Bit0 => 1 = Enable | |
241 | + 0 = Disable | |
242 | +Byte 3: Don't care | |
243 | +Byte 4: Don't care (MOUSE ID 3, 4) | |
244 | +Byte 5~8: Don't care (Absolute packet) | |
245 | + | |
246 | +============================================================================== | |
247 | +* PS/2 Command Set | |
248 | +============================================================================== | |
249 | + | |
250 | +FSP supports basic PS/2 commanding set and modes, refer to following URL for | |
251 | +details about PS/2 commands: | |
252 | + | |
253 | +http://www.computer-engineering.org/index.php?title=PS/2_Mouse_Interface | |
254 | + | |
255 | +============================================================================== | |
256 | +* Programming Sequence for Determining Packet Parsing Flow | |
257 | +============================================================================== | |
258 | +1. Identify FSP by reading device ID(0x00) and version(0x01) register | |
259 | + | |
260 | +2. Determine number of buttons by reading status2 (0x0b) register | |
261 | + | |
262 | + buttons = reg[0x0b] & 0x30 | |
263 | + | |
264 | + if buttons == 0x30 or buttons == 0x20: | |
265 | + # two/four buttons | |
266 | + Refer to 'Finger Sensing Pad PS/2 Mouse Intellimouse' | |
267 | + section A for packet parsing detail(ignore byte 4, bit ~ 7) | |
268 | + elif buttons == 0x10: | |
269 | + # 6 buttons | |
270 | + Refer to 'Finger Sensing Pad PS/2 Mouse Intellimouse' | |
271 | + section B for packet parsing detail | |
272 | + elif buttons == 0x00: | |
273 | + # 6 buttons | |
274 | + Refer to 'Finger Sensing Pad PS/2 Mouse Intellimouse' | |
275 | + section A for packet parsing detail | |
276 | + | |
277 | +============================================================================== | |
278 | +* Programming Sequence for Register Reading/Writing | |
279 | +============================================================================== | |
280 | + | |
281 | +Register inversion requirement: | |
282 | + | |
283 | + Following values needed to be inverted(the '~' operator in C) before being | |
284 | +sent to FSP: | |
285 | + | |
286 | + 0xe9, 0xee, 0xf2 and 0xff. | |
287 | + | |
288 | +Register swapping requirement: | |
289 | + | |
290 | + Following values needed to have their higher 4 bits and lower 4 bits being | |
291 | +swapped before being sent to FSP: | |
292 | + | |
293 | + 10, 20, 40, 60, 80, 100 and 200. | |
294 | + | |
295 | +Register reading sequence: | |
296 | + | |
297 | + 1. send 0xf3 PS/2 command to FSP; | |
298 | + | |
299 | + 2. send 0x66 PS/2 command to FSP; | |
300 | + | |
301 | + 3. send 0x88 PS/2 command to FSP; | |
302 | + | |
303 | + 4. send 0xf3 PS/2 command to FSP; | |
304 | + | |
305 | + 5. if the register address being to read is not required to be | |
306 | + inverted(refer to the 'Register inversion requirement' section), | |
307 | + goto step 6 | |
308 | + | |
309 | + 5a. send 0x68 PS/2 command to FSP; | |
310 | + | |
311 | + 5b. send the inverted register address to FSP and goto step 8; | |
312 | + | |
313 | + 6. if the register address being to read is not required to be | |
314 | + swapped(refer to the 'Register swapping requirement' section), | |
315 | + goto step 7 | |
316 | + | |
317 | + 6a. send 0xcc PS/2 command to FSP; | |
318 | + | |
319 | + 6b. send the swapped register address to FSP and goto step 8; | |
320 | + | |
321 | + 7. send 0x66 PS/2 command to FSP; | |
322 | + | |
323 | + 7a. send the original register address to FSP and goto step 8; | |
324 | + | |
325 | + 8. send 0xe9(status request) PS/2 command to FSP; | |
326 | + | |
327 | + 9. the response read from FSP should be the requested register value. | |
328 | + | |
329 | +Register writing sequence: | |
330 | + | |
331 | + 1. send 0xf3 PS/2 command to FSP; | |
332 | + | |
333 | + 2. if the register address being to write is not required to be | |
334 | + inverted(refer to the 'Register inversion requirement' section), | |
335 | + goto step 3 | |
336 | + | |
337 | + 2a. send 0x74 PS/2 command to FSP; | |
338 | + | |
339 | + 2b. send the inverted register address to FSP and goto step 5; | |
340 | + | |
341 | + 3. if the register address being to write is not required to be | |
342 | + swapped(refer to the 'Register swapping requirement' section), | |
343 | + goto step 4 | |
344 | + | |
345 | + 3a. send 0x77 PS/2 command to FSP; | |
346 | + | |
347 | + 3b. send the swapped register address to FSP and goto step 5; | |
348 | + | |
349 | + 4. send 0x55 PS/2 command to FSP; | |
350 | + | |
351 | + 4a. send the register address to FSP and goto step 5; | |
352 | + | |
353 | + 5. send 0xf3 PS/2 command to FSP; | |
354 | + | |
355 | + 6. if the register value being to write is not required to be | |
356 | + inverted(refer to the 'Register inversion requirement' section), | |
357 | + goto step 7 | |
358 | + | |
359 | + 6a. send 0x47 PS/2 command to FSP; | |
360 | + | |
361 | + 6b. send the inverted register value to FSP and goto step 9; | |
362 | + | |
363 | + 7. if the register value being to write is not required to be | |
364 | + swapped(refer to the 'Register swapping requirement' section), | |
365 | + goto step 8 | |
366 | + | |
367 | + 7a. send 0x44 PS/2 command to FSP; | |
368 | + | |
369 | + 7b. send the swapped register value to FSP and goto step 9; | |
370 | + | |
371 | + 8. send 0x33 PS/2 command to FSP; | |
372 | + | |
373 | + 8a. send the register value to FSP; | |
374 | + | |
375 | + 9. the register writing sequence is completed. | |
376 | + | |
377 | +============================================================================== | |
378 | +* Register Listing | |
379 | +============================================================================== | |
380 | + | |
381 | +offset width default r/w name | |
382 | +0x00 bit7~bit0 0x01 RO device ID | |
383 | + | |
384 | +0x01 bit7~bit0 0xc0 RW version ID | |
385 | + | |
386 | +0x02 bit7~bit0 0x01 RO vendor ID | |
387 | + | |
388 | +0x03 bit7~bit0 0x01 RO product ID | |
389 | + | |
390 | +0x04 bit3~bit0 0x01 RW revision ID | |
391 | + | |
392 | +0x0b RO test mode status 1 | |
393 | + bit3 1 RO 0: rotate 180 degree, 1: no rotation | |
394 | + | |
395 | + bit5~bit4 RO number of buttons | |
396 | + 11 => 2, lbtn/rbtn | |
397 | + 10 => 4, lbtn/rbtn/scru/scrd | |
398 | + 01 => 6, lbtn/rbtn/scru/scrd/scrl/scrr | |
399 | + 00 => 6, lbtn/rbtn/scru/scrd/fbtn/bbtn | |
400 | + | |
401 | +0x0f RW register file page control | |
402 | + bit0 0 RW 1 to enable page 1 register files | |
403 | + | |
404 | +0x10 RW system control 1 | |
405 | + bit0 1 RW Reserved, must be 1 | |
406 | + bit1 0 RW Reserved, must be 0 | |
407 | + bit4 1 RW Reserved, must be 0 | |
408 | + bit5 0 RW register clock gating enable | |
409 | + 0: read only, 1: read/write enable | |
410 | + (Note that following registers does not require clock gating being | |
411 | + enabled prior to write: 05 06 07 08 09 0c 0f 10 11 12 16 17 18 23 2e | |
412 | + 40 41 42 43.) | |
413 | + | |
414 | +0x31 RW on-pad command detection | |
415 | + bit7 0 RW on-pad command left button down tag | |
416 | + enable | |
417 | + 0: disable, 1: enable | |
418 | + | |
419 | +0x34 RW on-pad command control 5 | |
420 | + bit4~bit0 0x05 RW XLO in 0s/4/1, so 03h = 0010.1b = 2.5 | |
421 | + (Note that position unit is in 0.5 scanline) | |
422 | + | |
423 | + bit7 0 RW on-pad tap zone enable | |
424 | + 0: disable, 1: enable | |
425 | + | |
426 | +0x35 RW on-pad command control 6 | |
427 | + bit4~bit0 0x1d RW XHI in 0s/4/1, so 19h = 1100.1b = 12.5 | |
428 | + (Note that position unit is in 0.5 scanline) | |
429 | + | |
430 | +0x36 RW on-pad command control 7 | |
431 | + bit4~bit0 0x04 RW YLO in 0s/4/1, so 03h = 0010.1b = 2.5 | |
432 | + (Note that position unit is in 0.5 scanline) | |
433 | + | |
434 | +0x37 RW on-pad command control 8 | |
435 | + bit4~bit0 0x13 RW YHI in 0s/4/1, so 11h = 1000.1b = 8.5 | |
436 | + (Note that position unit is in 0.5 scanline) | |
437 | + | |
438 | +0x40 RW system control 5 | |
439 | + bit1 0 RW FSP Intellimouse mode enable | |
440 | + 0: disable, 1: enable | |
441 | + | |
442 | + bit2 0 RW movement + abs. coordinate mode enable | |
443 | + 0: disable, 1: enable | |
444 | + (Note that this function has the functionality of bit 1 even when | |
445 | + bit 1 is not set. However, the format is different from that of bit 1. | |
446 | + In addition, when bit 1 and bit 2 are set at the same time, bit 2 will | |
447 | + override bit 1.) | |
448 | + | |
449 | + bit3 0 RW abs. coordinate only mode enable | |
450 | + 0: disable, 1: enable | |
451 | + (Note that this function has the functionality of bit 1 even when | |
452 | + bit 1 is not set. However, the format is different from that of bit 1. | |
453 | + In addition, when bit 1, bit 2 and bit 3 are set at the same time, | |
454 | + bit 3 will override bit 1 and 2.) | |
455 | + | |
456 | + bit5 0 RW auto switch enable | |
457 | + 0: disable, 1: enable | |
458 | + | |
459 | + bit6 0 RW G0 abs. + notify packet format enable | |
460 | + 0: disable, 1: enable | |
461 | + (Note that the absolute/relative coordinate output still depends on | |
462 | + bit 2 and 3. That is, if any of those bit is 1, host will receive | |
463 | + absolute coordinates; otherwise, host only receives packets with | |
464 | + relative coordinate.) | |
465 | + | |
466 | +0x43 RW on-pad control | |
467 | + bit0 0 RW on-pad control enable | |
468 | + 0: disable, 1: enable | |
469 | + (Note that if this bit is cleared, bit 3/5 will be ineffective) | |
470 | + | |
471 | + bit3 0 RW on-pad fix vertical scrolling enable | |
472 | + 0: disable, 1: enable | |
473 | + | |
474 | + bit5 0 RW on-pad fix horizontal scrolling enable | |
475 | + 0: disable, 1: enable |
drivers/input/mouse/Kconfig
... | ... | @@ -107,6 +107,14 @@ |
107 | 107 | entries. For further information, |
108 | 108 | see <file:Documentation/input/elantech.txt>. |
109 | 109 | |
110 | +config MOUSE_PS2_SENTELIC | |
111 | + bool "Sentelic Finger Sensing Pad PS/2 protocol extension" | |
112 | + depends on MOUSE_PS2 | |
113 | + help | |
114 | + Say Y here if you have a laptop (such as MSI WIND Netbook) | |
115 | + with Sentelic Finger Sensing Pad touchpad. | |
116 | + | |
117 | + If unsure, say N. | |
110 | 118 | |
111 | 119 | config MOUSE_PS2_TOUCHKIT |
112 | 120 | bool "eGalax TouchKit PS/2 protocol extension" |
drivers/input/mouse/Makefile
... | ... | @@ -27,6 +27,7 @@ |
27 | 27 | psmouse-$(CONFIG_MOUSE_PS2_OLPC) += hgpk.o |
28 | 28 | psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP) += logips2pp.o |
29 | 29 | psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK) += lifebook.o |
30 | +psmouse-$(CONFIG_MOUSE_PS2_SENTELIC) += sentelic.o | |
30 | 31 | psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT) += trackpoint.o |
31 | 32 | psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT) += touchkit_ps2.o |
drivers/input/mouse/psmouse-base.c
... | ... | @@ -30,6 +30,7 @@ |
30 | 30 | #include "trackpoint.h" |
31 | 31 | #include "touchkit_ps2.h" |
32 | 32 | #include "elantech.h" |
33 | +#include "sentelic.h" | |
33 | 34 | |
34 | 35 | #define DRIVER_DESC "PS/2 mouse driver" |
35 | 36 | |
36 | 37 | |
... | ... | @@ -666,7 +667,21 @@ |
666 | 667 | max_proto = PSMOUSE_IMEX; |
667 | 668 | } |
668 | 669 | |
670 | +/* | |
671 | + * Try Finger Sensing Pad | |
672 | + */ | |
669 | 673 | if (max_proto > PSMOUSE_IMEX) { |
674 | + if (fsp_detect(psmouse, set_properties) == 0) { | |
675 | + if (!set_properties || fsp_init(psmouse) == 0) | |
676 | + return PSMOUSE_FSP; | |
677 | +/* | |
678 | + * Init failed, try basic relative protocols | |
679 | + */ | |
680 | + max_proto = PSMOUSE_IMEX; | |
681 | + } | |
682 | + } | |
683 | + | |
684 | + if (max_proto > PSMOUSE_IMEX) { | |
670 | 685 | if (genius_detect(psmouse, set_properties) == 0) |
671 | 686 | return PSMOUSE_GENPS; |
672 | 687 | |
... | ... | @@ -813,7 +828,16 @@ |
813 | 828 | .detect = elantech_detect, |
814 | 829 | .init = elantech_init, |
815 | 830 | }, |
816 | - #endif | |
831 | +#endif | |
832 | +#ifdef CONFIG_MOUSE_PS2_SENTELIC | |
833 | + { | |
834 | + .type = PSMOUSE_FSP, | |
835 | + .name = "FSPPS/2", | |
836 | + .alias = "fsp", | |
837 | + .detect = fsp_detect, | |
838 | + .init = fsp_init, | |
839 | + }, | |
840 | +#endif | |
817 | 841 | { |
818 | 842 | .type = PSMOUSE_CORTRON, |
819 | 843 | .name = "CortronPS/2", |
drivers/input/mouse/psmouse.h
drivers/input/mouse/sentelic.c
1 | +/*- | |
2 | + * Finger Sensing Pad PS/2 mouse driver. | |
3 | + * | |
4 | + * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd. | |
5 | + * Copyright (C) 2005-2009 Tai-hwa Liang, Sentelic Corporation. | |
6 | + * | |
7 | + * This program is free software; you can redistribute it and/or | |
8 | + * modify it under the terms of the GNU General Public License | |
9 | + * as published by the Free Software Foundation; either version 2 | |
10 | + * of the License, or (at your option) any later version. | |
11 | + * | |
12 | + * This program is distributed in the hope that it will be useful, | |
13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + * GNU General Public License for more details. | |
16 | + * | |
17 | + * You should have received a copy of the GNU General Public License | |
18 | + * along with this program; if not, write to the Free Software | |
19 | + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
20 | + */ | |
21 | + | |
22 | +#include <linux/module.h> | |
23 | +#include <linux/version.h> | |
24 | +#include <linux/input.h> | |
25 | +#include <linux/ctype.h> | |
26 | +#include <linux/libps2.h> | |
27 | +#include <linux/serio.h> | |
28 | +#include <linux/jiffies.h> | |
29 | + | |
30 | +#include "psmouse.h" | |
31 | +#include "sentelic.h" | |
32 | + | |
33 | +/* | |
34 | + * Timeout for FSP PS/2 command only (in milliseconds). | |
35 | + */ | |
36 | +#define FSP_CMD_TIMEOUT 200 | |
37 | +#define FSP_CMD_TIMEOUT2 30 | |
38 | + | |
39 | +/** Driver version. */ | |
40 | +static const char fsp_drv_ver[] = "1.0.0-K"; | |
41 | + | |
42 | +/* | |
43 | + * Make sure that the value being sent to FSP will not conflict with | |
44 | + * possible sample rate values. | |
45 | + */ | |
46 | +static unsigned char fsp_test_swap_cmd(unsigned char reg_val) | |
47 | +{ | |
48 | + switch (reg_val) { | |
49 | + case 10: case 20: case 40: case 60: case 80: case 100: case 200: | |
50 | + /* | |
51 | + * The requested value being sent to FSP matched to possible | |
52 | + * sample rates, swap the given value such that the hardware | |
53 | + * wouldn't get confused. | |
54 | + */ | |
55 | + return (reg_val >> 4) | (reg_val << 4); | |
56 | + default: | |
57 | + return reg_val; /* swap isn't necessary */ | |
58 | + } | |
59 | +} | |
60 | + | |
61 | +/* | |
62 | + * Make sure that the value being sent to FSP will not conflict with certain | |
63 | + * commands. | |
64 | + */ | |
65 | +static unsigned char fsp_test_invert_cmd(unsigned char reg_val) | |
66 | +{ | |
67 | + switch (reg_val) { | |
68 | + case 0xe9: case 0xee: case 0xf2: case 0xff: | |
69 | + /* | |
70 | + * The requested value being sent to FSP matched to certain | |
71 | + * commands, inverse the given value such that the hardware | |
72 | + * wouldn't get confused. | |
73 | + */ | |
74 | + return ~reg_val; | |
75 | + default: | |
76 | + return reg_val; /* inversion isn't necessary */ | |
77 | + } | |
78 | +} | |
79 | + | |
80 | +static int fsp_reg_read(struct psmouse *psmouse, int reg_addr, int *reg_val) | |
81 | +{ | |
82 | + struct ps2dev *ps2dev = &psmouse->ps2dev; | |
83 | + unsigned char param[3]; | |
84 | + unsigned char addr; | |
85 | + int rc = -1; | |
86 | + | |
87 | + /* | |
88 | + * We need to shut off the device and switch it into command | |
89 | + * mode so we don't confuse our protocol handler. We don't need | |
90 | + * to do that for writes because sysfs set helper does this for | |
91 | + * us. | |
92 | + */ | |
93 | + ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE); | |
94 | + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); | |
95 | + mutex_lock(&ps2dev->cmd_mutex); | |
96 | + | |
97 | + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) | |
98 | + goto out; | |
99 | + | |
100 | + /* should return 0xfe(request for resending) */ | |
101 | + ps2_sendbyte(ps2dev, 0x66, FSP_CMD_TIMEOUT2); | |
102 | + /* should return 0xfc(failed) */ | |
103 | + ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2); | |
104 | + | |
105 | + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) | |
106 | + goto out; | |
107 | + | |
108 | + if ((addr = fsp_test_invert_cmd(reg_addr)) != reg_addr) { | |
109 | + ps2_sendbyte(ps2dev, 0x68, FSP_CMD_TIMEOUT2); | |
110 | + } else if ((addr = fsp_test_swap_cmd(reg_addr)) != reg_addr) { | |
111 | + /* swapping is required */ | |
112 | + ps2_sendbyte(ps2dev, 0xcc, FSP_CMD_TIMEOUT2); | |
113 | + /* expect 0xfe */ | |
114 | + } else { | |
115 | + /* swapping isn't necessary */ | |
116 | + ps2_sendbyte(ps2dev, 0x66, FSP_CMD_TIMEOUT2); | |
117 | + /* expect 0xfe */ | |
118 | + } | |
119 | + /* should return 0xfc(failed) */ | |
120 | + ps2_sendbyte(ps2dev, addr, FSP_CMD_TIMEOUT); | |
121 | + | |
122 | + if (__ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO) < 0) | |
123 | + goto out; | |
124 | + | |
125 | + *reg_val = param[2]; | |
126 | + rc = 0; | |
127 | + | |
128 | + out: | |
129 | + mutex_unlock(&ps2dev->cmd_mutex); | |
130 | + ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE); | |
131 | + psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); | |
132 | + dev_dbg(&ps2dev->serio->dev, "READ REG: 0x%02x is 0x%02x (rc = %d)\n", | |
133 | + reg_addr, *reg_val, rc); | |
134 | + return rc; | |
135 | +} | |
136 | + | |
137 | +static int fsp_reg_write(struct psmouse *psmouse, int reg_addr, int reg_val) | |
138 | +{ | |
139 | + struct ps2dev *ps2dev = &psmouse->ps2dev; | |
140 | + unsigned char v; | |
141 | + int rc = -1; | |
142 | + | |
143 | + mutex_lock(&ps2dev->cmd_mutex); | |
144 | + | |
145 | + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) | |
146 | + goto out; | |
147 | + | |
148 | + if ((v = fsp_test_invert_cmd(reg_addr)) != reg_addr) { | |
149 | + /* inversion is required */ | |
150 | + ps2_sendbyte(ps2dev, 0x74, FSP_CMD_TIMEOUT2); | |
151 | + } else { | |
152 | + if ((v = fsp_test_swap_cmd(reg_addr)) != reg_addr) { | |
153 | + /* swapping is required */ | |
154 | + ps2_sendbyte(ps2dev, 0x77, FSP_CMD_TIMEOUT2); | |
155 | + } else { | |
156 | + /* swapping isn't necessary */ | |
157 | + ps2_sendbyte(ps2dev, 0x55, FSP_CMD_TIMEOUT2); | |
158 | + } | |
159 | + } | |
160 | + /* write the register address in correct order */ | |
161 | + ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2); | |
162 | + | |
163 | + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) | |
164 | + return -1; | |
165 | + | |
166 | + if ((v = fsp_test_invert_cmd(reg_val)) != reg_val) { | |
167 | + /* inversion is required */ | |
168 | + ps2_sendbyte(ps2dev, 0x47, FSP_CMD_TIMEOUT2); | |
169 | + } else if ((v = fsp_test_swap_cmd(reg_val)) != reg_val) { | |
170 | + /* swapping is required */ | |
171 | + ps2_sendbyte(ps2dev, 0x44, FSP_CMD_TIMEOUT2); | |
172 | + } else { | |
173 | + /* swapping isn't necessary */ | |
174 | + ps2_sendbyte(ps2dev, 0x33, FSP_CMD_TIMEOUT2); | |
175 | + } | |
176 | + | |
177 | + /* write the register value in correct order */ | |
178 | + ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2); | |
179 | + rc = 0; | |
180 | + | |
181 | + out: | |
182 | + mutex_unlock(&ps2dev->cmd_mutex); | |
183 | + dev_dbg(&ps2dev->serio->dev, "WRITE REG: 0x%02x to 0x%02x (rc = %d)\n", | |
184 | + reg_addr, reg_val, rc); | |
185 | + return rc; | |
186 | +} | |
187 | + | |
188 | +/* Enable register clock gating for writing certain registers */ | |
189 | +static int fsp_reg_write_enable(struct psmouse *psmouse, bool enable) | |
190 | +{ | |
191 | + int v, nv; | |
192 | + | |
193 | + if (fsp_reg_read(psmouse, FSP_REG_SYSCTL1, &v) == -1) | |
194 | + return -1; | |
195 | + | |
196 | + if (enable) | |
197 | + nv = v | FSP_BIT_EN_REG_CLK; | |
198 | + else | |
199 | + nv = v & ~FSP_BIT_EN_REG_CLK; | |
200 | + | |
201 | + /* only write if necessary */ | |
202 | + if (nv != v) | |
203 | + if (fsp_reg_write(psmouse, FSP_REG_SYSCTL1, nv) == -1) | |
204 | + return -1; | |
205 | + | |
206 | + return 0; | |
207 | +} | |
208 | + | |
209 | +static int fsp_page_reg_read(struct psmouse *psmouse, int *reg_val) | |
210 | +{ | |
211 | + struct ps2dev *ps2dev = &psmouse->ps2dev; | |
212 | + unsigned char param[3]; | |
213 | + int rc = -1; | |
214 | + | |
215 | + ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE); | |
216 | + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); | |
217 | + mutex_lock(&ps2dev->cmd_mutex); | |
218 | + | |
219 | + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) | |
220 | + goto out; | |
221 | + | |
222 | + ps2_sendbyte(ps2dev, 0x66, FSP_CMD_TIMEOUT2); | |
223 | + ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2); | |
224 | + | |
225 | + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) | |
226 | + goto out; | |
227 | + | |
228 | + ps2_sendbyte(ps2dev, 0x83, FSP_CMD_TIMEOUT2); | |
229 | + ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2); | |
230 | + | |
231 | + /* get the returned result */ | |
232 | + if (__ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) | |
233 | + goto out; | |
234 | + | |
235 | + *reg_val = param[2]; | |
236 | + rc = 0; | |
237 | + | |
238 | + out: | |
239 | + mutex_unlock(&ps2dev->cmd_mutex); | |
240 | + ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE); | |
241 | + psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); | |
242 | + dev_dbg(&ps2dev->serio->dev, "READ PAGE REG: 0x%02x (rc = %d)\n", | |
243 | + *reg_val, rc); | |
244 | + return rc; | |
245 | +} | |
246 | + | |
247 | +static int fsp_page_reg_write(struct psmouse *psmouse, int reg_val) | |
248 | +{ | |
249 | + struct ps2dev *ps2dev = &psmouse->ps2dev; | |
250 | + unsigned char v; | |
251 | + int rc = -1; | |
252 | + | |
253 | + mutex_lock(&ps2dev->cmd_mutex); | |
254 | + | |
255 | + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) | |
256 | + goto out; | |
257 | + | |
258 | + ps2_sendbyte(ps2dev, 0x38, FSP_CMD_TIMEOUT2); | |
259 | + ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2); | |
260 | + | |
261 | + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) | |
262 | + return -1; | |
263 | + | |
264 | + if ((v = fsp_test_invert_cmd(reg_val)) != reg_val) { | |
265 | + ps2_sendbyte(ps2dev, 0x47, FSP_CMD_TIMEOUT2); | |
266 | + } else if ((v = fsp_test_swap_cmd(reg_val)) != reg_val) { | |
267 | + /* swapping is required */ | |
268 | + ps2_sendbyte(ps2dev, 0x44, FSP_CMD_TIMEOUT2); | |
269 | + } else { | |
270 | + /* swapping isn't necessary */ | |
271 | + ps2_sendbyte(ps2dev, 0x33, FSP_CMD_TIMEOUT2); | |
272 | + } | |
273 | + | |
274 | + ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2); | |
275 | + rc = 0; | |
276 | + | |
277 | + out: | |
278 | + mutex_unlock(&ps2dev->cmd_mutex); | |
279 | + dev_dbg(&ps2dev->serio->dev, "WRITE PAGE REG: to 0x%02x (rc = %d)\n", | |
280 | + reg_val, rc); | |
281 | + return rc; | |
282 | +} | |
283 | + | |
284 | +static int fsp_get_version(struct psmouse *psmouse, int *version) | |
285 | +{ | |
286 | + if (fsp_reg_read(psmouse, FSP_REG_VERSION, version)) | |
287 | + return -EIO; | |
288 | + | |
289 | + return 0; | |
290 | +} | |
291 | + | |
292 | +static int fsp_get_revision(struct psmouse *psmouse, int *rev) | |
293 | +{ | |
294 | + if (fsp_reg_read(psmouse, FSP_REG_REVISION, rev)) | |
295 | + return -EIO; | |
296 | + | |
297 | + return 0; | |
298 | +} | |
299 | + | |
300 | +static int fsp_get_buttons(struct psmouse *psmouse, int *btn) | |
301 | +{ | |
302 | + static const int buttons[] = { | |
303 | + 0x16, /* Left/Middle/Right/Forward/Backward & Scroll Up/Down */ | |
304 | + 0x06, /* Left/Middle/Right & Scroll Up/Down/Right/Left */ | |
305 | + 0x04, /* Left/Middle/Right & Scroll Up/Down */ | |
306 | + 0x02, /* Left/Middle/Right */ | |
307 | + }; | |
308 | + int val; | |
309 | + | |
310 | + if (fsp_reg_read(psmouse, FSP_REG_TMOD_STATUS1, &val) == -1) | |
311 | + return -EIO; | |
312 | + | |
313 | + *btn = buttons[(val & 0x30) >> 4]; | |
314 | + return 0; | |
315 | +} | |
316 | + | |
317 | +/* Enable on-pad command tag output */ | |
318 | +static int fsp_opc_tag_enable(struct psmouse *psmouse, bool enable) | |
319 | +{ | |
320 | + int v, nv; | |
321 | + int res = 0; | |
322 | + | |
323 | + if (fsp_reg_read(psmouse, FSP_REG_OPC_QDOWN, &v) == -1) { | |
324 | + dev_err(&psmouse->ps2dev.serio->dev, "Unable get OPC state.\n"); | |
325 | + return -EIO; | |
326 | + } | |
327 | + | |
328 | + if (enable) | |
329 | + nv = v | FSP_BIT_EN_OPC_TAG; | |
330 | + else | |
331 | + nv = v & ~FSP_BIT_EN_OPC_TAG; | |
332 | + | |
333 | + /* only write if necessary */ | |
334 | + if (nv != v) { | |
335 | + fsp_reg_write_enable(psmouse, true); | |
336 | + res = fsp_reg_write(psmouse, FSP_REG_OPC_QDOWN, nv); | |
337 | + fsp_reg_write_enable(psmouse, false); | |
338 | + } | |
339 | + | |
340 | + if (res != 0) { | |
341 | + dev_err(&psmouse->ps2dev.serio->dev, | |
342 | + "Unable to enable OPC tag.\n"); | |
343 | + res = -EIO; | |
344 | + } | |
345 | + | |
346 | + return res; | |
347 | +} | |
348 | + | |
349 | +static int fsp_onpad_vscr(struct psmouse *psmouse, bool enable) | |
350 | +{ | |
351 | + struct fsp_data *pad = psmouse->private; | |
352 | + int val; | |
353 | + | |
354 | + if (fsp_reg_read(psmouse, FSP_REG_ONPAD_CTL, &val)) | |
355 | + return -EIO; | |
356 | + | |
357 | + pad->vscroll = enable; | |
358 | + | |
359 | + if (enable) | |
360 | + val |= (FSP_BIT_FIX_VSCR | FSP_BIT_ONPAD_ENABLE); | |
361 | + else | |
362 | + val &= ~FSP_BIT_FIX_VSCR; | |
363 | + | |
364 | + if (fsp_reg_write(psmouse, FSP_REG_ONPAD_CTL, val)) | |
365 | + return -EIO; | |
366 | + | |
367 | + return 0; | |
368 | +} | |
369 | + | |
370 | +static int fsp_onpad_hscr(struct psmouse *psmouse, bool enable) | |
371 | +{ | |
372 | + struct fsp_data *pad = psmouse->private; | |
373 | + int val, v2; | |
374 | + | |
375 | + if (fsp_reg_read(psmouse, FSP_REG_ONPAD_CTL, &val)) | |
376 | + return -EIO; | |
377 | + | |
378 | + if (fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &v2)) | |
379 | + return -EIO; | |
380 | + | |
381 | + pad->hscroll = enable; | |
382 | + | |
383 | + if (enable) { | |
384 | + val |= (FSP_BIT_FIX_HSCR | FSP_BIT_ONPAD_ENABLE); | |
385 | + v2 |= FSP_BIT_EN_MSID6; | |
386 | + } else { | |
387 | + val &= ~FSP_BIT_FIX_HSCR; | |
388 | + v2 &= ~(FSP_BIT_EN_MSID6 | FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8); | |
389 | + } | |
390 | + | |
391 | + if (fsp_reg_write(psmouse, FSP_REG_ONPAD_CTL, val)) | |
392 | + return -EIO; | |
393 | + | |
394 | + /* reconfigure horizontal scrolling packet output */ | |
395 | + if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, v2)) | |
396 | + return -EIO; | |
397 | + | |
398 | + return 0; | |
399 | +} | |
400 | + | |
401 | +/* | |
402 | + * Write device specific initial parameters. | |
403 | + * | |
404 | + * ex: 0xab 0xcd - write oxcd into register 0xab | |
405 | + */ | |
406 | +static ssize_t fsp_attr_set_setreg(struct psmouse *psmouse, void *data, | |
407 | + const char *buf, size_t count) | |
408 | +{ | |
409 | + unsigned long reg, val; | |
410 | + char *rest; | |
411 | + ssize_t retval; | |
412 | + | |
413 | + reg = simple_strtoul(buf, &rest, 16); | |
414 | + if (rest == buf || *rest != ' ' || reg > 0xff) | |
415 | + return -EINVAL; | |
416 | + | |
417 | + if (strict_strtoul(rest + 1, 16, &val) || val > 0xff) | |
418 | + return -EINVAL; | |
419 | + | |
420 | + if (fsp_reg_write_enable(psmouse, true)) | |
421 | + return -EIO; | |
422 | + | |
423 | + retval = fsp_reg_write(psmouse, reg, val) < 0 ? -EIO : count; | |
424 | + | |
425 | + fsp_reg_write_enable(psmouse, false); | |
426 | + | |
427 | + return count; | |
428 | +} | |
429 | + | |
430 | +PSMOUSE_DEFINE_WO_ATTR(setreg, S_IWUSR, NULL, fsp_attr_set_setreg); | |
431 | + | |
432 | +static ssize_t fsp_attr_show_getreg(struct psmouse *psmouse, | |
433 | + void *data, char *buf) | |
434 | +{ | |
435 | + struct fsp_data *pad = psmouse->private; | |
436 | + | |
437 | + return sprintf(buf, "%02x%02x\n", pad->last_reg, pad->last_val); | |
438 | +} | |
439 | + | |
440 | +/* | |
441 | + * Read a register from device. | |
442 | + * | |
443 | + * ex: 0xab -- read content from register 0xab | |
444 | + */ | |
445 | +static ssize_t fsp_attr_set_getreg(struct psmouse *psmouse, void *data, | |
446 | + const char *buf, size_t count) | |
447 | +{ | |
448 | + struct fsp_data *pad = psmouse->private; | |
449 | + unsigned long reg; | |
450 | + int val; | |
451 | + | |
452 | + if (strict_strtoul(buf, 16, ®) || reg > 0xff) | |
453 | + return -EINVAL; | |
454 | + | |
455 | + if (fsp_reg_read(psmouse, reg, &val)) | |
456 | + return -EIO; | |
457 | + | |
458 | + pad->last_reg = reg; | |
459 | + pad->last_val = val; | |
460 | + | |
461 | + return count; | |
462 | +} | |
463 | + | |
464 | +PSMOUSE_DEFINE_ATTR(getreg, S_IWUSR | S_IRUGO, NULL, | |
465 | + fsp_attr_show_getreg, fsp_attr_set_getreg); | |
466 | + | |
467 | +static ssize_t fsp_attr_show_pagereg(struct psmouse *psmouse, | |
468 | + void *data, char *buf) | |
469 | +{ | |
470 | + int val = 0; | |
471 | + | |
472 | + if (fsp_page_reg_read(psmouse, &val)) | |
473 | + return -EIO; | |
474 | + | |
475 | + return sprintf(buf, "%02x\n", val); | |
476 | +} | |
477 | + | |
478 | +static ssize_t fsp_attr_set_pagereg(struct psmouse *psmouse, void *data, | |
479 | + const char *buf, size_t count) | |
480 | +{ | |
481 | + unsigned long val; | |
482 | + | |
483 | + if (strict_strtoul(buf, 16, &val) || val > 0xff) | |
484 | + return -EINVAL; | |
485 | + | |
486 | + if (fsp_page_reg_write(psmouse, val)) | |
487 | + return -EIO; | |
488 | + | |
489 | + return count; | |
490 | +} | |
491 | + | |
492 | +PSMOUSE_DEFINE_ATTR(page, S_IWUSR | S_IRUGO, NULL, | |
493 | + fsp_attr_show_pagereg, fsp_attr_set_pagereg); | |
494 | + | |
495 | +static ssize_t fsp_attr_show_vscroll(struct psmouse *psmouse, | |
496 | + void *data, char *buf) | |
497 | +{ | |
498 | + struct fsp_data *pad = psmouse->private; | |
499 | + | |
500 | + return sprintf(buf, "%d\n", pad->vscroll); | |
501 | +} | |
502 | + | |
503 | +static ssize_t fsp_attr_set_vscroll(struct psmouse *psmouse, void *data, | |
504 | + const char *buf, size_t count) | |
505 | +{ | |
506 | + unsigned long val; | |
507 | + | |
508 | + if (strict_strtoul(buf, 10, &val) || val > 1) | |
509 | + return -EINVAL; | |
510 | + | |
511 | + fsp_onpad_vscr(psmouse, val); | |
512 | + | |
513 | + return count; | |
514 | +} | |
515 | + | |
516 | +PSMOUSE_DEFINE_ATTR(vscroll, S_IWUSR | S_IRUGO, NULL, | |
517 | + fsp_attr_show_vscroll, fsp_attr_set_vscroll); | |
518 | + | |
519 | +static ssize_t fsp_attr_show_hscroll(struct psmouse *psmouse, | |
520 | + void *data, char *buf) | |
521 | +{ | |
522 | + struct fsp_data *pad = psmouse->private; | |
523 | + | |
524 | + return sprintf(buf, "%d\n", pad->hscroll); | |
525 | +} | |
526 | + | |
527 | +static ssize_t fsp_attr_set_hscroll(struct psmouse *psmouse, void *data, | |
528 | + const char *buf, size_t count) | |
529 | +{ | |
530 | + unsigned long val; | |
531 | + | |
532 | + if (strict_strtoul(buf, 10, &val) || val > 1) | |
533 | + return -EINVAL; | |
534 | + | |
535 | + fsp_onpad_hscr(psmouse, val); | |
536 | + | |
537 | + return count; | |
538 | +} | |
539 | + | |
540 | +PSMOUSE_DEFINE_ATTR(hscroll, S_IWUSR | S_IRUGO, NULL, | |
541 | + fsp_attr_show_hscroll, fsp_attr_set_hscroll); | |
542 | + | |
543 | +static ssize_t fsp_attr_show_flags(struct psmouse *psmouse, | |
544 | + void *data, char *buf) | |
545 | +{ | |
546 | + struct fsp_data *pad = psmouse->private; | |
547 | + | |
548 | + return sprintf(buf, "%c\n", | |
549 | + pad->flags & FSPDRV_FLAG_EN_OPC ? 'C' : 'c'); | |
550 | +} | |
551 | + | |
552 | +static ssize_t fsp_attr_set_flags(struct psmouse *psmouse, void *data, | |
553 | + const char *buf, size_t count) | |
554 | +{ | |
555 | + struct fsp_data *pad = psmouse->private; | |
556 | + size_t i; | |
557 | + | |
558 | + for (i = 0; i < count; i++) { | |
559 | + switch (buf[i]) { | |
560 | + case 'C': | |
561 | + pad->flags |= FSPDRV_FLAG_EN_OPC; | |
562 | + break; | |
563 | + case 'c': | |
564 | + pad->flags &= ~FSPDRV_FLAG_EN_OPC; | |
565 | + break; | |
566 | + default: | |
567 | + return -EINVAL; | |
568 | + } | |
569 | + } | |
570 | + return count; | |
571 | +} | |
572 | + | |
573 | +PSMOUSE_DEFINE_ATTR(flags, S_IWUSR | S_IRUGO, NULL, | |
574 | + fsp_attr_show_flags, fsp_attr_set_flags); | |
575 | + | |
576 | +static ssize_t fsp_attr_show_ver(struct psmouse *psmouse, | |
577 | + void *data, char *buf) | |
578 | +{ | |
579 | + return sprintf(buf, "Sentelic FSP kernel module %s\n", fsp_drv_ver); | |
580 | +} | |
581 | + | |
582 | +PSMOUSE_DEFINE_RO_ATTR(ver, S_IRUGO, NULL, fsp_attr_show_ver); | |
583 | + | |
584 | +static struct attribute *fsp_attributes[] = { | |
585 | + &psmouse_attr_setreg.dattr.attr, | |
586 | + &psmouse_attr_getreg.dattr.attr, | |
587 | + &psmouse_attr_page.dattr.attr, | |
588 | + &psmouse_attr_vscroll.dattr.attr, | |
589 | + &psmouse_attr_hscroll.dattr.attr, | |
590 | + &psmouse_attr_flags.dattr.attr, | |
591 | + &psmouse_attr_ver.dattr.attr, | |
592 | + NULL | |
593 | +}; | |
594 | + | |
595 | +static struct attribute_group fsp_attribute_group = { | |
596 | + .attrs = fsp_attributes, | |
597 | +}; | |
598 | + | |
599 | +#ifdef FSP_DEBUG | |
600 | +static void fsp_packet_debug(unsigned char packet[]) | |
601 | +{ | |
602 | + static unsigned int ps2_packet_cnt; | |
603 | + static unsigned int ps2_last_second; | |
604 | + unsigned int jiffies_msec; | |
605 | + | |
606 | + ps2_packet_cnt++; | |
607 | + jiffies_msec = jiffies_to_msecs(jiffies); | |
608 | + printk(KERN_DEBUG "%08dms PS/2 packets: %02x, %02x, %02x, %02x\n", | |
609 | + jiffies_msec, packet[0], packet[1], packet[2], packet[3]); | |
610 | + | |
611 | + if (jiffies_msec - ps2_last_second > 1000) { | |
612 | + printk(KERN_DEBUG "PS/2 packets/sec = %d\n", ps2_packet_cnt); | |
613 | + ps2_packet_cnt = 0; | |
614 | + ps2_last_second = jiffies_msec; | |
615 | + } | |
616 | +} | |
617 | +#else | |
618 | +static void fsp_packet_debug(unsigned char packet[]) | |
619 | +{ | |
620 | +} | |
621 | +#endif | |
622 | + | |
623 | +static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse) | |
624 | +{ | |
625 | + struct input_dev *dev = psmouse->dev; | |
626 | + struct fsp_data *ad = psmouse->private; | |
627 | + unsigned char *packet = psmouse->packet; | |
628 | + unsigned char button_status = 0, lscroll = 0, rscroll = 0; | |
629 | + int rel_x, rel_y; | |
630 | + | |
631 | + if (psmouse->pktcnt < 4) | |
632 | + return PSMOUSE_GOOD_DATA; | |
633 | + | |
634 | + /* | |
635 | + * Full packet accumulated, process it | |
636 | + */ | |
637 | + | |
638 | + switch (psmouse->packet[0] >> FSP_PKT_TYPE_SHIFT) { | |
639 | + case FSP_PKT_TYPE_ABS: | |
640 | + dev_warn(&psmouse->ps2dev.serio->dev, | |
641 | + "Unexpected absolute mode packet, ignored.\n"); | |
642 | + break; | |
643 | + | |
644 | + case FSP_PKT_TYPE_NORMAL_OPC: | |
645 | + /* on-pad click, filter it if necessary */ | |
646 | + if ((ad->flags & FSPDRV_FLAG_EN_OPC) != FSPDRV_FLAG_EN_OPC) | |
647 | + packet[0] &= ~BIT(0); | |
648 | + /* fall through */ | |
649 | + | |
650 | + case FSP_PKT_TYPE_NORMAL: | |
651 | + /* normal packet */ | |
652 | + /* special packet data translation from on-pad packets */ | |
653 | + if (packet[3] != 0) { | |
654 | + if (packet[3] & BIT(0)) | |
655 | + button_status |= 0x01; /* wheel down */ | |
656 | + if (packet[3] & BIT(1)) | |
657 | + button_status |= 0x0f; /* wheel up */ | |
658 | + if (packet[3] & BIT(2)) | |
659 | + button_status |= BIT(5);/* horizontal left */ | |
660 | + if (packet[3] & BIT(3)) | |
661 | + button_status |= BIT(4);/* horizontal right */ | |
662 | + /* push back to packet queue */ | |
663 | + if (button_status != 0) | |
664 | + packet[3] = button_status; | |
665 | + rscroll = (packet[3] >> 4) & 1; | |
666 | + lscroll = (packet[3] >> 5) & 1; | |
667 | + } | |
668 | + /* | |
669 | + * Processing wheel up/down and extra button events | |
670 | + */ | |
671 | + input_report_rel(dev, REL_WHEEL, | |
672 | + (int)(packet[3] & 8) - (int)(packet[3] & 7)); | |
673 | + input_report_rel(dev, REL_HWHEEL, lscroll - rscroll); | |
674 | + input_report_key(dev, BTN_BACK, lscroll); | |
675 | + input_report_key(dev, BTN_FORWARD, rscroll); | |
676 | + | |
677 | + /* | |
678 | + * Standard PS/2 Mouse | |
679 | + */ | |
680 | + input_report_key(dev, BTN_LEFT, packet[0] & 1); | |
681 | + input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1); | |
682 | + input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1); | |
683 | + | |
684 | + rel_x = packet[1] ? (int)packet[1] - (int)((packet[0] << 4) & 0x100) : 0; | |
685 | + rel_y = packet[2] ? (int)((packet[0] << 3) & 0x100) - (int)packet[2] : 0; | |
686 | + | |
687 | + input_report_rel(dev, REL_X, rel_x); | |
688 | + input_report_rel(dev, REL_Y, rel_y); | |
689 | + break; | |
690 | + } | |
691 | + | |
692 | + input_sync(dev); | |
693 | + | |
694 | + fsp_packet_debug(packet); | |
695 | + | |
696 | + return PSMOUSE_FULL_PACKET; | |
697 | +} | |
698 | + | |
699 | +static int fsp_activate_protocol(struct psmouse *psmouse) | |
700 | +{ | |
701 | + struct fsp_data *pad = psmouse->private; | |
702 | + struct ps2dev *ps2dev = &psmouse->ps2dev; | |
703 | + unsigned char param[2]; | |
704 | + int val; | |
705 | + | |
706 | + /* | |
707 | + * Standard procedure to enter FSP Intellimouse mode | |
708 | + * (scrolling wheel, 4th and 5th buttons) | |
709 | + */ | |
710 | + param[0] = 200; | |
711 | + ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); | |
712 | + param[0] = 200; | |
713 | + ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); | |
714 | + param[0] = 80; | |
715 | + ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); | |
716 | + | |
717 | + ps2_command(ps2dev, param, PSMOUSE_CMD_GETID); | |
718 | + if (param[0] != 0x04) { | |
719 | + dev_err(&psmouse->ps2dev.serio->dev, | |
720 | + "Unable to enable 4 bytes packet format.\n"); | |
721 | + return -EIO; | |
722 | + } | |
723 | + | |
724 | + if (fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &val)) { | |
725 | + dev_err(&psmouse->ps2dev.serio->dev, | |
726 | + "Unable to read SYSCTL5 register.\n"); | |
727 | + return -EIO; | |
728 | + } | |
729 | + | |
730 | + val &= ~(FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8 | FSP_BIT_EN_AUTO_MSID8); | |
731 | + /* Ensure we are not in absolute mode */ | |
732 | + val &= ~FSP_BIT_EN_PKT_G0; | |
733 | + if (pad->buttons == 0x06) { | |
734 | + /* Left/Middle/Right & Scroll Up/Down/Right/Left */ | |
735 | + val |= FSP_BIT_EN_MSID6; | |
736 | + } | |
737 | + | |
738 | + if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, val)) { | |
739 | + dev_err(&psmouse->ps2dev.serio->dev, | |
740 | + "Unable to set up required mode bits.\n"); | |
741 | + return -EIO; | |
742 | + } | |
743 | + | |
744 | + /* | |
745 | + * Enable OPC tags such that driver can tell the difference between | |
746 | + * on-pad and real button click | |
747 | + */ | |
748 | + if (fsp_opc_tag_enable(psmouse, true)) | |
749 | + dev_warn(&psmouse->ps2dev.serio->dev, | |
750 | + "Failed to enable OPC tag mode.\n"); | |
751 | + | |
752 | + /* Enable on-pad vertical and horizontal scrolling */ | |
753 | + fsp_onpad_vscr(psmouse, true); | |
754 | + fsp_onpad_hscr(psmouse, true); | |
755 | + | |
756 | + return 0; | |
757 | +} | |
758 | + | |
759 | +int fsp_detect(struct psmouse *psmouse, int set_properties) | |
760 | +{ | |
761 | + int id; | |
762 | + | |
763 | + if (fsp_reg_read(psmouse, FSP_REG_DEVICE_ID, &id)) | |
764 | + return -EIO; | |
765 | + | |
766 | + if (id != 0x01) | |
767 | + return -ENODEV; | |
768 | + | |
769 | + if (set_properties) { | |
770 | + psmouse->vendor = "Sentelic"; | |
771 | + psmouse->name = "FingerSensingPad"; | |
772 | + } | |
773 | + | |
774 | + return 0; | |
775 | +} | |
776 | + | |
777 | +static void fsp_reset(struct psmouse *psmouse) | |
778 | +{ | |
779 | + fsp_opc_tag_enable(psmouse, false); | |
780 | + fsp_onpad_vscr(psmouse, false); | |
781 | + fsp_onpad_hscr(psmouse, false); | |
782 | +} | |
783 | + | |
784 | +static void fsp_disconnect(struct psmouse *psmouse) | |
785 | +{ | |
786 | + sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, | |
787 | + &fsp_attribute_group); | |
788 | + | |
789 | + fsp_reset(psmouse); | |
790 | + kfree(psmouse->private); | |
791 | +} | |
792 | + | |
793 | +static int fsp_reconnect(struct psmouse *psmouse) | |
794 | +{ | |
795 | + int version; | |
796 | + | |
797 | + if (fsp_detect(psmouse, 0)) | |
798 | + return -ENODEV; | |
799 | + | |
800 | + if (fsp_get_version(psmouse, &version)) | |
801 | + return -ENODEV; | |
802 | + | |
803 | + if (fsp_activate_protocol(psmouse)) | |
804 | + return -EIO; | |
805 | + | |
806 | + return 0; | |
807 | +} | |
808 | + | |
809 | +int fsp_init(struct psmouse *psmouse) | |
810 | +{ | |
811 | + struct fsp_data *priv; | |
812 | + int ver, rev, buttons; | |
813 | + int error; | |
814 | + | |
815 | + if (fsp_get_version(psmouse, &ver) || | |
816 | + fsp_get_revision(psmouse, &rev) || | |
817 | + fsp_get_buttons(psmouse, &buttons)) { | |
818 | + return -ENODEV; | |
819 | + } | |
820 | + | |
821 | + printk(KERN_INFO | |
822 | + "Finger Sensing Pad, hw: %d.%d.%d, sw: %s, buttons: %d\n", | |
823 | + ver >> 4, ver & 0x0F, rev, fsp_drv_ver, buttons & 7); | |
824 | + | |
825 | + psmouse->private = priv = kzalloc(sizeof(struct fsp_data), GFP_KERNEL); | |
826 | + if (!priv) | |
827 | + return -ENOMEM; | |
828 | + | |
829 | + priv->ver = ver; | |
830 | + priv->rev = rev; | |
831 | + priv->buttons = buttons; | |
832 | + | |
833 | + /* enable on-pad click by default */ | |
834 | + priv->flags |= FSPDRV_FLAG_EN_OPC; | |
835 | + | |
836 | + /* Set up various supported input event bits */ | |
837 | + __set_bit(BTN_BACK, psmouse->dev->keybit); | |
838 | + __set_bit(BTN_FORWARD, psmouse->dev->keybit); | |
839 | + __set_bit(REL_WHEEL, psmouse->dev->relbit); | |
840 | + __set_bit(REL_HWHEEL, psmouse->dev->relbit); | |
841 | + | |
842 | + psmouse->protocol_handler = fsp_process_byte; | |
843 | + psmouse->disconnect = fsp_disconnect; | |
844 | + psmouse->reconnect = fsp_reconnect; | |
845 | + psmouse->cleanup = fsp_reset; | |
846 | + psmouse->pktsize = 4; | |
847 | + | |
848 | + /* set default packet output based on number of buttons we found */ | |
849 | + error = fsp_activate_protocol(psmouse); | |
850 | + if (error) | |
851 | + goto err_out; | |
852 | + | |
853 | + error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj, | |
854 | + &fsp_attribute_group); | |
855 | + if (error) { | |
856 | + dev_err(&psmouse->ps2dev.serio->dev, | |
857 | + "Failed to create sysfs attributes (%d)", error); | |
858 | + goto err_out; | |
859 | + } | |
860 | + | |
861 | + return 0; | |
862 | + | |
863 | + err_out: | |
864 | + kfree(psmouse->private); | |
865 | + psmouse->private = NULL; | |
866 | + return error; | |
867 | +} |
drivers/input/mouse/sentelic.h
1 | +/*- | |
2 | + * Finger Sensing Pad PS/2 mouse driver. | |
3 | + * | |
4 | + * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd. | |
5 | + * Copyright (C) 2005-2009 Tai-hwa Liang, Sentelic Corporation. | |
6 | + * | |
7 | + * This program is free software; you can redistribute it and/or | |
8 | + * modify it under the terms of the GNU General Public License | |
9 | + * as published by the Free Software Foundation; either version 2 | |
10 | + * of the License, or (at your option) any later version. | |
11 | + * | |
12 | + * This program is distributed in the hope that it will be useful, | |
13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + * GNU General Public License for more details. | |
16 | + * | |
17 | + * You should have received a copy of the GNU General Public License | |
18 | + * along with this program; if not, write to the Free Software | |
19 | + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
20 | + */ | |
21 | + | |
22 | +#ifndef __SENTELIC_H | |
23 | +#define __SENTELIC_H | |
24 | + | |
25 | +/* Finger-sensing Pad information registers */ | |
26 | +#define FSP_REG_DEVICE_ID 0x00 | |
27 | +#define FSP_REG_VERSION 0x01 | |
28 | +#define FSP_REG_REVISION 0x04 | |
29 | +#define FSP_REG_TMOD_STATUS1 0x0B | |
30 | +#define FSP_BIT_NO_ROTATION BIT(3) | |
31 | +#define FSP_REG_PAGE_CTRL 0x0F | |
32 | + | |
33 | +/* Finger-sensing Pad control registers */ | |
34 | +#define FSP_REG_SYSCTL1 0x10 | |
35 | +#define FSP_BIT_EN_REG_CLK BIT(5) | |
36 | +#define FSP_REG_OPC_QDOWN 0x31 | |
37 | +#define FSP_BIT_EN_OPC_TAG BIT(7) | |
38 | +#define FSP_REG_OPTZ_XLO 0x34 | |
39 | +#define FSP_REG_OPTZ_XHI 0x35 | |
40 | +#define FSP_REG_OPTZ_YLO 0x36 | |
41 | +#define FSP_REG_OPTZ_YHI 0x37 | |
42 | +#define FSP_REG_SYSCTL5 0x40 | |
43 | +#define FSP_BIT_90_DEGREE BIT(0) | |
44 | +#define FSP_BIT_EN_MSID6 BIT(1) | |
45 | +#define FSP_BIT_EN_MSID7 BIT(2) | |
46 | +#define FSP_BIT_EN_MSID8 BIT(3) | |
47 | +#define FSP_BIT_EN_AUTO_MSID8 BIT(5) | |
48 | +#define FSP_BIT_EN_PKT_G0 BIT(6) | |
49 | + | |
50 | +#define FSP_REG_ONPAD_CTL 0x43 | |
51 | +#define FSP_BIT_ONPAD_ENABLE BIT(0) | |
52 | +#define FSP_BIT_ONPAD_FBBB BIT(1) | |
53 | +#define FSP_BIT_FIX_VSCR BIT(3) | |
54 | +#define FSP_BIT_FIX_HSCR BIT(5) | |
55 | +#define FSP_BIT_DRAG_LOCK BIT(6) | |
56 | + | |
57 | +/* Finger-sensing Pad packet formating related definitions */ | |
58 | + | |
59 | +/* absolute packet type */ | |
60 | +#define FSP_PKT_TYPE_NORMAL (0x00) | |
61 | +#define FSP_PKT_TYPE_ABS (0x01) | |
62 | +#define FSP_PKT_TYPE_NOTIFY (0x02) | |
63 | +#define FSP_PKT_TYPE_NORMAL_OPC (0x03) | |
64 | +#define FSP_PKT_TYPE_SHIFT (6) | |
65 | + | |
66 | +#ifdef __KERNEL__ | |
67 | + | |
68 | +struct fsp_data { | |
69 | + unsigned char ver; /* hardware version */ | |
70 | + unsigned char rev; /* hardware revison */ | |
71 | + unsigned char buttons; /* Number of buttons */ | |
72 | + unsigned int flags; | |
73 | +#define FSPDRV_FLAG_EN_OPC (0x001) /* enable on-pad clicking */ | |
74 | + | |
75 | + bool vscroll; /* Vertical scroll zone enabled */ | |
76 | + bool hscroll; /* Horizontal scroll zone enabled */ | |
77 | + | |
78 | + unsigned char last_reg; /* Last register we requested read from */ | |
79 | + unsigned char last_val; | |
80 | +}; | |
81 | + | |
82 | +#ifdef CONFIG_MOUSE_PS2_SENTELIC | |
83 | +extern int fsp_detect(struct psmouse *psmouse, int set_properties); | |
84 | +extern int fsp_init(struct psmouse *psmouse); | |
85 | +#else | |
86 | +inline int fsp_detect(struct psmouse *psmouse, int set_properties) | |
87 | +{ | |
88 | + return -ENOSYS; | |
89 | +} | |
90 | +inline int fsp_init(struct psmouse *psmouse) | |
91 | +{ | |
92 | + return -ENOSYS; | |
93 | +} | |
94 | +#endif | |
95 | + | |
96 | +#endif /* __KERNEL__ */ | |
97 | + | |
98 | +#endif /* !__SENTELIC_H */ |
drivers/input/serio/libps2.c
... | ... | @@ -161,7 +161,7 @@ |
161 | 161 | * ps2_command() can only be called from a process context |
162 | 162 | */ |
163 | 163 | |
164 | -int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) | |
164 | +int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) | |
165 | 165 | { |
166 | 166 | int timeout; |
167 | 167 | int send = (command >> 12) & 0xf; |
... | ... | @@ -179,8 +179,6 @@ |
179 | 179 | return -1; |
180 | 180 | } |
181 | 181 | |
182 | - mutex_lock(&ps2dev->cmd_mutex); | |
183 | - | |
184 | 182 | serio_pause_rx(ps2dev->serio); |
185 | 183 | ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0; |
186 | 184 | ps2dev->cmdcnt = receive; |
187 | 185 | |
... | ... | @@ -231,7 +229,18 @@ |
231 | 229 | ps2dev->flags = 0; |
232 | 230 | serio_continue_rx(ps2dev->serio); |
233 | 231 | |
232 | + return rc; | |
233 | +} | |
234 | +EXPORT_SYMBOL(__ps2_command); | |
235 | + | |
236 | +int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) | |
237 | +{ | |
238 | + int rc; | |
239 | + | |
240 | + mutex_lock(&ps2dev->cmd_mutex); | |
241 | + rc = __ps2_command(ps2dev, param, command); | |
234 | 242 | mutex_unlock(&ps2dev->cmd_mutex); |
243 | + | |
235 | 244 | return rc; |
236 | 245 | } |
237 | 246 | EXPORT_SYMBOL(ps2_command); |
include/linux/libps2.h
... | ... | @@ -44,6 +44,7 @@ |
44 | 44 | void ps2_init(struct ps2dev *ps2dev, struct serio *serio); |
45 | 45 | int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout); |
46 | 46 | void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout); |
47 | +int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command); | |
47 | 48 | int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command); |
48 | 49 | int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data); |
49 | 50 | int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data); |