source: rtems/c/src/lib/libbsp/i386/pc386/console/fb_vesa_rm.c @ 0684f35

Last change on this file since 0684f35 was 0684f35, checked in by Sebastian Huber <sebastian.huber@…>, on Jul 28, 2017 at 11:10:19 AM

bsp/i386: Fix warning

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