【Tiny6410 And Linux】—(6.1)—LCD 驱动测试程序——原理

总算要涉及到LCD的驱动程序了,不过之前还是先弄一下LCD的测试程序的好(这里看的是国嵌的代码)!

之前在电脑上找了很久的LCD的驱动程序,也就是xxxfb.c,但是真心看不懂究竟是哪个驱动,但是共性的文件fbmem.c还是可以了解的,这里就通过fbmem.c来进行简单的介绍吧,至于涉及到的相关的硬件设备(今天写的驱动测试没有涉及到硬件的具体信息),只能等以后再说了!

LCD 驱动测试程序:

首先介绍一下 Framebuffer:Framebuffer 从本质上讲是图形设备的硬件抽象。对开发者而言, Framebuffer 是一块显示缓存,往缓存中写入特定格式的数据就意味着向屏幕输出内容。通过不断的向 Framebuffer 中写入数据,显示控制器就会自动的从 Framebuffer 中取数据并显示出来,帧缓冲设备对应的设备文件为 /dev/fb0,如果系统有多个显示卡, Linux 下还可以支持多个帧缓冲设备,通常指向 /dev/fb0。真缓冲设备为标准的字符设备,主设备号为 29,次设备号从 0 到 31。

下面可以看看帧缓冲设备的架构:

1、帧缓冲设备结构体介绍:

Linux 内核使用 fb_info 结构来描述帧缓冲设备,定义在 include/linux/fb.h 中, fb_infor 结构常用成员:

struct fb_info {int node;int flags;struct mutex lock;/* Lock for open/release/ioctl funcs */struct mutex mm_lock;/* Lock for fb_mmap and smem_* fields */struct fb_var_screeninfo var;/* Current var */struct fb_fix_screeninfo fix;/* Current fix */struct fb_monspecs monspecs;/* Current Monitor specs */struct work_struct queue;/* Framebuffer event queue */struct fb_pixmap pixmap;/* Image hardware mapper */struct fb_pixmap sprite;/* Cursor hardware mapper */struct fb_cmap cmap;/* Current cmap */struct list_head modelist;      /* mode list */struct fb_videomode *mode;/* current mode *//* we need the PCI or similiar aperture base/size not   smem_start/size as smem_start may just be an object   allocated inside the aperture so may not actually overlap */struct apertures_struct {unsigned int count;struct aperture {resource_size_t base;resource_size_t size;} ranges[0];} *apertures;};

其中 fb_var_screeninfo 结构记录了用户可以修改的显示参数,包括屏幕分辨率等。

struct fb_var_screeninfo {__u32 xres;/* visible resolution*/__u32 yres;__u32 xres_virtual;/* virtual resolution*/__u32 yres_virtual;__u32 xoffset;/* offset from virtual to visible */__u32 yoffset;/* resolution*/__u32 bits_per_pixel;/* guess what*/__u32 grayscale;/* != 0 Graylevels instead of colors */struct fb_bitfield red;/* bitfield in fb mem if true color, */struct fb_bitfield green;/* else only length is significant */struct fb_bitfield blue;struct fb_bitfield transp;/* transparency*/__u32 nonstd;/* != 0 Non standard pixel format */__u32 activate;/* see FB_ACTIVATE_**/__u32 height;/* height of picture in mm    */__u32 width;/* width of picture in mm     */__u32 accel_flags;/* (OBSOLETE) see fb_info.flags */};

fb_fix_screeninfo 记录了用户不能修改的显示控制器参数,如显示缓存的物理地址等。

struct fb_fix_screeninfo {char id[16];/* identification string eg "TT Builtin" */unsigned long smem_start;/* Start of frame buffer mem *//* (physical address) */__u32 smem_len;/* Length of frame buffer mem */__u32 type;/* see FB_TYPE_**/__u32 type_aux;/* Interleave for interleaved Planes */__u32 visual;/* see FB_VISUAL_**/ __u16 xpanstep;/* zero if no hardware panning  */__u16 ypanstep;/* zero if no hardware panning  */__u16 ywrapstep;/* zero if no hardware ywrap    */__u32 line_length;/* length of a line in bytes    */unsigned long mmio_start;/* Start of Memory Mapped I/O   *//* (physical address) */__u32 mmio_len;/* Length of Memory Mapped I/O  */__u32 accel;/* Indicate to driver which*//*  specific chip/card we have*/__u16 reserved[3];/* Reserved for future compatibility */};

还有就是 fb_ops 结构包含了对控制器进行操作的函数指针。

struct fb_ops {/* open/release and usage marking */struct module *owner;int (*fb_open)(struct fb_info *info, int user);int (*fb_release)(struct fb_info *info, int user);/* For framebuffers with strange non linear layouts or that do not * work with normal memory mapped access */ssize_t (*fb_read)(struct fb_info *info, char __user *buf,   size_t count, loff_t *ppos);ssize_t (*fb_write)(struct fb_info *info, const char __user *buf,    size_t count, loff_t *ppos);/* checks var and eventually tweaks it to something supported, * DO NOT MODIFY PAR */int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);/* set the video mode according to info->var */int (*fb_set_par)(struct fb_info *info);/* set color register */int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,    unsigned blue, unsigned transp, struct fb_info *info);/* set color registers in batch */int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);/* blank display */int (*fb_blank)(int blank, struct fb_info *info);/* pan display */int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);/* Draws a rectangle */void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);/* Copy data from area to another */void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);/* Draws a image to the display */void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);/* Draws cursor */int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);/* Rotates the display */void (*fb_rotate)(struct fb_info *info, int angle);/* wait for blit idle, optional */int (*fb_sync)(struct fb_info *info);};

2、控制器操作函数(fbmem.c):

这里首先讲述一下 LCD 测试程序的基本步骤:

1)用 ioctl 操作取得当前屏幕的参数,根据屏幕参数可以计算屏幕缓冲区的大小。

2)将屏幕缓冲区映射到用户空间(mmap)。

3)映射后即可直接读写

这里用到 open、release、ioctl 等函数,主要介绍下 ioctl 函数吧,代码如下:

static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg){struct inode *inode = file->f_path.dentry->d_inode;int fbidx = iminor(inode);struct fb_info *info = registered_fb[fbidx];return do_fb_ioctl(info, cmd, arg);}static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,unsigned long arg){struct fb_ops *fb;struct fb_var_screeninfo var;struct fb_fix_screeninfo fix;struct fb_con2fbmap con2fb;struct fb_cmap cmap_from;struct fb_cmap_user cmap;struct fb_event event;void __user *argp = (void __user *)arg;long ret = 0;switch (cmd) {case FBIOGET_VSCREENINFO:if (!lock_fb_info(info))return -ENODEV;var = info->var;unlock_fb_info(info);ret = copy_to_user(argp, &var, sizeof(var)) ? -EFAULT : 0;break;case FBIOPUT_VSCREENINFO:if (copy_from_user(&var, argp, sizeof(var)))return -EFAULT;if (!lock_fb_info(info))return -ENODEV;console_lock();info->flags |= FBINFO_MISC_USEREVENT;ret = fb_set_var(info, &var);info->flags &= ~FBINFO_MISC_USEREVENT;console_unlock();unlock_fb_info(info);if (!ret && copy_to_user(argp, &var, sizeof(var)))ret = -EFAULT;break;case FBIOGET_FSCREENINFO:if (!lock_fb_info(info))return -ENODEV;fix = info->fix;unlock_fb_info(info);ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0;break;case FBIOPUTCMAP:if (copy_from_user(&cmap, argp, sizeof(cmap)))return -EFAULT;ret = fb_set_user_cmap(&cmap, info);break;case FBIOGETCMAP:if (copy_from_user(&cmap, argp, sizeof(cmap)))return -EFAULT;if (!lock_fb_info(info))return -ENODEV;cmap_from = info->cmap;unlock_fb_info(info);ret = fb_cmap_to_user(&cmap_from, &cmap);break;case FBIOPAN_DISPLAY:if (copy_from_user(&var, argp, sizeof(var)))return -EFAULT;if (!lock_fb_info(info))return -ENODEV;console_lock();ret = fb_pan_display(info, &var);console_unlock();unlock_fb_info(info);if (ret == 0 && copy_to_user(argp, &var, sizeof(var)))return -EFAULT;break;case FBIO_CURSOR:ret = -EINVAL;break;case FBIOGET_CON2FBMAP:if (copy_from_user(&con2fb, argp, sizeof(con2fb)))return -EFAULT;if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)return -EINVAL;con2fb.framebuffer = -1;event.data = &con2fb;if (!lock_fb_info(info))return -ENODEV;event.info = info;fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event);unlock_fb_info(info);ret = copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0;break;case FBIOPUT_CON2FBMAP:if (copy_from_user(&con2fb, argp, sizeof(con2fb)))return -EFAULT;if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)return -EINVAL;if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX)return -EINVAL;if (!registered_fb[con2fb.framebuffer])request_module("fb%d", con2fb.framebuffer);if (!registered_fb[con2fb.framebuffer]) {ret = -EINVAL;break;}event.data = &con2fb;if (!lock_fb_info(info))return -ENODEV;event.info = info;ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event);unlock_fb_info(info);break;case FBIOBLANK:if (!lock_fb_info(info))return -ENODEV;console_lock();info->flags |= FBINFO_MISC_USEREVENT;ret = fb_blank(info, arg);info->flags &= ~FBINFO_MISC_USEREVENT;console_unlock();unlock_fb_info(info);break;default:if (!lock_fb_info(info))return -ENODEV;fb = info->fbops;if (fb->fb_ioctl)ret = fb->fb_ioctl(info, cmd, arg);elseret = -ENOTTY;unlock_fb_info(info)}return ret;}

如果对 ioctl 函数有所理解,可以很快看到 cmd 变量 FBIOGET_VSCREENINFO,这个变量就可以获得设备体 /dev/fb0 的相关的详细信息!

写的有点乱,主要是 CSDN 今天不知道为什么,总是保存不了,然我重新翻工了好几遍!上火了!

人生好如足球赛,看自家总是无奈,对人家总是优待,

【Tiny6410 And Linux】—(6.1)—LCD 驱动测试程序——原理

相关文章:

你感兴趣的文章:

标签云: