source: rtems/c/src/lib/libbsp/i386/pc386/console/fb_vesa_rm.c @ 038e1dba

4.115
Last change on this file since 038e1dba was 038e1dba, checked in by Jan Dolezal <dolezj21@…>, on 12/03/14 at 23:56:39

i386: doxygen and comments related to VESA real mode framebuffer

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