Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

comedi: Use reference count for asynchronous command functions

For interrupts from badly behaved hardware (as emulated by Syzbot), it
is possible for the Comedi core functions that manage the progress of
asynchronous data acquisition to be called from driver ISRs while no
asynchronous command has been set up, which can cause problems such as
invalid pointer dereferencing or dividing by zero.

Change those functions in the Comedi core to use this pattern: if
`comedi_get_is_subdevice_running(s)` returns `true` then call a safe
version of the function with the same name prefixed with an underscore,
followed by a call to `comedi_put_is_subdevice_running(s)`, otherwise
take some default action.

`comedi_get_is_subdevice_running(s)` returning `true` ensures that the
details of the asynchronous command will not be destroyed before the
matching call to `comedi_put_is_subdevice_running(s)`.

Replace calls to those functions from elsewhere in the Comedi core with
calls to the safe versions of the functions.

The modified functions are: `comedi_buf_read_alloc()`,
`comedi_buf_read_free()`, `comedi_buf_read_n_available()`,
`comedi_buf_read_samples()`, `comedi_buf_write_alloc()`,
`comedi_buf_write_free()`, `comedi_buf_write_samples()`,
`comedi_bytes_per_scan()`, `comedi_event()`, `comedi_handle_events()`,
`comedi_inc_scan_progress()`, `comedi_nsamples_left()`,
`comedi_nscans_left()`.

Signed-off-by: Ian Abbott <abbotti@mev.co.uk>
Link: https://patch.msgid.link/20251023133001.8439-3-abbotti@mev.co.uk
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Ian Abbott and committed by
Greg Kroah-Hartman
51495254 4e1da516

+331 -160
+190 -100
drivers/comedi/comedi_buf.c
··· 273 273 return free_end - async->buf_write_count; 274 274 } 275 275 276 - /** 277 - * comedi_buf_write_alloc() - Reserve buffer space for writing 278 - * @s: COMEDI subdevice. 279 - * @nbytes: Maximum space to reserve in bytes. 280 - * 281 - * Reserve up to @nbytes bytes of space to be written in the COMEDI acquisition 282 - * data buffer associated with the subdevice. The amount reserved is limited 283 - * by the space available. 284 - * 285 - * Return: The amount of space reserved in bytes. 286 - */ 287 - unsigned int comedi_buf_write_alloc(struct comedi_subdevice *s, 288 - unsigned int nbytes) 276 + unsigned int _comedi_buf_write_alloc(struct comedi_subdevice *s, 277 + unsigned int nbytes) 289 278 { 290 279 struct comedi_async *async = s->async; 291 280 unsigned int unalloc = comedi_buf_write_n_unalloc(s); ··· 290 301 */ 291 302 smp_mb(); 292 303 304 + return nbytes; 305 + } 306 + 307 + /** 308 + * comedi_buf_write_alloc() - Reserve buffer space for writing 309 + * @s: COMEDI subdevice. 310 + * @nbytes: Maximum space to reserve in bytes. 311 + * 312 + * Reserve up to @nbytes bytes of space to be written in the COMEDI acquisition 313 + * data buffer associated with the subdevice. The amount reserved is limited 314 + * by the space available. 315 + * 316 + * Return: The amount of space reserved in bytes. 317 + */ 318 + unsigned int comedi_buf_write_alloc(struct comedi_subdevice *s, 319 + unsigned int nbytes) 320 + { 321 + if (comedi_get_is_subdevice_running(s)) { 322 + nbytes = _comedi_buf_write_alloc(s, nbytes); 323 + comedi_put_is_subdevice_running(s); 324 + } else { 325 + nbytes = 0; 326 + } 293 327 return nbytes; 294 328 } 295 329 EXPORT_SYMBOL_GPL(comedi_buf_write_alloc); ··· 374 362 return async->buf_write_alloc_count - async->buf_write_count; 375 363 } 376 364 365 + unsigned int _comedi_buf_write_free(struct comedi_subdevice *s, 366 + unsigned int nbytes) 367 + { 368 + struct comedi_async *async = s->async; 369 + unsigned int allocated = comedi_buf_write_n_allocated(s); 370 + 371 + if (nbytes > allocated) 372 + nbytes = allocated; 373 + 374 + async->buf_write_count += nbytes; 375 + async->buf_write_ptr += nbytes; 376 + comedi_buf_munge(s, async->buf_write_count - async->munge_count); 377 + if (async->buf_write_ptr >= async->prealloc_bufsz) 378 + async->buf_write_ptr %= async->prealloc_bufsz; 379 + 380 + return nbytes; 381 + } 382 + 377 383 /** 378 384 * comedi_buf_write_free() - Free buffer space after it is written 379 385 * @s: COMEDI subdevice. ··· 410 380 unsigned int comedi_buf_write_free(struct comedi_subdevice *s, 411 381 unsigned int nbytes) 412 382 { 413 - struct comedi_async *async = s->async; 414 - unsigned int allocated = comedi_buf_write_n_allocated(s); 415 - 416 - if (nbytes > allocated) 417 - nbytes = allocated; 418 - 419 - async->buf_write_count += nbytes; 420 - async->buf_write_ptr += nbytes; 421 - comedi_buf_munge(s, async->buf_write_count - async->munge_count); 422 - if (async->buf_write_ptr >= async->prealloc_bufsz) 423 - async->buf_write_ptr %= async->prealloc_bufsz; 424 - 383 + if (comedi_get_is_subdevice_running(s)) { 384 + nbytes = _comedi_buf_write_free(s, nbytes); 385 + comedi_put_is_subdevice_running(s); 386 + } else { 387 + nbytes = 0; 388 + } 425 389 return nbytes; 426 390 } 427 391 EXPORT_SYMBOL_GPL(comedi_buf_write_free); 428 392 429 - /** 430 - * comedi_buf_read_n_available() - Determine amount of readable buffer space 431 - * @s: COMEDI subdevice. 432 - * 433 - * Determine the amount of readable buffer space in the COMEDI acquisition data 434 - * buffer associated with the subdevice. The readable buffer space is that 435 - * which has been freed by the writer and "munged" to the sample data format 436 - * expected by COMEDI if necessary. 437 - * 438 - * Return: The amount of readable buffer space. 439 - */ 440 - unsigned int comedi_buf_read_n_available(struct comedi_subdevice *s) 393 + unsigned int _comedi_buf_read_n_available(struct comedi_subdevice *s) 441 394 { 442 395 struct comedi_async *async = s->async; 443 396 unsigned int num_bytes; ··· 438 425 439 426 return num_bytes; 440 427 } 428 + 429 + /** 430 + * comedi_buf_read_n_available() - Determine amount of readable buffer space 431 + * @s: COMEDI subdevice. 432 + * 433 + * Determine the amount of readable buffer space in the COMEDI acquisition data 434 + * buffer associated with the subdevice. The readable buffer space is that 435 + * which has been freed by the writer and "munged" to the sample data format 436 + * expected by COMEDI if necessary. 437 + * 438 + * Return: The amount of readable buffer space. 439 + */ 440 + unsigned int comedi_buf_read_n_available(struct comedi_subdevice *s) 441 + { 442 + unsigned int num_bytes; 443 + 444 + if (comedi_get_is_subdevice_running(s)) { 445 + num_bytes = _comedi_buf_read_n_available(s); 446 + comedi_put_is_subdevice_running(s); 447 + } else { 448 + num_bytes = 0; 449 + } 450 + return num_bytes; 451 + } 441 452 EXPORT_SYMBOL_GPL(comedi_buf_read_n_available); 453 + 454 + unsigned int _comedi_buf_read_alloc(struct comedi_subdevice *s, 455 + unsigned int nbytes) 456 + { 457 + struct comedi_async *async = s->async; 458 + unsigned int available; 459 + 460 + available = async->munge_count - async->buf_read_alloc_count; 461 + if (nbytes > available) 462 + nbytes = available; 463 + 464 + async->buf_read_alloc_count += nbytes; 465 + 466 + /* 467 + * ensure the async buffer 'counts' are read before we 468 + * attempt to read data from the read-alloc'ed buffer space 469 + */ 470 + smp_rmb(); 471 + 472 + return nbytes; 473 + } 442 474 443 475 /** 444 476 * comedi_buf_read_alloc() - Reserve buffer space for reading ··· 503 445 unsigned int comedi_buf_read_alloc(struct comedi_subdevice *s, 504 446 unsigned int nbytes) 505 447 { 506 - struct comedi_async *async = s->async; 507 - unsigned int available; 508 - 509 - available = async->munge_count - async->buf_read_alloc_count; 510 - if (nbytes > available) 511 - nbytes = available; 512 - 513 - async->buf_read_alloc_count += nbytes; 514 - 515 - /* 516 - * ensure the async buffer 'counts' are read before we 517 - * attempt to read data from the read-alloc'ed buffer space 518 - */ 519 - smp_rmb(); 520 - 448 + if (comedi_get_is_subdevice_running(s)) { 449 + nbytes = _comedi_buf_read_alloc(s, nbytes); 450 + comedi_put_is_subdevice_running(s); 451 + } else { 452 + nbytes = 0; 453 + } 521 454 return nbytes; 522 455 } 523 456 EXPORT_SYMBOL_GPL(comedi_buf_read_alloc); ··· 516 467 static unsigned int comedi_buf_read_n_allocated(struct comedi_async *async) 517 468 { 518 469 return async->buf_read_alloc_count - async->buf_read_count; 470 + } 471 + 472 + unsigned int _comedi_buf_read_free(struct comedi_subdevice *s, 473 + unsigned int nbytes) 474 + { 475 + struct comedi_async *async = s->async; 476 + unsigned int allocated; 477 + 478 + /* 479 + * ensure data has been read out of buffer before 480 + * the async read count is incremented 481 + */ 482 + smp_mb(); 483 + 484 + allocated = comedi_buf_read_n_allocated(async); 485 + if (nbytes > allocated) 486 + nbytes = allocated; 487 + 488 + async->buf_read_count += nbytes; 489 + async->buf_read_ptr += nbytes; 490 + async->buf_read_ptr %= async->prealloc_bufsz; 491 + return nbytes; 519 492 } 520 493 521 494 /** ··· 556 485 unsigned int comedi_buf_read_free(struct comedi_subdevice *s, 557 486 unsigned int nbytes) 558 487 { 559 - struct comedi_async *async = s->async; 560 - unsigned int allocated; 561 - 562 - /* 563 - * ensure data has been read out of buffer before 564 - * the async read count is incremented 565 - */ 566 - smp_mb(); 567 - 568 - allocated = comedi_buf_read_n_allocated(async); 569 - if (nbytes > allocated) 570 - nbytes = allocated; 571 - 572 - async->buf_read_count += nbytes; 573 - async->buf_read_ptr += nbytes; 574 - async->buf_read_ptr %= async->prealloc_bufsz; 488 + if (comedi_get_is_subdevice_running(s)) { 489 + nbytes = _comedi_buf_read_free(s, nbytes); 490 + comedi_put_is_subdevice_running(s); 491 + } else { 492 + nbytes = 0; 493 + } 575 494 return nbytes; 576 495 } 577 496 EXPORT_SYMBOL_GPL(comedi_buf_read_free); ··· 619 558 } 620 559 } 621 560 561 + static unsigned int _comedi_buf_write_samples(struct comedi_subdevice *s, 562 + const void *data, 563 + unsigned int nsamples) 564 + { 565 + unsigned int max_samples; 566 + unsigned int nbytes; 567 + 568 + /* 569 + * Make sure there is enough room in the buffer for all the samples. 570 + * If not, clamp the nsamples to the number that will fit, flag the 571 + * buffer overrun and add the samples that fit. 572 + */ 573 + max_samples = comedi_bytes_to_samples(s, comedi_buf_write_n_unalloc(s)); 574 + if (nsamples > max_samples) { 575 + dev_warn(s->device->class_dev, "buffer overrun\n"); 576 + s->async->events |= COMEDI_CB_OVERFLOW; 577 + nsamples = max_samples; 578 + } 579 + 580 + if (nsamples == 0) 581 + return 0; 582 + 583 + nbytes = comedi_samples_to_bytes(s, nsamples); 584 + nbytes = _comedi_buf_write_alloc(s, nbytes); 585 + comedi_buf_memcpy_to(s, data, nbytes); 586 + _comedi_buf_write_free(s, nbytes); 587 + _comedi_inc_scan_progress(s, nbytes); 588 + s->async->events |= COMEDI_CB_BLOCK; 589 + 590 + return nbytes; 591 + } 592 + 622 593 /** 623 594 * comedi_buf_write_samples() - Write sample data to COMEDI buffer 624 595 * @s: COMEDI subdevice. ··· 671 578 unsigned int comedi_buf_write_samples(struct comedi_subdevice *s, 672 579 const void *data, unsigned int nsamples) 673 580 { 581 + unsigned int nbytes; 582 + 583 + if (comedi_get_is_subdevice_running(s)) { 584 + nbytes = _comedi_buf_write_samples(s, data, nsamples); 585 + comedi_put_is_subdevice_running(s); 586 + } else { 587 + nbytes = 0; 588 + } 589 + return nbytes; 590 + } 591 + EXPORT_SYMBOL_GPL(comedi_buf_write_samples); 592 + 593 + static unsigned int _comedi_buf_read_samples(struct comedi_subdevice *s, 594 + void *data, unsigned int nsamples) 595 + { 674 596 unsigned int max_samples; 675 597 unsigned int nbytes; 676 598 677 - /* 678 - * Make sure there is enough room in the buffer for all the samples. 679 - * If not, clamp the nsamples to the number that will fit, flag the 680 - * buffer overrun and add the samples that fit. 681 - */ 682 - max_samples = comedi_bytes_to_samples(s, comedi_buf_write_n_unalloc(s)); 683 - if (nsamples > max_samples) { 684 - dev_warn(s->device->class_dev, "buffer overrun\n"); 685 - s->async->events |= COMEDI_CB_OVERFLOW; 599 + /* clamp nsamples to the number of full samples available */ 600 + max_samples = comedi_bytes_to_samples(s, 601 + _comedi_buf_read_n_available(s)); 602 + if (nsamples > max_samples) 686 603 nsamples = max_samples; 687 - } 688 604 689 605 if (nsamples == 0) 690 606 return 0; 691 607 692 - nbytes = comedi_buf_write_alloc(s, 608 + nbytes = _comedi_buf_read_alloc(s, 693 609 comedi_samples_to_bytes(s, nsamples)); 694 - comedi_buf_memcpy_to(s, data, nbytes); 695 - comedi_buf_write_free(s, nbytes); 696 - comedi_inc_scan_progress(s, nbytes); 610 + comedi_buf_memcpy_from(s, data, nbytes); 611 + _comedi_buf_read_free(s, nbytes); 612 + _comedi_inc_scan_progress(s, nbytes); 697 613 s->async->events |= COMEDI_CB_BLOCK; 698 614 699 615 return nbytes; 700 616 } 701 - EXPORT_SYMBOL_GPL(comedi_buf_write_samples); 702 617 703 618 /** 704 619 * comedi_buf_read_samples() - Read sample data from COMEDI buffer ··· 725 624 unsigned int comedi_buf_read_samples(struct comedi_subdevice *s, 726 625 void *data, unsigned int nsamples) 727 626 { 728 - unsigned int max_samples; 729 627 unsigned int nbytes; 730 628 731 - /* clamp nsamples to the number of full samples available */ 732 - max_samples = comedi_bytes_to_samples(s, 733 - comedi_buf_read_n_available(s)); 734 - if (nsamples > max_samples) 735 - nsamples = max_samples; 736 - 737 - if (nsamples == 0) 738 - return 0; 739 - 740 - nbytes = comedi_buf_read_alloc(s, 741 - comedi_samples_to_bytes(s, nsamples)); 742 - comedi_buf_memcpy_from(s, data, nbytes); 743 - comedi_buf_read_free(s, nbytes); 744 - comedi_inc_scan_progress(s, nbytes); 745 - s->async->events |= COMEDI_CB_BLOCK; 746 - 629 + if (comedi_get_is_subdevice_running(s)) { 630 + nbytes = _comedi_buf_read_samples(s, data, nsamples); 631 + comedi_put_is_subdevice_running(s); 632 + } else { 633 + nbytes = 0; 634 + } 747 635 return nbytes; 748 636 } 749 637 EXPORT_SYMBOL_GPL(comedi_buf_read_samples);
+32 -24
drivers/comedi/comedi_fops.c
··· 1206 1206 if (!(async->cmd.flags & CMDF_WRITE)) { 1207 1207 /* command was set up in "read" direction */ 1208 1208 if (bi.bytes_read) { 1209 - comedi_buf_read_alloc(s, bi.bytes_read); 1210 - bi.bytes_read = comedi_buf_read_free(s, bi.bytes_read); 1209 + _comedi_buf_read_alloc(s, bi.bytes_read); 1210 + bi.bytes_read = _comedi_buf_read_free(s, bi.bytes_read); 1211 1211 } 1212 1212 /* 1213 1213 * If nothing left to read, and command has stopped, and 1214 1214 * {"read" position not updated or command stopped normally}, 1215 1215 * then become non-busy. 1216 1216 */ 1217 - if (comedi_buf_read_n_available(s) == 0 && 1217 + if (_comedi_buf_read_n_available(s) == 0 && 1218 1218 !comedi_is_runflags_running(runflags) && 1219 1219 (bi.bytes_read == 0 || 1220 1220 !comedi_is_runflags_in_error(runflags))) { ··· 1231 1231 if (comedi_is_runflags_in_error(runflags)) 1232 1232 retval = -EPIPE; 1233 1233 } else if (bi.bytes_written) { 1234 - comedi_buf_write_alloc(s, bi.bytes_written); 1234 + _comedi_buf_write_alloc(s, bi.bytes_written); 1235 1235 bi.bytes_written = 1236 - comedi_buf_write_free(s, bi.bytes_written); 1236 + _comedi_buf_write_free(s, bi.bytes_written); 1237 1237 } 1238 1238 bi.bytes_read = 0; 1239 1239 } ··· 2569 2569 poll_wait(file, &s->async->wait_head, wait); 2570 2570 if (s->busy != file || !comedi_is_subdevice_running(s) || 2571 2571 (s->async->cmd.flags & CMDF_WRITE) || 2572 - comedi_buf_read_n_available(s) > 0) 2572 + _comedi_buf_read_n_available(s) > 0) 2573 2573 mask |= EPOLLIN | EPOLLRDNORM; 2574 2574 } 2575 2575 ··· 2702 2702 break; 2703 2703 2704 2704 /* Allocate all free buffer space. */ 2705 - comedi_buf_write_alloc(s, async->prealloc_bufsz); 2705 + _comedi_buf_write_alloc(s, async->prealloc_bufsz); 2706 2706 m = comedi_buf_write_n_allocated(s); 2707 2707 n = min_t(size_t, m, nbytes); 2708 2708 ··· 2730 2730 n -= m; 2731 2731 retval = -EFAULT; 2732 2732 } 2733 - comedi_buf_write_free(s, n); 2733 + _comedi_buf_write_free(s, n); 2734 2734 2735 2735 count += n; 2736 2736 nbytes -= n; ··· 2816 2816 while (count == 0 && !retval) { 2817 2817 set_current_state(TASK_INTERRUPTIBLE); 2818 2818 2819 - m = comedi_buf_read_n_available(s); 2819 + m = _comedi_buf_read_n_available(s); 2820 2820 n = min_t(size_t, m, nbytes); 2821 2821 2822 2822 if (n == 0) { ··· 2856 2856 retval = -EFAULT; 2857 2857 } 2858 2858 2859 - comedi_buf_read_alloc(s, n); 2860 - comedi_buf_read_free(s, n); 2859 + _comedi_buf_read_alloc(s, n); 2860 + _comedi_buf_read_free(s, n); 2861 2861 2862 2862 count += n; 2863 2863 nbytes -= n; ··· 2891 2891 s == new_s && new_s->async == async && s->busy == file && 2892 2892 !(async->cmd.flags & CMDF_WRITE) && 2893 2893 !comedi_is_subdevice_running(s) && 2894 - comedi_buf_read_n_available(s) == 0) 2894 + _comedi_buf_read_n_available(s) == 0) 2895 2895 do_become_nonbusy(dev, s); 2896 2896 mutex_unlock(&dev->mutex); 2897 2897 } ··· 3386 3386 .llseek = noop_llseek, 3387 3387 }; 3388 3388 3389 - /** 3390 - * comedi_event() - Handle events for asynchronous COMEDI command 3391 - * @dev: COMEDI device. 3392 - * @s: COMEDI subdevice. 3393 - * Context: in_interrupt() (usually), @s->spin_lock spin-lock not held. 3394 - * 3395 - * If an asynchronous COMEDI command is active on the subdevice, process 3396 - * any %COMEDI_CB_... event flags that have been set, usually by an 3397 - * interrupt handler. These may change the run state of the asynchronous 3398 - * command, wake a task, and/or send a %SIGIO signal. 3399 - */ 3400 - void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s) 3389 + void _comedi_event(struct comedi_device *dev, struct comedi_subdevice *s) 3401 3390 { 3402 3391 struct comedi_async *async = s->async; 3403 3392 unsigned int events; ··· 3421 3432 3422 3433 if (si_code) 3423 3434 kill_fasync(&dev->async_queue, SIGIO, si_code); 3435 + } 3436 + 3437 + /** 3438 + * comedi_event() - Handle events for asynchronous COMEDI command 3439 + * @dev: COMEDI device. 3440 + * @s: COMEDI subdevice. 3441 + * Context: in_interrupt() (usually), @s->spin_lock spin-lock not held. 3442 + * 3443 + * If an asynchronous COMEDI command is active on the subdevice, process 3444 + * any %COMEDI_CB_... event flags that have been set, usually by an 3445 + * interrupt handler. These may change the run state of the asynchronous 3446 + * command, wake a task, and/or send a %SIGIO signal. 3447 + */ 3448 + void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s) 3449 + { 3450 + if (comedi_get_is_subdevice_running(s)) { 3451 + comedi_event(dev, s); 3452 + comedi_put_is_subdevice_running(s); 3453 + } 3424 3454 } 3425 3455 EXPORT_SYMBOL_GPL(comedi_event); 3426 3456
+12
drivers/comedi/comedi_internal.h
··· 36 36 comedi_buf_map_from_subdev_get(struct comedi_subdevice *s); 37 37 unsigned int comedi_buf_write_n_available(struct comedi_subdevice *s); 38 38 unsigned int comedi_buf_write_n_allocated(struct comedi_subdevice *s); 39 + unsigned int _comedi_buf_write_alloc(struct comedi_subdevice *s, 40 + unsigned int nbytes); 41 + unsigned int _comedi_buf_write_free(struct comedi_subdevice *s, 42 + unsigned int nbytes); 43 + unsigned int _comedi_buf_read_n_available(struct comedi_subdevice *s); 44 + unsigned int _comedi_buf_read_alloc(struct comedi_subdevice *s, 45 + unsigned int nbytes); 46 + unsigned int _comedi_buf_read_free(struct comedi_subdevice *s, 47 + unsigned int nbytes); 48 + void _comedi_inc_scan_progress(struct comedi_subdevice *s, 49 + unsigned int num_bytes); 50 + void _comedi_event(struct comedi_device *dev, struct comedi_subdevice *s); 39 51 void comedi_device_cancel_all(struct comedi_device *dev); 40 52 bool comedi_can_auto_free_spriv(struct comedi_subdevice *s); 41 53
+97 -36
drivers/comedi/drivers.c
··· 441 441 } 442 442 EXPORT_SYMBOL_GPL(comedi_bytes_per_scan_cmd); 443 443 444 + static unsigned int _comedi_bytes_per_scan(struct comedi_subdevice *s) 445 + { 446 + struct comedi_cmd *cmd = &s->async->cmd; 447 + 448 + return comedi_bytes_per_scan_cmd(s, cmd); 449 + } 450 + 444 451 /** 445 452 * comedi_bytes_per_scan() - Get length of asynchronous command "scan" in bytes 446 453 * @s: COMEDI subdevice. ··· 465 458 */ 466 459 unsigned int comedi_bytes_per_scan(struct comedi_subdevice *s) 467 460 { 468 - struct comedi_cmd *cmd = &s->async->cmd; 461 + unsigned int num_bytes; 469 462 470 - return comedi_bytes_per_scan_cmd(s, cmd); 463 + if (comedi_get_is_subdevice_running(s)) { 464 + num_bytes = _comedi_bytes_per_scan(s); 465 + comedi_put_is_subdevice_running(s); 466 + } else { 467 + /* Use nomimal, single sample scan length. */ 468 + num_bytes = comedi_samples_to_bytes(s, 1); 469 + } 470 + return num_bytes; 471 471 } 472 472 EXPORT_SYMBOL_GPL(comedi_bytes_per_scan); 473 473 ··· 496 482 return nscans; 497 483 } 498 484 485 + static unsigned int _comedi_nscans_left(struct comedi_subdevice *s, 486 + unsigned int nscans) 487 + { 488 + if (nscans == 0) { 489 + unsigned int nbytes = _comedi_buf_read_n_available(s); 490 + 491 + nscans = nbytes / _comedi_bytes_per_scan(s); 492 + } 493 + return __comedi_nscans_left(s, nscans); 494 + } 495 + 499 496 /** 500 497 * comedi_nscans_left() - Return the number of scans left in the command 501 498 * @s: COMEDI subdevice. ··· 524 499 unsigned int comedi_nscans_left(struct comedi_subdevice *s, 525 500 unsigned int nscans) 526 501 { 527 - if (nscans == 0) { 528 - unsigned int nbytes = comedi_buf_read_n_available(s); 529 - 530 - nscans = nbytes / comedi_bytes_per_scan(s); 502 + if (comedi_get_is_subdevice_running(s)) { 503 + nscans = _comedi_nscans_left(s, nscans); 504 + comedi_put_is_subdevice_running(s); 505 + } else { 506 + nscans = 0; 531 507 } 532 - return __comedi_nscans_left(s, nscans); 508 + return nscans; 533 509 } 534 510 EXPORT_SYMBOL_GPL(comedi_nscans_left); 535 511 536 - /** 537 - * comedi_nsamples_left() - Return the number of samples left in the command 538 - * @s: COMEDI subdevice. 539 - * @nsamples: The expected number of samples. 540 - * 541 - * Returns the number of samples remaining to complete the command, or the 542 - * specified expected number of samples (@nsamples), whichever is fewer. 543 - */ 544 - unsigned int comedi_nsamples_left(struct comedi_subdevice *s, 545 - unsigned int nsamples) 512 + static unsigned int _comedi_nsamples_left(struct comedi_subdevice *s, 513 + unsigned int nsamples) 546 514 { 547 515 struct comedi_async *async = s->async; 548 516 struct comedi_cmd *cmd = &async->cmd; ··· 556 538 return samples_left; 557 539 return nsamples; 558 540 } 559 - EXPORT_SYMBOL_GPL(comedi_nsamples_left); 560 541 561 542 /** 562 - * comedi_inc_scan_progress() - Update scan progress in asynchronous command 543 + * comedi_nsamples_left() - Return the number of samples left in the command 563 544 * @s: COMEDI subdevice. 564 - * @num_bytes: Amount of data in bytes to increment scan progress. 545 + * @nsamples: The expected number of samples. 565 546 * 566 - * Increments the scan progress by the number of bytes specified by @num_bytes. 567 - * If the scan progress reaches or exceeds the scan length in bytes, reduce 568 - * it modulo the scan length in bytes and set the "end of scan" asynchronous 569 - * event flag (%COMEDI_CB_EOS) to be processed later. 547 + * Returns the number of samples remaining to complete the command, or the 548 + * specified expected number of samples (@nsamples), whichever is fewer. 570 549 */ 571 - void comedi_inc_scan_progress(struct comedi_subdevice *s, 572 - unsigned int num_bytes) 550 + unsigned int comedi_nsamples_left(struct comedi_subdevice *s, 551 + unsigned int nsamples) 552 + { 553 + if (comedi_get_is_subdevice_running(s)) { 554 + nsamples = _comedi_nsamples_left(s, nsamples); 555 + comedi_put_is_subdevice_running(s); 556 + } else { 557 + nsamples = 0; 558 + } 559 + return nsamples; 560 + } 561 + EXPORT_SYMBOL_GPL(comedi_nsamples_left); 562 + 563 + void _comedi_inc_scan_progress(struct comedi_subdevice *s, 564 + unsigned int num_bytes) 573 565 { 574 566 struct comedi_async *async = s->async; 575 567 struct comedi_cmd *cmd = &async->cmd; 576 - unsigned int scan_length = comedi_bytes_per_scan(s); 568 + unsigned int scan_length = _comedi_bytes_per_scan(s); 577 569 578 570 /* track the 'cur_chan' for non-SDF_PACKED subdevices */ 579 571 if (!(s->subdev_flags & SDF_PACKED)) { ··· 604 576 async->events |= COMEDI_CB_EOS; 605 577 } 606 578 } 579 + 580 + /** 581 + * comedi_inc_scan_progress() - Update scan progress in asynchronous command 582 + * @s: COMEDI subdevice. 583 + * @num_bytes: Amount of data in bytes to increment scan progress. 584 + * 585 + * Increments the scan progress by the number of bytes specified by @num_bytes. 586 + * If the scan progress reaches or exceeds the scan length in bytes, reduce 587 + * it modulo the scan length in bytes and set the "end of scan" asynchronous 588 + * event flag (%COMEDI_CB_EOS) to be processed later. 589 + */ 590 + void comedi_inc_scan_progress(struct comedi_subdevice *s, 591 + unsigned int num_bytes) 592 + { 593 + if (comedi_get_is_subdevice_running(s)) { 594 + _comedi_inc_scan_progress(s, num_bytes); 595 + comedi_put_is_subdevice_running(s); 596 + } 597 + } 607 598 EXPORT_SYMBOL_GPL(comedi_inc_scan_progress); 599 + 600 + static unsigned int _comedi_handle_events(struct comedi_device *dev, 601 + struct comedi_subdevice *s) 602 + { 603 + unsigned int events = s->async->events; 604 + 605 + if (events == 0) 606 + return events; 607 + 608 + if ((events & COMEDI_CB_CANCEL_MASK) && s->cancel) 609 + s->cancel(dev, s); 610 + 611 + _comedi_event(dev, s); 612 + 613 + return events; 614 + } 608 615 609 616 /** 610 617 * comedi_handle_events() - Handle events and possibly stop acquisition ··· 660 597 unsigned int comedi_handle_events(struct comedi_device *dev, 661 598 struct comedi_subdevice *s) 662 599 { 663 - unsigned int events = s->async->events; 600 + unsigned int events; 664 601 665 - if (events == 0) 666 - return events; 667 - 668 - if ((events & COMEDI_CB_CANCEL_MASK) && s->cancel) 669 - s->cancel(dev, s); 670 - 671 - comedi_event(dev, s); 672 - 602 + if (comedi_get_is_subdevice_running(s)) { 603 + events = _comedi_handle_events(dev, s); 604 + comedi_put_is_subdevice_running(s); 605 + } else { 606 + events = 0; 607 + } 673 608 return events; 674 609 } 675 610 EXPORT_SYMBOL_GPL(comedi_handle_events);