毕业论文论文范文课程设计实践报告法律论文英语论文教学论文医学论文农学论文艺术论文行政论文管理论文计算机安全
您现在的位置: 毕业论文 >> 计算机安全 >> 正文

设备驱动模型之总线浅析

更新时间:2010-3-6:  来源:毕业论文

设备驱动模型之总线浅析
,理解设备驱动模型对linux驱动的编写是大有裨益的,下面会结合一个简单的实例对总线这一块作一些分析。(基于TCC8900 + linux-2.6.28)

  二,实例代码如下: #include<linux/device.h>

  #include<linux/module.h>

  #include<linux/kernel.h>

  #include<linux/init.h>

  #include<linux/string.h>

  #define COMMENT_SIZE 1024

  staticchar comment[COMMENT_SIZE]="this bus is for test";

  staticint bus_match(struct device *dev,struct device_driver * driver)

  {

  return!strncmp(dev->bus_id,driver->name,strlen(driver->name));

  }

  struct bus_type test_bus_type ={

  /*这个名字会出现在/sys/bus/目录下*/

  .name ="test_bus",

  .match = bus_match,

  };

  static ssize_t show_bus_comment(struct bus_type * bus,char* buf)

  {

  return snprintf(buf, COMMENT_SIZE,"%s\n", comment);

  }

  static ssize_t store_bus_comment(struct bus_type *bus,

  constchar*buf,size_tcount)

  {

  memset(comment, 0, COMMENT_SIZE);

  if(count>COMMENT_SIZE){

  strncpy(comment,buf,COMMENT_SIZE-1);

  return COMMENT_SIZE-1;

  }else{

  strncpy(comment,buf,count);

  returncount;

  }

  }

  static BUS_ATTR(comment, S_IWUSR | S_IRUGO, show_bus_comment, store_bus_comment);

  staticint __init test_bus_init(void)

  {

  int ret;

  /*注册总线*/

  ret=bus_register(&test_bus_type);

  if(ret){

  printk(KERN_WARNING "bus_register error: %d\n", ret);

  return ret;

  }

  /*创建属性文件*/

  if(bus_create_file(&test_bus_type,&bus_attr_comment))

  printk(KERN_INFO "cannot create comment attribute!\n");

  return ret;

  }

  staticvoid __exit test_bus_exit(void)

  {

  bus_unregister(&test_bus_type);

  }

  module_init(test_bus_init);

  module_exit(test_bus_exit);

  MODULE_AUTHOR("J.H.Luo<sparkle-cliz@sohu.com>");

  MODULE_LICENSE("Dual BSD/GPL");

  1,bus_type结构体 struct bus_type {

  constchar *name;//总线名称

  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(*suspend_late)(struct device *dev, pm_message_t state);

  int(*resume_early)(struct device *dev);

  int(*resume)(struct device *dev);

  struct pm_ext_ops *pm;

  /*下面这个结构体可以说是一个容器,内嵌了sysfs文件系统最基本的结构体kobject*/

  struct bus_type_private *p;

  };

  在本例中,我们只定义了bus_type的name和match成员,其中match函数只是简单地匹配device和device_driver的ID是不是一样。如果一样则返回非零,说明匹配成功。 2, int bus_register(struct bus_type *bus)

  {

  int retval;

  struct bus_type_private *priv;

  /* 申请一个bus_type_private结构体,就是上面我们提到的“容器”*/

  priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);

  if(!priv)

  return-ENOMEM;

  /*我中有你,你中有我的思想在linux内核中随处可见*/

  priv->bus = bus;

  bus->p = priv;

  BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);

  /*把总线的名称设置为kobject的名称,这就是为什么我们在/sys/bus/下可以看到一个目录项跟新注册的总线名称一样的原因*/

  retval = kobject_set_name(&priv->subsys.kobj,"%s", bus->name);

  if(retval)

  goto out;

  /*初始化kset,并注册它*/

  priv->subsys.kobj.kset = bus_kset;

  priv->subsys.kobj.ktype =&bus_ktype;

  priv->drivers_autoprobe = 1;

  retval = kset_register(&priv->subsys);

  if(retval)

  goto out;

  /*创建属性文件uevent ,支持热插拔之用*/

  retval = bus_create_file(bus,&bus_attr_uevent);

  if(retval)

  goto bus_uevent_fail;

  /*在每条bus总线下创建两个目录项devices和drivers

  以存放挂在这条总线上的设备和驱动*/

  priv->devices_kset = kset_create_and_add("devices",NULL,

  &priv->subsys.kobj);

  if(!priv->devices_kset){

  retval =-ENOMEM;

  goto bus_devices_fail;

  }

  priv->drivers_kset = kset_create_and_add("drivers",NULL,

  &priv->subsys.kobj);

  if(!priv->drivers_kset){

  retval =-ENOMEM;

  goto bus_drivers_fail;

  }

  /*初始化klist, klist跟引用计数有关系,

  klist_devices_get和klist_devices_put分别是

  引用计数增加和减小的操作函数*/

  klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);

  klist_init(&priv->klist_drivers,NULL,NULL);

  /*创建两个属性:drivers_probe,drivers_autoprobe*/

  retval = add_probe_files(bus);

  if(retval)

  goto bus_probe_files_fail;

  /*如果总线中还有其它属性列表,则在这里创建*/

  retval = bus_add_attrs(bus);

  if(retval)

  goto bus_attrs_fail;

  pr_debug("bus: '%s': registered\n", bus->name);

  return 0;

  bus_attrs_fail:

  remove_probe_files(bus);

  bus_probe_files_fail:

  kset_unregister(bus->p->drivers_kset);

  bus_drivers_fail:

  kset_unregister(bus->p->devices_kset);

  bus_devices_fail:

  bus_remove_file(bus,&bus_attr_uevent);

  bus_uevent_fail:

  kset_unregister(&bus->p->subsys);

  kfree(bus->p);

  out:

  return retval;

  } 整个总线的注册过程大部分工作都是在处理bus_type_private这个结构体,最终的结果是在/sys/bus/下产生一个新的总线分支。

  3,在本例中,用bus_create_file()创建一个名为comment的属性,bus_attr_comment由宏BUS_ATTR定义,读写这个属性时分别会调用这个属性的函数:show_bus_comment和store_bus_comment。

  其实,由上面注册bus的过程可知,我们也可以直接把这个属性bus_attr_comment放在bus_type的bus_attrs的成员里,这样bus_register的时候它自会为我们创建这个属性。

  驱动代码稍作修改即可,如下:

  #include<linux/device.h>

  #include<linux/module.h>

  #include<linux/kernel.h>

  #include<linux/init.h>

  #include<linux/string.h>

  #define COMMENT_SIZE 1024

  staticchar comment[COMMENT_SIZE]="this bus is for test";

  staticint bus_match(struct device *dev,struct device_driver * driver)

  {

  return!strncmp(dev->bus_id,driver->name,strlen(driver->name));

  }

  static ssize_t show_bus_comment(struct bus_type * bus,char* buf)

  {

  return snprintf(buf, COMMENT_SIZE,"%s\n", comment);

  }

  static ssize_t store_bus_comment(struct bus_type *bus,

  constchar*buf,size_tcount)

  {

  memset(comment, 0, COMMENT_SIZE);

  if(count>COMMENT_SIZE){

  strncpy(comment,buf,COMMENT_SIZE-1);

  return COMMENT_SIZE-1;

  }else{

  strncpy(comment,buf,count);

  returncount;

  }

  }

  static BUS_ATTR(comment, S_IWUSR | S_IRUGO, show_bus_comment, store_bus_comment);

  struct bus_type test_bus_type ={

  .name ="test_bus",

  .match = bus_match,

  .bus_attrs =&bus_attr_comment,

  };

  staticint __init test_bus_init(void)

  {

  int ret;

  ret=bus_register(&test_bus_type);

  if(ret){

  printk(KERN_WARNING "bus_register error: %d\n", ret);

  return ret;

  }

  return ret;

  }

  staticvoid __exit test_bus_exit(void)

  {

  bus_unregister(&test_bus_type);

  }

  module_init(test_bus_init);

  module_exit(test_bus_exit);

  MODULE_AUTHOR("J.H.Luo<sparkle-cliz@sohu.com>");

  MODULE_LICENSE("Dual BSD/GPL"); 三,最后给出这个实例的测试过程: /nand2 # insmod bus_test.ko

  /nand2 # cd /sys/bus/test_bus/

  /sys/bus/test_bus # ls

  comment drivers drivers_probe

  devices drivers_autoprobe uevent

  /sys/bus/test_bus # cat comment

  this bus is fortest

  /sys/bus/test_bus # cat > comment

  hey,guys

  ^C

  /sys/bus/test_bus # cat comment

设备驱动模型之总线浅析下载如图片无法显示或论文不完整,请联系qq752018766
设为首页 | 联系站长 | 友情链接 | 网站地图 |

copyright©lwfree.cn 六维论文网 严禁转载
如果本毕业论文网损害了您的利益或者侵犯了您的权利,请及时联系,我们一定会及时改正。