发布新日志

  • 在Linux中用虚拟机添加应用程序HELLO

    2009-03-26 14:27:32

    1.保存下面文件hello.desktop  在QPEDIR/apps/applications

    [Desktop Entry]
    Comment=A Simply Application Program
    Exec=hello
    Icon=TodayApp
    Type=Application
    Name=Hello World

    2.把写好的应用程序hello.放在  QPEDIR/bin下面

    在运行qvfb&

    qpe后,将会看到自己刚写好的 hello程序在PDA中有显示.


     

     

  • arm-linux学习笔记之minigui移植

    2009-03-17 10:42:39

    arm-linux学习笔记之minigui移植
    minigui-1.6.10在s3c2410平台的移植

    开发板:atmel9263
    CPU:at9263
    linux-2.6.26
    fs:nfs
    LCD:TFT320 X 240

    PC:ubuntu 8.10

    (一)准备工作
    下载软件包
     libminigui-1.6.10.tar.gz
     mg-samples-1.6.10.tar.gz
     minigui-res-1.6.10.tar.gz
     mg-samples-str-1.6.2.tar.gz
    在/home/arm/创建一个minigui的目录,然后把这些载在的软件包放在该目录下,在分别解压缩。再在/home/arm/minigui下创建一个miniguitmp的目录,用于安装编译以后的库文件。
    (二 )编译 libminigui
    首先修改configure文件,在文件的开头加入交叉编译的路径
    CC=arm-9tdmi-linux-gnu-gcc
    CPP=arm-9tdmi-linux-gnu-cpp
    LD=arm-9tdmi-linux-gnu-ld
    AR=arm-9tdmi-linux-gnu-ar
    RANLIB=arm-9tdmi-linux-gnu-ranlib
    STRIP=arm-9tdmi-linux-gnu-strip
    然后执行
    [root@localhost libminigui-1.6.10]# ./configure --prefix=/home/arm/minigui/miniguitmp/ \
    --build=x86_64-linux \
    --host=arm-unknown-linux \
    --target=arm-unknown-linux
    [root@localhost libminigui-1.6.10]# make
    [root@localhost libminigui-1.6.10]# make install
    这个过程基本上不会有什么错误的
    执行make install的时候会把编译以后的资源安装到/home/arm/minigui/miniguitmp中,在这之下会有etc  include  lib  usr
    几个目录产生。
    ¥#%#¥%说明:由于这是之后作的记录所以这一步产生的目录是include  lib  usr这三个还是四个忘记了,网上一堆说明
    然后进入/home/arm/minigui/miniguitmp/lib,执行
    [root@localhost lib]# ldconfig
    libminigui的交叉编译工作就算完成了。

    (三)安装minigui-res比较简单
    进入/home/arm/minigui/minigui-res-1.6.10目录
    修改config.liux文件的第11行
    TOPDIR=/home/arm/minigui/miniguitmp
    保存
    然后[root@localhost minigui-res-1.6.10]# make install
    资源文件被安装到/home/arm/minigui/miniguitmp/usr/local/lib/minigui/res下面有这几个东西
    bmp  cursor  font  icon  imetab
    (四)修改/home/arm/minigui/miniguitmp/etc/MiniGUI.cfg文件
    [system]                                                                    
    # GAL engine and default options                                            
    gal_engine=fbcon                                                            
    defaultmode=320x240-16bpp                                                   
                                                                                
    # IAL engine                                                                
    #ial_engine=qvfb                                                            
    #mdev=/dev/input/mice                                                       
    ial_engine=console                                                          
    mdev=/dev/mouse                                                             
    mtype=IMPS2                                                                 
                                                                                
    [fbcon]                                                                     
    defaultmode=320x240-16bpp                                                   
                                                                                
    [qvfb]                                                                      
    defaultmode=320x240-16bpp                                                   
    display=0            

    一般就上面几个地方要修改
    然后把MiniGUI.cfg下载到开发板的/etc/目录下
    (五)下载minigui的运行库

        把PC上/home/arm/minigui/miniguitmp/lib中所有的运行库下载到开发板上的/usr/lib目录下;
    在把PC上/home/arm/minigui/miniguitmp/usr/local/lib下的minigui目录整个下载到开发板的/usr/lib下面,到现在开发板上应该有这些东西了
    在开发板的/usr/lib下面有
    lib.tar.bz2               libminigui-1.6.so.10      libvcongui-1.6.so.10.0.0
    libmgext-1.6.so.10        libminigui-1.6.so.10.0.0  libvcongui.a
    libmgext-1.6.so.10.0.0    libminigui.a              libvcongui.la
    libmgext.a                libminigui.la             libvcongui.so
    libmgext.la               libminigui.so             minigui
    libmgext.so               libvcongui-1.6.so.10
    其中minigui是目录
    在开发板的/etc下面应该有MiniGUI.cfg文件存在。
    现在准备工作已经已经完成,下面应该移植一些演示程序。
    (六)编译mg-samples-1.6.10或者mg-samples-str-1.6.2
    这两个东西编译的时候比较不好整,偶太菜,费劲半天才编译通过,事后作的记录可能遗漏。
    1、进入/home/arm/minigui/mg-samples-1.6.10
    修改configure.in第30行,这一步有没有用说不清楚,改成下面的样子
    AC_CHECK_HEADERS($prefix/include/minigui/common.h, have_libminigui=no, foo="bar")
    2、修改configure文件
    在文件的最前面加上交叉编译的工具
    CC=arm-9tdmi-linux-gnu-gcc
    CPP=arm-9tdmi-linux-gnu-cpp
    LD=arm-9tdmi-linux-gnu-ld
    AR=arm-9tdmi-linux-gnu-ar
    RANLIB=arm-9tdmi-linux-gnu-ranlib
    STRIP=arm-9tdmi-linux-gnu-strip
    3、运行configure进行配置
    [root@localhost mg-samples-1.6.10]# ./configure --prefix=/home/arm/minigui/miniguitmp/ \
    > --build=x86_64-linux \
    > --host=arm-unknown-linux \
    > --target=arm-unknown-linux
    ……
    ……
    最后还是有
    configure: WARNING:
            MiniGUI is not properly installed on the system. You need
            MiniGUI Ver 2.0.0 or later for building this package.
            Please configure and install MiniGUI Ver 2.0.0 first.

    这个提示,不管他。
    4、修改src/Makefile文件
    找到
    CC = arm-9tdmi-linux-gnu-gcc
    改成
    CC = arm-9tdmi-linux-gnu-gcc -I/home/arm/minigui/miniguitmp/include -L/home/arm/minigui/miniguitmp/lib

    CFLAGS = -g -O2 -`Wall -Wstrict-prototypes -pipe
    改成
    CFLAGS =-O2

    LIBOBJS = 
    改成
    LIBOBJS = -lminigui -lmgext -lm  -lpthread

    LIBS =  -lminigui
    改成
    LIBS =  -lminigui -lmgext -lm  -lpthread

    COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
        $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
    改成
    COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
        $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -lminigui -lmgext -lm  -lpthread

    (上面的有一步无用)¥%¥#……%¥……%丫的。

    这样基本上可以了,mginit.c文件里面有地方修改后也可以编译完成的,但是有./configure生成的Makefile,已经把这个地方注销掉了。象这样,省得动手修改。
    am__EXEEXT_2 =
    #am__EXEEXT_3 = scrnsaver$(EXEEXT) mginit$(EXEEXT)
    如果想要一起编译这个断,需要修改mginit.c源文件,暂时不说
    5、进入/home/arm/minigui/mg-samples-1.6.10/src
    运行make
    …………
    然后在res目录下会有很多可执行文件。

    (七)下载演示程序
    吧/home/arm/minigui/mg-samples-1.6.10/src下的所有文件和目录打包成一个mg.tar.bz2的文件
    下载到开发板的/usr/local/mg下面没有这个目录自己“贱”一个。
    然后解压缩
    在开发板上解压缩tar -xvzf mg.tar.bz2
    然后删除*.c和Makefile文件
    rm *.c
    现在可以运行minigui的演示程序了。


    (八)问题
    1、
    可能会有这个问题:
    GAL: Init GAL engine failure: fbcon.
    GDI: Can not initialize graphics engine!
    我也出现了,解决方法忘记了,网上查的,不是禁止newgal,就是修改源代码,还得上网查。

    2、tty0的问题
    保证tty0有效
    不行的话就自己创建一个tty0节点:
    crw-r--r--    1 root     root       4,   0 Jan  1 00:02 tty0

    3、鼠标的问题
    我的是usb鼠标。
    3.1要支持鼠标首先要在内核中加入驱动支持:
    #
    # USB Input Devices
    #
    CONFIG_USB_HID=y
    CONFIG_USB_HIDINPUT_POWERBOOK=y
    CONFIG_HID_FF=y
    CONFIG_HID_PID=y
    CONFIG_LOGITECH_FF=y
    CONFIG_PANTHERLORD_FF=y
    CONFIG_THRUSTMASTER_FF=y
    CONFIG_ZEROPLUS_FF=y
    CONFIG_USB_HIDDEV=y
    CONFIG_USB_SUPPORT=y
    CONFIG_USB_ARCH_HAS_HCD=y
    CONFIG_USB_ARCH_HAS_OHCI=y
    # CONFIG_USB_ARCH_HAS_EHCI is not set
    CONFIG_USB=y
    # CONFIG_USB_DEBUG is not set
    # CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
    大概这个样子

    3.2 然后创建节点
    查看/proc/bus/input/devices文件
    #cat /proc/bus/input/devices
    I: Bus="0003" Vendor="15d9" Product="0a33" Version="0110"
    N: Name="USB Mouse"
    P: Phys="usb-s3c24xx-1/input0"
    S: Sysfs="/class/input/input0"
    U: Uniq=
    H: Handlers="mouse0"
    B: EV="17"
    B: KEY="70000" 0 0 0 0 0 0 0 0
    B: REL="103"
    B: MSC="10"
    确定已经鼠标已经连接上了
    然后查看/proc/bus/input/handler
    # cat /proc/bus/input/handler
    N: Number="0" Name="kbd"
    N: Number="1" Name="mousedev" Minor="32"
    看到Number=1 Name="mousedev" Minor="32这个东西了"

    # cat /proc/devices
    Character devices:
     10 misc
     13 input
     29 fb

    到/dev下创建
    #mknod /dev/input/mouse c 13 32

    crw-r--r--    1 root     root      13,  32 Jan  1 00:25 input/mouse
    其中13是设备号的高位 32低位上面的Minor=32和13 input定的,不小的是不是这么会事情,反正鼠标可以工作了.
    可以用下面的命令测试一下:
    # cat /dev/input/mouse
    ??(?(?(?(8??8??8??8??8??8??8??8?
    ?(
    这一堆乱码就是移动鼠标的时候输出的东西,说明鼠标可以工作了。
    创建一个符号连接:
    ln -s /dev/input/mouse  /dev/mouse

    修改权限
    chmod go+r /dev/mouse
    chmod go+r /dev/input/mouse.

    这下运行minigui的时候有鼠标了。

    还有遇到的问题:

    如果鼠标无法使用。 可以修改如下
     25 [system]
     26 # GAL engine and default options
     27 gal_engine=fbcon
     28 defaultmode=240x320-16bpp
     29
     30 # IAL engine
     31 ial_engine=console
     32 mdev=/dev/mouse0
     33 mtype=IMPS2
    这个配置一定可用. 还要注意库的使用

    文章出处:DIY部落(http://www.diybl.com/course/6_system/linux/Linuxjs/20090314/161549.html)

  • minigui安装到PC机上

    2009-03-04 15:03:18

    1. 环境

    硬件环境:

    X86PC 

     

    软件环境:

    VMware虚拟机下的redhat linux 9.0(完全安装)

     

    2.    准备以下源码包(下载) 

    http://www.minigui.org/res.shtml

     

    开发库:libminigui-1.6.0.tar.gz

    资源文件:minigui-res-1.6.10.tar.gz

    示例程序:mg-samples-str-1.6.2.tar.gz

    FramBufferqvfb-1.1.tar.gz

     

    3.    编译安装

    (1) 准备工作

    redhat linux 9.0下新建工作目录

    [root@localhost /]# mkdir /minigui              工作目录 

    [root@localhost /]# mkdir /minigui/compressed /minigui/source

    [root@localhost /]# cd /minigui/compressed        进入工作目录

    说明:把第2步下载的源码包放到该目录中,即/minigui/compressed

     

    (2)编译安装minigui-res-1.6.0.tar.gz

    说明:minigui 所使用的资源,包括基本字体、图标、位图和鼠标光标。

     

    [root@localhost compressed]# tar xzvf minigui-res-1.6.10.tar.gz –C ../source

     

    [root@localhost compressed]# cd ../source/minigui-res-1.6.10

    [root@localhost minigui-res-1.6.10]# make install

      

    (3)编译安装libminigui-1.6.0.tar.gz

    说明:minigui函数库源代码。

    [root@localhost minigui-res-1.6.10]# cd /minigui/compressed

    [root@localhost compressed]# tar xzvf libminigui-1.6.0.tar.gz –C ../source

    [root@localhost compressed]# cd ../source/libminigui-1.6.0

    [root@localhost libminigui-1.6.0]# ./configure

    [root@localhost libminigui-1.6.0]# make

    [root@localhost libminigui-1.6.0]# make install

     

    (4)编译 mg-samples-str-1.6.2.tar.gz

    同上原理:

    解压

    [………]# ./configure

    [………]# make

     

    (5)编译安装qvfb-1.1.tar.gz

    同上原理:

    解压

    [………]# ./configure

    [………]# make

    [………]# make install

     

    (6) 配置

    第一处:修改/boot/grub/grub.conf文件

    用编辑器打开,在“kernel …………”行的后面加入如下内容:

    vga=0x0317

     

    第二处:修改/etc/ld.so.conf文件

    用编辑器打开,在后面加入如下内容:

    /usr/local/lib

     

    接着为了使刚加入的内容生效,在超级终端运行下列命令:

    [………]# ldconfig

     

    第三处:修改/usr/local/etc/MiniGUI.cfg文件,打开文件之后,注意如下内容:

    [system]

    # GAL engine and default options

    gal_engine=qvfb

    defaultmode=800x600-16bpp

     

    # IAL engine

    ial_engine=qvfb

    mdev=/dev/input/mice

    mtype=IMPS2

     

    [fbcon]

    defaultmode=1024x768-16bpp

     

    [qvfb]

    defaultmode=240x320-16bpp  //注意此项应该与运行qvfb&时弹出的虚拟显示屏一样.

    display=0

     

    与上述内容不一致的,请比较后,修改。

     

    4.    测试

    在超级终端运行qvfb,命令如下:

    [………]# qvfb &

    这说明在后台运行,接着再开一终端,或按“ctrl+c”退出,然后进入示例程序目录下,运行helloworld程序:

    [………]# cd /minigui/source/ mg-samples-str-1.6.2/src

    [………]# ./helloworld

     

    运行之后的效果如下图4-1所示:

    4-1  测试minigui示例程序效果

     

  • 安装在vm虚拟机中的redhat如何使用U盘

    2009-02-13 20:47:56

    首先你的redhat必须是安装在vm虚拟机中的那种。启动了redhat后,插上u盘,选择虚拟机的usb接口,一般默认是有2个usb1和usb2,你必须选择一个,虚拟机会自动卸载另外一个,如此你的usb接口才能在虚拟机中真正发挥作用。接下来运行fdisk -l ,系统会查找出来你的u盘,一般情况下你的虚拟机都使用的scsi硬盘(不会是ide),那么你的u盘基本上可以确定是/dev/sdb,或者是/dev/sdb1、/dev/sdb2等等。使用dmesg | more命令可以更清楚地研究配置情况。

    第二,你要了解你的u盘是什么文件格式的,如果是fat格式的,那你的问题就简单得多了。只要运行如下命令加载就行了:

    mkdir  /mnt/usb

    mount   -t  vfat   /dev/sdb  /mnt/usb

    如果不幸你的u盘是ntfs的,那情况就要麻烦一些了。高手可以去编译linux的内核,一般就要找支持ntfs的驱动了。先查找你的linux版本,可以使用的命令有很多,如下:

    uname -r

    rpm  -qi  kernel

    cat   /proc/version

    我的kernel版本是2.4.20-8,然后你就到google去找kernel-ntfs-2.4.20-8.***.rpm,参考http://linux-ntfs.sourceforge.net/rpm/redhat9.html,***代表不同的版本的细微差别,如果安装不上就要换版本。我的试了好几次,最后的文件是kernel-ntfs-2.4.20-8.athlon.rpm。运行如下命令安装好驱动:

    rpm -ivh  kernel-ntfs-2.4.20-8.athlon.rpm

    成功了没有?接下来就是简单的mount了

    mount  -t   ntfs   /dev/sdb   /mnt/usb

    终于在xwindow桌面看到了usb的图标,好激动啊。看看u盘里面的资料,拷贝出来。呵呵。再拷一个文件到u盘。啊,mygod 磁盘写保护,怎么会这样??这样我怎么带资料出去啊,痛苦,谁来救救我。

    下面是我从网上转来的一篇文章,没有试验过,大家自己参考。

    Linux/Windows双系统下实现Linux对NTFS的可靠的写操作

    随着windows 2000/XP的普及,越来越多的Linux爱好者面临Linux读写NTFS文件系统的困难。由于NTFS系统的复杂性和隐秘性,Open Source 对 NTFS 的reverse engineering 迄今只限于可靠的读取功能。

    Captive Project 使用合法的windows XP NTFS 系统文件 作了 类似wine 的仿真,实现了linux 对NTFS 文件系统的写操作。下面是一些简单的步骤:

    1. 下载 rpm package captive-static-1.1.5-0.i386.rpm

    http://www.jankratochvil.net/project/captive/dist/captive-static-1.1.5-0.i386.rpm

    安装:

    # rpm -ivh captive-static-1.1.5-0.i386.rpm

    2. 验证一下你的linux 有kernel source pakage:

    # rpm -qa |grep kernel-source

    如果没有的话, 先安装kernel-source, 例如

    # rpm -ivh kernel-source-2.4.20-8.i386.rpm

    如果你有更新kernel, 请用相应的kernel source包

    3. 设置 windows system files

    拷贝windows NTFS 文件: ntfs.sys 和 ntoskrnl.exe 到某linux 目录下

    运行 命令:

    # /usr/sbin/captive-install-acquire

    该命令会搜索linux目录下的NTFS 文件,如果你没有windows NTFS 文件:

    ntfs.sys 和 ntoskrnl.exe,该命令会请求是否从microsoft网站自动下载

    你也可以直接拷贝两个文件到 /var/lib/captive,

    注意 要使用windowsXP 的文件,win2000 的NTFS 文件不支持。

    4. 运行 命令 以产生 lufs module

    # /usr/share/lufs/prepmod

    5. 运行命令 安装 NTFS格式 例如: C 盘

    # mkdir /mnt/dosc

    # mount -t captive-ntfs /dev/hda1 /mnt/dosc

    captive 1.1.5 会自动寻找 NTFS 分区 并且修改/etc/fstab 文件,你可以按你所愿重新更改/etc/fstab 文件

    6. 运行命令 看/mnt/dosc 是否已挂上

    #df

    注意事项:

    要使用windowsXP 的文件,win2000 的NTFS 文件不支持。

    在Linux下使用sync, 及umount/mount NTFS分区 可以避免Linux重起动后NTFS分区文件丢失的问题。

    测试过程中务必做好windowXP/2000的备份工作,以防不测

  • 在开发板上测试hello程序出错及解答过程

    2009-01-08 16:46:44

    ./hello
    error:
    /hello: error while loading shared libraries: libqte.so.2: cannot open shared o
    bject file: No such file or directory
    try to run sister hello here
    # /tmp/hello
    error:
    Cannot find font definition file /home/qte/qt-embedded-free-3.3.4/lib/fonts/font
    dir - is Qt installed correctly?
    but there is truly no direcotory named /home/qte/.... on arm now, strange!
    then i
    #mount mp3 on /peter
    then
    i export LD_LIBRARY_PATH=/path/to/my/lib
    then
    #./hello
    still same error:lib not found.
    then i
    usr/qt/lib # mv libqte.so.2* /peter/mhel/ql/
    error:
    mv: cannot create symlink `/peter/mhel/ql/libqte.so.2': Operation not permitted
    mv: cannot create symlink `/peter/mhel/ql/libqte.so.2.3': Operation not permitte
    d
    mv: unable to preserve ownership of `/peter/mhel/ql/libqte.so.2.3.1': Operation
    not permitted
    so finally the sis lib itself is on mp3, but the two symbol links
    are still there on arm
    the lib's name become capitalized when i open it again in windows.
    that means i can not copy it back to arm directly now!!!
    that is bad, since linux is case sensitive.
    ok anyway,now reboot
    the sis-hello runs as before, so i know the /usr/qt/lib is not in use.
    it is the /lib/libqte that matters.
    so now
    *************************
    / # ./hello
    ./hello: error while loading shared libraries: libqte.so.2: cannot open shared o
    bject file: No such file or directory
    #cd lib
    #ln -s libqte.so.3 libqte.so.2
    #cd /
    # ./hello
    ./hello: error while loading shared libraries: libstdc++.so.5: cannot open share
    d object file: No such file or directory
     # cd  lib/
    /lib # ln -s libstdc++.so.6 libstdc++.so.5
    #cd /
     # ./hello
    ./hello: /lib/libstdc++.so.5: version `GLIBCPP_3.2' not found (required by ./hel
    lo)
    later, i find libstdc++.so.5 is in /usr/local/arm/3.3.2/lib
    people on net say libstdc++.so.5 and .6 are incompatiable, that's bad.
    **
    lib # ln -s libstdc\+\+-3-libc6.1-2-2.10.0.so  libstdc++.so.5
    peter: i make a symbol linux to a symbol link before, and it does not work,
    this time i think i am right,
    because  error message is different, and part of it is what shows up when i
    try to run sis_hello
    /hello: /lib/libstdc++.so.5: no version information available (required by /hell
    o)
    Cannot find font definition file /home/qte/qt-embedded-free-3.3.4/lib/fonts/font
    dir - is Qt installed correctly?
    **reboot arm
    # ./hello
    ./hello: /lib/libstdc++.so.5: no version information available (required by ./he
    llo)
    QSocket::writeBlock: Socket is not open
    QSocket::writeBlock: Socket is not open
    QSocket::writeBlock: Socket is not open
    No Qt/Embedded server appears to be running.
    If you want to run this program as a server,
    add the "-qws" command-line option.
    peter: from all above, i believe libqte.so.3 and .2 is compatiable. but the libstdc++6
    refuse to corperate.
    ********
    when i copy the right libstdc++
    from /usr/local/arm/3.3.2/arm-linux/lib
    and make the needed symbol link to it
    then
    #./hello
    the "no version information available" error disappers
    but the "Qsocket error" remains, reboot, nothing shows up on the screen.
    now may be the fake lqte.so is responsible!
    *******************
    now i will use a fake libstdC++, and a right lqte, wait and see
    /lib # ln -s libqte~1.7 libqte.so.2
    /lib # cd ..
    / # ./hello
    ./hello: /lib/libstdc++.so.5: no version information available (required by ./he
    llo)
    ./hello: relocation error: /lib/libqte.so.2: undefined symbol: __cxa_pure_virtua
    l
    peter: it is obvious that the lqte is right now. something wrong is with libstdc++.
    and one interesting phenomenon can be seen that even the empty screen do not shows up.
    i think i can understand, it is because qte needs the libc++, now that my hello invokes
    the fake c++ lib, so the qte fails to run.
    *********************************
    since there is not enough space on arm,
    i need to move libqte.so.3 or libstdc++.so.6 out of arm.
    once that are moved onto mp3, the name will be changed(caoitalized),
    can i move it back?
    now i
    #mv /lib/libqte.so.3.3.4 /peter
    peter/ is mp3
    then, reboot, no blue screen can be seen.
    now i will change the name of libqte back,

    and copy it back
    it is done. you just need to be very careful about the name.
    copy the lib to mp3 will not ruin it. that's good.
    *******************
    so finally when there is
    /lib/libstdc++.so.5(plus its symbol link)
    /lib/libqte.so.2(symbol link is also needed)
    my hello runs on arm perfectly.

     

  • 教你一招,不用root帐号也能实现复制粘贴

    2009-01-08 15:59:31

    ubuntu的安去管理很严格,我一直不会用普通帐号在界面中复制粘贴修改关键文件

    今天发现了一条好命令

    在终端中输入

    sudo gnome-open /

    输入密码后就可以自由修改根目录的文件了~不错吧
  • aclock.cpp:83: no matching function for call to `QPainter::setWindow(int, int,

    2009-01-07 20:07:34

    我编译aclock时,出现问题如下:[root@localhost aclock]# make
    g++ -c -pipe -DQWS -fno-exceptions -fno-rtti -Wall -W -O2 -DNO_DEBUG -I/friendly-arm/x86-qtopia/qt/include -o aclock.o aclock.cpp
    aclock.cpp: In member function `void AnalogClock::drawClock(QPainter*)':
    aclock.cpp:83: no matching function for call to `QPainter::setWindow(int, int,
      int, int)'
    aclock.cpp:85: no matching function for call to `QPainter::viewport()'
    aclock.cpp:88: no matching function for call to `QPainter::setViewport(int,
      int, int&, int&)'
    aclock.cpp:94: no matching function for call to `QPainter::rotate(int)'
    aclock.cpp:100: no matching function for call to `QPainter::rotate(int)'
    aclock.cpp:107: no matching function for call to `QPainter::rotate(in

    解决办法

    参见 qpainter.h (qt-embedded-2.3.7\include)
    setWindow函数的声明是用#ifndef QT_NO_TRANSFORMATIONS括起来的, 说明你的config里定义了这个宏, 所以这些函数都没编进你的qte

    注释这个宏即可.

  • QT中hello程序make出错

    2009-01-07 20:06:26

    [root@jude jude_qt]# make
    Makefile:119: warning: overriding commands for target `moc_hello.cpp'
    Makefile:116: warning: ignoring old commands for target `moc_hello.cpp'
    gcc  -o hello hello.o main.o hello.o moc_hello.o moc_hello.o  -L/usr/x-qtopia/qt-2.3.7/lib -lm -lqte
    hello.o(.text+0x0): In function `Hello::Hello[not-in-charge](QWidget*, char const*, unsigned)':
    : multiple definition of `Hello::Hello[not-in-charge](QWidget*, char const*, unsigned)'
    hello.o(.text+0x0): first defined here
    hello.o(.text+0x190): In function `Hello::Hello[in-charge](QWidget*, char const*, unsigned)':
    : multiple definition of `Hello::Hello[in-charge](QWidget*, char const*, unsigned)'
    hello.o(.text+0x190): first defined here
    hello.o(.text+0x320): In function `Hello::~Hello [not-in-charge]()':
    : multiple definition of `Hello::~Hello [not-in-charge]()'
    hello.o(.text+0x320): first defined here
    hello.o(.text+0x344): In function `Hello::~Hello [in-charge]()':
    : multiple definition of `Hello::~Hello [in-charge]()'
    hello.o(.text+0x344): first defined here
    hello.o(.text+0x368): In function `Hello::~Hello [in-charge deleting]()':
    : multiple definition of `Hello::~Hello [in-charge deleting]()'
    hello.o(.text+0x368): first defined here
    moc_hello.o(.text+0xcc): In function `Hello::staticMetaObject()':
    : multiple definition of `Hello::staticMetaObject()'
    moc_hello.o(.text+0xcc): first defined here
    moc_hello.o(.text+0x0): In function `Hello::className() const':
    : multiple definition of `Hello::className() const'
    moc_hello.o(.text+0x0): first defined here
    moc_hello.o(.data+0x0): multiple definition of `Hello::metaObj'
    moc_hello.o(.data+0x0): first defined here
    moc_hello.o(.text+0xc): In function `Hello::initMetaObject()':
    : multiple definition of `Hello::initMetaObject()'
    moc_hello.o(.text+0xc): first defined here
    moc_hello.o(.text+0x74): In function `Hello::tr(char const*)':
    : multiple definition of `Hello::tr(char const*)'
    moc_hello.o(.text+0x74): first defined here
    moc_hello.o(.text+0xa0): In function `Hello::tr(char const*, char const*)':
    : multiple definition of `Hello::tr(char const*, char const*)'
    moc_hello.o(.text+0xa0): first defined here
    /usr/x-qtopia/qt-2.3.7/lib/libqte.so: undefined reference to `QWizard::staticMetaObject()'
    collect2: ld returned 1 exit status
    make: *** [hello] Error 1

    解决方法:

     .pro文件中的qt改为qtopia

  • 用QT测试一个hello程序

    2009-01-07 20:03:00

    在Qt中编程,利用Signal和Slot进行对象之间的通信是Qt的主要特征。它与Windows中的消息机制非常类似,但是Signal和Slot机制真正实现了一种消息的封装。当对象的状态改变时,发出Signal,通知所有的Slot接受Signal,尽管它不知道哪些函数是Slot,Slot一开始也不知道哪些Signal可以接收。Signal和Slot之间不是一一对应的关系,一个Signal可以发给多个Slot, Slot也可以接收多个Signal。Slot除了可以接收Signal以外,与其它的成员函数没有区别。这种机制比使用回调函数要灵活,但是会减慢程序的运行速度。不过在现在高速CPU的面前,这种损失是无足轻重的,而且它还能保证程序的简明性和灵活性,非常便利。

    在Qt的组件中,不仅定义了常用的成员变量和成员函数,还定义了所有与该组件相关的Signal和Slot。

    要将组件组合起来,最简单的方法就是使用Qt Designer。首先要启动Qt Designer,在Linux命令模式下,键入以下命令(假设Qt安装在/usr/local下):

    cd qt-2.3.2/bin   ./designer

    这样就可以启动一个与Windows下的Delphi相类似的如图1的界面。

    Image

    图1 Qt Designer界面

    然后新建一个QFrame,将自己需要的组件直接拖拉到这个Frame中,相信很多人都有过这样的经历,此处就不再详细描述了。完成之后存盘时,会将这个新的组件保存为一个扩展名为.ui的文件。假设所存的文件名为test.ui,用vi test.ui来查看这个文件,发现这是一个用xml语言写的一个文本。下面用这个test.ui生成相应的test.h和test.cpp。同样还是在这个目录下,可以看到一个uic的工具,这个是Qt专门用来将ui文件生成.h和.cpp文件的,在终端模式下键入以下命令:

     progen -n hello -o hello.pro
    ./uic -o test.h test.ui  ./uic -o test.cpp -impl hello.h  test.ui
    vi main.cpp 然后加些自己需要的代码
     progen -n hello -o hello.pro
    tmake -o Makefile hello.pro  生成Makefile文件
    make   生成需要的可执行文件
    然后 qvrb&
     ./hello -qws
    即可观察到程序执行结果
     
     
     

    此时就能看到生成了相应test.h和test.cpp,这是一个类。当然这只是一些表面的东西,还需要在这些代码中添加相应的Signal和Slot,完成所需要的操作。值得注意的是,相应版本生成的ui最好用相应版本的uic来生成代码。


     
  • 错误:/bin/sh: line 1: arm-linux-g++: command not found

    2009-01-07 20:01:40

    ./configure -xplatform linux-arm-g++ -qconfig qpe

    编译的出错情况是这样:
    echo '#include "kernel/qt.h"' >allmoc.cpp
    arm-linux-g++ -E -DQT_MOC_CPP -I/usr/jin/qteqpe/qt-2.3.7/include -pipe -DQWS -fno-exceptions -fno-rtti -O2 -Wall -W -DNO_DEBUG -fPIC -DQT_NO_IMAGEIO_MNG -DQT_NO_QWS_VOODOO3 -DQT_NO_QWS_MACH64 -DQT_NO_QWS_MATROX -DQT_NO_QWS_VNC -DQT_NO_QWS_VGA_16 -DQT_NO_QWS_DEPTH_4 -DQT_NO_QWS_DEPTH_8 -DQT_NO_QWS_DEPTH_24 -DQT_NO_QWS_DEPTH_32 -DQT_BUILTIN_GIF_READER=0 -DQT_NO_IMAGEIO_JPEG -DQT_NO_IMAGEIO_MNG -DQT_NO_SM_SUPPORT -I/usr/jin/qteqpe/qt-2.3.7/src/3rdparty/zlib -I/usr/jin/qteqpe/qt-2.3.7/src/3rdparty/libpng -I3rdparty/kernel -I3rdparty/tools >allmoc.h allmoc.cpp

    /bin/sh: line 1: arm-linux-g++: command not found

    make[1]: *** [allmoc.cpp] Error 127
    make[1]: Leaving directory `/usr/jin/qteqpe/qt-2.3.7/src'
    make: *** [sub-src] Error 2
    [root@localhost qt-2.3.7]#

    解决方法:

    SYSCONF_LINK = arm-linux-gcc
    SYSCONF_LINK_SHLIB = arm-linux-gcc
    均改为
    SYSCONF_LINK = arm-linux-g++
    SYSCONF_LINK_SHLIB = arm-linux-g++

  • 错误:kernel/qt_x11.h:65:22: X11/Xlib.h: 没有那个文件或目录

    2009-01-07 20:00:12

    [root@localhost host]#cd qt-x11

    [root@localhost qt-x11]#export QTDIR=$PWD

    [root@localhost qt-x11]#echo yes|./configure -static -no-xft -no-opengl -no-sm

    [root@localhost qt-x11]# make -C src/moc

    [root@localhost qt-x11]# cp src/moc/moc bin/

    [root@localhost qt-x11]# make -C src

    注:此处可能会提示错误信息,那是由于你的系统没有安装X窗口系统环境有问题,错误提示信息如下所示:

    kernel/qt_x11.h:65:22: X11/Xlib.h: 没有那个文件或目录

    kernel/qt_x11.h:71:23: X11/Xutil.h: 没有那个文件或目录

    kernel/qt_x11.h:72:21: X11/Xos.h: 没有那个文件或目录

    kernel/qt_x11.h:73:23: X11/Xatom.h: 没有那个文件或目录

    kernel/qt_x11.h:84:34: X11/extensions/shape.h: 没有那个文件或目录

    kernel/qpsprinter.cpp: In member function `USHORT

    QPSPrinterFontTTF::unicode_for_glyph(int)':

    kernel/qpsprinter.cpp:3328: warning: `ULONG offset' might be used uninitialized

    in this function

    kernel/qpsprinter.cpp: In constructor `QPSPrinterFont::QPSPrinterFont(const

    QFont&, QPSPrinterPrivate*)':

    kernel/qpsprinter.cpp:5195: `XGetFontPath' undeclared (first use this function)

    kernel/qpsprinter.cpp:5195: (Each undeclared identifier is reported only once

    for each function it appears in.)

    kernel/qpsprinter.cpp:5235: `XFreeFontPath' undeclared (first use this

    function)

    make: *** [kernel/qpsprinter.o] Error 1

     

    解决方法:利用“添加/删除程序”给系统安装X软件开发包

  • 错误: undefined reference to `operator new(unsigned)'

    2009-01-07 19:59:04

    : undefined reference to `operator new(unsigned)'
    /usr/local/arm/qt_x86/qt/lib/libqte.so: undefined reference to `operator new[](unsigned)'
    /usr/local/arm/qt_x86/qt/lib/libqte.so: undefined reference to `__cxa_pure_virtual'
    /usr/local/arm/qt_x86/qt/lib/libqte.so: undefined reference to `operator delete[](void*)'
    collect2: ld returned 1 exit status
    make: *** [hello] Error 1

    【原因】:
    原因是Makefile 里的LINK 项应该为g++ 而不是gcc , 修改
    tmake/lib/qws/linux-generic-g++/tmake.conf
    #vi $TMAKEPATH/tmake.conf
    将TMAKE_LINK = gcc 和TMAKE_LINK_SHLIB = gcc
    分别修改成
    TMAKE_LINK = g++和TMAKE_LINK_SHLIB = g++
    #tmake –o Makefile hello.pro
    此时查看Makefile 里的LINK 项应该已经为g++

  • 错误: freetype/freetype.h: 没有那个文件或目录

    2009-01-07 19:56:21

    tar xfz qt-x11-2.3.2.tar.gz
    cd qt-2.3.2
    export QTDIR=$PWD
    export PATH=$QTDIR/bin:$PATH
    export LD_LIBRARY_PATH=$QTDIR/lib:$LD_LIBRARY_PATH
    ./configure -no-opengl
    结果又报错:
    In file included from kernel/qt_x11.h:76,
    from kernel/qpsprinter.cpp:97:
    /usr/X11R6/include/X11/Xft/Xft.h:35:31: freetype/freetype.h: 没有那个 文件或目录
    In file included from kernel/qt_x11.h:76,
    from kernel/qpsprinter.cpp:97:
    /usr/X11R6/include/X11/Xft/Xft.h:52: syntax error before `;' token
    /usr/X11R6/include/X11/Xft/Xft.h:86: 'FT_UInt' is used as a type, but is not
    defined as a type.
    /usr/X11R6/include/X11/Xft/Xft.h:93: 'FT_UInt' is used as a type, but is not
    defined as a type.
    /usr/X11R6/include/X11/Xft/Xft.h:190: parse error before `*' token
    /usr/X11R6/include/X11/Xft/Xft.h:295: parse error before `*' token
    /usr/X11R6/include/X11/Xft/Xft.h:354: parse error before `*' token
    /usr/X11R6/include/X11/Xft/Xft.h:393: parse error before `*' token
    /usr/X11R6/include/X11/Xft/Xft.h:399: parse error before `*' token
    /usr/X11R6/include/X11/Xft/Xft.h:408: type specifier omitted for parameter `
    FT_UInt'
    /usr/X11R6/include/X11/Xft/Xft.h:408: parse error before `,' token
    /usr/X11R6/include/X11/Xft/Xft.h:418: parse error before `*' token
    /usr/X11R6/include/X11/Xft/Xft.h:461: parse error before `*' token
    make[2]: *** [kernel/qpsprinter.o] Error 1
    make[2]: Leaving directory `/opt/qt-2.3.2/src'
    make[1]: *** [sub-src] Error 2
    make[1]: Leaving directory `/opt/qt-2.3.2'
    make: *** [init] Error 2

    解决方法:

    cd /usr/include
    ln -s freetype2/freetype freetype

    然后再回到qt-2.3.2 再make 即可

  • 安装qtopia的uuid.h找不到问题

    2009-01-07 19:53:43

    我的错误信息
    ......
    global1.cpp:39:23: uuid/uuid.h: No such file or directory
    global1.cpp: In static member function `static QUuid Global::generateUuid()':
    global1.cpp:188: `::uuid_generate' undeclared (first use here)
    make[1]: *** [.obj/linux-generic-g++//global1.o] Error 1
    make[1]: Leaving directory `/usr/src/qtopia-free-1.7.0/src/libraries/qtopia1'
    make: *** [libraries/qtopia1] Error 2
    You have new mail in /var/spool/mail/root

    QT编译补遗
         在安装完整版的RedHat9下,按照前面那个傻瓜教程可以一次编译通过qtopia的开发环境,但是…… 在非完整版的Rh9下面就行不通了。经过无数次的尝试,总结如下:

    问题一: 找不到 uuid.h
    解决: 下载 e2fsprogs-1.35.tar.gz,解压编译,把 e2fsprogs-1.35/lib/uuid 目录拷贝到 qtopia-free-1.7.0/include

    问题二: 找不到 -luuid
    把e2fsprogs-1.35/lib/uuid/libuuid.a 文件拷贝到 usr/lib 或者 qtopia-free-1.7.0/lib

  • QT安装

    2009-01-07 19:37:55

    安装:
    1.建立本机QTOPIA虚拟平台

     软件:  tmake-1.11.tar.gz          //编译工具,如progen与tmake
          qtopia-free-1.7.0.tar.gz      //QTE的桌面环境程序
          qt-embedded-2.3.7.tar.gz   //提供qte的库
          qt-x11-2.3.2.tar.gz               //为了生成相应的QT工具,如designer和qvfb等)

    首先准备软件安装包:tmake工具安装包   qt-embedded安装包   qt-x11 安装包 和具有友好人机界面的qtopia-free安装包


    把软件包下载到提前建立的x86-qtopia目录下.为防止版本的不同而造成的冲突,选择软件包时需要注意一些基本原则,因为qt-x11安装包的两个工具uic和designer产生的源文件会与qt-embedded库一起被编译链接,本着向前兼容的原则,qt-x11安装包的版本必须比qt-embedded安装包的版本旧..

    1,安装tmake
     tar xfz tmake-1.11.tar.gz
    [root@jude x86-qtopia]# export TMAKEDIR=/root/x86-qtopia/tmake-1.11
    [root@jude x86-qtopia]# export TMAKEPATH=/root/x86-qtopia/tmake-1.11/lib/qws/linux-x86-g++/
    [root@jude x86-qtopia]# export PATH=$TMAKEDIR/bin:$PATH

    2.安装Qt/embedded2.3.7
    [root@jude x86-qtopia]# tar xfz qtopia-free-1.7.0.tar.gz

    [root@jude root]# cd x86-qtopia/
    [root@jude x86-qtopia]# cd qt-2.3.7/

    [root@jude qt-2.3.7]# export QPEDIR="/root/x86-qtopia/qtopia-free-1.7.0"
    [root@jude qt-2.3.7]# export QTEDIR="/root/x86-qtopia/qt-2.3.7"
    [root@jude qt-2.3.7]# cp /root/x86-qtopia/qtopia-free-1.7.0/src/qt/qconfig-qpe.h   src/tools/
    [root@jude qt-2.3.7]# ./configure -qvfb -depths 4,8,16,32 -qconfig
    [root@jude qt-2.3.7]# make sub-src     //精简方式编译开发包.
    [root@jude qt-2.3.7]# cd ..


    3.安装qt/x11   2.3.2
    [root@jude x86-qtopia]# tar xfz qt-x11-2.3.2.tar.gz
    [root@jude x86-qtopia]# cd qt-2.3.2/
    [root@jude qt-2.3.2]# export QTDIR=$PWD
    [root@jude qt-2.3.2]# export PATH=/root/x86-qtopia/qt-2.3.2/bin/:$PATH
    [root@jude qt-2.3.2]# export LD_LIBRARY_PATH=/root/x86-qtopia/qt-2.3.2/lib/:$LD_LIBRARY_PATH
    [root@jude qt-2.3.2]# ./configure -no-opengl
    [root@jude qt-2.3.2]# make
    注意在make 之前  需要 先先cd /usr/include
    ln -s freetype2/freetype freetype
    [root@jude qt-2.3.2]# make -C tools/qvfb
    [root@jude qt-2.3.2]# mv tools/qvfb/qvfb  bin
    [root@jude qt-2.3.2]# cp bin/uic /root/x86-qtopia/qt-2.3.7/bin/
    [root@jude qt-2.3.2]# cd ..

    验证:进入/bin   ./desiger  弹出QT界面

    (点击有大图)


    5.安装Qtopia

    [root@jude x86-qtopia]# cd qtopia-free-1.7.0
    [root@jude qtopia-free-1.7.0]# cd qtopia-free-1.7.0
    [root@jude qtopia-free-1.7.0]# export QTDIR=$QTEDIR
    [root@jude qtopia-free-1.7.0]#export QPEDIR=$PWD
    [root@jude qtopia-free-1.7.0]#export PATH=$QPEDIR/bin:$PATH
    [root@jude qtopia-free-1.7.0]#cd src
    [root@jude qtopia-free-1.7.0]#./configure   如果环境变量没设好,将会出现错误
       global1.cpp:39:23: uuid/uuid.h: 没有那个文件或目录
       global1.cpp: In static member function `static QUuid Global::generateUuid()':
       global1.cpp:188: `::uuid_generate' undeclared (first use here)
       make[1]: *** [.obj/linux-generic-g++//global1.o] Error 1
       make[1]: Leaving directory `/root/x86-qtopia/qtopia-free-1.7.0/src/libraries/qtopia1'
       make: *** [libraries/qtopia1] Error 2

    安装 e2fsprogs-1.39
    cd e2fsprogs-1.39
    ./configure -enable-elf-shlibs
    make
    make install lib/uuid/
    问题一: 找不到 uuid.h
    解决: 下载 e2fsprogs-1.35.tar.gz,解压编译,把 e2fsprogs-1.35/lib/uuid 目录拷贝到 qtopia-free-1.7.0/include

    问题二: 找不到 -luuid
    把e2fsprogs-1.35/lib/uuid/libuuid.a 文件拷贝到 usr/lib 或者 qtopia-free-1.7.0/lib

    [root@jude src]# make

    [root@jude qtopia-free-1.7.0]#cd ../..


    6.安装Qtopia桌面
    [root@jude qtopia-free-1.7.0]#cd qtopia-free-1.7.0/src
    [root@jude src]# export QTEDIR=$QTEDIR
    [root@jude src]#./configure -qtopiadesktop
    [root@jude src]#make
    [root@jude src]#mv qtopiadesktop/bin/qtopiadesktop ../bin
    [root@jude src]#cd ..

     

    7.在PC机上运行QPE
      qvfb&
      qpe&


    8.添加自己的应用程序到QPE中.
      (1)新建一个hello.desktop文件,保存在$QPEDIR/apps/applications
         [Desktop Entry]
         Comment=A Simply Application Program
         Exec=hello
         Icon=TodayApp
         Type=Application
         Name=Hello World
      (2)把自己通过QT 等一系列的变换后,得到hello 可执行文件
         然后把其保存在$QPEDIR/bin文件夹下


  • 非常好的将framebuffer驱动的文章,看过后受益匪浅(转

    2009-01-07 19:12:17

    非常好的将framebuffer驱动的文章,看过后受益匪浅
     

    *一、FrameBuffer的原理*
        FrameBuffer 是出现在 2.2.xx 内核当中的一种驱动程序接口。


    Linux是工作在保护模式下,所以用户态进程是无法象DOS那样使用显卡BIOS里提供的中断调用来实现直接写屏,Linux抽象出FrameBuffer这-个设备来供用户态进程实现直接写屏。Framebuffer机制模仿显卡的功能,将显卡硬件结构抽象掉,可以通过Framebuffer的读写直接对显存进行操-作。用户可以将Framebuffer看成是显示内存的一个映像,将其映射到进程地址空间之后,就可以直接进行读写操作,而写操作可以立即反应在屏幕上。这种操-作是抽象的,统一的。用户不必关心物理显存的位置、换页机制等等具体细节。这些都是由Framebuffer设备驱动来完成的。
        但Framebuffer本身不具备任何运算数据的能力,就只好比是一个暂时存放水的水池.CPU将运算后的结果放到这个水池,
    水池再将结果流到显示器.中间不会对数据做处理. 应用程序也可以直接读写这个水池的内容.在这种机制下,
    尽管Framebuffer需要真正的显卡驱动的支持,但所有显示任务都有CPU完成,因此CPU负担很重.
    framebuffer的设备文件一般是 /dev/fb0、/dev/fb1 等等。
    可以用命令: #dd if=/dev/zero ōf=/dev/fb 清空屏幕.
    如果显示模式是 1024x768-8 位色,用命令:$ dd if=/dev/zero ōf=/dev/fb0 bs=1024 count=768
    清空屏幕;
    用命令: #dd if=/dev/fb ōf=fbfile 可以将fb中的内容保存下来;
    可以重新写回屏幕: #dd if=fbfile ōf=/dev/fb;
    在使用Framebuffer时,Linux是将显卡置于图形模式下的.


        在应用程序中,一般通过将 FrameBuffer 设备映射到进程地址空间的方式使用,比如下面的程序就打开 /dev/fb0 设备,并通过
    mmap 系统调用进行地址映射,随后用 memset 将屏幕清空(这里假设显示模式是 1024x768-8 位色模式,线性内存模式):


    int fb;
    unsigned char* fb_mem;
    fb = open ("/dev/fb0", O_RDWR);
    fb_mem = mmap (NULL, 1024*768, PROT_READ|PROT_WRITE,MAP_SHARED,fb,0);
    memset (fb_mem, 0, 1024*768);


        FrameBuffer 设备还提供了若干 ioctl
    命令,通过这些命令,可以获得显示设备的一些固定信息(比如显示内存大小)、与显示模式相关的可变信息(比如分辨率、象素结构、每扫描线的字节宽度),以及伪彩-色模式下的调色板信息等等。
        通过 FrameBuffer
    设备,还可以获得当前内核所支持的加速显示卡的类型(通过固定信息得到),这种类型通常是和特定显示芯片相关的。比如目前最新的内核(2.4.9)中,就包含有-对
    S3、Matrox、nVidia、3Dfx 等等流行显示芯片的加速支持。在获得了加速芯片类型之后,应用程序就可以将 PCI
    设备的内存I/O(memio)映射到进程的地址空间。这些 memio
    一般是用来控制显示卡的寄存器,通过对这些寄存器的操作,应用程序就可以控制特定显卡的加速功能。
        PCI
    设备可以将自己的控制寄存器映射到物理内存空间,而后,对这些控制寄存器的访问,给变成了对物理内存的访问。因此,这些寄存器又被称为"memio"。一旦被映-射到物理内存,Linux
    的普通进程就可以通过 mmap 将这些内存 I/O 映射到进程地址空间,这样就可以直接访问这些寄存器了。
        当然,因为不同的显示芯片具有不同的加速能力,对memio
    的使用和定义也各自不同,这时,就需要针对加速芯片的不同类型来编写实现不同的加速功能。比如大多数芯片都提供了对矩形填充的硬件加速支持,但不同的芯片实现方-式不同,这时,就需要针对不同的芯片类型编写不同的用来完成填充矩形的函数。
        FrameBuffer 只是一个提供显示内存和显示芯片寄存器从物理内存映射到进程地址空间中的设备。所以,对于应用程序而言,如果希望在
    FrameBuffer 之上进行图形编程,还需要自己动手完成其他许多工作。


    *二、FrameBuffer在Linux中的实现和机制
    *Framebuffer对应的源文件在linux/drivers/video/目录下。总的抽象设备文件为fbcon.c,
    在这个目录下还有与各种显卡驱动相关的源文件。


    (一)、分析Framebuffer设备驱动
        需要特别提出的是在INTEL平台上,老式的VESA
    1.2卡,如CGA/EGA卡,是不能支持Framebuffer的,因为Framebuffer要求显卡支持线性帧缓冲,即CPU可以访问显缓冲中的每一位,-但是VESA
    1.2 卡只能允许CPU一次访问64K的地址空间。
    FrameBuffer设备驱动基于如下两个文件:
    1) linux/include/linux/fb.h
    2) linux/drivers/video/fbmem.c


    下面分析这两个文件。
    1、fb.h
       几乎主要的结构都是在这个中文件定义的。这些结构包括:
    1)fb_var_screeninfo
       这个结构描述了显示卡的特性:


    struct fb_var_screeninfo
    {
    __u32 xres; /* visible resolution */
    __u32 yres;
    __u32 xres_virtual; /* virtual resolution */
    __u32 yres_virtual;
    __u32 xoffset; /* offset from virtual to visible resolution */
    __u32 yoffset;


    __u32 bits_per_pixel; /* guess what */
    __u32 grayscale; /* != 0 Gray levels instead of colors */


    struct fb_bitfield red; /* bitfield in fb mem if true color, */
    struct fb_bitfield green; /* else only length is significant */
    struct fb_bitfield blue;
    struct fb_bitfield transp; /* transparency */


    __u32 nonstd; /* != 0 Non standard pixel format */


    __u32 activate; /* see FB_ACTIVATE_* */


    __u32 height; /* height of picture in mm */
    __u32 width; /* width of picture in mm */


    __u32 accel_flags; /* acceleration flags (hints) */


    /* Timing: All values in pixclocks, except pixclock (of course) */
    __u32 pixclock; /* pixel clock in ps (pico seconds) */
    __u32 left_margin; /* time from sync to picture */
    __u32 right_margin; /* time from picture to sync */
    __u32 upper_margin; /* time from sync to picture */
    __u32 lower_margin;
    __u32 hsync_len; /* length of horizontal sync */
    __u32 vsync_len; /* length of vertical sync */
    __u32 sync; /* see FB_SYNC_* */
    __u32 vmode; /* see FB_VMODE_* */
    __u32 reserved[6]; /* Reserved for future compatibility */

    };


    2) fb_fix_screeninfon
    这个结构在显卡被设定模式后创建,它描述显示卡的属性,并且系统运行时不能被修改;比如FrameBuffer内存的起始地址。它依赖于被设定的模式,当一个模-式被设定后,内存信息由显示卡硬件给出,内存的位置等信息就不可以修改。

    struct fb_fix_screeninfo {
    char id[16]; /* identification string eg "TT Builtin" */
    unsigned long smem_start; /* Start of frame buffer mem */
    /* (physical address) */
    __u32 smem_len; /* Length of frame buffer mem */
    __u32 type; /* see FB_TYPE_* */
    __u32 type_aux; /* Interleave for interleaved Planes */
    __u32 visual; /* see FB_VISUAL_* */
    __u16 xpanstep; /* zero if no hardware panning */
    __u16 ypanstep; /* zero if no hardware panning */
    __u16 ywrapstep; /* zero if no hardware ywrap */
    __u32 line_length; /* length of a line in bytes */
    unsigned long mmio_start; /* Start of Memory Mapped I/O */
    /* (physical address) */
    __u32 mmio_len; /* Length of Memory Mapped I/O */
    __u32 accel; /* Type of acceleration available */
    __u16 reserved[3]; /* Reserved for future compatibility */

    };


    3) fb_cmap
    描述设备无关的颜色映射信息。可以通过FBIOGETCMAP 和 FBIOPUTCMAP 对应的ioctl操作设定或获取颜色映射信息.

    struct fb_cmap {
    __u32 start; /* First entry */
    __u32 len; /* Number of entries */
    __u16 *red; /* Red values */
    __u16 *green;
    __u16 *blue;
    __u16 *transp; /* transparency, can be NULL */

    };


    4) fb_info
    定义当显卡的当前状态;fb_info结构仅在内核中可见,在这个结构中有一个fb_ops指针, 指向驱动设备工作所需的函数集。

    struct fb_info {
    char modename[40]; /* default video mode */
    kdev_t node;
    int flags;
    int open; /* Has this been open already ? */
    #define FBINFO_FLAG_MODULE 1 /* Low-level driver is a module */
    struct fb_var_screeninfo var; /* Current var */
    struct fb_fix_screeninfo fix; /* Current fix */
    struct fb_monspecs monspecs; /* Current Monitor specs */
    struct fb_cmap cmap; /* Current cmap */
    struct fb_ops *fbops;
    char *screen_base; /* Virtual address */
    struct display *disp; /* initial display variable */
    struct vc_data *display_fg; /* Console visible on this display */
    char fontname[40]; /* default font name */
    devfs_handle_t devfs_handle; /* Devfs handle for new name */
    devfs_handle_t devfs_lhandle; /* Devfs handle for compat. symlink */
    int (*changevar)(int); /* tell console var has changed */
    int (*switch_con)(int, struct fb_info*);
    /* tell fb to switch consoles */
    int (*updatevar)(int, struct fb_info*);
    /* tell fb to update the vars */
    void (*blank)(int, struct fb_info*); /* tell fb to (un)blank the screen */
    /* arg = 0: unblank */
    /* arg > 0: VESA level (arg-1) */
    void *pseudo_palette; /* Fake palette of 16 colors and
    the cursor's color for non
    palette mode */
    /* From here on everything is device dependent */
    void *par;

    };


    5) struct fb_ops
    用户应用可以使用ioctl()系统调用来操作设备,这个结构就是用一支持ioctl()的这些操作的。

    struct fb_ops {
    /* open/release and usage marking */
    struct module *owner;
    int (*fb_open)(struct fb_info *info, int user);
    int (*fb_release)(struct fb_info *info, int user);
    /* get non settable parameters */
    int (*fb_get_fix)(struct fb_fix_screeninfo *fix, int con,
    struct fb_info *info);
    /* get settable parameters */
    int (*fb_get_var)(struct fb_var_screeninfo *var, int con,
    struct fb_info *info);
    /* set settable parameters */
    int (*fb_set_var)(struct fb_var_screeninfo *var, int con,
    struct fb_info *info);
    /* get colormap */
    int (*fb_get_cmap)(struct fb_cmap *cmap, int kspc, int con,
    struct fb_info *info);
    /* set colormap */
    int (*fb_set_cmap)(struct fb_cmap *cmap, int kspc, int con,
    struct fb_info *info);
    /* pan display (optional) */
    int (*fb_pan_display)(struct fb_var_screeninfo *var, int con,
    struct fb_info *info);
    /* perform fb specific ioctl (optional) */
    int (*fb_ioctl)(struct inode *inode, struct file *file, unsigned int cmd,
    unsigned long arg, int con, struct fb_info *info);
    /* perform fb specific mmap */
    int (*fb_mmap)(struct fb_info *info, struct file *file, struct
    vm_area_struct *vma);
    /* switch to/from raster image mode */
    int (*fb_rasterimg)(struct fb_info *info, int start);

    };


    6) structure map
    struct fb_info_gen | struct fb_info | fb_var_screeninfo
    | | fb_fix_screeninfo
    | | fb_cmap
    | | modename[40]
    | | fb_ops ---|--->ops on var
    | | ... | fb_open
    | | | fb_release
    | | | fb_ioctl
    | | | fb_mmap
    | struct fbgen_hwswitch -|-> detect
    | | encode_fix
    | | encode_var
    | | decode_fix
    | | decode_var
    | | get_var
    | | set_var
    | | getcolreg
    | | setcolreg
    | | pan_display
    | | blank
    | | set_disp

    [编排有点困难,第一行的第一条竖线和下面的第一列竖线对齐,第一行的第二条竖线和下面的第二列竖线对齐就可以了]
    这个结构 fbgen_hwswitch抽象了硬件的操作.虽然它不是必需的,但有时候很有用.


    2、 fbmem.c
    fbmem.c 处于Framebuffer设备驱动技术的中心位置.它为上层应用程序提供系统调用也为下一层的特定硬件驱动提供接口;那些底层硬件驱动需要用到这儿的接口来向-系统内核注册它们自己.
    fbmem.c 为所有支持FrameBuffer的设备驱动提供了通用的接口,避免重复工作.


    1) 全局变量


    struct fb_info *registered_fb[FB_MAX];
    int num_registered_fb;


    这两变量记录了所有fb_info 结构的实例,fb_info 结构描述显卡的当前状态,所有设备对应的fb_info
    结构都保存在这个数组中,当一个FrameBuffer设备驱动向系统注册自己时,其对应的fb_info
    结构就会添加到这个结构中,同时num_registered_fb 为自动加1.


    static struct {
    const char *name;
    int (*init)(void);
    int (*setup)(void);

    } fb_drivers[] __initdata= { ....};


    如果FrameBuffer设备被静态链接到内核,其对应的入口就会添加到这个表中;如果是动态加载的,即使用insmod/rmmod,就不需要关心这个表。

    static struct file_operations fb_ops ={
    owner: THIS_MODULE,
    read: fb_read,
    write: fb_write,
    ioctl: fb_ioctl,
    mmap: fb_mmap,
    open: fb_open,
    release: fb_release


    };


    这是一个提供给应用程序的接口.

    2)fbmem.c 实现了如下函数.


    register_framebuffer(struct fb_info *fb_info);
    unregister_framebuffer(struct fb_info *fb_info);


    这两个是提供给下层FrameBuffer设备驱动的接口,设备驱动通过这两函数向系统注册或注销自己。几乎底层设备驱动所要做的所有事情就是填充fb_inf-o结构然后向系统注册或注销它。


    (二)一个LCD显示芯片的驱动实例
        以Skeleton LCD
    控制器驱动为例,在LINUX中存有一个/fb/skeleton.c的skeleton的Framebuffer驱动程序,很简单,仅仅是填充了
    fb_info结构,并且注册/注销自己。设备驱动是向用户程序提供系统调用接口,所以我们需要实现底层硬件操作并且定义file_operations
    结构来向系统提供系统调用接口,从而实现更有效的LCD控制器驱动程序。


    1)在系统内存中分配显存
    在fbmem.c文件中可以看到, file_operations
    结构中的open()和release()操作不需底层支持,但read()、write()和 mmap()操作需要函数fb_get_fix()的
    支持.因此需要重新实现函数fb_get_fix()。另外还需要在系统内存中分配显存空间,大多数的LCD控制器都没有自己的显存空间,被分配的地址空间的起-始地址与长度将会被填充到fb_fix_screeninfo
    结构的smem_start 和smem_len 的两个变量中.被分配的空间必须是物理连续的。


    2)实现 fb_ops 中的函数
    用户应用程序通过ioctl()系统调用操作硬件,fb_ops 中的函数就用于支持这些操作。(注: fb_ops结构与file_operations
    结构不同,fb_ops是底层操作的抽象,而file_operations是提供给上层系统调用的接口,可以直接调用.
    ioctl()系统调用在文件fbmem.c中实现,通过观察可以发现ioctl()命令与fb_ops's 中函数的关系:
    FBIOGET_VSCREENINFO fb_get_var
    FBIOPUT_VSCREENINFO fb_set_var
    FBIOGET_FSCREENINFO fb_get_fix
    FBIOPUTCMAP fb_set_cmap
    FBIOGETCMAP fb_get_cmap
    FBIOPAN_DISPLAY fb_pan_display


    如果我们定义了fb_XXX_XXX 方法,用户程序就可以使用FBIOXXXX宏的ioctl()操作来操作硬件。


    文件linux/drivers/video/fbgen.c或者linux/drivers/video目录下的其它设备驱动是比较好的参考资料。在所有的这-些函数中fb_set_var()是最重要的,它用于设定显示卡的模式和其它属性,下面是函数fb_set_var()的执行步骤:


    1)检测是否必须设定模式
    2)设定模式


    3)设定颜色映射


    4) 根据以前的设定重新设置LCD控制器的各寄存器。
    第四步表明了底层操作到底放置在何处。在系统内存中分配显存后,显存的起始地址及长度将被设定到LCD控制器的各寄存器中(一般通过fb_set_var()
    函数),显存中的内容将自动被LCD控制器输出到屏幕上。另一方面,用户程序通过函数mmap()将显存映射到用户进程地址空间中,然后用户进程向映射空间发送-的所有数据都将会被显示到LCD显示器上。


    *三、FrameBuffer的应用*


    (一)、一个使用FrameBuffer的例子


       1. FrameBuffer主要是根据VESA标准的实现的,所以只能实现最简单的功能。
       2. 由于涉及内核的问题,FrameBuffer是不允许在系统起来后修改显示模式等一系列操作。(好象很多人都想要这样干,这是不被允许的,当然如果你自己写驱动-的话,是可以实现的).


       3. 对FrameBuffer的操作,会直接影响到本机的所有控制台的输出,包括XWIN的图形界面。


    好,现在可以让我们开始实现直接写屏:


    1、打开一个FrameBuffer设备


    2、通过mmap调用把显卡的物理内存空间映射到用户空间


    3、直接写内存。


    /********************************
    File name : fbtools.h
    */


    #ifndef _FBTOOLS_H_
    #define _FBTOOLS_H_
    #include <linux/fb.h>
    //a framebuffer device structure;
    typedef struct fbdev{
           int fb;
           unsigned long fb_mem_offset;
           unsigned long fb_mem;
           struct fb_fix_screeninfo fb_fix;
           struct fb_var_screeninfo fb_var;
           char dev[20];

    } FBDEV, *PFBDEV;


    //open & init a frame buffer
    //to use this function,
    //you must set FBDEV.dev="/dev/fb0"
    //or "/dev/fbX"
    //it's your frame buffer.
    int fb_open(PFBDEV pFbdev);

    //close a frame buffer
    int fb_close(PFBDEV pFbdev);


    //get display depth
    int get_display_depth(PFBDEV pFbdev);


    //full screen clear
    void fb_memset(void *addr, int c, size_t len);


    #endif


    /******************
    File name : fbtools.c
    */


    #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <string.h>
    #include <sys/ioctl.h>
    #include <sys/mman.h>
    #include <asm/page.h>
    #include "fbtools.h"
    #define TRUE        1
    #define FALSE       0
    #define MAX(x,y)        ((x)>(y)?(x)y))
    #define MIN(x,y)        ((x)<(y)?(x)y))


    //open & init a frame buffer
    int fb_open(PFBDEV pFbdev)
    {
           pFbdev->fb = open(pFbdev->dev, O_RDWR);
           if(pFbdev->fb < 0)
           {
                  printf("Error opening %s: %m. Check kernel config\n",
    pFbdev->dev);
                  return FALSE;
           }


           if (-1 == ioctl(pFbdev->fb,FBIOGET_VSCREENINFO,&(pFbdev->fb_var)))
           {
                  printf("ioctl FBIOGET_VSCREENINFO\n");
                  return FALSE;
           }


           if (-1 == ioctl(pFbdev->fb,FBIOGET_FSCREENINFO,&(pFbdev->fb_fix)))
           {
                  printf("ioctl FBIOGET_FSCREENINFO\n");
                  return FALSE;
           }


           //map physics address to virtual address
           pFbdev->fb_mem_offset = (unsigned long)(pFbdev->fb_fix.smem_start) &
    (~PAGE_MASK);
           pFbdev->fb_mem = (unsigned long int)mmap(NULL,
    pFbdev->fb_fix.smem_len + pFbdev->fb_mem_offset,              PROT_READ |
    PROT_WRITE, MAP_SHARED, pFbdev->fb, 0);


           if (-1L == (long) pFbdev->fb_mem)
           {
                  printf("mmap error! mem:%d offset:%d\n", pFbdev->fb_mem,
    pFbdev->fb_mem_offset);
                  return FALSE;
           }
           return TRUE;

    }


    //close frame buffer
    int fb_close(PFBDEV pFbdev)
    {
           close(pFbdev->fb);
           pFbdev->fb=-1;


    }


    //get display depth
    int get_display_depth(PFBDEV pFbdev);
    {
           if(pFbdev->fb<=0)
           {
                  printf("fb device not open, open it first\n");
                  return FALSE;
           }
           return pFbdev->fb_var.bits_per_pixel;


    }


    //full screen clear
    void fb_memset (void *addr, int c, size_t len)
    {
        memset(addr, c, len);


    }


    //use by test
    #define DEBUG
    #ifdef DEBUG
    main()
    {
           FBDEV fbdev;
           memset(&fbdev, 0, sizeof(FBDEV));
           strcpy(fbdev.dev, "/dev/fb0");
           if(fb_open(&fbdev)==FALSE)
           {
                  printf("open frame buffer error\n");
                  return;
           }
           fb_memset(fbdev.fb_mem + fbdev.fb_mem_offset, 0,
    fbdev.fb_fix.smem_len);
                  fb_close(&fbdev);


    }


    (二)基于Linux核心的汉字显示的尝试
    我们以一个简单的例子来说明字符显示的过程。我们假设是在虚拟终端1(/dev/tty1)下运行一个如下的简单程序。

    main ( )
    {
    puts("hello, world.\n");

    }


    puts 函数向缺省输出文件(/dev/tty1)发出写的系统调用write(2)。系统调用到linux核心里面对应的核心函数是console.c中的con_w-rite(),con_write()最终会调用do_con_write(
    )。在do_con_write( )中负责把"hello,
    world.\n"这个字符串放到tty1对应的缓冲区中去。
    do_con_write( )还负责处理控制字符和光标的位置。让我们来看一下do_con_write()这个函数的声明。
    static int do_con_write(struct tty_struct * tty, int from_user, const
    unsigned char *buf, int count)
        其中tty是指向tty_struct结构的指针,这个结构里面存放着关于这个tty的所有信息(请参照
    linux/include/linux/tty.h)。Tty_struct结构中定义了通用(或高层)tty的属性(例如宽度和高度等)。在do_con_-write(
    )函数中用到了tty_struct结构中的driver_data变量。driver_data是一个vt_struct指针。在vt_struct结构中包-含这个tty的序列号(我们正使用tty1,所以这个序号为1)。Vt_struct结构中有一个vc结构的数组vc_cons,这个数组就是各虚拟终端的私有-数据。

    static int do_con_write(struct tty_struct * tty, int from_user,const
    unsigned char *buf, int count)
    {
    struct vt_struct *vt = (struct vt_struct
    *)tty->driver_data;//我们用到了driver_data变量
    . . . . .
    currcons = vt->vc_num; file://我们在这里的vc_nums就是1
    . . . . .

    }


    要访问虚拟终端的私有数据,需使用vc_cons〔currcons〕.d指针。这个指针指向的结构含有当前虚拟终端上光标的位置、缓冲区的起始地址、缓冲区大-小等等。
        "hello, world.\n"中的每一个字符都要经过conv_uni_to_pc(
    )这个函数转换成8位的显示字符。这要做的主要目的是使不同语言的国家能把16位的UniCode码映射到8位的显示字符集上,目前还是主要针对欧洲国家的语言-,映射结果为8位,不包含对双字节(double
    byte)的范围。

    这种UNICODE到显示字符的映射关系可以由用户自行定义。在缺省的映射表上,会把中文的字符映射到其他的字符上,这是我们不希望看到也是不需要的。所以我们-有两个选择∶


       1. 不进行conv_uni_to_pc( )的转换。
       2. 加载符合双字节处理的映射关系,即对非控制字符进行1对1的不变映射。
       我们自己定制的符合这种映射关系的UNICODE码表是direct.uni。要想查看/装载当前系统的unicode映射表,可使外部命令loadunima-p。


    经过conv_uni_to_pc( )转换之后,"hello,
    world.\n"中的字符被一个一个地填写到tty1的缓冲区中。然后do_con_write(
    )调用下层的驱动,把缓冲区中的内容输出到显示器上(也就相当于把缓冲区的内容拷贝到VGA显存中去)。


    sw->con_putcs(vc_cons〔currcons〕.d, (u16 *)draw_from, (u16*)draw_to-(u16
    *)draw_from, y, draw_x);


    之所以要调用底层驱动,是因为存在不同的显示设备,其对应VGA显存的存取方式也不一样。
    上面的Sw->con_putcs(
    )就会调用到fbcon.c中的fbcon_putcs()函数(con_putcs是一个函数的指针,在Framebuffer模式下指向
    fbcon_putcs()函数)。也就是说在do_con_write(
    )函数中是直接调用了fbcon_putcs()函数来进行字符的绘制。比如说在256色模式下,真正负责输出的函数是void
    fbcon_cfb8_putcs(struct vc_data *conp, struct display *p,const unsigned
    short *s, int count, int yy, int xx)


    显示中文
        比如说我们试图输出一句中文∶putcs(你好\n
    );(你好的内码为0xc4,0xe3,0xba,0xc3)。这时候会怎么样呢,有一点可以肯定,"你好"肯定不会出现在屏幕上,国为核心中没有汉字字库,中-文显示就是无米之炊了.
        1 在负责字符显示的void fbcon_cfb8_putcs(
    )函数中,原有操作如下∶对于每个要显示的字符,依次从虚拟终端缓冲区中以WORD为单位读取(低位字节是ASCII码,高8位是字符的属性),由于汉字是双字-节编码方式,所以这种操作是不可能显示出汉字的,只能显示出xxxx_putcs()是一个一个VGA字符.


    要解决的问题∶
    确保在do_con_write( )时uni□pc转换不会改变原有编码。一个很直接的实现方式就是加载一个我们自己定制的UNICODE映射表,
    loadunimapdirect.uni,或者直接把direct.uni置为核心的缺省映射表。


    针对如上问题,我们要做的第一个尝试方案是如下。
    首先需要在核心中加载汉字字库,然后修改fbcon_cfb8_putcs()函数,在fbcon_cfb8_putcs(
    )中一次读两个WORD,检查这两个WORD的低位字节是否能拼成一个汉字,如果发现能拼成一个汉字,就算出这个汉字在汉字字库中的偏移,然后把它当成一个16
    x 16的VGA字符来显示。


    试验的结果表明∶


       1. 能够输出汉字,但仍有许多不理想的地方,比如说,输出以半个汉字开始的一串汉字,则这半个汉字后面的汉字都会是乱码。这是半个汉字的问题。
       2. 光标移动会破坏汉字的显示。表现为,光标移动过的汉字会变成乱码。这是因为光标的更新是通过xxxx_putc( )函数来完成的。


    xxxx_putc( )函数与xxxx_putcs(
    )函数实现的功能类似,但是xxxx_putc()函数只刷新一个字符而不是一个字符串,因而xxxx_putc()的输入参数是一个整数,而不是一个字符串的-地址。Xxxx_putc(
    )函数的声明如下∶void fbcon_cfb8_putc(struct vc_data *conp, struct display *p, int
    c, int yy, int xx)


        下一个尝试方案就是同时修改xxxx_putcs(
    )函数和xxxx_putc()函数。为了解决半个汉字的问题,每一次输出之前,都从屏幕当前行的起始位置开始扫描,以确定要输出的字符是否落在半个汉字的位置-上。如果是半个汉字的位置,则进行相应的调整,即从向前移动一个字节的位置开始输出。
        这个方案有一个困难,即xxxx_putc( )函数不用缓冲区的地址,而是用一个整数作为参数。所以xxxx_putc(
    )无法直接利用相邻的字符来判别该定符是否是汉字。
        解决方案是,利用xxxx_putc( )的光标位置参数(yy,
    xx),可以逆推出该字符在缓冲区中的位置。但仍有一些小麻烦,在Linux的虚拟终端下,用户可能会上卷该屏幕(shift +
    pageup),导致光标的y座标和相应字符在缓冲区的行数不一致。相应的解决方案是,在逆推的过程中,考虑卷屏的参量。


    这样一来,我们就又进了一步,得到了一个相对更好的版本。但仍有问题没有解决。敲入turbonetcfg,会发现菜单的边框字符也被当成汉字显示。这是因为,-这种边框字符是扩展字符,也使用了字符的第8位,因而被当作汉字来显示。例如,单线一的制表符内码为0xC4,当连成一条长线就是由一连串0xC4组成,而0x-C4C4正是汉字哪。于是水平的制表符被一连串的哪字替代了。要解决这个问题就非常不容易了,因为制表符的种类比较多,而且垂直制表符与其后面字符的组合型式又-多种多样,因而很难判断出相应位置的字符是不是制表符,从理论上说,无论采取什么样的排除算法,都必然存在误判的情况,因为总存在二义性,没有充足的条件来推断-出当前字符究竟是制表符还是汉字。


    我们一方面寻找更好的排除组合算法,一方面试图寻找其它的解决方案。要想从根本上解决定个问题,必须利用其它的辅助信息,仅仅从缓冲区的字符来判断是不够的。
        经过一番努力,我们发现,在UNIX中使用扩展字符时,都要先输出字符转义序列(Escape
    sequence)来切换当前字符集。字符转义序列是以控制字符Esc为首的控制命令,在UNIX的虚拟终端中完成终端控制命令,这种命令包括,移动光标座标、-卷屏、删除、切换字符集等等。也就是说在输出代表制表符的字符串之前,通常是要先输出特定的字符转义序列。
    在console.c里,有根据字符转义序列命令来记录字符状态的变量。结合该变量提供的信息,就可以非常干净地把制表符与汉字区别开来。


        在如上思路的指引下,我们又产生了新的解决方案。经过改动得到了另一各版本.


    在这个新版本上,turbonetcfg在初次绘制的时候,制表符与汉字被清晰地区分开来,结果是非常正确的。但还有新的问题存在∶turbonetcfg
    在重绘的时候(如切换虚拟终端或是移动鼠标光标的时候),制表符还是变成了汉字,因为重绘完全依赖于缓冲区,而这时用来记录字符集状态的变量并不反映当前字符集-状态。问题还是没有最终解决。我们又回到了起点。∶(
    看来问题的最终解决手段必须是把字符集的状态伴随每一个字符存在缓冲区中。让我们来研究一下缓冲区的结构。每一个字符占用16bit的缓冲区,低8位是ASCI-I值,完全被利用,高8位包含前景颜色和背景颜色的属性,也没有多余的空间可以利用。因而只能另外开辟新的缓冲区。为了保持一致性,我们决定在原来的缓冲区后面-添加相同大小的缓冲区,用来存放是否是汉字的信息。


    也许有读者会问,我们只需要为每个字符添加一bit的信息来标志是否是汉字就足够了,为什么还要开辟与原缓冲区大小相同的双倍缓冲区,是不是太浪费呢?我们先放-下这个问题,稍后再作回答。


    其实,如果再添加一bit来标志是当前字符是汉字的左半边还是右半边的话,就会省去扫描屏幕上当前整行字符串的工作,这样一来,编程会更简单。但是有读者会问,-即使是这样,使用8bit总够用了吧?为什么还要使用16bit呢?
        我们的作法是∶用低8位来存放汉字另外一半的内码,用高8位中的2
    bit来存放上面所讲的辅助信息,高8位的剩余6位可以用来存放汉字或其它编码方式(如BIG5或日文、韩文)的信息,从而使我们可以实现同屏显示多种双字节语-言的字符而不会有相互干扰。另外,在编程时,双倍缓冲也比较容易计算。这样我们就回答了如上的两个问题。
        迄今为止,我们有了一套彻底解决汉字和制表符相互干扰、半个汉字的刷新、重绘等问题的方案。剩下的就是具体编程实现的问题了。
        但是,由于Framebuffer的驱动很多,修改每一个驱动的xxxx_putc()函数和xxxx_putcs(
    )函数会是一项不小的工作,而且,改动驱动程序后,每种驱动的测试也是很麻烦的,尤其是对于有硬件加速的显卡,修改和测试会更不容易。那么,存不存在一种不需要-修改显卡驱动程序的方法呢?
        经过努力,我们发现,可以在调用xxxx_putcs(
    )或xxxx_putc()函数输出汉字之前,修改vga字库的指针使其指向所需显示的汉字在汉字字库中的位置,即把一个汉字当成两个vga
    ASCII字符输出。也就是说,在内核中存在两个字库,一个是原有的vga字符字库,另一个是汉字字库,当我们需要输出汉字的时候,就把vga字库的指针指向汉-字字库的相应位置,汉字输出完之后,再把该指针指向vga字库的原有位置。
       这样一来,我们只需要修改fbcon.c和console.c,其中console.c负责维护双倍缓冲区,把每一个字符的信息存入附加的缓冲区;
    而fbcon.c负责利用双倍缓冲区中附加的信息,调整vga字库的指针,调用底层的显示驱动程序。这里还有几个需要注意的地方∶


       1. 由于屏幕重绘等原因,调用底层驱动xxxx_putc(
       )和xxxx_putcs()的地方有多处。我们作了两个函数分别包装这两个调用,完成替换字库、调用xxxx_putcs( )或xxxx_putc(
       )、恢复字库等功能。
       2. 为了实现向上滚屏(shift + pageup)时也能看到汉字,我们需要作另外的修改。
           Linux 在设计虚拟终端的时候,提供了回顾被卷出屏幕以外的信息的功能,这就是用热键来向上滚屏(shift +
       pageup)。当前被使用的虚拟终端拥有一个公共的缓冲区(soft
       back),用来存放被滚出屏幕以外的信息。当切换虚拟终端的时候,公共缓冲区的内容会被清除而被新的虚拟终端使用。向上滚屏的时候,显示的是公共缓冲区中的内-容。因此,如果我们想在向上滚屏的时候看到汉字,公共缓冲区也必须加倍,以确保没有信息丢失。当滚出屏幕的信息向公共缓冲区填写的时候,必须把相应的附加信息也-填写进公共缓冲区的附加区域。
       这就要求fbcon.c必须懂得利用公共缓冲区的附加信息。
           当然,有另外一种偷懒的方法,那就是不允许用户向上滚屏,从而避免对公区缓冲区的处理。
       3. 把不同的编码方式(GB、BIG5、日文和韩文)写成不同的module,以实现动态加载,从而使得扩展新的编码方式不需要重新编译核心。


    测试


    本文实现的Kernel Patch文件(patch.kernel.chinese)可以从http://www.turbolinux.com.cn下载。Cd
    /usr/src/(该目录下应有Linux核心源程序所在的目录linux/) patch -p0 -b <
    patch.kernel.chinesemake menuconfig 请选择Console drivers选项中的


    〔*〕 Double Byte Character Display Support(EXPERIMENTAL)
    〔*〕 Double Byte GB encode (module only)
    〔*〕 VESA VGA graphics console
    <*> Virtual Frame Buffer support (ONLY FOR TESTING!)
    <*> 8 bpp packed pixels support
    <*> 16 bpp packed pixels support
    <*> VGA characters/attributes support
    〔*〕 Select compiled-in fonts
    〔*〕VGA 8x8 font
    〔*〕VGA 8x16 font


    make dep
    make bzImage
    make modules
    make install
    make modules_install


    然后用新的核心启动。


    Insmod encode-gb.o


    *四、其它*


    (一)   设置FrameBuffer
        FrameBuffer,可以译作"帧缓冲",有时简称为
    fbdrv,基于fbdrv的console也被称之为fbcon。这是一种独立于硬件的抽象图形设备。FrameBuffer的优点在于其高度的可移植
    性、易使用性、稳定性。使用Linux内核的
    FrameBuffer驱动(vesafb),可以轻松支持到1024X768X32bpp以上的分辩率。而且目前可得到的绝大多数linux版本所发行
    的内核中,已经预编译了FrameBuffer支持,通常不需要重新编译内核就可以使用。所以FrameBuffer也是zhcon推荐使用的驱动方式。


    进入FrameBuffer可以简单地在系统启动时向kernel传送vga=mode-number的参数来激活FrameBuffer设备,如:
    lilo:linux vga=305
    将会启动1024x768x8bpp模式。


               640x480    800x600    1024x768    1280x1024
    8 bpp      769          771       773        775
    16 bpp     785          788       791        794
    32 bpp     786          789       792        795


    (二)   要使linux缺省进入FrameBuffer,可以修改/etc/lilo.conf,加入一下语句:
    vga=0x303
    退出编辑,执行:
    lilo -v
    重新启动linux,可以使其进入800x600的256色模式。
    grub也是一样,在grub.conf中的kernel行后面写上vga=xxx就行了,也可以用vga=ask,让系统启动的时候询问你用多大的分辨率


    (三)我编译内核时,选择framebuffer模式,启动时屏幕上有一企鹅图片,不知这是如何造成的这个图片可以去掉或改动吗?
    可以将drivers/video/fbcon.c: fbcon_setup()中if (logo) { } 代码去掉。

  • 安装VMware tools

    2009-01-07 19:10:13

    1、启动并进入Linux系统。
    2、然后选择虚拟机菜单中的“虚拟机/安装VMware-Tools”,此时就会有把VMware-tools文件映像到CD-ROM中。
    3、把“VMwareTools-6.0.2-59824.i386.rpm,VMwareTools-6.0.2-59824.tar.gz”文件复制到自己的需要的位置中,然后选择一种安装方式。在此我选VMwareTools-6.0.2-59824.tar.gz。
    4、解压
    # tar -zxvf VmwareTools-6.0.2-59824.tar.gz

    5.
    #rpm -ivh ./vmwaretools-5.5.2.-29772.i386.rpm

    6.进入vmware-tools-distrib.

     

    7../vmwre-install.pl //开始安装中间会出现一些确认项,一直回车

  • 虚拟机VMware+Red Hat上搭建arm9交叉开发环境

    2009-01-07 19:08:38

    首先说下我使用的环境

    主机:XP SP2 虚拟机:VMware Workstation 6.0

    虚拟机上的系统:Red Hat9.0

    开发板:英蓓特公司的EDUKIT-III ARM9


    第一步:下载安装VMware Workstation 6.0

    1.下载地址:http://12.duote.net/ha_vmware.exe

    注册号:JHXUR-G0M88-GA44V-4MRN6

    2.安装VMware Workstation 6.0

    可以安装在任何路径,安装过程中只需要下一步就可以了

    安装完成之后会在桌面出现“VMware Workstation”的可

    执行文件的快捷图标。

    3.创建虚拟机环境:

    运行VMware Workstation,双击图中的“New Virtual Machine”,依次单击下一步,直到出现要求选择操作系统的

    界面,选择“linux" Version 选择“Other Linux 2.6x kernel,到提示你虚拟机要以什么方式和主机进行连接时你选

    择以NAT方式,然后依次点击下一步,直到要求选择磁盘容量,把Disk size 修改为10GB,注意这里的“Allocate all

    disk space now”不要选中(选中的话,表示所分配的空间都被此虚拟机占用,WINDOWS 无法使用这10GB 的空

    间。不选中就表示虚拟机是动态调整的,例如:虚拟机只用到5GB,另外的5GB 还是可以被WINDOW 使用的)。选

    择“完成”后就完成虚拟机环境的创建。


    第二步:下载Red Hat9.0镜像文件

    下载地址:

    红帽子公司官方下载点:

    Disk 1:http://ftp.redhat.com/pub/redhat/linux/9/en/iso/i386/shrike-i386-disc1.iso

    Disk 2:http://ftp.redhat.com/pub/redhat/linux/9/en/iso/i386/shrike-i386-disc2.iso

    Disk 3:http://ftp.redhat.com/pub/redhat/linux/9/en/iso/i386/shrike-i386-disc3.iso

    第三步:安装Red Hat9.0

    虚拟机新建好后在工具栏那选择虚拟机--设置--选择CD-ROM--选择使用ISO镜像--在

    下方的下拉栏里找到shrike-i386-disc1.iso

    并确定保存

    然后打开虚拟机这时你就可以进入到Red Hat9.0的安装界面了

    安装Red Hat9.0很简单的了,相信大家都会的了,这里我就不再说了

    第四步:建立主机和虚拟机之间的通信

    1.安装VMware Tools

    安装VMware Tools可以实现鼠标在虚拟机环境和WINDOWS 环境的方便切换(如果没有安装此工具,鼠标从虚拟机

    的Linux 环境中切换到WINDOWS 下,需要同时按Ctrl+Alt键,安装后鼠标可以直接移出);还可以使Linux 访问和

    操作WINDOWS 的目录。在工具栏那选择虚拟机--安装VMware Tools…,选择之后,桌面中的光盘图标变为

    VMware Tools,双击此光盘图标, 会看到两个文件: VMwareTools-5.0.0-13124.i386.rpm 和

    VMwareTools-5.0.0-13124.tar.gz。这里的安装有两种方法:

    (1)直接双击VMwareTools-5.0.0-13124.i386.rpm 开始运行,完成之后打开终端,

    执行vmware-config-tools.pl,开始安装,中间会出现一些确认选项,一直回车,直到出现设置屏幕大小的,选择一

    个然后回车(如选择3,1024×768),继续直到完成安装。

    (2)打开终端, cd 到/media/cdrom/ ( 此处是光盘所在的位置, 在此位置下应该有

    VMwareTools-5.0.0-13124.i386.rpm 和VMwareTools-5.0.0-13124.tar.gz 两个文件文件),

    执行如下命令:

    cp VMwareTools-5.0.0-13124.tar.gz /tmp //拷贝文件到tmp 目录下

    cd /tmp //CD 到tmp 目录下

    tar xzf VMwareTools-5.0.0-13124.tar.gz //解压文件

    cd /vmware-tools-distrib //CD到vmware-tools-distrib 目录下

    ./vmwre-install.pl //开始安装中间会出现一些确认项,一直回车

    2.设置共享文件

    共享文件的设置有两种方法:

    (1)在工具栏选择虚拟机--设置,选择Options\Share Folders,文件夹共享选择“总是启用”

    添加一个共享文件,如在Linux共享名share,WINDOWS 端的Host Folder 为:D:\os_share,打开终端,

    在/mnt/hgfs/share 目录下就可以访问到D:\os_share 目录下的文件了。

    (2)mount 方式

    把WINDOWS 系统下的某个文件共享,然后通过mount 命令把此文件共享到Linux 目录下。如:mount –t smbfs

    //172.16.53.214/test /mnt/share –o username=your_user_name,workgroup=your_nt_domain这样就

    把共享的test 目录文件共享到Linux 目录下的/mnt/share 中了,在Linux 中可以操作此目录中的文件了。其中

    172.16.53.214 是本机的IP 地址。

    第五步:为虚拟机添加串口

    如果你现在已经启动了Red Hat9.0的话请先关闭系统

    关闭后在工具栏那选择虚拟机--设置--点击ADD--选择seria port--保存退出

    第六步:配置minicom

    进入到minicom配置界面后选择 :Serial port setup

    然后按照下面的设置下就OK了

    A - Serial Device : :/dev/ttyS0
    B - Lockfile Location : /var/lock
    C - Callin Program :
    D - Callout Program :
    E - Bps/Par/Bits : 115200 8N1
    F - Hardware Flow Control : No
    G - Software Flow Control : No

    设置好要记得保存哦

    选择这项是保存:Save setup as dfl

    第七步:安装arm-linux-gcc编译器

    我买开发板的时候光盘上已经给有编译器了

    所以我的不需要去下载

    没有的就自己去下载吧

    我使用编译器版本分别是arm-linux-gcc-2.95.3 arm-linux-gcc-3.3 .2 arm-linux-gcc-3.4.1

    把这三个编译器的压缩包放到你的home目录下去

    我的是放在/home/xhylyx/qq2440目录下

    然后我们cd进入到根目录下分别执行

    root@xhylyx-desktop:/# tar xvzf /home/xhylyx/qq2440/arm-linux-gcc-2.95.3.tgz

    root@xhylyx-desktop:/# tar xvzf /home/xhylyx/qq2440/arm-linux-gcc-3.3.2.tgz

    root@xhylyx-desktop:/# tar xvzf /home/xhylyx/qq2440/arm-linux-gcc-3.4.1.tgz

    解压完后会在/usr/local目录下生成一个arm文件夹

    如果没有则是你解压的路径不正确

    把交叉编译器的路径加入到PATH,以方便使用:

    root@xhylyx-desktop:/#gedit /root/.bashrc

    编辑/root/.bashrc 文件,在最后一行

    export PATH=$PATH:/usr/loca/arm/3.4.1/bin

    保存退出

    我们重启下Red Hat9.0使以上设置生效

    重启后

    xhylyx@xhylyx-desktop:~$ arm-linux-gcc -v

    会出现如下信息,这说明交叉编译环境已经成功安装

    Reading specs from /usr/local/arm/3.4.1/lib/gcc/arm-linux/3.4.1/specs
    Configured with: /work/crosstool-0.27/build/arm-linux/gcc-3.4.1-glibc-2.3.2/gcc-3.4.1/configure --target=arm-linux --host=i686-host_pc-linux-gnu --prefix=/usr/local/arm/3.4.1 --with-headers=/usr/local/arm/3.4.1/arm-linux/include --with-local-prefix=/usr/local/arm/3.4.1/arm-linux --disable-nls --enable-threads=posix --enable-symvers=gnu --enable-__cxa_atexit --enable-languages=c,c++ --enable-shared --enable-c99 --enable-long-long
    Thread model: posix
    gcc version 3.4.1

    第八步:Red Hat9.0和虚拟机进行连接

    连接好电源,串口线,网线

    经过上面设置后在终端下以root用户执行minicom

    这时你就可以进入到开发板了

  • linux 下建立tftp server

    2009-01-07 19:05:41

    linux 下建立tftp server
    2006-08-25 20:50

    TFTP是用来下载远程文件的最简单网络协议,它其于UDP协议而实现。嵌入式linux的tftp开发环境包括两个方面:一是linux服务器端的tftp-server支持,二是嵌入式目标系统的tftp-client支持。因为u-boot本身内置支持tftp-client,所以嵌入式目标系统端就不用配置了。下面就详细介绍一下linux服务器端tftp-server的配置。

    在redhat 9.0的第三张光盘中,有tftp-server的安装rpm包。

    (1)安装

    #mount –t iso9660 /dev/hdc /mnt/cdrom //挂载光盘

    #rpm -ivh tftp-server-0.32-4.i386.rpm //安装

    #umount /mnt/cdrom //卸载光盘

    (2)修改文件

    在linux下,不管使用的是哪一种super-server,inetd或者xinetd,默认情况下TFTP服务是禁用的,所以要修改文件来开启服务。

    根据(1)的安装方法,可以修改文件/etc/xinetd.d/tftp。主要是设置TFTP服务器的根目录,开启服务。修改后的文件如下:

    service tftp
    {     socket_type               =dgram
          protocol                  =udp
          wait                      =yes
           user                     =root
           server                   =/usr/sbin/in.tftpd
           server_args              =-s  /home/lqm/tftpboot -c
           disable                  =no
           per_source               =11
           cps                      =100 2
           flags                    =IPv4
    }

    说明:修改项server_args= -s -c,其中处可以改为你的tftp-server的根目录,参数-s指定chroot,-c指定了可以创建文件。

    (3)创建tftp根目录,启动tftp-server

    #mkdir  /home/lqm/tftpboot
     #chmod o+w       /home/lqm/tftpboot
     #service xinetd restart
    这样,tftp-server就启动了。你可以登陆本机测试以下,命令如下:
     #tftp     your-ip-address
      tftp>get 
      tftp>put 
      tftp>q
     #
  • tftp.dhcp .nfs配置

    2009-01-07 19:04:48

    tftp、dhcp、nfs配置

           在嵌入式linux产品开发调试阶段经常会把目标板根文件系统挂载到开发机的NFS导出目录,且经常要通过tftp下载内核镜像文件到目标板,这里会牵涉到几个linux服务的配置,很多新手会面对NFS,tftp的配置束手无策,我这里就简单的讲一下他们的配置(呵呵,我也是新手菜鸟呀)

    我们主要进行3种配置:

    1.       tftp配置

    2.       dhcp配置

    3.       nfs配置

    : tftp配置

          首先要安装tftp service:redhat9CD3里找到tftp-server-0.32-4.i386.rpm文件

          [root@vcom/]#  rpm –ivh tftp-server-0.32-4.i386.rpm     安装tftp service

          [root@vcom/]#  rpm –qv tftp-server-0.32-4.i386.rpm      查询安装是否成功

          [root@vcom/]#  vi /etc/xinetd.d/tftp                   修改该文件里的server_args配置项为你自己的tftpboot根目录,修改disable 配置为no .然后保存退出。

    我使用的tftp文件内容如下

          service tftp

    {

            disable = no

            socket_type             = dgram

            protocol                = udp

            wait                    = yes

            disable                  = no

            user                    = root

            server                  = /usr/sbin/in.tftpd

            server_args             = -s /tftpboot

            per_source              = 110

            cps                     = 100 2

            flags                   = IPv4

    }

    .dhcp配置

          首先要安装dhcp service :redhat9CD2里找到 dhcp-3.0pl1-23.i386.rpm文件

          [root@vcom/]#  rpm –ivh dhcp-3.0pl1-23.i386.rpm   安装dhcp

          [root@vcom/]#  rpm –qv dhcp-3.0pl1-23.i386.rpm    查询安装是否成功

          [root@vcom/]#  vi /etc/dhcpd.conf                 修改dhcpd配置

          注意dhcpd..conf默认状态安装在 /usr/share/doc/dhcp-3.0.1/dhcpd.conf.sample可以

    考贝到/etc/dhcpd.conf,在此基础上修改既可以。

    我使用的dhcpd.conf文件内容如下

    DDns-update-style interim;

    ignore client-updates;

    subnet 192.168.3.0 netmask 255.255.255.0 {

            dynamic-bootp-lease-length 20;

            range dynamic-bootp 192.168.3.19 192.168.3.35;

            option routers 192.168.3.26;

            option subnet-mask 255.255.255.0;

            option domain-name-servers  192.168.3.26;

            default-lease-time 10;

            max-lease-time 10;

            host test{

                    hardware ethernet 00:60:6e:42:ba:86;

                    fixed-address 192.168.3.27

                    option root-path "ndvd9026l/target";

                    filename "zImage.treeboot_debug";

            }

    }

    其中192.168.3.26就是开发机(也是服务器)IP地址,目标板的IP地址是192.168.3.27

    . 设置NFS:

          [root@vcom/]#  vi /etc/export

    添加  /ndvd9026l/target 192.168.3.0/255.255.255.0(rw,no_root_squash)

    . 启动服务:

    [root@vcom/]#  ntsysv                            启动相关服务

    [root@vcom/]#  service dhcpd start

    [root@vcom/]#  service nfs start

    [root@vcom/]#  service portmap start

    [root@vcom/]#  service xinted star

663/4<1234>
Open Toolbar