diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2014-08-15 06:02:58 (GMT) |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2014-08-15 06:02:58 (GMT) |
commit | 91167e1914673972511617b6f4165bb12c3e0dcf (patch) | |
tree | 0d8d2b997d3aef7dc23eaabadef51ab29de88d23 /drivers/input | |
parent | a6b48699ae50ccce700506ced863ba1f5ce2af11 (diff) | |
parent | 3361a97601f243f1842bee6ca709e399f47b2ce3 (diff) | |
download | linux-91167e1914673972511617b6f4165bb12c3e0dcf.tar.xz |
Merge branch 'next' into for-linus
Prepare second round of input updates for 3.17.
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/input-mt.c | 38 | ||||
-rw-r--r-- | drivers/input/joystick/xpad.c | 174 | ||||
-rw-r--r-- | drivers/input/keyboard/cap1106.c | 8 | ||||
-rw-r--r-- | drivers/input/mouse/synaptics.c | 72 | ||||
-rw-r--r-- | drivers/input/touchscreen/atmel_mxt_ts.c | 366 | ||||
-rw-r--r-- | drivers/input/touchscreen/edt-ft5x06.c | 1 |
6 files changed, 458 insertions, 201 deletions
diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c index d398f13..c30204f 100644 --- a/drivers/input/input-mt.c +++ b/drivers/input/input-mt.c @@ -237,6 +237,31 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count) EXPORT_SYMBOL(input_mt_report_pointer_emulation); /** + * input_mt_drop_unused() - Inactivate slots not seen in this frame + * @dev: input device with allocated MT slots + * + * Lift all slots not seen since the last call to this function. + */ +void input_mt_drop_unused(struct input_dev *dev) +{ + struct input_mt *mt = dev->mt; + int i; + + if (!mt) + return; + + for (i = 0; i < mt->num_slots; i++) { + if (!input_mt_is_used(mt, &mt->slots[i])) { + input_mt_slot(dev, i); + input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1); + } + } + + mt->frame++; +} +EXPORT_SYMBOL(input_mt_drop_unused); + +/** * input_mt_sync_frame() - synchronize mt frame * @dev: input device with allocated MT slots * @@ -247,27 +272,18 @@ EXPORT_SYMBOL(input_mt_report_pointer_emulation); void input_mt_sync_frame(struct input_dev *dev) { struct input_mt *mt = dev->mt; - struct input_mt_slot *s; bool use_count = false; if (!mt) return; - if (mt->flags & INPUT_MT_DROP_UNUSED) { - for (s = mt->slots; s != mt->slots + mt->num_slots; s++) { - if (input_mt_is_used(mt, s)) - continue; - input_mt_slot(dev, s - mt->slots); - input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1); - } - } + if (mt->flags & INPUT_MT_DROP_UNUSED) + input_mt_drop_unused(dev); if ((mt->flags & INPUT_MT_POINTER) && !(mt->flags & INPUT_MT_SEMI_MT)) use_count = true; input_mt_report_pointer_emulation(dev, use_count); - - mt->frame++; } EXPORT_SYMBOL(input_mt_sync_frame); diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 603fe0d..177602c 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -95,7 +95,8 @@ #define XTYPE_XBOX 0 #define XTYPE_XBOX360 1 #define XTYPE_XBOX360W 2 -#define XTYPE_UNKNOWN 3 +#define XTYPE_XBOXONE 3 +#define XTYPE_UNKNOWN 4 static bool dpad_to_buttons; module_param(dpad_to_buttons, bool, S_IRUGO); @@ -121,6 +122,7 @@ static const struct xpad_device { { 0x045e, 0x0287, "Microsoft Xbox Controller S", 0, XTYPE_XBOX }, { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", 0, XTYPE_XBOX }, { 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 }, + { 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE }, { 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX }, @@ -231,10 +233,12 @@ static const signed short xpad_abs_triggers[] = { -1 }; -/* Xbox 360 has a vendor-specific class, so we cannot match it with only +/* + * Xbox 360 has a vendor-specific class, so we cannot match it with only * USB_INTERFACE_INFO (also specifically refused by USB subsystem), so we * match against vendor id as well. Wired Xbox 360 devices have protocol 1, - * wireless controllers have protocol 129. */ + * wireless controllers have protocol 129. + */ #define XPAD_XBOX360_VENDOR_PROTOCOL(vend,pr) \ .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, \ .idVendor = (vend), \ @@ -245,9 +249,20 @@ static const signed short xpad_abs_triggers[] = { { XPAD_XBOX360_VENDOR_PROTOCOL(vend,1) }, \ { XPAD_XBOX360_VENDOR_PROTOCOL(vend,129) } +/* The Xbox One controller uses subclass 71 and protocol 208. */ +#define XPAD_XBOXONE_VENDOR_PROTOCOL(vend, pr) \ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, \ + .idVendor = (vend), \ + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, \ + .bInterfaceSubClass = 71, \ + .bInterfaceProtocol = (pr) +#define XPAD_XBOXONE_VENDOR(vend) \ + { XPAD_XBOXONE_VENDOR_PROTOCOL(vend, 208) } + static struct usb_device_id xpad_table[] = { { USB_INTERFACE_INFO('X', 'B', 0) }, /* X-Box USB-IF not approved class */ XPAD_XBOX360_VENDOR(0x045e), /* Microsoft X-Box 360 controllers */ + XPAD_XBOXONE_VENDOR(0x045e), /* Microsoft X-Box One controllers */ XPAD_XBOX360_VENDOR(0x046d), /* Logitech X-Box 360 style controllers */ XPAD_XBOX360_VENDOR(0x0738), /* Mad Catz X-Box 360 controllers */ { USB_DEVICE(0x0738, 0x4540) }, /* Mad Catz Beat Pad */ @@ -278,12 +293,10 @@ struct usb_xpad { struct urb *bulk_out; unsigned char *bdata; -#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS) struct urb *irq_out; /* urb for interrupt out report */ unsigned char *odata; /* output data */ dma_addr_t odata_dma; struct mutex odata_mutex; -#endif #if defined(CONFIG_JOYSTICK_XPAD_LEDS) struct xpad_led *led; @@ -470,6 +483,105 @@ static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned cha xpad360_process_packet(xpad, cmd, &data[4]); } +/* + * xpadone_process_buttons + * + * Process a button update packet from an Xbox one controller. + */ +static void xpadone_process_buttons(struct usb_xpad *xpad, + struct input_dev *dev, + unsigned char *data) +{ + /* menu/view buttons */ + input_report_key(dev, BTN_START, data[4] & 0x04); + input_report_key(dev, BTN_SELECT, data[4] & 0x08); + + /* buttons A,B,X,Y */ + input_report_key(dev, BTN_A, data[4] & 0x10); + input_report_key(dev, BTN_B, data[4] & 0x20); + input_report_key(dev, BTN_X, data[4] & 0x40); + input_report_key(dev, BTN_Y, data[4] & 0x80); + + /* digital pad */ + if (xpad->mapping & MAP_DPAD_TO_BUTTONS) { + /* dpad as buttons (left, right, up, down) */ + input_report_key(dev, BTN_TRIGGER_HAPPY1, data[5] & 0x04); + input_report_key(dev, BTN_TRIGGER_HAPPY2, data[5] & 0x08); + input_report_key(dev, BTN_TRIGGER_HAPPY3, data[5] & 0x01); + input_report_key(dev, BTN_TRIGGER_HAPPY4, data[5] & 0x02); + } else { + input_report_abs(dev, ABS_HAT0X, + !!(data[5] & 0x08) - !!(data[5] & 0x04)); + input_report_abs(dev, ABS_HAT0Y, + !!(data[5] & 0x02) - !!(data[5] & 0x01)); + } + + /* TL/TR */ + input_report_key(dev, BTN_TL, data[5] & 0x10); + input_report_key(dev, BTN_TR, data[5] & 0x20); + + /* stick press left/right */ + input_report_key(dev, BTN_THUMBL, data[5] & 0x40); + input_report_key(dev, BTN_THUMBR, data[5] & 0x80); + + if (!(xpad->mapping & MAP_STICKS_TO_NULL)) { + /* left stick */ + input_report_abs(dev, ABS_X, + (__s16) le16_to_cpup((__le16 *)(data + 10))); + input_report_abs(dev, ABS_Y, + ~(__s16) le16_to_cpup((__le16 *)(data + 12))); + + /* right stick */ + input_report_abs(dev, ABS_RX, + (__s16) le16_to_cpup((__le16 *)(data + 14))); + input_report_abs(dev, ABS_RY, + ~(__s16) le16_to_cpup((__le16 *)(data + 16))); + } + + /* triggers left/right */ + if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) { + input_report_key(dev, BTN_TL2, + (__u16) le16_to_cpup((__le16 *)(data + 6))); + input_report_key(dev, BTN_TR2, + (__u16) le16_to_cpup((__le16 *)(data + 8))); + } else { + input_report_abs(dev, ABS_Z, + (__u16) le16_to_cpup((__le16 *)(data + 6))); + input_report_abs(dev, ABS_RZ, + (__u16) le16_to_cpup((__le16 *)(data + 8))); + } + + input_sync(dev); +} + +/* + * xpadone_process_packet + * + * Completes a request by converting the data into events for the + * input subsystem. This version is for the Xbox One controller. + * + * The report format was gleaned from + * https://github.com/kylelemons/xbox/blob/master/xbox.go + */ + +static void xpadone_process_packet(struct usb_xpad *xpad, + u16 cmd, unsigned char *data) +{ + struct input_dev *dev = xpad->dev; + + switch (data[0]) { + case 0x20: + xpadone_process_buttons(xpad, dev, data); + break; + + case 0x07: + /* the xbox button has its own special report */ + input_report_key(dev, BTN_MODE, data[4] & 0x01); + input_sync(dev); + break; + } +} + static void xpad_irq_in(struct urb *urb) { struct usb_xpad *xpad = urb->context; @@ -502,6 +614,9 @@ static void xpad_irq_in(struct urb *urb) case XTYPE_XBOX360W: xpad360w_process_packet(xpad, 0, xpad->idata); break; + case XTYPE_XBOXONE: + xpadone_process_packet(xpad, 0, xpad->idata); + break; default: xpad_process_packet(xpad, 0, xpad->idata); } @@ -535,7 +650,6 @@ static void xpad_bulk_out(struct urb *urb) } } -#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS) static void xpad_irq_out(struct urb *urb) { struct usb_xpad *xpad = urb->context; @@ -573,6 +687,7 @@ exit: static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) { struct usb_endpoint_descriptor *ep_irq_out; + int ep_irq_out_idx; int error; if (xpad->xtype == XTYPE_UNKNOWN) @@ -593,7 +708,10 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) goto fail2; } - ep_irq_out = &intf->cur_altsetting->endpoint[1].desc; + /* Xbox One controller has in/out endpoints swapped. */ + ep_irq_out_idx = xpad->xtype == XTYPE_XBOXONE ? 0 : 1; + ep_irq_out = &intf->cur_altsetting->endpoint[ep_irq_out_idx].desc; + usb_fill_int_urb(xpad->irq_out, xpad->udev, usb_sndintpipe(xpad->udev, ep_irq_out->bEndpointAddress), xpad->odata, XPAD_PKT_LEN, @@ -621,11 +739,6 @@ static void xpad_deinit_output(struct usb_xpad *xpad) xpad->odata, xpad->odata_dma); } } -#else -static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) { return 0; } -static void xpad_deinit_output(struct usb_xpad *xpad) {} -static void xpad_stop_output(struct usb_xpad *xpad) {} -#endif #ifdef CONFIG_JOYSTICK_XPAD_FF static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect) @@ -692,7 +805,7 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect static int xpad_init_ff(struct usb_xpad *xpad) { - if (xpad->xtype == XTYPE_UNKNOWN) + if (xpad->xtype == XTYPE_UNKNOWN || xpad->xtype == XTYPE_XBOXONE) return 0; input_set_capability(xpad->dev, EV_FF, FF_RUMBLE); @@ -801,6 +914,14 @@ static int xpad_open(struct input_dev *dev) if (usb_submit_urb(xpad->irq_in, GFP_KERNEL)) return -EIO; + if (xpad->xtype == XTYPE_XBOXONE) { + /* Xbox one controller needs to be initialized. */ + xpad->odata[0] = 0x05; + xpad->odata[1] = 0x20; + xpad->irq_out->transfer_buffer_length = 2; + return usb_submit_urb(xpad->irq_out, GFP_KERNEL); + } + return 0; } @@ -816,6 +937,7 @@ static void xpad_close(struct input_dev *dev) static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs) { + struct usb_xpad *xpad = input_get_drvdata(input_dev); set_bit(abs, input_dev->absbit); switch (abs) { @@ -827,7 +949,10 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs) break; case ABS_Z: case ABS_RZ: /* the triggers (if mapped to axes) */ - input_set_abs_params(input_dev, abs, 0, 255, 0, 0); + if (xpad->xtype == XTYPE_XBOXONE) + input_set_abs_params(input_dev, abs, 0, 1023, 0, 0); + else + input_set_abs_params(input_dev, abs, 0, 255, 0, 0); break; case ABS_HAT0X: case ABS_HAT0Y: /* the d-pad (only if dpad is mapped to axes */ @@ -842,6 +967,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id struct usb_xpad *xpad; struct input_dev *input_dev; struct usb_endpoint_descriptor *ep_irq_in; + int ep_irq_in_idx; int i, error; for (i = 0; xpad_device[i].idVendor; i++) { @@ -850,6 +976,16 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id break; } + if (xpad_device[i].xtype == XTYPE_XBOXONE && + intf->cur_altsetting->desc.bInterfaceNumber != 0) { + /* + * The Xbox One controller lists three interfaces all with the + * same interface class, subclass and protocol. Differentiate by + * interface number. + */ + return -ENODEV; + } + xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL); input_dev = input_allocate_device(); if (!xpad || !input_dev) { @@ -920,7 +1056,8 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id __set_bit(xpad_common_btn[i], input_dev->keybit); /* set up model-specific ones */ - if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W) { + if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W || + xpad->xtype == XTYPE_XBOXONE) { for (i = 0; xpad360_btn[i] >= 0; i++) __set_bit(xpad360_btn[i], input_dev->keybit); } else { @@ -933,7 +1070,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id __set_bit(xpad_btn_pad[i], input_dev->keybit); } else { for (i = 0; xpad_abs_pad[i] >= 0; i++) - xpad_set_up_abs(input_dev, xpad_abs_pad[i]); + xpad_set_up_abs(input_dev, xpad_abs_pad[i]); } if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) { @@ -956,7 +1093,10 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id if (error) goto fail5; - ep_irq_in = &intf->cur_altsetting->endpoint[0].desc; + /* Xbox One controller has in/out endpoints swapped. */ + ep_irq_in_idx = xpad->xtype == XTYPE_XBOXONE ? 1 : 0; + ep_irq_in = &intf->cur_altsetting->endpoint[ep_irq_in_idx].desc; + usb_fill_int_urb(xpad->irq_in, udev, usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress), xpad->idata, XPAD_PKT_LEN, xpad_irq_in, diff --git a/drivers/input/keyboard/cap1106.c b/drivers/input/keyboard/cap1106.c index f7d7a0d..180b184 100644 --- a/drivers/input/keyboard/cap1106.c +++ b/drivers/input/keyboard/cap1106.c @@ -64,7 +64,7 @@ struct cap1106_priv { struct input_dev *idev; /* config */ - unsigned int keycodes[CAP1106_NUM_CHN]; + unsigned short keycodes[CAP1106_NUM_CHN]; }; static const struct reg_default cap1106_reg_defaults[] = { @@ -272,6 +272,12 @@ static int cap1106_i2c_probe(struct i2c_client *i2c_client, for (i = 0; i < CAP1106_NUM_CHN; i++) __set_bit(priv->keycodes[i], priv->idev->keybit); + __clear_bit(KEY_RESERVED, priv->idev->keybit); + + priv->idev->keycode = priv->keycodes; + priv->idev->keycodesize = sizeof(priv->keycodes[0]); + priv->idev->keycodemax = ARRAY_SIZE(priv->keycodes); + priv->idev->id.vendor = CAP1106_MANUFACTURER_ID; priv->idev->id.product = CAP1106_PRODUCT_ID; priv->idev->id.version = rev; diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index ef9e0b8..e8573c6 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -117,6 +117,9 @@ void synaptics_reset(struct psmouse *psmouse) } #ifdef CONFIG_MOUSE_PS2_SYNAPTICS + +static bool cr48_profile_sensor; + struct min_max_quirk { const char * const *pnp_ids; int x_min, x_max, y_min, y_max; @@ -1152,6 +1155,42 @@ static void synaptics_image_sensor_process(struct psmouse *psmouse, priv->agm_pending = false; } +static void synaptics_profile_sensor_process(struct psmouse *psmouse, + struct synaptics_hw_state *sgm, + int num_fingers) +{ + struct input_dev *dev = psmouse->dev; + struct synaptics_data *priv = psmouse->private; + struct synaptics_hw_state *hw[2] = { sgm, &priv->agm }; + struct input_mt_pos pos[2]; + int slot[2], nsemi, i; + + nsemi = clamp_val(num_fingers, 0, 2); + + for (i = 0; i < nsemi; i++) { + pos[i].x = hw[i]->x; + pos[i].y = synaptics_invert_y(hw[i]->y); + } + + input_mt_assign_slots(dev, slot, pos, nsemi); + + for (i = 0; i < nsemi; i++) { + input_mt_slot(dev, slot[i]); + input_mt_report_slot_state(dev, MT_TOOL_FINGER, true); + input_report_abs(dev, ABS_MT_POSITION_X, pos[i].x); + input_report_abs(dev, ABS_MT_POSITION_Y, pos[i].y); + input_report_abs(dev, ABS_MT_PRESSURE, hw[i]->z); + } + + input_mt_drop_unused(dev); + input_mt_report_pointer_emulation(dev, false); + input_mt_report_finger_count(dev, num_fingers); + + synaptics_report_buttons(psmouse, sgm); + + input_sync(dev); +} + /* * called for each full received packet from the touchpad */ @@ -1215,6 +1254,11 @@ static void synaptics_process_packet(struct psmouse *psmouse) finger_width = 0; } + if (cr48_profile_sensor) { + synaptics_profile_sensor_process(psmouse, &hw, num_fingers); + return; + } + if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) synaptics_report_semi_mt_data(dev, &hw, &priv->agm, num_fingers); @@ -1360,6 +1404,9 @@ static void set_input_params(struct psmouse *psmouse, set_abs_position_params(dev, priv, ABS_X, ABS_Y); input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); + if (cr48_profile_sensor) + input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0); + if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) { set_abs_position_params(dev, priv, ABS_MT_POSITION_X, ABS_MT_POSITION_Y); @@ -1371,11 +1418,16 @@ static void set_input_params(struct psmouse *psmouse, __set_bit(BTN_TOOL_QUADTAP, dev->keybit); __set_bit(BTN_TOOL_QUINTTAP, dev->keybit); } else if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) { - /* Non-image sensors with AGM use semi-mt */ - __set_bit(INPUT_PROP_SEMI_MT, dev->propbit); - input_mt_init_slots(dev, 2, 0); set_abs_position_params(dev, priv, ABS_MT_POSITION_X, ABS_MT_POSITION_Y); + /* + * Profile sensor in CR-48 tracks contacts reasonably well, + * other non-image sensors with AGM use semi-mt. + */ + input_mt_init_slots(dev, 2, + INPUT_MT_POINTER | + (cr48_profile_sensor ? + INPUT_MT_TRACK : INPUT_MT_SEMI_MT)); } if (SYN_CAP_PALMDETECT(priv->capabilities)) @@ -1577,10 +1629,24 @@ static const struct dmi_system_id olpc_dmi_table[] __initconst = { { } }; +static const struct dmi_system_id __initconst cr48_dmi_table[] = { +#if defined(CONFIG_DMI) && defined(CONFIG_X86) + { + /* Cr-48 Chromebook (Codename Mario) */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "IEC"), + DMI_MATCH(DMI_PRODUCT_NAME, "Mario"), + }, + }, +#endif + { } +}; + void __init synaptics_module_init(void) { impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table); broken_olpc_ec = dmi_check_system(olpc_dmi_table); + cr48_profile_sensor = dmi_check_system(cr48_dmi_table); } static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 03b8571..db178ed 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -359,7 +359,6 @@ static int mxt_bootloader_read(struct mxt_data *data, msg.buf = val; ret = i2c_transfer(data->client->adapter, &msg, 1); - if (ret == 1) { ret = 0; } else { @@ -414,6 +413,7 @@ static int mxt_lookup_bootloader_address(struct mxt_data *data, bool retry) case 0x5b: bootloader = appmode - 0x26; break; + default: dev_err(&data->client->dev, "Appmode i2c address 0x%02x not found\n", @@ -425,20 +425,20 @@ static int mxt_lookup_bootloader_address(struct mxt_data *data, bool retry) return 0; } -static int mxt_probe_bootloader(struct mxt_data *data, bool retry) +static int mxt_probe_bootloader(struct mxt_data *data, bool alt_address) { struct device *dev = &data->client->dev; - int ret; + int error; u8 val; bool crc_failure; - ret = mxt_lookup_bootloader_address(data, retry); - if (ret) - return ret; + error = mxt_lookup_bootloader_address(data, alt_address); + if (error) + return error; - ret = mxt_bootloader_read(data, &val, 1); - if (ret) - return ret; + error = mxt_bootloader_read(data, &val, 1); + if (error) + return error; /* Check app crc fail mode */ crc_failure = (val & ~MXT_BOOT_STATUS_MASK) == MXT_APP_CRC_FAIL; @@ -1064,6 +1064,137 @@ static u32 mxt_calculate_crc(u8 *base, off_t start_off, off_t end_off) return crc; } +static int mxt_prepare_cfg_mem(struct mxt_data *data, + const struct firmware *cfg, + unsigned int data_pos, + unsigned int cfg_start_ofs, + u8 *config_mem, + size_t config_mem_size) +{ + struct device *dev = &data->client->dev; + struct mxt_object *object; + unsigned int type, instance, size, byte_offset; + int offset; + int ret; + int i; + u16 reg; + u8 val; + + while (data_pos < cfg->size) { + /* Read type, instance, length */ + ret = sscanf(cfg->data + data_pos, "%x %x %x%n", + &type, &instance, &size, &offset); + if (ret == 0) { + /* EOF */ + break; + } else if (ret != 3) { + dev_err(dev, "Bad format: failed to parse object\n"); + return -EINVAL; + } + data_pos += offset; + + object = mxt_get_object(data, type); + if (!object) { + /* Skip object */ + for (i = 0; i < size; i++) { + ret = sscanf(cfg->data + data_pos, "%hhx%n", + &val, &offset); + if (ret != 1) { + dev_err(dev, "Bad format in T%d at %d\n", + type, i); + return -EINVAL; + } + data_pos += offset; + } + continue; + } + + if (size > mxt_obj_size(object)) { + /* + * Either we are in fallback mode due to wrong + * config or config from a later fw version, + * or the file is corrupt or hand-edited. + */ + dev_warn(dev, "Discarding %zu byte(s) in T%u\n", + size - mxt_obj_size(object), type); + } else if (mxt_obj_size(object) > size) { + /* + * If firmware is upgraded, new bytes may be added to + * end of objects. It is generally forward compatible + * to zero these bytes - previous behaviour will be + * retained. However this does invalidate the CRC and + * will force fallback mode until the configuration is + * updated. We warn here but do nothing else - the + * malloc has zeroed the entire configuration. + */ + dev_warn(dev, "Zeroing %zu byte(s) in T%d\n", + mxt_obj_size(object) - size, type); + } + + if (instance >= mxt_obj_instances(object)) { + dev_err(dev, "Object instances exceeded!\n"); + return -EINVAL; + } + + reg = object->start_address + mxt_obj_size(object) * instance; + + for (i = 0; i < size; i++) { + ret = sscanf(cfg->data + data_pos, "%hhx%n", + &val, + &offset); + if (ret != 1) { + dev_err(dev, "Bad format in T%d at %d\n", + type, i); + return -EINVAL; + } + data_pos += offset; + + if (i > mxt_obj_size(object)) + continue; + + byte_offset = reg + i - cfg_start_ofs; + + if (byte_offset >= 0 && byte_offset < config_mem_size) { + *(config_mem + byte_offset) = val; + } else { + dev_err(dev, "Bad object: reg:%d, T%d, ofs=%d\n", + reg, object->type, byte_offset); + return -EINVAL; + } + } + } + + return 0; +} + +static int mxt_upload_cfg_mem(struct mxt_data *data, unsigned int cfg_start, + u8 *config_mem, size_t config_mem_size) +{ + unsigned int byte_offset = 0; + int error; + + /* Write configuration as blocks */ + while (byte_offset < config_mem_size) { + unsigned int size = config_mem_size - byte_offset; + + if (size > MXT_MAX_BLOCK_WRITE) + size = MXT_MAX_BLOCK_WRITE; + + error = __mxt_write_reg(data->client, + cfg_start + byte_offset, + size, config_mem + byte_offset); + if (error) { + dev_err(&data->client->dev, + "Config write error, ret=%d\n", error); + return error; + } + + byte_offset += size; + } + + return 0; +} + /* * mxt_update_cfg - download configuration to chip * @@ -1087,26 +1218,20 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg) { struct device *dev = &data->client->dev; struct mxt_info cfg_info; - struct mxt_object *object; int ret; int offset; int data_pos; - int byte_offset; int i; int cfg_start_ofs; u32 info_crc, config_crc, calculated_crc; u8 *config_mem; size_t config_mem_size; - unsigned int type, instance, size; - u8 val; - u16 reg; mxt_update_crc(data, MXT_COMMAND_REPORTALL, 1); if (strncmp(cfg->data, MXT_CFG_MAGIC, strlen(MXT_CFG_MAGIC))) { dev_err(dev, "Unrecognised config file\n"); - ret = -EINVAL; - goto release; + return -EINVAL; } data_pos = strlen(MXT_CFG_MAGIC); @@ -1118,8 +1243,7 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg) &offset); if (ret != 1) { dev_err(dev, "Bad format\n"); - ret = -EINVAL; - goto release; + return -EINVAL; } data_pos += offset; @@ -1127,30 +1251,26 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg) if (cfg_info.family_id != data->info.family_id) { dev_err(dev, "Family ID mismatch!\n"); - ret = -EINVAL; - goto release; + return -EINVAL; } if (cfg_info.variant_id != data->info.variant_id) { dev_err(dev, "Variant ID mismatch!\n"); - ret = -EINVAL; - goto release; + return -EINVAL; } /* Read CRCs */ ret = sscanf(cfg->data + data_pos, "%x%n", &info_crc, &offset); if (ret != 1) { dev_err(dev, "Bad format: failed to parse Info CRC\n"); - ret = -EINVAL; - goto release; + return -EINVAL; } data_pos += offset; ret = sscanf(cfg->data + data_pos, "%x%n", &config_crc, &offset); if (ret != 1) { dev_err(dev, "Bad format: failed to parse Config CRC\n"); - ret = -EINVAL; - goto release; + return -EINVAL; } data_pos += offset; @@ -1166,8 +1286,7 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg) } else if (config_crc == data->config_crc) { dev_dbg(dev, "Config CRC 0x%06X: OK\n", data->config_crc); - ret = 0; - goto release; + return 0; } else { dev_info(dev, "Config CRC 0x%06X: does not match file 0x%06X\n", data->config_crc, config_crc); @@ -1186,93 +1305,13 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg) config_mem = kzalloc(config_mem_size, GFP_KERNEL); if (!config_mem) { dev_err(dev, "Failed to allocate memory\n"); - ret = -ENOMEM; - goto release; + return -ENOMEM; } - while (data_pos < cfg->size) { - /* Read type, instance, length */ - ret = sscanf(cfg->data + data_pos, "%x %x %x%n", - &type, &instance, &size, &offset); - if (ret == 0) { - /* EOF */ - break; - } else if (ret != 3) { - dev_err(dev, "Bad format: failed to parse object\n"); - ret = -EINVAL; - goto release_mem; - } - data_pos += offset; - - object = mxt_get_object(data, type); - if (!object) { - /* Skip object */ - for (i = 0; i < size; i++) { - ret = sscanf(cfg->data + data_pos, "%hhx%n", - &val, - &offset); - data_pos += offset; - } - continue; - } - - if (size > mxt_obj_size(object)) { - /* - * Either we are in fallback mode due to wrong - * config or config from a later fw version, - * or the file is corrupt or hand-edited. - */ - dev_warn(dev, "Discarding %zu byte(s) in T%u\n", - size - mxt_obj_size(object), type); - } else if (mxt_obj_size(object) > size) { - /* - * If firmware is upgraded, new bytes may be added to - * end of objects. It is generally forward compatible - * to zero these bytes - previous behaviour will be - * retained. However this does invalidate the CRC and - * will force fallback mode until the configuration is - * updated. We warn here but do nothing else - the - * malloc has zeroed the entire configuration. - */ - dev_warn(dev, "Zeroing %zu byte(s) in T%d\n", - mxt_obj_size(object) - size, type); - } - - if (instance >= mxt_obj_instances(object)) { - dev_err(dev, "Object instances exceeded!\n"); - ret = -EINVAL; - goto release_mem; - } - - reg = object->start_address + mxt_obj_size(object) * instance; - - for (i = 0; i < size; i++) { - ret = sscanf(cfg->data + data_pos, "%hhx%n", - &val, - &offset); - if (ret != 1) { - dev_err(dev, "Bad format in T%d\n", type); - ret = -EINVAL; - goto release_mem; - } - data_pos += offset; - - if (i > mxt_obj_size(object)) - continue; - - byte_offset = reg + i - cfg_start_ofs; - - if ((byte_offset >= 0) - && (byte_offset <= config_mem_size)) { - *(config_mem + byte_offset) = val; - } else { - dev_err(dev, "Bad object: reg:%d, T%d, ofs=%d\n", - reg, object->type, byte_offset); - ret = -EINVAL; - goto release_mem; - } - } - } + ret = mxt_prepare_cfg_mem(data, cfg, data_pos, cfg_start_ofs, + config_mem, config_mem_size); + if (ret) + goto release_mem; /* Calculate crc of the received configs (not the raw config file) */ if (data->T7_address < cfg_start_ofs) { @@ -1286,28 +1325,14 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg) data->T7_address - cfg_start_ofs, config_mem_size); - if (config_crc > 0 && (config_crc != calculated_crc)) + if (config_crc > 0 && config_crc != calculated_crc) dev_warn(dev, "Config CRC error, calculated=%06X, file=%06X\n", calculated_crc, config_crc); - /* Write configuration as blocks */ - byte_offset = 0; - while (byte_offset < config_mem_size) { - size = config_mem_size - byte_offset; - - if (size > MXT_MAX_BLOCK_WRITE) - size = MXT_MAX_BLOCK_WRITE; - - ret = __mxt_write_reg(data->client, - cfg_start_ofs + byte_offset, - size, config_mem + byte_offset); - if (ret != 0) { - dev_err(dev, "Config write error, ret=%d\n", ret); - goto release_mem; - } - - byte_offset += size; - } + ret = mxt_upload_cfg_mem(data, cfg_start_ofs, + config_mem, config_mem_size); + if (ret) + goto release_mem; mxt_update_crc(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE); @@ -1319,8 +1344,6 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg) release_mem: kfree(config_mem); -release: - release_firmware(cfg); return ret; } @@ -1422,10 +1445,12 @@ static int mxt_get_object_table(struct mxt_data *data) switch (object->type) { case MXT_GEN_MESSAGE_T5: - if (data->info.family_id == 0x80) { + if (data->info.family_id == 0x80 && + data->info.version < 0x20) { /* - * On mXT224 read and discard unused CRC byte - * otherwise DMA reads are misaligned + * On mXT224 firmware versions prior to V2.0 + * read and discard unused CRC byte otherwise + * DMA reads are misaligned. */ data->T5_msg_size = mxt_obj_size(object); } else { @@ -1433,6 +1458,7 @@ static int mxt_get_object_table(struct mxt_data *data) data->T5_msg_size = mxt_obj_size(object) - 1; } data->T5_address = object->start_address; + break; case MXT_GEN_COMMAND_T6: data->T6_reportid = min_id; data->T6_address = object->start_address; @@ -1638,46 +1664,45 @@ static int mxt_configure_objects(struct mxt_data *data, static void mxt_config_cb(const struct firmware *cfg, void *ctx) { mxt_configure_objects(ctx, cfg); + release_firmware(cfg); } static int mxt_initialize(struct mxt_data *data) { struct i2c_client *client = data->client; + int recovery_attempts = 0; int error; - bool alt_bootloader_addr = false; - bool retry = false; -retry_info: - error = mxt_get_info(data); - if (error) { -retry_bootloader: - error = mxt_probe_bootloader(data, alt_bootloader_addr); + while (1) { + error = mxt_get_info(data); + if (!error) + break; + + /* Check bootloader state */ + error = mxt_probe_bootloader(data, false); if (error) { - if (alt_bootloader_addr) { + dev_info(&client->dev, "Trying alternate bootloader address\n"); + error = mxt_probe_bootloader(data, true); + if (error) { /* Chip is not in appmode or bootloader mode */ return error; } + } - dev_info(&client->dev, "Trying alternate bootloader address\n"); - alt_bootloader_addr = true; - goto retry_bootloader; - } else { - if (retry) { - dev_err(&client->dev, "Could not recover from bootloader mode\n"); - /* - * We can reflash from this state, so do not - * abort init - */ - data->in_bootloader = true; - return 0; - } - - /* Attempt to exit bootloader into app mode */ - mxt_send_bootloader_cmd(data, false); - msleep(MXT_FW_RESET_TIME); - retry = true; - goto retry_info; + /* OK, we are in bootloader, see if we can recover */ + if (++recovery_attempts > 1) { + dev_err(&client->dev, "Could not recover from bootloader mode\n"); + /* + * We can reflash from this state, so do not + * abort initialization. + */ + data->in_bootloader = true; + return 0; } + + /* Attempt to exit bootloader into app mode */ + mxt_send_bootloader_cmd(data, false); + msleep(MXT_FW_RESET_TIME); } /* Get object table information */ @@ -1687,13 +1712,18 @@ retry_bootloader: return error; } - mxt_acquire_irq(data); + error = mxt_acquire_irq(data); if (error) goto err_free_object_table; - request_firmware_nowait(THIS_MODULE, true, MXT_CFG_NAME, - &data->client->dev, GFP_KERNEL, data, - mxt_config_cb); + error = request_firmware_nowait(THIS_MODULE, true, MXT_CFG_NAME, + &client->dev, GFP_KERNEL, data, + mxt_config_cb); + if (error) { + dev_err(&client->dev, "Failed to invoke firmware loader: %d\n", + error); + goto err_free_object_table; + } return 0; diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 5a6d50c..8857d5b9 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -262,7 +262,6 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata, case M06: wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; - wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; wrbuf[2] = value; wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2]; return edt_ft5x06_ts_readwrite(tsdata->client, 4, |