Linux-2636-rc4移植.doc

上传人:本田雅阁 文档编号:2736553 上传时间:2019-05-09 格式:DOC 页数:115 大小:5.18MB
返回 下载 相关 举报
Linux-2636-rc4移植.doc_第1页
第1页 / 共115页
Linux-2636-rc4移植.doc_第2页
第2页 / 共115页
Linux-2636-rc4移植.doc_第3页
第3页 / 共115页
Linux-2636-rc4移植.doc_第4页
第4页 / 共115页
Linux-2636-rc4移植.doc_第5页
第5页 / 共115页
点击查看更多>>
资源描述

《Linux-2636-rc4移植.doc》由会员分享,可在线阅读,更多相关《Linux-2636-rc4移植.doc(115页珍藏版)》请在三一文库上搜索。

1、 Linux-2.6.36-rc4移植文档 制作人:陈颖 手机:xxxxxxxxx 邮箱: 博客: http:/ Linux-2.6.36-rc4移植文档 目录(1) 内核源码获取3(2) 修改平台机器码 1 . 修改平台机器码4 2. U-boot到linux内核机器码的传入与匹配原理浅析4(3) 修改时钟源频率 1. 修改时钟源频率6 2. 关于时钟源频率的探索6(4) 串口移植 1. 串口移植9 2. 串口设备驱动原理浅析10 (1)串口设备模型建立10 (2)串口数据流分析12(5) NAND FLASH移植 1. NAND FLASH移植18 2. 移植yaffs2文件系统18 3.

2、 MTD设备模型浅析21 (1)硬件驱动层21 (2)MTD设备的字符设备层23 (3)MTD设备的块设备层24(6) 看门狗驱动移植 1. 看门狗驱动移植26 2. 看门狗驱动原理分析27(7) RTC驱动移植 1. RTC驱动移植29 2. RTC驱动原理分析30(8) LCD显示驱动移植 1. LCD显示驱动移植33 2. 帧缓冲驱动原理浅析35(9) 触摸屏驱动移植 1. 触摸屏驱动移植39 2. 输入子系统原理分析42 (1)输入子系统设备模型建立流程42 (2)输入事件的传递过程46(10) USB主控制器驱动移植 1. 配置对U盘的支持50 2. USB主控制器驱动原理浅析51

3、(1)USB设备模型建立流程图51 (2)USB主控制器驱动程序分析53(11) I2C适配器驱动移植 1. I2C适配器驱动移植61 2. I2C适配器驱动原理分析63 (1)设备模型建立流程图63 (2)I2C适配器驱动程序分析65(12) 声卡驱动移植 1. UDA1341声卡驱动移植70 2. MP3 播放器madplay 移植72 3. 声卡驱动原理浅析75 (1)声卡驱动结构概览75 (2)声卡驱动设备模型建立流程图75 (3)声卡设备驱动程序分析77 (4)各操作函数集相互调用关系图86(13) DM9000网卡驱动移植 1. DM9000网卡驱动移植87 2. DM9000网卡

4、驱动程序简单分析89(14) SD卡驱动移植 1. SD卡驱动移植95 2. SD卡驱动原理浅析96 (1)设备模型建立流程图 96 (2)SD卡设备模型建立程序分析98(15) SPI设备驱动移植 1. SPI设备驱动移植104 2. SPI设备驱动原理分析106 (1)SPI设备模型建立流程图106 (2)SPI设备驱动程序分析108 制作人:陈颖 手机:xxxxxxxx 邮箱:博客: http:/ Linux-2.6.36-rc4移植环境: 交叉编译环境:Arm-linux-gcc-4.3.3 with EABI (天嵌科技提供,存放路径 /opt/EmbedSky/4.3.3)开发平台

5、:TQ2440(1) 内核源码获取 从http:/www.kernel.org/获取最新linux内核源码Linux-2.6.36-rc4,在/opt/embed下解压#tar jxvf linux-2.6.36-rc4.tar.bz2进入内核根目录#cd linux-2.6.36-rc4在整个移植过程中可能要经历很多次的便宜配置,所以在内核根目录下编写两个脚本如下:脚本一#vim mkm#!/bin/bashmake ARCH=arm CROSS_COMPILE=arm-linux- menuconfig脚本二#vim mkz#!/bin/bashmake ARCH=arm CROSS_CO

6、MPILE=arm-linux- zImage然后添加可执行权限#chmod +x mkm mkz使用缺省内核配置文件,s3c2410_defconfig#make ARCH=arm CROSS_COMPILE=arm-linux- s3c2410_defconfig 由于在制作根文件系统时,busybox是用Arm-linux-gcc-4.3.3编译的,而编译器默认是打开“EABI选项”的,所以内核也要选中EABI选项。#.mkm 用上面编写的脚本调出配置菜单 (2) 修改平台机器码 1 . 修改平台机器码 在文件 linux-2.6.36.rc4/arch/arm/tools/mach_t

7、ypes中有此处本来是362现在改为168 。本次移植将以SMDK2440为基础,所以这里的机器码对应着MACHINE_START(S3C2440, SMDK2440)MACHINE_END 中的S3C2440。这个平台描述结构在文件linux-2.6.36.rc4/arch/arm/mach-s3c2440/mach-smdk2440.c中。这个内核中的机器码必须与u-boot传入的机器码一致,内核才能正常启动。现在用的U-boot是先前移植的u-boot-2010.06,那时还没有移植自己的内核,用天嵌科技提供的内核,他的内核机器码是168,所以移植的u-boot的机器码也是168,所以为

8、了与u-boot中的机器码保持一致这里也将机器码改为168。2. U-boot到linux内核机器码的传入与匹配原理浅析 在u-boot中SMDK2440的机器码在文件arch/arm/tools/mach-types.h中定义在文件board/cy2440/cy2440.c(原路径board/samsung/smdk2410/smdk2410.c)中赋给了全局结构体成员gd-bd-bi_arch_number。int board_init (void)SMDK2440-Board */gd-bd-bi_arch_number = MACH_TYPE_SMDK2440;内核引导的过程中最终调用

9、函数do_bootm_linux(),在arch/arm/lib/bootm.c中int do_bootm_linux(int flag, int argc, char *argv, bootm_headers_t *images)Int machid = bd-bi_arch_number;theKernel = (void (*)(int, int, uint)images-ep;进入内核,传入三个参数r0为0,r1为机器码,r2为内核参数的位置。theKernel (0, machid, bd-bi_boot_params); 进入内核执行的第一个文件是linux/arch/arm/bo

10、ot/compressed/head.S,这个文件实现了内核的解压与重定位。在这个文件的开始有这样两句:1: mov r7, r1 save architecture ID /将机器码保存到r7,mov r8, r2 save atags pointer /将内核参数地址保存到r8在内核解压重定位之后将执行这样几句:mov r0, #0 must be zeromov r1, r7 restore architecture number /将机器码放回r1mov r2, r8 restore atags pointer mov pc, r4 call kernel /程序跳转接下来程序将进入文

11、件linux/arch/arm/kernel/head.S,在该文件中有这样一句bl _lookup_machine_type r5=machinfo在程序段_lookup_machine_type中实现了u-boot传入机器码与内核机器码的匹配,要知道这个匹配过程先来了解一些相关知识:Linux内核所支持的每一个CPU平台都有一个描述它的结构machine_desc。描述SMDK2440的结构体在文件linux-2.6.36.rc4/arch/arm/mach-s3c2440/mach-smdk2440.c中:MACHINE_START(S3C2440, SMDK2440).phys_io=

12、 S3C2410_PA_UART,MACHINE_END宏MACHINE_START在文件arch/arm/include/asm/mach/arch.h中定义:#define MACHINE_START(_type,_name)static const struct machine_desc _mach_desc_#_type_used _attribute_(_section_(.arch.info.init) = .nr= MACH_TYPE_#_type,.name= _name,#define MACHINE_END;因此SMDK2440描述结构体可展开如下:static const

13、 struct machine_desc _mach_desc_S3C2440 _used _attribute_(_section_(.arch.info.init) = .nr= MACH_TYPE_S3C2440,.name= SMDK2440,;_attribute_(_section_(.arch.info.init)表明了该结构在编译链接时存放的位置。在链接文件arch/arm/kernel/vmlinux.lds中有SECTIONS.init : /* Init code and data*/_arch_info_begin = .;*(.arch.info.init)_arch

14、_info_end = .;Linux中所有被编译的CPU平台描述结构体都存放在_arch_info_begin与_arch_info_end之间。程序段_lookup_machine_type在linux/arch/arm/kernel/head-common.S中实现,该程序段所做的工作就是在_arch_info_begin与_arch_info_end之间找出一个平台描述结构体static const struct machine_desc _mach_desc_S3C2440.nr= MACH_TYPE_#_type,;使该平台的机器码machine_desc-nr与u-boot传入的

15、机器码匹配。如下1: ldr r3, r5, #MACHINFO_TYPE 读取平台描述结构体中机器码 teq r3, r1 与u-boot传入的机器码相比较。 beq 2f found add r5, r5, #SIZEOF_MACHINE_DESC next machine_desc cmp r5, r6 blo 1b(3) 修改时钟源频率 1. 修改时钟源频率原SMDK2440目标板上的晶振是16.9344MHz,此处改为12MHZ。2. 关于时钟源频率的探索 CPU时钟相关寄存器的配置并不是在linux内核中进行的,而是在u-boot中。在u-boot移植的过程中加入了一个C文件clo

16、ck_init.c在改文件中实现了CPU时钟相关寄存器的配置如下。/* S3C2440: Mpll = (2*m * Fin) / (p * 2s), UPLL = (m * Fin) / (p * 2s) * m = M (the value for divider M)+ 8, p = P (the value for divider P) + 2 */* Fin = 12.0000MHz */#define S3C2440_MPLL_400MHZ (0x5c12)|(0x014)|(0x01)#define S3C2440_UPLL_48MHZ (0x3812)|(0x02CLKDIVN

17、 = S3C2440_CLKDIV;/1:4:8clk_power-LOCKTIME = 0xFFFFFF;clk_power-UPLLCON = S3C2440_UPLL_48MHZ;delay (4000);clk_power-MPLLCON = S3C2440_MPLL_400MHZ;delay (8000);在linux内核中此处修改频率有何作用?分析如下:函数 s3c24xx_init_clocks()在文件linux/arch/arm/plat-s3c/init.c中实现。下面就是它做的主要工作:void _init s3c24xx_init_clocks(int xtal)(cp

18、u-init_clocks)(xtal);Cpu是文件linux/arch/arm/plat-s3c/init.c中的一个全局变量static struct cpu_table *cpu;函数s3c24xx_init_io()将找出一个合适的结构体,并让这里的cpu指针指向这个结构体。void _init s3c24xx_init_io(struct map_desc *mach_desc, int size)if (cpu_architecture() = CPU_ARCH_ARMv5) idcode = s3c24xx_read_idcode_v5(); else idcode = s3c

19、24xx_read_idcode_v4();arm_pm_restart = s3c24xx_pm_restart;s3c_init_cpu(idcode, cpu_ids, ARRAY_SIZE(cpu_ids);函数s3c_init_cpu()当然是在文件linux/arch/arm/plat-s3c/init.c中实现了void _init s3c_init_cpu(unsigned long idcode,struct cpu_table *cputab, unsigned int cputab_size)cpu = s3c_lookup_cpu(idcode, cputab, cpu

20、tab_size); /找到合适的结构体并让指/针cpu指向s3c24xx系列CPU每一个具体的型号都有一个结构体来描述,这些结构体存放在数组cpu_ids中。数组cpu_ids在文件 linux/arch/arm/plat-s3c24xx/cpu.c中定义。static struct cpu_table cpu_ids _initdata = .idcode = 0x32440001,.idmask = 0xffffffff,.map_io = s3c244x_map_io,.init_clocks = s3c244x_init_clocks,.init_uarts = s3c244x_in

21、it_uarts,.init = s3c2440_init,.name = name_s3c2440a, ;此处我们要找的是 name_s3c2440a。在上面函数s3c24xx_init_clocks()中所调用的(cpu-init_clocks)(xtal);就是函数s3c244x_init_clocks()。这个函数的功能是将系统总线时钟hclk 和外设总线时钟pclk以及各个外设时钟包装成结构体clk,并注册到内核,也就是添加到链表clocks上。该clk结构在文件linux/arch/arm/plat-s3c/include/plat/clock.h中定义如下:struct clk

22、struct list_head list;struct module *owner;struct clk *parent;const char *name;int id;int usage;unsigned long rate;unsigned long ctrlbit;struct clk_ops*ops;int (*enable)(struct clk *, int enable);(4) 串口移植1. 串口移植S3C2440共有3个串口,在SMDK2440平台上串口0和串口1都作为普通串口使用,串口2工作在红外收发模式。TQ2440开发板将它们都作为普通串口,目前所需要的只有串口0,作

23、为控制终端,所以此处不作修改。在文件 linux/arch/arm/plat-s3c24xx/devs.c中定义了三个串口的硬件资源。static struct resource s3c2410_uart0_resource = ;static struct resource s3c2410_uart1_resource = ;static struct resource s3c2410_uart2_resource = ;在文件linux/arch/arm/plat-samsung/dev-uart.c中定义了每个串口对应的平台设备。static struct platform_device

24、 s3c24xx_uart_device0 = .id= 0,;static struct platform_device s3c24xx_uart_device1 = .id= 1,;static struct platform_device s3c24xx_uart_device2 = .id= 2,;在文件linux/arch/arm/mach-s3c2440/mach-smdk2440.c中有串口一些寄存器的初始化配置。static struct s3c2410_uartcfg smdk2440_uartcfgs _initdata = 0 = ,1 = ,/* IR port */2

25、 = ;在文件linux/arch/arm/mach-s3c2440/mach-smdk2440.c中将调用函数s3c24xx_init_uarts()最终将上面的硬件资源,初始化配置,平台设备整合到一起。在文件 linux/arch/arm/plat-s3c/init.c中有static int _init s3c_arch_init(void)ret = platform_add_devices(s3c24xx_uart_devs, nr_uarts);return ret;这个函数将串口所对应的平台设备添加到了内核。2. 串口设备驱动原理浅析我认为任何设备在linux中的实现就“两条线”

26、。一是设备模型的建立,二是读写数据流。串口驱动也是这样。(1)串口设备模型建立:串口设备驱动的核心结构体在文件linux/drivers/serial/samsuing.c中如下static struct uart_driver s3c24xx_uart_drv = .owner= THIS_MODULE,.dev_name= s3c2410_serial, .nr= CONFIG_SERIAL_SAMSUNG_UARTS,.cons= S3C24XX_SERIAL_CONSOLE,.driver_name= S3C24XX_SERIAL_NAME,.major= S3C24XX_SERIAL

27、_MAJOR,.minor= S3C24XX_SERIAL_MINOR,;串口驱动的注册static int _init s3c24xx_serial_modinit(void)ret = uart_register_driver(&s3c24xx_uart_drv);串口驱动其实是一个典型的tty驱动int uart_register_driver(struct uart_driver *drv)/每一个端口对应一个statedrv-state = kzalloc(sizeof(struct uart_state) * drv-nr, GFP_KERNEL);normal = alloc_t

28、ty_driver(drv-nr); /分配该串口驱动对应的tty_driver drv-tty_driver = normal; /让drv-tty_driver字段指向这个tty_drivernormal-driver_name= drv-driver_name;normal-name= drv-dev_name;normal-major= drv-major;normal-minor_start= drv-minor;/设置该tty驱动对应的操作函数集tty_operations (linux/drivers/char/core.c)tty_set_operations(normal,

29、&uart_ops); retval = tty_register_driver(normal); /将tty驱动注册到内核其实tty驱动的本质是一个字符设备,在文件 linux/drivers/char/tty_io.c中int tty_register_driver(struct tty_driver *driver)cdev_init(&driver-cdev, &tty_fops);driver-cdev.owner = driver-owner;error = cdev_add(&driver-cdev, dev, driver-num);它所关联的操作函数集tty_fops在文件l

30、inux/drivers/char/tty_io.c中实现static const struct file_operations tty_fops = .llseek= no_llseek,.read= tty_read,.write= tty_write,.open= tty_open,;到此串口的驱动作为tty_driver被注册到了内核。前面提到串口的每一个端口都是作为平台设备被添加到内核的。那么这些平台设备就对应着有它们的平台设备驱动。在文件linux/drivers/serial/s3c2440.c中有:static struct platform_driver s3c2440_se

31、rial_driver = .probe= s3c2440_serial_probe,.remove= _devexit_p(s3c24xx_serial_remove),.driver= .name= s3c2440-uart,.owner= THIS_MODULE,;当其驱动与设备匹配时就会调用他的探测函数static int s3c2440_serial_probe(struct platform_device *dev)return s3c24xx_serial_probe(dev, &s3c2440_uart_inf);每一个端口都有一个描述它的结构体s3c24xx_uart_por

32、t 在 文件linux/drivers/serial/samsuing.cstatic struct s3c24xx_uart_port s3c24xx_serial_portsCONFIG_SERIAL_SAMSUNG_UARTS = 0 = .port = .lock= _SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports0.port.lock),.iotype= UPIO_MEM,.irq= IRQ_S3CUART_RX0, /该端口的中断号.uartclk= 0,.fifosize= 16,.ops= &s3c24xx_serial_ops, /该端口的操作

33、函数集.flags= UPF_BOOT_AUTOCONF,.line= 0, /端口编号,上面探测函数的具体工作是函数s3c24xx_serial_probe()来完成的int s3c24xx_serial_probe(struct platform_device *dev, struct s3c24xx_uart_info *info)/根据平台设备提供的硬件资源等信息初始化端口描述结构体中的一些字段ret = s3c24xx_serial_init_port(ourport, info, dev);/前面注册了串口驱动,这里便要注册串口设备uart_add_one_port(&s3c24x

34、x_uart_drv, &ourport-port);int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) /前面说串口驱动是tty_driver,这里可以看到串口设备其实是tty_devtty_dev = tty_register_device(drv-tty_driver, uport-line, uport-dev);(2)串口数据流分析: 在串口设备模型建立中提到了三个操作函数集,uart_ops ,tty_fops,s3c24xx_serial_ops数据的流动便是这些操作函数间的调用,这些调用

35、关系如下: tty_readtty_writetty_ioctl struct file_operations tty_fops tty_io.c struct tty_ldisc_ops tty_ldisc_N_TTY N_tty.c struct tty_operations uart_ops serial_core.c static struct uart_ops s3c24xx_serial_ops Samsung.c 在对一个设备进行其他操作之前必须先打开它,linux/drivers/char/tty_io.cstatic const struct file_operations tty_fops = .open= tty_open,;static int tty_open(struct inode *inode, struct file *filp)dev_t device = inode-i_rdev;driver = get_tty_driver(device, &index); /根据端口设备号获取它的索引号if (tty) elsetty = tty_init_dev(driver, index, 0); /创建一个tty_struct 并初始化

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 其他


经营许可证编号:宁ICP备18001539号-1