Merge branch 'next' into for-linus
authorDmitry Torokhov <dmitry.torokhov@gmail.com>
Fri, 15 Aug 2014 06:02:58 +0000 (23:02 -0700)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Fri, 15 Aug 2014 06:02:58 +0000 (23:02 -0700)
Prepare second round of input updates for 3.17.

drivers/input/input-mt.c
drivers/input/joystick/xpad.c
drivers/input/keyboard/cap1106.c
drivers/input/mouse/synaptics.c
drivers/input/touchscreen/atmel_mxt_ts.c
drivers/input/touchscreen/edt-ft5x06.c
include/linux/input/mt.h

index d398f1321f143f834e5ddc70563ed368ca130c24..c30204f2fa3097a376eec7a32072f0c29b9c1a90 100644 (file)
@@ -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);
 
index 603fe0dd3682f7cd5baa859de39f37e2253825d9..177602cf7079a41edf22553d348400d8035e649a 100644 (file)
@@ -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,
index f7d7a0d4ab4ec5a7378f061d6d10e70085245625..180b184ab90f31935e1fa9c71bd7eb8fa4e68593 100644 (file)
@@ -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;
index ef9e0b8a9aa754b6b49e26b7b050c2a7bcf1f078..e8573c68f77e900e83e054c720443328adfa2f7f 100644 (file)
@@ -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)
index 03b85711cb70c9406aae09647d12df68045ff2b3..db178ed2b47ee282c27a5f424f45df168b99a091 100644 (file)
@@ -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;
 
index 5a6d50c004d73c9b2d6ceb2a4b573e1542b11b7f..8857d5b9be71dc03d4494562383fc76c779003ef 100644 (file)
@@ -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,
index 1b1dfa80d9fffe2b28cfd5f02c64a3bad3c932d4..f583ff63977608827cd2e7e56fe4f344cdf4d7ed 100644 (file)
@@ -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);