1 /* $NetBSD: pcdisplay.c,v 1.17 2002/03/17 19:40:59 atatat 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/cdefs.h> 36 __KERNEL_RCSID(0, "$NetBSD: pcdisplay.c,v 1.17 2002/03/17 19:40:59 atatat Exp $"); 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/kernel.h> 41 #include <sys/device.h> 42 #include <sys/malloc.h> 43 #include <machine/bus.h> 44 45 #include <dev/isa/isavar.h> 46 47 #include <dev/ic/mc6845reg.h> 48 #include <dev/ic/pcdisplayvar.h> 49 #include <dev/isa/pcdisplayvar.h> 50 51 #include <dev/ic/pcdisplay.h> 52 53 #include <dev/wscons/wsconsio.h> 54 #include <dev/wscons/wsdisplayvar.h> 55 56 #include "pcweasel.h" 57 #if NPCWEASEL > 0 58 #include <dev/isa/weaselreg.h> 59 #include <dev/isa/weaselvar.h> 60 #endif 61 62 struct pcdisplay_config { 63 struct pcdisplayscreen pcs; 64 struct pcdisplay_handle dc_ph; 65 int mono; 66 }; 67 68 struct pcdisplay_softc { 69 struct device sc_dev; 70 struct pcdisplay_config *sc_dc; 71 int nscreens; 72 #if NPCWEASEL > 0 73 struct weasel_handle sc_weasel; 74 #endif 75 }; 76 77 static int pcdisplayconsole, pcdisplay_console_attached; 78 static struct pcdisplay_config pcdisplay_console_dc; 79 80 int pcdisplay_match __P((struct device *, struct cfdata *, void *)); 81 void pcdisplay_attach __P((struct device *, struct device *, void *)); 82 83 static int pcdisplay_is_console __P((bus_space_tag_t)); 84 static int pcdisplay_probe_col __P((bus_space_tag_t, bus_space_tag_t)); 85 static int pcdisplay_probe_mono __P((bus_space_tag_t, bus_space_tag_t)); 86 static void pcdisplay_init __P((struct pcdisplay_config *, 87 bus_space_tag_t, bus_space_tag_t, 88 int)); 89 static int pcdisplay_alloc_attr __P((void *, int, int, int, long *)); 90 91 struct cfattach pcdisplay_ca = { 92 sizeof(struct pcdisplay_softc), pcdisplay_match, pcdisplay_attach, 93 }; 94 95 const struct wsdisplay_emulops pcdisplay_emulops = { 96 pcdisplay_cursor, 97 pcdisplay_mapchar, 98 pcdisplay_putchar, 99 pcdisplay_copycols, 100 pcdisplay_erasecols, 101 pcdisplay_copyrows, 102 pcdisplay_eraserows, 103 pcdisplay_alloc_attr 104 }; 105 106 const struct wsscreen_descr pcdisplay_scr = { 107 "80x25", 80, 25, 108 &pcdisplay_emulops, 109 0, 0, /* no font support */ 110 WSSCREEN_REVERSE /* that's minimal... */ 111 }; 112 113 const struct wsscreen_descr *_pcdisplay_scrlist[] = { 114 &pcdisplay_scr, 115 }; 116 117 const struct wsscreen_list pcdisplay_screenlist = { 118 sizeof(_pcdisplay_scrlist) / sizeof(struct wsscreen_descr *), 119 _pcdisplay_scrlist 120 }; 121 122 static int pcdisplay_ioctl __P((void *, u_long, caddr_t, int, struct proc *)); 123 static paddr_t pcdisplay_mmap __P((void *, off_t, int)); 124 static int pcdisplay_alloc_screen __P((void *, const struct wsscreen_descr *, 125 void **, int *, int *, long *)); 126 static void pcdisplay_free_screen __P((void *, void *)); 127 static int pcdisplay_show_screen __P((void *, void *, int, 128 void (*) (void *, int, int), void *)); 129 130 const struct wsdisplay_accessops pcdisplay_accessops = { 131 pcdisplay_ioctl, 132 pcdisplay_mmap, 133 pcdisplay_alloc_screen, 134 pcdisplay_free_screen, 135 pcdisplay_show_screen, 136 0 /* load_font */ 137 }; 138 139 static int 140 pcdisplay_probe_col(iot, memt) 141 bus_space_tag_t iot, memt; 142 { 143 bus_space_handle_t memh, ioh_6845; 144 u_int16_t oldval, val; 145 146 if (bus_space_map(memt, 0xb8000, 0x8000, 0, &memh)) 147 return (0); 148 oldval = bus_space_read_2(memt, memh, 0); 149 bus_space_write_2(memt, memh, 0, 0xa55a); 150 val = bus_space_read_2(memt, memh, 0); 151 bus_space_write_2(memt, memh, 0, oldval); 152 bus_space_unmap(memt, memh, 0x8000); 153 if (val != 0xa55a) 154 return (0); 155 156 if (bus_space_map(iot, 0x3d0, 0x10, 0, &ioh_6845)) 157 return (0); 158 bus_space_unmap(iot, ioh_6845, 0x10); 159 160 return (1); 161 } 162 163 static int 164 pcdisplay_probe_mono(iot, memt) 165 bus_space_tag_t iot, memt; 166 { 167 bus_space_handle_t memh, ioh_6845; 168 u_int16_t oldval, val; 169 170 if (bus_space_map(memt, 0xb0000, 0x8000, 0, &memh)) 171 return (0); 172 oldval = bus_space_read_2(memt, memh, 0); 173 bus_space_write_2(memt, memh, 0, 0xa55a); 174 val = bus_space_read_2(memt, memh, 0); 175 bus_space_write_2(memt, memh, 0, oldval); 176 bus_space_unmap(memt, memh, 0x8000); 177 if (val != 0xa55a) 178 return (0); 179 180 if (bus_space_map(iot, 0x3b0, 0x10, 0, &ioh_6845)) 181 return (0); 182 bus_space_unmap(iot, ioh_6845, 0x10); 183 184 return (1); 185 } 186 187 static void 188 pcdisplay_init(dc, iot, memt, mono) 189 struct pcdisplay_config *dc; 190 bus_space_tag_t iot, memt; 191 int mono; 192 { 193 struct pcdisplay_handle *ph = &dc->dc_ph; 194 int cpos; 195 196 ph->ph_iot = iot; 197 ph->ph_memt = memt; 198 dc->mono = mono; 199 200 if (bus_space_map(memt, mono ? 0xb0000 : 0xb8000, 0x8000, 201 0, &ph->ph_memh)) 202 panic("pcdisplay_init: cannot map memory"); 203 if (bus_space_map(iot, mono ? 0x3b0 : 0x3d0, 0x10, 204 0, &ph->ph_ioh_6845)) 205 panic("pcdisplay_init: cannot map io"); 206 207 /* 208 * initialize the only screen 209 */ 210 dc->pcs.hdl = ph; 211 dc->pcs.type = &pcdisplay_scr; 212 dc->pcs.active = 1; 213 dc->pcs.mem = NULL; 214 215 cpos = pcdisplay_6845_read(ph, cursorh) << 8; 216 cpos |= pcdisplay_6845_read(ph, cursorl); 217 218 /* make sure we have a valid cursor position */ 219 if (cpos < 0 || cpos >= pcdisplay_scr.nrows * pcdisplay_scr.ncols) 220 cpos = 0; 221 222 dc->pcs.dispoffset = 0; 223 224 dc->pcs.vc_crow = cpos / pcdisplay_scr.ncols; 225 dc->pcs.vc_ccol = cpos % pcdisplay_scr.ncols; 226 pcdisplay_cursor_init(&dc->pcs, 1); 227 } 228 229 int 230 pcdisplay_match(parent, match, aux) 231 struct device *parent; 232 struct cfdata *match; 233 void *aux; 234 { 235 struct isa_attach_args *ia = aux; 236 int mono; 237 238 if (ISA_DIRECT_CONFIG(ia)) 239 return (0); 240 241 /* If values are hardwired to something that they can't be, punt. */ 242 if (ia->ia_nio < 1 || 243 (ia->ia_io[0].ir_addr != ISACF_PORT_DEFAULT && 244 ia->ia_io[0].ir_addr != 0x3d0 && 245 ia->ia_io[0].ir_addr != 0x3b0)) 246 return (0); 247 248 if (ia->ia_niomem < 1 || 249 (ia->ia_iomem[0].ir_addr != ISACF_IOMEM_DEFAULT && 250 ia->ia_iomem[0].ir_addr != 0xb8000 && 251 ia->ia_iomem[0].ir_addr != 0xb0000)) 252 return (0); 253 if (ia->ia_iomem[0].ir_size != 0 && 254 ia->ia_iomem[0].ir_size != 0x8000) 255 return (0); 256 257 if (ia->ia_nirq > 0 && 258 ia->ia_irq[0].ir_irq != ISACF_IRQ_DEFAULT) 259 return (0); 260 261 if (ia->ia_ndrq > 0 && 262 ia->ia_drq[0].ir_drq != ISACF_DRQ_DEFAULT) 263 return (0); 264 265 if (pcdisplay_is_console(ia->ia_iot)) 266 mono = pcdisplay_console_dc.mono; 267 else if (ia->ia_io[0].ir_addr != 0x3b0 && 268 ia->ia_iomem[0].ir_addr != 0xb0000 && 269 pcdisplay_probe_col(ia->ia_iot, ia->ia_memt)) 270 mono = 0; 271 else if (ia->ia_io[0].ir_addr != 0x3d0 && 272 ia->ia_iomem[0].ir_addr != 0xb8000 && 273 pcdisplay_probe_mono(ia->ia_iot, ia->ia_memt)) 274 mono = 1; 275 else 276 return (0); 277 278 ia->ia_nio = 1; 279 ia->ia_io[0].ir_addr = mono ? 0x3b0 : 0x3d0; 280 ia->ia_io[0].ir_size = 0x10; 281 282 ia->ia_niomem = 1; 283 ia->ia_iomem[0].ir_size = mono ? 0xb0000 : 0xb8000; 284 ia->ia_iomem[0].ir_size = 0x8000; 285 286 ia->ia_nirq = 0; 287 ia->ia_ndrq = 0; 288 289 return (1); 290 } 291 292 void 293 pcdisplay_attach(parent, self, aux) 294 struct device *parent, *self; 295 void *aux; 296 { 297 struct isa_attach_args *ia = aux; 298 struct pcdisplay_softc *sc = (struct pcdisplay_softc *)self; 299 int console; 300 struct pcdisplay_config *dc; 301 struct wsemuldisplaydev_attach_args aa; 302 303 printf("\n"); 304 305 console = pcdisplay_is_console(ia->ia_iot); 306 307 if (console) { 308 dc = &pcdisplay_console_dc; 309 sc->nscreens = 1; 310 pcdisplay_console_attached = 1; 311 } else { 312 dc = malloc(sizeof(struct pcdisplay_config), 313 M_DEVBUF, M_WAITOK); 314 if (ia->ia_io[0].ir_addr != 0x3b0 && 315 ia->ia_iomem[0].ir_addr != 0xb0000 && 316 pcdisplay_probe_col(ia->ia_iot, ia->ia_memt)) 317 pcdisplay_init(dc, ia->ia_iot, ia->ia_memt, 0); 318 else if (ia->ia_io[0].ir_addr != 0x3d0 && 319 ia->ia_iomem[0].ir_addr != 0xb8000 && 320 pcdisplay_probe_mono(ia->ia_iot, ia->ia_memt)) 321 pcdisplay_init(dc, ia->ia_iot, ia->ia_memt, 1); 322 else 323 panic("pcdisplay_attach: display disappeared"); 324 } 325 sc->sc_dc = dc; 326 327 #if NPCWEASEL > 0 328 /* 329 * If the display is monochrome, check to see if we have 330 * a PC-Weasel, and initialize its special features. 331 */ 332 if (dc->mono) { 333 sc->sc_weasel.wh_st = dc->dc_ph.ph_memt; 334 sc->sc_weasel.wh_sh = dc->dc_ph.ph_memh; 335 sc->sc_weasel.wh_parent = &sc->sc_dev; 336 weasel_isa_init(&sc->sc_weasel); 337 } 338 #endif /* NPCWEASEL > 0 */ 339 340 aa.console = console; 341 aa.scrdata = &pcdisplay_screenlist; 342 aa.accessops = &pcdisplay_accessops; 343 aa.accesscookie = sc; 344 345 config_found(self, &aa, wsemuldisplaydevprint); 346 } 347 348 349 int 350 pcdisplay_cnattach(iot, memt) 351 bus_space_tag_t iot, memt; 352 { 353 int mono; 354 355 if (pcdisplay_probe_col(iot, memt)) 356 mono = 0; 357 else if (pcdisplay_probe_mono(iot, memt)) 358 mono = 1; 359 else 360 return (ENXIO); 361 362 pcdisplay_init(&pcdisplay_console_dc, iot, memt, mono); 363 364 wsdisplay_cnattach(&pcdisplay_scr, &pcdisplay_console_dc, 365 pcdisplay_console_dc.pcs.vc_ccol, 366 pcdisplay_console_dc.pcs.vc_crow, 367 FG_LIGHTGREY | BG_BLACK); 368 369 pcdisplayconsole = 1; 370 return (0); 371 } 372 373 static int 374 pcdisplay_is_console(iot) 375 bus_space_tag_t iot; 376 { 377 if (pcdisplayconsole && 378 !pcdisplay_console_attached && 379 iot == pcdisplay_console_dc.dc_ph.ph_iot) 380 return (1); 381 return (0); 382 } 383 384 static int 385 pcdisplay_ioctl(v, cmd, data, flag, p) 386 void *v; 387 u_long cmd; 388 caddr_t data; 389 int flag; 390 struct proc *p; 391 { 392 /* 393 * XXX "do something!" 394 */ 395 return (EPASSTHROUGH); 396 } 397 398 static paddr_t 399 pcdisplay_mmap(v, offset, prot) 400 void *v; 401 off_t offset; 402 int prot; 403 { 404 return (-1); 405 } 406 407 static int 408 pcdisplay_alloc_screen(v, type, cookiep, curxp, curyp, defattrp) 409 void *v; 410 const struct wsscreen_descr *type; 411 void **cookiep; 412 int *curxp, *curyp; 413 long *defattrp; 414 { 415 struct pcdisplay_softc *sc = v; 416 417 if (sc->nscreens > 0) 418 return (ENOMEM); 419 420 *cookiep = sc->sc_dc; 421 *curxp = 0; 422 *curyp = 0; 423 *defattrp = FG_LIGHTGREY | BG_BLACK; 424 sc->nscreens++; 425 return (0); 426 } 427 428 static void 429 pcdisplay_free_screen(v, cookie) 430 void *v; 431 void *cookie; 432 { 433 struct pcdisplay_softc *sc = v; 434 435 if (sc->sc_dc == &pcdisplay_console_dc) 436 panic("pcdisplay_free_screen: console"); 437 438 sc->nscreens--; 439 } 440 441 static int 442 pcdisplay_show_screen(v, cookie, waitok, cb, cbarg) 443 void *v; 444 void *cookie; 445 int waitok; 446 void (*cb) __P((void *, int, int)); 447 void *cbarg; 448 { 449 #ifdef DIAGNOSTIC 450 struct pcdisplay_softc *sc = v; 451 452 if (cookie != sc->sc_dc) 453 panic("pcdisplay_show_screen: bad screen"); 454 #endif 455 return (0); 456 } 457 458 static int 459 pcdisplay_alloc_attr(id, fg, bg, flags, attrp) 460 void *id; 461 int fg, bg; 462 int flags; 463 long *attrp; 464 { 465 if (flags & WSATTR_REVERSE) 466 *attrp = FG_BLACK | BG_LIGHTGREY; 467 else 468 *attrp = FG_LIGHTGREY | BG_BLACK; 469 return (0); 470 } 471