linux/drivers/input/mouse/sentelic.c
<<
>>
Prefs
   1/*-
   2 * Finger Sensing Pad PS/2 mouse driver.
   3 *
   4 * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd.
   5 * Copyright (C) 2005-2009 Tai-hwa Liang, Sentelic Corporation.
   6 *
   7 *   This program is free software; you can redistribute it and/or
   8 *   modify it under the terms of the GNU General Public License
   9 *   as published by the Free Software Foundation; either version 2
  10 *   of the License, or (at your option) any later version.
  11 *
  12 *   This program is distributed in the hope that it will be useful,
  13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 *   GNU General Public License for more details.
  16 *
  17 *   You should have received a copy of the GNU General Public License
  18 *   along with this program; if not, write to the Free Software
  19 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20 */
  21
  22#include <linux/module.h>
  23#include <linux/version.h>
  24#include <linux/input.h>
  25#include <linux/ctype.h>
  26#include <linux/libps2.h>
  27#include <linux/serio.h>
  28#include <linux/jiffies.h>
  29
  30#include "psmouse.h"
  31#include "sentelic.h"
  32
  33/*
  34 * Timeout for FSP PS/2 command only (in milliseconds).
  35 */
  36#define FSP_CMD_TIMEOUT         200
  37#define FSP_CMD_TIMEOUT2        30
  38
  39/** Driver version. */
  40static const char fsp_drv_ver[] = "1.0.0-K";
  41
  42/*
  43 * Make sure that the value being sent to FSP will not conflict with
  44 * possible sample rate values.
  45 */
  46static unsigned char fsp_test_swap_cmd(unsigned char reg_val)
  47{
  48        switch (reg_val) {
  49        case 10: case 20: case 40: case 60: case 80: case 100: case 200:
  50                /*
  51                 * The requested value being sent to FSP matched to possible
  52                 * sample rates, swap the given value such that the hardware
  53                 * wouldn't get confused.
  54                 */
  55                return (reg_val >> 4) | (reg_val << 4);
  56        default:
  57                return reg_val; /* swap isn't necessary */
  58        }
  59}
  60
  61/*
  62 * Make sure that the value being sent to FSP will not conflict with certain
  63 * commands.
  64 */
  65static unsigned char fsp_test_invert_cmd(unsigned char reg_val)
  66{
  67        switch (reg_val) {
  68        case 0xe9: case 0xee: case 0xf2: case 0xff:
  69                /*
  70                 * The requested value being sent to FSP matched to certain
  71                 * commands, inverse the given value such that the hardware
  72                 * wouldn't get confused.
  73                 */
  74                return ~reg_val;
  75        default:
  76                return reg_val; /* inversion isn't necessary */
  77        }
  78}
  79
  80static int fsp_reg_read(struct psmouse *psmouse, int reg_addr, int *reg_val)
  81{
  82        struct ps2dev *ps2dev = &psmouse->ps2dev;
  83        unsigned char param[3];
  84        unsigned char addr;
  85        int rc = -1;
  86
  87        /*
  88         * We need to shut off the device and switch it into command
  89         * mode so we don't confuse our protocol handler. We don't need
  90         * to do that for writes because sysfs set helper does this for
  91         * us.
  92         */
  93        ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE);
  94        psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
  95
  96        ps2_begin_command(ps2dev);
  97
  98        if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
  99                goto out;
 100
 101        /* should return 0xfe(request for resending) */
 102        ps2_sendbyte(ps2dev, 0x66, FSP_CMD_TIMEOUT2);
 103        /* should return 0xfc(failed) */
 104        ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2);
 105
 106        if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
 107                goto out;
 108
 109        if ((addr = fsp_test_invert_cmd(reg_addr)) != reg_addr) {
 110                ps2_sendbyte(ps2dev, 0x68, FSP_CMD_TIMEOUT2);
 111        } else if ((addr = fsp_test_swap_cmd(reg_addr)) != reg_addr) {
 112                /* swapping is required */
 113                ps2_sendbyte(ps2dev, 0xcc, FSP_CMD_TIMEOUT2);
 114                /* expect 0xfe */
 115        } else {
 116                /* swapping isn't necessary */
 117                ps2_sendbyte(ps2dev, 0x66, FSP_CMD_TIMEOUT2);
 118                /* expect 0xfe */
 119        }
 120        /* should return 0xfc(failed) */
 121        ps2_sendbyte(ps2dev, addr, FSP_CMD_TIMEOUT);
 122
 123        if (__ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO) < 0)
 124                goto out;
 125
 126        *reg_val = param[2];
 127        rc = 0;
 128
 129 out:
 130        ps2_end_command(ps2dev);
 131        ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
 132        psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
 133        dev_dbg(&ps2dev->serio->dev, "READ REG: 0x%02x is 0x%02x (rc = %d)\n",
 134                reg_addr, *reg_val, rc);
 135        return rc;
 136}
 137
 138static int fsp_reg_write(struct psmouse *psmouse, int reg_addr, int reg_val)
 139{
 140        struct ps2dev *ps2dev = &psmouse->ps2dev;
 141        unsigned char v;
 142        int rc = -1;
 143
 144        ps2_begin_command(ps2dev);
 145
 146        if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
 147                goto out;
 148
 149        if ((v = fsp_test_invert_cmd(reg_addr)) != reg_addr) {
 150                /* inversion is required */
 151                ps2_sendbyte(ps2dev, 0x74, FSP_CMD_TIMEOUT2);
 152        } else {
 153                if ((v = fsp_test_swap_cmd(reg_addr)) != reg_addr) {
 154                        /* swapping is required */
 155                        ps2_sendbyte(ps2dev, 0x77, FSP_CMD_TIMEOUT2);
 156                } else {
 157                        /* swapping isn't necessary */
 158                        ps2_sendbyte(ps2dev, 0x55, FSP_CMD_TIMEOUT2);
 159                }
 160        }
 161        /* write the register address in correct order */
 162        ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2);
 163
 164        if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
 165                return -1;
 166
 167        if ((v = fsp_test_invert_cmd(reg_val)) != reg_val) {
 168                /* inversion is required */
 169                ps2_sendbyte(ps2dev, 0x47, FSP_CMD_TIMEOUT2);
 170        } else if ((v = fsp_test_swap_cmd(reg_val)) != reg_val) {
 171                /* swapping is required */
 172                ps2_sendbyte(ps2dev, 0x44, FSP_CMD_TIMEOUT2);
 173        } else {
 174                /* swapping isn't necessary */
 175                ps2_sendbyte(ps2dev, 0x33, FSP_CMD_TIMEOUT2);
 176        }
 177
 178        /* write the register value in correct order */
 179        ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2);
 180        rc = 0;
 181
 182 out:
 183        ps2_end_command(ps2dev);
 184        dev_dbg(&ps2dev->serio->dev, "WRITE REG: 0x%02x to 0x%02x (rc = %d)\n",
 185                reg_addr, reg_val, rc);
 186        return rc;
 187}
 188
 189/* Enable register clock gating for writing certain registers */
 190static int fsp_reg_write_enable(struct psmouse *psmouse, bool enable)
 191{
 192        int v, nv;
 193
 194        if (fsp_reg_read(psmouse, FSP_REG_SYSCTL1, &v) == -1)
 195                return -1;
 196
 197        if (enable)
 198                nv = v | FSP_BIT_EN_REG_CLK;
 199        else
 200                nv = v & ~FSP_BIT_EN_REG_CLK;
 201
 202        /* only write if necessary */
 203        if (nv != v)
 204                if (fsp_reg_write(psmouse, FSP_REG_SYSCTL1, nv) == -1)
 205                        return -1;
 206
 207        return 0;
 208}
 209
 210static int fsp_page_reg_read(struct psmouse *psmouse, int *reg_val)
 211{
 212        struct ps2dev *ps2dev = &psmouse->ps2dev;
 213        unsigned char param[3];
 214        int rc = -1;
 215
 216        ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE);
 217        psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
 218
 219        ps2_begin_command(ps2dev);
 220
 221        if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
 222                goto out;
 223
 224        ps2_sendbyte(ps2dev, 0x66, FSP_CMD_TIMEOUT2);
 225        ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2);
 226
 227        if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
 228                goto out;
 229
 230        ps2_sendbyte(ps2dev, 0x83, FSP_CMD_TIMEOUT2);
 231        ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2);
 232
 233        /* get the returned result */
 234        if (__ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
 235                goto out;
 236
 237        *reg_val = param[2];
 238        rc = 0;
 239
 240 out:
 241        ps2_end_command(ps2dev);
 242        ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
 243        psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
 244        dev_dbg(&ps2dev->serio->dev, "READ PAGE REG: 0x%02x (rc = %d)\n",
 245                *reg_val, rc);
 246        return rc;
 247}
 248
 249static int fsp_page_reg_write(struct psmouse *psmouse, int reg_val)
 250{
 251        struct ps2dev *ps2dev = &psmouse->ps2dev;
 252        unsigned char v;
 253        int rc = -1;
 254
 255        ps2_begin_command(ps2dev);
 256
 257        if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
 258                goto out;
 259
 260        ps2_sendbyte(ps2dev, 0x38, FSP_CMD_TIMEOUT2);
 261        ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2);
 262
 263        if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
 264                return -1;
 265
 266        if ((v = fsp_test_invert_cmd(reg_val)) != reg_val) {
 267                ps2_sendbyte(ps2dev, 0x47, FSP_CMD_TIMEOUT2);
 268        } else if ((v = fsp_test_swap_cmd(reg_val)) != reg_val) {
 269                /* swapping is required */
 270                ps2_sendbyte(ps2dev, 0x44, FSP_CMD_TIMEOUT2);
 271        } else {
 272                /* swapping isn't necessary */
 273                ps2_sendbyte(ps2dev, 0x33, FSP_CMD_TIMEOUT2);
 274        }
 275
 276        ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2);
 277        rc = 0;
 278
 279 out:
 280        ps2_end_command(ps2dev);
 281        dev_dbg(&ps2dev->serio->dev, "WRITE PAGE REG: to 0x%02x (rc = %d)\n",
 282                reg_val, rc);
 283        return rc;
 284}
 285
 286static int fsp_get_version(struct psmouse *psmouse, int *version)
 287{
 288        if (fsp_reg_read(psmouse, FSP_REG_VERSION, version))
 289                return -EIO;
 290
 291        return 0;
 292}
 293
 294static int fsp_get_revision(struct psmouse *psmouse, int *rev)
 295{
 296        if (fsp_reg_read(psmouse, FSP_REG_REVISION, rev))
 297                return -EIO;
 298
 299        return 0;
 300}
 301
 302static int fsp_get_buttons(struct psmouse *psmouse, int *btn)
 303{
 304        static const int buttons[] = {
 305                0x16, /* Left/Middle/Right/Forward/Backward & Scroll Up/Down */
 306                0x06, /* Left/Middle/Right & Scroll Up/Down/Right/Left */
 307                0x04, /* Left/Middle/Right & Scroll Up/Down */
 308                0x02, /* Left/Middle/Right */
 309        };
 310        int val;
 311
 312        if (fsp_reg_read(psmouse, FSP_REG_TMOD_STATUS1, &val) == -1)
 313                return -EIO;
 314
 315        *btn = buttons[(val & 0x30) >> 4];
 316        return 0;
 317}
 318
 319/* Enable on-pad command tag output */
 320static int fsp_opc_tag_enable(struct psmouse *psmouse, bool enable)
 321{
 322        int v, nv;
 323        int res = 0;
 324
 325        if (fsp_reg_read(psmouse, FSP_REG_OPC_QDOWN, &v) == -1) {
 326                dev_err(&psmouse->ps2dev.serio->dev, "Unable get OPC state.\n");
 327                return -EIO;
 328        }
 329
 330        if (enable)
 331                nv = v | FSP_BIT_EN_OPC_TAG;
 332        else
 333                nv = v & ~FSP_BIT_EN_OPC_TAG;
 334
 335        /* only write if necessary */
 336        if (nv != v) {
 337                fsp_reg_write_enable(psmouse, true);
 338                res = fsp_reg_write(psmouse, FSP_REG_OPC_QDOWN, nv);
 339                fsp_reg_write_enable(psmouse, false);
 340        }
 341
 342        if (res != 0) {
 343                dev_err(&psmouse->ps2dev.serio->dev,
 344                        "Unable to enable OPC tag.\n");
 345                res = -EIO;
 346        }
 347
 348        return res;
 349}
 350
 351static int fsp_onpad_vscr(struct psmouse *psmouse, bool enable)
 352{
 353        struct fsp_data *pad = psmouse->private;
 354        int val;
 355
 356        if (fsp_reg_read(psmouse, FSP_REG_ONPAD_CTL, &val))
 357                return -EIO;
 358
 359        pad->vscroll = enable;
 360
 361        if (enable)
 362                val |= (FSP_BIT_FIX_VSCR | FSP_BIT_ONPAD_ENABLE);
 363        else
 364                val &= ~FSP_BIT_FIX_VSCR;
 365
 366        if (fsp_reg_write(psmouse, FSP_REG_ONPAD_CTL, val))
 367                return -EIO;
 368
 369        return 0;
 370}
 371
 372static int fsp_onpad_hscr(struct psmouse *psmouse, bool enable)
 373{
 374        struct fsp_data *pad = psmouse->private;
 375        int val, v2;
 376
 377        if (fsp_reg_read(psmouse, FSP_REG_ONPAD_CTL, &val))
 378                return -EIO;
 379
 380        if (fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &v2))
 381                return -EIO;
 382
 383        pad->hscroll = enable;
 384
 385        if (enable) {
 386                val |= (FSP_BIT_FIX_HSCR | FSP_BIT_ONPAD_ENABLE);
 387                v2 |= FSP_BIT_EN_MSID6;
 388        } else {
 389                val &= ~FSP_BIT_FIX_HSCR;
 390                v2 &= ~(FSP_BIT_EN_MSID6 | FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8);
 391        }
 392
 393        if (fsp_reg_write(psmouse, FSP_REG_ONPAD_CTL, val))
 394                return -EIO;
 395
 396        /* reconfigure horizontal scrolling packet output */
 397        if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, v2))
 398                return -EIO;
 399
 400        return 0;
 401}
 402
 403/*
 404 * Write device specific initial parameters.
 405 *
 406 * ex: 0xab 0xcd - write oxcd into register 0xab
 407 */
 408static ssize_t fsp_attr_set_setreg(struct psmouse *psmouse, void *data,
 409                                   const char *buf, size_t count)
 410{
 411        unsigned long reg, val;
 412        char *rest;
 413        ssize_t retval;
 414
 415        reg = simple_strtoul(buf, &rest, 16);
 416        if (rest == buf || *rest != ' ' || reg > 0xff)
 417                return -EINVAL;
 418
 419        if (strict_strtoul(rest + 1, 16, &val) || val > 0xff)
 420                return -EINVAL;
 421
 422        if (fsp_reg_write_enable(psmouse, true))
 423                return -EIO;
 424
 425        retval = fsp_reg_write(psmouse, reg, val) < 0 ? -EIO : count;
 426
 427        fsp_reg_write_enable(psmouse, false);
 428
 429        return count;
 430}
 431
 432PSMOUSE_DEFINE_WO_ATTR(setreg, S_IWUSR, NULL, fsp_attr_set_setreg);
 433
 434static ssize_t fsp_attr_show_getreg(struct psmouse *psmouse,
 435                                        void *data, char *buf)
 436{
 437        struct fsp_data *pad = psmouse->private;
 438
 439        return sprintf(buf, "%02x%02x\n", pad->last_reg, pad->last_val);
 440}
 441
 442/*
 443 * Read a register from device.
 444 *
 445 * ex: 0xab -- read content from register 0xab
 446 */
 447static ssize_t fsp_attr_set_getreg(struct psmouse *psmouse, void *data,
 448                                        const char *buf, size_t count)
 449{
 450        struct fsp_data *pad = psmouse->private;
 451        unsigned long reg;
 452        int val;
 453
 454        if (strict_strtoul(buf, 16, &reg) || reg > 0xff)
 455                return -EINVAL;
 456
 457        if (fsp_reg_read(psmouse, reg, &val))
 458                return -EIO;
 459
 460        pad->last_reg = reg;
 461        pad->last_val = val;
 462
 463        return count;
 464}
 465
 466PSMOUSE_DEFINE_ATTR(getreg, S_IWUSR | S_IRUGO, NULL,
 467                        fsp_attr_show_getreg, fsp_attr_set_getreg);
 468
 469static ssize_t fsp_attr_show_pagereg(struct psmouse *psmouse,
 470                                        void *data, char *buf)
 471{
 472        int val = 0;
 473
 474        if (fsp_page_reg_read(psmouse, &val))
 475                return -EIO;
 476
 477        return sprintf(buf, "%02x\n", val);
 478}
 479
 480static ssize_t fsp_attr_set_pagereg(struct psmouse *psmouse, void *data,
 481                                        const char *buf, size_t count)
 482{
 483        unsigned long val;
 484
 485        if (strict_strtoul(buf, 16, &val) || val > 0xff)
 486                return -EINVAL;
 487
 488        if (fsp_page_reg_write(psmouse, val))
 489                return -EIO;
 490
 491        return count;
 492}
 493
 494PSMOUSE_DEFINE_ATTR(page, S_IWUSR | S_IRUGO, NULL,
 495                        fsp_attr_show_pagereg, fsp_attr_set_pagereg);
 496
 497static ssize_t fsp_attr_show_vscroll(struct psmouse *psmouse,
 498                                        void *data, char *buf)
 499{
 500        struct fsp_data *pad = psmouse->private;
 501
 502        return sprintf(buf, "%d\n", pad->vscroll);
 503}
 504
 505static ssize_t fsp_attr_set_vscroll(struct psmouse *psmouse, void *data,
 506                                        const char *buf, size_t count)
 507{
 508        unsigned long val;
 509
 510        if (strict_strtoul(buf, 10, &val) || val > 1)
 511                return -EINVAL;
 512
 513        fsp_onpad_vscr(psmouse, val);
 514
 515        return count;
 516}
 517
 518PSMOUSE_DEFINE_ATTR(vscroll, S_IWUSR | S_IRUGO, NULL,
 519                        fsp_attr_show_vscroll, fsp_attr_set_vscroll);
 520
 521static ssize_t fsp_attr_show_hscroll(struct psmouse *psmouse,
 522                                        void *data, char *buf)
 523{
 524        struct fsp_data *pad = psmouse->private;
 525
 526        return sprintf(buf, "%d\n", pad->hscroll);
 527}
 528
 529static ssize_t fsp_attr_set_hscroll(struct psmouse *psmouse, void *data,
 530                                        const char *buf, size_t count)
 531{
 532        unsigned long val;
 533
 534        if (strict_strtoul(buf, 10, &val) || val > 1)
 535                return -EINVAL;
 536
 537        fsp_onpad_hscr(psmouse, val);
 538
 539        return count;
 540}
 541
 542PSMOUSE_DEFINE_ATTR(hscroll, S_IWUSR | S_IRUGO, NULL,
 543                        fsp_attr_show_hscroll, fsp_attr_set_hscroll);
 544
 545static ssize_t fsp_attr_show_flags(struct psmouse *psmouse,
 546                                        void *data, char *buf)
 547{
 548        struct fsp_data *pad = psmouse->private;
 549
 550        return sprintf(buf, "%c\n",
 551                        pad->flags & FSPDRV_FLAG_EN_OPC ? 'C' : 'c');
 552}
 553
 554static ssize_t fsp_attr_set_flags(struct psmouse *psmouse, void *data,
 555                                        const char *buf, size_t count)
 556{
 557        struct fsp_data *pad = psmouse->private;
 558        size_t i;
 559
 560        for (i = 0; i < count; i++) {
 561                switch (buf[i]) {
 562                case 'C':
 563                        pad->flags |= FSPDRV_FLAG_EN_OPC;
 564                        break;
 565                case 'c':
 566                        pad->flags &= ~FSPDRV_FLAG_EN_OPC;
 567                        break;
 568                default:
 569                        return -EINVAL;
 570                }
 571        }
 572        return count;
 573}
 574
 575PSMOUSE_DEFINE_ATTR(flags, S_IWUSR | S_IRUGO, NULL,
 576                        fsp_attr_show_flags, fsp_attr_set_flags);
 577
 578static ssize_t fsp_attr_show_ver(struct psmouse *psmouse,
 579                                        void *data, char *buf)
 580{
 581        return sprintf(buf, "Sentelic FSP kernel module %s\n", fsp_drv_ver);
 582}
 583
 584PSMOUSE_DEFINE_RO_ATTR(ver, S_IRUGO, NULL, fsp_attr_show_ver);
 585
 586static struct attribute *fsp_attributes[] = {
 587        &psmouse_attr_setreg.dattr.attr,
 588        &psmouse_attr_getreg.dattr.attr,
 589        &psmouse_attr_page.dattr.attr,
 590        &psmouse_attr_vscroll.dattr.attr,
 591        &psmouse_attr_hscroll.dattr.attr,
 592        &psmouse_attr_flags.dattr.attr,
 593        &psmouse_attr_ver.dattr.attr,
 594        NULL
 595};
 596
 597static struct attribute_group fsp_attribute_group = {
 598        .attrs = fsp_attributes,
 599};
 600
 601#ifdef FSP_DEBUG
 602static void fsp_packet_debug(unsigned char packet[])
 603{
 604        static unsigned int ps2_packet_cnt;
 605        static unsigned int ps2_last_second;
 606        unsigned int jiffies_msec;
 607
 608        ps2_packet_cnt++;
 609        jiffies_msec = jiffies_to_msecs(jiffies);
 610        printk(KERN_DEBUG "%08dms PS/2 packets: %02x, %02x, %02x, %02x\n",
 611                jiffies_msec, packet[0], packet[1], packet[2], packet[3]);
 612
 613        if (jiffies_msec - ps2_last_second > 1000) {
 614                printk(KERN_DEBUG "PS/2 packets/sec = %d\n", ps2_packet_cnt);
 615                ps2_packet_cnt = 0;
 616                ps2_last_second = jiffies_msec;
 617        }
 618}
 619#else
 620static void fsp_packet_debug(unsigned char packet[])
 621{
 622}
 623#endif
 624
 625static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
 626{
 627        struct input_dev *dev = psmouse->dev;
 628        struct fsp_data *ad = psmouse->private;
 629        unsigned char *packet = psmouse->packet;
 630        unsigned char button_status = 0, lscroll = 0, rscroll = 0;
 631        int rel_x, rel_y;
 632
 633        if (psmouse->pktcnt < 4)
 634                return PSMOUSE_GOOD_DATA;
 635
 636        /*
 637         * Full packet accumulated, process it
 638         */
 639
 640        switch (psmouse->packet[0] >> FSP_PKT_TYPE_SHIFT) {
 641        case FSP_PKT_TYPE_ABS:
 642                dev_warn(&psmouse->ps2dev.serio->dev,
 643                         "Unexpected absolute mode packet, ignored.\n");
 644                break;
 645
 646        case FSP_PKT_TYPE_NORMAL_OPC:
 647                /* on-pad click, filter it if necessary */
 648                if ((ad->flags & FSPDRV_FLAG_EN_OPC) != FSPDRV_FLAG_EN_OPC)
 649                        packet[0] &= ~BIT(0);
 650                /* fall through */
 651
 652        case FSP_PKT_TYPE_NORMAL:
 653                /* normal packet */
 654                /* special packet data translation from on-pad packets */
 655                if (packet[3] != 0) {
 656                        if (packet[3] & BIT(0))
 657                                button_status |= 0x01;  /* wheel down */
 658                        if (packet[3] & BIT(1))
 659                                button_status |= 0x0f;  /* wheel up */
 660                        if (packet[3] & BIT(2))
 661                                button_status |= BIT(5);/* horizontal left */
 662                        if (packet[3] & BIT(3))
 663                                button_status |= BIT(4);/* horizontal right */
 664                        /* push back to packet queue */
 665                        if (button_status != 0)
 666                                packet[3] = button_status;
 667                        rscroll = (packet[3] >> 4) & 1;
 668                        lscroll = (packet[3] >> 5) & 1;
 669                }
 670                /*
 671                 * Processing wheel up/down and extra button events
 672                 */
 673                input_report_rel(dev, REL_WHEEL,
 674                                 (int)(packet[3] & 8) - (int)(packet[3] & 7));
 675                input_report_rel(dev, REL_HWHEEL, lscroll - rscroll);
 676                input_report_key(dev, BTN_BACK, lscroll);
 677                input_report_key(dev, BTN_FORWARD, rscroll);
 678
 679                /*
 680                 * Standard PS/2 Mouse
 681                 */
 682                input_report_key(dev, BTN_LEFT, packet[0] & 1);
 683                input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1);
 684                input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1);
 685
 686                rel_x = packet[1] ? (int)packet[1] - (int)((packet[0] << 4) & 0x100) : 0;
 687                rel_y = packet[2] ? (int)((packet[0] << 3) & 0x100) - (int)packet[2] : 0;
 688
 689                input_report_rel(dev, REL_X, rel_x);
 690                input_report_rel(dev, REL_Y, rel_y);
 691                break;
 692        }
 693
 694        input_sync(dev);
 695
 696        fsp_packet_debug(packet);
 697
 698        return PSMOUSE_FULL_PACKET;
 699}
 700
 701static int fsp_activate_protocol(struct psmouse *psmouse)
 702{
 703        struct fsp_data *pad = psmouse->private;
 704        struct ps2dev *ps2dev = &psmouse->ps2dev;
 705        unsigned char param[2];
 706        int val;
 707
 708        /*
 709         * Standard procedure to enter FSP Intellimouse mode
 710         * (scrolling wheel, 4th and 5th buttons)
 711         */
 712        param[0] = 200;
 713        ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
 714        param[0] = 200;
 715        ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
 716        param[0] =  80;
 717        ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
 718
 719        ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
 720        if (param[0] != 0x04) {
 721                dev_err(&psmouse->ps2dev.serio->dev,
 722                        "Unable to enable 4 bytes packet format.\n");
 723                return -EIO;
 724        }
 725
 726        if (fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &val)) {
 727                dev_err(&psmouse->ps2dev.serio->dev,
 728                        "Unable to read SYSCTL5 register.\n");
 729                return -EIO;
 730        }
 731
 732        val &= ~(FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8 | FSP_BIT_EN_AUTO_MSID8);
 733        /* Ensure we are not in absolute mode */
 734        val &= ~FSP_BIT_EN_PKT_G0;
 735        if (pad->buttons == 0x06) {
 736                /* Left/Middle/Right & Scroll Up/Down/Right/Left */
 737                val |= FSP_BIT_EN_MSID6;
 738        }
 739
 740        if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, val)) {
 741                dev_err(&psmouse->ps2dev.serio->dev,
 742                        "Unable to set up required mode bits.\n");
 743                return -EIO;
 744        }
 745
 746        /*
 747         * Enable OPC tags such that driver can tell the difference between
 748         * on-pad and real button click
 749         */
 750        if (fsp_opc_tag_enable(psmouse, true))
 751                dev_warn(&psmouse->ps2dev.serio->dev,
 752                         "Failed to enable OPC tag mode.\n");
 753
 754        /* Enable on-pad vertical and horizontal scrolling */
 755        fsp_onpad_vscr(psmouse, true);
 756        fsp_onpad_hscr(psmouse, true);
 757
 758        return 0;
 759}
 760
 761int fsp_detect(struct psmouse *psmouse, bool set_properties)
 762{
 763        int id;
 764
 765        if (fsp_reg_read(psmouse, FSP_REG_DEVICE_ID, &id))
 766                return -EIO;
 767
 768        if (id != 0x01)
 769                return -ENODEV;
 770
 771        if (set_properties) {
 772                psmouse->vendor = "Sentelic";
 773                psmouse->name = "FingerSensingPad";
 774        }
 775
 776        return 0;
 777}
 778
 779static void fsp_reset(struct psmouse *psmouse)
 780{
 781        fsp_opc_tag_enable(psmouse, false);
 782        fsp_onpad_vscr(psmouse, false);
 783        fsp_onpad_hscr(psmouse, false);
 784}
 785
 786static void fsp_disconnect(struct psmouse *psmouse)
 787{
 788        sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj,
 789                           &fsp_attribute_group);
 790
 791        fsp_reset(psmouse);
 792        kfree(psmouse->private);
 793}
 794
 795static int fsp_reconnect(struct psmouse *psmouse)
 796{
 797        int version;
 798
 799        if (fsp_detect(psmouse, 0))
 800                return -ENODEV;
 801
 802        if (fsp_get_version(psmouse, &version))
 803                return -ENODEV;
 804
 805        if (fsp_activate_protocol(psmouse))
 806                return -EIO;
 807
 808        return 0;
 809}
 810
 811int fsp_init(struct psmouse *psmouse)
 812{
 813        struct fsp_data *priv;
 814        int ver, rev, buttons;
 815        int error;
 816
 817        if (fsp_get_version(psmouse, &ver) ||
 818            fsp_get_revision(psmouse, &rev) ||
 819            fsp_get_buttons(psmouse, &buttons)) {
 820                return -ENODEV;
 821        }
 822
 823        printk(KERN_INFO
 824                "Finger Sensing Pad, hw: %d.%d.%d, sw: %s, buttons: %d\n",
 825                ver >> 4, ver & 0x0F, rev, fsp_drv_ver, buttons & 7);
 826
 827        psmouse->private = priv = kzalloc(sizeof(struct fsp_data), GFP_KERNEL);
 828        if (!priv)
 829                return -ENOMEM;
 830
 831        priv->ver = ver;
 832        priv->rev = rev;
 833        priv->buttons = buttons;
 834
 835        /* enable on-pad click by default */
 836        priv->flags |= FSPDRV_FLAG_EN_OPC;
 837
 838        /* Set up various supported input event bits */
 839        __set_bit(BTN_BACK, psmouse->dev->keybit);
 840        __set_bit(BTN_FORWARD, psmouse->dev->keybit);
 841        __set_bit(REL_WHEEL, psmouse->dev->relbit);
 842        __set_bit(REL_HWHEEL, psmouse->dev->relbit);
 843
 844        psmouse->protocol_handler = fsp_process_byte;
 845        psmouse->disconnect = fsp_disconnect;
 846        psmouse->reconnect = fsp_reconnect;
 847        psmouse->cleanup = fsp_reset;
 848        psmouse->pktsize = 4;
 849
 850        /* set default packet output based on number of buttons we found */
 851        error = fsp_activate_protocol(psmouse);
 852        if (error)
 853                goto err_out;
 854
 855        error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj,
 856                                   &fsp_attribute_group);
 857        if (error) {
 858                dev_err(&psmouse->ps2dev.serio->dev,
 859                        "Failed to create sysfs attributes (%d)", error);
 860                goto err_out;
 861        }
 862
 863        return 0;
 864
 865 err_out:
 866        kfree(psmouse->private);
 867        psmouse->private = NULL;
 868        return error;
 869}
 870