My Frustrating Experiences With /dev/fb


rlyeh

Certified Guru
Joined
Mar 25, 2003
Messages
277
Age
46
Location
49°9' East latitude, 126°43' South longitude: in y
Website
www.retrodev.info
I've tried to do a double buffering code using ioctl() to use /dev/fb directly
Here's my initial setup:


Code:
    struct fb_fix_screeninfo fixed_info;
    struct fb_var_screeninfo variable_info;
    int fbdev[2];
    u16 *gp2x_screen[2], gp2x_screenc=0;

    fbdev[0]=open("/dev/fb0", O_RDWR);
    fbdev[1]=open("/dev/fb1", O_RDWR);

    gp2x_screen[0]=(u16 *)mmap(0, 320*240*sizeof(u16), PROT_WRITE, MAP_SHARED, fbdev[0], 0);
    gp2x_screen[1]=(u16 *)mmap(0, 320*240*sizeof(u16), PROT_WRITE, MAP_SHARED, fbdev[1], 0);

Ok, now gp2x_screen elements are mapped to framebuffers, and writing into [0] paints the screen as desired.

My problem is that I don't know how to switch the LCD to the [1] buffer



Trying a different approach, I've tried to pan the display, here it is how it should be done:

Code:
    ioctl (fbdev[0], FBIOGET_VSCREENINFO, &variable_info);

    variable_info.xres_virtual=640; //*=2
    variable_info.yres_virtual=480; //*=2

     ioctl (fbdev[0], FBIOPUT_VSCREENINFO, &variable_info);

By doing this, that Linux does it ok with no errors, our VSCREENINFO virtual size changes from 320x240 to 640x480.
In theory, we should call now FBIO_PANDISPLAY to scroll through the virtual area.

Code:
          variable_info.xoffset = 0;
          variable_info.yoffset = (gp2x_screenc^=1) ? 0 : 240;
          variable_info.activate = FB_ACTIVATE_VBL;

          if(ioctl (fbdev[0], FBIOPAN_DISPLAY, &variable_info) < 0)
          {
           printf("FBIOPAN_DISPLAY error %d = %s\n",errno,strerror(errno));
          }

But ioctl() returns error 22 'Invalid argument'.

So, how can I do double buffering through ioctl() ?
I have two methods:

- exchanging /fb/dev0 and /fb/dev1 which i dont know how to do it
- using FBIOPAN_DISPLAY to scroll /fb/dev0 which does not work at all

any idea?
 
Looking at the incredibly basic video driver, I'd say any of the IOCTL calls to set info along with fancy stuff like PAN is just going to fail.

Your best off getting the physical address of each frame buffer and changing the hardware registers directly, like I explained to you on irc.
 
squidge, look at this

Code:
void gp2x_videoflip(void)
{
u32 nBufferAddress;

if(gp2x_screenc)
{
 gp2x_screen[0]=(u16 *)0x40001000;
 nBufferAddress=0x40027000;
}
else
{
 gp2x_screen[0]=(u16 *)0x40027000;
 nBufferAddress=0x40001000;
}

gp2x_screenc^=1;

MSP_MLC_STL_OADRL = (unsigned short)(nBufferAddress & 0xffff);
MSP_MLC_STL_OADRH = (unsigned short)(nBufferAddress >> 16);
MSP_MLC_STL_EADRL = (unsigned short)(nBufferAddress & 0xffff);
MSP_MLC_STL_EADRH = (unsigned short)(nBufferAddress >> 16);
}

this didnt work at all either
I obtained the 0x40001000 and 0x40027000 from mmap'ing the /dev/fb*

any idea?
 
You can't use virtual addresses with the hardware registers - they must be physical addresses, which you can get by querying the fb devices. The physical address may change too, so don't hardcode it.

The addresses you get from mmap are virtual.
 
You can't use virtual addresses with the hardware registers - they must be physical addresses, which you can get by querying the fb devices. The physical address may change too, so don't hardcode it.

The addresses you get from mmap are virtual.


ok, i obtained the physical addresses by quering the fixed information from each framebuffer

Code:
ioctl (fbdev[0], FBIOGET_FSCREENINFO, &fixed_info);
smem_start[0]=fixed_info.smem_start;

ioctl (fbdev[1], FBIOGET_FSCREENINFO, &fixed_info);
smem_start[1]=fixed_info.smem_start;

phys address of fb0 is 0x3101000
phys address of fb1 is 0x3381000

both following pieces of codes did not work at all :(

Code:
u32 nBufferAddress;

if(gp2x_screenc)
{
 global(hpl_vfbi15)=(hpl_pixel *)gp2x_screen[0];
 nBufferAddress=smem_start[0]+320*240*2;
}
else
{
 global(hpl_vfbi15)=(hpl_pixel *)gp2x_screen[0]+320*240*2;
 nBufferAddress=smem_start[0];
}

and

Code:
u32 nBufferAddress;

if(gp2x_screenc)
{
 global(hpl_vfbi15)=(hpl_pixel *)gp2x_screen[0];
 nBufferAddress=smem_start[1];
}
else
{
 global(hpl_vfbi15)=(hpl_pixel *)gp2x_screen[1];
 nBufferAddress=smem_start[0];
}


exiting code:

Code:
pc : [<00019ce0>]    lr : [<00126588>]    Not tainted
sp : bffffdb4  ip : c0002914  fp : 001287cc
r10: 001287c8  r9 : 00128664  r8 : 00126f68
r7 : 00126584  r6 : 00128778  r5 : 00000310  r4 : 00000001
r3 : 00001000  r2 : c000290e  r1 : c0002910  r0 : c0002912
Flags: nZCv  IRQs on  FIQs on  Mode USER_32  Segment user
Control: C000317F  Table: 01F38000  DAC: 00000015
Segmentation fault

any idea? :-(
 
Last edited by a moderator:
Yes, you can't write to physical memory directly (which includes the gfx registers). You can only write to virtual memory in your address space.

So you need to mmap the registers into your own address space - and, if you want to write to both frame buffers, mmap those too.

I did send you an example program via rafb paste and irc pmsg - did you loose it?
 
Back
Top