linux设备驱动归纳总结,觉得这里写的很好
http://blog.chinaunix.net/uid-25014876-id-59420.html
以下代码来自该博客用来理解linux驱动中的总线
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
总线、设备和驱动
bus.c
#include <linux/module.h> #include <linux/init.h> #include <linux/device.h> #include <linux/kernel.h> #define VER_SIZE 100 char Version[VER_SIZE] = "WWW V1.0"; static ssize_t show_bus_version(struct bus_type *bus, char *buf){ return snprintf(buf, VER_SIZE, "%s\n", Version); } static ssize_t store_bus_version(struct bus_type *bus, const char *buf, size_t count){ return snprintf(Version, VER_SIZE, "%s", buf); } static BUS_ATTR(version,0644,show_bus_version,store_bus_version); int usb_bus_match(struct device *dev, struct device_driver *drv){ if(!strncmp(dev_name(dev), drv->name,3)){ printk("match success\n"); //为了配对成功,设备的bus_id和驱动的name我都更改为 return 1; //usb_mouse,详细的可以查看device.c和driver.c }else{ printk("match failed\n"); return 0; } } struct bus_type usb_bus = { .name = "my_usb", //定义总线的名字为usb,注册成功后将在/sys/bus目录下看 .match = usb_bus_match, }; EXPORT_SYMBOL(usb_bus); static int __init usb_bus_init(void){ int ret; ret = bus_register(&usb_bus);//总线注册,必须检测返回值 if(ret){ goto bus_register_err; } ret=bus_create_file(&usb_bus,&bus_attr_version); if(ret){ printk("bus create failed!\n"); goto bus_create_file_err; } printk("usb bus init\n"); return 0; bus_create_file_err: printk("bus_create_file_err\n"); bus_unregister(&usb_bus); return ret; bus_register_err: printk("bus_register_err\n"); return ret; } static void __exit usb_bus_exit(void){ bus_unregister(&usb_bus); printk("usb bus bye!\n"); } module_init(usb_bus_init); module_exit(usb_bus_exit); MODULE_LICENSE("GPL");
device.c
#include <linux/module.h> #include <linux/init.h> #include <linux/device.h> #include <linux/kernel.h> #define VER_SIZE 100 extern struct bus_type usb_bus; void usb_dev_release(struct device *dev){ printk(" release\n"); } struct device usb_device = { .init_name = "usb2", .bus = &usb_bus, //指定该设备的总线,这样会在sys/bus/usb/device目录下有一个软连接 .release = usb_dev_release, //必须要都有release函数,不然卸载时会出错 }; char Version[VER_SIZE] = "WWW V1.0"; static ssize_t show_device_version(struct device *dev,struct device_attribute *attr, char *buf){ return snprintf(buf, VER_SIZE, "%s\n", Version); } static ssize_t store_device_version(struct device *dev,struct device_attribute *attr, const char *buf, size_t count){ return snprintf(Version, VER_SIZE, "%s", buf); } /*该宏会定义一个名叫dev_attr_version的device_attribute的结构,并且成员name设置 * 为version,文件权限mode设置为S_IRUGO|S_IWUGO,并设置show函数为 *show_device_version, ,stror函数为stroe_device_version*/ static DEVICE_ATTR(version,0644,show_device_version, store_device_version); static int __init usb_device_init(void){ int ret; /*设备注册,注册成功后在/sys/device目录下创建目录usb_device*/ ret = device_register(&usb_device); if(ret){ printk("device register failed!\n"); goto err1; } /*为设备添加属性,调用成功后在/sys/device/usb_device/目录下有一个version的 * 文件,权限为S_IRUGO|S_IWUGO,查看该文件时会调用函数show_device_version, * 修改时调用store_device_version。*/ ret = device_create_file(&usb_device, &dev_attr_version); if(ret){ printk("device creat file failed!\n"); goto err2; } printk("usb device init\n"); return 0; err2: device_unregister(&usb_device); err1: return ret; } static void __exit usb_device_exit(void){ device_remove_file(&usb_device, &dev_attr_version); device_unregister(&usb_device); printk("usb device bye!\n"); } module_init(usb_device_init); module_exit(usb_device_exit); MODULE_LICENSE("GPL");
#include <linux/module.h> #include <linux/init.h> #include <linux/device.h> #include <linux/kernel.h> #define VER_SIZE 100 extern struct bus_type usb_bus; int usb_driver_probe(struct device *dev){ printk("usb_driver_probe\n"); return 0; } int usb_driver_remove(struct device *dev){ printk("usb_driver_remove\n"); return 0; } struct device_driver usb_driver = { .name = "usb1", .bus = &usb_bus, .probe = usb_driver_probe, .remove = usb_driver_remove, }; char Version[VER_SIZE] = "WWW V1.0"; static ssize_t show_driver_version(struct device_driver *drv, char *buf){ return snprintf(buf, VER_SIZE, "%s\n", Version); } static ssize_t store_driver_version(struct device_driver *drv,const char *buf, size_t count){ return snprintf(Version, VER_SIZE, "%s", buf); } /*该宏会定义一个名叫driver_attr_version的driver_attribute的结构,并且成员 * name设置为version,文件权限mode设置为S_IRUGO|S_IWUGO,并设置show函数为 * show_driver_version,stror函数为stroe_driver_version*/ static DRIVER_ATTR(version,0644,show_driver_version, store_driver_version); static int __init usb_driver_init(void){ int ret; /*驱动注册,注册成功后在/sys/bus/usb/driver目录下创建目录usb_driver*/ ret = driver_register(&usb_driver); if(ret){ printk("driver register failed!\n"); goto err1; } /*为驱动添加属性,调用成功后在/sys/bus/usb/dirver目录下有一个version的 * 文件,权限为S_IRUGO|S_IWUGO,查看该文件时会调用函数show_driver_version,修改时 * 调用store_driver_version。*/ ret = driver_create_file(&usb_driver, &driver_attr_version); if(ret){ printk("driver creat file failed!\n"); goto err2; } printk("usb driver init\n"); return 0; err2: driver_unregister(&usb_driver); err1: return ret; } static void __exit usb_driver_exit(void){ driver_remove_file(&usb_driver, &driver_attr_version); driver_unregister(&usb_driver); printk("usb driver bye!\n"); } module_init(usb_driver_init); module_exit(usb_driver_exit); MODULE_LICENSE("GPL");
ifeq ($(KERNELRELEASE),) KERNELDIR ?= /usr/src/linux-headers-3.19.0-39-generic PWD :=$(shell pwd) modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules modules_install: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install clear: rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions modules.order Module.symvers .PHONY: modules modules_install clean else obj-m:= bus.o device.o driver.o endif
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
上面的例子中设备和驱动函数注册时,它们是自己指定所属的总线。但是,内核开发人员觉得,这样的方法不好,应该由总线来提供设备和驱动的注册函数。当设备和驱动需要注册到指定总线时,那就必须使用该总线为设备和驱动提供的注册函数。
bus.c
#include <linux/module.h> #include <linux/init.h> #include <linux/device.h> #include <linux/kernel.h> #include "bus.h" int usb_bus_match(struct device *dev, struct device_driver *drv){ /*使用container_of找出总线自己定义的结构体*/ struct usb_device *usb_dev = container_of(dev, struct usb_device, dev); struct usb_driver *usb_drv = container_of(drv, struct usb_driver, drv); /*配对函数判断驱动和设备的生产厂商编号和设备编号是否一致*/ if((usb_dev->VendorID == usb_drv->VendorID) &&(usb_dev->DeviceID == usb_drv->DeviceID)){ printk("match success\n"); return 1; }else{ printk("match failed\n"); return 0; } } struct bus_type usb_bus = { .name = "my_usb", //定义总线的名字为usb,注册成功后将在/sys/bus目录下看 .match =usb_bus_match, }; int usb_device_register(struct usb_device *usb_dev){ usb_dev->dev.bus = &usb_bus; //设备device的总线为usb_bus return device_register(&usb_dev->dev); //注册此device } void usb_device_unregister(struct usb_device *usb_dev) { device_unregister(&usb_dev->dev); } EXPORT_SYMBOL(usb_device_register); EXPORT_SYMBOL(usb_device_unregister); /*总线提供的驱动注册函数*/ int usb_driver_register(struct usb_driver *usb_drv){ usb_drv->drv.bus = &usb_bus; //设置driver的总线为usb_bus return driver_register(&usb_drv->drv); //注册此driver } void usb_driver_unregister(struct usb_driver *usb_drv){ driver_unregister(&usb_drv->drv); } EXPORT_SYMBOL(usb_driver_register); EXPORT_SYMBOL(usb_driver_unregister); static int __init usb_bus_init(void){ int ret; ret = bus_register(&usb_bus);//总线注册,必须检测返回值 if(ret){ printk("bus create failed!\n"); return ret; } printk("usb bus init\n"); return ret; } static void __exit usb_bus_exit(void){ bus_unregister(&usb_bus); printk("usb bus bye!\n"); } module_init(usb_bus_init); module_exit(usb_bus_exit); MODULE_LICENSE("GPL");
device.c
#include <linux/module.h> #include <linux/init.h> #include <linux/device.h> #include <linux/kernel.h> #include "bus.h" extern struct bus_type usb_bus; void usb_dev_release(struct device *dev){ printk("usb_dev_release\n"); } struct usb_device mouse_dev = { .VendorID = 0x1122, .DeviceID = 0x3344, .dev = { .init_name = "usb_mouse", .release = usb_dev_release, }, }; static int __init usb_device_init(void){ int ret; /*设备注册,注册成功后在/sys/device目录下创建目录usb_device*/ ret = usb_device_register(&mouse_dev); if(ret){ printk("device register failed!\n"); return ret; } printk("usb device init\n"); return ret; } static void __exit usb_device_exit(void){ usb_device_unregister(&mouse_dev); printk("usb device bye!\n"); } module_init(usb_device_init); module_exit(usb_device_exit); MODULE_LICENSE("GPL");
driver.c
#include <linux/module.h> #include <linux/init.h> #include <linux/device.h> #include <linux/kernel.h> #include "bus.h" int usb_driver_probe(struct device *dev){ printk("usb_driver_probe\n"); return 0; } int usb_driver_remove(struct device *dev){ printk("usb_driver_remove\n"); return 0; } struct usb_driver mouse_drv = { .VendorID = 0x1122, .DeviceID = 0x3344, .drv = { .name = "usb_mouse", //在/sys/中的驱动目录名字 .probe = usb_driver_probe, .remove = usb_driver_remove, }, }; static int __init usb_driver_init(void){ int ret; /*驱动注册,注册成功后在/sys/bus/usb/driver目录下创建目录usb_driver*/ ret = usb_driver_register(&mouse_drv); if(ret){ printk("driver register failed!\n"); return ret; } printk("usb driver init\n"); return ret; } static void __exit usb_driver_exit(void){ usb_driver_unregister(&mouse_drv); printk("usb driver bye!\n"); } module_init(usb_driver_init); module_exit(usb_driver_exit); MODULE_LICENSE("GPL");
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
一个现实的linux设备和驱动通常都需要挂接在一种总线上,比较常见的总线有USB、PCI总线等。但是,在嵌入式系统里面,SoC系统中集成的独立的外设控制器、挂接在SoC内存空间的外设却不依附与此类总线。基于这样的背景下,2.6内核加入了platform虚拟总线。platform机制将设备本身的资源注册进内核,有内核统一管理,在驱动程序使用这些资源时使用统一的接口,这样提高了程序的可移植性。
driver.c
/*通过platform_driver_register和struct platform_driver来注册平台类驱动*/ #include <linux/module.h> #include <linux/init.h> #include <linux/platform_device.h> void init_mouse(void){ printk("init usb mouse\n"); } int usb_driver_probe(struct platform_device *dev){ //查询特定设备是否存在,以及是否能够才操作该设备,然后再进行设备操作。 //check_mouse(); //自己假设一下检查设备 init_mouse(); //usb鼠标驱动的真正入口 return 0; } int usb_driver_remove(struct platform_device *dev){ printk("remove mouse driver\n"); return 0; } /*结构体中不需要指定总线的成员,交由usb_device_register来完成*/ struct platform_driver mouse_drv = { .probe = usb_driver_probe, .remove = usb_driver_remove, .driver = { .name = "plat_usb_mouse", //在/sys/中的驱动目录名字 }, }; static int __init usb_driver_init(void){ int ret; /*驱动注册,注册成功后在/sys/platform/usb/driver目录下创建目录 *plat_usb_mouse*/ ret = platform_driver_register(&mouse_drv); if(ret){ printk("driver register failed!\n"); return ret; } printk("usb driver init\n"); return 0; } static void __exit usb_driver_exit(void){ platform_driver_unregister(&mouse_drv); printk("usb driver bye!\n"); } module_init(usb_driver_init); module_exit(usb_driver_exit); MODULE_LICENSE("GPL");
#include <linux/module.h> #include <linux/init.h> #include <linux/platform_device.h> void usb_dev_release(struct device *dev){ printk("usb_dev_release\n"); } struct platform_device mouse_dev = { .name = "plat_usb_mouse", .id = -1, .dev = { .init_name = "usb_mouse", .release = usb_dev_release, }, }; static int __init usb_device_init(void) { int ret; ret = platform_device_register(&mouse_dev); if(ret){ printk("device register failed!\n"); return ret; } printk("usb device init\n"); return 0; } static void __exit usb_device_exit(void){ platform_device_unregister(&mouse_dev); printk("usb device bye!\n"); } module_init(usb_device_init); module_exit(usb_device_exit); MODULE_LICENSE("GPL");
insmod driver.ko
insmod device.ko
root@G470:/sys/bus/platform/drivers/plat_usb_mouse# ls -al
总用量 0
drwxr-xr-x 2 root root 0 1月 10 21:42 .
drwxr-xr-x 34 root root 0 1月 10 21:41 ..
--w------- 1 root root 4096 1月 10 21:41 bind
lrwxrwxrwx 1 root root 0 1月 10 21:41 module -> ../../../../module/driver
--w------- 1 root root 4096 1月 10 21:41 uevent
--w------- 1 root root 4096 1月 10 21:41 unbind
lrwxrwxrwx 1 root root 0 1月 10 21:43 usb_mouse -> ../../../../devices/platform/usb_mouse