/*
* HID driver for multitouch panels
*
* Copyright (c) 2010-2012 Stephane Chatty <chatty@enac.fr>
* Copyright (c) 2010-2013 Benjamin Tissoires <benjamin.tissoires@gmail.com>
* Copyright (c) 2010-2012 Ecole Nationale de l'Aviation Civile, France
* Copyright (c) 2012-2013 Red Hat, Inc
*
* This code is partly based on hid-egalax.c:
*
* Copyright (c) 2010 Stephane Chatty <chatty@enac.fr>
* Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se>
* Copyright (c) 2010 Canonical, Ltd.
*
* This code is partly based on hid-3m-pct.c:
*
* Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr>
* Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se>
* Copyright (c) 2010 Canonical, Ltd.
*
*/
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*/
/*
* This driver is regularly tested thanks to the tool hid-test[1].
* This tool relies on hid-replay[2] and a database of hid devices[3].
* Please run these regression tests before patching this module so that
* your patch won't break existing known devices.
*
* [1] https://github.com/bentiss/hid-test
* [2] https://github.com/bentiss/hid-replay
* [3] https://github.com/bentiss/hid-devices
*/
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input/mt.h>
#include <linux/string.h>
MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
MODULE_DESCRIPTION("HID multitouch panels");
MODULE_LICENSE("GPL");
#include "hid-ids.h"
/* quirks to control the device */
#define MT_QUIRK_NOT_SEEN_MEANS_UP (1 << 0)
#define MT_QUIRK_SLOT_IS_CONTACTID (1 << 1)
#define MT_QUIRK_CYPRESS (1 << 2)
#define MT_QUIRK_SLOT_IS_CONTACTNUMBER (1 << 3)
#define MT_QUIRK_ALWAYS_VALID (1 << 4)
#define MT_QUIRK_VALID_IS_INRANGE (1 << 5)
#define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 6)
#define MT_QUIRK_CONFIDENCE (1 << 7)
#define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE (1 << 8)
#define MT_QUIRK_NO_AREA (1 << 9)
#define MT_QUIRK_IGNORE_DUPLICATES (1 << 10)
#define MT_QUIRK_HOVERING (1 << 11)
#define MT_QUIRK_CONTACT_CNT_ACCURATE (1 << 12)
#define MT_QUIRK_FORCE_GET_FEATURE (1 << 13)
#define MT_INPUTMODE_TOUCHSCREEN 0x02
#define MT_INPUTMODE_TOUCHPAD 0x03
#define MT_BUTTONTYPE_CLICKPAD 0
struct mt_slot {
__s32 x, y, cx, cy, p, w, h;
__s32 contactid; /* the device ContactID assigned to this slot */
bool touch_state; /* is the touch valid? */
bool inrange_state; /* is the finger in proximity of the sensor? */
bool confidence_state; /* is the touch made by a finger? */
};
struct mt_class {
__s32 name; /* MT_CLS */
__s32 quirks;
__s32 sn_move; /* Signal/noise ratio for move events */
__s32 sn_width; /* Signal/noise ratio for width events */
__s32 sn_height; /* Signal/noise ratio for height events */
__s32 sn_pressure; /* Signal/noise ratio for pressure events */
__u8 maxcontacts;
bool is_indirect; /* true for touchpads */
bool export_all_inputs; /* do not ignore mouse, keyboards, etc... */
};
struct mt_fields {
unsigned usages[HID_MAX_FIELDS];
unsigned int length;
};
struct mt_device {
struct mt_slot curdata; /* placeholder of incoming data */
struct mt_class mtclass; /* our mt device class */
struct mt_fields *fields; /* temporary placeholder for storing the
multitouch fields */
int cc_index; /* contact count field index in the report */
int cc_value_index; /* contact count value index in the field */
unsigned last_slot_field; /* the last field of a slot */
unsigned mt_report_id; /* the report ID of the multitouch device */
__s16 inputmode; /* InputMode HID feature, -1 if non-existent */
__s16 inputmode_index; /* InputMode HID feature index in the report */
__s16 maxcontact_report_id; /* Maximum Contact Number HID feature,
-1 if non-existent */
__u8 inputmode_value; /* InputMode HID feature value */
__u8 num_received; /* how many contacts we received */
__u8 num_expected; /* expected last contact index */
__u8 maxcontacts;
__u8 touches_by_report; /* how many touches are present in one report:
* 1 means we should use a serial protocol
* > 1 means hybrid (multitouch) protocol */
__u8 buttons_count; /* number of physical buttons per touchpad */
bool is_buttonpad; /* is this device a button pad? */
bool serial_maybe; /* need to check for serial protocol */
bool curvalid; /* is the current contact valid? */
unsigned mt_flags; /* flags to pass to input-mt */
};
static void mt_post_parse_default_settings(struct mt_device *td);
static void mt_post_parse(struct mt_device *td);
/* classes of device behavior */
#define MT_CLS_DEFAULT 0x0001
#define MT_CLS_SERIAL 0x0002
#define MT_CLS_CONFIDENCE 0x0003
#define MT_CLS_CONFIDENCE_CONTACT_ID 0x0004
#define MT_CLS_CONFIDENCE_MINUS_ONE 0x0005
#define MT_CLS_DUAL_INRANGE_CONTACTID 0x0006
#define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 0x0007
/* reserved 0x0008 */
#define MT_CLS_INRANGE_CONTACTNUMBER 0x0009
#define MT_CLS_NSMU 0x000a
/* reserved 0x0010 */
/* reserved 0x0011 */
#define MT_CLS_WIN_8 0x0012
#define MT_CLS_EXPORT_ALL_INPUTS 0x0013
/* vendor specific classes */
#define MT_CLS_3M 0x0101
/* reserved 0x0102 */
#define MT_CLS_EGALAX 0x0103
#define MT_CLS_EGALAX_SERIAL 0x0104
#define MT_CLS_TOPSEED 0x0105
#define MT_CLS_PANASONIC 0x0106
#define MT_CLS_FLATFROG 0x0107
#define MT_CLS_GENERALTOUCH_TWOFINGERS 0x0108
#define MT_CLS_GENERALTOUCH_PWT_TENFINGERS 0x0109
#define MT_CLS_VTL 0x0110
#define MT_DEFAULT_MAXCONTACT 10
#define MT_MAX_MAXCONTACT 250
#define MT_USB_DEVICE(v, p) HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH, v, p)
#define MT_BT_DEVICE(v, p) HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_MULTITOUCH, v, p)
/*
* these device-dependent functions determine what slot corresponds
* to a valid contact that was just read.
*/
static int cypress_compute_slot(struct mt_device *td)
{
if (td->curdata.contactid != 0 || td->num_received == 0)
return td->curdata.contactid;
else
return -1;
}
static struct mt_class mt_classes[] = {
{ .name = MT_CLS_DEFAULT,
.quirks = MT_QUIRK_ALWAYS_VALID |
MT_QUIRK_CONTACT_CNT_ACCURATE },
{ .name = MT_CLS_NSMU,
.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP },
{ .name = MT_CLS_SERIAL,
.quirks = MT_QUIRK_ALWAYS_VALID},
{ .name = MT_CLS_CONFIDENCE,
.quirks = MT_QUIRK_VALID_IS_CONFIDENCE },
{ .name = MT_CLS_CONFIDENCE_CONTACT_ID,
.quirks = MT_QUIRK_VALID_IS_CONFIDENCE |
MT_QUIRK_SLOT_IS_CONTACTID },
{ .name = MT_CLS_CONFIDENCE_MINUS_ONE,
.quirks = MT_QUIRK_VALID_IS_CONFIDENCE |
MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE },
{ .name = MT_CLS_DUAL_INRANGE_CONTACTID,
.quirks = MT_QUIRK_VALID_IS_INRANGE |
MT_QUIRK_SLOT_IS_CONTACTID,
.maxcontacts = 2 },
{ .name = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
.quirks = MT_QUIRK_VALID_IS_INRANGE |
MT_QUIRK_SLOT_IS_CONTACTNUMBER,
.maxcontacts = 2 },
{ .name = MT_CLS_INRANGE_CONTACTNUM
|