DNW原理和源代码分析

源代码地址:http://code.google.com/p/dnw-linux/

参考文章:http://www.cnblogs.com/QuLory/archive/2012/11/16/2773389.html

                  http://blog.csdn.net/yming0221/article/details/7211396

1.原理

      DNW原理就是通过PC端软件把要烧写的镜像(uboot,kernel,fs)通过usb口写进usb设备的RAM中,然后USB设备再把RAM里的数据写到rom(nandflash,emmc等)中实现固化程序。想比较直接从SD端口直接固化程序麻烦了许多,但是对于很多没有sd卡接口的设备却是必须的.

2.使用

     下载源代码,然后进入目录。输入命令sudo  make  install,注意这里需要root权限。

Makefile文件如下:

   3 driver_src = `pwd`/src/driver
    4 dnw_src = src/dnw
    5 
    6 all: driver dnw
    7 
    8 driver:
    9     make -C /lib/modules/`uname -r`/build M=$(driver_src) modules
   10 
   11 dnw:
   12     make -C $(dnw_src)
   13 
   14 install: all
   15     make -C $(dnw_src) install
   16     make -C /lib/modules/`uname -r`/build M=$(driver_src) modules_install
   17     cp dnw.rules /etc/udev/rules.d/
   18     depmod
   19 
   20 clean:
   21     make -C $(dnw_src) clean
   22     make -C /lib/modules/`uname -r`/build M=$(driver_src) clean
make指令编译出应用和驱动,没有进行安装,所以不须要root权限


make  install则需要root权限。

在pc端使用dnw将需要下载的镜像文件写入usb设备ram

$sudo ./dnw  [-a load_addr]  /filepath/filename


3.源代码分析:

驱动文件secbulk.c这个文件没什么好说的,usb设备驱动的模型,填入对应代码,要注意的是

static struct usb_device_id secbulk_table[]= {
	{ USB_DEVICE(0x5345, 0x1234) }, /* FS2410 */
	{ USB_DEVICE(0x04e8, 0x1234) }, /* EZ6410 */
	{ }
};

这里设置的pid和vid要与设备对应,否则驱动无法识别。

应用程序dnw.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdint.h>

const char* dev = "/dev/secbulk0";    //dnw所创建的设备文件,要对其写入
#define BLOCK_SIZE	(1*1024*1024) //设置的写入块大小1MB

struct download_buffer {
	uint32_t	load_addr;  /* load address */
	uint32_t	size; /* data size *///size=地址(4位)+大小(4位)+数据+校验(2位)=
	uint8_t		data[0];//0长度数组,指向数据
	/* uint16_t checksum; */数组后紧接着的两位是校验位
};

static int _download_buffer(struct download_buffer *buf)//从缓存写入到usb设备文件
{
	int fd_dev = open(dev, O_WRONLY);//打开设备
	if( -1 == fd_dev) {
		printf("Can not open %s: %s\n", dev, strerror(errno));
		return -1;
	}

	printf("Writing data...\n");
	size_t remain_size = buf->size;//写入文件的剩余大小
	size_t block_size = BLOCK_SIZE;//每次写入的大小
	size_t writed = 0;//已经写入的文件大小
	while(remain_size>0) {
		size_t to_write = remain_size > block_size ? block_size : remain_size;//每次写入的实际大小
		if( to_write != write(fd_dev, (unsigned char*)buf + writed, to_write)) {
			perror("write failed");
			close(fd_dev);
			return -1;
		}
		remain_size -= to_write;
		writed += to_write;
		printf("\r%02zu%%\t0x%08zX bytes (%zu K)",
			(size_t)((uint64_t)writed*100/(buf->size)),
			writed,
			writed/1024);//打印写入的百分比
		fflush(stdout);//将缓存写入文件
	}
	printf("\n");
	close(fd_dev);
	return 0;
}

static inline void cal_and_set_checksum(struct download_buffer *buf)
{
	uint16_t sum = 0;
	int i;

	for(i = 0; i < buf->size; i++) {
		sum += buf->data[i];
	}
	*((uint16_t*)(&((uint8_t*)buf)[buf->size - 2])) = sum;//校验码赋值给最后一个word
}

static struct download_buffer* alloc_buffer(size_t data_size)//分配空间的函数
{
	struct download_buffer	*buffer = NULL;
	size_t total_size = data_size + sizeof(struct download_buffer) + 2;buffer=文件大小+结构体前两项的大小+2位的校验位

	buffer = (typeof(buffer))malloc(total_size);
	if(NULL == buffer)
		return NULL;
	buffer->size = total_size;
	return buffer;//返回指向结构体的指针
}

static void free_buffer(struct download_buffer *buf)
{
	free(buf);
}

static struct download_buffer *load_file(const char *path, unsigned long load_addr)//载入文件到缓存
{
	struct stat		file_stat;
	struct download_buffer	*buffer = NULL;
	unsigned long		total_size;
	int			fd;

	fd = open(path, O_RDONLY);//通过路径打开文件,获得fd文件标识符
	if(-1 == fd) {
		printf("Can not open file %s: %s\n", path, strerror(errno));
		return NULL;
	}

	if( -1 == fstat(fd, &file_stat) ) {//获取文件的属性
		perror("Get file size filed!\n");
		goto error;
	}	

	buffer = alloc_buffer(file_stat.st_size);//给buffer分配空间(文件占用空间+结构体空间+2位校验)
	if(NULL == buffer) {
		perror("malloc failed!\n");
		goto error;
	}
	if( file_stat.st_size !=  read(fd, buffer->data, file_stat.st_size)) {//将文件写入buffer-》data
		perror("Read file failed!\n");
		goto error;
	}

	buffer->load_addr = load_addr;//填充结构体
	cal_and_set_checksum(buffer);//校验数据

	return buffer;

error:
	if(fd != -1)
		close(fd);
	if( NULL != buffer )
		free(buffer);
	return NULL;
}

static int download_file(const char *path, unsigned long load_addr)
{
	struct download_buffer *buffer;
	struct timeval __start, __end;
	long __time_val = 0;
	float speed = 0.0;

	buffer = load_file(path, load_addr);//将文件载入到buffer中
	gettimeofday(&__start,NULL);
	if (buffer != NULL) {
		if (_download_buffer(buffer) == 0) {//将缓存中的数据写入usb口
			gettimeofday(&__end,NULL);
			__time_val = (long)(__end.tv_usec - __start.tv_usec)/1000 + \
				(long)(__end.tv_sec - __start.tv_sec) * 1000;
			speed = (float)buffer->size/__time_val/(1024*1024) * 1000;
			printf("speed: %fM/S\n",speed);
			free_buffer(buffer);
		} else {
			free_buffer(buffer);
			return -1;
		}
	} else
		return -1;
}

int main(int argc, char* argv[])
{
	unsigned load_addr = 0x57e00000;
	char* path = NULL;
	int	c;

	while ((c = getopt (argc, argv, "a:h")) != EOF)
	switch (c) {
	case 'a':
		load_addr = strtol(optarg, NULL, 16);
		continue;
	case '?':
	case 'h':
	default:
usage:
		printf("Usage: dwn [-a load_addr] <filename>\n");
		printf("Default load address: 0x57e00000\n");
		return 1;
	}
	if (optind < argc)
		path = argv[optind];
	else
		goto usage;

	printf("load address: 0x%08X\n", load_addr);
	if (download_file(path, load_addr) != 0) {
		return -1;
	}

	return 0;
}


需要注意的几点:

1. struct download_buffer结构体含有一个零长度数组,不占用结构体空间长度,可以灵活分配空间。

2.cal_and_set_checksum检验函数通过指针偏移量写入到正确位置,位于分配空间的最后两位,数据段零长度数组后面2位。

3.load_addr参数要根据不同的设备,来设定,不指定具体地址,将会采用默认地址0x57e00000



你可能感兴趣的:(DNW原理和源代码分析)