usb: wacom touchscreen support

This commit is contained in:
Alexander Boettcher 2014-12-02 16:04:47 +01:00 committed by Christian Helmuth
parent 6344ab94b2
commit a59cf9f557
14 changed files with 337 additions and 42 deletions

View File

@ -35,6 +35,20 @@ Note: It has been observed that certain 1.0 versions of Qemu do not generate
mouse interrupts. The mouse driver should work correctly on Qemu 1.0.93 and
above.
HID - Touchscreen support
~~~~~~~~~~~~~~~~~~~~~~~~~
Touchscreen absolute coordinates must be calibrated (e.g. re-calculated) to
screen absolute coordinates. The screen resolution is not determined
automatically by the USB driver, but can be configured as sub node of the
hid xml tag:
!...
!<hid>
! <screen x="1024" y="768"/>
!<hid/>
!...
Storage
~~~~~~~

View File

@ -37,6 +37,9 @@ CC_CXX_OPT = -fpermissive
MOD_SUFFIX =
CC_OPT += -DMOD_SUFFIX=$(MOD_SUFFIX)
# common lib
SRC_C += lib/int_sqrt.c
# USB core
SRC_C += $(addprefix usb/core/,$(notdir $(wildcard $(USB_DIR)/core/*.c)))
SRC_C += usb/usb-common.c
@ -46,8 +49,10 @@ SRC_C += $(addprefix usb/host/, ehci-hcd.c)
# USB hid
SRC_C += $(addprefix hid/usbhid/, hid-core.c hid-quirks.c)
SRC_C += $(addprefix hid/, hid-core.c hid-generic.c hid-input.c hid-cherry.c hid-multitouch.c)
SRC_C += $(addprefix hid/, hid-core.c hid-generic.c hid-input.c \
hid-cherry.c hid-multitouch.c)
SRC_C += $(addprefix input/, evdev.c input.c input-mt.c)
SRC_C += $(addprefix input/, tablet/wacom_sys.c tablet/wacom_wac.c)
# USB storage
SRC_C += $(addprefix usb/storage/,scsiglue.c protocol.c transport.c usb.c \
@ -105,5 +110,6 @@ vpath %.cc $(LIB_DIR)/input
vpath %.cc $(LIB_DIR)/storage
vpath %.c $(LIB_DIR)/storage
vpath %.cc $(LIB_DIR)/nic
vpath lib/int_sqrt.c $(LX_CONTRIB_DIR)
# vi: set ft=make :

View File

@ -0,0 +1,181 @@
From aa61126013bd3f9bb41e5256e4246bc0c5bf348d Mon Sep 17 00:00:00 2001
From: Jason Gerecke <killertofu@gmail.com>
Date: Tue, 6 May 2014 17:14:59 -0700
Subject: [PATCH] Add support for 056a:5002 (Fujitsu T904)
The 5002 appears to use a standard multitouch packet type, but the
pen packet has a new report ID.
Signed-off-by: Jason Gerecke <killertofu@gmail.com>
---
drivers/input/tablet/wacom_sys.c | 19 +++++++++++++++++++
drivers/input/tablet/wacom_wac.c | 12 +++++++++++-
drivers/input/tablet/wacom_wac.h | 3 +++
3 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index b16ebef..0056a6d 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -364,6 +364,7 @@ static int wacom_parse_hid(struct usb_interface *intf,
break;
case MTTPC:
+ case MTTPC_B:
features->pktlen = WACOM_PKGLEN_MTTPC;
break;
@@ -395,6 +396,16 @@ static int wacom_parse_hid(struct usb_interface *intf,
i += 12;
break;
+ case MTTPC_B:
+ features->x_max =
+ get_unaligned_le16(&report[i + 3]);
+ features->x_phy =
+ get_unaligned_le16(&report[i + 6]);
+ features->unit = report[i - 5];
+ features->unitExpo = report[i - 3];
+ i += 9;
+ break;
+
default:
features->x_max =
get_unaligned_le16(&report[i + 3]);
@@ -447,6 +458,14 @@ static int wacom_parse_hid(struct usb_interface *intf,
i += 12;
break;
+ case MTTPC_B:
+ features->y_max =
+ get_unaligned_le16(&report[i + 3]);
+ features->y_phy =
+ get_unaligned_le16(&report[i + 6]);
+ i += 9;
+ break;
+
default:
features->y_max =
features->x_max;
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 05f371d..9330e17 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -966,7 +966,7 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
int x_offset = 0;
/* MTTPC does not support Height and Width */
- if (wacom->features.type == MTTPC)
+ if (wacom->features.type == MTTPC || wacom->features.type == MTTPC_B)
x_offset = -4;
/*
@@ -1119,6 +1119,9 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
case WACOM_PKGLEN_TPC2FG:
return wacom_tpc_mt_touch(wacom);
+ case WACOM_PKGLEN_PENABLED:
+ return wacom_tpc_pen(wacom);
+
default:
switch (data[0]) {
case WACOM_REPORT_TPC1FG:
@@ -1128,6 +1131,7 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
return wacom_tpc_single_touch(wacom, len);
case WACOM_REPORT_TPCMT:
+ case WACOM_REPORT_TPCMT2:
return wacom_mt_touch(wacom);
case WACOM_REPORT_PENABLED:
@@ -1470,6 +1474,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
case TABLETPC2FG:
case MTSCREEN:
case MTTPC:
+ case MTTPC_B:
sync = wacom_tpc_irq(wacom_wac, len);
break;
@@ -1811,6 +1816,7 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
case MTSCREEN:
case MTTPC:
+ case MTTPC_B:
case TABLETPC2FG:
if (features->device_type == BTN_TOOL_FINGER) {
unsigned int flags = INPUT_MT_DIRECT;
@@ -2245,6 +2251,9 @@ static const struct wacom_features wacom_features_0x10F =
static const struct wacom_features wacom_features_0x4001 =
{ "Wacom ISDv4 4001", WACOM_PKGLEN_MTTPC, 26202, 16325, 255,
0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x5002 =
+ { "Wacom ISDv4 5002", WACOM_PKGLEN_MTTPC, 29576, 16724, 1023,
+ 0, MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x47 =
{ "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023,
31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -2466,6 +2475,7 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_DETAILED(0x315, USB_CLASS_HID, 0, 0) },
{ USB_DEVICE_DETAILED(0x317, USB_CLASS_HID, 0, 0) },
{ USB_DEVICE_WACOM(0x4001) },
+ { USB_DEVICE_WACOM(0x5002) },
{ USB_DEVICE_WACOM(0x47) },
{ USB_DEVICE_WACOM(0xF4) },
{ USB_DEVICE_WACOM(0xF8) },
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
index f69c0eb..620dae8 100644
--- a/drivers/input/tablet/wacom_wac.h
+++ b/drivers/input/tablet/wacom_wac.h
@@ -30,6 +30,7 @@
#define WACOM_PKGLEN_MTOUCH 62
#define WACOM_PKGLEN_MTTPC 40
#define WACOM_PKGLEN_DTUS 68
+#define WACOM_PKGLEN_PENABLED 8
/* wacom data size per MT contact */
#define WACOM_BYTES_PER_MT_PACKET 11
@@ -52,6 +53,7 @@
#define WACOM_REPORT_TPC1FG 6
#define WACOM_REPORT_TPC2FG 13
#define WACOM_REPORT_TPCMT 13
+#define WACOM_REPORT_TPCMT2 3
#define WACOM_REPORT_TPCHID 15
#define WACOM_REPORT_TPCST 16
#define WACOM_REPORT_DTUS 17
@@ -105,6 +107,7 @@ enum {
TABLETPC2FG,
MTSCREEN,
MTTPC,
+ MTTPC_B,
MAX_TYPE
};
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -246,7 +248,7 @@
int result = 0;
unsigned char *rep_data;
- rep_data = kmalloc(2, GFP_KERNEL);
+ rep_data = kmalloc(2, GFP_NOIO);
if (rep_data) {
rep_data[0] = 12;
@@ -308,7 +310,7 @@
int i = 0, usage = WCM_UNDEFINED, finger = 0, pen = 0;
unsigned char *report;
- report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL);
+ report = kzalloc(hid_desc->wDescriptorLength, GFP_NOIO);
if (!report)
return -ENOMEM;
@@ -517,7 +538,7 @@
unsigned char *rep_data;
int error = -ENOMEM, limit = 0;
- rep_data = kzalloc(length, GFP_KERNEL);
+ rep_data = kzalloc(length, GFP_NOIO);
if (!rep_data)
return error;

View File

@ -1 +1 @@
98fc29a56d460ce5ee3be3992b60f57afa535596
8251d08813903fffb40bab8041618909d06e690a

View File

@ -99,6 +99,7 @@ PATCH_OPT(patches/usb_evdev.patch) := $(USB_OPT)
PATCH_OPT(patches/usb_mem.patch) := $(USB_OPT)
PATCH_OPT(patches/usb_usbnet.patch) := $(USB_OPT)
PATCH_OPT(patches/usb_xchi-quirks.patch) := $(USB_OPT)
PATCH_OPT(patches/usb_wacom.patch) := $(USB_OPT)
#IP stack
LXIP_OPT = -p1 -d$(SRC_DIR_LXIP)

View File

@ -102,7 +102,6 @@ int strncmp(const char *cs, const char *ct, size_t count) { TRACE; return 0;
char *strncpy(char *dst, const char *src, size_t s) { TRACE; return NULL; }
char *strchr(const char *s, int n) { TRACE; return NULL; }
char *strrchr(const char *s, int n) { TRACE; return NULL; }
size_t strlcpy(char *dest, const char *src, size_t size) { TRACE; return 0; }
char *strsep(char **s,const char *d) { TRACE; return NULL; }
char *kstrdup(const char *s, gfp_t gfp) { TRACE; return 0; }
char *strstr(const char *h, const char *n) { TRACE; return 0; }
@ -1105,3 +1104,10 @@ struct dwc3;
int dwc3_debugfs_init(struct dwc3 *d){ SKIP; return 0; }
void dwc3_debugfs_exit(struct dwc3 *d) { SKIP; }
/**************************
** linux/power_supply.h **
**************************/
#include <linux/power_supply.h>
int power_supply_register(struct device *parent, struct power_supply *psy) { TRACE; return 0; }
void power_supply_unregister(struct power_supply *psy) { TRACE; }
int power_supply_powers(struct power_supply *psy, struct device *dev) { TRACE; return 0; }

View File

@ -325,15 +325,6 @@ enum irqreturn {
typedef enum irqreturn irqreturn_t;
/******************
** linux/swab.h **
******************/
__u16 __swab16p(const __u16 *);
__u32 __swab32p(const __u32 *);
__u64 __swab64p(const __u64 *);
/*************************************
** linux/byteorder/little_endian.h **
*************************************/
@ -389,6 +380,15 @@ u64 get_unaligned_le64(const void *p);
#define get_unaligned get_unaligned_le32
#endif
/*********************************
** linux/unaligned/access_ok.h **
*********************************/
static inline u16 get_unaligned_be16(const void *p)
{
return be16_to_cpup((__be16 *)p);
}
/****************
** asm/page.h **
@ -654,6 +654,8 @@ long simple_strtoul(const char *cp, char **endp, unsigned int base);
int hex_to_bin(char ch);
unsigned long int_sqrt(unsigned long);
/*
* Needed by 'usb.h'
*/
@ -2668,19 +2670,13 @@ void cdev_del(struct cdev *);
** linux/stat.h **
******************/
#define S_IFMT 00170000
#define S_IFDIR 0040000
#define S_IFREG 0100000
#define S_ISVTX 0001000
#define S_IALLUGO 0007777
#define S_IRUGO 00444
#define S_IWUSR 00200
#define S_IXUGO 00111
#define S_IRWXUGO 00777
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#include <uapi/linux/stat.h>
/*********************
** linux/utsname.h **
@ -3842,16 +3838,19 @@ typedef void (*genode_input_event_cb)(enum input_event_type type,
* Register input handle
*
* \param handler call-back function on input events
* \param res_x pixels of screen (width) - used by usb touch devices
* \param res_y pixels of screen (height) - used by usb touch devices
*
* \return 0 on success; !0 otherwise
*/
void genode_input_register(genode_input_event_cb handler);
void genode_input_register(genode_input_event_cb handler, unsigned long res_x,
unsigned long res_y);
void genode_evdev_event(struct input_handle *handle, unsigned int type,
unsigned int code, int value);
void start_input_service(void *ep);
void start_input_service(void *ep, unsigned long res_x, unsigned long res_y);
/******************

View File

@ -32,15 +32,32 @@ struct Services
bool ehci; /* 2.0 */
bool xhci; /* 3.0 */
/*
* Screen resolution used by touch devices to convert touchscreen
* absolute coordinates to screen absolute coordinates
*/
unsigned long screen_x;
unsigned long screen_y;
Services()
: hid(false), stor(false), nic(false),
uhci(false), ehci(false), xhci(false)
uhci(false), ehci(false), xhci(false),
screen_x(0), screen_y(0)
{
using namespace Genode;
try {
config()->xml_node().sub_node("hid");
Genode::Xml_node node_hid = config()->xml_node().sub_node("hid");
hid = true;
try {
Genode::Xml_node node_screen = node_hid.sub_node("screen");
node_screen.attribute("x").value(&screen_x);
node_screen.attribute("y").value(&screen_y);
} catch (...) {
screen_x = screen_y = 0;
PDBG("Could not read screen resolution in config node");
}
} catch (Xml_node::Nonexistent_sub_node) {
PDBG("No <hid> config node found - not starting the USB HID (Input) service");
}

View File

@ -28,6 +28,10 @@
/* Callback function to Genode subsystem */
static genode_input_event_cb handler;;
static unsigned long screen_x = 0;
static unsigned long screen_y = 0;
void genode_evdev_event(struct input_handle *handle, unsigned int type,
unsigned int code, int value)
{
@ -97,8 +101,30 @@ void genode_evdev_event(struct input_handle *handle, unsigned int type,
* axis.
*/
arg_type = EVENT_TYPE_MOTION;
arg_ay = value;
arg_ax = last_ax;
arg_ay = value;
/* transform if requested */
if (screen_x && screen_y) {
int const min_x_dev = input_abs_get_min(handle->dev, ABS_X);
int const min_y_dev = input_abs_get_min(handle->dev, ABS_Y);
int const max_x_dev = input_abs_get_max(handle->dev, ABS_X);
int const max_y_dev = input_abs_get_max(handle->dev, ABS_Y);
int const max_y_norm = max_y_dev - min_y_dev;
int const max_x_norm = max_x_dev - min_x_dev;
if ((max_x_norm == 0) || (max_y_norm == 0) ||
(last_ax < min_x_dev) || (value < min_y_dev) ||
(last_ax > max_x_dev) || (value > max_y_dev))
{
printk("Ignore input source with coordinates out of range\n");
return;
}
arg_ax = screen_x * (last_ax - min_x_dev) / (max_x_norm);
arg_ay = screen_y * (value - min_y_dev) / (max_y_norm);
}
last_ax = -1;
if (arg_ax == -1) {
printk("Ignore absolute Y event without a preceeding X event\n");
@ -160,10 +186,18 @@ void genode_evdev_event(struct input_handle *handle, unsigned int type,
handler(arg_type, arg_keycode, arg_ax, arg_ay, arg_rx, arg_ry);
#if DEBUG_EVDEV
printk("event[%ld]. dev: %s, type: %d, code: %d, value: %d\n",
count++, handle->dev->name, type, code, value);
printk("event[%ld]. dev: %s, type: %d, code: %d, value: %d a=%d,%d "
"r=%d,%d\n", count++, handle->dev->name, type, code, value, arg_ax,
arg_ay, arg_rx, arg_ry);
#endif
}
void genode_input_register(genode_input_event_cb h) { handler = h; }
void genode_input_register(genode_input_event_cb h, unsigned long res_x,
unsigned long res_y)
{
handler = h;
screen_x = res_x;
screen_y = res_y;
}

View File

@ -75,11 +75,11 @@ static void input_callback(enum input_event_type type,
}
void start_input_service(void *ep_ptr)
void start_input_service(void *ep_ptr, unsigned long res_x, unsigned long res_y)
{
Rpc_entrypoint *ep = static_cast<Rpc_entrypoint *>(ep_ptr);
env()->parent()->announce(ep->manage(&input_root(ep)));
genode_input_register(input_callback);
genode_input_register(input_callback, res_x, res_y);
}

View File

@ -540,19 +540,35 @@ int strcmp(const char *s1, const char *s2) { return Genode::strcmp(s1, s2); }
size_t strlen(const char *s) { return Genode::strlen(s); }
size_t strlcat(char *dest, const char *src, size_t n)
size_t strlcat(char *dest, const char *src, size_t dest_size)
{
size_t len = strlen(dest);
size_t len_d = strlen(dest);
size_t len_s = strlen(src);
if (len >= n)
len = n - 1;
if (len_d > dest_size)
return 0;
memcpy(dest, src, len);
dest[len] = 0;
size_t len = dest_size - len_d - 1;
memcpy(dest + len_d, src, len);
dest[len_d + len] = 0;
return len;
}
size_t strlcpy(char *dest, const char *src, size_t size)
{
size_t ret = strlen(src);
if (size) {
size_t len = (ret >= size) ? size - 1 : ret;
Genode::memcpy(dest, src, len);
dest[len] = '\0';
}
return ret;
}
void *kmemdup(const void *src, size_t len, gfp_t gfp)
{
void *ptr = kmalloc(len, gfp);

View File

@ -39,10 +39,11 @@ extern "C" void module_hid_init();
extern "C" void module_hid_init_core();
extern "C" void module_hid_generic_init();
extern "C" void module_usb_storage_driver_init();
extern "C" void module_wacom_driver_init();
extern "C" void module_ch_driver_init();
extern "C" void module_mt_driver_init();
extern "C" void start_input_service(void *ep);
extern "C" void start_input_service(void *ep, unsigned long, unsigned long);
Routine *Routine::_current = 0;
Routine *Routine::_dead = 0;
@ -71,6 +72,7 @@ static void init(Services *services)
module_hid_generic_init();
module_ch_driver_init();
module_mt_driver_init();
module_wacom_driver_init();
}
/* host controller */
@ -87,7 +89,7 @@ void start_usb_driver(Server::Entrypoint &ep)
Services services;
if (services.hid)
start_input_service(&ep.rpc_ep());
start_input_service(&ep.rpc_ep(), services.screen_x, services.screen_y);
Timer::init(ep);
Irq::init(ep);

View File

@ -11,6 +11,10 @@ linux-3.14.5/drivers/input/evdev.c
linux-3.14.5/drivers/input/input-compat.h
linux-3.14.5/drivers/input/input-mt.c
linux-3.14.5/drivers/input/input.c
linux-3.14.5/drivers/input/tablet/wacom.h
linux-3.14.5/drivers/input/tablet/wacom_sys.c
linux-3.14.5/drivers/input/tablet/wacom_wac.c
linux-3.14.5/drivers/input/tablet/wacom_wac.h
linux-3.14.5/drivers/net/usb/asix_common.c
linux-3.14.5/drivers/net/usb/asix_devices.c
linux-3.14.5/drivers/net/usb/asix.h
@ -116,23 +120,26 @@ linux-3.14.5/include/linux/hiddev.h
linux-3.14.5/include/linux/hid.h
linux-3.14.5/include/linux/input.h
linux-3.14.5/include/linux/input/mt.h
linux-3.14.5/include/linux/leds.h
linux-3.14.5/include/linux/list.h
linux-3.14.5/include/linux/mod_devicetable.h
linux-3.14.5/include/linux/netdev_features.h
linux-3.14.5/include/linux/platform_data/dwc3-exynos.h
linux-3.14.5/include/linux/pci_ids.h
linux-3.14.5/include/linux/platform_data/usb-omap.h
linux-3.14.5/include/linux/power_supply.h
linux-3.14.5/include/linux/swab.h
linux-3.14.5/include/linux/usb.h
linux-3.14.5/include/linux/usb_usual.h
linux-3.14.5/include/linux/usb/ch9.h
linux-3.14.5/include/linux/usb/ehci_def.h
linux-3.14.5/include/linux/usb.h
linux-3.14.5/include/linux/usb/hcd.h
linux-3.14.5/include/linux/usb/input.h
linux-3.14.5/include/linux/usb/otg.h
linux-3.14.5/include/linux/usb/phy.h
linux-3.14.5/include/linux/usb/quirks.h
linux-3.14.5/include/linux/usb/storage.h
linux-3.14.5/include/linux/usb/usbnet.h
linux-3.14.5/include/linux/usb_usual.h
linux-3.14.5/include/scsi/scsi.h
linux-3.14.5/include/scsi/scsi_host.h
linux-3.14.5/include/uapi/asm-generic/ioctl.h
@ -140,5 +147,8 @@ linux-3.14.5/include/uapi/linux/byteorder/little_endian.h
linux-3.14.5/include/uapi/linux/hid.h
linux-3.14.5/include/uapi/linux/input.h
linux-3.14.5/include/uapi/linux/pci_regs.h
linux-3.14.5/include/uapi/linux/stat.h
linux-3.14.5/include/uapi/linux/swab.h
linux-3.14.5/include/uapi/linux/usb/ch11.h
linux-3.14.5/include/uapi/linux/usb/ch9.h
linux-3.14.5/lib/int_sqrt.c

View File

@ -36,6 +36,15 @@ static char const * ev_type(Input::Event::Type type)
}
static char const * key_name(Input::Event *ev)
{
if (ev->type() == Input::Event::MOTION)
return "";
return Input::key_name(static_cast<Input::Keycode>(ev->code()));
}
int main(int argc, char **argv)
{
/*
@ -66,9 +75,9 @@ int main(int argc, char **argv)
if (ev->type() == Input::Event::RELEASE) key_cnt--;
/* log event */
PLOG("Input event type=%s\tcode=%d\trx=%d\try=%d\tkey_cnt=%d\t%s",
ev_type(ev->type()), ev->code(), ev->rx(), ev->ry(), key_cnt,
Input::key_name(static_cast<Input::Keycode>(ev->code())));
PLOG("Input event type=%s\tcode=%d\trx=%d\try=%d\tax=%d\tay=%d\tkey_cnt=%d\t%s",
ev_type(ev->type()), ev->code(), ev->rx(), ev->ry(),
ev->ax(), ev->ay(), key_cnt, key_name(ev));
}
}