1fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang/*- 2fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * Finger Sensing Pad PS/2 mouse driver. 3fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * 4fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd. 5a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang * Copyright (C) 2005-2012 Tai-hwa Liang, Sentelic Corporation. 6fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * 7fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * This program is free software; you can redistribute it and/or 8fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * modify it under the terms of the GNU General Public License 9fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * as published by the Free Software Foundation; either version 2 10fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * of the License, or (at your option) any later version. 11fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * 12fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * This program is distributed in the hope that it will be useful, 13fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * but WITHOUT ANY WARRANTY; without even the implied warranty of 14fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * GNU General Public License for more details. 16fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * 17fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * You should have received a copy of the GNU General Public License 18fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * along with this program; if not, write to the Free Software 19fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang */ 21fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 22fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang#include <linux/module.h> 23fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang#include <linux/input.h> 24a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang#include <linux/input/mt.h> 25fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang#include <linux/ctype.h> 26fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang#include <linux/libps2.h> 27fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang#include <linux/serio.h> 28fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang#include <linux/jiffies.h> 295a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 30fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 31fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang#include "psmouse.h" 32fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang#include "sentelic.h" 33fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 34fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang/* 35fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * Timeout for FSP PS/2 command only (in milliseconds). 36fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang */ 37fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang#define FSP_CMD_TIMEOUT 200 38fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang#define FSP_CMD_TIMEOUT2 30 39fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 40727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa#define GET_ABS_X(packet) ((packet[1] << 2) | ((packet[3] >> 2) & 0x03)) 41727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa#define GET_ABS_Y(packet) ((packet[2] << 2) | (packet[3] & 0x03)) 42727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa 43fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang/** Driver version. */ 44fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic const char fsp_drv_ver[] = "1.0.0-K"; 45fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 46fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang/* 47fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * Make sure that the value being sent to FSP will not conflict with 48fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * possible sample rate values. 49fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang */ 50fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic unsigned char fsp_test_swap_cmd(unsigned char reg_val) 51fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 52fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang switch (reg_val) { 53fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang case 10: case 20: case 40: case 60: case 80: case 100: case 200: 54fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* 55fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * The requested value being sent to FSP matched to possible 56fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * sample rates, swap the given value such that the hardware 57fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * wouldn't get confused. 58fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang */ 59fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return (reg_val >> 4) | (reg_val << 4); 60fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang default: 61fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return reg_val; /* swap isn't necessary */ 62fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } 63fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 64fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 65fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang/* 66fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * Make sure that the value being sent to FSP will not conflict with certain 67fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * commands. 68fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang */ 69fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic unsigned char fsp_test_invert_cmd(unsigned char reg_val) 70fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 71fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang switch (reg_val) { 72fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang case 0xe9: case 0xee: case 0xf2: case 0xff: 73fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* 74fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * The requested value being sent to FSP matched to certain 75fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * commands, inverse the given value such that the hardware 76fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * wouldn't get confused. 77fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang */ 78fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return ~reg_val; 79fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang default: 80fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return reg_val; /* inversion isn't necessary */ 81fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } 82fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 83fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 84fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic int fsp_reg_read(struct psmouse *psmouse, int reg_addr, int *reg_val) 85fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 86fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang struct ps2dev *ps2dev = &psmouse->ps2dev; 87fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang unsigned char param[3]; 88fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang unsigned char addr; 89fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang int rc = -1; 90fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 91fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* 92fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * We need to shut off the device and switch it into command 93fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * mode so we don't confuse our protocol handler. We don't need 94fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * to do that for writes because sysfs set helper does this for 95fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * us. 96fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang */ 97c35c0e7d425c11f629d9d037df6c37a7ffebcd96Paul Fox psmouse_deactivate(psmouse); 98181d683d752c432635eda0f182ee71548c1f1820Dmitry Torokhov 99181d683d752c432635eda0f182ee71548c1f1820Dmitry Torokhov ps2_begin_command(ps2dev); 100fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 101fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) 102fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang goto out; 103fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 104fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* should return 0xfe(request for resending) */ 105fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_sendbyte(ps2dev, 0x66, FSP_CMD_TIMEOUT2); 106fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* should return 0xfc(failed) */ 107fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2); 108fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 109fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) 110fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang goto out; 111fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 112fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if ((addr = fsp_test_invert_cmd(reg_addr)) != reg_addr) { 113fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_sendbyte(ps2dev, 0x68, FSP_CMD_TIMEOUT2); 114fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } else if ((addr = fsp_test_swap_cmd(reg_addr)) != reg_addr) { 115fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* swapping is required */ 116fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_sendbyte(ps2dev, 0xcc, FSP_CMD_TIMEOUT2); 117fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* expect 0xfe */ 118fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } else { 119fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* swapping isn't necessary */ 120fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_sendbyte(ps2dev, 0x66, FSP_CMD_TIMEOUT2); 121fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* expect 0xfe */ 122fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } 123fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* should return 0xfc(failed) */ 124fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_sendbyte(ps2dev, addr, FSP_CMD_TIMEOUT); 125fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 126fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (__ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO) < 0) 127fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang goto out; 128fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 129fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang *reg_val = param[2]; 130fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang rc = 0; 131fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 132fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang out: 133181d683d752c432635eda0f182ee71548c1f1820Dmitry Torokhov ps2_end_command(ps2dev); 134c35c0e7d425c11f629d9d037df6c37a7ffebcd96Paul Fox psmouse_activate(psmouse); 1353ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang psmouse_dbg(psmouse, 1363ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang "READ REG: 0x%02x is 0x%02x (rc = %d)\n", 1373ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang reg_addr, *reg_val, rc); 138fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return rc; 139fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 140fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 141fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic int fsp_reg_write(struct psmouse *psmouse, int reg_addr, int reg_val) 142fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 143fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang struct ps2dev *ps2dev = &psmouse->ps2dev; 144fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang unsigned char v; 145fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang int rc = -1; 146fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 147181d683d752c432635eda0f182ee71548c1f1820Dmitry Torokhov ps2_begin_command(ps2dev); 148fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 149fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) 150fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang goto out; 151fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 152fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if ((v = fsp_test_invert_cmd(reg_addr)) != reg_addr) { 153fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* inversion is required */ 154fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_sendbyte(ps2dev, 0x74, FSP_CMD_TIMEOUT2); 155fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } else { 156fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if ((v = fsp_test_swap_cmd(reg_addr)) != reg_addr) { 157fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* swapping is required */ 158fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_sendbyte(ps2dev, 0x77, FSP_CMD_TIMEOUT2); 159fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } else { 160fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* swapping isn't necessary */ 161fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_sendbyte(ps2dev, 0x55, FSP_CMD_TIMEOUT2); 162fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } 163fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } 164fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* write the register address in correct order */ 165fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2); 166fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 167fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) 168d9bae67a7a91a6cc2e7a99d5ae72ada62abcc993Tai-hwa Liang goto out; 169fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 170fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if ((v = fsp_test_invert_cmd(reg_val)) != reg_val) { 171fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* inversion is required */ 172fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_sendbyte(ps2dev, 0x47, FSP_CMD_TIMEOUT2); 173fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } else if ((v = fsp_test_swap_cmd(reg_val)) != reg_val) { 174fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* swapping is required */ 175fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_sendbyte(ps2dev, 0x44, FSP_CMD_TIMEOUT2); 176fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } else { 177fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* swapping isn't necessary */ 178fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_sendbyte(ps2dev, 0x33, FSP_CMD_TIMEOUT2); 179fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } 180fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 181fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* write the register value in correct order */ 182fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2); 183fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang rc = 0; 184fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 185fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang out: 186181d683d752c432635eda0f182ee71548c1f1820Dmitry Torokhov ps2_end_command(ps2dev); 1873ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang psmouse_dbg(psmouse, 1883ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang "WRITE REG: 0x%02x to 0x%02x (rc = %d)\n", 1893ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang reg_addr, reg_val, rc); 190fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return rc; 191fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 192fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 193fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang/* Enable register clock gating for writing certain registers */ 194fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic int fsp_reg_write_enable(struct psmouse *psmouse, bool enable) 195fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 196fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang int v, nv; 197fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 198fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (fsp_reg_read(psmouse, FSP_REG_SYSCTL1, &v) == -1) 199fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -1; 200fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 201fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (enable) 202fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang nv = v | FSP_BIT_EN_REG_CLK; 203fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang else 204fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang nv = v & ~FSP_BIT_EN_REG_CLK; 205fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 206fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* only write if necessary */ 207fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (nv != v) 208fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (fsp_reg_write(psmouse, FSP_REG_SYSCTL1, nv) == -1) 209fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -1; 210fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 211fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return 0; 212fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 213fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 214fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic int fsp_page_reg_read(struct psmouse *psmouse, int *reg_val) 215fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 216fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang struct ps2dev *ps2dev = &psmouse->ps2dev; 217fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang unsigned char param[3]; 218fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang int rc = -1; 219fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 220c35c0e7d425c11f629d9d037df6c37a7ffebcd96Paul Fox psmouse_deactivate(psmouse); 221181d683d752c432635eda0f182ee71548c1f1820Dmitry Torokhov 222181d683d752c432635eda0f182ee71548c1f1820Dmitry Torokhov ps2_begin_command(ps2dev); 223fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 224fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) 225fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang goto out; 226fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 227fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_sendbyte(ps2dev, 0x66, FSP_CMD_TIMEOUT2); 228fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2); 229fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 230fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) 231fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang goto out; 232fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 233fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_sendbyte(ps2dev, 0x83, FSP_CMD_TIMEOUT2); 234fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2); 235fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 236fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* get the returned result */ 237fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (__ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) 238fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang goto out; 239fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 240fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang *reg_val = param[2]; 241fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang rc = 0; 242fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 243fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang out: 244181d683d752c432635eda0f182ee71548c1f1820Dmitry Torokhov ps2_end_command(ps2dev); 245c35c0e7d425c11f629d9d037df6c37a7ffebcd96Paul Fox psmouse_activate(psmouse); 2463ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang psmouse_dbg(psmouse, 2473ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang "READ PAGE REG: 0x%02x (rc = %d)\n", 2483ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang *reg_val, rc); 249fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return rc; 250fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 251fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 252fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic int fsp_page_reg_write(struct psmouse *psmouse, int reg_val) 253fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 254fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang struct ps2dev *ps2dev = &psmouse->ps2dev; 255fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang unsigned char v; 256fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang int rc = -1; 257fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 258181d683d752c432635eda0f182ee71548c1f1820Dmitry Torokhov ps2_begin_command(ps2dev); 259fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 260fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) 261fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang goto out; 262fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 263fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_sendbyte(ps2dev, 0x38, FSP_CMD_TIMEOUT2); 264fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2); 265fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 266fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) 267d9bae67a7a91a6cc2e7a99d5ae72ada62abcc993Tai-hwa Liang goto out; 268fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 269fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if ((v = fsp_test_invert_cmd(reg_val)) != reg_val) { 270fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_sendbyte(ps2dev, 0x47, FSP_CMD_TIMEOUT2); 271fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } else if ((v = fsp_test_swap_cmd(reg_val)) != reg_val) { 272fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* swapping is required */ 273fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_sendbyte(ps2dev, 0x44, FSP_CMD_TIMEOUT2); 274fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } else { 275fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* swapping isn't necessary */ 276fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_sendbyte(ps2dev, 0x33, FSP_CMD_TIMEOUT2); 277fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } 278fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 279fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2); 280fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang rc = 0; 281fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 282fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang out: 283181d683d752c432635eda0f182ee71548c1f1820Dmitry Torokhov ps2_end_command(ps2dev); 2843ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang psmouse_dbg(psmouse, 2853ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang "WRITE PAGE REG: to 0x%02x (rc = %d)\n", 2863ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang reg_val, rc); 287fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return rc; 288fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 289fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 290fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic int fsp_get_version(struct psmouse *psmouse, int *version) 291fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 292fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (fsp_reg_read(psmouse, FSP_REG_VERSION, version)) 293fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -EIO; 294fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 295fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return 0; 296fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 297fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 298fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic int fsp_get_revision(struct psmouse *psmouse, int *rev) 299fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 300fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (fsp_reg_read(psmouse, FSP_REG_REVISION, rev)) 301fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -EIO; 302fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 303fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return 0; 304fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 305fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 306fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic int fsp_get_buttons(struct psmouse *psmouse, int *btn) 307fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 308fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang static const int buttons[] = { 309fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 0x16, /* Left/Middle/Right/Forward/Backward & Scroll Up/Down */ 310fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 0x06, /* Left/Middle/Right & Scroll Up/Down/Right/Left */ 311fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 0x04, /* Left/Middle/Right & Scroll Up/Down */ 312fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 0x02, /* Left/Middle/Right */ 313fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang }; 314fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang int val; 315fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 3166ccbcf2cb41131f8d56ef0723bf3f7c1f8486076Tai-hwa Liang if (fsp_reg_read(psmouse, FSP_REG_TMOD_STATUS, &val) == -1) 317fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -EIO; 318fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 319fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang *btn = buttons[(val & 0x30) >> 4]; 320fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return 0; 321fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 322fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 323fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang/* Enable on-pad command tag output */ 324fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic int fsp_opc_tag_enable(struct psmouse *psmouse, bool enable) 325fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 326fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang int v, nv; 327fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang int res = 0; 328fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 329fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (fsp_reg_read(psmouse, FSP_REG_OPC_QDOWN, &v) == -1) { 3303ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang psmouse_err(psmouse, "Unable get OPC state.\n"); 331fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -EIO; 332fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } 333fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 334fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (enable) 335fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang nv = v | FSP_BIT_EN_OPC_TAG; 336fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang else 337fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang nv = v & ~FSP_BIT_EN_OPC_TAG; 338fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 339fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* only write if necessary */ 340fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (nv != v) { 341fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang fsp_reg_write_enable(psmouse, true); 342fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang res = fsp_reg_write(psmouse, FSP_REG_OPC_QDOWN, nv); 343fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang fsp_reg_write_enable(psmouse, false); 344fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } 345fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 346fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (res != 0) { 3473ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang psmouse_err(psmouse, "Unable to enable OPC tag.\n"); 348fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang res = -EIO; 349fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } 350fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 351fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return res; 352fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 353fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 354fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic int fsp_onpad_vscr(struct psmouse *psmouse, bool enable) 355fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 356fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang struct fsp_data *pad = psmouse->private; 357fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang int val; 358fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 359fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (fsp_reg_read(psmouse, FSP_REG_ONPAD_CTL, &val)) 360fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -EIO; 361fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 362fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang pad->vscroll = enable; 363fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 364fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (enable) 365fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang val |= (FSP_BIT_FIX_VSCR | FSP_BIT_ONPAD_ENABLE); 366fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang else 367fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang val &= ~FSP_BIT_FIX_VSCR; 368fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 369fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (fsp_reg_write(psmouse, FSP_REG_ONPAD_CTL, val)) 370fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -EIO; 371fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 372fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return 0; 373fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 374fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 375fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic int fsp_onpad_hscr(struct psmouse *psmouse, bool enable) 376fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 377fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang struct fsp_data *pad = psmouse->private; 378fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang int val, v2; 379fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 380fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (fsp_reg_read(psmouse, FSP_REG_ONPAD_CTL, &val)) 381fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -EIO; 382fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 383fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &v2)) 384fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -EIO; 385fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 386fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang pad->hscroll = enable; 387fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 388fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (enable) { 389fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang val |= (FSP_BIT_FIX_HSCR | FSP_BIT_ONPAD_ENABLE); 390fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang v2 |= FSP_BIT_EN_MSID6; 391fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } else { 392fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang val &= ~FSP_BIT_FIX_HSCR; 393fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang v2 &= ~(FSP_BIT_EN_MSID6 | FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8); 394fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } 395fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 396fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (fsp_reg_write(psmouse, FSP_REG_ONPAD_CTL, val)) 397fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -EIO; 398fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 399fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* reconfigure horizontal scrolling packet output */ 400fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, v2)) 401fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -EIO; 402fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 403fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return 0; 404fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 405fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 406fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang/* 407fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * Write device specific initial parameters. 408fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * 409fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * ex: 0xab 0xcd - write oxcd into register 0xab 410fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang */ 411fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic ssize_t fsp_attr_set_setreg(struct psmouse *psmouse, void *data, 412fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang const char *buf, size_t count) 413fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 41476496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding int reg, val; 415fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang char *rest; 416fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ssize_t retval; 417fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 418fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang reg = simple_strtoul(buf, &rest, 16); 419fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (rest == buf || *rest != ' ' || reg > 0xff) 420fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -EINVAL; 421fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 42276496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding retval = kstrtoint(rest + 1, 16, &val); 42376496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding if (retval) 42476496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding return retval; 42576496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding 42676496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding if (val > 0xff) 427fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -EINVAL; 428fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 429fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (fsp_reg_write_enable(psmouse, true)) 430fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -EIO; 431fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 432fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang retval = fsp_reg_write(psmouse, reg, val) < 0 ? -EIO : count; 433fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 434fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang fsp_reg_write_enable(psmouse, false); 435fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 436fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return count; 437fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 438fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 439fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa LiangPSMOUSE_DEFINE_WO_ATTR(setreg, S_IWUSR, NULL, fsp_attr_set_setreg); 440fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 441fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic ssize_t fsp_attr_show_getreg(struct psmouse *psmouse, 442fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang void *data, char *buf) 443fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 444fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang struct fsp_data *pad = psmouse->private; 445fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 446fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return sprintf(buf, "%02x%02x\n", pad->last_reg, pad->last_val); 447fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 448fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 449fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang/* 450fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * Read a register from device. 451fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * 452fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * ex: 0xab -- read content from register 0xab 453fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang */ 454fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic ssize_t fsp_attr_set_getreg(struct psmouse *psmouse, void *data, 455fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang const char *buf, size_t count) 456fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 457fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang struct fsp_data *pad = psmouse->private; 45876496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding int reg, val, err; 45976496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding 46076496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding err = kstrtoint(buf, 16, ®); 46176496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding if (err) 46276496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding return err; 463fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 46476496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding if (reg > 0xff) 465fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -EINVAL; 466fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 467fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (fsp_reg_read(psmouse, reg, &val)) 468fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -EIO; 469fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 470fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang pad->last_reg = reg; 471fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang pad->last_val = val; 472fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 473fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return count; 474fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 475fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 476fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa LiangPSMOUSE_DEFINE_ATTR(getreg, S_IWUSR | S_IRUGO, NULL, 477fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang fsp_attr_show_getreg, fsp_attr_set_getreg); 478fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 479fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic ssize_t fsp_attr_show_pagereg(struct psmouse *psmouse, 480fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang void *data, char *buf) 481fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 482fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang int val = 0; 483fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 484fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (fsp_page_reg_read(psmouse, &val)) 485fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -EIO; 486fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 487fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return sprintf(buf, "%02x\n", val); 488fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 489fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 490fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic ssize_t fsp_attr_set_pagereg(struct psmouse *psmouse, void *data, 491fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang const char *buf, size_t count) 492fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 49376496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding int val, err; 494fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 49576496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding err = kstrtoint(buf, 16, &val); 49676496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding if (err) 49776496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding return err; 49876496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding 49976496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding if (val > 0xff) 500fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -EINVAL; 501fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 502fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (fsp_page_reg_write(psmouse, val)) 503fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -EIO; 504fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 505fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return count; 506fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 507fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 508fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa LiangPSMOUSE_DEFINE_ATTR(page, S_IWUSR | S_IRUGO, NULL, 509fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang fsp_attr_show_pagereg, fsp_attr_set_pagereg); 510fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 511fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic ssize_t fsp_attr_show_vscroll(struct psmouse *psmouse, 512fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang void *data, char *buf) 513fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 514fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang struct fsp_data *pad = psmouse->private; 515fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 516fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return sprintf(buf, "%d\n", pad->vscroll); 517fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 518fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 519fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic ssize_t fsp_attr_set_vscroll(struct psmouse *psmouse, void *data, 520fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang const char *buf, size_t count) 521fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 52276496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding unsigned int val; 52376496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding int err; 52476496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding 52576496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding err = kstrtouint(buf, 10, &val); 52676496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding if (err) 52776496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding return err; 528fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 52976496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding if (val > 1) 530fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -EINVAL; 531fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 532fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang fsp_onpad_vscr(psmouse, val); 533fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 534fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return count; 535fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 536fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 537fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa LiangPSMOUSE_DEFINE_ATTR(vscroll, S_IWUSR | S_IRUGO, NULL, 538fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang fsp_attr_show_vscroll, fsp_attr_set_vscroll); 539fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 540fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic ssize_t fsp_attr_show_hscroll(struct psmouse *psmouse, 541fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang void *data, char *buf) 542fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 543fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang struct fsp_data *pad = psmouse->private; 544fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 545fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return sprintf(buf, "%d\n", pad->hscroll); 546fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 547fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 548fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic ssize_t fsp_attr_set_hscroll(struct psmouse *psmouse, void *data, 549fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang const char *buf, size_t count) 550fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 55176496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding unsigned int val; 55276496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding int err; 55376496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding 55476496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding err = kstrtouint(buf, 10, &val); 55576496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding if (err) 55676496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding return err; 557fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 55876496e7a02e99d42844f4fffa145b81e513e7acdJJ Ding if (val > 1) 559fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -EINVAL; 560fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 561fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang fsp_onpad_hscr(psmouse, val); 562fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 563fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return count; 564fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 565fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 566fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa LiangPSMOUSE_DEFINE_ATTR(hscroll, S_IWUSR | S_IRUGO, NULL, 567fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang fsp_attr_show_hscroll, fsp_attr_set_hscroll); 568fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 569fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic ssize_t fsp_attr_show_flags(struct psmouse *psmouse, 570fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang void *data, char *buf) 571fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 572fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang struct fsp_data *pad = psmouse->private; 573fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 574fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return sprintf(buf, "%c\n", 575fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang pad->flags & FSPDRV_FLAG_EN_OPC ? 'C' : 'c'); 576fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 577fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 578fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic ssize_t fsp_attr_set_flags(struct psmouse *psmouse, void *data, 579fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang const char *buf, size_t count) 580fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 581fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang struct fsp_data *pad = psmouse->private; 582fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang size_t i; 583fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 584fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang for (i = 0; i < count; i++) { 585fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang switch (buf[i]) { 586fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang case 'C': 587fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang pad->flags |= FSPDRV_FLAG_EN_OPC; 588fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang break; 589fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang case 'c': 590fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang pad->flags &= ~FSPDRV_FLAG_EN_OPC; 591fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang break; 592fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang default: 593fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -EINVAL; 594fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } 595fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } 596fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return count; 597fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 598fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 599fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa LiangPSMOUSE_DEFINE_ATTR(flags, S_IWUSR | S_IRUGO, NULL, 600fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang fsp_attr_show_flags, fsp_attr_set_flags); 601fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 602fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic ssize_t fsp_attr_show_ver(struct psmouse *psmouse, 603fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang void *data, char *buf) 604fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 605fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return sprintf(buf, "Sentelic FSP kernel module %s\n", fsp_drv_ver); 606fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 607fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 608fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa LiangPSMOUSE_DEFINE_RO_ATTR(ver, S_IRUGO, NULL, fsp_attr_show_ver); 609fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 610fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic struct attribute *fsp_attributes[] = { 611fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang &psmouse_attr_setreg.dattr.attr, 612fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang &psmouse_attr_getreg.dattr.attr, 613fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang &psmouse_attr_page.dattr.attr, 614fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang &psmouse_attr_vscroll.dattr.attr, 615fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang &psmouse_attr_hscroll.dattr.attr, 616fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang &psmouse_attr_flags.dattr.attr, 617fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang &psmouse_attr_ver.dattr.attr, 618fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang NULL 619fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang}; 620fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 621fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic struct attribute_group fsp_attribute_group = { 622fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang .attrs = fsp_attributes, 623fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang}; 624fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 625727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa#ifdef FSP_DEBUG 626727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaastatic void fsp_packet_debug(struct psmouse *psmouse, unsigned char packet[]) 627fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 628fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang static unsigned int ps2_packet_cnt; 629fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang static unsigned int ps2_last_second; 630fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang unsigned int jiffies_msec; 631727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa const char *packet_type = "UNKNOWN"; 632727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa unsigned short abs_x = 0, abs_y = 0; 633727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa 634727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa /* Interpret & dump the packet data. */ 635727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa switch (packet[0] >> FSP_PKT_TYPE_SHIFT) { 636727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa case FSP_PKT_TYPE_ABS: 637727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa packet_type = "Absolute"; 638727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa abs_x = GET_ABS_X(packet); 639727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa abs_y = GET_ABS_Y(packet); 640727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa break; 641727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa case FSP_PKT_TYPE_NORMAL: 642727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa packet_type = "Normal"; 643727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa break; 644727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa case FSP_PKT_TYPE_NOTIFY: 645727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa packet_type = "Notify"; 646727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa break; 647727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa case FSP_PKT_TYPE_NORMAL_OPC: 648727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa packet_type = "Normal-OPC"; 649727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa break; 650727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa } 651fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 652fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_packet_cnt++; 653fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang jiffies_msec = jiffies_to_msecs(jiffies); 654b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse_dbg(psmouse, 655727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa "%08dms %s packets: %02x, %02x, %02x, %02x; " 656727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa "abs_x: %d, abs_y: %d\n", 657727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa jiffies_msec, packet_type, 658727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa packet[0], packet[1], packet[2], packet[3], abs_x, abs_y); 659fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 660fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (jiffies_msec - ps2_last_second > 1000) { 661b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse_dbg(psmouse, "PS/2 packets/sec = %d\n", ps2_packet_cnt); 662fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_packet_cnt = 0; 663fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_last_second = jiffies_msec; 664fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } 665fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 666fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang#else 667727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaastatic void fsp_packet_debug(struct psmouse *psmouse, unsigned char packet[]) 668fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 669fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 670fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang#endif 671fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 672a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liangstatic void fsp_set_slot(struct input_dev *dev, int slot, bool active, 673a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang unsigned int x, unsigned int y) 674a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang{ 675a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang input_mt_slot(dev, slot); 676a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang input_mt_report_slot_state(dev, MT_TOOL_FINGER, active); 677a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang if (active) { 678a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang input_report_abs(dev, ABS_MT_POSITION_X, x); 679a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang input_report_abs(dev, ABS_MT_POSITION_Y, y); 680a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang } 681a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang} 682a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang 683fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic psmouse_ret_t fsp_process_byte(struct psmouse *psmouse) 684fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 685fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang struct input_dev *dev = psmouse->dev; 686fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang struct fsp_data *ad = psmouse->private; 687fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang unsigned char *packet = psmouse->packet; 688fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang unsigned char button_status = 0, lscroll = 0, rscroll = 0; 689a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang unsigned short abs_x, abs_y, fgrs = 0; 690fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang int rel_x, rel_y; 691fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 692fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (psmouse->pktcnt < 4) 693fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return PSMOUSE_GOOD_DATA; 694fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 695fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* 696fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * Full packet accumulated, process it 697fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang */ 698fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 699727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa fsp_packet_debug(psmouse, packet); 700727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa 701fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang switch (psmouse->packet[0] >> FSP_PKT_TYPE_SHIFT) { 702fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang case FSP_PKT_TYPE_ABS: 703727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa abs_x = GET_ABS_X(packet); 704727f9b480754dfcb82e36d431e85984893011b79Oskari Saarenmaa abs_y = GET_ABS_Y(packet); 705a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang 706a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang if (packet[0] & FSP_PB0_MFMC) { 707a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang /* 708a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang * MFMC packet: assume that there are two fingers on 709a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang * pad 710a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang */ 711a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang fgrs = 2; 712a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang 713a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang /* MFMC packet */ 714a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang if (packet[0] & FSP_PB0_MFMC_FGR2) { 715a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang /* 2nd finger */ 716a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang if (ad->last_mt_fgr == 2) { 717a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang /* 718a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang * workaround for buggy firmware 719a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang * which doesn't clear MFMC bit if 720a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang * the 1st finger is up 721a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang */ 722a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang fgrs = 1; 723a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang fsp_set_slot(dev, 0, false, 0, 0); 724a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang } 725a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang ad->last_mt_fgr = 2; 726a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang 727a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang fsp_set_slot(dev, 1, fgrs == 2, abs_x, abs_y); 728a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang } else { 729a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang /* 1st finger */ 730a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang if (ad->last_mt_fgr == 1) { 731a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang /* 732a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang * workaround for buggy firmware 733a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang * which doesn't clear MFMC bit if 734a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang * the 2nd finger is up 735a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang */ 736a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang fgrs = 1; 737a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang fsp_set_slot(dev, 1, false, 0, 0); 738a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang } 739a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang ad->last_mt_fgr = 1; 740a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang fsp_set_slot(dev, 0, fgrs != 0, abs_x, abs_y); 741a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang } 742a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang } else { 743a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang /* SFAC packet */ 744d626dad58f02e13730ded6ac84d6a9e53123f0e8Oskari Saarenmaa if ((packet[0] & (FSP_PB0_LBTN|FSP_PB0_PHY_BTN)) == 745d626dad58f02e13730ded6ac84d6a9e53123f0e8Oskari Saarenmaa FSP_PB0_LBTN) { 746d626dad58f02e13730ded6ac84d6a9e53123f0e8Oskari Saarenmaa /* On-pad click in SFAC mode should be handled 747d626dad58f02e13730ded6ac84d6a9e53123f0e8Oskari Saarenmaa * by userspace. On-pad clicks in MFMC mode 748d626dad58f02e13730ded6ac84d6a9e53123f0e8Oskari Saarenmaa * are real clickpad clicks, and not ignored. 749d626dad58f02e13730ded6ac84d6a9e53123f0e8Oskari Saarenmaa */ 750d626dad58f02e13730ded6ac84d6a9e53123f0e8Oskari Saarenmaa packet[0] &= ~FSP_PB0_LBTN; 751d626dad58f02e13730ded6ac84d6a9e53123f0e8Oskari Saarenmaa } 752a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang 753a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang /* no multi-finger information */ 754a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang ad->last_mt_fgr = 0; 755a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang 756a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang if (abs_x != 0 && abs_y != 0) 757a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang fgrs = 1; 758a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang 759a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang fsp_set_slot(dev, 0, fgrs > 0, abs_x, abs_y); 760a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang fsp_set_slot(dev, 1, false, 0, 0); 761a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang } 762a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang if (fgrs > 0) { 763a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang input_report_abs(dev, ABS_X, abs_x); 764a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang input_report_abs(dev, ABS_Y, abs_y); 765a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang } 766a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang input_report_key(dev, BTN_LEFT, packet[0] & 0x01); 767a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); 768a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang input_report_key(dev, BTN_TOUCH, fgrs); 769a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang input_report_key(dev, BTN_TOOL_FINGER, fgrs == 1); 770a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang input_report_key(dev, BTN_TOOL_DOUBLETAP, fgrs == 2); 771fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang break; 772fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 773fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang case FSP_PKT_TYPE_NORMAL_OPC: 774fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* on-pad click, filter it if necessary */ 775fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if ((ad->flags & FSPDRV_FLAG_EN_OPC) != FSPDRV_FLAG_EN_OPC) 7767b85f73d0461188aa397d428e6c53419ebfd86b4Tai-hwa Liang packet[0] &= ~FSP_PB0_LBTN; 777fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* fall through */ 778fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 779fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang case FSP_PKT_TYPE_NORMAL: 780fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* normal packet */ 781fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* special packet data translation from on-pad packets */ 782fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (packet[3] != 0) { 783fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (packet[3] & BIT(0)) 784fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang button_status |= 0x01; /* wheel down */ 785fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (packet[3] & BIT(1)) 786fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang button_status |= 0x0f; /* wheel up */ 787fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (packet[3] & BIT(2)) 788c332e9fcc5289698350d39d4d22c3ed5257d7a80Tai-hwa Liang button_status |= BIT(4);/* horizontal left */ 789fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (packet[3] & BIT(3)) 790c332e9fcc5289698350d39d4d22c3ed5257d7a80Tai-hwa Liang button_status |= BIT(5);/* horizontal right */ 791fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* push back to packet queue */ 792fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (button_status != 0) 793fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang packet[3] = button_status; 794fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang rscroll = (packet[3] >> 4) & 1; 795fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang lscroll = (packet[3] >> 5) & 1; 796fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } 797fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* 798fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * Processing wheel up/down and extra button events 799fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang */ 800fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang input_report_rel(dev, REL_WHEEL, 801fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang (int)(packet[3] & 8) - (int)(packet[3] & 7)); 802fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang input_report_rel(dev, REL_HWHEEL, lscroll - rscroll); 803fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang input_report_key(dev, BTN_BACK, lscroll); 804fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang input_report_key(dev, BTN_FORWARD, rscroll); 805fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 806fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* 807fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * Standard PS/2 Mouse 808fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang */ 809fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang input_report_key(dev, BTN_LEFT, packet[0] & 1); 810fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1); 811fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1); 812fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 813fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang rel_x = packet[1] ? (int)packet[1] - (int)((packet[0] << 4) & 0x100) : 0; 814fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang rel_y = packet[2] ? (int)((packet[0] << 3) & 0x100) - (int)packet[2] : 0; 815fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 816fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang input_report_rel(dev, REL_X, rel_x); 817fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang input_report_rel(dev, REL_Y, rel_y); 818fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang break; 819fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } 820fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 821fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang input_sync(dev); 822fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 823fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return PSMOUSE_FULL_PACKET; 824fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 825fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 826fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic int fsp_activate_protocol(struct psmouse *psmouse) 827fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 828fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang struct fsp_data *pad = psmouse->private; 829fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang struct ps2dev *ps2dev = &psmouse->ps2dev; 830fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang unsigned char param[2]; 831fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang int val; 832fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 833fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang /* 834fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * Standard procedure to enter FSP Intellimouse mode 835fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang * (scrolling wheel, 4th and 5th buttons) 836fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang */ 837fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang param[0] = 200; 838fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); 839fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang param[0] = 200; 840fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); 841fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang param[0] = 80; 842fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); 843fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 844fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang ps2_command(ps2dev, param, PSMOUSE_CMD_GETID); 845fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (param[0] != 0x04) { 8463ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang psmouse_err(psmouse, 8473ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang "Unable to enable 4 bytes packet format.\n"); 848fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -EIO; 849fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } 850fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 8513ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang if (pad->ver < FSP_VER_STL3888_C0) { 8523ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang /* Preparing relative coordinates output for older hardware */ 8533ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang if (fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &val)) { 8543ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang psmouse_err(psmouse, 8553ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang "Unable to read SYSCTL5 register.\n"); 8563ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang return -EIO; 8573ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang } 858fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 8593ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang if (fsp_get_buttons(psmouse, &pad->buttons)) { 8603ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang psmouse_err(psmouse, 8613ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang "Unable to retrieve number of buttons.\n"); 8623ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang return -EIO; 8633ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang } 864fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 8653ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang val &= ~(FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8 | FSP_BIT_EN_AUTO_MSID8); 8663ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang /* Ensure we are not in absolute mode */ 8673ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang val &= ~FSP_BIT_EN_PKT_G0; 8683ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang if (pad->buttons == 0x06) { 8693ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang /* Left/Middle/Right & Scroll Up/Down/Right/Left */ 8703ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang val |= FSP_BIT_EN_MSID6; 8713ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang } 8723ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang 8733ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, val)) { 8743ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang psmouse_err(psmouse, 8753ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang "Unable to set up required mode bits.\n"); 8763ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang return -EIO; 8773ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang } 8783ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang 8793ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang /* 8803ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang * Enable OPC tags such that driver can tell the difference 8813ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang * between on-pad and real button click 8823ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang */ 8833ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang if (fsp_opc_tag_enable(psmouse, true)) 8843ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang psmouse_warn(psmouse, 8853ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang "Failed to enable OPC tag mode.\n"); 8863ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang /* enable on-pad click by default */ 8873ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang pad->flags |= FSPDRV_FLAG_EN_OPC; 8883ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang 8893ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang /* Enable on-pad vertical and horizontal scrolling */ 8903ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang fsp_onpad_vscr(psmouse, true); 8913ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang fsp_onpad_hscr(psmouse, true); 892a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang } else { 893a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang /* Enable absolute coordinates output for Cx/Dx hardware */ 894a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang if (fsp_reg_write(psmouse, FSP_REG_SWC1, 895a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang FSP_BIT_SWC1_EN_ABS_1F | 896a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang FSP_BIT_SWC1_EN_ABS_2F | 897a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang FSP_BIT_SWC1_EN_FUP_OUT | 898a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang FSP_BIT_SWC1_EN_ABS_CON)) { 899a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang psmouse_err(psmouse, 900a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang "Unable to enable absolute coordinates output.\n"); 901a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang return -EIO; 902a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang } 903fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } 904fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 9053ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang return 0; 9063ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang} 9073ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang 9083ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liangstatic int fsp_set_input_params(struct psmouse *psmouse) 9093ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang{ 9103ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang struct input_dev *dev = psmouse->dev; 9113ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang struct fsp_data *pad = psmouse->private; 912fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 9133ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang if (pad->ver < FSP_VER_STL3888_C0) { 9143ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang __set_bit(BTN_MIDDLE, dev->keybit); 9153ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang __set_bit(BTN_BACK, dev->keybit); 9163ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang __set_bit(BTN_FORWARD, dev->keybit); 9173ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang __set_bit(REL_WHEEL, dev->relbit); 9183ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang __set_bit(REL_HWHEEL, dev->relbit); 919a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang } else { 920a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang /* 921a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang * Hardware prior to Cx performs much better in relative mode; 922a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang * hence, only enable absolute coordinates output as well as 923a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang * multi-touch output for the newer hardware. 924a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang * 925a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang * Maximum coordinates can be computed as: 926a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang * 927a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang * number of scanlines * 64 - 57 928a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang * 929a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang * where number of X/Y scanline lines are 16/12. 930a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang */ 931a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang int abs_x = 967, abs_y = 711; 932a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang 933a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang __set_bit(EV_ABS, dev->evbit); 934a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang __clear_bit(EV_REL, dev->evbit); 935a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang __set_bit(BTN_TOUCH, dev->keybit); 936a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang __set_bit(BTN_TOOL_FINGER, dev->keybit); 937a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); 938a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang __set_bit(INPUT_PROP_SEMI_MT, dev->propbit); 939a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang 940a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang input_set_abs_params(dev, ABS_X, 0, abs_x, 0, 0); 941a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang input_set_abs_params(dev, ABS_Y, 0, abs_y, 0, 0); 942a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang input_mt_init_slots(dev, 2); 943a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang input_set_abs_params(dev, ABS_MT_POSITION_X, 0, abs_x, 0, 0); 944a4c85075f00d56b38f5c277ab89f9aaad69eb17bTai-hwa Liang input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, abs_y, 0, 0); 9453ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang } 946fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 947fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return 0; 948fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 949fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 950b7802c5c1ea9563f3746bea09c214ccedc8600f4Dmitry Torokhovint fsp_detect(struct psmouse *psmouse, bool set_properties) 951fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 952fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang int id; 953fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 954fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (fsp_reg_read(psmouse, FSP_REG_DEVICE_ID, &id)) 955fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -EIO; 956fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 957fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (id != 0x01) 958fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -ENODEV; 959fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 960fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (set_properties) { 961fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang psmouse->vendor = "Sentelic"; 962fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang psmouse->name = "FingerSensingPad"; 963fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } 964fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 965fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return 0; 966fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 967fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 968fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic void fsp_reset(struct psmouse *psmouse) 969fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 970fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang fsp_opc_tag_enable(psmouse, false); 971fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang fsp_onpad_vscr(psmouse, false); 972fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang fsp_onpad_hscr(psmouse, false); 973fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 974fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 975fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic void fsp_disconnect(struct psmouse *psmouse) 976fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 977fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, 978fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang &fsp_attribute_group); 979fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 980fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang fsp_reset(psmouse); 981fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang kfree(psmouse->private); 982fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 983fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 984fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangstatic int fsp_reconnect(struct psmouse *psmouse) 985fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 986fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang int version; 987fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 988fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (fsp_detect(psmouse, 0)) 989fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -ENODEV; 990fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 991fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (fsp_get_version(psmouse, &version)) 992fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -ENODEV; 993fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 994fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (fsp_activate_protocol(psmouse)) 995fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -EIO; 996fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 997fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return 0; 998fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 999fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 1000fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liangint fsp_init(struct psmouse *psmouse) 1001fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang{ 1002fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang struct fsp_data *priv; 10033ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang int ver, rev; 1004fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang int error; 1005fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 1006fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (fsp_get_version(psmouse, &ver) || 10073ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang fsp_get_revision(psmouse, &rev)) { 1008fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -ENODEV; 1009fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } 1010fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 10113ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang psmouse_info(psmouse, "Finger Sensing Pad, hw: %d.%d.%d, sw: %s\n", 10123ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang ver >> 4, ver & 0x0F, rev, fsp_drv_ver); 1013fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 1014fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang psmouse->private = priv = kzalloc(sizeof(struct fsp_data), GFP_KERNEL); 1015fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (!priv) 1016fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return -ENOMEM; 1017fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 1018fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang priv->ver = ver; 1019fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang priv->rev = rev; 1020fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 1021fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang psmouse->protocol_handler = fsp_process_byte; 1022fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang psmouse->disconnect = fsp_disconnect; 1023fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang psmouse->reconnect = fsp_reconnect; 1024fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang psmouse->cleanup = fsp_reset; 1025fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang psmouse->pktsize = 4; 1026fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 1027fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang error = fsp_activate_protocol(psmouse); 1028fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (error) 1029fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang goto err_out; 1030fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 10313ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang /* Set up various supported input event bits */ 10323ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang error = fsp_set_input_params(psmouse); 10333ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang if (error) 10343ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang goto err_out; 10353ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang 1036fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj, 1037fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang &fsp_attribute_group); 1038fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang if (error) { 10393ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang psmouse_err(psmouse, 10403ac1780f9e6ed212e56d4132e997551297a97112Tai-hwa Liang "Failed to create sysfs attributes (%d)", error); 1041fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang goto err_out; 1042fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang } 1043fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 1044fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return 0; 1045fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang 1046fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang err_out: 1047fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang kfree(psmouse->private); 1048fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang psmouse->private = NULL; 1049fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang return error; 1050fc69f4a6af49ee69475dc4217924d9edf77760e0Tai-hwa Liang} 1051