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