Canonical has own Ubuntu driver for ALPS 73 03 28 devices
From: Pali RohÃr
Date: Sat Jun 18 2016 - 19:43:55 EST
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.
--
Pali RohÃr
pali.rohar@xxxxxxxxx
--- 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/...
Attachment:
signature.asc
Description: This is a digitally signed message part.