rk3288 基于App分析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 tty1\n");

	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 %d\n",
			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);					//返回给应用程序的映射空间
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

习惯就好zz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值