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

4.115
Last change on this file since d78eac6 was d78eac6, checked in by Jan Dolezal <dolezj21@…>, on Dec 3, 2014 at 11:56:38 PM

i386/pc386: cammelCase (struct and function names) to underscores, typedefed structs, break >80 chars lines, removed newlines at EOFs

fb_vesa_rm.c: removed inline from functions declared in fb_vesa.h

removed unnecessary printks in the end of patch

edid.h, vbe3.h: switched from custom *PACKED_ATTRIBUTE at the structs to the

RTEMS_COMPILER_PACKED_ATTRIBUTE for easier maintainability
of doxygen

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