cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

inport.c (4579B)


      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);