From f105e34a4e3ff073b0d96d5f91eb3c6e8dffaa4c Mon Sep 17 00:00:00 2001 From: Yunkang Tang Date: Fri, 25 Jul 2014 22:29:24 -0700 Subject: Input: alps - fix rushmore packet decoding Signed-off-by: Yunkang Tang Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index fb15c64ffb95..e15daea56864 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -559,6 +559,9 @@ static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p, { alps_decode_pinnacle(f, p, psmouse); + /* Rushmore's packet decode has a bit difference with Pinnacle's */ + 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; } -- cgit v1.2.3 From 20bea68bd1a5c783a23ad9e9de15ffb1b036f3a4 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 25 Jul 2014 22:33:33 -0700 Subject: Input: alps - improve 2-finger reporting on v3 models V3 models only report mt bitmap data when there are 2 or more fingers on the touchpad. So always generate 2 positions in alps_process_bitmap, and for v3 models only fall back to st data when there was no mt data in a mt packet (which should never happen). This fixes 2 finger scrolling not working when using 2 fingers close to each other. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 60 +++++++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 36 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index e15daea56864..cc197d7473c9 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -407,23 +407,20 @@ static int alps_process_bitmap(struct alps_data *priv, fingers = max(fingers_x, fingers_y); /* - * If total fingers is > 1 but either axis reports only a single - * contact, we have overlapping or adjacent fingers. For the - * purposes of creating a bounding box, divide the single contact - * (roughly) equally between the two points. + * If an axis reports only a single contact, we have overlapping or + * adjacent fingers. Divide the single contact between the two points. */ - if (fingers > 1) { - if (fingers_x == 1) { - i = x_low.num_bits / 2; - x_low.num_bits = x_low.num_bits - i; - x_high.start_bit = x_low.start_bit + i; - x_high.num_bits = max(i, 1); - } else if (fingers_y == 1) { - i = y_low.num_bits / 2; - y_low.num_bits = y_low.num_bits - i; - y_high.start_bit = y_low.start_bit + i; - y_high.num_bits = max(i, 1); - } + if (fingers_x == 1) { + i = x_low.num_bits / 2; + x_low.num_bits = x_low.num_bits - i; + x_high.start_bit = x_low.start_bit + i; + x_high.num_bits = max(i, 1); + } + if (fingers_y == 1) { + i = y_low.num_bits / 2; + y_low.num_bits = y_low.num_bits - i; + y_high.start_bit = y_low.start_bit + i; + y_high.num_bits = max(i, 1); } *x1 = (priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) / @@ -431,14 +428,12 @@ static int alps_process_bitmap(struct alps_data *priv, *y1 = (priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) / (2 * (priv->y_bits - 1)); - if (fingers > 1) { - *x2 = (priv->x_max * - (2 * x_high.start_bit + x_high.num_bits - 1)) / - (2 * (priv->x_bits - 1)); - *y2 = (priv->y_max * - (2 * y_high.start_bit + y_high.num_bits - 1)) / - (2 * (priv->y_bits - 1)); - } + *x2 = (priv->x_max * + (2 * x_high.start_bit + x_high.num_bits - 1)) / + (2 * (priv->x_bits - 1)); + *y2 = (priv->y_max * + (2 * y_high.start_bit + y_high.num_bits - 1)) / + (2 * (priv->y_bits - 1)); return fingers; } @@ -607,8 +602,7 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse) 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_fn; + int x1 = 0, y1 = 0, x2 = 0, y2 = 0, fingers = 0; struct alps_fields f = {0}; priv->decode_fields(&f, packet, psmouse); @@ -629,16 +623,10 @@ 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) { - 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; + if (alps_process_bitmap(priv, f.x_map, + f.y_map, &x1, &y1, + &x2, &y2) == 0) + fingers = 0; /* Use st data */ /* Now process position packet */ priv->decode_fields(&f, priv->multi_data, -- cgit v1.2.3 From 40e8f53bffe074e6cd409cf484e4b55c114c93d6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 25 Jul 2014 22:37:15 -0700 Subject: Input: alps - process_bitmap: don't invert the Y-axis on Rushmore Rushmore models don't have the Y-axis data in the bitmap inverted. Since we now have 2 different Y orientations, make the Y bitmap data processing use a forward loop like the X bitmap data processing, unifying the 2, and invert the data later, except on Rushmore. So far no-one has noticed this because the synaptics driver only uses the non mt coordinates (except on clickpads, and there are no alps clickpads using process_bitmap). Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 17 ++++++++++------- drivers/input/mouse/alps.h | 4 ++-- 2 files changed, 12 insertions(+), 9 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index cc197d7473c9..abe9f9bdf69a 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -99,6 +99,7 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = { #define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */ #define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with 6-byte ALPS packet */ +#define ALPS_IS_RUSHMORE 0x100 /* device is a rushmore */ static const struct alps_model_info alps_model_data[] = { { { 0x32, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */ @@ -376,15 +377,10 @@ static int alps_process_bitmap(struct alps_data *priv, prev_bit = bit; } - /* - * y bitmap is reversed for what we need (lower positions are in - * higher bits), so we process from the top end. - */ - y_map = y_map << (sizeof(y_map) * BITS_PER_BYTE - priv->y_bits); prev_bit = 0; point = &y_low; - for (i = 0; y_map != 0; i++, y_map <<= 1) { - bit = y_map & (1 << (sizeof(y_map) * BITS_PER_BYTE - 1)); + for (i = 0; y_map != 0; i++, y_map >>= 1) { + bit = y_map & 1; if (bit) { if (!prev_bit) { point->start_bit = i; @@ -435,6 +431,12 @@ static int alps_process_bitmap(struct alps_data *priv, (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->flags & ALPS_IS_RUSHMORE)) { + *y1 = priv->y_max - *y1; + *y2 = priv->y_max - *y2; + } + return fingers; } @@ -1981,6 +1983,7 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv) priv->decode_fields = alps_decode_rushmore; priv->x_bits = 16; priv->y_bits = 12; + priv->flags |= ALPS_IS_RUSHMORE; /* hack to make addr_command, nibble_command available */ psmouse->private = priv; diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index 03f88b6940c7..6d2666c0d63a 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h @@ -46,7 +46,7 @@ struct alps_model_info { unsigned char command_mode_resp; unsigned char proto_version; unsigned char byte0, mask0; - unsigned char flags; + int flags; }; /** @@ -142,7 +142,7 @@ struct alps_data { int addr_command; unsigned char proto_version; unsigned char byte0, mask0; - unsigned char flags; + int flags; int x_max; int y_max; int x_bits; -- cgit v1.2.3 From 036e6c7b541a9a57b4e294ee4727045d81f68ca0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 25 Jul 2014 22:38:51 -0700 Subject: Input: alps - process_bitmap: add alps_get_bitmap_points() helper function Factor out the identical code for getting the bitmap points for x and y into a helper function. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 75 +++++++++++++++++++--------------------------- drivers/input/mouse/alps.h | 5 ++++ 2 files changed, 35 insertions(+), 45 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index abe9f9bdf69a..c6af590a07d3 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -328,6 +328,33 @@ static void alps_process_bitmap_dolphin(struct alps_data *priv, } } +static void alps_get_bitmap_points(unsigned int map, + struct alps_bitmap_point *low, + struct alps_bitmap_point *high, + int *fingers) +{ + struct alps_bitmap_point *point; + int i, bit, prev_bit = 0; + + point = low; + for (i = 0; map != 0; i++, map >>= 1) { + bit = map & 1; + if (bit) { + if (!prev_bit) { + point->start_bit = i; + (*fingers)++; + } + point->num_bits++; + } else { + if (prev_bit) + point = high; + else + point->num_bits = 0; + } + prev_bit = bit; + } +} + /* * 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 @@ -342,59 +369,17 @@ static int alps_process_bitmap(struct alps_data *priv, unsigned int x_map, unsigned int y_map, int *x1, int *y1, int *x2, int *y2) { - struct alps_bitmap_point { - int start_bit; - int num_bits; - }; - - int fingers_x = 0, fingers_y = 0, fingers; - int i, bit, prev_bit; + int i, fingers_x = 0, fingers_y = 0, fingers; struct alps_bitmap_point x_low = {0,}, x_high = {0,}; struct alps_bitmap_point y_low = {0,}, y_high = {0,}; - struct alps_bitmap_point *point; if (!x_map || !y_map) return 0; *x1 = *y1 = *x2 = *y2 = 0; - prev_bit = 0; - point = &x_low; - for (i = 0; x_map != 0; i++, x_map >>= 1) { - bit = x_map & 1; - if (bit) { - if (!prev_bit) { - point->start_bit = i; - fingers_x++; - } - point->num_bits++; - } else { - if (prev_bit) - point = &x_high; - else - point->num_bits = 0; - } - prev_bit = bit; - } - - prev_bit = 0; - point = &y_low; - for (i = 0; y_map != 0; i++, y_map >>= 1) { - bit = y_map & 1; - if (bit) { - if (!prev_bit) { - point->start_bit = i; - fingers_y++; - } - point->num_bits++; - } else { - if (prev_bit) - point = &y_high; - else - point->num_bits = 0; - } - prev_bit = bit; - } + alps_get_bitmap_points(x_map, &x_low, &x_high, &fingers_x); + alps_get_bitmap_points(y_map, &y_low, &y_high, &fingers_y); /* * Fingers can overlap, so we use the maximum count of fingers diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index 6d2666c0d63a..e900a08b42e5 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h @@ -65,6 +65,11 @@ struct alps_nibble_commands { unsigned char data; }; +struct alps_bitmap_point { + int start_bit; + int num_bits; +}; + /** * struct alps_fields - decoded version of the report packet * @x_map: Bitmap of active X positions for MT. -- cgit v1.2.3 From 105affbfd588d5aec4171234051f7d589f7e62c1 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 25 Jul 2014 22:41:51 -0700 Subject: Input: alps - process_bitmap: fix counting of high point bits alps_process_bitmap was resetting the point bit-count as soon as it saw 2 0 bits in a row. This means that unless the high point actually is at the end of the bitmap, it would always get its num_bits set to 0. Instead reset num_bits to 0 on a 0->1 transition, so that with > 2 fingers we only count the number of bits occupied by the highest finger. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index c6af590a07d3..5b35f4fc4d2f 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -342,14 +342,13 @@ static void alps_get_bitmap_points(unsigned int map, if (bit) { if (!prev_bit) { point->start_bit = i; + point->num_bits = 0; (*fingers)++; } point->num_bits++; } else { if (prev_bit) point = high; - else - point->num_bits = 0; } prev_bit = bit; } -- cgit v1.2.3 From 28835f4540564e6319028c9c1aeadf16604bed9c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 25 Jul 2014 22:42:53 -0700 Subject: Input: alps - process_bitmap: round down when spreading adjescent fingers over 2 points This fixes 2 fingers at the same height or width on the touchpad getting reported at different y / x coordinates. Note num_bits is always at least 1. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 5b35f4fc4d2f..1c9917828956 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -391,13 +391,13 @@ static int alps_process_bitmap(struct alps_data *priv, * adjacent fingers. Divide the single contact between the two points. */ if (fingers_x == 1) { - i = x_low.num_bits / 2; + i = (x_low.num_bits - 1) / 2; x_low.num_bits = x_low.num_bits - i; x_high.start_bit = x_low.start_bit + i; x_high.num_bits = max(i, 1); } if (fingers_y == 1) { - i = y_low.num_bits / 2; + i = (y_low.num_bits - 1) / 2; y_low.num_bits = y_low.num_bits - i; y_high.start_bit = y_low.start_bit + i; y_high.num_bits = max(i, 1); -- cgit v1.2.3 From 02d04254a5dfb8de1459805c3433cd0e9e4853d7 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 25 Jul 2014 22:43:35 -0700 Subject: Input: alps - use struct input_mt_pos to track coordinates This is a preparation patch for switching the DIY mt handling to using input_mt_assign_slots && input_mt_sync_frame. struct alps_fields is quite large, so while making changes to almost all uses of it lets put it in our priv data instead of on the stack. Having it in our priv data also allows using it directly for storing values which need to be cached, rather then having separate x, y, z, fingers, etc. copies in our priv data. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 199 ++++++++++++++++++++------------------------- drivers/input/mouse/alps.h | 27 +++--- 2 files changed, 104 insertions(+), 122 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 1c9917828956..8c3017a92788 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -282,11 +282,10 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse) * * 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. + * These two points are returned in fields->mt. */ static void alps_process_bitmap_dolphin(struct alps_data *priv, - struct alps_fields *fields, - int *x1, int *y1, int *x2, int *y2) + struct alps_fields *fields) { int box_middle_x, box_middle_y; unsigned int x_map, y_map; @@ -309,8 +308,6 @@ static void alps_process_bitmap_dolphin(struct alps_data *priv, 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; @@ -321,10 +318,9 @@ static void alps_process_bitmap_dolphin(struct alps_data *priv, 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; + 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; } } @@ -361,24 +357,21 @@ static void alps_get_bitmap_points(unsigned int map, * * The bitmaps don't have enough data to track fingers, so this function * only generates points representing a bounding box of all contacts. - * These points are returned in x1, y1, x2, and y2 when the return value + * These points are returned in fields->mt when the return value * is greater than 0. */ static int alps_process_bitmap(struct alps_data *priv, - unsigned int x_map, unsigned int y_map, - int *x1, int *y1, int *x2, int *y2) + struct alps_fields *fields) { int i, fingers_x = 0, fingers_y = 0, fingers; struct alps_bitmap_point x_low = {0,}, x_high = {0,}; struct alps_bitmap_point y_low = {0,}, y_high = {0,}; - if (!x_map || !y_map) + if (!fields->x_map || !fields->y_map) return 0; - *x1 = *y1 = *x2 = *y2 = 0; - - alps_get_bitmap_points(x_map, &x_low, &x_high, &fingers_x); - alps_get_bitmap_points(y_map, &y_low, &y_high, &fingers_y); + alps_get_bitmap_points(fields->x_map, &x_low, &x_high, &fingers_x); + alps_get_bitmap_points(fields->y_map, &y_low, &y_high, &fingers_y); /* * Fingers can overlap, so we use the maximum count of fingers @@ -403,22 +396,24 @@ static int alps_process_bitmap(struct alps_data *priv, y_high.num_bits = max(i, 1); } - *x1 = (priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) / - (2 * (priv->x_bits - 1)); - *y1 = (priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) / - (2 * (priv->y_bits - 1)); + fields->mt[0].x = + (priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) / + (2 * (priv->x_bits - 1)); + fields->mt[0].y = + (priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) / + (2 * (priv->y_bits - 1)); - *x2 = (priv->x_max * - (2 * x_high.start_bit + x_high.num_bits - 1)) / - (2 * (priv->x_bits - 1)); - *y2 = (priv->y_max * - (2 * y_high.start_bit + y_high.num_bits - 1)) / - (2 * (priv->y_bits - 1)); + fields->mt[1].x = + (priv->x_max * (2 * x_high.start_bit + x_high.num_bits - 1)) / + (2 * (priv->x_bits - 1)); + fields->mt[1].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->flags & ALPS_IS_RUSHMORE)) { - *y1 = priv->y_max - *y1; - *y2 = priv->y_max - *y2; + fields->mt[0].y = priv->y_max - fields->mt[0].y; + fields->mt[1].y = priv->y_max - fields->mt[1].y; } return fingers; @@ -435,11 +430,14 @@ static void alps_set_slot(struct input_dev *dev, int slot, bool active, } } -static void alps_report_semi_mt_data(struct input_dev *dev, int num_fingers, - int x1, int y1, int x2, int y2) +static void alps_report_semi_mt_data(struct psmouse *psmouse, int num_fingers) { - alps_set_slot(dev, 0, num_fingers != 0, x1, y1); - alps_set_slot(dev, 1, num_fingers == 2, x2, y2); + struct alps_data *priv = psmouse->private; + struct input_dev *dev = psmouse->dev; + struct alps_fields *f = &priv->f; + + alps_set_slot(dev, 0, num_fingers != 0, f->mt[0].x, f->mt[0].y); + alps_set_slot(dev, 1, num_fingers == 2, f->mt[1].x, f->mt[1].y); } static void alps_process_trackstick_packet_v3(struct psmouse *psmouse) @@ -527,10 +525,10 @@ static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p, ((p[2] & 0x7f) << 1) | (p[4] & 0x01); - f->x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) | + f->st.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) | ((p[0] & 0x30) >> 4); - f->y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f); - f->z = p[5] & 0x7f; + f->st.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f); + f->pressure = p[5] & 0x7f; alps_decode_buttons_v3(f, p); } @@ -557,9 +555,9 @@ static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p, f->is_mp = !!(p[0] & 0x20); 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; + f->st.x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7)); + f->st.y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3)); + f->pressure = (p[0] & 4) ? 0 : p[5] & 0x7f; alps_decode_buttons_v3(f, p); } else { f->fingers = ((p[0] & 0x6) >> 1 | @@ -588,10 +586,12 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse) 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, fingers = 0; - struct alps_fields f = {0}; + struct alps_fields *f = &priv->f; + int fingers = 0; + + memset(f, 0, sizeof(*f)); - priv->decode_fields(&f, packet, psmouse); + priv->decode_fields(f, packet, psmouse); /* * There's no single feature of touchpad position and bitmap packets @@ -606,16 +606,14 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse) * packet. Check for this, and when it happens process the * position packet as usual. */ - if (f.is_mp) { - fingers = f.fingers; + if (f->is_mp) { + fingers = f->fingers; if (priv->proto_version == ALPS_PROTO_V3) { - if (alps_process_bitmap(priv, f.x_map, - f.y_map, &x1, &y1, - &x2, &y2) == 0) + if (alps_process_bitmap(priv, f) == 0) fingers = 0; /* Use st data */ /* Now process position packet */ - priv->decode_fields(&f, priv->multi_data, + priv->decode_fields(f, priv->multi_data, psmouse); } else { /* @@ -624,15 +622,14 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse) * calculate Pt2, so we need to do position * packet decode first. */ - priv->decode_fields(&f, priv->multi_data, + 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); + alps_process_bitmap_dolphin(priv, f); } } else { priv->multi_packet = 0; @@ -647,10 +644,10 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse) * out misidentified bitmap packets, we reject anything with this * bit set. */ - if (f.is_mp) + if (f->is_mp) return; - if (!priv->multi_packet && f.first_mp) { + if (!priv->multi_packet && f->first_mp) { priv->multi_packet = 1; memcpy(priv->multi_data, packet, sizeof(priv->multi_data)); return; @@ -664,7 +661,7 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse) * with x, y, and z all zero, so these seem to be flukes. * Ignore them. */ - if (f.x && f.y && !f.z) + if (f->st.x && f->st.y && !f->pressure) return; /* @@ -672,36 +669,36 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse) * to rely on ST data. */ if (!fingers) { - x1 = f.x; - y1 = f.y; - fingers = f.z > 0 ? 1 : 0; + f->mt[0].x = f->st.x; + f->mt[0].y = f->st.y; + fingers = f->pressure > 0 ? 1 : 0; } - if (f.z >= 64) + if (f->pressure >= 64) input_report_key(dev, BTN_TOUCH, 1); else input_report_key(dev, BTN_TOUCH, 0); - alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2); + alps_report_semi_mt_data(psmouse, fingers); input_mt_report_finger_count(dev, fingers); - input_report_key(dev, BTN_LEFT, f.left); - input_report_key(dev, BTN_RIGHT, f.right); - input_report_key(dev, BTN_MIDDLE, f.middle); + input_report_key(dev, BTN_LEFT, f->left); + input_report_key(dev, BTN_RIGHT, f->right); + input_report_key(dev, BTN_MIDDLE, f->middle); - if (f.z > 0) { - input_report_abs(dev, ABS_X, f.x); - input_report_abs(dev, ABS_Y, f.y); + if (f->pressure > 0) { + input_report_abs(dev, ABS_X, f->st.x); + input_report_abs(dev, ABS_Y, f->st.y); } - input_report_abs(dev, ABS_PRESSURE, f.z); + input_report_abs(dev, ABS_PRESSURE, f->pressure); input_sync(dev); if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) { - input_report_key(dev2, BTN_LEFT, f.ts_left); - input_report_key(dev2, BTN_RIGHT, f.ts_right); - input_report_key(dev2, BTN_MIDDLE, f.ts_middle); + input_report_key(dev2, BTN_LEFT, f->ts_left); + input_report_key(dev2, BTN_RIGHT, f->ts_right); + input_report_key(dev2, BTN_MIDDLE, f->ts_middle); input_sync(dev2); } } @@ -801,12 +798,8 @@ static void alps_process_packet_v4(struct psmouse *psmouse) struct alps_data *priv = psmouse->private; unsigned char *packet = psmouse->packet; struct input_dev *dev = psmouse->dev; - int offset; - int x, y, z; - int left, right; - int x1, y1, x2, y2; - int fingers = 0; - unsigned int x_bitmap, y_bitmap; + struct alps_fields *f = &priv->f; + int offset, fingers = 0; /* * v4 has a 6-byte encoding for bitmap data, but this data is @@ -828,67 +821,55 @@ static void alps_process_packet_v4(struct psmouse *psmouse) if (++priv->multi_packet > 2) { priv->multi_packet = 0; - x_bitmap = ((priv->multi_data[2] & 0x1f) << 10) | + f->x_map = ((priv->multi_data[2] & 0x1f) << 10) | ((priv->multi_data[3] & 0x60) << 3) | ((priv->multi_data[0] & 0x3f) << 2) | ((priv->multi_data[1] & 0x60) >> 5); - y_bitmap = ((priv->multi_data[5] & 0x01) << 10) | + f->y_map = ((priv->multi_data[5] & 0x01) << 10) | ((priv->multi_data[3] & 0x1f) << 5) | (priv->multi_data[1] & 0x1f); - fingers = alps_process_bitmap(priv, x_bitmap, y_bitmap, - &x1, &y1, &x2, &y2); - - /* Store MT data.*/ - priv->fingers = fingers; - priv->x1 = x1; - priv->x2 = x2; - priv->y1 = y1; - priv->y2 = y2; + f->fingers = alps_process_bitmap(priv, f); } - left = packet[4] & 0x01; - right = packet[4] & 0x02; + f->left = packet[4] & 0x01; + f->right = packet[4] & 0x02; - x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) | - ((packet[0] & 0x30) >> 4); - y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f); - z = packet[5] & 0x7f; + 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 there were no contacts in the bitmap, use ST * points in MT reports. * If there were two contacts or more, report MT data. */ - if (priv->fingers < 2) { - x1 = x; - y1 = y; - fingers = z > 0 ? 1 : 0; + if (f->fingers < 2) { + f->mt[0].x = f->st.x; + f->mt[0].y = f->st.y; + fingers = f->pressure > 0 ? 1 : 0; } else { - fingers = priv->fingers; - x1 = priv->x1; - x2 = priv->x2; - y1 = priv->y1; - y2 = priv->y2; + fingers = f->fingers; } - if (z >= 64) + if (f->pressure >= 64) input_report_key(dev, BTN_TOUCH, 1); else input_report_key(dev, BTN_TOUCH, 0); - alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2); + alps_report_semi_mt_data(psmouse, fingers); input_mt_report_finger_count(dev, fingers); - input_report_key(dev, BTN_LEFT, left); - input_report_key(dev, BTN_RIGHT, right); + input_report_key(dev, BTN_LEFT, f->left); + input_report_key(dev, BTN_RIGHT, f->right); - if (z > 0) { - input_report_abs(dev, ABS_X, x); - input_report_abs(dev, ABS_Y, y); + if (f->pressure > 0) { + input_report_abs(dev, ABS_X, f->st.x); + input_report_abs(dev, ABS_Y, f->st.y); } - input_report_abs(dev, ABS_PRESSURE, z); + input_report_abs(dev, ABS_PRESSURE, f->pressure); input_sync(dev); } diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index e900a08b42e5..ee841e53ef9c 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h @@ -12,6 +12,8 @@ #ifndef _ALPS_H #define _ALPS_H +#include + #define ALPS_PROTO_V1 1 #define ALPS_PROTO_V2 2 #define ALPS_PROTO_V3 3 @@ -19,6 +21,8 @@ #define ALPS_PROTO_V5 5 #define ALPS_PROTO_V6 6 +#define MAX_TOUCHES 2 + #define DOLPHIN_COUNT_PER_ELECTRODE 64 #define DOLPHIN_PROFILE_XOFFSET 8 /* x-electrode offset */ #define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode offset */ @@ -75,9 +79,9 @@ struct alps_bitmap_point { * @x_map: Bitmap of active X positions for MT. * @y_map: Bitmap of active Y positions for MT. * @fingers: Number of fingers for MT. - * @x: X position for ST. - * @y: Y position for ST. - * @z: Z position for ST. + * @pressure: Pressure. + * @st: position for ST. + * @mt: position for MT. * @first_mp: Packet is the first of a multi-packet report. * @is_mp: Packet is part of a multi-packet report. * @left: Left touchpad button is active. @@ -91,9 +95,11 @@ struct alps_fields { unsigned int x_map; unsigned int y_map; unsigned int fingers; - unsigned int x; - unsigned int y; - unsigned int z; + + int pressure; + struct input_mt_pos st; + struct input_mt_pos mt[MAX_TOUCHES]; + unsigned int first_mp:1; unsigned int is_mp:1; @@ -130,11 +136,7 @@ struct alps_fields { * @prev_fin: Finger bit from previous packet. * @multi_packet: Multi-packet data in progress. * @multi_data: Saved multi-packet data. - * @x1: First X coordinate from last MT report. - * @x2: Second X coordinate from last MT report. - * @y1: First Y coordinate from last MT report. - * @y2: Second Y coordinate from last MT report. - * @fingers: Number of fingers from last MT report. + * @f: Decoded packet data fields. * @quirks: Bitmap of ALPS_QUIRK_*. * @timer: Timer for flushing out the final report packet in the stream. */ @@ -162,8 +164,7 @@ struct alps_data { int prev_fin; int multi_packet; unsigned char multi_data[6]; - int x1, x2, y1, y2; - int fingers; + struct alps_fields f; u8 quirks; struct timer_list timer; }; -- cgit v1.2.3 From cdf333efdcad9891e7f9c26e9ece67776af13ae2 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 25 Jul 2014 22:44:42 -0700 Subject: Input: alps - use standard contact tracking instead of DIY When there are 2 fingers on the pad we don't know which one is which, so use input_mt_assign_slots to make sure the right set of coordinates ends up in the right slot. Besides ensuring things end up in the right slot, this also results in a nice cleanup, since sync_frame also handles non mt position and btn_touch reporting. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 52 ++++++++++++++-------------------------------- 1 file changed, 16 insertions(+), 36 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 8c3017a92788..8c2de016e223 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -419,25 +419,26 @@ static int alps_process_bitmap(struct alps_data *priv, return fingers; } -static void alps_set_slot(struct input_dev *dev, int slot, bool active, - int x, int y) +static void alps_set_slot(struct input_dev *dev, int slot, int x, int y) { input_mt_slot(dev, slot); - input_mt_report_slot_state(dev, MT_TOOL_FINGER, active); - if (active) { - input_report_abs(dev, ABS_MT_POSITION_X, x); - input_report_abs(dev, ABS_MT_POSITION_Y, y); - } + input_mt_report_slot_state(dev, MT_TOOL_FINGER, true); + input_report_abs(dev, ABS_MT_POSITION_X, x); + input_report_abs(dev, ABS_MT_POSITION_Y, y); } -static void alps_report_semi_mt_data(struct psmouse *psmouse, int num_fingers) +static void alps_report_mt_data(struct psmouse *psmouse, int n) { struct alps_data *priv = psmouse->private; struct input_dev *dev = psmouse->dev; struct alps_fields *f = &priv->f; + int i, slot[MAX_TOUCHES]; + + input_mt_assign_slots(dev, slot, f->mt, n); + for (i = 0; i < n; i++) + alps_set_slot(dev, slot[i], f->mt[i].x, f->mt[i].y); - alps_set_slot(dev, 0, num_fingers != 0, f->mt[0].x, f->mt[0].y); - alps_set_slot(dev, 1, num_fingers == 2, f->mt[1].x, f->mt[1].y); + input_mt_sync_frame(dev); } static void alps_process_trackstick_packet_v3(struct psmouse *psmouse) @@ -674,12 +675,7 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse) fingers = f->pressure > 0 ? 1 : 0; } - if (f->pressure >= 64) - input_report_key(dev, BTN_TOUCH, 1); - else - input_report_key(dev, BTN_TOUCH, 0); - - alps_report_semi_mt_data(psmouse, fingers); + alps_report_mt_data(psmouse, (fingers <= 2) ? fingers : 1); input_mt_report_finger_count(dev, fingers); @@ -687,10 +683,6 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse) input_report_key(dev, BTN_RIGHT, f->right); input_report_key(dev, BTN_MIDDLE, f->middle); - if (f->pressure > 0) { - input_report_abs(dev, ABS_X, f->st.x); - input_report_abs(dev, ABS_Y, f->st.y); - } input_report_abs(dev, ABS_PRESSURE, f->pressure); input_sync(dev); @@ -853,22 +845,13 @@ static void alps_process_packet_v4(struct psmouse *psmouse) fingers = f->fingers; } - if (f->pressure >= 64) - input_report_key(dev, BTN_TOUCH, 1); - else - input_report_key(dev, BTN_TOUCH, 0); - - alps_report_semi_mt_data(psmouse, fingers); + alps_report_mt_data(psmouse, (fingers <= 2) ? fingers : 1); input_mt_report_finger_count(dev, fingers); input_report_key(dev, BTN_LEFT, f->left); input_report_key(dev, BTN_RIGHT, f->right); - if (f->pressure > 0) { - input_report_abs(dev, ABS_X, f->st.x); - input_report_abs(dev, ABS_Y, f->st.y); - } input_report_abs(dev, ABS_PRESSURE, f->pressure); input_sync(dev); @@ -2003,17 +1986,14 @@ static void alps_set_abs_params_st(struct alps_data *priv, static void alps_set_abs_params_mt(struct alps_data *priv, struct input_dev *dev1) { - set_bit(INPUT_PROP_SEMI_MT, dev1->propbit); - input_mt_init_slots(dev1, 2, 0); input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0); input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0); - set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit); + 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); - - 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); } int alps_init(struct psmouse *psmouse) -- cgit v1.2.3 From c38a448a237534aecc40bd826c55132c479f4c42 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 25 Jul 2014 22:46:53 -0700 Subject: Input: alps - use single touch data when v3 mt data contains only one finger For v3 protocol devices, use the more accurate single touch data when the mt data contains only one finger. Note the mt data reporting a finger count of 1 should never happen, but better safe then sorry. This brings the v3 bitmap handling in line with what the v4 code does, allowing to factor out the common bits into a helper function. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 8c2de016e223..9a5f08db4537 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -669,7 +669,7 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse) * If we don't have MT data or the bitmaps were empty, we have * to rely on ST data. */ - if (!fingers) { + if (fingers < 2) { f->mt[0].x = f->st.x; f->mt[0].y = f->st.y; fingers = f->pressure > 0 ? 1 : 0; -- cgit v1.2.3 From 68c21870179d78ab7375da432e8dd753d4dc2ba0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 25 Jul 2014 22:47:25 -0700 Subject: Input: alps - add an alps_report_semi_mt_data function Move all the semi-mt specific handling shared between the v3 and v4 handling code to a common helper function. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 76 ++++++++++++++++++---------------------------- 1 file changed, 29 insertions(+), 47 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 9a5f08db4537..f16fe7c7d215 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -441,6 +441,32 @@ static void alps_report_mt_data(struct psmouse *psmouse, int n) input_mt_sync_frame(dev); } +static void alps_report_semi_mt_data(struct psmouse *psmouse, int fingers) +{ + struct alps_data *priv = psmouse->private; + struct input_dev *dev = psmouse->dev; + struct alps_fields *f = &priv->f; + + /* Use st data when we don't have mt data */ + if (fingers < 2) { + f->mt[0].x = f->st.x; + f->mt[0].y = f->st.y; + fingers = f->pressure > 0 ? 1 : 0; + } + + alps_report_mt_data(psmouse, (fingers <= 2) ? fingers : 1); + + input_mt_report_finger_count(dev, fingers); + + input_report_key(dev, BTN_LEFT, f->left); + input_report_key(dev, BTN_RIGHT, f->right); + input_report_key(dev, BTN_MIDDLE, f->middle); + + input_report_abs(dev, ABS_PRESSURE, f->pressure); + + input_sync(dev); +} + static void alps_process_trackstick_packet_v3(struct psmouse *psmouse) { struct alps_data *priv = psmouse->private; @@ -585,7 +611,6 @@ 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; struct alps_fields *f = &priv->f; int fingers = 0; @@ -665,27 +690,7 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse) if (f->st.x && f->st.y && !f->pressure) return; - /* - * If we don't have MT data or the bitmaps were empty, we have - * to rely on ST data. - */ - if (fingers < 2) { - f->mt[0].x = f->st.x; - f->mt[0].y = f->st.y; - fingers = f->pressure > 0 ? 1 : 0; - } - - alps_report_mt_data(psmouse, (fingers <= 2) ? fingers : 1); - - input_mt_report_finger_count(dev, fingers); - - input_report_key(dev, BTN_LEFT, f->left); - input_report_key(dev, BTN_RIGHT, f->right); - input_report_key(dev, BTN_MIDDLE, f->middle); - - input_report_abs(dev, ABS_PRESSURE, f->pressure); - - input_sync(dev); + alps_report_semi_mt_data(psmouse, fingers); if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) { input_report_key(dev2, BTN_LEFT, f->ts_left); @@ -789,9 +794,8 @@ static void alps_process_packet_v4(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; - int offset, fingers = 0; + int offset; /* * v4 has a 6-byte encoding for bitmap data, but this data is @@ -832,29 +836,7 @@ static void alps_process_packet_v4(struct psmouse *psmouse) f->st.y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f); f->pressure = packet[5] & 0x7f; - /* - * If there were no contacts in the bitmap, use ST - * points in MT reports. - * If there were two contacts or more, report MT data. - */ - if (f->fingers < 2) { - f->mt[0].x = f->st.x; - f->mt[0].y = f->st.y; - fingers = f->pressure > 0 ? 1 : 0; - } else { - fingers = f->fingers; - } - - alps_report_mt_data(psmouse, (fingers <= 2) ? fingers : 1); - - input_mt_report_finger_count(dev, fingers); - - input_report_key(dev, BTN_LEFT, f->left); - input_report_key(dev, BTN_RIGHT, f->right); - - input_report_abs(dev, ABS_PRESSURE, f->pressure); - - input_sync(dev); + alps_report_semi_mt_data(psmouse, f->fingers); } static void alps_report_bare_ps2_packet(struct psmouse *psmouse, -- cgit v1.2.3 From 99d9996c5c3b47c14c8717c7dd4692a25b83b3f7 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 25 Jul 2014 22:48:02 -0700 Subject: Input: alps - report 2 touches when we've > 2 fingers If we detect more then 2 fingers report 2 touches, rather then only reporting the upper left corner of the bounding box. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index f16fe7c7d215..5026600278d3 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -454,7 +454,7 @@ static void alps_report_semi_mt_data(struct psmouse *psmouse, int fingers) fingers = f->pressure > 0 ? 1 : 0; } - alps_report_mt_data(psmouse, (fingers <= 2) ? fingers : 1); + alps_report_mt_data(psmouse, (fingers <= 2) ? fingers : 2); input_mt_report_finger_count(dev, fingers); -- cgit v1.2.3 From 38c11eaaab0cf8ef6004aa704f1bb2ff5e6bc1b0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 25 Jul 2014 22:48:44 -0700 Subject: Input: alps - change decode function prototype to return an int So that decode functions can return a failure when appropriate. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 12 +++++++++--- drivers/input/mouse/alps.h | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 5026600278d3..8f794913f4cd 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -538,7 +538,7 @@ 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 int alps_decode_pinnacle(struct alps_fields *f, unsigned char *p, struct psmouse *psmouse) { f->first_mp = !!(p[4] & 0x40); @@ -558,9 +558,11 @@ static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p, f->pressure = p[5] & 0x7f; alps_decode_buttons_v3(f, p); + + return 0; } -static void alps_decode_rushmore(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); @@ -570,9 +572,11 @@ static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p, 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; + + return 0; } -static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p, +static int alps_decode_dolphin(struct alps_fields *f, unsigned char *p, struct psmouse *psmouse) { u64 palm_data = 0; @@ -605,6 +609,8 @@ static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p, f->x_map = (palm_data >> priv->y_bits) & (BIT(priv->x_bits) - 1); } + + return 0; } static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse) diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index ee841e53ef9c..17e3ae39bcb7 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h @@ -157,7 +157,7 @@ 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, + int (*decode_fields)(struct alps_fields *f, unsigned char *p, struct psmouse *psmouse); void (*set_abs_params)(struct alps_data *priv, struct input_dev *dev1); -- cgit v1.2.3 From c0cd17f6dc7342a81b61017e6b84e363f86081c6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 25 Jul 2014 22:49:14 -0700 Subject: Input: alps - cache firmware version Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 3 +++ drivers/input/mouse/alps.h | 2 ++ 2 files changed, 5 insertions(+) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 8f794913f4cd..31b963dbf9a9 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -1901,6 +1901,9 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv) alps_exit_command_mode(psmouse)) return -EIO; + /* Save the Firmware version */ + memcpy(priv->fw_ver, ec, 3); + if (alps_match_table(psmouse, priv, e7, ec) == 0) { return 0; } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 && diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index 17e3ae39bcb7..e3d0f09aeeb3 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h @@ -124,6 +124,7 @@ struct alps_fields { * known format for this model. The first byte of the report, ANDed with * mask0, should match byte0. * @mask0: The mask used to check the first byte of the report. + * @fw_ver: cached copy of firmware version (EC report) * @flags: Additional device capabilities (passthrough port, trackstick, etc.). * @x_max: Largest possible X position value. * @y_max: Largest possible Y position value. @@ -149,6 +150,7 @@ struct alps_data { int addr_command; unsigned char proto_version; unsigned char byte0, mask0; + unsigned char fw_ver[3]; int flags; int x_max; int y_max; -- cgit v1.2.3 From 3808843cf10e4a696d942359d99822eff1a2de8e Mon Sep 17 00:00:00 2001 From: Yunkang Tang Date: Sat, 26 Jul 2014 13:51:41 -0700 Subject: Input: alps - add support for v7 devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Such as found on the new Toshiba Portégé Z30-A and Z40-A. Signed-off-by: Yunkang Tang [hdegoede@redhat.com: Remove softbutton handling, this is done in userspace] [hdegoede@redhat.com: Report INPUT_PROP_BUTTONPAD] [hdegoede@redhat.com: Do not report fake PRESSURE, reporting BTN_TOUCH is enough] [hdegoede@redhat.com: Various cleanups / refactoring] Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 265 ++++++++++++++++++++++++++++++++++++++++++++- drivers/input/mouse/alps.h | 18 +++ 2 files changed, 280 insertions(+), 3 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 31b963dbf9a9..76d372f0084c 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -100,6 +100,7 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = { #define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with 6-byte ALPS packet */ #define ALPS_IS_RUSHMORE 0x100 /* device is a rushmore */ +#define ALPS_BUTTONPAD 0x200 /* device is a clickpad */ static const struct alps_model_info alps_model_data[] = { { { 0x32, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */ @@ -845,6 +846,185 @@ static void alps_process_packet_v4(struct psmouse *psmouse) alps_report_semi_mt_data(psmouse, f->fingers); } +static bool alps_is_valid_package_v7(struct psmouse *psmouse) +{ + switch (psmouse->pktcnt) { + case 3: + return (psmouse->packet[2] & 0x40) == 0x40; + case 4: + return (psmouse->packet[3] & 0x48) == 0x48; + case 6: + return (psmouse->packet[5] & 0x40) == 0x00; + } + return true; +} + +static unsigned char alps_get_packet_id_v7(char *byte) +{ + unsigned char packet_id; + + if (byte[4] & 0x40) + packet_id = V7_PACKET_ID_TWO; + else if (byte[4] & 0x01) + packet_id = V7_PACKET_ID_MULTI; + else if ((byte[0] & 0x10) && !(byte[4] & 0x43)) + packet_id = V7_PACKET_ID_NEW; + else if (byte[1] == 0x00 && byte[4] == 0x00) + packet_id = V7_PACKET_ID_IDLE; + else + packet_id = V7_PACKET_ID_UNKNOWN; + + return packet_id; +} + +static void alps_get_finger_coordinate_v7(struct input_mt_pos *mt, + unsigned char *pkt, + unsigned char pkt_id) +{ + mt[0].x = ((pkt[2] & 0x80) << 4); + mt[0].x |= ((pkt[2] & 0x3F) << 5); + mt[0].x |= ((pkt[3] & 0x30) >> 1); + mt[0].x |= (pkt[3] & 0x07); + mt[0].y = (pkt[1] << 3) | (pkt[0] & 0x07); + + mt[1].x = ((pkt[3] & 0x80) << 4); + mt[1].x |= ((pkt[4] & 0x80) << 3); + mt[1].x |= ((pkt[4] & 0x3F) << 4); + mt[1].y = ((pkt[5] & 0x80) << 3); + mt[1].y |= ((pkt[5] & 0x3F) << 4); + + switch (pkt_id) { + case V7_PACKET_ID_TWO: + mt[1].x &= ~0x000F; + mt[1].y |= 0x000F; + break; + + case V7_PACKET_ID_MULTI: + mt[1].x &= ~0x003F; + mt[1].y &= ~0x0020; + mt[1].y |= ((pkt[4] & 0x02) << 4); + mt[1].y |= 0x001F; + break; + + case V7_PACKET_ID_NEW: + mt[1].x &= ~0x003F; + mt[1].x |= (pkt[0] & 0x20); + mt[1].y |= 0x000F; + break; + } + + mt[0].y = 0x7FF - mt[0].y; + mt[1].y = 0x7FF - mt[1].y; +} + +static int alps_get_mt_count(struct input_mt_pos *mt) +{ + int i; + + for (i = 0; i < MAX_TOUCHES && mt[i].x != 0 && mt[i].y != 0; i++) + /* empty */; + + return i; +} + +static int alps_decode_packet_v7(struct alps_fields *f, + unsigned char *p, + struct psmouse *psmouse) +{ + unsigned char pkt_id; + + pkt_id = alps_get_packet_id_v7(p); + if (pkt_id == V7_PACKET_ID_IDLE) + return 0; + if (pkt_id == V7_PACKET_ID_UNKNOWN) + return -1; + + alps_get_finger_coordinate_v7(f->mt, p, pkt_id); + + if (pkt_id == V7_PACKET_ID_TWO || pkt_id == V7_PACKET_ID_MULTI) { + f->left = (p[0] & 0x80) >> 7; + f->right = (p[0] & 0x20) >> 5; + f->middle = (p[0] & 0x10) >> 4; + } + + if (pkt_id == V7_PACKET_ID_TWO) + f->fingers = alps_get_mt_count(f->mt); + else if (pkt_id == V7_PACKET_ID_MULTI) + f->fingers = 3 + (p[5] & 0x03); + + return 0; +} + +static void alps_process_trackstick_packet_v7(struct psmouse *psmouse) +{ + struct alps_data *priv = psmouse->private; + unsigned char *packet = psmouse->packet; + struct input_dev *dev2 = priv->dev2; + int x, y, z, left, right, middle; + + /* + * b7 b6 b5 b4 b3 b2 b1 b0 + * Byte0 0 1 0 0 1 0 0 0 + * Byte1 1 1 * * 1 M R L + * Byte2 X7 1 X5 X4 X3 X2 X1 X0 + * Byte3 Z6 1 Y6 X6 1 Y2 Y1 Y0 + * Byte4 Y7 0 Y5 Y4 Y3 1 1 0 + * Byte5 T&P 0 Z5 Z4 Z3 Z2 Z1 Z0 + * M / R / L: Middle / Right / Left button + */ + + x = ((packet[2] & 0xbf)) | ((packet[3] & 0x10) << 2); + y = (packet[3] & 0x07) | (packet[4] & 0xb8) | + ((packet[3] & 0x20) << 1); + z = (packet[5] & 0x3f) | ((packet[3] & 0x80) >> 1); + + left = (packet[1] & 0x01); + right = (packet[1] & 0x02) >> 1; + middle = (packet[1] & 0x04) >> 2; + + /* Divide 2 since trackpoint's speed is too fast */ + input_report_rel(dev2, REL_X, (char)x / 2); + input_report_rel(dev2, REL_Y, -((char)y / 2)); + + input_report_key(dev2, BTN_LEFT, left); + input_report_key(dev2, BTN_RIGHT, right); + input_report_key(dev2, BTN_MIDDLE, middle); + + input_sync(dev2); +} + +static void alps_process_touchpad_packet_v7(struct psmouse *psmouse) +{ + struct alps_data *priv = psmouse->private; + struct input_dev *dev = psmouse->dev; + struct alps_fields *f = &priv->f; + + memset(f, 0, sizeof(*f)); + + if (priv->decode_fields(f, psmouse->packet, psmouse)) + return; + + alps_report_mt_data(psmouse, alps_get_mt_count(f->mt)); + + 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_sync(dev); +} + +static void alps_process_packet_v7(struct psmouse *psmouse) +{ + unsigned char *packet = psmouse->packet; + + if (packet[0] == 0x48 && (packet[4] & 0x47) == 0x06) + alps_process_trackstick_packet_v7(psmouse); + else + alps_process_touchpad_packet_v7(psmouse); +} + static void alps_report_bare_ps2_packet(struct psmouse *psmouse, unsigned char packet[], bool report_buttons) @@ -1009,6 +1189,14 @@ 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)) { + psmouse_dbg(psmouse, "refusing packet[%i] = %x\n", + psmouse->pktcnt - 1, + psmouse->packet[psmouse->pktcnt - 1]); + return PSMOUSE_BAD_DATA; + } + if (psmouse->pktcnt == psmouse->pktsize) { priv->process_packet(psmouse); return PSMOUSE_FULL_PACKET; @@ -1121,6 +1309,22 @@ static int alps_rpt_cmd(struct psmouse *psmouse, int init_command, return 0; } +static bool alps_check_valid_firmware_id(unsigned char id[]) +{ + if (id[0] == 0x73) + return true; + + if (id[0] == 0x88 && + (id[1] == 0x07 || + id[1] == 0x08 || + (id[1] & 0xf0) == 0xb0 || + (id[1] & 0xf0) == 0xc0)) { + return true; + } + + return false; +} + static int alps_enter_command_mode(struct psmouse *psmouse) { unsigned char param[4]; @@ -1130,8 +1334,7 @@ static int alps_enter_command_mode(struct psmouse *psmouse) return -1; } - if ((param[0] != 0x88 || (param[1] != 0x07 && param[1] != 0x08)) && - param[0] != 0x73) { + if (!alps_check_valid_firmware_id(param)) { psmouse_dbg(psmouse, "unknown response while entering command mode\n"); return -1; @@ -1785,6 +1988,32 @@ static int alps_hw_init_dolphin_v1(struct psmouse *psmouse) return 0; } +static int alps_hw_init_v7(struct psmouse *psmouse) +{ + struct ps2dev *ps2dev = &psmouse->ps2dev; + int reg_val, ret = -1; + + if (alps_enter_command_mode(psmouse) || + alps_command_mode_read_reg(psmouse, 0xc2d9) == -1) + goto error; + + if (alps_command_mode_write_reg(psmouse, 0xc2c9, 0x64)) + goto error; + + reg_val = alps_command_mode_read_reg(psmouse, 0xc2c4); + if (reg_val == -1) + goto error; + if (__alps_command_mode_write_reg(psmouse, reg_val | 0x02)) + goto error; + + alps_exit_command_mode(psmouse); + return ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE); + +error: + alps_exit_command_mode(psmouse); + return ret; +} + static void alps_set_defaults(struct alps_data *priv) { priv->byte0 = 0x8f; @@ -1843,6 +2072,21 @@ static void alps_set_defaults(struct alps_data *priv) priv->x_max = 2047; priv->y_max = 1535; break; + case ALPS_PROTO_V7: + 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->nibble_commands = alps_v3_nibble_commands; + priv->addr_command = PSMOUSE_CMD_RESET_WRAP; + priv->x_max = 0xfff; + priv->y_max = 0x7ff; + priv->byte0 = 0x48; + priv->mask0 = 0x48; + + if (priv->fw_ver[1] != 0xba) + priv->flags |= ALPS_BUTTONPAD; + break; } } @@ -1914,6 +2158,12 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv) return -EIO; else return 0; + } else if (ec[0] == 0x88 && + ((ec[1] & 0xf0) == 0xb0 || (ec[1] & 0xf0) == 0xc0)) { + priv->proto_version = ALPS_PROTO_V7; + alps_set_defaults(priv); + + return 0; } else if (ec[0] == 0x88 && ec[1] == 0x08) { priv->proto_version = ALPS_PROTO_V3; alps_set_defaults(priv); @@ -1985,6 +2235,10 @@ static void alps_set_abs_params_mt(struct alps_data *priv, 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); } int alps_init(struct psmouse *psmouse) @@ -2030,7 +2284,9 @@ int alps_init(struct psmouse *psmouse) dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS); priv->set_abs_params(priv, dev1); - input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0); + /* 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); @@ -2047,6 +2303,9 @@ int alps_init(struct psmouse *psmouse) dev1->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1); dev1->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2); dev1->keybit[BIT_WORD(BTN_3)] |= BIT_MASK(BTN_3); + } else if (priv->flags & ALPS_BUTTONPAD) { + set_bit(INPUT_PROP_BUTTONPAD, dev1->propbit); + clear_bit(BTN_RIGHT, dev1->keybit); } else { dev1->keybit[BIT_WORD(BTN_MIDDLE)] |= BIT_MASK(BTN_MIDDLE); } diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index e3d0f09aeeb3..a98ac9ba5043 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h @@ -20,6 +20,7 @@ #define ALPS_PROTO_V4 4 #define ALPS_PROTO_V5 5 #define ALPS_PROTO_V6 6 +#define ALPS_PROTO_V7 7 /* t3btl t4s */ #define MAX_TOUCHES 2 @@ -27,6 +28,23 @@ #define DOLPHIN_PROFILE_XOFFSET 8 /* x-electrode offset */ #define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode offset */ +/* + * enum V7_PACKET_ID - defines the packet type for V7 + * V7_PACKET_ID_IDLE: There's no finger and no button activity. + * V7_PACKET_ID_TWO: There's one or two non-resting fingers on touchpad + * or there's button activities. + * V7_PACKET_ID_MULTI: There are at least three non-resting fingers. + * V7_PACKET_ID_NEW: The finger position in slot is not continues from + * previous packet. +*/ +enum V7_PACKET_ID { + V7_PACKET_ID_IDLE, + V7_PACKET_ID_TWO, + V7_PACKET_ID_MULTI, + V7_PACKET_ID_NEW, + V7_PACKET_ID_UNKNOWN, +}; + /** * struct alps_model_info - touchpad ID table * @signature: E7 response string to match. -- cgit v1.2.3 From f3f33c6776997db9d377ff3f1b759869f988d25e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 29 Jul 2014 11:22:07 -0700 Subject: Input: alps - Rushmore and v7 resolution support Add support for querying the physical size from the touchpad for Rushmore and v7 touchpads, and use that to tell userspace the device resolution. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/input/mouse/alps.h | 2 ++ 2 files changed, 50 insertions(+) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 76d372f0084c..a59a1a64b674 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -1792,6 +1792,45 @@ error: return -1; } +static int alps_get_v3_v7_resolution(struct psmouse *psmouse, int reg_pitch) +{ + int reg, x_pitch, y_pitch, x_electrode, y_electrode, x_phys, y_phys; + struct alps_data *priv = psmouse->private; + + reg = alps_command_mode_read_reg(psmouse, reg_pitch); + if (reg < 0) + return reg; + + x_pitch = (char)(reg << 4) >> 4; /* sign extend lower 4 bits */ + x_pitch = 50 + 2 * x_pitch; /* In 0.1 mm units */ + + y_pitch = (char)reg >> 4; /* sign extend upper 4 bits */ + y_pitch = 36 + 2 * y_pitch; /* In 0.1 mm units */ + + reg = alps_command_mode_read_reg(psmouse, reg_pitch + 1); + if (reg < 0) + return reg; + + x_electrode = (char)(reg << 4) >> 4; /* sign extend lower 4 bits */ + x_electrode = 17 + x_electrode; + + y_electrode = (char)reg >> 4; /* sign extend upper 4 bits */ + y_electrode = 13 + y_electrode; + + x_phys = x_pitch * (x_electrode - 1); /* In 0.1 mm units */ + y_phys = y_pitch * (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 */ + + psmouse_dbg(psmouse, + "pitch %dx%d num-electrodes %dx%d physical size %dx%d mm res %dx%d\n", + x_pitch, y_pitch, x_electrode, y_electrode, + x_phys / 10, y_phys / 10, priv->x_res, priv->y_res); + + return 0; +} + static int alps_hw_init_rushmore_v3(struct psmouse *psmouse) { struct alps_data *priv = psmouse->private; @@ -1812,6 +1851,9 @@ static int alps_hw_init_rushmore_v3(struct psmouse *psmouse) alps_command_mode_write_reg(psmouse, 0xc2cb, 0x00)) goto error; + if (alps_get_v3_v7_resolution(psmouse, 0xc2da)) + goto error; + reg_val = alps_command_mode_read_reg(psmouse, 0xc2c6); if (reg_val == -1) goto error; @@ -1997,6 +2039,9 @@ static int alps_hw_init_v7(struct psmouse *psmouse) alps_command_mode_read_reg(psmouse, 0xc2d9) == -1) goto error; + if (alps_get_v3_v7_resolution(psmouse, 0xc397)) + goto error; + if (alps_command_mode_write_reg(psmouse, 0xc2c9, 0x64)) goto error; @@ -2230,6 +2275,9 @@ static void alps_set_abs_params_mt(struct alps_data *priv, 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_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); diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index a98ac9ba5043..66240b47819a 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h @@ -174,6 +174,8 @@ struct alps_data { int y_max; int x_bits; int y_bits; + unsigned int x_res; + unsigned int y_res; int (*hw_init)(struct psmouse *psmouse); void (*process_packet)(struct psmouse *psmouse); -- cgit v1.2.3