aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIan Abbott <abbotti@mev.co.uk>2010-05-19 11:59:40 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-06-04 16:38:53 -0400
commitee4063fa6bd801fa6ea045f23a2934db009b3dac (patch)
treef23288b2f1900fa34950381a2c63ab11f42e4391
parentd4da77a73cb9cc9a1a349daa1a2723505b086e2d (diff)
Staging: comedi: amplc_dio200: Protect counter subdevice with spinlock
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>
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200.c35
1 files changed, 25 insertions, 10 deletions
diff --git a/drivers/staging/comedi/drivers/amplc_dio200.c b/drivers/staging/comedi/drivers/amplc_dio200.c
index 8eb67651486a..bf27617aa62d 100644
--- a/drivers/staging/comedi/drivers/amplc_dio200.c
+++ b/drivers/staging/comedi/drivers/amplc_dio200.c
@@ -460,6 +460,7 @@ struct dio200_subdev_8254 {
460 int has_clk_gat_sce; 460 int has_clk_gat_sce;
461 unsigned clock_src[3]; /* Current clock sources */ 461 unsigned clock_src[3]; /* Current clock sources */
462 unsigned gate_src[3]; /* Current gate sources */ 462 unsigned gate_src[3]; /* Current gate sources */
463 spinlock_t spinlock;
463}; 464};
464 465
465struct dio200_subdev_intr { 466struct dio200_subdev_intr {
@@ -1042,8 +1043,11 @@ dio200_subdev_8254_read(struct comedi_device *dev, struct comedi_subdevice *s,
1042{ 1043{
1043 struct dio200_subdev_8254 *subpriv = s->private; 1044 struct dio200_subdev_8254 *subpriv = s->private;
1044 int chan = CR_CHAN(insn->chanspec); 1045 int chan = CR_CHAN(insn->chanspec);
1046 unsigned long flags;
1045 1047
1048 spin_lock_irqsave(&subpriv->spinlock, flags);
1046 data[0] = i8254_read(subpriv->iobase, 0, chan); 1049 data[0] = i8254_read(subpriv->iobase, 0, chan);
1050 spin_unlock_irqrestore(&subpriv->spinlock, flags);
1047 1051
1048 return 1; 1052 return 1;
1049} 1053}
@@ -1057,8 +1061,11 @@ dio200_subdev_8254_write(struct comedi_device *dev, struct comedi_subdevice *s,
1057{ 1061{
1058 struct dio200_subdev_8254 *subpriv = s->private; 1062 struct dio200_subdev_8254 *subpriv = s->private;
1059 int chan = CR_CHAN(insn->chanspec); 1063 int chan = CR_CHAN(insn->chanspec);
1064 unsigned long flags;
1060 1065
1066 spin_lock_irqsave(&subpriv->spinlock, flags);
1061 i8254_write(subpriv->iobase, 0, chan, data[0]); 1067 i8254_write(subpriv->iobase, 0, chan, data[0]);
1068 spin_unlock_irqrestore(&subpriv->spinlock, flags);
1062 1069
1063 return 1; 1070 return 1;
1064} 1071}
@@ -1151,14 +1158,16 @@ dio200_subdev_8254_config(struct comedi_device *dev, struct comedi_subdevice *s,
1151 struct comedi_insn *insn, unsigned int *data) 1158 struct comedi_insn *insn, unsigned int *data)
1152{ 1159{
1153 struct dio200_subdev_8254 *subpriv = s->private; 1160 struct dio200_subdev_8254 *subpriv = s->private;
1154 int ret; 1161 int ret = 0;
1155 int chan = CR_CHAN(insn->chanspec); 1162 int chan = CR_CHAN(insn->chanspec);
1163 unsigned long flags;
1156 1164
1165 spin_lock_irqsave(&subpriv->spinlock, flags);
1157 switch (data[0]) { 1166 switch (data[0]) {
1158 case INSN_CONFIG_SET_COUNTER_MODE: 1167 case INSN_CONFIG_SET_COUNTER_MODE:
1159 ret = i8254_set_mode(subpriv->iobase, 0, chan, data[1]); 1168 ret = i8254_set_mode(subpriv->iobase, 0, chan, data[1]);
1160 if (ret < 0) 1169 if (ret < 0)
1161 return -EINVAL; 1170 ret = -EINVAL;
1162 break; 1171 break;
1163 case INSN_CONFIG_8254_READ_STATUS: 1172 case INSN_CONFIG_8254_READ_STATUS:
1164 data[1] = i8254_status(subpriv->iobase, 0, chan); 1173 data[1] = i8254_status(subpriv->iobase, 0, chan);
@@ -1166,30 +1175,35 @@ dio200_subdev_8254_config(struct comedi_device *dev, struct comedi_subdevice *s,
1166 case INSN_CONFIG_SET_GATE_SRC: 1175 case INSN_CONFIG_SET_GATE_SRC:
1167 ret = dio200_set_gate_src(subpriv, chan, data[2]); 1176 ret = dio200_set_gate_src(subpriv, chan, data[2]);
1168 if (ret < 0) 1177 if (ret < 0)
1169 return -EINVAL; 1178 ret = -EINVAL;
1170 break; 1179 break;
1171 case INSN_CONFIG_GET_GATE_SRC: 1180 case INSN_CONFIG_GET_GATE_SRC:
1172 ret = dio200_get_gate_src(subpriv, chan); 1181 ret = dio200_get_gate_src(subpriv, chan);
1173 if (ret < 0) 1182 if (ret < 0) {
1174 return -EINVAL; 1183 ret = -EINVAL;
1184 break;
1185 }
1175 data[2] = ret; 1186 data[2] = ret;
1176 break; 1187 break;
1177 case INSN_CONFIG_SET_CLOCK_SRC: 1188 case INSN_CONFIG_SET_CLOCK_SRC:
1178 ret = dio200_set_clock_src(subpriv, chan, data[1]); 1189 ret = dio200_set_clock_src(subpriv, chan, data[1]);
1179 if (ret < 0) 1190 if (ret < 0)
1180 return -EINVAL; 1191 ret = -EINVAL;
1181 break; 1192 break;
1182 case INSN_CONFIG_GET_CLOCK_SRC: 1193 case INSN_CONFIG_GET_CLOCK_SRC:
1183 ret = dio200_get_clock_src(subpriv, chan, &data[2]); 1194 ret = dio200_get_clock_src(subpriv, chan, &data[2]);
1184 if (ret < 0) 1195 if (ret < 0) {
1185 return -EINVAL; 1196 ret = -EINVAL;
1197 break;
1198 }
1186 data[1] = ret; 1199 data[1] = ret;
1187 break; 1200 break;
1188 default: 1201 default:
1189 return -EINVAL; 1202 ret = -EINVAL;
1190 break; 1203 break;
1191 } 1204 }
1192 return insn->n; 1205 spin_unlock_irqrestore(&subpriv->spinlock, flags);
1206 return ret < 0 ? ret : insn->n;
1193} 1207}
1194 1208
1195/* 1209/*
@@ -1222,6 +1236,7 @@ dio200_subdev_8254_init(struct comedi_device *dev, struct comedi_subdevice *s,
1222 s->insn_write = dio200_subdev_8254_write; 1236 s->insn_write = dio200_subdev_8254_write;
1223 s->insn_config = dio200_subdev_8254_config; 1237 s->insn_config = dio200_subdev_8254_config;
1224 1238
1239 spin_lock_init(&subpriv->spinlock);
1225 subpriv->iobase = offset + iobase; 1240 subpriv->iobase = offset + iobase;
1226 subpriv->has_clk_gat_sce = has_clk_gat_sce; 1241 subpriv->has_clk_gat_sce = has_clk_gat_sce;
1227 if (has_clk_gat_sce) { 1242 if (has_clk_gat_sce) {