📄 关于frambuffer--狼牙月.htm
字号:
<P>//a framebuffer device structure;</P>
<P>typedef struct fbdev{</P>
<P> int fb;</P>
<P> unsigned long
fb_mem_offset;</P>
<P> unsigned long
fb_mem;</P>
<P> struct
fb_fix_screeninfo fb_fix;</P>
<P> struct
fb_var_screeninfo fb_var;</P>
<P> char
dev[20];</P>
<P>} FBDEV, *PFBDEV;</P>
<P>//open & init a frame buffer</P>
<P>//to use this function,</P>
<P>//you must set FBDEV.dev="/dev/fb0"</P>
<P>//or "/dev/fbX"</P>
<P>//it's your frame buffer.</P>
<P>int fb_open(PFBDEV pFbdev);</P>
<P>//close a frame buffer</P>
<P>int fb_close(PFBDEV pFbdev);</P>
<P>//get display depth</P>
<P>int get_display_depth(PFBDEV pFbdev);</P>
<P>//full screen clear</P>
<P>void fb_memset(void *addr, int c, size_t len);</P>
<P>#endif</P>
<P><!--[if !supportEmptyParas]-->
<!--[endif]--></P>
<P>/******************</P>
<P>File name : fbtools.c</P>
<P>*/</P>
<P>#i nclude <stdio.h></P>
<P>#i nclude <stdlib.h></P>
<P>#i nclude <fcntl.h></P>
<P>#i nclude <unistd.h></P>
<P>#i nclude <string.h></P>
<P>#i nclude <sys/ioctl.h></P>
<P>#i nclude <sys/mman.h></P>
<P>#i nclude <asm/page.h></P>
<P>#i nclude "fbtools.h"</P>
<P>#define
TRUE 1</P>
<P>#define FALSE
0</P>
<P>#define
MAX(x,y)
((x)>(y)?(x)y))</P>
<P>#define
MIN(x,y)
((x)<(y)?(x)y))</P>
<P>//open & init a frame buffer</P>
<P>int fb_open(PFBDEV pFbdev)</P>
<P>{</P>
<P> pFbdev->fb =
open(pFbdev->dev, O_RDWR);</P>
<P> if(pFbdev->fb
< 0)</P>
<P> {</P>
<P>
printf("Error opening %s: %m. Check kernel config\n",
pFbdev->dev);</P>
<P>
return FALSE;</P>
<P> }</P>
<P> if (-1 ==
ioctl(pFbdev->fb,FBIOGET_VSCREENINFO,&(pFbdev->fb_var)))</P>
<P> {</P>
<P>
printf("ioctl FBIOGET_VSCREENINFO\n");</P>
<P>
return FALSE;</P>
<P> }</P>
<P> if (-1 ==
ioctl(pFbdev->fb,FBIOGET_FSCREENINFO,&(pFbdev->fb_fix)))</P>
<P> {</P>
<P>
printf("ioctl FBIOGET_FSCREENINFO\n");</P>
<P>
return FALSE;</P>
<P> }</P>
<P> //map physics
address to virtual address</P>
<P>
pFbdev->fb_mem_offset = (unsigned
long)(pFbdev->fb_fix.smem_start) &
(~PAGE_MASK);</P>
<P>
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);</P>
<P> if (-1L ==
(long) pFbdev->fb_mem) </P>
<P> {</P>
<P>
printf("mmap error! mem:%d offset:%d\n",
pFbdev->fb_mem, pFbdev->fb_mem_offset);</P>
<P>
return FALSE;</P>
<P> }</P>
<P> return TRUE;</P>
<P>}</P>
<P>//close frame buffer</P>
<P>int fb_close(PFBDEV pFbdev)</P>
<P>{</P>
<P>
close(pFbdev->fb);</P>
<P>
pFbdev->fb=-1;</P>
<P>}</P>
<P>//get display depth</P>
<P>int get_display_depth(PFBDEV pFbdev);</P>
<P>{</P>
<P>
if(pFbdev->fb<=0)</P>
<P> {</P>
<P>
printf("fb device not open, open it first\n");</P>
<P>
return FALSE;</P>
<P> }</P>
<P> return
pFbdev->fb_var.bits_per_pixel;</P>
<P>}</P>
<P>//full screen clear</P>
<P>void fb_memset (void *addr, int c, size_t len)</P>
<P>{</P>
<P> memset(addr, c, len);</P>
<P>}</P>
<P>//use by test</P>
<P>#define DEBUG</P>
<P>#ifdef DEBUG</P>
<P>main()</P>
<P>{</P>
<P> FBDEV fbdev;</P>
<P>
memset(&fbdev, 0, sizeof(FBDEV));</P>
<P>
strcpy(fbdev.dev, "/dev/fb0");</P>
<P>
if(fb_open(&fbdev)==FALSE)</P>
<P> {</P>
<P>
printf("open frame buffer error\n");</P>
<P>
return;</P>
<P> }</P>
<P>
fb_memset(fbdev.fb_mem + fbdev.fb_mem_offset, 0,
fbdev.fb_fix.smem_len);</P>
<P>
fb_close(&fbdev);</P>
<P>}</P>
<P>(二)基于Linux核心的汉字显示的尝试</P>
<P>我们以一个简单的例子来说明字符显示的过程。我们假设是在虚拟终端1(/dev/tty1)下运行一个如下的简单程序。</P>
<P>main ( )</P>
<P>{</P>
<P>puts("hello, world.\n");</P>
<P>}</P>
<P>puts
函数向缺省输出文件(/dev/tty1)发出写的系统调用write(2)。系统调用到linux核心里面对应的核心函数是console.c中的
con_write(),con_write()最终会调用do_con_write(
)。在do_con_write( )中负责把"hello,
world.\n"这个字符串放到tty1对应的缓冲区中去。</P>
<P>do_con_write(
)还负责处理控制字符和光标的位置。让我们来看一下do_con_write()这个函数的声明。</P>
<P>static int do_con_write(struct tty_struct * tty, int
from_user, const unsigned char *buf, int count) </P>
<P>其中tty是指向tty_struct结构的指针,这个结构里面存放着关于这个tty的所有信息(请参照
linux/include/linux/tty.h)。Tty_struct结构中定义了通用(或高层)tty的属性(例如宽度和高度等)。在do_con_write(
)函数中用到了tty_struct结构中的driver_data变量。driver_data是一个vt_struct指针。在vt_struct结构中包含这个tty的序列号(我们正使用tty1,所以这个序号为1)。Vt_struct结构中有一个vc结构的数组vc_cons,这个数组就是各虚拟终端的私有数据。</P>
<P>static int do_con_write(struct tty_struct * tty, int
from_user,const unsigned char *buf, int count)</P>
<P>{</P>
<P>struct vt_struct *vt = (struct vt_struct
*)tty->driver_data;//我们用到了driver_data变量</P>
<P>. . . . .</P>
<P>currcons = vt->vc_num; file://我们在这里的vc_nums就是1</P>
<P>. . . . .</P>
<P>}</P>
<P>要访问虚拟终端的私有数据,需使用vc_cons〔currcons〕.d指针。这个指针指向的结构含有当前虚拟终端上光标的位置、缓冲区的起始地址、缓冲区大小等等。</P>
<P>"hello, world.\n"中的每一个字符都要经过conv_uni_to_pc(
)这个函数转换成8位的显示字符。这要做的主要目的是使不同语言的国家能把16位的UniCode码映射到8位的显示字符集上,目前还是主要针对欧洲国家的语言,映射结果为8位,不包含对双字节(double
byte)的范围。</P>
<P>这种UNICODE到显示字符的映射关系可以由用户自行定义。在缺省的映射表上,会把中文的字符映射到其他的字符上,这是我们不希望看到也是不需要的。所以我们有两个选择∶</P>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -