1/*
2 * Macintosh ADB Mouse driver for Linux
3 *
4 * 27 Oct 1997 Michael Schmitz
5 * logitech fixes by anthony tong
6 * further hacking by Paul Mackerras
7 *
8 * Apple mouse protocol according to:
9 *
10 * Device code shamelessly stolen from:
11 */
12/*
13 * Atari Mouse Driver for Linux
14 * by Robert de Vries (robert@and.nl) 19Jul93
15 *
16 * 16 Nov 1994 Andreas Schwab
17 * Compatibility with busmouse
18 * Support for three button mouse (shamelessly stolen from MiNT)
19 * third button wired to one of the joystick directions on joystick 1
20 *
21 * 1996/02/11 Andreas Schwab
22 * Module support
23 * Allow multiple open's
24 *
25 * Converted to use new generic busmouse code.  11 July 1998
26 *   Russell King <rmk@arm.uk.linux.org>
27 */
28
29#include <linux/module.h>
30
31#include <linux/sched.h>
32#include <linux/errno.h>
33#include <linux/miscdevice.h>
34#include <linux/mm.h>
35#include <linux/random.h>
36#include <linux/poll.h>
37#include <linux/init.h>
38#include <linux/adb_mouse.h>
39
40#ifdef __powerpc__
41#include <asm/processor.h>
42#endif
43#if defined(__mc68000__) || defined(MODULE)
44#include <asm/setup.h>
45#endif
46
47#include "busmouse.h"
48
49static int msedev;
50static unsigned char adb_mouse_buttons[16];
51
52extern void (*adb_mouse_interrupt_hook)(unsigned char *, int);
53extern int adb_emulate_buttons;
54extern int adb_button2_keycode;
55extern int adb_button3_keycode;
56
57static void adb_mouse_interrupt(unsigned char *buf, int nb)
58{
59	int buttons, id;
60	char dx, dy;
61
62	/*
63	   Handler 1 -- 100cpi original Apple mouse protocol.
64	   Handler 2 -- 200cpi original Apple mouse protocol.
65
66	   For Apple's standard one-button mouse protocol the data array will
67	   contain the following values:
68
69		       BITS    COMMENTS
70	   data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
71	   data[1] = bxxx xxxx First button and x-axis motion.
72	   data[2] = byyy yyyy Second button and y-axis motion.
73
74	   Handler 4 -- Apple Extended mouse protocol.
75
76	   For Apple's 3-button mouse protocol the data array will contain the
77	   following values:
78
79		       BITS    COMMENTS
80	   data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
81	   data[1] = bxxx xxxx Left button and x-axis motion.
82	   data[2] = byyy yyyy Second button and y-axis motion.
83	   data[3] = byyy bxxx Third button and fourth button.
84		   Y is additiona. high bits of y-axis motion.
85		   X is additional high bits of x-axis motion.
86
87	   'buttons' here means 'button down' states!
88	   Button 1 (left)  : bit 2, busmouse button 3
89	   Button 2 (right) : bit 0, busmouse button 1
90	   Button 3 (middle): bit 1, busmouse button 2
91	 */
92
93	/* x/y and buttons swapped */
94
95	id = (buf[0] >> 4) & 0xf;
96
97	buttons = adb_mouse_buttons[id];
98
99	/* button 1 (left, bit 2) */
100	buttons = (buttons & 3) | (buf[1] & 0x80 ? 4 : 0); /* 1+2 unchanged */
101
102	/* button 2 (middle) */
103	buttons = (buttons & 5) | (buf[2] & 0x80 ? 2 : 0); /* 2+3 unchanged */
104
105	/* button 3 (right) present?
106	 *  on a logitech mouseman, the right and mid buttons sometimes behave
107	 *  strangely until they both have been pressed after booting. */
108	/* data valid only if extended mouse format ! */
109	if (nb >= 4)
110		buttons = (buttons & 6) | (buf[3] & 0x80 ? 1 : 0); /* 1+3 unchanged */
111
112	adb_mouse_buttons[id] = buttons;
113
114	/* a button is down if it is down on any mouse */
115	for (id = 0; id < 16; ++id)
116		buttons &= adb_mouse_buttons[id];
117
118	dx = ((buf[2] & 0x7f) < 64 ? (buf[2] & 0x7f) : (buf[2] & 0x7f) - 128);
119	dy = ((buf[1] & 0x7f) < 64 ? (buf[1] & 0x7f) : (buf[1] & 0x7f) - 128);
120	busmouse_add_movementbuttons(msedev, dx, -dy, buttons);
121
122	if (console_loglevel >= 8)
123		printk(" %X %X %X dx %d dy %d \n",
124		       buf[1], buf[2], buf[3], dx, dy);
125}
126
127static int release_mouse(struct inode *inode, struct file *file)
128{
129	adb_mouse_interrupt_hook = NULL;
130	return 0;
131}
132
133static int open_mouse(struct inode *inode, struct file *file)
134{
135	adb_mouse_interrupt_hook = adb_mouse_interrupt;
136	return 0;
137}
138
139static struct busmouse adb_mouse =
140{
141	ADB_MOUSE_MINOR, "adbmouse", THIS_MODULE, open_mouse, release_mouse, 7
142};
143
144static int __init adb_mouse_init(void)
145{
146#ifdef __powerpc__
147	if ((_machine != _MACH_chrp) && (_machine != _MACH_Pmac))
148		return -ENODEV;
149#endif
150#ifdef __mc68000__
151	if (!MACH_IS_MAC)
152		return -ENODEV;
153#endif
154	/* all buttons up */
155	memset(adb_mouse_buttons, 7, sizeof(adb_mouse_buttons));
156
157	msedev = register_busmouse(&adb_mouse);
158	if (msedev < 0)
159		printk(KERN_WARNING "Unable to register ADB mouse driver.\n");
160	else
161		printk(KERN_INFO "Macintosh ADB mouse driver installed.\n");
162
163	return msedev < 0 ? msedev : 0;
164}
165
166#ifndef MODULE
167
168static int __init adb_mouse_setup(char *str)
169{
170	int ints[4];
171
172	str = get_options(str, ARRAY_SIZE(ints), ints);
173	if (ints[0] >= 1) {
174		adb_emulate_buttons = ints[1];
175		if (ints[0] >= 2)
176			adb_button2_keycode = ints[2];
177		if (ints[0] >= 3)
178			adb_button3_keycode = ints[3];
179	}
180	return 1;
181}
182
183__setup("adb_buttons=", adb_mouse_setup);
184
185#endif /* !MODULE */
186
187static void __exit adb_mouse_cleanup(void)
188{
189	unregister_busmouse(msedev);
190}
191
192module_init(adb_mouse_init);
193module_exit(adb_mouse_cleanup);
194
195MODULE_LICENSE("GPL");
196