linux/drivers/hid/hid-ntrig.c
<<
>>
Prefs
   1/*
   2 *  HID driver for N-Trig touchscreens
   3 *
   4 *  Copyright (c) 2008 Rafi Rubin
   5 *  Copyright (c) 2009 Stephane Chatty
   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
  20#include "hid-ids.h"
  21
  22#define NTRIG_DUPLICATE_USAGES  0x001
  23
  24#define nt_map_key_clear(c)     hid_map_usage_clear(hi, usage, bit, max, \
  25                                        EV_KEY, (c))
  26
  27struct ntrig_data {
  28        __s32 x, y, id, w, h;
  29        char reading_a_point, found_contact_id;
  30        char pen_active;
  31        char finger_active;
  32        char inverted;
  33};
  34
  35/*
  36 * this driver is aimed at two firmware versions in circulation:
  37 *  - dual pen/finger single touch
  38 *  - finger multitouch, pen not working
  39 */
  40
  41static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi,
  42                struct hid_field *field, struct hid_usage *usage,
  43                unsigned long **bit, int *max)
  44{
  45        switch (usage->hid & HID_USAGE_PAGE) {
  46
  47        case HID_UP_GENDESK:
  48                switch (usage->hid) {
  49                case HID_GD_X:
  50                        hid_map_usage(hi, usage, bit, max,
  51                                        EV_ABS, ABS_MT_POSITION_X);
  52                        input_set_abs_params(hi->input, ABS_X,
  53                                        field->logical_minimum,
  54                                        field->logical_maximum, 0, 0);
  55                        return 1;
  56                case HID_GD_Y:
  57                        hid_map_usage(hi, usage, bit, max,
  58                                        EV_ABS, ABS_MT_POSITION_Y);
  59                        input_set_abs_params(hi->input, ABS_Y,
  60                                        field->logical_minimum,
  61                                        field->logical_maximum, 0, 0);
  62                        return 1;
  63                }
  64                return 0;
  65
  66        case HID_UP_DIGITIZER:
  67                switch (usage->hid) {
  68                /* we do not want to map these for now */
  69                case HID_DG_CONTACTID: /* value is useless */
  70                case HID_DG_INPUTMODE:
  71                case HID_DG_DEVICEINDEX:
  72                case HID_DG_CONTACTCOUNT:
  73                case HID_DG_CONTACTMAX:
  74                        return -1;
  75
  76                /* original mapping by Rafi Rubin */
  77                case HID_DG_CONFIDENCE:
  78                        nt_map_key_clear(BTN_TOOL_DOUBLETAP);
  79                        return 1;
  80
  81                /* width/height mapped on TouchMajor/TouchMinor/Orientation */
  82                case HID_DG_WIDTH:
  83                        hid_map_usage(hi, usage, bit, max,
  84                                        EV_ABS, ABS_MT_TOUCH_MAJOR);
  85                        return 1;
  86                case HID_DG_HEIGHT:
  87                        hid_map_usage(hi, usage, bit, max,
  88                                        EV_ABS, ABS_MT_TOUCH_MINOR);
  89                        input_set_abs_params(hi->input, ABS_MT_ORIENTATION,
  90                                        0, 1, 0, 0);
  91                        return 1;
  92                }
  93                return 0;
  94
  95        case 0xff000000:
  96                /* we do not want to map these: no input-oriented meaning */
  97                return -1;
  98        }
  99
 100        return 0;
 101}
 102
 103static int ntrig_input_mapped(struct hid_device *hdev, struct hid_input *hi,
 104                struct hid_field *field, struct hid_usage *usage,
 105                unsigned long **bit, int *max)
 106{
 107        if (usage->type == EV_KEY || usage->type == EV_REL
 108                        || usage->type == EV_ABS)
 109                clear_bit(usage->code, *bit);
 110
 111        return 0;
 112}
 113
 114/*
 115 * this function is called upon all reports
 116 * so that we can filter contact point information,
 117 * decide whether we are in multi or single touch mode
 118 * and call input_mt_sync after each point if necessary
 119 */
 120static int ntrig_event (struct hid_device *hid, struct hid_field *field,
 121                                        struct hid_usage *usage, __s32 value)
 122{
 123        struct input_dev *input = field->hidinput->input;
 124        struct ntrig_data *nd = hid_get_drvdata(hid);
 125
 126        if (hid->claimed & HID_CLAIMED_INPUT) {
 127                switch (usage->hid) {
 128
 129                case HID_DG_INRANGE:
 130                        if (field->application & 0x3)
 131                                nd->pen_active = (value != 0);
 132                        else
 133                                nd->finger_active = (value != 0);
 134                        return 0;
 135
 136                case HID_DG_INVERT:
 137                        nd->inverted = value;
 138                        return 0;
 139
 140                case HID_GD_X:
 141                        nd->x = value;
 142                        nd->reading_a_point = 1;
 143                        break;
 144                case HID_GD_Y:
 145                        nd->y = value;
 146                        break;
 147                case HID_DG_CONTACTID:
 148                        nd->id = value;
 149                        /* we receive this only when in multitouch mode */
 150                        nd->found_contact_id = 1;
 151                        break;
 152                case HID_DG_WIDTH:
 153                        nd->w = value;
 154                        break;
 155                case HID_DG_HEIGHT:
 156                        nd->h = value;
 157                        /*
 158                         * when in single touch mode, this is the last
 159                         * report received in a finger event. We want
 160                         * to emit a normal (X, Y) position
 161                         */
 162                        if (!nd->found_contact_id) {
 163                                if (nd->pen_active && nd->finger_active) {
 164                                        input_report_key(input, BTN_TOOL_DOUBLETAP, 0);
 165                                        input_report_key(input, BTN_TOOL_DOUBLETAP, 1);
 166                                }
 167                                input_event(input, EV_ABS, ABS_X, nd->x);
 168                                input_event(input, EV_ABS, ABS_Y, nd->y);
 169                        }
 170                        break;
 171                case HID_DG_TIPPRESSURE:
 172                        /*
 173                         * when in single touch mode, this is the last
 174                         * report received in a pen event. We want
 175                         * to emit a normal (X, Y) position
 176                         */
 177                        if (! nd->found_contact_id) {
 178                                if (nd->pen_active && nd->finger_active) {
 179                                        input_report_key(input,
 180                                                        nd->inverted ? BTN_TOOL_RUBBER : BTN_TOOL_PEN
 181                                                        , 0);
 182                                        input_report_key(input,
 183                                                        nd->inverted ? BTN_TOOL_RUBBER : BTN_TOOL_PEN
 184                                                        , 1);
 185                                }
 186                                input_event(input, EV_ABS, ABS_X, nd->x);
 187                                input_event(input, EV_ABS, ABS_Y, nd->y);
 188                                input_event(input, EV_ABS, ABS_PRESSURE, value);
 189                        }
 190                        break;
 191                case 0xff000002:
 192                        /*
 193                         * we receive this when the device is in multitouch
 194                         * mode. The first of the three values tagged with
 195                         * this usage tells if the contact point is real
 196                         * or a placeholder
 197                         */
 198                        if (!nd->reading_a_point || value != 1)
 199                                break;
 200                        /* emit a normal (X, Y) for the first point only */
 201                        if (nd->id == 0) {
 202                                input_event(input, EV_ABS, ABS_X, nd->x);
 203                                input_event(input, EV_ABS, ABS_Y, nd->y);
 204                        }
 205                        input_event(input, EV_ABS, ABS_MT_POSITION_X, nd->x);
 206                        input_event(input, EV_ABS, ABS_MT_POSITION_Y, nd->y);
 207                        if (nd->w > nd->h) {
 208                                input_event(input, EV_ABS,
 209                                                ABS_MT_ORIENTATION, 1);
 210                                input_event(input, EV_ABS,
 211                                                ABS_MT_TOUCH_MAJOR, nd->w);
 212                                input_event(input, EV_ABS,
 213                                                ABS_MT_TOUCH_MINOR, nd->h);
 214                        } else {
 215                                input_event(input, EV_ABS,
 216                                                ABS_MT_ORIENTATION, 0);
 217                                input_event(input, EV_ABS,
 218                                                ABS_MT_TOUCH_MAJOR, nd->h);
 219                                input_event(input, EV_ABS,
 220                                                ABS_MT_TOUCH_MINOR, nd->w);
 221                        }
 222                        input_mt_sync(field->hidinput->input);
 223                        nd->reading_a_point = 0;
 224                        nd->found_contact_id = 0;
 225                        break;
 226
 227                default:
 228                        /* fallback to the generic hidinput handling */
 229                        return 0;
 230                }
 231        }
 232
 233        /* we have handled the hidinput part, now remains hiddev */
 234        if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
 235                hid->hiddev_hid_event(hid, field, usage, value);
 236
 237        return 1;
 238}
 239
 240static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
 241{
 242        int ret;
 243        struct ntrig_data *nd;
 244
 245        nd = kmalloc(sizeof(struct ntrig_data), GFP_KERNEL);
 246        if (!nd) {
 247                dev_err(&hdev->dev, "cannot allocate N-Trig data\n");
 248                return -ENOMEM;
 249        }
 250        nd->reading_a_point = 0;
 251        nd->found_contact_id = 0;
 252        hid_set_drvdata(hdev, nd);
 253
 254        ret = hid_parse(hdev);
 255        if (!ret)
 256                ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 257
 258        if (ret)
 259                kfree (nd);
 260
 261        return ret;
 262}
 263
 264static void ntrig_remove(struct hid_device *hdev)
 265{
 266        hid_hw_stop(hdev);
 267        kfree(hid_get_drvdata(hdev));
 268}
 269
 270static const struct hid_device_id ntrig_devices[] = {
 271        { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN),
 272                .driver_data = NTRIG_DUPLICATE_USAGES },
 273        { }
 274};
 275MODULE_DEVICE_TABLE(hid, ntrig_devices);
 276
 277static const struct hid_usage_id ntrig_grabbed_usages[] = {
 278        { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
 279        { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
 280};
 281
 282static struct hid_driver ntrig_driver = {
 283        .name = "ntrig",
 284        .id_table = ntrig_devices,
 285        .probe = ntrig_probe,
 286        .remove = ntrig_remove,
 287        .input_mapping = ntrig_input_mapping,
 288        .input_mapped = ntrig_input_mapped,
 289        .usage_table = ntrig_grabbed_usages,
 290        .event = ntrig_event,
 291};
 292
 293static int __init ntrig_init(void)
 294{
 295        return hid_register_driver(&ntrig_driver);
 296}
 297
 298static void __exit ntrig_exit(void)
 299{
 300        hid_unregister_driver(&ntrig_driver);
 301}
 302
 303module_init(ntrig_init);
 304module_exit(ntrig_exit);
 305MODULE_LICENSE("GPL");
 306
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.