aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/Kconfig9
-rw-r--r--drivers/input/Makefile2
-rw-r--r--drivers/input/keyboard/Kconfig9
-rw-r--r--drivers/input/keyboard/Makefile1
-rw-r--r--drivers/input/keyboard/corgikbd.c1
-rw-r--r--drivers/input/keyboard/sh_keysc.c280
-rw-r--r--drivers/input/keyboard/spitzkbd.c1
-rw-r--r--drivers/input/misc/Kconfig1
-rw-r--r--drivers/input/serio/hp_sdc_mlc.c2
-rw-r--r--drivers/input/touchscreen/ads7846.c40
-rw-r--r--drivers/input/touchscreen/corgi_ts.c1
-rw-r--r--drivers/input/xen-kbdfront.c340
12 files changed, 646 insertions, 41 deletions
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 9dea14db724c..5f9d860925a1 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -149,6 +149,15 @@ config INPUT_APMPOWER
149 To compile this driver as a module, choose M here: the 149 To compile this driver as a module, choose M here: the
150 module will be called apm-power. 150 module will be called apm-power.
151 151
152config XEN_KBDDEV_FRONTEND
153 tristate "Xen virtual keyboard and mouse support"
154 depends on XEN_FBDEV_FRONTEND
155 default y
156 help
157 This driver implements the front-end of the Xen virtual
158 keyboard and mouse device driver. It communicates with a back-end
159 in another domain.
160
152comment "Input Device Drivers" 161comment "Input Device Drivers"
153 162
154source "drivers/input/keyboard/Kconfig" 163source "drivers/input/keyboard/Kconfig"
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 2ae87b19caa8..98c4f9a77876 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -23,3 +23,5 @@ obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/
23obj-$(CONFIG_INPUT_MISC) += misc/ 23obj-$(CONFIG_INPUT_MISC) += misc/
24 24
25obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o 25obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o
26
27obj-$(CONFIG_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 8ea709be3306..efd70a974591 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -314,4 +314,13 @@ config KEYBOARD_BFIN
314 To compile this driver as a module, choose M here: the 314 To compile this driver as a module, choose M here: the
315 module will be called bf54x-keys. 315 module will be called bf54x-keys.
316 316
317config KEYBOARD_SH_KEYSC
318 tristate "SuperH KEYSC keypad support"
319 depends on SUPERH
320 help
321 Say Y here if you want to use a keypad attached to the KEYSC block
322 on SuperH processors such as sh7722 and sh7343.
323
324 To compile this driver as a module, choose M here: the
325 module will be called sh_keysc.
317endif 326endif
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index e741f4031012..0edc8f285d1c 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -26,3 +26,4 @@ obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o
26obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o 26obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o
27obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o 27obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o
28obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o 28obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o
29obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o
diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c
index 5187c0c7a222..29fbec6218b9 100644
--- a/drivers/input/keyboard/corgikbd.c
+++ b/drivers/input/keyboard/corgikbd.c
@@ -23,6 +23,7 @@
23#include <asm/arch/corgi.h> 23#include <asm/arch/corgi.h>
24#include <asm/arch/hardware.h> 24#include <asm/arch/hardware.h>
25#include <asm/arch/pxa-regs.h> 25#include <asm/arch/pxa-regs.h>
26#include <asm/arch/pxa2xx-gpio.h>
26#include <asm/hardware/scoop.h> 27#include <asm/hardware/scoop.h>
27 28
28#define KB_ROWS 8 29#define KB_ROWS 8
diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c
new file mode 100644
index 000000000000..8486abc457ed
--- /dev/null
+++ b/drivers/input/keyboard/sh_keysc.c
@@ -0,0 +1,280 @@
1/*
2 * SuperH KEYSC Keypad Driver
3 *
4 * Copyright (C) 2008 Magnus Damm
5 *
6 * Based on gpio_keys.c, Copyright 2005 Phil Blundell
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/interrupt.h>
17#include <linux/irq.h>
18#include <linux/delay.h>
19#include <linux/platform_device.h>
20#include <linux/input.h>
21#include <linux/io.h>
22#include <asm/sh_keysc.h>
23
24#define KYCR1_OFFS 0x00
25#define KYCR2_OFFS 0x04
26#define KYINDR_OFFS 0x08
27#define KYOUTDR_OFFS 0x0c
28
29#define KYCR2_IRQ_LEVEL 0x10
30#define KYCR2_IRQ_DISABLED 0x00
31
32static const struct {
33 unsigned char kymd, keyout, keyin;
34} sh_keysc_mode[] = {
35 [SH_KEYSC_MODE_1] = { 0, 6, 5 },
36 [SH_KEYSC_MODE_2] = { 1, 5, 6 },
37 [SH_KEYSC_MODE_3] = { 2, 4, 7 },
38};
39
40struct sh_keysc_priv {
41 void __iomem *iomem_base;
42 unsigned long last_keys;
43 struct input_dev *input;
44 struct sh_keysc_info pdata;
45};
46
47static irqreturn_t sh_keysc_isr(int irq, void *dev_id)
48{
49 struct platform_device *pdev = dev_id;
50 struct sh_keysc_priv *priv = platform_get_drvdata(pdev);
51 struct sh_keysc_info *pdata = &priv->pdata;
52 unsigned long keys, keys1, keys0, mask;
53 unsigned char keyin_set, tmp;
54 int i, k;
55
56 dev_dbg(&pdev->dev, "isr!\n");
57
58 keys1 = ~0;
59 keys0 = 0;
60
61 do {
62 keys = 0;
63 keyin_set = 0;
64
65 iowrite16(KYCR2_IRQ_DISABLED, priv->iomem_base + KYCR2_OFFS);
66
67 for (i = 0; i < sh_keysc_mode[pdata->mode].keyout; i++) {
68 iowrite16(0xfff ^ (3 << (i * 2)),
69 priv->iomem_base + KYOUTDR_OFFS);
70 udelay(pdata->delay);
71 tmp = ioread16(priv->iomem_base + KYINDR_OFFS);
72 keys |= tmp << (sh_keysc_mode[pdata->mode].keyin * i);
73 tmp ^= (1 << sh_keysc_mode[pdata->mode].keyin) - 1;
74 keyin_set |= tmp;
75 }
76
77 iowrite16(0, priv->iomem_base + KYOUTDR_OFFS);
78 iowrite16(KYCR2_IRQ_LEVEL | (keyin_set << 8),
79 priv->iomem_base + KYCR2_OFFS);
80
81 keys ^= ~0;
82 keys &= (1 << (sh_keysc_mode[pdata->mode].keyin *
83 sh_keysc_mode[pdata->mode].keyout)) - 1;
84 keys1 &= keys;
85 keys0 |= keys;
86
87 dev_dbg(&pdev->dev, "keys 0x%08lx\n", keys);
88
89 } while (ioread16(priv->iomem_base + KYCR2_OFFS) & 0x01);
90
91 dev_dbg(&pdev->dev, "last_keys 0x%08lx keys0 0x%08lx keys1 0x%08lx\n",
92 priv->last_keys, keys0, keys1);
93
94 for (i = 0; i < SH_KEYSC_MAXKEYS; i++) {
95 k = pdata->keycodes[i];
96 if (!k)
97 continue;
98
99 mask = 1 << i;
100
101 if (!((priv->last_keys ^ keys0) & mask))
102 continue;
103
104 if ((keys1 | keys0) & mask) {
105 input_event(priv->input, EV_KEY, k, 1);
106 priv->last_keys |= mask;
107 }
108
109 if (!(keys1 & mask)) {
110 input_event(priv->input, EV_KEY, k, 0);
111 priv->last_keys &= ~mask;
112 }
113
114 }
115 input_sync(priv->input);
116
117 return IRQ_HANDLED;
118}
119
120#define res_size(res) ((res)->end - (res)->start + 1)
121
122static int __devinit sh_keysc_probe(struct platform_device *pdev)
123{
124 struct sh_keysc_priv *priv;
125 struct sh_keysc_info *pdata;
126 struct resource *res;
127 struct input_dev *input;
128 int i, k;
129 int irq, error;
130
131 if (!pdev->dev.platform_data) {
132 dev_err(&pdev->dev, "no platform data defined\n");
133 error = -EINVAL;
134 goto err0;
135 }
136
137 error = -ENXIO;
138 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
139 if (res == NULL) {
140 dev_err(&pdev->dev, "failed to get I/O memory\n");
141 goto err0;
142 }
143
144 irq = platform_get_irq(pdev, 0);
145 if (irq < 0) {
146 dev_err(&pdev->dev, "failed to get irq\n");
147 goto err0;
148 }
149
150 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
151 if (priv == NULL) {
152 dev_err(&pdev->dev, "failed to allocate driver data\n");
153 error = -ENOMEM;
154 goto err0;
155 }
156
157 platform_set_drvdata(pdev, priv);
158 memcpy(&priv->pdata, pdev->dev.platform_data, sizeof(priv->pdata));
159 pdata = &priv->pdata;
160
161 res = request_mem_region(res->start, res_size(res), pdev->name);
162 if (res == NULL) {
163 dev_err(&pdev->dev, "failed to request I/O memory\n");
164 error = -EBUSY;
165 goto err1;
166 }
167
168 priv->iomem_base = ioremap_nocache(res->start, res_size(res));
169 if (priv->iomem_base == NULL) {
170 dev_err(&pdev->dev, "failed to remap I/O memory\n");
171 error = -ENXIO;
172 goto err2;
173 }
174
175 priv->input = input_allocate_device();
176 if (!priv->input) {
177 dev_err(&pdev->dev, "failed to allocate input device\n");
178 error = -ENOMEM;
179 goto err3;
180 }
181
182 input = priv->input;
183 input->evbit[0] = BIT_MASK(EV_KEY);
184
185 input->name = pdev->name;
186 input->phys = "sh-keysc-keys/input0";
187 input->dev.parent = &pdev->dev;
188
189 input->id.bustype = BUS_HOST;
190 input->id.vendor = 0x0001;
191 input->id.product = 0x0001;
192 input->id.version = 0x0100;
193
194 error = request_irq(irq, sh_keysc_isr, 0, pdev->name, pdev);
195 if (error) {
196 dev_err(&pdev->dev, "failed to request IRQ\n");
197 goto err4;
198 }
199
200 for (i = 0; i < SH_KEYSC_MAXKEYS; i++) {
201 k = pdata->keycodes[i];
202 if (k)
203 input_set_capability(input, EV_KEY, k);
204 }
205
206 error = input_register_device(input);
207 if (error) {
208 dev_err(&pdev->dev, "failed to register input device\n");
209 goto err5;
210 }
211
212 iowrite16((sh_keysc_mode[pdata->mode].kymd << 8) |
213 pdata->scan_timing, priv->iomem_base + KYCR1_OFFS);
214 iowrite16(0, priv->iomem_base + KYOUTDR_OFFS);
215 iowrite16(KYCR2_IRQ_LEVEL, priv->iomem_base + KYCR2_OFFS);
216 return 0;
217 err5:
218 free_irq(irq, pdev);
219 err4:
220 input_free_device(input);
221 err3:
222 iounmap(priv->iomem_base);
223 err2:
224 release_mem_region(res->start, res_size(res));
225 err1:
226 platform_set_drvdata(pdev, NULL);
227 kfree(priv);
228 err0:
229 return error;
230}
231
232static int __devexit sh_keysc_remove(struct platform_device *pdev)
233{
234 struct sh_keysc_priv *priv = platform_get_drvdata(pdev);
235 struct resource *res;
236
237 iowrite16(KYCR2_IRQ_DISABLED, priv->iomem_base + KYCR2_OFFS);
238
239 input_unregister_device(priv->input);
240 free_irq(platform_get_irq(pdev, 0), pdev);
241 iounmap(priv->iomem_base);
242
243 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
244 release_mem_region(res->start, res_size(res));
245
246 platform_set_drvdata(pdev, NULL);
247 kfree(priv);
248 return 0;
249}
250
251
252#define sh_keysc_suspend NULL
253#define sh_keysc_resume NULL
254
255struct platform_driver sh_keysc_device_driver = {
256 .probe = sh_keysc_probe,
257 .remove = __devexit_p(sh_keysc_remove),
258 .suspend = sh_keysc_suspend,
259 .resume = sh_keysc_resume,
260 .driver = {
261 .name = "sh_keysc",
262 }
263};
264
265static int __init sh_keysc_init(void)
266{
267 return platform_driver_register(&sh_keysc_device_driver);
268}
269
270static void __exit sh_keysc_exit(void)
271{
272 platform_driver_unregister(&sh_keysc_device_driver);
273}
274
275module_init(sh_keysc_init);
276module_exit(sh_keysc_exit);
277
278MODULE_AUTHOR("Magnus Damm");
279MODULE_DESCRIPTION("SuperH KEYSC Keypad Driver");
280MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c
index 92102f9e4b8b..61e401bc9109 100644
--- a/drivers/input/keyboard/spitzkbd.c
+++ b/drivers/input/keyboard/spitzkbd.c
@@ -23,6 +23,7 @@
23#include <asm/arch/spitz.h> 23#include <asm/arch/spitz.h>
24#include <asm/arch/hardware.h> 24#include <asm/arch/hardware.h>
25#include <asm/arch/pxa-regs.h> 25#include <asm/arch/pxa-regs.h>
26#include <asm/arch/pxa2xx-gpio.h>
26 27
27#define KB_ROWS 7 28#define KB_ROWS 7
28#define KB_COLS 11 29#define KB_COLS 11
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index c5263d63aca3..92b683411d5a 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -15,6 +15,7 @@ if INPUT_MISC
15config INPUT_PCSPKR 15config INPUT_PCSPKR
16 tristate "PC Speaker support" 16 tristate "PC Speaker support"
17 depends on ALPHA || X86 || MIPS || PPC_PREP || PPC_CHRP || PPC_PSERIES 17 depends on ALPHA || X86 || MIPS || PPC_PREP || PPC_CHRP || PPC_PSERIES
18 depends on SND_PCSP=n
18 help 19 help
19 Say Y here if you want the standard PC Speaker to be used for 20 Say Y here if you want the standard PC Speaker to be used for
20 bells and whistles. 21 bells and whistles.
diff --git a/drivers/input/serio/hp_sdc_mlc.c b/drivers/input/serio/hp_sdc_mlc.c
index c45ea74d53e4..f1fd3b638a37 100644
--- a/drivers/input/serio/hp_sdc_mlc.c
+++ b/drivers/input/serio/hp_sdc_mlc.c
@@ -40,7 +40,7 @@
40#include <linux/module.h> 40#include <linux/module.h>
41#include <linux/init.h> 41#include <linux/init.h>
42#include <linux/string.h> 42#include <linux/string.h>
43#include <asm/semaphore.h> 43#include <linux/semaphore.h>
44 44
45#define PREFIX "HP SDC MLC: " 45#define PREFIX "HP SDC MLC: "
46 46
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index a571aa965da0..907a45fe9d40 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -28,13 +28,6 @@
28#include <linux/spi/ads7846.h> 28#include <linux/spi/ads7846.h>
29#include <asm/irq.h> 29#include <asm/irq.h>
30 30
31#ifdef CONFIG_ARM
32#include <asm/mach-types.h>
33#ifdef CONFIG_ARCH_OMAP
34#include <asm/arch/gpio.h>
35#endif
36#endif
37
38 31
39/* 32/*
40 * This code has been heavily tested on a Nokia 770, and lightly 33 * This code has been heavily tested on a Nokia 770, and lightly
@@ -1172,31 +1165,6 @@ static struct spi_driver ads7846_driver = {
1172 1165
1173static int __init ads7846_init(void) 1166static int __init ads7846_init(void)
1174{ 1167{
1175 /* grr, board-specific init should stay out of drivers!! */
1176
1177#ifdef CONFIG_ARCH_OMAP
1178 if (machine_is_omap_osk()) {
1179 /* GPIO4 = PENIRQ; GPIO6 = BUSY */
1180 omap_request_gpio(4);
1181 omap_set_gpio_direction(4, 1);
1182 omap_request_gpio(6);
1183 omap_set_gpio_direction(6, 1);
1184 }
1185 // also TI 1510 Innovator, bitbanging through FPGA
1186 // also Nokia 770
1187 // also Palm Tungsten T2
1188#endif
1189
1190 // PXA:
1191 // also Dell Axim X50
1192 // also HP iPaq H191x/H192x/H415x/H435x
1193 // also Intel Lubbock (additional to UCB1400; as temperature sensor)
1194 // also Sharp Zaurus C7xx, C8xx (corgi/sheperd/husky)
1195
1196 // Atmel at91sam9261-EK uses ads7843
1197
1198 // also various AMD Au1x00 devel boards
1199
1200 return spi_register_driver(&ads7846_driver); 1168 return spi_register_driver(&ads7846_driver);
1201} 1169}
1202module_init(ads7846_init); 1170module_init(ads7846_init);
@@ -1204,14 +1172,6 @@ module_init(ads7846_init);
1204static void __exit ads7846_exit(void) 1172static void __exit ads7846_exit(void)
1205{ 1173{
1206 spi_unregister_driver(&ads7846_driver); 1174 spi_unregister_driver(&ads7846_driver);
1207
1208#ifdef CONFIG_ARCH_OMAP
1209 if (machine_is_omap_osk()) {
1210 omap_free_gpio(4);
1211 omap_free_gpio(6);
1212 }
1213#endif
1214
1215} 1175}
1216module_exit(ads7846_exit); 1176module_exit(ads7846_exit);
1217 1177
diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c
index 765e964b7969..4e9d8eece2e0 100644
--- a/drivers/input/touchscreen/corgi_ts.c
+++ b/drivers/input/touchscreen/corgi_ts.c
@@ -22,6 +22,7 @@
22#include <asm/arch/sharpsl.h> 22#include <asm/arch/sharpsl.h>
23#include <asm/arch/hardware.h> 23#include <asm/arch/hardware.h>
24#include <asm/arch/pxa-regs.h> 24#include <asm/arch/pxa-regs.h>
25#include <asm/arch/pxa2xx-gpio.h>
25 26
26 27
27#define PWR_MODE_ACTIVE 0 28#define PWR_MODE_ACTIVE 0
diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c
new file mode 100644
index 000000000000..0f47f4697cdf
--- /dev/null
+++ b/drivers/input/xen-kbdfront.c
@@ -0,0 +1,340 @@
1/*
2 * Xen para-virtual input device
3 *
4 * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com>
5 * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
6 *
7 * Based on linux/drivers/input/mouse/sermouse.c
8 *
9 * This file is subject to the terms and conditions of the GNU General Public
10 * License. See the file COPYING in the main directory of this archive for
11 * more details.
12 */
13
14/*
15 * TODO:
16 *
17 * Switch to grant tables together with xen-fbfront.c.
18 */
19
20#include <linux/kernel.h>
21#include <linux/errno.h>
22#include <linux/module.h>
23#include <linux/input.h>
24#include <asm/xen/hypervisor.h>
25#include <xen/events.h>
26#include <xen/page.h>
27#include <xen/interface/io/fbif.h>
28#include <xen/interface/io/kbdif.h>
29#include <xen/xenbus.h>
30
31struct xenkbd_info {
32 struct input_dev *kbd;
33 struct input_dev *ptr;
34 struct xenkbd_page *page;
35 int irq;
36 struct xenbus_device *xbdev;
37 char phys[32];
38};
39
40static int xenkbd_remove(struct xenbus_device *);
41static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *);
42static void xenkbd_disconnect_backend(struct xenkbd_info *);
43
44/*
45 * Note: if you need to send out events, see xenfb_do_update() for how
46 * to do that.
47 */
48
49static irqreturn_t input_handler(int rq, void *dev_id)
50{
51 struct xenkbd_info *info = dev_id;
52 struct xenkbd_page *page = info->page;
53 __u32 cons, prod;
54
55 prod = page->in_prod;
56 if (prod == page->in_cons)
57 return IRQ_HANDLED;
58 rmb(); /* ensure we see ring contents up to prod */
59 for (cons = page->in_cons; cons != prod; cons++) {
60 union xenkbd_in_event *event;
61 struct input_dev *dev;
62 event = &XENKBD_IN_RING_REF(page, cons);
63
64 dev = info->ptr;
65 switch (event->type) {
66 case XENKBD_TYPE_MOTION:
67 input_report_rel(dev, REL_X, event->motion.rel_x);
68 input_report_rel(dev, REL_Y, event->motion.rel_y);
69 break;
70 case XENKBD_TYPE_KEY:
71 dev = NULL;
72 if (test_bit(event->key.keycode, info->kbd->keybit))
73 dev = info->kbd;
74 if (test_bit(event->key.keycode, info->ptr->keybit))
75 dev = info->ptr;
76 if (dev)
77 input_report_key(dev, event->key.keycode,
78 event->key.pressed);
79 else
80 printk(KERN_WARNING
81 "xenkbd: unhandled keycode 0x%x\n",
82 event->key.keycode);
83 break;
84 case XENKBD_TYPE_POS:
85 input_report_abs(dev, ABS_X, event->pos.abs_x);
86 input_report_abs(dev, ABS_Y, event->pos.abs_y);
87 break;
88 }
89 if (dev)
90 input_sync(dev);
91 }
92 mb(); /* ensure we got ring contents */
93 page->in_cons = cons;
94 notify_remote_via_irq(info->irq);
95
96 return IRQ_HANDLED;
97}
98
99static int __devinit xenkbd_probe(struct xenbus_device *dev,
100 const struct xenbus_device_id *id)
101{
102 int ret, i;
103 struct xenkbd_info *info;
104 struct input_dev *kbd, *ptr;
105
106 info = kzalloc(sizeof(*info), GFP_KERNEL);
107 if (!info) {
108 xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
109 return -ENOMEM;
110 }
111 dev->dev.driver_data = info;
112 info->xbdev = dev;
113 info->irq = -1;
114 snprintf(info->phys, sizeof(info->phys), "xenbus/%s", dev->nodename);
115
116 info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
117 if (!info->page)
118 goto error_nomem;
119
120 /* keyboard */
121 kbd = input_allocate_device();
122 if (!kbd)
123 goto error_nomem;
124 kbd->name = "Xen Virtual Keyboard";
125 kbd->phys = info->phys;
126 kbd->id.bustype = BUS_PCI;
127 kbd->id.vendor = 0x5853;
128 kbd->id.product = 0xffff;
129 kbd->evbit[0] = BIT(EV_KEY);
130 for (i = KEY_ESC; i < KEY_UNKNOWN; i++)
131 set_bit(i, kbd->keybit);
132 for (i = KEY_OK; i < KEY_MAX; i++)
133 set_bit(i, kbd->keybit);
134
135 ret = input_register_device(kbd);
136 if (ret) {
137 input_free_device(kbd);
138 xenbus_dev_fatal(dev, ret, "input_register_device(kbd)");
139 goto error;
140 }
141 info->kbd = kbd;
142
143 /* pointing device */
144 ptr = input_allocate_device();
145 if (!ptr)
146 goto error_nomem;
147 ptr->name = "Xen Virtual Pointer";
148 ptr->phys = info->phys;
149 ptr->id.bustype = BUS_PCI;
150 ptr->id.vendor = 0x5853;
151 ptr->id.product = 0xfffe;
152 ptr->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);
153 for (i = BTN_LEFT; i <= BTN_TASK; i++)
154 set_bit(i, ptr->keybit);
155 ptr->relbit[0] = BIT(REL_X) | BIT(REL_Y);
156 input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0);
157 input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0);
158
159 ret = input_register_device(ptr);
160 if (ret) {
161 input_free_device(ptr);
162 xenbus_dev_fatal(dev, ret, "input_register_device(ptr)");
163 goto error;
164 }
165 info->ptr = ptr;
166
167 ret = xenkbd_connect_backend(dev, info);
168 if (ret < 0)
169 goto error;
170
171 return 0;
172
173 error_nomem:
174 ret = -ENOMEM;
175 xenbus_dev_fatal(dev, ret, "allocating device memory");
176 error:
177 xenkbd_remove(dev);
178 return ret;
179}
180
181static int xenkbd_resume(struct xenbus_device *dev)
182{
183 struct xenkbd_info *info = dev->dev.driver_data;
184
185 xenkbd_disconnect_backend(info);
186 memset(info->page, 0, PAGE_SIZE);
187 return xenkbd_connect_backend(dev, info);
188}
189
190static int xenkbd_remove(struct xenbus_device *dev)
191{
192 struct xenkbd_info *info = dev->dev.driver_data;
193
194 xenkbd_disconnect_backend(info);
195 if (info->kbd)
196 input_unregister_device(info->kbd);
197 if (info->ptr)
198 input_unregister_device(info->ptr);
199 free_page((unsigned long)info->page);
200 kfree(info);
201 return 0;
202}
203
204static int xenkbd_connect_backend(struct xenbus_device *dev,
205 struct xenkbd_info *info)
206{
207 int ret, evtchn;
208 struct xenbus_transaction xbt;
209
210 ret = xenbus_alloc_evtchn(dev, &evtchn);
211 if (ret)
212 return ret;
213 ret = bind_evtchn_to_irqhandler(evtchn, input_handler,
214 0, dev->devicetype, info);
215 if (ret < 0) {
216 xenbus_free_evtchn(dev, evtchn);
217 xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler");
218 return ret;
219 }
220 info->irq = ret;
221
222 again:
223 ret = xenbus_transaction_start(&xbt);
224 if (ret) {
225 xenbus_dev_fatal(dev, ret, "starting transaction");
226 return ret;
227 }
228 ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
229 virt_to_mfn(info->page));
230 if (ret)
231 goto error_xenbus;
232 ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
233 evtchn);
234 if (ret)
235 goto error_xenbus;
236 ret = xenbus_transaction_end(xbt, 0);
237 if (ret) {
238 if (ret == -EAGAIN)
239 goto again;
240 xenbus_dev_fatal(dev, ret, "completing transaction");
241 return ret;
242 }
243
244 xenbus_switch_state(dev, XenbusStateInitialised);
245 return 0;
246
247 error_xenbus:
248 xenbus_transaction_end(xbt, 1);
249 xenbus_dev_fatal(dev, ret, "writing xenstore");
250 return ret;
251}
252
253static void xenkbd_disconnect_backend(struct xenkbd_info *info)
254{
255 if (info->irq >= 0)
256 unbind_from_irqhandler(info->irq, info);
257 info->irq = -1;
258}
259
260static void xenkbd_backend_changed(struct xenbus_device *dev,
261 enum xenbus_state backend_state)
262{
263 struct xenkbd_info *info = dev->dev.driver_data;
264 int ret, val;
265
266 switch (backend_state) {
267 case XenbusStateInitialising:
268 case XenbusStateInitialised:
269 case XenbusStateUnknown:
270 case XenbusStateClosed:
271 break;
272
273 case XenbusStateInitWait:
274InitWait:
275 ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend,
276 "feature-abs-pointer", "%d", &val);
277 if (ret < 0)
278 val = 0;
279 if (val) {
280 ret = xenbus_printf(XBT_NIL, info->xbdev->nodename,
281 "request-abs-pointer", "1");
282 if (ret)
283 printk(KERN_WARNING
284 "xenkbd: can't request abs-pointer");
285 }
286 xenbus_switch_state(dev, XenbusStateConnected);
287 break;
288
289 case XenbusStateConnected:
290 /*
291 * Work around xenbus race condition: If backend goes
292 * through InitWait to Connected fast enough, we can
293 * get Connected twice here.
294 */
295 if (dev->state != XenbusStateConnected)
296 goto InitWait; /* no InitWait seen yet, fudge it */
297 break;
298
299 case XenbusStateClosing:
300 xenbus_frontend_closed(dev);
301 break;
302 }
303}
304
305static struct xenbus_device_id xenkbd_ids[] = {
306 { "vkbd" },
307 { "" }
308};
309
310static struct xenbus_driver xenkbd = {
311 .name = "vkbd",
312 .owner = THIS_MODULE,
313 .ids = xenkbd_ids,
314 .probe = xenkbd_probe,
315 .remove = xenkbd_remove,
316 .resume = xenkbd_resume,
317 .otherend_changed = xenkbd_backend_changed,
318};
319
320static int __init xenkbd_init(void)
321{
322 if (!is_running_on_xen())
323 return -ENODEV;
324
325 /* Nothing to do if running in dom0. */
326 if (is_initial_xendomain())
327 return -ENODEV;
328
329 return xenbus_register_frontend(&xenkbd);
330}
331
332static void __exit xenkbd_cleanup(void)
333{
334 xenbus_unregister_driver(&xenkbd);
335}
336
337module_init(xenkbd_init);
338module_exit(xenkbd_cleanup);
339
340MODULE_LICENSE("GPL");