在读者学习本章以及后续LCD相关章节之前,最好拥有LCD裸机基础,可以参考:LCD编程

在内核中,表示LCD使用的是framebuffer(帧缓冲,简写为fb),其内容对应于屏幕上的界面显示。修改framebuffer中的内容,即修改屏幕上的内容。操作framebuffer可以直接在LCD上观察到效果。

framebuffer本质上是一段内存,或称作显存。

在内核中,LCD对应的参数使用struct fb_info存储,对应的行为使用struct fb_ops存储。

在以下章节,我会分别讨论fb_info和fb_ops。

一、fb_info

之前说过fb_info定义的是属性,其结构体定义如下:

  1. struct fb_info {
  2. ...
  3. struct fb_var_screeninfo var; /* LCD可变参数,如屏幕一行像素点个数xres,一列像素点个数yres,每像素点所占位数等 */
  4. struct fb_fix_screeninfo fix; /* LCD固定参数,记录用户不能修改的显示控制器的参数,如屏幕缓存区物理地址smem_start,id,type等 */
  5.  
  6. ...
  7.  
  8. struct backlight_device *bl_dev; /* 背光设备 */
  9.  
  10. ...
  11.  
  12. struct fb_ops *fbops; /* LCD操作函数 */
  13. struct device *device; /* This is the parent */
  14. struct device *dev; /* This is this fb device */
  15.  
  16. ...
  17.  
  18. char __iomem *screen_base; /* 显存虚拟地址 */
  19. unsigned long screen_size; /* 屏幕大小*每个像素的字节数 */
  20. void *pseudo_palette; /* Fake palette of 16 colors */
  21.  
  22. ...
  23. };

其中,我们需要关注的有var、fix、screen_base和pseudo_palette

var结构体定义如下:

  1. struct fb_var_screeninfo {
  2. __u32 xres; /* LCD物理分辨率 */
  3. __u32 yres;
  4. __u32 xres_virtual; /* LCD虚拟分辨率 */
  5. __u32 yres_virtual;
  6. __u32 xoffset; /* 虚拟和物理分辨率的偏移值 */
  7. __u32 yoffset;
  8.  
  9. __u32 bits_per_pixel; /* 每一个像素占多少bit */
  10. __u32 grayscale; /* 灰度值,0 = color,1 = grayscale, */
  11. /* >1 = FOURCC */
  12. struct fb_bitfield red; /* bitfield in fb mem if true color, */
  13. struct fb_bitfield green; /* else only length is significant */
  14. struct fb_bitfield blue;
  15.  
  16. ...
  17.  
  18. __u32 activate; /* see FB_ACTIVATE_* */
  19.  
  20. ...
  21.  
  22. /* Timing指的是LCD上下的黑框的宽度等参数,一般不用设置 */
  23. __u32 pixclock; /* pixel clock in ps (pico seconds) */
  24. __u32 left_margin; /* time from sync to picture */
  25. __u32 right_margin; /* time from picture to sync */
  26. __u32 upper_margin; /* time from sync to picture */
  27. __u32 lower_margin;
  28. __u32 hsync_len; /* length of horizontal sync */
  29. __u32 vsync_len; /* length of vertical sync */
  30. __u32 sync; /* see FB_SYNC_* */
  31. __u32 vmode; /* see FB_VMODE_* */
  32. __u32 rotate; /* angle we rotate counter clockwise */
  33. __u32 colorspace; /* colorspace for FOURCC-based modes */
  34. __u32 reserved[]; /* Reserved for future compatibility */
  35. };

其中需要我们了解的有:

1. bits_per_pixel是LCD逻辑中的BPP,一般有24BPP、16BPP和8BPP。BPP的数值越大,显存所需空间越大,给处理器带来的负担也就越重;BPP的数值在8位以下时,所能表达的颜色又太少,不能够满足用户特定的需求。为解决这个问题,就需要采取调色板,也就是pseudo_palette。

2. fb_bitfield结构体用于设置红色、绿色和蓝色在BPP中的位置和长度。比如16BPP,格式为565,则格式示例代码如下:

  1. fbinfo->var.red.offset = ;
  2. fbinfo->var.red.length = ;
  3. // fbinfo->var.red.msb_right = ; /* 1: 右边为高位 */
  4. fbinfo->var.green.offset = ;
  5. fbinfo->var.green.length = ;
  6. // fbinfo->var.green.msb_right = ;
  7. fbinfo->var.blue.offset = ;
  8. fbinfo->var.blue.length = ;
  9. // fbinfo->var.blue.msb_right = ;

3. FB_ACTIVATE宏定义如下:

  1. #define FB_ACTIVATE_NOW 0 /* 立即设置值,一般选用此选项 */
  2. #define FB_ACTIVATE_NXTOPEN 1 /* 下次打开时激活 */
  3. #define FB_ACTIVATE_TEST 2 /* 不设置 */
  4. #define FB_ACTIVATE_MASK 15
  5. /* values */
  6. #define FB_ACTIVATE_VBL 16 /* 在下一次设置值时激活 */
  7. #define FB_CHANGE_CMAP_VBL 32 /* change colormap on vbl */
  8. #define FB_ACTIVATE_ALL 64 /* change all VCs on this fb */
  9. #define FB_ACTIVATE_FORCE 128 /* force apply even when no change*/
  10. #define FB_ACTIVATE_INV_MODE 256 /* invalidate videomode */

fix结构体定义如下:

  1. struct fb_fix_screeninfo {
  2. char id[]; /* 屏幕名字,自行设置 */
  3. unsigned long smem_start; /* 屏幕缓存区物理地址 */
  4. __u32 smem_len; /* 屏幕缓存区长度 */
  5. __u32 type; /* see FB_TYPE_* */
  6. __u32 type_aux; /* 辅助类型,一般设置为0 */
  7. __u32 visual; /* see FB_VISUAL_* */
  8. __u16 xpanstep; /* zero if no hardware panning */
  9. __u16 ypanstep; /* zero if no hardware panning */
  10. __u16 ywrapstep; /* zero if no hardware ywrap */
  11. __u32 line_length; /* 一行的字节数 */
  12. unsigned long mmio_start; /* 寄存器的起始物理地址,一般不需要设置 */
  13. __u32 mmio_len; /* 寄存器的长度,一般不需要设置 */
  14. __u32 accel; /* Indicate to driver which */
  15. /* specific chip/card we have */
  16. __u16 reserved[]; /* Reserved for future compatibility */
  17. };

其中,FB_TYPE宏定义如下:

  1. #define FB_TYPE_PACKED_PIXELS 0 /* 像素填充,一般选用此选项 */
  2. #define FB_TYPE_PLANES 1 /* 非交错planes */
  3. #define FB_TYPE_INTERLEAVED_PLANES 2 /* 交错planes */
  4. #define FB_TYPE_TEXT 3 /*文本/属性 */
  5. #define FB_TYPE_VGA_PLANES 4 /* EGA/VGA planes */

FB_VISUAL宏定义如下:

  1. #define FB_VISUAL_MONO01 0 /* 二值图像,只有黑白 1=Black 0=White */
  2. #define FB_VISUAL_MONO10 1 /* 二值图像,只有黑白 1=White 0=Black */
  3. #define FB_VISUAL_TRUECOLOR 2 /* 真彩色,一般选用此选项 */
  4. #define FB_VISUAL_PSEUDOCOLOR 3 /* Pseudo color (like atari) */
  5. #define FB_VISUAL_DIRECTCOLOR 4 /* Direct color */
  6. #define FB_VISUAL_STATIC_PSEUDOCOLOR 5 /* Pseudo color readonly */

pseudo_palette,又称调色板,它可以在低位BPP的条件下,在有限的像素值与RGB颜色之间建立拥有对应关系的线性表。比如从所有的16BPP的颜色中抽取一定数量的颜色编制索引。当需要使用某种彩色时,不需要对这种颜色的RGB分量进行描述,只需要引用它的索引号,就可以选取自己需要的颜色。索引号的长度远远小于RGB分量的编码长度,因此在彩色显示的同时,也减轻了系统的负担。

若需要调色板,我们需要在LCD操作函数中添加如下代码:

  1. /* 代码来源于drivers/video/samsung/s3cfb_ops.c */
  2.  
  3. inline unsigned int __chan_to_field(unsigned int chan, struct fb_bitfield bf)
  4. {
  5. chan &= 0xffff;
  6. chan >>= - bf.length;
  7.  
  8. return chan << bf.offset;
  9. }
  10.  
  11. int s3cfb_setcolreg(unsigned int regno, unsigned int red,
  12. unsigned int green, unsigned int blue,
  13. unsigned int transp, struct fb_info *fb)
  14. {
  15. unsigned int *pal = (unsigned int *)fb->pseudo_palette;
  16. unsigned int val = ;
  17.  
  18. if (regno < ) {
  19. /* fake palette of 16 colors */
  20. val |= __chan_to_field(red, fb->var.red);
  21. val |= __chan_to_field(green, fb->var.green);
  22. val |= __chan_to_field(blue, fb->var.blue);
  23. val |= __chan_to_field(transp, fb->var.transp);
  24. pal[regno] = val;
  25. }
  26.  
  27. return ;
  28. }

二、fb_ops

之前说过fb_ops定义的是行为,其结构体定义如下:

  1. struct fb_ops {
  2. /* open/release and usage marking */
  3. struct module *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. ssize_t (*fb_read)(struct fb_info *info, char __user *buf,
  11. size_t count, loff_t *ppos);
  12. ssize_t (*fb_write)(struct fb_info *info, const char __user *buf,
  13. size_t count, 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 blue, 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. void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
  37. /* Copy data from area to another */
  38. void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
  39. /* Draws a image to the display */
  40. void (*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. void (*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. unsigned long arg);
  54.  
  55. /* Handle 32bit compat ioctl (optional) */
  56. int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd,
  57. unsigned long arg);
  58.  
  59. /* perform fb specific mmap */
  60. int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);
  61.  
  62. /* get capability given var */
  63. void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,
  64. struct fb_var_screeninfo *var);
  65.  
  66. /* teardown any resources to do with this framebuffer */
  67. void (*fb_destroy)(struct fb_info *info);
  68.  
  69. /* called at KDB enter and leave time to prepare the console */
  70. int (*fb_debug_enter)(struct fb_info *info);
  71. int (*fb_debug_leave)(struct fb_info *info);
  72. };

此结构体中函数我们只需要根据实际情况编写部分函数即可。比如之前的调色板代码应该设置为fb_setcolreg函数指针:.fb_setcolreg = s3cfb_setcolreg,

三、framebuffer驱动调用流程

在应用程序使用LCD之前,内核主要需要做以下工作:

1. 初始化framebuffer框架,这个在drivers/video/fbmem.c中实现

2. 注册LCD设备,也就是注册fb_info

接下来应用程序需要操作LCD,会调用内核函数:

3. 应用程序open(),调用fb_open()

4. 应用程序write()、mmap()等,调用fb_write()、fb_mmap()等

5. 应用程序close(),调用fb_release()

1. 初始化framebuffer框架

  1. static int __init
  2. fbmem_init(void)
  3. {
  4. /* 1. 在proc文件系统中创建fb相关操作接口 */
  5. proc_create("fb", , NULL, &fb_proc_fops);
  6.  
  7. /* 2. 注册fb字符驱动 */
  8. if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
  9. printk("unable to get major %d for fb devs\n", FB_MAJOR);
  10.  
  11. /* 3. 创建graphics类 */
  12. fb_class = class_create(THIS_MODULE, "graphics");
  13. if (IS_ERR(fb_class)) {
  14. printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class));
  15. fb_class = NULL;
  16. }
  17. return ;
  18. }

由代码可知,fb的主设备号是代码中定好的,区分各个LCD设备依靠的是次设备号。

在框架搭建完成之后,我们就需要注册自己写的驱动中的fb_info结构体

2. 注册fb_info结构体

  1. int
  2. register_framebuffer(struct fb_info *fb_info)
  3. {
  4. int ret;
  5.  
  6. mutex_lock(&registration_lock);
  7. ret = do_register_framebuffer(fb_info);
  8. mutex_unlock(&registration_lock);
  9.  
  10. return ret;
  11. }
  1. static int do_register_framebuffer(struct fb_info *fb_info)
  2. {
  3. ...
  4. /* 1. 判断要注册设备的显存和已有设备的显存是否冲突 */
  5. do_remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id,
  6. fb_is_primary_device(fb_info));
  7.  
  8. /* 2. FB_MAX = 32,最多支持32个LCD设备 */
  9. if (num_registered_fb == FB_MAX)
  10. return -ENXIO;
  11.  
  12. ...
  13.  
  14. /* 3. 创建设备fb0/1/2... */
  15. fb_info->dev = device_create(fb_class, fb_info->device,
  16. MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
  17. ...
  18.  
  19. /* 4. 若驱动没有实现fb_info中pixmap,内核使用默认参数 */
  20. if (fb_info->pixmap.addr == NULL) {
  21. fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
  22. if (fb_info->pixmap.addr) {
  23. fb_info->pixmap.size = FBPIXMAPSIZE;
  24. fb_info->pixmap.buf_align = ;
  25. fb_info->pixmap.scan_align = ;
  26. fb_info->pixmap.access_align = ;
  27. fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
  28. }
  29. }
  30. fb_info->pixmap.offset = ;
  31.  
  32. ...
  33.  
  34. /* 5. 使用fbinfo中参数初始化mode */
  35. fb_var_to_videomode(&mode, &fb_info->var);
  36. fb_add_videomode(&mode, &fb_info->modelist);
  37. registered_fb[i] = fb_info;
  38.  
  39. event.info = fb_info;
  40. if (!lock_fb_info(fb_info))
  41. return -ENODEV;
  42. /* 6. 通知fb注册成功 */
  43. fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
  44. unlock_fb_info(fb_info);
  45. return ;
  46. }

3. 应用程序open(),调用fb_open()函数

在初始化framebuffer框架的fbmem_init()函数中register_chrdev(FB_MAJOR,"fb",&fb_fops)的fb_fops定义了fb_open()函数。

  1. static int fb_open(struct inode *inode, struct file *file)
  2. __acquires(&info->lock)
  3. __releases(&info->lock)
  4. {
  5. /* 1. 根据次设备号获取fb_info */
  6. int fbidx = iminor(inode);
  7. struct fb_info *info;
  8. int res = ;
  9.  
  10. info = get_fb_info(fbidx);
  11.  
  12. ...
  13.  
  14. mutex_lock(&info->lock);
  15. if (!try_module_get(info->fbops->owner)) {
  16. res = -ENODEV;
  17. goto out;
  18. }
  19. file->private_data = info;
  20.  
  21. /* 2. 若驱动程序中定义了fb_open(),则优先调用 */
  22. if (info->fbops->fb_open) {
  23. res = info->fbops->fb_open(info,);
  24. if (res)
  25. module_put(info->fbops->owner);
  26. }
  27. #ifdef CONFIG_FB_DEFERRED_IO
  28. if (info->fbdefio)
  29. fb_deferred_io_open(info, inode, file);
  30. #endif
  31. out:
  32. mutex_unlock(&info->lock);
  33. if (res)
  34. put_fb_info(info);
  35. return res;
  36. }

fb_open()函数所做的有私有化数据和调用驱动程序中fb_ops的fb_open()函数。

4. 应用程序write(),调用fb_write()函数

看过LED和KEY驱动程序的读者可以发现write()和read()函数实现差别不大,在此以fb中常用的write()函数为例分析。

  1. static ssize_t fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
  2. {
  3. unsigned long p = *ppos; /* 偏移量 */
  4. struct fb_info *info = file_fb_info(file);
  5. u8 *buffer, *src;
  6. u8 __iomem *dst;
  7. int c, cnt = , err = ;
  8. unsigned long total_size;
  9.  
  10. ...
  11.  
  12. /* 若驱动程序中定义了fb_write(),则优先调用 */
  13. if (info->fbops->fb_write)
  14. return info->fbops->fb_write(info, buf, count, ppos);
  15.  
  16. total_size = info->screen_size;
  17.  
  18. if (total_size == )
  19. total_size = info->fix.smem_len;
  20.  
  21. if (p > total_size)
  22. return -EFBIG;
  23.  
  24. if (count > total_size) {
  25. err = -EFBIG;
  26. count = total_size;
  27. }
  28.  
  29. if (count + p > total_size) {
  30. if (!err)
  31. err = -ENOSPC;
  32.  
  33. count = total_size - p;
  34. }
  35.  
  36. buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
  37. GFP_KERNEL);
  38. if (!buffer)
  39. return -ENOMEM;
  40.  
  41. dst = (u8 __iomem *) (info->screen_base + p);
  42.  
  43. /* 若驱动程序中定义了fb_sync(),则优先调用 */
  44. if (info->fbops->fb_sync)
  45. info->fbops->fb_sync(info);
  46.  
  47. /* 使用copy_from_user()将数据从用户空间拷贝到内核空间 */
  48. while (count) {
  49. c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
  50. src = buffer;
  51.  
  52. if (copy_from_user(src, buf, c)) {
  53. err = -EFAULT;
  54. break;
  55. }
  56.  
  57. fb_memcpy_tofb(dst, src, c);
  58. dst += c;
  59. src += c;
  60. *ppos += c;
  61. buf += c;
  62. cnt += c;
  63. count -= c;
  64. }
  65.  
  66. kfree(buffer);
  67.  
  68. return (cnt) ? cnt : err;
  69. }

我们可以发现fb_write()函数默认提供的写操作同样使用了copy_from_user()拷贝数据。除此之外,它还使用fb_memcpy_tofb()函数把数据写到显存。也就是执行两次拷贝操作。

之前我们使用copy_from_user()拷贝数据是因为我们的数据量较小,一般只有几字节。但是fb显存一般为几百KB,copy_from_user()拷贝数据极有可能导致画面卡顿,导致效率降低。

解决此问题的方式就是使用mmap()函数。

应用程序mmap()函数使用方法可以参考:第七章:进程环境中六、存储空间的分配mmap()函数。

内核使用struct task_struct来表示某个进程,该结构体包含一些进程状态、调度信息等成员,并使用结构体链表来管理所有进程。我们需要关注进程描述符中内存描述符:struct mm_struct。

struct mm_struct中struct vm_area_struct用来表示一个独立的虚拟内存区域,该结构体包含映射地址、大小、结束地址等成员,并使用结构体链表来管理所有虚拟内存区域。

由此我们可以推出:mmap()把设备地址映射到进程虚拟地址(ioremap()把设备地址映射到内核虚拟空间)。指针指向如下图:

mmap()函数首先分配一个struct vm_area_struct放到进程的地址空间,之后实现文件地址和虚拟地址区域的映射关系。

此时映射关系有了,但内存中没有数据,进程访问内存会引发引发缺页异常,最终内核会发起请求调页过程,它先在交换缓存空间中寻找需要访问的内存页,如果没有则调用nopage()函数把所缺的页从磁盘装入到主存中。在这之后进程便可以正常访问数据。

这样做的好处是映射过程并没有拷贝数据,只需要从磁盘到用户主存的一次拷贝数据过程。而write()函数需要从磁盘到页缓存再到用户主存的两次拷贝数据过程。

分析完mmap()后,我们来查看fb_mmap()函数

  1. static int fb_mmap(struct file *file, struct vm_area_struct * vma)
  2. {
  3. struct fb_info *info = file_fb_info(file);
  4. struct fb_ops *fb;
  5. unsigned long off;
  6. unsigned long start;
  7. u32 len;
  8.  
  9. if (!info)
  10. return -ENODEV;
  11. if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
  12. return -EINVAL;
  13. off = vma->vm_pgoff << PAGE_SHIFT;
  14. fb = info->fbops;
  15. if (!fb)
  16. return -ENODEV;
  17. mutex_lock(&info->mm_lock);
  18. if (fb->fb_mmap) {
  19. int res;
  20. res = fb->fb_mmap(info, vma); /* 若驱动程序中定义了fb_mmap(),则优先调用 */
  21. mutex_unlock(&info->mm_lock);
  22. return res;
  23. }
  24.  
  25. /* frame buffer memory */
  26. start = info->fix.smem_start; /* 显存起始地址 */
  27. len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len); /* 显存大小*/
  28. if (off >= len) {
  29. /* memory mapped io */
  30. off -= len;
  31. if (info->var.accel_flags) {
  32. mutex_unlock(&info->mm_lock);
  33. return -EINVAL;
  34. }
  35. start = info->fix.mmio_start;
  36. len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
  37. }
  38. mutex_unlock(&info->mm_lock);
  39. start &= PAGE_MASK;
  40. if ((vma->vm_end - vma->vm_start + off) > len)
  41. return -EINVAL;
  42. off += start;
  43. vma->vm_pgoff = off >> PAGE_SHIFT;
  44. /* This is an IO map - tell maydump to skip this VMA */
  45. vma->vm_flags |= VM_IO | VM_RESERVED;
  46. vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
  47. fb_pgprotect(file, vma, off);
  48.  
  49. /* 映射页I/O,vma为用户分配的空间 */
  50. if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
  51. vma->vm_end - vma->vm_start, vma->vm_page_prot))
  52. return -EAGAIN;
  53. return ;
  54. }

接下来简单举例在应用程序中使用mmap()函数并把LCD显示器的背景刷成蓝色。此代码读者暂时不需要会修改,熟悉即可。我将在接下来的LCD章节中对平台驱动框架对代码中参数进行分析。

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <fcntl.h>
  4. #include <unistd.h>
  5. #include <string.h>
  6. #include <sys/mman.h>
  7.  
  8. /* Usage:
  9. * ./a.out <fb0|fb1|fb2|...>
  10. */
  11. int main(int argc, char **argv)
  12. {
  13. if (argc != ) {
  14. printf("Usage:\n");
  15. printf("%s <fb0|fb1|fb2|...>\n", argv[]);
  16. return -;
  17. }
  18.  
  19. char path[] = "/dev/";
  20. strcat(path, argv[]);
  21.  
  22. int fd = open(path, O_RDWR);
  23. if (fd < )
  24. perror("open"), exit(-);
  25.  
  26. /* 1280*800*4
  27. * 1280: xres,x方向分辨率
  28. * 800:yres,y方向分辨率
  29. * 4:我的内核中默认LCD为24BPP,查手册可以确定24BPP占32位,也就是4字节
  30. */
  31. unsigned int *memory = (unsigned int *)mmap(NULL, **, PROT_READ | PROT_WRITE, MAP_SHARED, fd, );
  32. if (memory == (unsigned int *)-) {
  33. close(fd);
  34. perror("mmap");
  35. exit(-);
  36. }
  37.  
  38. close(fd);
  39.  
  40. /* 把屏幕刷成蓝色 */
  41. int i;
  42. for (i = ; i < (*); ++i) {
  43. memory[i] = 0x000000ff;
  44. }
  45.  
  46. /* 写回磁盘文件中 */
  47. msync(memory, **, MS_SYNC);
  48.  
  49. return ;
  50. }

5. 应用程序close(),调用fb_release()

在此仅给出调用过程:

  1. fb_release(struct inode *inode, struct file *file)
  2. if (info->fbops->fb_release)
  3. info->fbops->fb_release(info,);
  4. -> put_fb_info(info);
  5. if (fb_info->fbops->fb_destroy)
  6. fb_info->fbops->fb_destroy(fb_info);

下一章  十一、三星平台framebuffer驱动

十、LCD的framebuffer设备驱动的更多相关文章

  1. 2016/1/9:深度剖析安卓Framebuffer设备驱动

    忙了几天,今天在公司居然没什么活干 ,所以早上就用公司的电脑写写之前在公司编写framebuffer的使用心得体会总结,这也算是一点开发经验,不过我还没写全,精华部分还是自己藏着吧.直到下午才开始有点 ...

  2. framebuffer设备驱动分析

    一.设备驱动相关文件 1.1. 驱动框架相关文件 1.1.1. drivers/video/fbmem.c a. 创建graphics类.注册FB的字符设备驱动 fbmem_init(void) { ...

  3. Linux设备驱动中的软件架构思想

    目录 更新记录 一.Linux驱动的软件架构 1.1 出发点 1.2 分离思想 1.3 分层思想 二.platform设备驱动 2.1 platform设备 2.2 platform驱动 2.3 pl ...

  4. Linux中LCD设备驱动-framebuffer(帧缓冲)【】

    转自:https://blog.csdn.net/linux_devices_driver/article/details/7079442 1.framebuffer 帧缓冲     帧缓冲(fram ...

  5. linux设备驱动归纳总结(十二):简单的数码相框【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-116926.html linux设备驱动归纳总结(十二):简单的数码相框 xxxxxxxxxxxxxx ...

  6. linux lcd设备驱动剖析四

    在"linux lcd设备驱动剖析二"文章中,我们详细分析了s3c24xxfb_probe函数. 文章链接:http://blog.csdn.net/lwj103862095/ar ...

  7. LCD驱动分析(一)字符设备驱动框架分析

    参考:S3C2440 LCD驱动(FrameBuffer)实例开发<一>   S3C2440 LCD驱动(FrameBuffer)实例开发<二> LCD驱动也是字符设备驱动,也 ...

  8. 【Linux开发】linux设备驱动归纳总结(十二):简单的数码相框

    linux设备驱动归纳总结(十二):简单的数码相框 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...

  9. linux设备驱动归纳总结(十):1.udev&misc【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-111839.html linux设备驱动归纳总结(十):1.udev&misc xxxxxxx ...

随机推荐

  1. zabbix (一) 初识

    1.什么是zabbix? Zabbix由Alexei Vladishev创建,目前由Zabbix SIA积极开发和支持. Zabbix是一种企业级开源分布式监控解决方案. Zabbix是监控底层存储( ...

  2. 2019-12-10:win7,win12提权练习

    一.win7 1,上传webshell到服务器,访问 2,因为win7权限没设置好,导致任何命令都可以执行 直接提权成功,还可以通过msf工具利用exp进行提权,今天太晚了就先不做了 二.win201 ...

  3. TCP和UDP并实现socket的简单通信

    http://www.cnblogs.com/IPrograming/archive/2012/10/15/CSharp_Socket_4.html http://www.cnblogs.com/do ...

  4. XGBoost、LightGBM、Catboost总结

    sklearn集成方法 bagging 常见变体(按照样本采样方式的不同划分) Pasting:直接从样本集里随机抽取的到训练样本子集 Bagging:自助采样(有放回的抽样)得到训练子集 Rando ...

  5. layui跨域问题的解决

      跨域问题的解决 由于浏览器存在同源策略,所以如果 layui(里面含图标字体文件)所在的地址与你当前的页面地址不在同一个域下,即会出现图标跨域问题.所以要么你就把 layui 与网站放在同一服务器 ...

  6. pgpool-II 高可用搭建

    pgpool-II主备流复制的架设1.环境 OS: CentOS release 6.4 (Final)DB: postgresql 9.3.6pgpool服务器: pgpool 172.16.0.2 ...

  7. python笔记9 线程进程 threading多线程模块 GIL锁 multiprocessing多进程模块 同步锁Lock 队列queue IO模型

    线程与进程 进程 进程就是一个程序在一个数据集上的一次动态执行过程.进程一般由程序.数据集.进程控制块三部分组成.我们编写的程序用来描述进程要完成哪些功能以及如何完成:数据集则是程序在执行过程中所需要 ...

  8. LC 989. Add to Array-Form of Integer

    For a non-negative integer X, the array-form of X is an array of its digits in left to right order.  ...

  9. SQL-W3School-函数:SQL AVG() 函数

    ylbtech-SQL-W3School-函数:SQL AVG() 函数 1.返回顶部 1. 定义和用法 AVG 函数返回数值列的平均值.NULL 值不包括在计算中. SQL AVG() 语法 SEL ...

  10. BitmapFactory之Options

    package com.loaderman.customviewdemo; import android.app.Activity; import android.graphics.Bitmap; i ...