diff options
Diffstat (limited to 'sys/dev/fb/fb.c')
-rw-r--r-- | sys/dev/fb/fb.c | 473 |
1 files changed, 433 insertions, 40 deletions
diff --git a/sys/dev/fb/fb.c b/sys/dev/fb/fb.c index a1d5f11..e10b75b 100644 --- a/sys/dev/fb/fb.c +++ b/sys/dev/fb/fb.c @@ -25,7 +25,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: fb.c,v 1.4 1999/05/30 16:51:23 phk Exp $ + * $Id: fb.c,v 1.5 1999/05/31 11:24:38 phk Exp $ */ #include "fb.h" @@ -34,10 +34,14 @@ #include <sys/param.h> #include <sys/systm.h> #include <sys/conf.h> +#include <sys/bus.h> #include <sys/kernel.h> #include <sys/malloc.h> +#include <sys/uio.h> +#include <sys/fbio.h> -#include <machine/console.h> +#include <vm/vm.h> +#include <vm/pmap.h> #include <dev/fb/fbreg.h> @@ -49,6 +53,7 @@ * when necessary. */ +static int vid_malloc; static int adapters = 1; static video_adapter_t *adp_ini; static video_adapter_t **adapter = &adp_ini; @@ -56,48 +61,69 @@ static video_switch_t *vidsw_ini; video_switch_t **vidsw = &vidsw_ini; #ifdef FB_INSTALL_CDEV - -#define ARRAY_DELTA 4 - static struct cdevsw *vidcdevsw_ini; static struct cdevsw **vidcdevsw = &vidcdevsw_ini; +#endif -static void +#define ARRAY_DELTA 4 + +static int vid_realloc_array(void) { video_adapter_t **new_adp; video_switch_t **new_vidsw; +#ifdef FB_INSTALL_CDEV struct cdevsw **new_cdevsw; +#endif int newsize; int s; + if (!vid_malloc) + return ENOMEM; + s = spltty(); newsize = ((adapters + ARRAY_DELTA)/ARRAY_DELTA)*ARRAY_DELTA; new_adp = malloc(sizeof(*new_adp)*newsize, M_DEVBUF, M_WAITOK); new_vidsw = malloc(sizeof(*new_vidsw)*newsize, M_DEVBUF, M_WAITOK); +#ifdef FB_INSTALL_CDEV new_cdevsw = malloc(sizeof(*new_cdevsw)*newsize, M_DEVBUF, M_WAITOK); +#endif bzero(new_adp, sizeof(*new_adp)*newsize); bzero(new_vidsw, sizeof(*new_vidsw)*newsize); - bzero(new_cdevsw, sizeof(*new_cdevsw)*newsize); bcopy(adapter, new_adp, sizeof(*adapter)*adapters); bcopy(vidsw, new_vidsw, sizeof(*vidsw)*adapters); +#ifdef FB_INSTALL_CDEV + bzero(new_cdevsw, sizeof(*new_cdevsw)*newsize); bcopy(vidcdevsw, new_cdevsw, sizeof(*vidcdevsw)*adapters); +#endif if (adapters > 1) { free(adapter, M_DEVBUF); free(vidsw, M_DEVBUF); +#ifdef FB_INSTALL_CDEV free(vidcdevsw, M_DEVBUF); +#endif } adapter = new_adp; vidsw = new_vidsw; +#ifdef FB_INSTALL_CDEV vidcdevsw = new_cdevsw; +#endif adapters = newsize; splx(s); if (bootverbose) printf("fb: new array size %d\n", adapters); + + return 0; } -#endif /* FB_INSTALL_CDEV */ +static void +vid_malloc_init(void *arg) +{ + vid_malloc = TRUE; +} + +SYSINIT(vid_mem, SI_SUB_KMEM, SI_ORDER_ANY, vid_malloc_init, NULL); /* * Low-level frame buffer driver functions @@ -120,20 +146,22 @@ vid_init_struct(video_adapter_t *adp, char *name, int type, int unit) int vid_register(video_adapter_t *adp) { - video_driver_t **list; - video_driver_t *p; + const video_driver_t **list; + const video_driver_t *p; int index; for (index = 0; index < adapters; ++index) { if (adapter[index] == NULL) break; } - if (index >= adapters) - return -1; + if (index >= adapters) { + if (vid_realloc_array()) + return -1; + } adp->va_index = index; adp->va_token = NULL; - list = (video_driver_t **)videodriver_set.ls_items; + list = (const video_driver_t **)videodriver_set.ls_items; while ((p = *list++) != NULL) { if (strcmp(p->name, adp->va_name) == 0) { adapter[index] = adp; @@ -162,10 +190,10 @@ vid_unregister(video_adapter_t *adp) video_switch_t *vid_get_switch(char *name) { - video_driver_t **list; - video_driver_t *p; + const video_driver_t **list; + const video_driver_t *p; - list = (video_driver_t **)videodriver_set.ls_items; + list = (const video_driver_t **)videodriver_set.ls_items; while ((p = *list++) != NULL) { if (strcmp(p->name, name) == 0) return p->vidsw; @@ -251,10 +279,10 @@ video_adapter_t int vid_configure(int flags) { - video_driver_t **list; - video_driver_t *p; + const video_driver_t **list; + const video_driver_t *p; - list = (video_driver_t **)videodriver_set.ls_items; + list = (const video_driver_t **)videodriver_set.ls_items; while ((p = *list++) != NULL) { if (p->configure != NULL) (*p->configure)(flags); @@ -269,27 +297,73 @@ vid_configure(int flags) * appropriate subdrivers. */ -#define DRIVER_NAME "fb" +#define FB_DRIVER_NAME "fb" #ifdef FB_INSTALL_CDEV +#if experimental + +static devclass_t fb_devclass; + +static int fbprobe(device_t dev); +static int fbattach(device_t dev); + +static device_method_t fb_methods[] = { + DEVMETHOD(device_probe, fbprobe), + DEVMETHOD(device_attach, fbattach), + + DEVMETHOD(bus_print_child, bus_generic_print_child), + { 0, 0 } +}; + +static driver_t fb_driver = { + FB_DRIVER_NAME, + fb_methods, + 0, +}; + +static int +fbprobe(device_t dev) +{ + int unit; + + unit = device_get_unit(dev); + if (unit >= adapters) + return ENXIO; + if (adapter[unit] == NULL) + return ENXIO; + + device_set_desc(dev, "generic frame buffer"); + return 0; +} + +static int +fbattach(device_t dev) +{ + printf("fbattach: about to attach children\n"); + bus_generic_attach(dev); + return 0; +} + +#endif /* experimental */ + #define FB_UNIT(dev) minor(dev) #define FB_MKMINOR(unit) (u) -#if notyet - static d_open_t fbopen; static d_close_t fbclose; +static d_read_t fbread; +static d_write_t fbwrite; static d_ioctl_t fbioctl; static d_mmap_t fbmmap; -#define CDEV_MAJOR 141 /* XXX */ +#define CDEV_MAJOR 123 /* XXX */ static struct cdevsw fb_cdevsw = { /* open */ fbopen, /* close */ fbclose, - /* read */ noread, - /* write */ nowrite, + /* read */ fbread, + /* write */ fbwrite, /* ioctl */ fbioctl, /* stop */ nostop, /* reset */ noreset, @@ -297,7 +371,7 @@ static struct cdevsw fb_cdevsw = { /* poll */ nopoll, /* mmap */ fbmmap, /* strategy */ nostrategy, - /* name */ DRIVER_NAME, + /* name */ FB_DRIVER_NAME, /* parms */ noparms, /* maj */ CDEV_MAJOR, /* dump */ nodump, @@ -320,10 +394,8 @@ vfbattach(void *arg) PSEUDO_SET(vfbattach, fb); -#endif /* notyet */ - int -fb_attach(dev_t dev, video_adapter *adp, struct cdevsw *cdevsw) +fb_attach(dev_t dev, video_adapter_t *adp, struct cdevsw *cdevsw) { int s; @@ -339,15 +411,12 @@ fb_attach(dev_t dev, video_adapter *adp, struct cdevsw *cdevsw) /* XXX: DEVFS? */ - if (adp->va_index + 1 >= adapters) - vid_realloc_array(); - printf("fb%d at %s%d\n", adp->va_index, adp->va_name, adp->va_unit); return 0; } int -fb_detach(dev_t dev, video_adapter *adp, struct cdevsw *cdevsw) +fb_detach(dev_t dev, video_adapter_t *adp, struct cdevsw *cdevsw) { int s; @@ -364,6 +433,165 @@ fb_detach(dev_t dev, video_adapter *adp, struct cdevsw *cdevsw) return 0; } +static int +fbopen(dev_t dev, int flag, int mode, struct proc *p) +{ + int unit; + + unit = FB_UNIT(dev); + if (unit >= adapters) + return ENXIO; + if (vidcdevsw[unit] == NULL) + return ENXIO; + return (*vidcdevsw[unit]->d_open)(makedev(0, adapter[unit]->va_minor), + flag, mode, p); +} + +static int +fbclose(dev_t dev, int flag, int mode, struct proc *p) +{ + int unit; + + unit = FB_UNIT(dev); + if (vidcdevsw[unit] == NULL) + return ENXIO; + return (*vidcdevsw[unit]->d_close)(makedev(0, adapter[unit]->va_minor), + flag, mode, p); +} + +static int +fbread(dev_t dev, struct uio *uio, int flag) +{ + int unit; + + unit = FB_UNIT(dev); + if (vidcdevsw[unit] == NULL) + return ENXIO; + return (*vidcdevsw[unit]->d_read)(makedev(0, adapter[unit]->va_minor), + uio, flag); +} + +static int +fbwrite(dev_t dev, struct uio *uio, int flag) +{ + int unit; + + unit = FB_UNIT(dev); + if (vidcdevsw[unit] == NULL) + return ENXIO; + return (*vidcdevsw[unit]->d_write)(makedev(0, adapter[unit]->va_minor), + uio, flag); +} + +static int +fbioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p) +{ + int unit; + + unit = FB_UNIT(dev); + if (vidcdevsw[unit] == NULL) + return ENXIO; + return (*vidcdevsw[unit]->d_ioctl)(makedev(0, adapter[unit]->va_minor), + cmd, arg, flag, p); +} + +static int +fbmmap(dev_t dev, vm_offset_t offset, int nprot) +{ + int unit; + + unit = FB_UNIT(dev); + if (vidcdevsw[unit] == NULL) + return ENXIO; + return (*vidcdevsw[unit]->d_mmap)(makedev(0, adapter[unit]->va_minor), + offset, nprot); +} + +#if experimental +DEV_DRIVER_MODULE(fb, ???, fb_driver, fb_devclass, + CDEV_MAJOR, NOMAJ, fb_cdevsw, 0, 0); +#endif + +/* + * Generic frame buffer cdev driver functions + * Frame buffer subdrivers may call these functions to implement common + * driver functions. + */ + +int genfbopen(genfb_softc_t *sc, video_adapter_t *adp, int flag, int mode, + struct proc *p) +{ + int s; + + s = spltty(); + if (!(sc->gfb_flags & FB_OPEN)) + sc->gfb_flags |= FB_OPEN; + splx(s); + return 0; +} + +int genfbclose(genfb_softc_t *sc, video_adapter_t *adp, int flag, int mode, + struct proc *p) +{ + int s; + + s = spltty(); + sc->gfb_flags &= ~FB_OPEN; + splx(s); + return 0; +} + +int genfbread(genfb_softc_t *sc, video_adapter_t *adp, struct uio *uio, + int flag) +{ + int size; + int offset; + int error; + int len; + + error = 0; + size = adp->va_buffer_size/adp->va_info.vi_planes; + while (uio->uio_resid > 0) { + if (uio->uio_offset >= size) + break; + offset = uio->uio_offset%adp->va_window_size; + len = imin(uio->uio_resid, size - uio->uio_offset); + len = imin(len, adp->va_window_size - offset); + if (len <= 0) + break; + (*vidsw[adp->va_index]->set_win_org)(adp, uio->uio_offset); + error = uiomove((caddr_t)(adp->va_window + offset), len, uio); + if (error) + break; + } + return error; +} + +int genfbwrite(genfb_softc_t *sc, video_adapter_t *adp, struct uio *uio, + int flag) +{ + return ENODEV; +} + +int genfbioctl(genfb_softc_t *sc, video_adapter_t *adp, u_long cmd, + caddr_t arg, int flag, struct proc *p) +{ + int error; + + if (adp == NULL) /* XXX */ + return ENXIO; + error = (*vidsw[adp->va_index]->ioctl)(adp, cmd, arg); + if (error == ENOIOCTL) + error = ENODEV; + return error; +} + +int genfbmmap(genfb_softc_t *sc, video_adapter_t *adp, vm_offset_t offset, + int prot) +{ + return (*vidsw[adp->va_index]->mmap)(adp, offset, prot); +} + #endif /* FB_INSTALL_CDEV */ static char @@ -379,6 +607,7 @@ static char { KD_EGA, "EGA" }, { KD_VGA, "VGA" }, { KD_PC98, "PC-98x1" }, + { KD_TGA, "TGA" }, { -1, "Unknown" }, }; int i; @@ -389,6 +618,12 @@ static char return names[i].name; } +/* + * Generic low-level frame buffer functions + * The low-level functions in the frame buffer subdriver may use these + * functions. + */ + void fb_dump_adp_info(char *driver, video_adapter_t *adp, int level) { @@ -396,19 +631,19 @@ fb_dump_adp_info(char *driver, video_adapter_t *adp, int level) return; printf("%s%d: %s%d, %s, type:%s (%d), flags:0x%x\n", - DRIVER_NAME, adp->va_index, driver, adp->va_unit, adp->va_name, + FB_DRIVER_NAME, adp->va_index, driver, adp->va_unit, adp->va_name, adapter_name(adp->va_type), adp->va_type, adp->va_flags); printf("%s%d: port:0x%x-0x%x, crtc:0x%x, mem:0x%x 0x%x\n", - DRIVER_NAME, adp->va_index, + FB_DRIVER_NAME, adp->va_index, adp->va_io_base, adp->va_io_base + adp->va_io_size - 1, adp->va_crtc_addr, adp->va_mem_base, adp->va_mem_size); printf("%s%d: init mode:%d, bios mode:%d, current mode:%d\n", - DRIVER_NAME, adp->va_index, + FB_DRIVER_NAME, adp->va_index, adp->va_initial_mode, adp->va_initial_bios_mode, adp->va_mode); - printf("%s%d: window:0x%x size:%dk gran:%dk, buf:0x%x size:%dk\n", - DRIVER_NAME, adp->va_index, - adp->va_window, (int)adp->va_window_size/1024, - (int)adp->va_window_gran/1024, adp->va_buffer, + printf("%s%d: window:%p size:%dk gran:%dk, buf:%p size:%dk\n", + FB_DRIVER_NAME, adp->va_index, + (void *)adp->va_window, (int)adp->va_window_size/1024, + (int)adp->va_window_gran/1024, (void *)adp->va_buffer, (int)adp->va_buffer_size/1024); } @@ -432,3 +667,161 @@ fb_dump_mode_info(char *driver, video_adapter_t *adp, video_info_t *info, info->vi_cwidth, info->vi_cheight); printf("win:0x%x\n", info->vi_window); } + +int +fb_type(int adp_type) +{ + static struct { + int fb_type; + int va_type; + } types[] = { + { FBTYPE_MDA, KD_MONO }, + { FBTYPE_HERCULES, KD_HERCULES }, + { FBTYPE_CGA, KD_CGA }, + { FBTYPE_EGA, KD_EGA }, + { FBTYPE_VGA, KD_VGA }, + { FBTYPE_PC98, KD_PC98 }, + { FBTYPE_TGA, KD_TGA }, + }; + int i; + + for (i = 0; i < sizeof(types)/sizeof(types[0]); ++i) { + if (types[i].va_type == adp_type) + return types[i].fb_type; + } + return -1; +} + +int +fb_commonioctl(video_adapter_t *adp, u_long cmd, caddr_t arg) +{ + int error; + int s; + + /* assert(adp != NULL) */ + + error = 0; + s = spltty(); + + switch (cmd) { + + case FBIO_ADAPTER: /* get video adapter index */ + *(int *)arg = adp->va_index; + break; + + case FBIO_ADPTYPE: /* get video adapter type */ + *(int *)arg = adp->va_type; + break; + + case FBIO_ADPINFO: /* get video adapter info */ + ((video_adapter_info_t *)arg)->va_index = adp->va_index; + ((video_adapter_info_t *)arg)->va_type = adp->va_type; + bcopy(adp->va_name, ((video_adapter_info_t *)arg)->va_name, + imin(strlen(adp->va_name) + 1, + sizeof(((video_adapter_info_t *)arg)->va_name))); + ((video_adapter_info_t *)arg)->va_unit = adp->va_unit; + ((video_adapter_info_t *)arg)->va_flags = adp->va_flags; + ((video_adapter_info_t *)arg)->va_io_base = adp->va_io_base; + ((video_adapter_info_t *)arg)->va_io_size = adp->va_io_size; + ((video_adapter_info_t *)arg)->va_crtc_addr = adp->va_crtc_addr; + ((video_adapter_info_t *)arg)->va_mem_base = adp->va_mem_base; + ((video_adapter_info_t *)arg)->va_mem_size = adp->va_mem_size; + ((video_adapter_info_t *)arg)->va_window + = vtophys(adp->va_window); + ((video_adapter_info_t *)arg)->va_window_size + = adp->va_window_size; + ((video_adapter_info_t *)arg)->va_window_gran + = adp->va_window_gran; + ((video_adapter_info_t *)arg)->va_window_orig + = adp->va_window_orig; + ((video_adapter_info_t *)arg)->va_unused0 + = (adp->va_buffer) ? vtophys(adp->va_buffer) : 0; + ((video_adapter_info_t *)arg)->va_buffer_size + = adp->va_buffer_size; + ((video_adapter_info_t *)arg)->va_mode = adp->va_mode; + ((video_adapter_info_t *)arg)->va_initial_mode + = adp->va_initial_mode; + ((video_adapter_info_t *)arg)->va_initial_bios_mode + = adp->va_initial_bios_mode; + ((video_adapter_info_t *)arg)->va_line_width + = adp->va_line_width; + ((video_adapter_info_t *)arg)->va_disp_start.x + = adp->va_disp_start.x; + ((video_adapter_info_t *)arg)->va_disp_start.y + = adp->va_disp_start.y; + break; + + case FBIO_MODEINFO: /* get mode information */ + error = (*vidsw[adp->va_index]->get_info)(adp, + ((video_info_t *)arg)->vi_mode, + (video_info_t *)arg); + if (error) + error = ENODEV; + break; + + case FBIO_FINDMODE: /* find a matching video mode */ + error = (*vidsw[adp->va_index]->query_mode)(adp, + (video_info_t *)arg); + if (error < 0) { + error = EINVAL; + } else { + error = (*vidsw[adp->va_index]->get_info)(adp, + error, (video_info_t *)arg); + if (error) + error = ENODEV; /* shouldn't happen */ + } + break; + + case FBIO_GETMODE: /* get video mode */ + *(int *)arg = adp->va_mode; + break; + + case FBIO_SETMODE: /* set video mode */ + error = (*vidsw[adp->va_index]->set_mode)(adp, *(int *)arg); + if (error) + error = ENODEV; /* EINVAL? */ + break; + + case FBIO_GETWINORG: /* get frame buffer window origin */ + *(u_int *)arg = adp->va_window_orig; + break; + + case FBIO_GETDISPSTART: /* get display start address */ + ((video_display_start_t *)arg)->x = adp->va_disp_start.x; + ((video_display_start_t *)arg)->y = adp->va_disp_start.y; + break; + + case FBIO_GETLINEWIDTH: /* get scan line width in bytes */ + *(u_int *)arg = adp->va_line_width; + break; + + case FBIO_GETPALETTE: /* get color palette */ + case FBIO_SETPALETTE: /* set color palette */ + /* XXX */ + + case FBIOPUTCMAP: + case FBIOGETCMAP: + /* XXX */ + + case FBIO_SETWINORG: /* set frame buffer window origin */ + case FBIO_SETDISPSTART: /* set display start address */ + case FBIO_SETLINEWIDTH: /* set scan line width in pixel */ + + case FBIOGTYPE: + case FBIOGATTR: + case FBIOSVIDEO: + case FBIOGVIDEO: + case FBIOSCURSOR: + case FBIOGCURSOR: + case FBIOSCURPOS: + case FBIOGCURPOS: + case FBIOGCURMAX: + + default: + error = ENODEV; + break; + } + + splx(s); + return error; +} |