#include #include #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