nano-pc-t1 4412 显示驱动分析
1. 和其它內核代碼類似。
???? 顯示驅動的分析都是由 drivers/video/fbmem.c開始,fbmem.c是顯示驅動的抽象,實際只是一個框架性的東西。
???? fbmem_init 中實現了一個字符設備驅動,并創建了class,但是沒有生成設備文件。
??? 這個字符設備驅動的file_operations里面的函數,實質上都是從struct fb_info *registered_fb[FB_MAX] ? 這個
??? fb_info的結構體數組中去調用 fb_ops 這個結構體中函數指針。數組下標為次設備號。那么這個結構體是如何賦值的
???? 呢?
??? fbmem.c里定義 register_framebuffer這個函數。真正的顯示設備都是調用這個函數來給registered_fb這個數組賦值,
?? 然后再去創建設備文件。
2.? 我們搜索register_framebuffer這個文件,有如下幾處:
???? drivers/gpu/drm/drm_fb_helper.c
???? drivers/video/s3c-fb.c
3. 我們先來看看s3c-fb.c
??? 這個文件注冊了一個平臺總線設備驅動程序,在其probe函數中調用 register_framebuffer。
??? 那么這個驅動的probe的函數什么時候調用呢?
??? 接下來我們看一下內核中實現平臺總線驅動代碼,注意,平臺總線驅動是內核實現的。
4. drivers/base/platform.c
??? 主要看platform_match這個函數,也就是平臺總線設備驅動和平臺總線設備是如何匹配的,知道了匹配規則,我們
??? 就知道如何去需找對應的平臺設備了。
??? 先看這句話
??? if (pdrv->id_table)
?? ??? ?return platform_match_id(pdrv->id_table, pdev) != NULL;
?? return (strcmp(pdev->name, drv->name) == 0);
??? 如何平臺總線設備驅動中有id_table的話,那么調用platform_match_id這個函數。
?? 我們再看一下platform_match_id函數做個什么。
?? while (id->name[0]) {
?? ??? ?if (strcmp(pdev->name, id->name) == 0) {
?? ??? ??? ?pdev->id_entry = id;
?? ??? ??? ?return id;
?? ??? ?}
?? ??? ?id++;
?? ?}
??? 很顯然,就是拿平臺總線設備的name去挨個比較平臺總線設備驅動的id_table,匹配成功測返回id。
??? 如果沒有匹配成功,則再去比較平臺總線設備的名稱和平臺總線驅動的名稱。也就是
???return (strcmp(pdev->name, drv->name) == 0);? 這句。
?? 一旦匹配成功,那么內核會自動調用平臺總線設備驅動的probe函數。
5.? 那么接下來,我們就看看s3c-fb.c這個文件里實現的平臺總線設備驅動程序的name和id_table
??? static struct platform_driver s3c_fb_driver = {
?? ?.probe?? ??? ?= s3c_fb_probe,
?? ?.remove?? ??? ?= s3c_fb_remove,
?? ?.id_table?? ?= s3c_fb_driver_ids,
?? ?.driver?? ??? ?= {
?? ??? ?.name?? ?= "s3c-fb",
?? ??? ?.owner?? ?= THIS_MODULE,
?? ??? ?.pm?? ?= &s3cfb_pm_ops,
?? ?},
};
static struct platform_device_id s3c_fb_driver_ids[] = {
?? ?{
?? ??? ?.name?? ??? ?= "s3c-fb",
?? ??? ?.driver_data?? ?= (unsigned long)&s3c_fb_data_64xx,
?? ?}, {
?? ??? ?.name?? ??? ?= "s5pc100-fb",
?? ??? ?.driver_data?? ?= (unsigned long)&s3c_fb_data_s5pc100,
?? ?}, {
?? ??? ?.name?? ??? ?= "s5pv210-fb",
?? ??? ?.driver_data?? ?= (unsigned long)&s3c_fb_data_s5pv210,
?? ?}, {
?? ??? ?.name?? ??? ?= "exynos4-fb",
?? ??? ?.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,
?? ?},
?? ?{},
};
? 有了第4點的分析,我們可以搜索上面紅字部分來查找對應的平臺總線設備了。
6.? 搜索"s3c-fb",找到了
???arch/arm/plat-samsung/devs.c這個文件
??? 搜索"exynos4-fb",找到了
??? arch/arm/mach-exynos/common.c
????? 其它name,我們應該不用理會,都是其它soc名稱。
?? 在devs.c里定義了
?? struct platform_device s3c_device_fb = {
?? ?.name?? ??? ?= "s3c-fb",
?? ?.id?? ??? ?= -1,
?? ?.num_resources?? ?= ARRAY_SIZE(s3c_fb_resource),
?? ?.resource?? ?= s3c_fb_resource,
?? ?.dev?? ??? ?= {
?? ??? ?.dma_mask?? ??? ?= &samsung_device_dma_mask,
?? ??? ?.coherent_dma_mask?? ?= DMA_BIT_MASK(32),
?? ?},
};?
?? 在common.c里是這句 s5p_fb_setname(0,"exynos4-fb");
?? 展開實際是這樣s5p_device_fimd0.name = name;
?? struct platform_device s5p_device_fimd0 = {
?? ?.name?? ??? ?= "s5p-fb",??? 這塊被改為了 "exynos4-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),
?? ?},
};
??? 從以上分析,實際定義了兩個設備,"s3c-fb","exynos4-fb"。
7. 現在,找到了,平臺總線的設備和驅動后,我們要做的主要事情就是去修改lcd的各種參數,主要是fb_info結構體
??? 的fb_var_screeninfo結構體,這里面記錄了lcd的主要9個參數。
?? 行前肩,行后肩,行同步信號脈寬,幀前肩,幀后肩,幀同步信號脈寬,像素時鐘頻率,x軸像素點,y軸像素點。
??? 分析了s3c_fb.c文件后,發現是這句來賦值,fb_videomode_to_var(&fbinfo->var, &initmode);
??? 經過再次分析后,實際數據是來源于平臺總線設備中,pd = pdev->dev.platform_data;
8.? 那么我們再次回到devs.c這個文件,因為上面兩個平臺總線設備均定義在次文件中。
??? 但是查看s3c_device_fb和s5p_device_fimd0這兩個平臺設備結構體后,沒有發現platform_data。那么一定是后面
?? 專門有賦值的地方。查找后,發現
?? void __init s3c_fb_set_platdata(struct s3c_fb_platdata *pd)
{
?? ?s3c_set_platdata(pd, sizeof(struct s3c_fb_platdata),
?? ??? ??? ? &s3c_device_fb);
}
void __init s5p_fimd0_set_platdata(struct s3c_fb_platdata *pd)
{
?? ?s3c_set_platdata(pd, sizeof(struct s3c_fb_platdata),
?? ??? ??? ? &s5p_device_fimd0);
}
?? 經過搜索發現,s5p_fimd0_set_platdata在 下面文件中調用,
??arch/arm/mach-exynos/mach-nanopc-t1.c
?? arch/arm/mach-exynos/mach-smdk4x12.c? 這個文件應該沒用
???s3c_fb_set_platdata沒有被任何地方調用,那么s3c_device_fb這個設備應該沒有用處,我認為應該去掉。
9. 接下來我們主要分析s5p_device_fimd0這個設備。
??? 在mach-nano-t1.c 這句 兩句
??? nanopc_fb_init_pdata(&nanopc_fb_pdata);
??? s5p_fimd0_set_platdata(&nanopc_fb_pdata);
??? 實際真正的數據是在nanopc_fb_pdata中,并且在nanopc_fb_init_pdata中得到的值。
??? 再看nanopc_fb_init_pdata這個函數,發現以下幾句
??? lcd = tiny4412_get_lcd();
???? mode->left_margin?? ?= lcd->timing.h_bp;
?? ?mode->right_margin?? ?= lcd->timing.h_fp;
?? ?mode->upper_margin?? ?= lcd->timing.v_bp;
?? ?mode->lower_margin?? ?= lcd->timing.v_fp;
?? ?mode->hsync_len?? ??? ?= lcd->timing.h_sw;
?? ?mode->vsync_len?? ??? ?= lcd->timing.v_sw;
?? ?mode->xres?? ??? ??? ?= lcd->width;
?? ?mode->yres?? ??? ??? ?= lcd->height;
??? 數據實際來源于tiny4412_get_lcd()。
??? tiny4412_get_lcd定義在
??? arch/arm/mach-exynos/tiny4412-lcds.c中
???? 到此,我們終于找到各種屏的參數定義,并且還有hdmi參數的定義。
???
??? 待續
???
???
總結
以上是生活随笔為你收集整理的nano-pc-t1 4412 显示驱动分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Ubuntu10.10的网络配置
- 下一篇: D2809次动车撞泥石流脱线 铁路及消防