xref: /openbsd-src/sys/dev/pci/vga_pci.c (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1 /* $OpenBSD: vga_pci.c,v 1.67 2011/04/14 21:04:29 oga Exp $ */
2 /* $NetBSD: vga_pci.c,v 1.3 1998/06/08 06:55:58 thorpej Exp $ */
3 
4 /*
5  * Copyright (c) 2001 Wasabi Systems, Inc.
6  * All rights reserved.
7  *
8  * Written by Frank van der Linden for Wasabi Systems, Inc.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed for the NetBSD Project by
21  *	Wasabi Systems, Inc.
22  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
23  *    or promote products derived from this software without specific prior
24  *    written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 /*
39  * Copyright (c) 1995, 1996 Carnegie-Mellon University.
40  * All rights reserved.
41  *
42  * Author: Chris G. Demetriou
43  *
44  * Permission to use, copy, modify and distribute this software and
45  * its documentation is hereby granted, provided that both the copyright
46  * notice and this permission notice appear in all copies of the
47  * software, derivative works or modified versions, and any portions
48  * thereof, and that both notices appear in supporting documentation.
49  *
50  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
51  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
52  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
53  *
54  * Carnegie Mellon requests users of this software to return to
55  *
56  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
57  *  School of Computer Science
58  *  Carnegie Mellon University
59  *  Pittsburgh PA 15213-3890
60  *
61  * any improvements or extensions that they make and grant Carnegie the
62  * rights to redistribute these changes.
63  */
64 
65 #include "vga.h"
66 #if defined(__i386__) || defined(__amd64__)
67 #include "acpi.h"
68 #endif
69 
70 #include <sys/param.h>
71 #include <sys/systm.h>
72 #include <sys/kernel.h>
73 #include <sys/device.h>
74 #include <sys/malloc.h>
75 #include <sys/agpio.h>
76 
77 #include <uvm/uvm.h>
78 
79 #include <machine/bus.h>
80 
81 #include <dev/pci/pcireg.h>
82 #include <dev/pci/pcivar.h>
83 #include <dev/pci/pcidevs.h>
84 
85 #include <dev/pci/agpvar.h>
86 
87 #include <dev/ic/mc6845reg.h>
88 #include <dev/ic/pcdisplayvar.h>
89 #include <dev/ic/vgareg.h>
90 #include <dev/ic/vgavar.h>
91 #include <dev/pci/vga_pcivar.h>
92 
93 
94 #include <dev/wscons/wsconsio.h>
95 #include <dev/wscons/wsdisplayvar.h>
96 
97 #ifdef X86EMU
98 #include <machine/vga_post.h>
99 #endif
100 
101 #ifdef VESAFB
102 #include <dev/vesa/vesabiosvar.h>
103 #endif
104 
105 #include "intagp.h"
106 #include "drm.h"
107 
108 int	vga_pci_match(struct device *, void *, void *);
109 void	vga_pci_attach(struct device *, struct device *, void *);
110 int	vga_pci_activate(struct device *, int);
111 paddr_t	vga_pci_mmap(void* v, off_t off, int prot);
112 void	vga_pci_bar_init(struct vga_pci_softc *, struct pci_attach_args *);
113 
114 #if NINTAGP > 0
115 int	intagpsubmatch(struct device *, void *, void *);
116 int	intagp_print(void *, const char *);
117 #endif
118 #if NDRM > 0
119 int	drmsubmatch(struct device *, void *, void *);
120 int	vga_drm_print(void *, const char *);
121 #endif
122 
123 #ifdef VESAFB
124 int	vesafb_putcmap(struct vga_pci_softc *, struct wsdisplay_cmap *);
125 int	vesafb_getcmap(struct vga_pci_softc *, struct wsdisplay_cmap *);
126 #endif
127 
128 #if !defined(SMALL_KERNEL) && NACPI > 0
129 void	vga_save_state(struct vga_pci_softc *);
130 void	vga_restore_state(struct vga_pci_softc *);
131 #endif
132 
133 
134 /*
135  * Function pointers for wsconsctl parameter handling.
136  * XXX These should be per-softc, but right now we only attach
137  * XXX a single vga@pci instance, so this will do.
138  */
139 int	(*ws_get_param)(struct wsdisplay_param *);
140 int	(*ws_set_param)(struct wsdisplay_param *);
141 
142 
143 struct cfattach vga_pci_ca = {
144 	sizeof(struct vga_pci_softc), vga_pci_match, vga_pci_attach,
145 	NULL, vga_pci_activate
146 };
147 
148 #if !defined(SMALL_KERNEL) && NACPI > 0
149 int vga_pci_do_post;
150 extern int do_real_mode_post;
151 
152 struct vga_device_description {
153 	u_int16_t	rval[4];
154 	u_int16_t	rmask[4];
155 	char	vga_pci_post;
156 	char	real_mode_post;
157 };
158 
159 static const struct vga_device_description vga_devs[] = {
160 	/*
161 	 * Header description:
162 	 *
163 	 * First entry is a list of the pci video information in the following
164 	 * order: VENDOR, PRODUCT, SUBVENDOR, SUBPRODUCT
165 	 *
166 	 * The next entry is a list of corresponding masks.
167 	 *
168 	 * Finally the last two values set what resume should do, repost with
169 	 * vga_pci (i.e. the x86emulator) or with a locore call to the video
170 	 * bios.
171 	 */
172 	{	/* All machines with Intel US15W (until more evidence) */
173 	    {	PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_US15W_IGD,
174 	    	0x0000, 0x0000 },
175 	    {	0xffff, 0xffff, 0x0000, 0x0000 }, 1, 0
176 	},
177 	{	/* All machines with Intel US15L (until more evidence) */
178 	    {	PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_US15L_IGD,
179 	    	0x0000, 0x0000 },
180 	    {	0xffff, 0xffff, 0x0000, 0x0000 }, 1, 0
181 	},
182 
183 	{	/*  Anything with on-die intel graphics, for now */
184 	    {	PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_ARRANDALE_IGD,
185 	    	0x0000, 0x0000 },
186 	    {	0xffff, 0xffff, 0x0000, 0x0000 }, 1, 0
187 	},
188 
189 	{	/*  Anything with on-die intel graphics, for now */
190 	    {	PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_CLARKDALE_IGD,
191 	    	0x0000, 0x0000 },
192 	    {	0xffff, 0xffff, 0x0000, 0x0000 }, 1, 0
193 	},
194 
195 	{	/* All ATI video until further notice */
196 	    {	PCI_VENDOR_ATI, 0x0000,
197 		0x0000, 0x0000 },
198 	    {	0xffff, 0x0000, 0x0000, 0x0000}, 1, 0
199 	},
200 };
201 #endif
202 
203 int
204 vga_pci_match(struct device *parent, void *match, void *aux)
205 {
206 	struct pci_attach_args *pa = aux;
207 
208 	if (DEVICE_IS_VGA_PCI(pa->pa_class) == 0)
209 		return (0);
210 
211 	/* check whether it is disabled by firmware */
212 	if ((pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG)
213 	    & (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE))
214 	    != (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE))
215 		return (0);
216 
217 	/* If it's the console, we have a winner! */
218 	if (vga_is_console(pa->pa_iot, WSDISPLAY_TYPE_PCIVGA))
219 		return (1);
220 
221 	/*
222 	 * If we might match, make sure that the card actually looks OK.
223 	 */
224 	if (!vga_common_probe(pa->pa_iot, pa->pa_memt))
225 		return (0);
226 
227 	return (1);
228 }
229 
230 void
231 vga_pci_attach(struct device *parent, struct device *self, void *aux)
232 {
233 	struct pci_attach_args *pa = aux;
234 	pcireg_t reg;
235 	struct vga_pci_softc *sc = (struct vga_pci_softc *)self;
236 
237 #if !defined(SMALL_KERNEL) && NACPI > 0
238 	int prod, vend, subid, subprod, subvend, i;
239 #endif
240 
241 	/*
242 	 * Enable bus master; X might need this for accelerated graphics.
243 	 */
244 	reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
245 	reg |= PCI_COMMAND_MASTER_ENABLE;
246 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, reg);
247 
248 #ifdef VESAFB
249 	if (vesabios_softc != NULL && vesabios_softc->sc_nmodes > 0) {
250 		sc->sc_textmode = vesafb_get_mode(sc);
251 		printf(", vesafb\n");
252 		sc->sc_vc = vga_extended_attach(self, pa->pa_iot, pa->pa_memt,
253 		    WSDISPLAY_TYPE_PCIVGA, vga_pci_mmap);
254 		return;
255 	}
256 #endif
257 	printf("\n");
258 	sc->sc_vc = vga_common_attach(self, pa->pa_iot, pa->pa_memt,
259 	    WSDISPLAY_TYPE_PCIVGA);
260 
261 	vga_pci_bar_init(sc, pa);
262 
263 #if !defined(SMALL_KERNEL) && NACPI > 0
264 
265 #ifdef X86EMU
266 	if ((sc->sc_posth = vga_post_init(pa->pa_bus, pa->pa_device,
267 	    pa->pa_function)) == NULL)
268 		printf("couldn't set up vga POST handler\n");
269 #endif
270 
271 	vend = PCI_VENDOR(pa->pa_id);
272 	prod = PCI_PRODUCT(pa->pa_id);
273 	subid = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
274 	subvend = PCI_VENDOR(subid);
275 	subprod = PCI_PRODUCT(subid);
276 
277 	for (i = 0; i < nitems(vga_devs); i++)
278 		if ((vend & vga_devs[i].rmask[0]) == vga_devs[i].rval[0] &&
279 		    (prod & vga_devs[i].rmask[1]) == vga_devs[i].rval[1] &&
280 		    (subvend & vga_devs[i].rmask[2]) == vga_devs[i].rval[2] &&
281 		    (subprod & vga_devs[i].rmask[3]) == vga_devs[i].rval[3]) {
282 			vga_pci_do_post = vga_devs[i].vga_pci_post;
283 			if (sc->sc_dev.dv_unit == 0)	/* main screen only */
284 				do_real_mode_post = vga_devs[i].real_mode_post;
285 			break;
286 		}
287 #endif
288 
289 #if NINTAGP > 0
290 	/*
291 	 * attach intagp here instead of pchb so it can share mappings
292 	 * with the DRM.
293 	 */
294 	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_INTEL) {
295 		config_found_sm(self, aux, intagp_print, intagpsubmatch);
296 
297 	}
298 #endif
299 
300 #if NDRM > 0
301 	config_found_sm(self, aux, NULL, drmsubmatch);
302 #endif
303 }
304 
305 int
306 vga_pci_activate(struct device *self, int act)
307 {
308 	int rv = 0;
309 
310 #if !defined(SMALL_KERNEL) && NACPI > 0
311 	struct vga_pci_softc *sc = (struct vga_pci_softc *)self;
312 #endif
313 
314 	switch (act) {
315 	case DVACT_QUIESCE:
316 		rv = config_activate_children(self, act);
317 		break;
318 	case DVACT_SUSPEND:
319 		rv = config_activate_children(self, act);
320 #if !defined(SMALL_KERNEL) && NACPI > 0
321 		/*
322 		 * Save the common vga state. This should theoretically only
323 		 * be necessary if we intend to POST, but it is preferrable
324 		 * to do it unconditionnaly, as many systems do not restore
325 		 * this state correctly upon resume.
326 		 */
327 		vga_save_state(sc);
328 #endif
329 		break;
330 	case DVACT_RESUME:
331 #if !defined(SMALL_KERNEL) && NACPI > 0
332 #if defined (X86EMU)
333 		if (vga_pci_do_post) {
334 #ifdef obnoxious
335 			printf("%s: reposting video using BIOS.  Is this necessary?\n",
336 			    sc->sc_dev.dv_xname);
337 #endif
338 			vga_post_call(sc->sc_posth);
339 		}
340 #endif
341 		vga_restore_state(sc);
342 #endif
343 		rv = config_activate_children(self, act);
344 		break;
345 	}
346 
347 	return (rv);
348 }
349 
350 #if NINTAGP > 0
351 int
352 intagpsubmatch(struct device *parent, void *match, void *aux)
353 {
354 	extern struct cfdriver intagp_cd;
355 	struct cfdata *cf = match;
356 
357 	/* only allow intagp to attach */
358 	if (cf->cf_driver == &intagp_cd)
359 		return ((*cf->cf_attach->ca_match)(parent, match, aux));
360 	return (0);
361 }
362 
363 int
364 intagp_print(void *vaa, const char *pnp)
365 {
366 	if (pnp)
367 		printf("intagp at %s", pnp);
368 	return (UNCONF);
369 }
370 #endif
371 
372 #if NDRM > 0
373 int
374 drmsubmatch(struct device *parent, void *match, void *aux)
375 {
376 	struct cfdata *cf = match;
377 	struct cfdriver *cd;
378 	size_t len = 0;
379 	char *sm;
380 
381 	cd = cf->cf_driver;
382 
383 	/* is this a *drm device? */
384 	len = strlen(cd->cd_name);
385 	sm = cd->cd_name + len - 3;
386 	if (strncmp(sm, "drm", 3) == 0)
387 		return ((*cf->cf_attach->ca_match)(parent, match, aux));
388 
389 	return (0);
390 }
391 #endif
392 
393 paddr_t
394 vga_pci_mmap(void *v, off_t off, int prot)
395 {
396 #ifdef VESAFB
397 	struct vga_config *vc = (struct vga_config *)v;
398 	struct vga_pci_softc *sc = (struct vga_pci_softc *)vc->vc_softc;
399 
400 	if (sc->sc_mode == WSDISPLAYIO_MODE_DUMBFB) {
401 		if (off < 0 || off > vesabios_softc->sc_size)
402 			return (-1);
403 		return (sc->sc_base + off);
404 	}
405 #endif
406 	return -1;
407 }
408 
409 int
410 vga_pci_cnattach(bus_space_tag_t iot, bus_space_tag_t memt,
411     pci_chipset_tag_t pc, int bus, int device, int function)
412 {
413 	return (vga_cnattach(iot, memt, WSDISPLAY_TYPE_PCIVGA, 0));
414 }
415 
416 int
417 vga_pci_ioctl(void *v, u_long cmd, caddr_t addr, int flag, struct proc *pb)
418 {
419 	int error = 0;
420 #ifdef VESAFB
421 	struct vga_config *vc = (struct vga_config *)v;
422 	struct vga_pci_softc *sc = (struct vga_pci_softc *)vc->vc_softc;
423 	struct wsdisplay_fbinfo *wdf;
424 	struct wsdisplay_gfx_mode *gfxmode;
425 	int mode;
426 #endif
427 
428 	switch (cmd) {
429 #ifdef VESAFB
430 	case WSDISPLAYIO_SMODE:
431 		mode = *(u_int *)addr;
432 		switch (mode) {
433 		case WSDISPLAYIO_MODE_EMUL:
434 			/* back to text mode */
435 			vesafb_set_mode(sc, sc->sc_textmode);
436 			sc->sc_mode = mode;
437 			break;
438 		case WSDISPLAYIO_MODE_DUMBFB:
439 			if (sc->sc_gfxmode == -1)
440 				return (-1);
441 			vesafb_set_mode(sc, sc->sc_gfxmode);
442 			sc->sc_mode = mode;
443 			break;
444 		default:
445 			error = -1;
446 		}
447 		break;
448 	case WSDISPLAYIO_GINFO:
449 		if (sc->sc_gfxmode == -1)
450 			return (-1);
451 		wdf = (void *)addr;
452 		wdf->height = sc->sc_height;
453 		wdf->width = sc->sc_width;
454 		wdf->depth = sc->sc_depth;
455 		wdf->cmsize = 256;
456 		break;
457 
458 	case WSDISPLAYIO_LINEBYTES:
459 		if (sc->sc_gfxmode == -1)
460 			return (-1);
461 		*(u_int *)addr = sc->sc_linebytes;
462 		break;
463 
464 	case WSDISPLAYIO_SVIDEO:
465 	case WSDISPLAYIO_GVIDEO:
466 		break;
467 	case WSDISPLAYIO_GETCMAP:
468 		if (sc->sc_depth == 8)
469 			error = vesafb_getcmap(sc,
470 			    (struct wsdisplay_cmap *)addr);
471 		break;
472 
473 	case WSDISPLAYIO_PUTCMAP:
474 		if (sc->sc_depth == 8)
475 			error = vesafb_putcmap(sc,
476 			    (struct wsdisplay_cmap *)addr);
477 		break;
478 
479 	case WSDISPLAYIO_GETSUPPORTEDDEPTH:
480 		*(int *)addr = vesafb_get_supported_depth(sc);
481 		break;
482 
483 	case WSDISPLAYIO_SETGFXMODE:
484 		gfxmode = (struct wsdisplay_gfx_mode *)addr;
485 		sc->sc_gfxmode = vesafb_find_mode(sc, gfxmode->width,
486 		    gfxmode->height, gfxmode->depth);
487 		if (sc->sc_gfxmode == -1)
488 			error = -1;
489 		break;
490 
491 #endif
492 	case WSDISPLAYIO_GETPARAM:
493 		if (ws_get_param != NULL)
494 			return (*ws_get_param)((struct wsdisplay_param *)addr);
495 		else
496 			error = ENOTTY;
497 		break;
498 	case WSDISPLAYIO_SETPARAM:
499 		if (ws_set_param != NULL)
500 			return (*ws_set_param)((struct wsdisplay_param *)addr);
501 		else
502 			error = ENOTTY;
503 		break;
504 	default:
505 		error = ENOTTY;
506 	}
507 
508 	return (error);
509 }
510 
511 #ifdef notyet
512 void
513 vga_pci_close(void *v)
514 {
515 }
516 #endif
517 
518 /*
519  * Prepare dev->bars to be used for information. we do this at startup
520  * so we can do the whole array at once, dealing with 64-bit BARs correctly.
521  */
522 void
523 vga_pci_bar_init(struct vga_pci_softc *dev, struct pci_attach_args *pa)
524 {
525 	pcireg_t type;
526 	int addr = PCI_MAPREG_START, i = 0;
527 	memcpy(&dev->pa, pa, sizeof(dev->pa));
528 
529 	while (i < VGA_PCI_MAX_BARS) {
530 		dev->bars[i] = malloc(sizeof((*dev->bars[i])), M_DEVBUF,
531 		    M_NOWAIT | M_ZERO);
532 		if (dev->bars[i] == NULL) {
533 			return;
534 		}
535 
536 		dev->bars[i]->addr = addr;
537 
538 		type = dev->bars[i]->maptype = pci_mapreg_type(pa->pa_pc,
539 		    pa->pa_tag, addr);
540 		if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, addr,
541 		    dev->bars[i]->maptype, &dev->bars[i]->base,
542 		    &dev->bars[i]->maxsize, &dev->bars[i]->flags) != 0) {
543 			free(dev->bars[i], M_DEVBUF);
544 			dev->bars[i] = NULL;
545 		}
546 
547 		if (type == PCI_MAPREG_MEM_TYPE_64BIT) {
548 			addr += 8;
549 			i += 2;
550 		} else {
551 			addr += 4;
552 			i++;
553 		}
554 	}
555 }
556 
557 /*
558  * Get the vga_pci_bar struct for the address in question. returns NULL if
559  * invalid BAR is passed.
560  */
561 struct vga_pci_bar*
562 vga_pci_bar_info(struct vga_pci_softc *dev, int no)
563 {
564 	if (dev == NULL || no >= VGA_PCI_MAX_BARS)
565 		return (NULL);
566 	return (dev->bars[no]);
567 }
568 
569 /*
570  * map the BAR in question, returning the vga_pci_bar struct in case any more
571  * processing needs to be done. Returns NULL on failure. Can be called multiple
572  * times.
573  */
574 struct vga_pci_bar*
575 vga_pci_bar_map(struct vga_pci_softc *dev, int addr, bus_size_t size,
576     int busflags)
577 {
578 	struct vga_pci_bar *bar = NULL;
579 	int i;
580 
581 	if (dev == NULL)
582 		return (NULL);
583 
584 	for (i = 0; i < VGA_PCI_MAX_BARS; i++) {
585 		if (dev->bars[i] && dev->bars[i]->addr == addr) {
586 			bar = dev->bars[i];
587 			break;
588 		}
589 	}
590 	if (bar == NULL) {
591 		printf("vga_pci_bar_map: given invalid address 0x%x\n", addr);
592 		return (NULL);
593 	}
594 
595 	if (bar->mapped == 0) {
596 		if (pci_mapreg_map(&dev->pa, bar->addr, bar->maptype,
597 		    bar->flags | busflags, &bar->bst, &bar->bsh, NULL,
598 		    &bar->size, size)) {
599 			printf("vga_pci_bar_map: can't map bar 0x%x\n", addr);
600 			return (NULL);
601 		}
602 	}
603 
604 	bar->mapped++;
605 	return (bar);
606 }
607 
608 /*
609  * "unmap" the BAR referred to by argument. If more than one place has mapped it
610  * we just decrement the reference counter so nothing untoward happens.
611  */
612 void
613 vga_pci_bar_unmap(struct vga_pci_bar *bar)
614 {
615 	if (bar != NULL && bar->mapped != 0) {
616 		if (--bar->mapped == 0)
617 			bus_space_unmap(bar->bst, bar->bsh, bar->size);
618 	}
619 }
620 
621 #if !defined(SMALL_KERNEL) && NACPI > 0
622 void
623 vga_save_state(struct vga_pci_softc *sc)
624 {
625 	struct vga_config *vc = sc->sc_vc;
626 	struct vga_handle *vh;
627 	struct vgascreen *scr;
628 	size_t i;
629 	char *buf;
630 
631 	if (vc == NULL)
632 		return;
633 
634 	vh = &vc->hdl;
635 
636 	/*
637 	 * Save sequencer registers
638 	 */
639 	vga_ts_write(vh, syncreset, 1);	/* stop sequencer */
640 	buf = (char *)&sc->sc_save_ts;
641 	*buf++ = 0;
642 	for (i = 1; i < sizeof(sc->sc_save_ts); i++)
643 		*buf++ = _vga_ts_read(vh, i);
644 	vga_ts_write(vh, syncreset, 3);	/* start sequencer */
645 	/* pretend screen is not blanked */
646 	sc->sc_save_ts.mode &= ~0x20;
647 	sc->sc_save_ts.mode |= 0x80;
648 
649 	/*
650 	 * Save CRTC registers
651 	 */
652 	buf = (char *)&sc->sc_save_crtc;
653 	for (i = 0; i < sizeof(sc->sc_save_crtc); i++)
654 		*buf++ = _pcdisplay_6845_read(&vh->vh_ph, i);
655 
656 	/*
657 	 * Save ATC registers
658 	 */
659 	buf = (char *)&sc->sc_save_atc;
660 	for (i = 0; i < sizeof(sc->sc_save_atc); i++)
661 		*buf++ = _vga_attr_read(vh, i);
662 
663 	/*
664 	 * Save GDC registers
665 	 */
666 	buf = (char *)&sc->sc_save_gdc;
667 	for (i = 0; i < sizeof(sc->sc_save_gdc); i++)
668 		*buf++ = _vga_gdc_read(vh, i);
669 
670 	vga_save_palette(vc);
671 
672 	/* XXX should also save font data */
673 
674 	/*
675 	 * Save current screen contents if we have backing store for it,
676 	 * and intend to POST on resume.
677 	 * XXX Since we don't allocate backing store unless the second VT is
678 	 * XXX created, we could theoretically have no backing store available
679 	 * XXX at this point.
680 	 */
681 	if (vga_pci_do_post) {
682 		scr = vc->active;
683 		if (scr != NULL && scr->pcs.active && scr->pcs.mem != NULL)
684 			bus_space_read_region_2(vh->vh_memt, vh->vh_memh,
685 			    scr->pcs.dispoffset, scr->pcs.mem,
686 			    scr->pcs.type->ncols * scr->pcs.type->nrows);
687 	}
688 }
689 
690 void
691 vga_restore_state(struct vga_pci_softc *sc)
692 {
693 	struct vga_config *vc = sc->sc_vc;
694 	struct vga_handle *vh;
695 	struct vgascreen *scr;
696 	size_t i;
697 	char *buf;
698 
699 	if (vc == NULL)
700 		return;
701 
702 	vh = &vc->hdl;
703 
704 	/*
705 	 * Restore sequencer registers
706 	 */
707 	vga_ts_write(vh, syncreset, 1);	/* stop sequencer */
708 	buf = (char *)&sc->sc_save_ts + 1;
709 	for (i = 1; i < sizeof(sc->sc_save_ts); i++)
710 		_vga_ts_write(vh, i, *buf++);
711 	vga_ts_write(vh, syncreset, 3);	/* start sequencer */
712 
713 	/*
714 	 * Restore CRTC registers
715 	 */
716 	/* unprotect registers 00-07 */
717 	vga_6845_write(vh, vsynce,
718 	    vga_6845_read(vh, vsynce) & ~0x80);
719 	buf = (char *)&sc->sc_save_crtc;
720 	for (i = 0; i < sizeof(sc->sc_save_crtc); i++)
721 		_pcdisplay_6845_write(&vh->vh_ph, i, *buf++);
722 
723 	/*
724 	 * Restore ATC registers
725 	 */
726 	buf = (char *)&sc->sc_save_atc;
727 	for (i = 0; i < sizeof(sc->sc_save_atc); i++)
728 		_vga_attr_write(vh, i, *buf++);
729 
730 	/*
731 	 * Restore GDC registers
732 	 */
733 	buf = (char *)&sc->sc_save_gdc;
734 	for (i = 0; i < sizeof(sc->sc_save_gdc); i++)
735 		_vga_gdc_write(vh, i, *buf++);
736 
737 	vga_restore_palette(vc);
738 
739 	/*
740 	 * Restore current screen contents if we have backing store for it,
741 	 * and have POSTed on resume.
742 	 * XXX Since we don't allocate backing store unless the second VT is
743 	 * XXX created, we could theoretically have no backing store available
744 	 * XXX at this point.
745 	 */
746 	if (vga_pci_do_post) {
747 		scr = vc->active;
748 		if (scr != NULL && scr->pcs.active && scr->pcs.mem != NULL)
749 			bus_space_write_region_2(vh->vh_memt, vh->vh_memh,
750 			    scr->pcs.dispoffset, scr->pcs.mem,
751 			    scr->pcs.type->ncols * scr->pcs.type->nrows);
752 	}
753 }
754 #endif
755