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