]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/fb/fb.c
MFV: zlib 1.3
[FreeBSD/FreeBSD.git] / sys / dev / fb / fb.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer as
12  *    the first lines of this file unmodified.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include <sys/cdefs.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/bus.h>
38 #include <sys/kernel.h>
39 #include <sys/malloc.h>
40 #include <sys/module.h>
41 #include <sys/uio.h>
42 #include <sys/fbio.h>
43 #include <sys/linker_set.h>
44
45 #include <vm/vm.h>
46 #include <vm/pmap.h>
47
48 #include <dev/fb/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 #define ARRAY_DELTA     4
68
69 static int
70 vid_realloc_array(void)
71 {
72         video_adapter_t **new_adp;
73         video_switch_t **new_vidsw;
74         int newsize;
75         int s;
76
77         if (!vid_malloc)
78                 return ENOMEM;
79
80         s = spltty();
81         newsize = rounddown(adapters + ARRAY_DELTA, ARRAY_DELTA);
82         new_adp = malloc(sizeof(*new_adp)*newsize, M_DEVBUF, M_WAITOK | M_ZERO);
83         new_vidsw = malloc(sizeof(*new_vidsw)*newsize, M_DEVBUF,
84             M_WAITOK | M_ZERO);
85         bcopy(adapter, new_adp, sizeof(*adapter)*adapters);
86         bcopy(vidsw, new_vidsw, sizeof(*vidsw)*adapters);
87         if (adapters > 1) {
88                 free(adapter, M_DEVBUF);
89                 free(vidsw, M_DEVBUF);
90         }
91         adapter = new_adp;
92         vidsw = new_vidsw;
93         adapters = newsize;
94         splx(s);
95
96         if (bootverbose)
97                 printf("fb: new array size %d\n", adapters);
98
99         return 0;
100 }
101
102 static void
103 vid_malloc_init(void *arg)
104 {
105         vid_malloc = TRUE;
106 }
107
108 SYSINIT(vid_mem, SI_SUB_KMEM, SI_ORDER_ANY, vid_malloc_init, NULL);
109
110 /*
111  * Low-level frame buffer driver functions
112  * frame buffer subdrivers, such as the VGA driver, call these functions
113  * to initialize the video_adapter structure and register it to the virtual
114  * frame buffer driver `fb'.
115  */
116
117 /* initialize the video_adapter_t structure */
118 void
119 vid_init_struct(video_adapter_t *adp, char *name, int type, int unit)
120 {
121         adp->va_flags = 0;
122         adp->va_name = name;
123         adp->va_type = type;
124         adp->va_unit = unit;
125 }
126
127 /* Register a video adapter */
128 int
129 vid_register(video_adapter_t *adp)
130 {
131         const video_driver_t **list;
132         const video_driver_t *p;
133         int index;
134
135         for (index = 0; index < adapters; ++index) {
136                 if (adapter[index] == NULL)
137                         break;
138         }
139         if (index >= adapters) {
140                 if (vid_realloc_array())
141                         return -1;
142         }
143
144         adp->va_index = index;
145         adp->va_token = NULL;
146         SET_FOREACH(list, videodriver_set) {
147                 p = *list;
148                 if (strcmp(p->name, adp->va_name) == 0) {
149                         adapter[index] = adp;
150                         vidsw[index] = p->vidsw;
151                         return index;
152                 }
153         }
154
155         return -1;
156 }
157
158 int
159 vid_unregister(video_adapter_t *adp)
160 {
161         if ((adp->va_index < 0) || (adp->va_index >= adapters))
162                 return ENOENT;
163         if (adapter[adp->va_index] != adp)
164                 return ENOENT;
165
166         adapter[adp->va_index] = NULL;
167         vidsw[adp->va_index] = NULL;
168         return 0;
169 }
170
171 /* Get video I/O function table */
172 video_switch_t
173 *vid_get_switch(char *name)
174 {
175         const video_driver_t **list;
176         const video_driver_t *p;
177
178         SET_FOREACH(list, videodriver_set) {
179                 p = *list;
180                 if (strcmp(p->name, name) == 0)
181                         return p->vidsw;
182         }
183
184         return NULL;
185 }
186
187 /*
188  * Video card client functions
189  * Video card clients, such as the console driver `syscons' and the frame
190  * buffer cdev driver, use these functions to claim and release a card for
191  * exclusive use.
192  */
193
194 /* find the video card specified by a driver name and a unit number */
195 int
196 vid_find_adapter(char *driver, int unit)
197 {
198         int i;
199
200         for (i = 0; i < adapters; ++i) {
201                 if (adapter[i] == NULL)
202                         continue;
203                 if (strcmp("*", driver) && strcmp(adapter[i]->va_name, driver))
204                         continue;
205                 if ((unit != -1) && (adapter[i]->va_unit != unit))
206                         continue;
207                 return i;
208         }
209         return -1;
210 }
211
212 /* allocate a video card */
213 int
214 vid_allocate(char *driver, int unit, void *id)
215 {
216         int index;
217         int s;
218
219         s = spltty();
220         index = vid_find_adapter(driver, unit);
221         if (index >= 0) {
222                 if (adapter[index]->va_token) {
223                         splx(s);
224                         return -1;
225                 }
226                 adapter[index]->va_token = id;
227         }
228         splx(s);
229         return index;
230 }
231
232 int
233 vid_release(video_adapter_t *adp, void *id)
234 {
235         int error;
236         int s;
237
238         s = spltty();
239         if (adp->va_token == NULL) {
240                 error = EINVAL;
241         } else if (adp->va_token != id) {
242                 error = EPERM;
243         } else {
244                 adp->va_token = NULL;
245                 error = 0;
246         }
247         splx(s);
248         return error;
249 }
250
251 /* Get a video adapter structure */
252 video_adapter_t
253 *vid_get_adapter(int index)
254 {
255         if ((index < 0) || (index >= adapters))
256                 return NULL;
257         return adapter[index];
258 }
259
260 /* Configure drivers: this is a backdoor for the console driver XXX */
261 int
262 vid_configure(int flags)
263 {
264         const video_driver_t **list;
265         const video_driver_t *p;
266
267         SET_FOREACH(list, videodriver_set) {
268                 p = *list;
269                 if (p->configure != NULL)
270                         (*p->configure)(flags);
271         }
272
273         return 0;
274 }
275
276 #define FB_DRIVER_NAME  "fb"
277
278 static char
279 *adapter_name(int type)
280 {
281     static struct {
282         int type;
283         char *name;
284     } names[] = {
285         { KD_MONO,      "MDA" },
286         { KD_HERCULES,  "Hercules" },
287         { KD_CGA,       "CGA" },
288         { KD_EGA,       "EGA" },
289         { KD_VGA,       "VGA" },
290         { KD_TGA,       "TGA" },
291         { -1,           "Unknown" },
292     };
293     int i;
294
295     for (i = 0; names[i].type != -1; ++i)
296         if (names[i].type == type)
297             break;
298     return names[i].name;
299 }
300
301 /*
302  * Generic low-level frame buffer functions
303  * The low-level functions in the frame buffer subdriver may use these
304  * functions.
305  */
306
307 void
308 fb_dump_adp_info(char *driver, video_adapter_t *adp, int level)
309 {
310     if (level <= 0)
311         return;
312
313     printf("%s%d: %s%d, %s, type:%s (%d), flags:0x%x\n", 
314            FB_DRIVER_NAME, adp->va_index, driver, adp->va_unit, adp->va_name,
315            adapter_name(adp->va_type), adp->va_type, adp->va_flags);
316     printf("%s%d: port:0x%lx-0x%lx, crtc:0x%lx, mem:0x%lx 0x%x\n",
317            FB_DRIVER_NAME, adp->va_index, (u_long)adp->va_io_base, 
318            (u_long)adp->va_io_base + adp->va_io_size - 1,
319            (u_long)adp->va_crtc_addr, (u_long)adp->va_mem_base, 
320            adp->va_mem_size);
321     printf("%s%d: init mode:%d, bios mode:%d, current mode:%d\n",
322            FB_DRIVER_NAME, adp->va_index,
323            adp->va_initial_mode, adp->va_initial_bios_mode, adp->va_mode);
324     printf("%s%d: window:%p size:%dk gran:%dk, buf:%p size:%dk\n",
325            FB_DRIVER_NAME, adp->va_index, 
326            (void *)adp->va_window, (int)adp->va_window_size/1024,
327            (int)adp->va_window_gran/1024, (void *)adp->va_buffer,
328            (int)adp->va_buffer_size/1024);
329 }
330
331 void
332 fb_dump_mode_info(char *driver, video_adapter_t *adp, video_info_t *info,
333                   int level)
334 {
335     if (level <= 0)
336         return;
337
338     printf("%s%d: %s, mode:%d, flags:0x%x ", 
339            driver, adp->va_unit, adp->va_name, info->vi_mode, info->vi_flags);
340     if (info->vi_flags & V_INFO_GRAPHICS)
341         printf("G %dx%dx%d, %d plane(s), font:%dx%d, ",
342                info->vi_width, info->vi_height, 
343                info->vi_depth, info->vi_planes, 
344                info->vi_cwidth, info->vi_cheight); 
345     else
346         printf("T %dx%d, font:%dx%d, ",
347                info->vi_width, info->vi_height, 
348                info->vi_cwidth, info->vi_cheight); 
349     printf("win:0x%lx\n", (u_long)info->vi_window);
350 }
351
352 int
353 fb_type(int adp_type)
354 {
355         static struct {
356                 int     fb_type;
357                 int     va_type;
358         } types[] = {
359                 { FBTYPE_MDA,           KD_MONO },
360                 { FBTYPE_HERCULES,      KD_HERCULES },
361                 { FBTYPE_CGA,           KD_CGA },
362                 { FBTYPE_EGA,           KD_EGA },
363                 { FBTYPE_VGA,           KD_VGA },
364                 { FBTYPE_TGA,           KD_TGA },
365         };
366         int i;
367
368         for (i = 0; i < nitems(types); ++i) {
369                 if (types[i].va_type == adp_type)
370                         return types[i].fb_type;
371         }
372         return -1;
373 }
374
375 int
376 fb_commonioctl(video_adapter_t *adp, u_long cmd, caddr_t arg)
377 {
378         int error;
379         int s;
380
381         /* assert(adp != NULL) */
382
383         error = 0;
384         s = spltty();
385
386         switch (cmd) {
387
388         case FBIO_ADAPTER:      /* get video adapter index */
389                 *(int *)arg = adp->va_index;
390                 break;
391
392         case FBIO_ADPTYPE:      /* get video adapter type */
393                 *(int *)arg = adp->va_type;
394                 break;
395
396         case FBIO_ADPINFO:      /* get video adapter info */
397                 ((video_adapter_info_t *)arg)->va_index = adp->va_index;
398                 ((video_adapter_info_t *)arg)->va_type = adp->va_type;
399                 bcopy(adp->va_name, ((video_adapter_info_t *)arg)->va_name,
400                       imin(strlen(adp->va_name) + 1,
401                            sizeof(((video_adapter_info_t *)arg)->va_name))); 
402                 ((video_adapter_info_t *)arg)->va_unit = adp->va_unit;
403                 ((video_adapter_info_t *)arg)->va_flags = adp->va_flags;
404                 ((video_adapter_info_t *)arg)->va_io_base = adp->va_io_base;
405                 ((video_adapter_info_t *)arg)->va_io_size = adp->va_io_size;
406                 ((video_adapter_info_t *)arg)->va_crtc_addr = adp->va_crtc_addr;
407                 ((video_adapter_info_t *)arg)->va_mem_base = adp->va_mem_base;
408                 ((video_adapter_info_t *)arg)->va_mem_size = adp->va_mem_size;
409                 ((video_adapter_info_t *)arg)->va_window
410 #if defined(__amd64__) || defined(__i386__)
411                         = vtophys(adp->va_window);
412 #else
413                         = adp->va_window;
414 #endif
415                 ((video_adapter_info_t *)arg)->va_window_size
416                         = adp->va_window_size;
417                 ((video_adapter_info_t *)arg)->va_window_gran
418                         = adp->va_window_gran;
419                 ((video_adapter_info_t *)arg)->va_window_orig
420                         = adp->va_window_orig;
421                 ((video_adapter_info_t *)arg)->va_unused0
422 #if defined(__amd64__) || defined(__i386__)
423                         = adp->va_buffer != 0 ? vtophys(adp->va_buffer) : 0;
424 #else
425                         = adp->va_buffer;
426 #endif
427                 ((video_adapter_info_t *)arg)->va_buffer_size
428                         = adp->va_buffer_size;
429                 ((video_adapter_info_t *)arg)->va_mode = adp->va_mode;
430                 ((video_adapter_info_t *)arg)->va_initial_mode
431                         = adp->va_initial_mode;
432                 ((video_adapter_info_t *)arg)->va_initial_bios_mode
433                         = adp->va_initial_bios_mode;
434                 ((video_adapter_info_t *)arg)->va_line_width
435                         = adp->va_line_width;
436                 ((video_adapter_info_t *)arg)->va_disp_start.x
437                         = adp->va_disp_start.x;
438                 ((video_adapter_info_t *)arg)->va_disp_start.y
439                         = adp->va_disp_start.y;
440                 break;
441
442         case FBIO_MODEINFO:     /* get mode information */
443                 error = vidd_get_info(adp,
444                     ((video_info_t *)arg)->vi_mode,
445                     (video_info_t *)arg);
446                 if (error)
447                         error = ENODEV;
448                 break;
449
450         case FBIO_FINDMODE:     /* find a matching video mode */
451                 error = vidd_query_mode(adp, (video_info_t *)arg);
452                 break;
453
454         case FBIO_GETMODE:      /* get video mode */
455                 *(int *)arg = adp->va_mode;
456                 break;
457
458         case FBIO_SETMODE:      /* set video mode */
459                 error = vidd_set_mode(adp, *(int *)arg);
460                 if (error)
461                         error = ENODEV; /* EINVAL? */
462                 break;
463
464         case FBIO_GETWINORG:    /* get frame buffer window origin */
465                 *(u_int *)arg = adp->va_window_orig;
466                 break;
467
468         case FBIO_GETDISPSTART: /* get display start address */
469                 ((video_display_start_t *)arg)->x = adp->va_disp_start.x;
470                 ((video_display_start_t *)arg)->y = adp->va_disp_start.y;
471                 break;
472
473         case FBIO_GETLINEWIDTH: /* get scan line width in bytes */
474                 *(u_int *)arg = adp->va_line_width;
475                 break;
476
477         case FBIO_BLANK:        /* blank display */
478                 error = vidd_blank_display(adp, *(int *)arg);
479                 break;
480
481         case FBIO_GETPALETTE:   /* get color palette */
482         case FBIO_SETPALETTE:   /* set color palette */
483                 /* XXX */
484
485         case FBIOPUTCMAP:
486         case FBIOGETCMAP:
487                 /* XXX */
488
489         case FBIO_SETWINORG:    /* set frame buffer window origin */
490         case FBIO_SETDISPSTART: /* set display start address */
491         case FBIO_SETLINEWIDTH: /* set scan line width in pixel */
492
493         case FBIOGTYPE:
494
495         default:
496                 error = ENODEV;
497                 break;
498         }
499
500         splx(s);
501         return error;
502 }