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