comedi_fops.c revision 92d0127c9d249c078b0939050f25041ed37be7cd
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> 47883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess#include <linux/stat.h> 48ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 49476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#include <linux/io.h> 50476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#include <linux/uaccess.h> 51ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 52242e7ad91a067243d7ab63b6a25ed2e085733446Greg Kroah-Hartman#include "internal.h" 53ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 54ed9eccbe8970f6eedc1b978c157caf1251a896d4David SchleefMODULE_AUTHOR("http://www.comedi.org"); 55ed9eccbe8970f6eedc1b978c157caf1251a896d4David SchleefMODULE_DESCRIPTION("Comedi core module"); 56ed9eccbe8970f6eedc1b978c157caf1251a896d4David SchleefMODULE_LICENSE("GPL"); 57ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 58ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef CONFIG_COMEDI_DEBUG 59ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefint comedi_debug; 6018736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL(comedi_debug); 61ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefmodule_param(comedi_debug, int, 0644); 62ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif 63ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 646a9d7a21d710e544df20266b83b7829d9f7a1020Ian Abbottint comedi_autoconfig = 1; 656a9d7a21d710e544df20266b83b7829d9f7a1020Ian Abbottmodule_param(comedi_autoconfig, bool, 0444); 666a9d7a21d710e544df20266b83b7829d9f7a1020Ian Abbott 6792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int comedi_num_legacy_minors; 681dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porrmodule_param(comedi_num_legacy_minors, int, 0444); 691dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porr 70ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic DEFINE_SPINLOCK(comedi_file_info_table_lock); 71476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstatic struct comedi_device_file_info 720a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral*comedi_file_info_table[COMEDI_NUM_MINORS]; 73476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman 740a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_devconfig_ioctl(struct comedi_device *dev, 7592d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman struct comedi_devconfig __user *arg); 7692d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_bufconfig_ioctl(struct comedi_device *dev, 7792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman struct comedi_bufconfig __user *arg); 780a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_devinfo_ioctl(struct comedi_device *dev, 7992d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman struct comedi_devinfo __user *arg, 8092d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman struct file *file); 810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_subdinfo_ioctl(struct comedi_device *dev, 8292d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman struct comedi_subdinfo __user *arg, void *file); 830a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_chaninfo_ioctl(struct comedi_device *dev, 8492d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman struct comedi_chaninfo __user *arg); 8592d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_bufinfo_ioctl(struct comedi_device *dev, 8692d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman struct comedi_bufinfo __user *arg); 8792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_cmd_ioctl(struct comedi_device *dev, 8892d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman struct comedi_cmd __user *arg, void *file); 890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_lock_ioctl(struct comedi_device *dev, unsigned int arg, 900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral void *file); 910a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg, 920a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral void *file); 930a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg, 940a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral void *file); 9592d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_cmdtest_ioctl(struct comedi_device *dev, 9692d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman struct comedi_cmd __user *arg, void *file); 9792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_insnlist_ioctl(struct comedi_device *dev, 9892d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman struct comedi_insnlist __user *arg, void *file); 9992d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_insn_ioctl(struct comedi_device *dev, 10092d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman struct comedi_insn __user *arg, void *file); 1010a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_poll_ioctl(struct comedi_device *dev, unsigned int subd, 1020a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral void *file); 10371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton 1040a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralextern void do_become_nonbusy(struct comedi_device *dev, 1050a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral struct comedi_subdevice *s); 10634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s); 107ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 108ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_fasync(int fd, struct file *file, int on); 109ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 11071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int is_device_busy(struct comedi_device *dev); 111883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic int resize_async_buffer(struct comedi_device *dev, 112883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_subdevice *s, 113883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_async *async, unsigned new_size); 114883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 115883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess/* declarations for sysfs attribute files */ 116883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_max_read_buffer_kb; 117883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_read_buffer_kb; 118883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_max_write_buffer_kb; 119883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_write_buffer_kb; 120ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 121ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, 122476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman unsigned long arg) 123ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 124ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef const unsigned minor = iminor(file->f_dentry->d_inode); 125476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct comedi_device_file_info *dev_file_info = 126476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_device_file_info(minor); 12771b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev; 128ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int rc; 129ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 13053b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess if (dev_file_info == NULL || dev_file_info->device == NULL) 13153b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess return -ENODEV; 13253b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess dev = dev_file_info->device; 13353b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess 134ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_lock(&dev->mutex); 135ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 136ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* Device config is special, because it must work on 137ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * an unconfigured device. */ 138ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (cmd == COMEDI_DEVCONFIG) { 13992d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman rc = do_devconfig_ioctl(dev, 14092d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman (struct comedi_devconfig __user *)arg); 141ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 142ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 143ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 144ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!dev->attached) { 145ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("no driver configured on /dev/comedi%i\n", dev->minor); 146ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = -ENODEV; 147ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 148ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 149ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 150ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef switch (cmd) { 151ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_BUFCONFIG: 15292d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman rc = do_bufconfig_ioctl(dev, 15392d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman (struct comedi_bufconfig __user *)arg); 154ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 155ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_DEVINFO: 15692d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman rc = do_devinfo_ioctl(dev, (struct comedi_devinfo __user *)arg, 15792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman file); 158ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 159ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_SUBDINFO: 16092d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman rc = do_subdinfo_ioctl(dev, 16192d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman (struct comedi_subdinfo __user *)arg, 16292d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman file); 163ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 164ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_CHANINFO: 16592d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman rc = do_chaninfo_ioctl(dev, (void __user *)arg); 166ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 167ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_RANGEINFO: 16892d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman rc = do_rangeinfo_ioctl(dev, (void __user *)arg); 169ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 170ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_BUFINFO: 17192d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman rc = do_bufinfo_ioctl(dev, 17292d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman (struct comedi_bufinfo __user *)arg); 173ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 174ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_LOCK: 175ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_lock_ioctl(dev, arg, file); 176ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 177ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_UNLOCK: 178ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_unlock_ioctl(dev, arg, file); 179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_CANCEL: 181ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_cancel_ioctl(dev, arg, file); 182ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 183ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_CMD: 18492d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman rc = do_cmd_ioctl(dev, (struct comedi_cmd __user *)arg, file); 185ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 186ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_CMDTEST: 18792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman rc = do_cmdtest_ioctl(dev, (struct comedi_cmd __user *)arg, 18892d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman file); 189ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 190ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_INSNLIST: 19192d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman rc = do_insnlist_ioctl(dev, 19292d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman (struct comedi_insnlist __user *)arg, 19392d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman file); 194ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 195ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_INSN: 19692d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman rc = do_insn_ioctl(dev, (struct comedi_insn __user *)arg, 19792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman file); 198ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_POLL: 200ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_poll_ioctl(dev, arg, file); 201ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef default: 203ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = -ENOTTY; 204ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 205ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 207476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmandone: 208ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 209ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return rc; 210ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 211ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 212ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_DEVCONFIG 214ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef device config ioctl 215ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 216ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 217ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef pointer to devconfig structure 218ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 219ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 220ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef devconfig structure at arg 221ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 222ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 223ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef none 224ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 2250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_devconfig_ioctl(struct comedi_device *dev, 22692d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman struct comedi_devconfig __user *arg) 227ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 2280707bb04be89b18ee83b5a997e36cc585f0b988dBill Pemberton struct comedi_devconfig it; 229ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int ret; 230ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned char *aux_data = NULL; 231ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int aux_len; 232ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 233ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!capable(CAP_SYS_ADMIN)) 234ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EPERM; 235ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 236ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (arg == NULL) { 237ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (is_device_busy(dev)) 238ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EBUSY; 239476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (dev->attached) { 240ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef struct module *driver_module = dev->driver->module; 241ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_device_detach(dev); 242ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef module_put(driver_module); 243ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 244ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 245ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 246ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2470707bb04be89b18ee83b5a997e36cc585f0b988dBill Pemberton if (copy_from_user(&it, arg, sizeof(struct comedi_devconfig))) 248ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 249ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 250ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef it.board_name[COMEDI_NAMELEN - 1] = 0; 251ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 252ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (comedi_aux_data(it.options, 0) && 253476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) { 254ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int bit_shift; 255ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef aux_len = it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]; 256ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (aux_len < 0) 257ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 258ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 259ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef aux_data = vmalloc(aux_len); 260ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!aux_data) 261ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENOMEM; 262ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 263ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_from_user(aux_data, 264476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_aux_data(it.options, 0), aux_len)) { 265ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef vfree(aux_data); 266ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 267ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 268ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef it.options[COMEDI_DEVCONF_AUX_DATA_LO] = 269476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman (unsigned long)aux_data; 270ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (sizeof(void *) > sizeof(int)) { 271ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bit_shift = sizeof(int) * 8; 272ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef it.options[COMEDI_DEVCONF_AUX_DATA_HI] = 273476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman ((unsigned long)aux_data) >> bit_shift; 274ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } else 275ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef it.options[COMEDI_DEVCONF_AUX_DATA_HI] = 0; 276ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 277ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 278ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = comedi_device_attach(dev, &it); 279476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (ret == 0) { 280476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (!try_module_get(dev->driver->module)) { 281ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_device_detach(dev); 282ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENOSYS; 283ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 284ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 285ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 286ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (aux_data) 287ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef vfree(aux_data); 288ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 289ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 290ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 291ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 292ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 293ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_BUFCONFIG 294ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef buffer configuration ioctl 295ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 296ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 297ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef pointer to bufconfig structure 298ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 299ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 300ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bufconfig at arg 301ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 302ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 303ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef modified bufconfig at arg 304ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 305ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 30692d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_bufconfig_ioctl(struct comedi_device *dev, 30792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman struct comedi_bufconfig __user *arg) 308ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 309be6aba4a423629126f318d351b2d0eb00abb9dd5Bill Pemberton struct comedi_bufconfig bc; 310d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton struct comedi_async *async; 31134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 312883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess int retval = 0; 313ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 314be6aba4a423629126f318d351b2d0eb00abb9dd5Bill Pemberton if (copy_from_user(&bc, arg, sizeof(struct comedi_bufconfig))) 315ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 316ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 317ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (bc.subdevice >= dev->n_subdevices || bc.subdevice < 0) 318ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 319ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 320ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + bc.subdevice; 321ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async = s->async; 322ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 323ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!async) { 324ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("subdevice does not have async capability\n"); 325ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bc.size = 0; 326ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bc.maximum_size = 0; 327ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto copyback; 328ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 329ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 330ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (bc.maximum_size) { 331ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!capable(CAP_SYS_ADMIN)) 332ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EPERM; 333ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 334ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->max_bufsize = bc.maximum_size; 335ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 336ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 337ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (bc.size) { 338883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess retval = resize_async_buffer(dev, s, async, bc.size); 339883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (retval < 0) 340883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 341ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 342ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 343ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bc.size = async->prealloc_bufsz; 344ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bc.maximum_size = async->max_bufsize; 345ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 346476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancopyback: 347be6aba4a423629126f318d351b2d0eb00abb9dd5Bill Pemberton if (copy_to_user(arg, &bc, sizeof(struct comedi_bufconfig))) 348ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 349ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 350ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 351ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 352ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 353ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 354ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_DEVINFO 355ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef device info ioctl 356ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 357ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 358ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef pointer to devinfo structure 359ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 360ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 361ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef none 362ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 363ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 364ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef devinfo structure 365ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 366ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 3670a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_devinfo_ioctl(struct comedi_device *dev, 36892d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman struct comedi_devinfo __user *arg, 36992d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman struct file *file) 370ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 371063db04b8901c5cf84c552a5053748d183d34e61Bill Pemberton struct comedi_devinfo devinfo; 372ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef const unsigned minor = iminor(file->f_dentry->d_inode); 373476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct comedi_device_file_info *dev_file_info = 374476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_device_file_info(minor); 37534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *read_subdev = 376476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_read_subdevice(dev_file_info); 37734c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *write_subdev = 378476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_write_subdevice(dev_file_info); 379ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 380ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef memset(&devinfo, 0, sizeof(devinfo)); 381ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 382ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* fill devinfo structure */ 383ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef devinfo.version_code = COMEDI_VERSION_CODE; 384ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef devinfo.n_subdevs = dev->n_subdevices; 385ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef memcpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN); 386ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef memcpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN); 387ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 388476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (read_subdev) 389ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef devinfo.read_subdevice = read_subdev - dev->subdevices; 390476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman else 391ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef devinfo.read_subdevice = -1; 392476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman 393476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (write_subdev) 394ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef devinfo.write_subdevice = write_subdev - dev->subdevices; 395476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman else 396ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef devinfo.write_subdevice = -1; 397ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 398063db04b8901c5cf84c552a5053748d183d34e61Bill Pemberton if (copy_to_user(arg, &devinfo, sizeof(struct comedi_devinfo))) 399ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 400ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 401ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 402ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 403ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 404ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 405ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_SUBDINFO 406ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef subdevice info ioctl 407ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 408ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 409ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef pointer to array of subdevice info structures 410ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 411ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 412ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef none 413ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 414ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 415ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef array of subdevice info structures at arg 416ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 417ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 4180a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_subdinfo_ioctl(struct comedi_device *dev, 41992d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman struct comedi_subdinfo __user *arg, void *file) 420ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 421ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int ret, i; 422bd52efbbcc9f5d70c736b9b73c82aee149da1fe5Bill Pemberton struct comedi_subdinfo *tmp, *us; 42334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 424ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 4250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral tmp = 4260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral kcalloc(dev->n_subdevices, sizeof(struct comedi_subdinfo), 4270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral GFP_KERNEL); 428ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!tmp) 429ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENOMEM; 430ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 431ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* fill subdinfo structs */ 432ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef for (i = 0; i < dev->n_subdevices; i++) { 433ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + i; 434ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us = tmp + i; 435ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 436ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->type = s->type; 437ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->n_chan = s->n_chan; 438ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags = s->subdev_flags; 439ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (comedi_get_subdevice_runflags(s) & SRF_RUNNING) 440ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags |= SDF_RUNNING; 441ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#define TIMER_nanosec 5 /* backwards compatibility */ 442ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->timer_type = TIMER_nanosec; 443ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->len_chanlist = s->len_chanlist; 444ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->maxdata = s->maxdata; 445ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->range_table) { 446ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->range_type = 447476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman (i << 24) | (0 << 16) | (s->range_table->length); 448ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } else { 449ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->range_type = 0; /* XXX */ 450ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 451ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->flags = s->flags; 452ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 453ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy) 454ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags |= SDF_BUSY; 455ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy == file) 456ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags |= SDF_BUSY_OWNER; 457ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->lock) 458ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags |= SDF_LOCKED; 459ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->lock == file) 460ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags |= SDF_LOCK_OWNER; 461ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->maxdata && s->maxdata_list) 462ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags |= SDF_MAXDATA; 463ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->flaglist) 464ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags |= SDF_FLAGS; 465ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->range_table_list) 466ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags |= SDF_RANGETYPE; 467ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->do_cmd) 468ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags |= SDF_CMD; 469ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 470ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->insn_bits != &insn_inval) 471ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->insn_bits_support = COMEDI_SUPPORTED; 472ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef else 473ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->insn_bits_support = COMEDI_UNSUPPORTED; 474ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 475ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->settling_time_0 = s->settling_time_0; 476ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 477ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 478ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = copy_to_user(arg, tmp, 479bd52efbbcc9f5d70c736b9b73c82aee149da1fe5Bill Pemberton dev->n_subdevices * sizeof(struct comedi_subdinfo)); 480ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 481ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kfree(tmp); 482ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 483ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret ? -EFAULT : 0; 484ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 485ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 486ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 487ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_CHANINFO 488ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef subdevice info ioctl 489ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 490ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 491ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef pointer to chaninfo structure 492ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 493ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 494ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef chaninfo structure at arg 495ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 496ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 497ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arrays at elements of chaninfo structure 498ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 499ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 5000a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_chaninfo_ioctl(struct comedi_device *dev, 50192d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman struct comedi_chaninfo __user *arg) 502ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 50334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 504a18b416dc11ff9596ebf2012b1d15f485b951b28Bill Pemberton struct comedi_chaninfo it; 505ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 506a18b416dc11ff9596ebf2012b1d15f485b951b28Bill Pemberton if (copy_from_user(&it, arg, sizeof(struct comedi_chaninfo))) 507ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 508ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 509ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (it.subdev >= dev->n_subdevices) 510ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 511ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + it.subdev; 512ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 513ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (it.maxdata_list) { 514ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->maxdata || !s->maxdata_list) 515ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 516ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_to_user(it.maxdata_list, s->maxdata_list, 517790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton s->n_chan * sizeof(unsigned int))) 518ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 519ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 520ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 521ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (it.flaglist) { 522ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->flaglist) 523ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 524ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_to_user(it.flaglist, s->flaglist, 525476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman s->n_chan * sizeof(unsigned int))) 526ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 527ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 528ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 529ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (it.rangelist) { 530ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int i; 531ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 532ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->range_table_list) 533ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 534ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef for (i = 0; i < s->n_chan; i++) { 535ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int x; 536ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 537ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef x = (dev->minor << 28) | (it.subdev << 24) | (i << 16) | 538476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman (s->range_table_list[i]->length); 539ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef put_user(x, it.rangelist + i); 540ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 541476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#if 0 542476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (copy_to_user(it.rangelist, s->range_type_list, 5430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral s->n_chan * sizeof(unsigned int))) 544476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman return -EFAULT; 545476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#endif 546ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 547ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 548ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 549ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 550ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 551ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* 552ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_BUFINFO 553ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef buffer information ioctl 554ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 555ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 556ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef pointer to bufinfo structure 557ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 558ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 559ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bufinfo at arg 560ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 561ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 562ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef modified bufinfo at arg 563ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 564ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */ 56592d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_bufinfo_ioctl(struct comedi_device *dev, 56692d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman struct comedi_bufinfo __user *arg) 567ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 5689aa5339ac1eba5268df69bbcdf1abb9fae5afecaBill Pemberton struct comedi_bufinfo bi; 56934c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 570d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton struct comedi_async *async; 571ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 5729aa5339ac1eba5268df69bbcdf1abb9fae5afecaBill Pemberton if (copy_from_user(&bi, arg, sizeof(struct comedi_bufinfo))) 573ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 574ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 575ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (bi.subdevice >= dev->n_subdevices || bi.subdevice < 0) 576ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 577ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 578ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + bi.subdevice; 579ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async = s->async; 580ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 581ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!async) { 582ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("subdevice does not have async capability\n"); 583ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.buf_write_ptr = 0; 584ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.buf_read_ptr = 0; 585ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.buf_write_count = 0; 586ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.buf_read_count = 0; 587ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto copyback; 588ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 589ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 590ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)) { 591ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read); 592ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_buf_read_free(async, bi.bytes_read); 593ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 594ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | 595476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman SRF_RUNNING)) 596476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman && async->buf_write_count == async->buf_read_count) { 597ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef do_become_nonbusy(dev, s); 598ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 599ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 600ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 601ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (bi.bytes_written && (s->subdev_flags & SDF_CMD_WRITE)) { 602ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.bytes_written = 603476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_buf_write_alloc(async, bi.bytes_written); 604ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_buf_write_free(async, bi.bytes_written); 605ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 606ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 607ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.buf_write_count = async->buf_write_count; 608ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.buf_write_ptr = async->buf_write_ptr; 609ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.buf_read_count = async->buf_read_count; 610ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.buf_read_ptr = async->buf_read_ptr; 611ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 612476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancopyback: 6139aa5339ac1eba5268df69bbcdf1abb9fae5afecaBill Pemberton if (copy_to_user(arg, &bi, sizeof(struct comedi_bufinfo))) 614ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 615ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 616ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 617ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 618ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 6190a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, 6200a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int *data, void *file); 621ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 62220617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * COMEDI_INSNLIST 62320617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * synchronous instructions 624ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 62520617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * arg: 62620617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * pointer to sync cmd structure 627ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 62820617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * reads: 62920617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * sync cmd struct at arg 63020617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * instruction list 63120617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * data (for writes) 632ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 63320617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * writes: 63420617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * data (for reads) 635ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */ 636ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* arbitrary limits */ 637ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#define MAX_SAMPLES 256 63892d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_insnlist_ioctl(struct comedi_device *dev, 63992d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman struct comedi_insnlist __user *arg, void *file) 640ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 641da613f4fabb43b8bc551bb874792e1f22a698696Bill Pemberton struct comedi_insnlist insnlist; 64290035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton struct comedi_insn *insns = NULL; 643790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton unsigned int *data = NULL; 644ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int i = 0; 645ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int ret = 0; 646ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 647da613f4fabb43b8bc551bb874792e1f22a698696Bill Pemberton if (copy_from_user(&insnlist, arg, sizeof(struct comedi_insnlist))) 648ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 649ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 650790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL); 651ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!data) { 652ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("kmalloc failed\n"); 653ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -ENOMEM; 654ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 655ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 656ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 6570a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral insns = 6580a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral kmalloc(sizeof(struct comedi_insn) * insnlist.n_insns, GFP_KERNEL); 659ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!insns) { 660ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("kmalloc failed\n"); 661ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -ENOMEM; 662ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 663ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 664ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 665ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_from_user(insns, insnlist.insns, 66690035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton sizeof(struct comedi_insn) * insnlist.n_insns)) { 667ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("copy_from_user failed\n"); 668ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 669ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 670ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 671ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 672ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef for (i = 0; i < insnlist.n_insns; i++) { 673ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insns[i].n > MAX_SAMPLES) { 674ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("number of samples too large\n"); 675ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 676ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 677ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 678ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insns[i].insn & INSN_MASK_WRITE) { 679ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_from_user(data, insns[i].data, 680790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton insns[i].n * sizeof(unsigned int))) { 681ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("copy_from_user failed\n"); 682ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 683ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 684ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 685ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 686ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = parse_insn(dev, insns + i, data, file); 687ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (ret < 0) 688ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 689ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insns[i].insn & INSN_MASK_READ) { 690ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_to_user(insns[i].data, data, 691790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton insns[i].n * sizeof(unsigned int))) { 692ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("copy_to_user failed\n"); 693ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 694ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 695ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 696ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 697ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (need_resched()) 698ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef schedule(); 699ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 700ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 701476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanerror: 702476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman kfree(insns); 703476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman kfree(data); 704ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 705ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (ret < 0) 706ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 707ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return i; 708ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 709ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 7100a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int check_insn_config_length(struct comedi_insn *insn, 7110a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int *data) 712ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 713476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (insn->n < 1) 714476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman return -EINVAL; 715ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 716ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef switch (data[0]) { 717ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_DIO_OUTPUT: 718ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_DIO_INPUT: 719ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_DISARM: 720ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_RESET: 721ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->n == 1) 722ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 723ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 724ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_ARM: 725ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_DIO_QUERY: 726ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_BLOCK_SIZE: 727ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_FILTER: 728ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_SERIAL_CLOCK: 729ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_BIDIRECTIONAL_DATA: 730ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_ALT_SOURCE: 731ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_SET_COUNTER_MODE: 732ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_8254_READ_STATUS: 733ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_SET_ROUTING: 734ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_GET_ROUTING: 735ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_GET_PWM_STATUS: 736ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_PWM_SET_PERIOD: 737ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_PWM_GET_PERIOD: 738ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->n == 2) 739ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 740ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 741ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_SET_GATE_SRC: 742ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_GET_GATE_SRC: 743ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_SET_CLOCK_SRC: 744ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_GET_CLOCK_SRC: 745ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_SET_OTHER_SRC: 746ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_GET_COUNTER_STATUS: 747ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_PWM_SET_H_BRIDGE: 748ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_PWM_GET_H_BRIDGE: 749ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE: 750ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->n == 3) 751ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 752ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 753ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_PWM_OUTPUT: 754ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_ANALOG_TRIG: 755ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->n == 5) 756ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 757ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 7580a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral /* by default we allow the insn since we don't have checks for 7590a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral * all possible cases yet */ 760ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef default: 7613fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor printk(KERN_WARNING 7623fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor "comedi: no check for data length of config insn id " 7630a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral "%i is implemented.\n" 7640a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral " Add a check to %s in %s.\n" 7650a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral " Assuming n=%i is correct.\n", data[0], __func__, 7660a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral __FILE__, insn->n); 767ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 768ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 769ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 770ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 771ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 772ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 7730a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, 7740a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int *data, void *file) 775ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 77634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 777ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int ret = 0; 778ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int i; 779ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 780ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->insn & INSN_MASK_SPECIAL) { 781ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* a non-subdevice instruction */ 782ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 783ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef switch (insn->insn) { 784ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_GTOD: 785ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef { 786ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef struct timeval tv; 787ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 788ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->n != 2) { 789ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 790ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 791ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 792ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 793ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef do_gettimeofday(&tv); 794ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef data[0] = tv.tv_sec; 795ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef data[1] = tv.tv_usec; 796ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = 2; 797ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 798ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 799ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 800ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_WAIT: 801ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->n != 1 || data[0] >= 100000) { 802ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 803ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 804ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 805ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef udelay(data[0] / 1000); 806ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = 1; 807ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 808ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_INTTRIG: 809ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->n != 1) { 810ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 811ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 812ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 813ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->subdev >= dev->n_subdevices) { 814ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("%d not usable subdevice\n", 815ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef insn->subdev); 816ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 817ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 818ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 819ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + insn->subdev; 820ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->async) { 821ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("no async\n"); 822ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 823ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 824ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 825ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->async->inttrig) { 826ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("no inttrig\n"); 827ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EAGAIN; 828ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 829ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 830ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->async->inttrig(dev, s, insn->data[0]); 831ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (ret >= 0) 832ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = 1; 833ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 834ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef default: 835ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("invalid insn\n"); 836ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 837ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 838ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 839ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } else { 840ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* a subdevice instruction */ 841790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton unsigned int maxdata; 842ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 843ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->subdev >= dev->n_subdevices) { 844ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("subdevice %d out of range\n", insn->subdev); 845ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 846ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto out; 847ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 848ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + insn->subdev; 849ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 850ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->type == COMEDI_SUBD_UNUSED) { 851ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("%d not usable subdevice\n", insn->subdev); 852ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EIO; 853ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto out; 854ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 855ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 856ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* are we locked? (ioctl lock) */ 857ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->lock && s->lock != file) { 858ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("device locked\n"); 859ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EACCES; 860ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto out; 861ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 862ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 8630fd0ca75fd9eb0e9cde49c28ad227c2d8d049366Greg Kroah-Hartman ret = comedi_check_chanlist(s, 1, &insn->chanspec); 864476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (ret < 0) { 865ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 866ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("bad chanspec\n"); 867ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto out; 868ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 869ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 870ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy) { 871ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EBUSY; 872ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto out; 873ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 874ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* This looks arbitrary. It is. */ 875ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->busy = &parse_insn; 876ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef switch (insn->insn) { 877ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_READ: 878ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->insn_read(dev, s, insn, data); 879ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 880ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_WRITE: 881ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef maxdata = s->maxdata_list 882476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman ? s->maxdata_list[CR_CHAN(insn->chanspec)] 883476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman : s->maxdata; 884ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef for (i = 0; i < insn->n; ++i) { 885ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (data[i] > maxdata) { 886ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 887ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("bad data value(s)\n"); 888ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 889ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 890ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 891ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (ret == 0) 892ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->insn_write(dev, s, insn, data); 893ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 894ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_BITS: 895ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->n != 2) { 896ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 897ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 898ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 899ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->insn_bits(dev, s, insn, data); 900ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 901ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG: 902ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = check_insn_config_length(insn, data); 903ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (ret) 904ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 905ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->insn_config(dev, s, insn, data); 906ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 907ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef default: 908ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 909ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 910ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 911ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 912ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->busy = NULL; 913ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 914ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 915476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanout: 916ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 917ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 918ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 919ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 92020617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * COMEDI_INSN 92120617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * synchronous instructions 922ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 92320617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * arg: 92420617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * pointer to insn 925ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 92620617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * reads: 92720617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * struct comedi_insn struct at arg 92820617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * data (for writes) 929ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 93020617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * writes: 93120617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * data (for reads) 932ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */ 93392d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_insn_ioctl(struct comedi_device *dev, 93492d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman struct comedi_insn __user *arg, void *file) 935ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 93690035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton struct comedi_insn insn; 937790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton unsigned int *data = NULL; 938ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int ret = 0; 939ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 940790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL); 941ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!data) { 942ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -ENOMEM; 943ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 944ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 945ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 94690035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton if (copy_from_user(&insn, arg, sizeof(struct comedi_insn))) { 947ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 948ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 949ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 950ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 951ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* This is where the behavior of insn and insnlist deviate. */ 952ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn.n > MAX_SAMPLES) 953ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef insn.n = MAX_SAMPLES; 954ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn.insn & INSN_MASK_WRITE) { 9550a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral if (copy_from_user 9560a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral (data, insn.data, insn.n * sizeof(unsigned int))) { 957ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 958ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 959ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 960ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 961ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = parse_insn(dev, &insn, data, file); 962ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (ret < 0) 963ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 964ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn.insn & INSN_MASK_READ) { 96592d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman if (copy_to_user(insn.data, data, insn.n * sizeof(unsigned int))) { 966ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 967ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 968ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 969ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 970ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = insn.n; 971ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 972476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanerror: 973476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman kfree(data); 974ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 975ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 976ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 977ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 978181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartmanstatic void comedi_set_subdevice_runflags(struct comedi_subdevice *s, 979181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman unsigned mask, unsigned bits) 980181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman{ 981181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman unsigned long flags; 982181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman 983181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman spin_lock_irqsave(&s->spin_lock, flags); 984181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman s->runflags &= ~mask; 985181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman s->runflags |= (bits & mask); 986181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman spin_unlock_irqrestore(&s->spin_lock, flags); 987181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman} 988181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman 98992d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_cmd_ioctl(struct comedi_device *dev, 99092d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman struct comedi_cmd __user *cmd, void *file) 991ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 992ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton struct comedi_cmd user_cmd; 99334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 994d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton struct comedi_async *async; 995ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int ret = 0; 99692d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman unsigned int __user *chanlist_saver = NULL; 997ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 99892d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman if (copy_from_user(&user_cmd, cmd, sizeof(struct comedi_cmd))) { 999ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("bad cmd address\n"); 1000ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 1001ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1002476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman /* save user's chanlist pointer so it can be restored later */ 1003ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef chanlist_saver = user_cmd.chanlist; 1004ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1005ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (user_cmd.subdev >= dev->n_subdevices) { 1006ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("%d no such subdevice\n", user_cmd.subdev); 1007ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENODEV; 1008ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1009ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1010ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + user_cmd.subdev; 1011ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async = s->async; 1012ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1013ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->type == COMEDI_SUBD_UNUSED) { 1014ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("%d not valid subdevice\n", user_cmd.subdev); 1015ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EIO; 1016ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1017ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1018ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->do_cmd || !s->do_cmdtest || !s->async) { 1019ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("subdevice %i does not support commands\n", 1020ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd.subdev); 1021ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EIO; 1022ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1023ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1024ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* are we locked? (ioctl lock) */ 1025ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->lock && s->lock != file) { 1026ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("subdevice locked\n"); 1027ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EACCES; 1028ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1029ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1030ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* are we busy? */ 1031ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy) { 1032ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("subdevice busy\n"); 1033ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EBUSY; 1034ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1035ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->busy = file; 1036ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1037ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* make sure channel/gain list isn't too long */ 1038ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (user_cmd.chanlist_len > s->len_chanlist) { 1039ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("channel/gain list too long %u > %d\n", 1040ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd.chanlist_len, s->len_chanlist); 1041ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 1042ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1043ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1044ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1045ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* make sure channel/gain list isn't too short */ 1046ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (user_cmd.chanlist_len < 1) { 1047ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("channel/gain list too short %u < 1\n", 1048ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd.chanlist_len); 1049ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 1050ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1051ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1052ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1053476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman kfree(async->cmd.chanlist); 1054ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->cmd = user_cmd; 1055ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->cmd.data = NULL; 1056ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* load channel/gain list */ 1057ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->cmd.chanlist = 1058476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman kmalloc(async->cmd.chanlist_len * sizeof(int), GFP_KERNEL); 1059ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!async->cmd.chanlist) { 1060ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("allocation failed\n"); 1061ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -ENOMEM; 1062ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1063ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1064ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1065ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_from_user(async->cmd.chanlist, user_cmd.chanlist, 1066476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman async->cmd.chanlist_len * sizeof(int))) { 1067ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("fault reading chanlist\n"); 1068ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 1069ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1070ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1071ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1072ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* make sure each element in channel/gain list is valid */ 10730fd0ca75fd9eb0e9cde49c28ad227c2d8d049366Greg Kroah-Hartman ret = comedi_check_chanlist(s, async->cmd.chanlist_len, async->cmd.chanlist); 1074476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (ret < 0) { 1075ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("bad chanlist\n"); 1076ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1077ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1078ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1079ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->do_cmdtest(dev, s, &async->cmd); 1080ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1081ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (async->cmd.flags & TRIG_BOGUS || ret) { 1082ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("test returned %d\n", ret); 1083ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd = async->cmd; 1084476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman /* restore chanlist pointer before copying back */ 1085ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd.chanlist = chanlist_saver; 1086ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd.data = NULL; 108792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman if (copy_to_user(cmd, &user_cmd, sizeof(struct comedi_cmd))) { 1088ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("fault writing cmd\n"); 1089ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 1090ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1091ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1092ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EAGAIN; 1093ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1094ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1095ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1096ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!async->prealloc_bufsz) { 1097ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -ENOMEM; 1098ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("no buffer (?)\n"); 1099ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1100ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1101ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1102ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_reset_async_buf(async); 1103ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1104ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->cb_mask = 1105476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR | 1106476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman COMEDI_CB_OVERFLOW; 1107476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (async->cmd.flags & TRIG_WAKE_EOS) 1108ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->cb_mask |= COMEDI_CB_EOS; 1109ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1110ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING); 1111ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1112ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->do_cmd(dev, s); 1113ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (ret == 0) 1114ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 1115ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1116476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancleanup: 1117ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef do_become_nonbusy(dev, s); 1118ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1119ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 1120ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1121ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1122ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 1123ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_CMDTEST 1124ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef command testing ioctl 1125ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1126ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 1127ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef pointer to cmd structure 1128ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1129ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 1130ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef cmd structure at arg 1131ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef channel/range list 1132ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1133ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 1134ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef modified cmd structure at arg 1135ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1136ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 113792d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic int do_cmdtest_ioctl(struct comedi_device *dev, 113892d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman struct comedi_cmd __user *arg, void *file) 1139ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1140ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton struct comedi_cmd user_cmd; 114134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 1142ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int ret = 0; 1143ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned int *chanlist = NULL; 114492d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman unsigned int __user *chanlist_saver = NULL; 1145ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1146ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton if (copy_from_user(&user_cmd, arg, sizeof(struct comedi_cmd))) { 1147ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("bad cmd address\n"); 1148ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 1149ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1150476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman /* save user's chanlist pointer so it can be restored later */ 1151ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef chanlist_saver = user_cmd.chanlist; 1152ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1153ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (user_cmd.subdev >= dev->n_subdevices) { 1154ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("%d no such subdevice\n", user_cmd.subdev); 1155ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENODEV; 1156ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1157ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1158ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + user_cmd.subdev; 1159ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->type == COMEDI_SUBD_UNUSED) { 1160ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("%d not valid subdevice\n", user_cmd.subdev); 1161ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EIO; 1162ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1163ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1164ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->do_cmd || !s->do_cmdtest) { 1165ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("subdevice %i does not support commands\n", 1166ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd.subdev); 1167ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EIO; 1168ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1169ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1170ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* make sure channel/gain list isn't too long */ 1171ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (user_cmd.chanlist_len > s->len_chanlist) { 1172ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("channel/gain list too long %d > %d\n", 1173ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd.chanlist_len, s->len_chanlist); 1174ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 1175ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1176ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1177ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1178ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* load channel/gain list */ 1179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (user_cmd.chanlist) { 1180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef chanlist = 1181476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman kmalloc(user_cmd.chanlist_len * sizeof(int), GFP_KERNEL); 1182ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!chanlist) { 1183ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("allocation failed\n"); 1184ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -ENOMEM; 1185ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1186ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1187ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1188ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_from_user(chanlist, user_cmd.chanlist, 1189476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman user_cmd.chanlist_len * sizeof(int))) { 1190ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("fault reading chanlist\n"); 1191ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 1192ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1193ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1194ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1195ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* make sure each element in channel/gain list is valid */ 11960fd0ca75fd9eb0e9cde49c28ad227c2d8d049366Greg Kroah-Hartman ret = comedi_check_chanlist(s, user_cmd.chanlist_len, chanlist); 1197476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (ret < 0) { 1198ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("bad chanlist\n"); 1199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1200ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1201ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd.chanlist = chanlist; 1203ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1204ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1205ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->do_cmdtest(dev, s, &user_cmd); 1206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1207476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman /* restore chanlist pointer before copying back */ 1208ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd.chanlist = chanlist_saver; 1209ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1210ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton if (copy_to_user(arg, &user_cmd, sizeof(struct comedi_cmd))) { 1211ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("bad cmd address\n"); 1212ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 1213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1214ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1215476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancleanup: 1216476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman kfree(chanlist); 1217ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1218ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 1219ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1220ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1221ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 1222ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_LOCK 1223ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef lock subdevice 1224ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1225ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 1226ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef subdevice number 1227ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1228ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 1229ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef none 1230ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1231ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 1232ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef none 1233ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1234ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 1235ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 12360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_lock_ioctl(struct comedi_device *dev, unsigned int arg, 12370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral void *file) 1238ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1239ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int ret = 0; 1240ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned long flags; 124134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 1242ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1243ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (arg >= dev->n_subdevices) 1244ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 1245ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + arg; 1246ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 12475f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_lock_irqsave(&s->spin_lock, flags); 1248476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (s->busy || s->lock) 1249ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EBUSY; 1250476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman else 1251ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->lock = file; 12525f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_unlock_irqrestore(&s->spin_lock, flags); 1253ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1254ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (ret < 0) 1255ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 1256ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1257ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#if 0 1258ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->lock_f) 1259ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->lock_f(dev, s); 1260ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif 1261ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1262ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 1263ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1264ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1265ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 1266ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_UNLOCK 1267ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unlock subdevice 1268ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1269ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 1270ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef subdevice number 1271ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1272ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 1273ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef none 1274ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1275ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 1276ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef none 1277ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1278ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef This function isn't protected by the semaphore, since 1279ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef we already own the lock. 1280ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 12810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg, 12820a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral void *file) 1283ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 128434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 1285ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1286ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (arg >= dev->n_subdevices) 1287ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 1288ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + arg; 1289ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1290ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy) 1291ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EBUSY; 1292ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1293ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->lock && s->lock != file) 1294ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EACCES; 1295ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1296ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->lock == file) { 1297ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#if 0 1298ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->unlock) 1299ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->unlock(dev, s); 1300ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif 1301ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1302ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->lock = NULL; 1303ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1304ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1305ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 1306ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1307ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1308ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 1309ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_CANCEL 1310ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef cancel acquisition ioctl 1311ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1312ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 1313ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef subdevice number 1314ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1315ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 1316ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef nothing 1317ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1318ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 1319ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef nothing 1320ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1321ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 13220a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg, 13230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral void *file) 1324ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 132534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 1326ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1327ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (arg >= dev->n_subdevices) 1328ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 1329ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + arg; 1330ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->async == NULL) 1331ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 1332ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1333ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->lock && s->lock != file) 1334ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EACCES; 1335ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1336ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->busy) 1337ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 1338ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1339ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy != file) 1340ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EBUSY; 1341ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1342ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return do_cancel(dev, s); 1343ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1344ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1345ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 1346ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_POLL ioctl 1347ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef instructs driver to synchronize buffers 1348ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1349ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 1350ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef subdevice number 1351ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1352ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 1353ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef nothing 1354ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1355ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 1356ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef nothing 1357ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1358ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 13590a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_poll_ioctl(struct comedi_device *dev, unsigned int arg, 13600a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral void *file) 1361ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 136234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 1363ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1364ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (arg >= dev->n_subdevices) 1365ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 1366ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + arg; 1367ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1368ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->lock && s->lock != file) 1369ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EACCES; 1370ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1371ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->busy) 1372ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 1373ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1374ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy != file) 1375ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EBUSY; 1376ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1377ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->poll) 1378ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return s->poll(dev, s); 1379ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1380ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 1381ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1382ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 138334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s) 1384ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1385ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int ret = 0; 1386ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1387ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) && s->cancel) 1388ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->cancel(dev, s); 1389ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1390ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef do_become_nonbusy(dev, s); 1391ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1392ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 1393ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1394ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 139592d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic void comedi_unmap(struct vm_area_struct *area) 1396ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1397d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton struct comedi_async *async; 139871b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev; 1399ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1400ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async = area->vm_private_data; 1401ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef dev = async->subdevice->device; 1402ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1403ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_lock(&dev->mutex); 1404ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->mmap_count--; 1405ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 1406ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1407ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1408ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic struct vm_operations_struct comedi_vm_ops = { 14090a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .close = comedi_unmap, 1410ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}; 1411ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1412ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_mmap(struct file *file, struct vm_area_struct *vma) 1413ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1414ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef const unsigned minor = iminor(file->f_dentry->d_inode); 1415476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct comedi_device_file_info *dev_file_info = 1416476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_device_file_info(minor); 141771b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev = dev_file_info->device; 1418d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton struct comedi_async *async = NULL; 1419ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned long start = vma->vm_start; 1420ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned long size; 1421ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int n_pages; 1422ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int i; 1423ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int retval; 142434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 1425ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1426ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_lock(&dev->mutex); 1427ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!dev->attached) { 1428ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("no driver configured on comedi%i\n", dev->minor); 1429ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -ENODEV; 1430ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1431ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1432476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (vma->vm_flags & VM_WRITE) 1433ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = comedi_get_write_subdevice(dev_file_info); 1434476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman else 1435ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = comedi_get_read_subdevice(dev_file_info); 1436476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman 1437ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s == NULL) { 1438ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EINVAL; 1439ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1440ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1441ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async = s->async; 1442ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (async == NULL) { 1443ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EINVAL; 1444ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1445ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1446ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1447ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (vma->vm_pgoff != 0) { 1448ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("comedi: mmap() offset must be 0.\n"); 1449ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EINVAL; 1450ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1451ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1452ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1453ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef size = vma->vm_end - vma->vm_start; 1454ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (size > async->prealloc_bufsz) { 1455ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EFAULT; 1456ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1457ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1458ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (size & (~PAGE_MASK)) { 1459ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EFAULT; 1460ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1461ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1462ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1463ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef n_pages = size >> PAGE_SHIFT; 1464ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef for (i = 0; i < n_pages; ++i) { 1465ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (remap_pfn_range(vma, start, 14660a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral page_to_pfn(virt_to_page 14670a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral (async->buf_page_list 14680a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral [i].virt_addr)), PAGE_SIZE, 14690a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral PAGE_SHARED)) { 1470ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EAGAIN; 1471ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1472ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1473ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef start += PAGE_SIZE; 1474ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1475ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1476ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef vma->vm_ops = &comedi_vm_ops; 1477ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef vma->vm_private_data = async; 1478ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1479ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->mmap_count++; 1480ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1481ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = 0; 1482476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmandone: 1483ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 1484ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return retval; 1485ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1486ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 14870a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic unsigned int comedi_poll(struct file *file, poll_table * wait) 1488ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1489ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned int mask = 0; 1490ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef const unsigned minor = iminor(file->f_dentry->d_inode); 1491476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct comedi_device_file_info *dev_file_info = 1492476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_device_file_info(minor); 149371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev = dev_file_info->device; 149434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *read_subdev; 149534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *write_subdev; 1496ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1497ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_lock(&dev->mutex); 1498ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!dev->attached) { 1499ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("no driver configured on comedi%i\n", dev->minor); 1500ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 1501ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 1502ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1503ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1504ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mask = 0; 1505ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef read_subdev = comedi_get_read_subdevice(dev_file_info); 1506ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (read_subdev) { 1507ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef poll_wait(file, &read_subdev->async->wait_head, wait); 1508ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!read_subdev->busy 1509476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman || comedi_buf_read_n_available(read_subdev->async) > 0 1510476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman || !(comedi_get_subdevice_runflags(read_subdev) & 1511476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman SRF_RUNNING)) { 1512ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mask |= POLLIN | POLLRDNORM; 1513ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1514ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1515ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef write_subdev = comedi_get_write_subdevice(dev_file_info); 1516ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (write_subdev) { 1517ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef poll_wait(file, &write_subdev->async->wait_head, wait); 1518476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_buf_write_alloc(write_subdev->async, 1519476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman write_subdev->async->prealloc_bufsz); 1520ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!write_subdev->busy 1521476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman || !(comedi_get_subdevice_runflags(write_subdev) & 1522476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman SRF_RUNNING) 1523476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman || comedi_buf_write_n_allocated(write_subdev->async) >= 1524476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman bytes_per_sample(write_subdev->async->subdevice)) { 1525ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mask |= POLLOUT | POLLWRNORM; 1526ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1527ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1528ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1529ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 1530ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return mask; 1531ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1532ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 153392d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic ssize_t comedi_write(struct file *file, const char __user *buf, 153492d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartman size_t nbytes, loff_t *offset) 1535ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 153634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 1537d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton struct comedi_async *async; 1538ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int n, m, count = 0, retval = 0; 1539ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DECLARE_WAITQUEUE(wait, current); 1540ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef const unsigned minor = iminor(file->f_dentry->d_inode); 1541476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct comedi_device_file_info *dev_file_info = 1542476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_device_file_info(minor); 154371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev = dev_file_info->device; 1544ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1545ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!dev->attached) { 1546ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("no driver configured on comedi%i\n", dev->minor); 1547ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -ENODEV; 1548ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1549ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1550ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1551ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = comedi_get_write_subdevice(dev_file_info); 1552ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s == NULL) { 1553ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EIO; 1554ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1555ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1556ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async = s->async; 1557ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1558ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!nbytes) { 1559ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = 0; 1560ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1561ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1562ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->busy) { 1563ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = 0; 1564ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1565ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1566ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy != file) { 1567ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EACCES; 1568ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1569ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1570ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef add_wait_queue(&async->wait_head, &wait); 1571ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef while (nbytes > 0 && !retval) { 1572ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef set_current_state(TASK_INTERRUPTIBLE); 1573ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1574ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef n = nbytes; 1575ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1576ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef m = n; 1577476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (async->buf_write_ptr + m > async->prealloc_bufsz) 1578ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef m = async->prealloc_bufsz - async->buf_write_ptr; 1579ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_buf_write_alloc(async, async->prealloc_bufsz); 1580476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (m > comedi_buf_write_n_allocated(async)) 1581ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef m = comedi_buf_write_n_allocated(async); 1582ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (m < n) 1583ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef n = m; 1584ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1585ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (n == 0) { 1586ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) { 1587ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (comedi_get_subdevice_runflags(s) & 1588476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman SRF_ERROR) { 1589ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EPIPE; 1590ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } else { 1591ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = 0; 1592ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1593ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef do_become_nonbusy(dev, s); 1594ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1595ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1596ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (file->f_flags & O_NONBLOCK) { 1597ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EAGAIN; 1598ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1599ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1600ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (signal_pending(current)) { 1601ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -ERESTARTSYS; 1602ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1603ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1604ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef schedule(); 1605476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (!s->busy) 1606ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1607ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy != file) { 1608ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EACCES; 1609ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1610ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1611ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef continue; 1612ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1613ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1614ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef m = copy_from_user(async->prealloc_buf + async->buf_write_ptr, 1615476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman buf, n); 1616ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (m) { 1617ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef n -= m; 1618ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EFAULT; 1619ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1620ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_buf_write_free(async, n); 1621ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1622ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef count += n; 1623ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef nbytes -= n; 1624ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1625ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef buf += n; 1626ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; /* makes device work like a pipe */ 1627ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1628ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef set_current_state(TASK_RUNNING); 1629ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef remove_wait_queue(&async->wait_head, &wait); 1630ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1631ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefdone: 1632476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman return count ? count : retval; 1633ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1634ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 163592d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, 16366705b68d0be284e2f9949f3657ea65d426d0f988Andrea Gelmini loff_t *offset) 1637ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 163834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 1639d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton struct comedi_async *async; 1640ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int n, m, count = 0, retval = 0; 1641ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DECLARE_WAITQUEUE(wait, current); 1642ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef const unsigned minor = iminor(file->f_dentry->d_inode); 1643476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct comedi_device_file_info *dev_file_info = 1644476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_device_file_info(minor); 164571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev = dev_file_info->device; 1646ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1647ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!dev->attached) { 1648ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("no driver configured on comedi%i\n", dev->minor); 1649ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -ENODEV; 1650ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1651ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1652ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1653ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = comedi_get_read_subdevice(dev_file_info); 1654ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s == NULL) { 1655ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EIO; 1656ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1657ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1658ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async = s->async; 1659ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!nbytes) { 1660ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = 0; 1661ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1662ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1663ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->busy) { 1664ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = 0; 1665ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1666ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1667ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy != file) { 1668ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EACCES; 1669ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1670ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1671ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1672ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef add_wait_queue(&async->wait_head, &wait); 1673ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef while (nbytes > 0 && !retval) { 1674ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef set_current_state(TASK_INTERRUPTIBLE); 1675ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1676ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef n = nbytes; 1677ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1678ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef m = comedi_buf_read_n_available(async); 1679476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman /* printk("%d available\n",m); */ 1680476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (async->buf_read_ptr + m > async->prealloc_bufsz) 1681ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef m = async->prealloc_bufsz - async->buf_read_ptr; 1682476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman /* printk("%d contiguous\n",m); */ 1683ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (m < n) 1684ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef n = m; 1685ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1686ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (n == 0) { 1687ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) { 1688ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef do_become_nonbusy(dev, s); 1689ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (comedi_get_subdevice_runflags(s) & 1690476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman SRF_ERROR) { 1691ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EPIPE; 1692ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } else { 1693ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = 0; 1694ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1695ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1696ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1697ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (file->f_flags & O_NONBLOCK) { 1698ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EAGAIN; 1699ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1700ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1701ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (signal_pending(current)) { 1702ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -ERESTARTSYS; 1703ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1704ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1705ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef schedule(); 1706ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->busy) { 1707ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = 0; 1708ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1709ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1710ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy != file) { 1711ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EACCES; 1712ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1713ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1714ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef continue; 1715ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1716ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef m = copy_to_user(buf, async->prealloc_buf + 1717476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman async->buf_read_ptr, n); 1718ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (m) { 1719ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef n -= m; 1720ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EFAULT; 1721ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1722ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1723ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_buf_read_alloc(async, n); 1724ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_buf_read_free(async, n); 1725ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1726ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef count += n; 1727ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef nbytes -= n; 1728ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1729ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef buf += n; 1730ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; /* makes device work like a pipe */ 1731ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1732ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | SRF_RUNNING)) && 1733476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman async->buf_read_count - async->buf_write_count == 0) { 1734ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef do_become_nonbusy(dev, s); 1735ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1736ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef set_current_state(TASK_RUNNING); 1737ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef remove_wait_queue(&async->wait_head, &wait); 1738ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1739ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefdone: 1740476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman return count ? count : retval; 1741ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1742ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1743ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 1744ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef This function restores a subdevice to an idle state. 1745ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */ 174634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s) 1747ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1748d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton struct comedi_async *async = s->async; 1749ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1750ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_set_subdevice_runflags(s, SRF_RUNNING, 0); 1751ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (async) { 1752ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_reset_async_buf(async); 1753ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->inttrig = NULL; 1754ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } else { 1755476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman printk(KERN_ERR 1756476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman "BUG: (?) do_become_nonbusy called with async=0\n"); 1757ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1758ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1759ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->busy = NULL; 1760ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1761ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1762ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_open(struct inode *inode, struct file *file) 1763ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1764ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef const unsigned minor = iminor(inode); 1765476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct comedi_device_file_info *dev_file_info = 1766476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_device_file_info(minor); 17670a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral struct comedi_device *dev = 17680a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral dev_file_info ? dev_file_info->device : NULL; 1769979200719d35934367bbf97d9b7d22d5b5281ddaIan Abbott 1770ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (dev == NULL) { 1771ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("invalid minor number\n"); 1772ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENODEV; 1773ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1774ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1775ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* This is slightly hacky, but we want module autoloading 1776ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * to work for root. 1777ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * case: user opens device, attached -> ok 1778ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * case: user opens device, unattached, in_request_module=0 -> autoload 1779ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * case: user opens device, unattached, in_request_module=1 -> fail 1780ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * case: root opens device, attached -> ok 1781ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * case: root opens device, unattached, in_request_module=1 -> ok 1782ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * (typically called from modprobe) 1783ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * case: root opens device, unattached, in_request_module=0 -> autoload 1784ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 1785ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * The last could be changed to "-> ok", which would deny root 1786ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * autoloading. 1787ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */ 1788ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_lock(&dev->mutex); 1789ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (dev->attached) 1790ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto ok; 1791a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris if (!capable(CAP_NET_ADMIN) && dev->in_request_module) { 1792ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("in request module\n"); 1793ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 1794ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENODEV; 1795ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1796a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris if (capable(CAP_NET_ADMIN) && dev->in_request_module) 1797ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto ok; 1798ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1799ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef dev->in_request_module = 1; 1800ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1801ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef CONFIG_KMOD 1802ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 180356d92c60e6dc708541711e9de4993e7d527d08e8Ian Abbott request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor); 1804ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_lock(&dev->mutex); 1805ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif 1806ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1807ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef dev->in_request_module = 0; 1808ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1809a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris if (!dev->attached && !capable(CAP_NET_ADMIN)) { 1810a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris DPRINTK("not attached and not CAP_NET_ADMIN\n"); 1811ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 1812ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENODEV; 1813ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1814ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefok: 1815ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef __module_get(THIS_MODULE); 1816ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1817ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (dev->attached) { 1818ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!try_module_get(dev->driver->module)) { 1819ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef module_put(THIS_MODULE); 1820ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 1821ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENOSYS; 1822ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1823ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1824ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1825476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (dev->attached && dev->use_count == 0 && dev->open) 1826ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef dev->open(dev); 1827ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1828ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef dev->use_count++; 1829ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1830ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 1831ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1832ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 1833ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1834ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1835ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_close(struct inode *inode, struct file *file) 1836ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1837ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef const unsigned minor = iminor(inode); 1838476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct comedi_device_file_info *dev_file_info = 1839476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_device_file_info(minor); 184071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev = dev_file_info->device; 184134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s = NULL; 1842ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int i; 1843ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1844ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_lock(&dev->mutex); 1845ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1846ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (dev->subdevices) { 1847ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef for (i = 0; i < dev->n_subdevices; i++) { 1848ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + i; 1849ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1850476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (s->busy == file) 1851ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef do_cancel(dev, s); 1852476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (s->lock == file) 1853ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->lock = NULL; 1854ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1855ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1856476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (dev->attached && dev->use_count == 1 && dev->close) 1857ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef dev->close(dev); 1858ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1859ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef module_put(THIS_MODULE); 1860476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (dev->attached) 1861ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef module_put(dev->driver->module); 1862ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1863ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef dev->use_count--; 1864ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1865ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 1866ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1867476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (file->f_flags & FASYNC) 1868ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_fasync(-1, file, 0); 1869ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1870ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 1871ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1872ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1873ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_fasync(int fd, struct file *file, int on) 1874ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1875ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef const unsigned minor = iminor(file->f_dentry->d_inode); 1876476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct comedi_device_file_info *dev_file_info = 1877476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_device_file_info(minor); 1878476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman 187971b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev = dev_file_info->device; 1880ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1881ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return fasync_helper(fd, file, on, &dev->async_queue); 1882ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1883ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1884ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefconst struct file_operations comedi_fops = { 18850a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .owner = THIS_MODULE, 18860a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .unlocked_ioctl = comedi_unlocked_ioctl, 18870a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .compat_ioctl = comedi_compat_ioctl, 18880a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .open = comedi_open, 18890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .release = comedi_close, 18900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .read = comedi_read, 18910a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .write = comedi_write, 18920a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .mmap = comedi_mmap, 18930a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .poll = comedi_poll, 18940a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .fasync = comedi_fasync, 1895ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}; 1896ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1897476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstruct class *comedi_class; 1898ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic struct cdev comedi_cdev; 1899ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1900ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic void comedi_cleanup_legacy_minors(void) 1901ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1902ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned i; 1903476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman 19041dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porr for (i = 0; i < comedi_num_legacy_minors; i++) 1905ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_free_board_minor(i); 1906ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1907ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1908ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int __init comedi_init(void) 1909ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1910ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int i; 1911ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int retval; 1912ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1913476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman printk(KERN_INFO "comedi: version " COMEDI_RELEASE 1914476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman " - http://www.comedi.org\n"); 1915ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1916a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess if (comedi_num_legacy_minors < 0 || 1917a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) { 1918a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess printk(KERN_ERR "comedi: error: invalid value for module " 1919a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess "parameter \"comedi_num_legacy_minors\". Valid values " 1920a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess "are 0 through %i.\n", COMEDI_NUM_BOARD_MINORS); 1921a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess return -EINVAL; 1922a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess } 1923a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess 1924a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess /* 1925a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess * comedi is unusable if both comedi_autoconfig and 1926a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess * comedi_num_legacy_minors are zero, so we might as well adjust the 1927a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess * defaults in that case 1928a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess */ 1929a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess if (comedi_autoconfig == 0 && comedi_num_legacy_minors == 0) 1930a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess comedi_num_legacy_minors = 16; 1931a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess 1932476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman memset(comedi_file_info_table, 0, 1933476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS); 1934ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1935ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0), 1936476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman COMEDI_NUM_MINORS, "comedi"); 1937ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (retval) 1938ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EIO; 1939ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef cdev_init(&comedi_cdev, &comedi_fops); 1940ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_cdev.owner = THIS_MODULE; 1941ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kobject_set_name(&comedi_cdev.kobj, "comedi"); 1942ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) { 1943ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), 1944476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman COMEDI_NUM_MINORS); 1945ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EIO; 1946ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1947ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_class = class_create(THIS_MODULE, "comedi"); 1948ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (IS_ERR(comedi_class)) { 19493fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor printk(KERN_ERR "comedi: failed to create class"); 1950ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef cdev_del(&comedi_cdev); 1951ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), 1952476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman COMEDI_NUM_MINORS); 1953ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return PTR_ERR(comedi_class); 1954ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1955ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1956ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* XXX requires /proc interface */ 1957ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_proc_init(); 1958ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1959476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman /* create devices files for legacy/manual use */ 19601dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porr for (i = 0; i < comedi_num_legacy_minors; i++) { 1961ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int minor; 1962ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef minor = comedi_alloc_board_minor(NULL); 1963476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (minor < 0) { 1964ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_cleanup_legacy_minors(); 1965ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef cdev_del(&comedi_cdev); 1966ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), 1967476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman COMEDI_NUM_MINORS); 1968ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return minor; 1969ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1970ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1971ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1972ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 1973ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1974ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1975ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic void __exit comedi_cleanup(void) 1976ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1977ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int i; 1978ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1979ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_cleanup_legacy_minors(); 1980476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman for (i = 0; i < COMEDI_NUM_MINORS; ++i) 1981ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef BUG_ON(comedi_file_info_table[i]); 1982476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman 1983ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef class_destroy(comedi_class); 1984ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef cdev_del(&comedi_cdev); 1985ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS); 1986ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1987ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_proc_cleanup(); 1988ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1989ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1990ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefmodule_init(comedi_init); 1991ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefmodule_exit(comedi_cleanup); 1992ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 199371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonvoid comedi_error(const struct comedi_device *dev, const char *s) 1994ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 19953fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor printk(KERN_ERR "comedi%d: %s: %s\n", dev->minor, 19963fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor dev->driver->driver_name, s); 1997ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 199818736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL(comedi_error); 1999ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 200034c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid comedi_event(struct comedi_device *dev, struct comedi_subdevice *s) 2001ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 2002d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton struct comedi_async *async = s->async; 2003ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned runflags = 0; 2004ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned runflags_mask = 0; 2005ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2006476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman /* DPRINTK("comedi_event 0x%x\n",mask); */ 2007ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2008ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) == 0) 2009ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return; 2010ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 20110a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral if (s-> 20120a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | 20130a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral COMEDI_CB_OVERFLOW)) { 2014ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef runflags_mask |= SRF_RUNNING; 2015ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2016ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* remember if an error event has occured, so an error 2017ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * can be returned the next time the user does a read() */ 2018ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) { 2019ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef runflags_mask |= SRF_ERROR; 2020ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef runflags |= SRF_ERROR; 2021ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2022ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (runflags_mask) { 2023ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /*sets SRF_ERROR and SRF_RUNNING together atomically */ 2024ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_set_subdevice_runflags(s, runflags_mask, runflags); 2025ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2026ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2027ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (async->cb_mask & s->async->events) { 2028ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (comedi_get_subdevice_runflags(s) & SRF_USER) { 2029fcea115462c690ba09f9df7471d60dda0d86a4eaGreg Kroah-Hartman wake_up_interruptible(&async->wait_head); 20306705b68d0be284e2f9949f3657ea65d426d0f988Andrea Gelmini if (s->subdev_flags & SDF_CMD_READ) 20310a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral kill_fasync(&dev->async_queue, SIGIO, POLL_IN); 20326705b68d0be284e2f9949f3657ea65d426d0f988Andrea Gelmini if (s->subdev_flags & SDF_CMD_WRITE) 20330a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral kill_fasync(&dev->async_queue, SIGIO, POLL_OUT); 2034ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } else { 2035ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (async->cb_func) 2036ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->cb_func(s->async->events, async->cb_arg); 2037ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2038ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2039ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->async->events = 0; 2040ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 204118736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL(comedi_event); 2042ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 204334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonunsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s) 2044ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 2045ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned long flags; 2046ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned runflags; 2047ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 20485f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_lock_irqsave(&s->spin_lock, flags); 2049ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef runflags = s->runflags; 20505f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_unlock_irqrestore(&s->spin_lock, flags); 2051ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return runflags; 2052ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 205318736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL(comedi_get_subdevice_runflags); 2054ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 205571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int is_device_busy(struct comedi_device *dev) 2056ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 205734c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 2058ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int i; 2059ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2060ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!dev->attached) 2061ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 2062ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2063ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef for (i = 0; i < dev->n_subdevices; i++) { 2064ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + i; 2065ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy) 2066ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 1; 2067ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->async && s->async->mmap_count) 2068ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 1; 2069ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2070ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2071ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 2072ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 2073ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 207492d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic void comedi_device_init(struct comedi_device *dev) 2075ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 207671b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton memset(dev, 0, sizeof(struct comedi_device)); 2077ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef spin_lock_init(&dev->spinlock); 2078ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_init(&dev->mutex); 2079ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef dev->minor = -1; 2080ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 2081ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 208292d0127c9d249c078b0939050f25041ed37be7cdGreg Kroah-Hartmanstatic void comedi_device_cleanup(struct comedi_device *dev) 2083ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 2084476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (dev == NULL) 2085476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman return; 2086ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_lock(&dev->mutex); 2087ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_device_detach(dev); 2088ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 2089ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_destroy(&dev->mutex); 2090ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 2091ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2092ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefint comedi_alloc_board_minor(struct device *hardware_device) 2093ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 2094ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned long flags; 2095ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef struct comedi_device_file_info *info; 20960bfbbe8f09617247c87d3b626cbf007c423afff1Bill Pemberton struct device *csdev; 2097ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned i; 2098883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess int retval; 2099ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2100ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); 2101476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (info == NULL) 2102476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman return -ENOMEM; 210371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton info->device = kzalloc(sizeof(struct comedi_device), GFP_KERNEL); 2104476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (info->device == NULL) { 2105ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kfree(info); 2106ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENOMEM; 2107ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2108ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_device_init(info->device); 21095f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_lock_irqsave(&comedi_file_info_table_lock, flags); 2110476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) { 2111476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (comedi_file_info_table[i] == NULL) { 2112ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_file_info_table[i] = info; 2113ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 2114ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2115ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 21165f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); 2117476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (i == COMEDI_NUM_BOARD_MINORS) { 2118ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_device_cleanup(info->device); 2119ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kfree(info->device); 2120ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kfree(info); 21210a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral printk(KERN_ERR 212220617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere 21230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral "comedi: error: ran out of minor numbers for board device files.\n"); 2124ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EBUSY; 2125ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2126ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info->device->minor = i; 2127ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef csdev = COMEDI_DEVICE_CREATE(comedi_class, NULL, 2128476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman MKDEV(COMEDI_MAJOR, i), NULL, 2129476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman hardware_device, "comedi%i", i); 2130476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (!IS_ERR(csdev)) 2131ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info->device->class_dev = csdev; 2132883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess dev_set_drvdata(csdev, info); 2133883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb); 2134883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (retval) { 21350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral printk(KERN_ERR 21360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral "comedi: failed to create sysfs attribute file \"%s\".\n", 21370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral dev_attr_max_read_buffer_kb.attr.name); 2138883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess comedi_free_board_minor(i); 2139883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2140883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 2141883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess retval = device_create_file(csdev, &dev_attr_read_buffer_kb); 2142883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (retval) { 21430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral printk(KERN_ERR 21440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral "comedi: failed to create sysfs attribute file \"%s\".\n", 21450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral dev_attr_read_buffer_kb.attr.name); 2146883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess comedi_free_board_minor(i); 2147883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2148883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 2149883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb); 2150883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (retval) { 21510a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral printk(KERN_ERR 21520a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral "comedi: failed to create sysfs attribute file \"%s\".\n", 21530a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral dev_attr_max_write_buffer_kb.attr.name); 2154883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess comedi_free_board_minor(i); 2155883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2156883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 2157883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess retval = device_create_file(csdev, &dev_attr_write_buffer_kb); 2158883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (retval) { 21590a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral printk(KERN_ERR 21600a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral "comedi: failed to create sysfs attribute file \"%s\".\n", 21610a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral dev_attr_write_buffer_kb.attr.name); 2162883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess comedi_free_board_minor(i); 2163883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2164883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 2165ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return i; 2166ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 2167ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2168ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefvoid comedi_free_board_minor(unsigned minor) 2169ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 2170ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned long flags; 2171ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef struct comedi_device_file_info *info; 2172ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2173ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS); 21745f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_lock_irqsave(&comedi_file_info_table_lock, flags); 2175ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info = comedi_file_info_table[minor]; 2176ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_file_info_table[minor] = NULL; 21775f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); 2178ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2179476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (info) { 218071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev = info->device; 2181476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (dev) { 2182476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (dev->class_dev) { 2183476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman device_destroy(comedi_class, 2184476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman MKDEV(COMEDI_MAJOR, dev->minor)); 2185ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2186ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_device_cleanup(dev); 2187ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kfree(dev); 2188ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2189ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kfree(info); 2190ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2191ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 2192ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2193883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessint comedi_alloc_subdevice_minor(struct comedi_device *dev, 2194883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_subdevice *s) 2195ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 2196ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned long flags; 2197ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef struct comedi_device_file_info *info; 21980bfbbe8f09617247c87d3b626cbf007c423afff1Bill Pemberton struct device *csdev; 2199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned i; 2200883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess int retval; 2201ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); 2203476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (info == NULL) 2204476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman return -ENOMEM; 2205ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info->device = dev; 2206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info->read_subdevice = s; 2207ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info->write_subdevice = s; 22085f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_lock_irqsave(&comedi_file_info_table_lock, flags); 22094c41f3ae3bf0bcc53f259b657c2fbc3961ff2b8aFrank Mori Hess for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) { 2210476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (comedi_file_info_table[i] == NULL) { 2211ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_file_info_table[i] = info; 2212ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 2213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2214ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 22155f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); 2216476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (i == COMEDI_NUM_MINORS) { 2217ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kfree(info); 22180a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral printk(KERN_ERR 22190a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral "comedi: error: ran out of minor numbers for board device files.\n"); 2220ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EBUSY; 2221ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2222ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->minor = i; 2223ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef csdev = COMEDI_DEVICE_CREATE(comedi_class, dev->class_dev, 2224476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman MKDEV(COMEDI_MAJOR, i), NULL, NULL, 2225476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman "comedi%i_subd%i", dev->minor, 2226476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman (int)(s - dev->subdevices)); 2227476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (!IS_ERR(csdev)) 2228ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->class_dev = csdev; 2229883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess dev_set_drvdata(csdev, info); 2230883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb); 2231883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (retval) { 22320a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral printk(KERN_ERR 22330a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral "comedi: failed to create sysfs attribute file \"%s\".\n", 22340a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral dev_attr_max_read_buffer_kb.attr.name); 2235883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess comedi_free_subdevice_minor(s); 2236883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2237883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 2238883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess retval = device_create_file(csdev, &dev_attr_read_buffer_kb); 2239883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (retval) { 22400a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral printk(KERN_ERR 22410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral "comedi: failed to create sysfs attribute file \"%s\".\n", 22420a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral dev_attr_read_buffer_kb.attr.name); 2243883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess comedi_free_subdevice_minor(s); 2244883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2245883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 2246883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb); 2247883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (retval) { 22480a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral printk(KERN_ERR 22490a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral "comedi: failed to create sysfs attribute file \"%s\".\n", 22500a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral dev_attr_max_write_buffer_kb.attr.name); 2251883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess comedi_free_subdevice_minor(s); 2252883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2253883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 2254883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess retval = device_create_file(csdev, &dev_attr_write_buffer_kb); 2255883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (retval) { 22560a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral printk(KERN_ERR 22570a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral "comedi: failed to create sysfs attribute file \"%s\".\n", 22580a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral dev_attr_write_buffer_kb.attr.name); 2259883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess comedi_free_subdevice_minor(s); 2260883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2261883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 2262ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return i; 2263ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 2264ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 226534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid comedi_free_subdevice_minor(struct comedi_subdevice *s) 2266ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 2267ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned long flags; 2268ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef struct comedi_device_file_info *info; 2269ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2270476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (s == NULL) 2271476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman return; 2272476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (s->minor < 0) 2273476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman return; 2274ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2275ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef BUG_ON(s->minor >= COMEDI_NUM_MINORS); 2276ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR); 2277ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 22785f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_lock_irqsave(&comedi_file_info_table_lock, flags); 2279ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info = comedi_file_info_table[s->minor]; 2280ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_file_info_table[s->minor] = NULL; 22815f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); 2282ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2283476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (s->class_dev) { 2284ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor)); 2285ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->class_dev = NULL; 2286ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2287ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kfree(info); 2288ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 2289ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2290ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstruct comedi_device_file_info *comedi_get_device_file_info(unsigned minor) 2291ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 2292ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned long flags; 2293ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef struct comedi_device_file_info *info; 2294ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2295ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef BUG_ON(minor >= COMEDI_NUM_MINORS); 22965f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_lock_irqsave(&comedi_file_info_table_lock, flags); 2297ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info = comedi_file_info_table[minor]; 22985f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); 2299ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return info; 2300ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 230118736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL_GPL(comedi_get_device_file_info); 2302883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2303883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic int resize_async_buffer(struct comedi_device *dev, 2304883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_subdevice *s, 2305883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_async *async, unsigned new_size) 2306883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{ 2307883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess int retval; 2308883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2309883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (new_size > async->max_bufsize) 2310883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EPERM; 2311883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2312883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (s->busy) { 2313883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess DPRINTK("subdevice is busy, cannot resize buffer\n"); 2314883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EBUSY; 2315883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 2316883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (async->mmap_count) { 2317883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess DPRINTK("subdevice is mmapped, cannot resize buffer\n"); 2318883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EBUSY; 2319883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 2320883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2321883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (!async->prealloc_buf) 2322883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 2323883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2324883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess /* make sure buffer is an integral number of pages 23250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral * (we round up) */ 2326883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK; 2327883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2328883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess retval = comedi_buf_alloc(dev, s, new_size); 2329883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (retval < 0) 2330883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2331883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2332883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (s->buf_change) { 2333883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess retval = s->buf_change(dev, s, new_size); 2334883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (retval < 0) 2335883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2336883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 2337883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2338883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess DPRINTK("comedi%i subd %d buffer resized to %i bytes\n", 2339b8b5cd9f87e08f72c78d9197bf199821fda4ba36Ian Abbott dev->minor, (int)(s - dev->subdevices), async->prealloc_bufsz); 2340883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return 0; 2341883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess} 2342883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2343883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess/* sysfs attribute files */ 2344883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2345883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic const unsigned bytes_per_kibi = 1024; 2346883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2347883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_max_read_buffer_kb(struct device *dev, 2348883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct device_attribute *attr, char *buf) 2349883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{ 2350883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess ssize_t retval; 2351883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_device_file_info *info = dev_get_drvdata(dev); 2352883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess unsigned max_buffer_size_kb = 0; 2353883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_subdevice *const read_subdevice = 23540a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral comedi_get_read_subdevice(info); 2355883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2356883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_lock(&info->device->mutex); 2357883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (read_subdevice && 2358883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess (read_subdevice->subdev_flags & SDF_CMD_READ) && 2359883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess read_subdevice->async) { 2360883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess max_buffer_size_kb = read_subdevice->async->max_bufsize / 23610a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral bytes_per_kibi; 2362883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 23630a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb); 2364883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_unlock(&info->device->mutex); 2365883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2366883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2367883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess} 2368883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2369883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_max_read_buffer_kb(struct device *dev, 2370883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct device_attribute *attr, 2371883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess const char *buf, size_t count) 2372883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{ 2373883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_device_file_info *info = dev_get_drvdata(dev); 2374883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess unsigned long new_max_size_kb; 2375883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess uint64_t new_max_size; 2376883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_subdevice *const read_subdevice = 23770a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral comedi_get_read_subdevice(info); 2378883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2379883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (strict_strtoul(buf, 10, &new_max_size_kb)) 2380883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 23810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral if (new_max_size_kb != (uint32_t) new_max_size_kb) 2382883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 23830a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral new_max_size = ((uint64_t) new_max_size_kb) * bytes_per_kibi; 23840a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral if (new_max_size != (uint32_t) new_max_size) 2385883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 2386883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2387883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_lock(&info->device->mutex); 2388883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (read_subdevice == NULL || 2389883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 || 2390883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess read_subdevice->async == NULL) { 2391883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_unlock(&info->device->mutex); 2392883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 2393883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 2394883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess read_subdevice->async->max_bufsize = new_max_size; 2395883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_unlock(&info->device->mutex); 2396883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2397883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return count; 2398883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess} 2399883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2400883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_max_read_buffer_kb = { 2401883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess .attr = { 24020a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .name = "max_read_buffer_kb", 24030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .mode = S_IRUGO | S_IWUSR}, 2404883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess .show = &show_max_read_buffer_kb, 2405883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess .store = &store_max_read_buffer_kb 2406883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}; 2407883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2408883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_read_buffer_kb(struct device *dev, 2409883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct device_attribute *attr, char *buf) 2410883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{ 2411883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess ssize_t retval; 2412883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_device_file_info *info = dev_get_drvdata(dev); 2413883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess unsigned buffer_size_kb = 0; 2414883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_subdevice *const read_subdevice = 24150a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral comedi_get_read_subdevice(info); 2416883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2417883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_lock(&info->device->mutex); 2418883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (read_subdevice && 24190a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral (read_subdevice->subdev_flags & SDF_CMD_READ) && 24200a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral read_subdevice->async) { 2421883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess buffer_size_kb = read_subdevice->async->prealloc_bufsz / 24220a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral bytes_per_kibi; 2423883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 24240a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb); 2425883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_unlock(&info->device->mutex); 2426883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2427883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2428883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess} 2429883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2430883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_read_buffer_kb(struct device *dev, 2431883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct device_attribute *attr, 2432883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess const char *buf, size_t count) 2433883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{ 2434883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_device_file_info *info = dev_get_drvdata(dev); 2435883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess unsigned long new_size_kb; 2436883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess uint64_t new_size; 2437883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess int retval; 2438883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_subdevice *const read_subdevice = 24390a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral comedi_get_read_subdevice(info); 2440883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2441883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (strict_strtoul(buf, 10, &new_size_kb)) 2442883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 24430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral if (new_size_kb != (uint32_t) new_size_kb) 2444883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 24450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral new_size = ((uint64_t) new_size_kb) * bytes_per_kibi; 24460a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral if (new_size != (uint32_t) new_size) 2447883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 2448883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2449883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_lock(&info->device->mutex); 2450883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (read_subdevice == NULL || 2451883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 || 2452883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess read_subdevice->async == NULL) { 2453883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_unlock(&info->device->mutex); 2454883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 2455883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 2456883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess retval = resize_async_buffer(info->device, read_subdevice, 2457883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess read_subdevice->async, new_size); 2458883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_unlock(&info->device->mutex); 2459883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2460883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (retval < 0) 2461883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2462883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return count; 2463883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess} 2464883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2465883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_read_buffer_kb = { 2466883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess .attr = { 24670a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .name = "read_buffer_kb", 24680a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .mode = S_IRUGO | S_IWUSR | S_IWGRP}, 2469883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess .show = &show_read_buffer_kb, 2470883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess .store = &store_read_buffer_kb 2471883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}; 2472883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2473883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_max_write_buffer_kb(struct device *dev, 2474883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct device_attribute *attr, 2475883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess char *buf) 2476883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{ 2477883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess ssize_t retval; 2478883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_device_file_info *info = dev_get_drvdata(dev); 2479883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess unsigned max_buffer_size_kb = 0; 2480883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_subdevice *const write_subdevice = 24810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral comedi_get_write_subdevice(info); 2482883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2483883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_lock(&info->device->mutex); 2484883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (write_subdevice && 2485883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess (write_subdevice->subdev_flags & SDF_CMD_WRITE) && 2486883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess write_subdevice->async) { 2487883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess max_buffer_size_kb = write_subdevice->async->max_bufsize / 24880a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral bytes_per_kibi; 2489883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 24900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb); 2491883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_unlock(&info->device->mutex); 2492883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2493883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2494883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess} 2495883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2496883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_max_write_buffer_kb(struct device *dev, 2497883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct device_attribute *attr, 2498883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess const char *buf, size_t count) 2499883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{ 2500883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_device_file_info *info = dev_get_drvdata(dev); 2501883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess unsigned long new_max_size_kb; 2502883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess uint64_t new_max_size; 2503883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_subdevice *const write_subdevice = 25040a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral comedi_get_write_subdevice(info); 2505883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2506883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (strict_strtoul(buf, 10, &new_max_size_kb)) 2507883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 25080a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral if (new_max_size_kb != (uint32_t) new_max_size_kb) 2509883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 25100a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral new_max_size = ((uint64_t) new_max_size_kb) * bytes_per_kibi; 25110a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral if (new_max_size != (uint32_t) new_max_size) 2512883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 2513883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2514883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_lock(&info->device->mutex); 2515883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (write_subdevice == NULL || 2516883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 || 2517883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess write_subdevice->async == NULL) { 2518883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_unlock(&info->device->mutex); 2519883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 2520883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 2521883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess write_subdevice->async->max_bufsize = new_max_size; 2522883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_unlock(&info->device->mutex); 2523883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2524883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return count; 2525883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess} 2526883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2527883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_max_write_buffer_kb = { 2528883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess .attr = { 25290a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .name = "max_write_buffer_kb", 25300a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .mode = S_IRUGO | S_IWUSR}, 2531883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess .show = &show_max_write_buffer_kb, 2532883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess .store = &store_max_write_buffer_kb 2533883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}; 2534883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2535883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_write_buffer_kb(struct device *dev, 2536883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct device_attribute *attr, char *buf) 2537883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{ 2538883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess ssize_t retval; 2539883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_device_file_info *info = dev_get_drvdata(dev); 2540883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess unsigned buffer_size_kb = 0; 2541883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_subdevice *const write_subdevice = 25420a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral comedi_get_write_subdevice(info); 2543883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2544883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_lock(&info->device->mutex); 2545883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (write_subdevice && 2546883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess (write_subdevice->subdev_flags & SDF_CMD_WRITE) && 2547883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess write_subdevice->async) { 2548883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess buffer_size_kb = write_subdevice->async->prealloc_bufsz / 25490a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral bytes_per_kibi; 2550883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 25510a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb); 2552883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_unlock(&info->device->mutex); 2553883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2554883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2555883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess} 2556883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2557883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_write_buffer_kb(struct device *dev, 2558883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct device_attribute *attr, 2559883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess const char *buf, size_t count) 2560883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{ 2561883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_device_file_info *info = dev_get_drvdata(dev); 2562883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess unsigned long new_size_kb; 2563883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess uint64_t new_size; 2564883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess int retval; 2565883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_subdevice *const write_subdevice = 25660a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral comedi_get_write_subdevice(info); 2567883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2568883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (strict_strtoul(buf, 10, &new_size_kb)) 2569883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 25700a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral if (new_size_kb != (uint32_t) new_size_kb) 2571883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 25720a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral new_size = ((uint64_t) new_size_kb) * bytes_per_kibi; 25730a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral if (new_size != (uint32_t) new_size) 2574883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 2575883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2576883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_lock(&info->device->mutex); 2577883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (write_subdevice == NULL || 2578883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 || 2579883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess write_subdevice->async == NULL) { 2580883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_unlock(&info->device->mutex); 2581883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 2582883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 2583883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess retval = resize_async_buffer(info->device, write_subdevice, 25840a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral write_subdevice->async, new_size); 2585883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_unlock(&info->device->mutex); 2586883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2587883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (retval < 0) 2588883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2589883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return count; 2590883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess} 2591883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2592883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_write_buffer_kb = { 2593883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess .attr = { 25940a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .name = "write_buffer_kb", 25950a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .mode = S_IRUGO | S_IWUSR | S_IWGRP}, 2596883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess .show = &show_write_buffer_kb, 2597883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess .store = &store_write_buffer_kb 2598883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}; 2599