fb.c revision 47640
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.4 1999/05/30 16:51:23 phk 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 /* open */ fbopen, 290 /* close */ fbclose, 291 /* read */ noread, 292 /* write */ nowrite, 293 /* ioctl */ fbioctl, 294 /* stop */ nostop, 295 /* reset */ noreset, 296 /* devtotty */ nodevtotty, 297 /* poll */ nopoll, 298 /* mmap */ fbmmap, 299 /* strategy */ nostrategy, 300 /* name */ DRIVER_NAME, 301 /* parms */ noparms, 302 /* maj */ CDEV_MAJOR, 303 /* dump */ nodump, 304 /* psize */ nopsize, 305 /* flags */ 0, 306 /* maxio */ 0, 307 /* bmaj */ -1 308}; 309 310static void 311vfbattach(void *arg) 312{ 313 static int fb_devsw_installed = FALSE; 314 315 if (!fb_devsw_installed) { 316 cdevsw_add(&fb_cdevsw); 317 fb_devsw_installed = TRUE; 318 } 319} 320 321PSEUDO_SET(vfbattach, fb); 322 323#endif /* notyet */ 324 325int 326fb_attach(dev_t dev, video_adapter *adp, struct cdevsw *cdevsw) 327{ 328 int s; 329 330 if (adp->va_index >= adapters) 331 return EINVAL; 332 if (adapter[adp->va_index] != adp) 333 return EINVAL; 334 335 s = spltty(); 336 adp->va_minor = minor(dev); 337 vidcdevsw[adp->va_index] = cdevsw; 338 splx(s); 339 340 /* XXX: DEVFS? */ 341 342 if (adp->va_index + 1 >= adapters) 343 vid_realloc_array(); 344 345 printf("fb%d at %s%d\n", adp->va_index, adp->va_name, adp->va_unit); 346 return 0; 347} 348 349int 350fb_detach(dev_t dev, video_adapter *adp, struct cdevsw *cdevsw) 351{ 352 int s; 353 354 if (adp->va_index >= adapters) 355 return EINVAL; 356 if (adapter[adp->va_index] != adp) 357 return EINVAL; 358 if (vidcdevsw[adp->va_index] != cdevsw) 359 return EINVAL; 360 361 s = spltty(); 362 vidcdevsw[adp->va_index] = NULL; 363 splx(s); 364 return 0; 365} 366 367#endif /* FB_INSTALL_CDEV */ 368 369static char 370*adapter_name(int type) 371{ 372 static struct { 373 int type; 374 char *name; 375 } names[] = { 376 { KD_MONO, "MDA" }, 377 { KD_HERCULES, "Hercules" }, 378 { KD_CGA, "CGA" }, 379 { KD_EGA, "EGA" }, 380 { KD_VGA, "VGA" }, 381 { KD_PC98, "PC-98x1" }, 382 { -1, "Unknown" }, 383 }; 384 int i; 385 386 for (i = 0; names[i].type != -1; ++i) 387 if (names[i].type == type) 388 break; 389 return names[i].name; 390} 391 392void 393fb_dump_adp_info(char *driver, video_adapter_t *adp, int level) 394{ 395 if (level <= 0) 396 return; 397 398 printf("%s%d: %s%d, %s, type:%s (%d), flags:0x%x\n", 399 DRIVER_NAME, adp->va_index, driver, adp->va_unit, adp->va_name, 400 adapter_name(adp->va_type), adp->va_type, adp->va_flags); 401 printf("%s%d: port:0x%x-0x%x, crtc:0x%x, mem:0x%x 0x%x\n", 402 DRIVER_NAME, adp->va_index, 403 adp->va_io_base, adp->va_io_base + adp->va_io_size - 1, 404 adp->va_crtc_addr, adp->va_mem_base, adp->va_mem_size); 405 printf("%s%d: init mode:%d, bios mode:%d, current mode:%d\n", 406 DRIVER_NAME, adp->va_index, 407 adp->va_initial_mode, adp->va_initial_bios_mode, adp->va_mode); 408 printf("%s%d: window:0x%x size:%dk gran:%dk, buf:0x%x size:%dk\n", 409 DRIVER_NAME, adp->va_index, 410 adp->va_window, (int)adp->va_window_size/1024, 411 (int)adp->va_window_gran/1024, adp->va_buffer, 412 (int)adp->va_buffer_size/1024); 413} 414 415void 416fb_dump_mode_info(char *driver, video_adapter_t *adp, video_info_t *info, 417 int level) 418{ 419 if (level <= 0) 420 return; 421 422 printf("%s%d: %s, mode:%d, flags:0x%x ", 423 driver, adp->va_unit, adp->va_name, info->vi_mode, info->vi_flags); 424 if (info->vi_flags & V_INFO_GRAPHICS) 425 printf("G %dx%dx%d, %d plane(s), font:%dx%d, ", 426 info->vi_width, info->vi_height, 427 info->vi_depth, info->vi_planes, 428 info->vi_cwidth, info->vi_cheight); 429 else 430 printf("T %dx%d, font:%dx%d, ", 431 info->vi_width, info->vi_height, 432 info->vi_cwidth, info->vi_cheight); 433 printf("win:0x%x\n", info->vi_window); 434} 435