2008年12月25日星期四

gst-ffmpeg

/home/gstreamer/gst-ffmpeg-0.10.6
./configure --host=arm-linux --prefix=/home/gstreamer/install --enable-shared CFLAGS=-I/home/gstreamer/install/include/ LDFLAGS="-L/home/gstreamer/install/lib -lbz2 -lamrwb -lamrnb" --with-ffmpeg-extra-configure="--prefix=/home/gstreamer/install --enable-cross-compile --enable-gpl --disable-network --disable-ipv6 --disable-vhook --disable-mpegaudio-hp --enable-pthreads --disable-parsers --arch=armv4l --disable-muxers --disable-encoders --disable-stripping --host-cc=arm-linux-gcc --disable-armv6 --disable-armv5te --disable-armvfp --disable-ffmpeg --enable-static --enable-shared --cross-prefix=/usr/local/arm/3.4.1/bin/arm-linux- ARCH_ARMV4L=y --enable-libamr-nb --enable-libamr-wb --enable-libxvid --enable-nonfree"

/home/gstreamer/amrnb-7.0.0.2
echo ac_cv_func_malloc_0_nonnull=yes >> arm.cache
echo ac_cv_file__bin_bash=yes >> arm.cache
./configure --host=arm-linux --prefix=/home/gstreamer/amrnb-7.0.0.2/../install --cache-file=arm.cache

/home/gstreamer/amrwb-7.0.0.3
echo ac_cv_func_malloc_0_nonnull=yes >> arm.cache
echo ac_cv_file__bin_bash=yes >> arm.cache
./configure --host=arm-linux --prefix=/home/gstreamer/amrwb-7.0.0.3/../install --cache-file=arm.cache

/home/gstreamer/xvidcore/build/generic
./configure --host=arm-linux --prefix=/home/gstreamer/install

How to install FFmpeg with MP3 and AMR support

http://www.mattiouz.com/blog/2007/07/02/how-to-install-ffmpeg-with-mp3-and-amr-support/

2008年12月20日星期六

编译gstreamer相关

把编译完的配置从config.log里拷出来,去掉双引号了,记得加上

gstreamer统一目录是/home/gstreamer,编译后统一安装在/home/gstreamer/install文件夹里,所以设置pkgconfig就只用设置一个地址
export PKG_CONFIG_LIBDIR=/home/gstreamer/install/lib/pkgconfig

然后开始编译
/home/gstreamer/gstreamer-0.10.21/

$ ./configure --disable-nls --disable-static --enable-binary-registry --disable-loadsave --with-html-dir=/tmp/dump --prefix=/home/gstreamer/gstreamer-0.10.21/../install --host=arm-linux LDFLAGS=-L/home/gstreamer/install/lib/ -L/home/gstreamer/install/lib/ -lglib-2.0 -lgio-2.0 -lgobject-2.0 -lgthread-2.0 -lgmodule-2.0 -lxml2 CFLAGS=-I/home/gstreamer/install/include/ -I/home/gstreamer/install/include/glib-2.0/ -I/home/gstreamer/install/lib/glib-2.0/include

/home/gstreamer/gst-plugins-base-0.10.21/
$ ./configure --host=arm-linux --prefix=/home/gstreamer/gst-plugins-base-0.10.21/../install --disable-static --with-html-dir=/tmp/dump CFLAGS=-I/home/gstreamer/install/lib/glib-2.0/include -I/home/gstreamer/install/include/glib-2.0 -I/home/gstreamer/install/include/liboil-0.3/liboil -I/home/gstreamer/install/include/gstreamer-0.10/gst -I/home/gstreamer/install/include/gio-unix-2.0/gio -I/home/gstreamer/install/include/libxml2/libxml LDFLAGS=-L/home/gstreamer/install/lib/ -L/home/gstreamer/install/lib/gstreamer-0.10 -L/home/gstreamer/install/lib/python2.5/site-packages --with-pkg-config-path=/home/gstreamer/install/lib/pkgconfig --disable-x --disable-xvideo --disable-xshm --disable-gnome_vfs --disable-cdparanoia --disable-libvisual --disable-alsa --disable-ogg --disable-oggtest --disable-pango --disable-vorbis --disable-vorbistest

/home/gstreamer/gst-plugins-good-0.10.11/
$ ./configure --host=arm-linux --prefix=/home/gstreamer/gst-plugins-good-0.10.11/../install --disable-nls --disable-static --with-html-dir=/tmp/dump --with-plugins=avi,qtdemux CFLAGS=-I/home/gstreamer/install/lib/glib-2.0/include -I/home/gstreamer/install/include/glib-2.0 -I/home/gstreamer/install/include/liboil-0.3/liboil -I/home/gstreamer/install/include/gstreamer-0.10/gst -I/home/gstreamer/install/include/gio-unix-2.0/gio -I/home/gstreamer/install/include/libxml2/libxml LDFLAGS=-L/home/gstreamer/install/lib/ -L/home/gstreamer/install/lib/gstreamer-0.10 -L/home/gstreamer/install/lib/python2.5/site-packages --disable-x --disable-xshm --disable-xvideo --disable-esd --disable-shout2

/home/gstreamer/gst-plugins-ugly-0.10.10/
$ ./configure --host=arm-linux --prefix=/home/gstreamer/gst-plugins-ugly-0.10.10/../install --disable-nls --disable-static --with-html-dir=/tmp/dump --with-plugins=asfdemux CFLAGS=-I/home/gstreamer/install/lib/glib-2.0/include -I/home/gstreamer/install/include/glib-2.0 -I/home/gstreamer/install/include/liboil-0.3/liboil -I/home/gstreamer/install/include/gstreamer-0.10/gst -I/home/gstreamer/install/include/gio-unix-2.0/gio -I/home/gstreamer/install/include/libxml2/libxml LDFLAGS=-L/home/gstreamer/install/lib/ -L/home/gstreamer/install/lib/gstreamer-0.10 -L/home/gstreamer/install/lib/python2.5/site-packages

/home/gstreamer/gst-plugins-bad-0.10.9/
$ ./configure --host=arm-linux --prefix=/home/gstreamer/gst-plugins-bad-0.10.9/../install CFLAGS=-I/home/gstreamer/install/lib/glib-2.0/include -I/home/gstreamer/install/include/glib-2.0 -I/home/gstreamer/install/include/liboil-0.3/liboil -I/home/gstreamer/install/include/gstreamer-0.10/gst -I/home/gstreamer/install/include/gio-unix-2.0/gio -I/home/gstreamer/install/include/libxml2/libxml LDFLAGS=-L/home/gstreamer/install/lib/ -L/home/gstreamer/install/lib/gstreamer-0.10 -L/home/gstreamer/install/lib/python2.5/site-packages --disable-nls --disable-static --with-html-dir=/tmp/dump --disable-apexsink --disable-sdl

/home/gstreamer/glib-2.18.3
$ ./configure --cache-file=arm.cache --host=arm-linux --prefix=/home/gstreamer/glib-2.18.3/install
arm.cache的内容在前面的文章里写了。家里用X86_64编译的,把posix那2个设置为no,可以编译过了。也没有WARNING提示了。

/home/gstreamer/libxml2-2.6.24/
$ ./configure --host=arm-linux --prefix=/home/gstreamer/libxml2-2.6.24/../install/

/home/gstreamer/liboil-0.3.15/
$ ./configure --host=arm-linux --prefix=/home/gstreamer/liboil-0.3.15/../install/ --disable-static --with-html-dir=/tmp/dump CFLAGS=-I/home/gstreamer/install/lib/glib-2.0/include -I/home/gstreamer/install/include/glib-2.0 LDFLAGS=-L/home/gstreamer/install/lib/
修改的configure文件在前面文章里写了

这里的编译都是不带额外的plugins,比如没有把mad加进去

运行时设置环境变量GST_PLUGINS_PATH为包含plugin的地址
在没有设置该环境变量时,运行/home/gstreamer/gstreamer-0.10.21/tests/examples/helloworld/.libs下的helloworld程序会报错:

# ./helloworld a
**
ERROR:helloworld.c:59:main: assertion failed: (filesrc)
Aborted

本来是件简单的事情,设置环境变量就行了,但是网上没搜到解决办法,加入了gstreamer的QQ群,也没人告诉我。有个人倒是算热心回答我问题,但是他觉得这里不应该出错,他不会在这里出错。那么他们怎么把有哪些plugin告诉gstreamer的?可能办法不一样吧。结果我找到一篇"GStreamer Plugin Writer's Guide(0.10.21.1)",Chapter 9. Building a Test Application才知道要设置GST_PLUGIN_PATH

2008年12月19日星期五

在fedora9 x86_64上编译arm qt2.2.0

系统:Fedora9 x86_64

1>下载cross-3.3.2.tar.bz2,并解压到/usr/local/arm/文件夹下,设置环境变量PATH
tar zjf cross-3.3.2.tar.bz2 -C /usr/local/arm/
export PATH=$PATH:/usr/local/arm/3.3.2/bin

2>建立目录armqt,设置环境变量
mkdir /home/armqt //arm qt根目录
export ARMQT=/home/armqt
mkdir $ARMQT/tools //arm库
mkdir $ARMQT/tools/lib //arm库lib
mkdir $ARMQT/tools/include //arm库include
mkdir $ARMQT/arm220 //编译arm qt
mkdir $ARMQT/qtopia //make install的路径,生成的qt及其库的文件系统文件夹

3>下载qtopia-free-src-2.2.0.tar.gz解压到$ARMQT/arm220,省掉下一级qtopia-free-2.2.0目录

4>下载arm需要的库,并解压到$ARMQT/tools下,并编译
A e2fsprogs-1.39.tar.gz

下载地址
http://nchc.dl.sourceforge.net/sourceforge/e2fsprogs/e2fsprogs-1.39.tar.gz

安装
./configure --host=arm-linux --enable-elf-shlibs --with-cc=arm-linux-gcc --with-linker=arm-linux-ld --prefix=/usr/local/arm/2.95.3/arm-linux
make
cp lib/libuuid.so* ../lib/

B jpegsrc.v6b.tar.gz

下载地址
http://down1.chinaunix.net/distfiles/jpegsrc.v6b.tar.gz

I 缺少libtool,下载
yum install libtool
cp /usr/share/libtool/config.guess /home/armqt/tools/jpeg-6b/ -rf
cp /usr/share/libtool/config.sub /home/armqt/tools/jpeg-6b/ -rf

II ./configure --enable-shared

III 修改Makfile,搜索到CC,AR,AR2宏替换为下面(如果是export CC=arm-linux-gcc,
在Makefile中虽然cc,ld等变了,但是ar,ranlib就没有改变)
CC=arm-linux-gcc
AR=arm-linux-ar rc
AR2=arm-linux-ranlib

IV make

V 拷贝库文件和头文件到统一目录
cp *.h ../include/
cp .libs/libjpeg.so* ../lib/

VI 可以用file看一下编译出来的是否是arm版本的及是否动态链接
[root@localhost jpeg-6b]# file wrjpgcom
wrjpgcom: ELF 32-bit LSB executable, ARM, version 1, dynamically linked (uses shared libs), for GNU/Linux 2.0.0, not stripped

C zlib-1.2.3.tar.bz2

下载地址
http://www.zlib.net/zlib-1.2.3.tar.gz

I ./configure -shared

II 修改Makfile,搜索到CC,LDSHARED,CPP,AR,RANLIB,prefix宏替换为下面
CC=arm-linux-gcc
CPP=arm-linux-gcc -E
LDSHARED=arm-linux-gcc -shared -Wl,-soname,libz.so.1
AR=arm-linux-ar rc
RANLIB=arm-linux-ranlib
prefix=/usr/local/arm/3.3.2/arm-linux

III make

IV 拷贝库文件和头文件到统一目录
cp libz.so* ../lib/
cp *.h ../include/

D libpng-1.2.14.tar.bz2

下载地址
http://superb-east.dl.sourceforge.net/sourceforge/libpng/libpng-1.2.14.tar.bz2

I cp scripts/makefile.linux Makefile

II 修改Makfile,搜索到CC,AR,AR2,prefix,ZLIBLIB,ZLIBINC宏替换为下面
CC=arm-linux-gcc
AR=arm-linux-ar rc
AR2=arm-linux-ranlib
prefix=/usr/local/arm/3.3.2/arm-linux
ZLIBLIB=../lib
ZLIBINC=../include

III make

IV 拷贝库文件和头文件到统一目录
cp libpng12.so* ../lib/
cp libpng12.so ../lib/libpng.so
cp *.h ../include/

E uic-qt2

下载地址
http://vanille.de/tools/uic-qt2

chmod 777 uic-qt2
cp uic-qt2 $ARMQT/arm220/qt2/bin/uic

5>编译qt前的准备
A修改文件$ARMQT/arm220/qtopia/mkspecs/qws/linux-arm-g++/qmake.conf
chmod 777 $ARMQT/arm220/qtopia/mkspecs/qws/linux-arm-g++/qmake.conf

QMAKE_LIBS_QT = -lqte
改为
QMAKE_LIBS_QT = -lqte -lpng -lz -luuid -ljpeg

B修改文件$ARMQT/arm220/qtopia/src/qt/qconfig-qpe.h
chmod 777 $ARMQT/arm220/qtopia/src/qt/qconfig-qpe.h
添加到文件最后
#define QT_QWS_IPAQ
#define QT_QWS_IPAQ_RAW

C修改文件$ARMQT/arm220/qt2/include/qvaluestack.h
chmod 777 $ARMQT/arm220/qt2/include/qvaluestack.h
remove( this->fromLast() );
改为
this->remove( this->fromLast() );

D修改文件$ARMQT/arm220/qtopia/src/libraries/qtopia/qdawg.cpp
chmod 777 $ARMQT/arm220/qtopia/src/libraries/qtopia/qdawg.cpp
QDawgPrivate::~QDawgPrivate()
改为
~QDawgPrivate()

E
cp $ARMQT/arm220/qtopia/src/qt/qconfig-qpe.h $ARMQT/arm220/qt2/src/tools
cd $ARMQT/arm220/qtopia/src/libraries/qtopia
cp custom-linux-ipaq-g++.cpp custom-linux-arm-g++.cpp
cp custom-linux-ipaq-g++.h custom-linux-arm-g++.h

F编译时出现了qvfb错误,没搜到网上别人怎么做的,反正arm也用不上,所以干脆删了
rm $ARMQT/arm220/dqt/tools/qvfb -rf

G下面都是在编译时少什么就加什么库,先用yum whatprovides确定库名字,然后用yum install更新,感觉很不安全一样,我怕影响有些什么功能不能使用了.gcc -m32也就是32位编译了,不知道为什么更新后它自动加上了-m32,是自适应还是手动?

/*****
本来安装了这3个包,但是按照前2天在32位机上使用gcc32的做法(替换gcc,g++,lib)会出错,所以只好放弃,谁能告诉我怎样在x86_64上用i386 gcc32?
compat-gcc-32-3.2.3-47.3.i386.rpm
compat-gcc-32-c%2B%2B-3.2.3-47.3.i386.rpm
compat-libstdc++-33-3.2.3-63.i386.rpm
******/

I gcc少头文件和libc
yum whatprovides */gnu/stubs-32.h
yum install glibc-devel.i386

yum whatprovides */4.3.0/libstdc++.a
yum install libstdc++-devel.i386

II 编译时缺少的其他i386库
yum whatprovides */libXext.so
yum install libXext-devel.i386

yum whatprovides */libX11*
yum install libX11-devel.i386
yum install libX11.i386

yum whatprovides */libSM*
yum install libSM.i386
cd /usr/lib64
rm libSM.so -rf
ln -s ../lib/libSM.so.6 libSM.so

yum whatprovides */libICE*
yum install libICE-devel.i386

H 配置环境变量
export QPEDIR=$ARMQT/arm220/qtopia
export QTDIR=$ARMQT/arm220/qtopia
export QTDIR=$ARMQT/arm220/qt2
export LD_LIBRARY_PATH=$QTDIR/lib:$QPEDIR/lib:$LD_LIBRARY_PATH
export TMAKEDIR=$ARMQT/arm220/tmake
export TMAKEPATH=$TMAKEDIR/lib/qws/linux-arm-g++

6>配置及编译qt, 最好配置是手敲的,网上考下来的容易少空格,配置错了又要重编划不来
echo 'yes'|./configure -qte "-embedded -xplatform linux-arm-g++ -qconfig qpe -no-qvfb -depths 16,24 -system-jpeg -system-libpng -system-zlib -gif -thread -no-xft -release -I$ARMQT/tools/include -L$ARMQT/tools/lib -lpng -lz -luuid -ljpeg" -qpe "-xplatform linux-arm-g++ -edition pda -displaysize 320x240 -I$ARMQT/tools/include -L$ARMQT/tools/lib -prefix=$ARMQT/qtopia"

make
make install

总算编出来了

2008年12月18日星期四

liboil编译选项

下载地址是http://liboil.freedesktop.org/download/

./configure --host=arm-linux --prefix=$PWD/install GLIB_CFLAGS=-I/home/gongh/test/gstreamer/glib-2.18.3/install/include/ GLIB_LIBS=-L/home/gongh/test/gstreamer/glib-2.18.3/install/lib/ CFLAGS="-I/home/gongh/test/gstreamer/glib-2.18.3/install/lib/glib-2.0/include -I/home/gongh/test/gstreamer/glib-2.18.3/install/include/glib-2.0" LDFLAGS=-L/home/gongh/test/gstreamer/glib-2.18.3/install/lib/ --disable-static --with-html-dir=/tmp/dump

开始用的是liboil0.3.15一直不能编译通过,错误是
arm-linux-gcc -DHAVE_CONFIG_H -I. -I. -I../.. -Wall -D_BSD_SOURCE -D_GNU_SOURCE -I../.. -DOIL_ENABLE_UNSTABLE_API -mfpu=vfp -I/home/gongh/test/gstreamer/glib-2.18.3/install/lib/glib-2.0/include -I/home/gongh/test/gstreamer/glib-2.18.3/install/include/glib-2.0 -MT libarm_la-math_vfp.lo -MD -MP -MF .deps/libarm_la-math_vfp.Tpo -c math_vfp.c -fPIC -DPIC -o .libs/libarm_la-math_vfp.o
cc1: error: invalid option `fpu=vfp'
make[3]: *** [libarm_la-math_vfp.lo] Error 1
make[3]: Leaving directory `/home/gongh/test/gstreamer/liboil-0.3.15/liboil/arm'
make[2]: *** [all-recursive] Error 1
make[2]: Leaving directory `/home/gongh/test/gstreamer/liboil-0.3.15/liboil'
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory `/home/gongh/test/gstreamer/liboil-0.3.15'
make: *** [all] Error 2

然后我换成了0.3.12版本居然过了。

但是0.3.12版本不能满足gstreamer 最低0.3.14要求。
再编译0.3.15,注释configure16617行,
#VFP_CFLAGS="$VFP_CFLAGS -mfpu=vfp"
这样是可以编译过,但这样会不会有什么问题?

gstreamer编译选项

另外下载了flex-2.5.35.tar.gz编译后替换了/usr/bin/flex,不然gstreamer-0.10.21配置检查flex版本过不了,即使修改configure中flex版本让老版本的去编译,也通过不了,确实还是需要高版本的flex才行

GLIB_CFLAGS=-I/home/gongh/test/gstreamer/glib-2.18.3/install/include/glib-2.0/ GLIB_LIBS=-L/home/gongh/test/gstreamer/glib-2.18.3/install/lib/ XML_LIBS=-L/home/gongh/test/gstreamer/libxml2-2.6.30/install/lib/ XML_CFLAGS=-I/home/gongh/test/gstreamer/libxml2-2.6.30/install/include/ ./configure --disable-nls --disable-static --enable-binary-registry --disable-loadsave --with-html-dir=/tmp/dump --prefix=$PWD/install --host=arm-linux LDFLAGS="-L/home/gongh/test/gstreamer/libxml2-2.6.30/install/lib/ -L/home/gongh/test/gstreamer/glib-2.18.3/install/lib/ -lglib-2.0 -lgio-2.0 -lgobject-2.0 -lgthread-2.0 -lgmodule-2.0" CFLAGS="-I/home/gongh/test/gstreamer/libxml2-2.6.30/install/include/ -I/home/gongh/test/gstreamer/glib-2.18.3/install/include/glib-2.0/ -I/home/gongh/test/gstreamer/glib-2.18.3/install/lib/glib-2.0/include" GLIB_ONLY_CFLAGS=-I/home/gongh/test/gstreamer/glib-2.18.3/install/include/glib-2.0/ GLIB_ONLY_LIBS=-L/home/gongh/test/gstreamer/glib-2.18.3/install/lib/

2008年12月17日星期三

交叉编译glib 2.18.3

现在版本是glib-2.18.3,编译器arm-linux 3.4.1

我用FC4编译的,有点老,在configure的时候说pkg-config版本太老了,至少要0.16版本的,而FC4是0.15版本,所以我把configure改了.新linux应该不用改吧
7600 if $PKG_CONFIG --atleast-pkgconfig-version 0.16 ; then
改成了
7600 if $PKG_CONFIG --atleast-pkgconfig-version 0.15 ; then

然后参考一篇很有用的howto
http://library.gnome.org/devel/glib/unstable/glib-cross-compiling.html
需要写一个cache文件arm.cache,且我在当前目录下建立了一个install文件夹,存放make install后的库等。配置是
./configure --cache-file=arm.cache --host=arm-linux --prefix=$PWD/install

编译时如果出现错误,就看错误是什么,根据howto添加,我编译时最少添加如下几项后就能配置通过,然后就编译通过了。以下是arm.cache的内容。
glib_cv_long_long_format=ll
glib_cv_stack_grows=no
glib_cv_uscore=no
ac_cv_func_posix_getpwuid_r=yes
ac_cv_func_posix_getgrgid_r=yes

当配置成功后arm.cache内容就变了

2008年12月11日星期四

MPlayer-1.0rc2编译选项

--target=arm-linux --prefix=install --cc=/usr/local/arm/gcc-3.4.5-glibc-2.3.6/arm-softfloat-linux-gnu/bin/arm-softfloat-linux-gnu-gcc --enable-fbdev --disable-win32dll --disable-dvdread --disable-network --enable-menu --disable-ftp --disable-alsa --enable-ossaudio --disable-tv --disable-x11 --enable-cross-compile --target=arm-linux --host-cc=gcc --disable-armv5te --disable-armv6 --language=en --enable-debug

可以跑,不过mp3没声音,所以一会加个mad上去
加上了,要make clean后再make,不然链接有错误
./configure --target=arm-linux --prefix=install --cc=/usr/local/arm/gcc-3.4.5-glibc-2.3.6/arm-softfloat-linux-gnu/bin/arm-softfloat-linux-gnu-gcc --enable-fbdev --disable-win32dll --disable-dvdread --disable-network --enable-menu --disable-ftp --disable-alsa --enable-ossaudio --disable-tv --disable-x11 --enable-cross-compile --target=arm-linux --host-cc=gcc --disable-armv5te --disable-armv6 --language=en --enable-debug --enable-mad --with-extraincdir=/home/gongh/test/libmad-0.15.1b/install/include --with-extralibdir=/home/gongh/test/libmad-0.15.1b/install/lib --disable-mp3lib

可以播mp3了

但是播放avi时还是会音视频不同步,加autosync后,视频虽然和音频打印同步了,但是其实CPU速度就是不够,声音还是走在视频前面

2008年11月27日星期四

uda1341在2.6.27 2440

直接用的网上的patch,虽然patch的时候稍微有一点差别,造成*.orig, *.prej,但是改一下就好了,把patch地址给出来。连续4页

[PATCH RESEND 0/3] ALSA SOC driver for s3c24xx with uda134x

http://www.spinics.net/lists/arm-kernel/msg58298.html

http://www.spinics.net/lists/arm-kernel/msg58299.html

http://www.spinics.net/lists/arm-kernel/msg58300.html

http://www.spinics.net/lists/arm-kernel/msg58301.html

记录一下今天上午看的mmc代码(2.6.27)

S3C2440板子。先统计一下编译了哪些文件,分别是

card/
block.o queue.o
host/
s3cmci.o
core/
bus.o core.o host.o
及sd,mmc,sdio 3种规范的相关文件:
sd: sd.o sd_ops.o
mmc: mmc.o mmc_ops.o
sdio: sdio.o sdio_ops.o sdio_bus.o sdio_cis.o sdio_io.o sdio_irq.o

看别人写的抄下来的流程:
1. 内核启动initcall ==>> mmc_init() ==>> mmc_blk_init()
2. xx_mmc_probe 检测挂在的设备
3. 起延时任务mmc_rescan()对卡初始化
4. mmc_attach_sd(),mmc_attach_mmc(),mmc_attach_sdio()加载设备
5. mmc_add_card()

6.卡加入系统后,mmc_blk_probe()分配mmc_blk_data结构变量
7.mmc_init_queue()初始化
8.建立线程mmc_queue_thread(),接受块设备读写请求并处理

然后看代码把每个文件做的事写一下,有点乱
s3cmci.c
注册s3c2410,2412,2440平台驱动
mmc_alloc_host
硬件初始化,注册中断
mmc->ops = &s3cmci_ops 结构成员函数有request,set_ios,get_ro,get_cd
中断函数s3cmci_irq()完成读写,中断中起tasklet即pio_tasklet(),再区分为do_pio_read(),do_pio_write()

block.c
注册块设备,主设备号179,向mmc_driver注册驱动
mmc_blk_probe()==>>mmc_blk_alloc()==>>mmc_init_queue()在此函数中起线程.线程函数是queue.c中的mmc_queue_thread()
在 线程中根据blk_queue_plugged()判断队列是否有插入,取得elv_next_request()的返回值struct request*,调用mq->issue_fn函数即block.c的mmc_blk_issue_irq()处理,在 mmc_wait_for_req()函数种把请求传给host->ops->request,即s3cmci_ops中的request结 构成员函数

bus.c
struct mmc_card结构相关
提供函数alloc card(),add_card(), 在add_card()中调用device_add()添加设备
向系统注册总线mmc_bus_type
把block.c注册过来的mmc_driver注册为系统的驱动

core.c
mmc_rescan()分辨检测卡
mmc_init()起工作队列,初始检测及热插拔时detect用
调用注册总线,注册class

host.c
与s3cmci.c相关联的文件,找到设备前先假设有设备,mmc_alloc_host()起工作队列mmc_rescan()检测设备,未检测到释放host,检测到了调用device_add添加设备

只看mmc规范
mmc.c
mmc_rescan中找到卡后调用mmc_attach_mmc初始化卡,提供detect函数每次检测卡是否拔出

mmc_ops.c
mmc的具体命令,比如go_idle(),send_cid()等

分辨sdio,mmc,sd卡,通过发命令,具体命令我不确定
发送cmd5,如果有响应就是sdio,没响应就往下走
发送cmd1,如果有响应就是mmc,如果没响应就是sd

卡插入中断后的处理:
s3cmci,c中的s3cmci_irq_cd()==>>mmc_detect_change()==>>host->detect()==>>mmc_detect()
这里的s3cmci_irq_cd()是sd卡插入检测脚cd的中断处理函数

mmc/sd 在 2.6.27 2440

让板子能识别热插拔的卡。正好手上MMC卡和SD卡都有,能用

1. 先加上sdi的platform_device, s3c_device_sdi
arch/arm/mach-s3c2440/mach-smdk2440.c
static struct platform_device *smdk2440_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c,
&s3c_device_iis,
//zhourr
&s3c_device_adc,
&s3c_device_sdi,
};

2. 添加自己板子特别的地方,比如卡接的中断脚,卡插入检测脚,卡写保护脚,检测和写保护脚的极性,提供的sd卡电压范围
static struct s3c24xx_mci_pdata s3cmci_def_pdata = {
/* This is currently here to avoid a number of if (host->pdata)
* checks. Any zero fields to ensure reaonable defaults are picked. */
//zhourr
.wprotect_invert = 0,
.detect_invert = 0,
.gpio_detect = S3C2410_GPG8,
.gpio_wprotect = S3C2410_GPH8,
.ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34,
.set_power = NULL,
};

此时MMC卡已经可以热插拔,并在dev下找到mmcblk0

# ls -l /dev/mmc*
brw-rw---- 1 0 0 179, 0 Jan 1 00:03 /dev/mmcblk0

但是SD卡系统启动前正常,热插拔插入时会有timeout错误
错误1:
s3c2440-sdi s3c2440-sdi: mci_setup_data() transfer stillin progress.
s3c2440-sdi s3c2440-sdi: CMDSTAT: error CMDTIMEOUT
s3c2440-sdi s3c2440-sdi: CMD[ERR -110] #47 op:6 arg:0x00fffff1 flags:0x08b5 retries:0 Status:nothing to complete
s3c2440-sdi s3c2440-sdi: DAT[OK] #4 bsize:64 blocks:1 bytes:64
s3c2440-sdi s3c2440-sdi: powered down.
mmc0: error -110 whilst initialising SD card

错误2:
s3c2440-sdi s3c2440-sdi: unfinished read - pio_count:[0] pio_words:[16]
s3c2440-sdi s3c2440-sdi: CMD[OK] #68 op:6 arg:0x00fffff1 flags:0x08b5 retries:0 R0:0x00000900
s3c2440-sdi s3c2440-sdi: DAT[ERR -22] #6 bsize:64 blocks:1 bytes:64 DCNT:0x00000000
mmc0: problem reading switch capabilities, performance might suffer.

3.解决SD插入错误-->加延时
driver/mmc/core/sd.c 的mmc_sd_init_card()函数中mmc_read_switch前延时10ms

mdelay(10);

err = mmc_read_switch(card);

查看插入后的设备
# ls -l /dev/mmc*
brw-rw---- 1 0 0 179, 0 Jan 1 00:04 /dev/mmcblk0
brw-rw---- 1 0 0 179, 1 Jan 1 00:04 /dev/mmcblk0p1

mount后使用卡,可读写
# mount -t vfat /dev/mmcblk0p1 /opt/

写完后自己sync一下,确保写进去了,PC上就可以看到了


4.有个问题:
如果拔出太快又插入,现在会当作只拔出了。还不清楚MMC里怎么做的,要看一下了

2008年11月26日星期三

cs8900在2440 linux2.6.27

driver/net/cs89x0.c

1.修改ioaddr和irq,接CS3,addr24选择io或memory方式,irq是EINT9,GPG1,写网卡MAC地址
#include "../../arch/arm/mach-s3c2410/include/mach/map.h"
#include "../../arch/arm/mach-s3c2410/include/mach/regs-mem.h"
#include "../../arch/arm/mach-s3c2410/include/mach/regs-gpio.h"
#include "../../arch/arm/mach-s3c2410/include/mach/regs-irq.h"
static unsigned int netcard_portlist[] __used __initdata = { S3C24XX_VA_CS8900_CS3 + 0x300, 0};
static unsigned int cs8900_irq_map[] = {IRQ_EINT9,0,0,0};

2.添加2440硬件初始化函数
static void cs89x0_hw_setup(struct net_device *dev)
{
unsigned int regval = 0;

//CS3, 16 bit bus width
__raw_writel(0x2211d110,S3C2410_BWSCON);
__raw_writel(0x1f7c,S3C2410_BANKCON3);

//EINT[9]
regval = __raw_readl(S3C2410_GPGCON);
regval &= ~(3<<2);
regval |= 2 <<2;
__raw_writel(regval, S3C2410_GPGCON);

//irq mode
regval = __raw_readl(S3C2410_EXTINT1);
regval &= ~(7<<4);
regval |= 4 <<4;
__raw_writel(regval, S3C2410_EXTINT1);

//irq MASK
regval = __raw_readl(S3C2410_EINTMASK);
regval &= ~(1<<9);
__raw_writel(regval, S3C2410_EINTMASK);

//mac addr
dev->dev_addr[0] = 0x00;
dev->dev_addr[1] = 0x00;
dev->dev_addr[2] = 0xc0;
dev->dev_addr[3] = 0xff;
dev->dev_addr[4] = 0xee;
dev->dev_addr[5] = 0x08;

printk("[cs89x0_probe] S3C2410_BWSCON = %x\r\n", __raw_readl(S3C2410_BWSCON));
printk("[cs89x0_probe] S3C2410_BANKCON3 = %x\r\n", __raw_readl(S3C2410_BANKCON3));
printk("[cs89x0_probe] S3C2410_GPGCON = %x\r\n", __raw_readl(S3C2410_GPGCON));
printk("[cs89x0_probe] S3C2410_EXTINT1 = %x\r\n", __raw_readl(S3C2410_EXTINT1));
printk("[cs89x0_probe] S3C2410_EINTMASK = %x\r\n", __raw_readl(S3C2410_EINTMASK));
printk("[cs89x0_probe] MAC ADDR: %x-%x-%x-%x-%x-%x\r\n",
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);

}

3.在cs89x0_probe里调用cs89x0_hw_setup函数

cs89x0_hw_setup(dev);

if (net_debug)
printk("cs89x0:cs89x0_probe(0x%x)\n", io);

4.修改readword,writeword函数,portno不需要左移(我现在怎么看着不需要了啊,好像else里的也没有左移)

static u16
readword(unsigned long base_addr, int portno)
{
return __raw_readw(base_addr+portno);
}

static void
writeword(unsigned long base_addr, int portno,u16 value)
{
__raw_writew(value,base_addr+portno);
}

5.设置网口RJ45,省去boot启动时带参数
lp->force = g_cs89x0_media__force;
改成
lp->force=FORCE_RJ45;

6.注释掉irq_map的安全检查
#if 0
if (((1 <<>irq) & lp->irq_map) == 0) {
printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
dev->name, dev->irq, lp->irq_map);
ret = -EAGAIN;
goto bad_out;
}
#endif

7.2440初始化时增加分配cs8900的io port,修改mach-smdk2440.c

static struct map_desc smdk2440_iodesc[] __initdata = {
/* ISA IO Space map (memory space selected by A24) */

{
.virtual = (u32)S3C24XX_VA_ISA_WORD,
.pfn = __phys_to_pfn(S3C2410_CS2),
.length = 0x10000,
.type = MT_DEVICE,
}, {
.virtual = (u32)S3C24XX_VA_ISA_WORD + 0x10000,
.pfn = __phys_to_pfn(S3C2410_CS2 + (1<<24)),
.length = SZ_4M,
.type = MT_DEVICE,
}, {
.virtual = (u32)S3C24XX_VA_ISA_BYTE,
.pfn = __phys_to_pfn(S3C2410_CS2),
.length = 0x10000,
.type = MT_DEVICE,
}, {
.virtual = (u32)S3C24XX_VA_ISA_BYTE + 0x10000,
.pfn = __phys_to_pfn(S3C2410_CS2 + (1<<24)),
.length = SZ_4M,
.type = MT_DEVICE,
}, { //zhourr
.virtual = (u32)S3C24XX_VA_CS8900_CS3,
.pfn = __phys_to_pfn(S3C2410_CS3 + (1<<24)),
.length = SZ_1M,
.type = MT_DEVICE,
}
};

8.在arch/arm/mach-s3c2410/include/mach/map.h增加宏定义,跟别的不冲突就行了
#define S3C24XX_VA_CS8900_CS3 S3C2410_ADDR(0x04000000)

2008年11月20日星期四

sh下运行#!/bin/bash开头的脚本会返回not found

inittab脚本:
::sysinit:/etc/rc.sysinit
::respawn:-/bin/sh
::once:/bin/mount -a
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
::shutdown

我在/etc/inittab里想执行/etc/rc.sysinit脚本失败,提示是:
cannot run '/etc/rc.sysinit': No such file or directory

单独在sh里敲提示not found
# /etc/rc.sysinit
-/bin/sh: /etc/rc.sysinit: not found

但是source就可以执行
# source /etc/rc.sysinit
starting udevd...

我以为是没有执行属性,还是不行
chmod 777 /etc/rc.sysinit

网上说sh /etc/rc.sysinit,我就改inittab第一行为:
::sysinit:/bin/sh /etc/rc.sysinit
这样脚本就可以执行了,

但是脚本里udevd失败,报错:
starting udevd...
udevd[824]: main: error disabling OOM: No such file or directory

后来发现我的rc.sysinit脚本前用的是#!/bin/bash,改为#!/bin/sh,又把inittab第一行恢复原样
这样rc.sysinit就可以找到并执行了

但是udevd还是报错,根据启动打印sysinit第一个执行,我想把它放到mount -a的后面,于是把第一行放到了第三行后面
::respawn:-/bin/sh
::once:/bin/mount -a
::sysinit:/etc/rc.sysinit
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
::shutdown
但是它还是第一个执行

我猜是::sysinit:使它第一个执行的,改为::once:
udevd就好了

2008年11月17日星期一

2440 2.6.27启动后主频405Mhz却打印出来是571Mhz

2.6.27
网上有人一样是启动时乱码,他说修改时钟频率为12M就可以了,我的板子本来就是12M晶振
我是临时通过屏蔽内核串口设置来去掉乱码的,下面有正确做法
drivers/serial/samsung.c中8个wr_regl 函数屏蔽掉
core 571.536 MHz,确实是主时钟错了,有点离谱,bootloader里的时钟是405M,启动后不修改uart设置,能正常显示打印,说明这时时钟还是405MHZ。虽然是主频导致uart计算波特率的divider出错导致的乱码,但是为什么会到571Mhz呢?

这样我启动后看到的打印是:
enter Main
cp15 register 1 = c000107c
************************************
* *
* 2440 bootloader *
* Nov 17 2008,11:22:08 *
* *
************************************
Read chip id = ec76
Nand flash status = c0
NAND_Read addr : 40000, size : 1c0000
................................................................................................................Uncompressing Linux.................................................................................................................. done, booting the kernel.
Linux version 2.6.27 (root@sherman_samba) (gcc version 3.4.1) #4 Tue Nov 18 11:51:27 CST 2008
CPU: ARM920T [41129200] revision 0 (ARMv4T), cr=c0007177
Machine: SMDK2440
ATAG_INITRD is deprecated; please update your bootloader.
Memory policy: ECC disabled, Data cache writeback
CPU S3C2440A (id 0x32440001)
S3C244X: core 571.536 MHz, memory 142.884 MHz, peripheral 71.442 MHz
S3C24XX Clocks, (c) 2004 Simtec Electronics
CLOCK: Slow mode (2.116 MHz), fast, MPLL on, UPLL on
CPU0: D VIVT write-back cache
CPU0: I cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets
CPU0: D cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets
Built 1 zonelists in Zone order, mobility grouping on. Total pages: 16256
Kernel command line: noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0,115200
irq: clearing subpending status 00000092
PID hash table entries: 256 (order: 8, 1024 bytes)
timer tcon=00000000, tcnt e88e, tcfg 00000200,00000000, usec 00001580
Console: colour dummy device 80x30
console [ttySAC0] enabled
Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
Memory: 64MB = 64MB total
Memory: 61120KB available (3256K code, 322K data, 144K init)
Calibrating delay loop... 285.08 BogoMIPS (lpj=712704)
Mount-cache hash table entries: 512
CPU: Testing write buffer coherency: ok
net_namespace: 440 bytes
NET: Registered protocol family 16
S3C2410 Power Management, (c) 2004 Simtec Electronics
S3C2440: Initialising architecture
S3C2440: IRQ Support
S3C24XX DMA Driver, (c) 2003-2004,2006 Simtec Electronics
DMA channel 0 at c4800000, irq 33
DMA channel 1 at c4800040, irq 34
DMA channel 2 at c4800080, irq 35
DMA channel 3 at c48000c0, irq 36
S3C244X: Clock Support, DVS off
SCSI subsystem initialized
usbcore: registered new interface driver usbfs
usbcore: registered new interface driver hub
usbcore: registered new device driver usb
NET: Registered protocol family 2
IP route cache hash table entries: 1024 (order: 0, 4096 bytes)
TCP established hash table entries: 2048 (order: 2, 16384 bytes)
TCP bind hash table entries: 2048 (order: 1, 8192 bytes)
TCP: Hash tables configured (established 2048 bind 2048)
TCP reno registered
NET: Registered protocol family 1
NetWinder Floating Point Emulator V0.97 (extended precision)
JFFS2 version 2.2. (NAND) (SUMMARY) © 2001-2006 Red Hat, Inc.
msgmni has been set to 119
io scheduler noop registered
io scheduler anticipatory registered (default)
io scheduler deadline registered
io scheduler cfq registered
Console: switching to colour frame buffer device 30x40
fb0: s3c2410fb frame buffer device
lp: driver loaded but no devices found
ppdev: user-space parallel port driver
Serial: 8250/16550 driver4 ports, IRQ sharing enabled
s3c2440-uart.0: s3c2410_serial0 at MMIO 0x50000000 (irq = 70) is a S3C2440
s3c2440-uart.1: s3c2410_serial1 at MMIO 0x50004000 (irq = 73) is a S3C2440
s3c2440-uart.2: s3c2410_serial2 at MMIO 0x50008000 (irq = 76) is a S3C2440
brd: module loaded
loop: module loaded
dm9000 Ethernet Driver, V1.31
Uniform Multi-Platform E-IDE driver
Driver 'sd' needs updating - please use bus_type methods
S3C24XX NAND Driver, (c) 2004 Simtec Electronics
60 ns is too big for current clock rate 142884
s3c2440-nand s3c2440-nand: cannot get suitable timings
s3c2440-nand: probe of s3c2440-nand failed with error -22
usbmon: debugfs is not available
s3c2410-ohci s3c2410-ohci: S3C24XX OHCI
s3c2410-ohci s3c2410-ohci: new USB bus registered, assigned bus number 1
s3c2410-ohci s3c2410-ohci: irq 42, io mem 0x49000000
usb usb1: configuration #1 chosen from 1 choice
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 2 ports detected
usbcore: registered new interface driver libusual
usbcore: registered new interface driver usbserial
usbserial: USB Serial support registered for generic
usbcore: registered new interface driver usbserial_generic
usbserial: USB Serial Driver core
usbserial: USB Serial support registered for FTDI USB Serial Device
usbcore: registered new interface driver ftdi_sio
ftdi_sio: v1.4.3:USB FTDI Serial Converters Driver
usbserial: USB Serial support registered for pl2303
usbcore: registered new interface driver pl2303
pl2303: Prolific PL2303 USB to serial adaptor driver
mice: PS/2 mouse device common for all mice
S3C24XX RTC, (c) 2004,2006 Simtec Electronics
s3c2440-i2c s3c2440-i2c: slave address 0x10
s3c2440-i2c s3c2440-i2c: bus frequency set to 372 KHz
s3c2440-i2c s3c2440-i2c: i2c-0: S3C I2C adapter
S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics
s3c2410-wdt s3c2410-wdt: watchdog inactive, reset disabled, irq enabled
TCP cubic registered
NET: Registered protocol family 17
RPC: Registered udp transport module.
RPC: Registered tcp transport module.
drivers/rtc/hctosys.c: unable to open rtc device (rtc0)
Root-NFS: No NFS server available, giving up.
VFS: Unable to mount root fs via NFS, trying floppy.
VFS: Cannot open root device "mtdblock2" or unknown-block(2,0)
Please append a correct "root=" boot option; here are the available partitions:
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(2,0)
========================
时钟不对,连nand都不能正常操作
------->>>>
s3c244x.c s3c244x_init_clocks
------->>>>
cpu.c static struct cpu_table cpu_ids[] __initdata
------->>>>
cpu.c s3c24xx_init_clocks
------->>>>
mach-smdk2440.c smdk2440_map_io
该函数中带了时钟输入参数
s3c24xx_init_clocks(16934400);
因为我们用的晶振是12M的,所以需要改成下面这样
s3c24xx_init_clocks(12000000);

这样串口也正常了,时钟也对了,nand也对了

2008年11月13日星期四

动态中断向量

ResetEntry
b ResetHandler
b Undefined_Handler
b SWI_Handler
b Prefetch_Handler
b Abort_Handler
nop
ldr pc, =0x300ffffc
b FIQ_Handler

//0x18 = jump to 0x300ffffc
//0x300ffffc = jump to IsrHandler
//b arm, ea000006 = 6 <<2 +8 + pc
//b code, (dst - src -8) >>2 +0xea000000
void RegInterrupteHandlerTable(void)
{
unsigned long dest_addr = (unsigned long)IsrHandler;
unsigned long offset_addr ;
unsigned long *pIrqHandler = (unsigned long *)0x300ffffc;

offset_addr = (((dest_addr - (unsigned long)pIrqHandler - 8)) >> 2)&0xffffff;

*pIrqHandler = 0xea000000+offset_addr;
}

以前把整个表做重新做动态了,没必要,现在就修改irq这一条,而且思路比以前清晰

0x18地址存放的指令是 pc=0x300ffffc
0x300ffffc地址存放的指令是 b IsrHandler,是做出来的指令

拿一般第一条指令的机器码来说,一般是b resethandler
0地址机器码 :0xea000006
resethandler函数地址 0x20

0 + 6 << 2 +8 = 0x20,这样就会跳转到resethandler函数的地址了

2008年11月4日星期二

-/bin/sh: XXX: not found

# ./qpe
-/bin/sh: ./qpe: not found

shell找不到该文件,及刚启动完打印的找不到/etc/rc.sysinit文件同样的现象

网上有人说是busybox静态编译改成动态编译就可以了,我改了,真的可以了
库文件当然用的是编译器里的*.so文件拷贝到根文件系统/lib下

在Fedora7上编译qtopia-2.2.0 x86版

1>下载gcc32编译器
http://d.download.csdn.net/down/382229/morre
compat-gcc-32-3.2.3-47.3.i386.rpm

http://d.download.csdn.net/down/382235/morre
compat-gcc-32-c++-3.2.3-47.3.i386.rpm

当时没有用rpm命令行安装,是firefox下载后点“打开”,弹出更新软件,点“应用”这样装的
应该怎么安装都行吧。安装完后,出现/usr/bin/gcc32等。有人说改Makefile或设置CC环境变量,我觉得可能会改不全,所以换gcc,下面这样改不确定对不对,不过以前gcc4.1.2编不过的现在可以编过了

//替换gcc
mv /usr/bin/gcc /usr/bin/gccbak
mv /usr/bin/gcc32 /usr/bin/gcc

//替换g++
mv /usr/bin/g++ /usr/bin/g++bak
mv /usr/bin/g++32 /usr/bin/g++

//替换libc
cp /usr/lib/gcc/i386-redhat-linux/4.1.2 /usr/lib/gcc/i386-redhat-linux/4.1.2bak -rf
cp /usr/lib/gcc-lib/i386-redhat-linux/3.2.3 /* /usr/lib/gcc/i386-redhat-linux/4.1.2/ -rf

2>下载freetype2.1.10
http://download.chinaunix.net/download.php?id=6228&ResourceID=3295
freetype-2.1.10.tar.bz2

解压后
./configure --prefix=/usr
make
make install
mv /usr/freetype2/freetype /usr/freetype2/freetypebak //不用以前的freetype 头文件
cp freetype-2.1.10/include/freetype /usr/freetype2/ -rf //既然只是新的头文件,那么是不是不用编译呢?

3>编译qtopia-2.2.0
./configure
make
make install

4>跑demo
. setQpeEnv
qtopia/bin/startdemo

2008年11月1日星期六

删除libstdc++后缺少libstdc++.so.6库导致很多命令执行不了

fedora7想把gcc4.1.2替换成gcc3.2.2, 所以下载了cpp-3.2.2-5.i386.rpm, gcc-3.2.2-5.i386.rpm等包,但在安装时提示已经有更新的版本,所以先删除新版本再装旧版本,更换cpp和gcc时未出问题,更换libstdc++出问题了
rpm -e --nodeps libstdc++-4.1.2-12
rpm: error while loading shared libraries: libstdc++.so.6: cannot open shared object file: No such file or directory

rpm -ivh libstdc++-4.1.2-12.i386.rpm
即使再执行rpm把libstdc++安装回来也不行, 因为rpm命令本身需要libstdc++.so.6库, 我有libstdc++.so.5, ln -s不可行。yum install也不能执行了

所以我到另一台机子考了一个libstdc++.so.6过来,放到/usr/lib/下,至少rpm,yum之类的可以用了,再看怎么换gcc,那台考libstdc++.so.6的机子少另一个gcc库,进不了X,都是被我换gcc搞的

2008年10月29日星期三

解决e2fsck版本太低造成的不能启动的问题:fsck.ext3:Filesystem has unsupported feature(s)

我也遇到了这个问题,到网上搜到的下面这个帖子:

转载请注明原创出处:HateMath的网上田园(http://blog.vckbase.com/hatemath/

1. 症状

PC上已经已装有Fedora 4,出于开发需要又装Red ha t 9.
FC4(hda7) & RH9(hda6) 都是ext3 文件格式.
装好后配置启动菜单,然后重启进FC4,正常进入,再重启进RH9,也正常进入.

开始配置RH9,什么系统、网络、程序、多媒体、等等、等等 - --麻烦啊.
折腾好了后,重启,出现错误:
........
checking root filesystem
fsck.ext3:filesystem has unsupported feature(s) (/12)
e2fsck:get a newer version of e2fsck!

2. 解决方法

将Fedora4中的 /sbin/e2fsck 文件拷贝到RedHat9的/sbin/目录下,覆盖原来的(最好备份一下)e2fsck 文件.
重启,一切恢复正常。

3. 探询原因
RedHat9中的e2fsck版本较低。

4.闲聊
你 看,解决方法好简单啊。可是你知道吗,我搞了3个多小时。用关键词“fsck.ext3:Filesystem has unsupported feature(s) ”google到的70多个外文网页,找了几个没合适的,中文的没有。所以,这下你理解我为什么用它做随笔的标题了吧。希望对别人有用。

(完)

======================================

但是我的fc4不在真实物理盘里,是vmware直接打开vmx文件,我在出错后命令行里看到的sda也只看到了它自己的,在根目录下也只搜索到了/sbin/e2fsck,不知道用哪个来替换了。
所以从启动脚本开始出发。看/etc/rc.d/rc.sysinit,在busybox里init命令调用到/etc/inittab会调用到/etc/rc.d/rc.sysinit,在里面搜索fsck的命令在哪里调用,既然是e2fsck版本的问题,只是检查文件系统有没有坏,那么我不要这条了,反正如果e2fsck检查出坏了也只是提示出错,没坏检查不检查不都差不多吗,或者先去掉sysinit里fsck部分,让桌面启动起来,再下载替换掉fsck命令也应该是可以的。

所以我注释了/etc/rc.d/rc.sysinit 第387-429行,也就是执行了fsck命令,但是不处理它的返回值,问题就解决了。
修改脚本前需要把根文件系统设置为rw,不然是readonly
mount -o remount,rw /
修改完后重启

我不明白为什么非物理盘安装的ubuntu会影响到非物理盘安装的FC4
========================================
xiaoshe说看不明白我写的,所以修改一下再写到下面,上面的也不想删了,照别人的板书写

1.症状
PC上用vmware装了FC4,后来又装了一个ubuntu8.04,当我用vmware打开ubuntu以后,以后在想打开FC4就在启动时提示以下错误:
checking root filesystem
fsck.ext3:filesystem has unsupported feature(s) (/12)
e2fsck:get a newer version of e2fsck!

2.解决办法
@ 网上找的办法: HateMath的网上田园(http://blog.vckbase.com/hatemath/)
将Fedora4中的 /sbin/e2fsck 文件拷贝到RedHat9的/sbin/目录下,覆盖原来的(最好备份一下)e2fsck 文件.
重启,一切恢复正常。

@我的办法:
将根文件系统修改为可读写的
mount -o remount,rw /
注释/etc/rc.d/rc.sysinit第387-429行

3. 探询原因
@ 网上找的原因: HateMath的网上田园(http://blog.vckbase.com/hatemath/)
RedHat9中的e2fsck版本较低。
@我的原因:e2fsck如果版本低就不启动

4.思考过程
既然是e2fsck版本的问题,只是检查文件系统有没有坏,那么我不要这条了,反正如果e2fsck检查出坏了也只是提示出错启动失败,没坏检查不检查不都差不多吗,所以我注释了/etc/rc.d/rc.sysinit 第387-429行,也就是执行了fsck命令,但是不处理它的返回值,问题就解决了

2008年10月27日星期一

安装了suse-linux11.0-dvd-x86_64

dvd我以为很全呢,4.3G,结果make都找不到命令,gcc估计都没有
然后从windows用vmware启动suse,结果在找硬盘处出错,网上有类似现象,by-id找不到,修改fstab不起作用,因为在fstab前就已经出错了,/dev下无sda*设备
我就又下载了fedora9,装3系统,真废时间

suse我觉得挺漂亮的,就是不会用,比fedora难操作

2008年10月24日星期五

编译busybox1.12.1和uboot1.1.6

原本编译器是arm-linux-3.4.1

下载uboot1.1.6后编译出错,网上说因为编译器不支持softfloat
lib_arm/libarm.a(_udivsi3.o)(.text+0x8c):/home/gongh/2440/u-boot-1.1.6/lib_arm/_udivsi3.S:67: relocation truncated to fit: R_ARM_PLT32 __div0
lib_arm/libarm.a(_umodsi3.o)(.text+0xa8):/home/gongh/2440/u-boot-1.1.6/lib_arm/_umodsi3.S:79: relocation truncated to fit: R_ARM_PLT32 __div0
make: *** [u-boot] Error 1

下载busybox1.12.1后编译出错,一般我都是哪个命令出错就去掉哪个命令,有inotifyd,taskset,然后是networking/interface.c出错,网络功能不能去掉,所以这个必须要编译过,这时我脑子是呆的,把uboot的softfloat对应到了busybox编译不过,所以我打算做一个交叉编译工具
networking/interface.c:818: error: `ARPHRD_INFINIBAND' undeclared here (not in a function)
networking/interface.c:818: error: initializer element is not constant
networking/interface.c:818: error: (near initialization for `ib_hwtype.type')
networking/interface.c:818: error: `ARPHRD_INFINIBAND' undeclared here (not in a function)
networking/interface.c:818: error: initializer element is not constant
networking/interface.c:818: error: (near initialization for `ib_hwtype.type')

下载crosstool-0.43
http://kegel.com/crosstool/crosstool-0.43.tar.gz

1>用非root用户登录,如果以root登录会提示这样太危险
2>建立目录/opt/crosstool,修改属性,编译时会建立这个目录,需要有权限
sudo mkdir /opt/crosstool
sudo chown $USER /opt/crosstool
3>./demo-arm-softfloat.sh,下载需要的源码并编译,虚拟机花了100分钟

然后用新的编译器gcc-3.4.5-glibc-2.3.6编译busybox的network就通过了,uboot1.1.6也通过了

2008年10月19日星期日

周日买了一台新电脑

现在电脑便宜多了。配置我说不清
CPU : amd 64位双核5000 2.5G
DDR : 2G
硬盘 : 160G
显示屏 : 20寸
一个音箱, 一个蓝牙适配器
加一个正方形电脑桌,花了3088,很久没了解市场了,至少比我预期的便宜

2008年10月16日星期四

在这里做几道题,我觉得我思路比较窄1

大学没好好上数学建模的选修,现在想自学一下,matlab还在下载,在这里做第2章19大题

19.对下面的问题列出问题表,并试图为这些问题寻求合理的解答

(a)需要一部新的电视,是买一部好还是租好?

1)问题Q:
a买的租的质量差别是否无所谓
b总共需要用多少年

2)因素F:
a新电视的价钱 输入变量 N
b租电视一年的价钱 输入变量 O
c总共需要用多少年 输入变量 T
d租的电视质量和折旧有多少 参数 A

3)假设A:新电视和租电视到家以后不会在需要它的期间内坏

4)对问题的描述P:
新电视价钱相当于租电视多少年?比打算用的年数大还是小?
租价钱:O*T+A 买电视N,比较 O*T+A 与N的大小

5)进一步考虑:
a租电视是否会因为时间越长而年租价越低
b新电视是否有促销活动
c如果电视会坏,新电视和租电视坏的概率又有多少,及新电视和租电视保修期有多久,维修费多少

=========================

(b)为长时间保存而购买冷冻食品合不合算?

1)问题Q:
a长时间保存是为了持续长时间有食品吃,还是隔一段时间后有食品吃
b超市离家的距离,改为购买常规食品的,购买频率

2)因素F:
a冷冻食品的保质期 参数 L
b每天需要的食品量 输入参数 n
c冷冻食品的价钱 输入参数 p1
d常规食品的价钱 输入参数 p2
e常规食品每日需求量 输入参数 t1
f常规食品保质期 参数 t2
g每次购买常规食品所需额外费用 参数 x
h总共需要度过的天数 参数 d

3)假设A:为了保证每天有食品吃的情况,d天内冷冻食品不过期

4)描述P:
d天内常规食品消费:(d/t2)*x + p2*n*d
d天内冷冻食品消费:p1*n*d
比较一下费用差别

5)进一步思考:
a对冷冻食品和常规食品每日需求量是否一样

2008年10月12日星期日

patch

以前有服务器,大家修改代码就合到svn里,现在没别人管内核了,所以我打一个patch
参考网页:
http://wordpad.blog.sohu.com/50009831.html
http://linux.chinaunix.net/bbs/viewthread.php?tid=615467
http://www-128.ibm.com/developerworks/cn/linux/l-diffp/index.html

1 清空新kernel多余文件
make mrproper
2 到内核根目录上一级生成patch
[root@sherman_samba kernel]#diff -Nur linux-2.6.14.4/ /home/gongh/now/t30x/src/kernel/linux-2.6.14.4/ > /home/gongh/1404patch
3 打上patch
[root@sherman_samba kernel]# patch -p0 < /home/gongh/1404patch

记一下,以后就不到网上搜了

添加config文件

以前的项目是通过load config和save config来配置。现在想把config文件放到arch/mips/config下,我把文件t30x_gpioi2c_config放在该目录下,执行make t30x_gpioi2c_config

[root@sherman_samba linux-2.6.14.4]# make t30x_gpioi2c_config
make[1]: *** No rule to make target `t30x_gpioi2c_config'. Stop.
make: *** [t30x_gpioi2c_config] Error 2

没有这个目标,然后看根目录的Makefile,有这么一段
# Brief documentation of the typical targets used
# ---------------------------------------------------------------------------

boards := $(wildcard $(srctree)/arch/$(ARCH)/configs/*_defconfig)
boards := $(notdir $(boards))

所以它需要新的config文件是以_defconfig为结尾的,所以修改 t30x_gpioi2c_config为 t30x_gpioi2c_defconfig就可以了

2008年10月8日星期三

半透明实现

GrCopyArea nanox中很多场景都需要拷贝区域,最后一直走到memmove真实的内存拷贝
|----GdBlit
|----|----dstpsd->Blit 这里的psd根绝scr_xxx.c决定哪个SUBDRIVER
|----|----|----linear24_blit 在scr_fb.c中的fb_open函数会调用fb.c中的select_fb_subdriver,根据屏每个像素占几位来确定Blit函数,如果是24位,SUBDRIVER就是fblinear24,由此确定dstpsd->Blit函数是linear24_blit
|----|----|----|----memmove

static void
linear24_blit(PSD dstpsd, MWCOORD dstx, MWCOORD dsty, MWCOORD w, MWCOORD h, PSD srcpsd, MWCOORD srcx, MWCOORD srcy, long op)
透明处理是下面这一段
alpha = op & 0xff;

while(--h >= 0) {
for(i=0; i < w; ++i) {
unsigned long s = *src++;
unsigned long d = *dst;

*dst++ = (unsigned char)(((s - d)*alpha)>>8) + d;
s = *src++;
d = *dst;
*dst++ = (unsigned char)(((s - d)*alpha)>>8) + d;
s = *src++;
d = *dst;
*dst++ = (unsigned char)(((s - d)*alpha)>>8) + d;
}
dst += dlinelen_minus_w;
src += slinelen_minus_w;
}

既然要透明也就是要2个图片一起显示,走下来也就是2个点一起显示。
这里有src和dst点,dst是背景,src是显示在上面的图片,该Blit拷贝函数需要把src图片拷贝到dst背景上。分别用3条语句把RGB红绿蓝分开来做计算。
op是传进来的透明参数,原本应该是0-1的透明范围,为了避免浮点运算,alpha范围是0-0xff,计算后右移8位。
就看蓝色这一条:
当alpha为0xff时,显示的完全是s,也就是不透明,把src拷贝到dst了
当alpha为0时,显示的完全是d,也就是完全透明,只能看到dst背景图片
当alpha取中间值时,就是半透明了,还是蛮容易的吧。值越大越不透明

nanox GsSelect函数记一下

GsSelect 获得nanox事件
|----select 同时select 2个文件描述符(鼠标,按键)
|----if((e > 0) 如果select有数据
|----|----GsCheckMouseEvent 获得鼠标事件
|----|----|----devmouse.c GdReadMouse 配置了鼠标或触摸屏
|----|----|----|----mousedev.Read 调用鼠标驱动读函数读数据,如果是transform模式则转换为lcd点再返回,如果是raw模式则直接返回数据
|----|----|----devnomouse.c GdReadMouse 未配置鼠标,直接返回x y为0的数据
|----|----GsCheckKeyboardEvent 获得键盘事件
|----|----|----GdReadKeyboard 调用devkbd.c读取键盘消息
|----|----|----|----kbddev.Read 读取键盘消息
|----|----GsDeliverKeyboardEvent 根据键值发送pen down/up事件
|----else if (e == 0) 如果select无数据
|----|----GdTimeout timeout返回
|----else if ( e < 0 ) 如果select出错,打印错误返回


说一下GsSelect的fd与select
/* Set up the FDs for use in the main select(): */
FD_ZERO(&rfds);
if(mouse_fd >= 0) {
FD_SET(mouse_fd, &rfds);
if (mouse_fd > setsize)
setsize = mouse_fd;
}
if(keyb_fd >= 0) {
FD_SET(keyb_fd, &rfds);
if (keyb_fd > setsize)
setsize = keyb_fd;

先将rfds清零,把mouse_fd和keyb_fd设置到rfds的某一位上,原本我不知道file descriptor怎样分配了,看了一下,结果fd是一个文件描述符表的索引,所以是个很小的正整数。这样FD_SET某一位时也不会重复

select(setsize+1, &rfds, NULL, NULL, to)

select同时作用到2个fd上,setsize是mouse_fd和keyb_fd中最大的一个加1,rfds里又有mouse和key的2位置1,这样内核sys_select里实现是有个for循环,会把mouse和key的poll都调用到,而不是我以前所理解的,一个select对应一个poll,而是一对多的关系。setsize加1是因为do_select 循环里用的是i < n,所以要执行到n传进去的数要加1

要看fd可以看sys_close(unsigned int fd)
struct fdtable *fdt;
fdt->fd[fd],数组下标就是fd

struct fdtable {
unsigned int max_fds;
int max_fdset;
int next_fd;
struct file ** fd; /* current fd array */
fd_set *close_on_exec;
fd_set *open_fds;
struct rcu_head rcu;
struct files_struct *free_files;
struct fdtable *next;
};

2008年10月7日星期二

nanox注释一下srvfunc.c的window方面函数

nanox的open,close,mainloop有了,然后就是它提供的画图函数了。先只看link to app的情况,主要文件是nanox/srvfunc.c,那么注释一下该文件主要函数window方面的

GrNewWindow 新建一个window
|--GsFindWindow 根据父window id找到父window的handle
|--NewWindow 在父window上建立一个新window
|--|--malloc(sizeof(GR_WINDOW)) 分配新window结构空间
|--|--window.*=* 为新window结构体赋初值

GrNewInputWindow 新建一个input window
它与GrNewWindow的差别是
GrNewWindow :window->output = GR_TRUE
GrNewInputWindow :window->output = GR_FALSE

GrNewPixmap 新建一个pixmap,通常是为画一张图片准备的一块区域,pix就是pixel(点)
|--rootwp->psd->AllocateMemGC(rootwp->psd); 根据root window的屏设备指针分配一个新的屏设备结构 typedef struct _mwscreendevice *PSD;
|--malloc(sizeof(GR_PIXMAP)); 分配pixmap结构空间
|--GdCalcMemGCAlloc 根据要分配的pixmap宽高计算出分配的实际空间,所以需要用到屏设备的参数确定一个点要分配多少字节size
|--calloc(size, 1); 分配size的空间
|--pp->psd = psd; 把psd挂在当前pixmap下
|-- psd->MapMemGC 初始化这块mem,并把画图函数指针挂进来

GrMapWindow 显示一个window
|--GsFindWindow id转换为handle
|--GsWpRealizeWindow 让window和它的子window可视
|--|--GsDeliverUpdateEvent(wp, GR_UPDATE_MAP... 发送更新map事件
|--|--if (!wp->mapped ... 如果是unmap就返回
|--|--if (wp->output) 如果不是inputwindow就显示
|--|--|--GsDrawBorder 画window边框
|--|--|--GsWpClearWindow 刷新window内部
|--|--|--|--GsSetClipWindow 判断该window刷新的部分有没有超过父window,超过就不刷新
|--|--|--|--GsWpDrawBackgroundPixmap 如果有背景pixmap就刷新
|--|--|--|--GdFillRect 如果没有背景pixmap就刷新background color
|--|--|--|--不需要刷背景就不刷
|--|--|--|--GsDeliverExposureEvent 有必要就发送exposure刷新事件
|--|--for (wp = wp->children ... GsWpRealizeWindow 递归调用将子window也刷新

GrUnmapWindow 隐藏一个window
它与GrMapWindow的差别是
GrMapWindow:wp->mapped = GR_TRUE;
GrUnmapWindow :wp->mapped = GR_FALSE;
wp->mapped = GR_TRUE;

GrMoveWindow 移动window
|--GsFindWindow id转换为handle
|--if (wp->mapped && wp == wp->parent->children && wp->parent->id == GR_ROOT_WINDOW_ID && !wp->clipregion) 如果该window可视,父window是root window,不在刷不到的区域那么刷局部
|--|--GrNewPixmap 临时新建一个pixmap为了存放window内容
|--|--GrCopyArea 把当前window内容拷贝到pixmap里
|--|--OffsetWindow 根据offset计算出新window坐标
|--|--GrCopyArea 把存放了老window内容的pixmap拷贝到新window坐标地点
|--|--GsExposeArea 刷新新老window并集的矩形区域
|--|--GrDestroyWindow 销毁临时建立的pixmap
|--|--DeliverUpdateMoveEventAndChildren 发送更新移动事件
|--else 刷整个屏
|--|--GsWpUnrealizeWindow 隐藏该window
|--|--OffsetWindow 根据offset计算出新window坐标
|--|--GsWpRealizeWindow 显示新window
|--|--DeliverUpdateMoveEventAndChildren 发送更新移动事件

GrRaiseWindow 让当前窗口显示在最上面
|--GsFindWindow id转换为handle
|-- if (wp->parent->children == wp) 如果该窗口已经在最上面就返回,wp->parent->children存放的是父window中最上面的子window
|--GsCheckOverlap 如果该窗口还有兄弟窗口,就检查兄弟窗口是否覆盖住了该窗口
|--wp->parent->children = wp; 该窗口为父窗口最上面的window
|--if (overlap) 如果有覆盖就刷新
|--|--GsDrawBorder 画window边框
|--|--GsExposeArea 更新该window的整块区域

GrLowerWindow 让当前窗口显示在最下面
|--GsFindWindow id转换为handle
|--if (wp->siblings == NULL) 如果没有兄弟窗口,那么也就没有最上最下的说法了,返回
|--if (prevwp == wp) wp->parent->children = wp->siblings; 如果当前窗口在最上面就让它的兄弟窗口显示在最上面
|--while (expwp && (expwp != wp)) ... expwp = expwp->siblings; 循环整个兄弟窗口链表找到兄弟窗口计算重叠区域并刷新,siblings是一个兄弟窗口链表
|--|--GsCheckOverlap 计算窗口与它的下一个兄弟窗口的重叠区域
|--|--GsExposeArea 刷新当前窗口,当while循环后当前窗口为它下一个兄弟窗口时就会刷新它的兄弟窗口,所以一个个刷,第一个刷的是自己,所以自己才能是最下面一层的窗口

GrDestroyWindow 销毁一个窗口或pixmap
|--GsFindWindow id转换为handle
|--if (wp) 如果是GsFindWindow返回不为0就是window
|--|--GsWpDestroyWindow 那么销毁window
|--|--|--GsWpUnrealizeWindow 如果该window在显示,先隐藏
|--|--|--GsDeliverUpdateEvent 发送更新事件
|--|--|--while (wp->children) GsWpDestroyWindow(wp->children); 递归销毁子窗口
|--|--|--该free的free,该清零的清零
|--else 如果是GsFindWindow返回为0就是pixmap
|--|--GsFindPixmap id转换为handle
|--|-- free pixmap那块区域,free pixmap结构体,free当初建立的psd

GrKillWindow 将当前window所属的client销毁或nanox server终止
|--GsFindWindow id转换为handle
|--GsClose(wp->owner->id) 根据client id销毁当前client在server中的连接
|--|--#if NONETWORK 如果是link app
|--|--|--GsDropClient --connectcount; link app的连接就是1,减一后connectcount为0
|--|--#else 如果是C/S
|--|--|--GsDropClient 销毁client,connectcount减一
|--|--if(!persistent_mode && connectcount == 0) 如果连接数为0,终止nanox server
|--|--|--GsTerminate 终止nanox server
|--|--|--|--#if !NONETWORK 如果是C/S关闭socket
|--|--|--|--|--GsCloseSocket 关闭socket
|--|--|--|--关闭屏,鼠标,键盘
|--|--|--|--exit(0); 退出

在window刷新的时候还有鼠标cursor需要特殊处理,比如移动刷新window时不能把cursor的图片也拷进来了。这个就不写了

2008年10月6日星期一

2008年10月5日星期日

nanox记一下大致的东西

Grxxx函数是C/S中client端调用的函数,在nanox文件夹里,client.c, nxproto.c, srvnet.c, 如果以link app的方式编译而不是C/S,那么srvfunc.c直接取代了client.c和srvnet.c

Gdxxx函数是nanox的核心函数,在engine文件夹里,devarc.c, devclip1.c, devdraw.c, devfont.c, devpoly.c等画图,devmouse.c,devkbd.c等是设备文件的接口,font_pcf.c, font_freetype.c是描述字体的文件格式是什么,如何解析。image_gif.c, image_jpeg.c是图片decode。

Gsxxx函数graphics server,在nanox/serv.h中可看到所有Gs开头函数原型。最重要的就是GsSelect函数,当系统初始化完毕进入主循环时,通过调用GsSelect函数获得按键等外部事件。

区分C/S还是link app to server在Makefile.rules里有一句,如果没定义LINK_APP_INTO_SERVER,那么用socket进行C/S通讯。
ifeq ($(LINK_APP_INTO_SERVER), Y)
DEFINES += -DNONETWORK=1
endif

如果是C/S,那么srvmain.c的main函数是第一个函数,调用GsInitialize初始化,然后进入GsSelect主循环获得外部事件。
/* Attempt to initialise the server*/
if(GsInitialize() < 0)
exit(1);

while(1)
GsSelect(0L);

如果是link app,那么app的main函数是第一个函数。当app调用GrOpen时,就会调用到GsInitialize初始化,之后app的主循环调用GrGetNextEvent函数获得事件并处理
for (;;)
{
GrGetNextEventTimeout(&event,1);
EventProc(&event);//app的事件处理函数
}

nanox记一下目录结构

源码树文件夹注释

configs //一些默认配置选项

demos //测试nanox的应用程序,配置时可选择是否编

drivers //nanox驱动,包括screen,keypad,touchpanel。比如mou_touchscreen.c里建立一个结构体变量 MOUSEDEVICE mousedev,fb开头是怎样画点画线SUBDRIVER,kbd开头是不同键盘KBDDEVICE,mou开头是不同鼠标MOUSEDEVICE。screen开头是不同屏SCREENDEVICE,如果内核提供的接口不同,比如键盘,就建立一个kbd_xxx.c,完成KBDDEVICE结构体里的函数就可以了。
typedef struct _mousedevice {
int (*Open)(struct _mousedevice *);
void (*Close)(void);
int (*GetButtonInfo)(void);
void (*GetDefaultAccel)(int *pscale,int *pthresh);
int (*Read)(MWCOORD *dx,MWCOORD *dy,MWCOORD *dz,int *bp);
int (*Poll)(void); /* not required if have select()*/
int flags; /* raw, normal, transform flags*/
} MOUSEDEVICE;


engine //nanox驱动上面一层
比如devmouse.c调用mousedev.Open(&mousedev)打开mouse设备。以dev开头的是设备相关文件,font开头是画字体的方式,image开头是不同格式的图片

fonts //纯字体数据文件,与此联系的是engine/font_xxx.c。
比如fonts/chinese/gb2312font.c建立了一个字体数组GUO_GB2312_12X12_FONT_BITMAP[],在engine/font_dbcs.c中会调用到unsigned char *src = GUO_GB2312_12X12_FONT_BITMAP + pos + i * 3;,条件是#if HAVE_GB2312_SUPPORT

mwin //microwindows API

nanox //nanox API

[摘]学而不思则罔,思而不学则殆

语出《论语·为政》——子曰:“学而不思则罔,思而不学则殆”。 此句讲学习方法.教人学思结合.只学而不思,人会被知识的表象所蒙蔽而感到迷茫困惑,尽信书不如无书,是为不通;只思而不学,就没有知识的积累,则会因为疑惑流于空想而更加危险,是为不懂。

最近老想到这2句,抄在这里。我感觉我比较偏向于学而不思

2008年9月27日星期六

unaligned.c报错的一个原因

unsigned long val=3;
printk("*val = %x\r\n",&val);
这样就会出现unaligned报错,因为未4字节对齐

2008年9月24日星期三

通过__setup宏解析bootloader传递上来的自定义参数

bootloader参数console=ttyS0,115200 root=/dev/ram rw init=/linuxrc之类的,在此后面再加一条ts=1也就是console=ttyS0,115200 root=/dev/ram rw init=/linuxrc ts=1

在内核里添加ts=对应的handle函数及__setup宏
static int __init ts_setup(char *options)
{
printk("[ts_setup] %s\r\n",options);
return 1;
}
__setup("ts=", ts_setup);

当发现bootloader参数中含有ts=字符串时就调用ts_setup函数,=后的值就是options字符串。这样除了在menuconfig里选编译文件外还可以通过setup来选功能。让我想起了前2天老板叫我用配置文件确定gpio转i2c的io口,我之前用rootfs里的配置文件,现在可以转成用__setup来配置gpio口了。
setup在initcall之前

2008年9月23日星期二

添加自己的i2c adapter (gpio转i2c)

用的这一款CPU没有i2c host,所以gpio模拟i2c,本来一个设备不用做i2c adapter,直接模拟就是了,但是接了3个i2c设备,ts,radio,touchpad,所以要用i2c总线。driver/i2c/下已经有比较成熟的代码了,所以添加我们这款CPU的adapter,然后做设备driver。
i2c通讯方式中有包含bit方式通讯,driver/i2c/algos/i2c-algo-bit.c
需要添加的是i2c-algo-bit.c里的setsda,setscl,getsda,getscl 4个函数

/* --- setting states on the bus with the right timing: --------------- */
#define setsda(adap,val) adap->setsda(adap->data, val)
#define setscl(adap,val) adap->setscl(adap->data, val)
#define getsda(adap) adap->getsda(adap->data)
#define getscl(adap) adap->getscl(adap->data)

做adapter数据结构
struct t30x_gpio_i2c_pins
{
unsigned int scl_gpio;
unsigned int scl_inout;
unsigned int scl_altfunc;
unsigned int sda_gpio;
unsigned int sda_inout;
unsigned int sda_altfunc;
};

struct t30x_gpio_i2c_data
{
struct t30x_gpio_i2c_pins gpio_pins;
struct i2c_adapter adapter;
struct i2c_algo_bit_data algo_data;
};

static struct t30x_gpio_i2c_data t30x_gpio_i2cd =
{
.gpio_pins =
{
.scl_gpio = 0x4,
.scl_inout = 0xff,
.sda_gpio = 0x8,
.sda_inout = 0xff,
},
.adapter =
{
.name = "t302b-gpio-i2c",
.owner = THIS_MODULE,
.id = I2C_HW_B_T30XGPIO,
.retries = 2,
.class = I2C_CLASS_ALL,
},
.algo_data =
{
.setsda = t30x_gpio_bit_setsda,
.setscl = t30x_gpio_bit_setscl,
.getsda = t30x_gpio_bit_getsda,
.getscl = NULL,
.udelay = 10,
.mdelay = 10,
.timeout = 100,
},
};

完成3个函数
static void t30x_gpio_bit_setscl(void *data, int val)
{
struct t30x_gpio_i2c_pins* gdata = (struct t30x_gpio_i2c_pins*)data;
//set output
if(T30X_GPIO_OUTPUT != gdata->scl_inout)
{
writel(readl(GPIO_OE)(gdata->sda_gpio), GPIO_OE);
gdata->scl_inout = T30X_GPIO_OUTPUT;
}
if (val)
writel(gdata->scl_gpio, GPIO_SET);
else
writel(gdata->scl_gpio, GPIO_CLEAR);
}

static void t30x_gpio_bit_setsda(void *data, int val)
{
struct t30x_gpio_i2c_pins* gdata = (struct t30x_gpio_i2c_pins*)data;
//set output
if(T30X_GPIO_OUTPUT != gdata->sda_inout)
{
writel(readl(GPIO_OE)(gdata->sda_gpio), GPIO_OE);
gdata->sda_inout = T30X_GPIO_OUTPUT;
}

if (val)
writel(gdata->sda_gpio, GPIO_SET);
else
writel(gdata->sda_gpio, GPIO_CLEAR);
}

static int t30x_gpio_bit_getsda(void *data)
{
int sda;
struct t30x_gpio_i2c_pins* gdata = (struct t30x_gpio_i2c_pins*)data;
//set input
if(T30X_GPIO_INPUT != gdata->sda_inout)
{
writel(readl(GPIO_OE)&(~(gdata->sda_gpio)), GPIO_OE);
gdata->sda_inout = T30X_GPIO_INPUT;
}
sda = readl(GPIO_LEVEL)&(gdata->sda_gpio);
return sda? 1 : 0;
}

完成gpio初始化函数
static int t30x_gpio_hw_init(void *data)
{
struct t30x_gpio_i2c_pins* gdata = (struct t30x_gpio_i2c_pins*)data;
//altfunc select
writel(readl(GPIO_ALTFUNC_SEL)&(~((gdata->scl_altfunc)(gdata->sda_altfunc))), GPIO_ALTFUNC_SEL);

//disable gpio interrupt mask
writel(readl(GPIO_INT_MASK)((gdata->scl_gpio)(gdata->sda_gpio)), GPIO_INT_MASK);

//set output
writel(readl(GPIO_OE)((gdata->scl_gpio)(gdata->sda_gpio)), GPIO_OE);

//set level high
writel(((gdata->scl_gpio)(gdata->sda_gpio)), GPIO_SET);
return 0;
}

模块初始化
static int __init t30x_gpio_i2c_init(void)
{
int err;
struct t30x_gpio_i2c_data *drv_data = &t30x_gpio_i2cd;
drv_data->adapter.algo_data = &(drv_data->algo_data);

//private data = gpio pins, set sda/scl will use it
drv_data->algo_data.data = &(drv_data->gpio_pins);

//gpio config
t30x_gpio_hw_init(&(drv_data->gpio_pins));

//add to i2c bit algos
if ((err = i2c_bit_add_bus(&drv_data->adapter) != 0))
{
printk(KERN_ERR "\033[0;40;36mERROR: Could not add %s to i2c bit algos\033[0m\r\n", drv_data->adapter.name); return err;
}

printk("t30x gpio i2c bus initialized\r\n");
return 0;
}

static void __exit t30x_gpio_i2c_exit(void)
{
struct t30x_gpio_i2c_data *drv_data = &t30x_gpio_i2cd;
i2c_bit_del_bus(&drv_data->adapter);
return;
}

module_init(t30x_gpio_i2c_init);
module_exit(t30x_gpio_i2c_exit);
MODULE_DESCRIPTION("GPIO-based I2C adapter for t30x systems");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zhourr");

2008年9月21日星期日

打算把ph701机子用上,作为mp4的功能

希望我上下班的途中能用ph701看电影。701的数据线我没从公司带出来,傻了。只好用2410开发板调,然后再看怎么办吧。我速度应该比较慢,每天晚上的杂事多,最好每天能保证1小时在这上面。

2008年9月17日星期三

内核读写文件

内核读写文件当然有用,比如打印的一些重要信息掉电后就看不到了,所以要存在flash里。直接调用flash驱动读写,还不如直接读写文件。应用程序可以直接用open, read, write, close文件操作,对应到内核的系统调用是sys_open, sys_read, sys_write, sys_close.在syscall里排号挺靠前的,第3,4,5,6
SYSCALL(0, 0) /* 00 */
SYSCALL(sys_exit, 1)
SYSCALL(sys_ni_syscall, 0)
SYSCALL(sys_read, 3)
SYSCALL(sys_write, 3)
SYSCALL(sys_open, 3) /* 05 */
SYSCALL(sys_close, 1)

一般没人直接调用sys_*函数,可能可以,我没试过。
sys_open -> do_sys_open -> filp_open
sys_close -> filp_close
sys_read -> vfs_read -> file->f_op->read
sys_write -> vfs_write -> file->f_op->write

因为是内核空间,要读写用户空间数据需要在read/write前设置,用来表示buf是内核地址还是用户地址,0xc0000000以上还是以下。
file->f_pos表示文件内读写位置,open时是0,read后可修改file->f_pos的值,再read/write

tsfile = filp_open(tsdev->fileName, O_RDONLY, 0);
set_fs(KERNEL_DS);
err = tsfile->f_op->read(tsfile, tsbuf, TSBUFSIZE, &(tsfile->f_pos));
set_fs(USER_DS);
filp_close(tsfile, 0);

touch screen注册字符设备

这2天写了touch screen驱动,IC是tsc2007,用gpio口模拟i2c。不管IC和模拟。这篇就写linux2.6里添加的ts 字符设备,本来正规是在input device里添加的,但是方案商的keypad和ir也是用字符设备做的,所以就配合它这样了。

1>
模块初始化

注册字符设备
rc = register_chrdev(tsdev->major, tsdev->devName, &ts_fops);
if (rc < 0)
{
printk("touch screen driver could not get major number\n");
return rc;
}

IC初始化
cp2007_gpio_init(tsdev);

与某个中断源共享pen down中断,注册
/*PENIRQ connect to SAR, share interrupt, set ts register flag, then pendown irq can up the tsdev->sem*/
tsRegisterIrq(tsPenIrq);

起内核线程
kernel_thread(tsThread,tsdev,0);

2>
完成ts_fops,主要是read和poll,ts的open和release可以do nothing
static struct file_operations ts_fops = {
.owner = THIS_MODULE,
.read = ts_read,
.poll = ts_poll,
.open = ts_open,
.release = ts_close,
};

//虽然不是注册到input设备里,但是read上去的数据结构还是input。我们用的是nanox ads touchscreen,所以就用的这个结构
struct ts_event
{
short x;
short y;
short pressure;/*equal to Z*/
};

static ssize_t ts_read(struct file *filp, char __user *buf, size_t count, loff_t *ptr)
{
struct tsc2007* tsdev = filp->private_data;
int retval = -1;

/*nonblock*/
if ((tsdev->head == tsdev->tail) && (filp->f_flags & O_NONBLOCK))
return -EAGAIN;
/*block*/
//如果是阻塞方式读取,并且buffer里无数据,那么wait
retval = wait_event_interruptible(tsdev->wait, tsdev->head != tsdev->tail);
if (retval)
return retval;
/*if circle buf have event, copy to the buf, else return*/
while ((tsdev->head != tsdev->tail) && (retval + sizeof (struct ts_event) <= count))
{
if (copy_to_user ((void*)(buf + retval), (void*)&(tsdev->eventBuf[tsdev->tail]), sizeof (struct ts_event)))
return -EFAULT;
tsdev->tail = (tsdev->tail + 1) & (TS_EVENT_CNT- 1);
retval += sizeof (struct ts_event);
}
return retval;
}

//当应用用阻塞的方式来读取数据,也就是调用select,对应到内核就是poll,无数据返回0,有数据返回POLLIN POLLRDNORM
static unsigned int ts_poll(struct file * filp, poll_table *wait)
{
struct tsc2007* tsdev = filp->private_data;
poll_wait(filp, &tsdev->wait, wait);
return (tsdev->head == tsdev->tail) ? 0 : (POLLIN POLLRDNORM);
}

3>
实现ts线程,死循环,一直采样并把数据放到circle buffer里,并wakeup等待队列,让app read
当采样一直是pen down,就循环采,如果是pen up,那么被信号量阻塞,直到发生pen down中断,up信号量
一般应该用ostimer来做采样间隔,这里的ostimer给keypad单独用了,且ts又不需要手写,只是电屏而已,所以虽然schedule时间可能很长,不过能让pen down时cpu占用率不会提高很多
/*touch panel main loop*/
static int tsThread(struct tsc2007* tsdev)
{
//don't have ps/top command, no need to daemon it. name it
while(1)
{
schedule();
if(PEN_DOWN == tsProcess(tsdev))
continue;
sema_init(&(tsdev->sem),0);
down(&(tsdev->sem));
}
return 0;
}

irqreturn_t tsPenIrq(int irq, void *dev_id, struct pt_regs * regs)
{
up(&(ts2007_dev.sem));
return IRQ_NONE;
}

4>
ts采样后的处理
/*filter & average 3 point*/
unsigned char tsProcess(struct tsc2007* tsdev)
{
struct ts_event event;
unsigned char cnt;
unsigned char penstate;

memset((void*)&event, 0, sizeof(struct ts_event));
memset((void*)&(tsdev->pointBuf), 0, sizeof(tsdev->pointBuf));

//连续采样3个点
for(cnt = 0; cnt < TS_SAMP_P_CNT; cnt++)
penstate = tsGetPoint(&tsdev->pointBuf[cnt], tsdev);

//判断3个点之间的间距,如果超过规定值(认为是飞笔),或者是pen up就认为是发送pen up消息
if(TS_ERR == tsCheckGap(tsdev))
{
event.x = 0;
event.y = 0;
event.pressure = 0;
tsdev->upTimes++;
if(tsdev->upTimes > 2)
return PEN_UP;

//插入事件到circle buffer
tsInsertEvent(&event,tsdev);
}

//first pen down point, discard it
if(2 == tsdev->upTimes)
{
tsdev->upTimes = 0;
return PEN_DOWN;
}
else
tsdev->upTimes = 0;

//3个点取重心
for(cnt = 0; cnt < TS_SAMP_P_CNT; cnt++)
{
event.x += tsdev->pointBuf[cnt].x;
event.y += tsdev->pointBuf[cnt].y;
}

event.x /= TS_SAMP_P_CNT;
event.y /= TS_SAMP_P_CNT;
event.pressure = 100;

tsInsertEvent(&event,tsdev);

//唤醒block read里的等待队列
wake_up_interruptible(&tsdev->wait);
return PEN_DOWN;
}

void tsInsertEvent(struct ts_event* event, struct tsc2007* tsdev)
{
tsdev->head = (tsdev->head + 1) & (TS_EVENT_CNT- 1);
memcpy((void*)&(tsdev->eventBuf[tsdev->head]), (void*)event, sizeof(struct ts_event));
return;
}

顺便贴的函数
#define CHECK_GAP_XY(point1, point2) \
do{ \
if((!point1.pressure) (!point2.pressure)) \
{ \
tsdev->upTimes++; \
return TS_ERR; \
} \
if((abs(point1.x - point2.x) > MAX_GAP_X)(abs(point1.y - point2.y) > MAX_GAP_Y)) \
return TS_ERR; \
}while(0)

unsigned char tsCheckGap(struct tsc2007* tsdev)
{
CHECK_GAP_XY(tsdev->pointBuf[0], tsdev->pointBuf[1]);
CHECK_GAP_XY(tsdev->pointBuf[0], tsdev->pointBuf[2]);
CHECK_GAP_XY(tsdev->pointBuf[1], tsdev->pointBuf[2]);
return TS_OK;
}

模块数据结构
struct tsc2007
{
int major;/*ts dev major*/
char devName[DEVNAME_LENGTH];/*dev name to register*/
unsigned char devI2cAddr;/*cp2007 i2c addr*/
union cp2007Cmd cmd;
int i2cDelay;/*iic delay u seconds*/
int adcDelay;/*wait for adc complete u seconds*/
wait_queue_head_t wait;/*ts event wakeup for ts poll*/
unsigned char head;/*for eventBuf cycle buf*/
unsigned char tail;/*for eventBuf* cycle buf*/
struct ts_event eventBuf[TS_EVENT_CNT];/*ts event buf to be read for tsdev*/
unsigned char upTimes;/*pen up times*/
struct ts_event pointBuf[TS_SAMP_P_CNT];/*point sample,3 point choose 1*/
unsigned char PressThresh;/*pen down pressure threshold*/
struct semaphore sem;/*pen down semaphore*/
unsigned char sclgpio;
unsigned char sdagpio;
char fileName[DEVNAME_LENGTH];/*老板说要从文件里读出来模拟I2C的GPIO口是多少,说这样以后别的产品换IO口了不用重新编译内核, 多土啊*/
};

2008年9月10日星期三

在procfs里添加可读写文件做调试

procfs可以查看内核信息,不过我刚开始做的时候还不知道procfs里的文件可以写。一旦可以写了,就有方便我们的调试接口,嗯,那么留在这里,忘了的时候看看。sysfs其实更好一些,以后再写一个sysfs的好了
做的是pcf50606寄存器读写接口文件

1>
在procfs的根目录下注册pcf目录/proc/pcf
static struct proc_dir_entry *pcfdir;
#define PCF_DIRNAME "pcf"
pcfdir = proc_mkdir( PCF_DIRNAME, &proc_root);
if ( pcfdir == NULL )
{
PMIC_PRINT(KERN_ERR "can't create /proc/" PCF_DIRNAME "\n");
return ;
}

2>
在/proc/pcf下建立pcf50606所有寄存器读写文件,比如/proc/pcf/ID
typedef struct pcf50606_reg_entry
{
u8 addr;
char *name;
unsigned short low_ino;
} pcf50606_reg_entry_t;

static pcf50606_reg_entry_t pcf50606_regs[] = {
{ 0x00 , "ID" },
{ 0x01 , "OOCS" },
{ 0x02 , "INT1" },
{ 0x03 , "INT2" },
{ 0x04 , "INT3" },
...
};

//读写处理函数
static struct file_operations proc_reg_operations = {
read: proc_read_reg,
write: proc_write_reg
};

//建立文件时把读写处理函数挂上
#define NUM_OF_PCF50606_REG_ENTRY ( sizeof(pcf50606_regs) / sizeof(pcf50606_reg_entry_t))
for ( i = 0 ; i < NUM_OF_PCF50606_REG_ENTRY; i++ ) {
entry = create_proc_entry( pcf50606_regs[i].name,
S_IWUSR S_IRUSR S_IRGRP S_IROTH, pcfdir );
if (entry) {
pcf50606_regs[i].low_ino = entry->low_ino; //把文件inode赋值给pcf变量,读写时根据inode判断是哪个
entry->proc_fops = &proc_reg_operations;
} else {
#define PMIC_PRINT(fmt, args...) printk("%s%s(): "fmt"", "[PCF50606] ",__FUNCTION__, ##args)
PMIC_PRINT( KERN_ERR "can't create /proc/" PCF_DIRNAME );
return ;
}
}

3>
创建读写处理函数
static ssize_t proc_read_reg( struct file *file, char *buf, size_t nbytes, loff_t *ppos )
{
int i_ino = (file->f_dentry->d_inode)->i_ino;
int i, count;
char outputbuf[15];
u8 addr = 0;

if (*ppos > 0 )
return 0;

//根据注册文件时对应的inode来确定到底那个文件名对应哪个寄存器,读写都这样
for ( i =0 ;i < NUM_OF_PCF50606_REG_ENTRY; i++ ) {
if ( pcf50606_regs[i].low_ino == i_ino ) {
addr = pcf50606_regs[i].addr;
break;
}
}

if ( i == NUM_OF_PCF50606_REG_ENTRY )
return -EINVAL;

//ul转字符串
count = sprintf(outputbuf, "0x%02x\n", readPCFregister(addr));
*ppos += count;
if (count > nbytes )
return -EINVAL;
if (copy_to_user(buf, outputbuf, count))
return -EFAULT;
return count;
}

static ssize_t proc_write_reg( struct file *file, const char *buf, size_t count, loff_t *ppos )
{
int i_ino = (file->f_dentry->d_inode)->i_ino;
int i;
char *endp;
u8 addr = 0;

for ( i = 0 ; i < NUM_OF_PCF50606_REG_ENTRY; i++ ) {
if ( pcf50606_regs[i].low_ino == i_ino ) {
addr = pcf50606_regs[i].addr;
break;
}
}
if ( i == NUM_OF_PCF50606_REG_ENTRY )
return -EINVAL;

//字符串转ul
writePCFregister( addr, simple_strtoul( buf, &endp, 0));
return ( count+endp-buf );
}

4>
在procfs中读写文件
cd /proc/pcf/ 到pcf目录
ll 列出所有寄存器名
cat * 列出所有寄存器值
或者单独的cat ID,显示ID寄存器值
echo 1 > ID 写ID寄存器,>左右有空格,1作为字符串传进去

除了这种多个文件公用一个读写函数的读写寄存器的接口,单独建立读写文件当然会更简单,比如常用的打印变量。在procfs里动态改变这个全局变量,而达到屏蔽/放开不同模块的信息,而不需要重新编译来开关打印宏。

放弃了的mips usb isoc

前段时间在调一款mips芯片的usb camera,失败了。方案商提供的代码已经可用U盘。也就是ehci host controller的块传输,控制传输没有问题。camera对应的是等时传输,方案商未测试过。我花了6周的时间试了1.1camera及2.0 uvc camera。始终是ehci等时传输有问题,一直觉得这个可能是瓶颈,驱动设置camera 或uvc设置,降低性能会做的出来。但是到第6周的周末我找leiming帮我调,他的初步结论是ehci host本身的问题,于是我放弃了。leiming是很热心的人,很感谢。6周,又一个丢人的时间片。这是我工作中第2次放弃做一个模块。第1次是破解加密芯片,发现是硬件加密狗,无人曾破解过时放弃。
那么我把失败的尝试列一下:
有2种现象差别,其余的现象都差不多
uframe传输数据大于1024,multi大于1时,一直出现xactErr错误
uframe传输数据小于等于1024,multi等于1时,出现一会xactErr后出现babble错误

1.修改uvc的uvcvideo.h中每次传输使用到的URB数
/* Number of isochronous URBs. */
#define UVC_URBS 5
修改为
#define UVC_URBS 1
出现4次Failed to resubmit status URB (-38)就一次也没有,但是这个规律是N-1次出现,除了少了这个错误打印外依然是xactErr和babble。所以不认为改成1可以解决。-38 -EL2NSYNC错误出现在2.6.14的版本里,高版本内核是-EFBIG错误。

2.修改uvc的uvcvideo.h中每次传输最多用多少个iso包,一个包对应一个uframe
/* Maximum number of packets per isochronous URB. */
#define UVC_MAX_ISO_PACKETS 40
修改为
#define UVC_MAX_ISO_PACKETS 8
1,2,4,6,8,10,20之类的值都试过,也就是每次URB传输不用40个uframe传输,每次少一点,希望能解决ehci瓶颈,但是没效果,不管多少,都会出现babble

3.修改uvc的uvc_video.c中uvc_get_video_ctrl函数里一个uframe最大传输多少字节
ctrl->dwMaxPayloadTransferSize = le32_to_cpu(get_unaligned((__le32 *)&data[22]));
修改为
ctrl->dwMaxPayloadTransferSize = 512;
512,128,1024,等值都试过。camera有6个setting,虽然每个setting的max packet size不同,从128到3072.但是它们的uframe最大传输字节都是3072,也就是multi=3。马上就是xactErr错误

4.去掉uvc_driver.c中反应status的中断urb传输
/* Initialize the interrupt URB */
if ((ret = uvc_status_init(dev)) < 0)
{
uvc_printk(KERN_INFO, "Unable to initialize the status "
"endpoint (%d), status interrupt will not be "
"supported.\n", ret);
}

5.方案商没有ehci capability register接口,读出来的值是0,它们用一个变量来代表register寄存器的值
Ehci_caps.hcs_params = 0x00000001;
Ehci_caps.hcc_params = 0x00000086;
因为不确定实际硬件到底是多少,所以将hcc修改多种组合无效果。
这里主要的2个参数:
1 isoc threshold为一个frame
2 periodic framelist长度为256,而不是1024

6.修改iso_stream_schedule里schedule不及时但是也没落后太久的处理,这个是根据网上的patch改的,但是改了后不产生ehci中断了
if (unlikely ((start + sched->span) > max))
goto ready;

其实也没试几种办法,也不至于大改ehci。没有能力解决问题,怎么办

cscope

1. 下载vim7.0
http://download.chinaunix.net/download.php?id=21977&ResourceID=11091

2. 编译vim
1>配置对cscope的支持
./configure --enable-cscope
2>编译
make
make install
vim在/usr/share/vim/vim70/里

3.下载taglist_45.zip
http://vim.sourceforge.net/scripts/script.php?script_id=273
解压后是doc,plugin文件夹,把里面的2个文件taglist.txt,taglist.vim分别复制到/usr/share/vim/vim70/下的doc,plugin文件夹里

4.到要编辑的源码目录,输入命令
cscope -Rbkq
R 表示把所有子目录里的文件也建立索引
b 表示cscope不启动自带的用户界面,而仅仅建立符号数据库
q生成cscope.in.out和cscope.po.out文件,加快cscope的索引速度
k在生成索引文件时,不搜索/usr/include目录
ctags -R

5.下载cscope_maps.vim,也就是cscope快捷键,放到/usr/share/vim/vim70/plugin文件夹
http://cscope.sourceforge.net/cscope_maps.vim

6.开始用了,vim打开文件,如果是vi打开就不认cscope命令
1>直接跳到start_kernel函数定义处
vim -t start_kernel
2>使用cscope命令,cscope find命令简化是cs f
cscope find s ---- 查找C语言符号,即查找函数名、宏、枚举值等出现的地方
cscope find g ---- 查找函数、宏、枚举等定义的位置,类似ctags所提供的功能
cscope find d ---- 查找本函数调用的函数
cscope find c ---- 查找调用本函数的函数
cscope find t: ---- 查找指定的字符串
cscopecope find e ---- 查找egrep模式,相当于egrep功能,但查找速度快多了
cscope find f ---- 查找并打开文件,类似vim的find功能
cscope find i ---- 查找包含本文件的文
Ctrl+]将跳到光标所在变量或函数的定义处 Ctrl+T返回
3>cscope命令可用快捷键
cs f s start_kernel用快捷键是让光标处于start_kernel字符串处,按Ctrl+\,再按s,也就是Ctrl+\等于cs f ? start_kernel,最方便的是省了敲符号名。如果想在另一个窗口弹出可使用快捷键Ctrl+@(水平窗口),连续2次按Ctrl+@(垂直窗口)。这个快捷键就是之前下载的cscope_maps.vim定义的,需要换按键就修改这个文件
4>使用taglist办法是在vim里输入TlistToggle,但是我这里就是用不了,提示92: Not an editor command: TlistToggle

共用中断源

多个事件共用中断源应该是很常见的,比如GPIO或外围设备
1 只调用一次request_irq,所有中断都根据注册的函数来判断状态而分发
2 自己初始化irq,所有中断事件都可调用request_irq挂自己的处理函数,当然分发函数还是存在,只是在do_IRQ之前
拿pcf50606的中断代码来说,平台是pxa270

1>
#define GPIOX_TO_IRQ(x) \
((x) - 2 + 64)
#define IRQ_GPIO(x) (((x) < 2) ? (IRQ_GPIO0 + (x)) : GPIOX_TO_IRQ(x))
#define PCF50606_IRQ(x) (IRQ_GPIO(128) + 1 + (x)) //也就是虚拟中断源号
void __init pcf50606_init_irq(void)
{
... //读pcf寄存器来清中断并设置中断掩码,未贴
// initialize PCF interrupt related registers //手动初始化虚拟中断源对应的irq_desc
for ( irq = PCF50606_IRQ(0); irq <= PCF50606_IRQ( MAX_PCF_INT ) ; irq++ ) {
irq_desc[irq].valid = 1;
irq_desc[irq].probe_ok = 1;
irq_desc[irq].mask_ack = PCF50606_mask_and_ack_irq;
irq_desc[irq].mask = PCF50606_mask_irq;
irq_desc[irq].unmask = PCF50606_unmask_irq;
//mask,unmask函数与enable_irq/disable_irq对应,把使能禁止中断对应到设置pcf50606中断mask中
}

set_GPIO_IRQ_edge( GPIO_PCF50606_INT , GPIO_FALLING_EDGE ); //相当于request_irq里的触发中断类型
setup_arm_irq( IRQ_GPIO( GPIO_PCF50606_INT ) , &pcf50606_irq ); //挂一个包含中断分发函数的数据结构pcf50606_irq
enable_irq( IRQ_GPIO(GPIO_PCF50606_INT) ); //request_irq函数最后也有enable_irq
}

2>
//中断action结构及处理函数pcf50606_irq_demux
static struct irqaction pcf50606_irq = {
name: "pcf50606",
handler: pcf50606_irq_demux,
flags: SA_INTERRUPT
};

void pcf50606_irq_demux( int irq, void *dev_id, struct pt_regs *regs )
{
int i ;
unsigned long stat0;
int flags;
//关中断
save_and_cli(flags);
disable_irq( IRQ_GPIO( GPIO_PCF50606_INT ));

while(1) {
stat0 = readPCFregister( PCF50606_INT3 ) << 16 |
readPCFregister( PCF50606_INT2 ) << 8 |
readPCFregister( PCF50606_INT1 );
//根据pcf50606中断寄存器中的值判断是哪个中断,调用do_IRQ,最终会走到它们注册该虚拟中断源的函数,因为同时可能产生多个中断,所以while里把所有产生中断的处理函数都执行一遍
for ( i = 0 ; i < 24 ; i++ )
if ( stat0 & ( 1 << i ) )
do_IRQ( PCF50606_IRQ(i), regs );
}
//开中断
enable_irq( IRQ_GPIO( GPIO_PCF50606_INT ));
restore_flags(flags);
}

3>
在某处注册希望处理的中断
err = request_irq ( PCF50606_ONKEYFM_IRQ, onkey_interrupt, 0, "Second", NULL );
err = request_irq ( PCF50606_ONKEYRM_IRQ , onkey_interrupt, 0, "Second", NULL );
err = request_irq ( PCF50606_EXTONRM_IRQ , extonkey_interrupt, 0, "Second", NULL );
err = request_irq ( PCF50606_EXTONFM_IRQ , extonkey_interrupt, 0, "Second", NULL );
虚拟中断源的号当然也要分配好,这里是191以上了
#define PCF50606_ONKEYRM_IRQ PCF50606_IRQ(0)
#define PCF50606_ONKEYFM_IRQ PCF50606_IRQ(1)
#define PCF50606_ONKEY1SM_IRQ PCF50606_IRQ(2)
#define PCF50606_EXTONRM_IRQ PCF50606_IRQ(3)
#define PCF50606_EXTONFM_IRQ PCF50606_IRQ(4)
...

4>
顺便贴一下mask/unmask

static void PCF50606_mask_irq( unsigned int irq )
{
unsigned int bit_value = ( irq - PCF50606_IRQ(0)) ;
unsigned int mask = 1 << (bit_value % 8 );
if ( bit_value > 15 )
writePCFregister( PCF50606_INT3M, readPCFregister( PCF50606_INT3M ) | mask ) ;
else if ( bit_value > 7 )
writePCFregister( PCF50606_INT2M, readPCFregister( PCF50606_INT2M ) | mask ) ;
else
writePCFregister( PCF50606_INT1M, readPCFregister( PCF50606_INT1M ) | mask ) ;
}

static void PCF50606_unmask_irq( unsigned int irq )
{
unsigned int bit_value = ( irq - PCF50606_IRQ(0)) ;
unsigned int mask = 1 << (bit_value % 8 );

if ( bit_value > 15 )
writePCFregister( PCF50606_INT3M, readPCFregister( PCF50606_INT3M ) & ~mask ) ;
else if ( bit_value > 7 )
writePCFregister( PCF50606_INT2M, readPCFregister( PCF50606_INT2M ) & ~mask ) ;
else
writePCFregister( PCF50606_INT1M, readPCFregister( PCF50606_INT1M ) & ~mask ) ;
}

换个平台试试看我漏掉些什么没。

2008年9月8日星期一

又打算开始写blog了

嗯,记一笔,希望能持续

2008年1月23日星期三

2008.1.22路考过关

感谢从07年到08年初 学车给我带来的快乐.
桩考,9选3,长训,路考都让我觉得兴奋.
记一下时间吧,
07年过完春节过来我就想报名学车了,争取了几个同事一起报名后,等待近1个月的暂住证办下来.
3月30号
我,chenzijun,zhushijie,zhaoxunling,liuqingfeng下班后一起去了深港驾校前海报名点.费用3980,5人优惠为3850.
5月11号
理论考试培训课,在福田车管所
7月2号
科目考试一:笔试,一次性过,95分
7月27号(左右?)
开始摸车
9月6号
科目考试二:桩考,一次性过.4人全过
9月21号
科目考试二:9选3,三车道, 没过.第1次因为直角转弯过早压线,第2次因为定点停车起步溜车,4人就我一个没过.
11月16号
科目考试二:9选3,四车道,一次性过.4人过了3个
拒绝了12月9号10号的长训
1月5,6号
韶关长训.下午4点半就到目的地了,长训教练在外打牌到快9点才进去排队,食堂关门了,到外面餐馆吃饭,车的风扇把车内电用光了.推车了很久也打不起火,直到另一辆车来拖.11点半到镇招待所.去时我开第3段,77分钟.返程我开最后一段,从定点吃饭的地方开回深圳海王,开了3个小时,下车觉得生理兴奋
1月22号
路考.下午2点到前海报名点集合在考场练车到5点吃饭,6点排队,我们是第2组第1辆车,后被抽中科长来考.科长只考2辆车.我第4个考.4人过了3个.我第1次没过.1超车时机不对,2连续变更3条车道.第2次无风浪就过了

2008年1月10日星期四

2008年了,感觉到我想大手大脚花钱了,特别是出去玩

2007年过去了我很怀念
12月下旬密集的去了2个地方玩
12月22号去中山仙沐园泡温泉,花了560的样子吧。现在想就觉得比起阳朔就划不来了,只是温泉而已,而且也不是很好,不如珠海的御温泉。御温泉又给我寄优惠券了,可以考虑去一次,拿到驾照后开车去ho
12月30号晚上到1月2号早上,2天3晚游阳朔,感觉不错。我和小舌去玩,比较休闲,住的旅馆也比较满意,榻榻米上放2个1米2的席梦思,窗外风景不错。早上我们赖床不起来,正好2人都有要看的书,吃完早饭就到了11点半。旅游这样还真自在。
把钱报一下,不完全统计1645.5
最贵的一项:火车票946
漂流110一个伐
岩洞50*2=100
住宿60
租双人自行车1天 10元
在阳朔西街吃芝麻糊莲子糊4碗,3*4=12
在阳朔西街买酥饼16
在阳朔西街某餐馆吃饭:批萨30+螺狮酿25+爱尔兰奶茶10=65
在阳朔西街某餐馆吃早饭:芝士蛋糕14+阳朔早晨套餐22(咖啡一杯,橙汁一杯,酸奶配水果,三文治)=36
在岩洞附近餐馆吃午饭:啤酒鱼30+荔脯蒸芋头15+米饭2=47
骑自行车买的2双手套2*2=4
阳朔地图5元
桂林到阳朔14*2=28
阳朔到桂林直达15*2=30
阳朔西街到漂流 坐摩托10,漂流终点到阳朔西街 坐摩托10
买水4
桂林米粉6,油条1
肯德基13.5
柚子3+3+5,泡面4
柿饼5
特产30
桂林三轮车5
桂林剪头24
桂林的士8
深圳人人乐40
来回K548A 10*4=40