关于嵌入式文件系统
时间:2010-09-21 来源:BinChengfei
关于文件系统
4.1 友善之臂 mini2440 root_qtopia 文件系统启动过程分析
本文简介:
友善之臂提供的根文件系统十分具有创新意义,其功能之强大,先进,实用至今保持在
领先地位,
网友 kasim 对其作了详尽的剖析,
道出了很多
“秘密” 对于任何致力于嵌入式 Linux
,
开发的人员是不可多得的好资料,现整理如下。
原文网址:
http://www.arm9home.net/read.php?tid-1702.html
下面是这篇文章的内容,我们对此进行了简单的编辑和修改:
对于 mini2440 最新的 root_qtopia 文件系统启动过程,我在这里做了一些简单的分析,
和大家分享一下经验,不足之处也请大家及时指出。
其实,虽然 root_qtopia 这个文件系统的 GUI 是基于 Qtopia 的,但其初始化启动过程
却是由大部分由 busybox 完成,Qtopia(qpe)只是在启动的最后阶段被开启。
由于默认的内核命令行上有 init=/linuxrc, 因此,在文件系统被挂载后,运行的第一个程
序是根目录下的 linuxrc。 这是一个指向/bin/busybox 的链接,也就是说,系统起来后运行的
第一个程序也就是 busybox 本身。
这种情况下,busybox 首先将试图解析/etc/inittab 来获取进一步的初始化配置信息(参
考 busybox 源代码 init/init.c 中的 parse_inittab()函数)。而事实上,root_qtopia 中并没有/et
c/inittab 这个配置文件,根据 busybox 的逻辑,它将生成默认的配置
复制代码
1. static void parse_inittab(void)
2. {
3. #if ENABLE_FEATURE_USE_INITTAB
4. char *token[4];
5. parser_t *parser = config_open2("/etc/inittab", fopen_for_read);
6.
7. if (parser == NULL)
8. #endif
9. {
10. /* No inittab file -- set up some default behavior */
11. /* Reboot on Ctrl-Alt-Del */
12. new_init_action(CTRLALTDEL, "reboot", "");
13. /* Umount all filesystems on halt/reboot */
14. new_init_action(SHUTDOWN, "umount -a -r", "");
15. /* Swapoff on halt/reboot */
16. if (ENABLE_SWAPONOFF)
17. new_init_action(SHUTDOWN, "swapoff -a", "");
18. /* Prepare to restart init when a QUIT is received */
19. new_init_action(RESTART, "init", "");
20. /* Askfirst shell on tty1-4 */
21. new_init_action(ASKFIRST, bb_default_login_shell, "");
22. //TODO: VC_1 instead of ""? "" is console -> ctty problems -> angry users
23. new_init_action(ASKFIRST, bb_default_login_shell, VC_2);
24. new_init_action(ASKFIRST, bb_default_login_shell, VC_3);
25. new_init_action(ASKFIRST, bb_default_login_shell, VC_4);
26. /* sysinit */
27. new_init_action(SYSINIT, INIT_SCRIPT, "");
28. return;
29. }
其中,最重要的一个,就是 new_init_action(SYSINIT, INIT_SCRIPT, ""),也就决定了
接下去初始化的脚本是 INIT_SCRIPT 所定义的值。这个宏的默认值是"/etc/init.d/rcS".
下面是文件系统中/etc/init.d/rcS 的内容, 也是我们要分析的重点
复制代码
1.
#! /bin/sh
2.
3. PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:
4. runlevel=S
5. prevlevel=N
6. umask 022
7. export PATH runlevel prevlevel
8.
9.
#
10. # Trap CTRL-C &c only in this shell so we can interrupt subprocesses.
11. #
12. trap ":" INT QUIT TSTP
13. /bin/hostname FriendlyARM
14.
15. /bin/mount -n -t proc none /proc
16. /bin/mount -n -t sysfs none /sys
17. /bin/mount -n -t usbfs none /proc/bus/usb
18. /bin/mount -t ramfs none /dev
19.
20. echo /sbin/mdev > /proc/sys/kernel/hotplug
21. /sbin/mdev -s
22. /bin/hotplug
23. # mounting file system specified in /etc/fstab
24. mkdir -p /dev/pts
25. mkdir -p /dev/shm
26. /bin/mount -n -t devpts none /dev/pts -o mode=0622
27. /bin/mount -n -t tmpfs tmpfs /dev/shm
28. /bin/mount -n -t ramfs none /tmp
29. /bin/mount -n -t ramfs none /var
30. mkdir -p /var/empty
31. mkdir -p /var/log
32. mkdir -p /var/lock
33. mkdir -p /var/run
34. mkdir -p /var/tmp
35.
36. /sbin/hwclock -s
37.
38. syslogd
39. /etc/rc.d/init.d/netd start
40. echo " " > /dev/tty1
41. echo "Starting networking..." > /dev/tty1
42. sleep 1
43. /etc/rc.d/init.d/httpd start
44. echo " " > /dev/tty1
45. echo "Starting web server..." > /dev/tty1
46. sleep 1
47. /etc/rc.d/init.d/leds start
48. echo " " > /dev/tty1
49. echo "Starting leds service..." > /dev/tty1
50. echo " "
51. sleep 1
52.
53. /sbin/ifconfig lo 127.0.0.1
54. /etc/init.d/ifconfig-eth0
55.
56. /bin/qtopia &
57. echo " " > /dev/tty1
58. echo "Starting Qtopia, please waiting..." > /dev/tty1
下面就逐个来分析:
复制代码
1. PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:
2. runlevel=S
3. prevlevel=N
4. umask 022
5. export PATH runlevel prevlevel
为启动环境设置必要的环境变量:
复制代码
1.
/bin/hostname FriendlyARM
设置机器名字;:
复制代码
1. /bin/mount -n -t proc none /proc
2. /bin/mount -n -t sysfs none /sys
3. /bin/mount -n -t usbfs none /proc/bus/usb
4. /bin/mount -t ramfs none /dev
挂载“虚拟”文件系统“/proc”和“/sys”,并且在/dev 目录上挂载一个 ramfs,相当于
把原本 NAND Flash 上的只读的/dev 目录“覆盖”上一块可写的空的 SDRAM。
这里要注意的是,/sys 和挂载了 ramfs 的/dev 是正确创建设备节点的关键。对于 2.6.2
9 内核来说,已经没有了 devfs 的支持,创建设备节点只有通过两种办法由文件系统完成:
1) 制作文件系统镜像前用 mknod 手动创建好系统中所有的(包括可能有的)设备节点,
并把这些节点文件一起做进文件系统镜像中;
2)在文件系统初始化过程中,通过/sys 目录所输出的信息,在/dev 目录下动态的创建
系统中当前实际有的设备节点。
显然,方法 1)有很大的局限性,仅限于没有设备动态增加或减少的情况,不适用于很
多设备热插拔的情况,比如 U 盘,SD 卡等等。方法 2)是目前大多数 PC 上 Linux 的做法(基
于 udev 实现)。这种方法有两个前提: /sys 目录挂载和一个可写的/dev 目录。 这也就是为
什么我们在这里需要挂载/sys 和 ramfs 在/dev 目录上。事实上,这种方法最早就是为热插拔
设计的, 你可以理解为当系统启动是,所有设备一下子全部“插入”了进来。
这里有一点要说明的是,在文件系统初始化跑到这里之前,原本的/dev 目录下必须有
一个的设备节点:/dev/console。
其实,要搞清楚“程序”这种东西,没有什么好的办法,无非两个东西,一是看源代码,
二是看脚本(其实还是一个东西,看脚本也是为了看脚本调用了什么程序
复制代码
1. echo /sbin/mdev > /proc/sys/kernel/hotplug
2. /sbin/mdev -s
3. /bin/hotplug
这几个就是用来完成我上面所说的两个东西: 1)通过 mdev -s 在/dev 目录下建立必
要的设备节点; 2)设置内核的 hotplug handler 为 mdev, 即当设备热插拔时,由 mdev 接收
来自内核的消息并作出相应的回应, 比如挂载 U 盘。
对于 mdev,需要注意的是,文件系统里存在/etc/mdev.conf 文件,它包含了 mdev 的
配置信息。通过这个文件,我们可以自定义一些设备节点的名称或链接来满足特定的需要。这
是 root qtopia 中 mdev.conf 的内容:
复制代码
1. # system all-writable devices
2. full
0:0
0666
3. null
0:0
0666
4. ptmx
5. random
0:0
6. tty
0666
7. zero
0:0
0:0
0666
0:0
0666
0666
8.
9.
# console devices
10. tty[0-9]* 0:5 0660
11. vc/[0-9]* 0:5 0660
12.
13. # serial port devices
14. s3c2410_serial0 0:5 0666 =ttySAC0
15. s3c2410_serial1 0:5 0666 =ttySAC1
16. s3c2410_serial2 0:5 0666 =ttySAC2
17. s3c2410_serial3 0:5 0666 =ttySAC3
18.
19. # loop devices
20. loop[0-9]*
0:0
0660
=loop/
21.
22. # i2c devices
23. i2c-0 0:0 0666 =i2c/0
24. i2c-1 0:0 0666 =i2c/1
25.
26. # frame buffer devices
27. fb[0-9]
0:0
0666
28.
29. # input devices
30. mice
0:0
31. mouse.*
0:0
32. event.*
33. ts.*
0660
0:0
0:0
=input/
0660
0660
=input/
=input/
0660 =input/
>rtc
34.
35. # rtc devices
36. rtc0 0:0 0644
37. rtc[1-9] 0:0 0644
38.
39. # misc devices
40. mmcblk0p1
41. sda1
0:0
0:0
0600
0600
=sdcard */bin/hotplug
=udisk * /bin/hotplug
可 以 看 到 , 原 本 串 口 驱 动 注 册 的 设 备 名 是 s3c2410_serial0, s3c2410_serial1 和
s3c2410_serial2,而 mdev 则会在/dev 目录下对应生成 ttySAC0, ttySAC1 和 ttySAC2 以符合
应用程序对于串口设备名称的习惯。同样的,/dev/sdcard 和/dev/udisk 永远分别指向 SD 卡和
U 盘的第一个分区。(所以,用那些没有分区表的 SD 卡或 U 盘的兄弟知道原因了吧...)
复制代码
1. # mounting file system specified in /etc/fstab
2. mkdir -p /dev/pts
3. mkdir -p /dev/shm
4. /bin/mount -n -t devpts none /dev/pts -o mode=0622
5. /bin/mount -n -t tmpfs tmpfs /dev/shm
6. /bin/mount -n -t ramfs none /tmp
7. /bin/mount -n -t ramfs none /var
8. mkdir -p /var/empty
9. mkdir -p /var/log
10. mkdir -p /var/lock
11. mkdir -p /var/run
12. mkdir -p /var/tmp
就像注释中所说的,这是用来挂载其他一些常用的文件系统,并在/var 目录下(同样是
ramfs,可写的)新建必要的目录。
复制代码
1.
/sbin/hwclock -s
用来设定系统时间的,从硬件 RTC 中获取,要获取正确的时间,必须先设置好正确的
时间(如何设置 RTC 见用户手册说明),目前友善之臂的开发板出厂时并没有设置实际的时
间,而是系统默认的。
接下来就是启动系统服务了,包括 log 记录,网络, http server 和自定义的"跑马灯服
务"...
关于 mdev.conf 中的一点补充说明:
复制代码
1. # misc devices
2. mmcblk0p1
3. sda1
0:0
0:0
0600
0600
=sdcard */bin/hotplug
=udisk * /bin/hotplug
这两句配置的意思是当 SD 卡或者 U 盘插入/拔出时,将这个消息传递给自定义的热插
拔 handler, /bin/hotplug. 这个程序是友善之臂开发的用于自动挂载可移动设备的,目前是 SD
卡和 U 盘。它的逻辑很简单,将 SD 卡或者 U 盘的第一个分区作为 FAT/FAT32 挂载到/sdcard
或者/udisk.
但这也同时带来一个问题,当 SD 卡或者 U 盘上没有分区表或者第一个分区不是 FAT/
FAT32 格式的时候,它就玩不转了:)
这是/bin/hotplug 里的二进制数据片段,可以看到我上面说的逻辑:
000010d0h: 52 00 00 00 4D 00 00 00 00 00 00 00 41 00 00 00 ; R...M.......A...
000010e0h: 43 00 00 00 54 00 00 00 49 00 00 00 4F 00 00 00 ; C...T...I...O...
000010f0h: 4E 00 00 00 00 00 00 00 44 00 00 00 45 00 00 00 ; N.......D...E...
00001100h: 56 00 00 00 4E 00 00 00 41 00 00 00 4D 00 00 00 ; V...N...A...M...
00001110h: 45 00 00 00 00 00 00 00 61 00 00 00 64 00 00 00 ; E.......a...d...
00001120h: 64 00 00 00 00 00 00 00 72 00 00 00 65 00 00 00 ; d.......r...e...
00001130h: 6D 00 00 00 6F 00 00 00 76 00 00 00 65 00 00 00 ; m...o...v...e...
00001140h: 00 00 00 00 2F 00 00 00 64 00 00 00 65 00 00 00 ; ..../...d...e...
00001150h: 76 00 00 00 2F 00 00 00 75 00 00 00 64 00 00 00 ; v.../...u...d...
00001160h: 69 00 00 00 73 00 00 00 6B 00 00 00 00 00 00 00 ; i...s...k.......
00001170h: 2F 00 00 00 64 00 00 00 65 00 00 00 76 00 00 00 ; /...d...e...v...
00001180h: 2F 00 00 00 73 00 00 00 64 00 00 00 63 00 00 00 ; /...s...d...c...
00001190h: 61 00 00 00 72 00 00 00 64 00 00 00 00 00 00 00 ; a...r...d.......
000011a0h: 4D 00 00 00 44 00 00 00 45 00 00 00 56 00 00 00 ; M...D...E...V...
000011b0h: 00 00 00 00 6D 00 00 00 6D 00 00 00 63 00 00 00 ; ....m...m...c...
000011c0h: 62 00 00 00 6C 00 00 00 6B 00 00 00 30 00 00 00 ; b...l...k...0...
000011d0h: 70 00 00 00 31 00 00 00 00 00 00 00 73 00 00 00 ; p...1.......s...
000011e0h: 64 00 00 00 61 00 00 00 31 00 00 00 00 00 00 00 ; d...a...1.......
000011f0h: 76 00 00 00 66 00 00 00 61 00 00 00 74 00 00 00 ; v...f...a...t...
00001200h: 00 00 00 00 2F 00 00 00 64 00 00 00 65 00 00 00 ; ..../...d...e...
00001210h: 76 00 00 00 2F 00 00 00 77 00 00 00 61 00 00 00 ; v.../...w...a...
00001220h: 74 00 00 00 63 00 00 00 68 00 00 00 64 00 00 00 ; t...c...h...d...
00001230h: 6F 00 00 00 67 00 00 00 00 00 00 00 9A B2 01 81 ; o...g.......毑.?
00001240h: B0
; ?
复制代码
1. syslogd
2. /etc/rc.d/init.d/netd start
3. echo "
" > /dev/tty1
4. echo "Starting networking..." > /dev/tty1
5. sleep 1
6. /etc/rc.d/init.d/httpd start
7. echo "
8. echo "Starting web server..." > /dev/tty1
9. sleep 1
" > /dev/tty1
10. /etc/rc.d/init.d/leds start
11. echo "
" > /dev/tty1
12. echo "Starting leds service..." > /dev/tty1
13. echo "
"
14. sleep 1
启动一系列服务:
syslog - 用于记录内核和应用程序 debug 信息
netd - inetd, 一个挂载启动各种网络相关服务的看守进程
httpd - http server 看守进程
leds -
跑马灯看守进程
其中,inetd 的配置文件为/etc/inetd.conf,这是文件内容
复制代码
1. # /etc/inetd.conf: see inetd(8) for further informations.
2. echo
stream tcp
3. echo
dgram
udp
nowait
wait
root
root
internal
internal
4. daytime stream tcp
5. daytime dgram
6. time
stream tcp
7. time
dgram
nowait
udp
root
internal
wait root internal
nowait root internal
udp
wait
root
internal
8.
9.
# These are standard services.
10. #
11. ftp
stream
12. telnet
tcp
stream
nowait
tcp
root
nowait
/usr/sbin/ftpd
root
/usr/sbin/ftpd
/usr/sbin/telnetd
/usr/sbin/telnetd -i
可以看到,这里启动的网络服务有两个: 1)ftp server 和 2)telnet server。有关网络
服务的端口和协议等具体信息,可以参考/etc/services, /etc/protocols
再接下来
复制代码
1. /sbin/ifconfig lo 127.0.0.1
2. /etc/init.d/ifconfig-eth0
配置网络设备(网卡):
1)设定本机回环地址为 127.0.0.1
2)运行网卡设置脚本/etc/init.d/ifconfig-eth0
这是/etc/init.d/ifconfig-eth0 的内容, 加入了我的一些注释
复制代码
1.
#!/bin/sh
2.
3.
echo -n Try to bring eth0 interface up......>/dev/ttySAC0
4.
5. #判断/etc/eth0-setting 文件是否存在
6. if [ -f /etc/eth0-setting ] ; then
7.
8.
#读取配置文件信息
source /etc/eth0-setting
9.
10.
11.
#如果根文件系统为 nfs,则说明网卡已经配置 OK,这里什么都不需要配置了
if grep -q "^/dev/root / nfs " /etc/mtab ; then
12.
echo -n NFS root ... > /dev/ttySAC0
#否则,根据配置文件中的 MAC, IP, Mask 和 Gateway 通过 ifconfig 命令相应地配置网卡
13.
14.
else
15. ifconfig eth0 down
16. ifconfig eth0 hw ether $MAC
17. ifconfig eth0 $IP netmask $Mask up
18. route add default gw $Gateway
19.
fi
20.
21.
22.
#将配置文件中的 DNS 设置写入/etc/resolv.conf 使之生效
echo nameserver $DNS > /etc/resolv.conf
23. #配置文件不存在,使用默认配置
24. else
25.
26.
#如果根文件系统为 nfs,则说明网卡已经配置 OK,这里什么都不需要配置了
27.
if grep -q "^/dev/root / nfs " /etc/mtab ; then
28.
echo -n NFS root ... > /dev/ttySAC0
29.
else
#将网卡的 IP 地址设定为 192.168.1.230
30.
31. /sbin/ifconfig eth0 192.168.1.230 netmask 255.255.255.0 up
32. fi
33. fi
34.
35. echo Done > /dev/ttySAC0
可以看到,NFS 自动识别就是靠判断/etc/mtab 中是否有 nfs 的挂载记录实现的。
这是 root qtopia 文件系统中/etc/eth0-settings 文件
复制代码
1. IP=192.168.1.230
2. Mask=255.255.255.0
3. Gateway=192.168.1.1
4. DNS=192.168.1.1
5. MAC=08:90:90:90:90:90
终于到最后了,启动 Qtopia GUI 环境
复制代码
1. /bin/qtopia &
2. echo "
3. echo "Starting Qtopia, please waiting..." > /dev/tty1
" > /dev/tty1
可以看到,这里 Qtopia 是通过运行/bin/qtopia 来启动的。事实上,/bin/qtopia 也是一
个脚本,它的任务是设定 Qtopia 运行必要的环境, 最后通过调用 qpe 可执行文件真正启动
Qtopia。这是它的全部内容,我加入了一些注释:
复制代码
1.
#!/bin/sh
2.
3. #tslib 环境变量设置,包括了 touchscreen 设备文件,tslib 配置文件,tslib plug-in 位置和 touchscreen 校准数据
4. export TSLIB_TSDEVICE=/dev/input/event0
5. export TSLIB_CONFFILE=/usr/local/etc/ts.conf
6. export TSLIB_PLUGINDIR=/usr/local/lib/ts
7. export TSLIB_CALIBFILE=/etc/pointercal
8. #Qtopia 环境变量设置,设定了 Qtopia 主要文件位置
9. export QTDIR=/opt/Qtopia
文件
10. export QPEDIR=/opt/Qtopia
11. #设定 PATH 和 LD_LIBRARY_PATH 以包含 Qtopia 的可执行文件和共享库文件,方便 Qtopia 正确运行
12. export PATH=$QTDIR/bin:$PATH
13. export LD_LIBRARY_PATH=$QTDIR/lib:/usr/local/lib:$LD_LIBRARY_PATH
14.
15. #通过判断/sys/devices/virtual/input/input0/uevent 中是否包含 touchscreen 信息使 Qtopia 自动识别 touchscreen
和 USB 鼠标
16. TS_INFO_FILE=/sys/devices/virtual/input/input0/uevent
17. if [ -e $TS_INFO_FILE -a "/bin/grep -q TouchScreen < $TS_INFO_FILE" ]; then
18. export QWS_MOUSE_PROTO="TPanel:/dev/input/event0 USB:/dev/input/mice"
19. if [ -e /etc/pointercal -a ! -s /etc/pointercal ] ; then
20.
21.
rm /etc/pointercal
fi
22. else
23. export QWS_MOUSE_PROTO="USB:/dev/input/mice"
24. >/etc/pointercal
25. fi
26. unset TS_INFO_FILE
27.
28. export QWS_KEYBOARD=TTY:/dev/tty1
29. export KDEDIR=/opt/kde
30.
31. export HOME=/root
32.
33. #通过调用/opt/Qtopia/bin/qpe 真正启动 Qtopia
34. exec $QPEDIR/bin/qpe 1>/dev/null 2>/dev/null
到此为止,文件系统从初始化到最终启动 Qtopia GUI 环境的全部过程就结束了,大家
可以看到,友善之臂的“小秘密”其实都在这里,说穿了很简单:)只要大家能够静下心来认真看
看脚本,看看源代码,加上一些背景知识的了解,搞清楚一个嵌入式系统就这么简单
4.2 使用 Busybox 构建文件系统
说明:本文主要基于网友 huang-tomey 所写的“yaffs2 文件系统移植”一文,这里详细
介绍了仅使用 busybox 建立基本根文件系统的过程,实际上根据开发和项目的需要,一般基本
的文件系统是远远不够的,
友善之臂提供的根文件系统是面向嵌入式爱好者精心配置的一个典
型示范,详细介绍可以参考 kasim 网友所写的“mini2440 root_qtopia 文件系统启动过程分析”
一文
原文网址:
http://huang-tomey.blog.163.com/blog/static/1247505732009916437175/
下面是使用 busybox 制作基本根文件系统的详细步骤
4.2.1 下载 busybox 源代码
从
http://www.busybox.net/downloads/ 下 载 busybox , 这 里 下 载 的 是
busy busybox-1.13.3.tar.gz,这和当前mini2440 开发板使用的版本是一致的。
4.2.2 根文件系统目录说明
嵌入式 Linux 中都需要构建根文件系统,构建根文件系统的规则在 FHS(Filesystem
Hierarchy Standard)文档中,下面是根文件系统顶层目录。
目录
内容
bin
存放所有用户都可以使用的、基本的命令。
sbin
存放的是基本的系统命令,它们用于启动系统、修复系统等。
usr
里面存放的是共享、只读的程序和数据。
proc
这是个空目录,常作为 proc 文件系统的挂载点。
dev
该目录存放设备文件和其它特殊文件。
etc
存放系统配置文件,包括启动文件。
lib
存放共享库和可加载块(即驱动程序),共享库用于启动系统、运行根文件系统中的可
boot
home
mnt
opt
root
tmp
var
执行程序。
引导加载程序使用的静态文件
用户主目录,包括供服务账号锁使用的主目录,如 FTP
用于临时挂接某个文件系统的挂接点,通常是空目录。也可以在里面创建空的子目
录。
给主机额外安装软件所摆放的目录。
root 用户的主目录
存放临时文件,通常是空目录。
存放可变的数据。
4.2.3 建立根文件系统目录
进入到/opt/studyarm 目录,新建建立根文件系统目录的脚本文件 create_rootfs_bash,使
用命令 chmod +x create_rootfs_bash 改变文件的可执行权限,./create_rootfs_bash 运行脚本,就
完成了根文件系统目录的创建。
#!/bin/sh
echo "------Create rootfs directons start...--------"
mkdir rootfs
cd rootfs
echo "--------Create root,dev....----------"
mkdir root dev etc boot tmp var sys proc lib mnt home
mkdir etc/init.d etc/rc.d etc/sysconfig
mkdir usr/sbin usr/bin usr/lib usr/modules
echo "make node in dev/console dev/null"
mknod -m 600 dev/console c 5 1
mknod -m 600 dev/null
c13
mkdir mnt/etc mnt/jffs2 mnt/yaffs mnt/data mnt/temp
mkdir var/lib var/lock var/run var/tmp
chmod 1777 tmp
chmod 1777 var/tmp
echo "-------make direction done---------"
改变了 tmp 目录的使用权,让它开启 sticky 位,为 tmp 目录的使用权开启此位,可确保
tmp 目录底下建立的文件,只有建立它的用户有权删除。尽管嵌入式系统多半是单用户,不过
有些嵌入式应用不一定用 root 的权限来执行,因此需要遵照根文件系统权限位的基本规定来
设计。
4.2.4 建立动态链接库
动态链接库直接用友善之臂的,先解压友善之臂的根文件包,拷贝 lib 的内容到新建的
根文件目录 lib 内。
cd /mnt/hgfs/share
tar –zxvf root_qtopia.tgz –C /opt/studyarm
cp –rfd /opt/studyarm/root_qtopia/lib/* /opt/studyarm/rootfs/lib/*
4.2.5 交叉编译 Bosybox
Bosybox 是一个遵循 GPL v2 协议的开源项目,它在编写过程总对文件大小进行优化,
并考虑了系统资源有限(比如内存等)的情况,使用 Busybox 可以自动生成根文件系统所需的
bin、sbin、usr 目录和 linuxrc 文件。
1、解压 busybox
cd /mnt/hgfs/share
tar –zxvf busybox-1.13.3.tar.tgz –C /opt/studyarm
2、进入源码,修改 Makefile 文件:
cd /opt/studyarm/busybox-1.13.3
修改:
CROSS_COMPILE ?=arm-linux-
ARCH ?=arm //第 189 行
//第 164 行
3、配置 busybox
提示:友善之臂已经在光盘中提供了 busybox 的源代码包,在光盘\linux 目录中,文件
名为:busybox-1.13.3-mini2440.tgz(用户手册 5.4 章节介绍了解压安装的方法)
,解压后里面包
含了友善之臂提供的缺省配置文件:fa_config(输入命令“cp fa.config .config”可以调用该配
置),一般用户直接使用缺省文件就可以了,这样生成的 busybox 和 root_qtopia 中的是完全一
致的。但为了对它的配置了解更多一些,可以参考原文作者的如下步骤:
输入 make menuconfig 进行配置
(1)、Busybox Settings--->
General Configuration--->
[*] Show verbose applet usage messages
[*] Store applet usage messages in compressed form
[*] Support –install [-s] to install applet links at runtime
[*] Enable locale support(system needs locale for this to work)
[*] Support for –long-options
[*] Use the devpts filesystem for unix98 PTYs
[*] Support writing pidfiles
[*] Runtime SUID/SGID configuration via /etc/busybox.config
[*] Suppress warning message if /etc/busybox.conf is not readable
Build Options--->
[*] Build BusyBox as a static binary(no shared libs)
[*] Build with Large File Support(for accessing files>2GB)
Installation Options->
[]Don’t use /usr
Applets links (as soft-links) --->
(./_install) BusyBox installation prefix
Busybox Library Tuning --->
(6)Minimum password legth
(2)MD5:Trade Bytes for Speed
[*]Fsater /proc scanning code(+100bytes)
[*]Command line editing
(1024)Maximum length of input
[*] vi-style line editing commands
(15) History size
[*] History saving
[*] Tab completion
[*]Fancy shell prompts
(4) Copy buffer size ,in kilobytes
[*]Use ioctl names rather than hex values in error messages
[*]Support infiniband HW
(2)、Linux Module Utilities--->
(/lib/modules)Default directory containing modules
(modules.dep)Default name of modules.dep
[*] insmod
[*] rmmod
[*] lsmod
[*] modprobe
-----options common to multiple modutils
[ ] support version 2.2/2.4 Linux kernels
[*]Support tainted module checking with new kernels
[*]Support for module .aliases file
[*] support for modules.symbols file
(3)、在 busybox 中配置对 dev 下设备类型的支持
dev 的创建有三种方法:
手动创建:在制作根文件系统的时候,就在 dev 目录下创建好要使用的设备文件,系统
挂接根文件系统后,就可以使用 dev 目录下的设备文件了。
使用 devfs 文件系统:这种方法已经过时,具有不确定的设备映射、没有足够的主/次设
备号、devfs 消耗大量的内存。
udev:它是个用户程序,能根据系统中硬件设备的状态动态的更新设备文件,包括设备
文件的创建、删除等。它的操作相对复杂,但灵活性很高
mdev 是 busybox 自带的一个简化版的 udev,适合于嵌入式的应用埸合。其具有使用简
单的特点。它的作用,就是在系统启动和热插拔或动态加载驱动程序时,自动产生驱动程序所
需的节点文件。在以 busybox 为基础构建嵌入式 linux 的根文件系统时,使用它是最优的选择。
下面的选项将增加对 mdev 的支持。
Linux System Utilities --->
[*]Support /etc/mdev.conf
[*]Support command execution at device addition/removal
4、编译 busybox
编译 busybox 到指定目录:
cd /opt/studyarm/busybox-1.13.3
make CONFIG_PREFIX=/opt/studyarm/rootfs install
在 rootfs 目录下会生成目录 bin、sbin、usr 和文件 linuxrc 的内容。
4.2.6 建立 etc 目录下的配置文件
1、etc/mdev.conf 文件,内容为空。
2、拷贝主机 etc 目录下的 passwd、group、shadow 文件到 rootfs/etc 目录下。
3、etc/sysconfig 目录下新建文件 HOSTNAME,内容为”H3-Studio”
。
4、etc/inittab 文件:
#etc/inittab
::sysinit:/etc/init.d/rcS
s3c2410_serial0::askfirst:-/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a –r
5、etc/init.d/rcS 文件:
#!/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
runlevel=S
prevlevel=N
umask 022
export PATH runlevel prevlevel
echo "----------munt all----------------"
mount -a
echo /sbin/mdev>/proc/sys/kernel/hotplug
mdev -s
echo "***********************************************"
echo "****************Studying ARM*********************"
echo "Kernel version:linux-2.6.29.1"
echo "Student:Huang huahai"
echo "Date:2009.10.1"
echo "***********************************************"
/bin/hostname -F /etc/sysconfig/HOSTNAME
(或者直接 /bin/hostname H3-Studio )
使用以下命令改变 rcS 的执行权限:
Chmod +x rcS
6、etc/fstab 文件:
#device
mount-point
type
option
dump fsck
proc
/proc
proc
defaults
0
0
none
/tmp
ramfs
defaults
0
0
sysfs
/sys
sysfs
defaults
0
0
mdev
/dev
ramfs
defaults
0
0
7、 etc/profile 文件:
#Ash profile
#vim:syntax=sh
#No core file by defaults
#ulimit -S -c 0>/dev/null 2>&1
USER="id -un"
LOGNAME=$USER
PS1='[\u@\h=W]#'
PATH=$PATH
HOSTNAME='/bin/hostname'
export USER LOGNAME PS1 PATH
order
4.2.7 制作根文件系统映像文件
使用以下命令安装好 yaffs 文件系统制作工具:
cd /mnt/hgfs/share
tar –zxvf mkyaffs2image.tgz –C /
在/opt/studyarm 目录下,使用命令 mkyaffs2image rootfs rootfs.img 生成根文件系统映像
文件。
启动信息:
Copy linux kernel from 0x00050000 to 0x30008000, size = 0x00200000 ... done
zImage magic = 0x016f2818
Setup linux parameters at 0x30000100
linux command line is: "noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0"
MACH_TYPE = 782
NOW, Booting Linux......
Uncompressing Linux........................................................................................................................... done, booting the kernel.
Linux version 2.6.29.1 (root@FriendlyARM) (gcc version 4.3.2 (Sourcery G++ Lite 2008q3-72) ) #2 Thu Oct 1 16:46:24 JST
2009
CPU: ARM920T [41129200] revision 0 (ARMv4T), cr=c0007177
CPU: VIVT data cache, VIVT instruction cache
Machine: Study-S3C2440
ATAG_INITRD is deprecated; please update your bootloader.
Memory policy: ECC disabled, Data cache writeback
CPU S3C2440A (id 0x32440001)
S3C24XX Clocks, (c) 2004 Simtec Electronics
S3C244X: core 405.000 MHz, memory 101.250 MHz, peripheral 50.625 MHz
CLOCK: Slow mode (1.500 MHz), fast, MPLL on, UPLL on
Built 1 zonelists in Zone order, mobility grouping on.
Total pages: 16256
Kernel command line: noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0
irq: clearing subpending status 00000003
irq: clearing subpending status 00000002
PID hash table entries: 256 (order: 8, 1024 bytes)
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: 60828KB available (3556K code, 302K data, 156K init)
Calibrating delay loop... 201.93 BogoMIPS (lpj=504832)
Mount-cache hash table entries: 512
CPU: Testing write buffer coherency: ok
net_namespace: 716 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 c4808000, irq 33
DMA channel 1 at c4808040, irq 34
DMA channel 2 at c4808080, irq 35
DMA channel 3 at c48080c0, irq 36
S3C244X: Clock Support, DVS off
bio: create slab <bio-0> at 0
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)
yaffs Oct
© 2001-2006 Red Hat, Inc.
1 2009 16:45:43 Installing.
msgmni has been set to 118
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 driver, 4 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
ide-gd driver 1.18
ide-cd driver 5.00
Driver 'sd' needs updating - please use bus_type methods
S3C24XX NAND Driver, (c) 2004 Simtec Electronics
s3c2440-nand s3c2440-nand: Tacls=1, 9ns Twrph0=4 39ns, Twrph1=1 9ns
NAND device: Manufacturer ID: 0xec, Chip ID: 0x76 (Samsung NAND 64MiB 3,3V 8-bit)
Scanning device for bad blocks
Bad eraseblock 3339 at 0x00000342c000
Creating 8 MTD partitions on "NAND 64MiB 3,3V 8-bit":
0x000000000000-0x000000030000 : "bootloder"
0x000000050000-0x000000250000 : "kernel"
0x000000250000-0x000003ffc000 : "root"
0x000000800000-0x000000a00000 : "S3C2410 flash partition 3"
0x000000a00000-0x000000e00000 : "S3C2410 flash partition 4"
0x000000e00000-0x000001800000 : "S3C2410 flash partition 5"
0x000001800000-0x000003000000 : "S3C2410 flash partition 6"
0x000003000000-0x000004000000 : "S3C2410 flash partition 7"
usbmon: debugfs is not available
ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
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
USB Serial support registered for generic
usbcore: registered new interface driver usbserial_generic
usbserial: USB Serial Driver core
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
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 98 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)
yaffs: dev is 32505858 name is "mtdblock2"
yaffs: passed flags ""
yaffs: Attempting MTD mount on 31.2, "mtdblock2"
yaffs: block 3191 is marked bad
block 3192 is bad
yaffs_read_super: isCheckpointed 0
VFS: Mounted root (yaffs filesystem) on device 31:2.
Freeing init memory: 156K
------mount all------
************************************
**********studyARM******************
Kernel version:linux-2.6.29.1
Student:Huang huahai
Data:2009.10.1
***********************************
Please press Enter to activate this console.
看到了,ok!
4.3 mdev 的使用方法和原理
说明:本文同样出自网友 hugerat
原文网址:http://blog.csdn.net/hugerat/archive/2008/12/03/3437099.aspx
mdev 是 busybox 自带的一个简化版的 udev,适合于嵌入式的应用埸合。其具有使用简
单的特点。它的作用,就是在系统启动和热插拔或动态加载驱动程序时,自动产生驱动程序所
需的节点文件。在以 busybox 为基础构建嵌入式 linux 的根文件系统时,使用它是最优的选择。
4.3.1 mdev 的使用
mdev 的使用在 busybox 中的 mdev.txt 文档已经将得很详细了。但作为例子,我简单讲
讲我的使用过程:
(1)在编译时加上对 mdev 的支持
说明: 我使用的是 busybox1.10.1
Linux System Utilities ---> mdev
Support /etc/mdev.conf
Support command execution at device addition/removal
(2)在启动时加上使用 mdev 的命令
我在自己创建的根文件系统(nfs)中的/linuxrc 文件中添加了如下指令:
#挂载/sys 为 sysfs 文件系统
echo "----------mount /sys as sysfs"
/bin/mount -t tmpfs mdev /dev
/bin/mount -t sysfs sysfs /sys
echo "----------Starting mdev......"
/bin/echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
注意:是/bin/echo /sbin/mdev > /proc/sys/kernel/hotplug,并非/bin/echo /bin/mdev >
/proc/sys/kernel/hotplug。
busybox 的文档有错!
!
(3)在驱动中加上对类设备接口的支持
在驱动程序的初始化函数中,使用下述的类似语句,就能在类设备目录下添加包含
设备号的名为
“dev”
的属性文件。
并通过 mdev 在/dev 目录下产生 gpio_dev0 的设备节点文件。
my_class = class_create(THIS_MODULE, "gpio_class");
if(IS_ERR(my_class)) {
printk("Err: failed in creating class.\n");
return -1;
}
/* register your own device in sysfs, and this will cause mdev to create corresponding
device node */
class_device_create(my_class,
MKDEV(gpio_major_number,
0),
NULL,
"gpio_dev%d" ,0);
在驱动程序的清除程序段,加入以下语句,以完成清除工作。
class_device_destroy(my_class, MKDEV(gpio_major_number, 0));
class_destroy(my_class);
需要的头文件是 linux/device.h,因此程序的开始应加入下句
#include <linux/device.h>
另外,my_class 是 class 类型的结构体指针,要在程序开始时声明成全局变量。
struct class *my_class;
上述程序中的 gpio_major_number 是设备的主节点号。可以换成需要的节点号。
gpio_dev 是最终生成的设备节点文件的名子。%d 是用于以相同设备自动编号的。gpio_class
是建立的 class 的名称,当驱动程序加载后,可以在/sys/class 的目录下看到它。
上述语句也不一定要在初始化和清除阶段使用,可以根据需要在其它地方使用。
(4)/etc/mdev.conf 文件
至于/etc/mdev.conf 文件,可有可无,不影响使用,只是添加了些功能。
关于 mdev 的使用方法,我在网上找到一篇中文版的。大家可以到我上传的资源中下
载。
4.3.2 mdev 的原理
要想真正用好 mdev,适当知道一下原理是必不可少的,现在简单介绍一下 mdev 的
原理:
(1)执行 mdev -s
说明:以‘-s’为参数调用位于/sbin 目录写的 mdev(其实是个链接,作用是传递参
数给/bin 目录下的 busybox 程序并调用它)
,mdev 扫描 /sys/class 和/sys/block 中所有的类设备
目录,如果在目录中含有名为“dev”的文件,且文件中包含的是设备号,则 mdev 就利用这
些信息为这个设备在/dev 下创建设备节点文件。一般只在启动时才执行一次 “mdev -s”
。
(2)热插拔事件
由于启动时运行了命令:echo /sbin/mdev > /proc/sys/kernel/hotplug ,那么当有热插拔
事件产生时,
内核就会调用位于/sbin 目录的 mdev。
这时 mdev 通过环境变量中的 ACTION 和
DEVPATH,
(这两个变量是系统自带的)来确定此次热插拔事件的动作以及影响了
/sys 中的那个目录。接着会看看这个目录中是否有“dev”的属性文件,如果有就利用这些信
息为
这个设备在/dev 下创建设备节点文件。
4.3.3 一个使用 mdev 的 gpio 控制驱动示例
最后,附上我在工作中编写的一段简单的 gpio 控制驱动程序。此程序没有什么功能,
主要是做一些测试用的。有兴趣的朋友可以用它测试一下上述的 mdev 的使用方法。我用的是
友善公司的 mini2440 开发板。
#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/kernel.h>
/* printk() */
#include <linux/fs.h>
/* everything... */
#include <linux/cdev.h>
#include <linux/interrupt.h>
/* request_irq() */
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-irq.h>
#include <asm/io.h>
#include <asm/uaccess.h>
/* copy_to_user() */
#include <linux/delay.h>
/* mdelay() */
#include <linux/device.h>
/*class_create()*/
#include <asm/arch-s3c2410/regs-gpio.h>
#include <asm/arch-s3c2410/regs-timer.h>
#define VERSION_STRING
"gpio driver for JM_Xcontrol"
#define DEVICE_NAME "JM_Xcontrol_gpio"
/* Use 0xE0 as magic number */
#define XRAY_IOC_MAGIC 0xE0
#define XRAY_IOCLCDBACKLIGHT
_IO(XRAY_IOC_MAGIC, 0)
#define XRAY_IOC485REC
_IO(XRAY_IOC_MAGIC, 1)
#define XRAY_IOC485TRC
_IO(XRAY_IOC_MAGIC, 2)
#define XRAY_IOCBUZZER
_IO(XRAY_IOC_MAGIC, 3)
#define XRAY_IOC_MAXNR 12
MODULE_AUTHOR("hugerat");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION(VERSION_STRING);
unsigned int gpio_major_number=0;
struct cdev gpio_dev;
struct class *my_class;
static int gpio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
int err=0;
unsigned long tmp;
//-------以下检查命令---------//
if (_IOC_TYPE(cmd) != XRAY_IOC_MAGIC) return -ENOTTY;
if (_IOC_NR(cmd) > XRAY_IOC_MAXNR) return -ENOTTY;
if (_IOC_DIR(cmd) & _IOC_READ)
err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd));
else if (_IOC_DIR(cmd) & _IOC_WRITE)
err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));
if (err)
return -EFAULT;
//--------------------------//
switch ( cmd )
{
case XRAY_IOCLCDBACKLIGHT: //控制 LCD 背光开关
if(arg==0)
{
s3c2410_gpio_setpin(S3C2410_GPB1, 1);
}
else
{
s3c2410_gpio_setpin(S3C2410_GPB1, 0);
}
break;
case XRAY_IOC485REC:
if(arg==0)
{
s3c2410_gpio_setpin(S3C2410_GPG10, 1);
}
else
{
s3c2410_gpio_setpin(S3C2410_GPG10, 0);
}
break;
case XRAY_IOC485TRC:
if(arg==0)
{
s3c2410_gpio_setpin(S3C2410_GPG12, 0);
}
else
{
s3c2410_gpio_setpin(S3C2410_GPG12, 1);
}
break;
case XRAY_IOCBUZZER:
if(arg==0)
{
s3c2410_gpio_setpin(S3C2410_GPB0, 0);
}
else
{
s3c2410_gpio_setpin(S3C2410_GPB0, 1);
}
break;
default:
break;
}
return 0;
}
static struct file_operations gpio_fops = {
.owner = THIS_MODULE,
//.open
= xray_open,
//.release = xray_release,
//.read
= xray_read,
//.write = xray_write,
.ioctl = gpio_ioctl,
//.fasync = xray_fasync,
};
static int __init gpio_init(void)
{
int ret,devno;
dev_t dev;
unsigned long tmp;
ret = alloc_chrdev_region(&dev,0,1,DEVICE_NAME);
gpio_major_number = MAJOR(dev);
printk(KERN_INFO "Initial jm_xcontrol_gpio driver!\n");
if (ret<0) {
printk(KERN_WARNING "gpio:can't get major number %d\n",gpio_major_number);
return ret;
}
devno = MKDEV(gpio_major_number,0);
cdev_init(&gpio_dev,&gpio_fops);
gpio_dev.owner = THIS_MODULE;
gpio_dev.ops
= &gpio_fops;
ret = cdev_add(&gpio_dev,devno,1);
if (ret) {
unregister_chrdev_region(dev,1);
printk(KERN_NOTICE "Error %d adding gpio device\n",ret);
return ret;
}
my_class = class_create(THIS_MODULE, "gpio_class");
if(IS_ERR(my_class)) {
printk("Err: failed in creating class.\n");
return -1;
}
/* register your own device in sysfs, and this will cause mdev to create corresponding device node */
class_device_create(my_class, MKDEV(gpio_major_number, 0), NULL, "gpio_dev%d" ,0);
//LCD 背光
s3c2410_gpio_cfgpin(S3C2410_GPB1, S3C2410_GPB1_OUTP);
s3c2410_gpio_setpin(S3C2410_GPB1, 0);
//蜂鸣器
s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPB0_OUTP);
s3c2410_gpio_setpin(S3C2410_GPB0, 0);
//485 收发控制
s3c2410_gpio_cfgpin(S3C2410_GPG10, S3C2410_GPG10_OUTP); //收
s3c2410_gpio_setpin(S3C2410_GPG10, 0);
s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPG12_OUTP);
s3c2410_gpio_setpin(S3C2410_GPG12, 0);
return 0;
}
static void __exit gpio_cleanup(void)
{
unsigned long tmp;
dev_t dev=MKDEV(gpio_major_number,0);
cdev_del(&gpio_dev);
class_device_destroy(my_class, MKDEV(gpio_major_number, 0));
class_destroy(my_class);
unregister_chrdev_region(dev,1);
s3c2410_gpio_setpin(S3C2410_GPB1, 1); //关背光
s3c2410_gpio_setpin(S3C2410_GPB0, 0); //关蜂鸣器
s3c2410_gpio_setpin(S3C2410_GPG10, 1); //关 485 收
s3c2410_gpio_setpin(S3C2410_GPG12, 0); //关 485 发
printk(KERN_INFO "unregistered the %s\n",DEVICE_NAME);
}
module_init(gpio_init);
module_exit(gpio_cleanup);
(待续)
//发
4.1 友善之臂 mini2440 root_qtopia 文件系统启动过程分析
本文简介:
友善之臂提供的根文件系统十分具有创新意义,其功能之强大,先进,实用至今保持在
领先地位,
网友 kasim 对其作了详尽的剖析,
道出了很多
“秘密” 对于任何致力于嵌入式 Linux
,
开发的人员是不可多得的好资料,现整理如下。
原文网址:
http://www.arm9home.net/read.php?tid-1702.html
下面是这篇文章的内容,我们对此进行了简单的编辑和修改:
对于 mini2440 最新的 root_qtopia 文件系统启动过程,我在这里做了一些简单的分析,
和大家分享一下经验,不足之处也请大家及时指出。
其实,虽然 root_qtopia 这个文件系统的 GUI 是基于 Qtopia 的,但其初始化启动过程
却是由大部分由 busybox 完成,Qtopia(qpe)只是在启动的最后阶段被开启。
由于默认的内核命令行上有 init=/linuxrc, 因此,在文件系统被挂载后,运行的第一个程
序是根目录下的 linuxrc。 这是一个指向/bin/busybox 的链接,也就是说,系统起来后运行的
第一个程序也就是 busybox 本身。
这种情况下,busybox 首先将试图解析/etc/inittab 来获取进一步的初始化配置信息(参
考 busybox 源代码 init/init.c 中的 parse_inittab()函数)。而事实上,root_qtopia 中并没有/et
c/inittab 这个配置文件,根据 busybox 的逻辑,它将生成默认的配置
复制代码
1. static void parse_inittab(void)
2. {
3. #if ENABLE_FEATURE_USE_INITTAB
4. char *token[4];
5. parser_t *parser = config_open2("/etc/inittab", fopen_for_read);
6.
7. if (parser == NULL)
8. #endif
9. {
10. /* No inittab file -- set up some default behavior */
11. /* Reboot on Ctrl-Alt-Del */
12. new_init_action(CTRLALTDEL, "reboot", "");
13. /* Umount all filesystems on halt/reboot */
14. new_init_action(SHUTDOWN, "umount -a -r", "");
15. /* Swapoff on halt/reboot */
16. if (ENABLE_SWAPONOFF)
17. new_init_action(SHUTDOWN, "swapoff -a", "");
18. /* Prepare to restart init when a QUIT is received */
19. new_init_action(RESTART, "init", "");
20. /* Askfirst shell on tty1-4 */
21. new_init_action(ASKFIRST, bb_default_login_shell, "");
22. //TODO: VC_1 instead of ""? "" is console -> ctty problems -> angry users
23. new_init_action(ASKFIRST, bb_default_login_shell, VC_2);
24. new_init_action(ASKFIRST, bb_default_login_shell, VC_3);
25. new_init_action(ASKFIRST, bb_default_login_shell, VC_4);
26. /* sysinit */
27. new_init_action(SYSINIT, INIT_SCRIPT, "");
28. return;
29. }
其中,最重要的一个,就是 new_init_action(SYSINIT, INIT_SCRIPT, ""),也就决定了
接下去初始化的脚本是 INIT_SCRIPT 所定义的值。这个宏的默认值是"/etc/init.d/rcS".
下面是文件系统中/etc/init.d/rcS 的内容, 也是我们要分析的重点
复制代码
1.
#! /bin/sh
2.
3. PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:
4. runlevel=S
5. prevlevel=N
6. umask 022
7. export PATH runlevel prevlevel
8.
9.
#
10. # Trap CTRL-C &c only in this shell so we can interrupt subprocesses.
11. #
12. trap ":" INT QUIT TSTP
13. /bin/hostname FriendlyARM
14.
15. /bin/mount -n -t proc none /proc
16. /bin/mount -n -t sysfs none /sys
17. /bin/mount -n -t usbfs none /proc/bus/usb
18. /bin/mount -t ramfs none /dev
19.
20. echo /sbin/mdev > /proc/sys/kernel/hotplug
21. /sbin/mdev -s
22. /bin/hotplug
23. # mounting file system specified in /etc/fstab
24. mkdir -p /dev/pts
25. mkdir -p /dev/shm
26. /bin/mount -n -t devpts none /dev/pts -o mode=0622
27. /bin/mount -n -t tmpfs tmpfs /dev/shm
28. /bin/mount -n -t ramfs none /tmp
29. /bin/mount -n -t ramfs none /var
30. mkdir -p /var/empty
31. mkdir -p /var/log
32. mkdir -p /var/lock
33. mkdir -p /var/run
34. mkdir -p /var/tmp
35.
36. /sbin/hwclock -s
37.
38. syslogd
39. /etc/rc.d/init.d/netd start
40. echo " " > /dev/tty1
41. echo "Starting networking..." > /dev/tty1
42. sleep 1
43. /etc/rc.d/init.d/httpd start
44. echo " " > /dev/tty1
45. echo "Starting web server..." > /dev/tty1
46. sleep 1
47. /etc/rc.d/init.d/leds start
48. echo " " > /dev/tty1
49. echo "Starting leds service..." > /dev/tty1
50. echo " "
51. sleep 1
52.
53. /sbin/ifconfig lo 127.0.0.1
54. /etc/init.d/ifconfig-eth0
55.
56. /bin/qtopia &
57. echo " " > /dev/tty1
58. echo "Starting Qtopia, please waiting..." > /dev/tty1
下面就逐个来分析:
复制代码
1. PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:
2. runlevel=S
3. prevlevel=N
4. umask 022
5. export PATH runlevel prevlevel
为启动环境设置必要的环境变量:
复制代码
1.
/bin/hostname FriendlyARM
设置机器名字;:
复制代码
1. /bin/mount -n -t proc none /proc
2. /bin/mount -n -t sysfs none /sys
3. /bin/mount -n -t usbfs none /proc/bus/usb
4. /bin/mount -t ramfs none /dev
挂载“虚拟”文件系统“/proc”和“/sys”,并且在/dev 目录上挂载一个 ramfs,相当于
把原本 NAND Flash 上的只读的/dev 目录“覆盖”上一块可写的空的 SDRAM。
这里要注意的是,/sys 和挂载了 ramfs 的/dev 是正确创建设备节点的关键。对于 2.6.2
9 内核来说,已经没有了 devfs 的支持,创建设备节点只有通过两种办法由文件系统完成:
1) 制作文件系统镜像前用 mknod 手动创建好系统中所有的(包括可能有的)设备节点,
并把这些节点文件一起做进文件系统镜像中;
2)在文件系统初始化过程中,通过/sys 目录所输出的信息,在/dev 目录下动态的创建
系统中当前实际有的设备节点。
显然,方法 1)有很大的局限性,仅限于没有设备动态增加或减少的情况,不适用于很
多设备热插拔的情况,比如 U 盘,SD 卡等等。方法 2)是目前大多数 PC 上 Linux 的做法(基
于 udev 实现)。这种方法有两个前提: /sys 目录挂载和一个可写的/dev 目录。 这也就是为
什么我们在这里需要挂载/sys 和 ramfs 在/dev 目录上。事实上,这种方法最早就是为热插拔
设计的, 你可以理解为当系统启动是,所有设备一下子全部“插入”了进来。
这里有一点要说明的是,在文件系统初始化跑到这里之前,原本的/dev 目录下必须有
一个的设备节点:/dev/console。
其实,要搞清楚“程序”这种东西,没有什么好的办法,无非两个东西,一是看源代码,
二是看脚本(其实还是一个东西,看脚本也是为了看脚本调用了什么程序
复制代码
1. echo /sbin/mdev > /proc/sys/kernel/hotplug
2. /sbin/mdev -s
3. /bin/hotplug
这几个就是用来完成我上面所说的两个东西: 1)通过 mdev -s 在/dev 目录下建立必
要的设备节点; 2)设置内核的 hotplug handler 为 mdev, 即当设备热插拔时,由 mdev 接收
来自内核的消息并作出相应的回应, 比如挂载 U 盘。
对于 mdev,需要注意的是,文件系统里存在/etc/mdev.conf 文件,它包含了 mdev 的
配置信息。通过这个文件,我们可以自定义一些设备节点的名称或链接来满足特定的需要。这
是 root qtopia 中 mdev.conf 的内容:
复制代码
1. # system all-writable devices
2. full
0:0
0666
3. null
0:0
0666
4. ptmx
5. random
0:0
6. tty
0666
7. zero
0:0
0:0
0666
0:0
0666
0666
8.
9.
# console devices
10. tty[0-9]* 0:5 0660
11. vc/[0-9]* 0:5 0660
12.
13. # serial port devices
14. s3c2410_serial0 0:5 0666 =ttySAC0
15. s3c2410_serial1 0:5 0666 =ttySAC1
16. s3c2410_serial2 0:5 0666 =ttySAC2
17. s3c2410_serial3 0:5 0666 =ttySAC3
18.
19. # loop devices
20. loop[0-9]*
0:0
0660
=loop/
21.
22. # i2c devices
23. i2c-0 0:0 0666 =i2c/0
24. i2c-1 0:0 0666 =i2c/1
25.
26. # frame buffer devices
27. fb[0-9]
0:0
0666
28.
29. # input devices
30. mice
0:0
31. mouse.*
0:0
32. event.*
33. ts.*
0660
0:0
0:0
=input/
0660
0660
=input/
=input/
0660 =input/
>rtc
34.
35. # rtc devices
36. rtc0 0:0 0644
37. rtc[1-9] 0:0 0644
38.
39. # misc devices
40. mmcblk0p1
41. sda1
0:0
0:0
0600
0600
=sdcard */bin/hotplug
=udisk * /bin/hotplug
可 以 看 到 , 原 本 串 口 驱 动 注 册 的 设 备 名 是 s3c2410_serial0, s3c2410_serial1 和
s3c2410_serial2,而 mdev 则会在/dev 目录下对应生成 ttySAC0, ttySAC1 和 ttySAC2 以符合
应用程序对于串口设备名称的习惯。同样的,/dev/sdcard 和/dev/udisk 永远分别指向 SD 卡和
U 盘的第一个分区。(所以,用那些没有分区表的 SD 卡或 U 盘的兄弟知道原因了吧...)
复制代码
1. # mounting file system specified in /etc/fstab
2. mkdir -p /dev/pts
3. mkdir -p /dev/shm
4. /bin/mount -n -t devpts none /dev/pts -o mode=0622
5. /bin/mount -n -t tmpfs tmpfs /dev/shm
6. /bin/mount -n -t ramfs none /tmp
7. /bin/mount -n -t ramfs none /var
8. mkdir -p /var/empty
9. mkdir -p /var/log
10. mkdir -p /var/lock
11. mkdir -p /var/run
12. mkdir -p /var/tmp
就像注释中所说的,这是用来挂载其他一些常用的文件系统,并在/var 目录下(同样是
ramfs,可写的)新建必要的目录。
复制代码
1.
/sbin/hwclock -s
用来设定系统时间的,从硬件 RTC 中获取,要获取正确的时间,必须先设置好正确的
时间(如何设置 RTC 见用户手册说明),目前友善之臂的开发板出厂时并没有设置实际的时
间,而是系统默认的。
接下来就是启动系统服务了,包括 log 记录,网络, http server 和自定义的"跑马灯服
务"...
关于 mdev.conf 中的一点补充说明:
复制代码
1. # misc devices
2. mmcblk0p1
3. sda1
0:0
0:0
0600
0600
=sdcard */bin/hotplug
=udisk * /bin/hotplug
这两句配置的意思是当 SD 卡或者 U 盘插入/拔出时,将这个消息传递给自定义的热插
拔 handler, /bin/hotplug. 这个程序是友善之臂开发的用于自动挂载可移动设备的,目前是 SD
卡和 U 盘。它的逻辑很简单,将 SD 卡或者 U 盘的第一个分区作为 FAT/FAT32 挂载到/sdcard
或者/udisk.
但这也同时带来一个问题,当 SD 卡或者 U 盘上没有分区表或者第一个分区不是 FAT/
FAT32 格式的时候,它就玩不转了:)
这是/bin/hotplug 里的二进制数据片段,可以看到我上面说的逻辑:
000010d0h: 52 00 00 00 4D 00 00 00 00 00 00 00 41 00 00 00 ; R...M.......A...
000010e0h: 43 00 00 00 54 00 00 00 49 00 00 00 4F 00 00 00 ; C...T...I...O...
000010f0h: 4E 00 00 00 00 00 00 00 44 00 00 00 45 00 00 00 ; N.......D...E...
00001100h: 56 00 00 00 4E 00 00 00 41 00 00 00 4D 00 00 00 ; V...N...A...M...
00001110h: 45 00 00 00 00 00 00 00 61 00 00 00 64 00 00 00 ; E.......a...d...
00001120h: 64 00 00 00 00 00 00 00 72 00 00 00 65 00 00 00 ; d.......r...e...
00001130h: 6D 00 00 00 6F 00 00 00 76 00 00 00 65 00 00 00 ; m...o...v...e...
00001140h: 00 00 00 00 2F 00 00 00 64 00 00 00 65 00 00 00 ; ..../...d...e...
00001150h: 76 00 00 00 2F 00 00 00 75 00 00 00 64 00 00 00 ; v.../...u...d...
00001160h: 69 00 00 00 73 00 00 00 6B 00 00 00 00 00 00 00 ; i...s...k.......
00001170h: 2F 00 00 00 64 00 00 00 65 00 00 00 76 00 00 00 ; /...d...e...v...
00001180h: 2F 00 00 00 73 00 00 00 64 00 00 00 63 00 00 00 ; /...s...d...c...
00001190h: 61 00 00 00 72 00 00 00 64 00 00 00 00 00 00 00 ; a...r...d.......
000011a0h: 4D 00 00 00 44 00 00 00 45 00 00 00 56 00 00 00 ; M...D...E...V...
000011b0h: 00 00 00 00 6D 00 00 00 6D 00 00 00 63 00 00 00 ; ....m...m...c...
000011c0h: 62 00 00 00 6C 00 00 00 6B 00 00 00 30 00 00 00 ; b...l...k...0...
000011d0h: 70 00 00 00 31 00 00 00 00 00 00 00 73 00 00 00 ; p...1.......s...
000011e0h: 64 00 00 00 61 00 00 00 31 00 00 00 00 00 00 00 ; d...a...1.......
000011f0h: 76 00 00 00 66 00 00 00 61 00 00 00 74 00 00 00 ; v...f...a...t...
00001200h: 00 00 00 00 2F 00 00 00 64 00 00 00 65 00 00 00 ; ..../...d...e...
00001210h: 76 00 00 00 2F 00 00 00 77 00 00 00 61 00 00 00 ; v.../...w...a...
00001220h: 74 00 00 00 63 00 00 00 68 00 00 00 64 00 00 00 ; t...c...h...d...
00001230h: 6F 00 00 00 67 00 00 00 00 00 00 00 9A B2 01 81 ; o...g.......毑.?
00001240h: B0
; ?
复制代码
1. syslogd
2. /etc/rc.d/init.d/netd start
3. echo "
" > /dev/tty1
4. echo "Starting networking..." > /dev/tty1
5. sleep 1
6. /etc/rc.d/init.d/httpd start
7. echo "
8. echo "Starting web server..." > /dev/tty1
9. sleep 1
" > /dev/tty1
10. /etc/rc.d/init.d/leds start
11. echo "
" > /dev/tty1
12. echo "Starting leds service..." > /dev/tty1
13. echo "
"
14. sleep 1
启动一系列服务:
syslog - 用于记录内核和应用程序 debug 信息
netd - inetd, 一个挂载启动各种网络相关服务的看守进程
httpd - http server 看守进程
leds -
跑马灯看守进程
其中,inetd 的配置文件为/etc/inetd.conf,这是文件内容
复制代码
1. # /etc/inetd.conf: see inetd(8) for further informations.
2. echo
stream tcp
3. echo
dgram
udp
nowait
wait
root
root
internal
internal
4. daytime stream tcp
5. daytime dgram
6. time
stream tcp
7. time
dgram
nowait
udp
root
internal
wait root internal
nowait root internal
udp
wait
root
internal
8.
9.
# These are standard services.
10. #
11. ftp
stream
12. telnet
tcp
stream
nowait
tcp
root
nowait
/usr/sbin/ftpd
root
/usr/sbin/ftpd
/usr/sbin/telnetd
/usr/sbin/telnetd -i
可以看到,这里启动的网络服务有两个: 1)ftp server 和 2)telnet server。有关网络
服务的端口和协议等具体信息,可以参考/etc/services, /etc/protocols
再接下来
复制代码
1. /sbin/ifconfig lo 127.0.0.1
2. /etc/init.d/ifconfig-eth0
配置网络设备(网卡):
1)设定本机回环地址为 127.0.0.1
2)运行网卡设置脚本/etc/init.d/ifconfig-eth0
这是/etc/init.d/ifconfig-eth0 的内容, 加入了我的一些注释
复制代码
1.
#!/bin/sh
2.
3.
echo -n Try to bring eth0 interface up......>/dev/ttySAC0
4.
5. #判断/etc/eth0-setting 文件是否存在
6. if [ -f /etc/eth0-setting ] ; then
7.
8.
#读取配置文件信息
source /etc/eth0-setting
9.
10.
11.
#如果根文件系统为 nfs,则说明网卡已经配置 OK,这里什么都不需要配置了
if grep -q "^/dev/root / nfs " /etc/mtab ; then
12.
echo -n NFS root ... > /dev/ttySAC0
#否则,根据配置文件中的 MAC, IP, Mask 和 Gateway 通过 ifconfig 命令相应地配置网卡
13.
14.
else
15. ifconfig eth0 down
16. ifconfig eth0 hw ether $MAC
17. ifconfig eth0 $IP netmask $Mask up
18. route add default gw $Gateway
19.
fi
20.
21.
22.
#将配置文件中的 DNS 设置写入/etc/resolv.conf 使之生效
echo nameserver $DNS > /etc/resolv.conf
23. #配置文件不存在,使用默认配置
24. else
25.
26.
#如果根文件系统为 nfs,则说明网卡已经配置 OK,这里什么都不需要配置了
27.
if grep -q "^/dev/root / nfs " /etc/mtab ; then
28.
echo -n NFS root ... > /dev/ttySAC0
29.
else
#将网卡的 IP 地址设定为 192.168.1.230
30.
31. /sbin/ifconfig eth0 192.168.1.230 netmask 255.255.255.0 up
32. fi
33. fi
34.
35. echo Done > /dev/ttySAC0
可以看到,NFS 自动识别就是靠判断/etc/mtab 中是否有 nfs 的挂载记录实现的。
这是 root qtopia 文件系统中/etc/eth0-settings 文件
复制代码
1. IP=192.168.1.230
2. Mask=255.255.255.0
3. Gateway=192.168.1.1
4. DNS=192.168.1.1
5. MAC=08:90:90:90:90:90
终于到最后了,启动 Qtopia GUI 环境
复制代码
1. /bin/qtopia &
2. echo "
3. echo "Starting Qtopia, please waiting..." > /dev/tty1
" > /dev/tty1
可以看到,这里 Qtopia 是通过运行/bin/qtopia 来启动的。事实上,/bin/qtopia 也是一
个脚本,它的任务是设定 Qtopia 运行必要的环境, 最后通过调用 qpe 可执行文件真正启动
Qtopia。这是它的全部内容,我加入了一些注释:
复制代码
1.
#!/bin/sh
2.
3. #tslib 环境变量设置,包括了 touchscreen 设备文件,tslib 配置文件,tslib plug-in 位置和 touchscreen 校准数据
4. export TSLIB_TSDEVICE=/dev/input/event0
5. export TSLIB_CONFFILE=/usr/local/etc/ts.conf
6. export TSLIB_PLUGINDIR=/usr/local/lib/ts
7. export TSLIB_CALIBFILE=/etc/pointercal
8. #Qtopia 环境变量设置,设定了 Qtopia 主要文件位置
9. export QTDIR=/opt/Qtopia
文件
10. export QPEDIR=/opt/Qtopia
11. #设定 PATH 和 LD_LIBRARY_PATH 以包含 Qtopia 的可执行文件和共享库文件,方便 Qtopia 正确运行
12. export PATH=$QTDIR/bin:$PATH
13. export LD_LIBRARY_PATH=$QTDIR/lib:/usr/local/lib:$LD_LIBRARY_PATH
14.
15. #通过判断/sys/devices/virtual/input/input0/uevent 中是否包含 touchscreen 信息使 Qtopia 自动识别 touchscreen
和 USB 鼠标
16. TS_INFO_FILE=/sys/devices/virtual/input/input0/uevent
17. if [ -e $TS_INFO_FILE -a "/bin/grep -q TouchScreen < $TS_INFO_FILE" ]; then
18. export QWS_MOUSE_PROTO="TPanel:/dev/input/event0 USB:/dev/input/mice"
19. if [ -e /etc/pointercal -a ! -s /etc/pointercal ] ; then
20.
21.
rm /etc/pointercal
fi
22. else
23. export QWS_MOUSE_PROTO="USB:/dev/input/mice"
24. >/etc/pointercal
25. fi
26. unset TS_INFO_FILE
27.
28. export QWS_KEYBOARD=TTY:/dev/tty1
29. export KDEDIR=/opt/kde
30.
31. export HOME=/root
32.
33. #通过调用/opt/Qtopia/bin/qpe 真正启动 Qtopia
34. exec $QPEDIR/bin/qpe 1>/dev/null 2>/dev/null
到此为止,文件系统从初始化到最终启动 Qtopia GUI 环境的全部过程就结束了,大家
可以看到,友善之臂的“小秘密”其实都在这里,说穿了很简单:)只要大家能够静下心来认真看
看脚本,看看源代码,加上一些背景知识的了解,搞清楚一个嵌入式系统就这么简单
4.2 使用 Busybox 构建文件系统
说明:本文主要基于网友 huang-tomey 所写的“yaffs2 文件系统移植”一文,这里详细
介绍了仅使用 busybox 建立基本根文件系统的过程,实际上根据开发和项目的需要,一般基本
的文件系统是远远不够的,
友善之臂提供的根文件系统是面向嵌入式爱好者精心配置的一个典
型示范,详细介绍可以参考 kasim 网友所写的“mini2440 root_qtopia 文件系统启动过程分析”
一文
原文网址:
http://huang-tomey.blog.163.com/blog/static/1247505732009916437175/
下面是使用 busybox 制作基本根文件系统的详细步骤
4.2.1 下载 busybox 源代码
从
http://www.busybox.net/downloads/ 下 载 busybox , 这 里 下 载 的 是
busy busybox-1.13.3.tar.gz,这和当前mini2440 开发板使用的版本是一致的。
4.2.2 根文件系统目录说明
嵌入式 Linux 中都需要构建根文件系统,构建根文件系统的规则在 FHS(Filesystem
Hierarchy Standard)文档中,下面是根文件系统顶层目录。
目录
内容
bin
存放所有用户都可以使用的、基本的命令。
sbin
存放的是基本的系统命令,它们用于启动系统、修复系统等。
usr
里面存放的是共享、只读的程序和数据。
proc
这是个空目录,常作为 proc 文件系统的挂载点。
dev
该目录存放设备文件和其它特殊文件。
etc
存放系统配置文件,包括启动文件。
lib
存放共享库和可加载块(即驱动程序),共享库用于启动系统、运行根文件系统中的可
boot
home
mnt
opt
root
tmp
var
执行程序。
引导加载程序使用的静态文件
用户主目录,包括供服务账号锁使用的主目录,如 FTP
用于临时挂接某个文件系统的挂接点,通常是空目录。也可以在里面创建空的子目
录。
给主机额外安装软件所摆放的目录。
root 用户的主目录
存放临时文件,通常是空目录。
存放可变的数据。
4.2.3 建立根文件系统目录
进入到/opt/studyarm 目录,新建建立根文件系统目录的脚本文件 create_rootfs_bash,使
用命令 chmod +x create_rootfs_bash 改变文件的可执行权限,./create_rootfs_bash 运行脚本,就
完成了根文件系统目录的创建。
#!/bin/sh
echo "------Create rootfs directons start...--------"
mkdir rootfs
cd rootfs
echo "--------Create root,dev....----------"
mkdir root dev etc boot tmp var sys proc lib mnt home
mkdir etc/init.d etc/rc.d etc/sysconfig
mkdir usr/sbin usr/bin usr/lib usr/modules
echo "make node in dev/console dev/null"
mknod -m 600 dev/console c 5 1
mknod -m 600 dev/null
c13
mkdir mnt/etc mnt/jffs2 mnt/yaffs mnt/data mnt/temp
mkdir var/lib var/lock var/run var/tmp
chmod 1777 tmp
chmod 1777 var/tmp
echo "-------make direction done---------"
改变了 tmp 目录的使用权,让它开启 sticky 位,为 tmp 目录的使用权开启此位,可确保
tmp 目录底下建立的文件,只有建立它的用户有权删除。尽管嵌入式系统多半是单用户,不过
有些嵌入式应用不一定用 root 的权限来执行,因此需要遵照根文件系统权限位的基本规定来
设计。
4.2.4 建立动态链接库
动态链接库直接用友善之臂的,先解压友善之臂的根文件包,拷贝 lib 的内容到新建的
根文件目录 lib 内。
cd /mnt/hgfs/share
tar –zxvf root_qtopia.tgz –C /opt/studyarm
cp –rfd /opt/studyarm/root_qtopia/lib/* /opt/studyarm/rootfs/lib/*
4.2.5 交叉编译 Bosybox
Bosybox 是一个遵循 GPL v2 协议的开源项目,它在编写过程总对文件大小进行优化,
并考虑了系统资源有限(比如内存等)的情况,使用 Busybox 可以自动生成根文件系统所需的
bin、sbin、usr 目录和 linuxrc 文件。
1、解压 busybox
cd /mnt/hgfs/share
tar –zxvf busybox-1.13.3.tar.tgz –C /opt/studyarm
2、进入源码,修改 Makefile 文件:
cd /opt/studyarm/busybox-1.13.3
修改:
CROSS_COMPILE ?=arm-linux-
ARCH ?=arm //第 189 行
//第 164 行
3、配置 busybox
提示:友善之臂已经在光盘中提供了 busybox 的源代码包,在光盘\linux 目录中,文件
名为:busybox-1.13.3-mini2440.tgz(用户手册 5.4 章节介绍了解压安装的方法)
,解压后里面包
含了友善之臂提供的缺省配置文件:fa_config(输入命令“cp fa.config .config”可以调用该配
置),一般用户直接使用缺省文件就可以了,这样生成的 busybox 和 root_qtopia 中的是完全一
致的。但为了对它的配置了解更多一些,可以参考原文作者的如下步骤:
输入 make menuconfig 进行配置
(1)、Busybox Settings--->
General Configuration--->
[*] Show verbose applet usage messages
[*] Store applet usage messages in compressed form
[*] Support –install [-s] to install applet links at runtime
[*] Enable locale support(system needs locale for this to work)
[*] Support for –long-options
[*] Use the devpts filesystem for unix98 PTYs
[*] Support writing pidfiles
[*] Runtime SUID/SGID configuration via /etc/busybox.config
[*] Suppress warning message if /etc/busybox.conf is not readable
Build Options--->
[*] Build BusyBox as a static binary(no shared libs)
[*] Build with Large File Support(for accessing files>2GB)
Installation Options->
[]Don’t use /usr
Applets links (as soft-links) --->
(./_install) BusyBox installation prefix
Busybox Library Tuning --->
(6)Minimum password legth
(2)MD5:Trade Bytes for Speed
[*]Fsater /proc scanning code(+100bytes)
[*]Command line editing
(1024)Maximum length of input
[*] vi-style line editing commands
(15) History size
[*] History saving
[*] Tab completion
[*]Fancy shell prompts
(4) Copy buffer size ,in kilobytes
[*]Use ioctl names rather than hex values in error messages
[*]Support infiniband HW
(2)、Linux Module Utilities--->
(/lib/modules)Default directory containing modules
(modules.dep)Default name of modules.dep
[*] insmod
[*] rmmod
[*] lsmod
[*] modprobe
-----options common to multiple modutils
[ ] support version 2.2/2.4 Linux kernels
[*]Support tainted module checking with new kernels
[*]Support for module .aliases file
[*] support for modules.symbols file
(3)、在 busybox 中配置对 dev 下设备类型的支持
dev 的创建有三种方法:
手动创建:在制作根文件系统的时候,就在 dev 目录下创建好要使用的设备文件,系统
挂接根文件系统后,就可以使用 dev 目录下的设备文件了。
使用 devfs 文件系统:这种方法已经过时,具有不确定的设备映射、没有足够的主/次设
备号、devfs 消耗大量的内存。
udev:它是个用户程序,能根据系统中硬件设备的状态动态的更新设备文件,包括设备
文件的创建、删除等。它的操作相对复杂,但灵活性很高
mdev 是 busybox 自带的一个简化版的 udev,适合于嵌入式的应用埸合。其具有使用简
单的特点。它的作用,就是在系统启动和热插拔或动态加载驱动程序时,自动产生驱动程序所
需的节点文件。在以 busybox 为基础构建嵌入式 linux 的根文件系统时,使用它是最优的选择。
下面的选项将增加对 mdev 的支持。
Linux System Utilities --->
[*]Support /etc/mdev.conf
[*]Support command execution at device addition/removal
4、编译 busybox
编译 busybox 到指定目录:
cd /opt/studyarm/busybox-1.13.3
make CONFIG_PREFIX=/opt/studyarm/rootfs install
在 rootfs 目录下会生成目录 bin、sbin、usr 和文件 linuxrc 的内容。
4.2.6 建立 etc 目录下的配置文件
1、etc/mdev.conf 文件,内容为空。
2、拷贝主机 etc 目录下的 passwd、group、shadow 文件到 rootfs/etc 目录下。
3、etc/sysconfig 目录下新建文件 HOSTNAME,内容为”H3-Studio”
。
4、etc/inittab 文件:
#etc/inittab
::sysinit:/etc/init.d/rcS
s3c2410_serial0::askfirst:-/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a –r
5、etc/init.d/rcS 文件:
#!/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
runlevel=S
prevlevel=N
umask 022
export PATH runlevel prevlevel
echo "----------munt all----------------"
mount -a
echo /sbin/mdev>/proc/sys/kernel/hotplug
mdev -s
echo "***********************************************"
echo "****************Studying ARM*********************"
echo "Kernel version:linux-2.6.29.1"
echo "Student:Huang huahai"
echo "Date:2009.10.1"
echo "***********************************************"
/bin/hostname -F /etc/sysconfig/HOSTNAME
(或者直接 /bin/hostname H3-Studio )
使用以下命令改变 rcS 的执行权限:
Chmod +x rcS
6、etc/fstab 文件:
#device
mount-point
type
option
dump fsck
proc
/proc
proc
defaults
0
0
none
/tmp
ramfs
defaults
0
0
sysfs
/sys
sysfs
defaults
0
0
mdev
/dev
ramfs
defaults
0
0
7、 etc/profile 文件:
#Ash profile
#vim:syntax=sh
#No core file by defaults
#ulimit -S -c 0>/dev/null 2>&1
USER="id -un"
LOGNAME=$USER
PS1='[\u@\h=W]#'
PATH=$PATH
HOSTNAME='/bin/hostname'
export USER LOGNAME PS1 PATH
order
4.2.7 制作根文件系统映像文件
使用以下命令安装好 yaffs 文件系统制作工具:
cd /mnt/hgfs/share
tar –zxvf mkyaffs2image.tgz –C /
在/opt/studyarm 目录下,使用命令 mkyaffs2image rootfs rootfs.img 生成根文件系统映像
文件。
启动信息:
Copy linux kernel from 0x00050000 to 0x30008000, size = 0x00200000 ... done
zImage magic = 0x016f2818
Setup linux parameters at 0x30000100
linux command line is: "noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0"
MACH_TYPE = 782
NOW, Booting Linux......
Uncompressing Linux........................................................................................................................... done, booting the kernel.
Linux version 2.6.29.1 (root@FriendlyARM) (gcc version 4.3.2 (Sourcery G++ Lite 2008q3-72) ) #2 Thu Oct 1 16:46:24 JST
2009
CPU: ARM920T [41129200] revision 0 (ARMv4T), cr=c0007177
CPU: VIVT data cache, VIVT instruction cache
Machine: Study-S3C2440
ATAG_INITRD is deprecated; please update your bootloader.
Memory policy: ECC disabled, Data cache writeback
CPU S3C2440A (id 0x32440001)
S3C24XX Clocks, (c) 2004 Simtec Electronics
S3C244X: core 405.000 MHz, memory 101.250 MHz, peripheral 50.625 MHz
CLOCK: Slow mode (1.500 MHz), fast, MPLL on, UPLL on
Built 1 zonelists in Zone order, mobility grouping on.
Total pages: 16256
Kernel command line: noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0
irq: clearing subpending status 00000003
irq: clearing subpending status 00000002
PID hash table entries: 256 (order: 8, 1024 bytes)
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: 60828KB available (3556K code, 302K data, 156K init)
Calibrating delay loop... 201.93 BogoMIPS (lpj=504832)
Mount-cache hash table entries: 512
CPU: Testing write buffer coherency: ok
net_namespace: 716 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 c4808000, irq 33
DMA channel 1 at c4808040, irq 34
DMA channel 2 at c4808080, irq 35
DMA channel 3 at c48080c0, irq 36
S3C244X: Clock Support, DVS off
bio: create slab <bio-0> at 0
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)
yaffs Oct
© 2001-2006 Red Hat, Inc.
1 2009 16:45:43 Installing.
msgmni has been set to 118
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 driver, 4 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
ide-gd driver 1.18
ide-cd driver 5.00
Driver 'sd' needs updating - please use bus_type methods
S3C24XX NAND Driver, (c) 2004 Simtec Electronics
s3c2440-nand s3c2440-nand: Tacls=1, 9ns Twrph0=4 39ns, Twrph1=1 9ns
NAND device: Manufacturer ID: 0xec, Chip ID: 0x76 (Samsung NAND 64MiB 3,3V 8-bit)
Scanning device for bad blocks
Bad eraseblock 3339 at 0x00000342c000
Creating 8 MTD partitions on "NAND 64MiB 3,3V 8-bit":
0x000000000000-0x000000030000 : "bootloder"
0x000000050000-0x000000250000 : "kernel"
0x000000250000-0x000003ffc000 : "root"
0x000000800000-0x000000a00000 : "S3C2410 flash partition 3"
0x000000a00000-0x000000e00000 : "S3C2410 flash partition 4"
0x000000e00000-0x000001800000 : "S3C2410 flash partition 5"
0x000001800000-0x000003000000 : "S3C2410 flash partition 6"
0x000003000000-0x000004000000 : "S3C2410 flash partition 7"
usbmon: debugfs is not available
ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
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
USB Serial support registered for generic
usbcore: registered new interface driver usbserial_generic
usbserial: USB Serial Driver core
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
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 98 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)
yaffs: dev is 32505858 name is "mtdblock2"
yaffs: passed flags ""
yaffs: Attempting MTD mount on 31.2, "mtdblock2"
yaffs: block 3191 is marked bad
block 3192 is bad
yaffs_read_super: isCheckpointed 0
VFS: Mounted root (yaffs filesystem) on device 31:2.
Freeing init memory: 156K
------mount all------
************************************
**********studyARM******************
Kernel version:linux-2.6.29.1
Student:Huang huahai
Data:2009.10.1
***********************************
Please press Enter to activate this console.
看到了,ok!
4.3 mdev 的使用方法和原理
说明:本文同样出自网友 hugerat
原文网址:http://blog.csdn.net/hugerat/archive/2008/12/03/3437099.aspx
mdev 是 busybox 自带的一个简化版的 udev,适合于嵌入式的应用埸合。其具有使用简
单的特点。它的作用,就是在系统启动和热插拔或动态加载驱动程序时,自动产生驱动程序所
需的节点文件。在以 busybox 为基础构建嵌入式 linux 的根文件系统时,使用它是最优的选择。
4.3.1 mdev 的使用
mdev 的使用在 busybox 中的 mdev.txt 文档已经将得很详细了。但作为例子,我简单讲
讲我的使用过程:
(1)在编译时加上对 mdev 的支持
说明: 我使用的是 busybox1.10.1
Linux System Utilities ---> mdev
Support /etc/mdev.conf
Support command execution at device addition/removal
(2)在启动时加上使用 mdev 的命令
我在自己创建的根文件系统(nfs)中的/linuxrc 文件中添加了如下指令:
#挂载/sys 为 sysfs 文件系统
echo "----------mount /sys as sysfs"
/bin/mount -t tmpfs mdev /dev
/bin/mount -t sysfs sysfs /sys
echo "----------Starting mdev......"
/bin/echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
注意:是/bin/echo /sbin/mdev > /proc/sys/kernel/hotplug,并非/bin/echo /bin/mdev >
/proc/sys/kernel/hotplug。
busybox 的文档有错!
!
(3)在驱动中加上对类设备接口的支持
在驱动程序的初始化函数中,使用下述的类似语句,就能在类设备目录下添加包含
设备号的名为
“dev”
的属性文件。
并通过 mdev 在/dev 目录下产生 gpio_dev0 的设备节点文件。
my_class = class_create(THIS_MODULE, "gpio_class");
if(IS_ERR(my_class)) {
printk("Err: failed in creating class.\n");
return -1;
}
/* register your own device in sysfs, and this will cause mdev to create corresponding
device node */
class_device_create(my_class,
MKDEV(gpio_major_number,
0),
NULL,
"gpio_dev%d" ,0);
在驱动程序的清除程序段,加入以下语句,以完成清除工作。
class_device_destroy(my_class, MKDEV(gpio_major_number, 0));
class_destroy(my_class);
需要的头文件是 linux/device.h,因此程序的开始应加入下句
#include <linux/device.h>
另外,my_class 是 class 类型的结构体指针,要在程序开始时声明成全局变量。
struct class *my_class;
上述程序中的 gpio_major_number 是设备的主节点号。可以换成需要的节点号。
gpio_dev 是最终生成的设备节点文件的名子。%d 是用于以相同设备自动编号的。gpio_class
是建立的 class 的名称,当驱动程序加载后,可以在/sys/class 的目录下看到它。
上述语句也不一定要在初始化和清除阶段使用,可以根据需要在其它地方使用。
(4)/etc/mdev.conf 文件
至于/etc/mdev.conf 文件,可有可无,不影响使用,只是添加了些功能。
关于 mdev 的使用方法,我在网上找到一篇中文版的。大家可以到我上传的资源中下
载。
4.3.2 mdev 的原理
要想真正用好 mdev,适当知道一下原理是必不可少的,现在简单介绍一下 mdev 的
原理:
(1)执行 mdev -s
说明:以‘-s’为参数调用位于/sbin 目录写的 mdev(其实是个链接,作用是传递参
数给/bin 目录下的 busybox 程序并调用它)
,mdev 扫描 /sys/class 和/sys/block 中所有的类设备
目录,如果在目录中含有名为“dev”的文件,且文件中包含的是设备号,则 mdev 就利用这
些信息为这个设备在/dev 下创建设备节点文件。一般只在启动时才执行一次 “mdev -s”
。
(2)热插拔事件
由于启动时运行了命令:echo /sbin/mdev > /proc/sys/kernel/hotplug ,那么当有热插拔
事件产生时,
内核就会调用位于/sbin 目录的 mdev。
这时 mdev 通过环境变量中的 ACTION 和
DEVPATH,
(这两个变量是系统自带的)来确定此次热插拔事件的动作以及影响了
/sys 中的那个目录。接着会看看这个目录中是否有“dev”的属性文件,如果有就利用这些信
息为
这个设备在/dev 下创建设备节点文件。
4.3.3 一个使用 mdev 的 gpio 控制驱动示例
最后,附上我在工作中编写的一段简单的 gpio 控制驱动程序。此程序没有什么功能,
主要是做一些测试用的。有兴趣的朋友可以用它测试一下上述的 mdev 的使用方法。我用的是
友善公司的 mini2440 开发板。
#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/kernel.h>
/* printk() */
#include <linux/fs.h>
/* everything... */
#include <linux/cdev.h>
#include <linux/interrupt.h>
/* request_irq() */
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-irq.h>
#include <asm/io.h>
#include <asm/uaccess.h>
/* copy_to_user() */
#include <linux/delay.h>
/* mdelay() */
#include <linux/device.h>
/*class_create()*/
#include <asm/arch-s3c2410/regs-gpio.h>
#include <asm/arch-s3c2410/regs-timer.h>
#define VERSION_STRING
"gpio driver for JM_Xcontrol"
#define DEVICE_NAME "JM_Xcontrol_gpio"
/* Use 0xE0 as magic number */
#define XRAY_IOC_MAGIC 0xE0
#define XRAY_IOCLCDBACKLIGHT
_IO(XRAY_IOC_MAGIC, 0)
#define XRAY_IOC485REC
_IO(XRAY_IOC_MAGIC, 1)
#define XRAY_IOC485TRC
_IO(XRAY_IOC_MAGIC, 2)
#define XRAY_IOCBUZZER
_IO(XRAY_IOC_MAGIC, 3)
#define XRAY_IOC_MAXNR 12
MODULE_AUTHOR("hugerat");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION(VERSION_STRING);
unsigned int gpio_major_number=0;
struct cdev gpio_dev;
struct class *my_class;
static int gpio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
int err=0;
unsigned long tmp;
//-------以下检查命令---------//
if (_IOC_TYPE(cmd) != XRAY_IOC_MAGIC) return -ENOTTY;
if (_IOC_NR(cmd) > XRAY_IOC_MAXNR) return -ENOTTY;
if (_IOC_DIR(cmd) & _IOC_READ)
err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd));
else if (_IOC_DIR(cmd) & _IOC_WRITE)
err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));
if (err)
return -EFAULT;
//--------------------------//
switch ( cmd )
{
case XRAY_IOCLCDBACKLIGHT: //控制 LCD 背光开关
if(arg==0)
{
s3c2410_gpio_setpin(S3C2410_GPB1, 1);
}
else
{
s3c2410_gpio_setpin(S3C2410_GPB1, 0);
}
break;
case XRAY_IOC485REC:
if(arg==0)
{
s3c2410_gpio_setpin(S3C2410_GPG10, 1);
}
else
{
s3c2410_gpio_setpin(S3C2410_GPG10, 0);
}
break;
case XRAY_IOC485TRC:
if(arg==0)
{
s3c2410_gpio_setpin(S3C2410_GPG12, 0);
}
else
{
s3c2410_gpio_setpin(S3C2410_GPG12, 1);
}
break;
case XRAY_IOCBUZZER:
if(arg==0)
{
s3c2410_gpio_setpin(S3C2410_GPB0, 0);
}
else
{
s3c2410_gpio_setpin(S3C2410_GPB0, 1);
}
break;
default:
break;
}
return 0;
}
static struct file_operations gpio_fops = {
.owner = THIS_MODULE,
//.open
= xray_open,
//.release = xray_release,
//.read
= xray_read,
//.write = xray_write,
.ioctl = gpio_ioctl,
//.fasync = xray_fasync,
};
static int __init gpio_init(void)
{
int ret,devno;
dev_t dev;
unsigned long tmp;
ret = alloc_chrdev_region(&dev,0,1,DEVICE_NAME);
gpio_major_number = MAJOR(dev);
printk(KERN_INFO "Initial jm_xcontrol_gpio driver!\n");
if (ret<0) {
printk(KERN_WARNING "gpio:can't get major number %d\n",gpio_major_number);
return ret;
}
devno = MKDEV(gpio_major_number,0);
cdev_init(&gpio_dev,&gpio_fops);
gpio_dev.owner = THIS_MODULE;
gpio_dev.ops
= &gpio_fops;
ret = cdev_add(&gpio_dev,devno,1);
if (ret) {
unregister_chrdev_region(dev,1);
printk(KERN_NOTICE "Error %d adding gpio device\n",ret);
return ret;
}
my_class = class_create(THIS_MODULE, "gpio_class");
if(IS_ERR(my_class)) {
printk("Err: failed in creating class.\n");
return -1;
}
/* register your own device in sysfs, and this will cause mdev to create corresponding device node */
class_device_create(my_class, MKDEV(gpio_major_number, 0), NULL, "gpio_dev%d" ,0);
//LCD 背光
s3c2410_gpio_cfgpin(S3C2410_GPB1, S3C2410_GPB1_OUTP);
s3c2410_gpio_setpin(S3C2410_GPB1, 0);
//蜂鸣器
s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPB0_OUTP);
s3c2410_gpio_setpin(S3C2410_GPB0, 0);
//485 收发控制
s3c2410_gpio_cfgpin(S3C2410_GPG10, S3C2410_GPG10_OUTP); //收
s3c2410_gpio_setpin(S3C2410_GPG10, 0);
s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPG12_OUTP);
s3c2410_gpio_setpin(S3C2410_GPG12, 0);
return 0;
}
static void __exit gpio_cleanup(void)
{
unsigned long tmp;
dev_t dev=MKDEV(gpio_major_number,0);
cdev_del(&gpio_dev);
class_device_destroy(my_class, MKDEV(gpio_major_number, 0));
class_destroy(my_class);
unregister_chrdev_region(dev,1);
s3c2410_gpio_setpin(S3C2410_GPB1, 1); //关背光
s3c2410_gpio_setpin(S3C2410_GPB0, 0); //关蜂鸣器
s3c2410_gpio_setpin(S3C2410_GPG10, 1); //关 485 收
s3c2410_gpio_setpin(S3C2410_GPG12, 0); //关 485 发
printk(KERN_INFO "unregistered the %s\n",DEVICE_NAME);
}
module_init(gpio_init);
module_exit(gpio_cleanup);
(待续)
//发
相关阅读 更多 +