linux lcd设备驱动剖析一

s3c2440 lcd驱动源码文件是:drivers/video/s3c2410fb.c

看驱动源码首先当然是先看入口函数,这里是s3c2410fb_init函数

[cpp]  view plain ?
  1. int __init s3c2410fb_init(void)  
  2. {  
  3.     /* 注册一个s3c2410fb_driver平台驱动 */  
  4.     int ret = platform_driver_register(&s3c2410fb_driver);  
  5.   
  6.     if (ret == 0)  
  7.         ret = platform_driver_register(&s3c2412fb_driver);;  
  8.   
  9.     return ret;  
  10. }  
出口函数,自然是注销s3c2410fb_driver平台驱动

[cpp]  view plain ?
  1. static void __exit s3c2410fb_cleanup(void)  
  2. {  
  3.     platform_driver_unregister(&s3c2410fb_driver);  
  4.     platform_driver_unregister(&s3c2412fb_driver);  
  5. }  
我们研究的是s3c2440,只关心s3c2410fb_driver,s3c2412fb_driver不用理会。

[cpp]  view plain ?
  1. static struct platform_driver s3c2410fb_driver = {  
  2.     .probe      = s3c2410fb_probe,  
  3.     .remove     = s3c2410fb_remove,  
  4.     .suspend    = s3c2410fb_suspend,  
  5.     .resume     = s3c2410fb_resume,  
  6.     .driver     = {  
  7.         .name   = "s3c2410-lcd",  
  8.         .owner  = THIS_MODULE,  
  9.     },  
  10. };  
这里看到s3c2410fb_driver的name字段为s3c2410-lcd。回顾这钱前面章节说过的知识,如果linux系统中存在同名的平台设备时,就会调用平台驱动的probe函数。这里,如果存在有同名"s3c2410-lcd"的平台设备,就会调用s3c2410fb_driver的s3c2410fb_probe函数。

在source  insight搜索s3c2410-lcd,很快就能搜索到arch/arm/plat-s3c24xx/devs.c中有那么一段

[cpp]  view plain ?
  1. struct platform_device s3c_device_lcd = {  
  2.     .name         = "s3c2410-lcd",  
  3.     .id       = -1,  
  4.     .num_resources    = ARRAY_SIZE(s3c_lcd_resource),  
  5.     .resource     = s3c_lcd_resource,  
  6.     .dev              = {  
  7.         .dma_mask       = &s3c_device_lcd_dmamask,  
  8.         .coherent_dma_mask  = 0xffffffffUL  
  9.     }  
  10. };  
  11.   
  12. EXPORT_SYMBOL(s3c_device_lcd);  
其中平台设备中比较重要的是成员是resource,这里是s3c_lcd_resource

[cpp]  view plain ?
  1. static struct resource s3c_lcd_resource[] = {  
  2.     [0] = {  
  3.         .start = S3C24XX_PA_LCD,                /* 0x4D000000 */  
  4.         .end   = S3C24XX_PA_LCD + S3C24XX_SZ_LCD - 1,  
  5.         .flags = IORESOURCE_MEM,  
  6.     },  
  7.     [1] = {  
  8.         .start = IRQ_LCD,                       /* IRQ = 32 */  
  9.         .end   = IRQ_LCD,  
  10.         .flags = IORESOURCE_IRQ,  
  11.     }  
  12.   
  13. };  
  14.   
  15. static u64 s3c_device_lcd_dmamask = 0xffffffffUL;  
那么接下来当然是要分析probe函数了

[cpp]  view plain ?
  1. static int __init s3c2410fb_probe(struct platform_device *pdev)  
  2. {  
  3.     return s3c24xxfb_probe(pdev, DRV_S3C2410);  
  4. }  
s3c2410fb_probe 函数调用s3c24xxfb_probe函数,这是lcd驱动的关键函数之一,留到"linux lcd设备驱动剖析二"再分析,但是在分析这个函数前,需要来熟悉一下几个结构体。

linux lcd驱动中有个关键词叫帧缓冲,它是linux为显示设备提供的一个接口,它允许应用程序在图形模式下直接对显示缓冲区进行读写操作,用户不必关心物理显示缓冲区的具体位置及存放方式,这些都由帧缓冲设备驱动本身来完成。

帧缓冲设备为标准字符设备,主设备号为29,对应/dev/fbn 设备文件,帧缓冲设备最关键的一个数据结构是fb_info结构体,它包括了关于帧缓冲设备属性和操作的完整描述。

[cpp]  view plain ?
  1. struct fb_info {  
  2.     int node;                       //用作次设备号索引  
  3.     int flags;  
  4.     struct mutex lock;              //用于open/release/ioctl函数的锁  
  5.     struct fb_var_screeninfo var;   //可变参数,重点  
  6.     struct fb_fix_screeninfo fix;   //固定参数,重点  
  7.     struct fb_monspecs monspecs;    //显示器标准  
  8.     struct work_struct queue;       //帧缓冲区队列  
  9.     struct fb_pixmap pixmap;        //图像硬件映射  
  10.     struct fb_pixmap sprite;        //光标硬件映射  
  11.     struct fb_cmap cmap;            //当前颜色表  
  12.     struct list_head modelist;      //模式链表  
  13.     struct fb_videomode *mode;      //当前video模式  
  14.   
  15.     char __iomem *screen_base;      //显存基地址  
  16.     unsigned long screen_size;      //显存大小  
  17.     void *pseudo_palette;           //伪16色颜色表  
  18. #define FBINFO_STATE_RUNNING    0  
  19. #define FBINFO_STATE_SUSPENDED  1  
  20.     u32 state;                      //硬件状态,如挂起  
  21.     void *fbcon_par;                //用作私有数据区  
  22.     void *par;                      //info->par指向了额外多申请内存空间的首地址  
  23. };  
s3c2410fb_info 结构体,这是s3c2410抽像出来的特有信息

[cpp]  view plain ?
  1. struct s3c2410fb_info {  
  2.     struct device       *dev;           //设备  
  3.     struct clk          *clk;           //时钟  
  4.   
  5.     struct resource     *mem;           //资源  
  6.     void __iomem        *io;            //IO地址  
  7.     void __iomem        *irq_base;      //IRQ基数  
  8.   
  9.     enum s3c_drv_type   drv_type;       //驱动类型,S3C2410或S3C2412  
  10.     struct s3c2410fb_hw regs;           //s3c2410 lcd硬件寄存器  
  11.   
  12.     unsigned int        palette_ready;  //调色板是否就绪标志位  
  13.   
  14.     /* keep these registers in case we need to re-write palette */  
  15.     u32         palette_buffer[256];    //调色板缓冲区  
  16.     u32         pseudo_pal[16];         //伪颜色表  
  17. };  
s3c2410fb_display 结构体,关于LCD参数的描述,如分辨率,LCD类型,BPP等等

[cpp]  view plain ?
  1. /* LCD description */  
  2. struct s3c2410fb_display {  
  3.     /* LCD type */  
  4.     unsigned type;  
  5.   
  6.     /* Screen size */  
  7.     unsigned short width;  
  8.     unsigned short height;  
  9.   
  10.     /* Screen info */  
  11.     unsigned short xres;  
  12.     unsigned short yres;  
  13.     unsigned short bpp;  
  14.   
  15.     unsigned pixclock;           /* pixclock in picoseconds */  
  16.     unsigned setclkval;          /* clkval */  
  17.     unsigned short left_margin;  /* value in pixels (TFT) or HCLKs (STN) */  
  18.     unsigned short right_margin; /* value in pixels (TFT) or HCLKs (STN) */  
  19.     unsigned short hsync_len;    /* value in pixels (TFT) or HCLKs (STN) */  
  20.     unsigned short upper_margin; /* value in lines (TFT) or 0 (STN) */  
  21.     unsigned short lower_margin; /* value in lines (TFT) or 0 (STN) */  
  22.     unsigned short vsync_len;    /* value in lines (TFT) or 0 (STN) */  
  23.   
  24.     /* lcd configuration registers */  
  25.     unsigned long   lcdcon5;  
  26. };  
对于TQ2440的液晶屏实例为tq2440_lcd_cfg,为方便查阅这里省略了其他分辨率的参数设置

[cpp]  view plain ?
  1. /* LCD driver info */  
  2. static struct s3c2410fb_display tq2440_lcd_cfg __initdata = {  
  3.     .lcdcon5    = S3C2410_LCDCON5_FRM565 |  
  4.               S3C2410_LCDCON5_INVVLINE |  
  5.               S3C2410_LCDCON5_INVVFRAME |  
  6.               S3C2410_LCDCON5_PWREN |  
  7.               S3C2410_LCDCON5_HWSWP,  
  8.     .type       = S3C2410_LCDCON1_TFT,  
  9.     /* TQ2440的液晶是4.3寸的,分辨率是480*272 */  
  10. #elif defined(CONFIG_FB_S3C24X0_TFT480272)  /* config_EmbedSky_W43:CONFIG_FB_S3C24X0_TFT480272=y */  
  11.     .width      = 480,  
  12.     .height     = 272,  
  13.   
  14.     .pixclock   = 40000,    /* HCLK 100 MHz, divisor 1 */  
  15.     .setclkval  = 0x4,  
  16.     .xres       = 480,  
  17.     .yres       = 272,  
  18.     .bpp        = 16,  
  19.     .left_margin    = 19,   /* for HFPD*/  
  20.     .right_margin   = 10,   /* for HBPD*/  
  21.     .hsync_len  = 30,       /* for HSPW*/  
  22.     .upper_margin   = 4,    /* for VFPD*/  
  23.     .lower_margin   = 2,    /* for VBPD*/  
  24.     .vsync_len  = 8,        /* for VSPW*/  
  25. };  
s3c2410fb_mach_info 结构体,它包括了s3c2410fb_display结构体

[cpp]  view plain ?
  1. struct s3c2410fb_mach_info {  
  2.     struct s3c2410fb_display *displays;     //s3c2410fb_display结构体  
  3.     unsigned num_displays;                  //displays的个数  
  4.     unsigned default_display;               //默认的default_display个数  
  5.   
  6.     /* GPIOs */  
  7.     unsigned long   gpcup;                  //GPC  
  8.     unsigned long   gpcup_mask;  
  9.     unsigned long   gpccon;  
  10.     unsigned long   gpccon_mask;  
  11.     unsigned long   gpdup;                  //GPD  
  12.     unsigned long   gpdup_mask;  
  13.     unsigned long   gpdcon;  
  14.     unsigned long   gpdcon_mask;  
  15.   
  16.     /* lpc3600 control register */  
  17.     unsigned long   lpcsel;  
  18. };  
要理解s3c24xxfb_probe函数,首先必须理清上面几个结构体之间的关系。

你可能感兴趣的:(linux lcd设备驱动剖析一)