日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

LINUX设备模型BUS,DEVICE,DRIVER

發布時間:2024/9/21 linux 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 LINUX设备模型BUS,DEVICE,DRIVER 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

雖然看了上面一篇轉載的《使用/sys/訪問系統》對總線,驅動,設備都講得比較細但還是沒有太多的感覺。在此就先把自己今天所學回憶一下。

為了滿足新的要求,linux2.6提供了新的設備模型:總線、驅動、設備。基本關系簡要的概括如下:
驅動核心可以注冊多種類型的總線。
每種總線下面可以掛載許多設備。(通過kset devices)
每種總線下可以用很多設備驅動。(通過包含一個kset drivers)}
每個驅動可以處理一組設備。按照我的理解就是所有的設備都掛載到總線上,當加載驅動時,驅動就支總線上找到自己對應的設備。或者先把驅動加載上,來了一個設備就去總線找驅動。

一:總線

  總線是處理器與設備之間通道,在設備模型中,所有的設備都通過總線相連

(1)bus_type.
struct bus_type {
?const char??* name;//設備名稱

struct bus_type {
?const char??* name;//設備名稱

?struct subsystem?subsys;//代表自身
?struct kset??drivers;?? //當前總線的設備驅動集合
?struct kset??devices;?//所有設備集合
?struct klist??klist_devices;
?struct klist??klist_drivers;

?struct bus_attribute?* bus_attrs;//總線屬性
?struct device_attribute?* dev_attrs;//設備屬性
?struct driver_attribute?* drv_attrs;

?int??(*match)(struct device * dev, struct device_driver * drv);//設備驅動匹配函數
?int??(*uevent)(struct device *dev, char **envp,???
????? int num_envp, char *buffer, int buffer_size);//熱拔插事件
?int??(*probe)(struct device * dev);
?int??(*remove)(struct device * dev);
?void??(*shutdown)(struct device * dev);
?int??(*suspend)(struct device * dev, pm_message_t state);
?int??(*resume)(struct device * dev);
};

在后面的實例當中用到了里面的兩個成員

1:const char *name;

2:?int??(*match)(struct device * dev, struct device_driver * drv);//設備驅動匹配函數

這個匹配函數是很關鍵的東西,這是建立總線上設備與驅動的橋梁,當一個新的設備或驅動被添加到一個總線上時被調用。

(2)總線的操作:

注冊:int bus_register(struct bus_type * bus)

注銷:void bus_unregister(struct bus_type *bus);

(3)總線屬性 bus_attribute

struct bus_attribute {
struct attribute attr;
ssize_t (*show)(struct bus_type *bus, char *buf);
ssize_t (*store)(struct bus_type *bus, const char *buf,
size_t count);
};
BUS_ATTR(name, mode, show, store);
這個宏聲明一個結構, 產生它的名子通過前綴字符串 bus_attr_ 到給定的名子.
任何屬于一個總線的屬性應當明確使用 bus_create_file 來創建:
int bus_create_file(struct bus_type *bus, struct bus_attribute *attr);?
屬性也可被去除, 使用:
void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr);?
lddbus 驅動創建一個簡單屬性文件, 再次, 包含源碼版本號. show 方法和 bus_attribute 結構設置如下:
static ssize_t show_bus_version(struct bus_type *bus, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", Version);
}
這個總線屬性現目前為止我還沒有發現它的作用。

(4)總線實例:

其實在這個程序中操作很簡單:

1:首先是要準備一個總線bus_type.也就是定義一個bus_type,然后給它填上一些成員。

定義如下:

struct bus_type my_bus_type = {
?.name = "my_bus",
?.match = my_match,
};

這里就對其兩個成員賦值了。一個是名稱。另一個則是匹配函數:

static int my_match(struct device *dev, struct device_driver *driver)
{
?return !strncmp(dev->bus_id, driver->name, strlen(driver->name));
}

這是匹配的邏輯則是設備的名字與驅動的名字一樣。

準備好了總線后就在模塊初始化函數中注冊:

??????? /*注冊總線*/
?ret = bus_register(&my_bus_type);
?if (ret)
??return ret;

然后在模塊退出函數中注解總線:

總線操作完后還要為總線創建屬性文件:

static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL);這句話就定義了一個總線屬性文件。BUS_ATTR宏的定義如下:

bus_unregister(&my_bus_type);

#define BUS_ATTR(_name, _mode, _show, _store)?\
struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store)

show_bus_version定義如下:

static ssize_t show_bus_version(struct bus_type *bus, char *buf)
{
?return snprintf(buf, PAGE_SIZE, "%s\n", Version);
}

定義好之后就是調用 函數創建文件

?/*創建屬性文件*/?
?if (bus_create_file(&my_bus_type, &bus_attr_version))
??printk(KERN_NOTICE "Fail to create version attribute!\n");

總線本身也是要對應一個設備的。還要為總線創建設備。

static void my_bus_release(struct device *dev)
{
?printk(KERN_DEBUG "my bus release\n");
}
?
struct device my_bus = {
?.bus_id?? = "my_bus0",
?.release? = my_bus_release
};

?/*注冊總線設備*/
?ret = device_register(&my_bus);
?if (ret)
??printk(KERN_NOTICE "Fail to register device:my_bus!\n");

可是這是有疑問,我還沒有找到這個總線設備,和剛才的總線的聯系。

源代碼:

#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>

MODULE_AUTHOR("David Xie");
MODULE_LICENSE("Dual BSD/GPL");

static char *Version = "$Revision: 1.9 $";

static int my_match(struct device *dev, struct device_driver *driver)
{
?return !strncmp(dev->bus_id, driver->name, strlen(driver->name));
}

static void my_bus_release(struct device *dev)
{
?printk(KERN_DEBUG "my bus release\n");
}
?
struct device my_bus = {
?.bus_id?? = "my_bus0",
?.release? = my_bus_release
};


struct bus_type my_bus_type = {
?.name = "my_bus",
?.match = my_match,
};

EXPORT_SYMBOL(my_bus);
EXPORT_SYMBOL(my_bus_type);


/*
?* Export a simple attribute.
?*/
static ssize_t show_bus_version(struct bus_type *bus, char *buf)
{
?return snprintf(buf, PAGE_SIZE, "%s\n", Version);
}

static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL);


static int __init my_bus_init(void)
{
?int ret;
????????
??????? /*注冊總線*/
?ret = bus_register(&my_bus_type);
?if (ret)
??return ret;
??
?/*創建屬性文件*/?
?if (bus_create_file(&my_bus_type, &bus_attr_version))
??printk(KERN_NOTICE "Fail to create version attribute!\n");
?
?/*注冊總線設備*/
?ret = device_register(&my_bus);
?if (ret)
??printk(KERN_NOTICE "Fail to register device:my_bus!\n");
??
?return ret;
}

static void my_bus_exit(void)
{
?device_unregister(&my_bus);
?bus_unregister(&my_bus_type);
}

module_init(my_bus_init);
module_exit(my_bus_exit);

二:設備:

1:device結構體

struct device {

struct device ?* parent; //父設備,一般一個bus也對應一個設備。
struct kobject kobj;//代表自身
char?bus_id[BUS_ID_SIZE];?
struct bus_type?* bus;??/*?所屬的總線 */
struct device_driver *driver;?/* 匹配的驅動*/

void??*driver_data;?/* data private to the driver?指向驅動?*/
?void??*platform_data;?/* Platform specific data,由驅動定義并使用*/

///更多字段忽略了

};

注冊設備:int device_register(sruct device *dev)

注銷設備:void device_unregister(struct device *dev);

2:設備屬性:

sysfs 中的設備入口可有屬性. 相關的結構是:
struct device_attribute {
struct attribute attr;
ssize_t (*show)(struct device *dev, char *buf);
ssize_t (*store)(struct device *dev, const char *buf,
size_t count);
};
這些屬性結構可在編譯時建立, 使用這些宏:
DEVICE_ATTR(name, mode, show, store);
結果結構通過前綴 dev_attr_ 到給定名子上來命名. 屬性文件的實際管理使用通常的函數對來處理:
int device_create_file(struct device *device, struct device_attribute *entry);
void device_remove_file(struct device *dev, struct device_attribute *attr);
struct bus_type 的 dev_attrs 成員指向一個缺省的屬性列表, 這些屬性給添加到總線的每個設備創建.

3:創建設備實例:

創建設備和創建總線基本一樣這里只貼出程序:

#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>

MODULE_AUTHOR("David Xie");
MODULE_LICENSE("Dual BSD/GPL");

extern struct device my_bus;?
extern struct bus_type my_bus_type;

/* Why need this ?*/
static void my_dev_release(struct device *dev)
{?
?
}

struct device my_dev = {
?.bus = &my_bus_type,//與總線接上關系?
?.parent = &my_bus,//與總線設備接上關系
?.release = my_dev_release,
};

/*
?* Export a simple attribute.
?*/
static ssize_t mydev_show(struct device *dev,struct device_attribute *attr, char *buf)
{
?return sprintf(buf, "%s\n", "This is my device!");
}

static DEVICE_ATTR(dev, S_IRUGO, mydev_show, NULL);

static int __init my_device_init(void)
{
?int ret = 0;
????????
??????? /* 初始化設備 */
?strncpy(my_dev.bus_id, "my_dev", BUS_ID_SIZE);
????????
??????? /*注冊設備*/
?device_register(&my_dev);
??
?/*創建屬性文件*/
?device_create_file(&my_dev, &dev_attr_dev);
?
?return ret;?

}

static void my_device_exit(void)
{
?device_unregister(&my_dev);
}

module_init(my_device_init);
module_exit(my_device_exit);

三:設備驅動:

在總線上掛載了設備后就要為其準備驅動程序。

驅動程序的實現與設備的實現類似,代碼如下:

#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>

MODULE_AUTHOR("David Xie");
MODULE_LICENSE("Dual BSD/GPL");

extern struct bus_type my_bus_type;

static int my_probe(struct device *dev)
{
??? printk("Driver found device which my driver can handle!\n");
??? return 0;
}

static int my_remove(struct device *dev)
{
??? printk("Driver found device unpluged!\n");
??? return 0;
}

struct device_driver my_driver = {
?.name = "my_dev",//對應的設備名稱
?.bus = &my_bus_type,//掛載的總線
?.probe = my_probe,//這個函數就是在找到與自己對應的設備時被調用。
??????? .remove?= my_remove,
};

/*
?* Export a simple attribute.
?*/
static ssize_t mydriver_show(struct device_driver *driver, char *buf)
{
?return sprintf(buf, "%s\n", "This is my driver!");
}

static DRIVER_ATTR(drv, S_IRUGO, mydriver_show, NULL);

static int __init my_driver_init(void)
{
?int ret = 0;
????????
??????? /*注冊驅動*/
?driver_register(&my_driver);
??
?/*創建屬性文件*/
?driver_create_file(&my_driver, &driver_attr_drv);
?
?return ret;?

}

static void my_driver_exit(void)
{
?driver_unregister(&my_driver);
}

module_init(my_driver_init);
module_exit(my_driver_exit);

總結

以上是生活随笔為你收集整理的LINUX设备模型BUS,DEVICE,DRIVER的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。