linux ------ 设备驱动模型之二(bus, device, driver)

      bus, device, driver属于设备驱动模型的高层部分,驱动程序员直接跟它们打交道,它们构成LINUX设备驱动模型这个建筑的外在表现。

      一.  总线及其注册

             总线是设备驱动模型的核心,它把设备与驱动紧密的联系起来,完成各自的使命。 总线有具体的物理总线抽象,比如PCI, I2C总线,也有虚拟的总线,比如platform总线。符合LINUX设备驱动模型的设备与驱动必须挂靠在一个总线上,无论是物理总线还是虚拟总线。平台相关的BSP设备驱动(RTC, 看门狗,LCD控制器等)一般是挂靠在platform这个虚拟总线上。

              1. 总线数据结构

                   struct bus_type{
                            const char  *name;            //总线名称
                            const char  *dev_name;   
                            struct device  *dev_root;
                            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, struct kobj_uevent_env *env);
                            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);

                            const struct dev_pm_ops *pm;  //对总线上设备进行电源管理的一组函数

                            struct iommu_ops *iommu_ops;  //对总线的IO内存进行管理

                            struct subsys_private *p;   //管理总线上设备与驱动的数据结构
                 };

                 subsys_private数据结构 

                 struct subsys_private{
                           struct kset subsys;       //总线所在的子系统
                           struct kset *devices_kset;   //该总线上所有设备的集合
                           struct list_head interfaces; //总线子系统接口链表

                           struct mutex mutex;      //对设备进行操作的互斥锁

                           struct kset *drivers_kset;     //该总线上所有驱动的集合
                           struct klist klist_devices;     //该总线上所有设备组成的链表
                           struct klist klist_drivers;      //该总线上所有驱动组成的链表
                           struct blocking_notifier_head bus_notifier;
                           unsigned int drivers_autoprobe:1;   //当向总线中注册某一设备或驱动时是否进行设备与驱动的绑定
                           struct bus_type *bus;          //指向与该bus_type_private对象关联的总线

                           struct kset glue_dirs;
                           struct class *class;
                 };

              2. 相关操作函数

                   (1). int __init buses_init(void); //在系统初始化阶段调用这个函数,它将创建一个名称为"bus"的 kset并将其加入到sysfs 文件树中,即创建目录/sys/bus

                   (2). int  bus_register(struct bus_type *bus); //向系统中注册一个总线,创建一个具体的总线,即在目录/sys/bus下创建一个总线名称的目录,比如/sys/bus/platform,同时在该目录下创建devices与drivers目录,比如/sys/bus/platform/devices与/sys/bus/platform/drivers.

      二.  总线的属性

             总线属性代表总线特有的信息与配置,通过sysfs 为总线生成属性文件,用户空间程序可以通过文件接口的方式显示或修改总线的属性。根据需要,可以为总线不止创建一个属性文件,每个文件代表总线的一个或一组属性信息。

             1. 总线属性的数据结构

                 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);     //更改总线的属性
                  };

                  #define __ATTR(_name,_mode,_show,_store) { \
                              .attr = {.name = __stringify(_name), .mode = _mode }, \
                              .show = _show,     \
                              .store = _store,     \
                  }

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

                  BUS_ATTR定义一个"bus_attr_"开头的总线属性对象。

             2. 相关函数,这个函数生成总线属性文件。

                  int bus_create_file(struct bus_type *bus, struct bus_attribute *attr)
                  {
                         int error;
                         if (bus_get(bus)) {
                                  error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr);
                                  bus_put(bus);
                         } else
                         error = -EINVAL;
                         return error;
                  }

      三.  设备与驱动的绑定

             绑定其实就是把设备与它的驱动程序紧密结合到一起,总线在设备与驱动的绑定中发挥着核心的作用。总线为驱动程序员提供一组外在接口,简化驱动程序的开发。在总线上发生的两类事件将导致设备与驱动的绑定行为发生:一个是通过函数device_register向某一个总线上注册一个设备,另一个通过driver_register将某一驱动注册到其所处的总线上。

              1. device_register 函数

                   内核将设备加入到总线的设备链表尾端,同时试图将此设备与总线上的所有驱动对象进行绑定。它会调函数device_bind_driver进行绑定。

              2. driver_register

                   将驱动注册到其所属的总线上,同时将驱动对象加入到总线的所有驱动对象构成的链表的尾端,试图将驱动与总线上的所有设备进行绑定。

      四.  设备

              1. 数据结构

                  struct device {
                          struct device  *parent;          //当前设备的父设备
                          struct device_private *p;      //该设备驱动相关的数据
                          struct kobject kobj;               //代表struct device的内核对象
                          const char  *init_name; /* initial name of the device */  //设备对象的名称,在sysfs中表现为一个目录
                          const struct device_type *type;
                          struct mutex  mutex;
                          struct bus_type *bus;  /* type of bus device is on */  //设备所在的总线对象指针
                          struct device_driver *driver;   //当前设备是否已经与它的驱动进行绑定,如果该值为NULL,说明没有找到它的驱动
                          struct list_head deferred_probe;
                          void  *platform_data;
                          struct dev_pm_info power;
                          struct dev_pm_domain *pm_domain;
                 #ifdef CONFIG_NUMA
                           int  numa_node; /* NUMA node this device is close to */
                 #endif
                           u64  *dma_mask; /* dma mask (if dma'able device) */
                           u64  coherent_dma_mask;
                           struct device_dma_parameters *dma_parms;
                           struct list_head dma_pools;
                           struct dma_coherent_mem *dma_mem;
                 #ifdef CONFIG_CMA
                           struct cma *cma_area;
                 #endif
                           /* arch specific additions */
                           struct dev_archdata archdata;
                           struct device_node *of_node; /* associated device tree node */
                           dev_t   devt; /* dev_t, creates the sysfs "dev" */
                           u32   id; /* device instance */
                           spinlock_t  devres_lock;
                           struct list_head devres_head;
                           struct klist_node knode_class;
                           struct class  *class;
                           const struct attribute_group **groups; /* optional groups */
                           void (*release)(struct device *dev);
                  };

              2. 主要操作函数

                  (1). 设备初始化函数,初始化dev的一些成员,dev->kobj.kset=devices_kset表明dev所属的kset对象为devices_kset.

                         void device_initialize(struct device *dev)
                         {
                                dev->kobj.kset = devices_kset;
                                kobject_init(&dev->kobj, &device_ktype);
                                INIT_LIST_HEAD(&dev->deferred_probe);
                                INIT_LIST_HEAD(&dev->dma_pools);
                                mutex_init(&dev->mutex);
                                lockdep_set_novalidate_class(&dev->mutex);
                                spin_lock_init(&dev->devres_lock);
                                INIT_LIST_HEAD(&dev->devres_head);
                                device_pm_init(dev);
                                set_dev_node(dev, -1);
                         }

                  (2). 设备注册函数

                         int device_register(struct device *dev)
                         {
                                 device_initialize(dev);
                                 return device_add(dev);
                         }

                         先调用device_initialize来初始化dev对象,然后通过device_add将设备对象dev加入到系统。

                  (3). 设备注销函数

                         void device_unregister(struct device *dev)
                         {
                                device_del(dev);
                                put_device(dev);
                         }

                         将设备从系统中注销,重点在函数device_del中。

      五.  驱动

              1. 数据结构

                  struct device_driver{
                           const char  *name;           //驱动名称
                           struct bus_type  *bus;      //驱动所属总线
                           struct module  *owner;     //驱动所在的内核模块
                           const char  *mod_name;
                           bool suppress_bind_attrs;
                           const struct of_device_id *of_match_table;
                           int (*probe) (struct device *dev);     //驱动程序的探测函数,在总线对设备与驱动进行绑定时,如果总线没有定义probe函数,内核会调用驱动的probe函数
                           int (*remove) (struct device *dev);  //卸载函数,当driver_unregister卸载驱动时,如果总线没有定义remove函数,在内核调用驱动的remove函数
                           void (*shutdown) (struct device *dev);
                           int (*suspend) (struct device *dev, pm_message_t state);
                           int (*resume) (struct device *dev);
                           const struct attribute_group **groups;
                           const struct dev_pm_ops *pm;
                           struct driver_private *p;
                   };

              2. 操作函数

                  (1). driver_find, 在总线的driver_kset 集合中查找指定的驱动,name为查找的驱动名称,参数bus 指明在哪个总线上查找,如果成功,返回驱动对象指针,否则返回0

                         struct device_driver *driver_find(const char *name, struct bus_type *bus)
                         {
                                  struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);
                                  struct driver_private *priv;

                                  if (k) {
                                           /* Drop reference added by kset_find_obj() */
                                           kobject_put(k);
                                           priv = to_driver(k);
                                           return priv->driver;
                                  }
                                  return NULL;
                         }

                  (2). 驱动注册函数,先调用driver_find在总线上查找当前要注册的drv,防止向系统重复注册同一驱动,如果没有注册过,调用bus_add_driver(drv)进行注册。

                         int driver_register(struct device_driver *drv)
                         {
                               int ret;
                               struct device_driver *other;
                               BUG_ON(!drv->bus->p);
                               if ((drv->bus->probe && drv->probe) ||
                                           (drv->bus->remove && drv->remove) ||
                                           (drv->bus->shutdown && drv->shutdown))
                                           printk(KERN_WARNING "Driver '%s' needs updating - please use "
                                                              "bus_type methods\n", drv->name);

                               other = driver_find(drv->name, drv->bus);
                               if (other) {
                                        printk(KERN_ERR "Error: Driver '%s' is already registered, "
                                                  "aborting...\n", drv->name);
                                        return -EBUSY;
                               }
                               ret = bus_add_driver(drv);
                               if (ret)
                                     return ret;
                               ret = driver_add_groups(drv, drv->groups);
                               if (ret)
                                     bus_remove_driver(drv);
                               return ret;
                         }

                  (3). 驱动注销函数

                         void driver_unregister(struct device_driver *drv)
                        {
                                if (!drv || !drv->p) {
                                      WARN(1, "Unexpected driver unregister!\n");
                                      return;
                                }
                                driver_remove_groups(drv, drv->groups);
                                bus_remove_driver(drv);
                        }

                        参数drv指定要注销的某一驱动对象,函数做的是driver_register的反向工作,主要在bus_remove_driver(drv)函数中完成。在注销一个驱动对象的过程中,如果其所在的总线定义了remove方法,则调用它,否则看驱动的驱动程序中有没有实现该方法,如果实现了则内核调用该函数。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《CAN-BUS现场总线基础教程pdf》是一本介绍CAN-BUS技术的基础教材。CAN-BUS即控制器局域网络总线,是一种用于车辆电子系统通信的现场总线标准。 这本教程首先介绍了CAN-BUS的背景和发展历程,包括其应用领域和特点。接着详细讲解了CAN-BUS的物理层、数据链路层和应用层的协议规范。物理层主要包括传输介质、线路电气特性以及节点的连接方式;数据链路层则包括帧格式、错误检测与纠正机制等;应用层主要涉及CAN-BUS的具体应用场景和协议。 教程中还介绍了CAN-BUS网络的拓扑结构,包括总线型和星形拓扑结构。对于总线型拓扑结构,教程详细描述了总线的构成和排布以及节点的连接方式;对于星形拓扑结构,教程介绍了星形网络中的主机和从机的通信方式。 此外,教程还包括了CAN-BUS的通信参数设置、帧的发送与接收以及错误处理等实际应用方面的内容。教程以简洁清晰的方式介绍了CAN-BUS的基本原理和通信过程,适合初学者阅读。 总之,这本《CAN-BUS现场总线基础教程pdf》是一本很好的入门教材,对于想要了解CAN-BUS技术的人员来说是一本不可或缺的参考书。它系统地介绍了CAN-BUS的各个方面,为读者提供了全面的理论基础和实际应用知识。无论是学生、工程师还是从事相关领域的研究人员,都能从中受益匪浅。 ### 回答2: CAN-bus现场总线基础教程 PDF是一个项目驱动的教程,主要介绍了CAN-bus现场总线的基础知识和应用。CAN-bus现场总线是一种应用广泛的通信协议,主要用于汽车电子控制系统和工业自动化控制系统中。 该教程提供了关于CAN-bus现场总线的详细介绍,包括其基本原理、通信速率、网络拓扑结构、消息传输、错误检测和纠正等内容。通过学习这些知识,读者可以对CAN-bus现场总线有一个全面的了解,从而能够在项目中合理应用并解决实际问题。 教程中还介绍了CAN-bus在不同领域的应用案例,比如汽车电子控制系统中的故障诊断、定位和排放监测等。同时,教程还提供了实际操作指南和示例代码,帮助读者理解和应用CAN-bus现场总线。 通过这个教程,读者可以迅速掌握CAN-bus现场总线的基础知识,并能够在实际项目中应用所学内容。这对于从事汽车电子工程、工业自动化控制等领域的专业人士来说,具有重要意义。而对于学生和初学者来说,这个教程也提供了一个很好的学习资源,帮助他们了解和掌握CAN-bus现场总线技术。 ### 回答3: 《CAN-BUS现场总线基础教程》是一本介绍CAN-BUS现场总线技术的基础教程。CAN-BUS(Controller Area Network Bus)是一种广泛应用于汽车、工业控制和航空领域的串行通信协议。 这本教程从理论和实践两个方面介绍了CAN-BUS现场总线的基本概念、工作原理以及应用技术。它首先介绍了CAN-BUS的发展历程,包括它的起源、应用范围和优势。接着,教程详细讲解了CAN-BUS的物理层、数据链路层和应用层的具体规范和协议。对于初学者来说,这本教程提供了一个全面的入门指南。 教程中还包含了一些基于CAN-BUS的应用案例,例如汽车电子控制单元(ECU)和传感器网络。通过这些案例,读者可以了解CAN-BUS在实际应用中的工作原理和使用方法。 此外,教程还介绍了一些常见的CAN-BUS工具和设备,例如CAN-BUS分析仪和开发套件。通过这些工具和设备,读者可以更好地理解和调试CAN-BUS系统。 总的来说,《CAN-BUS现场总线基础教程》是一本适合初学者的入门教材。它通过简单易懂的语言和丰富的案例,让读者了解CAN-BUS现场总线的基础知识和应用技术。无论是从事汽车电子、工业控制还是航空领域的工程师,都可以通过这本教程对CAN-BUS有一个系统而全面的了解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值