linux设备模型之总线设备驱动模型

总线

总线是处理器和设备之间的通道,在设备模型中,所有的设备都通过总线相连,甚至是内部虚拟的“platform”总线。在Linux设备模型中,总线由 bus_type 结构表示,定义在<linux/device.h>中。

总线的描述

在这里插入图片描述

总线的注册/删除

  1. 总线的注册使用
    bus_register(struct bus_type *bus)
    若成功注册,新的总线将被添加进系统,并可以在 sysfs 的 /sys/bus 下看到。
  2. 总线的删除使用
    void bus_unregister(struct bus_type *bus)

总线方法

在 bus_type 中一些总线方法是比较重要的。

  • int (*match)(struct device * dev,struct device_driver * drv)
    当一个新设备或者驱动被添加到这个总线时,该方法被调用。用于判断指定的驱动程序是否能处理指定的设备。若可以,则返回非零值。
  • int (*uevent)(struct device *dev,char **envp,int num_envp,char *buffer,int buffer_size)
    在为用户空间产生热插拔事件之前,这个方法允许总线添加环境变量。

总线属性

在 bus_type 中,总线属性由结构 bus_attribute 描述,定义如下:

		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);
		};
  • 总线属性的创建
    int bus_create_file(struct bus_type *bus,struct bus_attribute *attr)
  • 总线属性的删除
    void bus_remove_file(struct bus_type *bus,struct bus_attribute *attr)

实例:创建总线

(1)代码:bus_create.c
特别提醒: linux2.6.3x与之前linux内核不同在于,linux2.6.3x中device结构体中中没有 bus_id 成员,但有:
const char init_name; / initial name of the device *

要把结构中的**.bus_id** = “my_bus0”, 改为 .init_name = “my_bus0”,
同时上网搜到,return !strncmp(dev->bus_id, driver->name, strlen(driver->name));这句也要改成:
return !strncmp(dev_name(dev), driver->name, strlen(driver->name));

另外: 如果要设置设备的名字,也不再使用strncpy(my_dev.bus_id, “my_dev”, BUS_ID_SIZE); 而改用:
dev_set_name(&dev, “name”);

   	#include <linux/device.h>
   	#include <linux/module.h>
   	#include <linux/kernel.h>
   	#include <linux/init.h>
   	#include <linux/string.h>
   	
   	MODULE_AUTHOR("zhangbin");
   	MODULE_LICENSE("Dual BSD/GPL");
   	
   	static char *Version = "$Revision:1.0 $";
   	
   	static int my_match(struct device *dev,struct device_driver *driver)
   	{
   	        return !strncmp(dev_name(dev),driver->name,strlen(driver->name));
   	}
   	
   	struct bus_type my_bus_type =
   	{
   	        .name = "my_bus",
   	        .match = my_match,
   	};

   	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");
   	
   	        return ret;
   	}
   	
   	static void my_bus_exit(void)
   	{
   	        bus_unregister(&my_bus_type);
   	}
   	
   	module_init(my_bus_init);
   	module_exit(my_bus_exit);

(2)Makefile

		ifneq ($(KERNELRELEASE),)

		else
		
		KDIR := /home/zhangbin/mini6410/linux-2.6.38 
		all:
		        make -C $(KDIR) M=$(PWD) ARCH=arm CROSS_COMPILE=arm-linux-
		clean:
		        rm -f *.ko *.o *.mod.c *.symvers
		
		endif

(3)演示实例
在这里插入图片描述

设备描述

在这里插入图片描述

设备注册与注销

  • 注册设备
    int device_register(struct device *dev)
  • 注销设备
    void device_unregister(struct device *dev)

(一条总线也是个设备,也必须按设备注册)

设备属性

设备属性由 struct device_attribute 描述:

		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);
		};

创建与删除属性

  • 创建属性
    int device_create_file(struct device *device,struct device_attribute *entry)

  • 删除属性
    void device_remove_file(struct device *dev,struct device_attribute *attr)

代码实例(linux2.6.38内核)

bus.c

		#include <linux/device.h>
		#include <linux/module.h>
		#include <linux/kernel.h>
		#include <linux/init.h>
		#include <linux/string.h>
		
		MODULE_AUTHOR("zhangbin");
		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_name(dev),driver->name,strlen(driver->name));
		}
		
		static void my_bus_release(struct device *dev)
		{
		        printk(KERN_DEBUG "my bus release\n");
		}
		struct device my_bus =
		{
		        .init_name = "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)
		{
		        bus_unregister(&my_bus_type);
		        device_unregister(&my_bus);
		}
		
		module_init(my_bus_init);
		module_exit(my_bus_exit);

device.c

		#include <linux/device.h>
		#include <linux/module.h>
		#include <linux/kernel.h>
		#include <linux/init.h>
		#include <linux/string.h>
		
		MODULE_AUTHOR("zhangbin");
		MODULE_LICENSE("Dual BSD/GPL");
		
		extern struct device my_bus;
		extern struct bus_type my_bus_type;
		
		//
		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 my_dev_show(struct device *dev,char *buf)
		{
		        return sprintf(buf,"%s\n","This is my device!");
		}
		
		static DEVICE_ATTR(dev,S_IRUGO,my_dev_show,NULL);
		
		static int __init my_device_init(void)
		{
		        int ret = 0;
		
		        //初始化设备
		        dev_set_name(&my_dev,"my_dev");
		
		        //注册设备
		        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);

Makefie在可以根据前边的来自己编写

实例演示

安装完成之后的效果,安装的指令就是 inmod ***.ko ,比较简单,不展示
在这里插入图片描述

驱动描述

驱动程序由 struct device_driver 描述:
在这里插入图片描述

驱动的注册与注销

  • 驱动的注册
    int driver_register(struct device_driver *drv)

  • 驱动的注销
    int driver_unregister(struct device_driver *drv)

驱动属性

驱动的属性使用 struct driver_attribute 来描述
在这里插入图片描述

创建于删除驱动属性

  • 创建属性
    int driver_create_file(struct device_driver *drv,struct driver_attribute *attr)
  • 删除属性
    void driver_remove_file(struct device_driver *drv,struct driver_attribute *attr)

代码实例

driver.c

		#include <linux/device.h>
		#include <linux/module.h>
		#include <linux/kernel.h>
		#include <linux/init.h>
		#include <linux/string.h>
		
		MODULE_AUTHOR("zhangbin");
		MODULE_LICENSE("Dual BSD/GPL");
		
		extern struct bus_type my_bus_type;
		
		static int my_probe(struct device *dev)
		{
		        printk("Driver found 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 my_driver_show(struct device_driver *driver,char *buf)
		{
		        return snprintf(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 = 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);


综合演示:

先安装总线(insmod bus.ko),再安装设备(insmod device.ko),最后安装驱动(insmod driver.ko)

后两者可以调换顺序,但是必须先安装总线(bus)

安装后效果
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_41782149/article/details/89460944