⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qc-memory.c

📁 在Linux下用于webeye的摄像头的驱动
💻 C
字号:
/* Start of file *//* {{{ [fold] Comments *//* * qce-ga, linux V4L driver for the QuickCam Express and Dexxa QuickCam * * memory.c - contains all needed memory management functions * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * */ /* These routines have been derived from the ov511 driver, into which they * were derived from the bttv driver. *//* }}} *//* {{{ [fold] Includes */#include <linux/config.h>#include <linux/version.h>#ifdef CONFIG_SMP#define __SMP__#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)#define MODVERSIONS#endif#ifdef MODVERSIONS#include <linux/modversions.h>#endif#endif#include "qc-memory.h"#include <asm/io.h>#include <linux/mm.h>		/* Required on Alpha, from Bob McElrath <mcelrath@draal.physics.wisc.edu> */#include <asm/pgtable.h>	/* Required on Alpha */#include <linux/vmalloc.h>	/* Required on Alpha */#include <linux/pagemap.h>	/* pmd_offset requires this on SuSE supplied kernels */#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)#include <linux/wrapper.h>	/* For proper mem_map_(un)reserve define, the compatibility define below might not work */#endif/* }}} *//* {{{ [fold] Compatibility wrappers */#ifndef HAVE_VMA#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,5,3) || (defined(RED_HAT_LINUX_KERNEL) && defined(pte_offset_map))#define HAVE_VMA 1#else#define HAVE_VMA 0#endif#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)#if HAVE_VMA#warning "HAVE_VMA=1"/* remap_page_range is still emulated in 2.6.10, in 2.6.11 it's completely removed */static inline int qc_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long pfn, unsigned long size, pgprot_t prot) { return remap_page_range(vma, from, pfn<<PAGE_SHIFT, size, prot); }#undef remap_pfn_range#define remap_pfn_range(vma, from, pfn, size, prot)	qc_remap_page_range((vma), (from), (pfn), (size), (prot))#else#warning "HAVE_VMA=0"static inline int qc_remap_page_range(unsigned long from, unsigned long pfn, unsigned long size, pgprot_t prot) { return remap_page_range(from, pfn<<PAGE_SHIFT, size, prot); }#undef remap_pfn_range#define remap_pfn_range(vma, from, pfn, size, prot)	qc_remap_page_range((from),(pfn),(size),(prot))#endif#endif#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,5,3) || defined(pte_offset_map)#define pte_offset(pmd,adr)	pte_offset_map(pmd,adr)	/* Emulation for a kernel using the new rmap-vm */#endif							/* Fix by Michele Balistreri <brain87@gmx.net> */#ifndef SetPageReserved#define SetPageReserved(p)	mem_map_reserve(p)#endif#ifndef ClearPageReserved#define ClearPageReserved(p)	mem_map_unreserve(p)#endif/* }}} *//* {{{ [fold] kvirt_to_pa(): obtain physical address from virtual address obtained by vmalloc() */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)/* {{{ [fold] kvirt_to_pa(), 2.4.x and 2.6.x */#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)static struct page *vmalloc_to_page(void * vmalloc_addr);#endif/* Here we want the physical address of the memory obtained by vmalloc(). */static inline unsigned long kvirt_to_pa(unsigned long adr){	unsigned long kva, ret;	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));	kva |= adr & (PAGE_SIZE-1); /* restore the offset */	ret = __pa(kva);	return ret;}/* }}} */#else/* {{{ [fold] kvirt_to_pa() for 2.2.x */#define page_address(x)		(x | PAGE_OFFSET)	/* Damn ugly hack from kcomp.h; replaces original page_address() that made different thing! *//* Given PGD from the address space's page table, return the kernel * virtual mapping of the physical memory mapped at ADR. */static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr){	unsigned long ret = 0UL;	pmd_t *pmd;	pte_t *ptep, pte;	if (!pgd_none(*pgd)) {		pmd = pmd_offset(pgd, adr);		if (!pmd_none(*pmd)) {			ptep = pte_offset(pmd, adr);			pte = *ptep;			if (pte_present(pte)) {				ret = (unsigned long) page_address(pte_page(pte));				ret |= (adr & (PAGE_SIZE - 1));			}		}	}	return ret;}/* Here we want the physical address of the memory obtained by vmalloc(). * This is used when initializing the contents of the * area and marking the pages as reserved. */static unsigned long kvirt_to_pa(unsigned long adr){	unsigned long va, kva, ret;	va = VMALLOC_VMADDR(adr);	kva = uvirt_to_kva(pgd_offset_k(va), va);	ret = __pa(kva);	return ret;}/* }}} */#endif/* }}} *//* {{{ [fold] vmalloc_to_page(): obtain pointer to struct page from virtual address obtained by vmalloc() */#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,4,0) && LINUX_VERSION_CODE<KERNEL_VERSION(2,4,19)/* {{{ [fold] vmalloc_to_page() for 2.4.x (returns pointer to page) */static struct page *vmalloc_to_page(void * vmalloc_addr){	unsigned long addr = (unsigned long) vmalloc_addr;	struct page *page = NULL;	pmd_t *pmd;	pte_t *pte;	pgd_t *pgd;	pgd = pgd_offset_k(addr);	if (!pgd_none(*pgd)) {		pmd = pmd_offset(pgd, addr);		if (!pmd_none(*pmd)) {			pte = pte_offset(pmd, addr);			if (pte_present(*pte)) {				page = pte_page(*pte);			}		}	}	return page;}/* }}} */#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)/* {{{ [fold] vmalloc_to_page() for 2.2.x (returns page index in mem_map[]) */static inline unsigned long vmalloc_to_page(void * vmalloc_addr){	unsigned long pagenum;	unsigned long physaddr;	physaddr = kvirt_to_pa((unsigned long)vmalloc_addr);	pagenum = MAP_NR(__va(physaddr));	return pagenum;}/* }}} */#endif/* }}} *//* {{{ [fold] qc_mm_rvmalloc(size) */void *qc_mm_rvmalloc(unsigned long size){	void *mem;	unsigned long adr;	size = PAGE_ALIGN(size);	mem = vmalloc_32(size);	if (!mem)		return NULL;	memset(mem, 0, size); /* Clear the ram out, no junk to the user */	adr = (unsigned long) mem;	while ((long)size > 0) {		SetPageReserved(vmalloc_to_page((void *)adr));		adr += PAGE_SIZE;		size -= PAGE_SIZE;	}	return mem;}/* }}} *//* {{{ [fold] qc_mm_rvfree(mem, size) */void qc_mm_rvfree(void *mem, unsigned long size){	unsigned long adr;	if (!mem)		return;	adr = (unsigned long) mem;	while ((long) size > 0) {		ClearPageReserved(vmalloc_to_page((void *)adr));		adr += PAGE_SIZE;		size -= PAGE_SIZE;	}	vfree(mem);}/* }}} *//* {{{ [fold] qc_mm_remap(vma, src, src_size, dst, dst_size) */int qc_mm_remap(struct vm_area_struct *vma, void *src, unsigned long src_size, const void *dst, unsigned long dst_size){	unsigned long start = (unsigned long)dst;	unsigned long size  = dst_size;	unsigned long physaddr, pos;	pos = (unsigned long)src;	while ((long)size > 0) {		physaddr = kvirt_to_pa(pos);#if 1		if ((physaddr & ~PAGE_MASK)!=0) {			printk(KERN_CRIT "qc_mm_remap: physaddr=%08X not page aligned!\n", (int)physaddr);			return -EIO;		}#endif		if (remap_pfn_range(vma, start, physaddr>>PAGE_SHIFT, PAGE_SIZE, PAGE_SHARED))			return -EAGAIN;		start += PAGE_SIZE;		pos += PAGE_SIZE;		size -= PAGE_SIZE;	}	return 0;}/* }}} *//* End of file */

⌨️ 快捷键说明

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