1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1990, 1991 UNIX System Laboratories, Inc.	*/
28 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T	*/
29 /*	  All Rights Reserved  	*/
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 #include <sys/errno.h>
34 #include <sys/types.h>
35 #include <sys/conf.h>
36 #include <sys/kmem.h>
37 #include <sys/visual_io.h>
38 #include <sys/font.h>
39 #include <sys/fbio.h>
40 #include <sys/ddi.h>
41 #include <sys/stat.h>
42 #include <sys/sunddi.h>
43 #include <sys/file.h>
44 #include <sys/open.h>
45 #include <sys/modctl.h>
46 #include <sys/vgareg.h>
47 #include <sys/vgasubr.h>
48 #include <sys/pci.h>
49 #include <sys/kd.h>
50 #include <sys/ddi_impldefs.h>
51 
52 
53 
54 
55 #include "gfx_private.h"
56 
57 #define	MYNAME	"gfxp_vgatext"
58 
59 #define	TEXT_ROWS		25
60 #define	TEXT_COLS		80
61 
62 #define	VGA_BRIGHT_WHITE	0x0f
63 #define	VGA_BLACK		0x00
64 
65 #define	VGA_REG_ADDR		0x3c0
66 #define	VGA_REG_SIZE		0x20
67 
68 #define	VGA_MEM_ADDR		0xa0000
69 #define	VGA_MEM_SIZE		0x20000
70 
71 #define	VGA_MMAP_FB_BASE	VGA_MEM_ADDR
72 
73 struct vgatext_softc {
74 	struct vgaregmap 	regs;
75 	struct vgaregmap 	fb;
76 	off_t			fb_size;
77 	int			fb_regno;
78 	dev_info_t		*devi;
79 	int			mode;	/* KD_TEXT or KD_GRAPHICS */
80 	caddr_t			text_base;	/* hardware text base */
81 	char			shadow[TEXT_ROWS*TEXT_COLS*2];
82 	caddr_t			current_base;	/* hardware or shadow */
83 	struct {
84 		boolean_t visible;
85 		int row;
86 		int col;
87 	}			cursor;
88 	struct vis_polledio	polledio;
89 	struct {
90 		unsigned char red;
91 		unsigned char green;
92 		unsigned char blue;
93 	}			colormap[VGA8_CMAP_ENTRIES];
94 	unsigned char attrib_palette[VGA_ATR_NUM_PLT];
95 	unsigned int flags;
96 };
97 
98 typedef enum pc_colors {
99 	pc_black	= 0,
100 	pc_blue		= 1,
101 	pc_green	= 2,
102 	pc_cyan		= 3,
103 	pc_red		= 4,
104 	pc_magenta	= 5,
105 	pc_brown	= 6,
106 	pc_white	= 7,
107 	pc_grey		= 8,
108 	pc_brt_blue	= 9,
109 	pc_brt_green	= 10,
110 	pc_brt_cyan	= 11,
111 	pc_brt_red	= 12,
112 	pc_brt_magenta	= 13,
113 	pc_yellow	= 14,
114 	pc_brt_white	= 15
115 } pc_colors_t;
116 
117 static const unsigned char solaris_color_to_pc_color[16] = {
118 	pc_brt_white,		/*  0 - brt_white	*/
119 	pc_black,		/*  1 - black		*/
120 	pc_blue,		/*  2 - blue		*/
121 	pc_green,		/*  3 - green		*/
122 	pc_cyan,		/*  4 - cyan		*/
123 	pc_red,			/*  5 - red		*/
124 	pc_magenta,		/*  6 - magenta		*/
125 	pc_brown,		/*  7 - brown		*/
126 	pc_white,		/*  8 - white		*/
127 	pc_grey,		/*  9 - gery		*/
128 	pc_brt_blue,		/* 10 - brt_blue	*/
129 	pc_brt_green,		/* 11 - brt_green	*/
130 	pc_brt_cyan,		/* 12 - brt_cyan	*/
131 	pc_brt_red,		/* 13 - brt_red		*/
132 	pc_brt_magenta,		/* 14 - brt_magenta	*/
133 	pc_yellow		/* 15 - yellow		*/
134 };
135 
136 static ddi_device_acc_attr_t dev_attr = {
137 	DDI_DEVICE_ATTR_V0,
138 	DDI_NEVERSWAP_ACC,
139 	DDI_STRICTORDER_ACC,
140 };
141 
142 /* default structure for FBIOGATTR ioctl */
143 static struct fbgattr vgatext_attr =  {
144 /*	real_type	owner */
145 	FBTYPE_SUNFAST_COLOR, 0,
146 /* fbtype: type		h  w  depth cms  size */
147 	{ FBTYPE_SUNFAST_COLOR, TEXT_ROWS, TEXT_COLS, 1,    256,  0 },
148 /* fbsattr: flags emu_type	dev_specific */
149 	{ 0, FBTYPE_SUN4COLOR, { 0 } },
150 /*	emu_types */
151 	{ -1 }
152 };
153 
154 #define	GFXP_FLAG_CONSOLE 0x00000001
155 #define	GFXP_IS_CONSOLE(softc) ((softc)->flags & GFXP_FLAG_CONSOLE)
156 
157 /*
158  * Global name used to write the softc pointer in, for the
159  * data wrapper vgatext_return_pointers()
160  */
161 
162 
163 int gfxp_vgatext_detach(dev_info_t *devi, ddi_detach_cmd_t cmd,
164 	gfxp_vgatext_softc_ptr_t ptr);
165 static int vgatext_devinit(struct vgatext_softc *, struct vis_devinit *data);
166 static void	vgatext_cons_copy(struct vgatext_softc *,
167 			struct vis_conscopy *);
168 static void	vgatext_cons_display(struct vgatext_softc *,
169 			struct vis_consdisplay *);
170 static void	vgatext_cons_cursor(struct vgatext_softc *,
171 			struct vis_conscursor *);
172 static void	vgatext_polled_copy(struct vis_polledio_arg *,
173 			struct vis_conscopy *);
174 static void	vgatext_polled_display(struct vis_polledio_arg *,
175 			struct vis_consdisplay *);
176 static void	vgatext_polled_cursor(struct vis_polledio_arg *,
177 			struct vis_conscursor *);
178 static void	vgatext_init(struct vgatext_softc *);
179 static void	vgatext_set_text(struct vgatext_softc *);
180 
181 static void	vgatext_save_text(struct vgatext_softc *softc);
182 static void	vgatext_restore_textmode(struct vgatext_softc *softc);
183 static int	vgatext_suspend(struct vgatext_softc *softc);
184 static void	vgatext_resume(struct vgatext_softc *softc);
185 
186 #if	defined(USE_BORDERS)
187 static void	vgatext_init_graphics(struct vgatext_softc *);
188 #endif
189 
190 static int vgatext_kdsetmode(struct vgatext_softc *softc, int mode);
191 static void vgatext_setfont(struct vgatext_softc *softc);
192 static void vgatext_get_cursor(struct vgatext_softc *softc,
193 		screen_pos_t *row, screen_pos_t *col);
194 static void vgatext_set_cursor(struct vgatext_softc *softc, int row, int col);
195 static void vgatext_hide_cursor(struct vgatext_softc *softc);
196 static void vgatext_save_colormap(struct vgatext_softc *softc);
197 static void vgatext_restore_colormap(struct vgatext_softc *softc);
198 static int vgatext_get_pci_reg_index(dev_info_t *const devi,
199 		unsigned long himask, unsigned long hival, unsigned long addr,
200 		off_t *offset);
201 static int vgatext_get_isa_reg_index(dev_info_t *const devi,
202 		unsigned long hival, unsigned long addr, off_t *offset);
203 
204 static char	vgatext_silent;
205 static char	happyface_boot;
206 
207 gfxp_vgatext_softc_ptr_t
208 gfxp_vgatext_softc_alloc(void)
209 {
210 	return (kmem_zalloc(sizeof (struct vgatext_softc), KM_SLEEP));
211 }
212 
213 void
214 gfxp_vgatext_softc_free(gfxp_vgatext_softc_ptr_t ptr)
215 {
216 	kmem_free(ptr, sizeof (struct vgatext_softc));
217 }
218 
219 #define	STREQ(a, b)	(strcmp((a), (b)) == 0)
220 
221 static void
222 gfxp_check_for_console(dev_info_t *devi, struct vgatext_softc *softc,
223 	int pci_pcie_bus)
224 {
225 	ddi_acc_handle_t pci_conf;
226 	dev_info_t *pdevi;
227 	uint16_t data16;
228 
229 	/*
230 	 * Based on Section 11.3, "PCI Display Subsystem Initialization",
231 	 * of the 1.1 PCI-to-PCI Bridge Architecture Specification
232 	 * determine if this is the boot console device.  First, see
233 	 * if the SBIOS has turned on PCI I/O for this device.  Then if
234 	 * this is PCI/PCI-E, verify the parent bridge has VGAEnable set.
235 	 */
236 
237 	if (pci_config_setup(devi, &pci_conf) != DDI_SUCCESS) {
238 		cmn_err(CE_WARN,
239 		    MYNAME
240 		    ": can't get PCI conf handle");
241 		return;
242 	}
243 
244 	data16 = pci_config_get16(pci_conf, PCI_CONF_COMM);
245 	if (data16 & PCI_COMM_IO)
246 		softc->flags |= GFXP_FLAG_CONSOLE;
247 
248 	pci_config_teardown(&pci_conf);
249 
250 	/* If IO not enabled or ISA/EISA, just return */
251 	if (!(softc->flags & GFXP_FLAG_CONSOLE) || !pci_pcie_bus)
252 		return;
253 
254 	/*
255 	 * Check for VGA Enable in the Bridge Control register for all
256 	 * PCI/PCIEX parents.  If not set all the way up the chain,
257 	 * this cannot be the boot console.
258 	 */
259 
260 	pdevi = ddi_get_parent(devi);
261 	while (pdevi) {
262 		int	error;
263 		ddi_acc_handle_t ppci_conf;
264 		char	*parent_type = NULL;
265 
266 		error = ddi_prop_lookup_string(DDI_DEV_T_ANY, pdevi,
267 		    DDI_PROP_DONTPASS, "device_type", &parent_type);
268 		if (error != DDI_SUCCESS) {
269 			return;
270 		}
271 
272 		/* Verify still on the PCI/PCIEX parent tree */
273 		if (!STREQ(parent_type, "pci") &&
274 		    !STREQ(parent_type, "pciex")) {
275 			ddi_prop_free(parent_type);
276 			return;
277 		}
278 
279 		ddi_prop_free(parent_type);
280 		parent_type = NULL;
281 
282 		if (pci_config_setup(pdevi, &ppci_conf) != DDI_SUCCESS) {
283 			/* No registers on root node, done with check */
284 			return;
285 		}
286 
287 		data16 = pci_config_get16(ppci_conf, PCI_BCNF_BCNTRL);
288 		pci_config_teardown(&ppci_conf);
289 
290 		if (!(data16 & PCI_BCNF_BCNTRL_VGA_ENABLE)) {
291 			softc->flags &= ~GFXP_FLAG_CONSOLE;
292 			return;
293 		}
294 
295 		pdevi = ddi_get_parent(pdevi);
296 	}
297 }
298 
299 int
300 gfxp_vgatext_attach(dev_info_t *devi, ddi_attach_cmd_t cmd,
301 	gfxp_vgatext_softc_ptr_t ptr)
302 {
303 	struct vgatext_softc *softc = (struct vgatext_softc *)ptr;
304 	int	unit = ddi_get_instance(devi);
305 	int	error;
306 	char	*parent_type = NULL;
307 	int	reg_rnumber;
308 	off_t	reg_offset;
309 	off_t	mem_offset;
310 	char	*cons;
311 	int pci_pcie_bus = 0;
312 
313 
314 
315 	switch (cmd) {
316 	case DDI_ATTACH:
317 		break;
318 
319 	case DDI_RESUME:
320 		vgatext_resume(softc);
321 		return (DDI_SUCCESS);
322 
323 	default:
324 		return (DDI_FAILURE);
325 	}
326 
327 	/* DDI_ATTACH */
328 
329 	softc->devi = devi; /* Copy and init DEVI */
330 
331 	softc->polledio.arg = (struct vis_polledio_arg *)softc;
332 	softc->polledio.display = vgatext_polled_display;
333 	softc->polledio.copy = vgatext_polled_copy;
334 	softc->polledio.cursor = vgatext_polled_cursor;
335 
336 	error = ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_get_parent(devi),
337 	    DDI_PROP_DONTPASS, "device_type", &parent_type);
338 	if (error != DDI_SUCCESS) {
339 		cmn_err(CE_WARN, MYNAME ": can't determine parent type.");
340 		goto fail;
341 	}
342 
343 	/* Not enable AGP and DRM by default */
344 	if (STREQ(parent_type, "isa") || STREQ(parent_type, "eisa")) {
345 		reg_rnumber = vgatext_get_isa_reg_index(devi, 1, VGA_REG_ADDR,
346 		    &reg_offset);
347 		if (reg_rnumber < 0) {
348 			cmn_err(CE_WARN,
349 			    MYNAME
350 			    ": can't find reg entry for registers");
351 			error = DDI_FAILURE;
352 			goto fail;
353 		}
354 		softc->fb_regno = vgatext_get_isa_reg_index(devi, 0,
355 		    VGA_MEM_ADDR, &mem_offset);
356 		if (softc->fb_regno < 0) {
357 			cmn_err(CE_WARN,
358 			    MYNAME
359 			    ": can't find reg entry for memory");
360 			error = DDI_FAILURE;
361 			goto fail;
362 		}
363 	} else if (STREQ(parent_type, "pci") || STREQ(parent_type, "pciex")) {
364 		pci_pcie_bus = 1;
365 		reg_rnumber = vgatext_get_pci_reg_index(devi,
366 		    PCI_REG_ADDR_M|PCI_REG_REL_M,
367 		    PCI_ADDR_IO|PCI_RELOCAT_B, VGA_REG_ADDR,
368 		    &reg_offset);
369 		if (reg_rnumber < 0) {
370 			cmn_err(CE_WARN,
371 			    MYNAME
372 			    ": can't find reg entry for registers");
373 			error = DDI_FAILURE;
374 			goto fail;
375 		}
376 		softc->fb_regno = vgatext_get_pci_reg_index(devi,
377 		    PCI_REG_ADDR_M|PCI_REG_REL_M,
378 		    PCI_ADDR_MEM32|PCI_RELOCAT_B, VGA_MEM_ADDR,
379 		    &mem_offset);
380 		if (softc->fb_regno < 0) {
381 			cmn_err(CE_WARN,
382 			    MYNAME
383 			    ": can't find reg entry for memory");
384 			error = DDI_FAILURE;
385 			goto fail;
386 		}
387 	} else {
388 		cmn_err(CE_WARN, MYNAME ": unknown parent type \"%s\".",
389 		    parent_type);
390 		error = DDI_FAILURE;
391 		goto fail;
392 	}
393 	ddi_prop_free(parent_type);
394 	parent_type = NULL;
395 
396 	error = ddi_regs_map_setup(devi, reg_rnumber,
397 	    (caddr_t *)&softc->regs.addr, reg_offset, VGA_REG_SIZE,
398 	    &dev_attr, &softc->regs.handle);
399 	if (error != DDI_SUCCESS)
400 		goto fail;
401 	softc->regs.mapped = B_TRUE;
402 
403 	softc->fb_size = VGA_MEM_SIZE;
404 
405 	error = ddi_regs_map_setup(devi, softc->fb_regno,
406 	    (caddr_t *)&softc->fb.addr,
407 	    mem_offset, softc->fb_size,
408 	    &dev_attr, &softc->fb.handle);
409 	if (error != DDI_SUCCESS)
410 		goto fail;
411 	softc->fb.mapped = B_TRUE;
412 
413 	if (ddi_get8(softc->regs.handle,
414 	    softc->regs.addr + VGA_MISC_R) & VGA_MISC_IOA_SEL)
415 		softc->text_base = (caddr_t)softc->fb.addr + VGA_COLOR_BASE;
416 	else
417 		softc->text_base = (caddr_t)softc->fb.addr + VGA_MONO_BASE;
418 	softc->current_base = softc->text_base;
419 
420 	error = ddi_prop_create(makedevice(DDI_MAJOR_T_UNKNOWN, unit),
421 	    devi, DDI_PROP_CANSLEEP, DDI_KERNEL_IOCTL, NULL, 0);
422 	if (error != DDI_SUCCESS)
423 		goto fail;
424 
425 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
426 	    DDI_PROP_DONTPASS, "console", &cons) == DDI_SUCCESS) {
427 		if (strcmp(cons, "graphics") == 0) {
428 			happyface_boot = 1;
429 			vgatext_silent = 1;
430 		}
431 		ddi_prop_free(cons);
432 	}
433 
434 	gfxp_check_for_console(devi, softc, pci_pcie_bus);
435 
436 	/* only do this if not in graphics mode */
437 	if ((vgatext_silent == 0) && (GFXP_IS_CONSOLE(softc))) {
438 		vgatext_init(softc);
439 		vgatext_save_colormap(softc);
440 	}
441 
442 	return (DDI_SUCCESS);
443 
444 fail:
445 	if (parent_type != NULL)
446 		ddi_prop_free(parent_type);
447 	(void) gfxp_vgatext_detach(devi, DDI_DETACH, (void *)softc);
448 	return (error);
449 }
450 
451 /*ARGSUSED*/
452 int
453 gfxp_vgatext_detach(dev_info_t *devi, ddi_detach_cmd_t cmd,
454 	gfxp_vgatext_softc_ptr_t ptr)
455 {
456 	struct vgatext_softc *softc = (struct vgatext_softc *)ptr;
457 
458 
459 
460 
461 
462 	switch (cmd) {
463 
464 	case DDI_SUSPEND:
465 		return (vgatext_suspend(softc));
466 		/* break; */
467 	case DDI_DETACH:
468 		if (softc->fb.mapped)
469 			ddi_regs_map_free(&softc->fb.handle);
470 		if (softc->regs.mapped)
471 			ddi_regs_map_free(&softc->regs.handle);
472 		return (DDI_SUCCESS);
473 
474 	default:
475 		cmn_err(CE_WARN, "gfxp_vgatext_detach: unknown cmd 0x%x\n",
476 		    cmd);
477 		return (DDI_FAILURE);
478 	}
479 }
480 
481 /*ARGSUSED*/
482 int
483 gfxp_vgatext_open(dev_t *devp, int flag, int otyp, cred_t *cred,
484 	gfxp_vgatext_softc_ptr_t ptr)
485 {
486 	struct vgatext_softc *softc = (struct vgatext_softc *)ptr;
487 
488 	if (softc == NULL || otyp == OTYP_BLK)
489 		return (ENXIO);
490 
491 	return (0);
492 }
493 
494 /*ARGSUSED*/
495 int
496 gfxp_vgatext_close(dev_t devp, int flag, int otyp, cred_t *cred,
497 	gfxp_vgatext_softc_ptr_t ptr)
498 {
499 	return (0);
500 }
501 
502 /*ARGSUSED*/
503 int
504 gfxp_vgatext_ioctl(
505     dev_t dev,
506     int cmd,
507     intptr_t data,
508     int mode,
509     cred_t *cred,
510     int *rval,
511     gfxp_vgatext_softc_ptr_t ptr)
512 {
513 	struct vgatext_softc *softc = (struct vgatext_softc *)ptr;
514 	static char kernel_only[] =
515 	    "gfxp_vgatext_ioctl: %s is a kernel only ioctl";
516 	int err;
517 	int kd_mode;
518 
519 	switch (cmd) {
520 	case KDSETMODE:
521 		return (vgatext_kdsetmode(softc, (int)data));
522 
523 	case KDGETMODE:
524 		kd_mode = softc->mode;
525 		if (ddi_copyout(&kd_mode, (void *)data, sizeof (int), mode))
526 			return (EFAULT);
527 		break;
528 
529 	case VIS_DEVINIT:
530 
531 		if (!(mode & FKIOCTL)) {
532 			cmn_err(CE_CONT, kernel_only, "VIS_DEVINIT");
533 			return (ENXIO);
534 		}
535 
536 		err = vgatext_devinit(softc, (struct vis_devinit *)data);
537 		if (err != 0) {
538 			cmn_err(CE_WARN,
539 			    "gfxp_vgatext_ioctl:  could not"
540 			    " initialize console");
541 			return (err);
542 		}
543 		break;
544 
545 	case VIS_CONSCOPY:	/* move */
546 	{
547 		struct vis_conscopy pma;
548 
549 		if (ddi_copyin((void *)data, &pma,
550 		    sizeof (struct vis_conscopy), mode))
551 			return (EFAULT);
552 
553 		vgatext_cons_copy(softc, &pma);
554 		break;
555 	}
556 
557 	case VIS_CONSDISPLAY:	/* display */
558 	{
559 		struct vis_consdisplay display_request;
560 
561 		if (ddi_copyin((void *)data, &display_request,
562 		    sizeof (display_request), mode))
563 			return (EFAULT);
564 
565 		vgatext_cons_display(softc, &display_request);
566 		break;
567 	}
568 
569 	case VIS_CONSCURSOR:
570 	{
571 		struct vis_conscursor cursor_request;
572 
573 		if (ddi_copyin((void *)data, &cursor_request,
574 		    sizeof (cursor_request), mode))
575 			return (EFAULT);
576 
577 		vgatext_cons_cursor(softc, &cursor_request);
578 
579 		if (cursor_request.action == VIS_GET_CURSOR &&
580 		    ddi_copyout(&cursor_request, (void *)data,
581 		    sizeof (cursor_request), mode))
582 			return (EFAULT);
583 		break;
584 	}
585 
586 	case VIS_GETCMAP:
587 	case VIS_PUTCMAP:
588 	case FBIOPUTCMAP:
589 	case FBIOGETCMAP:
590 		/*
591 		 * At the moment, text mode is not considered to have
592 		 * a color map.
593 		 */
594 		return (EINVAL);
595 
596 	case FBIOGATTR:
597 		if (copyout(&vgatext_attr, (void *)data,
598 		    sizeof (struct fbgattr)))
599 			return (EFAULT);
600 		break;
601 
602 	case FBIOGTYPE:
603 		if (copyout(&vgatext_attr.fbtype, (void *)data,
604 		    sizeof (struct fbtype)))
605 			return (EFAULT);
606 		break;
607 
608 	default:
609 		return (ENXIO);
610 	}
611 	return (0);
612 }
613 
614 /*
615  * vgatext_save_text
616  * vgatext_restore_textmode
617  * vgatext_suspend
618  * vgatext_resume
619  *
620  * 	Routines to save and restore contents of the VGA text area
621  * Mostly, this is to support Suspend/Resume operation for graphics
622  * device drivers.  Here in the VGAtext common code, we simply squirrel
623  * away the contents of the hardware's text area during Suspend and then
624  * put it back during Resume
625  */
626 static void
627 vgatext_save_text(struct vgatext_softc *softc)
628 {
629 	unsigned	i;
630 
631 	for (i = 0; i < sizeof (softc->shadow); i++)
632 		softc->shadow[i] = softc->text_base[i];
633 }
634 
635 static void
636 vgatext_restore_textmode(struct vgatext_softc *softc)
637 {
638 	unsigned	i;
639 
640 	vgatext_init(softc);
641 	for (i = 0; i < sizeof (softc->shadow); i++) {
642 		softc->text_base[i] = softc->shadow[i];
643 	}
644 	if (softc->cursor.visible) {
645 		vgatext_set_cursor(softc,
646 		    softc->cursor.row, softc->cursor.col);
647 	}
648 	vgatext_restore_colormap(softc);
649 }
650 
651 static int
652 vgatext_suspend(struct vgatext_softc *softc)
653 {
654 	switch (softc->mode) {
655 	case KD_TEXT:
656 		vgatext_save_text(softc);
657 		break;
658 
659 	case KD_GRAPHICS:
660 		break;
661 
662 	default:
663 		cmn_err(CE_WARN, MYNAME ": unknown mode in vgatext_suspend.");
664 		return (DDI_FAILURE);
665 	}
666 	return (DDI_SUCCESS);
667 }
668 
669 static void
670 vgatext_resume(struct vgatext_softc *softc)
671 {
672 
673 	switch (softc->mode) {
674 	case KD_TEXT:
675 		vgatext_restore_textmode(softc);
676 		break;
677 
678 	case KD_GRAPHICS:
679 
680 		/*
681 		 * Upon RESUME, the graphics device will always actually
682 		 * be in TEXT mode even though the Xorg server did not
683 		 * make that mode change itself (the suspend code did).
684 		 * We want first, therefore, to restore textmode
685 		 * operation fully, and then the Xorg server will
686 		 * do the rest to restore the device to its
687 		 * (hi resolution) graphics mode
688 		 */
689 		vgatext_restore_textmode(softc);
690 #if	defined(USE_BORDERS)
691 		vgatext_init_graphics(softc);
692 #endif
693 		break;
694 	default:
695 		cmn_err(CE_WARN, MYNAME ": unknown mode in vgatext_resume.");
696 		break;
697 	}
698 }
699 
700 static int
701 vgatext_kdsetmode(struct vgatext_softc *softc, int mode)
702 {
703 	int i;
704 
705 	if ((mode == softc->mode) || (!GFXP_IS_CONSOLE(softc)))
706 		return (0);
707 
708 	switch (mode) {
709 	case KD_TEXT:
710 		vgatext_init(softc);
711 		for (i = 0; i < sizeof (softc->shadow); i++) {
712 			softc->text_base[i] = softc->shadow[i];
713 		}
714 		softc->current_base = softc->text_base;
715 		if (softc->cursor.visible) {
716 			vgatext_set_cursor(softc,
717 			    softc->cursor.row, softc->cursor.col);
718 		}
719 		vgatext_restore_colormap(softc);
720 		break;
721 
722 	case KD_GRAPHICS:
723 
724 
725 		if (vgatext_silent == 1) {
726 			extern void progressbar_stop(void);
727 
728 			vgatext_silent = 0;
729 			progressbar_stop();
730 		}
731 		vgatext_save_text(softc);
732 
733 
734 		softc->current_base = softc->shadow;
735 #if	defined(USE_BORDERS)
736 		vgatext_init_graphics(softc);
737 #endif
738 		break;
739 
740 	default:
741 		return (EINVAL);
742 	}
743 	softc->mode = mode;
744 	return (0);
745 }
746 
747 /*ARGSUSED*/
748 int
749 gfxp_vgatext_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len,
750 		size_t *maplen, uint_t model, void *ptr)
751 {
752 	struct vgatext_softc *softc = (struct vgatext_softc *)ptr;
753 	int err;
754 	size_t length;
755 
756 
757 	if (softc == NULL) {
758 		cmn_err(CE_WARN, "vgatext: Can't find softstate");
759 		return (-1);
760 	}
761 
762 	if (!(off >= VGA_MMAP_FB_BASE &&
763 	    off < VGA_MMAP_FB_BASE + softc->fb_size)) {
764 		cmn_err(CE_WARN, "vgatext: Can't map offset 0x%llx", off);
765 		return (-1);
766 	}
767 
768 	if (off + len > VGA_MMAP_FB_BASE + softc->fb_size)
769 		length = VGA_MMAP_FB_BASE + softc->fb_size - off;
770 	else
771 		length = len;
772 
773 	if ((err = devmap_devmem_setup(dhp, softc->devi,
774 	    NULL, softc->fb_regno, off - VGA_MMAP_FB_BASE,
775 	    length, PROT_ALL, 0, &dev_attr)) < 0) {
776 		return (err);
777 	}
778 
779 
780 	*maplen = length;
781 	return (0);
782 }
783 
784 
785 static int
786 vgatext_devinit(struct vgatext_softc *softc, struct vis_devinit *data)
787 {
788 	/* initialize console instance */
789 	data->version = VIS_CONS_REV;
790 	data->width = TEXT_COLS;
791 	data->height = TEXT_ROWS;
792 	data->linebytes = TEXT_COLS;
793 	data->depth = 4;
794 	data->mode = VIS_TEXT;
795 	data->polledio = &softc->polledio;
796 
797 	return (0);
798 }
799 
800 /*
801  * display a string on the screen at (row, col)
802  *	 assume it has been cropped to fit.
803  */
804 
805 static void
806 vgatext_cons_display(struct vgatext_softc *softc, struct vis_consdisplay *da)
807 {
808 	unsigned char	*string;
809 	int	i;
810 	unsigned char	attr;
811 	struct cgatext {
812 		unsigned char ch;
813 		unsigned char attr;
814 	};
815 	struct cgatext *addr;
816 
817 	if (vgatext_silent)
818 		return;
819 	/*
820 	 * Sanity checks.  This is a last-ditch effort to avoid damage
821 	 * from brokenness or maliciousness above.
822 	 */
823 	if (da->row < 0 || da->row >= TEXT_ROWS ||
824 	    da->col < 0 || da->col >= TEXT_COLS ||
825 	    da->col + da->width > TEXT_COLS)
826 		return;
827 
828 	/*
829 	 * To be fully general, we should copyin the data.  This is not
830 	 * really relevant for this text-only driver, but a graphical driver
831 	 * should support these ioctls from userland to enable simple
832 	 * system startup graphics.
833 	 */
834 	attr = (solaris_color_to_pc_color[da->bg_color & 0xf] << 4)
835 	    | solaris_color_to_pc_color[da->fg_color & 0xf];
836 	string = da->data;
837 	addr = (struct cgatext *)softc->current_base
838 	    +  (da->row * TEXT_COLS + da->col);
839 	for (i = 0; i < da->width; i++) {
840 		addr->ch = string[i];
841 		addr->attr = attr;
842 		addr++;
843 	}
844 }
845 
846 static void
847 vgatext_polled_display(
848 	struct vis_polledio_arg *arg,
849 	struct vis_consdisplay *da)
850 {
851 	vgatext_cons_display((struct vgatext_softc *)arg, da);
852 }
853 
854 /*
855  * screen-to-screen copy
856  */
857 
858 static void
859 vgatext_cons_copy(struct vgatext_softc *softc, struct vis_conscopy *ma)
860 {
861 	unsigned short	*from;
862 	unsigned short	*to;
863 	int		cnt;
864 	screen_size_t chars_per_row;
865 	unsigned short	*to_row_start;
866 	unsigned short	*from_row_start;
867 	screen_size_t	rows_to_move;
868 	unsigned short	*base;
869 
870 	if (vgatext_silent)
871 		return;
872 
873 	/*
874 	 * Sanity checks.  Note that this is a last-ditch effort to avoid
875 	 * damage caused by broken-ness or maliciousness above.
876 	 */
877 	if (ma->s_col < 0 || ma->s_col >= TEXT_COLS ||
878 	    ma->s_row < 0 || ma->s_row >= TEXT_ROWS ||
879 	    ma->e_col < 0 || ma->e_col >= TEXT_COLS ||
880 	    ma->e_row < 0 || ma->e_row >= TEXT_ROWS ||
881 	    ma->t_col < 0 || ma->t_col >= TEXT_COLS ||
882 	    ma->t_row < 0 || ma->t_row >= TEXT_ROWS ||
883 	    ma->s_col > ma->e_col ||
884 	    ma->s_row > ma->e_row)
885 		return;
886 
887 	/*
888 	 * Remember we're going to copy shorts because each
889 	 * character/attribute pair is 16 bits.
890 	 */
891 	chars_per_row = ma->e_col - ma->s_col + 1;
892 	rows_to_move = ma->e_row - ma->s_row + 1;
893 
894 	/* More sanity checks. */
895 	if (ma->t_row + rows_to_move > TEXT_ROWS ||
896 	    ma->t_col + chars_per_row > TEXT_COLS)
897 		return;
898 
899 	base = (unsigned short *)softc->current_base;
900 
901 	to_row_start = base + ((ma->t_row * TEXT_COLS) + ma->t_col);
902 	from_row_start = base + ((ma->s_row * TEXT_COLS) + ma->s_col);
903 
904 	if (to_row_start < from_row_start) {
905 		while (rows_to_move-- > 0) {
906 			to = to_row_start;
907 			from = from_row_start;
908 			to_row_start += TEXT_COLS;
909 			from_row_start += TEXT_COLS;
910 			for (cnt = chars_per_row; cnt-- > 0; )
911 				*to++ = *from++;
912 		}
913 	} else {
914 		/*
915 		 * Offset to the end of the region and copy backwards.
916 		 */
917 		cnt = rows_to_move * TEXT_COLS + chars_per_row;
918 		to_row_start += cnt;
919 		from_row_start += cnt;
920 
921 		while (rows_to_move-- > 0) {
922 			to_row_start -= TEXT_COLS;
923 			from_row_start -= TEXT_COLS;
924 			to = to_row_start;
925 			from = from_row_start;
926 			for (cnt = chars_per_row; cnt-- > 0; )
927 				*--to = *--from;
928 		}
929 	}
930 }
931 
932 static void
933 vgatext_polled_copy(
934 	struct vis_polledio_arg *arg,
935 	struct vis_conscopy *ca)
936 {
937 	vgatext_cons_copy((struct vgatext_softc *)arg, ca);
938 }
939 
940 
941 static void
942 vgatext_cons_cursor(struct vgatext_softc *softc, struct vis_conscursor *ca)
943 {
944 	if (vgatext_silent)
945 		return;
946 
947 	switch (ca->action) {
948 	case VIS_HIDE_CURSOR:
949 		softc->cursor.visible = B_FALSE;
950 		if (softc->current_base == softc->text_base)
951 			vgatext_hide_cursor(softc);
952 		break;
953 	case VIS_DISPLAY_CURSOR:
954 		/*
955 		 * Sanity check.  This is a last-ditch effort to avoid
956 		 * damage from brokenness or maliciousness above.
957 		 */
958 		if (ca->col < 0 || ca->col >= TEXT_COLS ||
959 		    ca->row < 0 || ca->row >= TEXT_ROWS)
960 			return;
961 
962 		softc->cursor.visible = B_TRUE;
963 		softc->cursor.col = ca->col;
964 		softc->cursor.row = ca->row;
965 		if (softc->current_base == softc->text_base)
966 			vgatext_set_cursor(softc, ca->row, ca->col);
967 		break;
968 	case VIS_GET_CURSOR:
969 		if (softc->current_base == softc->text_base) {
970 			vgatext_get_cursor(softc, &ca->row, &ca->col);
971 		}
972 		break;
973 	}
974 }
975 
976 static void
977 vgatext_polled_cursor(
978 	struct vis_polledio_arg *arg,
979 	struct vis_conscursor *ca)
980 {
981 	vgatext_cons_cursor((struct vgatext_softc *)arg, ca);
982 }
983 
984 
985 
986 /*ARGSUSED*/
987 static void
988 vgatext_hide_cursor(struct vgatext_softc *softc)
989 {
990 	/* Nothing at present */
991 }
992 
993 static void
994 vgatext_set_cursor(struct vgatext_softc *softc, int row, int col)
995 {
996 	short	addr;
997 
998 	if (vgatext_silent)
999 		return;
1000 
1001 	addr = row * TEXT_COLS + col;
1002 
1003 	vga_set_crtc(&softc->regs, VGA_CRTC_CLAH, addr >> 8);
1004 	vga_set_crtc(&softc->regs, VGA_CRTC_CLAL, addr & 0xff);
1005 }
1006 
1007 static int vga_row, vga_col;
1008 
1009 static void
1010 vgatext_get_cursor(struct vgatext_softc *softc,
1011     screen_pos_t *row, screen_pos_t *col)
1012 {
1013 	short   addr;
1014 
1015 	addr = (vga_get_crtc(&softc->regs, VGA_CRTC_CLAH) << 8) +
1016 	    vga_get_crtc(&softc->regs, VGA_CRTC_CLAL);
1017 
1018 	vga_row = *row = addr / TEXT_COLS;
1019 	vga_col = *col = addr % TEXT_COLS;
1020 }
1021 
1022 /*
1023  * This code is experimental. It's only enabled if console is
1024  * set to graphics, a preliminary implementation of happyface boot.
1025  */
1026 static void
1027 vgatext_set_text(struct vgatext_softc *softc)
1028 {
1029 	int i;
1030 
1031 	if (happyface_boot == 0)
1032 		return;
1033 
1034 	/* we are in graphics mode, set to text 80X25 mode */
1035 
1036 	/* set misc registers */
1037 	vga_set_reg(&softc->regs, VGA_MISC_W, VGA_MISC_TEXT);
1038 
1039 	/* set sequencer registers */
1040 	vga_set_seq(&softc->regs, VGA_SEQ_RST_SYN,
1041 	    (vga_get_seq(&softc->regs, VGA_SEQ_RST_SYN) &
1042 	    ~VGA_SEQ_RST_SYN_NO_SYNC_RESET));
1043 	for (i = 1; i < NUM_SEQ_REG; i++) {
1044 		vga_set_seq(&softc->regs, i, VGA_SEQ_TEXT[i]);
1045 	}
1046 	vga_set_seq(&softc->regs, VGA_SEQ_RST_SYN,
1047 	    (vga_get_seq(&softc->regs, VGA_SEQ_RST_SYN) |
1048 	    VGA_SEQ_RST_SYN_NO_ASYNC_RESET |
1049 	    VGA_SEQ_RST_SYN_NO_SYNC_RESET));
1050 
1051 	/* set crt controller registers */
1052 	vga_set_crtc(&softc->regs, VGA_CRTC_VRE,
1053 	    (vga_get_crtc(&softc->regs, VGA_CRTC_VRE) &
1054 	    ~VGA_CRTC_VRE_LOCK));
1055 	for (i = 0; i < NUM_CRTC_REG; i++) {
1056 		vga_set_crtc(&softc->regs, i, VGA_CRTC_TEXT[i]);
1057 	}
1058 
1059 	/* set graphics controller registers */
1060 	for (i = 0; i < NUM_GRC_REG; i++) {
1061 		vga_set_grc(&softc->regs, i, VGA_GRC_TEXT[i]);
1062 	}
1063 
1064 	/* set attribute registers */
1065 	for (i = 0; i < NUM_ATR_REG; i++) {
1066 		vga_set_atr(&softc->regs, i, VGA_ATR_TEXT[i]);
1067 	}
1068 
1069 	/* set palette */
1070 	for (i = 0; i < VGA_TEXT_CMAP_ENTRIES; i++) {
1071 		vga_put_cmap(&softc->regs, i, VGA_TEXT_PALETTES[i][0] << 2,
1072 		    VGA_TEXT_PALETTES[i][1] << 2,
1073 		    VGA_TEXT_PALETTES[i][2] << 2);
1074 	}
1075 	for (i = VGA_TEXT_CMAP_ENTRIES; i < VGA8_CMAP_ENTRIES; i++) {
1076 		vga_put_cmap(&softc->regs, i, 0, 0, 0);
1077 	}
1078 
1079 	vgatext_save_colormap(softc);
1080 }
1081 
1082 static void
1083 vgatext_init(struct vgatext_softc *softc)
1084 {
1085 	unsigned char atr_mode;
1086 
1087 	atr_mode = vga_get_atr(&softc->regs, VGA_ATR_MODE);
1088 	if (atr_mode & VGA_ATR_MODE_GRAPH)
1089 		vgatext_set_text(softc);
1090 	atr_mode = vga_get_atr(&softc->regs, VGA_ATR_MODE);
1091 	atr_mode &= ~VGA_ATR_MODE_BLINK;
1092 	atr_mode &= ~VGA_ATR_MODE_9WIDE;
1093 	vga_set_atr(&softc->regs, VGA_ATR_MODE, atr_mode);
1094 #if	defined(USE_BORDERS)
1095 	vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR,
1096 	    vga_get_atr(&softc->regs, VGA_BRIGHT_WHITE));
1097 #else
1098 	vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR,
1099 	    vga_get_atr(&softc->regs, VGA_BLACK));
1100 #endif
1101 	vgatext_setfont(softc);	/* need selectable font? */
1102 }
1103 
1104 #if	defined(USE_BORDERS)
1105 static void
1106 vgatext_init_graphics(struct vgatext_softc *softc)
1107 {
1108 	vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR,
1109 	    vga_get_atr(&softc->regs, VGA_BLACK));
1110 }
1111 #endif
1112 
1113 static void
1114 vgatext_setfont(struct vgatext_softc *softc)
1115 {
1116 	extern unsigned char *ENCODINGS[];
1117 	unsigned char *from;
1118 	unsigned char *to;
1119 	int	i;
1120 	int	j;
1121 	int	bpc;
1122 
1123 /*
1124  * The newboot code to use font plane 2 breaks NVIDIA
1125  * (and some ATI) behavior.  Revert back to the S10
1126  * code.
1127  */
1128 
1129 	/*
1130 	 * I'm embarassed to say that I don't know what these magic
1131 	 * sequences do, other than at the high level of "set the
1132 	 * memory window to allow font setup".  I stole them straight
1133 	 * from "kd"...
1134 	 */
1135 	vga_set_seq(&softc->regs, 0x02, 0x04);
1136 	vga_set_seq(&softc->regs, 0x04, 0x06);
1137 	vga_set_grc(&softc->regs, 0x05, 0x00);
1138 	vga_set_grc(&softc->regs, 0x06, 0x04);
1139 
1140 	/*
1141 	 * This assumes 8x16 characters, which yield the traditional 80x25
1142 	 * screen.  It really should support other character heights.
1143 	 */
1144 	bpc = 16;
1145 	for (i = 0; i < 256; i++) {
1146 		from = ENCODINGS[i];
1147 		to = (unsigned char *)softc->fb.addr + i * 0x20;
1148 		for (j = 0; j < bpc; j++)
1149 			*to++ = *from++;
1150 	}
1151 
1152 	vga_set_seq(&softc->regs, 0x02, 0x03);
1153 	vga_set_seq(&softc->regs, 0x04, 0x02);
1154 	vga_set_grc(&softc->regs, 0x04, 0x00);
1155 	vga_set_grc(&softc->regs, 0x05, 0x10);
1156 	vga_set_grc(&softc->regs, 0x06, 0x0e);
1157 
1158 }
1159 
1160 static void
1161 vgatext_save_colormap(struct vgatext_softc *softc)
1162 {
1163 	int i;
1164 
1165 	for (i = 0; i < VGA_ATR_NUM_PLT; i++) {
1166 		softc->attrib_palette[i] = vga_get_atr(&softc->regs, i);
1167 	}
1168 	for (i = 0; i < VGA8_CMAP_ENTRIES; i++) {
1169 		vga_get_cmap(&softc->regs, i,
1170 		    &softc->colormap[i].red,
1171 		    &softc->colormap[i].green,
1172 		    &softc->colormap[i].blue);
1173 	}
1174 }
1175 
1176 static void
1177 vgatext_restore_colormap(struct vgatext_softc *softc)
1178 {
1179 	int i;
1180 
1181 	for (i = 0; i < VGA_ATR_NUM_PLT; i++) {
1182 		vga_set_atr(&softc->regs, i, softc->attrib_palette[i]);
1183 	}
1184 	for (i = 0; i < VGA8_CMAP_ENTRIES; i++) {
1185 		vga_put_cmap(&softc->regs, i,
1186 		    softc->colormap[i].red,
1187 		    softc->colormap[i].green,
1188 		    softc->colormap[i].blue);
1189 	}
1190 }
1191 
1192 /*
1193  * search the entries of the "reg" property for one which has the desired
1194  * combination of phys_hi bits and contains the desired address.
1195  *
1196  * This version searches a PCI-style "reg" property.  It was prompted by
1197  * issues surrounding the presence or absence of an entry for the ROM:
1198  * (a) a transition problem with PowerPC Virtual Open Firmware
1199  * (b) uncertainty as to whether an entry will be included on a device
1200  *     with ROM support (and so an "active" ROM base address register),
1201  *     but no ROM actually installed.
1202  *
1203  * See the note below on vgatext_get_isa_reg_index for the reasons for
1204  * returning the offset.
1205  *
1206  * Note that this routine may not be fully general; it is intended for the
1207  * specific purpose of finding a couple of particular VGA reg entries and
1208  * may not be suitable for all reg-searching purposes.
1209  */
1210 static int
1211 vgatext_get_pci_reg_index(
1212 	dev_info_t *const devi,
1213 	unsigned long himask,
1214 	unsigned long hival,
1215 	unsigned long addr,
1216 	off_t *offset)
1217 {
1218 
1219 	int			length, index;
1220 	pci_regspec_t	*reg;
1221 
1222 	if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
1223 	    "reg", (caddr_t)&reg, &length) != DDI_PROP_SUCCESS) {
1224 		return (-1);
1225 	}
1226 
1227 	for (index = 0; index < length / sizeof (pci_regspec_t); index++) {
1228 		if ((reg[index].pci_phys_hi & himask) != hival)
1229 			continue;
1230 		if (reg[index].pci_size_hi != 0)
1231 			continue;
1232 		if (reg[index].pci_phys_mid != 0)
1233 			continue;
1234 		if (reg[index].pci_phys_low > addr)
1235 			continue;
1236 		if (reg[index].pci_phys_low + reg[index].pci_size_low <= addr)
1237 			continue;
1238 
1239 		*offset = addr - reg[index].pci_phys_low;
1240 		kmem_free(reg, (size_t)length);
1241 		return (index);
1242 	}
1243 	kmem_free(reg, (size_t)length);
1244 
1245 	return (-1);
1246 }
1247 
1248 /*
1249  * search the entries of the "reg" property for one which has the desired
1250  * combination of phys_hi bits and contains the desired address.
1251  *
1252  * This version searches a ISA-style "reg" property.  It was prompted by
1253  * issues surrounding 8514/A support.  By IEEE 1275 compatibility conventions,
1254  * 8514/A registers should have been added after all standard VGA registers.
1255  * Unfortunately, the Solaris/Intel device configuration framework
1256  * (a) lists the 8514/A registers before the video memory, and then
1257  * (b) also sorts the entries so that I/O entries come before memory
1258  *     entries.
1259  *
1260  * It returns the "reg" index and offset into that register set.
1261  * The offset is needed because there exist (broken?) BIOSes that
1262  * report larger ranges enclosing the standard ranges.  One reports
1263  * 0x3bf for 0x21 instead of 0x3c0 for 0x20, for instance.  Using the
1264  * offset adjusts for this difference in the base of the register set.
1265  *
1266  * Note that this routine may not be fully general; it is intended for the
1267  * specific purpose of finding a couple of particular VGA reg entries and
1268  * may not be suitable for all reg-searching purposes.
1269  */
1270 static int
1271 vgatext_get_isa_reg_index(
1272 	dev_info_t *const devi,
1273 	unsigned long hival,
1274 	unsigned long addr,
1275 	off_t *offset)
1276 {
1277 
1278 	int		length, index;
1279 	struct regspec	*reg;
1280 
1281 	if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
1282 	    "reg", (caddr_t)&reg, &length) != DDI_PROP_SUCCESS) {
1283 		return (-1);
1284 	}
1285 
1286 	for (index = 0; index < length / sizeof (struct regspec); index++) {
1287 		if (reg[index].regspec_bustype != hival)
1288 			continue;
1289 		if (reg[index].regspec_addr > addr)
1290 			continue;
1291 		if (reg[index].regspec_addr + reg[index].regspec_size <= addr)
1292 			continue;
1293 
1294 		*offset = addr - reg[index].regspec_addr;
1295 		kmem_free(reg, (size_t)length);
1296 		return (index);
1297 	}
1298 	kmem_free(reg, (size_t)length);
1299 
1300 	return (-1);
1301 }
1302 
1303 /*
1304  * This vgatext function is used to return the fb, and reg pointers
1305  * and handles for peer graphics drivers.
1306  */
1307 
1308 void
1309 vgatext_return_pointers(struct vgatext_softc *softc,
1310 			struct vgaregmap *fbs,
1311 			struct vgaregmap *regss)
1312 {
1313 
1314 	fbs->addr	= softc->fb.addr;
1315 	fbs->handle	= softc->fb.handle;
1316 	fbs->mapped	= softc->fb.mapped;
1317 	regss->addr	= softc->regs.addr;
1318 	regss->handle	= softc->regs.handle;
1319 	regss->mapped	= softc->regs.mapped;
1320 }
1321