1 1.37 chs /* $NetBSD: fb.c,v 1.37 2019/11/10 21:16:37 chs Exp $ */ 2 1.1 pk 3 1.1 pk /* 4 1.1 pk * Copyright (c) 1992, 1993 5 1.1 pk * The Regents of the University of California. All rights reserved. 6 1.1 pk * 7 1.1 pk * This software was developed by the Computer Systems Engineering group 8 1.1 pk * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 9 1.1 pk * contributed to Berkeley. 10 1.1 pk * 11 1.1 pk * All advertising materials mentioning features or use of this software 12 1.1 pk * must display the following acknowledgement: 13 1.1 pk * This product includes software developed by the University of 14 1.1 pk * California, Lawrence Berkeley Laboratory. 15 1.1 pk * 16 1.1 pk * Redistribution and use in source and binary forms, with or without 17 1.1 pk * modification, are permitted provided that the following conditions 18 1.1 pk * are met: 19 1.1 pk * 1. Redistributions of source code must retain the above copyright 20 1.1 pk * notice, this list of conditions and the following disclaimer. 21 1.1 pk * 2. Redistributions in binary form must reproduce the above copyright 22 1.1 pk * notice, this list of conditions and the following disclaimer in the 23 1.1 pk * documentation and/or other materials provided with the distribution. 24 1.13 agc * 3. Neither the name of the University nor the names of its contributors 25 1.1 pk * may be used to endorse or promote products derived from this software 26 1.1 pk * without specific prior written permission. 27 1.1 pk * 28 1.1 pk * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 1.1 pk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 1.1 pk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 1.1 pk * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 1.1 pk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 1.1 pk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 1.1 pk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 1.1 pk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 1.1 pk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 1.1 pk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 1.1 pk * SUCH DAMAGE. 39 1.1 pk * 40 1.1 pk * @(#)fb.c 8.1 (Berkeley) 6/11/93 41 1.1 pk */ 42 1.1 pk 43 1.1 pk /* 44 1.1 pk * /dev/fb (indirect frame buffer driver). This is gross; we should 45 1.1 pk * just build cdevsw[] dynamically. 46 1.1 pk */ 47 1.6 lukem 48 1.6 lukem #include <sys/cdefs.h> 49 1.37 chs __KERNEL_RCSID(0, "$NetBSD: fb.c,v 1.37 2019/11/10 21:16:37 chs Exp $"); 50 1.1 pk 51 1.1 pk #include <sys/param.h> 52 1.1 pk #include <sys/systm.h> 53 1.1 pk #include <sys/device.h> 54 1.1 pk #include <sys/proc.h> 55 1.1 pk #include <sys/conf.h> 56 1.21 jdc #include <sys/malloc.h> 57 1.21 jdc #include <sys/types.h> 58 1.1 pk 59 1.19 pk #include <machine/promlib.h> 60 1.1 pk #include <machine/autoconf.h> 61 1.1 pk #include <machine/kbd.h> 62 1.1 pk #include <machine/eeprom.h> 63 1.1 pk #include <sparc/dev/cons.h> 64 1.1 pk 65 1.1 pk #include <dev/sun/fbio.h> 66 1.1 pk #include <dev/sun/fbvar.h> 67 1.1 pk 68 1.5 uwe #include "kbd.h" 69 1.1 pk #include "pfour.h" 70 1.1 pk 71 1.21 jdc 72 1.21 jdc struct fbdevlist { 73 1.21 jdc struct fbdevice *fb_dev; 74 1.21 jdc struct fbdevlist *fb_next; 75 1.21 jdc }; 76 1.21 jdc 77 1.21 jdc static struct fbdevlist fblist = { 78 1.21 jdc NULL, 79 1.21 jdc NULL, 80 1.21 jdc }; 81 1.8 gehenna 82 1.8 gehenna dev_type_open(fbopen); 83 1.8 gehenna dev_type_close(fbclose); 84 1.8 gehenna dev_type_ioctl(fbioctl); 85 1.8 gehenna dev_type_poll(fbpoll); 86 1.8 gehenna dev_type_mmap(fbmmap); 87 1.10 jdolecek dev_type_kqfilter(fbkqfilter); 88 1.8 gehenna 89 1.8 gehenna const struct cdevsw fb_cdevsw = { 90 1.34 dholland .d_open = fbopen, 91 1.34 dholland .d_close = fbclose, 92 1.34 dholland .d_read = noread, 93 1.34 dholland .d_write = nowrite, 94 1.34 dholland .d_ioctl = fbioctl, 95 1.34 dholland .d_stop = nostop, 96 1.34 dholland .d_tty = notty, 97 1.34 dholland .d_poll = fbpoll, 98 1.34 dholland .d_mmap = fbmmap, 99 1.34 dholland .d_kqfilter = fbkqfilter, 100 1.35 dholland .d_discard = nodiscard, 101 1.34 dholland .d_flag = D_OTHER 102 1.8 gehenna }; 103 1.1 pk 104 1.1 pk void 105 1.31 cegger fb_unblank(void) 106 1.1 pk { 107 1.1 pk 108 1.21 jdc struct fbdevlist *fbl = &fblist; 109 1.21 jdc 110 1.21 jdc while (fbl != NULL && fbl->fb_dev != NULL) { 111 1.21 jdc (*fbl->fb_dev->fb_driver->fbd_unblank)(fbl->fb_dev->fb_device); 112 1.21 jdc fbl = fbl->fb_next; 113 1.21 jdc } 114 1.1 pk } 115 1.1 pk 116 1.1 pk /* 117 1.1 pk * Helper function for frame buffer devices. Decides whether 118 1.1 pk * the device can be the console output device according to 119 1.1 pk * PROM info. The result from this function may not be conclusive 120 1.1 pk * on machines with old PROMs; in that case, drivers should consult 121 1.1 pk * other sources of configuration information (e.g. EEPROM entries). 122 1.1 pk */ 123 1.1 pk int 124 1.29 dsl fb_is_console(int node) 125 1.1 pk { 126 1.19 pk #if !defined(SUN4U) 127 1.1 pk int fbnode; 128 1.1 pk 129 1.1 pk switch (prom_version()) { 130 1.1 pk case PROM_OLDMON: 131 1.1 pk /* `node' is not valid; just check for any fb device */ 132 1.1 pk return (prom_stdout() == PROMDEV_SCREEN); 133 1.1 pk 134 1.1 pk case PROM_OBP_V0: 135 1.1 pk /* 136 1.2 pk * First, check if prom_stdout() represents a frame buffer, 137 1.2 pk * then match on the `fb' property on the root node, if any. 138 1.1 pk */ 139 1.2 pk if (prom_stdout() != PROMDEV_SCREEN) 140 1.2 pk return (0); 141 1.2 pk 142 1.18 pk fbnode = prom_getpropint(findroot(), "fb", 0); 143 1.2 pk return (fbnode == 0 || node == fbnode); 144 1.1 pk 145 1.1 pk case PROM_OBP_V2: 146 1.1 pk case PROM_OBP_V3: 147 1.1 pk case PROM_OPENFIRM: 148 1.1 pk /* Just match the nodes */ 149 1.1 pk return (node == prom_stdout_node); 150 1.1 pk } 151 1.1 pk 152 1.1 pk return (0); 153 1.19 pk #else 154 1.19 pk return (node == prom_stdout_node); 155 1.19 pk #endif 156 1.1 pk } 157 1.1 pk 158 1.1 pk void 159 1.29 dsl fb_attach(struct fbdevice *fb, int isconsole) 160 1.1 pk { 161 1.21 jdc static int seen_force = 0; 162 1.21 jdc int nfb = 0; 163 1.21 jdc struct fbdevlist *fbl = &fblist; 164 1.1 pk 165 1.1 pk /* 166 1.21 jdc * Check to see if we're being forced into /dev/fb0, or if we're 167 1.21 jdc * the console. If we are, then move/replace the current fb0. 168 1.1 pk */ 169 1.21 jdc if ((fb->fb_flags & FB_FORCE || (isconsole && !seen_force)) && 170 1.21 jdc fblist.fb_dev != NULL) { 171 1.21 jdc while (fbl->fb_next != NULL) { 172 1.21 jdc fbl = fbl->fb_next; 173 1.21 jdc nfb++; 174 1.21 jdc } 175 1.37 chs fbl->fb_next = malloc(sizeof (struct fbdevlist), 176 1.37 chs M_DEVBUF, M_WAITOK); 177 1.37 chs fbl = fbl->fb_next; 178 1.37 chs nfb++; 179 1.37 chs fbl->fb_dev = fblist.fb_dev; 180 1.37 chs fbl->fb_next = NULL; 181 1.37 chs aprint_normal_dev(fbl->fb_dev->fb_device, 182 1.37 chs "moved to /dev/fb%d\n", nfb); 183 1.37 chs aprint_normal_dev(fbl->fb_dev->fb_device, 184 1.37 chs "attached to /dev/fb0\n"); 185 1.21 jdc fblist.fb_dev = fb; 186 1.21 jdc if (fb->fb_flags & FB_FORCE) 187 1.21 jdc seen_force = 1; 188 1.21 jdc /* Add to end of fb list. */ 189 1.21 jdc } else { 190 1.21 jdc if (fblist.fb_dev != NULL) { 191 1.21 jdc while (fbl->fb_next != NULL) { 192 1.21 jdc fbl = fbl->fb_next; 193 1.21 jdc nfb++; 194 1.21 jdc } 195 1.37 chs fbl->fb_next = malloc(sizeof (struct fbdevlist), 196 1.37 chs M_DEVBUF, M_WAITOK); 197 1.21 jdc fbl = fbl->fb_next; 198 1.21 jdc nfb++; 199 1.21 jdc } 200 1.21 jdc fbl->fb_dev = fb; 201 1.21 jdc fbl->fb_next = NULL; 202 1.33 mrg aprint_normal_dev(fbl->fb_dev->fb_device, 203 1.33 mrg "attached to /dev/fb%d\n", nfb); 204 1.1 pk } 205 1.1 pk } 206 1.1 pk 207 1.1 pk int 208 1.30 dsl fbopen(dev_t dev, int flags, int mode, struct lwp *l) 209 1.1 pk { 210 1.22 macallan int unit, nunit; 211 1.21 jdc struct fbdevlist *fbl = &fblist; 212 1.1 pk 213 1.21 jdc unit = minor(dev); 214 1.21 jdc while (unit-- && fbl != NULL) 215 1.21 jdc fbl = fbl->fb_next; 216 1.21 jdc if (fbl == NULL || fbl->fb_dev == NULL) 217 1.1 pk return (ENXIO); 218 1.22 macallan 219 1.24 thorpej nunit = device_unit(fbl->fb_dev->fb_device); 220 1.22 macallan return (fbl->fb_dev->fb_driver->fbd_open)(makedev(0, nunit), flags, 221 1.23 christos mode, l); 222 1.1 pk } 223 1.1 pk 224 1.1 pk int 225 1.30 dsl fbclose(dev_t dev, int flags, int mode, struct lwp *l) 226 1.1 pk { 227 1.22 macallan int unit, nunit; 228 1.21 jdc struct fbdevlist *fbl = &fblist; 229 1.21 jdc 230 1.21 jdc unit = minor(dev); 231 1.21 jdc while (unit-- && fbl != NULL) 232 1.21 jdc fbl = fbl->fb_next; 233 1.21 jdc if (fbl == NULL || fbl->fb_dev == NULL) 234 1.21 jdc return (ENXIO); 235 1.1 pk 236 1.24 thorpej nunit = device_unit(fbl->fb_dev->fb_device); 237 1.22 macallan return (fbl->fb_dev->fb_driver->fbd_close)(makedev(0, nunit), flags, 238 1.23 christos mode, l); 239 1.1 pk } 240 1.1 pk 241 1.1 pk int 242 1.29 dsl fbioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l) 243 1.1 pk { 244 1.22 macallan int unit, nunit; 245 1.21 jdc struct fbdevlist *fbl = &fblist; 246 1.1 pk 247 1.21 jdc unit = minor(dev); 248 1.21 jdc while (unit-- && fbl != NULL) 249 1.21 jdc fbl = fbl->fb_next; 250 1.21 jdc if (fbl == NULL || fbl->fb_dev == NULL) 251 1.21 jdc return (ENXIO); 252 1.21 jdc 253 1.24 thorpej nunit = device_unit(fbl->fb_dev->fb_device); 254 1.22 macallan return (fbl->fb_dev->fb_driver->fbd_ioctl)(makedev(0, nunit), cmd, 255 1.23 christos data, flags, l); 256 1.1 pk } 257 1.1 pk 258 1.1 pk int 259 1.29 dsl fbpoll(dev_t dev, int events, struct lwp *l) 260 1.1 pk { 261 1.22 macallan int unit, nunit; 262 1.21 jdc struct fbdevlist *fbl = &fblist; 263 1.1 pk 264 1.21 jdc unit = minor(dev); 265 1.21 jdc while (unit-- && fbl != NULL) 266 1.21 jdc fbl = fbl->fb_next; 267 1.21 jdc if (fbl == NULL || fbl->fb_dev == NULL) 268 1.21 jdc return (ENXIO); 269 1.21 jdc 270 1.24 thorpej nunit = device_unit(fbl->fb_dev->fb_device); 271 1.22 macallan return (fbl->fb_dev->fb_driver->fbd_poll)(makedev(0, nunit), events, 272 1.23 christos l); 273 1.10 jdolecek } 274 1.10 jdolecek 275 1.10 jdolecek int 276 1.29 dsl fbkqfilter(dev_t dev, struct knote *kn) 277 1.10 jdolecek { 278 1.22 macallan int unit, nunit; 279 1.21 jdc struct fbdevlist *fbl = &fblist; 280 1.10 jdolecek 281 1.21 jdc unit = minor(dev); 282 1.21 jdc while (unit-- && fbl != NULL) 283 1.21 jdc fbl = fbl->fb_next; 284 1.21 jdc if (fbl == NULL || fbl->fb_dev == NULL) 285 1.21 jdc return (ENXIO); 286 1.21 jdc 287 1.24 thorpej nunit = device_unit(fbl->fb_dev->fb_device); 288 1.22 macallan return (fbl->fb_dev->fb_driver->fbd_kqfilter)(makedev(0, nunit), kn); 289 1.1 pk } 290 1.1 pk 291 1.1 pk paddr_t 292 1.29 dsl fbmmap(dev_t dev, off_t off, int prot) 293 1.1 pk { 294 1.22 macallan int unit, nunit; 295 1.21 jdc struct fbdevlist *fbl = &fblist; 296 1.21 jdc 297 1.21 jdc unit = minor(dev); 298 1.21 jdc while (unit-- && fbl != NULL) 299 1.21 jdc fbl = fbl->fb_next; 300 1.21 jdc if (fbl == NULL || fbl->fb_dev == NULL) 301 1.21 jdc return (ENXIO); 302 1.21 jdc 303 1.24 thorpej nunit = device_unit(fbl->fb_dev->fb_device); 304 1.21 jdc paddr_t (*map)(dev_t, off_t, int) = fbl->fb_dev->fb_driver->fbd_mmap; 305 1.1 pk 306 1.1 pk if (map == NULL) 307 1.1 pk return (-1); 308 1.22 macallan return (map(makedev(0, nunit), off, prot)); 309 1.1 pk } 310 1.1 pk 311 1.1 pk void 312 1.30 dsl fb_setsize_obp(struct fbdevice *fb, int depth, int def_width, int def_height, int node) 313 1.1 pk { 314 1.18 pk fb->fb_type.fb_width = prom_getpropint(node, "width", def_width); 315 1.18 pk fb->fb_type.fb_height = prom_getpropint(node, "height", def_height); 316 1.18 pk fb->fb_linebytes = prom_getpropint(node, "linebytes", 317 1.1 pk (fb->fb_type.fb_width * depth) / 8); 318 1.1 pk } 319 1.1 pk 320 1.1 pk void 321 1.30 dsl fb_setsize_eeprom(struct fbdevice *fb, int depth, int def_width, int def_height) 322 1.1 pk { 323 1.7 fredette #if !defined(SUN4U) 324 1.1 pk struct eeprom *eep = (struct eeprom *)eeprom_va; 325 1.1 pk 326 1.1 pk if (!CPU_ISSUN4) { 327 1.1 pk printf("fb_setsize_eeprom: not sun4\n"); 328 1.1 pk return; 329 1.1 pk } 330 1.1 pk 331 1.1 pk /* Set up some defaults. */ 332 1.1 pk fb->fb_type.fb_width = def_width; 333 1.1 pk fb->fb_type.fb_height = def_height; 334 1.1 pk 335 1.1 pk if (fb->fb_flags & FB_PFOUR) { 336 1.1 pk #if NPFOUR > 0 337 1.1 pk fb_setsize_pfour(fb); 338 1.1 pk #endif 339 1.1 pk } else if (eep != NULL) { 340 1.1 pk switch (eep->eeScreenSize) { 341 1.1 pk case EE_SCR_1152X900: 342 1.1 pk fb->fb_type.fb_width = 1152; 343 1.1 pk fb->fb_type.fb_height = 900; 344 1.1 pk break; 345 1.1 pk 346 1.1 pk case EE_SCR_1024X1024: 347 1.1 pk fb->fb_type.fb_width = 1024; 348 1.1 pk fb->fb_type.fb_height = 1024; 349 1.1 pk break; 350 1.1 pk 351 1.1 pk case EE_SCR_1600X1280: 352 1.1 pk fb->fb_type.fb_width = 1600; 353 1.1 pk fb->fb_type.fb_height = 1280; 354 1.1 pk break; 355 1.1 pk 356 1.1 pk case EE_SCR_1440X1440: 357 1.1 pk fb->fb_type.fb_width = 1440; 358 1.1 pk fb->fb_type.fb_height = 1440; 359 1.1 pk break; 360 1.1 pk 361 1.1 pk default: 362 1.1 pk /* 363 1.1 pk * XXX: Do nothing, I guess. 364 1.1 pk * Should we print a warning about 365 1.1 pk * an unknown value? --thorpej 366 1.1 pk */ 367 1.1 pk break; 368 1.1 pk } 369 1.1 pk } 370 1.1 pk 371 1.1 pk fb->fb_linebytes = (fb->fb_type.fb_width * depth) / 8; 372 1.7 fredette #endif /* !SUN4U */ 373 1.1 pk } 374