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