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