当前位置:网站首页>LCD驱动端与设备端名称匹配过程分析(Tiny4412)
LCD驱动端与设备端名称匹配过程分析(Tiny4412)
2022-08-10 11:07:00 【51CTO】
LCD驱动端与设备端名称匹配过程
在tiny4412提供的内核下,LCD屏的平台设备名字和平台驱动名字不匹配也能驱动屏点亮,
这是怎么回事的呢?下面我们来分析这是如何实现的。
- 硬件平台
Cpu:exynos4412
板子:tiny4412
Linux内核:linux-3.5
21.6.1 lcd平台驱动层相关代码构架
Lcd平台驱动层在S3c-fb.c (linux-3.5\drivers\video)中实现。
21.6.2 s3c_fb_driver平台驱动结构变量
平台驱动结构变量如下:
static struct platform_driver s3c_fb_driver = { .probe= s3c_fb_probe, .remove= __devexit_p(s3c_fb_remove), .id_table= s3c_fb_driver_ids, .driver= { .name= "s3c-fb", .owner= THIS_MODULE, .pm= &s3cfb_pm_ops, }, }; |
驱动层的平台驱动结构实现了id_table,按常理就会根据这个id_table去匹配。
平台驱动结构原型如下:
struct platform_driver { int (*probe)(struct platform_device *); int (*remove)(struct platform_device *); void (*shutdown)(struct platform_device *); int (*suspend)(struct platform_device *, pm_message_t state); int (*resume)(struct platform_device *); struct device_driver driver; const struct platform_device_id *id_table; }; |
21.6.3 platform_device_id结构变量
先给出platform_device_id结构原型如下:
struct platform_device_id { char name[PLATFORM_NAME_SIZE]; kernel_ulong_t driver_data __attribute__((aligned(sizeof(kernel_ulong_t)))); }; |
name数组:用于存放设备的名字,也就是用来和平台设备结构匹配的依据。
driver_data :类型实际上是 unsigned long;
由驱动编写者决定这个整数的用途;
一般是传入一个结构体变量的地址。
内核中定义kernel_ulong_t如下:
typedef unsigned long kernel_ulong_t; |
那么我们就查看s3c_fb_driver_ids,SI跳转进去发现s3c_fb_driver_ids是一个结构数组。定义了许多这个内核支持的cpu的lcd控制器驱动。
代码如下:
static struct platform_device_id s3c_fb_driver_ids[] = { { .name= "s3c-fb", .driver_data= (unsigned long)&s3c_fb_data_64xx,//arm11 }, { .name= "s5pc100-fb", .driver_data= (unsigned long)&s3c_fb_data_s5pc100,//A8 }, { .name= "s5pv210-fb", .driver_data= (unsigned long)&s3c_fb_data_s5pv210,//A8 }, { .name= "exynos4-fb",//A9,这个就是tiny4412配套的lcd屏 .driver_data= (unsigned long)&s3c_fb_data_exynos4, }, { .name= "exynos5-fb", .driver_data= (unsigned long)&s3c_fb_data_exynos5, }, { .name= "s3c2443-fb", .driver_data= (unsigned long)&s3c_fb_data_s3c2443, }, { .name= "s5p64x0-fb", .driver_data= (unsigned long)&s3c_fb_data_s5p64x0, }, {}, }; |
按常理来说,lcd屏的设备层会来跟上面的id_table数组进行匹配,匹配成就会获取相应的.driver_data结构数据。
在tiny4412板子上,lcd平台设备端的name应该是"exynos4-fb"才会成功匹配。
21.6.4 lcd平台设备层相关代码构架
Tiny4412 开发板所带内核源码中已经集成了 LCD 驱动的平台设备层代码;
21.6.5内核启动阶段,板级相关设备驱动初始化结构
内核在启动阶段把平台设备注册进内核,这段代码实现在:
Mach-tiny4412.c (linux-3.5\arch\arm\mach-exynos)文件中。
在文件最后有如下代码段:
MACHINE_START(TINY4412, "TINY4412") /* Maintainer: FriendlyARM (www.arm9.net) */ /* Maintainer: Kukjin Kim <[email protected]> */ /* Maintainer: Changhwan Youn <[email protected]> */ .atag_offset= 0x100, .init_irq= exynos4_init_irq, .map_io= smdk4x12_map_io, .handle_irq= gic_handle_irq, .init_machine= smdk4x12_machine_init, .init_late= exynos_init_late, .timer= &exynos4_timer, .restart= exynos4_restart, .reserve= &smdk4x12_reserve, MACHINE_END |
代码中给 .init_machine 指针赋值 smdk4x12_machine_init;
.init_machine 指针指向的函数在系统启动前期就会被运行,板级相关设备驱动初始化、注册一般都是写在这个函数中,平台设备注册一般就是在此函数中编写。
那么接下来找到 smdk4x12_machine_init 函数实现,然后再寻找和平台设备注册相关的代码进行分析。
21.6.6 smdk4x12_machine_init函数实现
smdk4x12_machine_init函数实现代码如下:
static void __initsmdk4x12_machine_init(void) { #ifdef CONFIG_S3C64XX_DEV_SPI0 spi_register_board_info(spi0_board_info, ARRAY_SIZE(spi0_board_info)); #endif #ifdef CONFIG_S3C64XX_DEV_SPI1 spi_register_board_info(spi1_board_info, ARRAY_SIZE(spi1_board_info)); #endif #ifdef CONFIG_S3C64XX_DEV_SPI2 spi_register_board_info(spi2_board_info, ARRAY_SIZE(spi2_board_info)); #endif s3c_i2c0_set_platdata(NULL); if (samsung_pack() == EXYNOS4412_PACK_SCP) #ifdef CONFIG_REGULATOR_S5M8767 i2c_register_board_info(0, smdk4x12_i2c_devs0_s5m8767, ARRAY_SIZE(smdk4x12_i2c_devs0_s5m8767)); #endif else { #ifdef CONFIG_REGULATOR_MAX77686 max77686_populate_pdata(); i2c_register_board_info(0, smdk4x12_i2c_devs0_max77686, ARRAY_SIZE(smdk4x12_i2c_devs0_max77686)); #endif } s3c_i2c1_set_platdata(NULL); i2c_register_board_info(1, smdk4x12_i2c_devs1, ARRAY_SIZE(smdk4x12_i2c_devs1)); s3c_i2c2_set_platdata(NULL); i2c_register_board_info(2, smdk4x12_i2c_devs2, ARRAY_SIZE(smdk4x12_i2c_devs2)); s3c_i2c3_set_platdata(NULL); i2c_register_board_info(3, smdk4x12_i2c_devs3, ARRAY_SIZE(smdk4x12_i2c_devs3)); s3c_i2c4_set_platdata(NULL); smdk4x12_rtc_wake_init(); smdk4x12_pmu_wdt_init(); smdk4x12_touch_init(); s3c_i2c7_set_platdata(NULL); i2c_register_board_info(7, smdk4x12_i2c_devs7, ARRAY_SIZE(smdk4x12_i2c_devs7)); s3c_hsotg_set_platdata(&smdk4x12_hsotg_pdata); #ifdef CONFIG_USB_EXYNOS_SWITCH smdk4x12_usbswitch_init(); #endif samsung_bl_set(&smdk4x12_bl_gpio_info, &smdk4x12_bl_data); s5p_fimd0_set_platdata(&smdk4x12_lcd0_pdata);//设置私有数据 #ifdef CONFIG_LCD_LMS501KF03 spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); #endif samsung_keypad_set_platdata(&smdk4x12_keypad_data); #ifdef CONFIG_EXYNOS4_DEV_DWMCI exynos_dwmci_set_platdata(&exynos_dwmci_pdata); #endif s3c_sdhci2_set_platdata(&smdk4x12_hsmmc2_pdata); s3c_sdhci3_set_platdata(&smdk4x12_hsmmc3_pdata); #ifdef CONFIG_ION_EXYNOS exynos_ion_set_platdata(); #endif s5p_tv_setup(); s5p_i2c_hdmiphy_set_platdata(NULL); s5p_hdmi_set_platdata(smdk4x12_i2c_hdmiphy, NULL, 0); #ifdef CONFIG_VIDEO_EXYNOS_FIMG2D s5p_fimg2d_set_platdata(&fimg2d_data); #endif #if defined(CONFIG_VIDEO_M5MOLS) || defined(CONFIG_VIDEO_S5K6A3) smdk4x12_camera_init(); #endif #ifdef CONFIG_VIDEO_EXYNOS_FIMC_LITE smdk4x12_set_camera_flite_platdata(); s3c_set_platdata(&exynos_flite0_default_data, sizeof(exynos_flite0_default_data), &exynos_device_flite0); s3c_set_platdata(&exynos_flite1_default_data, sizeof(exynos_flite1_default_data), &exynos_device_flite1); #endif smdk4x12_ehci_init(); #ifdef CONFIG_S3C64XX_DEV_SPI0 s3c64xx_spi0_set_platdata(NULL, 0, 1); #endif #ifdef CONFIG_S3C64XX_DEV_SPI1 s3c64xx_spi1_set_platdata(NULL, 0, 1); #endif #ifdef CONFIG_S3C64XX_DEV_SPI2 s3c64xx_spi2_set_platdata(NULL, 0, 1); #endif smdk4x12_ohci_init(); /* 注册多个平台设备 */ platform_add_devices(smdk4x12_devices, ARRAY_SIZE(smdk4x12_devices)); #ifdef CONFIG_VIDEO_EXYNOS_FIMC_IS exynos4_fimc_is_set_platdata(NULL); #endif if (soc_is_exynos4412()) { if ((samsung_rev() >= EXYNOS4412_REV_2_0)) initialize_prime_clocks(); else initialize_non_prime_clocks(); } #ifdef CONFIG_BUSFREQ_OPP dev_add(&busfreq, &exynos4_busfreq.dev); ppmu_init(&exynos_ppmu[PPMU_DMC0], &exynos4_busfreq.dev); ppmu_init(&exynos_ppmu[PPMU_DMC1], &exynos4_busfreq.dev); ppmu_init(&exynos_ppmu[PPMU_CPU], &exynos4_busfreq.dev); #endif set_tmu_platdata(); } |
在上面函数中会调用平台设备注册函数,如下:
/* 注册多个平台设备 */ platform_add_devices(smdk4x12_devices, ARRAY_SIZE(smdk4x12_devices)); |
其中参数smdk4x12_devices就是注册的平台设备结构数组指针;
21.6.7 smdk4x12_devices平台设备结构数组
SI跳转查看smdk4x12_devices结构,代码段如下:
/* 多平台设备结构变量指针 */ static struct platform_device *smdk4x12_devices[] __initdata = { #ifdef CONFIG_EXYNOS4_DEV_DWMCI &exynos_device_dwmci, #endif &s3c_device_hsmmc2, &s3c_device_hsmmc3, &wm8994_fixed_voltage0, &wm8994_fixed_voltage1, &wm8994_fixed_voltage2, &s3c_device_i2c0, &s3c_device_i2c1, &s3c_device_i2c2, &s3c_device_i2c3, #ifdef CONFIG_VIDEO_M5MOLS &s3c_device_i2c4, #endif &s3c_device_i2c7, &s3c_device_adc, &s3c_device_rtc, &s3c_device_wdt, #ifdef CONFIG_TINY4412_BUZZER &s3c_device_timer[0], #endif #ifdef CONFIG_VIDEO_EXYNOS_FIMC_LITE &exynos_device_flite0, &exynos_device_flite1, #endif &s5p_device_mipi_csis0, &s5p_device_mipi_csis1, &s5p_device_fimc0, &s5p_device_fimc1, &s5p_device_fimc2, &s5p_device_fimc3, &s5p_device_fimc_md, &s5p_device_fimd0,//把LCD平台设备结构填充进来 &mali_gpu_device, &s5p_device_mfc, &s5p_device_mfc_l, &s5p_device_mfc_r, &s5p_device_jpeg, #ifdef CONFIG_SAMSUNG_DEV_KEYPAD &samsung_device_keypad, #endif &tiny4412_device_1wire, &tiny4412_device_adc, #ifdef CONFIG_INPUT_GPIO &tiny4412_input_device, #endif #ifdef CONFIG_IR_GPIO_CIR &tiny4412_device_gpiorc, #endif #ifdef CONFIG_VIDEO_EXYNOS_FIMC_IS &exynos4_device_fimc_is, #endif #ifdef CONFIG_LCD_LMS501KF03 &s3c_device_spi_gpio, #endif #ifdef CONFIG_S3C64XX_DEV_SPI0 &s3c64xx_device_spi0, #endif #ifdef CONFIG_S3C64XX_DEV_SPI1 &s3c64xx_device_spi1, #endif #ifdef CONFIG_S3C64XX_DEV_SPI2 &s3c64xx_device_spi2, #endif #ifdef CONFIG_ION_EXYNOS &exynos_device_ion, #endif &s5p_device_i2c_hdmiphy, &s5p_device_hdmi, &s5p_device_mixer, &exynos4_bus_devfreq, &samsung_asoc_dma, &samsung_asoc_idma, #ifdef CONFIG_SND_SAMSUNG_I2S &exynos4_device_i2s0, #endif #ifdef CONFIG_SND_SAMSUNG_PCM &exynos4_device_pcm0, #endif #ifdef CONFIG_SND_SAMSUNG_SPDIF &exynos4_device_spdif, #endif &tiny4412_audio, #ifdef CONFIG_VIDEO_EXYNOS_FIMG2D &s5p_device_fimg2d, #endif #ifdef CONFIG_EXYNOS_THERMAL &exynos_device_tmu, #endif &s5p_device_ehci, &exynos4_device_ohci, &s5p_device_usbswitch, #if defined CONFIG_SND_SAMSUNG_ALP &exynos_device_srp, #endif #ifdef CONFIG_BUSFREQ_OPP &exynos4_busfreq, #endif #ifdef CONFIG_BATTERY_SAMSUNG &samsung_device_battery, #endif }; |
可以发现,这个数组中存放了很多平台设备结构的地址,其中的 &s5p_device_fimd0 就是 LCD 平台设备结构。
21.6.8 Lcd平台设备结构变量s5p_device_fimd0
s5p_device_fimd0结构定义如下:
/* LCD平台设备结构 */ struct platform_device s5p_device_fimd0 = { .name= "s5p-fb", .id= 0, .num_resources= ARRAY_SIZE(s5p_fimd0_resource), .resource= s5p_fimd0_resource, .dev= { .dma_mask= &samsung_device_dma_mask, .coherent_dma_mask= DMA_BIT_MASK(32), //在这里没有填充lcd的平台数据??? }, }; |
前面分析出,我们要注册的LCD平台设备name成员应该是"exynos4-fb",但是上边lcd平台设备结构name成员并不是 "exynos4-fb"。
到此,新的问题出现,那它们是怎么匹配的呢?
要坚信:平台设备驱动层和平台设备层匹配一定是通过 name 成员进行匹配的。
所以,一定是系统在注册平台设备或注册平台驱动前,某一个地方做了修改:
修改平台设备层中的 name 成员为"exynos4-fb",
或者修改了平台驱动层中的 id_table中的 name 成员为 " s5p-fb"。
至于是哪种情况,可以自己一个一种去推,不过一般情况都是修改设备层 name。
理论论证:可变的都写在设备层,而驱动层一般是相对稳定的;
所以,修改的地方就是在内核源码中搜索"exynos4-fb"字符串出现的地方。
21.6.9 修改lcd设备层name的逆向分析
经过上面的分析,接下来我们搜索内核源码出现”exynos4-fb”地方。
(1)搜索调用”exynos4-fb”的地方
搜索出来可能有多个,要懂得过滤选择,根据文件名、文件所在路径以及使用场合;
我们可以确定是以下文件:
Common.c (arch\arm\mach-exynos):
static void __init exynos4_map_io(void) { iotable_init(exynos4_iodesc, ARRAY_SIZE(exynos4_iodesc)); if (soc_is_exynos4210() && samsung_rev() == EXYNOS4210_REV_0) iotable_init(exynos4_iodesc0, ARRAY_SIZE(exynos4_iodesc0)); else iotable_init(exynos4_iodesc1, ARRAY_SIZE(exynos4_iodesc1)); if (soc_is_exynos4412()) iotable_init(exynos4412_iodesc, ARRAY_SIZE(exynos4412_iodesc)); else iotable_init(exynos4xxx_iodesc, ARRAY_SIZE(exynos4xxx_iodesc)); exynos4_default_sdhci0(); exynos4_default_sdhci1(); exynos4_default_sdhci2(); exynos4_default_sdhci3(); s3c_adc_setname("samsung-adc-v3"); s3c_fimc_setname(0, "exynos4-fimc"); s3c_fimc_setname(1, "exynos4-fimc"); s3c_fimc_setname(2, "exynos4-fimc"); s3c_fimc_setname(3, "exynos4-fimc"); s3c_sdhci_setname(0, "exynos4-sdhci"); s3c_sdhci_setname(1, "exynos4-sdhci"); s3c_sdhci_setname(2, "exynos4-sdhci"); s3c_sdhci_setname(3, "exynos4-sdhci"); s3c_i2c0_setname("s3c2440-i2c"); s3c_i2c1_setname("s3c2440-i2c"); s3c_i2c2_setname("s3c2440-i2c"); s5p_fb_setname(0, "exynos4-fb"); s5p_hdmi_setname("exynos4-hdmi"); } |
我们就知道s5p_fb_setname调用了"exynos4-fb"。
我可以找到函数s5p_fb_setname原型:
static inline void s5p_fb_setname(int id, char *name) { switch (id) { #ifdef CONFIG_S5P_DEV_FIMD0 case 0: s5p_device_fimd0.name = name; break; #endif default: printk(KERN_ERR "%s: invalid device id(%d)\n", __func__, id); break; } } |
从这个函数知道,调用s5p_fb_setname(0, "exynos4-fb");
就执行case 0 :s5p_device_fimd0.name = name;把name(就是"exynos4-fb")设置进s5p_device_fimd0.name(lcd设备结构的name)。
到此,我们需要知道反推来知道是何处调用了exynos4_map_io这个函数。
(2) 何处调用exynos4_map_io函数
该函数是用static修饰的,肯定在本文件中,所以就在本文件搜索。
结果我们发现这个函数没有被调用,而是把它初始化给一个函数指针cpu_ids。
找到如下cpu_ids结构,代码如下:
static struct cpu_table cpu_ids[]__initdata = { { .idcode= EXYNOS4210_CPU_ID, .idmask= EXYNOS4_CPU_MASK, .map_io= exynos4_map_io, .init_clocks= exynos4_init_clocks, .init_uarts= exynos_init_uarts, .init= exynos_init, .name= name_exynos4210, }, { .idcode= EXYNOS4212_CPU_ID, .idmask= EXYNOS4_CPU_MASK, .map_io= exynos4_map_io, .init_clocks= exynos4_init_clocks, .init_uarts= exynos_init_uarts, .init= exynos_init, .name= name_exynos4212,//明显是我们所使用的板子 }, { .idcode= EXYNOS4412_CPU_ID, .idmask= EXYNOS4_CPU_MASK, .map_io= exynos4_map_io, .init_clocks= exynos4_init_clocks, .init_uarts= exynos_init_uarts, .init= exynos_init, .name= name_exynos4412, }, { .idcode= EXYNOS5250_SOC_ID, .idmask= EXYNOS5_SOC_MASK, .map_io= exynos5_map_io, .init_clocks= exynos5_init_clocks, .init_uarts= exynos_init_uarts, .init= exynos_init, .name= name_exynos5250, }, }; |
到此,我们就需要知道何处调用了cpu_ids结构?
在哪里才回调用.map_io指向的exynos4_map_io函数?
(3)何处调用了 cpu_ids结构
该结构也是static修饰,只会在本文件被调用。
找到如下调用代码:
void __init exynos_init_io(struct map_desc *mach_desc, int size) { /* initialize the io descriptors we need for initialization */ iotable_init(exynos_iodesc, ARRAY_SIZE(exynos_iodesc)); if (mach_desc) iotable_init(mach_desc, size); /* detect cpu id and rev. */ s5p_init_cpu(S5P_VA_CHIPID); s3c_init_cpu(samsung_cpu_id, cpu_ids, ARRAY_SIZE(cpu_ids)); } |
可以知道,在exynos_init_io函数中调用用了s3c_init_cpu函数,把cpu_ids作为参数给s3c_init_cpu函数使用。
(4)分析s3c_init_cpu函数
接下来分析一下s3c_init_cpu函数是否使用到了cpu_ids元素中的map_io成员;
因为这个map_io成员指向exynos4_map_io;
而exynos4_map_io函数就是实现修改了name的地方。
s3c_init_cpu函数原型:
这个函数定义在Init.c (linux-3.5\arch\arm\plat-samsung)文件下。
void __init s3c_init_cpu(unsigned long idcode, struct cpu_table *cputab, unsigned int cputab_size) { //从uputab找出和idcode相同的struct cpu_table成员指针 cpu = s3c_lookup_cpu(idcode, cputab, cputab_size); if (cpu == NULL) { printk(KERN_ERR "Unknown CPU type 0x%08lx\n", idcode); panic("Unknown S3C24XX CPU"); } printk("CPU %s (id 0x%08lx)\n", cpu->name, idcode); if (cpu->map_io == NULL || cpu->init == NULL) { printk(KERN_ERR "CPU %s support not enabled\n", cpu->name); panic("Unsupported Samsung CPU"); } cpu->map_io(); } |
我们来仔细的分许这个函数:
第一条代码:
cpu = s3c_lookup_cpu(idcode, cputab, cputab_size);
参数:
idcode就是s3c_init_cpu函数传入samsung_cpu_id;
cputab就是s3c_init_cpu函数传入cpu_ids;
cputab_size就是s3c_init_cpu函数传入ARRAY_SIZE(cpu_ids);
功能:
cputab 结构有一个 idcode成员,该函数就是找出cputab[X]->idcode和传入的idcode相同的cputab 结构数组元素指针。
返回:找到的结构cputab 结构数组元素指针存放在cpu变量中。
那么调用s3c_lookup_cpu函数就找到cpu_ids[]结构中idcode和samsung_cpu_id相同的的数组元素指针,存放到cpu变量。
s3c_lookup_cpu函数原型:
static struct cpu_table *__init s3c_lookup_cpu(unsigned long idcode, struct cpu_table *tab, unsigned int count) { for (; count != 0; count--, tab++) { if ((idcode & tab->idmask) == (tab->idcode & tab->idmask)) return tab; } return NULL; } |
最后一条代码:
cpu->map_io();
我们知道,这条代码执行cpu指向的(cpu_ids[]数组元素)的成员map_io函数指针指向的函数;就是前面的指向exynos4_map_io()函数。
而exynos4_map_io函数又调用了s5p_fb_setname(0, "exynos4-fb")来修改平台设备层 name 成员。
所以,此时已经可以打通 s5p_fb_setname(0,"exynos4-fb")的调用流程。
21.6.10何处调用了 exynos_init_io函数
搜索 exynos_init_io 函数的地方。
这个函数不再是 static 了,所以查的的目标不再是本文件内,而是整个源码。
搜索结果如下:
---- exynos_init_io Matches (11 in 11 files) ---- Common.c (linux-3.5\arch\arm\mach-exynos):void __init exynos_init_io(struct map_desc *mach_desc, int size) Common.h (linux-3.5\arch\arm\mach-exynos):void exynos_init_io(struct map_desc *mach_desc, int size); Mach-armlex4210.c (linux-3.5\arch\arm\mach-exynos):exynos_init_io(NULL, 0); Mach-exynos4-dt.c (linux-3.5\arch\arm\mach-exynos):exynos_init_io(NULL, 0); Mach-exynos5-dt.c (linux-3.5\arch\arm\mach-exynos):exynos_init_io(NULL, 0); Mach-nuri.c (linux-3.5\arch\arm\mach-exynos):exynos_init_io(NULL, 0); Mach-origen.c (linux-3.5\arch\arm\mach-exynos):exynos_init_io(NULL, 0); Mach-smdk4x12.c (linux-3.5\arch\arm\mach-exynos):exynos_init_io(NULL, 0); Mach-smdkv310.c (linux-3.5\arch\arm\mach-exynos):exynos_init_io(NULL, 0); Mach-tiny4412.c (linux-3.5\arch\arm\mach-exynos):exynos_init_io(NULL, 0); Mach-universal_c210.c (linux-3.5\arch\arm\mach-exynos):exynos_init_io(NULL, 0); |
我们知道就是板级文件 Mach-tiny4412.c。
调用exynos_init_io的地方,代码如下:
static void __init smdk4x12_map_io(void) { clk_xusbxti.rate = 24000000; exynos_init_io(NULL, 0); s3c24xx_init_clocks(clk_xusbxti.rate); s3c24xx_init_uarts(smdk4x12_uartcfgs, ARRAY_SIZE(smdk4x12_uartcfgs)); } |
那么又是何处调用了smdk4x12_map_io函数?
21.6.11 何处调用smdk4x12_map_io函数
注意smdk4x12_map_io前面的 static,在本文件搜索。
找到调用出如下:
MACHINE_START(TINY4412, "TINY4412") /* Maintainer: FriendlyARM (www.arm9.net) */ /* Maintainer: Kukjin Kim <[email protected]> */ /* Maintainer: Changhwan Youn <[email protected]> */ .atag_offset= 0x100, .init_irq= exynos4_init_irq, .map_io= smdk4x12_map_io, .handle_irq= gic_handle_irq, .init_machine= smdk4x12_machine_init, .init_late= exynos_init_late, .timer= &exynos4_timer, .restart= exynos4_restart, .reserve= &smdk4x12_reserve, MACHINE_END |
MACHINE_START和MACHINE_END的函数指针在系统启动时,会被自动执行,所以就会修改了lcd设备结构的name成员。
原来在这里调用,看到了没有是在平台设备注册之前执行的哦。
边栏推荐
猜你喜欢
What is an abstract class
3 injured in 'electrical accident' at Google data center
Gold, nine, silver and ten job-hopping seasons: technical interview questions and answers on Alibaba, Baidu, JD.com, and Meituan
How to join We Media, learn about these 5 monetization modes, and make your account quickly monetize
Intel pushes 20220809 CPU microcode update to patch Intel-SA-00657 security vulnerability
电脑怎么设置屏幕息屏时间(日常使用分享)
振弦传感器及核心VM系列振弦采集模块
模块九 - 设计电商秒杀系统
快手“弃”有赞与微盟“结亲”,电商SaaS行业竞争格局将变?
Alibaba最新神作!耗时182天肝出来1015页分布式全栈手册太香了
随机推荐
WeChat applet, global variables change in one place and the state in other places also changes.
第二十二章 源代码文件 REST API 参考(四)
怎么加入自媒体,了解这5种变现模式,让账号快速变现
阻塞 非阻塞 poll机制 异步
【电商运营】你真的了解社交媒体营销(SMM)吗?
3 injured in 'electrical accident' at Google data center
Clicking Exercise - 64 Longest Harmonic Subsequences
CodeChef STMRRG String Merging (dp)
leetcode 823. Binary Trees With Factors(因子二叉树)
不止跑路,拯救误操作rm -rf /*的小伙儿
基于UiAutomator2+PageObject模式开展APP自动化测试实战
[Brave food, not afraid to write the linked list] The problem of the penultimate node of the linked list
ISO9001在讲什么?过程方法和风险思维
Interviewer: How are Dao, Service, Controller, Util, and Model divided in the project?
不止跑路,拯救误操作rm -rf /*的小伙儿
接口定义与实现
Gold, nine, silver and ten job-hopping seasons: technical interview questions and answers on Alibaba, Baidu, JD.com, and Meituan
ENVI 5.3软件安装包和安装教程
Codeforces 862 C. Mahmoud and Ehab and the xor (技巧)
2022年裁员潮,失业程序员何去何从?