分离分层
bus_drv_dev模型:
简单说明:
这张图就是全部了。
device是与硬件相关的代码,driver是比较稳定的驱动代码。
当修改硬件部分的时候,只修改dev里面的东西。
=============================================================================================================================
LED例子
下面用一个点亮LED的例子来说明这个分离的的例子:
这个驱动程序分为左右两边,即:dev 与 drv
在led_dev.中 分配,设置,注册一个platform_device
在led_drv中分配,设置,注册一个platform_driver
led_dev.c
定义这个平台设备的资源:
1. static struct resource led_resource[] = {
2. [0] = {
3. .start = 0x56000010,//GPFCON的物理地址
4. .end = 0x56000010 + 8 - 1,
5. .flags = IORESOURCE_MEM,
6. },
7. [1] = {
8. .start = 6,// F6引脚
9. .end = 6,
10. .flags = IORESOURCE_IRQ,
11. },
12. };
flags表示资源的类型。这里表示引脚
定义一个平台设备:
1. struct platform_device device_led = {
2. .name = "myled",
3. .id = -1,
4. .num_resources = ARRAY_SIZE(led_resource),
5. .resource = led_resource,
6. .dev={
7. .release = led_release,
8. },
9. };
在入口函数中 注册 这个 “平台设备”
1. static int led_dev_init(void)
2. {
3. platform_device_register(&device_led);
4. return 0;
5. }
出口函数是卸载这个平台设备
1. static void led_dev_exit(void)
2. {
3. platform_device_unregister(&device_led);
4. }
led_drv.c
定义一个平台driver
1. static struct platform_driver led_drv = {
2. .probe = led_probe,
3. .remove = led_remove,
4. .driver = {
5. .name = "myled",
6. }
7. };
这里需要注意的是这个平台的name和dev的平台设备的名字要一致。
如果平台设备和平台driver匹配的上,就会调用这个led_driver这个函数。
实现这个probe函数:
1. static int led_probe(struct platform_device *pdev)
2. {
3. return 0;
4. }
在这个函数中需要完成以下工作:
1. 注册字符设备
2. 根据platfor_device的资源进行ioremap
注册字符设备:
1. major = register_chrdev(0,"myled",&led_fops);
这里需要构造led_fops结构体:
1. static struct file_operations led_fops=
2. {
3. .owner = THIS_MODULE,//这个宏在推向编译模块时自动创建 __this_module变量
4. .open = led_open,
5. .write = led_write,
6. };
完成 open,write的功能函数
1. static int led_open(struct inode *inode,struct file *file)
2. {
3. //配置为输出引脚
4. *gpio_con &=~(0x3<<(pin*2));
5. *gpio_con |=(0x1<<(pin*2));
6.
7. return 0;
8. }
1. static ssize_t led_write(struct file *file,const char __user *buf,size_t count,loff_t *ppos)
2. {
3. int val;
4. copy_from_user(&val,buf,count);//从用户空间向内核空间拷贝数据
5. if(val == 1)
6. {
7. printk("val ==1");
8. *gpio_dat &=~(1<<pin);
9. }
10. else
11. {
12. printk("val ==0");
13. *gpio_dat|=(1<<pin);
14. }
15.
16. return 0;
17. }
但是这里需要注意 gpio_dat和gpio_con还没有定义,需要映射一下:
1. struct resource *res;
2. /*根据platform_device的资源进行ioremap*/
3. res = platform_get_resource(pdev,IORESOURCE_MEM,0);
4. gpio_con = ioremap(res->start,res->end - res->start + 1);
5. gpio_dat = gpio_con + 1;
6.
7. res = platform_get_resource(pdev,IORESOURCE_IRQ,0);
8. pin = res->start;
这部分功能就是刚才提到的 “2、根据platfor_device的资源进行ioremap ”
platform_get_resource(pdev,IORESOURCE_IRQ,0);
是获得pdev的第1个IORESOURCE_IRQ类型的资源。
另外还需要在probe函数中创建设备节点:
1. led_cls = class_create(THIS_MODULE,"myled");
2. if(IS_ERR(led_cls))
3. return PTR_ERR(led_cls);
4. led_class_dev = device_create(led_cls,NULL,MKDEV(major,0),NULL,"wq_led");
5. if(unlikely(IS_ERR(led_class_dev)))
6. return PTR_ERR(led_class_dev);
这样基本就完成了。