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 > /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()
;您需要使用较新的DRM
和KMS
接口。
【讨论】:
我该怎么做? 似乎内核驱动程序确实支持mmap()
,但是它拒绝一次映射超过N个字节(似乎因硬件而异,但我'已经看到最大值在 3MB-8MB 左右),这使得它对于直接图形输出不是很有用。
实际上,我只能通过尝试 mmap 超过 X 次 Y 次 bpp 字节(对于 1280x800,32bpp,即 8294400 字节)来复制“无效参数”错误。因此,对于遇到这种情况的任何人,请确保您没有尝试映射超过帧缓冲区的大小。以上是关于mmap /dev/fb0 因“无效参数”而失败的主要内容,如果未能解决你的问题,请参考以下文章
pageViewController setViewControllers 因“无效参数不满足:[views count] == 3”而崩溃