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        s->busy = file;
1405
1406        /* make sure channel/gain list isn't too long */
1407        if (cmd.chanlist_len > s->len_chanlist) {
1408                DPRINTK("channel/gain list too long %u > %d\n",
1409                        cmd.chanlist_len, s->len_chanlist);
1410                ret = -EINVAL;
1411                goto cleanup;
1412        }
1413
1414        /* make sure channel/gain list isn't too short */
1415        if (cmd.chanlist_len < 1) {
1416                DPRINTK("channel/gain list too short %u < 1\n",
1417                        cmd.chanlist_len);
1418                ret = -EINVAL;
1419                goto cleanup;
1420        }
1421
1422        async->cmd = cmd;
1423        async->cmd.data = NULL;
1424        /* load channel/gain list */
1425        async->cmd.chanlist =
1426            kmalloc(async->cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1427        if (!async->cmd.chanlist) {
1428                DPRINTK("allocation failed\n");
1429                ret = -ENOMEM;
1430                goto cleanup;
1431        }
1432
1433        if (copy_from_user(async->cmd.chanlist, user_chanlist,
1434                           async->cmd.chanlist_len * sizeof(int))) {
1435                DPRINTK("fault reading chanlist\n");
1436                ret = -EFAULT;
1437                goto cleanup;
1438        }
1439
1440        /* make sure each element in channel/gain list is valid */
1441        ret = comedi_check_chanlist(s,
1442                                    async->cmd.chanlist_len,
1443                                    async->cmd.chanlist);
1444        if (ret < 0) {
1445                DPRINTK("bad chanlist\n");
1446                goto cleanup;
1447        }
1448
1449        ret = s->do_cmdtest(dev, s, &async->cmd);
1450
1451        if (async->cmd.flags & TRIG_BOGUS || ret) {
1452                DPRINTK("test returned %d\n", ret);
1453                cmd = async->cmd;
1454                /* restore chanlist pointer before copying back */
1455                cmd.chanlist = (unsigned int __force *)user_chanlist;
1456                cmd.data = NULL;
1457                if (copy_to_user(arg, &cmd, sizeof(cmd))) {
1458                        DPRINTK("fault writing cmd\n");
1459                        ret = -EFAULT;
1460                        goto cleanup;
1461                }
1462                ret = -EAGAIN;
1463                goto cleanup;
1464        }
1465
1466        if (!async->prealloc_bufsz) {
1467                ret = -ENOMEM;
1468                DPRINTK("no buffer (?)\n");
1469                goto cleanup;
1470        }
1471
1472        comedi_buf_reset(async);
1473
1474        async->cb_mask =
1475            COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR |
1476            COMEDI_CB_OVERFLOW;
1477        if (async->cmd.flags & TRIG_WAKE_EOS)
1478                async->cb_mask |= COMEDI_CB_EOS;
1479
1480        comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING);
1481
1482        ret = s->do_cmd(dev, s);
1483        if (ret == 0)
1484                return 0;
1485
1486cleanup:
1487        do_become_nonbusy(dev, s);
1488
1489        return ret;
1490}
1491
1492/*
1493        COMEDI_CMDTEST
1494        command testing ioctl
1495
1496        arg:
1497                pointer to cmd structure
1498
1499        reads:
1500                cmd structure at arg
1501                channel/range list
1502
1503        writes:
1504                modified cmd structure at arg
1505
1506*/
1507static int do_cmdtest_ioctl(struct comedi_device *dev,
1508                            struct comedi_cmd __user *arg, void *file)
1509{
1510        struct comedi_cmd cmd;
1511        struct comedi_subdevice *s;
1512        int ret = 0;
1513        unsigned int *chanlist = NULL;
1514        unsigned int __user *user_chanlist;
1515
1516        if (copy_from_user(&cmd, arg, sizeof(cmd))) {
1517                DPRINTK("bad cmd address\n");
1518                return -EFAULT;
1519        }
1520        /* save user's chanlist pointer so it can be restored later */
1521        user_chanlist = (unsigned int __user *)cmd.chanlist;
1522
1523        if (cmd.subdev >= dev->n_subdevices) {
1524                DPRINTK("%d no such subdevice\n", cmd.subdev);
1525                return -ENODEV;
1526        }
1527
1528        s = &dev->subdevices[cmd.subdev];
1529        if (s->type == COMEDI_SUBD_UNUSED) {
1530                DPRINTK("%d not valid subdevice\n", cmd.subdev);
1531                return -EIO;
1532        }
1533
1534        if (!s->do_cmd || !s->do_cmdtest) {
1535                DPRINTK("subdevice %i does not support commands\n",
1536                        cmd.subdev);
1537                return -EIO;
1538        }
1539
1540        /* make sure channel/gain list isn't too long */
1541        if (cmd.chanlist_len > s->len_chanlist) {
1542                DPRINTK("channel/gain list too long %d > %d\n",
1543                        cmd.chanlist_len, s->len_chanlist);
1544                ret = -EINVAL;
1545                goto cleanup;
1546        }
1547
1548        /* load channel/gain list */
1549        if (cmd.chanlist) {
1550                chanlist =
1551                    kmalloc(cmd.chanlist_len * sizeof(int), GFP_KERNEL);
1552                if (!chanlist) {
1553                        DPRINTK("allocation failed\n");
1554                        ret = -ENOMEM;
1555                        goto cleanup;
1556                }
1557
1558                if (copy_from_user(chanlist, user_chanlist,
1559                                   cmd.chanlist_len * sizeof(int))) {
1560                        DPRINTK("fault reading chanlist\n");
1561                        ret = -EFAULT;
1562                        goto cleanup;
1563                }
1564
1565                /* make sure each element in channel/gain list is valid */
1566                ret = comedi_check_chanlist(s, cmd.chanlist_len, chanlist);
1567                if (ret < 0) {
1568                        DPRINTK("bad chanlist\n");
1569                        goto cleanup;
1570                }
1571
1572                cmd.chanlist = chanlist;
1573        }
1574
1575        ret = s->do_cmdtest(dev, s, &cmd);
1576
1577        /* restore chanlist pointer before copying back */
1578        cmd.chanlist = (unsigned int __force *)user_chanlist;
1579
1580        if (copy_to_user(arg, &cmd, sizeof(cmd))) {
1581                DPRINTK("bad cmd address\n");
1582                ret = -EFAULT;
1583                goto cleanup;
1584        }
1585cleanup:
1586        kfree(chanlist);
1587
1588        return ret;
1589}
1590
1591/*
1592        COMEDI_LOCK
1593        lock subdevice
1594
1595        arg:
1596                subdevice number
1597
1598        reads:
1599                none
1600
1601        writes:
1602                none
1603
1604*/
1605
1606static int do_lock_ioctl(struct comedi_device *dev, unsigned int arg,
1607                         void *file)
1608{
1609        int ret = 0;
1610        unsigned long flags;
1611        struct comedi_subdevice *s;
1612
1613        if (arg >= dev->n_subdevices)
1614                return -EINVAL;
1615        s = &dev->subdevices[arg];
1616
1617        spin_lock_irqsave(&s->spin_lock, flags);
1618        if (s->busy || s->lock)
1619                ret = -EBUSY;
1620        else
1621                s->lock = file;
1622        spin_unlock_irqrestore(&s->spin_lock, flags);
1623
1624#if 0
1625        if (ret < 0)
1626                return ret;
1627
1628        if (s->lock_f)
1629                ret = s->lock_f(dev, s);
1630#endif
1631
1632        return ret;
1633}
1634
1635/*
1636        COMEDI_UNLOCK
1637        unlock subdevice
1638
1639        arg:
1640                subdevice number
1641
1642        reads:
1643                none
1644
1645        writes:
1646                none
1647
1648        This function isn't protected by the semaphore, since
1649        we already own the lock.
1650*/
1651static int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg,
1652                           void *file)
1653{
1654        struct comedi_subdevice *s;
1655
1656        if (arg >= dev->n_subdevices)
1657                return -EINVAL;
1658        s = &dev->subdevices[arg];
1659
1660        if (s->busy)
1661                return -EBUSY;
1662
1663        if (s->lock && s->lock != file)
1664                return -EACCES;
1665
1666        if (s->lock == file) {
1667#if 0
1668                if (s->unlock)
1669                        s->unlock(dev, s);
1670#endif
1671
1672                s->lock = NULL;
1673        }
1674
1675        return 0;
1676}
1677
1678/*
1679        COMEDI_CANCEL
1680        cancel acquisition ioctl
1681
1682        arg:
1683                subdevice number
1684
1685        reads:
1686                nothing
1687
1688        writes:
1689                nothing
1690
1691*/
1692static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
1693                           void *file)
1694{
1695        struct comedi_subdevice *s;
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        return do_cancel(dev, s);
1713}
1714
1715/*
1716        COMEDI_POLL ioctl
1717        instructs driver to synchronize buffers
1718
1719        arg:
1720                subdevice number
1721
1722        reads:
1723                nothing
1724
1725        writes:
1726                nothing
1727
1728*/
1729static int do_poll_ioctl(struct comedi_device *dev, unsigned int arg,
1730                         void *file)
1731{
1732        struct comedi_subdevice *s;
1733
1734        if (arg >= dev->n_subdevices)
1735                return -EINVAL;
1736        s = &dev->subdevices[arg];
1737
1738        if (s->lock && s->lock != file)
1739                return -EACCES;
1740
1741        if (!s->busy)
1742                return 0;
1743
1744        if (s->busy != file)
1745                return -EBUSY;
1746
1747        if (s->poll)
1748                return s->poll(dev, s);
1749
1750        return -EINVAL;
1751}
1752
1753static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
1754                                  unsigned long arg)
1755{
1756        const unsigned minor = iminor(file_inode(file));
1757        struct comedi_device *dev = comedi_dev_from_minor(minor);
1758        int rc;
1759
1760        if (!dev)
1761                return -ENODEV;
1762
1763        mutex_lock(&dev->mutex);
1764
1765        /* Device config is special, because it must work on
1766         * an unconfigured device. */
1767        if (cmd == COMEDI_DEVCONFIG) {
1768                if (minor >= COMEDI_NUM_BOARD_MINORS) {
1769                        /* Device config not appropriate on non-board minors. */
1770                        rc = -ENOTTY;
1771                        goto done;
1772                }
1773                rc = do_devconfig_ioctl(dev,
1774                                        (struct comedi_devconfig __user *)arg);
1775                if (rc == 0) {
1776                        if (arg == 0 &&
1777                            dev->minor >= comedi_num_legacy_minors) {
1778                                /* Successfully unconfigured a dynamically
1779                                 * allocated device.  Try and remove it. */
1780                                if (comedi_clear_board_dev(dev)) {
1781                                        mutex_unlock(&dev->mutex);
1782                                        comedi_free_board_dev(dev);
1783                                        return rc;
1784                                }
1785                        }
1786                }
1787                goto done;
1788        }
1789
1790        if (!dev->attached) {
1791                DPRINTK("no driver configured on /dev/comedi%i\n", dev->minor);
1792                rc = -ENODEV;
1793                goto done;
1794        }
1795
1796        switch (cmd) {
1797        case COMEDI_BUFCONFIG:
1798                rc = do_bufconfig_ioctl(dev,
1799                                        (struct comedi_bufconfig __user *)arg);
1800                break;
1801        case COMEDI_DEVINFO:
1802                rc = do_devinfo_ioctl(dev, (struct comedi_devinfo __user *)arg,
1803                                      file);
1804                break;
1805        case COMEDI_SUBDINFO:
1806                rc = do_subdinfo_ioctl(dev,
1807                                       (struct comedi_subdinfo __user *)arg,
1808                                       file);
1809                break;
1810        case COMEDI_CHANINFO:
1811                rc = do_chaninfo_ioctl(dev, (void __user *)arg);
1812                break;
1813        case COMEDI_RANGEINFO:
1814                rc = do_rangeinfo_ioctl(dev, (void __user *)arg);
1815                break;
1816        case COMEDI_BUFINFO:
1817                rc = do_bufinfo_ioctl(dev,
1818                                      (struct comedi_bufinfo __user *)arg,
1819                                      file);
1820                break;
1821        case COMEDI_LOCK:
1822                rc = do_lock_ioctl(dev, arg, file);
1823                break;
1824        case COMEDI_UNLOCK:
1825                rc = do_unlock_ioctl(dev, arg, file);
1826                break;
1827        case COMEDI_CANCEL:
1828                rc = do_cancel_ioctl(dev, arg, file);
1829                break;
1830        case COMEDI_CMD:
1831                rc = do_cmd_ioctl(dev, (struct comedi_cmd __user *)arg, file);
1832                break;
1833        case COMEDI_CMDTEST:
1834                rc = do_cmdtest_ioctl(dev, (struct comedi_cmd __user *)arg,
1835                                      file);
1836                break;
1837        case COMEDI_INSNLIST:
1838                rc = do_insnlist_ioctl(dev,
1839                                       (struct comedi_insnlist __user *)arg,
1840                                       file);
1841                break;
1842        case COMEDI_INSN:
1843                rc = do_insn_ioctl(dev, (struct comedi_insn __user *)arg,
1844                                   file);
1845                break;
1846        case COMEDI_POLL:
1847                rc = do_poll_ioctl(dev, arg, file);
1848                break;
1849        default:
1850                rc = -ENOTTY;
1851                break;
1852        }
1853
1854done:
1855        mutex_unlock(&dev->mutex);
1856        return rc;
1857}
1858
1859static void comedi_vm_open(struct vm_area_struct *area)
1860{
1861        struct comedi_async *async;
1862        struct comedi_device *dev;
1863
1864        async = area->vm_private_data;
1865        dev = async->subdevice->device;
1866
1867        mutex_lock(&dev->mutex);
1868        async->mmap_count++;
1869        mutex_unlock(&dev->mutex);
1870}
1871
1872static void comedi_vm_close(struct vm_area_struct *area)
1873{
1874        struct comedi_async *async;
1875        struct comedi_device *dev;
1876
1877        async = area->vm_private_data;
1878        dev = async->subdevice->device;
1879
1880        mutex_lock(&dev->mutex);
1881        async->mmap_count--;
1882        mutex_unlock(&dev->mutex);
1883}
1884
1885static struct vm_operations_struct comedi_vm_ops = {
1886        .open = comedi_vm_open,
1887        .close = comedi_vm_close,
1888};
1889
1890static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
1891{
1892        const unsigned minor = iminor(file_inode(file));
1893        struct comedi_device *dev = comedi_dev_from_minor(minor);
1894        struct comedi_subdevice *s;
1895        struct comedi_async *async;
1896        unsigned long start = vma->vm_start;
1897        unsigned long size;
1898        int n_pages;
1899        int i;
1900        int retval;
1901
1902        if (!dev)
1903                return -ENODEV;
1904
1905        mutex_lock(&dev->mutex);
1906
1907        if (!dev->attached) {
1908                DPRINTK("no driver configured on comedi%i\n", dev->minor);
1909                retval = -ENODEV;
1910                goto done;
1911        }
1912
1913        if (vma->vm_flags & VM_WRITE)
1914                s = comedi_write_subdevice(dev, minor);
1915        else
1916                s = comedi_read_subdevice(dev, minor);
1917        if (!s) {
1918                retval = -EINVAL;
1919                goto done;
1920        }
1921
1922        async = s->async;
1923        if (!async) {
1924                retval = -EINVAL;
1925                goto done;
1926        }
1927
1928        if (vma->vm_pgoff != 0) {
1929                DPRINTK("comedi: mmap() offset must be 0.\n");
1930                retval = -EINVAL;
1931                goto done;
1932        }
1933
1934        size = vma->vm_end - vma->vm_start;
1935        if (size > async->prealloc_bufsz) {
1936                retval = -EFAULT;
1937                goto done;
1938        }
1939        if (size & (~PAGE_MASK)) {
1940                retval = -EFAULT;
1941                goto done;
1942        }
1943
1944        n_pages = size >> PAGE_SHIFT;
1945        for (i = 0; i < n_pages; ++i) {
1946                struct comedi_buf_page *buf = &async->buf_page_list[i];
1947
1948                if (remap_pfn_range(vma, start,
1949                                    page_to_pfn(virt_to_page(buf->virt_addr)),
1950                                    PAGE_SIZE, PAGE_SHARED)) {
1951                        retval = -EAGAIN;
1952                        goto done;
1953                }
1954                start += PAGE_SIZE;
1955        }
1956
1957        vma->vm_ops = &comedi_vm_ops;
1958        vma->vm_private_data = async;
1959
1960        async->mmap_count++;
1961
1962        retval = 0;
1963done:
1964        mutex_unlock(&dev->mutex);
1965        return retval;
1966}
1967
1968static unsigned int comedi_poll(struct file *file, poll_table *wait)
1969{
1970        unsigned int mask = 0;
1971        const unsigned minor = iminor(file_inode(file));
1972        struct comedi_device *dev = comedi_dev_from_minor(minor);
1973        struct comedi_subdevice *s;
1974
1975        if (!dev)
1976                return -ENODEV;
1977
1978        mutex_lock(&dev->mutex);
1979
1980        if (!dev->attached) {
1981                DPRINTK("no driver configured on comedi%i\n", dev->minor);
1982                goto done;
1983        }
1984
1985        s = comedi_read_subdevice(dev, minor);
1986        if (s && s->async) {
1987                poll_wait(file, &s->async->wait_head, wait);
1988                if (!s->busy || !comedi_is_subdevice_running(s) ||
1989                    comedi_buf_read_n_available(s->async) > 0)
1990                        mask |= POLLIN | POLLRDNORM;
1991        }
1992
1993        s = comedi_write_subdevice(dev, minor);
1994        if (s && s->async) {
1995                unsigned int bps = bytes_per_sample(s->async->subdevice);
1996
1997                poll_wait(file, &s->async->wait_head, wait);
1998                comedi_buf_write_alloc(s->async, s->async->prealloc_bufsz);
1999                if (!s->busy || !comedi_is_subdevice_running(s) ||
2000                    comedi_buf_write_n_allocated(s->async) >= bps)
2001                        mask |= POLLOUT | POLLWRNORM;
2002        }
2003
2004done:
2005        mutex_unlock(&dev->mutex);
2006        return mask;
2007}
2008
2009static ssize_t comedi_write(struct file *file, const char __user *buf,
2010                            size_t nbytes, loff_t *offset)
2011{
2012        struct comedi_subdevice *s;
2013        struct comedi_async *async;
2014        int n, m, count = 0, retval = 0;
2015        DECLARE_WAITQUEUE(wait, current);
2016        const unsigned minor = iminor(file_inode(file));
2017        struct comedi_device *dev = comedi_dev_from_minor(minor);
2018
2019        if (!dev)
2020                return -ENODEV;
2021
2022        if (!dev->attached) {
2023                DPRINTK("no driver configured on comedi%i\n", dev->minor);
2024                return -ENODEV;
2025        }
2026
2027        s = comedi_write_subdevice(dev, minor);
2028        if (!s || !s->async)
2029                return -EIO;
2030
2031        async = s->async;
2032
2033        if (!s->busy || !nbytes)
2034                return 0;
2035        if (s->busy != file)
2036                return -EACCES;
2037
2038        add_wait_queue(&async->wait_head, &wait);
2039        while (nbytes > 0 && !retval) {
2040                set_current_state(TASK_INTERRUPTIBLE);
2041
2042                if (!comedi_is_subdevice_running(s)) {
2043                        if (count == 0) {
2044                                if (comedi_is_subdevice_in_error(s))
2045                                        retval = -EPIPE;
2046                                else
2047                                        retval = 0;
2048                                do_become_nonbusy(dev, s);
2049                        }
2050                        break;
2051                }
2052
2053                n = nbytes;
2054
2055                m = n;
2056                if (async->buf_write_ptr + m > async->prealloc_bufsz)
2057                        m = async->prealloc_bufsz - async->buf_write_ptr;
2058                comedi_buf_write_alloc(async, async->prealloc_bufsz);
2059                if (m > comedi_buf_write_n_allocated(async))
2060                        m = comedi_buf_write_n_allocated(async);
2061                if (m < n)
2062                        n = m;
2063
2064                if (n == 0) {
2065                        if (file->f_flags & O_NONBLOCK) {
2066                                retval = -EAGAIN;
2067                                break;
2068                        }
2069                        schedule();
2070                        if (signal_pending(current)) {
2071                                retval = -ERESTARTSYS;
2072                                break;
2073                        }
2074                        if (!s->busy)
2075                                break;
2076                        if (s->busy != file) {
2077                                retval = -EACCES;
2078                                break;
2079                        }
2080                        continue;
2081                }
2082
2083                m = copy_from_user(async->prealloc_buf + async->buf_write_ptr,
2084                                   buf, n);
2085                if (m) {
2086                        n -= m;
2087                        retval = -EFAULT;
2088                }
2089                comedi_buf_write_free(async, n);
2090
2091                count += n;
2092                nbytes -= n;
2093
2094                buf += n;
2095                break;          /* makes device work like a pipe */
2096        }
2097        set_current_state(TASK_RUNNING);
2098        remove_wait_queue(&async->wait_head, &wait);
2099
2100        return count ? count : retval;
2101}
2102
2103static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
2104                                loff_t *offset)
2105{
2106        struct comedi_subdevice *s;
2107        struct comedi_async *async;
2108        int n, m, count = 0, retval = 0;
2109        DECLARE_WAITQUEUE(wait, current);
2110        const unsigned minor = iminor(file_inode(file));
2111        struct comedi_device *dev = comedi_dev_from_minor(minor);
2112
2113        if (!dev)
2114                return -ENODEV;
2115
2116        if (!dev->attached) {
2117                DPRINTK("no driver configured on comedi%i\n", dev->minor);
2118                return -ENODEV;
2119        }
2120
2121        s = comedi_read_subdevice(dev, minor);
2122        if (!s || !s->async)
2123                return -EIO;
2124
2125        async = s->async;
2126        if (!s->busy || !nbytes)
2127                return 0;
2128        if (s->busy != file)
2129                return -EACCES;
2130
2131        add_wait_queue(&async->wait_head, &wait);
2132        while (nbytes > 0 && !retval) {
2133                set_current_state(TASK_INTERRUPTIBLE);
2134
2135                n = nbytes;
2136
2137                m = comedi_buf_read_n_available(async);
2138                /* printk("%d available\n",m); */
2139                if (async->buf_read_ptr + m > async->prealloc_bufsz)
2140                        m = async->prealloc_bufsz - async->buf_read_ptr;
2141                /* printk("%d contiguous\n",m); */
2142                if (m < n)
2143                        n = m;
2144
2145                if (n == 0) {
2146                        if (!comedi_is_subdevice_running(s)) {
2147                                do_become_nonbusy(dev, s);
2148                                if (comedi_is_subdevice_in_error(s))
2149                                        retval = -EPIPE;
2150                                else
2151                                        retval = 0;
2152                                break;
2153                        }
2154                        if (file->f_flags & O_NONBLOCK) {
2155                                retval = -EAGAIN;
2156                                break;
2157                        }
2158                        schedule();
2159                        if (signal_pending(current)) {
2160                                retval = -ERESTARTSYS;
2161                                break;
2162                        }
2163                        if (!s->busy) {
2164                                retval = 0;
2165                                break;
2166                        }
2167                        if (s->busy != file) {
2168                                retval = -EACCES;
2169                                break;
2170                        }
2171                        continue;
2172                }
2173                m = copy_to_user(buf, async->prealloc_buf +
2174                                 async->buf_read_ptr, n);
2175                if (m) {
2176                        n -= m;
2177                        retval = -EFAULT;
2178                }
2179
2180                comedi_buf_read_alloc(async, n);
2181                comedi_buf_read_free(async, n);
2182
2183                count += n;
2184                nbytes -= n;
2185
2186                buf += n;
2187                break;          /* makes device work like a pipe */
2188        }
2189        if (comedi_is_subdevice_idle(s) &&
2190            async->buf_read_count - async->buf_write_count == 0) {
2191                do_become_nonbusy(dev, s);
2192        }
2193        set_current_state(TASK_RUNNING);
2194        remove_wait_queue(&async->wait_head, &wait);
2195
2196        return count ? count : retval;
2197}
2198
2199static int comedi_open(struct inode *inode, struct file *file)
2200{
2201        const unsigned minor = iminor(inode);
2202        struct comedi_device *dev = comedi_dev_from_minor(minor);
2203
2204        if (!dev) {
2205                DPRINTK("invalid minor number\n");
2206                return -ENODEV;
2207        }
2208
2209        /* This is slightly hacky, but we want module autoloading
2210         * to work for root.
2211         * case: user opens device, attached -> ok
2212         * case: user opens device, unattached, !in_request_module -> autoload
2213         * case: user opens device, unattached, in_request_module -> fail
2214         * case: root opens device, attached -> ok
2215         * case: root opens device, unattached, in_request_module -> ok
2216         *   (typically called from modprobe)
2217         * case: root opens device, unattached, !in_request_module -> autoload
2218         *
2219         * The last could be changed to "-> ok", which would deny root
2220         * autoloading.
2221         */
2222        mutex_lock(&dev->mutex);
2223        if (dev->attached)
2224                goto ok;
2225        if (!capable(CAP_NET_ADMIN) && dev->in_request_module) {
2226                DPRINTK("in request module\n");
2227                mutex_unlock(&dev->mutex);
2228                return -ENODEV;
2229        }
2230        if (capable(CAP_NET_ADMIN) && dev->in_request_module)
2231                goto ok;
2232
2233        dev->in_request_module = true;
2234
2235#ifdef CONFIG_KMOD
2236        mutex_unlock(&dev->mutex);
2237        request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor);
2238        mutex_lock(&dev->mutex);
2239#endif
2240
2241        dev->in_request_module = false;
2242
2243        if (!dev->attached && !capable(CAP_NET_ADMIN)) {
2244                DPRINTK("not attached and not CAP_NET_ADMIN\n");
2245                mutex_unlock(&dev->mutex);
2246                return -ENODEV;
2247        }
2248ok:
2249        __module_get(THIS_MODULE);
2250
2251        if (dev->attached) {
2252                if (!try_module_get(dev->driver->module)) {
2253                        module_put(THIS_MODULE);
2254                        mutex_unlock(&dev->mutex);
2255                        return -ENOSYS;
2256                }
2257        }
2258
2259        if (dev->attached && dev->use_count == 0 && dev->open) {
2260                int rc = dev->open(dev);
2261                if (rc < 0) {
2262                        module_put(dev->driver->module);
2263                        module_put(THIS_MODULE);
2264                        mutex_unlock(&dev->mutex);
2265                        return rc;
2266                }
2267        }
2268
2269        dev->use_count++;
2270
2271        mutex_unlock(&dev->mutex);
2272
2273        return 0;
2274}
2275
2276static int comedi_fasync(int fd, struct file *file, int on)
2277{
2278        const unsigned minor = iminor(file_inode(file));
2279        struct comedi_device *dev = comedi_dev_from_minor(minor);
2280
2281        if (!dev)
2282                return -ENODEV;
2283
2284        return fasync_helper(fd, file, on, &dev->async_queue);
2285}
2286
2287static int comedi_close(struct inode *inode, struct file *file)
2288{
2289        const unsigned minor = iminor(inode);
2290        struct comedi_device *dev = comedi_dev_from_minor(minor);
2291        struct comedi_subdevice *s = NULL;
2292        int i;
2293
2294        if (!dev)
2295                return -ENODEV;
2296
2297        mutex_lock(&dev->mutex);
2298
2299        if (dev->subdevices) {
2300                for (i = 0; i < dev->n_subdevices; i++) {
2301                        s = &dev->subdevices[i];
2302
2303                        if (s->busy == file)
2304                                do_cancel(dev, s);
2305                        if (s->lock == file)
2306                                s->lock = NULL;
2307                }
2308        }
2309        if (dev->attached && dev->use_count == 1 && dev->close)
2310                dev->close(dev);
2311
2312        module_put(THIS_MODULE);
2313        if (dev->attached)
2314                module_put(dev->driver->module);
2315
2316        dev->use_count--;
2317
2318        mutex_unlock(&dev->mutex);
2319
2320        if (file->f_flags & FASYNC)
2321                comedi_fasync(-1, file, 0);
2322
2323        return 0;
2324}
2325
2326static const struct file_operations comedi_fops = {
2327        .owner = THIS_MODULE,
2328        .unlocked_ioctl = comedi_unlocked_ioctl,
2329        .compat_ioctl = comedi_compat_ioctl,
2330        .open = comedi_open,
2331        .release = comedi_close,
2332        .read = comedi_read,
2333        .write = comedi_write,
2334        .mmap = comedi_mmap,
2335        .poll = comedi_poll,
2336        .fasync = comedi_fasync,
2337        .llseek = noop_llseek,
2338};
2339
2340void comedi_error(const struct comedi_device *dev, const char *s)
2341{
2342        dev_err(dev->class_dev, "%s: %s\n", dev->driver->driver_name, s);
2343}
2344EXPORT_SYMBOL_GPL(comedi_error);
2345
2346void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
2347{
2348        struct comedi_async *async = s->async;
2349        unsigned runflags = 0;
2350        unsigned runflags_mask = 0;
2351
2352        /* DPRINTK("comedi_event 0x%x\n",mask); */
2353
2354        if (!comedi_is_subdevice_running(s))
2355                return;
2356
2357        if (s->
2358            async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR |
2359                             COMEDI_CB_OVERFLOW)) {
2360                runflags_mask |= SRF_RUNNING;
2361        }
2362        /* remember if an error event has occurred, so an error
2363         * can be returned the next time the user does a read() */
2364        if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) {
2365                runflags_mask |= SRF_ERROR;
2366                runflags |= SRF_ERROR;
2367        }
2368        if (runflags_mask) {
2369                /*sets SRF_ERROR and SRF_RUNNING together atomically */
2370                comedi_set_subdevice_runflags(s, runflags_mask, runflags);
2371        }
2372
2373        if (async->cb_mask & s->async->events) {
2374                if (comedi_get_subdevice_runflags(s) & SRF_USER) {
2375                        wake_up_interruptible(&async->wait_head);
2376                        if (s->subdev_flags & SDF_CMD_READ)
2377                                kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
2378                        if (s->subdev_flags & SDF_CMD_WRITE)
2379                                kill_fasync(&dev->async_queue, SIGIO, POLL_OUT);
2380                } else {
2381                        if (async->cb_func)
2382                                async->cb_func(s->async->events, async->cb_arg);
2383                }
2384        }
2385        s->async->events = 0;
2386}
2387EXPORT_SYMBOL_GPL(comedi_event);
2388
2389/* Note: the ->mutex is pre-locked on successful return */
2390struct comedi_device *comedi_alloc_board_minor(struct device *hardware_device)
2391{
2392        struct comedi_device *dev;
2393        struct device *csdev;
2394        unsigned i;
2395
2396        dev = kzalloc(sizeof(struct comedi_device), GFP_KERNEL);
2397        if (dev == NULL)
2398                return ERR_PTR(-ENOMEM);
2399        comedi_device_init(dev);
2400        comedi_set_hw_dev(dev, hardware_device);
2401        mutex_lock(&dev->mutex);
2402        mutex_lock(&comedi_board_minor_table_lock);
2403        for (i = hardware_device ? comedi_num_legacy_minors : 0;
2404             i < COMEDI_NUM_BOARD_MINORS; ++i) {
2405                if (comedi_board_minor_table[i] == NULL) {
2406                        comedi_board_minor_table[i] = dev;
2407                        break;
2408                }
2409        }
2410        mutex_unlock(&comedi_board_minor_table_lock);
2411        if (i == COMEDI_NUM_BOARD_MINORS) {
2412                mutex_unlock(&dev->mutex);
2413                comedi_device_cleanup(dev);
2414                kfree(dev);
2415                pr_err("comedi: error: ran out of minor numbers for board device files.\n");
2416                return ERR_PTR(-EBUSY);
2417        }
2418        dev->minor = i;
2419        csdev = device_create(comedi_class, hardware_device,
2420                              MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i", i);
2421        if (!IS_ERR(csdev))
2422                dev->class_dev = csdev;
2423
2424        /* Note: dev->mutex needs to be unlocked by the caller. */
2425        return dev;
2426}
2427
2428static void comedi_free_board_minor(unsigned minor)
2429{
2430        BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
2431        comedi_free_board_dev(comedi_clear_board_minor(minor));
2432}
2433
2434void comedi_release_hardware_device(struct device *hardware_device)
2435{
2436        int minor;
2437        struct comedi_device *dev;
2438
2439        for (minor = comedi_num_legacy_minors; minor < COMEDI_NUM_BOARD_MINORS;
2440             minor++) {
2441                mutex_lock(&comedi_board_minor_table_lock);
2442                dev = comedi_board_minor_table[minor];
2443                if (dev && dev->hw_dev == hardware_device) {
2444                        comedi_board_minor_table[minor] = NULL;
2445                        mutex_unlock(&comedi_board_minor_table_lock);
2446                        comedi_free_board_dev(dev);
2447                        break;
2448                }
2449                mutex_unlock(&comedi_board_minor_table_lock);
2450        }
2451}
2452
2453int comedi_alloc_subdevice_minor(struct comedi_subdevice *s)
2454{
2455        struct comedi_device *dev = s->device;
2456        struct device *csdev;
2457        unsigned i;
2458
2459        mutex_lock(&comedi_subdevice_minor_table_lock);
2460        for (i = 0; i < COMEDI_NUM_SUBDEVICE_MINORS; ++i) {
2461                if (comedi_subdevice_minor_table[i] == NULL) {
2462                        comedi_subdevice_minor_table[i] = s;
2463                        break;
2464                }
2465        }
2466        mutex_unlock(&comedi_subdevice_minor_table_lock);
2467        if (i == COMEDI_NUM_SUBDEVICE_MINORS) {
2468                pr_err("comedi: error: ran out of minor numbers for subdevice files.\n");
2469                return -EBUSY;
2470        }
2471        i += COMEDI_NUM_BOARD_MINORS;
2472        s->minor = i;
2473        csdev = device_create(comedi_class, dev->class_dev,
2474                              MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i_subd%i",
2475                              dev->minor, s->index);
2476        if (!IS_ERR(csdev))
2477                s->class_dev = csdev;
2478
2479        return 0;
2480}
2481
2482void comedi_free_subdevice_minor(struct comedi_subdevice *s)
2483{
2484        unsigned int i;
2485
2486        if (s == NULL)
2487                return;
2488        if (s->minor < 0)
2489                return;
2490
2491        BUG_ON(s->minor >= COMEDI_NUM_MINORS);
2492        BUG_ON(s->minor < COMEDI_NUM_BOARD_MINORS);
2493
2494        i = s->minor - COMEDI_NUM_BOARD_MINORS;
2495        mutex_lock(&comedi_subdevice_minor_table_lock);
2496        if (s == comedi_subdevice_minor_table[i])
2497                comedi_subdevice_minor_table[i] = NULL;
2498        mutex_unlock(&comedi_subdevice_minor_table_lock);
2499        if (s->class_dev) {
2500                device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
2501                s->class_dev = NULL;
2502        }
2503}
2504
2505static void comedi_cleanup_board_minors(void)
2506{
2507        unsigned i;
2508
2509        for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++)
2510                comedi_free_board_minor(i);
2511}
2512
2513static int __init comedi_init(void)
2514{
2515        int i;
2516        int retval;
2517
2518        pr_info("comedi: version " COMEDI_RELEASE " - http://www.comedi.org\n");
2519
2520        if (comedi_num_legacy_minors < 0 ||
2521            comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) {
2522                pr_err("comedi: error: invalid value for module parameter \"comedi_num_legacy_minors\".  Valid values are 0 through %i.\n",
2523                       COMEDI_NUM_BOARD_MINORS);
2524                return -EINVAL;
2525        }
2526
2527        retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2528                                        COMEDI_NUM_MINORS, "comedi");
2529        if (retval)
2530                return -EIO;
2531        cdev_init(&comedi_cdev, &comedi_fops);
2532        comedi_cdev.owner = THIS_MODULE;
2533        kobject_set_name(&comedi_cdev.kobj, "comedi");
2534        if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) {
2535                unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2536                                         COMEDI_NUM_MINORS);
2537                return -EIO;
2538        }
2539        comedi_class = class_create(THIS_MODULE, "comedi");
2540        if (IS_ERR(comedi_class)) {
2541                pr_err("comedi: failed to create class\n");
2542                cdev_del(&comedi_cdev);
2543                unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2544                                         COMEDI_NUM_MINORS);
2545                return PTR_ERR(comedi_class);
2546        }
2547
2548        comedi_class->dev_attrs = comedi_dev_attrs;
2549
2550        /* XXX requires /proc interface */
2551        comedi_proc_init();
2552
2553        /* create devices files for legacy/manual use */
2554        for (i = 0; i < comedi_num_legacy_minors; i++) {
2555                struct comedi_device *dev;
2556                dev = comedi_alloc_board_minor(NULL);
2557                if (IS_ERR(dev)) {
2558                        comedi_cleanup_board_minors();
2559                        cdev_del(&comedi_cdev);
2560                        unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2561                                                 COMEDI_NUM_MINORS);
2562                        return PTR_ERR(dev);
2563                } else {
2564                        /* comedi_alloc_board_minor() locked the mutex */
2565                        mutex_unlock(&dev->mutex);
2566                }
2567        }
2568
2569        return 0;
2570}
2571module_init(comedi_init);
2572
2573static void __exit comedi_cleanup(void)
2574{
2575        int i;
2576
2577        comedi_cleanup_board_minors();
2578        for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i)
2579                BUG_ON(comedi_board_minor_table[i]);
2580        for (i = 0; i < COMEDI_NUM_SUBDEVICE_MINORS; ++i)
2581                BUG_ON(comedi_subdevice_minor_table[i]);
2582
2583        class_destroy(comedi_class);
2584        cdev_del(&comedi_cdev);
2585        unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
2586
2587        comedi_proc_cleanup();
2588}
2589module_exit(comedi_cleanup);
2590
2591MODULE_AUTHOR("http://www.comedi.org");
2592MODULE_DESCRIPTION("Comedi core module");
2593MODULE_LICENSE("GPL");
2594