summaryrefslogtreecommitdiff
path: root/chips/dtop_handlers.c
blob: 7a83ea291f49b3b75226ecc5bf33a63c234ce5d5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
/* 
 * Mach Operating System
 * Copyright (c) 1992 Carnegie Mellon University
 * All Rights Reserved.
 * 
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 * 
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 * 
 * Carnegie Mellon requests users of this software to return to
 * 
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 * 
 * any improvements or extensions that they make and grant Carnegie Mellon
 * the rights to redistribute these changes.
 */
/*
 *	File: dtop_handlers.c
 * 	Author: Alessandro Forin, Carnegie Mellon University
 *	Date:	1/92
 *
 *	Handler functions for devices attached to the DESKTOP bus.
 */

#include <dtop.h>
#if	NDTOP > 0

#include <mach_kdb.h>

#include <machine/machspl.h>		/* spl definitions */
#include <mach/std_types.h>
#include <device/io_req.h>
#include <device/tty.h>

#include <chips/busses.h>
#include <chips/serial_defs.h>
#include <chips/screen_defs.h>
#include <mips/PMAX/tc.h>

#include <chips/dtop.h>
#include <chips/lk201.h>

/*
 * Default handler function
 */
int
dtop_null_device_handler(
	 dtop_device_t	dev,
	 dtop_message_t	msg,
	 int		event,
	 unsigned char	outc)
{
	/* See if the message was to the default address (powerup) */

	/* Uhmm, donno how to handle this. Drop it */
	if (event == DTOP_EVENT_RECEIVE_PACKET)
		dev->unknown_report = *msg;
	return 0;
}

/*
 * Handler for locator devices (mice)
 */
int
dtop_locator_handler(
	 dtop_device_t	dev,
	 dtop_message_t	msg,
	 int		event,
	 unsigned char	outc)
{
	register unsigned short	buttons;
	register short		coord;
#if	BYTE_MSF
#	define	get_short(b0,b1)	(((b1)<<8)|(b0))
#else
#	define	get_short(b0,b1)	(((b0)<<8)|(b1))
#endif

	/*
	 * Do the position first
	 */
	{
		register int		i;
		register boolean_t	moved;
		int			delta_coords[L_COORD_MAX];

		/*
		 * Get all coords, see if it moved at all (buttons!)
		 */
		moved = FALSE;
		for (i = 0; i < dev->locator.n_coords; i++) {

			coord = get_short(msg->body[2+(i<<1)],
					  msg->body[3+(i<<1)]);

			if (dev->locator.relative) {
				/*
				 * Flame on
				 * I am getting tired of this, why do they have to
				 * keep this bug around ?  Religion ?  Damn, they
				 * design a keyboard for X11 use and forget the mouse ?
				 * Flame off
				 */
#define	BOGUS_DEC_X_AXIS
#ifdef	BOGUS_DEC_X_AXIS
				if (i == 1) coord = - coord;
#endif	/* BOGUS_DEC_X_AXIS */
				/* dev->locator.coordinate[i] += coord; */
			} else {
				register unsigned int	old_coord;

				old_coord = dev->locator.coordinate[i];
				dev->locator.coordinate[i] = coord;
				coord = old_coord - coord;
			}
			delta_coords[i] = coord;
			if (coord != 0)
				moved = TRUE;
		}
		if (moved) {
			/* scale and threshold done higher up */
			screen_motion_event( 0,
				dev->locator.type,
				delta_coords[0],
				delta_coords[1]);
		}
	}

	/*
	 * Time for the buttons now
	 */
#define	new_buttons	coord
	new_buttons = get_short(msg->body[0],msg->body[1]);
	buttons = new_buttons ^ dev->locator.prev_buttons;
	if (buttons) {
		register int	i, type;

		dev->locator.prev_buttons = new_buttons;
		for (i = 0; buttons; i++, buttons >>= 1) {

			if ((buttons & 1) == 0) continue;

			type = (new_buttons & (1<<i)) ? 
				EVT_BUTTON_DOWN : EVT_BUTTON_UP;
			screen_keypress_event(	0,
						dev->locator.type,
						dev->locator.button_code[i],
						type);
		}
	}
#undef	new_buttons
}

/*
 * Handler for keyboard devices
 * Special case: outc set for recv packet means
 * we are inside the kernel debugger
 */
int
dtop_keyboard_handler(
	 dtop_device_t	dev,
	 dtop_message_t	msg,
	 int		event,
	 unsigned char	outc)
{
	char		save[11];
	register int	msg_len, c;

	/*
	 * Well, really this code handles just an lk401 and in
	 * a very primitive way at that.  Should at least emulate
	 * an lk201 decently, and make that a pluggable module.
	 * Sigh.
	 */

	if (event != DTOP_EVENT_RECEIVE_PACKET) {
		switch (event) {
		case DTOP_EVENT_POLL:
		    {
			register unsigned int	t, t0;

			/*
			 * Note we will always have at least the
			 * end-of-list marker present (a zero)
			 * Here stop and trigger of autorepeat.
			 * Do not repeat shift keys, either.
			 */
			{
				register unsigned char	uc, i = 0;

rpt_char:
				uc = dev->keyboard.last_codes[i];

				if (uc == DTOP_KBD_EMPTY) {
					dev->keyboard.k_ar_state = K_AR_OFF;
					return 0;
				}
				if ((uc >= LK_R_SHIFT) && (uc <= LK_R_ALT)) {
					/* sometimes swapped. Grrr. */
					if (++i < dev->keyboard.last_codes_count) 
						goto rpt_char;
					dev->keyboard.k_ar_state = K_AR_OFF;
					return 0;
				}
				c = uc;
			}

			/*
			 * Got a char. See if enough time from stroke,
			 * or from last repeat.
			 */
			t0 = (dev->keyboard.k_ar_state == K_AR_TRIGGER) ? 30 : 500;
			t = approx_time_in_msec();
			if ((t - dev->keyboard.last_msec) < t0)
				return 0;

			dev->keyboard.k_ar_state = K_AR_TRIGGER;

			/*
			 * Simplest thing to do is to mimic lk201
			 */
			outc = lk201_input(0, LK_REPEAT);
			if ( ! screen_keypress_event(	0,
							DEV_KEYBD,
							c,
							EVT_BUTTON_UP)) {
				if (outc > 0) cons_input(0, outc, 0);
			} else
				screen_keypress_event(	0,
							DEV_KEYBD,
							c,
							EVT_BUTTON_DOWN);
			return 0;
		    }
		default:	gimmeabreak();/*fornow*/
		}
		return -1;
	}

	msg_len = msg->code.val.len;

	/* Check for errors */
	c = msg->body[0];
	if ((c < DTOP_KBD_KEY_MIN) && (c != DTOP_KBD_EMPTY)) {
		printf("Keyboard error: %x %x %x..\n", msg_len, c, msg->body[1]);
		if (c != DTOP_KBD_OUT_ERR) return -1;
		/* spec sez if scan list overflow still there is data */
		msg->body[0] = 0;
	}

	dev->keyboard.last_msec = approx_time_in_msec();

	switch (dev->keyboard.k_ar_state) {
	case K_AR_IDLE:
		/* if from debugger, timeouts might not be working yet */
		if (outc == 0xff)
			break;
		dtop_keyboard_autorepeat( dev );
		/* fall through */
	case K_AR_TRIGGER:
		dev->keyboard.k_ar_state = K_AR_ACTIVE;
		break;
	case K_AR_ACTIVE:
		break;
	case K_AR_OFF:	gimmeabreak();	/* ??? */
		dev->keyboard.k_ar_state = K_AR_IDLE;
	}

	/*
	 * We can only assume that pressed keys are reported in the
	 * same order (a minimum of sanity, please) across scans.
	 * To make things readable, do a first pass cancelling out
	 * all keys that are still pressed, and a second one generating
	 * events.  While generating events, do the upstrokes first
	 * from oldest to youngest, then the downstrokes from oldest
	 * to youngest.  This copes with lost packets and provides
	 * a reasonable model even if scans are too slow.
	 */

	/* make a copy of new state first */
	{
		register char	*p, *q, *e;

		p = save;
		q = (char*)msg->body;
		e = (char*)&msg->body[msg_len];

		while (q < e)
			*p++ = *q++;
	}

	/*
	 * Do the cancelling pass
	 */
	{
		register char	*ls, *le, *ns, *ne, *sync;

		ls = (char*)dev->keyboard.last_codes;
		le = (char*)&dev->keyboard.last_codes[dev->keyboard.last_codes_count];
		ns = (char*)msg->body;
		ne = (char*)&msg->body[msg_len];

		/* sync marks where to restart scanning, saving
		   time thanks to ordering constraints */
		for (sync = ns; ls < le; ls++) {
			register char	c = *ls;
			for (ns = sync; ns < ne; ns++)
				if (c == *ns) {
					*ls = *ns = 0;
					sync = ns + 1;
					break;
				}
			/* we could already tell if c is an upstroke,
			   but see the above discussion about errors */
		}
	}
	/*
	 * Now generate all upstrokes
	 */
	{
		register char	*ls, *le;
		register unsigned char	c;

		le = (char*)dev->keyboard.last_codes;
		ls = (char*)&dev->keyboard.last_codes[dev->keyboard.last_codes_count - 1];

		for ( ; ls >= le; ls--)
		    if (c = *ls) {
			/* keep kernel notion of lk201 state consistent */
			(void) lk201_input(0,c);			

			if (outc == 0)
			    screen_keypress_event(0,
						  DEV_KEYBD,
						  c,
						  EVT_BUTTON_UP);
		    }
	}
	/*
	 * And finally the downstrokes
	 */
	{
		register char	*ns, *ne, c, retc;

		ne = (char*)msg->body;
		ns = (char*)&msg->body[msg_len - 1];
		retc = 0;

		for ( ; ns >= ne; ns--)
		    if (c = *ns) {
			register unsigned char	data;

			data = c;
			c = lk201_input(0, data);

			if (c == -2) {	/* just returned from kdb */
				/* NOTE: many things have happened while
				   we were sitting on the stack, now it
				   is last_codes that holds the truth */
#if 1
				/* But the truth might not be welcome.
				   If we get out because we hit RETURN
				   on the rconsole line all is well,
				   but if we did it from the keyboard
				   we get here on the downstroke. Then
				   we will get the upstroke which we
				   would give to X11. People complained
				   about this extra keypress..  so they
				   lose everything. */

				dev->keyboard.last_codes_count = 1;
				dev->keyboard.last_codes[0] = 0;
#endif
				return -1;
			}

			/*
			 * If X11 had better code for the keyboard this
			 * would be an EVT_BUTTON_DOWN.  But that would
			 * screwup the REPEAT function. Grrr.
			 */
			/* outc non zero sez we are in the debugger */
			if (outc == 0) {
			    if (screen_keypress_event(0,
						  DEV_KEYBD,
						  data,
						  EVT_BUTTON_DOWN))
				c = -1; /* consumed by X */
			    else
				if (c > 0) cons_input(0, c, 0);
			}
			/* return the xlated keycode anyways */
			if ((c > 0) && (retc == 0))
			    retc = c;
		    }
		outc = retc;
	}
	/* install new scan state */
	{
		register char	*p, *q, *e;

		p = (char*)dev->keyboard.last_codes;
		q = (char*)save;
		e = (char*)&save[msg_len];

		while (q < e)
			*p++ = *q++;
		dev->keyboard.last_codes_count = msg_len;
	}
	return outc;
}

/*
 * Polled operations: we must do autorepeat by hand. Sigh.
 */
dtop_keyboard_autorepeat(
	dtop_device_t	dev)
{
	spl_t	s = spltty();

	if (dev->keyboard.k_ar_state != K_AR_IDLE)
		dtop_keyboard_handler( dev, 0, DTOP_EVENT_POLL, 0);

	if (dev->keyboard.k_ar_state == K_AR_OFF)
		dev->keyboard.k_ar_state = K_AR_IDLE;
	else
		timeout( dtop_keyboard_autorepeat, dev, dev->keyboard.poll_frequency);

	splx(s);
}

#endif	/*NDTOP>0*/