linux lcd设备驱动剖析一
2014-01-12 20:43
344 查看
s3c2440 lcd驱动源码文件是:drivers/video/s3c2410fb.c
看驱动源码首先当然是先看入口函数,这里是s3c2410fb_init函数
出口函数,自然是注销s3c2410fb_driver平台驱动
我们研究的是s3c2440,只关心s3c2410fb_driver,s3c2412fb_driver不用理会。
这里看到s3c2410fb_driver的name字段为s3c2410-lcd。回顾这钱前面章节说过的知识,如果linux系统中存在同名的平台设备时,就会调用平台驱动的probe函数。这里,如果存在有同名"s3c2410-lcd"的平台设备,就会调用s3c2410fb_driver的s3c2410fb_probe函数。
在source insight搜索s3c2410-lcd,很快就能搜索到arch/arm/plat-s3c24xx/devs.c中有那么一段
其中平台设备中比较重要的是成员是resource,这里是s3c_lcd_resource
那么接下来当然是要分析probe函数了
linux lcd驱动中有个关键词叫帧缓冲,它是linux为显示设备提供的一个接口,它允许应用程序在图形模式下直接对显示缓冲区进行读写操作,用户不必关心物理显示缓冲区的具体位置及存放方式,这些都由帧缓冲设备驱动本身来完成。
帧缓冲设备为标准字符设备,主设备号为29,对应/dev/fbn 设备文件,帧缓冲设备最关键的一个数据结构是fb_info结构体,它包括了关于帧缓冲设备属性和操作的完整描述。
对于TQ2440的液晶屏实例为tq2440_lcd_cfg,为方便查阅这里省略了其他分辨率的参数设置
要理解s3c24xxfb_probe函数,首先必须理清上面几个结构体之间的关系。
看驱动源码首先当然是先看入口函数,这里是s3c2410fb_init函数
int __init s3c2410fb_init(void) { /* 注册一个s3c2410fb_driver平台驱动 */ int ret = platform_driver_register(&s3c2410fb_driver); if (ret == 0) ret = platform_driver_register(&s3c2412fb_driver);; return ret; }
出口函数,自然是注销s3c2410fb_driver平台驱动
static void __exit s3c2410fb_cleanup(void) { platform_driver_unregister(&s3c2410fb_driver); platform_driver_unregister(&s3c2412fb_driver); }
我们研究的是s3c2440,只关心s3c2410fb_driver,s3c2412fb_driver不用理会。
static struct platform_driver s3c2410fb_driver = { .probe = s3c2410fb_probe, .remove = s3c2410fb_remove, .suspend = s3c2410fb_suspend, .resume = s3c2410fb_resume, .driver = { .name = "s3c2410-lcd", .owner = THIS_MODULE, }, };
这里看到s3c2410fb_driver的name字段为s3c2410-lcd。回顾这钱前面章节说过的知识,如果linux系统中存在同名的平台设备时,就会调用平台驱动的probe函数。这里,如果存在有同名"s3c2410-lcd"的平台设备,就会调用s3c2410fb_driver的s3c2410fb_probe函数。
在source insight搜索s3c2410-lcd,很快就能搜索到arch/arm/plat-s3c24xx/devs.c中有那么一段
struct platform_device s3c_device_lcd = { .name = "s3c2410-lcd", .id = -1, .num_resources = ARRAY_SIZE(s3c_lcd_resource), .resource = s3c_lcd_resource, .dev = { .dma_mask = &s3c_device_lcd_dmamask, .coherent_dma_mask = 0xffffffffUL } }; EXPORT_SYMBOL(s3c_device_lcd);
其中平台设备中比较重要的是成员是resource,这里是s3c_lcd_resource
static struct resource s3c_lcd_resource[] = { [0] = { .start = S3C24XX_PA_LCD, /* 0x4D000000 */ .end = S3C24XX_PA_LCD + S3C24XX_SZ_LCD - 1, .flags = IORESOURCE_MEM, }, [1] = { .start = IRQ_LCD, /* IRQ = 32 */ .end = IRQ_LCD, .flags = IORESOURCE_IRQ, } }; static u64 s3c_device_lcd_dmamask = 0xffffffffUL;
那么接下来当然是要分析probe函数了
static int __init s3c2410fb_probe(struct platform_device *pdev) { return s3c24xxfb_probe(pdev, DRV_S3C2410); }s3c2410fb_probe函数调用s3c24xxfb_probe函数,这是lcd驱动的关键函数之一,留到"linux lcd设备驱动剖析二"再分析,但是在分析这个函数前,需要来熟悉一下几个结构体。
linux lcd驱动中有个关键词叫帧缓冲,它是linux为显示设备提供的一个接口,它允许应用程序在图形模式下直接对显示缓冲区进行读写操作,用户不必关心物理显示缓冲区的具体位置及存放方式,这些都由帧缓冲设备驱动本身来完成。
帧缓冲设备为标准字符设备,主设备号为29,对应/dev/fbn 设备文件,帧缓冲设备最关键的一个数据结构是fb_info结构体,它包括了关于帧缓冲设备属性和操作的完整描述。
struct fb_info { int node; //用作次设备号索引 int flags; struct mutex lock; //用于open/release/ioctl函数的锁 struct fb_var_screeninfo var; //可变参数,重点 struct fb_fix_screeninfo fix; //固定参数,重点 struct fb_monspecs monspecs; //显示器标准 struct work_struct queue; //帧缓冲区队列 struct fb_pixmap pixmap; //图像硬件映射 struct fb_pixmap sprite; //光标硬件映射 struct fb_cmap cmap; //当前颜色表 struct list_head modelist; //模式链表 struct fb_videomode *mode; //当前video模式 char __iomem *screen_base; //显存基地址 unsigned long screen_size; //显存大小 void *pseudo_palette; //伪16色颜色表 #define FBINFO_STATE_RUNNING 0 #define FBINFO_STATE_SUSPENDED 1 u32 state; //硬件状态,如挂起 void *fbcon_par; //用作私有数据区 void *par; //info->par指向了额外多申请内存空间的首地址 };s3c2410fb_info结构体,这是s3c2410抽像出来的特有信息
struct s3c2410fb_info { struct device *dev; //设备 struct clk *clk; //时钟 struct resource *mem; //资源 void __iomem *io; //IO地址 void __iomem *irq_base; //IRQ基数 enum s3c_drv_type drv_type; //驱动类型,S3C2410或S3C2412 struct s3c2410fb_hw regs; //s3c2410 lcd硬件寄存器 unsigned int palette_ready; //调色板是否就绪标志位 /* keep these registers in case we need to re-write palette */ u32 palette_buffer[256]; //调色板缓冲区 u32 pseudo_pal[16]; //伪颜色表 };s3c2410fb_display结构体,关于LCD参数的描述,如分辨率,LCD类型,BPP等等
/* LCD description */ struct s3c2410fb_display { /* LCD type */ unsigned type; /* Screen size */ unsigned short width; unsigned short height; /* Screen info */ unsigned short xres; unsigned short yres; unsigned short bpp; unsigned pixclock; /* pixclock in picoseconds */ unsigned setclkval; /* clkval */ unsigned short left_margin; /* value in pixels (TFT) or HCLKs (STN) */ unsigned short right_margin; /* value in pixels (TFT) or HCLKs (STN) */ unsigned short hsync_len; /* value in pixels (TFT) or HCLKs (STN) */ unsigned short upper_margin; /* value in lines (TFT) or 0 (STN) */ unsigned short lower_margin; /* value in lines (TFT) or 0 (STN) */ unsigned short vsync_len; /* value in lines (TFT) or 0 (STN) */ /* lcd configuration registers */ unsigned long lcdcon5; };
对于TQ2440的液晶屏实例为tq2440_lcd_cfg,为方便查阅这里省略了其他分辨率的参数设置
/* LCD driver info */ static struct s3c2410fb_display tq2440_lcd_cfg __initdata = { .lcdcon5 = S3C2410_LCDCON5_FRM565 | S3C2410_LCDCON5_INVVLINE | S3C2410_LCDCON5_INVVFRAME | S3C2410_LCDCON5_PWREN | S3C2410_LCDCON5_HWSWP, .type = S3C2410_LCDCON1_TFT, /* TQ2440的液晶是4.3寸的,分辨率是480*272 */ #elif defined(CONFIG_FB_S3C24X0_TFT480272) /* config_EmbedSky_W43:CONFIG_FB_S3C24X0_TFT480272=y */ .width = 480, .height = 272, .pixclock = 40000, /* HCLK 100 MHz, divisor 1 */ .setclkval = 0x4, .xres = 480, .yres = 272, .bpp = 16, .left_margin = 19, /* for HFPD*/ .right_margin = 10, /* for HBPD*/ .hsync_len = 30, /* for HSPW*/ .upper_margin = 4, /* for VFPD*/ .lower_margin = 2, /* for VBPD*/ .vsync_len = 8, /* for VSPW*/ };s3c2410fb_mach_info结构体,它包括了s3c2410fb_display结构体
struct s3c2410fb_mach_info { struct s3c2410fb_display *displays; //s3c2410fb_display结构体 unsigned num_displays; //displays的个数 unsigned default_display; //默认的default_display个数 /* GPIOs */ unsigned long gpcup; //GPC unsigned long gpcup_mask; unsigned long gpccon; unsigned long gpccon_mask; unsigned long gpdup; //GPD unsigned long gpdup_mask; unsigned long gpdcon; unsigned long gpdcon_mask; /* lpc3600 control register */ unsigned long lpcsel; };
要理解s3c24xxfb_probe函数,首先必须理清上面几个结构体之间的关系。
相关文章推荐
- Linux命令详解之shutdown
- Linux C SMTP POP3 极简陋邮件客户端
- linux密码忘记的方法
- Linux redhat下安装jdk-6u45-linux-x64.bin
- selinux及设置
- 随记:kickstart远程批量无人值守安装linux
- Linux中后缀名为ko、o、a、so、la的文件介绍
- Linux环境SVN命令行使用经验总结
- arm-linux-gcc compile the cross-platform mpich2 on ubuntu
- Linux下svn命令用法
- linux内核注释v0.11-超级块、inode索引节点和磁盘块(逻辑块)
- 2. Windows下Linux模拟器的卸载方法
- [Linux 命令]获取当前目录下某种格式文件个数
- 常用硬件驱动网址(linux)
- 2013 Linux领域年终盘点
- Linux 安装jdk-7u45-linux-x64.tar.gz
- Linux下软件安装方法总结
- linux mmap 详解
- linux修改用户名,登录界面无法登录问题解决
- centos6 安装chrome,wps