diff --git a/projects/imx6/linux/4.4-xbian/linux.arm.conf b/projects/imx6/linux/4.4-xbian/linux.arm.conf index 867b5a42b4..b27e21597d 100644 --- a/projects/imx6/linux/4.4-xbian/linux.arm.conf +++ b/projects/imx6/linux/4.4-xbian/linux.arm.conf @@ -210,6 +210,7 @@ CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y CONFIG_ARCH_USE_BUILTIN_BSWAP=y CONFIG_HAVE_KPROBES=y CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_OPTPROBES=y CONFIG_HAVE_ARCH_TRACEHOOK=y CONFIG_HAVE_DMA_ATTRS=y CONFIG_HAVE_DMA_CONTIGUOUS=y @@ -4679,6 +4680,7 @@ CONFIG_HID_MONTEREY=m CONFIG_HID_MULTITOUCH=m CONFIG_HID_NTRIG=m CONFIG_HID_ORTEK=m +CONFIG_HID_OUYA=m CONFIG_HID_PANTHERLORD=m CONFIG_PANTHERLORD_FF=y CONFIG_HID_PENMOUNT=m @@ -4698,6 +4700,7 @@ CONFIG_HID_SONY=m CONFIG_SONY_FF=y CONFIG_HID_SPEEDLINK=m CONFIG_HID_STEELSERIES=m +CONFIG_HID_SPINELPLUS=m CONFIG_HID_SUNPLUS=m CONFIG_HID_RMI=m CONFIG_HID_GREENASIA=m diff --git a/projects/imx6/patches/linux/4.4-xbian/linux-002-add-avermedia-td110-id.patch b/projects/imx6/patches/linux/4.4-xbian/linux-002-add-avermedia-td110-id.patch deleted file mode 100644 index 138abf349e..0000000000 --- a/projects/imx6/patches/linux/4.4-xbian/linux-002-add-avermedia-td110-id.patch +++ /dev/null @@ -1,31 +0,0 @@ -diff -rU5 a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h ---- a/drivers/media/dvb-core/dvb-usb-ids.h 2015-11-02 01:05:25.000000000 +0100 -+++ b/drivers/media/dvb-core/dvb-usb-ids.h 2015-11-30 12:53:14.482337310 +0100 -@@ -239,10 +239,11 @@ - #define USB_PID_AVERMEDIA_A835B_3835 0x3835 - #define USB_PID_AVERMEDIA_A835B_4835 0x4835 - #define USB_PID_AVERMEDIA_1867 0x1867 - #define USB_PID_AVERMEDIA_A867 0xa867 - #define USB_PID_AVERMEDIA_H335 0x0335 -+#define USB_PID_AVERMEDIA_TD110 0xa110 - #define USB_PID_AVERMEDIA_TWINSTAR 0x0825 - #define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006 - #define USB_PID_TECHNOTREND_CONNECT_S2400_8KEEPROM 0x3009 - #define USB_PID_TECHNOTREND_CONNECT_CT3650 0x300d - #define USB_PID_TECHNOTREND_CONNECT_S2_4600 0x3011 -diff -rU5 a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c ---- a/drivers/media/usb/dvb-usb-v2/af9035.c 2015-11-02 01:05:25.000000000 +0100 -+++ b/drivers/media/usb/dvb-usb-v2/af9035.c 2015-11-30 17:15:09.149803276 +0100 -@@ -2051,10 +2051,12 @@ - &af9035_props, "Avermedia A835B(2835)", RC_MAP_IT913X_V2) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_3835, - &af9035_props, "Avermedia A835B(3835)", RC_MAP_IT913X_V2) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_4835, - &af9035_props, "Avermedia A835B(4835)", RC_MAP_IT913X_V2) }, -+ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TD110, -+ &af9035_props, "Avermedia AverTV Volar HD 2 (TD110)", RC_MAP_AVERMEDIA_RM_KS) }, - { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_H335, - &af9035_props, "Avermedia H335", RC_MAP_IT913X_V2) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB499_2T_T09, - &af9035_props, "Kworld UB499-2T T09", RC_MAP_IT913X_V1) }, - { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22_IT9137, diff --git a/projects/imx6/patches/linux/4.4-xbian/linux-051-ouya_controller_support.patch b/projects/imx6/patches/linux/4.4-xbian/linux-051-ouya_controller_support.patch new file mode 100644 index 0000000000..9b0f253372 --- /dev/null +++ b/projects/imx6/patches/linux/4.4-xbian/linux-051-ouya_controller_support.patch @@ -0,0 +1,315 @@ +diff -Naur linux-3.19.orig/drivers/hid/hid-core.c linux-3.19/drivers/hid/hid-core.c +--- linux-3.19.orig/drivers/hid/hid-core.c 2015-02-20 14:01:17.080322846 -0800 ++++ linux-3.19/drivers/hid/hid-core.c 2015-02-20 14:03:30.375519421 -0800 +@@ -1884,6 +1884,7 @@ + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_18) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_PKB1700) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) }, ++ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_OUYA, USB_DEVICE_ID_OUYA_CONTROLLER) }, + { HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_6000) }, + { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_SPINEL_PLUS_1) }, +diff -Naur linux-3.19.orig/drivers/hid/hid-ids.h linux-3.19/drivers/hid/hid-ids.h +--- linux-3.19.orig/drivers/hid/hid-ids.h 2015-02-20 14:01:17.080322846 -0800 ++++ linux-3.19/drivers/hid/hid-ids.h 2015-02-20 14:03:30.382519482 -0800 +@@ -721,6 +721,9 @@ + #define USB_DEVICE_ID_ORTEK_PKB1700 0x1700 + #define USB_DEVICE_ID_ORTEK_WKB2000 0x2000 + ++#define USB_VENDOR_ID_OUYA 0x2836 ++#define USB_DEVICE_ID_OUYA_CONTROLLER 0x0001 ++ + #define USB_VENDOR_ID_PLANTRONICS 0x047f + + #define USB_VENDOR_ID_PANASONIC 0x04da +diff -Naur linux-3.19.orig/drivers/hid/hid-ouya.c linux-3.19/drivers/hid/hid-ouya.c +--- linux-3.19.orig/drivers/hid/hid-ouya.c 1969-12-31 16:00:00.000000000 -0800 ++++ linux-3.19/drivers/hid/hid-ouya.c 2015-02-20 14:03:30.371519386 -0800 +@@ -0,0 +1,260 @@ ++/* ++ * HID driver for OUYA Game Controller(s) ++ * ++ * Copyright (c) 2013 OUYA ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "hid-ids.h" ++ ++#define OUYA_TOUCHPAD_FIXUP (1 << 0) ++ ++struct ouya_sc { ++ unsigned long quirks; ++}; ++ ++/* Fixed report descriptor */ ++static __u8 ouya_rdesc_fixed[] = { ++ ++ 0x05, 0x01, /* Usage Page (Desktop), */ ++ 0x09, 0x05, /* Usage (Game Pad), */ ++ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x07, /* Report ID (7), */ ++ ++ 0xA1, 0x00, /* Collection (Physical), */ ++ 0x09, 0x30, /* Usage (X), */ ++ 0x09, 0x31, /* Usage (Y), */ ++ 0x15, 0x00, /* Logical Minimum (0), */ ++ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ ++ 0x35, 0x00, /* Physical Minimum (0), */ ++ 0x46, 0xFF, 0x00, /* Physical Maximum (255), */ ++ 0x95, 0x02, /* Report Count (2), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0xC0, /* End Collection, */ ++ ++ 0xA1, 0x00, /* Collection (Physical), */ ++ 0x09, 0x33, /* Usage (Rx), */ ++ 0x09, 0x34, /* Usage (Ry), */ ++ 0x15, 0x00, /* Logical Minimum (0), */ ++ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ ++ 0x35, 0x00, /* Physical Minimum (0), */ ++ 0x46, 0xFF, 0x00, /* Physical Maximum (255), */ ++ 0x95, 0x02, /* Report Count (2), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0xC0, /* End Collection, */ ++ ++ 0xA1, 0x00, /* Collection (Physical), */ ++ 0x09, 0x32, /* Usage (Z), */ ++ 0x15, 0x00, /* Logical Minimum (0), */ ++ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ ++ 0x35, 0x00, /* Physical Minimum (0), */ ++ 0x46, 0xFF, 0x00, /* Physical Maximum (255), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0xC0, /* End Collection, */ ++ ++ 0xA1, 0x00, /* Collection (Physical), */ ++ 0x09, 0x35, /* Usage (Rz), */ ++ 0x15, 0x00, /* Logical Minimum (0), */ ++ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ ++ 0x35, 0x00, /* Physical Minimum (0), */ ++ 0x46, 0xFF, 0x00, /* Physical Maximum (255), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0xC0, /* End Collection, */ ++ ++ 0x05, 0x09, /* Usage Page (Button), */ ++ 0x19, 0x01, /* Usage Minimum (01h), */ ++ 0x29, 0x10, /* Usage Maximum (10h), */ ++ 0x95, 0x10, /* Report Count (16), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ ++ /* ORIGINAL REPORT DESCRIPTOR FOR TOUCHPAD INPUT */ ++ /* 06 00 ff a1 02 09 02 15 00 26 ff 00 35 00 46 ff 00 95 03 75 08 81 02 c0 */ ++ ++ 0x06, 0x00, 0xFF, /* Usage Page (Custom), */ ++ 0x09, 0x02, /* Usage (Mouse), */ ++ 0x09, 0x01, /* Usage (Pointer), */ ++ 0xA1, 0x00, /* Collection (Physical), */ ++ 0x05, 0x09, /* Usage Page (Button), */ ++ 0x19, 0x01, /* Usage Minimum (01h), */ ++ 0x29, 0x03, /* Usage Maximum (03h), */ ++ 0x15, 0x00, /* Logical Minimum (0), */ ++ 0x25, 0x01, /* Logical Maximum (1), */ ++ 0x95, 0x03, /* Report Count (3), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x75, 0x05, /* Report Size (5), */ ++ 0x81, 0x01, /* Input (Constant), */ ++ 0x05, 0x01, /* Usage Page (Desktop), */ ++ 0x09, 0x30, /* Usage (X), */ ++ 0x09, 0x31, /* Usage (Y), */ ++ 0x15, 0x81, /* Logical Minimum (-127), */ ++ 0x25, 0x7f, /* Logical Maximum (127), */ ++ 0x95, 0x02, /* Report Count (2), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x81, 0x06, /* Input (Relative), */ ++ 0xC0, /* End Collection, */ ++ ++ 0x06, 0x00, 0xFF, /* Usage Page (Custom), */ ++ 0xA1, 0x02, /* Collection (Logical), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x95, 0x07, /* Report Count (7), */ ++ 0x46, 0xFF, 0x00, /* Physical Maximum (255), */ ++ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ ++ 0x09, 0x01, /* Usage (Pointer), */ ++ 0x91, 0x02, /* Output (Variable), */ ++ 0xC0, /* End Collection, */ ++ ++ 0xC0, /* End Collection */ ++ ++ ++ 0x06, 0x00, 0xFF, /* Usage Page (Custom), */ ++ 0x05, 0x0C, /* Usage Page (Consumer), */ ++ 0x09, 0x01, /* Usage (Consumer Control), */ ++ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x03, /* Report ID (3), */ ++ 0x05, 0x01, /* Usage Page (Desktop), */ ++ 0x09, 0x06, /* Usage (Keyboard), */ ++ 0xA1, 0x02, /* Collection (Logical), */ ++ 0x05, 0x06, /* Usage Page (Generic), */ ++ 0x09, 0x20, /* Usage (Battery Strgth), */ ++ 0x15, 0x00, /* Logical Minimum (0), */ ++ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x06, 0xBC, 0xFF, /* Usage Page (Custom), */ ++ ++ 0x0A, 0xAD, 0xBD, /* UNKNOWN */ ++ ++ 0x75, 0x08, /* Report Size (8), */ ++ 0x95, 0x06, /* Report Count (6), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0xC0, /* End Collection, */ ++ ++ 0xC0, /* End Collection */ ++ ++ 0x00 ++}; ++ ++static __u8 *ouya_report_fixup(struct hid_device *hdev, __u8 *rdesc, ++ unsigned int *rsize) ++{ ++ struct ouya_sc *sc = hid_get_drvdata(hdev); ++ ++ if (sc->quirks & OUYA_TOUCHPAD_FIXUP) { ++ rdesc = ouya_rdesc_fixed; ++ *rsize = sizeof(ouya_rdesc_fixed); ++ } ++ return rdesc; ++} ++ ++static int ouya_input_mapping(struct hid_device *hdev, struct hid_input *hi, ++ struct hid_field *field, struct hid_usage *usage, ++ unsigned long **bit, int *max) ++{ ++ struct ouya_sc *sc = hid_get_drvdata(hdev); ++ ++ if (!(sc->quirks & OUYA_TOUCHPAD_FIXUP)) { ++ return 0; ++ } ++ ++ if ((usage->hid & 0x90000) == 0x90000 && ++ (field->physical & 0xff000000) == 0xff000000 && ++ usage->collection_index == 5 && ++ field->report_count == 3) { ++ ++ hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_MOUSE + (usage->hid - 0x90001)); ++ ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static int ouya_probe(struct hid_device *hdev, const struct hid_device_id *id) ++{ ++ int ret; ++ struct ouya_sc *sc; ++ ++ sc = kzalloc(sizeof(*sc), GFP_KERNEL); ++ if (sc == NULL) { ++ hid_err(hdev, "can't alloc ouya descriptor\n"); ++ return -ENOMEM; ++ } ++ ++ if(((hdev->version & 0xff00) == 0x0100 && (hdev->version & 0xff) >= 0x04) || ++ ((hdev->version & 0xff00) == 0xe100 && (hdev->version & 0xff) >= 0x3a)) { ++ hid_info(hdev, "ouya controller - new version\n"); ++ sc->quirks = OUYA_TOUCHPAD_FIXUP; ++ } else { ++ sc->quirks = 0; ++ } ++ hid_set_drvdata(hdev, sc); ++ ++ ret = hid_parse(hdev); ++ if (ret) { ++ hid_err(hdev, "parse failed\n"); ++ goto err_free; ++ } ++ ++ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT | ++ HID_CONNECT_HIDDEV_FORCE); ++ if (ret) { ++ hid_err(hdev, "hw start failed\n"); ++ goto err_free; ++ } ++ ++ return 0; ++ ++err_free: ++ kfree(sc); ++ return ret; ++} ++ ++static void ouya_remove(struct hid_device *hdev) ++{ ++ hid_hw_stop(hdev); ++ kfree(hid_get_drvdata(hdev)); ++} ++ ++static const struct hid_device_id ouya_devices[] = { ++ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_OUYA, USB_DEVICE_ID_OUYA_CONTROLLER) }, ++ { } ++}; ++MODULE_DEVICE_TABLE(hid, ouya_devices); ++ ++static struct hid_driver ouya_driver = { ++ .name = "ouya", ++ .id_table = ouya_devices, ++ .probe = ouya_probe, ++ .remove = ouya_remove, ++ .input_mapping = ouya_input_mapping, ++ .report_fixup = ouya_report_fixup ++}; ++ ++static int __init ouya_init(void) ++{ ++ return hid_register_driver(&ouya_driver); ++} ++ ++static void __exit ouya_exit(void) ++{ ++ hid_unregister_driver(&ouya_driver); ++} ++ ++module_init(ouya_init); ++module_exit(ouya_exit); +diff -Naur linux-3.19.orig/drivers/hid/Kconfig linux-3.19/drivers/hid/Kconfig +--- linux-3.19.orig/drivers/hid/Kconfig 2015-02-20 14:01:17.081322855 -0800 ++++ linux-3.19/drivers/hid/Kconfig 2015-02-20 14:03:30.381519473 -0800 +@@ -528,6 +528,12 @@ + - Ortek WKB-2000 + - Skycable wireless presenter + ++config HID_OUYA ++ tristate "OUYA Game Controller" ++ depends on USB_HID ++ ---help--- ++ Support for OUYA Game Controller. ++ + config HID_PANTHERLORD + tristate "Pantherlord/GreenAsia game controller" + depends on HID +diff -Naur linux-3.19.orig/drivers/hid/Makefile linux-3.19/drivers/hid/Makefile +--- linux-3.19.orig/drivers/hid/Makefile 2015-02-20 14:01:17.081322855 -0800 ++++ linux-3.19/drivers/hid/Makefile 2015-02-20 14:03:30.382519482 -0800 +@@ -70,6 +70,7 @@ + obj-$(CONFIG_HID_MULTITOUCH) += hid-multitouch.o + obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o + obj-$(CONFIG_HID_ORTEK) += hid-ortek.o ++obj-$(CONFIG_HID_OUYA) += hid-ouya.o + obj-$(CONFIG_HID_PRODIKEYS) += hid-prodikeys.o + obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o + obj-$(CONFIG_HID_PENMOUNT) += hid-penmount.o diff --git a/projects/imx6/patches/linux/4.4-xbian/linux-053-spinelplus-remote-0.2.patch b/projects/imx6/patches/linux/4.4-xbian/linux-053-spinelplus-remote-0.2.patch new file mode 100644 index 0000000000..c85c2a883f --- /dev/null +++ b/projects/imx6/patches/linux/4.4-xbian/linux-053-spinelplus-remote-0.2.patch @@ -0,0 +1,164 @@ +diff -Naur linux-3.19/drivers/hid/hid-core.c linux-3.19.patch/drivers/hid/hid-core.c +--- linux-3.19/drivers/hid/hid-core.c 2015-02-09 03:54:22.000000000 +0100 ++++ linux-3.19.patch/drivers/hid/hid-core.c 2015-02-11 00:06:14.966131308 +0100 +@@ -1886,6 +1886,10 @@ + { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) }, + { HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_6000) }, + { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_SPINEL_PLUS_1) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_SPINEL_PLUS_2) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_SPINEL_PLUS_3) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_SPINEL_PLUS_4) }, + { HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS, HID_ANY_ID) }, + { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) }, + #if IS_ENABLED(CONFIG_HID_ROCCAT) +diff -Naur linux-3.19/drivers/hid/hid-ids.h linux-3.19.patch/drivers/hid/hid-ids.h +--- linux-3.19/drivers/hid/hid-ids.h 2015-02-09 03:54:22.000000000 +0100 ++++ linux-3.19.patch/drivers/hid/hid-ids.h 2015-02-11 00:04:45.885977057 +0100 +@@ -743,6 +743,10 @@ + + #define USB_VENDOR_ID_PHILIPS 0x0471 + #define USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE 0x0617 ++#define USB_DEVICE_ID_PHILIPS_SPINEL_PLUS_1 0x206c ++#define USB_DEVICE_ID_PHILIPS_SPINEL_PLUS_2 0x20cc ++#define USB_DEVICE_ID_PHILIPS_SPINEL_PLUS_3 0x0613 ++#define USB_DEVICE_ID_PHILIPS_SPINEL_PLUS_4 0x2168 + + #define USB_VENDOR_ID_PI_ENGINEERING 0x05f3 + #define USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL 0xff +diff -Naur linux-3.19/drivers/hid/hid-spinelplus.c linux-3.19.patch/drivers/hid/hid-spinelplus.c +--- linux-3.19/drivers/hid/hid-spinelplus.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.19.patch/drivers/hid/hid-spinelplus.c 2015-02-11 00:04:45.886977059 +0100 +@@ -0,0 +1,105 @@ ++/* ++ * HID driver for "PHILIPS MCE USB IR Receiver- Spinel plus" remotes ++ * ++ * Copyright (c) 2010 Panagiotis Skintzos ++ * ++ * Renamed to Spinel, cleanup and modified to also support ++ * Spinel Plus 0471:20CC by Stephan Raue 2012. ++ */ ++ ++/* ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the Free ++ * Software Foundation; either version 2 of the License, or (at your option) ++ * any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "hid-ids.h" ++ ++#define spinelplus_map_key(c) set_bit(EV_REP, hi->input->evbit); \ ++ hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c)) ++ ++static int spinelplus_input_mapping(struct hid_device *hdev, ++ struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, ++ unsigned long **bit, int *max) ++{ ++ switch (usage->hid) { ++ case 0xffbc000d: spinelplus_map_key(KEY_MEDIA); break; ++ case 0xffbc0024: spinelplus_map_key(KEY_MEDIA); break; ++ case 0xffbc0027: spinelplus_map_key(KEY_ZOOM); break; ++ case 0xffbc0033: spinelplus_map_key(KEY_HOME); break; ++ case 0xffbc0035: spinelplus_map_key(KEY_CAMERA); break; ++ case 0xffbc0036: spinelplus_map_key(KEY_EPG); break; ++ case 0xffbc0037: spinelplus_map_key(KEY_DVD); break; ++ case 0xffbc0038: spinelplus_map_key(KEY_HOME); break; ++ case 0xffbc0039: spinelplus_map_key(KEY_MP3); break; ++ case 0xffbc003a: spinelplus_map_key(KEY_VIDEO); break; ++ case 0xffbc005a: spinelplus_map_key(KEY_TEXT); break; ++ case 0xffbc005b: spinelplus_map_key(KEY_RED); break; ++ case 0xffbc005c: spinelplus_map_key(KEY_GREEN); break; ++ case 0xffbc005d: spinelplus_map_key(KEY_YELLOW); break; ++ case 0xffbc005e: spinelplus_map_key(KEY_BLUE); break; ++ default: ++ return 0; ++ } ++ return 1; ++} ++ ++static int spinelplus_probe(struct hid_device *hdev, ++ const struct hid_device_id *id) ++{ ++ int ret; ++ /* Connect only to hid input (not hiddev & hidraw)*/ ++ unsigned int cmask = HID_CONNECT_HIDINPUT; ++ ++ ret = hid_parse(hdev); ++ if (ret) { ++ dev_err(&hdev->dev, "parse failed\n"); ++ goto err_free; ++ } ++ ++ ret = hid_hw_start(hdev, cmask); ++ if (ret) { ++ dev_err(&hdev->dev, "hw start failed\n"); ++ goto err_free; ++ } ++ ++ return 0; ++err_free: ++ return ret; ++} ++ ++static const struct hid_device_id spinelplus_devices[] = { ++ { HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS,USB_DEVICE_ID_PHILIPS_SPINEL_PLUS_1) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS,USB_DEVICE_ID_PHILIPS_SPINEL_PLUS_2) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS,USB_DEVICE_ID_PHILIPS_SPINEL_PLUS_3) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS,USB_DEVICE_ID_PHILIPS_SPINEL_PLUS_4) }, ++ { } ++}; ++MODULE_DEVICE_TABLE(hid, spinelplus_devices); ++ ++static struct hid_driver spinelplus_driver = { ++ .name = "SpinelPlus", ++ .id_table = spinelplus_devices, ++ .input_mapping = spinelplus_input_mapping, ++ .probe = spinelplus_probe, ++}; ++ ++static int __init spinelplus_init(void) ++{ ++ return hid_register_driver(&spinelplus_driver); ++} ++ ++static void __exit spinelplus_exit(void) ++{ ++ hid_unregister_driver(&spinelplus_driver); ++} ++ ++module_init(spinelplus_init); ++module_exit(spinelplus_exit); ++MODULE_LICENSE("GPL"); +diff -Naur linux-3.19/drivers/hid/Kconfig linux-3.19.patch/drivers/hid/Kconfig +--- linux-3.19/drivers/hid/Kconfig 2015-02-09 03:54:22.000000000 +0100 ++++ linux-3.19.patch/drivers/hid/Kconfig 2015-02-11 00:04:45.886977059 +0100 +@@ -702,6 +702,12 @@ + ---help--- + Support for Steelseries SRW-S1 steering wheel + ++config HID_SPINELPLUS ++ tristate "Spinel Plus remote control" ++ depends on USB_HID ++ ---help--- ++ Say Y here if you have a Spinel Plus (0471:206c/20cc/0613/2168) remote ++ + config HID_SUNPLUS + tristate "Sunplus wireless desktop" + depends on HID +diff -Naur linux-3.19/drivers/hid/Makefile linux-3.19.patch/drivers/hid/Makefile +--- linux-3.19/drivers/hid/Makefile 2015-02-09 03:54:22.000000000 +0100 ++++ linux-3.19.patch/drivers/hid/Makefile 2015-02-11 00:04:45.886977059 +0100 +@@ -107,6 +107,7 @@ + obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o + obj-$(CONFIG_HID_SONY) += hid-sony.o + obj-$(CONFIG_HID_SPEEDLINK) += hid-speedlink.o ++obj-$(CONFIG_HID_SPINELPLUS) += hid-spinelplus.o + obj-$(CONFIG_HID_STEELSERIES) += hid-steelseries.o + obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o + obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o diff --git a/projects/imx6/patches/linux/4.4-xbian/linux-056-add_Adaptec_eHome_Infrared_Receiver.patch b/projects/imx6/patches/linux/4.4-xbian/linux-056-add_Adaptec_eHome_Infrared_Receiver.patch new file mode 100644 index 0000000000..4116b9ff86 --- /dev/null +++ b/projects/imx6/patches/linux/4.4-xbian/linux-056-add_Adaptec_eHome_Infrared_Receiver.patch @@ -0,0 +1,21 @@ +diff -Naur linux-3.17.1/drivers/media/rc/mceusb.c linux-3.17.1.patch/drivers/media/rc/mceusb.c +--- linux-3.17.1/drivers/media/rc/mceusb.c 2014-10-15 12:29:30.000000000 +0200 ++++ linux-3.17.1.patch/drivers/media/rc/mceusb.c 2014-10-16 11:45:57.480176874 +0200 +@@ -188,6 +188,8 @@ + #define VENDOR_TWISTEDMELON 0x2596 + #define VENDOR_HAUPPAUGE 0x2040 + #define VENDOR_PCTV 0x2013 ++#define VENDOR_ADAPTEC 0x03f3 ++ + + enum mceusb_model_type { + MCE_GEN2 = 0, /* Most boards */ +@@ -401,6 +403,8 @@ + .driver_info = HAUPPAUGE_CX_HYBRID_TV }, + { USB_DEVICE(VENDOR_PCTV, 0x025e), + .driver_info = HAUPPAUGE_CX_HYBRID_TV }, ++ /* Adaptec / HP eHome Receiver */ ++ { USB_DEVICE(VENDOR_ADAPTEC, 0x0094) }, + + /* Terminating entry */ + { } diff --git a/projects/imx6/patches/linux/4.4-xbian/linux-057-Removed-MCE-customer-code-restriction-in-rc6-decode.patch b/projects/imx6/patches/linux/4.4-xbian/linux-057-Removed-MCE-customer-code-restriction-in-rc6-decode.patch new file mode 100644 index 0000000000..2bc9542311 --- /dev/null +++ b/projects/imx6/patches/linux/4.4-xbian/linux-057-Removed-MCE-customer-code-restriction-in-rc6-decode.patch @@ -0,0 +1,28 @@ +--- linux/drivers/media/rc/ir-rc6-decoder.c 2012-11-25 22:08:13.148418669 -0800 ++++ linux.patch/drivers/media/rc/ir-rc6-decoder.c 2012-11-25 22:07:48.864417975 -0800 +@@ -39,7 +39,6 @@ + #define RC6_STARTBIT_MASK 0x08 /* for the header bits */ + #define RC6_6A_MCE_TOGGLE_MASK 0x8000 /* for the body bits */ + #define RC6_6A_LCC_MASK 0xffff0000 /* RC6-6A-32 long customer code mask */ +-#define RC6_6A_MCE_CC 0x800f0000 /* MCE customer code */ + #ifndef CHAR_BIT + #define CHAR_BIT 8 /* Normally in */ + #endif +@@ -257,14 +256,9 @@ again: + toggle = 0; + break; + case 32: +- if ((scancode & RC6_6A_LCC_MASK) == RC6_6A_MCE_CC) { +- protocol = RC_TYPE_RC6_MCE; +- toggle = !!(scancode & RC6_6A_MCE_TOGGLE_MASK); +- scancode &= ~RC6_6A_MCE_TOGGLE_MASK; +- } else { +- protocol = RC_BIT_RC6_6A_32; +- toggle = 0; +- } ++ protocol = RC_TYPE_RC6_MCE; ++ toggle = !!(scancode & RC6_6A_MCE_TOGGLE_MASK); ++ scancode &= ~RC6_6A_MCE_TOGGLE_MASK; + break; + default: + IR_dprintk(1, "RC6(6A) unsupported length\n"); diff --git a/projects/imx6/patches/linux/4.4-xbian/linux-057-add_SMK_Manufacturing_Inc_Infrared_Receiver.patch b/projects/imx6/patches/linux/4.4-xbian/linux-057-add_SMK_Manufacturing_Inc_Infrared_Receiver.patch new file mode 100644 index 0000000000..67fc7a0de8 --- /dev/null +++ b/projects/imx6/patches/linux/4.4-xbian/linux-057-add_SMK_Manufacturing_Inc_Infrared_Receiver.patch @@ -0,0 +1,13 @@ +diff -Naur linux-3.9.4/drivers/media/rc/mceusb.c linux-3.9.4.patch/drivers/media/rc/mceusb.c +--- linux-3.9.4/drivers/media/rc/mceusb.c 2013-05-24 20:45:59.000000000 +0200 ++++ linux-3.9.4.patch/drivers/media/rc/mceusb.c 2013-05-27 12:28:12.811230633 +0200 +@@ -309,6 +309,9 @@ + /* SMK/I-O Data GV-MC7/RCKIT Receiver */ + { USB_DEVICE(VENDOR_SMK, 0x0353), + .driver_info = MCE_GEN2_NO_TX }, ++ /* SMK Manufacturing, Inc. Receiver */ ++ { USB_DEVICE(VENDOR_SMK, 0x0357), ++ .driver_info = MCE_GEN2_NO_TX }, + /* Tatung eHome Infrared Transceiver */ + { USB_DEVICE(VENDOR_TATUNG, 0x9150) }, + /* Shuttle eHome Infrared Transceiver */ diff --git a/projects/imx6/patches/linux/4.4-xbian/linux-058.05-hid_sony-add_autorepeat_for_PS3_remotes.patch b/projects/imx6/patches/linux/4.4-xbian/linux-058.05-hid_sony-add_autorepeat_for_PS3_remotes.patch new file mode 100644 index 0000000000..c3d77a7028 --- /dev/null +++ b/projects/imx6/patches/linux/4.4-xbian/linux-058.05-hid_sony-add_autorepeat_for_PS3_remotes.patch @@ -0,0 +1,70 @@ +From 7051422474e4c4e302ede3d07ffd8ef2682e07a2 Mon Sep 17 00:00:00 2001 +From: Stefan Saraev +Date: Tue, 22 Apr 2014 16:05:14 +0300 +Subject: [PATCH] [RFC] hid/sony: add autorepeat for PS3 remotes + +adapted to 3.17 + +Betreff: [RFC] hid/sony: add autorepeat for PS3 remotes +Von: David Dillow +Datum: 28.06.2013 04:28 +An: linux-input@vger.kernel.org +Kopie (CC): Stephan Raue + +Some applications using the PS3 remote would like to have autorepeat +from the device. Use the input subsystem's software emulation to provide +this capability, and enable those that don't need it to turn it off. +--- +I'm not sure this is the correct approach, or if it is even appropriate +for a remote to do autorepeat. However, the media/rc subsystem does do +it by default, and it's been requested by users, so there is at least +some demand. + +This compiled against the hid-sony driver with the PS3 remote changes +merged, but I have done no testing of it. If the approach seems +reasonable, I'll try to test it when the MythTV is idle. +--- + drivers/hid/hid-sony.c | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c +index 661f94f..2256e35 100644 +--- a/drivers/hid/hid-sony.c ++++ b/drivers/hid/hid-sony.c +@@ -1111,6 +1111,25 @@ static int ps3remote_mapping(struct hid_device *hdev, struct hid_input *hi, + return 1; + } + ++static int ps3remote_setup_repeat(struct hid_device *hdev) ++{ ++ struct hid_input *hidinput = list_first_entry(&hdev->inputs, ++ struct hid_input, list); ++ struct input_dev *input = hidinput->input; ++ ++ /* ++ * Set up autorepeat defaults per the remote control subsystem; ++ * this must be done after hid_hw_start(), as having these non-zero ++ * at the time of input_register_device() tells the input system that ++ * the hardware does the autorepeat, and the PS3 remote does not. ++ */ ++ set_bit(EV_REP, input->evbit); ++ input->rep[REP_DELAY] = 500; ++ input->rep[REP_PERIOD] = 125; ++ ++ return 0; ++} ++ + static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) + { +@@ -2339,6 +2358,8 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) + sony_init_work(sc, dualshock4_state_worker); + } else if (sc->quirks & MOTION_CONTROLLER) { + sony_init_work(sc, motion_state_worker); ++ } else if (sc->quirks & PS3REMOTE) { ++ ret = ps3remote_setup_repeat(hdev); + } else { + ret = 0; + } +-- +1.9.1 diff --git a/projects/imx6/patches/linux/4.4-xbian/linux-062-imon_pad_ignore_diagonal.patch b/projects/imx6/patches/linux/4.4-xbian/linux-062-imon_pad_ignore_diagonal.patch new file mode 100644 index 0000000000..677de3ed7f --- /dev/null +++ b/projects/imx6/patches/linux/4.4-xbian/linux-062-imon_pad_ignore_diagonal.patch @@ -0,0 +1,21 @@ +diff -Naur linux-3.16.1/drivers/media/rc/imon.c linux-3.16.1.patch/drivers/media/rc/imon.c +--- linux-3.16.1/drivers/media/rc/imon.c 2014-08-14 04:36:35.000000000 +0200 ++++ linux-3.16.1.patch/drivers/media/rc/imon.c 2014-08-15 13:57:16.587620642 +0200 +@@ -1344,6 +1344,17 @@ + } + } else { + /* ++ * For users without stabilized, just ignore any value getting ++ * to close to the diagonal. ++ */ ++ if ((abs(rel_y) < 2 && abs(rel_x) < 2) || ++ abs(abs(rel_y) - abs(rel_x)) < 2 ) { ++ spin_lock_irqsave(&ictx->kc_lock, flags); ++ ictx->kc = KEY_UNKNOWN; ++ spin_unlock_irqrestore(&ictx->kc_lock, flags); ++ return; ++ } ++ /* + * Hack alert: instead of using keycodes, we have + * to use hard-coded scancodes here... + */ diff --git a/projects/imx6/patches/linux/4.4-xbian/linux-063-xpad-fix_xbox360_wireless.patch b/projects/imx6/patches/linux/4.4-xbian/linux-063-xpad-fix_xbox360_wireless.patch new file mode 100644 index 0000000000..67b8689582 --- /dev/null +++ b/projects/imx6/patches/linux/4.4-xbian/linux-063-xpad-fix_xbox360_wireless.patch @@ -0,0 +1,963 @@ +From 627e828fcf1bb9fc71dbbeca29acd33162efb448 Mon Sep 17 00:00:00 2001 +From: Matt DeVillier +Date: Wed, 2 Mar 2016 23:11:33 -0600 +Subject: [PATCH 1/1] linux/drivers/input/joystick/xpad: fixes for xbox360/one controllers + +merged from https://github.com/paroj/xpad + +- fixed blinking LED on Xbox 360 Wireless Controllers +- only expose actually connected Xbox 360 Wireless Controllers +- fixed kernel warnings due to submitting active URB requests +- updated Xbox One controller force feedback +- controller still works after suspend/ resume +- Xbox 360 Wireless button mappings are now compatible with Xbox 360 (non-wireless) mappings + +Signed-off-by: Matt DeVillier +--- + drivers/input/joystick/xpad.c | 608 ++++++++++++++++++++++++++++++------------ + 1 file changed, 432 insertions(+), 176 deletions(-) + +diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c +index fd4100d..1ee6626 100644 +--- a/drivers/input/joystick/xpad.c ++++ b/drivers/input/joystick/xpad.c +@@ -74,12 +74,15 @@ + * + * Later changes can be tracked in SCM. + */ +- ++#define DEBUG + #include ++#include ++#include + #include + #include + #include + #include ++#include + + #define DRIVER_AUTHOR "Marko Friedemann " + #define DRIVER_DESC "X-Box pad driver" +@@ -125,7 +128,8 @@ static const struct xpad_device { + { 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, 0x02dd, "Microsoft X-Box One pad (Covert Forces)", 0, XTYPE_XBOXONE }, ++ { 0x045e, 0x02dd, "Microsoft X-Box One pad (Firmware 2015)", 0, XTYPE_XBOXONE }, ++ { 0x0e6f, 0x0139, "Afterglow Prismatic Wired Controller", 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 }, +@@ -298,6 +302,7 @@ static struct usb_device_id xpad_table[] = { + XPAD_XBOX360_VENDOR(0x044f), /* Thrustmaster X-Box 360 controllers */ + XPAD_XBOX360_VENDOR(0x045e), /* Microsoft X-Box 360 controllers */ + XPAD_XBOXONE_VENDOR(0x045e), /* Microsoft X-Box One controllers */ ++ XPAD_XBOXONE_VENDOR(0x0e6f), /* 0x0e6f 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 */ +@@ -317,21 +322,42 @@ static struct usb_device_id xpad_table[] = { + + MODULE_DEVICE_TABLE(usb, xpad_table); + ++struct xpad_output_packet { ++ u8 data[XPAD_PKT_LEN]; ++ u8 len; ++ bool pending; ++}; ++ ++#define XPAD_OUT_CMD_IDX 0 ++#define XPAD_OUT_FF_IDX 1 ++#define XPAD_OUT_LED_IDX (1 + IS_ENABLED(CONFIG_JOYSTICK_XPAD_FF)) ++#define XPAD_NUM_OUT_PACKETS (1 + \ ++ IS_ENABLED(CONFIG_JOYSTICK_XPAD_FF) + \ ++ IS_ENABLED(CONFIG_JOYSTICK_XPAD_LEDS)) ++ + struct usb_xpad { + struct input_dev *dev; /* input device interface */ ++ struct input_dev __rcu *x360w_dev; + struct usb_device *udev; /* usb device */ + struct usb_interface *intf; /* usb interface */ + +- int pad_present; ++ bool pad_present; ++ bool input_created; + + struct urb *irq_in; /* urb for interrupt in report */ + unsigned char *idata; /* input data */ + dma_addr_t idata_dma; + + struct urb *irq_out; /* urb for interrupt out report */ ++ struct usb_anchor irq_out_anchor; ++ bool irq_out_active; /* we must not use an active URB */ ++ u8 odata_serial; /* serial number for xbox one protocol */ + unsigned char *odata; /* output data */ + dma_addr_t odata_dma; +- struct mutex odata_mutex; ++ spinlock_t odata_lock; ++ ++ struct xpad_output_packet out_packets[XPAD_NUM_OUT_PACKETS]; ++ int last_out_packet; + + #if defined(CONFIG_JOYSTICK_XPAD_LEDS) + struct xpad_led *led; +@@ -343,8 +369,12 @@ struct usb_xpad { + int xtype; /* type of xbox device */ + int pad_nr; /* the order x360 pads were attached */ + const char *name; /* name of the device */ ++ struct work_struct work; /* init/remove device from callback */ + }; + ++static int xpad_init_input(struct usb_xpad *xpad); ++static void xpad_deinit_input(struct usb_xpad *xpad); ++ + /* + * xpad_process_packet + * +@@ -424,11 +454,9 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d + * http://www.free60.org/wiki/Gamepad + */ + +-static void xpad360_process_packet(struct usb_xpad *xpad, ++static void xpad360_process_packet(struct usb_xpad *xpad, struct input_dev *dev, + u16 cmd, unsigned char *data) + { +- struct input_dev *dev = xpad->dev; +- + /* digital pad */ + if (xpad->mapping & MAP_DPAD_TO_BUTTONS) { + /* dpad as buttons (left, right, up, down) */ +@@ -495,7 +523,30 @@ static void xpad360_process_packet(struct usb_xpad *xpad, + input_sync(dev); + } + +-static void xpad_identify_controller(struct usb_xpad *xpad); ++static void xpad_presence_work(struct work_struct *work) ++{ ++ struct usb_xpad *xpad = container_of(work, struct usb_xpad, work); ++ int error; ++ ++ if (xpad->pad_present) { ++ error = xpad_init_input(xpad); ++ if (error) { ++ /* complain only, not much else we can do here */ ++ dev_err(&xpad->dev->dev, ++ "unable to init device: %d\n", error); ++ } else { ++ rcu_assign_pointer(xpad->x360w_dev, xpad->dev); ++ } ++ } else { ++ RCU_INIT_POINTER(xpad->x360w_dev, NULL); ++ synchronize_rcu(); ++ /* ++ * Now that we are sure xpad360w_process_packet is not ++ * using input device we can get rid of it. ++ */ ++ xpad_deinit_input(xpad); ++ } ++} + + /* + * xpad360w_process_packet +@@ -513,24 +564,28 @@ static void xpad_identify_controller(struct usb_xpad *xpad); + */ + static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data) + { ++ struct input_dev *dev; ++ bool present; ++ + /* Presence change */ + if (data[0] & 0x08) { +- if (data[1] & 0x80) { +- xpad->pad_present = 1; +- /* +- * Light up the segment corresponding to +- * controller number. +- */ +- xpad_identify_controller(xpad); +- } else +- xpad->pad_present = 0; ++ present = (data[1] & 0x80) != 0; ++ ++ if (xpad->pad_present != present) { ++ xpad->pad_present = present; ++ schedule_work(&xpad->work); ++ } + } + + /* Valid pad data */ +- if (!(data[1] & 0x1)) ++ if (data[1] != 0x1) + return; + +- xpad360_process_packet(xpad, cmd, &data[4]); ++ rcu_read_lock(); ++ dev = rcu_dereference(xpad->x360w_dev); ++ if (dev) ++ xpad360_process_packet(xpad, dev, cmd, &data[4]); ++ rcu_read_unlock(); + } + + /* +@@ -659,7 +714,7 @@ static void xpad_irq_in(struct urb *urb) + + switch (xpad->xtype) { + case XTYPE_XBOX360: +- xpad360_process_packet(xpad, 0, xpad->idata); ++ xpad360_process_packet(xpad, xpad->dev, 0, xpad->idata); + break; + case XTYPE_XBOX360W: + xpad360w_process_packet(xpad, 0, xpad->idata); +@@ -678,18 +733,73 @@ exit: + __func__, retval); + } + ++/* Callers must hold xpad->odata_lock spinlock */ ++static bool xpad_prepare_next_out_packet(struct usb_xpad *xpad) ++{ ++ struct xpad_output_packet *pkt, *packet = NULL; ++ int i; ++ ++ for (i = 0; i < XPAD_NUM_OUT_PACKETS; i++) { ++ if (++xpad->last_out_packet >= XPAD_NUM_OUT_PACKETS) ++ xpad->last_out_packet = 0; ++ ++ pkt = &xpad->out_packets[xpad->last_out_packet]; ++ if (pkt->pending) { ++ dev_dbg(&xpad->intf->dev, ++ "%s - found pending output packet %d\n", ++ __func__, xpad->last_out_packet); ++ packet = pkt; ++ break; ++ } ++ } ++ ++ if (packet) { ++ memcpy(xpad->odata, packet->data, packet->len); ++ xpad->irq_out->transfer_buffer_length = packet->len; ++ return true; ++ } ++ ++ return false; ++} ++ ++/* Callers must hold xpad->odata_lock spinlock */ ++static int xpad_try_sending_next_out_packet(struct usb_xpad *xpad) ++{ ++ int error; ++ ++ if (!xpad->irq_out_active && xpad_prepare_next_out_packet(xpad)) { ++ usb_anchor_urb(xpad->irq_out, &xpad->irq_out_anchor); ++ error = usb_submit_urb(xpad->irq_out, GFP_ATOMIC); ++ if (error) { ++ dev_err(&xpad->intf->dev, ++ "%s - usb_submit_urb failed with result %d\n", ++ __func__, error); ++ usb_unanchor_urb(xpad->irq_out); ++ return -EIO; ++ } ++ ++ xpad->irq_out_active = true; ++ } ++ ++ return 0; ++} ++ + static void xpad_irq_out(struct urb *urb) + { + struct usb_xpad *xpad = urb->context; + struct device *dev = &xpad->intf->dev; +- int retval, status; ++ int status = urb->status; ++ int error; ++ unsigned long flags; + +- status = urb->status; ++ spin_lock_irqsave(&xpad->odata_lock, flags); + + switch (status) { + case 0: + /* success */ +- return; ++ xpad->out_packets[xpad->last_out_packet].pending = false; ++ xpad->irq_out_active = xpad_prepare_next_out_packet(xpad); ++ break; + + case -ECONNRESET: + case -ENOENT: +@@ -697,43 +807,52 @@ static void xpad_irq_out(struct urb *urb) + /* this urb is terminated, clean up */ + dev_dbg(dev, "%s - urb shutting down with status: %d\n", + __func__, status); +- return; ++ xpad->irq_out_active = false; ++ break; + + default: + dev_dbg(dev, "%s - nonzero urb status received: %d\n", + __func__, status); +- goto exit; ++ break; + } + +-exit: +- retval = usb_submit_urb(urb, GFP_ATOMIC); +- if (retval) +- dev_err(dev, "%s - usb_submit_urb failed with result %d\n", +- __func__, retval); ++ if (xpad->irq_out_active) { ++ usb_anchor_urb(urb, &xpad->irq_out_anchor); ++ error = usb_submit_urb(urb, GFP_ATOMIC); ++ if (error) { ++ dev_err(dev, ++ "%s - usb_submit_urb failed with result %d\n", ++ __func__, error); ++ usb_unanchor_urb(urb); ++ xpad->irq_out_active = false; ++ } ++ } ++ ++ spin_unlock_irqrestore(&xpad->odata_lock, flags); + } + + 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) + return 0; + ++ init_usb_anchor(&xpad->irq_out_anchor); ++ + xpad->odata = usb_alloc_coherent(xpad->udev, XPAD_PKT_LEN, + GFP_KERNEL, &xpad->odata_dma); + if (!xpad->odata) { +- error = -ENOMEM; +- goto fail1; ++ return -ENOMEM; + } + +- mutex_init(&xpad->odata_mutex); ++ spin_lock_init(&xpad->odata_lock); + + xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL); + if (!xpad->irq_out) { +- error = -ENOMEM; +- goto fail2; ++ usb_free_coherent(xpad->udev, XPAD_PKT_LEN, xpad->odata, xpad->odata_dma); ++ return -ENOMEM; + } + + /* Xbox One controller has in/out endpoints swapped. */ +@@ -748,15 +867,18 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) + xpad->irq_out->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + return 0; +- +- fail2: usb_free_coherent(xpad->udev, XPAD_PKT_LEN, xpad->odata, xpad->odata_dma); +- fail1: return error; + } + + static void xpad_stop_output(struct usb_xpad *xpad) + { +- if (xpad->xtype != XTYPE_UNKNOWN) +- usb_kill_urb(xpad->irq_out); ++ if (xpad->xtype != XTYPE_UNKNOWN) { ++ if (!usb_wait_anchor_empty_timeout(&xpad->irq_out_anchor, ++ 5000)) { ++ dev_warn(&xpad->intf->dev, ++ "timed out waiting for output URB to complete, killing\n"); ++ usb_kill_anchored_urbs(&xpad->irq_out_anchor); ++ } ++ } + } + + static void xpad_deinit_output(struct usb_xpad *xpad) +@@ -770,27 +892,60 @@ static void xpad_deinit_output(struct usb_xpad *xpad) + + static int xpad_inquiry_pad_presence(struct usb_xpad *xpad) + { ++ struct xpad_output_packet *packet = ++ &xpad->out_packets[XPAD_OUT_CMD_IDX]; ++ unsigned long flags; ++ int retval; ++ ++ spin_lock_irqsave(&xpad->odata_lock, flags); ++ ++ packet->data[0] = 0x08; ++ packet->data[1] = 0x00; ++ packet->data[2] = 0x0F; ++ packet->data[3] = 0xC0; ++ packet->data[4] = 0x00; ++ packet->data[5] = 0x00; ++ packet->data[6] = 0x00; ++ packet->data[7] = 0x00; ++ packet->data[8] = 0x00; ++ packet->data[9] = 0x00; ++ packet->data[10] = 0x00; ++ packet->data[11] = 0x00; ++ packet->len = 12; ++ packet->pending = true; ++ ++ /* Reset the sequence so we send out presence first */ ++ xpad->last_out_packet = -1; ++ retval = xpad_try_sending_next_out_packet(xpad); ++ ++ spin_unlock_irqrestore(&xpad->odata_lock, flags); ++ ++ return retval; ++} ++ ++static int xpad_start_xbox_one(struct usb_xpad *xpad) ++{ ++ struct xpad_output_packet *packet = ++ &xpad->out_packets[XPAD_OUT_CMD_IDX]; ++ unsigned long flags; + int retval; + +- mutex_lock(&xpad->odata_mutex); ++ spin_lock_irqsave(&xpad->odata_lock, flags); + +- xpad->odata[0] = 0x08; +- xpad->odata[1] = 0x00; +- xpad->odata[2] = 0x0F; +- xpad->odata[3] = 0xC0; +- xpad->odata[4] = 0x00; +- xpad->odata[5] = 0x00; +- xpad->odata[6] = 0x00; +- xpad->odata[7] = 0x00; +- xpad->odata[8] = 0x00; +- xpad->odata[9] = 0x00; +- xpad->odata[10] = 0x00; +- xpad->odata[11] = 0x00; +- xpad->irq_out->transfer_buffer_length = 12; ++ /* Xbox one controller needs to be initialized. */ ++ packet->data[0] = 0x05; ++ packet->data[1] = 0x20; ++ packet->data[2] = xpad->odata_serial++; /* packet serial */ ++ packet->data[3] = 0x01; /* rumble bit enable? */ ++ packet->data[4] = 0x00; ++ packet->len = 5; ++ packet->pending = true; + +- retval = usb_submit_urb(xpad->irq_out, GFP_KERNEL); ++ /* Reset the sequence so we send out start packet first */ ++ xpad->last_out_packet = -1; ++ retval = xpad_try_sending_next_out_packet(xpad); + +- mutex_unlock(&xpad->odata_mutex); ++ spin_unlock_irqrestore(&xpad->odata_lock, flags); + + return retval; + } +@@ -799,8 +954,11 @@ static int xpad_inquiry_pad_presence(struct usb_xpad *xpad) + static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect) + { + struct usb_xpad *xpad = input_get_drvdata(dev); ++ struct xpad_output_packet *packet = &xpad->out_packets[XPAD_OUT_FF_IDX]; + __u16 strong; + __u16 weak; ++ int retval; ++ unsigned long flags; + + if (effect->type != FF_RUMBLE) + return 0; +@@ -808,69 +966,81 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect + strong = effect->u.rumble.strong_magnitude; + weak = effect->u.rumble.weak_magnitude; + ++ spin_lock_irqsave(&xpad->odata_lock, flags); ++ + switch (xpad->xtype) { + case XTYPE_XBOX: +- xpad->odata[0] = 0x00; +- xpad->odata[1] = 0x06; +- xpad->odata[2] = 0x00; +- xpad->odata[3] = strong / 256; /* left actuator */ +- xpad->odata[4] = 0x00; +- xpad->odata[5] = weak / 256; /* right actuator */ +- xpad->irq_out->transfer_buffer_length = 6; ++ packet->data[0] = 0x00; ++ packet->data[1] = 0x06; ++ packet->data[2] = 0x00; ++ packet->data[3] = strong / 256; /* left actuator */ ++ packet->data[4] = 0x00; ++ packet->data[5] = weak / 256; /* right actuator */ ++ packet->len = 6; ++ packet->pending = true; + break; + + case XTYPE_XBOX360: +- xpad->odata[0] = 0x00; +- xpad->odata[1] = 0x08; +- xpad->odata[2] = 0x00; +- xpad->odata[3] = strong / 256; /* left actuator? */ +- xpad->odata[4] = weak / 256; /* right actuator? */ +- xpad->odata[5] = 0x00; +- xpad->odata[6] = 0x00; +- xpad->odata[7] = 0x00; +- xpad->irq_out->transfer_buffer_length = 8; ++ packet->data[0] = 0x00; ++ packet->data[1] = 0x08; ++ packet->data[2] = 0x00; ++ packet->data[3] = strong / 256; /* left actuator? */ ++ packet->data[4] = weak / 256; /* right actuator? */ ++ packet->data[5] = 0x00; ++ packet->data[6] = 0x00; ++ packet->data[7] = 0x00; ++ packet->len = 8; ++ packet->pending = true; + break; + + case XTYPE_XBOX360W: +- xpad->odata[0] = 0x00; +- xpad->odata[1] = 0x01; +- xpad->odata[2] = 0x0F; +- xpad->odata[3] = 0xC0; +- xpad->odata[4] = 0x00; +- xpad->odata[5] = strong / 256; +- xpad->odata[6] = weak / 256; +- xpad->odata[7] = 0x00; +- xpad->odata[8] = 0x00; +- xpad->odata[9] = 0x00; +- xpad->odata[10] = 0x00; +- xpad->odata[11] = 0x00; +- xpad->irq_out->transfer_buffer_length = 12; ++ packet->data[0] = 0x00; ++ packet->data[1] = 0x01; ++ packet->data[2] = 0x0F; ++ packet->data[3] = 0xC0; ++ packet->data[4] = 0x00; ++ packet->data[5] = strong / 256; ++ packet->data[6] = weak / 256; ++ packet->data[7] = 0x00; ++ packet->data[8] = 0x00; ++ packet->data[9] = 0x00; ++ packet->data[10] = 0x00; ++ packet->data[11] = 0x00; ++ packet->len = 12; ++ packet->pending = true; + break; + + case XTYPE_XBOXONE: +- xpad->odata[0] = 0x09; /* activate rumble */ +- xpad->odata[1] = 0x08; +- xpad->odata[2] = 0x00; +- xpad->odata[3] = 0x08; /* continuous effect */ +- xpad->odata[4] = 0x00; /* simple rumble mode */ +- xpad->odata[5] = 0x03; /* L and R actuator only */ +- xpad->odata[6] = 0x00; /* TODO: LT actuator */ +- xpad->odata[7] = 0x00; /* TODO: RT actuator */ +- xpad->odata[8] = strong / 256; /* left actuator */ +- xpad->odata[9] = weak / 256; /* right actuator */ +- xpad->odata[10] = 0x80; /* length of pulse */ +- xpad->odata[11] = 0x00; /* stop period of pulse */ +- xpad->irq_out->transfer_buffer_length = 12; ++ packet->data[0] = 0x09; /* activate rumble */ ++ packet->data[1] = 0x08; ++ packet->data[2] = xpad->odata_serial++; ++ packet->data[3] = 0x08; /* continuous effect */ ++ packet->data[4] = 0x00; /* simple rumble mode */ ++ packet->data[5] = 0x03; /* L and R actuator only */ ++ packet->data[6] = 0x00; /* TODO: LT actuator */ ++ packet->data[7] = 0x00; /* TODO: RT actuator */ ++ packet->data[8] = strong / 512; /* left actuator */ ++ packet->data[9] = weak / 512; /* right actuator */ ++ packet->data[10] = 0x80; /* length of pulse */ ++ packet->data[11] = 0x00; /* stop period of pulse */ ++ packet->data[12] = 0x00; ++ packet->len = 13; ++ packet->pending = true; + break; + + default: + dev_dbg(&xpad->dev->dev, + "%s - rumble command sent to unsupported xpad type: %d\n", + __func__, xpad->xtype); +- return -EINVAL; ++ retval = -EINVAL; ++ goto out; + } + +- return usb_submit_urb(xpad->irq_out, GFP_ATOMIC); ++ retval = xpad_try_sending_next_out_packet(xpad); ++ ++out: ++ spin_unlock_irqrestore(&xpad->odata_lock, flags); ++ return retval; + } + + static int xpad_init_ff(struct usb_xpad *xpad) +@@ -921,36 +1091,44 @@ struct xpad_led { + */ + static void xpad_send_led_command(struct usb_xpad *xpad, int command) + { ++ struct xpad_output_packet *packet = ++ &xpad->out_packets[XPAD_OUT_LED_IDX]; ++ unsigned long flags; ++ + command %= 16; + +- mutex_lock(&xpad->odata_mutex); ++ spin_lock_irqsave(&xpad->odata_lock, flags); + + switch (xpad->xtype) { + case XTYPE_XBOX360: +- xpad->odata[0] = 0x01; +- xpad->odata[1] = 0x03; +- xpad->odata[2] = command; +- xpad->irq_out->transfer_buffer_length = 3; ++ packet->data[0] = 0x01; ++ packet->data[1] = 0x03; ++ packet->data[2] = command; ++ packet->len = 3; ++ packet->pending = true; + break; ++ + case XTYPE_XBOX360W: +- xpad->odata[0] = 0x00; +- xpad->odata[1] = 0x00; +- xpad->odata[2] = 0x08; +- xpad->odata[3] = 0x40 + command; +- xpad->odata[4] = 0x00; +- xpad->odata[5] = 0x00; +- xpad->odata[6] = 0x00; +- xpad->odata[7] = 0x00; +- xpad->odata[8] = 0x00; +- xpad->odata[9] = 0x00; +- xpad->odata[10] = 0x00; +- xpad->odata[11] = 0x00; +- xpad->irq_out->transfer_buffer_length = 12; ++ packet->data[0] = 0x00; ++ packet->data[1] = 0x00; ++ packet->data[2] = 0x08; ++ packet->data[3] = 0x40 + command; ++ packet->data[4] = 0x00; ++ packet->data[5] = 0x00; ++ packet->data[6] = 0x00; ++ packet->data[7] = 0x00; ++ packet->data[8] = 0x00; ++ packet->data[9] = 0x00; ++ packet->data[10] = 0x00; ++ packet->data[11] = 0x00; ++ packet->len = 12; ++ packet->pending = true; + break; + } + +- usb_submit_urb(xpad->irq_out, GFP_KERNEL); +- mutex_unlock(&xpad->odata_mutex); ++ xpad_try_sending_next_out_packet(xpad); ++ ++ spin_unlock_irqrestore(&xpad->odata_lock, flags); + } + + /* +@@ -959,7 +1137,7 @@ static void xpad_send_led_command(struct usb_xpad *xpad, int command) + */ + static void xpad_identify_controller(struct usb_xpad *xpad) + { +- xpad_send_led_command(xpad, (xpad->pad_nr % 4) + 2); ++ led_set_brightness(&xpad->led->led_cdev, (xpad->pad_nr % 4) + 2); + } + + static void xpad_led_set(struct led_classdev *led_cdev, +@@ -1001,14 +1179,7 @@ static int xpad_led_probe(struct usb_xpad *xpad) + if (error) + goto err_free_id; + +- if (xpad->xtype == XTYPE_XBOX360) { +- /* +- * Light up the segment corresponding to controller +- * number on wired devices. On wireless we'll do that +- * when they respond to "presence" packet. +- */ +- xpad_identify_controller(xpad); +- } ++ xpad_identify_controller(xpad); + + return 0; + +@@ -1036,37 +1207,73 @@ static void xpad_led_disconnect(struct usb_xpad *xpad) { } + static void xpad_identify_controller(struct usb_xpad *xpad) { } + #endif + +-static int xpad_open(struct input_dev *dev) ++static int xpad_start_input(struct usb_xpad *xpad) + { +- struct usb_xpad *xpad = input_get_drvdata(dev); +- +- /* URB was submitted in probe */ +- if (xpad->xtype == XTYPE_XBOX360W) +- return 0; ++ int error; + +- xpad->irq_in->dev = xpad->udev; + 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); ++ error = xpad_start_xbox_one(xpad); ++ if (error) { ++ usb_kill_urb(xpad->irq_in); ++ return error; ++ } + } + + return 0; + } + +-static void xpad_close(struct input_dev *dev) ++static void xpad_stop_input(struct usb_xpad *xpad) + { +- struct usb_xpad *xpad = input_get_drvdata(dev); ++ usb_kill_urb(xpad->irq_in); ++} ++ ++static int xpad360w_start_input(struct usb_xpad *xpad) ++{ ++ int error; ++ ++ error = usb_submit_urb(xpad->irq_in, GFP_KERNEL); ++ if (error) ++ return -EIO; + +- if (xpad->xtype != XTYPE_XBOX360W) ++ /* ++ * Send presence packet. ++ * This will force the controller to resend connection packets. ++ * This is useful in the case we activate the module after the ++ * adapter has been plugged in, as it won't automatically ++ * send us info about the controllers. ++ */ ++ error = xpad_inquiry_pad_presence(xpad); ++ if (error) { + usb_kill_urb(xpad->irq_in); ++ return error; ++ } + +- xpad_stop_output(xpad); ++ return 0; ++} ++ ++static void xpad360w_stop_input(struct usb_xpad *xpad) ++{ ++ usb_kill_urb(xpad->irq_in); ++ ++ /* Make sure we are done with presence work if it was scheduled */ ++ flush_work(&xpad->work); ++} ++ ++static int xpad_open(struct input_dev *dev) ++{ ++ struct usb_xpad *xpad = input_get_drvdata(dev); ++ ++ return xpad_start_input(xpad); ++} ++ ++static void xpad_close(struct input_dev *dev) ++{ ++ struct usb_xpad *xpad = input_get_drvdata(dev); ++ ++ xpad_stop_input(xpad); + } + + static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs) +@@ -1097,8 +1304,11 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs) + + static void xpad_deinit_input(struct usb_xpad *xpad) + { +- xpad_led_disconnect(xpad); +- input_unregister_device(xpad->dev); ++ if (xpad->input_created) { ++ xpad->input_created = false; ++ xpad_led_disconnect(xpad); ++ input_unregister_device(xpad->dev); ++ } + } + + static int xpad_init_input(struct usb_xpad *xpad) +@@ -1118,8 +1328,10 @@ static int xpad_init_input(struct usb_xpad *xpad) + + input_set_drvdata(input_dev, xpad); + +- input_dev->open = xpad_open; +- input_dev->close = xpad_close; ++ if (xpad->xtype != XTYPE_XBOX360W) { ++ input_dev->open = xpad_open; ++ input_dev->close = xpad_close; ++ } + + __set_bit(EV_KEY, input_dev->evbit); + +@@ -1181,6 +1393,7 @@ static int xpad_init_input(struct usb_xpad *xpad) + if (error) + goto err_disconnect_led; + ++ xpad->input_created = true; + return 0; + + err_disconnect_led: +@@ -1241,6 +1454,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id + xpad->mapping = xpad_device[i].mapping; + xpad->xtype = xpad_device[i].xtype; + xpad->name = xpad_device[i].name; ++ INIT_WORK(&xpad->work, xpad_presence_work); + + if (xpad->xtype == XTYPE_UNKNOWN) { + if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC) { +@@ -1277,10 +1491,6 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id + + usb_set_intfdata(intf, xpad); + +- error = xpad_init_input(xpad); +- if (error) +- goto err_deinit_output; +- + if (xpad->xtype == XTYPE_XBOX360W) { + /* + * Submit the int URB immediately rather than waiting for open +@@ -1289,28 +1499,24 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id + * exactly the message that a controller has arrived that + * we're waiting for. + */ +- xpad->irq_in->dev = xpad->udev; +- error = usb_submit_urb(xpad->irq_in, GFP_KERNEL); ++ error = xpad360w_start_input(xpad); + if (error) +- goto err_deinit_input; +- ++ goto err_deinit_output; + /* +- * Send presence packet. +- * This will force the controller to resend connection packets. +- * This is useful in the case we activate the module after the +- * adapter has been plugged in, as it won't automatically +- * send us info about the controllers. ++ * Wireless controllers require RESET_RESUME to work properly ++ * after suspend. Ideally this quirk should be in usb core ++ * quirk list, but we have too many vendors producing these ++ * controllers and we'd need to maintain 2 identical lists ++ * here in this driver and in usb core. + */ +- error = xpad_inquiry_pad_presence(xpad); ++ udev->quirks |= USB_QUIRK_RESET_RESUME; ++ } else { ++ error = xpad_init_input(xpad); + if (error) +- goto err_kill_in_urb; ++ goto err_deinit_output; + } + return 0; + +-err_kill_in_urb: +- usb_kill_urb(xpad->irq_in); +-err_deinit_input: +- xpad_deinit_input(xpad); + err_deinit_output: + xpad_deinit_output(xpad); + err_free_in_urb: +@@ -1320,19 +1526,24 @@ err_free_idata: + err_free_mem: + kfree(xpad); + return error; +- + } + + static void xpad_disconnect(struct usb_interface *intf) + { +- struct usb_xpad *xpad = usb_get_intfdata (intf); ++ struct usb_xpad *xpad = usb_get_intfdata(intf); ++ ++ if (xpad->xtype == XTYPE_XBOX360W) ++ xpad360w_stop_input(xpad); + + xpad_deinit_input(xpad); +- xpad_deinit_output(xpad); + +- if (xpad->xtype == XTYPE_XBOX360W) { +- usb_kill_urb(xpad->irq_in); +- } ++ /* ++ * Now that both input device and LED device are gone we can ++ * stop output URB. ++ */ ++ xpad_stop_output(xpad); ++ ++ xpad_deinit_output(xpad); + + usb_free_urb(xpad->irq_in); + usb_free_coherent(xpad->udev, XPAD_PKT_LEN, +@@ -1343,10 +1554,55 @@ static void xpad_disconnect(struct usb_interface *intf) + usb_set_intfdata(intf, NULL); + } + ++static int xpad_suspend(struct usb_interface *intf, pm_message_t message) ++{ ++ struct usb_xpad *xpad = usb_get_intfdata(intf); ++ struct input_dev *input = xpad->dev; ++ ++ if (xpad->xtype == XTYPE_XBOX360W) { ++ /* ++ * Wireless controllers always listen to input so ++ * they are notified when controller shows up ++ * or goes away. ++ */ ++ xpad360w_stop_input(xpad); ++ } else { ++ mutex_lock(&input->mutex); ++ if (input->users) ++ xpad_stop_input(xpad); ++ mutex_unlock(&input->mutex); ++ } ++ ++ xpad_stop_output(xpad); ++ ++ return 0; ++} ++ ++static int xpad_resume(struct usb_interface *intf) ++{ ++ struct usb_xpad *xpad = usb_get_intfdata(intf); ++ struct input_dev *input = xpad->dev; ++ int retval = 0; ++ ++ if (xpad->xtype == XTYPE_XBOX360W) { ++ retval = xpad360w_start_input(xpad); ++ } else { ++ mutex_lock(&input->mutex); ++ if (input->users) ++ retval = xpad_start_input(xpad); ++ mutex_unlock(&input->mutex); ++ } ++ ++ return retval; ++} ++ + static struct usb_driver xpad_driver = { + .name = "xpad", + .probe = xpad_probe, + .disconnect = xpad_disconnect, ++ .suspend = xpad_suspend, ++ .resume = xpad_resume, ++ .reset_resume = xpad_resume, + .id_table = xpad_table, + }; + +@@ -1354,4 +1610,4 @@ module_usb_driver(xpad_driver); + + MODULE_AUTHOR(DRIVER_AUTHOR); + MODULE_DESCRIPTION(DRIVER_DESC); +-MODULE_LICENSE("GPL"); ++MODULE_LICENSE("GPL"); +\ No newline at end of file +-- +2.5.0 + diff --git a/projects/imx6/patches/linux/4.4-xbian/linux-203-stb0899_enable_low_symbol_rate.patch b/projects/imx6/patches/linux/4.4-xbian/linux-203-stb0899_enable_low_symbol_rate.patch new file mode 100644 index 0000000000..f302b6ce1b --- /dev/null +++ b/projects/imx6/patches/linux/4.4-xbian/linux-203-stb0899_enable_low_symbol_rate.patch @@ -0,0 +1,12 @@ +diff -Naur linux-3.7.2/drivers/media/dvb-frontends/stb0899_drv.c linux-3.7.2.patch/drivers/media/dvb-frontends/stb0899_drv.c +--- linux-3.7.2/drivers/media/dvb-frontends/stb0899_drv.c 2013-01-11 18:19:28.000000000 +0100 ++++ linux-3.7.2.patch/drivers/media/dvb-frontends/stb0899_drv.c 2013-01-16 10:25:43.479645317 +0100 +@@ -1581,7 +1581,7 @@ + .frequency_max = 2150000, + .frequency_stepsize = 0, + .frequency_tolerance = 0, +- .symbol_rate_min = 5000000, ++ .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + + .caps = FE_CAN_INVERSION_AUTO | diff --git a/projects/imx6/patches/linux/4.4-xbian/linux-212-mantis_stb0899_faster_lock.patch b/projects/imx6/patches/linux/4.4-xbian/linux-212-mantis_stb0899_faster_lock.patch new file mode 100644 index 0000000000..eef4e1effc --- /dev/null +++ b/projects/imx6/patches/linux/4.4-xbian/linux-212-mantis_stb0899_faster_lock.patch @@ -0,0 +1,138 @@ +diff -Naur linux-3.7.2/drivers/media/dvb-frontends/stb0899_algo.c linux-3.7.2.patch/drivers/media/dvb-frontends/stb0899_algo.c +--- linux-3.7.2/drivers/media/dvb-frontends/stb0899_algo.c 2013-01-11 18:19:28.000000000 +0100 ++++ linux-3.7.2.patch/drivers/media/dvb-frontends/stb0899_algo.c 2013-01-16 10:28:33.633409961 +0100 +@@ -206,7 +206,6 @@ + static enum stb0899_status stb0899_search_tmg(struct stb0899_state *state) + { + struct stb0899_internal *internal = &state->internal; +- struct stb0899_params *params = &state->params; + + short int derot_step, derot_freq = 0, derot_limit, next_loop = 3; + int index = 0; +@@ -216,10 +215,9 @@ + + /* timing loop computation & symbol rate optimisation */ + derot_limit = (internal->sub_range / 2L) / internal->mclk; +- derot_step = (params->srate / 2L) / internal->mclk; ++ derot_step = internal->derot_step * 4; /* dertot_step = decreasing delta */ + + while ((stb0899_check_tmg(state) != TIMINGOK) && next_loop) { +- index++; + derot_freq += index * internal->direction * derot_step; /* next derot zig zag position */ + + if (abs(derot_freq) > derot_limit) +@@ -230,6 +228,7 @@ + STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq)); + stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency */ + } ++ index++; + internal->direction = -internal->direction; /* Change zigzag direction */ + } + +@@ -278,14 +277,18 @@ + { + struct stb0899_internal *internal = &state->internal; + +- short int derot_freq = 0, last_derot_freq = 0, derot_limit, next_loop = 3; ++ short int derot_freq = 0, last_derot_freq = 0, derot_limit, derot_step, next_loop = 3; + int index = 0; ++ int base_freq; + u8 cfr[2]; + u8 reg; + + internal->status = NOCARRIER; + derot_limit = (internal->sub_range / 2L) / internal->mclk; + derot_freq = internal->derot_freq; ++ derot_step = internal->derot_step * 2; ++ last_derot_freq = internal->derot_freq; ++ base_freq = internal->derot_freq; + + reg = stb0899_read_reg(state, STB0899_CFD); + STB0899_SETFIELD_VAL(CFD_ON, reg, 1); +@@ -294,11 +297,10 @@ + do { + dprintk(state->verbose, FE_DEBUG, 1, "Derot Freq=%d, mclk=%d", derot_freq, internal->mclk); + if (stb0899_check_carrier(state) == NOCARRIER) { +- index++; + last_derot_freq = derot_freq; +- derot_freq += index * internal->direction * internal->derot_step; /* next zig zag derotator position */ ++ derot_freq += index * internal->direction * derot_step; /* next zig zag derotator position */ + +- if(abs(derot_freq) > derot_limit) ++ if (derot_freq > base_freq + derot_limit || derot_freq < base_freq - derot_limit) + next_loop--; + + if (next_loop) { +@@ -310,9 +312,10 @@ + STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq)); + stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency */ + } ++ index++; ++ internal->direction = -internal->direction; /* Change zigzag direction */ + } + +- internal->direction = -internal->direction; /* Change zigzag direction */ + } while ((internal->status != CARRIEROK) && next_loop); + + if (internal->status == CARRIEROK) { +@@ -338,6 +341,7 @@ + int lock = 0, index = 0, dataTime = 500, loop; + u8 reg; + ++ msleep(1); + internal->status = NODATA; + + /* RESET FEC */ +@@ -348,6 +352,7 @@ + reg = stb0899_read_reg(state, STB0899_TSTRES); + STB0899_SETFIELD_VAL(FRESACS, reg, 0); + stb0899_write_reg(state, STB0899_TSTRES, reg); ++ msleep(1); + + if (params->srate <= 2000000) + dataTime = 2000; +@@ -363,6 +368,7 @@ + + stb0899_write_reg(state, STB0899_DSTATUS2, 0x00); /* force search loop */ + while (1) { ++ msleep(1); // Alex: added 1 mSec + /* WARNING! VIT LOCKED has to be tested before VIT_END_LOOOP */ + reg = stb0899_read_reg(state, STB0899_VSTATUS); + lock = STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg); +@@ -390,20 +396,21 @@ + short int derot_freq, derot_step, derot_limit, next_loop = 3; + u8 cfr[2]; + u8 reg; +- int index = 1; ++ int index = 0; ++ int base_freq; + + struct stb0899_internal *internal = &state->internal; +- struct stb0899_params *params = &state->params; + +- derot_step = (params->srate / 4L) / internal->mclk; ++ derot_step = internal->derot_step; + derot_limit = (internal->sub_range / 2L) / internal->mclk; + derot_freq = internal->derot_freq; ++ base_freq = internal->derot_freq; + + do { + if ((internal->status != CARRIEROK) || (stb0899_check_data(state) != DATAOK)) { + + derot_freq += index * internal->direction * derot_step; /* next zig zag derotator position */ +- if (abs(derot_freq) > derot_limit) ++ if (derot_freq > base_freq + derot_limit || derot_freq < base_freq - derot_limit) + next_loop--; + + if (next_loop) { +@@ -417,9 +424,9 @@ + stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency */ + + stb0899_check_carrier(state); +- index++; + } + } ++ index++; + internal->direction = -internal->direction; /* change zig zag direction */ + } while ((internal->status != DATAOK) && next_loop); + diff --git a/projects/imx6/patches/linux/4.4-xbian/linux-222-stb0899_signal_quality.patch b/projects/imx6/patches/linux/4.4-xbian/linux-222-stb0899_signal_quality.patch new file mode 100644 index 0000000000..fd6539d2bf --- /dev/null +++ b/projects/imx6/patches/linux/4.4-xbian/linux-222-stb0899_signal_quality.patch @@ -0,0 +1,62 @@ +diff -Naur linux-3.7.2/drivers/media/dvb-frontends/stb0899_drv.c linux-3.7.2.patch/drivers/media/dvb-frontends/stb0899_drv.c +--- linux-3.7.2/drivers/media/dvb-frontends/stb0899_drv.c 2013-01-11 18:19:28.000000000 +0100 ++++ linux-3.7.2.patch/drivers/media/dvb-frontends/stb0899_drv.c 2013-01-16 10:33:10.323380937 +0100 +@@ -971,6 +971,16 @@ + + *strength = stb0899_table_lookup(stb0899_dvbsrf_tab, ARRAY_SIZE(stb0899_dvbsrf_tab) - 1, val); + *strength += 750; ++ ++ const int MIN_STRENGTH_DVBS = 0; ++ const int MAX_STRENGTH_DVBS = 680; ++ if (*strength < MIN_STRENGTH_DVBS) ++ *strength = 0; ++ else if(*strength > MAX_STRENGTH_DVBS) ++ *strength = 0xFFFF; ++ else ++ *strength = (*strength - MIN_STRENGTH_DVBS) * 0xFFFF / (MAX_STRENGTH_DVBS - MIN_STRENGTH_DVBS); ++ + dprintk(state->verbose, FE_DEBUG, 1, "AGCIQVALUE = 0x%02x, C = %d * 0.1 dBm", + val & 0xff, *strength); + } +@@ -983,6 +993,7 @@ + + *strength = stb0899_table_lookup(stb0899_dvbs2rf_tab, ARRAY_SIZE(stb0899_dvbs2rf_tab) - 1, val); + *strength += 950; ++ *strength = *strength << 4; + dprintk(state->verbose, FE_DEBUG, 1, "IF_AGC_GAIN = 0x%04x, C = %d * 0.1 dBm", + val & 0x3fff, *strength); + } +@@ -1016,6 +1027,16 @@ + val = MAKEWORD16(buf[0], buf[1]); + + *snr = stb0899_table_lookup(stb0899_cn_tab, ARRAY_SIZE(stb0899_cn_tab) - 1, val); ++ ++ const int MIN_SNR_DVBS = 0; ++ const int MAX_SNR_DVBS = 200; ++ if (*snr < MIN_SNR_DVBS) ++ *snr = 0; ++ else if(*snr > MAX_SNR_DVBS) ++ *snr = 0xFFFF; ++ else ++ *snr = (*snr - MIN_SNR_DVBS) * 0xFFFF / (MAX_SNR_DVBS - MIN_SNR_DVBS); ++ + dprintk(state->verbose, FE_DEBUG, 1, "NIR = 0x%02x%02x = %u, C/N = %d * 0.1 dBm\n", + buf[0], buf[1], val, *snr); + } +@@ -1040,6 +1061,16 @@ + val = (quantn - estn) / 10; + } + *snr = val; ++ ++ const int MIN_SNR_DVBS2 = 10; ++ const int MAX_SNR_DVBS2 = 70; ++ if (*snr < MIN_SNR_DVBS2) ++ *snr = 0; ++ else if(*snr > MAX_SNR_DVBS2) ++ *snr = 0xFFFF; ++ else ++ *snr = (*snr - MIN_SNR_DVBS2) * 0xFFFF / (MAX_SNR_DVBS2 - MIN_SNR_DVBS2); ++ + dprintk(state->verbose, FE_DEBUG, 1, "Es/N0 quant = %d (%d) estimate = %u (%d), C/N = %d * 0.1 dBm", + quant, quantn, est, estn, val); + } diff --git a/projects/imx6/patches/linux/4.4-xbian/linux-223-Fix-video-artifacts-with-tt-3600-s2-usb.patch b/projects/imx6/patches/linux/4.4-xbian/linux-223-Fix-video-artifacts-with-tt-3600-s2-usb.patch new file mode 100644 index 0000000000..7aaabc48c0 --- /dev/null +++ b/projects/imx6/patches/linux/4.4-xbian/linux-223-Fix-video-artifacts-with-tt-3600-s2-usb.patch @@ -0,0 +1,17 @@ +diff -Naur linux-3.7.9/drivers/media/usb/dvb-usb/pctv452e.c linux-3.7.9.patch/drivers/media/usb/dvb-usb/pctv452e.c +--- linux-3.7.9/drivers/media/usb/dvb-usb/pctv452e.c 2013-01-11 18:19:28.000000000 +0100 ++++ linux-3.7.9.patch/drivers/media/usb/dvb-usb/pctv452e.c 2013-01-16 10:35:01.131342123 +0100 +@@ -995,11 +995,11 @@ + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_ISOC, +- .count = 7, ++ .count = 4, + .endpoint = 0x02, + .u = { + .isoc = { +- .framesperurb = 4, ++ .framesperurb = 64, + .framesize = 940, + .interval = 1 + } diff --git a/projects/imx6/patches/linux/4.4-xbian/linux-224_Hauppauge_WinTV-soloHD.patch b/projects/imx6/patches/linux/4.4-xbian/linux-224_Hauppauge_WinTV-soloHD.patch new file mode 100644 index 0000000000..e629f83b69 --- /dev/null +++ b/projects/imx6/patches/linux/4.4-xbian/linux-224_Hauppauge_WinTV-soloHD.patch @@ -0,0 +1,41 @@ +From 1efc21701d94ed0c5b91467b042bed8b8becd5cc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Arno=20Bauern=C3=B6ppel?= +Date: Sun, 15 Nov 2015 19:24:10 -0200 +Subject: [media] Add support for dvb usb stick Hauppauge WinTV-soloHD + +This patch adds support for the DVB-T/C/T2 usb stick WinTV-soloHD from +Hauppauge. It adds the usb ID 2040:0264 Hauppauge to the cards of the +driver em28xx. + +I successfully tested DVB-T/C and the IR remote control with the +firmware dvb-demod-si2168-b40-01.fw. + +Signed-off-by: Arno Bauernoeppel +Signed-off-by: Mauro Carvalho Chehab + +diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h +index 0a46580..1c1c298 100644 +--- a/drivers/media/dvb-core/dvb-usb-ids.h ++++ b/drivers/media/dvb-core/dvb-usb-ids.h +@@ -389,4 +389,5 @@ + #define USB_PID_PCTV_2002E_SE 0x025d + #define USB_PID_SVEON_STV27 0xd3af + #define USB_PID_TURBOX_DTT_2000 0xd3a4 ++#define USB_PID_WINTV_SOLOHD 0x0264 + #endif +diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c +index 5373dce..a1b6ef5 100644 +--- a/drivers/media/usb/em28xx/em28xx-cards.c ++++ b/drivers/media/usb/em28xx/em28xx-cards.c +@@ -2475,6 +2475,8 @@ struct usb_device_id em28xx_id_table[] = { + .driver_info = EM28178_BOARD_PCTV_461E }, + { USB_DEVICE(0x2013, 0x025f), + .driver_info = EM28178_BOARD_PCTV_292E }, ++ { USB_DEVICE(0x2040, 0x0264), /* Hauppauge WinTV-soloHD */ ++ .driver_info = EM28178_BOARD_PCTV_292E }, + { USB_DEVICE(0x0413, 0x6f07), + .driver_info = EM2861_BOARD_LEADTEK_VC100 }, + { USB_DEVICE(0xeb1a, 0x8179), +-- +cgit v0.10.2 + diff --git a/projects/imx6/patches/linux/4.4-xbian/linux-227-ds3000-invalid-symbol-rate.patch b/projects/imx6/patches/linux/4.4-xbian/linux-227-ds3000-invalid-symbol-rate.patch new file mode 100644 index 0000000000..79e04f2f82 --- /dev/null +++ b/projects/imx6/patches/linux/4.4-xbian/linux-227-ds3000-invalid-symbol-rate.patch @@ -0,0 +1,18 @@ +diff -rupN a/drivers/media/dvb-frontends/ds3000.c b/drivers/media/dvb-frontends/ds3000.c +--- a/drivers/media/dvb-frontends/ds3000.c 2015-01-28 23:24:59.000000000 +0100 ++++ b/drivers/media/dvb-frontends/ds3000.c 2015-01-29 21:57:56.000000000 +0100 +@@ -958,6 +958,14 @@ static int ds3000_set_frontend(struct dv + /* enable ac coupling */ + ds3000_writereg(state, 0x25, 0x8a); + ++ dprintk("%s() frequency:%u symbol_rate:%u\n", __func__, c->frequency, c->symbol_rate); ++ ++ if (c->symbol_rate < ds3000_ops.info.symbol_rate_min || c->symbol_rate > ds3000_ops.info.symbol_rate_max ) { ++ dprintk("%s() symbol_rate %u out of range (%u ... %u)\n", __func__, c->symbol_rate, ++ ds3000_ops.info.symbol_rate_min, ds3000_ops.info.symbol_rate_max); ++ return 1; ++ } ++ + /* enhance symbol rate performance */ + if ((c->symbol_rate / 1000) <= 5000) { + value = 29777 / (c->symbol_rate / 1000) + 1; \ No newline at end of file diff --git a/projects/imx6/patches/linux/4.4-xbian/linux-228-support-tt-ct2-4650-v2.patch b/projects/imx6/patches/linux/4.4-xbian/linux-228-support-tt-ct2-4650-v2.patch new file mode 100644 index 0000000000..bfc9e6bfca --- /dev/null +++ b/projects/imx6/patches/linux/4.4-xbian/linux-228-support-tt-ct2-4650-v2.patch @@ -0,0 +1,25 @@ +diff -urN a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h +--- a/drivers/media/dvb-core/dvb-usb-ids.h 2016-01-11 01:01:32.000000000 +0200 ++++ b/drivers/media/dvb-core/dvb-usb-ids.h 2016-01-13 12:42:17.648388583 +0200 +@@ -247,6 +247,7 @@ + #define USB_PID_TECHNOTREND_CONNECT_CT3650 0x300d + #define USB_PID_TECHNOTREND_CONNECT_S2_4600 0x3011 + #define USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI 0x3012 ++#define USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI_2 0x3015 + #define USB_PID_TECHNOTREND_TVSTICK_CT2_4400 0x3014 + #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a + #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2 0x0081 +diff -urN a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c +--- a/drivers/media/usb/dvb-usb-v2/dvbsky.c 2016-01-11 01:01:32.000000000 +0200 ++++ b/drivers/media/usb/dvb-usb-v2/dvbsky.c 2016-01-13 12:41:17.480386735 +0200 +@@ -847,6 +847,10 @@ + USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI, + &dvbsky_t680c_props, "TechnoTrend TT-connect CT2-4650 CI", + RC_MAP_TT_1500) }, ++ { DVB_USB_DEVICE(USB_VID_TECHNOTREND, ++ USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI_2, ++ &dvbsky_t680c_props, "TechnoTrend TT-connect CT2-4650 CI v1.1", ++ RC_MAP_TT_1500) }, + { DVB_USB_DEVICE(USB_VID_TERRATEC, + USB_PID_TERRATEC_H7_3, + &dvbsky_t680c_props, "Terratec H7 Rev.4", diff --git a/projects/imx6/patches/linux/4.4-xbian/linux-229-avermedia-volar-hd2.patch b/projects/imx6/patches/linux/4.4-xbian/linux-229-avermedia-volar-hd2.patch new file mode 100644 index 0000000000..1be01a5252 --- /dev/null +++ b/projects/imx6/patches/linux/4.4-xbian/linux-229-avermedia-volar-hd2.patch @@ -0,0 +1,25 @@ +taken from https://bugzilla.kernel.org/show_bug.cgi?id=108691 +diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c +--- a/drivers/media/usb/dvb-usb-v2/af9035.c ++++ b/drivers/media/usb/dvb-usb-v2/af9035.c +@@ -2053,6 +2053,8 @@ static const struct usb_device_id af9035_id_table[] = { + &af9035_props, "Avermedia A835B(3835)", RC_MAP_IT913X_V2) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835B_4835, + &af9035_props, "Avermedia A835B(4835)", RC_MAP_IT913X_V2) }, ++ { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TD110, ++ &af9035_props, "Avermedia AverTV Volar HD 2 (TD110)", RC_MAP_AVERMEDIA_RM_KS) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_H335, + &af9035_props, "Avermedia H335", RC_MAP_IT913X_V2) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB499_2T_T09, + +diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h +--- a/drivers/media/dvb-core/dvb-usb-ids.h ++++ b/drivers/media/dvb-core/dvb-usb-ids.h +@@ -242,6 +242,7 @@ + #define USB_PID_AVERMEDIA_1867 0x1867 + #define USB_PID_AVERMEDIA_A867 0xa867 + #define USB_PID_AVERMEDIA_H335 0x0335 ++#define USB_PID_AVERMEDIA_TD110 0xa110 + #define USB_PID_AVERMEDIA_TWINSTAR 0x0825 + #define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006 + #define USB_PID_TECHNOTREND_CONNECT_S2400_8KEEPROM 0x3009 diff --git a/projects/imx6/patches/linux/4.4-xbian/linux-230-elgato-eyetv-sat-v3.patch b/projects/imx6/patches/linux/4.4-xbian/linux-230-elgato-eyetv-sat-v3.patch new file mode 100644 index 0000000000..2056a250f5 --- /dev/null +++ b/projects/imx6/patches/linux/4.4-xbian/linux-230-elgato-eyetv-sat-v3.patch @@ -0,0 +1,50 @@ +diff --git a/drivers/media/usb/dvb-usb/az6027.c b/drivers/media/usb/dvb-usb/az6027.c +index 92e47d6..2e71136 100644 +--- a/drivers/media/usb/dvb-usb/az6027.c ++++ b/drivers/media/usb/dvb-usb/az6027.c +@@ -1090,6 +1090,7 @@ static struct usb_device_id az6027_usb_table[] = { + { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V2) }, + { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT) }, + { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT_V2) }, ++ { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT_V3) }, + { }, + }; + +@@ -1138,7 +1139,7 @@ static struct dvb_usb_device_properties az6027_properties = { + + .i2c_algo = &az6027_i2c_algo, + +- .num_device_descs = 7, ++ .num_device_descs = 8, + .devices = { + { + .name = "AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)", +@@ -1168,6 +1169,10 @@ static struct dvb_usb_device_properties az6027_properties = { + .name = "Elgato EyeTV Sat", + .cold_ids = { &az6027_usb_table[6], NULL }, + .warm_ids = { NULL }, ++ }, { ++ .name = "Elgato EyeTV Sat", ++ .cold_ids = { &az6027_usb_table[7], NULL }, ++ .warm_ids = { NULL }, + }, + { NULL }, + } + +warning: LF will be replaced by CRLF in az6027.c. +The file will have its original line endings in your working directory. +diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h +index c117fb3..7552f38 100644 +--- a/drivers/media/dvb-core/dvb-usb-ids.h ++++ b/drivers/media/dvb-core/dvb-usb-ids.h +@@ -365,6 +365,7 @@ + #define USB_PID_ELGATO_EYETV_DTT_Dlx 0x0020 + #define USB_PID_ELGATO_EYETV_SAT 0x002a + #define USB_PID_ELGATO_EYETV_SAT_V2 0x0025 ++#define USB_PID_ELGATO_EYETV_SAT_V3 0x0036 + #define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD 0x5000 + #define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM 0x5001 + #define USB_PID_FRIIO_WHITE 0x0001 + +warning: LF will be replaced by CRLF in dvb-usb-ids.h. +The file will have its original line endings in your working directory. diff --git a/projects/imx6/patches/linux/4.4-xbian/linux-231-fix-cx23885-ci-devices.patch b/projects/imx6/patches/linux/4.4-xbian/linux-231-fix-cx23885-ci-devices.patch new file mode 100644 index 0000000000..dd0d6fe700 --- /dev/null +++ b/projects/imx6/patches/linux/4.4-xbian/linux-231-fix-cx23885-ci-devices.patch @@ -0,0 +1,22 @@ +diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c +index 31765aa..f041b69 100644 +--- a/drivers/media/pci/cx23885/cx23885-dvb.c ++++ b/drivers/media/pci/cx23885/cx23885-dvb.c +@@ -1139,7 +1139,7 @@ static int dvb_register_ci_mac(struct cx23885_tsport *port) + u8 eeprom[256]; /* 24C02 i2c eeprom */ + struct sp2_config sp2_config; + struct i2c_board_info info; +- struct cx23885_i2c *i2c_bus2 = &dev->i2c_bus[1]; ++ struct cx23885_i2c *i2c_bus = &dev->i2c_bus[0]; + + /* attach CI */ + memset(&sp2_config, 0, sizeof(sp2_config)); +@@ -1151,7 +1151,7 @@ static int dvb_register_ci_mac(struct cx23885_tsport *port) + info.addr = 0x40; + info.platform_data = &sp2_config; + request_module(info.type); +- client_ci = i2c_new_device(&i2c_bus2->i2c_adap, &info); ++ client_ci = i2c_new_device(&i2c_bus->i2c_adap, &info); + if (client_ci == NULL || client_ci->dev.driver == NULL) + return -ENODEV; + if (!try_module_get(client_ci->dev.driver->owner)) { diff --git a/projects/imx6/patches/linux/4.4-xbian/linux-232-Terratec-Cinergy-S2-Rev.3.patch.patch b/projects/imx6/patches/linux/4.4-xbian/linux-232-Terratec-Cinergy-S2-Rev.3.patch.patch new file mode 100644 index 0000000000..788832adf1 --- /dev/null +++ b/projects/imx6/patches/linux/4.4-xbian/linux-232-Terratec-Cinergy-S2-Rev.3.patch.patch @@ -0,0 +1,48 @@ +From: cvh +Date: Sun, 29 May 2016 23:00:40 +0200 +Subject: [PATCH] [media] Add support for Terratec Cinergy S2 Rev.3 + +--- + drivers/media/usb/dvb-usb/dw2102.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c +index 49b55d7..961f64e 100644 +--- a/drivers/media/usb/dvb-usb/dw2102.c ++++ b/drivers/media/usb/dvb-usb/dw2102.c +@@ -1683,6 +1683,7 @@ enum dw2102_table_entry { + TEVII_S421, + TEVII_S632, + TERRATEC_CINERGY_S2_R2, ++ TERRATEC_CINERGY_S2_R3, + GOTVIEW_SAT_HD, + GENIATECH_T220, + TECHNOTREND_S2_4600, +@@ -1709,6 +1710,7 @@ static struct usb_device_id dw2102_table[] = { + [TEVII_S421] = {USB_DEVICE(0x9022, USB_PID_TEVII_S421)}, + [TEVII_S632] = {USB_DEVICE(0x9022, USB_PID_TEVII_S632)}, + [TERRATEC_CINERGY_S2_R2] = {USB_DEVICE(USB_VID_TERRATEC, 0x00b0)}, ++ [TERRATEC_CINERGY_S2_R3] = {USB_DEVICE(USB_VID_TERRATEC, 0x0102)}, + [GOTVIEW_SAT_HD] = {USB_DEVICE(0x1FE1, USB_PID_GOTVIEW_SAT_HD)}, + [GENIATECH_T220] = {USB_DEVICE(0x1f4d, 0xD220)}, + [TECHNOTREND_S2_4600] = {USB_DEVICE(USB_VID_TECHNOTREND, +@@ -2118,7 +2120,7 @@ static struct dvb_usb_device_properties su3000_properties = { + }}, + } + }, +- .num_device_descs = 5, ++ .num_device_descs = 6, + .devices = { + { "SU3000HD DVB-S USB2.0", + { &dw2102_table[GENIATECH_SU3000], NULL }, +@@ -2136,6 +2138,10 @@ static struct dvb_usb_device_properties su3000_properties = { + { &dw2102_table[TERRATEC_CINERGY_S2_R2], NULL }, + { NULL }, + }, ++ { "Terratec Cinergy S2 USB HD Rev.3", ++ { &dw2102_table[TERRATEC_CINERGY_S2_R3], NULL }, ++ { NULL }, ++ }, + { "GOTVIEW Satellite HD", + { &dw2102_table[GOTVIEW_SAT_HD], NULL }, + { NULL }, diff --git a/projects/imx6/patches/linux/4.4-xbian/linux-999.05-eMMC-Don-t-initialize-partitions-on-RPMB-flagged-are.patch b/projects/imx6/patches/linux/4.4-xbian/linux-999.05-eMMC-Don-t-initialize-partitions-on-RPMB-flagged-are.patch new file mode 100644 index 0000000000..b3eb8b34b0 --- /dev/null +++ b/projects/imx6/patches/linux/4.4-xbian/linux-999.05-eMMC-Don-t-initialize-partitions-on-RPMB-flagged-are.patch @@ -0,0 +1,26 @@ +From 57f0b99ca9a2db948fa70988c447553683368be1 Mon Sep 17 00:00:00 2001 +From: Nell Hardcastle +Date: Thu, 29 May 2014 22:06:50 -0700 +Subject: [PATCH] eMMC: Don't initialize partitions on RPMB flagged areas. + +Prevents a lot of pointless hanging at boot on some devices. +--- + drivers/mmc/card/block.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c +index 4409d79..56df902 100644 +--- a/drivers/mmc/card/block.c ++++ b/drivers/mmc/card/block.c +@@ -2254,7 +2254,7 @@ static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md) + return 0; + + for (idx = 0; idx < card->nr_parts; idx++) { +- if (card->part[idx].size) { ++ if (card->part[idx].size && !(card->part[idx].area_type & MMC_BLK_DATA_AREA_RPMB)) { + ret = mmc_blk_alloc_part(card, md, + card->part[idx].part_cfg, + card->part[idx].size >> 9, +-- +1.7.10.4 +