aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2012-01-23 02:27:54 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2012-01-23 03:02:31 -0500
commit409e15442fc7f7ae9d025f3ea3fdf3c60070314f (patch)
treeeac3828e0df5916e757b68f5b1fefa8488f94dc4 /drivers/input
parent3e8040b0a93cadeead148938188212ac7422a6bc (diff)
Input: q40kbd - convert driver to the split model
Convert the driver to standard spilt model arch-specific code registers platform device to which driver code can bind later. Also request IRQ immediately upon binding to the device instead of doing this when serio port is being opened. Acked-by: Geert Uytterhoeven <geert@linux-m68k.org> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/serio/q40kbd.c139
1 files changed, 79 insertions, 60 deletions
diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c
index 5eb84b3b67fb..0c0df7f73802 100644
--- a/drivers/input/serio/q40kbd.c
+++ b/drivers/input/serio/q40kbd.c
@@ -44,26 +44,31 @@
44#include <asm/irq.h> 44#include <asm/irq.h>
45#include <asm/q40ints.h> 45#include <asm/q40ints.h>
46 46
47#define DRV_NAME "q40kbd"
48
47MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); 49MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
48MODULE_DESCRIPTION("Q40 PS/2 keyboard controller driver"); 50MODULE_DESCRIPTION("Q40 PS/2 keyboard controller driver");
49MODULE_LICENSE("GPL"); 51MODULE_LICENSE("GPL");
52MODULE_ALIAS("platform:" DRV_NAME);
50 53
51static DEFINE_SPINLOCK(q40kbd_lock); 54struct q40kbd {
52static struct serio *q40kbd_port; 55 struct serio *port;
53static struct platform_device *q40kbd_device; 56 spinlock_t lock;
57};
54 58
55static irqreturn_t q40kbd_interrupt(int irq, void *dev_id) 59static irqreturn_t q40kbd_interrupt(int irq, void *dev_id)
56{ 60{
61 struct q40kbd *q40kbd = dev_id;
57 unsigned long flags; 62 unsigned long flags;
58 63
59 spin_lock_irqsave(&q40kbd_lock, flags); 64 spin_lock_irqsave(&q40kbd->lock, flags);
60 65
61 if (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG)) 66 if (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))
62 serio_interrupt(q40kbd_port, master_inb(KEYCODE_REG), 0); 67 serio_interrupt(q40kbd->port, master_inb(KEYCODE_REG), 0);
63 68
64 master_outb(-1, KEYBOARD_UNLOCK_REG); 69 master_outb(-1, KEYBOARD_UNLOCK_REG);
65 70
66 spin_unlock_irqrestore(&q40kbd_lock, flags); 71 spin_unlock_irqrestore(&q40kbd->lock, flags);
67 72
68 return IRQ_HANDLED; 73 return IRQ_HANDLED;
69} 74}
@@ -72,17 +77,23 @@ static irqreturn_t q40kbd_interrupt(int irq, void *dev_id)
72 * q40kbd_flush() flushes all data that may be in the keyboard buffers 77 * q40kbd_flush() flushes all data that may be in the keyboard buffers
73 */ 78 */
74 79
75static void q40kbd_flush(void) 80static void q40kbd_flush(struct q40kbd *q40kbd)
76{ 81{
77 int maxread = 100; 82 int maxread = 100;
78 unsigned long flags; 83 unsigned long flags;
79 84
80 spin_lock_irqsave(&q40kbd_lock, flags); 85 spin_lock_irqsave(&q40kbd->lock, flags);
81 86
82 while (maxread-- && (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))) 87 while (maxread-- && (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG)))
83 master_inb(KEYCODE_REG); 88 master_inb(KEYCODE_REG);
84 89
85 spin_unlock_irqrestore(&q40kbd_lock, flags); 90 spin_unlock_irqrestore(&q40kbd->lock, flags);
91}
92
93static void q40kbd_stop(void)
94{
95 master_outb(0, KEY_IRQ_ENABLE_REG);
96 master_outb(-1, KEYBOARD_UNLOCK_REG);
86} 97}
87 98
88/* 99/*
@@ -92,12 +103,9 @@ static void q40kbd_flush(void)
92 103
93static int q40kbd_open(struct serio *port) 104static int q40kbd_open(struct serio *port)
94{ 105{
95 q40kbd_flush(); 106 struct q40kbd *q40kbd = port->port_data;
96 107
97 if (request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0, "q40kbd", NULL)) { 108 q40kbd_flush(q40kbd);
98 printk(KERN_ERR "q40kbd.c: Can't get irq %d.\n", Q40_IRQ_KEYBOARD);
99 return -EBUSY;
100 }
101 109
102 /* off we go */ 110 /* off we go */
103 master_outb(-1, KEYBOARD_UNLOCK_REG); 111 master_outb(-1, KEYBOARD_UNLOCK_REG);
@@ -108,36 +116,72 @@ static int q40kbd_open(struct serio *port)
108 116
109static void q40kbd_close(struct serio *port) 117static void q40kbd_close(struct serio *port)
110{ 118{
111 master_outb(0, KEY_IRQ_ENABLE_REG); 119 struct q40kbd *q40kbd = port->port_data;
112 master_outb(-1, KEYBOARD_UNLOCK_REG);
113 free_irq(Q40_IRQ_KEYBOARD, NULL);
114 120
115 q40kbd_flush(); 121 q40kbd_stop();
122 q40kbd_flush(q40kbd);
116} 123}
117 124
118static int __devinit q40kbd_probe(struct platform_device *dev) 125static int __devinit q40kbd_probe(struct platform_device *pdev)
119{ 126{
120 q40kbd_port = kzalloc(sizeof(struct serio), GFP_KERNEL); 127 struct q40kbd *q40kbd;
121 if (!q40kbd_port) 128 struct serio *port;
122 return -ENOMEM; 129 int error;
123 130
124 q40kbd_port->id.type = SERIO_8042; 131 q40kbd = kzalloc(sizeof(struct q40kbd), GFP_KERNEL);
125 q40kbd_port->open = q40kbd_open; 132 port = kzalloc(sizeof(struct serio), GFP_KERNEL);
126 q40kbd_port->close = q40kbd_close; 133 if (!q40kbd || !port) {
127 q40kbd_port->dev.parent = &dev->dev; 134 error = -ENOMEM;
128 strlcpy(q40kbd_port->name, "Q40 Kbd Port", sizeof(q40kbd_port->name)); 135 goto err_free_mem;
129 strlcpy(q40kbd_port->phys, "Q40", sizeof(q40kbd_port->phys)); 136 }
130 137
131 serio_register_port(q40kbd_port); 138 q40kbd->port = port;
139 spin_lock_init(&q40kbd->lock);
140
141 port->id.type = SERIO_8042;
142 port->open = q40kbd_open;
143 port->close = q40kbd_close;
144 port->port_data = q40kbd;
145 port->dev.parent = &pdev->dev;
146 strlcpy(port->name, "Q40 Kbd Port", sizeof(port->name));
147 strlcpy(port->phys, "Q40", sizeof(port->phys));
148
149 q40kbd_stop();
150
151 error = request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0,
152 DRV_NAME, q40kbd);
153 if (error) {
154 dev_err(&pdev->dev, "Can't get irq %d.\n", Q40_IRQ_KEYBOARD);
155 goto err_free_mem;
156 }
157
158 serio_register_port(q40kbd->port);
159
160 platform_set_drvdata(pdev, q40kbd);
132 printk(KERN_INFO "serio: Q40 kbd registered\n"); 161 printk(KERN_INFO "serio: Q40 kbd registered\n");
133 162
134 return 0; 163 return 0;
164
165err_free_mem:
166 kfree(port);
167 kfree(q40kbd);
168 return error;
135} 169}
136 170
137static int __devexit q40kbd_remove(struct platform_device *dev) 171static int __devexit q40kbd_remove(struct platform_device *pdev)
138{ 172{
139 serio_unregister_port(q40kbd_port); 173 struct q40kbd *q40kbd = platform_get_drvdata(pdev);
140 174
175 /*
176 * q40kbd_close() will be called as part of unregistering
177 * and will ensure that IRQ is turned off, so it is safe
178 * to unregister port first and free IRQ later.
179 */
180 serio_unregister_port(q40kbd->port);
181 free_irq(Q40_IRQ_KEYBOARD, q40kbd);
182 kfree(q40kbd);
183
184 platform_set_drvdata(pdev, NULL);
141 return 0; 185 return 0;
142} 186}
143 187
@@ -146,41 +190,16 @@ static struct platform_driver q40kbd_driver = {
146 .name = "q40kbd", 190 .name = "q40kbd",
147 .owner = THIS_MODULE, 191 .owner = THIS_MODULE,
148 }, 192 },
149 .probe = q40kbd_probe,
150 .remove = __devexit_p(q40kbd_remove), 193 .remove = __devexit_p(q40kbd_remove),
151}; 194};
152 195
153static int __init q40kbd_init(void) 196static int __init q40kbd_init(void)
154{ 197{
155 int error; 198 return platform_driver_probe(&q40kbd_driver, q40kbd_probe);
156
157 if (!MACH_IS_Q40)
158 return -ENODEV;
159
160 error = platform_driver_register(&q40kbd_driver);
161 if (error)
162 return error;
163
164 q40kbd_device = platform_device_alloc("q40kbd", -1);
165 if (!q40kbd_device)
166 goto err_unregister_driver;
167
168 error = platform_device_add(q40kbd_device);
169 if (error)
170 goto err_free_device;
171
172 return 0;
173
174 err_free_device:
175 platform_device_put(q40kbd_device);
176 err_unregister_driver:
177 platform_driver_unregister(&q40kbd_driver);
178 return error;
179} 199}
180 200
181static void __exit q40kbd_exit(void) 201static void __exit q40kbd_exit(void)
182{ 202{
183 platform_device_unregister(q40kbd_device);
184 platform_driver_unregister(&q40kbd_driver); 203 platform_driver_unregister(&q40kbd_driver);
185} 204}
186 205