summaryrefslogtreecommitdiff
path: root/src/video_out/libdha/kernelhelper/dhahelper.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_out/libdha/kernelhelper/dhahelper.c')
-rw-r--r--src/video_out/libdha/kernelhelper/dhahelper.c1239
1 files changed, 0 insertions, 1239 deletions
diff --git a/src/video_out/libdha/kernelhelper/dhahelper.c b/src/video_out/libdha/kernelhelper/dhahelper.c
deleted file mode 100644
index 0e755064a..000000000
--- a/src/video_out/libdha/kernelhelper/dhahelper.c
+++ /dev/null
@@ -1,1239 +0,0 @@
-/*
- Direct Hardware Access kernel helper
-
- (C) 2002 Alex Beregszaszi <alex@naxine.org>
- (C) 2002-2003 Nick Kurshev <nickols_k@mail.ru>
- (C) 2002-2004 Måns Rullgård <mru@users.sourceforge.net>
-
- Accessing hardware from userspace as USER (no root needed!)
-
- Tested on 2.2.x (2.2.19), 2.4.x (2.4.3,2.4.17) and 2.6.1.
-
- 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 600 /dev/dhahelper c 252 0
-
- Also you can change the major number, setting the "dhahelper_major"
- module parameter, the default is 252, 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/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,6,0)
-#define pte_offset(p,a) pte_offset_kernel(p,a)
-#define LockPage(p) SetPageLocked(p)
-#define UnlockPage(p) ClearPageLocked(p)
-#define irqreturn(n) return(n)
-#else
-#define irqreturn_t void
-#define irqreturn(n) return
-#endif
-
-MODULE_AUTHOR("Alex Beregszaszi <alex@naxine.org>, Nick Kurshev <nickols_k@mail.ru>, Måns Rullgård <mru@users.sf.net>");
-MODULE_DESCRIPTION("Provides userspace access to hardware");
-#ifdef MODULE_LICENSE
-MODULE_LICENSE("GPL");
-#endif
-
-static 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 (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 (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 va)
-{
- unsigned long kva, ret;
-
- 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 va)
-{
- unsigned long kva, ret;
-
- 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);
- SetPageReserved(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);
- ClearPageReserved(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;
- unsigned 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 irqreturn_t 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);
- irqreturn(0);
-}
-
-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;
-
- rlen = pci_resource_len(pci, my_irq.ack_region);
- if(my_irq.ack_offset > rlen - 4)
- return -EINVAL;
-
- irqn = pci->irq;
-
- spin_lock_irqsave(&dha_irqs[irqn].lock,
- dha_irqs[irqn].flags);
-
- if(dha_irqs[irqn].handled){
- retval = -EBUSY;
- goto fail;
- }
-
- if(my_irq.ack_region >= 0){
- ack_addr = pci_resource_start(pci, my_irq.ack_region);
- ack_addr += my_irq.ack_offset;
-#ifdef CONFIG_ALPHA
- ack_addr += ((struct pci_controller *) pci->sysdata)->dense_mem_base;
-#endif
- /* FIXME: Other architectures */
-
- dha_irqs[irqn].ack_addr = phys_to_virt(ack_addr);
- dha_irqs[irqn].ack_data = my_irq.ack_data;
- } else {
- dha_irqs[irqn].ack_addr = 0;
- }
-
- dha_irqs[irqn].lock = SPIN_LOCK_UNLOCKED;
- dha_irqs[irqn].flags = 0;
- dha_irqs[irqn].rcvd = 0;
- dha_irqs[irqn].dev = pci;
- init_waitqueue_head(&dha_irqs[irqn].wait);
- dha_irqs[irqn].count = 0;
-
- retval = request_irq(irqn, dhahelper_irq_handler,
- SA_SHIRQ, "dhahelper", pci);
-
- if(retval < 0)
- goto fail;
-
- copy_to_user(&arg->num, &irqn, sizeof(irqn));
-
- dha_irqs[irqn].handled = 1;
-
-out:
- spin_unlock_irqrestore(&dha_irqs[irqn].lock,
- dha_irqs[irqn].flags);
- return retval;
-
-fail:
- if(retval == -EINVAL){
- printk("dhahelper: bad irq number or handler\n");
- } else if(retval == -EBUSY){
- printk("dhahelper: IRQ %u busy\n", irqn);
- } else {
- printk("dhahelper: Could not install irq handler...\n");
- }
- printk("dhahelper: Perhaps you need to let your BIOS assign an IRQ to your video card\n");
- goto out;
-}
-
-static int dhahelper_free_irq(dhahelper_irq_t *arg)
-{
- dhahelper_irq_t irq;
- struct pci_dev *pci;
- int irqn;
-
- if (copy_from_user(&irq, arg, sizeof(dhahelper_irq_t)))
- {
- if (dhahelper_verbosity > 0)
- printk(KERN_ERR "dhahelper: failed copy from userspace\n");
- return -EFAULT;
- }
-
- pci = pci_find_slot(irq.bus, PCI_DEVFN(irq.dev, irq.func));
- if(!pci)
- return -EINVAL;
-
- irqn = pci->irq;
-
- spin_lock_irqsave(&dha_irqs[irqn].lock, dha_irqs[irqn].flags);
- if(dha_irqs[irqn].handled) {
- free_irq(irqn, pci);
- dha_irqs[irqn].handled = 0;
- printk("IRQ %i: %li\n", irqn, dha_irqs[irqn].count);
- }
- spin_unlock_irqrestore(&dha_irqs[irqn].lock, dha_irqs[irqn].flags);
- return 0;
-}
-
-static int dhahelper_ack_irq(dhahelper_irq_t *arg)
-{
- dhahelper_irq_t irq;
- int retval = 0;
- DECLARE_WAITQUEUE(wait, current);
- if (copy_from_user(&irq, arg, sizeof(dhahelper_irq_t)))
- {
- if (dhahelper_verbosity > 0)
- printk(KERN_ERR "dhahelper: failed copy from userspace\n");
- return -EFAULT;
- }
- if(irq.num > 255) return -EINVAL;
- if(!dha_irqs[irq.num].handled) return -ESRCH;
- add_wait_queue(&dha_irqs[irq.num].wait, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
- for(;;){
- int r;
- spin_lock_irqsave(&dha_irqs[irq.num].lock,
- dha_irqs[irq.num].flags);
- r = dha_irqs[irq.num].rcvd;
- spin_unlock_irqrestore(&dha_irqs[irq.num].lock,
- dha_irqs[irq.num].flags);
-
- if(r){
- dha_irqs[irq.num].rcvd = 0;
- break;
- }
-
- if(signal_pending(current)){
- retval = -ERESTARTSYS;
- break;
- }
-
- schedule();
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&dha_irqs[irq.num].wait, &wait);
- return retval;
-}
-
-static int dhahelper_cpu_flush(dhahelper_cpu_flush_t *arg)
-{
- dhahelper_cpu_flush_t my_l2;
- if (copy_from_user(&my_l2, arg, sizeof(dhahelper_cpu_flush_t)))
- {
- if (dhahelper_verbosity > 0)
- printk(KERN_ERR "dhahelper: failed copy from userspace\n");
- return -EFAULT;
- }
-#if defined(__i386__)
- /* WBINVD writes all modified cache lines back to main memory */
- if(boot_cpu_data.x86 > 3) { __asm __volatile("wbinvd":::"memory"); }
-#else
- /* FIXME!!!*/
- mb(); /* declared in "asm/system.h" */
-#endif
- return 0;
-}
-
-static struct pci_dev *pdev = NULL;
-static int dhahelper_pci_find(dhahelper_pci_device_t *arg)
-{
- dhahelper_pci_device_t this_dev;
- pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev);
- if(pdev)
- {
- this_dev.bus = pdev->bus->number;
- this_dev.card = PCI_SLOT(pdev->devfn);
- this_dev.func = PCI_FUNC(pdev->devfn);
- this_dev.vendor = pdev->vendor;
- this_dev.device = pdev->device;
- this_dev.base0 = pci_resource_start (pdev, 0);
- this_dev.base1 = pci_resource_start (pdev, 1);
- this_dev.base2 = pci_resource_start (pdev, 2);
- pci_read_config_dword(pdev, pdev->rom_base_reg, (u32*)&this_dev.baserom);
- this_dev.base3 = pci_resource_start (pdev, 3);
- this_dev.base4 = pci_resource_start (pdev, 4);
- this_dev.base5 = pci_resource_start (pdev, 5);
- pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &this_dev.irq);
- pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &this_dev.ipin);
- pci_read_config_byte(pdev, PCI_MIN_GNT, &this_dev.gnt);
- pci_read_config_byte(pdev, PCI_MAX_LAT, &this_dev.lat);
- }
- else memset(&this_dev,0,sizeof(dhahelper_pci_device_t));
- if (copy_to_user(arg, &this_dev, sizeof(dhahelper_pci_device_t)))
- {
- if (dhahelper_verbosity > 0)
- printk(KERN_ERR "dhahelper: failed copy to userspace\n");
- return -EFAULT;
- }
- return pdev?0:-ENODATA;
-}
-
-static int dhahelper_pci_config(dhahelper_pci_config_t *arg)
-{
- dhahelper_pci_config_t op;
- struct pci_dev *pdev;
- if (copy_from_user(&op, arg, sizeof(dhahelper_pci_config_t)))
- {
- if (dhahelper_verbosity > 0)
- printk(KERN_ERR "dhahelper: failed copy from userspace\n");
- return -EFAULT;
- }
- pdev = pci_find_slot(op.bus,PCI_DEVFN(op.dev,op.func));
- if(!pdev)
- {
- if (dhahelper_verbosity > 0)
- printk(KERN_ERR "dhahelper: can't identify device\n");
- return -EFAULT;
- }
- switch(op.operation)
- {
- case PCI_OP_READ:
- switch(op.size)
- {
- case 1:
- pci_read_config_byte(pdev,op.cmd,(u8*)&op.ret);
- break;
- case 2:
- pci_read_config_word(pdev,op.cmd,(u16*)&op.ret);
- break;
- case 4:
- pci_read_config_dword(pdev,op.cmd,(u32*)&op.ret);
- break;
- default:
- if (dhahelper_verbosity > 0)
- printk(KERN_ERR "dhahelper: wrong size of pci operation: %u \n",op.size);
- return -EFAULT;
- }
- case PCI_OP_WRITE:
- switch(op.size)
- {
- case 1:
- pci_write_config_byte(pdev,op.cmd,op.ret);
- break;
- case 2:
- pci_write_config_word(pdev,op.cmd,op.ret);
- break;
- case 4:
- pci_write_config_dword(pdev,op.cmd,op.ret);
- break;
- default:
- if (dhahelper_verbosity > 0)
- printk(KERN_ERR "dhahelper: wrong size of pci operation: %u \n",op.size);
- return -EFAULT;
- }
- default:
- if (dhahelper_verbosity > 0)
- printk(KERN_ERR "dhahelper: unknown pci operation %i\n",op.operation);
- return -EFAULT;
- }
- if (copy_to_user(arg, &op, sizeof(dhahelper_pci_device_t)))
- {
- if (dhahelper_verbosity > 0)
- printk(KERN_ERR "dhahelper: failed copy to userspace\n");
- return -EFAULT;
- }
- return 0;
-}
-
-static int dhahelper_mtrr(dhahelper_mtrr_t *arg)
-{
-#ifdef CONFIG_MTRR
- dhahelper_mtrr_t op;
- if (copy_from_user(&op, arg, sizeof(dhahelper_pci_config_t)))
- {
- if (dhahelper_verbosity > 0)
- printk(KERN_ERR "dhahelper: failed copy from userspace\n");
- return -EFAULT;
- }
- switch(op.operation)
- {
- case MTRR_OP_ADD:
- op.privat = mtrr_add (op.start,op.size,op.type,1);
- break;
- case MTRR_OP_DEL:
- mtrr_del(op.privat, op.start, op.size);
- break;
- default:
- if (dhahelper_verbosity > 0)
- printk(KERN_ERR "dhahelper: unknown mtrr operation %i\n",op.operation);
- return -EFAULT;
- }
- if (copy_to_user(arg, &op, sizeof(dhahelper_mtrr_t)))
- {
- if (dhahelper_verbosity > 0)
- printk(KERN_ERR "dhahelper: failed copy to userspace\n");
- return -EFAULT;
- }
-#endif
- return 0;
-}
-
-static int dhahelper_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- if (dhahelper_verbosity > 1)
- printk(KERN_DEBUG "dhahelper: ioctl(cmd=%x, arg=%lx)\n",
- cmd, arg);
-
- if (MINOR(inode->i_rdev) != 0)
- return -ENXIO;
-
- switch(cmd)
- {
- case DHAHELPER_GET_VERSION: return dhahelper_get_version((int *)arg);
- case DHAHELPER_PORT: return dhahelper_port((dhahelper_port_t *)arg);
- case DHAHELPER_MTRR: return dhahelper_mtrr((dhahelper_mtrr_t *)arg);
- case DHAHELPER_PCI_CONFIG: return dhahelper_pci_config((dhahelper_pci_config_t *)arg);
- case DHAHELPER_VIRT_TO_PHYS:return dhahelper_virt_to_phys((dhahelper_vmi_t *)arg);
- case DHAHELPER_VIRT_TO_BUS: return dhahelper_virt_to_bus((dhahelper_vmi_t *)arg);
- case DHAHELPER_ALLOC_PA:return dhahelper_alloc_pa((dhahelper_mem_t *)arg);
- case DHAHELPER_FREE_PA: return dhahelper_free_pa((dhahelper_mem_t *)arg);
- case DHAHELPER_LOCK_MEM: return dhahelper_lock_mem((dhahelper_mem_t *)arg);
- case DHAHELPER_UNLOCK_MEM: return dhahelper_unlock_mem((dhahelper_mem_t *)arg);
- case DHAHELPER_INSTALL_IRQ: return dhahelper_install_irq((dhahelper_irq_t *)arg);
- case DHAHELPER_ACK_IRQ: return dhahelper_ack_irq((dhahelper_irq_t *)arg);
- case DHAHELPER_FREE_IRQ: return dhahelper_free_irq((dhahelper_irq_t *)arg);
- case DHAHELPER_CPU_FLUSH: return dhahelper_cpu_flush((dhahelper_cpu_flush_t *)arg);
- case DHAHELPER_PCI_FIND: return dhahelper_pci_find((dhahelper_pci_device_t *)arg);
- default:
- if (dhahelper_verbosity > 0)
- printk(KERN_ERR "dhahelper: invalid ioctl (%x)\n", cmd);
- return -EINVAL;
- }
- return 0;
-}
-
-/*
- fops functions were shamelessly stolen from linux-kernel project ;)
-*/
-
-static loff_t dhahelper_lseek(struct file * file, loff_t offset, int orig)
-{
- switch (orig) {
- case 0:
- file->f_pos = offset;
- return file->f_pos;
- case 1:
- file->f_pos += offset;
- return file->f_pos;
- default:
- return -EINVAL;
- }
-}
-
-/*
- * This funcion reads the *physical* memory. The f_pos points directly to the
- * memory location.
- */
-static ssize_t dhahelper_read(struct file * file, char * buf,
- size_t count, loff_t *ppos)
-{
- unsigned long p = *ppos;
- unsigned long end_mem;
- ssize_t read;
-
- end_mem = __pa(high_memory);
- if (p >= end_mem)
- return 0;
- if (count > end_mem - p)
- count = end_mem - p;
- read = 0;
-#if defined(__sparc__) || defined(__mc68000__)
- /* we don't have page 0 mapped on sparc and m68k.. */
- if (p < PAGE_SIZE) {
- unsigned long sz = PAGE_SIZE-p;
- if (sz > count)
- sz = count;
- if (sz > 0) {
- if (clear_user(buf, sz))
- return -EFAULT;
- buf += sz;
- p += sz;
- count -= sz;
- read += sz;
- }
- }
-#endif
- if (copy_to_user(buf, __va(p), count))
- return -EFAULT;
- read += count;
- *ppos += read;
- return read;
-}
-
-static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp,
- const char * buf, size_t count, loff_t *ppos)
-{
- ssize_t written;
-
- written = 0;
-#if defined(__sparc__) || defined(__mc68000__)
- /* we don't have page 0 mapped on sparc and m68k.. */
- if (realp < PAGE_SIZE) {
- unsigned long sz = PAGE_SIZE-realp;
- if (sz > count) sz = count;
- /* Hmm. Do something? */
- buf+=sz;
- p+=sz;
- count-=sz;
- written+=sz;
- }
-#endif
- if (copy_from_user(p, buf, count))
- return -EFAULT;
- written += count;
- *ppos += written;
- return written;
-}
-
-static ssize_t dhahelper_write(struct file * file, const char * buf,
- size_t count, loff_t *ppos)
-{
- unsigned long p = *ppos;
- unsigned long end_mem;
-
- end_mem = __pa(high_memory);
- if (p >= end_mem)
- return 0;
- if (count > end_mem - p)
- count = end_mem - p;
- return do_write_mem(file, __va(p), p, buf, count, ppos);
-}
-
-#ifndef pgprot_noncached
-
-/*
- * This should probably be per-architecture in <asm/pgtable.h>
- */
-static inline pgprot_t pgprot_noncached(pgprot_t _prot)
-{
- unsigned long prot = pgprot_val(_prot);
-
-#if defined(__i386__) || defined(__x86_64__)
- /* On PPro and successors, PCD alone doesn't always mean
- uncached because of interactions with the MTRRs. PCD | PWT
- means definitely uncached. */
- if (boot_cpu_data.x86 > 3)
- prot |= _PAGE_PCD | _PAGE_PWT;
-#elif defined(__powerpc__)
- prot |= _PAGE_NO_CACHE | _PAGE_GUARDED;
-#elif defined(__mc68000__)
-#ifdef SUN3_PAGE_NOCACHE
- if (MMU_IS_SUN3)
- prot |= SUN3_PAGE_NOCACHE;
- else
-#endif
- if (MMU_IS_851 || MMU_IS_030)
- prot |= _PAGE_NOCACHE030;
- /* Use no-cache mode, serialized */
- else if (MMU_IS_040 || MMU_IS_060)
- prot = (prot & _CACHEMASK040) | _PAGE_NOCACHE_S;
-#endif
-
- return __pgprot(prot);
-}
-
-#endif /* !pgprot_noncached */
-
-/*
- * Architectures vary in how they handle caching for addresses
- * outside of main memory.
- */
-static inline int noncached_address(unsigned long addr)
-{
-#if defined(__i386__)
- /*
- * On the PPro and successors, the MTRRs are used to set
- * memory types for physical addresses outside main memory,
- * so blindly setting PCD or PWT on those pages is wrong.
- * For Pentiums and earlier, the surround logic should disable
- * caching for the high addresses through the KEN pin, but
- * we maintain the tradition of paranoia in this code.
- */
- return !( test_bit(X86_FEATURE_MTRR, boot_cpu_data.x86_capability) ||
- test_bit(X86_FEATURE_K6_MTRR, boot_cpu_data.x86_capability) ||
- test_bit(X86_FEATURE_CYRIX_ARR, boot_cpu_data.x86_capability) ||
- test_bit(X86_FEATURE_CENTAUR_MCR, boot_cpu_data.x86_capability) )
- && addr >= __pa(high_memory);
-#else
- return addr >= __pa(high_memory);
-#endif
-}
-
-static int dhahelper_mmap(struct file * file, struct vm_area_struct * vma)
-{
- unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
- int err;
-
- /*
- * Accessing memory above the top the kernel knows about or
- * through a file pointer that was marked O_SYNC will be
- * done non-cached.
- */
- if (noncached_address(offset) || (file->f_flags & O_SYNC))
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
- /* Don't try to swap out physical pages.. */
- vma->vm_flags |= VM_RESERVED;
-
- /*
- * Don't dump addresses that are not real memory to a core file.
- */
- if (offset >= __pa(high_memory) || (file->f_flags & O_SYNC))
- vma->vm_flags |= VM_IO;
-
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
- err = remap_page_range(vma, vma->vm_start, offset,
- vma->vm_end-vma->vm_start, vma->vm_page_prot);
-#else
- err = remap_page_range(vma->vm_start, offset,
- vma->vm_end-vma->vm_start, vma->vm_page_prot);
-#endif
- if(err)
- return -EAGAIN;
- return 0;
-}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
-static struct file_operations dhahelper_fops =
-{
- /*llseek*/ dhahelper_lseek,
- /*read*/ dhahelper_read,
- /*write*/ dhahelper_write,
- /*readdir*/ NULL,
- /*poll*/ NULL,
- /*ioctl*/ dhahelper_ioctl,
- /*mmap*/ dhahelper_mmap,
- /*open*/ dhahelper_open,
- /*flush*/ NULL,
- /*release*/ dhahelper_release,
- /* zero out the last 5 entries too ? */
-};
-#else
-static struct file_operations dhahelper_fops =
-{
- owner: THIS_MODULE,
- ioctl: dhahelper_ioctl,
- open: dhahelper_open,
- release: dhahelper_release,
- llseek: dhahelper_lseek,
- read: dhahelper_read,
- write: dhahelper_write,
- mmap: dhahelper_mmap,
-};
-#endif
-
-#ifdef CONFIG_DEVFS_FS
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
-devfs_handle_t dha_devfsh;
-
-static int
-register_dev(void)
-{
- dha_devfsh = devfs_register(NULL, "dhahelper", DEVFS_FL_NONE,
- dhahelper_major, 0,
- S_IFCHR | S_IRUSR | S_IWUSR,
- &dhahelper_fops, NULL);
- if(!dha_devfsh)
- return -EIO;
- return 0;
-}
-
-static void
-unregister_dev(void)
-{
- devfs_unregister(dha_devfsh);
-}
-#else /* VERSION < 2.6.0 */
-static int
-register_dev(void)
-{
- devfs_mk_cdev(MKDEV(dhahelper_major, 0), S_IFCHR | S_IRUSR | S_IWUSR,
- "dhahelper");
- if(register_chrdev(dhahelper_major, "dhahelper", &dhahelper_fops))
- return -EIO;
- return 0;
-}
-
-static void
-unregister_dev(void)
-{
- devfs_remove("dhahelper");
- unregister_chrdev(dhahelper_major, "dhahelper");
-}
-#endif /* VERSION < 2.6.0 */
-#else
-static int
-register_dev(void)
-{
- return register_chrdev(dhahelper_major, "dhahelper", &dhahelper_fops);
-}
-
-static void
-unregister_dev(void)
-{
- unregister_chrdev(dhahelper_major, "dhahelper");
-}
-#endif /* defined CONFIG_DEVFS_FS */
-
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
-int init_module(void)
-#else
-static int __init init_dhahelper(void)
-#endif
-{
- int err = 0;
- printk(KERN_INFO "Direct Hardware Access kernel helper (C) Alex Beregszaszi\n");
-
- err = register_dev();
- if(err){
- if (dhahelper_verbosity > 0)
- printk(KERN_ERR "dhahelper: unable to register character device (major: %d)\n",
- dhahelper_major);
- return err;
- }
- memset(dha_irqs, 0, sizeof(dha_irqs));
- return 0;
-}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
-void cleanup_module(void)
-#else
-static void __exit exit_dhahelper(void)
-#endif
-{
- unsigned i;
- for(i=0;i<256;i++)
- if(dha_irqs[i].handled)
- free_irq(i, dha_irqs[i].dev);
-
- unregister_dev();
-}
-
-#ifdef EXPORT_NO_SYMBOLS
-EXPORT_NO_SYMBOLS;
-#endif
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-module_init(init_dhahelper);
-module_exit(exit_dhahelper);
-#endif