linux/drivers/staging/comedi/comedi_fops.c
<<
>>
Prefs
   1/*
   2    comedi/comedi_fops.c
   3    comedi kernel module
   4
   5    COMEDI - Linux Control and Measurement Device Interface
   6    Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
   7
   8    This program is free software; you can redistribute it and/or modify
   9    it under the terms of the GNU General Public License as published by
  10    the Free Software Foundation; either version 2 of the License, or
  11    (at your option) any later version.
  12
  13    This program is distributed in the hope that it will be useful,
  14    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16    GNU General Public License for more details.
  17
  18    You should have received a copy of the GNU General Public License
  19    along with this program; if not, write to the Free Software
  20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21
  22*/
  23
  24#undef DEBUG
  25
  26#include "comedi_compat32.h"
  27
  28#include <linux/module.h>
  29#include <linux/errno.h>
  30#include <linux/kernel.h>
  31#include <linux/sched.h>
  32#include <linux/fcntl.h>
  33#include <linux/delay.h>
  34#include <linux/ioport.h>
  35#include <linux/mm.h>
  36#include <linux/slab.h>
  37#include <linux/kmod.h>
  38#include <linux/poll.h>
  39#include <linux/init.h>
  40#include <linux/device.h>
  41#include <linux/vmalloc.h>
  42#include <linux/fs.h>
  43#include "comedidev.h"
  44#include <linux/cdev.h>
  45#include <linux/stat.h>
  46
  47#include <linux/io.h>
  48#include <linux/uaccess.h>
  49
  50#include "comedi_internal.h"
  51
  52#define COMEDI_NUM_MINORS 0x100
  53#define COMEDI_NUM_SUBDEVICE_MINORS     \
  54        (COMEDI_NUM_MINORS - COMEDI_NUM_BOARD_MINORS)
  55
  56#ifdef CONFIG_COMEDI_DEBUG
  57int comedi_debug;
  58EXPORT_SYMBOL_GPL(comedi_debug);
  59module_param(comedi_debug, int, S_IRUGO | S_IWUSR);
  60MODULE_PARM_DESC(comedi_debug,
  61                 "enable comedi core and driver debugging if non-zero (default 0)"
  62                );
  63#endif
  64
  65static int comedi_num_legacy_minors;
  66module_param(comedi_num_legacy_minors, int, S_IRUGO);
  67MODULE_PARM_DESC(comedi_num_legacy_minors,
  68                 "number of comedi minor devices to reserve for non-auto-configured devices (default 0)"
  69                );
  70
  71unsigned int comedi_default_buf_size_kb = CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB;
  72module_param(comedi_default_buf_size_kb, uint, S_IRUGO | S_IWUSR);
  73MODULE_PARM_DESC(comedi_default_buf_size_kb,
  74                 "default asynchronous buffer size in KiB (default "
  75                 __MODULE_STRING(CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB) ")");
  76
  77unsigned int comedi_default_buf_maxsize_kb
  78        = CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB;
  79module_param(comedi_default_buf_maxsize_kb, uint, S_IRUGO | S_IWUSR);
  80MODULE_PARM_DESC(comedi_default_buf_maxsize_kb,
  81                 "default maximum size of asynchronous buffer in KiB (default "
  82                 __MODULE_STRING(CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB) ")");
  83
  84static DEFINE_MUTEX(comedi_board_minor_table_lock);
  85static struct comedi_device
  86*comedi_board_minor_table[COMEDI_NUM_BOARD_MINORS];
  87
  88static DEFINE_MUTEX(comedi_subdevice_minor_table_lock);
  89/* Note: indexed by minor - COMEDI_NUM_BOARD_MINORS. */
  90static struct comedi_subdevice
  91*comedi_subdevice_minor_table[COMEDI_NUM_SUBDEVICE_MINORS];
  92
  93static struct class *comedi_class;
  94static struct cdev comedi_cdev;
  95
  96static void comedi_device_init(struct comedi_device *dev)
  97{
  98        spin_lock_init(&dev->spinlock);
  99        mutex_init(&dev->mutex);
 100        dev->minor = -1;
 101}
 102
 103static void comedi_device_cleanup(struct comedi_device *dev)
 104{
 105        struct module *driver_module = NULL;
 106
 107        if (dev == NULL)
 108                return;
 109        mutex_lock(&dev->mutex);
 110        if (dev->attached)
 111                driver_module = dev->driver->module;
 112        comedi_device_detach(dev);
 113        while (dev->use_count > 0) {
 114                if (driver_module)
 115                        module_put(driver_module);
 116                module_put(THIS_MODULE);
 117                dev->use_count--;
 118        }
 119        mutex_unlock(&dev->mutex);
 120        mutex_destroy(&dev->mutex);
 121}
 122
 123static bool comedi_clear_board_dev(struct comedi_device *dev)
 124{
 125        unsigned int i = dev->minor;
 126        bool cleared = false;
 127
 128        mutex_lock(&comedi_board_minor_table_lock);
 129        if (dev == comedi_board_minor_table[i]) {
 130                comedi_board_minor_table[i] = NULL;
 131                cleared = true;
 132        }
 133        mutex_unlock(&comedi_board_minor_table_lock);
 134        return cleared;
 135}
 136
 137static struct comedi_device *comedi_clear_board_minor(unsigned minor)
 138{
 139        struct comedi_device *dev;
 140
 141        mutex_lock(&comedi_board_minor_table_lock);
 142        dev = comedi_board_minor_table[minor];
 143        comedi_board_minor_table[minor] = NULL;
 144        mutex_unlock(&comedi_board_minor_table_lock);
 145        return dev;
 146}
 147
 148static void comedi_free_board_dev(struct comedi_device *dev)
 149{
 150        if (dev) {
 151                if (dev->class_dev) {
 152                        device_destroy(comedi_class,
 153                                       MKDEV(COMEDI_MAJOR, dev->minor));
 154                }
 155                comedi_device_cleanup(dev);
 156                kfree(dev);
 157        }
 158}
 159
 160static struct comedi_subdevice
 161*comedi_subdevice_from_minor(unsigned minor)
 162{
 163        struct comedi_subdevice *s;
 164        unsigned int i = minor - COMEDI_NUM_BOARD_MINORS;
 165
 166        BUG_ON(i >= COMEDI_NUM_SUBDEVICE_MINORS);
 167        mutex_lock(&comedi_subdevice_minor_table_lock);
 168        s = comedi_subdevice_minor_table[i];
 169        mutex_unlock(&comedi_subdevice_minor_table_lock);
 170        return s;
 171}
 172
 173static struct comedi_device *comedi_dev_from_board_minor(unsigned minor)
 174{
 175        struct comedi_device *dev;
 176
 177        BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
 178        mutex_lock(&comedi_board_minor_table_lock);
 179        dev = comedi_board_minor_table[minor];
 180        mutex_unlock(&comedi_board_minor_table_lock);
 181        return dev;
 182}
 183
 184static struct comedi_device *comedi_dev_from_subdevice_minor(unsigned minor)
 185{
 186        struct comedi_subdevice *s;
 187
 188        s = comedi_subdevice_from_minor(minor);
 189        return s ? s->device : NULL;
 190}
 191
 192struct comedi_device *comedi_dev_from_minor(unsigned minor)
 193{
 194        if (minor < COMEDI_NUM_BOARD_MINORS)
 195                return comedi_dev_from_board_minor(minor);
 196        else
 197                return comedi_dev_from_subdevice_minor(minor);
 198}
 199EXPORT_SYMBOL_GPL(comedi_dev_from_minor);
 200
 201static struct comedi_subdevice *
 202comedi_read_subdevice(const struct comedi_device *dev, unsigned int minor)
 203{
 204        struct comedi_subdevice *s;
 205
 206        if (minor >= COMEDI_NUM_BOARD_MINORS) {
 207                s = comedi_subdevice_from_minor(minor);
 208                if (!s || s->device != dev)
 209                        return NULL;
 210                if (s->subdev_flags & SDF_CMD_READ)
 211                        return s;
 212        }
 213        return dev->read_subdev;
 214}
 215
 216static struct comedi_subdevice *
 217comedi_write_subdevice(const struct comedi_device *dev, unsigned int minor)
 218{
 219        struct comedi_subdevice *s;
 220
 221        if (minor >= COMEDI_NUM_BOARD_MINORS) {
 222                s = comedi_subdevice_from_minor(minor);
 223                if (!s || s->device != dev)
 224                        return NULL;
 225                if (s->subdev_flags & SDF_CMD_WRITE)
 226                        return s;
 227        }
 228        return dev->write_subdev;
 229}
 230
 231static int resize_async_buffer(struct comedi_device *dev,
 232                               struct comedi_subdevice *s,
 233                               struct comedi_async *async, unsigned new_size)
 234{
 235        int retval;
 236
 237        if (new_size > async->max_bufsize)
 238                return -EPERM;
 239
 240        if (s->busy) {
 241                DPRINTK("subdevice is busy, cannot resize buffer\n");
 242                return -EBUSY;
 243        }
 244        if (async->mmap_count) {
 245                DPRINTK("subdevice is mmapped, cannot resize buffer\n");
 246                return -EBUSY;
 247        }
 248
 249        /* make sure buffer is an integral number of pages
 250         * (we round up) */
 251        new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
 252
 253        retval = comedi_buf_alloc(dev, s, new_size);
 254        if (retval < 0)
 255                return retval;
 256
 257        if (s->buf_change) {
 258                retval = s->buf_change(dev, s, new_size);
 259                if (retval < 0)
 260                        return retval;
 261        }
 262
 263        DPRINTK("comedi%i subd %d buffer resized to %i bytes\n",
 264                dev->minor, s->index, async->prealloc_bufsz);
 265        return 0;
 266}
 267
 268/* sysfs attribute files */
 269
 270static ssize_t show_max_read_buffer_kb(struct device *csdev,
 271                                       struct device_attribute *attr, char *buf)
 272{
 273        unsigned int minor = MINOR(csdev->devt);
 274        struct comedi_device *dev;
 275        struct comedi_subdevice *s;
 276        unsigned int size = 0;
 277
 278        dev = comedi_dev_from_minor(minor);
 279        if (!dev)
 280                return -ENODEV;
 281
 282        mutex_lock(&dev->mutex);
 283        s = comedi_read_subdevice(dev, minor);
 284        if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
 285                size = s->async->max_bufsize / 1024;
 286        mutex_unlock(&dev->mutex);
 287
 288        return snprintf(buf, PAGE_SIZE, "%i\n", size);
 289}
 290
 291static ssize_t store_max_read_buffer_kb(struct device *csdev,
 292                                        struct device_attribute *attr,
 293                                        const char *buf, size_t count)
 294{
 295        unsigned int minor = MINOR(csdev->devt);
 296        struct comedi_device *dev;
 297        struct comedi_subdevice *s;
 298        unsigned int size;
 299        int err;
 300
 301        err = kstrtouint(buf, 10, &size);
 302        if (err)
 303                return err;
 304        if (size > (UINT_MAX / 1024))
 305                return -EINVAL;
 306        size *= 1024;
 307
 308        dev = comedi_dev_from_minor(minor);
 309        if (!dev)
 310                return -ENODEV;
 311
 312        mutex_lock(&dev->mutex);
 313        s = comedi_read_subdevice(dev, minor);
 314        if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
 315                s->async->max_bufsize = size;
 316        else
 317                err = -EINVAL;
 318        mutex_unlock(&dev->mutex);
 319
 320        return err ? err : count;
 321}
 322
 323static ssize_t show_read_buffer_kb(struct device *csdev,
 324                                   struct device_attribute *attr, char *buf)
 325{
 326        unsigned int minor = MINOR(csdev->devt);
 327        struct comedi_device *dev;
 328        struct comedi_subdevice *s;
 329        unsigned int size = 0;
 330
 331        dev = comedi_dev_from_minor(minor);
 332        if (!dev)
 333                return -ENODEV;
 334
 335        mutex_lock(&dev->mutex);
 336        s = comedi_read_subdevice(dev, minor);
 337        if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
 338                size = s->async->prealloc_bufsz / 1024;
 339        mutex_unlock(&dev->mutex);
 340
 341        return snprintf(buf, PAGE_SIZE, "%i\n", size);
 342}
 343
 344static ssize_t store_read_buffer_kb(struct device *csdev,
 345                                    struct device_attribute *attr,
 346                                    const char *buf, size_t count)
 347{
 348        unsigned int minor = MINOR(csdev->devt);
 349        struct comedi_device *dev;
 350        struct comedi_subdevice *s;
 351        unsigned int size;
 352        int err;
 353
 354        err = kstrtouint(buf, 10, &size);
 355        if (err)
 356                return err;
 357        if (size > (UINT_MAX / 1024))
 358                return -EINVAL;
 359        size *= 1024;
 360
 361        dev = comedi_dev_from_minor(minor);
 362        if (!dev)
 363                return -ENODEV;
 364
 365        mutex_lock(&dev->mutex);
 366        s = comedi_read_subdevice(dev, minor);
 367        if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
 368                err = resize_async_buffer(dev, s, s->async, size);
 369        else
 370                err = -EINVAL;
 371        mutex_unlock(&dev->mutex);
 372
 373        return err ? err : count;
 374}
 375
 376static ssize_t show_max_write_buffer_kb(struct device *csdev,
 377                                        struct device_attribute *attr,
 378                                        char *buf)
 379{
 380        unsigned int minor = MINOR(csdev->devt);
 381        struct comedi_device *dev;
 382        struct comedi_subdevice *s;
 383        unsigned int size = 0;
 384
 385        dev = comedi_dev_from_minor(minor);
 386        if (!dev)
 387                return -ENODEV;
 388
 389        mutex_lock(&dev->mutex);
 390        s = comedi_write_subdevice(dev, minor);
 391        if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
 392                size = s->async->max_bufsize / 1024;
 393        mutex_unlock(&dev->mutex);
 394
 395        return snprintf(buf, PAGE_SIZE, "%i\n", size);
 396}
 397
 398static ssize_t store_max_write_buffer_kb(struct device *csdev,
 399                                         struct device_attribute *attr,
 400                                         const char *buf, size_t count)
 401{
 402        unsigned int minor = MINOR(csdev->devt);
 403        struct comedi_device *dev;
 404        struct comedi_subdevice *s;
 405        unsigned int size;
 406        int err;
 407
 408        err = kstrtouint(buf, 10, &size);
 409        if (err)
 410                return err;
 411        if (size > (UINT_MAX / 1024))
 412                return -EINVAL;
 413        size *= 1024;
 414
 415        dev = comedi_dev_from_minor(minor);
 416        if (!dev)
 417                return -ENODEV;
 418
 419        mutex_lock(&dev->mutex);
 420        s = comedi_write_subdevice(dev, minor);
 421        if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
 422                s->async->max_bufsize = size;
 423        else
 424                err = -EINVAL;
 425        mutex_unlock(&dev->mutex);
 426
 427        return err ? err : count;
 428}
 429
 430static ssize_t show_write_buffer_kb(struct device *csdev,
 431                                    struct device_attribute *attr, char *buf)
 432{
 433        unsigned int minor = MINOR(csdev->devt);
 434        struct comedi_device *dev;
 435        struct comedi_subdevice *s;
 436        unsigned int size = 0;
 437
 438        dev = comedi_dev_from_minor(minor);
 439        if (!dev)
 440                return -ENODEV;
 441
 442        mutex_lock(&dev->mutex);
 443        s = comedi_write_subdevice(dev, minor);
 444        if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
 445                size = s->async->prealloc_bufsz / 1024;
 446        mutex_unlock(&dev->mutex);
 447
 448        return snprintf(buf, PAGE_SIZE, "%i\n", size);
 449}
 450
 451static ssize_t store_write_buffer_kb(struct device *csdev,
 452                                     struct device_attribute *attr,
 453                                     const char *buf, size_t count)
 454{
 455        unsigned int minor = MINOR(csdev->devt);
 456        struct comedi_device *dev;
 457        struct comedi_subdevice *s;
 458        unsigned int size;
 459        int err;
 460
 461        err = kstrtouint(buf, 10, &size);
 462        if (err)
 463                return err;
 464        if (size > (UINT_MAX / 1024))
 465                return -EINVAL;
 466        size *= 1024;
 467
 468        dev = comedi_dev_from_minor(minor);
 469        if (!dev)
 470                return -ENODEV;
 471
 472        mutex_lock(&dev->mutex);
 473        s = comedi_write_subdevice(dev, minor);
 474        if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
 475                err = resize_async_buffer(dev, s, s->async, size);
 476        else
 477                err = -EINVAL;
 478        mutex_unlock(&dev->mutex);
 479
 480        return err ? err : count;
 481}
 482
 483static struct device_attribute comedi_dev_attrs[] = {
 484        __ATTR(max_read_buffer_kb, S_IRUGO | S_IWUSR,
 485                show_max_read_buffer_kb, store_max_read_buffer_kb),
 486        __ATTR(read_buffer_kb, S_IRUGO | S_IWUSR | S_IWGRP,
 487                show_read_buffer_kb, store_read_buffer_kb),
 488        __ATTR(max_write_buffer_kb, S_IRUGO | S_IWUSR,
 489                show_max_write_buffer_kb, store_max_write_buffer_kb),
 490        __ATTR(write_buffer_kb, S_IRUGO | S_IWUSR | S_IWGRP,
 491                show_write_buffer_kb, store_write_buffer_kb),
 492        __ATTR_NULL
 493};
 494
 495static void comedi_set_subdevice_runflags(struct comedi_subdevice *s,
 496                                          unsigned mask, unsigned bits)
 497{
 498        unsigned long flags;
 499
 500        spin_lock_irqsave(&s->spin_lock, flags);
 501        s->runflags &= ~mask;
 502        s->runflags |= (bits & mask);
 503        spin_unlock_irqrestore(&s->spin_lock, flags);
 504}
 505
 506static unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s)
 507{
 508        unsigned long flags;
 509        unsigned runflags;
 510
 511        spin_lock_irqsave(&s->spin_lock, flags);
 512        runflags = s->runflags;
 513        spin_unlock_irqrestore(&s->spin_lock, flags);
 514        return runflags;
 515}
 516
 517bool comedi_is_subdevice_running(struct comedi_subdevice *s)
 518{
 519        unsigned runflags = comedi_get_subdevice_runflags(s);
 520
 521        return (runflags & SRF_RUNNING) ? true : false;
 522}
 523EXPORT_SYMBOL_GPL(comedi_is_subdevice_running);
 524
 525static bool comedi_is_subdevice_in_error(struct comedi_subdevice *s)
 526{
 527        unsigned runflags = comedi_get_subdevice_runflags(s);
 528
 529        return (runflags & SRF_ERROR) ? true : false;
 530}
 531
 532static bool comedi_is_subdevice_idle(struct comedi_subdevice *s)
 533{
 534        unsigned runflags = comedi_get_subdevice_runflags(s);
 535
 536        return (runflags & (SRF_ERROR | SRF_RUNNING)) ? false : true;
 537}
 538
 539/*
 540   This function restores a subdevice to an idle state.
 541 */
 542static void do_become_nonbusy(struct comedi_device *dev,
 543                              struct comedi_subdevice *s)
 544{
 545        struct comedi_async *async = s->async;
 546
 547        comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
 548        if (async) {
 549                comedi_buf_reset(async);
 550                async->inttrig = NULL;
 551                kfree(async->cmd.chanlist);
 552                async->cmd.chanlist = NULL;
 553        } else {
 554                dev_err(dev->class_dev,
 555                        "BUG: (?) do_become_nonbusy called with async=NULL\n");
 556        }
 557
 558        s->busy = NULL;
 559}
 560
 561static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
 562{
 563        int ret = 0;
 564
 565        if (comedi_is_subdevice_running(s) && s->cancel)
 566                ret = s->cancel(dev, s);
 567
 568        do_become_nonbusy(dev, s);
 569
 570        return ret;
 571}
 572
 573static int is_device_busy(struct comedi_device *dev)
 574{
 575        struct comedi_subdevice *s;
 576        int i;
 577
 578        if (!dev->attached)
 579                return 0;
 580
 581        for (i = 0; i < dev->n_subdevices; i++) {
 582                s = &dev->subdevices[i];
 583                if (s->busy)
 584                        return 1;
 585                if (s->async && s->async->mmap_count)
 586                        return 1;
 587        }
 588
 589        return 0;
 590}
 591
 592/*
 593        COMEDI_DEVCONFIG
 594        device config ioctl
 595
 596        arg:
 597                pointer to devconfig structure
 598
 599        reads:
 600                devconfig structure at arg
 601
 602        writes:
 603                none
 604*/
 605static int do_devconfig_ioctl(struct comedi_device *dev,
 606                              struct comedi_devconfig __user *arg)
 607{
 608        struct comedi_devconfig it;
 609
 610        if (!capable(CAP_SYS_ADMIN))
 611                return -EPERM;
 612
 613        if (arg == NULL) {
 614                if (is_device_busy(dev))
 615                        return -EBUSY;
 616                if (dev->attached) {
 617                        struct module *driver_module = dev->driver->module;
 618                        comedi_device_detach(dev);
 619                        module_put(driver_module);
 620                }
 621                return 0;
 622        }
 623
 624        if (copy_from_user(&it, arg, sizeof(it)))
 625                return -EFAULT;
 626
 627        it.board_name[COMEDI_NAMELEN - 1] = 0;
 628
 629        if (it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
 630                dev_warn(dev->class_dev,
 631                         "comedi_config --init_data is deprecated\n");
 632                return -EINVAL;
 633        }
 634
 635        if (dev->minor >= comedi_num_legacy_minors)
 636                /* don't re-use dynamically allocated comedi devices */
 637                return -EBUSY;
 638
 639        /* This increments the driver module count on success. */
 640        return comedi_device_attach(dev, &it);
 641}
 642
 643/*
 644        COMEDI_BUFCONFIG
 645        buffer configuration ioctl
 646
 647        arg:
 648                pointer to bufconfig structure
 649
 650        reads:
 651                bufconfig at arg
 652
 653        writes:
 654                modified bufconfig at arg
 655
 656*/
 657static int do_bufconfig_ioctl(struct comedi_device *dev,
 658                              struct comedi_bufconfig __user *arg)
 659{
 660        struct comedi_bufconfig bc;
 661        struct comedi_async *async;
 662        struct comedi_subdevice *s;
 663        int retval = 0;
 664
 665        if (copy_from_user(&bc, arg, sizeof(bc)))
 666                return -EFAULT;
 667
 668        if (bc.subdevice >= dev->n_subdevices || bc.subdevice < 0)
 669                return -EINVAL;
 670
 671        s = &dev->subdevices[bc.subdevice];
 672        async = s->async;
 673
 674        if (!async) {
 675                DPRINTK("subdevice does not have async capability\n");
 676                bc.size = 0;
 677                bc.maximum_size = 0;
 678                goto copyback;
 679        }
 680
 681        if (bc.maximum_size) {
 682                if (!capable(CAP_SYS_ADMIN))
 683                        return -EPERM;
 684
 685                async->max_bufsize = bc.maximum_size;
 686        }
 687
 688        if (bc.size) {
 689                retval = resize_async_buffer(dev, s, async, bc.size);
 690                if (retval < 0)
 691                        return retval;
 692        }
 693
 694        bc.size = async->prealloc_bufsz;
 695        bc.maximum_size = async->max_bufsize;
 696
 697copyback:
 698        if (copy_to_user(arg, &bc, sizeof(bc)))
 699                return -EFAULT;
 700
 701        return 0;
 702}
 703
 704/*
 705        COMEDI_DEVINFO
 706        device info ioctl
 707
 708        arg:
 709                pointer to devinfo structure
 710
 711        reads:
 712                none
 713
 714        writes:
 715                devinfo structure
 716
 717*/
 718static int do_devinfo_ioctl(struct comedi_device *dev,
 719                            struct comedi_devinfo __user *arg,
 720                            struct file *file)
 721{
 722        const unsigned minor = iminor(file_inode(file));
 723        struct comedi_subdevice *s;
 724        struct comedi_devinfo devinfo;
 725
 726        memset(&devinfo, 0, sizeof(devinfo));
 727
 728        /* fill devinfo structure */
 729        devinfo.version_code = COMEDI_VERSION_CODE;
 730        devinfo.n_subdevs = dev->n_subdevices;
 731        strlcpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN);
 732        strlcpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN);
 733
 734        s = comedi_read_subdevice(dev, minor);
 735        if (s)
 736                devinfo.read_subdevice = s->index;
 737        else
 738                devinfo.read_subdevice = -1;
 739
 740        s = comedi_write_subdevice(dev, minor);
 741        if (s)
 742                devinfo.write_subdevice = s->index;
 743        else
 744                devinfo.write_subdevice = -1;
 745
 746        if (copy_to_user(arg, &devinfo, sizeof(devinfo)))
 747                return -EFAULT;
 748
 749        return 0;
 750}
 751
 752/*
 753        COMEDI_SUBDINFO
 754        subdevice info ioctl
 755
 756        arg:
 757                pointer to array of subdevice info structures
 758
 759        reads:
 760                none
 761
 762        writes:
 763                array of subdevice info structures at arg
 764
 765*/
 766static int do_subdinfo_ioctl(struct comedi_device *dev,
 767                             struct comedi_subdinfo __user *arg, void *file)
 768{
 769        int ret, i;
 770        struct comedi_subdinfo *tmp, *us;
 771        struct comedi_subdevice *s;
 772
 773        tmp = kcalloc(dev->n_subdevices, sizeof(*tmp), GFP_KERNEL);
 774        if (!tmp)
 775                return -ENOMEM;
 776
 777        /* fill subdinfo structs */
 778        for (i = 0; i < dev->n_subdevices; i++) {
 779                s = &dev->subdevices[i];
 780                us = tmp + i;
 781
 782                us->type = s->type;
 783                us->n_chan = s->n_chan;
 784                us->subd_flags = s->subdev_flags;
 785                if (comedi_is_subdevice_running(s))
 786                        us->subd_flags |= SDF_RUNNING;
 787#define TIMER_nanosec 5         /* backwards compatibility */
 788                us->timer_type = TIMER_nanosec;
 789                us->len_chanlist = s->len_chanlist;
 790                us->maxdata = s->maxdata;
 791                if (s->range_table) {
 792                        us->range_type =
 793                            (i << 24) | (0 << 16) | (s->range_table->length);
 794                } else {
 795                        us->range_type = 0;     /* XXX */
 796                }
 797                us->flags = s->flags;
 798
 799                if (s->busy)
 800                        us->subd_flags |= SDF_BUSY;
 801                if (s->busy == file)
 802                        us->subd_flags |= SDF_BUSY_OWNER;
 803                if (s->lock)
 804                        us->subd_flags |= SDF_LOCKED;
 805                if (s->lock == file)
 806                        us->subd_flags |= SDF_LOCK_OWNER;
 807                if (!s->maxdata && s->maxdata_list)
 808                        us->subd_flags |= SDF_MAXDATA;
 809                if (s->flaglist)
 810                        us->subd_flags |= SDF_FLAGS;
 811                if (s->range_table_list)
 812                        us->subd_flags |= SDF_RANGETYPE;
 813                if (s->do_cmd)
 814                        us->subd_flags |= SDF_CMD;
 815
 816                if (s->insn_bits != &insn_inval)
 817                        us->insn_bits_support = COMEDI_SUPPORTED;
 818                else
 819                        us->insn_bits_support = COMEDI_UNSUPPORTED;
 820
 821                us->settling_time_0 = s->settling_time_0;
 822        }
 823
 824        ret = copy_to_user(arg, tmp, dev->n_subdevices * sizeof(*tmp));
 825
 826        kfree(tmp);
 827
 828        return ret ? -EFAULT : 0;
 829}
 830
 831/*
 832        COMEDI_CHANINFO
 833        subdevice info ioctl
 834
 835        arg:
 836                pointer to chaninfo structure
 837
 838        reads:
 839                chaninfo structure at arg
 840
 841        writes:
 842                arrays at elements of chaninfo structure
 843
 844*/
 845static int do_chaninfo_ioctl(struct comedi_device *dev,
 846                             struct comedi_chaninfo __user *arg)
 847{
 848        struct comedi_subdevice *s;
 849        struct comedi_chaninfo it;
 850
 851        if (copy_from_user(&it, arg, sizeof(it)))
 852                return -EFAULT;
 853
 854        if (it.subdev >= dev->n_subdevices)
 855                return -EINVAL;
 856        s = &dev->subdevices[it.subdev];
 857
 858        if (it.maxdata_list) {
 859                if (s->maxdata || !s->maxdata_list)
 860                        return -EINVAL;
 861                if (copy_to_user(it.maxdata_list, s->maxdata_list,
 862                                 s->n_chan * sizeof(unsigned int)))
 863                        return -EFAULT;
 864        }
 865
 866        if (it.flaglist) {
 867                if (!s->flaglist)
 868                        return -EINVAL;
 869                if (copy_to_user(it.flaglist, s->flaglist,
 870                                 s->n_chan * sizeof(unsigned int)))
 871                        return -EFAULT;
 872        }
 873
 874        if (it.rangelist) {
 875                int i;
 876
 877                if (!s->range_table_list)
 878                        return -EINVAL;
 879                for (i = 0; i < s->n_chan; i++) {
 880                        int x;
 881
 882                        x = (dev->minor << 28) | (it.subdev << 24) | (i << 16) |
 883                            (s->range_table_list[i]->length);
 884                        if (put_user(x, it.rangelist + i))
 885                                return -EFAULT;
 886                }
 887#if 0
 888                if (copy_to_user(it.rangelist, s->range_type_list,
 889                                 s->n_chan * sizeof(unsigned int)))
 890                        return -EFAULT;
 891#endif
 892        }
 893
 894        return 0;
 895}
 896
 897 /*
 898    COMEDI_BUFINFO
 899    buffer information ioctl
 900
 901    arg:
 902    pointer to bufinfo structure
 903
 904    reads:
 905    bufinfo at arg
 906
 907    writes:
 908    modified bufinfo at arg
 909
 910  */
 911static int do_bufinfo_ioctl(struct comedi_device *dev,
 912                            struct comedi_bufinfo __user *arg, void *file)
 913{
 914        struct comedi_bufinfo bi;
 915        struct comedi_subdevice *s;
 916        struct comedi_async *async;
 917
 918        if (copy_from_user(&bi, arg, sizeof(bi)))
 919                return -EFAULT;
 920
 921        if (bi.subdevice >= dev->n_subdevices || bi.subdevice < 0)
 922                return -EINVAL;
 923
 924        s = &dev->subdevices[bi.subdevice];
 925
 926        if (s->lock && s->lock != file)
 927                return -EACCES;
 928
 929        async = s->async;
 930
 931        if (!async) {
 932                DPRINTK("subdevice does not have async capability\n");
 933                bi.buf_write_ptr = 0;
 934                bi.buf_read_ptr = 0;
 935                bi.buf_write_count = 0;
 936                bi.buf_read_count = 0;
 937                bi.bytes_read = 0;
 938                bi.bytes_written = 0;
 939                goto copyback;
 940        }
 941        if (!s->busy) {
 942                bi.bytes_read = 0;
 943                bi.bytes_written = 0;
 944                goto copyback_position;
 945        }
 946        if (s->busy != file)
 947                return -EACCES;
 948
 949        if (bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)) {
 950                bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read);
 951                comedi_buf_read_free(async, bi.bytes_read);
 952
 953                if (comedi_is_subdevice_idle(s) &&
 954                    async->buf_write_count == async->buf_read_count) {
 955                        do_become_nonbusy(dev, s);
 956                }
 957        }
 958
 959        if (bi.bytes_written && (s->subdev_flags & SDF_CMD_WRITE)) {
 960                bi.bytes_written =
 961                    comedi_buf_write_alloc(async, bi.bytes_written);
 962                comedi_buf_write_free(async, bi.bytes_written);
 963        }
 964
 965copyback_position:
 966        bi.buf_write_count = async->buf_write_count;
 967        bi.buf_write_ptr = async->buf_write_ptr;
 968        bi.buf_read_count = async->buf_read_count;
 969        bi.buf_read_ptr = async->buf_read_ptr;
 970
 971copyback:
 972        if (copy_to_user(arg, &bi, sizeof(bi)))
 973                return -EFAULT;
 974
 975        return 0;
 976}
 977
 978static int check_insn_config_length(struct comedi_insn *insn,
 979                                    unsigned int *data)
 980{
 981        if (insn->n < 1)
 982                return -EINVAL;
 983
 984        switch (data[0]) {
 985        case INSN_CONFIG_DIO_OUTPUT:
 986        case INSN_CONFIG_DIO_INPUT:
 987        case INSN_CONFIG_DISARM:
 988        case INSN_CONFIG_RESET:
 989                if (insn->n == 1)
 990                        return 0;
 991                break;
 992        case INSN_CONFIG_ARM:
 993        case INSN_CONFIG_DIO_QUERY:
 994        case INSN_CONFIG_BLOCK_SIZE:
 995        case INSN_CONFIG_FILTER:
 996        case INSN_CONFIG_SERIAL_CLOCK:
 997        case INSN_CONFIG_BIDIRECTIONAL_DATA:
 998        case INSN_CONFIG_ALT_SOURCE:
 999        case INSN_CONFIG_SET_COUNTER_MODE:
1000        case INSN_CONFIG_8254_READ_STATUS:
1001        case INSN_CONFIG_SET_ROUTING:
1002        case INSN_CONFIG_GET_ROUTING:
1003        case INSN_CONFIG_GET_PWM_STATUS:
1004        case INSN_CONFIG_PWM_SET_PERIOD:
1005        case INSN_CONFIG_PWM_GET_PERIOD:
1006                if (insn->n == 2)
1007                        return 0;
1008                break;
1009        case INSN_CONFIG_SET_GATE_SRC:
1010        case INSN_CONFIG_GET_GATE_SRC:
1011        case INSN_CONFIG_SET_CLOCK_SRC:
1012        case INSN_CONFIG_GET_CLOCK_SRC:
1013        case INSN_CONFIG_SET_OTHER_SRC:
1014        case INSN_CONFIG_GET_COUNTER_STATUS:
1015        case INSN_CONFIG_PWM_SET_H_BRIDGE:
1016        case INSN_CONFIG_PWM_GET_H_BRIDGE:
1017        case INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE:
1018                if (insn->n == 3)
1019                        return 0;
1020                break;
1021        case INSN_CONFIG_PWM_OUTPUT:
1022        case INSN_CONFIG_ANALOG_TRIG:
1023                if (insn->n == 5)
1024                        return 0;
1025                break;
1026        case INSN_CONFIG_DIGITAL_TRIG:
1027                if (insn->n == 6)
1028                        return 0;
1029                break;
1030                /* by default we allow the insn since we don't have checks for
1031                 * all possible cases yet */
1032        default:
1033                pr_warn("comedi: No check for data length of config insn id %i is implemented.\n",
1034                        data[0]);
1035                pr_warn("comedi: Add a check to %s in %s.\n",
1036                        __func__, __FILE__);
1037                pr_warn("comedi: Assuming n=%i is correct.\n", insn->n);
1038                return 0;
1039        }
1040        return -EINVAL;
1041}
1042
1043static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
1044                      unsigned int *data, void *file)
1045{
1046        struct comedi_subdevice *s;
1047        int ret = 0;
1048        int i;
1049
1050        if (insn->insn & INSN_MASK_SPECIAL) {
1051                /* a non-subdevice instruction */
1052
1053                switch (insn->insn) {
1054                case INSN_GTOD:
1055                        {
1056                                struct timeval tv;
1057
1058                                if (insn->n != 2) {
1059                                        ret = -EINVAL;
1060                                        break;
1061                                }
1062
1063                                do_gettimeofday(&tv);
1064                                data[0] = tv.tv_sec;
1065                                data[1] = tv.tv_usec;
1066                                ret = 2;
1067
1068                                break;
1069                        }
1070                case INSN_WAIT:
1071                        if (insn->n != 1 || data[0] >= 100000) {
1072                                ret = -EINVAL;
1073                                break;
1074                        }
1075                        udelay(data[0] / 1000);
1076                        ret = 1;
1077                        break;
1078                case INSN_INTTRIG:
1079                        if (insn->n != 1) {
1080                                ret = -EINVAL;
1081                                break;
1082                        }
1083                        if (insn->subdev >= dev->n_subdevices) {
1084                                DPRINTK("%d not usable subdevice\n",
1085                                        insn->subdev);
1086                                ret = -EINVAL;
1087                                break;
1088                        }
1089                        s = &dev->subdevices[insn->subdev];
1090                        if (!s->async) {
1091                                DPRINTK("no async\n");
1092                                ret = -EINVAL;
1093                                break;
1094                        }
1095                        if (!s->async->inttrig) {
1096                                DPRINTK("no inttrig\n");
1097                                ret = -EAGAIN;
1098                                break;
1099                        }
1100                        ret = s->async->inttrig(dev, s, data[0]);
1101                        if (ret >= 0)
1102                                ret = 1;
1103                        break;
1104                default:
1105                        DPRINTK("invalid insn\n");
1106                        ret = -EINVAL;
1107                        break;
1108                }
1109        } else {
1110                /* a subdevice instruction */
1111                unsigned int maxdata;
1112
1113                if (insn->subdev >= dev->n_subdevices) {
1114                        DPRINTK("subdevice %d out of range\n", insn->subdev);
1115                        ret = -EINVAL;
1116                        goto out;
1117                }
1118                s = &dev->subdevices[insn->subdev];
1119
1120                if (s->type == COMEDI_SUBD_UNUSED) {
1121                        DPRINTK("%d not usable subdevice\n", insn->subdev);
1122                        ret = -EIO;
1123                        goto out;
1124                }
1125
1126                /* are we locked? (ioctl lock) */
1127                if (s->lock && s->lock != file) {
1128                        DPRINTK("device locked\n");
1129                        ret = -EACCES;
1130                        goto out;
1131                }
1132
1133                ret = comedi_check_chanlist(s, 1, &insn->chanspec);
1134                if (ret < 0) {
1135                        ret = -EINVAL;
1136                        DPRINTK("bad chanspec\n");
1137                        goto out;
1138                }
1139
1140                if (s->busy) {
1141                        ret = -EBUSY;
1142                        goto out;
1143                }
1144                /* This looks arbitrary.  It is. */
1145                s->busy = &parse_insn;
1146                switch (insn->insn) {
1147                case INSN_READ:
1148                        ret = s->insn_read(dev, s, insn, data);
1149                        break;
1150                case INSN_WRITE:
1151                        maxdata = s->maxdata_list
1152                            ? s->maxdata_list[CR_CHAN(insn->chanspec)]
1153                            : s->maxdata;
1154                        for (i = 0; i < insn->n; ++i) {
1155                                if (data[i] > maxdata) {
1156                                        ret = -EINVAL;
1157                                        DPRINTK("bad data value(s)\n");
1158                                        break;
1159                                }
1160                        }
1161                        if (ret == 0)
1162                                ret = s->insn_write(dev, s, insn, data);
1163                        break;
1164                case INSN_BITS:
1165                        if (insn->n != 2) {
1166                                ret = -EINVAL;
1167                        } else {
1168                                /* Most drivers ignore the base channel in
1169                                 * insn->chanspec.  Fix this here if
1170                                 * the subdevice has <= 32 channels.  */
1171                                unsigned int shift;
1172                                unsigned int orig_mask;
1173
1174                                orig_mask = data[0];
1175                                if (s->n_chan <= 32) {
1176                                        shift = CR_CHAN(insn->chanspec);
1177                                        if (shift > 0) {
1178                                                insn->chanspec = 0;
1179                                                data[0] <<= shift;
1180                                                data[1] <<= shift;
1181                                        }
1182                                } else
1183                                        shift = 0;
1184                                ret = s->insn_bits(dev, s, insn, data);
1185                                data[0] = orig_mask;
1186                                if (shift > 0)
1187                                        data[1] >>= shift;
1188                        }
1189                        break;
1190                case INSN_CONFIG:
1191                        ret = check_insn_config_length(insn, data);
1192                        if (ret)
1193                                break;
1194                        ret = s->insn_config(dev, s, insn, data);
1195                        break;
1196                default:
1197                        ret = -EINVAL;
1198                        break;
1199                }
1200
1201                s->busy = NULL;
1202        }
1203
1204out:
1205        return ret;
1206}
1207
1208/*
1209 *      COMEDI_INSNLIST
1210 *      synchronous instructions
1211 *
1212 *      arg:
1213 *              pointer to sync cmd structure
1214 *
1215 *      reads:
1216 *              sync cmd struct at arg
1217 *              instruction list
1218 *              data (for writes)
1219 *
1220 *      writes:
1221 *              data (for reads)
1222 */
1223/* arbitrary limits */
1224#define MAX_SAMPLES 256
1225static int do_insnlist_ioctl(struct comedi_device *dev,
1226                             struct comedi_insnlist __user *arg, void *file)
1227{
1228        struct comedi_insnlist insnlist;
1229        struct comedi_insn *insns = NULL;
1230        unsigned int *data = NULL;
1231        int i = 0;
1232        int ret = 0;
1233
1234        if (copy_from_user(&insnlist, arg, sizeof(insnlist)))
1235                return -EFAULT;
1236
1237        data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
1238        if (!data) {
1239                DPRINTK("kmalloc failed\n");
1240                ret = -ENOMEM;
1241                goto error;
1242        }
1243
1244        insns = kcalloc(insnlist.n_insns, sizeof(*insns), GFP_KERNEL);
1245        if (!insns) {
1246                DPRINTK("kmalloc failed\n");
1247                ret = -ENOMEM;
1248                goto error;
1249        }
1250
1251        if (copy_from_user(insns, insnlist.insns,
1252                           sizeof(*insns) * insnlist.n_insns)) {
1253                DPRINTK("copy_from_user failed\n");
1254                ret = -EFAULT;
1255                goto error;
1256        }
1257
1258        for (i = 0; i < insnlist.n_insns; i++) {
1259                if (insns[i].n > MAX_SAMPLES) {
1260                        DPRINTK("number of samples too large\n");
1261                        ret = -EINVAL;
1262                        goto error;
1263                }
1264                if (insns[i].insn & INSN_MASK_WRITE) {
1265                        if (copy_from_user(data, insns[i].data,
1266                                           insns[i].n * sizeof(unsigned int))) {
1267                                DPRINTK("copy_from_user failed\n");
1268                                ret = -EFAULT;
1269                                goto error;
1270                        }
1271                }
1272                ret = parse_insn(dev, insns + i, data, file);
1273                if (ret < 0)
1274                        goto error;
1275                if (insns[i].insn & INSN_MASK_READ) {
1276                        if (copy_to_user(insns[i].data, data,
1277                                         insns[i].n * sizeof(unsigned int))) {
1278                                DPRINTK("copy_to_user failed\n");
1279                                ret = -EFAULT;
1280                                goto error;
1281                        }
1282                }
1283                if (need_resched())
1284                        schedule();
1285        }
1286
1287error:
1288        kfree(insns);
1289        kfree(data);
1290
1291        if (ret < 0)
1292                return ret;
1293        return i;
1294}
1295
1296/*
1297 *      COMEDI_INSN
1298 *      synchronous instructions
1299 *
1300 *      arg:
1301 *              pointer to insn
1302 *
1303 *      reads:
1304 *              struct comedi_insn struct at arg
1305 *              data (for writes)
1306 *
1307 *      writes:
1308 *              data (for reads)
1309 */
1310static int do_insn_ioctl(struct comedi_device *dev,
1311                         struct comedi_insn __user *arg, void *file)
1312{
1313        struct comedi_insn insn;
1314        unsigned int *data = NULL;
1315        int ret = 0;
1316
1317        data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
1318        if (!data) {
1319                ret = -ENOMEM;
1320                goto error;
1321        }
1322
1323        if (copy_from_user(&insn, arg, sizeof(insn))) {
1324                ret = -EFAULT;
1325                goto error;
1326        }
1327
1328        /* This is where the behavior of insn and insnlist deviate. */
1329        if (insn.n > MAX_SAMPLES)
1330                insn.n = MAX_SAMPLES;
1331        if (insn.insn & INSN_MASK_WRITE) {
1332                if (copy_from_user(data,
1333                                   insn.data,
1334                                   insn.n * sizeof(unsigned int))) {
1335                        ret = -EFAULT;
1336                        goto error;
1337                }
1338        }
1339        ret = parse_insn(dev, &insn, data, file);
1340        if (ret < 0)
1341                goto error;
1342        if (insn.insn & INSN_MASK_READ) {
1343                if (copy_to_user(insn.data,
1344                                 data,
1345                                 insn.n * sizeof(unsigned int))) {
1346                        ret = -EFAULT;
1347                        goto error;
1348                }
1349        }
1350        ret = insn.n;
1351
1352error:
1353        kfree(data);
1354
1355        return ret;
1356}
1357
1358static int do_cmd_ioctl(struct comedi_device *dev,
1359                        struct comedi_cmd __user *arg, void *file)
1360{
1361        struct comedi_cmd cmd;
1362        struct comedi_subdevice *s;
1363        struct comedi_async *async;
1364        int ret = 0;
1365        unsigned int __user *user_chanlist;
1366
1367        if (copy_from_user(&cmd, arg, sizeof(cmd))) {
1368                DPRINTK("bad cmd address\n");
1369                return -EFAULT;
1370        }
1371        /* save user's chanlist pointer so it can be restored later */
1372        user_chanlist = (unsigned int __user *)cmd.chanlist;
1373
1374        if (cmd.subdev >= dev->n_subdevices) {
1375                DPRINTK("%d no such subdevice\n", cmd.subdev);
1376                return -ENODEV;
1377        }
1378
1379        s = &dev->subdevices[cmd.subdev];
1380        async = s->async;
1381
1382        if (s->type == COMEDI_SUBD_UNUSED) {
1383                DPRINTK("%d not valid subdevice\n", cmd.subdev);
1384                return -EIO;
1385        }
1386
1387        if (!s->do_cmd || !s->do_cmdtest || !s->async) {
1388                DPRINTK("subdevice %i does not support commands\n",
1389                        cmd.subdev);
1390                return -EIO;
1391        }
1392
1393        /* are we locked? (ioctl lock) */
1394        if (s->lock && s->lock != file) {
1395                DPRINTK("subdevice locked\n");
1396                return -EACCES;
1397        }
1398
1399        /* are we busy? */
1400        if (s->busy) {
1401                DPRINTK("subdevice busy\n");
1402                return -EBUSY;
1403        }
1404
1405        /* make sure channel/gain list isn't too long */
1406        if (cmd.chanlist_len > s->len_chanlist) {
1407                DPRINTK("channel/gain list too long %u > %d\n",
1408                        cmd.chanlist_len, s->len_chanlist);
1409                return -EINVAL;
1410        }
1411
1412        /* make sure channel/gain list isn't too short */
1413        if (cmd.chanlist_len < 1) {
1414                DPRINTK("channel/gain list too short %u < 1\n",
1415                        cmd.chanlist_len);
1416                return -EINVAL;
1417        }
1418
1419        async->cmd = cmd;
1420        async->cmd.data = NULL;
1421        /* load channel/gain list */
1422        async->cmd.chanlist =
1423            kmalloc(async->cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1424        if (!async->cmd.chanlist) {
1425                DPRINTK("allocation failed\n");
1426                return -ENOMEM;
1427        }
1428
1429        if (copy_from_user(async->cmd.chanlist, user_chanlist,
1430                           async->cmd.chanlist_len * sizeof(int))) {
1431                DPRINTK("fault reading chanlist\n");
1432                ret = -EFAULT;
1433                goto cleanup;
1434        }
1435
1436        /* make sure each element in channel/gain list is valid */
1437        ret = comedi_check_chanlist(s,
1438                                    async->cmd.chanlist_len,
1439                                    async->cmd.chanlist);
1440        if (ret < 0) {
1441                DPRINTK("bad chanlist\n");
1442                goto cleanup;
1443        }
1444
1445        ret = s->do_cmdtest(dev, s, &async->cmd);
1446
1447        if (async->cmd.flags & TRIG_BOGUS || ret) {
1448                DPRINTK("test returned %d\n", ret);
1449                cmd = async->cmd;
1450                /* restore chanlist pointer before copying back */
1451                cmd.chanlist = (unsigned int __force *)user_chanlist;
1452                cmd.data = NULL;
1453                if (copy_to_user(arg, &cmd, sizeof(cmd))) {
1454                        DPRINTK("fault writing cmd\n");
1455                        ret = -EFAULT;
1456                        goto cleanup;
1457                }
1458                ret = -EAGAIN;
1459                goto cleanup;
1460        }
1461
1462        if (!async->prealloc_bufsz) {
1463                ret = -ENOMEM;
1464                DPRINTK("no buffer (?)\n");
1465                goto cleanup;
1466        }
1467
1468        comedi_buf_reset(async);
1469
1470        async->cb_mask =
1471            COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR |
1472            COMEDI_CB_OVERFLOW;
1473        if (async->cmd.flags & TRIG_WAKE_EOS)
1474                async->cb_mask |= COMEDI_CB_EOS;
1475
1476        comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING);
1477
1478        /* set s->busy _after_ setting SRF_RUNNING flag to avoid race with
1479         * comedi_read() or comedi_write() */
1480        s->busy = file;
1481        ret = s->do_cmd(dev, s);
1482        if (ret == 0)
1483                return 0;
1484
1485cleanup:
1486        do_become_nonbusy(dev, s);
1487
1488        return ret;
1489}
1490
1491/*
1492        COMEDI_CMDTEST
1493        command testing ioctl
1494
1495        arg:
1496                pointer to cmd structure
1497
1498        reads:
1499                cmd structure at arg
1500                channel/range list
1501
1502        writes:
1503                modified cmd structure at arg
1504
1505*/
1506static int do_cmdtest_ioctl(struct comedi_device *dev,
1507                            struct comedi_cmd __user *arg, void *file)
1508{
1509        struct comedi_cmd cmd;
1510        struct comedi_subdevice *s;
1511        int ret = 0;
1512        unsigned int *chanlist = NULL;
1513        unsigned int __user *user_chanlist;
1514
1515        if (copy_from_user(&cmd, arg, sizeof(cmd))) {
1516                DPRINTK("bad cmd address\n");
1517                return -EFAULT;
1518        }
1519        /* save user's chanlist pointer so it can be restored later */
1520        user_chanlist = (unsigned int __user *)cmd.chanlist;
1521
1522        if (cmd.subdev >= dev->n_subdevices) {
1523                DPRINTK("%d no such subdevice\n", cmd.subdev);
1524                return -ENODEV;
1525        }
1526
1527        s = &dev->subdevices[cmd.subdev];
1528        if (s->type == COMEDI_SUBD_UNUSED) {
1529                DPRINTK("%d not valid subdevice\n", cmd.subdev);
1530                return -EIO;
1531        }
1532
1533        if (!s->do_cmd || !s->do_cmdtest) {
1534                DPRINTK("subdevice %i does not support commands\n",
1535                        cmd.subdev);
1536                return -EIO;
1537        }
1538
1539        /* make sure channel/gain list isn't too long */
1540        if (cmd.chanlist_len > s->len_chanlist) {
1541                DPRINTK("channel/gain list too long %d > %d\n",
1542                        cmd.chanlist_len, s->len_chanlist);
1543                ret = -EINVAL;
1544                goto cleanup;
1545        }
1546
1547        /* load channel/gain list */
1548        if (cmd.chanlist) {
1549                chanlist =
1550                    kmalloc(cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1551                if (!chanlist) {
1552                        DPRINTK("allocation failed\n");
1553                        ret = -ENOMEM;
1554                        goto cleanup;
1555                }
1556
1557                if (copy_from_user(chanlist, user_chanlist,
1558                                   cmd.chanlist_len * sizeof(int))) {
1559                        DPRINTK("fault reading chanlist\n");
1560                        ret = -EFAULT;
1561                        goto cleanup;
1562                }
1563
1564                /* make sure each element in channel/gain list is valid */
1565                ret = comedi_check_chanlist(s, cmd.chanlist_len, chanlist);
1566                if (ret < 0) {
1567                        DPRINTK("bad chanlist\n");
1568                        goto cleanup;
1569                }
1570
1571                cmd.chanlist = chanlist;
1572        }
1573
1574        ret = s->do_cmdtest(dev, s, &cmd);
1575
1576        /* restore chanlist pointer before copying back */
1577        cmd.chanlist = (unsigned int __force *)user_chanlist;
1578
1579        if (copy_to_user(arg, &cmd, sizeof(cmd))) {
1580                DPRINTK("bad cmd address\n");
1581                ret = -EFAULT;
1582                goto cleanup;
1583        }
1584cleanup:
1585        kfree(chanlist);
1586
1587        return ret;
1588}
1589
1590/*
1591        COMEDI_LOCK
1592        lock subdevice
1593
1594        arg:
1595                subdevice number
1596
1597        reads:
1598                none
1599
1600        writes:
1601                none
1602
1603*/
1604
1605static int do_lock_ioctl(struct comedi_device *dev, unsigned int arg,
1606                         void *file)
1607{
1608        int ret = 0;
1609        unsigned long flags;
1610        struct comedi_subdevice *s;
1611
1612        if (arg >= dev->n_subdevices)
1613                return -EINVAL;
1614        s = &dev->subdevices[arg];
1615
1616        spin_lock_irqsave(&s->spin_lock, flags);
1617        if (s->busy || s->lock)
1618                ret = -EBUSY;
1619        else
1620                s->lock = file;
1621        spin_unlock_irqrestore(&s->spin_lock, flags);
1622
1623#if 0
1624        if (ret < 0)
1625                return ret;
1626
1627        if (s->lock_f)
1628                ret = s->lock_f(dev, s);
1629#endif
1630
1631        return ret;
1632}
1633
1634/*
1635        COMEDI_UNLOCK
1636        unlock subdevice
1637
1638        arg:
1639                subdevice number
1640
1641        reads:
1642                none
1643
1644        writes:
1645                none
1646
1647        This function isn't protected by the semaphore, since
1648        we already own the lock.
1649*/
1650static int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg,
1651                           void *file)
1652{
1653        struct comedi_subdevice *s;
1654
1655        if (arg >= dev->n_subdevices)
1656                return -EINVAL;
1657        s = &dev->subdevices[arg];
1658
1659        if (s->busy)
1660                return -EBUSY;
1661
1662        if (s->lock && s->lock != file)
1663                return -EACCES;
1664
1665        if (s->lock == file) {
1666#if 0
1667                if (s->unlock)
1668                        s->unlock(dev, s);
1669#endif
1670
1671                s->lock = NULL;
1672        }
1673
1674        return 0;
1675}
1676
1677/*
1678        COMEDI_CANCEL
1679        cancel acquisition ioctl
1680
1681        arg:
1682                subdevice number
1683
1684        reads:
1685                nothing
1686
1687        writes:
1688                nothing
1689
1690*/
1691static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
1692                           void *file)
1693{
1694        struct comedi_subdevice *s;
1695        int ret;
1696
1697        if (arg >= dev->n_subdevices)
1698                return -EINVAL;
1699        s = &dev->subdevices[arg];
1700        if (s->async == NULL)
1701                return -EINVAL;
1702
1703        if (s->lock && s->lock != file)
1704                return -EACCES;
1705
1706        if (!s->busy)
1707                return 0;
1708
1709        if (s->busy != file)
1710                return -EBUSY;
1711
1712        ret = do_cancel(dev, s);
1713        if (comedi_get_subdevice_runflags(s) & SRF_USER)
1714                wake_up_interruptible(&s->async->wait_head);
1715
1716        return ret;
1717}
1718
1719/*
1720        COMEDI_POLL ioctl
1721        instructs driver to synchronize buffers
1722
1723        arg:
1724                subdevice number
1725
1726        reads:
1727                nothing
1728
1729        writes:
1730                nothing
1731
1732*/
1733static int do_poll_ioctl(struct comedi_device *dev, unsigned int arg,
1734                         void *file)
1735{
1736        struct comedi_subdevice *s;
1737
1738        if (arg >= dev->n_subdevices)
1739                return -EINVAL;
1740        s = &dev->subdevices[arg];
1741
1742        if (s->lock && s->lock != file)
1743                return -EACCES;
1744
1745        if (!s->busy)
1746                return 0;
1747
1748        if (s->busy != file)
1749                return -EBUSY;
1750
1751        if (s->poll)
1752                return s->poll(dev, s);
1753
1754        return -EINVAL;
1755}
1756
1757static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
1758                                  unsigned long arg)
1759{
1760        const unsigned minor = iminor(file_inode(file));
1761        struct comedi_device *dev = comedi_dev_from_minor(minor);
1762        int rc;
1763
1764        if (!dev)
1765                return -ENODEV;
1766
1767        mutex_lock(&dev->mutex);
1768
1769        /* Device config is special, because it must work on
1770         * an unconfigured device. */
1771        if (cmd == COMEDI_DEVCONFIG) {
1772                if (minor >= COMEDI_NUM_BOARD_MINORS) {
1773                        /* Device config not appropriate on non-board minors. */
1774                        rc = -ENOTTY;
1775                        goto done;
1776                }
1777                rc = do_devconfig_ioctl(dev,
1778                                        (struct comedi_devconfig __user *)arg);
1779                if (rc == 0) {
1780                        if (arg == 0 &&
1781                            dev->minor >= comedi_num_legacy_minors) {
1782                                /* Successfully unconfigured a dynamically
1783                                 * allocated device.  Try and remove it. */
1784                                if (comedi_clear_board_dev(dev)) {
1785                                        mutex_unlock(&dev->mutex);
1786                                        comedi_free_board_dev(dev);
1787                                        return rc;
1788                                }
1789                        }
1790                }
1791                goto done;
1792        }
1793
1794        if (!dev->attached) {
1795                DPRINTK("no driver configured on /dev/comedi%i\n", dev->minor);
1796                rc = -ENODEV;
1797                goto done;
1798        }
1799
1800        switch (cmd) {
1801        case COMEDI_BUFCONFIG:
1802                rc = do_bufconfig_ioctl(dev,
1803                                        (struct comedi_bufconfig __user *)arg);
1804                break;
1805        case COMEDI_DEVINFO:
1806                rc = do_devinfo_ioctl(dev, (struct comedi_devinfo __user *)arg,
1807                                      file);
1808                break;
1809        case COMEDI_SUBDINFO:
1810                rc = do_subdinfo_ioctl(dev,
1811                                       (struct comedi_subdinfo __user *)arg,
1812                                       file);
1813                break;
1814        case COMEDI_CHANINFO:
1815                rc = do_chaninfo_ioctl(dev, (void __user *)arg);
1816                break;
1817        case COMEDI_RANGEINFO:
1818                rc = do_rangeinfo_ioctl(dev, (void __user *)arg);
1819                break;
1820        case COMEDI_BUFINFO:
1821                rc = do_bufinfo_ioctl(dev,
1822                                      (struct comedi_bufinfo __user *)arg,
1823                                      file);
1824                break;
1825        case COMEDI_LOCK:
1826                rc = do_lock_ioctl(dev, arg, file);
1827                break;
1828        case COMEDI_UNLOCK:
1829                rc = do_unlock_ioctl(dev, arg, file);
1830                break;
1831        case COMEDI_CANCEL:
1832                rc = do_cancel_ioctl(dev, arg, file);
1833                break;
1834        case COMEDI_CMD:
1835                rc = do_cmd_ioctl(dev, (struct comedi_cmd __user *)arg, file);
1836                break;
1837        case COMEDI_CMDTEST:
1838                rc = do_cmdtest_ioctl(dev, (struct comedi_cmd __user *)arg,
1839                                      file);
1840                break;
1841        case COMEDI_INSNLIST:
1842                rc = do_insnlist_ioctl(dev,
1843                                       (struct comedi_insnlist __user *)arg,
1844                                       file);
1845                break;
1846        case COMEDI_INSN:
1847                rc = do_insn_ioctl(dev, (struct comedi_insn __user *)arg,
1848                                   file);
1849                break;
1850        case COMEDI_POLL:
1851                rc = do_poll_ioctl(dev, arg, file);
1852                break;
1853        default:
1854                rc = -ENOTTY;
1855                break;
1856        }
1857
1858done:
1859        mutex_unlock(&dev->mutex);
1860        return rc;
1861}
1862
1863static void comedi_vm_open(struct vm_area_struct *area)
1864{
1865        struct comedi_async *async;
1866        struct comedi_device *dev;
1867
1868        async = area->vm_private_data;
1869        dev = async->subdevice->device;
1870
1871        mutex_lock(&dev->mutex);
1872        async->mmap_count++;
1873        mutex_unlock(&dev->mutex);
1874}
1875
1876static void comedi_vm_close(struct vm_area_struct *area)
1877{
1878        struct comedi_async *async;
1879        struct comedi_device *dev;
1880
1881        async = area->vm_private_data;
1882        dev = async->subdevice->device;
1883
1884        mutex_lock(&dev->mutex);
1885        async->mmap_count--;
1886        mutex_unlock(&dev->mutex);
1887}
1888
1889static struct vm_operations_struct comedi_vm_ops = {
1890        .open = comedi_vm_open,
1891        .close = comedi_vm_close,
1892};
1893
1894static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
1895{
1896        const unsigned minor = iminor(file_inode(file));
1897        struct comedi_device *dev = comedi_dev_from_minor(minor);
1898        struct comedi_subdevice *s;
1899        struct comedi_async *async;
1900        unsigned long start = vma->vm_start;
1901        unsigned long size;
1902        int n_pages;
1903        int i;
1904        int retval;
1905
1906        if (!dev)
1907                return -ENODEV;
1908
1909        mutex_lock(&dev->mutex);
1910
1911        if (!dev->attached) {
1912                DPRINTK("no driver configured on comedi%i\n", dev->minor);
1913                retval = -ENODEV;
1914                goto done;
1915        }
1916
1917        if (vma->vm_flags & VM_WRITE)
1918                s = comedi_write_subdevice(dev, minor);
1919        else
1920                s = comedi_read_subdevice(dev, minor);
1921        if (!s) {
1922                retval = -EINVAL;
1923                goto done;
1924        }
1925
1926        async = s->async;
1927        if (!async) {
1928                retval = -EINVAL;
1929                goto done;
1930        }
1931
1932        if (vma->vm_pgoff != 0) {
1933                DPRINTK("comedi: mmap() offset must be 0.\n");
1934                retval = -EINVAL;
1935                goto done;
1936        }
1937
1938        size = vma->vm_end - vma->vm_start;
1939        if (size > async->prealloc_bufsz) {
1940                retval = -EFAULT;
1941                goto done;
1942        }
1943        if (size & (~PAGE_MASK)) {
1944                retval = -EFAULT;
1945                goto done;
1946        }
1947
1948        n_pages = size >> PAGE_SHIFT;
1949        for (i = 0; i < n_pages; ++i) {
1950                struct comedi_buf_page *buf = &async->buf_page_list[i];
1951
1952                if (remap_pfn_range(vma, start,
1953                                    page_to_pfn(virt_to_page(buf->virt_addr)),
1954                                    PAGE_SIZE, PAGE_SHARED)) {
1955                        retval = -EAGAIN;
1956                        goto done;
1957                }
1958                start += PAGE_SIZE;
1959        }
1960
1961        vma->vm_ops = &comedi_vm_ops;
1962        vma->vm_private_data = async;
1963
1964        async->mmap_count++;
1965
1966        retval = 0;
1967done:
1968        mutex_unlock(&dev->mutex);
1969        return retval;
1970}
1971
1972static unsigned int comedi_poll(struct file *file, poll_table *wait)
1973{
1974        unsigned int mask = 0;
1975        const unsigned minor = iminor(file_inode(file));
1976        struct comedi_device *dev = comedi_dev_from_minor(minor);
1977        struct comedi_subdevice *s;
1978
1979        if (!dev)
1980                return -ENODEV;
1981
1982        mutex_lock(&dev->mutex);
1983
1984        if (!dev->attached) {
1985                DPRINTK("no driver configured on comedi%i\n", dev->minor);
1986                goto done;
1987        }
1988
1989        s = comedi_read_subdevice(dev, minor);
1990        if (s && s->async) {
1991                poll_wait(file, &s->async->wait_head, wait);
1992                if (!s->busy || !comedi_is_subdevice_running(s) ||
1993                    comedi_buf_read_n_available(s->async) > 0)
1994                        mask |= POLLIN | POLLRDNORM;
1995        }
1996
1997        s = comedi_write_subdevice(dev, minor);
1998        if (s && s->async) {
1999                unsigned int bps = bytes_per_sample(s->async->subdevice);
2000
2001                poll_wait(file, &s->async->wait_head, wait);
2002                comedi_buf_write_alloc(s->async, s->async->prealloc_bufsz);
2003                if (!s->busy || !comedi_is_subdevice_running(s) ||
2004                    comedi_buf_write_n_allocated(s->async) >= bps)
2005                        mask |= POLLOUT | POLLWRNORM;
2006        }
2007
2008done:
2009        mutex_unlock(&dev->mutex);
2010        return mask;
2011}
2012
2013static ssize_t comedi_write(struct file *file, const char __user *buf,
2014                            size_t nbytes, loff_t *offset)
2015{
2016        struct comedi_subdevice *s;
2017        struct comedi_async *async;
2018        int n, m, count = 0, retval = 0;
2019        DECLARE_WAITQUEUE(wait, current);
2020        const unsigned minor = iminor(file_inode(file));
2021        struct comedi_device *dev = comedi_dev_from_minor(minor);
2022
2023        if (!dev)
2024                return -ENODEV;
2025
2026        if (!dev->attached) {
2027                DPRINTK("no driver configured on comedi%i\n", dev->minor);
2028                return -ENODEV;
2029        }
2030
2031        s = comedi_write_subdevice(dev, minor);
2032        if (!s || !s->async)
2033                return -EIO;
2034
2035        async = s->async;
2036
2037        if (!s->busy || !nbytes)
2038                return 0;
2039        if (s->busy != file)
2040                return -EACCES;
2041
2042        add_wait_queue(&async->wait_head, &wait);
2043        while (nbytes > 0 && !retval) {
2044                set_current_state(TASK_INTERRUPTIBLE);
2045
2046                if (!comedi_is_subdevice_running(s)) {
2047                        if (count == 0) {
2048                                mutex_lock(&dev->mutex);
2049                                if (comedi_is_subdevice_in_error(s))
2050                                        retval = -EPIPE;
2051                                else
2052                                        retval = 0;
2053                                do_become_nonbusy(dev, s);
2054                                mutex_unlock(&dev->mutex);
2055                        }
2056                        break;
2057                }
2058
2059                n = nbytes;
2060
2061                m = n;
2062                if (async->buf_write_ptr + m > async->prealloc_bufsz)
2063                        m = async->prealloc_bufsz - async->buf_write_ptr;
2064                comedi_buf_write_alloc(async, async->prealloc_bufsz);
2065                if (m > comedi_buf_write_n_allocated(async))
2066                        m = comedi_buf_write_n_allocated(async);
2067                if (m < n)
2068                        n = m;
2069
2070                if (n == 0) {
2071                        if (file->f_flags & O_NONBLOCK) {
2072                                retval = -EAGAIN;
2073                                break;
2074                        }
2075                        schedule();
2076                        if (signal_pending(current)) {
2077                                retval = -ERESTARTSYS;
2078                                break;
2079                        }
2080                        if (!s->busy)
2081                                break;
2082                        if (s->busy != file) {
2083                                retval = -EACCES;
2084                                break;
2085                        }
2086                        continue;
2087                }
2088
2089                m = copy_from_user(async->prealloc_buf + async->buf_write_ptr,
2090                                   buf, n);
2091                if (m) {
2092                        n -= m;
2093                        retval = -EFAULT;
2094                }
2095                comedi_buf_write_free(async, n);
2096
2097                count += n;
2098                nbytes -= n;
2099
2100                buf += n;
2101                break;          /* makes device work like a pipe */
2102        }
2103        set_current_state(TASK_RUNNING);
2104        remove_wait_queue(&async->wait_head, &wait);
2105
2106        return count ? count : retval;
2107}
2108
2109static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
2110                                loff_t *offset)
2111{
2112        struct comedi_subdevice *s;
2113        struct comedi_async *async;
2114        int n, m, count = 0, retval = 0;
2115        DECLARE_WAITQUEUE(wait, current);
2116        const unsigned minor = iminor(file_inode(file));
2117        struct comedi_device *dev = comedi_dev_from_minor(minor);
2118
2119        if (!dev)
2120                return -ENODEV;
2121
2122        if (!dev->attached) {
2123                DPRINTK("no driver configured on comedi%i\n", dev->minor);
2124                return -ENODEV;
2125        }
2126
2127        s = comedi_read_subdevice(dev, minor);
2128        if (!s || !s->async)
2129                return -EIO;
2130
2131        async = s->async;
2132        if (!s->busy || !nbytes)
2133                return 0;
2134        if (s->busy != file)
2135                return -EACCES;
2136
2137        add_wait_queue(&async->wait_head, &wait);
2138        while (nbytes > 0 && !retval) {
2139                set_current_state(TASK_INTERRUPTIBLE);
2140
2141                n = nbytes;
2142
2143                m = comedi_buf_read_n_available(async);
2144                /* printk("%d available\n",m); */
2145                if (async->buf_read_ptr + m > async->prealloc_bufsz)
2146                        m = async->prealloc_bufsz - async->buf_read_ptr;
2147                /* printk("%d contiguous\n",m); */
2148                if (m < n)
2149                        n = m;
2150
2151                if (n == 0) {
2152                        if (!comedi_is_subdevice_running(s)) {
2153                                mutex_lock(&dev->mutex);
2154                                do_become_nonbusy(dev, s);
2155                                if (comedi_is_subdevice_in_error(s))
2156                                        retval = -EPIPE;
2157                                else
2158                                        retval = 0;
2159                                mutex_unlock(&dev->mutex);
2160                                break;
2161                        }
2162                        if (file->f_flags & O_NONBLOCK) {
2163                                retval = -EAGAIN;
2164                                break;
2165                        }
2166                        schedule();
2167                        if (signal_pending(current)) {
2168                                retval = -ERESTARTSYS;
2169                                break;
2170                        }
2171                        if (!s->busy) {
2172                                retval = 0;
2173                                break;
2174                        }
2175                        if (s->busy != file) {
2176                                retval = -EACCES;
2177                                break;
2178                        }
2179                        continue;
2180                }
2181                m = copy_to_user(buf, async->prealloc_buf +
2182                                 async->buf_read_ptr, n);
2183                if (m) {
2184                        n -= m;
2185                        retval = -EFAULT;
2186                }
2187
2188                comedi_buf_read_alloc(async, n);
2189                comedi_buf_read_free(async, n);
2190
2191                count += n;
2192                nbytes -= n;
2193
2194                buf += n;
2195                break;          /* makes device work like a pipe */
2196        }
2197        if (comedi_is_subdevice_idle(s)) {
2198                mutex_lock(&dev->mutex);
2199                if (async->buf_read_count - async->buf_write_count == 0)
2200                        do_become_nonbusy(dev, s);
2201                mutex_unlock(&dev->mutex);
2202        }
2203        set_current_state(TASK_RUNNING);
2204        remove_wait_queue(&async->wait_head, &wait);
2205
2206        return count ? count : retval;
2207}
2208
2209static int comedi_open(struct inode *inode, struct file *file)
2210{
2211        const unsigned minor = iminor(inode);
2212        struct comedi_device *dev = comedi_dev_from_minor(minor);
2213
2214        if (!dev) {
2215                DPRINTK("invalid minor number\n");
2216                return -ENODEV;
2217        }
2218
2219        /* This is slightly hacky, but we want module autoloading
2220         * to work for root.
2221         * case: user opens device, attached -> ok
2222         * case: user opens device, unattached, !in_request_module -> autoload
2223         * case: user opens device, unattached, in_request_module -> fail
2224         * case: root opens device, attached -> ok
2225         * case: root opens device, unattached, in_request_module -> ok
2226         *   (typically called from modprobe)
2227         * case: root opens device, unattached, !in_request_module -> autoload
2228         *
2229         * The last could be changed to "-> ok", which would deny root
2230         * autoloading.
2231         */
2232        mutex_lock(&dev->mutex);
2233        if (dev->attached)
2234                goto ok;
2235        if (!capable(CAP_NET_ADMIN) && dev->in_request_module) {
2236                DPRINTK("in request module\n");
2237                mutex_unlock(&dev->mutex);
2238                return -ENODEV;
2239        }
2240        if (capable(CAP_NET_ADMIN) && dev->in_request_module)
2241                goto ok;
2242
2243        dev->in_request_module = true;
2244
2245#ifdef CONFIG_KMOD
2246        mutex_unlock(&dev->mutex);
2247        request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor);
2248        mutex_lock(&dev->mutex);
2249#endif
2250
2251        dev->in_request_module = false;
2252
2253        if (!dev->attached && !capable(CAP_NET_ADMIN)) {
2254                DPRINTK("not attached and not CAP_NET_ADMIN\n");
2255                mutex_unlock(&dev->mutex);
2256                return -ENODEV;
2257        }
2258ok:
2259        __module_get(THIS_MODULE);
2260
2261        if (dev->attached) {
2262                if (!try_module_get(dev->driver->module)) {
2263                        module_put(THIS_MODULE);
2264                        mutex_unlock(&dev->mutex);
2265                        return -ENOSYS;
2266                }
2267        }
2268
2269        if (dev->attached && dev->use_count == 0 && dev->open) {
2270                int rc = dev->open(dev);
2271                if (rc < 0) {
2272                        module_put(dev->driver->module);
2273                        module_put(THIS_MODULE);
2274                        mutex_unlock(&dev->mutex);
2275                        return rc;
2276                }
2277        }
2278
2279        dev->use_count++;
2280
2281        mutex_unlock(&dev->mutex);
2282
2283        return 0;
2284}
2285
2286static int comedi_fasync(int fd, struct file *file, int on)
2287{
2288        const unsigned minor = iminor(file_inode(file));
2289        struct comedi_device *dev = comedi_dev_from_minor(minor);
2290
2291        if (!dev)
2292                return -ENODEV;
2293
2294        return fasync_helper(fd, file, on, &dev->async_queue);
2295}
2296
2297static int comedi_close(struct inode *inode, struct file *file)
2298{
2299        const unsigned minor = iminor(inode);
2300        struct comedi_device *dev = comedi_dev_from_minor(minor);
2301        struct comedi_subdevice *s = NULL;
2302        int i;
2303
2304        if (!dev)
2305                return -ENODEV;
2306
2307        mutex_lock(&dev->mutex);
2308
2309        if (dev->subdevices) {
2310                for (i = 0; i < dev->n_subdevices; i++) {
2311                        s = &dev->subdevices[i];
2312
2313                        if (s->busy == file)
2314                                do_cancel(dev, s);
2315                        if (s->lock == file)
2316                                s->lock = NULL;
2317                }
2318        }
2319        if (dev->attached && dev->use_count == 1 && dev->close)
2320                dev->close(dev);
2321
2322        module_put(THIS_MODULE);
2323        if (dev->attached)
2324                module_put(dev->driver->module);
2325
2326        dev->use_count--;
2327
2328        mutex_unlock(&dev->mutex);
2329
2330        if (file->f_flags & FASYNC)
2331                comedi_fasync(-1, file, 0);
2332
2333        return 0;
2334}
2335
2336static const struct file_operations comedi_fops = {
2337        .owner = THIS_MODULE,
2338        .unlocked_ioctl = comedi_unlocked_ioctl,
2339        .compat_ioctl = comedi_compat_ioctl,
2340        .open = comedi_open,
2341        .release = comedi_close,
2342        .read = comedi_read,
2343        .write = comedi_write,
2344        .mmap = comedi_mmap,
2345        .poll = comedi_poll,
2346        .fasync = comedi_fasync,
2347        .llseek = noop_llseek,
2348};
2349
2350void comedi_error(const struct comedi_device *dev, const char *s)
2351{
2352        dev_err(dev->class_dev, "%s: %s\n", dev->driver->driver_name, s);
2353}
2354EXPORT_SYMBOL_GPL(comedi_error);
2355
2356void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
2357{
2358        struct comedi_async *async = s->async;
2359        unsigned runflags = 0;
2360        unsigned runflags_mask = 0;
2361
2362        /* DPRINTK("comedi_event 0x%x\n",mask); */
2363
2364        if (!comedi_is_subdevice_running(s))
2365                return;
2366
2367        if (s->
2368            async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR |
2369                             COMEDI_CB_OVERFLOW)) {
2370                runflags_mask |= SRF_RUNNING;
2371        }
2372        /* remember if an error event has occurred, so an error
2373         * can be returned the next time the user does a read() */
2374        if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) {
2375                runflags_mask |= SRF_ERROR;
2376                runflags |= SRF_ERROR;
2377        }
2378        if (runflags_mask) {
2379                /*sets SRF_ERROR and SRF_RUNNING together atomically */
2380                comedi_set_subdevice_runflags(s, runflags_mask, runflags);
2381        }
2382
2383        if (async->cb_mask & s->async->events) {
2384                if (comedi_get_subdevice_runflags(s) & SRF_USER) {
2385                        wake_up_interruptible(&async->wait_head);
2386                        if (s->subdev_flags & SDF_CMD_READ)
2387                                kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
2388                        if (s->subdev_flags & SDF_CMD_WRITE)
2389                                kill_fasync(&dev->async_queue, SIGIO, POLL_OUT);
2390                } else {
2391                        if (async->cb_func)
2392                                async->cb_func(s->async->events, async->cb_arg);
2393                }
2394        }
2395        s->async->events = 0;
2396}
2397EXPORT_SYMBOL_GPL(comedi_event);
2398
2399/* Note: the ->mutex is pre-locked on successful return */
2400struct comedi_device *comedi_alloc_board_minor(struct device *hardware_device)
2401{
2402        struct comedi_device *dev;
2403        struct device *csdev;
2404        unsigned i;
2405
2406        dev = kzalloc(sizeof(struct comedi_device), GFP_KERNEL);
2407        if (dev == NULL)
2408                return ERR_PTR(-ENOMEM);
2409        comedi_device_init(dev);
2410        comedi_set_hw_dev(dev, hardware_device);
2411        mutex_lock(&dev->mutex);
2412        mutex_lock(&comedi_board_minor_table_lock);
2413        for (i = hardware_device ? comedi_num_legacy_minors : 0;
2414             i < COMEDI_NUM_BOARD_MINORS; ++i) {
2415                if (comedi_board_minor_table[i] == NULL) {
2416                        comedi_board_minor_table[i] = dev;
2417                        break;
2418                }
2419        }
2420        mutex_unlock(&comedi_board_minor_table_lock);
2421        if (i == COMEDI_NUM_BOARD_MINORS) {
2422                mutex_unlock(&dev->mutex);
2423                comedi_device_cleanup(dev);
2424                kfree(dev);
2425                pr_err("comedi: error: ran out of minor numbers for board device files.\n");
2426                return ERR_PTR(-EBUSY);
2427        }
2428        dev->minor = i;
2429        csdev = device_create(comedi_class, hardware_device,
2430                              MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i", i);
2431        if (!IS_ERR(csdev))
2432                dev->class_dev = csdev;
2433
2434        /* Note: dev->mutex needs to be unlocked by the caller. */
2435        return dev;
2436}
2437
2438static void comedi_free_board_minor(unsigned minor)
2439{
2440        BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
2441        comedi_free_board_dev(comedi_clear_board_minor(minor));
2442}
2443
2444void comedi_release_hardware_device(struct device *hardware_device)
2445{
2446        int minor;
2447        struct comedi_device *dev;
2448
2449        for (minor = comedi_num_legacy_minors; minor < COMEDI_NUM_BOARD_MINORS;
2450             minor++) {
2451                mutex_lock(&comedi_board_minor_table_lock);
2452                dev = comedi_board_minor_table[minor];
2453                if (dev && dev->hw_dev == hardware_device) {
2454                        comedi_board_minor_table[minor] = NULL;
2455                        mutex_unlock(&comedi_board_minor_table_lock);
2456                        comedi_free_board_dev(dev);
2457                        break;
2458                }
2459                mutex_unlock(&comedi_board_minor_table_lock);
2460        }
2461}
2462
2463int comedi_alloc_subdevice_minor(struct comedi_subdevice *s)
2464{
2465        struct comedi_device *dev = s->device;
2466        struct device *csdev;
2467        unsigned i;
2468
2469        mutex_lock(&comedi_subdevice_minor_table_lock);
2470        for (i = 0; i < COMEDI_NUM_SUBDEVICE_MINORS; ++i) {
2471                if (comedi_subdevice_minor_table[i] == NULL) {
2472                        comedi_subdevice_minor_table[i] = s;
2473                        break;
2474                }
2475        }
2476        mutex_unlock(&comedi_subdevice_minor_table_lock);
2477        if (i == COMEDI_NUM_SUBDEVICE_MINORS) {
2478                pr_err("comedi: error: ran out of minor numbers for subdevice files.\n");
2479                return -EBUSY;
2480        }
2481        i += COMEDI_NUM_BOARD_MINORS;
2482        s->minor = i;
2483        csdev = device_create(comedi_class, dev->class_dev,
2484                              MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i_subd%i",
2485                              dev->minor, s->index);
2486        if (!IS_ERR(csdev))
2487                s->class_dev = csdev;
2488
2489        return 0;
2490}
2491
2492void comedi_free_subdevice_minor(struct comedi_subdevice *s)
2493{
2494        unsigned int i;
2495
2496        if (s == NULL)
2497                return;
2498        if (s->minor < 0)
2499                return;
2500
2501        BUG_ON(s->minor >= COMEDI_NUM_MINORS);
2502        BUG_ON(s->minor < COMEDI_NUM_BOARD_MINORS);
2503
2504        i = s->minor - COMEDI_NUM_BOARD_MINORS;
2505        mutex_lock(&comedi_subdevice_minor_table_lock);
2506        if (s == comedi_subdevice_minor_table[i])
2507                comedi_subdevice_minor_table[i] = NULL;
2508        mutex_unlock(&comedi_subdevice_minor_table_lock);
2509        if (s->class_dev) {
2510                device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
2511                s->class_dev = NULL;
2512        }
2513}
2514
2515static void comedi_cleanup_board_minors(void)
2516{
2517        unsigned i;
2518
2519        for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++)
2520                comedi_free_board_minor(i);
2521}
2522
2523static int __init comedi_init(void)
2524{
2525        int i;
2526        int retval;
2527
2528        pr_info("comedi: version " COMEDI_RELEASE " - http://www.comedi.org\n");
2529
2530        if (comedi_num_legacy_minors < 0 ||
2531            comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) {
2532                pr_err("comedi: error: invalid value for module parameter \"comedi_num_legacy_minors\".  Valid values are 0 through %i.\n",
2533                       COMEDI_NUM_BOARD_MINORS);
2534                return -EINVAL;
2535        }
2536
2537        retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2538                                        COMEDI_NUM_MINORS, "comedi");
2539        if (retval)
2540                return -EIO;
2541        cdev_init(&comedi_cdev, &comedi_fops);
2542        comedi_cdev.owner = THIS_MODULE;
2543        kobject_set_name(&comedi_cdev.kobj, "comedi");
2544        if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) {
2545                unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2546                                         COMEDI_NUM_MINORS);
2547                return -EIO;
2548        }
2549        comedi_class = class_create(THIS_MODULE, "comedi");
2550        if (IS_ERR(comedi_class)) {
2551                pr_err("comedi: failed to create class\n");
2552                cdev_del(&comedi_cdev);
2553                unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2554                                         COMEDI_NUM_MINORS);
2555                return PTR_ERR(comedi_class);
2556        }
2557
2558        comedi_class->dev_attrs = comedi_dev_attrs;
2559
2560        /* XXX requires /proc interface */
2561        comedi_proc_init();
2562
2563        /* create devices files for legacy/manual use */
2564        for (i = 0; i < comedi_num_legacy_minors; i++) {
2565                struct comedi_device *dev;
2566                dev = comedi_alloc_board_minor(NULL);
2567                if (IS_ERR(dev)) {
2568                        comedi_cleanup_board_minors();
2569                        cdev_del(&comedi_cdev);
2570                        unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2571                                                 COMEDI_NUM_MINORS);
2572                        return PTR_ERR(dev);
2573                } else {
2574                        /* comedi_alloc_board_minor() locked the mutex */
2575                        mutex_unlock(&dev->mutex);
2576                }
2577        }
2578
2579        return 0;
2580}
2581module_init(comedi_init);
2582
2583static void __exit comedi_cleanup(void)
2584{
2585        int i;
2586
2587        comedi_cleanup_board_minors();
2588        for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i)
2589                BUG_ON(comedi_board_minor_table[i]);
2590        for (i = 0; i < COMEDI_NUM_SUBDEVICE_MINORS; ++i)
2591                BUG_ON(comedi_subdevice_minor_table[i]);
2592
2593        class_destroy(comedi_class);
2594        cdev_del(&comedi_cdev);
2595        unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
2596
2597        comedi_proc_cleanup();
2598}
2599module_exit(comedi_cleanup);
2600
2601MODULE_AUTHOR("http://www.comedi.org");
2602MODULE_DESCRIPTION("Comedi core module");
2603MODULE_LICENSE("GPL");
2604