Subversion Repositories shark

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
494 giacomo 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 <linuxcomp.h>
13
 
14
#include <linux/input.h>
15
#include "psmouse.h"
16
#include "logips2pp.h"
17
 
18
#define DUBUG
19
 
20
/*
21
 * Process a PS2++ or PS2T++ packet.
22
 */
23
 
24
void ps2pp_process_packet(struct psmouse *psmouse)
25
{
26
        struct input_dev *dev = &psmouse->dev;
27
        unsigned char *packet = psmouse->packet;
28
 
29
        if ((packet[0] & 0x48) == 0x48 && (packet[1] & 0x02) == 0x02) {
30
 
31
                switch ((packet[1] >> 4) | (packet[0] & 0x30)) {
32
 
33
                        case 0x0d: /* Mouse extra info */
34
 
35
                                input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL,
36
                                        (int) (packet[2] & 8) - (int) (packet[2] & 7));
37
                                input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1);
38
                                input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1);
39
 
40
                                break;
41
 
42
                        case 0x0e: /* buttons 4, 5, 6, 7, 8, 9, 10 info */
43
 
44
                                input_report_key(dev, BTN_SIDE, (packet[2]) & 1);
45
                                input_report_key(dev, BTN_EXTRA, (packet[2] >> 1) & 1);
46
                                input_report_key(dev, BTN_BACK, (packet[2] >> 3) & 1);
47
                                input_report_key(dev, BTN_FORWARD, (packet[2] >> 4) & 1);
48
                                input_report_key(dev, BTN_TASK, (packet[2] >> 2) & 1);
49
 
50
                                break;
51
 
52
                        case 0x0f: /* TouchPad extra info */
53
 
54
                                input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL,
55
                                        (int) ((packet[2] >> 4) & 8) - (int) ((packet[2] >> 4) & 7));
56
                                packet[0] = packet[2] | 0x08;
57
                                break;
58
 
59
#ifdef DEBUG
60
                        default:
61
                                printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n",
62
                                        (packet[1] >> 4) | (packet[0] & 0x30));
63
#endif
64
                }
65
 
66
                packet[0] &= 0x0f;
67
                packet[1] = 0;
68
                packet[2] = 0;
69
 
70
        }
71
}
72
 
73
/*
74
 * ps2pp_cmd() sends a PS2++ command, sliced into two bit
75
 * pieces through the SETRES command. This is needed to send extended
76
 * commands to mice on notebooks that try to understand the PS/2 protocol
77
 * Ugly.
78
 */
79
 
80
static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned char command)
81
{
82
        unsigned char d;
83
        int i;
84
 
85
        if (psmouse_command(psmouse,  NULL, PSMOUSE_CMD_SETSCALE11))
86
                return -1;
87
 
88
        for (i = 6; i >= 0; i -= 2) {
89
                d = (command >> i) & 3;
90
                if(psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES))
91
                        return -1;
92
        }
93
 
94
        if (psmouse_command(psmouse, param, PSMOUSE_CMD_POLL))
95
                return -1;
96
 
97
        return 0;
98
}
99
 
100
/*
101
 * SmartScroll / CruiseControl for some newer Logitech mice Defaults to
102
 * enabled if we do nothing to it. Of course I put this in because I want it
103
 * disabled :P
104
 * 1 - enabled (if previously disabled, also default)
105
 * 0/2 - disabled
106
 */
107
 
108
static void ps2pp_set_smartscroll(struct psmouse *psmouse)
109
{
110
        unsigned char param[4];
111
 
112
        ps2pp_cmd(psmouse, param, 0x32);
113
 
114
        param[0] = 0;
115
        psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
116
        psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
117
        psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
118
 
119
        if (psmouse_smartscroll == 1)
120
                param[0] = 1;
121
        else
122
        if (psmouse_smartscroll > 2)
123
                return;
124
 
125
        /* else leave param[0] == 0 to disable */
126
        psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
127
}
128
 
129
/*
130
 * Support 800 dpi resolution _only_ if the user wants it (there are good
131
 * reasons to not use it even if the mouse supports it, and of course there are
132
 * also good reasons to use it, let the user decide).
133
 */
134
 
135
void ps2pp_set_800dpi(struct psmouse *psmouse)
136
{
137
        unsigned char param = 3;
138
        psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
139
        psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
140
        psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
141
        psmouse_command(psmouse, &param, PSMOUSE_CMD_SETRES);
142
}
143
 
144
/*
145
 * Detect the exact model and features of a PS2++ or PS2T++ Logitech mouse or
146
 * touchpad.
147
 */
148
 
149
int ps2pp_detect_model(struct psmouse *psmouse, unsigned char *param)
150
{
151
        int i;
152
        static int logitech_4btn[] = { 12, 40, 41, 42, 43, 52, 73, 80, -1 };
153
        static int logitech_wheel[] = { 52, 53, 75, 76, 80, 81, 83, 88, 112, -1 };
154
        static int logitech_ps2pp[] = { 12, 13, 40, 41, 42, 43, 50, 51, 52, 53, 73, 75,
155
                                                76, 80, 81, 83, 88, 96, 97, 112, -1 };
156
        static int logitech_mx[] = { 112, -1 };
157
 
158
        psmouse->vendor = "Logitech";
159
        psmouse->model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
160
 
161
        if (param[1] < 3)
162
                clear_bit(BTN_MIDDLE, psmouse->dev.keybit);
163
        if (param[1] < 2)
164
                clear_bit(BTN_RIGHT, psmouse->dev.keybit);
165
 
166
        psmouse->type = PSMOUSE_PS2;
167
 
168
        for (i = 0; logitech_ps2pp[i] != -1; i++)
169
                if (logitech_ps2pp[i] == psmouse->model)
170
                        psmouse->type = PSMOUSE_PS2PP;
171
 
172
        if (psmouse->type == PSMOUSE_PS2PP) {
173
 
174
                for (i = 0; logitech_4btn[i] != -1; i++)
175
                        if (logitech_4btn[i] == psmouse->model)
176
                                set_bit(BTN_SIDE, psmouse->dev.keybit);
177
 
178
                for (i = 0; logitech_wheel[i] != -1; i++)
179
                        if (logitech_wheel[i] == psmouse->model) {
180
                                set_bit(REL_WHEEL, psmouse->dev.relbit);
181
                                psmouse->name = "Wheel Mouse";
182
                        }
183
 
184
                for (i = 0; logitech_mx[i] != -1; i++)
185
                        if (logitech_mx[i]  == psmouse->model) {
186
                                set_bit(BTN_SIDE, psmouse->dev.keybit);
187
                                set_bit(BTN_EXTRA, psmouse->dev.keybit);
188
                                set_bit(BTN_BACK, psmouse->dev.keybit);
189
                                set_bit(BTN_FORWARD, psmouse->dev.keybit);
190
                                set_bit(BTN_TASK, psmouse->dev.keybit);
191
                                psmouse->name = "MX Mouse";
192
                        }
193
 
194
/*
195
 * Do Logitech PS2++ / PS2T++ magic init.
196
 */
197
 
198
                if (psmouse->model == 97) { /* TouchPad 3 */
199
 
200
                        set_bit(REL_WHEEL, psmouse->dev.relbit);
201
                        set_bit(REL_HWHEEL, psmouse->dev.relbit);
202
 
203
                        param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; /* Unprotect RAM */
204
                        psmouse_command(psmouse, param, 0x30d1);
205
                        param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b; /* Enable features */
206
                        psmouse_command(psmouse, param, 0x30d1);
207
                        param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3; /* Enable PS2++ */
208
                        psmouse_command(psmouse, param, 0x30d1);
209
 
210
                        param[0] = 0;
211
                        if (!psmouse_command(psmouse, param, 0x13d1) &&
212
                                param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) {
213
                                psmouse->name = "TouchPad 3";
214
                                return PSMOUSE_PS2TPP;
215
                        }
216
 
217
                } else {
218
 
219
                        param[0] = param[1] = param[2] = 0;
220
                        ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */
221
                        ps2pp_cmd(psmouse, param, 0xDB);
222
 
223
                        if ((param[0] & 0x78) == 0x48 && (param[1] & 0xf3) == 0xc2 &&
224
                                (param[2] & 3) == ((param[1] >> 2) & 3)) {
225
                                        ps2pp_set_smartscroll(psmouse);
226
                                        return PSMOUSE_PS2PP;
227
                        }
228
                }
229
        }
230
 
231
        return 0;
232
}