linux/drivers/input/serio/rpckbd.c
<<
>>
Prefs
   1/*
   2 *  Copyright (c) 2000-2001 Vojtech Pavlik
   3 *  Copyright (c) 2002 Russell King
   4 */
   5
   6/*
   7 * Acorn RiscPC PS/2 keyboard controller driver for Linux/ARM
   8 */
   9
  10/*
  11 * This program is free software; you can redistribute it and/or modify
  12 * it under the terms of the GNU General Public License as published by
  13 * the Free Software Foundation; either version 2 of the License, or
  14 * (at your option) any later version.
  15 *
  16 * This program is distributed in the hope that it will be useful,
  17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19 * GNU General Public License for more details.
  20 *
  21 * You should have received a copy of the GNU General Public License
  22 * along with this program; if not, write to the Free Software
  23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  24 *
  25 * Should you need to contact me, the author, you can do so either by
  26 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  27 * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  28 */
  29
  30#include <linux/module.h>
  31#include <linux/interrupt.h>
  32#include <linux/serio.h>
  33#include <linux/err.h>
  34#include <linux/platform_device.h>
  35#include <linux/io.h>
  36#include <linux/slab.h>
  37
  38#include <mach/hardware.h>
  39#include <asm/hardware/iomd.h>
  40
  41MODULE_AUTHOR("Vojtech Pavlik, Russell King");
  42MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver");
  43MODULE_LICENSE("GPL");
  44MODULE_ALIAS("platform:kart");
  45
  46struct rpckbd_data {
  47        int tx_irq;
  48        int rx_irq;
  49};
  50
  51static int rpckbd_write(struct serio *port, unsigned char val)
  52{
  53        while (!(iomd_readb(IOMD_KCTRL) & (1 << 7)))
  54                cpu_relax();
  55
  56        iomd_writeb(val, IOMD_KARTTX);
  57
  58        return 0;
  59}
  60
  61static irqreturn_t rpckbd_rx(int irq, void *dev_id)
  62{
  63        struct serio *port = dev_id;
  64        unsigned int byte;
  65        int handled = IRQ_NONE;
  66
  67        while (iomd_readb(IOMD_KCTRL) & (1 << 5)) {
  68                byte = iomd_readb(IOMD_KARTRX);
  69
  70                serio_interrupt(port, byte, 0);
  71                handled = IRQ_HANDLED;
  72        }
  73        return handled;
  74}
  75
  76static irqreturn_t rpckbd_tx(int irq, void *dev_id)
  77{
  78        return IRQ_HANDLED;
  79}
  80
  81static int rpckbd_open(struct serio *port)
  82{
  83        struct rpckbd_data *rpckbd = port->port_data;
  84
  85        /* Reset the keyboard state machine. */
  86        iomd_writeb(0, IOMD_KCTRL);
  87        iomd_writeb(8, IOMD_KCTRL);
  88        iomd_readb(IOMD_KARTRX);
  89
  90        if (request_irq(rpckbd->rx_irq, rpckbd_rx, 0, "rpckbd", port) != 0) {
  91                printk(KERN_ERR "rpckbd.c: Could not allocate keyboard receive IRQ\n");
  92                return -EBUSY;
  93        }
  94
  95        if (request_irq(rpckbd->tx_irq, rpckbd_tx, 0, "rpckbd", port) != 0) {
  96                printk(KERN_ERR "rpckbd.c: Could not allocate keyboard transmit IRQ\n");
  97                free_irq(rpckbd->rx_irq, port);
  98                return -EBUSY;
  99        }
 100
 101        return 0;
 102}
 103
 104static void rpckbd_close(struct serio *port)
 105{
 106        struct rpckbd_data *rpckbd = port->port_data;
 107
 108        free_irq(rpckbd->rx_irq, port);
 109        free_irq(rpckbd->tx_irq, port);
 110}
 111
 112/*
 113 * Allocate and initialize serio structure for subsequent registration
 114 * with serio core.
 115 */
 116static int rpckbd_probe(struct platform_device *dev)
 117{
 118        struct rpckbd_data *rpckbd;
 119        struct serio *serio;
 120        int tx_irq, rx_irq;
 121
 122        rx_irq = platform_get_irq(dev, 0);
 123        if (rx_irq <= 0)
 124                return rx_irq < 0 ? rx_irq : -ENXIO;
 125
 126        tx_irq = platform_get_irq(dev, 1);
 127        if (tx_irq <= 0)
 128                return tx_irq < 0 ? tx_irq : -ENXIO;
 129
 130        serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
 131        rpckbd = kzalloc(sizeof(*rpckbd), GFP_KERNEL);
 132        if (!serio || !rpckbd) {
 133                kfree(rpckbd);
 134                kfree(serio);
 135                return -ENOMEM;
 136        }
 137
 138        rpckbd->rx_irq = rx_irq;
 139        rpckbd->tx_irq = tx_irq;
 140
 141        serio->id.type          = SERIO_8042;
 142        serio->write            = rpckbd_write;
 143        serio->open             = rpckbd_open;
 144        serio->close            = rpckbd_close;
 145        serio->dev.parent       = &dev->dev;
 146        serio->port_data        = rpckbd;
 147        strlcpy(serio->name, "RiscPC PS/2 kbd port", sizeof(serio->name));
 148        strlcpy(serio->phys, "rpckbd/serio0", sizeof(serio->phys));
 149
 150        platform_set_drvdata(dev, serio);
 151        serio_register_port(serio);
 152        return 0;
 153}
 154
 155static int rpckbd_remove(struct platform_device *dev)
 156{
 157        struct serio *serio = platform_get_drvdata(dev);
 158        struct rpckbd_data *rpckbd = serio->port_data;
 159
 160        serio_unregister_port(serio);
 161        kfree(rpckbd);
 162
 163        return 0;
 164}
 165
 166static struct platform_driver rpckbd_driver = {
 167        .probe          = rpckbd_probe,
 168        .remove         = rpckbd_remove,
 169        .driver         = {
 170                .name   = "kart",
 171        },
 172};
 173module_platform_driver(rpckbd_driver);
 174