一,前言
之前ubuntu18.04配置网桥支持qemu模拟开发板挂载NFS启动LCD--Apple的学习笔记
已经完成了qemu仿真LCD,并且实现了framebuffer的应用。于是想调试下源码,原因是光看代码可能会理解错误。但是vexpress a9开发板看了下设备树后发现他用的不是LCDC的framebuffer而是用了drm框架。
但是复习了下DRM框架后,发现其实framebuffer都是注册的,那么就可以当做fbdev用了。然后分析代码的话还是选简单的s3c2410fb.c来分析,看了代码后,发现和我之前分析fbtft使用framebuffer子系统类似,可以参考Linux驱动OLED屏st7735s(framebuffer学习)--Apple的学习笔记。为了能实际调试我在直接下载了一个被二次开发过的qemu,能支持mini2440仿真。
二,s3c2410fb.c关键代码分析(内核版本5.4.61)
1.设置寄存器为LCDC设置总线时序margin timer及刷新频率,LCD内存起始地址
s3c2410fb_set_par ->s3c2410fb_activate_var --->s3c2410fb_calculate_tft_lcd_regs和s3c2410fb_set_lcdaddr
2.probe函数会挂上具体芯片的操作函数
fbinfo->fbops = &s3c2410fb_ops;
static struct fb_ops s3c2410fb_ops = {
.owner = THIS_MODULE,
.fb_check_var = s3c2410fb_check_var,
.fb_set_par = s3c2410fb_set_par,
.fb_blank = s3c2410fb_blank,
.fb_setcolreg = s3c2410fb_setcolreg,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
};
`
2.probe函数中填充fbinfo后注册register_framebuffer,然后用户空间就可以操作文件系统了。
ret = register_framebuffer(fbinfo);
```c
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,
.release = fb_release,
#if defined(HAVE_ARCH_FB_UNMAPPED_AREA) || \
(defined(CONFIG_FB_PROVIDE_GET_FB_UNMAPPED_AREA) && \
!defined(CONFIG_MMU))
.get_unmapped_area = get_fb_unmapped_area,
#endif
#ifdef CONFIG_FB_DEFERRED_IO
.fsync = fb_deferred_io_fsync,
#endif
.llseek = default_llseek,
};
3.fb_mmap在s3c2410.c中没有调用。PAGE_ALIGN
和vm_iomap_memory
为关键函数,一个是alian一个是将虚拟地址转到物理地址,具体的page MMU相关函数内容我不展开,将来做专题分析。
static int fb_mmap(struct file *file, struct vm_area_struct * vma)
{
int fbidx = iminor(file->f_path.dentry->d_inode);
struct fb_info *info = registered_fb[fbidx];
struct fb_ops *fb = info->fbops;
unsigned long off;
unsigned long start;
u32 len;
if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
return -EINVAL;
off = vma->vm_pgoff << PAGE_SHIFT;
if (!fb)
return -ENODEV;
mutex_lock(&info->mm_lock);
//没有注册mmap所以没进入
if (fb->fb_mmap) {
printk("mmap-1\n");
int res;
res = fb->fb_mmap(info, vma);
mutex_unlock(&info->mm_lock);
return res;
}
// 走如下路径
/* frame buffer memory */
start = info->fix.smem_start;
len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
printk("mmap-start=0x%x,len=%d\n",start,len);
if (off >= len) {
printk("mmap-off=0x%x\n",off);
/* memory mapped io */
off -= len;
if (info->var.accel_flags) {
mutex_unlock(&info->mm_lock);
return -EINVAL;
}
start = info->fix.mmio_start;
len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
}
mutex_unlock(&info->mm_lock);
start &= PAGE_MASK;
if ((vma->vm_end - vma->vm_start + off) > len)
return -EINVAL;
off += start;
vma->vm_pgoff = off >> PAGE_SHIFT;
/* This is an IO map - tell maydump to skip this VMA */
vma->vm_flags |= VM_IO | VM_RESERVED;
fb_pgprotect(file, vma, off);
printk("mmap-2\n");
if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
return 0;
}
三,调试
之前我记得fbtft还使用了通用的mmap,并且开启了defio。s3c2410bf.c中没有使用自己的mmap,我添加调试信息来验证,打印输出的结果也如此,实际仿真与理解一致。见下图左下角log。