linux/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
<<
>>
Prefs
   1/*
   2    kcomedilib/kcomedilib.c
   3    a comedlib interface for kernel modules
   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#define __NO_VERSION__
  25#include <linux/module.h>
  26
  27#include <linux/errno.h>
  28#include <linux/kernel.h>
  29#include <linux/sched.h>
  30#include <linux/fcntl.h>
  31#include <linux/delay.h>
  32#include <linux/ioport.h>
  33#include <linux/mm.h>
  34#include <linux/slab.h>
  35#include <asm/io.h>
  36
  37#include "../comedi.h"
  38#include "../comedilib.h"
  39#include "../comedidev.h"
  40
  41MODULE_AUTHOR("David Schleef <ds@schleef.org>");
  42MODULE_DESCRIPTION("Comedi kernel library");
  43MODULE_LICENSE("GPL");
  44
  45void *comedi_open(const char *filename)
  46{
  47        struct comedi_device_file_info *dev_file_info;
  48        struct comedi_device *dev;
  49        unsigned int minor;
  50
  51        if (strncmp(filename, "/dev/comedi", 11) != 0)
  52                return NULL;
  53
  54        minor = simple_strtoul(filename + 11, NULL, 0);
  55
  56        if (minor >= COMEDI_NUM_BOARD_MINORS)
  57                return NULL;
  58
  59        dev_file_info = comedi_get_device_file_info(minor);
  60        if (dev_file_info == NULL)
  61                return NULL;
  62        dev = dev_file_info->device;
  63
  64        if (dev == NULL || !dev->attached)
  65                return NULL;
  66
  67        if (!try_module_get(dev->driver->module))
  68                return NULL;
  69
  70        return (void *)dev;
  71}
  72
  73void *comedi_open_old(unsigned int minor)
  74{
  75        struct comedi_device_file_info *dev_file_info;
  76        struct comedi_device *dev;
  77
  78        if (minor >= COMEDI_NUM_MINORS)
  79                return NULL;
  80
  81        dev_file_info = comedi_get_device_file_info(minor);
  82        if (dev_file_info == NULL)
  83                return NULL;
  84        dev = dev_file_info->device;
  85
  86        if (dev == NULL || !dev->attached)
  87                return NULL;
  88
  89        return (void *)dev;
  90}
  91
  92int comedi_close(void *d)
  93{
  94        struct comedi_device *dev = (struct comedi_device *)d;
  95
  96        module_put(dev->driver->module);
  97
  98        return 0;
  99}
 100
 101int comedi_loglevel(int newlevel)
 102{
 103        return 0;
 104}
 105
 106void comedi_perror(const char *message)
 107{
 108        printk("%s: unknown error\n", message);
 109}
 110
 111char *comedi_strerror(int err)
 112{
 113        return "unknown error";
 114}
 115
 116int comedi_fileno(void *d)
 117{
 118        struct comedi_device *dev = (struct comedi_device *)d;
 119
 120        /* return something random */
 121        return dev->minor;
 122}
 123
 124int comedi_command(void *d, struct comedi_cmd *cmd)
 125{
 126        struct comedi_device *dev = (struct comedi_device *)d;
 127        struct comedi_subdevice *s;
 128        struct comedi_async *async;
 129        unsigned runflags;
 130
 131        if (cmd->subdev >= dev->n_subdevices)
 132                return -ENODEV;
 133
 134        s = dev->subdevices + cmd->subdev;
 135        if (s->type == COMEDI_SUBD_UNUSED)
 136                return -EIO;
 137
 138        async = s->async;
 139        if (async == NULL)
 140                return -ENODEV;
 141
 142        if (s->busy)
 143                return -EBUSY;
 144        s->busy = d;
 145
 146        if (async->cb_mask & COMEDI_CB_EOS)
 147                cmd->flags |= TRIG_WAKE_EOS;
 148
 149        async->cmd = *cmd;
 150
 151        runflags = SRF_RUNNING;
 152
 153        comedi_set_subdevice_runflags(s, ~0, runflags);
 154
 155        comedi_reset_async_buf(async);
 156
 157        return s->do_cmd(dev, s);
 158}
 159
 160int comedi_command_test(void *d, struct comedi_cmd *cmd)
 161{
 162        struct comedi_device *dev = (struct comedi_device *)d;
 163        struct comedi_subdevice *s;
 164
 165        if (cmd->subdev >= dev->n_subdevices)
 166                return -ENODEV;
 167
 168        s = dev->subdevices + cmd->subdev;
 169        if (s->type == COMEDI_SUBD_UNUSED)
 170                return -EIO;
 171
 172        if (s->async == NULL)
 173                return -ENODEV;
 174
 175        return s->do_cmdtest(dev, s, cmd);
 176}
 177
 178/*
 179 *      COMEDI_INSN
 180 *      perform an instruction
 181 */
 182int comedi_do_insn(void *d, struct comedi_insn *insn)
 183{
 184        struct comedi_device *dev = (struct comedi_device *)d;
 185        struct comedi_subdevice *s;
 186        int ret = 0;
 187
 188        if (insn->insn & INSN_MASK_SPECIAL) {
 189                switch (insn->insn) {
 190                case INSN_GTOD:
 191                        {
 192                                struct timeval tv;
 193
 194                                do_gettimeofday(&tv);
 195                                insn->data[0] = tv.tv_sec;
 196                                insn->data[1] = tv.tv_usec;
 197                                ret = 2;
 198
 199                                break;
 200                        }
 201                case INSN_WAIT:
 202                        /* XXX isn't the value supposed to be nanosecs? */
 203                        if (insn->n != 1 || insn->data[0] >= 100) {
 204                                ret = -EINVAL;
 205                                break;
 206                        }
 207                        udelay(insn->data[0]);
 208                        ret = 1;
 209                        break;
 210                case INSN_INTTRIG:
 211                        if (insn->n != 1) {
 212                                ret = -EINVAL;
 213                                break;
 214                        }
 215                        if (insn->subdev >= dev->n_subdevices) {
 216                                printk("%d not usable subdevice\n",
 217                                       insn->subdev);
 218                                ret = -EINVAL;
 219                                break;
 220                        }
 221                        s = dev->subdevices + insn->subdev;
 222                        if (!s->async) {
 223                                printk("no async\n");
 224                                ret = -EINVAL;
 225                                break;
 226                        }
 227                        if (!s->async->inttrig) {
 228                                printk("no inttrig\n");
 229                                ret = -EAGAIN;
 230                                break;
 231                        }
 232                        ret = s->async->inttrig(dev, s, insn->data[0]);
 233                        if (ret >= 0)
 234                                ret = 1;
 235                        break;
 236                default:
 237                        ret = -EINVAL;
 238                }
 239        } else {
 240                /* a subdevice instruction */
 241                if (insn->subdev >= dev->n_subdevices) {
 242                        ret = -EINVAL;
 243                        goto error;
 244                }
 245                s = dev->subdevices + insn->subdev;
 246
 247                if (s->type == COMEDI_SUBD_UNUSED) {
 248                        printk("%d not useable subdevice\n", insn->subdev);
 249                        ret = -EIO;
 250                        goto error;
 251                }
 252
 253                /* XXX check lock */
 254
 255                ret = check_chanlist(s, 1, &insn->chanspec);
 256                if (ret < 0) {
 257                        printk("bad chanspec\n");
 258                        ret = -EINVAL;
 259                        goto error;
 260                }
 261
 262                if (s->busy) {
 263                        ret = -EBUSY;
 264                        goto error;
 265                }
 266                s->busy = d;
 267
 268                switch (insn->insn) {
 269                case INSN_READ:
 270                        ret = s->insn_read(dev, s, insn, insn->data);
 271                        break;
 272                case INSN_WRITE:
 273                        ret = s->insn_write(dev, s, insn, insn->data);
 274                        break;
 275                case INSN_BITS:
 276                        ret = s->insn_bits(dev, s, insn, insn->data);
 277                        break;
 278                case INSN_CONFIG:
 279                        /* XXX should check instruction length */
 280                        ret = s->insn_config(dev, s, insn, insn->data);
 281                        break;
 282                default:
 283                        ret = -EINVAL;
 284                        break;
 285                }
 286
 287                s->busy = NULL;
 288        }
 289        if (ret < 0)
 290                goto error;
 291#if 0
 292        /* XXX do we want this? -- abbotti #if'ed it out for now. */
 293        if (ret != insn->n) {
 294                printk("BUG: result of insn != insn.n\n");
 295                ret = -EINVAL;
 296                goto error;
 297        }
 298#endif
 299error:
 300
 301        return ret;
 302}
 303
 304/*
 305        COMEDI_LOCK
 306        lock subdevice
 307
 308        arg:
 309                subdevice number
 310
 311        reads:
 312                none
 313
 314        writes:
 315                none
 316
 317        necessary locking:
 318        - ioctl/rt lock  (this type)
 319        - lock while subdevice busy
 320        - lock while subdevice being programmed
 321
 322*/
 323int comedi_lock(void *d, unsigned int subdevice)
 324{
 325        struct comedi_device *dev = (struct comedi_device *)d;
 326        struct comedi_subdevice *s;
 327        unsigned long flags;
 328        int ret = 0;
 329
 330        if (subdevice >= dev->n_subdevices)
 331                return -EINVAL;
 332
 333        s = dev->subdevices + subdevice;
 334
 335        spin_lock_irqsave(&s->spin_lock, flags);
 336
 337        if (s->busy) {
 338                ret = -EBUSY;
 339        } else {
 340                if (s->lock) {
 341                        ret = -EBUSY;
 342                } else {
 343                        s->lock = d;
 344                }
 345        }
 346
 347        spin_unlock_irqrestore(&s->spin_lock, flags);
 348
 349        return ret;
 350}
 351
 352/*
 353        COMEDI_UNLOCK
 354        unlock subdevice
 355
 356        arg:
 357                subdevice number
 358
 359        reads:
 360                none
 361
 362        writes:
 363                none
 364
 365*/
 366int comedi_unlock(void *d, unsigned int subdevice)
 367{
 368        struct comedi_device *dev = (struct comedi_device *)d;
 369        struct comedi_subdevice *s;
 370        unsigned long flags;
 371        struct comedi_async *async;
 372        int ret;
 373
 374        if (subdevice >= dev->n_subdevices)
 375                return -EINVAL;
 376
 377        s = dev->subdevices + subdevice;
 378
 379        async = s->async;
 380
 381        spin_lock_irqsave(&s->spin_lock, flags);
 382
 383        if (s->busy) {
 384                ret = -EBUSY;
 385        } else if (s->lock && s->lock != (void *)d) {
 386                ret = -EACCES;
 387        } else {
 388                s->lock = NULL;
 389
 390                if (async) {
 391                        async->cb_mask = 0;
 392                        async->cb_func = NULL;
 393                        async->cb_arg = NULL;
 394                }
 395
 396                ret = 0;
 397        }
 398
 399        spin_unlock_irqrestore(&s->spin_lock, flags);
 400
 401        return ret;
 402}
 403
 404/*
 405        COMEDI_CANCEL
 406        cancel acquisition ioctl
 407
 408        arg:
 409                subdevice number
 410
 411        reads:
 412                nothing
 413
 414        writes:
 415                nothing
 416
 417*/
 418int comedi_cancel(void *d, unsigned int subdevice)
 419{
 420        struct comedi_device *dev = (struct comedi_device *)d;
 421        struct comedi_subdevice *s;
 422        int ret = 0;
 423
 424        if (subdevice >= dev->n_subdevices)
 425                return -EINVAL;
 426
 427        s = dev->subdevices + subdevice;
 428
 429        if (s->lock && s->lock != d)
 430                return -EACCES;
 431
 432#if 0
 433        if (!s->busy)
 434                return 0;
 435
 436        if (s->busy != d)
 437                return -EBUSY;
 438#endif
 439
 440        if (!s->cancel || !s->async)
 441                return -EINVAL;
 442
 443        ret = s->cancel(dev, s);
 444
 445        if (ret)
 446                return ret;
 447
 448        comedi_set_subdevice_runflags(s, SRF_RUNNING | SRF_RT, 0);
 449        s->async->inttrig = NULL;
 450        s->busy = NULL;
 451
 452        return 0;
 453}
 454
 455/*
 456   registration of callback functions
 457 */
 458int comedi_register_callback(void *d, unsigned int subdevice,
 459                             unsigned int mask, int (*cb) (unsigned int,
 460                                                           void *), void *arg)
 461{
 462        struct comedi_device *dev = (struct comedi_device *)d;
 463        struct comedi_subdevice *s;
 464        struct comedi_async *async;
 465
 466        if (subdevice >= dev->n_subdevices)
 467                return -EINVAL;
 468
 469        s = dev->subdevices + subdevice;
 470
 471        async = s->async;
 472        if (s->type == COMEDI_SUBD_UNUSED || !async)
 473                return -EIO;
 474
 475        /* are we locked? (ioctl lock) */
 476        if (s->lock && s->lock != d)
 477                return -EACCES;
 478
 479        /* are we busy? */
 480        if (s->busy)
 481                return -EBUSY;
 482
 483        if (!mask) {
 484                async->cb_mask = 0;
 485                async->cb_func = NULL;
 486                async->cb_arg = NULL;
 487        } else {
 488                async->cb_mask = mask;
 489                async->cb_func = cb;
 490                async->cb_arg = arg;
 491        }
 492
 493        return 0;
 494}
 495
 496int comedi_poll(void *d, unsigned int subdevice)
 497{
 498        struct comedi_device *dev = (struct comedi_device *)d;
 499        struct comedi_subdevice *s = dev->subdevices;
 500        struct comedi_async *async;
 501
 502        if (subdevice >= dev->n_subdevices)
 503                return -EINVAL;
 504
 505        s = dev->subdevices + subdevice;
 506
 507        async = s->async;
 508        if (s->type == COMEDI_SUBD_UNUSED || !async)
 509                return -EIO;
 510
 511        /* are we locked? (ioctl lock) */
 512        if (s->lock && s->lock != d)
 513                return -EACCES;
 514
 515        /* are we running? XXX wrong? */
 516        if (!s->busy)
 517                return -EIO;
 518
 519        return s->poll(dev, s);
 520}
 521
 522/* WARNING: not portable */
 523int comedi_map(void *d, unsigned int subdevice, void *ptr)
 524{
 525        struct comedi_device *dev = (struct comedi_device *)d;
 526        struct comedi_subdevice *s;
 527
 528        if (subdevice >= dev->n_subdevices)
 529                return -EINVAL;
 530
 531        s = dev->subdevices + subdevice;
 532
 533        if (!s->async)
 534                return -EINVAL;
 535
 536        if (ptr)
 537                *((void **)ptr) = s->async->prealloc_buf;
 538
 539        /* XXX no reference counting */
 540
 541        return 0;
 542}
 543
 544/* WARNING: not portable */
 545int comedi_unmap(void *d, unsigned int subdevice)
 546{
 547        struct comedi_device *dev = (struct comedi_device *)d;
 548        struct comedi_subdevice *s;
 549
 550        if (subdevice >= dev->n_subdevices)
 551                return -EINVAL;
 552
 553        s = dev->subdevices + subdevice;
 554
 555        if (!s->async)
 556                return -EINVAL;
 557
 558        /* XXX no reference counting */
 559
 560        return 0;
 561}
 562