xref: /openbmc/linux/drivers/input/mouse/inport.c (revision 1a59d1b8)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *  Copyright (c) 1999-2001 Vojtech Pavlik
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *  Based on the work of:
61da177e4SLinus Torvalds  *	Teemu Rantanen		Derrick Cole
71da177e4SLinus Torvalds  *	Peter Cervasio		Christoph Niemann
81da177e4SLinus Torvalds  *	Philip Blundell		Russell King
91da177e4SLinus Torvalds  *	Bob Harris
101da177e4SLinus Torvalds  */
111da177e4SLinus Torvalds 
121da177e4SLinus Torvalds /*
131da177e4SLinus Torvalds  * Inport (ATI XL and Microsoft) busmouse driver for Linux
141da177e4SLinus Torvalds  */
151da177e4SLinus Torvalds 
161da177e4SLinus Torvalds /*
171da177e4SLinus Torvalds  */
181da177e4SLinus Torvalds 
191da177e4SLinus Torvalds #include <linux/module.h>
201da177e4SLinus Torvalds #include <linux/ioport.h>
211da177e4SLinus Torvalds #include <linux/init.h>
221da177e4SLinus Torvalds #include <linux/interrupt.h>
231da177e4SLinus Torvalds #include <linux/input.h>
241da177e4SLinus Torvalds 
251da177e4SLinus Torvalds #include <asm/io.h>
261da177e4SLinus Torvalds #include <asm/irq.h>
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
291da177e4SLinus Torvalds MODULE_DESCRIPTION("Inport (ATI XL and Microsoft) busmouse driver");
301da177e4SLinus Torvalds MODULE_LICENSE("GPL");
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds #define INPORT_BASE		0x23c
331da177e4SLinus Torvalds #define INPORT_EXTENT		4
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds #define INPORT_CONTROL_PORT	INPORT_BASE + 0
361da177e4SLinus Torvalds #define INPORT_DATA_PORT	INPORT_BASE + 1
371da177e4SLinus Torvalds #define INPORT_SIGNATURE_PORT	INPORT_BASE + 2
381da177e4SLinus Torvalds 
391da177e4SLinus Torvalds #define INPORT_REG_BTNS	0x00
401da177e4SLinus Torvalds #define INPORT_REG_X		0x01
411da177e4SLinus Torvalds #define INPORT_REG_Y		0x02
421da177e4SLinus Torvalds #define INPORT_REG_MODE		0x07
431da177e4SLinus Torvalds #define INPORT_RESET		0x80
441da177e4SLinus Torvalds 
458370a643SRobert P. J. Day #ifdef CONFIG_MOUSE_ATIXL
461da177e4SLinus Torvalds #define INPORT_NAME		"ATI XL Mouse"
471da177e4SLinus Torvalds #define INPORT_VENDOR		0x0002
481da177e4SLinus Torvalds #define INPORT_SPEED_30HZ	0x01
491da177e4SLinus Torvalds #define INPORT_SPEED_50HZ	0x02
501da177e4SLinus Torvalds #define INPORT_SPEED_100HZ	0x03
511da177e4SLinus Torvalds #define INPORT_SPEED_200HZ	0x04
521da177e4SLinus Torvalds #define INPORT_MODE_BASE	INPORT_SPEED_100HZ
531da177e4SLinus Torvalds #define INPORT_MODE_IRQ		0x08
541da177e4SLinus Torvalds #else
551da177e4SLinus Torvalds #define INPORT_NAME		"Microsoft InPort Mouse"
561da177e4SLinus Torvalds #define INPORT_VENDOR		0x0001
571da177e4SLinus Torvalds #define INPORT_MODE_BASE	0x10
581da177e4SLinus Torvalds #define INPORT_MODE_IRQ		0x01
591da177e4SLinus Torvalds #endif
601da177e4SLinus Torvalds #define INPORT_MODE_HOLD	0x20
611da177e4SLinus Torvalds 
621da177e4SLinus Torvalds #define INPORT_IRQ		5
631da177e4SLinus Torvalds 
641da177e4SLinus Torvalds static int inport_irq = INPORT_IRQ;
65f6b12d04SDavid Howells module_param_hw_named(irq, inport_irq, uint, irq, 0);
661da177e4SLinus Torvalds MODULE_PARM_DESC(irq, "IRQ number (5=default)");
671da177e4SLinus Torvalds 
682e5b636bSDmitry Torokhov static struct input_dev *inport_dev;
692e5b636bSDmitry Torokhov 
707d12e780SDavid Howells static irqreturn_t inport_interrupt(int irq, void *dev_id)
712e5b636bSDmitry Torokhov {
722e5b636bSDmitry Torokhov 	unsigned char buttons;
732e5b636bSDmitry Torokhov 
742e5b636bSDmitry Torokhov 	outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
752e5b636bSDmitry Torokhov 	outb(INPORT_MODE_HOLD | INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
762e5b636bSDmitry Torokhov 
772e5b636bSDmitry Torokhov 	outb(INPORT_REG_X, INPORT_CONTROL_PORT);
782e5b636bSDmitry Torokhov 	input_report_rel(inport_dev, REL_X, inb(INPORT_DATA_PORT));
792e5b636bSDmitry Torokhov 
802e5b636bSDmitry Torokhov 	outb(INPORT_REG_Y, INPORT_CONTROL_PORT);
812e5b636bSDmitry Torokhov 	input_report_rel(inport_dev, REL_Y, inb(INPORT_DATA_PORT));
822e5b636bSDmitry Torokhov 
832e5b636bSDmitry Torokhov 	outb(INPORT_REG_BTNS, INPORT_CONTROL_PORT);
842e5b636bSDmitry Torokhov 	buttons = inb(INPORT_DATA_PORT);
852e5b636bSDmitry Torokhov 
862e5b636bSDmitry Torokhov 	input_report_key(inport_dev, BTN_MIDDLE, buttons & 1);
872e5b636bSDmitry Torokhov 	input_report_key(inport_dev, BTN_LEFT,   buttons & 2);
882e5b636bSDmitry Torokhov 	input_report_key(inport_dev, BTN_RIGHT,  buttons & 4);
892e5b636bSDmitry Torokhov 
902e5b636bSDmitry Torokhov 	outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
912e5b636bSDmitry Torokhov 	outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
922e5b636bSDmitry Torokhov 
932e5b636bSDmitry Torokhov 	input_sync(inport_dev);
942e5b636bSDmitry Torokhov 	return IRQ_HANDLED;
952e5b636bSDmitry Torokhov }
961da177e4SLinus Torvalds 
971da177e4SLinus Torvalds static int inport_open(struct input_dev *dev)
981da177e4SLinus Torvalds {
991da177e4SLinus Torvalds 	if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL))
1001da177e4SLinus Torvalds 		return -EBUSY;
1011da177e4SLinus Torvalds 	outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
1021da177e4SLinus Torvalds 	outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
1031da177e4SLinus Torvalds 
1041da177e4SLinus Torvalds 	return 0;
1051da177e4SLinus Torvalds }
1061da177e4SLinus Torvalds 
1071da177e4SLinus Torvalds static void inport_close(struct input_dev *dev)
1081da177e4SLinus Torvalds {
1091da177e4SLinus Torvalds 	outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
1101da177e4SLinus Torvalds 	outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
1111da177e4SLinus Torvalds 	free_irq(inport_irq, NULL);
1121da177e4SLinus Torvalds }
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds static int __init inport_init(void)
1151da177e4SLinus Torvalds {
1161da177e4SLinus Torvalds 	unsigned char a, b, c;
11772155615SDmitry Torokhov 	int err;
1181da177e4SLinus Torvalds 
1191da177e4SLinus Torvalds 	if (!request_region(INPORT_BASE, INPORT_EXTENT, "inport")) {
1201da177e4SLinus Torvalds 		printk(KERN_ERR "inport.c: Can't allocate ports at %#x\n", INPORT_BASE);
1211da177e4SLinus Torvalds 		return -EBUSY;
1221da177e4SLinus Torvalds 	}
1231da177e4SLinus Torvalds 
1241da177e4SLinus Torvalds 	a = inb(INPORT_SIGNATURE_PORT);
1251da177e4SLinus Torvalds 	b = inb(INPORT_SIGNATURE_PORT);
1261da177e4SLinus Torvalds 	c = inb(INPORT_SIGNATURE_PORT);
1272e5b636bSDmitry Torokhov 	if (a == b || a != c) {
1282a0f9c4cSHelge Deller 		printk(KERN_INFO "inport.c: Didn't find InPort mouse at %#x\n", INPORT_BASE);
12972155615SDmitry Torokhov 		err = -ENODEV;
13072155615SDmitry Torokhov 		goto err_release_region;
1311da177e4SLinus Torvalds 	}
1321da177e4SLinus Torvalds 
13372155615SDmitry Torokhov 	inport_dev = input_allocate_device();
13472155615SDmitry Torokhov 	if (!inport_dev) {
1352e5b636bSDmitry Torokhov 		printk(KERN_ERR "inport.c: Not enough memory for input device\n");
13672155615SDmitry Torokhov 		err = -ENOMEM;
13772155615SDmitry Torokhov 		goto err_release_region;
1382e5b636bSDmitry Torokhov 	}
1392e5b636bSDmitry Torokhov 
1402e5b636bSDmitry Torokhov 	inport_dev->name = INPORT_NAME;
1412e5b636bSDmitry Torokhov 	inport_dev->phys = "isa023c/input0";
1422e5b636bSDmitry Torokhov 	inport_dev->id.bustype = BUS_ISA;
1432e5b636bSDmitry Torokhov 	inport_dev->id.vendor  = INPORT_VENDOR;
1442e5b636bSDmitry Torokhov 	inport_dev->id.product = 0x0001;
1452e5b636bSDmitry Torokhov 	inport_dev->id.version = 0x0100;
1462e5b636bSDmitry Torokhov 
1477b19ada2SJiri Slaby 	inport_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
1487b19ada2SJiri Slaby 	inport_dev->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) |
1497b19ada2SJiri Slaby 		BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
1507b19ada2SJiri Slaby 	inport_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
1512e5b636bSDmitry Torokhov 
1522e5b636bSDmitry Torokhov 	inport_dev->open  = inport_open;
1532e5b636bSDmitry Torokhov 	inport_dev->close = inport_close;
1542e5b636bSDmitry Torokhov 
1551da177e4SLinus Torvalds 	outb(INPORT_RESET, INPORT_CONTROL_PORT);
1561da177e4SLinus Torvalds 	outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
1571da177e4SLinus Torvalds 	outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
1581da177e4SLinus Torvalds 
15972155615SDmitry Torokhov 	err = input_register_device(inport_dev);
16072155615SDmitry Torokhov 	if (err)
16172155615SDmitry Torokhov 		goto err_free_dev;
1621da177e4SLinus Torvalds 
1631da177e4SLinus Torvalds 	return 0;
16472155615SDmitry Torokhov 
16572155615SDmitry Torokhov  err_free_dev:
16672155615SDmitry Torokhov 	input_free_device(inport_dev);
16772155615SDmitry Torokhov  err_release_region:
16872155615SDmitry Torokhov 	release_region(INPORT_BASE, INPORT_EXTENT);
16972155615SDmitry Torokhov 
17072155615SDmitry Torokhov 	return err;
1711da177e4SLinus Torvalds }
1721da177e4SLinus Torvalds 
1731da177e4SLinus Torvalds static void __exit inport_exit(void)
1741da177e4SLinus Torvalds {
1752e5b636bSDmitry Torokhov 	input_unregister_device(inport_dev);
1761da177e4SLinus Torvalds 	release_region(INPORT_BASE, INPORT_EXTENT);
1771da177e4SLinus Torvalds }
1781da177e4SLinus Torvalds 
1791da177e4SLinus Torvalds module_init(inport_init);
1801da177e4SLinus Torvalds module_exit(inport_exit);
181