1 /* $OpenBSD: pcdisplay.c,v 1.4 2001/02/02 20:25:40 aaron Exp $ */ 2 /* $NetBSD: pcdisplay.c,v 1.9.4.1 2000/06/30 16:27:48 simonb Exp $ */ 3 4 /* 5 * Copyright (c) 1998 6 * Matthias Drochner. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed for the NetBSD Project 19 * by Matthias Drochner. 20 * 4. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 * 34 */ 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/kernel.h> 39 #include <sys/device.h> 40 #include <sys/malloc.h> 41 #include <machine/bus.h> 42 43 #include <dev/isa/isavar.h> 44 #include <dev/isa/isareg.h> 45 46 #include <dev/ic/mc6845reg.h> 47 #include <dev/ic/pcdisplayvar.h> 48 #include <dev/isa/pcdisplayvar.h> 49 50 #include <dev/ic/pcdisplay.h> 51 52 #include <dev/wscons/wsconsio.h> 53 #include <dev/wscons/wsdisplayvar.h> 54 55 struct pcdisplay_config { 56 struct pcdisplayscreen pcs; 57 struct pcdisplay_handle dc_ph; 58 int mono; 59 }; 60 61 struct pcdisplay_softc { 62 struct device sc_dev; 63 struct pcdisplay_config *sc_dc; 64 int nscreens; 65 }; 66 67 static int pcdisplayconsole, pcdisplay_console_attached; 68 static struct pcdisplay_config pcdisplay_console_dc; 69 70 int pcdisplay_match __P((struct device *, void *, void *)); 71 void pcdisplay_attach __P((struct device *, struct device *, void *)); 72 73 static int pcdisplay_is_console __P((bus_space_tag_t)); 74 static int pcdisplay_probe_col __P((bus_space_tag_t, bus_space_tag_t)); 75 static int pcdisplay_probe_mono __P((bus_space_tag_t, bus_space_tag_t)); 76 static void pcdisplay_init __P((struct pcdisplay_config *, 77 bus_space_tag_t, bus_space_tag_t, 78 int)); 79 static int pcdisplay_alloc_attr __P((void *, int, int, int, long *)); 80 81 struct cfattach pcdisplay_ca = { 82 sizeof(struct pcdisplay_softc), pcdisplay_match, pcdisplay_attach, 83 }; 84 85 const struct wsdisplay_emulops pcdisplay_emulops = { 86 pcdisplay_cursor, 87 pcdisplay_mapchar, 88 pcdisplay_putchar, 89 pcdisplay_copycols, 90 pcdisplay_erasecols, 91 pcdisplay_copyrows, 92 pcdisplay_eraserows, 93 pcdisplay_alloc_attr 94 }; 95 96 const struct wsscreen_descr pcdisplay_scr = { 97 "80x25", 80, 25, 98 &pcdisplay_emulops, 99 0, 0, /* no font support */ 100 WSSCREEN_REVERSE /* that's minimal... */ 101 }; 102 103 const struct wsscreen_descr *_pcdisplay_scrlist[] = { 104 &pcdisplay_scr, 105 }; 106 107 const struct wsscreen_list pcdisplay_screenlist = { 108 sizeof(_pcdisplay_scrlist) / sizeof(struct wsscreen_descr *), 109 _pcdisplay_scrlist 110 }; 111 112 static int pcdisplay_ioctl __P((void *, u_long, caddr_t, int, struct proc *)); 113 static paddr_t pcdisplay_mmap __P((void *, off_t, int)); 114 static int pcdisplay_alloc_screen __P((void *, const struct wsscreen_descr *, 115 void **, int *, int *, long *)); 116 static void pcdisplay_free_screen __P((void *, void *)); 117 static int pcdisplay_show_screen __P((void *, void *, int, 118 void (*) (void *, int, int), void *)); 119 120 const struct wsdisplay_accessops pcdisplay_accessops = { 121 pcdisplay_ioctl, 122 pcdisplay_mmap, 123 pcdisplay_alloc_screen, 124 pcdisplay_free_screen, 125 pcdisplay_show_screen, 126 0 /* load_font */ 127 }; 128 129 static int 130 pcdisplay_probe_col(iot, memt) 131 bus_space_tag_t iot, memt; 132 { 133 bus_space_handle_t memh, ioh_6845; 134 u_int16_t oldval, val; 135 136 if (bus_space_map(memt, 0xb8000, 0x8000, 0, &memh)) 137 return (0); 138 oldval = bus_space_read_2(memt, memh, 0); 139 bus_space_write_2(memt, memh, 0, 0xa55a); 140 val = bus_space_read_2(memt, memh, 0); 141 bus_space_write_2(memt, memh, 0, oldval); 142 bus_space_unmap(memt, memh, 0x8000); 143 if (val != 0xa55a) 144 return (0); 145 146 if (bus_space_map(iot, 0x3d0, 0x10, 0, &ioh_6845)) 147 return (0); 148 bus_space_unmap(iot, ioh_6845, 0x10); 149 150 return (1); 151 } 152 153 static int 154 pcdisplay_probe_mono(iot, memt) 155 bus_space_tag_t iot, memt; 156 { 157 bus_space_handle_t memh, ioh_6845; 158 u_int16_t oldval, val; 159 160 if (bus_space_map(memt, 0xb0000, 0x8000, 0, &memh)) 161 return (0); 162 oldval = bus_space_read_2(memt, memh, 0); 163 bus_space_write_2(memt, memh, 0, 0xa55a); 164 val = bus_space_read_2(memt, memh, 0); 165 bus_space_write_2(memt, memh, 0, oldval); 166 bus_space_unmap(memt, memh, 0x8000); 167 if (val != 0xa55a) 168 return (0); 169 170 if (bus_space_map(iot, 0x3b0, 0x10, 0, &ioh_6845)) 171 return (0); 172 bus_space_unmap(iot, ioh_6845, 0x10); 173 174 return (1); 175 } 176 177 static void 178 pcdisplay_init(dc, iot, memt, mono) 179 struct pcdisplay_config *dc; 180 bus_space_tag_t iot, memt; 181 int mono; 182 { 183 struct pcdisplay_handle *ph = &dc->dc_ph; 184 int cpos; 185 186 ph->ph_iot = iot; 187 ph->ph_memt = memt; 188 dc->mono = mono; 189 190 if (bus_space_map(memt, mono ? 0xb0000 : 0xb8000, 0x8000, 191 0, &ph->ph_memh)) 192 panic("pcdisplay_init: cannot map memory"); 193 if (bus_space_map(iot, mono ? 0x3b0 : 0x3d0, 0x10, 194 0, &ph->ph_ioh_6845)) 195 panic("pcdisplay_init: cannot map io"); 196 197 /* 198 * initialize the only screen 199 */ 200 dc->pcs.hdl = ph; 201 dc->pcs.type = &pcdisplay_scr; 202 dc->pcs.active = 1; 203 dc->pcs.mem = NULL; 204 205 cpos = pcdisplay_6845_read(ph, cursorh) << 8; 206 cpos |= pcdisplay_6845_read(ph, cursorl); 207 208 /* make sure we have a valid cursor position */ 209 if (cpos < 0 || cpos >= pcdisplay_scr.nrows * pcdisplay_scr.ncols) 210 cpos = 0; 211 212 dc->pcs.dispoffset = 0; 213 dc->pcs.visibleoffset = 0; 214 215 dc->pcs.vc_crow = cpos / pcdisplay_scr.ncols; 216 dc->pcs.vc_ccol = cpos % pcdisplay_scr.ncols; 217 pcdisplay_cursor_init(&dc->pcs, 1); 218 } 219 220 int 221 pcdisplay_match(parent, match, aux) 222 struct device *parent; 223 void *match; 224 void *aux; 225 { 226 struct isa_attach_args *ia = aux; 227 int mono; 228 229 /* If values are hardwired to something that they can't be, punt. */ 230 if ((ia->ia_iobase != IOBASEUNK && 231 ia->ia_iobase != 0x3d0 && 232 ia->ia_iobase != 0x3b0) || 233 /* ia->ia_iosize != 0 || XXX isa.c */ 234 (ia->ia_maddr != MADDRUNK && 235 ia->ia_maddr != 0xb8000 && 236 ia->ia_maddr != 0xb0000) || 237 (ia->ia_msize != 0 && ia->ia_msize != 0x8000) || 238 ia->ia_irq != IRQUNK || ia->ia_drq != DRQUNK) 239 return (0); 240 241 if (pcdisplay_is_console(ia->ia_iot)) 242 mono = pcdisplay_console_dc.mono; 243 else if (ia->ia_iobase != 0x3b0 && ia->ia_maddr != 0xb0000 && 244 pcdisplay_probe_col(ia->ia_iot, ia->ia_memt)) 245 mono = 0; 246 else if (ia->ia_iobase != 0x3d0 && ia->ia_maddr != 0xb8000 && 247 pcdisplay_probe_mono(ia->ia_iot, ia->ia_memt)) 248 mono = 1; 249 else 250 return (0); 251 252 ia->ia_iobase = mono ? 0x3b0 : 0x3d0; 253 ia->ia_iosize = 0x10; 254 ia->ia_maddr = mono ? 0xb0000 : 0xb8000; 255 ia->ia_msize = 0x8000; 256 return (1); 257 } 258 259 void 260 pcdisplay_attach(parent, self, aux) 261 struct device *parent, *self; 262 void *aux; 263 { 264 struct isa_attach_args *ia = aux; 265 struct pcdisplay_softc *sc = (struct pcdisplay_softc *)self; 266 int console; 267 struct pcdisplay_config *dc; 268 struct wsemuldisplaydev_attach_args aa; 269 270 printf("\n"); 271 272 console = pcdisplay_is_console(ia->ia_iot); 273 274 if (console) { 275 dc = &pcdisplay_console_dc; 276 sc->nscreens = 1; 277 pcdisplay_console_attached = 1; 278 } else { 279 dc = malloc(sizeof(struct pcdisplay_config), 280 M_DEVBUF, M_WAITOK); 281 if (ia->ia_iobase != 0x3b0 && ia->ia_maddr != 0xb0000 && 282 pcdisplay_probe_col(ia->ia_iot, ia->ia_memt)) 283 pcdisplay_init(dc, ia->ia_iot, ia->ia_memt, 0); 284 else if (ia->ia_iobase != 0x3d0 && ia->ia_maddr != 0xb8000 && 285 pcdisplay_probe_mono(ia->ia_iot, ia->ia_memt)) 286 pcdisplay_init(dc, ia->ia_iot, ia->ia_memt, 1); 287 else 288 panic("pcdisplay_attach: display disappeared"); 289 } 290 sc->sc_dc = dc; 291 292 aa.console = console; 293 aa.scrdata = &pcdisplay_screenlist; 294 aa.accessops = &pcdisplay_accessops; 295 aa.accesscookie = sc; 296 297 config_found(self, &aa, wsemuldisplaydevprint); 298 } 299 300 301 int 302 pcdisplay_cnattach(iot, memt) 303 bus_space_tag_t iot, memt; 304 { 305 int mono; 306 307 if (pcdisplay_probe_col(iot, memt)) 308 mono = 0; 309 else if (pcdisplay_probe_mono(iot, memt)) 310 mono = 1; 311 else 312 return (ENXIO); 313 314 pcdisplay_init(&pcdisplay_console_dc, iot, memt, mono); 315 316 wsdisplay_cnattach(&pcdisplay_scr, &pcdisplay_console_dc, 317 pcdisplay_console_dc.pcs.vc_ccol, 318 pcdisplay_console_dc.pcs.vc_crow, 319 FG_LIGHTGREY | BG_BLACK); 320 321 pcdisplayconsole = 1; 322 return (0); 323 } 324 325 static int 326 pcdisplay_is_console(iot) 327 bus_space_tag_t iot; 328 { 329 if (pcdisplayconsole && 330 !pcdisplay_console_attached && 331 iot == pcdisplay_console_dc.dc_ph.ph_iot) 332 return (1); 333 return (0); 334 } 335 336 static int 337 pcdisplay_ioctl(v, cmd, data, flag, p) 338 void *v; 339 u_long cmd; 340 caddr_t data; 341 int flag; 342 struct proc *p; 343 { 344 /* 345 * XXX "do something!" 346 */ 347 return (-1); 348 } 349 350 static paddr_t 351 pcdisplay_mmap(v, offset, prot) 352 void *v; 353 off_t offset; 354 int prot; 355 { 356 return (-1); 357 } 358 359 static int 360 pcdisplay_alloc_screen(v, type, cookiep, curxp, curyp, defattrp) 361 void *v; 362 const struct wsscreen_descr *type; 363 void **cookiep; 364 int *curxp, *curyp; 365 long *defattrp; 366 { 367 struct pcdisplay_softc *sc = v; 368 369 if (sc->nscreens > 0) 370 return (ENOMEM); 371 372 *cookiep = sc->sc_dc; 373 *curxp = 0; 374 *curyp = 0; 375 *defattrp = FG_LIGHTGREY | BG_BLACK; 376 sc->nscreens++; 377 return (0); 378 } 379 380 static void 381 pcdisplay_free_screen(v, cookie) 382 void *v; 383 void *cookie; 384 { 385 struct pcdisplay_softc *sc = v; 386 387 if (sc->sc_dc == &pcdisplay_console_dc) 388 panic("pcdisplay_free_screen: console"); 389 390 sc->nscreens--; 391 } 392 393 static int 394 pcdisplay_show_screen(v, cookie, waitok, cb, cbarg) 395 void *v; 396 void *cookie; 397 int waitok; 398 void (*cb) __P((void *, int, int)); 399 void *cbarg; 400 { 401 #ifdef DIAGNOSTIC 402 struct pcdisplay_softc *sc = v; 403 404 if (cookie != sc->sc_dc) 405 panic("pcdisplay_show_screen: bad screen"); 406 #endif 407 return (0); 408 } 409 410 static int 411 pcdisplay_alloc_attr(id, fg, bg, flags, attrp) 412 void *id; 413 int fg, bg; 414 int flags; 415 long *attrp; 416 { 417 if (flags & WSATTR_REVERSE) 418 *attrp = FG_BLACK | BG_LIGHTGREY; 419 else 420 *attrp = FG_LIGHTGREY | BG_BLACK; 421 return (0); 422 } 423 424 struct cfdriver pcdisplay_cd = { 425 NULL, "pcdisplay", DV_DULL 426 }; 427