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