| /* |
| comedi/comedi_compat32.c |
| 32-bit ioctl compatibility for 64-bit comedi kernel module. |
| |
| Author: Ian Abbott, MEV Ltd. <abbotti@mev.co.uk> |
| Copyright (C) 2007 MEV Ltd. <http://www.mev.co.uk/> |
| |
| COMEDI - Linux Control and Measurement Device Interface |
| Copyright (C) 1997-2007 David A. Schleef <ds@schleef.org> |
| |
| 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 "comedi.h" |
| #include <linux/smp_lock.h> |
| #include <asm/uaccess.h> |
| |
| #include "comedi_compat32.h" |
| |
| #ifdef CONFIG_COMPAT |
| |
| #ifndef HAVE_COMPAT_IOCTL |
| #include <linux/ioctl32.h> /* for (un)register_ioctl32_conversion */ |
| #endif |
| |
| #define COMEDI32_CHANINFO _IOR(CIO, 3, comedi32_chaninfo) |
| #define COMEDI32_RANGEINFO _IOR(CIO, 8, (struct comedi32_rangeinfo_struct)) |
| /* N.B. COMEDI32_CMD and COMEDI_CMD ought to use _IOWR, not _IOR. |
| * It's too late to change it now, but it only affects the command number. */ |
| #define COMEDI32_CMD _IOR(CIO, 9, (struct comedi32_cmd_struct)) |
| /* 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, (struct comedi32_cmd_struct)) |
| #define COMEDI32_INSNLIST _IOR(CIO, 11, (struct comedi32_insnlist_struct)) |
| #define COMEDI32_INSN _IOR(CIO, 12, (struct comedi32_insn_struct)) |
| |
| struct comedi32_chaninfo_struct { |
| unsigned int subdev; |
| compat_uptr_t maxdata_list; /* 32-bit 'unsigned int *' */ |
| compat_uptr_t flaglist; /* 32-bit 'unsigned int *' */ |
| compat_uptr_t rangelist; /* 32-bit 'unsigned int *' */ |
| unsigned int unused[4]; |
| }; |
| |
| struct comedi32_rangeinfo_struct { |
| unsigned int range_type; |
| compat_uptr_t range_ptr; /* 32-bit 'void *' */ |
| }; |
| |
| 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 'short *' */ |
| unsigned int data_len; |
| }; |
| |
| struct comedi32_insn_struct { |
| unsigned int insn; |
| unsigned int n; |
| compat_uptr_t data; /* 32-bit 'unsigned int *' */ |
| unsigned int subdev; |
| unsigned int chanspec; |
| unsigned int unused[3]; |
| }; |
| |
| struct comedi32_insnlist_struct { |
| unsigned int n_insns; |
| compat_uptr_t insns; /* 32-bit 'struct comedi_insn *' */ |
| }; |
| |
| /* 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) |
| { |
| struct comedi_chaninfo_struct __user *chaninfo; |
| struct comedi32_chaninfo_struct __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) |
| { |
| struct comedi_rangeinfo __user *rangeinfo; |
| struct comedi32_rangeinfo_struct __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(struct comedi_cmd __user *cmd, |
| struct comedi32_cmd_struct __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(struct comedi32_cmd_struct __user *cmd32, struct comedi_cmd __user *cmd) |
| { |
| 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) |
| { |
| struct comedi_cmd __user *cmd; |
| struct comedi32_cmd_struct __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) |
| { |
| struct comedi_cmd __user *cmd; |
| struct comedi32_cmd_struct __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(struct comedi_insn __user *insn, |
| struct comedi32_insn_struct __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 { |
| struct comedi_insnlist insnlist; |
| struct comedi_insn insn[1]; |
| } __user *s; |
| struct comedi32_insnlist_struct __user *insnlist32; |
| struct comedi32_insn_struct __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) |
| { |
| struct comedi_insn __user *insn; |
| struct comedi32_insn_struct __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); |
| } |
| |
| /* Process untranslated ioctl. */ |
| /* Returns -ENOIOCTLCMD for unrecognised ioctl codes. */ |
| static inline int raw_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; |
| } |
| |
| #ifdef HAVE_COMPAT_IOCTL /* defined in <linux/fs.h> 2.6.11 onwards */ |
| |
| /* compat_ioctl file operation. */ |
| /* Returns -ENOIOCTLCMD for unrecognised ioctl codes. */ |
| long comedi_compat_ioctl(struct file *file, unsigned int cmd, |
| unsigned long arg) |
| { |
| return raw_ioctl(file, cmd, arg); |
| } |
| |
| #else /* HAVE_COMPAT_IOCTL */ |
| |
| /* |
| * 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. |
| */ |
| |
| /* Handler for all 32-bit ioctl codes registered by this driver. */ |
| static int mapped_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg, |
| struct file *file) |
| { |
| int rc; |
| |
| /* Make sure we are dealing with a Comedi device. */ |
| if (imajor(file->f_dentry->d_inode) != COMEDI_MAJOR) |
| return -ENOTTY; |
| |
| rc = raw_ioctl(file, cmd, arg); |
| /* Do not return -ENOIOCTLCMD. */ |
| if (rc == -ENOIOCTLCMD) |
| rc = -ENOTTY; |
| |
| return rc; |
| } |
| |
| 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 */ |