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 62 static void 63 vga_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 88 save_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 104 static void 105 vga_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 128 static devclass_t isavga_devclass; 129 130 #ifdef FB_INSTALL_CDEV 131 132 static d_open_t isavga_open; 133 static d_close_t isavga_close; 134 static d_read_t isavga_read; 135 static d_write_t isavga_write; 136 static d_ioctl_t isavga_ioctl; 137 static d_mmap_t isavga_mmap; 138 139 static 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 153 static void 154 isavga_identify(driver_t *driver, device_t parent) 155 { 156 BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, VGA_DRIVER_NAME, 0); 157 } 158 159 static int 160 isavga_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 186 static int 187 isavga_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 226 static int 227 isavga_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 239 static int 240 isavga_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 250 static int 251 isavga_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 256 static int 257 isavga_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 262 static int 263 isavga_read(struct cdev *dev, struct uio *uio, int flag) 264 { 265 return (vga_read(dev, VGA_SOFTC(VGA_UNIT(dev)), uio, flag)); 266 } 267 268 static int 269 isavga_write(struct cdev *dev, struct uio *uio, int flag) 270 { 271 return (vga_write(dev, VGA_SOFTC(VGA_UNIT(dev)), uio, flag)); 272 } 273 274 static int 275 isavga_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 280 static int 281 isavga_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 290 static 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 300 static driver_t isavga_driver = { 301 VGA_DRIVER_NAME, 302 isavga_methods, 303 sizeof(vga_softc_t), 304 }; 305 306 DRIVER_MODULE(vga, isa, isavga_driver, isavga_devclass, 0, 0); 307 308 static devclass_t vgapm_devclass; 309 310 static void 311 vgapm_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 318 static int 319 vgapm_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 328 static int 329 vgapm_attach(device_t dev) 330 { 331 332 bus_generic_probe(dev); 333 bus_generic_attach(dev); 334 335 return (0); 336 } 337 338 static int 339 vgapm_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 355 static int 356 vgapm_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 367 static 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 376 static driver_t vgapm_driver = { 377 "vgapm", 378 vgapm_methods, 379 0 380 }; 381 382 DRIVER_MODULE(vgapm, vgapci, vgapm_driver, vgapm_devclass, 0, 0); 383