--- linux-2.4.0-test6/drivers/video/controlfb.c Fri Aug 18 23:09:26 2000 +++ linux-2.4.0-test7/drivers/video/controlfb.c Sat Aug 19 17:47:49 2000 @@ -127,6 +127,8 @@ struct fb_info *info); static int control_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); +static int control_mmap(struct fb_info *info, struct file *file, + struct vm_area_struct *vma); static int controlfb_getcolreg(u_int regno, u_int *red, u_int *green, @@ -176,6 +178,7 @@ fb_get_cmap: control_get_cmap, fb_set_cmap: control_set_cmap, fb_pan_display: control_pan_display, + fb_mmap: control_mmap, }; @@ -332,6 +335,50 @@ return 0; } +/* Private mmap since we want to have a different caching on the framebuffer + * for controlfb. + * Note there's no locking in here; it's done in fb_mmap() in fbmem.c. + */ +static int control_mmap(struct fb_info *info, struct file *file, + struct vm_area_struct *vma) +{ + struct fb_ops *fb = info->fbops; + struct fb_fix_screeninfo fix; + struct fb_var_screeninfo var; + unsigned long off, start; + u32 len; + + fb->fb_get_fix(&fix, PROC_CONSOLE(info), info); + off = vma->vm_pgoff << PAGE_SHIFT; + + /* frame buffer memory */ + start = fix.smem_start; + len = PAGE_ALIGN((start & ~PAGE_MASK)+fix.smem_len); + if (off >= len) { + /* memory mapped io */ + off -= len; + fb->fb_get_var(&var, PROC_CONSOLE(info), info); + if (var.accel_flags) + return -EINVAL; + start = fix.mmio_start; + len = PAGE_ALIGN((start & ~PAGE_MASK)+fix.mmio_len); + pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED; + } else { + /* framebuffer */ + pgprot_val(vma->vm_page_prot) |= _PAGE_WRITETHRU; + } + start &= PAGE_MASK; + if ((vma->vm_end - vma->vm_start + off) > len) + return -EINVAL; + off += start; + vma->vm_pgoff = off >> PAGE_SHIFT; + if (io_remap_page_range(vma->vm_start, off, + vma->vm_end - vma->vm_start, vma->vm_page_prot)) + return -EAGAIN; + + return 0; +} + /******************** End of controlfb_ops implementation ********************/ /* (new one that is) */