fb.c revision 42831
1/*- 2 * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer as 10 * the first lines of this file unmodified. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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 * $Id: fb.c,v 1.2 1999/01/12 10:35:50 yokota Exp $ 29 */ 30 31#include "fb.h" 32#include "opt_fb.h" 33 34#include <sys/param.h> 35#include <sys/systm.h> 36#include <sys/conf.h> 37#include <sys/kernel.h> 38#include <sys/malloc.h> 39 40#include <machine/console.h> 41 42#include <dev/fb/fbreg.h> 43 44/* local arrays */ 45 46/* 47 * We need at least one entry each in order to initialize a video card 48 * for the kernel console. The arrays will be increased dynamically 49 * when necessary. 50 */ 51 52static int adapters = 1; 53static video_adapter_t *adp_ini; 54static video_adapter_t **adapter = &adp_ini; 55static video_switch_t *vidsw_ini; 56 video_switch_t **vidsw = &vidsw_ini; 57 58#ifdef FB_INSTALL_CDEV 59 60#define ARRAY_DELTA 4 61 62static struct cdevsw *vidcdevsw_ini; 63static struct cdevsw **vidcdevsw = &vidcdevsw_ini; 64 65static void 66vid_realloc_array(void) 67{ 68 video_adapter_t **new_adp; 69 video_switch_t **new_vidsw; 70 struct cdevsw **new_cdevsw; 71 int newsize; 72 int s; 73 74 s = spltty(); 75 newsize = ((adapters + ARRAY_DELTA)/ARRAY_DELTA)*ARRAY_DELTA; 76 new_adp = malloc(sizeof(*new_adp)*newsize, M_DEVBUF, M_WAITOK); 77 new_vidsw = malloc(sizeof(*new_vidsw)*newsize, M_DEVBUF, M_WAITOK); 78 new_cdevsw = malloc(sizeof(*new_cdevsw)*newsize, M_DEVBUF, M_WAITOK); 79 bzero(new_adp, sizeof(*new_adp)*newsize); 80 bzero(new_vidsw, sizeof(*new_vidsw)*newsize); 81 bzero(new_cdevsw, sizeof(*new_cdevsw)*newsize); 82 bcopy(adapter, new_adp, sizeof(*adapter)*adapters); 83 bcopy(vidsw, new_vidsw, sizeof(*vidsw)*adapters); 84 bcopy(vidcdevsw, new_cdevsw, sizeof(*vidcdevsw)*adapters); 85 if (adapters > 1) { 86 free(adapter, M_DEVBUF); 87 free(vidsw, M_DEVBUF); 88 free(vidcdevsw, M_DEVBUF); 89 } 90 adapter = new_adp; 91 vidsw = new_vidsw; 92 vidcdevsw = new_cdevsw; 93 adapters = newsize; 94 splx(s); 95 96 if (bootverbose) 97 printf("fb: new array size %d\n", adapters); 98} 99 100#endif /* FB_INSTALL_CDEV */ 101 102/* 103 * Low-level frame buffer driver functions 104 * frame buffer subdrivers, such as the VGA driver, call these functions 105 * to initialize the video_adapter structure and register it to the virtual 106 * frame buffer driver `fb'. 107 */ 108 109/* initialize the video_adapter_t structure */ 110void 111vid_init_struct(video_adapter_t *adp, char *name, int type, int unit) 112{ 113 adp->va_flags = 0; 114 adp->va_name = name; 115 adp->va_type = type; 116 adp->va_unit = unit; 117} 118 119/* Register a video adapter */ 120int 121vid_register(video_adapter_t *adp) 122{ 123 video_driver_t **list; 124 video_driver_t *p; 125 int index; 126 127 for (index = 0; index < adapters; ++index) { 128 if (adapter[index] == NULL) 129 break; 130 } 131 if (index >= adapters) 132 return -1; 133 134 adp->va_index = index; 135 adp->va_token = NULL; 136 list = (video_driver_t **)videodriver_set.ls_items; 137 while ((p = *list++) != NULL) { 138 if (strcmp(p->name, adp->va_name) == 0) { 139 adapter[index] = adp; 140 vidsw[index] = p->vidsw; 141 return index; 142 } 143 } 144 145 return -1; 146} 147 148int 149vid_unregister(video_adapter_t *adp) 150{ 151 if ((adp->va_index < 0) || (adp->va_index >= adapters)) 152 return ENOENT; 153 if (adapter[adp->va_index] != adp) 154 return ENOENT; 155 156 adapter[adp->va_index] = NULL; 157 vidsw[adp->va_index] = NULL; 158 return 0; 159} 160 161/* Get video I/O function table */ 162video_switch_t 163*vid_get_switch(char *name) 164{ 165 video_driver_t **list; 166 video_driver_t *p; 167 168 list = (video_driver_t **)videodriver_set.ls_items; 169 while ((p = *list++) != NULL) { 170 if (strcmp(p->name, name) == 0) 171 return p->vidsw; 172 } 173 174 return NULL; 175} 176 177/* 178 * Video card client functions 179 * Video card clients, such as the console driver `syscons' and the frame 180 * buffer cdev driver, use these functions to claim and release a card for 181 * exclusive use. 182 */ 183 184/* find the video card specified by a driver name and a unit number */ 185int 186vid_find_adapter(char *driver, int unit) 187{ 188 int i; 189 190 for (i = 0; i < adapters; ++i) { 191 if (adapter[i] == NULL) 192 continue; 193 if (strcmp("*", driver) && strcmp(adapter[i]->va_name, driver)) 194 continue; 195 if ((unit != -1) && (adapter[i]->va_unit != unit)) 196 continue; 197 return i; 198 } 199 return -1; 200} 201 202/* allocate a video card */ 203int 204vid_allocate(char *driver, int unit, void *id) 205{ 206 int index; 207 int s; 208 209 s = spltty(); 210 index = vid_find_adapter(driver, unit); 211 if (index >= 0) { 212 if (adapter[index]->va_token) { 213 splx(s); 214 return -1; 215 } 216 adapter[index]->va_token = id; 217 } 218 splx(s); 219 return index; 220} 221 222int 223vid_release(video_adapter_t *adp, void *id) 224{ 225 int error; 226 int s; 227 228 s = spltty(); 229 if (adp->va_token == NULL) { 230 error = EINVAL; 231 } else if (adp->va_token != id) { 232 error = EPERM; 233 } else { 234 adp->va_token = NULL; 235 error = 0; 236 } 237 splx(s); 238 return error; 239} 240 241/* Get a video adapter structure */ 242video_adapter_t 243*vid_get_adapter(int index) 244{ 245 if ((index < 0) || (index >= adapters)) 246 return NULL; 247 return adapter[index]; 248} 249 250/* Configure drivers: this is a backdoor for the console driver XXX */ 251int 252vid_configure(int flags) 253{ 254 video_driver_t **list; 255 video_driver_t *p; 256 257 list = (video_driver_t **)videodriver_set.ls_items; 258 while ((p = *list++) != NULL) { 259 if (p->configure != NULL) 260 (*p->configure)(flags); 261 } 262 263 return 0; 264} 265 266/* 267 * Virtual frame buffer cdev driver functions 268 * The virtual frame buffer driver dispatches driver functions to 269 * appropriate subdrivers. 270 */ 271 272#define DRIVER_NAME "fb" 273 274#ifdef FB_INSTALL_CDEV 275 276#define FB_UNIT(dev) minor(dev) 277#define FB_MKMINOR(unit) (u) 278 279#if notyet 280 281static d_open_t fbopen; 282static d_close_t fbclose; 283static d_ioctl_t fbioctl; 284static d_mmap_t fbmmap; 285 286#define CDEV_MAJOR 141 /* XXX */ 287 288static struct cdevsw fb_cdevsw = { 289 fbopen, fbclose, noread, nowrite, /* ??? */ 290 fbioctl, nostop, nullreset, nodevtotty, 291 seltrue, fbmmap, NULL, DRIVER_NAME, 292 NULL, -1, nodump, nopsize, 293}; 294 295static void 296vfbattach(void *arg) 297{ 298 static int fb_devsw_installed = FALSE; 299 dev_t dev; 300 301 if (!fb_devsw_installed) { 302 dev = makedev(CDEV_MAJOR, 0); 303 cdevsw_add(&dev, &fb_cdevsw, NULL); 304 fb_devsw_installed = TRUE; 305 } 306} 307 308PSEUDO_SET(vfbattach, fb); 309 310#endif /* notyet */ 311 312int 313fb_attach(dev_t dev, video_adapter *adp, struct cdevsw *cdevsw) 314{ 315 int s; 316 317 if (adp->va_index >= adapters) 318 return EINVAL; 319 if (adapter[adp->va_index] != adp) 320 return EINVAL; 321 322 s = spltty(); 323 adp->va_minor = minor(dev); 324 vidcdevsw[adp->va_index] = cdevsw; 325 splx(s); 326 327 /* XXX: DEVFS? */ 328 329 if (adp->va_index + 1 >= adapters) 330 vid_realloc_array(); 331 332 printf("fb%d at %s%d\n", adp->va_index, adp->va_name, adp->va_unit); 333 return 0; 334} 335 336int 337fb_detach(dev_t dev, video_adapter *adp, struct cdevsw *cdevsw) 338{ 339 int s; 340 341 if (adp->va_index >= adapters) 342 return EINVAL; 343 if (adapter[adp->va_index] != adp) 344 return EINVAL; 345 if (vidcdevsw[adp->va_index] != cdevsw) 346 return EINVAL; 347 348 s = spltty(); 349 vidcdevsw[adp->va_index] = NULL; 350 splx(s); 351 return 0; 352} 353 354#endif /* FB_INSTALL_CDEV */ 355 356static char 357*adapter_name(int type) 358{ 359 static struct { 360 int type; 361 char *name; 362 } names[] = { 363 { KD_MONO, "MDA" }, 364 { KD_HERCULES, "Hercules" }, 365 { KD_CGA, "CGA" }, 366 { KD_EGA, "EGA" }, 367 { KD_VGA, "VGA" }, 368 { KD_PC98, "PC-98x1" }, 369 { -1, "Unknown" }, 370 }; 371 int i; 372 373 for (i = 0; names[i].type != -1; ++i) 374 if (names[i].type == type) 375 break; 376 return names[i].name; 377} 378 379void 380fb_dump_adp_info(char *driver, video_adapter_t *adp, int level) 381{ 382 if (level <= 0) 383 return; 384 385 printf("%s%d: %s%d, %s, type:%s (%d), flags:0x%x\n", 386 DRIVER_NAME, adp->va_index, driver, adp->va_unit, adp->va_name, 387 adapter_name(adp->va_type), adp->va_type, adp->va_flags); 388 printf("%s%d: port:0x%x-0x%x, crtc:0x%x, mem:0x%x 0x%x\n", 389 DRIVER_NAME, adp->va_index, 390 adp->va_io_base, adp->va_io_base + adp->va_io_size - 1, 391 adp->va_crtc_addr, adp->va_mem_base, adp->va_mem_size); 392 printf("%s%d: init mode:%d, bios mode:%d, current mode:%d\n", 393 DRIVER_NAME, adp->va_index, 394 adp->va_initial_mode, adp->va_initial_bios_mode, adp->va_mode); 395 printf("%s%d: window:0x%x size:%dk gran:%dk, buf:0x%x size:%dk\n", 396 DRIVER_NAME, adp->va_index, 397 adp->va_window, (int)adp->va_window_size/1024, 398 (int)adp->va_window_gran/1024, adp->va_buffer, 399 (int)adp->va_buffer_size/1024); 400} 401 402void 403fb_dump_mode_info(char *driver, video_adapter_t *adp, video_info_t *info, 404 int level) 405{ 406 if (level <= 0) 407 return; 408 409 printf("%s%d: %s, mode:%d, flags:0x%x ", 410 driver, adp->va_unit, adp->va_name, info->vi_mode, info->vi_flags); 411 if (info->vi_flags & V_INFO_GRAPHICS) 412 printf("G %dx%dx%d, %d plane(s), font:%dx%d, ", 413 info->vi_width, info->vi_height, 414 info->vi_depth, info->vi_planes, 415 info->vi_cwidth, info->vi_cheight); 416 else 417 printf("T %dx%d, font:%dx%d, ", 418 info->vi_width, info->vi_height, 419 info->vi_cwidth, info->vi_cheight); 420 printf("win:0x%x\n", info->vi_window); 421} 422