source: rtems/c/src/lib/libbsp/i386/pc386/console/fb_vesa_rm.c @ 22bbb9f1

5
Last change on this file since 22bbb9f1 was becbeda, checked in by Joel Sherrill <joel.sherrill@…>, on 06/09/15 at 20:48:22

pc386/console/fb*.c: Use atomics to avoid dependency on pthreads

closes #2364.

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