diff options
Diffstat (limited to 'drivers/comedi/drivers.c')
| -rw-r--r-- | drivers/comedi/drivers.c | 177 |
1 files changed, 125 insertions, 52 deletions
diff --git a/drivers/comedi/drivers.c b/drivers/comedi/drivers.c index 376130bfba8a..69cd2a253c66 100644 --- a/drivers/comedi/drivers.c +++ b/drivers/comedi/drivers.c @@ -158,7 +158,7 @@ static void comedi_device_detach_cleanup(struct comedi_device *dev) int i; struct comedi_subdevice *s; - lockdep_assert_held(&dev->attach_lock); + lockdep_assert_held_write(&dev->attach_lock); lockdep_assert_held(&dev->mutex); if (dev->subdevices) { for (i = 0; i < dev->n_subdevices; i++) { @@ -196,16 +196,23 @@ static void comedi_device_detach_cleanup(struct comedi_device *dev) comedi_clear_hw_dev(dev); } -void comedi_device_detach(struct comedi_device *dev) +void comedi_device_detach_locked(struct comedi_device *dev) { + lockdep_assert_held_write(&dev->attach_lock); lockdep_assert_held(&dev->mutex); comedi_device_cancel_all(dev); - down_write(&dev->attach_lock); dev->attached = false; dev->detach_count++; if (dev->driver) dev->driver->detach(dev); comedi_device_detach_cleanup(dev); +} + +void comedi_device_detach(struct comedi_device *dev) +{ + lockdep_assert_held(&dev->mutex); + down_write(&dev->attach_lock); + comedi_device_detach_locked(dev); up_write(&dev->attach_lock); } @@ -339,10 +346,10 @@ int comedi_dio_insn_config(struct comedi_device *dev, unsigned int *data, unsigned int mask) { - unsigned int chan_mask = 1 << CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); - if (!mask) - mask = chan_mask; + if (!mask && chan < 32) + mask = 1U << chan; switch (data[0]) { case INSN_CONFIG_DIO_INPUT: @@ -382,7 +389,7 @@ EXPORT_SYMBOL_GPL(comedi_dio_insn_config); unsigned int comedi_dio_update_state(struct comedi_subdevice *s, unsigned int *data) { - unsigned int chanmask = (s->n_chan < 32) ? ((1 << s->n_chan) - 1) + unsigned int chanmask = (s->n_chan < 32) ? ((1U << s->n_chan) - 1) : 0xffffffff; unsigned int mask = data[0] & chanmask; unsigned int bits = data[1]; @@ -434,6 +441,13 @@ unsigned int comedi_bytes_per_scan_cmd(struct comedi_subdevice *s, } EXPORT_SYMBOL_GPL(comedi_bytes_per_scan_cmd); +static unsigned int _comedi_bytes_per_scan(struct comedi_subdevice *s) +{ + struct comedi_cmd *cmd = &s->async->cmd; + + return comedi_bytes_per_scan_cmd(s, cmd); +} + /** * comedi_bytes_per_scan() - Get length of asynchronous command "scan" in bytes * @s: COMEDI subdevice. @@ -451,9 +465,16 @@ EXPORT_SYMBOL_GPL(comedi_bytes_per_scan_cmd); */ unsigned int comedi_bytes_per_scan(struct comedi_subdevice *s) { - struct comedi_cmd *cmd = &s->async->cmd; + unsigned int num_bytes; - return comedi_bytes_per_scan_cmd(s, cmd); + if (comedi_get_is_subdevice_running(s)) { + num_bytes = _comedi_bytes_per_scan(s); + comedi_put_is_subdevice_running(s); + } else { + /* Use nomimal, single sample scan length. */ + num_bytes = comedi_samples_to_bytes(s, 1); + } + return num_bytes; } EXPORT_SYMBOL_GPL(comedi_bytes_per_scan); @@ -475,6 +496,17 @@ static unsigned int __comedi_nscans_left(struct comedi_subdevice *s, return nscans; } +static unsigned int _comedi_nscans_left(struct comedi_subdevice *s, + unsigned int nscans) +{ + if (nscans == 0) { + unsigned int nbytes = _comedi_buf_read_n_available(s); + + nscans = nbytes / _comedi_bytes_per_scan(s); + } + return __comedi_nscans_left(s, nscans); +} + /** * comedi_nscans_left() - Return the number of scans left in the command * @s: COMEDI subdevice. @@ -492,25 +524,18 @@ static unsigned int __comedi_nscans_left(struct comedi_subdevice *s, unsigned int comedi_nscans_left(struct comedi_subdevice *s, unsigned int nscans) { - if (nscans == 0) { - unsigned int nbytes = comedi_buf_read_n_available(s); - - nscans = nbytes / comedi_bytes_per_scan(s); + if (comedi_get_is_subdevice_running(s)) { + nscans = _comedi_nscans_left(s, nscans); + comedi_put_is_subdevice_running(s); + } else { + nscans = 0; } - return __comedi_nscans_left(s, nscans); + return nscans; } EXPORT_SYMBOL_GPL(comedi_nscans_left); -/** - * comedi_nsamples_left() - Return the number of samples left in the command - * @s: COMEDI subdevice. - * @nsamples: The expected number of samples. - * - * Returns the number of samples remaining to complete the command, or the - * specified expected number of samples (@nsamples), whichever is fewer. - */ -unsigned int comedi_nsamples_left(struct comedi_subdevice *s, - unsigned int nsamples) +static unsigned int _comedi_nsamples_left(struct comedi_subdevice *s, + unsigned int nsamples) { struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; @@ -531,24 +556,34 @@ unsigned int comedi_nsamples_left(struct comedi_subdevice *s, return samples_left; return nsamples; } -EXPORT_SYMBOL_GPL(comedi_nsamples_left); /** - * comedi_inc_scan_progress() - Update scan progress in asynchronous command + * comedi_nsamples_left() - Return the number of samples left in the command * @s: COMEDI subdevice. - * @num_bytes: Amount of data in bytes to increment scan progress. + * @nsamples: The expected number of samples. * - * Increments the scan progress by the number of bytes specified by @num_bytes. - * If the scan progress reaches or exceeds the scan length in bytes, reduce - * it modulo the scan length in bytes and set the "end of scan" asynchronous - * event flag (%COMEDI_CB_EOS) to be processed later. + * Returns the number of samples remaining to complete the command, or the + * specified expected number of samples (@nsamples), whichever is fewer. */ -void comedi_inc_scan_progress(struct comedi_subdevice *s, - unsigned int num_bytes) +unsigned int comedi_nsamples_left(struct comedi_subdevice *s, + unsigned int nsamples) +{ + if (comedi_get_is_subdevice_running(s)) { + nsamples = _comedi_nsamples_left(s, nsamples); + comedi_put_is_subdevice_running(s); + } else { + nsamples = 0; + } + return nsamples; +} +EXPORT_SYMBOL_GPL(comedi_nsamples_left); + +void _comedi_inc_scan_progress(struct comedi_subdevice *s, + unsigned int num_bytes) { struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; - unsigned int scan_length = comedi_bytes_per_scan(s); + unsigned int scan_length = _comedi_bytes_per_scan(s); /* track the 'cur_chan' for non-SDF_PACKED subdevices */ if (!(s->subdev_flags & SDF_PACKED)) { @@ -569,8 +604,43 @@ void comedi_inc_scan_progress(struct comedi_subdevice *s, async->events |= COMEDI_CB_EOS; } } + +/** + * comedi_inc_scan_progress() - Update scan progress in asynchronous command + * @s: COMEDI subdevice. + * @num_bytes: Amount of data in bytes to increment scan progress. + * + * Increments the scan progress by the number of bytes specified by @num_bytes. + * If the scan progress reaches or exceeds the scan length in bytes, reduce + * it modulo the scan length in bytes and set the "end of scan" asynchronous + * event flag (%COMEDI_CB_EOS) to be processed later. + */ +void comedi_inc_scan_progress(struct comedi_subdevice *s, + unsigned int num_bytes) +{ + if (comedi_get_is_subdevice_running(s)) { + _comedi_inc_scan_progress(s, num_bytes); + comedi_put_is_subdevice_running(s); + } +} EXPORT_SYMBOL_GPL(comedi_inc_scan_progress); +static unsigned int _comedi_handle_events(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + unsigned int events = s->async->events; + + if (events == 0) + return events; + + if ((events & COMEDI_CB_CANCEL_MASK) && s->cancel) + s->cancel(dev, s); + + _comedi_event(dev, s); + + return events; +} + /** * comedi_handle_events() - Handle events and possibly stop acquisition * @dev: COMEDI device. @@ -590,16 +660,14 @@ EXPORT_SYMBOL_GPL(comedi_inc_scan_progress); unsigned int comedi_handle_events(struct comedi_device *dev, struct comedi_subdevice *s) { - unsigned int events = s->async->events; - - if (events == 0) - return events; - - if ((events & COMEDI_CB_CANCEL_MASK) && s->cancel) - s->cancel(dev, s); - - comedi_event(dev, s); + unsigned int events; + if (comedi_get_is_subdevice_running(s)) { + events = _comedi_handle_events(dev, s); + comedi_put_is_subdevice_running(s); + } else { + events = 0; + } return events; } EXPORT_SYMBOL_GPL(comedi_handle_events); @@ -613,6 +681,7 @@ static int insn_rw_emulate_bits(struct comedi_device *dev, unsigned int chan = CR_CHAN(insn->chanspec); unsigned int base_chan = (chan < 32) ? 0 : chan; unsigned int _data[2]; + unsigned int i; int ret; memset(_data, 0, sizeof(_data)); @@ -625,18 +694,21 @@ static int insn_rw_emulate_bits(struct comedi_device *dev, if (insn->insn == INSN_WRITE) { if (!(s->subdev_flags & SDF_WRITABLE)) return -EINVAL; - _data[0] = 1 << (chan - base_chan); /* mask */ - _data[1] = data[0] ? (1 << (chan - base_chan)) : 0; /* bits */ + _data[0] = 1U << (chan - base_chan); /* mask */ } + for (i = 0; i < insn->n; i++) { + if (insn->insn == INSN_WRITE) + _data[1] = data[i] ? _data[0] : 0; /* bits */ - ret = s->insn_bits(dev, s, &_insn, _data); - if (ret < 0) - return ret; + ret = s->insn_bits(dev, s, &_insn, _data); + if (ret < 0) + return ret; - if (insn->insn == INSN_READ) - data[0] = (_data[1] >> (chan - base_chan)) & 1; + if (insn->insn == INSN_READ) + data[i] = (_data[1] >> (chan - base_chan)) & 1; + } - return 1; + return insn->n; } static int __comedi_device_postconfig_async(struct comedi_device *dev, @@ -666,6 +738,7 @@ static int __comedi_device_postconfig_async(struct comedi_device *dev, return -ENOMEM; init_waitqueue_head(&async->wait_head); + init_completion(&async->run_complete); s->async = async; async->max_bufsize = comedi_default_buf_maxsize_kb * 1024; @@ -709,7 +782,7 @@ static int __comedi_device_postconfig(struct comedi_device *dev) if (s->type == COMEDI_SUBD_DO) { if (s->n_chan < 32) - s->io_bits = (1 << s->n_chan) - 1; + s->io_bits = (1U << s->n_chan) - 1; else s->io_bits = 0xffffffff; } |
