您的位置:首页 > 其它

Machine_desc & boot & Kernel_init & initcall & module_init

2014-11-10 10:12 162 查看
跳转到start_kernel中,与本题相关的主要是setup_arch()和rest_init(),其中前者执行的较早,而后者做为start_kernel执行的最后一个函数。

函数start_kernel()和rest_init()定义在kernel/init/main.c中,函数setup_arch()定义在kernel/arch/arch_name/kernel/setup.c中。

1.setup_arch()在.init.text中,会执行machine_desc.init_very_early和machine_desc.init_early,代码如下,

[cpp] view
plaincopy

915void __init setup_arch(char **cmdline_p)

916{

917 struct machine_desc *mdesc;

918

919 unwind_init();

920

921 setup_processor();

922 mdesc = setup_machine_fdt(__atags_pointer);

923 if (!mdesc)

924 mdesc = setup_machine_tags(machine_arch_type);

925 machine_desc = mdesc;

926 machine_name = mdesc->name;

927

928 if (mdesc->soft_reboot)

929 reboot_setup("s");

930

931 init_mm.start_code = (unsigned long) _text;

932 init_mm.end_code = (unsigned long) _etext;

933 init_mm.end_data = (unsigned long) _edata;

934 init_mm.brk = (unsigned long) _end;

935

936 /* populate cmd_line too for later use, preserving boot_command_line */

937 strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);

938 *cmdline_p = cmd_line;

939

940 parse_early_param();

941

942 if (mdesc->init_very_early)

943 mdesc->init_very_early();

944

945 sanity_check_meminfo();

946 arm_memblock_init(&meminfo, mdesc);

947

948 paging_init(mdesc);

949 request_standard_resources(mdesc);

950

951 unflatten_device_tree();

952

953#ifdef CONFIG_SMP

954 if (is_smp())

955 smp_init_cpus();

956#endif

957 reserve_crashkernel();

958

959 cpu_init();

960 tcm_init();

961

962#ifdef CONFIG_MULTI_IRQ_HANDLER

963 handle_arch_irq = mdesc->handle_irq;

964#endif

965

966#ifdef CONFIG_VT

967#if defined(CONFIG_VGA_CONSOLE)

968 conswitchp = &vga_con;

969#elif defined(CONFIG_DUMMY_CONSOLE)

970 conswitchp = &dummy_con;

971#endif

972#endif

973 early_trap_init();

974

975 if (mdesc->init_early)

976 mdesc->init_early();

977}

2. rest_init()执行后,创建内核线程kernel_init,这也是内核第一个线程,kernel_init做的与本题相关的初始化是do_pre_smp_initcalls()和do_basic_setup(),然后变成用户态进程init。代码如下,

[cpp] view
plaincopy

841static int __init kernel_init(void * unused)

842{

843 /*

844 * Wait until kthreadd is all set-up.

845 */

846 wait_for_completion(&kthreadd_done);

847 /*

848 * init can allocate pages on any node

849 */

850 set_mems_allowed(node_states[N_HIGH_MEMORY]);

851 /*

852 * init can run on any cpu.

853 */

854 set_cpus_allowed_ptr(current, cpu_all_mask);

855

856 cad_pid = task_pid(current);

857

858 smp_prepare_cpus(setup_max_cpus);

859

860 do_pre_smp_initcalls();

861 lockup_detector_init();

862

863 smp_init();

864 sched_init_smp();

865

866 do_basic_setup();

867

868 /* Open the /dev/console on the rootfs, this should never fail */

869 if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)

870 printk(KERN_WARNING "Warning: unable to open an initial console.\n");

871

872 (void) sys_dup(0);

873 (void) sys_dup(0);

874 /*

875 * check if there is an early userspace init. If yes, let it do all

876 * the work

877 */

878

879 if (!ramdisk_execute_command)

880 ramdisk_execute_command = "/init";

881

882 if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {

883 ramdisk_execute_command = NULL;

884 prepare_namespace();

885 }

886

887 /*

888 * Ok, we have completed the initial bootup, and

889 * we're essentially up and running. Get rid of the

890 * initmem segments and start the user-mode stuff..

891 */

892

893 init_post();

894 return 0;

895}

do_pre_smp_initcalls()做.initcallearly.init section函数的执行,早于.initcall0.init-.initcall7.init;在初始化完smp调度后,.initcalln.init函数在do_basic_setup()被调用。

do_pre_smp_initcalls()代码如下,

[cpp] view
plaincopy

786static void __init do_pre_smp_initcalls(void)

787{

788 initcall_t *fn;

789

790 for (fn = __initcall_start; fn < __initcall0_start; fn++)

791 do_one_initcall(*fn);

792}

do_basic_setup()及调用.initcalln.init的代码如下,

[cpp] view
plaincopy

743static void __init do_initcall_level(int level)

744{

745 extern const struct kernel_param __start___param[], __stop___param[];

746 initcall_t *fn;

747

748 strcpy(static_command_line, saved_command_line);

749 parse_args(initcall_level_names[level],

750 static_command_line, __start___param,

751 __stop___param - __start___param,

752 level, level,

753 repair_env_string);

754

755 for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)

756 do_one_initcall(*fn);

757}

758

759static void __init do_initcalls(void)

760{

761 int level;

762

763 for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)

764 do_initcall_level(level);

765}

766

767/*

768 * Ok, the machine is now initialized. None of the devices

769 * have been touched yet, but the CPU subsystem is up and

770 * running, and memory and process management works.

771 *

772 * Now we can finally start doing some real work..

773 */

774static void __init do_basic_setup(void)

775{

776 cpuset_init_smp();

777 usermodehelper_init();

778 shmem_init();

779 driver_init();

780 init_irq_proc();

781 do_ctors();

782 usermodehelper_enable();

783 do_initcalls();

784}

各.initcalln.init的宏定义如下

[cpp] view
plaincopy

168/* initcalls are now grouped by functionality into separate

169 * subsections. Ordering inside the subsections is determined

170 * by link order.

171 * For backwards compatibility, initcall() puts the call in

172 * the device init subsection.

173 *

174 * The `id' arg to __define_initcall() is needed so that multiple initcalls

175 * can point at the same handler without causing duplicate-symbol build errors.

176 */

177

178#define __define_initcall(level,fn,id) \

179 static initcall_t __initcall_##fn##id __used \

180 __attribute__((__section__(".initcall" level ".init"))) = fn

181

182/*

183 * Early initcalls run before initializing SMP.

184 *

185 * Only for built-in code, not modules.

186 */

187#define early_initcall(fn) __define_initcall("early",fn,early)

188

189/*

190 * A "pure" initcall has no dependencies on anything else, and purely

191 * initializes variables that couldn't be statically initialized.

192 *

193 * This only exists for built-in code, not for modules.

194 */

195#define pure_initcall(fn) __define_initcall("0",fn,0)

196

197#define core_initcall(fn) __define_initcall("1",fn,1)

198#define core_initcall_sync(fn) __define_initcall("1s",fn,1s)

199#define postcore_initcall(fn) __define_initcall("2",fn,2)

200#define postcore_initcall_sync(fn) __define_initcall("2s",fn,2s)

201#define arch_initcall(fn) __define_initcall("3",fn,3)

202#define arch_initcall_sync(fn) __define_initcall("3s",fn,3s)

203#define subsys_initcall(fn) __define_initcall("4",fn,4)

204#define subsys_initcall_sync(fn) __define_initcall("4s",fn,4s)

205#define fs_initcall(fn) __define_initcall("5",fn,5)

206#define fs_initcall_sync(fn) __define_initcall("5s",fn,5s)

207#define rootfs_initcall(fn) __define_initcall("rootfs",fn,rootfs)

208#define device_initcall(fn) __define_initcall("6",fn,6)

209#define device_initcall_sync(fn) __define_initcall("6s",fn,6s)

210#define late_initcall(fn) __define_initcall("7",fn,7)

211#define late_initcall_sync(fn) __define_initcall("7s",fn,7s)

212

213#define __initcall(fn) device_initcall(fn)

214

215#define __exitcall(fn) \

216 static exitcall_t __exitcall_##fn __exit_call = fn

217

218#define console_initcall(fn) \

219 static initcall_t __initcall_##fn \

220 __used __section(.con_initcall.init) = fn

221

222#define security_initcall(fn) \

223 static initcall_t __initcall_##fn \

224 __used __section(.security_initcall.init) = fn

machine_desc.init_machine在customize_machine() @ kernel/arch/arm/kernel/setup.c中被调用,而customize_machine指针引用在.initcall3.init中。customize_machine()代码如下,

[cpp] view
plaincopy

842static int __init customize_machine(void)

843{

844 /* customizes platform devices, or adds new ones */

845 if (machine_desc->init_machine)

846 machine_desc->init_machine();

847 return 0;

848}

849arch_initcall(customize_machine);

各module_init(fn)设备驱动在.initcall6.init中被调用,由以下module_init的宏定义可以看出,

[cpp] view
plaincopy

259/**

260 * module_init() - driver initialization entry point

261 * @x: function to be run at kernel boot time or module insertion

262 *

263 * module_init() will either be called during do_initcalls() (if

264 * builtin) or at module insertion time (if a module). There can only

265 * be one per module.

266 */

267#define module_init(x) __initcall(x);

而__initcall(x)宏定义为

[cpp] view
plaincopy

213#define __initcall(fn) device_initcall(fn)

综上,题中提及各初始化的顺序是machine_desc.init_very_early, machine_desc.init_early, .initcallearly.init, machine_desc.init_machine(.initcall3.init), module_init(.initcall6.init) 。

[End]

[参考文章]

http://blog.csdn.net/paomadi/article/details/8611408

一、定义

[cpp] view
plaincopy

#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 \

};

MACHINE_START和MACHINE_END框起了一个machine_desc结构体的声明并根据MACHINE_START宏的参数初始化其.nr和.name成员

并将该结构体标记编译到.arch.info.init段

在MACHINE_START和MACHINE_END宏之间可以初始化machine_desc结构体的剩余成员

machine_desc结构体的定义

[cpp] view
plaincopy

struct machine_desc {

unsigned int nr; /* architecture number 编号 */

const char *name; /* architecture name 名字 */

unsigned long boot_params; /* tagged list */

unsigned int nr_irqs; /* number of IRQs 中断数 */

unsigned int video_start; /* start of video RAM */

unsigned int video_end; /* end of video RAM */

unsigned int reserve_lp0 :1; /* never has lp0 */

unsigned int reserve_lp1 :1; /* never has lp1 */

unsigned int reserve_lp2 :1; /* never has lp2 */

unsigned int soft_reboot :1; /* soft reboot */

void (*fixup)(struct machine_desc *,struct tag *, char **,struct meminfo *);

void (*reserve)(void); /* reserve mem blocks */

void (*map_io)(void); /* IO mapping function io映射函数 */

void (*init_irq)(void); /* 中断初始化函数 */

struct sys_timer *timer; /* system tick timer 滴答定时器 */

void (*init_machine)(void); /* 初始化函数 */

};

使用例子:

[cpp] view
plaincopy

MACHINE_START(SMDKC110, "SMDKC110")

/* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */

.boot_params = S5P_PA_SDRAM + 0x100,

.init_irq = s5pv210_init_irq,

.map_io = smdkc110_map_io,

.init_machine = smdkc110_machine_init,

.timer = &s3c24xx_timer,

MACHINE_END

这里smdkc110_machine_init就是对应的板级初始化函数,s5pv210_init_irq就是板级中断初始化函数,smdkc110_map_io就是板级io初始化函数...

二、调用关系

MACHINE_START宏将machine_desc标记编译到.arch.info.init段, 而/arch/arm/kernel/vmlinux.lds中

[cpp] view
plaincopy

__arch_info_begin = .;

*(.arch.info.init)

__arch_info_end = .;

当系统启动时在linux启动函数start_kernel中调用了setup_arch(&command_line);

[cpp] view
plaincopy

void __init setup_arch(char **cmdline_p)

{

struct tag *tags = (struct tag *)&init_tags;

struct machine_desc *mdesc; //声明了一个machine_desc结构体指针

char *from = default_command_line;

init_tags.mem.start = PHYS_OFFSET;

unwind_init();

setup_processor();

mdesc = setup_machine(machine_arch_type); //0根据machine_arch_type获取machine_desc

machine_name = mdesc->name; //设置名字

if (mdesc->soft_reboot) //需要软重启?

reboot_setup("s");

if (__atags_pointer)

tags = phys_to_virt(__atags_pointer);

else if (mdesc->boot_params) { //处理启动参数

#ifdef CONFIG_MMU

if (mdesc->boot_params < PHYS_OFFSET ||

mdesc->boot_params >= PHYS_OFFSET + SZ_1M) {

printk(KERN_WARNING"Default boot params at physical 0x%08lx out of reach\n",mdesc->boot_params);

} else

#endif

{

tags = phys_to_virt(mdesc->boot_params);

}

}

#if defined(CONFIG_DEPRECATED_PARAM_STRUCT)

if (tags->hdr.tag != ATAG_CORE)

convert_to_tag_list(tags);

#endif

if (tags->hdr.tag != ATAG_CORE)

tags = (struct tag *)&init_tags;

if (mdesc->fixup) //若存在fixup方法则调用其方法

mdesc->fixup(mdesc, tags, &from, &meminfo);

if (tags->hdr.tag == ATAG_CORE) {

if (meminfo.nr_banks != 0)

squash_mem_tags(tags);

save_atags(tags);

parse_tags(tags);

}

init_mm.start_code = (unsigned long) _text;

init_mm.end_code = (unsigned long) _etext;

init_mm.end_data = (unsigned long) _edata;

init_mm.brk = (unsigned long) _end;

/* parse_early_param needs a boot_command_line */

strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);

/* populate cmd_line too for later use, preserving boot_command_line */

strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);

*cmdline_p = cmd_line;

parse_early_param();

arm_memblock_init(&meminfo, mdesc); //这里可能会调用reserve方法

paging_init(mdesc); //->devicemaps_init(mdesc)->map_io方法

request_standard_resources(&meminfo, mdesc); //这里可能会调用video_start方法

#ifdef CONFIG_SMP

if (is_smp())

smp_init_cpus();

#endif

reserve_crashkernel();

cpu_init();

tcm_init();

arch_nr_irqs = mdesc->nr_irqs; //1设置全局变量 中断个数

init_arch_irq = mdesc->init_irq; //2设置全局变量 中断初始化函数

system_timer = mdesc->timer; //3设置全局变量 sys_timer结构体

init_machine = mdesc->init_machine; //4设置全局变量 板级初始化函数

#ifdef CONFIG_VT

#if defined(CONFIG_VGA_CONSOLE)

conswitchp = &vga_con;

#elif defined(CONFIG_DUMMY_CONSOLE)

conswitchp = &dummy_con;

#endif

#endif

early_trap_init();

}

0. 结构machine_desc安装

[cpp] view
plaincopy

static struct machine_desc * __init setup_machine(unsigned int nr)

{

extern struct machine_desc __arch_info_begin[], __arch_info_end[];

struct machine_desc *p;

for (p = __arch_info_begin; p < __arch_info_end; p++)//遍历__arch_info_begin和__arch_info_end之间的machine_desc结构体

if (nr == p->nr) { //找到对应的板

printk("Machine: %s\n", p->name);//打印板级信息

return p;

}

early_print("\n"

"Error: unrecognized/unsupported machine ID (r1 = 0x%08x).\n\n"

"Available machine support:\n\nID (hex)\tNAME\n", nr);

for (p = __arch_info_begin; p < __arch_info_end; p++)

early_print("%08x\t%s\n", p->nr, p->name);

early_print("\nPlease check your kernel config and/or bootloader.\n");

while (true)

/* can't use cpu_relax() here as it may require MMU setup */;

}

1.中断个数

start_kernel->early_irq_init->arch_probe_nr_irqs函数中nr_irqs = arch_nr_irqs ? arch_nr_irqs : NR_IRQS;设置全局nr_irqs变量

2.中断初始化函数

start_kernel->init_IRQ->init_arch_irq()

3.sys_timer结构体

start_kernel->time_init()调用system_timer->init()方法既sys_timer->init()

4.板级初始化函数

[cpp] view
plaincopy

static void (*init_machine)(void) __initdata;

static int __init customize_machine(void)

{

/* customizes platform devices, or adds new ones */

if (init_machine)//全局函数init_machine存在

init_machine();//则调用,既mdesc->init_machine()

return 0;

}

arch_initcall(customize_machine);//用arch_initcall修饰customize_machine函数

arch_iniitcall函数在/include/linux/init.h中定义

[cpp] view
plaincopy

#define arch_initcall(fn) __define_initcall("3",fn,3)

__define_initcall的定义

[cpp] view
plaincopy

#define __define_initcall(level,fn,id) \

static initcall_t __initcall_##fn##id __used \

__attribute__((__section__(".initcall" level ".init"))) = fn

展开就是static initcall_t __initcall_customize_machine3 __used __attribute__((__section__(".initcall3.init")))=customize_machine

在vmlinux.lds中

[cpp] view
plaincopy

__initcall_start = .;

*(.initcallearly.init)

__early_initcall_end = .;

*(.initcall0.init)

*(.initcall0s.init)

*(.initcall1.init)

*(.initcall1s.init)

*(.initcall2.init)

*(.initcall2s.init)

*(.initcall3.init)

*(.initcall3s.init)

*(.initcall4.init)

*(.initcall4s.init)

*(.initcall5.init)

*(.initcall5s.init)

*(.initcallrootfs.init)

*(.initcall6.init)

*(.initcall6s.init)

*(.initcall7.init)

*(.initcall7s.init)

__initcall_end = .;

标注为.initcall3.init的函数编译进__initcall_start和__initcall_end框起的section中

而在系统启动的时候start_kernel->rest_init()->kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);创建了kernel线程

kernel_init->do_pre_smp_initcalls()

[cpp] view
plaincopy

static void __init do_pre_smp_initcalls(void)

{

initcall_t *fn;

for (fn = __initcall_start; fn < __early_initcall_end; fn++)

do_one_initcall(*fn);

}

该函数遍历__initcall_start和__early_initcall_end中的函数,并调用do_one_initcall

[cpp] view
plaincopy

int __init_or_module do_one_initcall(initcall_t fn)

{

int count = preempt_count();

int ret;

if (initcall_debug)

ret = do_one_initcall_debug(fn);

else

ret = fn();//执行了fn函数也就是customize_machine

msgbuf[0] = 0;

if (ret && ret != -ENODEV && initcall_debug)

sprintf(msgbuf, "error code %d ", ret);

if (preempt_count() != count) {

strlcat(msgbuf, "preemption imbalance ", sizeof(msgbuf));

preempt_count() = count;

}

if (irqs_disabled()) {

strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf));

local_irq_enable();

}

if (msgbuf[0]) {

printk("initcall %pF returned with %s\n", fn, msgbuf);

}

return ret;

}

/article/10023802.html

Machine定义以MACHINE_START开始并以MACHINE_END结束,如下mini2440开发板的移植为示例

[cpp] view
plaincopy

MACHINE_START(MINI2440, "MINI2440")

.phys_io = S3C2410_PA_UART,

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

.boot_params = S3C2410_SDRAM_PA + 0x100,

.map_io = mini2440_map_io,

.init_machine = mini2440_init,

.init_irq = s3c24xx_init_irq,

.timer = &s3c24xx_timer,

MACHINE_END

MACHINE_START、MACHINE_END都是定义的宏,代码如下

[cpp] view
plaincopy

<span style="font-size:12px;">/*

* Set of macros to define architecture features. This is built into

* a table by the linker.

*/

#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 \

};</span>

这两个宏一起定义了一个类型为struct machine_desc的变量,结构体定义如下

[cpp] view
plaincopy

<span style="font-size:12px;">struct machine_desc {

/*

* Note! The first four elements are used

* by assembler code in head.S, head-common.S

*/

unsigned int nr; /* architecture number */

unsigned int phys_io; /* start of physical io */

unsigned int io_pg_offst; /* byte offset for io

* page tabe entry */

const char *name; /* architecture name */

unsigned long boot_params; /* tagged list */

unsigned int video_start; /* start of video RAM */

unsigned int video_end; /* end of video RAM */

unsigned int reserve_lp0 :1; /* never has lp0 */

unsigned int reserve_lp1 :1; /* never has lp1 */

unsigned int reserve_lp2 :1; /* never has lp2 */

unsigned int soft_reboot :1; /* soft reboot */

void (*fixup)(struct machine_desc *,

struct tag *, char **,

struct meminfo *);

void (*map_io)(void);/* IO mapping function */

void (*init_irq)(void);

struct sys_timer *timer; /* system tick timer */

void (*init_machine)(void);

};</span>

这个类型的变量放在内核代码段.arch.info.init中,在内核运行初期,被函数lookup_machine_type(此函数用汇编实现,在汇编文件中)取出,读取流程为

Start_kernel() -> setup_arch() -> setup_machine() -> lookup_machine_type()

在函数setup_machine()中,利用这个结构体类型的变量初始化一些全局变量,以备内核运行时使用,比如

init_arch_irq = mdesc->init_irq;

system_timer = mdesc->timer;

init_machine = mdesc->init_machine;

这个结构体中,成员init_machine保存的是开发板资源注册的初始化代码,init_irq保存的是中断初始化指针,timer保存的是一个struct sys_timer类型的指针…..如果我们要给自己的开发板定制内核,那么我们必须自己实现以上成员函数,其中函数init_machine()是我们向内核传递开发板设备信息的重要的常规途径,分析mini2440开发板内核移植代码知道,在这个函数中,注册了开发板所用到的所有设备的相关硬件信息!

[cpp] view
plaincopy

static void __init mini2440_init(void)

{

struct mini2440_features_t features = { 0 };

int i;

printk(KERN_INFO "MINI2440: Option string mini2440=%s\n",

mini2440_features_str);

/* Parse the feature string */

mini2440_parse_features(&features, mini2440_features_str);

/* turn LCD on */

s3c_gpio_cfgpin(S3C2410_GPC(0), S3C2410_GPC0_LEND);

/* Turn the backlight early on */

WARN_ON(gpio_request(S3C2410_GPG(4), "backlight"));

gpio_direction_output(S3C2410_GPG(4), 1);

/* remove pullup on optional PWM backlight -- unused on 3.5 and 7"s */

s3c_gpio_setpull(S3C2410_GPB(1), S3C_GPIO_PULL_UP);

s3c2410_gpio_setpin(S3C2410_GPB(1), 0);

s3c_gpio_cfgpin(S3C2410_GPB(1), S3C2410_GPIO_INPUT);

/* Make sure the D+ pullup pin is output */

WARN_ON(gpio_request(S3C2410_GPC(5), "udc pup"));

gpio_direction_output(S3C2410_GPC(5), 0);

/* mark the key as input, without pullups (there is one on the board) */

for (i = 0; i < ARRAY_SIZE(mini2440_buttons); i++) {

s3c_gpio_setpull(mini2440_buttons[i].gpio, S3C_GPIO_PULL_UP);

s3c_gpio_cfgpin(mini2440_buttons[i].gpio, S3C2410_GPIO_INPUT);

}

if (features.lcd_index != -1) {

int li;

mini2440_fb_info.displays =

&mini2440_lcd_cfg[features.lcd_index];

printk(KERN_INFO "MINI2440: LCD");

for (li = 0; li < ARRAY_SIZE(mini2440_lcd_cfg); li++)

if (li == features.lcd_index)

printk(" [%d:%dx%d]", li,

mini2440_lcd_cfg[li].width,

mini2440_lcd_cfg[li].height);

else

printk(" %d:%dx%d", li,

mini2440_lcd_cfg[li].width,

mini2440_lcd_cfg[li].height);

printk("\n");

s3c24xx_fb_set_platdata(&mini2440_fb_info);

}

s3c24xx_udc_set_platdata(&mini2440_udc_cfg);

s3c24xx_mci_set_platdata(&mini2440_mmc_cfg);

s3c_nand_set_platdata(&mini2440_nand_info);

s3c_i2c0_set_platdata(NULL);

i2c_register_board_info(0, mini2440_i2c_devs,

ARRAY_SIZE(mini2440_i2c_devs));

platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));

if (features.count) /* the optional features */

platform_add_devices(features.optional, features.count);

}

那么成员函数init_machine什么时候被调用呢?

在函数setup_machine()中有一条语句init_machine = mdesc->init_machine;其中init_machine为全局函数指针变量,此变量在函数customize_machine()中被调用,代码如下所示:

[cpp] view
plaincopy

static int __init customize_machine(void)

{

/* customizes platform devices, or adds new ones */

if (init_machine)

init_machine();

return 0;

}

arch_initcall(customize_machine);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: