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