1 1.7 thorpej /* $NetBSD: lynxfb.c,v 1.7 2021/08/07 16:19:14 thorpej Exp $ */ 2 1.1 nonaka /* $OpenBSD: smfb.c,v 1.13 2011/07/21 20:36:12 miod Exp $ */ 3 1.1 nonaka 4 1.1 nonaka /* 5 1.1 nonaka * Copyright (c) 2012 NONAKA Kimihiro <nonaka (at) netbsd.org> 6 1.1 nonaka * Copyright (c) 2009, 2010 Miodrag Vallat. 7 1.1 nonaka * 8 1.1 nonaka * Permission to use, copy, modify, and distribute this software for any 9 1.1 nonaka * purpose with or without fee is hereby granted, provided that the above 10 1.1 nonaka * copyright notice and this permission notice appear in all copies. 11 1.1 nonaka * 12 1.1 nonaka * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 1.1 nonaka * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 1.1 nonaka * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 1.1 nonaka * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 1.1 nonaka * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 1.1 nonaka * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 1.1 nonaka * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 1.1 nonaka */ 20 1.1 nonaka 21 1.1 nonaka /* 22 1.1 nonaka * SiliconMotion SM712 frame buffer driver. 23 1.1 nonaka * 24 1.1 nonaka * Assumes its video output is an LCD panel, in 5:6:5 mode, and fixed 25 1.1 nonaka * 1024x600 resolution, depending on the system model. 26 1.1 nonaka */ 27 1.1 nonaka 28 1.1 nonaka #include <sys/cdefs.h> 29 1.7 thorpej __KERNEL_RCSID(0, "$NetBSD: lynxfb.c,v 1.7 2021/08/07 16:19:14 thorpej Exp $"); 30 1.1 nonaka 31 1.1 nonaka #include "opt_wsemul.h" 32 1.1 nonaka 33 1.1 nonaka #include <sys/param.h> 34 1.1 nonaka #include <sys/systm.h> 35 1.1 nonaka #include <sys/device.h> 36 1.1 nonaka #include <sys/endian.h> 37 1.3 nonaka #include <sys/kauth.h> 38 1.1 nonaka 39 1.1 nonaka #include <sys/bus.h> 40 1.1 nonaka 41 1.1 nonaka #include <dev/ic/vgareg.h> 42 1.1 nonaka #include <dev/isa/isareg.h> 43 1.1 nonaka #include <dev/pci/pcireg.h> 44 1.1 nonaka #include <dev/pci/pcivar.h> 45 1.1 nonaka #include <dev/pci/pcidevs.h> 46 1.1 nonaka #include <dev/pci/pciio.h> 47 1.1 nonaka 48 1.1 nonaka #include <dev/wscons/wsconsio.h> 49 1.1 nonaka #include <dev/wscons/wsdisplayvar.h> 50 1.1 nonaka #include <dev/rasops/rasops.h> 51 1.1 nonaka #include <dev/wscons/wsdisplay_vconsvar.h> 52 1.1 nonaka #include <dev/pci/wsdisplay_pci.h> 53 1.1 nonaka 54 1.1 nonaka #include <dev/pci/lynxfbreg.h> 55 1.1 nonaka #include <dev/pci/lynxfbvar.h> 56 1.1 nonaka 57 1.1 nonaka #ifndef LYNXFB_DEFAULT_WIDTH 58 1.1 nonaka #define LYNXFB_DEFAULT_WIDTH 1024 59 1.1 nonaka #endif 60 1.1 nonaka #ifndef LYNXFB_DEFAULT_HEIGHT 61 1.1 nonaka #define LYNXFB_DEFAULT_HEIGHT 600 62 1.1 nonaka #endif 63 1.1 nonaka #ifndef LYNXFB_DEFAULT_DEPTH 64 1.1 nonaka #define LYNXFB_DEFAULT_DEPTH 16 65 1.1 nonaka #endif 66 1.1 nonaka #ifndef LYNXFB_DEFAULT_STRIDE 67 1.1 nonaka #define LYNXFB_DEFAULT_STRIDE 0 68 1.1 nonaka #endif 69 1.1 nonaka #ifndef LYNXFB_DEFAULT_FLAGS 70 1.1 nonaka #ifdef __MIPSEL__ 71 1.1 nonaka #define LYNXFB_DEFAULT_FLAGS LYNXFB_FLAG_SWAPBR 72 1.1 nonaka #else 73 1.1 nonaka #define LYNXFB_DEFAULT_FLAGS 0 74 1.1 nonaka #endif 75 1.1 nonaka #endif 76 1.1 nonaka 77 1.1 nonaka struct lynxfb_softc; 78 1.1 nonaka 79 1.1 nonaka /* minimal frame buffer information, suitable for early console */ 80 1.1 nonaka struct lynxfb { 81 1.1 nonaka struct lynxfb_softc *sc; 82 1.1 nonaka void *fbaddr; 83 1.1 nonaka 84 1.1 nonaka bus_space_tag_t memt; 85 1.1 nonaka bus_space_handle_t memh; 86 1.1 nonaka 87 1.1 nonaka /* DPR registers */ 88 1.1 nonaka bus_space_tag_t dprt; 89 1.1 nonaka bus_space_handle_t dprh; 90 1.1 nonaka /* MMIO space */ 91 1.1 nonaka bus_space_tag_t mmiot; 92 1.1 nonaka bus_space_handle_t mmioh; 93 1.1 nonaka 94 1.1 nonaka struct vcons_screen vcs; 95 1.1 nonaka struct wsscreen_descr wsd; 96 1.1 nonaka 97 1.1 nonaka int width, height, depth, stride; 98 1.1 nonaka int accel; 99 1.1 nonaka int blank; 100 1.1 nonaka 101 1.1 nonaka /* LYNXFB_FLAG_* */ 102 1.1 nonaka int flags; 103 1.1 nonaka #define LYNXFB_FLAG_SWAPBR (1 << 0) 104 1.1 nonaka }; 105 1.1 nonaka 106 1.1 nonaka #define DPR_READ(fb, reg) \ 107 1.1 nonaka bus_space_read_4((fb)->memt, (fb)->dprh, (reg)) 108 1.1 nonaka #define DPR_WRITE(fb, reg, val) \ 109 1.1 nonaka bus_space_write_4((fb)->memt, (fb)->dprh, (reg), (val)) 110 1.1 nonaka 111 1.1 nonaka struct lynxfb_softc { 112 1.1 nonaka device_t sc_dev; 113 1.1 nonaka bus_space_tag_t sc_memt; 114 1.1 nonaka bus_space_handle_t sc_memh; 115 1.1 nonaka 116 1.1 nonaka pci_chipset_tag_t sc_pc; 117 1.1 nonaka pcitag_t sc_pcitag; 118 1.1 nonaka 119 1.1 nonaka struct lynxfb *sc_fb; 120 1.1 nonaka struct lynxfb sc_fb_store; 121 1.3 nonaka bus_addr_t sc_fbaddr; 122 1.3 nonaka bus_size_t sc_fbsize; 123 1.1 nonaka 124 1.1 nonaka struct vcons_data sc_vd; 125 1.1 nonaka struct wsscreen_list sc_screenlist; 126 1.1 nonaka const struct wsscreen_descr *sc_screens[1]; 127 1.1 nonaka int sc_mode; 128 1.1 nonaka }; 129 1.1 nonaka 130 1.1 nonaka static int lynxfb_match_by_id(pcireg_t); 131 1.1 nonaka static int lynxfb_match(device_t, cfdata_t, void *); 132 1.1 nonaka static void lynxfb_attach(device_t, device_t, void *); 133 1.1 nonaka 134 1.1 nonaka CFATTACH_DECL_NEW(lynxfb, sizeof(struct lynxfb_softc), 135 1.1 nonaka lynxfb_match, lynxfb_attach, NULL, NULL); 136 1.1 nonaka 137 1.1 nonaka static int lynxfb_ioctl(void *, void *, u_long, void *, int, struct lwp *); 138 1.1 nonaka static paddr_t lynxfb_mmap(void *, void *, off_t, int); 139 1.1 nonaka 140 1.1 nonaka static struct wsdisplay_accessops lynxfb_accessops = { 141 1.1 nonaka lynxfb_ioctl, 142 1.1 nonaka lynxfb_mmap, 143 1.1 nonaka NULL, /* alloc_screen */ 144 1.1 nonaka NULL, /* free_screen */ 145 1.1 nonaka NULL, /* show_screen */ 146 1.1 nonaka NULL, /* load_font */ 147 1.1 nonaka NULL, /* pollc */ 148 1.1 nonaka NULL, /* scroll */ 149 1.1 nonaka }; 150 1.1 nonaka 151 1.1 nonaka static bool lynxfb_is_console(struct lynxfb_softc *, pcitag_t); 152 1.1 nonaka static void lynxfb_init_screen(void *, struct vcons_screen *, int, long *); 153 1.1 nonaka static int lynxfb_setup(struct lynxfb *); 154 1.1 nonaka 155 1.1 nonaka static int lynxfb_wait(struct lynxfb *); 156 1.1 nonaka static void lynxfb_copyrect(struct lynxfb *, int, int, int, int, int, int); 157 1.1 nonaka static void lynxfb_fillrect(struct lynxfb *, int, int, int, int, int); 158 1.1 nonaka static void lynxfb_copyrows(void *, int, int, int); 159 1.1 nonaka static void lynxfb_copycols(void *, int, int, int, int); 160 1.1 nonaka static void lynxfb_erasecols(void *, int, int, int, long); 161 1.1 nonaka static void lynxfb_eraserows(void *, int, int, long); 162 1.1 nonaka static void lynxfb_vcons_copyrows(void *, int, int, int); 163 1.1 nonaka static void lynxfb_vcons_copycols(void *, int, int, int, int); 164 1.1 nonaka static void lynxfb_vcons_erasecols(void *, int, int, int, long); 165 1.1 nonaka static void lynxfb_vcons_eraserows(void *, int, int, long); 166 1.1 nonaka static void lynxfb_blank(struct lynxfb *, int); 167 1.1 nonaka 168 1.1 nonaka static struct { 169 1.1 nonaka bool is_console; 170 1.1 nonaka pcitag_t tag; 171 1.1 nonaka bus_space_tag_t memt; 172 1.1 nonaka bus_space_handle_t memh; 173 1.1 nonaka struct lynxfb fb; 174 1.3 nonaka bus_addr_t fbaddr; 175 1.3 nonaka bus_size_t fbsize; 176 1.1 nonaka } lynxfb_console; 177 1.1 nonaka 178 1.1 nonaka int lynxfb_default_width = LYNXFB_DEFAULT_WIDTH; 179 1.1 nonaka int lynxfb_default_height = LYNXFB_DEFAULT_HEIGHT; 180 1.1 nonaka int lynxfb_default_depth = LYNXFB_DEFAULT_DEPTH; 181 1.1 nonaka int lynxfb_default_stride = LYNXFB_DEFAULT_STRIDE; 182 1.1 nonaka int lynxfb_default_flags = LYNXFB_DEFAULT_FLAGS; 183 1.1 nonaka 184 1.1 nonaka static int 185 1.1 nonaka lynxfb_match_by_id(pcireg_t id) 186 1.1 nonaka { 187 1.1 nonaka 188 1.1 nonaka if (PCI_VENDOR(id) != PCI_VENDOR_SILMOTION) 189 1.1 nonaka return (0); 190 1.1 nonaka if (PCI_PRODUCT(id) != PCI_PRODUCT_SILMOTION_SM712) 191 1.1 nonaka return (0); 192 1.1 nonaka return (1); 193 1.1 nonaka } 194 1.1 nonaka 195 1.1 nonaka int 196 1.1 nonaka lynxfb_cnattach(bus_space_tag_t memt, bus_space_tag_t iot, pci_chipset_tag_t pc, 197 1.1 nonaka pcitag_t tag, pcireg_t id) 198 1.1 nonaka { 199 1.1 nonaka struct rasops_info *ri = &lynxfb_console.fb.vcs.scr_ri; 200 1.1 nonaka struct lynxfb *fb; 201 1.1 nonaka bus_space_handle_t memh; 202 1.1 nonaka bus_addr_t base; 203 1.1 nonaka bus_size_t size; 204 1.1 nonaka long defattr; 205 1.1 nonaka int mapflags; 206 1.1 nonaka int error; 207 1.1 nonaka 208 1.1 nonaka if (!lynxfb_match_by_id(id)) 209 1.1 nonaka return (ENODEV); 210 1.1 nonaka 211 1.1 nonaka if (pci_mapreg_info(pc, tag, PCI_MAPREG_START, PCI_MAPREG_TYPE_MEM, 212 1.1 nonaka &base, &size, &mapflags)) 213 1.1 nonaka return (EINVAL); 214 1.1 nonaka error = bus_space_map(memt, base, size, BUS_SPACE_MAP_LINEAR | mapflags, 215 1.1 nonaka &memh); 216 1.1 nonaka if (error) 217 1.1 nonaka return (error); 218 1.1 nonaka 219 1.1 nonaka fb = &lynxfb_console.fb; 220 1.1 nonaka fb->memt = memt; 221 1.1 nonaka fb->memh = memh; 222 1.1 nonaka fb->width = lynxfb_default_width; 223 1.1 nonaka fb->height = lynxfb_default_height; 224 1.1 nonaka fb->depth = lynxfb_default_depth; 225 1.1 nonaka fb->stride = lynxfb_default_stride; 226 1.1 nonaka if (fb->stride == 0) 227 1.1 nonaka fb->stride = fb->width * fb->depth / 8; 228 1.1 nonaka fb->flags = lynxfb_default_flags; 229 1.1 nonaka error = lynxfb_setup(fb); 230 1.1 nonaka if (error) { 231 1.1 nonaka bus_space_unmap(memt, memh, size); 232 1.1 nonaka return (error); 233 1.1 nonaka } 234 1.1 nonaka 235 1.1 nonaka lynxfb_console.is_console = true; 236 1.1 nonaka lynxfb_console.tag = tag; 237 1.3 nonaka lynxfb_console.fbaddr = base; 238 1.3 nonaka lynxfb_console.fbsize = size; 239 1.1 nonaka (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 240 1.1 nonaka wsdisplay_preattach(&fb->wsd, ri, 0, 0, defattr); 241 1.1 nonaka 242 1.1 nonaka return (0); 243 1.1 nonaka } 244 1.1 nonaka 245 1.1 nonaka static bool 246 1.1 nonaka lynxfb_is_console(struct lynxfb_softc *sc, pcitag_t tag) 247 1.1 nonaka { 248 1.1 nonaka 249 1.1 nonaka return (lynxfb_console.is_console && 250 1.1 nonaka !memcmp(&lynxfb_console.tag, &tag, sizeof(tag))); 251 1.1 nonaka } 252 1.1 nonaka 253 1.1 nonaka static int 254 1.1 nonaka lynxfb_match(device_t parent, cfdata_t match, void *aux) 255 1.1 nonaka { 256 1.1 nonaka struct pci_attach_args *pa = (struct pci_attach_args *)aux; 257 1.1 nonaka 258 1.1 nonaka if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY) 259 1.1 nonaka return (0); 260 1.1 nonaka if (!lynxfb_match_by_id(pa->pa_id)) 261 1.1 nonaka return (0); 262 1.1 nonaka return (1); 263 1.1 nonaka } 264 1.1 nonaka 265 1.1 nonaka static void 266 1.1 nonaka lynxfb_attach(device_t parent, device_t self, void *aux) 267 1.1 nonaka { 268 1.1 nonaka struct lynxfb_softc *sc = device_private(self); 269 1.1 nonaka struct pci_attach_args *pa = (struct pci_attach_args *)aux; 270 1.1 nonaka struct wsemuldisplaydev_attach_args waa; 271 1.1 nonaka struct lynxfb *fb; 272 1.1 nonaka struct rasops_info *ri; 273 1.1 nonaka prop_dictionary_t dict; 274 1.1 nonaka long defattr; 275 1.1 nonaka bool is_console; 276 1.1 nonaka 277 1.1 nonaka sc->sc_dev = self; 278 1.1 nonaka sc->sc_pc = pa->pa_pc; 279 1.1 nonaka sc->sc_pcitag = pa->pa_tag; 280 1.1 nonaka 281 1.1 nonaka pci_aprint_devinfo(pa, NULL); 282 1.1 nonaka 283 1.1 nonaka is_console = lynxfb_is_console(sc, sc->sc_pcitag); 284 1.1 nonaka 285 1.1 nonaka fb = is_console ? &lynxfb_console.fb : &sc->sc_fb_store; 286 1.1 nonaka sc->sc_fb = fb; 287 1.1 nonaka fb->sc = sc; 288 1.1 nonaka 289 1.3 nonaka if (is_console) { 290 1.3 nonaka sc->sc_fbaddr = lynxfb_console.fbaddr; 291 1.3 nonaka sc->sc_fbsize = lynxfb_console.fbsize; 292 1.3 nonaka } else { 293 1.1 nonaka if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_MEM, 294 1.3 nonaka BUS_SPACE_MAP_LINEAR, &fb->memt, &fb->memh, &sc->sc_fbaddr, 295 1.3 nonaka &sc->sc_fbsize)) { 296 1.1 nonaka aprint_error_dev(self, "can't map frame buffer\n"); 297 1.1 nonaka return; 298 1.1 nonaka } 299 1.1 nonaka 300 1.1 nonaka dict = device_properties(self); 301 1.1 nonaka if (!prop_dictionary_get_uint32(dict, "width", &fb->width)) 302 1.1 nonaka fb->width = lynxfb_default_width; 303 1.1 nonaka if (!prop_dictionary_get_uint32(dict, "height", &fb->height)) 304 1.1 nonaka fb->height = lynxfb_default_height; 305 1.1 nonaka if (!prop_dictionary_get_uint32(dict, "depth", &fb->depth)) 306 1.1 nonaka fb->depth = lynxfb_default_depth; 307 1.1 nonaka if (!prop_dictionary_get_uint32(dict, "linebytes", &fb->stride)) { 308 1.1 nonaka if (lynxfb_default_stride == 0) 309 1.1 nonaka fb->stride = fb->width * fb->depth / 8; 310 1.1 nonaka else 311 1.1 nonaka fb->stride = lynxfb_default_stride; 312 1.1 nonaka } 313 1.1 nonaka if (!prop_dictionary_get_uint32(dict, "flags", &fb->flags)) 314 1.1 nonaka fb->flags = lynxfb_default_flags; 315 1.1 nonaka 316 1.1 nonaka if (lynxfb_setup(fb)) { 317 1.1 nonaka aprint_error_dev(self, "can't setup frame buffer\n"); 318 1.3 nonaka bus_space_unmap(fb->memt, fb->memh, sc->sc_fbsize); 319 1.1 nonaka return; 320 1.1 nonaka } 321 1.1 nonaka } 322 1.1 nonaka sc->sc_memt = fb->memt; 323 1.1 nonaka sc->sc_memh = fb->memh; 324 1.1 nonaka 325 1.1 nonaka aprint_normal_dev(self, "%d x %d, %d bpp, stride %d\n", fb->width, 326 1.1 nonaka fb->height, fb->depth, fb->stride); 327 1.1 nonaka 328 1.1 nonaka fb->wsd = (struct wsscreen_descr) { 329 1.1 nonaka "default", 330 1.1 nonaka 0, 0, 331 1.1 nonaka NULL, 332 1.1 nonaka 8, 16, 333 1.1 nonaka WSSCREEN_WSCOLORS | WSSCREEN_HILIT, 334 1.1 nonaka NULL, 335 1.1 nonaka }; 336 1.1 nonaka sc->sc_screens[0] = &fb->wsd; 337 1.1 nonaka sc->sc_screenlist = (struct wsscreen_list){ 1, sc->sc_screens }; 338 1.1 nonaka sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 339 1.1 nonaka 340 1.1 nonaka vcons_init(&sc->sc_vd, sc, &fb->wsd, &lynxfb_accessops); 341 1.1 nonaka sc->sc_vd.init_screen = lynxfb_init_screen; 342 1.1 nonaka 343 1.1 nonaka ri = &fb->vcs.scr_ri; 344 1.1 nonaka if (is_console) { 345 1.1 nonaka vcons_init_screen(&sc->sc_vd, &fb->vcs, 1, &defattr); 346 1.1 nonaka fb->vcs.scr_flags |= VCONS_SCREEN_IS_STATIC; 347 1.1 nonaka 348 1.1 nonaka fb->wsd.textops = &ri->ri_ops; 349 1.1 nonaka fb->wsd.capabilities = ri->ri_caps; 350 1.1 nonaka fb->wsd.nrows = ri->ri_rows; 351 1.1 nonaka fb->wsd.ncols = ri->ri_cols; 352 1.1 nonaka wsdisplay_cnattach(&fb->wsd, ri, 0, 0, defattr); 353 1.1 nonaka vcons_replay_msgbuf(&fb->vcs); 354 1.1 nonaka } else { 355 1.1 nonaka /* 356 1.1 nonaka * since we're not the console we can postpone the rest 357 1.1 nonaka * until someone actually allocates a screen for us 358 1.1 nonaka */ 359 1.1 nonaka (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 360 1.1 nonaka } 361 1.1 nonaka 362 1.1 nonaka waa.console = is_console; 363 1.1 nonaka waa.scrdata = &sc->sc_screenlist; 364 1.1 nonaka waa.accessops = &lynxfb_accessops; 365 1.1 nonaka waa.accesscookie = &sc->sc_vd; 366 1.1 nonaka 367 1.7 thorpej config_found(self, &waa, wsemuldisplaydevprint, CFARGS_NONE); 368 1.1 nonaka } 369 1.1 nonaka 370 1.1 nonaka /* 371 1.1 nonaka * vga sequencer access through MMIO space 372 1.1 nonaka */ 373 1.1 nonaka static __inline uint8_t 374 1.1 nonaka lynxfb_vgats_read(struct lynxfb *fb, uint regno) 375 1.1 nonaka { 376 1.1 nonaka 377 1.1 nonaka bus_space_write_1(fb->mmiot, fb->mmioh, IO_VGA + VGA_TS_INDEX, regno); 378 1.1 nonaka return bus_space_read_1(fb->mmiot, fb->mmioh, IO_VGA + VGA_TS_DATA); 379 1.1 nonaka } 380 1.1 nonaka 381 1.1 nonaka static __inline void 382 1.1 nonaka lynxfb_vgats_write(struct lynxfb *fb, uint regno, uint8_t value) 383 1.1 nonaka { 384 1.1 nonaka 385 1.1 nonaka bus_space_write_1(fb->mmiot, fb->mmioh, IO_VGA + VGA_TS_INDEX, regno); 386 1.1 nonaka bus_space_write_1(fb->mmiot, fb->mmioh, IO_VGA + VGA_TS_DATA, value); 387 1.1 nonaka } 388 1.1 nonaka 389 1.1 nonaka /* 390 1.1 nonaka * wsdisplay accesops 391 1.1 nonaka */ 392 1.1 nonaka static int 393 1.1 nonaka lynxfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flags, 394 1.1 nonaka struct lwp *l) 395 1.1 nonaka { 396 1.1 nonaka struct vcons_data *vd = v; 397 1.1 nonaka struct lynxfb_softc *sc = vd->cookie; 398 1.1 nonaka struct lynxfb *fb = sc->sc_fb; 399 1.1 nonaka struct vcons_screen *ms = vd->active; 400 1.1 nonaka struct wsdisplay_fbinfo *wdf; 401 1.1 nonaka struct wsdisplay_param *param; 402 1.1 nonaka 403 1.1 nonaka switch (cmd) { 404 1.1 nonaka case WSDISPLAYIO_GTYPE: 405 1.1 nonaka *(uint *)data = WSDISPLAY_TYPE_PCIMISC; 406 1.1 nonaka return (0); 407 1.1 nonaka 408 1.1 nonaka /* PCI config read/write passthrough. */ 409 1.1 nonaka case PCI_IOC_CFGREAD: 410 1.1 nonaka case PCI_IOC_CFGWRITE: 411 1.1 nonaka return pci_devioctl(sc->sc_pc, sc->sc_pcitag, 412 1.1 nonaka cmd, data, flags, l); 413 1.1 nonaka 414 1.1 nonaka case WSDISPLAYIO_GET_BUSID: 415 1.2 nonaka return wsdisplayio_busid_pci(sc->sc_dev, sc->sc_pc, 416 1.2 nonaka sc->sc_pcitag, data); 417 1.1 nonaka 418 1.1 nonaka case WSDISPLAYIO_GINFO: 419 1.1 nonaka if (ms == NULL) 420 1.1 nonaka return (ENODEV); 421 1.1 nonaka wdf = (struct wsdisplay_fbinfo *)data; 422 1.1 nonaka wdf->width = ms->scr_ri.ri_width; 423 1.1 nonaka wdf->height = ms->scr_ri.ri_height; 424 1.1 nonaka wdf->depth = ms->scr_ri.ri_depth; 425 1.1 nonaka wdf->cmsize = 0; 426 1.1 nonaka return (0); 427 1.1 nonaka 428 1.1 nonaka case WSDISPLAYIO_LINEBYTES: 429 1.1 nonaka *(uint *)data = fb->stride; 430 1.1 nonaka return (0); 431 1.1 nonaka 432 1.1 nonaka case WSDISPLAYIO_GVIDEO: 433 1.1 nonaka *(int *)data = fb->blank ? WSDISPLAYIO_VIDEO_OFF : 434 1.1 nonaka WSDISPLAYIO_VIDEO_ON; 435 1.1 nonaka return (0); 436 1.1 nonaka 437 1.1 nonaka case WSDISPLAYIO_SVIDEO: 438 1.1 nonaka lynxfb_blank(fb, *(int *)data); 439 1.1 nonaka return (0); 440 1.1 nonaka 441 1.1 nonaka case WSDISPLAYIO_GETPARAM: 442 1.1 nonaka param = (struct wsdisplay_param *)data; 443 1.1 nonaka switch (param->param) { 444 1.1 nonaka case WSDISPLAYIO_PARAM_BACKLIGHT: 445 1.1 nonaka param->min = 0; 446 1.1 nonaka param->max = 1; 447 1.1 nonaka param->curval = fb->blank; 448 1.1 nonaka return (0); 449 1.1 nonaka } 450 1.1 nonaka break; 451 1.1 nonaka 452 1.1 nonaka case WSDISPLAYIO_SETPARAM: 453 1.1 nonaka param = (struct wsdisplay_param *)data; 454 1.1 nonaka switch (param->param) { 455 1.1 nonaka case WSDISPLAYIO_PARAM_BACKLIGHT: 456 1.1 nonaka lynxfb_blank(fb, param->curval); 457 1.1 nonaka return (0); 458 1.1 nonaka } 459 1.1 nonaka break; 460 1.1 nonaka } 461 1.1 nonaka return (EPASSTHROUGH); 462 1.1 nonaka } 463 1.1 nonaka 464 1.1 nonaka static paddr_t 465 1.1 nonaka lynxfb_mmap(void *v, void *vs, off_t offset, int prot) 466 1.1 nonaka { 467 1.1 nonaka struct vcons_data *vd = v; 468 1.1 nonaka struct lynxfb_softc *sc = vd->cookie; 469 1.1 nonaka struct rasops_info *ri = &sc->sc_fb->vcs.scr_ri; 470 1.1 nonaka 471 1.3 nonaka /* 'regular' framebuffer mmap()ing */ 472 1.3 nonaka if (offset < ri->ri_stride * ri->ri_height) { 473 1.3 nonaka return bus_space_mmap(sc->sc_memt, sc->sc_fbaddr + offset, 0, 474 1.3 nonaka prot, BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE); 475 1.3 nonaka } 476 1.3 nonaka 477 1.3 nonaka /* 478 1.3 nonaka * restrict all other mappings to processes with superuser privileges 479 1.3 nonaka * or the kernel itself 480 1.3 nonaka */ 481 1.4 nonaka if (kauth_authorize_machdep(kauth_cred_get(), 482 1.4 nonaka KAUTH_MACHDEP_UNMANAGEDMEM, NULL, NULL, NULL, NULL) != 0) { 483 1.3 nonaka aprint_normal_dev(sc->sc_dev, "mmap() rejected.\n"); 484 1.1 nonaka return (-1); 485 1.3 nonaka } 486 1.3 nonaka 487 1.3 nonaka /* framebuffer mmap()ing */ 488 1.3 nonaka if (offset >= sc->sc_fbaddr && 489 1.3 nonaka offset < sc->sc_fbaddr + ri->ri_stride * ri->ri_height) { 490 1.3 nonaka return bus_space_mmap(sc->sc_memt, offset, 0, prot, 491 1.3 nonaka BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE); 492 1.3 nonaka } 493 1.1 nonaka 494 1.3 nonaka /* register mmap()ing */ 495 1.3 nonaka if (offset >= sc->sc_fbaddr + SM7XX_REG_BASE && 496 1.3 nonaka offset < sc->sc_fbaddr + SM7XX_REG_BASE + SM7XX_REG_SIZE) { 497 1.3 nonaka return bus_space_mmap(sc->sc_memt, offset, 0, prot, 0); 498 1.3 nonaka } 499 1.1 nonaka 500 1.3 nonaka return (-1); 501 1.1 nonaka } 502 1.1 nonaka 503 1.1 nonaka static void 504 1.1 nonaka lynxfb_init_screen(void *cookie, struct vcons_screen *scr, 505 1.1 nonaka int existing, long *defattr) 506 1.1 nonaka { 507 1.1 nonaka struct lynxfb_softc *sc = cookie; 508 1.1 nonaka struct lynxfb *fb = sc->sc_fb; 509 1.1 nonaka struct rasops_info *ri = &scr->scr_ri; 510 1.1 nonaka 511 1.1 nonaka ri->ri_width = fb->width; 512 1.1 nonaka ri->ri_height = fb->height; 513 1.1 nonaka ri->ri_depth = fb->depth; 514 1.1 nonaka ri->ri_stride = fb->stride; 515 1.1 nonaka ri->ri_flg = RI_CENTER; 516 1.1 nonaka ri->ri_bits = fb->fbaddr; 517 1.1 nonaka 518 1.1 nonaka #ifdef VCONS_DRAW_INTR 519 1.1 nonaka scr->scr_flags |= VCONS_DONT_READ; 520 1.1 nonaka #endif 521 1.1 nonaka 522 1.1 nonaka if (existing) 523 1.1 nonaka ri->ri_flg |= RI_CLEAR; 524 1.1 nonaka 525 1.1 nonaka rasops_init(ri, 0, 0); 526 1.1 nonaka ri->ri_caps = WSSCREEN_WSCOLORS; 527 1.1 nonaka rasops_reconfig(ri, fb->height / ri->ri_font->fontheight, 528 1.1 nonaka fb->width / ri->ri_font->fontwidth); 529 1.1 nonaka 530 1.1 nonaka ri->ri_hw = scr; 531 1.1 nonaka 532 1.1 nonaka if (fb->accel) { 533 1.1 nonaka ri->ri_ops.copycols = lynxfb_vcons_copycols; 534 1.1 nonaka ri->ri_ops.copyrows = lynxfb_vcons_copyrows; 535 1.1 nonaka ri->ri_ops.erasecols = lynxfb_vcons_erasecols; 536 1.1 nonaka ri->ri_ops.eraserows = lynxfb_vcons_eraserows; 537 1.1 nonaka } 538 1.1 nonaka } 539 1.1 nonaka 540 1.1 nonaka /* 541 1.1 nonaka * Frame buffer initialization. 542 1.1 nonaka */ 543 1.1 nonaka static int 544 1.1 nonaka lynxfb_setup(struct lynxfb *fb) 545 1.1 nonaka { 546 1.1 nonaka struct rasops_info *ri = &fb->vcs.scr_ri; 547 1.1 nonaka int error; 548 1.1 nonaka 549 1.1 nonaka fb->dprt = fb->memt; 550 1.1 nonaka error = bus_space_subregion(fb->memt, fb->memh, SM7XX_DPR_BASE, 551 1.1 nonaka SMXXX_DPR_SIZE, &fb->dprh); 552 1.1 nonaka if (error != 0) 553 1.1 nonaka return (error); 554 1.1 nonaka 555 1.1 nonaka fb->mmiot = fb->memt; 556 1.1 nonaka error = bus_space_subregion(fb->mmiot, fb->memh, SM7XX_MMIO_BASE, 557 1.1 nonaka SM7XX_MMIO_SIZE, &fb->mmioh); 558 1.1 nonaka if (error != 0) 559 1.1 nonaka return (error); 560 1.1 nonaka 561 1.1 nonaka ri->ri_width = fb->width; 562 1.1 nonaka ri->ri_height = fb->height; 563 1.1 nonaka ri->ri_depth = fb->depth; 564 1.1 nonaka ri->ri_stride = fb->stride; 565 1.1 nonaka ri->ri_flg = RI_CENTER | RI_CLEAR | RI_NO_AUTO; 566 1.1 nonaka fb->fbaddr = ri->ri_bits = (void *)bus_space_vaddr(fb->memt, fb->memh); 567 1.1 nonaka ri->ri_hw = fb; 568 1.1 nonaka 569 1.1 nonaka if (fb->flags & LYNXFB_FLAG_SWAPBR) { 570 1.1 nonaka switch (fb->depth) { 571 1.1 nonaka case 16: 572 1.1 nonaka ri->ri_rnum = 5; 573 1.1 nonaka ri->ri_rpos = 11; 574 1.1 nonaka ri->ri_gnum = 6; 575 1.1 nonaka ri->ri_gpos = 5; 576 1.1 nonaka ri->ri_bnum = 5; 577 1.1 nonaka ri->ri_bpos = 0; 578 1.1 nonaka break; 579 1.1 nonaka } 580 1.1 nonaka } 581 1.1 nonaka 582 1.1 nonaka rasops_init(ri, 0, 0); 583 1.1 nonaka rasops_reconfig(ri, ri->ri_height / ri->ri_font->fontheight, 584 1.1 nonaka ri->ri_width / ri->ri_font->fontwidth); 585 1.1 nonaka 586 1.1 nonaka fb->wsd.name = "std"; 587 1.1 nonaka fb->wsd.ncols = ri->ri_cols; 588 1.1 nonaka fb->wsd.nrows = ri->ri_rows; 589 1.1 nonaka fb->wsd.textops = &ri->ri_ops; 590 1.1 nonaka fb->wsd.fontwidth = ri->ri_font->fontwidth; 591 1.1 nonaka fb->wsd.fontheight = ri->ri_font->fontheight; 592 1.1 nonaka fb->wsd.capabilities = ri->ri_caps; 593 1.1 nonaka 594 1.1 nonaka /* 595 1.1 nonaka * Setup 2D acceleration whenever possible 596 1.1 nonaka */ 597 1.1 nonaka if (lynxfb_wait(fb) == 0) { 598 1.1 nonaka fb->accel = 1; 599 1.1 nonaka 600 1.1 nonaka DPR_WRITE(fb, DPR_CROP_TOPLEFT_COORDS, DPR_COORDS(0, 0)); 601 1.1 nonaka /* use of width both times is intentional */ 602 1.1 nonaka DPR_WRITE(fb, DPR_PITCH, 603 1.1 nonaka DPR_COORDS(ri->ri_width, ri->ri_width)); 604 1.1 nonaka DPR_WRITE(fb, DPR_SRC_WINDOW, 605 1.1 nonaka DPR_COORDS(ri->ri_width, ri->ri_width)); 606 1.1 nonaka DPR_WRITE(fb, DPR_BYTE_BIT_MASK, 0xffffffff); 607 1.1 nonaka DPR_WRITE(fb, DPR_COLOR_COMPARE_MASK, 0); 608 1.1 nonaka DPR_WRITE(fb, DPR_COLOR_COMPARE, 0); 609 1.1 nonaka DPR_WRITE(fb, DPR_SRC_BASE, 0); 610 1.1 nonaka DPR_WRITE(fb, DPR_DST_BASE, 0); 611 1.1 nonaka DPR_READ(fb, DPR_DST_BASE); 612 1.1 nonaka 613 1.1 nonaka ri->ri_ops.copycols = lynxfb_copycols; 614 1.1 nonaka ri->ri_ops.copyrows = lynxfb_copyrows; 615 1.1 nonaka ri->ri_ops.erasecols = lynxfb_erasecols; 616 1.1 nonaka ri->ri_ops.eraserows = lynxfb_eraserows; 617 1.1 nonaka } 618 1.1 nonaka 619 1.1 nonaka return (0); 620 1.1 nonaka } 621 1.1 nonaka 622 1.1 nonaka static int 623 1.1 nonaka lynxfb_wait(struct lynxfb *fb) 624 1.1 nonaka { 625 1.1 nonaka uint32_t reg; 626 1.1 nonaka int i; 627 1.1 nonaka 628 1.1 nonaka for (i = 10000; i > 0; i--) { 629 1.1 nonaka reg = lynxfb_vgats_read(fb, 0x16); 630 1.1 nonaka if ((reg & 0x18) == 0x10) 631 1.1 nonaka return (0); 632 1.1 nonaka delay(1); 633 1.1 nonaka } 634 1.1 nonaka return (EBUSY); 635 1.1 nonaka } 636 1.1 nonaka 637 1.1 nonaka static void 638 1.1 nonaka lynxfb_copyrect(struct lynxfb *fb, int sx, int sy, int dx, int dy, int w, int h) 639 1.1 nonaka { 640 1.1 nonaka uint32_t dir; 641 1.1 nonaka 642 1.1 nonaka /* Compute rop direction */ 643 1.1 nonaka if (sy < dy || (sy == dy && sx <= dx)) { 644 1.1 nonaka sx += w - 1; 645 1.1 nonaka dx += w - 1; 646 1.1 nonaka sy += h - 1; 647 1.1 nonaka dy += h - 1; 648 1.1 nonaka dir = DE_CTRL_RTOL; 649 1.1 nonaka } else 650 1.1 nonaka dir = 0; 651 1.1 nonaka 652 1.1 nonaka DPR_WRITE(fb, DPR_SRC_COORDS, DPR_COORDS(sx, sy)); 653 1.1 nonaka DPR_WRITE(fb, DPR_DST_COORDS, DPR_COORDS(dx, dy)); 654 1.1 nonaka DPR_WRITE(fb, DPR_SPAN_COORDS, DPR_COORDS(w, h)); 655 1.1 nonaka DPR_WRITE(fb, DPR_DE_CTRL, DE_CTRL_START | DE_CTRL_ROP_ENABLE | dir | 656 1.1 nonaka (DE_CTRL_COMMAND_BITBLT << DE_CTRL_COMMAND_SHIFT) | 657 1.1 nonaka (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT)); 658 1.1 nonaka DPR_READ(fb, DPR_DE_CTRL); 659 1.1 nonaka 660 1.1 nonaka lynxfb_wait(fb); 661 1.1 nonaka } 662 1.1 nonaka 663 1.1 nonaka static void 664 1.1 nonaka lynxfb_fillrect(struct lynxfb *fb, int x, int y, int w, int h, int bg) 665 1.1 nonaka { 666 1.1 nonaka struct rasops_info *ri = &fb->vcs.scr_ri; 667 1.1 nonaka 668 1.1 nonaka DPR_WRITE(fb, DPR_FG_COLOR, ri->ri_devcmap[bg]); 669 1.1 nonaka DPR_WRITE(fb, DPR_DST_COORDS, DPR_COORDS(x, y)); 670 1.1 nonaka DPR_WRITE(fb, DPR_SPAN_COORDS, DPR_COORDS(w, h)); 671 1.1 nonaka DPR_WRITE(fb, DPR_DE_CTRL, DE_CTRL_START | DE_CTRL_ROP_ENABLE | 672 1.1 nonaka (DE_CTRL_COMMAND_SOLIDFILL << DE_CTRL_COMMAND_SHIFT) | 673 1.1 nonaka (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT)); 674 1.1 nonaka DPR_READ(fb, DPR_DE_CTRL); 675 1.1 nonaka 676 1.1 nonaka lynxfb_wait(fb); 677 1.1 nonaka } 678 1.1 nonaka 679 1.1 nonaka static inline void 680 1.1 nonaka lynxfb_copyrows1(struct rasops_info *ri, int src, int dst, int num, 681 1.1 nonaka struct lynxfb *fb) 682 1.1 nonaka { 683 1.1 nonaka struct wsdisplay_font *f = ri->ri_font; 684 1.1 nonaka 685 1.1 nonaka num *= f->fontheight; 686 1.1 nonaka src *= f->fontheight; 687 1.1 nonaka dst *= f->fontheight; 688 1.1 nonaka 689 1.1 nonaka lynxfb_copyrect(fb, ri->ri_xorigin, ri->ri_yorigin + src, 690 1.1 nonaka ri->ri_xorigin, ri->ri_yorigin + dst, ri->ri_emuwidth, num); 691 1.1 nonaka } 692 1.1 nonaka 693 1.1 nonaka static inline void 694 1.1 nonaka lynxfb_copycols1(struct rasops_info *ri, int row, int src, int dst, int num, 695 1.1 nonaka struct lynxfb *fb) 696 1.1 nonaka { 697 1.1 nonaka struct wsdisplay_font *f = ri->ri_font; 698 1.1 nonaka 699 1.1 nonaka num *= f->fontwidth; 700 1.1 nonaka src *= f->fontwidth; 701 1.1 nonaka dst *= f->fontwidth; 702 1.1 nonaka row *= f->fontheight; 703 1.1 nonaka 704 1.1 nonaka lynxfb_copyrect(fb, ri->ri_xorigin + src, ri->ri_yorigin + row, 705 1.1 nonaka ri->ri_xorigin + dst, ri->ri_yorigin + row, num, f->fontheight); 706 1.1 nonaka } 707 1.1 nonaka 708 1.1 nonaka static inline void 709 1.1 nonaka lynxfb_erasecols1(struct rasops_info *ri, int row, int col, int num, long attr, 710 1.1 nonaka struct lynxfb *fb) 711 1.1 nonaka { 712 1.1 nonaka struct wsdisplay_font *f = ri->ri_font; 713 1.1 nonaka int32_t bg, fg, ul; 714 1.1 nonaka 715 1.1 nonaka row *= f->fontheight; 716 1.1 nonaka col *= f->fontwidth; 717 1.1 nonaka num *= f->fontwidth; 718 1.1 nonaka rasops_unpack_attr(attr, &fg, &bg, &ul); 719 1.1 nonaka 720 1.1 nonaka lynxfb_fillrect(fb, ri->ri_xorigin + col, ri->ri_yorigin + row, 721 1.1 nonaka num, f->fontheight, bg); 722 1.1 nonaka } 723 1.1 nonaka 724 1.1 nonaka static inline void 725 1.1 nonaka lynxfb_eraserows1(struct rasops_info *ri, int row, int num, long attr, 726 1.1 nonaka struct lynxfb *fb) 727 1.1 nonaka { 728 1.1 nonaka struct wsdisplay_font *f = ri->ri_font; 729 1.1 nonaka int32_t bg, fg, ul; 730 1.1 nonaka int x, y, w; 731 1.1 nonaka 732 1.1 nonaka if ((num == ri->ri_rows) && ISSET(ri->ri_flg, RI_FULLCLEAR)) { 733 1.1 nonaka num = ri->ri_height; 734 1.1 nonaka x = y = 0; 735 1.1 nonaka w = ri->ri_width; 736 1.1 nonaka } else { 737 1.1 nonaka num *= f->fontheight; 738 1.1 nonaka x = ri->ri_xorigin; 739 1.1 nonaka y = ri->ri_yorigin + row * f->fontheight; 740 1.1 nonaka w = ri->ri_emuwidth; 741 1.1 nonaka } 742 1.1 nonaka rasops_unpack_attr(attr, &fg, &bg, &ul); 743 1.1 nonaka lynxfb_fillrect(fb, x, y, w, num, bg); 744 1.1 nonaka } 745 1.1 nonaka 746 1.1 nonaka static void 747 1.1 nonaka lynxfb_copyrows(void *cookie, int src, int dst, int num) 748 1.1 nonaka { 749 1.1 nonaka struct rasops_info *ri = cookie; 750 1.1 nonaka struct lynxfb *fb = ri->ri_hw; 751 1.1 nonaka 752 1.1 nonaka lynxfb_copyrows1(ri, src, dst, num, fb); 753 1.1 nonaka } 754 1.1 nonaka 755 1.1 nonaka static void 756 1.1 nonaka lynxfb_copycols(void *cookie, int row, int src, int dst, int num) 757 1.1 nonaka { 758 1.1 nonaka struct rasops_info *ri = cookie; 759 1.1 nonaka struct lynxfb *fb = ri->ri_hw; 760 1.1 nonaka 761 1.1 nonaka lynxfb_copycols1(ri, row, src, dst, num, fb); 762 1.1 nonaka } 763 1.1 nonaka 764 1.1 nonaka static void 765 1.1 nonaka lynxfb_erasecols(void *cookie, int row, int col, int num, long attr) 766 1.1 nonaka { 767 1.1 nonaka struct rasops_info *ri = cookie; 768 1.1 nonaka struct lynxfb *fb = ri->ri_hw; 769 1.1 nonaka 770 1.1 nonaka lynxfb_erasecols1(ri, row, col, num, attr, fb); 771 1.1 nonaka } 772 1.1 nonaka 773 1.1 nonaka static void 774 1.1 nonaka lynxfb_eraserows(void *cookie, int row, int num, long attr) 775 1.1 nonaka { 776 1.1 nonaka struct rasops_info *ri = cookie; 777 1.1 nonaka struct lynxfb *fb = ri->ri_hw; 778 1.1 nonaka 779 1.1 nonaka lynxfb_eraserows1(ri, row, num, attr, fb); 780 1.1 nonaka } 781 1.1 nonaka 782 1.1 nonaka static void 783 1.1 nonaka lynxfb_vcons_copyrows(void *cookie, int src, int dst, int num) 784 1.1 nonaka { 785 1.1 nonaka struct rasops_info *ri = cookie; 786 1.1 nonaka struct vcons_screen *scr = ri->ri_hw; 787 1.1 nonaka struct lynxfb_softc *sc = scr->scr_cookie; 788 1.1 nonaka struct lynxfb *fb = sc->sc_fb; 789 1.1 nonaka 790 1.1 nonaka lynxfb_copyrows1(ri, src, dst, num, fb); 791 1.1 nonaka } 792 1.1 nonaka 793 1.1 nonaka static void 794 1.1 nonaka lynxfb_vcons_copycols(void *cookie, int row, int src, int dst, int num) 795 1.1 nonaka { 796 1.1 nonaka struct rasops_info *ri = cookie; 797 1.1 nonaka struct vcons_screen *scr = ri->ri_hw; 798 1.1 nonaka struct lynxfb_softc *sc = scr->scr_cookie; 799 1.1 nonaka struct lynxfb *fb = sc->sc_fb; 800 1.1 nonaka 801 1.1 nonaka lynxfb_copycols1(ri, row, src, dst, num, fb); 802 1.1 nonaka } 803 1.1 nonaka 804 1.1 nonaka static void 805 1.1 nonaka lynxfb_vcons_erasecols(void *cookie, int row, int col, int num, long attr) 806 1.1 nonaka { 807 1.1 nonaka struct rasops_info *ri = cookie; 808 1.1 nonaka struct vcons_screen *scr = ri->ri_hw; 809 1.1 nonaka struct lynxfb_softc *sc = scr->scr_cookie; 810 1.1 nonaka struct lynxfb *fb = sc->sc_fb; 811 1.1 nonaka 812 1.1 nonaka lynxfb_erasecols1(ri, row, col, num, attr, fb); 813 1.1 nonaka } 814 1.1 nonaka 815 1.1 nonaka static void 816 1.1 nonaka lynxfb_vcons_eraserows(void *cookie, int row, int num, long attr) 817 1.1 nonaka { 818 1.1 nonaka struct rasops_info *ri = cookie; 819 1.1 nonaka struct vcons_screen *scr = ri->ri_hw; 820 1.1 nonaka struct lynxfb_softc *sc = scr->scr_cookie; 821 1.1 nonaka struct lynxfb *fb = sc->sc_fb; 822 1.1 nonaka 823 1.1 nonaka lynxfb_eraserows1(ri, row, num, attr, fb); 824 1.1 nonaka } 825 1.1 nonaka 826 1.1 nonaka static void 827 1.5 jmcneill lynxfb_blank(struct lynxfb *fb, int enable) 828 1.1 nonaka { 829 1.1 nonaka 830 1.5 jmcneill fb->blank = !enable; 831 1.5 jmcneill if (enable) { 832 1.1 nonaka lynxfb_vgats_write(fb, 0x31, 833 1.1 nonaka lynxfb_vgats_read(fb, 0x31) | 0x01); 834 1.1 nonaka } else { 835 1.1 nonaka lynxfb_vgats_write(fb, 0x21, 836 1.1 nonaka lynxfb_vgats_read(fb, 0x21) | 0x30); 837 1.1 nonaka lynxfb_vgats_write(fb, 0x31, 838 1.1 nonaka lynxfb_vgats_read(fb, 0x31) & ~0x01); 839 1.1 nonaka } 840 1.1 nonaka } 841