日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

LINUX framebuffer

發(fā)布時(shí)間:2023/12/10 linux 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 LINUX framebuffer 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
http://wangshh03.blog.163.com/blog/static/49103415201001231317484/

一、FrameBuffer的原理

??? FrameBuffer 是出現(xiàn)在 2.2.xx 內(nèi)核當(dāng)中的一種驅(qū)動(dòng)程序接口。

??? Linux是工作在保護(hù)模式下,所以用戶態(tài)進(jìn)程是無法象DOS那樣使用顯卡BIOS里提供的中斷調(diào)用來實(shí)現(xiàn)直接寫屏,Linux抽象出 FrameBuffer這個(gè)設(shè)備來供用戶態(tài)進(jìn)程實(shí)現(xiàn)直接寫屏。Framebuffer機(jī)制模仿顯卡的功能,將顯卡硬件結(jié)構(gòu)抽象掉,可以通過 Framebuffer的讀寫直接對(duì)顯存進(jìn)行操作。用戶可以將Framebuffer看成是顯示內(nèi)存的一個(gè)映像,將其映射到進(jìn)程地址空間之后,就可以直接進(jìn)行讀寫操作,而寫操作可以立即反應(yīng)在屏幕上。這種操作是抽象的,統(tǒng)一的。用戶不必關(guān)心物理顯存的位置、換頁(yè)機(jī)制等等具體細(xì)節(jié)。這些都是由 Framebuffer設(shè)備驅(qū)動(dòng)來完成的。

??? Framebuffer本身不具備任何運(yùn)算數(shù)據(jù)的能力,就只好比是一個(gè)暫時(shí)存放水的水池.CPU將運(yùn)算后的結(jié)果放到這個(gè)水池,水池再將結(jié)果流到顯示器. 中間不會(huì)對(duì)數(shù)據(jù)做處理. 應(yīng)用程序也可以直接讀寫這個(gè)水池的內(nèi)容.在這種機(jī)制下,盡管Framebuffer需要真正的顯卡驅(qū)動(dòng)的支持,但所有顯示任務(wù)都有CPU完成,因此CPU 負(fù)擔(dān)很重

framebuffer的設(shè)備文件一般是 /dev/fb0/dev/fb1 等等。

可以用命令: #dd if=/dev/zero of=/dev/fb 清空屏幕.

如果顯示模式是 1024x768-8 位色,用命令:$ dd if=/dev/zero of=/dev/fb0 bs=1024 count=768 清空屏幕;

用命令: #dd if=/dev/fb of=fbfile? 可以將fb中的內(nèi)容保存下來;

可以重新寫回屏幕: #dd if=fbfile of=/dev/fb

在使用Framebuffer時(shí),Linux是將顯卡置于圖形模式下的.

?

??? 在應(yīng)用程序中,一般通過將 FrameBuffer 設(shè)備映射到進(jìn)程地址空間的方式使用,比如下面的程序就打開 /dev/fb0 設(shè)備,并通過 mmap 系統(tǒng)調(diào)用進(jìn)行地址映射,隨后用 memset 將屏幕清空(這里假設(shè)顯示模式是 1024x768-8 位色模式,線性內(nèi)存模式):

?

int fb;

unsigned char* fb_mem;

fb = open ("/dev/fb0", O_RDWR);

fb_mem = mmap (NULL, 1024*768, PROT_READ|PROT_WRITE,MAP_SHARED,fb,0);

memset (fb_mem, 0, 1024*768); //這個(gè)命令應(yīng)該只有在root可以執(zhí)行

?

??? FrameBuffer 設(shè)備還提供了若干 ioctl 命令,通過這些命令,可以獲得顯示設(shè)備的一些固定信息(比如顯示內(nèi)存大小)、與顯示模式相關(guān)的可變信息(比如分辨率、象素結(jié)構(gòu)、每掃描線的字節(jié)寬度),以及偽彩色模式下的調(diào)色板信息等等。

??? 通過 FrameBuffer 設(shè)備,還可以獲得當(dāng)前內(nèi)核所支持的加速顯示卡的類型(通過固定信息得到),這種類型通常是和特定顯示芯片相關(guān)的。比如目前最新的內(nèi)核(2.4.9)中,就包含有對(duì) S3MatroxnVidia3Dfx 等等流行顯示芯片的加速支持。在獲得了加速芯片類型之后,應(yīng)用程序就可以將 PCI 設(shè)備的內(nèi)存I/Omemio)映射到進(jìn)程的地址空間。這些 memio 一般是用來控制顯示卡的寄存器,通過對(duì)這些寄存器的操作,應(yīng)用程序就可以控制特定顯卡的加速功能。

??? PCI 設(shè)備可以將自己的控制寄存器映射到物理內(nèi)存空間,而后,對(duì)這些控制寄存器的訪問,給變成了對(duì)物理內(nèi)存的訪問。因此,這些寄存器又被稱為"memio"。一旦被映射到物理內(nèi)存,Linux 的普通進(jìn)程就可以通過 mmap 將這些內(nèi)存 I/O 映射到進(jìn)程地址空間,這樣就可以直接訪問這些寄存器了。

??? 當(dāng)然,因?yàn)椴煌娘@示芯片具有不同的加速能力,對(duì)memio 的使用和定義也各自不同,這時(shí),就需要針對(duì)加速芯片的不同類型來編寫實(shí)現(xiàn)不同的加速功能。比如大多數(shù)芯片都提供了對(duì)矩形填充的硬件加速支持,但不同的芯片實(shí)現(xiàn)方式不同,這時(shí),就需要針對(duì)不同的芯片類型編寫不同的用來完成填充矩形的函數(shù)。

??? FrameBuffer 只是一個(gè)提供顯示內(nèi)存和顯示芯片寄存器從物理內(nèi)存映射到進(jìn)程地址空間中的設(shè)備。所以,對(duì)于應(yīng)用程序而言,如果希望在 FrameBuffer 之上進(jìn)行圖形編程,還需要自己動(dòng)手完成其他許多工作。

?

二、FrameBufferLinux中的實(shí)現(xiàn)和機(jī)制

Framebuffer對(duì)應(yīng)的源文件在linux/drivers/video/目錄下。總的抽象設(shè)備文件為fbcon.c,在這個(gè)目錄下還有與各種顯卡驅(qū)動(dòng)相關(guān)的源文件。?? //這個(gè)文件要好好看看

?

()、分析Framebuffer設(shè)備驅(qū)動(dòng)

??? 需要特別提出的是在INTEL平臺(tái)上,老式的VESA 1.2 卡,如CGA/EGA卡,是不能支持Framebuffer的,因?yàn)?/span>Framebuffer要求顯卡支持線性幀緩沖,即CPU可以訪問顯緩沖中的每一位,但是VESA 1.2 卡只能允許CPU一次訪問64K的地址空間。

FrameBuffer設(shè)備驅(qū)動(dòng)基于如下兩個(gè)文件:

1) linux/include/linux/fb.h

2) linux/drivers/video/fbmem.c

?

下面分析這兩個(gè)文件。

1fb.h

?? 幾乎主要的結(jié)構(gòu)都是在這個(gè)中文件定義的。這些結(jié)構(gòu)包括:

1fb_var_screeninfo

?? 這個(gè)結(jié)構(gòu)描述了顯示卡的特性:

NOTE::::?? __u32 是表示 unsigned 不帶符號(hào)的 32 bits 的數(shù)據(jù)類型,其余類推。這是 Linux 內(nèi)核中所用到的數(shù)據(jù)類型,如果是開發(fā)用戶空間(user-space)的程序,可以根據(jù)具體計(jì)算機(jī)平臺(tái)的情況,用 unsigned long 等等來代替

struct fb_var_screeninfo

{

__u32 xres; /* visible resolution */?? //可視區(qū)域

__u32 yres;

__u32 xres_virtual; /* virtual resolution */? //可視區(qū)域

__u32 yres_virtual;

__u32 xoffset; /* offset from virtual to visible resolution */ //可視區(qū)域的偏移

__u32 yoffset;

?

__u32 bits_per_pixel; /* guess what */? //每一象素的bit數(shù)

__u32 grayscale; /* != 0 Gray levels instead of colors *///等于零就成黑白

?

struct fb_bitfield red; /* bitfield in fb mem if true color, */真彩的bit機(jī)構(gòu)

struct fb_bitfield green; /* else only length is significant */

struct fb_bitfield blue;??

struct fb_bitfield transp; /* transparency */? 透明

?

__u32 nonstd; /* != 0 Non standard pixel format */ 不是標(biāo)準(zhǔn)格式

?

__u32 activate; /* see FB_ACTIVATE_* */

?

__u32 height; /* height of picture in mm */ 內(nèi)存中的圖像高度

__u32 width; /* width of picture in mm */ 內(nèi)存中的圖像寬度

?

__u32 accel_flags; /* acceleration flags (hints) */ 加速標(biāo)志

?

/* Timing: All values in pixclocks, except pixclock (of course) */

?

時(shí)序-_-這些部分就是顯示器的顯示方法了,可以找相關(guān)的資料看看

__u32 pixclock; /* pixel clock in ps (pico seconds) */

__u32 left_margin; /* time from sync to picture */

__u32 right_margin; /* time from picture to sync */

__u32 upper_margin; /* time from sync to picture */

__u32 lower_margin;

__u32 hsync_len; /* length of horizontal sync */? 水平可視區(qū)域

__u32 vsync_len; /* length of vertical sync */?? 垂直可視區(qū)域

__u32 sync; /* see FB_SYNC_* */

__u32 vmode; /* see FB_VMODE_* */

__u32 reserved[6]; /* Reserved for future compatibility */ 備用-以后開發(fā)

};

?

2) fb_fix_screeninfon

這個(gè)結(jié)構(gòu)在顯卡被設(shè)定模式后創(chuàng)建,它描述顯示卡的屬性,并且系統(tǒng)運(yùn)行時(shí)不能被修改;比如FrameBuffer內(nèi)存的起始地址。它依賴于被設(shè)定的模式,當(dāng)一個(gè)模式被設(shè)定后,內(nèi)存信息由顯示卡硬件給出,內(nèi)存的位置等信息就不可以修改。

?

struct fb_fix_screeninfo {

char id[16]; /* identification string eg "TT Builtin" */ID

unsigned long smem_start; /* Start of frame buffer mem */ 內(nèi)存起始

/* (physical address) */ 物理地址

__u32 smem_len; /* Length of frame buffer mem */ 內(nèi)存大小

__u32 type; /* see FB_TYPE_* */

__u32 type_aux; /* Interleave for interleaved Planes */插入?yún)^(qū)域?

__u32 visual; /* see FB_VISUAL_* */

__u16 xpanstep; /* zero if no hardware panning */沒有硬件設(shè)備就為零

__u16 ypanstep; /* zero if no hardware panning */

__u16 ywrapstep; /* zero if no hardware ywrap */

__u32 line_length; /* length of a line in bytes */ 一行的字節(jié)表示

unsigned long mmio_start; /* Start of Memory Mapped I/O */內(nèi)存映射的I/O起始

/* (physical address) */

__u32 mmio_len; /* Length of Memory Mapped I/O */ I/O的大小

__u32 accel; /* Type of acceleration available */ 可用的加速類型

__u16 reserved[3]; /* Reserved for future compatibility */

};

?

3) fb_cmap

描述設(shè)備無關(guān)的顏色映射信息。可以通過FBIOGETCMAP FBIOPUTCMAP 對(duì)應(yīng)的ioctl操作設(shè)定或獲取顏色映射信息.

?

struct fb_cmap {

__u32 start; /* First entry */ 第一個(gè)入口

__u32 len; /* Number of entries */ 入口的數(shù)字

__u16 *red; /* Red values */

__u16 *green;

__u16 *blue;

__u16 *transp; /* transparency, can be NULL */ 透明,可以為零

};

?

4) fb_info

定義當(dāng)顯卡的當(dāng)前狀態(tài);fb_info結(jié)構(gòu)僅在內(nèi)核中可見,在這個(gè)結(jié)構(gòu)中有一個(gè)fb_ops指針, 指向驅(qū)動(dòng)設(shè)備工作所需的函數(shù)集。

?

struct fb_info {

char modename[40]; /* default video mode */ 默認(rèn)的視頻卡類型

kdev_t node;

int flags;

int open; /* Has this been open already ? */ 被打開過么?

#define FBINFO_FLAG_MODULE 1 /* Low-level driver is a module */

struct fb_var_screeninfo var; /* Current var */ 現(xiàn)在的視頻信息

struct fb_fix_screeninfo fix; /* Current fix */ 修正的信息

struct fb_monspecs monspecs; /* Current Monitor specs */ 現(xiàn)在的顯示器模式

struct fb_cmap cmap; /* Current cmap */ 當(dāng)前優(yōu)先級(jí)

struct fb_ops *fbops;

char *screen_base; /* Virtual address */ 物理基址

struct display *disp; /* initial display variable */初始化

struct vc_data *display_fg; /* Console visible on this display */

char fontname[40]; /* default font name */默認(rèn)的字體

devfs_handle_t devfs_handle; /* Devfs handle for new name */

devfs_handle_t devfs_lhandle; /* Devfs handle for compat. symlink */兼容

int (*changevar)(int); /* tell console var has changed */ 告訴console變量修改了

int (*switch_con)(int, struct fb_info*);

/* tell fb to switch consoles */ 告訴fb選擇consoles

int (*updatevar)(int, struct fb_info*);

/* tell fb to update the vars */ 告訴fb更新變量

void (*blank)(int, struct fb_info*); /* tell fb to (un)blank the screen */告訴fb使用黑白模式(或者不黑)

/* arg = 0: unblank */arg0的時(shí)候黑白模式

/* arg > 0: VESA level (arg-1) */ arg>0時(shí)候選擇VESA模式

void *pseudo_palette; /* Fake palette of 16 colors and

the cursor's color for non

palette mode */? 修正調(diào)色板

/* From here on everything is device dependent */ 現(xiàn)在就可以使用了

void *par;

};

?

5) struct fb_ops

用戶應(yīng)用可以使用ioctl()系統(tǒng)調(diào)用來操作設(shè)備,這個(gè)結(jié)構(gòu)就是用一支持ioctl()的這些操作的。

?

struct fb_ops {

/* open/release and usage marking */

struct module *owner;

int (*fb_open)(struct fb_info *info, int user);

int (*fb_release)(struct fb_info *info, int user);

/* get non settable parameters */

int (*fb_get_fix)(struct fb_fix_screeninfo *fix, int con,

struct fb_info *info);

/* get settable parameters */

int (*fb_get_var)(struct fb_var_screeninfo *var, int con,

struct fb_info *info);

/* set settable parameters */

int (*fb_set_var)(struct fb_var_screeninfo *var, int con,

struct fb_info *info);

/* get colormap */

int (*fb_get_cmap)(struct fb_cmap *cmap, int kspc, int con,

struct fb_info *info);

/* set colormap */

int (*fb_set_cmap)(struct fb_cmap *cmap, int kspc, int con,

struct fb_info *info);

/* pan display (optional) */

int (*fb_pan_display)(struct fb_var_screeninfo *var, int con,

struct fb_info *info);

/* perform fb specific ioctl (optional) */

int (*fb_ioctl)(struct inode *inode, struct file *file, unsigned int cmd,

unsigned long arg, int con, struct fb_info *info);

/* perform fb specific mmap */

int (*fb_mmap)(struct fb_info *info, struct file *file, struct vm_area_struct *vma);

/* switch to/from raster image mode */

int (*fb_rasterimg)(struct fb_info *info, int start);

};

?

6) structure map

struct fb_info_gen | struct fb_info | fb_var_screeninfo

?????????????????? |??????????????? | fb_fix_screeninfo

?????????????????? |??????????????? | fb_cmap

?????????????????? |??????????????? | modename[40]

???? ??????????????|??????????????? | fb_ops ---|--->ops on var

?????????????????? |??????????????? | ...?????? | fb_open

?????????????????? |??????????????? |?????????? | fb_release

?????????????????? |??????????????? |?????????? | fb_ioctl

?????????????????? |??????????????? |?????????? | fb_mmap

?????????????????? | struct fbgen_hwswitch?

?

????????????????????????????? \-----|-> detect

??????????????????????????????????? | encode_fix

??????????????????????????????????? | encode_var

????????????????????????? ??????????| decode_fix

??????????????????????????????????? | decode_var

??????????????????????????????????? | get_var

??????????????????????????????????? | set_var

??????????????????????????????????? | getcolreg

??????????????????????????????????? | setcolreg

??????????????????????????????????? | pan_display

??????????????????????????????????? | blank

??????????????????????????????????? | set_disp

?

?

[編排有點(diǎn)困難,第一行的第一條豎線和下面的第一列豎線對(duì)齊,第一行的第二條豎線和下面的第二列豎線對(duì)齊就可以了]

這個(gè)結(jié)構(gòu) fbgen_hwswitch抽象了硬件的操作.雖然它不是必需的,但有時(shí)候很有用.

2 fbmem.c

fbmem.c 處于Framebuffer設(shè)備驅(qū)動(dòng)技術(shù)的中心位置.它為上層應(yīng)用程序提供系統(tǒng)調(diào)用也為下一層的特定硬件驅(qū)動(dòng)提供接口;那些底層硬件驅(qū)動(dòng)需要用到這兒的接口來向系統(tǒng)內(nèi)核注冊(cè)它們自己. fbmem.c 為所有支持FrameBuffer的設(shè)備驅(qū)動(dòng)提供了通用的接口,避免重復(fù)工作.

?

1) 全局變量

?

struct fb_info *registered_fb[FB_MAX];

int num_registered_fb;

?

?

這兩變量記錄了所有fb_info 結(jié)構(gòu)的實(shí)例,fb_info 結(jié)構(gòu)描述顯卡的當(dāng)前狀態(tài),所有設(shè)備對(duì)應(yīng)的fb_info 結(jié)構(gòu)都保存在這個(gè)數(shù)組中,當(dāng)一個(gè)FrameBuffer設(shè)備驅(qū)動(dòng)向系統(tǒng)注冊(cè)自己時(shí),其對(duì)應(yīng)的fb_info 結(jié)構(gòu)就會(huì)添加到這個(gè)結(jié)構(gòu)中,同時(shí)num_registered_fb 為自動(dòng)加1.

?

static struct {

const char *name;

int (*init)(void);

int (*setup)(void);

} fb_drivers[] __initdata= { ....};

?

如果FrameBuffer設(shè)備被靜態(tài)鏈接到內(nèi)核,其對(duì)應(yīng)的入口就會(huì)添加到這個(gè)表中;如果是動(dòng)態(tài)加載的,即使用insmod/rmmod,就不需要關(guān)心這個(gè)表。

?

static struct file_operations fb_ops ={

owner: THIS_MODULE,

read: fb_read,

write: fb_write,

ioctl: fb_ioctl,

mmap: fb_mmap,

open: fb_open,

release: fb_release

};

這是一個(gè)提供給應(yīng)用程序的接口.

?

2fbmem.c 實(shí)現(xiàn)了如下函數(shù).

?

register_framebuffer(struct fb_info *fb_info);

unregister_framebuffer(struct fb_info *fb_info);

?

這兩個(gè)是提供給下層FrameBuffer設(shè)備驅(qū)動(dòng)的接口,設(shè)備驅(qū)動(dòng)通過這兩函數(shù)向系統(tǒng)注冊(cè)或注銷自己。幾乎底層設(shè)備驅(qū)動(dòng)所要做的所有事情就是填充fb_info結(jié)構(gòu)然后向系統(tǒng)注冊(cè)或注銷它。

?

(二)一個(gè)LCD顯示芯片的驅(qū)動(dòng)實(shí)例

??? Skeleton LCD 控制器驅(qū)動(dòng)為例,在LINUX中存有一個(gè)/fb/skeleton.cskeletonFramebuffer驅(qū)動(dòng)程序,很簡(jiǎn)單,僅僅是填充了 fb_info結(jié)構(gòu),并且注冊(cè)/注銷自己。設(shè)備驅(qū)動(dòng)是向用戶程序提供系統(tǒng)調(diào)用接口,所以我們需要實(shí)現(xiàn)底層硬件操作并且定義file_operations 結(jié)構(gòu)來向系統(tǒng)提供系統(tǒng)調(diào)用接口,從而實(shí)現(xiàn)更有效的LCD控制器驅(qū)動(dòng)程序。

?

1)在系統(tǒng)內(nèi)存中分配顯存

fbmem.c文件中可以看到, file_operations 結(jié)構(gòu)中的open()release()操作不需底層支持,但read()write() mmap()操作需要函數(shù)fb_get_fix()的支持.因此需要重新實(shí)現(xiàn)函數(shù)fb_get_fix()。另外還需要在系統(tǒng)內(nèi)存中分配顯存空間,大多數(shù)的LCD控制器都沒有自己的顯存空間,被分配的地址空間的起始地址與長(zhǎng)度將會(huì)被填充到fb_fix_screeninfo 結(jié)構(gòu)的smem_start smem_len 的兩個(gè)變量中.被分配的空間必須是物理連續(xù)的。

?

?

2)實(shí)現(xiàn) fb_ops 中的函數(shù)

用戶應(yīng)用程序通過ioctl()系統(tǒng)調(diào)用操作硬件,fb_ops 中的函數(shù)就用于支持這些操作。(注: fb_ops結(jié)構(gòu)與file_operations 結(jié)構(gòu)不同,fb_ops是底層操作的抽象,file_operations是提供給上層系統(tǒng)調(diào)用的接口,可以直接調(diào)用.

? ioctl()系統(tǒng)調(diào)用在文件fbmem.c中實(shí)現(xiàn),通過觀察可以發(fā)現(xiàn)ioctl()命令與fb_opss 中函數(shù)的關(guān)系:

FBIOGET_VSCREENINFO fb_get_var

FBIOPUT_VSCREENINFO fb_set_var

FBIOGET_FSCREENINFO fb_get_fix

FBIOPUTCMAP fb_set_cmap

FBIOGETCMAP fb_get_cmap

FBIOPAN_DISPLAY fb_pan_display

?

?

如果我們定義了fb_XXX_XXX 方法,用戶程序就可以使用FBIOXXXX宏的ioctl()操作來操作硬件。

?

文件linux/drivers/video/fbgen.c或者linux/drivers/video目錄下的其它設(shè)備驅(qū)動(dòng)是比較好的參考資料。在所有的這些函數(shù)中fb_set_var()是最重要的,它用于設(shè)定顯示卡的模式和其它屬性,下面是函數(shù)fb_set_var()的執(zhí)行步驟:

?

1)檢測(cè)是否必須設(shè)定模式

2)設(shè)定模式

?

3)設(shè)定顏色映射

?

4) 根據(jù)以前的設(shè)定重新設(shè)置LCD控制器的各寄存器。

?

第四步表明了底層操作到底放置在何處。在系統(tǒng)內(nèi)存中分配顯存后,顯存的起始地址及長(zhǎng)度將被設(shè)定到 LCD控制器的各寄存器中(一般通過fb_set_var() 函數(shù)),顯存中的內(nèi)容將自動(dòng)被LCD控制器輸出到屏幕上。另一方面,用戶程序通過函數(shù)mmap()將顯存映射到用戶進(jìn)程地址空間中,然后用戶進(jìn)程向映射空間發(fā)送的所有數(shù)據(jù)都將會(huì)被顯示到LCD顯示器上。

?

三、FrameBuffer的應(yīng)用

?

(一)、一個(gè)使用FrameBuffer的例子

?

FrameBuffer主要是根據(jù)VESA標(biāo)準(zhǔn)的實(shí)現(xiàn)的,所以只能實(shí)現(xiàn)最簡(jiǎn)單的功能。

由于涉及內(nèi)核的問題,FrameBuffer是不允許在系統(tǒng)起來后修改顯示模式等一系列操作。(好象很多人都想要這樣干,這是不被允許的,當(dāng)然如果你自己寫驅(qū)動(dòng)的話,是可以實(shí)現(xiàn)的).

對(duì)FrameBuffer的操作,會(huì)直接影響到本機(jī)的所有控制臺(tái)的輸出,包括XWIN的圖形界面。

struct fb_info 中的char fontname[40]; /* default font name */默認(rèn)的字體

就可以實(shí)現(xiàn)顯示的中文化----難道 籃點(diǎn)linux就是這樣搞得??

好,現(xiàn)在可以讓我們開始實(shí)現(xiàn)直接寫屏:

?

1、打開一個(gè)FrameBuffer設(shè)備

?

2、通過mmap調(diào)用把顯卡的物理內(nèi)存空間映射到用戶空間

?

3、直接寫內(nèi)存。

?

/********************************

File name : 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

?

/******************

File name : 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);

}

?

(二)基于Linux核心的漢字顯示的嘗試

我們以一個(gè)簡(jiǎn)單的例子來說明字符顯示的過程。我們假設(shè)是在虛擬終端1/dev/tty1)下運(yùn)行一個(gè)如下的簡(jiǎn)單程序。

?

main ( )

{

puts("hello, world.\n");

}

?

puts 函數(shù)向缺省輸出文件(/dev/tty1)發(fā)出寫的系統(tǒng)調(diào)用write(2)。系統(tǒng)調(diào)用到linux核心里面對(duì)應(yīng)的核心函數(shù)是console.c中的 con_write()con_write()最終會(huì)調(diào)用do_con_write( )。在do_con_write( )中負(fù)責(zé)把"hello, world.\n"這個(gè)字符串放到tty1對(duì)應(yīng)的緩沖區(qū)中去。

do_con_write( )還負(fù)責(zé)處理控制字符和光標(biāo)的位置。讓我們來看一下do_con_write()這個(gè)函數(shù)的聲明。

static int do_con_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count)

??? 其中tty是指向tty_struct結(jié)構(gòu)的指針,這個(gè)結(jié)構(gòu)里面存放著關(guān)于這個(gè)tty的所有信息(請(qǐng)參照 linux/include/linux/tty.h)。Tty_struct結(jié)構(gòu)中定義了通用(或高層)tty的屬性(例如寬度和高度等)。在 do_con_write( )函數(shù)中用到了tty_struct結(jié)構(gòu)中的driver_data變量。driver_data是一個(gè)vt_struct指針。在vt_struct結(jié)構(gòu)中包含這個(gè)tty的序列號(hào)(我們正使用tty1,所以這個(gè)序號(hào)為1)。Vt_struct結(jié)構(gòu)中有一個(gè)vc結(jié)構(gòu)的數(shù)組vc_cons,這個(gè)數(shù)組就是各虛擬終端的私有數(shù)據(jù)。

?

static int do_con_write(struct tty_struct * tty, int from_user,const unsigned char *buf, int count)

{

struct vt_struct *vt = (struct vt_struct *)tty->driver_data;//我們用到了driver_data變量

. . . . .

currcons = vt->vc_num; file://我們?cè)谶@里的vc_nums就是1

. . . . .

}

?

??? 要訪問虛擬終端的私有數(shù)據(jù),需使用vc_conscurrcons.d指針。這個(gè)指針指向的結(jié)構(gòu)含有當(dāng)前虛擬終端上光標(biāo)的位置、緩沖區(qū)的起始地址、緩沖區(qū)大小等等。

??? "hello, world.\n"中的每一個(gè)字符都要經(jīng)過conv_uni_to_pc( )這個(gè)函數(shù)轉(zhuǎn)換成8位的顯示字符。這要做的主要目的是使不同語(yǔ)言的國(guó)家能把16位的UniCode碼映射到8位的顯示字符集上,目前還是主要針對(duì)歐洲國(guó)家的語(yǔ)言,映射結(jié)果為8位,不包含對(duì)雙字節(jié)(double byte)的范圍。

??? 這種UNICODE到顯示字符的映射關(guān)系可以由用戶自行定義。在缺省的映射表上,會(huì)把中文的字符映射到其他的字符上,這是我們不希望看到也是不需要的。所以我們有兩個(gè)選擇∶

?

不進(jìn)行conv_uni_to_pc( )的轉(zhuǎn)換。

加載符合雙字節(jié)處理的映射關(guān)系,即對(duì)非控制字符進(jìn)行1對(duì)1的不變映射。我們自己定制的符合這種映射關(guān)系的UNICODE碼表是direct.uni。要想查看/裝載當(dāng)前系統(tǒng)的unicode映射表,可使外部命令loadunimap

經(jīng)過conv_uni_to_pc( )轉(zhuǎn)換之后,"hello, world.\n"中的字符被一個(gè)一個(gè)地填寫到tty1的緩沖區(qū)中。然后do_con_write( )調(diào)用下層的驅(qū)動(dòng),把緩沖區(qū)中的內(nèi)容輸出到顯示器上(也就相當(dāng)于把緩沖區(qū)的內(nèi)容拷貝到VGA顯存中去)。

?

sw->con_putcs(vc_conscurrcons.d, (u16 *)draw_from, (u16*)draw_to-(u16 *)draw_from, y, draw_x);

?

之所以要調(diào)用底層驅(qū)動(dòng),是因?yàn)榇嬖诓煌娘@示設(shè)備,其對(duì)應(yīng)VGA顯存的存取方式也不一樣。

上面的Sw->con_putcs( )就會(huì)調(diào)用到fbcon.c中的fbcon_putcs()函數(shù)(con_putcs是一個(gè)函數(shù)的指針,在Framebuffer模式下指向 fbcon_putcs()函數(shù))。也就是說在do_con_write( )函數(shù)中是直接調(diào)用了fbcon_putcs()函數(shù)來進(jìn)行字符的繪制。比如說在256色模式下,真正負(fù)責(zé)輸出的函數(shù)是void fbcon_cfb8_putcs(struct vc_data *conp, struct display *p,const unsigned short *s, int count, int yy, int xx)

?

顯示中文

??? 比如說我們?cè)噲D輸出一句中文∶putcs(你好\n );(你好的內(nèi)碼為0xc4,0xe3,0xba,0xc3)。這時(shí)候會(huì)怎么樣呢,有一點(diǎn)可以肯定,"你好"肯定不會(huì)出現(xiàn)在屏幕上,國(guó)為核心中沒有漢字字庫(kù),中文顯示就是無米之炊了.

??? 1 在負(fù)責(zé)字符顯示的void fbcon_cfb8_putcs( )函數(shù)中,原有操作如下∶對(duì)于每個(gè)要顯示的字符,依次從虛擬終端緩沖區(qū)中以WORD為單位讀取(低位字節(jié)是ASCII碼,高8位是字符的屬性),由于漢字是雙字節(jié)編碼方式,所以這種操作是不可能顯示出漢字的,只能顯示出xxxx_putcs()是一個(gè)一個(gè)VGA字符.

?

要解決的問題∶

確保在do_con_write( )時(shí)uni_pc轉(zhuǎn)換不會(huì)改變?cè)芯幋a。一個(gè)很直接的實(shí)現(xiàn)方式就是加載一個(gè)我們自己定制的UNICODE映射表,loadunimapdirect.uni,或者直接把direct.uni置為核心的缺省映射表。

?

針對(duì)如上問題,我們要做的第一個(gè)嘗試方案是如下。

首先需要在核心中加載漢字字庫(kù),然后修改fbcon_cfb8_putcs()函數(shù),在 fbcon_cfb8_putcs( )中一次讀兩個(gè)WORD,檢查這兩個(gè)WORD的低位字節(jié)是否能拼成一個(gè)漢字,如果發(fā)現(xiàn)能拼成一個(gè)漢字,就算出這個(gè)漢字在漢字字庫(kù)中的偏移,然后把它當(dāng)成一個(gè)16 x 16VGA字符來顯示。

?

試驗(yàn)的結(jié)果表明∶

?

能夠輸出漢字,但仍有許多不理想的地方,比如說,輸出以半個(gè)漢字開始的一串漢字,則這半個(gè)漢字后面的漢字都會(huì)是亂碼。這是半個(gè)漢字的問題。

光標(biāo)移動(dòng)會(huì)破壞漢字的顯示。表現(xiàn)為,光標(biāo)移動(dòng)過的漢字會(huì)變成亂碼。這是因?yàn)楣鈽?biāo)的更新是通過xxxx_putc( )函數(shù)來完成的。

xxxx_putc( )函數(shù)與xxxx_putcs( )函數(shù)實(shí)現(xiàn)的功能類似,但是xxxx_putc()函數(shù)只刷新一個(gè)字符而不是一個(gè)字符串,因而xxxx_putc()的輸入?yún)?shù)是一個(gè)整數(shù),而不是一個(gè)字符串的地址。Xxxx_putc( )函數(shù)的聲明如下∶void fbcon_cfb8_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx)

?

??? 下一個(gè)嘗試方案就是同時(shí)修改xxxx_putcs( )函數(shù)和xxxx_putc()函數(shù)。為了解決半個(gè)漢字的問題,每一次輸出之前,都從屏幕當(dāng)前行的起始位置開始掃描,以確定要輸出的字符是否落在半個(gè)漢字的位置上。如果是半個(gè)漢字的位置,則進(jìn)行相應(yīng)的調(diào)整,即從向前移動(dòng)一個(gè)字節(jié)的位置開始輸出。

??? 這個(gè)方案有一個(gè)困難,即xxxx_putc( )函數(shù)不用緩沖區(qū)的地址,而是用一個(gè)整數(shù)作為參數(shù)。所以xxxx_putc( )無法直接利用相鄰的字符來判別該定符是否是漢字。

??? 解決方案是,利用xxxx_putc( )的光標(biāo)位置參數(shù)(yy, xx),可以逆推出該字符在緩沖區(qū)中的位置。但仍有一些小麻煩,在Linux的虛擬終端下,用戶可能會(huì)上卷該屏幕(shift + pageup),導(dǎo)致光標(biāo)的y座標(biāo)和相應(yīng)字符在緩沖區(qū)的行數(shù)不一致。相應(yīng)的解決方案是,在逆推的過程中,考慮卷屏的參量。

??? 這樣一來,我們就又進(jìn)了一步,得到了一個(gè)相對(duì)更好的版本。但仍有問題沒有解決。敲入turbonetcfg,會(huì)發(fā)現(xiàn)菜單的邊框字符也被當(dāng)成漢字顯示。這是因?yàn)?#xff0c;這種邊框字符是擴(kuò)展字符,也使用了字符的第8位,因而被當(dāng)作漢字來顯示。例如,單線一的制表符內(nèi)碼為0xC4,當(dāng)連成一條長(zhǎng)線就是由一連串0xC4 組成,而0xC4C4正是漢字哪。于是水平的制表符被一連串的哪字替代了。要解決這個(gè)問題就非常不容易了,因?yàn)橹票矸姆N類比較多,而且垂直制表符與其后面字符的組合型式又多種多樣,因而很難判斷出相應(yīng)位置的字符是不是制表符,從理論上說,無論采取什么樣的排除算法,都必然存在誤判的情況,因?yàn)榭偞嬖诙x性,沒有充足的條件來推斷出當(dāng)前字符究竟是制表符還是漢字。

??? 我們一方面尋找更好的排除組合算法,一方面試圖尋找其它的解決方案。要想從根本上解決定個(gè)問題,必須利用其它的輔助信息,僅僅從緩沖區(qū)的字符來判斷是不夠的。

??? 經(jīng)過一番努力,我們發(fā)現(xiàn),在UNIX中使用擴(kuò)展字符時(shí),都要先輸出字符轉(zhuǎn)義序列(Escape sequence)來切換當(dāng)前字符集。字符轉(zhuǎn)義序列是以控制字符Esc為首的控制命令,在UNIX的虛擬終端中完成終端控制命令,這種命令包括,移動(dòng)光標(biāo)座標(biāo)、卷屏、刪除、切換字符集等等。也就是說在輸出代表制表符的字符串之前,通常是要先輸出特定的字符轉(zhuǎn)義序列。在console.c里,有根據(jù)字符轉(zhuǎn)義序列命令來記錄字符狀態(tài)的變量。結(jié)合該變量提供的信息,就可以非常干凈地把制表符與漢字區(qū)別開來。

?

??? 在如上思路的指引下,我們又產(chǎn)生了新的解決方案。經(jīng)過改動(dòng)得到了另一各版本.

??? 在這個(gè)新版本上,turbonetcfg在初次繪制的時(shí)候,制表符與漢字被清晰地區(qū)分開來,結(jié)果是非常正確的。但還有新的問題存在 turbonetcfg 在重繪的時(shí)候(如切換虛擬終端或是移動(dòng)鼠標(biāo)光標(biāo)的時(shí)候),制表符還是變成了漢字,因?yàn)橹乩L完全依賴于緩沖區(qū),而這時(shí)用來記錄字符集狀態(tài)的變量并不反映當(dāng)前字符集狀態(tài)。問題還是沒有最終解決。我們又回到了起點(diǎn)。∶( 看來問題的最終解決手段必須是把字符集的狀態(tài)伴隨每一個(gè)字符存在緩沖區(qū)中。讓我們來研究一下緩沖區(qū)的結(jié)構(gòu)。每一個(gè)字符占用16bit的緩沖區(qū),低8位是 ASCII值,完全被利用,高8位包含前景顏色和背景顏色的屬性,也沒有多余的空間可以利用。因而只能另外開辟新的緩沖區(qū)。為了保持一致性,我們決定在原來的緩沖區(qū)后面添加相同大小的緩沖區(qū),用來存放是否是漢字的信息。

?

??? 也許有讀者會(huì)問,我們只需要為每個(gè)字符添加一bit的信息來標(biāo)志是否是漢字就足夠了,為什么還要開辟與原緩沖區(qū)大小相同的雙倍緩沖區(qū),是不是太浪費(fèi)呢?我們先放下這個(gè)問題,稍后再作回答。

??? 其實(shí),如果再添加一bit來標(biāo)志是當(dāng)前字符是漢字的左半邊還是右半邊的話,就會(huì)省去掃描屏幕上當(dāng)前整行字符串的工作,這樣一來,編程會(huì)更簡(jiǎn)單。但是有讀者會(huì)問,即使是這樣,使用8bit總夠用了吧?為什么還要使用16bit呢?

??? 我們的作法是∶用低8位來存放漢字另外一半的內(nèi)碼,用高8位中的2 bit來存放上面所講的輔助信息,高8位的剩余6位可以用來存放漢字或其它編碼方式(如BIG5或日文、韓文)的信息,從而使我們可以實(shí)現(xiàn)同屏顯示多種雙字節(jié)語(yǔ)言的字符而不會(huì)有相互干擾。另外,在編程時(shí),雙倍緩沖也比較容易計(jì)算。這樣我們就回答了如上的兩個(gè)問題。

??? 迄今為止,我們有了一套徹底解決漢字和制表符相互干擾、半個(gè)漢字的刷新、重繪等問題的方案。剩下的就是具體編程實(shí)現(xiàn)的問題了。

??? 但是,由于Framebuffer的驅(qū)動(dòng)很多,修改每一個(gè)驅(qū)動(dòng)的xxxx_putc()函數(shù)和xxxx_putcs( )函數(shù)會(huì)是一項(xiàng)不小的工作,而且,改動(dòng)驅(qū)動(dòng)程序后,每種驅(qū)動(dòng)的測(cè)試也是很麻煩的,尤其是對(duì)于有硬件加速的顯卡,修改和測(cè)試會(huì)更不容易。那么,存不存在一種不需要修改顯卡驅(qū)動(dòng)程序的方法呢?

??? 經(jīng)過努力,我們發(fā)現(xiàn),可以在調(diào)用xxxx_putcs( )xxxx_putc()函數(shù)輸出漢字之前,修改vga字庫(kù)的指針使其指向所需顯示的漢字在漢字字庫(kù)中的位置,即把一個(gè)漢字當(dāng)成兩個(gè)vga ASCII字符輸出。也就是說,在內(nèi)核中存在兩個(gè)字庫(kù),一個(gè)是原有的vga字符字庫(kù),另一個(gè)是漢字字庫(kù),當(dāng)我們需要輸出漢字的時(shí)候,就把vga字庫(kù)的指針指向漢字字庫(kù)的相應(yīng)位置,漢字輸出完之后,再把該指針指向vga字庫(kù)的原有位置。

?? 這樣一來,我們只需要修改fbcon.cconsole.c,其中console.c負(fù)責(zé)維護(hù)雙倍緩沖區(qū),把每一個(gè)字符的信息存入附加的緩沖區(qū);而 fbcon.c負(fù)責(zé)利用雙倍緩沖區(qū)中附加的信息,調(diào)整vga字庫(kù)的指針,調(diào)用底層的顯示驅(qū)動(dòng)程序。這里還有幾個(gè)需要注意的地方∶

?

由于屏幕重繪等原因,調(diào)用底層驅(qū)動(dòng)xxxx_putc( )xxxx_putcs()的地方有多處。我們作了兩個(gè)函數(shù)分別包裝這兩個(gè)調(diào)用,完成替換字庫(kù)、調(diào)用xxxx_putcs( )xxxx_putc( )、恢復(fù)字庫(kù)等功能。

為了實(shí)現(xiàn)向上滾屏(shift + pageup)時(shí)也能看到漢字,我們需要作另外的修改。

??? Linux 在設(shè)計(jì)虛擬終端的時(shí)候,提供了回顧被卷出屏幕以外的信息的功能,這就是用熱鍵來向上滾屏(shift + pageup)。當(dāng)前被使用的虛擬終端擁有一個(gè)公共的緩沖區(qū)(soft back),用來存放被滾出屏幕以外的信息。當(dāng)切換虛擬終端的時(shí)候,公共緩沖區(qū)的內(nèi)容會(huì)被清除而被新的虛擬終端使用。向上滾屏的時(shí)候,顯示的是公共緩沖區(qū)中的內(nèi)容。因此,如果我們想在向上滾屏的時(shí)候看到漢字,公共緩沖區(qū)也必須加倍,以確保沒有信息丟失。當(dāng)滾出屏幕的信息向公共緩沖區(qū)填寫的時(shí)候,必須把相應(yīng)的附加信息也填寫進(jìn)公共緩沖區(qū)的附加區(qū)域。這就要求fbcon.c必須懂得利用公共緩沖區(qū)的附加信息。

??? 當(dāng)然,有另外一種偷懶的方法,那就是不允許用戶向上滾屏,從而避免對(duì)公區(qū)緩沖區(qū)的處理。

把不同的編碼方式(GBBIG5、日文和韓文)寫成不同的module,以實(shí)現(xiàn)動(dòng)態(tài)加載,從而使得擴(kuò)展新的編碼方式不需要重新編譯核心。

測(cè)試

?

本文實(shí)現(xiàn)的Kernel Patch文件(patch.kernel.chinese)可以從http://www.turbolinux.com.cn下載。Cd /usr/src/(該目錄下應(yīng)有Linux核心源程序所在的目錄linux/ patch -p0 -b < patch.kernel.chinese make menuconfig 請(qǐng)選擇Console drivers選項(xiàng)中的

?

* Double Byte Character Display Support(EXPERIMENTAL)

* Double Byte GB encode (module only)

* VESA VGA graphics console

<*> Virtual Frame Buffer support (ONLY FOR TESTING!)

<*> 8 bpp packed pixels support

<*> 16 bpp packed pixels support

<*> VGA characters/attributes support

* Select compiled-in fonts

*VGA 8x8 font

*VGA 8x16 font

?

make dep

make bzImage

make modules

make install

make modules_install

?

然后用新的核心啟動(dòng)。

?

Insmod encode-gb.o

?

四、其它

?

(一)?? 設(shè)置FrameBuffer

??? FrameBuffer,可以譯作"幀緩沖",有時(shí)簡(jiǎn)稱為 fbdrv,基于fbdrvconsole也被稱之為fbcon。這是一種獨(dú)立于硬件的抽象圖形設(shè)備。FrameBuffer的優(yōu)點(diǎn)在于其高度的可移植性、易使用性、穩(wěn)定性。使用Linux內(nèi)核的 FrameBuffer驅(qū)動(dòng)(vesafb),可以輕松支持到1024X768X32bpp以上的分辯率。而且目前可得到的絕大多數(shù)linux版本所發(fā)行的內(nèi)核中,已經(jīng)預(yù)編譯了FrameBuffer支持,通常不需要重新編譯內(nèi)核就可以使用。所以FrameBuffer也是zhcon推薦使用的驅(qū)動(dòng)方式。

?

進(jìn)入FrameBuffer可以簡(jiǎn)單地在系統(tǒng)啟動(dòng)時(shí)向kernel傳送vga=mode-number的參數(shù)來激活FrameBuffer設(shè)備,如:

lilo:linux vga=305

將會(huì)啟動(dòng)1024x768x8bpp模式。

?

?????????? 640x480??? 800x600??? 1024x768??? 1280x1024

? 8 bpp????? 769????????? 771?????? 773??????? 775

? 16 bpp???? 785????????? 788?????? 791??????? 794

? 32 bpp???? 786????????? 789?????? 792??????? 795

?

(二)?? 要使linux缺省進(jìn)入FrameBuffer,可以修改/etc/lilo.conf,加入一下語(yǔ)句:

vga=0x303

退出編輯,執(zhí)行:

lilo -v

重新啟動(dòng)linux,可以使其進(jìn)入800x600256色模式。

grub也是一樣,在grub.conf中的kernel行后面寫上vga=xxx就行了,也可以用vga=ask,讓系統(tǒng)啟動(dòng)的時(shí)候詢問你用多大的分辨率

?

(三)我編譯內(nèi)核時(shí),選擇framebuffer模式,啟動(dòng)時(shí)屏幕上有一企鵝圖片,不知這是如何造成的這個(gè)圖片可以去掉或改動(dòng)嗎?

可以將drivers/video/fbcon.c: fbcon_setup()if (logo) { } 代碼去掉

總結(jié)

以上是生活随笔為你收集整理的LINUX framebuffer的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。