Commit 2f39691f authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input

Pull input layer fixes from Dmitry Torokhov:
 "Second round of updates for the input subsystem.  Mostly small fixups
  to the code merged in the first round (atmel_mxt_ts, wacom) but also a
  smallish patch to xbox driver to support Xbox One controllers and a
  patch to better handle Synaptics profile sensors found in Cr-48
  Chromebooks that should not affect any other devices"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
  Input: edt-ft5x06 - remove superfluous assignment
  Input: xpad - add support for Xbox One controllers
  Input: atmel_mxt_ts - fix a few issues reported by Coverity
  Input: atmel_mxt_ts - split config update a bit
  Input: atmel_mxt_ts - simplify mxt_initialize a bit
  Input: joystick - use get_cycles on ARMv8
  Input: wacom - fix compiler warning if !CONFIG_PM
  Input: cap1106 - allow changing key mapping from userspace
  Input: synaptics - use firmware data for Cr-48
  Input: synaptics - properly initialize slots for semi-MT
  Input: MT - make slot cleanup callable outside mt_sync_frame()
  Input: atmel_mxt_ts - mXT224 DMA quirk was fixed in firmware v2.0.AA
parents ffb29b42 91167e19
......@@ -1416,6 +1416,7 @@ static void wacom_remove(struct hid_device *hdev)
kfree(wacom);
}
#ifdef CONFIG_PM
static int wacom_resume(struct hid_device *hdev)
{
struct wacom *wacom = hid_get_drvdata(hdev);
......@@ -1436,6 +1437,7 @@ static int wacom_reset_resume(struct hid_device *hdev)
{
return wacom_resume(hdev);
}
#endif /* CONFIG_PM */
static struct hid_driver wacom_driver = {
.name = "wacom",
......
......@@ -236,6 +236,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);
......
......@@ -158,7 +158,7 @@ static unsigned int get_time_pit(void)
#define GET_TIME(x) rdtscl(x)
#define DELTA(x,y) ((y)-(x))
#define TIME_NAME "TSC"
#elif defined(__alpha__) || defined(CONFIG_MN10300) || defined(CONFIG_ARM) || defined(CONFIG_TILE)
#elif defined(__alpha__) || defined(CONFIG_MN10300) || defined(CONFIG_ARM) || defined(CONFIG_ARM64) || defined(CONFIG_TILE)
#define GET_TIME(x) do { x = get_cycles(); } while (0)
#define DELTA(x,y) ((y)-(x))
#define TIME_NAME "get_cycles"
......
......@@ -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 @@ static void xpad_irq_out(struct urb *urb)
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,6 +949,9 @@ 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) */
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:
......@@ -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 {
......@@ -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,
......
......@@ -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;
......
......@@ -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)
......
......@@ -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;
}
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;
return -ENOMEM;
}
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;
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);
ret = mxt_upload_cfg_mem(data, cfg_start_ofs,
config_mem, config_mem_size);
if (ret)
goto release_mem;
}
byte_offset += size;
}
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,35 +1664,37 @@ 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:
while (1) {
error = mxt_get_info(data);
if (!error)
break;
/* Check bootloader state */
error = mxt_probe_bootloader(data, false);
if (error) {
retry_bootloader:
error = mxt_probe_bootloader(data, alt_bootloader_addr);
dev_info(&client->dev, "Trying alternate bootloader address\n");
error = mxt_probe_bootloader(data, true);
if (error) {
if (alt_bootloader_addr) {
/* 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) {
/* 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 init
* abort initialization.
*/
data->in_bootloader = true;
return 0;
......@@ -1675,9 +1703,6 @@ static int mxt_initialize(struct mxt_data *data)
/* Attempt to exit bootloader into app mode */
mxt_send_bootloader_cmd(data, false);
msleep(MXT_FW_RESET_TIME);
retry = true;
goto retry_info;
}
}
/* Get object table information */
......@@ -1687,13 +1712,18 @@ static int mxt_initialize(struct mxt_data *data)
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,
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;
......
......@@ -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,
......
......@@ -105,6 +105,7 @@ void input_mt_report_slot_state(struct input_dev *dev,
void input_mt_report_finger_count(struct input_dev *dev, int count);
void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count);
void input_mt_drop_unused(struct input_dev *dev);
void input_mt_sync_frame(struct input_dev *dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment