diff options
-rw-r--r-- | drivers/input/keyboard/gpio_keys.c | 17 | ||||
-rw-r--r-- | drivers/input/misc/xen-kbdfront.c | 219 | ||||
-rw-r--r-- | drivers/input/serio/i8042.c | 12 |
3 files changed, 204 insertions, 44 deletions
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index da3d362f21b1..a047b9af8369 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c | |||
@@ -48,6 +48,7 @@ struct gpio_button_data { | |||
48 | spinlock_t lock; | 48 | spinlock_t lock; |
49 | bool disabled; | 49 | bool disabled; |
50 | bool key_pressed; | 50 | bool key_pressed; |
51 | bool suspended; | ||
51 | }; | 52 | }; |
52 | 53 | ||
53 | struct gpio_keys_drvdata { | 54 | struct gpio_keys_drvdata { |
@@ -396,8 +397,20 @@ static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id) | |||
396 | 397 | ||
397 | BUG_ON(irq != bdata->irq); | 398 | BUG_ON(irq != bdata->irq); |
398 | 399 | ||
399 | if (bdata->button->wakeup) | 400 | if (bdata->button->wakeup) { |
401 | const struct gpio_keys_button *button = bdata->button; | ||
402 | |||
400 | pm_stay_awake(bdata->input->dev.parent); | 403 | pm_stay_awake(bdata->input->dev.parent); |
404 | if (bdata->suspended && | ||
405 | (button->type == 0 || button->type == EV_KEY)) { | ||
406 | /* | ||
407 | * Simulate wakeup key press in case the key has | ||
408 | * already released by the time we got interrupt | ||
409 | * handler to run. | ||
410 | */ | ||
411 | input_report_key(bdata->input, button->code, 1); | ||
412 | } | ||
413 | } | ||
401 | 414 | ||
402 | mod_delayed_work(system_wq, | 415 | mod_delayed_work(system_wq, |
403 | &bdata->work, | 416 | &bdata->work, |
@@ -855,6 +868,7 @@ static int __maybe_unused gpio_keys_suspend(struct device *dev) | |||
855 | struct gpio_button_data *bdata = &ddata->data[i]; | 868 | struct gpio_button_data *bdata = &ddata->data[i]; |
856 | if (bdata->button->wakeup) | 869 | if (bdata->button->wakeup) |
857 | enable_irq_wake(bdata->irq); | 870 | enable_irq_wake(bdata->irq); |
871 | bdata->suspended = true; | ||
858 | } | 872 | } |
859 | } else { | 873 | } else { |
860 | mutex_lock(&input->mutex); | 874 | mutex_lock(&input->mutex); |
@@ -878,6 +892,7 @@ static int __maybe_unused gpio_keys_resume(struct device *dev) | |||
878 | struct gpio_button_data *bdata = &ddata->data[i]; | 892 | struct gpio_button_data *bdata = &ddata->data[i]; |
879 | if (bdata->button->wakeup) | 893 | if (bdata->button->wakeup) |
880 | disable_irq_wake(bdata->irq); | 894 | disable_irq_wake(bdata->irq); |
895 | bdata->suspended = false; | ||
881 | } | 896 | } |
882 | } else { | 897 | } else { |
883 | mutex_lock(&input->mutex); | 898 | mutex_lock(&input->mutex); |
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 @@ | |||
34 | struct xenkbd_info { | 35 | struct 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 | ||
44 | enum { KPARAM_X, KPARAM_Y, KPARAM_CNT }; | 48 | enum { 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 | ||
63 | static 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 | |||
73 | static 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 | |||
83 | static 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 | |||
101 | static 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 | |||
147 | static 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 | |||
59 | static irqreturn_t input_handler(int rq, void *dev_id) | 169 | static 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; |
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index c52da651269b..824f4c1c1f31 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c | |||
@@ -436,8 +436,10 @@ static int i8042_start(struct serio *serio) | |||
436 | { | 436 | { |
437 | struct i8042_port *port = serio->port_data; | 437 | struct i8042_port *port = serio->port_data; |
438 | 438 | ||
439 | spin_lock_irq(&i8042_lock); | ||
439 | port->exists = true; | 440 | port->exists = true; |
440 | mb(); | 441 | spin_unlock_irq(&i8042_lock); |
442 | |||
441 | return 0; | 443 | return 0; |
442 | } | 444 | } |
443 | 445 | ||
@@ -450,16 +452,20 @@ static void i8042_stop(struct serio *serio) | |||
450 | { | 452 | { |
451 | struct i8042_port *port = serio->port_data; | 453 | struct i8042_port *port = serio->port_data; |
452 | 454 | ||
455 | spin_lock_irq(&i8042_lock); | ||
453 | port->exists = false; | 456 | port->exists = false; |
457 | port->serio = NULL; | ||
458 | spin_unlock_irq(&i8042_lock); | ||
454 | 459 | ||
455 | /* | 460 | /* |
461 | * We need to make sure that interrupt handler finishes using | ||
462 | * our serio port before we return from this function. | ||
456 | * We synchronize with both AUX and KBD IRQs because there is | 463 | * We synchronize with both AUX and KBD IRQs because there is |
457 | * a (very unlikely) chance that AUX IRQ is raised for KBD port | 464 | * a (very unlikely) chance that AUX IRQ is raised for KBD port |
458 | * and vice versa. | 465 | * and vice versa. |
459 | */ | 466 | */ |
460 | synchronize_irq(I8042_AUX_IRQ); | 467 | synchronize_irq(I8042_AUX_IRQ); |
461 | synchronize_irq(I8042_KBD_IRQ); | 468 | synchronize_irq(I8042_KBD_IRQ); |
462 | port->serio = NULL; | ||
463 | } | 469 | } |
464 | 470 | ||
465 | /* | 471 | /* |
@@ -576,7 +582,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id) | |||
576 | 582 | ||
577 | spin_unlock_irqrestore(&i8042_lock, flags); | 583 | spin_unlock_irqrestore(&i8042_lock, flags); |
578 | 584 | ||
579 | if (likely(port->exists && !filtered)) | 585 | if (likely(serio && !filtered)) |
580 | serio_interrupt(serio, data, dfl); | 586 | serio_interrupt(serio, data, dfl); |
581 | 587 | ||
582 | out: | 588 | out: |