comedi_fops.c revision 242e7ad91a067243d7ab63b6a25ed2e085733446
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 676705b68d0be284e2f9949f3657ea65d426d0f988Andrea Gelminiint 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, 750a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral struct comedi_devconfig *arg); 7671b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_bufconfig_ioctl(struct comedi_device *dev, void *arg); 770a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_devinfo_ioctl(struct comedi_device *dev, 780a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral struct comedi_devinfo *arg, struct file *file); 790a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_subdinfo_ioctl(struct comedi_device *dev, 800a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral struct comedi_subdinfo *arg, void *file); 810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_chaninfo_ioctl(struct comedi_device *dev, 820a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral struct comedi_chaninfo *arg); 8371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_bufinfo_ioctl(struct comedi_device *dev, void *arg); 8471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_cmd_ioctl(struct comedi_device *dev, void *arg, void *file); 850a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_lock_ioctl(struct comedi_device *dev, unsigned int arg, 860a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral void *file); 870a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg, 880a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral void *file); 890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg, 900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral void *file); 9171b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_cmdtest_ioctl(struct comedi_device *dev, void *arg, void *file); 9271b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_insnlist_ioctl(struct comedi_device *dev, void *arg, void *file); 9371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_insn_ioctl(struct comedi_device *dev, void *arg, void *file); 940a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_poll_ioctl(struct comedi_device *dev, unsigned int subd, 950a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral void *file); 9671b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton 970a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralextern void do_become_nonbusy(struct comedi_device *dev, 980a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral struct comedi_subdevice *s); 9934c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s); 100ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 101ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_fasync(int fd, struct file *file, int on); 102ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 10371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int is_device_busy(struct comedi_device *dev); 104883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic int resize_async_buffer(struct comedi_device *dev, 105883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_subdevice *s, 106883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_async *async, unsigned new_size); 107883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 108883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess/* declarations for sysfs attribute files */ 109883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_max_read_buffer_kb; 110883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_read_buffer_kb; 111883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_max_write_buffer_kb; 112883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_write_buffer_kb; 113ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 114ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, 115476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman unsigned long arg) 116ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 117ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef const unsigned minor = iminor(file->f_dentry->d_inode); 118476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct comedi_device_file_info *dev_file_info = 119476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_device_file_info(minor); 12071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev; 121ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int rc; 122ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 12353b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess if (dev_file_info == NULL || dev_file_info->device == NULL) 12453b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess return -ENODEV; 12553b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess dev = dev_file_info->device; 12653b670a75bef4bf6484bbf6ca6a896c365676fd4Frank Mori Hess 127ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_lock(&dev->mutex); 128ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 129ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* Device config is special, because it must work on 130ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * an unconfigured device. */ 131ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (cmd == COMEDI_DEVCONFIG) { 132ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_devconfig_ioctl(dev, (void *)arg); 133ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 134ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 135ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 136ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!dev->attached) { 137ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("no driver configured on /dev/comedi%i\n", dev->minor); 138ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = -ENODEV; 139ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 140ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 141ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 142ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef switch (cmd) { 143ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_BUFCONFIG: 144ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_bufconfig_ioctl(dev, (void *)arg); 145ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 146ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_DEVINFO: 147ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_devinfo_ioctl(dev, (void *)arg, file); 148ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 149ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_SUBDINFO: 150ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_subdinfo_ioctl(dev, (void *)arg, file); 151ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 152ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_CHANINFO: 153ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_chaninfo_ioctl(dev, (void *)arg); 154ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 155ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_RANGEINFO: 156ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_rangeinfo_ioctl(dev, (void *)arg); 157ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 158ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_BUFINFO: 159ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_bufinfo_ioctl(dev, (void *)arg); 160ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 161ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_LOCK: 162ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_lock_ioctl(dev, arg, file); 163ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 164ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_UNLOCK: 165ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_unlock_ioctl(dev, arg, file); 166ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 167ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_CANCEL: 168ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_cancel_ioctl(dev, arg, file); 169ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 170ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_CMD: 171ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_cmd_ioctl(dev, (void *)arg, file); 172ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 173ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_CMDTEST: 174ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_cmdtest_ioctl(dev, (void *)arg, file); 175ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 176ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_INSNLIST: 177ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_insnlist_ioctl(dev, (void *)arg, file); 178ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_INSN: 180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_insn_ioctl(dev, (void *)arg, file); 181ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 182ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case COMEDI_POLL: 183ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = do_poll_ioctl(dev, arg, file); 184ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 185ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef default: 186ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef rc = -ENOTTY; 187ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 188ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 189ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 190476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmandone: 191ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 192ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return rc; 193ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 194ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 195ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 196ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_DEVCONFIG 197ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef device config ioctl 198ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 200ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef pointer to devconfig structure 201ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 202ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 203ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef devconfig structure at arg 204ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 205ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef none 207ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 2080a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_devconfig_ioctl(struct comedi_device *dev, 2090a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral struct comedi_devconfig *arg) 210ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 2110707bb04be89b18ee83b5a997e36cc585f0b988dBill Pemberton struct comedi_devconfig it; 212ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int ret; 213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned char *aux_data = NULL; 214ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int aux_len; 215ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 216ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!capable(CAP_SYS_ADMIN)) 217ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EPERM; 218ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 219ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (arg == NULL) { 220ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (is_device_busy(dev)) 221ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EBUSY; 222476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (dev->attached) { 223ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef struct module *driver_module = dev->driver->module; 224ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_device_detach(dev); 225ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef module_put(driver_module); 226ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 227ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 228ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 229ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2300707bb04be89b18ee83b5a997e36cc585f0b988dBill Pemberton if (copy_from_user(&it, arg, sizeof(struct comedi_devconfig))) 231ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 232ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 233ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef it.board_name[COMEDI_NAMELEN - 1] = 0; 234ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 235ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (comedi_aux_data(it.options, 0) && 236476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) { 237ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int bit_shift; 238ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef aux_len = it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]; 239ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (aux_len < 0) 240ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 241ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 242ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef aux_data = vmalloc(aux_len); 243ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!aux_data) 244ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENOMEM; 245ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 246ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_from_user(aux_data, 247476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_aux_data(it.options, 0), aux_len)) { 248ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef vfree(aux_data); 249ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 250ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 251ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef it.options[COMEDI_DEVCONF_AUX_DATA_LO] = 252476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman (unsigned long)aux_data; 253ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (sizeof(void *) > sizeof(int)) { 254ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bit_shift = sizeof(int) * 8; 255ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef it.options[COMEDI_DEVCONF_AUX_DATA_HI] = 256476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman ((unsigned long)aux_data) >> bit_shift; 257ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } else 258ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef it.options[COMEDI_DEVCONF_AUX_DATA_HI] = 0; 259ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 260ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 261ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = comedi_device_attach(dev, &it); 262476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (ret == 0) { 263476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (!try_module_get(dev->driver->module)) { 264ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_device_detach(dev); 265ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENOSYS; 266ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 267ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 268ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 269ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (aux_data) 270ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef vfree(aux_data); 271ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 272ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 273ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 274ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 275ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 276ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_BUFCONFIG 277ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef buffer configuration ioctl 278ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 279ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 280ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef pointer to bufconfig structure 281ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 282ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 283ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bufconfig at arg 284ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 285ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 286ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef modified bufconfig at arg 287ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 288ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 28971b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_bufconfig_ioctl(struct comedi_device *dev, void *arg) 290ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 291be6aba4a423629126f318d351b2d0eb00abb9dd5Bill Pemberton struct comedi_bufconfig bc; 292d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton struct comedi_async *async; 29334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 294883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess int retval = 0; 295ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 296be6aba4a423629126f318d351b2d0eb00abb9dd5Bill Pemberton if (copy_from_user(&bc, arg, sizeof(struct comedi_bufconfig))) 297ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 298ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 299ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (bc.subdevice >= dev->n_subdevices || bc.subdevice < 0) 300ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 301ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 302ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + bc.subdevice; 303ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async = s->async; 304ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 305ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!async) { 306ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("subdevice does not have async capability\n"); 307ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bc.size = 0; 308ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bc.maximum_size = 0; 309ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto copyback; 310ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 311ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 312ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (bc.maximum_size) { 313ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!capable(CAP_SYS_ADMIN)) 314ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EPERM; 315ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 316ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->max_bufsize = bc.maximum_size; 317ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 318ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 319ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (bc.size) { 320883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess retval = resize_async_buffer(dev, s, async, bc.size); 321883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (retval < 0) 322883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 323ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 324ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 325ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bc.size = async->prealloc_bufsz; 326ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bc.maximum_size = async->max_bufsize; 327ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 328476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancopyback: 329be6aba4a423629126f318d351b2d0eb00abb9dd5Bill Pemberton if (copy_to_user(arg, &bc, sizeof(struct comedi_bufconfig))) 330ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 331ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 332ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 333ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 334ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 335ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 336ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_DEVINFO 337ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef device info ioctl 338ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 339ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 340ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef pointer to devinfo structure 341ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 342ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 343ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef none 344ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 345ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 346ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef devinfo structure 347ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 348ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 3490a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_devinfo_ioctl(struct comedi_device *dev, 3500a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral struct comedi_devinfo *arg, struct file *file) 351ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 352063db04b8901c5cf84c552a5053748d183d34e61Bill Pemberton struct comedi_devinfo devinfo; 353ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef const unsigned minor = iminor(file->f_dentry->d_inode); 354476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct comedi_device_file_info *dev_file_info = 355476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_device_file_info(minor); 35634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *read_subdev = 357476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_read_subdevice(dev_file_info); 35834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *write_subdev = 359476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_write_subdevice(dev_file_info); 360ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 361ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef memset(&devinfo, 0, sizeof(devinfo)); 362ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 363ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* fill devinfo structure */ 364ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef devinfo.version_code = COMEDI_VERSION_CODE; 365ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef devinfo.n_subdevs = dev->n_subdevices; 366ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef memcpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN); 367ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef memcpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN); 368ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 369476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (read_subdev) 370ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef devinfo.read_subdevice = read_subdev - dev->subdevices; 371476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman else 372ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef devinfo.read_subdevice = -1; 373476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman 374476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (write_subdev) 375ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef devinfo.write_subdevice = write_subdev - dev->subdevices; 376476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman else 377ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef devinfo.write_subdevice = -1; 378ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 379063db04b8901c5cf84c552a5053748d183d34e61Bill Pemberton if (copy_to_user(arg, &devinfo, sizeof(struct comedi_devinfo))) 380ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 381ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 382ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 383ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 384ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 385ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 386ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_SUBDINFO 387ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef subdevice info ioctl 388ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 389ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 390ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef pointer to array of subdevice info structures 391ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 392ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 393ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef none 394ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 395ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 396ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef array of subdevice info structures at arg 397ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 398ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 3990a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_subdinfo_ioctl(struct comedi_device *dev, 4000a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral struct comedi_subdinfo *arg, void *file) 401ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 402ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int ret, i; 403bd52efbbcc9f5d70c736b9b73c82aee149da1fe5Bill Pemberton struct comedi_subdinfo *tmp, *us; 40434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 405ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 4060a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral tmp = 4070a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral kcalloc(dev->n_subdevices, sizeof(struct comedi_subdinfo), 4080a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral GFP_KERNEL); 409ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!tmp) 410ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENOMEM; 411ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 412ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* fill subdinfo structs */ 413ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef for (i = 0; i < dev->n_subdevices; i++) { 414ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + i; 415ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us = tmp + i; 416ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 417ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->type = s->type; 418ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->n_chan = s->n_chan; 419ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags = s->subdev_flags; 420ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (comedi_get_subdevice_runflags(s) & SRF_RUNNING) 421ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags |= SDF_RUNNING; 422ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#define TIMER_nanosec 5 /* backwards compatibility */ 423ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->timer_type = TIMER_nanosec; 424ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->len_chanlist = s->len_chanlist; 425ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->maxdata = s->maxdata; 426ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->range_table) { 427ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->range_type = 428476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman (i << 24) | (0 << 16) | (s->range_table->length); 429ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } else { 430ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->range_type = 0; /* XXX */ 431ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 432ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->flags = s->flags; 433ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 434ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy) 435ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags |= SDF_BUSY; 436ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy == file) 437ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags |= SDF_BUSY_OWNER; 438ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->lock) 439ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags |= SDF_LOCKED; 440ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->lock == file) 441ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags |= SDF_LOCK_OWNER; 442ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->maxdata && s->maxdata_list) 443ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags |= SDF_MAXDATA; 444ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->flaglist) 445ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags |= SDF_FLAGS; 446ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->range_table_list) 447ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags |= SDF_RANGETYPE; 448ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->do_cmd) 449ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->subd_flags |= SDF_CMD; 450ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 451ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->insn_bits != &insn_inval) 452ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->insn_bits_support = COMEDI_SUPPORTED; 453ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef else 454ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->insn_bits_support = COMEDI_UNSUPPORTED; 455ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 456ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef us->settling_time_0 = s->settling_time_0; 457ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 458ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 459ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = copy_to_user(arg, tmp, 460bd52efbbcc9f5d70c736b9b73c82aee149da1fe5Bill Pemberton dev->n_subdevices * sizeof(struct comedi_subdinfo)); 461ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 462ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kfree(tmp); 463ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 464ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret ? -EFAULT : 0; 465ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 466ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 467ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 468ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_CHANINFO 469ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef subdevice info ioctl 470ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 471ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 472ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef pointer to chaninfo structure 473ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 474ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 475ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef chaninfo structure at arg 476ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 477ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 478ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arrays at elements of chaninfo structure 479ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 480ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 4810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_chaninfo_ioctl(struct comedi_device *dev, 4820a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral struct comedi_chaninfo *arg) 483ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 48434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 485a18b416dc11ff9596ebf2012b1d15f485b951b28Bill Pemberton struct comedi_chaninfo it; 486ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 487a18b416dc11ff9596ebf2012b1d15f485b951b28Bill Pemberton if (copy_from_user(&it, arg, sizeof(struct comedi_chaninfo))) 488ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 489ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 490ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (it.subdev >= dev->n_subdevices) 491ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 492ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + it.subdev; 493ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 494ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (it.maxdata_list) { 495ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->maxdata || !s->maxdata_list) 496ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 497ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_to_user(it.maxdata_list, s->maxdata_list, 498790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton s->n_chan * sizeof(unsigned int))) 499ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 500ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 501ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 502ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (it.flaglist) { 503ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->flaglist) 504ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 505ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_to_user(it.flaglist, s->flaglist, 506476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman s->n_chan * sizeof(unsigned int))) 507ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 508ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 509ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 510ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (it.rangelist) { 511ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int i; 512ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 513ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->range_table_list) 514ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 515ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef for (i = 0; i < s->n_chan; i++) { 516ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int x; 517ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 518ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef x = (dev->minor << 28) | (it.subdev << 24) | (i << 16) | 519476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman (s->range_table_list[i]->length); 520ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef put_user(x, it.rangelist + i); 521ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 522476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#if 0 523476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (copy_to_user(it.rangelist, s->range_type_list, 5240a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral s->n_chan * sizeof(unsigned int))) 525476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman return -EFAULT; 526476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman#endif 527ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 528ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 529ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 530ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 531ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 532ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* 533ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_BUFINFO 534ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef buffer information ioctl 535ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 536ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 537ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef pointer to bufinfo structure 538ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 539ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 540ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bufinfo at arg 541ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 542ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 543ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef modified bufinfo at arg 544ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 545ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */ 54671b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_bufinfo_ioctl(struct comedi_device *dev, void *arg) 547ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 5489aa5339ac1eba5268df69bbcdf1abb9fae5afecaBill Pemberton struct comedi_bufinfo bi; 54934c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 550d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton struct comedi_async *async; 551ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 5529aa5339ac1eba5268df69bbcdf1abb9fae5afecaBill Pemberton if (copy_from_user(&bi, arg, sizeof(struct comedi_bufinfo))) 553ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 554ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 555ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (bi.subdevice >= dev->n_subdevices || bi.subdevice < 0) 556ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 557ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 558ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + bi.subdevice; 559ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async = s->async; 560ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 561ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!async) { 562ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("subdevice does not have async capability\n"); 563ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.buf_write_ptr = 0; 564ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.buf_read_ptr = 0; 565ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.buf_write_count = 0; 566ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.buf_read_count = 0; 567ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto copyback; 568ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 569ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 570ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)) { 571ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read); 572ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_buf_read_free(async, bi.bytes_read); 573ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 574ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | 575476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman SRF_RUNNING)) 576476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman && async->buf_write_count == async->buf_read_count) { 577ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef do_become_nonbusy(dev, s); 578ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 579ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 580ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 581ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (bi.bytes_written && (s->subdev_flags & SDF_CMD_WRITE)) { 582ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.bytes_written = 583476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_buf_write_alloc(async, bi.bytes_written); 584ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_buf_write_free(async, bi.bytes_written); 585ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 586ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 587ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.buf_write_count = async->buf_write_count; 588ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.buf_write_ptr = async->buf_write_ptr; 589ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.buf_read_count = async->buf_read_count; 590ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef bi.buf_read_ptr = async->buf_read_ptr; 591ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 592476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancopyback: 5939aa5339ac1eba5268df69bbcdf1abb9fae5afecaBill Pemberton if (copy_to_user(arg, &bi, sizeof(struct comedi_bufinfo))) 594ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 595ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 596ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 597ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 598ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 5990a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, 6000a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int *data, void *file); 601ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 60220617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * COMEDI_INSNLIST 60320617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * synchronous instructions 604ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 60520617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * arg: 60620617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * pointer to sync cmd structure 607ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 60820617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * reads: 60920617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * sync cmd struct at arg 61020617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * instruction list 61120617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * data (for writes) 612ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 61320617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * writes: 61420617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * data (for reads) 615ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */ 616ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* arbitrary limits */ 617ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#define MAX_SAMPLES 256 61871b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_insnlist_ioctl(struct comedi_device *dev, void *arg, void *file) 619ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 620da613f4fabb43b8bc551bb874792e1f22a698696Bill Pemberton struct comedi_insnlist insnlist; 62190035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton struct comedi_insn *insns = NULL; 622790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton unsigned int *data = NULL; 623ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int i = 0; 624ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int ret = 0; 625ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 626da613f4fabb43b8bc551bb874792e1f22a698696Bill Pemberton if (copy_from_user(&insnlist, arg, sizeof(struct comedi_insnlist))) 627ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 628ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 629790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL); 630ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!data) { 631ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("kmalloc failed\n"); 632ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -ENOMEM; 633ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 634ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 635ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 6360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral insns = 6370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral kmalloc(sizeof(struct comedi_insn) * insnlist.n_insns, GFP_KERNEL); 638ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!insns) { 639ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("kmalloc failed\n"); 640ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -ENOMEM; 641ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 642ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 643ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 644ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_from_user(insns, insnlist.insns, 64590035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton sizeof(struct comedi_insn) * insnlist.n_insns)) { 646ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("copy_from_user failed\n"); 647ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 648ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 649ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 650ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 651ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef for (i = 0; i < insnlist.n_insns; i++) { 652ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insns[i].n > MAX_SAMPLES) { 653ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("number of samples too large\n"); 654ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 655ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 656ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 657ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insns[i].insn & INSN_MASK_WRITE) { 658ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_from_user(data, insns[i].data, 659790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton insns[i].n * sizeof(unsigned int))) { 660ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("copy_from_user failed\n"); 661ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 662ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 663ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 664ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 665ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = parse_insn(dev, insns + i, data, file); 666ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (ret < 0) 667ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 668ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insns[i].insn & INSN_MASK_READ) { 669ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_to_user(insns[i].data, data, 670790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton insns[i].n * sizeof(unsigned int))) { 671ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("copy_to_user failed\n"); 672ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 673ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 674ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 675ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 676ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (need_resched()) 677ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef schedule(); 678ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 679ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 680476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanerror: 681476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman kfree(insns); 682476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman kfree(data); 683ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 684ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (ret < 0) 685ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 686ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return i; 687ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 688ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 6890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int check_insn_config_length(struct comedi_insn *insn, 6900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int *data) 691ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 692476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (insn->n < 1) 693476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman return -EINVAL; 694ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 695ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef switch (data[0]) { 696ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_DIO_OUTPUT: 697ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_DIO_INPUT: 698ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_DISARM: 699ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_RESET: 700ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->n == 1) 701ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 702ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 703ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_ARM: 704ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_DIO_QUERY: 705ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_BLOCK_SIZE: 706ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_FILTER: 707ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_SERIAL_CLOCK: 708ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_BIDIRECTIONAL_DATA: 709ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_ALT_SOURCE: 710ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_SET_COUNTER_MODE: 711ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_8254_READ_STATUS: 712ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_SET_ROUTING: 713ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_GET_ROUTING: 714ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_GET_PWM_STATUS: 715ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_PWM_SET_PERIOD: 716ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_PWM_GET_PERIOD: 717ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->n == 2) 718ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 719ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 720ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_SET_GATE_SRC: 721ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_GET_GATE_SRC: 722ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_SET_CLOCK_SRC: 723ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_GET_CLOCK_SRC: 724ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_SET_OTHER_SRC: 725ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_GET_COUNTER_STATUS: 726ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_PWM_SET_H_BRIDGE: 727ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_PWM_GET_H_BRIDGE: 728ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE: 729ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->n == 3) 730ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 731ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 732ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_PWM_OUTPUT: 733ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG_ANALOG_TRIG: 734ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->n == 5) 735ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 736ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 7370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral /* by default we allow the insn since we don't have checks for 7380a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral * all possible cases yet */ 739ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef default: 7403fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor printk(KERN_WARNING 7413fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor "comedi: no check for data length of config insn id " 7420a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral "%i is implemented.\n" 7430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral " Add a check to %s in %s.\n" 7440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral " Assuming n=%i is correct.\n", data[0], __func__, 7450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral __FILE__, insn->n); 746ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 747ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 748ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 749ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 750ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 751ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 7520a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, 7530a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral unsigned int *data, void *file) 754ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 75534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 756ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int ret = 0; 757ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int i; 758ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 759ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->insn & INSN_MASK_SPECIAL) { 760ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* a non-subdevice instruction */ 761ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 762ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef switch (insn->insn) { 763ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_GTOD: 764ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef { 765ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef struct timeval tv; 766ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 767ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->n != 2) { 768ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 769ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 770ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 771ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 772ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef do_gettimeofday(&tv); 773ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef data[0] = tv.tv_sec; 774ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef data[1] = tv.tv_usec; 775ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = 2; 776ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 777ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 778ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 779ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_WAIT: 780ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->n != 1 || data[0] >= 100000) { 781ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 782ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 783ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 784ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef udelay(data[0] / 1000); 785ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = 1; 786ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 787ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_INTTRIG: 788ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->n != 1) { 789ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 790ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 791ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 792ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->subdev >= dev->n_subdevices) { 793ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("%d not usable subdevice\n", 794ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef insn->subdev); 795ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 796ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 797ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 798ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + insn->subdev; 799ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->async) { 800ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("no async\n"); 801ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 802ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 803ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 804ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->async->inttrig) { 805ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("no inttrig\n"); 806ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EAGAIN; 807ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 808ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 809ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->async->inttrig(dev, s, insn->data[0]); 810ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (ret >= 0) 811ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = 1; 812ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 813ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef default: 814ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("invalid insn\n"); 815ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 816ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 817ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 818ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } else { 819ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* a subdevice instruction */ 820790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton unsigned int maxdata; 821ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 822ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->subdev >= dev->n_subdevices) { 823ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("subdevice %d out of range\n", insn->subdev); 824ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 825ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto out; 826ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 827ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + insn->subdev; 828ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 829ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->type == COMEDI_SUBD_UNUSED) { 830ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("%d not usable subdevice\n", insn->subdev); 831ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EIO; 832ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto out; 833ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 834ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 835ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* are we locked? (ioctl lock) */ 836ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->lock && s->lock != file) { 837ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("device locked\n"); 838ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EACCES; 839ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto out; 840ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 841ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 8420fd0ca75fd9eb0e9cde49c28ad227c2d8d049366Greg Kroah-Hartman ret = comedi_check_chanlist(s, 1, &insn->chanspec); 843476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (ret < 0) { 844ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 845ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("bad chanspec\n"); 846ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto out; 847ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 848ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 849ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy) { 850ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EBUSY; 851ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto out; 852ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 853ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* This looks arbitrary. It is. */ 854ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->busy = &parse_insn; 855ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef switch (insn->insn) { 856ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_READ: 857ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->insn_read(dev, s, insn, data); 858ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 859ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_WRITE: 860ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef maxdata = s->maxdata_list 861476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman ? s->maxdata_list[CR_CHAN(insn->chanspec)] 862476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman : s->maxdata; 863ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef for (i = 0; i < insn->n; ++i) { 864ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (data[i] > maxdata) { 865ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 866ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("bad data value(s)\n"); 867ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 868ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 869ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 870ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (ret == 0) 871ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->insn_write(dev, s, insn, data); 872ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 873ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_BITS: 874ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn->n != 2) { 875ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 876ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 877ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 878ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->insn_bits(dev, s, insn, data); 879ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 880ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef case INSN_CONFIG: 881ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = check_insn_config_length(insn, data); 882ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (ret) 883ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 884ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->insn_config(dev, s, insn, data); 885ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 886ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef default: 887ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 888ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 889ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 890ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 891ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->busy = NULL; 892ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 893ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 894476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanout: 895ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 896ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 897ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 898ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 89920617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * COMEDI_INSN 90020617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * synchronous instructions 901ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 90220617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * arg: 90320617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * pointer to insn 904ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 90520617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * reads: 90620617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * struct comedi_insn struct at arg 90720617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * data (for writes) 908ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 90920617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * writes: 91020617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere * data (for reads) 911ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */ 91271b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_insn_ioctl(struct comedi_device *dev, void *arg, void *file) 913ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 91490035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton struct comedi_insn insn; 915790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton unsigned int *data = NULL; 916ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int ret = 0; 917ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 918790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL); 919ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!data) { 920ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -ENOMEM; 921ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 922ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 923ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 92490035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton if (copy_from_user(&insn, arg, sizeof(struct comedi_insn))) { 925ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 926ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 927ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 928ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 929ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* This is where the behavior of insn and insnlist deviate. */ 930ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn.n > MAX_SAMPLES) 931ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef insn.n = MAX_SAMPLES; 932ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn.insn & INSN_MASK_WRITE) { 9330a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral if (copy_from_user 9340a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral (data, insn.data, insn.n * sizeof(unsigned int))) { 935ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 936ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 937ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 938ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 939ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = parse_insn(dev, &insn, data, file); 940ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (ret < 0) 941ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 942ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (insn.insn & INSN_MASK_READ) { 9430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral if (copy_to_user 9440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral (insn.data, data, insn.n * sizeof(unsigned int))) { 945ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 946ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto error; 947ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 948ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 949ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = insn.n; 950ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 951476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanerror: 952476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman kfree(data); 953ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 954ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 955ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 956ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 957181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartmanstatic void comedi_set_subdevice_runflags(struct comedi_subdevice *s, 958181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman unsigned mask, unsigned bits) 959181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman{ 960181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman unsigned long flags; 961181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman 962181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman spin_lock_irqsave(&s->spin_lock, flags); 963181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman s->runflags &= ~mask; 964181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman s->runflags |= (bits & mask); 965181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman spin_unlock_irqrestore(&s->spin_lock, flags); 966181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman} 967181bd67bf5780b941f2cba6247ed1c0cdfce468aGreg Kroah-Hartman 968ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 969ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_CMD 970ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef command ioctl 971ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 972ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 973ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef pointer to cmd structure 974ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 975ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 976ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef cmd structure at arg 977ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef channel/range list 978ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 979ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 980ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef modified cmd structure at arg 981ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 982ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 98371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_cmd_ioctl(struct comedi_device *dev, void *arg, void *file) 984ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 985ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton struct comedi_cmd user_cmd; 98634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 987d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton struct comedi_async *async; 988ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int ret = 0; 989ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned int *chanlist_saver = NULL; 990ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 991ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton if (copy_from_user(&user_cmd, arg, sizeof(struct comedi_cmd))) { 992ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("bad cmd address\n"); 993ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 994ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 995476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman /* save user's chanlist pointer so it can be restored later */ 996ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef chanlist_saver = user_cmd.chanlist; 997ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 998ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (user_cmd.subdev >= dev->n_subdevices) { 999ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("%d no such subdevice\n", user_cmd.subdev); 1000ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENODEV; 1001ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1002ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1003ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + user_cmd.subdev; 1004ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async = s->async; 1005ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1006ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->type == COMEDI_SUBD_UNUSED) { 1007ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("%d not valid subdevice\n", user_cmd.subdev); 1008ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EIO; 1009ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1010ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1011ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->do_cmd || !s->do_cmdtest || !s->async) { 1012ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("subdevice %i does not support commands\n", 1013ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd.subdev); 1014ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EIO; 1015ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1016ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1017ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* are we locked? (ioctl lock) */ 1018ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->lock && s->lock != file) { 1019ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("subdevice locked\n"); 1020ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EACCES; 1021ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1022ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1023ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* are we busy? */ 1024ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy) { 1025ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("subdevice busy\n"); 1026ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EBUSY; 1027ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1028ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->busy = file; 1029ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1030ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* make sure channel/gain list isn't too long */ 1031ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (user_cmd.chanlist_len > s->len_chanlist) { 1032ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("channel/gain list too long %u > %d\n", 1033ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd.chanlist_len, s->len_chanlist); 1034ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 1035ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1036ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1037ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1038ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* make sure channel/gain list isn't too short */ 1039ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (user_cmd.chanlist_len < 1) { 1040ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("channel/gain list too short %u < 1\n", 1041ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd.chanlist_len); 1042ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 1043ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1044ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1045ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1046476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman kfree(async->cmd.chanlist); 1047ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->cmd = user_cmd; 1048ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->cmd.data = NULL; 1049ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* load channel/gain list */ 1050ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->cmd.chanlist = 1051476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman kmalloc(async->cmd.chanlist_len * sizeof(int), GFP_KERNEL); 1052ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!async->cmd.chanlist) { 1053ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("allocation failed\n"); 1054ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -ENOMEM; 1055ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1056ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1057ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1058ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_from_user(async->cmd.chanlist, user_cmd.chanlist, 1059476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman async->cmd.chanlist_len * sizeof(int))) { 1060ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("fault reading chanlist\n"); 1061ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 1062ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1063ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1064ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1065ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* make sure each element in channel/gain list is valid */ 10660fd0ca75fd9eb0e9cde49c28ad227c2d8d049366Greg Kroah-Hartman ret = comedi_check_chanlist(s, async->cmd.chanlist_len, async->cmd.chanlist); 1067476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (ret < 0) { 1068ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("bad chanlist\n"); 1069ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1070ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1071ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1072ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->do_cmdtest(dev, s, &async->cmd); 1073ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1074ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (async->cmd.flags & TRIG_BOGUS || ret) { 1075ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("test returned %d\n", ret); 1076ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd = async->cmd; 1077476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman /* restore chanlist pointer before copying back */ 1078ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd.chanlist = chanlist_saver; 1079ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd.data = NULL; 1080ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton if (copy_to_user(arg, &user_cmd, sizeof(struct comedi_cmd))) { 1081ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("fault writing cmd\n"); 1082ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 1083ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1084ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1085ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EAGAIN; 1086ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1087ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1088ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1089ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!async->prealloc_bufsz) { 1090ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -ENOMEM; 1091ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("no buffer (?)\n"); 1092ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1093ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1094ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1095ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_reset_async_buf(async); 1096ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1097ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->cb_mask = 1098476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR | 1099476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman COMEDI_CB_OVERFLOW; 1100476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (async->cmd.flags & TRIG_WAKE_EOS) 1101ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->cb_mask |= COMEDI_CB_EOS; 1102ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1103ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING); 1104ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1105ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->do_cmd(dev, s); 1106ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (ret == 0) 1107ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 1108ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1109476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancleanup: 1110ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef do_become_nonbusy(dev, s); 1111ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1112ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 1113ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1114ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1115ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 1116ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_CMDTEST 1117ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef command testing ioctl 1118ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1119ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 1120ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef pointer to cmd structure 1121ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1122ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 1123ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef cmd structure at arg 1124ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef channel/range list 1125ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1126ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 1127ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef modified cmd structure at arg 1128ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1129ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 113071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int do_cmdtest_ioctl(struct comedi_device *dev, void *arg, void *file) 1131ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1132ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton struct comedi_cmd user_cmd; 113334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 1134ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int ret = 0; 1135ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned int *chanlist = NULL; 1136ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned int *chanlist_saver = NULL; 1137ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1138ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton if (copy_from_user(&user_cmd, arg, sizeof(struct comedi_cmd))) { 1139ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("bad cmd address\n"); 1140ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EFAULT; 1141ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1142476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman /* save user's chanlist pointer so it can be restored later */ 1143ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef chanlist_saver = user_cmd.chanlist; 1144ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1145ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (user_cmd.subdev >= dev->n_subdevices) { 1146ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("%d no such subdevice\n", user_cmd.subdev); 1147ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENODEV; 1148ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1149ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1150ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + user_cmd.subdev; 1151ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->type == COMEDI_SUBD_UNUSED) { 1152ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("%d not valid subdevice\n", user_cmd.subdev); 1153ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EIO; 1154ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1155ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1156ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->do_cmd || !s->do_cmdtest) { 1157ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("subdevice %i does not support commands\n", 1158ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd.subdev); 1159ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EIO; 1160ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1161ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1162ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* make sure channel/gain list isn't too long */ 1163ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (user_cmd.chanlist_len > s->len_chanlist) { 1164ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("channel/gain list too long %d > %d\n", 1165ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd.chanlist_len, s->len_chanlist); 1166ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EINVAL; 1167ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1168ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1169ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1170ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* load channel/gain list */ 1171ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (user_cmd.chanlist) { 1172ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef chanlist = 1173476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman kmalloc(user_cmd.chanlist_len * sizeof(int), GFP_KERNEL); 1174ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!chanlist) { 1175ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("allocation failed\n"); 1176ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -ENOMEM; 1177ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1178ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (copy_from_user(chanlist, user_cmd.chanlist, 1181476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman user_cmd.chanlist_len * sizeof(int))) { 1182ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("fault reading chanlist\n"); 1183ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 1184ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1185ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1186ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1187ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* make sure each element in channel/gain list is valid */ 11880fd0ca75fd9eb0e9cde49c28ad227c2d8d049366Greg Kroah-Hartman ret = comedi_check_chanlist(s, user_cmd.chanlist_len, chanlist); 1189476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (ret < 0) { 1190ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("bad chanlist\n"); 1191ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1192ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1193ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1194ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd.chanlist = chanlist; 1195ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1196ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1197ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->do_cmdtest(dev, s, &user_cmd); 1198ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1199476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman /* restore chanlist pointer before copying back */ 1200ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef user_cmd.chanlist = chanlist_saver; 1201ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1202ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton if (copy_to_user(arg, &user_cmd, sizeof(struct comedi_cmd))) { 1203ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("bad cmd address\n"); 1204ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EFAULT; 1205ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto cleanup; 1206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1207476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmancleanup: 1208476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman kfree(chanlist); 1209ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1210ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 1211ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1212ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 1214ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_LOCK 1215ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef lock subdevice 1216ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1217ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 1218ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef subdevice number 1219ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1220ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 1221ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef none 1222ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1223ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 1224ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef none 1225ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1226ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 1227ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 12280a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_lock_ioctl(struct comedi_device *dev, unsigned int arg, 12290a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral void *file) 1230ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1231ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int ret = 0; 1232ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned long flags; 123334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 1234ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1235ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (arg >= dev->n_subdevices) 1236ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 1237ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + arg; 1238ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 12395f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_lock_irqsave(&s->spin_lock, flags); 1240476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (s->busy || s->lock) 1241ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = -EBUSY; 1242476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman else 1243ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->lock = file; 12445f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_unlock_irqrestore(&s->spin_lock, flags); 1245ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1246ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (ret < 0) 1247ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 1248ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1249ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#if 0 1250ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->lock_f) 1251ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->lock_f(dev, s); 1252ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif 1253ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1254ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 1255ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1256ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1257ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 1258ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_UNLOCK 1259ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unlock subdevice 1260ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1261ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 1262ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef subdevice number 1263ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1264ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 1265ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef none 1266ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1267ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 1268ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef none 1269ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1270ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef This function isn't protected by the semaphore, since 1271ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef we already own the lock. 1272ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 12730a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg, 12740a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral void *file) 1275ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 127634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 1277ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1278ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (arg >= dev->n_subdevices) 1279ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 1280ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + arg; 1281ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1282ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy) 1283ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EBUSY; 1284ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1285ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->lock && s->lock != file) 1286ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EACCES; 1287ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1288ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->lock == file) { 1289ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#if 0 1290ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->unlock) 1291ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->unlock(dev, s); 1292ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif 1293ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1294ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->lock = NULL; 1295ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1296ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1297ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 1298ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1299ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1300ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 1301ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_CANCEL 1302ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef cancel acquisition ioctl 1303ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1304ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 1305ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef subdevice number 1306ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1307ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 1308ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef nothing 1309ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1310ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 1311ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef nothing 1312ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1313ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 13140a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg, 13150a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral void *file) 1316ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 131734c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 1318ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1319ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (arg >= dev->n_subdevices) 1320ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 1321ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + arg; 1322ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->async == NULL) 1323ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 1324ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1325ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->lock && s->lock != file) 1326ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EACCES; 1327ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1328ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->busy) 1329ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 1330ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1331ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy != file) 1332ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EBUSY; 1333ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1334ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return do_cancel(dev, s); 1335ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1336ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1337ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 1338ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef COMEDI_POLL ioctl 1339ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef instructs driver to synchronize buffers 1340ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1341ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef arg: 1342ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef subdevice number 1343ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1344ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef reads: 1345ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef nothing 1346ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1347ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef writes: 1348ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef nothing 1349ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1350ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef*/ 13510a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int do_poll_ioctl(struct comedi_device *dev, unsigned int arg, 13520a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral void *file) 1353ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 135434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 1355ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1356ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (arg >= dev->n_subdevices) 1357ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 1358ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + arg; 1359ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1360ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->lock && s->lock != file) 1361ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EACCES; 1362ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1363ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->busy) 1364ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 1365ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1366ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy != file) 1367ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EBUSY; 1368ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1369ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->poll) 1370ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return s->poll(dev, s); 1371ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1372ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EINVAL; 1373ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1374ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 137534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s) 1376ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1377ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int ret = 0; 1378ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1379ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) && s->cancel) 1380ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef ret = s->cancel(dev, s); 1381ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1382ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef do_become_nonbusy(dev, s); 1383ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1384ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return ret; 1385ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1386ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1387ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefvoid comedi_unmap(struct vm_area_struct *area) 1388ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1389d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton struct comedi_async *async; 139071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev; 1391ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1392ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async = area->vm_private_data; 1393ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef dev = async->subdevice->device; 1394ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1395ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_lock(&dev->mutex); 1396ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->mmap_count--; 1397ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 1398ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1399ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1400ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic struct vm_operations_struct comedi_vm_ops = { 14010a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .close = comedi_unmap, 1402ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}; 1403ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1404ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_mmap(struct file *file, struct vm_area_struct *vma) 1405ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1406ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef const unsigned minor = iminor(file->f_dentry->d_inode); 1407476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct comedi_device_file_info *dev_file_info = 1408476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_device_file_info(minor); 140971b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev = dev_file_info->device; 1410d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton struct comedi_async *async = NULL; 1411ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned long start = vma->vm_start; 1412ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned long size; 1413ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int n_pages; 1414ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int i; 1415ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int retval; 141634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 1417ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1418ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_lock(&dev->mutex); 1419ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!dev->attached) { 1420ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("no driver configured on comedi%i\n", dev->minor); 1421ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -ENODEV; 1422ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1423ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1424476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (vma->vm_flags & VM_WRITE) 1425ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = comedi_get_write_subdevice(dev_file_info); 1426476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman else 1427ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = comedi_get_read_subdevice(dev_file_info); 1428476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman 1429ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s == NULL) { 1430ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EINVAL; 1431ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1432ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1433ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async = s->async; 1434ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (async == NULL) { 1435ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EINVAL; 1436ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1437ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1438ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1439ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (vma->vm_pgoff != 0) { 1440ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("comedi: mmap() offset must be 0.\n"); 1441ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EINVAL; 1442ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1443ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1444ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1445ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef size = vma->vm_end - vma->vm_start; 1446ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (size > async->prealloc_bufsz) { 1447ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EFAULT; 1448ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1449ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1450ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (size & (~PAGE_MASK)) { 1451ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EFAULT; 1452ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1453ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1454ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1455ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef n_pages = size >> PAGE_SHIFT; 1456ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef for (i = 0; i < n_pages; ++i) { 1457ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (remap_pfn_range(vma, start, 14580a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral page_to_pfn(virt_to_page 14590a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral (async->buf_page_list 14600a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral [i].virt_addr)), PAGE_SIZE, 14610a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral PAGE_SHARED)) { 1462ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EAGAIN; 1463ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1464ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1465ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef start += PAGE_SIZE; 1466ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1467ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1468ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef vma->vm_ops = &comedi_vm_ops; 1469ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef vma->vm_private_data = async; 1470ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1471ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->mmap_count++; 1472ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1473ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = 0; 1474476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmandone: 1475ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 1476ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return retval; 1477ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1478ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 14790a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic unsigned int comedi_poll(struct file *file, poll_table * wait) 1480ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1481ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned int mask = 0; 1482ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef const unsigned minor = iminor(file->f_dentry->d_inode); 1483476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct comedi_device_file_info *dev_file_info = 1484476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_device_file_info(minor); 148571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev = dev_file_info->device; 148634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *read_subdev; 148734c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *write_subdev; 1488ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1489ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_lock(&dev->mutex); 1490ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!dev->attached) { 1491ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("no driver configured on comedi%i\n", dev->minor); 1492ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 1493ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 1494ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1495ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1496ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mask = 0; 1497ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef read_subdev = comedi_get_read_subdevice(dev_file_info); 1498ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (read_subdev) { 1499ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef poll_wait(file, &read_subdev->async->wait_head, wait); 1500ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!read_subdev->busy 1501476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman || comedi_buf_read_n_available(read_subdev->async) > 0 1502476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman || !(comedi_get_subdevice_runflags(read_subdev) & 1503476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman SRF_RUNNING)) { 1504ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mask |= POLLIN | POLLRDNORM; 1505ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1506ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1507ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef write_subdev = comedi_get_write_subdevice(dev_file_info); 1508ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (write_subdev) { 1509ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef poll_wait(file, &write_subdev->async->wait_head, wait); 1510476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_buf_write_alloc(write_subdev->async, 1511476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman write_subdev->async->prealloc_bufsz); 1512ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!write_subdev->busy 1513476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman || !(comedi_get_subdevice_runflags(write_subdev) & 1514476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman SRF_RUNNING) 1515476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman || comedi_buf_write_n_allocated(write_subdev->async) >= 1516476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman bytes_per_sample(write_subdev->async->subdevice)) { 1517ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mask |= POLLOUT | POLLWRNORM; 1518ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1519ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1520ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1521ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 1522ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return mask; 1523ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1524ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1525ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic ssize_t comedi_write(struct file *file, const char *buf, size_t nbytes, 15266705b68d0be284e2f9949f3657ea65d426d0f988Andrea Gelmini loff_t *offset) 1527ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 152834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 1529d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton struct comedi_async *async; 1530ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int n, m, count = 0, retval = 0; 1531ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DECLARE_WAITQUEUE(wait, current); 1532ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef const unsigned minor = iminor(file->f_dentry->d_inode); 1533476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct comedi_device_file_info *dev_file_info = 1534476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_device_file_info(minor); 153571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev = dev_file_info->device; 1536ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1537ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!dev->attached) { 1538ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("no driver configured on comedi%i\n", dev->minor); 1539ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -ENODEV; 1540ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1541ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1542ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1543ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = comedi_get_write_subdevice(dev_file_info); 1544ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s == NULL) { 1545ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EIO; 1546ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1547ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1548ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async = s->async; 1549ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1550ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!nbytes) { 1551ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = 0; 1552ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1553ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1554ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->busy) { 1555ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = 0; 1556ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1557ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1558ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy != file) { 1559ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EACCES; 1560ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1561ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1562ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef add_wait_queue(&async->wait_head, &wait); 1563ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef while (nbytes > 0 && !retval) { 1564ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef set_current_state(TASK_INTERRUPTIBLE); 1565ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1566ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef n = nbytes; 1567ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1568ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef m = n; 1569476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (async->buf_write_ptr + m > async->prealloc_bufsz) 1570ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef m = async->prealloc_bufsz - async->buf_write_ptr; 1571ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_buf_write_alloc(async, async->prealloc_bufsz); 1572476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (m > comedi_buf_write_n_allocated(async)) 1573ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef m = comedi_buf_write_n_allocated(async); 1574ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (m < n) 1575ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef n = m; 1576ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1577ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (n == 0) { 1578ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) { 1579ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (comedi_get_subdevice_runflags(s) & 1580476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman SRF_ERROR) { 1581ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EPIPE; 1582ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } else { 1583ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = 0; 1584ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1585ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef do_become_nonbusy(dev, s); 1586ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1587ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1588ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (file->f_flags & O_NONBLOCK) { 1589ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EAGAIN; 1590ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1591ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1592ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (signal_pending(current)) { 1593ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -ERESTARTSYS; 1594ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1595ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1596ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef schedule(); 1597476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (!s->busy) 1598ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1599ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy != file) { 1600ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EACCES; 1601ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1602ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1603ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef continue; 1604ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1605ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1606ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef m = copy_from_user(async->prealloc_buf + async->buf_write_ptr, 1607476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman buf, n); 1608ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (m) { 1609ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef n -= m; 1610ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EFAULT; 1611ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1612ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_buf_write_free(async, n); 1613ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1614ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef count += n; 1615ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef nbytes -= n; 1616ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1617ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef buf += n; 1618ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; /* makes device work like a pipe */ 1619ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1620ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef set_current_state(TASK_RUNNING); 1621ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef remove_wait_queue(&async->wait_head, &wait); 1622ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1623ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefdone: 1624476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman return count ? count : retval; 1625ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1626ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1627ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic ssize_t comedi_read(struct file *file, char *buf, size_t nbytes, 16286705b68d0be284e2f9949f3657ea65d426d0f988Andrea Gelmini loff_t *offset) 1629ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 163034c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 1631d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton struct comedi_async *async; 1632ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int n, m, count = 0, retval = 0; 1633ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DECLARE_WAITQUEUE(wait, current); 1634ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef const unsigned minor = iminor(file->f_dentry->d_inode); 1635476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct comedi_device_file_info *dev_file_info = 1636476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_device_file_info(minor); 163771b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev = dev_file_info->device; 1638ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1639ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!dev->attached) { 1640ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("no driver configured on comedi%i\n", dev->minor); 1641ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -ENODEV; 1642ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1643ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1644ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1645ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = comedi_get_read_subdevice(dev_file_info); 1646ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s == NULL) { 1647ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EIO; 1648ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1649ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1650ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async = s->async; 1651ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!nbytes) { 1652ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = 0; 1653ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1654ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1655ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->busy) { 1656ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = 0; 1657ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1658ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1659ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy != file) { 1660ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EACCES; 1661ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto done; 1662ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1663ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1664ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef add_wait_queue(&async->wait_head, &wait); 1665ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef while (nbytes > 0 && !retval) { 1666ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef set_current_state(TASK_INTERRUPTIBLE); 1667ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1668ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef n = nbytes; 1669ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1670ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef m = comedi_buf_read_n_available(async); 1671476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman /* printk("%d available\n",m); */ 1672476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (async->buf_read_ptr + m > async->prealloc_bufsz) 1673ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef m = async->prealloc_bufsz - async->buf_read_ptr; 1674476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman /* printk("%d contiguous\n",m); */ 1675ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (m < n) 1676ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef n = m; 1677ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1678ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (n == 0) { 1679ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) { 1680ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef do_become_nonbusy(dev, s); 1681ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (comedi_get_subdevice_runflags(s) & 1682476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman SRF_ERROR) { 1683ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EPIPE; 1684ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } else { 1685ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = 0; 1686ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1687ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1688ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1689ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (file->f_flags & O_NONBLOCK) { 1690ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EAGAIN; 1691ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1692ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1693ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (signal_pending(current)) { 1694ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -ERESTARTSYS; 1695ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1696ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1697ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef schedule(); 1698ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!s->busy) { 1699ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = 0; 1700ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1701ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1702ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy != file) { 1703ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EACCES; 1704ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 1705ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1706ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef continue; 1707ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1708ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef m = copy_to_user(buf, async->prealloc_buf + 1709476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman async->buf_read_ptr, n); 1710ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (m) { 1711ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef n -= m; 1712ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = -EFAULT; 1713ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1714ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1715ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_buf_read_alloc(async, n); 1716ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_buf_read_free(async, n); 1717ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1718ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef count += n; 1719ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef nbytes -= n; 1720ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1721ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef buf += n; 1722ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; /* makes device work like a pipe */ 1723ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1724ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | SRF_RUNNING)) && 1725476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman async->buf_read_count - async->buf_write_count == 0) { 1726ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef do_become_nonbusy(dev, s); 1727ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1728ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef set_current_state(TASK_RUNNING); 1729ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef remove_wait_queue(&async->wait_head, &wait); 1730ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1731ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefdone: 1732476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman return count ? count : retval; 1733ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1734ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1735ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef/* 1736ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef This function restores a subdevice to an idle state. 1737ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */ 173834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s) 1739ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1740d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton struct comedi_async *async = s->async; 1741ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1742ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_set_subdevice_runflags(s, SRF_RUNNING, 0); 1743ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (async) { 1744ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_reset_async_buf(async); 1745ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->inttrig = NULL; 1746ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } else { 1747476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman printk(KERN_ERR 1748476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman "BUG: (?) do_become_nonbusy called with async=0\n"); 1749ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1750ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1751ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->busy = NULL; 1752ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1753ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1754ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_open(struct inode *inode, struct file *file) 1755ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1756ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef const unsigned minor = iminor(inode); 1757476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct comedi_device_file_info *dev_file_info = 1758476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_device_file_info(minor); 17590a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral struct comedi_device *dev = 17600a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral dev_file_info ? dev_file_info->device : NULL; 1761979200719d35934367bbf97d9b7d22d5b5281ddaIan Abbott 1762ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (dev == NULL) { 1763ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("invalid minor number\n"); 1764ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENODEV; 1765ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1766ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1767ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* This is slightly hacky, but we want module autoloading 1768ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * to work for root. 1769ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * case: user opens device, attached -> ok 1770ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * case: user opens device, unattached, in_request_module=0 -> autoload 1771ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * case: user opens device, unattached, in_request_module=1 -> fail 1772ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * case: root opens device, attached -> ok 1773ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * case: root opens device, unattached, in_request_module=1 -> ok 1774ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * (typically called from modprobe) 1775ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * case: root opens device, unattached, in_request_module=0 -> autoload 1776ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * 1777ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * The last could be changed to "-> ok", which would deny root 1778ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * autoloading. 1779ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef */ 1780ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_lock(&dev->mutex); 1781ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (dev->attached) 1782ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto ok; 1783a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris if (!capable(CAP_NET_ADMIN) && dev->in_request_module) { 1784ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef DPRINTK("in request module\n"); 1785ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 1786ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENODEV; 1787ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1788a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris if (capable(CAP_NET_ADMIN) && dev->in_request_module) 1789ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef goto ok; 1790ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1791ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef dev->in_request_module = 1; 1792ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1793ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#ifdef CONFIG_KMOD 1794ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 179556d92c60e6dc708541711e9de4993e7d527d08e8Ian Abbott request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor); 1796ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_lock(&dev->mutex); 1797ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef#endif 1798ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1799ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef dev->in_request_module = 0; 1800ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1801a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris if (!dev->attached && !capable(CAP_NET_ADMIN)) { 1802a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565cEric Paris DPRINTK("not attached and not CAP_NET_ADMIN\n"); 1803ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 1804ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENODEV; 1805ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1806ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefok: 1807ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef __module_get(THIS_MODULE); 1808ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1809ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (dev->attached) { 1810ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!try_module_get(dev->driver->module)) { 1811ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef module_put(THIS_MODULE); 1812ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 1813ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENOSYS; 1814ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1815ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1816ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1817476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (dev->attached && dev->use_count == 0 && dev->open) 1818ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef dev->open(dev); 1819ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1820ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef dev->use_count++; 1821ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1822ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 1823ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1824ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 1825ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1826ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1827ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_close(struct inode *inode, struct file *file) 1828ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1829ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef const unsigned minor = iminor(inode); 1830476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct comedi_device_file_info *dev_file_info = 1831476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_device_file_info(minor); 183271b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev = dev_file_info->device; 183334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s = NULL; 1834ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int i; 1835ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1836ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_lock(&dev->mutex); 1837ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1838ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (dev->subdevices) { 1839ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef for (i = 0; i < dev->n_subdevices; i++) { 1840ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + i; 1841ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1842476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (s->busy == file) 1843ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef do_cancel(dev, s); 1844476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (s->lock == file) 1845ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->lock = NULL; 1846ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1847ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1848476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (dev->attached && dev->use_count == 1 && dev->close) 1849ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef dev->close(dev); 1850ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1851ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef module_put(THIS_MODULE); 1852476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (dev->attached) 1853ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef module_put(dev->driver->module); 1854ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1855ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef dev->use_count--; 1856ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1857ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 1858ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1859476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (file->f_flags & FASYNC) 1860ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_fasync(-1, file, 0); 1861ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1862ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 1863ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1864ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1865ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int comedi_fasync(int fd, struct file *file, int on) 1866ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1867ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef const unsigned minor = iminor(file->f_dentry->d_inode); 1868476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman struct comedi_device_file_info *dev_file_info = 1869476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman comedi_get_device_file_info(minor); 1870476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman 187171b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev = dev_file_info->device; 1872ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1873ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return fasync_helper(fd, file, on, &dev->async_queue); 1874ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1875ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1876ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefconst struct file_operations comedi_fops = { 18770a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .owner = THIS_MODULE, 18780a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .unlocked_ioctl = comedi_unlocked_ioctl, 18790a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .compat_ioctl = comedi_compat_ioctl, 18800a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .open = comedi_open, 18810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .release = comedi_close, 18820a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .read = comedi_read, 18830a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .write = comedi_write, 18840a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .mmap = comedi_mmap, 18850a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .poll = comedi_poll, 18860a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .fasync = comedi_fasync, 1887ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef}; 1888ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1889476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartmanstruct class *comedi_class; 1890ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic struct cdev comedi_cdev; 1891ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1892ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic void comedi_cleanup_legacy_minors(void) 1893ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1894ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned i; 1895476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman 18961dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porr for (i = 0; i < comedi_num_legacy_minors; i++) 1897ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_free_board_minor(i); 1898ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1899ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1900ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic int __init comedi_init(void) 1901ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1902ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int i; 1903ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int retval; 1904ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1905476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman printk(KERN_INFO "comedi: version " COMEDI_RELEASE 1906476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman " - http://www.comedi.org\n"); 1907ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1908a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess if (comedi_num_legacy_minors < 0 || 1909a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) { 1910a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess printk(KERN_ERR "comedi: error: invalid value for module " 1911a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess "parameter \"comedi_num_legacy_minors\". Valid values " 1912a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess "are 0 through %i.\n", COMEDI_NUM_BOARD_MINORS); 1913a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess return -EINVAL; 1914a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess } 1915a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess 1916a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess /* 1917a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess * comedi is unusable if both comedi_autoconfig and 1918a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess * comedi_num_legacy_minors are zero, so we might as well adjust the 1919a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess * defaults in that case 1920a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess */ 1921a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess if (comedi_autoconfig == 0 && comedi_num_legacy_minors == 0) 1922a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess comedi_num_legacy_minors = 16; 1923a3cb729ef4a192f04179f780122df78ef1ffe779Frank Mori Hess 1924476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman memset(comedi_file_info_table, 0, 1925476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS); 1926ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1927ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0), 1928476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman COMEDI_NUM_MINORS, "comedi"); 1929ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (retval) 1930ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EIO; 1931ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef cdev_init(&comedi_cdev, &comedi_fops); 1932ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_cdev.owner = THIS_MODULE; 1933ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kobject_set_name(&comedi_cdev.kobj, "comedi"); 1934ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) { 1935ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), 1936476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman COMEDI_NUM_MINORS); 1937ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EIO; 1938ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1939ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_class = class_create(THIS_MODULE, "comedi"); 1940ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (IS_ERR(comedi_class)) { 19413fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor printk(KERN_ERR "comedi: failed to create class"); 1942ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef cdev_del(&comedi_cdev); 1943ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), 1944476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman COMEDI_NUM_MINORS); 1945ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return PTR_ERR(comedi_class); 1946ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1947ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1948ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* XXX requires /proc interface */ 1949ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_proc_init(); 1950ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1951476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman /* create devices files for legacy/manual use */ 19521dd33ab8a9397793d65b9fc090174ff7cdfaff95Bernd Porr for (i = 0; i < comedi_num_legacy_minors; i++) { 1953ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int minor; 1954ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef minor = comedi_alloc_board_minor(NULL); 1955476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (minor < 0) { 1956ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_cleanup_legacy_minors(); 1957ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef cdev_del(&comedi_cdev); 1958ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), 1959476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman COMEDI_NUM_MINORS); 1960ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return minor; 1961ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1962ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 1963ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1964ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 1965ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1966ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1967ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstatic void __exit comedi_cleanup(void) 1968ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1969ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int i; 1970ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1971ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_cleanup_legacy_minors(); 1972476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman for (i = 0; i < COMEDI_NUM_MINORS; ++i) 1973ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef BUG_ON(comedi_file_info_table[i]); 1974476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman 1975ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef class_destroy(comedi_class); 1976ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef cdev_del(&comedi_cdev); 1977ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS); 1978ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1979ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_proc_cleanup(); 1980ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 1981ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1982ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefmodule_init(comedi_init); 1983ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefmodule_exit(comedi_cleanup); 1984ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 198571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonvoid comedi_error(const struct comedi_device *dev, const char *s) 1986ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 19873fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor printk(KERN_ERR "comedi%d: %s: %s\n", dev->minor, 19883fffdf2045d0dbca3833f8f54ae41ce5f2c0b8faMark Rankilor dev->driver->driver_name, s); 1989ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 199018736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL(comedi_error); 1991ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 199234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid comedi_event(struct comedi_device *dev, struct comedi_subdevice *s) 1993ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 1994d163679ceec20c50f9aee880fa76c0c1185244a8Bill Pemberton struct comedi_async *async = s->async; 1995ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned runflags = 0; 1996ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned runflags_mask = 0; 1997ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 1998476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman /* DPRINTK("comedi_event 0x%x\n",mask); */ 1999ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2000ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) == 0) 2001ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return; 2002ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 20030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral if (s-> 20040a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | 20050a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral COMEDI_CB_OVERFLOW)) { 2006ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef runflags_mask |= SRF_RUNNING; 2007ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2008ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /* remember if an error event has occured, so an error 2009ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef * can be returned the next time the user does a read() */ 2010ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) { 2011ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef runflags_mask |= SRF_ERROR; 2012ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef runflags |= SRF_ERROR; 2013ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2014ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (runflags_mask) { 2015ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef /*sets SRF_ERROR and SRF_RUNNING together atomically */ 2016ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_set_subdevice_runflags(s, runflags_mask, runflags); 2017ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2018ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2019ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (async->cb_mask & s->async->events) { 2020ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (comedi_get_subdevice_runflags(s) & SRF_USER) { 2021fcea115462c690ba09f9df7471d60dda0d86a4eaGreg Kroah-Hartman wake_up_interruptible(&async->wait_head); 20226705b68d0be284e2f9949f3657ea65d426d0f988Andrea Gelmini if (s->subdev_flags & SDF_CMD_READ) 20230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral kill_fasync(&dev->async_queue, SIGIO, POLL_IN); 20246705b68d0be284e2f9949f3657ea65d426d0f988Andrea Gelmini if (s->subdev_flags & SDF_CMD_WRITE) 20250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral kill_fasync(&dev->async_queue, SIGIO, POLL_OUT); 2026ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } else { 2027ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (async->cb_func) 2028ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef async->cb_func(s->async->events, async->cb_arg); 2029ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2030ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2031ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->async->events = 0; 2032ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 203318736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL(comedi_event); 2034ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 203534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonunsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s) 2036ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 2037ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned long flags; 2038ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned runflags; 2039ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 20405f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_lock_irqsave(&s->spin_lock, flags); 2041ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef runflags = s->runflags; 20425f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_unlock_irqrestore(&s->spin_lock, flags); 2043ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return runflags; 2044ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 204518736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL(comedi_get_subdevice_runflags); 2046ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 204771b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int is_device_busy(struct comedi_device *dev) 2048ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 204934c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton struct comedi_subdevice *s; 2050ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef int i; 2051ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2052ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (!dev->attached) 2053ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 2054ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2055ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef for (i = 0; i < dev->n_subdevices; i++) { 2056ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s = dev->subdevices + i; 2057ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->busy) 2058ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 1; 2059ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef if (s->async && s->async->mmap_count) 2060ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 1; 2061ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2062ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2063ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return 0; 2064ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 2065ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 206671b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonvoid comedi_device_init(struct comedi_device *dev) 2067ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 206871b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton memset(dev, 0, sizeof(struct comedi_device)); 2069ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef spin_lock_init(&dev->spinlock); 2070ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_init(&dev->mutex); 2071ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef dev->minor = -1; 2072ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 2073ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 207471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonvoid comedi_device_cleanup(struct comedi_device *dev) 2075ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 2076476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (dev == NULL) 2077476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman return; 2078ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_lock(&dev->mutex); 2079ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_device_detach(dev); 2080ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_unlock(&dev->mutex); 2081ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef mutex_destroy(&dev->mutex); 2082ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 2083ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2084ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefint comedi_alloc_board_minor(struct device *hardware_device) 2085ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 2086ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned long flags; 2087ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef struct comedi_device_file_info *info; 20880bfbbe8f09617247c87d3b626cbf007c423afff1Bill Pemberton struct device *csdev; 2089ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned i; 2090883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess int retval; 2091ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2092ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); 2093476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (info == NULL) 2094476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman return -ENOMEM; 209571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton info->device = kzalloc(sizeof(struct comedi_device), GFP_KERNEL); 2096476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (info->device == NULL) { 2097ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kfree(info); 2098ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -ENOMEM; 2099ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2100ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_device_init(info->device); 21015f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_lock_irqsave(&comedi_file_info_table_lock, flags); 2102476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) { 2103476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (comedi_file_info_table[i] == NULL) { 2104ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_file_info_table[i] = info; 2105ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 2106ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2107ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 21085f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); 2109476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (i == COMEDI_NUM_BOARD_MINORS) { 2110ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_device_cleanup(info->device); 2111ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kfree(info->device); 2112ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kfree(info); 21130a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral printk(KERN_ERR 211420617f22b006e12b81602d80d85f8f3f7efdef45Pieter De Praetere 21150a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral "comedi: error: ran out of minor numbers for board device files.\n"); 2116ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EBUSY; 2117ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2118ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info->device->minor = i; 2119ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef csdev = COMEDI_DEVICE_CREATE(comedi_class, NULL, 2120476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman MKDEV(COMEDI_MAJOR, i), NULL, 2121476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman hardware_device, "comedi%i", i); 2122476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (!IS_ERR(csdev)) 2123ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info->device->class_dev = csdev; 2124883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess dev_set_drvdata(csdev, info); 2125883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb); 2126883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (retval) { 21270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral printk(KERN_ERR 21280a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral "comedi: failed to create sysfs attribute file \"%s\".\n", 21290a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral dev_attr_max_read_buffer_kb.attr.name); 2130883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess comedi_free_board_minor(i); 2131883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2132883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 2133883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess retval = device_create_file(csdev, &dev_attr_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_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_max_write_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_max_write_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_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_write_buffer_kb.attr.name); 2154883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess comedi_free_board_minor(i); 2155883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2156883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 2157ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return i; 2158ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 2159ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2160ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefvoid comedi_free_board_minor(unsigned minor) 2161ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 2162ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned long flags; 2163ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef struct comedi_device_file_info *info; 2164ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2165ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS); 21665f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_lock_irqsave(&comedi_file_info_table_lock, flags); 2167ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info = comedi_file_info_table[minor]; 2168ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_file_info_table[minor] = NULL; 21695f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); 2170ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2171476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (info) { 217271b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton struct comedi_device *dev = info->device; 2173476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (dev) { 2174476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (dev->class_dev) { 2175476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman device_destroy(comedi_class, 2176476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman MKDEV(COMEDI_MAJOR, dev->minor)); 2177ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2178ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_device_cleanup(dev); 2179ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kfree(dev); 2180ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2181ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kfree(info); 2182ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2183ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 218418736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL_GPL(comedi_free_board_minor); 2185ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2186883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessint comedi_alloc_subdevice_minor(struct comedi_device *dev, 2187883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_subdevice *s) 2188ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 2189ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned long flags; 2190ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef struct comedi_device_file_info *info; 21910bfbbe8f09617247c87d3b626cbf007c423afff1Bill Pemberton struct device *csdev; 2192ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned i; 2193883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess int retval; 2194ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2195ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); 2196476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (info == NULL) 2197476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman return -ENOMEM; 2198ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info->device = dev; 2199ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info->read_subdevice = s; 2200ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info->write_subdevice = s; 22015f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_lock_irqsave(&comedi_file_info_table_lock, flags); 22024c41f3ae3bf0bcc53f259b657c2fbc3961ff2b8aFrank Mori Hess for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) { 2203476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (comedi_file_info_table[i] == NULL) { 2204ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_file_info_table[i] = info; 2205ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef break; 2206ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2207ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 22085f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); 2209476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (i == COMEDI_NUM_MINORS) { 2210ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kfree(info); 22110a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral printk(KERN_ERR 22120a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral "comedi: error: ran out of minor numbers for board device files.\n"); 2213ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return -EBUSY; 2214ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2215ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->minor = i; 2216ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef csdev = COMEDI_DEVICE_CREATE(comedi_class, dev->class_dev, 2217476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman MKDEV(COMEDI_MAJOR, i), NULL, NULL, 2218476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman "comedi%i_subd%i", dev->minor, 2219476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman (int)(s - dev->subdevices)); 2220476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (!IS_ERR(csdev)) 2221ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->class_dev = csdev; 2222883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess dev_set_drvdata(csdev, info); 2223883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb); 2224883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (retval) { 22250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral printk(KERN_ERR 22260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral "comedi: failed to create sysfs attribute file \"%s\".\n", 22270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral dev_attr_max_read_buffer_kb.attr.name); 2228883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess comedi_free_subdevice_minor(s); 2229883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2230883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 2231883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess retval = device_create_file(csdev, &dev_attr_read_buffer_kb); 2232883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (retval) { 22330a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral printk(KERN_ERR 22340a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral "comedi: failed to create sysfs attribute file \"%s\".\n", 22350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral dev_attr_read_buffer_kb.attr.name); 2236883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess comedi_free_subdevice_minor(s); 2237883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2238883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 2239883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb); 2240883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (retval) { 22410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral printk(KERN_ERR 22420a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral "comedi: failed to create sysfs attribute file \"%s\".\n", 22430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral dev_attr_max_write_buffer_kb.attr.name); 2244883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess comedi_free_subdevice_minor(s); 2245883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2246883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 2247883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess retval = device_create_file(csdev, &dev_attr_write_buffer_kb); 2248883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (retval) { 22490a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral printk(KERN_ERR 22500a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral "comedi: failed to create sysfs attribute file \"%s\".\n", 22510a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral dev_attr_write_buffer_kb.attr.name); 2252883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess comedi_free_subdevice_minor(s); 2253883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2254883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 2255ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return i; 2256ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 2257ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 225834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonvoid comedi_free_subdevice_minor(struct comedi_subdevice *s) 2259ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 2260ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned long flags; 2261ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef struct comedi_device_file_info *info; 2262ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2263476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (s == NULL) 2264476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman return; 2265476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (s->minor < 0) 2266476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman return; 2267ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2268ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef BUG_ON(s->minor >= COMEDI_NUM_MINORS); 2269ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR); 2270ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 22715f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_lock_irqsave(&comedi_file_info_table_lock, flags); 2272ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info = comedi_file_info_table[s->minor]; 2273ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef comedi_file_info_table[s->minor] = NULL; 22745f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); 2275ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2276476b847733636ce5765093f5d1a369cc470e78e6Greg Kroah-Hartman if (s->class_dev) { 2277ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor)); 2278ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef s->class_dev = NULL; 2279ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef } 2280ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef kfree(info); 2281ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 2282ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2283ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleefstruct comedi_device_file_info *comedi_get_device_file_info(unsigned minor) 2284ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef{ 2285ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef unsigned long flags; 2286ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef struct comedi_device_file_info *info; 2287ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef 2288ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef BUG_ON(minor >= COMEDI_NUM_MINORS); 22895f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_lock_irqsave(&comedi_file_info_table_lock, flags); 2290ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef info = comedi_file_info_table[minor]; 22915f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); 2292ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef return info; 2293ed9eccbe8970f6eedc1b978c157caf1251a896d4David Schleef} 229418736438ae4ab3d96602b92446e07cc03c024b02Greg Kroah-HartmanEXPORT_SYMBOL_GPL(comedi_get_device_file_info); 2295883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2296883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic int resize_async_buffer(struct comedi_device *dev, 2297883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_subdevice *s, 2298883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_async *async, unsigned new_size) 2299883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{ 2300883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess int retval; 2301883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2302883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (new_size > async->max_bufsize) 2303883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EPERM; 2304883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2305883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (s->busy) { 2306883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess DPRINTK("subdevice is busy, cannot resize buffer\n"); 2307883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EBUSY; 2308883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 2309883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (async->mmap_count) { 2310883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess DPRINTK("subdevice is mmapped, cannot resize buffer\n"); 2311883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EBUSY; 2312883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 2313883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2314883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (!async->prealloc_buf) 2315883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 2316883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2317883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess /* make sure buffer is an integral number of pages 23180a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral * (we round up) */ 2319883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK; 2320883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2321883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess retval = comedi_buf_alloc(dev, s, new_size); 2322883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (retval < 0) 2323883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2324883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2325883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (s->buf_change) { 2326883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess retval = s->buf_change(dev, s, new_size); 2327883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (retval < 0) 2328883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2329883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 2330883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2331883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess DPRINTK("comedi%i subd %d buffer resized to %i bytes\n", 2332b8b5cd9f87e08f72c78d9197bf199821fda4ba36Ian Abbott dev->minor, (int)(s - dev->subdevices), async->prealloc_bufsz); 2333883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return 0; 2334883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess} 2335883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2336883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess/* sysfs attribute files */ 2337883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2338883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic const unsigned bytes_per_kibi = 1024; 2339883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2340883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_max_read_buffer_kb(struct device *dev, 2341883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct device_attribute *attr, char *buf) 2342883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{ 2343883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess ssize_t retval; 2344883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_device_file_info *info = dev_get_drvdata(dev); 2345883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess unsigned max_buffer_size_kb = 0; 2346883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_subdevice *const read_subdevice = 23470a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral comedi_get_read_subdevice(info); 2348883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2349883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_lock(&info->device->mutex); 2350883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (read_subdevice && 2351883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess (read_subdevice->subdev_flags & SDF_CMD_READ) && 2352883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess read_subdevice->async) { 2353883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess max_buffer_size_kb = read_subdevice->async->max_bufsize / 23540a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral bytes_per_kibi; 2355883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 23560a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb); 2357883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_unlock(&info->device->mutex); 2358883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2359883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2360883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess} 2361883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2362883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_max_read_buffer_kb(struct device *dev, 2363883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct device_attribute *attr, 2364883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess const char *buf, size_t count) 2365883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{ 2366883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_device_file_info *info = dev_get_drvdata(dev); 2367883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess unsigned long new_max_size_kb; 2368883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess uint64_t new_max_size; 2369883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_subdevice *const read_subdevice = 23700a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral comedi_get_read_subdevice(info); 2371883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2372883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (strict_strtoul(buf, 10, &new_max_size_kb)) 2373883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 23740a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral if (new_max_size_kb != (uint32_t) new_max_size_kb) 2375883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 23760a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral new_max_size = ((uint64_t) new_max_size_kb) * bytes_per_kibi; 23770a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral if (new_max_size != (uint32_t) new_max_size) 2378883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 2379883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2380883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_lock(&info->device->mutex); 2381883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (read_subdevice == NULL || 2382883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 || 2383883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess read_subdevice->async == NULL) { 2384883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_unlock(&info->device->mutex); 2385883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 2386883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 2387883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess read_subdevice->async->max_bufsize = new_max_size; 2388883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_unlock(&info->device->mutex); 2389883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2390883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return count; 2391883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess} 2392883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2393883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_max_read_buffer_kb = { 2394883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess .attr = { 23950a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .name = "max_read_buffer_kb", 23960a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .mode = S_IRUGO | S_IWUSR}, 2397883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess .show = &show_max_read_buffer_kb, 2398883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess .store = &store_max_read_buffer_kb 2399883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}; 2400883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2401883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_read_buffer_kb(struct device *dev, 2402883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct device_attribute *attr, char *buf) 2403883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{ 2404883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess ssize_t retval; 2405883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_device_file_info *info = dev_get_drvdata(dev); 2406883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess unsigned buffer_size_kb = 0; 2407883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_subdevice *const read_subdevice = 24080a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral comedi_get_read_subdevice(info); 2409883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2410883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_lock(&info->device->mutex); 2411883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (read_subdevice && 24120a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral (read_subdevice->subdev_flags & SDF_CMD_READ) && 24130a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral read_subdevice->async) { 2414883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess buffer_size_kb = read_subdevice->async->prealloc_bufsz / 24150a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral bytes_per_kibi; 2416883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 24170a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb); 2418883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_unlock(&info->device->mutex); 2419883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2420883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2421883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess} 2422883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2423883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_read_buffer_kb(struct device *dev, 2424883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct device_attribute *attr, 2425883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess const char *buf, size_t count) 2426883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{ 2427883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_device_file_info *info = dev_get_drvdata(dev); 2428883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess unsigned long new_size_kb; 2429883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess uint64_t new_size; 2430883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess int retval; 2431883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_subdevice *const read_subdevice = 24320a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral comedi_get_read_subdevice(info); 2433883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2434883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (strict_strtoul(buf, 10, &new_size_kb)) 2435883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 24360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral if (new_size_kb != (uint32_t) new_size_kb) 2437883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 24380a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral new_size = ((uint64_t) new_size_kb) * bytes_per_kibi; 24390a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral if (new_size != (uint32_t) new_size) 2440883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 2441883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2442883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_lock(&info->device->mutex); 2443883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (read_subdevice == NULL || 2444883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 || 2445883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess read_subdevice->async == NULL) { 2446883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_unlock(&info->device->mutex); 2447883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 2448883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 2449883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess retval = resize_async_buffer(info->device, read_subdevice, 2450883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess read_subdevice->async, new_size); 2451883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_unlock(&info->device->mutex); 2452883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2453883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (retval < 0) 2454883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2455883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return count; 2456883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess} 2457883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2458883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_read_buffer_kb = { 2459883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess .attr = { 24600a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .name = "read_buffer_kb", 24610a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .mode = S_IRUGO | S_IWUSR | S_IWGRP}, 2462883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess .show = &show_read_buffer_kb, 2463883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess .store = &store_read_buffer_kb 2464883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}; 2465883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2466883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_max_write_buffer_kb(struct device *dev, 2467883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct device_attribute *attr, 2468883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess char *buf) 2469883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{ 2470883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess ssize_t retval; 2471883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_device_file_info *info = dev_get_drvdata(dev); 2472883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess unsigned max_buffer_size_kb = 0; 2473883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_subdevice *const write_subdevice = 24740a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral comedi_get_write_subdevice(info); 2475883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2476883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_lock(&info->device->mutex); 2477883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (write_subdevice && 2478883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess (write_subdevice->subdev_flags & SDF_CMD_WRITE) && 2479883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess write_subdevice->async) { 2480883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess max_buffer_size_kb = write_subdevice->async->max_bufsize / 24810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral bytes_per_kibi; 2482883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 24830a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb); 2484883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_unlock(&info->device->mutex); 2485883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2486883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2487883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess} 2488883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2489883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_max_write_buffer_kb(struct device *dev, 2490883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct device_attribute *attr, 2491883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess const char *buf, size_t count) 2492883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{ 2493883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_device_file_info *info = dev_get_drvdata(dev); 2494883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess unsigned long new_max_size_kb; 2495883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess uint64_t new_max_size; 2496883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_subdevice *const write_subdevice = 24970a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral comedi_get_write_subdevice(info); 2498883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2499883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (strict_strtoul(buf, 10, &new_max_size_kb)) 2500883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 25010a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral if (new_max_size_kb != (uint32_t) new_max_size_kb) 2502883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 25030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral new_max_size = ((uint64_t) new_max_size_kb) * bytes_per_kibi; 25040a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral if (new_max_size != (uint32_t) new_max_size) 2505883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 2506883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2507883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_lock(&info->device->mutex); 2508883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (write_subdevice == NULL || 2509883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 || 2510883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess write_subdevice->async == NULL) { 2511883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_unlock(&info->device->mutex); 2512883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 2513883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 2514883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess write_subdevice->async->max_bufsize = new_max_size; 2515883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_unlock(&info->device->mutex); 2516883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2517883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return count; 2518883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess} 2519883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2520883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_max_write_buffer_kb = { 2521883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess .attr = { 25220a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .name = "max_write_buffer_kb", 25230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .mode = S_IRUGO | S_IWUSR}, 2524883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess .show = &show_max_write_buffer_kb, 2525883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess .store = &store_max_write_buffer_kb 2526883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}; 2527883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2528883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t show_write_buffer_kb(struct device *dev, 2529883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct device_attribute *attr, char *buf) 2530883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{ 2531883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess ssize_t retval; 2532883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_device_file_info *info = dev_get_drvdata(dev); 2533883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess unsigned buffer_size_kb = 0; 2534883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_subdevice *const write_subdevice = 25350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral comedi_get_write_subdevice(info); 2536883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2537883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_lock(&info->device->mutex); 2538883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (write_subdevice && 2539883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess (write_subdevice->subdev_flags & SDF_CMD_WRITE) && 2540883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess write_subdevice->async) { 2541883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess buffer_size_kb = write_subdevice->async->prealloc_bufsz / 25420a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral bytes_per_kibi; 2543883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 25440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb); 2545883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_unlock(&info->device->mutex); 2546883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2547883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2548883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess} 2549883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2550883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic ssize_t store_write_buffer_kb(struct device *dev, 2551883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct device_attribute *attr, 2552883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess const char *buf, size_t count) 2553883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess{ 2554883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_device_file_info *info = dev_get_drvdata(dev); 2555883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess unsigned long new_size_kb; 2556883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess uint64_t new_size; 2557883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess int retval; 2558883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess struct comedi_subdevice *const write_subdevice = 25590a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral comedi_get_write_subdevice(info); 2560883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2561883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (strict_strtoul(buf, 10, &new_size_kb)) 2562883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 25630a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral if (new_size_kb != (uint32_t) new_size_kb) 2564883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 25650a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral new_size = ((uint64_t) new_size_kb) * bytes_per_kibi; 25660a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral if (new_size != (uint32_t) new_size) 2567883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 2568883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2569883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_lock(&info->device->mutex); 2570883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (write_subdevice == NULL || 2571883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 || 2572883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess write_subdevice->async == NULL) { 2573883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_unlock(&info->device->mutex); 2574883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return -EINVAL; 2575883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess } 2576883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess retval = resize_async_buffer(info->device, write_subdevice, 25770a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral write_subdevice->async, new_size); 2578883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess mutex_unlock(&info->device->mutex); 2579883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2580883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess if (retval < 0) 2581883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return retval; 2582883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess return count; 2583883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess} 2584883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess 2585883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hessstatic struct device_attribute dev_attr_write_buffer_kb = { 2586883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess .attr = { 25870a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .name = "write_buffer_kb", 25880a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral .mode = S_IRUGO | S_IWUSR | S_IWGRP}, 2589883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess .show = &show_write_buffer_kb, 2590883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess .store = &store_write_buffer_kb 2591883db3d9bb4d50f05cbb8b5197f6aef10c1231a9Frank Mori Hess}; 2592