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");
driver.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;
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");
Makefile文件为
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");
device.c
#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
将上面的的device和driver合在一起写,也可作为一种写驱动的模板。
#include <linux/module.h>
#include <linux/platform_device.h>
#ifdef CONFIG_PM
static int sensor_suspend(struct device *dev)
{
return 0;
}
static int sensor_resume(struct device *dev)
{
return 0;
}
static const struct dev_pm_ops sensor_ops = {
.suspend = sensor_suspend,
.resume = sensor_resume,
};
#endif
static int sensor_probe(struct platform_device *pdev)
{
return 0;
}
static int sensor_remove(struct platform_device *pdev)
{
return 0;
}
static struct platform_device sensor_devices =
{
.name = "sensor",
.id = 0,
};
static struct platform_driver sensor_driver =
{
.probe = sensor_probe,
.remove = sensor_remove,
.driver = {
.name = "sensor",
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &sensor_ops,
#endif
},
};
static int sensor_init(void)
{
platform_device_register(&sensor_devices);
platform_driver_register(&sensor_driver);
return 0;
}
static void __exit sensor_exit(void)
{
platform_device_unregister(&sensor_devices);
platform_driver_unregister(&sensor_driver);
}
module_init(sensor_init);
module_exit(sensor_exit);
MODULE_LICENSE("GPL");