一、LCD驱动程序架构
1.裸机驱动代码分析
①LCD初始化:控制器初始化,端口初始化,指明帧缓冲
②LCD图形显示:将图形数据写入帧缓冲

1. void lcd_init()
2. 
			{
3. ();     //初始化gpdcon和gpccon初始化
4. ();   //时序初始化和帧缓冲初始化
5. 
6. 
			    //打开LCD电源
7. |= 0b11<<8;
8. |= (1<<3);
9. |= 1;
10. 
			}

2.帧缓冲体验

帧缓冲:内存中的一段区域,通过对内存的修改。LCD控制器从内存中获取数据,自动的控制LCD的显示。

  1. # cat tq2440.bin > /dev/fb0

将图片显示到lcd。


3.帧缓冲架构

/dev/fb0就是帧缓冲,字符设备

fbmem_init():
1. static int __init
2. (void)
3. {
4. ("fb", 0, NULL, &fb_proc_fops);
5. 
6. if (register_chrdev(FB_MAJOR,"fb",&fb_fops))                                                    //注册设备文件,注册帧缓冲,fp_fops是操作函数集
7. ("unable to get major %d for fb devs\n", FB_MAJOR);
8. 
9. = class_create(THIS_MODULE, "graphics");
10. if (IS_ERR(fb_class)) {
11. (KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class));
12. = NULL;
13. }
14. ;
15. }
fb_ops:
1. static const struct file_operations fb_fops = {
2. .owner =    THIS_MODULE,
3. .read =        fb_read,                                        //写入
4. .write =    fb_write,
5. .unlocked_ioctl = fb_ioctl,
6. 
			#ifdef CONFIG_COMPAT
7. .compat_ioctl = fb_compat_ioctl,
8. 
			#endif
9. .mmap =        fb_mmap,
10. .open =        fb_open,
11. .release =    fb_release,
12. 
			#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
13. .get_unmapped_area = get_fb_unmapped_area,
14. 
			#endif
15. 
			#ifdef CONFIG_FB_DEFERRED_IO
16. .fsync =    fb_deferred_io_fsync,
17. 
			#endif
18. };
fb_write:
1. static ssize_t
2. (struct file *file, const char __user *buf, size_t count, loff_t *ppos)
3. {
4. = *ppos;
5. *inode = file->f_path.dentry->d_inode;
6. int fbidx = iminor(inode);
7. *info = registered_fb[fbidx];
8. *buffer, *src;
9. *dst;
10. int c, i, cnt = 0, err = 0;
11. ;
12. 
13. if (!info || !info->screen_base)
14. -ENODEV;
15. 
16. if (info->state != FBINFO_STATE_RUNNING)
17. -EPERM;
18. 
19. if (info->fbops->fb_write)
20. ->fbops->fb_write(info, buf, count, ppos);
21. 
			    
22. = info->screen_size;
23. 
24. if (total_size == 0)
25. = info->fix.smem_len;
26. 
27. if (p > total_size)
28. -EFBIG;
29. 
30. if (count > total_size) {
31. err = -EFBIG;
32. = total_size;
33. }
34. 
35. if (count + p > total_size) {
36. 
			   
		
37.     .........各种info
38. }

info结构:
1. struct fb_info {
2. int node;
3. int flags;
4. ;                                //控制io操作锁
5. ;/*LCD可变参数*/
6. fix;/*LCD固定参数*/
7. ; /*LCD显示器标准*/
8. ; /*帧缓冲事件队列*/
9. ; /*图像硬件mapper*/
10. ; /*光标硬件mapper*/
11. ; /*当前的颜色表*/
12. *mode; /*当前的显示模式*/
13. 
			 
14. 
			#ifdef CONFIG_FB_BACKLIGHT
15. *bl_dev;/*对应的背光设备*/
16. ;
17. [FB_BACKLIGHT_LEVELS];/*背光调整*/
18. 
			#endif
19. 
			#ifdef CONFIG_FB_DEFERRED_IO
20. ;
21. *fbdefio;
22. 
			#endif
23. 
			 
24. *fbops; /*对底层硬件操作的函数指针*/
25. *device;
26. *dev; /*fb设备*/
27. int class_flag; 
28. 
			#ifdef CONFIG_FB_TILEBLITTING
29. *tileops; /*图块Blitting*/
30. 
			#endif
31. *screen_base; /*虚拟基地址*/
32. ; /*LCD IO映射的虚拟内存大小*/
33. *pseudo_palette; /*伪16色颜色表*/
34. 
			#define FBINFO_STATE_RUNNING    0
35. 
			#define FBINFO_STATE_SUSPENDED  1
36. ; /*LCD的挂起或恢复状态*/
37. *fbcon_par;
38. *par; 
39. };
主要是fb_var_screeninfo、fb_fix_screeninfo、fb_ops三个结构体:
struct fb_var_screeninfo:主要记录用户可以修改的控制器的参数。
1. struct fb_var_screeninfo {
2. ;            /* visible resolution        */
3. ;
4. ;        /* virtual resolution        */
5. ;
6. ;            /* offset from virtual to visible */
7. ;            /* resolution            */
8. 
9. ;        /* guess what            */每个像素的位数即BPP
10. ;        /* != 0 Graylevels instead of colors */
11. 
12. ;        /* bitfield in fb mem if true color, */
13. ;    /* else only length is significant */
14. ;
15. ;    /* transparency            */    
16. 
17. ;            /* != 0 Non standard pixel format */
18. 
19. ;            /* see FB_ACTIVATE_*        */
20. 
21. ;            /* height of picture in mm */
22. ;            /* width of picture in mm */
23. 
24. ;        /* (OBSOLETE) see fb_info.flags */
25. 
26. /* Timing: All values in pixclocks, except pixclock (of course) */
27. ;            /* pixel clock in ps (pico seconds) */
28. ;        /* time from sync to picture    */
29. ;        /* time from picture to sync    */
30. ;        /* time from sync to picture    */
31. ;
32. ;        /* length of horizontal sync    */
33. ;        /* length of vertical sync    */
34. ;            /* see FB_SYNC_*        */
35. ;            /* see FB_VMODE_*        */
36. ;            /* angle we rotate counter clockwise */
37. [5];        /* Reserved for future compatibility */
38. };
fb_fix_screeninfo:主要记录用户不可以修改的控制器的参数
1. struct fb_fix_screeninfo {
2. [16];            /* identification string eg "TT Builtin" */
3. ;    /* Start of frame buffer mem */
4. /* (physical address) */
5. ;            /* Length of frame buffer mem */
6. ;            /* see FB_TYPE_*        */
7. ;            /* Interleave for interleaved Planes */
8. ;            /* see FB_VISUAL_*        */ 
9. ;            /* zero if no hardware panning */
10. ;            /* zero if no hardware panning */
11. ;        /* zero if no hardware ywrap */
12. ;        /* length of a line in bytes */
13. ;    /* Start of Memory Mapped I/O */
14. /* (physical address) */
15. ;            /* Length of Memory Mapped I/O */
16. ;            /* Indicate to driver which    */
17. /* specific chip/card we have    */
18. [3];        /* Reserved for future compatibility */
19. };
fb_ops:底层硬件操作的函数指针
1. struct fb_ops {
2. /* open/release and usage marking */
3. *owner;
4. int (*fb_open)(struct fb_info *info, int user);
5. int (*fb_release)(struct fb_info *info, int user);
6. 
7. /* For framebuffers with strange non linear layouts or that do not
8. * work with normal memory mapped access
9. */
10. (*fb_read)(struct fb_info *info, char __user *buf,
11. , loff_t *ppos);
12. (*fb_write)(struct fb_info *info, const char __user *buf,
13. , loff_t *ppos);
14. 
15. /* checks var and eventually tweaks it to something supported,
16. * DO NOT MODIFY PAR */
17. int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);
18. 
19. /* set the video mode according to info->var */
20. int (*fb_set_par)(struct fb_info *info);
21. 
22. /* set color register */
23. int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,
24. , unsigned transp, struct fb_info *info);
25. 
26. /* set color registers in batch */
27. int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);
28. 
29. /* blank display */
30. int (*fb_blank)(int blank, struct fb_info *info);
31. 
32. /* pan display */
33. int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);
34. 
35. /* Draws a rectangle */
36. (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
37. /* Copy data from area to another */
38. (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
39. /* Draws a image to the display */
40. (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);
41. 
42. /* Draws cursor */
43. int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);
44. 
45. /* Rotates the display */
46. (*fb_rotate)(struct fb_info *info, int angle);
47. 
48. /* wait for blit idle, optional */
49. int (*fb_sync)(struct fb_info *info);
50. 
51. /* perform fb specific ioctl (optional) */
52. int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,
53. );
54. 
55. /* Handle 32bit compat ioctl (optional) */
56. int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd,
57. );
58. 
59. /* perform fb specific mmap */
60. int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);
61. 
62. /* save current hardware state */
63. (*fb_save_state)(struct fb_info *info);
64. 
65. /* restore saved state */
66. (*fb_restore_state)(struct fb_info *info);
67. 
68. /* get capability given var */
69. (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,
70. *var);
71. };


二、LCD驱动程序分析
s3c2410fb_init:
1. int __init s3c2410fb_init(void)
2. {
3. int ret = platform_driver_register(&s3c2410fb_driver);                        //注册平台驱动设备
4. 
5. if (ret == 0)
6. = platform_driver_register(&s3c2412fb_driver);;
7. 
8. ;
9. }
s3c2410fb_driver:
1. static struct platform_driver s3c2410fb_driver = {
2. .probe        = s3c2410fb_probe,                                                //probe函数,里面调用了s3c24xxfb_probe
3. .remove        = s3c2410fb_remove,
4. .suspend    = s3c2410fb_suspend,
5. .resume        = s3c2410fb_resume,
6. .driver        = {
7. .name    = "s3c2410-lcd",
8. .owner    = THIS_MODULE,
9. },
10. };
s3c24xxfb_probe:
1. static int __init s3c24xxfb_probe(struct platform_device *pdev,
2. )
3. {
4. *info;
5. *display;
6. *fbinfo;
7. *mach_info;
8. *res;
9. int ret;
10. int irq;
11. int i;
12. int size;
13. ;
14. 
15. = pdev->dev.platform_data;
16. if (mach_info == NULL) {
17. (&pdev->dev,
18. "no platform data for lcd, cannot attach\n");
19. -EINVAL;
20. }
21. 
22. if (mach_info->default_display >= mach_info->num_displays) {
23. (&pdev->dev, "default is %d but only %d displays\n",
24. ->default_display, mach_info->num_displays);
25. -EINVAL;
26. }
27. 
28. = mach_info->displays + mach_info->default_display;
29. 
30. = platform_get_irq(pdev, 0);                                                       //获取中断号
31. if (irq < 0) {
32. (&pdev->dev, "no irq for device\n");
33. -ENOENT;
34. }
35. 
36. = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev);                 //分配fb_info结构
37. if (!fbinfo)
38. -ENOMEM;
39. 
40. (pdev, fbinfo);
41. 
42. = fbinfo->par;
43. ->dev = &pdev->dev;
44. ->drv_type = drv_type;
45. 
46. = platform_get_resource(pdev, IORESOURCE_MEM, 0);                                   //获取寄存器地址
47. if (res == NULL) {
48. (&pdev->dev, "failed to get memory registers\n");
49. = -ENXIO;
50. ;
51. }
52. 
53. = (res->end - res->start) + 1;
54. ->mem = request_mem_region(res->start, size, pdev->name);
55. if (info->mem == NULL) {
56. (&pdev->dev, "failed to get memory region\n");
57. = -ENOENT;
58. ;
59. }
60. 
61. ->io = ioremap(res->start, size);                                                 //转化成虚拟地址
62. if (info->io == NULL) {
63. (&pdev->dev, "ioremap() of registers failed\n");
64. = -ENXIO;
65. ;
66. }
67. 
68. ->irq_base = info->io + ((drv_type == DRV_S3C2412) ? S3C2412_LCDINTBASE : S3C2410_LCDINTBASE);
69. 
70. ("devinit\n");
71. 
72. (fbinfo->fix.id, driver_name);
73. 
74. /* Stop the video */                                                                   //初始化fbinfo结构
75. = readl(info->io + S3C2410_LCDCON1);
76. (lcdcon1 & ~S3C2410_LCDCON1_ENVID, info->io + S3C2410_LCDCON1);
77. 
78. ->fix.type     = FB_TYPE_PACKED_PIXELS;
79. ->fix.type_aux     = 0;
80. ->fix.xpanstep     = 0;
81. ->fix.ypanstep     = 0;
82. ->fix.ywrapstep     = 0;
83. ->fix.accel     = FB_ACCEL_NONE;
84. 
85. ->var.nonstd     = 0;
86. ->var.activate     = FB_ACTIVATE_NOW;
87. ->var.accel_flags = 0;
88. ->var.vmode     = FB_VMODE_NONINTERLACED;
89. 
90. ->fbops         = &s3c2410fb_ops;
91. ->flags         = FBINFO_FLAG_DEFAULT;
92. ->pseudo_palette = &info->pseudo_pal;
93. 
94. for (i = 0; i < 256; i++)
95. ->palette_buffer[i] = PALETTE_BUFF_CLEAR;
96. 
97. = request_irq(irq, s3c2410fb_irq, IRQF_DISABLED, pdev->name, info);                      //注册中断函数
98. if (ret) {
99. (&pdev->dev, "cannot get irq %d - err %d\n", irq, ret);
100. = -EBUSY;
101. ;
102. }
103. 
104. ->clk = clk_get(NULL, "lcd");
105. if (!info->clk || IS_ERR(info->clk)) {
106. (KERN_ERR "failed to get lcd clock source\n");
107. = -ENOENT;
108. ;
109. }
110. 
111. (info->clk);
112. ("got and enabled clock\n");
113. 
114. (1);
115. 
116. /* find maximum required memory size for display */
117. for (i = 0; i < mach_info->num_displays; i++) {
118. = mach_info->displays[i].xres;
119. 
120. *= mach_info->displays[i].yres;
121. *= mach_info->displays[i].bpp;
122. >>= 3;
123. if (fbinfo->fix.smem_len < smem_len)
124. ->fix.smem_len = smem_len;
125. }
126. 
127. /* Initialize video memory */
128. = s3c2410fb_map_video_memory(fbinfo);                                                   //为帧缓冲分配内存空间。同时使用了dma
129. if (ret) {
130. (KERN_ERR "Failed to allocate video RAM: %d\n", ret);
131. = -ENOMEM;
132. ;
133. }
134. 
135. ("got video memory\n");
136. 
137. ->var.xres = display->xres;
138. ->var.yres = display->yres;
139. ->var.bits_per_pixel = display->bpp;
140. 
141. (fbinfo);                                                           //GPIO初始化
142. 
143. (&fbinfo->var, fbinfo);                                                  //设置fb_var_screeninfo
144. 
145. = register_framebuffer(fbinfo);                                                         //注册帧缓冲-register_framebuffer
146. if (ret < 0) {
147. (KERN_ERR "Failed to register framebuffer device: %d\n",
148. );
149. ;
150. }
151. 
152. /* create device files */
153. = device_create_file(&pdev->dev, &dev_attr_debug);
154. if (ret) {
155. (KERN_ERR "failed to add debug attribute\n");
156. }
157. 
158. (KERN_INFO "fb%d: %s frame buffer device\n",
159. ->node, fbinfo->fix.id);
160. 
161. ;
162. 
163. :
164. (fbinfo);
165. :
166. (info->clk);
167. (info->clk);
168. :
169. (irq, info);
170. :
171. (info->io);
172. :
173. (info->mem);
174. (info->mem);
175. :
176. (pdev, NULL);
177. (fbinfo);
178. ;
179. }
s3c2410fb_map_vedio_memory:
1. static int __init s3c2410fb_map_video_memory(struct fb_info *info)
2. {
3. *fbi = info->par;
4. ;
5. = PAGE_ALIGN(info->fix.smem_len);
6. 
7. ("map_video_memory(fbi=%p) map_size %u\n", fbi, map_size);
8. 
9. ->screen_base = dma_alloc_writecombine(fbi->dev, map_size,
10. &map_dma, GFP_KERNEL);                                                      //为帧缓冲分配内存空间。同时使用了dma
11. 
12. if (info->screen_base) {
13. /* prevent initial garbage on screen */
14. ("map_video_memory: clear %p:%08x\n",
15. ->screen_base, map_size);
16. (info->screen_base, 0x00, map_size);
17. 
18. ->fix.smem_start = map_dma;
19. 
20. ("map_video_memory: dma=%08lx cpu=%p size=%08x\n",
21. ->fix.smem_start, info->screen_base, map_size);
22. }
23. 
24. ->screen_base ? 0 : -ENOMEM;
25. }

分析到这里发现并没有设置帧缓冲的地址:

于是可以通过搜索帧地址来辨别,在哪个函数中实现。

s3c2410fb_set_lcdaddr:
1. static void s3c2410fb_set_lcdaddr(struct fb_info *info)
2. {
3. , saddr2, saddr3;
4. *fbi = info->par;
5. *regs = fbi->io;
6. 
7. = info->fix.smem_start >> 1;
8. = info->fix.smem_start;
9. += info->fix.line_length * info->var.yres;
10. >>= 1;
11. 
12. = S3C2410_OFFSIZE(0) |
13. ((info->fix.line_length / 2) & 0x3ff);
14. 
15. ("LCDSADDR1 = 0x%08lx\n", saddr1);
16. ("LCDSADDR2 = 0x%08lx\n", saddr2);
17. ("LCDSADDR3 = 0x%08lx\n", saddr3);
18. 
19. (saddr1, regs + S3C2410_LCDSADDR1);                                  //这里设置了帧缓冲的地址
20. (saddr2, regs + S3C2410_LCDSADDR2);
21. (saddr3, regs + S3C2410_LCDSADDR3);
22. }
但是如何知道调用顺序呢,可以在函数中调用dump_stack():
1. Backtrace: 
2. [<c0049048>] (dump_backtrace+0x0/0x10c) from [<c0373fac>] (dump_stack+0x18/0x1c)
3. :232f3302 r6:5bd42233 r5:00000000 r4:3a352944
4. [<c0373f94>] (dump_stack+0x0/0x1c) from [<c01718c8>] (s3c2410fb_set_par+0x150/0x78c)
5. [<c0171778>] (s3c2410fb_set_par+0x0/0x78c) from [<c016a578>] (fbcon_init+0x42c/0x4b8)
6. [<c016a14c>] (fbcon_init+0x0/0x4b8) from [<c0185800>] (visual_init+0xb8/0x100)
7. [<c0185748>] (visual_init+0x0/0x100) from [<c018a65c>] (take_over_console+0x1f4/0x3d8)
8. :00000000 r6:c03a6c90 r5:c05a75a0 r4:00000019
9. [<c018a468>] (take_over_console+0x0/0x3d8) from [<c0167050>] (fbcon_takeover+0x7c/0xd4)
10. [<c0166fd4>] (fbcon_takeover+0x0/0xd4) from [<c016b1b0>] (fbcon_event_notify+0x768/0x7b0)
11. :ffffffff r4:00000000
12. [<c016aa48>] (fbcon_event_notify+0x0/0x7b0) from [<c0070784>] (notifier_call_chain+0x54/0x94)
13. [<c0070730>] (notifier_call_chain+0x0/0x94) from [<c0070d08>] (__blocking_notifier_call_chain+0x54/0x6c)
14. :c04b5008 r8:00000005 r7:ffffffff r6:c381dd98 r5:c04c5470
15. :c04c547c
16. [<c0070cb4>] (__blocking_notifier_call_chain+0x0/0x6c) from [<c0070d40>] (blocking_notifier_call_chain+0x20/0x28)
17. :c3842a04 r7:00000000 r6:c0513120 r5:c3842800 r4:c381dd60
18. [<c0070d20>] (blocking_notifier_call_chain+0x0/0x28) from [<c015fc48>] (fb_notifier_call_chain+0x1c/0x24)
19. [<c015fc2c>] (fb_notifier_call_chain+0x0/0x24) from [<c0160cf0>] (register_framebuffer+0x154/0x1fc)
20. [<c0160b9c>] (register_framebuffer+0x0/0x1fc) from [<c0014bbc>] (s3c24xxfb_probe+0x4c4/0x6fc)
21. [<c00146f8>] (s3c24xxfb_probe+0x0/0x6fc) from [<c0014e20>] (s3c2410fb_probe+0x14/0x18)
22. [<c0014e0c>] (s3c2410fb_probe+0x0/0x18) from [<c019369c>] (platform_drv_probe+0x20/0x24)
23. [<c019367c>] (platform_drv_probe+0x0/0x24) from [<c0192694>] (driver_probe_device+0x8c/0x1a0)
24. [<c0192608>] (driver_probe_device+0x0/0x1a0) from [<c019283c>] (__driver_attach+0x94/0x98)
25. [<c01927a8>] (__driver_attach+0x0/0x98) from [<c0191f38>] (bus_for_each_dev+0x6c/0x98)
26. :c01927a8 r6:c04c56b8 r5:c381de98 r4:00000000
27. [<c0191ecc>] (bus_for_each_dev+0x0/0x98) from [<c0192514>] (driver_attach+0x20/0x28)
28. :c04c56b8 r6:00000000 r5:c04c56b8 r4:c001fc68
29. [<c01924f4>] (driver_attach+0x0/0x28) from [<c0191764>] (bus_add_driver+0xa4/0x244)
30. [<c01916c0>] (bus_add_driver+0x0/0x244) from [<c0192b00>] (driver_register+0x74/0x15c)
31. [<c0192a8c>] (driver_register+0x0/0x15c) from [<c0193a80>] (platform_driver_register+0x6c/0x88)
32. :c381c000 r6:00000000 r5:c001fa50 r4:c001fc68
33. [<c0193a14>] (platform_driver_register+0x0/0x88) from [<c0014e38>] (s3c2410fb_init+0x14/0x30)
34. [<c0014e24>] (s3c2410fb_init+0x0/0x30) from [<c0044284>] (do_one_initcall+0x3c/0x1bc)
35. [<c0044248>] (do_one_initcall+0x0/0x1bc) from [<c0008438>] (kernel_init+0x88/0xf4)
36. [<c00083b0>] (kernel_init+0x0/0xf4) from [<c005a2e8>] (do_exit+0x0/0x620)

无欲速,无见小利。欲速,则不达;见小利,则大事不成。