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



  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
U-Boot是一种广泛使用的开源引导加载程序,用于嵌入式系统的引导过程。该程序提供了各种功能,可以使用户在设备上运行和测试自己的固件。DNW(Designated Network Writer)是一种用于通过网络从电脑上写入数据到设备的工具。 要在U-Boot中添加DNW功能,需要进行以下步骤: 1. 首先,需要阅读U-Boot的源代码,了解其体系结构和功能模块。找到与编译和加载固件相关的代码,并确定在哪里加入DNW的代码。 2. 接下来,需要下载并安装DNW工具,并确保该工具能在您的开发环境上正常工作。这通常包括安装相关的依赖项和配置网络连接。 3. 在U-Boot的源代码中,找到适当的位置插入DNW的功能代码。这可能涉及修改Makefile文件和源代码文件,以确保正确地编译和链接DNW代码。 4. 在源代码中添加与DNW工具通信的代码。这包括创建网络连接、发送和接收数据等。确保代码能够与DNW工具进行交互,正确地写入数据到设备。 5. 编译U-Boot代码,并生成适用于目标设备的固件。确保编译过程没有错误,并生成了正常工作的固件。 6. 将生成的固件烧录到目标设备上,并验证DNW功能是否正常工作。确保设备能够通过网络接收数据,并正确地写入到设备的存储器中。 在添加DNW功能时,还需要注意与其他功能的兼容性和冲突问题。确保在添加DNW功能后,其他U-Boot功能仍然正常工作,并没有引入新的问题。 总结起来,在U-Boot中添加DNW功能需要对U-Boot的源代码进行修改和扩展,以支持通过网络写入数据到设备。这需要仔细的编程和调试,以确保功能正确地实现和工作。添加DNW功能可以提高固件的调试和开发效率,使用户能够更方便地更新设备的固件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值