s3c2410 framebuffer驱动中的mmap分析备忘

原文地址:http://hi.baidu.com/deep_pro/blog/item/4d5f2003122d3b83d53f7c73.html

这几天的高级驱动课真是听得happy,块设备、MTD设备讲的真是框架清晰,豁然开朗
趁着还热乎,有空,记录下s3c2410 framebuffer驱动中的mmap的实现,留待以后实现自己的物理内存映射时参考
此前也就是会掉mmap,如何在内核空间自己实现一个mmap还没有概念
s3c2410fb.c中的fb_ops里并没有mmap的实现,fb是老牌设备驱动了,发展成为一个子系统,所以缺什么实现都是放在更高层的代码里了。

s3c2410fb.c -》s3c24xxfb_probe-》s3c2410fb_map_video_memory -》
info->screen_base = dma_alloc_writecombine(fbi->dev, map_size, &map_dma, GFP_KERNEL);
info->fix.smem_start = map_dma;

从dma内存空间得到了一片物理内存,物理起始地址位于map_dma
info->screen_base 虽然得到的是虚拟地址,但是是属于内核空间的虚拟地址

然后在fbmem.c 中,
static int
fb_mmap(struct file *file, struct vm_area_struct * vma)
__acquires(&info->lock)
__releases(&info->lock)
{
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;
//如果在fb_ops里实现了fb_mmap,调用用户自己实现的fb_mmap即可,如前所述,这里没有实现。
if (fb->fb_mmap) {
   int res;
   mutex_lock(&info->lock);
   res = fb->fb_mmap(info, vma);
   mutex_unlock(&info->lock);
   return res;
}

mutex_lock(&info->lock);

/* frame buffer memory */
start = info->fix.smem_start;
//起始地址是页对齐的
len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
//mmap中的off含义根据具体的驱动不同而不同
//显卡设备里往往是用作把显卡寄存器也直接映射给用户空间,加速操作
if (off >= len) {
   /* memory mapped io */
   off -= len;
   if (info->var.accel_flags) {
    mutex_unlock(&info->lock);
    return -EINVAL;
   }
   start = info->fix.mmio_start;
   len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
}
mutex_unlock(&info->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);
//正式映射物理内存到用户空间虚拟地址
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;
}

 

你可能感兴趣的:(Linux)