blob: 9810e37845c7ab48e4d3cef8f215dd4bfab6fac5 [file] [log] [blame]
David Schleefed9eccb2008-11-04 20:29:31 -08001/*
2 comedi/comedi_compat32.c
3 32-bit ioctl compatibility for 64-bit comedi kernel module.
4
5 Author: Ian Abbott, MEV Ltd. <abbotti@mev.co.uk>
6 Copyright (C) 2007 MEV Ltd. <http://www.mev.co.uk/>
7
8 COMEDI - Linux Control and Measurement Device Interface
9 Copyright (C) 1997-2007 David A. Schleef <ds@schleef.org>
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24
25*/
26
27#define __NO_VERSION__
28#include "comedi.h"
29#include <linux/smp_lock.h>
30#include <asm/uaccess.h>
31
32#include "comedi_compat32.h"
33
34#ifdef CONFIG_COMPAT
35
36#ifndef HAVE_COMPAT_IOCTL
37#include <linux/ioctl32.h> /* for (un)register_ioctl32_conversion */
38#endif
39
Greg Kroah-Hartman01914922009-03-20 21:34:38 -070040#define COMEDI32_CHANINFO _IOR(CIO, 3, struct comedi32_chaninfo_struct)
41#define COMEDI32_RANGEINFO _IOR(CIO, 8, struct comedi32_rangeinfo_struct)
David Schleefed9eccb2008-11-04 20:29:31 -080042/* N.B. COMEDI32_CMD and COMEDI_CMD ought to use _IOWR, not _IOR.
43 * It's too late to change it now, but it only affects the command number. */
Greg Kroah-Hartman01914922009-03-20 21:34:38 -070044#define COMEDI32_CMD _IOR(CIO, 9, struct comedi32_cmd_struct)
David Schleefed9eccb2008-11-04 20:29:31 -080045/* N.B. COMEDI32_CMDTEST and COMEDI_CMDTEST ought to use _IOWR, not _IOR.
46 * It's too late to change it now, but it only affects the command number. */
Greg Kroah-Hartman01914922009-03-20 21:34:38 -070047#define COMEDI32_CMDTEST _IOR(CIO, 10, struct comedi32_cmd_struct)
48#define COMEDI32_INSNLIST _IOR(CIO, 11, struct comedi32_insnlist_struct)
49#define COMEDI32_INSN _IOR(CIO, 12, struct comedi32_insn_struct)
David Schleefed9eccb2008-11-04 20:29:31 -080050
Bill Pembertonbf8db92e2009-03-16 22:04:29 -040051struct comedi32_chaninfo_struct {
David Schleefed9eccb2008-11-04 20:29:31 -080052 unsigned int subdev;
Bill Pemberton790c5542009-03-16 22:05:02 -040053 compat_uptr_t maxdata_list; /* 32-bit 'unsigned int *' */
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +053054 compat_uptr_t flaglist; /* 32-bit 'unsigned int *' */
David Schleefed9eccb2008-11-04 20:29:31 -080055 compat_uptr_t rangelist; /* 32-bit 'unsigned int *' */
56 unsigned int unused[4];
Bill Pembertonbf8db92e2009-03-16 22:04:29 -040057};
David Schleefed9eccb2008-11-04 20:29:31 -080058
Bill Pembertonbf8db92e2009-03-16 22:04:29 -040059struct comedi32_rangeinfo_struct {
David Schleefed9eccb2008-11-04 20:29:31 -080060 unsigned int range_type;
61 compat_uptr_t range_ptr; /* 32-bit 'void *' */
Bill Pembertonbf8db92e2009-03-16 22:04:29 -040062};
David Schleefed9eccb2008-11-04 20:29:31 -080063
Bill Pembertonbf8db92e2009-03-16 22:04:29 -040064struct comedi32_cmd_struct {
David Schleefed9eccb2008-11-04 20:29:31 -080065 unsigned int subdev;
66 unsigned int flags;
67 unsigned int start_src;
68 unsigned int start_arg;
69 unsigned int scan_begin_src;
70 unsigned int scan_begin_arg;
71 unsigned int convert_src;
72 unsigned int convert_arg;
73 unsigned int scan_end_src;
74 unsigned int scan_end_arg;
75 unsigned int stop_src;
76 unsigned int stop_arg;
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +053077 compat_uptr_t chanlist; /* 32-bit 'unsigned int *' */
David Schleefed9eccb2008-11-04 20:29:31 -080078 unsigned int chanlist_len;
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +053079 compat_uptr_t data; /* 32-bit 'short *' */
David Schleefed9eccb2008-11-04 20:29:31 -080080 unsigned int data_len;
Bill Pembertonbf8db92e2009-03-16 22:04:29 -040081};
David Schleefed9eccb2008-11-04 20:29:31 -080082
Bill Pembertonbf8db92e2009-03-16 22:04:29 -040083struct comedi32_insn_struct {
David Schleefed9eccb2008-11-04 20:29:31 -080084 unsigned int insn;
85 unsigned int n;
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +053086 compat_uptr_t data; /* 32-bit 'unsigned int *' */
David Schleefed9eccb2008-11-04 20:29:31 -080087 unsigned int subdev;
88 unsigned int chanspec;
89 unsigned int unused[3];
Bill Pembertonbf8db92e2009-03-16 22:04:29 -040090};
David Schleefed9eccb2008-11-04 20:29:31 -080091
Bill Pembertonbf8db92e2009-03-16 22:04:29 -040092struct comedi32_insnlist_struct {
David Schleefed9eccb2008-11-04 20:29:31 -080093 unsigned int n_insns;
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +053094 compat_uptr_t insns; /* 32-bit 'struct comedi_insn *' */
Bill Pembertonbf8db92e2009-03-16 22:04:29 -040095};
David Schleefed9eccb2008-11-04 20:29:31 -080096
97/* Handle translated ioctl. */
98static int translated_ioctl(struct file *file, unsigned int cmd,
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +053099 unsigned long arg)
David Schleefed9eccb2008-11-04 20:29:31 -0800100{
Bill Pemberton82675f32009-03-16 22:04:23 -0400101 if (!file->f_op)
David Schleefed9eccb2008-11-04 20:29:31 -0800102 return -ENOTTY;
Bill Pemberton82675f32009-03-16 22:04:23 -0400103
David Schleefed9eccb2008-11-04 20:29:31 -0800104#ifdef HAVE_UNLOCKED_IOCTL
105 if (file->f_op->unlocked_ioctl) {
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530106 int rc = (int)(*file->f_op->unlocked_ioctl) (file, cmd, arg);
Bill Pemberton82675f32009-03-16 22:04:23 -0400107 if (rc == -ENOIOCTLCMD)
David Schleefed9eccb2008-11-04 20:29:31 -0800108 rc = -ENOTTY;
David Schleefed9eccb2008-11-04 20:29:31 -0800109 return rc;
110 }
111#endif
112 if (file->f_op->ioctl) {
113 int rc;
114 lock_kernel();
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530115 rc = (*file->f_op->ioctl) (file->f_dentry->d_inode,
116 file, cmd, arg);
David Schleefed9eccb2008-11-04 20:29:31 -0800117 unlock_kernel();
118 return rc;
119 }
120 return -ENOTTY;
121}
122
123/* Handle 32-bit COMEDI_CHANINFO ioctl. */
124static int compat_chaninfo(struct file *file, unsigned long arg)
125{
Greg Kroah-Hartman01914922009-03-20 21:34:38 -0700126 struct comedi_chaninfo __user *chaninfo;
Bill Pembertonbf8db92e2009-03-16 22:04:29 -0400127 struct comedi32_chaninfo_struct __user *chaninfo32;
David Schleefed9eccb2008-11-04 20:29:31 -0800128 int err;
129 union {
130 unsigned int uint;
131 compat_uptr_t uptr;
132 } temp;
133
134 chaninfo32 = compat_ptr(arg);
135 chaninfo = compat_alloc_user_space(sizeof(*chaninfo));
136
137 /* Copy chaninfo structure. Ignore unused members. */
138 if (!access_ok(VERIFY_READ, chaninfo32, sizeof(*chaninfo32))
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530139 || !access_ok(VERIFY_WRITE, chaninfo, sizeof(*chaninfo))) {
David Schleefed9eccb2008-11-04 20:29:31 -0800140 return -EFAULT;
141 }
142 err = 0;
143 err |= __get_user(temp.uint, &chaninfo32->subdev);
144 err |= __put_user(temp.uint, &chaninfo->subdev);
145 err |= __get_user(temp.uptr, &chaninfo32->maxdata_list);
146 err |= __put_user(compat_ptr(temp.uptr), &chaninfo->maxdata_list);
147 err |= __get_user(temp.uptr, &chaninfo32->flaglist);
148 err |= __put_user(compat_ptr(temp.uptr), &chaninfo->flaglist);
149 err |= __get_user(temp.uptr, &chaninfo32->rangelist);
150 err |= __put_user(compat_ptr(temp.uptr), &chaninfo->rangelist);
Bill Pemberton82675f32009-03-16 22:04:23 -0400151 if (err)
David Schleefed9eccb2008-11-04 20:29:31 -0800152 return -EFAULT;
David Schleefed9eccb2008-11-04 20:29:31 -0800153
154 return translated_ioctl(file, COMEDI_CHANINFO, (unsigned long)chaninfo);
155}
156
157/* Handle 32-bit COMEDI_RANGEINFO ioctl. */
158static int compat_rangeinfo(struct file *file, unsigned long arg)
159{
Bill Pembertond0a353f2009-03-16 22:06:26 -0400160 struct comedi_rangeinfo __user *rangeinfo;
Bill Pembertonbf8db92e2009-03-16 22:04:29 -0400161 struct comedi32_rangeinfo_struct __user *rangeinfo32;
David Schleefed9eccb2008-11-04 20:29:31 -0800162 int err;
163 union {
164 unsigned int uint;
165 compat_uptr_t uptr;
166 } temp;
167
168 rangeinfo32 = compat_ptr(arg);
169 rangeinfo = compat_alloc_user_space(sizeof(*rangeinfo));
170
171 /* Copy rangeinfo structure. */
172 if (!access_ok(VERIFY_READ, rangeinfo32, sizeof(*rangeinfo32))
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530173 || !access_ok(VERIFY_WRITE, rangeinfo, sizeof(*rangeinfo))) {
David Schleefed9eccb2008-11-04 20:29:31 -0800174 return -EFAULT;
175 }
176 err = 0;
177 err |= __get_user(temp.uint, &rangeinfo32->range_type);
178 err |= __put_user(temp.uint, &rangeinfo->range_type);
179 err |= __get_user(temp.uptr, &rangeinfo32->range_ptr);
180 err |= __put_user(compat_ptr(temp.uptr), &rangeinfo->range_ptr);
Bill Pemberton82675f32009-03-16 22:04:23 -0400181 if (err)
David Schleefed9eccb2008-11-04 20:29:31 -0800182 return -EFAULT;
David Schleefed9eccb2008-11-04 20:29:31 -0800183
184 return translated_ioctl(file, COMEDI_RANGEINFO,
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530185 (unsigned long)rangeinfo);
David Schleefed9eccb2008-11-04 20:29:31 -0800186}
187
188/* Copy 32-bit cmd structure to native cmd structure. */
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530189static int get_compat_cmd(struct comedi_cmd __user * cmd,
190 struct comedi32_cmd_struct __user * cmd32)
David Schleefed9eccb2008-11-04 20:29:31 -0800191{
192 int err;
193 union {
194 unsigned int uint;
195 compat_uptr_t uptr;
196 } temp;
197
198 /* Copy cmd structure. */
199 if (!access_ok(VERIFY_READ, cmd32, sizeof(*cmd32))
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530200 || !access_ok(VERIFY_WRITE, cmd, sizeof(*cmd))) {
David Schleefed9eccb2008-11-04 20:29:31 -0800201 return -EFAULT;
202 }
203 err = 0;
204 err |= __get_user(temp.uint, &cmd32->subdev);
205 err |= __put_user(temp.uint, &cmd->subdev);
206 err |= __get_user(temp.uint, &cmd32->flags);
207 err |= __put_user(temp.uint, &cmd->flags);
208 err |= __get_user(temp.uint, &cmd32->start_src);
209 err |= __put_user(temp.uint, &cmd->start_src);
210 err |= __get_user(temp.uint, &cmd32->start_arg);
211 err |= __put_user(temp.uint, &cmd->start_arg);
212 err |= __get_user(temp.uint, &cmd32->scan_begin_src);
213 err |= __put_user(temp.uint, &cmd->scan_begin_src);
214 err |= __get_user(temp.uint, &cmd32->scan_begin_arg);
215 err |= __put_user(temp.uint, &cmd->scan_begin_arg);
216 err |= __get_user(temp.uint, &cmd32->convert_src);
217 err |= __put_user(temp.uint, &cmd->convert_src);
218 err |= __get_user(temp.uint, &cmd32->convert_arg);
219 err |= __put_user(temp.uint, &cmd->convert_arg);
220 err |= __get_user(temp.uint, &cmd32->scan_end_src);
221 err |= __put_user(temp.uint, &cmd->scan_end_src);
222 err |= __get_user(temp.uint, &cmd32->scan_end_arg);
223 err |= __put_user(temp.uint, &cmd->scan_end_arg);
224 err |= __get_user(temp.uint, &cmd32->stop_src);
225 err |= __put_user(temp.uint, &cmd->stop_src);
226 err |= __get_user(temp.uint, &cmd32->stop_arg);
227 err |= __put_user(temp.uint, &cmd->stop_arg);
228 err |= __get_user(temp.uptr, &cmd32->chanlist);
229 err |= __put_user(compat_ptr(temp.uptr), &cmd->chanlist);
230 err |= __get_user(temp.uint, &cmd32->chanlist_len);
231 err |= __put_user(temp.uint, &cmd->chanlist_len);
232 err |= __get_user(temp.uptr, &cmd32->data);
233 err |= __put_user(compat_ptr(temp.uptr), &cmd->data);
234 err |= __get_user(temp.uint, &cmd32->data_len);
235 err |= __put_user(temp.uint, &cmd->data_len);
236 return err ? -EFAULT : 0;
237}
238
239/* Copy native cmd structure to 32-bit cmd structure. */
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530240static int put_compat_cmd(struct comedi32_cmd_struct __user * cmd32,
241 struct comedi_cmd __user * cmd)
David Schleefed9eccb2008-11-04 20:29:31 -0800242{
243 int err;
244 unsigned int temp;
245
246 /* Copy back most of cmd structure. */
247 /* Assume the pointer values are already valid. */
248 /* (Could use ptr_to_compat() to set them, but that wasn't implemented
249 * until kernel version 2.6.11.) */
250 if (!access_ok(VERIFY_READ, cmd, sizeof(*cmd))
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530251 || !access_ok(VERIFY_WRITE, cmd32, sizeof(*cmd32))) {
David Schleefed9eccb2008-11-04 20:29:31 -0800252 return -EFAULT;
253 }
254 err = 0;
255 err |= __get_user(temp, &cmd->subdev);
256 err |= __put_user(temp, &cmd32->subdev);
257 err |= __get_user(temp, &cmd->flags);
258 err |= __put_user(temp, &cmd32->flags);
259 err |= __get_user(temp, &cmd->start_src);
260 err |= __put_user(temp, &cmd32->start_src);
261 err |= __get_user(temp, &cmd->start_arg);
262 err |= __put_user(temp, &cmd32->start_arg);
263 err |= __get_user(temp, &cmd->scan_begin_src);
264 err |= __put_user(temp, &cmd32->scan_begin_src);
265 err |= __get_user(temp, &cmd->scan_begin_arg);
266 err |= __put_user(temp, &cmd32->scan_begin_arg);
267 err |= __get_user(temp, &cmd->convert_src);
268 err |= __put_user(temp, &cmd32->convert_src);
269 err |= __get_user(temp, &cmd->convert_arg);
270 err |= __put_user(temp, &cmd32->convert_arg);
271 err |= __get_user(temp, &cmd->scan_end_src);
272 err |= __put_user(temp, &cmd32->scan_end_src);
273 err |= __get_user(temp, &cmd->scan_end_arg);
274 err |= __put_user(temp, &cmd32->scan_end_arg);
275 err |= __get_user(temp, &cmd->stop_src);
276 err |= __put_user(temp, &cmd32->stop_src);
277 err |= __get_user(temp, &cmd->stop_arg);
278 err |= __put_user(temp, &cmd32->stop_arg);
279 /* Assume chanlist pointer is unchanged. */
280 err |= __get_user(temp, &cmd->chanlist_len);
281 err |= __put_user(temp, &cmd32->chanlist_len);
282 /* Assume data pointer is unchanged. */
283 err |= __get_user(temp, &cmd->data_len);
284 err |= __put_user(temp, &cmd32->data_len);
285 return err ? -EFAULT : 0;
286}
287
288/* Handle 32-bit COMEDI_CMD ioctl. */
289static int compat_cmd(struct file *file, unsigned long arg)
290{
Bill Pembertonea6d0d42009-03-16 22:05:47 -0400291 struct comedi_cmd __user *cmd;
Bill Pembertonbf8db92e2009-03-16 22:04:29 -0400292 struct comedi32_cmd_struct __user *cmd32;
David Schleefed9eccb2008-11-04 20:29:31 -0800293 int rc;
294
295 cmd32 = compat_ptr(arg);
296 cmd = compat_alloc_user_space(sizeof(*cmd));
297
298 rc = get_compat_cmd(cmd, cmd32);
Bill Pemberton82675f32009-03-16 22:04:23 -0400299 if (rc)
David Schleefed9eccb2008-11-04 20:29:31 -0800300 return rc;
David Schleefed9eccb2008-11-04 20:29:31 -0800301
302 return translated_ioctl(file, COMEDI_CMD, (unsigned long)cmd);
303}
304
305/* Handle 32-bit COMEDI_CMDTEST ioctl. */
306static int compat_cmdtest(struct file *file, unsigned long arg)
307{
Bill Pembertonea6d0d42009-03-16 22:05:47 -0400308 struct comedi_cmd __user *cmd;
Bill Pembertonbf8db92e2009-03-16 22:04:29 -0400309 struct comedi32_cmd_struct __user *cmd32;
David Schleefed9eccb2008-11-04 20:29:31 -0800310 int rc, err;
311
312 cmd32 = compat_ptr(arg);
313 cmd = compat_alloc_user_space(sizeof(*cmd));
314
315 rc = get_compat_cmd(cmd, cmd32);
Bill Pemberton82675f32009-03-16 22:04:23 -0400316 if (rc)
David Schleefed9eccb2008-11-04 20:29:31 -0800317 return rc;
David Schleefed9eccb2008-11-04 20:29:31 -0800318
319 rc = translated_ioctl(file, COMEDI_CMDTEST, (unsigned long)cmd);
Bill Pemberton82675f32009-03-16 22:04:23 -0400320 if (rc < 0)
David Schleefed9eccb2008-11-04 20:29:31 -0800321 return rc;
David Schleefed9eccb2008-11-04 20:29:31 -0800322
323 err = put_compat_cmd(cmd32, cmd);
Bill Pemberton82675f32009-03-16 22:04:23 -0400324 if (err)
David Schleefed9eccb2008-11-04 20:29:31 -0800325 rc = err;
Bill Pemberton82675f32009-03-16 22:04:23 -0400326
David Schleefed9eccb2008-11-04 20:29:31 -0800327 return rc;
328}
329
330/* Copy 32-bit insn structure to native insn structure. */
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530331static int get_compat_insn(struct comedi_insn __user * insn,
332 struct comedi32_insn_struct __user * insn32)
David Schleefed9eccb2008-11-04 20:29:31 -0800333{
334 int err;
335 union {
336 unsigned int uint;
337 compat_uptr_t uptr;
338 } temp;
339
340 /* Copy insn structure. Ignore the unused members. */
341 err = 0;
342 if (!access_ok(VERIFY_READ, insn32, sizeof(*insn32))
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530343 || !access_ok(VERIFY_WRITE, insn, sizeof(*insn)))
David Schleefed9eccb2008-11-04 20:29:31 -0800344 return -EFAULT;
Bill Pemberton82675f32009-03-16 22:04:23 -0400345
David Schleefed9eccb2008-11-04 20:29:31 -0800346 err |= __get_user(temp.uint, &insn32->insn);
347 err |= __put_user(temp.uint, &insn->insn);
348 err |= __get_user(temp.uint, &insn32->n);
349 err |= __put_user(temp.uint, &insn->n);
350 err |= __get_user(temp.uptr, &insn32->data);
351 err |= __put_user(compat_ptr(temp.uptr), &insn->data);
352 err |= __get_user(temp.uint, &insn32->subdev);
353 err |= __put_user(temp.uint, &insn->subdev);
354 err |= __get_user(temp.uint, &insn32->chanspec);
355 err |= __put_user(temp.uint, &insn->chanspec);
356 return err ? -EFAULT : 0;
357}
358
359/* Handle 32-bit COMEDI_INSNLIST ioctl. */
360static int compat_insnlist(struct file *file, unsigned long arg)
361{
362 struct combined_insnlist {
Bill Pembertonda613f42009-03-16 22:05:59 -0400363 struct comedi_insnlist insnlist;
Bill Pemberton90035c02009-03-16 22:05:53 -0400364 struct comedi_insn insn[1];
David Schleefed9eccb2008-11-04 20:29:31 -0800365 } __user *s;
Bill Pembertonbf8db92e2009-03-16 22:04:29 -0400366 struct comedi32_insnlist_struct __user *insnlist32;
367 struct comedi32_insn_struct __user *insn32;
David Schleefed9eccb2008-11-04 20:29:31 -0800368 compat_uptr_t uptr;
369 unsigned int n_insns, n;
370 int err, rc;
371
372 insnlist32 = compat_ptr(arg);
373
374 /* Get 32-bit insnlist structure. */
375 if (!access_ok(VERIFY_READ, insnlist32, sizeof(*insnlist32))) {
376 return -EFAULT;
377 }
378 err = 0;
379 err |= __get_user(n_insns, &insnlist32->n_insns);
380 err |= __get_user(uptr, &insnlist32->insns);
381 insn32 = compat_ptr(uptr);
Bill Pemberton82675f32009-03-16 22:04:23 -0400382 if (err)
David Schleefed9eccb2008-11-04 20:29:31 -0800383 return -EFAULT;
David Schleefed9eccb2008-11-04 20:29:31 -0800384
385 /* Allocate user memory to copy insnlist and insns into. */
386 s = compat_alloc_user_space(offsetof(struct combined_insnlist,
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530387 insn[n_insns]));
David Schleefed9eccb2008-11-04 20:29:31 -0800388
389 /* Set native insnlist structure. */
390 if (!access_ok(VERIFY_WRITE, &s->insnlist, sizeof(s->insnlist))) {
391 return -EFAULT;
392 }
393 err |= __put_user(n_insns, &s->insnlist.n_insns);
394 err |= __put_user(&s->insn[0], &s->insnlist.insns);
Bill Pemberton82675f32009-03-16 22:04:23 -0400395 if (err)
David Schleefed9eccb2008-11-04 20:29:31 -0800396 return -EFAULT;
David Schleefed9eccb2008-11-04 20:29:31 -0800397
398 /* Copy insn structures. */
399 for (n = 0; n < n_insns; n++) {
400 rc = get_compat_insn(&s->insn[n], &insn32[n]);
Bill Pemberton82675f32009-03-16 22:04:23 -0400401 if (rc)
David Schleefed9eccb2008-11-04 20:29:31 -0800402 return rc;
David Schleefed9eccb2008-11-04 20:29:31 -0800403 }
404
405 return translated_ioctl(file, COMEDI_INSNLIST,
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530406 (unsigned long)&s->insnlist);
David Schleefed9eccb2008-11-04 20:29:31 -0800407}
408
409/* Handle 32-bit COMEDI_INSN ioctl. */
410static int compat_insn(struct file *file, unsigned long arg)
411{
Bill Pemberton90035c02009-03-16 22:05:53 -0400412 struct comedi_insn __user *insn;
Bill Pembertonbf8db92e2009-03-16 22:04:29 -0400413 struct comedi32_insn_struct __user *insn32;
David Schleefed9eccb2008-11-04 20:29:31 -0800414 int rc;
415
416 insn32 = compat_ptr(arg);
417 insn = compat_alloc_user_space(sizeof(*insn));
418
419 rc = get_compat_insn(insn, insn32);
Bill Pemberton82675f32009-03-16 22:04:23 -0400420 if (rc)
David Schleefed9eccb2008-11-04 20:29:31 -0800421 return rc;
David Schleefed9eccb2008-11-04 20:29:31 -0800422
423 return translated_ioctl(file, COMEDI_INSN, (unsigned long)insn);
424}
425
426/* Process untranslated ioctl. */
427/* Returns -ENOIOCTLCMD for unrecognised ioctl codes. */
428static inline int raw_ioctl(struct file *file, unsigned int cmd,
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530429 unsigned long arg)
David Schleefed9eccb2008-11-04 20:29:31 -0800430{
431 int rc;
432
433 switch (cmd) {
434 case COMEDI_DEVCONFIG:
435 case COMEDI_DEVINFO:
436 case COMEDI_SUBDINFO:
437 case COMEDI_BUFCONFIG:
438 case COMEDI_BUFINFO:
439 /* Just need to translate the pointer argument. */
440 arg = (unsigned long)compat_ptr(arg);
441 rc = translated_ioctl(file, cmd, arg);
442 break;
443 case COMEDI_LOCK:
444 case COMEDI_UNLOCK:
445 case COMEDI_CANCEL:
446 case COMEDI_POLL:
447 /* No translation needed. */
448 rc = translated_ioctl(file, cmd, arg);
449 break;
450 case COMEDI32_CHANINFO:
451 rc = compat_chaninfo(file, arg);
452 break;
453 case COMEDI32_RANGEINFO:
454 rc = compat_rangeinfo(file, arg);
455 break;
456 case COMEDI32_CMD:
457 rc = compat_cmd(file, arg);
458 break;
459 case COMEDI32_CMDTEST:
460 rc = compat_cmdtest(file, arg);
461 break;
462 case COMEDI32_INSNLIST:
463 rc = compat_insnlist(file, arg);
464 break;
465 case COMEDI32_INSN:
466 rc = compat_insn(file, arg);
467 break;
468 default:
469 rc = -ENOIOCTLCMD;
470 break;
471 }
472 return rc;
473}
474
475#ifdef HAVE_COMPAT_IOCTL /* defined in <linux/fs.h> 2.6.11 onwards */
476
477/* compat_ioctl file operation. */
478/* Returns -ENOIOCTLCMD for unrecognised ioctl codes. */
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530479long comedi_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
David Schleefed9eccb2008-11-04 20:29:31 -0800480{
481 return raw_ioctl(file, cmd, arg);
482}
483
484#else /* HAVE_COMPAT_IOCTL */
485
486/*
487 * Brain-dead ioctl compatibility for 2.6.10 and earlier.
488 *
489 * It's brain-dead because cmd numbers need to be unique system-wide!
490 * The comedi driver could end up attempting to execute ioctls for non-Comedi
491 * devices because it registered the system-wide cmd code first. Similarly,
492 * another driver could end up attempting to execute ioctls for a Comedi
493 * device because it registered the cmd code first. Chaos ensues.
494 */
495
496/* Handler for all 32-bit ioctl codes registered by this driver. */
497static int mapped_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg,
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530498 struct file *file)
David Schleefed9eccb2008-11-04 20:29:31 -0800499{
500 int rc;
501
502 /* Make sure we are dealing with a Comedi device. */
Bill Pemberton82675f32009-03-16 22:04:23 -0400503 if (imajor(file->f_dentry->d_inode) != COMEDI_MAJOR)
David Schleefed9eccb2008-11-04 20:29:31 -0800504 return -ENOTTY;
Bill Pemberton82675f32009-03-16 22:04:23 -0400505
David Schleefed9eccb2008-11-04 20:29:31 -0800506 rc = raw_ioctl(file, cmd, arg);
507 /* Do not return -ENOIOCTLCMD. */
Bill Pemberton82675f32009-03-16 22:04:23 -0400508 if (rc == -ENOIOCTLCMD)
David Schleefed9eccb2008-11-04 20:29:31 -0800509 rc = -ENOTTY;
Bill Pemberton82675f32009-03-16 22:04:23 -0400510
David Schleefed9eccb2008-11-04 20:29:31 -0800511 return rc;
512}
513
514struct ioctl32_map {
515 unsigned int cmd;
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530516 int (*handler) (unsigned int, unsigned int, unsigned long,
David Schleefed9eccb2008-11-04 20:29:31 -0800517 struct file *);
518 int registered;
519};
520
521static struct ioctl32_map comedi_ioctl32_map[] = {
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530522 {COMEDI_DEVCONFIG, mapped_ioctl, 0},
523 {COMEDI_DEVINFO, mapped_ioctl, 0},
524 {COMEDI_SUBDINFO, mapped_ioctl, 0},
525 {COMEDI_BUFCONFIG, mapped_ioctl, 0},
526 {COMEDI_BUFINFO, mapped_ioctl, 0},
527 {COMEDI_LOCK, mapped_ioctl, 0},
528 {COMEDI_UNLOCK, mapped_ioctl, 0},
529 {COMEDI_CANCEL, mapped_ioctl, 0},
530 {COMEDI_POLL, mapped_ioctl, 0},
531 {COMEDI32_CHANINFO, mapped_ioctl, 0},
532 {COMEDI32_RANGEINFO, mapped_ioctl, 0},
533 {COMEDI32_CMD, mapped_ioctl, 0},
534 {COMEDI32_CMDTEST, mapped_ioctl, 0},
535 {COMEDI32_INSNLIST, mapped_ioctl, 0},
536 {COMEDI32_INSN, mapped_ioctl, 0},
David Schleefed9eccb2008-11-04 20:29:31 -0800537};
538
539#define NUM_IOCTL32_MAPS ARRAY_SIZE(comedi_ioctl32_map)
540
541/* Register system-wide 32-bit ioctl handlers. */
542void comedi_register_ioctl32(void)
543{
544 int n, rc;
545
546 for (n = 0; n < NUM_IOCTL32_MAPS; n++) {
547 rc = register_ioctl32_conversion(comedi_ioctl32_map[n].cmd,
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530548 comedi_ioctl32_map[n].handler);
David Schleefed9eccb2008-11-04 20:29:31 -0800549 if (rc) {
550 printk(KERN_WARNING
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530551 "comedi: failed to register 32-bit "
552 "compatible ioctl handler for 0x%X - "
553 "expect bad things to happen!\n",
554 comedi_ioctl32_map[n].cmd);
David Schleefed9eccb2008-11-04 20:29:31 -0800555 }
556 comedi_ioctl32_map[n].registered = !rc;
557 }
558}
559
560/* Unregister system-wide 32-bit ioctl translations. */
561void comedi_unregister_ioctl32(void)
562{
563 int n, rc;
564
565 for (n = 0; n < NUM_IOCTL32_MAPS; n++) {
566 if (comedi_ioctl32_map[n].registered) {
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530567 rc = unregister_ioctl32_conversion(comedi_ioctl32_map
568 [n].cmd,
569 comedi_ioctl32_map
570 [n].handler);
David Schleefed9eccb2008-11-04 20:29:31 -0800571 if (rc) {
572 printk(KERN_ERR
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530573 "comedi: failed to unregister 32-bit "
574 "compatible ioctl handler for 0x%X - "
575 "expect kernel Oops!\n",
576 comedi_ioctl32_map[n].cmd);
David Schleefed9eccb2008-11-04 20:29:31 -0800577 } else {
578 comedi_ioctl32_map[n].registered = 0;
579 }
580 }
581 }
582}
583
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530584#endif /* HAVE_COMPAT_IOCTL */
David Schleefed9eccb2008-11-04 20:29:31 -0800585
Mithlesh Thukral0a85b6f2009-06-08 21:04:41 +0530586#endif /* CONFIG_COMPAT */