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