|
@@ -153,10 +153,18 @@ static const struct alps_protocol_info alps_v7_protocol_data = {
|
|
ALPS_PROTO_V7, 0x48, 0x48, ALPS_DUALPOINT
|
|
ALPS_PROTO_V7, 0x48, 0x48, ALPS_DUALPOINT
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+static const struct alps_protocol_info alps_v8_protocol_data = {
|
|
|
|
+ ALPS_PROTO_V8, 0x18, 0x18, 0
|
|
|
|
+};
|
|
|
|
+
|
|
static void alps_set_abs_params_st(struct alps_data *priv,
|
|
static void alps_set_abs_params_st(struct alps_data *priv,
|
|
struct input_dev *dev1);
|
|
struct input_dev *dev1);
|
|
static void alps_set_abs_params_mt(struct alps_data *priv,
|
|
static void alps_set_abs_params_mt(struct alps_data *priv,
|
|
struct input_dev *dev1);
|
|
struct input_dev *dev1);
|
|
|
|
+static void alps_set_abs_params_v7(struct alps_data *priv,
|
|
|
|
+ struct input_dev *dev1);
|
|
|
|
+static void alps_set_abs_params_ss4_v2(struct alps_data *priv,
|
|
|
|
+ struct input_dev *dev1);
|
|
|
|
|
|
/* Packet formats are described in Documentation/input/alps.txt */
|
|
/* Packet formats are described in Documentation/input/alps.txt */
|
|
|
|
|
|
@@ -243,6 +251,14 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /* Non interleaved V2 dualpoint has separate stick button bits */
|
|
|
|
+ if (priv->proto_version == ALPS_PROTO_V2 &&
|
|
|
|
+ priv->flags == (ALPS_PASS | ALPS_DUALPOINT)) {
|
|
|
|
+ left |= packet[0] & 1;
|
|
|
|
+ right |= packet[0] & 2;
|
|
|
|
+ middle |= packet[0] & 4;
|
|
|
|
+ }
|
|
|
|
+
|
|
alps_report_buttons(dev, dev2, left, right, middle);
|
|
alps_report_buttons(dev, dev2, left, right, middle);
|
|
|
|
|
|
/* Convert hardware tap to a reasonable Z value */
|
|
/* Convert hardware tap to a reasonable Z value */
|
|
@@ -1085,6 +1101,176 @@ static void alps_process_packet_v7(struct psmouse *psmouse)
|
|
alps_process_touchpad_packet_v7(psmouse);
|
|
alps_process_touchpad_packet_v7(psmouse);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static unsigned char alps_get_pkt_id_ss4_v2(unsigned char *byte)
|
|
|
|
+{
|
|
|
|
+ unsigned char pkt_id = SS4_PACKET_ID_IDLE;
|
|
|
|
+
|
|
|
|
+ if (byte[0] == 0x18 && byte[1] == 0x10 && byte[2] == 0x00 &&
|
|
|
|
+ (byte[3] & 0x88) == 0x08 && byte[4] == 0x10 && byte[5] == 0x00) {
|
|
|
|
+ pkt_id = SS4_PACKET_ID_IDLE;
|
|
|
|
+ } else if (!(byte[3] & 0x10)) {
|
|
|
|
+ pkt_id = SS4_PACKET_ID_ONE;
|
|
|
|
+ } else if (!(byte[3] & 0x20)) {
|
|
|
|
+ pkt_id = SS4_PACKET_ID_TWO;
|
|
|
|
+ } else {
|
|
|
|
+ pkt_id = SS4_PACKET_ID_MULTI;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return pkt_id;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int alps_decode_ss4_v2(struct alps_fields *f,
|
|
|
|
+ unsigned char *p, struct psmouse *psmouse)
|
|
|
|
+{
|
|
|
|
+ struct alps_data *priv = psmouse->private;
|
|
|
|
+ unsigned char pkt_id;
|
|
|
|
+ unsigned int no_data_x, no_data_y;
|
|
|
|
+
|
|
|
|
+ pkt_id = alps_get_pkt_id_ss4_v2(p);
|
|
|
|
+
|
|
|
|
+ /* Current packet is 1Finger coordinate packet */
|
|
|
|
+ switch (pkt_id) {
|
|
|
|
+ case SS4_PACKET_ID_ONE:
|
|
|
|
+ f->mt[0].x = SS4_1F_X_V2(p);
|
|
|
|
+ f->mt[0].y = SS4_1F_Y_V2(p);
|
|
|
|
+ f->pressure = ((SS4_1F_Z_V2(p)) * 2) & 0x7f;
|
|
|
|
+ f->fingers = 1;
|
|
|
|
+ f->first_mp = 0;
|
|
|
|
+ f->is_mp = 0;
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case SS4_PACKET_ID_TWO:
|
|
|
|
+ if (priv->flags & ALPS_BUTTONPAD) {
|
|
|
|
+ f->mt[0].x = SS4_BTL_MF_X_V2(p, 0);
|
|
|
|
+ f->mt[0].y = SS4_BTL_MF_Y_V2(p, 0);
|
|
|
|
+ f->mt[1].x = SS4_BTL_MF_X_V2(p, 1);
|
|
|
|
+ f->mt[1].y = SS4_BTL_MF_Y_V2(p, 1);
|
|
|
|
+ } else {
|
|
|
|
+ f->mt[0].x = SS4_STD_MF_X_V2(p, 0);
|
|
|
|
+ f->mt[0].y = SS4_STD_MF_Y_V2(p, 0);
|
|
|
|
+ f->mt[1].x = SS4_STD_MF_X_V2(p, 1);
|
|
|
|
+ f->mt[1].y = SS4_STD_MF_Y_V2(p, 1);
|
|
|
|
+ }
|
|
|
|
+ f->pressure = SS4_MF_Z_V2(p, 0) ? 0x30 : 0;
|
|
|
|
+
|
|
|
|
+ if (SS4_IS_MF_CONTINUE(p)) {
|
|
|
|
+ f->first_mp = 1;
|
|
|
|
+ } else {
|
|
|
|
+ f->fingers = 2;
|
|
|
|
+ f->first_mp = 0;
|
|
|
|
+ }
|
|
|
|
+ f->is_mp = 0;
|
|
|
|
+
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case SS4_PACKET_ID_MULTI:
|
|
|
|
+ if (priv->flags & ALPS_BUTTONPAD) {
|
|
|
|
+ f->mt[2].x = SS4_BTL_MF_X_V2(p, 0);
|
|
|
|
+ f->mt[2].y = SS4_BTL_MF_Y_V2(p, 0);
|
|
|
|
+ f->mt[3].x = SS4_BTL_MF_X_V2(p, 1);
|
|
|
|
+ f->mt[3].y = SS4_BTL_MF_Y_V2(p, 1);
|
|
|
|
+ no_data_x = SS4_MFPACKET_NO_AX_BL;
|
|
|
|
+ no_data_y = SS4_MFPACKET_NO_AY_BL;
|
|
|
|
+ } else {
|
|
|
|
+ f->mt[2].x = SS4_STD_MF_X_V2(p, 0);
|
|
|
|
+ f->mt[2].y = SS4_STD_MF_Y_V2(p, 0);
|
|
|
|
+ f->mt[3].x = SS4_STD_MF_X_V2(p, 1);
|
|
|
|
+ f->mt[3].y = SS4_STD_MF_Y_V2(p, 1);
|
|
|
|
+ no_data_x = SS4_MFPACKET_NO_AX;
|
|
|
|
+ no_data_y = SS4_MFPACKET_NO_AY;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ f->first_mp = 0;
|
|
|
|
+ f->is_mp = 1;
|
|
|
|
+
|
|
|
|
+ if (SS4_IS_5F_DETECTED(p)) {
|
|
|
|
+ f->fingers = 5;
|
|
|
|
+ } else if (f->mt[3].x == no_data_x &&
|
|
|
|
+ f->mt[3].y == no_data_y) {
|
|
|
|
+ f->mt[3].x = 0;
|
|
|
|
+ f->mt[3].y = 0;
|
|
|
|
+ f->fingers = 3;
|
|
|
|
+ } else {
|
|
|
|
+ f->fingers = 4;
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case SS4_PACKET_ID_IDLE:
|
|
|
|
+ default:
|
|
|
|
+ memset(f, 0, sizeof(struct alps_fields));
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ f->left = !!(SS4_BTN_V2(p) & 0x01);
|
|
|
|
+ if (!(priv->flags & ALPS_BUTTONPAD)) {
|
|
|
|
+ f->right = !!(SS4_BTN_V2(p) & 0x02);
|
|
|
|
+ f->middle = !!(SS4_BTN_V2(p) & 0x04);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void alps_process_packet_ss4_v2(struct psmouse *psmouse)
|
|
|
|
+{
|
|
|
|
+ struct alps_data *priv = psmouse->private;
|
|
|
|
+ unsigned char *packet = psmouse->packet;
|
|
|
|
+ struct input_dev *dev = psmouse->dev;
|
|
|
|
+ struct alps_fields *f = &priv->f;
|
|
|
|
+
|
|
|
|
+ memset(f, 0, sizeof(struct alps_fields));
|
|
|
|
+ priv->decode_fields(f, packet, psmouse);
|
|
|
|
+ if (priv->multi_packet) {
|
|
|
|
+ /*
|
|
|
|
+ * Sometimes the first packet will indicate a multi-packet
|
|
|
|
+ * sequence, but sometimes the next multi-packet would not
|
|
|
|
+ * come. Check for this, and when it happens process the
|
|
|
|
+ * position packet as usual.
|
|
|
|
+ */
|
|
|
|
+ if (f->is_mp) {
|
|
|
|
+ /* Now process the 1st packet */
|
|
|
|
+ priv->decode_fields(f, priv->multi_data, psmouse);
|
|
|
|
+ } else {
|
|
|
|
+ priv->multi_packet = 0;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * "f.is_mp" would always be '0' after merging the 1st and 2nd packet.
|
|
|
|
+ * When it is set, it means 2nd packet comes without 1st packet come.
|
|
|
|
+ */
|
|
|
|
+ if (f->is_mp)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ /* Save the first packet */
|
|
|
|
+ if (!priv->multi_packet && f->first_mp) {
|
|
|
|
+ priv->multi_packet = 1;
|
|
|
|
+ memcpy(priv->multi_data, packet, sizeof(priv->multi_data));
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ priv->multi_packet = 0;
|
|
|
|
+
|
|
|
|
+ alps_report_mt_data(psmouse, (f->fingers <= 4) ? f->fingers : 4);
|
|
|
|
+
|
|
|
|
+ input_mt_report_finger_count(dev, f->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);
|
|
|
|
+
|
|
|
|
+ input_report_abs(dev, ABS_PRESSURE, f->pressure);
|
|
|
|
+ input_sync(dev);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static bool alps_is_valid_package_ss4_v2(struct psmouse *psmouse)
|
|
|
|
+{
|
|
|
|
+ if (psmouse->pktcnt == 4 && ((psmouse->packet[3] & 0x08) != 0x08))
|
|
|
|
+ return false;
|
|
|
|
+ if (psmouse->pktcnt == 6 && ((psmouse->packet[5] & 0x10) != 0x0))
|
|
|
|
+ return false;
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
static DEFINE_MUTEX(alps_mutex);
|
|
static DEFINE_MUTEX(alps_mutex);
|
|
|
|
|
|
static void alps_register_bare_ps2_mouse(struct work_struct *work)
|
|
static void alps_register_bare_ps2_mouse(struct work_struct *work)
|
|
@@ -1159,13 +1345,14 @@ static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
|
|
bool report_buttons)
|
|
bool report_buttons)
|
|
{
|
|
{
|
|
struct alps_data *priv = psmouse->private;
|
|
struct alps_data *priv = psmouse->private;
|
|
- struct input_dev *dev;
|
|
|
|
|
|
+ struct input_dev *dev, *dev2 = NULL;
|
|
|
|
|
|
/* Figure out which device to use to report the bare packet */
|
|
/* Figure out which device to use to report the bare packet */
|
|
if (priv->proto_version == ALPS_PROTO_V2 &&
|
|
if (priv->proto_version == ALPS_PROTO_V2 &&
|
|
(priv->flags & ALPS_DUALPOINT)) {
|
|
(priv->flags & ALPS_DUALPOINT)) {
|
|
/* On V2 devices the DualPoint Stick reports bare packets */
|
|
/* On V2 devices the DualPoint Stick reports bare packets */
|
|
dev = priv->dev2;
|
|
dev = priv->dev2;
|
|
|
|
+ dev2 = psmouse->dev;
|
|
} else if (unlikely(IS_ERR_OR_NULL(priv->dev3))) {
|
|
} else if (unlikely(IS_ERR_OR_NULL(priv->dev3))) {
|
|
/* Register dev3 mouse if we received PS/2 packet first time */
|
|
/* Register dev3 mouse if we received PS/2 packet first time */
|
|
if (!IS_ERR(priv->dev3))
|
|
if (!IS_ERR(priv->dev3))
|
|
@@ -1177,7 +1364,7 @@ static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
|
|
}
|
|
}
|
|
|
|
|
|
if (report_buttons)
|
|
if (report_buttons)
|
|
- alps_report_buttons(dev, NULL,
|
|
|
|
|
|
+ alps_report_buttons(dev, dev2,
|
|
packet[0] & 1, packet[0] & 2, packet[0] & 4);
|
|
packet[0] & 1, packet[0] & 2, packet[0] & 4);
|
|
|
|
|
|
input_report_rel(dev, REL_X,
|
|
input_report_rel(dev, REL_X,
|
|
@@ -1305,8 +1492,12 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
|
|
* a device connected to the external PS/2 port. Because bare PS/2
|
|
* a device connected to the external PS/2 port. Because bare PS/2
|
|
* protocol does not have enough constant bits to self-synchronize
|
|
* protocol does not have enough constant bits to self-synchronize
|
|
* properly we only do this if the device is fully synchronized.
|
|
* properly we only do this if the device is fully synchronized.
|
|
|
|
+ * Can not distinguish V8's first byte from PS/2 packet's
|
|
*/
|
|
*/
|
|
- if (!psmouse->out_of_sync_cnt && (psmouse->packet[0] & 0xc8) == 0x08) {
|
|
|
|
|
|
+ if (priv->proto_version != ALPS_PROTO_V8 &&
|
|
|
|
+ !psmouse->out_of_sync_cnt &&
|
|
|
|
+ (psmouse->packet[0] & 0xc8) == 0x08) {
|
|
|
|
+
|
|
if (psmouse->pktcnt == 3) {
|
|
if (psmouse->pktcnt == 3) {
|
|
alps_report_bare_ps2_packet(psmouse, psmouse->packet,
|
|
alps_report_bare_ps2_packet(psmouse, psmouse->packet,
|
|
true);
|
|
true);
|
|
@@ -1354,8 +1545,10 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
|
|
return PSMOUSE_BAD_DATA;
|
|
return PSMOUSE_BAD_DATA;
|
|
}
|
|
}
|
|
|
|
|
|
- if (priv->proto_version == ALPS_PROTO_V7 &&
|
|
|
|
- !alps_is_valid_package_v7(psmouse)) {
|
|
|
|
|
|
+ if ((priv->proto_version == ALPS_PROTO_V7 &&
|
|
|
|
+ !alps_is_valid_package_v7(psmouse)) ||
|
|
|
|
+ (priv->proto_version == ALPS_PROTO_V8 &&
|
|
|
|
+ !alps_is_valid_package_ss4_v2(psmouse))) {
|
|
psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
|
|
psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
|
|
psmouse->pktcnt - 1,
|
|
psmouse->pktcnt - 1,
|
|
psmouse->packet[psmouse->pktcnt - 1]);
|
|
psmouse->packet[psmouse->pktcnt - 1]);
|
|
@@ -2130,6 +2323,88 @@ error:
|
|
return -1;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int alps_get_otp_values_ss4_v2(struct psmouse *psmouse,
|
|
|
|
+ unsigned char index, unsigned char otp[])
|
|
|
|
+{
|
|
|
|
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
|
|
|
|
+
|
|
|
|
+ switch (index) {
|
|
|
|
+ case 0:
|
|
|
|
+ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
|
|
|
|
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
|
|
|
|
+ ps2_command(ps2dev, otp, PSMOUSE_CMD_GETINFO))
|
|
|
|
+ return -1;
|
|
|
|
+
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case 1:
|
|
|
|
+ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) ||
|
|
|
|
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) ||
|
|
|
|
+ ps2_command(ps2dev, otp, PSMOUSE_CMD_GETINFO))
|
|
|
|
+ return -1;
|
|
|
|
+
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int alps_update_device_area_ss4_v2(unsigned char otp[][4],
|
|
|
|
+ struct alps_data *priv)
|
|
|
|
+{
|
|
|
|
+ int num_x_electrode;
|
|
|
|
+ int num_y_electrode;
|
|
|
|
+ int x_pitch, y_pitch, x_phys, y_phys;
|
|
|
|
+
|
|
|
|
+ num_x_electrode = SS4_NUMSENSOR_XOFFSET + (otp[1][0] & 0x0F);
|
|
|
|
+ num_y_electrode = SS4_NUMSENSOR_YOFFSET + ((otp[1][0] >> 4) & 0x0F);
|
|
|
|
+
|
|
|
|
+ priv->x_max = (num_x_electrode - 1) * SS4_COUNT_PER_ELECTRODE;
|
|
|
|
+ priv->y_max = (num_y_electrode - 1) * SS4_COUNT_PER_ELECTRODE;
|
|
|
|
+
|
|
|
|
+ x_pitch = ((otp[1][2] >> 2) & 0x07) + SS4_MIN_PITCH_MM;
|
|
|
|
+ y_pitch = ((otp[1][2] >> 5) & 0x07) + SS4_MIN_PITCH_MM;
|
|
|
|
+
|
|
|
|
+ x_phys = x_pitch * (num_x_electrode - 1); /* In 0.1 mm units */
|
|
|
|
+ y_phys = y_pitch * (num_y_electrode - 1); /* In 0.1 mm units */
|
|
|
|
+
|
|
|
|
+ priv->x_res = priv->x_max * 10 / x_phys; /* units / mm */
|
|
|
|
+ priv->y_res = priv->y_max * 10 / y_phys; /* units / mm */
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int alps_update_btn_info_ss4_v2(unsigned char otp[][4],
|
|
|
|
+ struct alps_data *priv)
|
|
|
|
+{
|
|
|
|
+ unsigned char is_btnless;
|
|
|
|
+
|
|
|
|
+ is_btnless = (otp[1][1] >> 3) & 0x01;
|
|
|
|
+
|
|
|
|
+ if (is_btnless)
|
|
|
|
+ priv->flags |= ALPS_BUTTONPAD;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int alps_set_defaults_ss4_v2(struct psmouse *psmouse,
|
|
|
|
+ struct alps_data *priv)
|
|
|
|
+{
|
|
|
|
+ unsigned char otp[2][4];
|
|
|
|
+
|
|
|
|
+ memset(otp, 0, sizeof(otp));
|
|
|
|
+
|
|
|
|
+ if (alps_get_otp_values_ss4_v2(psmouse, 0, &otp[0][0]) ||
|
|
|
|
+ alps_get_otp_values_ss4_v2(psmouse, 1, &otp[1][0]))
|
|
|
|
+ return -1;
|
|
|
|
+
|
|
|
|
+ alps_update_device_area_ss4_v2(otp, priv);
|
|
|
|
+
|
|
|
|
+ alps_update_btn_info_ss4_v2(otp, priv);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static int alps_dolphin_get_device_area(struct psmouse *psmouse,
|
|
static int alps_dolphin_get_device_area(struct psmouse *psmouse,
|
|
struct alps_data *priv)
|
|
struct alps_data *priv)
|
|
{
|
|
{
|
|
@@ -2222,6 +2497,35 @@ error:
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int alps_hw_init_ss4_v2(struct psmouse *psmouse)
|
|
|
|
+{
|
|
|
|
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
|
|
|
|
+ char param[2] = {0x64, 0x28};
|
|
|
|
+ int ret = -1;
|
|
|
|
+
|
|
|
|
+ /* enter absolute mode */
|
|
|
|
+ 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)) {
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* T.B.D. Decread noise packet number, delete in the future */
|
|
|
|
+ if (alps_exit_command_mode(psmouse) ||
|
|
|
|
+ alps_enter_command_mode(psmouse) ||
|
|
|
|
+ alps_command_mode_write_reg(psmouse, 0x001D, 0x20)) {
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
+ alps_exit_command_mode(psmouse);
|
|
|
|
+
|
|
|
|
+ return ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
|
|
|
|
+
|
|
|
|
+error:
|
|
|
|
+ alps_exit_command_mode(psmouse);
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
static int alps_set_protocol(struct psmouse *psmouse,
|
|
static int alps_set_protocol(struct psmouse *psmouse,
|
|
struct alps_data *priv,
|
|
struct alps_data *priv,
|
|
const struct alps_protocol_info *protocol)
|
|
const struct alps_protocol_info *protocol)
|
|
@@ -2311,7 +2615,7 @@ static int alps_set_protocol(struct psmouse *psmouse,
|
|
priv->hw_init = alps_hw_init_v7;
|
|
priv->hw_init = alps_hw_init_v7;
|
|
priv->process_packet = alps_process_packet_v7;
|
|
priv->process_packet = alps_process_packet_v7;
|
|
priv->decode_fields = alps_decode_packet_v7;
|
|
priv->decode_fields = alps_decode_packet_v7;
|
|
- priv->set_abs_params = alps_set_abs_params_mt;
|
|
|
|
|
|
+ priv->set_abs_params = alps_set_abs_params_v7;
|
|
priv->nibble_commands = alps_v3_nibble_commands;
|
|
priv->nibble_commands = alps_v3_nibble_commands;
|
|
priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
|
|
priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
|
|
priv->x_max = 0xfff;
|
|
priv->x_max = 0xfff;
|
|
@@ -2321,6 +2625,19 @@ static int alps_set_protocol(struct psmouse *psmouse,
|
|
priv->flags |= ALPS_BUTTONPAD;
|
|
priv->flags |= ALPS_BUTTONPAD;
|
|
|
|
|
|
break;
|
|
break;
|
|
|
|
+
|
|
|
|
+ case ALPS_PROTO_V8:
|
|
|
|
+ priv->hw_init = alps_hw_init_ss4_v2;
|
|
|
|
+ priv->process_packet = alps_process_packet_ss4_v2;
|
|
|
|
+ priv->decode_fields = alps_decode_ss4_v2;
|
|
|
|
+ priv->set_abs_params = alps_set_abs_params_ss4_v2;
|
|
|
|
+ priv->nibble_commands = alps_v3_nibble_commands;
|
|
|
|
+ priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
|
|
|
|
+
|
|
|
|
+ if (alps_set_defaults_ss4_v2(psmouse, priv))
|
|
|
|
+ return -EIO;
|
|
|
|
+
|
|
|
|
+ break;
|
|
}
|
|
}
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
@@ -2389,6 +2706,9 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
|
|
} else if (ec[0] == 0x88 && ec[1] == 0x07 &&
|
|
} else if (ec[0] == 0x88 && ec[1] == 0x07 &&
|
|
ec[2] >= 0x90 && ec[2] <= 0x9d) {
|
|
ec[2] >= 0x90 && ec[2] <= 0x9d) {
|
|
protocol = &alps_v3_protocol_data;
|
|
protocol = &alps_v3_protocol_data;
|
|
|
|
+ } else if (e7[0] == 0x73 && e7[1] == 0x03 &&
|
|
|
|
+ e7[2] == 0x14 && ec[1] == 0x02) {
|
|
|
|
+ protocol = &alps_v8_protocol_data;
|
|
} else {
|
|
} else {
|
|
psmouse_dbg(psmouse,
|
|
psmouse_dbg(psmouse,
|
|
"Likely not an ALPS touchpad: E7=%3ph, EC=%3ph\n", e7, ec);
|
|
"Likely not an ALPS touchpad: E7=%3ph, EC=%3ph\n", e7, ec);
|
|
@@ -2437,10 +2757,11 @@ static void alps_set_abs_params_st(struct alps_data *priv,
|
|
{
|
|
{
|
|
input_set_abs_params(dev1, ABS_X, 0, priv->x_max, 0, 0);
|
|
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);
|
|
input_set_abs_params(dev1, ABS_Y, 0, priv->y_max, 0, 0);
|
|
|
|
+ input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
|
|
}
|
|
}
|
|
|
|
|
|
-static void alps_set_abs_params_mt(struct alps_data *priv,
|
|
|
|
- struct input_dev *dev1)
|
|
|
|
|
|
+static void alps_set_abs_params_mt_common(struct alps_data *priv,
|
|
|
|
+ struct input_dev *dev1)
|
|
{
|
|
{
|
|
input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, priv->x_max, 0, 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);
|
|
input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0);
|
|
@@ -2448,15 +2769,44 @@ static void alps_set_abs_params_mt(struct alps_data *priv,
|
|
input_abs_set_res(dev1, ABS_MT_POSITION_X, priv->x_res);
|
|
input_abs_set_res(dev1, ABS_MT_POSITION_X, priv->x_res);
|
|
input_abs_set_res(dev1, ABS_MT_POSITION_Y, priv->y_res);
|
|
input_abs_set_res(dev1, ABS_MT_POSITION_Y, priv->y_res);
|
|
|
|
|
|
- input_mt_init_slots(dev1, MAX_TOUCHES, INPUT_MT_POINTER |
|
|
|
|
- INPUT_MT_DROP_UNUSED | INPUT_MT_TRACK | INPUT_MT_SEMI_MT);
|
|
|
|
-
|
|
|
|
set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit);
|
|
set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit);
|
|
set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
|
|
set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void alps_set_abs_params_mt(struct alps_data *priv,
|
|
|
|
+ struct input_dev *dev1)
|
|
|
|
+{
|
|
|
|
+ alps_set_abs_params_mt_common(priv, dev1);
|
|
|
|
+ input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
|
|
|
|
+
|
|
|
|
+ input_mt_init_slots(dev1, MAX_TOUCHES,
|
|
|
|
+ INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED |
|
|
|
|
+ INPUT_MT_TRACK | INPUT_MT_SEMI_MT);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void alps_set_abs_params_v7(struct alps_data *priv,
|
|
|
|
+ struct input_dev *dev1)
|
|
|
|
+{
|
|
|
|
+ alps_set_abs_params_mt_common(priv, dev1);
|
|
|
|
+ set_bit(BTN_TOOL_QUINTTAP, dev1->keybit);
|
|
|
|
+
|
|
|
|
+ input_mt_init_slots(dev1, MAX_TOUCHES,
|
|
|
|
+ INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED |
|
|
|
|
+ INPUT_MT_TRACK);
|
|
|
|
+
|
|
|
|
+ set_bit(BTN_TOOL_QUINTTAP, dev1->keybit);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void alps_set_abs_params_ss4_v2(struct alps_data *priv,
|
|
|
|
+ struct input_dev *dev1)
|
|
|
|
+{
|
|
|
|
+ alps_set_abs_params_mt_common(priv, dev1);
|
|
|
|
+ input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
|
|
|
|
+ set_bit(BTN_TOOL_QUINTTAP, dev1->keybit);
|
|
|
|
|
|
- /* V7 is real multi-touch */
|
|
|
|
- if (priv->proto_version == ALPS_PROTO_V7)
|
|
|
|
- clear_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
|
|
|
|
|
|
+ input_mt_init_slots(dev1, MAX_TOUCHES,
|
|
|
|
+ INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED |
|
|
|
|
+ INPUT_MT_TRACK);
|
|
}
|
|
}
|
|
|
|
|
|
int alps_init(struct psmouse *psmouse)
|
|
int alps_init(struct psmouse *psmouse)
|
|
@@ -2489,9 +2839,6 @@ int alps_init(struct psmouse *psmouse)
|
|
dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS);
|
|
dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS);
|
|
|
|
|
|
priv->set_abs_params(priv, dev1);
|
|
priv->set_abs_params(priv, dev1);
|
|
- /* No pressure on V7 */
|
|
|
|
- if (priv->proto_version != ALPS_PROTO_V7)
|
|
|
|
- input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
|
|
|
|
|
|
|
|
if (priv->flags & ALPS_WHEEL) {
|
|
if (priv->flags & ALPS_WHEEL) {
|
|
dev1->evbit[BIT_WORD(EV_REL)] |= BIT_MASK(EV_REL);
|
|
dev1->evbit[BIT_WORD(EV_REL)] |= BIT_MASK(EV_REL);
|