app操作flash

app中通过mtd flash的接口对 mtd5分区进行升级

//通过mtd实现linux下只读文件系统中的flash应用层读写文件
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <sys/types.h>

#define MTD_FACTORY     "/dev/mtd5"
#define FIBERHOME_MAGIC_NUM  0x13579246

#define MEMGETINFO    _IOR('M', 1, struct mtd_info_user)
#define MEMERASE    _IOW('M', 2, struct erase_info_user)
#define MEMUNLOCK    _IOW('M', 6, struct erase_info_user)


struct erase_info_user {
    unsigned int start;
    unsigned int length;
};

struct mtd_info_user {
    unsigned char type;
    unsigned int flags;
    unsigned int size;
    unsigned int erasesize;
    unsigned int oobblock;  
    unsigned int oobsize;  
    unsigned int ecctype;
    unsigned int eccsize;
};

void print_buf (unsigned char* p, int len)
{
    int i = 0;
    if (p == NULL || len < 0)
        return;

    for (i = 0; i < len; i++)
    {
        printf ("0x%x ", p[i]);
        if ((i % 16 == 0) && (i != 0))
            printf ("\n");
    }
}

int fhdrv_kdrv_set_led_control_data(int flag)
{
	FILE *fp = NULL;
	char buf[128] = {0};

	fp = fopen("/proc/driver/led_data", "w");
	if (fp == NULL)
	{
		return -1;
	}

	snprintf(buf, sizeof(buf), "%x %d", FIBERHOME_MAGIC_NUM, flag);
	fputs(buf,fp);
	fclose(fp);

	return 0;
}

int mtd_read(int off, int len)
{

    int i = 0;
    int fd = 0;
    unsigned char* buf = NULL;

    buf = malloc (len);
    if (buf == 0)
    {
        printf ("malloc err\n");
        return -1;
    }
    
    fd = open(MTD_FACTORY, O_RDWR | O_SYNC);
    if(fd < 0) {
        printf("Could not open mtd device: %s\n", MTD_FACTORY);
        free (buf);
        return -1;
    }

    lseek(fd, 0, SEEK_SET);

    if(read(fd, buf, len) != len){
        printf("read() failed\n");
        free(buf);
        close(fd);
        return -1;
    }

    print_buf (buf, len);
    close(fd);
    free(buf);
    return 0;
}
int mtd_erase ()
{
    struct mtd_info_user mtdInfo;
    struct erase_info_user mtdEraseInfo;
    int fd = 0;

    fd = open(MTD_FACTORY, O_RDWR | O_SYNC);
    if(fd < 0) {
        fprintf(stderr, "Could not open mtd device: %s\n", MTD_FACTORY);
        return -1;
    }
    if(ioctl(fd, MEMGETINFO, &mtdInfo)) {
        fprintf(stderr, "Could not get MTD device info from %s\n", MTD_FACTORY);
        close(fd);
        return -1;
    }

    lseek(fd, 0, SEEK_SET);

    mtdEraseInfo.length = mtdInfo.erasesize;

    mtdEraseInfo.start = 0x0;
    for (mtdEraseInfo.start; mtdEraseInfo.start < mtdInfo.size; mtdEraseInfo.start += mtdInfo.erasesize) {
        ioctl(fd, MEMUNLOCK, &mtdEraseInfo);
        if(ioctl(fd, MEMERASE, &mtdEraseInfo)){
            fprintf(stderr, "Failed to erase block on %s at 0x%x\n", MTD_FACTORY, mtdEraseInfo.start);
            close(fd);
            return -1;
        }
    }


    close(fd);
    return 0;
}
int mtd_write(int off, int len, unsigned char* data)
{
    struct mtd_info_user mtdInfo;
    struct erase_info_user mtdEraseInfo;
    int fd = 0;
	int offset;

	FILE *fp = NULL;
	char buf[2048] = {0};
	char buf_bak[2048] = {0};
	int read_len = 0;

	/* 打开镜像文件 */
	fp = fopen(data, "r");
	if (fp == NULL)
	{
		return -1;
	}

	printf("open image file :%s \n", data);

	/* 写入镜像文件 */
    fd = open(MTD_FACTORY, O_RDWR | O_SYNC);
    if(fd < 0) {
    	printf("write fail \n");
        return -1;
    }
    if(ioctl(fd, MEMGETINFO, &mtdInfo)) {
    	printf("write fail \n");
        close(fd);
        return -1;
    }

   	lseek(fd, 0, SEEK_SET);
	fseek(fp, 0, SEEK_SET);

	printf("prepare updata len:0x%x \n", len);

   	for (offset = 0; (offset + 1024) < len;)
   	{
		memset(&buf, 0, sizeof(buf));
		printf("write addr :0x%x per:%d\n", offset, offset*100/len);

		if (0 == fread(buf, 1024, 1, fp))
		{
			printf("read image err !!! offset:0x%x\n", offset);
		}

  	 	if (write(fd, buf, 1024) != 1024) {
			printf("write image err !!! offset:0x%x\n", offset);
    	    goto write_fail;
   		}

		offset += 1024;
	}

   	if (offset + 1024 > len)
   	{
		memset(&buf, 0, sizeof(buf));
		printf("left data :%d \n", len - offset);
		printf("write addr :0x%x per:%d\n", offset, offset*100/len);

		if (0 == fread(buf, len - offset, 1, fp))
		{
			printf("left read image err !!! offset:%x\n", offset);
		}

  	 	if (write(fd, buf, 1024) != 1024) {
			printf("left write image err !!! offset:0x:%x\n", offset);
    	    goto write_fail;
   		}
	}

	fclose(fp);
    close(fd);

	printf("updata success \n");	
	
    return 0;

write_fail:
    printf("write fail \n");
	fclose(fp);
    close(fd);
    return -1;
}

void usage(char **str)
{
    printf("How to use:\n");
    printf("\tread:   %s r offset length\n", str[0]);
    printf("\twrite:  %s w offset length data...\n", str[0]);
    printf ("\terase: %s e\n", str[0]);
    printf ("\tfor read, offset should >= 0 && offset + length should < 10240\n");
    printf ("\tfor write, offset should >= 0 && offset + length should < 10240 && length should <= 10\n");
    printf ("\tfor erase, off 0 to 10240(not included) will be erased to 0xFF\n");
}

int main(int argc,char **argv)
{
    char op;
    int off = 0;
    int len = 0;

    if (argc < 2)
        goto CmdFail;

	fhdrv_kdrv_set_led_control_data(1);

    op = *(argv[1]);

	if (op != 'e')
	{
		off = atoi (argv[2]);
		len = atoi (argv[3]);
		printf("op:%c, off:0x%x, len:0x%x \n", op, off, len);
	}

   switch (op) {
    case 'r':
        if (mtd_read(off, len) < 0)
            goto Fail;
        break;
    case 'w':
        if (mtd_write(off, len, argv[4]) < 0)
            goto Fail;
        break;
    case 'e':
        if (mtd_erase() < 0)
            goto Fail;
        break;
    default:
        goto CmdFail;
    }

    return 0;
CmdFail:
    usage(argv);
Fail:
    return -1;
}
#tftp -g -r a.out  10.35.27.168
a.out                100% |*******************************| a.out                100% |*******************************| 14764   0:00:00 ETA
#chmod +x a.out 
#./a.out e
#./a.out w 0 3964928 rootfs.squashfs.img 
op:w, off:0x0, len:0x3c8000 
open image file :rootfs.squashfs.img 
prepare updata len:0x3c8000 
write addr :0x0 per:0

横向对比,重要总结

linux 驱动为什么分为,字符设备,块设备,网络设备。这个和gpio,i2c,等子系统有什么关系呢。目前我认为,众多子系统都是根据总线不同,在字符设备上进行了封装,使得子系统可以支持很多的,通用的驱动外设的方法。所以这些子系统的设备都包含重要结构体fileoperation。

关键问题

read和write都是常见的文件操作,那么像erase这种文件操作,使用ioctl的这个结构体为什么是这么定义的呢?
ioctl其实就是驱动层和业务层,约定好的处理文件操作之外的命令,处理方式。所以说为什么这么定义,这个需要看驱动层代码。在mtdchar.c这个文件里面有介绍:

static const struct file_operations mtd_fops = {
    .owner      = THIS_MODULE,
    .llseek     = mtdchar_lseek,
    .read       = mtdchar_read,
    .write      = mtdchar_write,
    .unlocked_ioctl = mtdchar_unlocked_ioctl,
#ifdef CONFIG_COMPAT
    .compat_ioctl   = mtdchar_compat_ioctl,
#endif
    .open       = mtdchar_open,
    .release    = mtdchar_close,
    .mmap       = mtdchar_mmap,
#ifndef CONFIG_MMU
    .get_unmapped_area = mtdchar_get_unmapped_area,
    .mmap_capabilities = mtdchar_mmap_capabilities,
#endif
};

继续看ioctl这个里面函数的定义:

static long mtdchar_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
{
    int ret;

    mutex_lock(&mtd_mutex);
    ret = mtdchar_ioctl(file, cmd, arg);                                                            
    mutex_unlock(&mtd_mutex);

    return ret;
}

在这个函数中,就是加了互斥锁,然后直接调用mtdchar_ioctl。

static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
{
    struct mtd_file_info *mfi = file->private_data;
    struct mtd_info *mtd = mfi->mtd;
    void __user *argp = (void __user *)arg;
    int ret = 0;
    u_long size;
    struct mtd_info_user info;

    pr_debug("MTD_ioctl\n");

    size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
    if (cmd & IOC_IN) {
        if (!access_ok(VERIFY_READ, argp, size))
            return -EFAULT;
    }
    if (cmd & IOC_OUT) {
        if (!access_ok(VERIFY_WRITE, argp, size))
            return -EFAULT;
    }

    switch (cmd) {
    case MEMGETREGIONCOUNT:
        if (copy_to_user(argp, &(mtd->numeraseregions), sizeof(int)))
            return -EFAULT;
        break;

    case MEMGETREGIONINFO:
    。。。
}

重点关注传递命令,对应的参数的结构体,继续查找:

#define MEMGETINFO    _IOR('M', 1, struct mtd_info_user)
#define MEMERASE    _IOW('M', 2, struct erase_info_user)
#define MEMUNLOCK    _IOW('M', 6, struct erase_info_user)
struct mtd_info_user {
    __u8 type;
    __u32 flags;
    __u32 size; /* Total size of the MTD */
    __u32 erasesize;
    __u32 writesize;
    __u32 oobsize;  /* Amount of OOB data per block (e.g. 16) */
    __u64 padding;  /* Old obsolete field; do not use */
};

可以看到这个结构体信息,定义的。因此使用的才会这么使用

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值