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