143105Sdfr/*-
243105Sdfr * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
343105Sdfr * All rights reserved.
443105Sdfr *
543105Sdfr * Redistribution and use in source and binary forms, with or without
643105Sdfr * modification, are permitted provided that the following conditions
743105Sdfr * are met:
843105Sdfr * 1. Redistributions of source code must retain the above copyright
943105Sdfr *    notice, this list of conditions and the following disclaimer as
1043105Sdfr *    the first lines of this file unmodified.
1143105Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1243105Sdfr *    notice, this list of conditions and the following disclaimer in the
1343105Sdfr *    documentation and/or other materials provided with the distribution.
1443105Sdfr *
1543105Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
1643105Sdfr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1743105Sdfr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1843105Sdfr * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
1943105Sdfr * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2043105Sdfr * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2143105Sdfr * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2243105Sdfr * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2343105Sdfr * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2443105Sdfr * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2543105Sdfr */
2643105Sdfr
27116181Sobrien#include <sys/cdefs.h>
28116181Sobrien__FBSDID("$FreeBSD$");
29116181Sobrien
3043105Sdfr#include "opt_vga.h"
3143105Sdfr#include "opt_fb.h"
3243105Sdfr#include "opt_syscons.h"	/* should be removed in the future, XXX */
3343105Sdfr
3443105Sdfr#include <sys/param.h>
3543105Sdfr#include <sys/systm.h>
3643105Sdfr#include <sys/kernel.h>
37142833Siedowse#include <sys/malloc.h>
38129880Sphk#include <sys/module.h>
3948104Syokota#include <sys/conf.h>
4043105Sdfr#include <sys/bus.h>
4148104Syokota#include <sys/fbio.h>
4243105Sdfr
4348104Syokota#include <machine/bus.h>
4448104Syokota#include <machine/resource.h>
4548104Syokota
4648104Syokota#include <sys/rman.h>
4748104Syokota
4843105Sdfr#include <vm/vm.h>
4943105Sdfr#include <vm/pmap.h>
5043105Sdfr
5143105Sdfr#include <machine/md_var.h>
52114384Speter#ifdef __i386__
5343105Sdfr#include <machine/pc/bios.h>
54114384Speter#endif
5543105Sdfr
5643105Sdfr#include <dev/fb/fbreg.h>
5743105Sdfr#include <dev/fb/vgareg.h>
5843105Sdfr
5943105Sdfr#include <isa/isareg.h>
6043105Sdfr#include <isa/isavar.h>
6143105Sdfr
62199229Sjkimstatic void
63199229Sjkimvga_suspend(device_t dev)
64199229Sjkim{
65199229Sjkim	vga_softc_t *sc;
66199229Sjkim	int nbytes;
67199229Sjkim
68199229Sjkim	sc = device_get_softc(dev);
69199229Sjkim
70199229Sjkim	/* Save the video state across the suspend. */
71199229Sjkim	if (sc->state_buf != NULL)
72199229Sjkim		goto save_palette;
73199229Sjkim	nbytes = vidd_save_state(sc->adp, NULL, 0);
74199229Sjkim	if (nbytes <= 0)
75199229Sjkim		goto save_palette;
76199229Sjkim	sc->state_buf = malloc(nbytes, M_TEMP, M_NOWAIT);
77199229Sjkim	if (sc->state_buf == NULL)
78199229Sjkim		goto save_palette;
79199229Sjkim	if (bootverbose)
80199229Sjkim		device_printf(dev, "saving %d bytes of video state\n", nbytes);
81199229Sjkim	if (vidd_save_state(sc->adp, sc->state_buf, nbytes) != 0) {
82199229Sjkim		device_printf(dev, "failed to save state (nbytes=%d)\n",
83199229Sjkim		    nbytes);
84199229Sjkim		free(sc->state_buf, M_TEMP);
85199229Sjkim		sc->state_buf = NULL;
86199229Sjkim	}
87199229Sjkim
88199229Sjkimsave_palette:
89199229Sjkim	/* Save the color palette across the suspend. */
90199229Sjkim	if (sc->pal_buf != NULL)
91199229Sjkim		return;
92199229Sjkim	sc->pal_buf = malloc(256 * 3, M_TEMP, M_NOWAIT);
93199229Sjkim	if (sc->pal_buf == NULL)
94199229Sjkim		return;
95199229Sjkim	if (bootverbose)
96199229Sjkim		device_printf(dev, "saving color palette\n");
97199229Sjkim	if (vidd_save_palette(sc->adp, sc->pal_buf) != 0) {
98199229Sjkim		device_printf(dev, "failed to save palette\n");
99199229Sjkim		free(sc->pal_buf, M_TEMP);
100199229Sjkim		sc->pal_buf = NULL;
101199229Sjkim	}
102199229Sjkim}
103199229Sjkim
104199229Sjkimstatic void
105199229Sjkimvga_resume(device_t dev)
106199229Sjkim{
107199229Sjkim	vga_softc_t *sc;
108199229Sjkim
109199229Sjkim	sc = device_get_softc(dev);
110199229Sjkim
111199229Sjkim	if (sc->state_buf != NULL) {
112199229Sjkim		if (vidd_load_state(sc->adp, sc->state_buf) != 0)
113199229Sjkim			device_printf(dev, "failed to reload state\n");
114199229Sjkim		free(sc->state_buf, M_TEMP);
115199229Sjkim		sc->state_buf = NULL;
116199229Sjkim	}
117199229Sjkim	if (sc->pal_buf != NULL) {
118199229Sjkim		if (vidd_load_palette(sc->adp, sc->pal_buf) != 0)
119199229Sjkim			device_printf(dev, "failed to reload palette\n");
120199229Sjkim		free(sc->pal_buf, M_TEMP);
121199229Sjkim		sc->pal_buf = NULL;
122199229Sjkim	}
123199229Sjkim}
124199229Sjkim
12548104Syokota#define VGA_SOFTC(unit)		\
12648104Syokota	((vga_softc_t *)devclass_get_softc(isavga_devclass, unit))
12743105Sdfr
12848104Syokotastatic devclass_t	isavga_devclass;
12943105Sdfr
13043105Sdfr#ifdef FB_INSTALL_CDEV
13143105Sdfr
13248104Syokotastatic d_open_t		isavga_open;
13348104Syokotastatic d_close_t	isavga_close;
13448104Syokotastatic d_read_t		isavga_read;
13548104Syokotastatic d_write_t	isavga_write;
13648104Syokotastatic d_ioctl_t	isavga_ioctl;
13748104Syokotastatic d_mmap_t		isavga_mmap;
13843105Sdfr
13948104Syokotastatic struct cdevsw isavga_cdevsw = {
140126080Sphk	.d_version =	D_VERSION,
141126080Sphk	.d_flags =	D_NEEDGIANT,
142111815Sphk	.d_open =	isavga_open,
143111815Sphk	.d_close =	isavga_close,
144111815Sphk	.d_read =	isavga_read,
145111815Sphk	.d_write =	isavga_write,
146111815Sphk	.d_ioctl =	isavga_ioctl,
147111815Sphk	.d_mmap =	isavga_mmap,
148111815Sphk	.d_name =	VGA_DRIVER_NAME,
14943105Sdfr};
15043105Sdfr
15143105Sdfr#endif /* FB_INSTALL_CDEV */
15243105Sdfr
15362225Speterstatic void
15462225Speterisavga_identify(driver_t *driver, device_t parent)
15562225Speter{
15662225Speter	BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, VGA_DRIVER_NAME, 0);
15762225Speter}
15862225Speter
15943105Sdfrstatic int
16043105Sdfrisavga_probe(device_t dev)
16143105Sdfr{
16248104Syokota	video_adapter_t adp;
16348104Syokota	int error;
16443105Sdfr
16547618Sdfr	/* No pnp support */
16647618Sdfr	if (isa_get_vendorid(dev))
16747618Sdfr		return (ENXIO);
16847618Sdfr
16951052Sdfr	error = vga_probe_unit(device_get_unit(dev), &adp, device_get_flags(dev));
17048104Syokota	if (error == 0) {
171199229Sjkim		device_set_desc(dev, "Generic ISA VGA");
17252174Sdfr		bus_set_resource(dev, SYS_RES_IOPORT, 0,
17348104Syokota				 adp.va_io_base, adp.va_io_size);
17452174Sdfr		bus_set_resource(dev, SYS_RES_MEMORY, 0,
17548104Syokota				 adp.va_mem_base, adp.va_mem_size);
17648104Syokota#if 0
17748104Syokota		isa_set_port(dev, adp.va_io_base);
17848104Syokota		isa_set_portsize(dev, adp.va_io_size);
17948104Syokota		isa_set_maddr(dev, adp.va_mem_base);
18048104Syokota		isa_set_msize(dev, adp.va_mem_size);
18148104Syokota#endif
18248104Syokota	}
183199002Sjkim	return (error);
18443105Sdfr}
18543105Sdfr
18643105Sdfrstatic int
18743105Sdfrisavga_attach(device_t dev)
18843105Sdfr{
18948104Syokota	vga_softc_t *sc;
19048104Syokota	int unit;
19148104Syokota	int rid;
19248104Syokota	int error;
19343105Sdfr
19448104Syokota	unit = device_get_unit(dev);
19543105Sdfr	sc = device_get_softc(dev);
19643105Sdfr
19748104Syokota	rid = 0;
198295790Sjhibbits	bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
199295790Sjhibbits				  RF_ACTIVE | RF_SHAREABLE);
20048104Syokota	rid = 0;
201295790Sjhibbits	bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
202295790Sjhibbits				 RF_ACTIVE | RF_SHAREABLE);
20343105Sdfr
20451052Sdfr	error = vga_attach_unit(unit, sc, device_get_flags(dev));
20543105Sdfr	if (error)
206199002Sjkim		return (error);
20743105Sdfr
20843105Sdfr#ifdef FB_INSTALL_CDEV
20943105Sdfr	/* attach a virtual frame buffer device */
210120465Sphk	error = fb_attach(VGA_MKMINOR(unit), sc->adp, &isavga_cdevsw);
21143105Sdfr	if (error)
212199002Sjkim		return (error);
21343105Sdfr#endif /* FB_INSTALL_CDEV */
21443105Sdfr
215137148Sphk	if (0 && bootverbose)
216174985Swkoszek		vidd_diag(sc->adp, bootverbose);
21743105Sdfr
218153072Sru#if 0 /* experimental */
21954073Smdodd	device_add_child(dev, "fb", -1);
22048104Syokota	bus_generic_attach(dev);
22143105Sdfr#endif
22243105Sdfr
223199002Sjkim	return (0);
22443105Sdfr}
22543105Sdfr
226142833Siedowsestatic int
227142833Siedowseisavga_suspend(device_t dev)
228142833Siedowse{
229199229Sjkim	int error;
230142833Siedowse
231199229Sjkim	error = bus_generic_suspend(dev);
232199229Sjkim	if (error != 0)
233199229Sjkim		return (error);
234199229Sjkim	vga_suspend(dev);
235142833Siedowse
236199229Sjkim	return (error);
237142833Siedowse}
238142833Siedowse
239142833Siedowsestatic int
240142833Siedowseisavga_resume(device_t dev)
241142833Siedowse{
242142833Siedowse
243199229Sjkim	vga_resume(dev);
244198964Sjkim
245199229Sjkim	return (bus_generic_resume(dev));
246142833Siedowse}
247142833Siedowse
24848104Syokota#ifdef FB_INSTALL_CDEV
24943105Sdfr
25043105Sdfrstatic int
251130585Sphkisavga_open(struct cdev *dev, int flag, int mode, struct thread *td)
25243105Sdfr{
253199002Sjkim	return (vga_open(dev, VGA_SOFTC(VGA_UNIT(dev)), flag, mode, td));
25443105Sdfr}
25543105Sdfr
25643105Sdfrstatic int
257130585Sphkisavga_close(struct cdev *dev, int flag, int mode, struct thread *td)
25843105Sdfr{
259199002Sjkim	return (vga_close(dev, VGA_SOFTC(VGA_UNIT(dev)), flag, mode, td));
26043105Sdfr}
26143105Sdfr
26243105Sdfrstatic int
263130585Sphkisavga_read(struct cdev *dev, struct uio *uio, int flag)
26443105Sdfr{
265199002Sjkim	return (vga_read(dev, VGA_SOFTC(VGA_UNIT(dev)), uio, flag));
26643105Sdfr}
26743105Sdfr
26843105Sdfrstatic int
269130585Sphkisavga_write(struct cdev *dev, struct uio *uio, int flag)
27043105Sdfr{
271199002Sjkim	return (vga_write(dev, VGA_SOFTC(VGA_UNIT(dev)), uio, flag));
27243105Sdfr}
27343105Sdfr
27443105Sdfrstatic int
275130585Sphkisavga_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
27643105Sdfr{
277199002Sjkim	return (vga_ioctl(dev, VGA_SOFTC(VGA_UNIT(dev)), cmd, arg, flag, td));
27843105Sdfr}
27943105Sdfr
28043105Sdfrstatic int
281201223Srnolandisavga_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr,
282201223Srnoland    int prot, vm_memattr_t *memattr)
28343105Sdfr{
284201223Srnoland	return (vga_mmap(dev, VGA_SOFTC(VGA_UNIT(dev)), offset, paddr, prot,
285201223Srnoland	    memattr));
28643105Sdfr}
28743105Sdfr
28848104Syokota#endif /* FB_INSTALL_CDEV */
28962225Speter
29062225Speterstatic device_method_t isavga_methods[] = {
29162225Speter	DEVMETHOD(device_identify,	isavga_identify),
29262225Speter	DEVMETHOD(device_probe,		isavga_probe),
29362225Speter	DEVMETHOD(device_attach,	isavga_attach),
294142833Siedowse	DEVMETHOD(device_suspend,	isavga_suspend),
295142833Siedowse	DEVMETHOD(device_resume,	isavga_resume),
29662225Speter
297227843Smarius	DEVMETHOD_END
29862225Speter};
29962225Speter
30062225Speterstatic driver_t isavga_driver = {
30162225Speter	VGA_DRIVER_NAME,
30262225Speter	isavga_methods,
30362225Speter	sizeof(vga_softc_t),
30462225Speter};
30562225Speter
30662225SpeterDRIVER_MODULE(vga, isa, isavga_driver, isavga_devclass, 0, 0);
307199229Sjkim
308199229Sjkimstatic devclass_t	vgapm_devclass;
309199229Sjkim
310199229Sjkimstatic void
311199229Sjkimvgapm_identify(driver_t *driver, device_t parent)
312199229Sjkim{
313199229Sjkim
314199229Sjkim	if (device_get_flags(parent) != 0)
315199229Sjkim		device_add_child(parent, "vgapm", 0);
316199229Sjkim}
317199229Sjkim
318199229Sjkimstatic int
319199229Sjkimvgapm_probe(device_t dev)
320199229Sjkim{
321199229Sjkim
322199229Sjkim	device_set_desc(dev, "VGA suspend/resume");
323199229Sjkim	device_quiet(dev);
324199229Sjkim
325199229Sjkim	return (BUS_PROBE_DEFAULT);
326199229Sjkim}
327199229Sjkim
328199229Sjkimstatic int
329199229Sjkimvgapm_attach(device_t dev)
330199229Sjkim{
331199229Sjkim
332200584Sjkim	bus_generic_probe(dev);
333200584Sjkim	bus_generic_attach(dev);
334200584Sjkim
335199229Sjkim	return (0);
336199229Sjkim}
337199229Sjkim
338199229Sjkimstatic int
339199229Sjkimvgapm_suspend(device_t dev)
340199229Sjkim{
341199229Sjkim	device_t vga_dev;
342199229Sjkim	int error;
343199229Sjkim
344199229Sjkim	error = bus_generic_suspend(dev);
345199229Sjkim	if (error != 0)
346199229Sjkim		return (error);
347199229Sjkim	vga_dev = devclass_get_device(isavga_devclass, 0);
348199229Sjkim	if (vga_dev == NULL)
349199229Sjkim		return (0);
350199229Sjkim	vga_suspend(vga_dev);
351199229Sjkim
352199229Sjkim	return (0);
353199229Sjkim}
354199229Sjkim
355199229Sjkimstatic int
356199229Sjkimvgapm_resume(device_t dev)
357199229Sjkim{
358199229Sjkim	device_t vga_dev;
359199229Sjkim
360199229Sjkim	vga_dev = devclass_get_device(isavga_devclass, 0);
361199229Sjkim	if (vga_dev != NULL)
362199229Sjkim		vga_resume(vga_dev);
363199229Sjkim
364199229Sjkim	return (bus_generic_resume(dev));
365199229Sjkim}
366199229Sjkim
367199229Sjkimstatic device_method_t vgapm_methods[] = {
368199229Sjkim	DEVMETHOD(device_identify,	vgapm_identify),
369199229Sjkim	DEVMETHOD(device_probe,		vgapm_probe),
370199229Sjkim	DEVMETHOD(device_attach,	vgapm_attach),
371199229Sjkim	DEVMETHOD(device_suspend,	vgapm_suspend),
372199229Sjkim	DEVMETHOD(device_resume,	vgapm_resume),
373199229Sjkim	{ 0, 0 }
374199229Sjkim};
375199229Sjkim
376199229Sjkimstatic driver_t vgapm_driver = {
377199229Sjkim	"vgapm",
378199229Sjkim	vgapm_methods,
379199229Sjkim	0
380199229Sjkim};
381199229Sjkim
382199229SjkimDRIVER_MODULE(vgapm, vgapci, vgapm_driver, vgapm_devclass, 0, 0);
383