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