From 98613761026a3476b2de7081d75ea696aa761c8a Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Fri, 24 Sep 2010 14:32:26 +0200 Subject: This driver works for the joojoo, but not the other dwav devices. Signed-off-by: Henrik Rydberg --- usr/src/dkms_source_tree/hid-egalax.c | 200 ++++++++++++++++++++-------------- 1 file changed, 119 insertions(+), 81 deletions(-) (limited to 'usr/src/dkms_source_tree/hid-egalax.c') diff --git a/usr/src/dkms_source_tree/hid-egalax.c b/usr/src/dkms_source_tree/hid-egalax.c index 61e6a80..db4fbc9 100644 --- a/usr/src/dkms_source_tree/hid-egalax.c +++ b/usr/src/dkms_source_tree/hid-egalax.c @@ -27,38 +27,62 @@ MODULE_LICENSE("GPL"); void usbhid_submit_report (struct hid_device *hid, struct hid_report *report, unsigned char dir); +#define MAX_SLOTS 2 +#define MAX_TRKID USHRT_MAX +#define MAX_EVENTS 360 + +/* estimated signal-to-noise ratios */ +#define SN_MOVE 1024 +#define SN_PRESSURE 32 + +struct egalax_contact { + int id; + int x, y, z; +}; + 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; /* latest valid (x, y) in the frame */ + struct egalax_contact contact[MAX_SLOTS]; + int valid; + int x, y, z; + int slot, prev_slot; + int mask; + int trkid; + int reported; }; 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) { + int f1 = field->logical_minimum; + int f2 = field->logical_maximum; + int df = f2 - f1; + switch (usage->hid & HID_USAGE_PAGE) { case HID_UP_GENDESK: switch (usage->hid) { case HID_GD_X: + f1 = 0; + f2 = 32768; + df = f2 - f1; hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_POSITION_X); - /* touchscreen emulation */ + input_set_abs_params(hi->input, ABS_MT_POSITION_X, + f1, f2, df / SN_MOVE, 0); input_set_abs_params(hi->input, ABS_X, - field->logical_minimum, - field->logical_maximum, 0, 0); + f1, f2, df / SN_MOVE, 0); return 1; case HID_GD_Y: + f1 = 0; + f2 = 32768; + df = f2 - f1; hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_POSITION_Y); - /* touchscreen emulation */ + input_set_abs_params(hi->input, ABS_MT_POSITION_Y, + f1, f2, df / SN_MOVE, 0); input_set_abs_params(hi->input, ABS_Y, - field->logical_minimum, - field->logical_maximum, 0, 0); + f1, f2, df / SN_MOVE, 0); return 1; } return 0; @@ -68,6 +92,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(hi->input, EV_KEY, BTN_TOUCH); return 1; case HID_DG_INRANGE: case HID_DG_CONFIDENCE: @@ -75,12 +100,22 @@ static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi, case HID_DG_CONTACTMAX: 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); return 1; case HID_DG_TIPPRESSURE: hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_PRESSURE); + EV_ABS, ABS_PRESSURE); + input_set_abs_params(hi->input, ABS_MT_PRESSURE, + f1, f2, df / SN_PRESSURE, 0); + input_set_abs_params(hi->input, ABS_PRESSURE, + f1, f2, df / SN_PRESSURE, 0); return 1; } return 0; @@ -94,67 +129,60 @@ 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; } -/* - * this function is called when a whole finger has been parsed, - * so that it can decide what to send to the input layer. - */ -static void egalax_filter_event(struct egalax_data *td, struct input_dev *input) +static void report_frame(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); - 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; - } - - /* - * 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); - input_event(input, EV_ABS, ABS_Y, td->lasty); - } - - 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; + struct egalax_contact *f = &td->contact[td->slot]; + struct egalax_contact *oldest = 0; + int i; + + if (!td->valid) + f->id = -1; + else if (f->id < 0) + f->id = td->trkid++ & MAX_TRKID; + f->x = td->x; + f->y = td->y; + f->z = td->z; + + td->mask = 0; + if (td->prev_slot != td->slot) { + td->prev_slot = td->slot; + if (td->reported) { + td->reported = 0; + return; } - return; + } + td->reported = 1; + + for (i = 0; i < MAX_SLOTS; i++) { + f = &td->contact[i]; + input_mt_slot(input, i); + input_event(input, EV_ABS, ABS_MT_TRACKING_ID, f->id); + if (f->id < 0) + continue; + 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_PRESSURE, f->z); + if (!oldest) + oldest = f; } - - /* touchscreen emulation: if no previous activity, emit touch event */ - if (!td->activity) { + if (oldest) { input_event(input, EV_KEY, BTN_TOUCH, 1); - td->activity = true; + input_event(input, EV_ABS, ABS_X, oldest->x); + input_event(input, EV_ABS, ABS_Y, oldest->y); + input_event(input, EV_ABS, ABS_PRESSURE, oldest->z); + } else { + input_event(input, EV_KEY, BTN_TOUCH, 0); } -} + input_sync(input); +} static int egalax_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) @@ -171,37 +199,44 @@ static int egalax_event(struct hid_device *hid, struct hid_field *field, if (hid->claimed & HID_CLAIMED_INPUT) { struct input_dev *input = field->hidinput->input; + //printk(KERN_INFO "CHECK: %08x %d", usage->hid, value); + //return 1; + switch (usage->hid) { case HID_DG_INRANGE: case HID_DG_CONFIDENCE: - /* avoid interference from generic hidinput handling */ + case HID_DG_CONTACTCOUNT: break; + case HID_DG_TIPSWITCH: td->valid = value; + td->mask |= 0x01; 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); + td->mask |= 0x02; break; case HID_GD_X: - td->x = value; + td->x = 32768 - value; + td->mask |= 0x04; break; case HID_GD_Y: - td->y = value; - /* this is the last field in a finger */ - egalax_filter_event(td, input); + td->y = 32768 - value; + td->mask |= 0x08; break; - case HID_DG_CONTACTCOUNT: - /* touch emulation: this is the last field in a frame */ - td->first = false; + case HID_DG_TIPPRESSURE: + td->z = value; + td->mask |= 0x10; break; default: /* fallback to the generic hidinput handling */ return 0; } + + if (td->mask == 0x1f) + report_frame(td, input); } /* we have handled the hidinput part, now remains hiddev */ @@ -216,12 +251,17 @@ static int egalax_probe(struct hid_device *hdev, const struct hid_device_id *id) int ret; struct egalax_data *td; struct hid_report *report; + int i; - td = kmalloc(sizeof(struct egalax_data), GFP_KERNEL); + hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC; + + td = kzalloc(sizeof(struct egalax_data), GFP_KERNEL); if (!td) { dev_err(&hdev->dev, "cannot allocate eGalax data\n"); return -ENOMEM; } + for (i = 0; i < MAX_SLOTS; i++) + td->contact[i].id = -1; hid_set_drvdata(hdev, td); ret = hid_parse(hdev); @@ -232,7 +272,7 @@ static int egalax_probe(struct hid_device *hdev, const struct hid_device_id *id) if (ret) goto end; - report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[5]; + report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[5]; if (report) { report->field[0]->value[0] = 2; usbhid_submit_report(hdev, report, USB_DIR_OUT); @@ -253,8 +293,6 @@ static void egalax_remove(struct hid_device *hdev) } static const struct hid_device_id egalax_devices[] = { - { 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) }, { } @@ -267,7 +305,7 @@ static const struct hid_usage_id egalax_grabbed_usages[] = { }; static struct hid_driver egalax_driver = { - .name = "egalax-touch", + .name = "egalax-joojoo", .id_table = egalax_devices, .probe = egalax_probe, .remove = egalax_remove, -- cgit v1.2.3