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