aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>2017-06-29 03:20:19 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2017-07-09 17:43:26 -0400
commit49aac8204da5f344f52ed9b3eb8736ca7a60c4a8 (patch)
treee2e921ae3a25618d6ea1b6e8d45396a923e155b4
parent65938133784a3092c61b00aa63d1830fb465c1ac (diff)
Input: xen-kbdfront - add multi-touch support
Extend xen_kbdfront to provide multi-touch support to unprivileged domains. Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com> [dtor: factor out various sub-protocols - multitouch, single touch, keys] Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
-rw-r--r--drivers/input/misc/xen-kbdfront.c219
1 files changed, 179 insertions, 40 deletions
diff --git a/drivers/input/misc/xen-kbdfront.c b/drivers/input/misc/xen-kbdfront.c
index eb770613a9bd..fa130e7b734c 100644
--- a/drivers/input/misc/xen-kbdfront.c
+++ b/drivers/input/misc/xen-kbdfront.c
@@ -17,6 +17,7 @@
17#include <linux/errno.h> 17#include <linux/errno.h>
18#include <linux/module.h> 18#include <linux/module.h>
19#include <linux/input.h> 19#include <linux/input.h>
20#include <linux/input/mt.h>
20#include <linux/slab.h> 21#include <linux/slab.h>
21 22
22#include <asm/xen/hypervisor.h> 23#include <asm/xen/hypervisor.h>
@@ -34,11 +35,14 @@
34struct xenkbd_info { 35struct xenkbd_info {
35 struct input_dev *kbd; 36 struct input_dev *kbd;
36 struct input_dev *ptr; 37 struct input_dev *ptr;
38 struct input_dev *mtouch;
37 struct xenkbd_page *page; 39 struct xenkbd_page *page;
38 int gref; 40 int gref;
39 int irq; 41 int irq;
40 struct xenbus_device *xbdev; 42 struct xenbus_device *xbdev;
41 char phys[32]; 43 char phys[32];
44 /* current MT slot/contact ID we are injecting events in */
45 int mtouch_cur_contact_id;
42}; 46};
43 47
44enum { KPARAM_X, KPARAM_Y, KPARAM_CNT }; 48enum { KPARAM_X, KPARAM_Y, KPARAM_CNT };
@@ -56,6 +60,112 @@ static void xenkbd_disconnect_backend(struct xenkbd_info *);
56 * to do that. 60 * to do that.
57 */ 61 */
58 62
63static void xenkbd_handle_motion_event(struct xenkbd_info *info,
64 struct xenkbd_motion *motion)
65{
66 input_report_rel(info->ptr, REL_X, motion->rel_x);
67 input_report_rel(info->ptr, REL_Y, motion->rel_y);
68 if (motion->rel_z)
69 input_report_rel(info->ptr, REL_WHEEL, -motion->rel_z);
70 input_sync(info->ptr);
71}
72
73static void xenkbd_handle_position_event(struct xenkbd_info *info,
74 struct xenkbd_position *pos)
75{
76 input_report_abs(info->ptr, ABS_X, pos->abs_x);
77 input_report_abs(info->ptr, ABS_Y, pos->abs_y);
78 if (pos->rel_z)
79 input_report_rel(info->ptr, REL_WHEEL, -pos->rel_z);
80 input_sync(info->ptr);
81}
82
83static void xenkbd_handle_key_event(struct xenkbd_info *info,
84 struct xenkbd_key *key)
85{
86 struct input_dev *dev;
87
88 if (test_bit(key->keycode, info->ptr->keybit)) {
89 dev = info->ptr;
90 } else if (test_bit(key->keycode, info->kbd->keybit)) {
91 dev = info->kbd;
92 } else {
93 pr_warn("unhandled keycode 0x%x\n", key->keycode);
94 return;
95 }
96
97 input_report_key(dev, key->keycode, key->pressed);
98 input_sync(dev);
99}
100
101static void xenkbd_handle_mt_event(struct xenkbd_info *info,
102 struct xenkbd_mtouch *mtouch)
103{
104 if (unlikely(!info->mtouch))
105 return;
106
107 if (mtouch->contact_id != info->mtouch_cur_contact_id) {
108 info->mtouch_cur_contact_id = mtouch->contact_id;
109 input_mt_slot(info->mtouch, mtouch->contact_id);
110 }
111
112 switch (mtouch->event_type) {
113 case XENKBD_MT_EV_DOWN:
114 input_mt_report_slot_state(info->mtouch, MT_TOOL_FINGER, true);
115 /* fall through */
116
117 case XENKBD_MT_EV_MOTION:
118 input_report_abs(info->mtouch, ABS_MT_POSITION_X,
119 mtouch->u.pos.abs_x);
120 input_report_abs(info->mtouch, ABS_MT_POSITION_Y,
121 mtouch->u.pos.abs_y);
122 break;
123
124 case XENKBD_MT_EV_SHAPE:
125 input_report_abs(info->mtouch, ABS_MT_TOUCH_MAJOR,
126 mtouch->u.shape.major);
127 input_report_abs(info->mtouch, ABS_MT_TOUCH_MINOR,
128 mtouch->u.shape.minor);
129 break;
130
131 case XENKBD_MT_EV_ORIENT:
132 input_report_abs(info->mtouch, ABS_MT_ORIENTATION,
133 mtouch->u.orientation);
134 break;
135
136 case XENKBD_MT_EV_UP:
137 input_mt_report_slot_state(info->mtouch, MT_TOOL_FINGER, false);
138 break;
139
140 case XENKBD_MT_EV_SYN:
141 input_mt_sync_frame(info->mtouch);
142 input_sync(info->mtouch);
143 break;
144 }
145}
146
147static void xenkbd_handle_event(struct xenkbd_info *info,
148 union xenkbd_in_event *event)
149{
150 switch (event->type) {
151 case XENKBD_TYPE_MOTION:
152 xenkbd_handle_motion_event(info, &event->motion);
153 break;
154
155 case XENKBD_TYPE_KEY:
156 xenkbd_handle_key_event(info, &event->key);
157 break;
158
159 case XENKBD_TYPE_POS:
160 xenkbd_handle_position_event(info, &event->pos);
161 break;
162
163 case XENKBD_TYPE_MTOUCH:
164 xenkbd_handle_mt_event(info, &event->mtouch);
165 break;
166 }
167}
168
59static irqreturn_t input_handler(int rq, void *dev_id) 169static irqreturn_t input_handler(int rq, void *dev_id)
60{ 170{
61 struct xenkbd_info *info = dev_id; 171 struct xenkbd_info *info = dev_id;
@@ -66,44 +176,8 @@ static irqreturn_t input_handler(int rq, void *dev_id)
66 if (prod == page->in_cons) 176 if (prod == page->in_cons)
67 return IRQ_HANDLED; 177 return IRQ_HANDLED;
68 rmb(); /* ensure we see ring contents up to prod */ 178 rmb(); /* ensure we see ring contents up to prod */
69 for (cons = page->in_cons; cons != prod; cons++) { 179 for (cons = page->in_cons; cons != prod; cons++)
70 union xenkbd_in_event *event; 180 xenkbd_handle_event(info, &XENKBD_IN_RING_REF(page, cons));
71 struct input_dev *dev;
72 event = &XENKBD_IN_RING_REF(page, cons);
73
74 dev = info->ptr;
75 switch (event->type) {
76 case XENKBD_TYPE_MOTION:
77 input_report_rel(dev, REL_X, event->motion.rel_x);
78 input_report_rel(dev, REL_Y, event->motion.rel_y);
79 if (event->motion.rel_z)
80 input_report_rel(dev, REL_WHEEL,
81 -event->motion.rel_z);
82 break;
83 case XENKBD_TYPE_KEY:
84 dev = NULL;
85 if (test_bit(event->key.keycode, info->kbd->keybit))
86 dev = info->kbd;
87 if (test_bit(event->key.keycode, info->ptr->keybit))
88 dev = info->ptr;
89 if (dev)
90 input_report_key(dev, event->key.keycode,
91 event->key.pressed);
92 else
93 pr_warn("unhandled keycode 0x%x\n",
94 event->key.keycode);
95 break;
96 case XENKBD_TYPE_POS:
97 input_report_abs(dev, ABS_X, event->pos.abs_x);
98 input_report_abs(dev, ABS_Y, event->pos.abs_y);
99 if (event->pos.rel_z)
100 input_report_rel(dev, REL_WHEEL,
101 -event->pos.rel_z);
102 break;
103 }
104 if (dev)
105 input_sync(dev);
106 }
107 mb(); /* ensure we got ring contents */ 181 mb(); /* ensure we got ring contents */
108 page->in_cons = cons; 182 page->in_cons = cons;
109 notify_remote_via_irq(info->irq); 183 notify_remote_via_irq(info->irq);
@@ -115,9 +189,9 @@ static int xenkbd_probe(struct xenbus_device *dev,
115 const struct xenbus_device_id *id) 189 const struct xenbus_device_id *id)
116{ 190{
117 int ret, i; 191 int ret, i;
118 unsigned int abs; 192 unsigned int abs, touch;
119 struct xenkbd_info *info; 193 struct xenkbd_info *info;
120 struct input_dev *kbd, *ptr; 194 struct input_dev *kbd, *ptr, *mtouch;
121 195
122 info = kzalloc(sizeof(*info), GFP_KERNEL); 196 info = kzalloc(sizeof(*info), GFP_KERNEL);
123 if (!info) { 197 if (!info) {
@@ -152,6 +226,17 @@ static int xenkbd_probe(struct xenbus_device *dev,
152 } 226 }
153 } 227 }
154 228
229 touch = xenbus_read_unsigned(dev->nodename,
230 XENKBD_FIELD_FEAT_MTOUCH, 0);
231 if (touch) {
232 ret = xenbus_write(XBT_NIL, dev->nodename,
233 XENKBD_FIELD_REQ_MTOUCH, "1");
234 if (ret) {
235 pr_warn("xenkbd: can't request multi-touch");
236 touch = 0;
237 }
238 }
239
155 /* keyboard */ 240 /* keyboard */
156 kbd = input_allocate_device(); 241 kbd = input_allocate_device();
157 if (!kbd) 242 if (!kbd)
@@ -208,6 +293,58 @@ static int xenkbd_probe(struct xenbus_device *dev,
208 } 293 }
209 info->ptr = ptr; 294 info->ptr = ptr;
210 295
296 /* multi-touch device */
297 if (touch) {
298 int num_cont, width, height;
299
300 mtouch = input_allocate_device();
301 if (!mtouch)
302 goto error_nomem;
303
304 num_cont = xenbus_read_unsigned(info->xbdev->nodename,
305 XENKBD_FIELD_MT_NUM_CONTACTS,
306 1);
307 width = xenbus_read_unsigned(info->xbdev->nodename,
308 XENKBD_FIELD_MT_WIDTH,
309 XENFB_WIDTH);
310 height = xenbus_read_unsigned(info->xbdev->nodename,
311 XENKBD_FIELD_MT_HEIGHT,
312 XENFB_HEIGHT);
313
314 mtouch->name = "Xen Virtual Multi-touch";
315 mtouch->phys = info->phys;
316 mtouch->id.bustype = BUS_PCI;
317 mtouch->id.vendor = 0x5853;
318 mtouch->id.product = 0xfffd;
319
320 input_set_abs_params(mtouch, ABS_MT_TOUCH_MAJOR,
321 0, 255, 0, 0);
322 input_set_abs_params(mtouch, ABS_MT_POSITION_X,
323 0, width, 0, 0);
324 input_set_abs_params(mtouch, ABS_MT_POSITION_Y,
325 0, height, 0, 0);
326 input_set_abs_params(mtouch, ABS_MT_PRESSURE,
327 0, 255, 0, 0);
328
329 ret = input_mt_init_slots(mtouch, num_cont, INPUT_MT_DIRECT);
330 if (ret) {
331 input_free_device(mtouch);
332 xenbus_dev_fatal(info->xbdev, ret,
333 "input_mt_init_slots");
334 goto error;
335 }
336
337 ret = input_register_device(mtouch);
338 if (ret) {
339 input_free_device(mtouch);
340 xenbus_dev_fatal(info->xbdev, ret,
341 "input_register_device(mtouch)");
342 goto error;
343 }
344 info->mtouch_cur_contact_id = -1;
345 info->mtouch = mtouch;
346 }
347
211 ret = xenkbd_connect_backend(dev, info); 348 ret = xenkbd_connect_backend(dev, info);
212 if (ret < 0) 349 if (ret < 0)
213 goto error; 350 goto error;
@@ -240,6 +377,8 @@ static int xenkbd_remove(struct xenbus_device *dev)
240 input_unregister_device(info->kbd); 377 input_unregister_device(info->kbd);
241 if (info->ptr) 378 if (info->ptr)
242 input_unregister_device(info->ptr); 379 input_unregister_device(info->ptr);
380 if (info->mtouch)
381 input_unregister_device(info->mtouch);
243 free_page((unsigned long)info->page); 382 free_page((unsigned long)info->page);
244 kfree(info); 383 kfree(info);
245 return 0; 384 return 0;