瑞芯微Rockchip开发者社区
直播中

张亮

7年用户 1290经验值
私信 关注
[问答]

怎样去编写基于rk3288的LCD控制器驱动程序呢

LCD硬件原理
lcd去显存里取出数据,然后作用到屏幕上。
一旦设置好了LCD控制器,一旦分配好了显存,就什么都不用管了,当数据写入显存后,剩下的自己会做好。
应用程序需要做获得的信息;
显存的基地址
一个像素的格式
这些信息得由驱动程序提供。
open函数
//在fb-test.c中
int main(int argc, char **argv)
{
int opt;
int req_fb = 0;
int req_pattern = 0;
printf("fb-test %d.%d.%d (%s)n", VERSION, PATCHLEVEL, SUBLEVEL,
VERSION_NAME);
//...参数处理
fb_open(req_fb, &fb_info); //打开fb设置,获取fb_info结构体
do_fill_screen(&fb_info, req_pattern);
return 0;
}
//在common.c中
void fb_open(int fb_num, struct fb_info *fb_info)
{
char str[64];
int fd,tty;
tty = open("/dev/tty1", O_RDWR);
if(ioctl(tty, KDSETMODE, KD_GRAPHICS) == -1)
printf("Failed to set graphics mode on tty1n");
sprintf(str, "/dev/fb%d", fb_num);
fd = open(str, O_RDWR); //这里打开/dev/fb0
ASSERT(fd >= 0);
fb_info->fd = fd;
IOCTL1(fd, FBIOGET_VSCREENINFO, &fb_info->var); //这里获取var信息
IOCTL1(fd, FBIOGET_FSCREENINFO, &fb_info->fix); //这里获取fix信息
printf("fb res %dx%d virtual %dx%d, line_len %d, bpp %dn",
fb_info->var.xres, fb_info->var.yres,
fb_info->var.xres_virtual, fb_info->var.yres_virtual,
fb_info->fix.line_length, fb_info->var.bits_per_pixel);
//这里映射了显存地址
void *ptr = mmap(0,
fb_info->var.yres_virtual * fb_info->fix.line_length,
PROT_WRITE | PROT_READ,
MAP_SHARED, fd, 0);
ASSERT(ptr != MAP_FAILED);
fb_info->ptr = ptr;
}
对应的在驱动层的open里面
//fbmem.c中有注册fb文件结构体的代码
static const struct file_operations fb_fops = {
.owner = THIS_MODULE,
.read = fb_read,
.write = fb_write,
.unlocked_ioctl = fb_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = fb_compat_ioctl,
#endif
.mmap = fb_mmap,
.open = fb_open, //这里注册了fb_open
.release = fb_release,
#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
.get_unmapped_area = get_fb_unmapped_area,
#endif
#ifdef CONFIG_FB_DEFERRED_IO
.fsync = fb_deferred_io_fsync,
#endif
.llseek = default_llseek,
};
static int
fb_open(struct inode *inode, struct file *file)
__acquires(&info->lock)
__releases(&info->lock)
{
int fbidx = iminor(inode); //获取次设备号
struct fb_info *info;
int res = 0;
info = get_fb_info(fbidx); //从fbidx中获取注册的registered_fb,这个文件是在lcd_drv.c中注册的
if (!info) {
request_module("fb%d", fbidx);
info = get_fb_info(fbidx);
if (!info)
return -ENODEV;
}
if (IS_ERR(info))
return PTR_ERR(info);
mutex_lock(&info->lock);
if (!try_module_get(info->fbops->owner)) {
res = -ENODEV;
goto out;
}
file->private_data = info; //把fb_info保存在private_data中
if (info->fbops->fb_open) { //尝试打开设备
res = info->fbops->fb_open(info,1);
if (res)
module_put(info->fbops->owner);
}
#ifdef CONFIG_FB_DEFERRED_IO
if (info->fbdefio)
fb_deferred_io_open(info, inode, file);
#endif
out:
mutex_unlock(&info->lock);
if (res)
put_fb_info(info);
return res;
}
ioctl的驱动调用
在fbmem.c中的fb_ioctl:
static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct fb_info *info = file_fb_info(file); //从次设备号获得fb_info,open时保存在private_data中,这两个会对比一下是否一致
if (!info)
return -ENODEV;
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;
struct fb_dmabuf_export dmaexp;
void __user *argp = (void __user *)arg;
long ret = 0;
switch (cmd) {
case FBIOGET_VSCREENINFO:
if (!lock_fb_info(info))
return -ENODEV;
var = info->var; //从fb_info中获得var
unlock_fb_info(info);
ret = copy_to_user(argp, &var, sizeof(var)) ? -EFAULT : 0; //传递给用户
break;
case FBIOPUT_VSCREENINFO:
//...
break;
case FBIOGET_FSCREENINFO:
if (!lock_fb_info(info))
return -ENODEV;
fix = info->fix; //从fb_info中获得fix
unlock_fb_info(info);
ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0; //传递给用户
break;
case FBIOPUTCMAP:
//...
break;
case FBIOGETCMAP:
//...
break;
case FBIOPAN_DISPLAY:
//...
break;
case FBIO_CURSOR:
ret = -EINVAL;
break;
case FBIOGET_CON2FBMAP:
//...
break;
case FBIOPUT_CON2FBMAP:
//...
break;
case FBIOBLANK:
//...
break;
case FBIOGET_DMABUF:
//...
break;
default:
//...
}
return ret;
}
mmap驱动中的调用
在fbmem.c中有fb_mmap函数:
static int
fb_mmap(struct file *file, struct vm_area_struct * vma)
{
struct fb_info *info = file_fb_info(file); //获取fb_info
struct fb_ops *fb;
unsigned long mmio_pgoff;
unsigned long start;
u32 len;
//...
/*
* Ugh. This can be either the frame buffer mapping, or
* if pgoff points past it, the mmio mapping.
*/
start = info->fix.smem_start; //显存的起始地址
len = info->fix.smem_len; //显存长度
mmio_pgoff = PAGE_ALIGN((start & ~PAGE_MASK) + len) >> PAGE_SHIFT;
//....
vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
fb_pgprotect(file, vma, start);
return vm_iomap_memory(vma, start, len); //返回给应用程序的映射空间
}

原作者:习惯就好zz

更多回帖

发帖
×
20
完善资料,
赚取积分