2011年1月13日 星期四

platfrom_match trace

在kernel內,許多結構內都會包含一個父結構成員,以利結構的轉換。
今天trace platform device,看如何利用platform device structure內的device structure pointer得知platform device structure的位址

呼叫platform_match in drivers/base/platform.c
static  __init struct platform_device *
early_platform_match(struct early_platform_driver *epdrv, int id)
{
    struct platform_device *pd;

    list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
        if (platform_match(&pd->dev, &epdrv->pdrv->driver))
            if (pd->id == id)
                return pd;

    return NULL;
}

這是platform_match的定義
static int platform_match(struct device *dev, struct device_driver *drv)
{
    struct platform_device *pdev = to_platform_device(dev);
    struct platform_driver *pdrv = to_platform_driver(drv);

    /* match against the id table first */
    if (pdrv->id_table)
        return platform_match_id(pdrv->id_table, pdev) != NULL;

    /* fall-back to driver name match */
    return (strcmp(pdev->name, drv->name) == 0);
}

主要今天目標是這行,之前上課時老師有說過,現在才拿出來看 T _ T
struct platform_device *pdev = to_platform_device(dev);

define to_platform_device in include/linux/platform_device.h
#define to_platform_device(x) container_of((x), struct platform_device, dev)


define container_of in include/linux/kernel.h
#define container_of(ptr, type, member) ({          \
    const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
    (type *)( (char *)__mptr - offsetof(type,member) );})

define offsetof in include/linux/stddef.h
#ifdef __compiler_offsetof
#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
#else
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
#endif /* __KERNEL__ */

offsetof 將0轉換成(TYPE *),即指向0的TYPE指標,((size_t) &((TYPE *)0)->MEMBER)就可以取得此MEMBER在這結構內位址值。

比如說platform_device structure(pd) 內的 device structure(dev)成員位置在0x1004。
假設dev在pd內的相對位址為4,那0x1004減去4就可以得到pd的指標位址。