From patchwork Sat Jun 18 23:43:46 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?Pali_Roh=C3=A1r?= X-Patchwork-Id: 9185881 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 663546075F for ; Sat, 18 Jun 2016 23:43:53 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4F59C2793B for ; Sat, 18 Jun 2016 23:43:53 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3F2E227D45; Sat, 18 Jun 2016 23:43:53 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, T_DKIM_INVALID, T_TVD_MIME_EPI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4CB762793B for ; Sat, 18 Jun 2016 23:43:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751147AbcFRXnv (ORCPT ); Sat, 18 Jun 2016 19:43:51 -0400 Received: from mail-wm0-f66.google.com ([74.125.82.66]:33118 "EHLO mail-wm0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751114AbcFRXnu (ORCPT ); Sat, 18 Jun 2016 19:43:50 -0400 Received: by mail-wm0-f66.google.com with SMTP id r201so5848384wme.0; Sat, 18 Jun 2016 16:43:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:subject:date:user-agent:cc:mime-version :content-transfer-encoding:message-id; bh=UBXXbUbp4RdIJ8J+RmWEmorRgWc9VES/6YjHdFigvz4=; b=f2/wkzEi/pQQ7oj3lYkW7YARh3crzDzNZxN6Zq2tddQalytfhL9WiQ+O1dbsTeTuN0 jNEc6UZy4pofUJA+hn29AxszGNT0/DWYw6T2s9qu6jJUdy6bmHSr6NbALWokoFGM/Jts yHvKZ8Ghq1oPWRTOhCt0cEGFrrYNwGWsUQTvqzYk7IyakiNBSzfb71ULhP7gwTxutrC6 M4kHswPUf3fcD+eckKFvgWEps39Rcp4EDOLNe3lDNmPYGfVMVYChV7lV0f9UbhtuOQ7f YCDuSd/15vBIq70FqYM/gZAljaHWowIur3sj7mJ4C0x86hTNE2wa+yNPxDhcRz9vbqLC weZw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:subject:date:user-agent:cc:mime-version :content-transfer-encoding:message-id; bh=UBXXbUbp4RdIJ8J+RmWEmorRgWc9VES/6YjHdFigvz4=; b=irV26oMBoP3H1Dhn1uDbLl/TA8IALSQwvYSIyCjJ2htfxzX77dHPKpSgZQSxL5dEyJ c8kM4WCCejP2EjKgs7HkVlEmS6wxFpB0V6n5ntEDF7EfXYpJC7MYR8TqwYXUB8cXMUSC TY4Op7RtftbgNBSPV1FVUPDyvbU+H0CaX/pocMAjcF0+vyiojsfv4Dta+Pnkwin5NzMi 1yJc3SK4bxBSQwNpsGXyfe0QcxtUd7YWdU2jeAW7DeM4fkDRnHklSGBLyc0FKXa7vss9 Yrr5Er1VTVR9m58g8djmZ38vxX5zEZCAWWDGRodAd4lF++AyGGrRK//mKYl+lJUUZXVq UEEg== X-Gm-Message-State: ALyK8tKVGCZ2A3xkVS4VACVpyqrmtEHDRSP18i6Mk7KDYiI/+vgP55mTixk44EbBP7EAiA== X-Received: by 10.28.154.214 with SMTP id c205mr4731863wme.9.1466293428349; Sat, 18 Jun 2016 16:43:48 -0700 (PDT) Received: from pali-latitude.localnet (pali.kolej.mff.cuni.cz. [78.128.193.202]) by smtp.gmail.com with ESMTPSA id f73sm1013748wmg.1.2016.06.18.16.43.47 (version=TLS1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sat, 18 Jun 2016 16:43:47 -0700 (PDT) From: Pali =?utf-8?q?Roh=C3=A1r?= To: Ben Gamari , Hans de Goede , Allen Hung , Ben Morgan , Masaki Ota , Dmitry Torokhov Subject: Canonical has own Ubuntu driver for ALPS 73 03 28 devices Date: Sun, 19 Jun 2016 01:43:46 +0200 User-Agent: KMail/1.13.7 (Linux/3.13.0-88-generic; KDE/4.14.2; x86_64; ; ) Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org MIME-Version: 1.0 Message-Id: <201606190143.46444@pali> Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP I did not know about it since I found: http://oem.archive.canonical.com/pool/public/o/oem-alps-touchpad-1521052-dkms/oem-alps-touchpad-1521052-dkms_1oem7_all.deb If you are interested extracted patch is in attachment. I do not understand it... Why Canonical is hidden and don't communicate with rest of world? Otherwise touchpads could work out-of-box on non Ubuntu systems too with mainline kernel. --- alps.c 2016-06-19 01:26:34.755016680 +0200 +++ alps.c 2016-02-03 07:09:04.000000000 +0100 @@ -159,6 +159,10 @@ static const struct alps_protocol_info a ALPS_PROTO_V8, 0x18, 0x18, 0 }; +static const struct alps_protocol_info alps_flare_protocol_data = { + ALPS_PROTO_FLARE, 0x18, 0x18, 0 +}; + /* * Some v2 models report the stick buttons in separate bits */ @@ -509,7 +513,7 @@ static void alps_report_mt_data(struct p struct alps_fields *f = &priv->f; int i, slot[MAX_TOUCHES]; - input_mt_assign_slots(dev, slot, f->mt, n, 0); + input_mt_assign_slots(dev, slot, f->mt, n); for (i = 0; i < n; i++) alps_set_slot(dev, slot[i], f->mt[i].x, f->mt[i].y); @@ -716,6 +720,84 @@ static int alps_decode_dolphin(struct al return 0; } +static int alps_decode_flare_standard(struct alps_fields *f, unsigned char *p, + struct psmouse *psmouse) +{ + if (FLARE_IS_1F_PACKET(p)) { + f->fingers = 1; + f->st.x = FLARE_1F_X(p); + f->st.y = FLARE_1F_Y(p); + f->pressure = FLARE_1F_Z(p); + f->mt[0].x = f->st.x; + f->mt[0].y = f->st.y; + + f->middle = !!(FLARE_STD_BTN(p) & 0x04); + f->right = !!(FLARE_STD_BTN(p) & 0x02); + f->left = !!(FLARE_STD_BTN(p) & 0x01); + + /* Guard */ + if (f->pressure == 0) { + f->fingers = 0; + } + } else if (FLARE_IS_2F_PACKET(p)) { + f->fingers = 2; + if (FLARE_MF_Z(p, 0) == 1) { + f->pressure = 64; + } else if (FLARE_MF_Z(p, 0) == 2) { + f->pressure = 127; + } + + f->mt[0].x = FLARE_STD_MF_X(p, 0); + f->mt[0].y = FLARE_STD_MF_Y(p, 0); + f->mt[1].x = FLARE_STD_MF_X(p, 1); + f->mt[1].y = FLARE_STD_MF_Y(p, 1); + + f->st.x = f->mt[0].x; + f->st.y = f->mt[0].y; + } + + return 0; +} + +static int alps_decode_flare_buttonless(struct alps_fields *f, unsigned char *p, + struct psmouse *psmouse) +{ + if (FLARE_IS_1F_PACKET(p)) { + f->fingers = 1; + f->st.x = FLARE_1F_X(p); + f->st.y = FLARE_1F_Y(p); + f->pressure = FLARE_1F_LFB(p) ? 127 : 64; + f->mt[0].x = f->st.x; + f->mt[0].y = f->st.y; + + /* Guard. + * How the Z value is calculated is arbitrary. :-) */ + if (FLARE_1F_Z(p) == 0) { + f->fingers = 0; + f->pressure = 0; + } else if (FLARE_1F_Z(p) < 6) { + f->pressure = FLARE_1F_Z(p) * 12; + } + } else if (FLARE_IS_2F_PACKET(p)) { + f->fingers = 2; + if (FLARE_MF_Z(p, 0) == 1) { + f->pressure = 64; + } else if (FLARE_MF_Z(p, 0) == 2) { + f->pressure = 127; + } + + f->mt[0].x = FLARE_BTL_MF_X(p, 0); + f->mt[0].y = FLARE_BTL_MF_Y(p, 0); + f->mt[1].x = FLARE_BTL_MF_X(p, 1); + f->mt[1].y = FLARE_BTL_MF_Y(p, 1); + + f->st.x = f->mt[0].x; + f->st.y = f->mt[0].y; + } + + return 0; +} + static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse) { struct alps_data *priv = psmouse->private; @@ -793,6 +875,66 @@ static void alps_process_touchpad_packet input_sync(dev2); } } +static void alps_process_touchpad_packet_flare(struct psmouse *psmouse) +{ + struct alps_data *priv = psmouse->private; + unsigned char *packet = psmouse->packet; + struct input_dev *dev = psmouse->dev; + int x1 = 0, y1 = 0, x2 = 0, y2 = 0; + int fingers = 0; + struct alps_fields *f = &priv->f; + + priv->decode_fields(f, packet, psmouse); + + fingers = f->fingers; + x1 = f->mt[0].x; + y1 = f->mt[0].y; + x2 = f->mt[1].x; + y2 = f->mt[1].y; + + /* + * Sometimes the hardware sends a single packet with z = 0 + * in the middle of a stream. Real releases generate packets + * with x, y, and z all zero, so these seem to be flukes. + * Ignore them. + */ + if (f->st.x && f->st.y && !f->pressure) + return; + + if (f->pressure > 0) + input_report_key(dev, BTN_TOUCH, 1); + else + input_report_key(dev, BTN_TOUCH, 0); + + + input_mt_slot(dev, 0); + input_mt_report_slot_state(dev, MT_TOOL_FINGER, fingers != 0); + if (fingers != 0) { + input_report_abs(dev, ABS_MT_POSITION_X, x1); + input_report_abs(dev, ABS_MT_POSITION_Y, y1); + } + + input_mt_slot(dev, 1); + input_mt_report_slot_state(dev, MT_TOOL_FINGER, fingers == 2); + if (fingers == 2) { + input_report_abs(dev, ABS_MT_POSITION_X, x2); + input_report_abs(dev, ABS_MT_POSITION_Y, y2); + } + + input_mt_report_finger_count(dev, fingers); + + input_report_key(dev, BTN_LEFT, f->left); + input_report_key(dev, BTN_RIGHT, f->right); + input_report_key(dev, BTN_MIDDLE, f->middle); + + if (f->pressure > 0) { + input_report_abs(dev, ABS_X, f->st.x); + input_report_abs(dev, ABS_Y, f->st.y); + } + input_report_abs(dev, ABS_PRESSURE, f->pressure); + + input_sync(dev); +} static void alps_process_packet_v3(struct psmouse *psmouse) { @@ -1545,6 +1687,7 @@ static psmouse_ret_t alps_process_byte(s * Can not distinguish V8's first byte from PS/2 packet's */ if (priv->proto_version != ALPS_PROTO_V8 && + priv->proto_version != ALPS_PROTO_FLARE && /* Ss5 use absolute mode */ !psmouse->out_of_sync_cnt && (psmouse->packet[0] & 0xc8) == 0x08) { @@ -2518,6 +2661,24 @@ static int alps_hw_init_dolphin_v1(struc return 0; } +static int alps_hw_init_flare(struct psmouse *psmouse) +{ + struct ps2dev *ps2dev = &psmouse->ps2dev; + unsigned char param[2]; + + /* This is dolphin "v1" as empirically defined by florin9doi */ + param[0] = 0x64; + param[1] = 0x28; + + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) || + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) || + ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) || + ps2_command(ps2dev, ¶m[1], PSMOUSE_CMD_SETRATE)) + return -1; + + return 0; +} + static int alps_hw_init_v7(struct psmouse *psmouse) { struct ps2dev *ps2dev = &psmouse->ps2dev; @@ -2576,10 +2737,29 @@ error: return ret; } +static void alps_set_abs_params_mt(struct alps_data *priv, + struct input_dev *dev1) +{ + set_bit(INPUT_PROP_SEMI_MT, dev1->propbit); + input_mt_init_slots(dev1, 2, 0); + input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0); + input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0); + + set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit); + set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit); + set_bit(BTN_TOOL_QUADTAP, dev1->keybit); + + input_set_abs_params(dev1, ABS_X, 0, priv->x_max, 0, 0); + input_set_abs_params(dev1, ABS_Y, 0, priv->y_max, 0, 0); +} + static int alps_set_protocol(struct psmouse *psmouse, struct alps_data *priv, const struct alps_protocol_info *protocol) { + unsigned char flare_config_page[3]; + struct ps2dev *ps2dev = &psmouse->ps2dev; + psmouse->private = priv; setup_timer(&priv->timer, alps_flush_packet, (unsigned long)psmouse); @@ -2654,6 +2834,52 @@ static int alps_set_protocol(struct psmo break; + case ALPS_PROTO_FLARE: + priv->hw_init = alps_hw_init_flare; + priv->process_packet = alps_process_touchpad_packet_flare; + priv->set_abs_params = alps_set_abs_params_mt; + priv->nibble_commands = alps_v3_nibble_commands; + priv->addr_command = PSMOUSE_CMD_RESET_WRAP; + priv->x_bits = 12; + priv->y_bits = 12; + + /* Read configure page 0 */ + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || + ps2_command(ps2dev, flare_config_page, PSMOUSE_CMD_GETINFO) || + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) || + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) || + ps2_command(ps2dev, flare_config_page, PSMOUSE_CMD_GETINFO)) { + return -EIO; + } + + priv->x_max = (flare_config_page[2] & 0x0f) + 16 - 1; + priv->y_max = ((flare_config_page[2] >> 4) & 0x0f) + 5 - 1; + + /* Read configure page 1 */ + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) || + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) || + ps2_command(ps2dev, flare_config_page, PSMOUSE_CMD_GETINFO)) { + return -EIO; + } + + /* b1 of byte0 of configure page 1: Pad Button Emulation + * 0: No, standard mode + * 1: Yes, buttonless(or force) mode */ + if ((flare_config_page[0] & 0x02)) { + priv->decode_fields = alps_decode_flare_buttonless; + priv->x_max <<= 6; + priv->y_max <<= 6; + + } else { + priv->decode_fields = alps_decode_flare_standard; + priv->x_max <<= 7; + priv->y_max <<= 7; + } + + break; + case ALPS_PROTO_V6: priv->hw_init = alps_hw_init_v6; priv->process_packet = alps_process_packet_v6; @@ -2744,7 +2970,6 @@ static int alps_identify(struct psmouse PSMOUSE_CMD_RESET_WRAP, ec) || alps_exit_command_mode(psmouse)) return -EIO; - protocol = alps_match_table(e7, ec); if (!protocol) { if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 && @@ -2761,6 +2986,8 @@ static int alps_identify(struct psmouse } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x14 && ec[1] == 0x02) { protocol = &alps_v8_protocol_data; + } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x28) { + protocol = &alps_flare_protocol_data; } else { psmouse_dbg(psmouse, "Likely not an ALPS touchpad: E7=%3ph, EC=%3ph\n", e7, ec); --- alps.h 2016-06-19 01:34:46.745006525 +0200 +++ alps.h 2016-02-03 07:09:04.000000000 +0100 @@ -20,6 +20,7 @@ #define ALPS_PROTO_V3_RUSHMORE 0x310 #define ALPS_PROTO_V4 0x400 #define ALPS_PROTO_V5 0x500 +#define ALPS_PROTO_FLARE 0x510 #define ALPS_PROTO_V6 0x600 #define ALPS_PROTO_V7 0x700 /* t3btl t4s */ #define ALPS_PROTO_V8 0x800 /* SS4btl SS4s */ @@ -122,6 +123,58 @@ enum V7_PACKET_ID { V7_PACKET_ID_UNKNOWN, }; +/* Packet identification Macros for Flare Version2 */ +/* ------------------------------------------------------------- */ +/* FLARE_IS_1F_PACKET = Recognizes 1-finger packet from others */ +/* FLARE_IS_2F_PACKET = Recognizes 2-finger packet from others */ +#define FLARE_IS_1F_PACKET(_b) ((((_b[3] >> 4) & 0x01) == 0) && (((_b[3] >> 5) & 0x01) == 0)) +#define FLARE_IS_2F_PACKET(_b) ((((_b[3] >> 4) & 0x01) == 0x01) && (((_b[3] >> 5) & 0x01) == 0)) +#define FLARE_1F_Z(_b) (((_b[5] ) & 0x0F) | \ + ((_b[5] >> 1) & 0x70) | \ + ((_b[4] ) & 0x80) \ + ) + + +#define FLARE_1F_X(_b) ((_b[0] & 0x0007) | \ + ((_b[1] << 3) & 0x0078) | \ + ((_b[1] << 2) & 0x0380) | \ + ((_b[2] << 5) & 0x0C00) \ + ) +#define FLARE_1F_Y(_b) (((_b[2] ) & 0x000F) | \ + ((_b[3] >> 2) & 0x0030) | \ + ((_b[4] << 6) & 0x03C0) | \ + ((_b[4] << 5) & 0x0C00) \ + ) + +#define FLARE_1F_LFB(_b) (((_b[2] >> 4) & 0x01) == 0x01) +#define FLARE_MF_Z(_b, _i) (((_b[1 + _i * 3] ) & 0x0001) | \ + ((_b[1 + _i * 3] >> 1) & 0x0002) \ + ) +#define FLARE_MF_LF(_b, _i) ((_b[1 + _i * 3] & 0x0004) == 0x0004) + +/* Packet decoding macros of - Normal HW composition */ +/* ------------------------------------------------------ */ +/* FLARE_STD_BTN = 3-bit (; ---- ---- ---- -210 ) */ +/* FLARE_STD_MF_X = 8-bit (; ---- BA98 7654 ---- ) */ +/* FLARE_STD_MF_Y = 8-bit (; ---- BA98 7654 ---- ) */ +#define FLARE_STD_BTN(_b) ((_b[0] >> 5 ) & 0x07) +#define FLARE_STD_MF_X(_b, _i) (((_b[0 + _i * 3] << 4) & 0x0070) | \ + ((_b[1 + _i * 3] << 4) & 0x0F80) \ + ) +#define FLARE_STD_MF_Y(_b, _i) (((_b[1 + _i * 3] << 3) & 0x0010) | \ + ((_b[2 + _i * 3] << 5) & 0x01E0) | \ + ((_b[2 + _i * 3] << 4) & 0x0E00) \ + ) + +/* Packet decoding macros of - Buttonless HW composition */ +/* -------------------------------------------------------- */ +/* FLARE_BTL_MF_X = 9-bit (; ---- BA98 7654 3--- ) */ +/* FLARE_BTL_MF_Y = 9-bit (; ---- BA98 7654 3--- ) */ +#define FLARE_BTL_MF_X(_b, _i) (FLARE_STD_MF_X(_b, _i) | ((_b[0 + _i * 3] >> 4) & 0x0008)) +#define FLARE_BTL_MF_Y(_b, _i) (FLARE_STD_MF_Y(_b, _i) | ((_b[0 + _i * 3] >> 3) & 0x0008)) + + + /** * struct alps_protocol_info - information about protocol used by a device * @version: Indicates V1/V2/V3/...