linux/drivers/input/serio/rpckbd.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *  Copyright (c) 2000-2001 Vojtech Pavlik
   4 *  Copyright (c) 2002 Russell King
   5 */
   6
   7/*
   8 * Acorn RiscPC PS/2 keyboard controller driver for Linux/ARM
   9 */
  10
  11/*
  12 */
  13
  14#include <linux/module.h>
  15#include <linux/interrupt.h>
  16#include <linux/serio.h>
  17#include <linux/err.h>
  18#include <linux/platform_device.h>
  19#include <linux/io.h>
  20#include <linux/slab.h>
  21
  22#include <mach/hardware.h>
  23#include <asm/hardware/iomd.h>
  24
  25MODULE_AUTHOR("Vojtech Pavlik, Russell King");
  26MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver");
  27MODULE_LICENSE("GPL");
  28MODULE_ALIAS("platform:kart");
  29
  30struct rpckbd_data {
  31        int tx_irq;
  32        int rx_irq;
  33};
  34
  35static int rpckbd_write(struct serio *port, unsigned char val)
  36{
  37        while (!(iomd_readb(IOMD_KCTRL) & (1 << 7)))
  38                cpu_relax();
  39
  40        iomd_writeb(val, IOMD_KARTTX);
  41
  42        return 0;
  43}
  44
  45static irqreturn_t rpckbd_rx(int irq, void *dev_id)
  46{
  47        struct serio *port = dev_id;
  48        unsigned int byte;
  49        int handled = IRQ_NONE;
  50
  51        while (iomd_readb(IOMD_KCTRL) & (1 << 5)) {
  52                byte = iomd_readb(IOMD_KARTRX);
  53
  54                serio_interrupt(port, byte, 0);
  55                handled = IRQ_HANDLED;
  56        }
  57        return handled;
  58}
  59
  60static irqreturn_t rpckbd_tx(int irq, void *dev_id)
  61{
  62        return IRQ_HANDLED;
  63}
  64
  65static int rpckbd_open(struct serio *port)
  66{
  67        struct rpckbd_data *rpckbd = port->port_data;
  68
  69        /* Reset the keyboard state machine. */
  70        iomd_writeb(0, IOMD_KCTRL);
  71        iomd_writeb(8, IOMD_KCTRL);
  72        iomd_readb(IOMD_KARTRX);
  73
  74        if (request_irq(rpckbd->rx_irq, rpckbd_rx, 0, "rpckbd", port) != 0) {
  75                printk(KERN_ERR "rpckbd.c: Could not allocate keyboard receive IRQ\n");
  76                return -EBUSY;
  77        }
  78
  79        if (request_irq(rpckbd->tx_irq, rpckbd_tx, 0, "rpckbd", port) != 0) {
  80                printk(KERN_ERR "rpckbd.c: Could not allocate keyboard transmit IRQ\n");
  81                free_irq(rpckbd->rx_irq, port);
  82                return -EBUSY;
  83        }
  84
  85        return 0;
  86}
  87
  88static void rpckbd_close(struct serio *port)
  89{
  90        struct rpckbd_data *rpckbd = port->port_data;
  91
  92        free_irq(rpckbd->rx_irq, port);
  93        free_irq(rpckbd->tx_irq, port);
  94}
  95
  96/*
  97 * Allocate and initialize serio structure for subsequent registration
  98 * with serio core.
  99 */
 100static int rpckbd_probe(struct platform_device *dev)
 101{
 102        struct rpckbd_data *rpckbd;
 103        struct serio *serio;
 104        int tx_irq, rx_irq;
 105
 106        rx_irq = platform_get_irq(dev, 0);
 107        if (rx_irq <= 0)
 108                return rx_irq < 0 ? rx_irq : -ENXIO;
 109
 110        tx_irq = platform_get_irq(dev, 1);
 111        if (tx_irq <= 0)
 112                return tx_irq < 0 ? tx_irq : -ENXIO;
 113
 114        serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
 115        rpckbd = kzalloc(sizeof(*rpckbd), GFP_KERNEL);
 116        if (!serio || !rpckbd) {
 117                kfree(rpckbd);
 118                kfree(serio);
 119                return -ENOMEM;
 120        }
 121
 122        rpckbd->rx_irq = rx_irq;
 123        rpckbd->tx_irq = tx_irq;
 124
 125        serio->id.type          = SERIO_8042;
 126        serio->write            = rpckbd_write;
 127        serio->open             = rpckbd_open;
 128        serio->close            = rpckbd_close;
 129        serio->dev.parent       = &dev->dev;
 130        serio->port_data        = rpckbd;
 131        strlcpy(serio->name, "RiscPC PS/2 kbd port", sizeof(serio->name));
 132        strlcpy(serio->phys, "rpckbd/serio0", sizeof(serio->phys));
 133
 134        platform_set_drvdata(dev, serio);
 135        serio_register_port(serio);
 136        return 0;
 137}
 138
 139static int rpckbd_remove(struct platform_device *dev)
 140{
 141        struct serio *serio = platform_get_drvdata(dev);
 142        struct rpckbd_data *rpckbd = serio->port_data;
 143
 144        serio_unregister_port(serio);
 145        kfree(rpckbd);
 146
 147        return 0;
 148}
 149
 150static struct platform_driver rpckbd_driver = {
 151        .probe          = rpckbd_probe,
 152        .remove         = rpckbd_remove,
 153        .driver         = {
 154                .name   = "kart",
 155        },
 156};
 157module_platform_driver(rpckbd_driver);
 158