--- 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/...