Linux中,分别使用bus_type,device_driver,device来描述总线,驱动和设备,在设备模型中,所有的设备都通过总线来连接。即使有些设备没有连接到一根物理总线上,Linux为其设置了一个内部的、虚拟的platform总线,来维持总线、驱动、设备的关系。
总线:
-
struct bus_type {
-
const char * name;//总线名字
-
struct module * owner;
-
struct kset subsys;//子系统,连接到一个全局变量kset bus_subsys。这样每一根总线系统都会通过bus_subsys结构连接起来。
-
struct kset drivers;//总线驱动
-
struct kset devices;//插入总线的所有设备
-
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);//参数与kset里的uevent相同。
-
int (*probe)(struct device * dev);
-
int (*remove)(struct device * dev);
-
void (*shutdown)(struct device * dev);
-
....
-
}
总线注册:bus_register(struct bus_type *bus);
总线删除:bus_unregister(struct bus_type *bus);
总线属性:
-
struct bus_attribute {
-
struct attribute attr;
-
ssize_t (*show)(struct bus_type *, char * buf);
-
ssize_t (*store)(struct bus_type *, const char * buf, size_t count);
-
}
创建和初始化bus_attribute结构:
#define BUS_ATTR(_name,_mode,_show,_store)
创建总线属性:
int bus_create_file(struct bus_type *,struct bus_attribute *);
删除属性:
void bus_remove_file(struct bus_type *, struct bus_attribute *);
-
Bus.c
-
#include <linux/device.h>
-
#include <linux/module.h>
-
#include <linux/kernel.h>
-
#include <linux/init.h>
-
#include <linux/string.h>
-
#include <linux/sysfs.h>
-
#include <linux/stat.h>
-
#include <linux/mm.h>
-
-
-
static ssize_t show_bus_author(struct bus_type *bus,char *buf) {
-
return snprintf(buf,PAGE_SIZE,"%s\n","show_bus_author");
-
}
-
-
static int virtual_bus_match(struct device *dev,struct device_driver *drv) {
-
Printk(KERN_DEBUG”\n!!!!!!match!!!!!!\n”);
-
return !strcmp(dev_name(dev),drv->name);
-
}
-
-
void my_bus_release(struct device *dev) {
-
printk(KERN_DEBUG"my bus release\n");
-
}
-
-
struct bus_type virtual_bus={
-
.name = "virtual_bus",
-
.match = virtual_bus_match,
-
};
-
-
struct device my_busdev={
-
.init_name = "my_busdev",
-
.release = my_bus_release,
-
};
-
EXPORT_SYMBOL(virtual_bus);
-
EXPORT_SYMBOL(my_busdev);
-
-
static BUS_ATTR(c,S_IRUGO,show_bus_author,NULL);
-
-
static int __init bus_init(void) {
-
int ret;
-
ret=bus_register(&virtual_bus); //register virtual_bus
-
if(ret){
-
return ret;
-
}
-
if(bus_create_file(&virtual_bus,&bus_attr_c)) { //创建总线属性文件
-
printk(KERN_NOTICE"unable to create bus attr\n");
-
}
-
-
ret = device_register(&my_busdev);
-
if(ret) {
-
printk(KERN_NOTICE"unable to register device\n");
-
}
-
printk("bus register success!\n");
-
return 0;
-
}
-
-
static void __exit bus_exit(void) {
-
bus_unregister(&virtual_bus);
-
device_unregister(&my_busdev);
-
}
-
-
module_init(bus_init);
-
module_exit(bus_exit);
-
MODULE_AUTHOR("MANGO");
-
MODULE_LICENSE("Dual BSD/GPL")
编译后,会在/sys/bus下建立virtual_bus文件夹。
执行cat c,得到如下输出:
设备驱动程序:
-
struct device_driver {
-
const char * name;
-
struct bus_type * bus;
-
struct kobject kobj;
-
struct klist klist_devices;
-
struct klist_node knode_bus;
-
struct module * owner;
-
const char * mod_name; /* used for built-in modules */
-
struct module_kobject * mkobj;
-
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);
-
}
Driver.c
-
#include <linux/device.h>
-
#include <linux/module.h>
-
#include <linux/kernel.h>
-
#include <linux/init.h>
-
#include <linux/string.h>
-
#include <linux/sysfs.h>
-
#include <linux/stat.h>
-
#include <linux/mm.h>
-
-
extern struct device my_busdev;
-
extern struct bus_type virtual_bus;
-
extern struct device virtual_device;
-
-
static ssize_t show_driver_author(struct device_driver *driver,char *buf) {
-
return snprintf(buf,PAGE_SIZE,"%s\n","mango");
-
}
-
-
int my_driver_remove(struct device *dev) {
-
printk("my_driver_remove\n");
-
return 0;
-
}
-
-
int my_driver_probe(struct device *dev) {
-
printk("my_driver_probe\n");
-
return 0;
-
}
-
-
struct device_driver virtual_driver={
-
.name = "mytest",
-
.bus = &virtual_bus,
-
.probe = my_driver_probe,
-
.remove = my_driver_remove,
-
};
-
-
static DRIVER_ATTR(c,S_IRUGO,show_driver_author,NULL);
-
-
static int __init my_driver_init(void) {
-
int ret;
-
ret = driver_register(&virtual_driver);
-
if(ret)
-
return ret;
-
if(driver_create_file(&virtual_driver,&driver_attr_c))
-
printk(KERN_NOTICE"unable to create author attr\n");
-
printk("driver register success\n");
-
return ret;
-
}
-
-
static void __exit my_driver_exit(void) {
-
driver_unregister(&virtual_driver);
-
printk("driver unregister success\n");
-
}
-
-
module_init(my_driver_init);
-
module_exit(my_driver_exit);
-
MODULE_AUTHOR("MANGO");
-
MODULE_LICENSE("Dual BSD/GPL")
编译后driver.ko
设备:
-
struct device {
-
struct klist klist_children;
-
struct klist_node knode_parent; /* node in sibling list */
-
struct klist_node knode_driver;
-
struct klist_node knode_bus;
-
struct device *parent;//设备的父设备,大多数情况下,一个父设备是某种总线的宿主控制器。如果是NULL,则表示该设备是顶层设备。
-
struct kobject kobj;//device->kobj->parent与&device->parent->kobj是相同的。
-
char bus_id[BUS_ID_SIZE]; /* position on parent bus */
-
struct device_type *type;
-
......
-
struct bus_type * bus; /* type of bus device is on */
-
struct device_driver *driver; /* which driver has allocated this
-
device */
-
void *driver_data; /* data private to the driver */
-
......
-
void (*release)(struct device * dev);//当指向设备的最后一个引用被删除时,内核调用该方法。
-
}
设备注册:int device_register(struct device *dev);
设备删除:int device_unregister(struct device *dev);
设备属性:
-
struct device_attribute {
-
struct attribute attr;
-
ssize_t (*show)(struct device *dev, struct device_attribute *attr,
-
char *buf);
-
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
-
const char *buf, size_t count);
-
};
宏:#define DEVICE_ATTR(_name,_mode,_show,_store)
创建设备属性:
int device_create_file(struct device *device,struct device_attribute * entry);
删除设备属性:
void device_remove_file(struct device *dev,struct device_attribute *attr);
设置设备的名字:
dev_set_name(&dev, "name");
Device.c
点击(此处)折叠或打开
-
#include <linux/device.h>
-
#include <linux/module.h>
-
#include <linux/kernel.h>
-
#include <linux/init.h>
-
#include <linux/string.h>
-
#include <linux/sysfs.h>
-
#include <linux/stat.h>
-
#include <linux/mm.h>
-
-
extern struct device my_bus;
-
extern struct bus_type virtual_bus;
-
extern struct device virtual_device;
-
-
static ssize_t show_driver_author(struct device_driver *driver,char *buf) {
-
return snprintf(buf,PAGE_SIZE,"%s\n","mango");
-
}
-
-
int my_driver_remove(struct device *dev) {
-
printk("my_driver_remove\n");
-
return 0;
-
}
-
-
int my_driver_probe(struct device *dev) {
-
printk("my_driver_probe\n");
-
return 0;
-
}
-
-
struct device_driver virtual_driver={
-
.name = "mytest",
-
.bus = &virtual_bus,
-
.probe = my_driver_probe,
-
.remove = my_driver_remove,
-
};
-
static char *c="mango_attr";
-
-
static DRIVER_ATTR(c,S_IRUGO,show_driver_author,NULL);
-
-
static int __init my_driver_init(void) {
-
int ret;
-
ret = driver_register(&virtual_driver);
-
if(ret)
-
return ret;
-
if(driver_create_file(&virtual_driver,&driver_attr_c))
-
printk(KERN_NOTICE"unable to create author attr\n");
-
printk("driver register success\n");
-
return ret;
-
}
-
-
static void __exit my_driver_exit(void) {
-
driver_unregister(&virtual_driver);
-
printk("driver unregister success\n");
-
}
-
-
module_init(my_driver_init);
-
module_exit(my_driver_exit);
-
MODULE_AUTHOR("MANGO");
-
MODULE_LICENSE("Dual BSD/GPL")
编译完后生成device.ko,加载后得到如下输出:
该device指定的父设备是my_busdev,则应该对应目录为:/sys/devices/my_busdev/mytest
执行cat c,可以看到如下输出:
三个都加载,由于driver和device名字一样,会匹配上,如下图:
此时再看bus下,文件结构如下:
会发现依附于virtual_bus总线的device和driver通过总线match起来,且都建立了相应的连接文件。
device_driver和device分别表示驱动和设备,这两者必须依附于一条总线,因此都包含了struct bus_type指针。在Linux内核中,设备和驱动程序是分开注册的。bus_type的match成员函数可以将两者捆绑在一起。
总线、驱动和设备最终会落实为sysfs中的1个目录,总线、设备和驱动中的各个attribute则直接落实为sysfs中的1个文件,attribute会伴随着show和store函数,分别用于读和写该attribute对应的sysfs文件结点。
事实上,udev规则中个信息的来源实际上就是bus_type,device_driver,device以及attribute等所对应的文件节点。
类
一个设备类描述了一种设备类型,类是一个设备的高层视图,几乎所有的类都显示在/sys/class目录中。一个例外是块设备。出于历史原因,它们出现在/sys/block下。
每个类都需要一个唯一的名字,它将显示在/sys/class中。
注册函数:int class_register(struct class *cls);
删除函数:void class_unregister(struct class *cls);
阅读(2309) | 评论(0) | 转发(0) |