29EXPORT_SYMBOL_GPL(platform_bus); 621int __init platform_bus_init(void)
622{
623 int error;
624
625 error = device_register(&platform_bus);
626 if (error)
627 return error;
628 error = bus_register(&platform_bus_type);
629 if (error)
630 device_unregister(&platform_bus);
631 return error;
632}
该函数创建了一个名为 “platform”的设备,后续platform的设备都会以此为parent。在sysfs中表示为:所有platform类型的设备都会添加在 platform_bus所代表的目录下,即 /sys/devices/platform下面。
-sh-3.1# ls /sys/devices/platform/
Fixed MDIO bus.0 fsl-i2c.0 serial8250
fsl-ehci.0 fsl-i2c.1 serial8250.0
fsl-gianfar.0 mpc83xx_spi.0 uevent
fsl-gianfar.1 mpc83xx_wdt.0
fsl-gianfar_mdio.-5 power
-sh-3.1# ls /sys/
block/ class/ firmware/ kernel/ power/
bus/ devices/ fs/ module/
-sh-3.1# ls /sys/bus/
i2c/ of_platform/ pci_express/ scsi/ usb/
mdio_bus/ pci/ platform/ spi/
-sh-3.1# ls /sys/bus/i2c/
devices/ drivers_autoprobe uevent
drivers/ drivers_probe
-sh-3.1# ls /sys/bus/platform/devices/
Fixed MDIO bus.0/ fsl-gianfar_mdio.-5/ mpc83xx_wdt.0/
fsl-ehci.0/ fsl-i2c.0/ serial8250/
fsl-gianfar.0/ fsl-i2c.1/ serial8250.0/
fsl-gianfar.1/ mpc83xx_spi.0/
-sh-3.1# ls /sys/bus/platform/drivers
drivers/ drivers_autoprobe drivers_probe
-sh-3.1# ls /sys/bus/platform/drivers/
fsl-ehci/ fsl-gianfar_mdio/ mpc83xx_spi/ serial8250/
fsl-gianfar/ fsl-i2c/ mpc83xx_wdt/
platform_bus必须在系统注册任何platform driver和platform device之前初始化,那么这是如何实现的呢?
http://lxr.linux.no/#linux+v2.6.25/drivers/base/init.c
14
20void __init driver_init(void)
21{
22
23 devices_init();
24 buses_init();
25 classes_init();
26 firmware_init();
27 hypervisor_init();
28
29
32 platform_bus_init();
33 system_bus_init();
34 cpu_dev_init();
35 memory_dev_init();
36}
init/main.c
start_kernel 》 rest_init 》 kernel_init 》 do_basic_setup》driver_init 》platform_bus_init
http://lxr.linux.no/#linux+v2.6.25/drivers/base/init.c#L32
724
731static void __init do_basic_setup(void)
732{
733
734 init_workqueues();
735 usermodehelper_init();
736 driver_init();
737 init_irq_proc();
738 do_initcalls();
739}
platform driver和platform device的初始化是在do_initcalls中进行的。
8.2 定义platform_device
http://lxr.linux.no/#linux+v2.6.25/arch/arm/plat-s3c24xx/devs.c#L276中定义了系统的资源,是一个高度可移植的文件,大部分板级资源都在这里集中定义。
274
275
276static struct resource s3c_i2c_resource[] = {
277 [0] = {
278 .start = S3C24XX_PA_IIC,
279 .end = S3C24XX_PA_IIC + S3C24XX_SZ_IIC - 1,
280 .flags = IORESOURCE_MEM,
281 },
282 [1] = {
283 .start = IRQ_IIC,
284 .end = IRQ_IIC,
285 .flags = IORESOURCE_IRQ,
286 }
287
288};
289
290struct platform_device s3c_device_i2c = {
291 .name = "s3c2410-i2c",
292 .id = -1,
293 .num_resources = ARRAY_SIZE(s3c_i2c_resource),
294 .resource = s3c_i2c_resource,
295};
296
297EXPORT_SYMBOL(s3c_device_i2c);
设备名称为s3c2410-i2c,“-1”只有一个i2c设备,两个资源s3c_i2c_resource,分别为i2c控制器的寄存器空间和中断信息。
8.3 注册platform_device
定义了platform_device后,需要添加到系统中,就可以调用函数platform_add_devices。
http://lxr.linux.no/#linux+v2.6.25/arch/arm/mach-s3c2440/mach-smdk2440.c
smdk2440_devices将系统资源组织起来,统一注册进内核。
151static struct platform_device *smdk2440_devices[] __initdata = {
152 &s3c_device_usb,
153 &s3c_device_lcd,
154 &s3c_device_wdt,
155 &s3c_device_i2c,
156 &s3c_device_iis,
157};
166static void __init smdk2440_machine_init(void)
167{
168 s3c24xx_fb_set_platdata(&smdk2440_fb_info);
169
170 platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));
171 smdk_machine_init();
172}
173
174MACHINE_START(S3C2440, "SMDK2440")
175
176 .phys_io = S3C2410_PA_UART,
177 .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
178 .boot_params = S3C2410_SDRAM_PA + 0x100,
179
180 .init_irq = s3c24xx_init_irq,
181 .map_io = smdk2440_map_io,
182 .init_machine = smdk2440_machine_init,
183 .timer = &s3c24xx_timer,
184MACHINE_END
170 platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));
将系统所有资源注册进系统,在此之前platform bus需要初始化成功,否则无法将platform devices挂接到platform bus上。为了保证platform drive初始化时,相关platform资源已经注册进系统,smdk2440_machine_init需要很早执行,而其作为平台初始化init_machine 时,将优先于系统所有驱动的初始化。
其调用顺序如下:
start_kernel》setup_arch》init_machine》arch_initcall(customize_machine)
http://lxr.linux.no/#linux+v2.6.25/arch/arm/kernel/setup.c#L788
786arch_initcall(customize_machine);
787
788void __init setup_arch(char **cmdline_p)
789{
790 struct tag *tags = (struct tag *)&init_tags;
791 struct machine_desc *mdesc;
792 char *from = default_command_line;
793
794 setup_processor();
795 mdesc = setup_machine(machine_arch_type);
//根据machine id获得移植时定义的machine desc结构
796 machine_name = mdesc->name;
797
798 if (mdesc->soft_reboot)
799 reboot_setup("s");
800
801 if (__atags_pointer)
802 tags = phys_to_virt(__atags_pointer);
803 else if (mdesc->boot_params)
804 tags = phys_to_virt(mdesc->boot_params);
805
806
810 if (tags->hdr.tag != ATAG_CORE)
811 convert_to_tag_list(tags);
812 if (tags->hdr.tag != ATAG_CORE)
813 tags = (struct tag *)&init_tags;
814
815 if (mdesc->fixup)
816 mdesc->fixup(mdesc, tags, &from, &meminfo);
817
818 if (tags->hdr.tag == ATAG_CORE) {
819