Linux驅動之LCD驅動編寫


Linux驅動之內核自帶的S3C2440的LCD驅動分析這篇博客中已經分析了編寫LCD驅動的步驟,接下來就按照這個步驟來字嘗試字節編寫LCD驅動。用的LCD屏幕為tft屏,每個像素點為16bit。對應與紅綠藍分別為565。

1、分配一個fb_info結構

2、設置fb_info結構

3、硬件相關的操作,配置LCD時鍾、配置IO端口、配置LCD寄存器。

4、最終注冊fbinfo結構到registered_fb數組

 

要理解LCD的工作原理,需要了解LCD的時鍾,在TFT的LCD中有如下的時鍾。這個幾個時鍾數據在配置LCD寄存器時都說需要設置的。

1、VCLK:兩個像素之間的時鍾,即兩個像素隔多長時間才能顯示下一個像素

2、HSYNC:水平同步時鍾,即第一行像素點顯示完成之后隔多長時間才能開始下一行的顯示

3、VSYNC:垂直方向的同步時鍾,也叫幀同步信號,即一幀數據顯示完成之后(一幀數據表示一個屏幕顯示完成,即一個顯存的數據全部取完),過多長下一幀數據才開始顯示

 

本節需要用到的函數:

void *dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp);  //分配DMA緩存區給顯存
//返回值為:申請到的DMA緩沖區的虛擬地址,若為NULL,表示分配失敗,則需要使用dma_free_writecombine()釋放內存,避免內存泄漏
//參數如下: 

//*dev:指針,這里填0,表示這個申請的緩沖區里沒有內容

//size:分配的地址大小(字節單位)

//*handle:申請到的物理起始地址

//gfp:分配出來的內存參數,標志定義在<linux/gfp.h>,常用標志如下:
    //GFP_ATOMIC    用來從中斷處理和進程上下文之外的其他代碼中分配內存. 從不睡眠.
    //GFP_KERNEL    內核內存的正常分配. 可能睡眠.
    //GFP_USER      用來為用戶空間頁來分配內存; 它可能睡眠.   

分配一段DMA緩存區,分配出來的內存會禁止cache緩存(因為DMA傳輸不需要CPU)

它和 dma_alloc_coherent ()函數相似,不過 dma_alloc_coherent ()函數是分配出來的內存會禁止cache緩存以及禁止寫入緩沖區

dma_free_writecombine(dev,size,cpu_addr,handle);   //釋放緩存
//cpu_addr:虛擬地址, 
//handle:物理地址

釋放DMA緩沖區, dev和size參數和上面的一樣

struct fb_info *framebuffer_alloc(size_t size, struct device *dev);      //申請一個fb_info結構體,
//size:額外的內存,
//*dev:指針, 這里填0,表示這個申請的結構體里沒有內容

 

int register_framebuffer(struct fb_info *fb_info);  

                      //向內核中注冊fb_info結構體,若內存不夠,注冊失敗會返回負數

int unregister_framebuffer(struct fb_info *fb_info) ;

                      //注銷內核中fb_info結構體

 

本節需要用到的結構體:

fb_info結構體如下:

struct fb_info {
        ... ...
       struct fb_var_screeninfo var;       //可變的參數
       struct fb_fix_screeninfo fix;        //固定的參數
       ... ...
       struct fb_ops *fbops;              //操作函數
       ... ...
       char __iomem *screen_base;        //顯存虛擬起始地址
       unsigned long screen_size;          //顯存虛擬地址長度
  
       void *pseudo_palette;                
//假的16色調色板,里面存放了16色的數據,可以通過8bpp數據來找到調色板里面的16色顏色索引值,模擬出16色顏色來,節省內存,不需要的話就指向一個不用的數組即可
       ... ...
};

其中操作函數fb_info-> fbops 結構體寫法如下:

static struct fb_ops s3c_lcdfb_ops = {
         .owner                = THIS_MODULE,

         .fb_setcolreg    = my_lcdfb_setcolreg,//設置調色板fb_info-> pseudo_palette,自己構造該函數

         .fb_fillrect      = cfb_fillrect,     //填充矩形,用/drivers/video/ cfbfillrect.c里的函數即可

         .fb_copyarea    = cfb_copyarea,  //復制數據, 用/drivers/video/cfbcopyarea.c里的函數即可

         .fb_imageblit    = cfb_imageblit, //繪畫圖形, 用/drivers/video/imageblit.c里的函數即可
};

固定的參數fb_info-> fix 結構體如下:

struct fb_fix_screeninfo {
       char id[16];                   //id名字
       unsigned long smem_start;  //framebuffer物理起始地址                          
       __u32 smem_len;           //framebuffer長度,字節為單位
       __u32 type;                 //lcd類型,默認值0即可
       __u32 type_aux;               //附加類型,為0
       __u32 visual;                     //畫面設置,常用參數如下
// FB_VISUAL_MONO01             0   單色,0:白色,1:黑色
// FB_VISUAL_MONO10             1    單色,1:白色,0:黑色
// FB_VISUAL_TRUECOLOR          2     真彩(TFT:真彩)
// FB_VISUAL_PSEUDOCOLOR     3     偽彩
// FB_VISUAL_DIRECTCOLOR        4     直彩

    __u16 xpanstep;                /*如果沒有硬件panning就賦值為0 */
    __u16 ypanstep;                /*如果沒有硬件panning就賦值為0 */
    __u16 ywrapstep;                 /*如果沒有硬件ywrap就賦值為0 */

    __u32 line_length;                 /*一行的字節數 ,例:(RGB565)240*320,那么這里就等於240*16/8 */

    /*以下成員都可以不需要*/
    unsigned long mmio_start;        /*內存映射IO的起始地址,用於應用層直接訪問寄存器,可以不需要*/                                   
       __u32 mmio_len;                   /* 內存映射IO的長度,可以不需要*/
       __u32 accel;                 
       __u16 reserved[3];        

};

可變的參數fb_info-> var 結構體如下:

structfb_var_screeninfo{                                    
   __u32xres;                    /*可見屏幕一行有多少個像素點*/
    __u32 yres;                      /*可見屏幕一列有多少個像素點*/
    __u32 xres_virtual;         /*虛擬屏幕一行有多少個像素點 */       
    __u32  yres_virtual;       /*虛擬屏幕一列有多少個像素點*/
    __u32 xoffset;                 /*虛擬到可見屏幕之間的行偏移,若可見和虛擬的分辨率一樣,就直接設為0*/
    __u32 yoffset;                 /*虛擬到可見屏幕之間的列偏移*/
    __u32  bits_per_pixel;    /*每個像素的位數即BPP,比如:RGB565則填入16*/
    __u32 grayscale;           /*非0時,指的是灰度,真彩直接填0即可*/

    struct fb_bitfield red;          //fb緩存的R位域, fb_bitfield結構體成員如下:
//__u32 offset;          區域偏移值,比如RGB565中的R,就在第11位
//__u32 length;                   區域長度,比如RGB565的R,共有5位
//__u32 msb_right;  msb_right ==0,表示數據左邊最大, msb_right!=0,表示數據右邊最大


    struct fb_bitfield green;    /*fb緩存的G位域*/
    struct fb_bitfield blue;       /*fb緩存的B位域*/

   /*以下參數都可以不填,默認為0*/
    struct fb_bitfield transp;   /*透明度,不需要填0即可*/    
 
    __u32nonstd;                    /* != 0表示非標准像素格式*/
    __u32 activate;                 /*設為0即可*/
    __u32height;                     /*外設高度(單位mm),一般不需要填*/
    __u32width;                      /*外設寬度(單位mm),一般不需要填*/
    __u32 accel_flags;        /*過時的參數,不需要填*/

    /* 除了pixclock本身外,其他的都以像素時鍾為 單位*/ 
    __u32pixclock;                   /*像素時鍾(皮秒)*/
    __u32 left_margin;         /*行切換,從同步到繪圖之間的延遲*/
    __u32right_margin;        /*行切換,從繪圖到同步之間的延遲*/
    __u32upper_margin;       /*幀切換,從同步到繪圖之間的延遲*/
    __u32lower_margin;       /*幀切換,從繪圖到同步之間的延遲*/
    __u32hsync_len;              /*水平同步的長度*/
    __u32 vsync_len;           /*垂直同步的長度*/
    __u32 sync;
    __u32 vmode;
    __u32 rotate;
    __u32reserved[5];        /*保留*/

}

 

1.寫驅動程序:

(驅動設置:參考自帶的LCD平台驅動drivers/video/s3c2410fb.c )

(LCD控制寄存器設置:參考之前的LCD裸機驅動:http://www.cnblogs.com/lifexy/p/7144890.html)

1.1 步驟如下:

在驅動init入口函數中:

1)分配一個fb_info結構體

2)設置fb_info

  2.1)設置固定的參數fb_info-> fix

  2.2) 設置可變的參數fb_info-> var

  2.3) 設置操作函數fb_info-> fbops

  2.4) 設置fb_info 其它的成員

3)設置硬件相關的操作    

  3.1)配置LCD引腳

  3.2)根據LCD手冊設置LCD控制器

  3.3)分配顯存(framebuffer),把地址告訴LCD控制器和fb_info

4)開啟LCD,並注冊fb_info: register_framebuffer()

  4.1) 直接在init函數中開啟LCD(后面講到電源管理,再來優化)

    控制LCDCON5允許PWREN信號,

    然后控制LCDCON1輸出PWREN信號,

    輸出GPB0高電平來開背光,

  4.2) 注冊fb_info

在驅動exit出口函數中:

1)卸載內核中的fb_info

2) 控制LCDCON1關閉PWREN信號,關背光,iounmap注銷地址

3)釋放DMA緩存地址dma_free_writecombine()

4)釋放注冊的fb_info

 

1.2 具體代碼如下:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <asm/io.h>        //含有iomap函數iounmap函數
#include <asm/uaccess.h>//含有copy_from_user函數
#include <linux/device.h>//含有類相關的處理函數
#include <linux/fb.h>      //含有fb_info結構體定義
//#include <asm/dma-mapping.h> //含有dma_free_writecombine宏定義
#include <linux/dma-mapping.h>  //含有dma_free_writecombine宏定義
#include <linux/platform_device.h>//含有平台設備總線模型相關變量
#include <linux/mm.h>
#include <linux/slab.h>

//#include <linux/module.h>
//#include <linux/kernel.h>
//#include <linux/errno.h>
//#include <linux/string.h>
//#include <linux/mm.h>
//#include <linux/slab.h>
//#include <linux/delay.h>
//#include <linux/fb.h>
//#include <linux/init.h>
//#include <linux/dma-mapping.h>
//#include <linux/interrupt.h>
//#include <linux/workqueue.h>
//#include <linux/wait.h>
//#include <linux/platform_device.h>
//#include <linux/clk.h>

//#include <asm/io.h>
//#include <asm/uaccess.h>
//#include <asm/div64.h>

//#include <asm/mach/map.h>
//#include <asm/arch/regs-lcd.h>
//#include <asm/arch/regs-gpio.h>
//#include <asm/arch/fb.h>

/*lcd控制寄存器放在一個結構體里面*/
struct lcd_regs {
    unsigned long    lcdcon1;    
    unsigned long    lcdcon2;    
    unsigned long    lcdcon3;    
    unsigned long    lcdcon4;    
    unsigned long    lcdcon5;    
    unsigned long    lcdsaddr1;    
    unsigned long    lcdsaddr2;    
    unsigned long    lcdsaddr3;    
    unsigned long    redlut;    
    unsigned long    greenlut;    
    unsigned long    bluelut;    
    unsigned long    reserved[9];    
    unsigned long    dithmode;    
    unsigned long    tpal;    
    unsigned long    lcdintpnd;    
    unsigned long    lcdsrcpnd;    
    unsigned long    lcdintmsk;    
    unsigned long    lpcsel;
};


static struct fb_info *s3c_mylcdfb_info;//fb_info結構體
static volatile unsigned long *gpbcon;//GPB0用於lcd背光的控制
static volatile unsigned long *gpbdat;//GPB0用於lcd背光的控制
static volatile unsigned long *gpccon;
static volatile unsigned long *gpdcon;
static volatile unsigned long *gpgcon;//GPG4用於lcd電源
static volatile struct lcd_regs* lcd_regs;//lcd寄存器
static u32 pseudo_palette[16];            //調色板內存


/* from pxafb.c */
static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
{
    chan &= 0xffff;                //取出16bit的數據
    chan >>= 16 - bf->length; //
    return chan << bf->offset;
}


static int s3c_mylcdfb_setcolreg(unsigned int regno, unsigned int red,
                 unsigned int green, unsigned int blue,
                 unsigned int transp, struct fb_info *info)
{
    unsigned int val;
    
    if (regno > 16)
        return 1;

    /* 用red,green,blue三原色構造出val */
    val  = chan_to_field(red,    &info->var.red);
    val |= chan_to_field(green, &info->var.green);
    val |= chan_to_field(blue,    &info->var.blue);
    
    //((u32 *)(info->pseudo_palette))[regno] = val;
    pseudo_palette[regno] = val;
    return 0;
}

static struct fb_ops s3c_mylcdfb_ops = {     //操作函數結構體
    .owner        = THIS_MODULE,
    .fb_setcolreg    = s3c_mylcdfb_setcolreg,//待會設置,這個是調色板,如果使用小於16bit的像素需要用到
    .fb_fillrect    = cfb_fillrect,
    .fb_copyarea    = cfb_copyarea,
    .fb_imageblit    = cfb_imageblit,
};

static int lcd_drv_init(void)
{
    /*1、分配一個fb_info*/
    s3c_mylcdfb_info = framebuffer_alloc(0,NULL);//size為額外分配的大小,這里不需要,所以設為0
    if(s3c_mylcdfb_info==NULL)
        {
        printk("unframebuffer_alloc\n");
        return 1;
        }
    
    /*2、設置*/
    /*2.1 設置固定的參數*/
    strcpy(s3c_mylcdfb_info->fix.id, "mylcd");//名字
    //s3c_mylcdfb_info->fix.smem_start = ;//顯存的物理起始地址,后面設置
    s3c_mylcdfb_info->fix.smem_len = 480*272*16/8;//單位為字節,每個像素點占用16bit :565,顯存的大小
    s3c_mylcdfb_info->fix.type = FB_TYPE_PACKED_PIXELS;//LCD類型,填充像素的類型 tft
    //s3c_mylcdfb_info->fix.type_aux= //附加的LCD類型,不需要設置
    s3c_mylcdfb_info->fix.visual = FB_VISUAL_TRUECOLOR;//視覺類型,選擇真彩色
    s3c_mylcdfb_info->fix.line_length = 480*16/8; //一行的長度,單位為字節
//    s3c_mylcdfb_info->fix.mmio_start = //控制lcd的寄存器的物理地址
//    s3c_mylcdfb_info->fix.mmio_len = //控制lcd的寄存器的大小

    /*2.2 設置可變的參數*/
    s3c_mylcdfb_info->var.xres = 480;//x方向的分辨率
    s3c_mylcdfb_info->var.yres = 272;//y方向的分辨率
    s3c_mylcdfb_info->var.xres_virtual = 480;//x方向的虛擬分辨率
    s3c_mylcdfb_info->var.yres_virtual = 272;//y方向的虛擬分辨率
    s3c_mylcdfb_info->var.bits_per_pixel = 16;//每個像素的大小,單位為bit
    s3c_mylcdfb_info->var.grayscale = 0;//灰度值
    
    s3c_mylcdfb_info->var.red.length = 5;//紅色像素占用的長度,單位bit
    s3c_mylcdfb_info->var.green.length = 6;//綠色像素占用的長度,單位bit
    s3c_mylcdfb_info->var.blue.length = 5;//藍色像素占用的長度,單位bit
    
    s3c_mylcdfb_info->var.red.offset= 11;//紅色像素在16bit中的偏移值
    s3c_mylcdfb_info->var.green.offset= 6;//綠色像素在16bit中的偏移值
    s3c_mylcdfb_info->var.blue.offset=0;//藍色像素在16bit中的偏移值
    
    s3c_mylcdfb_info->var.red.msb_right= 0;//低位在前還是高位在前,一般高位在前,也就是小端模式
    s3c_mylcdfb_info->var.green.msb_right= 0;
    s3c_mylcdfb_info->var.blue.msb_right=0;

    s3c_mylcdfb_info->var.activate = FB_ACTIVATE_NOW;//使用默認參數,顯存立刻生效
    
    /*2.3 設置操作函數*/
    s3c_mylcdfb_info->fbops            = &s3c_mylcdfb_ops;
    
    /*2.4 其它的一些設置 */
    s3c_mylcdfb_info->pseudo_palette  = pseudo_palette;//調色板的地址
    //s3c_mylcdfb_info->screen_base     = ;//顯存的虛擬基地址
    s3c_mylcdfb_info->screen_size       = 480*272*16/8;//單位為字節,每個像素點占用16bit :565,顯存的大小
    
    /*3、硬件相關的操作 */
    /*3.1、配置GPIO用於LCD*/
    gpbcon = ioremap(0x56000010, 8);//將實際的寄存器地址轉換為虛擬地址
    gpccon =  ioremap(0x56000020 , 4);
    gpdcon = ioremap(0x56000030 , 4);
    gpgcon = ioremap(0x56000060 , 4);
    gpbdat = gpbcon + 1;

    *gpccon  = 0xaaaaaaaa;   /* GPIO管腳用於VD[7:0],LCDVF[2:0],VM,VFRAME,VLINE,VCLK,LEND */
    *gpdcon  = 0xaaaaaaaa;   /* GPIO管腳用於VD[23:8] */
    
    *gpbcon &= ~(3);  /* GPB0設置為輸出引腳 */
    *gpbcon |= 1;
    
    *gpbdat &= ~1;     /* 輸出低電平關閉LCD背光 */

    *gpgcon |= (3<<8); /* GPG4用作LCD_PWREN 電源*/
    
    
    /*3.2、根據LCD手冊設置LCD控制器,比如VCLK的頻率等 */
    lcd_regs = ioremap(0X4D000000 , sizeof(struct lcd_regs));

    /* 
      *  bit[17:8] : VCLK = HCLK / [(CLKVAL+1) x 2] 
      *                 10M = 100M/[(CLKVAL+1) x 2] 
      *                  CLKVAL = 4
      * 
      * bit[6:5] :PNRMODE = 11顯示模式,選擇TFT模式
      *
      * bit[4:1] :BPPMODE = 1100;像素=16bit 565
      *
      * bit[0]    :ENVID = 0;先關閉LCD控制器
      */
    lcd_regs->lcdcon1 = (4<<8) | (3<<5) | (0x0c<<1);//


    /*
      * [31:24] : VBPD = 幀同步信號發出后,過多長時間開始顯示數據,單位為行,理解為1行的時間
      * 看LCD手冊tvb = VBPD + 1 = 2;所以VBPD = 1
      *
      * [23:14]:LINEVAL + 1= 272;,所以LINEVAL = 271;垂直方向尺寸,多少行
      *
      * [13:6]:VFPD = 一幀的數據傳輸完成之后,過多長時間開始下一幀數據的幀同步信號,單位為行,理解為1行的時間
      * 看LCD手冊tvf = VFPD + 1 = 2;所以VFPD = 1
      *
      * [5:0]:VSPW = 幀同步信號的脈沖寬度,單位為行
      * 看LCD手冊tvp = VSPW + 1 =10;所以VSPW = 9
      */
    lcd_regs->lcdcon2 = (1<<24) | (271<<14) | (1<<6) | (9<<0);


    /* 
      * [25:19]:HBPD = 行同步信號發出后,經過多少個VCLK,才發送像素的數據,單位為VCLK
      * 看LCD手冊thb = HBPD + 1 = 2;所以HBPD=1
      * 
      * [18:8]:HOZVAL + 1 = 480,所以 HOZVAL = 479;水平方向尺寸,多少列
      *
      *[7:0]:HFPD = 一行的像素數據傳輸完成之后,經過多長時間,才能發送下一個行同步信號,單位為VCLK
      *看LCD手冊thf = HFPD + 1 = 2;所以HFPD = 1;
      */
    lcd_regs->lcdcon3 = (1<<19) | (479<<8) | (1<<0);


    /*
      * [7:0]:HSPW = 行同步信號的脈沖寬度,單位為VCLK
      * 看LCD手冊thp = HSPW + 1 = 41;所以HSPW = 40
      *
      */
    lcd_regs->lcdcon4 = (40<<0);

    /*
      * [11] :FRM565 = 1;16位模式的格式 R:G:B = 5:6:5
      * [10] :INVVCLK = 0;VCLK在哪個邊沿取數據 = 0表示下降沿取數據
      * [9] :INVVLINE  = 1;行同步信號是否需要反轉= 1需要反轉
      * [8] :INVVFRAME = 1;幀同步信號是否需要反轉= 1需要反轉
      * [7] :INVVD = 0;    數據是否需要反轉
      * [6] :INVVDEN = 0; 數據使能信號是否需要反轉
      * [5] :INVPWREN = 0;電源使能信號是否需要反轉
      * [4] :INVLEND = 0;行結束信號是否需要反轉
      * [3] :PWREN  = 0;電源使能信號,先不使能
      * [2] :ENLEND = 1;//行結束信號先使能
      * [1:0] :BSWP 、HWSWP = 0 1;字節內部不需要交換,字節間需要交換
      */
    lcd_regs->lcdcon5= (1<<11) | (3<<8) | (1<<2) | (1<<0);

    /*3.3、顯存和調色板設置 */

    /*
      *利用dma_alloc_writecombine分配一塊連續的顯存
      */
    s3c_mylcdfb_info->screen_base = dma_alloc_writecombine(NULL,s3c_mylcdfb_info->screen_size,(&(s3c_mylcdfb_info->fix.smem_start)),GFP_KERNEL);//返回虛擬地址
    if(s3c_mylcdfb_info->screen_base==NULL)        //如果顯存分配失敗,直接返回
        {
        printk("undma_alloc_writecombine\n");
        return 1;
        }

    /*
      *將顯存的地址告訴LCD控制器(物理地址)
      */
     lcd_regs->lcdsaddr1 = (s3c_mylcdfb_info->fix.smem_start >> 1) & (~(3<<30));//起始地址
     lcd_regs->lcdsaddr2 =  ((s3c_mylcdfb_info->fix.smem_start + s3c_mylcdfb_info->screen_size) >> 1) & 0x1fffff;//結束地址
     lcd_regs->lcdsaddr3  = (480*16/16);  /* 一行的長度(單位: 2字節) */    
    
    //s3c_lcd->fix.smem_start = xxx;  /* 顯存的物理地址 */
    /* 啟動LCD */
    lcd_regs->lcdcon1 |= (1<<0); /* 使能LCD控制器 */
    lcd_regs->lcdcon5 |= (1<<3); /* 使能LCD本身電源 */
    *gpbdat |= 1;                       /* 輸出高電平, 使能背光 */    
    
    /*4、注冊LCD*/
    register_framebuffer(s3c_mylcdfb_info);
    printk("register_framebuffer\n");
    return 0;
}

static void lcd_drv_exit(void)
{
    unregister_framebuffer(s3c_mylcdfb_info);
    lcd_regs->lcdcon1 &= ~(1<<0); /* 關閉LCD本身 */
    *gpbdat &= ~1;                       /* 關閉背光 */
    dma_free_writecombine(NULL, s3c_mylcdfb_info->fix.smem_len, s3c_mylcdfb_info->screen_base, s3c_mylcdfb_info->fix.smem_start);
    iounmap(lcd_regs);
    iounmap(gpbcon);
    iounmap(gpccon);
    iounmap(gpdcon);
    iounmap(gpgcon);
    framebuffer_release(s3c_mylcdfb_info);
}


module_init(lcd_drv_init);
module_exit(lcd_drv_exit);
MODULE_LICENSE("GPL");

 

 

2.重新編譯內核,去掉默認的LCD

make menuconfig ,進入menu菜單重新設置內核參數:

進入Device Drivers-> Graphics support:
<M> S3C2410 LCD framebuffer support          //將自帶的LCD驅動設為模塊, 不編進內核中

然后make uImage 編譯內核

make modules 編譯模塊

為什么要編譯模塊?

因為LCD驅動相關的文件也沒有編進內核,而fb_ops里的成員fb_fillrect(), fb_copyarea(), fb_imageblit()用的都是drivers/video下面的3個文件,所以需要這3個的.ko模塊,如下圖所示:

 

3.掛載驅動

將編譯好的LCD驅動模塊 和drivers/video里的3個.ko模塊 放入nfs文件系統目錄中

然后燒寫內核, 先裝載3個/drivers/video下編譯好的模塊,再來裝載LCD驅動模塊

掛載LCD驅動后, 如下圖,可以通過  ls -l /dev/fb*   命令查看已掛載的LCD設備節點:

 

4.測試運行

測試有兩種: 

(echo和cat命令詳解入口地址: http://www.cnblogs.com/lifexy/p/7601122.html)

echo hello> /dev/tty1     // LCD上便顯示hello字段

cat Makefile>/dev/tty1    // LCD上便顯示Makeflie文件的內容

 

4.1使用上節的鍵盤驅動在LCD終端打印命令行

vi  /etc/inittab         //修改inittab, inittab:配置文件,用於啟動init進程時,讀取inittab

添加->tty1::askfirst:-/bin/sh   //將sh進程(命令行)輸出到tty1里,也就是使LCD輸出信息

然后重啟,insmod裝載3個/drivers/video下編譯好的模塊,再來insmod裝載LCD驅動模塊,tty1設備便有了,就能看到提示信息:

 

如下圖,我們insmod上一節的鍵盤驅動后,按下enter鍵,便能在LCD終端上操作linux了

(上一節的鍵盤驅動詳解入口地址: http://www.cnblogs.com/lifexy/p/7553861.html)

 

從上圖可以看到按下enter鍵,它就啟動了一個進程號772的-sh進程,如下圖發現這個-sh的描述符都指向了tty1:

 

 

以上內容轉載自16.Linux-LCD驅動(詳解)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM