嵌入式 Linux framebuffer 驱动移植日志

本文详细介绍了Linux内核从启动到进入系统的过程,包括初始化硬件、加载核心模块、启动线程等关键步骤,并深入探讨了系统架构如何将函数与硬件相连接。

Linux 初始化过程:

/init/main.c中的start_kernel()开始:
该函数中,主要做了下列事情:

1)先是
boot_cpu_init();
初始化了启动相关的内容后
然后
printk(KERN_NOTICE);
printk(linux_banner);
打印内核信息,比如我这里的:
Linux version 2.6.22.2 (crifan@localhost.localdomain) (gcc version 4.3.2 (GCC) ) #89 Fri May 15 11:25:09 CST 2009

2
其后主要初始化了中断,时钟等:
init_IRQ();
init_timers();
softirq_init();
3
再打印出命令行:
printk(KERN_NOTICE "Kernel command line: %s/n", boot_command_line);
如此处的:
Kernel command line: root=/dev/mtdblock2 rw init=/linuxrc console=ttyS0,115200 mem=64M rootfstype=jffs2

4
后来才是调用
console_init();
去初始化Uart的,就是调用uartprobe函数。

5
先预初始化:
cpuset_init_early();

6
初始化内存:
mem_init();

7
初始化buffer
buffer_init();
再初始化cpu(组):
cpuset_init();

8
check_bugs();
去测试CPU的相关情况:

CPU: Testing write buffer coherency: ok

9
最后调用:
rest_init();
去启动线程
kernel_init
{
。。。
do_basic_setup();
。。。
init_post();

}

其中调用
do_basic_setup();
{
。。。
driver_init();
。。。
do_initcalls();
。。。
}
去初始化Linux kernel相关的内容

其中
driver_init()
{
/* These are the core pieces */
devices_init();
buses_init();
classes_init();
firmware_init();
hypervisor_init();

/* These are also core pieces, but must come after the
* core core pieces.
*/
platform_bus_init();
system_bus_init();
cpu_dev_init();
memory_dev_init();
attribute_container_init();
}
初始化真正的系统的

device
busclass等等内容,

然后的
do_initcalls()
{
//
__Start 开始 __End 结束,
//
以此调用之前内核中相关的__init前缀的那些初始化函数
}

其中,这些用__init标明的函数,可以在system.map中看到对应的信息,
包括对应的变量和其对应的地址

c001d164 t __initcall_ptrace_break_init1
c001d164 T __initcall_start
c001d168 t __initcall_consistent_init
1
c001d16c t __initcall_sysctl_init
1
c001d170 t __initcall_init_jiffies_clocksource
1
c001d174 t __initcall_pm_init
1
c001d178 t __initcall_ksysfs_init1
。。。。。。。。。。。。。。。
c001d194 t __initcall_sock_init1
c001d198 t __initcall_netlink_proto_init
1
c001d19c t __initcall_kobject_uevent_init
2
c001d1a0 t __initcall_amba_init
2
c001d1a4 t __initcall_tty_class_init
2
c001d1a8 t __initcall_vtconsole_class_init
2
c001d1ac t __initcall_customize_machine3
。。。。。。。。。。。
c001d1b0 t __initcall_clk_init3
c001d1b4 t __initcall_dma_init
3
c001d1bc t __initcall_topology_init
4
c001d1c0 t __initcall_param_sysfs_init4
。。。。。。。。。。。。。
c001d200 t __initcall_init_pipe_fs5
c001d204 t __initcall_eventpoll_init5
。。。。。。。。。。。。。。
c001d24c t __initcall_init6
c001d250 t __initcall_kallsyms_init
6
c001d254 t __initcall_utsname_sysctl_init
6
c001d258 t __initcall_init_per_zone_pages_min
6
c001d25c t __initcall_pdflush_init6
。。。。。。。。。。
c001d2e8 t __initcall_loop_init6
c001d2ec t __initcall_net_olddevs_init
6
c001d2f0 t __initcall_loopback_init
6
c001d2f4 t __initcall_init_mtd
6
c001d2f8 t __initcall_afs_parser_init
6
c001d2fc t __initcall_init_mtdchar
6
c001d300 t __initcall_init_mtdblock
6
c001d304 t __initcall_init_nftl6
。。。。。。。。。。。。
c001d388 t __initcall_ip_auto_config7
。。。。。。。。。。。

可以看出,这些函数经过系统处理后,
加了前缀__initcall_和后缀的数字,看起来是表示启动的阶段。
也就是加了和函数对应的一个个变量(标示)

当然,也可以找到函数对应的首地址,比如
变量
c001d1b0 t __initcall_clk_init3
对应的函数clk_init放在c000e624
c000e624 t clk_init

然后,调用
init_post()
{
1.
打开console
sys_open("/dev/console", O_RDWR, 0)

2.运行命令:
run_init_process(ramdisk_execute_command);

run_init_process(execute_command);

3.运行系统初始化文件:
run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh");

}
最后,我们才进入我们熟悉的嵌入式Linux环境,

才能输入用户名和密码(如果有的话),比如:
Welcome to Embedded Linux
(none) login: root
Dec 31 17:00:11 login[704]: root login on 'ttyS0'
# cd /
。。。


【附录】
关于系统架构中,如何把函数和系统联系起来

注:我这里是arm架构的板子

arch/arm/kernel/setup.c
void __init setup_arch(char **cmdline_p)
{
init_arch_irq = mdesc->init_irq;
system_timer = mdesc->timer;
init_machine = mdesc->init_machine;
}

mdesc即使machine description
对应的是你在arch/arm/mach-XXX/mach-XXXX.c
中定义的,类似于如下的内容:

MACHINE_START(XXXX, "XXXX")
/* Maintainer: Austriamicrosystems Ltd */
.phys_io = XXXX,
.io_pg_offst = XXXX,
.boot_params = XXXX,
.map_io   = XXXX_map_io,
.init_irq = XXXX_init_irq,
.timer   = &XXXX_timer,
.init_machine = XXXX_init,
MACHINE_END

其中XXX代表你的板子(架构)名字。

 

 

 

 

移植日志:

 

1)初始化LCD控制器

  Arch/arm/mach-s3c2410/Mach-smdk2410.c

 

static struct s3c2410fb_mach_info s3c2410fb_info _initdata = {

       .fixed_syncs     = 0,

    .regs    = {

           .lcdcon1    = S3C2410_LCDCON1_TFT16BPP |

                    S3C2410_LCDCON1_TFT |

                // S3C2410_LCDCON1_ENVID |

                    S3C2410_LCDCON1_CLKVAL(1),

           .lcdcon2    = S3C2410_LCDCON2_VBPD(25) | S3C2410_LCDCON2_VFPD(5)

| S3C2410_LCDCON2_VSPW(1),

     .lcdcon3    = S3C2410_LCDCON3_HBPD(67) | S3C2410_LCDCON3_HFPD(40),

      .lcdcon4    = S3C2410_LCDCON4_HSPW(31) | S3C2410_LCDCON4_MVAL(13),

      .lcdcon5    = S3C2410_LCDCON5_FRM565 | S3C2410_LCDCON5_HWSWP |

S3C2410_LCDCON5_PWREN|S3C2410_LCDCON5_INVVLINE|S3C2410_LCDCON5_INVV

FRAME ,

    },

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

   .gpccon=        0xaaaaaaaa,

   .gpccon_mask=   0xffffffff,

   .gpcup=         0xffffffff,

   .gpcup_mask=    0xffffffff,

   .gpdcon=        0xaaaaaaaa,

   .gpdup =       0xFFFFFFFF,

   .gpdup_mask=    0xffffffff,

   .width        = 640,

   .height       = 480,

   .yres        = {

       .min    = 480,

       .max    = 480,

       .defval    = 480,

    },

   .xres        = {

      .min    = 640,

      .max    = 640,

      .defval = 640,

   },

.bpp        = {

     .min    = 16,

     .max    = 16,

     .defval = 16,

   },

};

2)添加信息到设备

static void __init smdk2410_lcd_init(void)

{

       set_s3c2410fb_info(&s3c2410fb_info);  //devs.c中实现的加入控制器信息到device设备

}

 

  3)在系统初始化中增加对 lcd 的初始化

MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch

                                * to SMDK2410 */

       /* Maintainer: Jonas Dietsche */

       .phys_ram      = S3C2410_SDRAM_PA,

       .phys_io  = S3C2410_PA_UART,

       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,

       .boot_params  = S3C2410_SDRAM_PA + 0x100,

       .map_io          = smdk2410_map_io,

       .init_irq   = smdk2410_init_irq,

       .timer             = &s3c24xx_timer,

       .init_machine =smdk2410_lcd_init;

MACHINE_END

4make menuconfig 中还要加入 S3C2410 frambuffer support 选项。

     Device Driver

           Ghipics support

            具体显示设备支持选项、Framebuffer终端配置选项和Framebuffer Logo配置选项

         s3c2410 LCD framebuffer support

          

  4)最后编译执行,就能看到小企鹅了。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值