linux/drivers/input/mouse/inport.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *  Copyright (c) 1999-2001 Vojtech Pavlik
   4 *
   5 *  Based on the work of:
   6 *      Teemu Rantanen          Derrick Cole
   7 *      Peter Cervasio          Christoph Niemann
   8 *      Philip Blundell         Russell King
   9 *      Bob Harris
  10 */
  11
  12/*
  13 * Inport (ATI XL and Microsoft) busmouse driver for Linux
  14 */
  15
  16/*
  17 */
  18
  19#include <linux/module.h>
  20#include <linux/ioport.h>
  21#include <linux/init.h>
  22#include <linux/interrupt.h>
  23#include <linux/input.h>
  24
  25#include <asm/io.h>
  26#include <asm/irq.h>
  27
  28MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
  29MODULE_DESCRIPTION("Inport (ATI XL and Microsoft) busmouse driver");
  30MODULE_LICENSE("GPL");
  31
  32#define INPORT_BASE             0x23c
  33#define INPORT_EXTENT           4
  34
  35#define INPORT_CONTROL_PORT     INPORT_BASE + 0
  36#define INPORT_DATA_PORT        INPORT_BASE + 1
  37#define INPORT_SIGNATURE_PORT   INPORT_BASE + 2
  38
  39#define INPORT_REG_BTNS 0x00
  40#define INPORT_REG_X            0x01
  41#define INPORT_REG_Y            0x02
  42#define INPORT_REG_MODE         0x07
  43#define INPORT_RESET            0x80
  44
  45#ifdef CONFIG_MOUSE_ATIXL
  46#define INPORT_NAME             "ATI XL Mouse"
  47#define INPORT_VENDOR           0x0002
  48#define INPORT_SPEED_30HZ       0x01
  49#define INPORT_SPEED_50HZ       0x02
  50#define INPORT_SPEED_100HZ      0x03
  51#define INPORT_SPEED_200HZ      0x04
  52#define INPORT_MODE_BASE        INPORT_SPEED_100HZ
  53#define INPORT_MODE_IRQ         0x08
  54#else
  55#define INPORT_NAME             "Microsoft InPort Mouse"
  56#define INPORT_VENDOR           0x0001
  57#define INPORT_MODE_BASE        0x10
  58#define INPORT_MODE_IRQ         0x01
  59#endif
  60#define INPORT_MODE_HOLD        0x20
  61
  62#define INPORT_IRQ              5
  63
  64static int inport_irq = INPORT_IRQ;
  65module_param_hw_named(irq, inport_irq, uint, irq, 0);
  66MODULE_PARM_DESC(irq, "IRQ number (5=default)");
  67
  68static struct input_dev *inport_dev;
  69
  70static irqreturn_t inport_interrupt(int irq, void *dev_id)
  71{
  72        unsigned char buttons;
  73
  74        outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
  75        outb(INPORT_MODE_HOLD | INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
  76
  77        outb(INPORT_REG_X, INPORT_CONTROL_PORT);
  78        input_report_rel(inport_dev, REL_X, inb(INPORT_DATA_PORT));
  79
  80        outb(INPORT_REG_Y, INPORT_CONTROL_PORT);
  81        input_report_rel(inport_dev, REL_Y, inb(INPORT_DATA_PORT));
  82
  83        outb(INPORT_REG_BTNS, INPORT_CONTROL_PORT);
  84        buttons = inb(INPORT_DATA_PORT);
  85
  86        input_report_key(inport_dev, BTN_MIDDLE, buttons & 1);
  87        input_report_key(inport_dev, BTN_LEFT,   buttons & 2);
  88        input_report_key(inport_dev, BTN_RIGHT,  buttons & 4);
  89
  90        outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
  91        outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
  92
  93        input_sync(inport_dev);
  94        return IRQ_HANDLED;
  95}
  96
  97static int inport_open(struct input_dev *dev)
  98{
  99        if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL))
 100                return -EBUSY;
 101        outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
 102        outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
 103
 104        return 0;
 105}
 106
 107static void inport_close(struct input_dev *dev)
 108{
 109        outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
 110        outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
 111        free_irq(inport_irq, NULL);
 112}
 113
 114static int __init inport_init(void)
 115{
 116        unsigned char a, b, c;
 117        int err;
 118
 119        if (!request_region(INPORT_BASE, INPORT_EXTENT, "inport")) {
 120                printk(KERN_ERR "inport.c: Can't allocate ports at %#x\n", INPORT_BASE);
 121                return -EBUSY;
 122        }
 123
 124        a = inb(INPORT_SIGNATURE_PORT);
 125        b = inb(INPORT_SIGNATURE_PORT);
 126        c = inb(INPORT_SIGNATURE_PORT);
 127        if (a == b || a != c) {
 128                printk(KERN_INFO "inport.c: Didn't find InPort mouse at %#x\n", INPORT_BASE);
 129                err = -ENODEV;
 130                goto err_release_region;
 131        }
 132
 133        inport_dev = input_allocate_device();
 134        if (!inport_dev) {
 135                printk(KERN_ERR "inport.c: Not enough memory for input device\n");
 136                err = -ENOMEM;
 137                goto err_release_region;
 138        }
 139
 140        inport_dev->name = INPORT_NAME;
 141        inport_dev->phys = "isa023c/input0";
 142        inport_dev->id.bustype = BUS_ISA;
 143        inport_dev->id.vendor  = INPORT_VENDOR;
 144        inport_dev->id.product = 0x0001;
 145        inport_dev->id.version = 0x0100;
 146
 147        inport_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
 148        inport_dev->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) |
 149                BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
 150        inport_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
 151
 152        inport_dev->open  = inport_open;
 153        inport_dev->close = inport_close;
 154
 155        outb(INPORT_RESET, INPORT_CONTROL_PORT);
 156        outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
 157        outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
 158
 159        err = input_register_device(inport_dev);
 160        if (err)
 161                goto err_free_dev;
 162
 163        return 0;
 164
 165 err_free_dev:
 166        input_free_device(inport_dev);
 167 err_release_region:
 168        release_region(INPORT_BASE, INPORT_EXTENT);
 169
 170        return err;
 171}
 172
 173static void __exit inport_exit(void)
 174{
 175        input_unregister_device(inport_dev);
 176        release_region(INPORT_BASE, INPORT_EXTENT);
 177}
 178
 179module_init(inport_init);
 180module_exit(inport_exit);
 181