linux 设备驱动 总线 设备 驱动之间关系

1840阅读 0评论2014-10-15 hnylcxq
分类:LINUX


        kernel_init中do_basic_setup()->driver_init()->platform_bus_init()->...初始化platform bus(虚拟总线)
        设备向内核注册的时候platform_device_register()->platform_device_add()->...内核把设备挂在虚拟的platform bus下
        驱动注册的时候platform_driver_register()->driver_register()->bus_add_driver()->driver_attach()->bus_for_each_dev()
        对每个挂在虚拟的platform bus的设备作__driver_attach()->driver_probe_device()->drv->bus->match()==platform_match()->比较strncmp(pdev->name, drv->name, BUS_ID_SIZE),
        如果相符就调用platform_drv_probe()->driver->probe(),如果probe成功则绑定该设备到该驱动.
        kernel/init/main.c 

              对内核结构感到迷惑,是因为缺少好奇心。这句话说得一点也不假。顺利的移植完驱动,看到内核顺利的启动,驱动正常工作。貌似是大功告成。可是对于一个学习驱动的人来说这可不是什么好事。由于前段时间太顺利,被一次次的“success”迷了心窍。自认为了不得了。上星期在移植uda1341驱动时,才突然反思,驱动目录里很多设备的驱动都是基于platform虚拟平台总线的。但是驱动程序里只有对device_driver的注册,那设备在哪里注册的。难道不需要?这当然是不可能的。

         追踪内核的驱动代码,没发现platform_device注册的蛛丝马迹(后来才发现是没找对地方)。今天突然想到了内核启动时,加载的平台相关的模块。于是我找到了自己内核的mach-micro2440.c文件。。。原来在这里。。。全都在这里。。。这个文件里有所有需要初始化的平台设备(设备结构体)。最后将所有的平台设备定义在一个平台结构体数组中。

static struct platform_device *mini2440_devices[] __initdata = {
 &s3c_device_usb,
 &s3c_device_wdt,
/* &s3c_device_adc,*/ /* ADC doesn't like living with touchscreen ! */
 &s3c_device_i2c0,
 &s3c_device_rtc,
 &s3c_device_usbgadget,
 &mini2440_device_eth,
 &mini2440_led1,
 &mini2440_led2,
 &mini2440_led3,
 &mini2440_led4,
 &mini2440_button_device,
 &s3c_device_nand,
 &s3c_device_sdi,
 &s3c_device_iis,
 &mini2440_audio,
/* &s3c_device_timer[0],*/ /* buzzer pwm, no API for it */
 /* remaining devices are optional */
};

在我们加载模块时,会调用到platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_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]);
  if (ret) {
   while (--i >= 0)
    platform_device_unregister(devs[i]);
   break;
  }
 }

 return ret;
}

然后调用到了platform_device_register(devs[i]);
这个函数

int platform_device_register(struct platform_device *pdev)
{
 device_initialize(&pdev->dev);
 return platform_device_add(pdev);
}


下面小结一下:

   1,自己编写的字符设备,自己来完成设备的注册工作,在驱动中手动调用register_chrdev() 函数注册字符设备,一般不需要总线驱动。
   2,platform相关的设备,在系统初始化的时候,会调用platform_device_register进行注册
   3,另外的一些支持热插拔的设备(eg:usb pci),应该是在检测到的时候才完成注册工作的,不一定是调用的platrom_device_register.比如在usb驱动中检测到了设备接入会一层一层调用到usb_new_device函数。http://blog.chinaunix.net/uid-23117778-id-4550345.html

上一篇:linux设备驱动归纳: 总线 设备 驱动
下一篇:linux驱动学习 usb设备驱动的初步认知 .