comedi_fops.c revision ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3f
1ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 2ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi/comedi_fops.c 3ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi kernel module 4ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 5ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI - Linux Control and Measurement Device Interface 6ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org> 7ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 8ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef This program is free software; you can redistribute it and/or modify 9ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef it under the terms of the GNU General Public License as published by 10ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef the Free Software Foundation; either version 2 of the License, or 11ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef (at your option) any later version. 12ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 13ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef This program is distributed in the hope that it will be useful, 14ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef but WITHOUT ANY WARRANTY; without even the implied warranty of 15ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef GNU General Public License for more details. 17ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 18ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef You should have received a copy of the GNU General Public License 19ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef along with this program; if not, write to the Free Software 20ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 22ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 23ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 24ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#undef DEBUG 25ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 26ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#define __NO_VERSION__ 27ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include "comedi_fops.h" 28ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include "comedi_compat32.h" 29ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 30ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/module.h> 31ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/errno.h> 32ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/kernel.h> 33ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/sched.h> 34ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/fcntl.h> 35ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/delay.h> 36ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/ioport.h> 37ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/mm.h> 38ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/slab.h> 39ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/kmod.h> 40ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/poll.h> 41ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/init.h> 42ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/device.h> 43ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/vmalloc.h> 44ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/fs.h> 45ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include "comedidev.h" 46ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#include <linux/cdev.h> 47ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 48476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#include <linux/io.h> 49476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#include <linux/uaccess.h> 50ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 51476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman/* #include "kvmem.h" */ 52ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 53ed9eccbe8970f6eedc1b978c157caf1251a896d4David SchleefMODULE_AUTHOR("http://www.comedi.org"); 54ed9eccbe8970f6eedc1b978c157caf1251a896d4David SchleefMODULE_DESCRIPTION("Comedi core module"); 55ed9eccbe8970f6eedc1b978c157caf1251a896d4David SchleefMODULE_LICENSE("GPL"); 56ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 57ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef CONFIG_COMEDI_DEBUG 58ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefint comedi_debug; 59ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefmodule_param(comedi_debug, int, 0644); 60ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif 61ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 626a9d7a21d710e544df20266b83b7829d9f7a1020Ian Abbottint comedi_autoconfig = 1; 636a9d7a21d710e544df20266b83b7829d9f7a1020Ian Abbottmodule_param(comedi_autoconfig, bool, 0444); 646a9d7a21d710e544df20266b83b7829d9f7a1020Ian Abbott 651dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porrint comedi_num_legacy_minors = 0; 661dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porrmodule_param(comedi_num_legacy_minors, int, 0444); 671dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porr 68ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic DEFINE_SPINLOCK(comedi_file_info_table_lock); 69476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic struct comedi_device_file_info 70476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman *comedi_file_info_table[COMEDI_NUM_MINORS]; 71476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman 7271b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_devconfig_ioctl(struct comedi_device *dev, comedi_devconfig *arg); 7371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_bufconfig_ioctl(struct comedi_device *dev, void *arg); 7471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_devinfo_ioctl(struct comedi_device *dev, comedi_devinfo *arg, 75476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct file *file); 7671b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_subdinfo_ioctl(struct comedi_device *dev, comedi_subdinfo *arg, 77476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman void *file); 7871b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_chaninfo_ioctl(struct comedi_device *dev, comedi_chaninfo *arg); 7971b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_bufinfo_ioctl(struct comedi_device *dev, void *arg); 8071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_cmd_ioctl(struct comedi_device *dev, void *arg, void *file); 8171b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_lock_ioctl(struct comedi_device *dev, unsigned int arg, void *file); 8271b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg, void *file); 8371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg, void *file); 8471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_cmdtest_ioctl(struct comedi_device *dev, void *arg, void *file); 8571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_insnlist_ioctl(struct comedi_device *dev, void *arg, void *file); 8671b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_insn_ioctl(struct comedi_device *dev, void *arg, void *file); 8771b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_poll_ioctl(struct comedi_device *dev, unsigned int subd, void *file); 8871b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton 8934c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonextern void do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s); 9034c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s); 91ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 92ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_fasync(int fd, struct file *file, int on); 93ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 9471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int is_device_busy(struct comedi_device *dev); 95ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 96ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef HAVE_UNLOCKED_IOCTL 97ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, 98476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman unsigned long arg) 99ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#else 100ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_ioctl(struct inode *inode, struct file *file, 101476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman unsigned int cmd, unsigned long arg) 102ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif 103ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 104ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef const unsigned minor = iminor(file->f_dentry->d_inode); 105476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct comedi_device_file_info *dev_file_info = 106476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_device_file_info(minor); 10771b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev; 108ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int rc; 109ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 11053b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess if (dev_file_info == NULL || dev_file_info->device == NULL) 11153b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess return -ENODEV; 11253b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess dev = dev_file_info->device; 11353b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess 114ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_lock(&dev->mutex); 115ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 116ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* Device config is special, because it must work on 117ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * an unconfigured device. */ 118ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (cmd == COMEDI_DEVCONFIG) { 119ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_devconfig_ioctl(dev, (void *)arg); 120ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 121ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 122ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 123ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!dev->attached) { 124ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("no driver configured on /dev/comedi%i\n", dev->minor); 125ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = -ENODEV; 126ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 127ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 128ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 129ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef switch (cmd) { 130ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_BUFCONFIG: 131ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_bufconfig_ioctl(dev, (void *)arg); 132ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 133ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_DEVINFO: 134ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_devinfo_ioctl(dev, (void *)arg, file); 135ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 136ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_SUBDINFO: 137ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_subdinfo_ioctl(dev, (void *)arg, file); 138ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 139ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_CHANINFO: 140ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_chaninfo_ioctl(dev, (void *)arg); 141ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 142ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_RANGEINFO: 143ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_rangeinfo_ioctl(dev, (void *)arg); 144ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 145ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_BUFINFO: 146ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_bufinfo_ioctl(dev, (void *)arg); 147ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 148ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_LOCK: 149ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_lock_ioctl(dev, arg, file); 150ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 151ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_UNLOCK: 152ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_unlock_ioctl(dev, arg, file); 153ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 154ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_CANCEL: 155ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_cancel_ioctl(dev, arg, file); 156ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 157ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_CMD: 158ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_cmd_ioctl(dev, (void *)arg, file); 159ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 160ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_CMDTEST: 161ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_cmdtest_ioctl(dev, (void *)arg, file); 162ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 163ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_INSNLIST: 164ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_insnlist_ioctl(dev, (void *)arg, file); 165ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 166ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_INSN: 167ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_insn_ioctl(dev, (void *)arg, file); 168ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 169ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_POLL: 170ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_poll_ioctl(dev, arg, file); 171ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 172ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef default: 173ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = -ENOTTY; 174ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 175ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 176ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 177476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmandone: 178ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return rc; 180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 181ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 182ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 183ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_DEVCONFIG 184ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef device config ioctl 185ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 186ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 187ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef pointer to devconfig structure 188ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 189ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 190ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef devconfig structure at arg 191ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 192ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 193ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef none 194ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 19571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_devconfig_ioctl(struct comedi_device *dev, comedi_devconfig *arg) 196ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 197ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_devconfig it; 198ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int ret; 199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned char *aux_data = NULL; 200ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int aux_len; 201ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!capable(CAP_SYS_ADMIN)) 203ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EPERM; 204ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 205ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (arg == NULL) { 206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (is_device_busy(dev)) 207ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EBUSY; 208476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (dev->attached) { 209ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef struct module *driver_module = dev->driver->module; 210ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_device_detach(dev); 211ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef module_put(driver_module); 212ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 214ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 215ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 216ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_from_user(&it, arg, sizeof(comedi_devconfig))) 217ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 218ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 219ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef it.board_name[COMEDI_NAMELEN - 1] = 0; 220ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 221ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (comedi_aux_data(it.options, 0) && 222476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) { 223ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int bit_shift; 224ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef aux_len = it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]; 225ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (aux_len < 0) 226ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 227ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 228ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef aux_data = vmalloc(aux_len); 229ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!aux_data) 230ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENOMEM; 231ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 232ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_from_user(aux_data, 233476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_aux_data(it.options, 0), aux_len)) { 234ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef vfree(aux_data); 235ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 236ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 237ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef it.options[COMEDI_DEVCONF_AUX_DATA_LO] = 238476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman (unsigned long)aux_data; 239ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (sizeof(void *) > sizeof(int)) { 240ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bit_shift = sizeof(int) * 8; 241ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef it.options[COMEDI_DEVCONF_AUX_DATA_HI] = 242476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman ((unsigned long)aux_data) >> bit_shift; 243ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } else 244ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef it.options[COMEDI_DEVCONF_AUX_DATA_HI] = 0; 245ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 246ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 247ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = comedi_device_attach(dev, &it); 248476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (ret == 0) { 249476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (!try_module_get(dev->driver->module)) { 250ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_device_detach(dev); 251ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENOSYS; 252ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 253ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 254ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 255ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (aux_data) 256ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef vfree(aux_data); 257ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 258ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 259ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 260ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 261ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 262ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_BUFCONFIG 263ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef buffer configuration ioctl 264ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 265ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 266ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef pointer to bufconfig structure 267ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 268ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 269ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bufconfig at arg 270ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 271ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 272ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef modified bufconfig at arg 273ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 274ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 27571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_bufconfig_ioctl(struct comedi_device *dev, void *arg) 276ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 277ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_bufconfig bc; 278d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton struct comedi_async *async; 27934c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 280ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int ret = 0; 281ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 282ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_from_user(&bc, arg, sizeof(comedi_bufconfig))) 283ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 284ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 285ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (bc.subdevice >= dev->n_subdevices || bc.subdevice < 0) 286ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 287ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 288ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + bc.subdevice; 289ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async = s->async; 290ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 291ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!async) { 292ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("subdevice does not have async capability\n"); 293ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bc.size = 0; 294ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bc.maximum_size = 0; 295ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto copyback; 296ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 297ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 298ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (bc.maximum_size) { 299ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!capable(CAP_SYS_ADMIN)) 300ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EPERM; 301ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 302ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->max_bufsize = bc.maximum_size; 303ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 304ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 305ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (bc.size) { 306ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (bc.size > async->max_bufsize) 307ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EPERM; 308ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 309ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy) { 310ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("subdevice is busy, cannot resize buffer\n"); 311ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EBUSY; 312ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 313ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (async->mmap_count) { 314ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("subdevice is mmapped, cannot resize buffer\n"); 315ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EBUSY; 316ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 317ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 318ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!async->prealloc_buf) 319ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 320ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 321ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* make sure buffer is an integral number of pages 322ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * (we round up) */ 323ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bc.size = (bc.size + PAGE_SIZE - 1) & PAGE_MASK; 324ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 325ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = comedi_buf_alloc(dev, s, bc.size); 326ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (ret < 0) 327ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 328ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 329ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->buf_change) { 330ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->buf_change(dev, s, bc.size); 331ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (ret < 0) 332ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 333ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 334ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 335ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("comedi%i subd %d buffer resized to %i bytes\n", 336ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef dev->minor, bc.subdevice, async->prealloc_bufsz); 337ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 338ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 339ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bc.size = async->prealloc_bufsz; 340ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bc.maximum_size = async->max_bufsize; 341ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 342476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancopyback: 343ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_to_user(arg, &bc, sizeof(comedi_bufconfig))) 344ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 345ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 346ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 347ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 348ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 349ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 350ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_DEVINFO 351ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef device info ioctl 352ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 353ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 354ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef pointer to devinfo structure 355ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 356ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 357ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef none 358ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 359ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 360ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef devinfo structure 361ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 362ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 36371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_devinfo_ioctl(struct comedi_device *dev, comedi_devinfo *arg, 364476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct file *file) 365ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 366ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_devinfo devinfo; 367ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef const unsigned minor = iminor(file->f_dentry->d_inode); 368476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct comedi_device_file_info *dev_file_info = 369476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_device_file_info(minor); 37034c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *read_subdev = 371476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_read_subdevice(dev_file_info); 37234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *write_subdev = 373476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_write_subdevice(dev_file_info); 374ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 375ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef memset(&devinfo, 0, sizeof(devinfo)); 376ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 377ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* fill devinfo structure */ 378ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef devinfo.version_code = COMEDI_VERSION_CODE; 379ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef devinfo.n_subdevs = dev->n_subdevices; 380ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef memcpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN); 381ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef memcpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN); 382ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 383476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (read_subdev) 384ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef devinfo.read_subdevice = read_subdev - dev->subdevices; 385476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman else 386ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef devinfo.read_subdevice = -1; 387476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman 388476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (write_subdev) 389ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef devinfo.write_subdevice = write_subdev - dev->subdevices; 390476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman else 391ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef devinfo.write_subdevice = -1; 392ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 393ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_to_user(arg, &devinfo, sizeof(comedi_devinfo))) 394ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 395ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 396ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 397ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 398ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 399ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 400ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_SUBDINFO 401ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef subdevice info ioctl 402ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 403ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 404ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef pointer to array of subdevice info structures 405ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 406ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 407ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef none 408ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 409ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 410ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef array of subdevice info structures at arg 411ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 412ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 41371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_subdinfo_ioctl(struct comedi_device *dev, comedi_subdinfo *arg, 414476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman void *file) 415ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 416ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int ret, i; 417ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_subdinfo *tmp, *us; 41834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 419ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 420ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef tmp = kcalloc(dev->n_subdevices, sizeof(comedi_subdinfo), GFP_KERNEL); 421ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!tmp) 422ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENOMEM; 423ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 424ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* fill subdinfo structs */ 425ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef for (i = 0; i < dev->n_subdevices; i++) { 426ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + i; 427ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us = tmp + i; 428ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 429ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->type = s->type; 430ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->n_chan = s->n_chan; 431ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags = s->subdev_flags; 432ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (comedi_get_subdevice_runflags(s) & SRF_RUNNING) 433ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags |= SDF_RUNNING; 434ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#define TIMER_nanosec 5 /* backwards compatibility */ 435ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->timer_type = TIMER_nanosec; 436ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->len_chanlist = s->len_chanlist; 437ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->maxdata = s->maxdata; 438ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->range_table) { 439ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->range_type = 440476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman (i << 24) | (0 << 16) | (s->range_table->length); 441ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } else { 442ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->range_type = 0; /* XXX */ 443ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 444ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->flags = s->flags; 445ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 446ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy) 447ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags |= SDF_BUSY; 448ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy == file) 449ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags |= SDF_BUSY_OWNER; 450ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->lock) 451ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags |= SDF_LOCKED; 452ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->lock == file) 453ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags |= SDF_LOCK_OWNER; 454ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->maxdata && s->maxdata_list) 455ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags |= SDF_MAXDATA; 456ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->flaglist) 457ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags |= SDF_FLAGS; 458ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->range_table_list) 459ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags |= SDF_RANGETYPE; 460ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->do_cmd) 461ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags |= SDF_CMD; 462ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 463ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->insn_bits != &insn_inval) 464ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->insn_bits_support = COMEDI_SUPPORTED; 465ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef else 466ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->insn_bits_support = COMEDI_UNSUPPORTED; 467ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 468ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->settling_time_0 = s->settling_time_0; 469ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 470ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 471ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = copy_to_user(arg, tmp, 472476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman dev->n_subdevices * sizeof(comedi_subdinfo)); 473ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 474ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kfree(tmp); 475ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 476ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret ? -EFAULT : 0; 477ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 478ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 479ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 480ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_CHANINFO 481ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef subdevice info ioctl 482ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 483ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 484ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef pointer to chaninfo structure 485ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 486ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 487ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef chaninfo structure at arg 488ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 489ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 490ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arrays at elements of chaninfo structure 491ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 492ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 49371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_chaninfo_ioctl(struct comedi_device *dev, comedi_chaninfo *arg) 494ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 49534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 496ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_chaninfo it; 497ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 498ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_from_user(&it, arg, sizeof(comedi_chaninfo))) 499ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 500ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 501ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (it.subdev >= dev->n_subdevices) 502ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 503ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + it.subdev; 504ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 505ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (it.maxdata_list) { 506ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->maxdata || !s->maxdata_list) 507ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 508ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_to_user(it.maxdata_list, s->maxdata_list, 509790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton s->n_chan * sizeof(unsigned int))) 510ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 511ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 512ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 513ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (it.flaglist) { 514ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->flaglist) 515ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 516ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_to_user(it.flaglist, s->flaglist, 517476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman s->n_chan * sizeof(unsigned int))) 518ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 519ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 520ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 521ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (it.rangelist) { 522ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int i; 523ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 524ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->range_table_list) 525ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 526ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef for (i = 0; i < s->n_chan; i++) { 527ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int x; 528ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 529ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef x = (dev->minor << 28) | (it.subdev << 24) | (i << 16) | 530476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman (s->range_table_list[i]->length); 531ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef put_user(x, it.rangelist + i); 532ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 533476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#if 0 534476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (copy_to_user(it.rangelist, s->range_type_list, 535476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman s->n_chan*sizeof(unsigned int))) 536476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman return -EFAULT; 537476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#endif 538ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 539ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 540ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 541ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 542ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 543ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* 544ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_BUFINFO 545ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef buffer information ioctl 546ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 547ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 548ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef pointer to bufinfo structure 549ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 550ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 551ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bufinfo at arg 552ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 553ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 554ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef modified bufinfo at arg 555ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 556ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */ 55771b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_bufinfo_ioctl(struct comedi_device *dev, void *arg) 558ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 559ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_bufinfo bi; 56034c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 561d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton struct comedi_async *async; 562ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 563ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_from_user(&bi, arg, sizeof(comedi_bufinfo))) 564ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 565ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 566ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (bi.subdevice >= dev->n_subdevices || bi.subdevice < 0) 567ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 568ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 569ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + bi.subdevice; 570ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async = s->async; 571ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 572ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!async) { 573ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("subdevice does not have async capability\n"); 574ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.buf_write_ptr = 0; 575ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.buf_read_ptr = 0; 576ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.buf_write_count = 0; 577ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.buf_read_count = 0; 578ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto copyback; 579ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 580ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 581ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)) { 582ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read); 583ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_buf_read_free(async, bi.bytes_read); 584ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 585ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | 586476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman SRF_RUNNING)) 587476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman && async->buf_write_count == async->buf_read_count) { 588ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef do_become_nonbusy(dev, s); 589ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 590ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 591ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 592ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (bi.bytes_written && (s->subdev_flags & SDF_CMD_WRITE)) { 593ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.bytes_written = 594476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_buf_write_alloc(async, bi.bytes_written); 595ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_buf_write_free(async, bi.bytes_written); 596ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 597ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 598ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.buf_write_count = async->buf_write_count; 599ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.buf_write_ptr = async->buf_write_ptr; 600ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.buf_read_count = async->buf_read_count; 601ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.buf_read_ptr = async->buf_read_ptr; 602ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 603476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancopyback: 604ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_to_user(arg, &bi, sizeof(comedi_bufinfo))) 605ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 606ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 607ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 608ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 609ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 61071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int parse_insn(struct comedi_device *dev, comedi_insn *insn, unsigned int *data, 611476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman void *file); 612ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 613ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * COMEDI_INSNLIST 614ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * synchronous instructions 615ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 616ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * arg: 617ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * pointer to sync cmd structure 618ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 619ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * reads: 620ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * sync cmd struct at arg 621ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * instruction list 622ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * data (for writes) 623ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 624ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * writes: 625ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * data (for reads) 626ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */ 627ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* arbitrary limits */ 628ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#define MAX_SAMPLES 256 62971b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_insnlist_ioctl(struct comedi_device *dev, void *arg, void *file) 630ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 631ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_insnlist insnlist; 632ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_insn *insns = NULL; 633790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton unsigned int *data = NULL; 634ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int i = 0; 635ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int ret = 0; 636ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 637ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_from_user(&insnlist, arg, sizeof(comedi_insnlist))) 638ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 639ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 640790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL); 641ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!data) { 642ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("kmalloc failed\n"); 643ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -ENOMEM; 644ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 645ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 646ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 647ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef insns = kmalloc(sizeof(comedi_insn) * insnlist.n_insns, GFP_KERNEL); 648ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!insns) { 649ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("kmalloc failed\n"); 650ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -ENOMEM; 651ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 652ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 653ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 654ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_from_user(insns, insnlist.insns, 655476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman sizeof(comedi_insn) * insnlist.n_insns)) { 656ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("copy_from_user failed\n"); 657ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 658ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 659ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 660ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 661ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef for (i = 0; i < insnlist.n_insns; i++) { 662ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insns[i].n > MAX_SAMPLES) { 663ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("number of samples too large\n"); 664ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 665ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 666ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 667ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insns[i].insn & INSN_MASK_WRITE) { 668ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_from_user(data, insns[i].data, 669790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton insns[i].n * sizeof(unsigned int))) { 670ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("copy_from_user failed\n"); 671ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 672ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 673ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 674ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 675ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = parse_insn(dev, insns + i, data, file); 676ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (ret < 0) 677ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 678ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insns[i].insn & INSN_MASK_READ) { 679ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_to_user(insns[i].data, data, 680790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton insns[i].n * sizeof(unsigned int))) { 681ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("copy_to_user failed\n"); 682ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 683ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 684ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 685ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 686ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (need_resched()) 687ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef schedule(); 688ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 689ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 690476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanerror: 691476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman kfree(insns); 692476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman kfree(data); 693ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 694ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (ret < 0) 695ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 696ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return i; 697ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 698ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 699790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pembertonstatic int check_insn_config_length(comedi_insn *insn, unsigned int *data) 700ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 701476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (insn->n < 1) 702476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman return -EINVAL; 703ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 704ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef switch (data[0]) { 705ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_DIO_OUTPUT: 706ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_DIO_INPUT: 707ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_DISARM: 708ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_RESET: 709ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->n == 1) 710ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 711ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 712ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_ARM: 713ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_DIO_QUERY: 714ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_BLOCK_SIZE: 715ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_FILTER: 716ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_SERIAL_CLOCK: 717ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_BIDIRECTIONAL_DATA: 718ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_ALT_SOURCE: 719ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_SET_COUNTER_MODE: 720ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_8254_READ_STATUS: 721ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_SET_ROUTING: 722ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_GET_ROUTING: 723ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_GET_PWM_STATUS: 724ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_PWM_SET_PERIOD: 725ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_PWM_GET_PERIOD: 726ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->n == 2) 727ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 728ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 729ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_SET_GATE_SRC: 730ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_GET_GATE_SRC: 731ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_SET_CLOCK_SRC: 732ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_GET_CLOCK_SRC: 733ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_SET_OTHER_SRC: 734ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_GET_COUNTER_STATUS: 735ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_PWM_SET_H_BRIDGE: 736ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_PWM_GET_H_BRIDGE: 737ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE: 738ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->n == 3) 739ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 740ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 741ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_PWM_OUTPUT: 742ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_ANALOG_TRIG: 743ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->n == 5) 744ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 745ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 746476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman /* by default we allow the insn since we don't have checks for 747476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman * all possible cases yet */ 748ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef default: 749476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman rt_printk("comedi: no check for data length of config insn id " 750476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman "%i is implemented.\n" 751476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman " Add a check to %s in %s.\n" 752476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman " Assuming n=%i is correct.\n", data[0], __func__, 753476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman __FILE__, insn->n); 754ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 755ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 756ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 757ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 758ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 759ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 76071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int parse_insn(struct comedi_device *dev, comedi_insn *insn, unsigned int *data, 761476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman void *file) 762ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 76334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 764ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int ret = 0; 765ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int i; 766ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 767ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->insn & INSN_MASK_SPECIAL) { 768ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* a non-subdevice instruction */ 769ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 770ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef switch (insn->insn) { 771ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_GTOD: 772ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef { 773ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef struct timeval tv; 774ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 775ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->n != 2) { 776ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 777ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 778ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 779ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 780ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef do_gettimeofday(&tv); 781ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef data[0] = tv.tv_sec; 782ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef data[1] = tv.tv_usec; 783ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = 2; 784ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 785ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 786ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 787ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_WAIT: 788ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->n != 1 || data[0] >= 100000) { 789ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 790ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 791ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 792ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef udelay(data[0] / 1000); 793ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = 1; 794ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 795ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_INTTRIG: 796ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->n != 1) { 797ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 798ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 799ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 800ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->subdev >= dev->n_subdevices) { 801ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("%d not usable subdevice\n", 802ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef insn->subdev); 803ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 804ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 805ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 806ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + insn->subdev; 807ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->async) { 808ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("no async\n"); 809ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 810ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 811ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 812ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->async->inttrig) { 813ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("no inttrig\n"); 814ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EAGAIN; 815ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 816ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 817ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->async->inttrig(dev, s, insn->data[0]); 818ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (ret >= 0) 819ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = 1; 820ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 821ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef default: 822ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("invalid insn\n"); 823ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 824ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 825ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 826ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } else { 827ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* a subdevice instruction */ 828790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton unsigned int maxdata; 829ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 830ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->subdev >= dev->n_subdevices) { 831ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("subdevice %d out of range\n", insn->subdev); 832ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 833ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto out; 834ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 835ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + insn->subdev; 836ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 837ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->type == COMEDI_SUBD_UNUSED) { 838ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("%d not usable subdevice\n", insn->subdev); 839ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EIO; 840ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto out; 841ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 842ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 843ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* are we locked? (ioctl lock) */ 844ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->lock && s->lock != file) { 845ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("device locked\n"); 846ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EACCES; 847ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto out; 848ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 849ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 850476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman ret = check_chanlist(s, 1, &insn->chanspec); 851476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (ret < 0) { 852ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 853ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("bad chanspec\n"); 854ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto out; 855ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 856ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 857ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy) { 858ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EBUSY; 859ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto out; 860ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 861ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* This looks arbitrary. It is. */ 862ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->busy = &parse_insn; 863ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef switch (insn->insn) { 864ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_READ: 865ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->insn_read(dev, s, insn, data); 866ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 867ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_WRITE: 868ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef maxdata = s->maxdata_list 869476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman ? s->maxdata_list[CR_CHAN(insn->chanspec)] 870476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman : s->maxdata; 871ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef for (i = 0; i < insn->n; ++i) { 872ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (data[i] > maxdata) { 873ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 874ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("bad data value(s)\n"); 875ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 876ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 877ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 878ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (ret == 0) 879ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->insn_write(dev, s, insn, data); 880ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 881ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_BITS: 882ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->n != 2) { 883ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 884ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 885ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 886ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->insn_bits(dev, s, insn, data); 887ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 888ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG: 889ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = check_insn_config_length(insn, data); 890ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (ret) 891ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 892ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->insn_config(dev, s, insn, data); 893ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 894ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef default: 895ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 896ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 897ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 898ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 899ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->busy = NULL; 900ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 901ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 902476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanout: 903ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 904ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 905ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 906ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 907ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * COMEDI_INSN 908ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * synchronous instructions 909ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 910ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * arg: 911ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * pointer to insn 912ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 913ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * reads: 914ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * comedi_insn struct at arg 915ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * data (for writes) 916ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 917ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * writes: 918ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * data (for reads) 919ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */ 92071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_insn_ioctl(struct comedi_device *dev, void *arg, void *file) 921ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 922ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_insn insn; 923790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton unsigned int *data = NULL; 924ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int ret = 0; 925ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 926790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL); 927ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!data) { 928ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -ENOMEM; 929ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 930ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 931ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 932ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_from_user(&insn, arg, sizeof(comedi_insn))) { 933ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 934ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 935ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 936ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 937ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* This is where the behavior of insn and insnlist deviate. */ 938ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn.n > MAX_SAMPLES) 939ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef insn.n = MAX_SAMPLES; 940ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn.insn & INSN_MASK_WRITE) { 941790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton if (copy_from_user(data, insn.data, insn.n * sizeof(unsigned int))) { 942ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 943ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 944ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 945ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 946ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = parse_insn(dev, &insn, data, file); 947ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (ret < 0) 948ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 949ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn.insn & INSN_MASK_READ) { 950790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton if (copy_to_user(insn.data, data, insn.n * sizeof(unsigned int))) { 951ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 952ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 953ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 954ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 955ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = insn.n; 956ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 957476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanerror: 958476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman kfree(data); 959ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 960ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 961ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 962ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 963ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 964ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_CMD 965ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef command ioctl 966ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 967ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 968ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef pointer to cmd structure 969ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 970ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 971ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef cmd structure at arg 972ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef channel/range list 973ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 974ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 975ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef modified cmd structure at arg 976ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 977ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 97871b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_cmd_ioctl(struct comedi_device *dev, void *arg, void *file) 979ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 980ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton struct comedi_cmd user_cmd; 98134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 982d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton struct comedi_async *async; 983ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int ret = 0; 984ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned int *chanlist_saver = NULL; 985ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 986ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton if (copy_from_user(&user_cmd, arg, sizeof(struct comedi_cmd))) { 987ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("bad cmd address\n"); 988ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 989ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 990476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman /* save user's chanlist pointer so it can be restored later */ 991ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef chanlist_saver = user_cmd.chanlist; 992ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 993ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (user_cmd.subdev >= dev->n_subdevices) { 994ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("%d no such subdevice\n", user_cmd.subdev); 995ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENODEV; 996ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 997ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 998ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + user_cmd.subdev; 999ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async = s->async; 1000ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1001ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->type == COMEDI_SUBD_UNUSED) { 1002ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("%d not valid subdevice\n", user_cmd.subdev); 1003ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EIO; 1004ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1005ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1006ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->do_cmd || !s->do_cmdtest || !s->async) { 1007ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("subdevice %i does not support commands\n", 1008ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd.subdev); 1009ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EIO; 1010ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1011ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1012ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* are we locked? (ioctl lock) */ 1013ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->lock && s->lock != file) { 1014ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("subdevice locked\n"); 1015ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EACCES; 1016ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1017ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1018ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* are we busy? */ 1019ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy) { 1020ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("subdevice busy\n"); 1021ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EBUSY; 1022ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1023ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->busy = file; 1024ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1025ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* make sure channel/gain list isn't too long */ 1026ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (user_cmd.chanlist_len > s->len_chanlist) { 1027ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("channel/gain list too long %u > %d\n", 1028ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd.chanlist_len, s->len_chanlist); 1029ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 1030ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1031ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1032ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1033ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* make sure channel/gain list isn't too short */ 1034ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (user_cmd.chanlist_len < 1) { 1035ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("channel/gain list too short %u < 1\n", 1036ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd.chanlist_len); 1037ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 1038ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1039ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1040ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1041476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman kfree(async->cmd.chanlist); 1042ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->cmd = user_cmd; 1043ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->cmd.data = NULL; 1044ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* load channel/gain list */ 1045ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->cmd.chanlist = 1046476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman kmalloc(async->cmd.chanlist_len * sizeof(int), GFP_KERNEL); 1047ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!async->cmd.chanlist) { 1048ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("allocation failed\n"); 1049ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -ENOMEM; 1050ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1051ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1052ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1053ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_from_user(async->cmd.chanlist, user_cmd.chanlist, 1054476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman async->cmd.chanlist_len * sizeof(int))) { 1055ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("fault reading chanlist\n"); 1056ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 1057ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1058ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1059ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1060ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* make sure each element in channel/gain list is valid */ 1061476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman ret = check_chanlist(s, async->cmd.chanlist_len, async->cmd.chanlist); 1062476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (ret < 0) { 1063ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("bad chanlist\n"); 1064ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1065ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1066ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1067ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->do_cmdtest(dev, s, &async->cmd); 1068ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1069ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (async->cmd.flags & TRIG_BOGUS || ret) { 1070ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("test returned %d\n", ret); 1071ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd = async->cmd; 1072476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman /* restore chanlist pointer before copying back */ 1073ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd.chanlist = chanlist_saver; 1074ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd.data = NULL; 1075ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton if (copy_to_user(arg, &user_cmd, sizeof(struct comedi_cmd))) { 1076ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("fault writing cmd\n"); 1077ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 1078ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1079ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1080ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EAGAIN; 1081ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1082ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1083ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1084ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!async->prealloc_bufsz) { 1085ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -ENOMEM; 1086ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("no buffer (?)\n"); 1087ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1088ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1089ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1090ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_reset_async_buf(async); 1091ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1092ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->cb_mask = 1093476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR | 1094476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman COMEDI_CB_OVERFLOW; 1095476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (async->cmd.flags & TRIG_WAKE_EOS) 1096ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->cb_mask |= COMEDI_CB_EOS; 1097ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1098ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING); 1099ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1100ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef CONFIG_COMEDI_RT 1101ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (async->cmd.flags & TRIG_RT) { 1102ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (comedi_switch_to_rt(dev) == 0) 1103ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_set_subdevice_runflags(s, SRF_RT, SRF_RT); 1104ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1105ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif 1106ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1107ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->do_cmd(dev, s); 1108ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (ret == 0) 1109ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 1110ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1111476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancleanup: 1112ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef do_become_nonbusy(dev, s); 1113ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1114ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 1115ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1116ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1117ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 1118ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_CMDTEST 1119ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef command testing ioctl 1120ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1121ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 1122ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef pointer to cmd structure 1123ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1124ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 1125ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef cmd structure at arg 1126ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef channel/range list 1127ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1128ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 1129ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef modified cmd structure at arg 1130ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1131ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 113271b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_cmdtest_ioctl(struct comedi_device *dev, void *arg, void *file) 1133ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1134ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton struct comedi_cmd user_cmd; 113534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 1136ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int ret = 0; 1137ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned int *chanlist = NULL; 1138ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned int *chanlist_saver = NULL; 1139ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1140ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton if (copy_from_user(&user_cmd, arg, sizeof(struct comedi_cmd))) { 1141ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("bad cmd address\n"); 1142ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 1143ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1144476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman /* save user's chanlist pointer so it can be restored later */ 1145ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef chanlist_saver = user_cmd.chanlist; 1146ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1147ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (user_cmd.subdev >= dev->n_subdevices) { 1148ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("%d no such subdevice\n", user_cmd.subdev); 1149ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENODEV; 1150ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1151ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1152ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + user_cmd.subdev; 1153ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->type == COMEDI_SUBD_UNUSED) { 1154ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("%d not valid subdevice\n", user_cmd.subdev); 1155ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EIO; 1156ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1157ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1158ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->do_cmd || !s->do_cmdtest) { 1159ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("subdevice %i does not support commands\n", 1160ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd.subdev); 1161ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EIO; 1162ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1163ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1164ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* make sure channel/gain list isn't too long */ 1165ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (user_cmd.chanlist_len > s->len_chanlist) { 1166ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("channel/gain list too long %d > %d\n", 1167ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd.chanlist_len, s->len_chanlist); 1168ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 1169ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1170ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1171ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1172ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* load channel/gain list */ 1173ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (user_cmd.chanlist) { 1174ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef chanlist = 1175476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman kmalloc(user_cmd.chanlist_len * sizeof(int), GFP_KERNEL); 1176ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!chanlist) { 1177ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("allocation failed\n"); 1178ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -ENOMEM; 1179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1181ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1182ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_from_user(chanlist, user_cmd.chanlist, 1183476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman user_cmd.chanlist_len * sizeof(int))) { 1184ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("fault reading chanlist\n"); 1185ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 1186ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1187ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1188ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1189ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* make sure each element in channel/gain list is valid */ 1190476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman ret = check_chanlist(s, user_cmd.chanlist_len, chanlist); 1191476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (ret < 0) { 1192ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("bad chanlist\n"); 1193ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1194ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1195ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1196ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd.chanlist = chanlist; 1197ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1198ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->do_cmdtest(dev, s, &user_cmd); 1200ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1201476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman /* restore chanlist pointer before copying back */ 1202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd.chanlist = chanlist_saver; 1203ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1204ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton if (copy_to_user(arg, &user_cmd, sizeof(struct comedi_cmd))) { 1205ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("bad cmd address\n"); 1206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 1207ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1208ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1209476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancleanup: 1210476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman kfree(chanlist); 1211ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1212ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 1213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1214ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1215ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 1216ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_LOCK 1217ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef lock subdevice 1218ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1219ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 1220ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef subdevice number 1221ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1222ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 1223ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef none 1224ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1225ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 1226ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef none 1227ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1228ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 1229ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 123071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_lock_ioctl(struct comedi_device *dev, unsigned int arg, void *file) 1231ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1232ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int ret = 0; 1233ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned long flags; 123434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 1235ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1236ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (arg >= dev->n_subdevices) 1237ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 1238ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + arg; 1239ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1240ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_spin_lock_irqsave(&s->spin_lock, flags); 1241476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (s->busy || s->lock) 1242ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EBUSY; 1243476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman else 1244ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->lock = file; 1245ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_spin_unlock_irqrestore(&s->spin_lock, flags); 1246ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1247ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (ret < 0) 1248ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 1249ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1250ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#if 0 1251ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->lock_f) 1252ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->lock_f(dev, s); 1253ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif 1254ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1255ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 1256ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1257ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1258ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 1259ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_UNLOCK 1260ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unlock subdevice 1261ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1262ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 1263ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef subdevice number 1264ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1265ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 1266ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef none 1267ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1268ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 1269ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef none 1270ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1271ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef This function isn't protected by the semaphore, since 1272ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef we already own the lock. 1273ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 127471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg, void *file) 1275ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 127634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 1277ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1278ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (arg >= dev->n_subdevices) 1279ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 1280ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + arg; 1281ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1282ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy) 1283ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EBUSY; 1284ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1285ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->lock && s->lock != file) 1286ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EACCES; 1287ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1288ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->lock == file) { 1289ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#if 0 1290ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->unlock) 1291ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->unlock(dev, s); 1292ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif 1293ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1294ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->lock = NULL; 1295ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1296ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1297ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 1298ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1299ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1300ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 1301ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_CANCEL 1302ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef cancel acquisition ioctl 1303ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1304ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 1305ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef subdevice number 1306ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1307ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 1308ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef nothing 1309ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1310ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 1311ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef nothing 1312ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1313ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 131471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg, void *file) 1315ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 131634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 1317ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1318ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (arg >= dev->n_subdevices) 1319ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 1320ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + arg; 1321ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->async == NULL) 1322ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 1323ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1324ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->lock && s->lock != file) 1325ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EACCES; 1326ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1327ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->busy) 1328ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 1329ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1330ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy != file) 1331ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EBUSY; 1332ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1333ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return do_cancel(dev, s); 1334ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1335ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1336ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 1337ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_POLL ioctl 1338ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef instructs driver to synchronize buffers 1339ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1340ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 1341ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef subdevice number 1342ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1343ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 1344ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef nothing 1345ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1346ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 1347ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef nothing 1348ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1349ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 135071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_poll_ioctl(struct comedi_device *dev, unsigned int arg, void *file) 1351ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 135234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 1353ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1354ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (arg >= dev->n_subdevices) 1355ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 1356ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + arg; 1357ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1358ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->lock && s->lock != file) 1359ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EACCES; 1360ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1361ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->busy) 1362ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 1363ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1364ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy != file) 1365ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EBUSY; 1366ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1367ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->poll) 1368ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return s->poll(dev, s); 1369ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1370ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 1371ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1372ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 137334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s) 1374ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1375ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int ret = 0; 1376ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1377ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) && s->cancel) 1378ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->cancel(dev, s); 1379ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1380ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef do_become_nonbusy(dev, s); 1381ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1382ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 1383ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1384ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1385ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefvoid comedi_unmap(struct vm_area_struct *area) 1386ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1387d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton struct comedi_async *async; 138871b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev; 1389ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1390ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async = area->vm_private_data; 1391ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef dev = async->subdevice->device; 1392ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1393ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_lock(&dev->mutex); 1394ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->mmap_count--; 1395ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 1396ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1397ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1398ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic struct vm_operations_struct comedi_vm_ops = { 1399476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman .close = comedi_unmap, 1400ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}; 1401ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1402ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_mmap(struct file *file, struct vm_area_struct *vma) 1403ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1404ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef const unsigned minor = iminor(file->f_dentry->d_inode); 1405476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct comedi_device_file_info *dev_file_info = 1406476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_device_file_info(minor); 140771b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev = dev_file_info->device; 1408d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton struct comedi_async *async = NULL; 1409ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned long start = vma->vm_start; 1410ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned long size; 1411ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int n_pages; 1412ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int i; 1413ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int retval; 141434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 1415ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1416ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_lock(&dev->mutex); 1417ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!dev->attached) { 1418ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("no driver configured on comedi%i\n", dev->minor); 1419ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -ENODEV; 1420ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1421ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1422476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (vma->vm_flags & VM_WRITE) 1423ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = comedi_get_write_subdevice(dev_file_info); 1424476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman else 1425ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = comedi_get_read_subdevice(dev_file_info); 1426476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman 1427ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s == NULL) { 1428ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EINVAL; 1429ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1430ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1431ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async = s->async; 1432ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (async == NULL) { 1433ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EINVAL; 1434ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1435ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1436ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1437ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (vma->vm_pgoff != 0) { 1438ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("comedi: mmap() offset must be 0.\n"); 1439ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EINVAL; 1440ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1441ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1442ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1443ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef size = vma->vm_end - vma->vm_start; 1444ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (size > async->prealloc_bufsz) { 1445ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EFAULT; 1446ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1447ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1448ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (size & (~PAGE_MASK)) { 1449ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EFAULT; 1450ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1451ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1452ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1453ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef n_pages = size >> PAGE_SHIFT; 1454ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef for (i = 0; i < n_pages; ++i) { 1455ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (remap_pfn_range(vma, start, 1456476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman page_to_pfn(virt_to_page(async-> 1457476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman buf_page_list[i]. 1458476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman virt_addr)), 1459476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman PAGE_SIZE, PAGE_SHARED)) { 1460ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EAGAIN; 1461ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1462ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1463ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef start += PAGE_SIZE; 1464ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1465ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1466ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef vma->vm_ops = &comedi_vm_ops; 1467ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef vma->vm_private_data = async; 1468ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1469ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->mmap_count++; 1470ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1471ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = 0; 1472476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmandone: 1473ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 1474ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return retval; 1475ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1476ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1477476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic unsigned int comedi_poll(struct file *file, poll_table *wait) 1478ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1479ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned int mask = 0; 1480ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef const unsigned minor = iminor(file->f_dentry->d_inode); 1481476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct comedi_device_file_info *dev_file_info = 1482476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_device_file_info(minor); 148371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev = dev_file_info->device; 148434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *read_subdev; 148534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *write_subdev; 1486ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1487ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_lock(&dev->mutex); 1488ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!dev->attached) { 1489ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("no driver configured on comedi%i\n", dev->minor); 1490ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 1491ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 1492ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1493ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1494ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mask = 0; 1495ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef read_subdev = comedi_get_read_subdevice(dev_file_info); 1496ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (read_subdev) { 1497ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef poll_wait(file, &read_subdev->async->wait_head, wait); 1498ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!read_subdev->busy 1499476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman || comedi_buf_read_n_available(read_subdev->async) > 0 1500476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman || !(comedi_get_subdevice_runflags(read_subdev) & 1501476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman SRF_RUNNING)) { 1502ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mask |= POLLIN | POLLRDNORM; 1503ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1504ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1505ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef write_subdev = comedi_get_write_subdevice(dev_file_info); 1506ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (write_subdev) { 1507ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef poll_wait(file, &write_subdev->async->wait_head, wait); 1508476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_buf_write_alloc(write_subdev->async, 1509476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman write_subdev->async->prealloc_bufsz); 1510ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!write_subdev->busy 1511476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman || !(comedi_get_subdevice_runflags(write_subdev) & 1512476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman SRF_RUNNING) 1513476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman || comedi_buf_write_n_allocated(write_subdev->async) >= 1514476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman bytes_per_sample(write_subdev->async->subdevice)) { 1515ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mask |= POLLOUT | POLLWRNORM; 1516ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1517ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1518ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1519ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 1520ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return mask; 1521ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1522ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1523ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic ssize_t comedi_write(struct file *file, const char *buf, size_t nbytes, 1524476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman loff_t *offset) 1525ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 152634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 1527d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton struct comedi_async *async; 1528ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int n, m, count = 0, retval = 0; 1529ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DECLARE_WAITQUEUE(wait, current); 1530ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef const unsigned minor = iminor(file->f_dentry->d_inode); 1531476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct comedi_device_file_info *dev_file_info = 1532476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_device_file_info(minor); 153371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev = dev_file_info->device; 1534ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1535ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!dev->attached) { 1536ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("no driver configured on comedi%i\n", dev->minor); 1537ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -ENODEV; 1538ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1539ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1540ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1541ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = comedi_get_write_subdevice(dev_file_info); 1542ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s == NULL) { 1543ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EIO; 1544ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1545ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1546ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async = s->async; 1547ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1548ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!nbytes) { 1549ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = 0; 1550ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1551ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1552ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->busy) { 1553ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = 0; 1554ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1555ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1556ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy != file) { 1557ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EACCES; 1558ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1559ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1560ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef add_wait_queue(&async->wait_head, &wait); 1561ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef while (nbytes > 0 && !retval) { 1562ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef set_current_state(TASK_INTERRUPTIBLE); 1563ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1564ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef n = nbytes; 1565ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1566ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef m = n; 1567476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (async->buf_write_ptr + m > async->prealloc_bufsz) 1568ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef m = async->prealloc_bufsz - async->buf_write_ptr; 1569ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_buf_write_alloc(async, async->prealloc_bufsz); 1570476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (m > comedi_buf_write_n_allocated(async)) 1571ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef m = comedi_buf_write_n_allocated(async); 1572ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (m < n) 1573ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef n = m; 1574ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1575ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (n == 0) { 1576ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) { 1577ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (comedi_get_subdevice_runflags(s) & 1578476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman SRF_ERROR) { 1579ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EPIPE; 1580ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } else { 1581ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = 0; 1582ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1583ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef do_become_nonbusy(dev, s); 1584ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1585ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1586ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (file->f_flags & O_NONBLOCK) { 1587ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EAGAIN; 1588ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1589ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1590ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (signal_pending(current)) { 1591ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -ERESTARTSYS; 1592ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1593ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1594ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef schedule(); 1595476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (!s->busy) 1596ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1597ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy != file) { 1598ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EACCES; 1599ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1600ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1601ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef continue; 1602ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1603ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1604ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef m = copy_from_user(async->prealloc_buf + async->buf_write_ptr, 1605476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman buf, n); 1606ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (m) { 1607ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef n -= m; 1608ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EFAULT; 1609ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1610ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_buf_write_free(async, n); 1611ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1612ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef count += n; 1613ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef nbytes -= n; 1614ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1615ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef buf += n; 1616ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; /* makes device work like a pipe */ 1617ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1618ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef set_current_state(TASK_RUNNING); 1619ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef remove_wait_queue(&async->wait_head, &wait); 1620ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1621ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefdone: 1622476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman return count ? count : retval; 1623ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1624ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1625ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic ssize_t comedi_read(struct file *file, char *buf, size_t nbytes, 1626476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman loff_t *offset) 1627ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 162834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 1629d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton struct comedi_async *async; 1630ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int n, m, count = 0, retval = 0; 1631ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DECLARE_WAITQUEUE(wait, current); 1632ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef const unsigned minor = iminor(file->f_dentry->d_inode); 1633476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct comedi_device_file_info *dev_file_info = 1634476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_device_file_info(minor); 163571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev = dev_file_info->device; 1636ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1637ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!dev->attached) { 1638ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("no driver configured on comedi%i\n", dev->minor); 1639ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -ENODEV; 1640ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1641ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1642ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1643ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = comedi_get_read_subdevice(dev_file_info); 1644ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s == NULL) { 1645ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EIO; 1646ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1647ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1648ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async = s->async; 1649ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!nbytes) { 1650ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = 0; 1651ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1652ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1653ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->busy) { 1654ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = 0; 1655ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1656ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1657ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy != file) { 1658ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EACCES; 1659ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1660ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1661ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1662ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef add_wait_queue(&async->wait_head, &wait); 1663ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef while (nbytes > 0 && !retval) { 1664ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef set_current_state(TASK_INTERRUPTIBLE); 1665ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1666ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef n = nbytes; 1667ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1668ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef m = comedi_buf_read_n_available(async); 1669476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman /* printk("%d available\n",m); */ 1670476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (async->buf_read_ptr + m > async->prealloc_bufsz) 1671ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef m = async->prealloc_bufsz - async->buf_read_ptr; 1672476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman /* printk("%d contiguous\n",m); */ 1673ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (m < n) 1674ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef n = m; 1675ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1676ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (n == 0) { 1677ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) { 1678ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef do_become_nonbusy(dev, s); 1679ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (comedi_get_subdevice_runflags(s) & 1680476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman SRF_ERROR) { 1681ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EPIPE; 1682ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } else { 1683ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = 0; 1684ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1685ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1686ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1687ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (file->f_flags & O_NONBLOCK) { 1688ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EAGAIN; 1689ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1690ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1691ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (signal_pending(current)) { 1692ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -ERESTARTSYS; 1693ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1694ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1695ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef schedule(); 1696ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->busy) { 1697ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = 0; 1698ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1699ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1700ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy != file) { 1701ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EACCES; 1702ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1703ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1704ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef continue; 1705ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1706ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef m = copy_to_user(buf, async->prealloc_buf + 1707476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman async->buf_read_ptr, n); 1708ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (m) { 1709ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef n -= m; 1710ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EFAULT; 1711ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1712ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1713ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_buf_read_alloc(async, n); 1714ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_buf_read_free(async, n); 1715ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1716ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef count += n; 1717ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef nbytes -= n; 1718ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1719ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef buf += n; 1720ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; /* makes device work like a pipe */ 1721ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1722ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | SRF_RUNNING)) && 1723476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman async->buf_read_count - async->buf_write_count == 0) { 1724ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef do_become_nonbusy(dev, s); 1725ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1726ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef set_current_state(TASK_RUNNING); 1727ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef remove_wait_queue(&async->wait_head, &wait); 1728ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1729ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefdone: 1730476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman return count ? count : retval; 1731ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1732ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1733ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 1734ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef This function restores a subdevice to an idle state. 1735ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */ 173634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s) 1737ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1738d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton struct comedi_async *async = s->async; 1739ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1740ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_set_subdevice_runflags(s, SRF_RUNNING, 0); 1741ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef CONFIG_COMEDI_RT 1742ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (comedi_get_subdevice_runflags(s) & SRF_RT) { 1743ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_switch_to_non_rt(dev); 1744ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_set_subdevice_runflags(s, SRF_RT, 0); 1745ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1746ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif 1747ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (async) { 1748ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_reset_async_buf(async); 1749ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->inttrig = NULL; 1750ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } else { 1751476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman printk(KERN_ERR 1752476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman "BUG: (?) do_become_nonbusy called with async=0\n"); 1753ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1754ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1755ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->busy = NULL; 1756ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1757ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1758ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_open(struct inode *inode, struct file *file) 1759ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1760ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef const unsigned minor = iminor(inode); 1761476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct comedi_device_file_info *dev_file_info = 1762476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_device_file_info(minor); 176371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev = dev_file_info ? dev_file_info->device : NULL; 1764979200719d35934367bbf97d9b7d22d5b5281ddaIan Abbott 1765ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (dev == NULL) { 1766ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("invalid minor number\n"); 1767ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENODEV; 1768ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1769ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1770ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* This is slightly hacky, but we want module autoloading 1771ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * to work for root. 1772ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * case: user opens device, attached -> ok 1773ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * case: user opens device, unattached, in_request_module=0 -> autoload 1774ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * case: user opens device, unattached, in_request_module=1 -> fail 1775ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * case: root opens device, attached -> ok 1776ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * case: root opens device, unattached, in_request_module=1 -> ok 1777ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * (typically called from modprobe) 1778ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * case: root opens device, unattached, in_request_module=0 -> autoload 1779ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 1780ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * The last could be changed to "-> ok", which would deny root 1781ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * autoloading. 1782ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */ 1783ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_lock(&dev->mutex); 1784ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (dev->attached) 1785ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto ok; 1786ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!capable(CAP_SYS_MODULE) && dev->in_request_module) { 1787ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("in request module\n"); 1788ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 1789ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENODEV; 1790ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1791ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (capable(CAP_SYS_MODULE) && dev->in_request_module) 1792ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto ok; 1793ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1794ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef dev->in_request_module = 1; 1795ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1796ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef CONFIG_KMOD 1797ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 179856d92c60e6dc708541711e9de4993e7d527d08e8Ian Abbott request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor); 1799ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_lock(&dev->mutex); 1800ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif 1801ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1802ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef dev->in_request_module = 0; 1803ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1804ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!dev->attached && !capable(CAP_SYS_MODULE)) { 1805ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("not attached and not CAP_SYS_MODULE\n"); 1806ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 1807ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENODEV; 1808ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1809ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefok: 1810ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef __module_get(THIS_MODULE); 1811ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1812ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (dev->attached) { 1813ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!try_module_get(dev->driver->module)) { 1814ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef module_put(THIS_MODULE); 1815ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 1816ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENOSYS; 1817ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1818ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1819ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1820476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (dev->attached && dev->use_count == 0 && dev->open) 1821ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef dev->open(dev); 1822ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1823ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef dev->use_count++; 1824ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1825ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 1826ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1827ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 1828ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1829ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1830ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_close(struct inode *inode, struct file *file) 1831ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1832ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef const unsigned minor = iminor(inode); 1833476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct comedi_device_file_info *dev_file_info = 1834476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_device_file_info(minor); 183571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev = dev_file_info->device; 183634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s = NULL; 1837ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int i; 1838ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1839ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_lock(&dev->mutex); 1840ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1841ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (dev->subdevices) { 1842ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef for (i = 0; i < dev->n_subdevices; i++) { 1843ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + i; 1844ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1845476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (s->busy == file) 1846ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef do_cancel(dev, s); 1847476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (s->lock == file) 1848ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->lock = NULL; 1849ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1850ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1851476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (dev->attached && dev->use_count == 1 && dev->close) 1852ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef dev->close(dev); 1853ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1854ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef module_put(THIS_MODULE); 1855476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (dev->attached) 1856ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef module_put(dev->driver->module); 1857ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1858ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef dev->use_count--; 1859ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1860ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 1861ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1862476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (file->f_flags & FASYNC) 1863ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_fasync(-1, file, 0); 1864ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1865ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 1866ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1867ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1868ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_fasync(int fd, struct file *file, int on) 1869ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1870ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef const unsigned minor = iminor(file->f_dentry->d_inode); 1871476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct comedi_device_file_info *dev_file_info = 1872476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_device_file_info(minor); 1873476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman 187471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev = dev_file_info->device; 1875ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1876ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return fasync_helper(fd, file, on, &dev->async_queue); 1877ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1878ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1879ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefconst struct file_operations comedi_fops = { 1880476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman .owner = THIS_MODULE, 1881ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef HAVE_UNLOCKED_IOCTL 1882476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman .unlocked_ioctl = comedi_unlocked_ioctl, 1883ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#else 1884476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman .ioctl = comedi_ioctl, 1885ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif 1886ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef HAVE_COMPAT_IOCTL 1887476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman .compat_ioctl = comedi_compat_ioctl, 1888ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif 1889476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman .open = comedi_open, 1890476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman .release = comedi_close, 1891476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman .read = comedi_read, 1892476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman .write = comedi_write, 1893476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman .mmap = comedi_mmap, 1894476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman .poll = comedi_poll, 1895476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman .fasync = comedi_fasync, 1896ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}; 1897ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1898476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstruct class *comedi_class; 1899ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic struct cdev comedi_cdev; 1900ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1901ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic void comedi_cleanup_legacy_minors(void) 1902ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1903ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned i; 1904476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman 19051dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porr for (i = 0; i < comedi_num_legacy_minors; i++) 1906ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_free_board_minor(i); 1907ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1908ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1909ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int __init comedi_init(void) 1910ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1911ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int i; 1912ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int retval; 1913ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1914476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman printk(KERN_INFO "comedi: version " COMEDI_RELEASE 1915476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman " - http://www.comedi.org\n"); 1916ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1917a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess if (comedi_num_legacy_minors < 0 || 1918a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) { 1919a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess printk(KERN_ERR "comedi: error: invalid value for module " 1920a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess "parameter \"comedi_num_legacy_minors\". Valid values " 1921a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess "are 0 through %i.\n", COMEDI_NUM_BOARD_MINORS); 1922a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess return -EINVAL; 1923a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess } 1924a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess 1925a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess /* 1926a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess * comedi is unusable if both comedi_autoconfig and 1927a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess * comedi_num_legacy_minors are zero, so we might as well adjust the 1928a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess * defaults in that case 1929a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess */ 1930a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess if (comedi_autoconfig == 0 && comedi_num_legacy_minors == 0) 1931a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess comedi_num_legacy_minors = 16; 1932a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess 1933476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman memset(comedi_file_info_table, 0, 1934476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS); 1935ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1936ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0), 1937476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman COMEDI_NUM_MINORS, "comedi"); 1938ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (retval) 1939ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EIO; 1940ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef cdev_init(&comedi_cdev, &comedi_fops); 1941ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_cdev.owner = THIS_MODULE; 1942ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kobject_set_name(&comedi_cdev.kobj, "comedi"); 1943ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) { 1944ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), 1945476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman COMEDI_NUM_MINORS); 1946ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EIO; 1947ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1948ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_class = class_create(THIS_MODULE, "comedi"); 1949ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (IS_ERR(comedi_class)) { 1950ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef printk("comedi: failed to create class"); 1951ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef cdev_del(&comedi_cdev); 1952ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), 1953476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman COMEDI_NUM_MINORS); 1954ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return PTR_ERR(comedi_class); 1955ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1956ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1957ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* XXX requires /proc interface */ 1958ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_proc_init(); 1959ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1960476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman /* create devices files for legacy/manual use */ 19611dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porr for (i = 0; i < comedi_num_legacy_minors; i++) { 1962ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int minor; 1963ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef minor = comedi_alloc_board_minor(NULL); 1964476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (minor < 0) { 1965ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_cleanup_legacy_minors(); 1966ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef cdev_del(&comedi_cdev); 1967ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), 1968476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman COMEDI_NUM_MINORS); 1969ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return minor; 1970ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1971ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1972ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1973ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_rt_init(); 1974ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1975ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_register_ioctl32(); 1976ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1977ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 1978ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1979ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1980ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic void __exit comedi_cleanup(void) 1981ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1982ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int i; 1983ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1984ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_cleanup_legacy_minors(); 1985476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman for (i = 0; i < COMEDI_NUM_MINORS; ++i) 1986ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef BUG_ON(comedi_file_info_table[i]); 1987476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman 1988ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1989ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef class_destroy(comedi_class); 1990ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef cdev_del(&comedi_cdev); 1991ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS); 1992ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1993ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_proc_cleanup(); 1994ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1995ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_rt_cleanup(); 1996ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1997ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_unregister_ioctl32(); 1998ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1999ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2000ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefmodule_init(comedi_init); 2001ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefmodule_exit(comedi_cleanup); 2002ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 200371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonvoid comedi_error(const struct comedi_device *dev, const char *s) 2004ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 2005ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rt_printk("comedi%d: %s: %s\n", dev->minor, dev->driver->driver_name, 2006476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman s); 2007ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 2008ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 200934c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid comedi_event(struct comedi_device *dev, struct comedi_subdevice *s) 2010ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 2011d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton struct comedi_async *async = s->async; 2012ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned runflags = 0; 2013ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned runflags_mask = 0; 2014ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2015476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman /* DPRINTK("comedi_event 0x%x\n",mask); */ 2016ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2017ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) == 0) 2018ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return; 2019ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2020ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->async-> 2021476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) { 2022ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef runflags_mask |= SRF_RUNNING; 2023ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2024ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* remember if an error event has occured, so an error 2025ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * can be returned the next time the user does a read() */ 2026ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) { 2027ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef runflags_mask |= SRF_ERROR; 2028ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef runflags |= SRF_ERROR; 2029ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2030ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (runflags_mask) { 2031ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /*sets SRF_ERROR and SRF_RUNNING together atomically */ 2032ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_set_subdevice_runflags(s, runflags_mask, runflags); 2033ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2034ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2035ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (async->cb_mask & s->async->events) { 2036ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (comedi_get_subdevice_runflags(s) & SRF_USER) { 2037ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2038ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (dev->rt) { 2039ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef CONFIG_COMEDI_RT 2040476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman /* pend wake up */ 2041ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_rt_pend_wakeup(&async->wait_head); 2042ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#else 2043476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman printk 2044476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman ("BUG: comedi_event() code unreachable\n"); 2045ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif 2046ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } else { 2047ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef wake_up_interruptible(&async->wait_head); 2048ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->subdev_flags & SDF_CMD_READ) { 2049ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kill_fasync(&dev->async_queue, SIGIO, 2050476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman POLL_IN); 2051ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2052ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->subdev_flags & SDF_CMD_WRITE) { 2053ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kill_fasync(&dev->async_queue, SIGIO, 2054476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman POLL_OUT); 2055ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2056ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2057ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } else { 2058ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (async->cb_func) 2059ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->cb_func(s->async->events, async->cb_arg); 2060ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* XXX bug here. If subdevice A is rt, and 2061ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * subdevice B tries to callback to a normal 2062ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * linux kernel function, it will be at the 2063ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * wrong priority. Since this isn't very 2064ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * common, I'm not going to worry about it. */ 2065ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2066ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2067ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->async->events = 0; 2068ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 2069ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 207034c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid comedi_set_subdevice_runflags(struct comedi_subdevice *s, unsigned mask, 2071476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman unsigned bits) 2072ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 2073ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned long flags; 2074ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2075ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_spin_lock_irqsave(&s->spin_lock, flags); 2076ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->runflags &= ~mask; 2077ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->runflags |= (bits & mask); 2078ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_spin_unlock_irqrestore(&s->spin_lock, flags); 2079ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 2080ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 208134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonunsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s) 2082ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 2083ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned long flags; 2084ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned runflags; 2085ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2086ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_spin_lock_irqsave(&s->spin_lock, flags); 2087ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef runflags = s->runflags; 2088ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_spin_unlock_irqrestore(&s->spin_lock, flags); 2089ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return runflags; 2090ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 2091ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 209271b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int is_device_busy(struct comedi_device *dev) 2093ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 209434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 2095ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int i; 2096ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2097ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!dev->attached) 2098ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 2099ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2100ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef for (i = 0; i < dev->n_subdevices; i++) { 2101ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + i; 2102ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy) 2103ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 1; 2104ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->async && s->async->mmap_count) 2105ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 1; 2106ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2107ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2108ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 2109ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 2110ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 211171b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonvoid comedi_device_init(struct comedi_device *dev) 2112ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 211371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton memset(dev, 0, sizeof(struct comedi_device)); 2114ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef spin_lock_init(&dev->spinlock); 2115ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_init(&dev->mutex); 2116ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef dev->minor = -1; 2117ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 2118ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 211971b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonvoid comedi_device_cleanup(struct comedi_device *dev) 2120ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 2121476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (dev == NULL) 2122476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman return; 2123ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_lock(&dev->mutex); 2124ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_device_detach(dev); 2125ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 2126ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_destroy(&dev->mutex); 2127ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 2128ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2129ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefint comedi_alloc_board_minor(struct device *hardware_device) 2130ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 2131ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned long flags; 2132ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef struct comedi_device_file_info *info; 21330bfbbe8f09617247c87d3b626cbf007c423afff1Bill Pemberton struct device *csdev; 2134ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned i; 2135ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2136ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); 2137476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (info == NULL) 2138476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman return -ENOMEM; 213971b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton info->device = kzalloc(sizeof(struct comedi_device), GFP_KERNEL); 2140476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (info->device == NULL) { 2141ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kfree(info); 2142ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENOMEM; 2143ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2144ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_device_init(info->device); 2145ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags); 2146476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) { 2147476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (comedi_file_info_table[i] == NULL) { 2148ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_file_info_table[i] = info; 2149ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 2150ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2151ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2152ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); 2153476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (i == COMEDI_NUM_BOARD_MINORS) { 2154ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_device_cleanup(info->device); 2155ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kfree(info->device); 2156ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kfree(info); 2157476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman rt_printk 2158476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman ("comedi: error: ran out of minor numbers for board device files.\n"); 2159ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EBUSY; 2160ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2161ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info->device->minor = i; 2162ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef csdev = COMEDI_DEVICE_CREATE(comedi_class, NULL, 2163476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman MKDEV(COMEDI_MAJOR, i), NULL, 2164476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman hardware_device, "comedi%i", i); 2165476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (!IS_ERR(csdev)) 2166ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info->device->class_dev = csdev; 2167476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman 2168ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return i; 2169ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 2170ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2171ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefvoid comedi_free_board_minor(unsigned minor) 2172ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 2173ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned long flags; 2174ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef struct comedi_device_file_info *info; 2175ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2176ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS); 2177ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags); 2178ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info = comedi_file_info_table[minor]; 2179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_file_info_table[minor] = NULL; 2180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); 2181ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2182476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (info) { 218371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev = info->device; 2184476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (dev) { 2185476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (dev->class_dev) { 2186476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman device_destroy(comedi_class, 2187476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman MKDEV(COMEDI_MAJOR, dev->minor)); 2188ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2189ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_device_cleanup(dev); 2190ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kfree(dev); 2191ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2192ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kfree(info); 2193ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2194ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 2195ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 219634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonint comedi_alloc_subdevice_minor(struct comedi_device *dev, struct comedi_subdevice *s) 2197ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 2198ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned long flags; 2199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef struct comedi_device_file_info *info; 22000bfbbe8f09617247c87d3b626cbf007c423afff1Bill Pemberton struct device *csdev; 2201ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned i; 2202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2203ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); 2204476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (info == NULL) 2205476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman return -ENOMEM; 2206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info->device = dev; 2207ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info->read_subdevice = s; 2208ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info->write_subdevice = s; 2209ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags); 22104c41f3ae3bf0bcc53f259b657c2fbc3961ff2b8aFrank Mori Hess for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) { 2211476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (comedi_file_info_table[i] == NULL) { 2212ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_file_info_table[i] = info; 2213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 2214ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2215ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2216ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); 2217476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (i == COMEDI_NUM_MINORS) { 2218ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kfree(info); 2219476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman rt_printk 2220476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman ("comedi: error: ran out of minor numbers for board device files.\n"); 2221ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EBUSY; 2222ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2223ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->minor = i; 2224ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef csdev = COMEDI_DEVICE_CREATE(comedi_class, dev->class_dev, 2225476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman MKDEV(COMEDI_MAJOR, i), NULL, NULL, 2226476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman "comedi%i_subd%i", dev->minor, 2227476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman (int)(s - dev->subdevices)); 2228476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (!IS_ERR(csdev)) 2229ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->class_dev = csdev; 2230476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman 2231ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return i; 2232ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 2233ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 223434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid comedi_free_subdevice_minor(struct comedi_subdevice *s) 2235ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 2236ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned long flags; 2237ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef struct comedi_device_file_info *info; 2238ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2239476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (s == NULL) 2240476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman return; 2241476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (s->minor < 0) 2242476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman return; 2243ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2244ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef BUG_ON(s->minor >= COMEDI_NUM_MINORS); 2245ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR); 2246ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2247ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags); 2248ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info = comedi_file_info_table[s->minor]; 2249ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_file_info_table[s->minor] = NULL; 2250ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); 2251ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2252476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (s->class_dev) { 2253ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor)); 2254ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->class_dev = NULL; 2255ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2256ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kfree(info); 2257ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 2258ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2259ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstruct comedi_device_file_info *comedi_get_device_file_info(unsigned minor) 2260ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 2261ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned long flags; 2262ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef struct comedi_device_file_info *info; 2263ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2264ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef BUG_ON(minor >= COMEDI_NUM_MINORS); 2265ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags); 2266ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info = comedi_file_info_table[minor]; 2267ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); 2268ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return info; 2269ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 2270