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