ドライバのロードからprobeの実行まで


カーネルがドライバをロードすると、まずmodule_init()が実行される。module_init()はマクロであり、プリコンパイル後は以下のように展開される(pxa2xx-ac97ドライバの場合)

static initcall_t 
__initcall_pxa2xx_ac97_init6 
__attribute__( (__used__)) 
__attribute__((__section__(".initcall" "6" ".init"))) = pxa2xx_ac97_init;


その後、ドライバ固有のprobe関数(この例ではpxa2xx_ac97_probe)の実行までは以下の経路を辿る。

1. sound/arm/pxa2xx-ac97.c(427) : pxa2xx_ac97_init() start
2. drivers/base/platform.c(444) : platform_driver_register() start
3. drivers/base/driver.c(160)   : driver_register() start
4. drivers/base/bus.c(540)      : bus_add_driver() start
5. drivers/base/dd.c(332)       : driver_attach() start
6. drivers/base/dd.c(292)       : __driver_attach() start
7. drivers/base/dd.c(207)       : driver_probe_device() start
8. drivers/base/dd.c(108)       : really_probe() start
9. drivers/base/platform.c(390) : platform_drv_probe() start
   ※really_probe()内では drv->probe(dev) としてcallされる

10. platform_drv_probe()内で各ドライバ固有のprobeが実行される
    ※drv->probe(dev) としてcallされる


ただし、7番目のdriver_probe_device()において、8番目のreally_probe()をcallする前に以下の関数を実行する。この関数の結果如何によっては、really_probe()は実行されず、そのまま return 0 行い、結果としてドライバ固有のprobeは実行されない。

 drivers/base/platform.c(571) : platform_match() start
 ※driver_probe_device()内では drv->bus->match(dev, drv) として実行される


platform_match()は以下のように定義されている。

static int platform_match(struct device * dev, struct device_driver * drv)
{
    struct platform_device *pdev = container_of(dev, struct platform_device, dev);

    return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);
}


これをプリコンパイルして適当に分解してみた。

static int platform_match(struct device * dev, struct device_driver * drv)
{
    int res ;
    int n;
    char *c;
    struct platform_device *pdev;

    pdev = (
         {
              const typeof( ((struct platform_device *)0)->dev ) *__mptr;  /* __mptrの宣言 */

              __mptr = dev;
              c = (char *)__mptr;
              n = (size_t) &((struct platform_device *)0)->dev;

              (struct platform_device *) ( c  - n );
         }
         );

    res = (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);
    return res;
}


参考

pdev->name = pxa2xx-ac97
drv->name = pxa2xx-ac97