From aab9cf7b0349b2f6f3d8a32d3f2414981777ebdc Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 20 May 2015 14:38:33 -0700 Subject: Input: alps - change alps_decode_rushmore to do all decoding itself Change alps_decode_rushmore to do all decoding itself, rather then relying on alps_decode_pinnacle and then overriding some fields + or-ing in some bits. This is a preparation patch for modifying the decode functions to properly differentiate between position and bitmap packets. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 15d6bffdea77..f4ba73b81d31 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -597,13 +597,25 @@ 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; + 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); + + 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; } -- cgit v1.2.3 From a839cd579b64e41779a24c691d0c88c6a16c63e0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 20 May 2015 14:39:21 -0700 Subject: Input: alps - only set fields that are actually present Pinnacle / Rushmore packets contain either position info, or bitmap info, never both. So far we've in essence been storing garbage in the position / bitmap fields of the fields struct when decoding a bitmap / pos packet. We've been relying on the following sequence to get away with this: 1) Decode bitmap packet 2) Process bitmap packet 3) Decode position packet 4) Use position / button info This patch allows us to change this sequence, which will allow using the position info when processing the bitmap for more accurate results. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 62 ++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 29 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index f4ba73b81d31..942ee08ce6b4 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -576,20 +576,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; } @@ -600,22 +602,24 @@ static int alps_decode_rushmore(struct alps_fields *f, unsigned char *p, 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) | - ((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); - - 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); + 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; } -- cgit v1.2.3 From 44b77f38dce59f57a679083df12509deab02cfcc Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 20 May 2015 14:40:06 -0700 Subject: Input: alps - decode the position packet first We should decode the position packet before the packet with the bitmap data. This way we can use the more accurate position info in process_bitmap() to get better results. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 942ee08ce6b4..d1488db6d149 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -688,24 +688,17 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse) */ if (f->is_mp) { fingers = f->fingers; + /* + * 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 (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. @@ -873,6 +866,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; @@ -887,14 +888,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); } -- cgit v1.2.3 From 4dd265730710bd881c45d6ccf41050c3738ffccd Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 20 May 2015 14:41:10 -0700 Subject: Input: alps - use more accurate coordinates for first touch in semi-mt mode All alps semi-mt touchpads give us the following data when 2 (or more) fingers are touching: 1 more or less accurate touch for the first finger down, and a bitmap with columns and rows in which 1 or more fingers are seen resulting in a crude (low res) bounding box. So far for v3, rushmore and v4 touchpads we've been reporting the coordinates of 2 opposite corners of the box when 2 fingers are touching. Ignoring the much better resolution data given in the normal position packet. This commit actually uses this data for the first touch, figures out which corner of the bounding box is closest to the first touch, and reports the coordinates of the opposite corner for the second touch, resulting in much better data for the first touch and for the single touch pointer-emulation events. This approach is similar to the one in alps_process_bitmap_dolphin, that function takes the single accurate touch info, calculates the distance to the center of the bounding box, and then puts the 2nd touch mirrored to the center. The downside of that approach is that if both touches move slowly in the same direction, the bounding box will stay the same for a while (as it is low res) and the second touch will thus been seen moving in the opposite direction until the bounding box actually changes, and then the second touch snaps to its new position resulting in a saw tooth pattern in the coordinates for the second touch, hence this new approach. This commit fixes 2 finger scrolling being choppy / jumpy on these touchpads. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 59 ++++++++++++++++++++++++++++++++++++++++------ drivers/input/mouse/alps.h | 1 + 2 files changed, 53 insertions(+), 7 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index d1488db6d149..220acb63ffd7 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -388,9 +388,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; @@ -421,26 +422,69 @@ 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; + 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; } @@ -477,6 +521,7 @@ 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); diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index 6dfdccc3a7c6..d37f814dc447 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; -- cgit v1.2.3 From 1662c03387a777be0a00efaf8665de77bc898158 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 20 May 2015 14:42:15 -0700 Subject: Input: alps - do not use input-mt finger tracking for semi-mt devices With the recent process_bitmap() changes all semi-mt devices always report the first finger down in slot 0, so stop using input-mt finger tracking for these. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 220acb63ffd7..f066761e8985 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -524,7 +524,11 @@ static void alps_report_semi_mt_data(struct psmouse *psmouse, int fingers) 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); @@ -2826,7 +2830,7 @@ static void alps_set_abs_params_mt(struct alps_data *priv, 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, -- cgit v1.2.3 From 688ea364b2e73ae4d757e550ec06663a4903b334 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 20 May 2015 14:42:50 -0700 Subject: Input: alps - rename alps_set_abs_params_mt to alps_set_abs_params_semi_mt Rename alps_set_abs_params_mt to alps_set_abs_params_semi_mt, to make it clear that it is only (to be) used for semi-mt devices. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index f066761e8985..e9e13cd026d2 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -159,8 +159,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, @@ -2606,7 +2606,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; @@ -2615,7 +2615,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; @@ -2631,7 +2631,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; @@ -2640,7 +2640,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; @@ -2822,8 +2822,8 @@ 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); -- cgit v1.2.3 From dccf1dd8458236a28552510b83a06a8cc0f1c473 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 20 May 2015 14:43:09 -0700 Subject: Input: alps - use the generic process_bitmap function for v5 touchpads Now that the generic process_bitmap function has been improved to offer accurate coordinates for the first touch we can use it for v5 (dolphin) touchpads too. Besides being a nice code cleanup this also fixes the saw tooth pattern in the coordinates for the second touch the dolphin specific version had. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 74 ++++++++-------------------------------------- 1 file changed, 12 insertions(+), 62 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index e9e13cd026d2..4e1af89c7749 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -302,53 +302,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, @@ -376,7 +329,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. * @@ -454,8 +407,15 @@ static int alps_process_bitmap(struct alps_data *priv, (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) { + /* 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; } @@ -742,18 +702,8 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse) * data, so we need to do decode it first. */ priv->decode_fields(f, priv->multi_data, psmouse); - - 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 */ - } else { - /* - * Since Dolphin's finger number is reliable, - * there is no need to compare with bmap_fn. - */ - alps_process_bitmap_dolphin(priv, f); - } + if (alps_process_bitmap(priv, f) == 0) + fingers = 0; /* Use st data */ } else { priv->multi_packet = 0; } -- cgit v1.2.3 From b53d750884b26561a3e37f1a49775540120930e5 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 14 Apr 2015 17:46:43 -0700 Subject: Input: cyapa - do not set otherwise unused variable As the name suggests, always_unused argument in cyapa_gen3_set_power_mode() is never used, so there is no reason for setting it to 0. Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/cyapa_gen3.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/cyapa_gen3.c b/drivers/input/mouse/cyapa_gen3.c index 1e2291c378fe..3faf01c1b191 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; -- cgit v1.2.3 From bde304575f3ecaa9570a9329196dffaadf3adafa Mon Sep 17 00:00:00 2001 From: Khem Raj Date: Fri, 22 May 2015 09:56:29 -0700 Subject: Input: sentelic - use "static inline" instead of "inline" gcc-5 defaults to gnu11 which used c99 inline semantics in c99 'inline' is not externally visible unlike gnu89, therefore we use 'static inline' which has same semantics between gnu89 and c99 Signed-off-by: Khem Raj Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/sentelic.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/sentelic.h b/drivers/input/mouse/sentelic.h index aa697ece405b..42df9e3beae8 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; } -- cgit v1.2.3 From 7debcbb135f9d0e74596039d648f1ff2d87a9305 Mon Sep 17 00:00:00 2001 From: Shailendra Verma Date: Tue, 26 May 2015 13:44:06 -0700 Subject: Input: cyapa - fix a few typos in comments Signed-off-by: Shailendra Verma Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/cyapa_gen5.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c index 5b611dd71e79..afc39e799da2 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) -- cgit v1.2.3 From feb9eba80cce00c73a79ba22a5962657afadc476 Mon Sep 17 00:00:00 2001 From: Shailendra Verma Date: Tue, 26 May 2015 14:07:12 -0700 Subject: Input: psmouse - use true instead of 1 for boolean values The variable psmouse_smartscroll is bool type so assigning true instead of 1. Signed-off-by: Shailendra Verma Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/psmouse-base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 5bb1658f60c7..7c4ba43d253e 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -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."); -- cgit v1.2.3 From e002273b37821941623d231b5c7346778b486c9b Mon Sep 17 00:00:00 2001 From: Shailendra Verma Date: Tue, 26 May 2015 14:08:37 -0700 Subject: Input: synaptics_i2c - use proper boolean values The variable no_decel is bool type so assigning "true" instead of "1". Also, synaptics_i2c_get_input() has bool return type, so let's use "false" there. Signed-off-by: Shailendra Verma Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics_i2c.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c index 878f18498f3b..ffceedcaf3c8 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); -- cgit v1.2.3 From 85919a00e55f90e72405e707eb23c930b8d8db91 Mon Sep 17 00:00:00 2001 From: Dmitry Tunin Date: Sun, 31 May 2015 11:26:49 -0700 Subject: Input: focaltech - report finger width to userspace Focaltech touchpads report finger width in packet[5] of absolute packet. Range for width in raw format is 0x10 - 0x70. Second half-byte is always 0. 0xff is reported, when a large contact area is detected. This can be handled in userspace. Signed-off-by: Dmitry Tunin Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/focaltech.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/focaltech.c b/drivers/input/mouse/focaltech.c index 23d259416f2f..4d5576de81be 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); } -- cgit v1.2.3 From 12018ac3d679d6a3c6c738ac805797fe4dd43912 Mon Sep 17 00:00:00 2001 From: Duson Lin Date: Mon, 8 Jun 2015 16:39:35 -0700 Subject: Input: elan_i2c - add support for multi IC type and iap format In order to support multiple IC types for i2c/smbus protocol, add get ic type command and use this data when checking firmware page count and signature address. Signed-off-by: Duson Lin Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c.h | 5 ++-- drivers/input/mouse/elan_i2c_core.c | 45 ++++++++++++++++++++++++++++++++---- drivers/input/mouse/elan_i2c_i2c.c | 4 +++- drivers/input/mouse/elan_i2c_smbus.c | 6 +++-- 4 files changed, 49 insertions(+), 11 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/elan_i2c.h b/drivers/input/mouse/elan_i2c.h index 6d5f8a4c1748..ff622a1b0c2c 100644 --- a/drivers/input/mouse/elan_i2c.h +++ b/drivers/input/mouse/elan_i2c.h @@ -33,9 +33,7 @@ #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 +56,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 fd5068b2542d..b4cfd18cdaca 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) - * Version: 1.5.7 + * Version: 1.5.8 * * 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.8" #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]; @@ -454,7 +489,7 @@ static ssize_t elan_sysfs_update_fw(struct device *dev, } /* 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, diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c index a0acbbf83bfd..683c840c9dd7 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 30ab80dbcdd6..ff36a366b2aa 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; } -- cgit v1.2.3 From 7b9f1830745cb3ad9e0f3774e83900610cedd39c Mon Sep 17 00:00:00 2001 From: Charlie Mooney Date: Mon, 8 Jun 2015 16:48:23 -0700 Subject: Input: elan_i2c - add product IDs FW names Previously the elan_i2c touchpad driver would simply request the firmware "/lib/firmware/elan_i2c.bin", which does not work well if there are multiple such devices in the system. Let's append the "product ID" (by using the same function as the sysfs interface for consistency) to the filename. This results in filenames of the form "/lib/firmware/elan_i2c_72.0.bin", allowing you to support multiple elan_i2c touchpads on the same device by simply naming each device's FW with its corresponding product ID. This way when you trigger a fw update the driver will load the correct binary. Signed-off-by: Charlie Mooney Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c.h | 3 ++- drivers/input/mouse/elan_i2c_core.c | 22 ++++++++++++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/elan_i2c.h b/drivers/input/mouse/elan_i2c.h index ff622a1b0c2c..73670f2aebfd 100644 --- a/drivers/input/mouse/elan_i2c.h +++ b/drivers/input/mouse/elan_i2c.h @@ -28,7 +28,8 @@ #define ETP_PRESSURE_OFFSET 25 /* IAP Firmware handling */ -#define ETP_FW_NAME "elan_i2c.bin" +#define ETP_PRODUCT_ID_FORMAT_STRING "%d.0" +#define ETP_FW_NAME "elan_i2c_" ETP_PRODUCT_ID_FORMAT_STRING ".bin" #define ETP_IAP_START_ADDR 0x0083 #define ETP_FW_IAP_PAGE_ERR (1 << 5) #define ETP_FW_IAP_INTF_ERR (1 << 4) diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index b4cfd18cdaca..62641f2adaf7 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) - * Version: 1.5.8 + * 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.8" +#define ELAN_DRIVER_VERSION "1.5.9" #define ETP_MAX_PRESSURE 255 #define ETP_FWIDTH_REDUCE 90 #define ETP_FINGER_WIDTH 15 @@ -438,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, @@ -477,14 +478,23 @@ 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 = request_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 = request_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; } -- cgit v1.2.3