Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1575283
  • 博文数量: 204
  • 博客积分: 2215
  • 博客等级: 大尉
  • 技术积分: 4426
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-06 08:03
个人简介

气质,源于心灵的自信!

文章存档

2018年(1)

2017年(1)

2016年(1)

2015年(18)

2014年(20)

2013年(30)

2012年(119)

2011年(14)

分类: LINUX

2012-07-22 11:39:21

现在是初始化讲完啦,下面就看平台设备的注册啦,也就是咱们的I2C控制器的注册,注册函数为
platform_add_devices(surf_devices,ARRAY_SIZE(surf_devices));该函数已经在第一讲中提到,但是没有进入分析,下面咱们就进入看下平台设备是怎么注册的。
后面的代码只列出主要部分,以免其他代码干扰我们的视线。
int platform_add_devices(struct platform_device **devs, int num)
{
   int i, ret = 0;
   for (i = 0; i < num; i++) {
   ret = platform_device_register(devs[i]); 
   }
   return ret;
}
int platform_device_register(struct platform_device *pdev)
{
 device_initialize(&pdev->dev);//初始化平台设备的dev结构体,为加入设备驱动模型做准备
 return platform_device_add(pdev);
}
下面继续跟踪函数
int platform_device_add(struct platform_device *pdev)
{
 if (!pdev->dev.parent)
  pdev->dev.parent = &platform_bus;//如果pdev->dev.parent为空就赋值为platform_bus
  pdev->dev.bus = &platform_bus_type;//设置该设备的总线类型
 
 /*根据pdev->id的值设备pdev->dev的name*/
 if (pdev->id != -1)
  dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
 else
  dev_set_name(&pdev->dev, "%s", pdev->name);
 
 /*下面是对资源的处理,把每个平台设备的资源插入相应的资源树中*/
 for (i = 0; i < pdev->num_resources; i++) {
  struct resource *p, *r = &pdev->resource[i];
  if (r->name == NULL)
   r->name = dev_name(&pdev->dev);
  p = r->parent;
  if (!p) {
   if (resource_type(r) == IORESOURCE_MEM)
    p = &iomem_resource;
   else if (resource_type(r) == IORESOURCE_IO)
    p = &ioport_resource;
  }
  if (p && insert_resource(p, r)) {
   printk(KERN_ERR
          "%s: failed to claim resource %d\n",
          dev_name(&pdev->dev), i);
   ret = -EBUSY;
   goto failed;
  }
  ret = device_add(&pdev->dev);//把该设备注册到设备驱动模型中
 }
}
下面的函数处理就和一般的设备注册是一样的啦!
在上述函数中用到的两个结构体定义如下
struct device platform_bus = {
 .init_name = "platform",
};
struct bus_type platform_bus_type = {
 .name  = "platform",
 .dev_attrs = platform_dev_attrs,
 .match  = platform_match,
 .uevent  = platform_uevent,
 .pm  = &platform_dev_pm_ops,
};
platform总线的结构体,其中比较重要的函数的match函数,用于平台设备匹配平台驱动时用的。
下面看下platform_bus_type的注册。
<./init/main.c>-------------------------

asmlinkage void __init start_kernel(void)
{

  ......
  rest_init();
}

start_kernel()中的函数rest_init()将创建第一个核心线程kernel_thread(init, NULL, CLONE_FS | CLONE_SIGHAND),调用init()函数:

static int init(void * unused)-------------------
  {

    do_basic_setup();

}

static void __init do_basic_setup(void)-----------------
{
  .......

  driver_init();     //建立设备模型子系统

}
<./drivers/base/init.c>-------------------------
void __init driver_init(void)
{
 platform_bus_init();
}

下面进去看看platform_bus_init();的实现。

int __init platform_bus_init(void)
{
 device_register(&platform_bus);//注册platform_bus设备
 bus_register(&platform_bus_type);//注册platform bus总线
}

下面看看这个平台总线到底怎么注册的:

int bus_register(struct bus_type *bus)
{
 struct bus_type_private *priv;

 priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);//分配一个priv结构体
 priv->bus = bus;//把priv结构体依附在该总线上
 bus->p = priv;//把总线的p指针赋值为priv

 BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);//初始化通知链的

 retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);//设置priv->sybsys的name
 priv->subsys.kobj.kset = bus_kset;
 priv->subsys.kobj.ktype = &bus_ktype;
 priv->drivers_autoprobe = 1;

 retval = kset_register(&priv->subsys);//注册subsys
 retval = bus_create_file(bus, &bus_attr_uevent);//为总线创建属性

 /*初始化priv的两个kset,分别存放属于该总线的devices和drivers*/
 priv->devices_kset = kset_create_and_add("devices", NULL,&priv->subsys.kobj);

 priv->drivers_kset = kset_create_and_add("drivers", NULL,&priv->subsys.kobj);

 /*初始化priv的两个链表,该链表链接了该总线的设备与驱动*/
 klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);

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

}

上述函数总结起来如下:

建立一条总线,把她加入bus_kset专门存放bus的容器中,然后初始化该总线所用的devices kset,driver kset,devices driver链表,创建总线的属性等,以后在该总线上注册的驱动或者是设备,都会挂载到相应的链表和kset下。

阅读(2230) | 评论(0) | 转发(3) |
给主人留下些什么吧!~~