patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / drivers / input / mouse / logips2pp.c
1 /*
2  * Logitech PS/2++ mouse driver
3  *
4  * Copyright (c) 1999-2003 Vojtech Pavlik <vojtech@suse.cz>
5  * Copyright (c) 2003 Eric Wong <eric@yhbt.net>
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License version 2 as published by
9  * the Free Software Foundation.
10  */
11
12 #include <linux/input.h>
13 #include <linux/serio.h>
14 #include "psmouse.h"
15 #include "logips2pp.h"
16
17 /* Logitech mouse types */
18 #define PS2PP_KIND_WHEEL        1
19 #define PS2PP_KIND_MX           2
20 #define PS2PP_KIND_TP3          3
21
22 /* Logitech mouse features */
23 #define PS2PP_WHEEL             0x01
24 #define PS2PP_HWHEEL            0x02
25 #define PS2PP_SIDE_BTN          0x04
26 #define PS2PP_EXTRA_BTN         0x08
27 #define PS2PP_TASK_BTN          0x10
28 #define PS2PP_NAV_BTN           0x20
29
30 struct ps2pp_info {
31         const int model;
32         unsigned const int kind;
33         unsigned const int features;
34 };
35
36 /*
37  * Process a PS2++ or PS2T++ packet.
38  */
39
40 void ps2pp_process_packet(struct psmouse *psmouse)
41 {
42         struct input_dev *dev = &psmouse->dev;
43         unsigned char *packet = psmouse->packet;
44
45         if ((packet[0] & 0x48) == 0x48 && (packet[1] & 0x02) == 0x02) {
46
47                 switch ((packet[1] >> 4) | (packet[0] & 0x30)) {
48
49                         case 0x0d: /* Mouse extra info */
50
51                                 input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL,
52                                         (int) (packet[2] & 8) - (int) (packet[2] & 7));
53                                 input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1);
54                                 input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1);
55
56                                 break;
57
58                         case 0x0e: /* buttons 4, 5, 6, 7, 8, 9, 10 info */
59
60                                 input_report_key(dev, BTN_SIDE, (packet[2]) & 1);
61                                 input_report_key(dev, BTN_EXTRA, (packet[2] >> 1) & 1);
62                                 input_report_key(dev, BTN_BACK, (packet[2] >> 3) & 1);
63                                 input_report_key(dev, BTN_FORWARD, (packet[2] >> 4) & 1);
64                                 input_report_key(dev, BTN_TASK, (packet[2] >> 2) & 1);
65
66                                 break;
67
68                         case 0x0f: /* TouchPad extra info */
69
70                                 input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL,
71                                         (int) ((packet[2] >> 4) & 8) - (int) ((packet[2] >> 4) & 7));
72                                 packet[0] = packet[2] | 0x08;
73                                 break;
74
75 #ifdef DEBUG
76                         default:
77                                 printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n",
78                                         (packet[1] >> 4) | (packet[0] & 0x30));
79 #endif
80                 }
81
82                 packet[0] &= 0x0f;
83                 packet[1] = 0;
84                 packet[2] = 0;
85         }
86 }
87
88 /*
89  * ps2pp_cmd() sends a PS2++ command, sliced into two bit
90  * pieces through the SETRES command. This is needed to send extended
91  * commands to mice on notebooks that try to understand the PS/2 protocol
92  * Ugly.
93  */
94
95 static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned char command)
96 {
97         if (psmouse_sliced_command(psmouse, command))
98                 return -1;
99
100         if (psmouse_command(psmouse, param, PSMOUSE_CMD_POLL))
101                 return -1;
102
103         return 0;
104 }
105
106 /*
107  * SmartScroll / CruiseControl for some newer Logitech mice Defaults to
108  * enabled if we do nothing to it. Of course I put this in because I want it
109  * disabled :P
110  * 1 - enabled (if previously disabled, also default)
111  * 0/2 - disabled
112  */
113
114 static void ps2pp_set_smartscroll(struct psmouse *psmouse)
115 {
116         unsigned char param[4];
117
118         ps2pp_cmd(psmouse, param, 0x32);
119
120         param[0] = 0;
121         psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
122         psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
123         psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
124
125         if (psmouse_smartscroll < 2) {
126                 /* 0 - disabled, 1 - enabled */
127                 param[0] = psmouse_smartscroll;
128                 psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
129         }
130 }
131
132 /*
133  * Support 800 dpi resolution _only_ if the user wants it (there are good
134  * reasons to not use it even if the mouse supports it, and of course there are
135  * also good reasons to use it, let the user decide).
136  */
137
138 void ps2pp_set_800dpi(struct psmouse *psmouse)
139 {
140         unsigned char param = 3;
141         psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
142         psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
143         psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
144         psmouse_command(psmouse, &param, PSMOUSE_CMD_SETRES);
145 }
146
147 static struct ps2pp_info *get_model_info(unsigned char model)
148 {
149         static struct ps2pp_info ps2pp_list[] = {
150                 { 12,   0,                      PS2PP_SIDE_BTN},
151                 { 13,   0,                      0 },
152                 { 40,   0,                      PS2PP_SIDE_BTN },
153                 { 41,   0,                      PS2PP_SIDE_BTN },
154                 { 42,   0,                      PS2PP_SIDE_BTN },
155                 { 43,   0,                      PS2PP_SIDE_BTN },
156                 { 50,   0,                      0 },
157                 { 51,   0,                      0 },
158                 { 52,   PS2PP_KIND_WHEEL,       PS2PP_SIDE_BTN | PS2PP_WHEEL },
159                 { 53,   PS2PP_KIND_WHEEL,       PS2PP_WHEEL },
160                 { 61,   PS2PP_KIND_MX,
161                                 PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
162                                 PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },      /* MX700 */
163                 { 73,   0,                      PS2PP_SIDE_BTN },
164                 { 75,   PS2PP_KIND_WHEEL,       PS2PP_WHEEL },
165                 { 76,   PS2PP_KIND_WHEEL,       PS2PP_WHEEL },
166                 { 80,   PS2PP_KIND_WHEEL,       PS2PP_SIDE_BTN | PS2PP_WHEEL },
167                 { 81,   PS2PP_KIND_WHEEL,       PS2PP_WHEEL },
168                 { 83,   PS2PP_KIND_WHEEL,       PS2PP_WHEEL },
169                 { 88,   PS2PP_KIND_WHEEL,       PS2PP_WHEEL },
170                 { 96,   0,                      0 },
171                 { 97,   PS2PP_KIND_TP3,         PS2PP_WHEEL | PS2PP_HWHEEL },
172                 { 100,  PS2PP_KIND_MX,
173                                 PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
174                                 PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },      /* MX510 */
175                 { 112,  PS2PP_KIND_MX,
176                                 PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
177                                 PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },      /* MX500 */
178                 { 114,  PS2PP_KIND_MX,
179                                 PS2PP_WHEEL | PS2PP_SIDE_BTN |
180                                 PS2PP_TASK_BTN | PS2PP_EXTRA_BTN },     /* M310 */
181                 { }
182         };
183         int i;
184
185         for (i = 0; ps2pp_list[i].model; i++)
186                 if (model == ps2pp_list[i].model)
187                         return &ps2pp_list[i];
188         return NULL;
189 }
190
191 /*
192  * Set up input device's properties based on the detected mouse model.
193  */
194
195 static void ps2pp_set_model_properties(struct psmouse *psmouse, struct ps2pp_info *model_info)
196 {
197         if (model_info->features & PS2PP_SIDE_BTN)
198                 set_bit(BTN_SIDE, psmouse->dev.keybit);
199
200         if (model_info->features & PS2PP_EXTRA_BTN)
201                 set_bit(BTN_EXTRA, psmouse->dev.keybit);
202
203         if (model_info->features & PS2PP_TASK_BTN)
204                 set_bit(BTN_TASK, psmouse->dev.keybit);
205
206         if (model_info->features & PS2PP_NAV_BTN) {
207                 set_bit(BTN_FORWARD, psmouse->dev.keybit);
208                 set_bit(BTN_BACK, psmouse->dev.keybit);
209         }
210
211         if (model_info->features & PS2PP_WHEEL)
212                 set_bit(REL_WHEEL, psmouse->dev.relbit);
213
214         if (model_info->features & PS2PP_HWHEEL)
215                 set_bit(REL_HWHEEL, psmouse->dev.relbit);
216
217         switch (model_info->kind) {
218                 case PS2PP_KIND_WHEEL:
219                         psmouse->name = "Wheel Mouse";
220                         break;
221
222                 case PS2PP_KIND_MX:
223                         psmouse->name = "MX Mouse";
224                         break;
225
226                 case PS2PP_KIND_TP3:
227                         psmouse->name = "TouchPad 3";
228                         break;
229         }
230 }
231
232
233 /*
234  * Logitech magic init. Detect whether the mouse is a Logitech one
235  * and its exact model and try turning on extended protocol for ones
236  * that support it.
237  */
238
239 int ps2pp_init(struct psmouse *psmouse, int set_properties)
240 {
241         unsigned char param[4];
242         unsigned char protocol = PSMOUSE_PS2;
243         unsigned char model, buttons;
244         struct ps2pp_info *model_info;
245
246         param[0] = 0;
247         psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
248         psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
249         psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
250         psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11);
251         param[1] = 0;
252         psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
253
254         if (param[1] != 0) {
255                 model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
256                 buttons = param[1];
257                 model_info = get_model_info(model);
258
259 /*
260  * Do Logitech PS2++ / PS2T++ magic init.
261  */
262                 if (model == 97) { /* Touch Pad 3 */
263
264                         /* Unprotect RAM */
265                         param[0] = 0x11; param[1] = 0x04; param[2] = 0x68;
266                         psmouse_command(psmouse, param, 0x30d1);
267                         /* Enable features */
268                         param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b;
269                         psmouse_command(psmouse, param, 0x30d1);
270                         /* Enable PS2++ */
271                         param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3;
272                         psmouse_command(psmouse, param, 0x30d1);
273
274                         param[0] = 0;
275                         if (!psmouse_command(psmouse, param, 0x13d1) &&
276                             param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) {
277                                 protocol = PSMOUSE_PS2TPP;
278                         }
279
280                 } else if (get_model_info(model) != NULL) {
281
282                         param[0] = param[1] = param[2] = 0;
283                         ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */
284                         ps2pp_cmd(psmouse, param, 0xDB);
285
286                         if ((param[0] & 0x78) == 0x48 &&
287                             (param[1] & 0xf3) == 0xc2 &&
288                             (param[2] & 0x03) == ((param[1] >> 2) & 3)) {
289                                 ps2pp_set_smartscroll(psmouse);
290                                 protocol = PSMOUSE_PS2PP;
291                         }
292                 }
293
294                 if (set_properties) {
295                         psmouse->vendor = "Logitech";
296                         psmouse->model = model;
297
298                         if (buttons < 3)
299                                 clear_bit(BTN_MIDDLE, psmouse->dev.keybit);
300                         if (buttons < 2)
301                                 clear_bit(BTN_RIGHT, psmouse->dev.keybit);
302
303                         if (model_info)
304                                 ps2pp_set_model_properties(psmouse, model_info);
305                 }
306         }
307
308         return protocol;
309 }
310