diff options
author | H Hartley Sweeten <hsweeten@visionengravers.com> | 2013-06-18 16:25:47 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-06-24 18:51:04 -0400 |
commit | 1fdd0fc5fe28cd11ecf64e77892a1d9a1fd89fbf (patch) | |
tree | a36a21eb6305fefd410830cc195ddaf70fea5743 | |
parent | 89aaa92adffa5c57d9c2a545c7cb9809ddd3b615 (diff) |
staging: comedi: pcmuio: cleanup DIO subdevice (*insn_{bits,config})
Use the pcmuio_{read,write}() helpers to read/write all 24 channels
instead of handling the digital I/O as three separate ports. This
simplifies both functions with minimal overhead.
Signed-off-by: H Hartley Sweeten <hsweeten@visionengravers.com>
Reviewed-by: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/staging/comedi/drivers/pcmuio.c | 104 |
1 files changed, 29 insertions, 75 deletions
diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c index e52f6aeee453..d1f5fc024089 100644 --- a/drivers/staging/comedi/drivers/pcmuio.c +++ b/drivers/staging/comedi/drivers/pcmuio.c | |||
@@ -203,51 +203,42 @@ static unsigned int pcmuio_read(struct comedi_device *dev, | |||
203 | return val; | 203 | return val; |
204 | } | 204 | } |
205 | 205 | ||
206 | /* | ||
207 | * Each channel can be individually programmed for input or output. | ||
208 | * Writing a '0' to a channel causes the corresponding output pin | ||
209 | * to go to a high-z state (pulled high by an external 10K resistor). | ||
210 | * This allows it to be used as an input. When used in the input mode, | ||
211 | * a read reflects the inverted state of the I/O pin, such that a | ||
212 | * high on the pin will read as a '0' in the register. Writing a '1' | ||
213 | * to a bit position causes the pin to sink current (up to 12mA), | ||
214 | * effectively pulling it low. | ||
215 | */ | ||
206 | static int pcmuio_dio_insn_bits(struct comedi_device *dev, | 216 | static int pcmuio_dio_insn_bits(struct comedi_device *dev, |
207 | struct comedi_subdevice *s, | 217 | struct comedi_subdevice *s, |
208 | struct comedi_insn *insn, unsigned int *data) | 218 | struct comedi_insn *insn, unsigned int *data) |
209 | { | 219 | { |
220 | unsigned int mask = data[0] & s->io_bits; /* outputs only */ | ||
221 | unsigned int bits = data[1]; | ||
210 | int asic = s->index / 2; | 222 | int asic = s->index / 2; |
211 | int port = (s->index % 2) ? 3 : 0; | 223 | int port = (s->index % 2) ? 3 : 0; |
212 | unsigned long iobase = dev->iobase + (asic * ASIC_IOSIZE); | 224 | unsigned int val; |
213 | int byte_no; | ||
214 | |||
215 | /* NOTE: | ||
216 | reading a 0 means this channel was high | ||
217 | writine a 0 sets the channel high | ||
218 | reading a 1 means this channel was low | ||
219 | writing a 1 means set this channel low | ||
220 | |||
221 | Therefore everything is always inverted. */ | ||
222 | |||
223 | /* The insn data is a mask in data[0] and the new data | ||
224 | * in data[1], each channel cooresponding to a bit. */ | ||
225 | 225 | ||
226 | s->state = 0; | 226 | /* get inverted state of the channels from the port */ |
227 | val = pcmuio_read(dev, asic, 0, port); | ||
227 | 228 | ||
228 | for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) { | 229 | /* get the true state of the channels */ |
229 | /* bit offset of port in 32-bit doubleword */ | 230 | s->state = val ^ ((0x1 << s->n_chan) - 1); |
230 | unsigned long offset = byte_no * 8; | ||
231 | /* this 8-bit port's data */ | ||
232 | unsigned char byte = 0, | ||
233 | /* The write mask for this port (if any) */ | ||
234 | write_mask_byte = (data[0] >> offset) & 0xff, | ||
235 | /* The data byte for this port */ | ||
236 | data_byte = (data[1] >> offset) & 0xff; | ||
237 | 231 | ||
238 | byte = inb(iobase + PCMUIO_PORT_REG(port + byte_no)); | 232 | if (mask) { |
233 | s->state &= ~mask; | ||
234 | s->state |= (mask & bits); | ||
239 | 235 | ||
240 | if (write_mask_byte) { | 236 | /* invert the state and update the channels */ |
241 | byte &= ~write_mask_byte; | 237 | val = s->state ^ ((0x1 << s->n_chan) - 1); |
242 | byte |= ~data_byte & write_mask_byte; | 238 | pcmuio_write(dev, val, asic, 0, port); |
243 | outb(byte, iobase + PCMUIO_PORT_REG(port + byte_no)); | ||
244 | } | ||
245 | /* save the digital input lines for this byte.. */ | ||
246 | s->state |= ((unsigned int)byte) << offset; | ||
247 | } | 239 | } |
248 | 240 | ||
249 | /* now return the DIO lines to data[1] - note they came inverted! */ | 241 | data[1] = s->state; |
250 | data[1] = ~s->state; | ||
251 | 242 | ||
252 | return insn->n; | 243 | return insn->n; |
253 | } | 244 | } |
@@ -256,58 +247,21 @@ static int pcmuio_dio_insn_config(struct comedi_device *dev, | |||
256 | struct comedi_subdevice *s, | 247 | struct comedi_subdevice *s, |
257 | struct comedi_insn *insn, unsigned int *data) | 248 | struct comedi_insn *insn, unsigned int *data) |
258 | { | 249 | { |
250 | unsigned int chan_mask = 1 << CR_CHAN(insn->chanspec); | ||
259 | int asic = s->index / 2; | 251 | int asic = s->index / 2; |
260 | int port = (s->index % 2) ? 3 : 0; | 252 | int port = (s->index % 2) ? 3 : 0; |
261 | unsigned long iobase = dev->iobase + (asic * ASIC_IOSIZE); | ||
262 | unsigned int chan = CR_CHAN(insn->chanspec); | ||
263 | int byte_no = chan / 8; | ||
264 | int bit_no = chan % 8; | ||
265 | unsigned char byte; | ||
266 | |||
267 | /* NOTE: | ||
268 | writing a 0 an IO channel's bit sets the channel to INPUT | ||
269 | and pulls the line high as well | ||
270 | |||
271 | writing a 1 to an IO channel's bit pulls the line low | ||
272 | |||
273 | All channels are implicitly always in OUTPUT mode -- but when | ||
274 | they are high they can be considered to be in INPUT mode.. | ||
275 | |||
276 | Thus, we only force channels low if the config request was INPUT, | ||
277 | otherwise we do nothing to the hardware. */ | ||
278 | 253 | ||
279 | switch (data[0]) { | 254 | switch (data[0]) { |
280 | case INSN_CONFIG_DIO_OUTPUT: | 255 | case INSN_CONFIG_DIO_OUTPUT: |
281 | /* save to io_bits -- don't actually do anything since | 256 | s->io_bits |= chan_mask; |
282 | all input channels are also output channels... */ | ||
283 | s->io_bits |= 1 << chan; | ||
284 | break; | 257 | break; |
285 | case INSN_CONFIG_DIO_INPUT: | 258 | case INSN_CONFIG_DIO_INPUT: |
286 | /* write a 0 to the actual register representing the channel | 259 | s->io_bits &= ~chan_mask; |
287 | to set it to 'input'. 0 means "float high". */ | 260 | pcmuio_write(dev, s->io_bits, asic, 0, port); |
288 | byte = inb(iobase + PCMUIO_PORT_REG(port + byte_no)); | ||
289 | byte &= ~(1 << bit_no); | ||
290 | /**< set input channel to '0' */ | ||
291 | |||
292 | /* | ||
293 | * write out byte | ||
294 | * This is the only time we actually affect the hardware | ||
295 | * as all channels are implicitly output -- but input | ||
296 | * channels are set to float-high. | ||
297 | */ | ||
298 | outb(byte, iobase + PCMUIO_PORT_REG(port + byte_no)); | ||
299 | |||
300 | /* save to io_bits */ | ||
301 | s->io_bits &= ~(1 << chan); | ||
302 | break; | 261 | break; |
303 | |||
304 | case INSN_CONFIG_DIO_QUERY: | 262 | case INSN_CONFIG_DIO_QUERY: |
305 | /* retrieve from shadow register */ | 263 | data[1] = (s->io_bits & chan_mask) ? COMEDI_OUTPUT : COMEDI_INPUT; |
306 | data[1] = | ||
307 | (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; | ||
308 | return insn->n; | ||
309 | break; | 264 | break; |
310 | |||
311 | default: | 265 | default: |
312 | return -EINVAL; | 266 | return -EINVAL; |
313 | break; | 267 | break; |