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