diff options
author | Daniel Caujolle-Bert <f1rmb@users.sourceforge.net> | 2002-06-01 14:08:36 +0000 |
---|---|---|
committer | Daniel Caujolle-Bert <f1rmb@users.sourceforge.net> | 2002-06-01 14:08:36 +0000 |
commit | bb7a31a69bac993ffb9cfb195b84c1e374308e08 (patch) | |
tree | dfa504dd8c27837562c4850308d668afef851dd2 /src/video_out/libdha/kernelhelper | |
parent | c49645144f4d31c88610c449059d48493736b5b6 (diff) | |
download | xine-lib-bb7a31a69bac993ffb9cfb195b84c1e374308e08.tar.gz xine-lib-bb7a31a69bac993ffb9cfb195b84c1e374308e08.tar.bz2 |
Add vidix/libdha from mplayerxp and Miguel's video ouput vidix.
CVS patchset: 1976
CVS date: 2002/06/01 14:08:36
Diffstat (limited to 'src/video_out/libdha/kernelhelper')
-rw-r--r-- | src/video_out/libdha/kernelhelper/Makefile.am | 41 | ||||
-rw-r--r-- | src/video_out/libdha/kernelhelper/README | 34 | ||||
-rw-r--r-- | src/video_out/libdha/kernelhelper/dhahelper.c | 416 | ||||
-rw-r--r-- | src/video_out/libdha/kernelhelper/dhahelper.h | 78 | ||||
-rw-r--r-- | src/video_out/libdha/kernelhelper/test.c | 60 |
5 files changed, 629 insertions, 0 deletions
diff --git a/src/video_out/libdha/kernelhelper/Makefile.am b/src/video_out/libdha/kernelhelper/Makefile.am new file mode 100644 index 000000000..4d603c0e7 --- /dev/null +++ b/src/video_out/libdha/kernelhelper/Makefile.am @@ -0,0 +1,41 @@ +EXTRA_DIST = README dhahelper.c + +CFLAGS = -O2 -Wall -D__KERNEL__ -DMODULE + +## CLEAN ME +KVERSION = $(shell $(SHELL) -c 'uname -r') +MISC_KDIR = /lib/modules/$(KVERSION)/misc + +KCOMPILE = $(CC) $(CFLAGS) $(INCLUDES) $(LINUX_INCLUDE) + +noinst_HEADERS = dhahelper.h + +EXTRA_PROGRAMS = test +test_SOURCES = test.c + +dhahelper.o: + $(KCOMPILE) -c `test -f $< || echo '$(srcdir)/'`$< + +install-data-local: @HAVE_LINUX_TRUE@ dhahelper.o +@HAVE_LINUX_TRUE@ if test ! -d $(MISC_KDIR); then \ +@HAVE_LINUX_TRUE@ mkdir -p $(MISC_KDIR); \ +@HAVE_LINUX_TRUE@ fi +@HAVE_LINUX_TRUE@ $(INSTALL_DATA) dhahelper.o $(MISC_KDIR)/dhahelper.o +@HAVE_LINUX_TRUE@ $(DEPMOD) -a +@HAVE_LINUX_TRUE@ if test ! -c /dev/dhahelper; then \ +@HAVE_LINUX_TRUE@ $(MKNOD) -m 666 /dev/dhahelper c 180 0; \ +@HAVE_LINUX_TRUE@ fi + +uninstall-local: +@HAVE_LINUX_TRUE@ rm -f $(MISC_KDIR)/dhahelper.o + +debug: +install-debug: install + +mostlyclean-generic: + -rm -f *~ \#* .*~ .\#* test + +maintainer-clean-generic: + -@echo "This command is intended for maintainers to use;" + -@echo "it deletes files that may require special tools to rebuild." + -rm -f Makefile.in diff --git a/src/video_out/libdha/kernelhelper/README b/src/video_out/libdha/kernelhelper/README new file mode 100644 index 000000000..cb5964cb8 --- /dev/null +++ b/src/video_out/libdha/kernelhelper/README @@ -0,0 +1,34 @@ +dhahelper is small driver to provide some kernel function into userspace. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Main goal why you need to use that it's busmastering. +(Btw, lacking of possibility to implement convertion of +virtual addresses into physical in userspace caused +implementing of so-called DRM drivers for Linux from +XFree86 side). +Second goal (still is unfinished) - provide possibility +to control port and physical memory access through +groups and access rights of this driver. (Unix way). + +Installation: +~~~~~~~~~~~~~ +just type in this directory: +make all install + +If you have compiled this driver first-time then +type also: +make nodes + +Porting: +~~~~~~~~ +This driver was developed only for Linux. +So if someone will port that on other unicies +then any patches are gladly accepted. + +WARNING: +~~~~~~~~ +This driver violates some kernel's security rules. +To keep this driver from anonymous access I suggest +you create new group for mplayerxp and /dev/dhahelper +only. + +Good luck! diff --git a/src/video_out/libdha/kernelhelper/dhahelper.c b/src/video_out/libdha/kernelhelper/dhahelper.c new file mode 100644 index 000000000..f85b4efd1 --- /dev/null +++ b/src/video_out/libdha/kernelhelper/dhahelper.c @@ -0,0 +1,416 @@ +/* + Direct Hardware Access kernel helper + + (C) 2002 Alex Beregszaszi <alex@naxine.org> + + 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! + + 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: + * do memory mapping without fops:mmap + * implement unmap memory + * 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/string.h> +#include <linux/errno.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> + +#include "dhahelper.h" + +MODULE_AUTHOR("Alex Beregszaszi <alex@naxine.org>"); +MODULE_DESCRIPTION("Provides userspace access to hardware (security violation!)"); +#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 dhahelper_memory_t last_mem_request; + + +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; + + MOD_INC_USE_COUNT; + + 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; + + MOD_DEC_USE_COUNT; + + 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; +} + +static int dhahelper_memory(dhahelper_memory_t * arg) +{ + dhahelper_memory_t mem; + if (copy_from_user(&mem, arg, sizeof(dhahelper_memory_t))) + { + if (dhahelper_verbosity > 0) + printk(KERN_ERR "dhahelper: failed copy from userspace\n"); + return -EFAULT; + } + switch(mem.operation) + { + case MEMORY_OP_MAP: + { +#if 1 + memcpy(&last_mem_request, &mem, sizeof(dhahelper_memory_t)); +#else + mem.ret = do_mmap(file, mem.start, mem.size, PROT_READ|PROT_WRITE, + MAP_SHARED, mem.offset); +#endif + break; + } + case MEMORY_OP_UNMAP: + break; + default: + if (dhahelper_verbosity > 0) + printk(KERN_ERR "dhahelper: invalid memory operation (%d)\n", + mem.operation); + return -EINVAL; + } + if (copy_to_user(arg, &mem, sizeof(dhahelper_memory_t))) + { + if (dhahelper_verbosity > 0) + printk(KERN_ERR "dhahelper: failed copy to userspace\n"); + return -EFAULT; + } + return 0; +} + +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 = virt_to_phys(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 = virt_to_bus(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_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_MEMORY: return dhahelper_memory((dhahelper_memory_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); + default: + if (dhahelper_verbosity > 0) + printk(KERN_ERR "dhahelper: invalid ioctl (%x)\n", cmd); + return -EINVAL; + } + return 0; +} + +static int dhahelper_mmap(struct file *file, struct vm_area_struct *vma) +{ + if (last_mem_request.operation != MEMORY_OP_MAP) + { + if (dhahelper_verbosity > 0) + printk(KERN_ERR "dhahelper: mapping not requested before mmap\n"); + return -EFAULT; + } + + if (dhahelper_verbosity > 1) + printk(KERN_INFO "dhahelper: mapping %x (size: %x)\n", + last_mem_request.start+last_mem_request.offset, last_mem_request.size); + + if (remap_page_range(0, last_mem_request.start + last_mem_request.offset, + last_mem_request.size, vma->vm_page_prot)) + { + if (dhahelper_verbosity > 0) + printk(KERN_ERR "dhahelper: error mapping memory\n"); + return -EFAULT; + } + + return 0; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) +static struct file_operations dhahelper_fops = +{ + /*llseek*/ NULL, + /*read*/ NULL, + /*write*/ NULL, + /*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, + mmap: dhahelper_mmap, + open: dhahelper_open, + release: dhahelper_release +}; +#endif + +#if KERNEL_VERSION < KERNEL_VERSION(2,4,0) +int init_module(void) +#else +static int __init init_dhahelper(void) +#endif +{ + printk(KERN_INFO "Direct Hardware Access kernel helper (C) Alex Beregszaszi\n"); + + if(register_chrdev(dhahelper_major, "dhahelper", &dhahelper_fops)) + { + if (dhahelper_verbosity > 0) + printk(KERN_ERR "dhahelper: unable to register character device (major: %d)\n", + dhahelper_major); + return -EIO; + } + + return 0; +} + +#if KERNEL_VERSION < KERNEL_VERSION(2,4,0) +void cleanup_module(void) +#else +static void __exit exit_dhahelper(void) +#endif +{ + unregister_chrdev(dhahelper_major, "dhahelper"); +} + +EXPORT_NO_SYMBOLS; + +#if KERNEL_VERSION >= KERNEL_VERSION(2,4,0) +module_init(init_dhahelper); +module_exit(exit_dhahelper); +#endif diff --git a/src/video_out/libdha/kernelhelper/dhahelper.h b/src/video_out/libdha/kernelhelper/dhahelper.h new file mode 100644 index 000000000..2cbcb5550 --- /dev/null +++ b/src/video_out/libdha/kernelhelper/dhahelper.h @@ -0,0 +1,78 @@ +/* + Direct Hardware Access kernel helper + + (C) 2002 Alex Beregszaszi <alex@naxine.org> +*/ + +#ifndef DHAHELPER_H +#define DHAHELPER_H + +#include <linux/ioctl.h> + +/* feel free to change */ +#define DEFAULT_MAJOR 180 + +#define API_VERSION 0x2 + +typedef struct dhahelper_port_s +{ +#define PORT_OP_READ 1 +#define PORT_OP_WRITE 2 + int operation; + int size; + int addr; + int value; +} dhahelper_port_t; + +typedef struct dhahelper_memory_s +{ +#define MEMORY_OP_MAP 1 +#define MEMORY_OP_UNMAP 2 + int operation; + int start; + int offset; + int size; + int ret; +#define MEMORY_FLAG_NOCACHE 1 + int flags; +} dhahelper_memory_t; + +typedef struct dhahelper_mtrr_s +{ +#define MTRR_OP_ADD 1 +#define MTRR_OP_DEL 2 + int operation; + int start; + int size; + int type; +} dhahelper_mtrr_t; + +typedef struct dhahelper_pci_s +{ +#define PCI_OP_READ 1 +#define PCI_OP_WRITE 1 + int operation; + int bus; + int dev; + int func; + int cmd; + int size; + int ret; +} dhahelper_pci_t; + +typedef struct dhahelper_vmi_s +{ + void * virtaddr; + unsigned long length; + unsigned long *realaddr; +}dhahelper_vmi_t; + +#define DHAHELPER_GET_VERSION _IOW('D', 0, int) +#define DHAHELPER_PORT _IOWR('D', 1, dhahelper_port_t) +#define DHAHELPER_MEMORY _IOWR('D', 2, dhahelper_memory_t) +#define DHAHELPER_MTRR _IOWR('D', 3, dhahelper_mtrr_t) +#define DHAHELPER_PCI _IOWR('D', 4, dhahelper_pci_t) +#define DHAHELPER_VIRT_TO_PHYS _IOWR('D', 5, dhahelper_vmi_t) +#define DHAHELPER_VIRT_TO_BUS _IOWR('D', 6, dhahelper_vmi_t) + +#endif /* DHAHELPER_H */ diff --git a/src/video_out/libdha/kernelhelper/test.c b/src/video_out/libdha/kernelhelper/test.c new file mode 100644 index 000000000..3dca94c74 --- /dev/null +++ b/src/video_out/libdha/kernelhelper/test.c @@ -0,0 +1,60 @@ +#include <string.h> +#include <stdio.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/mman.h> + +#include "dhahelper.h" + +int main(int argc, char *argv[]) +{ + int fd; + int ret; + + fd = open("/dev/dhahelper", O_RDWR); + + ioctl(fd, DHAHELPER_GET_VERSION, &ret); + + printf("api version: %d\n", ret); + if (ret != API_VERSION) + printf("incompatible api!\n"); + + { + dhahelper_memory_t mem; + + mem.operation = MEMORY_OP_MAP; + //mem.start = 0xe0000000; + mem.start = 0xe4000008; + mem.offset = 0; + mem.size = 0x4000; + mem.ret = 0; + + ret = ioctl(fd, DHAHELPER_MEMORY, &mem); + + printf("ret: %s\n", strerror(errno)); + + mem.ret = (int)mmap(NULL, (size_t)mem.size, PROT_READ, MAP_SHARED, fd, (off_t)0); + printf("allocated to %x\n", mem.ret); + + if (argc > 1) + if (mem.ret != 0) + { + int i; + + for (i = 0; i < 256; i++) + printf("[%x] ", *(int *)(mem.ret+i)); + printf("\n"); + } + + munmap((void *)mem.ret, mem.size); + + mem.operation = MEMORY_OP_UNMAP; + mem.start = mem.ret; + + ioctl(fd, DHAHELPER_MEMORY, &mem); + } + + return(0); +} |