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