source: rtems/bsps/i386/pc386/console/fb_vesa_rm.c

Last change on this file was 25a4dff, checked in by Chris Johns <chrisj@…>, on 10/04/23 at 02:17:13

bsp/i386/pc686: Clean up warnings

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