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