xref: /openbmc/linux/drivers/input/mouse/inport.c (revision 2d09ac95)
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 #include <linux/module.h>
171da177e4SLinus Torvalds #include <linux/ioport.h>
181da177e4SLinus Torvalds #include <linux/init.h>
191da177e4SLinus Torvalds #include <linux/interrupt.h>
201da177e4SLinus Torvalds #include <linux/input.h>
211da177e4SLinus Torvalds 
221da177e4SLinus Torvalds #include <asm/io.h>
231da177e4SLinus Torvalds #include <asm/irq.h>
241da177e4SLinus Torvalds 
251da177e4SLinus Torvalds MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
261da177e4SLinus Torvalds MODULE_DESCRIPTION("Inport (ATI XL and Microsoft) busmouse driver");
271da177e4SLinus Torvalds MODULE_LICENSE("GPL");
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds #define INPORT_BASE		0x23c
301da177e4SLinus Torvalds #define INPORT_EXTENT		4
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds #define INPORT_CONTROL_PORT	INPORT_BASE + 0
331da177e4SLinus Torvalds #define INPORT_DATA_PORT	INPORT_BASE + 1
341da177e4SLinus Torvalds #define INPORT_SIGNATURE_PORT	INPORT_BASE + 2
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds #define INPORT_REG_BTNS	0x00
371da177e4SLinus Torvalds #define INPORT_REG_X		0x01
381da177e4SLinus Torvalds #define INPORT_REG_Y		0x02
391da177e4SLinus Torvalds #define INPORT_REG_MODE		0x07
401da177e4SLinus Torvalds #define INPORT_RESET		0x80
411da177e4SLinus Torvalds 
428370a643SRobert P. J. Day #ifdef CONFIG_MOUSE_ATIXL
431da177e4SLinus Torvalds #define INPORT_NAME		"ATI XL Mouse"
441da177e4SLinus Torvalds #define INPORT_VENDOR		0x0002
451da177e4SLinus Torvalds #define INPORT_SPEED_30HZ	0x01
461da177e4SLinus Torvalds #define INPORT_SPEED_50HZ	0x02
471da177e4SLinus Torvalds #define INPORT_SPEED_100HZ	0x03
481da177e4SLinus Torvalds #define INPORT_SPEED_200HZ	0x04
491da177e4SLinus Torvalds #define INPORT_MODE_BASE	INPORT_SPEED_100HZ
501da177e4SLinus Torvalds #define INPORT_MODE_IRQ		0x08
511da177e4SLinus Torvalds #else
521da177e4SLinus Torvalds #define INPORT_NAME		"Microsoft InPort Mouse"
531da177e4SLinus Torvalds #define INPORT_VENDOR		0x0001
541da177e4SLinus Torvalds #define INPORT_MODE_BASE	0x10
551da177e4SLinus Torvalds #define INPORT_MODE_IRQ		0x01
561da177e4SLinus Torvalds #endif
571da177e4SLinus Torvalds #define INPORT_MODE_HOLD	0x20
581da177e4SLinus Torvalds 
591da177e4SLinus Torvalds #define INPORT_IRQ		5
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds static int inport_irq = INPORT_IRQ;
62f6b12d04SDavid Howells module_param_hw_named(irq, inport_irq, uint, irq, 0);
631da177e4SLinus Torvalds MODULE_PARM_DESC(irq, "IRQ number (5=default)");
641da177e4SLinus Torvalds 
652e5b636bSDmitry Torokhov static struct input_dev *inport_dev;
662e5b636bSDmitry Torokhov 
inport_interrupt(int irq,void * dev_id)677d12e780SDavid Howells static irqreturn_t inport_interrupt(int irq, void *dev_id)
682e5b636bSDmitry Torokhov {
692e5b636bSDmitry Torokhov 	unsigned char buttons;
702e5b636bSDmitry Torokhov 
712e5b636bSDmitry Torokhov 	outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
722e5b636bSDmitry Torokhov 	outb(INPORT_MODE_HOLD | INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
732e5b636bSDmitry Torokhov 
742e5b636bSDmitry Torokhov 	outb(INPORT_REG_X, INPORT_CONTROL_PORT);
752e5b636bSDmitry Torokhov 	input_report_rel(inport_dev, REL_X, inb(INPORT_DATA_PORT));
762e5b636bSDmitry Torokhov 
772e5b636bSDmitry Torokhov 	outb(INPORT_REG_Y, INPORT_CONTROL_PORT);
782e5b636bSDmitry Torokhov 	input_report_rel(inport_dev, REL_Y, inb(INPORT_DATA_PORT));
792e5b636bSDmitry Torokhov 
802e5b636bSDmitry Torokhov 	outb(INPORT_REG_BTNS, INPORT_CONTROL_PORT);
812e5b636bSDmitry Torokhov 	buttons = inb(INPORT_DATA_PORT);
822e5b636bSDmitry Torokhov 
832e5b636bSDmitry Torokhov 	input_report_key(inport_dev, BTN_MIDDLE, buttons & 1);
842e5b636bSDmitry Torokhov 	input_report_key(inport_dev, BTN_LEFT,   buttons & 2);
852e5b636bSDmitry Torokhov 	input_report_key(inport_dev, BTN_RIGHT,  buttons & 4);
862e5b636bSDmitry Torokhov 
872e5b636bSDmitry Torokhov 	outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
882e5b636bSDmitry Torokhov 	outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
892e5b636bSDmitry Torokhov 
902e5b636bSDmitry Torokhov 	input_sync(inport_dev);
912e5b636bSDmitry Torokhov 	return IRQ_HANDLED;
922e5b636bSDmitry Torokhov }
931da177e4SLinus Torvalds 
inport_open(struct input_dev * dev)941da177e4SLinus Torvalds static int inport_open(struct input_dev *dev)
951da177e4SLinus Torvalds {
961da177e4SLinus Torvalds 	if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL))
971da177e4SLinus Torvalds 		return -EBUSY;
981da177e4SLinus Torvalds 	outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
991da177e4SLinus Torvalds 	outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
1001da177e4SLinus Torvalds 
1011da177e4SLinus Torvalds 	return 0;
1021da177e4SLinus Torvalds }
1031da177e4SLinus Torvalds 
inport_close(struct input_dev * dev)1041da177e4SLinus Torvalds static void inport_close(struct input_dev *dev)
1051da177e4SLinus Torvalds {
1061da177e4SLinus Torvalds 	outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
1071da177e4SLinus Torvalds 	outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
1081da177e4SLinus Torvalds 	free_irq(inport_irq, NULL);
1091da177e4SLinus Torvalds }
1101da177e4SLinus Torvalds 
inport_init(void)1111da177e4SLinus Torvalds static int __init inport_init(void)
1121da177e4SLinus Torvalds {
1131da177e4SLinus Torvalds 	unsigned char a, b, c;
11472155615SDmitry Torokhov 	int err;
1151da177e4SLinus Torvalds 
1161da177e4SLinus Torvalds 	if (!request_region(INPORT_BASE, INPORT_EXTENT, "inport")) {
1171da177e4SLinus Torvalds 		printk(KERN_ERR "inport.c: Can't allocate ports at %#x\n", INPORT_BASE);
1181da177e4SLinus Torvalds 		return -EBUSY;
1191da177e4SLinus Torvalds 	}
1201da177e4SLinus Torvalds 
1211da177e4SLinus Torvalds 	a = inb(INPORT_SIGNATURE_PORT);
1221da177e4SLinus Torvalds 	b = inb(INPORT_SIGNATURE_PORT);
1231da177e4SLinus Torvalds 	c = inb(INPORT_SIGNATURE_PORT);
1242e5b636bSDmitry Torokhov 	if (a == b || a != c) {
1252a0f9c4cSHelge Deller 		printk(KERN_INFO "inport.c: Didn't find InPort mouse at %#x\n", INPORT_BASE);
12672155615SDmitry Torokhov 		err = -ENODEV;
12772155615SDmitry Torokhov 		goto err_release_region;
1281da177e4SLinus Torvalds 	}
1291da177e4SLinus Torvalds 
13072155615SDmitry Torokhov 	inport_dev = input_allocate_device();
13172155615SDmitry Torokhov 	if (!inport_dev) {
1322e5b636bSDmitry Torokhov 		printk(KERN_ERR "inport.c: Not enough memory for input device\n");
13372155615SDmitry Torokhov 		err = -ENOMEM;
13472155615SDmitry Torokhov 		goto err_release_region;
1352e5b636bSDmitry Torokhov 	}
1362e5b636bSDmitry Torokhov 
1372e5b636bSDmitry Torokhov 	inport_dev->name = INPORT_NAME;
1382e5b636bSDmitry Torokhov 	inport_dev->phys = "isa023c/input0";
1392e5b636bSDmitry Torokhov 	inport_dev->id.bustype = BUS_ISA;
1402e5b636bSDmitry Torokhov 	inport_dev->id.vendor  = INPORT_VENDOR;
1412e5b636bSDmitry Torokhov 	inport_dev->id.product = 0x0001;
1422e5b636bSDmitry Torokhov 	inport_dev->id.version = 0x0100;
1432e5b636bSDmitry Torokhov 
1447b19ada2SJiri Slaby 	inport_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
1457b19ada2SJiri Slaby 	inport_dev->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) |
1467b19ada2SJiri Slaby 		BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
1477b19ada2SJiri Slaby 	inport_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
1482e5b636bSDmitry Torokhov 
1492e5b636bSDmitry Torokhov 	inport_dev->open  = inport_open;
1502e5b636bSDmitry Torokhov 	inport_dev->close = inport_close;
1512e5b636bSDmitry Torokhov 
1521da177e4SLinus Torvalds 	outb(INPORT_RESET, INPORT_CONTROL_PORT);
1531da177e4SLinus Torvalds 	outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
1541da177e4SLinus Torvalds 	outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
1551da177e4SLinus Torvalds 
15672155615SDmitry Torokhov 	err = input_register_device(inport_dev);
15772155615SDmitry Torokhov 	if (err)
15872155615SDmitry Torokhov 		goto err_free_dev;
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds 	return 0;
16172155615SDmitry Torokhov 
16272155615SDmitry Torokhov  err_free_dev:
16372155615SDmitry Torokhov 	input_free_device(inport_dev);
16472155615SDmitry Torokhov  err_release_region:
16572155615SDmitry Torokhov 	release_region(INPORT_BASE, INPORT_EXTENT);
16672155615SDmitry Torokhov 
16772155615SDmitry Torokhov 	return err;
1681da177e4SLinus Torvalds }
1691da177e4SLinus Torvalds 
inport_exit(void)1701da177e4SLinus Torvalds static void __exit inport_exit(void)
1711da177e4SLinus Torvalds {
1722e5b636bSDmitry Torokhov 	input_unregister_device(inport_dev);
1731da177e4SLinus Torvalds 	release_region(INPORT_BASE, INPORT_EXTENT);
1741da177e4SLinus Torvalds }
1751da177e4SLinus Torvalds 
1761da177e4SLinus Torvalds module_init(inport_init);
1771da177e4SLinus Torvalds module_exit(inport_exit);
178