1 /* 2 * Fujitsu B-series Lifebook PS/2 TouchScreen driver 3 * 4 * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz> 5 * Copyright (c) 2005 Kenan Esau <kenan.esau@conan.de> 6 * 7 * TouchScreen detection, absolute mode setting and packet layout is taken from 8 * Harald Hoyer's description of the device. 9 * 10 * This program is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License version 2 as published by 12 * the Free Software Foundation. 13 */ 14 15 #include <linux/input.h> 16 #include <linux/serio.h> 17 #include <linux/libps2.h> 18 #include <linux/dmi.h> 19 20 #include "psmouse.h" 21 #include "lifebook.h" 22 23 struct lifebook_data { 24 struct input_dev *dev2; /* Relative device */ 25 char phys[32]; 26 }; 27 28 static bool lifebook_present; 29 30 static const char *desired_serio_phys; 31 32 static int lifebook_limit_serio3(const struct dmi_system_id *d) 33 { 34 desired_serio_phys = "isa0060/serio3"; 35 return 0; 36 } 37 38 static bool lifebook_use_6byte_proto; 39 40 static int lifebook_set_6byte_proto(const struct dmi_system_id *d) 41 { 42 lifebook_use_6byte_proto = true; 43 return 0; 44 } 45 46 static const struct dmi_system_id __initconst lifebook_dmi_table[] = { 47 { 48 /* FLORA-ie 55mi */ 49 .matches = { 50 DMI_MATCH(DMI_PRODUCT_NAME, "FLORA-ie 55mi"), 51 }, 52 }, 53 { 54 /* LifeBook B */ 55 .matches = { 56 DMI_MATCH(DMI_PRODUCT_NAME, "Lifebook B Series"), 57 }, 58 }, 59 { 60 /* LifeBook B */ 61 .matches = { 62 DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B Series"), 63 }, 64 }, 65 { 66 /* Lifebook B */ 67 .matches = { 68 DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK B Series"), 69 }, 70 }, 71 { 72 /* Lifebook B-2130 */ 73 .matches = { 74 DMI_MATCH(DMI_BOARD_NAME, "ZEPHYR"), 75 }, 76 }, 77 { 78 /* Lifebook B213x/B2150 */ 79 .matches = { 80 DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B2131/B2133/B2150"), 81 }, 82 }, 83 { 84 /* Zephyr */ 85 .matches = { 86 DMI_MATCH(DMI_PRODUCT_NAME, "ZEPHYR"), 87 }, 88 }, 89 { 90 /* Panasonic CF-18 */ 91 .matches = { 92 DMI_MATCH(DMI_PRODUCT_NAME, "CF-18"), 93 }, 94 .callback = lifebook_limit_serio3, 95 }, 96 { 97 /* Panasonic CF-28 */ 98 .matches = { 99 DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"), 100 DMI_MATCH(DMI_PRODUCT_NAME, "CF-28"), 101 }, 102 .callback = lifebook_set_6byte_proto, 103 }, 104 { 105 /* Panasonic CF-29 */ 106 .matches = { 107 DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"), 108 DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"), 109 }, 110 .callback = lifebook_set_6byte_proto, 111 }, 112 { 113 /* Panasonic CF-72 */ 114 .matches = { 115 DMI_MATCH(DMI_PRODUCT_NAME, "CF-72"), 116 }, 117 .callback = lifebook_set_6byte_proto, 118 }, 119 { 120 /* Lifebook B142 */ 121 .matches = { 122 DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B142"), 123 }, 124 }, 125 { } 126 }; 127 128 void __init lifebook_module_init(void) 129 { 130 lifebook_present = dmi_check_system(lifebook_dmi_table); 131 } 132 133 static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse) 134 { 135 struct lifebook_data *priv = psmouse->private; 136 struct input_dev *dev1 = psmouse->dev; 137 struct input_dev *dev2 = priv ? priv->dev2 : NULL; 138 unsigned char *packet = psmouse->packet; 139 bool relative_packet = packet[0] & 0x08; 140 141 if (relative_packet || !lifebook_use_6byte_proto) { 142 if (psmouse->pktcnt != 3) 143 return PSMOUSE_GOOD_DATA; 144 } else { 145 switch (psmouse->pktcnt) { 146 case 1: 147 return (packet[0] & 0xf8) == 0x00 ? 148 PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA; 149 case 2: 150 return PSMOUSE_GOOD_DATA; 151 case 3: 152 return ((packet[2] & 0x30) << 2) == (packet[2] & 0xc0) ? 153 PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA; 154 case 4: 155 return (packet[3] & 0xf8) == 0xc0 ? 156 PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA; 157 case 5: 158 return (packet[4] & 0xc0) == (packet[2] & 0xc0) ? 159 PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA; 160 case 6: 161 if (((packet[5] & 0x30) << 2) != (packet[5] & 0xc0)) 162 return PSMOUSE_BAD_DATA; 163 if ((packet[5] & 0xc0) != (packet[1] & 0xc0)) 164 return PSMOUSE_BAD_DATA; 165 break; /* report data */ 166 } 167 } 168 169 if (relative_packet) { 170 if (!dev2) 171 printk(KERN_WARNING "lifebook.c: got relative packet " 172 "but no relative device set up\n"); 173 } else { 174 if (lifebook_use_6byte_proto) { 175 input_report_abs(dev1, ABS_X, 176 ((packet[1] & 0x3f) << 6) | (packet[2] & 0x3f)); 177 input_report_abs(dev1, ABS_Y, 178 4096 - (((packet[4] & 0x3f) << 6) | (packet[5] & 0x3f))); 179 } else { 180 input_report_abs(dev1, ABS_X, 181 (packet[1] | ((packet[0] & 0x30) << 4))); 182 input_report_abs(dev1, ABS_Y, 183 1024 - (packet[2] | ((packet[0] & 0xC0) << 2))); 184 } 185 input_report_key(dev1, BTN_TOUCH, packet[0] & 0x04); 186 input_sync(dev1); 187 } 188 189 if (dev2) { 190 if (relative_packet) { 191 input_report_rel(dev2, REL_X, 192 ((packet[0] & 0x10) ? packet[1] - 256 : packet[1])); 193 input_report_rel(dev2, REL_Y, 194 -(int)((packet[0] & 0x20) ? packet[2] - 256 : packet[2])); 195 } 196 input_report_key(dev2, BTN_LEFT, packet[0] & 0x01); 197 input_report_key(dev2, BTN_RIGHT, packet[0] & 0x02); 198 input_sync(dev2); 199 } 200 201 return PSMOUSE_FULL_PACKET; 202 } 203 204 static int lifebook_absolute_mode(struct psmouse *psmouse) 205 { 206 struct ps2dev *ps2dev = &psmouse->ps2dev; 207 unsigned char param; 208 209 if (psmouse_reset(psmouse)) 210 return -1; 211 212 /* 213 * Enable absolute output -- ps2_command fails always but if 214 * you leave this call out the touchsreen will never send 215 * absolute coordinates 216 */ 217 param = lifebook_use_6byte_proto ? 0x08 : 0x07; 218 ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES); 219 220 return 0; 221 } 222 223 static void lifebook_relative_mode(struct psmouse *psmouse) 224 { 225 struct ps2dev *ps2dev = &psmouse->ps2dev; 226 unsigned char param = 0x06; 227 228 ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES); 229 } 230 231 static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution) 232 { 233 static const unsigned char params[] = { 0, 1, 2, 2, 3 }; 234 unsigned char p; 235 236 if (resolution == 0 || resolution > 400) 237 resolution = 400; 238 239 p = params[resolution / 100]; 240 ps2_command(&psmouse->ps2dev, &p, PSMOUSE_CMD_SETRES); 241 psmouse->resolution = 50 << p; 242 } 243 244 static void lifebook_disconnect(struct psmouse *psmouse) 245 { 246 struct lifebook_data *priv = psmouse->private; 247 248 psmouse_reset(psmouse); 249 if (priv) { 250 input_unregister_device(priv->dev2); 251 kfree(priv); 252 } 253 psmouse->private = NULL; 254 } 255 256 int lifebook_detect(struct psmouse *psmouse, bool set_properties) 257 { 258 if (!lifebook_present) 259 return -1; 260 261 if (desired_serio_phys && 262 strcmp(psmouse->ps2dev.serio->phys, desired_serio_phys)) 263 return -1; 264 265 if (set_properties) { 266 psmouse->vendor = "Fujitsu"; 267 psmouse->name = "Lifebook TouchScreen"; 268 } 269 270 return 0; 271 } 272 273 static int lifebook_create_relative_device(struct psmouse *psmouse) 274 { 275 struct input_dev *dev2; 276 struct lifebook_data *priv; 277 int error = -ENOMEM; 278 279 priv = kzalloc(sizeof(struct lifebook_data), GFP_KERNEL); 280 dev2 = input_allocate_device(); 281 if (!priv || !dev2) 282 goto err_out; 283 284 priv->dev2 = dev2; 285 snprintf(priv->phys, sizeof(priv->phys), 286 "%s/input1", psmouse->ps2dev.serio->phys); 287 288 dev2->phys = priv->phys; 289 dev2->name = "PS/2 Touchpad"; 290 dev2->id.bustype = BUS_I8042; 291 dev2->id.vendor = 0x0002; 292 dev2->id.product = PSMOUSE_LIFEBOOK; 293 dev2->id.version = 0x0000; 294 dev2->dev.parent = &psmouse->ps2dev.serio->dev; 295 296 dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); 297 dev2->relbit[BIT_WORD(REL_X)] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); 298 dev2->keybit[BIT_WORD(BTN_LEFT)] = 299 BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT); 300 301 error = input_register_device(priv->dev2); 302 if (error) 303 goto err_out; 304 305 psmouse->private = priv; 306 return 0; 307 308 err_out: 309 input_free_device(dev2); 310 kfree(priv); 311 return error; 312 } 313 314 int lifebook_init(struct psmouse *psmouse) 315 { 316 struct input_dev *dev1 = psmouse->dev; 317 int max_coord = lifebook_use_6byte_proto ? 4096 : 1024; 318 319 if (lifebook_absolute_mode(psmouse)) 320 return -1; 321 322 dev1->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY); 323 dev1->relbit[0] = 0; 324 dev1->keybit[BIT_WORD(BTN_MOUSE)] = 0; 325 dev1->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); 326 input_set_abs_params(dev1, ABS_X, 0, max_coord, 0, 0); 327 input_set_abs_params(dev1, ABS_Y, 0, max_coord, 0, 0); 328 329 if (!desired_serio_phys) { 330 if (lifebook_create_relative_device(psmouse)) { 331 lifebook_relative_mode(psmouse); 332 return -1; 333 } 334 } 335 336 psmouse->protocol_handler = lifebook_process_byte; 337 psmouse->set_resolution = lifebook_set_resolution; 338 psmouse->disconnect = lifebook_disconnect; 339 psmouse->reconnect = lifebook_absolute_mode; 340 341 psmouse->model = lifebook_use_6byte_proto ? 6 : 3; 342 343 /* 344 * Use packet size = 3 even when using 6-byte protocol because 345 * that's what POLL will return on Lifebooks (according to spec). 346 */ 347 psmouse->pktsize = 3; 348 349 return 0; 350 } 351 352