]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge branches 'for-3.15/multitouch', 'for-3.15/sony' and 'for-3.15/uhid' into for...
authorJiri Kosina <jkosina@suse.cz>
Tue, 1 Apr 2014 17:06:50 +0000 (19:06 +0200)
committerJiri Kosina <jkosina@suse.cz>
Tue, 1 Apr 2014 17:06:50 +0000 (19:06 +0200)
1  2  3  4 
drivers/hid/hid-ids.h
drivers/hid/hid-multitouch.c
drivers/hid/hid-sony.c
include/linux/hid.h

index af15a631bb24183b3553aa8712d1a683639cdd45,ca9b206a01c1c87bb3c8c686bfdb1363de3d4ff7,239f29c1c85c14f64fe5d51ff1a935b98377d06c,239f29c1c85c14f64fe5d51ff1a935b98377d06c..548c1a51959334e867b27c73ae20d682515c9149
    
    #define USB_VENDOR_ID_CYGNAL                0x10c4
    #define USB_DEVICE_ID_CYGNAL_RADIO_SI470X   0x818a
 +++#define USB_DEVICE_ID_FOCALTECH_FTXXXX_MULTITOUCH   0x81b9
 +  #define USB_DEVICE_ID_CYGNAL_CP2112 0xea90
    
    #define USB_VENDOR_ID_CYPRESS               0x04b4
    #define USB_DEVICE_ID_CYPRESS_MOUSE 0x0001
index 221d503f1c24fa7b1bbbc0c5871c3cbe742d1a5b,59742f49295cfe9f469be8eede5e4c5435b4cefb,f134d73beca16b72ddce5716d36e4d7ca949e61d,f134d73beca16b72ddce5716d36e4d7ca949e61d..35278e43c7a48d1999283c21f0f60cceccbc3b84
@@@@@ -784,20 -744,38 -784,20 -784,20 +744,38 @@@@@ static int mt_input_mapping(struct hid_
            field->application != HID_DG_TOUCHPAD)
                return -1;
    
+ ++    /*
+ ++     * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
+ ++     * for the stylus.
+ ++     */
        if (field->physical == HID_DG_STYLUS)
- --            return mt_pen_input_mapping(hdev, hi, field, usage, bit, max);
+ ++            return 0;
  ++
-       return mt_touch_input_mapping(hdev, hi, field, usage, bit, max);
+ ++    if (field->application == HID_DG_TOUCHSCREEN ||
+ ++        field->application == HID_DG_TOUCHPAD)
+ ++            return mt_touch_input_mapping(hdev, hi, field, usage, bit, max);
+   
  --    return mt_touch_input_mapping(hdev, hi, field, usage, bit, max);
+ ++    /* let hid-core decide for the others */
+ ++    return 0;
    }
    
    static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
                struct hid_field *field, struct hid_usage *usage,
                unsigned long **bit, int *max)
    {
+ ++    /*
+ ++     * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
+ ++     * for the stylus.
+ ++     */
        if (field->physical == HID_DG_STYLUS)
- --            return mt_pen_input_mapped(hdev, hi, field, usage, bit, max);
+ ++            return 0;
  ++
-       return mt_touch_input_mapped(hdev, hi, field, usage, bit, max);
+ ++    if (field->application == HID_DG_TOUCHSCREEN ||
+ ++        field->application == HID_DG_TOUCHPAD)
+ ++            return mt_touch_input_mapped(hdev, hi, field, usage, bit, max);
+   
  --    return mt_touch_input_mapped(hdev, hi, field, usage, bit, max);
+ ++    /* let hid-core decide for the others */
+ ++    return 0;
    }
    
    static int mt_event(struct hid_device *hid, struct hid_field *field,
index b3e82585309e51ec85297d4be4e797871a71f21a,e3e89b6a41c28d9b18702e8c53e21218cb292840,908de278921944dfae837284f582e117617c479d,4884bb567bf88ab0a71030c6eb9666c4fc88cbab..4d348c069981f21b51c12aabfea9f4fdaa342952
@@@@@ -843,107 -599,6 -843,107 -843,107 +843,107 @@@@@ static __u8 *sony_report_fixup(struct h
        return rdesc;
    }
    
-  -    cable_state = !((rd[31] >> 4) & 0x01);
 +  static void sixaxis_parse_report(struct sony_sc *sc, __u8 *rd, int size)
 +  {
 +      static const __u8 sixaxis_battery_capacity[] = { 0, 1, 25, 50, 75, 100 };
 +      unsigned long flags;
 +      __u8 cable_state, battery_capacity, battery_charging;
 +  
 +      /*
 +       * The sixaxis is charging if the battery value is 0xee
 +       * and it is fully charged if the value is 0xef.
 +       * It does not report the actual level while charging so it
 +       * is set to 100% while charging is in progress.
 +       */
 +      if (rd[30] >= 0xee) {
 +              battery_capacity = 100;
 +              battery_charging = !(rd[30] & 0x01);
 +      } else {
 +              __u8 index = rd[30] <= 5 ? rd[30] : 5;
 +              battery_capacity = sixaxis_battery_capacity[index];
 +              battery_charging = 0;
 +      }
++ +    cable_state = !(rd[31] & 0x04);
 +  
 +      spin_lock_irqsave(&sc->lock, flags);
 +      sc->cable_state = cable_state;
 +      sc->battery_capacity = battery_capacity;
 +      sc->battery_charging = battery_charging;
 +      spin_unlock_irqrestore(&sc->lock, flags);
 +  }
 +  
 +  static void dualshock4_parse_report(struct sony_sc *sc, __u8 *rd, int size)
 +  {
 +      struct hid_input *hidinput = list_entry(sc->hdev->inputs.next,
 +                                              struct hid_input, list);
 +      struct input_dev *input_dev = hidinput->input;
 +      unsigned long flags;
 +      int n, offset;
 +      __u8 cable_state, battery_capacity, battery_charging;
 +  
 +      /*
 +       * Battery and touchpad data starts at byte 30 in the USB report and
 +       * 32 in Bluetooth report.
 +       */
 +      offset = (sc->quirks & DUALSHOCK4_CONTROLLER_USB) ? 30 : 32;
 +  
 +      /*
 +       * The lower 4 bits of byte 30 contain the battery level
 +       * and the 5th bit contains the USB cable state.
 +       */
 +      cable_state = (rd[offset] >> 4) & 0x01;
 +      battery_capacity = rd[offset] & 0x0F;
 +  
 +      /*
 +       * When a USB power source is connected the battery level ranges from
 +       * 0 to 10, and when running on battery power it ranges from 0 to 9.
 +       * A battery level above 10 when plugged in means charge completed.
 +       */
 +      if (!cable_state || battery_capacity > 10)
 +              battery_charging = 0;
 +      else
 +              battery_charging = 1;
 +  
 +      if (!cable_state)
 +              battery_capacity++;
 +      if (battery_capacity > 10)
 +              battery_capacity = 10;
 +  
 +      battery_capacity *= 10;
 +  
 +      spin_lock_irqsave(&sc->lock, flags);
 +      sc->cable_state = cable_state;
 +      sc->battery_capacity = battery_capacity;
 +      sc->battery_charging = battery_charging;
 +      spin_unlock_irqrestore(&sc->lock, flags);
 +  
 +      offset += 5;
 +  
 +      /*
 +       * The Dualshock 4 multi-touch trackpad data starts at offset 35 on USB
 +       * and 37 on Bluetooth.
 +       * The first 7 bits of the first byte is a counter and bit 8 is a touch
 +       * indicator that is 0 when pressed and 1 when not pressed.
 +       * The next 3 bytes are two 12 bit touch coordinates, X and Y.
 +       * The data for the second touch is in the same format and immediatly
 +       * follows the data for the first.
 +       */
 +      for (n = 0; n < 2; n++) {
 +              __u16 x, y;
 +  
 +              x = rd[offset+1] | ((rd[offset+2] & 0xF) << 8);
 +              y = ((rd[offset+2] & 0xF0) >> 4) | (rd[offset+3] << 4);
 +  
 +              input_mt_slot(input_dev, n);
 +              input_mt_report_slot_state(input_dev, MT_TOOL_FINGER,
 +                                      !(rd[offset] >> 7));
 +              input_report_abs(input_dev, ABS_MT_POSITION_X, x);
 +              input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
 +  
 +              offset += 4;
 +      }
 +  }
 +  
    static int sony_raw_event(struct hid_device *hdev, struct hid_report *report,
                __u8 *rd, int size)
    {
@@@@@ -1616,38 -1076,15 -1616,48 -1616,38 +1616,48 @@@@@ static int sony_probe(struct hid_devic
        }
    
        if (sc->quirks & SIXAXIS_CONTROLLER_USB) {
 -              hdev->hid_output_raw_report = sixaxis_usb_output_raw_report;
 +              /*
 +               * The Sony Sixaxis does not handle HID Output Reports on the
 +               * Interrupt EP like it could, so we need to force HID Output
 +               * Reports to use HID_REQ_SET_REPORT on the Control EP.
 +               *
 +               * There is also another issue about HID Output Reports via USB,
 +               * the Sixaxis does not want the report_id as part of the data
 +               * packet, so we have to discard buf[0] when sending the actual
 +               * control message, even for numbered reports, humpf!
 +               */
 +              hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP;
 +              hdev->quirks |= HID_QUIRK_SKIP_OUTPUT_REPORT_ID;
                ret = sixaxis_set_operational_usb(hdev);
 +              sc->worker_initialized = 1;
                INIT_WORK(&sc->state_worker, sixaxis_state_worker);
 -      }
 -      else if (sc->quirks & SIXAXIS_CONTROLLER_BT)
 +      } else if (sc->quirks & SIXAXIS_CONTROLLER_BT) {
++ +            /*
++ +             * The Sixaxis wants output reports sent on the ctrl endpoint
++ +             * when connected via Bluetooth.
++ +             */
++ +            hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP;
                ret = sixaxis_set_operational_bt(hdev);
 -      else if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) {
 -              /* Report 5 (31 bytes) is used to send data to the controller via USB */
 -              ret = sony_set_output_report(sc, 0x05, 248);
 +              sc->worker_initialized = 1;
 +              INIT_WORK(&sc->state_worker, sixaxis_state_worker);
 +      } else if (sc->quirks & DUALSHOCK4_CONTROLLER) {
 +              if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) {
++ +                    /*
++ +                     * The DualShock 4 wants output reports sent on the ctrl
++ +                     * endpoint when connected via Bluetooth.
++ +                     */
++ +                    hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP;
 +                      ret = dualshock4_set_operational_bt(hdev);
 +                      if (ret < 0) {
 +                              hid_err(hdev, "failed to set the Dualshock 4 operational mode\n");
 +                              goto err_stop;
 +                      }
 +              }
 +              /*
 +               * The Dualshock 4 touchpad supports 2 touches and has a
 +               * resolution of 1920x940.
 +               */
 +              ret = sony_register_touchpad(sc, 2, 1920, 940);
                if (ret < 0)
                        goto err_stop;
    
                        goto err_stop;
        }
    
 -      ret = sony_init_ff(hdev);
 -      if (ret < 0)
 -              goto err_stop;
 +++    if (sc->quirks & SONY_FF_SUPPORT) {
 +++            ret = sony_init_ff(hdev);
 +++            if (ret < 0)
 +++                    goto err_stop;
 +      if (sc->quirks & SONY_BATTERY_SUPPORT) {
 +              ret = sony_battery_probe(sc);
 +              if (ret < 0)
 +                      goto err_stop;
 +  
 +              /* Open the device to receive reports with battery info */
 +              ret = hid_hw_open(hdev);
 +              if (ret < 0) {
 +                      hid_err(hdev, "hw open failed\n");
 +                      goto err_stop;
 +              }
 +      }
 +  
 +      if (sc->quirks & SONY_FF_SUPPORT) {
 +              ret = sony_init_ff(hdev);
 +              if (ret < 0)
 +                      goto err_close;
 +      }
    
        return 0;
 +  err_close:
 +      hid_hw_close(hdev);
    err_stop:
        if (sc->quirks & SONY_LED_SUPPORT)
                sony_leds_remove(hdev);
@@@@@ -1715,17 -1121,7 -1721,15 -1711,15 +1725,17 @@@@@ static void sony_remove(struct hid_devi
        if (sc->quirks & SONY_LED_SUPPORT)
                sony_leds_remove(hdev);
    
 -      sony_destroy_ff(hdev);
 +++    if (sc->worker_initialized)
 +++            cancel_work_sync(&sc->state_worker);
 +      if (sc->quirks & SONY_BATTERY_SUPPORT) {
 +              hid_hw_close(hdev);
 +              sony_battery_remove(sc);
 +      }
 +  
 +      if (sc->worker_initialized)
 +              cancel_work_sync(&sc->state_worker);
 +  
 +      sony_remove_dev_list(sc);
    
        hid_hw_stop(hdev);
    }
Simple merge