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