The internal state of an 82C54 counter timer chip will get messed up if
several threads read, write, configure, or check the status of the chip
simultaneously. Protect the register access sequences with a spin lock.
Signed-off-by: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
int has_clk_gat_sce;
unsigned clock_src[3]; /* Current clock sources */
unsigned gate_src[3]; /* Current gate sources */
int has_clk_gat_sce;
unsigned clock_src[3]; /* Current clock sources */
unsigned gate_src[3]; /* Current gate sources */
};
struct dio200_subdev_intr {
};
struct dio200_subdev_intr {
{
struct dio200_subdev_8254 *subpriv = s->private;
int chan = CR_CHAN(insn->chanspec);
{
struct dio200_subdev_8254 *subpriv = s->private;
int chan = CR_CHAN(insn->chanspec);
+ spin_lock_irqsave(&subpriv->spinlock, flags);
data[0] = i8254_read(subpriv->iobase, 0, chan);
data[0] = i8254_read(subpriv->iobase, 0, chan);
+ spin_unlock_irqrestore(&subpriv->spinlock, flags);
{
struct dio200_subdev_8254 *subpriv = s->private;
int chan = CR_CHAN(insn->chanspec);
{
struct dio200_subdev_8254 *subpriv = s->private;
int chan = CR_CHAN(insn->chanspec);
+ spin_lock_irqsave(&subpriv->spinlock, flags);
i8254_write(subpriv->iobase, 0, chan, data[0]);
i8254_write(subpriv->iobase, 0, chan, data[0]);
+ spin_unlock_irqrestore(&subpriv->spinlock, flags);
struct comedi_insn *insn, unsigned int *data)
{
struct dio200_subdev_8254 *subpriv = s->private;
struct comedi_insn *insn, unsigned int *data)
{
struct dio200_subdev_8254 *subpriv = s->private;
int chan = CR_CHAN(insn->chanspec);
int chan = CR_CHAN(insn->chanspec);
+ spin_lock_irqsave(&subpriv->spinlock, flags);
switch (data[0]) {
case INSN_CONFIG_SET_COUNTER_MODE:
ret = i8254_set_mode(subpriv->iobase, 0, chan, data[1]);
if (ret < 0)
switch (data[0]) {
case INSN_CONFIG_SET_COUNTER_MODE:
ret = i8254_set_mode(subpriv->iobase, 0, chan, data[1]);
if (ret < 0)
break;
case INSN_CONFIG_8254_READ_STATUS:
data[1] = i8254_status(subpriv->iobase, 0, chan);
break;
case INSN_CONFIG_8254_READ_STATUS:
data[1] = i8254_status(subpriv->iobase, 0, chan);
case INSN_CONFIG_SET_GATE_SRC:
ret = dio200_set_gate_src(subpriv, chan, data[2]);
if (ret < 0)
case INSN_CONFIG_SET_GATE_SRC:
ret = dio200_set_gate_src(subpriv, chan, data[2]);
if (ret < 0)
break;
case INSN_CONFIG_GET_GATE_SRC:
ret = dio200_get_gate_src(subpriv, chan);
break;
case INSN_CONFIG_GET_GATE_SRC:
ret = dio200_get_gate_src(subpriv, chan);
- if (ret < 0)
- return -EINVAL;
+ if (ret < 0) {
+ ret = -EINVAL;
+ break;
+ }
data[2] = ret;
break;
case INSN_CONFIG_SET_CLOCK_SRC:
ret = dio200_set_clock_src(subpriv, chan, data[1]);
if (ret < 0)
data[2] = ret;
break;
case INSN_CONFIG_SET_CLOCK_SRC:
ret = dio200_set_clock_src(subpriv, chan, data[1]);
if (ret < 0)
break;
case INSN_CONFIG_GET_CLOCK_SRC:
ret = dio200_get_clock_src(subpriv, chan, &data[2]);
break;
case INSN_CONFIG_GET_CLOCK_SRC:
ret = dio200_get_clock_src(subpriv, chan, &data[2]);
- if (ret < 0)
- return -EINVAL;
+ if (ret < 0) {
+ ret = -EINVAL;
+ break;
+ }
data[1] = ret;
break;
default:
data[1] = ret;
break;
default:
+ spin_unlock_irqrestore(&subpriv->spinlock, flags);
+ return ret < 0 ? ret : insn->n;
s->insn_write = dio200_subdev_8254_write;
s->insn_config = dio200_subdev_8254_config;
s->insn_write = dio200_subdev_8254_write;
s->insn_config = dio200_subdev_8254_config;
+ spin_lock_init(&subpriv->spinlock);
subpriv->iobase = offset + iobase;
subpriv->has_clk_gat_sce = has_clk_gat_sce;
if (has_clk_gat_sce) {
subpriv->iobase = offset + iobase;
subpriv->has_clk_gat_sce = has_clk_gat_sce;
if (has_clk_gat_sce) {