📄 cfi_probe.c
字号:
struct cfi_private *retcfi; struct flchip chip[MAX_CFI_CHIPS]; int i; memset(&cfi, 0, sizeof(cfi)); /* The first invocation (with chips == NULL) leaves the device in Query Mode */ cfi.interleave = cfi_probe_new_chip(map, 0, NULL, NULL); if (!cfi.interleave) { printk("%s: Found no CFI device at location zero\n", map->name); /* Doesn't appear to be CFI-compliant at all */ return NULL; } /* Read the Basic Query Structure from the device */ for (i=0; i<sizeof(struct cfi_ident); i++) { ((unsigned char *)&cfi.cfiq)[i] = map->read8(map,base + ((0x10 + i)*map->buswidth)); } /* Do any necessary byteswapping */ cfi.cfiq.P_ID = le16_to_cpu(cfi.cfiq.P_ID); cfi.cfiq.P_ADR = le16_to_cpu(cfi.cfiq.P_ADR); cfi.cfiq.A_ID = le16_to_cpu(cfi.cfiq.A_ID); cfi.cfiq.A_ADR = le16_to_cpu(cfi.cfiq.A_ADR); cfi.cfiq.InterfaceDesc = le16_to_cpu(cfi.cfiq.InterfaceDesc); cfi.cfiq.MaxBufWriteSize = le16_to_cpu(cfi.cfiq.MaxBufWriteSize); #if 1 /* Dump the information therein */ print_cfi_ident(&cfi.cfiq); for (i=0; i<cfi.cfiq.NumEraseRegions; i++) { __u16 EraseRegionInfoNum = (map->read8(map,base + ((0x2d + (4*i))*map->buswidth))) + (((map->read8(map,(0x2e + (4*i))*map->buswidth)) << 8)); __u16 EraseRegionInfoSize = (map->read8(map, base + ((0x2f + (4*i))*map->buswidth))) + (map->read8(map, base + ((0x30 + (4*i))*map->buswidth)) << 8); printk(" Erase Region #%d: BlockSize 0x%4.4X bytes, %d blocks\n", i, EraseRegionInfoSize * 256, EraseRegionInfoNum+1); } printk("\n");#endif /* Switch the chip back into Read Mode, to make the alias detection work */ switch(map->buswidth) { case 1: map->write8(map, 0xff, 0x55); break; case 2: map->write16(map, 0xffff, 0xaa); break; case 4: map->write32(map, 0xffffffff, 0x154); break; } /* OK. We've worked out what it is and we're happy with it. Now see if there are others */ chip[0].start = 0; chip[0].state = FL_READY; chip[0].mutex = &chip[0]._spinlock; cfi.chipshift = cfi.cfiq.DevSize; cfi.numchips = 1; if (!cfi.chipshift) { printk("cfi.chipsize is zero. This is bad. cfi.cfiq.DevSize is %d\n", cfi.cfiq.DevSize); return NULL; } for (base = (1<<cfi.chipshift); base < map->size; base += (1<<cfi.chipshift)) cfi_probe_new_chip(map, base, &chip[0], &cfi); retcfi = kmalloc(sizeof(struct cfi_private) + cfi.numchips * sizeof(struct flchip), GFP_KERNEL); if (!retcfi) return NULL; memcpy(retcfi, &cfi, sizeof(cfi)); memcpy(&retcfi->chips[0], chip, sizeof(struct flchip) * cfi.numchips); for (i=0; i< retcfi->numchips; i++) { init_waitqueue_head(&retcfi->chips[i].wq); spin_lock_init(&retcfi->chips[i]._spinlock); } return retcfi;}static char *vendorname(__u16 vendor) { switch (vendor) { case P_ID_NONE: return "None"; case P_ID_INTEL_EXT: return "Intel/Sharp Extended"; case P_ID_AMD_STD: return "AMD/Fujitsu Standard"; case P_ID_INTEL_STD: return "Intel/Sharp Standard"; case P_ID_AMD_EXT: return "AMD/Fujitsu Extended"; case P_ID_MITSUBISHI_STD: return "Mitsubishi Standard"; case P_ID_MITSUBISHI_EXT: return "Mitsubishi Extended"; case P_ID_RESERVED: return "Not Allowed / Reserved for Future Use"; default: return "Unknown"; }} static void print_cfi_ident(struct cfi_ident *cfip){ if (cfip->qry[0] != 'Q' || cfip->qry[1] != 'R' || cfip->qry[2] != 'Y') { printk("Invalid CFI ident structure.\n"); return; } printk("Primary Vendor Command Set: %4.4X (%s)\n", cfip->P_ID, vendorname(cfip->P_ID)); if (cfip->P_ADR) printk("Primary Algorithm Table at %4.4X\n", cfip->P_ADR); else printk("No Primary Algorithm Table\n"); printk("Alternative Vendor Command Set: %4.4X (%s)\n", cfip->A_ID, vendorname(cfip->A_ID)); if (cfip->A_ADR) printk("Alternate Algorithm Table at %4.4X\n", cfip->A_ADR); else printk("No Alternate Algorithm Table\n"); printk("Vcc Minimum: %x.%x V\n", cfip->VccMin >> 4, cfip->VccMin & 0xf); printk("Vcc Maximum: %x.%x V\n", cfip->VccMax >> 4, cfip->VccMax & 0xf); if (cfip->VppMin) { printk("Vpp Minimum: %x.%x V\n", cfip->VppMin >> 4, cfip->VppMin & 0xf); printk("Vpp Maximum: %x.%x V\n", cfip->VppMax >> 4, cfip->VppMax & 0xf); } else printk("No Vpp line\n"); printk("Typical byte/word write timeout: %d 祍\n", 1<<cfip->WordWriteTimeoutTyp); printk("Maximum byte/word write timeout: %d 祍\n", (1<<cfip->WordWriteTimeoutMax) * (1<<cfip->WordWriteTimeoutTyp)); if (cfip->BufWriteTimeoutTyp || cfip->BufWriteTimeoutMax) { printk("Typical full buffer write timeout: %d 祍\n", 1<<cfip->BufWriteTimeoutTyp); printk("Maximum full buffer write timeout: %d 祍\n", (1<<cfip->BufWriteTimeoutMax) * (1<<cfip->BufWriteTimeoutTyp)); } else printk("Full buffer write not supported\n"); printk("Typical block erase timeout: %d 祍\n", 1<<cfip->BlockEraseTimeoutTyp); printk("Maximum block erase timeout: %d 祍\n", (1<<cfip->BlockEraseTimeoutMax) * (1<<cfip->BlockEraseTimeoutTyp)); if (cfip->ChipEraseTimeoutTyp || cfip->ChipEraseTimeoutMax) { printk("Typical chip erase timeout: %d 祍\n", 1<<cfip->ChipEraseTimeoutTyp); printk("Maximum chip erase timeout: %d 祍\n", (1<<cfip->ChipEraseTimeoutMax) * (1<<cfip->ChipEraseTimeoutTyp)); } else printk("Chip erase not supported\n"); printk("Device size: 0x%X bytes (%d Mb)\n", 1 << cfip->DevSize, 1<< (cfip->DevSize - 20)); printk("Flash Device Interface description: 0x%4.4X\n", cfip->InterfaceDesc); switch(cfip->InterfaceDesc) { case 0: printk(" - x8-only asynchronous interface\n"); break; case 1: printk(" - x16-only asynchronous interface\n"); break; case 2: printk(" - supports x8 and x16 via BYTE# with asynchronous interface\n"); break; case 3: printk(" - x32-only asynchronous interface\n"); break; case 65535: printk(" - Not Allowed / Reserved\n"); break; default: printk(" - Unknown\n"); break; } printk("Max. bytes in buffer write: 0x%x\n", 1<< cfip->MaxBufWriteSize); printk("Number of Erase Block Regions: %d\n", cfip->NumEraseRegions); }static void check_cmd_set(struct map_info *map, int primary, unsigned long base){ __u16 adr; struct cfi_private *cfi = map->fldrv_priv; __u16 type = primary?cfi->cfiq.P_ID:cfi->cfiq.A_ID; char probename[32]; void (*probe_function)(struct map_info *, int, unsigned long); if (type == P_ID_NONE || type == P_ID_RESERVED) return; sprintf(probename, "cfi_cmdset_%4.4X", type); probe_function = inter_module_get_request(probename, probename); if (probe_function) { (*probe_function)(map, primary, base); return; } /* This was a command set we don't know about. Print only the basic info */ adr = primary?cfi->cfiq.P_ADR:cfi->cfiq.A_ADR; if (!adr) { printk(" No Extended Query Table\n"); } else if (map->read8(map,base+(adr*map->buswidth)) != (primary?'P':'A') || map->read8(map,base+((adr+1)*map->buswidth)) != (primary?'R':'L') || map->read8(map,base+((adr+2)*map->buswidth)) != (primary?'I':'T')) { printk ("Invalid Extended Query Table at %4.4X: %2.2X %2.2X %2.2X\n", adr, map->read8(map,base+(adr*map->buswidth)), map->read8(map,base+((adr+1)*map->buswidth)), map->read8(map,base+((adr+2)*map->buswidth))); } else { printk(" Extended Query Table version %c.%c\n", map->read8(map,base+((adr+3)*map->buswidth)), map->read8(map,base+((adr+4)*map->buswidth))); }}static int __init cfi_probe_init(void){ inter_module_register(im_name, THIS_MODULE, &cfi_probe); return 0;}static void __exit cfi_probe_exit(void){ inter_module_unregister(im_name);}module_init(cfi_probe_init);module_exit(cfi_probe_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -