xref: /original-bsd/sys/pmax/dev/xcfb.c (revision 00a25f5a)
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  *	@(#)xcfb.c	8.2 (Berkeley) 06/02/95
11  */
12 
13 /*
14  * Mach Operating System
15  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
16  * All Rights Reserved.
17  *
18  * Permission to use, copy, modify and distribute this software and its
19  * documentation is hereby granted, provided that both the copyright
20  * notice and this permission notice appear in all copies of the
21  * software, derivative works or modified versions, and any portions
22  * thereof, and that both notices appear in supporting documentation.
23  *
24  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
25  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
26  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
27  *
28  * Carnegie Mellon requests users of this software to return to
29  *
30  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
31  *  School of Computer Science
32  *  Carnegie Mellon University
33  *  Pittsburgh PA 15213-3890
34  *
35  * any improvements or extensions that they make and grant Carnegie the
36  * rights to redistribute these changes.
37  */
38 /*
39  *  devGraphics.c --
40  *
41  *     	This file contains machine-dependent routines for the graphics device.
42  *
43  *	Copyright (C) 1989 Digital Equipment Corporation.
44  *	Permission to use, copy, modify, and distribute this software and
45  *	its documentation for any purpose and without fee is hereby granted,
46  *	provided that the above copyright notice appears in all copies.
47  *	Digital Equipment Corporation makes no representations about the
48  *	suitability of this software for any purpose.  It is provided "as is"
49  *	without express or implied warranty.
50  *
51  * from: $Header: /sprite/src/kernel/dev/ds3100.md/RCS/devGraphics.c,
52  *	v 9.2 90/02/13 22:16:24 shirriff Exp $ SPRITE (DECWRL)";
53  */
54 
55 #include <xcfb.h>
56 #include <dtop.h>
57 #if NXCFB > 0
58 #if NDTOP == 0
59 xcfb needs dtop device
60 #else
61 
62 #include <sys/param.h>
63 #include <sys/time.h>
64 #include <sys/kernel.h>
65 #include <sys/ioctl.h>
66 #include <sys/file.h>
67 #include <sys/errno.h>
68 #include <sys/proc.h>
69 #include <sys/mman.h>
70 
71 #include <vm/vm.h>
72 
73 #include <machine/machConst.h>
74 #include <machine/pmioctl.h>
75 
76 #include <pmax/pmax/maxine.h>
77 #include <pmax/pmax/cons.h>
78 #include <pmax/pmax/pmaxtype.h>
79 
80 #include <pmax/dev/device.h>
81 #include <pmax/dev/xcfbreg.h>
82 #include <pmax/dev/dtopreg.h>
83 #include <pmax/dev/fbreg.h>
84 
85 /*
86  * These need to be mapped into user space.
87  */
88 struct fbuaccess xcfbu;
89 struct pmax_fb xcfbfb;
90 
91 /*
92  * Forward references.
93  */
94 static void xcfbScreenInit();
95 static void xcfbLoadCursor();
96 static void xcfbRestoreCursorColor();
97 static void xcfbCursorColor();
98 void xcfbPosCursor();
99 static void xcfbInitColorMap();
100 static void xcfbLoadColorMap();
101 static u_int ims332_read_register();
102 static void ims332_write_register();
103 static void ims332_load_colormap_entry();
104 static void ims332_video_off();
105 static void ims332_video_on();
106 
107 void xcfbKbdEvent(), xcfbMouseEvent(), xcfbMouseButtons();
108 extern void dtopKBDPutc();
109 extern void (*dtopDivertXInput)();
110 extern void (*dtopMouseEvent)();
111 extern void (*dtopMouseButtons)();
112 extern int pmax_boardtype;
113 extern u_short defCursor[32];
114 extern struct consdev cn_tab;
115 
116 int	xcfbprobe();
117 struct	driver xcfbdriver = {
118 	"xcfb", xcfbprobe, 0, 0,
119 };
120 
121 /*
122  * Test to see if device is present.
123  * Return true if found and initialized ok.
124  */
125 /*ARGSUSED*/
126 xcfbprobe(cp)
127 	register struct pmax_ctlr *cp;
128 {
129 	register struct pmax_fb *fp = &xcfbfb;
130 
131 	if (pmax_boardtype != DS_MAXINE)
132 		return (0);
133 	if (!fp->initialized && !xcfbinit())
134 		return (0);
135 	printf("xcfb0 (color display)\n");
136 	return (1);
137 }
138 
139 /*ARGSUSED*/
140 xcfbopen(dev, flag)
141 	dev_t dev;
142 	int flag;
143 {
144 	register struct pmax_fb *fp = &xcfbfb;
145 	int s;
146 
147 	if (!fp->initialized)
148 		return (ENXIO);
149 	if (fp->GraphicsOpen)
150 		return (EBUSY);
151 
152 	fp->GraphicsOpen = 1;
153 	xcfbInitColorMap();
154 	/*
155 	 * Set up event queue for later
156 	 */
157 	fp->fbu->scrInfo.qe.eSize = PM_MAXEVQ;
158 	fp->fbu->scrInfo.qe.eHead = fp->fbu->scrInfo.qe.eTail = 0;
159 	fp->fbu->scrInfo.qe.tcSize = MOTION_BUFFER_SIZE;
160 	fp->fbu->scrInfo.qe.tcNext = 0;
161 	fp->fbu->scrInfo.qe.timestamp_ms = TO_MS(time);
162 	s = spltty();
163 	dtopDivertXInput = xcfbKbdEvent;
164 	dtopMouseEvent = xcfbMouseEvent;
165 	dtopMouseButtons = xcfbMouseButtons;
166 	splx(s);
167 	return (0);
168 }
169 
170 /*ARGSUSED*/
171 xcfbclose(dev, flag)
172 	dev_t dev;
173 	int flag;
174 {
175 	register struct pmax_fb *fp = &xcfbfb;
176 	int s;
177 
178 	if (!fp->GraphicsOpen)
179 		return (EBADF);
180 
181 	fp->GraphicsOpen = 0;
182 	xcfbInitColorMap();
183 	s = spltty();
184 	dtopDivertXInput = (void (*)())0;
185 	dtopMouseEvent = (void (*)())0;
186 	dtopMouseButtons = (void (*)())0;
187 	splx(s);
188 	xcfbScreenInit();
189 	bzero((caddr_t)fp->fr_addr, 1024 * 768);
190 	xcfbPosCursor(fp->col * 8, fp->row * 15);
191 	return (0);
192 }
193 
194 /*ARGSUSED*/
195 xcfbioctl(dev, cmd, data, flag, p)
196 	dev_t dev;
197 	u_long cmd;
198 	caddr_t data;
199 	struct proc *p;
200 {
201 	register struct pmax_fb *fp = &xcfbfb;
202 	int s;
203 
204 	switch (cmd) {
205 	case QIOCGINFO:
206 		return (fbmmap(fp, dev, data, p));
207 
208 	case QIOCPMSTATE:
209 		/*
210 		 * Set mouse state.
211 		 */
212 		fp->fbu->scrInfo.mouse = *(pmCursor *)data;
213 		xcfbPosCursor(fp->fbu->scrInfo.mouse.x, fp->fbu->scrInfo.mouse.y);
214 		break;
215 
216 	case QIOCINIT:
217 		/*
218 		 * Initialize the screen.
219 		 */
220 		xcfbScreenInit();
221 		break;
222 
223 	case QIOCKPCMD:
224 	    {
225 		pmKpCmd *kpCmdPtr;
226 		unsigned char *cp;
227 
228 		kpCmdPtr = (pmKpCmd *)data;
229 		if (kpCmdPtr->nbytes == 0)
230 			kpCmdPtr->cmd |= 0x80;
231 		if (!fp->GraphicsOpen)
232 			kpCmdPtr->cmd |= 1;
233 		(*fp->KBDPutc)(fp->kbddev, (int)kpCmdPtr->cmd);
234 		cp = &kpCmdPtr->par[0];
235 		for (; kpCmdPtr->nbytes > 0; cp++, kpCmdPtr->nbytes--) {
236 			if (kpCmdPtr->nbytes == 1)
237 				*cp |= 0x80;
238 			(*fp->KBDPutc)(fp->kbddev, (int)*cp);
239 		}
240 		break;
241 	    }
242 
243 	case QIOCADDR:
244 		*(PM_Info **)data = &fp->fbu->scrInfo;
245 		break;
246 
247 	case QIOWCURSOR:
248 		xcfbLoadCursor((unsigned short *)data);
249 		break;
250 
251 	case QIOWCURSORCOLOR:
252 		xcfbCursorColor((unsigned int *)data);
253 		break;
254 
255 	case QIOSETCMAP:
256 		xcfbLoadColorMap((ColorMap *)data);
257 		break;
258 
259 	case QIOKERNLOOP:
260 		s = spltty();
261 		dtopDivertXInput = xcfbKbdEvent;
262 		dtopMouseEvent = xcfbMouseEvent;
263 		dtopMouseButtons = xcfbMouseButtons;
264 		splx(s);
265 		break;
266 
267 	case QIOKERNUNLOOP:
268 		s = spltty();
269 		dtopDivertXInput = (void (*)())0;
270 		dtopMouseEvent = (void (*)())0;
271 		dtopMouseButtons = (void (*)())0;
272 		splx(s);
273 		break;
274 
275 	case QIOVIDEOON:
276 		xcfbRestoreCursorColor();
277 		ims332_video_on();
278 		break;
279 
280 	case QIOVIDEOOFF:
281 		ims332_video_off();
282 		break;
283 
284 	default:
285 		printf("xcfb0: Unknown ioctl command %x\n", cmd);
286 		return (EINVAL);
287 	}
288 	return (0);
289 }
290 
291 /*
292  * Return the physical page number that corresponds to byte offset 'off'.
293  */
294 /*ARGSUSED*/
295 xcfbmap(dev, off, prot)
296 	dev_t dev;
297 {
298 	int len;
299 
300 	len = pmax_round_page(((vm_offset_t)&xcfbu & PGOFSET) + sizeof(xcfbu));
301 	if (off < len)
302 		return pmax_btop(MACH_CACHED_TO_PHYS(&xcfbu) + off);
303 	off -= len;
304 	if (off >= xcfbfb.fr_size)
305 		return (-1);
306 	return pmax_btop(MACH_UNCACHED_TO_PHYS(xcfbfb.fr_addr) + off);
307 }
308 
309 xcfbselect(dev, flag, p)
310 	dev_t dev;
311 	int flag;
312 	struct proc *p;
313 {
314 	struct pmax_fb *fp = &xcfbfb;
315 
316 	switch (flag) {
317 	case FREAD:
318 		if (fp->fbu->scrInfo.qe.eHead != fp->fbu->scrInfo.qe.eTail)
319 			return (1);
320 		selrecord(p, &fp->selp);
321 		break;
322 	}
323 
324 	return (0);
325 }
326 
327 static u_char	cursor_RGB[6];	/* cursor color 2 & 3 */
328 
329 /*
330  *	Routines for the Inmos IMS-G332 Colour video controller
331  * 	Author: Alessandro Forin, Carnegie Mellon University
332  */
333 static u_int
334 ims332_read_register(regno)
335 {
336 	register u_char *regs = (u_char *)IMS332_ADDRESS;
337 	unsigned char *rptr;
338 	register u_int val, v1;
339 
340 	/* spec sez: */
341 	rptr = regs + 0x80000 + (regno << 4);
342 	val = *((volatile u_short *) rptr );
343 	v1  = *((volatile u_short *) regs );
344 
345 	return (val & 0xffff) | ((v1 & 0xff00) << 8);
346 }
347 
348 static void
349 ims332_write_register(regno, val)
350 	register unsigned int val;
351 {
352 	register u_char *regs = (u_char *)IMS332_ADDRESS;
353 	u_char *wptr;
354 
355 	/* spec sez: */
356 	wptr = regs + 0xa0000 + (regno << 4);
357 	*((volatile u_int *)(regs)) = (val >> 8) & 0xff00;
358 	*((volatile u_short *)(wptr)) = val;
359 }
360 
361 #define	assert_ims332_reset_bit(r)	*r &= ~0x40
362 #define	deassert_ims332_reset_bit(r)	*r |=  0x40
363 
364 /*
365  * Color map
366  */
367 static void
368 xcfbLoadColorMap(ptr)
369 	ColorMap *ptr;
370 {
371 	register int i;
372 
373 	if (ptr->index > 256)
374 		return;
375 	ims332_load_colormap_entry(ptr->index, ptr);
376 }
377 
378 static void
379 ims332_load_colormap_entry(entry, map)
380 	ColorMap *map;
381 {
382 	/* ?? stop VTG */
383 	ims332_write_register(IMS332_REG_LUT_BASE + (entry & 0xff),
384 			      (map->Entry.blue << 16) |
385 			      (map->Entry.green << 8) |
386 			      (map->Entry.red));
387 }
388 
389 static void
390 xcfbInitColorMap()
391 {
392 	register int i;
393 	ColorMap m;
394 
395 	m.Entry.red = m.Entry.green = m.Entry.blue = 0;
396 	ims332_load_colormap_entry(0, &m);
397 
398 	m.Entry.red = m.Entry.green = m.Entry.blue = 0xff;
399 	for (i = 1; i < 256; i++)
400 		ims332_load_colormap_entry(i, &m);
401 
402 	for (i = 0; i < 3; i++) {
403 		cursor_RGB[i] = 0x00;
404 		cursor_RGB[i + 3] = 0xff;
405 	}
406 	xcfbRestoreCursorColor();
407 }
408 
409 /*
410  * Video on/off
411  *
412  * It is unfortunate that X11 goes backward with white@0
413  * and black@1.  So we must stash away the zero-th entry
414  * and fix it while screen is off.  Also must remember
415  * it, sigh.
416  */
417 static struct {
418 	u_int	save;
419 	int	off;
420 } xcfb_vstate;
421 
422 static void
423 ims332_video_off()
424 {
425 	register u_int csr;
426 
427 	if (xcfb_vstate.off)
428 		return;
429 
430 	xcfb_vstate.save = ims332_read_register(IMS332_REG_LUT_BASE);
431 
432 	ims332_write_register(IMS332_REG_LUT_BASE, 0);
433 
434 	ims332_write_register(IMS332_REG_COLOR_MASK, 0);
435 
436 	/* cursor now */
437 	csr = ims332_read_register(IMS332_REG_CSR_A);
438 	csr |= IMS332_CSR_A_DISABLE_CURSOR;
439 	ims332_write_register(IMS332_REG_CSR_A, csr);
440 
441 	xcfb_vstate.off = 1;
442 }
443 
444 static void
445 ims332_video_on()
446 {
447 	register u_int csr;
448 
449 	if (!xcfb_vstate.off)
450 		return;
451 
452 	ims332_write_register(IMS332_REG_LUT_BASE, xcfb_vstate.save);
453 
454 	ims332_write_register(IMS332_REG_COLOR_MASK, 0xffffffff);
455 
456 	/* cursor now */
457 	csr = ims332_read_register(IMS332_REG_CSR_A);
458 	csr &= ~IMS332_CSR_A_DISABLE_CURSOR;
459 	ims332_write_register(IMS332_REG_CSR_A, csr);
460 
461 	xcfb_vstate.off = 0;
462 }
463 
464 /*
465  * Cursor
466  */
467 void
468 xcfbPosCursor(x, y)
469 	register int x, y;
470 {
471 	register struct pmax_fb *fp = &xcfbfb;
472 
473 	if (y < fp->fbu->scrInfo.min_cur_y || y > fp->fbu->scrInfo.max_cur_y)
474 		y = fp->fbu->scrInfo.max_cur_y;
475 	if (x < fp->fbu->scrInfo.min_cur_x || x > fp->fbu->scrInfo.max_cur_x)
476 		x = fp->fbu->scrInfo.max_cur_x;
477 	fp->fbu->scrInfo.cursor.x = x;		/* keep track of real cursor */
478 	fp->fbu->scrInfo.cursor.y = y;		/* position, indep. of mouse */
479 	ims332_write_register(IMS332_REG_CURSOR_LOC,
480 		((x & 0xfff) << 12) | (y & 0xfff));
481 }
482 
483 /*
484  * xcfbRestoreCursorColor
485  */
486 static void
487 xcfbRestoreCursorColor()
488 {
489 
490 	/* Bg is color[0], Fg is color[1] */
491 	ims332_write_register(IMS332_REG_CURSOR_LUT_0,
492 			      (cursor_RGB[2] << 16) |
493 			      (cursor_RGB[1] << 8) |
494 			      (cursor_RGB[0]));
495 	ims332_write_register(IMS332_REG_CURSOR_LUT_1, 0x7f0000);
496 	ims332_write_register(IMS332_REG_CURSOR_LUT_2,
497 			      (cursor_RGB[5] << 16) |
498 			      (cursor_RGB[4] << 8) |
499 			      (cursor_RGB[3]));
500 }
501 
502 /*
503  * ----------------------------------------------------------------------------
504  *
505  * xcfbCursorColor --
506  *
507  *	Set the color of the cursor.
508  *
509  * Results:
510  *	None.
511  *
512  * Side effects:
513  *	None.
514  *
515  * ----------------------------------------------------------------------------
516  */
517 static void
518 xcfbCursorColor(color)
519 	unsigned int color[];
520 {
521 	register int i, j;
522 
523 	for (i = 0; i < 6; i++)
524 		cursor_RGB[i] = (u_char)(color[i] >> 8);
525 
526 	xcfbRestoreCursorColor();
527 }
528 
529 static void
530 xcfbLoadCursor(cursor)
531 	u_short *cursor;
532 {
533 	register int i, j, k, pos;
534 	register u_short ap, bp, out;
535 
536 	/*
537 	 * Fill in the cursor sprite using the A and B planes, as provided
538 	 * for the pmax.
539 	 * XXX This will have to change when the X server knows that this
540 	 * is not a pmax display.
541 	 */
542 	pos = 0;
543 	for (k = 0; k < 16; k++) {
544 		ap = *cursor;
545 		bp = *(cursor + 16);
546 		j = 0;
547 		while (j < 2) {
548 			out = 0;
549 			for (i = 0; i < 8; i++) {
550 				out = ((out >> 2) & 0x3fff) |
551 					((ap & 0x1) << 15) |
552 					((bp & 0x1) << 14);
553 				ap >>= 1;
554 				bp >>= 1;
555 			}
556 			ims332_write_register(IMS332_REG_CURSOR_RAM + pos, out);
557 			pos++;
558 			j++;
559 		}
560 		while (j < 8) {
561 			ims332_write_register(IMS332_REG_CURSOR_RAM + pos, 0);
562 			pos++;
563 			j++;
564 		}
565 		cursor++;
566 	}
567 	while (pos < 512) {
568 		ims332_write_register(IMS332_REG_CURSOR_RAM + pos, 0);
569 		pos++;
570 	}
571 }
572 
573 /*
574  * Initialization
575  */
576 int
577 xcfbinit()
578 {
579 	register u_int *reset = (u_int *)IMS332_RESET_ADDRESS;
580 	register struct pmax_fb *fp = &xcfbfb;
581 
582 	fp->isMono = 0;
583 
584 	/*
585 	 * Or Cached? A comment in the Mach driver suggests that the X server
586 	 * runs faster in cached address space, but the X server is going
587 	 * to blow away the data cache whenever it updates the screen, so..
588 	 */
589 	fp->fr_addr = (char *)
590 		MACH_PHYS_TO_UNCACHED(XINE_PHYS_CFB_START + VRAM_OFFSET);
591 	fp->fr_size = 0x100000;
592 	/*
593 	 * Must be in Uncached space since the fbuaccess structure is
594 	 * mapped into the user's address space uncached.
595 	 */
596 	fp->fbu = (struct fbuaccess *)
597 		MACH_PHYS_TO_UNCACHED(MACH_CACHED_TO_PHYS(&xcfbu));
598 	fp->posCursor = xcfbPosCursor;
599 	fp->KBDPutc = dtopKBDPutc;
600 	fp->kbddev = makedev(DTOPDEV, DTOPKBD_PORT);
601 
602 	/*
603 	 * Initialize the screen.
604 	 */
605 #ifdef notdef
606 	assert_ims332_reset_bit(reset);
607 	DELAY(1);	/* specs sez 50ns.. */
608 	deassert_ims332_reset_bit(reset);
609 
610 	/* CLOCKIN appears to receive a 6.25 Mhz clock --> PLL 12 for 75Mhz monitor */
611 	ims332_write_register(IMS332_REG_BOOT, 12 | IMS332_BOOT_CLOCK_PLL);
612 
613 	/* initialize VTG */
614 	ims332_write_register(IMS332_REG_CSR_A,
615 				IMS332_BPP_8 | IMS332_CSR_A_DISABLE_CURSOR);
616 	DELAY(50);	/* spec does not say */
617 
618 	/* datapath registers (values taken from prom's settings) */
619 
620 	ims332_write_register(IMS332_REG_HALF_SYNCH, 0x10);
621 	ims332_write_register(IMS332_REG_BACK_PORCH, 0x21);
622 	ims332_write_register(IMS332_REG_DISPLAY, 0x100);
623 	ims332_write_register(IMS332_REG_SHORT_DIS, 0x5d);
624 	ims332_write_register(IMS332_REG_BROAD_PULSE, 0x9f);
625 	ims332_write_register(IMS332_REG_V_SYNC, 0xc);
626 	ims332_write_register(IMS332_REG_V_PRE_EQUALIZE, 2);
627 	ims332_write_register(IMS332_REG_V_POST_EQUALIZE, 2);
628 	ims332_write_register(IMS332_REG_V_BLANK, 0x2a);
629 	ims332_write_register(IMS332_REG_V_DISPLAY, 0x600);
630 	ims332_write_register(IMS332_REG_LINE_TIME, 0x146);
631 	ims332_write_register(IMS332_REG_LINE_START, 0x10);
632 	ims332_write_register(IMS332_REG_MEM_INIT, 0xa);
633 	ims332_write_register(IMS332_REG_XFER_DELAY, 0xa);
634 
635 	ims332_write_register(IMS332_REG_COLOR_MASK, 0xffffff);
636 #endif
637 
638 	/*
639 	 * Initialize screen info.
640 	 */
641 	fp->fbu->scrInfo.max_row = 50;
642 	fp->fbu->scrInfo.max_col = 80;
643 	fp->fbu->scrInfo.max_x = 1024;
644 	fp->fbu->scrInfo.max_y = 768;
645 	fp->fbu->scrInfo.max_cur_x = 1008;
646 	fp->fbu->scrInfo.max_cur_y = 752;
647 	fp->fbu->scrInfo.version = 11;
648 	fp->fbu->scrInfo.mthreshold = 4;
649 	fp->fbu->scrInfo.mscale = 2;
650 	fp->fbu->scrInfo.min_cur_x = -15;
651 	fp->fbu->scrInfo.min_cur_y = -15;
652 	fp->fbu->scrInfo.qe.timestamp_ms = TO_MS(time);
653 	fp->fbu->scrInfo.qe.eSize = PM_MAXEVQ;
654 	fp->fbu->scrInfo.qe.eHead = fp->fbu->scrInfo.qe.eTail = 0;
655 	fp->fbu->scrInfo.qe.tcSize = MOTION_BUFFER_SIZE;
656 	fp->fbu->scrInfo.qe.tcNext = 0;
657 
658 	xcfbInitColorMap();
659 
660 	ims332_write_register(IMS332_REG_CSR_A,
661 		IMS332_BPP_8 | IMS332_CSR_A_DMA_DISABLE | IMS332_CSR_A_VTG_ENABLE);
662 
663 	xcfbScreenInit();
664 	fbScroll(fp);
665 
666 	fp->initialized = 1;
667 	if (cn_tab.cn_fb == (struct pmax_fb *)0)
668 		cn_tab.cn_fb = fp;
669 	return (1);
670 }
671 
672 /*
673  * ----------------------------------------------------------------------------
674  *
675  * xcfbScreenInit --
676  *
677  *	Initialize the screen.
678  *
679  * Results:
680  *	None.
681  *
682  * Side effects:
683  *	The screen is initialized.
684  *
685  * ----------------------------------------------------------------------------
686  */
687 static void
688 xcfbScreenInit()
689 {
690 	register struct pmax_fb *fp = &xcfbfb;
691 
692 	/*
693 	 * Home the cursor.
694 	 * We want an LSI terminal emulation.  We want the graphics
695 	 * terminal to scroll from the bottom. So start at the bottom.
696 	 */
697 	fp->row = 49;
698 	fp->col = 0;
699 
700 	/*
701 	 * Load the cursor with the default values
702 	 *
703 	 */
704 	xcfbLoadCursor(defCursor);
705 }
706 
707 /*
708  * xcfb keyboard and mouse input. Just punt to the generic ones in fb.c
709  */
710 void
711 xcfbKbdEvent(ch)
712 	int ch;
713 {
714 	fbKbdEvent(ch, &xcfbfb);
715 }
716 
717 void
718 xcfbMouseEvent(newRepPtr)
719 	MouseReport *newRepPtr;
720 {
721 	fbMouseEvent(newRepPtr, &xcfbfb);
722 }
723 
724 void
725 xcfbMouseButtons(newRepPtr)
726 	MouseReport *newRepPtr;
727 {
728 	fbMouseButtons(newRepPtr, &xcfbfb);
729 }
730 #endif /* NDTOP */
731 #endif /* NXCFB */
732