diff options
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/Kconfig | 3 | ||||
-rw-r--r-- | drivers/hid/hid-3m-pct.c | 36 | ||||
-rw-r--r-- | drivers/hid/hid-core.c | 4 | ||||
-rw-r--r-- | drivers/hid/hid-egalax.c | 131 | ||||
-rw-r--r-- | drivers/hid/hid-ids.h | 5 |
5 files changed, 72 insertions, 107 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index d2a2751..ffbc278 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -164,7 +164,8 @@ config HID_EGALAX tristate "eGalax multi-touch panel" depends on USB_HID ---help--- - Support for the eGalax dual-touch panel. + Support for the eGalax dual-touch panels, including the + Joojoo and Wetab tablets. config HID_ELECOM tristate "ELECOM BM084 bluetooth mouse" diff --git a/drivers/hid/hid-3m-pct.c b/drivers/hid/hid-3m-pct.c index 4546c12..5243ae2 100644 --- a/drivers/hid/hid-3m-pct.c +++ b/drivers/hid/hid-3m-pct.c @@ -19,6 +19,7 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/usb.h> +#include <linux/input/mt.h> MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>"); MODULE_DESCRIPTION("3M PCT multitouch panels"); @@ -27,8 +28,6 @@ MODULE_LICENSE("GPL"); #include "hid-ids.h" #define MAX_SLOTS 60 -#define MAX_TRKID USHRT_MAX -#define MAX_EVENTS 360 /* estimated signal-to-noise ratios */ #define SN_MOVE 2048 @@ -36,14 +35,11 @@ MODULE_LICENSE("GPL"); struct mmm_finger { __s32 x, y, w, h; - __u16 id; - bool prev_touch; bool touch, valid; }; struct mmm_data { struct mmm_finger f[MAX_SLOTS]; - __u16 id; __u8 curid; __u8 nexp, nreal; bool touch, valid; @@ -117,14 +113,7 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi, 0, 1, 0, 0); return 1; case HID_DG_CONTACTID: - field->logical_maximum = MAX_TRKID; - hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_TRACKING_ID); - input_set_abs_params(hi->input, ABS_MT_TRACKING_ID, - 0, MAX_TRKID, 0, 0); - if (!hi->input->mt) - input_mt_create_slots(hi->input, MAX_SLOTS); - input_set_events_per_packet(hi->input, MAX_EVENTS); + input_mt_init_slots(hi->input, MAX_SLOTS); return 1; } /* let hid-input decide for the others */ @@ -154,7 +143,6 @@ static int mmm_input_mapped(struct hid_device *hdev, struct hid_input *hi, */ static void mmm_filter_event(struct mmm_data *md, struct input_dev *input) { - struct mmm_finger *oldest = 0; int i; for (i = 0; i < MAX_SLOTS; ++i) { struct mmm_finger *f = &md->f[i]; @@ -163,6 +151,7 @@ static void mmm_filter_event(struct mmm_data *md, struct input_dev *input) continue; } input_mt_slot(input, i); + input_mt_report_slot_state(input, MT_TOOL_FINGER, f->touch); if (f->touch) { /* this finger is on the screen */ int wide = (f->w > f->h); @@ -170,33 +159,16 @@ static void mmm_filter_event(struct mmm_data *md, struct input_dev *input) int major = max(f->w, f->h) >> 1; int minor = min(f->w, f->h) >> 1; - if (!f->prev_touch) - f->id = md->id++; - input_event(input, EV_ABS, ABS_MT_TRACKING_ID, f->id); input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x); input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y); input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide); input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); - /* touchscreen emulation: pick the oldest contact */ - if (!oldest || ((f->id - oldest->id) & (SHRT_MAX + 1))) - oldest = f; - } else { - /* this finger took off the screen */ - input_event(input, EV_ABS, ABS_MT_TRACKING_ID, -1); } - f->prev_touch = f->touch; f->valid = 0; } - /* touchscreen emulation */ - if (oldest) { - input_event(input, EV_KEY, BTN_TOUCH, 1); - input_event(input, EV_ABS, ABS_X, oldest->x); - input_event(input, EV_ABS, ABS_Y, oldest->y); - } else { - input_event(input, EV_KEY, BTN_TOUCH, 0); - } + input_mt_report_pointer_emulation(input, true); input_sync(input); } diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 04b7eb0..2611686 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1327,6 +1327,9 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) }, { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) }, + { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) }, + { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, { HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) }, { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) }, @@ -1633,6 +1636,7 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_DEALEXTREAME, USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701) }, { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE) }, { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) }, + { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x0004) }, { HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) }, { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) }, { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) }, diff --git a/drivers/hid/hid-egalax.c b/drivers/hid/hid-egalax.c index 72b1dd8..03bee19 100644 --- a/drivers/hid/hid-egalax.c +++ b/drivers/hid/hid-egalax.c @@ -2,6 +2,8 @@ * HID driver for eGalax dual-touch panels * * Copyright (c) 2010 Stephane Chatty <chatty@enac.fr> + * Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se> + * Copyright (c) 2010 Canonical, Ltd. * */ @@ -16,6 +18,7 @@ #include <linux/hid.h> #include <linux/module.h> #include <linux/usb.h> +#include <linux/input/mt.h> #include <linux/slab.h> #include "usbhid/usbhid.h" @@ -25,38 +28,53 @@ MODULE_LICENSE("GPL"); #include "hid-ids.h" +#define MAX_SLOTS 2 + +/* estimated signal-to-noise ratios */ +#define SN_MOVE 4096 +#define SN_PRESSURE 32 + struct egalax_data { - __u16 x, y, z; - __u8 id; - bool first; /* is this the first finger in the frame? */ - bool valid; /* valid finger data, or just placeholder? */ - bool activity; /* at least one active finger previously? */ - __u16 lastx, lasty, lastz; /* latest valid (x, y, z) in the frame */ + int valid; + int slot; + int touch; + int x, y, z; }; +static void set_abs(struct input_dev *input, unsigned int code, + struct hid_field *field, int snratio) +{ + int fmin = field->logical_minimum; + int fmax = field->logical_maximum; + int fuzz = snratio ? (fmax - fmin) / snratio : 0; + input_set_abs_params(input, code, fmin, fmax, fuzz, 0); +} + static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { + struct input_dev *input = hi->input; + switch (usage->hid & HID_USAGE_PAGE) { case HID_UP_GENDESK: switch (usage->hid) { case HID_GD_X: + field->logical_maximum = 32760; hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_POSITION_X); + set_abs(input, ABS_MT_POSITION_X, field, SN_MOVE); /* touchscreen emulation */ - input_set_abs_params(hi->input, ABS_X, - field->logical_minimum, - field->logical_maximum, 0, 0); + set_abs(input, ABS_X, field, SN_MOVE); return 1; case HID_GD_Y: + field->logical_maximum = 32760; hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_POSITION_Y); + set_abs(input, ABS_MT_POSITION_Y, field, SN_MOVE); /* touchscreen emulation */ - input_set_abs_params(hi->input, ABS_Y, - field->logical_minimum, - field->logical_maximum, 0, 0); + set_abs(input, ABS_Y, field, SN_MOVE); return 1; } return 0; @@ -66,6 +84,7 @@ static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi, case HID_DG_TIPSWITCH: /* touchscreen emulation */ hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); + input_set_capability(input, EV_KEY, BTN_TOUCH); return 1; case HID_DG_INRANGE: case HID_DG_CONFIDENCE: @@ -73,16 +92,15 @@ static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi, case HID_DG_CONTACTMAX: return -1; case HID_DG_CONTACTID: - hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_TRACKING_ID); + input_mt_init_slots(input, MAX_SLOTS); return 1; case HID_DG_TIPPRESSURE: + field->logical_minimum = 0; hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_PRESSURE); + set_abs(input, ABS_MT_PRESSURE, field, SN_PRESSURE); /* touchscreen emulation */ - input_set_abs_params(hi->input, ABS_PRESSURE, - field->logical_minimum, - field->logical_maximum, 0, 0); + set_abs(input, ABS_PRESSURE, field, SN_PRESSURE); return 1; } return 0; @@ -96,10 +114,10 @@ static int egalax_input_mapped(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { + /* tell hid-input to skip setup of these event types */ if (usage->type == EV_KEY || usage->type == EV_ABS) - clear_bit(usage->code, *bit); - - return 0; + set_bit(usage->type, hi->input->evbit); + return -1; } /* @@ -108,58 +126,16 @@ static int egalax_input_mapped(struct hid_device *hdev, struct hid_input *hi, */ static void egalax_filter_event(struct egalax_data *td, struct input_dev *input) { - td->first = !td->first; /* touchscreen emulation */ - - if (td->valid) { - /* emit multitouch events */ - input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id); - input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x >> 3); - input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y >> 3); + input_mt_slot(input, td->slot); + input_mt_report_slot_state(input, MT_TOOL_FINGER, td->touch); + if (td->touch) { + input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x); + input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y); input_event(input, EV_ABS, ABS_MT_PRESSURE, td->z); - - input_mt_sync(input); - - /* - * touchscreen emulation: store (x, y) as - * the last valid values in this frame - */ - td->lastx = td->x; - td->lasty = td->y; - td->lastz = td->z; - } - - /* - * touchscreen emulation: if this is the second finger and at least - * one in this frame is valid, the latest valid in the frame is - * the oldest on the panel, the one we want for single touch - */ - if (!td->first && td->activity) { - input_event(input, EV_ABS, ABS_X, td->lastx >> 3); - input_event(input, EV_ABS, ABS_Y, td->lasty >> 3); - input_event(input, EV_ABS, ABS_PRESSURE, td->lastz); - } - - if (!td->valid) { - /* - * touchscreen emulation: if the first finger is invalid - * and there previously was finger activity, this is a release - */ - if (td->first && td->activity) { - input_event(input, EV_KEY, BTN_TOUCH, 0); - td->activity = false; - } - return; - } - - - /* touchscreen emulation: if no previous activity, emit touch event */ - if (!td->activity) { - input_event(input, EV_KEY, BTN_TOUCH, 1); - td->activity = true; } + input_mt_report_pointer_emulation(input, true); } - static int egalax_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { @@ -169,25 +145,26 @@ static int egalax_event(struct hid_device *hid, struct hid_field *field, * uses a standard parallel multitouch protocol (product ID == * 48xx). The second is capacitive and uses an unusual "serial" * protocol with a different message for each multitouch finger - * (product ID == 72xx). We do not yet generate a correct event - * sequence for the capacitive/serial protocol. + * (product ID == 72xx). */ if (hid->claimed & HID_CLAIMED_INPUT) { struct input_dev *input = field->hidinput->input; switch (usage->hid) { case HID_DG_INRANGE: + td->valid = value; + break; case HID_DG_CONFIDENCE: /* avoid interference from generic hidinput handling */ break; case HID_DG_TIPSWITCH: - td->valid = value; + td->touch = value; break; case HID_DG_TIPPRESSURE: td->z = value; break; case HID_DG_CONTACTID: - td->id = value; + td->slot = clamp_val(value, 0, MAX_SLOTS - 1); break; case HID_GD_X: td->x = value; @@ -195,11 +172,11 @@ static int egalax_event(struct hid_device *hid, struct hid_field *field, case HID_GD_Y: td->y = value; /* this is the last field in a finger */ - egalax_filter_event(td, input); + if (td->valid) + egalax_filter_event(td, input); break; case HID_DG_CONTACTCOUNT: /* touch emulation: this is the last field in a frame */ - td->first = false; break; default: @@ -261,6 +238,12 @@ static const struct hid_device_id egalax_devices[] = { USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) }, + { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, + USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, + USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) }, + { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, + USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) }, { } }; MODULE_DEVICE_TABLE(hid, egalax_devices); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index a945d79..f65cace 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -203,10 +203,15 @@ #define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH 0x480d #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1 0x720c +#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2 0x72a1 +#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3 0x480e +#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4 0x726b #define USB_VENDOR_ID_ELECOM 0x056e #define USB_DEVICE_ID_ELECOM_BM084 0x0061 +#define USB_VENDOR_ID_DREAM_CHEEKY 0x1d34 + #define USB_VENDOR_ID_ELO 0x04E7 #define USB_DEVICE_ID_ELO_TS2700 0x0020 |