root/drivers/input/serio/pcips2.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pcips2_write
  2. pcips2_interrupt
  3. pcips2_flush_input
  4. pcips2_open
  5. pcips2_close
  6. pcips2_probe
  7. pcips2_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * linux/drivers/input/serio/pcips2.c
   4  *
   5  *  Copyright (C) 2003 Russell King, All Rights Reserved.
   6  *
   7  *  I'm not sure if this is a generic PS/2 PCI interface or specific to
   8  *  the Mobility Electronics docking station.
   9  */
  10 #include <linux/module.h>
  11 #include <linux/interrupt.h>
  12 #include <linux/ioport.h>
  13 #include <linux/input.h>
  14 #include <linux/pci.h>
  15 #include <linux/slab.h>
  16 #include <linux/serio.h>
  17 #include <linux/delay.h>
  18 #include <asm/io.h>
  19 
  20 #define PS2_CTRL                (0)
  21 #define PS2_STATUS              (1)
  22 #define PS2_DATA                (2)
  23 
  24 #define PS2_CTRL_CLK            (1<<0)
  25 #define PS2_CTRL_DAT            (1<<1)
  26 #define PS2_CTRL_TXIRQ          (1<<2)
  27 #define PS2_CTRL_ENABLE         (1<<3)
  28 #define PS2_CTRL_RXIRQ          (1<<4)
  29 
  30 #define PS2_STAT_CLK            (1<<0)
  31 #define PS2_STAT_DAT            (1<<1)
  32 #define PS2_STAT_PARITY         (1<<2)
  33 #define PS2_STAT_RXFULL         (1<<5)
  34 #define PS2_STAT_TXBUSY         (1<<6)
  35 #define PS2_STAT_TXEMPTY        (1<<7)
  36 
  37 struct pcips2_data {
  38         struct serio    *io;
  39         unsigned int    base;
  40         struct pci_dev  *dev;
  41 };
  42 
  43 static int pcips2_write(struct serio *io, unsigned char val)
  44 {
  45         struct pcips2_data *ps2if = io->port_data;
  46         unsigned int stat;
  47 
  48         do {
  49                 stat = inb(ps2if->base + PS2_STATUS);
  50                 cpu_relax();
  51         } while (!(stat & PS2_STAT_TXEMPTY));
  52 
  53         outb(val, ps2if->base + PS2_DATA);
  54 
  55         return 0;
  56 }
  57 
  58 static irqreturn_t pcips2_interrupt(int irq, void *devid)
  59 {
  60         struct pcips2_data *ps2if = devid;
  61         unsigned char status, scancode;
  62         int handled = 0;
  63 
  64         do {
  65                 unsigned int flag;
  66 
  67                 status = inb(ps2if->base + PS2_STATUS);
  68                 if (!(status & PS2_STAT_RXFULL))
  69                         break;
  70                 handled = 1;
  71                 scancode = inb(ps2if->base + PS2_DATA);
  72                 if (status == 0xff && scancode == 0xff)
  73                         break;
  74 
  75                 flag = (status & PS2_STAT_PARITY) ? 0 : SERIO_PARITY;
  76 
  77                 if (hweight8(scancode) & 1)
  78                         flag ^= SERIO_PARITY;
  79 
  80                 serio_interrupt(ps2if->io, scancode, flag);
  81         } while (1);
  82         return IRQ_RETVAL(handled);
  83 }
  84 
  85 static void pcips2_flush_input(struct pcips2_data *ps2if)
  86 {
  87         unsigned char status, scancode;
  88 
  89         do {
  90                 status = inb(ps2if->base + PS2_STATUS);
  91                 if (!(status & PS2_STAT_RXFULL))
  92                         break;
  93                 scancode = inb(ps2if->base + PS2_DATA);
  94                 if (status == 0xff && scancode == 0xff)
  95                         break;
  96         } while (1);
  97 }
  98 
  99 static int pcips2_open(struct serio *io)
 100 {
 101         struct pcips2_data *ps2if = io->port_data;
 102         int ret, val = 0;
 103 
 104         outb(PS2_CTRL_ENABLE, ps2if->base);
 105         pcips2_flush_input(ps2if);
 106 
 107         ret = request_irq(ps2if->dev->irq, pcips2_interrupt, IRQF_SHARED,
 108                           "pcips2", ps2if);
 109         if (ret == 0)
 110                 val = PS2_CTRL_ENABLE | PS2_CTRL_RXIRQ;
 111 
 112         outb(val, ps2if->base);
 113 
 114         return ret;
 115 }
 116 
 117 static void pcips2_close(struct serio *io)
 118 {
 119         struct pcips2_data *ps2if = io->port_data;
 120 
 121         outb(0, ps2if->base);
 122 
 123         free_irq(ps2if->dev->irq, ps2if);
 124 }
 125 
 126 static int pcips2_probe(struct pci_dev *dev, const struct pci_device_id *id)
 127 {
 128         struct pcips2_data *ps2if;
 129         struct serio *serio;
 130         int ret;
 131 
 132         ret = pci_enable_device(dev);
 133         if (ret)
 134                 goto out;
 135 
 136         ret = pci_request_regions(dev, "pcips2");
 137         if (ret)
 138                 goto disable;
 139 
 140         ps2if = kzalloc(sizeof(struct pcips2_data), GFP_KERNEL);
 141         serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
 142         if (!ps2if || !serio) {
 143                 ret = -ENOMEM;
 144                 goto release;
 145         }
 146 
 147 
 148         serio->id.type          = SERIO_8042;
 149         serio->write            = pcips2_write;
 150         serio->open             = pcips2_open;
 151         serio->close            = pcips2_close;
 152         strlcpy(serio->name, pci_name(dev), sizeof(serio->name));
 153         strlcpy(serio->phys, dev_name(&dev->dev), sizeof(serio->phys));
 154         serio->port_data        = ps2if;
 155         serio->dev.parent       = &dev->dev;
 156         ps2if->io               = serio;
 157         ps2if->dev              = dev;
 158         ps2if->base             = pci_resource_start(dev, 0);
 159 
 160         pci_set_drvdata(dev, ps2if);
 161 
 162         serio_register_port(ps2if->io);
 163         return 0;
 164 
 165  release:
 166         kfree(ps2if);
 167         kfree(serio);
 168         pci_release_regions(dev);
 169  disable:
 170         pci_disable_device(dev);
 171  out:
 172         return ret;
 173 }
 174 
 175 static void pcips2_remove(struct pci_dev *dev)
 176 {
 177         struct pcips2_data *ps2if = pci_get_drvdata(dev);
 178 
 179         serio_unregister_port(ps2if->io);
 180         kfree(ps2if);
 181         pci_release_regions(dev);
 182         pci_disable_device(dev);
 183 }
 184 
 185 static const struct pci_device_id pcips2_ids[] = {
 186         {
 187                 .vendor         = 0x14f2,       /* MOBILITY */
 188                 .device         = 0x0123,       /* Keyboard */
 189                 .subvendor      = PCI_ANY_ID,
 190                 .subdevice      = PCI_ANY_ID,
 191                 .class          = PCI_CLASS_INPUT_KEYBOARD << 8,
 192                 .class_mask     = 0xffff00,
 193         },
 194         {
 195                 .vendor         = 0x14f2,       /* MOBILITY */
 196                 .device         = 0x0124,       /* Mouse */
 197                 .subvendor      = PCI_ANY_ID,
 198                 .subdevice      = PCI_ANY_ID,
 199                 .class          = PCI_CLASS_INPUT_MOUSE << 8,
 200                 .class_mask     = 0xffff00,
 201         },
 202         { 0, }
 203 };
 204 MODULE_DEVICE_TABLE(pci, pcips2_ids);
 205 
 206 static struct pci_driver pcips2_driver = {
 207         .name                   = "pcips2",
 208         .id_table               = pcips2_ids,
 209         .probe                  = pcips2_probe,
 210         .remove                 = pcips2_remove,
 211 };
 212 
 213 module_pci_driver(pcips2_driver);
 214 
 215 MODULE_LICENSE("GPL");
 216 MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
 217 MODULE_DESCRIPTION("PCI PS/2 keyboard/mouse driver");

/* [<][>][^][v][top][bottom][index][help] */