udev的使用

十 08 2013 由 创建在标签 开发

UDEV的文章网上有很多,但是很多都是直接转载过来,所以搜了很久都是相同的东西。关于UDEV英文的资料已经很全面了,我也不会去翻译那些文档。我主要从如何使用着手去写这篇文章,让读的人能够很快找到自己想要的东西。

配置

Udev有两种配置,一种是udev的配置,另一种是热插拔设备的规则配置;

udev配置文件

一个典型的配置如下:

# cat /etc/udev/udev.conf
# udev.conf
# The initial syslog(3) priority: "err", "info", "debug" or its
# state can be changed with: "udevcontrol log_priority=".
udev_root="/dev/" # 设备节点的根目录
udev_rules="/etc/udev/rules.d" #规则文件的路径,里面的具体文件格式在下一节介绍
udev_log="err" #udev的日志级别

规则配置文件

规则文件以.rules为后缀名,每一个文件处理一系列规则来帮助udev分配名字给设备文件以保证能被内核识别。

在一个规则文件中,以”#”开头的行被认为是注释。每一个非空的行都是一条规则,规则不能跨越多行。一条规则由多个规则语句(条件判断或赋值)组成,每个规则间用‘,’分隔。如 key OP vaule(OP表示操作符,后面提到的key和value均指此处)。

操作符

操作符如下表所示。

操作符 意义
== 比较是否相等
!= 比较是否不相等
= 给一个key 赋值。 表示一个列表的key会被重置,并且把这个唯一的值传给它
+= 将一个值增加到key中
:= 将一个值传给一个key,并且不允许再修改这个key

匹配关键字

这些关键字用于匹配设备,可以根据指定的条件执行特定的动作。

关键字 意义
ACTION 匹配事件的动作名
DEVPATH 匹配事件的设备devpath
KERNEL 匹配事件的设备名
NAME 匹配网络接口或者设备节点的名字。NAME 只有在前面的规则赋值之后才可以使用。
SYMLINK 匹配设备节点符号链的名字。SYMLINK 只有在前面的规则赋值之后才可以使用。可以有多个symlinks,只需要匹配一个。
SUBSYSTEM 匹配设备子系统,如block表示块设备,net代表网络等;
DRIVER 匹配设备的驱动名。只对绑定到一个驱动的设备有用。
ATTR { filename } 匹配事件设备的 sysfs 属性。
KERNELS 向上搜索devpath,直到找到一个匹配的设备名
SUBSYSTEMS 向上搜索devpath,直到找到一个匹配的子系统名
DRIVERS 向上搜索devpath,直到找到一个匹配的驱动名
ATTRS{ filename } 向上搜索devpath,直到找到一个含匹配 sysfs 属性的设备
ENV{key} 内核设置的环境变量
TAG 设备的 tag(暂时没有明白这个的用途)
TEST{octal mode mask} 测试一个文件是否存在,可以指定一个8进制的模式掩码。
PROGRAM 执行一个程序。如果程序成功返回, key 为 true。设备的属性被放在被执行进程的环境变量中,该程序的输出为 stdout, 可以从 RESULT 这个 key 读取。
RESULT 匹配最近一次 PROGRAM 调用的返回字符串。它应该在 PROGRAM 之后使用。

注:加了s的关键字会找其devpath的父目录,可以使用udevinfo -a -p /sys/***来查看具体的路径;

赋值关键字

这部分关键字用于修改设备的属性或者环境变量。

操作符 意义
NAME 修改网络设备的节点
SYMLINK 创建设备节点的符号链接;
OWNER, GROUP, MODE 设备节点的属性,用于修改用户组的权限
ATTR {key} 修改sysfs中设备属性的值
ENV {key} 修改环境变量
RUN 对于特定设备指定执行的命令
LABEL GOTO 可以跳到的地方
GOTO 跳到下一个带有匹配名字的 LABEL 处

上面对基本的配置进行了简单的介绍,现在看了一下之后基本上就是man手册里面的内容了,可以参考man udev中的内容。

配置实例

  • 网络设备的开机自动up和更名
SUBSYSTEM=="net", ACTION=="add", KERNEL=="eth*", NAME="lan", RUN+="/sbin/ifconfig lan up"
SUBSYSTEM=="net", ACTION=="add", KERNEL=="lo", RUN+="/sbin/ifconfig lo up"

上例中,网络设备的子系统名字是“net”,在开机时会有“add”事件,kernel中用了*号来匹配设备号,后面的NAME用于将eth0改成lan,这里之所以这样是因为我们的嵌入式设备只有一个网卡,不会因为多个网卡而造成冲突,同时将eth*改为lan的目的是为了管理起来方便(这样每次设备插入时就自动改为lan,不需要改上层的软件代码,增强代码的可移植性);最后RUN用于将接口UP。

  • 磁盘热插拔
ACTION=="add", KERNEL=="sd[a-z][1-9]", SUBSYSTEM=="block",  SYMLINK+="disk/by-name/%k"
ACTION=="add", KERNEL=="sd[a-z][1-9]", SUBSYSTEM=="block", RUN+="/bin/mkdir -p /disk/%k"
ACTION=="add", KERNEL=="sd[a-z][1-9]", SUBSYSTEM=="block", RUN+="/bin/mount -t auto /dev/%k /disk/%k"
ACTION=="remove", KERNEL=="sd[a-z][1-9]", SUBSYSTEM=="block", RUN+="/bin/umount -l /disk/%k"
ACTION=="remove", KERNEL=="sd[a-z][1-9]", SUBSYSTEM=="block", RUN+="/bin/rm -rf /disk/%k"

磁盘热插拔分为两个部分,一个是磁盘的插入,另一个是磁盘的移除;插入时现在devfs中创建按磁盘名字区分的链接;第二句穿件要mount的目录;第三句是自动mount到刚刚创建的目录;最后两句是移除磁盘时的操作,即先umount,再删除mount的路径。

udevinfo工具

通过udevinfo工具可以查看到设备的一些变量,这样可以帮助我们来写规则文件。下面是一个磁盘设备在执行udevinfo命令后的输出。

  looking at device '/block/sdb/sdb1':
    KERNEL=="sdb1"
    SUBSYSTEM=="block"
    DRIVER==""
    ATTR{dev}=="8:17"
    ATTR{partition}=="1"
    ATTR{start}=="63"
    ATTR{size}=="7892929"
    ATTR{ro}=="0"
    ATTR{alignment_offset}=="0"
    ATTR{discard_alignment}=="0"
    ATTR{stat}=="     322      391      800     4900      351    43241    43592   464200        0     7700   469100"
    ATTR{inflight}=="       0        0"

  looking at parent device '/devices/platform/hiusb-ehci.0/usb1/1-1/1-1:1.0/host3/target3:0:0/3:0:0:0/block/sdb':
    KERNELS=="sdb"
    SUBSYSTEMS=="block"
    DRIVERS==""
    ATTRS{dev}=="8:16"
    ATTRS{range}=="16"
    ATTRS{ext_range}=="256"
    ATTRS{removable}=="1"
    ATTRS{ro}=="0"
    ATTRS{size}=="7892992"
    ATTRS{alignment_offset}=="0"
    ATTRS{discard_alignment}=="0"
    ATTRS{capability}=="51"
    ATTRS{stat}=="     323      391      808     4900      351    43241    43592   464200        0     7700   469100"
    ATTRS{inflight}=="       0        0"
    ATTRS{events}=="media_change"
    ATTRS{events_async}==""
    ATTRS{events_poll_msecs}=="-1"

  looking at parent device '/devices/platform/hiusb-ehci.0/usb1/1-1/1-1:1.0/host3/target3:0:0/3:0:0:0/block':
    KERNELS=="block"
    SUBSYSTEMS==""
    DRIVERS==""

  looking at parent device '/devices/platform/hiusb-ehci.0/usb1/1-1/1-1:1.0/host3/target3:0:0/3:0:0:0':
    KERNELS=="3:0:0:0"
    SUBSYSTEMS=="scsi"
    DRIVERS=="sd"
    ATTRS{device_blocked}=="0"
    ATTRS{type}=="0"
    ATTRS{scsi_level}=="3"
    ATTRS{vendor}=="ADATA   "
    ATTRS{model}=="USB Flash Drive "
    ATTRS{rev}=="0.00"
    ATTRS{state}=="running"
    ATTRS{timeout}=="30"
    ATTRS{iocounterbits}=="32"
    ATTRS{iorequest_cnt}=="0x2b9"
    ATTRS{iodone_cnt}=="0x2b9"
    ATTRS{ioerr_cnt}=="0x1"
    ATTRS{modalias}=="scsi:t-0x00"
    ATTRS{evt_media_change}=="0"
    ATTRS{queue_depth}=="1"
    ATTRS{queue_type}=="none"
    ATTRS{max_sectors}=="240"

  looking at parent device '/devices/platform/hiusb-ehci.0/usb1/1-1/1-1:1.0/host3/target3:0:0':
    KERNELS=="target3:0:0"
    SUBSYSTEMS=="scsi"
    DRIVERS==""
    ATTRS{uevent}=="DEVTYPE=scsi_target"

  looking at parent device '/devices/platform/hiusb-ehci.0/usb1/1-1/1-1:1.0/host3':
    KERNELS=="host3"
    SUBSYSTEMS=="scsi"
    DRIVERS==""
    ATTRS{uevent}=="DEVTYPE=scsi_host"

  looking at parent device '/devices/platform/hiusb-ehci.0/usb1/1-1/1-1:1.0':
    KERNELS=="1-1:1.0"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb-storage"
    ATTRS{bInterfaceNumber}=="00"
    ATTRS{bAlternateSetting}==" 0"
    ATTRS{bNumEndpoints}=="02"
    ATTRS{bInterfaceClass}=="08"
    ATTRS{bInterfaceSubClass}=="06"
    ATTRS{bInterfaceProtocol}=="50"
    ATTRS{modalias}=="usb:v125FpC82Ad0100dc00dsc00dp00ic08isc06ip50"
    ATTRS{supports_autosuspend}=="1"

  looking at parent device '/devices/platform/hiusb-ehci.0/usb1/1-1':
    KERNELS=="1-1"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{dev}=="189:2"
    ATTRS{configuration}==""
    ATTRS{bNumInterfaces}==" 1"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bmAttributes}=="80"
    ATTRS{bMaxPower}=="480mA"
    ATTRS{urbnum}=="2092"
    ATTRS{idVendor}=="125f"
    ATTRS{idProduct}=="c82a"
    ATTRS{bcdDevice}=="0100"
    ATTRS{bDeviceClass}=="00"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bDeviceProtocol}=="00"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{speed}=="480"
    ATTRS{busnum}=="1"
    ATTRS{devnum}=="3"
    ATTRS{devpath}=="1"
    ATTRS{version}==" 2.00"
    ATTRS{maxchild}=="0"
    ATTRS{quirks}=="0x0"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{authorized}=="1"
    ATTRS{manufacturer}=="ADATA"
    ATTRS{product}=="ADATA USB Flash Drive"
    ATTRS{serial}=="0000000C082ACB"

  looking at parent device '/devices/platform/hiusb-ehci.0/usb1':
    KERNELS=="usb1"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{dev}=="189:0"
    ATTRS{configuration}==""
    ATTRS{bNumInterfaces}==" 1"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bmAttributes}=="e0"
    ATTRS{bMaxPower}=="  0mA"
    ATTRS{urbnum}=="38"
    ATTRS{idVendor}=="1d6b"
    ATTRS{idProduct}=="0002"
    ATTRS{bcdDevice}=="0300"
    ATTRS{bDeviceClass}=="09"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bDeviceProtocol}=="00"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{speed}=="480"
    ATTRS{busnum}=="1"
    ATTRS{devnum}=="1"
    ATTRS{devpath}=="0"
    ATTRS{version}==" 2.00"
    ATTRS{maxchild}=="2"
    ATTRS{quirks}=="0x0"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{authorized}=="1"
    ATTRS{manufacturer}=="Linux 3.0.8 ehci_hcd"
    ATTRS{product}=="HIUSB EHCI"
    ATTRS{serial}=="hiusb-ehci"
    ATTRS{authorized_default}=="1"

  looking at parent device '/devices/platform/hiusb-ehci.0':
    KERNELS=="hiusb-ehci.0"
    SUBSYSTEMS=="platform"
    DRIVERS=="hiusb-ehci"
    ATTRS{modalias}=="platform:hiusb-ehci"
    ATTRS{companion}==""

  looking at parent device '/devices/platform':
    KERNELS=="platform"
    SUBSYSTEMS==""
    DRIVERS==""
    ATTRS{uevent}==""

参考资料

  1. http://www.linuxsir.org/bbs/thread323186.html
  2. http://www.cnitblog.com/luofuchong/archive/2007/12/18/37831.html
  3. linux man udev;
  4. udev wiki
  5. 编写UDEV规则

 

无评论

MiniGUI核心库自动编译脚本

一 17 2013 由 创建在标签 开发

前一段时间整理了一下MiniGUI的编译,写了一个自动编译的脚本,把所有的环境变量都添加在脚本中,免去配置的痛苦,只需要更改相应的环境变量配置即可。

脚本如下:

#!/bin/sh
# Author : sgbihu.com
# Create date: 2013-01-17
# Function: compile the minigui lib
#
#

CURPATH=$PWD
# The complie path
MINIGUIROOTDIR=/home/linux/minigui

# Compile env
export CC=arm-linux-gcc
export CXX=arm-linux-g++
export LD=arm-linux-ld
export AS=arm-linux-as
export AR=arm-linux-ar
export CFLAGS="-I/usr/local/minigui/include"
export CPPFLAGS="-g -I/usr/local/minigui/include"
export CXXFLAGS="-g -I/usr/local/minigui/include"
export LIBS="-L/usr/local/minigui/lib"
export STRIP=arm-linux-strip

# The path you want to install
INSTALLPATH="/usr/local/minigui"
# The crosstool's include, Now only used by miniGUI Core lib.
CROSSCOMPILEINCLUDE="/opt/crosstool/arm-linux/gcc-3.4.4-glibc-2.3.5/arm-linux/arm-linux/include"
# The Compile devices
HOST=arm-linux
BUILD=i386-linux
TARGET=arm-linux

cd $MINIGUIROOTDIR

# Zlib
cd ./zlib-1.2.6
./configure --prefix=$INSTALLPATH --shared
make
make install
#PNG
cd ../libpng-1.5.8
./configure --prefix=$INSTALLPATH --includedir=$INSTALLPATH/include --build=$BUILD --host=$HOST --target=$TARGET

make
make install

#JEPG
cd ../jpeg-8c

./configure --prefix=$INSTALLPATH --build=$BUILD --host=$HOST --target=$TARGET --enable-shared
make
make install

# FREE TYPE
cd ../freetype-1.3.1

export ac_cv_sizeof_int=4
export ac_cv_sizeof_long=4
./configure --prefix=$INSTALLPATH --build=$BUILD --host=$HOST --target=$TARGET --enable-static

unset ac_cv_sizeof_int
unset ac_cv_sizeof_long
make
make install

# MiniGUI resource
cd ../minigui-res-be-3.0.12
./configure --prefix=$INSTALLPATH
make
make install

# MiniGUI Core Lib
cd ../libminigui-gpl-3.0.12
./configure --prefix=$INSTALLPATH --build=$BUILD --host=$HOST --target=$TARGET --with-osname=linux --with-style=classic \
            --with-targetname=fbcon --enable-autoial --enable-rbf16 --disable-vbfsupport --oldincludedir=$CROSSCOMPILEINCLUDE

make
make install

# Strip
$STRIP $INSTALLPATH/lib/*

在执行脚本中还是会遇到错误,需要改几个Makefile的生成模板。Makefile.in和Makefile.am。同时需要注释掉一些测试程序的编译。注意点如下:

freetype库:在Makefile.in中去掉“all:”后的变量“tttest”,注释掉“install:”下的第二行: $(FTTESTDIR); $(MAKE) –f$(MAKEFILE) install。

minigui核心库:所有目录下的Makefile.in和Makefile.am都有一个/usr/include的绝对路径,将这个路径替换成$(oldincludedir),执行这个脚本即可编译minigui的核心库。

最后编译一个例子程序,然后在你的开发板上运行吧!

无评论

3G modem在linux上的移植

三 31 2012 由 创建在标签 开发

3G模块调试

第三代移动通信技术(3rd-generation,3G),是指支持高速数据传输的蜂窝移动通讯技术。3G服务能够同时传送声音及数据信息,速率一般在几百kbps以上。目前3G存在四种标准:CDMA2000,WCDMA,TD-SCDMA,WiMAX。

1简介

现在市场上的3G模块大部分都是zero CD模式,只能识别成CD-ROM,在这个虚拟的光驱中提供驱动,但是大部分厂商只会提供Windows驱动,少部分厂商提供Linux驱动(大部分厂商都是通过自己的工具或者通过udev来转换modem的模式,而嵌入式系统一般使用mdev),没有厂商提供嵌入式Linux驱动,对于做嵌入式Linux的人来说就要自己动手了。因而不能识别成我们所需要的串口设备,这样就没有办法去享受移动网络所带来的便利,也就没有办法完成任务了。网上有很多方法来让设备变成串口设备,所以让3G modem上网的主要工作就是将存储设备转换成串口设备。
USB modem转换成串口设备的方法主要有以下几种方法。

1.1eject命令

就是讲CD-ROM弹出,这个命令需要设备的支持,网上有很多人用这种方法来做,但是有很大一部分人来做,如果你买的设备支持,那恭喜你,可以不用看后面的内容了。

1.2修改通用设备将对应的设备忽略

文件drivers/usb/storage/unusual_devs.h中可以通过宏忽略我们的设备为通用设备,我们通过lsusb或者在windows设备管理器中可以查到设备的vendorID和productID,在文件中添加如下代码即可。

UNUSUAL_DEV(  vendorID, productID, 0x0000, 0x0000,
                "AzureWave",
                "AzureWave CDROM USB Device",
                US_SC_DEVICE, US_PR_DEVICE, NULL,
                US_FL_IGNORE_DEVICE ),

我使用的设备在这样修改后可以识别成一个ttyUSB0,没有测试那个串口是否可以直接发送AT命令,但是为了保险起见,还是想办法将其识别成多个串口设备。很多网上的资料都说要识别成多个串口,我猜可能是单个串口会影响到网速(个人猜测,没有验证)。

1.3通过usb_modeswitch切换modem的运行模式

我在这个过程中走了很多弯路,主要花在这个抓usb传输消息的过程,然后测试不同的消息发到USB modem那边看是否有反应,能否识别成多个串口。反复测试无果,只能想其他办法。

抓包是通过usbsniffer工具在windows下做的,因为一般的设备都提供了windows的驱动,在windows下可以获得驱动是如何让设备转换zeroCD模式的,如果知道了驱动发送的消息,我们在linux下面通过工具发送同样的消息就可以使设备安装我们的意愿工作了。

然而事情往往没有我们想象中的那么单纯,有了抓包这一步,就需要去区分哪些有用消息哪些是无效的消息,而抓包的过程中会产生很多报文,通过sh脚本和windows下自己写的工具来将数据提取出来(代码写得太挫,只为了提取数据)。通过TTerm的脚本批量发送获取的消息。

本以为到此结束,谁曾想到这只是一个开始,大量的数据中没有找到我要数据,那个伤心呐~~一时之间陷入困境,开始看USB子系统相关的知识。

功夫不负有心人,结合厂商提供的udev规则,发现我们的设备是工作在第二配置下,而在识别设备的时候都是直接使用的配置一。只要有工具能够修改设备的配置就可以了,本打算自己动手写一个,后来看usb_modeswitch代码的时候发现它是可以完成这个工作的,本打算只用它来发消息的,没想到它还能修改配置模式,可谓是转了一圈又回到了原点。这样修改配置后,设备就可以识别成我们想的串口了,一下子转换成12个ttyUSB,真是幸福来得太快了,但是这样也不好,需要区分哪些是可以发送AT命令的串口,只要做些区分就可以安装我们的意愿来工作了,可以在proc文件系统中看USB设备各个接口的工作模式,找到对应的串口就可以直接发送AT命令了。

1.4通过工具在Windows下禁用设备的zero CD模式

这个方法就是通过工具对设备进行操作,让设备在识别的时候就只能识别出串口设备,具体的机制不太明白,有点像软改。那样插上设备就可以直接识别出串口设备了。

1.5通过SYS文件系统

这个方法是我在读USB子系统的内核源码发现的,就是通过SYS文件系统提供的方法来实现USB设备配置的更改,与USB_modeswitch工具的原理是一样的,只是一个通过工具来做,一个是通过内核提供的文件系统来做,原理是相通的。

1.6几种方法的比较

第四种方法简单,但是并不建议使用,所以我在捣腾的过程中直接忽略这种方法,毕竟一个产品如果量产,我们要去修改每一个3G modem,那样工作量就太大了。还是比较推荐使用usb_modeswitch工具来修改设备的配置,这样最稳定,也不会留下任何后遗症;第二种方法其实并不可取,因为我们只是不识别成串口了,其他接口同样没有被识别出来,我虽然没有尝试就用一个串口来进行拨号,但是那样设备并没有真正工作在modem模式,不能叫设备正常运行;如果能够拨号成功,也不能算错或者有问题,最糟糕的就应该是识别出来的不是AT命令对应的tty口,那就让人郁闷了,拨号的时候不能拨通。

有了第五种方法后,usb_modeswitch工具似乎就可以不用了,但是这个只适用于USB设备是采用的多个配置方式来实现设备的,如果像华为那样通过消息来改变设备的工作模式的话,此方法并不可取,必须通过工具来实现运行模式的切换。

2内核配置

Device Drivers  --->
  [*] USB support  --->
       USB Serial Converter support  --->
      [*]   USB Generic Serial Driver
         USB driver for GSM and CDMA modems
  [*] Network device support  --->
          PPP (point-to-point protocol) support
       [*]     PPP multilink support (EXPERIMENTAL)
       [*]     PPP filtering
            PPP support for async serial ports
            PPP support for sync tty ports
            PPP Deflate compression
            PPP over Ethernet (EXPERIMENTAL)

2.1修改option.c文件

让option能够支持我们的模块。

2.2安装模块

/ # insmod /lib/modules/2.6.28/usbserial.ko
/ # insmod /lib/modules/2.6.28/option.ko

3 USB工具

俗话说:“工欲善其事必先利其器”,有好的工具就能够带来很高的效率。下面是我在测试3G模块成功过程中所用到的工具。可以根据自己的需要选用恰当的工具。

3.1 usbsniffer

windows下的USB抓包工具,可以监听usb口的数据传输,分析USB数据包。有很多工具可以使用,需要的可以在网上搜一下。我用的是SniffUsb。

3.2 libusb

其实这只是一个usb库,它不提供任何功能,但是下面的三个工具都会使用到这个库,所以在USB modem的调试过程中起着至关重要的作用。我们也可以通过这个库来写适合自己的小工具,USB库已经把与内核通信的接口封装好了,使用起来比较方便。写自己工具的适合可以适当参考usb_modeswitch工具的源码,那个里面包含了自动识别设备及接口的代码,以及消息的发送方法,有较大的参考意义。

3.2.1 交叉编译

[root@localhost] CC=/opt/EmbedSky/4.3.3/bin/arm-linux-gcc \
			     CXX=/opt/EmbedSky/4.3.3/bin/arm-linux-g++\
			     ./configure --build=i686-linux \
                                    --host=arm-linux \
			     --target=arm-linux \
			     --prefix=/home/ driver/3g/libusb-0.1.12/_install
[root@localhost] make
[root@localhost] make install

3.3 usb_modeswitch

切换多重USB设备运行模式的转换工具。现在一些新的USB 设备(特别是一些高速 WAN 设备,很贵的那种)都有MS Windows的驱动程序,当第一次插入机子的时候,它们处于闪存模式,并从中提取和安装驱动。在驱动安装完毕之后,驱动马上转换模式,储存设备消失(基本上都是这样的),然后一个新的设备(比如一个USB modem)出现。

此工具在网上有现成的配置文件可以下载,如果你的设备包含在其中的话,那就恭喜你能够省略很多繁琐的步骤去做抓包工作了,也可以少走很多弯路。

3.3.1 交叉编译

[root@localhost] CC=arm-none-linux-gnueabi-gcc \
                 CXX=arm-none-linux-gnueabi-g++ \
                 LD=arm-none-linux-gnueabi-ld \
                 CFLAGS="-I/home/driver/3g/libusb-0.1.12/_install/include -I/opt/arm-none-linux-gnueabi-4.4.0_ARMv5TE/arm-none-linux-gnueabi/include " \
                 CPPFLAGS="-g -I/home/driver/3g/libusb-0.1.12/_install/include -I/opt/arm-none-linux-gnueabi-4.4.0_ARMv5TE/arm-none-linux-gnueabi/include " \
                 CXXFLAGS="-g -I/home/driver/3g/libusb-0.1.12/_install/include -I/opt/arm-none-linux-gnueabi-4.4.0_ARMv5TE/arm-none-linux-gnueabi/include " \
                   ./configure --prefix=/home/driver/3g/libusb-0.1.12/_install \
                   --host=arm-linux\
                   --target=arm-linux
[root@localhost] make
[root@localhost] make install

3.4 lsusb

lsusb是一个学习USB驱动开发,认识USB设备的助手,它用于查询usb设备的信息,它依赖于虚拟文件中proc系统,在使用时需要配置内核。

3.4.1 交叉编译

[root@localhost] CC=arm-none-linux-gnueabi-gcc \
                 CXX=arm-none-linux-gnueabi-g++ \
                 LD=arm-none-linux-gnueabi-ld \
                 CFLAGS="-I/home/ driver/3g/libusb-0.1.12/_install/include -I/opt/arm-none-linux-gnueabi-4.4.0_ARMv5TE/arm-none-linux-gnueabi/include " \
                 CPPFLAGS="-g -I/home /driver/3g/libusb-0.1.12/_install/include -I/opt/arm-none-linux-gnueabi-4.4.0_ARMv5TE/arm-none-linux-gnueabi/include " \
                 CXXFLAGS="-g -I/home/ driver/3g/libusb-0.1.12/_install/include -I/opt/arm-none-linux-gnueabi-4.4.0_ARMv5TE/arm-none-linux-gnueabi/include " \
                   ./configure --prefix=/home/ driver/3g/libusb-0.1.12/_install \
                   --host=arm-linux\
                   --target=arm-linux
[root@localhost] make
[root@localhost] make install

3.5 ppp

智能拨号工具,其他拨号工具也会依赖此工具,如wvdial。拨号使用到两个可执行程序pppd和chat,有了这两个工具只要借助脚本就可以是modem拨号上网了。

这个工具的交叉编译也不是很难,只要修改一下makefile,然后直接make就可以了。

3.6 wvdial

自动拨号工具,通过wvdialconf工具可以测试接口支持的速率并自动生成配置文件,只需要改少量的配置就可以拨号上网。

我也没有交叉编译过此工具,只是在pc上用它生成过配置文件,并验证能否上网,在嵌入式设备上并没有使用它,因为开发板上的资源太紧张了。

3.7 ppp和wvdial比较

上两种方式各有自己的优缺点,第一种方式智能稳定,他不需要chat程序,使用集成的wvdial工具包直接连接ISP,安全稳定,可以断线自动重拨。第二方式,使用chat程序,但是很多的参数需要自己去配置,虽然比较灵活,但是如果遇到了拨号错误以后,你若不清ppp协议拨号实现的具体机制和每个参数的含义,你就会很吃力,也许运气好的时候,你运行的环境正好和本地的移动isp配置吻合,恭喜你能上网了,但是你遗憾的是没有学到东西,想了解 ppp机制的朋友,可以试试第2种方式,在了解大体了解ppp协议的前提下,观察思考/var/log/messages中的信息。

3.8 其他

minicom是linux下一款比较方便的串口助手,类似于Windows下的超级终端,功能比较强大可以自己使用的时候尝尝鲜。

3.8.1 ncurses-5.5

minicom的依赖库。

[root@localhost]# mkdir install
[root@localhost]# ./configure --build=i686-linux --host=arm-linux --prefix=/home/minicom/ncurses-5.5/install
[root@localhost]# make&&make install

3.8.2 minicom-2.1

minicom工具的编译。

[root@localhost]# mkdir install
[root@localhost]# ./configure --build=i686-linux --host=arm-linux --prefix=/ home /minicom/minicom-2.1/install/ CPPFLAGS="-I / home /minicom/ncurses-5.5/install/include/ncurses" LDFLAGS="-L / home /minicom/ncurses-5.5/install/lib"

3.8.3 minicom使用

至此工具已经编译完成,剩下的工作就是拷贝到开发板上去运行我们交叉编译的程序,不要以为工作已经全部完成,还有一步需要我们去做。就是配置minicom运行的环境变量。

如果没有配置终端信息的话,运行时会提示错误,需要将lib目录下的tesrminfo的v文件夹中的终端信息拷贝到文件系统中,并导出环境变量,这样在开发板上才能正确运行。

cp -r /lib/terminfo/v $rootfs/usr/share/terminfo
export TERMINFO=/usr/share/terminfo

4 热插拔脚本

开始尝试直接在hotplug文件中直接执行usb_modeswitch程序,但是在添加USB设备的阶段还是早了一点,于是就在mdev.conf文件中添加执行脚本。但是下面这段代码可以用来动态添加和删除模块。

SUBACTION="$SUBSYSTEM.$ACTION"
if [ "$SUBACTION" = "usb-serial.add" ] ; then
    SUBINFO=${PRODUCT:0:8}
    echo $SUBINFO>>/var/test
    if [ "$SUBINFO" = "4cc/231f" ] ; then
      /bin/usb_modeswitch -v 0x04cc -p 0x231f -u 2
      echo "testtttt">>/var/test
    fi
fi

5 拨号

设备识别出来后,下一步要做的工作就是拨号上网,其中内核中关于PPP的配置一定要配置上,否则拨号会失败。

5.1 运营商设置

不同的运营商会使用不同的拨号参数,虽然设备是一个,但是需要根据运营商来设置我们拨号相关的参数。而拨号的脚本基本相同,但是不同设备间可能会有少许差异,不同的设备可以根据实际来作简单调整。

5.1.1 电信3G设置

Dail number : #777
User name : card
Password : card

5.1.2 中国联通3G设置

APN:3gnet
Access number:*99#  (拨号号蚂)
User name: uninet
Password:空

5.1.3 中国移动 3G 设置

APN: cmnet
Access number 拨号号码: *99***1#
User name (账号) :空
Password (密码)  : 空

5.2 自动拨号

pppd connect 'chat  -v -s -r "/var/report" -f "/etc/ppp/ppp-on-dialer"' /dev/ttyUSB0 115200 mru 1280 mtu 1280 nodetach debug dump defaultroute usepeerdns novj novjccomp noipdefault ipcp-accept-remote connect-delay 5000 linkname ppp0
ABORT   BUSY
ABORT   'NO CARRIER'
ABORT   ERROR
REPORT  CONNECT
TIMEOUT 10
""      "AT&F"
OK      "ATE1"
OK      'AT+CGDCONT=1,"IP","3gnet"'
SAY     "Calling UMTS/GPRS"
TIMEOUT 30
OK      "ATD*99#"
CONNECT ' '

6 UI需求

拨号号码

apn
username
password

7 总结

还没有完全整理完毕,后续会继续补充。

附录:

1. usb_modeswitch网站(http://www.draisberghof.de/usb_modeswitch);
2. SniffUSB(http://www.pcausa.com/Utilities/UsbSnoop/default.htm);
3.

一条评论

ath9k_htc使用compatwireless在嵌入式linux上的使用

三 02 2012 由 创建在标签 开发

最近忙一个项目的无线模块,使用的是ath9k_htc这个wifi模块,由于官方没有提供驱动源码,只能使用无线兼容包。其实所有的驱动在高版本的内核中都已经包含,如果开发环境允许,可以使用高版本的内核,也许就不会遇到那么多的问题了。下面就言归正传,说说我是如何在2.6.28的内核上移植无线驱动的。

开发环境

内核版本:2.6.28

交叉编译器:gcc version 4.4.0 (Faraday C/C++ Compiler Release 20100325)

compatwireless:2.6(日期是2012-02-15)

firmware:1.3

wireless-tool:29

iw(配置ap模式,并没有实际测试)

配置内核

[*] Networking support  --->
    [*]   Wireless  --->
        [*]   Wireless extensions
        [*]     Wireless extensions sysfs files

-*- Cryptographic API  --->
    {M}   Cryptographic algorithm manager
       ARC4 cipher algorithm

配置内核使内核支持无线,由于802.11需要用到一些加密算法,所以需要把加密模块编译成模块,由于开始没有考虑加密,所以无线在连接的时候总是连不上,最终不得不在代码中寻找问题,后面我也会详细来说。

编译compatwireless

# 配置驱动类型
./scripts/driver-select ath9k_htc
# 编译驱动
make KLIB=//linux-2.6.28 KLIB_BUILD=/linux-2.6.28

这使ath9k_htc驱动的主体部分,它需要读取内核配置文件.conf,然后根据内核的配置来决定编译哪些模块。编译的时候会遇到很多问题,都可以根据它的提示来解决。主要是trace.h包含的一些调试函数,基本上所有的错误都是由于这个头文件里的函数造成的。我的处理办法就是把他们全部注释掉,但是这样就不能跟踪代码了。其实我们使用这个驱动也没有必要来跟踪代码,毕竟我们对802.11协议还不是十分了解,让我们这些外行跟踪内部的东西那就不敢想象其中的工作量了。

编写驱动加载脚本

# 兼容包及802.11驱动
insmod /lib/modules/2.6.28/compat.ko
insmod /lib/modules/2.6.28/compat_firmware_class.ko
insmod /lib/modules/2.6.28/rfkill_backport.ko
insmod /lib/modules/2.6.28/cfg80211.ko
insmod /lib/modules/2.6.28/mac80211.ko
# ath9k_htc驱动
insmod /lib/modules/2.6.28/ath.ko
insmod /lib/modules/2.6.28/ath9k_hw.ko
insmod /lib/modules/2.6.28/ath9k_common.ko
insmod /lib/modules/2.6.28/ath9k.ko
insmod /lib/modules/2.6.28/ath9k_htc.ko
# 加密模块
insmod /lib/modules/2.6.28/crypto_algapi.ko
insmod /lib/modules/2.6.28/arc4.ko

驱动编译完成后,先手动加载,发现驱动的加载有先后顺序,而且每次开机启动都要手动加载,那是相当的麻烦,所以就写了一个加载wifi驱动的脚本,开机后自动运行就可以了。主要是保证他们的加载先后顺序。

热插拔自动启动设备

#!/bin/sh

#do something that mdev has to do
/sbin/mdev $1

EVENT="$SUBSYSTEM.$INTERFACE.$ACTION";

if [ "$EVENT" = "net.wlan0.add" ] ; then
    iwconfig wlan0 essid "ap01"
    iwconfig wlan0 key 11111111111111111111111111
    echo "The wlan0 is created!">> /var/log
    ifconfig wlan0 up
# mdev 貌似不能发出linkup的热插拔时间,对此不太了解,所以在启动后就直接配置
#elif [ "$EVENT" = "net.wlan0.linkup" ] ; then
    ifconfig wlan0 192.168.88.188 netmask 255.255.255.0
    route add default gw 192.168.88.254
    echo "The wlan0 is up!">> /var/log
fi

可能显得没有很大的必要,因为设备一旦启动了,一般不会无缘无故把wifi设备拔掉,只要开机启动的时候做好就可以了,但是有了热插拔还有另一个好处,那就是自动配置设备,并启动设备。上面的配置也很简单,就是检测到无线wlan0插入后自动启动无线并配置ip地址,也可以根据实际应用开启相关的网络应用程序,保证对网络相关的程序能够正常执行。

遇到的问题及解决方案

wep不能认证

开始觉得很奇怪,为什么设备已经被识别了,而且能够正常工作,为什么加密后就不能连接ap,而是用open方式可以连接上ap。所就觉得不是驱动的问题,因为驱动有问题的话open方式的ap也就连接不上了,所以应该是加密或者配置的部分有问题。开始就在看compatwireless和wireless-tool的代码,代码实在是太庞大,想发现问题也没有那么容易,而且也没发现配置有问题,密码应该是配置下去了。

只有自己加一点调试信息,然后根据调试信息来定位,后来发现代码根本就没有走到认证的地方,无奈只能从驱动的初始化和wep加密相关的地方入手,就在初始化的过程中加了一些调试信息。同时修改内核,在内核配置的时候发现配置了内核中802.11协议栈的时候,发现协议栈对加密模块有依赖,而我在运行驱动的时候并没有加载加密的驱动,后来又跟踪到如下代码,发现用到了arc4算法,遂配置内核的加密模块,编译加载之,发现错误的调试信息就没有打印出来,同时也能上线了~~

int ieee80211_wep_init (struct ieee80211_local *local)
{
    /* start WEP IV from a random value */
    get_random_bytes (&local->wep_iv, WEP_IV_LEN);
    // 加载arc4加密模块
    local->wep_tx_tfm = crypto_alloc_cipher ("arc4", 0, CRYPTO_ALG_ASYNC);
    if (IS_ERR (local->wep_tx_tfm))
    {
        local->wep_rx_tfm = ERR_PTR (-EINVAL);
        return PTR_ERR (local->wep_tx_tfm);
    }

    local->wep_rx_tfm = crypto_alloc_cipher ("arc4", 0, CRYPTO_ALG_ASYNC);
    if (IS_ERR (local->wep_rx_tfm))
    {
        crypto_free_cipher (local->wep_tx_tfm);
        local->wep_tx_tfm = ERR_PTR (-EINVAL);
        return PTR_ERR (local->wep_rx_tfm);
    }

    return 0;
}

其实很难让人怀疑到是那个地方的错误,因为一般如果说某个函数不存在,在运行的时候会报错,而这个通过了一个接口封装,将算法的提取放到封装的函数接口中去了,而且这个接口特别友好,不会让你的程序在运行运行出错,只会告诉你一个简单的错误码。所以觉得有的时候太友好了导致的错误更让人头疼。

热插拔脚本不能执行

在/sbin目录下创建一个文件名为hotplug的shell脚本,在里面添加echo语句,但是前台没有打印,就直接判断不能执行热插拔的脚本。但是反复测试后发现即使用mdev来做也不会打印信息(有师兄说有时候会打印出echo输出的信息),但是其实它是在后台执行了的,只是没有表现出来而已。可以把打印出来的消息输入文件,然后在文件中查看,这样就可以确定是否真正运行了。

注意:需要注意的是hotplug可执行的脚本在第一行一定要加上:#!/bin/sh,否则不能执行。

ath9k_htc找不到firmware

这个问题我也不能完全确定,但是在两种情况下是不会发生的。第一:将mdev指定为/proc/sys/kernel/hotplug的执行程序;第二:在/sbin目录下添加上面写道hotplug脚本,而且需要添加:/sbin/mdev $1,如果不加也会出现错误。

所以就猜测是由于/sbin目录下不存在hotplug可执行程序且没有为其指定,但是至于为什么,现在还没有了解清楚。可能是插入USB wifi后需要处理一系列的热插拔事件,每个处理完了才能进入下一步。

iwconfig配置AP模式master时出错

用iwconfig配置模式的时候会出现配置错误,因为有了前面出错的经验,就直接在源码中寻找问题的所在。最终在函数cfg80211_wext_siwmode中找到问题所在,从代码中可以看出,当遇到配置为master时就会返回错误,然后就会提示配置错误。

int cfg80211_wext_siwmode(struct net_device *dev,
                          struct iw_request_info *info,
			  u32 *mode,
                          char *extra)
{
	struct wireless_dev *wdev = dev->ieee80211_ptr;
	struct cfg80211_registered_device *rdev;
	struct vif_params vifparams;
	enum nl80211_iftype type;
	int ret;

	rdev = wiphy_to_dev(wdev->wiphy);

	switch (*mode) {
	case IW_MODE_INFRA:
		type = NL80211_IFTYPE_STATION;
		break;
	case IW_MODE_ADHOC:
		type = NL80211_IFTYPE_ADHOC;
		break;
	case IW_MODE_REPEAT:
		type = NL80211_IFTYPE_WDS;
		break;
	case IW_MODE_MONITOR:
		type = NL80211_IFTYPE_MONITOR;
		break;
	default:
		return -EINVAL;
	}

	if (type == wdev->iftype)
		return 0;

	memset(&vifparams, 0, sizeof(vifparams));

	cfg80211_lock_rdev(rdev);
	ret = cfg80211_change_iface(rdev, dev, type, NULL, &vifparams);
	cfg80211_unlock_rdev(rdev);

	return ret;
}

所以iwconfig不能配置,搜索后发现需使用其他工具iw。只找了一下,由于项目中不需要这个功能,且进度比较紧,所以就直接没有测试它是否真的有效。想配置的可以去尝试一下。

附录:

1、firmware下载链接;

2、ATH9k_htc驱动主页

3、无配置线工具(wireless-tool);

4、新的无线配置工具(iw);

 

10 条评论

miniGUI3.0在mini6410上的移植

二 12 2012 由 创建在标签 开发

简介

MiniGUI 是一款面向嵌入式系统的高级窗口系统(Windowing System)和图形用户界面(Graphical User Interface,GUI)支持系统,由魏永明先生于 1998 年底开始开发。2002 年,魏永明先生创建北京飞漫软件技术有限公司,为 MiniGUI 提供商业技术支持,同时也继续提供开源版本,飞漫软件是中国地区为开源社区贡献代码最多的软件企业。最后一个采用 GPL 授权的 MiniGUI 版本是 1.6.10,从 MiniGUI 2.0.4 开始 MiniGUI 被重写并使用商业授权,从3.0.12开始,部分版本使用GPL授权。历经十余年时间, MiniGUI 已经成为性能优良、功能丰富的跨操作系统嵌入式图形用户界面支持系统,支持Linux/uClinux、eCos、 uC/OS-II、 VxWorks、ThreadX、Nucleus 、pSOS、OSE 等操作系统和数十种 SoC芯片,已验证的硬件平台包括 ARM-based SoCs、MIPS based SoCs、IA-based SoCs、PowerPC、M68K(DragonBall /ColdFire)、Intel x86 等等。

准备工作

交叉编译器

友善提供,具体安装参考mini6410的使用手册;

源码的下载

miniGUI官网上下载,需要有新浪账号或者twitter账号。下面是我下载的版本。

[root@localhost minigui]# ls -l *.tar.gz
-rwxrw-rw-. 1 root root 1427072 Jan 16 17:30 freetype-1_3_1.tar.gz
-rw-rw-r--. 1 root root   63582 Jan 16 17:31 gvfb-1_0_0.tar.gz
-rw-rw-r--. 1 root root  602762 Jan 16 17:32 qvfb2-2_0.tar.gz  
-rwxrw-rw-. 1 root root  557220 Feb 11 00:56 zlib-1.2.6.tar.gz
-rwxrw-rw-. 1 root root 1059513 Feb 11 00:55 libpng-1.5.8.tar.gz
-rwxrw-rw-. 1 root root  986681 Feb 10 23:42 jpegsrc.v8c.tar.gz
-rw-rw-r--. 1 root root  340656 Jan 16 17:33 libmg3d-1_0_2.tar.gz
-rw-rw-r--. 1 root root 1545209 Jan 16 17:34 libmgi-2_0_4.tar.gz
-rw-rw-r--. 1 root root 1116885 Jan 16 17:33 libmgp-1_2_2.tar.gz
-rw-rw-r--. 1 root root  648207 Jan 16 17:34 libmgplus-1_2_4.tar.gz
-rw-rw-r--. 1 root root  659702 Jan 16 17:33 libmgutils-1_0_4.tar.gz
-rw-rw-r--. 1 root root 3202804 Jan 17 00:29 libminigui-gpl-3_0_12.tar.gz
-rw-rw-r--. 1 root root 2608473 Jan 16 17:29 mg-samples-3_0_12.tar.gz
-rw-rw-r--. 1 root root 3449215 Jan 16 17:29 minigui-res-be-3_0_12.tar.gz

官网上有几个库的版本太低,所以需要自己去网上下载,其中jpegsrc.v8c.tar.gzlibpng-1.5.8.tar.gzzlib-1.2.6.tar.gz都是从网上找的最近版本(png和zlib这两个soucefoge上都有,前面一个是网上搜的,所以不能保证链接长期有效,但是网上搜一下还是比较容易找到的)。其实我也是在运行例子程序的时候才发现问题的,库更新后就可以正常运行了。

简单介绍一下使用到的几个库。

freetype:FreeType库是一个完全免费(开源)的、高质量的且可移植的字体引擎,它提供统一的接口来访问多种字体格式文件,包括TrueType, OpenType, Type1, CID, CFF, Windows FON/FNT, X11 PCF等。支持单色位图、反走样位图的渲染。FreeType库是高度模块化的程序库,虽然它是使用ANSI C开发,但是采用面向对象的思想,因此,FreeType的用户可以灵活地对它进行裁剪。

gvfb与qvfb2:这两个主要用于pc上仿真,在嵌入式平台上没用,就不做说明。

zlib:zlib是提供数据压缩用的函式库,由Jean-loup Gailly与Mark Adler所开发,初版0.9版在1995年5月1日发表。zlib使用DEFLATE算法,最初是为libpng函式库所写的,后来普遍为许多软件所使用。

libpng:这个是用来显示png图形的,MiniGUI里很多图都是png的,如果没有这个库,MiniGUI将无法正常工作。

jpeg:用于显示jpeg图像,否则程序不能正常运行。

minigui-res:minigui3.0工具栏所使用的资源集合,包括字体、图标、位图等。

libminigui:minigui3.0的核心库。

mg-samples:minigui3.0的例子程序,有一两个小游戏,可以玩玩~~

minigui可选组件:libmg3d(3D支持)、libmgi(提供输入接口)、libmgp(提供打印机接口的支持)、libmgplus(2D矢量图支持和图像加速)、libmgutils(提供一些常用对话框的模板),可以根据自己的需要使用,在跑例子程序的时候使用到了libmgplus,所以就临时编了它的lib。

交叉编译图像库

先将代码解压到你所放置代码的位置,然后再进行如下步骤来编译安装图像库。我的安装目录是:/usr/local/minigui,可以根据自己的习惯和喜好安装在其他目录,通过prefix参数来配置安装目录。

编译zlib库

编译与配置脚本:

[root@localhost] CC=arm-linux-gcc \
                 CXX=arm-linux-g++ \
                 LD=arm-linux-ld \
                 AS=arm-linux-as \
                 AR=arm-linux-ar \
                 ./configure --prefix=/usr/local/minigui \
                   --shared
#配置完成后
[root@localhost] make
[root@localhost] make install

 编译png库

[root@localhost] CC=arm-linux-gcc \
                 CXX=arm-linux-g++ \
                 LD=arm-linux-ld \
                 AS=arm-linux-as \
                 AR=arm-linux-ar \
                ./configure --prefix=/usr/local/minigui \
                    --build=i386-linux \
                    --host=arm-linux \
                    --target=arm-linux
[root@localhost] make
[root@localhost] make install

编译Jpeg库

[root@localhost] CC=arm-linux-gcc \
                 CXX=arm-linux-g++ \
                 LD=arm-linux-ld \
                 AS=arm-linux-as \
                 AR=arm-linux-ar \
                 ./configure --prefix=/usr/local/minigui \
                   --build=i386-linux \
                   --host=arm-linux \
                   --target=arm-linux \
                   --enable-shared
[root@localhost] make
[root@localhost] make install

 编译freetype库

自动配置还有问题,也没有尝试高版本的freetype能不能使用,暂时就先这样,好像例子代码里面并没有使用它。后面再尝试高版本的freetype。

[root@localhost] cd freetype-1.3.1/
[root@localhost] ./configure --host=arm-linux --enable-static --prefix=/usr/local/minigui
[root@localhost] vim config.cache
# 修改如下行
ac_cv_path_LD=${ac_cv_path_LD=arm-linux-gnu-ld}
ac_cv_prog_CC=${ac_cv_prog_CC=arm-linux-gnu-gcc}
ac_cv_prog_CPP=${ac_cv_prog_CPP='arm-linux-gnu-gcc -E'}
#重新配置
[root@localhost] ./configure --host=arm-linux --enable-static --prefix=/usr/local/minigui
# 修改Makefile文件,以跳过编译test目录。
# 去掉“all:”后的变量“tttest”
# 注释掉“install:”下的第二行:“cd $(FTTESTDIR); $(MAKE) –f$(MAKEFILE) install”
[root@localhost] make
[root@localhost] make install

安装minigui资源库

[root@localhost] CC=arm-linux-gcc \
                 CXX=arm-linux-g++ \
                 LD=arm-linux-ld \
                 AS=arm-linux-as \
                 AR=arm-linux-ar \
                  ./configure --prefix=/usr/local/minigui
[root@localhost] make
[root@localhost] make install

编译minigui核心库

配置脚本:

[root@localhost] CC=arm-linux-gcc \
                 CXX=arm-linux-g++ \
                 LD=arm-linux-ld \
                 CFLAGS="-I/usr/local/minigui/include -I/opt/arm/toolschain/4.5.1/arm-none-linux-gnueabi/include " \
                 CPPFLAGS="-g -I/usr/local/minigui/include -I/opt/arm/toolschain/4.5.1/arm-none-linux-gnueabi/include " \
                 CXXFLAGS="-g -I/usr/local/minigui/include -I/opt/arm/toolschain/4.5.1/arm-none-linux-gnueabi/include " \
                   ./configure --prefix=/usr/local/minigui \
                   --host=arm-linux \
                   --target=arm-linux \
                   --build=i386-linux \
                   --with-osname=linux \
                   --with-style=classic \
                   --with-targetname=fbcon \
                   --enable-autoial \
                   --enable-rbf16 \
                   --disable-vbfsupport
[root@localhost] make
[root@localhost] make install

遇到错误:pcxvfb.c:490:13: error: impossible constraint in ‘asm’,因为使用了错误的头文件,解决方法如下:

 mv select.h select.h.bak
 cp /opt/arm/toolschain/4.5.1/arm-none-linux-gnueabi/include/bits/select.h ./
 rm select.h
 mv select.h.bak select.h

编译minigui例子程序

例子程序也不是一帆风顺的,从配置到最后编译都会有问题。具体配置脚本如下:

[root@localhost] CC=arm-linux-gcc \
                 CXX=arm-linux-g++ \
                 LD=arm-linux-ld \
                 CFLAGS="-I/usr/local/minigui/include -I/opt/arm/toolschain/4.5.1/arm-none-linux-gnueabi/include " \
                 CPPFLAGS="-g -I/usr/local/minigui/include -I/opt/arm/toolschain/4.5.1/arm-none-linux-gnueabi/include " \
                 CXXFLAGS="-g -I/usr/local/minigui/include -I/opt/arm/toolschain/4.5.1/arm-none-linux-gnueabi/include " \
                 ./configure --prefix=/usr/local/minigui \
                    --build=i386-linux \
                    --host=arm-linux \
                    --target=arm-linux

在配置阶段或遇到环境变量的问题,但是在配置了环境变量后还是出现错误,就直接在configure文件中添加了变量,这样才通过配置。修改如下:

vim configure
# 在 $as_echo_n "checking for MINIGUI... " >&6; }后添加如下变量:
MINIGUI_CFLAGS = /usr/local/minigui/include
MINIGUI_LIBS = /usr/local/minigui/lib

然后开始make,又出现如下错误:no such file: File format not recognized collect2: ld returned 1 exit status。经过网上查资料后发现是生成的Makefile有问题,需要逐个修改Makefile。修改每个Makefile钟的如下行:

 LIBS = -lminigui_ths -ljpeg -lm -lpthread -ldl
 LDFLAGS = -L/usr/local/minigui/lib

这样就可以通过编译并生成可执行文件了。

部署图像库

其实这个工作很简单,主要有两个步骤,一个修改minigui的配置文件,另一个是拷贝库文件到文件系统就可以了。配置文件在minigui的wiki上也有较详细的介绍,可以参考:《MiniGUI V3.0 的运行

修改配置文件:

$ vim /usr/local/minigui/etc/MiniGUI.cfg
# 修改如下参数
# GAL engine and default options
gal_engine=fbcon

# IAL engine
ial_engine=console
mdev=/dev/input/mice
mtype=IMPS2

# 根据实际的显示大小填
[fbcon]
defaultmode=480x272-16bpp

拷贝库到文件系统:

$ cp /usr/local/minigui/* /myrootfs/usr/local

拷贝你的例子程序就可以在开发板上运行了~~

参考文档和链接

  1. minigui的wiki
  2. MiniGUI-1.6.10 MiniGUI-1.6.10在mini2440上的移植(网络文档)
  3. miniGUI官网

6 条评论

支持6410从SD卡启动的Uboot

一 16 2012 由 创建在标签 开发

友善提供的Superboot确实很好用,但是samsung提供的uboot版本比较低,从友善的官网也看到对应的uboot介绍,了解到它启动的时候并不能很好地支持SD卡,尤其是SDHC的支持很不好,那个是因为uboot版本太低,而且SD卡也不能超过2G。最让人头疼的是不能从SD卡直接启动系统,只能将img拷贝到NAND,然后再从NAND中启动(参考友善官网6410的bootloader介绍)。对于想定制自己的Bootloader人就会遇到想不到的麻烦,所以就想着找一个能够很好支持SD卡启动Linux的Uboot。

SD/MMC的启动原理

要想知道启动的原理,就必须先了解芯片的特性和它的启动过程,需要查看厂商提供的Datasheet和芯片相关的资料。对于6410,samsung提供了一份启动相关的文档——《SMDK6410_IROM_APPLICATION NOTE_REV 1.00》,想了解的人可以自己在网上搜一下,我只简单说一下我看了之后对我比较有用的东西,肯定会有信息遗漏。

6410最开始启动的时候先执行固化在芯片里面的代码,iRom(BL0)它所做的事情很简单,主要完成系统时钟、堆栈、设备控制器和启动设备标识的初始化,确定下一阶段(BL1)的启动设备和起始地址,拷贝BL1到启动区域,然后将执行权交给启动区域,开始BL1的执行。其中iRom初始化了很多函数指针和全局变量,这些都为BL1阶段的执行和代码的拷贝做好准备;6410通过从引脚来判断是从Nand还是从SD卡拷贝数据的,在6410中就有一个开关来选择是从NAND还是从SD卡启动的。BL1就已经是Bootloader的代码了,但是BL1的大小是有8k的限制,不能完成所有的Bootloader的工作,还需要BL2的配合才能真正完成所有的引导过程。

Uboot的移植

其实写到这里就已经没有多少我的东西了,因为自己并没有真正去移植,所以后面说的有点人云亦云,我只是从网上下了一份tekkamanninja移植好的代码(亲自测试,可以运行,运行时有启动背景),自己做了一些比较,说说他的这份代码是如何移植的,而且作者的博客上也有很多关于Uboot移植的代码和一些关于这方面原理的分析。如果有机会自己移植的话再写一些关于Uboot移植的东西。

/u-boot-2011.06mini6410/arch/arm/include/asm/arch-s3c64xx
# ls -l
total 80
-rw-rw-r--. 1 root root 1995 Sep  7 07:30 hardware.h
-rw-rw-r--. 1 root root 2066 Sep  7 07:30 mmc.h
-rw-rw-r--. 1 root root 13667 Sep  7 07:30 regs-fb.h
-rw-rw-r--. 1 root root 5470 Sep  7 07:30 regs-fb-v4.h
-rw-rw-r--. 1 root root 36503 Sep  7 07:30 s3c6400.h
-rw-rw-r--. 1 root root 9205 Sep  7 07:30 s3c64x0.h

上面列出了初始化时需要调用的一些公共函数、结构体、宏等相关的声明,主要增加了SD卡和mini6410的LCD支持,完成他们的初始化,使得开机时能够显示Logo、背景以及SD卡启动系统。

/u-boot-2011.06mini6410/arch/arm/cpu/arm1176
# ls -l
total 56
-rw-rw-r--. 1 root root 1319 Sep  7 07:30 config.mk
-rw-rw-r--. 1 root root 1717 Sep  7 07:30 cpu.c
-rw-rw-r--. 1 root root 1496 Sep  7 07:30 Makefile
drwxrwxr-x. 2 root root 4096 Jan 14 00:26 s3c64xx
-rw-rw-r--. 1 root root 15078 Sep  7 07:30 start.S
-rw-rw-r--. 1 root root 1712 Sep  7 07:30 u-boot.lds
# cd s3c64xx/
# ls -l
total 76
-rw-rw-r--. 1 root root 1319 Sep  7 07:30 config.mk
-rw-rw-r--. 1 root root 5424 Sep  7 07:30 cpu_init.S
-rw-rw-r--. 1 root root 1459 Sep  7 07:30 Makefile
-rw-rw-r--. 1 root root 1109 Sep  7 07:30 reset.S
-rw-rw-r--. 1 root root 3441 Sep  7 07:30 speed.c
-rw-rw-r--. 1 root root 4363 Sep  7 07:30 timer.c

上面列出了与芯片有关的初始化代码,作者修改了cpu_init.S和start.S,其中cpu_init.S主要是自动检测内存大小的代码(参考Mini6410自动识别内存大小);star.S主要是增加启动时自动检测内存、确定是从SD卡还是从NAND启动以及LED功能。

/u-boot-2011.06mini6410/arch/arm/lib
# ls -l
-rw-rw-r--. 1 root root 17540 Sep  7 07:30 board.c

上面列出了lib中修改了的文件,它的修改主要是为了添加LED功能。

/u-boot-2011.06mini6410/drivers/mmc
# ls -l
-rw-rw-r--. 1 root root 24139 Sep  7 07:30 mmc.c
-rw-rw-r--. 1 root root 11091 Sep  7 07:30 s3c64x0_mmc.c

上面新增了s3c64x0_mmc.c文件,它主要完成6410 SD卡的初始化;mmc.c主要添加了一些打印信息。

/u-boot-2011.06mini6410/drivers/video
# ls -l
total 552
-rw-rw-r--. 1 root     root     49102 Sep  7 07:30 cfb_console.c
-rw-rw-r--. 1 root     root      9151 Jan 14 00:14 s3c64x0_fb.c
-rw-rw-r--. 1 root     root      8945 Sep  7 07:30 videomodes.c
-rw-rw-r--. 1 root     root      3480 Sep  7 07:30 videomodes.h

上面主要增加了对LCD的支持,支持开机时使用友善的上自带的LCD,可以显示开机Logo和背景。

/u-boot-2011.06mini6410/mmc_spl/board/samsung/mini6410
# ls -l
lrwxrwxrwx. 1 root     root       86 Jan  5 22:58 cpu_init.S
lrwxrwxrwx. 1 root     root       85 Jan  5 22:58 lowlevel_init.S
-rw-rw-r--. 1 root     root     2417 Sep  7 07:30 mmc_boot.c
lrwxrwxrwx. 1 root     root       75 Jan  5 22:58 start.S
-rw-rw-r--. 1 root     root     1725 Sep  7 07:30 u-boot.lds

上面这个目录为新增目录,它们就是针对mini6410启动初始化的过程,其实cpu_init.S等汇编代码其实只是上面体系结构目录下的符号链接,它们将烧写在BL1中,作为iRom执行后第一个执行的部分,主要就是完成初始化,并调用mmc_boot.c中的初始化函数,其中copy_uboot_to_ram函数从BL2中拷贝代码到内存,并跳转到对应的区域执行,从而进入BL2的代码段执行。

其他修改过的文件都只是一些配置相关的,因为作者增加了很多新的功能,所以在编译的时候还需要让其他部分也编译进去。

烧写Uboot

在Linux中可以通过命令和网友Amankwah提供的工具(下载地址)。但是在使用的时候要获得root权限,我在Fedora下面也是可以正常工作的。但是在使用的时候注意将BL1的目录选择mmc_spl目录下,否则默认的是NAND那个目录下。烧写的命令如下:

$ sudo fdisk /dev/sdb

Command (m for help): p
Disk /dev/sdb: 7969 MB, 7969177600 bytes
246 heads, 62 sectors/track, 1020 cylinders
Units = cylinders of 15252 * 512 = 7809024 bytes
Disk identifier: 0x00000000

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1   *           1           6       45755+   b  W95 FAT32
/dev/sdb2   *           7        1020     7732764   83  Linux

##################################################################
# 所以总块数是7969177600/512=15564800
# IROM所认为的总块数15563776(15564800-1024)(仅在SDHC时需要减去1024)
# 所以nand_spl/u-boot-spl-16k.bin烧写的位置是15563758块(15563776-18)
# u-boot.bin烧写的位置是15557632块(15563776-6144(3MB))(根据我的Uboot配置文件)
###################################################################
# 烧写命令:
sudo dd if='(Uboot源码)/nand_spl/u-boot-spl-16k.bin'     of=/dev/(SD卡的设备节点) bs=512   seek=15563758
sudo dd if='/(Uboot源码)/u-boot.bin'      of=/dev/(SD卡的设备节点) bs=512   seek=15557632

其实觉得友善的Superboot和这个应该差不多,友善的烧写工具应该也是将他们分成两步来做的,因为我用这个版本的Uboot编译后用友善的烧写工具烧写发现打开的文件格式错误,再加上看了6410的启动过程,所以感觉友善的编译出来的Uboot和Superboot应该是将两个打包成一个了,然后在烧写时再做区分,分别写到对应的区域中去。

现在我已经用网友提供的 Uboot引导成功,能够正常进入了,也设置了开机画面和背景。其实这篇文章主要是参考的别人的博客,自己只是把别人的博客和代码拿过来整理了一下,希望能够对6410学习的人和想移植Uboot的人有所帮助。

参考网站

Tekkaman Ninja的博客

一条评论

Mini6410启动过程(二)

一 13 2012 由 创建在标签 开发

前一段时间写过Mini6410的启动过程,但是那个只写出了它启动的后半部分,因为自己那个时候还没有彻底了解清楚友善的启动机制和过程,所以只写了后一部分。这段时间在尝试使用uBoot来替代友善的Superboot,让板子支持从SD卡启动,所以就仔细研究了一下友善提供的内核和它的启动参数,发现友善真的蛮聪明,把电脑的启动方式借鉴到它们自己的开发板上了。现在就把6410启动的过程分享出来,可能还有不完善的地方,希望了解的人也能指出我文章里面的不足。

initramfs启动

以前在X86平台上做过一个最小的U盘启动小系统,用的就是initramfs的方式,只是在最后阶段不要让它切换根目录。对于initramfs的启动方式网上有很多相关的文章,Linux内核的文档也有相应的介绍。这里只简单说一下它的原理,initramfs将归档好的文件系统添加到img中,在启动的时候就只需要指定少量的内核启动参数,在启动过程中的临时文件系统所运行的脚本都是此文件系统中的程序和脚本,当然,这个文件系统其实就是一个简单的linux系统,可以进行简单的操作,如果要扩展功能又不想把img做得很大,可以考虑用mount文件系统然后转换的方式来做。

这样就将启动过程分成两个阶段,第一阶段就是用编入内核的文件系统做初始化,然后用定制的文件系统来跑应用程序。不仅减少了更新内核的负担,而且在更新的时候不需要更新应用程序的文件系统,文件系统和内核的更新可以分开来做,提高了效率。

init脚本

Linux启动后执行的第一个程序就根目录下的ini,友善通过init脚本来完成启动过程。其主要工作就是声明一些环境,加载要运行的文件系统,然后做文件系统的切换。因为不像X86下那么复杂,所以设备的初始化相对而言较为简单。启动脚本和注释如下。

#! /bin/sh

#初始化环境变量
PATH=/sbin:/bin:/usr/sbin:/usr/bin
runlevel=S
prevlevel=N
umask 022
export PATH runlevel prevlevel

#
#       Trap CTRL-C &c only in this shell so we can interrupt subprocesses.
#
trap ":" INT QUIT TSTP
#设置主机名
/bin/hostname FriendlyARM
#mount proc文件系统
/bin/mount -n -t proc proc /proc

#获取U-boot启动参数,主要设置文件系统内型、根目录、init等
cmdline=`cat /proc/cmdline`

#声明初始化启动相关参数,并设置默认值
ROOT=none
ROOTFLAGS=
ROOTFSTYPE=
NFSROOT=
IP=
INIT=/sbin/init

#从获取的命令中获取启动参数
for x in $cmdline ; do
        case $x in
        root=*)
                ROOT=${x#root=}
                ;;
        rootfstype=*)
                ROOTFSTYPE="-t ${x#rootfstype=}"
                ;;
        rootflags=*)
                ROOTFLAGS="-o ${x#rootflags=}"
                ;;
        init=*)
                INIT=${x#init=}
                ;;
        nfsroot=*)
                NFSROOT=${x#nfsroot=}
                ;;
        ip=*)
                IP=${x#ip=}
                ;;

        esac
done

if [ ! -z $NFSROOT ] ; then
	#网络文件系统启动
	echo $NFSROOT | sed s/:/\ /g  > /dev/x ;  read sip dir < /dev/x 	echo $IP | sed s/:/\ /g > /dev/x;  read cip sip2 gip netmask hostname device autoconf < /dev/x
	rm /dev/x

	mount -t nfs $NFSROOT /r -o nolock,proto=tcp

elif [ ! -z $run_fs_image ] ; then
	#制定的文件系统启动,这个环境变量还不知道是如何导出的,所以还需要了解,
	#看到友善提供的配置文件需要制定启动的文件系统,感觉应该是和那个地方相关,
	#但是又不能确定,高手可以指点一下
	ROOTFSTYPE="-t ext3" #设置文件系统类型
	#重复加载SD卡,重复尝试5次
	for i in 1 2 3 4 5 ; do
	/bin/mount -n -o sync -o noatime -o nodiratime -t vfat /dev/mmcblk0p1 /sdcard && break
	echo Waiting for SD Card...
	sleep 1
	done
	#加载文件系统
	/sbin/losetup /dev/loop0 /sdcard/$run_fs_image
	/bin/mount $ROOTFSTYPE /dev/loop0 /r
	mount -o move /sdcard /r/sdcard
else
    #直接用指定的启动参数加载文件系统
    /bin/mount -n $ROOTFLAGS $ROOTFSTYPE $ROOT /r
fi

#检测并设置触摸屏的校正参数,可无
ONE_WIRE_PROC=/proc/driver/one-wire-info
ETC_BASE=/r/etc
[ -d /r/system/etc ] && ETC_BASE=/r/system/etc
[ -e $ETC_BASE/ts.detected ] && . $ETC_BASE/ts.detected
[ -z $CHECK_1WIRE ] && CHECK_1WIRE=Y
if [ $CHECK_1WIRE = "Y" -a -e $ONE_WIRE_PROC ] ; then
        if read lcd_type fw_ver tail < $ONE_WIRE_PROC ; then                 if [ x$lcd_type = "x0" -a x$fw_ver = "x0" ] ; then                         TS_DEV=/dev/touchscreen                 else                         TS_DEV=/dev/touchscreen-1wire                         echo "1Wire touchscreen OK"                 fi                 if [ -e $ETC_BASE/friendlyarm-ts-input.conf ]; then                         sed "s:^\(TSLIB_TSDEVICE=\).*:\1$TS_DEV:g" $ETC_BASE/friendlyarm-ts-input.conf > $ETC_BASE/ts-autodetect.conf
                        mv $ETC_BASE/ts-autodetect.conf $ETC_BASE/friendlyarm-ts-input.conf -f
                        echo "CHECK_1WIRE=N" > $ETC_BASE/ts.detected
                        sync
                fi
        fi
fi

[ -e /r/etc/friendlyarm-ts-input.conf ] && . /r/etc/friendlyarm-ts-input.conf
[ -e /r/system/etc/friendlyarm-ts-input.conf ] && . /r/system/etc/friendlyarm-ts-input.conf
export TSLIB_TSDEVICE

#exec /bin/sh

#文件系统替换
umount /proc
exec switch_root /r $INIT /r/dev/console 2>&1

被“欺骗”的脚本

当初以为ext3的文件系统就是实际启动时执行的操作,但是那个却是一个错误的认识,之所以认为那个是启动的文件系统,是因为内核的一个配置参数和此文件系统包含了一些脚本,所以在启动时走了不少的弯路。

首先是对initramfs的认识不够,内核中有下面一个配置项:

General setup  --->
    (scripts/FriendlyARM.cpio) Initramfs source file(s)

看了文件后,我以为是友善的一个加密程序,是为了保护自己的知识产权,所以以为它只是打包进去,到了加载初始化文件系统的时候从内核配置的地址读取文件系统,然后再用这个程序解密。其次那个启动的参数加深了我的这个认识,让我误入歧途,脚本如下:

Boot options  --->
    (console=ttySAC0,115200 root=/dev/ram init=/linuxrc initrd=0x51000000,6M ramdisk_size=6144)

所以我一直以为是我的文件系统没有拷贝到正确的物理地址,导致内核死掉;一直在尝试文件系统到内存并设置u-boot的环境变量,然后反复重新启动,但是一直是无解,最后我绝望了。在网上看了很多资料,发现Initramfs source file配置的应该是文件系统,再看看这个配置项就感觉像是一个cpio命令归档的文件系统,然后果断尝试能否将他解压。用如下命令解压它的归档文件:

cpio -ivmd < FriendlyARM.cpio

发现神奇般的解压开了,然后发现它就是一个文件系统,只是友善打包好了,然后配合它的Superboot来启动它的文件系统。然后就可以看到友善的第一步启动过程,其脚本也在上一节做了一些注释(一开始我还是死脑子地认为init也是一个可执行文件,琢磨一段时间后才考虑直接打开的)。其实上面的Boot options是使用ramdisk启动Linux所用到的配置项,用initramfs这个配置项是不必要的。

这样也就知道了mini6410的全部启动过程,前面走过的弯路总算有一个较好的结局了。

总结

其实Linux启动过程的介绍网上有很多,制作自己的最小启动系统的资料也不少,但是用了友善的开发板后总觉得它会保密,所以在理解它的一些机制的时候总会有定向思维,不敢放手去做,总是觉得自己哪里做错了。其实应该大胆去尝试,毕竟搞开发的人不会去把简单问题复杂化。冷静的思考其实也很重要,看到那个FriendlyARM.cpio时,我没有想到他是一个文件系统的归档文件,以为是和cpio命令相关的应用程序,这才让我走了很多弯路,其实可以通过file命令查看一下它到底是什么文件,那样也不至于走那么多的弯路。还是自己的经验尚浅啊~~不过走了一些弯路应该会记得更加清楚。

无评论

在Mini6410上安装自己的内核和文件系统

一 09 2012 由 创建在标签 开发

前面有一篇文章说的是Mini6410的启动过程,主要说的是6410的启动的一些大致流程,并没有提到内核和文件系统。做过嵌入式的人都应该知道系统的资源是有限的,需要倍加珍惜,所以在特定的应用场景中要使用定制的内核和文件系统,而友善提供的文件系统显得很臃肿,有点浪费空间,而且不是所有的功能我们都需要用到,自己定制一个文件系统是一个很好的选择,也是在开发过程中一个必须做到的工作。

6410的内核和文件系统

由于用的是友善提供的Superboot,所以需要了解友善是如何来做的。友善的Superboot启动的时候先读取它的配置文件,找到内核镜像和文件系统的目录(注:友善Superboot的具体实现不太清楚,所以只是猜测),然后加载内核,我是用SD卡启动的,方便更新文件系统和内核。下面是友善提供的文件系统和内核的大小,你会发现比你想象的要大很多。

[root@gaoliang Linux]# ls -lh
-rwxr-xr-x    1 root     root        3.6M Nov 16 18:49 zImage_n43
-rwxr-xr-x    1 root     root      293.0M Nov 19 21:04 rootfs_qtopia_qt4.ext3

一个文件系统就占了近200M的空间,在硬件资源有限的情况下,我们还是应该要好好珍惜那点宝贵的资源。

裁剪文件系统

我是直接从友善的文件系统中把文件拷贝过来,在原有的基础上做一些改动,主要是删除一些没有用或者不实用的功能。

首先先查看每个目录的大小,从而知道哪些地方是我们重点关注的地方。

[root@localhost rootfs_qtopia_qt4]# du -sh *
724K    bin
4.0K    dev
648K    etc
53M     lib
0       linuxrc
4.0K    mnt
86M     opt
4.0K    proc
21M     root
1.2M    sbin
4.0K    sys
4.0K    tmp
76M     usr
4.0K    var
592K    www

其中lib、opt和usr占用的空间比较多,其中lib目录是因为modules目录中包含了两个版本的内核;opt是一些可选包,主要是QT相关的一些库;usr目录主要是播放器的应用程序和一些测试程序。

所以将opt目录下的东西全部删除,删除usr目录下关于应用程序的部分,如果删除了应用程序,应用程序会起不来,如smplayer就不能正常工作,也可以同时删除bin目录下相应的东西。

最后再将lib目录下的modules删除,删除了之后就只安装我们自己编译内核配置的模块,可以直接复制一份友善提供的配置文件编译内核(要与开发板对应),编译完成后用如下命令来在我的文件系统下安装模块。

make modules_install INSTALL_MOD_PATH=/opt/arm/mini6410/linux/rootfs
#INSTALL_MOD_PATH你的文件系统所在的路径

这样就可以将我们所配置的内核模块安装到我们的文件系统中来。从而减小文件系统的大小。

内核配置

内核的裁剪网上也有很多介绍,每一个配置项也都有介绍,而且翻译过来的中文资料也比较多,可以在网上搜一搜。

目前的状态和打算

现在我裁剪后文件系统已经比原先的小了很多,因为还有一些不了解的东西,所以也没有细看,如果把一些无用的东西全部去掉的话,应该能够做得很小。下面是我裁剪后的内核和文件系统:

[root@gaoliang Linux]# ls -lh
-rwxr-xr-x    1 root     root       89.0M Nov 20 08:01 rootfs_qtopia_qt4.ext3
-rwxr-xr-x    1 root     root        3.6M Jan  9  2012 zImage_n43

但是也有一个比较奇怪的现象,就是用友善提供的制作文件系统的工具所制作的文件系统比原来的还要大,并没有压缩。这个让人感动有些奇怪。我在Linux下未打包的文件系统只有69M,所以后面打算用压缩的方式打包,将文件系统压得更小,但是因为不了解Superboot做了哪些工作,这个还有一定难度。配置文件对Superboot有什么影响也需要弄清楚,因为配置文件中指定了文件系统,所以也不清楚如何让内核加载文件系统有没有受到Bootloader的影响。

因为删除了QT相关的库,所以也想移植一个新的GUI库,主要是减少文件系统的大小,我身边有人在做MiniGUI,所以初步想法是用miniGUI做一套新的GUI,但是不去开发它的应用程序了,等miniGUI3.0的源码放出来之后开始做这个工作(今天问过miniGUI的技术支持,3.0的源码还有一个月才放出,但是总归是开源,还是不错的)。

希望有对Superboot有了解的人说说,但是这个是人家的商业机密,让人挺烦的…不过这个也没有办法,还是靠自己去慢慢去摸索吧。

无评论

U-boot简介及启动过程

一 03 2012 由 创建在标签 开发

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嵌入式操作系统。其目前要支持的目标操作系统是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软件工程中心WolfgangDenk本人精湛专业水平和持着不懈的努力。当前,U-Boot项目正在他的领军之下,众多有志于开放源码BOOT LOADER移植工作的嵌入式开发人员正如火如荼地将各个不同系列嵌入式处理器的移植工作不断展开和深入,以支持更多的嵌入式操作系统的装载与引导。

选择U-Boot的理由:

  1. 开放源码;
  2. 支持多种嵌入式操作系统内核,如Linux、NetBSD, VxWorks, QNX, RTEMS, ARTOS, ynxOS;
  3. 支持多个处理器系列,如PowerPC、ARM、x86、MIPS、XScale;
  4. 较高的可靠性和稳定性;
  5. 较高的可靠性和稳定性;
  6. 高度灵活的功能设置,适合U-Boot调试、操作系统不同引导要求、产品发布等;
  7. 丰富的设备驱动源码,如串口、以太网、SDRAM、FLASH、LCD、NVRAM、EEPROM、RTC、键盘等;
  8. 较为丰富的开发调试文档与强大的网络技术支持;

U-boot源码结构

解压就可以得到全部u-boot源程序。在顶层目录下有18个子目录,分别存放和管理不同的源程序。这些目录中所要存放的文件有其规则,可以分为3类。

  • 第1类目录与处理器体系结构或者开发板硬件直接相关;
  • 第2类目录是一些通用的函数或者驱动程序;
  • 第3类目录是u-boot的应用程序、工具或者文档。

U-boot的源码顶层目录说明

目    录 特    性 解 释 说 明
board 平台依赖 存放电路板相关的目录文件,例如:RPXlite(mpc8xx)、smdk2410(arm920t)、sc520_cdp(x86) 等目录
cpu 平台依赖性 存放CPU相关的目录文件,例如:mpc8xx、ppc4xx、arm720t、arm920t、 xscale、i386等目录
lib_ppc 平台依赖 存放对PowerPC体系结构通用的文件,主要用于实现PowerPC平台通用的函数
lib_arm 平台依赖 存放对ARM体系结构通用的文件,主要用于实现ARM平台通用的函数
lib_i386 平台依赖 存放对X86体系结构通用的文件,主要用于实现X86平台通用的函数
include 通用 头文件和开发板配置文件,所有开发板的配置文件都在configs目录下
common 通用 通用的多功能函数实现
lib_generic 通用 通用库函数的实现
net 通用 存放网络的程序
fs 通用 存放文件系统的程序
post 通用 存放上电自检程序
drivers 通用 通用的设备驱动程序,主要有以太网接口的驱动
disk 通用 硬盘接口程序
rtc 通用 RTC的驱动程序
dtt 通用 数字温度测量器或者传感器的驱动
examples 应用例程 一些独立运行的应用程序的例子,例如helloworld
tools 工具 存放制作S-Record或者u-boot格式的映像等工具,例如mkimage
doc 文档 开发使用文档

设备启动过程

开机或者重启后分为两个步骤处理,处理器先完成基本的初始化,然后将执行权交给U-boot来完成初始化。

处理器执行如下步骤:

  1. 执行主引导配置,初始化中断向量、异常向量、时钟和SDRAM;
  2. 将U-Boot的代码从Flash解压到RAM;
  3. 将执行控制权交给U-Boot;

U-boot执行如下几个步骤:

  1. 配置的以太网MAC地址、Flash、串口;
  2. 加载存储在非易失性内存中的环境变量的设置;
  3. 过几秒钟(可编程的时间长度),自动启动预先安装内核;

U-boot相关参考站点

  1. 官方网站源码包(http://sourceforge.net/projects/U-Boot);
  2. U-Boot官方网站的DULG(The DENX U-Boot and Linux Guide)文档http://www.denx.de/twiki/bin/view/DULG/Manual);

无评论

Mini6410的启动过程

十二 27 2011 由 创建在标签 开发

入手Mini6410很久,一直没有用起来,最近项目稍微轻松一点,开始拿起来做点事情、学点东西,后面也会把这款开发板的一些情况发不上来。

Mini6410简介

Mini6410是友善基于三星6410开发的一款ARM11开发板,想了解的人可以到官网看看(6410友善官网),里面有详细的信息。

这里也简要提一下6410一些让人蛋疼的东西,让人用着很不爽,因为还没有用得很熟悉,就说说目前发现的两个让人不爽的地方。第一,它的Superloader不开源,提供的开源的U-boot又不能支持SD卡启动;第二,文件系统压缩使用了自己的压缩方法(在内核配置的地方可以查看到),如果我们想用通用的程序来做的话,压力会比较大。

6410的启动过程介绍

和X86平台的启动过程不同的是6410通过busybox启动,将复杂的启动过程变得简单化,便于初学者学习和使用此块开发板。

开机启动时首先进入Bootloader,它主要完成的工作是初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境。友善提供了两种Bootloader,基于Samsung的u-boot做了一点修改的和友善自己开发的SuperLoader,SuperLoader功能比较强大,但是不开源,可以免费使用;但是如果我们自己想做一些改变的话,那就有点困难了。

由Bootloader引导后,系统加载内核,内核加载后加载文件系统,之后执行init程序,但是友善直接修改了内核的配置,直接运行linuxrc程序(其实是busybox),然后就开始执行init.d下的rcS脚本。下面将通过内核配置和脚本来介绍它启动的一些细节。

在友善提供的文件系统中的.config中,可以看到启动执行的程序被修改为linuxrc,而且linuxrc只是busybox的一个符号链接,如下:

init.d目录下的启动脚本

rcS启动脚本注解

#! /bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:
runlevel=S
prevlevel=N
umask 022
#导出环境变量和运行级别
export PATH runlevel prevlevel
#
#       Trap CTRL-C &c only in this shell so we can interrupt subprocesses.
#
trap ":" INT QUIT TSTP
#设置主机名称
/bin/hostname friendARM
[ -e /proc/1 ]    || /bin/mount -n -t proc  none /proc
[ -e /sys/class ] || /bin/mount -n -t sysfs none /sys
[ -e /dev/tty ]   || /bin/mount    -t ramfs none /dev
/bin/mount -n -t usbfs none /proc/bus/usb

echo /sbin/mdev > /proc/sys/kernel/hotplug

#udev实现U盘或SD卡的自动挂载,mdev是busybox中的一个udev管理程序的一个精简版,他也可以实现设备节点的自动创建和设备的自动挂载
/sbin/mdev -s
/bin/hotplug

# mounting file system specified in /etc/fstab
mkdir -p /dev/pts
mkdir -p /dev/shm
/bin/mount -n -t devpts none /dev/pts -o mode=0622
/bin/mount -n -t tmpfs tmpfs /dev/shm
/bin/mount -n -t ramfs none /tmp
/bin/mount -n -t ramfs none /var
mkdir -p /var/empty
mkdir -p /var/log
mkdir -p /var/lock
mkdir -p /var/run
mkdir -p /var/tmp

/sbin/hwclock -s
syslogd

#启动网络配置
/etc/rc.d/init.d/netd start
echo "                        " > /dev/tty1
echo "Starting networking..." > /dev/tty1
sleep 1

#启动httpd
/etc/rc.d/init.d/httpd start
echo "                        " > /dev/tty1
echo "Starting web server..." > /dev/tty1
sleep 1

#启动Led模块
/etc/rc.d/init.d/leds start
echo "                        " > /dev/tty1
echo "Starting leds service..." > /dev/tty1
echo "                        "
sleep 1
echo "                        " > /dev/tty1

#alsaconf,看了启动的程序发现是一些默认的配置项
/etc/rc.d/init.d/alsaconf start
echo "Loading sound card config..." > /dev/tty1
echo "                        "

#配置网络相关地址
/sbin/ifconfig lo 127.0.0.1
/etc/init.d/ifconfig-eth0

#启动QT图形界面
/bin/qtopia &
echo "                                  " > /dev/tty1
echo "Starting Qtopia, please waiting..." > /dev/tty1

一条评论

下一页 »