From: Ian Abbott Date: Wed, 7 Nov 2007 16:03:15 +0000 (+0000) Subject: Support 32-bit ioctl calls on 64-bit kernel (CONFIG_COMPAT). X-Git-Tag: v0_7_76~94 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=a36a7b4facba016c0f85844ba9997d45dac7acb2;p=comedi.git Support 32-bit ioctl calls on 64-bit kernel (CONFIG_COMPAT). --- diff --git a/comedi/Kbuild b/comedi/Kbuild index b744d040..e1fa4fc3 100644 --- a/comedi/Kbuild +++ b/comedi/Kbuild @@ -4,6 +4,7 @@ include comedi_kbuild.inc obj-m += comedi.o comedi-y := comedi_fops.o proc.o range.o drivers.o comedi_ksyms.o comedi-$(CONFIG_COMEDI_RT) += rt_pend_tq.o rt.o +comedi-$(CONFIG_COMPAT) += comedi_compat32.o obj-y += kcomedilib/ obj-y += drivers/ diff --git a/comedi/Makefile.am b/comedi/Makefile.am index 0ba5bc21..7fe641ef 100644 --- a/comedi/Makefile.am +++ b/comedi/Makefile.am @@ -43,7 +43,8 @@ endif EXTRA_DIST = \ Kbuild \ rt_pend_tq.h \ - comedi_fops.h + comedi_fops.h \ + comedi_compat32.h if CONFIG_COMEDI_RT RT_SOURCES = rt_pend_tq.c rt.c @@ -56,6 +57,7 @@ comedi_ko_SOURCES = \ proc.c \ range.c \ drivers.c \ + comedi_compat32.c \ comedi_ksyms.c \ $(RT_SOURCES) diff --git a/comedi/comedi_compat32.c b/comedi/comedi_compat32.c new file mode 100644 index 00000000..89ce85d9 --- /dev/null +++ b/comedi/comedi_compat32.c @@ -0,0 +1,574 @@ +/* + comedi/comedi_compat32.c + 32-bit ioctl compatibility for 64-bit comedi kernel module. + + Author: Ian Abbott, MEV Ltd. + Copyright (C) 2007 MEV Ltd. + + COMEDI - Linux Control and Measurement Device Interface + Copyright (C) 1997-2007 David A. Schleef + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#define __NO_VERSION__ +#include +#include +#include + +#include "comedi_compat32.h" + +#ifdef CONFIG_COMPAT + +#define COMEDI32_CHANINFO _IOR(CIO,3,comedi32_chaninfo) +#define COMEDI32_RANGEINFO _IOR(CIO,8,comedi32_rangeinfo) +#define COMEDI32_CMD _IOR(CIO,9,comedi32_cmd) +/* N.B. COMEDI32_CMDTEST and COMEDI_CMDTEST ought to use _IOWR, not _IOR. + * It's too late to change it now, but it only affects the command number. */ +#define COMEDI32_CMDTEST _IOR(CIO,10,comedi32_cmd) +#define COMEDI32_INSNLIST _IOR(CIO,11,comedi32_insnlist) +#define COMEDI32_INSN _IOR(CIO,12,comedi32_insn) + +typedef struct comedi32_chaninfo_struct { + unsigned int subdev; + compat_uptr_t maxdata_list; /* 32-bit 'lsampl_t *' */ + compat_uptr_t flaglist; /* 32-bit 'unsigned int *' */ + compat_uptr_t rangelist; /* 32-bit 'unsigned int *' */ + unsigned int unused[4]; +} comedi32_chaninfo; + +typedef struct comedi32_rangeinfo_struct { + unsigned int range_type; + compat_uptr_t range_ptr; /* 32-bit 'void *' */ +} comedi32_rangeinfo; + +typedef struct comedi32_cmd_struct { + unsigned int subdev; + unsigned int flags; + unsigned int start_src; + unsigned int start_arg; + unsigned int scan_begin_src; + unsigned int scan_begin_arg; + unsigned int convert_src; + unsigned int convert_arg; + unsigned int scan_end_src; + unsigned int scan_end_arg; + unsigned int stop_src; + unsigned int stop_arg; + compat_uptr_t chanlist; /* 32-bit 'unsigned int *' */ + unsigned int chanlist_len; + compat_uptr_t data; /* 32-bit 'sampl_t *' */ + unsigned int data_len; +} comedi32_cmd; + +typedef struct comedi32_insn_struct { + unsigned int insn; + unsigned int n; + compat_uptr_t data; /* 32-bit 'lsampl_t *' */ + unsigned int subdev; + unsigned int chanspec; + unsigned int unused[3]; +} comedi32_insn; + +typedef struct comedi32_insnlist_struct { + unsigned int n_insns; + compat_uptr_t insns; /* 32-bit 'comedi_insn *' */ +} comedi32_insnlist; + +/* Handle translated ioctl. */ +static int translated_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + if (!file->f_op) { + return -ENOTTY; + } +#ifdef HAVE_UNLOCKED_IOCTL + if (file->f_op->unlocked_ioctl) { + int rc = (int)(*file->f_op->unlocked_ioctl)(file, cmd, arg); + if (rc == -ENOIOCTLCMD) { + rc = -ENOTTY; + } + return rc; + } +#endif + if (file->f_op->ioctl) { + int rc; + lock_kernel(); + rc = (*file->f_op->ioctl)(file->f_dentry->d_inode, + file, cmd, arg); + unlock_kernel(); + return rc; + } + return -ENOTTY; +} + +/* Handle 32-bit COMEDI_CHANINFO ioctl. */ +static int compat_chaninfo(struct file *file, unsigned long arg) +{ + comedi_chaninfo __user *chaninfo; + comedi32_chaninfo __user *chaninfo32; + int err; + union { + unsigned int uint; + compat_uptr_t uptr; + } temp; + + chaninfo32 = compat_ptr(arg); + chaninfo = compat_alloc_user_space(sizeof(*chaninfo)); + + /* Copy chaninfo structure. Ignore unused members. */ + if (!access_ok(VERIFY_READ, chaninfo32, sizeof(*chaninfo32)) + || !access_ok(VERIFY_WRITE, chaninfo, + sizeof(*chaninfo))) { + return -EFAULT; + } + err = 0; + err |= __get_user(temp.uint, &chaninfo32->subdev); + err |= __put_user(temp.uint, &chaninfo->subdev); + err |= __get_user(temp.uptr, &chaninfo32->maxdata_list); + err |= __put_user(compat_ptr(temp.uptr), &chaninfo->maxdata_list); + err |= __get_user(temp.uptr, &chaninfo32->flaglist); + err |= __put_user(compat_ptr(temp.uptr), &chaninfo->flaglist); + err |= __get_user(temp.uptr, &chaninfo32->rangelist); + err |= __put_user(compat_ptr(temp.uptr), &chaninfo->rangelist); + if (err) { + return -EFAULT; + } + + return translated_ioctl(file, COMEDI_CHANINFO, (unsigned long)chaninfo); +} + +/* Handle 32-bit COMEDI_RANGEINFO ioctl. */ +static int compat_rangeinfo(struct file *file, unsigned long arg) +{ + comedi_rangeinfo __user *rangeinfo; + comedi32_rangeinfo __user *rangeinfo32; + int err; + union { + unsigned int uint; + compat_uptr_t uptr; + } temp; + + rangeinfo32 = compat_ptr(arg); + rangeinfo = compat_alloc_user_space(sizeof(*rangeinfo)); + + /* Copy rangeinfo structure. */ + if (!access_ok(VERIFY_READ, rangeinfo32, sizeof(*rangeinfo32)) + || !access_ok(VERIFY_WRITE, rangeinfo, + sizeof(*rangeinfo))) { + return -EFAULT; + } + err = 0; + err |= __get_user(temp.uint, &rangeinfo32->range_type); + err |= __put_user(temp.uint, &rangeinfo->range_type); + err |= __get_user(temp.uptr, &rangeinfo32->range_ptr); + err |= __put_user(compat_ptr(temp.uptr), &rangeinfo->range_ptr); + if (err) { + return -EFAULT; + } + + return translated_ioctl(file, COMEDI_RANGEINFO, + (unsigned long)rangeinfo); +} + +/* Copy 32-bit cmd structure to native cmd structure. */ +static int get_compat_cmd(comedi_cmd __user *cmd, + comedi32_cmd __user *cmd32) +{ + int err; + union { + unsigned int uint; + compat_uptr_t uptr; + } temp; + + /* Copy cmd structure. */ + if (!access_ok(VERIFY_READ, cmd32, sizeof(*cmd32)) + || !access_ok(VERIFY_WRITE, cmd, sizeof(*cmd))) { + return -EFAULT; + } + err = 0; + err |= __get_user(temp.uint, &cmd32->subdev); + err |= __put_user(temp.uint, &cmd->subdev); + err |= __get_user(temp.uint, &cmd32->flags); + err |= __put_user(temp.uint, &cmd->flags); + err |= __get_user(temp.uint, &cmd32->start_src); + err |= __put_user(temp.uint, &cmd->start_src); + err |= __get_user(temp.uint, &cmd32->start_arg); + err |= __put_user(temp.uint, &cmd->start_arg); + err |= __get_user(temp.uint, &cmd32->scan_begin_src); + err |= __put_user(temp.uint, &cmd->scan_begin_src); + err |= __get_user(temp.uint, &cmd32->scan_begin_arg); + err |= __put_user(temp.uint, &cmd->scan_begin_arg); + err |= __get_user(temp.uint, &cmd32->convert_src); + err |= __put_user(temp.uint, &cmd->convert_src); + err |= __get_user(temp.uint, &cmd32->convert_arg); + err |= __put_user(temp.uint, &cmd->convert_arg); + err |= __get_user(temp.uint, &cmd32->scan_end_src); + err |= __put_user(temp.uint, &cmd->scan_end_src); + err |= __get_user(temp.uint, &cmd32->scan_end_arg); + err |= __put_user(temp.uint, &cmd->scan_end_arg); + err |= __get_user(temp.uint, &cmd32->stop_src); + err |= __put_user(temp.uint, &cmd->stop_src); + err |= __get_user(temp.uint, &cmd32->stop_arg); + err |= __put_user(temp.uint, &cmd->stop_arg); + err |= __get_user(temp.uptr, &cmd32->chanlist); + err |= __put_user(compat_ptr(temp.uptr), &cmd->chanlist); + err |= __get_user(temp.uint, &cmd32->chanlist_len); + err |= __put_user(temp.uint, &cmd->chanlist_len); + err |= __get_user(temp.uptr, &cmd32->data); + err |= __put_user(compat_ptr(temp.uptr), &cmd->data); + err |= __get_user(temp.uint, &cmd32->data_len); + err |= __put_user(temp.uint, &cmd->data_len); + return err ? -EFAULT : 0; +} + +/* Copy native cmd structure to 32-bit cmd structure. */ +static int put_compat_cmd(comedi32_cmd __user *cmd32, comedi_cmd __user *cmd) +{ + /* N.B. Assume the pointer values in the 32-bit cmd structure are + * still valid from when they were copied originally. + * (Could use ptr_to_compat(), but it wasn't implemented until + * kernel version 2.6.11.) */ + int err; + unsigned int temp; + + /* Copy back most of cmd structure. */ + /* Assume the pointer values are already valid. */ + /* (Could use ptr_to_compat() to set them, but that wasn't implemented + * until kernel version 2.6.11.) */ + if (!access_ok(VERIFY_READ, cmd, sizeof(*cmd)) + || !access_ok(VERIFY_WRITE, cmd32, sizeof(*cmd32))) { + return -EFAULT; + } + err = 0; + err |= __get_user(temp, &cmd->subdev); + err |= __put_user(temp, &cmd32->subdev); + err |= __get_user(temp, &cmd->flags); + err |= __put_user(temp, &cmd32->flags); + err |= __get_user(temp, &cmd->start_src); + err |= __put_user(temp, &cmd32->start_src); + err |= __get_user(temp, &cmd->start_arg); + err |= __put_user(temp, &cmd32->start_arg); + err |= __get_user(temp, &cmd->scan_begin_src); + err |= __put_user(temp, &cmd32->scan_begin_src); + err |= __get_user(temp, &cmd->scan_begin_arg); + err |= __put_user(temp, &cmd32->scan_begin_arg); + err |= __get_user(temp, &cmd->convert_src); + err |= __put_user(temp, &cmd32->convert_src); + err |= __get_user(temp, &cmd->convert_arg); + err |= __put_user(temp, &cmd32->convert_arg); + err |= __get_user(temp, &cmd->scan_end_src); + err |= __put_user(temp, &cmd32->scan_end_src); + err |= __get_user(temp, &cmd->scan_end_arg); + err |= __put_user(temp, &cmd32->scan_end_arg); + err |= __get_user(temp, &cmd->stop_src); + err |= __put_user(temp, &cmd32->stop_src); + err |= __get_user(temp, &cmd->stop_arg); + err |= __put_user(temp, &cmd32->stop_arg); + /* Assume chanlist pointer is unchanged. */ + err |= __get_user(temp, &cmd->chanlist_len); + err |= __put_user(temp, &cmd32->chanlist_len); + /* Assume data pointer is unchanged. */ + err |= __get_user(temp, &cmd->data_len); + err |= __put_user(temp, &cmd32->data_len); + return err ? -EFAULT : 0; +} + +/* Handle 32-bit COMEDI_CMD ioctl. */ +static int compat_cmd(struct file *file, unsigned long arg) +{ + comedi_cmd __user *cmd; + comedi32_cmd __user *cmd32; + int rc; + + cmd32 = compat_ptr(arg); + cmd = compat_alloc_user_space(sizeof(*cmd)); + + rc = get_compat_cmd(cmd, cmd32); + if (rc) { + return rc; + } + + return translated_ioctl(file, COMEDI_CMD, (unsigned long)cmd); +} + +/* Handle 32-bit COMEDI_CMDTEST ioctl. */ +static int compat_cmdtest(struct file *file, unsigned long arg) +{ + comedi_cmd __user *cmd; + comedi32_cmd __user *cmd32; + int rc, err; + + cmd32 = compat_ptr(arg); + cmd = compat_alloc_user_space(sizeof(*cmd)); + + rc = get_compat_cmd(cmd, cmd32); + if (rc) { + return rc; + } + + rc = translated_ioctl(file, COMEDI_CMDTEST, (unsigned long)cmd); + if (rc < 0) { + return rc; + } + + err = put_compat_cmd(cmd32, cmd); + if (err) { + rc = err; + } + return rc; +} + +/* Copy 32-bit insn structure to native insn structure. */ +static int get_compat_insn(comedi_insn __user *insn, + comedi32_insn __user *insn32) +{ + int err; + union { + unsigned int uint; + compat_uptr_t uptr; + } temp; + + /* Copy insn structure. Ignore the unused members. */ + err = 0; + if (!access_ok(VERIFY_READ, insn32, sizeof(*insn32)) + || !access_ok(VERIFY_WRITE, insn, sizeof(*insn))) { + return -EFAULT; + } + err |= __get_user(temp.uint, &insn32->insn); + err |= __put_user(temp.uint, &insn->insn); + err |= __get_user(temp.uint, &insn32->n); + err |= __put_user(temp.uint, &insn->n); + err |= __get_user(temp.uptr, &insn32->data); + err |= __put_user(compat_ptr(temp.uptr), &insn->data); + err |= __get_user(temp.uint, &insn32->subdev); + err |= __put_user(temp.uint, &insn->subdev); + err |= __get_user(temp.uint, &insn32->chanspec); + err |= __put_user(temp.uint, &insn->chanspec); + return err ? -EFAULT : 0; +} + +/* Handle 32-bit COMEDI_INSNLIST ioctl. */ +static int compat_insnlist(struct file *file, unsigned long arg) +{ + struct combined_insnlist { + comedi_insnlist insnlist; + comedi_insn insn[1]; + } __user *s; + comedi32_insnlist __user *insnlist32; + comedi32_insn __user *insn32; + compat_uptr_t uptr; + unsigned int n_insns, n; + int err, rc; + + insnlist32 = compat_ptr(arg); + + /* Get 32-bit insnlist structure. */ + if (!access_ok(VERIFY_READ, insnlist32, sizeof(*insnlist32))) { + return -EFAULT; + } + err = 0; + err |= __get_user(n_insns, &insnlist32->n_insns); + err |= __get_user(uptr, &insnlist32->insns); + insn32 = compat_ptr(uptr); + if (err) { + return -EFAULT; + } + + /* Allocate user memory to copy insnlist and insns into. */ + s = compat_alloc_user_space(offsetof(struct combined_insnlist, + insn[n_insns])); + + /* Set native insnlist structure. */ + if (!access_ok(VERIFY_WRITE, &s->insnlist, sizeof(s->insnlist))) { + return -EFAULT; + } + err |= __put_user(n_insns, &s->insnlist.n_insns); + err |= __put_user(&s->insn[0], &s->insnlist.insns); + if (err) { + return -EFAULT; + } + + /* Copy insn structures. */ + for (n = 0; n < n_insns; n++) { + rc = get_compat_insn(&s->insn[n], &insn32[n]); + if (rc) { + return rc; + } + } + + return translated_ioctl(file, COMEDI_INSNLIST, + (unsigned long)&s->insnlist); +} + +/* Handle 32-bit COMEDI_INSN ioctl. */ +static int compat_insn(struct file *file, unsigned long arg) +{ + comedi_insn __user *insn; + comedi32_insn __user *insn32; + int rc; + + insn32 = compat_ptr(arg); + insn = compat_alloc_user_space(sizeof(*insn)); + + rc = get_compat_insn(insn, insn32); + if (rc) { + return rc; + } + + return translated_ioctl(file, COMEDI_INSN, (unsigned long)insn); +} + +long comedi_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int rc; + + switch (cmd) { + case COMEDI_DEVCONFIG: + case COMEDI_DEVINFO: + case COMEDI_SUBDINFO: + case COMEDI_BUFCONFIG: + case COMEDI_BUFINFO: + /* Just need to translate the pointer argument. */ + arg = (unsigned long)compat_ptr(arg); + rc = translated_ioctl(file, cmd, arg); + break; + case COMEDI_LOCK: + case COMEDI_UNLOCK: + case COMEDI_CANCEL: + case COMEDI_POLL: + /* No translation needed. */ + rc = translated_ioctl(file, cmd, arg); + break; + case COMEDI32_CHANINFO: + rc = compat_chaninfo(file, arg); + break; + case COMEDI32_RANGEINFO: + rc = compat_rangeinfo(file, arg); + break; + case COMEDI32_CMD: + rc = compat_cmd(file, arg); + break; + case COMEDI32_CMDTEST: + rc = compat_cmdtest(file, arg); + break; + case COMEDI32_INSNLIST: + rc = compat_insnlist(file, arg); + break; + case COMEDI32_INSN: + rc = compat_insn(file, arg); + break; + default: + rc = -ENOIOCTLCMD; + break; + } + return rc; +} + +#ifndef HAVE_COMPAT_IOCTL /* defined in 2.6.11 onwards */ + +/* + * Brain-dead ioctl compatibility for 2.6.10 and earlier. + * + * It's brain-dead because cmd numbers need to be unique system-wide! + * The comedi driver could end up attempting to execute ioctls for non-Comedi + * devices because it registered the system-wide cmd code first. Similarly, + * another driver could end up attempting to execute ioctls for a Comedi + * device because it registered the cmd code first. Chaos ensues. + */ + +static int mapped_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg, + struct file *file) +{ + /* Make sure we are dealing with a Comedi device. */ + if (imajor(file->f_dentry->d_inode) != COMEDI_MAJOR) { + return -ENOTTY; + } + return (int)comedi_compat_ioctl(file, cmd, arg); +} + +struct ioctl32_map { + unsigned int cmd; + int (*handler)(unsigned int, unsigned int, unsigned long, + struct file *); + int registered; +}; + +static struct ioctl32_map comedi_ioctl32_map[] = { + { COMEDI_DEVCONFIG, mapped_ioctl, 0 }, + { COMEDI_DEVINFO, mapped_ioctl, 0 }, + { COMEDI_SUBDINFO, mapped_ioctl, 0 }, + { COMEDI_BUFCONFIG, mapped_ioctl, 0 }, + { COMEDI_BUFINFO, mapped_ioctl, 0 }, + { COMEDI_LOCK, mapped_ioctl, 0 }, + { COMEDI_UNLOCK, mapped_ioctl, 0 }, + { COMEDI_CANCEL, mapped_ioctl, 0 }, + { COMEDI_POLL, mapped_ioctl, 0 }, + { COMEDI32_CHANINFO, mapped_ioctl, 0 }, + { COMEDI32_RANGEINFO, mapped_ioctl, 0 }, + { COMEDI32_CMD, mapped_ioctl, 0 }, + { COMEDI32_CMDTEST, mapped_ioctl, 0 }, + { COMEDI32_INSNLIST, mapped_ioctl, 0 }, + { COMEDI32_INSN, mapped_ioctl, 0 }, +}; + +#define NUM_IOCTL32_MAPS ARRAY_SIZE(comedi_ioctl32_map) + +/* Register system-wide 32-bit ioctl handlers. */ +void comedi_register_ioctl32(void) +{ + int n, rc; + + for (n = 0; n < NUM_IOCTL32_MAPS; n++) { + rc = register_ioctl32_conversion(comedi_ioctl32_map[n].cmd, + comedi_ioctl32_map[n].handler); + if (rc) { + printk(KERN_WARNING + "comedi: failed to register 32-bit " + "compatible ioctl handler for 0x%X - " + "expect bad things to happen!\n", + comedi_ioctl32_map[n].cmd); + } + comedi_ioctl32_map[n].registered = !rc; + } +} + +/* Unregister system-wide 32-bit ioctl translations. */ +void comedi_unregister_ioctl32(void) +{ + int n, rc; + + for (n = 0; n < NUM_IOCTL32_MAPS; n++) { + if (comedi_ioctl32_map[n].registered) { + rc = unregister_ioctl32_conversion( + comedi_ioctl32_map[n].cmd, + comedi_ioctl32_map[n].handler); + if (rc) { + printk(KERN_ERR + "comedi: failed to unregister 32-bit " + "compatible ioctl handler for 0x%X - " + "expect kernel Oops!\n", + comedi_ioctl32_map[n].cmd); + } else { + comedi_ioctl32_map[n].registered = 0; + } + } + } +} + +#endif /* HAVE_COMPAT_IOCTL */ + +#endif /* CONFIG_COMPAT */ diff --git a/comedi/comedi_compat32.h b/comedi/comedi_compat32.h new file mode 100644 index 00000000..198aea54 --- /dev/null +++ b/comedi/comedi_compat32.h @@ -0,0 +1,58 @@ +/* + comedi/comedi_compat32.h + 32-bit ioctl compatibility for 64-bit comedi kernel module. + + Author: Ian Abbott, MEV Ltd. + Copyright (C) 2007 MEV Ltd. + + COMEDI - Linux Control and Measurement Device Interface + Copyright (C) 1997-2007 David A. Schleef + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef _COMEDI_COMPAT32_H +#define _COMEDI_COMPAT32_H + +#include +#include /* For HAVE_COMPAT_IOCTL and HAVE_UNLOCKED_IOCTL */ + +#ifdef CONFIG_COMPAT + +#ifdef HAVE_COMPAT_IOCTL + +extern long comedi_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg); +#define comedi_register_ioctl32() do{}while(0) +#define comedi_unregister_ioctl32() do{}while(0) + +#else /* HAVE_COMPAT_IOCTL */ + +#define comedi_compat_ioctl 0 /* NULL */ +extern void comedi_register_ioctl32(void); +extern void comedi_unregister_ioctl32(void); + +#endif /* HAVE_COMPAT_IOCTL */ + +#else /* CONFIG_COMPAT */ + +#define comedi_compat_ioctl 0 /* NULL */ +#define comedi_register_ioctl32() do{}while(0) +#define comedi_unregister_ioctl32() do{}while(0) + +#endif /* CONFIG_COMPAT */ + +#endif /* _COMEDI_COMPAT32_H */ diff --git a/comedi/comedi_fops.c b/comedi/comedi_fops.c index f39deb66..ecea4b4a 100644 --- a/comedi/comedi_fops.c +++ b/comedi/comedi_fops.c @@ -25,6 +25,7 @@ #define __NO_VERSION__ #include "comedi_fops.h" +#include "comedi_compat32.h" #include #include @@ -1722,6 +1723,9 @@ static int comedi_fasync(int fd, struct file *file, int on) const struct file_operations comedi_fops = { owner:THIS_MODULE, ioctl:comedi_ioctl, +#ifdef HAVE_COMPAT_IOCTL + compat_ioctl:comedi_compat_ioctl, +#endif open:comedi_open, release:comedi_close, read:comedi_read, @@ -1787,6 +1791,8 @@ static int __init comedi_init(void) comedi_rt_init(); + comedi_register_ioctl32(); + return 0; } @@ -1819,6 +1825,8 @@ static void __exit comedi_cleanup(void) kfree(comedi_devices); comedi_rt_cleanup(); + + comedi_unregister_ioctl32(); } module_init(comedi_init);