/* * 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 * */ #include #include #include #include /* Required on Alpha, from Bob McElrath */ #include /* Required on Alpha */ #include /* Required on Alpha */ #include /* pmd_offset requires this on SuSE supplied kernels */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) #define MAP_NR virt_to_page #endif /* * Given PGD from the address space's page table, return the kernel * virtual mapping of the physical memory mapped at ADR. */ 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)) { #ifdef pte_offset /* Check if it is not a kernel using the new rmap-vm */ ptep = pte_offset(pmd, adr); #else ptep = pte_offset_map(pmd, adr); #endif pte = *ptep; if(pte_present(pte)) { ret = (unsigned long) page_address(pte_page(pte)); ret |= (adr & (PAGE_SIZE - 1)); } } } return ret; } inline unsigned long uvirt_to_bus(unsigned long adr) { unsigned long kva, ret; kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr); ret = virt_to_bus((void *) kva); return ret; } inline unsigned long kvirt_to_bus(unsigned long adr) { unsigned long va, kva, ret; va = VMALLOC_VMADDR(adr); kva = uvirt_to_kva(pgd_offset_k(va), va); ret = virt_to_bus((void *) kva); return ret; } /* * Here we want the physical address of the memory. * This is used when initializing the contents of the * area and marking the pages as reserved. */ inline 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; } void *rvmalloc(unsigned long size) { void *mem; unsigned long adr, page; /* Round it off to PAGE_SIZE */ size += (PAGE_SIZE - 1); size &= ~(PAGE_SIZE - 1); mem = vmalloc(size); if(!mem) return NULL; memset(mem, 0, size); /* Clear the ram out, no junk to the user */ adr = (unsigned long) mem; while(size > 0) { page = kvirt_to_pa(adr); mem_map_reserve(MAP_NR(__va(page))); adr += PAGE_SIZE; if(size > PAGE_SIZE) size -= PAGE_SIZE; else size = 0; } return mem; } void rvfree(void *mem, unsigned long size) { unsigned long adr, page; if(!mem) return; size += (PAGE_SIZE - 1); size &= ~(PAGE_SIZE - 1); adr = (unsigned long) mem; while(size > 0) { page = kvirt_to_pa(adr); mem_map_unreserve(MAP_NR(__va(page))); adr += PAGE_SIZE; if(size > PAGE_SIZE) size -= PAGE_SIZE; else size = 0; } vfree(mem); }