diff options
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/Kconfig | 8 | ||||
-rw-r--r-- | drivers/hid/Makefile | 20 | ||||
-rw-r--r-- | drivers/hid/hid-core.c | 1 | ||||
-rw-r--r-- | drivers/hid/hid-ids.h | 4 | ||||
-rw-r--r-- | drivers/hid/hid-input.c | 11 | ||||
-rw-r--r-- | drivers/hid/hid-lg.c | 9 | ||||
-rw-r--r-- | drivers/hid/hid-lg.h | 4 | ||||
-rw-r--r-- | drivers/hid/hid-lg4ff.c | 194 | ||||
-rw-r--r-- | drivers/hid/hid-magicmouse.c | 2 | ||||
-rw-r--r-- | drivers/hid/hid-multitouch.c | 185 | ||||
-rw-r--r-- | drivers/hid/hid-picolcd.c | 2748 | ||||
-rw-r--r-- | drivers/hid/hid-picolcd.h | 309 | ||||
-rw-r--r-- | drivers/hid/hid-picolcd_backlight.c | 122 | ||||
-rw-r--r-- | drivers/hid/hid-picolcd_cir.c | 152 | ||||
-rw-r--r-- | drivers/hid/hid-picolcd_core.c | 689 | ||||
-rw-r--r-- | drivers/hid/hid-picolcd_debugfs.c | 899 | ||||
-rw-r--r-- | drivers/hid/hid-picolcd_fb.c | 615 | ||||
-rw-r--r-- | drivers/hid/hid-picolcd_lcd.c | 107 | ||||
-rw-r--r-- | drivers/hid/hid-picolcd_leds.c | 175 | ||||
-rw-r--r-- | drivers/hid/hid-uclogic.c | 98 | ||||
-rw-r--r-- | drivers/hid/hid-wacom.c | 169 | ||||
-rw-r--r-- | drivers/hid/hid-wiimote-ext.c | 97 | ||||
-rw-r--r-- | drivers/hid/hidraw.c | 69 |
23 files changed, 3722 insertions, 2965 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 378be0bdc99..bf0617e47b8 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -527,6 +527,14 @@ config HID_PICOLCD_LEDS ---help--- Provide access to PicoLCD's GPO pins via leds class. +config HID_PICOLCD_CIR + bool "CIR via RC class" if EXPERT + default !EXPERT + depends on HID_PICOLCD + depends on HID_PICOLCD=RC_CORE || RC_CORE=y + ---help--- + Provide access to PicoLCD's CIR interface via remote control (LIRC). + config HID_PRIMAX tristate "Primax non-fully HID-compliant devices" depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 333ed6c961c..5a3690ff9bf 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -69,6 +69,26 @@ obj-$(CONFIG_HID_PRODIKEYS) += hid-prodikeys.o obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o +hid-picolcd-y += hid-picolcd_core.o +ifdef CONFIG_HID_PICOLCD_FB +hid-picolcd-y += hid-picolcd_fb.o +endif +ifdef CONFIG_HID_PICOLCD_BACKLIGHT +hid-picolcd-y += hid-picolcd_backlight.o +endif +ifdef CONFIG_HID_PICOLCD_LCD +hid-picolcd-y += hid-picolcd_lcd.o +endif +ifdef CONFIG_HID_PICOLCD_LEDS +hid-picolcd-y += hid-picolcd_leds.o +endif +ifdef CONFIG_HID_PICOLCD_CIR +hid-picolcd-y += hid-picolcd_cir.o +endif +ifdef CONFIG_DEBUG_FS +hid-picolcd-y += hid-picolcd_debugfs.o +endif + obj-$(CONFIG_HID_PRIMAX) += hid-primax.o obj-$(CONFIG_HID_PS3REMOTE) += hid-ps3remote.o obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \ diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index e4275d4934e..9072e0ed187 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1665,6 +1665,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) }, + { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) }, { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) }, { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SUPER_JOY_BOX_3) }, { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 40411c9d88f..a534375fdf2 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -283,6 +283,9 @@ #define USB_VENDOR_ID_EMS 0x2006 #define USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II 0x0118 +#define USB_VENDOR_ID_FLATFROG 0x25b5 +#define USB_DEVICE_ID_MULTITOUCH_3200 0x0002 + #define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 @@ -760,6 +763,7 @@ #define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U 0x0005 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP1062 0x0064 #define USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850 0x0522 +#define USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60 0x0781 #define USB_VENDOR_ID_UNITEC 0x227d #define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709 0x0709 diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 811bfad6460..d917c0d5368 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1154,6 +1154,7 @@ static void report_features(struct hid_device *hid) int hidinput_connect(struct hid_device *hid, unsigned int force) { + struct hid_driver *drv = hid->driver; struct hid_report *report; struct hid_input *hidinput = NULL; struct input_dev *input_dev; @@ -1228,6 +1229,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) * UGCI) cram a lot of unrelated inputs into the * same interface. */ hidinput->report = report; + if (drv->input_configured) + drv->input_configured(hid, hidinput); if (input_register_device(hidinput->input)) goto out_cleanup; hidinput = NULL; @@ -1235,8 +1238,12 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) } } - if (hidinput && input_register_device(hidinput->input)) - goto out_cleanup; + if (hidinput) { + if (drv->input_configured) + drv->input_configured(hid, hidinput); + if (input_register_device(hidinput->input)) + goto out_cleanup; + } return 0; diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index fc37ed6b108..afc4de389f8 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -342,6 +342,9 @@ static int lg_event(struct hid_device *hdev, struct hid_field *field, -value); return 1; } + if (drv_data->quirks & LG_FF4) { + return lg4ff_adjust_input_event(hdev, field, usage, value, drv_data); + } return 0; } @@ -358,7 +361,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) return -ENOMEM; } drv_data->quirks = id->driver_data; - + hid_set_drvdata(hdev, (void *)drv_data); if (drv_data->quirks & LG_NOGET) @@ -380,7 +383,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) } /* Setup wireless link with Logitech Wii wheel */ - if(hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) { + if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) { 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); @@ -476,7 +479,7 @@ static const struct hid_device_id lg_devices[] = { .driver_data = LG_NOGET | LG_FF4 }, { 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 ), + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG), .driver_data = LG_FF }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2), .driver_data = LG_FF2 }, diff --git a/drivers/hid/hid-lg.h b/drivers/hid/hid-lg.h index d64cf8d2751..142ce3f5f05 100644 --- a/drivers/hid/hid-lg.h +++ b/drivers/hid/hid-lg.h @@ -25,9 +25,13 @@ static inline int lg3ff_init(struct hid_device *hdev) { return -1; } #endif #ifdef CONFIG_LOGIWHEELS_FF +int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field, + struct hid_usage *usage, __s32 value, struct lg_drv_data *drv_data); int lg4ff_init(struct hid_device *hdev); int lg4ff_deinit(struct hid_device *hdev); #else +static inline int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field, + struct hid_usage *usage, __s32 value, struct lg_drv_data *drv_data) { return 0; } static inline int lg4ff_init(struct hid_device *hdev) { return -1; } static inline int lg4ff_deinit(struct hid_device *hdev) { return -1; } #endif diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index f3390ee6105..4fb4a80928c 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -43,6 +43,11 @@ #define G27_REV_MAJ 0x12 #define G27_REV_MIN 0x38 +#define DFP_X_MIN 0 +#define DFP_X_MAX 16383 +#define DFP_PEDAL_MIN 0 +#define DFP_PEDAL_MAX 255 + #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); @@ -53,6 +58,7 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at static DEVICE_ATTR(range, S_IRWXU | S_IRWXG | S_IRWXO, lg4ff_range_show, lg4ff_range_store); struct lg4ff_device_entry { + __u32 product_id; __u16 range; __u16 min_range; __u16 max_range; @@ -129,26 +135,77 @@ static const struct lg4ff_usb_revision lg4ff_revs[] = { {G27_REV_MAJ, G27_REV_MIN, &native_g27}, /* G27 */ }; +/* Recalculates X axis value accordingly to currently selected range */ +static __s32 lg4ff_adjust_dfp_x_axis(__s32 value, __u16 range) +{ + __u16 max_range; + __s32 new_value; + + if (range == 900) + return value; + else if (range == 200) + return value; + else if (range < 200) + max_range = 200; + else + max_range = 900; + + new_value = 8192 + mult_frac(value - 8192, max_range, range); + if (new_value < 0) + return 0; + else if (new_value > 16383) + return 16383; + else + return new_value; +} + +int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field, + struct hid_usage *usage, __s32 value, struct lg_drv_data *drv_data) +{ + struct lg4ff_device_entry *entry = drv_data->device_props; + __s32 new_value = 0; + + if (!entry) { + hid_err(hid, "Device properties not found"); + return 0; + } + + switch (entry->product_id) { + case USB_DEVICE_ID_LOGITECH_DFP_WHEEL: + switch (usage->code) { + case ABS_X: + new_value = lg4ff_adjust_dfp_x_axis(value, entry->range); + input_event(field->hidinput->input, usage->type, usage->code, new_value); + return 1; + default: + return 0; + } + default: + return 0; + } +} + 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; struct hid_report *report = list_entry(report_list->next, struct hid_report, list); + __s32 *value = report->field[0]->value; int x; -#define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff +#define CLAMP(x) do { if (x < 0) x = 0; else if (x > 0xff) x = 0xff; } while (0) switch (effect->type) { case FF_CONSTANT: 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[2] = x; - report->field[0]->value[3] = 0x80; - report->field[0]->value[4] = 0x00; - report->field[0]->value[5] = 0x00; - report->field[0]->value[6] = 0x00; + value[0] = 0x11; /* Slot 1 */ + value[1] = 0x08; + value[2] = x; + value[3] = 0x80; + value[4] = 0x00; + value[5] = 0x00; + value[6] = 0x00; usbhid_submit_report(hid, report, USB_DIR_OUT); break; @@ -163,14 +220,15 @@ static void hid_lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitud 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; + value[0] = 0xfe; + value[1] = 0x0d; + value[2] = magnitude >> 13; + value[3] = magnitude >> 13; + value[4] = magnitude >> 8; + value[5] = 0x00; + value[6] = 0x00; usbhid_submit_report(hid, report, USB_DIR_OUT); } @@ -181,16 +239,16 @@ 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); + __s32 *value = report->field[0]->value; 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; + value[0] = 0xfe; + value[1] = 0x03; + value[2] = magnitude >> 14; + value[3] = magnitude >> 14; + value[4] = magnitude; + value[5] = 0x00; + value[6] = 0x00; usbhid_submit_report(hid, report, USB_DIR_OUT); } @@ -200,15 +258,17 @@ 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); + __s32 *value = report->field[0]->value; + 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; + value[0] = 0xf8; + value[1] = 0x81; + value[2] = range & 0x00ff; + value[3] = (range & 0xff00) >> 8; + value[4] = 0x00; + value[5] = 0x00; + value[6] = 0x00; usbhid_submit_report(hid, report, USB_DIR_OUT); } @@ -219,16 +279,18 @@ 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; + __s32 *value = report->field[0]->value; + 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; + value[0] = 0xf8; + value[1] = 0x00; /* Set later */ + value[2] = 0x00; + value[3] = 0x00; + value[4] = 0x00; + value[5] = 0x00; + value[6] = 0x00; if (range > 200) { report->field[0]->value[1] = 0x03; @@ -240,13 +302,13 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range) 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; + value[0] = 0x81; + value[1] = 0x0b; + value[2] = 0x00; + value[3] = 0x00; + value[4] = 0x00; + value[5] = 0x00; + value[6] = 0x00; if (range == 200 || range == 900) { /* Do not apply any fine limit */ usbhid_submit_report(hid, report, USB_DIR_OUT); @@ -257,11 +319,11 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range) 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[2] = start_left >> 4; + value[3] = start_right >> 4; + value[4] = 0xff; + value[5] = (start_right & 0xe) << 4 | (start_left & 0xe); + value[6] = 0xff; usbhid_submit_report(hid, report, USB_DIR_OUT); } @@ -344,14 +406,15 @@ static void lg4ff_set_leds(struct hid_device *hid, __u8 leds) { 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); - - report->field[0]->value[0] = 0xf8; - report->field[0]->value[1] = 0x12; - report->field[0]->value[2] = leds; - report->field[0]->value[3] = 0x00; - report->field[0]->value[4] = 0x00; - report->field[0]->value[5] = 0x00; - report->field[0]->value[6] = 0x00; + __s32 *value = report->field[0]->value; + + value[0] = 0xf8; + value[1] = 0x12; + value[2] = leds; + value[3] = 0x00; + value[4] = 0x00; + value[5] = 0x00; + value[6] = 0x00; usbhid_submit_report(hid, report, USB_DIR_OUT); } @@ -501,7 +564,7 @@ int lg4ff_init(struct hid_device *hid) /* 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 */ + 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; @@ -524,6 +587,7 @@ int lg4ff_init(struct hid_device *hid) } drv_data->device_props = entry; + entry->product_id = lg4ff_devices[i].product_id; entry->min_range = lg4ff_devices[i].min_range; entry->max_range = lg4ff_devices[i].max_range; entry->set_range = lg4ff_devices[i].set_range; @@ -534,6 +598,18 @@ int lg4ff_init(struct hid_device *hid) return error; dbg_hid("sysfs interface created\n"); + /* Set default axes parameters */ + switch (lg4ff_devices[i].product_id) { + case USB_DEVICE_ID_LOGITECH_DFP_WHEEL: + dbg_hid("Setting axes parameters for Driving Force Pro\n"); + input_set_abs_params(dev, ABS_X, DFP_X_MIN, DFP_X_MAX, 0, 0); + input_set_abs_params(dev, ABS_Y, DFP_PEDAL_MIN, DFP_PEDAL_MAX, 0, 0); + input_set_abs_params(dev, ABS_RZ, DFP_PEDAL_MIN, DFP_PEDAL_MAX, 0, 0); + break; + default: + break; + } + /* Set the maximum range to start with */ entry->range = entry->max_range; if (entry->set_range != NULL) @@ -594,6 +670,8 @@ out: return 0; } + + int lg4ff_deinit(struct hid_device *hid) { struct lg4ff_device_entry *entry; diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index 73647266daa..25ddf3e3aec 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -392,7 +392,7 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd __set_bit(EV_ABS, input->evbit); - error = input_mt_init_slots(input, 16); + error = input_mt_init_slots(input, 16, 0); if (error) return error; input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255 << 2, diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 59c8b5c1d2d..ee0b76b398c 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -51,12 +51,12 @@ MODULE_LICENSE("GPL"); #define MT_QUIRK_VALID_IS_INRANGE (1 << 5) #define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 6) #define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE (1 << 8) +#define MT_QUIRK_NO_AREA (1 << 9) struct mt_slot { __s32 x, y, p, w, h; __s32 contactid; /* the device ContactID assigned to this slot */ bool touch_state; /* is the touch valid? */ - bool seen_in_this_frame;/* has this slot been updated */ }; struct mt_class { @@ -92,8 +92,9 @@ struct mt_device { __u8 touches_by_report; /* how many touches are present in one report: * 1 means we should use a serial protocol * > 1 means hybrid (multitouch) protocol */ + bool serial_maybe; /* need to check for serial protocol */ bool curvalid; /* is the current contact valid? */ - struct mt_slot *slots; + unsigned mt_flags; /* flags to pass to input-mt */ }; /* classes of device behavior */ @@ -115,6 +116,7 @@ struct mt_device { #define MT_CLS_EGALAX_SERIAL 0x0104 #define MT_CLS_TOPSEED 0x0105 #define MT_CLS_PANASONIC 0x0106 +#define MT_CLS_FLATFROG 0x0107 #define MT_DEFAULT_MAXCONTACT 10 @@ -134,25 +136,6 @@ static int cypress_compute_slot(struct mt_device *td) return -1; } -static int find_slot_from_contactid(struct mt_device *td) -{ - int i; - for (i = 0; i < td->maxcontacts; ++i) { - if (td->slots[i].contactid == td->curdata.contactid && - td->slots[i].touch_state) - return i; - } - for (i = 0; i < td->maxcontacts; ++i) { - if (!td->slots[i].seen_in_this_frame && - !td->slots[i].touch_state) - return i; - } - /* should not occurs. If this happens that means - * that the device sent more touches that it says - * in the report descriptor. It is ignored then. */ - return -1; -} - static struct mt_class mt_classes[] = { { .name = MT_CLS_DEFAULT, .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP }, @@ -190,7 +173,9 @@ static struct mt_class mt_classes[] = { MT_QUIRK_SLOT_IS_CONTACTID, .sn_move = 2048, .sn_width = 128, - .sn_height = 128 }, + .sn_height = 128, + .maxcontacts = 60, + }, { .name = MT_CLS_CYPRESS, .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | MT_QUIRK_CYPRESS, @@ -216,6 +201,12 @@ static struct mt_class mt_classes[] = { .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP, .maxcontacts = 4 }, + { .name = MT_CLS_FLATFROG, + .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | + MT_QUIRK_NO_AREA, + .sn_move = 2048, + .maxcontacts = 40, + }, { } }; @@ -319,24 +310,16 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, * 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); + td->mt_flags |= INPUT_MT_DIRECT; else if (field->application != HID_DG_TOUCHPAD) return 0; - /* In case of an indirect device (touchpad), we need to add - * specific BTN_TOOL_* to be handled by the synaptics xorg - * driver. - * We also consider that touchscreens providing buttons are touchpads. + /* + * Model touchscreens providing buttons as touchpads. */ if (field->application == HID_DG_TOUCHPAD || - (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON || - cls->is_indirect) { - set_bit(INPUT_PROP_POINTER, hi->input->propbit); - set_bit(BTN_TOOL_FINGER, hi->input->keybit); - set_bit(BTN_TOOL_DOUBLETAP, hi->input->keybit); - set_bit(BTN_TOOL_TRIPLETAP, hi->input->keybit); - set_bit(BTN_TOOL_QUADTAP, hi->input->keybit); - } + (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) + td->mt_flags |= INPUT_MT_POINTER; /* eGalax devices provide a Digitizer.Stylus input which overrides * the correct Digitizers.Finger X/Y ranges. @@ -353,8 +336,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, EV_ABS, ABS_MT_POSITION_X); set_abs(hi->input, ABS_MT_POSITION_X, field, cls->sn_move); - /* touchscreen emulation */ - set_abs(hi->input, ABS_X, field, cls->sn_move); mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; @@ -363,8 +344,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, EV_ABS, ABS_MT_POSITION_Y); set_abs(hi->input, ABS_MT_POSITION_Y, field, cls->sn_move); - /* touchscreen emulation */ - set_abs(hi->input, ABS_Y, field, cls->sn_move); mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; @@ -388,9 +367,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, td->last_field_index = field->index; return 1; case HID_DG_CONTACTID: - if (!td->maxcontacts) - td->maxcontacts = MT_DEFAULT_MAXCONTACT; - input_mt_init_slots(hi->input, td->maxcontacts); mt_store_field(usage, td, hi); td->last_field_index = field->index; td->touches_by_report++; @@ -398,18 +374,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, case HID_DG_WIDTH: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOUCH_MAJOR); - set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, - cls->sn_width); + if (!(cls->quirks & MT_QUIRK_NO_AREA)) + set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, + cls->sn_width); mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; case HID_DG_HEIGHT: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOUCH_MINOR); - set_abs(hi->input, ABS_MT_TOUCH_MINOR, field, - cls->sn_height); - input_set_abs_params(hi->input, + if (!(cls->quirks & MT_QUIRK_NO_AREA)) { + set_abs(hi->input, ABS_MT_TOUCH_MINOR, field, + cls->sn_height); + input_set_abs_params(hi->input, ABS_MT_ORIENTATION, 0, 1, 0, 0); + } mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; @@ -418,9 +397,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, EV_ABS, ABS_MT_PRESSURE); set_abs(hi->input, ABS_MT_PRESSURE, field, cls->sn_pressure); - /* touchscreen emulation */ - set_abs(hi->input, ABS_PRESSURE, field, - cls->sn_pressure); mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; @@ -464,7 +440,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, return -1; } -static int mt_compute_slot(struct mt_device *td) +static int mt_compute_slot(struct mt_device *td, struct input_dev *input) { __s32 quirks = td->mtclass.quirks; @@ -480,42 +456,23 @@ static int mt_compute_slot(struct mt_device *td) if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE) return td->curdata.contactid - 1; - return find_slot_from_contactid(td); + return input_mt_get_slot_by_key(input, td->curdata.contactid); } /* * this function is called when a whole contact has been processed, * so that it can assign it to a slot and store the data there */ -static void mt_complete_slot(struct mt_device *td) +static void mt_complete_slot(struct mt_device *td, struct input_dev *input) { - td->curdata.seen_in_this_frame = true; if (td->curvalid) { - int slotnum = mt_compute_slot(td); - - if (slotnum >= 0 && slotnum < td->maxcontacts) - td->slots[slotnum] = td->curdata; - } - td->num_received++; -} - + int slotnum = mt_compute_slot(td, input); + struct mt_slot *s = &td->curdata; -/* - * this function is called when a whole packet has been received and processed, - * so that it can decide what to send to the input layer. - */ -static void mt_emit_event(struct mt_device *td, struct input_dev *input) -{ - int i; + if (slotnum < 0 || slotnum >= td->maxcontacts) + return; - for (i = 0; i < td->maxcontacts; ++i) { - struct mt_slot *s = &(td->slots[i]); - if ((td->mtclass.quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) && - !s->seen_in_this_frame) { - s->touch_state = false; - } - - input_mt_slot(input, i); + input_mt_slot(input, slotnum); input_mt_report_slot_state(input, MT_TOOL_FINGER, s->touch_state); if (s->touch_state) { @@ -532,24 +489,29 @@ static void mt_emit_event(struct mt_device *td, struct input_dev *input) input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); } - s->seen_in_this_frame = false; - } - input_mt_report_pointer_emulation(input, true); + td->num_received++; +} + +/* + * this function is called when a whole packet has been received and processed, + * so that it can decide what to send to the input layer. + */ +static void mt_sync_frame(struct mt_device *td, struct input_dev *input) +{ + input_mt_sync_frame(input); input_sync(input); td->num_received = 0; } - - static int mt_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { struct mt_device *td = hid_get_drvdata(hid); __s32 quirks = td->mtclass.quirks; - if (hid->claimed & HID_CLAIMED_INPUT && td->slots) { + if (hid->claimed & HID_CLAIMED_INPUT) { switch (usage->hid) { case HID_DG_INRANGE: if (quirks & MT_QUIRK_ALWAYS_VALID) @@ -602,11 +564,11 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, } if (usage->hid == td->last_slot_field) - mt_complete_slot(td); + mt_complete_slot(td, field->hidinput->input); if (field->index == td->last_field_index && td->num_received >= td->num_expected) - mt_emit_event(td, field->hidinput->input); + mt_sync_frame(td, field->hidinput->input); } @@ -685,6 +647,35 @@ static void mt_post_parse(struct mt_device *td) } } +static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + +{ + struct mt_device *td = hid_get_drvdata(hdev); + struct mt_class *cls = &td->mtclass; + struct input_dev *input = hi->input; + + /* Only initialize slots for MT input devices */ + if (!test_bit(ABS_MT_POSITION_X, input->absbit)) + return; + + if (!td->maxcontacts) + td->maxcontacts = MT_DEFAULT_MAXCONTACT; + + mt_post_parse(td); + if (td->serial_maybe) + mt_post_parse_default_settings(td); + + if (cls->is_indirect) + td->mt_flags |= INPUT_MT_POINTER; + + if (cls->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) + td->mt_flags |= INPUT_MT_DROP_UNUSED; + + input_mt_init_slots(input, td->maxcontacts, td->mt_flags); + + td->mt_flags = 0; +} + static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret, i; @@ -722,6 +713,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) goto fail; } + if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID) + td->serial_maybe = true; + ret = hid_parse(hdev); if (ret != 0) goto fail; @@ -730,20 +724,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) |