LCOV - code coverage report
Current view: top level - drivers/input/mouse - lifebook.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 5 114 4.4 %
Date: 2022-04-01 14:35:51 Functions: 2 9 22.2 %
Branches: 1 55 1.8 %

           Branch data     Line data    Source code
       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                 :          0 : static int lifebook_limit_serio3(const struct dmi_system_id *d)
      32                 :            : {
      33                 :          0 :         desired_serio_phys = "isa0060/serio3";
      34                 :          0 :         return 1;
      35                 :            : }
      36                 :            : 
      37                 :            : static bool lifebook_use_6byte_proto;
      38                 :            : 
      39                 :          0 : static int lifebook_set_6byte_proto(const struct dmi_system_id *d)
      40                 :            : {
      41                 :          0 :         lifebook_use_6byte_proto = true;
      42                 :          0 :         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                 :         21 : void __init lifebook_module_init(void)
     128                 :            : {
     129                 :         21 :         lifebook_present = dmi_check_system(lifebook_dmi_table);
     130                 :         21 : }
     131                 :            : 
     132                 :          0 : static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
     133                 :            : {
     134                 :          0 :         struct lifebook_data *priv = psmouse->private;
     135                 :          0 :         struct input_dev *dev1 = psmouse->dev;
     136         [ #  # ]:          0 :         struct input_dev *dev2 = priv ? priv->dev2 : NULL;
     137                 :          0 :         u8 *packet = psmouse->packet;
     138                 :          0 :         bool relative_packet = packet[0] & 0x08;
     139                 :            : 
     140   [ #  #  #  # ]:          0 :         if (relative_packet || !lifebook_use_6byte_proto) {
     141         [ #  # ]:          0 :                 if (psmouse->pktcnt != 3)
     142                 :            :                         return PSMOUSE_GOOD_DATA;
     143                 :            :         } else {
     144   [ #  #  #  #  :          0 :                 switch (psmouse->pktcnt) {
                #  #  # ]
     145                 :          0 :                 case 1:
     146                 :          0 :                         return (packet[0] & 0xf8) == 0x00 ?
     147                 :          0 :                                 PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
     148                 :            :                 case 2:
     149                 :            :                         return PSMOUSE_GOOD_DATA;
     150                 :          0 :                 case 3:
     151                 :          0 :                         return ((packet[2] & 0x30) << 2) == (packet[2] & 0xc0) ?
     152                 :          0 :                                 PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
     153                 :          0 :                 case 4:
     154                 :          0 :                         return (packet[3] & 0xf8) == 0xc0 ?
     155                 :          0 :                                 PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
     156                 :          0 :                 case 5:
     157                 :          0 :                         return (packet[4] & 0xc0) == (packet[2] & 0xc0) ?
     158                 :          0 :                                 PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
     159                 :          0 :                 case 6:
     160         [ #  # ]:          0 :                         if (((packet[5] & 0x30) << 2) != (packet[5] & 0xc0))
     161                 :            :                                 return PSMOUSE_BAD_DATA;
     162         [ #  # ]:          0 :                         if ((packet[5] & 0xc0) != (packet[1] & 0xc0))
     163                 :            :                                 return PSMOUSE_BAD_DATA;
     164                 :            :                         break; /* report data */
     165                 :            :                 }
     166                 :          0 :         }
     167                 :            : 
     168         [ #  # ]:          0 :         if (relative_packet) {
     169         [ #  # ]:          0 :                 if (!dev2)
     170                 :          0 :                         psmouse_warn(psmouse,
     171                 :            :                                      "got relative packet but no relative device set up\n");
     172                 :            :         } else {
     173         [ #  # ]:          0 :                 if (lifebook_use_6byte_proto) {
     174                 :          0 :                         input_report_abs(dev1, ABS_X,
     175                 :          0 :                                 ((packet[1] & 0x3f) << 6) | (packet[2] & 0x3f));
     176                 :          0 :                         input_report_abs(dev1, ABS_Y,
     177                 :          0 :                                 4096 - (((packet[4] & 0x3f) << 6) | (packet[5] & 0x3f)));
     178                 :            :                 } else {
     179                 :          0 :                         input_report_abs(dev1, ABS_X,
     180                 :          0 :                                 (packet[1] | ((packet[0] & 0x30) << 4)));
     181                 :          0 :                         input_report_abs(dev1, ABS_Y,
     182                 :          0 :                                 1024 - (packet[2] | ((packet[0] & 0xC0) << 2)));
     183                 :            :                 }
     184                 :          0 :                 input_report_key(dev1, BTN_TOUCH, packet[0] & 0x04);
     185                 :          0 :                 input_sync(dev1);
     186                 :            :         }
     187                 :            : 
     188         [ #  # ]:          0 :         if (dev2) {
     189         [ #  # ]:          0 :                 if (relative_packet)
     190                 :          0 :                         psmouse_report_standard_motion(dev2, packet);
     191                 :            : 
     192                 :          0 :                 psmouse_report_standard_buttons(dev2, packet[0]);
     193                 :          0 :                 input_sync(dev2);
     194                 :            :         }
     195                 :            : 
     196                 :            :         return PSMOUSE_FULL_PACKET;
     197                 :            : }
     198                 :            : 
     199                 :          0 : static int lifebook_absolute_mode(struct psmouse *psmouse)
     200                 :            : {
     201                 :          0 :         struct ps2dev *ps2dev = &psmouse->ps2dev;
     202                 :          0 :         u8 param;
     203                 :          0 :         int error;
     204                 :            : 
     205                 :          0 :         error = psmouse_reset(psmouse);
     206         [ #  # ]:          0 :         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         [ #  # ]:          0 :         param = lifebook_use_6byte_proto ? 0x08 : 0x07;
     215                 :          0 :         ps2_command(ps2dev, &param, PSMOUSE_CMD_SETRES);
     216                 :            : 
     217                 :          0 :         return 0;
     218                 :            : }
     219                 :            : 
     220                 :          0 : static void lifebook_relative_mode(struct psmouse *psmouse)
     221                 :            : {
     222                 :          0 :         struct ps2dev *ps2dev = &psmouse->ps2dev;
     223                 :          0 :         u8 param = 0x06;
     224                 :            : 
     225                 :          0 :         ps2_command(ps2dev, &param, PSMOUSE_CMD_SETRES);
     226                 :            : }
     227                 :            : 
     228                 :          0 : static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution)
     229                 :            : {
     230                 :          0 :         static const u8 params[] = { 0, 1, 2, 2, 3 };
     231                 :          0 :         u8 p;
     232                 :            : 
     233         [ #  # ]:          0 :         if (resolution == 0 || resolution > 400)
     234                 :          0 :                 resolution = 400;
     235                 :            : 
     236                 :          0 :         p = params[resolution / 100];
     237                 :          0 :         ps2_command(&psmouse->ps2dev, &p, PSMOUSE_CMD_SETRES);
     238                 :          0 :         psmouse->resolution = 50 << p;
     239                 :          0 : }
     240                 :            : 
     241                 :          0 : static void lifebook_disconnect(struct psmouse *psmouse)
     242                 :            : {
     243                 :          0 :         struct lifebook_data *priv = psmouse->private;
     244                 :            : 
     245                 :          0 :         psmouse_reset(psmouse);
     246         [ #  # ]:          0 :         if (priv) {
     247                 :          0 :                 input_unregister_device(priv->dev2);
     248                 :          0 :                 kfree(priv);
     249                 :            :         }
     250                 :          0 :         psmouse->private = NULL;
     251                 :          0 : }
     252                 :            : 
     253                 :         21 : int lifebook_detect(struct psmouse *psmouse, bool set_properties)
     254                 :            : {
     255         [ -  + ]:         21 :         if (!lifebook_present)
     256                 :            :                 return -ENXIO;
     257                 :            : 
     258         [ #  # ]:          0 :         if (desired_serio_phys &&
     259         [ #  # ]:          0 :             strcmp(psmouse->ps2dev.serio->phys, desired_serio_phys))
     260                 :            :                 return -ENXIO;
     261                 :            : 
     262         [ #  # ]:          0 :         if (set_properties) {
     263                 :          0 :                 psmouse->vendor = "Fujitsu";
     264                 :          0 :                 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                 :          0 : int lifebook_init(struct psmouse *psmouse)
     312                 :            : {
     313                 :          0 :         struct input_dev *dev1 = psmouse->dev;
     314         [ #  # ]:          0 :         int max_coord = lifebook_use_6byte_proto ? 4096 : 1024;
     315                 :          0 :         int error;
     316                 :            : 
     317                 :          0 :         error = lifebook_absolute_mode(psmouse);
     318         [ #  # ]:          0 :         if (error)
     319                 :            :                 return error;
     320                 :            : 
     321                 :            :         /* Clear default capabilities */
     322                 :          0 :         bitmap_zero(dev1->evbit, EV_CNT);
     323                 :          0 :         bitmap_zero(dev1->relbit, REL_CNT);
     324                 :          0 :         bitmap_zero(dev1->keybit, KEY_CNT);
     325                 :            : 
     326                 :          0 :         input_set_capability(dev1, EV_KEY, BTN_TOUCH);
     327                 :          0 :         input_set_abs_params(dev1, ABS_X, 0, max_coord, 0, 0);
     328                 :          0 :         input_set_abs_params(dev1, ABS_Y, 0, max_coord, 0, 0);
     329                 :            : 
     330         [ #  # ]:          0 :         if (!desired_serio_phys) {
     331                 :          0 :                 error = lifebook_create_relative_device(psmouse);
     332         [ #  # ]:          0 :                 if (error) {
     333                 :          0 :                         lifebook_relative_mode(psmouse);
     334                 :          0 :                         return error;
     335                 :            :                 }
     336                 :            :         }
     337                 :            : 
     338                 :          0 :         psmouse->protocol_handler = lifebook_process_byte;
     339                 :          0 :         psmouse->set_resolution = lifebook_set_resolution;
     340                 :          0 :         psmouse->disconnect = lifebook_disconnect;
     341                 :          0 :         psmouse->reconnect  = lifebook_absolute_mode;
     342                 :            : 
     343         [ #  # ]:          0 :         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                 :          0 :         psmouse->pktsize = 3;
     350                 :            : 
     351                 :          0 :         return 0;
     352                 :            : }
     353                 :            : 

Generated by: LCOV version 1.14