文档章节

RT5350 nvram驱动分析

ansonc
 ansonc
发布于 2015/07/27 01:47
字数 1084
阅读 187
收藏 0

一、相关版本

sdk版本:MTK_Ralink_ApSoC_SDK_4200_20131106

kernel版本:linux-2.6.21.x

二、分析

1.nvram初始化接口:void nvram_init(int index)

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设备是怎么被加载的呢?

2. 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读入的接口了。

3. init_nvram_block接口

    //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]) 

4. MTD设备接口ra_mtd_read_nm

位置: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"读接口操作。

5. MTD设备初始化接口rt2880_mtd_init

    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。

6. cfi_probe

    return mtd_do_chip_probe(map, &cfi_chip_probe);


cfi_probe()直接调用mtd_do_chip_probe(),传入cfi_probe_chip()函数指针和map_info。

7. mtd_do_chip_probe(linux-2.6.21.x/drivers/mtd/chips/gen_probe.c)

    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()获取和初始化芯片命令集。

8. ralink_spi.c(linux-2.6.21.x/drivers/mtd/ralink/ralink_spi.c)

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驱动具体操作接口。

© 著作权归作者所有

ansonc
粉丝 3
博文 46
码字总数 16716
作品 0
南京
私信 提问
[RK3288][Android6.0] 调试笔记 --- WiFi芯片AP6356S添加

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kris_fei/article/details/87630882 Platform: RK3288 OS: Android 6.0 Kernel: 3.10.92 背景: RK3288 Andro......

KrisFei
02/18
0
0
凑个热闹,分析下Padavan的代码,一

Padavan固件研究 一、添加pppoe拔号时lcp echo 开启/关闭 选项 刚开始使用Padavan时,看一看路由器日志,发现里面全部是pppoe已边接,pppoe已断开连接,不断的断线重拔,跳开路由器,换成电脑...

shzwork
04/18
41
0
一个小型的无线路由器 Linux 系统OpenWRT

OpenWRT - (http://www.openwrt.org) 开发板: 十几种市面上很容易买到的无线路由器,价钱500元左右, 请看硬件列表: (http://wiki.openwrt.org/TableOfHardware) 我使用的是 Linksys WRT54G: ...

AlphaJay
2011/07/26
3.2K
0
C语言嵌入式系统编程修炼之内存操作

这是我13年前创作和发表在互联网上的文章,这么多年过去了,这篇文章仍然在到处传播。现在贴回Linuxer公众号。 全文目录: C语言嵌入式系统编程修炼之道——背景篇 C语言嵌入式系统编程修炼之...

jus3ve
2017/12/29
0
0
Android WIFI模块分析

一:什么是WIFI WIFI是一种无线连接技术,可用于手机、电脑、PDA等终端。WIFI技术产生的目的是改善基于IEEE802.11标准的无线网络产品之间的互通性,也就是说WIFI是基于802.11标准的,但WIFI不...

nothingfinal
2012/02/22
0
0

没有更多内容

加载失败,请刷新页面

加载更多

nginx学习笔记

中间件位于客户机/ 服务器的操作系统之上,管理计算机资源和网络通讯。 是连接两个独立应用程序或独立系统的软件。 web请求通过中间件可以直接调用操作系统,也可以经过中间件把请求分发到多...

码农实战
今天
5
0
Spring Security 实战干货:玩转自定义登录

1. 前言 前面的关于 Spring Security 相关的文章只是一个预热。为了接下来更好的实战,如果你错过了请从 Spring Security 实战系列 开始。安全访问的第一步就是认证(Authentication),认证...

码农小胖哥
今天
12
0
JAVA 实现雪花算法生成唯一订单号工具类

import lombok.SneakyThrows;import lombok.extern.slf4j.Slf4j;import java.util.Calendar;/** * Default distributed primary key generator. * * <p> * Use snowflake......

huangkejie
昨天
12
0
PhotoShop 色调:RGB/CMYK 颜色模式

一·、 RGB : 三原色:红绿蓝 1.通道:通道中的红绿蓝通道分别对应的是红绿蓝三种原色(RGB)的显示范围 1.差值模式能模拟三种原色叠加之后的效果 2.添加-颜色曲线:调整图像RGB颜色----R色增强...

东方墨天
昨天
11
1
将博客搬至CSDN

将博客搬至CSDN

算法与编程之美
昨天
13
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部