目录
一linux环境变量,设备驱动模型1.Linux设备驱动模型的来历
首先回顾设备驱动编撰的通常流程
【1】实现入口函数module_init()和模块卸载函数module_exit();
【2】申请设备号,register_chrdev();----->(与内核相关)
【3】利用udev/mdev机制创建设备文件结点class_create(),device_create();------>(与内核相关)
【4】硬件初始化:1.io资源映射ioremap(),内核提供gpio库函数;2.注册中断。------->(与硬件相关)
【5】构建file_operation结构体-------->(与内核相关)
【6】实现操作硬件的方式xxx_open(),xxx_write()…
推论:整个流程不仅第四部份与硬件有关,其他都是相像的操作方式,为了便捷的(不重复造轮子)编撰设备驱动,节约人力,所以提出了设备驱动模型,简化了设备驱动编撰的流程。
2.设备驱动模型框架
可以通过sysfs虚拟文件系统查看总线对象(以usb为例)
二linux驱动编程,BUS总线模型编程
概念图
1.总线对象
【1】structbus_type:总线对象linux培训机构,描述一个总线,管理device和driverlinux驱动编程,完匹配。
struct bus_type {//只列举重要成员 const char *name; //总线名字 int (*match)(struct device *dev, struct device_driver *drv);//匹配方法 };
【2】注册和注销总线
int bus_register(struct bus_type *bus); void bus_unregister(struct bus_type *bus);
【3】构建一个总线
#include #include #include //实例化一个bus对象 struct bus_type mybus = { .name = "mybus", .match = mybus_match, }; EXPORT_SYMBOL(mybus); //导出总线对象,让device对象和driver对象使用 static int __init mybus_init(void) { printk("------%s---------n",__FUNCTION__); int ret; //构建一个总线结果:/sys/bus/mybus ret = bus_register(&mybus); if(ret != 0) { printk("bus_register errorn"); return ret; } return 0; } static void __exit mybus_exit(void) { printk("------%s---------n",__FUNCTION__); bus_unregister(&mybus); } module_init(mybus_init); module_exit(mybus_exit); MODULE_LICENSE("GPL");
2.device对象
【1】device对象:设备对象,描述设备信息,包括地址,中断等其他数据
struct device {//只列举重要成员 struct kobject kobj; //所有对象的父类 const char *init_name;//在/sys/bus/mybus/device的名字,用于在总线中匹配 struct bus_type *bus; //指向该device对象依附的总线对象 void *platform_data; //自定义的数据,指向任何类型的数据 };
【2】注册和注销总线
int device_register(struct device *dev); void device_unregister(struct device *dev);
【3】编写设备对象
定义一个描述设备的信息的结构体,匹配成功以后让driver对象在总线中领到device对象的信息,实现分离。
#include #include #include extern struct bus_type mybus; struct mydev_desc{ char* name; int irqno; unsigned long addr; }; struct mydev_desc deviofo = { .name = "hqs", .irqno = 8877, .addr = 0x12345678, }; void mydev_release(struct device* dev) { printk("------%s---------n",__FUNCTION__); } //构建一个device对象 struct device mydev = { .init_name = "fsdev_drv", .bus = &mybus, .release = mydev_release, .platform_data = &deviofo, }; static int __init mydev_init(void) { printk("------%s---------n",__FUNCTION__); int ret; //将device注册到总线中 ret = device_register(&mydev); if(ret < 0) { printk("device_register errorn"); return ret; } return 0; } static void __exit mydev_exit(void) { printk("------%s---------n",__FUNCTION__); device_unregister(&mydev); } module_init(mydev_init); module_exit(mydev_exit); MODULE_LICENSE("GPL");
3.driver对象
【1】driver对象:描述设备驱动发的方式
struct device_driver {//只列举重要成员 const char *name;//在/sys/bus/mybus/driver的名字,用于在总线中匹配 struct bus_type *bus;//指向该device对象依附的总线对象 int (*probe) (struct device *dev); //device和driver匹配之后要做的事情 int (*remove) (struct device *dev); //device和driver分离之后要做的事情 };
【2】注册和注销总线
int driver_register(struct device_driver *drv); void driver_unregister(struct device_driver *drv);
【3】编写driver对象
匹配成功以后可以在总线中领到device对象的数据,具体实现在probe函数里。
#include #include #include #include extern struct bus_type mybus; struct mydev_desc{ char* name; int irqno; unsigned long addr; }; struct mydev_desc* pdesc; int mydrv_probe(struct device *dev) { printk("------%s---------n",__FUNCTION__); pdesc = (struct mydev_desc*)dev->platform_data; printk("name =%sn",pdesc->name); printk("irqno = %dn",pdesc->irqno); unsigned long * paddr = ioremap(pdesc->addr, 8); return 0; } int mydrv_remove (struct device *dev) { printk("------%s---------n",__FUNCTION__); return 0; } //构建一个driver对象 struct device_driver mydrv = { .name = "fsdev_drv", .bus = &mybus, .probe = mydrv_probe, .remove = mydrv_remove, }; static int __init mydrv_init(void) { printk("------%s---------n",__FUNCTION__); int ret; //将device注册到总线中 ret = driver_register(&mydrv); if(ret < 0) { printk("driver_register errorn"); return ret; } return 0; } static void __exit mydrv_exit(void) { printk("------%s---------n",__FUNCTION__); driver_unregister(&mydrv); } module_init(mydrv_init); module_exit(mydrv_exit); MODULE_LICENSE("GPL");
4.device对象和driver对象匹配
【1】实现BUS对象中的match方式(按device对象的名子和driver对象中的名子相匹配)
要注意的是不能直接用device对象中的init_name,而要用device对象中继承的structkobjectkobj;上面的成员name不然会报错
int mybus_match(struct device *dev, struct device_driver *drv) { //如果匹配成功,match方法一定要返回一个1,失败返回0 if(! strncmp(drv->name,dev->kobj.name,strlen(drv->name))) { printk("match okn"); return 1; } else { printk("match failedn"); return 0; } return 0; } //实例化一个bus对象 struct bus_type mybus = { .name = "mybus", .match = mybus_match, };
【2】保证device对象和driver对象的名子一样:例如这儿都使用"fsdev_drv"才能保证能匹配成功
//构建一个device对象 struct device mydev = { .init_name = "fsdev_drv", .bus = &mybus, .release = mydev_release, .platform_data = &deviofo, };
//构建一个driver对象 struct device_driver mydrv = { .name = "fsdev_drv", .bus = &mybus, .probe = mydrv_probe, .remove = mydrv_remove, };
以上就是Linux设备驱动模型的详细内容,更多请关注CTO智库其它相关文章!