Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.39-rc1 296 lines 7.4 kB view raw
1/* 2 * HID driver for the multitouch panel on the ASUS EeePC T91MT 3 * 4 * Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr> 5 * Copyright (c) 2010 Teemu Tuominen <teemu.tuominen@cybercom.com> 6 * 7 */ 8 9/* 10 * This program is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License as published by the Free 12 * Software Foundation; either version 2 of the License, or (at your option) 13 * any later version. 14 */ 15 16#include <linux/device.h> 17#include <linux/hid.h> 18#include <linux/module.h> 19#include <linux/slab.h> 20#include <linux/usb.h> 21#include "usbhid/usbhid.h" 22 23MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>"); 24MODULE_DESCRIPTION("MosArt dual-touch panel"); 25MODULE_LICENSE("GPL"); 26 27#include "hid-ids.h" 28 29struct mosart_data { 30 __u16 x, y; 31 __u8 id; 32 bool valid; /* valid finger data, or just placeholder? */ 33 bool first; /* is this the first finger in this frame? */ 34 bool activity_now; /* at least one active finger in this frame? */ 35 bool activity; /* at least one active finger previously? */ 36}; 37 38static int mosart_input_mapping(struct hid_device *hdev, struct hid_input *hi, 39 struct hid_field *field, struct hid_usage *usage, 40 unsigned long **bit, int *max) 41{ 42 switch (usage->hid & HID_USAGE_PAGE) { 43 44 case HID_UP_GENDESK: 45 switch (usage->hid) { 46 case HID_GD_X: 47 hid_map_usage(hi, usage, bit, max, 48 EV_ABS, ABS_MT_POSITION_X); 49 /* touchscreen emulation */ 50 input_set_abs_params(hi->input, ABS_X, 51 field->logical_minimum, 52 field->logical_maximum, 0, 0); 53 return 1; 54 case HID_GD_Y: 55 hid_map_usage(hi, usage, bit, max, 56 EV_ABS, ABS_MT_POSITION_Y); 57 /* touchscreen emulation */ 58 input_set_abs_params(hi->input, ABS_Y, 59 field->logical_minimum, 60 field->logical_maximum, 0, 0); 61 return 1; 62 } 63 return 0; 64 65 case HID_UP_DIGITIZER: 66 switch (usage->hid) { 67 case HID_DG_CONFIDENCE: 68 case HID_DG_TIPSWITCH: 69 case HID_DG_INPUTMODE: 70 case HID_DG_DEVICEINDEX: 71 case HID_DG_CONTACTCOUNT: 72 case HID_DG_CONTACTMAX: 73 case HID_DG_TIPPRESSURE: 74 case HID_DG_WIDTH: 75 case HID_DG_HEIGHT: 76 return -1; 77 case HID_DG_INRANGE: 78 /* touchscreen emulation */ 79 hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); 80 return 1; 81 82 case HID_DG_CONTACTID: 83 hid_map_usage(hi, usage, bit, max, 84 EV_ABS, ABS_MT_TRACKING_ID); 85 return 1; 86 87 } 88 return 0; 89 90 case 0xff000000: 91 /* ignore HID features */ 92 return -1; 93 94 case HID_UP_BUTTON: 95 /* ignore buttons */ 96 return -1; 97 } 98 99 return 0; 100} 101 102static int mosart_input_mapped(struct hid_device *hdev, struct hid_input *hi, 103 struct hid_field *field, struct hid_usage *usage, 104 unsigned long **bit, int *max) 105{ 106 if (usage->type == EV_KEY || usage->type == EV_ABS) 107 clear_bit(usage->code, *bit); 108 109 return 0; 110} 111 112/* 113 * this function is called when a whole finger has been parsed, 114 * so that it can decide what to send to the input layer. 115 */ 116static void mosart_filter_event(struct mosart_data *td, struct input_dev *input) 117{ 118 td->first = !td->first; /* touchscreen emulation */ 119 120 if (!td->valid) { 121 /* 122 * touchscreen emulation: if no finger in this frame is valid 123 * and there previously was finger activity, this is a release 124 */ 125 if (!td->first && !td->activity_now && td->activity) { 126 input_event(input, EV_KEY, BTN_TOUCH, 0); 127 td->activity = false; 128 } 129 return; 130 } 131 132 input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id); 133 input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x); 134 input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y); 135 136 input_mt_sync(input); 137 td->valid = false; 138 139 /* touchscreen emulation: if first active finger in this frame... */ 140 if (!td->activity_now) { 141 /* if there was no previous activity, emit touch event */ 142 if (!td->activity) { 143 input_event(input, EV_KEY, BTN_TOUCH, 1); 144 td->activity = true; 145 } 146 td->activity_now = true; 147 /* and in any case this is our preferred finger */ 148 input_event(input, EV_ABS, ABS_X, td->x); 149 input_event(input, EV_ABS, ABS_Y, td->y); 150 } 151} 152 153 154static int mosart_event(struct hid_device *hid, struct hid_field *field, 155 struct hid_usage *usage, __s32 value) 156{ 157 struct mosart_data *td = hid_get_drvdata(hid); 158 159 if (hid->claimed & HID_CLAIMED_INPUT) { 160 struct input_dev *input = field->hidinput->input; 161 switch (usage->hid) { 162 case HID_DG_INRANGE: 163 td->valid = !!value; 164 break; 165 case HID_GD_X: 166 td->x = value; 167 break; 168 case HID_GD_Y: 169 td->y = value; 170 mosart_filter_event(td, input); 171 break; 172 case HID_DG_CONTACTID: 173 td->id = value; 174 break; 175 case HID_DG_CONTACTCOUNT: 176 /* touch emulation: this is the last field in a frame */ 177 td->first = false; 178 td->activity_now = false; 179 break; 180 case HID_DG_CONFIDENCE: 181 case HID_DG_TIPSWITCH: 182 /* avoid interference from generic hidinput handling */ 183 break; 184 185 default: 186 /* fallback to the generic hidinput handling */ 187 return 0; 188 } 189 } 190 191 /* we have handled the hidinput part, now remains hiddev */ 192 if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) 193 hid->hiddev_hid_event(hid, field, usage, value); 194 195 return 1; 196} 197 198static int mosart_probe(struct hid_device *hdev, const struct hid_device_id *id) 199{ 200 int ret; 201 struct mosart_data *td; 202 203 204 td = kmalloc(sizeof(struct mosart_data), GFP_KERNEL); 205 if (!td) { 206 hid_err(hdev, "cannot allocate MosArt data\n"); 207 return -ENOMEM; 208 } 209 td->valid = false; 210 td->activity = false; 211 td->activity_now = false; 212 td->first = false; 213 hid_set_drvdata(hdev, td); 214 215 /* currently, it's better to have one evdev device only */ 216#if 0 217 hdev->quirks |= HID_QUIRK_MULTI_INPUT; 218#endif 219 220 ret = hid_parse(hdev); 221 if (ret == 0) 222 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 223 224 if (ret == 0) { 225 struct hid_report_enum *re = hdev->report_enum 226 + HID_FEATURE_REPORT; 227 struct hid_report *r = re->report_id_hash[7]; 228 229 r->field[0]->value[0] = 0x02; 230 usbhid_submit_report(hdev, r, USB_DIR_OUT); 231 } else 232 kfree(td); 233 234 return ret; 235} 236 237#ifdef CONFIG_PM 238static int mosart_reset_resume(struct hid_device *hdev) 239{ 240 struct hid_report_enum *re = hdev->report_enum 241 + HID_FEATURE_REPORT; 242 struct hid_report *r = re->report_id_hash[7]; 243 244 r->field[0]->value[0] = 0x02; 245 usbhid_submit_report(hdev, r, USB_DIR_OUT); 246 return 0; 247} 248#endif 249 250static void mosart_remove(struct hid_device *hdev) 251{ 252 hid_hw_stop(hdev); 253 kfree(hid_get_drvdata(hdev)); 254 hid_set_drvdata(hdev, NULL); 255} 256 257static const struct hid_device_id mosart_devices[] = { 258 { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT) }, 259 { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) }, 260 { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) }, 261 { } 262}; 263MODULE_DEVICE_TABLE(hid, mosart_devices); 264 265static const struct hid_usage_id mosart_grabbed_usages[] = { 266 { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, 267 { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} 268}; 269 270static struct hid_driver mosart_driver = { 271 .name = "mosart", 272 .id_table = mosart_devices, 273 .probe = mosart_probe, 274 .remove = mosart_remove, 275 .input_mapping = mosart_input_mapping, 276 .input_mapped = mosart_input_mapped, 277 .usage_table = mosart_grabbed_usages, 278 .event = mosart_event, 279#ifdef CONFIG_PM 280 .reset_resume = mosart_reset_resume, 281#endif 282}; 283 284static int __init mosart_init(void) 285{ 286 return hid_register_driver(&mosart_driver); 287} 288 289static void __exit mosart_exit(void) 290{ 291 hid_unregister_driver(&mosart_driver); 292} 293 294module_init(mosart_init); 295module_exit(mosart_exit); 296