linux/drivers/hid/hid-cando.c
<<
>>
Prefs
   1/*
   2 *  HID driver for Cando dual-touch panels
   3 *
   4 *  Copyright (c) 2010 Stephane Chatty <chatty@enac.fr>
   5 *
   6 */
   7
   8/*
   9 * This program is free software; you can redistribute it and/or modify it
  10 * under the terms of the GNU General Public License as published by the Free
  11 * Software Foundation; either version 2 of the License, or (at your option)
  12 * any later version.
  13 */
  14
  15#include <linux/device.h>
  16#include <linux/hid.h>
  17#include <linux/module.h>
  18#include <linux/slab.h>
  19
  20MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
  21MODULE_DESCRIPTION("Cando dual-touch panel");
  22MODULE_LICENSE("GPL");
  23
  24#include "hid-ids.h"
  25
  26struct cando_data {
  27        __u16 x, y;
  28        __u8 id;
  29        __s8 oldest;            /* id of the oldest finger in previous frame */
  30        bool valid;             /* valid finger data, or just placeholder? */
  31        bool first;             /* is this the first finger in this frame? */
  32        __s8 firstid;           /* id of the first finger in the frame */
  33        __u16 firstx, firsty;   /* (x, y) of the first finger in the frame */
  34};
  35
  36static int cando_input_mapping(struct hid_device *hdev, struct hid_input *hi,
  37                struct hid_field *field, struct hid_usage *usage,
  38                unsigned long **bit, int *max)
  39{
  40        switch (usage->hid & HID_USAGE_PAGE) {
  41
  42        case HID_UP_GENDESK:
  43                switch (usage->hid) {
  44                case HID_GD_X:
  45                        hid_map_usage(hi, usage, bit, max,
  46                                        EV_ABS, ABS_MT_POSITION_X);
  47                        /* touchscreen emulation */
  48                        input_set_abs_params(hi->input, ABS_X,
  49                                                field->logical_minimum,
  50                                                field->logical_maximum, 0, 0);
  51                        return 1;
  52                case HID_GD_Y:
  53                        hid_map_usage(hi, usage, bit, max,
  54                                        EV_ABS, ABS_MT_POSITION_Y);
  55                        /* touchscreen emulation */
  56                        input_set_abs_params(hi->input, ABS_Y,
  57                                                field->logical_minimum,
  58                                                field->logical_maximum, 0, 0);
  59                        return 1;
  60                }
  61                return 0;
  62
  63        case HID_UP_DIGITIZER:
  64                switch (usage->hid) {
  65                case HID_DG_TIPSWITCH:
  66                case HID_DG_CONTACTMAX:
  67                        return -1;
  68                case HID_DG_INRANGE:
  69                        /* touchscreen emulation */
  70                        hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
  71                        return 1;
  72                case HID_DG_CONTACTID:
  73                        hid_map_usage(hi, usage, bit, max,
  74                                        EV_ABS, ABS_MT_TRACKING_ID);
  75                        return 1;
  76                }
  77                return 0;
  78        }
  79
  80        return 0;
  81}
  82
  83static int cando_input_mapped(struct hid_device *hdev, struct hid_input *hi,
  84                struct hid_field *field, struct hid_usage *usage,
  85                unsigned long **bit, int *max)
  86{
  87        if (usage->type == EV_KEY || usage->type == EV_ABS)
  88                clear_bit(usage->code, *bit);
  89
  90        return 0;
  91}
  92
  93/*
  94 * this function is called when a whole finger has been parsed,
  95 * so that it can decide what to send to the input layer.
  96 */
  97static void cando_filter_event(struct cando_data *td, struct input_dev *input)
  98{
  99        td->first = !td->first; /* touchscreen emulation */
 100
 101        if (!td->valid) {
 102                /*
 103                 * touchscreen emulation: if this is the second finger and
 104                 * the first was valid, the first was the oldest; if the
 105                 * first was not valid and there was a valid finger in the
 106                 * previous frame, this is a release.
 107                 */
 108                if (td->first) {
 109                        td->firstid = -1;
 110                } else if (td->firstid >= 0) {
 111                        input_event(input, EV_ABS, ABS_X, td->firstx);
 112                        input_event(input, EV_ABS, ABS_Y, td->firsty);
 113                        td->oldest = td->firstid;
 114                } else if (td->oldest >= 0) {
 115                        input_event(input, EV_KEY, BTN_TOUCH, 0);
 116                        td->oldest = -1;
 117                }
 118
 119                return;
 120        }
 121        
 122        input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id);
 123        input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
 124        input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);
 125
 126        input_mt_sync(input);
 127
 128        /*
 129         * touchscreen emulation: if there was no touching finger previously,
 130         * emit touch event
 131         */
 132        if (td->oldest < 0) {
 133                input_event(input, EV_KEY, BTN_TOUCH, 1);
 134                td->oldest = td->id;
 135        }
 136
 137        /*
 138         * touchscreen emulation: if this is the first finger, wait for the
 139         * second; the oldest is then the second if it was the oldest already
 140         * or if there was no first, the first otherwise.
 141         */
 142        if (td->first) {
 143                td->firstx = td->x;
 144                td->firsty = td->y;
 145                td->firstid = td->id;
 146        } else {
 147                int x, y, oldest;
 148                if (td->id == td->oldest || td->firstid < 0) {
 149                        x = td->x;
 150                        y = td->y;
 151                        oldest = td->id;
 152                } else {
 153                        x = td->firstx;
 154                        y = td->firsty;
 155                        oldest = td->firstid;
 156                }
 157                input_event(input, EV_ABS, ABS_X, x);
 158                input_event(input, EV_ABS, ABS_Y, y);
 159                td->oldest = oldest;
 160        }
 161}
 162
 163
 164static int cando_event(struct hid_device *hid, struct hid_field *field,
 165                                struct hid_usage *usage, __s32 value)
 166{
 167        struct cando_data *td = hid_get_drvdata(hid);
 168
 169        if (hid->claimed & HID_CLAIMED_INPUT) {
 170                struct input_dev *input = field->hidinput->input;
 171
 172                switch (usage->hid) {
 173                case HID_DG_INRANGE:
 174                        td->valid = value;
 175                        break;
 176                case HID_DG_CONTACTID:
 177                        td->id = value;
 178                        break;
 179                case HID_GD_X:
 180                        td->x = value;
 181                        break;
 182                case HID_GD_Y:
 183                        td->y = value;
 184                        cando_filter_event(td, input);
 185                        break;
 186                case HID_DG_TIPSWITCH:
 187                        /* avoid interference from generic hidinput handling */
 188                        break;
 189
 190                default:
 191                        /* fallback to the generic hidinput handling */
 192                        return 0;
 193                }
 194        }
 195
 196        /* we have handled the hidinput part, now remains hiddev */
 197        if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
 198                hid->hiddev_hid_event(hid, field, usage, value);
 199
 200        return 1;
 201}
 202
 203static int cando_probe(struct hid_device *hdev, const struct hid_device_id *id)
 204{
 205        int ret;
 206        struct cando_data *td;
 207
 208        td = kmalloc(sizeof(struct cando_data), GFP_KERNEL);
 209        if (!td) {
 210                hid_err(hdev, "cannot allocate Cando Touch data\n");
 211                return -ENOMEM;
 212        }
 213        hid_set_drvdata(hdev, td);
 214        td->first = false;
 215        td->oldest = -1;
 216        td->valid = false;
 217
 218        ret = hid_parse(hdev);
 219        if (!ret)
 220                ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 221
 222        if (ret)
 223                kfree(td);
 224
 225        return ret;
 226}
 227
 228static void cando_remove(struct hid_device *hdev)
 229{
 230        hid_hw_stop(hdev);
 231        kfree(hid_get_drvdata(hdev));
 232        hid_set_drvdata(hdev, NULL);
 233}
 234
 235static const struct hid_device_id cando_devices[] = {
 236        { HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
 237                        USB_DEVICE_ID_CANDO_MULTI_TOUCH) },
 238        { HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
 239                        USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) },
 240        { HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
 241                        USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) },
 242        { HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
 243                USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },
 244        { }
 245};
 246MODULE_DEVICE_TABLE(hid, cando_devices);
 247
 248static const struct hid_usage_id cando_grabbed_usages[] = {
 249        { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
 250        { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
 251};
 252
 253static struct hid_driver cando_driver = {
 254        .name = "cando-touch",
 255        .id_table = cando_devices,
 256        .probe = cando_probe,
 257        .remove = cando_remove,
 258        .input_mapping = cando_input_mapping,
 259        .input_mapped = cando_input_mapped,
 260        .usage_table = cando_grabbed_usages,
 261        .event = cando_event,
 262};
 263
 264static int __init cando_init(void)
 265{
 266        return hid_register_driver(&cando_driver);
 267}
 268
 269static void __exit cando_exit(void)
 270{
 271        hid_unregister_driver(&cando_driver);
 272}
 273
 274module_init(cando_init);
 275module_exit(cando_exit);
 276
 277