diff options
Diffstat (limited to 'drivers/input/mouse')
-rw-r--r-- | drivers/input/mouse/lifebook.c | 113 |
1 files changed, 93 insertions, 20 deletions
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c index aa3b245f25d9..1740cadd9594 100644 --- a/drivers/input/mouse/lifebook.c +++ b/drivers/input/mouse/lifebook.c | |||
@@ -20,6 +20,11 @@ | |||
20 | #include "psmouse.h" | 20 | #include "psmouse.h" |
21 | #include "lifebook.h" | 21 | #include "lifebook.h" |
22 | 22 | ||
23 | struct lifebook_data { | ||
24 | struct input_dev *dev2; /* Relative device */ | ||
25 | char phys[32]; | ||
26 | }; | ||
27 | |||
23 | static const char *desired_serio_phys; | 28 | static const char *desired_serio_phys; |
24 | 29 | ||
25 | static int lifebook_set_serio_phys(struct dmi_system_id *d) | 30 | static int lifebook_set_serio_phys(struct dmi_system_id *d) |
@@ -102,7 +107,9 @@ static struct dmi_system_id lifebook_dmi_table[] = { | |||
102 | 107 | ||
103 | static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse) | 108 | static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse) |
104 | { | 109 | { |
105 | struct input_dev *dev = psmouse->dev; | 110 | struct lifebook_data *priv = psmouse->private; |
111 | struct input_dev *dev1 = psmouse->dev; | ||
112 | struct input_dev *dev2 = priv->dev2; | ||
106 | unsigned char *packet = psmouse->packet; | 113 | unsigned char *packet = psmouse->packet; |
107 | int relative_packet = packet[0] & 0x08; | 114 | int relative_packet = packet[0] & 0x08; |
108 | 115 | ||
@@ -135,27 +142,35 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse) | |||
135 | } | 142 | } |
136 | 143 | ||
137 | if (relative_packet) { | 144 | if (relative_packet) { |
138 | input_report_rel(dev, REL_X, | 145 | if (!dev2) |
139 | ((packet[0] & 0x10) ? packet[1] - 256 : packet[1])); | 146 | printk(KERN_WARNING "lifebook.c: got relative packet " |
140 | input_report_rel(dev, REL_Y, | 147 | "but no relative device set up\n"); |
141 | -(int)((packet[0] & 0x20) ? packet[2] - 256 : packet[2])); | ||
142 | } else if (lifebook_use_6byte_proto) { | 148 | } else if (lifebook_use_6byte_proto) { |
143 | input_report_abs(dev, ABS_X, | 149 | input_report_abs(dev1, ABS_X, |
144 | ((packet[1] & 0x3f) << 6) | (packet[2] & 0x3f)); | 150 | ((packet[1] & 0x3f) << 6) | (packet[2] & 0x3f)); |
145 | input_report_abs(dev, ABS_Y, | 151 | input_report_abs(dev1, ABS_Y, |
146 | 4096 - (((packet[4] & 0x3f) << 6) | (packet[5] & 0x3f))); | 152 | 4096 - (((packet[4] & 0x3f) << 6) | (packet[5] & 0x3f))); |
147 | } else { | 153 | } else { |
148 | input_report_abs(dev, ABS_X, | 154 | input_report_abs(dev1, ABS_X, |
149 | (packet[1] | ((packet[0] & 0x30) << 4))); | 155 | (packet[1] | ((packet[0] & 0x30) << 4))); |
150 | input_report_abs(dev, ABS_Y, | 156 | input_report_abs(dev1, ABS_Y, |
151 | 1024 - (packet[2] | ((packet[0] & 0xC0) << 2))); | 157 | 1024 - (packet[2] | ((packet[0] & 0xC0) << 2))); |
152 | } | 158 | } |
153 | 159 | ||
154 | input_report_key(dev, BTN_LEFT, packet[0] & 0x01); | 160 | input_report_key(dev1, BTN_TOUCH, packet[0] & 0x04); |
155 | input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); | 161 | input_sync(dev1); |
156 | input_report_key(dev, BTN_TOUCH, packet[0] & 0x04); | ||
157 | 162 | ||
158 | input_sync(dev); | 163 | if (dev2) { |
164 | if (relative_packet) { | ||
165 | input_report_rel(dev2, REL_X, | ||
166 | ((packet[0] & 0x10) ? packet[1] - 256 : packet[1])); | ||
167 | input_report_rel(dev2, REL_Y, | ||
168 | -(int)((packet[0] & 0x20) ? packet[2] - 256 : packet[2])); | ||
169 | } | ||
170 | input_report_key(dev2, BTN_LEFT, packet[0] & 0x01); | ||
171 | input_report_key(dev2, BTN_RIGHT, packet[0] & 0x02); | ||
172 | input_sync(dev2); | ||
173 | } | ||
159 | 174 | ||
160 | return PSMOUSE_FULL_PACKET; | 175 | return PSMOUSE_FULL_PACKET; |
161 | } | 176 | } |
@@ -179,6 +194,14 @@ static int lifebook_absolute_mode(struct psmouse *psmouse) | |||
179 | return 0; | 194 | return 0; |
180 | } | 195 | } |
181 | 196 | ||
197 | static void lifebook_relative_mode(struct psmouse *psmouse) | ||
198 | { | ||
199 | struct ps2dev *ps2dev = &psmouse->ps2dev; | ||
200 | unsigned char param = 0x06; | ||
201 | |||
202 | ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES); | ||
203 | } | ||
204 | |||
182 | static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution) | 205 | static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution) |
183 | { | 206 | { |
184 | static const unsigned char params[] = { 0, 1, 2, 2, 3 }; | 207 | static const unsigned char params[] = { 0, 1, 2, 2, 3 }; |
@@ -195,6 +218,8 @@ static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolu | |||
195 | static void lifebook_disconnect(struct psmouse *psmouse) | 218 | static void lifebook_disconnect(struct psmouse *psmouse) |
196 | { | 219 | { |
197 | psmouse_reset(psmouse); | 220 | psmouse_reset(psmouse); |
221 | kfree(psmouse->private); | ||
222 | psmouse->private = NULL; | ||
198 | } | 223 | } |
199 | 224 | ||
200 | int lifebook_detect(struct psmouse *psmouse, int set_properties) | 225 | int lifebook_detect(struct psmouse *psmouse, int set_properties) |
@@ -214,26 +239,74 @@ int lifebook_detect(struct psmouse *psmouse, int set_properties) | |||
214 | return 0; | 239 | return 0; |
215 | } | 240 | } |
216 | 241 | ||
242 | static int lifebook_create_relative_device(struct psmouse *psmouse) | ||
243 | { | ||
244 | struct input_dev *dev2; | ||
245 | struct lifebook_data *priv; | ||
246 | int error = -ENOMEM; | ||
247 | |||
248 | priv = kzalloc(sizeof(struct lifebook_data), GFP_KERNEL); | ||
249 | dev2 = input_allocate_device(); | ||
250 | if (!priv || !dev2) | ||
251 | goto err_out; | ||
252 | |||
253 | priv->dev2 = dev2; | ||
254 | snprintf(priv->phys, sizeof(priv->phys), | ||
255 | "%s/input1", psmouse->ps2dev.serio->phys); | ||
256 | |||
257 | dev2->phys = priv->phys; | ||
258 | dev2->name = "PS/2 Touchpad"; | ||
259 | dev2->id.bustype = BUS_I8042; | ||
260 | dev2->id.vendor = 0x0002; | ||
261 | dev2->id.product = PSMOUSE_LIFEBOOK; | ||
262 | dev2->id.version = 0x0000; | ||
263 | dev2->dev.parent = &psmouse->ps2dev.serio->dev; | ||
264 | |||
265 | dev2->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); | ||
266 | dev2->relbit[LONG(REL_X)] = BIT(REL_X) | BIT(REL_Y); | ||
267 | dev2->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT); | ||
268 | |||
269 | error = input_register_device(priv->dev2); | ||
270 | if (error) | ||
271 | goto err_out; | ||
272 | |||
273 | psmouse->private = priv; | ||
274 | return 0; | ||
275 | |||
276 | err_out: | ||
277 | input_free_device(dev2); | ||
278 | kfree(priv); | ||
279 | return error; | ||
280 | } | ||
281 | |||
217 | int lifebook_init(struct psmouse *psmouse) | 282 | int lifebook_init(struct psmouse *psmouse) |
218 | { | 283 | { |
219 | struct input_dev *input_dev = psmouse->dev; | 284 | struct input_dev *dev1 = psmouse->dev; |
220 | int max_coord = lifebook_use_6byte_proto ? 1024 : 4096; | 285 | int max_coord = lifebook_use_6byte_proto ? 1024 : 4096; |
221 | 286 | ||
222 | if (lifebook_absolute_mode(psmouse)) | 287 | if (lifebook_absolute_mode(psmouse)) |
223 | return -1; | 288 | return -1; |
224 | 289 | ||
225 | input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL); | 290 | dev1->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY); |
226 | input_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); | 291 | dev1->relbit[0] = 0; |
227 | input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); | 292 | dev1->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); |
228 | input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); | 293 | input_set_abs_params(dev1, ABS_X, 0, max_coord, 0, 0); |
229 | input_set_abs_params(input_dev, ABS_X, 0, max_coord, 0, 0); | 294 | input_set_abs_params(dev1, ABS_Y, 0, max_coord, 0, 0); |
230 | input_set_abs_params(input_dev, ABS_Y, 0, max_coord, 0, 0); | 295 | |
296 | if (!desired_serio_phys) { | ||
297 | if (lifebook_create_relative_device(psmouse)) { | ||
298 | lifebook_relative_mode(psmouse); | ||
299 | return -1; | ||
300 | } | ||
301 | } | ||
231 | 302 | ||
232 | psmouse->protocol_handler = lifebook_process_byte; | 303 | psmouse->protocol_handler = lifebook_process_byte; |
233 | psmouse->set_resolution = lifebook_set_resolution; | 304 | psmouse->set_resolution = lifebook_set_resolution; |
234 | psmouse->disconnect = lifebook_disconnect; | 305 | psmouse->disconnect = lifebook_disconnect; |
235 | psmouse->reconnect = lifebook_absolute_mode; | 306 | psmouse->reconnect = lifebook_absolute_mode; |
236 | 307 | ||
308 | psmouse->model = lifebook_use_6byte_proto ? 6 : 3; | ||
309 | |||
237 | /* | 310 | /* |
238 | * Use packet size = 3 even when using 6-byte protocol because | 311 | * Use packet size = 3 even when using 6-byte protocol because |
239 | * that's what POLL will return on Lifebooks (according to spec). | 312 | * that's what POLL will return on Lifebooks (according to spec). |