Linux操作系统下使用FrameBuffer直接写屏

时间:2022-03-04 08:38:34

因为Linux是工作在保护模式下,所以用户态进程是无法象DOS那样使用显卡BIOS里提供的中断调用来实现直接写屏,故Linux抽象出FrameBuffer这个设备来供用户态进程实现直接写屏。

         在继续下面的之前,先说明几个背景知识:

  1. FrameBuffer主要是根据VESA标准的实现的,所以只能实现最简单的功能。
  2. 由于涉及内核的问题,FrameBuffer是不允许在系统起来后修改显示模式等一系列操作。(好象很多人都想要这样干,这是不被允许的,当然如果你自己与驱动的话,是可以实现的)
  3. 对FrameBuffer的操作,会直接影响到本机的所有控制台的输出,包括XWIN的图形界面。

  好,现在可以让我们开始实现直接写屏:

  1. 打开一个FrameBuffer设备
  2. 通过mmap调用把显卡的物理内存空间映射到用户空间
  3. 直接写内存。

  好象很简单哦~
  fbtools.h

 

#
ifndef
_FBTOOLS_H_
#
define
_FBTOOLS_H_

#
include
<
linux/
fb.
h>


/* a framebuffer device structure */

typedef
struct
fbdev{

int
fb;

unsigned
long
fb_mem_offset;

unsigned
long
fb_mem;

struct
fb_fix_screeninfo fb_fix;

struct
fb_var_screeninfo fb_var;

char
dev[
20]
;

}
FBDEV,
*
PFBDEV;


/* open & init a frame buffer */

/* to use this function,
you must set FBDEV.dev="/dev/fb0"
or "/dev/fbX" */


/* it's your frame buffer. */

int
fb_open(
PFBDEV pFbdev)
;


/*close a frame buffer*/

int
fb_close(
PFBDEV pFbdev)
;


/*get display depth*/

int
get_display_depth(
PFBDEV pFbdev)
;



/*full screen clear */

void
fb_memset(
void
*
addr,
int
c,
size_t
len)
;


#
endif


 

  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)
;

}