From: Jiri Kosina Date: Tue, 1 Apr 2014 17:06:50 +0000 (+0200) Subject: Merge branches 'for-3.15/multitouch', 'for-3.15/sony' and 'for-3.15/uhid' into for... X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=fa1054a29b21e4c932b5c93def600149451cec32;p=openwrt%2Fstaging%2Fblogic.git Merge branches 'for-3.15/multitouch', 'for-3.15/sony' and 'for-3.15/uhid' into for-linus --- fa1054a29b21e4c932b5c93def600149451cec32 diff --cc drivers/hid/hid-ids.h index af15a631bb24,ca9b206a01c1,239f29c1c85c,239f29c1c85c..548c1a519593 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@@@@ -241,8 -243,6 -240,7 -240,7 +244,8 @@@@@ #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 diff --cc drivers/hid/hid-multitouch.c index 221d503f1c24,59742f49295c,f134d73beca1,f134d73beca1..35278e43c7a4 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@@@@ -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, diff --cc drivers/hid/hid-sony.c index b3e82585309e,e3e89b6a41c2,908de2789219,4884bb567bf8..4d348c069981 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@@@@ -843,107 -599,6 -843,107 -843,107 +843,107 @@@@@ static __u8 *sony_report_fixup(struct h return rdesc; } + 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] >> 4) & 0x01); ++ + 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; @@@@@ -1670,32 -1102,11 -1680,28 -1670,28 +1680,32 @@@@@ 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); }