無法識別apacer CF(compact flash)

最近測試CF卡,發現apacer牌子的CF卡無法識別,於是跟蹤原因 ,現把分析過程寫下,以備參考。

kernel verison 2.6.25.8

在文件

linux-2.6.25.8/drivers/ide/legacy/ide-cs.c

裏面註冊 pcmcia driver,
static struct pcmcia_driver ide_cs_driver = {
    .owner        = THIS_MODULE,
    .drv        = {
        .name    = "ide-cs",
    },
    .probe        = ide_probe,
    .remove        = ide_detach,
    .id_table       = ide_ids,
};

static int __init init_ide_cs(void)
{
    return pcmcia_register_driver(&ide_cs_driver);
}


//pcmcia_register_driver 的實現。

在 linux-2.6.25.8/drivers/pcmcia/ds.c
int pcmcia_register_driver(struct pcmcia_driver *driver)
{
    int error;

    if (!driver)
        return -EINVAL;

    pcmcia_check_driver(driver);

    /* initialize common fields */
    driver->drv.bus = &pcmcia_bus_type;
    driver->drv.owner = driver->owner;
    spin_lock_init(&driver->dynids.lock);
    INIT_LIST_HEAD(&driver->dynids.list);

    ds_dbg(3, "registering driver %s\n", driver->drv.name);

    error = driver_register(&driver->drv);
    if (error < 0)
        return error;

    error = pcmcia_create_newid_file(driver);
    if (error)
        driver_unregister(&driver->drv);

    return error;

}


//pcmcia driver和device  對應bus 實現


struct bus_type pcmcia_bus_type = {
    .name = "pcmcia",
    .uevent = pcmcia_bus_uevent,
    .match = pcmcia_bus_match,
    .dev_attrs = pcmcia_dev_attrs,
    .probe = pcmcia_device_probe,
    .remove = pcmcia_device_remove,
    .suspend = pcmcia_dev_suspend,
    .resume = pcmcia_dev_resume,
};

//檢查設備是否匹配
static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) {
 ................

    while (did && did->match_flags) {
        ds_dbg(3, "trying to match %s to %s\n", dev->bus_id,
               drv->name);
        if (pcmcia_devmatch(p_dev, did)) {
            ds_dbg(0, "matched %s to %s\n", dev->bus_id,
                   drv->name);
            return 1;
        }
        did++;
    }
....
}


//具體匹配函數,此函數會遍歷 drivers/ide/legacy/ ide-cs.c 裏面的 ide_ids


static inline int pcmcia_devmatch(struct pcmcia_device *dev,
                  struct pcmcia_device_id *did)
{

    if (did->match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID) {
        if ((!dev->has_manf_id) || (dev->manf_id != did->manf_id))
            return 0;
    }

    if (did->match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID) {
        if ((!dev->has_card_id) || (dev->card_id != did->card_id))
            return 0;
    }

    if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION) {
        if (dev->func != did->function)
            return 0;
    }

    if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1) {
        if (!dev->prod_id[0])
            return 0;
        if (strcmp(did->prod_id[0], dev->prod_id[0]))
            return 0;
    }

    if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2) {
        if (!dev->prod_id[1])
            return 0;
        if (strcmp(did->prod_id[1], dev->prod_id[1]))
            return 0;
    }

    if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3) {
        if (!dev->prod_id[2])
            return 0;
        if (strcmp(did->prod_id[2], dev->prod_id[2]))
            return 0;
    }

    if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4) {
        if (!dev->prod_id[3])
            return 0;
        if (strcmp(did->prod_id[3], dev->prod_id[3]))
            return 0;
    }

    if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) {
        if (dev->device_no != did->device_no)
            return 0;
    }

    if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID) {
        if ((!dev->has_func_id) || (dev->func_id != did->func_id))
            return 0;

        /* if this is a pseudo-multi-function device,
         * we need explicit matches */
        if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO)
            return 0;
        if (dev->device_no)
            return 0;

        /* also, FUNC_ID matching needs to be activated by userspace
         * after it has re-checked that there is no possible module
         * with a prod_id/manf_id/card_id match.
         */
        ds_dbg(0, "skipping FUNC_ID match for %s until userspace "
               "interaction\n", dev->dev.bus_id);
        if (!dev->allow_func_id_match)
            return 0;
    }

    if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) {
        ds_dbg(0, "device %s needs a fake CIS\n", dev->dev.bus_id);
        if (!dev->socket->fake_cis)
            pcmcia_load_firmware(dev, did->cisfile);

        if (!dev->socket->fake_cis)
            return 0;
    }

    if (did->match_flags & PCMCIA_DEV_ID_MATCH_ANONYMOUS) {
        int i;
        for (i=0; i<4; i++)
            if (dev->prod_id[i])
                return 0;
        if (dev->has_manf_id || dev->has_card_id || dev->has_func_id)
            return 0;
    }

    dev->dev.driver_data = (void *) did;

    return 1;
}


//通過跟蹤發現,apacer CF卡 無法匹配到任何的匹配方式,因爲drivers/ide/legacy/ ide-cs.c 裏面的 

ide_ids 沒有對應的匹配項。


而通過如下命令
#cd /sys/devices/platform/pxa2xx-pcmcia/1.0/
#cat manf_id
0x00bf
#cat card_id

0x0001


可以查到device的 manufactute id 和 card id 可以查詢出來。


故在static struct pcmcia_device_id ide_ids[] 添加如下一行

PCMCIA_DEVICE_MANF_CARD(0x00bf, 0x0001)

順利實現匹配。目前需要進一步確認是否只有這種匹配方式,其它方式是否可行。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章