aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/serio
diff options
context:
space:
mode:
authorHaavard Skinnemoen <haavard.skinnemoen@atmel.com>2008-07-27 07:54:08 -0400
committerHaavard Skinnemoen <haavard.skinnemoen@atmel.com>2008-07-27 07:54:08 -0400
commiteda3d8f5604860aae1bb9996bb5efc4213778369 (patch)
tree9d3887d2665bcc5f5abf200758794545c7b2c69b /drivers/input/serio
parent87a9f704658a40940e740b1d73d861667e9164d3 (diff)
parent8be1a6d6c77ab4532e4476fdb8177030ef48b52c (diff)
Merge commit 'upstream/master'
Diffstat (limited to 'drivers/input/serio')
-rw-r--r--drivers/input/serio/Kconfig10
-rw-r--r--drivers/input/serio/Makefile1
-rw-r--r--drivers/input/serio/ct82c710.c2
-rw-r--r--drivers/input/serio/hil_mlc.c6
-rw-r--r--drivers/input/serio/hp_sdc.c11
-rw-r--r--drivers/input/serio/hp_sdc_mlc.c2
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h67
-rw-r--r--drivers/input/serio/libps2.c52
-rw-r--r--drivers/input/serio/q40kbd.c4
-rw-r--r--drivers/input/serio/rpckbd.c2
-rw-r--r--drivers/input/serio/serio.c9
-rw-r--r--drivers/input/serio/serport.c2
-rw-r--r--drivers/input/serio/xilinx_ps2.c380
13 files changed, 469 insertions, 79 deletions
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index ec4b6610f730..27d70d326ff3 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -190,4 +190,14 @@ config SERIO_RAW
190 To compile this driver as a module, choose M here: the 190 To compile this driver as a module, choose M here: the
191 module will be called serio_raw. 191 module will be called serio_raw.
192 192
193config SERIO_XILINX_XPS_PS2
194 tristate "Xilinx XPS PS/2 Controller Support"
195 depends on PPC
196 help
197 This driver supports XPS PS/2 IP from the Xilinx EDK on
198 PowerPC platform.
199
200 To compile this driver as a module, choose M here: the
201 module will be called xilinx_ps2.
202
193endif 203endif
diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
index 38b886887cbc..9b6c8135955f 100644
--- a/drivers/input/serio/Makefile
+++ b/drivers/input/serio/Makefile
@@ -21,3 +21,4 @@ obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o
21obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o 21obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o
22obj-$(CONFIG_SERIO_LIBPS2) += libps2.o 22obj-$(CONFIG_SERIO_LIBPS2) += libps2.o
23obj-$(CONFIG_SERIO_RAW) += serio_raw.o 23obj-$(CONFIG_SERIO_RAW) += serio_raw.o
24obj-$(CONFIG_SERIO_XILINX_XPS_PS2) += xilinx_ps2.o
diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c
index 0d35018c23a9..d1380fc72cc6 100644
--- a/drivers/input/serio/ct82c710.c
+++ b/drivers/input/serio/ct82c710.c
@@ -1,6 +1,4 @@
1/* 1/*
2 * $Id: ct82c710.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $
3 *
4 * Copyright (c) 1999-2001 Vojtech Pavlik 2 * Copyright (c) 1999-2001 Vojtech Pavlik
5 */ 3 */
6 4
diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c
index 93a1a6ba216a..37586a68d345 100644
--- a/drivers/input/serio/hil_mlc.c
+++ b/drivers/input/serio/hil_mlc.c
@@ -76,7 +76,7 @@ static struct timer_list hil_mlcs_kicker;
76static int hil_mlcs_probe; 76static int hil_mlcs_probe;
77 77
78static void hil_mlcs_process(unsigned long unused); 78static void hil_mlcs_process(unsigned long unused);
79DECLARE_TASKLET_DISABLED(hil_mlcs_tasklet, hil_mlcs_process, 0); 79static DECLARE_TASKLET_DISABLED(hil_mlcs_tasklet, hil_mlcs_process, 0);
80 80
81 81
82/* #define HIL_MLC_DEBUG */ 82/* #define HIL_MLC_DEBUG */
@@ -459,7 +459,7 @@ static int hilse_operate(hil_mlc *mlc, int repoll)
459#define OUT_LAST(pack) \ 459#define OUT_LAST(pack) \
460{ HILSE_OUT_LAST, { .packet = pack }, 0, 0, 0, 0 }, 460{ HILSE_OUT_LAST, { .packet = pack }, 0, 0, 0, 0 },
461 461
462const struct hilse_node hil_mlc_se[HILSEN_END] = { 462static const struct hilse_node hil_mlc_se[HILSEN_END] = {
463 463
464 /* 0 HILSEN_START */ 464 /* 0 HILSEN_START */
465 FUNC(hilse_init_lcv, 0, HILSEN_NEXT, HILSEN_SLEEP, 0) 465 FUNC(hilse_init_lcv, 0, HILSEN_NEXT, HILSEN_SLEEP, 0)
@@ -784,7 +784,7 @@ static void hil_mlcs_process(unsigned long unused)
784 784
785/************************* Keepalive timer task *********************/ 785/************************* Keepalive timer task *********************/
786 786
787void hil_mlcs_timer(unsigned long data) 787static void hil_mlcs_timer(unsigned long data)
788{ 788{
789 hil_mlcs_probe = 1; 789 hil_mlcs_probe = 1;
790 tasklet_schedule(&hil_mlcs_tasklet); 790 tasklet_schedule(&hil_mlcs_tasklet);
diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c
index edfedd9a166c..0d395979b2d1 100644
--- a/drivers/input/serio/hp_sdc.c
+++ b/drivers/input/serio/hp_sdc.c
@@ -67,9 +67,9 @@
67#include <linux/module.h> 67#include <linux/module.h>
68#include <linux/ioport.h> 68#include <linux/ioport.h>
69#include <linux/time.h> 69#include <linux/time.h>
70#include <linux/semaphore.h>
70#include <linux/slab.h> 71#include <linux/slab.h>
71#include <linux/hil.h> 72#include <linux/hil.h>
72#include <linux/semaphore.h>
73#include <asm/io.h> 73#include <asm/io.h>
74#include <asm/system.h> 74#include <asm/system.h>
75 75
@@ -105,6 +105,10 @@ EXPORT_SYMBOL(__hp_sdc_enqueue_transaction);
105EXPORT_SYMBOL(hp_sdc_enqueue_transaction); 105EXPORT_SYMBOL(hp_sdc_enqueue_transaction);
106EXPORT_SYMBOL(hp_sdc_dequeue_transaction); 106EXPORT_SYMBOL(hp_sdc_dequeue_transaction);
107 107
108static unsigned int hp_sdc_disabled;
109module_param_named(no_hpsdc, hp_sdc_disabled, bool, 0);
110MODULE_PARM_DESC(no_hpsdc, "Do not enable HP SDC driver.");
111
108static hp_i8042_sdc hp_sdc; /* All driver state is kept in here. */ 112static hp_i8042_sdc hp_sdc; /* All driver state is kept in here. */
109 113
110/*************** primitives for use in any context *********************/ 114/*************** primitives for use in any context *********************/
@@ -980,6 +984,11 @@ static int __init hp_sdc_register(void)
980 unsigned char i; 984 unsigned char i;
981#endif 985#endif
982 986
987 if (hp_sdc_disabled) {
988 printk(KERN_WARNING PREFIX "HP SDC driver disabled by no_hpsdc=1.\n");
989 return -ENODEV;
990 }
991
983 hp_sdc.dev = NULL; 992 hp_sdc.dev = NULL;
984 hp_sdc.dev_err = 0; 993 hp_sdc.dev_err = 0;
985#if defined(__hppa__) 994#if defined(__hppa__)
diff --git a/drivers/input/serio/hp_sdc_mlc.c b/drivers/input/serio/hp_sdc_mlc.c
index 587398f5c9df..b587e2d576ac 100644
--- a/drivers/input/serio/hp_sdc_mlc.c
+++ b/drivers/input/serio/hp_sdc_mlc.c
@@ -50,7 +50,7 @@ MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
50MODULE_DESCRIPTION("Glue for onboard HIL MLC in HP-PARISC machines"); 50MODULE_DESCRIPTION("Glue for onboard HIL MLC in HP-PARISC machines");
51MODULE_LICENSE("Dual BSD/GPL"); 51MODULE_LICENSE("Dual BSD/GPL");
52 52
53struct hp_sdc_mlc_priv_s { 53static struct hp_sdc_mlc_priv_s {
54 int emtestmode; 54 int emtestmode;
55 hp_sdc_transaction trans; 55 hp_sdc_transaction trans;
56 u8 tseq[16]; 56 u8 tseq[16];
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 78eb7841174c..fe732a574ec2 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -63,13 +63,22 @@ static inline void i8042_write_command(int val)
63 outb(val, I8042_COMMAND_REG); 63 outb(val, I8042_COMMAND_REG);
64} 64}
65 65
66#if defined(__i386__) || defined(__x86_64__) 66#ifdef CONFIG_X86
67 67
68#include <linux/dmi.h> 68#include <linux/dmi.h>
69 69
70static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { 70static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
71 { 71 {
72 /* AUX LOOP command does not raise AUX IRQ */ 72 /* AUX LOOP command does not raise AUX IRQ */
73 .ident = "Arima-Rioworks HDAMB",
74 .matches = {
75 DMI_MATCH(DMI_BOARD_VENDOR, "RIOWORKS"),
76 DMI_MATCH(DMI_BOARD_NAME, "HDAMB"),
77 DMI_MATCH(DMI_BOARD_VERSION, "Rev E"),
78 },
79 },
80 {
81 /* AUX LOOP command does not raise AUX IRQ */
73 .ident = "ASUS P65UP5", 82 .ident = "ASUS P65UP5",
74 .matches = { 83 .matches = {
75 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), 84 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
@@ -118,6 +127,14 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
118 DMI_MATCH(DMI_PRODUCT_VERSION, "VS2005R2"), 127 DMI_MATCH(DMI_PRODUCT_VERSION, "VS2005R2"),
119 }, 128 },
120 }, 129 },
130 {
131 .ident = "Medion MAM 2070",
132 .matches = {
133 DMI_MATCH(DMI_SYS_VENDOR, "Notebook"),
134 DMI_MATCH(DMI_PRODUCT_NAME, "MAM 2070"),
135 DMI_MATCH(DMI_PRODUCT_VERSION, "5a"),
136 },
137 },
121 { } 138 { }
122}; 139};
123 140
@@ -291,17 +308,36 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
291 DMI_MATCH(DMI_PRODUCT_VERSION, "3000 N100"), 308 DMI_MATCH(DMI_PRODUCT_VERSION, "3000 N100"),
292 }, 309 },
293 }, 310 },
311 {
312 .ident = "Acer Aspire 1360",
313 .matches = {
314 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
315 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"),
316 },
317 },
318 {
319 .ident = "Gericom Bellagio",
320 .matches = {
321 DMI_MATCH(DMI_SYS_VENDOR, "Gericom"),
322 DMI_MATCH(DMI_PRODUCT_NAME, "N34AS6"),
323 },
324 },
294 { } 325 { }
295}; 326};
296 327
297 328#ifdef CONFIG_PNP
298 329static struct dmi_system_id __initdata i8042_dmi_nopnp_table[] = {
330 {
331 .ident = "Intel MBO Desktop D845PESV",
332 .matches = {
333 DMI_MATCH(DMI_BOARD_NAME, "D845PESV"),
334 DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
335 },
336 },
337 { }
338};
299#endif 339#endif
300 340
301#ifdef CONFIG_X86
302
303#include <linux/dmi.h>
304
305/* 341/*
306 * Some Wistron based laptops need us to explicitly enable the 'Dritek 342 * Some Wistron based laptops need us to explicitly enable the 'Dritek
307 * keyboard extension' to make their extra keys start generating scancodes. 343 * keyboard extension' to make their extra keys start generating scancodes.
@@ -331,6 +367,13 @@ static struct dmi_system_id __initdata i8042_dmi_dritek_table[] = {
331 }, 367 },
332 }, 368 },
333 { 369 {
370 .ident = "Acer Aspire 5720",
371 .matches = {
372 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
373 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5720"),
374 },
375 },
376 {
334 .ident = "Acer Aspire 9110", 377 .ident = "Acer Aspire 9110",
335 .matches = { 378 .matches = {
336 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 379 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
@@ -356,7 +399,6 @@ static struct dmi_system_id __initdata i8042_dmi_dritek_table[] = {
356 399
357#endif /* CONFIG_X86 */ 400#endif /* CONFIG_X86 */
358 401
359
360#ifdef CONFIG_PNP 402#ifdef CONFIG_PNP
361#include <linux/pnp.h> 403#include <linux/pnp.h>
362 404
@@ -466,6 +508,11 @@ static int __init i8042_pnp_init(void)
466 int pnp_data_busted = 0; 508 int pnp_data_busted = 0;
467 int err; 509 int err;
468 510
511#ifdef CONFIG_X86
512 if (dmi_check_system(i8042_dmi_nopnp_table))
513 i8042_nopnp = 1;
514#endif
515
469 if (i8042_nopnp) { 516 if (i8042_nopnp) {
470 printk(KERN_INFO "i8042: PNP detection disabled\n"); 517 printk(KERN_INFO "i8042: PNP detection disabled\n");
471 return 0; 518 return 0;
@@ -591,15 +638,13 @@ static int __init i8042_platform_init(void)
591 i8042_reset = 1; 638 i8042_reset = 1;
592#endif 639#endif
593 640
594#if defined(__i386__) || defined(__x86_64__) 641#ifdef CONFIG_X86
595 if (dmi_check_system(i8042_dmi_noloop_table)) 642 if (dmi_check_system(i8042_dmi_noloop_table))
596 i8042_noloop = 1; 643 i8042_noloop = 1;
597 644
598 if (dmi_check_system(i8042_dmi_nomux_table)) 645 if (dmi_check_system(i8042_dmi_nomux_table))
599 i8042_nomux = 1; 646 i8042_nomux = 1;
600#endif
601 647
602#ifdef CONFIG_X86
603 if (dmi_check_system(i8042_dmi_dritek_table)) 648 if (dmi_check_system(i8042_dmi_dritek_table))
604 i8042_dritek = 1; 649 i8042_dritek = 1;
605#endif /* CONFIG_X86 */ 650#endif /* CONFIG_X86 */
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
index b819239d74dc..2b304c22c200 100644
--- a/drivers/input/serio/libps2.c
+++ b/drivers/input/serio/libps2.c
@@ -26,15 +26,6 @@ MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
26MODULE_DESCRIPTION("PS/2 driver library"); 26MODULE_DESCRIPTION("PS/2 driver library");
27MODULE_LICENSE("GPL"); 27MODULE_LICENSE("GPL");
28 28
29/* Work structure to schedule execution of a command */
30struct ps2work {
31 struct work_struct work;
32 struct ps2dev *ps2dev;
33 int command;
34 unsigned char param[0];
35};
36
37
38/* 29/*
39 * ps2_sendbyte() sends a byte to the device and waits for acknowledge. 30 * ps2_sendbyte() sends a byte to the device and waits for acknowledge.
40 * It doesn't handle retransmission, though it could - because if there 31 * It doesn't handle retransmission, though it could - because if there
@@ -246,49 +237,6 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
246EXPORT_SYMBOL(ps2_command); 237EXPORT_SYMBOL(ps2_command);
247 238
248/* 239/*
249 * ps2_execute_scheduled_command() sends a command, previously scheduled by
250 * ps2_schedule_command(), to a PS/2 device (keyboard, mouse, etc.)
251 */
252
253static void ps2_execute_scheduled_command(struct work_struct *work)
254{
255 struct ps2work *ps2work = container_of(work, struct ps2work, work);
256
257 ps2_command(ps2work->ps2dev, ps2work->param, ps2work->command);
258 kfree(ps2work);
259}
260
261/*
262 * ps2_schedule_command() allows to schedule delayed execution of a PS/2
263 * command and can be used to issue a command from an interrupt or softirq
264 * context.
265 */
266
267int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int command)
268{
269 struct ps2work *ps2work;
270 int send = (command >> 12) & 0xf;
271 int receive = (command >> 8) & 0xf;
272
273 if (!(ps2work = kmalloc(sizeof(struct ps2work) + max(send, receive), GFP_ATOMIC)))
274 return -1;
275
276 memset(ps2work, 0, sizeof(struct ps2work));
277 ps2work->ps2dev = ps2dev;
278 ps2work->command = command;
279 memcpy(ps2work->param, param, send);
280 INIT_WORK(&ps2work->work, ps2_execute_scheduled_command);
281
282 if (!schedule_work(&ps2work->work)) {
283 kfree(ps2work);
284 return -1;
285 }
286
287 return 0;
288}
289EXPORT_SYMBOL(ps2_schedule_command);
290
291/*
292 * ps2_init() initializes ps2dev structure 240 * ps2_init() initializes ps2dev structure
293 */ 241 */
294 242
diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c
index d962a8d78b14..e36a0901646c 100644
--- a/drivers/input/serio/q40kbd.c
+++ b/drivers/input/serio/q40kbd.c
@@ -1,6 +1,4 @@
1/* 1/*
2 * $Id: q40kbd.c,v 1.12 2002/02/02 22:26:44 vojtech Exp $
3 *
4 * Copyright (c) 2000-2001 Vojtech Pavlik 2 * Copyright (c) 2000-2001 Vojtech Pavlik
5 * 3 *
6 * Based on the work of: 4 * Based on the work of:
@@ -49,7 +47,7 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
49MODULE_DESCRIPTION("Q40 PS/2 keyboard controller driver"); 47MODULE_DESCRIPTION("Q40 PS/2 keyboard controller driver");
50MODULE_LICENSE("GPL"); 48MODULE_LICENSE("GPL");
51 49
52DEFINE_SPINLOCK(q40kbd_lock); 50static DEFINE_SPINLOCK(q40kbd_lock);
53static struct serio *q40kbd_port; 51static struct serio *q40kbd_port;
54static struct platform_device *q40kbd_device; 52static struct platform_device *q40kbd_device;
55 53
diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c
index 34c59d9c6205..1567b7782478 100644
--- a/drivers/input/serio/rpckbd.c
+++ b/drivers/input/serio/rpckbd.c
@@ -1,6 +1,4 @@
1/* 1/*
2 * $Id: rpckbd.c,v 1.7 2001/09/25 10:12:07 vojtech Exp $
3 *
4 * Copyright (c) 2000-2001 Vojtech Pavlik 2 * Copyright (c) 2000-2001 Vojtech Pavlik
5 * Copyright (c) 2002 Russell King 3 * Copyright (c) 2002 Russell King
6 */ 4 */
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index 7f5293828fbf..78f2abb5c11b 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -331,9 +331,10 @@ static void serio_handle_event(void)
331} 331}
332 332
333/* 333/*
334 * Remove all events that have been submitted for a given serio port. 334 * Remove all events that have been submitted for a given
335 * object, be it serio port or driver.
335 */ 336 */
336static void serio_remove_pending_events(struct serio *serio) 337static void serio_remove_pending_events(void *object)
337{ 338{
338 struct list_head *node, *next; 339 struct list_head *node, *next;
339 struct serio_event *event; 340 struct serio_event *event;
@@ -343,7 +344,7 @@ static void serio_remove_pending_events(struct serio *serio)
343 344
344 list_for_each_safe(node, next, &serio_event_list) { 345 list_for_each_safe(node, next, &serio_event_list) {
345 event = list_entry(node, struct serio_event, node); 346 event = list_entry(node, struct serio_event, node);
346 if (event->object == serio) { 347 if (event->object == object) {
347 list_del_init(node); 348 list_del_init(node);
348 serio_free_event(event); 349 serio_free_event(event);
349 } 350 }
@@ -837,7 +838,9 @@ void serio_unregister_driver(struct serio_driver *drv)
837 struct serio *serio; 838 struct serio *serio;
838 839
839 mutex_lock(&serio_mutex); 840 mutex_lock(&serio_mutex);
841
840 drv->manual_bind = 1; /* so serio_find_driver ignores it */ 842 drv->manual_bind = 1; /* so serio_find_driver ignores it */
843 serio_remove_pending_events(drv);
841 844
842start_over: 845start_over:
843 list_for_each_entry(serio, &serio_list, node) { 846 list_for_each_entry(serio, &serio_list, node) {
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
index 7ff71ba7b7c9..b9694b6445d0 100644
--- a/drivers/input/serio/serport.c
+++ b/drivers/input/serio/serport.c
@@ -216,7 +216,7 @@ static void serport_ldisc_write_wakeup(struct tty_struct * tty)
216 * The line discipline structure. 216 * The line discipline structure.
217 */ 217 */
218 218
219static struct tty_ldisc serport_ldisc = { 219static struct tty_ldisc_ops serport_ldisc = {
220 .owner = THIS_MODULE, 220 .owner = THIS_MODULE,
221 .name = "input", 221 .name = "input",
222 .open = serport_ldisc_open, 222 .open = serport_ldisc_open,
diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c
new file mode 100644
index 000000000000..0ed044d5e685
--- /dev/null
+++ b/drivers/input/serio/xilinx_ps2.c
@@ -0,0 +1,380 @@
1/*
2 * Xilinx XPS PS/2 device driver
3 *
4 * (c) 2005 MontaVista Software, Inc.
5 * (c) 2008 Xilinx, Inc.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 *
12 * You should have received a copy of the GNU General Public License along
13 * with this program; if not, write to the Free Software Foundation, Inc.,
14 * 675 Mass Ave, Cambridge, MA 02139, USA.
15 */
16
17
18#include <linux/module.h>
19#include <linux/serio.h>
20#include <linux/interrupt.h>
21#include <linux/errno.h>
22#include <linux/init.h>
23#include <linux/list.h>
24#include <linux/io.h>
25
26#include <linux/of_device.h>
27#include <linux/of_platform.h>
28
29#define DRIVER_NAME "xilinx_ps2"
30
31/* Register offsets for the xps2 device */
32#define XPS2_SRST_OFFSET 0x00000000 /* Software Reset register */
33#define XPS2_STATUS_OFFSET 0x00000004 /* Status register */
34#define XPS2_RX_DATA_OFFSET 0x00000008 /* Receive Data register */
35#define XPS2_TX_DATA_OFFSET 0x0000000C /* Transmit Data register */
36#define XPS2_GIER_OFFSET 0x0000002C /* Global Interrupt Enable reg */
37#define XPS2_IPISR_OFFSET 0x00000030 /* Interrupt Status register */
38#define XPS2_IPIER_OFFSET 0x00000038 /* Interrupt Enable register */
39
40/* Reset Register Bit Definitions */
41#define XPS2_SRST_RESET 0x0000000A /* Software Reset */
42
43/* Status Register Bit Positions */
44#define XPS2_STATUS_RX_FULL 0x00000001 /* Receive Full */
45#define XPS2_STATUS_TX_FULL 0x00000002 /* Transmit Full */
46
47/* Bit definitions for ISR/IER registers. Both the registers have the same bit
48 * definitions and are only defined once. */
49#define XPS2_IPIXR_WDT_TOUT 0x00000001 /* Watchdog Timeout Interrupt */
50#define XPS2_IPIXR_TX_NOACK 0x00000002 /* Transmit No ACK Interrupt */
51#define XPS2_IPIXR_TX_ACK 0x00000004 /* Transmit ACK (Data) Interrupt */
52#define XPS2_IPIXR_RX_OVF 0x00000008 /* Receive Overflow Interrupt */
53#define XPS2_IPIXR_RX_ERR 0x00000010 /* Receive Error Interrupt */
54#define XPS2_IPIXR_RX_FULL 0x00000020 /* Receive Data Interrupt */
55
56/* Mask for all the Transmit Interrupts */
57#define XPS2_IPIXR_TX_ALL (XPS2_IPIXR_TX_NOACK | XPS2_IPIXR_TX_ACK)
58
59/* Mask for all the Receive Interrupts */
60#define XPS2_IPIXR_RX_ALL (XPS2_IPIXR_RX_OVF | XPS2_IPIXR_RX_ERR | \
61 XPS2_IPIXR_RX_FULL)
62
63/* Mask for all the Interrupts */
64#define XPS2_IPIXR_ALL (XPS2_IPIXR_TX_ALL | XPS2_IPIXR_RX_ALL | \
65 XPS2_IPIXR_WDT_TOUT)
66
67/* Global Interrupt Enable mask */
68#define XPS2_GIER_GIE_MASK 0x80000000
69
70struct xps2data {
71 int irq;
72 u32 phys_addr;
73 u32 remap_size;
74 spinlock_t lock;
75 u8 rxb; /* Rx buffer */
76 void __iomem *base_address; /* virt. address of control registers */
77 unsigned int dfl;
78 struct serio serio; /* serio */
79};
80
81/************************************/
82/* XPS PS/2 data transmission calls */
83/************************************/
84
85/*
86 * xps2_recv() will attempt to receive a byte of data from the PS/2 port.
87 */
88static int xps2_recv(struct xps2data *drvdata, u8 *byte)
89{
90 u32 sr;
91 int status = -1;
92
93 /* If there is data available in the PS/2 receiver, read it */
94 sr = in_be32(drvdata->base_address + XPS2_STATUS_OFFSET);
95 if (sr & XPS2_STATUS_RX_FULL) {
96 *byte = in_be32(drvdata->base_address + XPS2_RX_DATA_OFFSET);
97 status = 0;
98 }
99
100 return status;
101}
102
103/*********************/
104/* Interrupt handler */
105/*********************/
106static irqreturn_t xps2_interrupt(int irq, void *dev_id)
107{
108 struct xps2data *drvdata = dev_id;
109 u32 intr_sr;
110 u8 c;
111 int status;
112
113 /* Get the PS/2 interrupts and clear them */
114 intr_sr = in_be32(drvdata->base_address + XPS2_IPISR_OFFSET);
115 out_be32(drvdata->base_address + XPS2_IPISR_OFFSET, intr_sr);
116
117 /* Check which interrupt is active */
118 if (intr_sr & XPS2_IPIXR_RX_OVF)
119 printk(KERN_WARNING "%s: receive overrun error\n",
120 drvdata->serio.name);
121
122 if (intr_sr & XPS2_IPIXR_RX_ERR)
123 drvdata->dfl |= SERIO_PARITY;
124
125 if (intr_sr & (XPS2_IPIXR_TX_NOACK | XPS2_IPIXR_WDT_TOUT))
126 drvdata->dfl |= SERIO_TIMEOUT;
127
128 if (intr_sr & XPS2_IPIXR_RX_FULL) {
129 status = xps2_recv(drvdata, &drvdata->rxb);
130
131 /* Error, if a byte is not received */
132 if (status) {
133 printk(KERN_ERR
134 "%s: wrong rcvd byte count (%d)\n",
135 drvdata->serio.name, status);
136 } else {
137 c = drvdata->rxb;
138 serio_interrupt(&drvdata->serio, c, drvdata->dfl);
139 drvdata->dfl = 0;
140 }
141 }
142
143 if (intr_sr & XPS2_IPIXR_TX_ACK)
144 drvdata->dfl = 0;
145
146 return IRQ_HANDLED;
147}
148
149/*******************/
150/* serio callbacks */
151/*******************/
152
153/*
154 * sxps2_write() sends a byte out through the PS/2 interface.
155 */
156static int sxps2_write(struct serio *pserio, unsigned char c)
157{
158 struct xps2data *drvdata = pserio->port_data;
159 unsigned long flags;
160 u32 sr;
161 int status = -1;
162
163 spin_lock_irqsave(&drvdata->lock, flags);
164
165 /* If the PS/2 transmitter is empty send a byte of data */
166 sr = in_be32(drvdata->base_address + XPS2_STATUS_OFFSET);
167 if (!(sr & XPS2_STATUS_TX_FULL)) {
168 out_be32(drvdata->base_address + XPS2_TX_DATA_OFFSET, c);
169 status = 0;
170 }
171
172 spin_unlock_irqrestore(&drvdata->lock, flags);
173
174 return status;
175}
176
177/*
178 * sxps2_open() is called when a port is open by the higher layer.
179 */
180static int sxps2_open(struct serio *pserio)
181{
182 struct xps2data *drvdata = pserio->port_data;
183 int retval;
184
185 retval = request_irq(drvdata->irq, &xps2_interrupt, 0,
186 DRIVER_NAME, drvdata);
187 if (retval) {
188 printk(KERN_ERR
189 "%s: Couldn't allocate interrupt %d\n",
190 drvdata->serio.name, drvdata->irq);
191 return retval;
192 }
193
194 /* start reception by enabling the interrupts */
195 out_be32(drvdata->base_address + XPS2_GIER_OFFSET, XPS2_GIER_GIE_MASK);
196 out_be32(drvdata->base_address + XPS2_IPIER_OFFSET, XPS2_IPIXR_RX_ALL);
197 (void)xps2_recv(drvdata, &drvdata->rxb);
198
199 return 0; /* success */
200}
201
202/*
203 * sxps2_close() frees the interrupt.
204 */
205static void sxps2_close(struct serio *pserio)
206{
207 struct xps2data *drvdata = pserio->port_data;
208
209 /* Disable the PS2 interrupts */
210 out_be32(drvdata->base_address + XPS2_GIER_OFFSET, 0x00);
211 out_be32(drvdata->base_address + XPS2_IPIER_OFFSET, 0x00);
212 free_irq(drvdata->irq, drvdata);
213}
214
215/*********************/
216/* Device setup code */
217/*********************/
218
219static int xps2_setup(struct device *dev, struct resource *regs_res,
220 struct resource *irq_res)
221{
222 struct xps2data *drvdata;
223 struct serio *serio;
224 unsigned long remap_size;
225 int retval;
226
227 if (!dev)
228 return -EINVAL;
229
230 if (!regs_res || !irq_res) {
231 dev_err(dev, "IO resource(s) not found\n");
232 return -EINVAL;
233 }
234
235 drvdata = kzalloc(sizeof(struct xps2data), GFP_KERNEL);
236 if (!drvdata) {
237 dev_err(dev, "Couldn't allocate device private record\n");
238 return -ENOMEM;
239 }
240
241 dev_set_drvdata(dev, drvdata);
242
243 spin_lock_init(&drvdata->lock);
244 drvdata->irq = irq_res->start;
245
246 remap_size = regs_res->end - regs_res->start + 1;
247 if (!request_mem_region(regs_res->start, remap_size, DRIVER_NAME)) {
248 dev_err(dev, "Couldn't lock memory region at 0x%08X\n",
249 (unsigned int)regs_res->start);
250 retval = -EBUSY;
251 goto failed1;
252 }
253
254 /* Fill in configuration data and add them to the list */
255 drvdata->phys_addr = regs_res->start;
256 drvdata->remap_size = remap_size;
257 drvdata->base_address = ioremap(regs_res->start, remap_size);
258 if (drvdata->base_address == NULL) {
259 dev_err(dev, "Couldn't ioremap memory at 0x%08X\n",
260 (unsigned int)regs_res->start);
261 retval = -EFAULT;
262 goto failed2;
263 }
264
265 /* Disable all the interrupts, just in case */
266 out_be32(drvdata->base_address + XPS2_IPIER_OFFSET, 0);
267
268 /* Reset the PS2 device and abort any current transaction, to make sure
269 * we have the PS2 in a good state */
270 out_be32(drvdata->base_address + XPS2_SRST_OFFSET, XPS2_SRST_RESET);
271
272 dev_info(dev, "Xilinx PS2 at 0x%08X mapped to 0x%08X, irq=%d\n",
273 drvdata->phys_addr, (u32)drvdata->base_address, drvdata->irq);
274
275 serio = &drvdata->serio;
276 serio->id.type = SERIO_8042;
277 serio->write = sxps2_write;
278 serio->open = sxps2_open;
279 serio->close = sxps2_close;
280 serio->port_data = drvdata;
281 serio->dev.parent = dev;
282 snprintf(serio->name, sizeof(serio->name),
283 "Xilinx XPS PS/2 at %08X", drvdata->phys_addr);
284 snprintf(serio->phys, sizeof(serio->phys),
285 "xilinxps2/serio at %08X", drvdata->phys_addr);
286 serio_register_port(serio);
287
288 return 0; /* success */
289
290failed2:
291 release_mem_region(regs_res->start, remap_size);
292failed1:
293 kfree(drvdata);
294 dev_set_drvdata(dev, NULL);
295
296 return retval;
297}
298
299/***************************/
300/* OF Platform Bus Support */
301/***************************/
302
303static int __devinit xps2_of_probe(struct of_device *ofdev, const struct
304 of_device_id * match)
305{
306 struct resource r_irq; /* Interrupt resources */
307 struct resource r_mem; /* IO mem resources */
308 int rc = 0;
309
310 printk(KERN_INFO "Device Tree Probing \'%s\'\n",
311 ofdev->node->name);
312
313 /* Get iospace for the device */
314 rc = of_address_to_resource(ofdev->node, 0, &r_mem);
315 if (rc) {
316 dev_err(&ofdev->dev, "invalid address\n");
317 return rc;
318 }
319
320 /* Get IRQ for the device */
321 rc = of_irq_to_resource(ofdev->node, 0, &r_irq);
322 if (rc == NO_IRQ) {
323 dev_err(&ofdev->dev, "no IRQ found\n");
324 return rc;
325 }
326
327 return xps2_setup(&ofdev->dev, &r_mem, &r_irq);
328}
329
330static int __devexit xps2_of_remove(struct of_device *of_dev)
331{
332 struct device *dev = &of_dev->dev;
333 struct xps2data *drvdata;
334
335 if (!dev)
336 return -EINVAL;
337
338 drvdata = dev_get_drvdata(dev);
339
340 serio_unregister_port(&drvdata->serio);
341 iounmap(drvdata->base_address);
342 release_mem_region(drvdata->phys_addr, drvdata->remap_size);
343 kfree(drvdata);
344
345 dev_set_drvdata(dev, NULL);
346
347 return 0; /* success */
348}
349
350/* Match table for of_platform binding */
351static struct of_device_id xps2_of_match[] __devinitdata = {
352 { .compatible = "xlnx,xps-ps2-1.00.a", },
353 { /* end of list */ },
354};
355MODULE_DEVICE_TABLE(of, xps2_of_match);
356
357static struct of_platform_driver xps2_of_driver = {
358 .name = DRIVER_NAME,
359 .match_table = xps2_of_match,
360 .probe = xps2_of_probe,
361 .remove = __devexit_p(xps2_of_remove),
362};
363
364static int __init xps2_init(void)
365{
366 return of_register_platform_driver(&xps2_of_driver);
367}
368
369static void __exit xps2_cleanup(void)
370{
371 of_unregister_platform_driver(&xps2_of_driver);
372}
373
374module_init(xps2_init);
375module_exit(xps2_cleanup);
376
377MODULE_AUTHOR("Xilinx, Inc.");
378MODULE_DESCRIPTION("Xilinx XPS PS/2 driver");
379MODULE_LICENSE("GPL");
380