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

📄 dhahelper.c

📁 原名叫avifile
💻 C
📖 第 1 页 / 共 2 页
字号:
/*    Direct Hardware Access kernel helper        (C) 2002 Alex Beregszaszi <alex@naxine.org>    (C) 2002-2003 Nick Kurshev <nickols_k@mail.ru>    Accessing hardware from userspace as USER (no root needed!)    Tested on 2.2.x (2.2.19) and 2.4.x (2.4.3,2.4.17).        License: GPL        WARNING! THIS MODULE VIOLATES SEVERAL SECURITY LINES! DON'T USE IT    ON PRODUCTION SYSTEMS, ONLY AT HOME, ON A "SINGLE-USER" SYSTEM.    NO WARRANTY!        IF YOU WANT TO USE IT ON PRODUCTION SYSTEMS THEN PLEASE READ 'README'    FILE TO KNOW HOW TO PREVENT ANONYMOUS ACCESS TO THIS MODULE.    Tech:	Communication between userspace and kernelspace goes over character	device using ioctl.    Usage:	mknod -m 666 /dev/dhahelper c 180 0		Also you can change the major number, setting the "dhahelper_major"	module parameter, the default is 180, specified in dhahelper.h.		Note: do not use other than minor==0, the module forbids it.    TODO:	* select (request?) a "valid" major number (from Linux project? ;)	* make security	* is pci handling needed? (libdha does this with lowlevel port funcs)	* is mttr handling needed?	* test on older kernels (2.0.x (?))*/#ifndef MODULE#define MODULE#endif#ifndef __KERNEL__#define __KERNEL__#endif#include <linux/config.h>#ifdef CONFIG_MODVERSION#define MODVERSION#include <linux/modversions.h>#endif#include <linux/version.h>#include <linux/module.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/mm.h>#include <linux/pagemap.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/interrupt.h>#include <linux/wrapper.h>#include <linux/vmalloc.h>#include <linux/string.h>#include <linux/errno.h>#include <asm/io.h>#include <asm/pgtable.h>#include <asm/unistd.h>#include <asm/uaccess.h>#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)#include <linux/malloc.h>#else#include <linux/slab.h>#endif#include <linux/pci.h>#include <linux/ioport.h>#include <linux/init.h>#include <asm/uaccess.h>#include <asm/system.h>#include <asm/io.h>#include <linux/mman.h>#include <linux/fs.h>#include <linux/unistd.h>#ifdef CONFIG_MTRR #include <asm/mtrr.h>#endif#ifdef CONFIG_DEVFS_FS#include <linux/devfs_fs_kernel.h>#endif#include "dhahelper.h"#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)#define DEV_MINOR(d) minor(d)#define pte_offset(p,a) pte_offset_kernel(p,a)#define LockPage(p) SetPageLocked(p)#define UnlockPage(p) ClearPageLocked(p)#else#define DEV_MINOR(d) MINOR(d)#endifMODULE_AUTHOR("Alex Beregszaszi <alex@naxine.org>, Nick Kurshev <nickols_k@mail.ru>, M錸s Rullg錼d <mru@users.sf.net>");MODULE_DESCRIPTION("Provides userspace access to hardware");#ifdef MODULE_LICENSEMODULE_LICENSE("GPL");#endifstatic int dhahelper_major = DEFAULT_MAJOR;MODULE_PARM(dhahelper_major, "i");MODULE_PARM_DESC(dhahelper_major, "Major number of dhahelper characterdevice");/* 0 = silent *//* 1 = report errors (default) *//* 2 = debug */static int dhahelper_verbosity = 1;MODULE_PARM(dhahelper_verbosity, "i");MODULE_PARM_DESC(dhahelper_verbosity, "Level of verbosity (0 = silent, 1 = only errors, 2 = debug)");static int dhahelper_open(struct inode *inode, struct file *file){    if (dhahelper_verbosity > 1)	printk(KERN_DEBUG "dhahelper: device opened\n");    if (DEV_MINOR(inode->i_rdev) != 0)	return -ENXIO;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)    MOD_INC_USE_COUNT;#endif    return 0;}static int dhahelper_release(struct inode *inode, struct file *file){    if (dhahelper_verbosity > 1)	printk(KERN_DEBUG "dhahelper: device released\n");    if (DEV_MINOR(inode->i_rdev) != 0)	return -ENXIO;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)    MOD_DEC_USE_COUNT;#endif    return 0;}static int dhahelper_get_version(int * arg){	int version = API_VERSION;	if (copy_to_user(arg, &version, sizeof(int)))	{		if (dhahelper_verbosity > 0)		    printk(KERN_ERR "dhahelper: failed copy to userspace\n");		return -EFAULT;	}	return 0;}static int dhahelper_port(dhahelper_port_t * arg){	dhahelper_port_t port;	if (copy_from_user(&port, arg, sizeof(dhahelper_port_t)))	{		if (dhahelper_verbosity > 0)		    printk(KERN_ERR "dhahelper: failed copy from userspace\n");		return -EFAULT;	}	switch(port.operation)	{		case PORT_OP_READ:		{		    switch(port.size)		    {			case 1:			    port.value = inb(port.addr);			    break;			case 2:			    port.value = inw(port.addr);			    break;			case 4:			    port.value = inl(port.addr);			    break;			default:			    if (dhahelper_verbosity > 0)				printk(KERN_ERR "dhahelper: invalid port read size (%d)\n",				    port.size);			    return -EINVAL;		    }		    break;		}		case PORT_OP_WRITE:		{		    switch(port.size)		    {			case 1:			    outb(port.value, port.addr);			    break;			case 2:			    outw(port.value, port.addr);			    break;			case 4:			    outl(port.value, port.addr);			    break;			default:			    if (dhahelper_verbosity > 0)				printk(KERN_ERR "dhahelper: invalid port write size (%d)\n",				    port.size);			    return -EINVAL;		    }		    break;		}		default:		    if (dhahelper_verbosity > 0)		        printk(KERN_ERR "dhahelper: invalid port operation (%d)\n",		    	    port.operation);		    return -EINVAL;	}	/* copy back only if read was performed */	if (port.operation == PORT_OP_READ)	if (copy_to_user(arg, &port, sizeof(dhahelper_port_t)))	{		if (dhahelper_verbosity > 0)		    printk(KERN_ERR "dhahelper: failed copy to userspace\n");		return -EFAULT;	}	return 0;}/*******************************//* Memory management functions *//* from kernel:/drivers/media/video/bttv-driver.c *//*******************************/#define MDEBUG(x)	do { } while(0)		/* Debug memory management *//* [DaveM] I've recoded most of this so that: * 1) It's easier to tell what is happening * 2) It's more portable, especially for translating things *    out of vmalloc mapped areas in the kernel. * 3) Less unnecessary translations happen. * * The code used to assume that the kernel vmalloc mappings * existed in the page tables of every process, this is simply * not guarenteed.  We now use pgd_offset_k which is the * defined way to get at the kernel page tables. *//* 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));							}                }        }        MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret));	return ret;}static 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);        MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret));        return ret;}static inline unsigned long uvirt_to_pa(unsigned long adr) {        unsigned long kva, ret;        kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr);	ret = virt_to_phys((void *)kva);        MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret));        return ret;}static 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);        MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret));        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. */static 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);        MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));        return ret;}static void * rvmalloc(signed long size){	void * mem;	unsigned long adr, page;	mem=vmalloc_32(size);	if (mem) 	{		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(virt_to_page(__va(page)));			adr+=PAGE_SIZE;			size-=PAGE_SIZE;		}	}	return mem;}static int pag_lock(unsigned long addr){	unsigned long page;	unsigned long kva;	kva = uvirt_to_kva(pgd_offset(current->mm, addr), addr);	if(kva)	{	    lock_it:	    page = uvirt_to_pa((unsigned long)addr);	    LockPage(virt_to_page(__va(page)));	    SetPageReserved(virt_to_page(__va(page)));	}	else	{	    copy_from_user(&page,(char *)addr,1); /* try access it */	    kva = uvirt_to_kva(pgd_offset(current->mm, addr), addr);	    if(kva) goto lock_it;	    else return EPERM;	}	return 0;}static int pag_unlock(unsigned long addr){	    unsigned long page;	    unsigned long kva;	    kva = uvirt_to_kva(pgd_offset(current->mm, addr), addr);	    if(kva)	    {		page = uvirt_to_pa((unsigned long)addr);		UnlockPage(virt_to_page(__va(page)));		ClearPageReserved(virt_to_page(__va(page)));		return 0;	    }	    return EPERM;}static void rvfree(void * mem, signed long size){        unsigned long adr, page;        	if (mem) 	{	        adr=(unsigned long) mem;		while (size > 0)                 {	                page = kvirt_to_pa(adr);			mem_map_unreserve(virt_to_page(__va(page)));			adr+=PAGE_SIZE;			size-=PAGE_SIZE;		}		vfree(mem);	}}static int dhahelper_virt_to_phys(dhahelper_vmi_t *arg){	dhahelper_vmi_t mem;	unsigned long i,nitems;	char *addr;	if (copy_from_user(&mem, arg, sizeof(dhahelper_vmi_t)))	{		if (dhahelper_verbosity > 0)		    printk(KERN_ERR "dhahelper: failed copy from userspace\n");		return -EFAULT;	}	nitems = mem.length / PAGE_SIZE;	if(mem.length % PAGE_SIZE) nitems++;	addr = mem.virtaddr;	for(i=0;i<nitems;i++)	{	    unsigned long result;	    result = uvirt_to_pa((unsigned long)addr);	    if (copy_to_user(&mem.realaddr[i], &result, sizeof(unsigned long)))	    {		if (dhahelper_verbosity > 0)		    printk(KERN_ERR "dhahelper: failed copy to userspace\n");		return -EFAULT;	    }	    addr += PAGE_SIZE;	}	return 0;}static int dhahelper_virt_to_bus(dhahelper_vmi_t *arg){	dhahelper_vmi_t mem;	unsigned long i,nitems;	char *addr;	if (copy_from_user(&mem, arg, sizeof(dhahelper_vmi_t)))	{		if (dhahelper_verbosity > 0)		    printk(KERN_ERR "dhahelper: failed copy from userspace\n");		return -EFAULT;	}	nitems = mem.length / PAGE_SIZE;	if(mem.length % PAGE_SIZE) nitems++;	addr = mem.virtaddr;	for(i=0;i<nitems;i++)	{	    unsigned long result;	    result = uvirt_to_bus((unsigned long)addr);	    if (copy_to_user(&mem.realaddr[i], &result, sizeof(unsigned long)))	    {		if (dhahelper_verbosity > 0)		    printk(KERN_ERR "dhahelper: failed copy to userspace\n");		return -EFAULT;	    }	    addr += PAGE_SIZE;	}	return 0;}static int dhahelper_alloc_pa(dhahelper_mem_t *arg){	dhahelper_mem_t mem;	if (copy_from_user(&mem, arg, sizeof(dhahelper_mem_t)))	{		if (dhahelper_verbosity > 0)		    printk(KERN_ERR "dhahelper: failed copy from userspace\n");		return -EFAULT;	}	mem.addr = rvmalloc(mem.length);	if (copy_to_user(arg, &mem, sizeof(dhahelper_mem_t)))	{		if (dhahelper_verbosity > 0)		    printk(KERN_ERR "dhahelper: failed copy to userspace\n");		return -EFAULT;	}	return 0;}static int dhahelper_free_pa(dhahelper_mem_t *arg){	dhahelper_mem_t mem;	if (copy_from_user(&mem, arg, sizeof(dhahelper_mem_t)))	{		if (dhahelper_verbosity > 0)		    printk(KERN_ERR "dhahelper: failed copy from userspace\n");		return -EFAULT;	}	rvfree(mem.addr,mem.length);	return 0;}static int dhahelper_lock_mem(dhahelper_mem_t *arg){	dhahelper_mem_t mem;	int retval;	unsigned long i,nitems,addr;	if (copy_from_user(&mem, arg, sizeof(dhahelper_mem_t)))	{		if (dhahelper_verbosity > 0)		    printk(KERN_ERR "dhahelper: failed copy from userspace\n");		return -EFAULT;	}	nitems = mem.length / PAGE_SIZE;	if(mem.length % PAGE_SIZE) nitems++;	addr = (unsigned long)mem.addr;	for(i=0;i<nitems;i++)	{	    retval = pag_lock((unsigned long)addr);	    if(retval)	    {		unsigned long j;		addr = (unsigned long)mem.addr;		for(j=0;j<i;j++)		{		    pag_unlock(addr);		    addr +=  PAGE_SIZE;		}		return retval;	    }	    addr += PAGE_SIZE;	}	return 0;}static int dhahelper_unlock_mem(dhahelper_mem_t *arg){	dhahelper_mem_t mem;	int retval;	unsigned long i,nitems,addr;	if (copy_from_user(&mem, arg, sizeof(dhahelper_mem_t)))	{		if (dhahelper_verbosity > 0)		    printk(KERN_ERR "dhahelper: failed copy from userspace\n");		return -EFAULT;	}	nitems = mem.length / PAGE_SIZE;	if(mem.length % PAGE_SIZE) nitems++;	addr = (unsigned long)mem.addr;	for(i=0;i<nitems;i++)	{	    retval = pag_unlock((unsigned long)addr);	    if(retval) return retval;	    addr += PAGE_SIZE;	}	return 0;}static struct dha_irq {    spinlock_t lock;    long flags;    int handled;    int rcvd;    volatile u32 *ack_addr;    u32 ack_data;    struct pci_dev *dev;    wait_queue_head_t wait;    unsigned long count;} dha_irqs[256];static void dhahelper_irq_handler(int irq, void *dev_id, struct pt_regs *regs){    spin_lock_irqsave(&dha_irqs[irq].lock, dha_irqs[irq].flags);    if(dha_irqs[irq].handled){	dha_irqs[irq].rcvd = 1;	dha_irqs[irq].count++;	if(dha_irqs[irq].ack_addr){	    *dha_irqs[irq].ack_addr = dha_irqs[irq].ack_data;	    mb();	}	wake_up_interruptible(&dha_irqs[irq].wait);    }    spin_unlock_irqrestore(&dha_irqs[irq].lock, dha_irqs[irq].flags);}static int dhahelper_install_irq(dhahelper_irq_t *arg){    dhahelper_irq_t my_irq;    struct pci_dev *pci;    long rlen;    int retval;    long ack_addr;    int irqn;    if (copy_from_user(&my_irq, arg, sizeof(dhahelper_irq_t)))    {	if (dhahelper_verbosity > 0)	    printk(KERN_ERR "dhahelper: failed copy from userspace\n");	return -EFAULT;    }    if(!(pci = pci_find_slot(my_irq.bus, PCI_DEVFN(my_irq.dev, my_irq.func))))	return -EINVAL;

⌨️ 快捷键说明

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