天天看点

linux驱动中的总线理解

 linux设备驱动归纳总结,觉得这里写的很好

http://blog.chinaunix.net/uid-25014876-id-59420.html

以下代码来自该博客用来理解linux驱动中的总线

-----------------------------------------------------------------------------

-----------------------------------------------------------------------------

总线、设备和驱动

linux驱动中的总线理解

总线、设备和驱动

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机制将设备本身的资源注册进内核,有内核统一管理,在驱动程序使用这些资源时使用统一的接口,这样提高了程序的可移植性。

linux驱动中的总线理解

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

[email protected]:/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");
           

继续阅读