11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * ALPS touchpad PS/2 mouse driver 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (c) 2003 Neil Brown <neilb@cse.unsw.edu.au> 5963f626dSPeter Osterlund * Copyright (c) 2003-2005 Peter Osterlund <petero2@telia.com> 61da177e4SLinus Torvalds * Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru> 71da177e4SLinus Torvalds * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz> 81d9f2626SSebastian Kapfer * Copyright (c) 2009 Sebastian Kapfer <sebastian_kapfer@gmx.net> 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * ALPS detection, tap switching and status querying info is taken from 111da177e4SLinus Torvalds * tpconfig utility (by C. Scott Ananian and Bruce Kall). 121da177e4SLinus Torvalds * 131da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify it 141da177e4SLinus Torvalds * under the terms of the GNU General Public License version 2 as published by 151da177e4SLinus Torvalds * the Free Software Foundation. 161da177e4SLinus Torvalds */ 171da177e4SLinus Torvalds 185a0e3ad6STejun Heo #include <linux/slab.h> 191da177e4SLinus Torvalds #include <linux/input.h> 2001ce661fSSeth Forshee #include <linux/input/mt.h> 211da177e4SLinus Torvalds #include <linux/serio.h> 221da177e4SLinus Torvalds #include <linux/libps2.h> 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds #include "psmouse.h" 251da177e4SLinus Torvalds #include "alps.h" 261da177e4SLinus Torvalds 2725bded7cSSeth Forshee /* 2825bded7cSSeth Forshee * Definitions for ALPS version 3 and 4 command mode protocol 2925bded7cSSeth Forshee */ 3025bded7cSSeth Forshee #define ALPS_CMD_NIBBLE_10 0x01f2 3125bded7cSSeth Forshee 32cd401204SKevin Cernekee #define ALPS_REG_BASE_RUSHMORE 0xc2c0 33cd401204SKevin Cernekee #define ALPS_REG_BASE_PINNACLE 0x0000 34cd401204SKevin Cernekee 3525bded7cSSeth Forshee static const struct alps_nibble_commands alps_v3_nibble_commands[] = { 3625bded7cSSeth Forshee { PSMOUSE_CMD_SETPOLL, 0x00 }, /* 0 */ 3725bded7cSSeth Forshee { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */ 3825bded7cSSeth Forshee { PSMOUSE_CMD_SETSCALE21, 0x00 }, /* 2 */ 3925bded7cSSeth Forshee { PSMOUSE_CMD_SETRATE, 0x0a }, /* 3 */ 4025bded7cSSeth Forshee { PSMOUSE_CMD_SETRATE, 0x14 }, /* 4 */ 4125bded7cSSeth Forshee { PSMOUSE_CMD_SETRATE, 0x28 }, /* 5 */ 4225bded7cSSeth Forshee { PSMOUSE_CMD_SETRATE, 0x3c }, /* 6 */ 4325bded7cSSeth Forshee { PSMOUSE_CMD_SETRATE, 0x50 }, /* 7 */ 4425bded7cSSeth Forshee { PSMOUSE_CMD_SETRATE, 0x64 }, /* 8 */ 4525bded7cSSeth Forshee { PSMOUSE_CMD_SETRATE, 0xc8 }, /* 9 */ 4625bded7cSSeth Forshee { ALPS_CMD_NIBBLE_10, 0x00 }, /* a */ 4725bded7cSSeth Forshee { PSMOUSE_CMD_SETRES, 0x00 }, /* b */ 4825bded7cSSeth Forshee { PSMOUSE_CMD_SETRES, 0x01 }, /* c */ 4925bded7cSSeth Forshee { PSMOUSE_CMD_SETRES, 0x02 }, /* d */ 5025bded7cSSeth Forshee { PSMOUSE_CMD_SETRES, 0x03 }, /* e */ 5125bded7cSSeth Forshee { PSMOUSE_CMD_SETSCALE11, 0x00 }, /* f */ 5225bded7cSSeth Forshee }; 5325bded7cSSeth Forshee 5425bded7cSSeth Forshee static const struct alps_nibble_commands alps_v4_nibble_commands[] = { 5525bded7cSSeth Forshee { PSMOUSE_CMD_ENABLE, 0x00 }, /* 0 */ 5625bded7cSSeth Forshee { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */ 5725bded7cSSeth Forshee { PSMOUSE_CMD_SETSCALE21, 0x00 }, /* 2 */ 5825bded7cSSeth Forshee { PSMOUSE_CMD_SETRATE, 0x0a }, /* 3 */ 5925bded7cSSeth Forshee { PSMOUSE_CMD_SETRATE, 0x14 }, /* 4 */ 6025bded7cSSeth Forshee { PSMOUSE_CMD_SETRATE, 0x28 }, /* 5 */ 6125bded7cSSeth Forshee { PSMOUSE_CMD_SETRATE, 0x3c }, /* 6 */ 6225bded7cSSeth Forshee { PSMOUSE_CMD_SETRATE, 0x50 }, /* 7 */ 6325bded7cSSeth Forshee { PSMOUSE_CMD_SETRATE, 0x64 }, /* 8 */ 6425bded7cSSeth Forshee { PSMOUSE_CMD_SETRATE, 0xc8 }, /* 9 */ 6525bded7cSSeth Forshee { ALPS_CMD_NIBBLE_10, 0x00 }, /* a */ 6625bded7cSSeth Forshee { PSMOUSE_CMD_SETRES, 0x00 }, /* b */ 6725bded7cSSeth Forshee { PSMOUSE_CMD_SETRES, 0x01 }, /* c */ 6825bded7cSSeth Forshee { PSMOUSE_CMD_SETRES, 0x02 }, /* d */ 6925bded7cSSeth Forshee { PSMOUSE_CMD_SETRES, 0x03 }, /* e */ 7025bded7cSSeth Forshee { PSMOUSE_CMD_SETSCALE11, 0x00 }, /* f */ 7125bded7cSSeth Forshee }; 7225bded7cSSeth Forshee 7395f75e91SYunkang Tang static const struct alps_nibble_commands alps_v6_nibble_commands[] = { 7495f75e91SYunkang Tang { PSMOUSE_CMD_ENABLE, 0x00 }, /* 0 */ 7595f75e91SYunkang Tang { PSMOUSE_CMD_SETRATE, 0x0a }, /* 1 */ 7695f75e91SYunkang Tang { PSMOUSE_CMD_SETRATE, 0x14 }, /* 2 */ 7795f75e91SYunkang Tang { PSMOUSE_CMD_SETRATE, 0x28 }, /* 3 */ 7895f75e91SYunkang Tang { PSMOUSE_CMD_SETRATE, 0x3c }, /* 4 */ 7995f75e91SYunkang Tang { PSMOUSE_CMD_SETRATE, 0x50 }, /* 5 */ 8095f75e91SYunkang Tang { PSMOUSE_CMD_SETRATE, 0x64 }, /* 6 */ 8195f75e91SYunkang Tang { PSMOUSE_CMD_SETRATE, 0xc8 }, /* 7 */ 8295f75e91SYunkang Tang { PSMOUSE_CMD_GETID, 0x00 }, /* 8 */ 8395f75e91SYunkang Tang { PSMOUSE_CMD_GETINFO, 0x00 }, /* 9 */ 8495f75e91SYunkang Tang { PSMOUSE_CMD_SETRES, 0x00 }, /* a */ 8595f75e91SYunkang Tang { PSMOUSE_CMD_SETRES, 0x01 }, /* b */ 8695f75e91SYunkang Tang { PSMOUSE_CMD_SETRES, 0x02 }, /* c */ 8795f75e91SYunkang Tang { PSMOUSE_CMD_SETRES, 0x03 }, /* d */ 8895f75e91SYunkang Tang { PSMOUSE_CMD_SETSCALE21, 0x00 }, /* e */ 8995f75e91SYunkang Tang { PSMOUSE_CMD_SETSCALE11, 0x00 }, /* f */ 9095f75e91SYunkang Tang }; 9195f75e91SYunkang Tang 9225bded7cSSeth Forshee 9371bb21b6SMaxim Levitsky #define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */ 9471bb21b6SMaxim Levitsky #define ALPS_PASS 0x04 /* device has a pass-through port */ 9571bb21b6SMaxim Levitsky 9671bb21b6SMaxim Levitsky #define ALPS_WHEEL 0x08 /* hardware wheel present */ 9771bb21b6SMaxim Levitsky #define ALPS_FW_BK_1 0x10 /* front & back buttons present */ 9871bb21b6SMaxim Levitsky #define ALPS_FW_BK_2 0x20 /* front & back buttons present */ 9971bb21b6SMaxim Levitsky #define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */ 1001d9f2626SSebastian Kapfer #define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with 1011d9f2626SSebastian Kapfer 6-byte ALPS packet */ 1021da177e4SLinus Torvalds 103e38de678SHelge Deller static const struct alps_model_info alps_model_data[] = { 10425bded7cSSeth Forshee { { 0x32, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */ 10525bded7cSSeth Forshee { { 0x33, 0x02, 0x0a }, 0x00, ALPS_PROTO_V1, 0x88, 0xf8, 0 }, /* UMAX-530T */ 10625bded7cSSeth Forshee { { 0x53, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, 10725bded7cSSeth Forshee { { 0x53, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, 10825bded7cSSeth Forshee { { 0x60, 0x03, 0xc8 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, /* HP ze1115 */ 10925bded7cSSeth Forshee { { 0x63, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, 11025bded7cSSeth Forshee { { 0x63, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, 11125bded7cSSeth Forshee { { 0x63, 0x02, 0x28 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Fujitsu Siemens S6010 */ 11225bded7cSSeth Forshee { { 0x63, 0x02, 0x3c }, 0x00, ALPS_PROTO_V2, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */ 11325bded7cSSeth Forshee { { 0x63, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */ 11425bded7cSSeth Forshee { { 0x63, 0x02, 0x64 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, 11525bded7cSSeth Forshee { { 0x63, 0x03, 0xc8 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D800 */ 11625bded7cSSeth Forshee { { 0x73, 0x00, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_DUALPOINT }, /* ThinkPad R61 8918-5QG */ 11725bded7cSSeth Forshee { { 0x73, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, 11825bded7cSSeth Forshee { { 0x73, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */ 11925bded7cSSeth Forshee { { 0x20, 0x02, 0x0e }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */ 12025bded7cSSeth Forshee { { 0x22, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, 12125bded7cSSeth Forshee { { 0x22, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ 1221d9f2626SSebastian Kapfer /* Dell Latitude E5500, E6400, E6500, Precision M4400 */ 12325bded7cSSeth Forshee { { 0x62, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, 1241d9f2626SSebastian Kapfer ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, 12595f75e91SYunkang Tang { { 0x73, 0x00, 0x14 }, 0x00, ALPS_PROTO_V6, 0xff, 0xff, ALPS_DUALPOINT }, /* Dell XT2 */ 12625bded7cSSeth Forshee { { 0x73, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */ 12725bded7cSSeth Forshee { { 0x52, 0x01, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff, 128eb8bff85SThomas Bächler ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */ 12925bded7cSSeth Forshee { { 0x73, 0x02, 0x64 }, 0x8a, ALPS_PROTO_V4, 0x8f, 0x8f, 0 }, 1301da177e4SLinus Torvalds }; 1311da177e4SLinus Torvalds 13224af5cb9SKevin Cernekee static void alps_set_abs_params_st(struct alps_data *priv, 13324af5cb9SKevin Cernekee struct input_dev *dev1); 13424af5cb9SKevin Cernekee static void alps_set_abs_params_mt(struct alps_data *priv, 13524af5cb9SKevin Cernekee struct input_dev *dev1); 13624af5cb9SKevin Cernekee 1371da177e4SLinus Torvalds /* 1381da177e4SLinus Torvalds * XXX - this entry is suspicious. First byte has zero lower nibble, 1391da177e4SLinus Torvalds * which is what a normal mouse would report. Also, the value 0x0e 1401da177e4SLinus Torvalds * isn't valid per PS/2 spec. 1411da177e4SLinus Torvalds */ 1421da177e4SLinus Torvalds 143d4b347b2SSeth Forshee /* Packet formats are described in Documentation/input/alps.txt */ 1441da177e4SLinus Torvalds 14599df65e7SKevin Cernekee static bool alps_is_valid_first_byte(struct alps_data *priv, 1461d9f2626SSebastian Kapfer unsigned char data) 1471d9f2626SSebastian Kapfer { 14899df65e7SKevin Cernekee return (data & priv->mask0) == priv->byte0; 1491d9f2626SSebastian Kapfer } 1501d9f2626SSebastian Kapfer 1511d9f2626SSebastian Kapfer static void alps_report_buttons(struct psmouse *psmouse, 1521d9f2626SSebastian Kapfer struct input_dev *dev1, struct input_dev *dev2, 1531d9f2626SSebastian Kapfer int left, int right, int middle) 1541d9f2626SSebastian Kapfer { 1551d9f2626SSebastian Kapfer struct input_dev *dev; 1561d9f2626SSebastian Kapfer 1571d9f2626SSebastian Kapfer /* 1581d9f2626SSebastian Kapfer * If shared button has already been reported on the 1591d9f2626SSebastian Kapfer * other device (dev2) then this event should be also 1601d9f2626SSebastian Kapfer * sent through that device. 1611d9f2626SSebastian Kapfer */ 1621d9f2626SSebastian Kapfer dev = test_bit(BTN_LEFT, dev2->key) ? dev2 : dev1; 1631d9f2626SSebastian Kapfer input_report_key(dev, BTN_LEFT, left); 1641d9f2626SSebastian Kapfer 1651d9f2626SSebastian Kapfer dev = test_bit(BTN_RIGHT, dev2->key) ? dev2 : dev1; 1661d9f2626SSebastian Kapfer input_report_key(dev, BTN_RIGHT, right); 1671d9f2626SSebastian Kapfer 1681d9f2626SSebastian Kapfer dev = test_bit(BTN_MIDDLE, dev2->key) ? dev2 : dev1; 1691d9f2626SSebastian Kapfer input_report_key(dev, BTN_MIDDLE, middle); 1701d9f2626SSebastian Kapfer 1711d9f2626SSebastian Kapfer /* 1721d9f2626SSebastian Kapfer * Sync the _other_ device now, we'll do the first 1731d9f2626SSebastian Kapfer * device later once we report the rest of the events. 1741d9f2626SSebastian Kapfer */ 1751d9f2626SSebastian Kapfer input_sync(dev2); 1761d9f2626SSebastian Kapfer } 1771d9f2626SSebastian Kapfer 17825bded7cSSeth Forshee static void alps_process_packet_v1_v2(struct psmouse *psmouse) 1791da177e4SLinus Torvalds { 1801da177e4SLinus Torvalds struct alps_data *priv = psmouse->private; 1811da177e4SLinus Torvalds unsigned char *packet = psmouse->packet; 1822e5b636bSDmitry Torokhov struct input_dev *dev = psmouse->dev; 1832e5b636bSDmitry Torokhov struct input_dev *dev2 = priv->dev2; 1841da177e4SLinus Torvalds int x, y, z, ges, fin, left, right, middle; 185c30b4c10SIvan Casado Ruiz int back = 0, forward = 0; 1861da177e4SLinus Torvalds 18799df65e7SKevin Cernekee if (priv->proto_version == ALPS_PROTO_V1) { 188d2f4012fSYotam Medini left = packet[2] & 0x10; 189d2f4012fSYotam Medini right = packet[2] & 0x08; 1901da177e4SLinus Torvalds middle = 0; 1911da177e4SLinus Torvalds x = packet[1] | ((packet[0] & 0x07) << 7); 1921da177e4SLinus Torvalds y = packet[4] | ((packet[3] & 0x07) << 7); 1931da177e4SLinus Torvalds z = packet[5]; 1941da177e4SLinus Torvalds } else { 1951da177e4SLinus Torvalds left = packet[3] & 1; 1961da177e4SLinus Torvalds right = packet[3] & 2; 1971da177e4SLinus Torvalds middle = packet[3] & 4; 1981da177e4SLinus Torvalds x = packet[1] | ((packet[2] & 0x78) << (7 - 3)); 1991da177e4SLinus Torvalds y = packet[4] | ((packet[3] & 0x70) << (7 - 4)); 2001da177e4SLinus Torvalds z = packet[5]; 2011da177e4SLinus Torvalds } 2021da177e4SLinus Torvalds 20399df65e7SKevin Cernekee if (priv->flags & ALPS_FW_BK_1) { 2043c00bb96SLaszlo Kajan back = packet[0] & 0x10; 2053c00bb96SLaszlo Kajan forward = packet[2] & 4; 206c30b4c10SIvan Casado Ruiz } 207c30b4c10SIvan Casado Ruiz 20899df65e7SKevin Cernekee if (priv->flags & ALPS_FW_BK_2) { 209c30b4c10SIvan Casado Ruiz back = packet[3] & 4; 210c30b4c10SIvan Casado Ruiz forward = packet[2] & 4; 211c30b4c10SIvan Casado Ruiz if ((middle = forward && back)) 212c30b4c10SIvan Casado Ruiz forward = back = 0; 213c30b4c10SIvan Casado Ruiz } 214c30b4c10SIvan Casado Ruiz 2151da177e4SLinus Torvalds ges = packet[2] & 1; 2161da177e4SLinus Torvalds fin = packet[2] & 2; 2171da177e4SLinus Torvalds 21899df65e7SKevin Cernekee if ((priv->flags & ALPS_DUALPOINT) && z == 127) { 2191da177e4SLinus Torvalds input_report_rel(dev2, REL_X, (x > 383 ? (x - 768) : x)); 2201da177e4SLinus Torvalds input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y)); 221d7ed5d88SUlrich Dangel 2221d9f2626SSebastian Kapfer alps_report_buttons(psmouse, dev2, dev, left, right, middle); 223d7ed5d88SUlrich Dangel 2241da177e4SLinus Torvalds input_sync(dev2); 2251da177e4SLinus Torvalds return; 2261da177e4SLinus Torvalds } 2271da177e4SLinus Torvalds 2281d9f2626SSebastian Kapfer alps_report_buttons(psmouse, dev, dev2, left, right, middle); 229d7ed5d88SUlrich Dangel 2301da177e4SLinus Torvalds /* Convert hardware tap to a reasonable Z value */ 23171bb21b6SMaxim Levitsky if (ges && !fin) 23271bb21b6SMaxim Levitsky z = 40; 2331da177e4SLinus Torvalds 2341da177e4SLinus Torvalds /* 2351da177e4SLinus Torvalds * A "tap and drag" operation is reported by the hardware as a transition 2361da177e4SLinus Torvalds * from (!fin && ges) to (fin && ges). This should be translated to the 2371da177e4SLinus Torvalds * sequence Z>0, Z==0, Z>0, so the Z==0 event has to be generated manually. 2381da177e4SLinus Torvalds */ 2391da177e4SLinus Torvalds if (ges && fin && !priv->prev_fin) { 2401da177e4SLinus Torvalds input_report_abs(dev, ABS_X, x); 2411da177e4SLinus Torvalds input_report_abs(dev, ABS_Y, y); 2421da177e4SLinus Torvalds input_report_abs(dev, ABS_PRESSURE, 0); 2431da177e4SLinus Torvalds input_report_key(dev, BTN_TOOL_FINGER, 0); 2441da177e4SLinus Torvalds input_sync(dev); 2451da177e4SLinus Torvalds } 2461da177e4SLinus Torvalds priv->prev_fin = fin; 2471da177e4SLinus Torvalds 24871bb21b6SMaxim Levitsky if (z > 30) 24971bb21b6SMaxim Levitsky input_report_key(dev, BTN_TOUCH, 1); 25071bb21b6SMaxim Levitsky if (z < 25) 25171bb21b6SMaxim Levitsky input_report_key(dev, BTN_TOUCH, 0); 2521da177e4SLinus Torvalds 2531da177e4SLinus Torvalds if (z > 0) { 2541da177e4SLinus Torvalds input_report_abs(dev, ABS_X, x); 2551da177e4SLinus Torvalds input_report_abs(dev, ABS_Y, y); 2561da177e4SLinus Torvalds } 2571da177e4SLinus Torvalds 2581da177e4SLinus Torvalds input_report_abs(dev, ABS_PRESSURE, z); 2591da177e4SLinus Torvalds input_report_key(dev, BTN_TOOL_FINGER, z > 0); 2601da177e4SLinus Torvalds 26199df65e7SKevin Cernekee if (priv->flags & ALPS_WHEEL) 262e6c047b9SVojtech Pavlik input_report_rel(dev, REL_WHEEL, ((packet[2] << 1) & 0x08) - ((packet[0] >> 4) & 0x07)); 2631da177e4SLinus Torvalds 26499df65e7SKevin Cernekee if (priv->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { 265c30b4c10SIvan Casado Ruiz input_report_key(dev, BTN_FORWARD, forward); 266c30b4c10SIvan Casado Ruiz input_report_key(dev, BTN_BACK, back); 2671da177e4SLinus Torvalds } 2681da177e4SLinus Torvalds 26999df65e7SKevin Cernekee if (priv->flags & ALPS_FOUR_BUTTONS) { 27071bb21b6SMaxim Levitsky input_report_key(dev, BTN_0, packet[2] & 4); 27171bb21b6SMaxim Levitsky input_report_key(dev, BTN_1, packet[0] & 0x10); 27271bb21b6SMaxim Levitsky input_report_key(dev, BTN_2, packet[3] & 4); 27371bb21b6SMaxim Levitsky input_report_key(dev, BTN_3, packet[0] & 0x20); 27471bb21b6SMaxim Levitsky } 27571bb21b6SMaxim Levitsky 2761da177e4SLinus Torvalds input_sync(dev); 2771da177e4SLinus Torvalds } 2781da177e4SLinus Torvalds 27901ce661fSSeth Forshee /* 280ee65d4b3SYunkang Tang * Process bitmap data for V5 protocols. Return value is null. 281ee65d4b3SYunkang Tang * 282ee65d4b3SYunkang Tang * The bitmaps don't have enough data to track fingers, so this function 283ee65d4b3SYunkang Tang * only generates points representing a bounding box of at most two contacts. 284ee65d4b3SYunkang Tang * These two points are returned in x1, y1, x2, and y2. 285ee65d4b3SYunkang Tang */ 286ee65d4b3SYunkang Tang static void alps_process_bitmap_dolphin(struct alps_data *priv, 287ee65d4b3SYunkang Tang struct alps_fields *fields, 288ee65d4b3SYunkang Tang int *x1, int *y1, int *x2, int *y2) 289ee65d4b3SYunkang Tang { 290ee65d4b3SYunkang Tang int box_middle_x, box_middle_y; 291ee65d4b3SYunkang Tang unsigned int x_map, y_map; 292ee65d4b3SYunkang Tang unsigned char start_bit, end_bit; 293ee65d4b3SYunkang Tang unsigned char x_msb, x_lsb, y_msb, y_lsb; 294ee65d4b3SYunkang Tang 295ee65d4b3SYunkang Tang x_map = fields->x_map; 296ee65d4b3SYunkang Tang y_map = fields->y_map; 297ee65d4b3SYunkang Tang 298ee65d4b3SYunkang Tang if (!x_map || !y_map) 299ee65d4b3SYunkang Tang return; 300ee65d4b3SYunkang Tang 301ee65d4b3SYunkang Tang /* Get Most-significant and Least-significant bit */ 302ee65d4b3SYunkang Tang x_msb = fls(x_map); 303ee65d4b3SYunkang Tang x_lsb = ffs(x_map); 304ee65d4b3SYunkang Tang y_msb = fls(y_map); 305ee65d4b3SYunkang Tang y_lsb = ffs(y_map); 306ee65d4b3SYunkang Tang 307ee65d4b3SYunkang Tang /* Most-significant bit should never exceed max sensor line number */ 308ee65d4b3SYunkang Tang if (x_msb > priv->x_bits || y_msb > priv->y_bits) 309ee65d4b3SYunkang Tang return; 310ee65d4b3SYunkang Tang 311ee65d4b3SYunkang Tang *x1 = *y1 = *x2 = *y2 = 0; 312ee65d4b3SYunkang Tang 313ee65d4b3SYunkang Tang if (fields->fingers > 1) { 314ee65d4b3SYunkang Tang start_bit = priv->x_bits - x_msb; 315ee65d4b3SYunkang Tang end_bit = priv->x_bits - x_lsb; 316ee65d4b3SYunkang Tang box_middle_x = (priv->x_max * (start_bit + end_bit)) / 317ee65d4b3SYunkang Tang (2 * (priv->x_bits - 1)); 318ee65d4b3SYunkang Tang 319ee65d4b3SYunkang Tang start_bit = y_lsb - 1; 320ee65d4b3SYunkang Tang end_bit = y_msb - 1; 321ee65d4b3SYunkang Tang box_middle_y = (priv->y_max * (start_bit + end_bit)) / 322ee65d4b3SYunkang Tang (2 * (priv->y_bits - 1)); 323ee65d4b3SYunkang Tang *x1 = fields->x; 324ee65d4b3SYunkang Tang *y1 = fields->y; 325ee65d4b3SYunkang Tang *x2 = 2 * box_middle_x - *x1; 326ee65d4b3SYunkang Tang *y2 = 2 * box_middle_y - *y1; 327ee65d4b3SYunkang Tang } 328ee65d4b3SYunkang Tang } 329ee65d4b3SYunkang Tang 330ee65d4b3SYunkang Tang /* 33101ce661fSSeth Forshee * Process bitmap data from v3 and v4 protocols. Returns the number of 33201ce661fSSeth Forshee * fingers detected. A return value of 0 means at least one of the 33301ce661fSSeth Forshee * bitmaps was empty. 33401ce661fSSeth Forshee * 33501ce661fSSeth Forshee * The bitmaps don't have enough data to track fingers, so this function 33601ce661fSSeth Forshee * only generates points representing a bounding box of all contacts. 33701ce661fSSeth Forshee * These points are returned in x1, y1, x2, and y2 when the return value 33801ce661fSSeth Forshee * is greater than 0. 33901ce661fSSeth Forshee */ 3407a9f73e7SKevin Cernekee static int alps_process_bitmap(struct alps_data *priv, 3417a9f73e7SKevin Cernekee unsigned int x_map, unsigned int y_map, 34201ce661fSSeth Forshee int *x1, int *y1, int *x2, int *y2) 34301ce661fSSeth Forshee { 34401ce661fSSeth Forshee struct alps_bitmap_point { 34501ce661fSSeth Forshee int start_bit; 34601ce661fSSeth Forshee int num_bits; 34701ce661fSSeth Forshee }; 34801ce661fSSeth Forshee 34901ce661fSSeth Forshee int fingers_x = 0, fingers_y = 0, fingers; 35001ce661fSSeth Forshee int i, bit, prev_bit; 35101ce661fSSeth Forshee struct alps_bitmap_point x_low = {0,}, x_high = {0,}; 35201ce661fSSeth Forshee struct alps_bitmap_point y_low = {0,}, y_high = {0,}; 35301ce661fSSeth Forshee struct alps_bitmap_point *point; 35401ce661fSSeth Forshee 35501ce661fSSeth Forshee if (!x_map || !y_map) 35601ce661fSSeth Forshee return 0; 35701ce661fSSeth Forshee 35801ce661fSSeth Forshee *x1 = *y1 = *x2 = *y2 = 0; 35901ce661fSSeth Forshee 36001ce661fSSeth Forshee prev_bit = 0; 36101ce661fSSeth Forshee point = &x_low; 36201ce661fSSeth Forshee for (i = 0; x_map != 0; i++, x_map >>= 1) { 36301ce661fSSeth Forshee bit = x_map & 1; 36401ce661fSSeth Forshee if (bit) { 36501ce661fSSeth Forshee if (!prev_bit) { 36601ce661fSSeth Forshee point->start_bit = i; 36701ce661fSSeth Forshee fingers_x++; 36801ce661fSSeth Forshee } 36901ce661fSSeth Forshee point->num_bits++; 37001ce661fSSeth Forshee } else { 37101ce661fSSeth Forshee if (prev_bit) 37201ce661fSSeth Forshee point = &x_high; 37301ce661fSSeth Forshee else 37401ce661fSSeth Forshee point->num_bits = 0; 37501ce661fSSeth Forshee } 37601ce661fSSeth Forshee prev_bit = bit; 37701ce661fSSeth Forshee } 37801ce661fSSeth Forshee 37901ce661fSSeth Forshee /* 38001ce661fSSeth Forshee * y bitmap is reversed for what we need (lower positions are in 38101ce661fSSeth Forshee * higher bits), so we process from the top end. 38201ce661fSSeth Forshee */ 3837a9f73e7SKevin Cernekee y_map = y_map << (sizeof(y_map) * BITS_PER_BYTE - priv->y_bits); 38401ce661fSSeth Forshee prev_bit = 0; 38501ce661fSSeth Forshee point = &y_low; 38601ce661fSSeth Forshee for (i = 0; y_map != 0; i++, y_map <<= 1) { 38701ce661fSSeth Forshee bit = y_map & (1 << (sizeof(y_map) * BITS_PER_BYTE - 1)); 38801ce661fSSeth Forshee if (bit) { 38901ce661fSSeth Forshee if (!prev_bit) { 39001ce661fSSeth Forshee point->start_bit = i; 39101ce661fSSeth Forshee fingers_y++; 39201ce661fSSeth Forshee } 39301ce661fSSeth Forshee point->num_bits++; 39401ce661fSSeth Forshee } else { 39501ce661fSSeth Forshee if (prev_bit) 39601ce661fSSeth Forshee point = &y_high; 39701ce661fSSeth Forshee else 39801ce661fSSeth Forshee point->num_bits = 0; 39901ce661fSSeth Forshee } 40001ce661fSSeth Forshee prev_bit = bit; 40101ce661fSSeth Forshee } 40201ce661fSSeth Forshee 40301ce661fSSeth Forshee /* 40401ce661fSSeth Forshee * Fingers can overlap, so we use the maximum count of fingers 40501ce661fSSeth Forshee * on either axis as the finger count. 40601ce661fSSeth Forshee */ 40701ce661fSSeth Forshee fingers = max(fingers_x, fingers_y); 40801ce661fSSeth Forshee 40901ce661fSSeth Forshee /* 41020bea68bSHans de Goede * If an axis reports only a single contact, we have overlapping or 41120bea68bSHans de Goede * adjacent fingers. Divide the single contact between the two points. 41201ce661fSSeth Forshee */ 41301ce661fSSeth Forshee if (fingers_x == 1) { 41401ce661fSSeth Forshee i = x_low.num_bits / 2; 41501ce661fSSeth Forshee x_low.num_bits = x_low.num_bits - i; 41601ce661fSSeth Forshee x_high.start_bit = x_low.start_bit + i; 41701ce661fSSeth Forshee x_high.num_bits = max(i, 1); 41820bea68bSHans de Goede } 41920bea68bSHans de Goede if (fingers_y == 1) { 42001ce661fSSeth Forshee i = y_low.num_bits / 2; 42101ce661fSSeth Forshee y_low.num_bits = y_low.num_bits - i; 42201ce661fSSeth Forshee y_high.start_bit = y_low.start_bit + i; 42301ce661fSSeth Forshee y_high.num_bits = max(i, 1); 42401ce661fSSeth Forshee } 42501ce661fSSeth Forshee 4267a9f73e7SKevin Cernekee *x1 = (priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) / 4277a9f73e7SKevin Cernekee (2 * (priv->x_bits - 1)); 4287a9f73e7SKevin Cernekee *y1 = (priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) / 4297a9f73e7SKevin Cernekee (2 * (priv->y_bits - 1)); 43001ce661fSSeth Forshee 4317a9f73e7SKevin Cernekee *x2 = (priv->x_max * 4327a9f73e7SKevin Cernekee (2 * x_high.start_bit + x_high.num_bits - 1)) / 4337a9f73e7SKevin Cernekee (2 * (priv->x_bits - 1)); 4347a9f73e7SKevin Cernekee *y2 = (priv->y_max * 4357a9f73e7SKevin Cernekee (2 * y_high.start_bit + y_high.num_bits - 1)) / 4367a9f73e7SKevin Cernekee (2 * (priv->y_bits - 1)); 43701ce661fSSeth Forshee 43801ce661fSSeth Forshee return fingers; 43901ce661fSSeth Forshee } 44001ce661fSSeth Forshee 44101ce661fSSeth Forshee static void alps_set_slot(struct input_dev *dev, int slot, bool active, 44201ce661fSSeth Forshee int x, int y) 44301ce661fSSeth Forshee { 44401ce661fSSeth Forshee input_mt_slot(dev, slot); 44501ce661fSSeth Forshee input_mt_report_slot_state(dev, MT_TOOL_FINGER, active); 44601ce661fSSeth Forshee if (active) { 44701ce661fSSeth Forshee input_report_abs(dev, ABS_MT_POSITION_X, x); 44801ce661fSSeth Forshee input_report_abs(dev, ABS_MT_POSITION_Y, y); 44901ce661fSSeth Forshee } 45001ce661fSSeth Forshee } 45101ce661fSSeth Forshee 45201ce661fSSeth Forshee static void alps_report_semi_mt_data(struct input_dev *dev, int num_fingers, 45301ce661fSSeth Forshee int x1, int y1, int x2, int y2) 45401ce661fSSeth Forshee { 45501ce661fSSeth Forshee alps_set_slot(dev, 0, num_fingers != 0, x1, y1); 45601ce661fSSeth Forshee alps_set_slot(dev, 1, num_fingers == 2, x2, y2); 45701ce661fSSeth Forshee } 45801ce661fSSeth Forshee 45925bded7cSSeth Forshee static void alps_process_trackstick_packet_v3(struct psmouse *psmouse) 46025bded7cSSeth Forshee { 46125bded7cSSeth Forshee struct alps_data *priv = psmouse->private; 46225bded7cSSeth Forshee unsigned char *packet = psmouse->packet; 46325bded7cSSeth Forshee struct input_dev *dev = priv->dev2; 46425bded7cSSeth Forshee int x, y, z, left, right, middle; 46525bded7cSSeth Forshee 46625bded7cSSeth Forshee /* Sanity check packet */ 46725bded7cSSeth Forshee if (!(packet[0] & 0x40)) { 46825bded7cSSeth Forshee psmouse_dbg(psmouse, "Bad trackstick packet, discarding\n"); 46925bded7cSSeth Forshee return; 47025bded7cSSeth Forshee } 47125bded7cSSeth Forshee 47225bded7cSSeth Forshee /* 47325bded7cSSeth Forshee * There's a special packet that seems to indicate the end 47425bded7cSSeth Forshee * of a stream of trackstick data. Filter these out. 47525bded7cSSeth Forshee */ 47625bded7cSSeth Forshee if (packet[1] == 0x7f && packet[2] == 0x7f && packet[4] == 0x7f) 47725bded7cSSeth Forshee return; 47825bded7cSSeth Forshee 47925bded7cSSeth Forshee x = (s8)(((packet[0] & 0x20) << 2) | (packet[1] & 0x7f)); 48025bded7cSSeth Forshee y = (s8)(((packet[0] & 0x10) << 3) | (packet[2] & 0x7f)); 48125bded7cSSeth Forshee z = (packet[4] & 0x7c) >> 2; 48225bded7cSSeth Forshee 48325bded7cSSeth Forshee /* 48425bded7cSSeth Forshee * The x and y values tend to be quite large, and when used 48525bded7cSSeth Forshee * alone the trackstick is difficult to use. Scale them down 48625bded7cSSeth Forshee * to compensate. 48725bded7cSSeth Forshee */ 48825bded7cSSeth Forshee x /= 8; 48925bded7cSSeth Forshee y /= 8; 49025bded7cSSeth Forshee 49125bded7cSSeth Forshee input_report_rel(dev, REL_X, x); 49225bded7cSSeth Forshee input_report_rel(dev, REL_Y, -y); 49325bded7cSSeth Forshee 49425bded7cSSeth Forshee /* 49525bded7cSSeth Forshee * Most ALPS models report the trackstick buttons in the touchpad 49625bded7cSSeth Forshee * packets, but a few report them here. No reliable way has been 49725bded7cSSeth Forshee * found to differentiate between the models upfront, so we enable 49825bded7cSSeth Forshee * the quirk in response to seeing a button press in the trackstick 49925bded7cSSeth Forshee * packet. 50025bded7cSSeth Forshee */ 50125bded7cSSeth Forshee left = packet[3] & 0x01; 50225bded7cSSeth Forshee right = packet[3] & 0x02; 50325bded7cSSeth Forshee middle = packet[3] & 0x04; 50425bded7cSSeth Forshee 50525bded7cSSeth Forshee if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS) && 50625bded7cSSeth Forshee (left || right || middle)) 50725bded7cSSeth Forshee priv->quirks |= ALPS_QUIRK_TRACKSTICK_BUTTONS; 50825bded7cSSeth Forshee 50925bded7cSSeth Forshee if (priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS) { 51025bded7cSSeth Forshee input_report_key(dev, BTN_LEFT, left); 51125bded7cSSeth Forshee input_report_key(dev, BTN_RIGHT, right); 51225bded7cSSeth Forshee input_report_key(dev, BTN_MIDDLE, middle); 51325bded7cSSeth Forshee } 51425bded7cSSeth Forshee 51525bded7cSSeth Forshee input_sync(dev); 51625bded7cSSeth Forshee return; 51725bded7cSSeth Forshee } 51825bded7cSSeth Forshee 519f85e5001SKevin Cernekee static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p) 520f85e5001SKevin Cernekee { 521f85e5001SKevin Cernekee f->left = !!(p[3] & 0x01); 522f85e5001SKevin Cernekee f->right = !!(p[3] & 0x02); 523f85e5001SKevin Cernekee f->middle = !!(p[3] & 0x04); 524f85e5001SKevin Cernekee 525f85e5001SKevin Cernekee f->ts_left = !!(p[3] & 0x10); 526f85e5001SKevin Cernekee f->ts_right = !!(p[3] & 0x20); 527f85e5001SKevin Cernekee f->ts_middle = !!(p[3] & 0x40); 528f85e5001SKevin Cernekee } 529f85e5001SKevin Cernekee 530ee65d4b3SYunkang Tang static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p, 531ee65d4b3SYunkang Tang struct psmouse *psmouse) 532f85e5001SKevin Cernekee { 533f85e5001SKevin Cernekee f->first_mp = !!(p[4] & 0x40); 534f85e5001SKevin Cernekee f->is_mp = !!(p[0] & 0x40); 535f85e5001SKevin Cernekee 536f85e5001SKevin Cernekee f->fingers = (p[5] & 0x3) + 1; 537f85e5001SKevin Cernekee f->x_map = ((p[4] & 0x7e) << 8) | 538f85e5001SKevin Cernekee ((p[1] & 0x7f) << 2) | 539f85e5001SKevin Cernekee ((p[0] & 0x30) >> 4); 540f85e5001SKevin Cernekee f->y_map = ((p[3] & 0x70) << 4) | 541f85e5001SKevin Cernekee ((p[2] & 0x7f) << 1) | 542f85e5001SKevin Cernekee (p[4] & 0x01); 543f85e5001SKevin Cernekee 544f85e5001SKevin Cernekee f->x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) | 545f85e5001SKevin Cernekee ((p[0] & 0x30) >> 4); 546f85e5001SKevin Cernekee f->y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f); 547f85e5001SKevin Cernekee f->z = p[5] & 0x7f; 548f85e5001SKevin Cernekee 549f85e5001SKevin Cernekee alps_decode_buttons_v3(f, p); 550f85e5001SKevin Cernekee } 551f85e5001SKevin Cernekee 552ee65d4b3SYunkang Tang static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p, 553ee65d4b3SYunkang Tang struct psmouse *psmouse) 5541302bac3SKevin Cernekee { 555ee65d4b3SYunkang Tang alps_decode_pinnacle(f, p, psmouse); 5561302bac3SKevin Cernekee 557f105e34aSYunkang Tang /* Rushmore's packet decode has a bit difference with Pinnacle's */ 558f105e34aSYunkang Tang f->is_mp = !!(p[5] & 0x40); 559f105e34aSYunkang Tang f->fingers = max((p[5] & 0x3), ((p[5] >> 2) & 0x3)) + 1; 5601302bac3SKevin Cernekee f->x_map |= (p[5] & 0x10) << 11; 5611302bac3SKevin Cernekee f->y_map |= (p[5] & 0x20) << 6; 5621302bac3SKevin Cernekee } 5631302bac3SKevin Cernekee 564ee65d4b3SYunkang Tang static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p, 565ee65d4b3SYunkang Tang struct psmouse *psmouse) 56675af9e56SDave Turvene { 567ee65d4b3SYunkang Tang u64 palm_data = 0; 568ee65d4b3SYunkang Tang struct alps_data *priv = psmouse->private; 569ee65d4b3SYunkang Tang 57075af9e56SDave Turvene f->first_mp = !!(p[0] & 0x02); 57175af9e56SDave Turvene f->is_mp = !!(p[0] & 0x20); 57275af9e56SDave Turvene 573ee65d4b3SYunkang Tang if (!f->is_mp) { 57475af9e56SDave Turvene f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7)); 57575af9e56SDave Turvene f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3)); 57675af9e56SDave Turvene f->z = (p[0] & 4) ? 0 : p[5] & 0x7f; 57775af9e56SDave Turvene alps_decode_buttons_v3(f, p); 578ee65d4b3SYunkang Tang } else { 579ee65d4b3SYunkang Tang f->fingers = ((p[0] & 0x6) >> 1 | 580ee65d4b3SYunkang Tang (p[0] & 0x10) >> 2); 581ee65d4b3SYunkang Tang 582ee65d4b3SYunkang Tang palm_data = (p[1] & 0x7f) | 583ee65d4b3SYunkang Tang ((p[2] & 0x7f) << 7) | 584ee65d4b3SYunkang Tang ((p[4] & 0x7f) << 14) | 585ee65d4b3SYunkang Tang ((p[5] & 0x7f) << 21) | 586ee65d4b3SYunkang Tang ((p[3] & 0x07) << 28) | 587ee65d4b3SYunkang Tang (((u64)p[3] & 0x70) << 27) | 588ee65d4b3SYunkang Tang (((u64)p[0] & 0x01) << 34); 589ee65d4b3SYunkang Tang 590ee65d4b3SYunkang Tang /* Y-profile is stored in P(0) to p(n-1), n = y_bits; */ 591ee65d4b3SYunkang Tang f->y_map = palm_data & (BIT(priv->y_bits) - 1); 592ee65d4b3SYunkang Tang 593ee65d4b3SYunkang Tang /* X-profile is stored in p(n) to p(n+m-1), m = x_bits; */ 594ee65d4b3SYunkang Tang f->x_map = (palm_data >> priv->y_bits) & 595ee65d4b3SYunkang Tang (BIT(priv->x_bits) - 1); 596ee65d4b3SYunkang Tang } 59775af9e56SDave Turvene } 59875af9e56SDave Turvene 599ee65d4b3SYunkang Tang static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse) 60025bded7cSSeth Forshee { 60125bded7cSSeth Forshee struct alps_data *priv = psmouse->private; 60225bded7cSSeth Forshee unsigned char *packet = psmouse->packet; 60325bded7cSSeth Forshee struct input_dev *dev = psmouse->dev; 60425bded7cSSeth Forshee struct input_dev *dev2 = priv->dev2; 60520bea68bSHans de Goede int x1 = 0, y1 = 0, x2 = 0, y2 = 0, fingers = 0; 606ee65d4b3SYunkang Tang struct alps_fields f = {0}; 607f85e5001SKevin Cernekee 608ee65d4b3SYunkang Tang priv->decode_fields(&f, packet, psmouse); 60925bded7cSSeth Forshee 61025bded7cSSeth Forshee /* 61101ce661fSSeth Forshee * There's no single feature of touchpad position and bitmap packets 61201ce661fSSeth Forshee * that can be used to distinguish between them. We rely on the fact 61301ce661fSSeth Forshee * that a bitmap packet should always follow a position packet with 61401ce661fSSeth Forshee * bit 6 of packet[4] set. 61525bded7cSSeth Forshee */ 61625bded7cSSeth Forshee if (priv->multi_packet) { 61725bded7cSSeth Forshee /* 61825bded7cSSeth Forshee * Sometimes a position packet will indicate a multi-packet 61925bded7cSSeth Forshee * sequence, but then what follows is another position 62025bded7cSSeth Forshee * packet. Check for this, and when it happens process the 62125bded7cSSeth Forshee * position packet as usual. 62225bded7cSSeth Forshee */ 623f85e5001SKevin Cernekee if (f.is_mp) { 624f85e5001SKevin Cernekee fingers = f.fingers; 625ee65d4b3SYunkang Tang if (priv->proto_version == ALPS_PROTO_V3) { 62620bea68bSHans de Goede if (alps_process_bitmap(priv, f.x_map, 627ee65d4b3SYunkang Tang f.y_map, &x1, &y1, 62820bea68bSHans de Goede &x2, &y2) == 0) 62920bea68bSHans de Goede fingers = 0; /* Use st data */ 63001ce661fSSeth Forshee 63101ce661fSSeth Forshee /* Now process position packet */ 632ee65d4b3SYunkang Tang priv->decode_fields(&f, priv->multi_data, 633ee65d4b3SYunkang Tang psmouse); 634ee65d4b3SYunkang Tang } else { 635ee65d4b3SYunkang Tang /* 636ee65d4b3SYunkang Tang * Because Dolphin uses position packet's 637ee65d4b3SYunkang Tang * coordinate data as Pt1 and uses it to 638ee65d4b3SYunkang Tang * calculate Pt2, so we need to do position 639ee65d4b3SYunkang Tang * packet decode first. 640ee65d4b3SYunkang Tang */ 641ee65d4b3SYunkang Tang priv->decode_fields(&f, priv->multi_data, 642ee65d4b3SYunkang Tang psmouse); 643ee65d4b3SYunkang Tang 644ee65d4b3SYunkang Tang /* 645ee65d4b3SYunkang Tang * Since Dolphin's finger number is reliable, 646ee65d4b3SYunkang Tang * there is no need to compare with bmap_fn. 647ee65d4b3SYunkang Tang */ 648ee65d4b3SYunkang Tang alps_process_bitmap_dolphin(priv, &f, &x1, &y1, 649ee65d4b3SYunkang Tang &x2, &y2); 650ee65d4b3SYunkang Tang } 65101ce661fSSeth Forshee } else { 65201ce661fSSeth Forshee priv->multi_packet = 0; 65325bded7cSSeth Forshee } 65425bded7cSSeth Forshee } 65525bded7cSSeth Forshee 65601ce661fSSeth Forshee /* 65701ce661fSSeth Forshee * Bit 6 of byte 0 is not usually set in position packets. The only 65801ce661fSSeth Forshee * times it seems to be set is in situations where the data is 65901ce661fSSeth Forshee * suspect anyway, e.g. a palm resting flat on the touchpad. Given 66001ce661fSSeth Forshee * this combined with the fact that this bit is useful for filtering 66101ce661fSSeth Forshee * out misidentified bitmap packets, we reject anything with this 66201ce661fSSeth Forshee * bit set. 66301ce661fSSeth Forshee */ 664f85e5001SKevin Cernekee if (f.is_mp) 66501ce661fSSeth Forshee return; 66601ce661fSSeth Forshee 667f85e5001SKevin Cernekee if (!priv->multi_packet && f.first_mp) { 66825bded7cSSeth Forshee priv->multi_packet = 1; 66901ce661fSSeth Forshee memcpy(priv->multi_data, packet, sizeof(priv->multi_data)); 67001ce661fSSeth Forshee return; 67101ce661fSSeth Forshee } 67201ce661fSSeth Forshee 67325bded7cSSeth Forshee priv->multi_packet = 0; 67425bded7cSSeth Forshee 67525bded7cSSeth Forshee /* 67625bded7cSSeth Forshee * Sometimes the hardware sends a single packet with z = 0 67725bded7cSSeth Forshee * in the middle of a stream. Real releases generate packets 67825bded7cSSeth Forshee * with x, y, and z all zero, so these seem to be flukes. 67925bded7cSSeth Forshee * Ignore them. 68025bded7cSSeth Forshee */ 681f85e5001SKevin Cernekee if (f.x && f.y && !f.z) 68225bded7cSSeth Forshee return; 68325bded7cSSeth Forshee 68401ce661fSSeth Forshee /* 68501ce661fSSeth Forshee * If we don't have MT data or the bitmaps were empty, we have 68601ce661fSSeth Forshee * to rely on ST data. 68701ce661fSSeth Forshee */ 68801ce661fSSeth Forshee if (!fingers) { 689f85e5001SKevin Cernekee x1 = f.x; 690f85e5001SKevin Cernekee y1 = f.y; 691f85e5001SKevin Cernekee fingers = f.z > 0 ? 1 : 0; 69201ce661fSSeth Forshee } 69301ce661fSSeth Forshee 694f85e5001SKevin Cernekee if (f.z >= 64) 69525bded7cSSeth Forshee input_report_key(dev, BTN_TOUCH, 1); 69625bded7cSSeth Forshee else 69725bded7cSSeth Forshee input_report_key(dev, BTN_TOUCH, 0); 69825bded7cSSeth Forshee 69901ce661fSSeth Forshee alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2); 70001ce661fSSeth Forshee 701616575c2SDmitry Torokhov input_mt_report_finger_count(dev, fingers); 70201ce661fSSeth Forshee 703f85e5001SKevin Cernekee input_report_key(dev, BTN_LEFT, f.left); 704f85e5001SKevin Cernekee input_report_key(dev, BTN_RIGHT, f.right); 705f85e5001SKevin Cernekee input_report_key(dev, BTN_MIDDLE, f.middle); 70601ce661fSSeth Forshee 707f85e5001SKevin Cernekee if (f.z > 0) { 708f85e5001SKevin Cernekee input_report_abs(dev, ABS_X, f.x); 709f85e5001SKevin Cernekee input_report_abs(dev, ABS_Y, f.y); 71025bded7cSSeth Forshee } 711f85e5001SKevin Cernekee input_report_abs(dev, ABS_PRESSURE, f.z); 71225bded7cSSeth Forshee 71325bded7cSSeth Forshee input_sync(dev); 71425bded7cSSeth Forshee 71525bded7cSSeth Forshee if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) { 716f85e5001SKevin Cernekee input_report_key(dev2, BTN_LEFT, f.ts_left); 717f85e5001SKevin Cernekee input_report_key(dev2, BTN_RIGHT, f.ts_right); 718f85e5001SKevin Cernekee input_report_key(dev2, BTN_MIDDLE, f.ts_middle); 71925bded7cSSeth Forshee input_sync(dev2); 72025bded7cSSeth Forshee } 72125bded7cSSeth Forshee } 72225bded7cSSeth Forshee 72325bded7cSSeth Forshee static void alps_process_packet_v3(struct psmouse *psmouse) 72425bded7cSSeth Forshee { 72525bded7cSSeth Forshee unsigned char *packet = psmouse->packet; 72625bded7cSSeth Forshee 72725bded7cSSeth Forshee /* 72825bded7cSSeth Forshee * v3 protocol packets come in three types, two representing 72925bded7cSSeth Forshee * touchpad data and one representing trackstick data. 73025bded7cSSeth Forshee * Trackstick packets seem to be distinguished by always 73125bded7cSSeth Forshee * having 0x3f in the last byte. This value has never been 73225bded7cSSeth Forshee * observed in the last byte of either of the other types 73325bded7cSSeth Forshee * of packets. 73425bded7cSSeth Forshee */ 73525bded7cSSeth Forshee if (packet[5] == 0x3f) { 73625bded7cSSeth Forshee alps_process_trackstick_packet_v3(psmouse); 73725bded7cSSeth Forshee return; 73825bded7cSSeth Forshee } 73925bded7cSSeth Forshee 740ee65d4b3SYunkang Tang alps_process_touchpad_packet_v3_v5(psmouse); 74125bded7cSSeth Forshee } 74225bded7cSSeth Forshee 74395f75e91SYunkang Tang static void alps_process_packet_v6(struct psmouse *psmouse) 74495f75e91SYunkang Tang { 74595f75e91SYunkang Tang struct alps_data *priv = psmouse->private; 74695f75e91SYunkang Tang unsigned char *packet = psmouse->packet; 74795f75e91SYunkang Tang struct input_dev *dev = psmouse->dev; 74895f75e91SYunkang Tang struct input_dev *dev2 = priv->dev2; 74995f75e91SYunkang Tang int x, y, z, left, right, middle; 75095f75e91SYunkang Tang 75195f75e91SYunkang Tang /* 75295f75e91SYunkang Tang * We can use Byte5 to distinguish if the packet is from Touchpad 75395f75e91SYunkang Tang * or Trackpoint. 75495f75e91SYunkang Tang * Touchpad: 0 - 0x7E 75595f75e91SYunkang Tang * Trackpoint: 0x7F 75695f75e91SYunkang Tang */ 75795f75e91SYunkang Tang if (packet[5] == 0x7F) { 75895f75e91SYunkang Tang /* It should be a DualPoint when received Trackpoint packet */ 75995f75e91SYunkang Tang if (!(priv->flags & ALPS_DUALPOINT)) 76095f75e91SYunkang Tang return; 76195f75e91SYunkang Tang 76295f75e91SYunkang Tang /* Trackpoint packet */ 76395f75e91SYunkang Tang x = packet[1] | ((packet[3] & 0x20) << 2); 76495f75e91SYunkang Tang y = packet[2] | ((packet[3] & 0x40) << 1); 76595f75e91SYunkang Tang z = packet[4]; 76695f75e91SYunkang Tang left = packet[3] & 0x01; 76795f75e91SYunkang Tang right = packet[3] & 0x02; 76895f75e91SYunkang Tang middle = packet[3] & 0x04; 76995f75e91SYunkang Tang 77095f75e91SYunkang Tang /* To prevent the cursor jump when finger lifted */ 77195f75e91SYunkang Tang if (x == 0x7F && y == 0x7F && z == 0x7F) 77295f75e91SYunkang Tang x = y = z = 0; 77395f75e91SYunkang Tang 77495f75e91SYunkang Tang /* Divide 4 since trackpoint's speed is too fast */ 77595f75e91SYunkang Tang input_report_rel(dev2, REL_X, (char)x / 4); 77695f75e91SYunkang Tang input_report_rel(dev2, REL_Y, -((char)y / 4)); 77795f75e91SYunkang Tang 77895f75e91SYunkang Tang input_report_key(dev2, BTN_LEFT, left); 77995f75e91SYunkang Tang input_report_key(dev2, BTN_RIGHT, right); 78095f75e91SYunkang Tang input_report_key(dev2, BTN_MIDDLE, middle); 78195f75e91SYunkang Tang 78295f75e91SYunkang Tang input_sync(dev2); 78395f75e91SYunkang Tang return; 78495f75e91SYunkang Tang } 78595f75e91SYunkang Tang 78695f75e91SYunkang Tang /* Touchpad packet */ 78795f75e91SYunkang Tang x = packet[1] | ((packet[3] & 0x78) << 4); 78895f75e91SYunkang Tang y = packet[2] | ((packet[4] & 0x78) << 4); 78995f75e91SYunkang Tang z = packet[5]; 79095f75e91SYunkang Tang left = packet[3] & 0x01; 79195f75e91SYunkang Tang right = packet[3] & 0x02; 79295f75e91SYunkang Tang 79395f75e91SYunkang Tang if (z > 30) 79495f75e91SYunkang Tang input_report_key(dev, BTN_TOUCH, 1); 79595f75e91SYunkang Tang if (z < 25) 79695f75e91SYunkang Tang input_report_key(dev, BTN_TOUCH, 0); 79795f75e91SYunkang Tang 79895f75e91SYunkang Tang if (z > 0) { 79995f75e91SYunkang Tang input_report_abs(dev, ABS_X, x); 80095f75e91SYunkang Tang input_report_abs(dev, ABS_Y, y); 80195f75e91SYunkang Tang } 80295f75e91SYunkang Tang 80395f75e91SYunkang Tang input_report_abs(dev, ABS_PRESSURE, z); 80495f75e91SYunkang Tang input_report_key(dev, BTN_TOOL_FINGER, z > 0); 80595f75e91SYunkang Tang 80695f75e91SYunkang Tang /* v6 touchpad does not have middle button */ 80795f75e91SYunkang Tang input_report_key(dev, BTN_LEFT, left); 80895f75e91SYunkang Tang input_report_key(dev, BTN_RIGHT, right); 80995f75e91SYunkang Tang 81095f75e91SYunkang Tang input_sync(dev); 81195f75e91SYunkang Tang } 81295f75e91SYunkang Tang 81325bded7cSSeth Forshee static void alps_process_packet_v4(struct psmouse *psmouse) 81425bded7cSSeth Forshee { 8153b7e09faSGeorge Pantalos struct alps_data *priv = psmouse->private; 81625bded7cSSeth Forshee unsigned char *packet = psmouse->packet; 81725bded7cSSeth Forshee struct input_dev *dev = psmouse->dev; 8183b7e09faSGeorge Pantalos int offset; 81925bded7cSSeth Forshee int x, y, z; 82025bded7cSSeth Forshee int left, right; 8213b7e09faSGeorge Pantalos int x1, y1, x2, y2; 8223b7e09faSGeorge Pantalos int fingers = 0; 8233b7e09faSGeorge Pantalos unsigned int x_bitmap, y_bitmap; 8243b7e09faSGeorge Pantalos 8253b7e09faSGeorge Pantalos /* 8263b7e09faSGeorge Pantalos * v4 has a 6-byte encoding for bitmap data, but this data is 8273b7e09faSGeorge Pantalos * broken up between 3 normal packets. Use priv->multi_packet to 8283b7e09faSGeorge Pantalos * track our position in the bitmap packet. 8293b7e09faSGeorge Pantalos */ 8303b7e09faSGeorge Pantalos if (packet[6] & 0x40) { 8313b7e09faSGeorge Pantalos /* sync, reset position */ 8323b7e09faSGeorge Pantalos priv->multi_packet = 0; 8333b7e09faSGeorge Pantalos } 8343b7e09faSGeorge Pantalos 8353b7e09faSGeorge Pantalos if (WARN_ON_ONCE(priv->multi_packet > 2)) 8363b7e09faSGeorge Pantalos return; 8373b7e09faSGeorge Pantalos 8383b7e09faSGeorge Pantalos offset = 2 * priv->multi_packet; 8393b7e09faSGeorge Pantalos priv->multi_data[offset] = packet[6]; 8403b7e09faSGeorge Pantalos priv->multi_data[offset + 1] = packet[7]; 8413b7e09faSGeorge Pantalos 8423b7e09faSGeorge Pantalos if (++priv->multi_packet > 2) { 8433b7e09faSGeorge Pantalos priv->multi_packet = 0; 8443b7e09faSGeorge Pantalos 8453b7e09faSGeorge Pantalos x_bitmap = ((priv->multi_data[2] & 0x1f) << 10) | 8463b7e09faSGeorge Pantalos ((priv->multi_data[3] & 0x60) << 3) | 8473b7e09faSGeorge Pantalos ((priv->multi_data[0] & 0x3f) << 2) | 8483b7e09faSGeorge Pantalos ((priv->multi_data[1] & 0x60) >> 5); 8493b7e09faSGeorge Pantalos y_bitmap = ((priv->multi_data[5] & 0x01) << 10) | 8503b7e09faSGeorge Pantalos ((priv->multi_data[3] & 0x1f) << 5) | 8513b7e09faSGeorge Pantalos (priv->multi_data[1] & 0x1f); 8523b7e09faSGeorge Pantalos 8537a9f73e7SKevin Cernekee fingers = alps_process_bitmap(priv, x_bitmap, y_bitmap, 8543b7e09faSGeorge Pantalos &x1, &y1, &x2, &y2); 8553b7e09faSGeorge Pantalos 8563b7e09faSGeorge Pantalos /* Store MT data.*/ 8573b7e09faSGeorge Pantalos priv->fingers = fingers; 8583b7e09faSGeorge Pantalos priv->x1 = x1; 8593b7e09faSGeorge Pantalos priv->x2 = x2; 8603b7e09faSGeorge Pantalos priv->y1 = y1; 8613b7e09faSGeorge Pantalos priv->y2 = y2; 8623b7e09faSGeorge Pantalos } 86325bded7cSSeth Forshee 86425bded7cSSeth Forshee left = packet[4] & 0x01; 86525bded7cSSeth Forshee right = packet[4] & 0x02; 86625bded7cSSeth Forshee 86725bded7cSSeth Forshee x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) | 86825bded7cSSeth Forshee ((packet[0] & 0x30) >> 4); 86925bded7cSSeth Forshee y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f); 87025bded7cSSeth Forshee z = packet[5] & 0x7f; 87125bded7cSSeth Forshee 8723b7e09faSGeorge Pantalos /* 8733b7e09faSGeorge Pantalos * If there were no contacts in the bitmap, use ST 8743b7e09faSGeorge Pantalos * points in MT reports. 8753b7e09faSGeorge Pantalos * If there were two contacts or more, report MT data. 8763b7e09faSGeorge Pantalos */ 8773b7e09faSGeorge Pantalos if (priv->fingers < 2) { 8783b7e09faSGeorge Pantalos x1 = x; 8793b7e09faSGeorge Pantalos y1 = y; 8803b7e09faSGeorge Pantalos fingers = z > 0 ? 1 : 0; 8813b7e09faSGeorge Pantalos } else { 8823b7e09faSGeorge Pantalos fingers = priv->fingers; 8833b7e09faSGeorge Pantalos x1 = priv->x1; 8843b7e09faSGeorge Pantalos x2 = priv->x2; 8853b7e09faSGeorge Pantalos y1 = priv->y1; 8863b7e09faSGeorge Pantalos y2 = priv->y2; 8873b7e09faSGeorge Pantalos } 8883b7e09faSGeorge Pantalos 88925bded7cSSeth Forshee if (z >= 64) 89025bded7cSSeth Forshee input_report_key(dev, BTN_TOUCH, 1); 89125bded7cSSeth Forshee else 89225bded7cSSeth Forshee input_report_key(dev, BTN_TOUCH, 0); 89325bded7cSSeth Forshee 8943b7e09faSGeorge Pantalos alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2); 8953b7e09faSGeorge Pantalos 896616575c2SDmitry Torokhov input_mt_report_finger_count(dev, fingers); 8973b7e09faSGeorge Pantalos 8983b7e09faSGeorge Pantalos input_report_key(dev, BTN_LEFT, left); 8993b7e09faSGeorge Pantalos input_report_key(dev, BTN_RIGHT, right); 9003b7e09faSGeorge Pantalos 90125bded7cSSeth Forshee if (z > 0) { 90225bded7cSSeth Forshee input_report_abs(dev, ABS_X, x); 90325bded7cSSeth Forshee input_report_abs(dev, ABS_Y, y); 90425bded7cSSeth Forshee } 90525bded7cSSeth Forshee input_report_abs(dev, ABS_PRESSURE, z); 90625bded7cSSeth Forshee 90725bded7cSSeth Forshee input_sync(dev); 90825bded7cSSeth Forshee } 90925bded7cSSeth Forshee 9101d9f2626SSebastian Kapfer static void alps_report_bare_ps2_packet(struct psmouse *psmouse, 9111d9f2626SSebastian Kapfer unsigned char packet[], 9121d9f2626SSebastian Kapfer bool report_buttons) 9131d9f2626SSebastian Kapfer { 9141d9f2626SSebastian Kapfer struct alps_data *priv = psmouse->private; 9151d9f2626SSebastian Kapfer struct input_dev *dev2 = priv->dev2; 9161d9f2626SSebastian Kapfer 9171d9f2626SSebastian Kapfer if (report_buttons) 9181d9f2626SSebastian Kapfer alps_report_buttons(psmouse, dev2, psmouse->dev, 9191d9f2626SSebastian Kapfer packet[0] & 1, packet[0] & 2, packet[0] & 4); 9201d9f2626SSebastian Kapfer 9211d9f2626SSebastian Kapfer input_report_rel(dev2, REL_X, 9221d9f2626SSebastian Kapfer packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0); 9231d9f2626SSebastian Kapfer input_report_rel(dev2, REL_Y, 9241d9f2626SSebastian Kapfer packet[2] ? ((packet[0] << 3) & 0x100) - packet[2] : 0); 9251d9f2626SSebastian Kapfer 9261d9f2626SSebastian Kapfer input_sync(dev2); 9271d9f2626SSebastian Kapfer } 9281d9f2626SSebastian Kapfer 9291d9f2626SSebastian Kapfer static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse) 9301da177e4SLinus Torvalds { 9311da177e4SLinus Torvalds struct alps_data *priv = psmouse->private; 9321da177e4SLinus Torvalds 9331d9f2626SSebastian Kapfer if (psmouse->pktcnt < 6) 9341d9f2626SSebastian Kapfer return PSMOUSE_GOOD_DATA; 9351d9f2626SSebastian Kapfer 9361d9f2626SSebastian Kapfer if (psmouse->pktcnt == 6) { 9371d9f2626SSebastian Kapfer /* 9381d9f2626SSebastian Kapfer * Start a timer to flush the packet if it ends up last 9391d9f2626SSebastian Kapfer * 6-byte packet in the stream. Timer needs to fire 9401d9f2626SSebastian Kapfer * psmouse core times out itself. 20 ms should be enough 9411d9f2626SSebastian Kapfer * to decide if we are getting more data or not. 9421d9f2626SSebastian Kapfer */ 9431d9f2626SSebastian Kapfer mod_timer(&priv->timer, jiffies + msecs_to_jiffies(20)); 9441d9f2626SSebastian Kapfer return PSMOUSE_GOOD_DATA; 9451d9f2626SSebastian Kapfer } 9461d9f2626SSebastian Kapfer 9471d9f2626SSebastian Kapfer del_timer(&priv->timer); 9481d9f2626SSebastian Kapfer 9491d9f2626SSebastian Kapfer if (psmouse->packet[6] & 0x80) { 9501d9f2626SSebastian Kapfer 9511d9f2626SSebastian Kapfer /* 9521d9f2626SSebastian Kapfer * Highest bit is set - that means we either had 9531d9f2626SSebastian Kapfer * complete ALPS packet and this is start of the 9541d9f2626SSebastian Kapfer * next packet or we got garbage. 9551d9f2626SSebastian Kapfer */ 9561d9f2626SSebastian Kapfer 9571d9f2626SSebastian Kapfer if (((psmouse->packet[3] | 9581d9f2626SSebastian Kapfer psmouse->packet[4] | 9591d9f2626SSebastian Kapfer psmouse->packet[5]) & 0x80) || 96099df65e7SKevin Cernekee (!alps_is_valid_first_byte(priv, psmouse->packet[6]))) { 961b5d21704SDmitry Torokhov psmouse_dbg(psmouse, 9623b112923SAndy Shevchenko "refusing packet %4ph (suspected interleaved ps/2)\n", 9633b112923SAndy Shevchenko psmouse->packet + 3); 9641d9f2626SSebastian Kapfer return PSMOUSE_BAD_DATA; 9651d9f2626SSebastian Kapfer } 9661d9f2626SSebastian Kapfer 96724af5cb9SKevin Cernekee priv->process_packet(psmouse); 9681d9f2626SSebastian Kapfer 9691d9f2626SSebastian Kapfer /* Continue with the next packet */ 9701d9f2626SSebastian Kapfer psmouse->packet[0] = psmouse->packet[6]; 9711d9f2626SSebastian Kapfer psmouse->pktcnt = 1; 9721d9f2626SSebastian Kapfer 9731d9f2626SSebastian Kapfer } else { 9741d9f2626SSebastian Kapfer 9751d9f2626SSebastian Kapfer /* 9761d9f2626SSebastian Kapfer * High bit is 0 - that means that we indeed got a PS/2 9771d9f2626SSebastian Kapfer * packet in the middle of ALPS packet. 9781d9f2626SSebastian Kapfer * 9791d9f2626SSebastian Kapfer * There is also possibility that we got 6-byte ALPS 9801d9f2626SSebastian Kapfer * packet followed by 3-byte packet from trackpoint. We 9811d9f2626SSebastian Kapfer * can not distinguish between these 2 scenarios but 982b5d21704SDmitry Torokhov * because the latter is unlikely to happen in course of 9831d9f2626SSebastian Kapfer * normal operation (user would need to press all 9841d9f2626SSebastian Kapfer * buttons on the pad and start moving trackpoint 9851d9f2626SSebastian Kapfer * without touching the pad surface) we assume former. 9861d9f2626SSebastian Kapfer * Even if we are wrong the wost thing that would happen 9871d9f2626SSebastian Kapfer * the cursor would jump but we should not get protocol 988b5d21704SDmitry Torokhov * de-synchronization. 9891d9f2626SSebastian Kapfer */ 9901d9f2626SSebastian Kapfer 9911d9f2626SSebastian Kapfer alps_report_bare_ps2_packet(psmouse, &psmouse->packet[3], 9921d9f2626SSebastian Kapfer false); 9931d9f2626SSebastian Kapfer 9941d9f2626SSebastian Kapfer /* 9951d9f2626SSebastian Kapfer * Continue with the standard ALPS protocol handling, 9961d9f2626SSebastian Kapfer * but make sure we won't process it as an interleaved 9971d9f2626SSebastian Kapfer * packet again, which may happen if all buttons are 9981d9f2626SSebastian Kapfer * pressed. To avoid this let's reset the 4th bit which 9991d9f2626SSebastian Kapfer * is normally 1. 10001d9f2626SSebastian Kapfer */ 10011d9f2626SSebastian Kapfer psmouse->packet[3] = psmouse->packet[6] & 0xf7; 10021d9f2626SSebastian Kapfer psmouse->pktcnt = 4; 10031d9f2626SSebastian Kapfer } 10041d9f2626SSebastian Kapfer 10051d9f2626SSebastian Kapfer return PSMOUSE_GOOD_DATA; 10061d9f2626SSebastian Kapfer } 10071d9f2626SSebastian Kapfer 10081d9f2626SSebastian Kapfer static void alps_flush_packet(unsigned long data) 10091d9f2626SSebastian Kapfer { 10101d9f2626SSebastian Kapfer struct psmouse *psmouse = (struct psmouse *)data; 101124af5cb9SKevin Cernekee struct alps_data *priv = psmouse->private; 10121d9f2626SSebastian Kapfer 10131d9f2626SSebastian Kapfer serio_pause_rx(psmouse->ps2dev.serio); 10141d9f2626SSebastian Kapfer 1015b46615feSSeth Forshee if (psmouse->pktcnt == psmouse->pktsize) { 10161d9f2626SSebastian Kapfer 10171d9f2626SSebastian Kapfer /* 10181d9f2626SSebastian Kapfer * We did not any more data in reasonable amount of time. 10191d9f2626SSebastian Kapfer * Validate the last 3 bytes and process as a standard 10201d9f2626SSebastian Kapfer * ALPS packet. 10211d9f2626SSebastian Kapfer */ 10221d9f2626SSebastian Kapfer if ((psmouse->packet[3] | 10231d9f2626SSebastian Kapfer psmouse->packet[4] | 10241d9f2626SSebastian Kapfer psmouse->packet[5]) & 0x80) { 1025b5d21704SDmitry Torokhov psmouse_dbg(psmouse, 10263b112923SAndy Shevchenko "refusing packet %3ph (suspected interleaved ps/2)\n", 10273b112923SAndy Shevchenko psmouse->packet + 3); 10281d9f2626SSebastian Kapfer } else { 102924af5cb9SKevin Cernekee priv->process_packet(psmouse); 10301d9f2626SSebastian Kapfer } 10311d9f2626SSebastian Kapfer psmouse->pktcnt = 0; 10321d9f2626SSebastian Kapfer } 10331d9f2626SSebastian Kapfer 10341d9f2626SSebastian Kapfer serio_continue_rx(psmouse->ps2dev.serio); 10351d9f2626SSebastian Kapfer } 10361d9f2626SSebastian Kapfer 10371d9f2626SSebastian Kapfer static psmouse_ret_t alps_process_byte(struct psmouse *psmouse) 10381d9f2626SSebastian Kapfer { 10391d9f2626SSebastian Kapfer struct alps_data *priv = psmouse->private; 10401d9f2626SSebastian Kapfer 10411da177e4SLinus Torvalds if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */ 10421da177e4SLinus Torvalds if (psmouse->pktcnt == 3) { 10431d9f2626SSebastian Kapfer alps_report_bare_ps2_packet(psmouse, psmouse->packet, 10441d9f2626SSebastian Kapfer true); 10451da177e4SLinus Torvalds return PSMOUSE_FULL_PACKET; 10461da177e4SLinus Torvalds } 10471da177e4SLinus Torvalds return PSMOUSE_GOOD_DATA; 10481da177e4SLinus Torvalds } 10491da177e4SLinus Torvalds 10501d9f2626SSebastian Kapfer /* Check for PS/2 packet stuffed in the middle of ALPS packet. */ 10511d9f2626SSebastian Kapfer 105299df65e7SKevin Cernekee if ((priv->flags & ALPS_PS2_INTERLEAVED) && 10531d9f2626SSebastian Kapfer psmouse->pktcnt >= 4 && (psmouse->packet[3] & 0x0f) == 0x0f) { 10541d9f2626SSebastian Kapfer return alps_handle_interleaved_ps2(psmouse); 10551d9f2626SSebastian Kapfer } 10561d9f2626SSebastian Kapfer 105799df65e7SKevin Cernekee if (!alps_is_valid_first_byte(priv, psmouse->packet[0])) { 1058b5d21704SDmitry Torokhov psmouse_dbg(psmouse, 1059b5d21704SDmitry Torokhov "refusing packet[0] = %x (mask0 = %x, byte0 = %x)\n", 106099df65e7SKevin Cernekee psmouse->packet[0], priv->mask0, priv->byte0); 10611da177e4SLinus Torvalds return PSMOUSE_BAD_DATA; 10621d9f2626SSebastian Kapfer } 10631da177e4SLinus Torvalds 1064b46615feSSeth Forshee /* Bytes 2 - pktsize should have 0 in the highest bit */ 106595f75e91SYunkang Tang if ((priv->proto_version < ALPS_PROTO_V5) && 106675af9e56SDave Turvene psmouse->pktcnt >= 2 && psmouse->pktcnt <= psmouse->pktsize && 10671d9f2626SSebastian Kapfer (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) { 1068b5d21704SDmitry Torokhov psmouse_dbg(psmouse, "refusing packet[%i] = %x\n", 1069b5d21704SDmitry Torokhov psmouse->pktcnt - 1, 1070b5d21704SDmitry Torokhov psmouse->packet[psmouse->pktcnt - 1]); 10711da177e4SLinus Torvalds return PSMOUSE_BAD_DATA; 10721d9f2626SSebastian Kapfer } 10731da177e4SLinus Torvalds 1074b46615feSSeth Forshee if (psmouse->pktcnt == psmouse->pktsize) { 107524af5cb9SKevin Cernekee priv->process_packet(psmouse); 10761da177e4SLinus Torvalds return PSMOUSE_FULL_PACKET; 10771da177e4SLinus Torvalds } 10781da177e4SLinus Torvalds 10791da177e4SLinus Torvalds return PSMOUSE_GOOD_DATA; 10801da177e4SLinus Torvalds } 10811da177e4SLinus Torvalds 108225bded7cSSeth Forshee static int alps_command_mode_send_nibble(struct psmouse *psmouse, int nibble) 108325bded7cSSeth Forshee { 108425bded7cSSeth Forshee struct ps2dev *ps2dev = &psmouse->ps2dev; 108525bded7cSSeth Forshee struct alps_data *priv = psmouse->private; 108625bded7cSSeth Forshee int command; 108725bded7cSSeth Forshee unsigned char *param; 108825bded7cSSeth Forshee unsigned char dummy[4]; 108925bded7cSSeth Forshee 109025bded7cSSeth Forshee BUG_ON(nibble > 0xf); 109125bded7cSSeth Forshee 109225bded7cSSeth Forshee command = priv->nibble_commands[nibble].command; 109325bded7cSSeth Forshee param = (command & 0x0f00) ? 109425bded7cSSeth Forshee dummy : (unsigned char *)&priv->nibble_commands[nibble].data; 109525bded7cSSeth Forshee 109625bded7cSSeth Forshee if (ps2_command(ps2dev, param, command)) 109725bded7cSSeth Forshee return -1; 109825bded7cSSeth Forshee 109925bded7cSSeth Forshee return 0; 110025bded7cSSeth Forshee } 110125bded7cSSeth Forshee 110225bded7cSSeth Forshee static int alps_command_mode_set_addr(struct psmouse *psmouse, int addr) 110325bded7cSSeth Forshee { 110425bded7cSSeth Forshee struct ps2dev *ps2dev = &psmouse->ps2dev; 110525bded7cSSeth Forshee struct alps_data *priv = psmouse->private; 110625bded7cSSeth Forshee int i, nibble; 110725bded7cSSeth Forshee 110825bded7cSSeth Forshee if (ps2_command(ps2dev, NULL, priv->addr_command)) 110925bded7cSSeth Forshee return -1; 111025bded7cSSeth Forshee 111125bded7cSSeth Forshee for (i = 12; i >= 0; i -= 4) { 111225bded7cSSeth Forshee nibble = (addr >> i) & 0xf; 111325bded7cSSeth Forshee if (alps_command_mode_send_nibble(psmouse, nibble)) 111425bded7cSSeth Forshee return -1; 111525bded7cSSeth Forshee } 111625bded7cSSeth Forshee 111725bded7cSSeth Forshee return 0; 111825bded7cSSeth Forshee } 111925bded7cSSeth Forshee 112025bded7cSSeth Forshee static int __alps_command_mode_read_reg(struct psmouse *psmouse, int addr) 112125bded7cSSeth Forshee { 112225bded7cSSeth Forshee struct ps2dev *ps2dev = &psmouse->ps2dev; 112325bded7cSSeth Forshee unsigned char param[4]; 112425bded7cSSeth Forshee 112525bded7cSSeth Forshee if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) 112625bded7cSSeth Forshee return -1; 112725bded7cSSeth Forshee 112825bded7cSSeth Forshee /* 112925bded7cSSeth Forshee * The address being read is returned in the first two bytes 113025bded7cSSeth Forshee * of the result. Check that this address matches the expected 113125bded7cSSeth Forshee * address. 113225bded7cSSeth Forshee */ 113325bded7cSSeth Forshee if (addr != ((param[0] << 8) | param[1])) 113425bded7cSSeth Forshee return -1; 113525bded7cSSeth Forshee 113625bded7cSSeth Forshee return param[2]; 113725bded7cSSeth Forshee } 113825bded7cSSeth Forshee 113925bded7cSSeth Forshee static int alps_command_mode_read_reg(struct psmouse *psmouse, int addr) 114025bded7cSSeth Forshee { 114125bded7cSSeth Forshee if (alps_command_mode_set_addr(psmouse, addr)) 114225bded7cSSeth Forshee return -1; 114325bded7cSSeth Forshee return __alps_command_mode_read_reg(psmouse, addr); 114425bded7cSSeth Forshee } 114525bded7cSSeth Forshee 114625bded7cSSeth Forshee static int __alps_command_mode_write_reg(struct psmouse *psmouse, u8 value) 114725bded7cSSeth Forshee { 114825bded7cSSeth Forshee if (alps_command_mode_send_nibble(psmouse, (value >> 4) & 0xf)) 114925bded7cSSeth Forshee return -1; 115025bded7cSSeth Forshee if (alps_command_mode_send_nibble(psmouse, value & 0xf)) 115125bded7cSSeth Forshee return -1; 115225bded7cSSeth Forshee return 0; 115325bded7cSSeth Forshee } 115425bded7cSSeth Forshee 115525bded7cSSeth Forshee static int alps_command_mode_write_reg(struct psmouse *psmouse, int addr, 115625bded7cSSeth Forshee u8 value) 115725bded7cSSeth Forshee { 115825bded7cSSeth Forshee if (alps_command_mode_set_addr(psmouse, addr)) 115925bded7cSSeth Forshee return -1; 116025bded7cSSeth Forshee return __alps_command_mode_write_reg(psmouse, value); 116125bded7cSSeth Forshee } 116225bded7cSSeth Forshee 116324ba9707SKevin Cernekee static int alps_rpt_cmd(struct psmouse *psmouse, int init_command, 116424ba9707SKevin Cernekee int repeated_command, unsigned char *param) 116524ba9707SKevin Cernekee { 116624ba9707SKevin Cernekee struct ps2dev *ps2dev = &psmouse->ps2dev; 116724ba9707SKevin Cernekee 116824ba9707SKevin Cernekee param[0] = 0; 116924ba9707SKevin Cernekee if (init_command && ps2_command(ps2dev, param, init_command)) 117024ba9707SKevin Cernekee return -EIO; 117124ba9707SKevin Cernekee 117224ba9707SKevin Cernekee if (ps2_command(ps2dev, NULL, repeated_command) || 117324ba9707SKevin Cernekee ps2_command(ps2dev, NULL, repeated_command) || 117424ba9707SKevin Cernekee ps2_command(ps2dev, NULL, repeated_command)) 117524ba9707SKevin Cernekee return -EIO; 117624ba9707SKevin Cernekee 117724ba9707SKevin Cernekee param[0] = param[1] = param[2] = 0xff; 117824ba9707SKevin Cernekee if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) 117924ba9707SKevin Cernekee return -EIO; 118024ba9707SKevin Cernekee 118139fbe585SDmitry Torokhov psmouse_dbg(psmouse, "%2.2X report: %3ph\n", 118239fbe585SDmitry Torokhov repeated_command, param); 118324ba9707SKevin Cernekee return 0; 118424ba9707SKevin Cernekee } 118524ba9707SKevin Cernekee 1186d18e53fcSKevin Cernekee static int alps_enter_command_mode(struct psmouse *psmouse) 118725bded7cSSeth Forshee { 118825bded7cSSeth Forshee unsigned char param[4]; 118925bded7cSSeth Forshee 119024ba9707SKevin Cernekee if (alps_rpt_cmd(psmouse, 0, PSMOUSE_CMD_RESET_WRAP, param)) { 119125bded7cSSeth Forshee psmouse_err(psmouse, "failed to enter command mode\n"); 119225bded7cSSeth Forshee return -1; 119325bded7cSSeth Forshee } 119425bded7cSSeth Forshee 119575af9e56SDave Turvene if ((param[0] != 0x88 || (param[1] != 0x07 && param[1] != 0x08)) && 119675af9e56SDave Turvene param[0] != 0x73) { 119725bded7cSSeth Forshee psmouse_dbg(psmouse, 119824ba9707SKevin Cernekee "unknown response while entering command mode\n"); 119925bded7cSSeth Forshee return -1; 120025bded7cSSeth Forshee } 120125bded7cSSeth Forshee return 0; 120225bded7cSSeth Forshee } 120325bded7cSSeth Forshee 120425bded7cSSeth Forshee static inline int alps_exit_command_mode(struct psmouse *psmouse) 120525bded7cSSeth Forshee { 120625bded7cSSeth Forshee struct ps2dev *ps2dev = &psmouse->ps2dev; 120725bded7cSSeth Forshee if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM)) 120825bded7cSSeth Forshee return -1; 120925bded7cSSeth Forshee return 0; 121025bded7cSSeth Forshee } 121125bded7cSSeth Forshee 12121da177e4SLinus Torvalds /* 12131da177e4SLinus Torvalds * For DualPoint devices select the device that should respond to 12141da177e4SLinus Torvalds * subsequent commands. It looks like glidepad is behind stickpointer, 12151da177e4SLinus Torvalds * I'd thought it would be other way around... 12161da177e4SLinus Torvalds */ 121725bded7cSSeth Forshee static int alps_passthrough_mode_v2(struct psmouse *psmouse, bool enable) 12181da177e4SLinus Torvalds { 12191da177e4SLinus Torvalds struct ps2dev *ps2dev = &psmouse->ps2dev; 12201da177e4SLinus Torvalds int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11; 12211da177e4SLinus Torvalds 12221da177e4SLinus Torvalds if (ps2_command(ps2dev, NULL, cmd) || 12231da177e4SLinus Torvalds ps2_command(ps2dev, NULL, cmd) || 12241da177e4SLinus Torvalds ps2_command(ps2dev, NULL, cmd) || 12251da177e4SLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE)) 12261da177e4SLinus Torvalds return -1; 12271da177e4SLinus Torvalds 12281da177e4SLinus Torvalds /* we may get 3 more bytes, just ignore them */ 1229c611763dSDmitry Torokhov ps2_drain(ps2dev, 3, 100); 12301da177e4SLinus Torvalds 12311da177e4SLinus Torvalds return 0; 12321da177e4SLinus Torvalds } 12331da177e4SLinus Torvalds 123425bded7cSSeth Forshee static int alps_absolute_mode_v1_v2(struct psmouse *psmouse) 12351da177e4SLinus Torvalds { 12361da177e4SLinus Torvalds struct ps2dev *ps2dev = &psmouse->ps2dev; 12371da177e4SLinus Torvalds 12381da177e4SLinus Torvalds /* Try ALPS magic knock - 4 disable before enable */ 12391da177e4SLinus Torvalds if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || 12401da177e4SLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || 12411da177e4SLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || 12421da177e4SLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || 12431da177e4SLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE)) 12441da177e4SLinus Torvalds return -1; 12451da177e4SLinus Torvalds 12461da177e4SLinus Torvalds /* 12471da177e4SLinus Torvalds * Switch mouse to poll (remote) mode so motion data will not 12481da177e4SLinus Torvalds * get in our way 12491da177e4SLinus Torvalds */ 12501da177e4SLinus Torvalds return ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETPOLL); 12511da177e4SLinus Torvalds } 12521da177e4SLinus Torvalds 125395f75e91SYunkang Tang static int alps_monitor_mode_send_word(struct psmouse *psmouse, u16 word) 125495f75e91SYunkang Tang { 125595f75e91SYunkang Tang int i, nibble; 125695f75e91SYunkang Tang 125795f75e91SYunkang Tang /* 125895f75e91SYunkang Tang * b0-b11 are valid bits, send sequence is inverse. 125995f75e91SYunkang Tang * e.g. when word = 0x0123, nibble send sequence is 3, 2, 1 126095f75e91SYunkang Tang */ 126195f75e91SYunkang Tang for (i = 0; i <= 8; i += 4) { 126295f75e91SYunkang Tang nibble = (word >> i) & 0xf; 126395f75e91SYunkang Tang if (alps_command_mode_send_nibble(psmouse, nibble)) 126495f75e91SYunkang Tang return -1; 126595f75e91SYunkang Tang } 126695f75e91SYunkang Tang 126795f75e91SYunkang Tang return 0; 126895f75e91SYunkang Tang } 126995f75e91SYunkang Tang 127095f75e91SYunkang Tang static int alps_monitor_mode_write_reg(struct psmouse *psmouse, 127195f75e91SYunkang Tang u16 addr, u16 value) 127295f75e91SYunkang Tang { 127395f75e91SYunkang Tang struct ps2dev *ps2dev = &psmouse->ps2dev; 127495f75e91SYunkang Tang 127595f75e91SYunkang Tang /* 0x0A0 is the command to write the word */ 127695f75e91SYunkang Tang if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE) || 127795f75e91SYunkang Tang alps_monitor_mode_send_word(psmouse, 0x0A0) || 127895f75e91SYunkang Tang alps_monitor_mode_send_word(psmouse, addr) || 127995f75e91SYunkang Tang alps_monitor_mode_send_word(psmouse, value) || 128095f75e91SYunkang Tang ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE)) 128195f75e91SYunkang Tang return -1; 128295f75e91SYunkang Tang 128395f75e91SYunkang Tang return 0; 128495f75e91SYunkang Tang } 128595f75e91SYunkang Tang 128695f75e91SYunkang Tang static int alps_monitor_mode(struct psmouse *psmouse, bool enable) 128795f75e91SYunkang Tang { 128895f75e91SYunkang Tang struct ps2dev *ps2dev = &psmouse->ps2dev; 128995f75e91SYunkang Tang 129095f75e91SYunkang Tang if (enable) { 129195f75e91SYunkang Tang /* EC E9 F5 F5 E7 E6 E7 E9 to enter monitor mode */ 129295f75e91SYunkang Tang if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) || 129395f75e91SYunkang Tang ps2_command(ps2dev, NULL, PSMOUSE_CMD_GETINFO) || 129495f75e91SYunkang Tang ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || 129595f75e91SYunkang Tang ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || 129695f75e91SYunkang Tang ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || 129795f75e91SYunkang Tang ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || 129895f75e91SYunkang Tang ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || 129995f75e91SYunkang Tang ps2_command(ps2dev, NULL, PSMOUSE_CMD_GETINFO)) 130095f75e91SYunkang Tang return -1; 130195f75e91SYunkang Tang } else { 130295f75e91SYunkang Tang /* EC to exit monitor mode */ 130395f75e91SYunkang Tang if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP)) 130495f75e91SYunkang Tang return -1; 130595f75e91SYunkang Tang } 130695f75e91SYunkang Tang 130795f75e91SYunkang Tang return 0; 130895f75e91SYunkang Tang } 130995f75e91SYunkang Tang 131095f75e91SYunkang Tang static int alps_absolute_mode_v6(struct psmouse *psmouse) 131195f75e91SYunkang Tang { 131295f75e91SYunkang Tang u16 reg_val = 0x181; 131395f75e91SYunkang Tang int ret = -1; 131495f75e91SYunkang Tang 131595f75e91SYunkang Tang /* enter monitor mode, to write the register */ 131695f75e91SYunkang Tang if (alps_monitor_mode(psmouse, true)) 131795f75e91SYunkang Tang return -1; 131895f75e91SYunkang Tang 131995f75e91SYunkang Tang ret = alps_monitor_mode_write_reg(psmouse, 0x000, reg_val); 132095f75e91SYunkang Tang 132195f75e91SYunkang Tang if (alps_monitor_mode(psmouse, false)) 132295f75e91SYunkang Tang ret = -1; 132395f75e91SYunkang Tang 132495f75e91SYunkang Tang return ret; 132595f75e91SYunkang Tang } 132695f75e91SYunkang Tang 13271da177e4SLinus Torvalds static int alps_get_status(struct psmouse *psmouse, char *param) 13281da177e4SLinus Torvalds { 13291da177e4SLinus Torvalds /* Get status: 0xF5 0xF5 0xF5 0xE9 */ 133024ba9707SKevin Cernekee if (alps_rpt_cmd(psmouse, 0, PSMOUSE_CMD_DISABLE, param)) 13311da177e4SLinus Torvalds return -1; 13321da177e4SLinus Torvalds 13331da177e4SLinus Torvalds return 0; 13341da177e4SLinus Torvalds } 13351da177e4SLinus Torvalds 13361da177e4SLinus Torvalds /* 13371da177e4SLinus Torvalds * Turn touchpad tapping on or off. The sequences are: 13381da177e4SLinus Torvalds * 0xE9 0xF5 0xF5 0xF3 0x0A to enable, 13391da177e4SLinus Torvalds * 0xE9 0xF5 0xF5 0xE8 0x00 to disable. 13401da177e4SLinus Torvalds * My guess that 0xE9 (GetInfo) is here as a sync point. 13411da177e4SLinus Torvalds * For models that also have stickpointer (DualPoints) its tapping 13421da177e4SLinus Torvalds * is controlled separately (0xE6 0xE6 0xE6 0xF3 0x14|0x0A) but 13431da177e4SLinus Torvalds * we don't fiddle with it. 13441da177e4SLinus Torvalds */ 13451da177e4SLinus Torvalds static int alps_tap_mode(struct psmouse *psmouse, int enable) 13461da177e4SLinus Torvalds { 13471da177e4SLinus Torvalds struct ps2dev *ps2dev = &psmouse->ps2dev; 13481da177e4SLinus Torvalds int cmd = enable ? PSMOUSE_CMD_SETRATE : PSMOUSE_CMD_SETRES; 13491da177e4SLinus Torvalds unsigned char tap_arg = enable ? 0x0A : 0x00; 13501da177e4SLinus Torvalds unsigned char param[4]; 13511da177e4SLinus Torvalds 13521da177e4SLinus Torvalds if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO) || 13531da177e4SLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || 13541da177e4SLinus Torvalds ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || 13551da177e4SLinus Torvalds ps2_command(ps2dev, &tap_arg, cmd)) 13561da177e4SLinus Torvalds return -1; 13571da177e4SLinus Torvalds 13581da177e4SLinus Torvalds if (alps_get_status(psmouse, param)) 13591da177e4SLinus Torvalds return -1; 13601da177e4SLinus Torvalds 13611da177e4SLinus Torvalds return 0; 13621da177e4SLinus Torvalds } 13631da177e4SLinus Torvalds 1364f0d5c6f4SDmitry Torokhov /* 1365f0d5c6f4SDmitry Torokhov * alps_poll() - poll the touchpad for current motion packet. 1366f0d5c6f4SDmitry Torokhov * Used in resync. 1367f0d5c6f4SDmitry Torokhov */ 1368f0d5c6f4SDmitry Torokhov static int alps_poll(struct psmouse *psmouse) 1369f0d5c6f4SDmitry Torokhov { 1370f0d5c6f4SDmitry Torokhov struct alps_data *priv = psmouse->private; 1371b46615feSSeth Forshee unsigned char buf[sizeof(psmouse->packet)]; 1372b7802c5cSDmitry Torokhov bool poll_failed; 1373f0d5c6f4SDmitry Torokhov 137499df65e7SKevin Cernekee if (priv->flags & ALPS_PASS) 137525bded7cSSeth Forshee alps_passthrough_mode_v2(psmouse, true); 1376f0d5c6f4SDmitry Torokhov 1377f0d5c6f4SDmitry Torokhov poll_failed = ps2_command(&psmouse->ps2dev, buf, 1378f0d5c6f4SDmitry Torokhov PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)) < 0; 1379f0d5c6f4SDmitry Torokhov 138099df65e7SKevin Cernekee if (priv->flags & ALPS_PASS) 138125bded7cSSeth Forshee alps_passthrough_mode_v2(psmouse, false); 1382f0d5c6f4SDmitry Torokhov 138399df65e7SKevin Cernekee if (poll_failed || (buf[0] & priv->mask0) != priv->byte0) 1384f0d5c6f4SDmitry Torokhov return -1; 1385f0d5c6f4SDmitry Torokhov 1386f0d5c6f4SDmitry Torokhov if ((psmouse->badbyte & 0xc8) == 0x08) { 1387f0d5c6f4SDmitry Torokhov /* 1388f0d5c6f4SDmitry Torokhov * Poll the track stick ... 1389f0d5c6f4SDmitry Torokhov */ 1390f0d5c6f4SDmitry Torokhov if (ps2_command(&psmouse->ps2dev, buf, PSMOUSE_CMD_POLL | (3 << 8))) 1391f0d5c6f4SDmitry Torokhov return -1; 1392f0d5c6f4SDmitry Torokhov } 1393f0d5c6f4SDmitry Torokhov 1394f0d5c6f4SDmitry Torokhov memcpy(psmouse->packet, buf, sizeof(buf)); 1395f0d5c6f4SDmitry Torokhov return 0; 1396f0d5c6f4SDmitry Torokhov } 1397f0d5c6f4SDmitry Torokhov 139825bded7cSSeth Forshee static int alps_hw_init_v1_v2(struct psmouse *psmouse) 13991da177e4SLinus Torvalds { 14001da177e4SLinus Torvalds struct alps_data *priv = psmouse->private; 14011da177e4SLinus Torvalds 140299df65e7SKevin Cernekee if ((priv->flags & ALPS_PASS) && 140325bded7cSSeth Forshee alps_passthrough_mode_v2(psmouse, true)) { 14041da177e4SLinus Torvalds return -1; 1405b7802c5cSDmitry Torokhov } 14061da177e4SLinus Torvalds 1407b7802c5cSDmitry Torokhov if (alps_tap_mode(psmouse, true)) { 1408b5d21704SDmitry Torokhov psmouse_warn(psmouse, "Failed to enable hardware tapping\n"); 14091da177e4SLinus Torvalds return -1; 1410963f626dSPeter Osterlund } 14111da177e4SLinus Torvalds 141225bded7cSSeth Forshee if (alps_absolute_mode_v1_v2(psmouse)) { 1413b5d21704SDmitry Torokhov psmouse_err(psmouse, "Failed to enable absolute mode\n"); 14141da177e4SLinus Torvalds return -1; 14151da177e4SLinus Torvalds } 14161da177e4SLinus Torvalds 141799df65e7SKevin Cernekee if ((priv->flags & ALPS_PASS) && 141825bded7cSSeth Forshee alps_passthrough_mode_v2(psmouse, false)) { 14191da177e4SLinus Torvalds return -1; 1420b7802c5cSDmitry Torokhov } 14211da177e4SLinus Torvalds 14221e0c5b12SDmitry Torokhov /* ALPS needs stream mode, otherwise it won't report any data */ 14231e0c5b12SDmitry Torokhov if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSTREAM)) { 1424b5d21704SDmitry Torokhov psmouse_err(psmouse, "Failed to enable stream mode\n"); 14251e0c5b12SDmitry Torokhov return -1; 14261e0c5b12SDmitry Torokhov } 14271e0c5b12SDmitry Torokhov 14281e0c5b12SDmitry Torokhov return 0; 14291e0c5b12SDmitry Torokhov } 14301e0c5b12SDmitry Torokhov 143195f75e91SYunkang Tang static int alps_hw_init_v6(struct psmouse *psmouse) 143295f75e91SYunkang Tang { 143395f75e91SYunkang Tang unsigned char param[2] = {0xC8, 0x14}; 143495f75e91SYunkang Tang 143595f75e91SYunkang Tang /* Enter passthrough mode to let trackpoint enter 6byte raw mode */ 143695f75e91SYunkang Tang if (alps_passthrough_mode_v2(psmouse, true)) 143795f75e91SYunkang Tang return -1; 143895f75e91SYunkang Tang 143995f75e91SYunkang Tang if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || 144095f75e91SYunkang Tang ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || 144195f75e91SYunkang Tang ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || 144295f75e91SYunkang Tang ps2_command(&psmouse->ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) || 144395f75e91SYunkang Tang ps2_command(&psmouse->ps2dev, ¶m[1], PSMOUSE_CMD_SETRATE)) 144495f75e91SYunkang Tang return -1; 144595f75e91SYunkang Tang 144695f75e91SYunkang Tang if (alps_passthrough_mode_v2(psmouse, false)) 144795f75e91SYunkang Tang return -1; 144895f75e91SYunkang Tang 144995f75e91SYunkang Tang if (alps_absolute_mode_v6(psmouse)) { 145095f75e91SYunkang Tang psmouse_err(psmouse, "Failed to enable absolute mode\n"); 145195f75e91SYunkang Tang return -1; 145295f75e91SYunkang Tang } 145395f75e91SYunkang Tang 145495f75e91SYunkang Tang return 0; 145595f75e91SYunkang Tang } 145695f75e91SYunkang Tang 145725bded7cSSeth Forshee /* 1458cd401204SKevin Cernekee * Enable or disable passthrough mode to the trackstick. 145925bded7cSSeth Forshee */ 1460cd401204SKevin Cernekee static int alps_passthrough_mode_v3(struct psmouse *psmouse, 1461cd401204SKevin Cernekee int reg_base, bool enable) 146225bded7cSSeth Forshee { 1463cd401204SKevin Cernekee int reg_val, ret = -1; 146425bded7cSSeth Forshee 1465d18e53fcSKevin Cernekee if (alps_enter_command_mode(psmouse)) 146625bded7cSSeth Forshee return -1; 146725bded7cSSeth Forshee 1468cd401204SKevin Cernekee reg_val = alps_command_mode_read_reg(psmouse, reg_base + 0x0008); 1469cd401204SKevin Cernekee if (reg_val == -1) 1470cd401204SKevin Cernekee goto error; 1471cd401204SKevin Cernekee 147225bded7cSSeth Forshee if (enable) 147325bded7cSSeth Forshee reg_val |= 0x01; 147425bded7cSSeth Forshee else 147525bded7cSSeth Forshee reg_val &= ~0x01; 147625bded7cSSeth Forshee 1477cd401204SKevin Cernekee ret = __alps_command_mode_write_reg(psmouse, reg_val); 147825bded7cSSeth Forshee 1479cd401204SKevin Cernekee error: 1480cd401204SKevin Cernekee if (alps_exit_command_mode(psmouse)) 1481cd401204SKevin Cernekee ret = -1; 1482cd401204SKevin Cernekee return ret; 148325bded7cSSeth Forshee } 148425bded7cSSeth Forshee 148525bded7cSSeth Forshee /* Must be in command mode when calling this function */ 148625bded7cSSeth Forshee static int alps_absolute_mode_v3(struct psmouse *psmouse) 148725bded7cSSeth Forshee { 148825bded7cSSeth Forshee int reg_val; 148925bded7cSSeth Forshee 149025bded7cSSeth Forshee reg_val = alps_command_mode_read_reg(psmouse, 0x0004); 149125bded7cSSeth Forshee if (reg_val == -1) 149225bded7cSSeth Forshee return -1; 149325bded7cSSeth Forshee 149425bded7cSSeth Forshee reg_val |= 0x06; 149525bded7cSSeth Forshee if (__alps_command_mode_write_reg(psmouse, reg_val)) 149625bded7cSSeth Forshee return -1; 149725bded7cSSeth Forshee 149825bded7cSSeth Forshee return 0; 149925bded7cSSeth Forshee } 150025bded7cSSeth Forshee 1501cd401204SKevin Cernekee static int alps_probe_trackstick_v3(struct psmouse *psmouse, int reg_base) 150225bded7cSSeth Forshee { 1503cd401204SKevin Cernekee int ret = -EIO, reg_val; 150425bded7cSSeth Forshee 1505d18e53fcSKevin Cernekee if (alps_enter_command_mode(psmouse)) 150625bded7cSSeth Forshee goto error; 150725bded7cSSeth Forshee 1508cd401204SKevin Cernekee reg_val = alps_command_mode_read_reg(psmouse, reg_base + 0x08); 150925bded7cSSeth Forshee if (reg_val == -1) 151025bded7cSSeth Forshee goto error; 1511cd401204SKevin Cernekee 1512cd401204SKevin Cernekee /* bit 7: trackstick is present */ 1513cd401204SKevin Cernekee ret = reg_val & 0x80 ? 0 : -ENODEV; 1514cd401204SKevin Cernekee 1515cd401204SKevin Cernekee error: 1516cd401204SKevin Cernekee alps_exit_command_mode(psmouse); 1517cd401204SKevin Cernekee return ret; 1518cd401204SKevin Cernekee } 1519cd401204SKevin Cernekee 1520cd401204SKevin Cernekee static int alps_setup_trackstick_v3(struct psmouse *psmouse, int reg_base) 1521cd401204SKevin Cernekee { 1522cd401204SKevin Cernekee struct ps2dev *ps2dev = &psmouse->ps2dev; 1523cd401204SKevin Cernekee int ret = 0; 1524cd401204SKevin Cernekee unsigned char param[4]; 1525cd401204SKevin Cernekee 1526cd401204SKevin Cernekee if (alps_passthrough_mode_v3(psmouse, reg_base, true)) 1527cd401204SKevin Cernekee return -EIO; 152825bded7cSSeth Forshee 152925bded7cSSeth Forshee /* 153025bded7cSSeth Forshee * E7 report for the trackstick 153125bded7cSSeth Forshee * 153225bded7cSSeth Forshee * There have been reports of failures to seem to trace back 153325bded7cSSeth Forshee * to the above trackstick check failing. When these occur 153425bded7cSSeth Forshee * this E7 report fails, so when that happens we continue 153525bded7cSSeth Forshee * with the assumption that there isn't a trackstick after 153625bded7cSSeth Forshee * all. 153725bded7cSSeth Forshee */ 1538cd401204SKevin Cernekee if (alps_rpt_cmd(psmouse, 0, PSMOUSE_CMD_SETSCALE21, param)) { 153925bded7cSSeth Forshee psmouse_warn(psmouse, "trackstick E7 report failed\n"); 1540cd401204SKevin Cernekee ret = -ENODEV; 154125bded7cSSeth Forshee } else { 154239fbe585SDmitry Torokhov psmouse_dbg(psmouse, "trackstick E7 report: %3ph\n", param); 154325bded7cSSeth Forshee 154425bded7cSSeth Forshee /* 154525bded7cSSeth Forshee * Not sure what this does, but it is absolutely 154625bded7cSSeth Forshee * essential. Without it, the touchpad does not 154725bded7cSSeth Forshee * work at all and the trackstick just emits normal 154825bded7cSSeth Forshee * PS/2 packets. 154925bded7cSSeth Forshee */ 155025bded7cSSeth Forshee if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || 155125bded7cSSeth Forshee ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || 155225bded7cSSeth Forshee ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || 155325bded7cSSeth Forshee alps_command_mode_send_nibble(psmouse, 0x9) || 155425bded7cSSeth Forshee alps_command_mode_send_nibble(psmouse, 0x4)) { 155525bded7cSSeth Forshee psmouse_err(psmouse, 155625bded7cSSeth Forshee "Error sending magic E6 sequence\n"); 1557cd401204SKevin Cernekee ret = -EIO; 155825bded7cSSeth Forshee goto error; 155925bded7cSSeth Forshee } 156025bded7cSSeth Forshee 1561cd401204SKevin Cernekee /* 1562cd401204SKevin Cernekee * This ensures the trackstick packets are in the format 1563cd401204SKevin Cernekee * supported by this driver. If bit 1 isn't set the packet 1564cd401204SKevin Cernekee * format is different. 1565cd401204SKevin Cernekee */ 1566d18e53fcSKevin Cernekee if (alps_enter_command_mode(psmouse) || 1567cd401204SKevin Cernekee alps_command_mode_write_reg(psmouse, 1568cd401204SKevin Cernekee reg_base + 0x08, 0x82) || 1569cd401204SKevin Cernekee alps_exit_command_mode(psmouse)) 1570cd401204SKevin Cernekee ret = -EIO; 1571cd401204SKevin Cernekee } 1572cd401204SKevin Cernekee 1573cd401204SKevin Cernekee error: 1574cd401204SKevin Cernekee if (alps_passthrough_mode_v3(psmouse, reg_base, false)) 1575cd401204SKevin Cernekee ret = -EIO; 1576cd401204SKevin Cernekee 1577cd401204SKevin Cernekee return ret; 1578cd401204SKevin Cernekee } 1579cd401204SKevin Cernekee 1580cd401204SKevin Cernekee static int alps_hw_init_v3(struct psmouse *psmouse) 1581cd401204SKevin Cernekee { 1582cd401204SKevin Cernekee struct ps2dev *ps2dev = &psmouse->ps2dev; 1583cd401204SKevin Cernekee int reg_val; 1584cd401204SKevin Cernekee unsigned char param[4]; 1585cd401204SKevin Cernekee 1586cd401204SKevin Cernekee reg_val = alps_probe_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE); 1587cd401204SKevin Cernekee if (reg_val == -EIO) 1588cd401204SKevin Cernekee goto error; 158939fbe585SDmitry Torokhov 1590cd401204SKevin Cernekee if (reg_val == 0 && 1591cd401204SKevin Cernekee alps_setup_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE) == -EIO) 1592cd401204SKevin Cernekee goto error; 1593cd401204SKevin Cernekee 1594d18e53fcSKevin Cernekee if (alps_enter_command_mode(psmouse) || 1595cd401204SKevin Cernekee alps_absolute_mode_v3(psmouse)) { 159625bded7cSSeth Forshee psmouse_err(psmouse, "Failed to enter absolute mode\n"); 159725bded7cSSeth Forshee goto error; 159825bded7cSSeth Forshee } 159925bded7cSSeth Forshee 160025bded7cSSeth Forshee reg_val = alps_command_mode_read_reg(psmouse, 0x0006); 160125bded7cSSeth Forshee if (reg_val == -1) 160225bded7cSSeth Forshee goto error; 160325bded7cSSeth Forshee if (__alps_command_mode_write_reg(psmouse, reg_val | 0x01)) 160425bded7cSSeth Forshee goto error; 160525bded7cSSeth Forshee 160625bded7cSSeth Forshee reg_val = alps_command_mode_read_reg(psmouse, 0x0007); 160725bded7cSSeth Forshee if (reg_val == -1) 160825bded7cSSeth Forshee goto error; 160925bded7cSSeth Forshee if (__alps_command_mode_write_reg(psmouse, reg_val | 0x01)) 161025bded7cSSeth Forshee goto error; 161125bded7cSSeth Forshee 161225bded7cSSeth Forshee if (alps_command_mode_read_reg(psmouse, 0x0144) == -1) 161325bded7cSSeth Forshee goto error; 161425bded7cSSeth Forshee if (__alps_command_mode_write_reg(psmouse, 0x04)) 161525bded7cSSeth Forshee goto error; 161625bded7cSSeth Forshee 161725bded7cSSeth Forshee if (alps_command_mode_read_reg(psmouse, 0x0159) == -1) 161825bded7cSSeth Forshee goto error; 161925bded7cSSeth Forshee if (__alps_command_mode_write_reg(psmouse, 0x03)) 162025bded7cSSeth Forshee goto error; 162125bded7cSSeth Forshee 162225bded7cSSeth Forshee if (alps_command_mode_read_reg(psmouse, 0x0163) == -1) 162325bded7cSSeth Forshee goto error; 162425bded7cSSeth Forshee if (alps_command_mode_write_reg(psmouse, 0x0163, 0x03)) 162525bded7cSSeth Forshee goto error; 162625bded7cSSeth Forshee 162725bded7cSSeth Forshee if (alps_command_mode_read_reg(psmouse, 0x0162) == -1) 162825bded7cSSeth Forshee goto error; 162925bded7cSSeth Forshee if (alps_command_mode_write_reg(psmouse, 0x0162, 0x04)) 163025bded7cSSeth Forshee goto error; 163125bded7cSSeth Forshee 163225bded7cSSeth Forshee alps_exit_command_mode(psmouse); 163325bded7cSSeth Forshee 163425bded7cSSeth Forshee /* Set rate and enable data reporting */ 163525bded7cSSeth Forshee param[0] = 0x64; 163625bded7cSSeth Forshee if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE) || 163725bded7cSSeth Forshee ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE)) { 163825bded7cSSeth Forshee psmouse_err(psmouse, "Failed to enable data reporting\n"); 163925bded7cSSeth Forshee return -1; 164025bded7cSSeth Forshee } 164125bded7cSSeth Forshee 164225bded7cSSeth Forshee return 0; 164325bded7cSSeth Forshee 164425bded7cSSeth Forshee error: 164525bded7cSSeth Forshee /* 164625bded7cSSeth Forshee * Leaving the touchpad in command mode will essentially render 164725bded7cSSeth Forshee * it unusable until the machine reboots, so exit it here just 164825bded7cSSeth Forshee * to be safe 164925bded7cSSeth Forshee */ 165025bded7cSSeth Forshee alps_exit_command_mode(psmouse); 165125bded7cSSeth Forshee return -1; 165225bded7cSSeth Forshee } 165325bded7cSSeth Forshee 16541302bac3SKevin Cernekee static int alps_hw_init_rushmore_v3(struct psmouse *psmouse) 16551302bac3SKevin Cernekee { 1656cd401204SKevin Cernekee struct alps_data *priv = psmouse->private; 16571302bac3SKevin Cernekee struct ps2dev *ps2dev = &psmouse->ps2dev; 16581302bac3SKevin Cernekee int reg_val, ret = -1; 16591302bac3SKevin Cernekee 1660cd401204SKevin Cernekee if (priv->flags & ALPS_DUALPOINT) { 1661cd401204SKevin Cernekee reg_val = alps_setup_trackstick_v3(psmouse, 1662cd401204SKevin Cernekee ALPS_REG_BASE_RUSHMORE); 1663cd401204SKevin Cernekee if (reg_val == -EIO) 1664cd401204SKevin Cernekee goto error; 1665cd401204SKevin Cernekee if (reg_val == -ENODEV) 1666cd401204SKevin Cernekee priv->flags &= ~ALPS_DUALPOINT; 1667cd401204SKevin Cernekee } 1668cd401204SKevin Cernekee 1669d18e53fcSKevin Cernekee if (alps_enter_command_mode(psmouse) || 16701302bac3SKevin Cernekee alps_command_mode_read_reg(psmouse, 0xc2d9) == -1 || 16711302bac3SKevin Cernekee alps_command_mode_write_reg(psmouse, 0xc2cb, 0x00)) 16721302bac3SKevin Cernekee goto error; 16731302bac3SKevin Cernekee 16741302bac3SKevin Cernekee reg_val = alps_command_mode_read_reg(psmouse, 0xc2c6); 16751302bac3SKevin Cernekee if (reg_val == -1) 16761302bac3SKevin Cernekee goto error; 16771302bac3SKevin Cernekee if (__alps_command_mode_write_reg(psmouse, reg_val & 0xfd)) 16781302bac3SKevin Cernekee goto error; 16791302bac3SKevin Cernekee 16801302bac3SKevin Cernekee if (alps_command_mode_write_reg(psmouse, 0xc2c9, 0x64)) 16811302bac3SKevin Cernekee goto error; 16821302bac3SKevin Cernekee 16831302bac3SKevin Cernekee /* enter absolute mode */ 16841302bac3SKevin Cernekee reg_val = alps_command_mode_read_reg(psmouse, 0xc2c4); 16851302bac3SKevin Cernekee if (reg_val == -1) 16861302bac3SKevin Cernekee goto error; 16871302bac3SKevin Cernekee if (__alps_command_mode_write_reg(psmouse, reg_val | 0x02)) 16881302bac3SKevin Cernekee goto error; 16891302bac3SKevin Cernekee 16901302bac3SKevin Cernekee alps_exit_command_mode(psmouse); 16911302bac3SKevin Cernekee return ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE); 16921302bac3SKevin Cernekee 16931302bac3SKevin Cernekee error: 16941302bac3SKevin Cernekee alps_exit_command_mode(psmouse); 16951302bac3SKevin Cernekee return ret; 16961302bac3SKevin Cernekee } 16971302bac3SKevin Cernekee 169825bded7cSSeth Forshee /* Must be in command mode when calling this function */ 169925bded7cSSeth Forshee static int alps_absolute_mode_v4(struct psmouse *psmouse) 170025bded7cSSeth Forshee { 170125bded7cSSeth Forshee int reg_val; 170225bded7cSSeth Forshee 170325bded7cSSeth Forshee reg_val = alps_command_mode_read_reg(psmouse, 0x0004); 170425bded7cSSeth Forshee if (reg_val == -1) 170525bded7cSSeth Forshee return -1; 170625bded7cSSeth Forshee 170725bded7cSSeth Forshee reg_val |= 0x02; 170825bded7cSSeth Forshee if (__alps_command_mode_write_reg(psmouse, reg_val)) 170925bded7cSSeth Forshee return -1; 171025bded7cSSeth Forshee 171125bded7cSSeth Forshee return 0; 171225bded7cSSeth Forshee } 171325bded7cSSeth Forshee 171425bded7cSSeth Forshee static int alps_hw_init_v4(struct psmouse *psmouse) 171525bded7cSSeth Forshee { 171625bded7cSSeth Forshee struct ps2dev *ps2dev = &psmouse->ps2dev; 171725bded7cSSeth Forshee unsigned char param[4]; 171825bded7cSSeth Forshee 1719d18e53fcSKevin Cernekee if (alps_enter_command_mode(psmouse)) 172025bded7cSSeth Forshee goto error; 172125bded7cSSeth Forshee 172225bded7cSSeth Forshee if (alps_absolute_mode_v4(psmouse)) { 172325bded7cSSeth Forshee psmouse_err(psmouse, "Failed to enter absolute mode\n"); 172425bded7cSSeth Forshee goto error; 172525bded7cSSeth Forshee } 172625bded7cSSeth Forshee 172725bded7cSSeth Forshee if (alps_command_mode_write_reg(psmouse, 0x0007, 0x8c)) 172825bded7cSSeth Forshee goto error; 172925bded7cSSeth Forshee 173025bded7cSSeth Forshee if (alps_command_mode_write_reg(psmouse, 0x0149, 0x03)) 173125bded7cSSeth Forshee goto error; 173225bded7cSSeth Forshee 173325bded7cSSeth Forshee if (alps_command_mode_write_reg(psmouse, 0x0160, 0x03)) 173425bded7cSSeth Forshee goto error; 173525bded7cSSeth Forshee 173625bded7cSSeth Forshee if (alps_command_mode_write_reg(psmouse, 0x017f, 0x15)) 173725bded7cSSeth Forshee goto error; 173825bded7cSSeth Forshee 173925bded7cSSeth Forshee if (alps_command_mode_write_reg(psmouse, 0x0151, 0x01)) 174025bded7cSSeth Forshee goto error; 174125bded7cSSeth Forshee 174225bded7cSSeth Forshee if (alps_command_mode_write_reg(psmouse, 0x0168, 0x03)) 174325bded7cSSeth Forshee goto error; 174425bded7cSSeth Forshee 174525bded7cSSeth Forshee if (alps_command_mode_write_reg(psmouse, 0x014a, 0x03)) 174625bded7cSSeth Forshee goto error; 174725bded7cSSeth Forshee 174825bded7cSSeth Forshee if (alps_command_mode_write_reg(psmouse, 0x0161, 0x03)) 174925bded7cSSeth Forshee goto error; 175025bded7cSSeth Forshee 175125bded7cSSeth Forshee alps_exit_command_mode(psmouse); 175225bded7cSSeth Forshee 175325bded7cSSeth Forshee /* 175425bded7cSSeth Forshee * This sequence changes the output from a 9-byte to an 175525bded7cSSeth Forshee * 8-byte format. All the same data seems to be present, 175625bded7cSSeth Forshee * just in a more compact format. 175725bded7cSSeth Forshee */ 175825bded7cSSeth Forshee param[0] = 0xc8; 175925bded7cSSeth Forshee param[1] = 0x64; 176025bded7cSSeth Forshee param[2] = 0x50; 176125bded7cSSeth Forshee if (ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) || 176225bded7cSSeth Forshee ps2_command(ps2dev, ¶m[1], PSMOUSE_CMD_SETRATE) || 176325bded7cSSeth Forshee ps2_command(ps2dev, ¶m[2], PSMOUSE_CMD_SETRATE) || 176425bded7cSSeth Forshee ps2_command(ps2dev, param, PSMOUSE_CMD_GETID)) 176525bded7cSSeth Forshee return -1; 176625bded7cSSeth Forshee 176725bded7cSSeth Forshee /* Set rate and enable data reporting */ 176825bded7cSSeth Forshee param[0] = 0x64; 176925bded7cSSeth Forshee if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE) || 177025bded7cSSeth Forshee ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE)) { 177125bded7cSSeth Forshee psmouse_err(psmouse, "Failed to enable data reporting\n"); 177225bded7cSSeth Forshee return -1; 177325bded7cSSeth Forshee } 177425bded7cSSeth Forshee 177525bded7cSSeth Forshee return 0; 177625bded7cSSeth Forshee 177725bded7cSSeth Forshee error: 177825bded7cSSeth Forshee /* 177925bded7cSSeth Forshee * Leaving the touchpad in command mode will essentially render 178025bded7cSSeth Forshee * it unusable until the machine reboots, so exit it here just 178125bded7cSSeth Forshee * to be safe 178225bded7cSSeth Forshee */ 178325bded7cSSeth Forshee alps_exit_command_mode(psmouse); 178425bded7cSSeth Forshee return -1; 178525bded7cSSeth Forshee } 178625bded7cSSeth Forshee 1787ee65d4b3SYunkang Tang static int alps_dolphin_get_device_area(struct psmouse *psmouse, 1788ee65d4b3SYunkang Tang struct alps_data *priv) 1789ee65d4b3SYunkang Tang { 1790ee65d4b3SYunkang Tang struct ps2dev *ps2dev = &psmouse->ps2dev; 1791ee65d4b3SYunkang Tang unsigned char param[4] = {0}; 1792ee65d4b3SYunkang Tang int num_x_electrode, num_y_electrode; 1793ee65d4b3SYunkang Tang 1794ee65d4b3SYunkang Tang if (alps_enter_command_mode(psmouse)) 1795ee65d4b3SYunkang Tang return -1; 1796ee65d4b3SYunkang Tang 1797ee65d4b3SYunkang Tang param[0] = 0x0a; 1798ee65d4b3SYunkang Tang if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) || 1799ee65d4b3SYunkang Tang ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) || 1800ee65d4b3SYunkang Tang ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) || 1801ee65d4b3SYunkang Tang ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) || 1802ee65d4b3SYunkang Tang ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE)) 1803ee65d4b3SYunkang Tang return -1; 1804ee65d4b3SYunkang Tang 1805ee65d4b3SYunkang Tang if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) 1806ee65d4b3SYunkang Tang return -1; 1807ee65d4b3SYunkang Tang 1808ee65d4b3SYunkang Tang /* 1809ee65d4b3SYunkang Tang * Dolphin's sensor line number is not fixed. It can be calculated 1810ee65d4b3SYunkang Tang * by adding the device's register value with DOLPHIN_PROFILE_X/YOFFSET. 1811ee65d4b3SYunkang Tang * Further more, we can get device's x_max and y_max by multiplying 1812ee65d4b3SYunkang Tang * sensor line number with DOLPHIN_COUNT_PER_ELECTRODE. 1813ee65d4b3SYunkang Tang * 1814ee65d4b3SYunkang Tang * e.g. When we get register's sensor_x = 11 & sensor_y = 8, 1815ee65d4b3SYunkang Tang * real sensor line number X = 11 + 8 = 19, and 1816ee65d4b3SYunkang Tang * real sensor line number Y = 8 + 1 = 9. 1817ee65d4b3SYunkang Tang * So, x_max = (19 - 1) * 64 = 1152, and 1818ee65d4b3SYunkang Tang * y_max = (9 - 1) * 64 = 512. 1819ee65d4b3SYunkang Tang */ 1820ee65d4b3SYunkang Tang num_x_electrode = DOLPHIN_PROFILE_XOFFSET + (param[2] & 0x0F); 1821ee65d4b3SYunkang Tang num_y_electrode = DOLPHIN_PROFILE_YOFFSET + ((param[2] >> 4) & 0x0F); 1822ee65d4b3SYunkang Tang priv->x_bits = num_x_electrode; 1823ee65d4b3SYunkang Tang priv->y_bits = num_y_electrode; 1824ee65d4b3SYunkang Tang priv->x_max = (num_x_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE; 1825ee65d4b3SYunkang Tang priv->y_max = (num_y_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE; 1826ee65d4b3SYunkang Tang 1827ee65d4b3SYunkang Tang if (alps_exit_command_mode(psmouse)) 1828ee65d4b3SYunkang Tang return -1; 1829ee65d4b3SYunkang Tang 1830ee65d4b3SYunkang Tang return 0; 1831ee65d4b3SYunkang Tang } 1832ee65d4b3SYunkang Tang 183375af9e56SDave Turvene static int alps_hw_init_dolphin_v1(struct psmouse *psmouse) 183475af9e56SDave Turvene { 183575af9e56SDave Turvene struct ps2dev *ps2dev = &psmouse->ps2dev; 183675af9e56SDave Turvene unsigned char param[2]; 183775af9e56SDave Turvene 183875af9e56SDave Turvene /* This is dolphin "v1" as empirically defined by florin9doi */ 183975af9e56SDave Turvene param[0] = 0x64; 184075af9e56SDave Turvene param[1] = 0x28; 184175af9e56SDave Turvene 184275af9e56SDave Turvene if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) || 184375af9e56SDave Turvene ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) || 184475af9e56SDave Turvene ps2_command(ps2dev, ¶m[1], PSMOUSE_CMD_SETRATE)) 184575af9e56SDave Turvene return -1; 184675af9e56SDave Turvene 184775af9e56SDave Turvene return 0; 184875af9e56SDave Turvene } 184975af9e56SDave Turvene 185024af5cb9SKevin Cernekee static void alps_set_defaults(struct alps_data *priv) 185125bded7cSSeth Forshee { 1852f673ceb1SKevin Cernekee priv->byte0 = 0x8f; 1853f673ceb1SKevin Cernekee priv->mask0 = 0x8f; 1854f673ceb1SKevin Cernekee priv->flags = ALPS_DUALPOINT; 1855f673ceb1SKevin Cernekee 18567a9f73e7SKevin Cernekee priv->x_max = 2000; 18577a9f73e7SKevin Cernekee priv->y_max = 1400; 18587a9f73e7SKevin Cernekee priv->x_bits = 15; 18597a9f73e7SKevin Cernekee priv->y_bits = 11; 18607a9f73e7SKevin Cernekee 186199df65e7SKevin Cernekee switch (priv->proto_version) { 186225bded7cSSeth Forshee case ALPS_PROTO_V1: 186325bded7cSSeth Forshee case ALPS_PROTO_V2: 186424af5cb9SKevin Cernekee priv->hw_init = alps_hw_init_v1_v2; 186524af5cb9SKevin Cernekee priv->process_packet = alps_process_packet_v1_v2; 186624af5cb9SKevin Cernekee priv->set_abs_params = alps_set_abs_params_st; 186795f75e91SYunkang Tang priv->x_max = 1023; 186895f75e91SYunkang Tang priv->y_max = 767; 186925bded7cSSeth Forshee break; 187025bded7cSSeth Forshee case ALPS_PROTO_V3: 187124af5cb9SKevin Cernekee priv->hw_init = alps_hw_init_v3; 187224af5cb9SKevin Cernekee priv->process_packet = alps_process_packet_v3; 187324af5cb9SKevin Cernekee priv->set_abs_params = alps_set_abs_params_mt; 1874f85e5001SKevin Cernekee priv->decode_fields = alps_decode_pinnacle; 187550e8b216SKevin Cernekee priv->nibble_commands = alps_v3_nibble_commands; 187650e8b216SKevin Cernekee priv->addr_command = PSMOUSE_CMD_RESET_WRAP; 187725bded7cSSeth Forshee break; 187825bded7cSSeth Forshee case ALPS_PROTO_V4: 187924af5cb9SKevin Cernekee priv->hw_init = alps_hw_init_v4; 188024af5cb9SKevin Cernekee priv->process_packet = alps_process_packet_v4; 188124af5cb9SKevin Cernekee priv->set_abs_params = alps_set_abs_params_mt; 188250e8b216SKevin Cernekee priv->nibble_commands = alps_v4_nibble_commands; 188350e8b216SKevin Cernekee priv->addr_command = PSMOUSE_CMD_DISABLE; 188425bded7cSSeth Forshee break; 188575af9e56SDave Turvene case ALPS_PROTO_V5: 188675af9e56SDave Turvene priv->hw_init = alps_hw_init_dolphin_v1; 1887ee65d4b3SYunkang Tang priv->process_packet = alps_process_touchpad_packet_v3_v5; 188875af9e56SDave Turvene priv->decode_fields = alps_decode_dolphin; 188975af9e56SDave Turvene priv->set_abs_params = alps_set_abs_params_mt; 189075af9e56SDave Turvene priv->nibble_commands = alps_v3_nibble_commands; 189175af9e56SDave Turvene priv->addr_command = PSMOUSE_CMD_RESET_WRAP; 189275af9e56SDave Turvene priv->byte0 = 0xc8; 1893ee65d4b3SYunkang Tang priv->mask0 = 0xd8; 189475af9e56SDave Turvene priv->flags = 0; 189575af9e56SDave Turvene priv->x_max = 1360; 189675af9e56SDave Turvene priv->y_max = 660; 189775af9e56SDave Turvene priv->x_bits = 23; 189875af9e56SDave Turvene priv->y_bits = 12; 189975af9e56SDave Turvene break; 190095f75e91SYunkang Tang case ALPS_PROTO_V6: 190195f75e91SYunkang Tang priv->hw_init = alps_hw_init_v6; 190295f75e91SYunkang Tang priv->process_packet = alps_process_packet_v6; 190395f75e91SYunkang Tang priv->set_abs_params = alps_set_abs_params_st; 190495f75e91SYunkang Tang priv->nibble_commands = alps_v6_nibble_commands; 190595f75e91SYunkang Tang priv->x_max = 2047; 190695f75e91SYunkang Tang priv->y_max = 1535; 190795f75e91SYunkang Tang break; 190825bded7cSSeth Forshee } 190925bded7cSSeth Forshee } 191025bded7cSSeth Forshee 1911b5d6b851SKevin Cernekee static int alps_match_table(struct psmouse *psmouse, struct alps_data *priv, 1912b5d6b851SKevin Cernekee unsigned char *e7, unsigned char *ec) 19132e992cc0SKevin Cernekee { 1914b5d6b851SKevin Cernekee const struct alps_model_info *model; 19152e992cc0SKevin Cernekee int i; 19162e992cc0SKevin Cernekee 1917b5d6b851SKevin Cernekee for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) { 1918b5d6b851SKevin Cernekee model = &alps_model_data[i]; 1919b5d6b851SKevin Cernekee 1920b5d6b851SKevin Cernekee if (!memcmp(e7, model->signature, sizeof(model->signature)) && 1921b5d6b851SKevin Cernekee (!model->command_mode_resp || 1922b5d6b851SKevin Cernekee model->command_mode_resp == ec[2])) { 1923b5d6b851SKevin Cernekee 1924b5d6b851SKevin Cernekee priv->proto_version = model->proto_version; 192524af5cb9SKevin Cernekee alps_set_defaults(priv); 192624af5cb9SKevin Cernekee 1927b5d6b851SKevin Cernekee priv->flags = model->flags; 1928b5d6b851SKevin Cernekee priv->byte0 = model->byte0; 1929b5d6b851SKevin Cernekee priv->mask0 = model->mask0; 1930b5d6b851SKevin Cernekee 1931b5d6b851SKevin Cernekee return 0; 1932b5d6b851SKevin Cernekee } 1933b5d6b851SKevin Cernekee } 1934b5d6b851SKevin Cernekee 1935b5d6b851SKevin Cernekee return -EINVAL; 1936b5d6b851SKevin Cernekee } 1937b5d6b851SKevin Cernekee 1938b5d6b851SKevin Cernekee static int alps_identify(struct psmouse *psmouse, struct alps_data *priv) 1939b5d6b851SKevin Cernekee { 1940b5d6b851SKevin Cernekee unsigned char e6[4], e7[4], ec[4]; 1941b5d6b851SKevin Cernekee 19422e992cc0SKevin Cernekee /* 19432e992cc0SKevin Cernekee * First try "E6 report". 19442e992cc0SKevin Cernekee * ALPS should return 0,0,10 or 0,0,100 if no buttons are pressed. 19452e992cc0SKevin Cernekee * The bits 0-2 of the first byte will be 1s if some buttons are 19462e992cc0SKevin Cernekee * pressed. 19472e992cc0SKevin Cernekee */ 1948b5d6b851SKevin Cernekee if (alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES, 1949b5d6b851SKevin Cernekee PSMOUSE_CMD_SETSCALE11, e6)) 1950b5d6b851SKevin Cernekee return -EIO; 19512e992cc0SKevin Cernekee 1952b5d6b851SKevin Cernekee if ((e6[0] & 0xf8) != 0 || e6[1] != 0 || (e6[2] != 10 && e6[2] != 100)) 1953b5d6b851SKevin Cernekee return -EINVAL; 19542e992cc0SKevin Cernekee 19552e992cc0SKevin Cernekee /* 1956b5d6b851SKevin Cernekee * Now get the "E7" and "EC" reports. These will uniquely identify 1957b5d6b851SKevin Cernekee * most ALPS touchpads. 19582e992cc0SKevin Cernekee */ 1959b5d6b851SKevin Cernekee if (alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES, 1960b5d6b851SKevin Cernekee PSMOUSE_CMD_SETSCALE21, e7) || 1961b5d6b851SKevin Cernekee alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES, 1962b5d6b851SKevin Cernekee PSMOUSE_CMD_RESET_WRAP, ec) || 1963b5d6b851SKevin Cernekee alps_exit_command_mode(psmouse)) 1964b5d6b851SKevin Cernekee return -EIO; 19652e992cc0SKevin Cernekee 1966f673ceb1SKevin Cernekee if (alps_match_table(psmouse, priv, e7, ec) == 0) { 1967b5d6b851SKevin Cernekee return 0; 196875af9e56SDave Turvene } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 && 1969ee65d4b3SYunkang Tang ec[0] == 0x73 && (ec[1] == 0x01 || ec[1] == 0x02)) { 197075af9e56SDave Turvene priv->proto_version = ALPS_PROTO_V5; 197175af9e56SDave Turvene alps_set_defaults(priv); 1972ee65d4b3SYunkang Tang if (alps_dolphin_get_device_area(psmouse, priv)) 1973ee65d4b3SYunkang Tang return -EIO; 1974ee65d4b3SYunkang Tang else 197575af9e56SDave Turvene return 0; 19761302bac3SKevin Cernekee } else if (ec[0] == 0x88 && ec[1] == 0x08) { 19771302bac3SKevin Cernekee priv->proto_version = ALPS_PROTO_V3; 19781302bac3SKevin Cernekee alps_set_defaults(priv); 19791302bac3SKevin Cernekee 19801302bac3SKevin Cernekee priv->hw_init = alps_hw_init_rushmore_v3; 19811302bac3SKevin Cernekee priv->decode_fields = alps_decode_rushmore; 19821302bac3SKevin Cernekee priv->x_bits = 16; 19831302bac3SKevin Cernekee priv->y_bits = 12; 19841302bac3SKevin Cernekee 1985cd401204SKevin Cernekee /* hack to make addr_command, nibble_command available */ 1986cd401204SKevin Cernekee psmouse->private = priv; 1987cd401204SKevin Cernekee 1988cd401204SKevin Cernekee if (alps_probe_trackstick_v3(psmouse, ALPS_REG_BASE_RUSHMORE)) 1989cd401204SKevin Cernekee priv->flags &= ~ALPS_DUALPOINT; 1990cd401204SKevin Cernekee 19911302bac3SKevin Cernekee return 0; 1992f673ceb1SKevin Cernekee } else if (ec[0] == 0x88 && ec[1] == 0x07 && 1993f673ceb1SKevin Cernekee ec[2] >= 0x90 && ec[2] <= 0x9d) { 1994f673ceb1SKevin Cernekee priv->proto_version = ALPS_PROTO_V3; 1995f673ceb1SKevin Cernekee alps_set_defaults(priv); 1996f673ceb1SKevin Cernekee 1997f673ceb1SKevin Cernekee return 0; 1998f673ceb1SKevin Cernekee } 19992e992cc0SKevin Cernekee 2000b5d6b851SKevin Cernekee psmouse_info(psmouse, 200139fbe585SDmitry Torokhov "Unknown ALPS touchpad: E7=%3ph, EC=%3ph\n", e7, ec); 20022e992cc0SKevin Cernekee 2003b5d6b851SKevin Cernekee return -EINVAL; 20042e992cc0SKevin Cernekee } 20052e992cc0SKevin Cernekee 20061e0c5b12SDmitry Torokhov static int alps_reconnect(struct psmouse *psmouse) 20071e0c5b12SDmitry Torokhov { 2008b5d6b851SKevin Cernekee struct alps_data *priv = psmouse->private; 200971bb21b6SMaxim Levitsky 20101e0c5b12SDmitry Torokhov psmouse_reset(psmouse); 20111e0c5b12SDmitry Torokhov 2012b5d6b851SKevin Cernekee if (alps_identify(psmouse, priv) < 0) 20131e0c5b12SDmitry Torokhov return -1; 20141e0c5b12SDmitry Torokhov 201524af5cb9SKevin Cernekee return priv->hw_init(psmouse); 20161da177e4SLinus Torvalds } 20171da177e4SLinus Torvalds 20181da177e4SLinus Torvalds static void alps_disconnect(struct psmouse *psmouse) 20191da177e4SLinus Torvalds { 20201da177e4SLinus Torvalds struct alps_data *priv = psmouse->private; 20212e5b636bSDmitry Torokhov 20221da177e4SLinus Torvalds psmouse_reset(psmouse); 20231d9f2626SSebastian Kapfer del_timer_sync(&priv->timer); 20242e5b636bSDmitry Torokhov input_unregister_device(priv->dev2); 20251da177e4SLinus Torvalds kfree(priv); 20261da177e4SLinus Torvalds } 20271da177e4SLinus Torvalds 202824af5cb9SKevin Cernekee static void alps_set_abs_params_st(struct alps_data *priv, 202924af5cb9SKevin Cernekee struct input_dev *dev1) 203024af5cb9SKevin Cernekee { 203195f75e91SYunkang Tang input_set_abs_params(dev1, ABS_X, 0, priv->x_max, 0, 0); 203295f75e91SYunkang Tang input_set_abs_params(dev1, ABS_Y, 0, priv->y_max, 0, 0); 203324af5cb9SKevin Cernekee } 203424af5cb9SKevin Cernekee 203524af5cb9SKevin Cernekee static void alps_set_abs_params_mt(struct alps_data *priv, 203624af5cb9SKevin Cernekee struct input_dev *dev1) 203724af5cb9SKevin Cernekee { 203824af5cb9SKevin Cernekee set_bit(INPUT_PROP_SEMI_MT, dev1->propbit); 203924af5cb9SKevin Cernekee input_mt_init_slots(dev1, 2, 0); 20407a9f73e7SKevin Cernekee input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0); 20417a9f73e7SKevin Cernekee input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0); 204224af5cb9SKevin Cernekee 204324af5cb9SKevin Cernekee set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit); 204424af5cb9SKevin Cernekee set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit); 204524af5cb9SKevin Cernekee set_bit(BTN_TOOL_QUADTAP, dev1->keybit); 204624af5cb9SKevin Cernekee 20477a9f73e7SKevin Cernekee input_set_abs_params(dev1, ABS_X, 0, priv->x_max, 0, 0); 20487a9f73e7SKevin Cernekee input_set_abs_params(dev1, ABS_Y, 0, priv->y_max, 0, 0); 204924af5cb9SKevin Cernekee } 205024af5cb9SKevin Cernekee 20511da177e4SLinus Torvalds int alps_init(struct psmouse *psmouse) 20521da177e4SLinus Torvalds { 20531da177e4SLinus Torvalds struct alps_data *priv; 20542e5b636bSDmitry Torokhov struct input_dev *dev1 = psmouse->dev, *dev2; 20551da177e4SLinus Torvalds 2056f42649e8SDmitry Torokhov priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL); 20572e5b636bSDmitry Torokhov dev2 = input_allocate_device(); 20582e5b636bSDmitry Torokhov if (!priv || !dev2) 20591da177e4SLinus Torvalds goto init_fail; 20602e5b636bSDmitry Torokhov 20612e5b636bSDmitry Torokhov priv->dev2 = dev2; 20621d9f2626SSebastian Kapfer setup_timer(&priv->timer, alps_flush_packet, (unsigned long)psmouse); 20631d9f2626SSebastian Kapfer 20641e0c5b12SDmitry Torokhov psmouse->private = priv; 20651da177e4SLinus Torvalds 206625bded7cSSeth Forshee psmouse_reset(psmouse); 206725bded7cSSeth Forshee 2068b5d6b851SKevin Cernekee if (alps_identify(psmouse, priv) < 0) 206971bb21b6SMaxim Levitsky goto init_fail; 207071bb21b6SMaxim Levitsky 207124af5cb9SKevin Cernekee if (priv->hw_init(psmouse)) 20721da177e4SLinus Torvalds goto init_fail; 20731da177e4SLinus Torvalds 20747105d2eaSDmitry Torokhov /* 20757105d2eaSDmitry Torokhov * Undo part of setup done for us by psmouse core since touchpad 20767105d2eaSDmitry Torokhov * is not a relative device. 20777105d2eaSDmitry Torokhov */ 20787105d2eaSDmitry Torokhov __clear_bit(EV_REL, dev1->evbit); 20797105d2eaSDmitry Torokhov __clear_bit(REL_X, dev1->relbit); 20807105d2eaSDmitry Torokhov __clear_bit(REL_Y, dev1->relbit); 20817105d2eaSDmitry Torokhov 20827105d2eaSDmitry Torokhov /* 20837105d2eaSDmitry Torokhov * Now set up our capabilities. 20847105d2eaSDmitry Torokhov */ 20857b19ada2SJiri Slaby dev1->evbit[BIT_WORD(EV_KEY)] |= BIT_MASK(EV_KEY); 20867b19ada2SJiri Slaby dev1->keybit[BIT_WORD(BTN_TOUCH)] |= BIT_MASK(BTN_TOUCH); 20877b19ada2SJiri Slaby dev1->keybit[BIT_WORD(BTN_TOOL_FINGER)] |= BIT_MASK(BTN_TOOL_FINGER); 208871bb21b6SMaxim Levitsky dev1->keybit[BIT_WORD(BTN_LEFT)] |= 208971bb21b6SMaxim Levitsky BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT); 20901da177e4SLinus Torvalds 20917b19ada2SJiri Slaby dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS); 209225bded7cSSeth Forshee 209324af5cb9SKevin Cernekee priv->set_abs_params(priv, dev1); 20942e5b636bSDmitry Torokhov input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0); 20951da177e4SLinus Torvalds 209699df65e7SKevin Cernekee if (priv->flags & ALPS_WHEEL) { 20977b19ada2SJiri Slaby dev1->evbit[BIT_WORD(EV_REL)] |= BIT_MASK(EV_REL); 20987b19ada2SJiri Slaby dev1->relbit[BIT_WORD(REL_WHEEL)] |= BIT_MASK(REL_WHEEL); 20991da177e4SLinus Torvalds } 21001da177e4SLinus Torvalds 210199df65e7SKevin Cernekee if (priv->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { 21027b19ada2SJiri Slaby dev1->keybit[BIT_WORD(BTN_FORWARD)] |= BIT_MASK(BTN_FORWARD); 21037b19ada2SJiri Slaby dev1->keybit[BIT_WORD(BTN_BACK)] |= BIT_MASK(BTN_BACK); 21041da177e4SLinus Torvalds } 21051da177e4SLinus Torvalds 210699df65e7SKevin Cernekee if (priv->flags & ALPS_FOUR_BUTTONS) { 210771bb21b6SMaxim Levitsky dev1->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_0); 210871bb21b6SMaxim Levitsky dev1->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1); 210971bb21b6SMaxim Levitsky dev1->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2); 211071bb21b6SMaxim Levitsky dev1->keybit[BIT_WORD(BTN_3)] |= BIT_MASK(BTN_3); 211171bb21b6SMaxim Levitsky } else { 211271bb21b6SMaxim Levitsky dev1->keybit[BIT_WORD(BTN_MIDDLE)] |= BIT_MASK(BTN_MIDDLE); 211371bb21b6SMaxim Levitsky } 211471bb21b6SMaxim Levitsky 211508ffce45SDmitry Torokhov snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys); 21162e5b636bSDmitry Torokhov dev2->phys = priv->phys; 211799df65e7SKevin Cernekee dev2->name = (priv->flags & ALPS_DUALPOINT) ? 21189354f263SYunkang Tang "DualPoint Stick" : "ALPS PS/2 Device"; 21192e5b636bSDmitry Torokhov dev2->id.bustype = BUS_I8042; 21202e5b636bSDmitry Torokhov dev2->id.vendor = 0x0002; 21212e5b636bSDmitry Torokhov dev2->id.product = PSMOUSE_ALPS; 21222e5b636bSDmitry Torokhov dev2->id.version = 0x0000; 21231db3a345SDmitry Torokhov dev2->dev.parent = &psmouse->ps2dev.serio->dev; 21241da177e4SLinus Torvalds 21257b19ada2SJiri Slaby dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); 212671bb21b6SMaxim Levitsky dev2->relbit[BIT_WORD(REL_X)] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); 212771bb21b6SMaxim Levitsky dev2->keybit[BIT_WORD(BTN_LEFT)] = 212871bb21b6SMaxim Levitsky BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); 21291da177e4SLinus Torvalds 2130f42649e8SDmitry Torokhov if (input_register_device(priv->dev2)) 2131f42649e8SDmitry Torokhov goto init_fail; 21321da177e4SLinus Torvalds 21331da177e4SLinus Torvalds psmouse->protocol_handler = alps_process_byte; 2134f0d5c6f4SDmitry Torokhov psmouse->poll = alps_poll; 21351da177e4SLinus Torvalds psmouse->disconnect = alps_disconnect; 21361da177e4SLinus Torvalds psmouse->reconnect = alps_reconnect; 213799df65e7SKevin Cernekee psmouse->pktsize = priv->proto_version == ALPS_PROTO_V4 ? 8 : 6; 21381da177e4SLinus Torvalds 2139f0d5c6f4SDmitry Torokhov /* We are having trouble resyncing ALPS touchpads so disable it for now */ 2140f0d5c6f4SDmitry Torokhov psmouse->resync_time = 0; 2141f0d5c6f4SDmitry Torokhov 21421da177e4SLinus Torvalds return 0; 21431da177e4SLinus Torvalds 21441da177e4SLinus Torvalds init_fail: 2145f42649e8SDmitry Torokhov psmouse_reset(psmouse); 21462e5b636bSDmitry Torokhov input_free_device(dev2); 21471da177e4SLinus Torvalds kfree(priv); 21481e0c5b12SDmitry Torokhov psmouse->private = NULL; 21491da177e4SLinus Torvalds return -1; 21501da177e4SLinus Torvalds } 21511da177e4SLinus Torvalds 2152b7802c5cSDmitry Torokhov int alps_detect(struct psmouse *psmouse, bool set_properties) 21531da177e4SLinus Torvalds { 2154b5d6b851SKevin Cernekee struct alps_data dummy; 21551da177e4SLinus Torvalds 2156b5d6b851SKevin Cernekee if (alps_identify(psmouse, &dummy) < 0) 21571da177e4SLinus Torvalds return -1; 21581da177e4SLinus Torvalds 21591da177e4SLinus Torvalds if (set_properties) { 21601da177e4SLinus Torvalds psmouse->vendor = "ALPS"; 2161b5d6b851SKevin Cernekee psmouse->name = dummy.flags & ALPS_DUALPOINT ? 2162968ac842SDmitry Torokhov "DualPoint TouchPad" : "GlidePoint"; 2163b5d6b851SKevin Cernekee psmouse->model = dummy.proto_version << 8; 21641da177e4SLinus Torvalds } 21651da177e4SLinus Torvalds return 0; 21661da177e4SLinus Torvalds } 21671da177e4SLinus Torvalds 2168