源代码地址: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) cleanmake指令编译出应用和驱动,没有进行安装,所以不须要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 */ { } };
应用程序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