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