显示标签为“Embedded”的博文。显示所有博文
显示标签为“Embedded”的博文。显示所有博文

星期六, 四月 05, 2008

一些常用且需要记忆的数

经常遇到这些东西,每次都拿计算器计算太麻烦,在网上看见了一个列表,转过来:


0x40000000是1GB处;
0x00040000是256K处,
0x00020000是128K处,
0x90000000是2GB多的地方。
1M->0x00100000,
2M->0x00200000,
8M->0x00800000
16M->0x01000000,
32M->0x02000000
256M->0x10000000
64K->0x00010000
4K->0x00001000

Read More...

星期一, 三月 10, 2008

s3c2410 LCD图片显示【转】

最近研究了s3c2410下LCD控制器的相关知识,主要的参考资料就是 三星s3c2410数据手册(arm920T),英文版,看的不是非常明白,后来参考了WinCE下的部分代码,似有所领悟。于是写了此程序,用以在LCD上显示图片。
本程序可以在LCD上居中显示小于800×480的任意大小的图片。用到的辅助工具就是上篇文章中的RGB分量提取器.
关键模块如下:

0、全局变量的定义:

#define DMA_BUFFER_BASE 0xAC000000
#define DMA_PHYSICAL_BASE 0x35000000 // S3C2410X01 0x30000000

#define FRAMEBUF_BASE (DMA_BUFFER_BASE + 0x00100000)
#define FRAMEBUF_DMA_BASE (DMA_PHYSICAL_BASE + 0x00000000)//0x00100000

#define IOP_BASE 0x56000000 // 0x56000000

typedef struct {
unsigned int GPACON; // 00
unsigned int GPADAT;
unsigned int PAD1[2];
...................
}IOPreg;

// Define LCD type of S3C2400X01
#define TFT24BPP 3
#define LCDTYPE TFT24BPP // define LCD type as upper definition.
//
// Registers : LCD Controller
//

#define LCD_BASE 0x4D000000 // 0x4D000000
typedef struct {
unsigned int LCDCON1; // 00
unsigned int LCDCON2; // 04
unsigned int LCDCON3; // 08
.....................
}LCDreg ;

// LCD register value

#define MODE_TFT_24BIT (224)
#define LCD_XSIZE_TFT (800)
#define LCD_YSIZE_TFT (480)
#define ARRAY_SIZE_TFT_24BIT (SCR_XSIZE*4*SCR_YSIZE)
#define HOZVAL_TFT (LCD_XSIZE_TFT-1)
#define LINEVAL_TFT (LCD_YSIZE_TFT-1)
#define MVAL (13)
#define MVAL_USED (0)
#define VBPD ((32-1)&0xff)
#define VFPD ((11-1)&0xff)
#define VSPW ((2-1) &0x3f)
#define HBPD ((88-1)&0x7f)
#define HFPD ((40-1)&0xff)
#define HSPW ((128-1)&0xff)
#define CLKVAL_TFT (1)
#define M5D(n) ((n) & 0x1fffff)

U32* pLCDBuffer24=(U32*)FRAMEBUF_DMA_BASE;
U32* picData;

volatile LCDreg *s2410LCD = (LCDreg *)LCD_BASE;

volatile IOPreg *s2410IOP= (IOPreg *)IOP_BASE;

int nCol = 800;//象素列数
int nRow = 480;//象素行数
U32* picDataT=NULL;

1、入口函数,其中包括了相应端口、寄存器初始化的入口,aa,bb,cc,dd,ee是可选择的5幅预定义图片的GRB码数组,具体代码如下

void lcd_Main(void)
{
char sel;
Uart_Printf("Lcd_Driver ");

lcd_port_init();
lcd_regs_init();

Uart_Printf("select one Picture to show(1 2 3 4 5 0) ");

while((sel = Uart_Getch()) != 'e')
{
Uart_Printf("%c ",sel);
switch(sel)
{
case '1':
picData = (U32*)aa;break;
case '2':
picData =(U32*)bb;break;
case '3':
picData = (U32*)cc;break;
case '4':
picData = (U32*)dd; break;
case '5':
picData = (U32*)ee;break;
default:
Uart_Printf("Input 1 2 3 4 5 0 ");
}

lcd_display();

Uart_Printf("select one Picture to show(1 2 3 4 5 0) ");
}
Uart_Printf("Exit");
//lcd_close();
}

2、相应端口设置,包括GPC,GPD,GPG的相应位的设置:


void lcd_port_init(void)
{

// LCD port initialize.
s2410IOP->GPCUP = 0xFFFFFFFF;
s2410IOP->GPCCON = 0xAAAAAAAA;

s2410IOP->GPDUP = 0xFFFFFFFF;
s2410IOP->GPDCON = 0xAAAAAAAA;

s2410IOP->GPGCON &= ~(3 <<>GPGCON |= (1 <<>GPGDAT |= (1 <<>LCDCON1 = (1 << vclk =" HCLK"> About 7 Mhz
(MVAL_USED <<>LCDCON2 = (VBPD <<>LCDCON3 = (HBPD <<>LCDCON4 = (MVAL <<>LCDCON5 = 0x00000000;
/**//*
s2410LCD->LCDCON5 = (0 <<>LCDSADDR1 = ((FRAMEBUF_DMA_BASE >> 22) <<>> 1)) << lcdbank =" ((FRAMEBUF_DMA_BASE">> 22) << lcdbaseu =" ((M5D(FRAMEBUF_DMA_BASE)">> 1) <<>LCDSADDR2 = (M5D(FRAMEBUF_DMA_BASE) >> 1) + ( (LCD_XSIZE_TFT*2) + 0 )*(LINEVAL_TFT+1);
//LCDBASEL = s2410LCD->LCDSADDR2

s2410LCD->LCDSADDR3 = (((LCD_XSIZE_TFT - LCD_XSIZE_TFT) / 1) << offsize =" (((LCD_XSIZE_TFT" pagewidth =" (LCD_XSIZE_TFT)">TPAL = 0x0;
s2410LCD->LCDCON1 |= 1;

#endif
}

4、居中显示图片:

void lcd_display(void)
{
int y;
int pw, ph;
int sw=800, sh=480;
U32* pdata;
U32* pBt=NULL;

lcd_clear();

get_XY();//获得图片的宽与高,以保存在RGB数组的头两个字节。
pw = nCol, ph = nRow;

pBt = pLCDBuffer24 + sw*(sh/2-ph/2) + (sw/2-pw/2);//定位图片显示的起始位置

pdata = (U32*)picDataT;
for(y=0; yLCDCON1 |= 0;

}

5、每次显示都要获得图片的宽度和高度,并且清除前面的屏幕,所谓清屏就是显示背景图片(蓝色):

void lcd_clear()
{
int y=0;
U32* pdata = (U32*)(bgData+2);
for(y=0; y<480; ++y)
{
memcpy((pLCDBuffer24+800*y),(char*)pdata,800*4);
pdata = (U32*)(pdata+800);
}
}

void get_XY(void)
{
nCol = picData[0];
nRow = picData[1];

picDataT =(U32*) (picData + 2);
}

Read More...

星期一, 一月 21, 2008

UDEV on embeded Linux-2.6.19.2 UDEV on embeded Linux-2.6.19.2[转]

UDEV,新一代的用户空间设备管理系统,用以取代臃肿的DEVFS(其实DEVFS我还没用过,谁叫我是新来的 ^_^ ,关于两者的对比,可以参考 udev_vs_devfs )。关于UDEV的使用已经有一遍不错的译文 udev轻松上路 ,不过里面关于配置文件的编写与 Writing udev rules 不符。/etc/udev/udev.conf 是udev启动检查的配置文件,包括路径,权限,规则目录等,具体的规则文件应该为/etc/udev/rules.d/10-local.rules 。

我开始移植的第一个Linux是2.6.19.2,已放弃对DEVFS的支持,下面谈谈UDEV在我的arm开发板上的应用。由于BusyBox已带有一个简化板的udev--mdev。通过简单的 mdev -s ,就能自动装配/dev目录下的设备文件:

# ls /dev
console null ptmx pts shm
# mdev -s && ls /dev
apm_bios ptypd tty24 tty56
console ptype tty25 tty57
fb0 ptypf tty26 tty58
full ram0 tty27 tty59
kmem ram1 tty28 tty6
kmsg ram2 tty29 tty60
loop0 ram3 tty3 tty61
... ...
启动热拔插支持的话,用这一句
echo /sbin/mdev > /proc/sys/kernel/hotplug
一切就是这么简单,相应的/dev目录下会出现一大堆设备文件,甚是难看 ^_^
mdev的规则文件是/etc/mdev.conf ,与传统的udev规则文件写法上有点区别(简化了^_^)。
KERNEL=="tty[0-9]*", NAME="vc/%n" //for udev
tty[0-9]* 0:5 660 //for mdev
如果选上FEATURE_MDEV_EXEC支持,规则后面可以执行相应的命令,如:
pts/ 0:0 755 $mount -t devpts /dev/pts /dev/pts
不过我的程序还算简单,mdev -s 对我而言已足够,规则,留作日后写吧 ^_^
我用的是mdev,因为简单 ^_^
在启动教本(如:linuxrc)加入这两句就搞定:
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s

Read More...

busybox mdev的初始化问题


mdev来自动创建/dev中的设备文件,busybox的文档中说的很明白,使用
mdev时不加参数就是用hotplug机制来决定创建什么样的设备文件。

而用mdev -s是用sys文件系统提供的信息来创建设备文件的。我一开始没仔细看文档,在linuxrc中没加参数调用的mdev,结果造成真正的根文件系统没有挂载成功。因为那样mdev就要找hotplug而
buzybox好像还不能支持hotplug,我自己也没提供hotplug的机制,所以设备文件创建失
败,那么在mount 根文件系统的时候就失败了,后面再pivot_root也就没戏了。
最后一点要注意的是在你的initrd的/dev中必须要有console这个文件,要不启动的时候
就会报错的。
我把linuxrc贴在这,顺便加点注释:
#!/bin/ash
echo Start the script in initrd #输出一些信息
echo Press any key to continue #输出信息
read TEMP #等待你瞪大眼睛看后面的东西
/bin/mount -t proc /proc /proc #挂proc fs,其实我们这暂时还没用到,如果你要动
#态分析根文件系统,你就得分析kernel的cmdline,那个cmdline就在proc中
/bin/mount -t sysfs none /sys #挂sys为mdev填充/dev搜集信息
echo Creating /dev
/bin/mount -o mode=0755 -t tmpfs none /dev #在原有的/dev目录上再盖上一层,这
#样系统退出时就不会留下mdev填充的东西
#下面创建一些最基本设备文件,这些设备文件是mdev所使用的
/bin/mknod /dev/console c 5 1
/bin/mknod /dev/null c 1 3
/bin/mknod /dev/zero c 1 5
/bin/mkdir /dev/pts
/bin/mkdir /dev/shm
/sbin/mdev -s #mdev为我们自动填充/dev目录,该有的都会有的
#下面加载ext3所需的模块
echo "Loading ext3 modules"
/sbin/insmod /lib/jbd.ko
/sbin/insmod /lib/ext3.ko
/sbin/mdev -s #再次调用mdev,我不知道为什么,rh的initrd中就是调用两次,也许
#去掉前面的一次也没问题,回头我试试
/bin/umount /sys #卸掉sys,反正用完了
echo press any key to continue
read TEMP #等待你瞪大眼睛
echo Mounting root filesystem
/bin/mount -o defaults --ro -t ext2 /dev/hda1 /sysroot #挂载真正的根文件系统
,老道的技术应该是从kernel的cmdling中猜出根文件设备,而不是象我这样hard coded
/bin/mount -t tmpfs --bind /dev /sysroot/dev #保持新旧root 中的/dev是一样的
#下面的root切换都是标准动作在pivot_root的man page中有
echo Switching to new root
read TEMP
cd /sysroot
/sbin/pivot_root . mnt
exec /usr/sbin/chroot . /sbin/init
/bin/umount /mnt/dev #卸掉原来root 的dev目录

Read More...

移植2.6.22.1到2410上


今天在板子上移植了2.6.22内核,用uboot能正常引导进入cramfs文件系统,但是cs8900a网卡还不能正常工作,明天继续加油,得好好研究研究这块了。


主要是参考http://hi.baidu.com/wangy0919/blog/


这个blog收集的文章很全,呵呵,虽然不是原创,但是也难能可贵的,我也受益匪浅,谢谢blog主人了。


基本没出什么大问题,就是在制作根文件系统的时候,有点小问题,还有就是uboot的bootargs参数设置


Read More...

星期四, 一月 17, 2008

使U-BOOT正确引导linux内核

1、为了能使得U-BOOT正确引导linux内核。必须传递合适的参数给内核。
修改include/configs/zj2410.h如下:
/************************************************************
* RTC
************************************************************/
#define CONFIG_RTC_S 24X0 1
/* allow to overwrite serial and ethaddr */
#define CONFIG_ENV_OVERWRITE
#define CONFIG_BAUDRATE 115200
/************************************************************/
/* My Add */
/* enable passing of ATAGs */#define CONFIG_CMDLINE_TAG 1
#define CONFIG_SETUP_MEMORY_TAGS 1
#define CONFIG_INITRD_TAG 1
/***********************************************************
* Command definition
***********************************************************/
#define CONFIG_COMMANDS \
(CONFIG_CMD_DFL | \
CFG_CMD_CACHE | \
CFG_CMD_NAND | \
/*CFG_CMD_EEPROM |*/ \
/*CFG_CMD_I |*/ \
/*CFG_CMD_USB |*/ \
CFG_CMD_REGINFO | \
CFG_CMD_DATE | \
CFG_CMD_ELF)
2、为了能稳定正确引导linux内核,得修改UBOOT的2410CPU频率。
smdk2410的U-BOOT原来运行频率是 ,在这个频率我已开始能正确引导内核,但是后来突然就不能引导了,
总是死在下面这个地方:
Uncompressing Linux....................................................... done, booting the kernel.
按照网上的说法,内核中,在\arch\arm\mach_s 2410\s 2410.c 中
fclk = s 2410_get_pll(MPLLCON, xtal); //读出来的fclk结果和bootloader的频率不一致。
既然不能用 ,VIVI的 能跑得好好的,那我把U-BOOT的频率改成 , 2.6.20 .3的内核和阳初光盘的2.4.18的内核都能正确稳定地引导了。
修改board/yangchu2410/smdk2410.c文件如下:
#define FCLK_SPEED 1
#if FCLK_SPEED==0 /* Fout = 203MHz, Fin = 12MHz for Audio */
#define M_MDIV 0xC3
#define M_PDIV 0x4
#define M_SDIV 0x1
#elif FCLK_SPEED==1 /* Fout = 202.8MHz */
//#define M_MDIV 0xA1
//#define M_PDIV 0x3
//#define M_SDIV 0x1
#define M_MDIV 0x /* Fout = 200MHz */
#define M_PDIV 0x4
#define M_SDIV 0x0
#endif
好了,编译烧写U-BOOT到NAND FLASH,通过setenv 设置bootargs,引导内核时就可以将bootargs传递给内核了。
注意:
1、 对于U-BOOT而言,启动内核时候使用bootm命令才能传递内核参数,使用go命令是不传递内核参数的。
2、 bootm命令引导的只能是用U-BOOT的mkimage工具做过的内核映像,所以要引导阳初光盘带的内核映像,必须用其工具转换一下,至于这个工具怎么用,到U-BOOT的tools目录下找这个工具去吧,./mkimage --help 或者网上找找资料看下就知道了。^_^。

Read More...

移植uboot到2410上总结

这两天有点空闲时间,自己忙里偷闲,偷偷的在实验室的板子上移植了uboot
板子是我们自己制版焊接的,所以稳定性不是很好,不过凑合也能正常工作,一直以来工作都是用vivi,但是这个版本的vivi没有tftp下载功能,所以用xmodem协议下载zImage的时候太漫长了,而自己想移植个带tftp功能的vivi,可是由于没那么多时间就一直没成功,一直uboot也是试试,如果折腾折腾没成功,估计最后也得放弃,毕竟现在没那么多时间,而且主管也没给那个时间,这一切都是凭着工作之余,自己的兴趣所在。
板子是参考广州斯道2410的公版,还有友善之臂,反正内核什么的都没改直接就用他们的这些能正常在我们的板子上跑,我想硬件都一样吧,要不然也不能正常的跑,而且都是smdk2410公版的修改,(硬件是另一个同事做的,我具体不是很懂,不过应该和我想想的一样)
uboot是1.1.4的主要参考了
要参考了luofuchong 大侠
http://www.hhcn.com/cgi-bin/topic.cgi?forum=3&topic=562&start=0&show=
和bekars大侠
http://dev.csdn.net/article/84/84538.shtm
代码就是直接下载的xiaoluo的代码,然后打上他的补丁就ok了
make distclean
make clean
make smdk2410_config
make
就可以生成u-boot.bin了
用sjf2410烧写可以看到能够在板子上启动
一切都比较顺利(我想这都是因为xiaoluo都已经改过了)
但是还是有些问题,那就是不能正常引导内核
到Uncompressing Linux....................................................... done, booting the kernel的时候就停住了
这时候自己连uboot的基本命令都还不懂,又上网查了查用法
继续试验,还是不行,后来参考了另一个帖子,说是因为内核参数没有正确传递的原因,内核应该启动起来了,可是就是没有输出信息,和我在调试其他驱动的时候把console设为tty0一样,于是就朝着这个方向去解决问题
修改board目录下smdk2410.c
#if FCLK_SPEED==0 /* Fout = 203MHz, Fin = 12MHz for Audio */
#define M_MDIV 0xC3
#define M_PDIV 0x4
#define M_SDIV 0x1
#elif FCLK_SPEED==1 /* Fout = 202.8MHz */
//#define M_MDIV 0xA1
//#define M_PDIV 0x3
//#define M_SDIV 0x1
#define M_MDIV 0x /* Fout = 200MHz */
#define M_PDIV 0x4
#define M_SDIV 0x0

#endif
在include/configs/smdk2410.h中加上

#define CONFIG_CMDLINE_TAG 1 /* enable passing of ATAGs */

#define CONFIG_SETUP_MEMORY_TAGS 1

#define CONFIG_INITRD_TAG 1

然后重新编译uboot

重新下载后,问题还是一样,很是郁闷,就有上网抠,查到还有人说是频率不对,我下面转的

几个帖子就是。
smdk2410的U-BOOT原来运行频率是202.8M,把U-BOOT的频率改成200M,

"board/smdk2410/smdk2410.c"

#define FCLK_SPEED 1

#if FCLK_SPEED==0 /* Fout = 203MHz, Fin = 12MHz for Audio */
#define M_MDIV 0xC3
#define M_PDIV 0x4
#define M_SDIV 0x1
#elif FCLK_SPEED==1 /* Fout = 202.8MHz */
//#define M_MDIV 0xA1
//#define M_PDIV 0x3
//#define M_SDIV 0x1
#define M_MDIV 0x5c /* Fout = 200MHz */
#define M_PDIV 0x4
#define M_SDIV 0x0
#endif

重新少些后问题依然,郁闷ing
后来又反复试验,在快要放弃的时候,突然发现有一次能引导kernel了
发现在这个uboot中有个bootargs参数要正确设置,由于受vivi影响,一直都是这么设置的
setenv bootargs="noinitrd console=ttyS0 root=/dev/mtdblock/4"
然后就saveenv了
以为没有问题,所以反复试验都没查这个,但是后来仔细printenv一看
bootargs="noinitrd=console=ttyS0 root=/dev/mtdblock/4"
不知道为什么多了个“=”
又反复设置,就是不能像vivi那样,不明白了,是不是这个uboot的bug还是uboot就是这样,没用过uboot不知道了
后来看设置bootcmd的时候是这样的:
setenv bootcmd=nand read 0x30000 0x1d0000
没有引号,不是自己想象的那样用引号括起来。
于是重新设置bootargs
setenv bootargs=noinitrd console=ttyS0 root=/dev/mtdblock/4
saveenv
这下终于可以boot kernel了
查点到这里就放弃了,回想起来,细心和坚持很重要,要不是坚持,可能这个问题就这么放过去了。
坚持!!!!!!!!!
再一次鼓励了我,虽然这次没什么太多的技术含量(个人感觉没有什么技术含量,就是google,还有就是直觉)
后来重新试验,发现上面修改的频率是有作用的,如果

#define M_MDIV 0x5c /* Fout = 200MHz */
#define M_PDIV 0x4
#define M_SDIV 0x0
改为
#define M_MDIV 0x5c /* Fout = 200MHz */
#define M_PDIV 0x4
#define M_SDIV 0x2
就出现了乱码,可能是波特率也随着改变了,所以有输出但是乱码,
但是

#define CONFIG_CMDLINE_TAG 1 /* enable passing of ATAGs */

#define CONFIG_SETUP_MEMORY_TAGS 1

#define CONFIG_INITRD_TAG 1

这个还没有机会试验呢,但是我想也应该有作用的
不然kernel的参数就传递不过来了

Read More...

星期三, 一月 16, 2008

U-BOOT移植到阳初2410的板子【转】

这个好东西是从阳初论坛上下载的。我自己还没有研究,希望有兴趣的朋友可以研究一下。附件上有源代码,还有专门的word文档说明。以后研究了再放上更多的详细介绍,先发给大家玩玩!最近忙考试和制作简历,没时间!!呵呵!!!!!

以下是作者在论坛的讨论的内容:

晕死,发了半天,居然都没发上来,说我字数限制,我都没几个字。

只能传了。

写的匆忙,还没来得及改,有错的地方,望各位指出。^_^

我的工作环境:

RedHat 9

arm-linux-gcc 4.1.1(glibc2.3.2)

U-BOOT1.2.0

目标板:阳初S3C2410开发板V2.3版

买回来,板子上没有NOR FLASH,给的也只有VIVI,我想用U-BOOT(这个用的比较广),所以只能修改U-BOOT从NAND FLASH启动了。

我的内容包括:

NAND FLASH启动;

NAND FLASH驱动,让U-BOOT可以对NAND FLASH读写;

环境变量保存到NAND FLASH。

引导linux内核

参照的主要是网上的文章,我只不过相当于拼凑了一下。呵呵。

我晕,大小上传也只有100KB。只能压缩传了。

顺便把U-BOOT中修改后的几个文件也发上来:

点击浏览该文件

编译后的U-BOOT.bin,可以利用JTAG烧写到NAND FLASH运行的:

点击浏览该文件

晕,之前做的U-BOOT不能正确阳初光盘编译好的linux映像内核。

下载到板子上0x30008000运行,不行,用bootm和go命令的结果都是和前面的结果一样,最后死在这里:

……

……

Uncompressing Linux....................................................... done, booting the kernel.

往下就没了。网上查了很多文章,说法不一,各人的遇到的特殊情况不同吧。

于是,我用2.6.20.3源码make s3c2410_defconfig默认配置,编译了一下,在板子上跑了一下,结果跑起来了,但是查看启动信息,发现U-BOOT的bootargs并没传递给内核:

U-BOOT的bootargs如下:

bootargs=root=/dev/ram rw initrd="0x308000",6000000 console="ttyS0",115200 mem="64M"

而内核启动显示如下:

Kernel command line: root="/dev/hda1" ro init="/bin/bash" console="ttySAC0"

说明U-BOOT并没有设置bootargs到参数里去。
再查看U-BOOT的include/configs/yangchu2410.h文件,发现没有定义如下:

#define CONFIG_CMDLINE_TAG 1 /* enable passing of ATAGs */

#define CONFIG_SETUP_MEMORY_TAGS 1

#define CONFIG_INITRD_TAG 1

而#define CONFIG_CMDLINE_TAG 1是在传递cmdline时候必须设置的,所以在include/configs/yangchu2410.h文件中添加如上定义。

定义之后,重新编译U-BOOT,烧写到NAND FLASH中,启动板子。

再跑上面编译的2.6.20.3linux,内核启动信息中显示的参数信息和U-BOOT中设置的一致了。

设置U-BOOT的bootargs:noinitrd root="/dev/mtdblock/2" console="ttyS0" mac="00:01:5d:68:7a:0f",再跑阳初光盘带的linxu内核,往下看到兴奋的字眼了:

YANGCHU2410 # bootm 30008000

## Booting image at 30008000 ...

Image Name: yangchu_linux2.4.18

Created: 2007-08-26 8:06:16 UTC

Image Type: ARM Linux Kernel Image (uncompressed)

Data Size: 772272 Bytes = 754.2 kB

Load Address: 30008000

Entry Point: 30008040

Verifying Checksum ... OK

XIP Kernel Image ... OK

Starting kernel ...

Uncompressing Linux....................................................... done, booting the kernel.

Linux version 2.4.18-rmk7-pxa1 (fc@localhost.localdomain) (gcc version 2.95.3 20010315 (release)) #441 7 10 11:29:04 CST 2007

CPU: ARM/CIRRUS Arm920Tsid(wb) revision 0

Machine: Samsung-SMDK2410

On node 0 totalpages: 16384

zone(0): 16384 pages.

zone(1): 0 pages.

zone(2): 0 pages.

Kernel command line: noinitrd root="/dev/mtdblock/2" console="ttyS0" mac="00:01:5d:68:7a:0f"
……
……

楼顶的文章我已经改过了,上传了我更新过的文章。

相应要要修改的U-BOOT以及编译好的uboot.bin也重新上传了

UBOOT引导内核真是搞怪,前几天还能引导的,这几天又不能引导了,但是这些内核用VIVI都是能引导的,搞得头痛死了,总是死在下面这个地方:
Uncompressing Linux....................................................... done, booting the kernel.

后来发现是频率的问题。因为网上有人也遇到此问题,相关说法如下:

之后用仿真器追踪内核结果发现:

start_kernel函数的time_init()中程序进入死循环~~

我随之进入time_init()

继续进入 system_timer->init();

结果发现,我的fclk,pclk都不能得到正确的值,积存器正确,我拿笔都能算出来,可是他就是总出错,所以我一气之下把他们全部写死.

具体如下:
在\arch\arm\mach_s3c2410\s3c2410.c 中 搜索 fclk ;

fclk = s3c2410_get_pll(MPLLCON, xtal); //这是他原来的,结果不是我们想要的200MHZ
fclk =200*1000*1000 ; // 这是我加的
在\arch\arm\mach_s3c2410\time.c 中搜索 pclk:

pclk = clk_get_rate(clk); //这是原来的

pclk = 50*1000*1000; //这是我加的

当然这都是根据2410的DATASHEET而定的

我现在用的是FCLK : HCLK : PCLK = 1 : 2 : 4 ,所以我分别写死为200M 100M 50M.

看来我的问题差不多也出在这边了,fclk得不到正确的值,由于没有仿真器,只能这么推测了。因为我终端上显示出来的传递参数都没有问题。

我再看了看VIVI,它里面用的就是200M。

smdk2410的U-BOOT原来运行频率是202.8M,后来把U-BOOT的频率改成200M,2.6.20.3的内核和阳初光盘的2.4.18的内核都能稳定地引导了。

修改文件如下:

"board/yangchu2410/smdk2410.c"

#define FCLK_SPEED 1

#if FCLK_SPEED==0 /* Fout = 203MHz, Fin = 12MHz for Audio */
#define M_MDIV 0xC3
#define M_PDIV 0x4
#define M_SDIV 0x1
#elif FCLK_SPEED==1 /* Fout = 202.8MHz */
//#define M_MDIV 0xA1
//#define M_PDIV 0x3
//#define M_SDIV 0x1
#define M_MDIV 0x5c /* Fout = 200MHz */
#define M_PDIV 0x4
#define M_SDIV 0x0
#endif

Read More...

星期五, 十二月 28, 2007

以用户空间权限访问GPIO

在将Linux系统移植到相关板子上后,我们面临的就是一个编程问题了。开发板上有很多资源是可以和内核中的驱动对应的,比如我们今天要介绍的,最简单的,gpio。

首先你需要用在/dev下mknod xgpio:

crw-rw-rw- 1 root root 10, 185 Jun 1 13:59 /dev/xgpio

下面就是具体访问gpio的示例:


To write to the channel change the call:
ioctl(fgpio,XGPIO_IN,&sGpioData); to ioctl(fgpio,XGPIO_OUT,&sGpioData);

#include
#include
#include
#include

#include

main(){

int fgpio =0;
struct xgpio_ioctl_data sGpioData;
/* {
__u32 device;
__u32 mask;
__u32 data;
}*/

sGpioData.device=0; /* N=0,1,2,3-> GPIO DEV NR 2*N (Lower 32 bit part)
2*N+1 (Upper 32 bit part)*/
sGpioData.mask=0xffffffff;
sGpioData.data=0×55555555;

fgpio = open (”/dev/xgpio”,O_RDWR);

if( fgpio != -1){
ioctl(fgpio,XGPIO_IN,&sGpioData);//pointer here to xgpio_ioctl_data
printf(”Dip Swich readout 0x%X\n”,sGpioData.data);
}
else
printf(”Can not open GPIO\n”);

close(fgpio);
}// end main

Read More...

星期一, 十二月 03, 2007

一个Linux下的char型设备的驱动

        这个驱动程序是典型char型设备驱动,它涉及到了如何使用共享中断、相同功能的设备共用驱动程序等一些技巧。个人的愚见,欢迎来讨论。
/****************************************************************************
    直放站 UART3 driver
    shanghai xinmin telecom std.
    diming.feng 2007-05
*****************************************************************************/
#include <linux/init.h>
#include <linux/slab.h>
#include <asm/errno.h>
#include <asm/delay.h>
//#include <asm/fcntl.h>
#include <asm/arch/irqs.h>
#include <linux/mm.h>
#include <linux/poll.h>
#include <linux/module.h>
#include <linux/serial_reg.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include "expuart.h"

#define GPIO_CFG0  VPint(0xFFF83000)
#define GPIO_DIR0  VPint(0xFFF83004)
#define GPIO_DATAOUT0 VPint(0xFFF83008)

#define GPIO_CFG5  VPint(0xFFF83050) 
#define GPIO_DIR5  VPint(0xFFF83054)
#define GPIO_DATAOUT5 VPint(0xFFF83058)

#define GPIO_XICFG  VPint(0xFFF83074)
#define GPIO_XISTATUS VPint(0xFFF83078)

#define UART_TX   VPchar(COM_TX_3)
#define UART_RX   VPchar(COM_RX_3)
#define UART_DLL  VPchar(COM_DLL_3)
#define UART_DLM  VPchar(COM_DLM_3) 
#define UART_IER  VPchar(COM_IER_3)
#define UART_IIR  VPchar(COM_IIR_3)
#define UART_FCR  VPchar(COM_FCR_3)
#define UART_LCR  VPchar(COM_LCR_3) 
#define UART_MCR  VPchar(COM_MCR_3) 
#define UART_LSR  VPchar(COM_LSR_3) 
#define UART_MSR  VPchar(COM_MSR_3) 
#define UART_TOR  VPchar(COM_TOR_3)

#define LSR_TE   0x40
#define LSR_THRE  0x20 
#define LSR_RFDR  0x01

#define nIRQ2   31
#define uart3_IRQ  12

#define NOIRQ   0x01
#define RSTIRQ   0x06 
#define RFVIRQ   0x04
#define RFTIRQ   0x0C
#define THRIRQ   0x02
#define MSTIRQ   0x00

#define RX_FIFO_LEVEL 14
#define UART_FCR_LEVEL  0xc0


#define CMD_BANDRATE 0   // set bandrate
#define CMD_UARTLCR  1   // set data bit
#define CMD_RXTIMEOUT 2
#define CMD_MODE  3   // set RS-485/RS-232 mode
#define CMD_MODEM_SET 4   // set internal modem

#define MAJOR_NUM  248
#define YES    1
#define NO    0
#define TIME_OUT  20000

#define uart3_int(band)   do{     \
         UART_LCR = 0; \
         UART_IER = 0; \
         UART_LCR = DLAB;\
         UART_DLL = band;\
         UART_DLM = 0; \
         UART_LCR = 0x03;\
         UART_FCR = 0x07;\ 
         UART_TOR = 0x00;\
        }while(0)

#define write_reg(reg,dat)  do{      \
         UART_TX = 0x80+reg; \
         while((UART_LSR&LSR_TE)!=LSR_TE); \
         UART_TX = dat; \
         while((UART_LSR&LSR_TE)!=LSR_TE); \
        }while(0)
        
#define read_reg(reg,dat)  do{      \
         UART_TX = reg; \
         while((UART_LSR & LSR_RFDR)!=LSR_RFDR); \
         dat = UART_RX; \
        }while(0)

static int uart3tx_busy;
static uart3_dev exp_uart[EXPUART_NUM]={
 {248, "uart3", 0},
 {247, "uart4", 1},
 {246, "uart5", 2},   // internal mode
 {245, "uart6", 3},
};

DECLARE_WAIT_QUEUE_HEAD(expuart1_queue_Rd);
DECLARE_WAIT_QUEUE_HEAD(expuart1_queue_Wr);

DECLARE_WAIT_QUEUE_HEAD(expuart2_queue_Rd);
DECLARE_WAIT_QUEUE_HEAD(expuart2_queue_Wr);

DECLARE_WAIT_QUEUE_HEAD(expuart3_queue_Rd);
DECLARE_WAIT_QUEUE_HEAD(expuart3_queue_Wr);

DECLARE_WAIT_QUEUE_HEAD(expuart4_queue_Rd);
DECLARE_WAIT_QUEUE_HEAD(expuart4_queue_Wr);

static void ms_delay(int ms)
{
 while(ms--){
  udelay(1000);
 }
}

/*
static void write_reg(char reg_addr, char reg_dat)
{
 char temp;
 
 UART_TX = 0x80+reg_addr;
 do{
  temp = UART_LSR;
 }while((temp&LSR_TE)!=LSR_TE);
 UART_TX = reg_dat;
 do{
  temp = UART_LSR;
 }while((temp&LSR_TE)!=LSR_TE);
}
*/

static int uart3_chkbuf(int write, int read, int reqnum)
{
 int temp = write-read;
 if(temp >= 0){
  if(temp >= reqnum){
   return 1;
  }
 }
 else{
  if((temp + RX_BUFF_SIZE)>= reqnum){
   return 1;
  }
 }
 return 0;
}

static void expuart_handler(int irq, void *dev_id, struct pt_regs * regs)
{
 char sub_sifr, int_no, sub_ssr;
 int  expnum;
 int  ctn;
 
 GPIO_XISTATUS = 0;
 uart3_dev *dev = (uart3_dev *)dev_id;
 expnum = dev->no;
 
 /* disable VK3214 all interrupt */
 write_reg(gIR,0x00);
 
 read_reg(gIR,int_no);   // read current interrupt uart
 int_no = int_no & 0x0f;
 if(1<<expnum != int_no){
  goto out;
 }

/* read sub uart of VK3214 interrupt flags */
 read_reg(SSR(expnum),sub_ssr);
 
 // send data to uart
 if((dev->usr_wr_num>0)&&((sub_ssr&4)==4)){
  ctn = dev->usr_wr_num - dev->tx_ctn;
  if(ctn >15){
   ctn = 15;
  }
  UART_TX = 0xc0+(expnum<<4)+(ctn-1);
  while(ctn--){
   UART_TX = dev->txbuf[dev->tx_ctn++];
  }
  while((UART_LSR & LSR_TE)!=LSR_TE);
  do{
   UART_TX = SSR(expnum);
   while((UART_LSR & LSR_RFDR)!=LSR_RFDR);
  }while((UART_RX&4)!=4);
  if(dev->tx_ctn == dev->usr_wr_num){
   write_reg(SIER(expnum),0x01);   // tx interrupt disable, rx interrupt enable
   dev->usr_wr_num = 0;
   dev->tran_flag = 1;
   uart3tx_busy = NO;
   if(exp_uart[0].wait_flag == 1){
   // printk("wake 0\n");
    exp_uart[0].wait_flag = 0;
    wake_up_interruptible(&expuart1_queue_Wr); //
   }
   if(exp_uart[1].wait_flag == 1){
   // printk("wake 1\n");
    exp_uart[1].wait_flag = 0;
    wake_up_interruptible(&expuart2_queue_Wr); //
   }
   if(exp_uart[2].wait_flag == 1){
   // printk("wake 2\n");
    exp_uart[2].wait_flag = 0;
    wake_up_interruptible(&expuart3_queue_Wr); //
   }
   if(exp_uart[3].wait_flag == 1){
   // printk("wake 3\n");
    exp_uart[3].wait_flag = 0;
    wake_up_interruptible(&expuart4_queue_Wr); //
   }
  }
  goto out;  
 }
 
 // receive data from uart
 if((sub_ssr&1) == 1){
  goto out;
 } 
 read_reg(SFSR(expnum), ctn);
 ctn = UART_RX & 0x0f;
 while(ctn--){
  read_reg(SFDR(expnum), dev->rxbuf[dev->Recv_wr_index++]);
  if(dev->Recv_wr_index == RX_BUFF_SIZE){
   dev->Recv_wr_index = 0;
  }
 }
 dev->recv_flag = uart3_chkbuf(dev->Recv_wr_index,dev->Recv_rd_index,dev->usr_rd_num);
 if(dev->recv_flag){
  switch(expnum){
   case 0:
    wake_up_interruptible(&expuart1_queue_Rd); //
    break;
   case 1:
    wake_up_interruptible(&expuart2_queue_Rd); //
    break;
   case 2:
    wake_up_interruptible(&expuart3_queue_Rd); //
    break;
   case 3:
    wake_up_interruptible(&expuart4_queue_Rd); //
    break;
   default:
    break;
  }
 }
out:
 write_reg(gIR,0xf0);
}
                         
ssize_t uart3_read(struct file *flip, char *buf, size_t count, loff_t *offset)
{     
 int i;        
 int expnum;
 wait_queue_t wait;
 uart3_dev *dev = (uart3_dev *)flip->private_data;
         
 expnum = dev->no;
 dev->usr_rd_num = count;
 dev->recv_flag = uart3_chkbuf(dev->Recv_wr_index,dev->Recv_rd_index,dev->usr_rd_num);
 if(dev->recv_flag==0){
  init_waitqueue_entry(&wait, current); //
  switch(expnum){
   case 0:
    add_wait_queue(&expuart1_queue_Rd, &wait); //
    break;
   case 1:
    add_wait_queue(&expuart2_queue_Rd, &wait); //
    break;
   case 2:
    add_wait_queue(&expuart3_queue_Rd, &wait); //
    break;
   case 3:
    add_wait_queue(&expuart4_queue_Rd, &wait); //
    break;
   default:
    break;
  }  
  set_current_state(TASK_INTERRUPTIBLE);
  schedule_timeout(dev->time_out*HZ); 
  set_current_state(TASK_RUNNING);
  switch(expnum){
   case 0:
    remove_wait_queue(&expuart1_queue_Rd, &wait); //
    break;
   case 1:
    remove_wait_queue(&expuart2_queue_Rd, &wait); //
    break;
   case 2:
    remove_wait_queue(&expuart3_queue_Rd, &wait); //
    break;
   case 3:
    remove_wait_queue(&expuart4_queue_Rd, &wait); //
    break;
   default:
    break;
  }  
 }
 count = dev->Recv_wr_index - dev->Recv_rd_index;
 if(count<0){
  count += RX_BUFF_SIZE;
 }
 if(count > dev->usr_rd_num){
  count = dev->usr_rd_num; 
 }
 dev->usr_rd_num = 0;
 for(i=0; i<count; i++){
  buf[i] = dev->rxbuf[dev->Recv_rd_index];
  dev->Recv_rd_index += 1;
  if(dev->Recv_rd_index == RX_BUFF_SIZE){
   dev->Recv_rd_index = 0;
  }
 }
 return count;
}

static int uart3_write(struct file *flip, int *buf, size_t count, loff_t *offset)
{
 int expnum;
 wait_queue_t wait;
 uart3_dev *dev = (uart3_dev *)flip->private_data;
 
 if(count==0){
  return 0;
 }
 dev->tx_ctn = 0;
 expnum = dev->no;
 if((dev->tran_flag==1)&&(uart3tx_busy==NO)){
  goto copy_data;
 }
// printk("wait %d\n",expnum);
 dev->wait_flag = 1;
 init_waitqueue_entry(&wait, current); //
 switch(expnum){
  case 0:
   add_wait_queue(&expuart1_queue_Wr, &wait); //
   break;
  case 1:
   add_wait_queue(&expuart2_queue_Wr, &wait); //
   break;
  case 2:
   add_wait_queue(&expuart3_queue_Wr, &wait); //
   break;
  case 3:
   add_wait_queue(&expuart4_queue_Wr, &wait); //
   break;
  default:
   break;
 } 
 set_current_state(TASK_INTERRUPTIBLE);   
 schedule();
 set_current_state(TASK_RUNNING);
 switch(expnum){
  case 0:
   remove_wait_queue(&expuart1_queue_Wr, &wait); //
   break;
  case 1:
   remove_wait_queue(&expuart2_queue_Wr, &wait); //
   break;
  case 2:
   remove_wait_queue(&expuart3_queue_Wr, &wait); //
   break;
  case 3:
   remove_wait_queue(&expuart4_queue_Wr, &wait); //
   break;
  default:
   break;
 }
copy_data:
 if(count > TX_BUFF_SIZE){
  count = TX_BUFF_SIZE;
 }
 copy_to_user(dev->txbuf, buf, count);
 dev->tran_flag = 0;
 dev->usr_wr_num = count;
 uart3tx_busy = YES;
 write_reg(SIER(expnum),0x03);   // rx and tx interrupt enable
 return count;
}

static int uart3_open(struct inode *inode,struct file* flip)
{
 int result;
 int expnum;
 uart3_dev *dev;
 
 expnum = 248 - MAJOR(inode->i_rdev);
 dev =(uart3_dev *)(&exp_uart[expnum]);
 result = request_irq(nIRQ2, expuart_handler, SA_SHIRQ, dev->dev_name, dev);
 if(result == -1){
  printk("register the expand uart irq failed!\n");
  return -EIO;
 }
 
 dev->no = expnum;
 dev->Recv_wr_index = 0;
 dev->Recv_rd_index = 0;
 dev->usr_rd_num = 0;
 dev->recv_flag = 0;
 dev->time_out = 10;
 
 dev->tx_ctn = 0;
 dev->usr_wr_num = 0;
 dev->tran_flag = 1;
 
 MOD_INC_USE_COUNT;
 flip->private_data = dev;
 
 // default
 write_reg(SCTLR(expnum),B1200+0x08); // enable uart
 write_reg(SFOCR(expnum),0xff);  
 write_reg(SFOCR(expnum),0x0c);
 write_reg(SIER(expnum),0x01);   // rx interrupt enable, tx interrupt disable
 return 0;
}

static int uart3_close(struct inode* i,struct file* flip)
{
 uart3_dev *dev = (uart3_dev *)flip->private_data;
 
 free_irq(nIRQ2, dev);
 MOD_DEC_USE_COUNT;
 return 0;
}

static int uart3_ioctl(struct inode *inode, struct file *flip, unsigned int cmd, unsigned long arg)
{
 char temp;
 int  expnum;
 uart3_dev *dev = (uart3_dev *)flip->private_data;
 
 expnum = dev->no;
 
 switch(cmd)
 {
  case CMD_BANDRATE:  // set bandrate
   if(arg==115200)
    temp = B115200;
   else if(arg==57600)
    temp = B57600;
   else if(arg==38400)
    temp = B38400;
   else if(arg==19200)
    temp = B19200;
   else if(arg==9600)
    temp = B9600;
   else if(arg==4800)
    temp = B4800;
   else if(arg==2400)
    temp = B2400;
   else if(arg==1200)
    temp = B1200;
   else
    temp = B9600;
  // printk("set expuart %d bandrate:%d\n",expnum,arg);
   write_reg(SCTLR(expnum),temp+0x08); // enable uart
   break;
  case CMD_UARTLCR:  // set uart
   write_reg(SCONR(expnum),(char)arg);
   break;
  case CMD_RXTIMEOUT:
   dev->time_out = arg;
   break;
  case CMD_MODEM_SET:
   if((arg == 1)&&(expnum==2)){
    GPIO_DATAOUT5 |= 0x200;
    printk("high\n");
   }
   if((arg == 0)&&(expnum==2)){
    GPIO_DATAOUT5 &= 0xFFFFFDFF;
    printk("low\n");
   }
   break;
  default:
   break;
 }
 return 0;
}

struct file_operations uart3_fops =
{
 owner:  THIS_MODULE,
 open:  uart3_open,
 write:  uart3_write,
 read:  uart3_read,
 ioctl: uart3_ioctl,
 release: uart3_close,
};

static int __init uart3_init(void)
{
 int i;
 char temp;
 int result;
 int cfg;
 int time,time1;

 time1 = 1;
 cfg = GPIO_CFG0;
 cfg &= 0xFFFFFC00;
 cfg |= 0x3C2;   // GPIO.0=nIRQ2, GPIO.1=output, GPIO.3=TXD3,GPIO.4=RXD3
 GPIO_CFG0 = cfg;
 GPIO_DIR0 |= 0x60006;
 GPIO_DATAOUT0 |= 0x4;
 cfg = GPIO_XICFG;
 cfg &= 0xf0;
// cfg |= 0x8;    // low level sensitive
 cfg |= 0xa;    // negative edge triggered
 GPIO_XICFG = cfg;
 
 cfg = GPIO_CFG5;  // GPIO.14=output
 cfg &= 0x3F3FFFF;
 GPIO_CFG5 = cfg;
 GPIO_DIR5 = 0x2000200; 
 GPIO_DATAOUT5 |= 0x200;
  
 uart3_int(96);     // default 9600
 
 GPIO_DATAOUT0 |= 0x02;    // gpio.1=1
 ms_delay(10);
 GPIO_DATAOUT0 &= ~(0x02);   // gpio.1=0
 ms_delay(20);
 GPIO_DATAOUT0 |= 0x02;    // gpio.1=1
 write_reg(gIR,0xf0);   // enable all uart port interrupt

loop:
 uart3_int(96);     // default 9600
 write_reg(gMUCR,B115200);  // main uart bandrate 115200
 uart3_int(6);     // 230400bps@15MHz
 for(i=0;i<time1;i++){
  ms_delay(10);
 }
 time = TIME_OUT;
 UART_TX = gMUCR;
 do{
  temp = UART_LSR;
  time--;
  if(time == 0){
   time1++;
   goto loop;
  }
 }while((temp & LSR_RFDR)!=LSR_RFDR);
 temp = UART_RX;
 if(temp != B115200){
  time1++;
//  printk("temp = %02x\n",temp);
  goto loop;
 }
 
 for(i=0;i<EXPUART_NUM;i++){ 
  result = register_chrdev(exp_uart[i].major_num,exp_uart[i].dev_name,&uart3_fops);
  if(result == 0)
   printk("expand uart %d at 0xfff80300 (irq = 31) is a W90N745!\n",i+1);
 }
 uart3tx_busy = NO;
 return 0;
}

static void uart3_release(void)
{
 int i;
 
 for(i=0;i<EXPUART_NUM;i++){ 
  unregister_chrdev(exp_uart[i].major_num,exp_uart[i].dev_name);
 }
 printk("cancel the device expand uart1,2,3,4!\n");
 return;
}

module_init(uart3_init);
module_exit(uart3_release);
      

Read More...

星期六, 十一月 24, 2007

S3C2410启动信息注释(vivi部分)『转』

uclinux的启动主要分为两个阶段:
第一部分bootloader启动阶段
第二部分linux 内核初始化和启动阶段
     第一节:start_kernel
     第二节:用户模式( user_mode )开始,start_kernel结束
     第三节:加载linux内核完毕,转入cpu_idle进程

Specification of the machine

- CPU: S3C2410
- MEM: 64MB (bank 0)
- ROM: 64MB (Inte Starata Flash Memory)
- got UART ports

64MB RAM (DRAM)

0x3400 0000 +----------------------+
                  |VIVI RAM (size: 1M)    |
0x33F0 0000 +----------------------+ VIVI_RAM_BASE
                  |HEAP AREA(size: 1M)   |
0x33E0 0000 +----------------------+ HEAP_BASE
                  |MMU TABLE(size: 16k)  |
0x33DF C000 +----------------------+ MMU_TABLE_BASE
                 
|                               |
           mtd partition table (size: 16k)| MTD_PART_SIZE -----\
0x33DF 8000 +----------------------+                               |
          vivi parameter table(size: 16k)| PARAMETER_TLB_SIZE  | vivi pri data
0x33DF 4000 |----------------------+                               |
        
linux command line (size: 16k)  | LINUX_CMD_SIZE  -----/
                  |                               |

0x33DF 0000 +----------------------+ VIVI_PRIV_RAM_BASE
                  |                              |
                  |   free memory            |
                  |                              |
0x3010 8000 +----------------------+
                  |   kernel (size: 1MB)     |
0x3000 8000 +----------------------+
                  |                              |
                  |   free memory            |
                  |                              |
0x3000 0100 +----------------------+
           kernel param (size 256Byte)  |
0x3000 0000 +----------------------+ DRAM_BASE


64MB ROM (NAND Flash)

* 0x0400 0000 +-----------------------------+
*                   |                                         |
*                   | jffs2 (size: 61M)                   | user
*                   |                                         |
* 0x0030 0000 +-----------------------------+
*                   | root  (size: 2048k)                 |
* 0x0010 0000 +-----------------------------+
*                   | kernel (size: 832k)                |
* 0x0003 0000 +-----------------------------+
*                   | param (size: 64k)                   |
* 0x0002 0000 +-----------------------------+
*                   | vivi  (size: 128k)                  |
* 0x0000 0000 +-----------------------------+

[root@localhost root]# minicom
Welcome to minicom 2.00.0


OPTIONS: History Buffer, F-key Macros, Search History Buffer, I18nCompiled on Jan 25 2003, 00:15:18.Press CTRL-A Z for help on special keys


minicom信息


VIVI version 0.1.4 (root@BC) (gcc version 2.95.2 20000516 (release) [Rebel.com]5


Bootloader头信息,版本等,这个因不同的bootloader的设计而有所不同,由此你能看出bootloader的版本信息,有很多使用的是通用的bootloader,如u-boot,redboot等。

链接 Boot Loader  VIVI

源代码: vivi/lib/version.c vivi/main.c


#define VIVI_RELEASE "0.1.4"
#define VIVI_COMPILE_BY "root"
#define VIVI_COMPILE_HOST "localhost.localdomain"
#define VIVI_COMPILER "gcc version 2.95.2 20000516 (release)[Rebel.com]"
#define UTS_VERSION "#0.1.4 六 6月 5 05:27:07 CST 2004"

const char *vivi_banner = "VIVI version " VIVI_RELEASE " (" VIVI_COMPILE_BY "@" VIVI_COMPILE_HOST ") (" VIVI_COMPILER ") " UTS_VERSION "\r\n";putstr(vivi_banner);


MMU table base address = 0x33DFC000
Succeed memory mapping.


链接 MMU

    内存映射(memory map)就是指在整个4GB物理地址空间中有哪些地址范围被分配用来寻址系统的RAM单元。比如,在SA-1100CPU中,从0xC000,0000开 始的512M地址空间被用作系统的RAM地址空间,而在Samsung S3C44B0X CPU中,从0x0c00,0000到0x1000,0000之间的64M地址空间被用作系统的RAM地址空间。虽然 CPU 通常预留出一大段足够的地址空间给系统 RAM,但是在搭建具体的嵌入式系统时却不一定会实现CPU预留的全部RAM地址空间。也就是说,具体的嵌入式系统往往只把CPU预留的全部RAM地址空 间中的一部分映射到RAM单元上,而让剩下的那部分预留RAM地址空间处于未使用(unused)状态。由于上述这个事实,因此Boot Loader的stage2必须在它想干点什么之前——比如,将存储在flash上的内核映像读到RAM空间中——检测整个系统的内存映射情况,也即它必 须知道CPU预留的全部RAM地址空间中的哪些被真正映射到RAM地址单元,哪些是处于unused状态的。
    VIVI中用CONFIG_BOOTUP_MEMTEST中的memtest完成基本的RAM检测,针对
Samsung S3C2410 CPU从0x3000,0000到0x3400,0000之间的64M地址空间被用作系统的RAM地址空间。

源代码:vivi/arch/s3c2410/mmu.c

#define MMU_TABLE_BASE (HEAP_BASE - MMU_TABLE_SIZE)
#define HEAP_BASE (VIVI_RAM_BASE - HEAP_SIZE)
#define VIVI_RAM_BASE (DRAM_BASE + DRAM_SIZE - VIVI_RAM_SIZE)
#define DRAM_BASE DRAM_BASE0
#define DRAM_BASE0       0x30000000      /* base address of dram bank 0 */
#define DRAM_SIZE        SZ_64M
#define SZ_8M            0x00800000
#define VIVI_RAM_SIZE    SZ_1M
#define HEAP_SIZE        SZ_1M
#define SZ_1M            0x00100000
#define MMU_TABLE_SIZE   SZ_16K
#define SZ_16K           0x00004000static
unsigned long *mmu_tlb_base = (unsigned long *) MMU_TABLE_BASE;
putstr_hex("MMU table base address = 0x", (unsigned long)mmu_tlb_base);

源代码:vivi/main.c

mem_map_init();
mmu_init();
putstr("Succeed memory mapping.\r\n");



NAND device: Manufacture ID: 0xec, Chip ID: 0x76 (Samsung K9D1208V0M)

链接:闪存芯片

NAND Flash:1989年,东芝公司发明。是以块和页为单位来读写的,不能随机访问某个指定的点。因而相对来说读取速度较慢,而擦除和写入的速度则比较快。一般适用在大容量的多媒体应用中,如:CF,SM。
NOR  Flash:Intel于1988年发明.随机读取的速度比较快,随机按字节写,写入和擦除速度很低。一般适合应用于数据/程序的存贮应用中,如:手机,机顶盒。NOR还可以片内执行(execute-in-place)XIP。

简单的说,NAND类似于硬盘,NOR类似于内存

源代码:vivi/drivers/mtd/nand/smc_core.c


struct nand_flash_dev {
    char * name;
    int manufacture_id;
    int model_id;
    int chipshift;
    char page256;
    char pageadrlen;
    unsigned long erasesize;
};
static struct nand_flash_dev nand_flash_ids[] = {
  {"Toshiba TC5816BDC",     NAND_MFR_TOSHIBA, 0x64, 21, 1, 2, 0x1000},    // 2Mb 5V
  {"Toshiba TC58V16BDC",    NAND_MFR_TOSHIBA, 0xea, 21, 1, 2, 0x1000},    // 2Mb 3.3V
  {"Toshiba TC5832DC",      NAND_MFR_TOSHIBA, 0x6b, 22, 0, 2, 0x2000},    // 4Mb 5V
  {"Toshiba TC58V32DC",     NAND_MFR_TOSHIBA, 0xe5, 22, 0, 2, 0x2000},    // 4Mb 3.3V
  {"Toshiba TC58V64AFT/DC", NAND_MFR_TOSHIBA, 0xe6, 23, 0, 2, 0x2000},    // 8Mb 3.3V
  {"Toshiba TH58V128DC",    NAND_MFR_TOSHIBA, 0x73, 24, 0, 2, 0x4000},    // 16Mb
  {"Toshiba TC58256FT/DC",  NAND_MFR_TOSHIBA, 0x75, 25, 0, 2, 0x4000},    // 32Mb
  {"Toshiba TH58512FT",     NAND_MFR_TOSHIBA, 0x76, 26, 0, 3, 0x4000},    // 64Mb
  {"Toshiba TH58NS100/DC",  NAND_MFR_TOSHIBA, 0x79, 27, 0, 3, 0x4000},    // 128Mb
  {"Samsung KM29N16000",    NAND_MFR_SAMSUNG, 0x64, 21, 1, 2, 0x1000},    // 2Mb 5V
  {"Samsung KM29W16000",    NAND_MFR_SAMSUNG, 0xea, 21, 1, 2, 0x1000},    // 2Mb 3.3V
  {"Samsung unknown 4Mb",   NAND_MFR_SAMSUNG, 0x6b, 22, 0, 2, 0x2000},    // 4Mb 5V
  {"Samsung KM29W32000",    NAND_MFR_SAMSUNG, 0xe3, 22, 0, 2, 0x2000},    // 4Mb 3.3V
  {"Samsung unknown 4Mb",   NAND_MFR_SAMSUNG, 0xe5, 22, 0, 2, 0x2000},    // 4Mb 3.3V
  {"Samsung KM29U64000",    NAND_MFR_SAMSUNG, 0xe6, 23, 0, 2, 0x2000},    // 8Mb 3.3V
  {"Samsung KM29U128T",     NAND_MFR_SAMSUNG, 0x73, 24, 0, 2, 0x4000},    // 16Mb
  {"Samsung KM29U256T",     NAND_MFR_SAMSUNG, 0x75, 25, 0, 2, 0x4000},    // 32Mb
  {"Samsung K9D1208V0M",    NAND_MFR_SAMSUNG, 0x76, 26, 0, 3, 0x4000},    // 64Mb
  {"Samsung K9D1G08V0M",    NAND_MFR_SAMSUNG, 0x79, 27, 0, 3, 0x4000},    // 128Mb
  {NULL,}
};
mtd->name = nand_flash_ids[i].name;
printk("NAND device: Manufacture ID:" \
                " 0x%02x, Chip ID: 0x%02x (%s)\n",
                nand_maf_id, nand_dev_id, mtd->name);


Could not found stored vivi parameters. Use default vivi parameters.

vivi参数

vivi_parameter_t default_vivi_parameters[] = {
    { "mach_type",            MACH_TYPE,    NULL },
    { "media_type",            MT_S3C2410,    NULL },
    { "boot_mem_base",        0x30000000,    NULL },
    { "baudrate",            UART_BAUD_RATE,    NULL },
    { "xmodem_one_nak",        0,        NULL },
    { "xmodem_initial_timeout",    300000,        NULL },
    { "xmodem_timeout",        1000000,    NULL },
    { "ymodem_initial_timeout",    1500000,    NULL },
    { "boot_delay",            0x1000000,    NULL }
};
#define MACH_TYPE        193
#define MT_S3C2410       MT_SMC_S3C2410
#define UART_BAUD_RATE   115200

源代码:vivi/lib/priv_data.c

int init_priv_data(void)
{
    int ret_def;
#ifdef CONFIG_PARSE_PRIV_DATA //#define CONFIG_PARSE_PRIV_DATA 1
    int ret_saved;
#endif
    ret_def = get_default_priv_data();
#ifdef CONFIG_PARSE_PRIV_DATA
    ret_saved = load_saved_priv_data();
    if (ret_def && ret_saved) {
        printk("Could not found vivi parameters.\n");
        return -1;
    } else if (ret_saved && !ret_def) {
        printk("Could not found stored vivi parameters.");
        printk(" Use default vivi parameters.\n");
    } else {
        printk("Found saved vivi parameters.\n");
    }
#else
    if (ret_def) {
        printk("Could not found vivi parameters\n");
        return -1;
    } else {
        printk("Found default vivi parameters\n");
    }
#endif

#ifdef CONFIG_DEBUG_VIVI_PRIV
    display_param_tlb();
    display_mtd_partition();
#endif
    return 0;



Press Return to start the LINUX now, any other key for vivi

按回车进入linux,其它键进vivi。当然,从vivi中boot也可以。

源代码:vivi/main.c

void boot_or_vivi(void)
{
    char c;
    int ret;
    ulong boot_delay;

    boot_delay = get_param_value("boot_delay", &ret);
    if (ret) boot_delay = DEFAULT_BOOT_DELAY;
    /* If a value of boot_delay is zero,
     * unconditionally call vivi shell */
    if (boot_delay == 0) vivi_shell();


    /*
     * wait for a keystroke (or a button press if you want.)
     */
    printk("Press Return to start the LINUX now, any other key for vivi\n");
    c = awaitkey(boot_delay, NULL);
    if (((c != '\r') && (c != '\n') && (c != '\0'))) {
        printk("type \"help\" for help.\n");
        vivi_shell();
    } // 有问题,'\r' '\n'都是回车,'\0'是什么?
    run_autoboot();

    return;
}
【注:这里还有个小问题。就是在这里添加的时候,\n\r要合起来用,不能只用\n。原因如下:
    计算机还没有出现之前,有一种叫做电传打字机(Teletype Model 33)的玩意,每秒钟可以打10个字符。但是它有一个问题,就是打完一行换行的时候,要用去0.2秒,正好可以打两个字符。要是在这0.2秒里面,又有新的字符传过来,那么这个字符将丢失。
    于是,研制人员想了个办法解决这个问题,就是在每行后面加两个表示结束的字符。一个叫做“回车”,告诉打字机把打印头定位在左边界;另一个叫做“换行”,告诉打字机把纸向下移一行。
    这就是“换行”和“回车”的来历,从它们的英语名字上也可以看出一二。
    后来,计算机发明了,这两个概念也就被般到了计算机上。那时,存储器很贵,一些科学家认为在每行结尾加两个字符太浪费了,加一个就可以。于是,就出现了分歧。Unix 系统里,每行结尾只有“<换行>”,即“\n”;Windows系统里面,每行结尾是“<换行><回车>”,即“\ n\r”;Mac系统里,每行结尾是“<回车>”。一个直接后果是,Unix/Mac系统下的文件在Windows里打开的话,所有文字会变成一行;而Windows里的文件在Unix/Mac下打开的话,在每行的结尾可能会多出一个^M符号。
    这几个地方我都遇到过,不过一直没有搞清楚。现在才算是找到根源了。】



Copy linux kernel from 0x00030000 to 0x30008000, size = 0x00100000 ... done

    启 动linux kernel,kernel映像必须被放到MTD设备的一个分区中,from、size分别表示linux kernel起始地址和kernel的大小。为什么要指定kernel大小呢?因为kernel首先要被copy到boot_mem_base + 0x8000的地方,然后在boot_mem_base + 0x100开始的地方设置内核启动参数。要拷贝 kernel,当然需要知道kernel的大小啦,这个大小不一定非要和kernel实际大小一样,但是必须大于等于kernel的大小。(单位字节)
  
    media_type是指定的媒介类型,因为boot命令对不同媒介的处理方式是不同的,例如如果kernel在 SDRAM中,那么boot执行的过程中就可以跳过拷贝kernel映像到SDRAM中这一步骤了
   
Boot命令识别的媒介类型有以下三种:
ram 表示从RAM中启动linux kernel,linux kernel必须要放在RAM中,我的S3C2410平台就是如此。
nor 表示从NOR Flash中启动linux kernel,linux kernel必须已经被烧写到了NOR Flash中
smc 表示从NAND Flash中启动linux kernel,linux kernel必须已经被烧写到了NAND Flash中 


源代码:vivi/lib/boot-kernel.c

    int boot_kernel(ulong from, size_t size, int media_type)
{
    int ret;
    ulong boot_mem_base;    /* base address of bootable memory */
    ulong to;

    boot_mem_base = get_param_value("boot_mem_base", &ret);
    if (ret) {
        printk("Can't get base address of bootable memory\n");
        printk("Get default DRAM address. (0x%08lx\n", DRAM_BASE);
        boot_mem_base = DRAM_BASE;
    }   //boot_mem_base = 0x30000000

    /* copy kerne image */
    to = boot_mem_base + LINUX_KERNEL_OFFSET;
        // #define LINUX_KERNEL_OFFSET    0x8000
        // to = 0x30008000
    printk("Copy linux kernel from 0x%08lx to 0x%08lx, size = 0x%08lx ... ",from, to, size);
    ret = copy_kernel_img(to, (char *)from, size, media_type);
        // 将内核镜像从NAND FLASH拷入RAM
        //
media_type=MT_SMC_S3C2410
    if (ret) {
        printk("failed\n");
        return -1;
    } else {
        printk("done\n");
    }

    return 0;
}

  
void command_boot(int argc, const char **argv)
{
    int media_type = 0;
    ulong from = 0;
    size_t size = 0;
    mtd_partition_t *kernel_part;
    int ret;
   
    media_type = get_param_value("media_type", &ret);
            if (ret) {
                printk("Can't get default 'media_type'\n");
                return;
            }
    kernel_part = get_mtd_partition("kernel");
            if (kernel_part == NULL) {
                printk("Can't find default 'kernel' partition\n");
                return;
            }
    from = kernel_part->offset;
    size = kernel_part->size;
    boot_kernel(from, size, media_type);
}

user_command_t boot_cmd = {
    "boot",
    command_boot,
    NULL,
    "boot [{cmds}] \t\t\t-- Booting linux kernel"
};

zImage magic = 0x016f2818

判断内核文件是否为压缩镜像,而当前文件是压缩镜像


源文件: vivi/lib/boot-kernel.c

#define LINUX_ZIMAGE_MAGIC    0x016f2818

if (*(ulong *)(to + 9*4) != LINUX_ZIMAGE_MAGIC) {
       printk("Warning: this binary is not compressed linux kernel image\n");
       printk("zImage magic = 0x%08lx\n", *(ulong *)(to + 9*4));
    } else {
        printk("zImage magic = 0x%08lx\n", *(ulong *)(to + 9*4));
    }

Setup linux parameters at 0x30000100
linux command line is: "noinitrd root=/dev/bon/3 init=/linuxrc console=ttyS0"


设置linux参数和控制行

static void setup_linux_param(ulong param_base)
{
/*
linux parameters*/
    struct param_struct *params = (struct param_struct *)param_base;
    char *linux_cmd;
    printk("Setup linux parameters at 0x%08lx\n", param_base);
    memset(params, 0, sizeof(struct param_struct));
    params->u1.s.page_size = LINUX_PAGE_SIZE;
    params->u1.s.nr_pages = (DRAM_SIZE >> LINUX_PAGE_SHIFT);

/* set linux command line */
    linux_cmd = get_linux_cmd_line();//
linux_cmd = 0x33DF8008
    if (linux_cmd == NULL) {
        printk("Wrong magic: could not found linux command line\n");
    } else {
        memcpy(params->commandline, linux_cmd, strlen(linux_cmd) + 1);
        printk("linux command line is: \"%s\"\n", linux_cmd);
    }
}

//
#define boot_mem_base 0x30000000
//#define LINUX_PARAM_OFFSET 0x100
setup_linux_param(boot_mem_base + LINUX_PARAM_OFFSET);


MACH_TYPE = 193

/* Get machine type */
    mach_type = get_param_value("mach_type", &ret);
    printk("MACH_TYPE = %d\n", mach_type);

NOW, Booting Linux......

激动人心的消息,终于可以引导linux了。。。

源代码: vivi/lib/boot-kernel.c

printk("NOW, Booting Linux......\n");
    call_linux(0, mach_type, to);

#elif defined(CONFIG_ARCH_S3C2410)
void  call_linux(long a0, long a1, long a2)
{
    cache_clean_invalidate();
    tlb_invalidate();

__asm__(
    "mov    r0, %0\n"
    "mov    r1, %1\n"
    "mov    r2, %2\n"
    "mov    ip, #0\n"
    "mcr    p15, 0, ip, c13, c0, 0\n"    /* zero PID */
    "mcr    p15, 0, ip, c7, c7, 0\n"    /* invalidate I,D caches */
    "mcr    p15, 0, ip, c7, c10, 4\n"    /* drain write buffer */
    "mcr    p15, 0, ip, c8, c7, 0\n"    /* invalidate I,D TLBs */
    "mrc    p15, 0, ip, c1, c0, 0\n"    /* get control register */
    "bic    ip, ip, #0x0001\n"        /* disable MMU */
    "mcr    p15, 0, ip, c1, c0, 0\n"    /* write control register */
    "mov    pc, r2\n"
    "nop\n"
    "nop\n"
    : /* no outpus */
    : "r" (a0), "r" (a1), "r" (a2)
    );
//全是汇编,有空再研究

Boot Loader 调用 Linux 内核的方法是直接跳转到内核的第一条指令处,也即直接跳转到 MEM_START+0x8000 地址处。在跳转时,下列条件要满足: 

1. CPU 寄存器的设置: 
R0=0;
R1=机器类型 ID;关于 Machine Type Number,可以参见 linux/arch/arm/tools/mach-types。 
R2=启动参数标记列表在 RAM 中起始基地址; 

2. CPU 模式:
必须禁止中断(IRQs和FIQs);
CPU 必须 SVC 模式;

3. Cache 和 MMU 的设置:
MMU 必须关闭;
指令 Cache 可以打开也可以关闭;
数据 Cache 必须关闭;

Read More...

嵌入式一些有用的东西

一、嵌入式系统
嵌入式系统概述 http://blogimg.chinaunix.net/blog/upfile/070926202343.pdf
嵌入式系统的发展现状 http://blogimg.chinaunix.net/blog/upfile/070929025142.pdf
符号说明 http://blogimg.chinaunix.net/blog/upfile/070924162110.pdf

二、视频监控
视频监控系统研究现状 http://blogimg.chinaunix.net/blog/upfile/070928034009.pdf
视频监控系统的发展历程 http://blogimg.chinaunix.net/blog/upfile/070924163711.pdf
视频监控系统的发展方向 http://blogimg.chinaunix.net/blog/upfile/070928034003.pdf
视频监控系统的组成 http://blogimg.chinaunix.net/blog/upfile/070924163839.pdf

三、视频数据采集
3.1 S3C2410概述 http://blogimg.chinaunix.net/blog/upfile/070926202329.pdf
vivi_理论 http://blogimg.chinaunix.net/blog/upfile/070926202336.pdf

3.2 Linux_理论 http://blogimg.chinaunix.net/blog/upfile/070926202850.pdf
内核的编译_理论 http://blogimg.chinaunix.net/blog/upfile/070926203800.pdf

3.3 OV511摄像头
采用USB摄像头 http://blogimg.chinaunix.net/blog/upfile/070929025205.pdf
OV511与OV7610_理论 http://blogimg.chinaunix.net/blog/upfile/070926202318.pdf
OV7620_理论 http://blogimg.chinaunix.net/blog/upfile/070929025211.pdf

四、视频数据压缩编码
MPEG-4_理论 http://blogimg.chinaunix.net/blog/upfile/070928033956.pdf

五、视频数据传输
流媒体理论基础 http://blogimg.chinaunix.net/blog/upfile/070924162338.pdf
ASF流格式 http://blogimg.chinaunix.net/blog/upfile/070924153047.pdf
RTP/RTCP

六、视频分析处理
图形用户界面及MiniGUI_理论http://blogimg.chinaunix.net/blog/upfile/070929025158.pdf
RGB和YUV颜色空间_理论 http://blogimg.chinaunix.net/blog/upfile/070928032645.pdf
   数字图像处理技术 http://blogimg.chinaunix.net/blog/upfile/070929025152.pdf

Read More...

S3C2410启动信息注释(user_mode部分)『转』

uclinux的启动主要分为两个阶段: 第一部分bootloader启动阶段 第二部分linux 内核初始化和启动阶段 第一节:start_kernel 第二节:用户模式( user_mode )开始,start_kernel结束 第三节:加载linux内核完毕,转入cpu_idle进程

Linux NET4.0 for Linux 2.4
Based upon Swansea University Computer Society NET3.039

英国威尔士,斯旺西大学的NET3.039, TCP/IP 协议栈。
此信息,在linux启动过程中都会出现。
Initializing RT netlink socket
BlueZ Core ver 2.4 Copyright (C) 2000,2001 Qualcomm Inc
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
CPU clock = 202.800000 Mhz, HCLK = 101.400000 Mhz, PCLK = 50.700000 Mhz

对Socket的初始化,socket_init(),Netlink 一种路由器管理协议(linux-2.4.22\net\core\Rtnetlink.c,Routing netlink socket interface: protocol independent part。 其中RT是route路由的意思。这句输出是在create产生rtnetlink的socket套接字时的一个调试输出。)

此信息,在linux启动过程中都会出现。

Initializing S3C2410 buffer pool for DMA workaround

初始化内存池

Starting kswapd

启动交换守护进程kswapd,进程IO操作例程kpiod。

kswapd可以配合kpiod运行。进 程有时候无事可做,当它运行时也不一定需要把其所有的代码和数据都放在内存中。这就意味着我们可以通过把运行中程序不用的内容切换到交换分区来更好的是利 用内存。大约每隔1秒,kswapd醒来并检查内存情况。如果在硬盘的东西要读入内存,或者内存可用空间不足,kpiod就会被调用来做移入/移出操作。 kswapd负责检查,kpiod负责移动。

devfs: v1.10 (20020120) Richard Gooch (rgooch@atnf.csiro.au)
devfs: boot_options: 0x1


Devfs模块的输出信息。设备文件系统devfs,版本1.12c

Samsung S3C2410X (i2c) algorithm module version 2.6.1 (20010830)
iic_s3c2410_init: Samsung S3C2410X iic adapter module version 2.6.1 (20010830)
i2c-dev.o: Registered 'Samsung S3C2410X IIC adapter' as minor 0
s3c2410_init: Initialized IIC on S3C2410X, 386kHz clock
iic_s3c2410_init: initialized iic-bus at 0xf4000000.


I2C

tts/%d0 at I/O 0x50000000 (irq = 52) is a S3C2410
tts/%d1 at I/O 0x50004000 (irq = 55) is a S3C2410
tts/%d2 at I/O 0x50008000 (irq = 58) is a S3C2410

Console: switching to colour frame buffer device 80x60
Installed S3C2410 frame buffer


framebuffer

pty: 256 Unix98 ptys configured

Pty模块的输出信息,与控制台操作有关的设置。
将通过 devpts 文件系统使用 Unix98 PTYs,(Pseudo-ttys (telnet etc) device是伪ttys设备的缩写。
  • ① TTY(/dev/tty)是TeleTYpe的一个老缩写,为用户输入提供不同控制台的设备驱动程序。它的名字来源于实际挂接到 UNIX系统的、被称为电传打字机(teletype)的终端。在Linux下,这些文件提供对虚拟控制台的支持,可以通过按<Alt-F1>到<Alt -F6>键来访问这些虚拟控制台。这些虚拟控制台提供独立的、同时进行的本地登录对话过程
  • ② ttys(/dev/ttys)是计算机终端的串行接口。/dev/ttyS0对应MS-DOS下的 COM1。

使 用 make dev脚本MAKEDEV来建立pty文件。这样系统内核就支持Unix98风格的pty了。在进行Telnet登录时将要用到/dev/pty设备。 pty是伪终端设备,在远程登录等需要以终端方式进行连接,但又并非真实终端的应用程序中必须使用这种设备,如telnet或xterm等程序。 Linux 2.2以后增添了UNIX98风格的Pty设备,它使用一个新的文件系统(devpts针对伪终端的文件系统)和一个克隆的设备cloning device来实现其功能。

linux-2.4.22\drivers\char\Pty.c, 在devfs_mk_dir (NULL, "pts", NULL);时会输出上面的信息。

s3c44b0-kbd initialized
s3c2410-ts initialized
s3c2410-adc initialized
S3C2410 Real Time Clock Driver v0.1

S3C2410键盘、 、ad转换器、实时时钟初始化

block: 128 slots per queue, batch=32
Uniform Multi-Platform E-IDE driver Revision: 6.31
ide: Assuming 50MHz system bus speed for PIO modes; override with idebus=xxne.c:v1.10 9/23/94 Donald Becker (becker@scyld.com)
Last modified Nov 1, 2000 by Paul Gortmaker

ide块设备驱动

eth0: NE2000 found at 0xd1000200, using IRQ 2.
PPP generic driver version 2.4.1

网卡驱动,基地址为:
0xd1000200,中断号:2

SCSI subsystem driver Revision: 1.00
request_module[scsi_hostadapter]: Root fs not mounted

USB设备信息,USB会被当做SCSI来处理。

UDA1341 audio driver initialized

声卡驱动

NAND device: Manufacture ID: 0xec, Chip ID: 0x76 (Samsung K9D1208V0M)
Find a MTD partition from BONFS -> nandflash0 (bon4)
Creating 1 MTD partitions on "Samsung K9D1208V0M":
0x00430000-0x03f30000 : "nandflash0 (bon4)"
devfs_mk_dir(bon): using old entry in dir: c03650a0 ""
bon0: 00000000-00020000 (00020000) 00000000
bon1: 00020000-00030000 (00010000) 00000000
bon2: 00030000-00130000 (00100000) 00000000
bon3: 00130000-00430000 (00300000) 00000000
bon4: 00430000-03f30000 (03b00000) 00000001
bon5: 03f30000-03ffc000 (000cc000) 00000000


NAND device

flash提供了写BUFFER的命令来加快对flash上块的操作。对Flash擦除和写数据是很慢的。如果用写BUFFER的命令会快一点。据 手册上说,会快20倍。Buffer Size :5 bytes的buffer缓冲不是每个块都有,是整个flash只有一个5 bytes的buffer,用写BUFFER命令对所有的块进行写操作,都要用同一个buffer,写Buffer是主要检查buffer是否 available,其实buffer起缓冲作用,来提高工作效率。

比如某flash有128个128K字节 块。允许用户对任意块进行字节编程和写缓冲器字节编程操作,每字节编程时间为210μs;若采用写缓冲器字节编程方式,32字节编程共需218μs,每字 节编程时间仅为6.8μs。芯片的块擦除时间为1s,允许在编程或块擦除操作的同时进行悬挂中断去进行读操作,待读操作完成后,写入悬挂恢复命令,再继续 编程或块擦除。

此处为重要信息部分,需要特别留意。在内存中映射过的flash,创建三个MTD分区:flash上的内容将被映射到内存中的对应地址
前128K为BootLoader--->0x00000000-0x00020000
接着的128K为系统配置信息Config存放的位置--->0x00020000-0x00040000
再后面的 16M - 2X128K 为romfs的存放处.--->0x00040000-0x01000000
上面的内容,大家可以根据前面的换算公式得到。
A> 编译的bootloader一般大小约50K左右;
B> 在此处就知道了配置信息config是放在第2分区中的;
C> 制作的romfs的大小,一般为8M或10M左右,所以能放得下;

对于linux 的根文件系统,目前有三种块设备的驱动可以选择,它们分别是:

a) Blkmem 驱动
b) MTD 驱动
c) RAM disk 驱动

Blkmem 驱动是专门为uclinux 开发的一种块设备驱动,它是uclinux系统中最为古老和通用的块设备驱动。它原理相对简单但是配置比较复杂,需要根据你即的Flash的分区使用情况 来修改代码。当然修改的结果是它可以对一些NOR型的Flash进行读写操作。不过目前支持的Flash类型不够多。如果新加入对一种Flash的支持需 要作的工作量比较大。

Linux的MTD驱动是标准Linux的Flash驱动。它支持大量的设备, 有足够的功能来定义Flash的分区,进行地址映射等等。使用MTD你可以在一个系统中使用不同类型的Flash。它可以将不同的Flash组合成一个线 性的地址让你来使用。在标准的Linux 2.4内核中MTD有一系列的选项,你可以根据个人系统的需要来选择,定制。

另 外一种选择就是RAM disk 驱动。在PC上它经常用于没有硬盘的Linux的启动过程。它和Flash没有直接的关系。不过当Flash上启动的是经过压缩的内核时。RAM disk 可以作为根文件系统。MTD 驱动提供了对Flash强大的支持,你通过它甚至可以在Flash上运行一个可以读写的真正的文件系统,比如JFFS2。而Blkmem驱动则望尘莫及

usb.c: registered new driver usbdevfs
usb.c: registered new driver hub
usb-ohci.c: USB OHCI at membase 0xe9000000, IRQ 26
usb.c: new USB bus registered, assigned bus number 1
hub.c: USB hub found
port #1 suspened!
port #0 alived!
hub.c: 1 port detected
Initializing USB Mass Storage driver...
usb.c: registered new driver usb-storage
USB Mass Storage support registered.

USB信息


NET4: Linux TCP/IP 1.0 for NET4.0

调用inet_init [ linux-2.4.22\net\ipv4\Af_inet.c ]时的输出信息, 在启动过程中被socket.c调用到。
IP Protocols: ICMP, UDP, TCP, IGMP

列出可以支持的IP协议,此处为kernel源代码inet_add_protocol(p);的输出。在linux启动过程中,都会看到这句的输出。

IP: routing cache hash table of 512 buckets, 4Kbytes

IP路由代码的输出信息。

ip_rt_init [ linux-2.4.22\net\ipv4\Route.c ],设置 IP module,路由缓冲hash表

TCP: Hash tables configured (established 4096 bind 4096)

TCP协议初始化输出信息。tcp_init [ linux-2.4.22\net\ipv4\Tcp.c ]

NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.

UNIX网络协议信息。

af_unix_init[ linux-2.4.22\net\unix\Af_unix.c ], 多种连接的一种(IPv4, UNIX domain sockets, IPv6和IrDA). SMP 对称多处理器—Symmetrical Multi Processing,这里主要是指UNIX的一些网络协议。

上面的关于网络的输出信息是在linux启动信息中都会出现的。

NetWinder Floating Point Emulator V0.95 (c) 1998-1999 Rebel.com



VFS: Mounted root (cramfs filesystem).

虚拟文件系统VFS(Virtual Filesystem Switch)的输出信息。

再次强调一下 一个概念。VFS 是一种软件机制,也可称它为 Linux 的文件系统管理者,它是用来管理实际文件系统的挂载点,目的是为了能支持多种文件系统。kernel会先在内存中建立一颗 VFS 目录树,是内存中的一个数据对象,然后在其下挂载rootfs文件系统,还可以挂载其他类型的文件系统到某个子目录上。


Mounted devfs on /dev

加载devfs设备管理文件系统到dev安装点上。/dev是我们经常会用到的一个目录。在2.4的kernel中才有使用到。每次启动时内核会自动挂载devfs。

devfs 提供了访问内核设备的命名空间。它并不是建立或更改设备节点,devfs只是为你的特别文件系统进行维护。一般我们可以手工mknod创件设备节点。 /dev目录最初是空的,里面特定的文件是在系统启动时、或是加载模组后驱动程序载入时建立的。当模组和驱动程序卸载时,文件就消失了。


Freeing init memory: 68K

释放1号用户进程init所占用的内存。

yaffs: dev is 7937 name is "1f:01"
mount: Mounting ramfs on /root failed: No such file or directory


VFS

cramfs 是 Linus Torvalds 本人开发的一个适用于嵌入式系统的小文件系统。由于它是只读的,所以,虽然它采取了 zlib 做压缩,但是它还是可以做到高效的随机读取。 cramfs 不会影响系统读取文件的速度,又是一个高度压缩的文件系统。

我们制作image文件之后,我们还要考虑怎样才能在系统运行的时候,把这个 image 文件 mount 上来,成为一个可用的文件系统。由于这个 image 文件不是一个通常意义上的 block 设备,我们必须采用 loopback 设备来完成这一任务,如:
mount -o loop -t cramfs /usr.img /usr

这样,就可以经由 loopback 设备,把 usr.img 这个 cramfs 的 image 文件 mount 到 /usr 目录上去了。内核中需要对loopback这个设备的支持。
cramfs 的压缩效率一般都能达到将近 50%。
Cramfs通过优化索引节点表的尺寸和除去传统文件系统中文件之间的空间浪费来达到节约空间的目的。它还使用了zlib压缩,实现优于2:1的压缩比例。解压缩过程的系统开销并不是很大,因为Cramfs支持指定单块的解压,而并不必解压缩整个文件。
Cramfs不仅能节省空间,还能避免非正常关机导致的等待fsck或手工进行fsck的麻烦。它通过只读的方式达到这一目的。

BusyBox v1.00 (2005.01.20-11:59+0000) Built-in shell (ash)

BusyBox

Enter 'help' for a list of built-in commands.

help

runing /etc/profile ok
[/mnt/yaffs]


OK

Read More...