comedi_fops.c revision 21fe2eea6381845956322e63e441f351774de7f9
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 n = nbytes; 1580 1581 m = n; 1582 if (async->buf_write_ptr + m > async->prealloc_bufsz) 1583 m = async->prealloc_bufsz - async->buf_write_ptr; 1584 comedi_buf_write_alloc(async, async->prealloc_bufsz); 1585 if (m > comedi_buf_write_n_allocated(async)) 1586 m = comedi_buf_write_n_allocated(async); 1587 if (m < n) 1588 n = m; 1589 1590 if (n == 0) { 1591 if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) { 1592 if (comedi_get_subdevice_runflags(s) & 1593 SRF_ERROR) { 1594 retval = -EPIPE; 1595 } else { 1596 retval = 0; 1597 } 1598 do_become_nonbusy(dev, s); 1599 break; 1600 } 1601 if (file->f_flags & O_NONBLOCK) { 1602 retval = -EAGAIN; 1603 break; 1604 } 1605 if (signal_pending(current)) { 1606 retval = -ERESTARTSYS; 1607 break; 1608 } 1609 schedule(); 1610 if (!s->busy) 1611 break; 1612 if (s->busy != file) { 1613 retval = -EACCES; 1614 break; 1615 } 1616 continue; 1617 } 1618 1619 m = copy_from_user(async->prealloc_buf + async->buf_write_ptr, 1620 buf, n); 1621 if (m) { 1622 n -= m; 1623 retval = -EFAULT; 1624 } 1625 comedi_buf_write_free(async, n); 1626 1627 count += n; 1628 nbytes -= n; 1629 1630 buf += n; 1631 break; /* makes device work like a pipe */ 1632 } 1633 set_current_state(TASK_RUNNING); 1634 remove_wait_queue(&async->wait_head, &wait); 1635 1636done: 1637 return count ? count : retval; 1638} 1639 1640static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, 1641 loff_t *offset) 1642{ 1643 struct comedi_subdevice *s; 1644 struct comedi_async *async; 1645 int n, m, count = 0, retval = 0; 1646 DECLARE_WAITQUEUE(wait, current); 1647 const unsigned minor = iminor(file->f_dentry->d_inode); 1648 struct comedi_device_file_info *dev_file_info = 1649 comedi_get_device_file_info(minor); 1650 struct comedi_device *dev = dev_file_info->device; 1651 1652 if (!dev->attached) { 1653 DPRINTK("no driver configured on comedi%i\n", dev->minor); 1654 retval = -ENODEV; 1655 goto done; 1656 } 1657 1658 s = comedi_get_read_subdevice(dev_file_info); 1659 if (s == NULL) { 1660 retval = -EIO; 1661 goto done; 1662 } 1663 async = s->async; 1664 if (!nbytes) { 1665 retval = 0; 1666 goto done; 1667 } 1668 if (!s->busy) { 1669 retval = 0; 1670 goto done; 1671 } 1672 if (s->busy != file) { 1673 retval = -EACCES; 1674 goto done; 1675 } 1676 1677 add_wait_queue(&async->wait_head, &wait); 1678 while (nbytes > 0 && !retval) { 1679 set_current_state(TASK_INTERRUPTIBLE); 1680 1681 n = nbytes; 1682 1683 m = comedi_buf_read_n_available(async); 1684 /* printk("%d available\n",m); */ 1685 if (async->buf_read_ptr + m > async->prealloc_bufsz) 1686 m = async->prealloc_bufsz - async->buf_read_ptr; 1687 /* printk("%d contiguous\n",m); */ 1688 if (m < n) 1689 n = m; 1690 1691 if (n == 0) { 1692 if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) { 1693 do_become_nonbusy(dev, s); 1694 if (comedi_get_subdevice_runflags(s) & 1695 SRF_ERROR) { 1696 retval = -EPIPE; 1697 } else { 1698 retval = 0; 1699 } 1700 break; 1701 } 1702 if (file->f_flags & O_NONBLOCK) { 1703 retval = -EAGAIN; 1704 break; 1705 } 1706 if (signal_pending(current)) { 1707 retval = -ERESTARTSYS; 1708 break; 1709 } 1710 schedule(); 1711 if (!s->busy) { 1712 retval = 0; 1713 break; 1714 } 1715 if (s->busy != file) { 1716 retval = -EACCES; 1717 break; 1718 } 1719 continue; 1720 } 1721 m = copy_to_user(buf, async->prealloc_buf + 1722 async->buf_read_ptr, n); 1723 if (m) { 1724 n -= m; 1725 retval = -EFAULT; 1726 } 1727 1728 comedi_buf_read_alloc(async, n); 1729 comedi_buf_read_free(async, n); 1730 1731 count += n; 1732 nbytes -= n; 1733 1734 buf += n; 1735 break; /* makes device work like a pipe */ 1736 } 1737 if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | SRF_RUNNING)) && 1738 async->buf_read_count - async->buf_write_count == 0) { 1739 do_become_nonbusy(dev, s); 1740 } 1741 set_current_state(TASK_RUNNING); 1742 remove_wait_queue(&async->wait_head, &wait); 1743 1744done: 1745 return count ? count : retval; 1746} 1747 1748/* 1749 This function restores a subdevice to an idle state. 1750 */ 1751void do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s) 1752{ 1753 struct comedi_async *async = s->async; 1754 1755 comedi_set_subdevice_runflags(s, SRF_RUNNING, 0); 1756 if (async) { 1757 comedi_reset_async_buf(async); 1758 async->inttrig = NULL; 1759 } else { 1760 printk(KERN_ERR 1761 "BUG: (?) do_become_nonbusy called with async=0\n"); 1762 } 1763 1764 s->busy = NULL; 1765} 1766 1767static int comedi_open(struct inode *inode, struct file *file) 1768{ 1769 const unsigned minor = iminor(inode); 1770 struct comedi_device_file_info *dev_file_info = 1771 comedi_get_device_file_info(minor); 1772 struct comedi_device *dev = 1773 dev_file_info ? dev_file_info->device : NULL; 1774 1775 if (dev == NULL) { 1776 DPRINTK("invalid minor number\n"); 1777 return -ENODEV; 1778 } 1779 1780 /* This is slightly hacky, but we want module autoloading 1781 * to work for root. 1782 * case: user opens device, attached -> ok 1783 * case: user opens device, unattached, in_request_module=0 -> autoload 1784 * case: user opens device, unattached, in_request_module=1 -> fail 1785 * case: root opens device, attached -> ok 1786 * case: root opens device, unattached, in_request_module=1 -> ok 1787 * (typically called from modprobe) 1788 * case: root opens device, unattached, in_request_module=0 -> autoload 1789 * 1790 * The last could be changed to "-> ok", which would deny root 1791 * autoloading. 1792 */ 1793 mutex_lock(&dev->mutex); 1794 if (dev->attached) 1795 goto ok; 1796 if (!capable(CAP_NET_ADMIN) && dev->in_request_module) { 1797 DPRINTK("in request module\n"); 1798 mutex_unlock(&dev->mutex); 1799 return -ENODEV; 1800 } 1801 if (capable(CAP_NET_ADMIN) && dev->in_request_module) 1802 goto ok; 1803 1804 dev->in_request_module = 1; 1805 1806#ifdef CONFIG_KMOD 1807 mutex_unlock(&dev->mutex); 1808 request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor); 1809 mutex_lock(&dev->mutex); 1810#endif 1811 1812 dev->in_request_module = 0; 1813 1814 if (!dev->attached && !capable(CAP_NET_ADMIN)) { 1815 DPRINTK("not attached and not CAP_NET_ADMIN\n"); 1816 mutex_unlock(&dev->mutex); 1817 return -ENODEV; 1818 } 1819ok: 1820 __module_get(THIS_MODULE); 1821 1822 if (dev->attached) { 1823 if (!try_module_get(dev->driver->module)) { 1824 module_put(THIS_MODULE); 1825 mutex_unlock(&dev->mutex); 1826 return -ENOSYS; 1827 } 1828 } 1829 1830 if (dev->attached && dev->use_count == 0 && dev->open) 1831 dev->open(dev); 1832 1833 dev->use_count++; 1834 1835 mutex_unlock(&dev->mutex); 1836 1837 return 0; 1838} 1839 1840static int comedi_close(struct inode *inode, struct file *file) 1841{ 1842 const unsigned minor = iminor(inode); 1843 struct comedi_device_file_info *dev_file_info = 1844 comedi_get_device_file_info(minor); 1845 struct comedi_device *dev = dev_file_info->device; 1846 struct comedi_subdevice *s = NULL; 1847 int i; 1848 1849 mutex_lock(&dev->mutex); 1850 1851 if (dev->subdevices) { 1852 for (i = 0; i < dev->n_subdevices; i++) { 1853 s = dev->subdevices + i; 1854 1855 if (s->busy == file) 1856 do_cancel(dev, s); 1857 if (s->lock == file) 1858 s->lock = NULL; 1859 } 1860 } 1861 if (dev->attached && dev->use_count == 1 && dev->close) 1862 dev->close(dev); 1863 1864 module_put(THIS_MODULE); 1865 if (dev->attached) 1866 module_put(dev->driver->module); 1867 1868 dev->use_count--; 1869 1870 mutex_unlock(&dev->mutex); 1871 1872 if (file->f_flags & FASYNC) 1873 comedi_fasync(-1, file, 0); 1874 1875 return 0; 1876} 1877 1878static int comedi_fasync(int fd, struct file *file, int on) 1879{ 1880 const unsigned minor = iminor(file->f_dentry->d_inode); 1881 struct comedi_device_file_info *dev_file_info = 1882 comedi_get_device_file_info(minor); 1883 1884 struct comedi_device *dev = dev_file_info->device; 1885 1886 return fasync_helper(fd, file, on, &dev->async_queue); 1887} 1888 1889const struct file_operations comedi_fops = { 1890 .owner = THIS_MODULE, 1891 .unlocked_ioctl = comedi_unlocked_ioctl, 1892 .compat_ioctl = comedi_compat_ioctl, 1893 .open = comedi_open, 1894 .release = comedi_close, 1895 .read = comedi_read, 1896 .write = comedi_write, 1897 .mmap = comedi_mmap, 1898 .poll = comedi_poll, 1899 .fasync = comedi_fasync, 1900}; 1901 1902struct class *comedi_class; 1903static struct cdev comedi_cdev; 1904 1905static void comedi_cleanup_legacy_minors(void) 1906{ 1907 unsigned i; 1908 1909 for (i = 0; i < comedi_num_legacy_minors; i++) 1910 comedi_free_board_minor(i); 1911} 1912 1913static int __init comedi_init(void) 1914{ 1915 int i; 1916 int retval; 1917 1918 printk(KERN_INFO "comedi: version " COMEDI_RELEASE 1919 " - http://www.comedi.org\n"); 1920 1921 if (comedi_num_legacy_minors < 0 || 1922 comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) { 1923 printk(KERN_ERR "comedi: error: invalid value for module " 1924 "parameter \"comedi_num_legacy_minors\". Valid values " 1925 "are 0 through %i.\n", COMEDI_NUM_BOARD_MINORS); 1926 return -EINVAL; 1927 } 1928 1929 /* 1930 * comedi is unusable if both comedi_autoconfig and 1931 * comedi_num_legacy_minors are zero, so we might as well adjust the 1932 * defaults in that case 1933 */ 1934 if (comedi_autoconfig == 0 && comedi_num_legacy_minors == 0) 1935 comedi_num_legacy_minors = 16; 1936 1937 memset(comedi_file_info_table, 0, 1938 sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS); 1939 1940 retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0), 1941 COMEDI_NUM_MINORS, "comedi"); 1942 if (retval) 1943 return -EIO; 1944 cdev_init(&comedi_cdev, &comedi_fops); 1945 comedi_cdev.owner = THIS_MODULE; 1946 kobject_set_name(&comedi_cdev.kobj, "comedi"); 1947 if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) { 1948 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), 1949 COMEDI_NUM_MINORS); 1950 return -EIO; 1951 } 1952 comedi_class = class_create(THIS_MODULE, "comedi"); 1953 if (IS_ERR(comedi_class)) { 1954 printk(KERN_ERR "comedi: failed to create class"); 1955 cdev_del(&comedi_cdev); 1956 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), 1957 COMEDI_NUM_MINORS); 1958 return PTR_ERR(comedi_class); 1959 } 1960 1961 /* XXX requires /proc interface */ 1962 comedi_proc_init(); 1963 1964 /* create devices files for legacy/manual use */ 1965 for (i = 0; i < comedi_num_legacy_minors; i++) { 1966 int minor; 1967 minor = comedi_alloc_board_minor(NULL); 1968 if (minor < 0) { 1969 comedi_cleanup_legacy_minors(); 1970 cdev_del(&comedi_cdev); 1971 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), 1972 COMEDI_NUM_MINORS); 1973 return minor; 1974 } 1975 } 1976 1977 return 0; 1978} 1979 1980static void __exit comedi_cleanup(void) 1981{ 1982 int i; 1983 1984 comedi_cleanup_legacy_minors(); 1985 for (i = 0; i < COMEDI_NUM_MINORS; ++i) 1986 BUG_ON(comedi_file_info_table[i]); 1987 1988 class_destroy(comedi_class); 1989 cdev_del(&comedi_cdev); 1990 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS); 1991 1992 comedi_proc_cleanup(); 1993} 1994 1995module_init(comedi_init); 1996module_exit(comedi_cleanup); 1997 1998void comedi_error(const struct comedi_device *dev, const char *s) 1999{ 2000 printk(KERN_ERR "comedi%d: %s: %s\n", dev->minor, 2001 dev->driver->driver_name, s); 2002} 2003EXPORT_SYMBOL(comedi_error); 2004 2005void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s) 2006{ 2007 struct comedi_async *async = s->async; 2008 unsigned runflags = 0; 2009 unsigned runflags_mask = 0; 2010 2011 /* DPRINTK("comedi_event 0x%x\n",mask); */ 2012 2013 if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) == 0) 2014 return; 2015 2016 if (s-> 2017 async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | 2018 COMEDI_CB_OVERFLOW)) { 2019 runflags_mask |= SRF_RUNNING; 2020 } 2021 /* remember if an error event has occured, so an error 2022 * can be returned the next time the user does a read() */ 2023 if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) { 2024 runflags_mask |= SRF_ERROR; 2025 runflags |= SRF_ERROR; 2026 } 2027 if (runflags_mask) { 2028 /*sets SRF_ERROR and SRF_RUNNING together atomically */ 2029 comedi_set_subdevice_runflags(s, runflags_mask, runflags); 2030 } 2031 2032 if (async->cb_mask & s->async->events) { 2033 if (comedi_get_subdevice_runflags(s) & SRF_USER) { 2034 wake_up_interruptible(&async->wait_head); 2035 if (s->subdev_flags & SDF_CMD_READ) 2036 kill_fasync(&dev->async_queue, SIGIO, POLL_IN); 2037 if (s->subdev_flags & SDF_CMD_WRITE) 2038 kill_fasync(&dev->async_queue, SIGIO, POLL_OUT); 2039 } else { 2040 if (async->cb_func) 2041 async->cb_func(s->async->events, async->cb_arg); 2042 } 2043 } 2044 s->async->events = 0; 2045} 2046EXPORT_SYMBOL(comedi_event); 2047 2048unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s) 2049{ 2050 unsigned long flags; 2051 unsigned runflags; 2052 2053 spin_lock_irqsave(&s->spin_lock, flags); 2054 runflags = s->runflags; 2055 spin_unlock_irqrestore(&s->spin_lock, flags); 2056 return runflags; 2057} 2058EXPORT_SYMBOL(comedi_get_subdevice_runflags); 2059 2060static int is_device_busy(struct comedi_device *dev) 2061{ 2062 struct comedi_subdevice *s; 2063 int i; 2064 2065 if (!dev->attached) 2066 return 0; 2067 2068 for (i = 0; i < dev->n_subdevices; i++) { 2069 s = dev->subdevices + i; 2070 if (s->busy) 2071 return 1; 2072 if (s->async && s->async->mmap_count) 2073 return 1; 2074 } 2075 2076 return 0; 2077} 2078 2079static void comedi_device_init(struct comedi_device *dev) 2080{ 2081 memset(dev, 0, sizeof(struct comedi_device)); 2082 spin_lock_init(&dev->spinlock); 2083 mutex_init(&dev->mutex); 2084 dev->minor = -1; 2085} 2086 2087static void comedi_device_cleanup(struct comedi_device *dev) 2088{ 2089 if (dev == NULL) 2090 return; 2091 mutex_lock(&dev->mutex); 2092 comedi_device_detach(dev); 2093 mutex_unlock(&dev->mutex); 2094 mutex_destroy(&dev->mutex); 2095} 2096 2097int comedi_alloc_board_minor(struct device *hardware_device) 2098{ 2099 unsigned long flags; 2100 struct comedi_device_file_info *info; 2101 struct device *csdev; 2102 unsigned i; 2103 int retval; 2104 2105 info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); 2106 if (info == NULL) 2107 return -ENOMEM; 2108 info->device = kzalloc(sizeof(struct comedi_device), GFP_KERNEL); 2109 if (info->device == NULL) { 2110 kfree(info); 2111 return -ENOMEM; 2112 } 2113 comedi_device_init(info->device); 2114 spin_lock_irqsave(&comedi_file_info_table_lock, flags); 2115 for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) { 2116 if (comedi_file_info_table[i] == NULL) { 2117 comedi_file_info_table[i] = info; 2118 break; 2119 } 2120 } 2121 spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); 2122 if (i == COMEDI_NUM_BOARD_MINORS) { 2123 comedi_device_cleanup(info->device); 2124 kfree(info->device); 2125 kfree(info); 2126 printk(KERN_ERR 2127 "comedi: error: " 2128 "ran out of minor numbers for board device files.\n"); 2129 return -EBUSY; 2130 } 2131 info->device->minor = i; 2132 csdev = COMEDI_DEVICE_CREATE(comedi_class, NULL, 2133 MKDEV(COMEDI_MAJOR, i), NULL, 2134 hardware_device, "comedi%i", i); 2135 if (!IS_ERR(csdev)) 2136 info->device->class_dev = csdev; 2137 dev_set_drvdata(csdev, info); 2138 retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb); 2139 if (retval) { 2140 printk(KERN_ERR 2141 "comedi: " 2142 "failed to create sysfs attribute file \"%s\".\n", 2143 dev_attr_max_read_buffer_kb.attr.name); 2144 comedi_free_board_minor(i); 2145 return retval; 2146 } 2147 retval = device_create_file(csdev, &dev_attr_read_buffer_kb); 2148 if (retval) { 2149 printk(KERN_ERR 2150 "comedi: " 2151 "failed to create sysfs attribute file \"%s\".\n", 2152 dev_attr_read_buffer_kb.attr.name); 2153 comedi_free_board_minor(i); 2154 return retval; 2155 } 2156 retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb); 2157 if (retval) { 2158 printk(KERN_ERR 2159 "comedi: " 2160 "failed to create sysfs attribute file \"%s\".\n", 2161 dev_attr_max_write_buffer_kb.attr.name); 2162 comedi_free_board_minor(i); 2163 return retval; 2164 } 2165 retval = device_create_file(csdev, &dev_attr_write_buffer_kb); 2166 if (retval) { 2167 printk(KERN_ERR 2168 "comedi: " 2169 "failed to create sysfs attribute file \"%s\".\n", 2170 dev_attr_write_buffer_kb.attr.name); 2171 comedi_free_board_minor(i); 2172 return retval; 2173 } 2174 return i; 2175} 2176 2177void comedi_free_board_minor(unsigned minor) 2178{ 2179 unsigned long flags; 2180 struct comedi_device_file_info *info; 2181 2182 BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS); 2183 spin_lock_irqsave(&comedi_file_info_table_lock, flags); 2184 info = comedi_file_info_table[minor]; 2185 comedi_file_info_table[minor] = NULL; 2186 spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); 2187 2188 if (info) { 2189 struct comedi_device *dev = info->device; 2190 if (dev) { 2191 if (dev->class_dev) { 2192 device_destroy(comedi_class, 2193 MKDEV(COMEDI_MAJOR, dev->minor)); 2194 } 2195 comedi_device_cleanup(dev); 2196 kfree(dev); 2197 } 2198 kfree(info); 2199 } 2200} 2201 2202int comedi_alloc_subdevice_minor(struct comedi_device *dev, 2203 struct comedi_subdevice *s) 2204{ 2205 unsigned long flags; 2206 struct comedi_device_file_info *info; 2207 struct device *csdev; 2208 unsigned i; 2209 int retval; 2210 2211 info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); 2212 if (info == NULL) 2213 return -ENOMEM; 2214 info->device = dev; 2215 info->read_subdevice = s; 2216 info->write_subdevice = s; 2217 spin_lock_irqsave(&comedi_file_info_table_lock, flags); 2218 for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) { 2219 if (comedi_file_info_table[i] == NULL) { 2220 comedi_file_info_table[i] = info; 2221 break; 2222 } 2223 } 2224 spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); 2225 if (i == COMEDI_NUM_MINORS) { 2226 kfree(info); 2227 printk(KERN_ERR 2228 "comedi: error: " 2229 "ran out of minor numbers for board device files.\n"); 2230 return -EBUSY; 2231 } 2232 s->minor = i; 2233 csdev = COMEDI_DEVICE_CREATE(comedi_class, dev->class_dev, 2234 MKDEV(COMEDI_MAJOR, i), NULL, NULL, 2235 "comedi%i_subd%i", dev->minor, 2236 (int)(s - dev->subdevices)); 2237 if (!IS_ERR(csdev)) 2238 s->class_dev = csdev; 2239 dev_set_drvdata(csdev, info); 2240 retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb); 2241 if (retval) { 2242 printk(KERN_ERR 2243 "comedi: " 2244 "failed to create sysfs attribute file \"%s\".\n", 2245 dev_attr_max_read_buffer_kb.attr.name); 2246 comedi_free_subdevice_minor(s); 2247 return retval; 2248 } 2249 retval = device_create_file(csdev, &dev_attr_read_buffer_kb); 2250 if (retval) { 2251 printk(KERN_ERR 2252 "comedi: " 2253 "failed to create sysfs attribute file \"%s\".\n", 2254 dev_attr_read_buffer_kb.attr.name); 2255 comedi_free_subdevice_minor(s); 2256 return retval; 2257 } 2258 retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb); 2259 if (retval) { 2260 printk(KERN_ERR 2261 "comedi: " 2262 "failed to create sysfs attribute file \"%s\".\n", 2263 dev_attr_max_write_buffer_kb.attr.name); 2264 comedi_free_subdevice_minor(s); 2265 return retval; 2266 } 2267 retval = device_create_file(csdev, &dev_attr_write_buffer_kb); 2268 if (retval) { 2269 printk(KERN_ERR 2270 "comedi: " 2271 "failed to create sysfs attribute file \"%s\".\n", 2272 dev_attr_write_buffer_kb.attr.name); 2273 comedi_free_subdevice_minor(s); 2274 return retval; 2275 } 2276 return i; 2277} 2278 2279void comedi_free_subdevice_minor(struct comedi_subdevice *s) 2280{ 2281 unsigned long flags; 2282 struct comedi_device_file_info *info; 2283 2284 if (s == NULL) 2285 return; 2286 if (s->minor < 0) 2287 return; 2288 2289 BUG_ON(s->minor >= COMEDI_NUM_MINORS); 2290 BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR); 2291 2292 spin_lock_irqsave(&comedi_file_info_table_lock, flags); 2293 info = comedi_file_info_table[s->minor]; 2294 comedi_file_info_table[s->minor] = NULL; 2295 spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); 2296 2297 if (s->class_dev) { 2298 device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor)); 2299 s->class_dev = NULL; 2300 } 2301 kfree(info); 2302} 2303 2304struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor) 2305{ 2306 unsigned long flags; 2307 struct comedi_device_file_info *info; 2308 2309 BUG_ON(minor >= COMEDI_NUM_MINORS); 2310 spin_lock_irqsave(&comedi_file_info_table_lock, flags); 2311 info = comedi_file_info_table[minor]; 2312 spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); 2313 return info; 2314} 2315EXPORT_SYMBOL_GPL(comedi_get_device_file_info); 2316 2317static int resize_async_buffer(struct comedi_device *dev, 2318 struct comedi_subdevice *s, 2319 struct comedi_async *async, unsigned new_size) 2320{ 2321 int retval; 2322 2323 if (new_size > async->max_bufsize) 2324 return -EPERM; 2325 2326 if (s->busy) { 2327 DPRINTK("subdevice is busy, cannot resize buffer\n"); 2328 return -EBUSY; 2329 } 2330 if (async->mmap_count) { 2331 DPRINTK("subdevice is mmapped, cannot resize buffer\n"); 2332 return -EBUSY; 2333 } 2334 2335 if (!async->prealloc_buf) 2336 return -EINVAL; 2337 2338 /* make sure buffer is an integral number of pages 2339 * (we round up) */ 2340 new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK; 2341 2342 retval = comedi_buf_alloc(dev, s, new_size); 2343 if (retval < 0) 2344 return retval; 2345 2346 if (s->buf_change) { 2347 retval = s->buf_change(dev, s, new_size); 2348 if (retval < 0) 2349 return retval; 2350 } 2351 2352 DPRINTK("comedi%i subd %d buffer resized to %i bytes\n", 2353 dev->minor, (int)(s - dev->subdevices), async->prealloc_bufsz); 2354 return 0; 2355} 2356 2357/* sysfs attribute files */ 2358 2359static const unsigned bytes_per_kibi = 1024; 2360 2361static ssize_t show_max_read_buffer_kb(struct device *dev, 2362 struct device_attribute *attr, char *buf) 2363{ 2364 ssize_t retval; 2365 struct comedi_device_file_info *info = dev_get_drvdata(dev); 2366 unsigned max_buffer_size_kb = 0; 2367 struct comedi_subdevice *const read_subdevice = 2368 comedi_get_read_subdevice(info); 2369 2370 mutex_lock(&info->device->mutex); 2371 if (read_subdevice && 2372 (read_subdevice->subdev_flags & SDF_CMD_READ) && 2373 read_subdevice->async) { 2374 max_buffer_size_kb = read_subdevice->async->max_bufsize / 2375 bytes_per_kibi; 2376 } 2377 retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb); 2378 mutex_unlock(&info->device->mutex); 2379 2380 return retval; 2381} 2382 2383static ssize_t store_max_read_buffer_kb(struct device *dev, 2384 struct device_attribute *attr, 2385 const char *buf, size_t count) 2386{ 2387 struct comedi_device_file_info *info = dev_get_drvdata(dev); 2388 unsigned long new_max_size_kb; 2389 uint64_t new_max_size; 2390 struct comedi_subdevice *const read_subdevice = 2391 comedi_get_read_subdevice(info); 2392 2393 if (strict_strtoul(buf, 10, &new_max_size_kb)) 2394 return -EINVAL; 2395 if (new_max_size_kb != (uint32_t) new_max_size_kb) 2396 return -EINVAL; 2397 new_max_size = ((uint64_t) new_max_size_kb) * bytes_per_kibi; 2398 if (new_max_size != (uint32_t) new_max_size) 2399 return -EINVAL; 2400 2401 mutex_lock(&info->device->mutex); 2402 if (read_subdevice == NULL || 2403 (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 || 2404 read_subdevice->async == NULL) { 2405 mutex_unlock(&info->device->mutex); 2406 return -EINVAL; 2407 } 2408 read_subdevice->async->max_bufsize = new_max_size; 2409 mutex_unlock(&info->device->mutex); 2410 2411 return count; 2412} 2413 2414static struct device_attribute dev_attr_max_read_buffer_kb = { 2415 .attr = { 2416 .name = "max_read_buffer_kb", 2417 .mode = S_IRUGO | S_IWUSR}, 2418 .show = &show_max_read_buffer_kb, 2419 .store = &store_max_read_buffer_kb 2420}; 2421 2422static ssize_t show_read_buffer_kb(struct device *dev, 2423 struct device_attribute *attr, char *buf) 2424{ 2425 ssize_t retval; 2426 struct comedi_device_file_info *info = dev_get_drvdata(dev); 2427 unsigned buffer_size_kb = 0; 2428 struct comedi_subdevice *const read_subdevice = 2429 comedi_get_read_subdevice(info); 2430 2431 mutex_lock(&info->device->mutex); 2432 if (read_subdevice && 2433 (read_subdevice->subdev_flags & SDF_CMD_READ) && 2434 read_subdevice->async) { 2435 buffer_size_kb = read_subdevice->async->prealloc_bufsz / 2436 bytes_per_kibi; 2437 } 2438 retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb); 2439 mutex_unlock(&info->device->mutex); 2440 2441 return retval; 2442} 2443 2444static ssize_t store_read_buffer_kb(struct device *dev, 2445 struct device_attribute *attr, 2446 const char *buf, size_t count) 2447{ 2448 struct comedi_device_file_info *info = dev_get_drvdata(dev); 2449 unsigned long new_size_kb; 2450 uint64_t new_size; 2451 int retval; 2452 struct comedi_subdevice *const read_subdevice = 2453 comedi_get_read_subdevice(info); 2454 2455 if (strict_strtoul(buf, 10, &new_size_kb)) 2456 return -EINVAL; 2457 if (new_size_kb != (uint32_t) new_size_kb) 2458 return -EINVAL; 2459 new_size = ((uint64_t) new_size_kb) * bytes_per_kibi; 2460 if (new_size != (uint32_t) new_size) 2461 return -EINVAL; 2462 2463 mutex_lock(&info->device->mutex); 2464 if (read_subdevice == NULL || 2465 (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 || 2466 read_subdevice->async == NULL) { 2467 mutex_unlock(&info->device->mutex); 2468 return -EINVAL; 2469 } 2470 retval = resize_async_buffer(info->device, read_subdevice, 2471 read_subdevice->async, new_size); 2472 mutex_unlock(&info->device->mutex); 2473 2474 if (retval < 0) 2475 return retval; 2476 return count; 2477} 2478 2479static struct device_attribute dev_attr_read_buffer_kb = { 2480 .attr = { 2481 .name = "read_buffer_kb", 2482 .mode = S_IRUGO | S_IWUSR | S_IWGRP}, 2483 .show = &show_read_buffer_kb, 2484 .store = &store_read_buffer_kb 2485}; 2486 2487static ssize_t show_max_write_buffer_kb(struct device *dev, 2488 struct device_attribute *attr, 2489 char *buf) 2490{ 2491 ssize_t retval; 2492 struct comedi_device_file_info *info = dev_get_drvdata(dev); 2493 unsigned max_buffer_size_kb = 0; 2494 struct comedi_subdevice *const write_subdevice = 2495 comedi_get_write_subdevice(info); 2496 2497 mutex_lock(&info->device->mutex); 2498 if (write_subdevice && 2499 (write_subdevice->subdev_flags & SDF_CMD_WRITE) && 2500 write_subdevice->async) { 2501 max_buffer_size_kb = write_subdevice->async->max_bufsize / 2502 bytes_per_kibi; 2503 } 2504 retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb); 2505 mutex_unlock(&info->device->mutex); 2506 2507 return retval; 2508} 2509 2510static ssize_t store_max_write_buffer_kb(struct device *dev, 2511 struct device_attribute *attr, 2512 const char *buf, size_t count) 2513{ 2514 struct comedi_device_file_info *info = dev_get_drvdata(dev); 2515 unsigned long new_max_size_kb; 2516 uint64_t new_max_size; 2517 struct comedi_subdevice *const write_subdevice = 2518 comedi_get_write_subdevice(info); 2519 2520 if (strict_strtoul(buf, 10, &new_max_size_kb)) 2521 return -EINVAL; 2522 if (new_max_size_kb != (uint32_t) new_max_size_kb) 2523 return -EINVAL; 2524 new_max_size = ((uint64_t) new_max_size_kb) * bytes_per_kibi; 2525 if (new_max_size != (uint32_t) new_max_size) 2526 return -EINVAL; 2527 2528 mutex_lock(&info->device->mutex); 2529 if (write_subdevice == NULL || 2530 (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 || 2531 write_subdevice->async == NULL) { 2532 mutex_unlock(&info->device->mutex); 2533 return -EINVAL; 2534 } 2535 write_subdevice->async->max_bufsize = new_max_size; 2536 mutex_unlock(&info->device->mutex); 2537 2538 return count; 2539} 2540 2541static struct device_attribute dev_attr_max_write_buffer_kb = { 2542 .attr = { 2543 .name = "max_write_buffer_kb", 2544 .mode = S_IRUGO | S_IWUSR}, 2545 .show = &show_max_write_buffer_kb, 2546 .store = &store_max_write_buffer_kb 2547}; 2548 2549static ssize_t show_write_buffer_kb(struct device *dev, 2550 struct device_attribute *attr, char *buf) 2551{ 2552 ssize_t retval; 2553 struct comedi_device_file_info *info = dev_get_drvdata(dev); 2554 unsigned buffer_size_kb = 0; 2555 struct comedi_subdevice *const write_subdevice = 2556 comedi_get_write_subdevice(info); 2557 2558 mutex_lock(&info->device->mutex); 2559 if (write_subdevice && 2560 (write_subdevice->subdev_flags & SDF_CMD_WRITE) && 2561 write_subdevice->async) { 2562 buffer_size_kb = write_subdevice->async->prealloc_bufsz / 2563 bytes_per_kibi; 2564 } 2565 retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb); 2566 mutex_unlock(&info->device->mutex); 2567 2568 return retval; 2569} 2570 2571static ssize_t store_write_buffer_kb(struct device *dev, 2572 struct device_attribute *attr, 2573 const char *buf, size_t count) 2574{ 2575 struct comedi_device_file_info *info = dev_get_drvdata(dev); 2576 unsigned long new_size_kb; 2577 uint64_t new_size; 2578 int retval; 2579 struct comedi_subdevice *const write_subdevice = 2580 comedi_get_write_subdevice(info); 2581 2582 if (strict_strtoul(buf, 10, &new_size_kb)) 2583 return -EINVAL; 2584 if (new_size_kb != (uint32_t) new_size_kb) 2585 return -EINVAL; 2586 new_size = ((uint64_t) new_size_kb) * bytes_per_kibi; 2587 if (new_size != (uint32_t) new_size) 2588 return -EINVAL; 2589 2590 mutex_lock(&info->device->mutex); 2591 if (write_subdevice == NULL || 2592 (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 || 2593 write_subdevice->async == NULL) { 2594 mutex_unlock(&info->device->mutex); 2595 return -EINVAL; 2596 } 2597 retval = resize_async_buffer(info->device, write_subdevice, 2598 write_subdevice->async, new_size); 2599 mutex_unlock(&info->device->mutex); 2600 2601 if (retval < 0) 2602 return retval; 2603 return count; 2604} 2605 2606static struct device_attribute dev_attr_write_buffer_kb = { 2607 .attr = { 2608 .name = "write_buffer_kb", 2609 .mode = S_IRUGO | S_IWUSR | S_IWGRP}, 2610 .show = &show_write_buffer_kb, 2611 .store = &store_write_buffer_kb 2612}; 2613