diff --git a/Input-ALPS-add-support-for-Dolphin-devices.patch b/Input-ALPS-add-support-for-Dolphin-devices.patch new file mode 100644 index 000000000..1bdc0cbf8 --- /dev/null +++ b/Input-ALPS-add-support-for-Dolphin-devices.patch @@ -0,0 +1,348 @@ +Bugzilla: 953211 +Upstream-status: Queued for 3.14 + +From 4081924b7b6ce876fdb8e8049f1a5ba9c1496483 Mon Sep 17 00:00:00 2001 +From: Yunkang Tang +Date: Thu, 26 Dec 2013 14:54:19 -0800 +Subject: [PATCH] Input: ALPS - add support for "Dolphin" devices + +This adds support for another flavor of ALPS protocol used in newer +"Dolphin" devices. + +Signed-off-by: Yunkang Tang +Signed-off-by: Dmitry Torokhov +--- + drivers/input/mouse/alps.c | 214 ++++++++++++++++++++++++++++++++++++--------- + drivers/input/mouse/alps.h | 7 +- + 2 files changed, 179 insertions(+), 42 deletions(-) + +diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c +index 5cf62e3..fb15c64 100644 +--- a/drivers/input/mouse/alps.c ++++ b/drivers/input/mouse/alps.c +@@ -277,6 +277,57 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse) + } + + /* ++ * 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 x1, y1, x2, and y2. ++ */ ++static void alps_process_bitmap_dolphin(struct alps_data *priv, ++ struct alps_fields *fields, ++ int *x1, int *y1, int *x2, int *y2) ++{ ++ 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; ++ ++ *x1 = *y1 = *x2 = *y2 = 0; ++ ++ 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)); ++ *x1 = fields->x; ++ *y1 = fields->y; ++ *x2 = 2 * box_middle_x - *x1; ++ *y2 = 2 * box_middle_y - *y1; ++ } ++} ++ ++/* + * Process bitmap data from v3 and v4 protocols. Returns the number of + * fingers detected. A return value of 0 means at least one of the + * bitmaps was empty. +@@ -481,7 +532,8 @@ static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p) + f->ts_middle = !!(p[3] & 0x40); + } + +-static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p) ++static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p, ++ struct psmouse *psmouse) + { + f->first_mp = !!(p[4] & 0x40); + f->is_mp = !!(p[0] & 0x40); +@@ -502,48 +554,61 @@ static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p) + alps_decode_buttons_v3(f, p); + } + +-static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p) ++static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p, ++ struct psmouse *psmouse) + { +- alps_decode_pinnacle(f, p); ++ alps_decode_pinnacle(f, p, psmouse); + + f->x_map |= (p[5] & 0x10) << 11; + f->y_map |= (p[5] & 0x20) << 6; + } + +-static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p) ++static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p, ++ struct psmouse *psmouse) + { ++ u64 palm_data = 0; ++ struct alps_data *priv = psmouse->private; ++ + f->first_mp = !!(p[0] & 0x02); + f->is_mp = !!(p[0] & 0x20); + +- f->fingers = ((p[0] & 0x6) >> 1 | ++ if (!f->is_mp) { ++ f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7)); ++ f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3)); ++ f->z = (p[0] & 4) ? 0 : p[5] & 0x7f; ++ alps_decode_buttons_v3(f, p); ++ } else { ++ f->fingers = ((p[0] & 0x6) >> 1 | + (p[0] & 0x10) >> 2); +- f->x_map = ((p[2] & 0x60) >> 5) | +- ((p[4] & 0x7f) << 2) | +- ((p[5] & 0x7f) << 9) | +- ((p[3] & 0x07) << 16) | +- ((p[3] & 0x70) << 15) | +- ((p[0] & 0x01) << 22); +- f->y_map = (p[1] & 0x7f) | +- ((p[2] & 0x1f) << 7); +- +- f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7)); +- f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3)); +- f->z = (p[0] & 4) ? 0 : p[5] & 0x7f; + +- alps_decode_buttons_v3(f, p); ++ palm_data = (p[1] & 0x7f) | ++ ((p[2] & 0x7f) << 7) | ++ ((p[4] & 0x7f) << 14) | ++ ((p[5] & 0x7f) << 21) | ++ ((p[3] & 0x07) << 28) | ++ (((u64)p[3] & 0x70) << 27) | ++ (((u64)p[0] & 0x01) << 34); ++ ++ /* Y-profile is stored in P(0) to p(n-1), n = y_bits; */ ++ f->y_map = palm_data & (BIT(priv->y_bits) - 1); ++ ++ /* X-profile is stored in p(n) to p(n+m-1), m = x_bits; */ ++ f->x_map = (palm_data >> priv->y_bits) & ++ (BIT(priv->x_bits) - 1); ++ } + } + +-static void alps_process_touchpad_packet_v3(struct psmouse *psmouse) ++static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse) + { + struct alps_data *priv = psmouse->private; + unsigned char *packet = psmouse->packet; + struct input_dev *dev = psmouse->dev; + struct input_dev *dev2 = priv->dev2; + int x1 = 0, y1 = 0, x2 = 0, y2 = 0; +- int fingers = 0, bmap_fingers; +- struct alps_fields f; ++ int fingers = 0, bmap_fn; ++ struct alps_fields f = {0}; + +- priv->decode_fields(&f, packet); ++ priv->decode_fields(&f, packet, psmouse); + + /* + * There's no single feature of touchpad position and bitmap packets +@@ -560,19 +625,38 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse) + */ + if (f.is_mp) { + fingers = f.fingers; +- bmap_fingers = alps_process_bitmap(priv, +- f.x_map, f.y_map, +- &x1, &y1, &x2, &y2); +- +- /* +- * We shouldn't report more than one finger if +- * we don't have two coordinates. +- */ +- if (fingers > 1 && bmap_fingers < 2) +- fingers = bmap_fingers; +- +- /* Now process position packet */ +- priv->decode_fields(&f, priv->multi_data); ++ if (priv->proto_version == ALPS_PROTO_V3) { ++ bmap_fn = alps_process_bitmap(priv, f.x_map, ++ f.y_map, &x1, &y1, ++ &x2, &y2); ++ ++ /* ++ * We shouldn't report more than one finger if ++ * we don't have two coordinates. ++ */ ++ if (fingers > 1 && bmap_fn < 2) ++ fingers = bmap_fn; ++ ++ /* 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, &x1, &y1, ++ &x2, &y2); ++ } + } else { + priv->multi_packet = 0; + } +@@ -662,7 +746,7 @@ static void alps_process_packet_v3(struct psmouse *psmouse) + return; + } + +- alps_process_touchpad_packet_v3(psmouse); ++ alps_process_touchpad_packet_v3_v5(psmouse); + } + + static void alps_process_packet_v6(struct psmouse *psmouse) +@@ -1709,6 +1793,52 @@ error: + return -1; + } + ++static int alps_dolphin_get_device_area(struct psmouse *psmouse, ++ struct alps_data *priv) ++{ ++ struct ps2dev *ps2dev = &psmouse->ps2dev; ++ unsigned char param[4] = {0}; ++ int num_x_electrode, num_y_electrode; ++ ++ if (alps_enter_command_mode(psmouse)) ++ return -1; ++ ++ param[0] = 0x0a; ++ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) || ++ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) || ++ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) || ++ ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) || ++ ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE)) ++ return -1; ++ ++ if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) ++ return -1; ++ ++ /* ++ * Dolphin's sensor line number is not fixed. It can be calculated ++ * by adding the device's register value with DOLPHIN_PROFILE_X/YOFFSET. ++ * Further more, we can get device's x_max and y_max by multiplying ++ * sensor line number with DOLPHIN_COUNT_PER_ELECTRODE. ++ * ++ * e.g. When we get register's sensor_x = 11 & sensor_y = 8, ++ * real sensor line number X = 11 + 8 = 19, and ++ * real sensor line number Y = 8 + 1 = 9. ++ * So, x_max = (19 - 1) * 64 = 1152, and ++ * y_max = (9 - 1) * 64 = 512. ++ */ ++ num_x_electrode = DOLPHIN_PROFILE_XOFFSET + (param[2] & 0x0F); ++ num_y_electrode = DOLPHIN_PROFILE_YOFFSET + ((param[2] >> 4) & 0x0F); ++ priv->x_bits = num_x_electrode; ++ priv->y_bits = num_y_electrode; ++ priv->x_max = (num_x_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE; ++ priv->y_max = (num_y_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE; ++ ++ if (alps_exit_command_mode(psmouse)) ++ return -1; ++ ++ return 0; ++} ++ + static int alps_hw_init_dolphin_v1(struct psmouse *psmouse) + { + struct ps2dev *ps2dev = &psmouse->ps2dev; +@@ -1763,13 +1893,13 @@ static void alps_set_defaults(struct alps_data *priv) + break; + case ALPS_PROTO_V5: + priv->hw_init = alps_hw_init_dolphin_v1; +- priv->process_packet = alps_process_packet_v3; ++ 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->nibble_commands = alps_v3_nibble_commands; + priv->addr_command = PSMOUSE_CMD_RESET_WRAP; + priv->byte0 = 0xc8; +- priv->mask0 = 0xc8; ++ priv->mask0 = 0xd8; + priv->flags = 0; + priv->x_max = 1360; + priv->y_max = 660; +@@ -1845,11 +1975,13 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv) + if (alps_match_table(psmouse, priv, e7, ec) == 0) { + return 0; + } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 && +- ec[0] == 0x73 && ec[1] == 0x01) { ++ ec[0] == 0x73 && (ec[1] == 0x01 || ec[1] == 0x02)) { + priv->proto_version = ALPS_PROTO_V5; + alps_set_defaults(priv); +- +- return 0; ++ if (alps_dolphin_get_device_area(psmouse, priv)) ++ return -EIO; ++ else ++ return 0; + } else if (ec[0] == 0x88 && ec[1] == 0x08) { + priv->proto_version = ALPS_PROTO_V3; + alps_set_defaults(priv); +diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h +index 704f0f9..03f88b6 100644 +--- a/drivers/input/mouse/alps.h ++++ b/drivers/input/mouse/alps.h +@@ -19,6 +19,10 @@ + #define ALPS_PROTO_V5 5 + #define ALPS_PROTO_V6 6 + ++#define DOLPHIN_COUNT_PER_ELECTRODE 64 ++#define DOLPHIN_PROFILE_XOFFSET 8 /* x-electrode offset */ ++#define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode offset */ ++ + /** + * struct alps_model_info - touchpad ID table + * @signature: E7 response string to match. +@@ -146,7 +150,8 @@ struct alps_data { + + int (*hw_init)(struct psmouse *psmouse); + void (*process_packet)(struct psmouse *psmouse); +- void (*decode_fields)(struct alps_fields *f, unsigned char *p); ++ void (*decode_fields)(struct alps_fields *f, unsigned char *p, ++ struct psmouse *psmouse); + void (*set_abs_params)(struct alps_data *priv, struct input_dev *dev1); + + int prev_fin; +-- +1.8.4.2 + diff --git a/kernel.spec b/kernel.spec index 4ed901f44..06b2ea4e1 100644 --- a/kernel.spec +++ b/kernel.spec @@ -700,6 +700,9 @@ Patch25181: 0001-Input-wacom-make-sure-touch_max-is-set-for-touch-dev.patch Patch25182: 0002-Input-wacom-add-support-for-three-new-Intuos-devices.patch Patch25183: 0003-Input-wacom-add-reporting-of-SW_MUTE_DEVICE-events.patch +#rhbz 953211 +Patch25184: Input-ALPS-add-support-for-Dolphin-devices.patch + # END OF PATCH DEFINITIONS %endif @@ -1374,6 +1377,9 @@ ApplyPatch 0001-Input-wacom-make-sure-touch_max-is-set-for-touch-dev.patch ApplyPatch 0002-Input-wacom-add-support-for-three-new-Intuos-devices.patch ApplyPatch 0003-Input-wacom-add-reporting-of-SW_MUTE_DEVICE-events.patch +#rhbz 953211 +ApplyPatch Input-ALPS-add-support-for-Dolphin-devices.patch + # END OF PATCH APPLICATIONS %endif @@ -2161,6 +2167,9 @@ fi # ||----w | # || || %changelog +* Wed Jan 08 2014 Josh Boyer +- Backport support for ALPS Dolphin devices (rhbz 953211) + * Wed Jan 08 2014 Josh Boyer - 3.13.0-0.rc7.git2.1 - Linux v3.13-rc7-67-gceb3b02 - Enable BCMA_DRIVER_GPIO by turning on GPIOLIB everywhere (rhbz 1021098)