天天看點

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");
           

繼續閱讀