fb.c revision 42831
142421Syokota/*- 242421Syokota * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> 342421Syokota * All rights reserved. 442421Syokota * 542421Syokota * Redistribution and use in source and binary forms, with or without 642421Syokota * modification, are permitted provided that the following conditions 742421Syokota * are met: 842421Syokota * 1. Redistributions of source code must retain the above copyright 942421Syokota * notice, this list of conditions and the following disclaimer as 1042421Syokota * the first lines of this file unmodified. 1142421Syokota * 2. Redistributions in binary form must reproduce the above copyright 1242421Syokota * notice, this list of conditions and the following disclaimer in the 1342421Syokota * documentation and/or other materials provided with the distribution. 1442421Syokota * 3. The name of the author may not be used to endorse or promote products 1542421Syokota * derived from this software without specific prior written permission. 1642421Syokota * 1742421Syokota * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 1842421Syokota * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1942421Syokota * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2042421Syokota * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 2142421Syokota * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2242421Syokota * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2342421Syokota * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2442421Syokota * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2542421Syokota * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2642421Syokota * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2742421Syokota * 2842831Syokota * $Id: fb.c,v 1.2 1999/01/12 10:35:50 yokota Exp $ 2942421Syokota */ 3042421Syokota 3142421Syokota#include "fb.h" 3242421Syokota#include "opt_fb.h" 3342421Syokota 3442421Syokota#include <sys/param.h> 3542421Syokota#include <sys/systm.h> 3642421Syokota#include <sys/conf.h> 3742421Syokota#include <sys/kernel.h> 3842421Syokota#include <sys/malloc.h> 3942421Syokota 4042421Syokota#include <machine/console.h> 4142421Syokota 4242421Syokota#include <dev/fb/fbreg.h> 4342421Syokota 4442421Syokota/* local arrays */ 4542421Syokota 4642421Syokota/* 4742421Syokota * We need at least one entry each in order to initialize a video card 4842421Syokota * for the kernel console. The arrays will be increased dynamically 4942421Syokota * when necessary. 5042421Syokota */ 5142564Syokota 5242564Syokotastatic int adapters = 1; 5342421Syokotastatic video_adapter_t *adp_ini; 5442564Syokotastatic video_adapter_t **adapter = &adp_ini; 5542421Syokotastatic video_switch_t *vidsw_ini; 5642421Syokota video_switch_t **vidsw = &vidsw_ini; 5742421Syokota 5842564Syokota#ifdef FB_INSTALL_CDEV 5942564Syokota 6042421Syokota#define ARRAY_DELTA 4 6142421Syokota 6242564Syokotastatic struct cdevsw *vidcdevsw_ini; 6342564Syokotastatic struct cdevsw **vidcdevsw = &vidcdevsw_ini; 6442564Syokota 6542421Syokotastatic void 6642421Syokotavid_realloc_array(void) 6742421Syokota{ 6842421Syokota video_adapter_t **new_adp; 6942421Syokota video_switch_t **new_vidsw; 7042421Syokota struct cdevsw **new_cdevsw; 7142421Syokota int newsize; 7242421Syokota int s; 7342421Syokota 7442421Syokota s = spltty(); 7542421Syokota newsize = ((adapters + ARRAY_DELTA)/ARRAY_DELTA)*ARRAY_DELTA; 7642421Syokota new_adp = malloc(sizeof(*new_adp)*newsize, M_DEVBUF, M_WAITOK); 7742421Syokota new_vidsw = malloc(sizeof(*new_vidsw)*newsize, M_DEVBUF, M_WAITOK); 7842421Syokota new_cdevsw = malloc(sizeof(*new_cdevsw)*newsize, M_DEVBUF, M_WAITOK); 7942421Syokota bzero(new_adp, sizeof(*new_adp)*newsize); 8042421Syokota bzero(new_vidsw, sizeof(*new_vidsw)*newsize); 8142421Syokota bzero(new_cdevsw, sizeof(*new_cdevsw)*newsize); 8242421Syokota bcopy(adapter, new_adp, sizeof(*adapter)*adapters); 8342421Syokota bcopy(vidsw, new_vidsw, sizeof(*vidsw)*adapters); 8442421Syokota bcopy(vidcdevsw, new_cdevsw, sizeof(*vidcdevsw)*adapters); 8542421Syokota if (adapters > 1) { 8642421Syokota free(adapter, M_DEVBUF); 8742421Syokota free(vidsw, M_DEVBUF); 8842421Syokota free(vidcdevsw, M_DEVBUF); 8942421Syokota } 9042421Syokota adapter = new_adp; 9142421Syokota vidsw = new_vidsw; 9242421Syokota vidcdevsw = new_cdevsw; 9342421Syokota adapters = newsize; 9442421Syokota splx(s); 9542421Syokota 9642421Syokota if (bootverbose) 9742421Syokota printf("fb: new array size %d\n", adapters); 9842421Syokota} 9942421Syokota 10042564Syokota#endif /* FB_INSTALL_CDEV */ 10142564Syokota 10242421Syokota/* 10342421Syokota * Low-level frame buffer driver functions 10442421Syokota * frame buffer subdrivers, such as the VGA driver, call these functions 10542421Syokota * to initialize the video_adapter structure and register it to the virtual 10642421Syokota * frame buffer driver `fb'. 10742421Syokota */ 10842421Syokota 10942421Syokota/* initialize the video_adapter_t structure */ 11042421Syokotavoid 11142421Syokotavid_init_struct(video_adapter_t *adp, char *name, int type, int unit) 11242421Syokota{ 11342421Syokota adp->va_flags = 0; 11442421Syokota adp->va_name = name; 11542421Syokota adp->va_type = type; 11642421Syokota adp->va_unit = unit; 11742421Syokota} 11842421Syokota 11942421Syokota/* Register a video adapter */ 12042421Syokotaint 12142421Syokotavid_register(video_adapter_t *adp) 12242421Syokota{ 12342421Syokota video_driver_t **list; 12442421Syokota video_driver_t *p; 12542421Syokota int index; 12642421Syokota 12742421Syokota for (index = 0; index < adapters; ++index) { 12842421Syokota if (adapter[index] == NULL) 12942421Syokota break; 13042421Syokota } 13142421Syokota if (index >= adapters) 13242421Syokota return -1; 13342421Syokota 13442421Syokota adp->va_index = index; 13542421Syokota adp->va_token = NULL; 13642421Syokota list = (video_driver_t **)videodriver_set.ls_items; 13742421Syokota while ((p = *list++) != NULL) { 13842421Syokota if (strcmp(p->name, adp->va_name) == 0) { 13942421Syokota adapter[index] = adp; 14042421Syokota vidsw[index] = p->vidsw; 14142421Syokota return index; 14242421Syokota } 14342421Syokota } 14442421Syokota 14542421Syokota return -1; 14642421Syokota} 14742421Syokota 14842421Syokotaint 14942421Syokotavid_unregister(video_adapter_t *adp) 15042421Syokota{ 15142421Syokota if ((adp->va_index < 0) || (adp->va_index >= adapters)) 15242421Syokota return ENOENT; 15342421Syokota if (adapter[adp->va_index] != adp) 15442421Syokota return ENOENT; 15542421Syokota 15642421Syokota adapter[adp->va_index] = NULL; 15742421Syokota vidsw[adp->va_index] = NULL; 15842421Syokota return 0; 15942421Syokota} 16042421Syokota 16142421Syokota/* Get video I/O function table */ 16242421Syokotavideo_switch_t 16342421Syokota*vid_get_switch(char *name) 16442421Syokota{ 16542421Syokota video_driver_t **list; 16642421Syokota video_driver_t *p; 16742421Syokota 16842421Syokota list = (video_driver_t **)videodriver_set.ls_items; 16942421Syokota while ((p = *list++) != NULL) { 17042421Syokota if (strcmp(p->name, name) == 0) 17142421Syokota return p->vidsw; 17242421Syokota } 17342421Syokota 17442421Syokota return NULL; 17542421Syokota} 17642421Syokota 17742421Syokota/* 17842421Syokota * Video card client functions 17942421Syokota * Video card clients, such as the console driver `syscons' and the frame 18042421Syokota * buffer cdev driver, use these functions to claim and release a card for 18142421Syokota * exclusive use. 18242421Syokota */ 18342421Syokota 18442421Syokota/* find the video card specified by a driver name and a unit number */ 18542421Syokotaint 18642421Syokotavid_find_adapter(char *driver, int unit) 18742421Syokota{ 18842421Syokota int i; 18942421Syokota 19042421Syokota for (i = 0; i < adapters; ++i) { 19142421Syokota if (adapter[i] == NULL) 19242421Syokota continue; 19342421Syokota if (strcmp("*", driver) && strcmp(adapter[i]->va_name, driver)) 19442421Syokota continue; 19542421Syokota if ((unit != -1) && (adapter[i]->va_unit != unit)) 19642421Syokota continue; 19742421Syokota return i; 19842421Syokota } 19942421Syokota return -1; 20042421Syokota} 20142421Syokota 20242421Syokota/* allocate a video card */ 20342421Syokotaint 20442421Syokotavid_allocate(char *driver, int unit, void *id) 20542421Syokota{ 20642421Syokota int index; 20742421Syokota int s; 20842421Syokota 20942421Syokota s = spltty(); 21042421Syokota index = vid_find_adapter(driver, unit); 21142421Syokota if (index >= 0) { 21242421Syokota if (adapter[index]->va_token) { 21342421Syokota splx(s); 21442421Syokota return -1; 21542421Syokota } 21642421Syokota adapter[index]->va_token = id; 21742421Syokota } 21842421Syokota splx(s); 21942421Syokota return index; 22042421Syokota} 22142421Syokota 22242421Syokotaint 22342421Syokotavid_release(video_adapter_t *adp, void *id) 22442421Syokota{ 22542421Syokota int error; 22642421Syokota int s; 22742421Syokota 22842421Syokota s = spltty(); 22942421Syokota if (adp->va_token == NULL) { 23042421Syokota error = EINVAL; 23142421Syokota } else if (adp->va_token != id) { 23242421Syokota error = EPERM; 23342421Syokota } else { 23442421Syokota adp->va_token = NULL; 23542421Syokota error = 0; 23642421Syokota } 23742421Syokota splx(s); 23842421Syokota return error; 23942421Syokota} 24042421Syokota 24142421Syokota/* Get a video adapter structure */ 24242421Syokotavideo_adapter_t 24342421Syokota*vid_get_adapter(int index) 24442421Syokota{ 24542421Syokota if ((index < 0) || (index >= adapters)) 24642421Syokota return NULL; 24742421Syokota return adapter[index]; 24842421Syokota} 24942421Syokota 25042421Syokota/* Configure drivers: this is a backdoor for the console driver XXX */ 25142421Syokotaint 25242421Syokotavid_configure(int flags) 25342421Syokota{ 25442421Syokota video_driver_t **list; 25542421Syokota video_driver_t *p; 25642421Syokota 25742421Syokota list = (video_driver_t **)videodriver_set.ls_items; 25842421Syokota while ((p = *list++) != NULL) { 25942421Syokota if (p->configure != NULL) 26042421Syokota (*p->configure)(flags); 26142421Syokota } 26242421Syokota 26342421Syokota return 0; 26442421Syokota} 26542421Syokota 26642421Syokota/* 26742421Syokota * Virtual frame buffer cdev driver functions 26842421Syokota * The virtual frame buffer driver dispatches driver functions to 26942421Syokota * appropriate subdrivers. 27042421Syokota */ 27142421Syokota 27242421Syokota#define DRIVER_NAME "fb" 27342421Syokota 27442421Syokota#ifdef FB_INSTALL_CDEV 27542421Syokota 27642421Syokota#define FB_UNIT(dev) minor(dev) 27742421Syokota#define FB_MKMINOR(unit) (u) 27842421Syokota 27942421Syokota#if notyet 28042421Syokota 28142421Syokotastatic d_open_t fbopen; 28242421Syokotastatic d_close_t fbclose; 28342421Syokotastatic d_ioctl_t fbioctl; 28442421Syokotastatic d_mmap_t fbmmap; 28542421Syokota 28642421Syokota#define CDEV_MAJOR 141 /* XXX */ 28742421Syokota 28842421Syokotastatic struct cdevsw fb_cdevsw = { 28942421Syokota fbopen, fbclose, noread, nowrite, /* ??? */ 29042421Syokota fbioctl, nostop, nullreset, nodevtotty, 29142421Syokota seltrue, fbmmap, NULL, DRIVER_NAME, 29242421Syokota NULL, -1, nodump, nopsize, 29342421Syokota}; 29442421Syokota 29542421Syokotastatic void 29642421Syokotavfbattach(void *arg) 29742421Syokota{ 29842421Syokota static int fb_devsw_installed = FALSE; 29942421Syokota dev_t dev; 30042421Syokota 30142421Syokota if (!fb_devsw_installed) { 30242421Syokota dev = makedev(CDEV_MAJOR, 0); 30342421Syokota cdevsw_add(&dev, &fb_cdevsw, NULL); 30442421Syokota fb_devsw_installed = TRUE; 30542421Syokota } 30642421Syokota} 30742421Syokota 30842421SyokotaPSEUDO_SET(vfbattach, fb); 30942421Syokota 31042421Syokota#endif /* notyet */ 31142421Syokota 31242421Syokotaint 31342421Syokotafb_attach(dev_t dev, video_adapter *adp, struct cdevsw *cdevsw) 31442421Syokota{ 31542421Syokota int s; 31642421Syokota 31742421Syokota if (adp->va_index >= adapters) 31842421Syokota return EINVAL; 31942421Syokota if (adapter[adp->va_index] != adp) 32042421Syokota return EINVAL; 32142421Syokota 32242421Syokota s = spltty(); 32342421Syokota adp->va_minor = minor(dev); 32442421Syokota vidcdevsw[adp->va_index] = cdevsw; 32542421Syokota splx(s); 32642421Syokota 32742421Syokota /* XXX: DEVFS? */ 32842421Syokota 32942421Syokota if (adp->va_index + 1 >= adapters) 33042421Syokota vid_realloc_array(); 33142421Syokota 33242421Syokota printf("fb%d at %s%d\n", adp->va_index, adp->va_name, adp->va_unit); 33342421Syokota return 0; 33442421Syokota} 33542421Syokota 33642421Syokotaint 33742421Syokotafb_detach(dev_t dev, video_adapter *adp, struct cdevsw *cdevsw) 33842421Syokota{ 33942421Syokota int s; 34042421Syokota 34142421Syokota if (adp->va_index >= adapters) 34242421Syokota return EINVAL; 34342421Syokota if (adapter[adp->va_index] != adp) 34442421Syokota return EINVAL; 34542421Syokota if (vidcdevsw[adp->va_index] != cdevsw) 34642421Syokota return EINVAL; 34742421Syokota 34842421Syokota s = spltty(); 34942421Syokota vidcdevsw[adp->va_index] = NULL; 35042421Syokota splx(s); 35142421Syokota return 0; 35242421Syokota} 35342421Syokota 35442421Syokota#endif /* FB_INSTALL_CDEV */ 35542421Syokota 35642421Syokotastatic char 35742421Syokota*adapter_name(int type) 35842421Syokota{ 35942421Syokota static struct { 36042421Syokota int type; 36142421Syokota char *name; 36242421Syokota } names[] = { 36342421Syokota { KD_MONO, "MDA" }, 36442421Syokota { KD_HERCULES, "Hercules" }, 36542421Syokota { KD_CGA, "CGA" }, 36642421Syokota { KD_EGA, "EGA" }, 36742421Syokota { KD_VGA, "VGA" }, 36842421Syokota { KD_PC98, "PC-98x1" }, 36942421Syokota { -1, "Unknown" }, 37042421Syokota }; 37142421Syokota int i; 37242421Syokota 37342421Syokota for (i = 0; names[i].type != -1; ++i) 37442421Syokota if (names[i].type == type) 37542421Syokota break; 37642421Syokota return names[i].name; 37742421Syokota} 37842421Syokota 37942421Syokotavoid 38042421Syokotafb_dump_adp_info(char *driver, video_adapter_t *adp, int level) 38142421Syokota{ 38242421Syokota if (level <= 0) 38342421Syokota return; 38442421Syokota 38542421Syokota printf("%s%d: %s%d, %s, type:%s (%d), flags:0x%x\n", 38642421Syokota DRIVER_NAME, adp->va_index, driver, adp->va_unit, adp->va_name, 38742421Syokota adapter_name(adp->va_type), adp->va_type, adp->va_flags); 38842421Syokota printf("%s%d: port:0x%x-0x%x, crtc:0x%x, mem:0x%x 0x%x\n", 38942421Syokota DRIVER_NAME, adp->va_index, 39042421Syokota adp->va_io_base, adp->va_io_base + adp->va_io_size - 1, 39142421Syokota adp->va_crtc_addr, adp->va_mem_base, adp->va_mem_size); 39242421Syokota printf("%s%d: init mode:%d, bios mode:%d, current mode:%d\n", 39342421Syokota DRIVER_NAME, adp->va_index, 39442421Syokota adp->va_initial_mode, adp->va_initial_bios_mode, adp->va_mode); 39542421Syokota printf("%s%d: window:0x%x size:%dk gran:%dk, buf:0x%x size:%dk\n", 39642421Syokota DRIVER_NAME, adp->va_index, 39742831Syokota adp->va_window, (int)adp->va_window_size/1024, 39842831Syokota (int)adp->va_window_gran/1024, adp->va_buffer, 39942831Syokota (int)adp->va_buffer_size/1024); 40042421Syokota} 40142421Syokota 40242421Syokotavoid 40342421Syokotafb_dump_mode_info(char *driver, video_adapter_t *adp, video_info_t *info, 40442421Syokota int level) 40542421Syokota{ 40642421Syokota if (level <= 0) 40742421Syokota return; 40842421Syokota 40942421Syokota printf("%s%d: %s, mode:%d, flags:0x%x ", 41042421Syokota driver, adp->va_unit, adp->va_name, info->vi_mode, info->vi_flags); 41142421Syokota if (info->vi_flags & V_INFO_GRAPHICS) 41242421Syokota printf("G %dx%dx%d, %d plane(s), font:%dx%d, ", 41342421Syokota info->vi_width, info->vi_height, 41442421Syokota info->vi_depth, info->vi_planes, 41542421Syokota info->vi_cwidth, info->vi_cheight); 41642421Syokota else 41742421Syokota printf("T %dx%d, font:%dx%d, ", 41842421Syokota info->vi_width, info->vi_height, 41942421Syokota info->vi_cwidth, info->vi_cheight); 42042421Syokota printf("win:0x%x\n", info->vi_window); 42142421Syokota} 422