Merge branch 'next' into for-linus
Prepare first round of input updates for 4.1 merge window.
This commit is contained in:
@@ -153,10 +153,18 @@ static const struct alps_protocol_info alps_v7_protocol_data = {
|
||||
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,
|
||||
struct input_dev *dev1);
|
||||
static void alps_set_abs_params_mt(struct alps_data *priv,
|
||||
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 */
|
||||
|
||||
@@ -1093,6 +1101,176 @@ static void alps_process_packet_v7(struct psmouse *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 void alps_register_bare_ps2_mouse(struct work_struct *work)
|
||||
@@ -1314,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
|
||||
* protocol does not have enough constant bits to self-synchronize
|
||||
* 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) {
|
||||
alps_report_bare_ps2_packet(psmouse, psmouse->packet,
|
||||
true);
|
||||
@@ -1363,8 +1545,10 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
|
||||
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->pktcnt - 1,
|
||||
psmouse->packet[psmouse->pktcnt - 1]);
|
||||
@@ -2139,6 +2323,88 @@ error:
|
||||
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,
|
||||
struct alps_data *priv)
|
||||
{
|
||||
@@ -2231,6 +2497,35 @@ error:
|
||||
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,
|
||||
struct alps_data *priv,
|
||||
const struct alps_protocol_info *protocol)
|
||||
@@ -2320,7 +2615,7 @@ static int alps_set_protocol(struct psmouse *psmouse,
|
||||
priv->hw_init = alps_hw_init_v7;
|
||||
priv->process_packet = alps_process_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->addr_command = PSMOUSE_CMD_RESET_WRAP;
|
||||
priv->x_max = 0xfff;
|
||||
@@ -2330,6 +2625,19 @@ static int alps_set_protocol(struct psmouse *psmouse,
|
||||
priv->flags |= ALPS_BUTTONPAD;
|
||||
|
||||
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;
|
||||
@@ -2398,6 +2706,9 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
|
||||
} else if (ec[0] == 0x88 && ec[1] == 0x07 &&
|
||||
ec[2] >= 0x90 && ec[2] <= 0x9d) {
|
||||
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 {
|
||||
psmouse_dbg(psmouse,
|
||||
"Likely not an ALPS touchpad: E7=%3ph, EC=%3ph\n", e7, ec);
|
||||
@@ -2446,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_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_Y, 0, priv->y_max, 0, 0);
|
||||
@@ -2457,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_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_QUADTAP, dev1->keybit);
|
||||
}
|
||||
|
||||
/* V7 is real multi-touch */
|
||||
if (priv->proto_version == ALPS_PROTO_V7)
|
||||
clear_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
|
||||
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);
|
||||
|
||||
input_mt_init_slots(dev1, MAX_TOUCHES,
|
||||
INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED |
|
||||
INPUT_MT_TRACK);
|
||||
}
|
||||
|
||||
int alps_init(struct psmouse *psmouse)
|
||||
@@ -2498,9 +2839,6 @@ int alps_init(struct psmouse *psmouse)
|
||||
dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS);
|
||||
|
||||
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) {
|
||||
dev1->evbit[BIT_WORD(EV_REL)] |= BIT_MASK(EV_REL);
|
||||
|
@@ -22,13 +22,89 @@
|
||||
#define ALPS_PROTO_V5 0x500
|
||||
#define ALPS_PROTO_V6 0x600
|
||||
#define ALPS_PROTO_V7 0x700 /* t3btl t4s */
|
||||
#define ALPS_PROTO_V8 0x800 /* SS4btl SS4s */
|
||||
|
||||
#define MAX_TOUCHES 2
|
||||
#define MAX_TOUCHES 4
|
||||
|
||||
#define DOLPHIN_COUNT_PER_ELECTRODE 64
|
||||
#define DOLPHIN_PROFILE_XOFFSET 8 /* x-electrode offset */
|
||||
#define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode offset */
|
||||
|
||||
/*
|
||||
* enum SS4_PACKET_ID - defines the packet type for V8
|
||||
* SS4_PACKET_ID_IDLE: There's no finger and no button activity.
|
||||
* SS4_PACKET_ID_ONE: There's one finger on touchpad
|
||||
* or there's button activities.
|
||||
* SS4_PACKET_ID_TWO: There's two or more fingers on touchpad
|
||||
* SS4_PACKET_ID_MULTI: There's three or more fingers on touchpad
|
||||
*/
|
||||
enum SS4_PACKET_ID {
|
||||
SS4_PACKET_ID_IDLE = 0,
|
||||
SS4_PACKET_ID_ONE,
|
||||
SS4_PACKET_ID_TWO,
|
||||
SS4_PACKET_ID_MULTI,
|
||||
};
|
||||
|
||||
#define SS4_COUNT_PER_ELECTRODE 256
|
||||
#define SS4_NUMSENSOR_XOFFSET 7
|
||||
#define SS4_NUMSENSOR_YOFFSET 7
|
||||
#define SS4_MIN_PITCH_MM 50
|
||||
|
||||
#define SS4_MASK_NORMAL_BUTTONS 0x07
|
||||
|
||||
#define SS4_1F_X_V2(_b) ((_b[0] & 0x0007) | \
|
||||
((_b[1] << 3) & 0x0078) | \
|
||||
((_b[1] << 2) & 0x0380) | \
|
||||
((_b[2] << 5) & 0x1C00) \
|
||||
)
|
||||
|
||||
#define SS4_1F_Y_V2(_b) (((_b[2]) & 0x000F) | \
|
||||
((_b[3] >> 2) & 0x0030) | \
|
||||
((_b[4] << 6) & 0x03C0) | \
|
||||
((_b[4] << 5) & 0x0C00) \
|
||||
)
|
||||
|
||||
#define SS4_1F_Z_V2(_b) (((_b[5]) & 0x0F) | \
|
||||
((_b[5] >> 1) & 0x70) | \
|
||||
((_b[4]) & 0x80) \
|
||||
)
|
||||
|
||||
#define SS4_1F_LFB_V2(_b) (((_b[2] >> 4) & 0x01) == 0x01)
|
||||
|
||||
#define SS4_MF_LF_V2(_b, _i) ((_b[1 + (_i) * 3] & 0x0004) == 0x0004)
|
||||
|
||||
#define SS4_BTN_V2(_b) ((_b[0] >> 5) & SS4_MASK_NORMAL_BUTTONS)
|
||||
|
||||
#define SS4_STD_MF_X_V2(_b, _i) (((_b[0 + (_i) * 3] << 5) & 0x00E0) | \
|
||||
((_b[1 + _i * 3] << 5) & 0x1F00) \
|
||||
)
|
||||
|
||||
#define SS4_STD_MF_Y_V2(_b, _i) (((_b[1 + (_i) * 3] << 3) & 0x0010) | \
|
||||
((_b[2 + (_i) * 3] << 5) & 0x01E0) | \
|
||||
((_b[2 + (_i) * 3] << 4) & 0x0E00) \
|
||||
)
|
||||
|
||||
#define SS4_BTL_MF_X_V2(_b, _i) (SS4_STD_MF_X_V2(_b, _i) | \
|
||||
((_b[0 + (_i) * 3] >> 3) & 0x0010) \
|
||||
)
|
||||
|
||||
#define SS4_BTL_MF_Y_V2(_b, _i) (SS4_STD_MF_Y_V2(_b, _i) | \
|
||||
((_b[0 + (_i) * 3] >> 3) & 0x0008) \
|
||||
)
|
||||
|
||||
#define SS4_MF_Z_V2(_b, _i) (((_b[1 + (_i) * 3]) & 0x0001) | \
|
||||
((_b[1 + (_i) * 3] >> 1) & 0x0002) \
|
||||
)
|
||||
|
||||
#define SS4_IS_MF_CONTINUE(_b) ((_b[2] & 0x10) == 0x10)
|
||||
#define SS4_IS_5F_DETECTED(_b) ((_b[2] & 0x10) == 0x10)
|
||||
|
||||
|
||||
#define SS4_MFPACKET_NO_AX 8160 /* X-Coordinate value */
|
||||
#define SS4_MFPACKET_NO_AY 4080 /* Y-Coordinate value */
|
||||
#define SS4_MFPACKET_NO_AX_BL 8176 /* Buttonless X-Coordinate value */
|
||||
#define SS4_MFPACKET_NO_AY_BL 4088 /* Buttonless Y-Coordinate value */
|
||||
|
||||
/*
|
||||
* enum V7_PACKET_ID - defines the packet type for V7
|
||||
* V7_PACKET_ID_IDLE: There's no finger and no button activity.
|
||||
|
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
#ifndef _ELAN_I2C_H
|
||||
#define _ELAN_i2C_H
|
||||
#define _ELAN_I2C_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
|
@@ -99,7 +99,7 @@ static int elan_enable_power(struct elan_tp_data *data)
|
||||
error = regulator_enable(data->vcc);
|
||||
if (error) {
|
||||
dev_err(&data->client->dev,
|
||||
"Failed to enable regulator: %d\n", error);
|
||||
"failed to enable regulator: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -111,6 +111,7 @@ static int elan_enable_power(struct elan_tp_data *data)
|
||||
msleep(30);
|
||||
} while (--repeat > 0);
|
||||
|
||||
dev_err(&data->client->dev, "failed to enable power: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -125,7 +126,7 @@ static int elan_disable_power(struct elan_tp_data *data)
|
||||
error = regulator_disable(data->vcc);
|
||||
if (error) {
|
||||
dev_err(&data->client->dev,
|
||||
"Failed to disable regulator: %d\n",
|
||||
"failed to disable regulator: %d\n",
|
||||
error);
|
||||
/* Attempt to power the chip back up */
|
||||
data->ops->power_control(data->client, true);
|
||||
@@ -138,6 +139,7 @@ static int elan_disable_power(struct elan_tp_data *data)
|
||||
msleep(30);
|
||||
} while (--repeat > 0);
|
||||
|
||||
dev_err(&data->client->dev, "failed to disable power: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -196,7 +198,6 @@ static int elan_initialize(struct elan_tp_data *data)
|
||||
if (!error)
|
||||
return 0;
|
||||
|
||||
repeat--;
|
||||
msleep(30);
|
||||
} while (--repeat > 0);
|
||||
|
||||
@@ -1084,16 +1085,18 @@ static int __maybe_unused elan_resume(struct device *dev)
|
||||
}
|
||||
|
||||
error = elan_enable_power(data);
|
||||
if (error)
|
||||
if (error) {
|
||||
dev_err(dev, "power up when resuming failed: %d\n", error);
|
||||
goto err;
|
||||
}
|
||||
|
||||
error = elan_initialize(data);
|
||||
if (error)
|
||||
dev_err(dev, "initialize when resuming failed: %d\n", error);
|
||||
|
||||
err:
|
||||
enable_irq(data->client->irq);
|
||||
|
||||
return 0;
|
||||
return error;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(elan_pm_ops, elan_suspend, elan_resume);
|
||||
|
@@ -117,7 +117,15 @@ static int elan_i2c_write_cmd(struct i2c_client *client, u16 reg, u16 cmd)
|
||||
int ret;
|
||||
|
||||
ret = i2c_transfer(client->adapter, &msg, 1);
|
||||
return ret == 1 ? 0 : (ret < 0 ? ret : -EIO);
|
||||
if (ret != 1) {
|
||||
if (ret >= 0)
|
||||
ret = -EIO;
|
||||
dev_err(&client->dev, "writing cmd (0x%04x) failed: %d\n",
|
||||
reg, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int elan_i2c_initialize(struct i2c_client *client)
|
||||
|
@@ -256,8 +256,8 @@ static void lifebook_disconnect(struct psmouse *psmouse)
|
||||
|
||||
int lifebook_detect(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
if (!lifebook_present)
|
||||
return -1;
|
||||
if (!lifebook_present)
|
||||
return -1;
|
||||
|
||||
if (desired_serio_phys &&
|
||||
strcmp(psmouse->ps2dev.serio->phys, desired_serio_phys))
|
||||
@@ -268,7 +268,7 @@ int lifebook_detect(struct psmouse *psmouse, bool set_properties)
|
||||
psmouse->name = "Lifebook TouchScreen";
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lifebook_create_relative_device(struct psmouse *psmouse)
|
||||
|
@@ -474,19 +474,45 @@ static int psmouse_poll(struct psmouse *psmouse)
|
||||
PSMOUSE_CMD_POLL | (psmouse->pktsize << 8));
|
||||
}
|
||||
|
||||
static bool psmouse_check_pnp_id(const char *id, const char * const ids[])
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; ids[i]; i++)
|
||||
if (!strcasecmp(id, ids[i]))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* psmouse_matches_pnp_id - check if psmouse matches one of the passed in ids.
|
||||
*/
|
||||
bool psmouse_matches_pnp_id(struct psmouse *psmouse, const char * const ids[])
|
||||
{
|
||||
int i;
|
||||
struct serio *serio = psmouse->ps2dev.serio;
|
||||
char *p, *fw_id_copy, *save_ptr;
|
||||
bool found = false;
|
||||
|
||||
if (!strncmp(psmouse->ps2dev.serio->firmware_id, "PNP:", 4))
|
||||
for (i = 0; ids[i]; i++)
|
||||
if (strstr(psmouse->ps2dev.serio->firmware_id, ids[i]))
|
||||
return true;
|
||||
if (strncmp(serio->firmware_id, "PNP: ", 5))
|
||||
return false;
|
||||
|
||||
return false;
|
||||
fw_id_copy = kstrndup(&serio->firmware_id[5],
|
||||
sizeof(serio->firmware_id) - 5,
|
||||
GFP_KERNEL);
|
||||
if (!fw_id_copy)
|
||||
return false;
|
||||
|
||||
save_ptr = fw_id_copy;
|
||||
while ((p = strsep(&fw_id_copy, " ")) != NULL) {
|
||||
if (psmouse_check_pnp_id(p, ids)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
kfree(save_ptr);
|
||||
return found;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -67,6 +67,9 @@
|
||||
#define X_MAX_POSITIVE 8176
|
||||
#define Y_MAX_POSITIVE 8176
|
||||
|
||||
/* maximum ABS_MT_POSITION displacement (in mm) */
|
||||
#define DMAX 10
|
||||
|
||||
/*****************************************************************************
|
||||
* Stuff we need even when we do not want native Synaptics support
|
||||
****************************************************************************/
|
||||
@@ -203,6 +206,13 @@ static const char * const topbuttonpad_pnp_ids[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
/* This list has been kindly provided by Synaptics. */
|
||||
static const char * const forcepad_pnp_ids[] = {
|
||||
"SYN300D",
|
||||
"SYN3014",
|
||||
NULL
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
* Synaptics communications functions
|
||||
****************************************************************************/
|
||||
@@ -687,8 +697,6 @@ static void synaptics_parse_ext_buttons(const unsigned char buf[],
|
||||
hw->ext_buttons |= (buf[5] & ext_mask) << ext_bits;
|
||||
}
|
||||
|
||||
static bool is_forcepad;
|
||||
|
||||
static int synaptics_parse_hw_state(const unsigned char buf[],
|
||||
struct synaptics_data *priv,
|
||||
struct synaptics_hw_state *hw)
|
||||
@@ -718,7 +726,7 @@ static int synaptics_parse_hw_state(const unsigned char buf[],
|
||||
hw->left = (buf[0] & 0x01) ? 1 : 0;
|
||||
hw->right = (buf[0] & 0x02) ? 1 : 0;
|
||||
|
||||
if (is_forcepad) {
|
||||
if (priv->is_forcepad) {
|
||||
/*
|
||||
* ForcePads, like Clickpads, use middle button
|
||||
* bits to report primary button clicks.
|
||||
@@ -917,7 +925,7 @@ static void synaptics_report_mt_data(struct psmouse *psmouse,
|
||||
pos[i].y = synaptics_invert_y(hw[i]->y);
|
||||
}
|
||||
|
||||
input_mt_assign_slots(dev, slot, pos, nsemi, 0);
|
||||
input_mt_assign_slots(dev, slot, pos, nsemi, DMAX * priv->x_res);
|
||||
|
||||
for (i = 0; i < nsemi; i++) {
|
||||
input_mt_slot(dev, slot[i]);
|
||||
@@ -1186,7 +1194,7 @@ static void set_input_params(struct psmouse *psmouse,
|
||||
ABS_MT_POSITION_Y);
|
||||
/* Image sensors can report per-contact pressure */
|
||||
input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
|
||||
input_mt_init_slots(dev, 2, INPUT_MT_POINTER | INPUT_MT_TRACK);
|
||||
input_mt_init_slots(dev, 3, INPUT_MT_POINTER | INPUT_MT_TRACK);
|
||||
|
||||
/* Image sensors can signal 4 and 5 finger clicks */
|
||||
__set_bit(BTN_TOOL_QUADTAP, dev->keybit);
|
||||
@@ -1418,29 +1426,11 @@ static const struct dmi_system_id __initconst cr48_dmi_table[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct dmi_system_id forcepad_dmi_table[] __initconst = {
|
||||
#if defined(CONFIG_DMI) && defined(CONFIG_X86)
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook Folio 1040 G1"),
|
||||
},
|
||||
},
|
||||
#endif
|
||||
{ }
|
||||
};
|
||||
|
||||
void __init synaptics_module_init(void)
|
||||
{
|
||||
impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table);
|
||||
broken_olpc_ec = dmi_check_system(olpc_dmi_table);
|
||||
cr48_profile_sensor = dmi_check_system(cr48_dmi_table);
|
||||
|
||||
/*
|
||||
* Unfortunately ForcePad capability is not exported over PS/2,
|
||||
* so we have to resort to checking DMI.
|
||||
*/
|
||||
is_forcepad = dmi_check_system(forcepad_dmi_table);
|
||||
}
|
||||
|
||||
static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode)
|
||||
@@ -1475,6 +1465,12 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode)
|
||||
if (SYN_ID_DISGEST_SUPPORTED(priv->identity))
|
||||
priv->disable_gesture = true;
|
||||
|
||||
/*
|
||||
* Unfortunately ForcePad capability is not exported over PS/2,
|
||||
* so we have to resort to checking PNP IDs.
|
||||
*/
|
||||
priv->is_forcepad = psmouse_matches_pnp_id(psmouse, forcepad_pnp_ids);
|
||||
|
||||
if (synaptics_set_mode(psmouse)) {
|
||||
psmouse_err(psmouse, "Unable to initialize device.\n");
|
||||
goto init_fail;
|
||||
|
@@ -196,6 +196,7 @@ struct synaptics_data {
|
||||
unsigned long press_start;
|
||||
bool press;
|
||||
bool report_press;
|
||||
bool is_forcepad;
|
||||
};
|
||||
|
||||
void synaptics_module_init(void);
|
||||
|
Reference in New Issue
Block a user