linux/drivers/input/mouse/inport.c
<<
>>
Prefs
   1/*
   2 *  Copyright (c) 1999-2001 Vojtech Pavlik
   3 *
   4 *  Based on the work of:
   5 *      Teemu Rantanen          Derrick Cole
   6 *      Peter Cervasio          Christoph Niemann
   7 *      Philip Blundell         Russell King
   8 *      Bob Harris
   9 */
  10
  11/*
  12 * Inport (ATI XL and Microsoft) busmouse driver for Linux
  13 */
  14
  15/*
  16 * This program is free software; you can redistribute it and/or modify
  17 * it under the terms of the GNU General Public License as published by
  18 * the Free Software Foundation; either version 2 of the License, or
  19 * (at your option) any later version.
  20 *
  21 * This program is distributed in the hope that it will be useful,
  22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  24 * GNU General Public License for more details.
  25 *
  26 * You should have received a copy of the GNU General Public License
  27 * along with this program; if not, write to the Free Software
  28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  29 *
  30 * Should you need to contact me, the author, you can do so either by
  31 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  32 * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  33 */
  34
  35#include <linux/module.h>
  36#include <linux/ioport.h>
  37#include <linux/init.h>
  38#include <linux/interrupt.h>
  39#include <linux/input.h>
  40
  41#include <asm/io.h>
  42#include <asm/irq.h>
  43
  44MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
  45MODULE_DESCRIPTION("Inport (ATI XL and Microsoft) busmouse driver");
  46MODULE_LICENSE("GPL");
  47
  48#define INPORT_BASE             0x23c
  49#define INPORT_EXTENT           4
  50
  51#define INPORT_CONTROL_PORT     INPORT_BASE + 0
  52#define INPORT_DATA_PORT        INPORT_BASE + 1
  53#define INPORT_SIGNATURE_PORT   INPORT_BASE + 2
  54
  55#define INPORT_REG_BTNS 0x00
  56#define INPORT_REG_X            0x01
  57#define INPORT_REG_Y            0x02
  58#define INPORT_REG_MODE         0x07
  59#define INPORT_RESET            0x80
  60
  61#ifdef CONFIG_MOUSE_ATIXL
  62#define INPORT_NAME             "ATI XL Mouse"
  63#define INPORT_VENDOR           0x0002
  64#define INPORT_SPEED_30HZ       0x01
  65#define INPORT_SPEED_50HZ       0x02
  66#define INPORT_SPEED_100HZ      0x03
  67#define INPORT_SPEED_200HZ      0x04
  68#define INPORT_MODE_BASE        INPORT_SPEED_100HZ
  69#define INPORT_MODE_IRQ         0x08
  70#else
  71#define INPORT_NAME             "Microsoft InPort Mouse"
  72#define INPORT_VENDOR           0x0001
  73#define INPORT_MODE_BASE        0x10
  74#define INPORT_MODE_IRQ         0x01
  75#endif
  76#define INPORT_MODE_HOLD        0x20
  77
  78#define INPORT_IRQ              5
  79
  80static int inport_irq = INPORT_IRQ;
  81module_param_hw_named(irq, inport_irq, uint, irq, 0);
  82MODULE_PARM_DESC(irq, "IRQ number (5=default)");
  83
  84static struct input_dev *inport_dev;
  85
  86static irqreturn_t inport_interrupt(int irq, void *dev_id)
  87{
  88        unsigned char buttons;
  89
  90        outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
  91        outb(INPORT_MODE_HOLD | INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
  92
  93        outb(INPORT_REG_X, INPORT_CONTROL_PORT);
  94        input_report_rel(inport_dev, REL_X, inb(INPORT_DATA_PORT));
  95
  96        outb(INPORT_REG_Y, INPORT_CONTROL_PORT);
  97        input_report_rel(inport_dev, REL_Y, inb(INPORT_DATA_PORT));
  98
  99        outb(INPORT_REG_BTNS, INPORT_CONTROL_PORT);
 100        buttons = inb(INPORT_DATA_PORT);
 101
 102        input_report_key(inport_dev, BTN_MIDDLE, buttons & 1);
 103        input_report_key(inport_dev, BTN_LEFT,   buttons & 2);
 104        input_report_key(inport_dev, BTN_RIGHT,  buttons & 4);
 105
 106        outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
 107        outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
 108
 109        input_sync(inport_dev);
 110        return IRQ_HANDLED;
 111}
 112
 113static int inport_open(struct input_dev *dev)
 114{
 115        if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL))
 116                return -EBUSY;
 117        outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
 118        outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
 119
 120        return 0;
 121}
 122
 123static void inport_close(struct input_dev *dev)
 124{
 125        outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
 126        outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
 127        free_irq(inport_irq, NULL);
 128}
 129
 130static int __init inport_init(void)
 131{
 132        unsigned char a, b, c;
 133        int err;
 134
 135        if (!request_region(INPORT_BASE, INPORT_EXTENT, "inport")) {
 136                printk(KERN_ERR "inport.c: Can't allocate ports at %#x\n", INPORT_BASE);
 137                return -EBUSY;
 138        }
 139
 140        a = inb(INPORT_SIGNATURE_PORT);
 141        b = inb(INPORT_SIGNATURE_PORT);
 142        c = inb(INPORT_SIGNATURE_PORT);
 143        if (a == b || a != c) {
 144                printk(KERN_INFO "inport.c: Didn't find InPort mouse at %#x\n", INPORT_BASE);
 145                err = -ENODEV;
 146                goto err_release_region;
 147        }
 148
 149        inport_dev = input_allocate_device();
 150        if (!inport_dev) {
 151                printk(KERN_ERR "inport.c: Not enough memory for input device\n");
 152                err = -ENOMEM;
 153                goto err_release_region;
 154        }
 155
 156        inport_dev->name = INPORT_NAME;
 157        inport_dev->phys = "isa023c/input0";
 158        inport_dev->id.bustype = BUS_ISA;
 159        inport_dev->id.vendor  = INPORT_VENDOR;
 160        inport_dev->id.product = 0x0001;
 161        inport_dev->id.version = 0x0100;
 162
 163        inport_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
 164        inport_dev->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) |
 165                BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
 166        inport_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
 167
 168        inport_dev->open  = inport_open;
 169        inport_dev->close = inport_close;
 170
 171        outb(INPORT_RESET, INPORT_CONTROL_PORT);
 172        outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
 173        outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
 174
 175        err = input_register_device(inport_dev);
 176        if (err)
 177                goto err_free_dev;
 178
 179        return 0;
 180
 181 err_free_dev:
 182        input_free_device(inport_dev);
 183 err_release_region:
 184        release_region(INPORT_BASE, INPORT_EXTENT);
 185
 186        return err;
 187}
 188
 189static void __exit inport_exit(void)
 190{
 191        input_unregister_device(inport_dev);
 192        release_region(INPORT_BASE, INPORT_EXTENT);
 193}
 194
 195module_init(inport_init);
 196module_exit(inport_exit);
 197