diff options
Diffstat (limited to 'drivers/input/mouse/lifebook.c')
-rw-r--r-- | drivers/input/mouse/lifebook.c | 195 |
1 files changed, 171 insertions, 24 deletions
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c index 29542f0631cb..1740cadd9594 100644 --- a/drivers/input/mouse/lifebook.c +++ b/drivers/input/mouse/lifebook.c | |||
@@ -20,6 +20,27 @@ | |||
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 | |||
28 | static const char *desired_serio_phys; | ||
29 | |||
30 | static int lifebook_set_serio_phys(struct dmi_system_id *d) | ||
31 | { | ||
32 | desired_serio_phys = d->driver_data; | ||
33 | return 0; | ||
34 | } | ||
35 | |||
36 | static unsigned char lifebook_use_6byte_proto; | ||
37 | |||
38 | static int lifebook_set_6byte_proto(struct dmi_system_id *d) | ||
39 | { | ||
40 | lifebook_use_6byte_proto = 1; | ||
41 | return 0; | ||
42 | } | ||
43 | |||
23 | static struct dmi_system_id lifebook_dmi_table[] = { | 44 | static struct dmi_system_id lifebook_dmi_table[] = { |
24 | { | 45 | { |
25 | .ident = "FLORA-ie 55mi", | 46 | .ident = "FLORA-ie 55mi", |
@@ -56,6 +77,24 @@ static struct dmi_system_id lifebook_dmi_table[] = { | |||
56 | .matches = { | 77 | .matches = { |
57 | DMI_MATCH(DMI_PRODUCT_NAME, "CF-18"), | 78 | DMI_MATCH(DMI_PRODUCT_NAME, "CF-18"), |
58 | }, | 79 | }, |
80 | .callback = lifebook_set_serio_phys, | ||
81 | .driver_data = "isa0060/serio3", | ||
82 | }, | ||
83 | { | ||
84 | .ident = "Panasonic CF-28", | ||
85 | .matches = { | ||
86 | DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"), | ||
87 | DMI_MATCH(DMI_PRODUCT_NAME, "CF-28"), | ||
88 | }, | ||
89 | .callback = lifebook_set_6byte_proto, | ||
90 | }, | ||
91 | { | ||
92 | .ident = "Panasonic CF-29", | ||
93 | .matches = { | ||
94 | DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"), | ||
95 | DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"), | ||
96 | }, | ||
97 | .callback = lifebook_set_6byte_proto, | ||
59 | }, | 98 | }, |
60 | { | 99 | { |
61 | .ident = "Lifebook B142", | 100 | .ident = "Lifebook B142", |
@@ -68,30 +107,70 @@ static struct dmi_system_id lifebook_dmi_table[] = { | |||
68 | 107 | ||
69 | static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse) | 108 | static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse) |
70 | { | 109 | { |
110 | struct lifebook_data *priv = psmouse->private; | ||
111 | struct input_dev *dev1 = psmouse->dev; | ||
112 | struct input_dev *dev2 = priv->dev2; | ||
71 | unsigned char *packet = psmouse->packet; | 113 | unsigned char *packet = psmouse->packet; |
72 | struct input_dev *dev = psmouse->dev; | 114 | int relative_packet = packet[0] & 0x08; |
73 | 115 | ||
74 | if (psmouse->pktcnt != 3) | 116 | if (relative_packet || !lifebook_use_6byte_proto) { |
75 | return PSMOUSE_GOOD_DATA; | 117 | if (psmouse->pktcnt != 3) |
118 | return PSMOUSE_GOOD_DATA; | ||
119 | } else { | ||
120 | switch (psmouse->pktcnt) { | ||
121 | case 1: | ||
122 | return (packet[0] & 0xf8) == 0x00 ? | ||
123 | PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA; | ||
124 | case 2: | ||
125 | return PSMOUSE_GOOD_DATA; | ||
126 | case 3: | ||
127 | return ((packet[2] & 0x30) << 2) == (packet[2] & 0xc0) ? | ||
128 | PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA; | ||
129 | case 4: | ||
130 | return (packet[3] & 0xf8) == 0xc0 ? | ||
131 | PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA; | ||
132 | case 5: | ||
133 | return (packet[4] & 0xc0) == (packet[2] & 0xc0) ? | ||
134 | PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA; | ||
135 | case 6: | ||
136 | if (((packet[5] & 0x30) << 2) != (packet[5] & 0xc0)) | ||
137 | return PSMOUSE_BAD_DATA; | ||
138 | if ((packet[5] & 0xc0) != (packet[1] & 0xc0)) | ||
139 | return PSMOUSE_BAD_DATA; | ||
140 | break; /* report data */ | ||
141 | } | ||
142 | } | ||
76 | 143 | ||
77 | /* calculate X and Y */ | 144 | if (relative_packet) { |
78 | if ((packet[0] & 0x08) == 0x00) { | 145 | if (!dev2) |
79 | input_report_abs(dev, ABS_X, | 146 | printk(KERN_WARNING "lifebook.c: got relative packet " |
147 | "but no relative device set up\n"); | ||
148 | } else if (lifebook_use_6byte_proto) { | ||
149 | input_report_abs(dev1, ABS_X, | ||
150 | ((packet[1] & 0x3f) << 6) | (packet[2] & 0x3f)); | ||
151 | input_report_abs(dev1, ABS_Y, | ||
152 | 4096 - (((packet[4] & 0x3f) << 6) | (packet[5] & 0x3f))); | ||
153 | } else { | ||
154 | input_report_abs(dev1, ABS_X, | ||
80 | (packet[1] | ((packet[0] & 0x30) << 4))); | 155 | (packet[1] | ((packet[0] & 0x30) << 4))); |
81 | input_report_abs(dev, ABS_Y, | 156 | input_report_abs(dev1, ABS_Y, |
82 | 1024 - (packet[2] | ((packet[0] & 0xC0) << 2))); | 157 | 1024 - (packet[2] | ((packet[0] & 0xC0) << 2))); |
83 | } else { | ||
84 | input_report_rel(dev, REL_X, | ||
85 | ((packet[0] & 0x10) ? packet[1] - 256 : packet[1])); | ||
86 | input_report_rel(dev, REL_Y, | ||
87 | -(int)((packet[0] & 0x20) ? packet[2] - 256 : packet[2])); | ||
88 | } | 158 | } |
89 | 159 | ||
90 | input_report_key(dev, BTN_LEFT, packet[0] & 0x01); | 160 | input_report_key(dev1, BTN_TOUCH, packet[0] & 0x04); |
91 | input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); | 161 | input_sync(dev1); |
92 | input_report_key(dev, BTN_TOUCH, packet[0] & 0x04); | ||
93 | 162 | ||
94 | 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 | } | ||
95 | 174 | ||
96 | return PSMOUSE_FULL_PACKET; | 175 | return PSMOUSE_FULL_PACKET; |
97 | } | 176 | } |
@@ -109,12 +188,20 @@ static int lifebook_absolute_mode(struct psmouse *psmouse) | |||
109 | you leave this call out the touchsreen will never send | 188 | you leave this call out the touchsreen will never send |
110 | absolute coordinates | 189 | absolute coordinates |
111 | */ | 190 | */ |
112 | param = 0x07; | 191 | param = lifebook_use_6byte_proto ? 0x08 : 0x07; |
113 | ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES); | 192 | ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES); |
114 | 193 | ||
115 | return 0; | 194 | return 0; |
116 | } | 195 | } |
117 | 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 | |||
118 | static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution) | 205 | static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution) |
119 | { | 206 | { |
120 | static const unsigned char params[] = { 0, 1, 2, 2, 3 }; | 207 | static const unsigned char params[] = { 0, 1, 2, 2, 3 }; |
@@ -131,6 +218,8 @@ static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolu | |||
131 | static void lifebook_disconnect(struct psmouse *psmouse) | 218 | static void lifebook_disconnect(struct psmouse *psmouse) |
132 | { | 219 | { |
133 | psmouse_reset(psmouse); | 220 | psmouse_reset(psmouse); |
221 | kfree(psmouse->private); | ||
222 | psmouse->private = NULL; | ||
134 | } | 223 | } |
135 | 224 | ||
136 | int lifebook_detect(struct psmouse *psmouse, int set_properties) | 225 | int lifebook_detect(struct psmouse *psmouse, int set_properties) |
@@ -138,6 +227,10 @@ int lifebook_detect(struct psmouse *psmouse, int set_properties) | |||
138 | if (!dmi_check_system(lifebook_dmi_table)) | 227 | if (!dmi_check_system(lifebook_dmi_table)) |
139 | return -1; | 228 | return -1; |
140 | 229 | ||
230 | if (desired_serio_phys && | ||
231 | strcmp(psmouse->ps2dev.serio->phys, desired_serio_phys)) | ||
232 | return -1; | ||
233 | |||
141 | if (set_properties) { | 234 | if (set_properties) { |
142 | psmouse->vendor = "Fujitsu"; | 235 | psmouse->vendor = "Fujitsu"; |
143 | psmouse->name = "Lifebook TouchScreen"; | 236 | psmouse->name = "Lifebook TouchScreen"; |
@@ -146,24 +239,78 @@ int lifebook_detect(struct psmouse *psmouse, int set_properties) | |||
146 | return 0; | 239 | return 0; |
147 | } | 240 | } |
148 | 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 | |||
149 | int lifebook_init(struct psmouse *psmouse) | 282 | int lifebook_init(struct psmouse *psmouse) |
150 | { | 283 | { |
151 | struct input_dev *input_dev = psmouse->dev; | 284 | struct input_dev *dev1 = psmouse->dev; |
285 | int max_coord = lifebook_use_6byte_proto ? 1024 : 4096; | ||
152 | 286 | ||
153 | if (lifebook_absolute_mode(psmouse)) | 287 | if (lifebook_absolute_mode(psmouse)) |
154 | return -1; | 288 | return -1; |
155 | 289 | ||
156 | input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL); | 290 | dev1->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY); |
157 | input_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); | 291 | dev1->relbit[0] = 0; |
158 | input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); | 292 | dev1->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); |
159 | input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); | 293 | input_set_abs_params(dev1, ABS_X, 0, max_coord, 0, 0); |
160 | input_set_abs_params(input_dev, ABS_X, 0, 1024, 0, 0); | 294 | input_set_abs_params(dev1, ABS_Y, 0, max_coord, 0, 0); |
161 | input_set_abs_params(input_dev, ABS_Y, 0, 1024, 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 | } | ||
162 | 302 | ||
163 | psmouse->protocol_handler = lifebook_process_byte; | 303 | psmouse->protocol_handler = lifebook_process_byte; |
164 | psmouse->set_resolution = lifebook_set_resolution; | 304 | psmouse->set_resolution = lifebook_set_resolution; |
165 | psmouse->disconnect = lifebook_disconnect; | 305 | psmouse->disconnect = lifebook_disconnect; |
166 | psmouse->reconnect = lifebook_absolute_mode; | 306 | psmouse->reconnect = lifebook_absolute_mode; |
307 | |||
308 | psmouse->model = lifebook_use_6byte_proto ? 6 : 3; | ||
309 | |||
310 | /* | ||
311 | * Use packet size = 3 even when using 6-byte protocol because | ||
312 | * that's what POLL will return on Lifebooks (according to spec). | ||
313 | */ | ||
167 | psmouse->pktsize = 3; | 314 | psmouse->pktsize = 3; |
168 | 315 | ||
169 | return 0; | 316 | return 0; |