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