linux驱动之分离分层的概念
来源:互联网 发布:淘宝中老年女装棉袄 编辑:程序博客网 时间:2024/06/11 12:10
bus_drv_dev模型:
简单说明:
这张图就是全部了。
device是与硬件相关的代码,driver是比较稳定的驱动代码。
当修改硬件部分的时候,只修改dev里面的东西。
=============================================================================================================================
LED例子
下面用一个点亮LED的例子来说明这个分离的的例子:
这个驱动程序分为左右两边,即:dev 与 drv
在led_dev.中 分配,设置,注册一个platform_device
在led_drv中分配,设置,注册一个platform_driver
led_dev.c
定义这个平台设备的资源:
static struct resource led_resource[] = { [0] = { .start= 0x56000010,//GPFCON的物理地址 .end= 0x56000010 + 8 - 1, .flags= IORESOURCE_MEM, }, [1] = { .start= 6,// F6引脚 .end= 6, .flags= IORESOURCE_IRQ, },};
flags表示资源的类型。这里表示引脚
定义一个平台设备:
struct platform_device device_led = { .name= "myled", .id= -1, .num_resources= ARRAY_SIZE(led_resource), .resource= led_resource,.dev={.release = led_release, },};
在入口函数中 注册 这个 “平台设备”
static int led_dev_init(void){platform_device_register(&device_led);return 0;}
出口函数是卸载这个平台设备
static void led_dev_exit(void){platform_device_unregister(&device_led);}
led_drv.c
定义一个平台driver
static struct platform_driver led_drv = {.probe= led_probe,.remove= led_remove,.driver= {.name= "myled",}};
这里需要注意的是这个平台的name和dev的平台设备的名字要一致。
如果平台设备和平台driver匹配的上,就会调用这个led_driver这个函数。
实现这个probe函数:
static int led_probe(struct platform_device *pdev){return 0;}
在这个函数中需要完成以下工作:
- 注册字符设备
- 根据platfor_device的资源进行ioremap
注册字符设备:
major = register_chrdev(0,"myled",&led_fops);
这里需要构造led_fops结构体:
static struct file_operations led_fops={.owner = THIS_MODULE,//这个宏在推向编译模块时自动创建 __this_module变量.open = led_open,.write = led_write,};
完成 open,write的功能函数
static int led_open(struct inode *inode,struct file *file){//配置为输出引脚*gpio_con &=~(0x3<<(pin*2));*gpio_con |=(0x1<<(pin*2));return 0;}
static ssize_t led_write(struct file *file,const char __user *buf,size_t count,loff_t *ppos){int val;copy_from_user(&val,buf,count);//从用户空间向内核空间拷贝数据if(val == 1){printk("val ==1");*gpio_dat &=~(1<<pin);}else{printk("val ==0");*gpio_dat|=(1<<pin);}return 0;}
这两个函数在前面的博文中多次提到。但是这里需要注意 gpio_dat和gpio_con还没有定义,需要映射一下:
struct resource *res;/*根据platform_device的资源进行ioremap*/res = platform_get_resource(pdev,IORESOURCE_MEM,0);gpio_con = ioremap(res->start,res->end - res->start + 1);gpio_dat = gpio_con + 1;res = platform_get_resource(pdev,IORESOURCE_IRQ,0);pin = res->start;
这部分功能就是刚才提到的 “2、根据platfor_device的资源进行ioremap ”
platform_get_resource(pdev,IORESOURCE_IRQ,0);
是获得pdev的第1个IORESOURCE_IRQ类型的资源。
另外还需要在probe函数中创建设备节点:
led_cls = class_create(THIS_MODULE,"myled");if(IS_ERR(led_cls))return PTR_ERR(led_cls);led_class_dev = device_create(led_cls,NULL,MKDEV(major,0),NULL,"wq_led");if(unlikely(IS_ERR(led_class_dev)))return PTR_ERR(led_class_dev);
这样基本就完成了。
完整的led _dev.c
#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/interrupt.h>#include <linux/list.h>#include <linux/timer.h>#include <linux/init.h>#include <linux/serial_core.h>#include <linux/platform_device.h>#include <linux/io.h>/*分配/设置/注册一个platform_device*//*这个平台设备的资源*/static struct resource led_resource[] = { [0] = { .start= 0x56000010, .end= 0x56000010 + 8 - 1, .flags= IORESOURCE_MEM, }, [1] = { .start= 6, .end= 6, .flags= IORESOURCE_IRQ, },};static void led_release(struct device *dev){}struct platform_device device_led = { .name= "myled", .id= -1, .num_resources= ARRAY_SIZE(led_resource), .resource= led_resource,.dev={.release = led_release, },};static int led_dev_init(void){platform_device_register(&device_led);return 0;}static void led_dev_exit(void){platform_device_unregister(&device_led);}module_init(led_dev_init);module_exit(led_dev_exit);MODULE_LICENSE("GPL");
完整的led_drv.c
/*分配/设置/注册一个platform_driver*/#include <linux/module.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/interrupt.h>#include <linux/irq.h>#include <linux/sched.h>#include <linux/pm.h>#include <linux/sysctl.h>#include <linux/proc_fs.h>#include <linux/delay.h>#include <linux/platform_device.h>#include <linux/input.h>#include <linux/irq.h>#include <linux/cdev.h>#include <asm/uaccess.h>#include <asm/io.h>static int major;static volatile unsigned long *gpio_con;static volatile unsigned long *gpio_dat;static struct class *led_cls;//设备类static struct class_devices *led_class_dev;//设备static int pin;static int led_open(struct inode *inode,struct file *file){//配置为输出引脚*gpio_con &=~(0x3<<(pin*2));*gpio_con |=(0x1<<(pin*2));return 0;}static ssize_t led_write(struct file *file,const char __user *buf,size_t count,loff_t *ppos){int val;copy_from_user(&val,buf,count);//从用户空间向内核空间拷贝数据if(val == 1){printk("val ==1");*gpio_dat &=~(1<<pin);}else{printk("val ==0");*gpio_dat|=(1<<pin);}return 0;}static struct file_operations led_fops={.owner = THIS_MODULE,//这个宏在推向编译模块时自动创建 __this_module变量.open = led_open,.write = led_write,};static int led_probe(struct platform_device *pdev){struct resource *res;/*根据platform_device的资源进行ioremap*/res = platform_get_resource(pdev,IORESOURCE_MEM,0);gpio_con = ioremap(res->start,res->end - res->start + 1);gpio_dat = gpio_con + 1;res = platform_get_resource(pdev,IORESOURCE_IRQ,0);pin = res->start;/*注册字符设备驱动*/printk("led_probe found led \n");major = register_chrdev(0,"myled",&led_fops);led_cls = class_create(THIS_MODULE,"myled");if(IS_ERR(led_cls))return PTR_ERR(led_cls);led_class_dev = device_create(led_cls,NULL,MKDEV(major,0),NULL,"wq_led");if(unlikely(IS_ERR(led_class_dev)))return PTR_ERR(led_class_dev);return 0;}static int led_remove(struct platform_device *pdev){/*卸载字符设备驱动*/device_unregister(led_class_dev);class_destroy(led_cls);unregister_chrdev(major,"myled");iounmap(gpio_con);/*根据platform_device的资源进行iounmap*/return 0;}static struct platform_driver led_drv = {.probe= led_probe,.remove= led_remove,.driver= {.name= "myled",}};static int led_drv_init(void){platform_driver_register(&led_drv);return 0;}static void led_drv_exit(void){platform_driver_unregister(&led_drv);}module_init(led_drv_init);module_exit(led_drv_exit);MODULE_LICENSE("GPL");
测试程序:
#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdio.h>/*wq_led on 打开 *wq_led off 关闭 */int main(int argc, char **argv){int fd;int val = 1;fd = open("/dev/wq_led",O_RDWR);if(fd < 0){printf("can't open \n");}if(argc != 2){printf("Usage :\n");printf("%s <on|off>\n",argv[0]);return 0;}if(strcmp(argv[1],"on") == 0){val =1;}else{val =0;}write(fd,&val,4);return 0;}
1 0
- linux驱动之分离分层的概念
- Linux驱动之分离分层的概念
- 嵌入式linux之分离分层概念,总线驱动设备模型
- 《Linux驱动》分层分离
- 分层驱动的概念
- 6410之驱动程序的分层分离,总线设备驱动模型
- 嵌入式Linux设备驱动开发思想进阶之驱动分层与驱动分离
- Linux设备驱动模型--分离分层思想
- 驱动分层的概念--转
- 驱动程序分层分离概念_总线驱动设备模型
- 分层分离的总线驱动模型分析
- 驱动分离分层
- 嵌入式--驱动分离分层
- Linux驱动开发十一:分层分离LED子系统
- Linux下驱动:分层、分离机制学习笔记
- 驱动的分层和主机外设分离思想
- Linux 设备驱动开发思想 —— 驱动分层与驱动分离
- Linux 设备驱动开发思想 —— 驱动分层与驱动分离
- 10个有用的php代码实例
- Text Kit学习(入门和进阶)
- Android实现多个跑马灯效果,多个文本框TextView的跑马灯
- java参数传递(超经典)
- django cpu监控之六-----使用COM组件获取CPU数据
- linux驱动之分离分层的概念
- 搭pl/proxy集群
- Android布局优化
- vs2012 boost库安装配置
- 大陆下载android 源码
- C++ 结构体(四)
- CSS盒子模型
- MATLAB矩阵操作大全
- CentOS6.4配置Hadoop-2.6.0集群配置安装指南(经过实战演练)【张振华.Jack】