您好,欢迎来到爱够旅游网。
搜索
您的当前位置:首页linux-2.6.32.2内核在mini2440上基于supervivi的移植

linux-2.6.32.2内核在mini2440上基于supervivi的移植

来源:爱够旅游网
linux 2.6.32.2 mini2440平台移植--内核移植、yaffs2文件系统移植 1.1 获取Linux内核源代码

有很多方式可以获取Linux内核源代码,如果你的linux平台可以上互联网,可以直接在命令行输入以下命令获取到Linux-2.6.32.2:

#wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.32.2.tar.gz

当然你也可以先在Windows系统下使用迅雷等工具下载完,再复制到linux中。 1.2 解压内核源代码

假定我们刚才把内核源代码下载到了/root/mini2440目录,执行以下解压命 令:

#cd /opt/FriendlyARM/mini2440 #tar xvzf linux-2.6.32.2.tar.gz 1.3 指定交叉编译变量

我们移植目的是让Linux-2.6.32.2可以在mini2440上运行。

首先,我们要使得Linux-2.6.32.2的缺省目标平台成为ARM的平台。 修改总目录下的Makefile 原

export KBUILD_BUILDHOST := $(SUBARCH) ARCH ?= $(SUBARCH) CROSS_COMPILE ?= 改为

export KBUILD_BUILDHOST := $(SUBARCH) ARCH ?= arm

CROSS_COMPILE ?= arm-linux-

其中,ARCH是指定目标平台为arm,CROSS_COMPILE是指定交叉编译器,这里指定的是系统默认的交叉编译器,如要使用其它的,则要把编译器的全路径在这里写出。 接下来,要测试一下linux的编译是否能正常通过。 执行:

#make s3c2410_defconfig ;使用缺省内核配置文件,s3c2410_defconfig是SMDK2440的缺省配置文件,我的s3c2410_defconfig文件位于/arch/arm/configs/s3c2410_defconfig #make ;编译时间较长

编译通过,在此我们先不必烧写到开发板验证它的正确性。

1.4 克隆建立自己的目标平台 1.4.1关于机器码

以上编译是用的Linux内核本身支持的目标平台配置,它对应于SMDK2440。现在我们要参考SMDK2440加入自已的开发板平台,我们使用的是mini2440,因此取名为MINI2440。需要说明的是,Linux-2.6.32.2本身已经包含了mini2440的支持,这样就出现了重名。那怎么办呢?在此我们依然使用MINI2440这个名称,只不过在后面的移植步骤中,把原始内核自带的mini2440代码部分直接删除就可以了,以免和我们自己移植的混淆了。首先,很关键的一点,内核在启动时,是通过bootloader传入的机器码(MACH_TYPE)确定应启动哪种目标平台的,友善之臂已经为mini2440申请了自己的机器码为1999,它位于linux-2.6.32.2/arch/arm/tools/mach_types文件中.

如果内核的机器码和bootloader传入的不匹配,就会经常出现下面的错误: Uncompressing

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

运行到这不就停住了

提示:在U-boot/include/asm-arm/mach-types.h中可以看到mini2440的机器码定义 接下来,我们注意到linux-2.6.32.2/arch/arm/mach-s3c2440目录下有个

mach-mini2440.c文件,它其实就是国外爱好者为mini2440移植添加的主要内容了,但我们不用它,把它直接删除。将linux-2.6.32.2/arch/arm/mach-s3c2440/目录下的mach-smdk2440.c复制一份。命名为mach-mini2440.c,

找到MACHINE_START(S3C2440, \"SMDK2440\"),修改为

MACHINE_START(MINI2440, \"FriendlyARM Mini2440 development board\")。

提示:开发板运行后,在命令行终端输入:cat /proc/cpuinfo 可以看到我们添加的开发板信息

1.4.2 修改时钟源频率

现在再来修改系统时钟源,在mach-mini2440.c(就是我们刚刚通过复制

mach-smdk2440.c得到的)的第160行static void __init smdk2440_map_io(void)函数中,把其中的16934400(代表原SMDK2440目标板上的晶振是16.9344MHz)改为mini2440开发板上实际使用的12,000,000(代表mini2440开发板上的晶振12MHz,元器件标号为X2)

1.4.3 从SMDK2440到MINI2440

因为我们要制作自己的mini2440平台体系,因此把mach-mini2440.c中所有的 smdk2440字样改为mini2440,可以使用批处理命令修改,在vim的命令模式下输入: %s/smdk2440/mini2440/g

上面这句的意思是:把所有和―smdk2440‖匹配的字符串全部替换为―mini2440‖,前面的―%s―代表字符串匹配,最后的―g‖代表global,是全局的意思,

除此之外,还有一个地方需要改动,在mini2440_machine_init(void)函数中,把

smdk_machine_init()函数调用注释掉,因为我们后面会编写自己的初始化函数,不需要调用smdk2440原来的.

1.4.4 编译测试

在Linux源代码根目录下执行

#make mini2440_defconfig ;使用Linux官方自带的mini2440配置 #make zImage ;编译内核,时间较长,最后会生成zImage

我的s3c2410_defconfig文件位于/arch/arm/configs/mini2440_defconfig

重新编译并把生成的内核文件zImage(位于arch/arm/boot目录)下到板子中,可以看到内核已经可以正常启动了,但此时大部分硬件驱动还没加,并且也没有文件系统,因此还无法登陆。 注意:

(1)如果你先前已经编译过内核了,请先清理一下,不然会提示编译的文件过时了。 (2)注意在先前关于机器码一项时修改的MACHINE_START(S3C2440, \"SMDK2440\"),修改为

MACHINE_START(MINI2440, \"FriendlyARM Mini2440 development board\")。 这里的MINI2440必须要大写,我自己的理解是跟机器码里面的类型一致。

1.5 关于内核配置菜单中的mini2440选项

在开始移植其他驱动之前,我们再了解一些看起来比较―神秘‖的常识,那就是运行make menuconfig时,内核配置菜单中的mini2440选项是如何出现的。 在命令行执行:

#make menuconfig ;前面已经执行了make mini2440_defconfig加载了缺省配置,因此这里可以直接执行该命令

按上下键移动到System Type,按回车进入该子菜单,再找到S3C2440 Machines,按回车进入该子菜单

在此就可以看到Linux天生内核对mini2440开发板的支持选项了,那么它们是从哪里来的呢?

打开Linux-2.6.32.2/arch/arm/mach-s3c2440/Kconfig文件可以找到相关信息。

现在明白了吧,―MINI2440 development board‖正是在这个Kconfig文件中定义说明的, 当然你可以根据自己的喜好改为其他显示信息。

这里的显示信息只是在内核配置菜单中出现的,要让选择的配置实际起效,还需要根据此配置在Makefile中添加相应的代码文件,请看该目录下的Makefile。

这样,配置文件就跟实际的代码文件通过配置定义联系在一起了,这里的配置定义是―CONFIG_MACH_MINI2440‖,内核中还有很多类似的配置定义,并且有的配置定义还存在依赖关系,我们在此就不对它们详细说明了,随着对内核代码结构的不断熟悉,你就会逐渐学会分析和查找你所需要的各种配置和定义等。

1.6 移植Nand驱动并更改分区信息

1.6.1 Linux-2.6.32.2内核所支持的Nand Flash类型

Linux2.6.32.2已经自带了大部分Nand Flash驱动,在

linux-2.6.32.2/drivers/mtd/nand/nand_ids.c文件中,定义了所支持的各种Nand Flash类型。

1.6.2 修改Nand Flash分区表

但是系统默认的分区不是我们所需的,所以要自已修改,除此之外,还有Nand Flash的结构信息需要增加填写,以便能够适合系统自带的Nand Flash驱动接口,这可以参考SMDK2440中关于Nand Flash设备注册的一些信息。

打开/arch/arm/plat-s3c24xx/common-smdk.c,可以看到这样一个结构体: 注意这里是参考这个文件夹的内容,改动还是在mach-mini2440.c static struct mtd_partition smdk_default_nand_part[] = { [0] = {

.name = \"Boot Agent\ .size = SZ_16K, .offset = 0, }, [1] = {

.name = \"S3C2410 flash partition 1\ .offset = 0, .size = SZ_2M, }, [2] = {

.name = \"S3C2410 flash partition 2\ .offset = SZ_4M,

.size = SZ_4M, }, [3] = {

.name = \"S3C2410 flash partition 3\ .offset = SZ_8M, .size = SZ_2M, }, [4] = {

.name = \"S3C2410 flash partition 4\ .offset = SZ_1M * 10, .size = SZ_4M, }, [5] = {

.name = \"S3C2410 flash partition 5\ .offset = SZ_1M * 14, .size = SZ_1M * 10, }, [6] = {

.name = \"S3C2410 flash partition 6\ .offset = SZ_1M * 24, .size = SZ_1M * 24, }, [7] = {

.name = \"S3C2410 flash partition 7\ .offset = SZ_1M * 48, .size = SZ_16M, } };

这其实就是Nand Flash的分区表,在Linux-2.6.32.2中,nand驱动是被注册为平台设备的,这同样可在/arch/arm/plat-24xx/common-smdk.c文件中看出,如下: static struct s3c2410_platform_nand smdk_nand_info = { .tacls = 20, .twrph0 = 60, .twrph1 = 20,

.nr_sets = ARRAY_SIZE(smdk_nand_sets),

.sets = smdk_nand_sets, };

/* devices we initialise */

static struct platform_device __initdata *smdk_devs[] = { &s3c_device_nand, &smdk_led4, &smdk_led5, &smdk_led6, &smdk_led7, };

参考以上结构信息,我们也在自己的mach-mini2440.c中照此添加实现,同时需要参考友善之臂原厂内核中的Nand分区表

因此,在mach-mini2440.c中加入以下代码: 首先添加几个头文件: #include #include #include #include #include 然后加入以下代码:

static struct mtd_partition mini2440_default_nand_part[] = { [0] = {

.name = \"supervivi\这里是bootloader所在的分区,可以放置u-boot, supervivi等内容,对应/dev/mtdblock0 .size = 0x00040000, .offset = 0, }, [1] = {

.name = \"param\这里是supervivi的参数区,其实也属于bootloader的一部分,如果u-boot比较大,可以把此区域覆盖掉,不会影响系统启动,对应/dev/mtdblock1

.offset = 0x00040000, .size = 0x00020000, },

[2] = {

.name = \"Kernel\内核所在的分区,大小为5M,足够放下大部分自己定制的巨型内核了,比如内核使用了更大的Linux Logo图片等,对应/dev/mtdblock2 .offset = 0x00060000, .size = 0x00500000, }, [3] = {

.name = \"root\文件系统分区,友善之臂主要用来存放yaffs2文件系统内容,对应/dev/mtdblock3

.offset = 0x00560000, .size = 1024 * 1024 * 1024, // }, [4] = {

.name = \"nand\此区域代表了整片的nand flash,主要是预留使用,比如以后可以通过应用程序访问读取/dev/mtdblock4就能实现备份整片nand flash了。 .offset = 0x00000000, .size = 1024 * 1024 * 1024, // } };

//这里是开发板的nand flash设置表,因为板子上只有一片,因此也就只有一个表 static struct s3c2410_nand_set mini2440_nand_sets[] = { [0] = {

.name = \"NAND\ .nr_chips = 1,

.nr_partitions = ARRAY_SIZE(mini2440_default_nand_part), .partitions = mini2440_default_nand_part, }, };

//这里是nand flash本身的一些特性,一般需要对照datasheet填写,大部分情况下按照以下参数填写即可

static struct s3c2410_platform_nand mini2440_nand_info = { .tacls = 20, .twrph0 = 60, .twrph1 = 20,

.nr_sets = ARRAY_SIZE(mini2440_nand_sets), .sets = mini2440_nand_sets, .ignore_unset_ecc = 1, };

//除此之外,还需要把nand flash设备注册到系统中, static struct platform_device *mini2440_devices[] __initdata = { &s3c_device_usb, &s3c_device_lcd, &s3c_device_wdt, &s3c_device_i2c0, &s3c_device_iis,

&s3c_device_nand, //把nand flash设备添加到开发板的设备列表结构 };

找到下边程序添加一条语句:

static void __init mini2440_machine_init(void){ s3c24xx_fb_set_platdata(&mini2440_fb_info); s3c_i2c0_set_platdata(NULL);

s3c_device_nand.dev.platform_data = &mini2440_nand_info; //添加 platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices)); }

注意:mini2440_default_nand_part、mini2440_nand_sets、mini2440_nand_info三个结构体顺序不能错。另外,这三段最好放在顶端头文件的下边,之前测试过放在下边有编译出错的情况不知时候与位置有关。。。

到这里就完成了NandFlash的驱动的移植,可以下载到开发板运行看看启动的信息了。

1.6.3 从启动信息中查看分区表

注意:虽然说开始信息里面uncorrectable error :这样的错误,但是还是可以继续成功,这里不要在意这些error。

至此,就完成了nand flash驱动的移植,此时在内核根目录执行―make zImage‖,把生成的zImage烧写到开发板,可以在启动时看到如图红色信息,它们正是我们刚刚添加的nand flash分区信息,以及开发板本身nand flash的一些信息,这里可以看到是256M的nand flash。

S3C24XX NAND Driver, (c) 2004 Simtec Electronics

s3c24xx-nand s3c2440-nand: Tacls=3, 29ns Twrph0=7 69ns, Twrph1=3 29ns s3c24xx-nand s3c2440-nand: NAND soft ECC

NAND device: Manufacturer ID: 0xec, Chip ID: 0xda (Samsung NAND 256MiB 3,3V 8-bi t)

Scanning device for bad blocks

Bad eraseblock 256 at 0x000002000000 Bad eraseblock 257 at 0x000002020000 Bad eraseblock 317 at 0x0000027a0000 Bad eraseblock 1261 at 0x000009da0000

Creating 5 MTD partitions on \"NAND 256MiB 3,3V 8-bit\": 0x000000000000-0x000000040000 : \"supervivi\" uncorrectable error :

0x000000040000-0x000000060000 : \"param\" ftl_cs: FTL header not found.

0x000000060000-0x000000560000 : \"Kernel\" 0x000000560000-0x000040560000 : \"root\"

mtd: partition \"root\" extends beyond the end of device \"NAND 256MiB 3,3V 8-bit\"

-- size truncated to 0xfaa0000 ftl_cs: FTL header not found.

0x000000000000-0x000040000000 : \"nand\"

mtd: partition \"nand\" extends beyond the end of device \"NAND 256MiB 3,3V 8-bit\"

-- size truncated to 0x10000000

uncorrectable error :

dm9000 Ethernet Driver, V1.31

dm9000 dm9000: eth%d: Invalid ethernet MAC address. Please set using ifconfig

eth0: dm9000e at c486e300,c4872304 IRQ 51 MAC: 00:00:00:00:00:00 (chip) 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

s3c2440-usbgadget s3c2440-usbgadget: S3C2440: increasing FIFO to 128 bytes

mice: PS/2 mouse device common for all mice S3C24XX RTC, (c) 2004,2006 Simtec Electronics s3c2410-rtc s3c2410-rtc: rtc disabled, re-enabling s3c2410-rtc s3c2410-rtc: rtc core: registered s3c as rtc0 i2c /dev entries driver

S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics

s3c2410-wdt s3c2410-wdt: watchdog inactive, reset disabled, irq enabled cpuidle: using governor ladder

sdhci: Secure Digital Host Controller Interface driver sdhci: Copyright(c) Pierre Ossman s3c-sdi s3c2440-sdi: powered down.

s3c-sdi s3c2440-sdi: mmc0 - using pio, sw SDIO IRQ usbcore: registered new interface driver hiddev usbcore: registered new interface driver usbhid

1.7 移植yaffs2

1.7.1 获取yaffs2源代码

现在大部分开发板都可以支持yaffs2文件系统,它是专门针对嵌入式设备,特别是使用nand flash作为存储器的嵌入式设备而创建的一种文件系统,早先的yaffs

仅支持小页(512byte/page)的nand flash,现在的开发板大都配备了更大容量的nand flash,它们一般是大页模式的(2K/page),使用yaffs2就可以支持大页的nand flash,下面是yaffs2的移植详细步骤。 在

http://www.yaffs.net/node/346

可以下载到最新的yaffs2源代码,需要使用git工具,在命令行输入: #git clone git://www.aleph1.co.uk/yaffs2

稍等片刻,就可以下载到最新的yaffs2的源代码目录。

1.7.2 为内核打上yaffs2补丁

这可以通过yaffs2目录下的脚本文件patch-ker.sh来给内核打补丁,用法如下:

[root@localhost yaffs2]# ./patch-ker.sh c /root/linux-test/linux-2.6.32.2

usage: ./patch-ker.sh c/l m/s kernelpath if c/l is c, then copy. If l then link

if m/s is m, then use multi version code. If s then use single version code //注意这一句话,根据自己需要选用第二个参数是m还是s

[root@localhost yaffs2]# ./patch-ker.sh c s /root/linux-test/linux-2.6.32.2 *** Warning ***

You have chosen to use the single kernel variant of the yaffs VFS glue code

that only works with the latest Linux kernel tree. If you are using an older

version of Linux then you probably wanted to use the multi-version variant by

re-running the patch-ker.sh script using m as a the second argument.

ie ./patch-ker.sh c m /root/linux-test/linux-2.6.32.2 Updating /root/linux-test/linux-2.6.32.2/fs/Kconfig Updating /root/linux-test/linux-2.6.32.2/fs/Makefile [root@localhost yaffs2]#

注意第二个参数m/s,如果不指定,有时会执行失败。 上述命令完成下面三件事://有助于理解

<1>修改内核文件/fs/Kconfig,增加下面两行(在177行附近): if MISC_FILESYSTEMS source \"fs/adfs/Kconfig\" source \"fs/affs/Kconfig\" source \"fs/ecryptfs/Kconfig\" source \"fs/hfs/Kconfig\" source \"fs/hfsplus/Kconfig\" source \"fs/befs/Kconfig\" source \"fs/bfs/Kconfig\" source \"fs/efs/Kconfig\" source \"fs/yaffs2/Kconfig\" source \"fs/jffs2/Kconfig\" # UBIFS File system configuration

<2>修改内核文件/fs/Makefile,增加下面两行(在129行附近): obj-$(CONFIG_GFS2_FS) += gfs2/ obj-$(CONFIG_EXOFS_FS) += exofs/ obj-$(CONFIG_YAFFS_FS) += yaffs2/

<3>在内核文件的fs目录下创建yaffs2子目录,然后复制如下文件: 将yaffs2源码目录下的Makefile.kernel文件复制为内核fs/yaffs2/Makefile文件。

将yaffs2源码目录下的Kconfig文件复制为内核fs/yaffs2/目录下。 将yaffs2源码目录下的*.c、*.h文件(不包括子目录下的文件)复制为内核fs/yaffs2/目录下。

1.7.3 配置和编译带YAFFS2支持的内核

在 Linux 内核源代码根目录运行:make menuconfig,移动上下按键找到 File Systems,按回车进入该子菜单再找到\"Miscellaneous filesystems\"菜单项,按回车进入该子菜单,找到\"YAFFS2 file system support\",并按空格选中它,这样我们就在内核中添加了 yaffs2 文件系统的支持,按\"Exit\"退出内核配置。 在命令行执行: #make zImage

最后会生成linux-2.6.32.2/arch/arm/boot/zImage,使用supervivi的“k“功能把它烧写到nand flash,按“b“启动系统,这时,如果nand flash已经存在文件系统(可以使用supervivi的“y“功能烧写友善之臂提供的现成的yaffs2文件系统映像root_qtopia-128M.img用以测试),如果可以进入文件系统了,这说明yaffs2已经移植成功。

linux2.6.32.2 mini2440平台移植--移植DM9000网卡驱动

1.1.1 设备资源初始化

Linux-2..6.32.2已经自带了完善的DM9000网卡驱动 (源代码位置:linux-2.6.32.2/ drivers/net/dm9000.c),它也是一个平台设备,因此在目标平台初始化代码中,只要填写好相应的结构表即可(在mach-mini2440.c里面),具体步骤如下: 首先添加驱动所需的头文件dm9000.h: #include

再定义DM9000网卡设备的物理基地址,以便后面用到: /* DM9000AEP 10/100 ethernet controller */

#define MACH_MINI2440_DM9K_BASE (S3C2410_CS4 + 0x300)

再填充该平台设备的资源设置,以便和DM9000网卡驱动接口配合起来,如下 static struct resource mini2440_dm9k_resource[] = { [0] = {

.start = MACH_MINI2440_DM9K_BASE, .end = MACH_MINI2440_DM9K_BASE + 3, .flags = IORESOURCE_MEM }, [1] = {

.start = MACH_MINI2440_DM9K_BASE + 4, .end = MACH_MINI2440_DM9K_BASE + 7, .flags = IORESOURCE_MEM }, [2] = {

.start = IRQ_EINT7, .end = IRQ_EINT7,

.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE, } }; /*

* * * The DM9000 has no eeprom, and it's MAC address is set by * * * the bootloader before starting the kernel. * * */

static struct dm9000_plat_data mini2440_dm9k_pdata = {

.flags = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM), };

static struct platform_device mini2440_device_eth = {

.name = \"dm9000\ .id = -1,

.num_resources = ARRAY_SIZE(mini2440_dm9k_resource), .resource = mini2440_dm9k_resource, .dev = {

.platform_data = &mini2440_dm9k_pdata, }, };

//同时在mini2440设备集中添加上面做好的网卡平台设备,如下红色部分

static struct platform_device *mini2440_devices[] __initdata = { &s3c_device_usb, &s3c_device_lcd, &s3c_device_wdt, &s3c_device_i2c0, &s3c_device_iis, &mini2440_device_eth, &s3c_device_nand, };

这样,DM9000平台设备的接口就填完了。

1.1.2 调整DM9000所用的位宽寄存器

因为Linux-2.6.32.2的DM9000网卡驱动并不是专门为mini2440准备的,所以还要在其源代码中做一些移植工作,如下步骤。打开linux-2.6.32.2/ drivers/net/dm9000.c,头文件处添加2410相关的配置定义,如下 #include #include #include

#if defined(CONFIG_ARCH_S3C2410) #include #endif

#include \"dm9000.h\"

在dm9000设备的初始化函数中添加如下红色部分,这里是配置DM9000所用片选总线的时序,因为mini2440目前只有一个通过总线外扩的设备,在此设备驱动中直接修改相关的寄存器配置会更加容易理解一些,当然这部分也可以放到mach-mini2440.c中(注意将这部分放在mach-mini2440.c里会有几个常量需要自己找定义),你可以自行实验一下,在此不再赘述。

static int __init dm9000_init(void) {

#if defined(CONFIG_ARCH_S3C2410)

unsigned int oldval_bwscon = *(volatile unsigned int *)S3C2410_BWSCON; unsigned int oldval_bankcon4 = *(volatile unsigned int *)S3C2410_BANKCON4; *((volatile unsigned int *)S3C2410_BWSCON) =

(oldval_bwscon & ~(3<<16)) | S3C2410_BWSCON_DW4_16 | S3C2410_BWSCON_WS4 | S3C2410_BWSCON_ST4; *((volatile unsigned int *)S3C2410_BANKCON4) = 0x1f7c; #endif

printk(KERN_INFO \"%s Ethernet Driver, V%s\\n\

return platform_driver_register(&dm9000_driver); }

1.1.3 关于MAC地址

需要注意的是,本开发板所用的DM9000网卡并没有外接EEPROM用以存储MAC地址,因此系统中的MAC地址是一个―软‖地址,也就是可以通过软件进行修改,可以随意改为其他值,在static int __devinit dm9000_probe(struct platform_device *pdev)函数中可以看出: /* try reading the node address from the attached EEPROM */ //尝试从EEPROM读取MAC地址 for (i = 0; i < 6; i += 2)

dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i);

if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) { mac_src = \"platform data\";

memcpy(ndev->dev_addr, pdata->dev_addr, 6); }

if (!is_valid_ether_addr(ndev->dev_addr)) { /* try reading from mac */

mac_src = \"chip\"; for (i = 0; i < 6; i++)

ndev->dev_addr[i] = ior(db, i+DM9000_PAR); }

//使用―软‖MAC地址: 08:90:90:90:90:90

memcpy(ndev->dev_addr, \"\\x08\\x90\\x90\\x90\\x90\\x90\

if (!is_valid_ether_addr(ndev->dev_addr))

dev_warn(db->dev, \"%s: Invalid ethernet MAC address. Please \" \"set using ifconfig\\n\ 实际上到此为止DM9000就已经移植结束了。

1.1.4 配置内核加入DM9000,并编译运行测试 此时会带内核源代码目录,执行: #make menuconfig

开始在内核中配置网卡驱动,依次选择如下菜单项

Device Drivers --->Network device support ---> Ethernet (10 or 100Mbit) --->

即可找到DM9000的配置项,可以看到DM9000已经被选中,这是因为Linux-2.6.32.2默认的内核配置已经加入了DM9000的支持。 然后执行: #make zImage

最后生成 arch/arm/boot/zImage 文件,使用\"k\"命令把它烧写到开发板,并使用默认的文件系统启动,在命令行终端运行 ifconfig 命令可以看到如下所示。

[root@FriendlyARM /]# ifconfig

eth0 Link encap:Ethernet HWaddr 08:90:90:90:90:90

inet addr:192.168.1.230 Bcast:192.168.1.255 Mask:255.255.255.0 UP BROADCAST MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000

RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

Interrupt:51 Base address:0x300

lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0

UP LOOPBACK RUNNING MTU:136 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0

RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

测试网络:ping 127.0.0.1,等号后面有数的话,就是网卡正常ping 网关地址,等号后面有数的话,就是和网关连接正常ping 别的主机的IP,等号后面有数的话,就是和别的主机连接正常.

linux2.6.32.2 mini2440平台移植-- 激活 RTC 驱动

RTC的英文全称是Real-Time Clock,翻译过来是实时时钟芯片. RTC是PC主板上的晶振及相关电路组成的时钟电路的生成脉冲,RTC经过82电路的变频产生一个频率较低一点的OS(系统)时钟TSC,系统时钟每一个cpu周期加一,每次系统时钟在系统初起时通过RTC初始化。82本身工作也需要有自己的驱动时钟(PIT)。

1.2.1 在初始化文件中加入 RTC 设备结构

Linux-2.6.32.2 内核对 2440 的 RTC 驱动已经十分完善了,但并未在 mach-mini2440.c 中的设备集中加入它,因此并没有被激活,加入 RTC 结构体如下红色字体: ;在 mini2440 设备集中加入 RTC 结构体

static struct platform_device *mini2440_devices[] __initdata = { &s3c_device_usb, &s3c_device_rtc, &s3c_device_lcd, &s3c_device_wdt, &s3c_device_i2c0, &s3c_device_iis, &mini2440_device_eth, &s3c_device_nand, };

1.2.2 在内核中配置 RTC

接下来重新配置内核,以加入 RTC 的驱动支持,依次选择如下菜单项: Device Drivers ---> <*> Real Time Clock --->

可以看到这里缺省配置已经选择了 RTC 相关的选项,这里特别要注意的是该配置菜单最下方的<*> Samsung S3C series SoC RTC 选项支持,因为这里才是内核中真正的 2440 之RTC 驱动配置项。

1.2.3 测试 RTC

[root@localhost linux-2.6.32.2]# make zImage 编译生成zImage之后,将其烧写到开发板上。 [root@mini2440 /]#ls -l dev/rtc*

crw-rw---- 1 root root 2, 0 Jan 1 00:00 dev/rtc0 [root@mini2440 /]#

在Linux中有硬件时钟与系统时钟两种时钟。硬件时钟是指主机板上的时钟设备,也就是通常可在 BIOS画面设定的时钟。系统时钟则是指kernel中的 时钟。当Linux启动时,系统时钟会去读取硬件时钟的设定,之後系统时钟即运作。所有Linux相关指令与函数都是读取系统时钟的设定。 hwclock实现了BIOS和linux的时间同步

既然Linux有两个时钟系统,那么大家所使用的Linux默认使用哪种时钟系统呢?会不回出现两种系统时钟冲突的情况呢?这些疑问和担心不无道理。首先,Linux并没有默认哪个时钟系统。当Linux启动时,硬件时钟会去读取系统时钟的设置,然后系统时钟就会于硬件运作。

从Linux启动过程来看,系统时钟和硬件时钟不会发生冲突,但Linux中的所有命令(包括函数) 都是采用的系统时钟设置。不仅如此,系统时钟和硬件时钟还可以采用异步方式,即系统时间和硬件时间可以不同。这样做的好处对于普通用户意义不大,但对于 Linux网络管理员却有很大的用处。例如,要将一个很大的网络中(跨越若干时区)的服务器同步,假如位于美国纽约的Linux服务器和北京的Linux 服务器,其中一台服务器无须改变硬件时钟而只需临时设置一个系统时间,如要将北京服务器上的时间设置为纽约时间,两台服务器完成文件的同步后,再与原来的时钟同步一下即可。这样系统和硬件时钟就提供了更为灵活的操作。

Linux 中更改时间的方法一般使用date 命令,为了把S3C2440 内部带的时钟与linux 系统时钟同步,一般使用hwclock 命令,下面是它们的使用方法: (1) date -s 062016192011 #设置时间为 2011-06-20 16:19 [root@mini2440 /]#date -s 062016202011 Mon Jun 20 16:20:00 UTC 2011 [root@mini2440 /]#

(2) hwclock -w #把刚刚设置的时间存入S3C2440 内部的RTC [root@mini2440 /]#hwclock -w [root@mini2440 /]#

(3).开机时使用hwclock -s 命令可以恢复 linux 系统时钟为RTC, 一般把该语句放入/etc/init.d/rcS 文件自动执行。 [root@mini2440 /]#vi 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 \"************booting to mini2440 *****************\" echo \"Kernel version:linux-2.6.32.2\" echo \"the fans:singleboy\" echo \"Date:2011.5.30\"

echo \"*************************************************\" /bin/hostname -F /etc/sysconfig/HOSTNAME echo \"update the time from RTC\" hwclock -s

#show the current system time date ~

~ ~

I etc/init.d/rcS [Modified] 18/19 94% 然后保存退出。 下面是启动信息

----------munt all----------------

************************************************* ************booting to mini2440 ***************** Kernel version:linux-2.6.32.2 the fans:singleboy Date:2011.5.30

************************************************* update the time from RTC Mon Jun 20 21:19:49 UTC 2011

Please press Enter to activate this console. 然而,在有时启动时发现: ... ...

mice: PS/2 mouse device common for all mice S3C24XX RTC, (c) 2004,2006 Simtec Electronics s3c2410-rtc s3c2410-rtc: rtc disabled, re-enabling s3c2410-rtc s3c2410-rtc: rtc core: registered s3c as rtc0 i2c /dev entries driver ... ...

NET: Registered protocol family 17

s3c2410-rtc s3c2410-rtc: hctosys: invalid date/time eth0: link up, 100Mbps, full-duplex, lpa 0x45E1 ... ...

----------munt all----------------

************************************************* ************booting to mini2440 ***************** Kernel version:linux-2.6.32.2 the fans:singleboy Date:2011.5.30

************************************************* update the time from RTC

hwclock: settimeofday() failed: Invalid argument Thu Jan 1 00:00:08 UTC 1970

Please press Enter to activate this console.

网上给出的答案:这个是正常的,原因是你没有同步硬件时钟。第一次启动,没有正确设置 RTC 日期。启动文件系统后执行Data命令设置系统时间后,再使用hwclock -w将系统时间同步到RTC即可避免这个错误提示。

现在明白了,上面的错误信息是重新编译内核后才出现的。现在可以按照开始时的办法重新设置。

[root@mini2440 /]#date -s 062110092011.00 Tue Jun 21 10:09:00 UTC 2011 [root@mini2440 /]#hwclock -w [root@mini2440 /]#date Tue Jun 21 10:09:36 UTC 2011 [root@mini2440 /]#

linux2.6.32.2 mini2440平台移植--LCD 背光驱动

1.3.1 LCD 背光控制原理

到目前为止,我们一直都在命令行下移植,查看结果,在 mini2440/micro2440 开发板中,LCD 背光是通过 CPU 的 LCD_PWR 引脚来控制的,从原理图中可以看出,它对应于 GPG4 。 当 LCD_PWR 输出为高电平\"1\"时,将打开背光;当输出为低电平\"0\"时,将关闭背光(注意:这里只是打开和关闭背光,而并没有背光亮度的调节作用)。

1.3.2 在内核中添加背光驱动程序

现在,我们需要增加一个简单的背光驱动,以便能够通过软件便可简单的控制背光的开关。我们要达到的目的是:在命令终端通过向背光设备发送偶数比如\"0\"便可关闭背光,发送奇数比如\"1\"便可打开背光,这样使用起来就方便多了,而不需要专门的应用程序控制它,提示:LCD 背光设备文件:/dev/backlight

在命令行种输入:echo 0 > /dev/backlight 可以关闭 LCD 背光。 在命令行种输入:echo 1 > /dev/backlight 可以打开 LCD 背光。

为了实现这点,我们在 linux-2.6.32.2/drivers/video 目录增加一个 mini2440_backlight.c 文件,内容如下:

//以下头文件可能并不是每一个都必须的,但多余的并不会影响驱动程序的内容 #include #include #include

#include #include #include #include #include #include #include #include

#include #include #include #include #include

#include #include

#undef DEBUG //#define DEBUG #ifdef DEBUG

#define DPRINTK(x...) {printk(__FUNCTION__\"(%d): \ #else

#define DPRINTK(x...) (void)(0) #endif

//定义背光驱动的名称为 backligh,将会出现在/dev/backlight #define DEVICE_NAME \"backlight\"

//定义背光变量 bl_state,以记录背光的开关状态 static unsigned int bl_state;

//设置背光开关的函数,主要是翻转背光变量 bl_state

static inline void set_bl(int state) {

bl_state = !!state; //翻转 bl_state 变量

s3c2410_gpio_setpin(S3C2410_GPG(4), bl_state); //把结果写入背光所用的寄存器 GPG4 }

//获取背光状态

static inline unsigned int get_bl(void) {

return bl_state; }

//从应用程序读取参数,并传递到内核中

static ssize_t dev_write(struct file *file, const char *buffer, size_t count, loff_t * ppos) {

unsigned char ch; int ret; if (count == 0) { return count; }

//使用 copy_from_user 函数从用户层/应用层读取参数 ret = copy_from_user(&ch, buffer, sizeof ch) ? -EFAULT : 0; if (ret) { return ret; }

ch &= 0x01; //判断奇数还是偶数

set_bl(ch); //设置背光状态

return count; }

//把内核参数传递给用户层/应用层的读函数

static ssize_t dev_read(struct file *filp, char *buffer, size_t count, loff_t *ppos) { int ret;

unsigned char str[] = {'0', '1' };

if (count == 0) { return 0; }

//使用 copy_to_user 函数把内核参数传递到用户层/应用层

ret = copy_to_user(buffer, str + get_bl(), sizeof(unsigned char) ) ? -EFAULT : 0; if (ret) { return ret; }

return sizeof(unsigned char); }

//设备操作集

static struct file_operations dev_fops = { owner: THIS_MODULE, read:dev_read, write: dev_write, };

static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops, };

//设备初始化,内核启动时就有效 static int __init dev_init(void)

{ int ret;

ret = misc_register(&misc);

printk (DEVICE_NAME\"\initialized\\n\");

//初始化背光所用的端口 GPG4 为输出

s3c2410_gpio_cfgpin(S3C2410_GPG(4), S3C2410_GPIO_OUTPUT); //启动内核时打开背光 set_bl(1); return ret; }

static void __exit dev_exit(void) {

misc_deregister(&misc); }

module_init(dev_init); //注册背光驱动模块 module_exit(dev_exit); //卸载背光驱动模块 MODULE_LICENSE(\"GPL\");

MODULE_AUTHOR(\"FriendlyARM Inc.\");

然后把背光配置选项加入内核配置菜单,打开 linux-2.6.32.2/drivers/video/Kconfig,在如下位置加入:

config FB_S3C2410_DEBUG bool \"S3C2410 lcd debug messages\" depends on FB_S3C2410 help

Turn on debugging messages. Note that you can set/unset at run time through sysfs

//在里加入 MINI2440 的背光驱动配置 config BACKLIGHT_MINI2440

tristate \"Backlight support for mini2440 from FriendlyARM\"

depends on MACH_MINI2440 && FB_S3C2410 help

backlight driver for MINI2440 from FriendlyARM

config FB_SM501

tristate \"Silicon Motion SM501 framebuffer support\" depends on FB && MFD_SM501 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT

再打开 linux-2.6.32.2/drivers/video/Makefile,根据配置定义加入驱动目标文件,如下: # the test framebuffer is last obj-$(CONFIG_FB_VIRTUAL)

#video output switch sysfs driver += vfb.o

obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o

obj-$(CONFIG_BACKLIGHT_MINI2440) += mini2440_backlight.o

这样,我们就在内核中移植好了 mini2440 的背光驱动,在内核源代码根目录执行: make menuconfig,依次选择如下子菜单: Device Drivers ---> Graphics support --->

<*> Support for frame buffer devices --->

就可以找到该配置选项,在这里,按空格选中我们刚刚加入的 mini2440 配置项,然后退出保存内核配置菜单,在命令行执行:make zImage

将生成 arch/arm/boot/zImage,使用 supervivi 的\"k\"功能把它烧写到开发板中,可以在启动时看到如图所示的企鹅图像,这说明我们已经点亮了背光,只不过 LCD 驱动还有些问题,下一节我们将会详细的介绍如何移植 LCD 驱动。

linux2.6.32.2 mini2440平台移植-- LCD 显示驱动 ( W35屏 )

1.4.1 LCD 驱动基础知识

Linux-2.6.32.2 内核已经支持 S3C2440 的 LCD 控制器驱动,但在此我们先介绍一下关于 2440 LCD 控制器以及驱动相关的 LCD 的一些基础知识。 注意:在此我们只讨论 TFT LCD,也就是真彩屏。

LCD 驱动中最关键的就是时钟频率(Clock frequency)的设置,时钟频率设置不对,LCD 的显示就会闪,或者根本没有显示。一般 LCD 的 Datasheet上会写有一个推荐的频率,比如 mini2440 所用的统宝 3.5\"LCD,在它的数据手册第 13 页,有这样一个表格:可以看到,这里推荐的时钟频率是6.39MHz,近似于 6.4MHz,范围,是 5M-6.85MHz。

S3C2440 之 LCD 控制器与此相关的设置为 CLKVAL,通过设置它,就可以在 LCD 接口的 VCLK 引脚上产生 LCD 所需要的时钟频率,那么 CLKVAL和 VCLK 有何种关系呢?在 2440 英文手册(411页 )中,有这样一段描述:

The rate of VCLK signal depends on the CLKVAL field in the LCDCON1 register. Table 15-3 defines the

relationship of VCLK and CLKVAL. The minimum value of CLKVAL is 0 接下来,手册中提供了它们的数学关系公式: VCLK(Hz) = HCLK/[(CLKVAL+1)x2] 因此可以得出:

VCLK = HCLK / ((CLKVAL+1)*2) 那么 HCLK 是多少呢?

我们的开发板运行于400Mhz,这个可以在 bootloader 的源代码头文件中看到 FCLK:HCLK:PCLK = 1:4:8,因此得出 HCLK=100Mhz,再根据上述公式得出 CLKVAL 应为:

CLKVAL=HCLK/(VCLK*2) -1 VCLK :LCD屏幕所需的频率

CLKVAL = 100000000 / (00000 * 2) - 1 = 6.8

选择最接近的整数值 7,并把它写入 LCDCON1:17-8(注意:我们实际使用的数值是 8),由此产生的 VCLK 频率实测为 5.63Mhz 左右,它也是在 5-6.85Mhz 之间的数值。

1.4.2 新内核中的 pixclock 参数

在以前较老的 Linux 内核中,对于 LCD 寄存器的设置都是这样直接填写 CLKVAL 的,但 Linux-2.6.32.2 内核却不再使用这样简单直观的方式,而是通过一个称为\"pixclock\"的参数进行调节,它的计算变的复杂和难以理解,我们不清楚 Linux 内核中关于 2440 部分的移植为何改变成这样的方式,这有可能是为了和 X86 体系中的设置保持一致的风格,下面我们根据实际的代码进行一些推导和说明,但推导结果和我们的实际设置是并不一致的,会有一些误差。

提示:我们实际提供的 pixclock 参数并不是按照以下的方式推导计算出的,而是先确定好 CLKVAL 的数值,再反复尝试、猜测得到的。

在 Framebuffer 驱动(linux-2.6.32.2/ drivers/video/s3c2410fb.c)中有这样一个函数: clkdiv = DIV_ROUND_UP(s3c2410fb_calc_pixclk(fbi, var->pixclock), 2);

这里的 clkdiv 就是我们上面提到的 CLKVAL,而 DIV_ROUND_UP 是一个宏定义,它位于 include/linux/kernel.h 文件中:

#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))

这其实是一个数学概念:向上取整。下面是关于\"向上取整\"的一段说明: 以下信息来自:

http://www.vckbase.com/document/viewdoc/?id=743 1. 问题

A,B 都是整数并且 A>1, B>1 求┌A/B┐即 A/B 的上取整。

当 A/B 整除,往上取整返回值 为 A/B。 当 不整除,返回值是 int(A/B) + 1

这个算法的一个应用:如果你有一个动态增长的缓冲区,增长的步长是 B,

某一次缓冲区申请的大小是 A,这个时候,就可以用这个算法,计算出缓冲区的一个合 适大小了,正好可以容纳 A,并且不会过于得多,多余部分不会比 B 多。 2. 方法 int( (A+B-1)/B ) 3. HUNTON 的证明 上取整用 UP 表示

由于 A>1、B>1,且 A、B 都是整数,所以可以设 A=NB+M 其中 N 为非负整数,M 为 0 到 B-1 的数,则 A/B = N + M/B

(A+B-1)/B = N + 1 + (M - 1)/B; 当 M 为 0 时, UP(A/B) = N,

int((A+B-1)/B) = N + int(1 - 1/B) = N 当 M 为 1 到 B-1 的数时,0 <= M-1 <= B-2 UP(A/B) = N + 1,

int((A+B-1)/B) = N + 1 + int((M-1)/B) = N + 1 所以对 A>1、B>1 的整数 A、B 都有:

UP(A/B) = int((A+B-1)/B)

对于除数为\"2\"的本算法而言,我们可以简单的理解为\"(n/2)+0.5\"所对应的整数值,因此这里不可能避免的就出现了误差,也就是说n的数值是有一定范围的,这里的n就是 \"s3c2410fb_calc_pixclk(fbi, var->pixclock)\",因此上面的公式可以改写为:clkdiv= s3c2410fb_calc_pixclk(fbi, var->pixclock)/2 + 0.5 而 s3c2410fb_calc_pixclk(fbi, var->pixclock)

这个函数在linux-2.6.32.2/ drivers/video/s3c2410fb.c 中是这样定义的: /* s3c2410fb_calc_pixclk() *

* calculate divisor for clk->pixclk */

static unsigned int s3c2410fb_calc_pixclk(struct s3c2410fb_info *fbi, unsigned long pixclk) {

unsigned long clk = fbi->clk_rate; unsigned long long div;

/* pixclk is in picoseconds, our clock is in Hz *

* Hz -> picoseconds is / 10^-12 */

;这里计算出本函数的结果

div = (unsigned long long)clk * pixclk;

div >>= 12; /* div / 2^12 */ do_div(div, 625 * 625UL * 625); /* div / 5^12 */

dprintk(\"pixclk %ld, divisor is %ld\\n\ return div; }

因此得出:

clkdiv=clk*pixclk/(10^12)/2 + 0.5

根据实际打印结果验证,此处的 clk 其实就是 HCLK。

而根据 static void s3c2410fb_activate_var(struct fb_info *info)函数中的描述,会得出这样一个关系:

CLKVAL=clkdiv-1

再结合从 2440 芯片手册得到的公式 CLKVAL=HCLK/(VCLK*2) -1,因此可以得出大致这样的结果(\"大致\"可以理解为一定的误差范围): Pixclk=(HCLK-VLCK)x10^12/HCLK*VCLK 以我们所用的统宝屏为例: HCLK=100Mhz=100,000,000Hz VLCK=6.4Mhz=00,000Hz

因此计算出:pixclk =146250,单位是 ps(picoseconds),这和我们实际设置的数值 170000是有一定误差的。另外在Linux内核文档中,还有另外一种计算 pixclock的方式,见 linux/Documentation/fb/framebuffer.txt。

1.4.3 在内核中添加各种 LCD 类型的支持

打开 arch/arm/mach-s3c2440/mach-mini2440.c,先删除之前的 LCD 设备平台代码,如下: /* LCD driver info */

static struct s3c2410fb_display mini2440_lcd_cfg __initdata = {

.lcdcon5 = S3C2410_LCDCON5_FRM565 | S3C2410_LCDCON5_INVVLINE | S3C2410_LCDCON5_INVVFRAME | S3C2410_LCDCON5_PWREN | S3C2410_LCDCON5_HWSWP,

.type = S3C2410_LCDCON1_TFT,

.width = 240, .height = 320,

.pixclock = 166667, /* HCLK 60 MHz, divisor 10 */ .xres = 240, .yres = 320, .bpp = 16, .left_margin = 20, .right_margin = 8, .hsync_len = 4,

.upper_margin = 8, .lower_margin = 7, .vsync_len = 4, };

static struct s3c2410fb_mach_info mini2440_fb_info __initdata = { .displays = &mini2440_lcd_cfg, .num_displays = 1, .default_display = 0, #if 0

/* currently setup by downloader */ .gpccon = 0xaa940659, .gpccon_mask = 0xffffffff, .gpcup = 0x0000ffff, .gpcup_mask = 0xffffffff, .gpdcon = 0xaa84aaa0, .gpdcon_mask = 0xffffffff, .gpdup = 0x0000faff, .gpdup_mask = 0xffffffff, #endif

.lpcsel = ((0xCE6) & ~7) | 1<<4,

};

再把友善之臂已经移植好的代码加入,如下 //这里有多种屏幕的配置,我用的是w35屏

#if defined(CONFIG_FB_S3C2410_N240320) #define LCD_WIDTH 240 #define LCD_HEIGHT 320 #define LCD_PIXCLOCK 100000 #define LCD_RIGHT_MARGIN 36 #define LCD_LEFT_MARGIN 19 #define LCD_HSYNC_LEN 5 #define LCD_UPPER_MARGIN 1 #define LCD_LOWER_MARGIN 5 #define LCD_VSYNC_LEN 1

#elif defined(CONFIG_FB_S3C2410_N480272) #define LCD_WIDTH 480 #define LCD_HEIGHT 272 #define LCD_PIXCLOCK 100000 #define LCD_RIGHT_MARGIN 36 #define LCD_LEFT_MARGIN 19 #define LCD_HSYNC_LEN 5 #define LCD_UPPER_MARGIN 1 #define LCD_LOWER_MARGIN 5 #define LCD_VSYNC_LEN 1

#elif defined(CONFIG_FB_S3C2410_W320240) //这里是W35屏的配置 #define LCD_WIDTH 320 #define LCD_HEIGHT 240 #define LCD_PIXCLOCK 70000 #define LCD_RIGHT_MARGIN 68 #define LCD_LEFT_MARGIN 66 #define LCD_HSYNC_LEN 4 #define LCD_UPPER_MARGIN 4 #define LCD_LOWER_MARGIN 4

#define LCD_VSYNC_LEN 9

#define LCD_CON5 (S3C2410_LCDCON5_FRM565 |S3C2410_LCDCON5_INVVDEN | S3C2410_LCDCON5_INVVFRAME | S3C2410_LCDCON5_INVVLINE| S3C2410_LCDCON5_INVVCLK | S3C2410_LCDCON5_HWSWP)

#elif defined(CONFIG_FB_S3C2410_TFT0480) #define LCD_WIDTH 0 #define LCD_HEIGHT 480 #define LCD_PIXCLOCK 40000 #define LCD_RIGHT_MARGIN 67 #define LCD_LEFT_MARGIN 40 #define LCD_HSYNC_LEN 31 #define LCD_UPPER_MARGIN 5 #define LCD_LOWER_MARGIN 25 #define LCD_VSYNC_LEN 1

#elif defined(CONFIG_FB_S3C2410_T240320) #define LCD_WIDTH 240 #define LCD_HEIGHT 320 #define LCD_PIXCLOCK 170000 #define LCD_RIGHT_MARGIN 25 #define LCD_LEFT_MARGIN 0 #define LCD_HSYNC_LEN 4 #define LCD_UPPER_MARGIN 1 #define LCD_LOWER_MARGIN 4 #define LCD_VSYNC_LEN 1

#define LCD_CON5 (S3C2410_LCDCON5_FRM565 | S3C2410_LCDCON5_INVVDEN | S3C2410_LCDCON5_INVVFRAME | S3C2410_LCDCON5_INVVLINE | S3C2410_LCDCON5_INVVCLK | S3C2410_LCDCON5_HWSWP )

#elif defined(CONFIG_FB_S3C2410_X240320) #define LCD_WIDTH 240 #define LCD_HEIGHT 320 #define LCD_PIXCLOCK 170000 #define LCD_RIGHT_MARGIN 25 #define LCD_LEFT_MARGIN 0 #define LCD_HSYNC_LEN 4 #define LCD_UPPER_MARGIN 0 #define LCD_LOWER_MARGIN 4 #define LCD_VSYNC_LEN 9

#define LCD_CON5 (S3C2410_LCDCON5_FRM565 | S3C2410_LCDCON5_INVVDEN | \\

S3C2410_LCDCON5_INVVFRAME | S3C2410_LCDCON5_INVVLINE | \\ S3C2410_LCDCON5_INVVCLK | S3C2410_LCDCON5_HWSWP )

#elif defined(CONFIG_FB_S3C2410_TFT800480) #define LCD_WIDTH 800 #define LCD_HEIGHT 480 #define LCD_PIXCLOCK 40000 #define LCD_RIGHT_MARGIN 67

#define LCD_LEFT_MARGIN 40 #define LCD_HSYNC_LEN 31 #define LCD_UPPER_MARGIN 25 #define LCD_LOWER_MARGIN 5 #define LCD_VSYNC_LEN 1

#elif defined(CONFIG_FB_S3C2410_VGA1024768) #define LCD_WIDTH 1024 #define LCD_HEIGHT 768 #define LCD_PIXCLOCK 80000 #define LCD_RIGHT_MARGIN 15 #define LCD_LEFT_MARGIN 199 #define LCD_HSYNC_LEN 15 #define LCD_UPPER_MARGIN 1 #define LCD_LOWER_MARGIN 1 #define LCD_VSYNC_LEN 1

#define LCD_CON5 (S3C2410_LCDCON5_FRM565 | S3C2410_LCDCON5_HWSWP) #endif

#if defined (LCD_WIDTH)

static struct s3c2410fb_display mini2440_lcd_cfg __initdata = {

#if !defined (LCD_CON5)

.lcdcon5 = S3C2410_LCDCON5_FRM565 | S3C2410_LCDCON5_INVVLINE | S3C2410_LCDCON5_INVVFRAME | S3C2410_LCDCON5_PWREN | S3C2410_LCDCON5_HWSWP, #else

.lcdcon5 = LCD_CON5, #endif

.type = S3C2410_LCDCON1_TFT, .width = LCD_WIDTH,

.height = LCD_HEIGHT,

.pixclock = LCD_PIXCLOCK, .xres = LCD_WIDTH, .yres = LCD_HEIGHT, .bpp = 16,

.left_margin = LCD_LEFT_MARGIN + 1, .right_margin = LCD_RIGHT_MARGIN + 1, .hsync_len = LCD_HSYNC_LEN + 1, .upper_margin = LCD_UPPER_MARGIN + 1, .lower_margin = LCD_LOWER_MARGIN + 1, .vsync_len = LCD_VSYNC_LEN + 1, };

static struct s3c2410fb_mach_info mini2440_fb_info __initdata = { .displays = &mini2440_lcd_cfg, .num_displays = 1, .default_display = 0,

.gpccon = 0xaa955699, .gpccon_mask = 0xffc003cc, .gpcup = 0x0000ffff, .gpcup_mask = 0xffffffff,

.gpdcon = 0xaa95aaa1, .gpdcon_mask = 0xffc0fff0, .gpdup = 0x0000faff, .gpdup_mask = 0xffffffff,

.lpcsel = 0xf82, }; #endif

注意:若您粘贴此段程序的话 如果编译过程中这段有问题请检查一下对应行 可能有多余空格。。。

然后打开 drivers/video/Kconfig,在大概 1935 行加入以下配置信息:

config FB_S3C2410_DEBUG bool \"S3C2410 lcd debug messages\" depends on FB_S3C2410 help

Turn on debugging messages. Note that you can set/unset at run time through sysfs choice

prompt \"LCD select\" depends on FB_S3C2410 help

S3C24x0 LCD size select

config FB_S3C2410_T240320

boolean \"3.5 inch 240X320 Toppoly LCD\" depends on FB_S3C2410 help

3.5 inch 240X320 Toppoly LCD

configFB_S3C2410_W320240 //此段为配置 W35屏 boolean \"3.5 inch 320x240 W35i LCD\" depends on FB_S3C2410 help

3.5 inch 320x240 W35i LCD

config FB_S3C2410_X240320

boolean \"3.5 inch 240X320 LCD(ACX502BMU)\" depends on FB_S3C2410 help

3.5 inch 240X320 LCD(ACX502BMU)

config FB_S3C2410_N240320

boolean \"3.5 inch 240X320 NEC LCD\" depends on FB_S3C2410 help

3.5 inch 240x320 NEC LCD

config FB_S3C2410_N480272

boolean \"4.3 inch 480X272 NEC LCD\" depends on FB_S3C2410 help

4.3 inch 480x272 NEC LCD

config FB_S3C2410_TFT0480 boolean \"8 inch 0X480 L80 LCD\" depends on FB_S3C2410 help

8 inch 0X480 LCD

config FB_S3C2410_TFT800480 boolean \"7 inch 800x480 TFT LCD\" depends on FB_S3C2410 help

7 inch 800x480 TFT LCD

config FB_S3C2410_VGA1024768 boolean \"VGA 1024x768\" depends on FB_S3C2410 help

VGA 1024x768 endchoice

config BACKLIGHT_MINI2440

tristate \"Backlight support for mini2440 from FriendlyARM\"

depends on MACH_MINI2440 && FB_S3C2410 help

backlight driver for MINI2440 from FriendlyARM

config FB_SM501

tristate \"Silicon Motion SM501 framebuffer support\" depends on FB && MFD_SM501 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT

这样,我们就完成了 LCD 驱动的移植,如果你需要加入其他型号的 LCD 驱动,也可以参照上面的方式复制即可,一般小尺寸的 pixclock 参数可以参考统宝 3.5\"的,超过 0x480 分辨率的参数可以参考 8\"LCD 的,特别要注意你使用的 LCD 的长宽也要修改。

1.4.4 配置内核并下载到开发板测试

现在,我们在命令行输入:make menuconfig 进入内核配置,依次按下面的子菜单项选择: Device Drivers ---> Graphics support --->

<*> Support for frame buffer devices ---> LCD select (3.5 inch 320x240 W35i LCD) ---> 会出现如图所示 LCD 型号配置选项:

按空格或者回车键选择我们需要的 LCD 型号,然后退出保存内核配置。 在命令行执行: #make zImage

将会生成 arch/arm/boot/zImage,把它烧写到开发板中,就可以看到一个小企鹅出现在屏幕上了。

linux2.6.32.2 mini2440平台移植-- ADC 驱动移植

1.2.1 关于 S3C2440 的 ADC 和触摸屏接口

Linux-2.6.32.2 内核并没有提供支持 S3C2440 的 ADC 驱动程序,因此我们自行设计了一个,这个驱动比较简单,属于字符设备,。在 S3C2440 芯片中,AD 输入和触摸屏接口使用共同的 A/D 转换器,见S3C2440芯片手册第 16 章节,如图。

1.2.2 在内核中添加 ADC 驱动

在 S3C2440 芯片中,AD 输入和触摸屏接口使用共同的 A/D 转换器,因此,ADC 驱动和触摸屏驱动若想共存,就必须解决共享\"A/D 转换器\"资源这个问

题,因此在 ADC 驱动程序中声明了一个全局的\"ADC_LOCK\"信号量。

(1)将ADC驱动程序(s3c24xx-adc.h文件和mini2440_adc.c)放于drivers/char目录下

//s3c24xx-adc.h 内容如下:

#ifndef _S3C2410_ADC_H_ #define _S3C2410_ADC_H_

#define ADC_WRITE_GETCH(data) (((data)>>16)&0x7) #define ADC_WRITE_GETPRE(data) ((data)&0xff)

// ADC_WRITE_GETCH(data)得到ch ADC_WRITE_GETPRE(data)得到prescale!! #define ADC_WRITE(ch, prescale) ((ch)<<16|(prescale)) #endif /* _S3C2410_ADC_H_ */

//mini2440_adc.c 内容如下: /*ADC驱动*/

#include #include #include

#include #include #include #include #include #include #include #include #include #include #include #include #include

#include #include #include #include

//自己定义的头文件 因为原生内核并么有包含 #include \"s3c24xx-adc.h\"

#undef DEBUG //#define DEBUG #ifdef DEBUG

#define DPRINTK(x...) {printk(__FUNCTION__\"(%d): \#else

#define DPRINTK(x...) (void)(0) #endif

#define DEVICE_NAME \"adc\"

static void __iomem *base_addr;

//定义ADC设备就结构

typedef struct {

wait_queue_head_t wait; int channel; int prescale; }ADC_DEV;

//声明全局变量,以使和触摸屏驱动程序共享A/D转换器 DECLARE_MUTEX(ADC_LOCK);

//ADC驱动是否拥有A/D转换器资源的状态变量 static int OwnADC = 0;

static ADC_DEV adcdev; static volatile int ev_adc = 0; static int adc_data;

static struct clk *adc_clock;

//定义ADC相关的寄存器

#define ADCCON (*(volatile unsigned long *)(base_addr + S3C2410_ADCCON)) //ADC control

#define ADCTSC (*(volatile unsigned long *)(base_addr + S3C2410_ADCTSC)) //ADC touch screen control

#define ADCDLY (*(volatile unsigned long *)(base_addr + S3C2410_ADCDLY)) //ADC start or Interval Delay

#define ADCDAT0 (*(volatile unsigned long *)(base_addr + S3C2410_ADCDAT0)) //ADC conversion data 0

#define ADCDAT1 (*(volatile unsigned long *)(base_addr + S3C2410_ADCDAT1)) //ADC conversion data 1

#define ADCUPDN (*(volatile unsigned long *)(base_addr + 0x14)) //Stylus Up/Down interrupt status

#define PRESCALE_DIS (0 << 14) #define PRESCALE_EN (1 << 14) #define PRSCVL(x) ((x) << 6)

#define ADC_INPUT(x) ((x) << 3) #define ADC_START (1 << 0) #define ADC_ENDCVT (1 << 15)

//开启AD输入

#define START_ADC_AIN(ch, prescale) \\ do{ \\

ADCCON = PRESCALE_EN | PRSCVL(prescale) | ADC_INPUT((ch)) ; \\ ADCCON |= ADC_START; \\ }while(0)

//ADC中断处理函数

static irqreturn_t adcdone_int_handler(int irq, void *dev_id) {

//如果ADC驱动拥有A/D转换器资源,则从ADC寄存器读取转换状态 if (OwnADC) {

adc_data = ADCDAT0 & 0x3ff; ev_adc = 1;

wake_up_interruptible(&adcdev.wait); }

return IRQ_HANDLED; }

//ADC读函数,

static ssize_t s3c2410_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos) {

char str[20]; int value; size_t len;

//判断'A/D转换器'资源是否可用 if (down_trylock(&ADC_LOCK) == 0) {

OwnADC = 1;//标记为'A/D转换器'资源是可用

START_ADC_AIN(adcdev.channel, adcdev.prescale);//开始转换 wait_event_interruptible(adcdev.wait, ev_adc);//等待转换结束

ev_adc = 0;

DPRINTK(\"AIN[%d] = 0x%04x, %d\\n\0x80 ? 1:0);

//把转换结果赋值,以便传递到用户层 value = adc_data;

//释放A/D转换器资源 OwnADC = 0; up(&ADC_LOCK); } else {

//没有A/D转换器资源 value = -1; }

len = sprintf(str, \"%d\\n\ if (count >= len) {

//将转换结果传到到用户层

int r = copy_to_user(buffer, str, len); return r ? r : len; } else {

return -EINVAL; } }

//ADC设备的打开函数

static int s3c2410_adc_open(struct inode *inode, struct file *filp) {

//初始化中断队列

init_waitqueue_head(&(adcdev.wait));

//缺省通道为'0' adcdev.channel=0; adcdev.prescale=0xff;

DPRINTK( \"adc opened\\n\"); return 0; }

static int s3c2410_adc_release(struct inode *inode, struct file *filp) {

DPRINTK( \"adc closed\\n\"); return 0; }

static struct file_operations dev_fops = { owner: THIS_MODULE, open: s3c2410_adc_open, read: s3c2410_adc_read, release: s3c2410_adc_release, };

static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops, };

static int __init dev_init(void) { int ret;

base_addr=ioremap(S3C2410_PA_ADC,0x20); if (base_addr == NULL) {

printk(KERN_ERR \"Failed to remap register block\\n\"); return -ENOMEM; }

adc_clock = clk_get(NULL, \"adc\"); if (!adc_clock) {

printk(KERN_ERR \"failed to get adc clock source\\n\"); return -ENOENT; }

clk_enable(adc_clock);

/* normal ADC */ ADCTSC = 0;

ret = request_irq(IRQ_ADC, adcdone_int_handler, IRQF_SHARED, DEVICE_NAME, &adcdev); if (ret) {

iounmap(base_addr); return ret; }

ret = misc_register(&misc);

printk (DEVICE_NAME\"\initialized\\n\"); return ret; }

static void __exit dev_exit(void) {

free_irq(IRQ_ADC, &adcdev); iounmap(base_addr);

if (adc_clock) {

clk_disable(adc_clock); clk_put(adc_clock);

adc_clock = NULL; }

misc_deregister(&misc); }

//导出信号量\"ADC_LOCK\"以便触摸屏驱动使用 EXPORT_SYMBOL(ADC_LOCK); module_init(dev_init); module_exit(dev_exit); MODULE_LICENSE(\"GPL\");

MODULE_AUTHOR(\"FriendlyARM Inc.\");

然后打开 drivers/char/Makefile 文件,在大概 114 行(这里没有必要一定是,看到类似的地方加进去就行了)加入 ADC 驱动程序目标模块:

obj-$(CONFIG_JS_RTC) += js-rtc.o js-rtc-y = rtc.o

obj-$(CONFIG_MINI2440_ADC) += mini2440_adc.o

# Files generated that shall be removed upon make clean clean-files := consolemap_deftbl.c defkeymap.c

(2)再打开 drivers/char/Kconfig 文件,加入 ADC 驱动配置选项:

config DEVKMEM

bool \"/dev/kmem virtual device support\" default y help

Say Y here if you want to support the /dev/kmem device. The /dev/kmem device is rarely used, but can be used for certain kind of kernel debugging operations.

When in doubt, say \"N\".

config MINI2440_ADC

bool \"ADC driver for FriendlyARM Mini2440 development boards\" depends on MACH_MINI2440 default y if MACH_MINI2440 help

this is ADC driver for FriendlyARM Mini2440 development boards Notes: the touch-screen-driver required this option

config BFIN_JTAG_COMM

tristate \"Blackfin JTAG Communication\" depends on BLACKFIN help

(3)这样,我们就在内核中添加了 ADC 驱动,现在内核源代码目录的命令行执行:make menuconfig,依次选择如下子菜单项,找到刚刚添加的 ADC 驱动配置选项: Device Drivers ---> Character devices ---> 按空格键选中 ADC 配置选项

(4)然 后 退 出 保 存 所 选 配 置 , 在 命 令 行 执 行 : make zImage ,

将 会 生 成 arch/arm/boot/zImage,使用 supervivi 的\"k\"命令把它烧写到开发板。

1.2.3 ADC 测试程序

我们在这里使用友善之臂自带的文件系统,里面有一个adc-test命令,它的源代码如下: #include #include #include #include #include #include

#include #include #include #include

int main(void) {

fprintf(stderr, \"press Ctrl-C to stop\\n\"); int fd = open(\"/dev/adc\ if (fd < 0) {

perror(\"open ADC device:\"); return 1; } for(;;) { char buffer[30];

int len = read(fd, buffer, sizeof buffer -1); if (len > 0) { buffer[len] = '\\0'; int value = -1;

sscanf(buffer, \"%d\ printf(\"ADC Value: %d\\n\ } else {

perror(\"read ADC device:\"); return 1; }

usleep(500* 1000); } close(fd); }

\"adc-test\"测试程序已经集成到我们的文件系统中,因此在开发板的命令行终端输入: adc-test,旋转开发板上的 W1 可调电阻,可以看到 ADC 转换的结果也在变动,按下触摸屏时,会输出\"-1\",这和我们在驱动程序中设置的结果是一样的。

linux 2.6.32.2 mini2440平台移植--触摸屏驱动移植 1.3.1 在内核中添加触摸屏驱动程序 以下介绍为网上摘取的一部分内容: 1)、Linux输入子系统(Input Subsystem):

在Linux中,输入子系统是由输入子系统设备驱动层、输入子系统核心层(Input Core)和输入子系统事件处理层(Event Handler)组成。其中设备驱动层提供对硬件各寄存器的读写访问和将底层硬件对用户输入访问的响应转换为标准的输入事件,再通过核心层提交给事件处理层;而核心层对下提供了设备驱动层的编程接口,对上又提供了事件处理层的编程接口;而事件处理层就为我们用户空间的应用程序提供了统一访问设备的接口和驱动层提交来的事件处理。所以这使得我们输入设备的驱动部分不再用关心对设备文件的操作,而是要关心对各硬件寄存器的操作和提交的输入事件。下面用图形来描述一下这三者的关系吧! 另外,又找了另一幅图来说明Linux输入子系统的结构,可能更加形象容易理解。如下:

2)、输入子系统设备驱动层实现原理:

在Linux中,Input设备用input_dev结构体描述,定义在input.h中。设备的驱动只需按照如下步骤就可实现了。

①、在驱动模块加载函数中设置Input设备支持input子系统的哪些事件; ②、将Input设备注册到input子系统中;

③、在Input设备发生输入操作时(如:键盘被按下/抬起、触摸屏被触摸/抬起/移动、鼠标被移动/单击/抬起时等),提交所发生的事件及对应的键值/坐标等状态。

Linux中输入设备的事件类型有(这里只列出了常用的一些,更多请看linux/input.h中):

1. EV_SYN 0x00 同步事件 2.

3. EV_KEY 0x01 按键事件 4.

5. EV_REL 0x02 相对坐标(如:鼠标移动,报告的是相对最后一次位置的偏移) 6.

7. EV_ABS 0x03 绝对坐标(如:触摸屏和操作杆,报告的是绝对的坐标位置) 8.

9. EV_MSC 0x04 其它 10.

11. EV_LED 0x11 LED 12.

13. EV_SND 0x12 声音 14.

15. EV_REP 0x14 Repeat 16.

17. EV_FF 0x15 力反馈 18.

用于提交较常用的事件类型给输入子系统的函数有:

1. void input_report_key(struct input_dev *dev, unsigned int code, int value); 2.

3. //提交按键事件的函数 4.

5. void input_report_rel(struct input_dev *dev, unsigned int code, int value); 6.

7. //提交相对坐标事件的函数 8.

9. void input_report_abs(struct input_dev *dev, unsigned int code, int value); 10.

11. //提交绝对坐标事件的函数 12.

注意,在提交输入设备的事件后必须用下列方法使事件同步,让它告知input系统,设备驱动已经发出了一个完整的报告:

1. void input_sync(struct input_dev *dev)

3)、触摸屏驱动的实现步骤

S3c2440芯片内部触摸屏接口与ADC接口是集成在一起的,硬件结构原理图请看:S3C2440上ADC驱动实例开发讲解中的图,其中通道7(XP或AIN7)作为触摸屏接口的X坐标输入,通道5(YP或AIN5)作为触摸屏接口的Y坐标输入。在\"S3C2440上ADC驱动实例开发讲解\"中,AD转换的模拟信号是由开发板上的一个电位器产生并通过通道1(AIN0)输入的,而这里的模拟信号则是由点触触摸屏所产生的X坐标和Y坐标两个模拟信号,并分别通过通道7和通道5输入。S3c2440提供的触摸屏接口有4种处理模式,分别是:正常转换模式、单独的X/Y位置转换模式、自动X/Y位置转换模式和等待中断模式,对于在每种模式下工作的要求,请详细查看数据手册的描述。本驱动实例将采用自动X/Y位置转换模式和等待中断模式。

4)Linux-2.6.32.2 内核也没有包含支持 S3C2440 的触摸屏驱动,因此我们需要加入一个mini2440_touchscreen.c

将它放于drivers/input/touchscreen目录下 #include

#include #include #include #include #include #include #include #include

/*用于保存从平台时钟列表中获取的ADC时钟*/ static struct clk *adc_clk;

/*定义了一个用来保存经过虚拟映射后的内存地址*/ static void __iomem *adc_base; /*定义一个输入设备来表示我们的触摸屏设备*/ static struct input_dev *ts_dev; /*设备名称*/

#define DEVICE_NAME \"my2440_TouchScreen\"

/*定义一个WAIT4INT宏,该宏将对ADC触摸屏控制寄存器进行操作

#define WAIT4INT(x) (((x)<<8) | S3C2410_ADCTSC_YM_SEN | \\

/*定义一个外部的信号量ADC_LOCK,因为ADC_LOCK在ADC驱动程序中已申明

这样就能保证ADC资源在ADC驱动和触摸屏驱动中进行互斥访问*/

S3C2410_ADCTSC_YP_SEN |S3C2410_ADCTSC_XP_SEN | S3C2410_ADCTSC_XY_PST(3)) S3C2410_ADCTSC_YM_SEN这些宏都定义在regs-adc.h中*/

extern struct semaphore ADC_LOCK;

/*做为一个标签,只有对触摸屏操作后才对X和Y坐标进行转换*/ static int OwnADC = 0; //在ADC驱动里面也有 ADC资源的控制权

/*用于记录转换后的X坐标值和Y坐标值*/ static long xp; static long yp;

/*用于计数对触摸屏压下或抬起时模拟输入转换的次数*/ static int count;

/*定义一个AUTOPST宏,将ADC触摸屏控制寄存器设置成自动转换模式*/

#define AUTOPST (S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | \\

S3C2410_ADCTSC_XP_SEN |S3C2410_ADCTSC_AUTO_PST |

S3C2410_ADCTSC_XY_PST(0))

static void touch_timer_fire(unsigned long data) ;

/*定义并初始化了一个定时器touch_timer,定时器服务程序为touch_timer_fire*/ static struct timer_list touch_timer = TIMER_INITIALIZER(touch_timer_fire, 0, 0);

static void touch_timer_fire(unsigned long data) {

/*用于记录这一次AD转换后的值*/

/*用于记录触摸屏操作状态是按下还是抬起*/

/*读取这一次AD转换后的值,注意这次主要读的是状态*/

/*记录这一次对触摸屏是压下还是抬起,该状态保存在数据寄存器的第15位,

所以与上 S3C2410_ADCDAT0_UPDOWN*/

updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & data0 = readl(adc_base + S3C2410_ADCDAT0); data1 = readl(adc_base + S3C2410_ADCDAT1); int updown;

unsigned long data0; unsigned long data1;

S3C2410_ADCDAT0_UPDOWN));

/*判断触摸屏的操作状态*/

if (updown) {

/*如果状态是按下,并且ADC已经转换了就报告事件和数据*/

if (count != 0) {

long tmp; tmp = xp; xp = yp; yp = tmp; xp >>= 2; yp >>= 2;

#ifdef CONFIG_TOUCHSCREEN_MY2440_DEBUG

/*触摸屏调试信息,编译内核时选上此项后,点击触摸屏会在终端上打印出坐标信息*/

struct timeval tv; do_gettimeofday(&tv);

printk(KERN_DEBUG \"T: %06d, X: %03ld, Y: %03ld\\n\

#endif

/*报告X、Y的绝对坐标值*/

input_report_abs(ts_dev, ABS_X, xp); input_report_abs(ts_dev, ABS_Y, yp);

/*报告触摸屏的状态,1表明触摸屏被按下*/

input_report_abs(ts_dev, ABS_PRESSURE, 1);

/*报告按键事件,键值为1(代表触摸屏对应的按键被按下)*/

input_report_key(ts_dev, BTN_TOUCH, 1);

/*等待接收方受到数据后回复确认,用于同步*/

input_sync(ts_dev);

}

/*如果状态是按下,并且ADC还没有开始转换就启动ADC进行转换*/

xp = 0; yp = 0;

count = 0;

writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, adc_base + /*设置触摸屏的模式为自动转换模式*/

S3C2410_ADCTSC); }

/*触摸屏中断服务程序,对触摸屏按下或提笔时触发执行*/

/*否则是抬起状态*/

count = 0; } else {

/*启动ADC转换*/

writel(readl(adc_base + S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START,

adc_base + S3C2410_ADCCON);

/*报告按键事件,键值为0(代表触摸屏对应的按键被释放)*/

input_report_key(ts_dev, BTN_TOUCH, 0);

/*报告触摸屏的状态,0表明触摸屏没被按下*/

input_report_abs(ts_dev, ABS_PRESSURE, 0);

/*等待接收方受到数据后回复确认,用于同步*/

input_sync(ts_dev);

/*将触摸屏重新设置为等待中断状态*/

writel(WAIT4INT(0), adc_base + S3C2410_ADCTSC);

/*如果触摸屏抬起,就意味着这一次的操作结束,所以就释放ADC资源的占有*/ }

if (OwnADC) { }

OwnADC = 0; up(&ADC_LOCK);

static irqreturn_t tc_irq(int irq, void *dev_id) {

/*用于记录触摸屏操作状态是按下还是抬起*/ /*用于记录这一次AD转换后的值*/ unsigned long data0; unsigned long data1;

int updown;

/*记录这一次对触摸屏是压下还是抬起,该状态保存在数据寄存器的第15位, /*读取这一次AD转换后的值,注意这次主要读的是状态*/

data0 = readl(adc_base + S3C2410_ADCDAT0); data1 = readl(adc_base + S3C2410_ADCDAT1); /*ADC资源可以获取,即上锁*/

if (down_trylock(&ADC_LOCK) == 0) {

/*标识对触摸屏进行了操作*/

OwnADC = 1;

所以与上 S3C2410_ADCDAT0_UPDOWN*/

updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 &

S3C2410_ADCDAT0_UPDOWN));

/*判断触摸屏的操作状态*/

if (updown) {

/*如果是按下状态,则调用touch_timer_fire函数来启动ADC转换,该函数定义后面再讲*/ } else {

/*如果是抬起状态,就结束了这一次的操作,所以就释放ADC资源的占有*/

touch_timer_fire(0);

}

}

}

OwnADC = 0; up(&ADC_LOCK);

return IRQ_HANDLED;

/*ADC中断服务程序,AD转换完成后触发执行*/ static irqreturn_t adc_irq(int irq, void *dev_id) {

/*记录这一次通过AD转换后的X坐标值和Y坐标值,根据数据手册可知,X和Y坐标转换数值

分别保存在数据寄存器0和1的第0-9位,所以这里与上S3C2410_ADCDAT0_XPDATA_MASKif(OwnADC) //OwnADC初始值为0,只有对触摸屏操作后才对X和Y坐标进行转换 {

/*读取这一次AD转换后的值,注意这次主要读的是坐标*/

data0 = readl(adc_base + S3C2410_ADCDAT0); data1 = readl(adc_base + S3C2410_ADCDAT1); /*用于记录这一次AD转换后的值*/ unsigned long data0; unsigned long data1;

就是取0-9位的值*/

if (count < (1<<2)) {

/*如果转换的次数小于4,则重新启动ADC转换*/

writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, adc_base + /*计数这一次AD转换的次数*/

count++;

xp += data0 & S3C2410_ADCDAT0_XPDATA_MASK; yp += data1 & S3C2410_ADCDAT1_YPDATA_MASK;

S3C2410_ADCTSC);

writel(readl(adc_base + S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START,

}

}

} else {

adc_base + S3C2410_ADCCON);

/*否则,启动1个时间滴答的定时器,这是就会去执行定时器服务程序上报事件和数据*/ /*touch_timer = TIMER_INITIALIZER(touch_timer_fire, 0, 0); */ }

mod_timer(&touch_timer, jiffies + 1);

writel(WAIT4INT(1), adc_base + S3C2410_ADCTSC);

return IRQ_HANDLED;

/*初始化ADC控制寄存器和ADC触摸屏控制寄存器*/

static void adc_initialize(void) {

/*计算结果为(二进制):111111111000000,再根据数据手册得知

此处是将AD转换预定标器值设为255、AD转换预定标器使能有效*/

writel(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(0xFF), adc_base +

S3C2410_ADCCON); }

static int __init ts_init(void) {

int ret;

/*WAIT4INT宏计算结果为(二进制):11010011,再根据数据手册得知 此处是将ADC触摸屏控制寄存器设置成等待中断模式*/ writel(WAIT4INT(0), adc_base + S3C2410_ADCTSC); /*对ADC开始延时寄存器进行设置,延时值为0xffff*/ writel(0xffff, adc_base + S3C2410_ADCDLY);

关。

//touch_timer = TIMER_INITIALIZER(touch_timer_fire, 0, 0);

/*从平台时钟队列中获取ADC的时钟,这里为什么要取得这个时钟,因为ADC的转换频率跟时钟有

系统的一些时钟定义在arch/arm/plat-s3c24xx/s3c2410-clock.c中*/ adc_clk = clk_get(NULL, \"adc\"); if(!adc_clk) {

/*错误处理*/ }

printk(KERN_ERR \"falied to find adc clock source\\n\"); return -ENOENT;

/*时钟获取后要使能后才可以使用,clk_enable定义在arch/arm/plat-s3c/clock.c中*/ clk_enable(adc_clk);

/*将ADC的IO端口占用的这段IO空间映射到内存的虚拟地址,ioremap定义在io.h中。

注意:IO空间要映射后才能使用,以后对虚拟地址的操作就是对IO空间的操作,

S3C2410_PA_ADC是ADC控制器的基地址,定义在mach-s3c2410/include/mach/map.h

中,0x20是虚拟地址长度大小*/

/*初始化ADC控制寄存器和ADC 触摸屏控制寄存器*/ adc_initialize();

if(adc_base == NULL) { /*错误处理*/ }

printk(KERN_ERR \"failed to remap register block\\n\"); ret = -EINVAL; goto err_noclk;

adc_base = ioremap(S3C2410_PA_ADC, 0x20);

/*申请ADC中断,AD转换完成后触发。这里使用共享中断IRQF_SHARED 是因为该中断号在ADC

驱动

中也使用了,最后一个参数1是随便给的一个值,因为如果不给值设为NULL的话,中断就申请不成功*/

/*keybit字段用于描述按键的类型,在input.h中定义了很多, 这里用BTN_TOUCH类型来表示触摸屏的点击*/

ts_dev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS); /*下面初始化输入设备,即给输入设备结构体input_dev的成员设置值。 evbit字段用于描述支持的事件,这里支持同步事件、按键事件、绝对坐标事件, BIT宏实际就是对1进行位操作,定义在linux/bitops.h中*/ /*给输入设备申请空间,input_allocate_device定义在input.h中*/ ts_dev = input_allocate_device();

/*申请触摸屏中断,对触摸屏按下或提笔时触发*/

ret = request_irq(IRQ_TC, tc_irq, IRQF_SAMPLE_RANDOM, DEVICE_NAME, 1); if(ret) { }

printk(KERN_ERR \"IRQ%d error %d\\n\ret = -EINVAL; goto err_noirq;

//因为是共享中断必须最后一个此参数不为NULL ret = request_irq(IRQ_ADC, adc_irq, IRQF_SHARED | \\

IRQF_SAMPLE_RANDOM, DEVICE_NAME, 1);

if(ret) { }

printk(KERN_ERR \"IRQ%d error %d\\n\ret = -EINVAL; goto err_nomap;

/*对于触摸屏来说,使用的是绝对坐标系统。这里设置该坐标系统中X和Y坐标的最小值和最大值 (0-1023范围)ABS_X和ABS_Y就表示X坐标和Y坐标,ABS_PRESSURE就表示触摸屏是按下还ts_dev->keybit[BITS_TO_LONGS(BTN_TOUCH)] = BIT(BTN_TOUCH);

是抬起状态*/ }

err_noirq:

free_irq(IRQ_ADC, 1); return ret; err_nomap:

iounmap(adc_base);

/*好了,一些都准备就绪,现在就把 ts_dev触摸屏设备注册到输入子系统中*/ input_register_device(ts_dev); return 0;

/*下面是错误跳转处理*/ err_noclk:

clk_disable(adc_clk); clk_put(adc_clk);

ts_dev->name = DEVICE_NAME; /*设备名称*/ ts_dev->id.bustype = BUS_RS232; /*总线类型*/ ts_dev->id.vendor = 0xDEAD; /*经销商ID号*/ ts_dev->id.product = 0xBEEF; /*产品ID号*/ ts_dev->id.version = 0x0101; /*版本ID号*/ /*以下是设置触摸屏输入设备的身份信息,直接在这里写死。 这些信息可以在驱动挂载后在/proc/bus/input/devices中查看到*/ input_set_abs_params(ts_dev, ABS_X, 0, 0x3FF, 0, 0); input_set_abs_params(ts_dev, ABS_Y, 0, 0x3FF, 0, 0); input_set_abs_params(ts_dev, ABS_PRESSURE, 0, 1, 0, 0);

static void __exit ts_exit(void) { }

module_init(ts_init); module_exit(ts_exit);

MODULE_LICENSE(\"GPL\"); MODULE_AUTHOR(\"Huang Gang\");

MODULE_DESCRIPTION(\"My2440 Touch Screen Driver\");

/*将触摸屏设备从输入子系统中注销*/ input_unregister_device(ts_dev); /*屏蔽和销毁时钟*/ if(adc_clk) { }

clk_disable(adc_clk); clk_put(adc_clk); adc_clk = NULL; /*释放虚拟地址映射空间*/ iounmap(adc_base); /*屏蔽和释放中断*/ disable_irq(IRQ_ADC); disable_irq(IRQ_TC); free_irq(IRQ_ADC, 1); free_irq(IRQ_TC, 1);

然后在 linux-2.6.32.2/drivers/input/touchscreen/Makefile 文件中添加该源代码的目标模块,如图红色部分: obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) +=zylonite-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o

obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o

obj-$(CONFIG_TOUCHSCREEN_MINI2440) += mini2440_touchscreen.o

再打开 linux-2.6.32.2/drivers/input/touchscreen/Kconfig 文件,加入如下红色部分,这样就在内核配置中添加了 mini2440 的触摸屏驱动选项: menuconfig INPUT_TOUCHSCREEN bool \"Touchscreens\" help

Say Y here, and a list of supported touchscreens will be displayed. This option doesn't affect the kernel.

If unsure, say Y.

if INPUT_TOUCHSCREEN

config TOUCHSCREEN_MINI2440

tristate \"Samsung S3C2410 touchscreen input driver\"

depends on MACH_MINI2440 && INPUT && INPUT_TOUCHSCREEN && MINI2440_ADC help

Say Y here if you have the mini2440 touchscreen.

If unsure, say N.

To compile this driver as a module, choose M here: the module will be called s3c2410_ts.

config TOUCHSCREEN_ADS7846

tristate \"ADS7846/TSC2046 and ADS7843 based touchscreens\" depends on SPI_MASTER

depends on HWMON = n || HWMON help

1.3.2 配置编译内核并测试触摸屏驱动

在命令行执行:make menuconfig,然后依次选择如下子菜单,找到刚刚添加的触摸屏驱动选项: Device Drivers ---> Input device support ---> [*] Touchscreens --->

按空格键选中触摸屏驱动配置选项,并且进入选择自己的驱动。退出并保存以上内核配置,在命令行输入:make zImage,将生成 arch/arm/boot/zImage 文件,使用supervivi 的\"k\"命令把它烧写到开发板。

1.3.3 触摸屏驱动原理详解

原文出处:

http://www.arm9home.net/read.php?tid-2406-keyword-%B4%A5%C3%FE%C6%C1%B3%CC%D0%F2.html 这里不再赘述。

linux2.6.32.2 mini2440平台移植-- 配置 USB 外设、SD卡移植 Linux-2.6.32.2 内核对 USB外设的支持是相当丰富的,并且已经包含了 S3C2440 的 USB Host 驱动支持,因此我们只要配置一下内核就可以了,下面是各种 USB外设的详细配置步骤。

1.4.1 配置和测试 USB键盘、扫描器和鼠标

在内核源代码目录的终端输入:make menuconfig,依次选择如下子菜单项: Device Drivers ---> [*] HID Devices --->

按空格键选中\"USB Human Interface Device (full HID) support\",这样就配置好了 USB键盘和鼠标项。

提示:这里的配置选项对应的内核源代码目录是:linux-2.6.32.2/drivers/hid/usbhid,其中 USB键盘和条码扫描器的原理是一样的,因此它们的代码是相同的。

1.4.2 测试 USB键盘、扫描器和鼠标

在内核源代码根目录下执行:make zImage,把生成的新内核烧写到开发板中,我们这里依然使用友善之臂提供的文件系统 root_qtopia做测试,因为它可以同时支持 USB 键盘、鼠标和触摸屏,并且是支持热插拔,所以使用起来十分方便。在前面的步骤中,我们通过触摸屏点击已经进入了 qtopia图形系统,因此这里直接找个 USB HUB,同时连上 USB鼠标和键盘,甚至是 USB 条码扫描器就可以了,使用鼠标找到一个应用程序,比如 qtopia自带的\"便签\",

点击打开它,这时就可以使用键盘输入各种英文字符了,还可以使用 USB条码扫描器直接扫描条码进行输入。

1.4.3 配置优盘

(1)因为优盘用到了 SCSI命令,所以我们先增加 SCSI 支持。

在 Device Drivers 菜单里面,选择 SCSI device support,再选择SCSI disk support

(2)返回 Device Drivers菜单,再选择 USB support,按回车进入 USB support菜单找到并选中\"<*> USB Mass Storage support\",

(3)另外,现在的优盘等移动存储器使用的大都是 FAT/FAT32格式的,因此我们还需要添加 FAT32 文件系统的支持,在内核配置主菜单下依次选择如下菜单项: File systems --->

DOS/FAT/NT Filesystems --->

进入 FAT32 文件系统配置子菜单,并选择MSDOS fs support

(4)除此之外,为了支持中英文的编码,在\"File systems\"菜单下选择\"-*- Native language support --->\"并进入在这里,我们要选择如下几个编码的支持: Codepage 437 (United States, Canada)

NLS ISO 8859-1 (Latin 1; Western European Languages) NLS UTF-8

退出保存以上配置。

1.4.3 测试优盘

接上面的步骤,在内核源代码根目录下执行:make zImage,把生成的新内核烧写到开发板中,先不要插入优盘(这样做是为了看插入时的打印信息),等系统启动后,进入命令行控制台,此时优盘已经被自动挂载到开发板的/udisk 目录。 Ls

说明:在 Qtopia中支持优盘自动挂载是通过友善之臂开发的一个 Qtopia 2.2.0插件实现的,目前它只识别 MMC/SD 卡或优盘的第一个分区,并且格式为常见的 VFAT/FAT32/FAT16,如果你的优盘或者 SD卡不能识别,请检查是否为 VFAT/FAT32/FAT16 格式。

1.5 移植 SD卡驱动

1.5.1 在内核中注册 SD设备驱动

Linux-2.6.32.2 已经自带了 S3C2440芯片的 SD 卡驱动,我们只需在初始化代码中加入SD平台设备结构就可以,打arch/arm/mach-s3c2440/mach-mini2440.c,在 nand flash平台结 构后面添加如下红色代码:

;在 mini2440.c的顶部添加 SD 卡设备结构所需的头文件 #include #include

static struct platform_device mini2440_device_eth = { .name = \"dm9000\ .id = -1,

.num_resources = ARRAY_SIZE(mini2440_dm9k_resource), .resource = mini2440_dm9k_resource, .dev = {

.platform_data = &mini2440_dm9k_pdata, }; },

/* MMC/SD */

// mini2440_mmc_cfg在初始化函数里面

static struct s3c24xx_mci_pdata mini2440_mmc_cfg = { .gpio_detect = S3C2410_GPG(8), .gpio_wprotect = S3C2410_GPH(8), .set_power = NULL,

.ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34, };

并把 SD 卡结构设备添加到目标平台设备集中,如图: static struct platform_device *mini2440_devices[] __initdata = { &s3c_device_usb, &s3c_device_rtc,

&s3c_device_lcd, &s3c_device_wdt, &s3c_device_i2c0, &s3c_device_iis, &mini2440_device_eth, &s3c24xx_uda134x, &s3c_device_nand, &s3c_device_sdi, };

SD 卡的驱动程序底层操作实际对应源代码 linux-2.6.32.2/drivers/mmc/host/s3cmci.c, 根据测试,当包含内核打印信息时,SD 卡可以被正常识别使用,而没有打印信息时,则表现的不太稳定,因此我们在该程序中添加了一句延时代码,如图: ;延时函数所需的头文件 #include

static void pio_tasklet(unsigned long data) {

struct s3cmci_host *host = (struct s3cmci_host *) data;

s3cmci_disable_irq(host, true); udelay(50); //在此处添加了延时函数

if (host->pio_active == XFER_WRITE) do_pio_write(host);

注意:还要在mach-mini2440.c中的初始化函数里面加入SD信息。 static void __init mini2440_machine_init(void) {

s3c24xx_fb_set_platdata(&mini2440_fb_info); s3c_i2c0_set_platdata(NULL);

s3c_device_nand.dev.platform_data = &mini2440_nand_info; s3c_device_sdi.dev.platform_data = &mini2440_mmc_cfg;

platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices)); //smdk_machine_init(); }

这样,我们就完成了 SD 卡驱动的初步移植。

注意:添加完这些之后SD卡能自动挂载了,但是还是不能正常的读写。

1.5.2 测试 SD卡

接上面的步骤,在内核源代码目录执行:make zImage,把生成的内核烧写到开发板中,先不要插入 SD卡(这样做是为了看插入时的打印信息),等系统启动后,进入命令行控制台此时 SD卡已经被自动挂载到开发板的/sdcard 目录。

说明:支持 SD卡或者优盘自动挂载是通过友善之臂开发的一个 Qtopia 2.2.0插件实现的,目前它只识别 MMC/SD 卡或优盘的第一个分区,并且格式为常见的 VFAT/FAT32/FAT16,如果你的优盘或者 SD卡不能识别,请检查是否为 VFAT/FAT32/FAT16 格式。

1.5.3 mini2440 的 SD卡驱动分析(来自网络)

原文出处:

http://www.arm9home.net/read.php?tid-2570.html

linux2.6.32.2 mini2440平台移植-- UDA1341 音频驱动移植

1.6.1 在初始化文件中加入 UDA1341 设备结构

Linux-2.6.32.2已经完美的支持UDA1341音频芯片的驱动,我们只要在

arch/arm/mach-s3c2440/mach-mini2440.c 文件中注册 UDA1341 平台设备的控制端口就可以了,打开 mach-mini2440.c,添加如下内容: //在文件首部添加头文件

#include

//在 LCD 平台设备后面添加 UDA1341 设备结构

static struct s3c24xx_uda134x_platform_data s3c24xx_uda134x_data = { .l3_clk = S3C2410_GPB(4), .l3_data = S3C2410_GPB(3), .l3_mode = S3C2410_GPB(2), .model = UDA134X_UDA1341, };

static struct platform_device s3c24xx_uda134x = { .name = \"s3c24xx_uda134x\

.dev = {

.platform_data = &s3c24xx_uda134x_data, } };

//注册 UDA1341 设备平台到内核中 //这些注册的结构在哪定义的??

static struct platform_device *mini2440_devices[] __initdata = { &s3c_device_usb, &s3c_device_rtc, &s3c_device_lcd, &s3c_device_wdt, &s3c_device_i2c0, &s3c_device_iis, &mini2440_device_eth, &s3c24xx_uda134x, &s3c_device_nand, };

这样,我们基本就添加好了 UDA1341 音频设备的驱动,接下来我们在内核中配置该驱动。

注意:其实在做完以上工作时还是不能放MP3,没有DSP节点,我后面根据 http://www.arm9home.net/read.php?tid-1481-fpage-0-toread--page-2.html 引用

No device for DAI UDA134X No device for DAI s3c24xx-i2s

这是ALSA的警告信息,不影响uda1341驱动的。 引用

S3C24XX_UDA134X SoC Audio driver UDA134X SoC Audio Codec

asoc: UDA134X <-> s3c24xx-i2s mapping ok ALSA device list:

#0: S3C24XX_UDA134X (UDA134X)

这说明UDA1341 for S3C24xx的ALSA驱动已经成功加载了。需要了解的是,ALSA本身

并不会生成/dev/dsp节点,那是OSS驱动的东西。

要在你的系统里使用/dev/dsp节点,你必须确保选中了ALSA的―OSS 模拟‖选项。它可以通过在内核配置中的

\"Sound card support\" ---> \"Advanced Linux Sound Architecture\" --> \"OSS PCM (digital audio) API\" 配置。

1.6.2 在内核中配置 UDA1341 设备驱动

在内核源代码目录输入:make menuconfig 开始配置内核,依次选择如下子菜单,找到音频驱动配置菜单: Device Drivers ---> <*> Sound card support --->

按空格选中\"[*] Preclaim OSS device numbers \",

再选中\"<*> Advanced Linux Sound Architecture --->\",并回车进入该子菜单 出现音频驱动体系结构菜单,在这里,我们选择 OSS 接口相关的配置选项,需

要注意的是,这里的 OSS 接口其实是基于 ALSA 接口创建的,因为新的内核中现在都已经改用 ALSA 设计,这里是为了和以前的软件兼容才这样做的,

再选择\"<*> ALSA for SoC audio support --->\"子菜单并回车进入,在这里我们可以看到专门为 S3C24xx 系列芯片(包括 S3C2410/2440/2443 等)而做的

配置选项,打开 linux-2.6.32.2/sound/soc/s3c24xx/Makefile 文件就可以看到, 我们的开发板使用的是 UDA1341 音频芯片,在这里当然要选择 \"-*- SoC I2S Audio support UDA134X wired to a S3C24XX\"了。 退出保存以上各项配置。

1.6.3 mp3 放音测试

在内核源代码目录执行:make zImage,把生成的内核映像文件烧写到开发板,依然使用友善之臂提供的文件系统 root_qtopia,系统启动后,使用系统自带的 madplay 软件播放一首mp3 进行测试,把音箱或者耳机插入开发板的绿色音频输出插座,就可以听到音乐了,

1.6.4 修正驱动中的录音代码

虽然播放 mp3 很正常,但当使用系统自带的录音程序进行录音时,我们发现无法听到任何结果,这是因为开发板的录音电路和 SMDK2440 目标板的电路是有所区别的。

mini2440 开发板使用的录音通道为 VIN2,而 SMDK2440 使用的则是 VIN1,打开 linux-2.6.32.2/sound/soc/codecs/ uda134x.c,在大概 201 行添加如下红色代码: uda134x->slave_substream = substream; } else

uda134x->master_substream = substream;

uda134x_write(codec, 2, 2|(5U<<2)); //把录音通道改为 VIN2 return 0; }

static void uda134x_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) {

这样,我们就完成了录音驱动的修正,在内核源代码目录下执行:make zImage,重新编译内核并烧写到开发板中。

1.6.5 录音测试

打开 Qtopia 中的\"录音机\"测试程序,根据提示,点\"REC\"按钮开始录音,这时对着板上的麦克风说话,可以看到录音的波形,点\"STOP\"按钮结束录音,此时可以点\"PLAY\"按钮播放刚才的录音,同时录制的音频文件将以\"WAV\"格式

自动存储到\"文档\"中:说明:Qtopia2.2.0 系统自带了一个录音程序,中文名为\"语音便签\",但它不能正常使用板上的麦克风进行录制。

linux2.6.32.2 mini2440平台移植-- 串口驱动移植、I2C-EEPROM 驱动移植、看门狗驱动移植 1.7.1 把 UART2 改为普通串口驱动

S3C2440 芯片具有 3 个串口:UART0,1,2,我们下载的 Linux-2.6.32.2 已经具备完善的 UART0,1 的驱动,但对UART2 却用作了红外通讯(Irda),因此我们需要把 UART2 驱动稍微调整一下,以便作为普通串口来用。 先看看 S3C2440 串口部分寄存器的说明,如下图

接下来我们修改内核中关于 UART2 的配置,打开 mach-mini2440.c 文件,找到,如下红色代码为修改后的:

static struct s3c2410_uartcfg mini2440_uartcfgs[] __initdata = { [0] = { .hwport = 0, .flags = 0, .ucon = 0x3c5, .ulcon = 0x03, .ufcon = 0x51, }, [1] = { .hwport = 1, .flags = 0, .ucon = 0x3c5, .ulcon = 0x03, .ufcon = 0x51, },

/* 把 UART2 改为普通串口 */ [2] = { .hwport = 2, .flags = 0,

.ucon = 0x3c5, .ulcon = 0x03, .ufcon = 0x51, }; }

再修改串口所使用的端口初始化,打开 linux-2.6.32.2/drivers/serial/samsung.c,在大概 432 行左右,添加如下红色部分代码: //需要添加的头文件 #include #include

ourport->tx_claimed = 1;

dbg(\"s3c24xx_serial_startup ok\\n\");

/* the port reset code should have done the correct * register setup for the port controls */ //串口 2 对应的端口初始化 if (port->line == 2) {

s3c2410_gpio_cfgpin(S3C2410_GPH(6), S3C2410_GPH6_TXD2); s3c2410_gpio_pullup(S3C2410_GPH(6), 1);

s3c2410_gpio_cfgpin(S3C2410_GPH(7), S3C2410_GPH7_RXD2); s3c2410_gpio_pullup(S3C2410_GPH(7), 1); } return ret;

这样,我们就完成了 UART2 的修整。

1.7.2 测试串口

回到内核源代码目录,执行:make zImage,把重新生成的内核烧写到开发板中,依然使用友善之臂提供的 root_qtopia 文件系统,因为里面包含了一个图形界面的串口助手测试程序,极其方便测试。需要注意的是,mini2440 开发板并没有把 UART2 做成 RS232 端口引出,而是直接把它通过CON3 排针引出了,因此需要一条 RS232 转接板(该转接板由友善之臂提供),把它连接到 mini2440 开发板的 CON3 接口,并把引出的串口通过直连线连接到另一台

电脑的串口上,连接好开发板的电源,并设置 S2 为 nand 启动,打开电源,进入 Qtopia 系统,在\"友善之臂\"程序组中点\"串口助手\"图标,打开相应的程序界面,从该程序窗口的标题可以看到,默认设置为\"ttySAC1 115200 8N1 [C]\",它表示默认 端口的设置:

- 串口设备:/dev/ttySAC1,它对应 CPU 的第二个串口 UART1 - 波特率:115200 - 数据位:8 - 流控制:无 - 停止位:1

- [C]:表示字符模式,如果是[H]则表示 16 进制模式

上图中有两个\"编辑框\"区域,上面的\"编辑框\"是用于显示接收到的数据,它实际

上是不能编辑的;下面的\"编辑框\"可以通过 USB 键盘或者 Qtopia 的软键盘获取输入。因为我们要测试 UART2,因此点\"Setting\"按钮,在设置窗口中选中/dev/ttySAC2,

然后返回主界面,点 Connect 按钮,以打开开发板串口/dev/ttySAC2,在窗口下面的编辑框输入一些字符,点 Send 按钮,就可以向与它相连的串口设备发送数据了,下图显示的是通过Windows 超级终端接收的数据截图(注意:与此终端对应的串口也应该设置为 115200 8N1)。

1.8.1 在内核中配置 I2C 驱动

Linux-2.6.32.2 对 S2C2440 的 I2C 接口提供了完善的驱动,因此我们只需在内核中配置一下即可使用。

提示:其实 Linux-2.6.32.2 内核缺省的 mini2440_defconfig 就已经配置好了 I2C 驱动, 我们只不过在此打开看看具体的配置路径。在内核源代码目录执行: make menuconfig,进入内核配置主菜单,依次选择进入如下子菜单: Device Drivers ---> <*> I2C support --->

I2C Hardware Bus support --->

我们看到这里已经选择好了\"<*> S3C2410 I2C Driver\",这里的 S3C2410 也可以适用于 S3C2440,因为它们的 I2C 端口及寄存器定义都是完全相同的。

以上配置所对应的驱动源代码为:linux-2.6.32.2/drivers/i2c/busses/i2c-s3c2410.c,

1.8.2 测试 I2C-EEPROM 测试程序名称: i2c

测试程序源代码文件名Eeprom.c 24cXX.c 测试程序源代码位置解压 linux\\examples.tgz 可得 交叉编译器Arm-linux-gcc-4.3.2 with EABI 开发板上对应的设备名/dev/i2c/0

对应的内核驱动源代码Linux-src/drivers/i2c/busses/i2c-s3c2440.c 其他:

Mini2440 为了方便用户测试,基于 I2C 总线挂接了一个 EEPROM 芯片,它是 AT24C08,通过写入和读取该芯片,我们就可以测试 I2C 总线驱动了。在内核根目录下执行:make zImage,把生成的新内核烧写到开发板中,依然使用友

善之臂提供的root_qtopoia,因为里面已经包含了I2C-EEPROM测试程序,分别有命令行和图形界面的,其中命令行测试程序名为\"i2c\",它是基于开源的eeprog软件修改而来的,eeprog软件的下载地址是:http://codesink.org/eeprog.html

在命令行种输入:i2c -w 可以向板子的 24C08 器件中写入数据(0x00-0xff) 在命令行中输入:i2c -r 可以从板子的 24C08 器件中读出输出

1.9.1 在内核中配置看门狗驱动

Linux-2.6.32.2 内核具有完善的 S3C2440 的看门狗驱动,我们只需配置一下就可以使用了。 提示:其实 Linux-2.6.32.2 内核缺省的 mini2440_defconfig 就已经配置好了看门狗驱动, 在内核源代码目录执行:make menuconfig,进入内核配置主菜单,依次选择进入如下子菜单:

Device Drivers --->

[*] Watchdog Timer Support --->

如图,打开看门狗配置菜单,在这里可以选择对 S2C2410/2440 中看门狗的配置选项,以上配置所对应的驱动源代码为:linux-2.6.32.2/drivers/watchdog/s3c2410_wdt.c,感

1.9.2 关于打开和关闭看门狗

在看门狗驱动程序中,我们注意到有这样一个函数,注意其中的红色部分字体: #define PFX \"s3c2410-wdt: \"

#define CONFIG_S3C2410_WATCHDOG_ATBOOT (0)

//这里表明看门狗的默认时间是 15 秒,如果超过此时间系统将自行重启 #define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15)

static ssize_t s3c2410wdt_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) { /*

* Refresh the timer. */ if (len) { if (!nowayout) { size_t i;

/* In case it was set long ago */ expect_close = 0;

for (i = 0; i != len; i++) { char c;

if (get_user(c, data + i)) return -EFAULT; if (c == 'V') expect_close = 42; } }

s3c2410wdt_keepalive(); return len; } }

根据此代码,我们判定可以在打开看门狗设备(/dev/watchdog)之后不断的向看门狗随便写入一些数据以实现喂狗操作,但是,当写入\"V\"时,就可以关闭看门狗了。

1.9.3 测试看门狗

虽然友善之臂提供了一个漂亮的图形界面的看门狗测试程序,但因为操作看门狗比较简单,我们不需要编写任何代码即可测试。

根据上面的分析,我们可以使用 echo 命令向/dev/watchdog 设备随便写入一些数据即可开启看门狗,比如:echo 0 > /dev/watchdog,此时,如果静等15 秒钟,系统将会自动重启,这样就证实了看门狗已经被开启了。如果 15 秒之内,我们不停地重复\"喂狗\"操作,也就是不停的使用 echo 命令向看门狗写入数据,那么系统就不会重启。那么,如何停止看门狗呢?根据上面的分析,只要写入\"V\"就可以了。需要知道的是,但我们使用 echo 命令向/dev/watchdog 写入数据的时候,同时也把\"回车\"给送进去了, 因此可以这样操作:echo -n V >/dev/watchdog

这里的\"-n\"意思是\"去掉回车\",为了测试,你可以先输入: echo 0 > /dev/watchdog 接着再输入:

echo -n V > /dev/watchdog

然后接着静等,过了好久,系统依然在正常运行,这就证明了看门狗已经被关闭了。

几种linux内核文件的区别(vmlinux、zImage、bzImage、uImage、vmlinuz、initrd )

对于Linux内核,编译可以生成不同格式的映像文件,例如: # make zImage # make uImage

zImage是ARM Linux常用的一种压缩映像文件,uImage是U-boot专用的映像文件,它是在zImage之前加上一个长度为0x40的―头‖,说明这个映像文件的类型、加载位置、生成时间、大小等信息。换句话说,如果直接从uImage的0x40位置开始执行,zImage和uImage没有任何区别。另外,Linux2.4内核不支持uImage,Linux2.6内核加入了很多对嵌入式系统的支持,但是uImage的生成也需要设置。

几种linux内核文件的区别:

1、vmlinux 编译出来的最原始的内核文件,未压缩。 2、zImage 是vmlinux经过gzip压缩后的文件。

3、bzImage bz表示“big zImage”,不是用bzip2压缩的。两者的不同之处在于,zImage解压缩内核到低端内存(第一个0K),bzImage解压

缩内核到高端内存(1M以上)。如果内核比较小,那么采用zImage或bzImage都行,如果比较大应该用bzImage。

4、uImage U-boot专用的映像文件,它是在zImage之前加上一个长度为0x40的tag。

5、vmlinuz 是bzImage/zImage文件的拷贝或指向bzImage/zImage的链接。

6、initrd 是“initial ramdisk”的简写。一般被用来临时的引导硬件到实际内核vmlinuz能够接管并继续引导的状态。

一、vmlinuz

vmlinuz是可引导的、压缩的内核。―vm‖代表―Virtual Memory‖。Linux 支持虚拟内存,不像老的操作系统比如DOS有0KB内存的。Linux能够使用硬盘空间作为虚拟内存,因此得名―vm‖。

vmlinuz 的建立有两种方式。一是编译内核时通过―make zImage‖创建,然后通过:―cp /usr/src/linux-2.4/arch/i386/linux/boot/zImage/boot/vmlinuz‖产生。zImage适用于小内核的情况,它的存在是为了向后的兼容性。 二是内核编译时通过命令make bzImage创建,然后通

过:―cp/usr/src/linux-2.4/arch/i386/linux/boot/bzImage /boot/vmlinuz‖产生。bzImage是压缩的内核映像,需要注意,bzImage不是用bzip2压缩的,bzImage中的bz容易引起误解,bz表示―big zImage‖。 bzImage中的b是―big‖意思。 zImage(vmlinuz)和bzImage(vmlinuz)都是用gzip压缩的。它们不仅是一个压缩文件,而且在这两个文件的开头部分内嵌有 gzip解压缩代码。所以你不能用gunzip 或 gzip –dc解包vmlinuz。 二、initrd-x.x.x.img

initrd是―initial ramdisk‖的简写。initrd一般被用来临时的引导硬件到实际内核vmlinuz能够接管并继续引导的状态。

initrd 映象文件是使用mkinitrd创建的。mkinitrd实用程序能够创建initrd映象文件。这个命令是RedHat专有的。其它Linux发行版或许有相应的命令。这是个

很方便的实用程序。具体情况请看帮助:man mkinitrd下面的命令创建initrd映象文件。

最后生成的内核镜象有两种 zImage 以及 uImage 。其中 zImage 下载到目标板中后,可以直接用 uboot 的命令 go 来进行直接跳转。这时候内核直接解压启动。但是无法挂载文件系统,因为 go 命令没有将内核需要的相关的启动参数传递给内核。传递启动参数我们必须使用命令 bootm 来进行跳转。 Bootm 命令跳转只处理 uImage 的镜象。

uboot 源代码的 tools/ 目录下有 mkimage 工具,这个工具可以用来制作不压缩或者压缩的多种可启动映象文件。

mkimage 在制作映象文件的时候,是在原来的可执行映象文件的前面加上一个 0x40 字节的头,记录参数所指定的信息,这样 uboot 才能识别这个映象是针对哪个 CPU 体系结构的,哪个 OS 的,哪种类型,加载内存中的哪个位置, 入口点在内存的那个位置以及映象名是什么 用法如下:

./mkimage -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image -A ==> set architecture to 'arch' -O ==> set operating system to 'os' -T ==> set image type to 'type' -C ==> set compression type 'comp' -a ==> set load address to 'addr' (hex) -e ==> set entry point to 'ep' (hex) -n ==> set image name to 'name' -d ==> use image data from 'datafile' -x ==> set XIP (execute in place) 参数说明:

-A 指定 CPU 的体系结构:

取值 表示的体系结构 alpha Alpha arm A RM x86 Intel x86 ia IA

mips MIPS

mips MIPS Bit ppc PowerPC s390 IBM S390 sh SuperH sparc SPARC

sparc SPARC Bit m68k MC68000

-O 指定操作系统类型,可以取以下值:

openbsd 、 netbsd 、 freebsd 、 4_4bsd 、 linux 、 svr4 、 esix 、 solaris 、 irix 、 sco 、 dell 、 ncr 、 lynxos 、 vxworks 、 psos 、 qnx 、 u-boot 、 rtems 、 artos

-T 指定映象类型,可以取以下值:

standalone 、 kernel 、 ramdisk 、 multi 、 firmware 、 script 、 filesystem

-C 指定映象压缩方式,可以取以下值: none 不压缩

gzip 用 gzip 的压缩方式 bzip2 用 bzip2 的压缩方式

-a 指定映象在内存中的加载地址,映象下载到内存中时,要按照用 mkimage 制作映象时,这个参数所指定的地址值来下载

-e 指定映象运行的入口点地址,这个地址就是 -a 参数指定的值加上 0x40 (因为前面有个 mkimage 添加的 0x40 个字节的头)

-n 指定映象名

-d 指定制作映象的源文件 我在编译时用到的命令如下:

# make zImage // 生成 zImage 镜象

# /usr/local/arm/k9uboot/tools/ mkimage -n 'Linux 2.4.27' -A arm -O linux -T kernel -C none -a 0x20007fc0 -e 0x20008000 -d zImage uImage

在嵌入式开发领域,ARM是一款非常受欢迎的微处理器,其市场覆盖率极高,DSP和FPGA则是作为嵌入式开发的协处理器,协助微处理器更好的实现产品功能。那三者的技术特点以及区别是什么呢?下文就此问题略做了总结。

ARM(Advanced RISC Machines)是微处理器行业的一家知名企业,设计了大量高性能、廉价、耗能低的RISC处理器、相关技术及软件。

ARM架构是面向低预算市场设计的第一款RISC微处理器,基本是32位单片机的行业标准,它提供一系列内核、体系扩展、微处理器和系统芯片方案,四个功能模块可供生产厂商根据不同用户的要求来配置生产。由于所有产品均采用一个通用的软件体系,所以相同的软件可在所有产品中运行。目前ARM在手持设备市场占有90以上的份额,可以有效地缩短应用程序开发与测试的时间,也降低了研发费用。

DSP(digital singnal processor)是一种独特的微处理器,有自己的完整指令系统,是以数字信号来处理大量信息的器件。一个数字信号处理器在一块不大的芯片内包括有控制单元、运算单元、各种寄存器以及一定数量的存储单元等等,在其外围还可以连接若干存储器,并可以与一定数量的外部设备互相通信,有软、硬件的全面功能,本身就是一个微型计算机。DSP采用的是哈佛设计,即数据总线和地址总线分开,使程序和数据分别存储在两个分开的空间,允许取指令和执行指令完全重叠。也就是说在执行上一条指令的同时就可取出下一条指令,并进行译码,这大大的提高了微处理器的速度 。另外还允许在程序空间和数据空间之间进行传输,因为增加了器件的灵活性。其工作原理是接收模拟信号,转换为0或1

的数字信号,再对数字信号进行修改、删除、强化,并在其他系统芯片中把数字数据解译回模拟数据或实际环境格式。它不仅具有可编程性,而且其实时运行速度可达每秒数以千万条复杂指令程序,远远超过通用微处理器,是数字化电子世界中日益重要的电脑芯片。它的强大数据处理能力和高运行速度,是最值得称道的两大特色。由于它运算能力很强,速度很快,体积很小,而且采用软件编程具有高度的灵活性,因此为从事各种复杂的应用提供了一条有效途径。根据数字信号处理的要求,DSP芯片一般具有如下主要特点:

(1)在一个指令周期内可完成一次乘法和一次加法; (2)程序和数据空间分开,可以同时访问指令和数据;

(3)片内具有快速RAM,通常可通过的数据总线在两块中同时访问; (4)具有低开销或无开销循环及跳转的硬件支持; (5)快速的中断处理和硬件I/O支持;

(6)具有在单周期内操作的多个硬件地址产生器; (7)可以并行执行多个操作;

(8)支持流水线操作,使取指、译码和执行等操作可以重叠执行。 当然,与通用微处理器相比,DSP芯片的其他通用功能相对较弱些。

FPGA是英文Field Programmable Gate Array(现场可编程门阵列)的缩写,它是在PAL、GAL、PLD等可编程器件的基础上进一步发展的产物,是专用集成电路(ASIC)中集成度最高的一种。FPGA采用了逻辑单元阵列LCA(Logic Cell Array)这样一个新概念,内部包括可配置逻辑模块CLB(Configurable Logic Block)、输出输入模块IOB(Input Output Block)和内部连线(Interconnect)三个部分。用户可对FPGA内部的逻辑模块和I/O模块重新配置,以实现用户的逻辑。它还具有静态可重复编程和动态在系统重构的特性,使得硬件的功能可以像软件一样通过编程来修改。作为专用集成电路(ASIC)领域中的一种半定制电路,FPGA既解决了定制电路的不足,又克服了原有可编程器件门电路数有限的缺点。可以毫不夸张的讲,FPGA能完成任何数字器件的功能,上至高性能CPU,下至简单的74电路,都可以用FPGA来实现。FPGA如同一张白纸或是一堆积木,工程师可以通过传统的原理图输入法,或是硬件描述语言自由的设计一个数字系统。通过软件仿真,我们可以事先验证设计的正确性。在PCB完成以后,还可以利用FPGA的在线修改能力,随时修改设计而不必改动硬件电路。使用FPGA来开发数字电路,可以大大缩短设计时间,减少PCB面积,提高系统的可靠性。FPGA是由存放在片内RAM中的程序来设置其工作状态的,因此工作时需要对片内的RAM进行编程。用户可以根据不同的配置模式,采用不同的编程方式。加电时,FPGA芯片将EPROM中数据读入片内编程RAM中,配置完成后,FPGA进入工作状态。掉电后,FPGA恢复成白片,内部逻辑关系消失,因此,FPGA能够反复使用。FPGA的编程无须专用的FPGA编程器,只须用通用的EPROM、PROM编程器即可。当

需要修改FPGA功能时,只需换一片EPROM即可。这样,同一片FPGA,不同的编程数据,可以产生不同的电路功能。因此,FPGA的使用非常灵活。可以说,FPGA芯片是小批量系统提高系统集成度、可靠性的最佳选择之一。目前FPGA的品种很多,有XILINX的XC系列、TI公司的TPC系列、ALTERA公司的FIEX系列等。

ARM作为嵌入式开发最常用的处理器,是嵌入式工程师必须掌握的一门知识。ARM体系架构在嵌入式学院<嵌入式工程师职业培训班>的二期课程中将会结合嵌入式linux应用开发、嵌入式linux系统移植进行详细介绍,另外华清远见的短期培训业务中也分别有针对ARM、DSP、FPGA的培训课程。

区别是什么?:ARM具有比较强的事务管理功能,可以用来跑界面以及应用程序等,其优势主要体现在控制方面,而DSP主要是用来计算的,比如进行加密解密、调制解调等,优势是强大的数据处理能力和较高的运行速度。FPGA可以用VHDL或verilogHDL来编程,灵活性强,由于能够进行编程、除错、再编程和重复操作,因此可以充分地进行设计开发和验证。当电路有少量改动时,更能显示出FPGA的优势,其现场编程能力可以延长产品在市场上的寿命,而这种能力可以用来进行系统升级或除错。

Linux下解压命令大全 解压缩 tar bz2 zip tar.gz gz

大致总结了一下linux下各种格式的压缩包的压缩、解压方法。但是部分方法我没有用到,也就不全,希望大家帮我补充,我将随时修改完善,谢谢!

整理:会游泳的鱼 来自:www.LinuxByte.net 最后更新时间:2005-2-20

.tar

解包:tar xvf FileName.tar

打包:tar cvf FileName.tar DirName (注:tar是打包,不是压缩!) ———————————————

.gz

解压1:gunzip FileName.gz 解压2:gzip -d FileName.gz 压缩:gzip FileName

.tar.gz 和 .tgz

解压:tar zxvf FileName.tar.gz

压缩:tar zcvf FileName.tar.gz DirName

———————————————

.bz2

解压1:bzip2 -d FileName.bz2 解压2:bunzip2 FileName.bz2 压缩: bzip2 -z FileName

.tar.bz2

解压:tar jxvf FileName.tar.bz2

压缩:tar jcvf FileName.tar.bz2 DirName ———————————————

.bz

解压1:bzip2 -d FileName.bz 解压2:bunzip2 FileName.bz 压缩:未知

.tar.bz

解压:tar jxvf FileName.tar.bz 压缩:未知

———————————————

.Z

解压:uncompress FileName.Z 压缩:compress FileName

.tar.Z

解压:tar Zxvf FileName.tar.Z

压缩:tar Zcvf FileName.tar.Z DirName ———————————————

.zip

解压:unzip FileName.zip 压缩:zip FileName.zip DirName ———————————————

.rar

解压:rar x FileName.rar

压缩:rar a FileName.rar DirName

rar请到:http://www.rarsoft.com/download.htm 下载!

解压后请将rar_static拷贝到/usr/bin目录(其他由$PATH环境变量指定的目录也可以): [root@www2 tmp]# cp rar_static /usr/bin/rar

———————————————

.lha

解压:lha -e FileName.lha

压缩:lha -a FileName.lha FileName

lha请到:http://www.infor.kanazawa-it.ac.jp/~ishii/lhaunix/下载!

>解压后请将lha拷贝到/usr/bin目录(其他由$PATH环境变量指定的目录也可以): [root@www2 tmp]# cp lha /usr/bin/ ———————————————

.rpm

解包:rpm2cpio FileName.rpm | cpio -div ———————————————

.deb

解包:ar p FileName.deb data.tar.gz | tar zxf - ———————————————

.tar .tgz .tar.gz.tar.Z .tar.bz .tar.bz2 .zip .cpio .rpm .deb .slp .arj .rar .ace .lha.lzh .lzx .lzs .arc .sda .sfx .lnx .zoo .cab .kar .cpt .pit .sit .sea

解压:sEx x FileName.*

压缩:sEx a FileName.* FileName

sEx只是调用相关程序,本身并无压缩、解压功能,请注意! sEx请到: http://sourceforge.net/projects/sex下载!

解压后请将sEx拷贝到/usr/bin目录(其他由$PATH环境变量指定的目录也可以): [root@www2 tmp]# cp sEx /usr/bin/

gzip 命令

减少文件大小有两个明显的好处,一是可以减少存储空间,二是通过网络传输文件时,可以减少传输的时间。gzip 是在 Linux 系统中经常使用的一个对文件进行压缩和解压缩的命令,既方便又好用。

语法:gzip [选项] 压缩(解压缩)的文件名 该命令的各选项含义如下:

-c 将输出写到标准输出上,并保留原有文件。 -d 将压缩文件解压。

-l 对每个压缩文件,显示下列字段:

压缩文件的大小;未压缩文件的大小;压缩比;未压缩文件的名字 -r 递归式地查找指定目录并压缩其中的所有文件或者是解压缩。

-t 测试,检查压缩文件是否完整。

-v 对每一个压缩和解压的文件,显示文件名和压缩比。

-num 用指定的数字 num 调整压缩的速度,-1 或 --fast 表示最快压缩方法(低压缩比), -9 或--best表示最慢压缩方法(高压缩比)。系统缺省值为 6。 指令实例: gzip *

% 把当前目录下的每个文件压缩成 .gz 文件。

gzip -dv *

% 把当前目录下每个压缩的文件解压,并列出详细的信息。

gzip -l *

% 详细显示例1中每个压缩的文件的信息,并不解压。

gzip usr.tar

% 压缩 tar 备份文件 usr.tar,此时压缩文件的扩展名为.tar.gz。

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- igbc.cn 版权所有 湘ICP备2023023988号-5

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务