Xplain 发表于 2014-12-5 11:36:02

sdio wifi驱动注册过程

        linux的驱动一般分为两部分,一部分是platform device,这部分代码一般在板级文件中定义,另一部分是platform driver,一般在drivers目录.
        厂家给的wifi驱动属于platform driver,但是内核并没有做任何的修改,相当于没有platform device, 但是加载了wifi的platform driver之后
        wifi就能用了,很奇怪没有platform device, platform driver是怎样加载进内核的.
        先看platform driver的代码:

       static struct sdio_driver bcmsdh_sdmmc_driver = {
                .probe                = bcmsdh_sdmmc_probe,
                .remove                = bcmsdh_sdmmc_remove,
                .name                = "bcmsdh_sdmmc",
                .id_table        = bcmsdh_sdmmc_ids,
        #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM)
                .drv = {
                        .pm        = &bcmsdh_sdmmc_pm_ops,
                },
        #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */
        };

        /*
       * module init
        */
        int sdio_function_init(void)
        {
                int error = 0;
                sd_trace(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__));

                gInstance = kzalloc(sizeof(BCMSDH_SDMMC_INSTANCE), GFP_KERNEL);
                if (!gInstance)
                        return -ENOMEM;

                error = sdio_register_driver(&bcmsdh_sdmmc_driver);
                if (error) {
                        kfree(gInstance);
                        gInstance = NULL;
                }

                return error;
        }       
        注意到sdio_driver有个id_table字段,platform device和platform driver是根据该字段匹配的,而bus负责匹配工作,sdio wifi属于sdio总线,看一下sdio 总线
        是怎样做匹配的:
       
static const struct sdio_device_id *sdio_match_one(struct sdio_func *func,
        const struct sdio_device_id *id)
{               
        if (id->class != (__u8)SDIO_ANY_ID && id->class != func->class)
                return NULL;
        if (id->vendor != (__u16)SDIO_ANY_ID && id->vendor != func->vendor)
                return NULL;
        if (id->device != (__u16)SDIO_ANY_ID && id->device != func->device)
                return NULL;
        return id;
}

static const struct sdio_device_id *sdio_match_device(struct sdio_func *func,
        struct sdio_driver *sdrv)
{
        const struct sdio_device_id *ids;

        ids = sdrv->id_table;

        if (ids) {
                while (ids->class || ids->vendor || ids->device) {
                        if (sdio_match_one(func, ids))
                                return ids;
                        ids++;
                }
        }

        return NULL;
}

static int sdio_bus_match(struct device *dev, struct device_driver *drv)
{
        struct sdio_func *func = dev_to_sdio_func(dev);
        struct sdio_driver *sdrv = to_sdio_driver(drv);

        if (sdio_match_device(func, sdrv))
                return 1;

        return 0;
}
       
        可见,sdio总线是根据sdio设备的class, vendor, device来匹配的.platform driver的这几个字段是事先定义好的,
        在sdio_driver->id_tables表中:
       /* devices we support, null terminated */
static const struct sdio_device_id bcmsdh_sdmmc_ids[] = {
        { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_DEFAULT) },
        { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) },
        { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325) },
        { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329) },
        { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4319) },
        { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330) },
        { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334) },
        { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4324) },
        { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43239) },
        { SDIO_DEVICE_CLASS(SDIO_CLASS_NONE)                },
        { /* end: all zeroes */                                },
};
        但是内核并没有platform device的相关代码,这几个字段从哪来呢?这个是sdio设备跟其他驱动不一样的地方了,
        sdio的platform device是动态生成的,当插入sdio wifi的时候会产生中断,然后根据sdio设备的寄存器内容来生成
        platform device.该工作由函数mmc_attach_sdio完成(drivers\mmc\core\sdio.c):
        /*
       * Initialize (but don't add) all present functions.
       */
        for (i = 0; i < funcs; i++, card->sdio_funcs++) {
                err = sdio_init_func(host->card, i + 1);
                if (err)
                        goto remove;

                /*
               * Enable Runtime PM for this func (if supported)
               */
                if (host->caps & MMC_CAP_POWER_OFF_CARD)
                        pm_runtime_enable(&card->sdio_func->dev);
        }
        ......
        /*
       * ...then the SDIO functions.
       */
        for (i = 0;i < funcs;i++) {
                err = sdio_add_func(host->card->sdio_func);
                if (err)
                        goto remove_added;
        }       
        sdio_init_func读sdio设备的fbr, cis寄存器来给class, vendor和device赋值.
        最后sdio_add_func调用device_add注册设备,所以当driver注册时才能匹配成功,driver的probe函数才能被调用.

wangcjishu 发表于 2014-12-5 11:39:14

内核并没有做任何的修改,不一定没有platform device,你可以试着在内核里搜索和dirver同名的平台设备,看看有没有?

374533905 发表于 2014-12-9 14:21:57

我就是来学习一下
页: [1]
查看完整版本: sdio wifi驱动注册过程