summaryrefslogtreecommitdiff
path: root/drivers/input/mouse
diff options
context:
space:
mode:
authorAndré Fabian Silva Delgado <emulatorman@parabola.nu>2015-09-08 01:01:14 -0300
committerAndré Fabian Silva Delgado <emulatorman@parabola.nu>2015-09-08 01:01:14 -0300
commite5fd91f1ef340da553f7a79da9540c3db711c937 (patch)
treeb11842027dc6641da63f4bcc524f8678263304a3 /drivers/input/mouse
parent2a9b0348e685a63d97486f6749622b61e9e3292f (diff)
Linux-libre 4.2-gnu
Diffstat (limited to 'drivers/input/mouse')
-rw-r--r--drivers/input/mouse/alps.c244
-rw-r--r--drivers/input/mouse/alps.h1
-rw-r--r--drivers/input/mouse/bcm5974.c165
-rw-r--r--drivers/input/mouse/cyapa_gen3.c3
-rw-r--r--drivers/input/mouse/cyapa_gen5.c23
-rw-r--r--drivers/input/mouse/elan_i2c.h6
-rw-r--r--drivers/input/mouse/elan_i2c_core.c75
-rw-r--r--drivers/input/mouse/elan_i2c_i2c.c4
-rw-r--r--drivers/input/mouse/elan_i2c_smbus.c6
-rw-r--r--drivers/input/mouse/elantech.c35
-rw-r--r--drivers/input/mouse/elantech.h1
-rw-r--r--drivers/input/mouse/focaltech.c13
-rw-r--r--drivers/input/mouse/psmouse-base.c4
-rw-r--r--drivers/input/mouse/sentelic.h4
-rw-r--r--drivers/input/mouse/synaptics.c4
-rw-r--r--drivers/input/mouse/synaptics_i2c.c6
16 files changed, 369 insertions, 225 deletions
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index bc7eed679..4d246861d 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -161,8 +161,8 @@ static const struct alps_protocol_info alps_v8_protocol_data = {
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_semi_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,
@@ -312,53 +312,6 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
input_sync(dev);
}
-/*
- * Process bitmap data for V5 protocols. Return value is null.
- *
- * The bitmaps don't have enough data to track fingers, so this function
- * only generates points representing a bounding box of at most two contacts.
- * These two points are returned in fields->mt.
- */
-static void alps_process_bitmap_dolphin(struct alps_data *priv,
- struct alps_fields *fields)
-{
- int box_middle_x, box_middle_y;
- unsigned int x_map, y_map;
- unsigned char start_bit, end_bit;
- unsigned char x_msb, x_lsb, y_msb, y_lsb;
-
- x_map = fields->x_map;
- y_map = fields->y_map;
-
- if (!x_map || !y_map)
- return;
-
- /* Get Most-significant and Least-significant bit */
- x_msb = fls(x_map);
- x_lsb = ffs(x_map);
- y_msb = fls(y_map);
- y_lsb = ffs(y_map);
-
- /* Most-significant bit should never exceed max sensor line number */
- if (x_msb > priv->x_bits || y_msb > priv->y_bits)
- return;
-
- if (fields->fingers > 1) {
- start_bit = priv->x_bits - x_msb;
- end_bit = priv->x_bits - x_lsb;
- box_middle_x = (priv->x_max * (start_bit + end_bit)) /
- (2 * (priv->x_bits - 1));
-
- start_bit = y_lsb - 1;
- end_bit = y_msb - 1;
- box_middle_y = (priv->y_max * (start_bit + end_bit)) /
- (2 * (priv->y_bits - 1));
- fields->mt[0] = fields->st;
- fields->mt[1].x = 2 * box_middle_x - fields->mt[0].x;
- fields->mt[1].y = 2 * box_middle_y - fields->mt[0].y;
- }
-}
-
static void alps_get_bitmap_points(unsigned int map,
struct alps_bitmap_point *low,
struct alps_bitmap_point *high,
@@ -386,7 +339,7 @@ static void alps_get_bitmap_points(unsigned int map,
}
/*
- * Process bitmap data from v3 and v4 protocols. Returns the number of
+ * Process bitmap data from semi-mt protocols. Returns the number of
* fingers detected. A return value of 0 means at least one of the
* bitmaps was empty.
*
@@ -398,9 +351,10 @@ static void alps_get_bitmap_points(unsigned int map,
static int alps_process_bitmap(struct alps_data *priv,
struct alps_fields *fields)
{
- int i, fingers_x = 0, fingers_y = 0, fingers;
+ int i, fingers_x = 0, fingers_y = 0, fingers, closest;
struct alps_bitmap_point x_low = {0,}, x_high = {0,};
struct alps_bitmap_point y_low = {0,}, y_high = {0,};
+ struct input_mt_pos corner[4];
if (!fields->x_map || !fields->y_map)
return 0;
@@ -431,26 +385,76 @@ static int alps_process_bitmap(struct alps_data *priv,
y_high.num_bits = max(i, 1);
}
- fields->mt[0].x =
+ /* top-left corner */
+ corner[0].x =
(priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) /
(2 * (priv->x_bits - 1));
- fields->mt[0].y =
+ corner[0].y =
(priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) /
(2 * (priv->y_bits - 1));
- fields->mt[1].x =
+ /* top-right corner */
+ corner[1].x =
(priv->x_max * (2 * x_high.start_bit + x_high.num_bits - 1)) /
(2 * (priv->x_bits - 1));
- fields->mt[1].y =
+ corner[1].y =
+ (priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) /
+ (2 * (priv->y_bits - 1));
+
+ /* bottom-right corner */
+ corner[2].x =
+ (priv->x_max * (2 * x_high.start_bit + x_high.num_bits - 1)) /
+ (2 * (priv->x_bits - 1));
+ corner[2].y =
+ (priv->y_max * (2 * y_high.start_bit + y_high.num_bits - 1)) /
+ (2 * (priv->y_bits - 1));
+
+ /* bottom-left corner */
+ corner[3].x =
+ (priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) /
+ (2 * (priv->x_bits - 1));
+ corner[3].y =
(priv->y_max * (2 * y_high.start_bit + y_high.num_bits - 1)) /
(2 * (priv->y_bits - 1));
- /* y-bitmap order is reversed, except on rushmore */
- if (priv->proto_version != ALPS_PROTO_V3_RUSHMORE) {
- fields->mt[0].y = priv->y_max - fields->mt[0].y;
- fields->mt[1].y = priv->y_max - fields->mt[1].y;
+ /* x-bitmap order is reversed on v5 touchpads */
+ if (priv->proto_version == ALPS_PROTO_V5) {
+ for (i = 0; i < 4; i++)
+ corner[i].x = priv->x_max - corner[i].x;
+ }
+
+ /* y-bitmap order is reversed on v3 and v4 touchpads */
+ if (priv->proto_version == ALPS_PROTO_V3 ||
+ priv->proto_version == ALPS_PROTO_V4) {
+ for (i = 0; i < 4; i++)
+ corner[i].y = priv->y_max - corner[i].y;
+ }
+
+ /*
+ * We only select a corner for the second touch once per 2 finger
+ * touch sequence to avoid the chosen corner (and thus the coordinates)
+ * jumping around when the first touch is in the middle.
+ */
+ if (priv->second_touch == -1) {
+ /* Find corner closest to our st coordinates */
+ closest = 0x7fffffff;
+ for (i = 0; i < 4; i++) {
+ int dx = fields->st.x - corner[i].x;
+ int dy = fields->st.y - corner[i].y;
+ int distance = dx * dx + dy * dy;
+
+ if (distance < closest) {
+ priv->second_touch = i;
+ closest = distance;
+ }
+ }
+ /* And select the opposite corner to use for the 2nd touch */
+ priv->second_touch = (priv->second_touch + 2) % 4;
}
+ fields->mt[0] = fields->st;
+ fields->mt[1] = corner[priv->second_touch];
+
return fingers;
}
@@ -487,9 +491,14 @@ static void alps_report_semi_mt_data(struct psmouse *psmouse, int fingers)
f->mt[0].x = f->st.x;
f->mt[0].y = f->st.y;
fingers = f->pressure > 0 ? 1 : 0;
+ priv->second_touch = -1;
}
- alps_report_mt_data(psmouse, (fingers <= 2) ? fingers : 2);
+ if (fingers >= 1)
+ alps_set_slot(dev, 0, f->mt[0].x, f->mt[0].y);
+ if (fingers >= 2)
+ alps_set_slot(dev, 1, f->mt[1].x, f->mt[1].y);
+ input_mt_sync_frame(dev);
input_mt_report_finger_count(dev, fingers);
@@ -586,20 +595,22 @@ static int alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
f->first_mp = !!(p[4] & 0x40);
f->is_mp = !!(p[0] & 0x40);
- f->fingers = (p[5] & 0x3) + 1;
- f->x_map = ((p[4] & 0x7e) << 8) |
- ((p[1] & 0x7f) << 2) |
- ((p[0] & 0x30) >> 4);
- f->y_map = ((p[3] & 0x70) << 4) |
- ((p[2] & 0x7f) << 1) |
- (p[4] & 0x01);
-
- f->st.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
- ((p[0] & 0x30) >> 4);
- f->st.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
- f->pressure = p[5] & 0x7f;
+ if (f->is_mp) {
+ f->fingers = (p[5] & 0x3) + 1;
+ f->x_map = ((p[4] & 0x7e) << 8) |
+ ((p[1] & 0x7f) << 2) |
+ ((p[0] & 0x30) >> 4);
+ f->y_map = ((p[3] & 0x70) << 4) |
+ ((p[2] & 0x7f) << 1) |
+ (p[4] & 0x01);
+ } else {
+ f->st.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
+ ((p[0] & 0x30) >> 4);
+ f->st.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
+ f->pressure = p[5] & 0x7f;
- alps_decode_buttons_v3(f, p);
+ alps_decode_buttons_v3(f, p);
+ }
return 0;
}
@@ -607,13 +618,27 @@ static int alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
static int alps_decode_rushmore(struct alps_fields *f, unsigned char *p,
struct psmouse *psmouse)
{
- alps_decode_pinnacle(f, p, psmouse);
-
- /* Rushmore's packet decode has a bit difference with Pinnacle's */
+ f->first_mp = !!(p[4] & 0x40);
f->is_mp = !!(p[5] & 0x40);
- f->fingers = max((p[5] & 0x3), ((p[5] >> 2) & 0x3)) + 1;
- f->x_map |= (p[5] & 0x10) << 11;
- f->y_map |= (p[5] & 0x20) << 6;
+
+ if (f->is_mp) {
+ f->fingers = max((p[5] & 0x3), ((p[5] >> 2) & 0x3)) + 1;
+ f->x_map = ((p[5] & 0x10) << 11) |
+ ((p[4] & 0x7e) << 8) |
+ ((p[1] & 0x7f) << 2) |
+ ((p[0] & 0x30) >> 4);
+ f->y_map = ((p[5] & 0x20) << 6) |
+ ((p[3] & 0x70) << 4) |
+ ((p[2] & 0x7f) << 1) |
+ (p[4] & 0x01);
+ } else {
+ f->st.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
+ ((p[0] & 0x30) >> 4);
+ f->st.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
+ f->pressure = p[5] & 0x7f;
+
+ alps_decode_buttons_v3(f, p);
+ }
return 0;
}
@@ -682,30 +707,13 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
*/
if (f->is_mp) {
fingers = f->fingers;
- if (priv->proto_version == ALPS_PROTO_V3 ||
- priv->proto_version == ALPS_PROTO_V3_RUSHMORE) {
- if (alps_process_bitmap(priv, f) == 0)
- fingers = 0; /* Use st data */
-
- /* Now process position packet */
- priv->decode_fields(f, priv->multi_data,
- psmouse);
- } else {
- /*
- * Because Dolphin uses position packet's
- * coordinate data as Pt1 and uses it to
- * calculate Pt2, so we need to do position
- * packet decode first.
- */
- priv->decode_fields(f, priv->multi_data,
- psmouse);
-
- /*
- * Since Dolphin's finger number is reliable,
- * there is no need to compare with bmap_fn.
- */
- alps_process_bitmap_dolphin(priv, f);
- }
+ /*
+ * Bitmap processing uses position packet's coordinate
+ * data, so we need to do decode it first.
+ */
+ priv->decode_fields(f, priv->multi_data, psmouse);
+ if (alps_process_bitmap(priv, f) == 0)
+ fingers = 0; /* Use st data */
} else {
priv->multi_packet = 0;
}
@@ -867,6 +875,14 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
priv->multi_data[offset] = packet[6];
priv->multi_data[offset + 1] = packet[7];
+ f->left = !!(packet[4] & 0x01);
+ f->right = !!(packet[4] & 0x02);
+
+ f->st.x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) |
+ ((packet[0] & 0x30) >> 4);
+ f->st.y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f);
+ f->pressure = packet[5] & 0x7f;
+
if (++priv->multi_packet > 2) {
priv->multi_packet = 0;
@@ -881,14 +897,6 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
f->fingers = alps_process_bitmap(priv, f);
}
- f->left = !!(packet[4] & 0x01);
- f->right = !!(packet[4] & 0x02);
-
- f->st.x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) |
- ((packet[0] & 0x30) >> 4);
- f->st.y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f);
- f->pressure = packet[5] & 0x7f;
-
alps_report_semi_mt_data(psmouse, f->fingers);
}
@@ -2565,7 +2573,7 @@ static int alps_set_protocol(struct psmouse *psmouse,
case ALPS_PROTO_V3:
priv->hw_init = alps_hw_init_v3;
priv->process_packet = alps_process_packet_v3;
- priv->set_abs_params = alps_set_abs_params_mt;
+ priv->set_abs_params = alps_set_abs_params_semi_mt;
priv->decode_fields = alps_decode_pinnacle;
priv->nibble_commands = alps_v3_nibble_commands;
priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
@@ -2574,7 +2582,7 @@ static int alps_set_protocol(struct psmouse *psmouse,
case ALPS_PROTO_V3_RUSHMORE:
priv->hw_init = alps_hw_init_rushmore_v3;
priv->process_packet = alps_process_packet_v3;
- priv->set_abs_params = alps_set_abs_params_mt;
+ priv->set_abs_params = alps_set_abs_params_semi_mt;
priv->decode_fields = alps_decode_rushmore;
priv->nibble_commands = alps_v3_nibble_commands;
priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
@@ -2590,7 +2598,7 @@ static int alps_set_protocol(struct psmouse *psmouse,
case ALPS_PROTO_V4:
priv->hw_init = alps_hw_init_v4;
priv->process_packet = alps_process_packet_v4;
- priv->set_abs_params = alps_set_abs_params_mt;
+ priv->set_abs_params = alps_set_abs_params_semi_mt;
priv->nibble_commands = alps_v4_nibble_commands;
priv->addr_command = PSMOUSE_CMD_DISABLE;
break;
@@ -2599,7 +2607,7 @@ static int alps_set_protocol(struct psmouse *psmouse,
priv->hw_init = alps_hw_init_dolphin_v1;
priv->process_packet = alps_process_touchpad_packet_v3_v5;
priv->decode_fields = alps_decode_dolphin;
- priv->set_abs_params = alps_set_abs_params_mt;
+ priv->set_abs_params = alps_set_abs_params_semi_mt;
priv->nibble_commands = alps_v3_nibble_commands;
priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
priv->x_bits = 23;
@@ -2781,15 +2789,15 @@ static void alps_set_abs_params_mt_common(struct alps_data *priv,
set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
}
-static void alps_set_abs_params_mt(struct alps_data *priv,
- struct input_dev *dev1)
+static void alps_set_abs_params_semi_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);
+ INPUT_MT_SEMI_MT);
}
static void alps_set_abs_params_v7(struct alps_data *priv,
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index 6dfdccc3a..d37f814dc 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -278,6 +278,7 @@ struct alps_data {
int prev_fin;
int multi_packet;
+ int second_touch;
unsigned char multi_data[6];
struct alps_fields f;
u8 quirks;
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index b10709f04..30e344251 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -2,6 +2,7 @@
* Apple USB BCM5974 (Macbook Air and Penryn Macbook Pro) multitouch driver
*
* Copyright (C) 2008 Henrik Rydberg (rydberg@euromail.se)
+ * Copyright (C) 2015 John Horan (knasher@gmail.com)
*
* The USB initialization and package decoding was made by
* Scott Shawcroft as part of the touchd user-space driver project:
@@ -91,6 +92,10 @@
#define USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI 0x0290
#define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO 0x0291
#define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS 0x0292
+/* MacbookPro12,1 (2015) */
+#define USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI 0x0272
+#define USB_DEVICE_ID_APPLE_WELLSPRING9_ISO 0x0273
+#define USB_DEVICE_ID_APPLE_WELLSPRING9_JIS 0x0274
#define BCM5974_DEVICE(prod) { \
.match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \
@@ -152,6 +157,10 @@ static const struct usb_device_id bcm5974_table[] = {
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING8_ISO),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING8_JIS),
+ /* MacbookPro12,1 */
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING9_ISO),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING9_JIS),
/* Terminating entry */
{}
};
@@ -180,21 +189,47 @@ struct bt_data {
enum tp_type {
TYPE1, /* plain trackpad */
TYPE2, /* button integrated in trackpad */
- TYPE3 /* additional header fields since June 2013 */
+ TYPE3, /* additional header fields since June 2013 */
+ TYPE4 /* additional header field for pressure data */
};
/* trackpad finger data offsets, le16-aligned */
-#define FINGER_TYPE1 (13 * sizeof(__le16))
-#define FINGER_TYPE2 (15 * sizeof(__le16))
-#define FINGER_TYPE3 (19 * sizeof(__le16))
+#define HEADER_TYPE1 (13 * sizeof(__le16))
+#define HEADER_TYPE2 (15 * sizeof(__le16))
+#define HEADER_TYPE3 (19 * sizeof(__le16))
+#define HEADER_TYPE4 (23 * sizeof(__le16))
/* trackpad button data offsets */
+#define BUTTON_TYPE1 0
#define BUTTON_TYPE2 15
#define BUTTON_TYPE3 23
+#define BUTTON_TYPE4 31
/* list of device capability bits */
#define HAS_INTEGRATED_BUTTON 1
+/* trackpad finger data block size */
+#define FSIZE_TYPE1 (14 * sizeof(__le16))
+#define FSIZE_TYPE2 (14 * sizeof(__le16))
+#define FSIZE_TYPE3 (14 * sizeof(__le16))
+#define FSIZE_TYPE4 (15 * sizeof(__le16))
+
+/* offset from header to finger struct */
+#define DELTA_TYPE1 (0 * sizeof(__le16))
+#define DELTA_TYPE2 (0 * sizeof(__le16))
+#define DELTA_TYPE3 (0 * sizeof(__le16))
+#define DELTA_TYPE4 (1 * sizeof(__le16))
+
+/* usb control message mode switch data */
+#define USBMSG_TYPE1 8, 0x300, 0, 0, 0x1, 0x8
+#define USBMSG_TYPE2 8, 0x300, 0, 0, 0x1, 0x8
+#define USBMSG_TYPE3 8, 0x300, 0, 0, 0x1, 0x8
+#define USBMSG_TYPE4 2, 0x302, 2, 1, 0x1, 0x0
+
+/* Wellspring initialization constants */
+#define BCM5974_WELLSPRING_MODE_READ_REQUEST_ID 1
+#define BCM5974_WELLSPRING_MODE_WRITE_REQUEST_ID 9
+
/* trackpad finger structure, le16-aligned */
struct tp_finger {
__le16 origin; /* zero when switching track finger */
@@ -207,14 +242,13 @@ struct tp_finger {
__le16 orientation; /* 16384 when point, else 15 bit angle */
__le16 touch_major; /* touch area, major axis */
__le16 touch_minor; /* touch area, minor axis */
- __le16 unused[3]; /* zeros */
+ __le16 unused[2]; /* zeros */
+ __le16 pressure; /* pressure on forcetouch touchpad */
__le16 multi; /* one finger: varies, more fingers: constant */
} __attribute__((packed,aligned(2)));
/* trackpad finger data size, empirically at least ten fingers */
#define MAX_FINGERS 16
-#define SIZEOF_FINGER sizeof(struct tp_finger)
-#define SIZEOF_ALL_FINGERS (MAX_FINGERS * SIZEOF_FINGER)
#define MAX_FINGER_ORIENTATION 16384
/* device-specific parameters */
@@ -232,8 +266,17 @@ struct bcm5974_config {
int bt_datalen; /* data length of the button interface */
int tp_ep; /* the endpoint of the trackpad interface */
enum tp_type tp_type; /* type of trackpad interface */
- int tp_offset; /* offset to trackpad finger data */
+ int tp_header; /* bytes in header block */
int tp_datalen; /* data length of the trackpad interface */
+ int tp_button; /* offset to button data */
+ int tp_fsize; /* bytes in single finger block */
+ int tp_delta; /* offset from header to finger struct */
+ int um_size; /* usb control message length */
+ int um_req_val; /* usb control message value */
+ int um_req_idx; /* usb control message index */
+ int um_switch_idx; /* usb control message mode switch index */
+ int um_switch_on; /* usb control message mode switch on */
+ int um_switch_off; /* usb control message mode switch off */
struct bcm5974_param p; /* finger pressure limits */
struct bcm5974_param w; /* finger width limits */
struct bcm5974_param x; /* horizontal limits */
@@ -259,6 +302,24 @@ struct bcm5974 {
int slots[MAX_FINGERS]; /* slot assignments */
};
+/* trackpad finger block data, le16-aligned */
+static const struct tp_finger *get_tp_finger(const struct bcm5974 *dev, int i)
+{
+ const struct bcm5974_config *c = &dev->cfg;
+ u8 *f_base = dev->tp_data + c->tp_header + c->tp_delta;
+
+ return (const struct tp_finger *)(f_base + i * c->tp_fsize);
+}
+
+#define DATAFORMAT(type) \
+ type, \
+ HEADER_##type, \
+ HEADER_##type + (MAX_FINGERS) * (FSIZE_##type), \
+ BUTTON_##type, \
+ FSIZE_##type, \
+ DELTA_##type, \
+ USBMSG_##type
+
/* logical signal quality */
#define SN_PRESSURE 45 /* pressure signal-to-noise ratio */
#define SN_WIDTH 25 /* width signal-to-noise ratio */
@@ -273,7 +334,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
USB_DEVICE_ID_APPLE_WELLSPRING_JIS,
0,
0x84, sizeof(struct bt_data),
- 0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS,
+ 0x81, DATAFORMAT(TYPE1),
{ SN_PRESSURE, 0, 256 },
{ SN_WIDTH, 0, 2048 },
{ SN_COORD, -4824, 5342 },
@@ -286,7 +347,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
USB_DEVICE_ID_APPLE_WELLSPRING2_JIS,
0,
0x84, sizeof(struct bt_data),
- 0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS,
+ 0x81, DATAFORMAT(TYPE1),
{ SN_PRESSURE, 0, 256 },
{ SN_WIDTH, 0, 2048 },
{ SN_COORD, -4824, 4824 },
@@ -299,7 +360,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
USB_DEVICE_ID_APPLE_WELLSPRING3_JIS,
HAS_INTEGRATED_BUTTON,
0x84, sizeof(struct bt_data),
- 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+ 0x81, DATAFORMAT(TYPE2),
{ SN_PRESSURE, 0, 300 },
{ SN_WIDTH, 0, 2048 },
{ SN_COORD, -4460, 5166 },
@@ -312,7 +373,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
USB_DEVICE_ID_APPLE_WELLSPRING4_JIS,
HAS_INTEGRATED_BUTTON,
0x84, sizeof(struct bt_data),
- 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+ 0x81, DATAFORMAT(TYPE2),
{ SN_PRESSURE, 0, 300 },
{ SN_WIDTH, 0, 2048 },
{ SN_COORD, -4620, 5140 },
@@ -325,7 +386,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS,
HAS_INTEGRATED_BUTTON,
0x84, sizeof(struct bt_data),
- 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+ 0x81, DATAFORMAT(TYPE2),
{ SN_PRESSURE, 0, 300 },
{ SN_WIDTH, 0, 2048 },
{ SN_COORD, -4616, 5112 },
@@ -338,7 +399,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
USB_DEVICE_ID_APPLE_WELLSPRING5_JIS,
HAS_INTEGRATED_BUTTON,
0x84, sizeof(struct bt_data),
- 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+ 0x81, DATAFORMAT(TYPE2),
{ SN_PRESSURE, 0, 300 },
{ SN_WIDTH, 0, 2048 },
{ SN_COORD, -4415, 5050 },
@@ -351,7 +412,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
USB_DEVICE_ID_APPLE_WELLSPRING6_JIS,
HAS_INTEGRATED_BUTTON,
0x84, sizeof(struct bt_data),
- 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+ 0x81, DATAFORMAT(TYPE2),
{ SN_PRESSURE, 0, 300 },
{ SN_WIDTH, 0, 2048 },
{ SN_COORD, -4620, 5140 },
@@ -364,7 +425,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS,
HAS_INTEGRATED_BUTTON,
0x84, sizeof(struct bt_data),
- 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+ 0x81, DATAFORMAT(TYPE2),
{ SN_PRESSURE, 0, 300 },
{ SN_WIDTH, 0, 2048 },
{ SN_COORD, -4750, 5280 },
@@ -377,7 +438,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS,
HAS_INTEGRATED_BUTTON,
0x84, sizeof(struct bt_data),
- 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+ 0x81, DATAFORMAT(TYPE2),
{ SN_PRESSURE, 0, 300 },
{ SN_WIDTH, 0, 2048 },
{ SN_COORD, -4620, 5140 },
@@ -390,7 +451,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
USB_DEVICE_ID_APPLE_WELLSPRING7_JIS,
HAS_INTEGRATED_BUTTON,
0x84, sizeof(struct bt_data),
- 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+ 0x81, DATAFORMAT(TYPE2),
{ SN_PRESSURE, 0, 300 },
{ SN_WIDTH, 0, 2048 },
{ SN_COORD, -4750, 5280 },
@@ -403,7 +464,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS,
HAS_INTEGRATED_BUTTON,
0x84, sizeof(struct bt_data),
- 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+ 0x81, DATAFORMAT(TYPE2),
{ SN_PRESSURE, 0, 300 },
{ SN_WIDTH, 0, 2048 },
{ SN_COORD, -4750, 5280 },
@@ -416,13 +477,26 @@ static const struct bcm5974_config bcm5974_config_table[] = {
USB_DEVICE_ID_APPLE_WELLSPRING8_JIS,
HAS_INTEGRATED_BUTTON,
0, sizeof(struct bt_data),
- 0x83, TYPE3, FINGER_TYPE3, FINGER_TYPE3 + SIZEOF_ALL_FINGERS,
+ 0x83, DATAFORMAT(TYPE3),
{ SN_PRESSURE, 0, 300 },
{ SN_WIDTH, 0, 2048 },
{ SN_COORD, -4620, 5140 },
{ SN_COORD, -150, 6600 },
{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
},
+ {
+ USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI,
+ USB_DEVICE_ID_APPLE_WELLSPRING9_ISO,
+ USB_DEVICE_ID_APPLE_WELLSPRING9_JIS,
+ HAS_INTEGRATED_BUTTON,
+ 0, sizeof(struct bt_data),
+ 0x83, DATAFORMAT(TYPE4),
+ { SN_PRESSURE, 0, 300 },
+ { SN_WIDTH, 0, 2048 },
+ { SN_COORD, -4828, 5345 },
+ { SN_COORD, -203, 6803 },
+ { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
+ },
{}
};
@@ -549,19 +623,18 @@ static int report_tp_state(struct bcm5974 *dev, int size)
struct input_dev *input = dev->input;
int raw_n, i, n = 0;
- if (size < c->tp_offset || (size - c->tp_offset) % SIZEOF_FINGER != 0)
+ if (size < c->tp_header || (size - c->tp_header) % c->tp_fsize != 0)
return -EIO;
- /* finger data, le16-aligned */
- f = (const struct tp_finger *)(dev->tp_data + c->tp_offset);
- raw_n = (size - c->tp_offset) / SIZEOF_FINGER;
+ raw_n = (size - c->tp_header) / c->tp_fsize;
for (i = 0; i < raw_n; i++) {
- if (raw2int(f[i].touch_major) == 0)
+ f = get_tp_finger(dev, i);
+ if (raw2int(f->touch_major) == 0)
continue;
- dev->pos[n].x = raw2int(f[i].abs_x);
- dev->pos[n].y = c->y.min + c->y.max - raw2int(f[i].abs_y);
- dev->index[n++] = &f[i];
+ dev->pos[n].x = raw2int(f->abs_x);
+ dev->pos[n].y = c->y.min + c->y.max - raw2int(f->abs_y);
+ dev->index[n++] = f;
}
input_mt_assign_slots(input, dev->slots, dev->pos, n, 0);
@@ -572,32 +645,22 @@ static int report_tp_state(struct bcm5974 *dev, int size)
input_mt_sync_frame(input);
- report_synaptics_data(input, c, f, raw_n);
+ report_synaptics_data(input, c, get_tp_finger(dev, 0), raw_n);
- /* type 2 reports button events via ibt only */
- if (c->tp_type == TYPE2) {
- int ibt = raw2int(dev->tp_data[BUTTON_TYPE2]);
+ /* later types report button events via integrated button only */
+ if (c->caps & HAS_INTEGRATED_BUTTON) {
+ int ibt = raw2int(dev->tp_data[c->tp_button]);
input_report_key(input, BTN_LEFT, ibt);
}
- if (c->tp_type == TYPE3)
- input_report_key(input, BTN_LEFT, dev->tp_data[BUTTON_TYPE3]);
-
input_sync(input);
return 0;
}
-/* Wellspring initialization constants */
-#define BCM5974_WELLSPRING_MODE_READ_REQUEST_ID 1
-#define BCM5974_WELLSPRING_MODE_WRITE_REQUEST_ID 9
-#define BCM5974_WELLSPRING_MODE_REQUEST_VALUE 0x300
-#define BCM5974_WELLSPRING_MODE_REQUEST_INDEX 0
-#define BCM5974_WELLSPRING_MODE_VENDOR_VALUE 0x01
-#define BCM5974_WELLSPRING_MODE_NORMAL_VALUE 0x08
-
static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
{
+ const struct bcm5974_config *c = &dev->cfg;
int retval = 0, size;
char *data;
@@ -605,7 +668,7 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
if (dev->cfg.tp_type == TYPE3)
return 0;
- data = kmalloc(8, GFP_KERNEL);
+ data = kmalloc(c->um_size, GFP_KERNEL);
if (!data) {
dev_err(&dev->intf->dev, "out of memory\n");
retval = -ENOMEM;
@@ -616,28 +679,24 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
size = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
BCM5974_WELLSPRING_MODE_READ_REQUEST_ID,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- BCM5974_WELLSPRING_MODE_REQUEST_VALUE,
- BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000);
+ c->um_req_val, c->um_req_idx, data, c->um_size, 5000);
- if (size != 8) {
+ if (size != c->um_size) {
dev_err(&dev->intf->dev, "could not read from device\n");
retval = -EIO;
goto out;
}
/* apply the mode switch */
- data[0] = on ?
- BCM5974_WELLSPRING_MODE_VENDOR_VALUE :
- BCM5974_WELLSPRING_MODE_NORMAL_VALUE;
+ data[c->um_switch_idx] = on ? c->um_switch_on : c->um_switch_off;
/* write configuration */
size = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
BCM5974_WELLSPRING_MODE_WRITE_REQUEST_ID,
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- BCM5974_WELLSPRING_MODE_REQUEST_VALUE,
- BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000);
+ c->um_req_val, c->um_req_idx, data, c->um_size, 5000);
- if (size != 8) {
+ if (size != c->um_size) {
dev_err(&dev->intf->dev, "could not write to device\n");
retval = -EIO;
goto out;
diff --git a/drivers/input/mouse/cyapa_gen3.c b/drivers/input/mouse/cyapa_gen3.c
index 1e2291c37..3faf01c1b 100644
--- a/drivers/input/mouse/cyapa_gen3.c
+++ b/drivers/input/mouse/cyapa_gen3.c
@@ -950,14 +950,13 @@ static u16 cyapa_get_wait_time_for_pwr_cmd(u8 pwr_mode)
* Device power mode can only be set when device is in operational mode.
*/
static int cyapa_gen3_set_power_mode(struct cyapa *cyapa, u8 power_mode,
- u16 always_unused)
+ u16 always_unused)
{
int ret;
u8 power;
int tries;
u16 sleep_time;
- always_unused = 0;
if (cyapa->state != CYAPA_STATE_OP)
return 0;
diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c
index 5b611dd71..afc39e799 100644
--- a/drivers/input/mouse/cyapa_gen5.c
+++ b/drivers/input/mouse/cyapa_gen5.c
@@ -352,7 +352,7 @@ struct gen5_app_cmd_head {
u8 parameter_data[0]; /* Parameter data variable based on cmd_code */
} __packed;
-/* Applicaton get/set parameter command data structure */
+/* Application get/set parameter command data structure */
struct gen5_app_set_parameter_data {
u8 parameter_id;
u8 parameter_size;
@@ -832,7 +832,7 @@ static int gen5_hid_description_header_parse(struct cyapa *cyapa, u8 *reg_data)
int ret;
/* 0x20 0x00 0xF7 is Gen5 Application HID Description Header;
- * 0x20 0x00 0xFF is Gen5 Booloader HID Description Header.
+ * 0x20 0x00 0xFF is Gen5 Bootloader HID Description Header.
*
* Must read HID Description content through out,
* otherwise Gen5 trackpad cannot response next command
@@ -1654,8 +1654,8 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa,
* that trackpad unable to report signal to wake system up
* in the special situation that system is in suspending, and
* at the same time, user touch trackpad to wake system up.
- * This function can avoid the data to be buffured when system
- * is suspending which may cause interrput line unable to be
+ * This function can avoid the data to be buffered when system
+ * is suspending which may cause interrupt line unable to be
* asserted again.
*/
cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
@@ -2546,16 +2546,11 @@ static bool cyapa_gen5_irq_cmd_handler(struct cyapa *cyapa)
gen5_pip->resp_sort_func(cyapa,
gen5_pip->irq_cmd_buf, length))) {
/*
- * Cover the Gen5 V1 firmware issue.
- * The issue is there is no interrut will be
- * asserted to notityf host to read a command
- * data out when always has finger touch on
- * trackpad during the command is issued to
- * trackad device.
- * This issue has the scenario is that,
- * user always has his fingers touched on
- * trackpad device when booting/rebooting
- * their chrome book.
+ * Work around the Gen5 V1 firmware
+ * that does not assert interrupt signalling
+ * that command response is ready if user
+ * keeps touching the trackpad while command
+ * is sent to the device.
*/
length = 0;
if (gen5_pip->resp_len)
diff --git a/drivers/input/mouse/elan_i2c.h b/drivers/input/mouse/elan_i2c.h
index 9be9ebe40..8c8ea5680 100644
--- a/drivers/input/mouse/elan_i2c.h
+++ b/drivers/input/mouse/elan_i2c.h
@@ -28,14 +28,13 @@
#define ETP_PRESSURE_OFFSET 25
/* IAP Firmware handling */
+#define ETP_PRODUCT_ID_FORMAT_STRING "%d.0"
#define ETP_FW_NAME "/*(DEBLOBBED)*/"
#define ETP_IAP_START_ADDR 0x0083
#define ETP_FW_IAP_PAGE_ERR (1 << 5)
#define ETP_FW_IAP_INTF_ERR (1 << 4)
#define ETP_FW_PAGE_SIZE 64
-#define ETP_FW_VAILDPAGE_COUNT 768
#define ETP_FW_SIGNATURE_SIZE 6
-#define ETP_FW_SIGNATURE_ADDRESS 0xBFFA
struct i2c_client;
struct completion;
@@ -58,7 +57,8 @@ struct elan_transport_ops {
bool max_baseliune, u8 *value);
int (*get_version)(struct i2c_client *client, bool iap, u8 *version);
- int (*get_sm_version)(struct i2c_client *client, u8 *version);
+ int (*get_sm_version)(struct i2c_client *client,
+ u8* ic_type, u8 *version);
int (*get_checksum)(struct i2c_client *client, bool iap, u16 *csum);
int (*get_product_id)(struct i2c_client *client, u8 *id);
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index 7837ba0f8..4ca73013a 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -4,7 +4,7 @@
* Copyright (c) 2013 ELAN Microelectronics Corp.
*
* Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw>
- * Version: 1.5.7
+ * Version: 1.5.9
*
* Based on cyapa driver:
* copyright (c) 2011-2012 Cypress Semiconductor, Inc.
@@ -40,7 +40,7 @@
#include "elan_i2c.h"
#define DRIVER_NAME "elan_i2c"
-#define ELAN_DRIVER_VERSION "1.5.7"
+#define ELAN_DRIVER_VERSION "1.5.9"
#define ETP_MAX_PRESSURE 255
#define ETP_FWIDTH_REDUCE 90
#define ETP_FINGER_WIDTH 15
@@ -83,6 +83,9 @@ struct elan_tp_data {
u16 fw_checksum;
int pressure_adjustment;
u8 mode;
+ u8 ic_type;
+ u16 fw_vaildpage_count;
+ u16 fw_signature_address;
bool irq_wake;
@@ -91,6 +94,29 @@ struct elan_tp_data {
bool baseline_ready;
};
+static int elan_get_fwinfo(u8 ic_type, u16 *vaildpage_count,
+ u16 *signature_address)
+{
+ switch(ic_type) {
+ case 0x09:
+ *vaildpage_count = 768;
+ break;
+ case 0x0D:
+ *vaildpage_count = 896;
+ break;
+ default:
+ /* unknown ic type clear value */
+ *vaildpage_count = 0;
+ *signature_address = 0;
+ return -ENXIO;
+ }
+
+ *signature_address =
+ (*vaildpage_count * ETP_FW_PAGE_SIZE) - ETP_FW_SIGNATURE_SIZE;
+
+ return 0;
+}
+
static int elan_enable_power(struct elan_tp_data *data)
{
int repeat = ETP_RETRY_COUNT;
@@ -221,7 +247,8 @@ static int elan_query_device_info(struct elan_tp_data *data)
if (error)
return error;
- error = data->ops->get_sm_version(data->client, &data->sm_version);
+ error = data->ops->get_sm_version(data->client, &data->ic_type,
+ &data->sm_version);
if (error)
return error;
@@ -234,6 +261,14 @@ static int elan_query_device_info(struct elan_tp_data *data)
if (error)
return error;
+ error = elan_get_fwinfo(data->ic_type, &data->fw_vaildpage_count,
+ &data->fw_signature_address);
+ if (error) {
+ dev_err(&data->client->dev,
+ "unknown ic type %d\n", data->ic_type);
+ return error;
+ }
+
return 0;
}
@@ -318,7 +353,7 @@ static int __elan_update_firmware(struct elan_tp_data *data,
iap_start_addr = get_unaligned_le16(&fw->data[ETP_IAP_START_ADDR * 2]);
boot_page_count = (iap_start_addr * 2) / ETP_FW_PAGE_SIZE;
- for (i = boot_page_count; i < ETP_FW_VAILDPAGE_COUNT; i++) {
+ for (i = boot_page_count; i < data->fw_vaildpage_count; i++) {
u16 checksum = 0;
const u8 *page = &fw->data[i * ETP_FW_PAGE_SIZE];
@@ -403,7 +438,8 @@ static ssize_t elan_sysfs_read_product_id(struct device *dev,
struct i2c_client *client = to_i2c_client(dev);
struct elan_tp_data *data = i2c_get_clientdata(client);
- return sprintf(buf, "%d.0\n", data->product_id);
+ return sprintf(buf, ETP_PRODUCT_ID_FORMAT_STRING "\n",
+ data->product_id);
}
static ssize_t elan_sysfs_read_fw_ver(struct device *dev,
@@ -442,19 +478,28 @@ static ssize_t elan_sysfs_update_fw(struct device *dev,
{
struct elan_tp_data *data = dev_get_drvdata(dev);
const struct firmware *fw;
+ char *fw_name;
int error;
const u8 *fw_signature;
static const u8 signature[] = {0xAA, 0x55, 0xCC, 0x33, 0xFF, 0xFF};
- error = reject_firmware(&fw, ETP_FW_NAME, dev);
+ /* Look for a firmware with the product id appended. */
+ fw_name = kasprintf(GFP_KERNEL, ETP_FW_NAME, data->product_id);
+ if (!fw_name) {
+ dev_err(dev, "failed to allocate memory for firmware name\n");
+ return -ENOMEM;
+ }
+
+ dev_info(dev, "requesting fw '%s'\n", fw_name);
+ error = reject_firmware(&fw, fw_name, dev);
+ kfree(fw_name);
if (error) {
- dev_err(dev, "cannot load firmware %s: %d\n",
- ETP_FW_NAME, error);
+ dev_err(dev, "failed to request firmware: %d\n", error);
return error;
}
/* Firmware file must match signature data */
- fw_signature = &fw->data[ETP_FW_SIGNATURE_ADDRESS];
+ fw_signature = &fw->data[data->fw_signature_address];
if (memcmp(fw_signature, signature, sizeof(signature)) != 0) {
dev_err(dev, "signature mismatch (expected %*ph, got %*ph)\n",
(int)sizeof(signature), signature,
@@ -726,7 +771,7 @@ static const struct attribute_group *elan_sysfs_groups[] = {
*/
static void elan_report_contact(struct elan_tp_data *data,
int contact_num, bool contact_valid,
- bool hover_event, u8 *finger_data)
+ u8 *finger_data)
{
struct input_dev *input = data->input;
unsigned int pos_x, pos_y;
@@ -770,9 +815,7 @@ static void elan_report_contact(struct elan_tp_data *data,
input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
input_report_abs(input, ABS_MT_POSITION_X, pos_x);
input_report_abs(input, ABS_MT_POSITION_Y, data->max_y - pos_y);
- input_report_abs(input, ABS_MT_DISTANCE, hover_event);
- input_report_abs(input, ABS_MT_PRESSURE,
- hover_event ? 0 : scaled_pressure);
+ input_report_abs(input, ABS_MT_PRESSURE, scaled_pressure);
input_report_abs(input, ABS_TOOL_WIDTH, mk_x);
input_report_abs(input, ABS_MT_TOUCH_MAJOR, major);
input_report_abs(input, ABS_MT_TOUCH_MINOR, minor);
@@ -794,14 +837,14 @@ static void elan_report_absolute(struct elan_tp_data *data, u8 *packet)
hover_event = hover_info & 0x40;
for (i = 0; i < ETP_MAX_FINGERS; i++) {
contact_valid = tp_info & (1U << (3 + i));
- elan_report_contact(data, i, contact_valid, hover_event,
- finger_data);
+ elan_report_contact(data, i, contact_valid, finger_data);
if (contact_valid)
finger_data += ETP_FINGER_DATA_LEN;
}
input_report_key(input, BTN_LEFT, tp_info & 0x01);
+ input_report_abs(input, ABS_DISTANCE, hover_event != 0);
input_mt_report_pointer_emulation(input, true);
input_sync(input);
}
@@ -877,6 +920,7 @@ static int elan_setup_input_device(struct elan_tp_data *data)
input_abs_set_res(input, ABS_Y, data->y_res);
input_set_abs_params(input, ABS_PRESSURE, 0, ETP_MAX_PRESSURE, 0, 0);
input_set_abs_params(input, ABS_TOOL_WIDTH, 0, ETP_FINGER_WIDTH, 0, 0);
+ input_set_abs_params(input, ABS_DISTANCE, 0, 1, 0, 0);
/* And MT parameters */
input_set_abs_params(input, ABS_MT_POSITION_X, 0, data->max_x, 0, 0);
@@ -889,7 +933,6 @@ static int elan_setup_input_device(struct elan_tp_data *data)
ETP_FINGER_WIDTH * max_width, 0, 0);
input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0,
ETP_FINGER_WIDTH * min_width, 0, 0);
- input_set_abs_params(input, ABS_MT_DISTANCE, 0, 1, 0, 0);
data->input = input;
diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c
index a0acbbf83..683c840c9 100644
--- a/drivers/input/mouse/elan_i2c_i2c.c
+++ b/drivers/input/mouse/elan_i2c_i2c.c
@@ -259,7 +259,8 @@ static int elan_i2c_get_version(struct i2c_client *client,
return 0;
}
-static int elan_i2c_get_sm_version(struct i2c_client *client, u8 *version)
+static int elan_i2c_get_sm_version(struct i2c_client *client,
+ u8 *ic_type, u8 *version)
{
int error;
u8 val[3];
@@ -271,6 +272,7 @@ static int elan_i2c_get_sm_version(struct i2c_client *client, u8 *version)
}
*version = val[0];
+ *ic_type = val[1];
return 0;
}
diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c
index 30ab80dbc..ff36a366b 100644
--- a/drivers/input/mouse/elan_i2c_smbus.c
+++ b/drivers/input/mouse/elan_i2c_smbus.c
@@ -165,7 +165,8 @@ static int elan_smbus_get_version(struct i2c_client *client,
return 0;
}
-static int elan_smbus_get_sm_version(struct i2c_client *client, u8 *version)
+static int elan_smbus_get_sm_version(struct i2c_client *client,
+ u8 *ic_type, u8 *version)
{
int error;
u8 val[3];
@@ -177,7 +178,8 @@ static int elan_smbus_get_sm_version(struct i2c_client *client, u8 *version)
return error;
}
- *version = val[0]; /* XXX Why 0 and not 2 as in IAP/FW versions? */
+ *version = val[0];
+ *ic_type = val[1];
return 0;
}
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index ce3d40004..2955f1d0c 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -783,19 +783,26 @@ static int elantech_packet_check_v4(struct psmouse *psmouse)
struct elantech_data *etd = psmouse->private;
unsigned char *packet = psmouse->packet;
unsigned char packet_type = packet[3] & 0x03;
+ unsigned int ic_version;
bool sanity_check;
if (etd->tp_dev && (packet[3] & 0x0f) == 0x06)
return PACKET_TRACKPOINT;
+ /* This represents the version of IC body. */
+ ic_version = (etd->fw_version & 0x0f0000) >> 16;
+
/*
* Sanity check based on the constant bits of a packet.
* The constant bits change depending on the value of
- * the hardware flag 'crc_enabled' but are the same for
- * every packet, regardless of the type.
+ * the hardware flag 'crc_enabled' and the version of
+ * the IC body, but are the same for every packet,
+ * regardless of the type.
*/
if (etd->crc_enabled)
sanity_check = ((packet[3] & 0x08) == 0x00);
+ else if (ic_version == 7 && etd->samples[1] == 0x2A)
+ sanity_check = ((packet[3] & 0x1c) == 0x10);
else
sanity_check = ((packet[0] & 0x0c) == 0x04 &&
(packet[3] & 0x1c) == 0x10);
@@ -1116,6 +1123,7 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,
* Avatar AVIU-145A2 0x361f00 ? clickpad
* Fujitsu LIFEBOOK E544 0x470f00 d0, 12, 09 2 hw buttons
* Fujitsu LIFEBOOK E554 0x570f01 40, 14, 0c 2 hw buttons
+ * Fujitsu T725 0x470f01 05, 12, 09 2 hw buttons
* Fujitsu H730 0x570f00 c0, 14, 0c 3 hw buttons (**)
* Gigabyte U2442 0x450f01 58, 17, 0c 2 hw buttons
* Lenovo L430 0x350f02 b9, 15, 0c 2 hw buttons (*)
@@ -1167,7 +1175,7 @@ static int elantech_set_input_params(struct psmouse *psmouse)
struct input_dev *dev = psmouse->dev;
struct elantech_data *etd = psmouse->private;
unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0, width = 0;
- unsigned int x_res = 0, y_res = 0;
+ unsigned int x_res = 31, y_res = 31;
if (elantech_set_range(psmouse, &x_min, &y_min, &x_max, &y_max, &width))
return -1;
@@ -1232,8 +1240,6 @@ static int elantech_set_input_params(struct psmouse *psmouse)
/* For X to recognize me as touchpad. */
input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);
- input_abs_set_res(dev, ABS_X, x_res);
- input_abs_set_res(dev, ABS_Y, y_res);
/*
* range of pressure and width is the same as v2,
* report ABS_PRESSURE, ABS_TOOL_WIDTH for compatibility.
@@ -1246,8 +1252,6 @@ static int elantech_set_input_params(struct psmouse *psmouse)
input_mt_init_slots(dev, ETP_MAX_FINGERS, 0);
input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
- input_abs_set_res(dev, ABS_MT_POSITION_X, x_res);
- input_abs_set_res(dev, ABS_MT_POSITION_Y, y_res);
input_set_abs_params(dev, ABS_MT_PRESSURE, ETP_PMIN_V2,
ETP_PMAX_V2, 0, 0);
/*
@@ -1259,6 +1263,13 @@ static int elantech_set_input_params(struct psmouse *psmouse)
break;
}
+ input_abs_set_res(dev, ABS_X, x_res);
+ input_abs_set_res(dev, ABS_Y, y_res);
+ if (etd->hw_version > 1) {
+ input_abs_set_res(dev, ABS_MT_POSITION_X, x_res);
+ input_abs_set_res(dev, ABS_MT_POSITION_Y, y_res);
+ }
+
etd->y_max = y_max;
etd->width = width;
@@ -1648,6 +1659,16 @@ int elantech_init(struct psmouse *psmouse)
etd->capabilities[0], etd->capabilities[1],
etd->capabilities[2]);
+ if (etd->hw_version != 1) {
+ if (etd->send_cmd(psmouse, ETP_SAMPLE_QUERY, etd->samples)) {
+ psmouse_err(psmouse, "failed to query sample data\n");
+ goto init_fail;
+ }
+ psmouse_info(psmouse,
+ "Elan sample query result %02x, %02x, %02x\n",
+ etd->samples[0], etd->samples[1], etd->samples[2]);
+ }
+
if (elantech_set_absolute_mode(psmouse)) {
psmouse_err(psmouse,
"failed to put touchpad into absolute mode.\n");
diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
index f965d1569..e1cbf409d 100644
--- a/drivers/input/mouse/elantech.h
+++ b/drivers/input/mouse/elantech.h
@@ -129,6 +129,7 @@ struct elantech_data {
unsigned char reg_26;
unsigned char debug;
unsigned char capabilities[3];
+ unsigned char samples[3];
bool paritycheck;
bool jumpy_cursor;
bool reports_pressure;
diff --git a/drivers/input/mouse/focaltech.c b/drivers/input/mouse/focaltech.c
index 23d259416..4d5576de8 100644
--- a/drivers/input/mouse/focaltech.c
+++ b/drivers/input/mouse/focaltech.c
@@ -103,6 +103,16 @@ struct focaltech_hw_state {
*/
struct focaltech_finger_state fingers[FOC_MAX_FINGERS];
+ /*
+ * Finger width 0-7 and 15 for a very big contact area.
+ * 15 value stays until the finger is released.
+ * Width is reported only in absolute packets.
+ * Since hardware reports width only for last touching finger,
+ * there is no need to store width for every specific finger,
+ * so we keep only last value reported.
+ */
+ unsigned int width;
+
/* True if the clickpad has been pressed. */
bool pressed;
};
@@ -137,6 +147,7 @@ static void focaltech_report_state(struct psmouse *psmouse)
input_report_abs(dev, ABS_MT_POSITION_X, clamped_x);
input_report_abs(dev, ABS_MT_POSITION_Y,
priv->y_max - clamped_y);
+ input_report_abs(dev, ABS_TOOL_WIDTH, state->width);
}
}
input_mt_report_pointer_emulation(dev, true);
@@ -187,6 +198,7 @@ static void focaltech_process_abs_packet(struct psmouse *psmouse,
state->fingers[finger].x = ((packet[1] & 0xf) << 8) | packet[2];
state->fingers[finger].y = (packet[3] << 8) | packet[4];
+ state->width = packet[5] >> 4;
state->fingers[finger].valid = true;
}
@@ -331,6 +343,7 @@ static void focaltech_set_input_params(struct psmouse *psmouse)
__set_bit(EV_ABS, dev->evbit);
input_set_abs_params(dev, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0);
+ input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);
input_mt_init_slots(dev, 5, INPUT_MT_POINTER);
__set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
}
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 5bb1658f6..ec3477036 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -47,7 +47,7 @@ MODULE_LICENSE("GPL");
static unsigned int psmouse_max_proto = PSMOUSE_AUTO;
static int psmouse_set_maxproto(const char *val, const struct kernel_param *);
static int psmouse_get_maxproto(char *buffer, const struct kernel_param *kp);
-static struct kernel_param_ops param_ops_proto_abbrev = {
+static const struct kernel_param_ops param_ops_proto_abbrev = {
.set = psmouse_set_maxproto,
.get = psmouse_get_maxproto,
};
@@ -63,7 +63,7 @@ static unsigned int psmouse_rate = 100;
module_param_named(rate, psmouse_rate, uint, 0644);
MODULE_PARM_DESC(rate, "Report rate, in reports per second.");
-static bool psmouse_smartscroll = 1;
+static bool psmouse_smartscroll = true;
module_param_named(smartscroll, psmouse_smartscroll, bool, 0644);
MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
diff --git a/drivers/input/mouse/sentelic.h b/drivers/input/mouse/sentelic.h
index aa697ece4..42df9e3be 100644
--- a/drivers/input/mouse/sentelic.h
+++ b/drivers/input/mouse/sentelic.h
@@ -123,11 +123,11 @@ struct fsp_data {
extern int fsp_detect(struct psmouse *psmouse, bool set_properties);
extern int fsp_init(struct psmouse *psmouse);
#else
-inline int fsp_detect(struct psmouse *psmouse, bool set_properties)
+static inline int fsp_detect(struct psmouse *psmouse, bool set_properties)
{
return -ENOSYS;
}
-inline int fsp_init(struct psmouse *psmouse)
+static inline int fsp_init(struct psmouse *psmouse)
{
return -ENOSYS;
}
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 287208c45..e678212f1 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -1486,12 +1486,12 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode)
priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
psmouse_info(psmouse,
- "Touchpad model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx, board id: %lu, fw id: %lu\n",
+ "Touchpad model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx/%#lx, board id: %lu, fw id: %lu\n",
SYN_ID_MODEL(priv->identity),
SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity),
priv->model_id,
priv->capabilities, priv->ext_cap, priv->ext_cap_0c,
- priv->board_id, priv->firmware_id);
+ priv->ext_cap_10, priv->board_id, priv->firmware_id);
set_input_params(psmouse, priv);
diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c
index 878f18498..ffceedcaf 100644
--- a/drivers/input/mouse/synaptics_i2c.c
+++ b/drivers/input/mouse/synaptics_i2c.c
@@ -185,7 +185,7 @@
#define NO_DATA_SLEEP_MSECS (MSEC_PER_SEC / 4)
/* Control touchpad's No Deceleration option */
-static bool no_decel = 1;
+static bool no_decel = true;
module_param(no_decel, bool, 0644);
MODULE_PARM_DESC(no_decel, "No Deceleration. Default = 1 (on)");
@@ -340,9 +340,9 @@ static bool synaptics_i2c_get_input(struct synaptics_i2c *touch)
s32 data;
s8 x_delta, y_delta;
- /* Deal with spontanious resets and errors */
+ /* Deal with spontaneous resets and errors */
if (synaptics_i2c_check_error(touch->client))
- return 0;
+ return false;
/* Get Gesture Bit */
data = synaptics_i2c_reg_get(touch->client, DATA_REG0);