程序员人生 网站导航

如何写分层驱动(复杂的字符驱动)----以lcd驱动为例

栏目:框架设计时间:2015-06-23 09:05:25

*********如何写分层驱动(复杂的字符驱动)----以lcd驱动为例**************


思路:复杂的驱动都是建立在简单的驱动的基础上,所以首先要知道内核简单字符装备驱动如何写
1.如何简单驱动程序
1.1 构造file_operations
.open = drv_open
.read = drv_read
1.2 告知内核有1.1这个结构,register_chrdev(主装备号,fop,name)
上面可以被下面3句话代替
分配cdev
设置cdev
cdev_add
1.3 入口函数:调用1.2的注册函数
1.4 出口函数:unregister_chrdev
2.复杂装备驱动程序:1.简单驱动程序框架+分层
第1层:和简单驱动程序框架类似,这里以fbmem.c为例
2.1. 构造file_operations 
open/read/write
2.2.register_chrdev
2.3.入口/出口
第2层:驱动层:硬件相干(具体驱动具体不同):3把斧
3.1. 分配1个fb_info结构体: framebuffer_alloc
3.2. 设置
3.3. 注册: register_framebuffer: 实质:register_framebuffer做的事:设置registered_fb数组的值

3.4. 硬件相干的操作


****************************************************************************************

整体架构:



分析fbmem.c
static const struct file_operations fb_fops = { // ------⑵.1
.owner = THIS_MODULE,
.read = fb_read,
.write = fb_write,
.ioctl = fb_ioctl,
.mmap = fb_mmap,
.open = fb_open,
.release = fb_release,
};

static int __init
fbmem_init(void)// -----⑵.3
{
create_proc_read_entry("fb", 0, NULL, fbmem_read_proc, NULL);


if (register_chrdev(FB_MAJOR,"fb",&fb_fops)) // ---------⑵.2
printk("unable to get major %d for fb devs ", FB_MAJOR);


fb_class = class_create(THIS_MODULE, "graphics"); // 注册装备类
if (IS_ERR(fb_class)) {
printk(KERN_WARNING "Unable to create fb class; errno = %ld ", PTR_ERR(fb_class));
fb_class = NULL;
}
return 0;
}

例子:具体分析:LCD驱动程序   // 要具体由app到内核到驱动分析才知道全部架构如何构成

  假定:
app:  open("/dev/fb0", ...)   主装备号: 29, 次装备号: 0
--------------------------------------------------------------
kernel:
fb_open // 第1层的通用代码作用:1.中转作用:判断参数和设置参数,成为子类的多态函数参数  2.提供通用的操作:如果子类没有覆盖调用该方法,则使用通用代码,实现多态
int fbidx = iminor(inode);    // 这个是register_framebuffer时候设置的,次装备号就是数组的下标
struct fb_info *info = = registered_fb[0];  // 获得3.3驱动注册的结构体
file->private_data = info;// 方法1:重新设置file的fop,设置成info里面提供的fop
// 方法2:不重新设置file的fop,根据次装备号获得驱动设置的fop,调用驱动提供的函数
if (info->fbops->fb_open) {
res = info->fbops->fb_open(info,1);
if (res)
module_put(info->fbops->owner);
}


app:  read()
---------------------------------------------------------------
kernel:
fb_read
int fbidx = iminor(inode);
struct fb_info *info = registered_fb[fbidx];// 同fb_open

if (!info || ! info->screen_base)// 中转作用:参数合法性判断
return -ENODEV;


if (info->state != FBINFO_STATE_RUNNING)
return -EPERM;



if (info->fbops->fb_read)// 多态:子类有自己实现,那末用子类函数
return info->fbops->fb_read(info, buf, count, ppos);

// 如果子类没有覆盖掉该方法则用基类提供通用方法
src = (u32 __iomem *) (info->screen_base + p);
dst = buffer;
*dst++ = fb_readl(src++);
copy_to_user(buf, buffer, c)        



附录:register_framebuffer分析
int
register_framebuffer(struct fb_info *fb_info)
{
int i;
struct fb_event event;
struct fb_videomode mode;


if (num_registered_fb == FB_MAX)
return -ENXIO;
num_registered_fb++;
// 1.算法:找到次装备号
for (i = 0 ; i < FB_MAX; i++)
if (!registered_fb[i])
break;
fb_info->node = i;


// 2.建立装备节点
fb_info->dev = device_create(fb_class, fb_info->device,//以该次装备号建立装备节点
MKDEV(FB_MAJOR, i), "fb%d", i);// 在app open的时候fb%d,就有次装备号就传递进来了
// 驱动可以利用该次装备号
if (IS_ERR(fb_info->dev)) {
/* Not fatal */
printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld ", i, PTR_ERR(fb_info->dev));
fb_info->dev = NULL;
} else
fb_init_device(fb_info);




return 0;
}



忠于梦想 勇于实践

------分隔线----------------------------
------分隔线----------------------------

最新技术推荐