diff options
Diffstat (limited to 'linux/drivers/media/dvb/dvb-core/compat.c')
-rw-r--r-- | linux/drivers/media/dvb/dvb-core/compat.c | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/linux/drivers/media/dvb/dvb-core/compat.c b/linux/drivers/media/dvb/dvb-core/compat.c index 925fbdefb..6d6d11d98 100644 --- a/linux/drivers/media/dvb/dvb-core/compat.c +++ b/linux/drivers/media/dvb/dvb-core/compat.c @@ -8,6 +8,66 @@ * even when everything compiles. */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) || !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,0)) static u32 crc32_table[256] = { |