因为Linux是工作在保护模式下,所以用户态进程是无法象DOS那样使用显卡BIOS里提供的中断调用来实现直接写屏,故Linux抽象出FrameBuffer这个设备来供用户态进程实现直接写屏。
在继续下面的之前,先说明几个背景知识:
- FrameBuffer主要是根据VESA标准的实现的,所以只能实现最简单的功能。
- 由于涉及内核的问题,FrameBuffer是不允许在系统起来后修改显示模式等一系列操作。(好象很多人都想要这样干,这是不被允许的,当然如果你自己与驱动的话,是可以实现的)
- 对FrameBuffer的操作,会直接影响到本机的所有控制台的输出,包括XWIN的图形界面。
好,现在可以让我们开始实现直接写屏:
- 打开一个FrameBuffer设备
- 通过mmap调用把显卡的物理内存空间映射到用户空间
- 直接写内存。
好象很简单哦~
fbtools.h
|
fbtools.c
代码:
#
include
<
stdio.
h>
#
include
<
stdlib.
h>
#
include
<
fcntl.
h>
#
include
<
unistd.
h>
#
include
<
string
.
h>
#
include
<
sys/
ioctl.
h>
#
include
<
sys/
mman.
h>
#
include
<
asm
/
page.
h>
#
include
"fbtools.h"
#
define
TRUE
1
#
define
FALSE
0
#
define
MAX
(
x,
y)
(
(
x)
>
(
y)
?
(
x)
:
(
y)
)
#
define
MIN
(
x,
y)
(
(
x)
<
(
y)
?
(
x)
:
(
y)
)
/* open & init a frame buffer */
int
fb_open(
PFBDEV pFbdev)
{
pFbdev-
>
fb =
open
(
pFbdev-
>
dev,
O_RDWR)
;
if
(
pFbdev-
>
fb <
0)
{
printf
(
"Error opening %s: %m. Check kernel config/n"
,
pFbdev-
>
dev)
;
return
FALSE
;
}
if
(
-
1 =
=
ioctl(
pFbdev-
>
fb,
FBIOGET_VSCREENINFO,
&
(
pFbdev-
>
fb_var)
)
)
{
printf
(
"ioctl FBIOGET_VSCREENINFO/n"
)
;
return
FALSE
;
}
if
(
-
1 =
=
ioctl(
pFbdev-
>
fb,
FBIOGET_FSCREENINFO,
&
(
pFbdev-
>
fb_fix)
)
)
{
printf
(
"ioctl FBIOGET_FSCREENINFO/n"
)
;
return
FALSE
;
}
/*map physics address to virtual address */
pFbdev-
>
fb_mem_offset =
(
unsigned
long
)
(
pFbdev-
>
fb_fix.
smem_start)
&
(
~
PAGE_MASK)
;
pFbdev-
>
fb_mem =
(
unsigned
long
int
)
mmap(
NULL
,
pFbdev-
>
fb_fix.
smem_len +
pFbdev-
>
fb_mem_offset,
PROT_READ |
PROT_WRITE,
MAP_SHARED,
pFbdev-
>
fb,
0)
;
if
(
-
1L =
=
(
long
)
pFbdev-
>
fb_mem)
{
printf
(
"mmap error! mem:%d offset:%d/n"
,
pFbdev-
>
fb_mem,
pFbdev-
>
fb_mem_offset)
;
return
FALSE
;
}
return
TRUE
;
}
/* close frame buffer */
int
fb_close(
PFBDEV pFbdev)
{
close
(
pFbdev-
>
fb)
;
pFbdev-
>
fb=
-
1;
}
/* get display depth */
int
get_display_depth(
PFBDEV pFbdev)
;
{
if
(
pFbdev-
>
fb<
=
0)
{
printf
(
"fb device not open, open it first/n"
)
;
return
FALSE
;
}
return
pFbdev-
>
fb_var.
bits_per_pixel;
}
/* full screen clear */
void
fb_memset (
void
*
addr,
int
c,
size_t
len)
{
memset
(
addr,
c,
len)
;
}
/* use by test */
#
define
DEBUG
#
ifdef
DEBUG
main(
)
{
FBDEV fbdev;
memset
(
&
fbdev,
0,
sizeof
(
FBDEV)
)
;
strcpy
(
fbdev.
dev,
"/dev/fb0"
)
;
if
(
fb_open(
&
fbdev)
=
=
FALSE
)
{
printf
(
"open frame buffer error/n"
)
;
return
;
}
fb_memset(
fbdev.
fb_mem +
fbdev.
fb_mem_offset,
0,
fbdev.
fb_fix.
smem_len)
;
fb_close(
&
fbdev)
;
}