搜索
bottom↓
回复: 2

sdio wifi驱动注册过程

[复制链接]

出0入0汤圆

发表于 2014-12-5 11:36:02 | 显示全部楼层 |阅读模式
        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[i]->dev);
        }
        ......
        /*
         * ...then the SDIO functions.
         */
        for (i = 0;i < funcs;i++) {
                err = sdio_add_func(host->card->sdio_func[i]);
                if (err)
                        goto remove_added;
        }         
        sdio_init_func读sdio设备的fbr, cis寄存器来给class, vendor和device赋值.
        最后sdio_add_func调用device_add注册设备,所以当driver注册时才能匹配成功,driver的probe函数才能被调用.

出0入0汤圆

发表于 2014-12-5 11:39:14 | 显示全部楼层
内核并没有做任何的修改,不一定没有platform device,你可以试着在内核里搜索和dirver同名的平台设备,看看有没有?

出0入0汤圆

发表于 2014-12-9 14:21:57 | 显示全部楼层
我就是来学习一下
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-9 07:34

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表