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