summaryrefslogtreecommitdiff
path: root/linux/drivers/media/dvb/dvb-core/compat.c
blob: af33c58b7c4262a8989c943c62d2353a0903939d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include <linux/slab.h>
#include "compat.h"

/**
 *  compatibility crap for old kernels. No guarantee for a working driver
 *  even when everything compiles.
 */

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,45)) || !CONFIG_VIDEO_DEV
int generic_usercopy(struct inode *inode, struct file *file,
	             unsigned int cmd, unsigned long arg,
		     int (*func)(struct inode *inode, struct file *file,
		     unsigned int cmd, void *arg))
{
        char    sbuf[128];
        void    *mbuf = NULL;
        void    *parg = NULL;
        int     err  = -EINVAL;

        /*  Copy arguments into temp kernel buffer  */
        switch (_IOC_DIR(cmd)) {
        case _IOC_NONE:
                parg = (void *)arg;
                break;
        case _IOC_READ: /* some v4l ioctls are marked wrong ... */
        case _IOC_WRITE:
        case (_IOC_WRITE | _IOC_READ):
                if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
                        parg = sbuf;
                } else {
                        /* too big to allocate from stack */
                        mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
                        if (NULL == mbuf)
                                return -ENOMEM;
                        parg = mbuf;
                }

                err = -EFAULT;
                if (copy_from_user(parg, (void *)arg, _IOC_SIZE(cmd)))
                        goto out;
                break;
        }

        /* call driver */
        if ((err = func(inode, file, cmd, parg)) == -ENOIOCTLCMD)
                err = -EINVAL;

        if (err < 0)
                goto out;

        /*  Copy results into user buffer  */
        switch (_IOC_DIR(cmd))
        {
        case _IOC_READ:
        case (_IOC_WRITE | _IOC_READ):
                if (copy_to_user((void *)arg, parg, _IOC_SIZE(cmd)))
                        err = -EFAULT;
                break;
        }

out:
        if (mbuf)
                kfree(mbuf);

        return err;
}
#endif


#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,45))
struct page * vmalloc_to_page(void *vmalloc_addr)
{
        unsigned long addr = (unsigned long) vmalloc_addr;
        struct page *page = NULL;
        pgd_t *pgd = pgd_offset_k(addr);
        pmd_t *pmd;
        pte_t *ptep, pte;

        if (!pgd_none(*pgd)) {
                pmd = pmd_offset(pgd, addr);
                if (!pmd_none(*pmd)) {
                        ptep = pte_offset(pmd, addr);
                        pte = *ptep;
                        if (pte_present(pte))
                                page = pte_page(pte);
                }
        }
        return page;
}
#endif