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