comedi_fops.c revision 92d0127c9d249c078b0939050f25041ed37be7cd
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 956 (data, insn.data, insn.n * sizeof(unsigned int))) { 957 ret = -EFAULT; 958 goto error; 959 } 960 } 961 ret = parse_insn(dev, &insn, data, file); 962 if (ret < 0) 963 goto error; 964 if (insn.insn & INSN_MASK_READ) { 965 if (copy_to_user(insn.data, data, insn.n * sizeof(unsigned int))) { 966 ret = -EFAULT; 967 goto error; 968 } 969 } 970 ret = insn.n; 971 972error: 973 kfree(data); 974 975 return ret; 976} 977 978static void comedi_set_subdevice_runflags(struct comedi_subdevice *s, 979 unsigned mask, unsigned bits) 980{ 981 unsigned long flags; 982 983 spin_lock_irqsave(&s->spin_lock, flags); 984 s->runflags &= ~mask; 985 s->runflags |= (bits & mask); 986 spin_unlock_irqrestore(&s->spin_lock, flags); 987} 988 989static int do_cmd_ioctl(struct comedi_device *dev, 990 struct comedi_cmd __user *cmd, void *file) 991{ 992 struct comedi_cmd user_cmd; 993 struct comedi_subdevice *s; 994 struct comedi_async *async; 995 int ret = 0; 996 unsigned int __user *chanlist_saver = NULL; 997 998 if (copy_from_user(&user_cmd, cmd, sizeof(struct comedi_cmd))) { 999 DPRINTK("bad cmd address\n"); 1000 return -EFAULT; 1001 } 1002 /* save user's chanlist pointer so it can be restored later */ 1003 chanlist_saver = user_cmd.chanlist; 1004 1005 if (user_cmd.subdev >= dev->n_subdevices) { 1006 DPRINTK("%d no such subdevice\n", user_cmd.subdev); 1007 return -ENODEV; 1008 } 1009 1010 s = dev->subdevices + user_cmd.subdev; 1011 async = s->async; 1012 1013 if (s->type == COMEDI_SUBD_UNUSED) { 1014 DPRINTK("%d not valid subdevice\n", user_cmd.subdev); 1015 return -EIO; 1016 } 1017 1018 if (!s->do_cmd || !s->do_cmdtest || !s->async) { 1019 DPRINTK("subdevice %i does not support commands\n", 1020 user_cmd.subdev); 1021 return -EIO; 1022 } 1023 1024 /* are we locked? (ioctl lock) */ 1025 if (s->lock && s->lock != file) { 1026 DPRINTK("subdevice locked\n"); 1027 return -EACCES; 1028 } 1029 1030 /* are we busy? */ 1031 if (s->busy) { 1032 DPRINTK("subdevice busy\n"); 1033 return -EBUSY; 1034 } 1035 s->busy = file; 1036 1037 /* make sure channel/gain list isn't too long */ 1038 if (user_cmd.chanlist_len > s->len_chanlist) { 1039 DPRINTK("channel/gain list too long %u > %d\n", 1040 user_cmd.chanlist_len, s->len_chanlist); 1041 ret = -EINVAL; 1042 goto cleanup; 1043 } 1044 1045 /* make sure channel/gain list isn't too short */ 1046 if (user_cmd.chanlist_len < 1) { 1047 DPRINTK("channel/gain list too short %u < 1\n", 1048 user_cmd.chanlist_len); 1049 ret = -EINVAL; 1050 goto cleanup; 1051 } 1052 1053 kfree(async->cmd.chanlist); 1054 async->cmd = user_cmd; 1055 async->cmd.data = NULL; 1056 /* load channel/gain list */ 1057 async->cmd.chanlist = 1058 kmalloc(async->cmd.chanlist_len * sizeof(int), GFP_KERNEL); 1059 if (!async->cmd.chanlist) { 1060 DPRINTK("allocation failed\n"); 1061 ret = -ENOMEM; 1062 goto cleanup; 1063 } 1064 1065 if (copy_from_user(async->cmd.chanlist, user_cmd.chanlist, 1066 async->cmd.chanlist_len * sizeof(int))) { 1067 DPRINTK("fault reading chanlist\n"); 1068 ret = -EFAULT; 1069 goto cleanup; 1070 } 1071 1072 /* make sure each element in channel/gain list is valid */ 1073 ret = comedi_check_chanlist(s, async->cmd.chanlist_len, async->cmd.chanlist); 1074 if (ret < 0) { 1075 DPRINTK("bad chanlist\n"); 1076 goto cleanup; 1077 } 1078 1079 ret = s->do_cmdtest(dev, s, &async->cmd); 1080 1081 if (async->cmd.flags & TRIG_BOGUS || ret) { 1082 DPRINTK("test returned %d\n", ret); 1083 user_cmd = async->cmd; 1084 /* restore chanlist pointer before copying back */ 1085 user_cmd.chanlist = chanlist_saver; 1086 user_cmd.data = NULL; 1087 if (copy_to_user(cmd, &user_cmd, sizeof(struct comedi_cmd))) { 1088 DPRINTK("fault writing cmd\n"); 1089 ret = -EFAULT; 1090 goto cleanup; 1091 } 1092 ret = -EAGAIN; 1093 goto cleanup; 1094 } 1095 1096 if (!async->prealloc_bufsz) { 1097 ret = -ENOMEM; 1098 DPRINTK("no buffer (?)\n"); 1099 goto cleanup; 1100 } 1101 1102 comedi_reset_async_buf(async); 1103 1104 async->cb_mask = 1105 COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR | 1106 COMEDI_CB_OVERFLOW; 1107 if (async->cmd.flags & TRIG_WAKE_EOS) 1108 async->cb_mask |= COMEDI_CB_EOS; 1109 1110 comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING); 1111 1112 ret = s->do_cmd(dev, s); 1113 if (ret == 0) 1114 return 0; 1115 1116cleanup: 1117 do_become_nonbusy(dev, s); 1118 1119 return ret; 1120} 1121 1122/* 1123 COMEDI_CMDTEST 1124 command testing ioctl 1125 1126 arg: 1127 pointer to cmd structure 1128 1129 reads: 1130 cmd structure at arg 1131 channel/range list 1132 1133 writes: 1134 modified cmd structure at arg 1135 1136*/ 1137static int do_cmdtest_ioctl(struct comedi_device *dev, 1138 struct comedi_cmd __user *arg, void *file) 1139{ 1140 struct comedi_cmd user_cmd; 1141 struct comedi_subdevice *s; 1142 int ret = 0; 1143 unsigned int *chanlist = NULL; 1144 unsigned int __user *chanlist_saver = NULL; 1145 1146 if (copy_from_user(&user_cmd, arg, sizeof(struct comedi_cmd))) { 1147 DPRINTK("bad cmd address\n"); 1148 return -EFAULT; 1149 } 1150 /* save user's chanlist pointer so it can be restored later */ 1151 chanlist_saver = user_cmd.chanlist; 1152 1153 if (user_cmd.subdev >= dev->n_subdevices) { 1154 DPRINTK("%d no such subdevice\n", user_cmd.subdev); 1155 return -ENODEV; 1156 } 1157 1158 s = dev->subdevices + user_cmd.subdev; 1159 if (s->type == COMEDI_SUBD_UNUSED) { 1160 DPRINTK("%d not valid subdevice\n", user_cmd.subdev); 1161 return -EIO; 1162 } 1163 1164 if (!s->do_cmd || !s->do_cmdtest) { 1165 DPRINTK("subdevice %i does not support commands\n", 1166 user_cmd.subdev); 1167 return -EIO; 1168 } 1169 1170 /* make sure channel/gain list isn't too long */ 1171 if (user_cmd.chanlist_len > s->len_chanlist) { 1172 DPRINTK("channel/gain list too long %d > %d\n", 1173 user_cmd.chanlist_len, s->len_chanlist); 1174 ret = -EINVAL; 1175 goto cleanup; 1176 } 1177 1178 /* load channel/gain list */ 1179 if (user_cmd.chanlist) { 1180 chanlist = 1181 kmalloc(user_cmd.chanlist_len * sizeof(int), GFP_KERNEL); 1182 if (!chanlist) { 1183 DPRINTK("allocation failed\n"); 1184 ret = -ENOMEM; 1185 goto cleanup; 1186 } 1187 1188 if (copy_from_user(chanlist, user_cmd.chanlist, 1189 user_cmd.chanlist_len * sizeof(int))) { 1190 DPRINTK("fault reading chanlist\n"); 1191 ret = -EFAULT; 1192 goto cleanup; 1193 } 1194 1195 /* make sure each element in channel/gain list is valid */ 1196 ret = comedi_check_chanlist(s, user_cmd.chanlist_len, chanlist); 1197 if (ret < 0) { 1198 DPRINTK("bad chanlist\n"); 1199 goto cleanup; 1200 } 1201 1202 user_cmd.chanlist = chanlist; 1203 } 1204 1205 ret = s->do_cmdtest(dev, s, &user_cmd); 1206 1207 /* restore chanlist pointer before copying back */ 1208 user_cmd.chanlist = chanlist_saver; 1209 1210 if (copy_to_user(arg, &user_cmd, sizeof(struct comedi_cmd))) { 1211 DPRINTK("bad cmd address\n"); 1212 ret = -EFAULT; 1213 goto cleanup; 1214 } 1215cleanup: 1216 kfree(chanlist); 1217 1218 return ret; 1219} 1220 1221/* 1222 COMEDI_LOCK 1223 lock subdevice 1224 1225 arg: 1226 subdevice number 1227 1228 reads: 1229 none 1230 1231 writes: 1232 none 1233 1234*/ 1235 1236static int do_lock_ioctl(struct comedi_device *dev, unsigned int arg, 1237 void *file) 1238{ 1239 int ret = 0; 1240 unsigned long flags; 1241 struct comedi_subdevice *s; 1242 1243 if (arg >= dev->n_subdevices) 1244 return -EINVAL; 1245 s = dev->subdevices + arg; 1246 1247 spin_lock_irqsave(&s->spin_lock, flags); 1248 if (s->busy || s->lock) 1249 ret = -EBUSY; 1250 else 1251 s->lock = file; 1252 spin_unlock_irqrestore(&s->spin_lock, flags); 1253 1254 if (ret < 0) 1255 return ret; 1256 1257#if 0 1258 if (s->lock_f) 1259 ret = s->lock_f(dev, s); 1260#endif 1261 1262 return ret; 1263} 1264 1265/* 1266 COMEDI_UNLOCK 1267 unlock subdevice 1268 1269 arg: 1270 subdevice number 1271 1272 reads: 1273 none 1274 1275 writes: 1276 none 1277 1278 This function isn't protected by the semaphore, since 1279 we already own the lock. 1280*/ 1281static int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg, 1282 void *file) 1283{ 1284 struct comedi_subdevice *s; 1285 1286 if (arg >= dev->n_subdevices) 1287 return -EINVAL; 1288 s = dev->subdevices + arg; 1289 1290 if (s->busy) 1291 return -EBUSY; 1292 1293 if (s->lock && s->lock != file) 1294 return -EACCES; 1295 1296 if (s->lock == file) { 1297#if 0 1298 if (s->unlock) 1299 s->unlock(dev, s); 1300#endif 1301 1302 s->lock = NULL; 1303 } 1304 1305 return 0; 1306} 1307 1308/* 1309 COMEDI_CANCEL 1310 cancel acquisition ioctl 1311 1312 arg: 1313 subdevice number 1314 1315 reads: 1316 nothing 1317 1318 writes: 1319 nothing 1320 1321*/ 1322static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg, 1323 void *file) 1324{ 1325 struct comedi_subdevice *s; 1326 1327 if (arg >= dev->n_subdevices) 1328 return -EINVAL; 1329 s = dev->subdevices + arg; 1330 if (s->async == NULL) 1331 return -EINVAL; 1332 1333 if (s->lock && s->lock != file) 1334 return -EACCES; 1335 1336 if (!s->busy) 1337 return 0; 1338 1339 if (s->busy != file) 1340 return -EBUSY; 1341 1342 return do_cancel(dev, s); 1343} 1344 1345/* 1346 COMEDI_POLL ioctl 1347 instructs driver to synchronize buffers 1348 1349 arg: 1350 subdevice number 1351 1352 reads: 1353 nothing 1354 1355 writes: 1356 nothing 1357 1358*/ 1359static int do_poll_ioctl(struct comedi_device *dev, unsigned int arg, 1360 void *file) 1361{ 1362 struct comedi_subdevice *s; 1363 1364 if (arg >= dev->n_subdevices) 1365 return -EINVAL; 1366 s = dev->subdevices + arg; 1367 1368 if (s->lock && s->lock != file) 1369 return -EACCES; 1370 1371 if (!s->busy) 1372 return 0; 1373 1374 if (s->busy != file) 1375 return -EBUSY; 1376 1377 if (s->poll) 1378 return s->poll(dev, s); 1379 1380 return -EINVAL; 1381} 1382 1383static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s) 1384{ 1385 int ret = 0; 1386 1387 if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) && s->cancel) 1388 ret = s->cancel(dev, s); 1389 1390 do_become_nonbusy(dev, s); 1391 1392 return ret; 1393} 1394 1395static void comedi_unmap(struct vm_area_struct *area) 1396{ 1397 struct comedi_async *async; 1398 struct comedi_device *dev; 1399 1400 async = area->vm_private_data; 1401 dev = async->subdevice->device; 1402 1403 mutex_lock(&dev->mutex); 1404 async->mmap_count--; 1405 mutex_unlock(&dev->mutex); 1406} 1407 1408static struct vm_operations_struct comedi_vm_ops = { 1409 .close = comedi_unmap, 1410}; 1411 1412static int comedi_mmap(struct file *file, struct vm_area_struct *vma) 1413{ 1414 const unsigned minor = iminor(file->f_dentry->d_inode); 1415 struct comedi_device_file_info *dev_file_info = 1416 comedi_get_device_file_info(minor); 1417 struct comedi_device *dev = dev_file_info->device; 1418 struct comedi_async *async = NULL; 1419 unsigned long start = vma->vm_start; 1420 unsigned long size; 1421 int n_pages; 1422 int i; 1423 int retval; 1424 struct comedi_subdevice *s; 1425 1426 mutex_lock(&dev->mutex); 1427 if (!dev->attached) { 1428 DPRINTK("no driver configured on comedi%i\n", dev->minor); 1429 retval = -ENODEV; 1430 goto done; 1431 } 1432 if (vma->vm_flags & VM_WRITE) 1433 s = comedi_get_write_subdevice(dev_file_info); 1434 else 1435 s = comedi_get_read_subdevice(dev_file_info); 1436 1437 if (s == NULL) { 1438 retval = -EINVAL; 1439 goto done; 1440 } 1441 async = s->async; 1442 if (async == NULL) { 1443 retval = -EINVAL; 1444 goto done; 1445 } 1446 1447 if (vma->vm_pgoff != 0) { 1448 DPRINTK("comedi: mmap() offset must be 0.\n"); 1449 retval = -EINVAL; 1450 goto done; 1451 } 1452 1453 size = vma->vm_end - vma->vm_start; 1454 if (size > async->prealloc_bufsz) { 1455 retval = -EFAULT; 1456 goto done; 1457 } 1458 if (size & (~PAGE_MASK)) { 1459 retval = -EFAULT; 1460 goto done; 1461 } 1462 1463 n_pages = size >> PAGE_SHIFT; 1464 for (i = 0; i < n_pages; ++i) { 1465 if (remap_pfn_range(vma, start, 1466 page_to_pfn(virt_to_page 1467 (async->buf_page_list 1468 [i].virt_addr)), PAGE_SIZE, 1469 PAGE_SHARED)) { 1470 retval = -EAGAIN; 1471 goto done; 1472 } 1473 start += PAGE_SIZE; 1474 } 1475 1476 vma->vm_ops = &comedi_vm_ops; 1477 vma->vm_private_data = async; 1478 1479 async->mmap_count++; 1480 1481 retval = 0; 1482done: 1483 mutex_unlock(&dev->mutex); 1484 return retval; 1485} 1486 1487static unsigned int comedi_poll(struct file *file, poll_table * wait) 1488{ 1489 unsigned int mask = 0; 1490 const unsigned minor = iminor(file->f_dentry->d_inode); 1491 struct comedi_device_file_info *dev_file_info = 1492 comedi_get_device_file_info(minor); 1493 struct comedi_device *dev = dev_file_info->device; 1494 struct comedi_subdevice *read_subdev; 1495 struct comedi_subdevice *write_subdev; 1496 1497 mutex_lock(&dev->mutex); 1498 if (!dev->attached) { 1499 DPRINTK("no driver configured on comedi%i\n", dev->minor); 1500 mutex_unlock(&dev->mutex); 1501 return 0; 1502 } 1503 1504 mask = 0; 1505 read_subdev = comedi_get_read_subdevice(dev_file_info); 1506 if (read_subdev) { 1507 poll_wait(file, &read_subdev->async->wait_head, wait); 1508 if (!read_subdev->busy 1509 || comedi_buf_read_n_available(read_subdev->async) > 0 1510 || !(comedi_get_subdevice_runflags(read_subdev) & 1511 SRF_RUNNING)) { 1512 mask |= POLLIN | POLLRDNORM; 1513 } 1514 } 1515 write_subdev = comedi_get_write_subdevice(dev_file_info); 1516 if (write_subdev) { 1517 poll_wait(file, &write_subdev->async->wait_head, wait); 1518 comedi_buf_write_alloc(write_subdev->async, 1519 write_subdev->async->prealloc_bufsz); 1520 if (!write_subdev->busy 1521 || !(comedi_get_subdevice_runflags(write_subdev) & 1522 SRF_RUNNING) 1523 || comedi_buf_write_n_allocated(write_subdev->async) >= 1524 bytes_per_sample(write_subdev->async->subdevice)) { 1525 mask |= POLLOUT | POLLWRNORM; 1526 } 1527 } 1528 1529 mutex_unlock(&dev->mutex); 1530 return mask; 1531} 1532 1533static ssize_t comedi_write(struct file *file, const char __user *buf, 1534 size_t nbytes, loff_t *offset) 1535{ 1536 struct comedi_subdevice *s; 1537 struct comedi_async *async; 1538 int n, m, count = 0, retval = 0; 1539 DECLARE_WAITQUEUE(wait, current); 1540 const unsigned minor = iminor(file->f_dentry->d_inode); 1541 struct comedi_device_file_info *dev_file_info = 1542 comedi_get_device_file_info(minor); 1543 struct comedi_device *dev = dev_file_info->device; 1544 1545 if (!dev->attached) { 1546 DPRINTK("no driver configured on comedi%i\n", dev->minor); 1547 retval = -ENODEV; 1548 goto done; 1549 } 1550 1551 s = comedi_get_write_subdevice(dev_file_info); 1552 if (s == NULL) { 1553 retval = -EIO; 1554 goto done; 1555 } 1556 async = s->async; 1557 1558 if (!nbytes) { 1559 retval = 0; 1560 goto done; 1561 } 1562 if (!s->busy) { 1563 retval = 0; 1564 goto done; 1565 } 1566 if (s->busy != file) { 1567 retval = -EACCES; 1568 goto done; 1569 } 1570 add_wait_queue(&async->wait_head, &wait); 1571 while (nbytes > 0 && !retval) { 1572 set_current_state(TASK_INTERRUPTIBLE); 1573 1574 n = nbytes; 1575 1576 m = n; 1577 if (async->buf_write_ptr + m > async->prealloc_bufsz) 1578 m = async->prealloc_bufsz - async->buf_write_ptr; 1579 comedi_buf_write_alloc(async, async->prealloc_bufsz); 1580 if (m > comedi_buf_write_n_allocated(async)) 1581 m = comedi_buf_write_n_allocated(async); 1582 if (m < n) 1583 n = m; 1584 1585 if (n == 0) { 1586 if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) { 1587 if (comedi_get_subdevice_runflags(s) & 1588 SRF_ERROR) { 1589 retval = -EPIPE; 1590 } else { 1591 retval = 0; 1592 } 1593 do_become_nonbusy(dev, s); 1594 break; 1595 } 1596 if (file->f_flags & O_NONBLOCK) { 1597 retval = -EAGAIN; 1598 break; 1599 } 1600 if (signal_pending(current)) { 1601 retval = -ERESTARTSYS; 1602 break; 1603 } 1604 schedule(); 1605 if (!s->busy) 1606 break; 1607 if (s->busy != file) { 1608 retval = -EACCES; 1609 break; 1610 } 1611 continue; 1612 } 1613 1614 m = copy_from_user(async->prealloc_buf + async->buf_write_ptr, 1615 buf, n); 1616 if (m) { 1617 n -= m; 1618 retval = -EFAULT; 1619 } 1620 comedi_buf_write_free(async, n); 1621 1622 count += n; 1623 nbytes -= n; 1624 1625 buf += n; 1626 break; /* makes device work like a pipe */ 1627 } 1628 set_current_state(TASK_RUNNING); 1629 remove_wait_queue(&async->wait_head, &wait); 1630 1631done: 1632 return count ? count : retval; 1633} 1634 1635static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, 1636 loff_t *offset) 1637{ 1638 struct comedi_subdevice *s; 1639 struct comedi_async *async; 1640 int n, m, count = 0, retval = 0; 1641 DECLARE_WAITQUEUE(wait, current); 1642 const unsigned minor = iminor(file->f_dentry->d_inode); 1643 struct comedi_device_file_info *dev_file_info = 1644 comedi_get_device_file_info(minor); 1645 struct comedi_device *dev = dev_file_info->device; 1646 1647 if (!dev->attached) { 1648 DPRINTK("no driver configured on comedi%i\n", dev->minor); 1649 retval = -ENODEV; 1650 goto done; 1651 } 1652 1653 s = comedi_get_read_subdevice(dev_file_info); 1654 if (s == NULL) { 1655 retval = -EIO; 1656 goto done; 1657 } 1658 async = s->async; 1659 if (!nbytes) { 1660 retval = 0; 1661 goto done; 1662 } 1663 if (!s->busy) { 1664 retval = 0; 1665 goto done; 1666 } 1667 if (s->busy != file) { 1668 retval = -EACCES; 1669 goto done; 1670 } 1671 1672 add_wait_queue(&async->wait_head, &wait); 1673 while (nbytes > 0 && !retval) { 1674 set_current_state(TASK_INTERRUPTIBLE); 1675 1676 n = nbytes; 1677 1678 m = comedi_buf_read_n_available(async); 1679 /* printk("%d available\n",m); */ 1680 if (async->buf_read_ptr + m > async->prealloc_bufsz) 1681 m = async->prealloc_bufsz - async->buf_read_ptr; 1682 /* printk("%d contiguous\n",m); */ 1683 if (m < n) 1684 n = m; 1685 1686 if (n == 0) { 1687 if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) { 1688 do_become_nonbusy(dev, s); 1689 if (comedi_get_subdevice_runflags(s) & 1690 SRF_ERROR) { 1691 retval = -EPIPE; 1692 } else { 1693 retval = 0; 1694 } 1695 break; 1696 } 1697 if (file->f_flags & O_NONBLOCK) { 1698 retval = -EAGAIN; 1699 break; 1700 } 1701 if (signal_pending(current)) { 1702 retval = -ERESTARTSYS; 1703 break; 1704 } 1705 schedule(); 1706 if (!s->busy) { 1707 retval = 0; 1708 break; 1709 } 1710 if (s->busy != file) { 1711 retval = -EACCES; 1712 break; 1713 } 1714 continue; 1715 } 1716 m = copy_to_user(buf, async->prealloc_buf + 1717 async->buf_read_ptr, n); 1718 if (m) { 1719 n -= m; 1720 retval = -EFAULT; 1721 } 1722 1723 comedi_buf_read_alloc(async, n); 1724 comedi_buf_read_free(async, n); 1725 1726 count += n; 1727 nbytes -= n; 1728 1729 buf += n; 1730 break; /* makes device work like a pipe */ 1731 } 1732 if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | SRF_RUNNING)) && 1733 async->buf_read_count - async->buf_write_count == 0) { 1734 do_become_nonbusy(dev, s); 1735 } 1736 set_current_state(TASK_RUNNING); 1737 remove_wait_queue(&async->wait_head, &wait); 1738 1739done: 1740 return count ? count : retval; 1741} 1742 1743/* 1744 This function restores a subdevice to an idle state. 1745 */ 1746void do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s) 1747{ 1748 struct comedi_async *async = s->async; 1749 1750 comedi_set_subdevice_runflags(s, SRF_RUNNING, 0); 1751 if (async) { 1752 comedi_reset_async_buf(async); 1753 async->inttrig = NULL; 1754 } else { 1755 printk(KERN_ERR 1756 "BUG: (?) do_become_nonbusy called with async=0\n"); 1757 } 1758 1759 s->busy = NULL; 1760} 1761 1762static int comedi_open(struct inode *inode, struct file *file) 1763{ 1764 const unsigned minor = iminor(inode); 1765 struct comedi_device_file_info *dev_file_info = 1766 comedi_get_device_file_info(minor); 1767 struct comedi_device *dev = 1768 dev_file_info ? dev_file_info->device : NULL; 1769 1770 if (dev == NULL) { 1771 DPRINTK("invalid minor number\n"); 1772 return -ENODEV; 1773 } 1774 1775 /* This is slightly hacky, but we want module autoloading 1776 * to work for root. 1777 * case: user opens device, attached -> ok 1778 * case: user opens device, unattached, in_request_module=0 -> autoload 1779 * case: user opens device, unattached, in_request_module=1 -> fail 1780 * case: root opens device, attached -> ok 1781 * case: root opens device, unattached, in_request_module=1 -> ok 1782 * (typically called from modprobe) 1783 * case: root opens device, unattached, in_request_module=0 -> autoload 1784 * 1785 * The last could be changed to "-> ok", which would deny root 1786 * autoloading. 1787 */ 1788 mutex_lock(&dev->mutex); 1789 if (dev->attached) 1790 goto ok; 1791 if (!capable(CAP_NET_ADMIN) && dev->in_request_module) { 1792 DPRINTK("in request module\n"); 1793 mutex_unlock(&dev->mutex); 1794 return -ENODEV; 1795 } 1796 if (capable(CAP_NET_ADMIN) && dev->in_request_module) 1797 goto ok; 1798 1799 dev->in_request_module = 1; 1800 1801#ifdef CONFIG_KMOD 1802 mutex_unlock(&dev->mutex); 1803 request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor); 1804 mutex_lock(&dev->mutex); 1805#endif 1806 1807 dev->in_request_module = 0; 1808 1809 if (!dev->attached && !capable(CAP_NET_ADMIN)) { 1810 DPRINTK("not attached and not CAP_NET_ADMIN\n"); 1811 mutex_unlock(&dev->mutex); 1812 return -ENODEV; 1813 } 1814ok: 1815 __module_get(THIS_MODULE); 1816 1817 if (dev->attached) { 1818 if (!try_module_get(dev->driver->module)) { 1819 module_put(THIS_MODULE); 1820 mutex_unlock(&dev->mutex); 1821 return -ENOSYS; 1822 } 1823 } 1824 1825 if (dev->attached && dev->use_count == 0 && dev->open) 1826 dev->open(dev); 1827 1828 dev->use_count++; 1829 1830 mutex_unlock(&dev->mutex); 1831 1832 return 0; 1833} 1834 1835static int comedi_close(struct inode *inode, struct file *file) 1836{ 1837 const unsigned minor = iminor(inode); 1838 struct comedi_device_file_info *dev_file_info = 1839 comedi_get_device_file_info(minor); 1840 struct comedi_device *dev = dev_file_info->device; 1841 struct comedi_subdevice *s = NULL; 1842 int i; 1843 1844 mutex_lock(&dev->mutex); 1845 1846 if (dev->subdevices) { 1847 for (i = 0; i < dev->n_subdevices; i++) { 1848 s = dev->subdevices + i; 1849 1850 if (s->busy == file) 1851 do_cancel(dev, s); 1852 if (s->lock == file) 1853 s->lock = NULL; 1854 } 1855 } 1856 if (dev->attached && dev->use_count == 1 && dev->close) 1857 dev->close(dev); 1858 1859 module_put(THIS_MODULE); 1860 if (dev->attached) 1861 module_put(dev->driver->module); 1862 1863 dev->use_count--; 1864 1865 mutex_unlock(&dev->mutex); 1866 1867 if (file->f_flags & FASYNC) 1868 comedi_fasync(-1, file, 0); 1869 1870 return 0; 1871} 1872 1873static int comedi_fasync(int fd, struct file *file, int on) 1874{ 1875 const unsigned minor = iminor(file->f_dentry->d_inode); 1876 struct comedi_device_file_info *dev_file_info = 1877 comedi_get_device_file_info(minor); 1878 1879 struct comedi_device *dev = dev_file_info->device; 1880 1881 return fasync_helper(fd, file, on, &dev->async_queue); 1882} 1883 1884const struct file_operations comedi_fops = { 1885 .owner = THIS_MODULE, 1886 .unlocked_ioctl = comedi_unlocked_ioctl, 1887 .compat_ioctl = comedi_compat_ioctl, 1888 .open = comedi_open, 1889 .release = comedi_close, 1890 .read = comedi_read, 1891 .write = comedi_write, 1892 .mmap = comedi_mmap, 1893 .poll = comedi_poll, 1894 .fasync = comedi_fasync, 1895}; 1896 1897struct class *comedi_class; 1898static struct cdev comedi_cdev; 1899 1900static void comedi_cleanup_legacy_minors(void) 1901{ 1902 unsigned i; 1903 1904 for (i = 0; i < comedi_num_legacy_minors; i++) 1905 comedi_free_board_minor(i); 1906} 1907 1908static int __init comedi_init(void) 1909{ 1910 int i; 1911 int retval; 1912 1913 printk(KERN_INFO "comedi: version " COMEDI_RELEASE 1914 " - http://www.comedi.org\n"); 1915 1916 if (comedi_num_legacy_minors < 0 || 1917 comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) { 1918 printk(KERN_ERR "comedi: error: invalid value for module " 1919 "parameter \"comedi_num_legacy_minors\". Valid values " 1920 "are 0 through %i.\n", COMEDI_NUM_BOARD_MINORS); 1921 return -EINVAL; 1922 } 1923 1924 /* 1925 * comedi is unusable if both comedi_autoconfig and 1926 * comedi_num_legacy_minors are zero, so we might as well adjust the 1927 * defaults in that case 1928 */ 1929 if (comedi_autoconfig == 0 && comedi_num_legacy_minors == 0) 1930 comedi_num_legacy_minors = 16; 1931 1932 memset(comedi_file_info_table, 0, 1933 sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS); 1934 1935 retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0), 1936 COMEDI_NUM_MINORS, "comedi"); 1937 if (retval) 1938 return -EIO; 1939 cdev_init(&comedi_cdev, &comedi_fops); 1940 comedi_cdev.owner = THIS_MODULE; 1941 kobject_set_name(&comedi_cdev.kobj, "comedi"); 1942 if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) { 1943 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), 1944 COMEDI_NUM_MINORS); 1945 return -EIO; 1946 } 1947 comedi_class = class_create(THIS_MODULE, "comedi"); 1948 if (IS_ERR(comedi_class)) { 1949 printk(KERN_ERR "comedi: failed to create class"); 1950 cdev_del(&comedi_cdev); 1951 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), 1952 COMEDI_NUM_MINORS); 1953 return PTR_ERR(comedi_class); 1954 } 1955 1956 /* XXX requires /proc interface */ 1957 comedi_proc_init(); 1958 1959 /* create devices files for legacy/manual use */ 1960 for (i = 0; i < comedi_num_legacy_minors; i++) { 1961 int minor; 1962 minor = comedi_alloc_board_minor(NULL); 1963 if (minor < 0) { 1964 comedi_cleanup_legacy_minors(); 1965 cdev_del(&comedi_cdev); 1966 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), 1967 COMEDI_NUM_MINORS); 1968 return minor; 1969 } 1970 } 1971 1972 return 0; 1973} 1974 1975static void __exit comedi_cleanup(void) 1976{ 1977 int i; 1978 1979 comedi_cleanup_legacy_minors(); 1980 for (i = 0; i < COMEDI_NUM_MINORS; ++i) 1981 BUG_ON(comedi_file_info_table[i]); 1982 1983 class_destroy(comedi_class); 1984 cdev_del(&comedi_cdev); 1985 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS); 1986 1987 comedi_proc_cleanup(); 1988} 1989 1990module_init(comedi_init); 1991module_exit(comedi_cleanup); 1992 1993void comedi_error(const struct comedi_device *dev, const char *s) 1994{ 1995 printk(KERN_ERR "comedi%d: %s: %s\n", dev->minor, 1996 dev->driver->driver_name, s); 1997} 1998EXPORT_SYMBOL(comedi_error); 1999 2000void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s) 2001{ 2002 struct comedi_async *async = s->async; 2003 unsigned runflags = 0; 2004 unsigned runflags_mask = 0; 2005 2006 /* DPRINTK("comedi_event 0x%x\n",mask); */ 2007 2008 if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) == 0) 2009 return; 2010 2011 if (s-> 2012 async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | 2013 COMEDI_CB_OVERFLOW)) { 2014 runflags_mask |= SRF_RUNNING; 2015 } 2016 /* remember if an error event has occured, so an error 2017 * can be returned the next time the user does a read() */ 2018 if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) { 2019 runflags_mask |= SRF_ERROR; 2020 runflags |= SRF_ERROR; 2021 } 2022 if (runflags_mask) { 2023 /*sets SRF_ERROR and SRF_RUNNING together atomically */ 2024 comedi_set_subdevice_runflags(s, runflags_mask, runflags); 2025 } 2026 2027 if (async->cb_mask & s->async->events) { 2028 if (comedi_get_subdevice_runflags(s) & SRF_USER) { 2029 wake_up_interruptible(&async->wait_head); 2030 if (s->subdev_flags & SDF_CMD_READ) 2031 kill_fasync(&dev->async_queue, SIGIO, POLL_IN); 2032 if (s->subdev_flags & SDF_CMD_WRITE) 2033 kill_fasync(&dev->async_queue, SIGIO, POLL_OUT); 2034 } else { 2035 if (async->cb_func) 2036 async->cb_func(s->async->events, async->cb_arg); 2037 } 2038 } 2039 s->async->events = 0; 2040} 2041EXPORT_SYMBOL(comedi_event); 2042 2043unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s) 2044{ 2045 unsigned long flags; 2046 unsigned runflags; 2047 2048 spin_lock_irqsave(&s->spin_lock, flags); 2049 runflags = s->runflags; 2050 spin_unlock_irqrestore(&s->spin_lock, flags); 2051 return runflags; 2052} 2053EXPORT_SYMBOL(comedi_get_subdevice_runflags); 2054 2055static int is_device_busy(struct comedi_device *dev) 2056{ 2057 struct comedi_subdevice *s; 2058 int i; 2059 2060 if (!dev->attached) 2061 return 0; 2062 2063 for (i = 0; i < dev->n_subdevices; i++) { 2064 s = dev->subdevices + i; 2065 if (s->busy) 2066 return 1; 2067 if (s->async && s->async->mmap_count) 2068 return 1; 2069 } 2070 2071 return 0; 2072} 2073 2074static void comedi_device_init(struct comedi_device *dev) 2075{ 2076 memset(dev, 0, sizeof(struct comedi_device)); 2077 spin_lock_init(&dev->spinlock); 2078 mutex_init(&dev->mutex); 2079 dev->minor = -1; 2080} 2081 2082static void comedi_device_cleanup(struct comedi_device *dev) 2083{ 2084 if (dev == NULL) 2085 return; 2086 mutex_lock(&dev->mutex); 2087 comedi_device_detach(dev); 2088 mutex_unlock(&dev->mutex); 2089 mutex_destroy(&dev->mutex); 2090} 2091 2092int comedi_alloc_board_minor(struct device *hardware_device) 2093{ 2094 unsigned long flags; 2095 struct comedi_device_file_info *info; 2096 struct device *csdev; 2097 unsigned i; 2098 int retval; 2099 2100 info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); 2101 if (info == NULL) 2102 return -ENOMEM; 2103 info->device = kzalloc(sizeof(struct comedi_device), GFP_KERNEL); 2104 if (info->device == NULL) { 2105 kfree(info); 2106 return -ENOMEM; 2107 } 2108 comedi_device_init(info->device); 2109 spin_lock_irqsave(&comedi_file_info_table_lock, flags); 2110 for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) { 2111 if (comedi_file_info_table[i] == NULL) { 2112 comedi_file_info_table[i] = info; 2113 break; 2114 } 2115 } 2116 spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); 2117 if (i == COMEDI_NUM_BOARD_MINORS) { 2118 comedi_device_cleanup(info->device); 2119 kfree(info->device); 2120 kfree(info); 2121 printk(KERN_ERR 2122 2123 "comedi: error: ran out of minor numbers for board device files.\n"); 2124 return -EBUSY; 2125 } 2126 info->device->minor = i; 2127 csdev = COMEDI_DEVICE_CREATE(comedi_class, NULL, 2128 MKDEV(COMEDI_MAJOR, i), NULL, 2129 hardware_device, "comedi%i", i); 2130 if (!IS_ERR(csdev)) 2131 info->device->class_dev = csdev; 2132 dev_set_drvdata(csdev, info); 2133 retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb); 2134 if (retval) { 2135 printk(KERN_ERR 2136 "comedi: failed to create sysfs attribute file \"%s\".\n", 2137 dev_attr_max_read_buffer_kb.attr.name); 2138 comedi_free_board_minor(i); 2139 return retval; 2140 } 2141 retval = device_create_file(csdev, &dev_attr_read_buffer_kb); 2142 if (retval) { 2143 printk(KERN_ERR 2144 "comedi: failed to create sysfs attribute file \"%s\".\n", 2145 dev_attr_read_buffer_kb.attr.name); 2146 comedi_free_board_minor(i); 2147 return retval; 2148 } 2149 retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb); 2150 if (retval) { 2151 printk(KERN_ERR 2152 "comedi: failed to create sysfs attribute file \"%s\".\n", 2153 dev_attr_max_write_buffer_kb.attr.name); 2154 comedi_free_board_minor(i); 2155 return retval; 2156 } 2157 retval = device_create_file(csdev, &dev_attr_write_buffer_kb); 2158 if (retval) { 2159 printk(KERN_ERR 2160 "comedi: failed to create sysfs attribute file \"%s\".\n", 2161 dev_attr_write_buffer_kb.attr.name); 2162 comedi_free_board_minor(i); 2163 return retval; 2164 } 2165 return i; 2166} 2167 2168void comedi_free_board_minor(unsigned minor) 2169{ 2170 unsigned long flags; 2171 struct comedi_device_file_info *info; 2172 2173 BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS); 2174 spin_lock_irqsave(&comedi_file_info_table_lock, flags); 2175 info = comedi_file_info_table[minor]; 2176 comedi_file_info_table[minor] = NULL; 2177 spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); 2178 2179 if (info) { 2180 struct comedi_device *dev = info->device; 2181 if (dev) { 2182 if (dev->class_dev) { 2183 device_destroy(comedi_class, 2184 MKDEV(COMEDI_MAJOR, dev->minor)); 2185 } 2186 comedi_device_cleanup(dev); 2187 kfree(dev); 2188 } 2189 kfree(info); 2190 } 2191} 2192 2193int comedi_alloc_subdevice_minor(struct comedi_device *dev, 2194 struct comedi_subdevice *s) 2195{ 2196 unsigned long flags; 2197 struct comedi_device_file_info *info; 2198 struct device *csdev; 2199 unsigned i; 2200 int retval; 2201 2202 info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); 2203 if (info == NULL) 2204 return -ENOMEM; 2205 info->device = dev; 2206 info->read_subdevice = s; 2207 info->write_subdevice = s; 2208 spin_lock_irqsave(&comedi_file_info_table_lock, flags); 2209 for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) { 2210 if (comedi_file_info_table[i] == NULL) { 2211 comedi_file_info_table[i] = info; 2212 break; 2213 } 2214 } 2215 spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); 2216 if (i == COMEDI_NUM_MINORS) { 2217 kfree(info); 2218 printk(KERN_ERR 2219 "comedi: error: ran out of minor numbers for board device files.\n"); 2220 return -EBUSY; 2221 } 2222 s->minor = i; 2223 csdev = COMEDI_DEVICE_CREATE(comedi_class, dev->class_dev, 2224 MKDEV(COMEDI_MAJOR, i), NULL, NULL, 2225 "comedi%i_subd%i", dev->minor, 2226 (int)(s - dev->subdevices)); 2227 if (!IS_ERR(csdev)) 2228 s->class_dev = csdev; 2229 dev_set_drvdata(csdev, info); 2230 retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb); 2231 if (retval) { 2232 printk(KERN_ERR 2233 "comedi: failed to create sysfs attribute file \"%s\".\n", 2234 dev_attr_max_read_buffer_kb.attr.name); 2235 comedi_free_subdevice_minor(s); 2236 return retval; 2237 } 2238 retval = device_create_file(csdev, &dev_attr_read_buffer_kb); 2239 if (retval) { 2240 printk(KERN_ERR 2241 "comedi: failed to create sysfs attribute file \"%s\".\n", 2242 dev_attr_read_buffer_kb.attr.name); 2243 comedi_free_subdevice_minor(s); 2244 return retval; 2245 } 2246 retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb); 2247 if (retval) { 2248 printk(KERN_ERR 2249 "comedi: failed to create sysfs attribute file \"%s\".\n", 2250 dev_attr_max_write_buffer_kb.attr.name); 2251 comedi_free_subdevice_minor(s); 2252 return retval; 2253 } 2254 retval = device_create_file(csdev, &dev_attr_write_buffer_kb); 2255 if (retval) { 2256 printk(KERN_ERR 2257 "comedi: failed to create sysfs attribute file \"%s\".\n", 2258 dev_attr_write_buffer_kb.attr.name); 2259 comedi_free_subdevice_minor(s); 2260 return retval; 2261 } 2262 return i; 2263} 2264 2265void comedi_free_subdevice_minor(struct comedi_subdevice *s) 2266{ 2267 unsigned long flags; 2268 struct comedi_device_file_info *info; 2269 2270 if (s == NULL) 2271 return; 2272 if (s->minor < 0) 2273 return; 2274 2275 BUG_ON(s->minor >= COMEDI_NUM_MINORS); 2276 BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR); 2277 2278 spin_lock_irqsave(&comedi_file_info_table_lock, flags); 2279 info = comedi_file_info_table[s->minor]; 2280 comedi_file_info_table[s->minor] = NULL; 2281 spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); 2282 2283 if (s->class_dev) { 2284 device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor)); 2285 s->class_dev = NULL; 2286 } 2287 kfree(info); 2288} 2289 2290struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor) 2291{ 2292 unsigned long flags; 2293 struct comedi_device_file_info *info; 2294 2295 BUG_ON(minor >= COMEDI_NUM_MINORS); 2296 spin_lock_irqsave(&comedi_file_info_table_lock, flags); 2297 info = comedi_file_info_table[minor]; 2298 spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); 2299 return info; 2300} 2301EXPORT_SYMBOL_GPL(comedi_get_device_file_info); 2302 2303static int resize_async_buffer(struct comedi_device *dev, 2304 struct comedi_subdevice *s, 2305 struct comedi_async *async, unsigned new_size) 2306{ 2307 int retval; 2308 2309 if (new_size > async->max_bufsize) 2310 return -EPERM; 2311 2312 if (s->busy) { 2313 DPRINTK("subdevice is busy, cannot resize buffer\n"); 2314 return -EBUSY; 2315 } 2316 if (async->mmap_count) { 2317 DPRINTK("subdevice is mmapped, cannot resize buffer\n"); 2318 return -EBUSY; 2319 } 2320 2321 if (!async->prealloc_buf) 2322 return -EINVAL; 2323 2324 /* make sure buffer is an integral number of pages 2325 * (we round up) */ 2326 new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK; 2327 2328 retval = comedi_buf_alloc(dev, s, new_size); 2329 if (retval < 0) 2330 return retval; 2331 2332 if (s->buf_change) { 2333 retval = s->buf_change(dev, s, new_size); 2334 if (retval < 0) 2335 return retval; 2336 } 2337 2338 DPRINTK("comedi%i subd %d buffer resized to %i bytes\n", 2339 dev->minor, (int)(s - dev->subdevices), async->prealloc_bufsz); 2340 return 0; 2341} 2342 2343/* sysfs attribute files */ 2344 2345static const unsigned bytes_per_kibi = 1024; 2346 2347static ssize_t show_max_read_buffer_kb(struct device *dev, 2348 struct device_attribute *attr, char *buf) 2349{ 2350 ssize_t retval; 2351 struct comedi_device_file_info *info = dev_get_drvdata(dev); 2352 unsigned max_buffer_size_kb = 0; 2353 struct comedi_subdevice *const read_subdevice = 2354 comedi_get_read_subdevice(info); 2355 2356 mutex_lock(&info->device->mutex); 2357 if (read_subdevice && 2358 (read_subdevice->subdev_flags & SDF_CMD_READ) && 2359 read_subdevice->async) { 2360 max_buffer_size_kb = read_subdevice->async->max_bufsize / 2361 bytes_per_kibi; 2362 } 2363 retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb); 2364 mutex_unlock(&info->device->mutex); 2365 2366 return retval; 2367} 2368 2369static ssize_t store_max_read_buffer_kb(struct device *dev, 2370 struct device_attribute *attr, 2371 const char *buf, size_t count) 2372{ 2373 struct comedi_device_file_info *info = dev_get_drvdata(dev); 2374 unsigned long new_max_size_kb; 2375 uint64_t new_max_size; 2376 struct comedi_subdevice *const read_subdevice = 2377 comedi_get_read_subdevice(info); 2378 2379 if (strict_strtoul(buf, 10, &new_max_size_kb)) 2380 return -EINVAL; 2381 if (new_max_size_kb != (uint32_t) new_max_size_kb) 2382 return -EINVAL; 2383 new_max_size = ((uint64_t) new_max_size_kb) * bytes_per_kibi; 2384 if (new_max_size != (uint32_t) new_max_size) 2385 return -EINVAL; 2386 2387 mutex_lock(&info->device->mutex); 2388 if (read_subdevice == NULL || 2389 (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 || 2390 read_subdevice->async == NULL) { 2391 mutex_unlock(&info->device->mutex); 2392 return -EINVAL; 2393 } 2394 read_subdevice->async->max_bufsize = new_max_size; 2395 mutex_unlock(&info->device->mutex); 2396 2397 return count; 2398} 2399 2400static struct device_attribute dev_attr_max_read_buffer_kb = { 2401 .attr = { 2402 .name = "max_read_buffer_kb", 2403 .mode = S_IRUGO | S_IWUSR}, 2404 .show = &show_max_read_buffer_kb, 2405 .store = &store_max_read_buffer_kb 2406}; 2407 2408static ssize_t show_read_buffer_kb(struct device *dev, 2409 struct device_attribute *attr, char *buf) 2410{ 2411 ssize_t retval; 2412 struct comedi_device_file_info *info = dev_get_drvdata(dev); 2413 unsigned buffer_size_kb = 0; 2414 struct comedi_subdevice *const read_subdevice = 2415 comedi_get_read_subdevice(info); 2416 2417 mutex_lock(&info->device->mutex); 2418 if (read_subdevice && 2419 (read_subdevice->subdev_flags & SDF_CMD_READ) && 2420 read_subdevice->async) { 2421 buffer_size_kb = read_subdevice->async->prealloc_bufsz / 2422 bytes_per_kibi; 2423 } 2424 retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb); 2425 mutex_unlock(&info->device->mutex); 2426 2427 return retval; 2428} 2429 2430static ssize_t store_read_buffer_kb(struct device *dev, 2431 struct device_attribute *attr, 2432 const char *buf, size_t count) 2433{ 2434 struct comedi_device_file_info *info = dev_get_drvdata(dev); 2435 unsigned long new_size_kb; 2436 uint64_t new_size; 2437 int retval; 2438 struct comedi_subdevice *const read_subdevice = 2439 comedi_get_read_subdevice(info); 2440 2441 if (strict_strtoul(buf, 10, &new_size_kb)) 2442 return -EINVAL; 2443 if (new_size_kb != (uint32_t) new_size_kb) 2444 return -EINVAL; 2445 new_size = ((uint64_t) new_size_kb) * bytes_per_kibi; 2446 if (new_size != (uint32_t) new_size) 2447 return -EINVAL; 2448 2449 mutex_lock(&info->device->mutex); 2450 if (read_subdevice == NULL || 2451 (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 || 2452 read_subdevice->async == NULL) { 2453 mutex_unlock(&info->device->mutex); 2454 return -EINVAL; 2455 } 2456 retval = resize_async_buffer(info->device, read_subdevice, 2457 read_subdevice->async, new_size); 2458 mutex_unlock(&info->device->mutex); 2459 2460 if (retval < 0) 2461 return retval; 2462 return count; 2463} 2464 2465static struct device_attribute dev_attr_read_buffer_kb = { 2466 .attr = { 2467 .name = "read_buffer_kb", 2468 .mode = S_IRUGO | S_IWUSR | S_IWGRP}, 2469 .show = &show_read_buffer_kb, 2470 .store = &store_read_buffer_kb 2471}; 2472 2473static ssize_t show_max_write_buffer_kb(struct device *dev, 2474 struct device_attribute *attr, 2475 char *buf) 2476{ 2477 ssize_t retval; 2478 struct comedi_device_file_info *info = dev_get_drvdata(dev); 2479 unsigned max_buffer_size_kb = 0; 2480 struct comedi_subdevice *const write_subdevice = 2481 comedi_get_write_subdevice(info); 2482 2483 mutex_lock(&info->device->mutex); 2484 if (write_subdevice && 2485 (write_subdevice->subdev_flags & SDF_CMD_WRITE) && 2486 write_subdevice->async) { 2487 max_buffer_size_kb = write_subdevice->async->max_bufsize / 2488 bytes_per_kibi; 2489 } 2490 retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb); 2491 mutex_unlock(&info->device->mutex); 2492 2493 return retval; 2494} 2495 2496static ssize_t store_max_write_buffer_kb(struct device *dev, 2497 struct device_attribute *attr, 2498 const char *buf, size_t count) 2499{ 2500 struct comedi_device_file_info *info = dev_get_drvdata(dev); 2501 unsigned long new_max_size_kb; 2502 uint64_t new_max_size; 2503 struct comedi_subdevice *const write_subdevice = 2504 comedi_get_write_subdevice(info); 2505 2506 if (strict_strtoul(buf, 10, &new_max_size_kb)) 2507 return -EINVAL; 2508 if (new_max_size_kb != (uint32_t) new_max_size_kb) 2509 return -EINVAL; 2510 new_max_size = ((uint64_t) new_max_size_kb) * bytes_per_kibi; 2511 if (new_max_size != (uint32_t) new_max_size) 2512 return -EINVAL; 2513 2514 mutex_lock(&info->device->mutex); 2515 if (write_subdevice == NULL || 2516 (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 || 2517 write_subdevice->async == NULL) { 2518 mutex_unlock(&info->device->mutex); 2519 return -EINVAL; 2520 } 2521 write_subdevice->async->max_bufsize = new_max_size; 2522 mutex_unlock(&info->device->mutex); 2523 2524 return count; 2525} 2526 2527static struct device_attribute dev_attr_max_write_buffer_kb = { 2528 .attr = { 2529 .name = "max_write_buffer_kb", 2530 .mode = S_IRUGO | S_IWUSR}, 2531 .show = &show_max_write_buffer_kb, 2532 .store = &store_max_write_buffer_kb 2533}; 2534 2535static ssize_t show_write_buffer_kb(struct device *dev, 2536 struct device_attribute *attr, char *buf) 2537{ 2538 ssize_t retval; 2539 struct comedi_device_file_info *info = dev_get_drvdata(dev); 2540 unsigned buffer_size_kb = 0; 2541 struct comedi_subdevice *const write_subdevice = 2542 comedi_get_write_subdevice(info); 2543 2544 mutex_lock(&info->device->mutex); 2545 if (write_subdevice && 2546 (write_subdevice->subdev_flags & SDF_CMD_WRITE) && 2547 write_subdevice->async) { 2548 buffer_size_kb = write_subdevice->async->prealloc_bufsz / 2549 bytes_per_kibi; 2550 } 2551 retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb); 2552 mutex_unlock(&info->device->mutex); 2553 2554 return retval; 2555} 2556 2557static ssize_t store_write_buffer_kb(struct device *dev, 2558 struct device_attribute *attr, 2559 const char *buf, size_t count) 2560{ 2561 struct comedi_device_file_info *info = dev_get_drvdata(dev); 2562 unsigned long new_size_kb; 2563 uint64_t new_size; 2564 int retval; 2565 struct comedi_subdevice *const write_subdevice = 2566 comedi_get_write_subdevice(info); 2567 2568 if (strict_strtoul(buf, 10, &new_size_kb)) 2569 return -EINVAL; 2570 if (new_size_kb != (uint32_t) new_size_kb) 2571 return -EINVAL; 2572 new_size = ((uint64_t) new_size_kb) * bytes_per_kibi; 2573 if (new_size != (uint32_t) new_size) 2574 return -EINVAL; 2575 2576 mutex_lock(&info->device->mutex); 2577 if (write_subdevice == NULL || 2578 (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 || 2579 write_subdevice->async == NULL) { 2580 mutex_unlock(&info->device->mutex); 2581 return -EINVAL; 2582 } 2583 retval = resize_async_buffer(info->device, write_subdevice, 2584 write_subdevice->async, new_size); 2585 mutex_unlock(&info->device->mutex); 2586 2587 if (retval < 0) 2588 return retval; 2589 return count; 2590} 2591 2592static struct device_attribute dev_attr_write_buffer_kb = { 2593 .attr = { 2594 .name = "write_buffer_kb", 2595 .mode = S_IRUGO | S_IWUSR | S_IWGRP}, 2596 .show = &show_write_buffer_kb, 2597 .store = &store_write_buffer_kb 2598}; 2599