fb_defio.c

来自「linux 内核源代码」· C语言 代码 · 共 151 行

C
151
字号
/* *  linux/drivers/video/fb_defio.c * *  Copyright (C) 2006 Jaya Kumar * * This file is subject to the terms and conditions of the GNU General Public * License.  See the file COPYING in the main directory of this archive * for more details. */#include <linux/module.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/fb.h>#include <linux/list.h>/* to support deferred IO */#include <linux/rmap.h>#include <linux/pagemap.h>/* this is to find and return the vmalloc-ed fb pages */static struct page* fb_deferred_io_nopage(struct vm_area_struct *vma,					unsigned long vaddr, int *type){	unsigned long offset;	struct page *page;	struct fb_info *info = vma->vm_private_data;	/* info->screen_base is in System RAM */	void *screen_base = (void __force *) info->screen_base;	offset = (vaddr - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);	if (offset >= info->fix.smem_len)		return NOPAGE_SIGBUS;	page = vmalloc_to_page(screen_base + offset);	if (!page)		return NOPAGE_OOM;	get_page(page);	if (type)		*type = VM_FAULT_MINOR;	return page;}int fb_deferred_io_fsync(struct file *file, struct dentry *dentry, int datasync){	struct fb_info *info = file->private_data;	/* Kill off the delayed work */	cancel_rearming_delayed_work(&info->deferred_work);	/* Run it immediately */	return schedule_delayed_work(&info->deferred_work, 0);}EXPORT_SYMBOL_GPL(fb_deferred_io_fsync);/* vm_ops->page_mkwrite handler */static int fb_deferred_io_mkwrite(struct vm_area_struct *vma,				  struct page *page){	struct fb_info *info = vma->vm_private_data;	struct fb_deferred_io *fbdefio = info->fbdefio;	/* this is a callback we get when userspace first tries to	write to the page. we schedule a workqueue. that workqueue	will eventually mkclean the touched pages and execute the	deferred framebuffer IO. then if userspace touches a page	again, we repeat the same scheme */	/* protect against the workqueue changing the page list */	mutex_lock(&fbdefio->lock);	list_add(&page->lru, &fbdefio->pagelist);	mutex_unlock(&fbdefio->lock);	/* come back after delay to process the deferred IO */	schedule_delayed_work(&info->deferred_work, fbdefio->delay);	return 0;}static struct vm_operations_struct fb_deferred_io_vm_ops = {	.nopage   	= fb_deferred_io_nopage,	.page_mkwrite	= fb_deferred_io_mkwrite,};static int fb_deferred_io_mmap(struct fb_info *info, struct vm_area_struct *vma){	vma->vm_ops = &fb_deferred_io_vm_ops;	vma->vm_flags |= ( VM_IO | VM_RESERVED | VM_DONTEXPAND );	vma->vm_private_data = info;	return 0;}/* workqueue callback */static void fb_deferred_io_work(struct work_struct *work){	struct fb_info *info = container_of(work, struct fb_info,						deferred_work.work);	struct list_head *node, *next;	struct page *cur;	struct fb_deferred_io *fbdefio = info->fbdefio;	/* here we mkclean the pages, then do all deferred IO */	mutex_lock(&fbdefio->lock);	list_for_each_entry(cur, &fbdefio->pagelist, lru) {		lock_page(cur);		page_mkclean(cur);		unlock_page(cur);	}	/* driver's callback with pagelist */	fbdefio->deferred_io(info, &fbdefio->pagelist);	/* clear the list */	list_for_each_safe(node, next, &fbdefio->pagelist) {		list_del(node);	}	mutex_unlock(&fbdefio->lock);}void fb_deferred_io_init(struct fb_info *info){	struct fb_deferred_io *fbdefio = info->fbdefio;	BUG_ON(!fbdefio);	mutex_init(&fbdefio->lock);	info->fbops->fb_mmap = fb_deferred_io_mmap;	INIT_DELAYED_WORK(&info->deferred_work, fb_deferred_io_work);	INIT_LIST_HEAD(&fbdefio->pagelist);	if (fbdefio->delay == 0) /* set a default of 1 s */		fbdefio->delay = HZ;}EXPORT_SYMBOL_GPL(fb_deferred_io_init);void fb_deferred_io_cleanup(struct fb_info *info){	struct fb_deferred_io *fbdefio = info->fbdefio;	BUG_ON(!fbdefio);	cancel_delayed_work(&info->deferred_work);	flush_scheduled_work();}EXPORT_SYMBOL_GPL(fb_deferred_io_cleanup);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?