diff --git a/[refs] b/[refs] index 4499ceb68c43..cc59a23f7aed 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: e00ddc9b8f978ffbc6c212f780a2bb83aafe2fbd +refs/heads/master: 658d4aed59b36f877edc668cc27b188a33e643e5 diff --git a/trunk/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff b/trunk/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff deleted file mode 100644 index 9aec8ef228b0..000000000000 --- a/trunk/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff +++ /dev/null @@ -1,7 +0,0 @@ -What: /sys/module/hid_logitech/drivers/hid:logitech//range. -Date: July 2011 -KernelVersion: 3.2 -Contact: Michal Malư -Description: Display minimum, maximum and current range of the steering - wheel. Writing a value within min and max boundaries sets the - range of the wheel. diff --git a/trunk/drivers/hid/Kconfig b/trunk/drivers/hid/Kconfig index d2c97343fc0d..306b15f39c9c 100644 --- a/trunk/drivers/hid/Kconfig +++ b/trunk/drivers/hid/Kconfig @@ -245,15 +245,6 @@ config HID_LOGITECH ---help--- Support for Logitech devices that are not fully compliant with HID standard. -config HID_LOGITECH_DJ - tristate "Logitech Unifying receivers full support" - depends on HID_LOGITECH - default m - ---help--- - Say Y if you want support for Logitech Unifying receivers and devices. - Unifying receivers are capable of pairing up to 6 Logitech compliant - devices to the same receiver. - config LOGITECH_FF bool "Logitech force feedback support" depends on HID_LOGITECH @@ -287,21 +278,13 @@ config LOGIG940_FF Say Y here if you want to enable force feedback support for Logitech Flight System G940 devices. -config LOGIWHEELS_FF - bool "Logitech wheels configuration and force feedback support" +config LOGIWII_FF + bool "Logitech Speed Force Wireless force feedback support" depends on HID_LOGITECH select INPUT_FF_MEMLESS - default LOGITECH_FF help - Say Y here if you want to enable force feedback and range setting - support for following Logitech wheels: - - Logitech Driving Force - - Logitech Driving Force Pro - - Logitech Driving Force GT - - Logitech G25 - - Logitech G27 - - Logitech MOMO/MOMO 2 - - Logitech Formula Force EX + Say Y here if you want to enable force feedback support for Logitech + Speed Force Wireless (Wii) devices. config HID_MAGICMOUSE tristate "Apple MagicMouse multi-touch support" diff --git a/trunk/drivers/hid/Makefile b/trunk/drivers/hid/Makefile index b7ddabb0b34c..0a0a38e9fd28 100644 --- a/trunk/drivers/hid/Makefile +++ b/trunk/drivers/hid/Makefile @@ -21,7 +21,7 @@ endif ifdef CONFIG_LOGIG940_FF hid-logitech-y += hid-lg3ff.o endif -ifdef CONFIG_LOGIWHEELS_FF +ifdef CONFIG_LOGIWII_FF hid-logitech-y += hid-lg4ff.o endif @@ -43,7 +43,6 @@ obj-$(CONFIG_HID_KEYTOUCH) += hid-keytouch.o obj-$(CONFIG_HID_KYE) += hid-kye.o obj-$(CONFIG_HID_LCPOWER) += hid-lcpower.o obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o -obj-$(CONFIG_HID_LOGITECH_DJ) += hid-logitech-dj.o obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o diff --git a/trunk/drivers/hid/hid-core.c b/trunk/drivers/hid/hid-core.c index 73e67872ff1d..1a5cf0c9cfca 100644 --- a/trunk/drivers/hid/hid-core.c +++ b/trunk/drivers/hid/hid-core.c @@ -1417,11 +1417,8 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER) }, diff --git a/trunk/drivers/hid/hid-ids.h b/trunk/drivers/hid/hid-ids.h index 3d065d096a07..db63ccf21cc8 100644 --- a/trunk/drivers/hid/hid-ids.h +++ b/trunk/drivers/hid/hid-ids.h @@ -436,7 +436,6 @@ #define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295 #define USB_DEVICE_ID_LOGITECH_DFP_WHEEL 0xc298 #define USB_DEVICE_ID_LOGITECH_G25_WHEEL 0xc299 -#define USB_DEVICE_ID_LOGITECH_DFGT_WHEEL 0xc29a #define USB_DEVICE_ID_LOGITECH_G27_WHEEL 0xc29b #define USB_DEVICE_ID_LOGITECH_WII_WHEEL 0xc29c #define USB_DEVICE_ID_LOGITECH_ELITE_KBD 0xc30a @@ -444,8 +443,6 @@ #define USB_DEVICE_ID_S510_RECEIVER_2 0xc517 #define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500 0xc512 #define USB_DEVICE_ID_MX3000_RECEIVER 0xc513 -#define USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER 0xc52b -#define USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2 0xc532 #define USB_DEVICE_ID_SPACETRAVELLER 0xc623 #define USB_DEVICE_ID_SPACENAVIGATOR 0xc626 #define USB_DEVICE_ID_DINOVO_DESKTOP 0xc704 diff --git a/trunk/drivers/hid/hid-lg.c b/trunk/drivers/hid/hid-lg.c index e7a7bd1eb34a..a7f916e8fc32 100644 --- a/trunk/drivers/hid/hid-lg.c +++ b/trunk/drivers/hid/hid-lg.c @@ -363,7 +363,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) goto err_free; } - if (quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4)) + if (quirks & (LG_FF | LG_FF2 | LG_FF3)) connect_mask &= ~HID_CONNECT_FF; ret = hid_hw_start(hdev, connect_mask); @@ -372,8 +372,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) goto err_free; } - /* Setup wireless link with Logitech Wii wheel */ - if(hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) { + if (quirks & LG_FF4) { unsigned char buf[] = { 0x00, 0xAF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT); @@ -406,15 +405,6 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) return ret; } -static void lg_remove(struct hid_device *hdev) -{ - unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); - if(quirks & LG_FF4) - lg4ff_deinit(hdev); - - hid_hw_stop(hdev); -} - static const struct hid_device_id lg_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER), .driver_data = LG_RDESC | LG_WIRELESS }, @@ -441,7 +431,7 @@ static const struct hid_device_id lg_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D), .driver_data = LG_NOGET }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL), - .driver_data = LG_NOGET | LG_FF4 }, + .driver_data = LG_NOGET | LG_FF }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD), .driver_data = LG_FF2 }, @@ -454,17 +444,15 @@ static const struct hid_device_id lg_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO), .driver_data = LG_FF }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL), - .driver_data = LG_FF4 }, + .driver_data = LG_FF }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2), - .driver_data = LG_FF4 }, + .driver_data = LG_FF }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL), - .driver_data = LG_FF4 }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL), - .driver_data = LG_FF4 }, + .driver_data = LG_FF }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL), - .driver_data = LG_FF4 }, + .driver_data = LG_FF }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL), - .driver_data = LG_NOGET | LG_FF4 }, + .driver_data = LG_NOGET | LG_FF }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL), .driver_data = LG_FF4 }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ), @@ -490,7 +478,6 @@ static struct hid_driver lg_driver = { .input_mapped = lg_input_mapped, .event = lg_event, .probe = lg_probe, - .remove = lg_remove, }; static int __init lg_init(void) diff --git a/trunk/drivers/hid/hid-lg.h b/trunk/drivers/hid/hid-lg.h index 4b097286dc78..b0100ba2ae0b 100644 --- a/trunk/drivers/hid/hid-lg.h +++ b/trunk/drivers/hid/hid-lg.h @@ -19,12 +19,10 @@ int lg3ff_init(struct hid_device *hdev); static inline int lg3ff_init(struct hid_device *hdev) { return -1; } #endif -#ifdef CONFIG_LOGIWHEELS_FF +#ifdef CONFIG_LOGIWII_FF int lg4ff_init(struct hid_device *hdev); -int lg4ff_deinit(struct hid_device *hdev); #else static inline int lg4ff_init(struct hid_device *hdev) { return -1; } -static inline int lg4ff_deinit(struct hid_device *hdev) { return -1; } #endif #endif diff --git a/trunk/drivers/hid/hid-lg4ff.c b/trunk/drivers/hid/hid-lg4ff.c index 103f30d93f76..fa550c8e1d1b 100644 --- a/trunk/drivers/hid/hid-lg4ff.c +++ b/trunk/drivers/hid/hid-lg4ff.c @@ -29,108 +29,19 @@ #include "usbhid/usbhid.h" #include "hid-lg.h" -#include "hid-ids.h" -#define DFGT_REV_MAJ 0x13 -#define DFGT_REV_MIN 0x22 -#define DFP_REV_MAJ 0x11 -#define DFP_REV_MIN 0x06 -#define FFEX_REV_MAJ 0x21 -#define FFEX_REV_MIN 0x00 -#define G25_REV_MAJ 0x12 -#define G25_REV_MIN 0x22 -#define G27_REV_MAJ 0x12 -#define G27_REV_MIN 0x38 - -#define to_hid_device(pdev) container_of(pdev, struct hid_device, dev) - -static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range); -static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range); -static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *attr, char *buf); -static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); - -static DEVICE_ATTR(range, S_IRWXU | S_IRWXG | S_IRWXO, lg4ff_range_show, lg4ff_range_store); - -static bool list_inited; - -struct lg4ff_device_entry { - char *device_id; /* Use name in respective kobject structure's address as the ID */ - __u16 range; - __u16 min_range; - __u16 max_range; - __u8 leds; - struct list_head list; - void (*set_range)(struct hid_device *hid, u16 range); +struct lg4ff_device { + struct hid_report *report; }; -static struct lg4ff_device_entry device_list; - -static const signed short lg4ff_wheel_effects[] = { +static const signed short ff4_wheel_ac[] = { FF_CONSTANT, FF_AUTOCENTER, -1 }; -struct lg4ff_wheel { - const __u32 product_id; - const signed short *ff_effects; - const __u16 min_range; - const __u16 max_range; - void (*set_range)(struct hid_device *hid, u16 range); -}; - -static const struct lg4ff_wheel lg4ff_devices[] = { - {USB_DEVICE_ID_LOGITECH_WHEEL, lg4ff_wheel_effects, 40, 270, NULL}, - {USB_DEVICE_ID_LOGITECH_MOMO_WHEEL, lg4ff_wheel_effects, 40, 270, NULL}, - {USB_DEVICE_ID_LOGITECH_DFP_WHEEL, lg4ff_wheel_effects, 40, 900, hid_lg4ff_set_range_dfp}, - {USB_DEVICE_ID_LOGITECH_G25_WHEEL, lg4ff_wheel_effects, 40, 900, hid_lg4ff_set_range_g25}, - {USB_DEVICE_ID_LOGITECH_DFGT_WHEEL, lg4ff_wheel_effects, 40, 900, hid_lg4ff_set_range_g25}, - {USB_DEVICE_ID_LOGITECH_G27_WHEEL, lg4ff_wheel_effects, 40, 900, hid_lg4ff_set_range_g25}, - {USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2, lg4ff_wheel_effects, 40, 270, NULL}, - {USB_DEVICE_ID_LOGITECH_WII_WHEEL, lg4ff_wheel_effects, 40, 270, NULL} -}; - -struct lg4ff_native_cmd { - const __u8 cmd_num; /* Number of commands to send */ - const __u8 cmd[]; -}; - -struct lg4ff_usb_revision { - const __u16 rev_maj; - const __u16 rev_min; - const struct lg4ff_native_cmd *command; -}; - -static const struct lg4ff_native_cmd native_dfp = { - 1, - {0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00} -}; - -static const struct lg4ff_native_cmd native_dfgt = { - 2, - {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1st command */ - 0xf8, 0x09, 0x03, 0x01, 0x00, 0x00, 0x00} /* 2nd command */ -}; - -static const struct lg4ff_native_cmd native_g25 = { - 1, - {0xf8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00} -}; - -static const struct lg4ff_native_cmd native_g27 = { - 2, - {0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1st command */ - 0xf8, 0x09, 0x04, 0x01, 0x00, 0x00, 0x00} /* 2nd command */ -}; - -static const struct lg4ff_usb_revision lg4ff_revs[] = { - {DFGT_REV_MAJ, DFGT_REV_MIN, &native_dfgt}, /* Driving Force GT */ - {DFP_REV_MAJ, DFP_REV_MIN, &native_dfp}, /* Driving Force Pro */ - {G25_REV_MAJ, G25_REV_MIN, &native_g25}, /* G25 */ - {G27_REV_MAJ, G27_REV_MIN, &native_g27}, /* G27 */ -}; - -static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *effect) +static int hid_lg4ff_play(struct input_dev *dev, void *data, + struct ff_effect *effect) { struct hid_device *hid = input_get_drvdata(dev); struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; @@ -144,12 +55,13 @@ static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *e x = effect->u.ramp.start_level + 0x80; /* 0x80 is no force */ CLAMP(x); report->field[0]->value[0] = 0x11; /* Slot 1 */ - report->field[0]->value[1] = 0x08; + report->field[0]->value[1] = 0x10; report->field[0]->value[2] = x; - report->field[0]->value[3] = 0x80; + report->field[0]->value[3] = 0x00; report->field[0]->value[4] = 0x00; - report->field[0]->value[5] = 0x00; + report->field[0]->value[5] = 0x08; report->field[0]->value[6] = 0x00; + dbg_hid("Autocenter, x=0x%02X\n", x); usbhid_submit_report(hid, report, USB_DIR_OUT); break; @@ -157,184 +69,24 @@ static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *e return 0; } -/* Sends default autocentering command compatible with - * all wheels except Formula Force EX */ -static void hid_lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitude) +static void hid_lg4ff_set_autocenter(struct input_dev *dev, u16 magnitude) { struct hid_device *hid = input_get_drvdata(dev); struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report = list_entry(report_list->next, struct hid_report, list); + __s32 *value = report->field[0]->value; - report->field[0]->value[0] = 0xfe; - report->field[0]->value[1] = 0x0d; - report->field[0]->value[2] = magnitude >> 13; - report->field[0]->value[3] = magnitude >> 13; - report->field[0]->value[4] = magnitude >> 8; - report->field[0]->value[5] = 0x00; - report->field[0]->value[6] = 0x00; - - usbhid_submit_report(hid, report, USB_DIR_OUT); -} - -/* Sends autocentering command compatible with Formula Force EX */ -static void hid_lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude) -{ - struct hid_device *hid = input_get_drvdata(dev); - struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; - struct hid_report *report = list_entry(report_list->next, struct hid_report, list); - magnitude = magnitude * 90 / 65535; - - - report->field[0]->value[0] = 0xfe; - report->field[0]->value[1] = 0x03; - report->field[0]->value[2] = magnitude >> 14; - report->field[0]->value[3] = magnitude >> 14; - report->field[0]->value[4] = magnitude; - report->field[0]->value[5] = 0x00; - report->field[0]->value[6] = 0x00; - - usbhid_submit_report(hid, report, USB_DIR_OUT); -} - -/* Sends command to set range compatible with G25/G27/Driving Force GT */ -static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range) -{ - struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; - struct hid_report *report = list_entry(report_list->next, struct hid_report, list); - dbg_hid("G25/G27/DFGT: setting range to %u\n", range); - - report->field[0]->value[0] = 0xf8; - report->field[0]->value[1] = 0x81; - report->field[0]->value[2] = range & 0x00ff; - report->field[0]->value[3] = (range & 0xff00) >> 8; - report->field[0]->value[4] = 0x00; - report->field[0]->value[5] = 0x00; - report->field[0]->value[6] = 0x00; - - usbhid_submit_report(hid, report, USB_DIR_OUT); -} - -/* Sends commands to set range compatible with Driving Force Pro wheel */ -static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range) -{ - struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; - struct hid_report *report = list_entry(report_list->next, struct hid_report, list); - int start_left, start_right, full_range; - dbg_hid("Driving Force Pro: setting range to %u\n", range); - - /* Prepare "coarse" limit command */ - report->field[0]->value[0] = 0xf8; - report->field[0]->value[1] = 0x00; /* Set later */ - report->field[0]->value[2] = 0x00; - report->field[0]->value[3] = 0x00; - report->field[0]->value[4] = 0x00; - report->field[0]->value[5] = 0x00; - report->field[0]->value[6] = 0x00; - - if (range > 200) { - report->field[0]->value[1] = 0x03; - full_range = 900; - } else { - report->field[0]->value[1] = 0x02; - full_range = 200; - } - usbhid_submit_report(hid, report, USB_DIR_OUT); - - /* Prepare "fine" limit command */ - report->field[0]->value[0] = 0x81; - report->field[0]->value[1] = 0x0b; - report->field[0]->value[2] = 0x00; - report->field[0]->value[3] = 0x00; - report->field[0]->value[4] = 0x00; - report->field[0]->value[5] = 0x00; - report->field[0]->value[6] = 0x00; - - if (range == 200 || range == 900) { /* Do not apply any fine limit */ - usbhid_submit_report(hid, report, USB_DIR_OUT); - return; - } - - /* Construct fine limit command */ - start_left = (((full_range - range + 1) * 2047) / full_range); - start_right = 0xfff - start_left; - - report->field[0]->value[2] = start_left >> 4; - report->field[0]->value[3] = start_right >> 4; - report->field[0]->value[4] = 0xff; - report->field[0]->value[5] = (start_right & 0xe) << 4 | (start_left & 0xe); - report->field[0]->value[6] = 0xff; + *value++ = 0xfe; + *value++ = 0x0d; + *value++ = 0x07; + *value++ = 0x07; + *value++ = (magnitude >> 8) & 0xff; + *value++ = 0x00; + *value = 0x00; usbhid_submit_report(hid, report, USB_DIR_OUT); } -static void hid_lg4ff_switch_native(struct hid_device *hid, const struct lg4ff_native_cmd *cmd) -{ - struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; - struct hid_report *report = list_entry(report_list->next, struct hid_report, list); - __u8 i, j; - - j = 0; - while (j < 7*cmd->cmd_num) { - for (i = 0; i < 7; i++) - report->field[0]->value[i] = cmd->cmd[j++]; - - usbhid_submit_report(hid, report, USB_DIR_OUT); - } -} - -/* Read current range and display it in terminal */ -static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct lg4ff_device_entry *uninitialized_var(entry); - struct list_head *h; - struct hid_device *hid = to_hid_device(dev); - size_t count; - - list_for_each(h, &device_list.list) { - entry = list_entry(h, struct lg4ff_device_entry, list); - if (strcmp(entry->device_id, (&hid->dev)->kobj.name) == 0) - break; - } - if (h == &device_list.list) { - dbg_hid("Device not found!"); - return 0; - } - - count = scnprintf(buf, PAGE_SIZE, "%u\n", entry->range); - return count; -} - -/* Set range to user specified value, call appropriate function - * according to the type of the wheel */ -static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct lg4ff_device_entry *uninitialized_var(entry); - struct list_head *h; - struct hid_device *hid = to_hid_device(dev); - __u16 range = simple_strtoul(buf, NULL, 10); - - list_for_each(h, &device_list.list) { - entry = list_entry(h, struct lg4ff_device_entry, list); - if (strcmp(entry->device_id, (&hid->dev)->kobj.name) == 0) - break; - } - if (h == &device_list.list) { - dbg_hid("Device not found!"); - return count; - } - - if (range == 0) - range = entry->max_range; - - /* Check if the wheel supports range setting - * and that the range is within limits for the wheel */ - if (entry->set_range != NULL && range >= entry->min_range && range <= entry->max_range) { - entry->set_range(hid, range); - entry->range = range; - } - - return count; -} int lg4ff_init(struct hid_device *hid) { @@ -343,10 +95,9 @@ int lg4ff_init(struct hid_device *hid) struct input_dev *dev = hidinput->input; struct hid_report *report; struct hid_field *field; - struct lg4ff_device_entry *entry; - struct usb_device_descriptor *udesc; - int error, i, j; - __u16 bcdDevice, rev_maj, rev_min; + const signed short *ff_bits = ff4_wheel_ac; + int error; + int i; /* Find the report to use */ if (list_empty(report_list)) { @@ -367,122 +118,18 @@ int lg4ff_init(struct hid_device *hid) return -1; } - /* Check what wheel has been connected */ - for (i = 0; i < ARRAY_SIZE(lg4ff_devices); i++) { - if (hid->product == lg4ff_devices[i].product_id) { - dbg_hid("Found compatible device, product ID %04X\n", lg4ff_devices[i].product_id); - break; - } - } - - if (i == ARRAY_SIZE(lg4ff_devices)) { - hid_err(hid, "Device is not supported by lg4ff driver. If you think it should be, consider reporting a bug to" - "LKML, Simon Wood or Michal Maly \n"); - return -1; - } - - /* Attempt to switch wheel to native mode when applicable */ - udesc = &(hid_to_usb_dev(hid)->descriptor); - if (!udesc) { - hid_err(hid, "NULL USB device descriptor\n"); - return -1; - } - bcdDevice = le16_to_cpu(udesc->bcdDevice); - rev_maj = bcdDevice >> 8; - rev_min = bcdDevice & 0xff; - - if (lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_WHEEL) { - dbg_hid("Generic wheel detected, can it do native?\n"); - dbg_hid("USB revision: %2x.%02x\n", rev_maj, rev_min); - - for (j = 0; j < ARRAY_SIZE(lg4ff_revs); j++) { - if (lg4ff_revs[j].rev_maj == rev_maj && lg4ff_revs[j].rev_min == rev_min) { - hid_lg4ff_switch_native(hid, lg4ff_revs[j].command); - hid_info(hid, "Switched to native mode\n"); - } - } - } - - /* Set supported force feedback capabilities */ - for (j = 0; lg4ff_devices[i].ff_effects[j] >= 0; j++) - set_bit(lg4ff_devices[i].ff_effects[j], dev->ffbit); + for (i = 0; ff_bits[i] >= 0; i++) + set_bit(ff_bits[i], dev->ffbit); error = input_ff_create_memless(dev, NULL, hid_lg4ff_play); if (error) return error; - /* Check if autocentering is available and - * set the centering force to zero by default */ - if (test_bit(FF_AUTOCENTER, dev->ffbit)) { - if(rev_maj == FFEX_REV_MAJ && rev_min == FFEX_REV_MIN) /* Formula Force EX expects different autocentering command */ - dev->ff->set_autocenter = hid_lg4ff_set_autocenter_ffex; - else - dev->ff->set_autocenter = hid_lg4ff_set_autocenter_default; - - dev->ff->set_autocenter(dev, 0); - } - - /* Initialize device_list if this is the first device to handle by lg4ff */ - if (!list_inited) { - INIT_LIST_HEAD(&device_list.list); - list_inited = 1; - } - - /* Add the device to device_list */ - entry = (struct lg4ff_device_entry *)kzalloc(sizeof(struct lg4ff_device_entry), GFP_KERNEL); - if (!entry) { - hid_err(hid, "Cannot add device, insufficient memory.\n"); - return -ENOMEM; - } - entry->device_id = kstrdup((&hid->dev)->kobj.name, GFP_KERNEL); - if (!entry->device_id) { - hid_err(hid, "Cannot set device_id, insufficient memory.\n"); - kfree(entry); - return -ENOMEM; - } - entry->min_range = lg4ff_devices[i].min_range; - entry->max_range = lg4ff_devices[i].max_range; - entry->set_range = lg4ff_devices[i].set_range; - list_add(&entry->list, &device_list.list); - - /* Create sysfs interface */ - error = device_create_file(&hid->dev, &dev_attr_range); - if (error) - return error; - dbg_hid("sysfs interface created\n"); - - /* Set the maximum range to start with */ - entry->range = entry->max_range; - if (entry->set_range != NULL) - entry->set_range(hid, entry->range); + if (test_bit(FF_AUTOCENTER, dev->ffbit)) + dev->ff->set_autocenter = hid_lg4ff_set_autocenter; hid_info(hid, "Force feedback for Logitech Speed Force Wireless by Simon Wood \n"); return 0; } -int lg4ff_deinit(struct hid_device *hid) -{ - bool found = 0; - struct lg4ff_device_entry *entry; - struct list_head *h, *g; - list_for_each_safe(h, g, &device_list.list) { - entry = list_entry(h, struct lg4ff_device_entry, list); - if (strcmp(entry->device_id, (&hid->dev)->kobj.name) == 0) { - list_del(h); - kfree(entry->device_id); - kfree(entry); - found = 1; - break; - } - } - - if (!found) { - dbg_hid("Device entry not found!\n"); - return -1; - } - - device_remove_file(&hid->dev, &dev_attr_range); - dbg_hid("Device successfully unregistered\n"); - return 0; -} diff --git a/trunk/drivers/hid/hid-lgff.c b/trunk/drivers/hid/hid-lgff.c index 27bc54f92f44..088f85049290 100644 --- a/trunk/drivers/hid/hid-lgff.c +++ b/trunk/drivers/hid/hid-lgff.c @@ -58,6 +58,12 @@ static const signed short ff_joystick_ac[] = { -1 }; +static const signed short ff_wheel[] = { + FF_CONSTANT, + FF_AUTOCENTER, + -1 +}; + static const struct dev_type devices[] = { { 0x046d, 0xc211, ff_rumble }, { 0x046d, 0xc219, ff_rumble }, @@ -65,7 +71,14 @@ static const struct dev_type devices[] = { { 0x046d, 0xc286, ff_joystick_ac }, { 0x046d, 0xc287, ff_joystick_ac }, { 0x046d, 0xc293, ff_joystick }, + { 0x046d, 0xc294, ff_wheel }, + { 0x046d, 0xc298, ff_wheel }, + { 0x046d, 0xc299, ff_wheel }, + { 0x046d, 0xc29b, ff_wheel }, { 0x046d, 0xc295, ff_joystick }, + { 0x046d, 0xc298, ff_wheel }, + { 0x046d, 0xc299, ff_wheel }, + { 0x046d, 0xca03, ff_wheel }, }; static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *effect) diff --git a/trunk/drivers/hid/hid-logitech-dj.c b/trunk/drivers/hid/hid-logitech-dj.c deleted file mode 100644 index 38b12e45780c..000000000000 --- a/trunk/drivers/hid/hid-logitech-dj.c +++ /dev/null @@ -1,922 +0,0 @@ -/* - * HID driver for Logitech Unifying receivers - * - * Copyright (c) 2011 Logitech - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - - -#include -#include -#include -#include -#include "usbhid/usbhid.h" -#include "hid-ids.h" -#include "hid-logitech-dj.h" - -/* Keyboard descriptor (1) */ -static const char kbd_descriptor[] = { - 0x05, 0x01, /* USAGE_PAGE (generic Desktop) */ - 0x09, 0x06, /* USAGE (Keyboard) */ - 0xA1, 0x01, /* COLLECTION (Application) */ - 0x85, 0x01, /* REPORT_ID (1) */ - 0x95, 0x08, /* REPORT_COUNT (8) */ - 0x75, 0x01, /* REPORT_SIZE (1) */ - 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ - 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ - 0x05, 0x07, /* USAGE_PAGE (Keyboard) */ - 0x19, 0xE0, /* USAGE_MINIMUM (Left Control) */ - 0x29, 0xE7, /* USAGE_MAXIMUM (Right GUI) */ - 0x81, 0x02, /* INPUT (Data,Var,Abs) */ - 0x95, 0x05, /* REPORT COUNT (5) */ - 0x05, 0x08, /* USAGE PAGE (LED page) */ - 0x19, 0x01, /* USAGE MINIMUM (1) */ - 0x29, 0x05, /* USAGE MAXIMUM (5) */ - 0x91, 0x02, /* OUTPUT (Data, Variable, Absolute) */ - 0x95, 0x01, /* REPORT COUNT (1) */ - 0x75, 0x03, /* REPORT SIZE (3) */ - 0x91, 0x01, /* OUTPUT (Constant) */ - 0x95, 0x06, /* REPORT_COUNT (6) */ - 0x75, 0x08, /* REPORT_SIZE (8) */ - 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ - 0x26, 0xFF, 0x00, /* LOGICAL_MAXIMUM (255) */ - 0x05, 0x07, /* USAGE_PAGE (Keyboard) */ - 0x19, 0x00, /* USAGE_MINIMUM (no event) */ - 0x2A, 0xFF, 0x00, /* USAGE_MAXIMUM (reserved) */ - 0x81, 0x00, /* INPUT (Data,Ary,Abs) */ - 0xC0 -}; - -/* Mouse descriptor (2) */ -static const char mse_descriptor[] = { - 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ - 0x09, 0x02, /* USAGE (Mouse) */ - 0xA1, 0x01, /* COLLECTION (Application) */ - 0x85, 0x02, /* REPORT_ID = 2 */ - 0x09, 0x01, /* USAGE (pointer) */ - 0xA1, 0x00, /* COLLECTION (physical) */ - 0x05, 0x09, /* USAGE_PAGE (buttons) */ - 0x19, 0x01, /* USAGE_MIN (1) */ - 0x29, 0x10, /* USAGE_MAX (16) */ - 0x15, 0x00, /* LOGICAL_MIN (0) */ - 0x25, 0x01, /* LOGICAL_MAX (1) */ - 0x95, 0x10, /* REPORT_COUNT (16) */ - 0x75, 0x01, /* REPORT_SIZE (1) */ - 0x81, 0x02, /* INPUT (data var abs) */ - 0x05, 0x01, /* USAGE_PAGE (generic desktop) */ - 0x16, 0x01, 0xF8, /* LOGICAL_MIN (-2047) */ - 0x26, 0xFF, 0x07, /* LOGICAL_MAX (2047) */ - 0x75, 0x0C, /* REPORT_SIZE (12) */ - 0x95, 0x02, /* REPORT_COUNT (2) */ - 0x09, 0x30, /* USAGE (X) */ - 0x09, 0x31, /* USAGE (Y) */ - 0x81, 0x06, /* INPUT */ - 0x15, 0x81, /* LOGICAL_MIN (-127) */ - 0x25, 0x7F, /* LOGICAL_MAX (127) */ - 0x75, 0x08, /* REPORT_SIZE (8) */ - 0x95, 0x01, /* REPORT_COUNT (1) */ - 0x09, 0x38, /* USAGE (wheel) */ - 0x81, 0x06, /* INPUT */ - 0x05, 0x0C, /* USAGE_PAGE(consumer) */ - 0x0A, 0x38, 0x02, /* USAGE(AC Pan) */ - 0x95, 0x01, /* REPORT_COUNT (1) */ - 0x81, 0x06, /* INPUT */ - 0xC0, /* END_COLLECTION */ - 0xC0, /* END_COLLECTION */ -}; - -/* Consumer Control descriptor (3) */ -static const char consumer_descriptor[] = { - 0x05, 0x0C, /* USAGE_PAGE (Consumer Devices) */ - 0x09, 0x01, /* USAGE (Consumer Control) */ - 0xA1, 0x01, /* COLLECTION (Application) */ - 0x85, 0x03, /* REPORT_ID = 3 */ - 0x75, 0x10, /* REPORT_SIZE (16) */ - 0x95, 0x02, /* REPORT_COUNT (2) */ - 0x15, 0x01, /* LOGICAL_MIN (1) */ - 0x26, 0x8C, 0x02, /* LOGICAL_MAX (652) */ - 0x19, 0x01, /* USAGE_MIN (1) */ - 0x2A, 0x8C, 0x02, /* USAGE_MAX (652) */ - 0x81, 0x00, /* INPUT (Data Ary Abs) */ - 0xC0, /* END_COLLECTION */ -}; /* */ - -/* System control descriptor (4) */ -static const char syscontrol_descriptor[] = { - 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ - 0x09, 0x80, /* USAGE (System Control) */ - 0xA1, 0x01, /* COLLECTION (Application) */ - 0x85, 0x04, /* REPORT_ID = 4 */ - 0x75, 0x02, /* REPORT_SIZE (2) */ - 0x95, 0x01, /* REPORT_COUNT (1) */ - 0x15, 0x01, /* LOGICAL_MIN (1) */ - 0x25, 0x03, /* LOGICAL_MAX (3) */ - 0x09, 0x82, /* USAGE (System Sleep) */ - 0x09, 0x81, /* USAGE (System Power Down) */ - 0x09, 0x83, /* USAGE (System Wake Up) */ - 0x81, 0x60, /* INPUT (Data Ary Abs NPrf Null) */ - 0x75, 0x06, /* REPORT_SIZE (6) */ - 0x81, 0x03, /* INPUT (Cnst Var Abs) */ - 0xC0, /* END_COLLECTION */ -}; - -/* Media descriptor (8) */ -static const char media_descriptor[] = { - 0x06, 0xbc, 0xff, /* Usage Page 0xffbc */ - 0x09, 0x88, /* Usage 0x0088 */ - 0xa1, 0x01, /* BeginCollection */ - 0x85, 0x08, /* Report ID 8 */ - 0x19, 0x01, /* Usage Min 0x0001 */ - 0x29, 0xff, /* Usage Max 0x00ff */ - 0x15, 0x01, /* Logical Min 1 */ - 0x26, 0xff, 0x00, /* Logical Max 255 */ - 0x75, 0x08, /* Report Size 8 */ - 0x95, 0x01, /* Report Count 1 */ - 0x81, 0x00, /* Input */ - 0xc0, /* EndCollection */ -}; /* */ - -/* Maximum size of all defined hid reports in bytes (including report id) */ -#define MAX_REPORT_SIZE 8 - -/* Number of possible hid report types that can be created by this driver. - * - * Right now, RF report types have the same report types (or report id's) - * than the hid report created from those RF reports. In the future - * this doesnt have to be true. - * - * For instance, RF report type 0x01 which has a size of 8 bytes, corresponds - * to hid report id 0x01, this is standard keyboard. Same thing applies to mice - * reports and consumer control, etc. If a new RF report is created, it doesn't - * has to have the same report id as its corresponding hid report, so an - * translation may have to take place for future report types. - */ -#define NUMBER_OF_HID_REPORTS 32 -static const u8 hid_reportid_size_map[NUMBER_OF_HID_REPORTS] = { - [1] = 8, /* Standard keyboard */ - [2] = 8, /* Standard mouse */ - [3] = 5, /* Consumer control */ - [4] = 2, /* System control */ - [8] = 2, /* Media Center */ -}; - - -#define LOGITECH_DJ_INTERFACE_NUMBER 0x02 - -static struct hid_ll_driver logi_dj_ll_driver; - -static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf, - size_t count, - unsigned char report_type); - -static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev, - struct dj_report *dj_report) -{ - /* Called in delayed work context */ - struct dj_device *dj_dev; - unsigned long flags; - - spin_lock_irqsave(&djrcv_dev->lock, flags); - dj_dev = djrcv_dev->paired_dj_devices[dj_report->device_index]; - djrcv_dev->paired_dj_devices[dj_report->device_index] = NULL; - spin_unlock_irqrestore(&djrcv_dev->lock, flags); - - if (dj_dev != NULL) { - hid_destroy_device(dj_dev->hdev); - kfree(dj_dev); - } else { - dev_err(&djrcv_dev->hdev->dev, "%s: can't destroy a NULL device\n", - __func__); - } -} - -static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev, - struct dj_report *dj_report) -{ - /* Called in delayed work context */ - struct hid_device *djrcv_hdev = djrcv_dev->hdev; - struct usb_interface *intf = to_usb_interface(djrcv_hdev->dev.parent); - struct usb_device *usbdev = interface_to_usbdev(intf); - struct hid_device *dj_hiddev; - struct dj_device *dj_dev; - - /* Device index goes from 1 to 6, we need 3 bytes to store the - * semicolon, the index, and a null terminator - */ - unsigned char tmpstr[3]; - - if (dj_report->report_params[DEVICE_PAIRED_PARAM_SPFUNCTION] & - SPFUNCTION_DEVICE_LIST_EMPTY) { - dbg_hid("%s: device list is empty\n", __func__); - return; - } - - if ((dj_report->device_index < DJ_DEVICE_INDEX_MIN) || - (dj_report->device_index > DJ_DEVICE_INDEX_MAX)) { - dev_err(&djrcv_hdev->dev, "%s: invalid device index:%d\n", - __func__, dj_report->device_index); - return; - } - - dj_hiddev = hid_allocate_device(); - if (IS_ERR(dj_hiddev)) { - dev_err(&djrcv_hdev->dev, "%s: hid_allocate_device failed\n", - __func__); - return; - } - - dj_hiddev->ll_driver = &logi_dj_ll_driver; - dj_hiddev->hid_output_raw_report = logi_dj_output_hidraw_report; - - dj_hiddev->dev.parent = &djrcv_hdev->dev; - dj_hiddev->bus = BUS_USB; - dj_hiddev->vendor = le16_to_cpu(usbdev->descriptor.idVendor); - dj_hiddev->product = le16_to_cpu(usbdev->descriptor.idProduct); - snprintf(dj_hiddev->name, sizeof(dj_hiddev->name), - "Logitech Unifying Device. Wireless PID:%02x%02x", - dj_report->report_params[DEVICE_PAIRED_PARAM_EQUAD_ID_MSB], - dj_report->report_params[DEVICE_PAIRED_PARAM_EQUAD_ID_LSB]); - - usb_make_path(usbdev, dj_hiddev->phys, sizeof(dj_hiddev->phys)); - snprintf(tmpstr, sizeof(tmpstr), ":%d", dj_report->device_index); - strlcat(dj_hiddev->phys, tmpstr, sizeof(dj_hiddev->phys)); - - dj_dev = kzalloc(sizeof(struct dj_device), GFP_KERNEL); - - if (!dj_dev) { - dev_err(&djrcv_hdev->dev, "%s: failed allocating dj_device\n", - __func__); - goto dj_device_allocate_fail; - } - - dj_dev->reports_supported = le32_to_cpu( - dj_report->report_params[DEVICE_PAIRED_RF_REPORT_TYPE]); - dj_dev->hdev = dj_hiddev; - dj_dev->dj_receiver_dev = djrcv_dev; - dj_dev->device_index = dj_report->device_index; - dj_hiddev->driver_data = dj_dev; - - djrcv_dev->paired_dj_devices[dj_report->device_index] = dj_dev; - - if (hid_add_device(dj_hiddev)) { - dev_err(&djrcv_hdev->dev, "%s: failed adding dj_device\n", - __func__); - goto hid_add_device_fail; - } - - return; - -hid_add_device_fail: - djrcv_dev->paired_dj_devices[dj_report->device_index] = NULL; - kfree(dj_dev); -dj_device_allocate_fail: - hid_destroy_device(dj_hiddev); -} - -static void delayedwork_callback(struct work_struct *work) -{ - struct dj_receiver_dev *djrcv_dev = - container_of(work, struct dj_receiver_dev, work); - - struct dj_report dj_report; - unsigned long flags; - int count; - - dbg_hid("%s\n", __func__); - - spin_lock_irqsave(&djrcv_dev->lock, flags); - - count = kfifo_out(&djrcv_dev->notif_fifo, &dj_report, - sizeof(struct dj_report)); - - if (count != sizeof(struct dj_report)) { - dev_err(&djrcv_dev->hdev->dev, "%s: workitem triggered without " - "notifications available\n", __func__); - spin_unlock_irqrestore(&djrcv_dev->lock, flags); - return; - } - - if (!kfifo_is_empty(&djrcv_dev->notif_fifo)) { - if (schedule_work(&djrcv_dev->work) == 0) { - dbg_hid("%s: did not schedule the work item, was " - "already queued\n", __func__); - } - } - - spin_unlock_irqrestore(&djrcv_dev->lock, flags); - - switch (dj_report.report_type) { - case REPORT_TYPE_NOTIF_DEVICE_PAIRED: - logi_dj_recv_add_djhid_device(djrcv_dev, &dj_report); - break; - case REPORT_TYPE_NOTIF_DEVICE_UNPAIRED: - logi_dj_recv_destroy_djhid_device(djrcv_dev, &dj_report); - break; - default: - dbg_hid("%s: unexpected report type\n", __func__); - } -} - -static void logi_dj_recv_queue_notification(struct dj_receiver_dev *djrcv_dev, - struct dj_report *dj_report) -{ - /* We are called from atomic context (tasklet && djrcv->lock held) */ - - kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report)); - - if (schedule_work(&djrcv_dev->work) == 0) { - dbg_hid("%s: did not schedule the work item, was already " - "queued\n", __func__); - } -} - -static void logi_dj_recv_forward_null_report(struct dj_receiver_dev *djrcv_dev, - struct dj_report *dj_report) -{ - /* We are called from atomic context (tasklet && djrcv->lock held) */ - unsigned int i; - u8 reportbuffer[MAX_REPORT_SIZE]; - struct dj_device *djdev; - - djdev = djrcv_dev->paired_dj_devices[dj_report->device_index]; - - if (!djdev) { - dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]" - " is NULL, index %d\n", dj_report->device_index); - return; - } - - memset(reportbuffer, 0, sizeof(reportbuffer)); - - for (i = 0; i < NUMBER_OF_HID_REPORTS; i++) { - if (djdev->reports_supported & (1 << i)) { - reportbuffer[0] = i; - if (hid_input_report(djdev->hdev, - HID_INPUT_REPORT, - reportbuffer, - hid_reportid_size_map[i], 1)) { - dbg_hid("hid_input_report error sending null " - "report\n"); - } - } - } -} - -static void logi_dj_recv_forward_report(struct dj_receiver_dev *djrcv_dev, - struct dj_report *dj_report) -{ - /* We are called from atomic context (tasklet && djrcv->lock held) */ - struct dj_device *dj_device; - - dj_device = djrcv_dev->paired_dj_devices[dj_report->device_index]; - - if (dj_device == NULL) { - dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]" - " is NULL, index %d\n", dj_report->device_index); - return; - } - - if ((dj_report->report_type > ARRAY_SIZE(hid_reportid_size_map) - 1) || - (hid_reportid_size_map[dj_report->report_type] == 0)) { - dbg_hid("invalid report type:%x\n", dj_report->report_type); - return; - } - - if (hid_input_report(dj_device->hdev, - HID_INPUT_REPORT, &dj_report->report_type, - hid_reportid_size_map[dj_report->report_type], 1)) { - dbg_hid("hid_input_report error\n"); - } -} - - -static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev, - struct dj_report *dj_report) -{ - struct hid_device *hdev = djrcv_dev->hdev; - int sent_bytes; - - if (!hdev->hid_output_raw_report) { - dev_err(&hdev->dev, "%s:" - "hid_output_raw_report is null\n", __func__); - return -ENODEV; - } - - sent_bytes = hdev->hid_output_raw_report(hdev, (u8 *) dj_report, - sizeof(struct dj_report), - HID_OUTPUT_REPORT); - - return (sent_bytes < 0) ? sent_bytes : 0; -} - -static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev) -{ - struct dj_report dj_report; - - memset(&dj_report, 0, sizeof(dj_report)); - dj_report.report_id = REPORT_ID_DJ_SHORT; - dj_report.device_index = 0xFF; - dj_report.report_type = REPORT_TYPE_CMD_GET_PAIRED_DEVICES; - return logi_dj_recv_send_report(djrcv_dev, &dj_report); -} - -static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev, - unsigned timeout) -{ - struct dj_report dj_report; - - memset(&dj_report, 0, sizeof(dj_report)); - dj_report.report_id = REPORT_ID_DJ_SHORT; - dj_report.device_index = 0xFF; - dj_report.report_type = REPORT_TYPE_CMD_SWITCH; - dj_report.report_params[CMD_SWITCH_PARAM_DEVBITFIELD] = 0x1F; - dj_report.report_params[CMD_SWITCH_PARAM_TIMEOUT_SECONDS] = (u8)timeout; - return logi_dj_recv_send_report(djrcv_dev, &dj_report); -} - - -static int logi_dj_ll_open(struct hid_device *hid) -{ - dbg_hid("%s:%s\n", __func__, hid->phys); - return 0; - -} - -static void logi_dj_ll_close(struct hid_device *hid) -{ - dbg_hid("%s:%s\n", __func__, hid->phys); -} - -static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf, - size_t count, - unsigned char report_type) -{ - /* Called by hid raw to send data */ - dbg_hid("%s\n", __func__); - - return 0; -} - -static int logi_dj_ll_parse(struct hid_device *hid) -{ - struct dj_device *djdev = hid->driver_data; - int retval; - - dbg_hid("%s\n", __func__); - - djdev->hdev->version = 0x0111; - djdev->hdev->country = 0x00; - - if (djdev->reports_supported & STD_KEYBOARD) { - dbg_hid("%s: sending a kbd descriptor, reports_supported: %x\n", - __func__, djdev->reports_supported); - retval = hid_parse_report(hid, - (u8 *) kbd_descriptor, - sizeof(kbd_descriptor)); - if (retval) { - dbg_hid("%s: sending a kbd descriptor, hid_parse failed" - " error: %d\n", __func__, retval); - return retval; - } - } - - if (djdev->reports_supported & STD_MOUSE) { - dbg_hid("%s: sending a mouse descriptor, reports_supported: " - "%x\n", __func__, djdev->reports_supported); - retval = hid_parse_report(hid, - (u8 *) mse_descriptor, - sizeof(mse_descriptor)); - if (retval) { - dbg_hid("%s: sending a mouse descriptor, hid_parse " - "failed error: %d\n", __func__, retval); - return retval; - } - } - - if (djdev->reports_supported & MULTIMEDIA) { - dbg_hid("%s: sending a multimedia report descriptor: %x\n", - __func__, djdev->reports_supported); - retval = hid_parse_report(hid, - (u8 *) consumer_descriptor, - sizeof(consumer_descriptor)); - if (retval) { - dbg_hid("%s: sending a consumer_descriptor, hid_parse " - "failed error: %d\n", __func__, retval); - return retval; - } - } - - if (djdev->reports_supported & POWER_KEYS) { - dbg_hid("%s: sending a power keys report descriptor: %x\n", - __func__, djdev->reports_supported); - retval = hid_parse_report(hid, - (u8 *) syscontrol_descriptor, - sizeof(syscontrol_descriptor)); - if (retval) { - dbg_hid("%s: sending a syscontrol_descriptor, " - "hid_parse failed error: %d\n", - __func__, retval); - return retval; - } - } - - if (djdev->reports_supported & MEDIA_CENTER) { - dbg_hid("%s: sending a media center report descriptor: %x\n", - __func__, djdev->reports_supported); - retval = hid_parse_report(hid, - (u8 *) media_descriptor, - sizeof(media_descriptor)); - if (retval) { - dbg_hid("%s: sending a media_descriptor, hid_parse " - "failed error: %d\n", __func__, retval); - return retval; - } - } - - if (djdev->reports_supported & KBD_LEDS) { - dbg_hid("%s: need to send kbd leds report descriptor: %x\n", - __func__, djdev->reports_supported); - } - - return 0; -} - -static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type, - unsigned int code, int value) -{ - /* Sent by the input layer to handle leds and Force Feedback */ - struct hid_device *dj_hiddev = input_get_drvdata(dev); - struct dj_device *dj_dev = dj_hiddev->driver_data; - - struct dj_receiver_dev *djrcv_dev = - dev_get_drvdata(dj_hiddev->dev.parent); - struct hid_device *dj_rcv_hiddev = djrcv_dev->hdev; - struct hid_report_enum *output_report_enum; - - struct hid_field *field; - struct hid_report *report; - unsigned char data[8]; - int offset; - - dbg_hid("%s: %s, type:%d | code:%d | value:%d\n", - __func__, dev->phys, type, code, value); - - if (type != EV_LED) - return -1; - - offset = hidinput_find_field(dj_hiddev, type, code, &field); - - if (offset == -1) { - dev_warn(&dev->dev, "event field not found\n"); - return -1; - } - hid_set_field(field, offset, value); - hid_output_report(field->report, &data[0]); - - output_report_enum = &dj_rcv_hiddev->report_enum[HID_OUTPUT_REPORT]; - report = output_report_enum->report_id_hash[REPORT_ID_DJ_SHORT]; - hid_set_field(report->field[0], 0, dj_dev->device_index); - hid_set_field(report->field[0], 1, REPORT_TYPE_LEDS); - hid_set_field(report->field[0], 2, data[1]); - - usbhid_submit_report(dj_rcv_hiddev, report, USB_DIR_OUT); - - return 0; - -} - -static int logi_dj_ll_start(struct hid_device *hid) -{ - dbg_hid("%s\n", __func__); - return 0; -} - -static void logi_dj_ll_stop(struct hid_device *hid) -{ - dbg_hid("%s\n", __func__); -} - - -static struct hid_ll_driver logi_dj_ll_driver = { - .parse = logi_dj_ll_parse, - .start = logi_dj_ll_start, - .stop = logi_dj_ll_stop, - .open = logi_dj_ll_open, - .close = logi_dj_ll_close, - .hidinput_input_event = logi_dj_ll_input_event, -}; - - -static int logi_dj_raw_event(struct hid_device *hdev, - struct hid_report *report, u8 *data, - int size) -{ - struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev); - struct dj_report *dj_report = (struct dj_report *) data; - unsigned long flags; - bool report_processed = false; - - dbg_hid("%s, size:%d\n", __func__, size); - - /* Here we receive all data coming from iface 2, there are 4 cases: - * - * 1) Data should continue its normal processing i.e. data does not - * come from the DJ collection, in which case we do nothing and - * return 0, so hid-core can continue normal processing (will forward - * to associated hidraw device) - * - * 2) Data is from DJ collection, and is intended for this driver i. e. - * data contains arrival, departure, etc notifications, in which case - * we queue them for delayed processing by the work queue. We return 1 - * to hid-core as no further processing is required from it. - * - * 3) Data is from DJ collection, and informs a connection change, - * if the change means rf link loss, then we must send a null report - * to the upper layer to discard potentially pressed keys that may be - * repeated forever by the input layer. Return 1 to hid-core as no - * further processing is required. - * - * 4) Data is from DJ collection and is an actual input event from - * a paired DJ device in which case we forward it to the correct hid - * device (via hid_input_report() ) and return 1 so hid-core does not do - * anything else with it. - */ - - spin_lock_irqsave(&djrcv_dev->lock, flags); - if (dj_report->report_id == REPORT_ID_DJ_SHORT) { - switch (dj_report->report_type) { - case REPORT_TYPE_NOTIF_DEVICE_PAIRED: - case REPORT_TYPE_NOTIF_DEVICE_UNPAIRED: - logi_dj_recv_queue_notification(djrcv_dev, dj_report); - break; - case REPORT_TYPE_NOTIF_CONNECTION_STATUS: - if (dj_report->report_params[CONNECTION_STATUS_PARAM_STATUS] == - STATUS_LINKLOSS) { - logi_dj_recv_forward_null_report(djrcv_dev, dj_report); - } - break; - default: - logi_dj_recv_forward_report(djrcv_dev, dj_report); - } - report_processed = true; - } - spin_unlock_irqrestore(&djrcv_dev->lock, flags); - - return report_processed; -} - -static int logi_dj_probe(struct hid_device *hdev, - const struct hid_device_id *id) -{ - struct usb_interface *intf = to_usb_interface(hdev->dev.parent); - struct dj_receiver_dev *djrcv_dev; - int retval; - - if (is_dj_device((struct dj_device *)hdev->driver_data)) - return -ENODEV; - - dbg_hid("%s called for ifnum %d\n", __func__, - intf->cur_altsetting->desc.bInterfaceNumber); - - /* Ignore interfaces 0 and 1, they will not carry any data, dont create - * any hid_device for them */ - if (intf->cur_altsetting->desc.bInterfaceNumber != - LOGITECH_DJ_INTERFACE_NUMBER) { - dbg_hid("%s: ignoring ifnum %d\n", __func__, - intf->cur_altsetting->desc.bInterfaceNumber); - return -ENODEV; - } - - /* Treat interface 2 */ - - djrcv_dev = kzalloc(sizeof(struct dj_receiver_dev), GFP_KERNEL); - if (!djrcv_dev) { - dev_err(&hdev->dev, - "%s:failed allocating dj_receiver_dev\n", __func__); - return -ENOMEM; - } - djrcv_dev->hdev = hdev; - INIT_WORK(&djrcv_dev->work, delayedwork_callback); - spin_lock_init(&djrcv_dev->lock); - if (kfifo_alloc(&djrcv_dev->notif_fifo, - DJ_MAX_NUMBER_NOTIFICATIONS * sizeof(struct dj_report), - GFP_KERNEL)) { - dev_err(&hdev->dev, - "%s:failed allocating notif_fifo\n", __func__); - kfree(djrcv_dev); - return -ENOMEM; - } - hid_set_drvdata(hdev, djrcv_dev); - - /* Call to usbhid to fetch the HID descriptors of interface 2 and - * subsequently call to the hid/hid-core to parse the fetched - * descriptors, this will in turn create the hidraw and hiddev nodes - * for interface 2 of the receiver */ - retval = hid_parse(hdev); - if (retval) { - dev_err(&hdev->dev, - "%s:parse of interface 2 failed\n", __func__); - goto hid_parse_fail; - } - - /* Starts the usb device and connects to upper interfaces hiddev and - * hidraw */ - retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT); - if (retval) { - dev_err(&hdev->dev, - "%s:hid_hw_start returned error\n", __func__); - goto hid_hw_start_fail; - } - - retval = logi_dj_recv_switch_to_dj_mode(djrcv_dev, 0); - if (retval < 0) { - dev_err(&hdev->dev, - "%s:logi_dj_recv_switch_to_dj_mode returned error:%d\n", - __func__, retval); - goto switch_to_dj_mode_fail; - } - - /* This is enabling the polling urb on the IN endpoint */ - retval = hdev->ll_driver->open(hdev); - if (retval < 0) { - dev_err(&hdev->dev, "%s:hdev->ll_driver->open returned " - "error:%d\n", __func__, retval); - goto llopen_failed; - } - - retval = logi_dj_recv_query_paired_devices(djrcv_dev); - if (retval < 0) { - dev_err(&hdev->dev, "%s:logi_dj_recv_query_paired_devices " - "error:%d\n", __func__, retval); - goto logi_dj_recv_query_paired_devices_failed; - } - - return retval; - -logi_dj_recv_query_paired_devices_failed: - hdev->ll_driver->close(hdev); - -llopen_failed: -switch_to_dj_mode_fail: - hid_hw_stop(hdev); - -hid_hw_start_fail: -hid_parse_fail: - kfifo_free(&djrcv_dev->notif_fifo); - kfree(djrcv_dev); - hid_set_drvdata(hdev, NULL); - return retval; - -} - -#ifdef CONFIG_PM -static int logi_dj_reset_resume(struct hid_device *hdev) -{ - int retval; - struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev); - - retval = logi_dj_recv_switch_to_dj_mode(djrcv_dev, 0); - if (retval < 0) { - dev_err(&hdev->dev, - "%s:logi_dj_recv_switch_to_dj_mode returned error:%d\n", - __func__, retval); - } - - return 0; -} -#endif - -static void logi_dj_remove(struct hid_device *hdev) -{ - struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev); - struct dj_device *dj_dev; - int i; - - dbg_hid("%s\n", __func__); - - cancel_work_sync(&djrcv_dev->work); - - hdev->ll_driver->close(hdev); - hid_hw_stop(hdev); - - /* I suppose that at this point the only context that can access - * the djrecv_data is this thread as the work item is guaranteed to - * have finished and no more raw_event callbacks should arrive after - * the remove callback was triggered so no locks are put around the - * code below */ - for (i = 0; i < (DJ_MAX_PAIRED_DEVICES + DJ_DEVICE_INDEX_MIN); i++) { - dj_dev = djrcv_dev->paired_dj_devices[i]; - if (dj_dev != NULL) { - hid_destroy_device(dj_dev->hdev); - kfree(dj_dev); - djrcv_dev->paired_dj_devices[i] = NULL; - } - } - - kfifo_free(&djrcv_dev->notif_fifo); - kfree(djrcv_dev); - hid_set_drvdata(hdev, NULL); -} - -static int logi_djdevice_probe(struct hid_device *hdev, - const struct hid_device_id *id) -{ - int ret; - struct dj_device *dj_dev = hdev->driver_data; - - if (!is_dj_device(dj_dev)) - return -ENODEV; - - ret = hid_parse(hdev); - if (!ret) - ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); - - return ret; -} - -static const struct hid_device_id logi_dj_receivers[] = { - {HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, - USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER)}, - {HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, - USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2)}, - {} -}; - -MODULE_DEVICE_TABLE(hid, logi_dj_receivers); - -static struct hid_driver logi_djreceiver_driver = { - .name = "logitech-djreceiver", - .id_table = logi_dj_receivers, - .probe = logi_dj_probe, - .remove = logi_dj_remove, - .raw_event = logi_dj_raw_event, -#ifdef CONFIG_PM - .reset_resume = logi_dj_reset_resume, -#endif -}; - - -static const struct hid_device_id logi_dj_devices[] = { - {HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, - USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER)}, - {HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, - USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2)}, - {} -}; - -static struct hid_driver logi_djdevice_driver = { - .name = "logitech-djdevice", - .id_table = logi_dj_devices, - .probe = logi_djdevice_probe, -}; - - -static int __init logi_dj_init(void) -{ - int retval; - - dbg_hid("Logitech-DJ:%s\n", __func__); - - retval = hid_register_driver(&logi_djreceiver_driver); - if (retval) - return retval; - - retval = hid_register_driver(&logi_djdevice_driver); - if (retval) - hid_unregister_driver(&logi_djreceiver_driver); - - return retval; - -} - -static void __exit logi_dj_exit(void) -{ - dbg_hid("Logitech-DJ:%s\n", __func__); - - hid_unregister_driver(&logi_djdevice_driver); - hid_unregister_driver(&logi_djreceiver_driver); - -} - -module_init(logi_dj_init); -module_exit(logi_dj_exit); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Logitech"); -MODULE_AUTHOR("Nestor Lopez Casado"); -MODULE_AUTHOR("nlopezcasad@logitech.com"); diff --git a/trunk/drivers/hid/hid-logitech-dj.h b/trunk/drivers/hid/hid-logitech-dj.h deleted file mode 100644 index fd28a5e0ca3b..000000000000 --- a/trunk/drivers/hid/hid-logitech-dj.h +++ /dev/null @@ -1,123 +0,0 @@ -#ifndef __HID_LOGITECH_DJ_H -#define __HID_LOGITECH_DJ_H - -/* - * HID driver for Logitech Unifying receivers - * - * Copyright (c) 2011 Logitech - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include - -#define DJ_MAX_PAIRED_DEVICES 6 -#define DJ_MAX_NUMBER_NOTIFICATIONS 8 -#define DJ_DEVICE_INDEX_MIN 1 -#define DJ_DEVICE_INDEX_MAX 6 - -#define DJREPORT_SHORT_LENGTH 15 -#define DJREPORT_LONG_LENGTH 32 - -#define REPORT_ID_DJ_SHORT 0x20 -#define REPORT_ID_DJ_LONG 0x21 - -#define REPORT_TYPE_RFREPORT_FIRST 0x01 -#define REPORT_TYPE_RFREPORT_LAST 0x1F - -/* Command Switch to DJ mode */ -#define REPORT_TYPE_CMD_SWITCH 0x80 -#define CMD_SWITCH_PARAM_DEVBITFIELD 0x00 -#define CMD_SWITCH_PARAM_TIMEOUT_SECONDS 0x01 -#define TIMEOUT_NO_KEEPALIVE 0x00 - -/* Command to Get the list of Paired devices */ -#define REPORT_TYPE_CMD_GET_PAIRED_DEVICES 0x81 - -/* Device Paired Notification */ -#define REPORT_TYPE_NOTIF_DEVICE_PAIRED 0x41 -#define SPFUNCTION_MORE_NOTIF_EXPECTED 0x01 -#define SPFUNCTION_DEVICE_LIST_EMPTY 0x02 -#define DEVICE_PAIRED_PARAM_SPFUNCTION 0x00 -#define DEVICE_PAIRED_PARAM_EQUAD_ID_LSB 0x01 -#define DEVICE_PAIRED_PARAM_EQUAD_ID_MSB 0x02 -#define DEVICE_PAIRED_RF_REPORT_TYPE 0x03 - -/* Device Un-Paired Notification */ -#define REPORT_TYPE_NOTIF_DEVICE_UNPAIRED 0x40 - - -/* Connection Status Notification */ -#define REPORT_TYPE_NOTIF_CONNECTION_STATUS 0x42 -#define CONNECTION_STATUS_PARAM_STATUS 0x00 -#define STATUS_LINKLOSS 0x01 - -/* Error Notification */ -#define REPORT_TYPE_NOTIF_ERROR 0x7F -#define NOTIF_ERROR_PARAM_ETYPE 0x00 -#define ETYPE_KEEPALIVE_TIMEOUT 0x01 - -/* supported DJ HID && RF report types */ -#define REPORT_TYPE_KEYBOARD 0x01 -#define REPORT_TYPE_MOUSE 0x02 -#define REPORT_TYPE_CONSUMER_CONTROL 0x03 -#define REPORT_TYPE_SYSTEM_CONTROL 0x04 -#define REPORT_TYPE_MEDIA_CENTER 0x08 -#define REPORT_TYPE_LEDS 0x0E - -/* RF Report types bitfield */ -#define STD_KEYBOARD 0x00000002 -#define STD_MOUSE 0x00000004 -#define MULTIMEDIA 0x00000008 -#define POWER_KEYS 0x00000010 -#define MEDIA_CENTER 0x00000100 -#define KBD_LEDS 0x00004000 - -struct dj_report { - u8 report_id; - u8 device_index; - u8 report_type; - u8 report_params[DJREPORT_SHORT_LENGTH - 3]; -}; - -struct dj_receiver_dev { - struct hid_device *hdev; - struct dj_device *paired_dj_devices[DJ_MAX_PAIRED_DEVICES + - DJ_DEVICE_INDEX_MIN]; - struct work_struct work; - struct kfifo notif_fifo; - spinlock_t lock; -}; - -struct dj_device { - struct hid_device *hdev; - struct dj_receiver_dev *dj_receiver_dev; - u32 reports_supported; - u8 device_index; -}; - -/** - * is_dj_device - know if the given dj_device is not the receiver. - * @dj_dev: the dj device to test - * - * This macro tests if a struct dj_device pointer is a device created - * by the bus enumarator. - */ -#define is_dj_device(dj_dev) \ - (&(dj_dev)->dj_receiver_dev->hdev->dev == (dj_dev)->hdev->dev.parent) - -#endif diff --git a/trunk/drivers/hid/hid-multitouch.c b/trunk/drivers/hid/hid-multitouch.c index 58d0e7aaf088..4ee21ac8e856 100644 --- a/trunk/drivers/hid/hid-multitouch.c +++ b/trunk/drivers/hid/hid-multitouch.c @@ -213,6 +213,16 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct mt_class *cls = td->mtclass; __s32 quirks = cls->quirks; + /* Only map fields from TouchScreen or TouchPad collections. + * We need to ignore fields that belong to other collections + * such as Mouse that might have the same GenericDesktop usages. */ + if (field->application == HID_DG_TOUCHSCREEN) + set_bit(INPUT_PROP_DIRECT, hi->input->propbit); + else if (field->application == HID_DG_TOUCHPAD) + set_bit(INPUT_PROP_POINTER, hi->input->propbit); + else + return 0; + switch (usage->hid & HID_USAGE_PAGE) { case HID_UP_GENDESK: