alps.c revision fa629ef5222193214da9a2b3c94369f79353bec9
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> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serio.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/libps2.h> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "psmouse.h" 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "alps.h" 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2671bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky#define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */ 2771bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky#define ALPS_PASS 0x04 /* device has a pass-through port */ 2871bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky 2971bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky#define ALPS_WHEEL 0x08 /* hardware wheel present */ 3071bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky#define ALPS_FW_BK_1 0x10 /* front & back buttons present */ 3171bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky#define ALPS_FW_BK_2 0x20 /* front & back buttons present */ 3271bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky#define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */ 331d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer#define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with 341d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 6-byte ALPS packet */ 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36e38de678f6b19be3e46a678ec4deeaa7fa0fc140Helge Dellerstatic const struct alps_model_info alps_model_data[] = { 37fa629ef5222193214da9a2b3c94369f79353bec9Seth Forshee { { 0x32, 0x02, 0x14 }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */ 38fa629ef5222193214da9a2b3c94369f79353bec9Seth Forshee { { 0x33, 0x02, 0x0a }, ALPS_PROTO_V1, 0x88, 0xf8, 0 }, /* UMAX-530T */ 39fa629ef5222193214da9a2b3c94369f79353bec9Seth Forshee { { 0x53, 0x02, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, 40fa629ef5222193214da9a2b3c94369f79353bec9Seth Forshee { { 0x53, 0x02, 0x14 }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, 41fa629ef5222193214da9a2b3c94369f79353bec9Seth Forshee { { 0x60, 0x03, 0xc8 }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, /* HP ze1115 */ 42fa629ef5222193214da9a2b3c94369f79353bec9Seth Forshee { { 0x63, 0x02, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, 43fa629ef5222193214da9a2b3c94369f79353bec9Seth Forshee { { 0x63, 0x02, 0x14 }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, 44fa629ef5222193214da9a2b3c94369f79353bec9Seth Forshee { { 0x63, 0x02, 0x28 }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Fujitsu Siemens S6010 */ 45fa629ef5222193214da9a2b3c94369f79353bec9Seth Forshee { { 0x63, 0x02, 0x3c }, ALPS_PROTO_V2, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */ 46fa629ef5222193214da9a2b3c94369f79353bec9Seth Forshee { { 0x63, 0x02, 0x50 }, ALPS_PROTO_V2, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */ 47fa629ef5222193214da9a2b3c94369f79353bec9Seth Forshee { { 0x63, 0x02, 0x64 }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, 48fa629ef5222193214da9a2b3c94369f79353bec9Seth Forshee { { 0x63, 0x03, 0xc8 }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D800 */ 49fa629ef5222193214da9a2b3c94369f79353bec9Seth Forshee { { 0x73, 0x00, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_DUALPOINT }, /* ThinkPad R61 8918-5QG */ 50fa629ef5222193214da9a2b3c94369f79353bec9Seth Forshee { { 0x73, 0x02, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, 51fa629ef5222193214da9a2b3c94369f79353bec9Seth Forshee { { 0x73, 0x02, 0x14 }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */ 52fa629ef5222193214da9a2b3c94369f79353bec9Seth Forshee { { 0x20, 0x02, 0x0e }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */ 53fa629ef5222193214da9a2b3c94369f79353bec9Seth Forshee { { 0x22, 0x02, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, 54fa629ef5222193214da9a2b3c94369f79353bec9Seth Forshee { { 0x22, 0x02, 0x14 }, ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ 551d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer /* Dell Latitude E5500, E6400, E6500, Precision M4400 */ 56fa629ef5222193214da9a2b3c94369f79353bec9Seth Forshee { { 0x62, 0x02, 0x14 }, ALPS_PROTO_V2, 0xcf, 0xcf, 571d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, 58fa629ef5222193214da9a2b3c94369f79353bec9Seth Forshee { { 0x73, 0x02, 0x50 }, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */ 59fa629ef5222193214da9a2b3c94369f79353bec9Seth Forshee { { 0x52, 0x01, 0x14 }, ALPS_PROTO_V2, 0xff, 0xff, 60fa629ef5222193214da9a2b3c94369f79353bec9Seth Forshee ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */ 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * XXX - this entry is suspicious. First byte has zero lower nibble, 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * which is what a normal mouse would report. Also, the value 0x0e 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * isn't valid per PS/2 spec. 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 69d4b347b29b4d14647c7394f7167bf6785dc98e50Seth Forshee/* Packet formats are described in Documentation/input/alps.txt */ 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 711d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapferstatic bool alps_is_valid_first_byte(const struct alps_model_info *model, 721d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer unsigned char data) 731d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer{ 741d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer return (data & model->mask0) == model->byte0; 751d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer} 761d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 771d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapferstatic void alps_report_buttons(struct psmouse *psmouse, 781d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer struct input_dev *dev1, struct input_dev *dev2, 791d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer int left, int right, int middle) 801d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer{ 81c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck struct input_dev *dev; 82c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck 83c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck /* 84c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck * If shared button has already been reported on the 85c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck * other device (dev2) then this event should be also 86c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck * sent through that device. 87c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck */ 88c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck dev = test_bit(BTN_LEFT, dev2->key) ? dev2 : dev1; 89c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck input_report_key(dev, BTN_LEFT, left); 90c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck 91c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck dev = test_bit(BTN_RIGHT, dev2->key) ? dev2 : dev1; 92c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck input_report_key(dev, BTN_RIGHT, right); 93c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck 94c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck dev = test_bit(BTN_MIDDLE, dev2->key) ? dev2 : dev1; 95c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck input_report_key(dev, BTN_MIDDLE, middle); 96c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck 97c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck /* 98c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck * Sync the _other_ device now, we'll do the first 99c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck * device later once we report the rest of the events. 100c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck */ 101c91ed059a080c6f9a7ba525e5027c65d19115d15Martin Buck input_sync(dev2); 1021d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer} 1031d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 1047d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void alps_process_packet(struct psmouse *psmouse) 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct alps_data *priv = psmouse->private; 10771bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky const struct alps_model_info *model = priv->i; 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *packet = psmouse->packet; 1092e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov struct input_dev *dev = psmouse->dev; 1102e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov struct input_dev *dev2 = priv->dev2; 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int x, y, z, ges, fin, left, right, middle; 112c30b4c10d9cfe5506fd421304935d8836773c7e5Ivan Casado Ruiz int back = 0, forward = 0; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 114fa629ef5222193214da9a2b3c94369f79353bec9Seth Forshee if (model->proto_version == ALPS_PROTO_V1) { 115d2f4012f15845761bd3c6f90172e53767c11e359Yotam Medini left = packet[2] & 0x10; 116d2f4012f15845761bd3c6f90172e53767c11e359Yotam Medini right = packet[2] & 0x08; 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds middle = 0; 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds x = packet[1] | ((packet[0] & 0x07) << 7); 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds y = packet[4] | ((packet[3] & 0x07) << 7); 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds z = packet[5]; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds left = packet[3] & 1; 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds right = packet[3] & 2; 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds middle = packet[3] & 4; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds x = packet[1] | ((packet[2] & 0x78) << (7 - 3)); 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds y = packet[4] | ((packet[3] & 0x70) << (7 - 4)); 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds z = packet[5]; 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13071bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if (model->flags & ALPS_FW_BK_1) { 1313c00bb96497a9c1251359a1faf68dddbb8d50a23Laszlo Kajan back = packet[0] & 0x10; 1323c00bb96497a9c1251359a1faf68dddbb8d50a23Laszlo Kajan forward = packet[2] & 4; 133c30b4c10d9cfe5506fd421304935d8836773c7e5Ivan Casado Ruiz } 134c30b4c10d9cfe5506fd421304935d8836773c7e5Ivan Casado Ruiz 13571bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if (model->flags & ALPS_FW_BK_2) { 136c30b4c10d9cfe5506fd421304935d8836773c7e5Ivan Casado Ruiz back = packet[3] & 4; 137c30b4c10d9cfe5506fd421304935d8836773c7e5Ivan Casado Ruiz forward = packet[2] & 4; 138c30b4c10d9cfe5506fd421304935d8836773c7e5Ivan Casado Ruiz if ((middle = forward && back)) 139c30b4c10d9cfe5506fd421304935d8836773c7e5Ivan Casado Ruiz forward = back = 0; 140c30b4c10d9cfe5506fd421304935d8836773c7e5Ivan Casado Ruiz } 141c30b4c10d9cfe5506fd421304935d8836773c7e5Ivan Casado Ruiz 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ges = packet[2] & 1; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fin = packet[2] & 2; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14571bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if ((model->flags & ALPS_DUALPOINT) && z == 127) { 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_rel(dev2, REL_X, (x > 383 ? (x - 768) : x)); 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y)); 148d7ed5d883c09c5474f842dcb148515dfaef2a567Ulrich Dangel 1491d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer alps_report_buttons(psmouse, dev2, dev, left, right, middle); 150d7ed5d883c09c5474f842dcb148515dfaef2a567Ulrich Dangel 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_sync(dev2); 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1551d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer alps_report_buttons(psmouse, dev, dev2, left, right, middle); 156d7ed5d883c09c5474f842dcb148515dfaef2a567Ulrich Dangel 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Convert hardware tap to a reasonable Z value */ 15871bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if (ges && !fin) 15971bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky z = 40; 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A "tap and drag" operation is reported by the hardware as a transition 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * from (!fin && ges) to (fin && ges). This should be translated to the 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sequence Z>0, Z==0, Z>0, so the Z==0 event has to be generated manually. 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ges && fin && !priv->prev_fin) { 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_abs(dev, ABS_X, x); 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_abs(dev, ABS_Y, y); 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_abs(dev, ABS_PRESSURE, 0); 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_key(dev, BTN_TOOL_FINGER, 0); 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_sync(dev); 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->prev_fin = fin; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17571bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if (z > 30) 17671bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky input_report_key(dev, BTN_TOUCH, 1); 17771bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if (z < 25) 17871bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky input_report_key(dev, BTN_TOUCH, 0); 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (z > 0) { 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_abs(dev, ABS_X, x); 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_abs(dev, ABS_Y, y); 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_abs(dev, ABS_PRESSURE, z); 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_report_key(dev, BTN_TOOL_FINGER, z > 0); 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18871bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if (model->flags & ALPS_WHEEL) 189e6c047b98bbd09473c586744c681e877ebf954ffVojtech Pavlik input_report_rel(dev, REL_WHEEL, ((packet[2] << 1) & 0x08) - ((packet[0] >> 4) & 0x07)); 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19171bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if (model->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { 192c30b4c10d9cfe5506fd421304935d8836773c7e5Ivan Casado Ruiz input_report_key(dev, BTN_FORWARD, forward); 193c30b4c10d9cfe5506fd421304935d8836773c7e5Ivan Casado Ruiz input_report_key(dev, BTN_BACK, back); 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19671bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if (model->flags & ALPS_FOUR_BUTTONS) { 19771bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky input_report_key(dev, BTN_0, packet[2] & 4); 19871bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky input_report_key(dev, BTN_1, packet[0] & 0x10); 19971bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky input_report_key(dev, BTN_2, packet[3] & 4); 20071bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky input_report_key(dev, BTN_3, packet[0] & 0x20); 20171bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky } 20271bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds input_sync(dev); 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2061d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapferstatic void alps_report_bare_ps2_packet(struct psmouse *psmouse, 2071d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer unsigned char packet[], 2081d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer bool report_buttons) 2091d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer{ 2101d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer struct alps_data *priv = psmouse->private; 2111d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer struct input_dev *dev2 = priv->dev2; 2121d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 2131d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer if (report_buttons) 2141d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer alps_report_buttons(psmouse, dev2, psmouse->dev, 2151d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer packet[0] & 1, packet[0] & 2, packet[0] & 4); 2161d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 2171d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer input_report_rel(dev2, REL_X, 2181d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0); 2191d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer input_report_rel(dev2, REL_Y, 2201d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer packet[2] ? ((packet[0] << 3) & 0x100) - packet[2] : 0); 2211d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 2221d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer input_sync(dev2); 2231d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer} 2241d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 2251d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapferstatic psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse) 2261d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer{ 2271d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer struct alps_data *priv = psmouse->private; 2281d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 2291d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer if (psmouse->pktcnt < 6) 2301d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer return PSMOUSE_GOOD_DATA; 2311d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 2321d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer if (psmouse->pktcnt == 6) { 2331d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer /* 2341d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * Start a timer to flush the packet if it ends up last 2351d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * 6-byte packet in the stream. Timer needs to fire 2361d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * psmouse core times out itself. 20 ms should be enough 2371d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * to decide if we are getting more data or not. 2381d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer */ 2391d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer mod_timer(&priv->timer, jiffies + msecs_to_jiffies(20)); 2401d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer return PSMOUSE_GOOD_DATA; 2411d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer } 2421d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 2431d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer del_timer(&priv->timer); 2441d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 2451d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer if (psmouse->packet[6] & 0x80) { 2461d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 2471d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer /* 2481d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * Highest bit is set - that means we either had 2491d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * complete ALPS packet and this is start of the 2501d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * next packet or we got garbage. 2511d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer */ 2521d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 2531d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer if (((psmouse->packet[3] | 2541d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer psmouse->packet[4] | 2551d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer psmouse->packet[5]) & 0x80) || 2561d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer (!alps_is_valid_first_byte(priv->i, psmouse->packet[6]))) { 257b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse_dbg(psmouse, 258b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov "refusing packet %x %x %x %x (suspected interleaved ps/2)\n", 259b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse->packet[3], psmouse->packet[4], 260b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse->packet[5], psmouse->packet[6]); 2611d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer return PSMOUSE_BAD_DATA; 2621d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer } 2631d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 2641d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer alps_process_packet(psmouse); 2651d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 2661d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer /* Continue with the next packet */ 2671d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer psmouse->packet[0] = psmouse->packet[6]; 2681d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer psmouse->pktcnt = 1; 2691d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 2701d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer } else { 2711d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 2721d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer /* 2731d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * High bit is 0 - that means that we indeed got a PS/2 2741d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * packet in the middle of ALPS packet. 2751d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * 2761d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * There is also possibility that we got 6-byte ALPS 2771d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * packet followed by 3-byte packet from trackpoint. We 2781d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * can not distinguish between these 2 scenarios but 279b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov * because the latter is unlikely to happen in course of 2801d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * normal operation (user would need to press all 2811d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * buttons on the pad and start moving trackpoint 2821d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * without touching the pad surface) we assume former. 2831d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * Even if we are wrong the wost thing that would happen 2841d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * the cursor would jump but we should not get protocol 285b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov * de-synchronization. 2861d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer */ 2871d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 2881d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer alps_report_bare_ps2_packet(psmouse, &psmouse->packet[3], 2891d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer false); 2901d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 2911d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer /* 2921d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * Continue with the standard ALPS protocol handling, 2931d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * but make sure we won't process it as an interleaved 2941d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * packet again, which may happen if all buttons are 2951d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * pressed. To avoid this let's reset the 4th bit which 2961d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * is normally 1. 2971d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer */ 2981d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer psmouse->packet[3] = psmouse->packet[6] & 0xf7; 2991d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer psmouse->pktcnt = 4; 3001d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer } 3011d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 3021d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer return PSMOUSE_GOOD_DATA; 3031d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer} 3041d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 3051d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapferstatic void alps_flush_packet(unsigned long data) 3061d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer{ 3071d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer struct psmouse *psmouse = (struct psmouse *)data; 3081d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 3091d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer serio_pause_rx(psmouse->ps2dev.serio); 3101d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 3111d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer if (psmouse->pktcnt == 6) { 3121d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 3131d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer /* 3141d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * We did not any more data in reasonable amount of time. 3151d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * Validate the last 3 bytes and process as a standard 3161d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer * ALPS packet. 3171d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer */ 3181d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer if ((psmouse->packet[3] | 3191d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer psmouse->packet[4] | 3201d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer psmouse->packet[5]) & 0x80) { 321b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse_dbg(psmouse, 322b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov "refusing packet %x %x %x (suspected interleaved ps/2)\n", 323b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse->packet[3], psmouse->packet[4], 324b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse->packet[5]); 3251d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer } else { 3261d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer alps_process_packet(psmouse); 3271d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer } 3281d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer psmouse->pktcnt = 0; 3291d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer } 3301d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 3311d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer serio_continue_rx(psmouse->ps2dev.serio); 3321d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer} 3331d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 3347d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic psmouse_ret_t alps_process_byte(struct psmouse *psmouse) 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct alps_data *priv = psmouse->private; 3371d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer const struct alps_model_info *model = priv->i; 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */ 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (psmouse->pktcnt == 3) { 3411d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer alps_report_bare_ps2_packet(psmouse, psmouse->packet, 3421d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer true); 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return PSMOUSE_FULL_PACKET; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return PSMOUSE_GOOD_DATA; 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3481d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer /* Check for PS/2 packet stuffed in the middle of ALPS packet. */ 3491d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 3501d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer if ((model->flags & ALPS_PS2_INTERLEAVED) && 3511d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer psmouse->pktcnt >= 4 && (psmouse->packet[3] & 0x0f) == 0x0f) { 3521d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer return alps_handle_interleaved_ps2(psmouse); 3531d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer } 3541d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 3551d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer if (!alps_is_valid_first_byte(model, psmouse->packet[0])) { 356b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse_dbg(psmouse, 357b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov "refusing packet[0] = %x (mask0 = %x, byte0 = %x)\n", 358b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse->packet[0], model->mask0, model->byte0); 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return PSMOUSE_BAD_DATA; 3601d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer } 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Bytes 2 - 6 should have 0 in the highest bit */ 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= 6 && 3641d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) { 365b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse_dbg(psmouse, "refusing packet[%i] = %x\n", 366b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse->pktcnt - 1, 367b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse->packet[psmouse->pktcnt - 1]); 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return PSMOUSE_BAD_DATA; 3691d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer } 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (psmouse->pktcnt == 6) { 3727d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells alps_process_packet(psmouse); 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return PSMOUSE_FULL_PACKET; 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return PSMOUSE_GOOD_DATA; 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 379e38de678f6b19be3e46a678ec4deeaa7fa0fc140Helge Dellerstatic const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version) 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ps2dev *ps2dev = &psmouse->ps2dev; 382e38de678f6b19be3e46a678ec4deeaa7fa0fc140Helge Deller static const unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 }; 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char param[4]; 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * First try "E6 report". 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ALPS should return 0,0,10 or 0,0,100 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds param[0] = 0; 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) || 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11)) 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds param[0] = param[1] = param[2] = 0xff; 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 401b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse_dbg(psmouse, "E6 report: %2.2x %2.2x %2.2x", 402b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov param[0], param[1], param[2]); 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (param[0] != 0 || param[1] != 0 || (param[2] != 10 && param[2] != 100)) 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Now try "E7 report". Allowed responses are in 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * alps_model_data[].signature 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds param[0] = 0; 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) || 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21)) 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds param[0] = param[1] = param[2] = 0xff; 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 422b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse_dbg(psmouse, "E7 report: %2.2x %2.2x %2.2x", 423b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov param[0], param[1], param[2]); 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4251e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov if (version) { 4261e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov for (i = 0; i < ARRAY_SIZE(rates) && param[2] != rates[i]; i++) 4271e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov /* empty */; 4281e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov *version = (param[0] << 8) | (param[1] << 4) | i; 4291e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov } 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) 4321e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov if (!memcmp(param, alps_model_data[i].signature, 4331e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov sizeof(alps_model_data[i].signature))) 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return alps_model_data + i; 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For DualPoint devices select the device that should respond to 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * subsequent commands. It looks like glidepad is behind stickpointer, 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * I'd thought it would be other way around... 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 444b7802c5c1ea9563f3746bea09c214ccedc8600f4Dmitry Torokhovstatic int alps_passthrough_mode(struct psmouse *psmouse, bool enable) 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ps2dev *ps2dev = &psmouse->ps2dev; 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11; 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ps2_command(ps2dev, NULL, cmd) || 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, cmd) || 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, cmd) || 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE)) 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* we may get 3 more bytes, just ignore them */ 456c611763d048990de5cdf848d97af6392f8fa7430Dmitry Torokhov ps2_drain(ps2dev, 3, 100); 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int alps_absolute_mode(struct psmouse *psmouse) 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ps2dev *ps2dev = &psmouse->ps2dev; 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Try ALPS magic knock - 4 disable before enable */ 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE)) 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Switch mouse to poll (remote) mode so motion data will not 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * get in our way 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETPOLL); 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int alps_get_status(struct psmouse *psmouse, char *param) 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ps2dev *ps2dev = &psmouse->ps2dev; 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Get status: 0xF5 0xF5 0xF5 0xE9 */ 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 491b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse_dbg(psmouse, "Status: %2.2x %2.2x %2.2x", 492b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov param[0], param[1], param[2]); 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Turn touchpad tapping on or off. The sequences are: 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0xE9 0xF5 0xF5 0xF3 0x0A to enable, 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0xE9 0xF5 0xF5 0xE8 0x00 to disable. 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * My guess that 0xE9 (GetInfo) is here as a sync point. 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For models that also have stickpointer (DualPoints) its tapping 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is controlled separately (0xE6 0xE6 0xE6 0xF3 0x14|0x0A) but 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we don't fiddle with it. 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int alps_tap_mode(struct psmouse *psmouse, int enable) 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ps2dev *ps2dev = &psmouse->ps2dev; 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cmd = enable ? PSMOUSE_CMD_SETRATE : PSMOUSE_CMD_SETRES; 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char tap_arg = enable ? 0x0A : 0x00; 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char param[4]; 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO) || 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_command(ps2dev, &tap_arg, cmd)) 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (alps_get_status(psmouse, param)) 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 525f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov/* 526f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov * alps_poll() - poll the touchpad for current motion packet. 527f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov * Used in resync. 528f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov */ 529f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhovstatic int alps_poll(struct psmouse *psmouse) 530f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov{ 531f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov struct alps_data *priv = psmouse->private; 532f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov unsigned char buf[6]; 533b7802c5c1ea9563f3746bea09c214ccedc8600f4Dmitry Torokhov bool poll_failed; 534f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov 535f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov if (priv->i->flags & ALPS_PASS) 536b7802c5c1ea9563f3746bea09c214ccedc8600f4Dmitry Torokhov alps_passthrough_mode(psmouse, true); 537f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov 538f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov poll_failed = ps2_command(&psmouse->ps2dev, buf, 539f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)) < 0; 540f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov 541f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov if (priv->i->flags & ALPS_PASS) 542b7802c5c1ea9563f3746bea09c214ccedc8600f4Dmitry Torokhov alps_passthrough_mode(psmouse, false); 543f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov 544f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov if (poll_failed || (buf[0] & priv->i->mask0) != priv->i->byte0) 545f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov return -1; 546f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov 547f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov if ((psmouse->badbyte & 0xc8) == 0x08) { 548f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov/* 549f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov * Poll the track stick ... 550f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov */ 551f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov if (ps2_command(&psmouse->ps2dev, buf, PSMOUSE_CMD_POLL | (3 << 8))) 552f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov return -1; 553f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov } 554f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov 555f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov memcpy(psmouse->packet, buf, sizeof(buf)); 556f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov return 0; 557f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov} 558f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov 55971bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitskystatic int alps_hw_init(struct psmouse *psmouse) 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct alps_data *priv = psmouse->private; 56271bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky const struct alps_model_info *model = priv->i; 563f3a5c73d5ecb40909db662c4d2ace497b25c5940Dmitry Torokhov 56471bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if ((model->flags & ALPS_PASS) && 565b7802c5c1ea9563f3746bea09c214ccedc8600f4Dmitry Torokhov alps_passthrough_mode(psmouse, true)) { 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 567b7802c5c1ea9563f3746bea09c214ccedc8600f4Dmitry Torokhov } 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 569b7802c5c1ea9563f3746bea09c214ccedc8600f4Dmitry Torokhov if (alps_tap_mode(psmouse, true)) { 570b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse_warn(psmouse, "Failed to enable hardware tapping\n"); 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 572963f626d46d5caeeb3cff29998d8a64df5b25591Peter Osterlund } 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (alps_absolute_mode(psmouse)) { 575b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse_err(psmouse, "Failed to enable absolute mode\n"); 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57971bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if ((model->flags & ALPS_PASS) && 580b7802c5c1ea9563f3746bea09c214ccedc8600f4Dmitry Torokhov alps_passthrough_mode(psmouse, false)) { 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 582b7802c5c1ea9563f3746bea09c214ccedc8600f4Dmitry Torokhov } 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5841e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov /* ALPS needs stream mode, otherwise it won't report any data */ 5851e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSTREAM)) { 586b5d21704361eefe337a36ebbb57a1d9927132511Dmitry Torokhov psmouse_err(psmouse, "Failed to enable stream mode\n"); 5871e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov return -1; 5881e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov } 5891e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov 5901e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov return 0; 5911e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov} 5921e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov 5931e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhovstatic int alps_reconnect(struct psmouse *psmouse) 5941e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov{ 59571bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky const struct alps_model_info *model; 59671bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky 5971e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov psmouse_reset(psmouse); 5981e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov 59971bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky model = alps_get_model(psmouse, NULL); 60071bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if (!model) 6011e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov return -1; 6021e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov 60371bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky return alps_hw_init(psmouse); 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void alps_disconnect(struct psmouse *psmouse) 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct alps_data *priv = psmouse->private; 6092e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psmouse_reset(psmouse); 6111d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer del_timer_sync(&priv->timer); 6122e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov input_unregister_device(priv->dev2); 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(priv); 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint alps_init(struct psmouse *psmouse) 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct alps_data *priv; 61971bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky const struct alps_model_info *model; 6202e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov struct input_dev *dev1 = psmouse->dev, *dev2; 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int version; 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 623f42649e84831efc69d5f621f1c36a39b4e384a99Dmitry Torokhov priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL); 6242e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov dev2 = input_allocate_device(); 6252e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov if (!priv || !dev2) 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto init_fail; 6272e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov 6282e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov priv->dev2 = dev2; 6291d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer setup_timer(&priv->timer, alps_flush_packet, (unsigned long)psmouse); 6301d9f26262aef6d63ff65eba0fd5f1583f342b69bSebastian Kapfer 6311e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov psmouse->private = priv; 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 63371bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky model = alps_get_model(psmouse, &version); 63471bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if (!model) 63571bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky goto init_fail; 63671bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky 63771bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky priv->i = model; 63871bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky 63971bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if (alps_hw_init(psmouse)) 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto init_fail; 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6427105d2ea73e1391b681d0e1212c42f561c64d429Dmitry Torokhov /* 6437105d2ea73e1391b681d0e1212c42f561c64d429Dmitry Torokhov * Undo part of setup done for us by psmouse core since touchpad 6447105d2ea73e1391b681d0e1212c42f561c64d429Dmitry Torokhov * is not a relative device. 6457105d2ea73e1391b681d0e1212c42f561c64d429Dmitry Torokhov */ 6467105d2ea73e1391b681d0e1212c42f561c64d429Dmitry Torokhov __clear_bit(EV_REL, dev1->evbit); 6477105d2ea73e1391b681d0e1212c42f561c64d429Dmitry Torokhov __clear_bit(REL_X, dev1->relbit); 6487105d2ea73e1391b681d0e1212c42f561c64d429Dmitry Torokhov __clear_bit(REL_Y, dev1->relbit); 6497105d2ea73e1391b681d0e1212c42f561c64d429Dmitry Torokhov 6507105d2ea73e1391b681d0e1212c42f561c64d429Dmitry Torokhov /* 6517105d2ea73e1391b681d0e1212c42f561c64d429Dmitry Torokhov * Now set up our capabilities. 6527105d2ea73e1391b681d0e1212c42f561c64d429Dmitry Torokhov */ 6537b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby dev1->evbit[BIT_WORD(EV_KEY)] |= BIT_MASK(EV_KEY); 6547b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby dev1->keybit[BIT_WORD(BTN_TOUCH)] |= BIT_MASK(BTN_TOUCH); 6557b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby dev1->keybit[BIT_WORD(BTN_TOOL_FINGER)] |= BIT_MASK(BTN_TOOL_FINGER); 65671bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky dev1->keybit[BIT_WORD(BTN_LEFT)] |= 65771bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT); 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6597b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS); 6602e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0); 6612e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0); 6622e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0); 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 66471bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if (model->flags & ALPS_WHEEL) { 6657b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby dev1->evbit[BIT_WORD(EV_REL)] |= BIT_MASK(EV_REL); 6667b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby dev1->relbit[BIT_WORD(REL_WHEEL)] |= BIT_MASK(REL_WHEEL); 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 66971bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if (model->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { 6707b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby dev1->keybit[BIT_WORD(BTN_FORWARD)] |= BIT_MASK(BTN_FORWARD); 6717b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby dev1->keybit[BIT_WORD(BTN_BACK)] |= BIT_MASK(BTN_BACK); 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 67471bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky if (model->flags & ALPS_FOUR_BUTTONS) { 67571bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky dev1->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_0); 67671bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky dev1->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1); 67771bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky dev1->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2); 67871bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky dev1->keybit[BIT_WORD(BTN_3)] |= BIT_MASK(BTN_3); 67971bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky } else { 68071bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky dev1->keybit[BIT_WORD(BTN_MIDDLE)] |= BIT_MASK(BTN_MIDDLE); 68171bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky } 68271bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky 68308ffce4560e0133e10634b0dd85eecee11257a1cDmitry Torokhov snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys); 6842e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov dev2->phys = priv->phys; 68571bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky dev2->name = (model->flags & ALPS_DUALPOINT) ? "DualPoint Stick" : "PS/2 Mouse"; 6862e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov dev2->id.bustype = BUS_I8042; 6872e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov dev2->id.vendor = 0x0002; 6882e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov dev2->id.product = PSMOUSE_ALPS; 6892e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov dev2->id.version = 0x0000; 6901db3a3453f6915d6af322e3a1b25f7ab2c9d9a2bDmitry Torokhov dev2->dev.parent = &psmouse->ps2dev.serio->dev; 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6927b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); 69371bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky dev2->relbit[BIT_WORD(REL_X)] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); 69471bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky dev2->keybit[BIT_WORD(BTN_LEFT)] = 69571bb21b677e89a2b438b804231f92b779beda5d7Maxim Levitsky BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 697f42649e84831efc69d5f621f1c36a39b4e384a99Dmitry Torokhov if (input_register_device(priv->dev2)) 698f42649e84831efc69d5f621f1c36a39b4e384a99Dmitry Torokhov goto init_fail; 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psmouse->protocol_handler = alps_process_byte; 701f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov psmouse->poll = alps_poll; 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psmouse->disconnect = alps_disconnect; 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psmouse->reconnect = alps_reconnect; 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psmouse->pktsize = 6; 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 706f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov /* We are having trouble resyncing ALPS touchpads so disable it for now */ 707f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov psmouse->resync_time = 0; 708f0d5c6f419d3a10443f66d6835855837eae4ac4bDmitry Torokhov 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsinit_fail: 712f42649e84831efc69d5f621f1c36a39b4e384a99Dmitry Torokhov psmouse_reset(psmouse); 7132e5b636bb5f8dacbb91d08544e2c41ebcad5daceDmitry Torokhov input_free_device(dev2); 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(priv); 7151e0c5b1275a0e59747349745da8778523a9dcd18Dmitry Torokhov psmouse->private = NULL; 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 719b7802c5c1ea9563f3746bea09c214ccedc8600f4Dmitry Torokhovint alps_detect(struct psmouse *psmouse, bool set_properties) 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int version; 722e38de678f6b19be3e46a678ec4deeaa7fa0fc140Helge Deller const struct alps_model_info *model; 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 724f42649e84831efc69d5f621f1c36a39b4e384a99Dmitry Torokhov model = alps_get_model(psmouse, &version); 725f42649e84831efc69d5f621f1c36a39b4e384a99Dmitry Torokhov if (!model) 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (set_properties) { 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psmouse->vendor = "ALPS"; 730968ac842c4946abcd6ae623414783548672177f5Dmitry Torokhov psmouse->name = model->flags & ALPS_DUALPOINT ? 731968ac842c4946abcd6ae623414783548672177f5Dmitry Torokhov "DualPoint TouchPad" : "GlidePoint"; 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psmouse->model = version; 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 737