mmap /dev/fb0 因“无效参数”而失败

Posted

技术标签:

【中文标题】mmap /dev/fb0 因“无效参数”而失败【英文标题】:mmap /dev/fb0 fails with "Invalid argument" 【发布时间】:2014-04-07 14:46:58 【问题描述】:

我有一个嵌入式系统,想直接使用/dev/fb0。作为第一个测试,我使用一些基于找到的示例代码everywhereinthe netand SO 的代码。打开成功,还有fstat 和类似的。但是mmap 因 EINVAL 而失败。

来源:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

int main() 
    int fbfd = 0;

    struct fb_var_screeninfo vinfo;
    struct fb_fix_screeninfo finfo;
    long int screensize = 0;
    char *fbp = 0;
    int x = 0, y = 0;
    long int location = 0;

    // Open the file for reading and writing
    fbfd = open("/dev/fb0", O_RDWR);
    if (fbfd == -1) 
        perror("Error: cannot open framebuffer device");
        exit(1);
    
    printf("The framebuffer device was opened successfully.\n");

    struct stat stat;
    fstat(fbfd, &stat);
    printf("/dev/mem -> size: %u blksize: %u blkcnt: %u\n", 
            stat.st_size, stat.st_blksize, stat.st_blocks);

    // Get fixed screen information
    if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) 
        perror("Error reading fixed information");
        exit(2);
    

    // Get variable screen information
    if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) 
        perror("Error reading variable information");
        exit(3);
    

    printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);

    // Figure out the size of the screen in bytes
    screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
    const int PADDING = 4096;
    int mmapsize = (screensize + PADDING - 1) & ~(PADDING-1);

    // Map the device to memory
    fbp = (char *)mmap(0, mmapsize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
    if ((int)fbp == -1) 
        perror("Error: failed to map framebuffer device to memory");
        exit(4);
    
    printf("The framebuffer device was mapped to memory successfully.\n");

    munmap(fbp, screensize);
    close(fbfd);

    return 0;

输出:

The framebuffer device was opened successfully.
/dev/mem -> size: 0 blksize: 4096 blkcnt: 0
640x480, 4bpp
Error: failed to map framebuffer device to memory: Invalid argument

追踪:

...
open("/dev/fb0", O_RDWR)                = 3
write(1, "The framebuffer device was opene"..., 48The framebuffer device was opened successfully.
) = 48
fstat64(3, st_mode=S_IFCHR|0640, st_rdev=makedev(29, 0), ...) = 0
write(1, "/dev/mem -> size: 0 blksize: 409"..., 44/dev/mem -> size: 0 blksize: 4096 blkcnt: 0
) = 44
ioctl(3, FBIOGET_FSCREENINFO or FBIOPUT_CONTRAST, 0xbfca6564) = 0
ioctl(3, FBIOGET_VSCREENINFO, 0xbfca6600) = 0
write(1, "640x480, 4bpp\n", 14640x480, 4bpp
)         = 14
old_mmap(NULL, 155648, PROT_READ|PROT_WRITE, MAP_SHARED, 3, 0) = -1 EINVAL (Invalid argument)
write(2, "Error: failed to map framebuffer"..., 49Error: failed to map framebuffer device to memory) = 49
write(2, ": ", 2: )                       = 2
write(2, "Invalid argument", 16Invalid argument)        = 16
write(2, "\n", 1
)                       = 1

可以看到带有控制台和 tux 的启动屏幕。而cat /dev/urandom &gt; /dev/fb0 让屏幕充满噪音。系统上的页面大小为 4096 (`getconf PAGESIZE)。所以,155648 (0x26000) 是一个倍数。偏移量和指针都为零。映射和文件模式都是 RW .. 我错过了什么?

这是针对使用 uClibc 和 busybox 运行单个应用程序的嵌入式设备构建的,我必须从一个古老的内核移植它。有用于线条绘制等的代码,不需要多处理/窗口..请不要提示directfb ;).

【问题讨论】:

你知道你的帧缓冲驱动支持映射吗?您甚至可以逐步从帧缓冲区中读取()(使用 dd 进行简单测试)吗? 没有。它只是一个香草内核和“标准”-x86 硬件。我该如何检查? 也许您可以对照实际文件检查 mmap 代码的有效性?至于framebuffer,你可能需要查看它的驱动源。 我用 /dev/mem 测试过 - 没问题(第一个 MB 仍然有效,没有特殊的内核选项)。我希望我可以避免深入挖掘内核源代码:/ 我不太确定你的问题,我曾经遇到过类似 dev/fb0 is not accessible 的错误。将 linux 映像复制到其中(在它的 BOOT 分区中)后,我没有从计算机中正确移除我的 sd 卡。 SD 卡应安全地从计算机中取出。所以我可以建议正确地遵循所有基本步骤。 【参考方案1】:

提供framebuffer 的内核驱动程序不支持framebuffer 设备的旧版直接mmap();您需要使用较新的DRMKMS 接口。

【讨论】:

我该怎么做? 似乎内核驱动程序确实支持mmap(),但是它拒绝一次映射超过N个字节(似乎因硬件而异,但我'已经看到最大值在 3MB-8MB 左右),这使得它对于直接图形输出不是很有用。 实际上,我只能通过尝试 mmap 超过 X 次 Y 次 bpp 字节(对于 1280x800,32bpp,即 8294400 字节)来复制“无效参数”错误。因此,对于遇到这种情况的任何人,请确保您没有尝试映射超过帧缓冲区的大小。

以上是关于mmap /dev/fb0 因“无效参数”而失败的主要内容,如果未能解决你的问题,请参考以下文章

帧缓冲设备应用开发

显示设备文件接口

pageViewController setViewControllers 因“无效参数不满足:[views count] == 3”而崩溃

python中的Elasticsearch parallel_bulk辅助函数在使用响应时会因部分失败而引发错误

使用 OpenCV 写入 /dev/fb0

Linux DRM ( DRI ) 无法像以前一样使用 FBDEV 筛选 /dev/fb0