驱动05.lcd设备驱动程序
参考s3c2410fb.c总结出框架
1.代码分析
1.1 入口函数
int __devinit s3c2410fb_init(void)
{
return platform_driver_register(&s3c2410fb_driver);
}
注册一个platform_driver结构体,如果存在同名的设备dev时,将调用probe函数。
static struct platform_driver s3c2410fb_driver = {
.probe = s3c2410fb_probe,
.remove = s3c2410fb_remove,
.suspend = s3c2410fb_suspend,
.resume = s3c2410fb_resume,
.driver = {
.name = "s3c2410-lcd", //如果存在有同名"s3c2410-lcd"的平台设备,就会调用s3c2410fb_driver的s3c2410fb_probe函数
.owner = THIS_MODULE,
},
}; //这是s3c2410fb_driver这个结构体的具体成员
搜索s3c2410-lcd可得下面的s3c_device_lcd结构体
struct platform_device s3c_device_lcd = {
.name = "s3c2410-lcd",
.id = -,
.num_resources = ARRAY_SIZE(s3c_lcd_resource),
.resource = s3c_lcd_resource, //最重要的部分
.dev = {
.dma_mask = &s3c_device_lcd_dmamask,
.coherent_dma_mask = 0xffffffffUL
}
};
1.2 probe函数(只列出关键性代码)
static int __init s3c2410fb_probe(struct platform_device *pdev)
{
struct s3c2410fb_info *info;
struct fb_info *fbinfo;
...... fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev);
if (!fbinfo) {
return -ENOMEM;
}
......
fbinfo->fix.type = FB_TYPE_PACKED_PIXELS;
fbinfo->fix.type_aux = ;
fbinfo->fix.xpanstep = ;
fbinfo->fix.ypanstep = ;
fbinfo->fix.ywrapstep = ;
fbinfo->fix.accel = FB_ACCEL_NONE; fbinfo->var.nonstd = ;
fbinfo->var.activate = FB_ACTIVATE_NOW;
fbinfo->var.height = mach_info->height;
fbinfo->var.width = mach_info->width;
fbinfo->var.accel_flags = ;
fbinfo->var.vmode = FB_VMODE_NONINTERLACED;
.......
ret = register_framebuffer(fbinfo);
return ; }
由此可知,其主要框架是
(1)分配一个fb_info结构体
(2)设置其参数
(3)注册这个结构体
(4)硬件相关的操作
1.3 fb_info结构体成员的了解
lcd为标准的帧缓冲设备,其主设备号为29,对应的设备为/dev/fb*
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指向了额外多申请内存空间的首地址
};
另外,fb_fix_screeninfo和fb_var_screeninfo也是两个比较重要的结构体,在设置fb_info结构体时会大量用到。
struct fb_fix_screeninfo {
char id[]; /* identification string eg "TT Builtin" */
unsigned long smem_start; /* Start of frame buffer mem */
/* (physical address) */
__u32 smem_len; /* Length of frame buffer mem */
__u32 type; /* see FB_TYPE_* */
__u32 type_aux; /* Interleave for interleaved Planes */
__u32 visual; /* see FB_VISUAL_* */
__u16 xpanstep; /* zero if no hardware panning */
__u16 ypanstep; /* zero if no hardware panning */
__u16 ywrapstep; /* zero if no hardware ywrap */
__u32 line_length; /* length of a line in bytes */
unsigned long mmio_start; /* Start of Memory Mapped I/O */
/* (physical address) */
__u32 mmio_len; /* Length of Memory Mapped I/O */
__u32 accel; /* Indicate to driver which */
/* specific chip/card we have */
__u16 reserved[]; /* Reserved for future compatibility */
};
struct fb_var_screeninfo {
__u32 xres; /* visible resolution */
__u32 yres;
__u32 xres_virtual; /* virtual resolution */
__u32 yres_virtual;
__u32 xoffset; /* offset from virtual to visible */
__u32 yoffset; /* resolution */ __u32 bits_per_pixel; /* guess what */
__u32 grayscale; /* != 0 Graylevels instead of colors */ struct fb_bitfield red; /* bitfield in fb mem if true color, */
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 */ __u32 activate; /* see FB_ACTIVATE_* */ __u32 height; /* height of picture in mm */
__u32 width; /* width of picture in mm */ __u32 accel_flags; /* (OBSOLETE) see fb_info.flags */ /* Timing: All values in pixclocks, except pixclock (of course) */
__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 */
__u32 vsync_len; /* length of vertical sync */
__u32 sync; /* see FB_SYNC_* */
__u32 vmode; /* see FB_VMODE_* */
__u32 rotate; /* angle we rotate counter clockwise */
__u32 reserved[]; /* Reserved for future compatibility */
};
1.4 fb_open函数
app: open("/dev/fb0"...) 主设备号:29 次设备号:0
-----------------------------------------------------------
kernel:
fb_open
int fbidx = iminor(inode)//获取次设备号
struct fb_info *info = registered_fb[fbidx]
1.5 fb_read函数
app: read()
------------------------------------------------------------
kernel:
fb_read
int fbidx = iminor(inode);
struct fb_info *info = registered_fb[fbidx];
if (info->fbops->fb_read)
return info->fbops->fb_read(info, buf, count, ppos);
src = (u32 __iomem *) (info->screen_base + p);
*dst++ = fb_readl(src++);
copy_to_user(buf, buffer, c)
1.6 registered_fb数组由谁来定义?
register_framebuffer
registered_fb[i] = fb_info
2 写代码
由1.2我们可以得知,代码的总体框架为:
(1)分配一个fb_info结构体
(2)设置其参数
(3)注册这个结构体
(4)硬件相关的操作
其实难点就在于第(2)步,主要是设置fb_info结构体的固定参数 fb_fix_screeninfo结构体和可变参数fb_var_screeninfo结构体,还有就是硬件相关
的设置,比如lcd时序参数的设置,也就是要设置lcdcon1~lcdcon5,lcdaddr1~lcdaddr3个寄存器。
2.2 源代码
#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> 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[];
unsigned long dithmode;
unsigned long tpal;
unsigned long lcdintpnd;
unsigned long lcdsrcpnd;
unsigned long lcdintmsk;
unsigned long tconsel;
}; static struct fb_info *s3c_lcd;
static volatile unsigned long *gpbcon;
static volatile unsigned long *gpbdat;
static volatile unsigned long *gpccon;
static volatile unsigned long *gpdcon;
static volatile unsigned long *gpgcon;
static u32 pseudo_palette[];
static volatile struct lcd_regs *lcd_regs; static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
{
chan &= 0xffff;
chan >>= - bf->length;
return chan << bf->offset;
} static int s3c_lcdfb_setcolreg(unsigned regno,
unsigned red, unsigned green, unsigned blue,
unsigned transp, struct fb_info *info)
{
unsigned int val; if (regno < )
{
// u32 *pal = fbi->fb->pseudo_palette;
val = chan_to_field(red, &info->var.red);
val |= chan_to_field(green, &info->var.green);
val |= chan_to_field(blue, &info->var.blue);
pseudo_palette[regno] = val;
}
else
return ; return ; } static struct fb_ops s3clcdfb_ops = {
.owner = THIS_MODULE,
.fb_setcolreg = s3c_lcdfb_setcolreg,//调色板
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
}; static int lcd_init(void)
{
int ret;
/*1.分配一个fb_info结构体*/
s3c_lcd = framebuffer_alloc(, NULL);
if (!s3c_lcd) {
return -ENOMEM;
} /*2.设置 */
strcpy(s3c_lcd->fix.id, "mylcd"); /*2.1设置固定数据fix*/
s3c_lcd->fix.smem_len = **/;
s3c_lcd->fix.type = FB_TYPE_PACKED_PIXELS;
s3c_lcd->fix.type_aux = ;
s3c_lcd->fix.visual = FB_VISUAL_TRUECOLOR;//TFT真彩色
s3c_lcd->fix.line_length = */;
// s3c_lcd->fix.smem_start /*2.2设置可变参数var*/
s3c_lcd->var.xres = ;
s3c_lcd->var.yres = ;
s3c_lcd->var.xres_virtual = ;
s3c_lcd->var.yres_virtual = ;
s3c_lcd->var.bits_per_pixel = ; /*RGB:565*/
s3c_lcd->var.red.offset= ;
s3c_lcd->var.red.length = ;
s3c_lcd->var.green.offset = ;
s3c_lcd->var.green.length = ;
s3c_lcd->var.blue.offset = ;
s3c_lcd->var.blue.length = ; s3c_lcd->var.activate = FB_ACTIVATE_NOW; s3c_lcd->fbops = &s3clcdfb_ops;
s3c_lcd->pseudo_palette = pseudo_palette;
s3c_lcd->screen_size = **/; /*3.硬件相关的操作*/
/*3.1GPIO的初始化*/
gpbcon = ioremap(0x56000010, );
gpbdat = gpbcon+;
gpccon = ioremap(0x56000020, );
gpdcon = ioremap(0x56000030, );
gpgcon = ioremap(0x56000060, ); *gpccon = 0xaaaaaaaa;
*gpdcon = 0xaaaaaaaa; *gpbcon &= ~();
*gpbcon |= ;
*gpbdat &= ~;//背光使能 *gpgcon |= (<<); //LCD 电源使能 /*3.2 设置LCD controller*/
lcd_regs = ioremap(0x4D000000,sizeof(struct lcd_regs)); lcd_regs->lcdcon1 = (<<) |(<<) |(0x0c<<);
//lcdcon1[0] Enable the video output and the LCD control signal lcd_regs->lcdcon2 = (<<) |(<<) |(<<) |(); lcd_regs->lcdcon3 = (<<) |(<<) |(); lcd_regs->lcdcon4 = ; lcd_regs->lcdcon5 = (<<) |(<<) |(<<) |(<<); /*3.3 设置显存的地址*/
s3c_lcd->screen_base = dma_alloc_writecombine(NULL,s3c_lcd->fix.smem_len,&s3c_lcd->fix.smem_start,GFP_KERNEL); lcd_regs->lcdsaddr1 = (s3c_lcd->fix.smem_start>>) & ~(<<);
lcd_regs->lcdsaddr2 = (s3c_lcd->fix.smem_start + s3c_lcd->fix.smem_len) & 0x1fffff;
lcd_regs->lcdsaddr3 = (*/);//行的长度 /*启动lcd*/ lcd_regs->lcdcon1 |= ();//使能LCD控制器
lcd_regs->lcdcon5 |= (<<);//使能LCD电源
*gpbdat |=; //使能背光 /*4.注册该结构体*/
ret = register_framebuffer(s3c_lcd);
if (ret < ) {
printk("Failed to register framebuffer device: %d\n", ret);
} return ;
} static int lcd_exit(void)
{
unregister_framebuffer(s3c_lcd);
lcd_regs->lcdcon1 &= ~;
lcd_regs->lcdcon5 &= ~(<<);
*gpbdat &= ~; dma_free_writecombine(NULL, s3c_lcd->fix.smem_len, s3c_lcd->screen_base, s3c_lcd->fix.smem_start);
iounmap(lcd_regs);
iounmap(gpbcon);
iounmap(gpccon);
iounmap(gpdcon);
iounmap(gpgcon); framebuffer_release(s3c_lcd);
return ;
} module_init(lcd_init);
module_exit(lcd_exit); MODULE_AUTHOR("lwd20170110"); MODULE_LICENSE("GPL");
lcd驱动程序
测试:
. make menuconfig去掉原来的驱动程序
-> Device Drivers
-> Graphics support
<M> S3C2410 LCD framebuffer support . make uImage
make modules . 使用新的uImage启动开发板: .
insmod cfbcopyarea.ko
insmod cfbfillrect.ko
insmod cfbimgblt.ko
insmod lcd.ko echo hello > /dev/tty1 // 可以在LCD上看见hello
cat lcd.ko > /dev/fb0 // 花屏 . 修改 /etc/inittab
tty1::askfirst:-/bin/sh
用新内核重启开发板 insmod cfbcopyarea.ko
insmod cfbfillrect.ko
insmod cfbimgblt.ko
insmod lcd.ko
insmod buttons.ko
2.3 待解决:1.出现段错误。2.用新内核启动后无法挂载nfs。
2017-01-10 16:12:27
驱动05.lcd设备驱动程序的更多相关文章
- LCD设备驱动程序
LCD是Liquid Crystal Display的简称,也就是经常所说的液晶显示器 LCD能够支持彩色图像的显示和视频的播放,是一种非常重要的输出设备 Framebuffer 是Linux系统 ...
- 驱动13.i2c设备驱动程序
1 分析i2c设备的识别过程i2c_add_driver i2c_register_driver driver->driver.bus = &i2c_bus_type ...
- linux设备驱动程序第四部分:从如何定位oops对代码的调试方法,驱动线
在一个我们谈到了如何编写一个简单的字符设备驱动程序,我们不是神,编写肯定会失败的代码,在这个过程中,我们需要继续写代码调试.在普通c应用.我们经常使用printf输出信息.或者使用gdb要调试程序,然 ...
- 嵌入式Linux驱动学习之路(二十一)字符设备驱动程序总结和块设备驱动程序的引入
字符设备驱动程序 应用程序是调用C库中的open read write等函数.而为了操作硬件,所以引入了驱动模块. 构建一个简单的驱动,有一下步骤. 1. 创建file_operations 2. 申 ...
- linux设备驱动程序该添加哪些头文件以及驱动常用头文件介绍(转)
原文链接:http://blog.chinaunix.net/uid-22609852-id-3506475.html 驱动常用头文件介绍 #include <linux/***.h> 是 ...
- 【转】linux设备驱动程序之简单字符设备驱动
原文网址:http://www.cnblogs.com/geneil/archive/2011/12/03/2272869.html 一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用 ...
- linux lcd设备驱动剖析四
在"linux lcd设备驱动剖析二"文章中,我们详细分析了s3c24xxfb_probe函数. 文章链接:http://blog.csdn.net/lwj103862095/ar ...
- linux lcd设备驱动剖析一
s3c2440 lcd驱动源码文件是:drivers/video/s3c2410fb.c 看驱动源码首先当然是先看入口函数,这里是s3c2410fb_init函数 [cpp] view plain? ...
- 【Linux 驱动】设备驱动程序再理解
学习设备驱动编程也有一段时间了,也写过了几个驱动程序,因此有对设备驱动程序有了一些新的理解和认识,总结一下.学习设备驱动编程也有一段时间了,也写过了几个驱动程序.因此有对设备驱动程序有了一些新的理解和 ...
随机推荐
- 基于Quqrtz.NET 做的任务调度管理工具
基于Quqrtz.NET 做的任务调度管理工具 国庆前,需求让我看了一下任务调度的数据表设计.和之前一样,有100多个字段,p1 ~ p100, 我说这是干嘛啊!按这写,写死去了! 然后在网上搜了一下 ...
- 读书笔记—CLR via C#章节3
这本书这几年零零散散读过两三遍了,作为经典书籍,应该重复读反复读,既然我现在开始写博了,我也准备把以前觉得经典的好书重读细读一遍,并且将笔记整理到博客中,好记性不如烂笔头,同时也在写的过程中也可以加深 ...
- 【转】Android 工程在4.0基础上混淆
Android现在对安全方面要求比较高了,我今天要做的对apk进行混淆,用所有的第三方工具都不能反编译,作者的知识产权得到保障了,是不是碉堡了. 一,首先说明我这是在4.0基础上进行的. 先看 ...
- 【转】Android官方下拉刷新控件 SwipeRefreshLayout
今天在Google+上看到了SwipeRefreshLayout这个名词,遂搜索了下,发现竟然是刚刚google更新sdk新增加的一个widget,于是赶紧抢先体验学习下. SwipeRefreshL ...
- JavaScript闭包小窥
众所周知,JavaScript没有块级作用域,只有函数作用域.那就意味着定义在函数中的参数和变量在函数外部是不可见的,而在一个函数内部任何位置定义的变量,在该函数内部任何地方都可见.这带来的好处是内部 ...
- 13个不可不知的ASP.NET MVC扩展点
13个不可不知的ASP.NET MVC扩展点 ASP.NET MVC设计的主要原则之一是可扩展性.处理管线(processing pipeline)上的所有(或大多数)东西都是可替换的.因此,如果您不 ...
- MIT Introduction to Computer Science and Programming (Lesson one )
MIT Introduction to Computer Science and Programming (Lesson one ) 这篇文是记载 MIT 计算机科学及编程导论 第一集 的笔记 Les ...
- SZU:A25 Favorite Number
Judge Info Memory Limit: 32768KB Case Time Limit: 10000MS Time Limit: 10000MS Judger: Number Only Ju ...
- Linq无聊练习系列7----Insert,delete,update,attach操作练习
/*********************Insert,delete,update,attach操作练习**********************************/ ...
- C++反汇编与逆向分析技术揭秘
C++反汇编-继承和多重继承 学无止尽,积土成山,积水成渊-<C++反汇编与逆向分析技术揭秘> 读书笔记 一.单类继承 在父类中声明为私有的成员,子类对象无法直接访问,但是在子类对象的 ...