xref: /plan9/sys/src/9/omap/mouse.c (revision 9363102901f027b4c277460d9c65669202d4ae69)
1*93631029SDavid du Colombier #include "u.h"
2*93631029SDavid du Colombier #include "../port/lib.h"
3*93631029SDavid du Colombier #include "mem.h"
4*93631029SDavid du Colombier #include "dat.h"
5*93631029SDavid du Colombier #include "fns.h"
6*93631029SDavid du Colombier #include "../port/error.h"
7*93631029SDavid du Colombier #include "io.h"
8*93631029SDavid du Colombier 
9*93631029SDavid du Colombier #define	Image	IMAGE
10*93631029SDavid du Colombier #include <draw.h>
11*93631029SDavid du Colombier #include <memdraw.h>
12*93631029SDavid du Colombier #include <cursor.h>
13*93631029SDavid du Colombier #include "screen.h"
14*93631029SDavid du Colombier 
15*93631029SDavid du Colombier /*
16*93631029SDavid du Colombier  *  mouse types
17*93631029SDavid du Colombier  */
18*93631029SDavid du Colombier enum
19*93631029SDavid du Colombier {
20*93631029SDavid du Colombier 	Mouseother=	0,
21*93631029SDavid du Colombier 	Mouseserial=	1,
22*93631029SDavid du Colombier 	MousePS2=	2,
23*93631029SDavid du Colombier };
24*93631029SDavid du Colombier 
25*93631029SDavid du Colombier extern int mouseshifted;
26*93631029SDavid du Colombier 
27*93631029SDavid du Colombier static QLock mousectlqlock;
28*93631029SDavid du Colombier static int mousetype;
29*93631029SDavid du Colombier static int intellimouse;
30*93631029SDavid du Colombier static int packetsize;
31*93631029SDavid du Colombier static int resolution;
32*93631029SDavid du Colombier static int accelerated;
33*93631029SDavid du Colombier static int mousehwaccel;
34*93631029SDavid du Colombier static char mouseport[5];
35*93631029SDavid du Colombier 
36*93631029SDavid du Colombier enum
37*93631029SDavid du Colombier {
38*93631029SDavid du Colombier 	CMaccelerated,
39*93631029SDavid du Colombier 	CMhwaccel,
40*93631029SDavid du Colombier 	CMintellimouse,
41*93631029SDavid du Colombier 	CMlinear,
42*93631029SDavid du Colombier 	CMps2,
43*93631029SDavid du Colombier 	CMps2intellimouse,
44*93631029SDavid du Colombier 	CMres,
45*93631029SDavid du Colombier 	CMreset,
46*93631029SDavid du Colombier 	CMserial,
47*93631029SDavid du Colombier };
48*93631029SDavid du Colombier 
49*93631029SDavid du Colombier static Cmdtab mousectlmsg[] =
50*93631029SDavid du Colombier {
51*93631029SDavid du Colombier 	CMaccelerated,		"accelerated",		0,
52*93631029SDavid du Colombier 	CMhwaccel,		"hwaccel",		2,
53*93631029SDavid du Colombier 	CMintellimouse,		"intellimouse",		1,
54*93631029SDavid du Colombier 	CMlinear,		"linear",		1,
55*93631029SDavid du Colombier 	CMps2,			"ps2",			1,
56*93631029SDavid du Colombier 	CMps2intellimouse,	"ps2intellimouse",	1,
57*93631029SDavid du Colombier 	CMres,			"res",			0,
58*93631029SDavid du Colombier 	CMreset,		"reset",		1,
59*93631029SDavid du Colombier 	CMserial,		"serial",		0,
60*93631029SDavid du Colombier };
61*93631029SDavid du Colombier 
62*93631029SDavid du Colombier /*
63*93631029SDavid du Colombier  *  ps/2 mouse message is three bytes
64*93631029SDavid du Colombier  *
65*93631029SDavid du Colombier  *	byte 0 -	0 0 SDY SDX 1 M R L
66*93631029SDavid du Colombier  *	byte 1 -	DX
67*93631029SDavid du Colombier  *	byte 2 -	DY
68*93631029SDavid du Colombier  *
69*93631029SDavid du Colombier  *  shift & right button is the same as middle button
70*93631029SDavid du Colombier  *
71*93631029SDavid du Colombier  * Intellimouse and AccuPoint with extra buttons deliver
72*93631029SDavid du Colombier  *	byte 3 -	00 or 01 or FF according to extra button state.
73*93631029SDavid du Colombier  * extra buttons are mapped in this code to buttons 4 and 5.
74*93631029SDavid du Colombier  * AccuPoint generates repeated events for these buttons;
75*93631029SDavid du Colombier *  it and Intellimouse generate 'down' events only, so
76*93631029SDavid du Colombier  * user-level code is required to generate button 'up' events
77*93631029SDavid du Colombier  * if they are needed by the application.
78*93631029SDavid du Colombier  * Also on laptops with AccuPoint AND external mouse, the
79*93631029SDavid du Colombier  * controller may deliver 3 or 4 bytes according to the type
80*93631029SDavid du Colombier  * of the external mouse; code must adapt.
81*93631029SDavid du Colombier  *
82*93631029SDavid du Colombier  * On the NEC Versa series (and perhaps others?) we seem to
83*93631029SDavid du Colombier  * lose a byte from the packet every once in a while, which
84*93631029SDavid du Colombier  * means we lose where we are in the instruction stream.
85*93631029SDavid du Colombier  * To resynchronize, if we get a byte more than two seconds
86*93631029SDavid du Colombier  * after the previous byte, we assume it's the first in a packet.
87*93631029SDavid du Colombier  */
88*93631029SDavid du Colombier static void
ps2mouseputc(int c,int shift)89*93631029SDavid du Colombier ps2mouseputc(int c, int shift)
90*93631029SDavid du Colombier {
91*93631029SDavid du Colombier 	static short msg[4];
92*93631029SDavid du Colombier 	static int nb;
93*93631029SDavid du Colombier 	static uchar b[] = {0, 1, 4, 5, 2, 3, 6, 7, 0, 1, 2, 3, 2, 3, 6, 7 };
94*93631029SDavid du Colombier 	static ulong lasttick;
95*93631029SDavid du Colombier 	ulong m;
96*93631029SDavid du Colombier 	int buttons, dx, dy;
97*93631029SDavid du Colombier 
98*93631029SDavid du Colombier 	shift |= mouseshifted;
99*93631029SDavid du Colombier 	m = MACHP(0)->ticks;
100*93631029SDavid du Colombier 	if(TK2SEC(m - lasttick) > 2)
101*93631029SDavid du Colombier 		nb = 0;
102*93631029SDavid du Colombier 	lasttick = m;
103*93631029SDavid du Colombier 	if(nb==0 && (c&0xc8)!=0x08)
104*93631029SDavid du Colombier 		if(intellimouse && (c==0x00 || c==0x01 || c==0xFF)){
105*93631029SDavid du Colombier 			packetsize = 4;
106*93631029SDavid du Colombier 			return;
107*93631029SDavid du Colombier 		}
108*93631029SDavid du Colombier 
109*93631029SDavid du Colombier 	msg[nb] = c;
110*93631029SDavid du Colombier 	if(++nb == packetsize){
111*93631029SDavid du Colombier 		nb = 0;
112*93631029SDavid du Colombier 		if(msg[0] & 0x10)
113*93631029SDavid du Colombier 			msg[1] |= 0xFF00;
114*93631029SDavid du Colombier 		if(msg[0] & 0x20)
115*93631029SDavid du Colombier 			msg[2] |= 0xFF00;
116*93631029SDavid du Colombier 
117*93631029SDavid du Colombier 		buttons = b[(msg[0]&7) | (shift ? 8 : 0)];
118*93631029SDavid du Colombier 		if(intellimouse && packetsize==4){
119*93631029SDavid du Colombier 			if((msg[3]&0xc8) == 0x08){
120*93631029SDavid du Colombier 				packetsize = 3;
121*93631029SDavid du Colombier 				msg[0] = msg[3];
122*93631029SDavid du Colombier 				nb = 1;
123*93631029SDavid du Colombier 			}else{
124*93631029SDavid du Colombier 				if((msg[3] >> 3) & 1)
125*93631029SDavid du Colombier 					buttons |= 1<<3;
126*93631029SDavid du Colombier 				else if(msg[3] & 0x7)
127*93631029SDavid du Colombier 					buttons |= 1<<4;
128*93631029SDavid du Colombier 			}
129*93631029SDavid du Colombier 		}
130*93631029SDavid du Colombier 		dx = msg[1];
131*93631029SDavid du Colombier 		dy = -msg[2];
132*93631029SDavid du Colombier 		mousetrack(dx, dy, buttons, TK2MS(MACHP(0)->ticks));
133*93631029SDavid du Colombier 	}
134*93631029SDavid du Colombier }
135*93631029SDavid du Colombier 
136*93631029SDavid du Colombier /*
137*93631029SDavid du Colombier  *  set up a ps2 mouse
138*93631029SDavid du Colombier  */
139*93631029SDavid du Colombier static void
ps2mouse(void)140*93631029SDavid du Colombier ps2mouse(void)
141*93631029SDavid du Colombier {
142*93631029SDavid du Colombier 	if(mousetype == MousePS2)
143*93631029SDavid du Colombier 		return;
144*93631029SDavid du Colombier 
145*93631029SDavid du Colombier //	i8042auxenable(ps2mouseputc);
146*93631029SDavid du Colombier //	i8042auxcmd(0xEA);	// TODO
147*93631029SDavid du Colombier //	i8042auxcmd(0xF4);
148*93631029SDavid du Colombier 
149*93631029SDavid du Colombier 	mousetype = MousePS2;
150*93631029SDavid du Colombier 	packetsize = 3;
151*93631029SDavid du Colombier 	mousehwaccel = 1;
152*93631029SDavid du Colombier }
153*93631029SDavid du Colombier 
154*93631029SDavid du Colombier /*
155*93631029SDavid du Colombier  * The PS/2 Trackpoint multiplexor on the IBM Thinkpad T23 ignores
156*93631029SDavid du Colombier  * acceleration commands.  It is supposed to pass them on
157*93631029SDavid du Colombier  * to the attached device, but my Logitech mouse is simply
158*93631029SDavid du Colombier  * not behaving any differently.  For such devices, we allow
159*93631029SDavid du Colombier  * the user to use "hwaccel off" to tell us to back off to
160*93631029SDavid du Colombier  * software acceleration even if we're using the PS/2 port.
161*93631029SDavid du Colombier  * (Serial mice are always software accelerated.)
162*93631029SDavid du Colombier  * For more information on the Thinkpad multiplexor, see
163*93631029SDavid du Colombier  * http://wwwcssrv.almaden.ibm.com/trackpoint/
164*93631029SDavid du Colombier  */
165*93631029SDavid du Colombier static void
setaccelerated(int x)166*93631029SDavid du Colombier setaccelerated(int x)
167*93631029SDavid du Colombier {
168*93631029SDavid du Colombier 	accelerated = x;
169*93631029SDavid du Colombier 	mouseaccelerate(x);
170*93631029SDavid du Colombier }
171*93631029SDavid du Colombier 
172*93631029SDavid du Colombier static void
setlinear(void)173*93631029SDavid du Colombier setlinear(void)
174*93631029SDavid du Colombier {
175*93631029SDavid du Colombier 	accelerated = 0;
176*93631029SDavid du Colombier 	mouseaccelerate(0);
177*93631029SDavid du Colombier }
178*93631029SDavid du Colombier 
179*93631029SDavid du Colombier static void
setres(int n)180*93631029SDavid du Colombier setres(int n)
181*93631029SDavid du Colombier {
182*93631029SDavid du Colombier 	resolution = n;
183*93631029SDavid du Colombier }
184*93631029SDavid du Colombier 
185*93631029SDavid du Colombier static void
setintellimouse(void)186*93631029SDavid du Colombier setintellimouse(void)
187*93631029SDavid du Colombier {
188*93631029SDavid du Colombier 	intellimouse = 1;
189*93631029SDavid du Colombier 	packetsize = 4;
190*93631029SDavid du Colombier }
191*93631029SDavid du Colombier 
192*93631029SDavid du Colombier static void
resetmouse(void)193*93631029SDavid du Colombier resetmouse(void)
194*93631029SDavid du Colombier {
195*93631029SDavid du Colombier 	packetsize = 3;
196*93631029SDavid du Colombier }
197*93631029SDavid du Colombier 
198*93631029SDavid du Colombier void
mousectl(Cmdbuf * cb)199*93631029SDavid du Colombier mousectl(Cmdbuf *cb)
200*93631029SDavid du Colombier {
201*93631029SDavid du Colombier 	Cmdtab *ct;
202*93631029SDavid du Colombier 
203*93631029SDavid du Colombier 	qlock(&mousectlqlock);
204*93631029SDavid du Colombier 	if(waserror()){
205*93631029SDavid du Colombier 		qunlock(&mousectlqlock);
206*93631029SDavid du Colombier 		nexterror();
207*93631029SDavid du Colombier 	}
208*93631029SDavid du Colombier 
209*93631029SDavid du Colombier 	ct = lookupcmd(cb, mousectlmsg, nelem(mousectlmsg));
210*93631029SDavid du Colombier 	switch(ct->index){
211*93631029SDavid du Colombier 	case CMaccelerated:
212*93631029SDavid du Colombier 		setaccelerated(cb->nf == 1? 1: atoi(cb->f[1]));
213*93631029SDavid du Colombier 		break;
214*93631029SDavid du Colombier 	case CMintellimouse:
215*93631029SDavid du Colombier 		setintellimouse();
216*93631029SDavid du Colombier 		break;
217*93631029SDavid du Colombier 	case CMlinear:
218*93631029SDavid du Colombier 		setlinear();
219*93631029SDavid du Colombier 		break;
220*93631029SDavid du Colombier 	case CMps2:
221*93631029SDavid du Colombier 		intellimouse = 0;
222*93631029SDavid du Colombier 		break;
223*93631029SDavid du Colombier 	case CMps2intellimouse:
224*93631029SDavid du Colombier 		setintellimouse();
225*93631029SDavid du Colombier 		break;
226*93631029SDavid du Colombier 	case CMres:
227*93631029SDavid du Colombier 		if(cb->nf >= 2)
228*93631029SDavid du Colombier 			setres(atoi(cb->f[1]));
229*93631029SDavid du Colombier 		else
230*93631029SDavid du Colombier 			setres(1);
231*93631029SDavid du Colombier 		break;
232*93631029SDavid du Colombier 	case CMreset:
233*93631029SDavid du Colombier 		resetmouse();
234*93631029SDavid du Colombier 		if(accelerated)
235*93631029SDavid du Colombier 			setaccelerated(accelerated);
236*93631029SDavid du Colombier 		if(resolution)
237*93631029SDavid du Colombier 			setres(resolution);
238*93631029SDavid du Colombier 		if(intellimouse)
239*93631029SDavid du Colombier 			setintellimouse();
240*93631029SDavid du Colombier 		break;
241*93631029SDavid du Colombier 	case CMserial:
242*93631029SDavid du Colombier 		error("serial mice not supported");
243*93631029SDavid du Colombier 		break;
244*93631029SDavid du Colombier 	case CMhwaccel:
245*93631029SDavid du Colombier 		if(strcmp(cb->f[1], "on")==0)
246*93631029SDavid du Colombier 			mousehwaccel = 1;
247*93631029SDavid du Colombier 		else if(strcmp(cb->f[1], "off")==0)
248*93631029SDavid du Colombier 			mousehwaccel = 0;
249*93631029SDavid du Colombier 		else
250*93631029SDavid du Colombier 			cmderror(cb, "bad mouse control message");
251*93631029SDavid du Colombier 	}
252*93631029SDavid du Colombier 
253*93631029SDavid du Colombier 	qunlock(&mousectlqlock);
254*93631029SDavid du Colombier 	poperror();
255*93631029SDavid du Colombier }
256