分离分层

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. };  


这里需要注意的是这个平台的namedev的平台设备的名字要一致。

如果平台设备和平台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. };  


完成 openwrite的功能函数

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_datgpio_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的第1IORESOURCE_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);  

 

这样基本就完成了。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值