diff options
-rw-r--r-- | drivers/staging/comedi/drivers/amplc_dio200.c | 35 |
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 | ||
465 | struct dio200_subdev_intr { | 466 | struct 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) { |