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