aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH Hartley Sweeten <hsweeten@visionengravers.com>2013-06-18 16:25:47 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-06-24 18:51:04 -0400
commit1fdd0fc5fe28cd11ecf64e77892a1d9a1fd89fbf (patch)
treea36a21eb6305fefd410830cc195ddaf70fea5743
parent89aaa92adffa5c57d9c2a545c7cb9809ddd3b615 (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.c104
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 */
206static int pcmuio_dio_insn_bits(struct comedi_device *dev, 216static 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;