Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+89 -57
+13
arch/m68k/q40/config.c
··· 24 24 #include <linux/rtc.h> 25 25 #include <linux/vt_kern.h> 26 26 #include <linux/bcd.h> 27 + #include <linux/platform_device.h> 27 28 28 29 #include <asm/io.h> 29 30 #include <asm/rtc.h> ··· 330 329 } else 331 330 return -EINVAL; 332 331 } 332 + 333 + static __init int q40_add_kbd_device(void) 334 + { 335 + struct platform_device *pdev; 336 + 337 + pdev = platform_device_register_simple("q40kbd", -1, NULL, 0); 338 + if (IS_ERR(pdev)) 339 + return PTR_ERR(pdev); 340 + 341 + return 0; 342 + } 343 + arch_initcall(q40_add_kbd_device);
+76 -57
drivers/input/serio/q40kbd.c
··· 44 44 #include <asm/irq.h> 45 45 #include <asm/q40ints.h> 46 46 47 + #define DRV_NAME "q40kbd" 48 + 47 49 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); 48 50 MODULE_DESCRIPTION("Q40 PS/2 keyboard controller driver"); 49 51 MODULE_LICENSE("GPL"); 52 + MODULE_ALIAS("platform:" DRV_NAME); 50 53 51 - static DEFINE_SPINLOCK(q40kbd_lock); 52 - static struct serio *q40kbd_port; 53 - static struct platform_device *q40kbd_device; 54 + struct q40kbd { 55 + struct serio *port; 56 + spinlock_t lock; 57 + }; 54 58 55 59 static irqreturn_t q40kbd_interrupt(int irq, void *dev_id) 56 60 { 61 + struct q40kbd *q40kbd = dev_id; 57 62 unsigned long flags; 58 63 59 - spin_lock_irqsave(&q40kbd_lock, flags); 64 + spin_lock_irqsave(&q40kbd->lock, flags); 60 65 61 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 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 73 return IRQ_HANDLED; 69 74 } ··· 77 72 * q40kbd_flush() flushes all data that may be in the keyboard buffers 78 73 */ 79 74 80 - static void q40kbd_flush(void) 75 + static void q40kbd_flush(struct q40kbd *q40kbd) 81 76 { 82 77 int maxread = 100; 83 78 unsigned long flags; 84 79 85 - spin_lock_irqsave(&q40kbd_lock, flags); 80 + spin_lock_irqsave(&q40kbd->lock, flags); 86 81 87 82 while (maxread-- && (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))) 88 83 master_inb(KEYCODE_REG); 89 84 90 - spin_unlock_irqrestore(&q40kbd_lock, flags); 85 + spin_unlock_irqrestore(&q40kbd->lock, flags); 86 + } 87 + 88 + static void q40kbd_stop(void) 89 + { 90 + master_outb(0, KEY_IRQ_ENABLE_REG); 91 + master_outb(-1, KEYBOARD_UNLOCK_REG); 91 92 } 92 93 93 94 /* ··· 103 92 104 93 static int q40kbd_open(struct serio *port) 105 94 { 106 - q40kbd_flush(); 95 + struct q40kbd *q40kbd = port->port_data; 107 96 108 - if (request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0, "q40kbd", NULL)) { 109 - printk(KERN_ERR "q40kbd.c: Can't get irq %d.\n", Q40_IRQ_KEYBOARD); 110 - return -EBUSY; 111 - } 97 + q40kbd_flush(q40kbd); 112 98 113 99 /* off we go */ 114 100 master_outb(-1, KEYBOARD_UNLOCK_REG); ··· 116 108 117 109 static void q40kbd_close(struct serio *port) 118 110 { 119 - master_outb(0, KEY_IRQ_ENABLE_REG); 120 - master_outb(-1, KEYBOARD_UNLOCK_REG); 121 - free_irq(Q40_IRQ_KEYBOARD, NULL); 111 + struct q40kbd *q40kbd = port->port_data; 122 112 123 - q40kbd_flush(); 113 + q40kbd_stop(); 114 + q40kbd_flush(q40kbd); 124 115 } 125 116 126 - static int __devinit q40kbd_probe(struct platform_device *dev) 117 + static int __devinit q40kbd_probe(struct platform_device *pdev) 127 118 { 128 - q40kbd_port = kzalloc(sizeof(struct serio), GFP_KERNEL); 129 - if (!q40kbd_port) 130 - return -ENOMEM; 119 + struct q40kbd *q40kbd; 120 + struct serio *port; 121 + int error; 131 122 132 - q40kbd_port->id.type = SERIO_8042; 133 - q40kbd_port->open = q40kbd_open; 134 - q40kbd_port->close = q40kbd_close; 135 - q40kbd_port->dev.parent = &dev->dev; 136 - strlcpy(q40kbd_port->name, "Q40 Kbd Port", sizeof(q40kbd_port->name)); 137 - strlcpy(q40kbd_port->phys, "Q40", sizeof(q40kbd_port->phys)); 123 + q40kbd = kzalloc(sizeof(struct q40kbd), GFP_KERNEL); 124 + port = kzalloc(sizeof(struct serio), GFP_KERNEL); 125 + if (!q40kbd || !port) { 126 + error = -ENOMEM; 127 + goto err_free_mem; 128 + } 138 129 139 - serio_register_port(q40kbd_port); 130 + q40kbd->port = port; 131 + spin_lock_init(&q40kbd->lock); 132 + 133 + port->id.type = SERIO_8042; 134 + port->open = q40kbd_open; 135 + port->close = q40kbd_close; 136 + port->port_data = q40kbd; 137 + port->dev.parent = &pdev->dev; 138 + strlcpy(port->name, "Q40 Kbd Port", sizeof(port->name)); 139 + strlcpy(port->phys, "Q40", sizeof(port->phys)); 140 + 141 + q40kbd_stop(); 142 + 143 + error = request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0, 144 + DRV_NAME, q40kbd); 145 + if (error) { 146 + dev_err(&pdev->dev, "Can't get irq %d.\n", Q40_IRQ_KEYBOARD); 147 + goto err_free_mem; 148 + } 149 + 150 + serio_register_port(q40kbd->port); 151 + 152 + platform_set_drvdata(pdev, q40kbd); 140 153 printk(KERN_INFO "serio: Q40 kbd registered\n"); 141 154 142 155 return 0; 156 + 157 + err_free_mem: 158 + kfree(port); 159 + kfree(q40kbd); 160 + return error; 143 161 } 144 162 145 - static int __devexit q40kbd_remove(struct platform_device *dev) 163 + static int __devexit q40kbd_remove(struct platform_device *pdev) 146 164 { 147 - serio_unregister_port(q40kbd_port); 165 + struct q40kbd *q40kbd = platform_get_drvdata(pdev); 148 166 167 + /* 168 + * q40kbd_close() will be called as part of unregistering 169 + * and will ensure that IRQ is turned off, so it is safe 170 + * to unregister port first and free IRQ later. 171 + */ 172 + serio_unregister_port(q40kbd->port); 173 + free_irq(Q40_IRQ_KEYBOARD, q40kbd); 174 + kfree(q40kbd); 175 + 176 + platform_set_drvdata(pdev, NULL); 149 177 return 0; 150 178 } 151 179 ··· 190 146 .name = "q40kbd", 191 147 .owner = THIS_MODULE, 192 148 }, 193 - .probe = q40kbd_probe, 194 149 .remove = __devexit_p(q40kbd_remove), 195 150 }; 196 151 197 152 static int __init q40kbd_init(void) 198 153 { 199 - int error; 200 - 201 - if (!MACH_IS_Q40) 202 - return -ENODEV; 203 - 204 - error = platform_driver_register(&q40kbd_driver); 205 - if (error) 206 - return error; 207 - 208 - q40kbd_device = platform_device_alloc("q40kbd", -1); 209 - if (!q40kbd_device) 210 - goto err_unregister_driver; 211 - 212 - error = platform_device_add(q40kbd_device); 213 - if (error) 214 - goto err_free_device; 215 - 216 - return 0; 217 - 218 - err_free_device: 219 - platform_device_put(q40kbd_device); 220 - err_unregister_driver: 221 - platform_driver_unregister(&q40kbd_driver); 222 - return error; 154 + return platform_driver_probe(&q40kbd_driver, q40kbd_probe); 223 155 } 224 156 225 157 static void __exit q40kbd_exit(void) 226 158 { 227 - platform_device_unregister(q40kbd_device); 228 159 platform_driver_unregister(&q40kbd_driver); 229 160 } 230 161