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