90e3ee5c299b3aa4c69d3f0d3dc5939027a08828
[cascardo/linux.git] / drivers / staging / android / sw_sync.c
1 /*
2  * drivers/dma-buf/sw_sync.c
3  *
4  * Copyright (C) 2012 Google, Inc.
5  *
6  * This software is licensed under the terms of the GNU General Public
7  * License version 2, as published by the Free Software Foundation, and
8  * may be copied, distributed, and modified under those terms.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  */
16
17 #include <linux/file.h>
18 #include <linux/fs.h>
19 #include <linux/uaccess.h>
20 #include <linux/sync_file.h>
21
22 #include "uapi/sw_sync.h"
23 #include "sync.h"
24
25 /*
26  * *WARNING*
27  *
28  * improper use of this can result in deadlocking kernel drivers from userspace.
29  */
30
31 /* opening sw_sync create a new sync obj */
32 static int sw_sync_debugfs_open(struct inode *inode, struct file *file)
33 {
34         struct sync_timeline *obj;
35         char task_comm[TASK_COMM_LEN];
36
37         get_task_comm(task_comm, current);
38
39         obj = sync_timeline_create("sw_sync", task_comm);
40         if (!obj)
41                 return -ENOMEM;
42
43         file->private_data = obj;
44
45         return 0;
46 }
47
48 static int sw_sync_debugfs_release(struct inode *inode, struct file *file)
49 {
50         struct sync_timeline *obj = file->private_data;
51
52         sync_timeline_destroy(obj);
53         return 0;
54 }
55
56 static long sw_sync_ioctl_create_fence(struct sync_timeline *obj,
57                                        unsigned long arg)
58 {
59         int fd = get_unused_fd_flags(O_CLOEXEC);
60         int err;
61         struct sync_pt *pt;
62         struct sync_file *sync_file;
63         struct sw_sync_create_fence_data data;
64
65         if (fd < 0)
66                 return fd;
67
68         if (copy_from_user(&data, (void __user *)arg, sizeof(data))) {
69                 err = -EFAULT;
70                 goto err;
71         }
72
73         pt = sync_pt_create(obj, sizeof(*pt), data.value);
74         if (!pt) {
75                 err = -ENOMEM;
76                 goto err;
77         }
78
79         sync_file = sync_file_create(&pt->base);
80         if (!sync_file) {
81                 fence_put(&pt->base);
82                 err = -ENOMEM;
83                 goto err;
84         }
85
86         data.fence = fd;
87         if (copy_to_user((void __user *)arg, &data, sizeof(data))) {
88                 fput(sync_file->file);
89                 err = -EFAULT;
90                 goto err;
91         }
92
93         fd_install(fd, sync_file->file);
94
95         return 0;
96
97 err:
98         put_unused_fd(fd);
99         return err;
100 }
101
102 static long sw_sync_ioctl_inc(struct sync_timeline *obj, unsigned long arg)
103 {
104         u32 value;
105
106         if (copy_from_user(&value, (void __user *)arg, sizeof(value)))
107                 return -EFAULT;
108
109         sync_timeline_signal(obj, value);
110
111         return 0;
112 }
113
114 static long sw_sync_ioctl(struct file *file, unsigned int cmd,
115                           unsigned long arg)
116 {
117         struct sync_timeline *obj = file->private_data;
118
119         switch (cmd) {
120         case SW_SYNC_IOC_CREATE_FENCE:
121                 return sw_sync_ioctl_create_fence(obj, arg);
122
123         case SW_SYNC_IOC_INC:
124                 return sw_sync_ioctl_inc(obj, arg);
125
126         default:
127                 return -ENOTTY;
128         }
129 }
130
131 const struct file_operations sw_sync_debugfs_fops = {
132         .open           = sw_sync_debugfs_open,
133         .release        = sw_sync_debugfs_release,
134         .unlocked_ioctl = sw_sync_ioctl,
135         .compat_ioctl   = sw_sync_ioctl,
136 };