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