总线设备驱动模型

总线设备驱动模型

总线是主机和设备之间的通道,由bus_type结构描述。

int bus_register(struct bus_type *bus) 总线的注册,若成功,新的总线将被添加进系统,并可在sysfs/sys/bus 下看到。

void bus_unregister(struct bus_type *bus) 总线的删除。

int (*match) (struct device *dev,  struct device_driver *drv)  比较设备dev和驱动drv是否匹配,驱动能否处理这个设备。

int (*event) (struct device  *dev,  char **envp,  int  num_envp,  char *buffer,  int buffer_size)在为用户空间产生热插拔事件之前,这个方法允许总线添加环境变量。

总线属性由结构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);

}; 类似于前面的kobject

int bus_create_file(struct bus_type *bus, struct bus_attribute *attr) 创建总线属性

void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr)   删除总线属性

例子:在系统中创建一条总线

  #include <linux/device.h>
  #include <linux/module.h>
  #include <linux/kernel.h>
  #include <linux/init.h>
  #include <linux/string.h>
  
  static char *Version = "$Revision: 1.0 $";
  
  static int my_match(struct device *dev, struct device_driver *driver)
  {
  	return !strncmp(dev->bus_id, driver->name, strlen(driver->name));
  //判断驱动能否处理这个设备,设备的bus_id和驱动的名字是一样的
  }
  
  struct bus_type my_bus_type = {
  	.name = "my_bus",			//创建总线目录名为 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);

执行结果在 /sys/bus 里有一个目录为my_busmy_bus目录里是总线属性。

下面是设备,每个设备由一个struct device 描述,

int device_register(struct device *dev)  注册设备

int device_unregister(struct device *dev)  注销设备

另外,总线也是设备,也需要按设备注册。

设备属性由device_attribute描述.

int device_create_file(struct device *dev,  const struct device_attribute *attr)                  创建设备属性文件。

void device_remove_file(struct device *dev,  const struct device_attribute *attr)

删除设备属性文件。

Bus.c
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>


static char *Version = "$Revision: 1.9 $";

static int my_match(struct device *dev, struct device_driver *driver)
{
	return !strncmp(dev->bus_id, driver->name, strlen(driver->name));
}

static void my_bus_release(struct device *dev)
{
	printk(KERN_DEBUG "my bus release\n");
}
	
struct device my_bus = {	//定义总线设备
	.bus_id   = "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)
{
	device_unregister(&my_bus);
	bus_unregister(&my_bus_type);
}

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>

extern struct device my_bus; 
extern struct bus_type my_bus_type;

/* Why need this ?*/
static void my_dev_release(struct device *dev)
{ 
	
}

struct device my_dev = {
	.bus = &my_bus_type,	//设备属于my_bus_type总线
	.parent = &my_bus,    //在这里体现设备和总线的关系
	.release = my_dev_release,
};

/*
 * Export a simple attribute.
 */
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 = 0;
        
        /* 初始化设备 设备的名字my_dev*/
	strncpy(my_dev.bus_id, "my_dev", BUS_ID_SIZE);
        
        /*注册设备*/
	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);

注册后产生一个设备,设备属于my_busbus下所有设备都是链接,真正的设备在device目录下。



最后一个是驱动描述

驱动程序是由struct device_driver描述的,里面有个重要指针

int  (*probe) (struct device *dev);  当驱动找到与他匹配的设备的时候,就会调用probe()

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

void driver_unregister(struct device_driver *drv) 注销驱动

驱动的属性文件struct driver_register

int driver_create_file(struct device_driver *drv, const struct driver_attribute *attr)

创建属性文件

void driver_remove_file(struct device_driver *drv, const 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>
  
  extern struct bus_type my_bus_type;
  
  static int my_probe(struct device *dev)
  {
      printk("Driver found device 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,	//指明这个驱动程序属于my_bus_type这条总线
  	.probe = my_probe,		
  //当驱动程序在这条总线上找到,能处理的设备时会调用my_probe
      .remove	= my_remove,	 //当他所能处理的设备删除时会调用my_remove
  };
  
  /*
   * Export a simple attribute.
   */
  static ssize_t mydriver_show(struct device_driver *driver, char *buf)
  {
  	return sprintf(buf, "%s\n", "This is my driver!");
  }
  
  static DRIVER_ATTR(drv, S_IRUGO, mydriver_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);
  

先加驱动,后加设备,在加设备时总线会遍历驱动,看有无驱动能处理设备,如果有调用驱动probe()。先加设备后加驱动,加驱动总线也会查找所有设备,看有无设备被驱动处理,如果有调用驱动probe()


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值