Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include "u.h"
2
#include "../port/lib.h"
3
#include "mem.h"
4
#include "dat.h"
5
#include "fns.h"
6
#include "../port/error.h"
7
#include "io.h"
8
 
9
#define	Image	IMAGE
10
#include <draw.h>
11
#include <memdraw.h>
12
#include <cursor.h>
13
#include "screen.h"
14
 
15
/*
16
 *  mouse types
17
 */
18
enum
19
{
20
	Mouseother=	0,
21
	Mouseserial=	1,
22
	MousePS2=	2,
23
};
24
 
25
extern int mouseshifted;
26
 
27
static QLock mousectlqlock;
28
static int mousetype;
29
static int intellimouse;
30
static int packetsize;
31
static int resolution;
32
static int accelerated;
33
static int mousehwaccel;
34
static char mouseport[5];
35
 
36
enum
37
{
38
	CMaccelerated,
39
	CMhwaccel,
40
	CMintellimouse,
41
	CMlinear,
42
	CMps2,
43
	CMps2intellimouse,
44
	CMres,
45
	CMreset,
46
	CMserial,
47
};
48
 
49
static Cmdtab mousectlmsg[] =
50
{
51
	CMaccelerated,		"accelerated",		0,
52
	CMhwaccel,		"hwaccel",		2,
53
	CMintellimouse,		"intellimouse",		1,
54
	CMlinear,		"linear",		1,
55
	CMps2,			"ps2",			1,
56
	CMps2intellimouse,	"ps2intellimouse",	1,
57
	CMres,			"res",			0,
58
	CMreset,		"reset",		1,
59
	CMserial,		"serial",		0,
60
};
61
 
62
/*
63
 *  ps/2 mouse message is three bytes
64
 *
65
 *	byte 0 -	0 0 SDY SDX 1 M R L
66
 *	byte 1 -	DX
67
 *	byte 2 -	DY
68
 *
69
 *  shift & right button is the same as middle button
70
 *
71
 * Intellimouse and AccuPoint with extra buttons deliver
72
 *	byte 3 -	00 or 01 or FF according to extra button state.
73
 * extra buttons are mapped in this code to buttons 4 and 5.
74
 * AccuPoint generates repeated events for these buttons;
75
*  it and Intellimouse generate 'down' events only, so
76
 * user-level code is required to generate button 'up' events
77
 * if they are needed by the application.
78
 * Also on laptops with AccuPoint AND external mouse, the
79
 * controller may deliver 3 or 4 bytes according to the type
80
 * of the external mouse; code must adapt.
81
 *
82
 * On the NEC Versa series (and perhaps others?) we seem to
83
 * lose a byte from the packet every once in a while, which
84
 * means we lose where we are in the instruction stream.
85
 * To resynchronize, if we get a byte more than two seconds
86
 * after the previous byte, we assume it's the first in a packet.
87
 */
88
static void
89
ps2mouseputc(int c, int shift)
90
{
91
	static short msg[4];
92
	static int nb;
93
	static uchar b[] = {0, 1, 4, 5, 2, 3, 6, 7, 0, 1, 2, 3, 2, 3, 6, 7 };
94
	static ulong lasttick;
95
	ulong m;
96
	int buttons, dx, dy;
97
 
98
	/*
99
	 * non-ps2 keyboards might not set shift
100
	 * but still set mouseshifted.
101
	 */
102
	shift |= mouseshifted;
103
	/*
104
	 * Resynchronize in stream with timing; see comment above.
105
	 */
106
	m = MACHP(0)->ticks;
107
	if(TK2SEC(m - lasttick) > 2)
108
		nb = 0;
109
	lasttick = m;
110
 
111
	/* 
112
	 *  check byte 0 for consistency
113
	 */
114
	if(nb==0 && (c&0xc8)!=0x08)
115
		if(intellimouse && (c==0x00 || c==0x01 || c==0xFF)){
116
			/* last byte of 4-byte packet */
117
			packetsize = 4;
118
			return;
119
		}
120
 
121
	msg[nb] = c;
122
	if(++nb == packetsize){
123
		nb = 0;
124
		if(msg[0] & 0x10)
125
			msg[1] |= 0xFF00;
126
		if(msg[0] & 0x20)
127
			msg[2] |= 0xFF00;
128
 
129
		buttons = b[(msg[0]&7) | (shift ? 8 : 0)];
130
		if(intellimouse && packetsize==4){
131
			if((msg[3]&0xc8) == 0x08){
132
				/* first byte of 3-byte packet */
133
				packetsize = 3;
134
				msg[0] = msg[3];
135
				nb = 1;
136
				/* fall through to emit previous packet */
137
			}else{
138
				/* The AccuPoint on the Toshiba 34[48]0CT
139
				 * encodes extra buttons as 4 and 5. They repeat
140
				 * and don't release, however, so user-level
141
				 * timing code is required. Furthermore,
142
				 * intellimice with 3buttons + scroll give a
143
				 * two's complement number in the lower 4 bits
144
				 * (bit 4 is sign extension) that describes
145
				 * the amount the scroll wheel has moved during
146
				 * the last sample. Here we use only the sign to
147
				 * decide whether the wheel is moving up or down
148
				 * and generate a single button 4 or 5 click
149
				 * accordingly.
150
				 */
151
				if((msg[3] >> 3) & 1) 
152
					buttons |= 1<<3;
153
				else if(msg[3] & 0x7) 
154
					buttons |= 1<<4;
155
			}
156
		}
157
		dx = msg[1];
158
		dy = -msg[2];
159
		mousetrack(dx, dy, buttons, TK2MS(MACHP(0)->ticks));
160
	}
161
	return;
162
}
163
 
164
/*
165
 *  set up a ps2 mouse
166
 */
167
static void
168
ps2mouse(void)
169
{
170
	if(mousetype == MousePS2)
171
		return;
172
 
173
	i8042auxenable(ps2mouseputc);
174
	/* make mouse streaming, enabled */
175
	i8042auxcmd(0xEA);
176
	i8042auxcmd(0xF4);
177
 
178
	mousetype = MousePS2;
179
	packetsize = 3;
180
	mousehwaccel = 1;
181
}
182
 
183
/*
184
 * The PS/2 Trackpoint multiplexor on the IBM Thinkpad T23 ignores
185
 * acceleration commands.  It is supposed to pass them on
186
 * to the attached device, but my Logitech mouse is simply
187
 * not behaving any differently.  For such devices, we allow
188
 * the user to use "hwaccel off" to tell us to back off to
189
 * software acceleration even if we're using the PS/2 port.
190
 * (Serial mice are always software accelerated.)
191
 * For more information on the Thinkpad multiplexor, see
192
 * http://wwwcssrv.almaden.ibm.com/trackpoint/
193
 */
194
static void
195
setaccelerated(int x)
196
{
197
	accelerated = x;
198
	if(mousehwaccel){
199
		switch(mousetype){
200
		case MousePS2:
201
			i8042auxcmd(0xE7);
202
			return;
203
		}
204
	}
205
	mouseaccelerate(x);
206
}
207
 
208
static void
209
setlinear(void)
210
{
211
	accelerated = 0;
212
	if(mousehwaccel){
213
		switch(mousetype){
214
		case MousePS2:
215
			i8042auxcmd(0xE6);
216
			return;
217
		}
218
	}
219
	mouseaccelerate(0);
220
}
221
 
222
static void
223
setres(int n)
224
{
225
	resolution = n;
226
	switch(mousetype){
227
	case MousePS2:
228
		i8042auxcmd(0xE8);
229
		i8042auxcmd(n);
230
		break;
231
	}
232
}
233
 
234
static void
235
setintellimouse(void)
236
{
237
	intellimouse = 1;
238
	packetsize = 4;
239
	switch(mousetype){
240
	case MousePS2:
241
		i8042auxcmd(0xF3);	/* set sample */
242
		i8042auxcmd(0xC8);
243
		i8042auxcmd(0xF3);	/* set sample */
244
		i8042auxcmd(0x64);
245
		i8042auxcmd(0xF3);	/* set sample */
246
		i8042auxcmd(0x50);
247
		break;
248
	case Mouseserial:
249
		i8250setmouseputc(mouseport, m5mouseputc);
250
		break;
251
	}
252
}
253
 
254
static void
255
resetmouse(void)
256
{
257
	packetsize = 3;
258
	switch(mousetype){
259
	case MousePS2:
260
		i8042auxcmd(0xF6);
261
		i8042auxcmd(0xEA);	/* streaming */
262
		i8042auxcmd(0xE8);	/* set resolution */
263
		i8042auxcmd(3);
264
		i8042auxcmd(0xF4);	/* enabled */
265
		break;
266
	}
267
}
268
 
269
void
270
mousectl(Cmdbuf *cb)
271
{
272
	Cmdtab *ct;
273
 
274
	qlock(&mousectlqlock);
275
	if(waserror()){
276
		qunlock(&mousectlqlock);
277
		nexterror();
278
	}
279
 
280
	ct = lookupcmd(cb, mousectlmsg, nelem(mousectlmsg));
281
	switch(ct->index){
282
	case CMaccelerated:
283
		setaccelerated(cb->nf == 1 ? 1 : atoi(cb->f[1]));
284
		break;
285
	case CMintellimouse:
286
		setintellimouse();
287
		break;
288
	case CMlinear:
289
		setlinear();
290
		break;
291
	case CMps2:
292
		intellimouse = 0;
293
		ps2mouse();
294
		break;
295
	case CMps2intellimouse:
296
		ps2mouse();
297
		setintellimouse();
298
		break;
299
	case CMres:
300
		if(cb->nf >= 2)
301
			setres(atoi(cb->f[1]));
302
		else
303
			setres(1);
304
		break;
305
	case CMreset:
306
		resetmouse();
307
		if(accelerated)
308
			setaccelerated(accelerated);
309
		if(resolution)
310
			setres(resolution);
311
		if(intellimouse)
312
			setintellimouse();
313
		break;
314
	case CMserial:
315
		if(mousetype == Mouseserial)
316
			error(Emouseset);
317
 
318
		if(cb->nf > 2){
319
			if(strcmp(cb->f[2], "M") == 0)
320
				i8250mouse(cb->f[1], m3mouseputc, 0);
321
			else if(strcmp(cb->f[2], "MI") == 0)
322
				i8250mouse(cb->f[1], m5mouseputc, 0);
323
			else
324
				i8250mouse(cb->f[1], mouseputc, cb->nf == 1);
325
		} else
326
			i8250mouse(cb->f[1], mouseputc, cb->nf == 1);
327
 
328
		mousetype = Mouseserial;
329
		strncpy(mouseport, cb->f[1], sizeof(mouseport)-1);
330
		packetsize = 3;
331
		break;
332
	case CMhwaccel:
333
		if(strcmp(cb->f[1], "on")==0)
334
			mousehwaccel = 1;
335
		else if(strcmp(cb->f[1], "off")==0)
336
			mousehwaccel = 0;
337
		else
338
			cmderror(cb, "bad mouse control message");
339
	}
340
 
341
	qunlock(&mousectlqlock);
342
	poperror();
343
}