root/drivers/input/mouse/lifebook.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. lifebook_limit_serio3
  2. lifebook_set_6byte_proto
  3. lifebook_module_init
  4. lifebook_process_byte
  5. lifebook_absolute_mode
  6. lifebook_relative_mode
  7. lifebook_set_resolution
  8. lifebook_disconnect
  9. lifebook_detect
  10. lifebook_create_relative_device
  11. lifebook_init

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

/* [<][>][^][v][top][bottom][index][help] */