1/*- 2 * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer as 10 * the first lines of this file unmodified. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD$"); 29 30#include "opt_vga.h" 31#include "opt_fb.h" 32#include "opt_syscons.h" /* should be removed in the future, XXX */ 33 34#include <sys/param.h> 35#include <sys/systm.h> 36#include <sys/kernel.h> 37#include <sys/malloc.h> 38#include <sys/module.h> 39#include <sys/conf.h> 40#include <sys/bus.h> 41#include <sys/fbio.h> 42 43#include <machine/bus.h> 44#include <machine/resource.h> 45 46#include <sys/rman.h> 47 48#include <vm/vm.h> 49#include <vm/pmap.h> 50 51#include <machine/md_var.h> 52#ifdef __i386__ 53#include <machine/pc/bios.h> 54#endif 55 56#include <dev/fb/fbreg.h> 57#include <dev/fb/vgareg.h> 58 59#include <isa/isareg.h> 60#include <isa/isavar.h> 61 62static void 63vga_suspend(device_t dev) 64{ 65 vga_softc_t *sc; 66 int nbytes; 67 68 sc = device_get_softc(dev); 69 70 /* Save the video state across the suspend. */ 71 if (sc->state_buf != NULL) 72 goto save_palette; 73 nbytes = vidd_save_state(sc->adp, NULL, 0); 74 if (nbytes <= 0) 75 goto save_palette; 76 sc->state_buf = malloc(nbytes, M_TEMP, M_NOWAIT); 77 if (sc->state_buf == NULL) 78 goto save_palette; 79 if (bootverbose) 80 device_printf(dev, "saving %d bytes of video state\n", nbytes); 81 if (vidd_save_state(sc->adp, sc->state_buf, nbytes) != 0) { 82 device_printf(dev, "failed to save state (nbytes=%d)\n", 83 nbytes); 84 free(sc->state_buf, M_TEMP); 85 sc->state_buf = NULL; 86 } 87 88save_palette: 89 /* Save the color palette across the suspend. */ 90 if (sc->pal_buf != NULL) 91 return; 92 sc->pal_buf = malloc(256 * 3, M_TEMP, M_NOWAIT); 93 if (sc->pal_buf == NULL) 94 return; 95 if (bootverbose) 96 device_printf(dev, "saving color palette\n"); 97 if (vidd_save_palette(sc->adp, sc->pal_buf) != 0) { 98 device_printf(dev, "failed to save palette\n"); 99 free(sc->pal_buf, M_TEMP); 100 sc->pal_buf = NULL; 101 } 102} 103 104static void 105vga_resume(device_t dev) 106{ 107 vga_softc_t *sc; 108 109 sc = device_get_softc(dev); 110 111 if (sc->state_buf != NULL) { 112 if (vidd_load_state(sc->adp, sc->state_buf) != 0) 113 device_printf(dev, "failed to reload state\n"); 114 free(sc->state_buf, M_TEMP); 115 sc->state_buf = NULL; 116 } 117 if (sc->pal_buf != NULL) { 118 if (vidd_load_palette(sc->adp, sc->pal_buf) != 0) 119 device_printf(dev, "failed to reload palette\n"); 120 free(sc->pal_buf, M_TEMP); 121 sc->pal_buf = NULL; 122 } 123} 124 125#define VGA_SOFTC(unit) \ 126 ((vga_softc_t *)devclass_get_softc(isavga_devclass, unit)) 127 128static devclass_t isavga_devclass; 129 130#ifdef FB_INSTALL_CDEV 131 132static d_open_t isavga_open; 133static d_close_t isavga_close; 134static d_read_t isavga_read; 135static d_write_t isavga_write; 136static d_ioctl_t isavga_ioctl; 137static d_mmap_t isavga_mmap; 138 139static struct cdevsw isavga_cdevsw = { 140 .d_version = D_VERSION, 141 .d_flags = D_NEEDGIANT, 142 .d_open = isavga_open, 143 .d_close = isavga_close, 144 .d_read = isavga_read, 145 .d_write = isavga_write, 146 .d_ioctl = isavga_ioctl, 147 .d_mmap = isavga_mmap, 148 .d_name = VGA_DRIVER_NAME, 149}; 150 151#endif /* FB_INSTALL_CDEV */ 152 153static void 154isavga_identify(driver_t *driver, device_t parent) 155{ 156 BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, VGA_DRIVER_NAME, 0); 157} 158 159static int 160isavga_probe(device_t dev) 161{ 162 video_adapter_t adp; 163 int error; 164 165 /* No pnp support */ 166 if (isa_get_vendorid(dev)) 167 return (ENXIO); 168 169 error = vga_probe_unit(device_get_unit(dev), &adp, device_get_flags(dev)); 170 if (error == 0) { 171 device_set_desc(dev, "Generic ISA VGA"); 172 bus_set_resource(dev, SYS_RES_IOPORT, 0, 173 adp.va_io_base, adp.va_io_size); 174 bus_set_resource(dev, SYS_RES_MEMORY, 0, 175 adp.va_mem_base, adp.va_mem_size); 176#if 0 177 isa_set_port(dev, adp.va_io_base); 178 isa_set_portsize(dev, adp.va_io_size); 179 isa_set_maddr(dev, adp.va_mem_base); 180 isa_set_msize(dev, adp.va_mem_size); 181#endif 182 } 183 return (error); 184} 185 186static int 187isavga_attach(device_t dev) 188{ 189 vga_softc_t *sc; 190 int unit; 191 int rid; 192 int error; 193 194 unit = device_get_unit(dev); 195 sc = device_get_softc(dev); 196 197 rid = 0; 198 bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, 199 RF_ACTIVE | RF_SHAREABLE); 200 rid = 0; 201 bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 202 RF_ACTIVE | RF_SHAREABLE); 203 204 error = vga_attach_unit(unit, sc, device_get_flags(dev)); 205 if (error) 206 return (error); 207 208#ifdef FB_INSTALL_CDEV 209 /* attach a virtual frame buffer device */ 210 error = fb_attach(VGA_MKMINOR(unit), sc->adp, &isavga_cdevsw); 211 if (error) 212 return (error); 213#endif /* FB_INSTALL_CDEV */ 214 215 if (0 && bootverbose) 216 vidd_diag(sc->adp, bootverbose); 217 218#if 0 /* experimental */ 219 device_add_child(dev, "fb", -1); 220 bus_generic_attach(dev); 221#endif 222 223 return (0); 224} 225 226static int 227isavga_suspend(device_t dev) 228{ 229 int error; 230 231 error = bus_generic_suspend(dev); 232 if (error != 0) 233 return (error); 234 vga_suspend(dev); 235 236 return (error); 237} 238 239static int 240isavga_resume(device_t dev) 241{ 242 243 vga_resume(dev); 244 245 return (bus_generic_resume(dev)); 246} 247 248#ifdef FB_INSTALL_CDEV 249 250static int 251isavga_open(struct cdev *dev, int flag, int mode, struct thread *td) 252{ 253 return (vga_open(dev, VGA_SOFTC(VGA_UNIT(dev)), flag, mode, td)); 254} 255 256static int 257isavga_close(struct cdev *dev, int flag, int mode, struct thread *td) 258{ 259 return (vga_close(dev, VGA_SOFTC(VGA_UNIT(dev)), flag, mode, td)); 260} 261 262static int 263isavga_read(struct cdev *dev, struct uio *uio, int flag) 264{ 265 return (vga_read(dev, VGA_SOFTC(VGA_UNIT(dev)), uio, flag)); 266} 267 268static int 269isavga_write(struct cdev *dev, struct uio *uio, int flag) 270{ 271 return (vga_write(dev, VGA_SOFTC(VGA_UNIT(dev)), uio, flag)); 272} 273 274static int 275isavga_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 276{ 277 return (vga_ioctl(dev, VGA_SOFTC(VGA_UNIT(dev)), cmd, arg, flag, td)); 278} 279 280static int 281isavga_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, 282 int prot, vm_memattr_t *memattr) 283{ 284 return (vga_mmap(dev, VGA_SOFTC(VGA_UNIT(dev)), offset, paddr, prot, 285 memattr)); 286} 287 288#endif /* FB_INSTALL_CDEV */ 289 290static device_method_t isavga_methods[] = { 291 DEVMETHOD(device_identify, isavga_identify), 292 DEVMETHOD(device_probe, isavga_probe), 293 DEVMETHOD(device_attach, isavga_attach), 294 DEVMETHOD(device_suspend, isavga_suspend), 295 DEVMETHOD(device_resume, isavga_resume), 296 297 DEVMETHOD_END 298}; 299 300static driver_t isavga_driver = { 301 VGA_DRIVER_NAME, 302 isavga_methods, 303 sizeof(vga_softc_t), 304}; 305 306DRIVER_MODULE(vga, isa, isavga_driver, isavga_devclass, 0, 0); 307 308static devclass_t vgapm_devclass; 309 310static void 311vgapm_identify(driver_t *driver, device_t parent) 312{ 313 314 if (device_get_flags(parent) != 0) 315 device_add_child(parent, "vgapm", 0); 316} 317 318static int 319vgapm_probe(device_t dev) 320{ 321 322 device_set_desc(dev, "VGA suspend/resume"); 323 device_quiet(dev); 324 325 return (BUS_PROBE_DEFAULT); 326} 327 328static int 329vgapm_attach(device_t dev) 330{ 331 332 bus_generic_probe(dev); 333 bus_generic_attach(dev); 334 335 return (0); 336} 337 338static int 339vgapm_suspend(device_t dev) 340{ 341 device_t vga_dev; 342 int error; 343 344 error = bus_generic_suspend(dev); 345 if (error != 0) 346 return (error); 347 vga_dev = devclass_get_device(isavga_devclass, 0); 348 if (vga_dev == NULL) 349 return (0); 350 vga_suspend(vga_dev); 351 352 return (0); 353} 354 355static int 356vgapm_resume(device_t dev) 357{ 358 device_t vga_dev; 359 360 vga_dev = devclass_get_device(isavga_devclass, 0); 361 if (vga_dev != NULL) 362 vga_resume(vga_dev); 363 364 return (bus_generic_resume(dev)); 365} 366 367static device_method_t vgapm_methods[] = { 368 DEVMETHOD(device_identify, vgapm_identify), 369 DEVMETHOD(device_probe, vgapm_probe), 370 DEVMETHOD(device_attach, vgapm_attach), 371 DEVMETHOD(device_suspend, vgapm_suspend), 372 DEVMETHOD(device_resume, vgapm_resume), 373 { 0, 0 } 374}; 375 376static driver_t vgapm_driver = { 377 "vgapm", 378 vgapm_methods, 379 0 380}; 381 382DRIVER_MODULE(vgapm, vgapci, vgapm_driver, vgapm_devclass, 0, 0); 383