1/*
2 * Copyright (C) 2013 Google, Inc.
3 *
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * GNU General Public License for more details.
12 *
13 */
14
15#include <linux/uaccess.h>
16#include <video/adf.h>
17
18#include "adf_fops.h"
19#include "adf_fops32.h"
20
21long adf_compat_post_config(struct file *file,
22		struct adf_post_config32 __user *arg)
23{
24	struct adf_post_config32 cfg32;
25	struct adf_post_config __user *cfg;
26	int ret;
27
28	if (copy_from_user(&cfg32, arg, sizeof(cfg32)))
29		return -EFAULT;
30
31	cfg = compat_alloc_user_space(sizeof(*cfg));
32	if (!access_ok(VERIFY_WRITE, cfg, sizeof(*cfg)))
33		return -EFAULT;
34
35	if (put_user(cfg32.n_interfaces, &cfg->n_interfaces) ||
36			put_user(compat_ptr(cfg32.interfaces),
37					&cfg->interfaces) ||
38			put_user(cfg32.n_bufs, &cfg->n_bufs) ||
39			put_user(compat_ptr(cfg32.bufs), &cfg->bufs) ||
40			put_user(cfg32.custom_data_size,
41					&cfg->custom_data_size) ||
42			put_user(compat_ptr(cfg32.custom_data),
43					&cfg->custom_data))
44		return -EFAULT;
45
46	ret = adf_file_ioctl(file, ADF_POST_CONFIG, (unsigned long)cfg);
47	if (ret < 0)
48		return ret;
49
50	if (copy_in_user(&arg->complete_fence, &cfg->complete_fence,
51			sizeof(cfg->complete_fence)))
52		return -EFAULT;
53
54	return 0;
55}
56
57long adf_compat_get_device_data(struct file *file,
58		struct adf_device_data32 __user *arg)
59{
60	struct adf_device_data32 data32;
61	struct adf_device_data __user *data;
62	int ret;
63
64	if (copy_from_user(&data32, arg, sizeof(data32)))
65		return -EFAULT;
66
67	data = compat_alloc_user_space(sizeof(*data));
68	if (!access_ok(VERIFY_WRITE, data, sizeof(*data)))
69		return -EFAULT;
70
71	if (put_user(data32.n_attachments, &data->n_attachments) ||
72			put_user(compat_ptr(data32.attachments),
73					&data->attachments) ||
74			put_user(data32.n_allowed_attachments,
75					&data->n_allowed_attachments) ||
76			put_user(compat_ptr(data32.allowed_attachments),
77					&data->allowed_attachments) ||
78			put_user(data32.custom_data_size,
79					&data->custom_data_size) ||
80			put_user(compat_ptr(data32.custom_data),
81					&data->custom_data))
82		return -EFAULT;
83
84	ret = adf_file_ioctl(file, ADF_GET_DEVICE_DATA, (unsigned long)data);
85	if (ret < 0)
86		return ret;
87
88	if (copy_in_user(arg->name, data->name, sizeof(arg->name)) ||
89			copy_in_user(&arg->n_attachments, &data->n_attachments,
90					sizeof(arg->n_attachments)) ||
91			copy_in_user(&arg->n_allowed_attachments,
92					&data->n_allowed_attachments,
93					sizeof(arg->n_allowed_attachments)) ||
94			copy_in_user(&arg->custom_data_size,
95					&data->custom_data_size,
96					sizeof(arg->custom_data_size)))
97		return -EFAULT;
98
99	return 0;
100}
101
102long adf_compat_get_interface_data(struct file *file,
103		struct adf_interface_data32 __user *arg)
104{
105	struct adf_interface_data32 data32;
106	struct adf_interface_data __user *data;
107	int ret;
108
109	if (copy_from_user(&data32, arg, sizeof(data32)))
110		return -EFAULT;
111
112	data = compat_alloc_user_space(sizeof(*data));
113	if (!access_ok(VERIFY_WRITE, data, sizeof(*data)))
114		return -EFAULT;
115
116	if (put_user(data32.n_available_modes, &data->n_available_modes) ||
117			put_user(compat_ptr(data32.available_modes),
118					&data->available_modes) ||
119			put_user(data32.custom_data_size,
120					&data->custom_data_size) ||
121			put_user(compat_ptr(data32.custom_data),
122					&data->custom_data))
123		return -EFAULT;
124
125	ret = adf_file_ioctl(file, ADF_GET_INTERFACE_DATA, (unsigned long)data);
126	if (ret < 0)
127		return ret;
128
129	if (copy_in_user(arg->name, data->name, sizeof(arg->name)) ||
130			copy_in_user(&arg->type, &data->type,
131					sizeof(arg->type)) ||
132			copy_in_user(&arg->id, &data->id, sizeof(arg->id)) ||
133			copy_in_user(&arg->flags, &data->flags,
134					sizeof(arg->flags)) ||
135			copy_in_user(&arg->dpms_state, &data->dpms_state,
136					sizeof(arg->dpms_state)) ||
137			copy_in_user(&arg->hotplug_detect,
138					&data->hotplug_detect,
139					sizeof(arg->hotplug_detect)) ||
140			copy_in_user(&arg->width_mm, &data->width_mm,
141					sizeof(arg->width_mm)) ||
142			copy_in_user(&arg->height_mm, &data->height_mm,
143					sizeof(arg->height_mm)) ||
144			copy_in_user(&arg->current_mode, &data->current_mode,
145					sizeof(arg->current_mode)) ||
146			copy_in_user(&arg->n_available_modes,
147					&data->n_available_modes,
148					sizeof(arg->n_available_modes)) ||
149			copy_in_user(&arg->custom_data_size,
150					&data->custom_data_size,
151					sizeof(arg->custom_data_size)))
152		return -EFAULT;
153
154	return 0;
155}
156
157long adf_compat_get_overlay_engine_data(struct file *file,
158		struct adf_overlay_engine_data32 __user *arg)
159{
160	struct adf_overlay_engine_data32 data32;
161	struct adf_overlay_engine_data __user *data;
162	int ret;
163
164	if (copy_from_user(&data32, arg, sizeof(data32)))
165		return -EFAULT;
166
167	data = compat_alloc_user_space(sizeof(*data));
168	if (!access_ok(VERIFY_WRITE, data, sizeof(*data)))
169		return -EFAULT;
170
171	if (put_user(data32.n_supported_formats, &data->n_supported_formats) ||
172			put_user(compat_ptr(data32.supported_formats),
173					&data->supported_formats) ||
174			put_user(data32.custom_data_size,
175					&data->custom_data_size) ||
176			put_user(compat_ptr(data32.custom_data),
177					&data->custom_data))
178		return -EFAULT;
179
180	ret = adf_file_ioctl(file, ADF_GET_OVERLAY_ENGINE_DATA,
181			(unsigned long)data);
182	if (ret < 0)
183		return ret;
184
185	if (copy_in_user(arg->name, data->name, sizeof(arg->name)) ||
186			copy_in_user(&arg->n_supported_formats,
187					&data->n_supported_formats,
188					sizeof(arg->n_supported_formats)) ||
189			copy_in_user(&arg->custom_data_size,
190					&data->custom_data_size,
191					sizeof(arg->custom_data_size)))
192		return -EFAULT;
193
194	return 0;
195}
196
197long adf_file_compat_ioctl(struct file *file, unsigned int cmd,
198		unsigned long arg)
199{
200	switch (cmd) {
201	case ADF_POST_CONFIG32:
202		return adf_compat_post_config(file, compat_ptr(arg));
203
204	case ADF_GET_DEVICE_DATA32:
205		return adf_compat_get_device_data(file, compat_ptr(arg));
206
207	case ADF_GET_INTERFACE_DATA32:
208		return adf_compat_get_interface_data(file, compat_ptr(arg));
209
210	case ADF_GET_OVERLAY_ENGINE_DATA32:
211		return adf_compat_get_overlay_engine_data(file,
212				compat_ptr(arg));
213
214	default:
215		return adf_file_ioctl(file, cmd, arg);
216	}
217}
218