From fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 Mon Sep 17 00:00:00 2001 From: Jonathan Herman Date: Tue, 22 Jan 2013 10:38:37 -0500 Subject: Added missing tegra files. --- drivers/media/video/tegra/avp/trpc_sema.c | 244 ++++++++++++++++++++++++++++++ 1 file changed, 244 insertions(+) create mode 100644 drivers/media/video/tegra/avp/trpc_sema.c (limited to 'drivers/media/video/tegra/avp/trpc_sema.c') diff --git a/drivers/media/video/tegra/avp/trpc_sema.c b/drivers/media/video/tegra/avp/trpc_sema.c new file mode 100644 index 00000000000..cd717a1a0ca --- /dev/null +++ b/drivers/media/video/tegra/avp/trpc_sema.c @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2010 Google, Inc. + * + * Author: + * Dima Zavin + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "trpc_sema.h" + +struct tegra_sema_info { + struct file *file; + wait_queue_head_t wq; + spinlock_t lock; + int count; +}; + +static int rpc_sema_minor = -1; + +static inline bool is_trpc_sema_file(struct file *file) +{ + dev_t rdev = file->f_dentry->d_inode->i_rdev; + + if (MAJOR(rdev) == MISC_MAJOR && MINOR(rdev) == rpc_sema_minor) + return true; + return false; +} + +struct tegra_sema_info *trpc_sema_get_from_fd(int fd) +{ + struct file *file; + + file = fget(fd); + if (unlikely(file == NULL)) { + pr_err("%s: fd %d is invalid\n", __func__, fd); + return ERR_PTR(-EINVAL); + } + + if (!is_trpc_sema_file(file)) { + pr_err("%s: fd (%d) is not a trpc_sema file\n", __func__, fd); + fput(file); + return ERR_PTR(-EINVAL); + } + + return file->private_data; +} + +void trpc_sema_put(struct tegra_sema_info *info) +{ + if (info->file) + fput(info->file); +} + +int tegra_sema_signal(struct tegra_sema_info *info) +{ + unsigned long flags; + + if (!info) + return -EINVAL; + + spin_lock_irqsave(&info->lock, flags); + info->count++; + wake_up_interruptible_all(&info->wq); + spin_unlock_irqrestore(&info->lock, flags); + return 0; +} + +int tegra_sema_wait(struct tegra_sema_info *info, long *timeout) +{ + unsigned long flags; + int ret = 0; + unsigned long endtime; + long timeleft = *timeout; + + *timeout = 0; + if (timeleft < 0) + timeleft = MAX_SCHEDULE_TIMEOUT; + + timeleft = msecs_to_jiffies(timeleft); + endtime = jiffies + timeleft; + +again: + if (timeleft) + ret = wait_event_interruptible_timeout(info->wq, + info->count > 0, + timeleft); + spin_lock_irqsave(&info->lock, flags); + if (info->count > 0) { + info->count--; + ret = 0; + } else if (ret == 0 || timeout == 0) { + ret = -ETIMEDOUT; + } else if (ret < 0) { + ret = -EINTR; + if (timeleft != MAX_SCHEDULE_TIMEOUT && + time_before(jiffies, endtime)) + *timeout = jiffies_to_msecs(endtime - jiffies); + else + *timeout = 0; + } else { + /* we woke up but someone else got the semaphore and we have + * time left, try again */ + timeleft = ret; + spin_unlock_irqrestore(&info->lock, flags); + goto again; + } + spin_unlock_irqrestore(&info->lock, flags); + return ret; +} + +int tegra_sema_open(struct tegra_sema_info **sema) +{ + struct tegra_sema_info *info; + info = kzalloc(sizeof(struct tegra_sema_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + init_waitqueue_head(&info->wq); + spin_lock_init(&info->lock); + *sema = info; + return 0; +} + +static int trpc_sema_open(struct inode *inode, struct file *file) +{ + struct tegra_sema_info *info; + int ret; + + ret = tegra_sema_open(&info); + if (ret < 0) + return ret; + + info->file = file; + nonseekable_open(inode, file); + file->private_data = info; + return 0; +} + +int tegra_sema_release(struct tegra_sema_info *sema) +{ + kfree(sema); + return 0; +} + +static int trpc_sema_release(struct inode *inode, struct file *file) +{ + struct tegra_sema_info *info = file->private_data; + + file->private_data = NULL; + tegra_sema_release(info); + return 0; +} + +static long trpc_sema_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct tegra_sema_info *info = file->private_data; + int ret; + long timeout; + + if (_IOC_TYPE(cmd) != TEGRA_SEMA_IOCTL_MAGIC || + _IOC_NR(cmd) < TEGRA_SEMA_IOCTL_MIN_NR || + _IOC_NR(cmd) > TEGRA_SEMA_IOCTL_MAX_NR) + return -ENOTTY; + else if (!info) + return -EINVAL; + + switch (cmd) { + case TEGRA_SEMA_IOCTL_WAIT: + if (copy_from_user(&timeout, (void __user *)arg, sizeof(long))) + return -EFAULT; + ret = tegra_sema_wait(info, &timeout); + if (ret != -EINTR) + break; + if (copy_to_user((void __user *)arg, &timeout, sizeof(long))) + ret = -EFAULT; + break; + case TEGRA_SEMA_IOCTL_SIGNAL: + ret = tegra_sema_signal(info); + break; + default: + pr_err("%s: Unknown tegra_sema ioctl 0x%x\n", __func__, + _IOC_NR(cmd)); + ret = -ENOTTY; + break; + } + return ret; +} + +static const struct file_operations trpc_sema_misc_fops = { + .owner = THIS_MODULE, + .open = trpc_sema_open, + .release = trpc_sema_release, + .unlocked_ioctl = trpc_sema_ioctl, +}; + +static struct miscdevice trpc_sema_misc_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "tegra_sema", + .fops = &trpc_sema_misc_fops, +}; + +int __init trpc_sema_init(void) +{ + int ret; + + if (rpc_sema_minor >= 0) { + pr_err("%s: trpc_sema already registered\n", __func__); + return -EBUSY; + } + + ret = misc_register(&trpc_sema_misc_device); + if (ret) { + pr_err("%s: can't register misc device\n", __func__); + return ret; + } + + rpc_sema_minor = trpc_sema_misc_device.minor; + pr_info("%s: registered misc dev %d:%d\n", __func__, MISC_MAJOR, + rpc_sema_minor); + + return 0; +} -- cgit v1.2.2