11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ALPS touchpad PS/2 mouse driver 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 2003 Neil Brown <neilb@cse.unsw.edu.au> 5963f626d46d5caeeb3cff29998d8a64df5b25591Peter Osterlund * Copyright (c) 2003-2005 Peter Osterlund <petero2@telia.com> 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru> 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz> 81d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * Copyright (c) 2009 Sebastian Kapfer <sebastian_kapfer@gmx.net> 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ALPS detection, tap switching and status querying info is taken from 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tpconfig utility (by C. Scott Ananian and Bruce Kall). 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify it 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * under the terms of the GNU General Public License version 2 as published by 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation. 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 185a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/input.h> 2001ce661fc83005947dc958a5739c153843af8a73Seth Forshee#include <linux/input/mt.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serio.h> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/libps2.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "psmouse.h" 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "alps.h" 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee/* 2825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * Definitions for ALPS version 3 and 4 command mode protocol 2925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee */ 3001ce661fc83005947dc958a5739c153843af8a73Seth Forshee#define ALPS_V3_X_MAX 2000 3101ce661fc83005947dc958a5739c153843af8a73Seth Forshee#define ALPS_V3_Y_MAX 1400 3201ce661fc83005947dc958a5739c153843af8a73Seth Forshee 3301ce661fc83005947dc958a5739c153843af8a73Seth Forshee#define ALPS_BITMAP_X_BITS 15 3401ce661fc83005947dc958a5739c153843af8a73Seth Forshee#define ALPS_BITMAP_Y_BITS 11 3501ce661fc83005947dc958a5739c153843af8a73Seth Forshee 3625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee#define ALPS_CMD_NIBBLE_10 0x01f2 3725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 3825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forsheestatic const struct alps_nibble_commands alps_v3_nibble_commands[] = { 3925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_SETPOLL, 0x00 }, /* 0 */ 4025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */ 4125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_SETSCALE21, 0x00 }, /* 2 */ 4225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_SETRATE, 0x0a }, /* 3 */ 4325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_SETRATE, 0x14 }, /* 4 */ 4425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_SETRATE, 0x28 }, /* 5 */ 4525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_SETRATE, 0x3c }, /* 6 */ 4625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_SETRATE, 0x50 }, /* 7 */ 4725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_SETRATE, 0x64 }, /* 8 */ 4825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_SETRATE, 0xc8 }, /* 9 */ 4925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { ALPS_CMD_NIBBLE_10, 0x00 }, /* a */ 5025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_SETRES, 0x00 }, /* b */ 5125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_SETRES, 0x01 }, /* c */ 5225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_SETRES, 0x02 }, /* d */ 5325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_SETRES, 0x03 }, /* e */ 5425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_SETSCALE11, 0x00 }, /* f */ 5525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee}; 5625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 5725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forsheestatic const struct alps_nibble_commands alps_v4_nibble_commands[] = { 5825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_ENABLE, 0x00 }, /* 0 */ 5925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */ 6025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_SETSCALE21, 0x00 }, /* 2 */ 6125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_SETRATE, 0x0a }, /* 3 */ 6225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_SETRATE, 0x14 }, /* 4 */ 6325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_SETRATE, 0x28 }, /* 5 */ 6425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_SETRATE, 0x3c }, /* 6 */ 6525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_SETRATE, 0x50 }, /* 7 */ 6625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_SETRATE, 0x64 }, /* 8 */ 6725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_SETRATE, 0xc8 }, /* 9 */ 6825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { ALPS_CMD_NIBBLE_10, 0x00 }, /* a */ 6925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_SETRES, 0x00 }, /* b */ 7025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_SETRES, 0x01 }, /* c */ 7125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_SETRES, 0x02 }, /* d */ 7225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_SETRES, 0x03 }, /* e */ 7325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { PSMOUSE_CMD_SETSCALE11, 0x00 }, /* f */ 7425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee}; 7525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 7625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 7771bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky#define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */ 7871bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky#define ALPS_PASS 0x04 /* device has a pass-through port */ 7971bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky 8071bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky#define ALPS_WHEEL 0x08 /* hardware wheel present */ 8171bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky#define ALPS_FW_BK_1 0x10 /* front & back buttons present */ 8271bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky#define ALPS_FW_BK_2 0x20 /* front & back buttons present */ 8371bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky#define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */ 841d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer#define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with 851d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 6-byte ALPS packet */ 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 87e38de678f6b19be3e46a678ec4deeaa7fa0fc140Helge Dellerstatic const struct alps_model_info alps_model_data[] = { 8825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { { 0x32, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */ 8925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { { 0x33, 0x02, 0x0a }, 0x00, ALPS_PROTO_V1, 0x88, 0xf8, 0 }, /* UMAX-530T */ 9025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { { 0x53, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, 9125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { { 0x53, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, 9225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { { 0x60, 0x03, 0xc8 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, /* HP ze1115 */ 9325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { { 0x63, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, 9425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { { 0x63, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, 9525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { { 0x63, 0x02, 0x28 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Fujitsu Siemens S6010 */ 9625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { { 0x63, 0x02, 0x3c }, 0x00, ALPS_PROTO_V2, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */ 9725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { { 0x63, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */ 9825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { { 0x63, 0x02, 0x64 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, 9925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { { 0x63, 0x03, 0xc8 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D800 */ 10025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { { 0x73, 0x00, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_DUALPOINT }, /* ThinkPad R61 8918-5QG */ 10125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { { 0x73, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, 10225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { { 0x73, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */ 10325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { { 0x20, 0x02, 0x0e }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */ 10425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { { 0x22, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, 10525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { { 0x22, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ 1061d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer /* Dell Latitude E5500, E6400, E6500, Precision M4400 */ 10725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { { 0x62, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, 1081d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, 10925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { { 0x73, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */ 11025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { { 0x52, 0x01, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff, 11125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */ 11225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { { 0x73, 0x02, 0x64 }, 0x9b, ALPS_PROTO_V3, 0x8f, 0x8f, ALPS_DUALPOINT }, 11325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { { 0x73, 0x02, 0x64 }, 0x9d, ALPS_PROTO_V3, 0x8f, 0x8f, ALPS_DUALPOINT }, 11425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee { { 0x73, 0x02, 0x64 }, 0x8a, ALPS_PROTO_V4, 0x8f, 0x8f, 0 }, 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * XXX - this entry is suspicious. First byte has zero lower nibble, 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * which is what a normal mouse would report. Also, the value 0x0e 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * isn't valid per PS/2 spec. 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 123d4b347b29b4d14647c7394f7167bf6785dc98e50Seth Forshee/* Packet formats are described in Documentation/input/alps.txt */ 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1251d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapferstatic bool alps_is_valid_first_byte(const struct alps_model_info *model, 1261d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer unsigned char data) 1271d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer{ 1281d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer return (data & model->mask0) == model->byte0; 1291d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer} 1301d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 1311d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapferstatic void alps_report_buttons(struct psmouse *psmouse, 1321d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer struct input_dev *dev1, struct input_dev *dev2, 1331d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer int left, int right, int middle) 1341d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer{ 135c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck struct input_dev *dev; 136c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck 137c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck /* 138c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck * If shared button has already been reported on the 139c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck * other device (dev2) then this event should be also 140c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck * sent through that device. 141c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck */ 142c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck dev = test_bit(BTN_LEFT, dev2->key) ? dev2 : dev1; 143c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck input_report_key(dev, BTN_LEFT, left); 144c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck 145c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck dev = test_bit(BTN_RIGHT, dev2->key) ? dev2 : dev1; 146c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck input_report_key(dev, BTN_RIGHT, right); 147c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck 148c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck dev = test_bit(BTN_MIDDLE, dev2->key) ? dev2 : dev1; 149c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck input_report_key(dev, BTN_MIDDLE, middle); 150c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck 151c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck /* 152c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck * Sync the _other_ device now, we'll do the first 153c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck * device later once we report the rest of the events. 154c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck */ 155c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck input_sync(dev2); 1561d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer} 1571d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 15825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forsheestatic void alps_process_packet_v1_v2(struct psmouse *psmouse) 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct alps_data *priv = psmouse->private; 16171bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky const struct alps_model_info *model = priv->i; 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *packet = psmouse->packet; 1632e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov struct input_dev *dev = psmouse->dev; 1642e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov struct input_dev *dev2 = priv->dev2; 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int x, y, z, ges, fin, left, right, middle; 166c30b4c10d9cfe5506fd421304935d8836773c7e5Ivan Casado Ruiz int back = 0, forward = 0; 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 168fa629ef5222193214da9a2b3c94369f79353bec9Seth Forshee if (model->proto_version == ALPS_PROTO_V1) { 169d2f4012f15845761bd3c6f90172e53767c11e359Yotam Medini left = packet[2] & 0x10; 170d2f4012f15845761bd3c6f90172e53767c11e359Yotam Medini right = packet[2] & 0x08; 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds middle = 0; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds x = packet[1] | ((packet[0] & 0x07) << 7); 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds y = packet[4] | ((packet[3] & 0x07) << 7); 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds z = packet[5]; 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds left = packet[3] & 1; 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds right = packet[3] & 2; 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds middle = packet[3] & 4; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds x = packet[1] | ((packet[2] & 0x78) << (7 - 3)); 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds y = packet[4] | ((packet[3] & 0x70) << (7 - 4)); 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds z = packet[5]; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18471bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if (model->flags & ALPS_FW_BK_1) { 1853c00bb96497a9c1251359a1faf68dddbb8d50a23Laszlo Kajan back = packet[0] & 0x10; 1863c00bb96497a9c1251359a1faf68dddbb8d50a23Laszlo Kajan forward = packet[2] & 4; 187c30b4c10d9cfe5506fd421304935d8836773c7e5Ivan Casado Ruiz } 188c30b4c10d9cfe5506fd421304935d8836773c7e5Ivan Casado Ruiz 18971bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if (model->flags & ALPS_FW_BK_2) { 190c30b4c10d9cfe5506fd421304935d8836773c7e5Ivan Casado Ruiz back = packet[3] & 4; 191c30b4c10d9cfe5506fd421304935d8836773c7e5Ivan Casado Ruiz forward = packet[2] & 4; 192c30b4c10d9cfe5506fd421304935d8836773c7e5Ivan Casado Ruiz if ((middle = forward && back)) 193c30b4c10d9cfe5506fd421304935d8836773c7e5Ivan Casado Ruiz forward = back = 0; 194c30b4c10d9cfe5506fd421304935d8836773c7e5Ivan Casado Ruiz } 195c30b4c10d9cfe5506fd421304935d8836773c7e5Ivan Casado Ruiz 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ges = packet[2] & 1; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fin = packet[2] & 2; 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19971bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if ((model->flags & ALPS_DUALPOINT) && z == 127) { 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_rel(dev2, REL_X, (x > 383 ? (x - 768) : x)); 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y)); 202d7ed5d883c09c5474f842dcb148515dfaef2a567Ulrich Dangel 2031d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer alps_report_buttons(psmouse, dev2, dev, left, right, middle); 204d7ed5d883c09c5474f842dcb148515dfaef2a567Ulrich Dangel 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_sync(dev2); 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2091d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer alps_report_buttons(psmouse, dev, dev2, left, right, middle); 210d7ed5d883c09c5474f842dcb148515dfaef2a567Ulrich Dangel 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Convert hardware tap to a reasonable Z value */ 21271bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if (ges && !fin) 21371bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky z = 40; 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A "tap and drag" operation is reported by the hardware as a transition 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * from (!fin && ges) to (fin && ges). This should be translated to the 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sequence Z>0, Z==0, Z>0, so the Z==0 event has to be generated manually. 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ges && fin && !priv->prev_fin) { 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_abs(dev, ABS_X, x); 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_abs(dev, ABS_Y, y); 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_abs(dev, ABS_PRESSURE, 0); 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_key(dev, BTN_TOOL_FINGER, 0); 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_sync(dev); 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->prev_fin = fin; 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22971bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if (z > 30) 23071bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky input_report_key(dev, BTN_TOUCH, 1); 23171bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if (z < 25) 23271bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky input_report_key(dev, BTN_TOUCH, 0); 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (z > 0) { 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_abs(dev, ABS_X, x); 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_abs(dev, ABS_Y, y); 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_abs(dev, ABS_PRESSURE, z); 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_key(dev, BTN_TOOL_FINGER, z > 0); 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24271bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if (model->flags & ALPS_WHEEL) 243e6c047b98bbd09473c586744c681e877ebf954ffVojtech Pavlik input_report_rel(dev, REL_WHEEL, ((packet[2] << 1) & 0x08) - ((packet[0] >> 4) & 0x07)); 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24571bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if (model->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { 246c30b4c10d9cfe5506fd421304935d8836773c7e5Ivan Casado Ruiz input_report_key(dev, BTN_FORWARD, forward); 247c30b4c10d9cfe5506fd421304935d8836773c7e5Ivan Casado Ruiz input_report_key(dev, BTN_BACK, back); 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25071bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if (model->flags & ALPS_FOUR_BUTTONS) { 25171bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky input_report_key(dev, BTN_0, packet[2] & 4); 25271bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky input_report_key(dev, BTN_1, packet[0] & 0x10); 25371bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky input_report_key(dev, BTN_2, packet[3] & 4); 25471bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky input_report_key(dev, BTN_3, packet[0] & 0x20); 25571bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky } 25671bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_sync(dev); 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26001ce661fc83005947dc958a5739c153843af8a73Seth Forshee/* 26101ce661fc83005947dc958a5739c153843af8a73Seth Forshee * Process bitmap data from v3 and v4 protocols. Returns the number of 26201ce661fc83005947dc958a5739c153843af8a73Seth Forshee * fingers detected. A return value of 0 means at least one of the 26301ce661fc83005947dc958a5739c153843af8a73Seth Forshee * bitmaps was empty. 26401ce661fc83005947dc958a5739c153843af8a73Seth Forshee * 26501ce661fc83005947dc958a5739c153843af8a73Seth Forshee * The bitmaps don't have enough data to track fingers, so this function 26601ce661fc83005947dc958a5739c153843af8a73Seth Forshee * only generates points representing a bounding box of all contacts. 26701ce661fc83005947dc958a5739c153843af8a73Seth Forshee * These points are returned in x1, y1, x2, and y2 when the return value 26801ce661fc83005947dc958a5739c153843af8a73Seth Forshee * is greater than 0. 26901ce661fc83005947dc958a5739c153843af8a73Seth Forshee */ 27001ce661fc83005947dc958a5739c153843af8a73Seth Forsheestatic int alps_process_bitmap(unsigned int x_map, unsigned int y_map, 27101ce661fc83005947dc958a5739c153843af8a73Seth Forshee int *x1, int *y1, int *x2, int *y2) 27201ce661fc83005947dc958a5739c153843af8a73Seth Forshee{ 27301ce661fc83005947dc958a5739c153843af8a73Seth Forshee struct alps_bitmap_point { 27401ce661fc83005947dc958a5739c153843af8a73Seth Forshee int start_bit; 27501ce661fc83005947dc958a5739c153843af8a73Seth Forshee int num_bits; 27601ce661fc83005947dc958a5739c153843af8a73Seth Forshee }; 27701ce661fc83005947dc958a5739c153843af8a73Seth Forshee 27801ce661fc83005947dc958a5739c153843af8a73Seth Forshee int fingers_x = 0, fingers_y = 0, fingers; 27901ce661fc83005947dc958a5739c153843af8a73Seth Forshee int i, bit, prev_bit; 28001ce661fc83005947dc958a5739c153843af8a73Seth Forshee struct alps_bitmap_point x_low = {0,}, x_high = {0,}; 28101ce661fc83005947dc958a5739c153843af8a73Seth Forshee struct alps_bitmap_point y_low = {0,}, y_high = {0,}; 28201ce661fc83005947dc958a5739c153843af8a73Seth Forshee struct alps_bitmap_point *point; 28301ce661fc83005947dc958a5739c153843af8a73Seth Forshee 28401ce661fc83005947dc958a5739c153843af8a73Seth Forshee if (!x_map || !y_map) 28501ce661fc83005947dc958a5739c153843af8a73Seth Forshee return 0; 28601ce661fc83005947dc958a5739c153843af8a73Seth Forshee 28701ce661fc83005947dc958a5739c153843af8a73Seth Forshee *x1 = *y1 = *x2 = *y2 = 0; 28801ce661fc83005947dc958a5739c153843af8a73Seth Forshee 28901ce661fc83005947dc958a5739c153843af8a73Seth Forshee prev_bit = 0; 29001ce661fc83005947dc958a5739c153843af8a73Seth Forshee point = &x_low; 29101ce661fc83005947dc958a5739c153843af8a73Seth Forshee for (i = 0; x_map != 0; i++, x_map >>= 1) { 29201ce661fc83005947dc958a5739c153843af8a73Seth Forshee bit = x_map & 1; 29301ce661fc83005947dc958a5739c153843af8a73Seth Forshee if (bit) { 29401ce661fc83005947dc958a5739c153843af8a73Seth Forshee if (!prev_bit) { 29501ce661fc83005947dc958a5739c153843af8a73Seth Forshee point->start_bit = i; 29601ce661fc83005947dc958a5739c153843af8a73Seth Forshee fingers_x++; 29701ce661fc83005947dc958a5739c153843af8a73Seth Forshee } 29801ce661fc83005947dc958a5739c153843af8a73Seth Forshee point->num_bits++; 29901ce661fc83005947dc958a5739c153843af8a73Seth Forshee } else { 30001ce661fc83005947dc958a5739c153843af8a73Seth Forshee if (prev_bit) 30101ce661fc83005947dc958a5739c153843af8a73Seth Forshee point = &x_high; 30201ce661fc83005947dc958a5739c153843af8a73Seth Forshee else 30301ce661fc83005947dc958a5739c153843af8a73Seth Forshee point->num_bits = 0; 30401ce661fc83005947dc958a5739c153843af8a73Seth Forshee } 30501ce661fc83005947dc958a5739c153843af8a73Seth Forshee prev_bit = bit; 30601ce661fc83005947dc958a5739c153843af8a73Seth Forshee } 30701ce661fc83005947dc958a5739c153843af8a73Seth Forshee 30801ce661fc83005947dc958a5739c153843af8a73Seth Forshee /* 30901ce661fc83005947dc958a5739c153843af8a73Seth Forshee * y bitmap is reversed for what we need (lower positions are in 31001ce661fc83005947dc958a5739c153843af8a73Seth Forshee * higher bits), so we process from the top end. 31101ce661fc83005947dc958a5739c153843af8a73Seth Forshee */ 31201ce661fc83005947dc958a5739c153843af8a73Seth Forshee y_map = y_map << (sizeof(y_map) * BITS_PER_BYTE - ALPS_BITMAP_Y_BITS); 31301ce661fc83005947dc958a5739c153843af8a73Seth Forshee prev_bit = 0; 31401ce661fc83005947dc958a5739c153843af8a73Seth Forshee point = &y_low; 31501ce661fc83005947dc958a5739c153843af8a73Seth Forshee for (i = 0; y_map != 0; i++, y_map <<= 1) { 31601ce661fc83005947dc958a5739c153843af8a73Seth Forshee bit = y_map & (1 << (sizeof(y_map) * BITS_PER_BYTE - 1)); 31701ce661fc83005947dc958a5739c153843af8a73Seth Forshee if (bit) { 31801ce661fc83005947dc958a5739c153843af8a73Seth Forshee if (!prev_bit) { 31901ce661fc83005947dc958a5739c153843af8a73Seth Forshee point->start_bit = i; 32001ce661fc83005947dc958a5739c153843af8a73Seth Forshee fingers_y++; 32101ce661fc83005947dc958a5739c153843af8a73Seth Forshee } 32201ce661fc83005947dc958a5739c153843af8a73Seth Forshee point->num_bits++; 32301ce661fc83005947dc958a5739c153843af8a73Seth Forshee } else { 32401ce661fc83005947dc958a5739c153843af8a73Seth Forshee if (prev_bit) 32501ce661fc83005947dc958a5739c153843af8a73Seth Forshee point = &y_high; 32601ce661fc83005947dc958a5739c153843af8a73Seth Forshee else 32701ce661fc83005947dc958a5739c153843af8a73Seth Forshee point->num_bits = 0; 32801ce661fc83005947dc958a5739c153843af8a73Seth Forshee } 32901ce661fc83005947dc958a5739c153843af8a73Seth Forshee prev_bit = bit; 33001ce661fc83005947dc958a5739c153843af8a73Seth Forshee } 33101ce661fc83005947dc958a5739c153843af8a73Seth Forshee 33201ce661fc83005947dc958a5739c153843af8a73Seth Forshee /* 33301ce661fc83005947dc958a5739c153843af8a73Seth Forshee * Fingers can overlap, so we use the maximum count of fingers 33401ce661fc83005947dc958a5739c153843af8a73Seth Forshee * on either axis as the finger count. 33501ce661fc83005947dc958a5739c153843af8a73Seth Forshee */ 33601ce661fc83005947dc958a5739c153843af8a73Seth Forshee fingers = max(fingers_x, fingers_y); 33701ce661fc83005947dc958a5739c153843af8a73Seth Forshee 33801ce661fc83005947dc958a5739c153843af8a73Seth Forshee /* 33901ce661fc83005947dc958a5739c153843af8a73Seth Forshee * If total fingers is > 1 but either axis reports only a single 34001ce661fc83005947dc958a5739c153843af8a73Seth Forshee * contact, we have overlapping or adjacent fingers. For the 34101ce661fc83005947dc958a5739c153843af8a73Seth Forshee * purposes of creating a bounding box, divide the single contact 34201ce661fc83005947dc958a5739c153843af8a73Seth Forshee * (roughly) equally between the two points. 34301ce661fc83005947dc958a5739c153843af8a73Seth Forshee */ 34401ce661fc83005947dc958a5739c153843af8a73Seth Forshee if (fingers > 1) { 34501ce661fc83005947dc958a5739c153843af8a73Seth Forshee if (fingers_x == 1) { 34601ce661fc83005947dc958a5739c153843af8a73Seth Forshee i = x_low.num_bits / 2; 34701ce661fc83005947dc958a5739c153843af8a73Seth Forshee x_low.num_bits = x_low.num_bits - i; 34801ce661fc83005947dc958a5739c153843af8a73Seth Forshee x_high.start_bit = x_low.start_bit + i; 34901ce661fc83005947dc958a5739c153843af8a73Seth Forshee x_high.num_bits = max(i, 1); 35001ce661fc83005947dc958a5739c153843af8a73Seth Forshee } else if (fingers_y == 1) { 35101ce661fc83005947dc958a5739c153843af8a73Seth Forshee i = y_low.num_bits / 2; 35201ce661fc83005947dc958a5739c153843af8a73Seth Forshee y_low.num_bits = y_low.num_bits - i; 35301ce661fc83005947dc958a5739c153843af8a73Seth Forshee y_high.start_bit = y_low.start_bit + i; 35401ce661fc83005947dc958a5739c153843af8a73Seth Forshee y_high.num_bits = max(i, 1); 35501ce661fc83005947dc958a5739c153843af8a73Seth Forshee } 35601ce661fc83005947dc958a5739c153843af8a73Seth Forshee } 35701ce661fc83005947dc958a5739c153843af8a73Seth Forshee 35801ce661fc83005947dc958a5739c153843af8a73Seth Forshee *x1 = (ALPS_V3_X_MAX * (2 * x_low.start_bit + x_low.num_bits - 1)) / 35901ce661fc83005947dc958a5739c153843af8a73Seth Forshee (2 * (ALPS_BITMAP_X_BITS - 1)); 36001ce661fc83005947dc958a5739c153843af8a73Seth Forshee *y1 = (ALPS_V3_Y_MAX * (2 * y_low.start_bit + y_low.num_bits - 1)) / 36101ce661fc83005947dc958a5739c153843af8a73Seth Forshee (2 * (ALPS_BITMAP_Y_BITS - 1)); 36201ce661fc83005947dc958a5739c153843af8a73Seth Forshee 36301ce661fc83005947dc958a5739c153843af8a73Seth Forshee if (fingers > 1) { 36401ce661fc83005947dc958a5739c153843af8a73Seth Forshee *x2 = (ALPS_V3_X_MAX * (2 * x_high.start_bit + x_high.num_bits - 1)) / 36501ce661fc83005947dc958a5739c153843af8a73Seth Forshee (2 * (ALPS_BITMAP_X_BITS - 1)); 36601ce661fc83005947dc958a5739c153843af8a73Seth Forshee *y2 = (ALPS_V3_Y_MAX * (2 * y_high.start_bit + y_high.num_bits - 1)) / 36701ce661fc83005947dc958a5739c153843af8a73Seth Forshee (2 * (ALPS_BITMAP_Y_BITS - 1)); 36801ce661fc83005947dc958a5739c153843af8a73Seth Forshee } 36901ce661fc83005947dc958a5739c153843af8a73Seth Forshee 37001ce661fc83005947dc958a5739c153843af8a73Seth Forshee return fingers; 37101ce661fc83005947dc958a5739c153843af8a73Seth Forshee} 37201ce661fc83005947dc958a5739c153843af8a73Seth Forshee 37301ce661fc83005947dc958a5739c153843af8a73Seth Forsheestatic void alps_set_slot(struct input_dev *dev, int slot, bool active, 37401ce661fc83005947dc958a5739c153843af8a73Seth Forshee int x, int y) 37501ce661fc83005947dc958a5739c153843af8a73Seth Forshee{ 37601ce661fc83005947dc958a5739c153843af8a73Seth Forshee input_mt_slot(dev, slot); 37701ce661fc83005947dc958a5739c153843af8a73Seth Forshee input_mt_report_slot_state(dev, MT_TOOL_FINGER, active); 37801ce661fc83005947dc958a5739c153843af8a73Seth Forshee if (active) { 37901ce661fc83005947dc958a5739c153843af8a73Seth Forshee input_report_abs(dev, ABS_MT_POSITION_X, x); 38001ce661fc83005947dc958a5739c153843af8a73Seth Forshee input_report_abs(dev, ABS_MT_POSITION_Y, y); 38101ce661fc83005947dc958a5739c153843af8a73Seth Forshee } 38201ce661fc83005947dc958a5739c153843af8a73Seth Forshee} 38301ce661fc83005947dc958a5739c153843af8a73Seth Forshee 38401ce661fc83005947dc958a5739c153843af8a73Seth Forsheestatic void alps_report_semi_mt_data(struct input_dev *dev, int num_fingers, 38501ce661fc83005947dc958a5739c153843af8a73Seth Forshee int x1, int y1, int x2, int y2) 38601ce661fc83005947dc958a5739c153843af8a73Seth Forshee{ 38701ce661fc83005947dc958a5739c153843af8a73Seth Forshee alps_set_slot(dev, 0, num_fingers != 0, x1, y1); 38801ce661fc83005947dc958a5739c153843af8a73Seth Forshee alps_set_slot(dev, 1, num_fingers == 2, x2, y2); 38901ce661fc83005947dc958a5739c153843af8a73Seth Forshee} 39001ce661fc83005947dc958a5739c153843af8a73Seth Forshee 39125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forsheestatic void alps_process_trackstick_packet_v3(struct psmouse *psmouse) 39225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee{ 39325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee struct alps_data *priv = psmouse->private; 39425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee unsigned char *packet = psmouse->packet; 39525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee struct input_dev *dev = priv->dev2; 39625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee int x, y, z, left, right, middle; 39725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 39825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee /* Sanity check packet */ 39925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (!(packet[0] & 0x40)) { 40025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee psmouse_dbg(psmouse, "Bad trackstick packet, discarding\n"); 40125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return; 40225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } 40325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 40425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee /* 40525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * There's a special packet that seems to indicate the end 40625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * of a stream of trackstick data. Filter these out. 40725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee */ 40825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (packet[1] == 0x7f && packet[2] == 0x7f && packet[4] == 0x7f) 40925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return; 41025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 41125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee x = (s8)(((packet[0] & 0x20) << 2) | (packet[1] & 0x7f)); 41225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee y = (s8)(((packet[0] & 0x10) << 3) | (packet[2] & 0x7f)); 41325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee z = (packet[4] & 0x7c) >> 2; 41425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 41525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee /* 41625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * The x and y values tend to be quite large, and when used 41725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * alone the trackstick is difficult to use. Scale them down 41825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * to compensate. 41925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee */ 42025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee x /= 8; 42125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee y /= 8; 42225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 42325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee input_report_rel(dev, REL_X, x); 42425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee input_report_rel(dev, REL_Y, -y); 42525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 42625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee /* 42725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * Most ALPS models report the trackstick buttons in the touchpad 42825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * packets, but a few report them here. No reliable way has been 42925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * found to differentiate between the models upfront, so we enable 43025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * the quirk in response to seeing a button press in the trackstick 43125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * packet. 43225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee */ 43325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee left = packet[3] & 0x01; 43425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee right = packet[3] & 0x02; 43525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee middle = packet[3] & 0x04; 43625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 43725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS) && 43825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee (left || right || middle)) 43925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee priv->quirks |= ALPS_QUIRK_TRACKSTICK_BUTTONS; 44025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 44125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS) { 44225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee input_report_key(dev, BTN_LEFT, left); 44325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee input_report_key(dev, BTN_RIGHT, right); 44425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee input_report_key(dev, BTN_MIDDLE, middle); 44525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } 44625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 44725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee input_sync(dev); 44825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return; 44925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee} 45025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 45125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forsheestatic void alps_process_touchpad_packet_v3(struct psmouse *psmouse) 45225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee{ 45325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee struct alps_data *priv = psmouse->private; 45425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee unsigned char *packet = psmouse->packet; 45525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee struct input_dev *dev = psmouse->dev; 45625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee struct input_dev *dev2 = priv->dev2; 45725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee int x, y, z; 45825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee int left, right, middle; 45901ce661fc83005947dc958a5739c153843af8a73Seth Forshee int x1 = 0, y1 = 0, x2 = 0, y2 = 0; 46001ce661fc83005947dc958a5739c153843af8a73Seth Forshee int fingers = 0, bmap_fingers; 46101ce661fc83005947dc958a5739c153843af8a73Seth Forshee unsigned int x_bitmap, y_bitmap; 46225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 46325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee /* 46401ce661fc83005947dc958a5739c153843af8a73Seth Forshee * There's no single feature of touchpad position and bitmap packets 46501ce661fc83005947dc958a5739c153843af8a73Seth Forshee * that can be used to distinguish between them. We rely on the fact 46601ce661fc83005947dc958a5739c153843af8a73Seth Forshee * that a bitmap packet should always follow a position packet with 46701ce661fc83005947dc958a5739c153843af8a73Seth Forshee * bit 6 of packet[4] set. 46825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee */ 46925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (priv->multi_packet) { 47025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee /* 47125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * Sometimes a position packet will indicate a multi-packet 47225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * sequence, but then what follows is another position 47325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * packet. Check for this, and when it happens process the 47425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * position packet as usual. 47525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee */ 47625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (packet[0] & 0x40) { 47701ce661fc83005947dc958a5739c153843af8a73Seth Forshee fingers = (packet[5] & 0x3) + 1; 47801ce661fc83005947dc958a5739c153843af8a73Seth Forshee x_bitmap = ((packet[4] & 0x7e) << 8) | 47901ce661fc83005947dc958a5739c153843af8a73Seth Forshee ((packet[1] & 0x7f) << 2) | 48001ce661fc83005947dc958a5739c153843af8a73Seth Forshee ((packet[0] & 0x30) >> 4); 48101ce661fc83005947dc958a5739c153843af8a73Seth Forshee y_bitmap = ((packet[3] & 0x70) << 4) | 48201ce661fc83005947dc958a5739c153843af8a73Seth Forshee ((packet[2] & 0x7f) << 1) | 48301ce661fc83005947dc958a5739c153843af8a73Seth Forshee (packet[4] & 0x01); 48401ce661fc83005947dc958a5739c153843af8a73Seth Forshee 48501ce661fc83005947dc958a5739c153843af8a73Seth Forshee bmap_fingers = alps_process_bitmap(x_bitmap, y_bitmap, 48601ce661fc83005947dc958a5739c153843af8a73Seth Forshee &x1, &y1, &x2, &y2); 48701ce661fc83005947dc958a5739c153843af8a73Seth Forshee 48825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee /* 48901ce661fc83005947dc958a5739c153843af8a73Seth Forshee * We shouldn't report more than one finger if 49001ce661fc83005947dc958a5739c153843af8a73Seth Forshee * we don't have two coordinates. 49125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee */ 49201ce661fc83005947dc958a5739c153843af8a73Seth Forshee if (fingers > 1 && bmap_fingers < 2) 49301ce661fc83005947dc958a5739c153843af8a73Seth Forshee fingers = bmap_fingers; 49401ce661fc83005947dc958a5739c153843af8a73Seth Forshee 49501ce661fc83005947dc958a5739c153843af8a73Seth Forshee /* Now process position packet */ 49601ce661fc83005947dc958a5739c153843af8a73Seth Forshee packet = priv->multi_data; 49701ce661fc83005947dc958a5739c153843af8a73Seth Forshee } else { 49801ce661fc83005947dc958a5739c153843af8a73Seth Forshee priv->multi_packet = 0; 49925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } 50025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } 50125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 50201ce661fc83005947dc958a5739c153843af8a73Seth Forshee /* 50301ce661fc83005947dc958a5739c153843af8a73Seth Forshee * Bit 6 of byte 0 is not usually set in position packets. The only 50401ce661fc83005947dc958a5739c153843af8a73Seth Forshee * times it seems to be set is in situations where the data is 50501ce661fc83005947dc958a5739c153843af8a73Seth Forshee * suspect anyway, e.g. a palm resting flat on the touchpad. Given 50601ce661fc83005947dc958a5739c153843af8a73Seth Forshee * this combined with the fact that this bit is useful for filtering 50701ce661fc83005947dc958a5739c153843af8a73Seth Forshee * out misidentified bitmap packets, we reject anything with this 50801ce661fc83005947dc958a5739c153843af8a73Seth Forshee * bit set. 50901ce661fc83005947dc958a5739c153843af8a73Seth Forshee */ 51001ce661fc83005947dc958a5739c153843af8a73Seth Forshee if (packet[0] & 0x40) 51101ce661fc83005947dc958a5739c153843af8a73Seth Forshee return; 51201ce661fc83005947dc958a5739c153843af8a73Seth Forshee 51301ce661fc83005947dc958a5739c153843af8a73Seth Forshee if (!priv->multi_packet && (packet[4] & 0x40)) { 51425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee priv->multi_packet = 1; 51501ce661fc83005947dc958a5739c153843af8a73Seth Forshee memcpy(priv->multi_data, packet, sizeof(priv->multi_data)); 51601ce661fc83005947dc958a5739c153843af8a73Seth Forshee return; 51701ce661fc83005947dc958a5739c153843af8a73Seth Forshee } 51801ce661fc83005947dc958a5739c153843af8a73Seth Forshee 51901ce661fc83005947dc958a5739c153843af8a73Seth Forshee priv->multi_packet = 0; 52025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 52125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee left = packet[3] & 0x01; 52225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee right = packet[3] & 0x02; 52325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee middle = packet[3] & 0x04; 52425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 52525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee x = ((packet[1] & 0x7f) << 4) | ((packet[4] & 0x30) >> 2) | 52625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee ((packet[0] & 0x30) >> 4); 52725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee y = ((packet[2] & 0x7f) << 4) | (packet[4] & 0x0f); 52825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee z = packet[5] & 0x7f; 52925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 53025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee /* 53125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * Sometimes the hardware sends a single packet with z = 0 53225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * in the middle of a stream. Real releases generate packets 53325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * with x, y, and z all zero, so these seem to be flukes. 53425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * Ignore them. 53525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee */ 53625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (x && y && !z) 53725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return; 53825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 53901ce661fc83005947dc958a5739c153843af8a73Seth Forshee /* 54001ce661fc83005947dc958a5739c153843af8a73Seth Forshee * If we don't have MT data or the bitmaps were empty, we have 54101ce661fc83005947dc958a5739c153843af8a73Seth Forshee * to rely on ST data. 54201ce661fc83005947dc958a5739c153843af8a73Seth Forshee */ 54301ce661fc83005947dc958a5739c153843af8a73Seth Forshee if (!fingers) { 54401ce661fc83005947dc958a5739c153843af8a73Seth Forshee x1 = x; 54501ce661fc83005947dc958a5739c153843af8a73Seth Forshee y1 = y; 54601ce661fc83005947dc958a5739c153843af8a73Seth Forshee fingers = z > 0 ? 1 : 0; 54701ce661fc83005947dc958a5739c153843af8a73Seth Forshee } 54801ce661fc83005947dc958a5739c153843af8a73Seth Forshee 54925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (z >= 64) 55025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee input_report_key(dev, BTN_TOUCH, 1); 55125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee else 55225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee input_report_key(dev, BTN_TOUCH, 0); 55325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 55401ce661fc83005947dc958a5739c153843af8a73Seth Forshee alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2); 55501ce661fc83005947dc958a5739c153843af8a73Seth Forshee 55601ce661fc83005947dc958a5739c153843af8a73Seth Forshee input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); 55701ce661fc83005947dc958a5739c153843af8a73Seth Forshee input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); 55801ce661fc83005947dc958a5739c153843af8a73Seth Forshee input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); 55901ce661fc83005947dc958a5739c153843af8a73Seth Forshee input_report_key(dev, BTN_TOOL_QUADTAP, fingers == 4); 56001ce661fc83005947dc958a5739c153843af8a73Seth Forshee 56101ce661fc83005947dc958a5739c153843af8a73Seth Forshee input_report_key(dev, BTN_LEFT, left); 56201ce661fc83005947dc958a5739c153843af8a73Seth Forshee input_report_key(dev, BTN_RIGHT, right); 56301ce661fc83005947dc958a5739c153843af8a73Seth Forshee input_report_key(dev, BTN_MIDDLE, middle); 56401ce661fc83005947dc958a5739c153843af8a73Seth Forshee 56525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (z > 0) { 56625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee input_report_abs(dev, ABS_X, x); 56725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee input_report_abs(dev, ABS_Y, y); 56825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } 56925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee input_report_abs(dev, ABS_PRESSURE, z); 57025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 57125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee input_sync(dev); 57225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 57325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) { 57425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee left = packet[3] & 0x10; 57525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee right = packet[3] & 0x20; 57625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee middle = packet[3] & 0x40; 57725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 57825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee input_report_key(dev2, BTN_LEFT, left); 57925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee input_report_key(dev2, BTN_RIGHT, right); 58025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee input_report_key(dev2, BTN_MIDDLE, middle); 58125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee input_sync(dev2); 58225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } 58325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee} 58425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 58525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forsheestatic void alps_process_packet_v3(struct psmouse *psmouse) 58625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee{ 58725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee unsigned char *packet = psmouse->packet; 58825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 58925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee /* 59025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * v3 protocol packets come in three types, two representing 59125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * touchpad data and one representing trackstick data. 59225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * Trackstick packets seem to be distinguished by always 59325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * having 0x3f in the last byte. This value has never been 59425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * observed in the last byte of either of the other types 59525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * of packets. 59625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee */ 59725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (packet[5] == 0x3f) { 59825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee alps_process_trackstick_packet_v3(psmouse); 59925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return; 60025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } 60125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 60225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee alps_process_touchpad_packet_v3(psmouse); 60325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee} 60425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 60525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forsheestatic void alps_process_packet_v4(struct psmouse *psmouse) 60625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee{ 60725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee unsigned char *packet = psmouse->packet; 60825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee struct input_dev *dev = psmouse->dev; 60925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee int x, y, z; 61025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee int left, right; 61125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 61225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee left = packet[4] & 0x01; 61325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee right = packet[4] & 0x02; 61425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 61525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) | 61625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee ((packet[0] & 0x30) >> 4); 61725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f); 61825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee z = packet[5] & 0x7f; 61925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 62025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (z >= 64) 62125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee input_report_key(dev, BTN_TOUCH, 1); 62225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee else 62325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee input_report_key(dev, BTN_TOUCH, 0); 62425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 62525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (z > 0) { 62625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee input_report_abs(dev, ABS_X, x); 62725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee input_report_abs(dev, ABS_Y, y); 62825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } 62925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee input_report_abs(dev, ABS_PRESSURE, z); 63025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 63125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee input_report_key(dev, BTN_TOOL_FINGER, z > 0); 63225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee input_report_key(dev, BTN_LEFT, left); 63325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee input_report_key(dev, BTN_RIGHT, right); 63425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 63525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee input_sync(dev); 63625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee} 63725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 63825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forsheestatic void alps_process_packet(struct psmouse *psmouse) 63925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee{ 64025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee struct alps_data *priv = psmouse->private; 64125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee const struct alps_model_info *model = priv->i; 64225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 64325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee switch (model->proto_version) { 64425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee case ALPS_PROTO_V1: 64525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee case ALPS_PROTO_V2: 64625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee alps_process_packet_v1_v2(psmouse); 64725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee break; 64825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee case ALPS_PROTO_V3: 64925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee alps_process_packet_v3(psmouse); 65025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee break; 65125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee case ALPS_PROTO_V4: 65225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee alps_process_packet_v4(psmouse); 65325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee break; 65425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } 65525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee} 65625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 6571d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapferstatic void alps_report_bare_ps2_packet(struct psmouse *psmouse, 6581d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer unsigned char packet[], 6591d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer bool report_buttons) 6601d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer{ 6611d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer struct alps_data *priv = psmouse->private; 6621d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer struct input_dev *dev2 = priv->dev2; 6631d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 6641d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer if (report_buttons) 6651d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer alps_report_buttons(psmouse, dev2, psmouse->dev, 6661d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer packet[0] & 1, packet[0] & 2, packet[0] & 4); 6671d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 6681d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer input_report_rel(dev2, REL_X, 6691d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0); 6701d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer input_report_rel(dev2, REL_Y, 6711d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer packet[2] ? ((packet[0] << 3) & 0x100) - packet[2] : 0); 6721d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 6731d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer input_sync(dev2); 6741d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer} 6751d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 6761d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapferstatic psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse) 6771d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer{ 6781d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer struct alps_data *priv = psmouse->private; 6791d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 6801d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer if (psmouse->pktcnt < 6) 6811d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer return PSMOUSE_GOOD_DATA; 6821d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 6831d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer if (psmouse->pktcnt == 6) { 6841d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer /* 6851d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * Start a timer to flush the packet if it ends up last 6861d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * 6-byte packet in the stream. Timer needs to fire 6871d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * psmouse core times out itself. 20 ms should be enough 6881d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * to decide if we are getting more data or not. 6891d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer */ 6901d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer mod_timer(&priv->timer, jiffies + msecs_to_jiffies(20)); 6911d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer return PSMOUSE_GOOD_DATA; 6921d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer } 6931d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 6941d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer del_timer(&priv->timer); 6951d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 6961d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer if (psmouse->packet[6] & 0x80) { 6971d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 6981d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer /* 6991d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * Highest bit is set - that means we either had 7001d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * complete ALPS packet and this is start of the 7011d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * next packet or we got garbage. 7021d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer */ 7031d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 7041d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer if (((psmouse->packet[3] | 7051d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer psmouse->packet[4] | 7061d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer psmouse->packet[5]) & 0x80) || 7071d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer (!alps_is_valid_first_byte(priv->i, psmouse->packet[6]))) { 708b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse_dbg(psmouse, 709b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov "refusing packet %x %x %x %x (suspected interleaved ps/2)\n", 710b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse->packet[3], psmouse->packet[4], 711b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse->packet[5], psmouse->packet[6]); 7121d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer return PSMOUSE_BAD_DATA; 7131d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer } 7141d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 7151d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer alps_process_packet(psmouse); 7161d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 7171d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer /* Continue with the next packet */ 7181d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer psmouse->packet[0] = psmouse->packet[6]; 7191d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer psmouse->pktcnt = 1; 7201d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 7211d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer } else { 7221d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 7231d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer /* 7241d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * High bit is 0 - that means that we indeed got a PS/2 7251d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * packet in the middle of ALPS packet. 7261d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * 7271d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * There is also possibility that we got 6-byte ALPS 7281d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * packet followed by 3-byte packet from trackpoint. We 7291d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * can not distinguish between these 2 scenarios but 730b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov * because the latter is unlikely to happen in course of 7311d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * normal operation (user would need to press all 7321d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * buttons on the pad and start moving trackpoint 7331d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * without touching the pad surface) we assume former. 7341d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * Even if we are wrong the wost thing that would happen 7351d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * the cursor would jump but we should not get protocol 736b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov * de-synchronization. 7371d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer */ 7381d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 7391d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer alps_report_bare_ps2_packet(psmouse, &psmouse->packet[3], 7401d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer false); 7411d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 7421d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer /* 7431d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * Continue with the standard ALPS protocol handling, 7441d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * but make sure we won't process it as an interleaved 7451d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * packet again, which may happen if all buttons are 7461d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * pressed. To avoid this let's reset the 4th bit which 7471d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * is normally 1. 7481d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer */ 7491d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer psmouse->packet[3] = psmouse->packet[6] & 0xf7; 7501d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer psmouse->pktcnt = 4; 7511d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer } 7521d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 7531d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer return PSMOUSE_GOOD_DATA; 7541d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer} 7551d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 7561d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapferstatic void alps_flush_packet(unsigned long data) 7571d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer{ 7581d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer struct psmouse *psmouse = (struct psmouse *)data; 7591d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 7601d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer serio_pause_rx(psmouse->ps2dev.serio); 7611d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 762b46615fe9215214ac00e26d35fc54dbe1c510803Seth Forshee if (psmouse->pktcnt == psmouse->pktsize) { 7631d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 7641d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer /* 7651d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * We did not any more data in reasonable amount of time. 7661d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * Validate the last 3 bytes and process as a standard 7671d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * ALPS packet. 7681d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer */ 7691d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer if ((psmouse->packet[3] | 7701d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer psmouse->packet[4] | 7711d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer psmouse->packet[5]) & 0x80) { 772b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse_dbg(psmouse, 773b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov "refusing packet %x %x %x (suspected interleaved ps/2)\n", 774b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse->packet[3], psmouse->packet[4], 775b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse->packet[5]); 7761d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer } else { 7771d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer alps_process_packet(psmouse); 7781d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer } 7791d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer psmouse->pktcnt = 0; 7801d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer } 7811d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 7821d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer serio_continue_rx(psmouse->ps2dev.serio); 7831d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer} 7841d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 7857d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic psmouse_ret_t alps_process_byte(struct psmouse *psmouse) 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct alps_data *priv = psmouse->private; 7881d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer const struct alps_model_info *model = priv->i; 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */ 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (psmouse->pktcnt == 3) { 7921d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer alps_report_bare_ps2_packet(psmouse, psmouse->packet, 7931d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer true); 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return PSMOUSE_FULL_PACKET; 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return PSMOUSE_GOOD_DATA; 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7991d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer /* Check for PS/2 packet stuffed in the middle of ALPS packet. */ 8001d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 8011d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer if ((model->flags & ALPS_PS2_INTERLEAVED) && 8021d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer psmouse->pktcnt >= 4 && (psmouse->packet[3] & 0x0f) == 0x0f) { 8031d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer return alps_handle_interleaved_ps2(psmouse); 8041d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer } 8051d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 8061d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer if (!alps_is_valid_first_byte(model, psmouse->packet[0])) { 807b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse_dbg(psmouse, 808b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov "refusing packet[0] = %x (mask0 = %x, byte0 = %x)\n", 809b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse->packet[0], model->mask0, model->byte0); 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return PSMOUSE_BAD_DATA; 8111d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer } 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 813b46615fe9215214ac00e26d35fc54dbe1c510803Seth Forshee /* Bytes 2 - pktsize should have 0 in the highest bit */ 814b46615fe9215214ac00e26d35fc54dbe1c510803Seth Forshee if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= psmouse->pktsize && 8151d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) { 816b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse_dbg(psmouse, "refusing packet[%i] = %x\n", 817b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse->pktcnt - 1, 818b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse->packet[psmouse->pktcnt - 1]); 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return PSMOUSE_BAD_DATA; 8201d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer } 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 822b46615fe9215214ac00e26d35fc54dbe1c510803Seth Forshee if (psmouse->pktcnt == psmouse->pktsize) { 8237d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells alps_process_packet(psmouse); 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return PSMOUSE_FULL_PACKET; 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return PSMOUSE_GOOD_DATA; 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 83025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forsheestatic int alps_command_mode_send_nibble(struct psmouse *psmouse, int nibble) 83125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee{ 83225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee struct ps2dev *ps2dev = &psmouse->ps2dev; 83325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee struct alps_data *priv = psmouse->private; 83425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee int command; 83525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee unsigned char *param; 83625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee unsigned char dummy[4]; 83725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 83825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee BUG_ON(nibble > 0xf); 83925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 84025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee command = priv->nibble_commands[nibble].command; 84125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee param = (command & 0x0f00) ? 84225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee dummy : (unsigned char *)&priv->nibble_commands[nibble].data; 84325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 84425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (ps2_command(ps2dev, param, command)) 84525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return -1; 84625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 84725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return 0; 84825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee} 84925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 85025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forsheestatic int alps_command_mode_set_addr(struct psmouse *psmouse, int addr) 85125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee{ 85225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee struct ps2dev *ps2dev = &psmouse->ps2dev; 85325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee struct alps_data *priv = psmouse->private; 85425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee int i, nibble; 85525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 85625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (ps2_command(ps2dev, NULL, priv->addr_command)) 85725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return -1; 85825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 85925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee for (i = 12; i >= 0; i -= 4) { 86025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee nibble = (addr >> i) & 0xf; 86125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_command_mode_send_nibble(psmouse, nibble)) 86225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return -1; 86325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } 86425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 86525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return 0; 86625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee} 86725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 86825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forsheestatic int __alps_command_mode_read_reg(struct psmouse *psmouse, int addr) 86925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee{ 87025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee struct ps2dev *ps2dev = &psmouse->ps2dev; 87125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee unsigned char param[4]; 87225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 87325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) 87425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return -1; 87525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 87625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee /* 87725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * The address being read is returned in the first two bytes 87825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * of the result. Check that this address matches the expected 87925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * address. 88025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee */ 88125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (addr != ((param[0] << 8) | param[1])) 88225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return -1; 88325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 88425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return param[2]; 88525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee} 88625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 88725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forsheestatic int alps_command_mode_read_reg(struct psmouse *psmouse, int addr) 88825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee{ 88925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_command_mode_set_addr(psmouse, addr)) 89025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return -1; 89125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return __alps_command_mode_read_reg(psmouse, addr); 89225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee} 89325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 89425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forsheestatic int __alps_command_mode_write_reg(struct psmouse *psmouse, u8 value) 89525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee{ 89625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_command_mode_send_nibble(psmouse, (value >> 4) & 0xf)) 89725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return -1; 89825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_command_mode_send_nibble(psmouse, value & 0xf)) 89925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return -1; 90025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return 0; 90125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee} 90225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 90325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forsheestatic int alps_command_mode_write_reg(struct psmouse *psmouse, int addr, 90425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee u8 value) 90525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee{ 90625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_command_mode_set_addr(psmouse, addr)) 90725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return -1; 90825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return __alps_command_mode_write_reg(psmouse, value); 90925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee} 91025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 91125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forsheestatic int alps_enter_command_mode(struct psmouse *psmouse, 91225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee unsigned char *resp) 91325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee{ 91425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee unsigned char param[4]; 91525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee struct ps2dev *ps2dev = &psmouse->ps2dev; 91625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 91725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) || 91825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) || 91925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) || 92025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) { 92125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee psmouse_err(psmouse, "failed to enter command mode\n"); 92225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return -1; 92325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } 92425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 92525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (param[0] != 0x88 && param[1] != 0x07) { 92625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee psmouse_dbg(psmouse, 92725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee "unknown response while entering command mode: %2.2x %2.2x %2.2x\n", 92825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee param[0], param[1], param[2]); 92925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return -1; 93025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } 93125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 93225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (resp) 93325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee *resp = param[2]; 93425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return 0; 93525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee} 93625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 93725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forsheestatic inline int alps_exit_command_mode(struct psmouse *psmouse) 93825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee{ 93925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee struct ps2dev *ps2dev = &psmouse->ps2dev; 94025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM)) 94125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return -1; 94225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return 0; 94325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee} 94425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 945e38de678f6b19be3e46a678ec4deeaa7fa0fc140Helge Dellerstatic const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version) 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ps2dev *ps2dev = &psmouse->ps2dev; 948e38de678f6b19be3e46a678ec4deeaa7fa0fc140Helge Deller static const unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 }; 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char param[4]; 95025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee const struct alps_model_info *model = NULL; 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * First try "E6 report". 95599c90ab31fad855b9da9dee3a5aa6c27f263e9d6Akio Idehara * ALPS should return 0,0,10 or 0,0,100 if no buttons are pressed. 95699c90ab31fad855b9da9dee3a5aa6c27f263e9d6Akio Idehara * The bits 0-2 of the first byte will be 1s if some buttons are 95799c90ab31fad855b9da9dee3a5aa6c27f263e9d6Akio Idehara * pressed. 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds param[0] = 0; 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) || 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11)) 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds param[0] = param[1] = param[2] = 0xff; 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 970b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse_dbg(psmouse, "E6 report: %2.2x %2.2x %2.2x", 971b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov param[0], param[1], param[2]); 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 97399c90ab31fad855b9da9dee3a5aa6c27f263e9d6Akio Idehara if ((param[0] & 0xf8) != 0 || param[1] != 0 || 97499c90ab31fad855b9da9dee3a5aa6c27f263e9d6Akio Idehara (param[2] != 10 && param[2] != 100)) 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Now try "E7 report". Allowed responses are in 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * alps_model_data[].signature 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds param[0] = 0; 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) || 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21)) 9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds param[0] = param[1] = param[2] = 0xff; 9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) 9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 992b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse_dbg(psmouse, "E7 report: %2.2x %2.2x %2.2x", 993b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov param[0], param[1], param[2]); 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9951e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov if (version) { 9961e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov for (i = 0; i < ARRAY_SIZE(rates) && param[2] != rates[i]; i++) 9971e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov /* empty */; 9981e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov *version = (param[0] << 8) | (param[1] << 4) | i; 9991e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov } 10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 100125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) { 10021e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov if (!memcmp(param, alps_model_data[i].signature, 100325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee sizeof(alps_model_data[i].signature))) { 100425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee model = alps_model_data + i; 100525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee break; 100625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } 100725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 100925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (model && model->proto_version > ALPS_PROTO_V2) { 101025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee /* 101125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * Need to check command mode response to identify 101225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * model 101325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee */ 101425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee model = NULL; 101525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_enter_command_mode(psmouse, param)) { 101625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee psmouse_warn(psmouse, 101725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee "touchpad failed to enter command mode\n"); 101825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } else { 101925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) { 102025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_model_data[i].proto_version > ALPS_PROTO_V2 && 102125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee alps_model_data[i].command_mode_resp == param[0]) { 102225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee model = alps_model_data + i; 102325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee break; 102425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } 102525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } 102625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee alps_exit_command_mode(psmouse); 102725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 102825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (!model) 102925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee psmouse_dbg(psmouse, 103025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee "Unknown command mode response %2.2x\n", 103125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee param[0]); 103225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } 103325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } 103425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 103525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return model; 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For DualPoint devices select the device that should respond to 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * subsequent commands. It looks like glidepad is behind stickpointer, 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * I'd thought it would be other way around... 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 104325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forsheestatic int alps_passthrough_mode_v2(struct psmouse *psmouse, bool enable) 10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ps2dev *ps2dev = &psmouse->ps2dev; 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11; 10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ps2_command(ps2dev, NULL, cmd) || 10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, cmd) || 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, cmd) || 10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE)) 10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* we may get 3 more bytes, just ignore them */ 1055c611763d048990de5cdf848d97af6392f8fa7430Dmitry Torokhov ps2_drain(ps2dev, 3, 100); 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 106025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forsheestatic int alps_absolute_mode_v1_v2(struct psmouse *psmouse) 10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ps2dev *ps2dev = &psmouse->ps2dev; 10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Try ALPS magic knock - 4 disable before enable */ 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || 10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE)) 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Switch mouse to poll (remote) mode so motion data will not 10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * get in our way 10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETPOLL); 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int alps_get_status(struct psmouse *psmouse, char *param) 10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ps2dev *ps2dev = &psmouse->ps2dev; 10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Get status: 0xF5 0xF5 0xF5 0xE9 */ 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1090b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse_dbg(psmouse, "Status: %2.2x %2.2x %2.2x", 1091b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov param[0], param[1], param[2]); 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Turn touchpad tapping on or off. The sequences are: 10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0xE9 0xF5 0xF5 0xF3 0x0A to enable, 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0xE9 0xF5 0xF5 0xE8 0x00 to disable. 11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * My guess that 0xE9 (GetInfo) is here as a sync point. 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For models that also have stickpointer (DualPoints) its tapping 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is controlled separately (0xE6 0xE6 0xE6 0xF3 0x14|0x0A) but 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we don't fiddle with it. 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int alps_tap_mode(struct psmouse *psmouse, int enable) 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ps2dev *ps2dev = &psmouse->ps2dev; 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cmd = enable ? PSMOUSE_CMD_SETRATE : PSMOUSE_CMD_SETRES; 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char tap_arg = enable ? 0x0A : 0x00; 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char param[4]; 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO) || 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, &tap_arg, cmd)) 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (alps_get_status(psmouse, param)) 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1124f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov/* 1125f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov * alps_poll() - poll the touchpad for current motion packet. 1126f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov * Used in resync. 1127f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov */ 1128f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhovstatic int alps_poll(struct psmouse *psmouse) 1129f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov{ 1130f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov struct alps_data *priv = psmouse->private; 1131b46615fe9215214ac00e26d35fc54dbe1c510803Seth Forshee unsigned char buf[sizeof(psmouse->packet)]; 1132b7802c5c1ea9563f3746bea09c214ccedc8600f4Dmitry Torokhov bool poll_failed; 1133f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov 1134f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov if (priv->i->flags & ALPS_PASS) 113525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee alps_passthrough_mode_v2(psmouse, true); 1136f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov 1137f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov poll_failed = ps2_command(&psmouse->ps2dev, buf, 1138f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)) < 0; 1139f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov 1140f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov if (priv->i->flags & ALPS_PASS) 114125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee alps_passthrough_mode_v2(psmouse, false); 1142f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov 1143f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov if (poll_failed || (buf[0] & priv->i->mask0) != priv->i->byte0) 1144f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov return -1; 1145f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov 1146f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov if ((psmouse->badbyte & 0xc8) == 0x08) { 1147f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov/* 1148f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov * Poll the track stick ... 1149f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov */ 1150f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov if (ps2_command(&psmouse->ps2dev, buf, PSMOUSE_CMD_POLL | (3 << 8))) 1151f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov return -1; 1152f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov } 1153f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov 1154f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov memcpy(psmouse->packet, buf, sizeof(buf)); 1155f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov return 0; 1156f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov} 1157f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov 115825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forsheestatic int alps_hw_init_v1_v2(struct psmouse *psmouse) 11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct alps_data *priv = psmouse->private; 116171bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky const struct alps_model_info *model = priv->i; 1162f3a5c73d5ecb40909db662c4d2ace497b25c5940Dmitry Torokhov 116371bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if ((model->flags & ALPS_PASS) && 116425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee alps_passthrough_mode_v2(psmouse, true)) { 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 1166b7802c5c1ea9563f3746bea09c214ccedc8600f4Dmitry Torokhov } 11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1168b7802c5c1ea9563f3746bea09c214ccedc8600f4Dmitry Torokhov if (alps_tap_mode(psmouse, true)) { 1169b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse_warn(psmouse, "Failed to enable hardware tapping\n"); 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 1171963f626d46d5caeeb3cff29998d8a64df5b25591Peter Osterlund } 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 117325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_absolute_mode_v1_v2(psmouse)) { 1174b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse_err(psmouse, "Failed to enable absolute mode\n"); 11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 117871bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if ((model->flags & ALPS_PASS) && 117925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee alps_passthrough_mode_v2(psmouse, false)) { 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 1181b7802c5c1ea9563f3746bea09c214ccedc8600f4Dmitry Torokhov } 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11831e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov /* ALPS needs stream mode, otherwise it won't report any data */ 11841e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSTREAM)) { 1185b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse_err(psmouse, "Failed to enable stream mode\n"); 11861e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov return -1; 11871e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov } 11881e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov 11891e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov return 0; 11901e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov} 11911e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov 119225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee/* 119325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * Enable or disable passthrough mode to the trackstick. Must be in 119425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * command mode when calling this function. 119525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee */ 119625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forsheestatic int alps_passthrough_mode_v3(struct psmouse *psmouse, bool enable) 119725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee{ 119825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee int reg_val; 119925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 120025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee reg_val = alps_command_mode_read_reg(psmouse, 0x0008); 120125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (reg_val == -1) 120225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return -1; 120325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 120425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (enable) 120525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee reg_val |= 0x01; 120625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee else 120725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee reg_val &= ~0x01; 120825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 120925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (__alps_command_mode_write_reg(psmouse, reg_val)) 121025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return -1; 121125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 121225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return 0; 121325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee} 121425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 121525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee/* Must be in command mode when calling this function */ 121625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forsheestatic int alps_absolute_mode_v3(struct psmouse *psmouse) 121725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee{ 121825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee int reg_val; 121925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 122025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee reg_val = alps_command_mode_read_reg(psmouse, 0x0004); 122125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (reg_val == -1) 122225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return -1; 122325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 122425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee reg_val |= 0x06; 122525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (__alps_command_mode_write_reg(psmouse, reg_val)) 122625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return -1; 122725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 122825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return 0; 122925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee} 123025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 123125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forsheestatic int alps_hw_init_v3(struct psmouse *psmouse) 123225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee{ 123325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee struct alps_data *priv = psmouse->private; 123425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee struct ps2dev *ps2dev = &psmouse->ps2dev; 123525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee int reg_val; 123625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee unsigned char param[4]; 123725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 123825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee priv->nibble_commands = alps_v3_nibble_commands; 123925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee priv->addr_command = PSMOUSE_CMD_RESET_WRAP; 124025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 124125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_enter_command_mode(psmouse, NULL)) 124225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 124325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 124425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee /* Check for trackstick */ 124525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee reg_val = alps_command_mode_read_reg(psmouse, 0x0008); 124625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (reg_val == -1) 124725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 124825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (reg_val & 0x80) { 124925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_passthrough_mode_v3(psmouse, true)) 125025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 125125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_exit_command_mode(psmouse)) 125225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 125325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 125425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee /* 125525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * E7 report for the trackstick 125625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * 125725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * There have been reports of failures to seem to trace back 125825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * to the above trackstick check failing. When these occur 125925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * this E7 report fails, so when that happens we continue 126025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * with the assumption that there isn't a trackstick after 126125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * all. 126225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee */ 126325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee param[0] = 0x64; 126425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || 126525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || 126625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || 126725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) { 126825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee psmouse_warn(psmouse, "trackstick E7 report failed\n"); 126925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } else { 127025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee psmouse_dbg(psmouse, 127125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee "trackstick E7 report: %2.2x %2.2x %2.2x\n", 127225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee param[0], param[1], param[2]); 127325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 127425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee /* 127525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * Not sure what this does, but it is absolutely 127625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * essential. Without it, the touchpad does not 127725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * work at all and the trackstick just emits normal 127825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * PS/2 packets. 127925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee */ 128025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || 128125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || 128225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || 128325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee alps_command_mode_send_nibble(psmouse, 0x9) || 128425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee alps_command_mode_send_nibble(psmouse, 0x4)) { 128525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee psmouse_err(psmouse, 128625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee "Error sending magic E6 sequence\n"); 128725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error_passthrough; 128825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } 128925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } 129025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 129125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_enter_command_mode(psmouse, NULL)) 129225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error_passthrough; 129325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_passthrough_mode_v3(psmouse, false)) 129425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 129525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } 129625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 129725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_absolute_mode_v3(psmouse)) { 129825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee psmouse_err(psmouse, "Failed to enter absolute mode\n"); 129925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 130025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } 130125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 130225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee reg_val = alps_command_mode_read_reg(psmouse, 0x0006); 130325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (reg_val == -1) 130425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 130525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (__alps_command_mode_write_reg(psmouse, reg_val | 0x01)) 130625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 130725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 130825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee reg_val = alps_command_mode_read_reg(psmouse, 0x0007); 130925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (reg_val == -1) 131025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 131125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (__alps_command_mode_write_reg(psmouse, reg_val | 0x01)) 131225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 131325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 131425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_command_mode_read_reg(psmouse, 0x0144) == -1) 131525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 131625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (__alps_command_mode_write_reg(psmouse, 0x04)) 131725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 131825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 131925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_command_mode_read_reg(psmouse, 0x0159) == -1) 132025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 132125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (__alps_command_mode_write_reg(psmouse, 0x03)) 132225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 132325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 132425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_command_mode_read_reg(psmouse, 0x0163) == -1) 132525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 132625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_command_mode_write_reg(psmouse, 0x0163, 0x03)) 132725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 132825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 132925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_command_mode_read_reg(psmouse, 0x0162) == -1) 133025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 133125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_command_mode_write_reg(psmouse, 0x0162, 0x04)) 133225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 133325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 133425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee /* 133525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * This ensures the trackstick packets are in the format 133625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * supported by this driver. If bit 1 isn't set the packet 133725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * format is different. 133825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee */ 133925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_command_mode_write_reg(psmouse, 0x0008, 0x82)) 134025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 134125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 134225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee alps_exit_command_mode(psmouse); 134325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 134425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee /* Set rate and enable data reporting */ 134525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee param[0] = 0x64; 134625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE) || 134725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE)) { 134825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee psmouse_err(psmouse, "Failed to enable data reporting\n"); 134925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return -1; 135025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } 135125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 135225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return 0; 135325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 135425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forsheeerror_passthrough: 135525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee /* Something failed while in passthrough mode, so try to get out */ 135625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (!alps_enter_command_mode(psmouse, NULL)) 135725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee alps_passthrough_mode_v3(psmouse, false); 135825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forsheeerror: 135925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee /* 136025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * Leaving the touchpad in command mode will essentially render 136125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * it unusable until the machine reboots, so exit it here just 136225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * to be safe 136325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee */ 136425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee alps_exit_command_mode(psmouse); 136525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return -1; 136625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee} 136725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 136825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee/* Must be in command mode when calling this function */ 136925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forsheestatic int alps_absolute_mode_v4(struct psmouse *psmouse) 137025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee{ 137125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee int reg_val; 137225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 137325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee reg_val = alps_command_mode_read_reg(psmouse, 0x0004); 137425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (reg_val == -1) 137525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return -1; 137625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 137725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee reg_val |= 0x02; 137825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (__alps_command_mode_write_reg(psmouse, reg_val)) 137925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return -1; 138025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 138125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return 0; 138225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee} 138325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 138425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forsheestatic int alps_hw_init_v4(struct psmouse *psmouse) 138525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee{ 138625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee struct alps_data *priv = psmouse->private; 138725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee struct ps2dev *ps2dev = &psmouse->ps2dev; 138825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee unsigned char param[4]; 138925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 139025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee priv->nibble_commands = alps_v4_nibble_commands; 139125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee priv->addr_command = PSMOUSE_CMD_DISABLE; 139225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 139325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_enter_command_mode(psmouse, NULL)) 139425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 139525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 139625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_absolute_mode_v4(psmouse)) { 139725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee psmouse_err(psmouse, "Failed to enter absolute mode\n"); 139825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 139925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } 140025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 140125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_command_mode_write_reg(psmouse, 0x0007, 0x8c)) 140225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 140325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 140425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_command_mode_write_reg(psmouse, 0x0149, 0x03)) 140525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 140625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 140725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_command_mode_write_reg(psmouse, 0x0160, 0x03)) 140825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 140925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 141025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_command_mode_write_reg(psmouse, 0x017f, 0x15)) 141125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 141225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 141325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_command_mode_write_reg(psmouse, 0x0151, 0x01)) 141425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 141525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 141625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_command_mode_write_reg(psmouse, 0x0168, 0x03)) 141725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 141825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 141925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_command_mode_write_reg(psmouse, 0x014a, 0x03)) 142025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 142125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 142225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (alps_command_mode_write_reg(psmouse, 0x0161, 0x03)) 142325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee goto error; 142425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 142525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee alps_exit_command_mode(psmouse); 142625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 142725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee /* 142825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * This sequence changes the output from a 9-byte to an 142925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * 8-byte format. All the same data seems to be present, 143025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * just in a more compact format. 143125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee */ 143225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee param[0] = 0xc8; 143325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee param[1] = 0x64; 143425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee param[2] = 0x50; 143525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) || 143625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee ps2_command(ps2dev, ¶m[1], PSMOUSE_CMD_SETRATE) || 143725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee ps2_command(ps2dev, ¶m[2], PSMOUSE_CMD_SETRATE) || 143825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee ps2_command(ps2dev, param, PSMOUSE_CMD_GETID)) 143925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return -1; 144025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 144125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee /* Set rate and enable data reporting */ 144225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee param[0] = 0x64; 144325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE) || 144425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE)) { 144525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee psmouse_err(psmouse, "Failed to enable data reporting\n"); 144625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return -1; 144725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } 144825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 144925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return 0; 145025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 145125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forsheeerror: 145225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee /* 145325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * Leaving the touchpad in command mode will essentially render 145425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * it unusable until the machine reboots, so exit it here just 145525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee * to be safe 145625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee */ 145725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee alps_exit_command_mode(psmouse); 145825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return -1; 145925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee} 146025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 146125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forsheestatic int alps_hw_init(struct psmouse *psmouse) 146225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee{ 146325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee struct alps_data *priv = psmouse->private; 146425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee const struct alps_model_info *model = priv->i; 146525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee int ret = -1; 146625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 146725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee switch (model->proto_version) { 146825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee case ALPS_PROTO_V1: 146925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee case ALPS_PROTO_V2: 147025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee ret = alps_hw_init_v1_v2(psmouse); 147125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee break; 147225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee case ALPS_PROTO_V3: 147325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee ret = alps_hw_init_v3(psmouse); 147425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee break; 147525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee case ALPS_PROTO_V4: 147625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee ret = alps_hw_init_v4(psmouse); 147725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee break; 147825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } 147925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 148025bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee return ret; 148125bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee} 148225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 14831e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhovstatic int alps_reconnect(struct psmouse *psmouse) 14841e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov{ 148571bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky const struct alps_model_info *model; 148671bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky 14871e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov psmouse_reset(psmouse); 14881e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov 148971bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky model = alps_get_model(psmouse, NULL); 149071bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if (!model) 14911e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov return -1; 14921e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov 149371bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky return alps_hw_init(psmouse); 14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void alps_disconnect(struct psmouse *psmouse) 14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct alps_data *priv = psmouse->private; 14992e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov 15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psmouse_reset(psmouse); 15011d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer del_timer_sync(&priv->timer); 15022e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov input_unregister_device(priv->dev2); 15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(priv); 15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint alps_init(struct psmouse *psmouse) 15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct alps_data *priv; 150971bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky const struct alps_model_info *model; 15102e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov struct input_dev *dev1 = psmouse->dev, *dev2; 15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int version; 15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1513f42649e84831efc69d5f621f1c36a39b4e384a99Dmitry Torokhov priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL); 15142e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov dev2 = input_allocate_device(); 15152e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov if (!priv || !dev2) 15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto init_fail; 15172e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov 15182e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov priv->dev2 = dev2; 15191d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer setup_timer(&priv->timer, alps_flush_packet, (unsigned long)psmouse); 15201d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 15211e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov psmouse->private = priv; 15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 152325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee psmouse_reset(psmouse); 152425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 152571bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky model = alps_get_model(psmouse, &version); 152671bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if (!model) 152771bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky goto init_fail; 152871bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky 152971bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky priv->i = model; 153071bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky 153171bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if (alps_hw_init(psmouse)) 15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto init_fail; 15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15347105d2ea73e1391b681d0e1212c42f561c64d429Dmitry Torokhov /* 15357105d2ea73e1391b681d0e1212c42f561c64d429Dmitry Torokhov * Undo part of setup done for us by psmouse core since touchpad 15367105d2ea73e1391b681d0e1212c42f561c64d429Dmitry Torokhov * is not a relative device. 15377105d2ea73e1391b681d0e1212c42f561c64d429Dmitry Torokhov */ 15387105d2ea73e1391b681d0e1212c42f561c64d429Dmitry Torokhov __clear_bit(EV_REL, dev1->evbit); 15397105d2ea73e1391b681d0e1212c42f561c64d429Dmitry Torokhov __clear_bit(REL_X, dev1->relbit); 15407105d2ea73e1391b681d0e1212c42f561c64d429Dmitry Torokhov __clear_bit(REL_Y, dev1->relbit); 15417105d2ea73e1391b681d0e1212c42f561c64d429Dmitry Torokhov 15427105d2ea73e1391b681d0e1212c42f561c64d429Dmitry Torokhov /* 15437105d2ea73e1391b681d0e1212c42f561c64d429Dmitry Torokhov * Now set up our capabilities. 15447105d2ea73e1391b681d0e1212c42f561c64d429Dmitry Torokhov */ 15457b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby dev1->evbit[BIT_WORD(EV_KEY)] |= BIT_MASK(EV_KEY); 15467b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby dev1->keybit[BIT_WORD(BTN_TOUCH)] |= BIT_MASK(BTN_TOUCH); 15477b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby dev1->keybit[BIT_WORD(BTN_TOOL_FINGER)] |= BIT_MASK(BTN_TOOL_FINGER); 154871bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky dev1->keybit[BIT_WORD(BTN_LEFT)] |= 154971bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT); 15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15517b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS); 155225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 155325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee switch (model->proto_version) { 155425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee case ALPS_PROTO_V1: 155525bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee case ALPS_PROTO_V2: 155625bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0); 155725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0); 155825bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee break; 155925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee case ALPS_PROTO_V3: 156001ce661fc83005947dc958a5739c153843af8a73Seth Forshee set_bit(INPUT_PROP_SEMI_MT, dev1->propbit); 156101ce661fc83005947dc958a5739c153843af8a73Seth Forshee input_mt_init_slots(dev1, 2); 156201ce661fc83005947dc958a5739c153843af8a73Seth Forshee input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, ALPS_V3_X_MAX, 0, 0); 156301ce661fc83005947dc958a5739c153843af8a73Seth Forshee input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, ALPS_V3_Y_MAX, 0, 0); 156401ce661fc83005947dc958a5739c153843af8a73Seth Forshee 156501ce661fc83005947dc958a5739c153843af8a73Seth Forshee set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit); 156601ce661fc83005947dc958a5739c153843af8a73Seth Forshee set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit); 156701ce661fc83005947dc958a5739c153843af8a73Seth Forshee set_bit(BTN_TOOL_QUADTAP, dev1->keybit); 156801ce661fc83005947dc958a5739c153843af8a73Seth Forshee /* fall through */ 156925bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee case ALPS_PROTO_V4: 157001ce661fc83005947dc958a5739c153843af8a73Seth Forshee input_set_abs_params(dev1, ABS_X, 0, ALPS_V3_X_MAX, 0, 0); 157101ce661fc83005947dc958a5739c153843af8a73Seth Forshee input_set_abs_params(dev1, ABS_Y, 0, ALPS_V3_Y_MAX, 0, 0); 157225bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee break; 157325bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee } 157425bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee 15752e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0); 15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 157771bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if (model->flags & ALPS_WHEEL) { 15787b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby dev1->evbit[BIT_WORD(EV_REL)] |= BIT_MASK(EV_REL); 15797b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby dev1->relbit[BIT_WORD(REL_WHEEL)] |= BIT_MASK(REL_WHEEL); 15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 158271bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if (model->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { 15837b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby dev1->keybit[BIT_WORD(BTN_FORWARD)] |= BIT_MASK(BTN_FORWARD); 15847b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby dev1->keybit[BIT_WORD(BTN_BACK)] |= BIT_MASK(BTN_BACK); 15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 158771bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if (model->flags & ALPS_FOUR_BUTTONS) { 158871bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky dev1->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_0); 158971bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky dev1->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1); 159071bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky dev1->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2); 159171bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky dev1->keybit[BIT_WORD(BTN_3)] |= BIT_MASK(BTN_3); 159271bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky } else { 159371bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky dev1->keybit[BIT_WORD(BTN_MIDDLE)] |= BIT_MASK(BTN_MIDDLE); 159471bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky } 159571bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky 159608ffce4560e0133e10634b0dd85eecee11257a1cDmitry Torokhov snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys); 15972e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov dev2->phys = priv->phys; 159871bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky dev2->name = (model->flags & ALPS_DUALPOINT) ? "DualPoint Stick" : "PS/2 Mouse"; 15992e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov dev2->id.bustype = BUS_I8042; 16002e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov dev2->id.vendor = 0x0002; 16012e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov dev2->id.product = PSMOUSE_ALPS; 16022e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov dev2->id.version = 0x0000; 16031db3a3453f6915d6af322e3a1b25f7ab2c9d9a2bDmitry Torokhov dev2->dev.parent = &psmouse->ps2dev.serio->dev; 16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16057b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); 160671bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky dev2->relbit[BIT_WORD(REL_X)] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); 160771bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky dev2->keybit[BIT_WORD(BTN_LEFT)] = 160871bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); 16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1610f42649e84831efc69d5f621f1c36a39b4e384a99Dmitry Torokhov if (input_register_device(priv->dev2)) 1611f42649e84831efc69d5f621f1c36a39b4e384a99Dmitry Torokhov goto init_fail; 16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psmouse->protocol_handler = alps_process_byte; 1614f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov psmouse->poll = alps_poll; 16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psmouse->disconnect = alps_disconnect; 16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psmouse->reconnect = alps_reconnect; 161725bded7cd60fa460e520e9f819bd06f4c5cb53f0Seth Forshee psmouse->pktsize = model->proto_version == ALPS_PROTO_V4 ? 8 : 6; 16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1619f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov /* We are having trouble resyncing ALPS touchpads so disable it for now */ 1620f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov psmouse->resync_time = 0; 1621f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov 16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsinit_fail: 1625f42649e84831efc69d5f621f1c36a39b4e384a99Dmitry Torokhov psmouse_reset(psmouse); 16262e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov input_free_device(dev2); 16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(priv); 16281e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov psmouse->private = NULL; 16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1632b7802c5c1ea9563f3746bea09c214ccedc8600f4Dmitry Torokhovint alps_detect(struct psmouse *psmouse, bool set_properties) 16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int version; 1635e38de678f6b19be3e46a678ec4deeaa7fa0fc140Helge Deller const struct alps_model_info *model; 16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1637f42649e84831efc69d5f621f1c36a39b4e384a99Dmitry Torokhov model = alps_get_model(psmouse, &version); 1638f42649e84831efc69d5f621f1c36a39b4e384a99Dmitry Torokhov if (!model) 16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (set_properties) { 16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psmouse->vendor = "ALPS"; 1643968ac842c4946abcd6ae623414783548672177f5Dmitry Torokhov psmouse->name = model->flags & ALPS_DUALPOINT ? 1644968ac842c4946abcd6ae623414783548672177f5Dmitry Torokhov "DualPoint TouchPad" : "GlidePoint"; 16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psmouse->model = version; 16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1650