Linux设备驱动程序基础知识

《Linux设备驱动程序》-chapter14

Linux设备模型

kobject、kset和子系统
1.kobject
kobject_init的函数初始化
kobject_set_name设置名称
kobject_get增加计数
kobject_put减少计数
kobj_type结构体中的release成员中保存的是这种kobject类型的release函数指针。
kobject有两种独立的机制用于连接:parent指针和kset。


一个子系统其实是对kset和一个信号量的封装。每一个kset都必须属于一个子系统。
2.底层sysfs操作
kobject是隐藏在sysfs虚拟文件系统后的机制,对于sysfs中的每一个目录,内核中都会存在一个对应的kobject。
每一个kobject都输出一个或者多个属性,它们在kobject的sysfs目录中表现为文件,其中的内容由内核生成。
3.热插拔事件的产生
热插拔事件的实际控制是有保存在kset_hotplug_ops结构中的函数完成的。
无论什么时候,当内核要为指定的kobject产生事件时,都要调用filter函数。如果filter返回0,将不产生事件。因此,该函数给kset代码一个机会,用于决定是否向用户空间


传递特定的事件。


4.总线
总线是处理器与一个或者多个设备之间的通道。在设备模型中,所有的设备都通过总线相连。
在Linux中,bus_type结构表示总线()


struct bus_type {
        const char              *name;
        const char              *dev_name;
        struct device           *dev_root;
        struct device_attribute *dev_attrs;    
        const struct attribute_group **bus_groups;
        const struct attribute_group **dev_groups;
        const struct attribute_group **drv_groups;


        int (*match)(struct device *dev, struct device_driver *drv);
        int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
        int (*probe)(struct device *dev);
        int (*remove)(struct device *dev);
        void (*shutdown)(struct device *dev);


        int (*online)(struct device *dev);
        int (*offline)(struct device *dev);


        int (*suspend)(struct device *dev, pm_message_t state);
        int (*resume)(struct device *dev);


        const struct dev_pm_ops *pm;


        struct iommu_ops *iommu_ops;


        struct subsys_private *p;
        struct lock_class_key lock_key;
};


每个总线都有自己的子系统:subsys,我们可以在总线子系统下面发现它们。
一个总线包含两个kset,分别代表了总线的驱动程序和插入总线的所有设备。(最新的内核发生变化,每找到这两个)
4.1总线用下面的代码设置bus_type结构:
struct bus_type ldd_bus_type  = {
.name = "ldd",
.match = ldd_match,
.hotplug = ldd_hotplug,
};
4.2然后用bus_register注册:
ret = bus_register(&ldd_bus_type);
if(ret)
      return ret;
4.3如果注册成功,新的总线子系统将可以在/sys/bus目录下看到,然后,我们就可以向这个总线添加设备了。
4.4删除总线用函数void bus_unregister(struct bus_type *bus);
4.5在bus_type中定义了许多方法,这些方法允许总线核心作为中间介质,在设备核心与单独的驱动程序之间提供服务。

*match
*hotplug


4.6.对设备和驱动程序的迭代
用bus_for_each_dev()函数可以迭代在总线上的每个设备,将相关的device结构传递给fn,
5.设备
linux系统中的每一个设备都用device结构的一个实例来表示。
用device_register注册设备
用device_unregister注销设备


5.1设备结构的嵌入
device结构中包含了设备模型核心用来模拟系统的信息。
单纯用device结构表示的设备是很少的,而是通常把类似kobject这样的结构内嵌在设备的高层表示之中。
比如:
struct ldd_device{
char *name;
struct ldd_driver *driver;
struct device dev;
}
#define to_ldd_device(dev) container_of(dev,struct ldd_device,dev);
这里就将device类型的结构嵌在高层结构ldd_device中。
6.驱动程序
驱动程序由
struct device_driver来定义
devices是当前驱动程序能操作的设备链表
probe是用来查询特定设备是否存在的函数,
当设备从系统中删除的时候要调用remove函数,
在关机的时候调用shutdown函数关闭设备。


(都包含注册、注销函数、属性结构,属性文件创建函数)
对于大多数驱动程序核心结构来说,device_driver结构通常被包含在高层和总线相关的结构中。
比如:
struct ldd_driver{
char *version;
struct module *module;
struct device_driver driver;
struct driver_attribute version_attr;
};
#define to_ldd_driver(drv) container_of(drv,struct ldd_driver,driver);
这和设备的结构嵌入是一样的。
然后就是向核心注册,如:
int register_ldd_driver(struct ldd_driver *driver)
{
int ret;
driver->driver.bus = &ldd_bus_type;
ret = driver_register(&driver->driver);
if(ret)
      return ret;
driver->version_attr.attr.name = "version";
driver->version_attr.attr.owner = driver->module;
driver->version_attr.attr.mode = S_IRUGO;
driver->version_attr.show = show_version;
driver->version_attr.store = NULL;
return driver_create_file(&driver->driver,&driver->version_attr);
}
这里的owner属性要设置成驱动程序模块。
然后创建自己的ldd_driver结构
static struct ldd_driver sculld_driver = {
.version = "$version: 1.1.1",
.module = THIS_MODULE,
.driver = {
      .name = "sculld",
},
};
然后调用register_ldd_driver将其添加到系统中。




7.类
类是一个设备的高层视图,它抽象出了底层的实现细节。在许多情况下,类子系统是向用户空间导出信息的最好方法。当子系统创建一个类时,它将完全拥有这个类,因此根本


不必担心哪个模块拥有哪些属性。我们会发现/sys/device目录下的信息展示并不友好,在/sys/class/下来看设备信息会明了很多。
驱动核心提供了两个接口用来管理类
7.1class_simple接口
类的创建:class_simple_create
类的销毁:class_simple_destroy
为类添加设备:class_simple_device_add


在插拔设备时,类会产生热插拔事件。如果驱动程序需要为用户空间处理程序添加环境变量的话,
可以用下面的代码设置热插拔回调函数。
int class_simple_set_hotplug(struct class_simple *cs,int(*hotplug)(struct class_device *dev,char **envp,int num_envp,char *buffer,int buffer_size));
当拔除设备时,使用下面的函数删除类入口:
void class_simple_device_remove(dev_t dev);
dev是设备号
7.2类设备
类存在的真正目的是,给作为类成员的各个设备提供一个容器。用class_device结构表示类的成员:
struct class_device{
struct kobject kobj;
struct class *class;
struct device *dev;
void *class_data;
char class_id[BUS_ID_SIZE];
};


7.3类接口
struct class_interface{
struct class *class;
int (*add) (struct class_device *cd);
void (*remove) (struct class_device *cd);
};
接口注册函数:int class_interface_register(struct class_interface *intf);
接口注销函数:void class_interface_unregister(struct class_interface *intf);


这篇博文记录了Linux设备模型的基本概念,比如,总线,设备,驱动,接口,类。
可以看到这些基本概念的设计理念都是从同一角度出发的,比如都有属性,都有注册和注销函数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值