<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_He,YuanHui —— 业精于勤荒于嬉，行成于思毁于随</title><subtitle type="text">如果你喜欢一个事，又有这样的才干，那就把整个人都投入进去，就要象一把刀直扎下去直到刀柄一样，不要问为什么，也不要管会碰到什么。</subtitle><id>http://feed.cnblogs.com/blog/u/39443/rss</id><updated>2012-05-23T05:23:28Z</updated><author><name>He,YuanHui</name><uri>http://www.cnblogs.com/khler/</uri></author><generator>feed.cnblogs.com</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/khler/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/39443/rss"/><entry><id>http://www.cnblogs.com/khler/archive/2011/05/16/2047362.html</id><title type="text">Linux下如何清空socket的接收缓冲区的数据</title><summary type="text">=================================================本文为HeYuanHui原作转载必须确保本文完整并完整保留原作者信息及本文原始链接!NN: khlerE-mail: khler@163.comQQ:23381103MSN:pragmac@hotmail.com=================================================最近碰到一个问题，对于阻塞模式的socket通讯，如果要实现设备的命令控制，那么进入命令流前，缓冲区不能存有上次通讯没有取回的信息，否则一旦命令发出，然后读取缓冲区，很显然会读到上一次的剩余数</summary><published>2011-05-16T01:47:00Z</published><updated>2011-05-16T01:47:00Z</updated><author><name>He,YuanHui</name><uri>http://www.cnblogs.com/khler/</uri></author><link rel="alternate" href="http://www.cnblogs.com/khler/archive/2011/05/16/2047362.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/khler/archive/2011/05/16/2047362.html"/><content type="html">&lt;p&gt;&lt;font face="Verdana"&gt;&lt;em&gt;&lt;font face="Verdana"&gt;&lt;em&gt;=================================================&lt;br /&gt;&lt;/em&gt;&lt;/font&gt;&lt;font face="Verdana"&gt;&lt;em&gt;本文为&lt;em&gt;HeYuanHui&lt;/em&gt;原作&lt;/em&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="title"&gt;&lt;font face="Verdana"&gt;&lt;em&gt;转载必须确保本文完整并完整保留原作者信息及本文原始链接!&lt;/em&gt;&lt;/font&gt;&lt;/p&gt;&lt;p class="title"&gt;&lt;font face="Verdana"&gt;&lt;em&gt;&lt;em&gt;NN:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; khler&lt;/em&gt;&lt;br /&gt;&lt;/em&gt;&lt;/font&gt;&lt;font face="Verdana"&gt;&lt;em&gt;E-mail: &lt;/em&gt;&lt;a href="&amp;#109;&amp;#97;&amp;#105;&amp;#108;&amp;#116;&amp;#111;&amp;#58;&amp;#107;&amp;#104;&amp;#108;&amp;#101;&amp;#114;&amp;#64;&amp;#49;&amp;#54;&amp;#51;&amp;#46;&amp;#99;&amp;#111;&amp;#109;" target="_blank"&gt;&lt;em&gt;khler@163.com&lt;/em&gt;&lt;/a&gt;&lt;br /&gt;&lt;/font&gt;&lt;font face="Verdana"&gt;&lt;em&gt;QQ:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;23381103&lt;br /&gt;&lt;/em&gt;&lt;/font&gt;&lt;font face="Verdana"&gt;&lt;em&gt;MSN:&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/em&gt;&lt;a href="&amp;#109;&amp;#97;&amp;#105;&amp;#108;&amp;#116;&amp;#111;&amp;#58;&amp;#112;&amp;#114;&amp;#97;&amp;#103;&amp;#109;&amp;#97;&amp;#99;&amp;#64;&amp;#104;&amp;#111;&amp;#116;&amp;#109;&amp;#97;&amp;#105;&amp;#108;&amp;#46;&amp;#99;&amp;#111;&amp;#109;"&gt;&lt;em&gt;pragmac@hotmail.com&lt;/em&gt;&lt;/a&gt;&lt;br /&gt;&lt;/font&gt;&lt;font face="Verdana"&gt;&lt;font face="Verdana"&gt;&lt;em&gt;=================================================&lt;/em&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;div class="title"&gt;&amp;nbsp;&lt;/div&gt;&lt;/em&gt;&lt;div class="title"&gt;&lt;/div&gt;&lt;/font&gt;&lt;div class="title"&gt;&lt;/div&gt;&lt;div class="title"&gt;最近碰到一个问题，对于阻塞模式的socket通讯，如果要实现设备的命令控制，那么进入命令流前，缓冲区不能存有上次通讯没有取回的信息，否则一旦命令发出，然后读取缓冲区，很显然会读到上一次的剩余数据。做法当然很简单，就是先清除接收区的缓冲数据，可是如何清除？&lt;/div&gt;&lt;div class="entry"&gt;&lt;p&gt;网上有很多这样的问题，但都没什么规范的解决办法，有的甚至为了达到清空的目的，建议先close一下socket，这个太大手笔了，为了解决一个小问题而大动干戈，根本不是个合理的解决办法。&lt;/p&gt;&lt;p&gt;还有就是用recv读取，但是由于不知道缓存里有多少数据，如果是阻塞模式，到最后必然等到超时才知道数据已经读取完毕，这是个问题。&lt;/p&gt;&lt;p&gt;另一个是用fgetc，通过返回判断是否是feof：&lt;/p&gt;&lt;p&gt;whlie (1) {&lt;br /&gt;a=fgetc(f);&lt;br /&gt;if (feof(f)) break;&lt;br /&gt;//&amp;#8230;&lt;br /&gt;b=fgetc(f);&lt;br /&gt;if (feof(f)) break;&lt;br /&gt;//&amp;#8230;&lt;br /&gt;}&lt;/p&gt;&lt;p&gt;当然，我不知道读取完毕后最后一次调用fgetc会不会堵塞，需要测试。&lt;/p&gt;&lt;p&gt;在非阻塞模式下，我们用recv就可以轻松搞定了，但是阻塞模式下，由于我们不知道缓冲区有多少数据，不能直接调用recv尝试清除。&lt;/p&gt;&lt;p&gt;使用一个小小的技巧，利用select函数，我们可以轻松搞定这个问题：&lt;/p&gt;&lt;p&gt;select函数用于监视一个文件描述符集合，如果集合中的描述符没有变化，则一直阻塞在这里，直到超时时间到达；在超时时间内，一旦某个描述符触发了你所关心的事件，select立即返回，通过检索文件描述符集合处理相应事件；select函数出错则返回小于零的值，如果有事件触发，则返回触发事件的描述符个数；如果超时，返回0，即没有数据可读。&lt;/p&gt;&lt;p&gt;重点在于：我们可以用select的超时特性，将超时时间设置为0，通过检测select的返回值，就可以判断缓冲是否被清空。通过这个技巧，使一个阻塞的socket成了&amp;#8216;非阻塞&amp;#8217;socket。&lt;/p&gt;&lt;p&gt;现在就可以得出解决方案了：使用select函数来监视要清空的socket描述符，并把超时时间设置为0，每次读取一个字节然后丢弃（或者按照业务需要进行处理，随你便了），一旦select返回0，说明缓冲区没数据了（&amp;#8220;超时&amp;#8221;了）。&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;struct timeval tmOut;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;tmOut.tv_sec = 0;&lt;br /&gt;tmOut.tv_usec = 0;&lt;br /&gt;fd_set&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; fds;&lt;br /&gt;FD_ZEROS(&amp;amp;fds);&lt;br /&gt;FD_SET(skt, &amp;amp;fds);&lt;/p&gt;&lt;p&gt;int&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; nRet;&lt;/p&gt;&lt;p&gt;char tmp[2];&lt;/p&gt;&lt;p&gt;memset(tmp, 0, sizeof(tmp));&lt;/p&gt;&lt;p&gt;while(1)&lt;br /&gt;{&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; nRet= select(FD_SETSIZE, &amp;amp;fds, NULL, NULL, &amp;amp;tmOut);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(nRet== 0) &amp;nbsp;break;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;recv(skt, tmp, 1,0);&lt;br /&gt;}&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&amp;nbsp;这种方式的好处是，不再需要用recv、recvfrom等阻塞函数直接去读取，而是使用select，利用其超时特性检测缓冲区是否为空来判断是否有数据，有数据时才调用recv进行清除。&lt;/p&gt;&lt;p&gt;有人说同样可以用recv和socket的超时设置去清空啊，这个没错，但是你需要直接对socket描述符设置超时时间，而为了清空数据而直接修改socket描述符的属性，可能会影响到其他地方的使用，造成系统奇奇怪怪的问题，所以，不推荐使用。&lt;/p&gt;&lt;/div&gt;    &lt;img src="http://www.cnblogs.com/khler/aggbug/2047362.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/khler/archive/2011/05/16/2047362.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/khler/archive/2011/03/24/1993459.html</id><title type="text">新博客地址</title><summary type="text">最近又倒腾了个美国服务器，搞了个WordPress blog：www.roboby.com欢迎感兴趣的朋友围观 ：）</summary><published>2011-03-24T02:05:00Z</published><updated>2011-03-24T02:05:00Z</updated><author><name>He,YuanHui</name><uri>http://www.cnblogs.com/khler/</uri></author><link rel="alternate" href="http://www.cnblogs.com/khler/archive/2011/03/24/1993459.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/khler/archive/2011/03/24/1993459.html"/><content type="html">&lt;p&gt;最近又倒腾了个美国服务器，搞了个WordPress blog：&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.roboby.com"&gt;www.roboby.com&lt;/a&gt;&lt;/p&gt;&lt;p&gt;欢迎感兴趣的朋友围观 ：）&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/khler/aggbug/1993459.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/khler/archive/2011/03/24/1993459.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/khler/archive/2011/02/25/1965256.html</id><title type="text">【转】Ubuntu 10.04建立源碼樹實現最簡單的驅動模塊</title><summary type="text">这篇文章写得相当不错，推荐阅读，同时在此感谢一下原作者 ——hyh 飛帆網 http://www.pyoix.com 2010年09月17日 09:02 本文參考了很多網上的文章，在這裏先感謝網上的朋友們。編譯了一天終於可以導入Ubuntu 10.04 設備驅動程序最簡單的 Hello World。 其實我也是一個初學者，但衹要堅持學習，一定會理解的。 現在我講述在Ubuntu 10.04下安裝的...</summary><published>2011-02-25T10:06:00Z</published><updated>2011-02-25T10:06:00Z</updated><author><name>He,YuanHui</name><uri>http://www.cnblogs.com/khler/</uri></author><link rel="alternate" href="http://www.cnblogs.com/khler/archive/2011/02/25/1965256.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/khler/archive/2011/02/25/1965256.html"/><content type="html">&lt;p&gt;&lt;strong&gt;这篇文章写得相当不错，推荐阅读，同时在此感谢一下原作者 &lt;img style="border-bottom-style: none; border-right-style: none; border-top-style: none; border-left-style: none" class="wlEmoticon wlEmoticon-smile" alt="微笑" src="http://images.cnblogs.com/cnblogs_com/khler/201102/201102251806139287.png"&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ——hyh&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;飛帆網　 http://www.pyoix.com　 2010年09月17日 09:02 &lt;p&gt;&lt;ins&gt;&lt;ins&gt;&lt;/ins&gt;&lt;/ins&gt; &lt;p&gt;本文參考了很多網上的文章，在這裏先感謝網上的朋友們。編譯了一天終於可以導入Ubuntu 10.04 設備驅動程序最簡單的 Hello World。 &lt;p&gt;其實我也是一個初學者，但衹要堅持學習，一定會理解的。 &lt;p&gt;現在我講述在Ubuntu 10.04下安裝的過程： &lt;p&gt;1.安裝編譯內核所需要的軟件 &lt;p&gt;build-essential、autoconf、automake、cvs、subversion &lt;p&gt;apt-get install build-essential kernel-package libncurses5-dev &lt;p&gt;libncurses5這個軟件包在使用menuconfig配置內核的時候會用到。 &lt;p&gt;2.下載內核源碼 &lt;p&gt;使用uname -r 命令查看當前的內核版本號，我的是2.6.32-25-generic，使用apt-cache search linux-source查看軟件庫的源碼包，我查詢到的源碼包有:&lt;br&gt;linux-source - Linux kernel source with Ubuntu patches&lt;br&gt;linux-source-2.6.32 - Linux kernel source for version 2.6.32 with Ubuntu patches &lt;p&gt;我選擇linux-source-2.6.32 - Linux kernel source for version 2.6.32 with Ubuntu patches &lt;p&gt;sudo apt-get install linux-source-2.6.32 &lt;p&gt;下載好後cd /usr/src 目錄下就可以看見linux-source-2.6.32.tar.bz2,然後解壓到當前的目錄&lt;br&gt;sudo tar xjvf linux-source-2.6.32.tar.bz2 &lt;p&gt;解壓完畢，會生成linux-source-2.6.32目錄 &lt;p&gt;3.編譯內核源碼 &lt;p&gt;在編譯之前我們需要 Ubuntu原來內核的一個配置文件 &lt;p&gt;這是我/usr/src目錄下的文件預覽： &lt;p&gt;drwxr-xr-x&amp;nbsp; 4 root root&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4096 2010-09-04 21:31 fglrx-8.723.1&lt;br&gt;drwxr-xr-x 24 root root&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4096 2010-09-04 20:35 linux-headers-2.6.32-25&lt;br&gt;drwxr-xr-x&amp;nbsp; 7 root root&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4096 2010-09-04 20:35 linux-headers-2.6.32-25-generic&lt;br&gt;drwxr-xr-x 25 root root&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4096 2010-09-16 21:39 linux-source-2.6.32&lt;br&gt;-rw-r--r--&amp;nbsp; 1 root root 65846876 2010-09-01 22:41 linux-source-2.6.32.tar.bz2 &lt;p&gt;現在我們需要linux-headers-2.6.32-25-generic目錄下的.config文件，我們把它拷貝到我們剛下好解壓的目錄，也就是linux-source-2.6.32 &lt;p&gt;sudo cp /usr/src/linux-headers-2.6.32-25-generic/.config /usr/src/linux-2.6.32 &lt;p&gt;接下來切換到root用戶&lt;br&gt;sudo -i &lt;p&gt;cd /usr/src/linux-2.6.32 &lt;p&gt;make menuconfig &lt;p&gt;終端會彈出一個配置界面 &lt;p&gt;最後有兩項：load a kernel configuration... &lt;br&gt;save a kernel configuration... &lt;br&gt;選擇load a kernel configuration保存，然後在選擇save akernel configuration再保存退出，並退出配置環境。 &lt;p&gt;接下來我們開始編譯 &lt;p&gt;cd /usr/src/linux-2.6.32&lt;br&gt;make&lt;br&gt;記住一定要是管理員帳號運行,這個過程真的很久，如果你的cpu是雙核的可以在make後面加個參數,make -j4. &lt;p&gt;make bzImage 執行結束後，可以看到在當前目錄下生成了一個新的文件: vmlinux, 其屬性爲-rwxr-xr-x。 &lt;br&gt;make modules /* 編譯 模塊 */ &lt;br&gt;make modules_install&amp;nbsp; 這條命令能在/lib/modules目錄下產生一個目錄。 &lt;p&gt;4.測試驅動模塊 &lt;p&gt;這裏就抄個程序測試了，初學者顧不了那麽多了。 &lt;p&gt;我在 /home/shana/linux_q/ 目錄下創建2個文本文件 hello.c Makefile &lt;p&gt;//hello.c &lt;br&gt;#include &amp;lt;linux/init.h&amp;gt; &lt;br&gt;#include &amp;lt;linux/module.h&amp;gt; &lt;br&gt;MODULE_LICENSE("Dual BSD/GPL");&amp;nbsp; &lt;p&gt;static int hello_init(void) &lt;br&gt;{ &lt;br&gt;printk(KERN_ALERT "Hello, world\n"); &lt;br&gt;return 0; &lt;br&gt;} &lt;p&gt;static void hello_exit(void) &lt;br&gt;{ &lt;br&gt;printk(KERN_ALERT"Goodbye, cruel world\n"); &lt;br&gt;} &lt;p&gt;module_init(hello_init); &lt;br&gt;module_exit(hello_exit); &lt;p&gt;Makefile 文件 &lt;p&gt;obj-m := hello.o &lt;br&gt;KERNELDIR := /lib/modules/2.6.20/build &lt;br&gt;PWD := $(shell pwd) &lt;p&gt;modules: &lt;br&gt;$(MAKE) -C $(KERNELDIR) M=$(PWD) modules &lt;p&gt;modules_install: &lt;br&gt;$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install &lt;p&gt;需要註意的是makefile的格式$(MAKE)前面要加個tab.&lt;br&gt;make 編譯，產生如下文件:&lt;br&gt;hello.c&amp;nbsp;&amp;nbsp; hello.mod.c&amp;nbsp; hello.o&amp;nbsp;&amp;nbsp; modules.order&lt;br&gt;hello.ko&amp;nbsp; hello.mod.o&amp;nbsp; Makefile&amp;nbsp; Module.symvers &lt;p&gt;5.加載模塊到內核去 &lt;p&gt;sudo insmod ./hello.ko 這個命令把hello.ko加載到內核 &lt;p&gt;sudo rmmod hello 這個命令是把hello這個模塊移除掉 &lt;p&gt;lsmod 這個命令可以查看當前所有的驅動模塊 &lt;p&gt;程序的輸出結果可以在&lt;br&gt;/var/log/syslog文件中查看 &lt;p&gt;Sep 16 21:50:10 wuyangyu-desktop kernel: [10428.551271] Hello,World&lt;br&gt;Sep 16 21:55:45 wuyangyu-desktop kernel: [10763.644605] Goodbye,cruel world &lt;p&gt;這是程序的輸出。 &lt;p&gt;&amp;nbsp; &lt;p&gt;本文来自：&lt;a title="http://www.pyoix.com/a/735.html" href="http://www.pyoix.com/a/735.html"&gt;http://www.pyoix.com/a/735.html&lt;/a&gt; &lt;p&gt;收藏备查&lt;/p&gt;&lt;img src="http://www.cnblogs.com/khler/aggbug/1965256.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/khler/archive/2011/02/25/1965256.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/khler/archive/2011/02/25/1965248.html</id><title type="text">【转】Linux2.6.19内核源码目录树</title><summary type="text">[日期：2010-09-18]来源：Linux社区 作者：Linux 这里简单的介绍下Linux 2.6.19内核源代码（最新内核源代码可从这里下载）目录树结构。 arch：包含和硬件体系结构相关的代码，每种平台占一个相应的目录。和32位PC相关的代码存放在i386目录下，其中比较重要的包括kernel（内核核心部分）、mm（内存管理）、math-emu（浮点单元仿真）、lib（硬件相关工具函数...</summary><published>2011-02-25T10:00:00Z</published><updated>2011-02-25T10:00:00Z</updated><author><name>He,YuanHui</name><uri>http://www.cnblogs.com/khler/</uri></author><link rel="alternate" href="http://www.cnblogs.com/khler/archive/2011/02/25/1965248.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/khler/archive/2011/02/25/1965248.html"/><content type="html">&lt;p&gt;&lt;strong&gt;&amp;nbsp;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;[日期：2010-09-18]&lt;br&gt;来源：Linux社区&amp;nbsp; 作者：Linux &lt;p&gt;&lt;ins&gt;&lt;ins&gt;&lt;/ins&gt;&lt;/ins&gt; &lt;p&gt;这里简单的介绍下Linux 2.6.19内核源代码（最新内核源代码可从&lt;a href="http://www.kernel.org/"&gt;这里&lt;/a&gt;下载）目录树结构。 &lt;p&gt;arch：包含和硬件体系结构相关的代码，每种平台占一个相应的目录。和32位PC相关的代码存放在i386目录下，其中比较重要的包括kernel（内核核心部分）、mm（内存管理）、math-emu（浮点单元仿真）、lib（硬件相关工具函数）、boot（引导程序）、pci（PCI总线）和power（CPU相关状态）。 &lt;p&gt;block：部分块设备驱动程序。 &lt;p&gt;crypto：常用加密和散列算法（如AES、SHA等），还有一些压缩和CRC校验算法。 &lt;p&gt;Documentation：关于内核各部分的通用解释和注释。 &lt;p&gt;drivers：设备驱动程序，每个不同的驱动占用一个子目录。 &lt;p&gt;fs：各种支持的文件系统，如ext、fat、ntfs等。 &lt;p&gt;include：头文件。其中，和系统相关的头文件被放置在linux子目录下。 &lt;p&gt;init：内核初始化代码（注意不是系统引导代码）。 &lt;p&gt;ipc：进程间通信的代码。 &lt;p&gt;kernel：内核的最核心部分，包括进程调度、定时器等，和平台相关的一部分代码放在archmm目录下。 &lt;p&gt;net：网络相关代码，实现了各种常见的网络协议。 &lt;p&gt;scripts：用于配置内核文件的脚本文件。 &lt;p&gt;security：主要是一个SELinux的模块。 &lt;p&gt;sound：常用音频设备的驱动程序等。 &lt;p&gt;usr：实现了一个cpio。 &lt;p&gt;在i386体系下，系统引导将从arch/i386/kernel/head.s开始执行，并进而转移到init/main.c中的main()函数初始化内核。可按流程顺序进行阅读（主要数据结构定义要弄清），对于各模块代码粗略看看就可以了，重点应该放在你所要研究的那个方向。要知道，一个人掌握全部Linux内核源代码是很困难的！ &lt;p&gt;&amp;nbsp; &lt;p&gt;本文来自：&lt;a title="http://www.linuxidc.com/Linux/2010-09/28674.htm" href="http://www.linuxidc.com/Linux/2010-09/28674.htm"&gt;http://www.linuxidc.com/Linux/2010-09/28674.htm&lt;/a&gt;&lt;img src="http://www.cnblogs.com/khler/aggbug/1965248.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/khler/archive/2011/02/25/1965248.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/khler/archive/2011/02/25/1965246.html</id><title type="text">【转】Ubuntu学习---编译源码包</title><summary type="text">以tree实用程序（以树型结构获取目录树）为例，介绍Ubuntu中如何管理源码包，包括查询，获取，编译源码包，直至安装。 1） 在获取源码包之前，确保在软件源配置文件/etc/apt/sources.list中添加了deb-src项 2） 使用如下命令获取tree源码包的详细信息: sudo apt-cache showsrc tree 这用来查询当前镜像站点中是否有该源码包。 3)源码包中通常...</summary><published>2011-02-25T09:59:00Z</published><updated>2011-02-25T09:59:00Z</updated><author><name>He,YuanHui</name><uri>http://www.cnblogs.com/khler/</uri></author><link rel="alternate" href="http://www.cnblogs.com/khler/archive/2011/02/25/1965246.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/khler/archive/2011/02/25/1965246.html"/><content type="html">&lt;p&gt;&lt;strong&gt;&amp;nbsp;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;以tree实用程序（以树型结构获取目录树）为例，介绍Ubuntu中如何管理源码包，包括查询，获取，编译源码包，直至安装。  &lt;p&gt;1） 在获取源码包之前，确保在软件源配置文件/etc/apt/sources.list中添加了deb-src项  &lt;p&gt;2） 使用如下命令获取tree源码包的详细信息:  &lt;p&gt;sudo apt-cache showsrc tree  &lt;p&gt;这用来查询当前镜像站点中是否有该源码包。  &lt;p&gt;3)源码包中通常包含3个文件，分别以dsc，orig.tar.gz和diff.gz为后缀名。使用”apt-get source”命令来获取源码包，它会将源码包下载到用户当前目录，并在命令执行过程中，调用dpkg-source命令，根据dsc文件中的信息，将源码包解压到同名目录中，应用程序的源代码就在这里面。  &lt;p&gt;sudo apt-get source tree  &lt;p&gt;要强调的是，在下载源码包前，必须确保安装了dpkg-dev（执行”apt-get install dpkg-dev”来安装），否则，只会下载源码包的3个文件，但不会解压缩源码包。当然你也可以自己用dpkg-source命令去解压缩源码包。  &lt;p&gt;4)在编译源码包前，需要安装具有依赖关系的相关软件包。使用”apt-get build-dep”命令可以主动获取并安装所有相关的软件包。  &lt;p&gt;sudo apt-get build-dep tree  &lt;p&gt;5)现在可以来编译源码包了，首先进入源码所在目录，使用dpkg-buildpackage命令来编译源码包，它会将生成的Deb软件包放置在上层目录中。  &lt;p&gt;cd tree-1.5.1.2&lt;br&gt;sudo dpkg-buildpackage  &lt;p&gt;这样就会编译生成tree-1.5.1.2-1_i386.deb  &lt;p&gt;6)安装软件包。使用”dpkg –i”命令来安装生成的Deb软件包。  &lt;p&gt;sudo dpkg –I tree-1.5.1.2-1_i386.deb  &lt;p&gt;7)测试tree程序，我们用它来查看编译所在工作目录的内容。  &lt;p&gt;tree –L 2  &lt;p&gt;作者：&lt;a href="http://phinecos.cnblogs.com/"&gt;洞庭散人&lt;/a&gt;  &lt;p&gt;出处：&lt;a href="http://phinecos.cnblogs.com/"&gt;http://phinecos.cnblogs.com/&lt;/a&gt;  &lt;p&gt;本博客遵从&lt;u&gt;&lt;a href="http://creativecommons.org/licenses/by-nc-sa/3.0/"&gt;Creative Commons Attribution 3.0 License&lt;/a&gt;&lt;/u&gt;，若用于非商业目的，您可以自由转载，但请保留原作者信息和文章链接URL。  &lt;img src="http://www.cnblogs.com/khler/aggbug/1965246.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/khler/archive/2011/02/25/1965246.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/khler/archive/2011/02/25/1965227.html</id><title type="text">【转】Linux 2.6.3x内核源码编译和安装</title><summary type="text">[日期：2011-02-25]来源：Linux社区 作者：wdwbw 新版本Linux内核的编译特别简单下载内核并解压后，先进行配置make menuconfig注意要选择General Setup-&gt; enable deprecated sysfs features to support old...(即CONFIG_SYSFS_DEPRECATED_V2)，否则会报错“mount:could...</summary><published>2011-02-25T09:38:00Z</published><updated>2011-02-25T09:38:00Z</updated><author><name>He,YuanHui</name><uri>http://www.cnblogs.com/khler/</uri></author><link rel="alternate" href="http://www.cnblogs.com/khler/archive/2011/02/25/1965227.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/khler/archive/2011/02/25/1965227.html"/><content type="html">&lt;p&gt;&lt;strong&gt;&amp;nbsp;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;[日期：2011-02-25]&lt;br&gt;来源：Linux社区&amp;nbsp; 作者：wdwbw &lt;p&gt;&lt;ins&gt;&lt;ins&gt;&lt;/ins&gt;&lt;/ins&gt; &lt;p&gt;新版本Linux内核的编译特别简单&lt;br&gt;下载内核并解压后，先进行配置&lt;br&gt;make menuconfig&lt;br&gt;注意要选择General Setup-&amp;gt; enable deprecated sysfs features to support old...(即CONFIG_SYSFS_DEPRECATED_V2)，否则会报错“mount:could not find filesystem ‘/dev/root’” &lt;p&gt;然后&lt;br&gt;make &lt;p&gt;再后（如果原有版本与此相同，先备份/lib/modules下该版本）&lt;br&gt;make modules_install &lt;p&gt;最后，备份/boot下现有内容，再执行&lt;br&gt;make install &lt;p&gt;有些机器启动会报重复插入dm-region-hash.ko模块&lt;br&gt;解决方法如下 &lt;p&gt;解压修改内核：&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; cd /tmp/&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; mkdir newinitrd&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; cd newinitrd/&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; zcat /boot/initrd-2.6.35.1.img |cpio -i &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; vim init&lt;br&gt;找到这2段一样的，去掉其中1段重复的： &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; echo “Loading dm-region-hash.ko module”&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; insmod /lib/dm-region-hash.ko&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; echo “Loading dm-region-hash.ko module”&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; insmod /lib/dm-region-hash.ko &lt;p&gt;从新打包新内核： &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; find .|cpio -c -o &amp;gt; ../initrd&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; cd ../&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; gzip -9 &amp;lt; initrd &amp;gt; initrd-2.6.35.1.img&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; rm -fr /boot/initrd-2.6.35.1.img&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; cp initrd-2.6.35.1.img /boot &lt;p&gt;重启验证 &lt;p&gt;&amp;nbsp; &lt;p&gt;本文来自：&lt;a title="http://www.linuxidc.com/Linux/2011-02/32672.htm" href="http://www.linuxidc.com/Linux/2011-02/32672.htm"&gt;http://www.linuxidc.com/Linux/2011-02/32672.htm&lt;/a&gt;&lt;img src="http://www.cnblogs.com/khler/aggbug/1965227.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/khler/archive/2011/02/25/1965227.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/khler/archive/2011/02/25/1965218.html</id><title type="text">【转】Linux内核源码树学习：Kconfig和Makefile</title><summary type="text">[日期：2009-11-29] 作者：张成 Linux内核源码树的每个目录下都有两个文档Kconfig和Makefile。分布到各目录的Kconfig构成了一个分布式的内核配置数据库，每个Kconfig分别描述了所属目录源文档相关的内核配置菜单。在执行内核配置make menuconfig时，从Kconfig中读出菜单，用户选择后保存到.config的内核配置文档中。在内核编译时，主Makefil...</summary><published>2011-02-25T09:34:00Z</published><updated>2011-02-25T09:34:00Z</updated><author><name>He,YuanHui</name><uri>http://www.cnblogs.com/khler/</uri></author><link rel="alternate" href="http://www.cnblogs.com/khler/archive/2011/02/25/1965218.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/khler/archive/2011/02/25/1965218.html"/><content type="html">&lt;p&gt;[日期：2009-11-29]  &lt;p&gt;作者：张成  &lt;p&gt;&lt;ins&gt;&lt;ins&gt;&lt;/ins&gt;&lt;/ins&gt; &lt;p&gt;Linux内核源码树的每个目录下都有两个文档Kconfig和Makefile。分布到各目录的Kconfig构成了一个分布式的内核配置数据库，每个Kconfig分别描述了所属目录源文档相关的内核配置菜单。在执行内核配置make menuconfig时，从Kconfig中读出菜单，用户选择后保存到.config的内核配置文档中。在内核编译时，主Makefile调用这个.config，就知道了用户的选择。这个内容说明了，Kconfig就是对应着内核的每级配置菜单。  &lt;p&gt;假如要想添加新的驱动到内核的源码中，要修改Kconfig,这样就能够选择这个驱动，假如想使这个驱动被编译，则要修改Makefile。添加新的驱动时需要修改的文档有两种（如果添加的只是文件，则只需修改当前层Kconfig和Makefile文件；如果添加的是目录，则需修改当前层和目录下的共一对Kconfig和Makefile）Kconfig和Makefile。要想知道怎么修改这两种文档，就要知道两种文档的语法结构。  &lt;p&gt;Kconfig：每个菜单都有一个关键字标识，最常见的就是config。语法：config symbol，是个新的标记的菜单项，options是在这个新的菜单项下的属性和选项。  &lt;p&gt;1，每个config菜单项都要有类型定义，bool布尔类型、 tristate三态：内建、模块、移除。bool类型的只能选中或不选中，tristate类型的菜单项多了编译成内核模块的选项，假如选择编译成内核模块，则会在.config中生成一个CONFIG_HELLO_MODULE=m的配置；假如选择内建，就是直接编译成内核映像，就会在.config中生成一个CONFIG_HELLO_MODULE=y的配置。  &lt;p&gt;2，依赖型定义depends on或requires，指此菜单的出现和否依赖于另一个定义  &lt;p&gt;config HELLO_MODULE  &lt;p&gt;bool "hello test module"  &lt;p&gt;depends on ARCH_PXA  &lt;p&gt;这个例子表明HELLO_MODULE这个菜单项只对XScale处理器有效。  &lt;p&gt;3，帮助性定义  &lt;p&gt;只是增加帮助用关键字help或---help---。  &lt;p&gt;举一个完整实例如下，例如添加一个I2C芯片：  &lt;p&gt;config QL_VEE  &lt;p&gt;tristate "QL Visual Enhancement Engine (VEE)"  &lt;p&gt;default y  &lt;p&gt;depends on I2C &amp;amp;&amp;amp; EXPERIMENTAL  &lt;p&gt;help  &lt;p&gt;QL Visual Enhancement Engine (VEE) v1.0 with I2C-Compatible Interface and 24-Bit RGB Support Rev.  &lt;p&gt;Makefile：内核的Makefile分为5个组成部分：  &lt;p&gt;（1）Makefile&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 最顶层的Makefile  &lt;p&gt;（2）.config&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 内核的当前配置文档，编译时成为顶层Makefile的一部分  &lt;p&gt;（3）arch/$(ARCH)/Makefile&amp;nbsp;&amp;nbsp;&amp;nbsp; 和体系结构相关的Makefile  &lt;p&gt;（4）Makefile.*&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 一些特定Makefile的规则  &lt;p&gt;（5）kbuild级别Makefile&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 各级目录下的大概约500个文档，编译时根据上层Makefile传下来的宏定义和其他编译规则，将源代码编译成模块或编入内核。顶层的Makefile文档读取.config文档的内容，并总体上负责build内核和模块。Arch Makefile则提供补充体系结构相关的信息。其中.config的内容是在make menuconfig的时候，通过Kconfig文档配置的结果。  &lt;p&gt;假设想把自己写的一个flash的驱动程式加载到工程中，而且能够通过menuconfig配置内核时选择该驱动该怎么办呢？如下：  &lt;p&gt;第一：将您写的flashtest.c 文档添加到/driver/mtd/maps/ 目录下。  &lt;p&gt;第二：修改/driver/mtd/maps目录下的kconfig文档：  &lt;p&gt;config MTD_flashtest  &lt;p&gt;tristate “ap71 flash"  &lt;p&gt;这样当make menuconfig时 ，将会出现 ap71 flash选项。  &lt;p&gt;第三：修改该目录下makefile文档。添加如下内容：obj-$(CONFIG_MTD_flashtest)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; += flashtest.o  &lt;p&gt;这样，当您运行make menucofnig时，您将发现ap71 flash选项，假如您选择了此项。该选择就会保存在.config文档中。当您编译内核时，将会读取.config文档，当发现ap71 flash 选项为yes，系统在调用/driver/mtd/maps/下的makefile 时，将会把 flashtest.o 加入到内核中。  &lt;p&gt;&amp;nbsp; &lt;p&gt;本文来自：&lt;a title="http://www.linuxidc.com/Linux/2009-11/23091p3.htm" href="http://www.linuxidc.com/Linux/2009-11/23091p3.htm"&gt;http://www.linuxidc.com/Linux/2009-11/23091p3.htm&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/khler/aggbug/1965218.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/khler/archive/2011/02/25/1965218.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/khler/archive/2011/02/25/1965214.html</id><title type="text">用于主题检测的临时日志(18aafc4f-4072-403c-a52f-7860bea590e1 - 3bfe001a-32de-4114-a6b4-4005b770f6d7)</title><summary type="text">这是一个未删除的临时日志。请手动删除它。(94b7086f-7e57-4b30-bed3-ff4e669d3e35 - 3bfe001a-32de-4114-a6b4-4005b770f6d7)</summary><published>2011-02-25T09:29:00Z</published><updated>2011-02-25T09:29:00Z</updated><author><name>He,YuanHui</name><uri>http://www.cnblogs.com/khler/</uri></author><link rel="alternate" href="http://www.cnblogs.com/khler/archive/2011/02/25/1965214.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/khler/archive/2011/02/25/1965214.html"/><content type="html">&lt;p&gt;这是一个未删除的临时日志。请手动删除它。(94b7086f-7e57-4b30-bed3-ff4e669d3e35 - 3bfe001a-32de-4114-a6b4-4005b770f6d7)&lt;/p&gt;&lt;img src="http://www.cnblogs.com/khler/aggbug/1965214.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/khler/archive/2011/02/25/1965214.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/khler/archive/2011/02/25/1964789.html</id><title type="text">VC MFC程序，在About对话框中获取并显示程序的版本号</title><summary type="text">=================================================本文为HeYuanHui原作转载必须确保本文完整并完整保留原作者信息及本文原始链接!NN: khlerE-mail: khler@163.comQQ:23381103MSN:pragmac@hotmail.com================================================= 用VC++写的MFC程序，不管是exe的或者dll，都有个'VERSION'资源，在里面可以指定程序的版本号，这样在程序文件上右键点击，查看属性，就可以看到内嵌的版本信息了。</summary><published>2011-02-25T05:44:00Z</published><updated>2011-02-25T05:44:00Z</updated><author><name>He,YuanHui</name><uri>http://www.cnblogs.com/khler/</uri></author><link rel="alternate" href="http://www.cnblogs.com/khler/archive/2011/02/25/1964789.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/khler/archive/2011/02/25/1964789.html"/><content type="html">&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;font face="Verdana"&gt;&lt;em&gt;=================================================&lt;br /&gt;&lt;/em&gt;&lt;/font&gt;&lt;font face="Verdana"&gt;&lt;em&gt;本文为&lt;em&gt;HeYuanHui&lt;/em&gt;原作&lt;/em&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Verdana"&gt;&lt;em&gt;转载必须确保本文完整并完整保留原作者信息及本文原始链接!&lt;/em&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Verdana"&gt;&lt;em&gt;&lt;em&gt;NN:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; khler&lt;/em&gt;&lt;br /&gt;&lt;/em&gt;&lt;/font&gt;&lt;font face="Verdana"&gt;&lt;em&gt;E-mail: &lt;/em&gt;&lt;a href="&amp;#109;&amp;#97;&amp;#105;&amp;#108;&amp;#116;&amp;#111;&amp;#58;&amp;#107;&amp;#104;&amp;#108;&amp;#101;&amp;#114;&amp;#64;&amp;#49;&amp;#54;&amp;#51;&amp;#46;&amp;#99;&amp;#111;&amp;#109;" target="_blank"&gt;&lt;em&gt;khler@163.com&lt;/em&gt;&lt;/a&gt;&lt;br /&gt;&lt;/font&gt;&lt;font face="Verdana"&gt;&lt;em&gt;QQ:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;23381103&lt;br /&gt;&lt;/em&gt;&lt;/font&gt;&lt;font face="Verdana"&gt;&lt;em&gt;MSN:&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/em&gt;&lt;a href="&amp;#109;&amp;#97;&amp;#105;&amp;#108;&amp;#116;&amp;#111;&amp;#58;&amp;#112;&amp;#114;&amp;#97;&amp;#103;&amp;#109;&amp;#97;&amp;#99;&amp;#64;&amp;#104;&amp;#111;&amp;#116;&amp;#109;&amp;#97;&amp;#105;&amp;#108;&amp;#46;&amp;#99;&amp;#111;&amp;#109;"&gt;&lt;em&gt;pragmac@hotmail.com&lt;/em&gt;&lt;/a&gt;&lt;br /&gt;&lt;/font&gt;&lt;font face="Verdana"&gt;&lt;font face="Verdana"&gt;&lt;em&gt;=================================================&lt;/em&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 用VC++写的MFC程序，不管是exe的或者dll，都有个'VERSION'资源，在里面可以指定程序的版本号，这样在程序文件上右键点击，查看属性，就可以看到内嵌的版本信息了。同样，所有程序都愿意在'About'对话框中显示程序的当前版本，但是这里如何显示，跟资源里的'VERSION'信息还是有好几毛钱的关系呢 ：）&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 如果我们从'VERSION'资源里获取版本信息并在about对话框中显示，那么我们每次发布的时候只要修改'VERSION'里的信息就行了，经过一定处理，就可以在about对话框中显示了。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 其实MSDN中也有说明，但是说实话，要想从'VERSION'中读取信息，还真不是件简单的事情，下面一一实现，代码大部分来自MSDN。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 结果如下图所示：&lt;/p&gt;&lt;p&gt;&lt;img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/khler/about.png" width="412" height="241" /&gt;&lt;/p&gt;&lt;p&gt;显示1.1.6 build 718&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 代码：&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding:10px;"&gt;&lt;div&gt;&lt;span style="color: #0000ff"&gt;void&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;CAboutDlg::OnShowWindow(BOOL&amp;nbsp;bShow,&amp;nbsp;UINT&amp;nbsp;nStatus)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;CDialog::OnShowWindow(bShow,&amp;nbsp;nStatus);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #008000"&gt;//&lt;/span&gt;&lt;span style="color: #008000"&gt;&amp;nbsp;TODO:&amp;nbsp;在此处添加消息处理程序代码&lt;/span&gt;&lt;span style="color: #008000"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000"&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;CString&amp;nbsp;ver&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000"&gt;=&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;GetAppVersion(L&lt;/span&gt;&lt;span style="color: #800000"&gt;"&lt;/span&gt;&lt;span style="color: #800000"&gt;TowerWatch.exe&lt;/span&gt;&lt;span style="color: #800000"&gt;"&lt;/span&gt;&lt;span style="color: #000000"&gt;);&lt;br /&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;if&lt;/span&gt;&lt;span style="color: #000000"&gt;(ver.IsEmpty())&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;return&lt;/span&gt;&lt;span style="color: #000000"&gt;;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;int&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;pos&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000"&gt;=&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;ver.ReverseFind(&lt;/span&gt;&lt;span style="color: #800000"&gt;'&lt;/span&gt;&lt;span style="color: #800000"&gt;.&lt;/span&gt;&lt;span style="color: #800000"&gt;'&lt;/span&gt;&lt;span style="color: #000000"&gt;);&lt;br /&gt;&amp;nbsp;CString&amp;nbsp;mainVer&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000"&gt;=&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;ver.Left(pos);&lt;br /&gt;&amp;nbsp;CString&amp;nbsp;build&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000"&gt;=&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;ver.Right(ver.GetLength()&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000"&gt;-&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;pos&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000"&gt;-&lt;/span&gt;&lt;span style="color: #800080"&gt;1&lt;/span&gt;&lt;span style="color: #000000"&gt;);&lt;br /&gt;&amp;nbsp;GetDlgItem(IDC_STATIC_VER)&lt;/span&gt;&lt;span style="color: #000000"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color: #000000"&gt;SetWindowText(mainVer);&lt;br /&gt;&amp;nbsp;GetDlgItem(IDC_STATIC_BUILD)&lt;/span&gt;&lt;span style="color: #000000"&gt;-&amp;gt;&lt;/span&gt;&lt;span style="color: #000000"&gt;SetWindowText(build);&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;void&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;ErrorExit(LPTSTR&amp;nbsp;lpszFunction)&amp;nbsp;&lt;br /&gt;{&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #008000"&gt;//&lt;/span&gt;&lt;span style="color: #008000"&gt;&amp;nbsp;Retrieve&amp;nbsp;the&amp;nbsp;system&amp;nbsp;error&amp;nbsp;message&amp;nbsp;for&amp;nbsp;the&amp;nbsp;last-error&amp;nbsp;code&lt;/span&gt;&lt;span style="color: #008000"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000"&gt;&lt;br /&gt;&amp;nbsp;LPVOID&amp;nbsp;lpMsgBuf;&lt;br /&gt;&amp;nbsp;LPVOID&amp;nbsp;lpDisplayBuf;&lt;br /&gt;&amp;nbsp;DWORD&amp;nbsp;dw&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000"&gt;=&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;GetLastError();&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;FormatMessage(&lt;br /&gt;&amp;nbsp;&amp;nbsp;FORMAT_MESSAGE_ALLOCATE_BUFFER&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000"&gt;|&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;FORMAT_MESSAGE_FROM_SYSTEM&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000"&gt;|&lt;/span&gt;&lt;span style="color: #000000"&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;FORMAT_MESSAGE_IGNORE_INSERTS,&lt;br /&gt;&amp;nbsp;&amp;nbsp;NULL,&lt;br /&gt;&amp;nbsp;&amp;nbsp;dw,&lt;br /&gt;&amp;nbsp;&amp;nbsp;MAKELANGID(LANG_NEUTRAL,&amp;nbsp;SUBLANG_DEFAULT),&lt;br /&gt;&amp;nbsp;&amp;nbsp;(LPTSTR)&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color: #000000"&gt;lpMsgBuf,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #800080"&gt;0&lt;/span&gt;&lt;span style="color: #000000"&gt;,&amp;nbsp;NULL&amp;nbsp;);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #008000"&gt;//&lt;/span&gt;&lt;span style="color: #008000"&gt;&amp;nbsp;Display&amp;nbsp;the&amp;nbsp;error&amp;nbsp;message&amp;nbsp;and&amp;nbsp;exit&amp;nbsp;the&amp;nbsp;process&lt;/span&gt;&lt;span style="color: #008000"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000"&gt;&lt;br /&gt;&amp;nbsp;lpDisplayBuf&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000"&gt;=&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;(LPVOID)LocalAlloc(LMEM_ZEROINIT,&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;(lstrlen((LPCTSTR)lpMsgBuf)&lt;/span&gt;&lt;span style="color: #000000"&gt;+&lt;/span&gt;&lt;span style="color: #000000"&gt;lstrlen((LPCTSTR)lpszFunction)&lt;/span&gt;&lt;span style="color: #000000"&gt;+&lt;/span&gt;&lt;span style="color: #800080"&gt;40&lt;/span&gt;&lt;span style="color: #000000"&gt;)&lt;/span&gt;&lt;span style="color: #000000"&gt;*&lt;/span&gt;&lt;span style="color: #0000ff"&gt;sizeof&lt;/span&gt;&lt;span style="color: #000000"&gt;(TCHAR));&amp;nbsp;&lt;br /&gt;&amp;nbsp;StringCchPrintf((LPTSTR)lpDisplayBuf,&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;LocalSize(lpDisplayBuf),&lt;br /&gt;&amp;nbsp;&amp;nbsp;TEXT(&lt;/span&gt;&lt;span style="color: #800000"&gt;"&lt;/span&gt;&lt;span style="color: #800000"&gt;%s&amp;nbsp;failed&amp;nbsp;with&amp;nbsp;error&amp;nbsp;%d:&amp;nbsp;%s&lt;/span&gt;&lt;span style="color: #800000"&gt;"&lt;/span&gt;&lt;span style="color: #000000"&gt;),&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;lpszFunction,&amp;nbsp;dw,&amp;nbsp;lpMsgBuf);&amp;nbsp;&lt;br /&gt;&amp;nbsp;MessageBox(NULL,&amp;nbsp;(LPCTSTR)lpDisplayBuf,&amp;nbsp;TEXT(&lt;/span&gt;&lt;span style="color: #800000"&gt;"&lt;/span&gt;&lt;span style="color: #800000"&gt;Error&lt;/span&gt;&lt;span style="color: #800000"&gt;"&lt;/span&gt;&lt;span style="color: #000000"&gt;),&amp;nbsp;MB_OK);&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;LocalFree(lpMsgBuf);&lt;br /&gt;&amp;nbsp;LocalFree(lpDisplayBuf);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;CString&amp;nbsp;CAboutDlg::GetAppVersion(WCHAR&lt;/span&gt;&lt;span style="color: #000000"&gt;*&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;AppName)&amp;nbsp;&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;CString&amp;nbsp;&amp;nbsp;&amp;nbsp;AppVersion;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;DWORD&amp;nbsp;&amp;nbsp;&amp;nbsp;RessourceVersionInfoSize;&amp;nbsp;&lt;br /&gt;&amp;nbsp;DWORD&amp;nbsp;&amp;nbsp;&amp;nbsp;JustAJunkVariabel;&amp;nbsp;&lt;br /&gt;&amp;nbsp;WCHAR&lt;/span&gt;&lt;span style="color: #000000"&gt;*&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;VersionInfoPtr;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;struct&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;LANGANDCODEPAGE&lt;br /&gt;&amp;nbsp;{&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;WORD&amp;nbsp;&amp;nbsp;&amp;nbsp;wLanguage;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;WORD&amp;nbsp;&amp;nbsp;&amp;nbsp;wCodePage;&amp;nbsp;&lt;br /&gt;&amp;nbsp;}&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000"&gt;*&lt;/span&gt;&lt;span style="color: #000000"&gt;TranslationPtr;&amp;nbsp;&lt;br /&gt;&amp;nbsp;WCHAR&lt;/span&gt;&lt;span style="color: #000000"&gt;*&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;InformationPtr;&amp;nbsp;&lt;br /&gt;&amp;nbsp;UINT&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;VersionInfoSize;&amp;nbsp;&lt;br /&gt;&amp;nbsp;WCHAR&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;VersionValue[&lt;/span&gt;&lt;span style="color: #800080"&gt;255&lt;/span&gt;&lt;span style="color: #000000"&gt;];&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;RessourceVersionInfoSize&lt;/span&gt;&lt;span style="color: #000000"&gt;=&lt;/span&gt;&lt;span style="color: #000000"&gt;GetFileVersionInfoSize(AppName,&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color: #000000"&gt;JustAJunkVariabel);&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;if&lt;/span&gt;&lt;span style="color: #000000"&gt;(&lt;/span&gt;&lt;span style="color: #800080"&gt;0&lt;/span&gt;&lt;span style="color: #000000"&gt;!=&lt;/span&gt;&lt;span style="color: #000000"&gt;RessourceVersionInfoSize)&amp;nbsp;&lt;br /&gt;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;VersionInfoPtr&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000"&gt;=&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;new&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;WCHAR[RessourceVersionInfoSize];&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;if&lt;/span&gt;&lt;span style="color: #000000"&gt;(&lt;/span&gt;&lt;span style="color: #000000"&gt;!&lt;/span&gt;&lt;span style="color: #000000"&gt;GetFileVersionInfo(AppName,&lt;/span&gt;&lt;span style="color: #800080"&gt;0&lt;/span&gt;&lt;span style="color: #000000"&gt;,RessourceVersionInfoSize,VersionInfoPtr))&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ErrorExit((LPTSTR)L&lt;/span&gt;&lt;span style="color: #800000"&gt;"&lt;/span&gt;&lt;span style="color: #800000"&gt;GetFileVersionInfo&lt;/span&gt;&lt;span style="color: #800000"&gt;"&lt;/span&gt;&lt;span style="color: #000000"&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;delete[]&amp;nbsp;&amp;nbsp;&amp;nbsp;VersionInfoPtr;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;return&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;NULL;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;if&lt;/span&gt;&lt;span style="color: #000000"&gt;(&lt;/span&gt;&lt;span style="color: #000000"&gt;!&lt;/span&gt;&lt;span style="color: #000000"&gt;VerQueryValue(&amp;nbsp;VersionInfoPtr,&amp;nbsp;L&lt;/span&gt;&lt;span style="color: #800000"&gt;"&lt;/span&gt;&lt;span style="color: #800000"&gt;VarFileInfo\\Translation&lt;/span&gt;&lt;span style="color: #800000"&gt;"&lt;/span&gt;&lt;span style="color: #000000"&gt;,&amp;nbsp;(LPVOID&lt;/span&gt;&lt;span style="color: #000000"&gt;*&lt;/span&gt;&lt;span style="color: #000000"&gt;)&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color: #000000"&gt;TranslationPtr,&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color: #000000"&gt;VersionInfoSize))&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;{&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;ErrorExit((LPTSTR)L&lt;/span&gt;&lt;span style="color: #800000"&gt;"&lt;/span&gt;&lt;span style="color: #800000"&gt;VerQueryValue&lt;/span&gt;&lt;span style="color: #800000"&gt;"&lt;/span&gt;&lt;span style="color: #000000"&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;delete[]&amp;nbsp;&amp;nbsp;&amp;nbsp;VersionInfoPtr;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;return&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;NULL;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #008000"&gt;//&lt;/span&gt;&lt;span style="color: #008000"&gt;&amp;nbsp;retrieve&amp;nbsp;product&amp;nbsp;version&lt;/span&gt;&lt;span style="color: #008000"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;&amp;nbsp;wsprintf(VersionValue,&amp;nbsp;L&lt;/span&gt;&lt;span style="color: #800000"&gt;"&lt;/span&gt;&lt;span style="color: #800000"&gt;\\StringFileInfo\\%04x%04x\\ProductVersion&lt;/span&gt;&lt;span style="color: #800000"&gt;"&lt;/span&gt;&lt;span style="color: #000000"&gt;,&amp;nbsp;TranslationPtr[&lt;/span&gt;&lt;span style="color: #800080"&gt;0&lt;/span&gt;&lt;span style="color: #000000"&gt;].wLanguage,&amp;nbsp;TranslationPtr[&lt;/span&gt;&lt;span style="color: #800080"&gt;0&lt;/span&gt;&lt;span style="color: #000000"&gt;].wCodePage);&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;if&lt;/span&gt;&lt;span style="color: #000000"&gt;(&lt;/span&gt;&lt;span style="color: #000000"&gt;!&lt;/span&gt;&lt;span style="color: #000000"&gt;VerQueryValue(&amp;nbsp;VersionInfoPtr,&amp;nbsp;VersionValue,&amp;nbsp;(LPVOID&lt;/span&gt;&lt;span style="color: #000000"&gt;*&lt;/span&gt;&lt;span style="color: #000000"&gt;)&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color: #000000"&gt;InformationPtr,&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color: #000000"&gt;VersionInfoSize))&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;{&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;ErrorExit((LPTSTR)L&lt;/span&gt;&lt;span style="color: #800000"&gt;"&lt;/span&gt;&lt;span style="color: #800000"&gt;VerQueryValue&lt;/span&gt;&lt;span style="color: #800000"&gt;"&lt;/span&gt;&lt;span style="color: #000000"&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;delete[]&amp;nbsp;&amp;nbsp;&amp;nbsp;VersionInfoPtr;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;return&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;NULL;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;if&lt;/span&gt;&lt;span style="color: #000000"&gt;(wcslen(InformationPtr)&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #800080"&gt;0&lt;/span&gt;&lt;span style="color: #000000"&gt;)&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #008000"&gt;//&lt;/span&gt;&lt;span style="color: #008000"&gt;Not&amp;nbsp;&amp;nbsp;&amp;nbsp;Null&amp;nbsp;&lt;/span&gt;&lt;span style="color: #008000"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;&amp;nbsp;{&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;AppVersion&lt;/span&gt;&lt;span style="color: #000000"&gt;=&lt;/span&gt;&lt;span style="color: #000000"&gt;CString(InformationPtr);&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;delete[]&amp;nbsp;&amp;nbsp;&amp;nbsp;VersionInfoPtr;&amp;nbsp;&lt;br /&gt;&amp;nbsp;}&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;return&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;AppVersion;&amp;nbsp;&lt;br /&gt;}&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;当然，你可以将分解Version和build部分代码也封装到GetAppVersion函数中。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;img src="http://www.cnblogs.com/khler/aggbug/1964789.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/khler/archive/2011/02/25/1964789.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/khler/archive/2011/02/21/1959384.html</id><title type="text">u－boot 移植步骤详解</title><summary type="text">u－boot 移植步骤详解 2008-05-17 19:53:421 U-Boot简介U-Boot，全称Universal Boot Loader，是遵循GPL条款的开放源码项目。从FADSROM、8xxROM、PPCBOOT逐步发展演化而来。其源码目录、编译形式与Linux内核很相似，事实上，不少U-Boot源码就是相应的Linux内核源程序的简化，尤其是一些设备的驱动程序，这从U-Boot源码的注释中能体现这一点。但是U-Boot不仅仅支持嵌入式Linux系统的引导，当前，它还支持NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS嵌入式操作系统。其目前要支</summary><published>2011-02-20T16:45:00Z</published><updated>2011-02-20T16:45:00Z</updated><author><name>He,YuanHui</name><uri>http://www.cnblogs.com/khler/</uri></author><link rel="alternate" href="http://www.cnblogs.com/khler/archive/2011/02/21/1959384.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/khler/archive/2011/02/21/1959384.html"/><content type="html">u－boot 移植步骤详解 &lt;div class="date"&gt;2008-05-17 19:53:42&lt;/div&gt;&lt;table style="table-layout: fixed"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;div class="cnt"&gt;&lt;p&gt;1 U-Boot简介&lt;br /&gt;U-Boot，全称Universal Boot Loader，是遵循GPL条款的开放源码项目。从FADSROM、8xxROM、PPCBOOT逐步发展演化而来。其源码目录、编译形式与Linux内核很相似，事实上，不少U-Boot源码就是相应的Linux内核源程序的简化，尤其是一些设备的驱动程序，这从U-Boot源码的注释中能体现这一点。但是U-Boot不仅仅支持嵌入式Linux系统的引导，当前，它还支持NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS嵌入式操作系统。其目前要支持的目标操作系统是OpenBSD, NetBSD, FreeBSD,4.4BSD, Linux, SVR4, Esix, Solaris, Irix, SCO, Dell, NCR, VxWorks, LynxOS, pSOS, QNX, RTEMS, ARTOS。这是U-Boot中Universal的一层含义，另外一层含义则是U-Boot除了支持PowerPC系列的处理器外，还能支持MIPS、x86、ARM、NIOS、XScale等诸多常用系列的处理器。这两个特点正是U-Boot项目的开发目标，即支持尽可能多的嵌入式处理器和嵌入式操作系统。就目前来看，U-Boot对PowerPC系列处理器支持最为丰富，对Linux的支持最完善。其它系列的处理器和操作系统基本是在2002年11月PPCBOOT改名为U-Boot后逐步扩充的。从PPCBOOT向U-Boot的顺利过渡，很大程度上归功于U-Boot的维护人德国DENX软件工程中心Wolfgang Denk[以下简称W.D]本人精湛专业水平和持着不懈的努力。当前，U-Boot项目正在他的领军之下，众多有志于开放源码BOOT LOADER移植工作的嵌入式开发人员正如火如荼地将各个不同系列嵌入式处理器的移植工作不断展开和深入，以支持更多的嵌入式操作系统的装载与引导。&lt;br /&gt;选择U-Boot的理由：&lt;br /&gt;&amp;#9312; 开放源码；&lt;br /&gt;&amp;#9313; 支持多种嵌入式操作系统内核，如Linux、NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS；&lt;br /&gt;&amp;#9314; 支持多个处理器系列，如PowerPC、ARM、x86、MIPS、XScale；&lt;br /&gt;&amp;#9315; 较高的可靠性和稳定性；&lt;br /&gt;&amp;#9315; 较高的可靠性和稳定性；&lt;br /&gt;&amp;#9316; 高度灵活的功能设置，适合U-Boot调试、操作系统不同引导要求、产品发布等；&lt;br /&gt;&amp;#9317; 丰富的设备驱动源码，如串口、以太网、SDRAM、FLASH、LCD、NVRAM、EEPROM、RTC、键盘等；&lt;br /&gt;&amp;#9318; 较为丰富的开发调试文档与强大的网络技术支持；&lt;/p&gt;&lt;p&gt;&lt;br /&gt;2 U-Boot主要目录结构&lt;br /&gt;- board 目标板相关文件，主要包含SDRAM、FLASH驱动；&lt;br /&gt;- common 独立于处理器体系结构的通用代码，如内存大小探测与故障检测；&lt;br /&gt;- cpu 与处理器相关的文件。如mpc8xx子目录下含串口、网口、LCD驱动及中断初始化等文件；&lt;br /&gt;- driver 通用设备驱动，如CFI FLASH驱动（目前对INTEL FLASH支持较好）&lt;br /&gt;- doc U-Boot的说明文档；&lt;br /&gt;- examples可在U-Boot下运行的示例程序；如hello_world.c,timer.c；&lt;br /&gt;- include U-Boot头文件；尤其configs子目录下与目标板相关的配置头文件是移植过程中经常要修改的文件；&lt;br /&gt;- lib_xxx 处理器体系相关的文件，如lib_ppc, lib_arm目录分别包含与PowerPC、ARM体系结构相关的文件；&lt;br /&gt;- net 与网络功能相关的文件目录，如bootp,nfs,tftp；&lt;br /&gt;- post 上电自检文件目录。尚有待于进一步完善；&lt;br /&gt;- rtc RTC驱动程序；&lt;br /&gt;- tools 用于创建U-Boot S-RECORD和BIN镜像文件的工具；&lt;/p&gt;&lt;p&gt;&lt;br /&gt;3 U-Boot支持的主要功能&lt;br /&gt;U-Boot可支持的主要功能列表&lt;br /&gt;系统引导 支持NFS挂载、RAMDISK（压缩或非压缩）形式的根文件系统&lt;br /&gt;支持NFS挂载、从FLASH中引导压缩或非压缩系统内核；&lt;br /&gt;基本辅助功能 强大的操作系统接口功能；可灵活设置、传递多个关键参数给操作系统，适合系统在不同开发阶段的调试要求与产品发布，尤对Linux支持最为强劲；&lt;br /&gt;支持目标板环境参数多种存储方式，如FLASH、NVRAM、EEPROM；&lt;br /&gt;CRC32校验，可校验FLASH中内核、RAMDISK镜像文件是否完好；&lt;br /&gt;设备驱动 串口、SDRAM、FLASH、以太网、LCD、NVRAM、EEPROM、键盘、USB、PCMCIA、PCI、RTC等驱动支持；&lt;br /&gt;上电自检功能 SDRAM、FLASH大小自动检测；SDRAM故障检测；CPU型号；&lt;br /&gt;特殊功能 XIP内核引导；&lt;/p&gt;&lt;p&gt;4 移植前的准备&lt;/p&gt;&lt;p&gt;（1）、首先读读uboot自带的readme文件，了解了一个大概。&lt;br /&gt;（2）、看看common.h，这个文件定义了一些基本的东西，并包含了一些必要的头文件。再看看flash.h，这个文件里面定义了flash_info_t为一个struct。包含了flash的一些属性定义。并且定义了所有的flash的属性，其中，AMD的有：AMD_ID_LV320B，定义为&amp;#8220;#define AMD_ID_LV320B 0x22F922F9&amp;#8221;。&lt;br /&gt;（3）、对于&amp;#8220;./borad/at91rm9200dk/flash.c&amp;#8221;的修改，有以下的方面：&lt;br /&gt;&amp;#8220;void flash_identification(flash_info_t *info)&amp;#8221;这个函数的目的是确认flash的型号。注意的是，这个函数里面有一些宏定义，直接读写了flash。并获得ID号。&lt;br /&gt;（4）、修改：&amp;#8221;./board/at91rm9200dk/config.mk&amp;#8221;为&lt;br /&gt;TEXT_BASE=0x21f80000 为TEXT_BASE=0x21f00000 （当然，你应该根据自己的板子来修改，和一级boot的定义的一致即可）。&lt;br /&gt;（5）、再修改&amp;#8221;./include/configs/at91rm9200dk.h&amp;#8221;为&lt;br /&gt;修改flash和SDRAM的大小。&lt;br /&gt;（6）、另外一个要修改的文件是：&lt;br /&gt;./borad/at91rm9200dk/flash.c。这个文件修改的部分比较的多。&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; a． 首先是OrgDef的定义，加上目前的flash。&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; b． 接下来，修改&amp;#8221;#define FLASH_BANK_SIZE 0x200000&amp;#8221;为自己flash的&amp;nbsp; 容量&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; c． 在修改函数flash_identification(flash_info_t * info)里面的打印信息，这部分将在u-boot启动的时候显示。&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; d． 然后修改函数flash_init(void)里面对一些变量的赋值。&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; e． 最后修改的是函数flash_print_info(flash_info_t * info)里面实际打印的函数信息。&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; f． 还有一个函数需要修改，就是：&amp;#8220;flash_erase&amp;#8221;，这个函数要检测先前知道的flash类型是否匹配，否则，直接就返回了。把这里给注释掉。&lt;/p&gt;&lt;p&gt;（7）、接下来看看SDRAM的修改。&lt;br /&gt;这个里面对于&amp;#8220;SIZE&amp;#8221;的定义都是基于字节计算的。&lt;br /&gt;只要修改&amp;#8221;./include/configs/at91rm9200dk.h&amp;#8221;里面的&lt;br /&gt;&amp;#8220;#define PHYS_SDRAM_SIZE 0X200000&amp;#8221;就可以了。注意，SIZE是以字节为单位的。&lt;br /&gt;（8）、还有一个地方要注意&lt;br /&gt;就是按照目前的设定，一级boot把u_boot加载到了SDRAM的空间为：21F00000 -&amp;gt; 21F16B10，这恰好是SDRAM的高端部分。另外，BSS为21F1AE34。&lt;/p&gt;&lt;p&gt;（9）、编译后，可以写入flash了。&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; a． 压缩这个u-boot.bin&lt;br /&gt;&amp;#8220;gzip &amp;#8211;c u-boot.bin &amp;gt; u-boot.gz&amp;#8221;&lt;br /&gt;压缩后的文件大小为：&lt;br /&gt;43Kbytes&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; b． 接着把boot.bin和u-boot.gz烧到flash里面去。&lt;br /&gt;Boot.bin大约11kBytes，在flash的0x1000 0000 ~ 0x1000 3fff&lt;/p&gt;&lt;p&gt;5 U-Boot移植过程&lt;br /&gt;&amp;#9312; 获得发布的最新版本U-Boot源码，与Linux内核源码类似，也是 bzip2的压缩格式。可从U-Boot的官方网站&lt;a href="http://sourceforge.net/projects/U-Boot"&gt;http://sourceforge.net/projects/U-Boot&lt;/a&gt;上获得；&lt;br /&gt;&amp;#9313; 阅读相关文档，主要是U-Boot源码根目录下的README文档和U-Boot官方网站的DULG（The DENX U-Boot and Linux Guide）文档&lt;a href="http://www.denx.de/twiki/bin/view/DULG/Manual"&gt;http://www.denx.de/twiki/bin/view/DULG/Manual&lt;/a&gt;。尤其是DULG文档，从如何安装建立交叉开发环境和解决U-Boot移植中常见问题都一一给出详尽的说明；&lt;br /&gt;&amp;#9314; 订阅U-Boot用户邮件列表&lt;a href="http://lists.sourceforge.net/lists/listinfo/u-boot-users"&gt;http://lists.sourceforge.net/lists/listinfo/u-boot-users&lt;/a&gt;。在移植U-Boot过程中遇有问题，在参考相关文档和搜索U-Boot-User邮件档案库&lt;a href="http://sourceforge.net/mailarchive/forum.php?forum_id=12898"&gt;http://sourceforge.net/mailarchive/forum.php?forum_id=12898&lt;/a&gt;仍不能解决的情况下，第一时间提交所遇到的这些问题，众多热心的U-Boot开发人员会乐于迅速排查问题，而且很有可能，W.D本人会直接参与指导；&lt;br /&gt;&amp;#9315; 在建立的开发环境下进行移植工作。绝大多数的开发环境是交叉开发环境。在这方面，DENX 和MontaVista均提供了完整的开发工具集；&lt;br /&gt;&amp;#9316; 在目标板与开发主机间接入硬件调试器。这是进行U-Boot移植应当具备且非常关键的调试工具。因为在整个U-Boot的移植工作中,尤其是初始阶段，硬件调试器是我们了解目标板真实运行状态的唯一途径。在这方面，W.D本人和众多嵌入式开发人员倾向于使用BDI2000。一方面，其价格不如ICE调试器昂贵，同时其可靠性高，功能强大，完全能胜任移植和调试U-Boot。另外，网上也有不少关于BDI2000调试方面的参考文档。&lt;br /&gt;&amp;#9317; 如果在参考开发板上移植U-Boot，可能需要移除目标板上已有的BOOT LOADER。可以根据板上BOOT LOADER的说明文档，先着手解决在移除当前BOOT LOADER的情况下，如何进行恢复。以便今后在需要场合能重新装入原先的BOOT LOADER。&lt;/p&gt;&lt;p&gt;6. U-Boot移植方法&lt;br /&gt;当前，对于U-Boot的移植方法，大致分为两种。一种是先用BDI2000创建目标板初始运行环境，将U-Boot镜像文件u-boot.bin下载到目标板RAM中的指定位置，然后，用BDI2000进行跟踪调试。其好处是不用将U-Boot镜像文件烧写到FLASH中去。但弊端在于对移植开发人员的移植调试技能要求较高，BDI2000的配置文件较为复杂。另外一种方法是用BDI2000先将U-Boot镜像文件烧写到FLASH中去，然后利用GDB和BDI2000进行调试。这种方法所用BDI2000的配置文件较为简单，调试过程与U-Boot移植后运行过程相吻合，即U-Boot先从FLASH中运行，再重载至RAM中相应位置，并从那里正式投入运行。唯一感到有些麻烦的就是需要不断烧写FLASH。但考虑到FLASH常规擦写次数基本为10万次左右，作为移植U-Boot，不会占用太多的次数，应该不会为FLASH烧写有什么担忧。同时，W. D本人也极力推荐使用后一种方法。笔者建议，除非U-Boot移植资深人士或有强有力的技术支持，建议采用第二种移植方法。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;7. U-Boot移植主要修改的文件&lt;br /&gt;从移植U-Boot最小要求－U-Boot能正常启动的角度出发，主要考虑修改如下文件：&lt;br /&gt;&amp;#9312; &amp;lt;目标板&amp;gt;.h头文件，如include/configs/RPXlite.h。可以是U-Boot源码中已有的目标板头文件，也可以是新命名的配置头文件；大多数的寄存器参数都是在这一文件中设置完成的；&lt;br /&gt;&amp;#9313; &amp;lt;目标板&amp;gt;.c文件，如board/RPXlite/RPXlite.c。它是SDRAM的驱动程序，主要完成SDRAM的UPM表设置，上电初始化。&lt;br /&gt;&amp;#9314; FLASH的驱动程序，如board/RPXlite/flash.c，或common/cfi_flash.c。可在参考已有FLASH驱动的基础上，结合目标板FLASH数据手册，进行适当修改； &lt;br /&gt;&amp;#9315; 串口驱动，如修改cpu/mpc8xx/serial.c串口收发器芯片使能部分。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;8. U-Boot移植要点&lt;br /&gt;&amp;#9312; BDI2000的配置文件。如果采用第二种移植方法，即先烧入FLASH的方法，配置项只需很少几个，就可以进行U-Boot的烧写与调试了。对PPC 8xx系列的主板，可参考DULG文档中TQM8xx的配置文件进行相应的修改。下面，笔者以美国Embedded Planet公司的RPXlite DW板为例，给出在嵌入式Linux交叉开发环境下的BDI2000参考配置文件以作参考：&lt;br /&gt;; bdiGDB configuration file for RPXlite DW or LITE_DW&lt;br /&gt;; --------------------------------------------&lt;br /&gt;[INIT]&lt;br /&gt;; init core register&lt;br /&gt;WSPR 149 0x2002000F ;DER : set debug enable register&lt;br /&gt;; WSPR 149 0x2006000F ;DER : enable SYSIE for BDI flash program&lt;br /&gt;WSPR 638 0xFA200000 ;IMMR : internal memory at 0xFA200000&lt;br /&gt;WM32 0xFA200004 0xFFFFFF89 ;SYPCR&lt;br /&gt;[TARGET]&lt;br /&gt;CPUCLOCK 40000000 ;the CPU clock rate after processing the init list&lt;br /&gt;BDIMODE AGENT ;the BDI working mode (LOADONLY | AGENT)&lt;br /&gt;BREAKMODE HARD ;SOFT or HARD, HARD uses PPC hardware breakpoints&lt;br /&gt;[HOST]&lt;br /&gt;IP 173.60.120.5&lt;br /&gt;FILE uImage.litedw &lt;br /&gt;FORMAT BIN&lt;br /&gt;LOAD MANUAL ;load code MANUAL or AUTO after reset&lt;br /&gt;DEBUGPORT 2001&lt;br /&gt;START 0x0100&lt;br /&gt;[FLASH]&lt;br /&gt;CHIPTYPE AM29BX8 ;;Flash type (AM29F | AM29BX8 | AM29BX16 | I28BX8 | I28BX16)&lt;br /&gt;CHIPSIZE 0x400000 ;;The size of one flash chip in bytes&lt;br /&gt;BUSWIDTH 32 ;The width of the flash memory bus in bits (8 | 16 | 32)&lt;br /&gt;WORKSPACE 0xFA202000 ; RAM buffer for fast flash programming&lt;br /&gt;FILE u-boot.bin ;The file to program&lt;br /&gt;FORMAT BIN 0x00000000&lt;br /&gt;ERASE 0x00000000 BLOCK&lt;br /&gt;ERASE 0x00008000 BLOCK&lt;br /&gt;ERASE 0x00010000 BLOCK&lt;br /&gt;ERASE 0x00018000 BLOCK&lt;br /&gt;[REGS]&lt;br /&gt;DMM1 0xFA200000&lt;br /&gt;FILE reg823.def&lt;br /&gt;&amp;#9313; U-Boot移植参考板。这是进行U-Boot移植首先要明确的。可以根据目标板上CPU、FLASH、SDRAM的情况，以尽可能相一致为原则，先找出一个与所移植目标板为同一个或同一系列处理器的U-Boot支持板为移植参考板。如RPXlite DW板可选择U-Boot源码中RPXlite板作为U-Boot移植参考板。对U-Boot移植新手，建议依照循序渐进的原则，目标板文件名暂时先用移植参考板的名称，在逐步熟悉U-Boot移植基础上，再考虑给目标板重新命名。在实际移植过程中，可用Linux命令查找移植参考板的特定代码，如grep &amp;#8211;r RPXlite ./ 可确定出在U-Boot中与RPXlite板有关的代码，依此对照目标板实际进行屏蔽或修改。同时应不局限于移植参考板中的代码，要广泛借鉴U-Boot中已有的代码更好地实现一些具体的功能。&lt;br /&gt;&amp;#9314; U-Boot烧写地址。不同目标板，对U-Boot在FLASH中存放地址要求不尽相同。事实上，这是由处理器中断复位向量来决定的，与主板硬件相关，对MPC8xx主板来讲，就是由硬件配置字(HRCW)决定的。也就是说，U-Boot烧写具体位置是由硬件决定的，而不是程序设计来选择的。程序中相应U-Boot起始地址必须与硬件所确定的硬件复位向量相吻合；如RPXlite DW板的中断复位向量设置为0x00000100。因此， U-Boot 的BIN镜像文件必须烧写到FLASH的起始位置。事实上，大多数的PPC系列的处理器中断复位向量是0x00000100和0xfff00100。这也是一般所说的高位启动和低位启动的BOOT LOADER所在位置。可通过修改U-Boot源码&amp;lt;目标板&amp;gt;.h头文件中CFG_MONITOR_BASE 和board/&amp;lt;目标板&amp;gt;/config.mk中的TEXT_BASE的设置来与硬件配置相对应。&lt;br /&gt;&amp;#9315; CPU寄存器参数设置。根据处理器系列、类型不同，寄存器名称与作用有一定差别。必须根据目标板的实际，进行合理配置。一个较为可行和有效的方法，就是借鉴参考移植板的配置，再根据目标板实际，进行合理修改。这是一个较费功夫和考验耐力的过程，需要仔细对照处理器各寄存器定义、参考设置、目标板实际作出选择并不断测试。MPC8xx处理器较为关键的寄存器设置为SIUMCR、PLPRCR、SCCR、BRx、ORx。&lt;br /&gt;&amp;#9316; 串口调试。能从串口输出信息，即使是乱码，也可以说U-Boot移植取得了实质性突破。依据笔者调试经历，串口是否有输出，除了与串口驱动相关外，还与FLASH相关的寄存器设置有关。因为U-Boot是从FLASH中被引导启动的，如果FLASH设置不正确，U-Boot代码读取和执行就会出现一些问题。因此，还需要就FLASH的相关寄存器设置进行一些参数调试。同时，要注意串口收发芯片相关引脚工作波形。依据笔者调试情况，如果串口无输出或出现乱码，一种可能就是该芯片损坏或工作不正常。&lt;br /&gt;&amp;#9317; 与启动 FLASH相关的寄存器BR0、OR0的参数设置。应根据目标板FLASH的数据手册与BR0和OR0的相关位含义进行合理设置。这不仅关系到FLASH能否正常工作，而且与串口调试有直接的关联。&lt;br /&gt;&amp;#9318; 关于CPLD电路。目标板上是否有CPLD电路丝毫不会影响U-Boot的移植与嵌入式操作系统的正常运行。事实上，CPLD电路是一个集中将板上电路的一些逻辑关系可编程设置的一种实现方法。其本身所起的作用就是实现一些目标板所需的脉冲信号和电路逻辑，其功能完全可以用一些逻辑电路与CPU口线来实现。&lt;br /&gt;&amp;#9319; SDRAM的驱动。串口能输出以后，U-Boot移植是否顺利基本取决于SDRAM的驱动是否正确。与串口调试相比，这部分工作更为核心，难度更大。MPC8xx目标板SDRAM驱动涉及三部分。一是相关寄存器的设置；二是UPM表；三是SDRAM上电初始化过程。任何一部分有问题，都会影响U-Boot、嵌入式操作系统甚至应用程序的稳定、可靠运行。所以说，SDRAM的驱动不仅关系到U-Boot本身能否正常运行，而且还与后续部分相关，是相当关键的部分。&lt;br /&gt;&amp;#9320; 补充功能的添加。在获得一个能工作的U-Boot后，就可以根据目标板和实际开发需要，添加一些其它功能支持。如以太网、LCD、NVRAM等。与串口和SDRAM调试相比，在已有基础之上，这些功能添加还是较为容易的。大多只是在参考现有源码的基础上，进行一些修改和配置。&lt;br /&gt;另外，如果在自主设计的主板上移植U-Boot，那么除了考虑上述软件因素以外，还需要排查目标板硬件可能存在的问题。如原理设计、PCB布线、元件好坏。在移植过程中，敏锐判断出故障态是硬件还是软件问题，往往是关系到项目进度甚至移植成败的关键，相应难度会增加许多。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 下面以移植u-boot 到44B0开发板的步骤为例，移植中上仅需要修改和硬件相关的部分。在代码结构上：&lt;br /&gt;1) 在board 目录下创建ev44b0ii 目录，创建ev44b0ii.c 以及flash.c,memsetup.S,u-boot.lds等。不需要从零开始，可选择一个相似的目录，直接复制过来，修改文件名以及内容。我在移植u-boot 过程中，选择的是ep7312 目录。由于u-boot 已经包含基于s3c24b0 的开发板目录，作为参考，也可以复制相应的目录。&lt;br /&gt;2) 在cpu 目录下创建arm7tdmi 目录,主要包含start.S，interrupts.c 以及cpu.c,serial.c几个文件。同样不需要从零开始建立文件，直接从arm720t 复制，然后修改相应内容。&lt;br /&gt;3) 在include/configs 目录下添加ev44b0ii.h，在这里放上全局的宏定义等。&lt;br /&gt;4) 找到u-boot 根目录下Makefile 修改加入&lt;br /&gt;ev44b0ii_config : unconfig&lt;br /&gt;@./mkconfig $(@:_config=) arm arm7tdmi ev44b0ii&lt;br /&gt;5) 运行make ev44bii_config,如果没有错误就可以开始硬件相关代码移植的工作&lt;/p&gt;&lt;p&gt;&lt;br /&gt;3. u-boot 的体系结构&lt;br /&gt;1) 总体结构&lt;br /&gt;u-boot 是一个层次式结构。从上图也可以看出，做移植工作的软件人员应当提供串口驱动（UART Driver）,以太网驱动(Ethernet Driver),Flash 驱动（Flash 驱动）,USB 驱动（USB Driver）。目前，通过USB 口下载程序显得不是十分必要，所以暂时没有移植USB 驱动。驱动层之上是u-boot 的应用，command 通过串口提供人机界面。我们可以使用一些命令做一些常用的工作，比如内存查看命令md。&lt;br /&gt;Kermit 应用主要用来支持使用串口通过超级终端下载应用程序。TFTP 则是通过网络方式来下载应用程序，例如uclinux 操作系统。&lt;br /&gt;2) 内存分布&lt;br /&gt;在flash rom 中内存分布图ev44b0ii 的flash 大小2M(8bits),现在将0-40000 共256k 作为u-boot 的存储空间。由于u-boot 中有一些环境变量，例如ip 地址，引导文件名等，可在命令行通过setenv 配置好,通过saveenv 保存在40000-50000（共64k）这段空间里。如果存在保存好的环境变量，u-boot 引导将直接使用这些环境变量。正如从代码分析中可以看到，我们会把flash 引导代码搬移到DRAM 中运行。下图给出u-boot 的代码在DRAM中的位置。引导代码u-boot 将从0x0000 0000 处搬移到0x0C700000 处。特别注意的由于ev44b0ii uclinux 中断向量程序地址在0x0c00 0000 处，所以不能将程序下载到0x0c00 0000 出，通常下载到0x0c08 0000 处。&lt;/p&gt;&lt;p&gt;4. start.S 代码结构&lt;br /&gt;1) 定义入口&lt;br /&gt;一个可执行的Image 必须有一个入口点并且只能有一个唯一的全局入口，通常这个入口放在Rom(flash)的0x0 地址。例如start.S 中的&lt;br /&gt;.globl _start&lt;br /&gt;_start:&lt;br /&gt;值得注意的是你必须告诉编译器知道这个入口，这个工作主要是修改连接器脚本文件（lds）。&lt;br /&gt;2) 设置异常向量(Exception Vector)&lt;br /&gt;异常向量表，也可称为中断向量表，必须是从0 地址开始，连续的存放。如下面的就包括了复位(reset),未定义处理（undef）,软件中断(SWI),预去指令错误(Pabort),数据错误(Dabort),保留，以及IRQ,FIQ 等。注意这里的值必须与uclinux 的vector_base 一致。这就是说如果uclinux 中vector_base(include/armnommu/proc-armv/system.h)定义为0x0c00 0000,则HandleUndef 应该在&lt;br /&gt;0x0c00 0004。&lt;br /&gt;b reset //for debug&lt;br /&gt;ldr pc,=HandleUndef&lt;br /&gt;ldr pc,=HandleSWI&lt;br /&gt;ldr pc,=HandlePabort&lt;br /&gt;ldr pc,=HandleDabort&lt;br /&gt;b .&lt;br /&gt;ldr pc,=HandleIRQ&lt;br /&gt;ldr pc,=HandleFIQ&lt;br /&gt;ldr pc,=HandleEINT0 /*mGA H/W interrupt vector table*/&lt;br /&gt;ldr pc,=HandleEINT1&lt;br /&gt;ldr pc,=HandleEINT2&lt;br /&gt;ldr pc,=HandleEINT3&lt;br /&gt;ldr pc,=HandleEINT4567&lt;br /&gt;ldr pc,=HandleTICK /*mGA*/&lt;br /&gt;b .&lt;br /&gt;b .&lt;br /&gt;ldr pc,=HandleZDMA0 /*mGB*/&lt;br /&gt;ldr pc,=HandleZDMA1&lt;br /&gt;ldr pc,=HandleBDMA0&lt;br /&gt;ldr pc,=HandleBDMA1&lt;br /&gt;ldr pc,=HandleWDT&lt;br /&gt;ldr pc,=HandleUERR01 /*mGB*/&lt;br /&gt;b .&lt;br /&gt;b .&lt;br /&gt;ldr pc,=HandleTIMER0 /*mGC*/&lt;br /&gt;ldr pc,=HandleTIMER1&lt;br /&gt;ldr pc,=HandleTIMER2&lt;br /&gt;ldr pc,=HandleTIMER3&lt;br /&gt;ldr pc,=HandleTIMER4&lt;br /&gt;ldr pc,=HandleTIMER5 /*mGC*/&lt;br /&gt;b .&lt;br /&gt;b .&lt;br /&gt;ldr pc,=HandleURXD0 /*mGD*/&lt;br /&gt;ldr pc,=HandleURXD1&lt;br /&gt;ldr pc,=HandleIIC&lt;br /&gt;ldr pc,=HandleSIO&lt;br /&gt;ldr pc,=HandleUTXD0&lt;br /&gt;ldr pc,=HandleUTXD1 /*mGD*/&lt;br /&gt;b .&lt;br /&gt;b .&lt;br /&gt;ldr pc,=HandleRTC /*mGKA*/&lt;br /&gt;b .&lt;br /&gt;b .&lt;br /&gt;b .&lt;br /&gt;b .&lt;br /&gt;b . /*mGKA*/&lt;br /&gt;b .&lt;br /&gt;b .&lt;br /&gt;ldr pc,=HandleADC /*mGKB*/&lt;br /&gt;b .&lt;br /&gt;b .&lt;br /&gt;b .&lt;br /&gt;b .&lt;br /&gt;b . /*mGKB*/&lt;br /&gt;b .&lt;br /&gt;b .&lt;br /&gt;ldr pc,=EnterPWDN&lt;br /&gt;作为对照：请看以上标记的值：&lt;br /&gt;.equ HandleReset, 0xc000000&lt;br /&gt;.equ HandleUndef,0xc000004&lt;br /&gt;.equ HandleSWI, 0xc000008&lt;br /&gt;.equ HandlePabort, 0xc00000c&lt;br /&gt;.equ HandleDabort, 0xc000010&lt;br /&gt;.equ HandleReserved, 0xc000014&lt;br /&gt;.equ HandleIRQ, 0xc000018&lt;br /&gt;.equ HandleFIQ, 0xc00001c&lt;br /&gt;/*the value is different with an address you think it may be.&lt;br /&gt;*IntVectorTable */&lt;br /&gt;.equ HandleADC, 0xc000020&lt;br /&gt;.equ HandleRTC, 0xc000024&lt;br /&gt;.equ HandleUTXD1, 0xc000028&lt;br /&gt;.equ HandleUTXD0, 0xc00002c&lt;br /&gt;.equ HandleSIO, 0xc000030&lt;br /&gt;.equ HandleIIC, 0xc000034&lt;br /&gt;.equ HandleURXD1, 0xc000038&lt;br /&gt;.equ HandleURXD0, 0xc00003c&lt;br /&gt;.equ HandleTIMER5, 0xc000040&lt;br /&gt;.equ HandleTIMER4, 0xc000044&lt;br /&gt;.equ HandleTIMER3, 0xc000048&lt;br /&gt;.equ HandleTIMER2, 0xc00004c&lt;br /&gt;.equ HandleTIMER1, 0xc000050&lt;br /&gt;.equ HandleTIMER0, 0xc000054&lt;br /&gt;.equ HandleUERR01, 0xc000058&lt;br /&gt;.equ HandleWDT, 0xc00005c&lt;br /&gt;.equ HandleBDMA1, 0xc000060&lt;br /&gt;.equ HandleBDMA0, 0xc000064&lt;br /&gt;.equ HandleZDMA1, 0xc000068&lt;br /&gt;.equ HandleZDMA0, 0xc00006c&lt;br /&gt;.equ HandleTICK, 0xc000070&lt;br /&gt;.equ HandleEINT4567, 0xc000074&lt;br /&gt;.equ HandleEINT3, 0xc000078&lt;br /&gt;.equ HandleEINT2, 0xc00007c&lt;br /&gt;.equ HandleEINT1, 0xc000080&lt;br /&gt;.equ HandleEINT0, 0xc000084&lt;br /&gt;3) 初始化CPU 相关的pll,clock,中断控制寄存器&lt;br /&gt;依次为关闭watch dog timer,关闭中断，设置LockTime，PLL(phase lock loop),以及时钟。&lt;br /&gt;这些值（除了LOCKTIME）都可从Samsung 44b0 的手册中查到。&lt;br /&gt;ldr r0,WTCON //watch dog disable&lt;br /&gt;ldr r1,=0x0&lt;br /&gt;str r1,[r0]&lt;br /&gt;ldr r0,INTMSK&lt;br /&gt;ldr r1,MASKALL //all interrupt disable&lt;br /&gt;str r1,[r0]&lt;br /&gt;/*****************************************************&lt;br /&gt;* Set clock control registers *&lt;br /&gt;*****************************************************/&lt;br /&gt;ldr r0,LOCKTIME&lt;br /&gt;ldr r1,=800 // count = t_lock * Fin (t_lock=200us, Fin=4MHz) = 800&lt;br /&gt;str r1,[r0]&lt;br /&gt;ldr r0,PLLCON /*temporary setting of PLL*/&lt;br /&gt;ldr r1,PLLCON_DAT /*Fin=10MHz,Fout=40MHz or 60MHz*/&lt;br /&gt;str r1,[r0]&lt;br /&gt;ldr r0,CLKCON&lt;br /&gt;ldr r1,=0x7ff8 //All unit block CLK enable&lt;br /&gt;str r1,[r0]&lt;br /&gt;4) 初始化内存控制器&lt;br /&gt;内存控制器，主要通过设置13 个从1c80000 开始的寄存器来设置，包括总线宽度，&lt;br /&gt;8 个内存bank，bank 大小，sclk,以及两个bank mode。&lt;br /&gt;/*****************************************************&lt;br /&gt;* Set memory control registers *&lt;br /&gt;*****************************************************/&lt;br /&gt;memsetup:&lt;br /&gt;adr r0,SMRDATA&lt;br /&gt;ldmia r0,{r1-r13}&lt;br /&gt;ldr r0,=0x01c80000 //BWSCON Address&lt;br /&gt;stmia r0,{r1-r13}&lt;br /&gt;5) 将rom 中的程序复制到RAM 中&lt;br /&gt;首先利用PC 取得bootloader 在flash 的起始地址，再通过标号之差计算出这个程序代&lt;br /&gt;码的大小。这些标号，编译器会在连接（link）的时候生成正确的分布的值。取得正&lt;br /&gt;确信息后，通过寄存器(r3 到r10)做为复制的中间媒介，将代码复制到RAM 中。&lt;br /&gt;relocate:&lt;br /&gt;/*&lt;br /&gt;* relocate armboot to RAM&lt;br /&gt;*/&lt;br /&gt;adr r0, _start /* r0 &amp;lt;- current position of code */&lt;br /&gt;ldr r2, _armboot_start&lt;br /&gt;ldr r3, _armboot_end&lt;br /&gt;sub r2, r3, r2 /* r2 &amp;lt;- size of armboot */&lt;br /&gt;ldr r1, _TEXT_BASE /* r1 &amp;lt;- destination address */&lt;br /&gt;add r2, r0, r2 /* r2 &amp;lt;- source end address */&lt;br /&gt;/*&lt;br /&gt;* r0 = source address&lt;br /&gt;* r1 = target address&lt;br /&gt;* r2 = source end address&lt;br /&gt;*/&lt;br /&gt;copy_loop:&lt;br /&gt;ldmia r0!, {r3-r10}&lt;br /&gt;stmia r1!, {r3-r10}&lt;br /&gt;cmp r0, r2&lt;br /&gt;ble copy_loop&lt;br /&gt;6) 初始化堆栈&lt;br /&gt;进入各种模式设置相应模式的堆栈。&lt;br /&gt;InitStacks:&lt;br /&gt;/*Don't use DRAM,such as stmfd,ldmfd......&lt;br /&gt;SVCstack is initialized before*/&lt;br /&gt;mrs r0,cpsr&lt;br /&gt;bic r0,r0,#0X1F&lt;br /&gt;orr r1,r0,#0xDB /*UNDEFMODE|NOINT*/&lt;br /&gt;msr cpsr,r1 /*UndefMode*/&lt;br /&gt;ldr sp,UndefStack&lt;br /&gt;orr r1,r0,#0XD7 /*ABORTMODE|NOINT*/&lt;br /&gt;msr cpsr,r1 /*AbortMode*/&lt;br /&gt;ldr sp,AbortStack&lt;br /&gt;orr r1,r0,#0XD2 /*IRQMODE|NOINT*/&lt;br /&gt;msr cpsr,r1 /*IRQMode*/&lt;br /&gt;ldr sp,IRQStack&lt;br /&gt;orr r1,r0,#0XD1 /*FIQMODE|NOINT*/&lt;br /&gt;msr cpsr,r1 /*FIQMode*/&lt;br /&gt;ldr sp,FIQStack&lt;br /&gt;bic r0,r0,#0XDF /*MODEMASK|NOINT*/&lt;br /&gt;orr r1,r0,#0X13&lt;br /&gt;msr cpsr,r1 /*SVCMode*/&lt;br /&gt;ldr sp,SVCStack&lt;br /&gt;7) 转到RAM 中执行&lt;br /&gt;使用指令ldr,pc,RAM 中C 函数地址就可以转到RAM 中去执行。&lt;br /&gt;5. 系统初始化部分&lt;br /&gt;1. 串口部分&lt;br /&gt;串口的设置主要包括初始化串口部分，值得注意的串口的Baudrate 与时钟MCLK 有很大关系，是通过：rUBRDIV0=( (int)(MCLK/16./(gd -&amp;gt;baudrate) + 0.5) -1 )计算得出。这可以在手册中查到。其他的函数包括发送，接收。这个时候没有中断，是通过循环等待来判断是否动作完成。&lt;br /&gt;例如，接收函数：&lt;br /&gt;while(!(rUTRSTAT0 &amp;amp; 0x1)); //Receive data read&lt;br /&gt;return RdURXH0();&lt;br /&gt;2. 时钟部分&lt;br /&gt;实现了延时函数udelay。&lt;br /&gt;这里的get_timer 由于没有使用中断，是使用全局变量来累加的。&lt;br /&gt;3. flash 部分&lt;br /&gt;flash 作为内存的一部分，读肯定没有问题，关键是flash 的写部分。&lt;br /&gt;Flash 的写必须先擦除，然后再写。&lt;br /&gt;unsigned long flash_init (void)&lt;br /&gt;{&lt;br /&gt;int i;&lt;br /&gt;u16 manId,devId;&lt;br /&gt;//first we init it as unknown,even if you forget assign it below,it's not a problem&lt;br /&gt;for (i=0; i &amp;lt; CFG_MAX_FLASH_BANKS; ++i){&lt;br /&gt;flash_info[i].flash_id = FLASH_UNKNOWN;&lt;br /&gt;flash_info[i].sector_count=CFG_MAX_FLASH_SECT;&lt;br /&gt;}&lt;br /&gt;/*check manId,devId*/&lt;br /&gt;_RESET();&lt;br /&gt;_WR(0x555,0xaa);&lt;br /&gt;_WR(0x2aa,0x55);&lt;br /&gt;_WR(0x555,0x90);&lt;br /&gt;manId=_RD(0x0);&lt;br /&gt;_WR(0x555,0xaa);&lt;br /&gt;_WR(0x2aa,0x55);&lt;br /&gt;_WR(0x555,0x90);&lt;br /&gt;devId=_RD(0x1);&lt;br /&gt;_RESET();&lt;br /&gt;printf("flashn");&lt;br /&gt;printf("Manufacture ID=%4x(0x0004), Device ID(0x22c4)=%4xn",manId,devId);&lt;br /&gt;if(manId!=0x0004 &amp;amp;&amp;amp; devId!=0x22c4){&lt;br /&gt;printf("flash check faliluren");&lt;br /&gt;return 0;&lt;br /&gt;}else{&lt;br /&gt;for (i=0; i &amp;lt; CFG_MAX_FLASH_BANKS; ++i){&lt;br /&gt;flash_info[i].flash_id=FLASH_AM160T;/*In fact it is fujitu,I only don't want to&lt;br /&gt;modify common files*/&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;/* Setup offsets */&lt;br /&gt;flash_get_offsets (CFG_FLASH_BASE, &amp;amp;flash_info[0]);&lt;br /&gt;/* zhangyy comment&lt;br /&gt;#if CFG_MONITOR_BASE &amp;gt;= CFG_FLASH_BASE&lt;br /&gt;//onitor protection ON by default&lt;br /&gt;flash_protect(FLAG_PROTECT_SET,&lt;br /&gt;CFG_MONITOR_BASE,&lt;br /&gt;CFG_MONITOR_BASE+monitor_flash_len-1,&lt;br /&gt;&amp;amp;flash_info[0]);&lt;br /&gt;#endif&lt;br /&gt;*/&lt;br /&gt;flash_info[0].size =PHYS_FLASH_SIZE;&lt;br /&gt;return (PHYS_FLASH_SIZE);&lt;br /&gt;}&lt;br /&gt;flash_init 完成初始化部分，这里的主要目的是检验flash 的型号是否正确。&lt;br /&gt;int flash_erase (flash_info_t *info, int s_first, int s_last)&lt;br /&gt;{&lt;br /&gt;volatile unsigned char *addr = (volatile unsigned char *)(info-&amp;gt;start[0]);&lt;br /&gt;int flag, prot, sect, l_sect;&lt;br /&gt;//ulong start, now, last;&lt;br /&gt;u32 targetAddr;&lt;br /&gt;u32 targetSize;&lt;br /&gt;/*zyy note:It is required and can't be omitted*/&lt;br /&gt;rNCACHBE0=( (0x2000000&amp;gt;&amp;gt;12)&amp;lt;&amp;lt;16 )|(0&amp;gt;&amp;gt;12); //flash area(Bank0) must be non-cachable&lt;br /&gt;area.&lt;br /&gt;rSYSCFG=rSYSCFG &amp;amp; (~0x8); //write buffer has to be off for proper timing.&lt;br /&gt;if ((s_first &amp;lt; 0) || (s_first &amp;gt; s_last)) {&lt;br /&gt;if (info-&amp;gt;flash_id == FLASH_UNKNOWN) {&lt;br /&gt;printf ("- missingn");&lt;br /&gt;} else {&lt;br /&gt;printf ("- no sectors to erasen");&lt;br /&gt;}&lt;br /&gt;return 1;&lt;br /&gt;}&lt;br /&gt;if ((info-&amp;gt;flash_id == FLASH_UNKNOWN) ||&lt;br /&gt;(info-&amp;gt;flash_id &amp;gt; FLASH_AMD_COMP)) {&lt;br /&gt;printf ("Can't erase unknown flash type - abortedn");&lt;br /&gt;return 1;&lt;br /&gt;}&lt;br /&gt;prot = 0;&lt;br /&gt;for (sect=s_first; sect&amp;lt;=s_last; ++sect) {&lt;br /&gt;if (info-&amp;gt;protect[sect]) {&lt;br /&gt;prot++;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;if (prot) {&lt;br /&gt;printf ("- Warning: %d protected sectors will not be erased!n",&lt;br /&gt;prot);&lt;br /&gt;} else {&lt;br /&gt;printf ("n");&lt;br /&gt;}&lt;br /&gt;l_sect = -1;&lt;br /&gt;/* Disable interrupts which might cause a timeout here */&lt;br /&gt;flag = disable_interrupts();&lt;br /&gt;/* Start erase on unprotected sectors */&lt;br /&gt;for (sect = s_first; sect&amp;lt;=s_last; sect++) {&lt;br /&gt;if (info-&amp;gt;protect[sect] == 0) {/* not protected */&lt;br /&gt;targetAddr=0x10000*sect;&lt;br /&gt;if(targetAddr&amp;lt;0x1F0000)&lt;br /&gt;targetSize=0x10000;&lt;br /&gt;else if(targetAddr&amp;lt;0x1F8000)&lt;br /&gt;targetSize=0x8000;&lt;br /&gt;else if(targetAddr&amp;lt;0x1FC000)&lt;br /&gt;targetSize=0x2000;&lt;br /&gt;else&lt;br /&gt;targetSize=0x4000;&lt;br /&gt;F29LV160_EraseSector(targetAddr);&lt;br /&gt;l_sect = sect;&lt;br /&gt;if(!BlankCheck(targetAddr, targetSize))&lt;br /&gt;printf("BlankCheck Errorn");&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;/* re-enable interrupts if necessary */&lt;br /&gt;if (flag)&lt;br /&gt;enable_interrupts();&lt;br /&gt;/* wait at least 80us - let's wait 1 ms */&lt;br /&gt;udelay (1000);&lt;br /&gt;/*&lt;br /&gt;*We wait for the last triggered sector&lt;br /&gt;*/&lt;br /&gt;if (l_sect &amp;lt; 0)&lt;br /&gt;goto DONE;&lt;br /&gt;DONE:&lt;br /&gt;printf (" donen");&lt;br /&gt;return 0;&lt;br /&gt;}&lt;br /&gt;int BlankCheck(int targetAddr,int targetSize)&lt;br /&gt;{&lt;br /&gt;int i,j;&lt;br /&gt;for(i=0;i{&lt;br /&gt;j=*((u16 *)(i+targetAddr));&lt;br /&gt;if( j!=0xffff)&lt;br /&gt;{&lt;br /&gt;printf("E:%x=%xn",(i+targetAddr),j);&lt;br /&gt;return 0;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;return 1;&lt;br /&gt;}&lt;br /&gt;flash_erase 擦除flash,BlankCheck 则检查该部分内容是否擦除成功。&lt;br /&gt;/*-----------------------------------------------------------------------&lt;br /&gt;*Write a word to Flash, returns:&lt;br /&gt;* 0 - OK&lt;br /&gt;* 1 - write timeout&lt;br /&gt;* 2 - Flash not erased&lt;br /&gt;*/&lt;br /&gt;static int write_word (flash_info_t *info, ulong dest, ulong data)&lt;br /&gt;{&lt;br /&gt;volatile u16 *tempPt;&lt;br /&gt;/*zhangyy note:because of compatiblity of function,I use low &amp;amp; hi*/&lt;br /&gt;u16 low = data &amp;amp; 0xffff;&lt;br /&gt;u16 high = (data &amp;gt;&amp;gt; 16) &amp;amp; 0xffff;&lt;br /&gt;low=swap_16(low);&lt;br /&gt;high=swap_16(high);&lt;br /&gt;tempPt=(volatile u16 *)dest;&lt;br /&gt;_WR(0x555,0xaa);&lt;br /&gt;_WR(0x2aa,0x55);&lt;br /&gt;_WR(0x555,0xa0);&lt;br /&gt;*tempPt=high;&lt;br /&gt;_WAIT();&lt;br /&gt;_WR(0x555,0xaa);&lt;br /&gt;_WR(0x2aa,0x55);&lt;br /&gt;_WR(0x555,0xa0);&lt;br /&gt;*(tempPt+1)=low;&lt;br /&gt;_WAIT();&lt;br /&gt;return 0;&lt;br /&gt;}&lt;br /&gt;wirte_word 则想flash 里面写入unsigned long 类型的data，因为flash 一次只能写入16bits，所以这里分两次写入。&lt;/p&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;br /&gt;本文引用地址：&lt;a onclick="clipboardData.setData('text',('http://patton.spaces.eepw.com.cn/articles/trackback/item/23450'),alert('引用地址已经复制到剪贴板:-)'));" href="http://patton.spaces.eepw.com.cn/articles/article/item/23450"&gt;http://patton.spaces.eepw.com.cn/articles/article/item/23450&lt;/a&gt; &lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/khler/aggbug/1959384.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/khler/archive/2011/02/21/1959384.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
