source: rtems/c/src/lib/libbsp/i386/pc386/console/fb_vesa_rm.c @ 56399c3b

4.115
Last change on this file since 56399c3b was 56399c3b, checked in by Jan Dolezal <dolezj21@…>, on May 23, 2015 at 5:32:00 PM

i386/pc386/VESA framebuffer driver: modified and extended initialization options

driver is not initialized by default
initialization is possible through multiboot command line option or
through the string variable (see fb_default_mode.h) set in user's module
allowing the driver to evaluate this variable after the two
modules are linked together

  • Property mode set to 100644
File size: 32.9 KB
Line 
1/**
2 * @file fb_vesa_rm.c
3 *
4 * @ingroup i386_pc386
5 *
6 * @brief FB driver for graphic hardware compatible with VESA Bios Extension
7 *     Real mode interface utilized
8 *     Tested on real HW.
9 *
10 * Public sources related:
11 *   - VESA BIOS EXTENSION (VBE) Core Function Standard, Ver: 3.0, Sep 16, 1998
12 *   - VESA Enhanced Extended Display Identification Data (E-EDID) Standard
13 *     Release A, Revision 2, September 25, 2006
14 *
15 * Hardware is completely initialized upon boot of the system.
16 * Therefore there is no way to change graphics mode later.
17 *
18 * Interrupt 0x10 is used for entering graphics BIOS.
19 *
20 * Driver reads parameter from multiboot command line to setup video:
21 * "--video=<resX>x<resY>[-<bpp>]"
22 * "--video=auto" - try EDID to find mode that fits the display attached best
23 * "--video=none" / "--video=off" - do not initialize the driver
24 * If cmdline parameter is not specified the rtems_fb_default_mode
25 * variable content is tested (see doc below).
26 * Command line option has higher priority. rtems_fb_default_mode is probed
27 * only if cmdline "--video=" is not specified at all.
28 *
29 * If neither of the above options is specified the driver is not initialized.
30 */
31
32/*
33 * Copyright (c) 2014 - CTU in Prague
34 *                      Jan DoleÅŸal ( dolezj21@fel.cvut.cz )
35 *
36 * The license and distribution terms for this file may be
37 * found in the file LICENSE in this distribution or at
38 * http://www.rtems.org/license/LICENSE.
39 *
40 * The code for rtems_buffer_* functions was greatly
41 * inspired or coppied from:
42 *   - RTEMS fb_cirrus.c - Alexandru-Sever Horin (alex.sever.h@gmail.com)
43 */
44
45#include <bsp.h>
46
47#include <bsp/fb_default_mode.h>
48#include <bsp/fb_vesa.h>
49#include <bsp/realmode_int.h>
50
51#include <pthread.h>
52
53#include <rtems/libio.h>
54
55#include <rtems/fb.h>
56#include <rtems/framebuffer.h>
57
58#include <stdlib.h>
59
60#define FB_VESA_NAME    "FB_VESA_RM"
61
62/**
63 * @brief Allows to enable initialization of VESA real mode driver from
64 * an application by setting the value of this variable to non null value in
65 * user's module. The value of this variable will be then updated
66 * when linked with application's object.
67 *
68 * Further the value should point to string in the following format:
69 * "<resX>x<resY>[-<bpp>]" - e.g. "1024x768-32"
70 * "auto" - try EDID to find mode that fits the display attached best
71 * "none" / "off" - do not initialize the driver
72 * the given parameters are used if applicable.
73 *
74 * Command line argument "--video=" has priority over this string.
75 */
76const char * const rtems_fb_default_mode;
77
78/**
79 * @brief Initializes VBE framebuffer during bootup.
80 *
81 * utilizes switches to real mode interrupts and therefore must be
82 * called during bootup before tick is set up and real-time
83 * interrupt vectors utilized
84 */
85void vesa_realmode_bootup_init(void);
86
87/* mutex for protection against multiple opens, when called frame_buffer_open */
88static pthread_mutex_t vesa_mutex = PTHREAD_MUTEX_INITIALIZER;
89
90/* screen information for the VGA driver
91 * standard structures - from RTEMS fb interface
92 */
93static struct fb_var_screeninfo fb_var;
94static struct fb_fix_screeninfo fb_fix;
95
96static int32_t vbe_used_mode;
97
98uint32_t VBE_controller_information( VBE_vbe_info_block *info_block,
99                                            uint16_t queried_VBE_Version)
100{
101    uint16_t size;
102    VBE_vbe_info_block *VBE_buffer =
103        (VBE_vbe_info_block *)i386_get_default_rm_buffer(&size);
104    i386_realmode_interrupt_registers parret;
105    parret.reg_eax = VBE_RetVBEConInf;
106    uint16_t seg, off;
107    i386_Physical_to_real(VBE_buffer, &seg, &off);
108    parret.reg_edi = (uint32_t)off;
109    parret.reg_es = seg;
110    /* indicate to graphic's bios that VBE2.0 extended information is desired */
111    if (queried_VBE_Version >= 0x200)
112    {
113        strncpy(
114            (char *)&VBE_buffer->VbeSignature,
115            VBE20plus_SIGNATURE,
116            4*sizeof(size_t)
117        );
118    }
119    if (i386_real_interrupt_call(INTERRUPT_NO_VIDEO_SERVICES, &parret) == 0)
120        return -1;
121    if ((parret.reg_eax & 0xFFFF) ==
122        (VBE_callSuccessful<<8 | VBE_functionSupported))
123    {
124        *info_block = *VBE_buffer;
125    }
126    return (parret.reg_eax & 0xFFFF);
127}
128
129uint32_t VBE_mode_information( VBE_mode_info_block *info_block,
130                                    uint16_t mode_number)
131{
132    uint16_t size;
133    VBE_mode_info_block *VBE_buffer =
134        (VBE_mode_info_block *)i386_get_default_rm_buffer(&size);
135    i386_realmode_interrupt_registers parret;
136    parret.reg_eax = VBE_RetVBEModInf;
137    parret.reg_ecx = mode_number;
138    uint16_t seg, off;
139    i386_Physical_to_real(VBE_buffer, &seg, &off);
140    parret.reg_edi = (uint32_t)off;
141    parret.reg_es = seg;
142    if (i386_real_interrupt_call(INTERRUPT_NO_VIDEO_SERVICES, &parret) == 0)
143        return -1;
144    if ((parret.reg_eax & 0xFFFF) ==
145        (VBE_callSuccessful<<8 | VBE_functionSupported))
146    {
147        *info_block = *VBE_buffer;
148    }
149    return (parret.reg_eax & 0xFFFF);
150}
151
152uint32_t VBE_set_mode( uint16_t mode_number,
153                            VBE_CRTC_info_block *info_block)
154{
155    uint16_t size;
156    VBE_CRTC_info_block *VBE_buffer =
157        (VBE_CRTC_info_block *)i386_get_default_rm_buffer(&size);
158    i386_realmode_interrupt_registers parret;
159    /* copy CRTC */
160    *VBE_buffer = *info_block;
161    parret.reg_eax = VBE_SetVBEMod;
162    parret.reg_ebx = mode_number;
163    uint16_t seg, off;
164    i386_Physical_to_real(VBE_buffer, &seg, &off);
165    parret.reg_edi = (uint32_t)off;
166    parret.reg_es = seg;
167    if (i386_real_interrupt_call(INTERRUPT_NO_VIDEO_SERVICES, &parret) == 0)
168        return -1;
169    return (parret.reg_eax & 0xFFFF);
170}
171
172uint32_t VBE_current_mode(uint16_t *mode_number)
173{
174    i386_realmode_interrupt_registers parret;
175    parret.reg_eax = VBE_RetCurVBEMod;
176    if (i386_real_interrupt_call(INTERRUPT_NO_VIDEO_SERVICES, &parret) == 0)
177        return -1;
178    *mode_number = (uint16_t)parret.reg_ebx;
179    return (parret.reg_eax & 0xFFFF);
180}
181
182uint32_t VBE_report_DDC_capabilities(uint16_t controller_unit_number,
183                                        uint8_t *seconds_to_transfer_EDID_block,
184                                        uint8_t *DDC_level_supported)
185{
186    i386_realmode_interrupt_registers parret;
187    parret.reg_eax = VBE_DisDatCha;
188    parret.reg_ebx = VBEDDC_Capabilities;
189    parret.reg_ecx = controller_unit_number;
190    parret.reg_edi = 0;
191    parret.reg_es = 0;
192    if (i386_real_interrupt_call(INTERRUPT_NO_VIDEO_SERVICES, &parret) == 0)
193        return -1;
194    *seconds_to_transfer_EDID_block = (uint8_t)parret.reg_ebx >> 8;
195    *DDC_level_supported = (uint8_t)parret.reg_ebx;
196    return (parret.reg_eax & 0xFFFF);
197}
198
199uint32_t VBE_read_EDID(uint16_t controller_unit_number,
200                            uint16_t EDID_block_number,
201                            EDID_edid1 *buffer)
202{
203    uint16_t size;
204    EDID_edid1 *VBE_buffer = (EDID_edid1*)i386_get_default_rm_buffer(&size);
205    i386_realmode_interrupt_registers parret;
206    parret.reg_eax = VBE_DisDatCha;
207    parret.reg_ebx = VBEDDC_ReadEDID;
208    parret.reg_ecx = controller_unit_number;
209    parret.reg_edx = EDID_block_number;
210    uint16_t seg, off;
211    i386_Physical_to_real(VBE_buffer, &seg, &off);
212    parret.reg_edi = (uint32_t)off;
213    parret.reg_es = seg;
214    if (i386_real_interrupt_call(INTERRUPT_NO_VIDEO_SERVICES, &parret) == 0)
215        return -1;
216    if ((parret.reg_eax & 0xFFFF) ==
217        (VBE_callSuccessful<<8 | VBE_functionSupported))
218    {
219        *buffer = *VBE_buffer;
220    }
221    return (parret.reg_eax & 0xFFFF);
222}
223
224/**
225 * @brief Basic graphic's mode parameters
226 */
227typedef struct {
228    /** number of the graphic's mode */
229    uint16_t mode_number;
230    /** number of pixels in one line */
231    uint16_t resX;
232    /** number of lines */
233    uint16_t resY;
234    /** bits per pixel */
235    uint8_t bpp;
236} Mode_params;
237
238typedef enum {
239    NO_SUITABLE_MODE    = -1,
240    BAD_FORMAT          = -2,
241    AUTO_SELECT         = -3,
242    DONT_INIT           = -4,
243    NO_MODE_REQ         = -5,
244} mode_err_ret_val;
245
246/**
247 * @brief Find mode by resolution in the given list of modes
248 *
249 * finds mode in \p mode_list of \p list_length length according to resolution
250 * given in \p searched_resolution . If bpp is given in that struct as well
251 * mode with such color depth and resolution is searched for. Otherwise bpp
252 * has to be zero. Mode number found is returned and also filled into
253 * \p searched_resolution . bpp is also filled into \p searchedResolution if it
254 * was 0 before call.
255 *
256 * @param[in] mode_list list of modes to be searched
257 * @param[in] list_length number of modes in the list
258 * @param[in,out] searched_resolution element filled with searched resolution
259 *                or/and bpp; mode_number is filled in if appropriate mode found
260 * @retval mode number satisfying given parameters
261 * @retval -1 no suitable mode found
262 */
263static int32_t find_mode_by_resolution(Mode_params *mode_list,
264                                        uint8_t list_length,
265                                        Mode_params *searched_resolution)
266{
267    uint8_t i = 0;
268    while (i < list_length)
269    {
270        if (searched_resolution->resX == mode_list[i].resX &&
271            searched_resolution->resY == mode_list[i].resY)
272        {
273            if (searched_resolution->bpp==0 ||
274                searched_resolution->bpp==mode_list[i].bpp)
275            {
276                searched_resolution->bpp = mode_list[i].bpp;
277                searched_resolution->mode_number = mode_list[i].mode_number;
278                return mode_list[i].mode_number;
279            }
280        }
281        i++;
282    }
283    return NO_SUITABLE_MODE;
284}
285
286/**
287 * @brief Find mode given in string format.
288 *
289 *  expected format
290 *  <resX>x<resY>[-<bpp>]
291 *  numbers <resX>, <resY> and <bpp> are decadic
292 *
293 * @param[in] mode_list list of modes to be searched
294 * @param[in] list_length number of modes in the list
295 * @param[in] video_string string to be parsed
296 * @retval video mode number to be set
297 * @retval -1 no suitable mode found
298 * @retval -2 bad format of the video_string
299 * @retval -3 automatic mode selection requested
300 * @retval -4 request to not initialize graphics
301 * @retval -5 no mode requested/empty video string
302 */
303static int32_t find_mode_from_string(Mode_params *mode_list,
304                                      uint8_t list_length,
305                                      const char *video_string)
306{
307    const char* opt;
308    Mode_params cmdline_mode;
309    char* endptr;
310    cmdline_mode.bpp = 16; /* default bpp */
311    opt = video_string;
312    if (opt)
313    {
314        if (strncmp(opt, "auto", 4) == 0)
315            return AUTO_SELECT;
316        if (strncmp(opt, "none", 4) == 0 ||
317            strncmp(opt, "off", 3) == 0)
318        {
319            return DONT_INIT;
320        }
321        cmdline_mode.resX = strtol(opt, &endptr, 10);
322        if (*endptr != 'x')
323        {
324            return BAD_FORMAT;
325        }
326        opt = endptr+1;
327        cmdline_mode.resY = strtol(opt, &endptr, 10);
328        switch (*endptr)
329        {
330            case '-':
331                opt = endptr+1;
332                if (strlen(opt) <= 2)
333                    cmdline_mode.bpp = strtol(opt, &endptr, 10);
334                else
335                {
336                    cmdline_mode.bpp = strtol(opt, &endptr, 10);
337                    if (*endptr != ' ')
338                    {
339                        return BAD_FORMAT;
340                    }
341                }
342            case ' ':
343            case 0:
344                break;
345            default:
346                return BAD_FORMAT;
347        }
348
349        return find_mode_by_resolution(mode_list, list_length, &cmdline_mode);
350    }
351    return NO_MODE_REQ;
352}
353
354/**
355 * @brief Find mode given within command line.
356 *
357 * Parse command line option "--video=" if available.
358 *  expected format
359 *  --video=<resX>x<resY>[-<bpp>]
360 *  numbers <resX>, <resY> and <bpp> are decadic
361 *
362 * @param[in] mode_list list of modes to be searched
363 * @param[in] list_length number of modes in the list
364 * @retval video mode number to be set
365 * @retval -1 no suitable mode found
366 * @retval -2 bad format of the video_string
367 * @retval -3 automatic mode selection requested
368 * @retval -4 request to not initialize graphics
369 * @retval -5 no mode requested/empty video string
370 */
371static int32_t find_mode_using_cmdline(Mode_params *mode_list,
372                                        uint8_t list_length)
373{
374    const char* opt;
375    opt = bsp_cmdline_arg("--video=");
376    if (opt)
377    {
378        opt += sizeof("--video=")-1;
379        return find_mode_from_string(mode_list, list_length, opt);
380    }
381    return NO_MODE_REQ;
382}
383
384/**
385 * @brief Find mode number best fitting to monitor attached
386 *
387 * @param[in] mode_list list of modes to be searched
388 * @param[in] list_length number of modes in the list
389 * @retval video mode number to be set
390 * @retval -1 on parsing error or when no suitable mode found
391 */
392static int32_t find_mode_using_EDID( Mode_params *mode_list,
393                                      uint8_t list_length)
394{
395    EDID_edid1 edid;
396    uint8_t checksum, iterator;
397    uint8_t index, j;
398    Mode_params EDIDmode;
399    checksum = 0;
400    iterator = 0;
401    EDIDmode.bpp = 0;
402    if (VBE_read_EDID(0, 0, &edid) !=
403        (VBE_callSuccessful<<8 | VBE_functionSupported))
404    {
405        printk(FB_VESA_NAME " Function 15h (read EDID) not supported.\n");
406        return -1;
407    }
408/* version of EDID structure */
409    if (edid.Version == 1)
410    { /* EDID version 1 */
411        while (iterator < sizeof(EDID_edid1))
412        {
413            checksum += *((uint8_t *)&edid+iterator);
414            iterator++;
415        }
416        if (checksum)
417            /* not implemented: try to read EDID again */
418            printk(FB_VESA_NAME " EDID v1 checksum failed\n");
419
420        /* try to find Detailed Timing Descriptor (defined in BASE EDID)
421           in controller mode list; first should be preffered mode */
422        index = 0;
423        while (index < 4)
424        {
425            /* skip if it is monitor descriptor */
426            if (edid.dtd_md[index].md.Flag0[0] == 0 &&
427                edid.dtd_md[index].md.Flag0[1] == 0 &&
428                edid.dtd_md[index].md.Flag1 == 0)
429            {
430                index++;
431                continue;
432            }
433            EDIDmode.resX = DTD_horizontal_active(&edid.dtd_md[0].dtd);
434            EDIDmode.resY = DTD_vertical_active(&edid.dtd_md[0].dtd);
435            if (find_mode_by_resolution(mode_list, list_length, &EDIDmode) !=
436                -1)
437                return EDIDmode.mode_number;
438
439            index++;
440        }
441        /* try to find Detailed Timing Descriptor (defined in optional EXTENSION
442        Blocks) in controller mode list */
443        if (edid.ExtensionFlag > 0)
444        {
445            /* not implemented */
446        }
447        /* try to find CVT (defined in BASE EDID) in controller mode list */
448        index = 1;
449        while (index < 4)
450        {
451            if (edid.dtd_md[index].md.DataTypeTag ==
452                    EDID_DTT_CVT3ByteTimingCodes     &&
453                edid.dtd_md[index].md.Flag0[0] == 0  &&
454                edid.dtd_md[index].md.Flag0[1] == 0  &&
455                edid.dtd_md[index].md.Flag1 == 0     &&
456                edid.dtd_md[index].md.Flag2 == 0)
457            {
458                EDID_CVT_timing_codes_3B *cvt = (EDID_CVT_timing_codes_3B *)
459                    &edid.dtd_md[index].md.DescriptorData[0];
460                j = 0;
461                while (j < 4)
462                {
463                    EDIDmode.resY = edid1_CVT_addressable_lines_high(
464                        &cvt->cvt[j]
465                    );
466                    switch (edid1_CVT_aspect_ratio(&cvt->cvt[j]))
467                    {
468                        case EDID_CVT_AspectRatio_4_3:
469                            EDIDmode.resX = (EDIDmode.resY*4)/3;
470                            break;
471                        case EDID_CVT_AspectRatio_16_9:
472                            EDIDmode.resX = (EDIDmode.resY*16)/9;
473                            break;
474                        case EDID_CVT_AspectRatio_16_10:
475                            EDIDmode.resX = (EDIDmode.resY*16)/10;
476                            break;
477                        case EDID_CVT_AspectRatio_15_9:
478                            EDIDmode.resX = (EDIDmode.resY*15)/9;
479                            break;
480                    }
481                    EDIDmode.resX = (EDIDmode.resX/8)*8;
482                    if (find_mode_by_resolution(
483                            mode_list, list_length, &EDIDmode) != -1)
484                        return EDIDmode.mode_number;
485
486                    j++;
487                }
488            }
489            index++;
490        }
491        /* try to find CVT (defined in optional EXTENSION Blocks)
492        in controller mode list */
493        /* not implemented */
494        /* try to find Standard Timings (listed in BASE EDID)
495        in controller mode list */
496        index = 0;
497        while (index < 8)
498        {
499            /* check if descriptor is unused */
500            if (*(uint16_t*)&edid.STI[index] == EDID_STI_DescriptorUnused)
501            {
502                index++;
503                continue;
504            }
505            EDIDmode.resX = (edid.STI[index].HorizontalActivePixels+31)*8;
506            switch (edid.STI[index].ImageAspectRatio_RefreshRate &
507                    EDID1_STI_ImageAspectRatioMask)
508            {
509                case EDID_STI_AspectRatio_16_10:
510                    EDIDmode.resY = (EDIDmode.resX*10)/16;
511                    break;
512                case EDID_STI_AspectRatio_4_3:
513                    EDIDmode.resY = (EDIDmode.resX*3)/4;
514                    break;
515                case EDID_STI_AspectRatio_5_4:
516                    EDIDmode.resY = (EDIDmode.resX*4)/5;
517                    break;
518                case EDID_STI_AspectRatio_16_9:
519                    EDIDmode.resY = (EDIDmode.resX*9)/16;
520                    break;
521            }
522            if (find_mode_by_resolution(mode_list, list_length, &EDIDmode) !=
523                -1)
524                return EDIDmode.mode_number;
525
526            index++;
527        }
528        /* try to find Standard Timings (listed in optional EXTENSION Blocks)
529        in controller mode list */
530        /* not implemented */
531        /* use Established Timings */
532        if (edid1_established_tim(&edid, EST_1280x1024_75Hz))
533        {
534            EDIDmode.resX = 1280;
535            EDIDmode.resY = 1024;
536            EDIDmode.bpp = 0;
537            if (find_mode_by_resolution(mode_list, list_length, &EDIDmode) !=
538                -1)
539                return EDIDmode.mode_number;
540        }
541        if (edid1_established_tim(&edid, EST_1152x870_75Hz))
542        {
543            EDIDmode.resX = 1152;
544            EDIDmode.resY = 870;
545            EDIDmode.bpp = 0;
546            if (find_mode_by_resolution(mode_list, list_length, &EDIDmode) !=
547                -1)
548                return EDIDmode.mode_number;
549        }
550        if (edid1_established_tim(&edid, EST_1024x768_75Hz) ||
551            edid1_established_tim(&edid, EST_1024x768_70Hz) ||
552            edid1_established_tim(&edid, EST_1024x768_60Hz) ||
553            edid1_established_tim(&edid, EST_1024x768_87Hz))
554        {
555            EDIDmode.resX = 1024;
556            EDIDmode.resY = 768;
557            EDIDmode.bpp = 0;
558            if (find_mode_by_resolution(mode_list, list_length, &EDIDmode) !=
559                -1)
560                return EDIDmode.mode_number;
561        }
562        if (edid1_established_tim(&edid, EST_832x624_75Hz))
563        {
564            EDIDmode.resX = 832;
565            EDIDmode.resY = 624;
566            EDIDmode.bpp = 0;
567            if (find_mode_by_resolution(mode_list, list_length, &EDIDmode) !=
568                -1)
569                return EDIDmode.mode_number;
570        }
571        if (edid1_established_tim(&edid, EST_800x600_60Hz) ||
572            edid1_established_tim(&edid, EST_800x600_56Hz) ||
573            edid1_established_tim(&edid, EST_800x600_75Hz) ||
574            edid1_established_tim(&edid, EST_800x600_72Hz))
575        {
576            EDIDmode.resX = 800;
577            EDIDmode.resY = 600;
578            EDIDmode.bpp = 0;
579            if (find_mode_by_resolution(mode_list, list_length, &EDIDmode) !=
580                -1)
581                return EDIDmode.mode_number;
582        }
583        if (edid1_established_tim(&edid, EST_720x400_88Hz) ||
584            edid1_established_tim(&edid, EST_720x400_70Hz))
585        {
586            EDIDmode.resX = 720;
587            EDIDmode.resY = 400;
588            EDIDmode.bpp = 0;
589            if (find_mode_by_resolution(mode_list, list_length, &EDIDmode) !=
590                -1)
591                return EDIDmode.mode_number;
592        }
593        if (edid1_established_tim(&edid, EST_640x480_75Hz) ||
594            edid1_established_tim(&edid, EST_640x480_72Hz) ||
595            edid1_established_tim(&edid, EST_640x480_67Hz) ||
596            edid1_established_tim(&edid, EST_640x480_60Hz))
597        {
598            EDIDmode.resX = 640;
599            EDIDmode.resY = 480;
600            EDIDmode.bpp = 0;
601            if (find_mode_by_resolution(mode_list, list_length, &EDIDmode) !=
602                -1)
603                return EDIDmode.mode_number;
604        }
605    }
606    else
607        printk(FB_VESA_NAME " error reading EDID: unsupported version\n");
608    return -1;
609}
610
611void vesa_realmode_bootup_init(void)
612{
613    uint32_t vbe_ret_val;
614    uint16_t size;
615    VBE_vbe_info_block *vib = (VBE_vbe_info_block *)
616        i386_get_default_rm_buffer(&size);
617    vbe_ret_val = VBE_controller_information(vib, 0x300);
618    if (vbe_ret_val == -1)
619    {
620        printk(FB_VESA_NAME " error calling real mode interrupt.\n");
621        return;
622    }
623    if (vbe_ret_val != (VBE_callSuccessful<<8 | VBE_functionSupported))
624    {
625        printk(FB_VESA_NAME " Function 00h (read VBE info block)"
626            "not supported.\n");
627    }
628/*  Helper array is later filled with mode numbers and their parameters
629    sorted from the biggest values to the smalest where priorities of
630    parameters are from the highest to the lowest: resolution X,
631    resolution Y, bits per pixel.
632    The array is used for search the monitor provided parameters in EDID
633    structure and if found we set such mode using corresponding
634    VESA function. */
635#define MAX_NO_OF_SORTED_MODES 100
636    Mode_params sorted_mode_params[MAX_NO_OF_SORTED_MODES];
637
638    uint16_t *vmpSegOff = (uint16_t *)&vib->VideoModePtr;
639    uint16_t *modeNOPtr = (uint16_t*)
640        i386_Real_to_physical(*(vmpSegOff+1), *vmpSegOff);
641    uint16_t iterator = 0;
642
643    if (*(uint16_t*)vib->VideoModePtr == VBE_STUB_VideoModeList)
644    {
645        printk(FB_VESA_NAME " VBE Core not implemented!\n");
646    }
647    else
648    {
649        /* prepare list of modes */
650        while (*(modeNOPtr+iterator) != VBE_END_OF_VideoModeList &&
651            *(modeNOPtr+iterator) != 0)
652        { /* some bios implementations ends the list incorrectly with 0 */
653            if (iterator < MAX_NO_OF_SORTED_MODES)
654            {
655                sorted_mode_params[iterator].mode_number =*(modeNOPtr+iterator);
656                iterator ++;
657            }
658            else
659                break;
660        }
661        if (iterator < MAX_NO_OF_SORTED_MODES)
662            sorted_mode_params[iterator].mode_number = 0;
663    }
664
665    VBE_mode_info_block *mib = (VBE_mode_info_block *)
666        i386_get_default_rm_buffer(&size);
667    iterator = 0;
668    uint8_t nextFilteredMode = 0;
669    uint16_t required_mode_attributes = VBE_modSupInHWMask |
670        VBE_ColorModeMask | VBE_GraphicsModeMask | VBE_LinFraBufModeAvaiMask;
671    /* get parameters of modes and filter modes according to set
672        required parameters */
673    while (iterator < MAX_NO_OF_SORTED_MODES &&
674        sorted_mode_params[iterator].mode_number!=0)
675    {
676        VBE_mode_information(mib, sorted_mode_params[iterator].mode_number);
677        if ((mib->ModeAttributes&required_mode_attributes) ==
678            required_mode_attributes)
679        {
680            sorted_mode_params[nextFilteredMode].mode_number =
681                sorted_mode_params[iterator].mode_number;
682            sorted_mode_params[nextFilteredMode].resX = mib->XResolution;
683            sorted_mode_params[nextFilteredMode].resY = mib->YResolution;
684            sorted_mode_params[nextFilteredMode].bpp  = mib->BitsPerPixel;
685            nextFilteredMode ++;
686        }
687        iterator ++;
688    }
689    sorted_mode_params[nextFilteredMode].mode_number = 0;
690
691    uint8_t number_of_modes = nextFilteredMode;
692
693    /* first search for video argument in multiboot options */
694    vbe_used_mode = find_mode_using_cmdline(sorted_mode_params,
695                                            number_of_modes);
696
697    if (vbe_used_mode == NO_MODE_REQ) {
698        vbe_used_mode = find_mode_from_string(sorted_mode_params,
699                            number_of_modes, rtems_fb_default_mode);
700        if (vbe_used_mode != NO_MODE_REQ) {
701            printk(FB_VESA_NAME " using application option to select"
702                " video mode\n");
703        }
704    }
705    else
706    {
707        printk(FB_VESA_NAME " using command line option '--video='"
708            "to select video mode\n");
709    }
710
711    switch (vbe_used_mode) {
712        case NO_SUITABLE_MODE:
713            printk(FB_VESA_NAME " requested mode not found\n");
714            return;
715        case BAD_FORMAT:
716            printk(FB_VESA_NAME " bad format of video requested\n");
717            return;
718        case DONT_INIT:
719            printk(FB_VESA_NAME " selected not to initialize graphics\n");
720            return;
721        case NO_MODE_REQ:
722            printk(FB_VESA_NAME " not initialized, no video selected\n");
723            return;
724    }
725
726    /* sort filtered modes */
727    Mode_params modeXchgPlace;
728    iterator = 0;
729    uint8_t j;
730    uint8_t idxBestMode;
731    while (iterator < number_of_modes)
732    {
733        idxBestMode = iterator;
734        j = iterator+1;
735        while (j < number_of_modes)
736        {
737            if (sorted_mode_params[j].resX >
738                    sorted_mode_params[idxBestMode].resX)
739                idxBestMode = j;
740            else if (sorted_mode_params[j].resX ==
741                     sorted_mode_params[idxBestMode].resX)
742            {
743                if (sorted_mode_params[j].resY >
744                        sorted_mode_params[idxBestMode].resY)
745                    idxBestMode = j;
746                else if (sorted_mode_params[j].resY ==
747                    sorted_mode_params[idxBestMode].resY)
748                {
749                    if (sorted_mode_params[j].bpp >
750                            sorted_mode_params[idxBestMode].bpp)
751                        idxBestMode = j;
752                }
753            }
754            j++;
755        }
756        if (idxBestMode != iterator)
757        {
758            modeXchgPlace = sorted_mode_params[iterator];
759            sorted_mode_params[iterator] = sorted_mode_params[idxBestMode];
760            sorted_mode_params[idxBestMode] = modeXchgPlace;
761        }
762        iterator++;
763    }
764
765    if (vbe_used_mode == AUTO_SELECT)
766    {
767        printk(FB_VESA_NAME " auto video mode selected"
768            "\n\ttrying EDID ...\n");
769        /* second search monitor for good resolution */
770        vbe_used_mode = find_mode_using_EDID(sorted_mode_params,
771                                             number_of_modes);
772        if (vbe_used_mode == -1)
773        {
774            printk(FB_VESA_NAME" monitor's EDID video parameters not supported"
775                               "\n\tusing mode with highest resolution, bpp\n");
776            /* third set highest values */
777            vbe_used_mode = sorted_mode_params[0].mode_number;
778        }
779    }
780
781    /* fill framebuffer structs with info about selected mode */
782    vbe_ret_val = VBE_mode_information(mib, vbe_used_mode);
783    if ((vbe_ret_val&0xff)!=VBE_functionSupported ||
784        (vbe_ret_val>>8)!=VBE_callSuccessful)
785    {
786        printk(FB_VESA_NAME " Cannot get mode info anymore. ax=0x%x\n",
787            vbe_ret_val);
788    }
789
790    fb_var.xres = mib->XResolution;
791    fb_var.yres = mib->YResolution;
792    fb_var.bits_per_pixel = mib->BitsPerPixel;
793    fb_var.red.offset =      mib->LinRedFieldPosition;
794    fb_var.red.length =      mib->LinRedMaskSize;
795    fb_var.red.msb_right =   0;
796    fb_var.green.offset =    mib->LinGreenFieldPosition;
797    fb_var.green.length =    mib->LinGreenMaskSize;
798    fb_var.green.msb_right = 0;
799    fb_var.blue.offset =     mib->LinBlueFieldPosition;
800    fb_var.blue.length =     mib->LinBlueMaskSize;
801    fb_var.blue.msb_right =  0;
802    fb_var.transp.offset =   mib->LinRsvdFieldPosition;
803    fb_var.transp.length =   mib->LinRsvdMaskSize;
804    fb_var.transp.msb_right =0;
805
806    fb_fix.smem_start  = (char *)mib->PhysBasePtr;
807    fb_fix.line_length = mib->LinBytesPerScanLine;
808    fb_fix.smem_len    = fb_fix.line_length*fb_var.yres;
809    fb_fix.type        = FB_TYPE_PACKED_PIXELS;
810    if (fb_var.bits_per_pixel < 24)
811        fb_fix.visual  = FB_VISUAL_DIRECTCOLOR;
812    else
813        fb_fix.visual  = FB_VISUAL_TRUECOLOR;
814
815    /* set selected mode */
816    vbe_ret_val = VBE_set_mode(vbe_used_mode | VBE_linearFlatFrameBufMask,
817        (VBE_CRTC_info_block *)(i386_get_default_rm_buffer(&size)));
818    if (vbe_ret_val>>8 == VBE_callFailed)
819        printk(FB_VESA_NAME " VBE: Requested mode is not available.");
820
821    if ((vbe_ret_val&0xff)!= (VBE_functionSupported | VBE_callSuccessful<<8))
822        printk(FB_VESA_NAME " Call to function 2h (set VBE mode) failed. "
823            "ax=0x%x\n", vbe_ret_val);
824
825    vib = (void *) 0;
826    mib = (void *) 0;
827}
828
829/*
830 * fb_vesa device driver INITIALIZE entry point.
831 */
832rtems_device_driver
833frame_buffer_initialize(
834    rtems_device_major_number  major,
835    rtems_device_minor_number  minor,
836    void                      *arg
837)
838{
839    rtems_status_code status;
840
841    printk(FB_VESA_NAME " frame buffer -- driver initializing..\n" );
842
843/*
844 * Register the device.
845 */
846    status = rtems_io_register_name(FRAMEBUFFER_DEVICE_0_NAME, major, 0);
847    if (status != RTEMS_SUCCESSFUL)
848    {
849        printk("Error registering " FRAMEBUFFER_DEVICE_0_NAME
850        " - " FB_VESA_NAME " frame buffer device!\n");
851        rtems_fatal_error_occurred( status );
852    }
853
854    return RTEMS_SUCCESSFUL;
855}
856
857/*
858 * fb_vesa device driver OPEN entry point
859 */
860rtems_device_driver
861frame_buffer_open(
862    rtems_device_major_number  major,
863    rtems_device_minor_number  minor,
864    void                      *arg
865)
866{
867    printk( FB_VESA_NAME " open device\n" );
868
869    if (pthread_mutex_trylock(&vesa_mutex) != 0)
870    {
871        printk( FB_VESA_NAME " could not lock vesa_mutex\n" );
872
873        return RTEMS_UNSATISFIED;
874    }
875
876    return RTEMS_SUCCESSFUL;
877
878}
879
880/*
881 * fb_vesa device driver CLOSE entry point
882 */
883rtems_device_driver
884frame_buffer_close(
885    rtems_device_major_number  major,
886    rtems_device_minor_number  minor,
887    void                      *arg
888)
889{
890  printk( FB_VESA_NAME " close device\n" );
891  if (pthread_mutex_unlock(&vesa_mutex) == 0)
892  {
893      /* restore previous state.  for VGA this means return to text mode.
894       * leave out if graphics hardware has been initialized in
895       * frame_buffer_initialize() */
896
897      printk(FB_VESA_NAME ": close called.\n" );
898      return RTEMS_SUCCESSFUL;
899  }
900
901  return RTEMS_UNSATISFIED;
902}
903
904/*
905 * fb_vesa device driver READ entry point.
906 */
907rtems_device_driver
908frame_buffer_read(
909    rtems_device_major_number  major,
910    rtems_device_minor_number  minor,
911    void                      *arg
912)
913{
914  printk( FB_VESA_NAME " read device\n" );
915  rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg;
916  rw_args->bytes_moved =
917    ((rw_args->offset + rw_args->count) > fb_fix.smem_len ) ?
918        (fb_fix.smem_len - rw_args->offset) :
919        rw_args->count;
920  memcpy(rw_args->buffer, (const void *)
921    (fb_fix.smem_start + rw_args->offset), rw_args->bytes_moved);
922  return RTEMS_SUCCESSFUL;
923}
924
925/*
926 * frame_vesa device driver WRITE entry point.
927 */
928rtems_device_driver
929frame_buffer_write(
930    rtems_device_major_number  major,
931    rtems_device_minor_number  minor,
932    void                      *arg
933)
934{
935  printk( FB_VESA_NAME " write device\n" );
936  rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg;
937  rw_args->bytes_moved =
938    ((rw_args->offset + rw_args->count) > fb_fix.smem_len ) ?
939        (fb_fix.smem_len - rw_args->offset) :
940        rw_args->count;
941  memcpy( (void *) (fb_fix.smem_start + rw_args->offset),
942    rw_args->buffer, rw_args->bytes_moved);
943  return RTEMS_SUCCESSFUL;
944}
945
946static int get_fix_screen_info( struct fb_fix_screeninfo *info )
947{
948  *info = fb_fix;
949  return 0;
950}
951
952static int get_var_screen_info( struct fb_var_screeninfo *info )
953{
954  *info =  fb_var;
955  return 0;
956}
957
958/*
959 * IOCTL entry point -- This method is called to carry
960 * all services of this interface.
961 */
962rtems_device_driver
963frame_buffer_control(
964    rtems_device_major_number  major,
965    rtems_device_minor_number  minor,
966    void                      *arg
967)
968{
969  rtems_libio_ioctl_args_t *args = arg;
970
971  printk( FB_VESA_NAME " ioctl called, cmd=%x\n", args->command  );
972    printk("fbxres %d, fbyres %d\n", fb_var.xres, fb_var.yres);
973    printk("fbbpp %d\n", fb_var.bits_per_pixel);
974
975  switch (args->command)
976  {
977  case FBIOGET_FSCREENINFO:
978      args->ioctl_return =
979        get_fix_screen_info( ( struct fb_fix_screeninfo * ) args->buffer );
980      break;
981  case FBIOGET_VSCREENINFO:
982      args->ioctl_return =
983        get_var_screen_info( ( struct fb_var_screeninfo * ) args->buffer );
984      break;
985  case FBIOPUT_VSCREENINFO:
986    /* not implemented yet */
987    args->ioctl_return = -1;
988    return RTEMS_UNSATISFIED;
989  case FBIOGETCMAP:
990    /* no palette - truecolor mode */
991    args->ioctl_return = -1;
992    return RTEMS_UNSATISFIED;
993  case FBIOPUTCMAP:
994    /* no palette - truecolor mode */
995    args->ioctl_return = -1;
996    return RTEMS_UNSATISFIED;
997  default:
998    args->ioctl_return = 0;
999    break;
1000  }
1001  return RTEMS_SUCCESSFUL;
1002}
Note: See TracBrowser for help on using the repository browser.