最近测试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.cint 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 可以查询出来。
PCMCIA_DEVICE_MANF_CARD(0x00bf, 0x0001)
顺利实现匹配。目前需要进一步确认是否只有这种匹配方式,其它方式是否可行。