sdk版本:MTK_Ralink_ApSoC_SDK_4200_20131106
kernel版本:linux-2.6.21.x
a. 编译配置:cat sdk/RT288x_SDK/source/linux-2.6.21/.config | grep NVRAM
CONFIG_KERNEL_NVRAM=y
CONFIG_HOSTAP_FIRMWARE_NVRAM=y
a. 位置:sdk/RT288x_SDK/source/lib/libnvram/nvram_env.c
b. nvram_init代码片段
from = fb[index].flash_offset + sizeof(fb[index].env.crc);
len = fb[index].flash_max_len - sizeof(fb[index].env.crc);
fb[index].env.data = (char *)malloc(len);
nvr.index = index;
nvr.value = fb[index].env.data;
fd = open(NV_DEV, O_RDONLY);
if (fd < 0) {
perror(NV_DEV);
goto out;
}
if (ioctl(fd, RALINK_NVRAM_IOCTL_GETALL, &nvr) < 0) {
perror("ioctl");
close(fd);
goto out;
}////////////////////////////////////////////////////////////////
p = fb[index].env.data;
for (i = 0; i < MAX_CACHE_ENTRY; i++) {
if (NULL == (q = strchr(p, '='))) {
LIBNV_PRINT("parsed failed - cannot find '='\n");
break;
}
*q = '\0'; //strip '='
fb[index].cache[i].name = strdup(p);
//printf(" %d '%s'->", i, p);
p = q + 1; //value
if (NULL == (q = strchr(p, '\0'))) {
LIBNV_PRINT("parsed failed - cannot find '\\0'\n");
break;
}
fb[index].cache[i].value = strdup(p);
//printf("'%s'\n", p);
p = q + 1; //next entry
if (p - fb[index].env.data + 1 >= len) //end of block
break;
if (*p == '\0') //end of env
break;
}
这里主要是跟进fb全局变量,获取flash块信息,打开NV_DEV ("/dev/nvram" )设备,通过ioctl对其进行读入操作,并复制到内存空间。所以nvram接口是对/dev/nvram设备进行操作的。那么/dev/nvram设备是怎么被加载的呢?
a. 根据CONFIG_KERNEL_NVRAM=y ,在内核make menuconfig查找KERNEL_NVRAM
Symbol: KERNEL_NVRAM [=y] │
│ Prompt: Kernel NVRAM │
│ Defined at arch/mips/rt2880/Kconfig:182 │
│ Location: │
│ -> Machine selection
b. arch/mips/rt2880/Makefile:
obj-$(CONFIG_KERNEL_NVRAM) += nvram.o
发现nvram设备。
c. arch/mips/rt2880/nvram.c
late_initcall(ra_nvram_init);
module_exit(ra_nvram_exit);
EXPORT_SYMBOL(nvram_get);
EXPORT_SYMBOL(nvram_set);
EXPORT_SYMBOL(nvram_commit);
设备注册接口。
d. 设备初始化接口ra_nvram_init
r = register_chrdev(ralink_nvram_major, RALINK_NVRAM_DEVNAME,
&ralink_nvram_fops);
if (r < 0) {
printk(KERN_ERR "ralink_nvram: unable to register character device\n");
return r;
}
if (ralink_nvram_major == 0) {
ralink_nvram_major = r;
printk(KERN_DEBUG "ralink_nvram: got dynamic major %d\n", r);
}init_MUTEX(&nvram_sem);
down(&nvram_sem);
for (i = 0; i < FLASH_BLOCK_NUM; i++)
init_nvram_block(i);
up(&nvram_sem);
先调用register_chrdev注册设备RALINK_NVRAM_DEVNAME("nvram")接口,然后调用init_nvram_block对复制flash到内存进行初始化。终于找到flash读入的接口了。
//read data from flash
from = from + len;
len = fb[i].flash_max_len - len;
fb[i].env.data = (char *)kmalloc(len, GFP_KERNEL);
if (!fb[i].env.data)
return -ENOMEM;
ra_mtd_read_nm(RALINK_NVRAM_MTDNAME, from, len, (unsigned char *)fb[i].env.data);
调用MTD设备接口ra_mtd_read_nm对设备RALINK_NVRAM_MTDNAME("Config")进行读入。
Symbol: MTD_SPI_RALINK [=y] │
│ Prompt: SPI │
│ Defined at arch/mips/rt2880/Kconfig:143 │
│ Depends on: <choice> && !RALINK_RT2880 │
│ Location: │
│ -> Machine selection │
│ -> Flash Type (<choice> [=y])
位置:drivers/mtd/maps/ralink-flash.c
mtd = get_mtd_device_nm(name);
if (IS_ERR(mtd))
return (int)mtd;
ret = mtd->read(mtd, from, len, &rdlen, buf);
通过对mtd设备"Config"读接口操作。
for (i = 0; i < NUM_FLASH_BANKS; i++) {
printk(KERN_NOTICE "ralink flash device: 0x%x at 0x%x\n",
ralink_map[i].size, ralink_map[i].phys);
ralink_map[i].virt = ioremap_nocache(ralink_map[i].phys, ralink_map[i].size);
if (!ralink_map[i].virt) {
printk("Failed to ioremap\n");
return -EIO;
}
simple_map_init(&ralink_map[i]);
ralink_mtd[i] = do_map_probe("cfi_probe", &ralink_map[i]);
if (ralink_mtd[i]) {
ralink_mtd[i]->owner = THIS_MODULE;
ralink_mtd[i]->lock = ralink_lock;
ralink_mtd[i]->unlock = ralink_unlock;
++found;
}
else
iounmap(ralink_map[i].virt);
}
if (found == NUM_FLASH_BANKS) {
#ifdef CONFIG_RT2880_FLASH_32M
merged_mtd = mtd_concat_create(ralink_mtd, NUM_FLASH_BANKS,
"Ralink Merged Flash");
ret = add_mtd_partitions(merged_mtd, rt2880_partitions,
ARRAY_SIZE(rt2880_partitions));
#else
ret = add_mtd_partitions(ralink_mtd[0], rt2880_partitions,
ARRAY_SIZE(rt2880_partitions));
#endif
if (ret) {
for (i = 0; i < NUM_FLASH_BANKS; i++)
iounmap(ralink_map[i].virt);
return ret;
}
}
else {
printk("Error: %d flash device was found\n", found);
return -ENXIO;
}
#endif
构造map_info结构,调用do_map_probe,根据名字"cfi_probe"找到芯片驱动linux-2.6.21.x/drivers/mtd/chips/cfi_probe.c。
return mtd_do_chip_probe(map, &cfi_chip_probe);
cfi_probe()直接调用mtd_do_chip_probe(),传入cfi_probe_chip()函数指针和map_info。
cfi = genprobe_ident_chips(map, cp);
if (!cfi)
return NULL;
map->fldrv_priv = cfi;
/* OK we liked it. Now find a driver for the command set it talks */
mtd = check_cmd_set(map, 1); /* First the primary cmdset */
if (!mtd)
mtd = check_cmd_set(map, 0); /* Then the secondary */
先调用genprobe_ident_chips(),cfi_probe_chip根据map_info探测芯片信息,后调用check_cmd_set()获取和初始化芯片命令集。
static struct mtd_partition rt2880_partitions[] = {
{
name: "ALL",
size: MTDPART_SIZ_FULL,
offset: 0,
},
/* Put your own partition definitions here */
{
name: "Bootloader",
size: MTD_BOOT_PART_SIZE,
offset: 0,
}, {
name: "Config",
size: MTD_CONFIG_PART_SIZE,
offset: MTDPART_OFS_APPEND
}, {
name: "Factory",
size: MTD_FACTORY_PART_SIZE,
offset: MTDPART_OFS_APPEND
#ifdef CONFIG_RT2880_ROOTFS_IN_FLASH
}, {
name: "Kernel",
size: MTD_KERN_PART_SIZE,
offset: MTDPART_OFS_APPEND,
}, {
name: "RootFS",
size: MTD_ROOTFS_PART_SIZE,
offset: MTDPART_OFS_APPEND,
#ifdef CONFIG_ROOTFS_IN_FLASH_NO_PADDING
}, {
name: "Kernel_RootFS",
size: MTD_KERN_PART_SIZE + MTD_ROOTFS_PART_SIZE,
offset: MTD_BOOT_PART_SIZE + MTD_CONFIG_PART_SIZE + MTD_FACTORY_PART_SIZE,
#endif
#else //CONFIG_RT2880_ROOTFS_IN_RAM
}, {
name: "Kernel",
size: MTD_KERN_PART_SIZE,
offset: MTDPART_OFS_APPEND,
#endif
#ifdef CONFIG_DUAL_IMAGE
}, {
name: "Kernel2",
size: MTD_KERN2_PART_SIZE,
offset: MTD_KERN2_PART_OFFSET,
#ifdef CONFIG_RT2880_ROOTFS_IN_FLASH
}, {
name: "RootFS2",
size: MTD_ROOTFS2_PART_SIZE,
offset: MTD_ROOTFS2_PART_OFFSET,
#endif
#endif
}
};
mtd分区,cfi_probe_chip通过分区信息表关联mtd接口到该设备的操作接口。
static int __init raspi_init(void)
{
register_mtd_chip_driver(&raspi_chipdrv);
raspi_chipdrv.probe(NULL);
return 0;
}
mtd设备初始化。
flash->chip = chip;
flash->mtd.name = "raspi";
flash->mtd.type = MTD_NORFLASH;
flash->mtd.writesize = 1;
flash->mtd.flags = MTD_CAP_NORFLASH;
flash->mtd.size = chip->sector_size * chip->n_sectors;
flash->mtd.erasesize = chip->sector_size;
flash->mtd.erase = ramtd_erase;
flash->mtd.read = ramtd_read;
flash->mtd.write = ramtd_write;
flash->mtd.lock = ramtd_lock;
flash->mtd.unlock = ramtd_unlock;
flash驱动具体操作接口。