linux笔记6

linux设备模型bus,device,driver
作者 codercjg10 十一月 2015, 2:43 下午

linux2.6提供了新的设备模型:总线、驱动、设备。基本关系简要的概括如下:
驱动核心可以注册多种类型的总线。
每种总线下面可以挂载许多设备。(通过kset devices)
每种总线下可以用很多设备驱动。(通过包含一个kset drivers)}
每个驱动可以处理一组设备。按照我的理解就是所有的设备都挂载到总线上,当加载驱动时,驱动就支总线上找到自己对应的设备。或者先把驱动加载上,来了一个设备就去总线找驱动。
一:总线
总线是处理器与设备之间通道,在设备模型中,所有的设备都通过总线相连。
关于总线的一些结构体:bus_type,
(1)bus_type:
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_attr_name),然后利用bus_create_file来创建总线属性
int bus_create_file(struct bus_type *bus, struct bus_attribute *attr);
参数中的attr,即为bus_attr_name。
另外, 就是参数中的 show 方法,设置方法如下
static ssize_t show_bus_version(struct bus_type *bus, char *buf) {
return snprintf(buf, PAGE_SIZE, “%s\n”, Version);
}
总线属性的删除, 使用:
void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr);
(4)总线实例:
1:首先是要准备一个总线bus_type.也就是定义一个bus_type,然后给它填上一些成员。定义如下:
struct bus_type my_bus_type = {
.name = “my_bus”,
.match = my_match,
};
这里就对其两个成员赋值了。一个是名称。另一个则是匹配函数:
2,总线本身也是要对应一个设备的。还要为总线创建设备。
struct device my_bus = {
.bus_id = “my_bus0″,
.release = my_bus_release
};
源代码:

include <linux/module.h>

include <linux/kernel.h>

include <linux/init.h>

include <linux/device.h>

include <linux/string.h>

static char *version = “version 1.0″;
//用于判断指定的驱动程序是否能处理指定的设备。
static int my_match(struct device *dev, struct device_driver *driver) {
return !strncmp(dev->bus_id, driver->name, strlen(driver->name));
}
static int my_bus_release(struct device *dev) {
return 0;
}
static ssize_t show_bus_version(struct bus_type *bus, char buf) {
return sprintf(buf, PAGE_SIZE, “%s\n”, version);
}
static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL);
struct device my_bus = {//定义总线设备
.bus_id = “my_bus0″,
.release = my_bus_release,
};
EXPORT_SYMBOL(my_bus);
struct bus_type my_bus_type = { //定义总线类型
.name = “my_bus”,
.match = my_match,
};
EXPORT_SYMBOL(my_bus_type);
static int __init my_bus_init(void){
int ret;
ret = bus_register(&my_bus_type);//注册总线
if(ret)
printk(“bus_register failed!\n”);
if(bus_create_file(&my_bus_type, &bus_attr_version))//创建总线属性
printk(“Creat bus failed!\n”);
ret = device_register(&my_bus);//注册总线设备
if (ret)
printk(“device_register failed!\n”);
return ret;
}
static void __exit my_bus_exit(void) {
bus_unregister(&my_bus_type);//删除总线属性
device_unregister(&my_bus);//删除总线设备
}
module_init(my_bus_init);
module_exit(my_bus_exit);
MODULE_AUTHOR(“Fany”);
MODULE_LICENSE(“GPL”);
(5)测试
将bus.c以动态加载的方式加载到内核,insmod bus.ko,在/sys/bus/目录下会有一个my_bus目录,这就是我们添加的总线。该目录下有devices,drivers目录,因为该总线上没有挂载任何设备和驱动,所以这两个目录都为空;同时,在/sy/devices目录下,还可看到my_bus0设备(总线本身也是一种设备)。
二:设备:
关于设备的一些常用结构体:device,
1:
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);
3:创建设备实例:

include <linux/module.h>

include <linux/kernel.h>

include <linux/init.h>

include <linux/device.h>

include <linux/string.h>

extern struct device my_bus; //这里用到了总线设备中定义的结构体
extern struct bus_type my_bus_type;
static int my_device_release() {
return 0;
}
struct device my_dev={ //创建设备属性
.bus = &my_bus_type,//定义总线类型
.parent = &my_bus,//定义my_dev的父设备。
.release = my_device_release,
};
static ssize_t mydev_show(struct device dev, 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;
strncpy(my_dev.bus_id, “my_dev”, BUS_ID_SIZE); //初始化设备
ret = device_register(&my_dev); //注册设备
if (ret)
printk(“device register!\n”);
device_create_file(&my_dev, &dev_attr_dev); //创建设备文件
return ret;
}
static void __exit my_device_exit(void) {
device_unregister(&my_dev);//卸载设备
}
module_init(my_device_init);
module_exit(my_device_exit);
MODULE_AUTHOR(“Fany”);
MODULE_LICENSE(“GPL”);
4:测试
将设备device.c,编译成模块,以动态加载的方式加载到内核。会发现在sys/bus/my_bus/devices/目录下有一个my_dev设备,查看属性,它是挂在/sys/devices/my_bus0/my_dev目录下,至此添加设备成功。
三:设备驱动:
1:关于驱动的常用结构体:device_driver
struct device_driver {
const char name; /驱动程序的名字( 在 sysfs 中出现 )
/
struct bus_type bus; /驱动程序所操作的总线类型
/
struct module *owner;
const char mod_name; / used for built-in modules /
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);
struct attribute_group *groups;
struct pm_ops pm;
struct driver_private p;
};
2:驱动程序的注册和注销
/
注册device_driver 结构的函数是:
/
int driver_register(struct device_driver drv);
void driver_unregister(struct device_driver drv);
3:驱动程序的属性
/
driver的属性结构在:
/
struct driver_attribute {
struct attribute attr;
ssize_t (
show)(struct device_driver *drv, char buf);
ssize_t (
store)(struct device_driver drv, const char buf, size_t count);
};
DRIVER_ATTR(_name,_mode,_show,_store) /
属性文件创建的方法:
/
int driver_create_file(struct device_driver * drv, struct driver_attribute * attr);//创建设备驱动的属性
void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr);
4:驱动实例

include <linux/module.h>

include <linux/kernel.h>

include <linux/init.h>

include <linux/device.h>

include <linux/string.h>

extern struct bus_type my_bus_type;
static int my_probe(struct device *dev) {
printk(“Driver found device!\n”);
return 0;
};
static int my_remove(struct device *dev) {
printk(“Driver unpluged!\n”);
return 0;
};
struct device_driver my_driver = {
.name = “my_dev”,
.bus = &my_bus_type,
.probe = my_probe,
.remove = my_remove,
};
//定义设备驱动属性
static ssize_t my_driver_show(struct device_driver *driver, char *buf) {
return sprintf(buf, “%s\n”, “This is my driver!”);
};
static DRIVER_ATTR(drv, S_IRUGO, my_driver_show, NULL);
static int __init my_driver_init(void){
int ret;
//注册设备驱动
ret = driver_register(&my_driver);
if(ret)
printk(“driver_register failed!\n”);
//创建设备驱动属性
ret = driver_create_file(&my_driver, &driver_attr_drv);
if(ret)
printk(“create_driver_file failed!\n”);
return ret;
}
static void __exit my_driver_exit(void){
driver_unregister(&my_driver);//注销设备驱动
}
module_init(my_driver_init);
module_exit(my_driver_exit);
MODULE_AUTHOR(“Fany”);
MODULE_LICENSE(“GPL”);
5:测试
当加载驱动程序时,终端界面上打印
Driver found device!
说明驱动找到了匹配的设备,看到打印这个时,想到在windows下插U盘,立马弹出“发现可移动设备”,有点相像!
再看看相应的目录:/sys/bus/my_bus/drivers/,多了一个my_dev。

说明添加驱动成功
原文地址:http://blog.chinaunix.net/uid-23254875-id-341060.html

分类: Linux驱动 | 评论

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容