File:  [DragonFly] / src / sys / dev / video / fb / fb.c
Revision 1.9: download - view: text, annotated - select for diffs
Wed May 19 22:52:54 2004 UTC (10 years, 3 months ago) by dillon
Branches: MAIN
CVS tags: HEAD, DragonFly_Snap29Sep2004, DragonFly_Snap13Sep2004, DragonFly_1_0_REL, DragonFly_1_0_RC1, DragonFly_1_0A_REL
Device layer rollup commit.

* cdevsw_add() is now required.  cdevsw_add() and cdevsw_remove() may specify
  a mask/match indicating the range of supported minor numbers.  Multiple
  cdevsw_add()'s using the same major number, but distinctly different
  ranges, may be issued.  All devices that failed to call cdevsw_add() before
  now do.

* cdevsw_remove() now automatically marks all devices within its supported
  range as being destroyed.

* vnode->v_rdev is no longer resolved when the vnode is created.  Instead,
  only v_udev (a newly added field) is resolved.  v_rdev is resolved when
  the vnode is opened and cleared on the last close.

* A great deal of code was making rather dubious assumptions with regards
  to the validity of devices associated with vnodes, primarily due to
  the persistence of a device structure due to being indexed by (major, minor)
  instead of by (cdevsw, major, minor).  In particular, if you run a program
  which connects to a USB device and then you pull the USB device and plug
  it back in, the vnode subsystem will continue to believe that the device
  is open when, in fact, it isn't (because it was destroyed and recreated).

  In particular, note that all the VFS mount procedures now check devices
  via v_udev instead of v_rdev prior to calling VOP_OPEN(), since v_rdev
  is NULL prior to the first open.

* The disk layer's device interaction has been rewritten.  The disk layer
  (i.e. the slice and disklabel management layer) no longer overloads
  its data onto the device structure representing the underlying physical
  disk.  Instead, the disk layer uses the new cdevsw_add() functionality
  to register its own cdevsw using the underlying device's major number,
  and simply does NOT register the underlying device's cdevsw.  No
  confusion is created because the device hash is now based on
  (cdevsw,major,minor) rather then (major,minor).

  NOTE: This also means that underlying raw disk devices may use the entire
  device minor number instead of having to reserve the bits used by the disk
  layer, and also means that can we (theoretically) stack a fully
  disklabel-supported 'disk' on top of any block device.

* The new reference counting scheme prevents this by associating a device
  with a cdevsw and disconnecting the device from its cdevsw when the cdevsw
  is removed.  Additionally, all udev2dev() lookups run through the cdevsw
  mask/match and only successfully find devices still associated with an
  active cdevsw.

* Major work on MFS:  MFS no longer shortcuts vnode and device creation.  It
  now creates a real vnode and a real device and implements real open and
  close VOPs.  Additionally, due to the disk layer changes, MFS is no longer
  limited to 255 mounts.  The new limit is 16 million.  Since MFS creates a
  real device node, mount_mfs will now create a real /dev/mfs<PID> device
  that can be read from userland (e.g. so you can dump an MFS filesystem).

* BUF AND DEVICE STRATEGY changes.  The struct buf contains a b_dev field.
  In order to properly handle stacked devices we now require that the b_dev
  field be initialized before the device strategy routine is called.  This
  required some additional work in various VFS implementations.  To enforce
  this requirement, biodone() now sets b_dev to NODEV.  The new disk layer
  will adjust b_dev before forwarding a request to the actual physical
  device.

* A bug in the ISO CD boot sequence which resulted in a panic has been fixed.

Testing by: lots of people, but David Rhodus found the most aggregious bugs.

    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:  * $FreeBSD: src/sys/dev/fb/fb.c,v 1.11.2.2 2000/08/02 22:35:22 peter Exp $
   29:  * $DragonFly: src/sys/dev/video/fb/fb.c,v 1.9 2004/05/19 22:52:54 dillon Exp $
   30:  */
   31: 
   32: #include "opt_fb.h"
   33: 
   34: #include <sys/param.h>
   35: #include <sys/systm.h>
   36: #include <sys/conf.h>
   37: #include <sys/bus.h>
   38: #include <sys/kernel.h>
   39: #include <sys/malloc.h>
   40: #include <sys/uio.h>
   41: #include <sys/fbio.h>
   42: #include <sys/linker_set.h>
   43: #include <sys/device.h>
   44: 
   45: #include <vm/vm.h>
   46: #include <vm/pmap.h>
   47: 
   48: #include "fbreg.h"
   49: 
   50: SET_DECLARE(videodriver_set, const video_driver_t);
   51: 
   52: /* local arrays */
   53: 
   54: /*
   55:  * We need at least one entry each in order to initialize a video card
   56:  * for the kernel console.  The arrays will be increased dynamically
   57:  * when necessary.
   58:  */
   59: 
   60: static int		vid_malloc;
   61: static int		adapters = 1;
   62: static video_adapter_t	*adp_ini;
   63: static video_adapter_t	**adapter = &adp_ini;
   64: static video_switch_t	*vidsw_ini;
   65:        video_switch_t	**vidsw = &vidsw_ini;
   66: 
   67: #ifdef FB_INSTALL_CDEV
   68: static dev_t	vidcdevsw_ini;
   69: static dev_t	*vidcdevsw = &vidcdevsw_ini;
   70: #endif
   71: 
   72: #define ARRAY_DELTA	4
   73: 
   74: static int
   75: vid_realloc_array(void)
   76: {
   77: 	video_adapter_t **new_adp;
   78: 	video_switch_t **new_vidsw;
   79: #ifdef FB_INSTALL_CDEV
   80: 	dev_t *new_cdevsw;
   81: #endif
   82: 	int newsize;
   83: 	int s;
   84: 
   85: 	if (!vid_malloc)
   86: 		return ENOMEM;
   87: 
   88: 	s = spltty();
   89: 	newsize = ((adapters + ARRAY_DELTA)/ARRAY_DELTA)*ARRAY_DELTA;
   90: 	new_adp = malloc(sizeof(*new_adp)*newsize, M_DEVBUF, M_WAITOK);
   91: 	new_vidsw = malloc(sizeof(*new_vidsw)*newsize, M_DEVBUF, M_WAITOK);
   92: #ifdef FB_INSTALL_CDEV
   93: 	new_cdevsw = malloc(sizeof(*new_cdevsw)*newsize, M_DEVBUF, M_WAITOK);
   94: #endif
   95: 	bzero(new_adp, sizeof(*new_adp)*newsize);
   96: 	bzero(new_vidsw, sizeof(*new_vidsw)*newsize);
   97: 	bcopy(adapter, new_adp, sizeof(*adapter)*adapters);
   98: 	bcopy(vidsw, new_vidsw, sizeof(*vidsw)*adapters);
   99: #ifdef FB_INSTALL_CDEV
  100: 	bzero(new_cdevsw, sizeof(*new_cdevsw)*newsize);
  101: 	bcopy(vidcdevsw, new_cdevsw, sizeof(*vidcdevsw)*adapters);
  102: #endif
  103: 	if (adapters > 1) {
  104: 		free(adapter, M_DEVBUF);
  105: 		free(vidsw, M_DEVBUF);
  106: #ifdef FB_INSTALL_CDEV
  107: 		free(vidcdevsw, M_DEVBUF);
  108: #endif
  109: 	}
  110: 	adapter = new_adp;
  111: 	vidsw = new_vidsw;
  112: #ifdef FB_INSTALL_CDEV
  113: 	vidcdevsw = new_cdevsw;
  114: #endif
  115: 	adapters = newsize;
  116: 	splx(s);
  117: 
  118: 	if (bootverbose)
  119: 		printf("fb: new array size %d\n", adapters);
  120: 
  121: 	return 0;
  122: }
  123: 
  124: static void
  125: vid_malloc_init(void *arg)
  126: {
  127: 	vid_malloc = TRUE;
  128: }
  129: 
  130: SYSINIT(vid_mem, SI_SUB_KMEM, SI_ORDER_ANY, vid_malloc_init, NULL);
  131: 
  132: /*
  133:  * Low-level frame buffer driver functions
  134:  * frame buffer subdrivers, such as the VGA driver, call these functions
  135:  * to initialize the video_adapter structure and register it to the virtual
  136:  * frame buffer driver `fb'.
  137:  */
  138: 
  139: /* initialize the video_adapter_t structure */
  140: void
  141: vid_init_struct(video_adapter_t *adp, char *name, int type, int unit)
  142: {
  143: 	adp->va_flags = 0;
  144: 	adp->va_name = name;
  145: 	adp->va_type = type;
  146: 	adp->va_unit = unit;
  147: }
  148: 
  149: /* Register a video adapter */
  150: int
  151: vid_register(video_adapter_t *adp)
  152: {
  153: 	const video_driver_t **list;
  154: 	const video_driver_t *p;
  155: 	int index;
  156: 
  157: 	for (index = 0; index < adapters; ++index) {
  158: 		if (adapter[index] == NULL)
  159: 			break;
  160: 	}
  161: 	if (index >= adapters) {
  162: 		if (vid_realloc_array())
  163: 			return -1;
  164: 	}
  165: 
  166: 	adp->va_index = index;
  167: 	adp->va_token = NULL;
  168: 	SET_FOREACH(list, videodriver_set) {
  169: 		p = *list;
  170: 		if (strcmp(p->name, adp->va_name) == 0) {
  171: 			adapter[index] = adp;
  172: 			vidsw[index] = p->vidsw;
  173: 			return index;
  174: 		}
  175: 	}
  176: 
  177: 	return -1;
  178: }
  179: 
  180: int
  181: vid_unregister(video_adapter_t *adp)
  182: {
  183: 	if ((adp->va_index < 0) || (adp->va_index >= adapters))
  184: 		return ENOENT;
  185: 	if (adapter[adp->va_index] != adp)
  186: 		return ENOENT;
  187: 
  188: 	adapter[adp->va_index] = NULL;
  189: 	vidsw[adp->va_index] = NULL;
  190: 	return 0;
  191: }
  192: 
  193: /* Get video I/O function table */
  194: video_switch_t
  195: *vid_get_switch(char *name)
  196: {
  197: 	const video_driver_t **list;
  198: 	const video_driver_t *p;
  199: 
  200: 	SET_FOREACH(list, videodriver_set) {
  201: 		p = *list;
  202: 		if (strcmp(p->name, name) == 0)
  203: 			return p->vidsw;
  204: 	}
  205: 
  206: 	return NULL;
  207: }
  208: 
  209: /*
  210:  * Video card client functions
  211:  * Video card clients, such as the console driver `syscons' and the frame
  212:  * buffer cdev driver, use these functions to claim and release a card for
  213:  * exclusive use.
  214:  */
  215: 
  216: /* find the video card specified by a driver name and a unit number */
  217: int
  218: vid_find_adapter(char *driver, int unit)
  219: {
  220: 	int i;
  221: 
  222: 	for (i = 0; i < adapters; ++i) {
  223: 		if (adapter[i] == NULL)
  224: 			continue;
  225: 		if (strcmp("*", driver) && strcmp(adapter[i]->va_name, driver))
  226: 			continue;
  227: 		if ((unit != -1) && (adapter[i]->va_unit != unit))
  228: 			continue;
  229: 		return i;
  230: 	}
  231: 	return -1;
  232: }
  233: 
  234: /* allocate a video card */
  235: int
  236: vid_allocate(char *driver, int unit, void *id)
  237: {
  238: 	int index;
  239: 	int s;
  240: 
  241: 	s = spltty();
  242: 	index = vid_find_adapter(driver, unit);
  243: 	if (index >= 0) {
  244: 		if (adapter[index]->va_token) {
  245: 			splx(s);
  246: 			return -1;
  247: 		}
  248: 		adapter[index]->va_token = id;
  249: 	}
  250: 	splx(s);
  251: 	return index;
  252: }
  253: 
  254: int
  255: vid_release(video_adapter_t *adp, void *id)
  256: {
  257: 	int error;
  258: 	int s;
  259: 
  260: 	s = spltty();
  261: 	if (adp->va_token == NULL) {
  262: 		error = EINVAL;
  263: 	} else if (adp->va_token != id) {
  264: 		error = EPERM;
  265: 	} else {
  266: 		adp->va_token = NULL;
  267: 		error = 0;
  268: 	}
  269: 	splx(s);
  270: 	return error;
  271: }
  272: 
  273: /* Get a video adapter structure */
  274: video_adapter_t
  275: *vid_get_adapter(int index)
  276: {
  277: 	if ((index < 0) || (index >= adapters))
  278: 		return NULL;
  279: 	return adapter[index];
  280: }
  281: 
  282: /* Configure drivers: this is a backdoor for the console driver XXX */
  283: int
  284: vid_configure(int flags)
  285: {
  286: 	const video_driver_t **list;
  287: 	const video_driver_t *p;
  288: 
  289: 	SET_FOREACH(list, videodriver_set) {
  290: 		p = *list;
  291: 		if (p->configure != NULL)
  292: 			(*p->configure)(flags);
  293: 	}
  294: 
  295: 	return 0;
  296: }
  297: 
  298: /*
  299:  * Virtual frame buffer cdev driver functions
  300:  * The virtual frame buffer driver dispatches driver functions to
  301:  * appropriate subdrivers.
  302:  */
  303: 
  304: #define FB_DRIVER_NAME	"fb"
  305: 
  306: #ifdef FB_INSTALL_CDEV
  307: 
  308: #if experimental
  309: 
  310: static devclass_t	fb_devclass;
  311: 
  312: static int		fbprobe(device_t dev);
  313: static int		fbattach(device_t dev);
  314: 
  315: static device_method_t fb_methods[] = {
  316: 	DEVMETHOD(device_probe,		fbprobe),
  317: 	DEVMETHOD(device_attach,	fbattach),
  318: 
  319: 	DEVMETHOD(bus_print_child,	bus_generic_print_child),
  320: 	{ 0, 0 }
  321: };
  322: 
  323: static driver_t fb_driver = {
  324: 	FB_DRIVER_NAME,
  325: 	fb_methods,
  326: 	0,
  327: };
  328: 
  329: static int
  330: fbprobe(device_t dev)
  331: {
  332: 	int unit;
  333: 
  334: 	unit = device_get_unit(dev);
  335: 	if (unit >= adapters)
  336: 		return ENXIO;
  337: 	if (adapter[unit] == NULL)
  338: 		return ENXIO;
  339: 
  340: 	device_set_desc(dev, "generic frame buffer");
  341: 	return 0;
  342: }
  343: 
  344: static int
  345: fbattach(device_t dev)
  346: {
  347: 	printf("fbattach: about to attach children\n");
  348: 	bus_generic_attach(dev);
  349: 	return 0;
  350: }
  351: 
  352: #endif /* experimental */
  353: 
  354: #define FB_UNIT(dev)	minor(dev)
  355: #define FB_MKMINOR(unit) (u)
  356: 
  357: static d_open_t		fbopen;
  358: static d_close_t	fbclose;
  359: static d_read_t		fbread;
  360: static d_write_t	fbwrite;
  361: static d_ioctl_t	fbioctl;
  362: static d_mmap_t		fbmmap;
  363: 
  364: #define CDEV_MAJOR	123	/* XXX */
  365: 
  366: static struct cdevsw fb_cdevsw = {
  367: 	/* name */	FB_DRIVER_NAME,
  368: 	/* maj */	CDEV_MAJOR,
  369: 	/* flags */	0,
  370: 	/* port */      NULL,
  371: 	/* clone */	NULL,
  372: 
  373: 	/* open */	fbopen,
  374: 	/* close */	fbclose,
  375: 	/* read */	fbread,
  376: 	/* write */	fbwrite,
  377: 	/* ioctl */	fbioctl,
  378: 	/* poll */	nopoll,
  379: 	/* mmap */	fbmmap,
  380: 	/* strategy */	nostrategy,
  381: 	/* dump */	nodump,
  382: 	/* psize */	nopsize
  383: };
  384: 
  385: static void
  386: vfbattach(void *arg)
  387: {
  388: 	static int fb_devsw_installed = FALSE;
  389: 
  390: 	if (!fb_devsw_installed) {
  391: 		cdevsw_add(&fb_cdevsw, 0, 0);
  392: 		fb_devsw_installed = TRUE;
  393: 	}
  394: }
  395: 
  396: PSEUDO_SET(vfbattach, fb);
  397: 
  398: /*
  399:  *  Note: dev represents the actual video device, not the frame buffer
  400:  */
  401: int
  402: fb_attach(dev_t dev, video_adapter_t *adp)
  403: {
  404: 	int s;
  405: 
  406: 	if (adp->va_index >= adapters)
  407: 		return EINVAL;
  408: 	if (adapter[adp->va_index] != adp)
  409: 		return EINVAL;
  410: 
  411: 	s = spltty();
  412: 	reference_dev(dev);
  413: 	adp->va_minor = minor(dev);
  414: 	vidcdevsw[adp->va_index] = dev;
  415: 	splx(s);
  416: 
  417: 	printf("fb%d at %s%d\n", adp->va_index, adp->va_name, adp->va_unit);
  418: 	return 0;
  419: }
  420: 
  421: /*
  422:  *  Note: dev represents the actual video device, not the frame buffer
  423:  */
  424: int
  425: fb_detach(dev_t dev, video_adapter_t *adp)
  426: {
  427: 	int s;
  428: 
  429: 	if (adp->va_index >= adapters)
  430: 		return EINVAL;
  431: 	if (adapter[adp->va_index] != adp)
  432: 		return EINVAL;
  433: 	if (vidcdevsw[adp->va_index] != dev)
  434: 		return EINVAL;
  435: 
  436: 	s = spltty();
  437: 	vidcdevsw[adp->va_index] = NULL;
  438: 	splx(s);
  439: 	release_dev(dev);
  440: 	return 0;
  441: }
  442: 
  443: static int
  444: fbopen(dev_t dev, int flag, int mode, struct thread *td)
  445: {
  446: 	int unit;
  447: 	dev_t fdev;
  448: 
  449: 	unit = FB_UNIT(dev);
  450: 	if (unit >= adapters)
  451: 		return ENXIO;
  452: 	if ((fdev = vidcdevsw[unit]) == NULL)
  453: 		return ENXIO;
  454: 	return dev_dopen(fdev, flag, mode, td);
  455: }
  456: 
  457: static int
  458: fbclose(dev_t dev, int flag, int mode, struct thread *td)
  459: {
  460: 	int unit;
  461: 	dev_t fdev;
  462: 
  463: 	unit = FB_UNIT(dev);
  464: 	if ((fdev = vidcdevsw[unit]) == NULL)
  465: 		return ENXIO;
  466: 	return dev_dclose(fdev, flag, mode, td);
  467: }
  468: 
  469: static int
  470: fbread(dev_t dev, struct uio *uio, int flag)
  471: {
  472: 	int unit;
  473: 	dev_t fdev;
  474: 
  475: 	unit = FB_UNIT(dev);
  476: 	if ((fdev = vidcdevsw[unit]) == NULL)
  477: 		return ENXIO;
  478: 	return dev_dread(fdev, uio, flag);
  479: }
  480: 
  481: static int
  482: fbwrite(dev_t dev, struct uio *uio, int flag)
  483: {
  484: 	int unit;
  485: 	dev_t fdev;
  486: 
  487: 	unit = FB_UNIT(dev);
  488: 	if ((fdev = vidcdevsw[unit]) == NULL)
  489: 		return ENXIO;
  490: 	return dev_dwrite(fdev, uio, flag);
  491: }
  492: 
  493: static int
  494: fbioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
  495: {
  496: 	int unit;
  497: 	dev_t fdev;
  498: 
  499: 	unit = FB_UNIT(dev);
  500: 	if ((fdev = vidcdevsw[unit]) == NULL)
  501: 		return ENXIO;
  502: 	return dev_dioctl(fdev, cmd, arg, flag, td);
  503: }
  504: 
  505: static int
  506: fbmmap(dev_t dev, vm_offset_t offset, int nprot)
  507: {
  508: 	int unit;
  509: 	dev_t fdev;
  510: 
  511: 	unit = FB_UNIT(dev);
  512: 	if ((fdev = vidcdevsw[unit]) == NULL)
  513: 		return ENXIO;
  514: 	return (dev_dmmap(fdev, offset, nprot));
  515: }
  516: 
  517: #if experimental
  518: DEV_DRIVER_MODULE(fb, ???, fb_driver, fb_devclass, fb_cdevsw, 0, 0);
  519: #endif
  520: 
  521: /*
  522:  * Generic frame buffer cdev driver functions
  523:  * Frame buffer subdrivers may call these functions to implement common
  524:  * driver functions.
  525:  */
  526: 
  527: int genfbopen(genfb_softc_t *sc, video_adapter_t *adp, int flag, int mode,
  528: 	      struct thread *td)
  529: {
  530: 	int s;
  531: 
  532: 	s = spltty();
  533: 	if (!(sc->gfb_flags & FB_OPEN))
  534: 		sc->gfb_flags |= FB_OPEN;
  535: 	splx(s);
  536: 	return 0;
  537: }
  538: 
  539: int genfbclose(genfb_softc_t *sc, video_adapter_t *adp, int flag, int mode,
  540: 	       struct thread *td)
  541: {
  542: 	int s;
  543: 
  544: 	s = spltty();
  545: 	sc->gfb_flags &= ~FB_OPEN;
  546: 	splx(s);
  547: 	return 0;
  548: }
  549: 
  550: int genfbread(genfb_softc_t *sc, video_adapter_t *adp, struct uio *uio,
  551: 	      int flag)
  552: {
  553: 	int size;
  554: 	int offset;
  555: 	int error;
  556: 	int len;
  557: 
  558: 	error = 0;
  559: 	size = adp->va_buffer_size/adp->va_info.vi_planes;
  560: 	while (uio->uio_resid > 0) {
  561: 		if (uio->uio_offset >= size)
  562: 			break;
  563: 		offset = uio->uio_offset%adp->va_window_size;
  564: 		len = imin(uio->uio_resid, size - uio->uio_offset);
  565: 		len = imin(len, adp->va_window_size - offset);
  566: 		if (len <= 0)
  567: 			break;
  568: 		(*vidsw[adp->va_index]->set_win_org)(adp, uio->uio_offset);
  569: 		error = uiomove((caddr_t)(adp->va_window + offset), len, uio);
  570: 		if (error)
  571: 			break;
  572: 	}
  573: 	return error;
  574: }
  575: 
  576: int genfbwrite(genfb_softc_t *sc, video_adapter_t *adp, struct uio *uio,
  577: 	       int flag)
  578: {
  579: 	return ENODEV;
  580: }
  581: 
  582: int genfbioctl(genfb_softc_t *sc, video_adapter_t *adp, u_long cmd,
  583: 	       caddr_t arg, int flag, struct thread *td)
  584: {
  585: 	int error;
  586: 
  587: 	if (adp == NULL)	/* XXX */
  588: 		return ENXIO;
  589: 	error = (*vidsw[adp->va_index]->ioctl)(adp, cmd, arg);
  590: 	if (error == ENOIOCTL)
  591: 		error = ENODEV;
  592: 	return error;
  593: }
  594: 
  595: int genfbmmap(genfb_softc_t *sc, video_adapter_t *adp, vm_offset_t offset,
  596: 	      int prot)
  597: {
  598: 	return (*vidsw[adp->va_index]->mmap)(adp, offset, prot);
  599: }
  600: 
  601: #endif /* FB_INSTALL_CDEV */
  602: 
  603: static char
  604: *adapter_name(int type)
  605: {
  606:     static struct {
  607: 	int type;
  608: 	char *name;
  609:     } names[] = {
  610: 	{ KD_MONO,	"MDA" },
  611: 	{ KD_HERCULES,	"Hercules" },
  612: 	{ KD_CGA,	"CGA" },
  613: 	{ KD_EGA,	"EGA" },
  614: 	{ KD_VGA,	"VGA" },
  615: 	{ KD_PC98,	"PC-98x1" },
  616: 	{ KD_TGA,	"TGA" },
  617: 	{ -1,		"Unknown" },
  618:     };
  619:     int i;
  620: 
  621:     for (i = 0; names[i].type != -1; ++i)
  622: 	if (names[i].type == type)
  623: 	    break;
  624:     return names[i].name;
  625: }
  626: 
  627: /*
  628:  * Generic low-level frame buffer functions
  629:  * The low-level functions in the frame buffer subdriver may use these
  630:  * functions.
  631:  */
  632: 
  633: void
  634: fb_dump_adp_info(char *driver, video_adapter_t *adp, int level)
  635: {
  636:     if (level <= 0)
  637: 	return;
  638: 
  639:     printf("%s%d: %s%d, %s, type:%s (%d), flags:0x%x\n", 
  640: 	   FB_DRIVER_NAME, adp->va_index, driver, adp->va_unit, adp->va_name,
  641: 	   adapter_name(adp->va_type), adp->va_type, adp->va_flags);
  642:     printf("%s%d: port:0x%x-0x%x, crtc:0x%x, mem:0x%x 0x%x\n",
  643: 	   FB_DRIVER_NAME, adp->va_index,
  644: 	   adp->va_io_base, adp->va_io_base + adp->va_io_size - 1,
  645: 	   adp->va_crtc_addr, adp->va_mem_base, adp->va_mem_size);
  646:     printf("%s%d: init mode:%d, bios mode:%d, current mode:%d\n",
  647: 	   FB_DRIVER_NAME, adp->va_index,
  648: 	   adp->va_initial_mode, adp->va_initial_bios_mode, adp->va_mode);
  649:     printf("%s%d: window:%p size:%dk gran:%dk, buf:%p size:%dk\n",
  650: 	   FB_DRIVER_NAME, adp->va_index, 
  651: 	   (void *)adp->va_window, (int)adp->va_window_size/1024,
  652: 	   (int)adp->va_window_gran/1024, (void *)adp->va_buffer,
  653: 	   (int)adp->va_buffer_size/1024);
  654: }
  655: 
  656: void
  657: fb_dump_mode_info(char *driver, video_adapter_t *adp, video_info_t *info,
  658: 		  int level)
  659: {
  660:     if (level <= 0)
  661: 	return;
  662: 
  663:     printf("%s%d: %s, mode:%d, flags:0x%x ", 
  664: 	   driver, adp->va_unit, adp->va_name, info->vi_mode, info->vi_flags);
  665:     if (info->vi_flags & V_INFO_GRAPHICS)
  666: 	printf("G %dx%dx%d, %d plane(s), font:%dx%d, ",
  667: 	       info->vi_width, info->vi_height, 
  668: 	       info->vi_depth, info->vi_planes, 
  669: 	       info->vi_cwidth, info->vi_cheight); 
  670:     else
  671: 	printf("T %dx%d, font:%dx%d, ",
  672: 	       info->vi_width, info->vi_height, 
  673: 	       info->vi_cwidth, info->vi_cheight); 
  674:     printf("win:0x%x\n", info->vi_window);
  675: }
  676: 
  677: int
  678: fb_type(int adp_type)
  679: {
  680: 	static struct {
  681: 		int	fb_type;
  682: 		int	va_type;
  683: 	} types[] = {
  684: 		{ FBTYPE_MDA,		KD_MONO },
  685: 		{ FBTYPE_HERCULES,	KD_HERCULES },
  686: 		{ FBTYPE_CGA,		KD_CGA },
  687: 		{ FBTYPE_EGA,		KD_EGA },
  688: 		{ FBTYPE_VGA,		KD_VGA },
  689: 		{ FBTYPE_PC98,		KD_PC98 },
  690: 		{ FBTYPE_TGA,		KD_TGA },
  691: 	};
  692: 	int i;
  693: 
  694: 	for (i = 0; i < sizeof(types)/sizeof(types[0]); ++i) {
  695: 		if (types[i].va_type == adp_type)
  696: 			return types[i].fb_type;
  697: 	}
  698: 	return -1;
  699: }
  700: 
  701: int
  702: fb_commonioctl(video_adapter_t *adp, u_long cmd, caddr_t arg)
  703: {
  704: 	int error;
  705: 	int s;
  706: 
  707: 	/* assert(adp != NULL) */
  708: 
  709: 	error = 0;
  710: 	s = spltty();
  711: 
  712: 	switch (cmd) {
  713: 
  714: 	case FBIO_ADAPTER:	/* get video adapter index */
  715: 		*(int *)arg = adp->va_index;
  716: 		break;
  717: 
  718: 	case FBIO_ADPTYPE:	/* get video adapter type */
  719: 		*(int *)arg = adp->va_type;
  720: 		break;
  721: 
  722: 	case FBIO_ADPINFO:	/* get video adapter info */
  723: 	        ((video_adapter_info_t *)arg)->va_index = adp->va_index;
  724: 		((video_adapter_info_t *)arg)->va_type = adp->va_type;
  725: 		bcopy(adp->va_name, ((video_adapter_info_t *)arg)->va_name,
  726: 		      imin(strlen(adp->va_name) + 1,
  727: 			   sizeof(((video_adapter_info_t *)arg)->va_name))); 
  728: 		((video_adapter_info_t *)arg)->va_unit = adp->va_unit;
  729: 		((video_adapter_info_t *)arg)->va_flags = adp->va_flags;
  730: 		((video_adapter_info_t *)arg)->va_io_base = adp->va_io_base;
  731: 		((video_adapter_info_t *)arg)->va_io_size = adp->va_io_size;
  732: 		((video_adapter_info_t *)arg)->va_crtc_addr = adp->va_crtc_addr;
  733: 		((video_adapter_info_t *)arg)->va_mem_base = adp->va_mem_base;
  734: 		((video_adapter_info_t *)arg)->va_mem_size = adp->va_mem_size;
  735: 		((video_adapter_info_t *)arg)->va_window
  736: #ifdef __i386__
  737: 			= vtophys(adp->va_window);
  738: #else
  739: 			= adp->va_window;
  740: #endif
  741: 		((video_adapter_info_t *)arg)->va_window_size
  742: 			= adp->va_window_size;
  743: 		((video_adapter_info_t *)arg)->va_window_gran
  744: 			= adp->va_window_gran;
  745: 		((video_adapter_info_t *)arg)->va_window_orig
  746: 			= adp->va_window_orig;
  747: 		((video_adapter_info_t *)arg)->va_unused0
  748: #ifdef __i386__
  749: 			= (adp->va_buffer) ? vtophys(adp->va_buffer) : 0;
  750: #else
  751: 			= adp->va_buffer;
  752: #endif
  753: 		((video_adapter_info_t *)arg)->va_buffer_size
  754: 			= adp->va_buffer_size;
  755: 		((video_adapter_info_t *)arg)->va_mode = adp->va_mode;
  756: 		((video_adapter_info_t *)arg)->va_initial_mode
  757: 			= adp->va_initial_mode;
  758: 		((video_adapter_info_t *)arg)->va_initial_bios_mode
  759: 			= adp->va_initial_bios_mode;
  760: 		((video_adapter_info_t *)arg)->va_line_width
  761: 			= adp->va_line_width;
  762: 		((video_adapter_info_t *)arg)->va_disp_start.x
  763: 			= adp->va_disp_start.x;
  764: 		((video_adapter_info_t *)arg)->va_disp_start.y
  765: 			= adp->va_disp_start.y;
  766: 		break;
  767: 
  768: 	case FBIO_MODEINFO:	/* get mode information */
  769: 		error = (*vidsw[adp->va_index]->get_info)(adp, 
  770: 				((video_info_t *)arg)->vi_mode,
  771: 				(video_info_t *)arg); 
  772: 		if (error)
  773: 			error = ENODEV;
  774: 		break;
  775: 
  776: 	case FBIO_FINDMODE:	/* find a matching video mode */
  777: 		error = (*vidsw[adp->va_index]->query_mode)(adp, 
  778: 				(video_info_t *)arg); 
  779: 		break;
  780: 
  781: 	case FBIO_GETMODE:	/* get video mode */
  782: 		*(int *)arg = adp->va_mode;
  783: 		break;
  784: 
  785: 	case FBIO_SETMODE:	/* set video mode */
  786: 		error = (*vidsw[adp->va_index]->set_mode)(adp, *(int *)arg);
  787: 		if (error)
  788: 			error = ENODEV;	/* EINVAL? */
  789: 		break;
  790: 
  791: 	case FBIO_GETWINORG:	/* get frame buffer window origin */
  792: 		*(u_int *)arg = adp->va_window_orig;
  793: 		break;
  794: 
  795: 	case FBIO_GETDISPSTART:	/* get display start address */
  796: 		((video_display_start_t *)arg)->x = adp->va_disp_start.x;
  797: 		((video_display_start_t *)arg)->y = adp->va_disp_start.y;
  798: 		break;
  799: 
  800: 	case FBIO_GETLINEWIDTH:	/* get scan line width in bytes */
  801: 		*(u_int *)arg = adp->va_line_width;
  802: 		break;
  803: 
  804: 	case FBIO_GETPALETTE:	/* get color palette */
  805: 	case FBIO_SETPALETTE:	/* set color palette */
  806: 		/* XXX */
  807: 
  808: 	case FBIOPUTCMAP:
  809: 	case FBIOGETCMAP:
  810: 		/* XXX */
  811: 
  812: 	case FBIO_SETWINORG:	/* set frame buffer window origin */
  813: 	case FBIO_SETDISPSTART:	/* set display start address */
  814: 	case FBIO_SETLINEWIDTH:	/* set scan line width in pixel */
  815: 
  816: 	case FBIOGTYPE:
  817: 	case FBIOGATTR:
  818: 	case FBIOSVIDEO:
  819: 	case FBIOGVIDEO:
  820: 	case FBIOSCURSOR:
  821: 	case FBIOGCURSOR:
  822: 	case FBIOSCURPOS:
  823: 	case FBIOGCURPOS:
  824: 	case FBIOGCURMAX:
  825: 
  826: 	default:
  827: 		error = ENODEV;
  828: 		break;
  829: 	}
  830: 
  831: 	splx(s);
  832: 	return error;
  833: }