xref: /original-bsd/sys/pmax/dev/fb.c (revision 3705696b)
1 /*-
2  * Copyright (c) 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Ralph Campbell and Rick Macklem.
7  *
8  * %sccs.include.redist.c%
9  *
10  *	@(#)fb.c	8.1 (Berkeley) 06/10/93
11  */
12 
13 /*
14  *  devGraphics.c --
15  *
16  *     	This file contains machine-dependent routines for the graphics device.
17  *
18  *	Copyright (C) 1989 Digital Equipment Corporation.
19  *	Permission to use, copy, modify, and distribute this software and
20  *	its documentation for any purpose and without fee is hereby granted,
21  *	provided that the above copyright notice appears in all copies.
22  *	Digital Equipment Corporation makes no representations about the
23  *	suitability of this software for any purpose.  It is provided "as is"
24  *	without express or implied warranty.
25  *
26  * from: $Header: /sprite/src/kernel/dev/ds3100.md/RCS/devGraphics.c,
27  *	v 9.2 90/02/13 22:16:24 shirriff Exp $ SPRITE (DECWRL)";
28  */
29 
30 /*
31  * This file has all the routines common to the various frame buffer drivers
32  * including a generic ioctl routine. The pmax_fb structure is passed into the
33  * routines and has device specifics stored in it.
34  * The LK201 keycode mapping routine is also here along with initialization
35  * functions for the keyboard and mouse.
36  */
37 
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/ioctl.h>
41 #include <sys/tty.h>
42 #include <sys/time.h>
43 #include <sys/kernel.h>
44 #include <sys/ioctl.h>
45 #include <sys/file.h>
46 #include <sys/vnode.h>
47 #include <sys/errno.h>
48 #include <sys/proc.h>
49 #include <sys/mman.h>
50 #include <sys/syslog.h>
51 
52 #include <vm/vm.h>
53 #include <miscfs/specfs/specdev.h>
54 
55 #include <machine/machConst.h>
56 #include <machine/pmioctl.h>
57 
58 #include <pmax/dev/device.h>
59 #include <pmax/dev/font.c>
60 #include <pmax/dev/fbreg.h>
61 
62 #include <pmax/stand/dec_prom.h>
63 
64 #include <pmax/pmax/cons.h>
65 #include <pmax/pmax/pmaxtype.h>
66 
67 #include <dc.h>
68 #include <scc.h>
69 #include <dtop.h>
70 
71 void fbKbdEvent(), fbMouseEvent(), fbMouseButtons(), fbScroll();
72 void fbBlitc(), fbPutc();
73 extern int pmax_boardtype;
74 extern struct consdev cn_tab;
75 #if NDC > 0
76 #include <machine/dc7085cons.h>
77 extern int dcGetc(), dcparam();
78 extern void dcPutc();
79 #endif
80 #if NDTOP > 0
81 #include <pmax/dev/dtopreg.h>
82 extern void dtopKBDPutc();
83 #endif
84 #if NSCC > 0
85 #include <pmax/dev/sccreg.h>
86 extern int sccGetc(), sccparam();
87 extern void sccPutc();
88 #endif
89 
90 /*
91  * The default cursor.
92  */
93 u_short defCursor[32] = {
94 /* plane A */ 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF,
95 	      0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF,
96 /* plane B */ 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF,
97               0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF
98 
99 };
100 
101 /*
102  * Font mask bits used by fbBlitc().
103  */
104 static unsigned int fontmaskBits[16] = {
105 	0x00000000,
106 	0x00000001,
107 	0x00000100,
108 	0x00000101,
109 	0x00010000,
110 	0x00010001,
111 	0x00010100,
112 	0x00010101,
113 	0x01000000,
114 	0x01000001,
115 	0x01000100,
116 	0x01000101,
117 	0x01010000,
118 	0x01010001,
119 	0x01010100,
120 	0x01010101
121 };
122 
123 /*
124  * Ascii values of command keys.
125  */
126 #define KBD_TAB		'\t'
127 #define KBD_DEL		127
128 #define KBD_RET		'\r'
129 
130 /*
131  *  Define "hardware-independent" codes for the control, shift, meta and
132  *  function keys.  Codes start after the last 7-bit ASCII code (127)
133  *  and are assigned in an arbitrary order.
134  */
135 #define KBD_NOKEY	128
136 
137 #define KBD_F1		201
138 #define KBD_F2		202
139 #define KBD_F3		203
140 #define KBD_F4		204
141 #define KBD_F5		205
142 #define KBD_F6		206
143 #define KBD_F7		207
144 #define KBD_F8		208
145 #define KBD_F9		209
146 #define KBD_F10		210
147 #define KBD_F11		211
148 #define KBD_F12		212
149 #define KBD_F13		213
150 #define KBD_F14		214
151 #define KBD_HELP	215
152 #define KBD_DO		216
153 #define KBD_F17		217
154 #define KBD_F18		218
155 #define KBD_F19		219
156 #define KBD_F20		220
157 
158 #define KBD_FIND	221
159 #define KBD_INSERT	222
160 #define KBD_REMOVE	223
161 #define KBD_SELECT	224
162 #define KBD_PREVIOUS	225
163 #define KBD_NEXT	226
164 
165 #define KBD_KP_ENTER	227
166 #define KBD_KP_F1	228
167 #define KBD_KP_F2	229
168 #define KBD_KP_F3	230
169 #define KBD_KP_F4	231
170 #define KBD_LEFT	232
171 #define KBD_RIGHT	233
172 #define KBD_DOWN	234
173 #define KBD_UP		235
174 
175 #define KBD_CONTROL	236
176 #define KBD_SHIFT	237
177 #define KBD_CAPSLOCK	238
178 #define KBD_ALTERNATE	239
179 
180 /*
181  * Keyboard to Ascii, unshifted.
182  */
183 static unsigned char unshiftedAscii[] = {
184 /*  0 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
185 /*  4 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
186 /*  8 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
187 /*  c */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
188 /* 10 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
189 /* 14 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
190 /* 18 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
191 /* 1c */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
192 /* 20 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
193 /* 24 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
194 /* 28 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
195 /* 2c */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
196 /* 30 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
197 /* 34 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
198 /* 38 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
199 /* 3c */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
200 /* 40 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
201 /* 44 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
202 /* 48 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
203 /* 4c */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
204 /* 50 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
205 /* 54 */ KBD_NOKEY,	KBD_NOKEY,	KBD_F1,		KBD_F2,
206 /* 58 */ KBD_F3,	KBD_F4,		KBD_F5,		KBD_NOKEY,
207 /* 5c */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
208 /* 60 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
209 /* 64 */ KBD_F6,	KBD_F7,		KBD_F8,		KBD_F9,
210 /* 68 */ KBD_F10,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
211 /* 6c */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
212 /* 70 */ KBD_NOKEY,	'\033',		KBD_F12,	KBD_F13,
213 /* 74 */ KBD_F14,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
214 /* 78 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
215 /* 7c */ KBD_HELP,	KBD_DO,		KBD_NOKEY,	KBD_NOKEY,
216 /* 80 */ KBD_F17,	KBD_F18,	KBD_F19,	KBD_F20,
217 /* 84 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
218 /* 88 */ KBD_NOKEY,	KBD_NOKEY,	KBD_FIND,	KBD_INSERT,
219 /* 8c */ KBD_REMOVE,	KBD_SELECT,	KBD_PREVIOUS,	KBD_NEXT,
220 /* 90 */ KBD_NOKEY,	KBD_NOKEY,	'0',		KBD_NOKEY,
221 /* 94 */ '.',		KBD_KP_ENTER,	'1',		'2',
222 /* 98 */ '3',		'4',		'5',		'6',
223 /* 9c */ ',',		'7',		'8',		'9',
224 /* a0 */ '-',		KBD_KP_F1,	KBD_KP_F2,	KBD_KP_F3,
225 /* a4 */ KBD_KP_F4,	KBD_NOKEY,	KBD_NOKEY,	KBD_LEFT,
226 /* a8 */ KBD_RIGHT,	KBD_DOWN, 	KBD_UP,		KBD_NOKEY,
227 /* ac */ KBD_NOKEY,	KBD_NOKEY,	KBD_SHIFT,	KBD_CONTROL,
228 /* b0 */ KBD_CAPSLOCK,	KBD_ALTERNATE,	KBD_NOKEY,	KBD_NOKEY,
229 /* b4 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
230 /* b8 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
231 /* bc */ KBD_DEL,	KBD_RET,	KBD_TAB,	'`',
232 /* c0 */ '1',		'q',		'a',		'z',
233 /* c4 */ KBD_NOKEY,	'2',		'w',		's',
234 /* c8 */ 'x',		'<',		KBD_NOKEY,	'3',
235 /* cc */ 'e',		'd',		'c',		KBD_NOKEY,
236 /* d0 */ '4',		'r',		'f',		'v',
237 /* d4 */ ' ',		KBD_NOKEY,	'5',		't',
238 /* d8 */ 'g',		'b',		KBD_NOKEY,	'6',
239 /* dc */ 'y',		'h',		'n',		KBD_NOKEY,
240 /* e0 */ '7',		'u',		'j',		'm',
241 /* e4 */ KBD_NOKEY,	'8',		'i',		'k',
242 /* e8 */ ',',		KBD_NOKEY,	'9',		'o',
243 /* ec */ 'l',		'.',		KBD_NOKEY,	'0',
244 /* f0 */ 'p',		KBD_NOKEY,	';',		'/',
245 /* f4 */ KBD_NOKEY,	'=',		']',		'\\',
246 /* f8 */ KBD_NOKEY,	'-',		'[',		'\'',
247 /* fc */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
248 };
249 
250 /*
251  * Keyboard to Ascii, shifted.
252  */
253 static unsigned char shiftedAscii[] = {
254 /*  0 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
255 /*  4 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
256 /*  8 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
257 /*  c */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
258 /* 10 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
259 /* 14 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
260 /* 18 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
261 /* 1c */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
262 /* 20 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
263 /* 24 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
264 /* 28 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
265 /* 2c */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
266 /* 30 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
267 /* 34 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
268 /* 38 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
269 /* 3c */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
270 /* 40 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
271 /* 44 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
272 /* 48 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
273 /* 4c */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
274 /* 50 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
275 /* 54 */ KBD_NOKEY,	KBD_NOKEY,	KBD_F1,		KBD_F2,
276 /* 58 */ KBD_F3,	KBD_F4,		KBD_F5,		KBD_NOKEY,
277 /* 5c */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
278 /* 60 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
279 /* 64 */ KBD_F6,	KBD_F7,		KBD_F8,		KBD_F9,
280 /* 68 */ KBD_F10,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
281 /* 6c */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
282 /* 70 */ KBD_NOKEY,	KBD_F11,	KBD_F12,	KBD_F13,
283 /* 74 */ KBD_F14,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
284 /* 78 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
285 /* 7c */ KBD_HELP,	KBD_DO,		KBD_NOKEY,	KBD_NOKEY,
286 /* 80 */ KBD_F17,	KBD_F18,	KBD_F19,	KBD_F20,
287 /* 84 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
288 /* 88 */ KBD_NOKEY,	KBD_NOKEY,	KBD_FIND,	KBD_INSERT,
289 /* 8c */ KBD_REMOVE,	KBD_SELECT,	KBD_PREVIOUS,	KBD_NEXT,
290 /* 90 */ KBD_NOKEY,	KBD_NOKEY,	'0',		KBD_NOKEY,
291 /* 94 */ '.',		KBD_KP_ENTER,	'1',		'2',
292 /* 98 */ '3',		'4',		'5',		'6',
293 /* 9c */ ',',		'7',		'8',		'9',
294 /* a0 */ '-',		KBD_KP_F1,	KBD_KP_F2,	KBD_KP_F3,
295 /* a4 */ KBD_KP_F4,	KBD_NOKEY,	KBD_NOKEY,	KBD_LEFT,
296 /* a8 */ KBD_RIGHT,	KBD_DOWN, 	KBD_UP,		KBD_NOKEY,
297 /* ac */ KBD_NOKEY,	KBD_NOKEY,	KBD_SHIFT,	KBD_CONTROL,
298 /* b0 */ KBD_CAPSLOCK,	KBD_ALTERNATE,	KBD_NOKEY,	KBD_NOKEY,
299 /* b4 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
300 /* b8 */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
301 /* bc */ KBD_DEL,	KBD_RET,	KBD_TAB,	'~',
302 /* c0 */ '!',		'q',		'a',		'z',
303 /* c4 */ KBD_NOKEY,	'@',		'w',		's',
304 /* c8 */ 'x',		'>',		KBD_NOKEY,	'#',
305 /* cc */ 'e',		'd',		'c',		KBD_NOKEY,
306 /* d0 */ '$',		'r',		'f',		'v',
307 /* d4 */ ' ',		KBD_NOKEY,	'%',		't',
308 /* d8 */ 'g',		'b',		KBD_NOKEY,	'^',
309 /* dc */ 'y',		'h',		'n',		KBD_NOKEY,
310 /* e0 */ '&',		'u',		'j',		'm',
311 /* e4 */ KBD_NOKEY,	'*',		'i',		'k',
312 /* e8 */ '<',		KBD_NOKEY,	'(',		'o',
313 /* ec */ 'l',		'>',		KBD_NOKEY,	')',
314 /* f0 */ 'p',		KBD_NOKEY,	':',		'?',
315 /* f4 */ KBD_NOKEY,	'+',		'}',		'|',
316 /* f8 */ KBD_NOKEY,	'_',		'{',		'"',
317 /* fc */ KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,	KBD_NOKEY,
318 };
319 
320 /*
321  * Keyboard initialization string.
322  */
323 static u_char kbdInitString[] = {
324 	LK_LED_ENABLE, LED_ALL,		/* show we are resetting keyboard */
325 	LK_DEFAULTS,
326 	LK_CMD_MODE(LK_AUTODOWN, 1),
327 	LK_CMD_MODE(LK_AUTODOWN, 2),
328 	LK_CMD_MODE(LK_AUTODOWN, 3),
329 	LK_CMD_MODE(LK_DOWN, 4),	/* could also be LK_AUTODOWN */
330 	LK_CMD_MODE(LK_UPDOWN, 5),
331 	LK_CMD_MODE(LK_UPDOWN, 6),
332 	LK_CMD_MODE(LK_AUTODOWN, 7),
333 	LK_CMD_MODE(LK_AUTODOWN, 8),
334 	LK_CMD_MODE(LK_AUTODOWN, 9),
335 	LK_CMD_MODE(LK_AUTODOWN, 10),
336 	LK_CMD_MODE(LK_AUTODOWN, 11),
337 	LK_CMD_MODE(LK_AUTODOWN, 12),
338 	LK_CMD_MODE(LK_DOWN, 13),
339 	LK_CMD_MODE(LK_AUTODOWN, 14),
340 	LK_AR_ENABLE,			/* we want autorepeat by default */
341 	LK_CL_ENABLE, 0x83,		/* keyclick, volume */
342 	LK_KBD_ENABLE,			/* the keyboard itself */
343 	LK_BELL_ENABLE, 0x83,		/* keyboard bell, volume */
344 	LK_LED_DISABLE, LED_ALL,	/* clear keyboard leds */
345 };
346 
347 /*
348  *----------------------------------------------------------------------
349  *
350  * fbKbdEvent --
351  *
352  *	Process a received character.
353  *
354  * Results:
355  *	None.
356  *
357  * Side effects:
358  *	Events added to the queue.
359  *
360  *----------------------------------------------------------------------
361  */
362 void
363 fbKbdEvent(ch, fp)
364 	int ch;
365 	register struct pmax_fb *fp;
366 {
367 	register pmEvent *eventPtr;
368 	int i;
369 
370 	if (!fp->GraphicsOpen)
371 		return;
372 
373 	/*
374 	 * See if there is room in the queue.
375 	 */
376 	i = PM_EVROUND(fp->fbu->scrInfo.qe.eTail + 1);
377 	if (i == fp->fbu->scrInfo.qe.eHead)
378 		return;
379 
380 	/*
381 	 * Add the event to the queue.
382 	 */
383 	eventPtr = &fp->fbu->events[fp->fbu->scrInfo.qe.eTail];
384 	eventPtr->type = BUTTON_RAW_TYPE;
385 	eventPtr->device = KEYBOARD_DEVICE;
386 	eventPtr->x = fp->fbu->scrInfo.mouse.x;
387 	eventPtr->y = fp->fbu->scrInfo.mouse.y;
388 	eventPtr->time = TO_MS(time);
389 	eventPtr->key = ch;
390 	fp->fbu->scrInfo.qe.eTail = i;
391 	selwakeup(&fp->selp);
392 }
393 
394 /*
395  *----------------------------------------------------------------------
396  *
397  * fbMouseEvent --
398  *
399  *	Process a mouse event.
400  *
401  * Results:
402  *	None.
403  *
404  * Side effects:
405  *	An event is added to the event queue.
406  *
407  *----------------------------------------------------------------------
408  */
409 void
410 fbMouseEvent(newRepPtr, fp)
411 	register MouseReport *newRepPtr;
412 	register struct pmax_fb *fp;
413 {
414 	unsigned milliSec;
415 	int i;
416 	pmEvent *eventPtr;
417 
418 	if (!fp->GraphicsOpen)
419 		return;
420 
421 	milliSec = TO_MS(time);
422 
423 	/*
424 	 * Check to see if we have to accelerate the mouse
425 	 */
426 	if (fp->fbu->scrInfo.mscale >= 0) {
427 		if (newRepPtr->dx >= fp->fbu->scrInfo.mthreshold) {
428 			newRepPtr->dx +=
429 				(newRepPtr->dx - fp->fbu->scrInfo.mthreshold) *
430 				fp->fbu->scrInfo.mscale;
431 		}
432 		if (newRepPtr->dy >= fp->fbu->scrInfo.mthreshold) {
433 			newRepPtr->dy +=
434 				(newRepPtr->dy - fp->fbu->scrInfo.mthreshold) *
435 				fp->fbu->scrInfo.mscale;
436 		}
437 	}
438 
439 	/*
440 	 * Update mouse position
441 	 */
442 	if (newRepPtr->state & MOUSE_X_SIGN) {
443 		fp->fbu->scrInfo.mouse.x += newRepPtr->dx;
444 		if (fp->fbu->scrInfo.mouse.x > fp->fbu->scrInfo.max_cur_x)
445 			fp->fbu->scrInfo.mouse.x = fp->fbu->scrInfo.max_cur_x;
446 	} else {
447 		fp->fbu->scrInfo.mouse.x -= newRepPtr->dx;
448 		if (fp->fbu->scrInfo.mouse.x < fp->fbu->scrInfo.min_cur_x)
449 			fp->fbu->scrInfo.mouse.x = fp->fbu->scrInfo.min_cur_x;
450 	}
451 	if (newRepPtr->state & MOUSE_Y_SIGN) {
452 		fp->fbu->scrInfo.mouse.y -= newRepPtr->dy;
453 		if (fp->fbu->scrInfo.mouse.y < fp->fbu->scrInfo.min_cur_y)
454 			fp->fbu->scrInfo.mouse.y = fp->fbu->scrInfo.min_cur_y;
455 	} else {
456 		fp->fbu->scrInfo.mouse.y += newRepPtr->dy;
457 		if (fp->fbu->scrInfo.mouse.y > fp->fbu->scrInfo.max_cur_y)
458 			fp->fbu->scrInfo.mouse.y = fp->fbu->scrInfo.max_cur_y;
459 	}
460 
461 	/*
462 	 * Move the hardware cursor.
463 	 */
464 	(*fp->posCursor)(fp->fbu->scrInfo.mouse.x, fp->fbu->scrInfo.mouse.y);
465 
466 	/*
467 	 * Store the motion event in the motion buffer.
468 	 */
469 	fp->fbu->tcs[fp->fbu->scrInfo.qe.tcNext].time = milliSec;
470 	fp->fbu->tcs[fp->fbu->scrInfo.qe.tcNext].x = fp->fbu->scrInfo.mouse.x;
471 	fp->fbu->tcs[fp->fbu->scrInfo.qe.tcNext].y = fp->fbu->scrInfo.mouse.y;
472 	if (++fp->fbu->scrInfo.qe.tcNext >= MOTION_BUFFER_SIZE)
473 		fp->fbu->scrInfo.qe.tcNext = 0;
474 	if (fp->fbu->scrInfo.mouse.y < fp->fbu->scrInfo.mbox.bottom &&
475 	    fp->fbu->scrInfo.mouse.y >=  fp->fbu->scrInfo.mbox.top &&
476 	    fp->fbu->scrInfo.mouse.x < fp->fbu->scrInfo.mbox.right &&
477 	    fp->fbu->scrInfo.mouse.x >=  fp->fbu->scrInfo.mbox.left)
478 		return;
479 
480 	fp->fbu->scrInfo.mbox.bottom = 0;
481 	if (PM_EVROUND(fp->fbu->scrInfo.qe.eTail + 1) == fp->fbu->scrInfo.qe.eHead)
482 		return;
483 
484 	i = PM_EVROUND(fp->fbu->scrInfo.qe.eTail - 1);
485 	if ((fp->fbu->scrInfo.qe.eTail != fp->fbu->scrInfo.qe.eHead) &&
486 	    (i != fp->fbu->scrInfo.qe.eHead)) {
487 		pmEvent *eventPtr;
488 
489 		eventPtr = &fp->fbu->events[i];
490 		if (eventPtr->type == MOTION_TYPE) {
491 			eventPtr->x = fp->fbu->scrInfo.mouse.x;
492 			eventPtr->y = fp->fbu->scrInfo.mouse.y;
493 			eventPtr->time = milliSec;
494 			eventPtr->device = MOUSE_DEVICE;
495 			return;
496 		}
497 	}
498 	/*
499 	 * Put event into queue and wakeup any waiters.
500 	 */
501 	eventPtr = &fp->fbu->events[fp->fbu->scrInfo.qe.eTail];
502 	eventPtr->type = MOTION_TYPE;
503 	eventPtr->time = milliSec;
504 	eventPtr->x = fp->fbu->scrInfo.mouse.x;
505 	eventPtr->y = fp->fbu->scrInfo.mouse.y;
506 	eventPtr->device = MOUSE_DEVICE;
507 	fp->fbu->scrInfo.qe.eTail = PM_EVROUND(fp->fbu->scrInfo.qe.eTail + 1);
508 	selwakeup(&fp->selp);
509 }
510 
511 /*
512  *----------------------------------------------------------------------
513  *
514  * fbMouseButtons --
515  *
516  *	Process mouse buttons.
517  *
518  * Results:
519  *	None.
520  *
521  * Side effects:
522  *	None.
523  *
524  *----------------------------------------------------------------------
525  */
526 void
527 fbMouseButtons(newRepPtr, fp)
528 	MouseReport *newRepPtr;
529 	register struct pmax_fb *fp;
530 {
531 	static char temp, oldSwitch, newSwitch;
532 	int i, j;
533 	pmEvent *eventPtr;
534 	static MouseReport lastRep;
535 
536 	if (!fp->GraphicsOpen)
537 		return;
538 
539 	newSwitch = newRepPtr->state & 0x07;
540 	oldSwitch = lastRep.state & 0x07;
541 
542 	temp = oldSwitch ^ newSwitch;
543 	if (temp == 0)
544 		return;
545 	for (j = 1; j < 8; j <<= 1) {
546 		if ((j & temp) == 0)
547 			continue;
548 
549 		/*
550 		 * Check for room in the queue
551 		 */
552 		i = PM_EVROUND(fp->fbu->scrInfo.qe.eTail+1);
553 		if (i == fp->fbu->scrInfo.qe.eHead)
554 			return;
555 
556 		/*
557 		 * Put event into queue.
558 		 */
559 		eventPtr = &fp->fbu->events[fp->fbu->scrInfo.qe.eTail];
560 
561 		switch (j) {
562 		case RIGHT_BUTTON:
563 			eventPtr->key = EVENT_RIGHT_BUTTON;
564 			break;
565 
566 		case MIDDLE_BUTTON:
567 			eventPtr->key = EVENT_MIDDLE_BUTTON;
568 			break;
569 
570 		case LEFT_BUTTON:
571 			eventPtr->key = EVENT_LEFT_BUTTON;
572 		}
573 		if (newSwitch & j)
574 			eventPtr->type = BUTTON_DOWN_TYPE;
575 		else
576 			eventPtr->type = BUTTON_UP_TYPE;
577 		eventPtr->device = MOUSE_DEVICE;
578 
579 		eventPtr->time = TO_MS(time);
580 		eventPtr->x = fp->fbu->scrInfo.mouse.x;
581 		eventPtr->y = fp->fbu->scrInfo.mouse.y;
582 		fp->fbu->scrInfo.qe.eTail = i;
583 	}
584 	selwakeup(&fp->selp);
585 
586 	lastRep = *newRepPtr;
587 	fp->fbu->scrInfo.mswitches = newSwitch;
588 }
589 
590 /*
591  *----------------------------------------------------------------------
592  *
593  * fbScroll --
594  *
595  *	Scroll the screen.
596  *
597  * Results:
598  *	None.
599  *
600  * Side effects:
601  *	None.
602  *
603  *----------------------------------------------------------------------
604  */
605 void
606 fbScroll(fp)
607 	register struct pmax_fb *fp;
608 {
609 	register int *dest, *src;
610 	register int *end;
611 	register int temp0, temp1, temp2, temp3;
612 	register int i, scanInc, lineCount;
613 	int line;
614 
615 	/*
616 	 * If the mouse is on we don't scroll so that the bit map remains sane.
617 	 */
618 	if (fp->GraphicsOpen) {
619 		fp->row = 0;
620 		return;
621 	}
622 
623 	/*
624 	 *  The following is an optimization to cause the scrolling
625 	 *  of text to be memory limited.  Basically the writebuffer is
626 	 *  4 words (32 bits ea.) long so to achieve maximum speed we
627 	 *  read and write in multiples of 4 words. We also limit the
628 	 *  size to be fp->fbu->scrInfo.max_col characters for more speed.
629 	 */
630 	if (fp->isMono) {
631 		lineCount = 5;
632 		line = 1920 * 2;
633 		scanInc = 44;
634 	} else {
635 		lineCount = 40;
636 		if (fp->fbu->scrInfo.max_x > 1024) {
637 			scanInc = 352;
638 			line = 1920 * 16;
639 		} else {
640 			scanInc = 96;
641 			line = 1920 * 8;
642 		}
643 	}
644 	src = (int *)(fp->fr_addr + line);
645 	dest = (int *)(fp->fr_addr);
646 	end = (int *)(fp->fr_addr + (68 * line) - line);
647 	do {
648 		i = 0;
649 		do {
650 			temp0 = src[0];
651 			temp1 = src[1];
652 			temp2 = src[2];
653 			temp3 = src[3];
654 			dest[0] = temp0;
655 			dest[1] = temp1;
656 			dest[2] = temp2;
657 			dest[3] = temp3;
658 			dest += 4;
659 			src += 4;
660 			i++;
661 		} while (i < lineCount);
662 		src += scanInc;
663 		dest += scanInc;
664 	} while (src < end);
665 
666 	/*
667 	 * Now zero out the last two lines
668 	 */
669 	bzero(fp->fr_addr + (fp->row * line), 3 * line);
670 }
671 
672 /*
673  *----------------------------------------------------------------------
674  *
675  * fbPutc --
676  *
677  *	Write a character to the console.
678  *
679  * Results:
680  *	None.
681  *
682  * Side effects:
683  *	None.
684  *
685  *----------------------------------------------------------------------
686  */
687 void
688 fbPutc(dev, c)
689 	dev_t dev;
690 	register int c;
691 {
692 	int s;
693 
694 	if (cn_tab.cn_fb) {
695 		static int recurse;
696 
697 		/*
698 		 * We need to prevent recursion in case a printf to the
699 		 * console happens at interrupt time but using splhigh()
700 		 * all the time locks out interrupts too much. We simply
701 		 * discard the character in this case and rely on the
702 		 * console log buffer to save the message.
703 		 */
704 		if (recurse)
705 			return;
706 		recurse = 1;
707 		fbBlitc(c, cn_tab.cn_fb);
708 		recurse = 0;
709 	} else {
710 		s = splhigh();
711 		(*callv->printf)("%c", c);
712 		splx(s);
713 	}
714 }
715 
716 /*
717  *----------------------------------------------------------------------
718  *
719  * fbBlitc --
720  *
721  *	Write a character to the screen.
722  *
723  * Results:
724  *	None.
725  *
726  * Side effects:
727  *	None.
728  *
729  *----------------------------------------------------------------------
730  */
731 void
732 fbBlitc(c, fp)
733 	register int c;
734 	register struct pmax_fb *fp;
735 {
736 	register char *bRow, *fRow;
737 	register int i;
738 	register int ote;
739 	int colMult = fp->isMono ? 1 : 8;
740 
741 	if (fp->isMono)
742 		ote = 256;
743 	else
744 		ote = ((fp->fbu->scrInfo.max_x + 1023) / 1024) * 1024;
745 	c &= 0xff;
746 
747 	switch (c) {
748 	case '\t':
749 		for (i = 8 - (fp->col & 0x7); i > 0; i--)
750 			fbBlitc(' ', fp);
751 		break;
752 
753 	case '\r':
754 		fp->col = 0;
755 		break;
756 
757 	case '\b':
758 		fp->col--;
759 		if (fp->col < 0)
760 			fp->col = 0;
761 		break;
762 
763 	case '\n':
764 		if (fp->row + 1 >= fp->fbu->scrInfo.max_row)
765 			fbScroll(fp);
766 		else
767 			fp->row++;
768 		fp->col = 0;
769 		break;
770 
771 	case '\007':
772 		(*fp->KBDPutc)(fp->kbddev, LK_RING_BELL);
773 		break;
774 
775 	default:
776 		/*
777 		 * 0xA1 to 0xFD are the printable characters added with 8-bit
778 		 * support.
779 		 */
780 		if (c < ' ' || c > '~' && c < 0xA1 || c > 0xFD)
781 			break;
782 		/*
783 		 * If the next character will wrap around then
784 		 * increment fp->row counter or scroll screen.
785 		 */
786 		if (fp->col >= fp->fbu->scrInfo.max_col) {
787 			fp->col = 0;
788 			if (fp->row + 1 >= fp->fbu->scrInfo.max_row)
789 				fbScroll(fp);
790 			else
791 				fp->row++;
792 		}
793 		bRow = (char *)(fp->fr_addr +
794 			(fp->row * 15 & 0x3ff) * ote + fp->col * colMult);
795 		i = c - ' ';
796 		/*
797 		 * This is to skip the (32) 8-bit
798 		 * control chars, as well as DEL
799 		 * and 0xA0 which aren't printable
800 		 */
801 		if (c > '~')
802 			i -= 34;
803 		i *= 15;
804 		fRow = (char *)((int)pmFont + i);
805 
806 		/* inline expansion for speed */
807 		if (fp->isMono) {
808 			*bRow = *fRow++; bRow += ote;
809 			*bRow = *fRow++; bRow += ote;
810 			*bRow = *fRow++; bRow += ote;
811 			*bRow = *fRow++; bRow += ote;
812 			*bRow = *fRow++; bRow += ote;
813 			*bRow = *fRow++; bRow += ote;
814 			*bRow = *fRow++; bRow += ote;
815 			*bRow = *fRow++; bRow += ote;
816 			*bRow = *fRow++; bRow += ote;
817 			*bRow = *fRow++; bRow += ote;
818 			*bRow = *fRow++; bRow += ote;
819 			*bRow = *fRow++; bRow += ote;
820 			*bRow = *fRow++; bRow += ote;
821 			*bRow = *fRow++; bRow += ote;
822 			*bRow = *fRow++; bRow += ote;
823 		} else {
824 			register int j;
825 			register unsigned int *pInt;
826 
827 			pInt = (unsigned int *)bRow;
828 			for (j = 0; j < 15; j++) {
829 				/*
830 				 * fontmaskBits converts a nibble
831 				 * (4 bytes) to a long word
832 				 * containing 4 pixels corresponding
833 				 * to each bit in the nibble.  Thus
834 				 * we write two longwords for each
835 				 * byte in font.
836 				 *
837 				 * Remember the font is 8 bits wide
838 				 * and 15 bits high.
839 				 *
840 				 * We add 256/512 to the pointer to
841 				 * point to the pixel on the
842 				 * next scan line
843 				 * directly below the current
844 				 * pixel.
845 				 */
846 				pInt[0] = fontmaskBits[(*fRow) & 0xf];
847 				pInt[1] = fontmaskBits[((*fRow) >> 4) & 0xf];
848 				fRow++;
849 				if (fp->fbu->scrInfo.max_x > 1024)
850 					pInt += 512;
851 				else
852 					pInt += 256;
853 			}
854 		}
855 		fp->col++; /* increment column counter */
856 	}
857 	if (!fp->GraphicsOpen)
858 		(*fp->posCursor)(fp->col * 8, fp->row * 15);
859 }
860 
861 /*
862  * ----------------------------------------------------------------------------
863  *
864  * kbdMapChar --
865  *
866  *	Map characters from the keyboard to ASCII. Return -1 if there is
867  *	no valid mapping.
868  *
869  * Results:
870  *	None.
871  *
872  * Side effects:
873  *	Remember state of shift and control keys.
874  *
875  * ----------------------------------------------------------------------------
876  */
877 kbdMapChar(cc)
878 	int cc;
879 {
880 	static u_char shiftDown;
881 	static u_char ctrlDown;
882 	static u_char lastChar;
883 
884 	switch (cc) {
885 	case KEY_REPEAT:
886 		cc = lastChar;
887 		goto done;
888 
889 	case KEY_UP:
890 		shiftDown = 0;
891 		ctrlDown = 0;
892 		return (-1);
893 
894 	case KEY_SHIFT:
895 	case KEY_R_SHIFT:
896 		if (ctrlDown || shiftDown)
897 			shiftDown = 0;
898 		else
899 			shiftDown = 1;
900 		return (-1);
901 
902 	case KEY_CONTROL:
903 		if (shiftDown || ctrlDown)
904 			ctrlDown = 0;
905 		else
906 			ctrlDown = 1;
907 		return (-1);
908 
909 	case LK_POWER_ERROR:
910 	case LK_KDOWN_ERROR:
911 	case LK_INPUT_ERROR:
912 	case LK_OUTPUT_ERROR:
913 		log(LOG_WARNING,
914 			"lk201: keyboard error, code=%x\n", cc);
915 		return (-1);
916 	}
917 	if (shiftDown)
918 		cc = shiftedAscii[cc];
919 	else
920 		cc = unshiftedAscii[cc];
921 	if (cc >= KBD_NOKEY) {
922 		/*
923 		 * A function key was typed - ignore it.
924 		 */
925 		return (-1);
926 	}
927 	if (cc >= 'a' && cc <= 'z') {
928 		if (ctrlDown)
929 			cc = cc - 'a' + '\1'; /* ^A */
930 		else if (shiftDown)
931 			cc = cc - 'a' + 'A';
932 	} else if (ctrlDown) {
933 		if (cc >= '[' && cc <= '_')
934 			cc = cc - '@';
935 		else if (cc == ' ' || cc == '@')
936 			cc = '\0';
937 	}
938 	lastChar = cc;
939 done:
940 	return (cc);
941 }
942 
943 /*
944  * Initialize the Keyboard.
945  */
946 void
947 KBDReset(kbddev, putc)
948 	dev_t kbddev;
949 	void (*putc)();
950 {
951 	register int i;
952 	static int inKBDReset;
953 
954 	if (inKBDReset)
955 		return;
956 	inKBDReset = 1;
957 	for (i = 0; i < sizeof(kbdInitString); i++)
958 		(*putc)(kbddev, (int)kbdInitString[i]);
959 	inKBDReset = 0;
960 }
961 
962 /*
963  * Initialize the mouse.
964  */
965 void
966 MouseInit(mdev, putc, getc)
967 	dev_t mdev;
968 	void (*putc)();
969 	int (*getc)();
970 {
971 	int id_byte1, id_byte2, id_byte3, id_byte4;
972 
973 	/*
974 	 * Initialize the mouse.
975 	 */
976 	(*putc)(mdev, MOUSE_SELF_TEST);
977 	id_byte1 = (*getc)(mdev);
978 	if (id_byte1 < 0) {
979 		printf("MouseInit: Timeout on 1st byte of self-test report\n");
980 		return;
981 	}
982 	id_byte2 = (*getc)(mdev);
983 	if (id_byte2 < 0) {
984 		printf("MouseInit: Timeout on 2nd byte of self-test report\n");
985 		return;
986 	}
987 	id_byte3 = (*getc)(mdev);
988 	if (id_byte3 < 0) {
989 		printf("MouseInit: Timeout on 3rd byte of self-test report\n");
990 		return;
991 	}
992 	id_byte4 = (*getc)(mdev);
993 	if (id_byte4 < 0) {
994 		printf("MouseInit: Timeout on 4th byte of self-test report\n");
995 		return;
996 	}
997 	if ((id_byte2 & 0x0f) != 0x2)
998 		printf("MouseInit: We don't have a mouse!!!\n");
999 	/*
1000 	 * For some reason, the mouse doesn't see this command if it comes
1001 	 * too soon after a self test.
1002 	 */
1003 	DELAY(100);
1004 	(*putc)(mdev, MOUSE_INCREMENTAL);
1005 }
1006 
1007 /*
1008  * Get a character off of the keyboard.
1009  */
1010 int
1011 KBDGetc()
1012 {
1013 	register int c;
1014 
1015 	for (;;) {
1016 		c = (*cn_tab.cn_kbdgetc)(cn_tab.cn_dev);
1017 		if (c == 0)
1018 			return (-1);
1019 		if ((c = kbdMapChar(c & 0xff)) >= 0)
1020 			break;
1021 	}
1022 	return (c);
1023 }
1024 
1025 /*
1026  * Configure the keyboard/mouse based on machine type for turbochannel
1027  * display boards.
1028  */
1029 tb_kbdmouseconfig(fp)
1030 	struct pmax_fb *fp;
1031 {
1032 
1033 	switch (pmax_boardtype) {
1034 #if NDC > 0
1035 	case DS_3MAX:
1036 		fp->KBDPutc = dcPutc;
1037 		fp->kbddev = makedev(DCDEV, DCKBD_PORT);
1038 		break;
1039 #endif
1040 #if NSCC > 0
1041 	case DS_3MIN:
1042 	case DS_3MAXPLUS:
1043 		fp->KBDPutc = sccPutc;
1044 		fp->kbddev = makedev(SCCDEV, SCCKBD_PORT);
1045 		break;
1046 #endif
1047 #if NDTOP > 0
1048 	case DS_MAXINE:
1049 		fp->KBDPutc = dtopKBDPutc;
1050 		fp->kbddev = makedev(DTOPDEV, DTOPKBD_PORT);
1051 		break;
1052 #endif
1053 	default:
1054 		printf("Can't configure keyboard/mouse\n");
1055 		return (1);
1056 	};
1057 	return (0);
1058 }
1059 
1060 /*
1061  * Use vm_mmap() to map the frame buffer and shared data into the user's
1062  * address space.
1063  * Return errno if there was an error.
1064  */
1065 fbmmap(fp, dev, data, p)
1066 	struct pmax_fb *fp;
1067 	dev_t dev;
1068 	caddr_t data;
1069 	struct proc *p;
1070 {
1071 	int error;
1072 	vm_offset_t addr;
1073 	vm_size_t len;
1074 	struct vnode vn;
1075 	struct specinfo si;
1076 	struct fbuaccess *fbp;
1077 
1078 	len = pmax_round_page(((vm_offset_t)fp->fbu & PGOFSET) +
1079 		sizeof(struct fbuaccess)) + pmax_round_page(fp->fr_size);
1080 	addr = (vm_offset_t)0x20000000;		/* XXX */
1081 	vn.v_type = VCHR;			/* XXX */
1082 	vn.v_specinfo = &si;			/* XXX */
1083 	vn.v_rdev = dev;			/* XXX */
1084 	/*
1085 	 * Map the all the data the user needs access to into
1086 	 * user space.
1087 	 */
1088 	error = vm_mmap(&p->p_vmspace->vm_map, &addr, len,
1089 		VM_PROT_ALL, VM_PROT_ALL, MAP_SHARED, (caddr_t)&vn,
1090 		(vm_offset_t)0);
1091 	if (error)
1092 		return (error);
1093 	fbp = (struct fbuaccess *)(addr + ((vm_offset_t)fp->fbu & PGOFSET));
1094 	*(PM_Info **)data = &fbp->scrInfo;
1095 	fp->fbu->scrInfo.qe.events = fbp->events;
1096 	fp->fbu->scrInfo.qe.tcs = fbp->tcs;
1097 	fp->fbu->scrInfo.planemask = (char *)0;
1098 	/*
1099 	 * Map the frame buffer into the user's address space.
1100 	 */
1101 	fp->fbu->scrInfo.bitmap = (char *)pmax_round_page(fbp + 1);
1102 	return (0);
1103 }
1104