Staging: comedi: remove space after ampersand
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / staging / comedi / drivers / pcmuio.c
CommitLineData
6baef150
CC
1/*
2 comedi/drivers/pcmuio.c
3 Driver for Winsystems PC-104 based 48-channel and 96-channel DIO boards.
4
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 2006 Calin A. Culianu <calin@ajvar.org>
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21*/
22/*
23Driver: pcmuio
24Description: A driver for the PCM-UIO48A and PCM-UIO96A boards from Winsystems.
25Devices: [Winsystems] PCM-UIO48A (pcmuio48), PCM-UIO96A (pcmuio96)
26Author: Calin Culianu <calin@ajvar.org>
27Updated: Fri, 13 Jan 2006 12:01:01 -0500
28Status: works
29
30A driver for the relatively straightforward-to-program PCM-UIO48A and
31PCM-UIO96A boards from Winsystems. These boards use either one or two
32(in the 96-DIO version) WS16C48 ASIC HighDensity I/O Chips (HDIO).
33This chip is interesting in that each I/O line is individually
34programmable for INPUT or OUTPUT (thus comedi_dio_config can be done
35on a per-channel basis). Also, each chip supports edge-triggered
36interrupts for the first 24 I/O lines. Of course, since the
3796-channel version of the board has two ASICs, it can detect polarity
38changes on up to 48 I/O lines. Since this is essentially an (non-PnP)
39ISA board, I/O Address and IRQ selection are done through jumpers on
40the board. You need to pass that information to this driver as the
41first and second comedi_config option, respectively. Note that the
4248-channel version uses 16 bytes of IO memory and the 96-channel
43version uses 32-bytes (in case you are worried about conflicts). The
4448-channel board is split into two 24-channel comedi subdevices.
45The 96-channel board is split into 4 24-channel DIO subdevices.
46
47Note that IRQ support has been added, but it is untested.
48
49To use edge-detection IRQ support, pass the IRQs of both ASICS
50(for the 96 channel version) or just 1 ASIC (for 48-channel version).
51Then, use use comedi_commands with TRIG_NOW.
52Your callback will be called each time an edge is triggered, and the data
53values will be two sample_t's, which should be concatenated to form one
5432-bit unsigned int. This value is the mask of channels that had
55edges detected from your channel list. Note that the bits positions
56in the mask correspond to positions in your chanlist when you specified
57the command and *not* channel id's!
58
59To set the polarity of the edge-detection interrupts pass a nonzero value for
60either CR_RANGE or CR_AREF for edge-up polarity, or a zero value for both
61CR_RANGE and CR_AREF if you want edge-down polarity.
62
63In the 48-channel version:
64
65On subdev 0, the first 24 channels channels are edge-detect channels.
66
67In the 96-channel board you have the collowing channels that can do edge detection:
68
69subdev 0, channels 0-24 (first 24 channels of 1st ASIC)
70subdev 2, channels 0-24 (first 24 channels of 2nd ASIC)
71
72Configuration Options:
73 [0] - I/O port base address
74 [1] - IRQ (for first ASIC, or first 24 channels)
75 [2] - IRQ for second ASIC (pcmuio96 only - IRQ for chans 48-72 .. can be the same as first irq!)
76*/
77
78#include "../comedidev.h"
79
80#include <linux/pci.h> /* for PCI devices */
81
53106ae6 82#define MIN(a, b) (((a) < (b)) ? (a) : (b))
6baef150
CC
83#define CHANS_PER_PORT 8
84#define PORTS_PER_ASIC 6
85#define INTR_PORTS_PER_ASIC 3
86#define MAX_CHANS_PER_SUBDEV 24 /* number of channels per comedi subdevice */
87#define PORTS_PER_SUBDEV (MAX_CHANS_PER_SUBDEV/CHANS_PER_PORT)
88#define CHANS_PER_ASIC (CHANS_PER_PORT*PORTS_PER_ASIC)
89#define INTR_CHANS_PER_ASIC 24
90#define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC/CHANS_PER_PORT)
91#define MAX_DIO_CHANS (PORTS_PER_ASIC*2*CHANS_PER_PORT)
92#define MAX_ASICS (MAX_DIO_CHANS/CHANS_PER_ASIC)
93#define SDEV_NO ((int)(s - dev->subdevices))
94#define CALC_N_SUBDEVS(nchans) ((nchans)/MAX_CHANS_PER_SUBDEV + (!!((nchans)%MAX_CHANS_PER_SUBDEV)) /*+ (nchans > INTR_CHANS_PER_ASIC ? 2 : 1)*/)
95/* IO Memory sizes */
96#define ASIC_IOSIZE (0x10)
97#define PCMUIO48_IOSIZE ASIC_IOSIZE
98#define PCMUIO96_IOSIZE (ASIC_IOSIZE*2)
99
100/* Some offsets - these are all in the 16byte IO memory offset from
101 the base address. Note that there is a paging scheme to swap out
102 offsets 0x8-0xA using the PAGELOCK register. See the table below.
103
104 Register(s) Pages R/W? Description
105 --------------------------------------------------------------
106 REG_PORTx All R/W Read/Write/Configure IO
107 REG_INT_PENDING All ReadOnly Quickly see which INT_IDx has int.
108 REG_PAGELOCK All WriteOnly Select a page
109 REG_POLx Pg. 1 only WriteOnly Select edge-detection polarity
110 REG_ENABx Pg. 2 only WriteOnly Enable/Disable edge-detect. int.
111 REG_INT_IDx Pg. 3 only R/W See which ports/bits have ints.
112 */
113#define REG_PORT0 0x0
114#define REG_PORT1 0x1
115#define REG_PORT2 0x2
116#define REG_PORT3 0x3
117#define REG_PORT4 0x4
118#define REG_PORT5 0x5
119#define REG_INT_PENDING 0x6
120#define REG_PAGELOCK 0x7 /* page selector register, upper 2 bits select a page
121 and bits 0-5 are used to 'lock down' a particular
122 port above to make it readonly. */
123#define REG_POL0 0x8
124#define REG_POL1 0x9
125#define REG_POL2 0xA
126#define REG_ENAB0 0x8
127#define REG_ENAB1 0x9
128#define REG_ENAB2 0xA
129#define REG_INT_ID0 0x8
130#define REG_INT_ID1 0x9
131#define REG_INT_ID2 0xA
132
133#define NUM_PAGED_REGS 3
134#define NUM_PAGES 4
135#define FIRST_PAGED_REG 0x8
136#define REG_PAGE_BITOFFSET 6
137#define REG_LOCK_BITOFFSET 0
138#define REG_PAGE_MASK (~((0x1<<REG_PAGE_BITOFFSET)-1))
139#define REG_LOCK_MASK ~(REG_PAGE_MASK)
140#define PAGE_POL 1
141#define PAGE_ENAB 2
142#define PAGE_INT_ID 3
143
144/*
145 * Board descriptions for two imaginary boards. Describing the
146 * boards in this way is optional, and completely driver-dependent.
147 * Some drivers use arrays such as this, other do not.
148 */
70a6001a 149struct pcmuio_board {
6baef150
CC
150 const char *name;
151 const int num_asics;
152 const int num_channels_per_port;
153 const int num_ports;
70a6001a 154};
6baef150 155
70a6001a 156static const struct pcmuio_board pcmuio_boards[] = {
6baef150 157 {
68c3dbff
BP
158 .name = "pcmuio48",
159 .num_asics = 1,
160 .num_ports = 6,
6baef150
CC
161 },
162 {
68c3dbff
BP
163 .name = "pcmuio96",
164 .num_asics = 2,
165 .num_ports = 12,
6baef150
CC
166 },
167};
168
169/*
170 * Useful for shorthand access to the particular board structure
171 */
70a6001a 172#define thisboard ((const struct pcmuio_board *)dev->board_ptr)
6baef150
CC
173
174/* this structure is for data unique to this subdevice. */
e15849e5 175struct pcmuio_subdev_private {
6baef150
CC
176 /* mapping of halfwords (bytes) in port/chanarray to iobase */
177 unsigned long iobases[PORTS_PER_SUBDEV];
178
179 /* The below is only used for intr subdevices */
180 struct {
181 int asic; /* if non-negative, this subdev has an interrupt asic */
182 int first_chan; /* if nonnegative, the first channel id for
183 interrupts. */
184 int num_asic_chans; /* the number of asic channels in this subdev
185 that have interrutps */
186 int asic_chan; /* if nonnegative, the first channel id with
187 respect to the asic that has interrupts */
188 int enabled_mask; /* subdev-relative channel mask for channels
189 we are interested in */
190 int active;
191 int stop_count;
192 int continuous;
193 spinlock_t spinlock;
194 } intr;
e15849e5 195};
6baef150
CC
196
197/* this structure is for data unique to this hardware driver. If
198 several hardware drivers keep similar information in this structure,
71b5f4f1 199 feel free to suggest moving the variable to the struct comedi_device struct. */
055f6636 200struct pcmuio_private {
6baef150
CC
201 struct {
202 unsigned char pagelock; /* current page and lock */
203 unsigned char pol[NUM_PAGED_REGS]; /* shadow of POLx registers */
204 unsigned char enab[NUM_PAGED_REGS]; /* shadow of ENABx registers */
205 int num;
206 unsigned long iobase;
207 unsigned int irq;
208 spinlock_t spinlock;
209 } asics[MAX_ASICS];
e15849e5 210 struct pcmuio_subdev_private *sprivs;
055f6636 211};
6baef150
CC
212
213/*
214 * most drivers define the following macro to make it easy to
215 * access the private structure.
216 */
055f6636 217#define devpriv ((struct pcmuio_private *)dev->private)
e15849e5 218#define subpriv ((struct pcmuio_subdev_private *)s->private)
6baef150 219/*
139dfbdf 220 * The struct comedi_driver structure tells the Comedi core module
6baef150
CC
221 * which functions to call to configure/deconfigure (attach/detach)
222 * the board, and also about the kernel module that contains
223 * the device code.
224 */
da91b269
BP
225static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it);
226static int pcmuio_detach(struct comedi_device *dev);
6baef150 227
139dfbdf 228static struct comedi_driver driver = {
68c3dbff
BP
229 .driver_name = "pcmuio",
230 .module = THIS_MODULE,
231 .attach = pcmuio_attach,
232 .detach = pcmuio_detach,
6baef150
CC
233/* It is not necessary to implement the following members if you are
234 * writing a driver for a ISA PnP or PCI card */
235 /* Most drivers will support multiple types of boards by
236 * having an array of board structures. These were defined
237 * in pcmuio_boards[] above. Note that the element 'name'
238 * was first in the structure -- Comedi uses this fact to
239 * extract the name of the board without knowing any details
240 * about the structure except for its length.
241 * When a device is attached (by comedi_config), the name
242 * of the device is given to Comedi, and Comedi tries to
243 * match it by going through the list of board names. If
244 * there is a match, the address of the pointer is put
245 * into dev->board_ptr and driver->attach() is called.
246 *
247 * Note that these are not necessary if you can determine
248 * the type of board in software. ISA PnP, PCI, and PCMCIA
249 * devices are such boards.
250 */
68c3dbff
BP
251 .board_name = &pcmuio_boards[0].name,
252 .offset = sizeof(struct pcmuio_board),
253 .num_names = sizeof(pcmuio_boards) / sizeof(struct pcmuio_board),
6baef150
CC
254};
255
34c43922 256static int pcmuio_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
90035c08 257 struct comedi_insn * insn, unsigned int * data);
34c43922 258static int pcmuio_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s,
90035c08 259 struct comedi_insn * insn, unsigned int * data);
6baef150 260
70265d24 261static irqreturn_t interrupt_pcmuio(int irq, void *d);
34c43922
BP
262static void pcmuio_stop_intr(struct comedi_device *, struct comedi_subdevice *);
263static int pcmuio_cancel(struct comedi_device * dev, struct comedi_subdevice * s);
264static int pcmuio_cmd(struct comedi_device * dev, struct comedi_subdevice * s);
265static int pcmuio_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s,
ea6d0d4c 266 struct comedi_cmd * cmd);
6baef150
CC
267
268/* some helper functions to deal with specifics of this device's registers */
71b5f4f1
BP
269static void init_asics(struct comedi_device * dev); /* sets up/clears ASIC chips to defaults */
270static void switch_page(struct comedi_device * dev, int asic, int page);
6baef150 271#ifdef notused
71b5f4f1
BP
272static void lock_port(struct comedi_device * dev, int asic, int port);
273static void unlock_port(struct comedi_device * dev, int asic, int port);
6baef150
CC
274#endif
275
276/*
277 * Attach is called by the Comedi core to configure the driver
278 * for a particular board. If you specified a board_name array
279 * in the driver structure, dev->board_ptr contains that
280 * address.
281 */
da91b269 282static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
6baef150 283{
34c43922 284 struct comedi_subdevice *s;
6baef150
CC
285 int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0;
286 unsigned long iobase;
287 unsigned int irq[MAX_ASICS];
288
289 iobase = it->options[0];
290 irq[0] = it->options[1];
291 irq[1] = it->options[2];
292
293 printk("comedi%d: %s: io: %lx ", dev->minor, driver.driver_name,
294 iobase);
295
296 dev->iobase = iobase;
297
298 if (!iobase || !request_region(iobase,
299 thisboard->num_asics * ASIC_IOSIZE,
300 driver.driver_name)) {
301 printk("I/O port conflict\n");
302 return -EIO;
303 }
304
305/*
306 * Initialize dev->board_name. Note that we can use the "thisboard"
307 * macro now, since we just initialized it in the last line.
308 */
309 dev->board_name = thisboard->name;
310
311/*
312 * Allocate the private structure area. alloc_private() is a
313 * convenient macro defined in comedidev.h.
314 */
055f6636 315 if (alloc_private(dev, sizeof(struct pcmuio_private)) < 0) {
6baef150
CC
316 printk("cannot allocate private data structure\n");
317 return -ENOMEM;
318 }
319
320 for (asic = 0; asic < MAX_ASICS; ++asic) {
321 devpriv->asics[asic].num = asic;
322 devpriv->asics[asic].iobase = dev->iobase + asic * ASIC_IOSIZE;
323 devpriv->asics[asic].irq = 0; /* this gets actually set at the end of
324 this function when we
325 comedi_request_irqs */
326 spin_lock_init(&devpriv->asics[asic].spinlock);
327 }
328
329 chans_left = CHANS_PER_ASIC * thisboard->num_asics;
330 n_subdevs = CALC_N_SUBDEVS(chans_left);
331 devpriv->sprivs =
e15849e5 332 kcalloc(n_subdevs, sizeof(struct pcmuio_subdev_private), GFP_KERNEL);
6baef150
CC
333 if (!devpriv->sprivs) {
334 printk("cannot allocate subdevice private data structures\n");
335 return -ENOMEM;
336 }
337 /*
338 * Allocate the subdevice structures. alloc_subdevice() is a
339 * convenient macro defined in comedidev.h.
340 *
341 * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the
342 * 96-channel version of the board.
343 */
344 if (alloc_subdevices(dev, n_subdevs) < 0) {
345 printk("cannot allocate subdevice data structures\n");
346 return -ENOMEM;
347 }
348
349 port = 0;
350 asic = 0;
351 for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
352 int byte_no;
353
354 s = dev->subdevices + sdev_no;
355 s->private = devpriv->sprivs + sdev_no;
356 s->maxdata = 1;
357 s->range_table = &range_digital;
358 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
359 s->type = COMEDI_SUBD_DIO;
360 s->insn_bits = pcmuio_dio_insn_bits;
361 s->insn_config = pcmuio_dio_insn_config;
362 s->n_chan = MIN(chans_left, MAX_CHANS_PER_SUBDEV);
363 subpriv->intr.asic = -1;
364 subpriv->intr.first_chan = -1;
365 subpriv->intr.asic_chan = -1;
366 subpriv->intr.num_asic_chans = -1;
367 subpriv->intr.active = 0;
368 s->len_chanlist = 1;
369
370 /* save the ioport address for each 'port' of 8 channels in the
371 subdevice */
372 for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
373 if (port >= PORTS_PER_ASIC) {
374 port = 0;
375 ++asic;
376 thisasic_chanct = 0;
377 }
378 subpriv->iobases[byte_no] =
379 devpriv->asics[asic].iobase + port;
380
381 if (thisasic_chanct <
382 CHANS_PER_PORT * INTR_PORTS_PER_ASIC
383 && subpriv->intr.asic < 0) {
384 /* this is an interrupt subdevice, so setup the struct */
385 subpriv->intr.asic = asic;
386 subpriv->intr.active = 0;
387 subpriv->intr.stop_count = 0;
388 subpriv->intr.first_chan = byte_no * 8;
389 subpriv->intr.asic_chan = thisasic_chanct;
390 subpriv->intr.num_asic_chans =
391 s->n_chan - subpriv->intr.first_chan;
392 dev->read_subdev = s;
393 s->subdev_flags |= SDF_CMD_READ;
394 s->cancel = pcmuio_cancel;
395 s->do_cmd = pcmuio_cmd;
396 s->do_cmdtest = pcmuio_cmdtest;
397 s->len_chanlist = subpriv->intr.num_asic_chans;
398 }
399 thisasic_chanct += CHANS_PER_PORT;
400 }
401 spin_lock_init(&subpriv->intr.spinlock);
402
403 chans_left -= s->n_chan;
404
405 if (!chans_left) {
406 asic = 0; /* reset the asic to our first asic, to do intr subdevs */
407 port = 0;
408 }
409
410 }
411
412 init_asics(dev); /* clear out all the registers, basically */
413
414 for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
415 if (irq[asic]
416 && comedi_request_irq(irq[asic], interrupt_pcmuio,
417 IRQF_SHARED, thisboard->name, dev)) {
418 int i;
419 /* unroll the allocated irqs.. */
420 for (i = asic - 1; i >= 0; --i) {
421 comedi_free_irq(irq[i], dev);
422 devpriv->asics[i].irq = irq[i] = 0;
423 }
424 irq[asic] = 0;
425 }
426 devpriv->asics[asic].irq = irq[asic];
427 }
428
429 dev->irq = irq[0]; /* grr.. wish comedi dev struct supported multiple
430 irqs.. */
431
432 if (irq[0]) {
433 printk("irq: %u ", irq[0]);
434 if (irq[1] && thisboard->num_asics == 2)
435 printk("second ASIC irq: %u ", irq[1]);
436 } else {
437 printk("(IRQ mode disabled) ");
438 }
439
440 printk("attached\n");
441
442 return 1;
443}
444
445/*
446 * _detach is called to deconfigure a device. It should deallocate
447 * resources.
448 * This function is also called when _attach() fails, so it should be
449 * careful not to release resources that were not necessarily
450 * allocated by _attach(). dev->private and dev->subdevices are
451 * deallocated automatically by the core.
452 */
da91b269 453static int pcmuio_detach(struct comedi_device *dev)
6baef150
CC
454{
455 int i;
456
457 printk("comedi%d: %s: remove\n", dev->minor, driver.driver_name);
458 if (dev->iobase)
459 release_region(dev->iobase, ASIC_IOSIZE * thisboard->num_asics);
460
461 for (i = 0; i < MAX_ASICS; ++i) {
462 if (devpriv->asics[i].irq)
463 comedi_free_irq(devpriv->asics[i].irq, dev);
464 }
465
466 if (devpriv && devpriv->sprivs)
467 kfree(devpriv->sprivs);
468
469 return 0;
470}
471
472/* DIO devices are slightly special. Although it is possible to
473 * implement the insn_read/insn_write interface, it is much more
474 * useful to applications if you implement the insn_bits interface.
475 * This allows packed reading/writing of the DIO channels. The
476 * comedi core can convert between insn_bits and insn_read/write */
da91b269
BP
477static int pcmuio_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
478 struct comedi_insn *insn, unsigned int *data)
6baef150
CC
479{
480 int byte_no;
481 if (insn->n != 2)
482 return -EINVAL;
483
484 /* NOTE:
485 reading a 0 means this channel was high
486 writine a 0 sets the channel high
487 reading a 1 means this channel was low
488 writing a 1 means set this channel low
489
490 Therefore everything is always inverted. */
491
492 /* The insn data is a mask in data[0] and the new data
493 * in data[1], each channel cooresponding to a bit. */
494
495#ifdef DAMMIT_ITS_BROKEN
496 /* DEBUG */
497 printk("write mask: %08x data: %08x\n", data[0], data[1]);
498#endif
499
500 s->state = 0;
501
502 for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) {
503 /* address of 8-bit port */
504 unsigned long ioaddr = subpriv->iobases[byte_no],
505 /* bit offset of port in 32-bit doubleword */
506 offset = byte_no * 8;
507 /* this 8-bit port's data */
508 unsigned char byte = 0,
509 /* The write mask for this port (if any) */
510 write_mask_byte = (data[0] >> offset) & 0xff,
511 /* The data byte for this port */
512 data_byte = (data[1] >> offset) & 0xff;
513
514 byte = inb(ioaddr); /* read all 8-bits for this port */
515
516#ifdef DAMMIT_ITS_BROKEN
517 /* DEBUG */
518 printk("byte %d wmb %02x db %02x offset %02d io %04x, data_in %02x ", byte_no, (unsigned)write_mask_byte, (unsigned)data_byte, offset, ioaddr, (unsigned)byte);
519#endif
520
521 if (write_mask_byte) {
522 /* this byte has some write_bits -- so set the output lines */
523 byte &= ~write_mask_byte; /* clear bits for write mask */
524 byte |= ~data_byte & write_mask_byte; /* set to inverted data_byte */
525 /* Write out the new digital output state */
526 outb(byte, ioaddr);
527 }
528#ifdef DAMMIT_ITS_BROKEN
529 /* DEBUG */
530 printk("data_out_byte %02x\n", (unsigned)byte);
531#endif
532 /* save the digital input lines for this byte.. */
533 s->state |= ((unsigned int)byte) << offset;
534 }
535
536 /* now return the DIO lines to data[1] - note they came inverted! */
537 data[1] = ~s->state;
538
539#ifdef DAMMIT_ITS_BROKEN
540 /* DEBUG */
541 printk("s->state %08x data_out %08x\n", s->state, data[1]);
542#endif
543
544 return 2;
545}
546
547/* The input or output configuration of each digital line is
548 * configured by a special insn_config instruction. chanspec
549 * contains the channel to be changed, and data[0] contains the
550 * value COMEDI_INPUT or COMEDI_OUTPUT. */
da91b269
BP
551static int pcmuio_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s,
552 struct comedi_insn *insn, unsigned int *data)
6baef150
CC
553{
554 int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no =
555 chan % 8;
556 unsigned long ioaddr;
557 unsigned char byte;
558
559 /* Compute ioaddr for this channel */
560 ioaddr = subpriv->iobases[byte_no];
561
562 /* NOTE:
563 writing a 0 an IO channel's bit sets the channel to INPUT
564 and pulls the line high as well
565
566 writing a 1 to an IO channel's bit pulls the line low
567
568 All channels are implicitly always in OUTPUT mode -- but when
569 they are high they can be considered to be in INPUT mode..
570
571 Thus, we only force channels low if the config request was INPUT,
572 otherwise we do nothing to the hardware. */
573
574 switch (data[0]) {
575 case INSN_CONFIG_DIO_OUTPUT:
576 /* save to io_bits -- don't actually do anything since
577 all input channels are also output channels... */
578 s->io_bits |= 1 << chan;
579 break;
580 case INSN_CONFIG_DIO_INPUT:
581 /* write a 0 to the actual register representing the channel
582 to set it to 'input'. 0 means "float high". */
583 byte = inb(ioaddr);
584 byte &= ~(1 << bit_no);
585 /**< set input channel to '0' */
586
587 /* write out byte -- this is the only time we actually affect the
588 hardware as all channels are implicitly output -- but input
589 channels are set to float-high */
590 outb(byte, ioaddr);
591
592 /* save to io_bits */
593 s->io_bits &= ~(1 << chan);
594 break;
595
596 case INSN_CONFIG_DIO_QUERY:
597 /* retreive from shadow register */
598 data[1] =
599 (s->
600 io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
601 return insn->n;
602 break;
603
604 default:
605 return -EINVAL;
606 break;
607 }
608
609 return insn->n;
610}
611
da91b269 612static void init_asics(struct comedi_device *dev)
6baef150
CC
613{ /* sets up an
614 ASIC chip to defaults */
615 int asic;
616
617 for (asic = 0; asic < thisboard->num_asics; ++asic) {
618 int port, page;
619 unsigned long baseaddr = dev->iobase + asic * ASIC_IOSIZE;
620
621 switch_page(dev, asic, 0); /* switch back to page 0 */
622
623 /* first, clear all the DIO port bits */
624 for (port = 0; port < PORTS_PER_ASIC; ++port)
625 outb(0, baseaddr + REG_PORT0 + port);
626
627 /* Next, clear all the paged registers for each page */
628 for (page = 1; page < NUM_PAGES; ++page) {
629 int reg;
630 /* now clear all the paged registers */
631 switch_page(dev, asic, page);
632 for (reg = FIRST_PAGED_REG;
633 reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg)
634 outb(0, baseaddr + reg);
635 }
636
637 /* DEBUG set rising edge interrupts on port0 of both asics */
638 /*switch_page(dev, asic, PAGE_POL);
639 outb(0xff, baseaddr + REG_POL0);
640 switch_page(dev, asic, PAGE_ENAB);
641 outb(0xff, baseaddr + REG_ENAB0); */
642 /* END DEBUG */
643
644 switch_page(dev, asic, 0); /* switch back to default page 0 */
645
646 }
647}
648
da91b269 649static void switch_page(struct comedi_device *dev, int asic, int page)
6baef150
CC
650{
651 if (asic < 0 || asic >= thisboard->num_asics)
652 return; /* paranoia */
653 if (page < 0 || page >= NUM_PAGES)
654 return; /* more paranoia */
655
656 devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
657 devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
658
659 /* now write out the shadow register */
660 outb(devpriv->asics[asic].pagelock,
661 dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
662}
663
664#ifdef notused
da91b269 665static void lock_port(struct comedi_device *dev, int asic, int port)
6baef150
CC
666{
667 if (asic < 0 || asic >= thisboard->num_asics)
668 return; /* paranoia */
669 if (port < 0 || port >= PORTS_PER_ASIC)
670 return; /* more paranoia */
671
672 devpriv->asics[asic].pagelock |= 0x1 << port;
673 /* now write out the shadow register */
674 outb(devpriv->asics[asic].pagelock,
675 dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
676}
677
da91b269 678static void unlock_port(struct comedi_device *dev, int asic, int port)
6baef150
CC
679{
680 if (asic < 0 || asic >= thisboard->num_asics)
681 return; /* paranoia */
682 if (port < 0 || port >= PORTS_PER_ASIC)
683 return; /* more paranoia */
684 devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK;
685 /* now write out the shadow register */
686 outb(devpriv->asics[asic].pagelock,
687 dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
688}
689#endif /* notused */
690
70265d24 691static irqreturn_t interrupt_pcmuio(int irq, void *d)
6baef150
CC
692{
693 int asic, got1 = 0;
71b5f4f1 694 struct comedi_device *dev = (struct comedi_device *) d;
6baef150
CC
695
696 for (asic = 0; asic < MAX_ASICS; ++asic) {
697 if (irq == devpriv->asics[asic].irq) {
698 unsigned long flags;
699 unsigned triggered = 0;
700 unsigned long iobase = devpriv->asics[asic].iobase;
701 /* it is an interrupt for ASIC #asic */
702 unsigned char int_pend;
703
704 comedi_spin_lock_irqsave(&devpriv->asics[asic].spinlock,
705 flags);
706
707 int_pend = inb(iobase + REG_INT_PENDING) & 0x07;
708
709 if (int_pend) {
710 int port;
711 for (port = 0; port < INTR_PORTS_PER_ASIC;
712 ++port) {
713 if (int_pend & (0x1 << port)) {
714 unsigned char
715 io_lines_with_edges = 0;
716 switch_page(dev, asic,
717 PAGE_INT_ID);
718 io_lines_with_edges =
719 inb(iobase +
720 REG_INT_ID0 + port);
721
722 if (io_lines_with_edges)
723 /* clear pending interrupt */
724 outb(0, iobase +
725 REG_INT_ID0 +
726 port);
727
728 triggered |=
729 io_lines_with_edges <<
730 port * 8;
731 }
732 }
733
734 ++got1;
735 }
736
737 comedi_spin_unlock_irqrestore(&devpriv->asics[asic].
738 spinlock, flags);
739
740 if (triggered) {
34c43922 741 struct comedi_subdevice *s;
6baef150
CC
742 /* TODO here: dispatch io lines to subdevs with commands.. */
743 printk("PCMUIO DEBUG: got edge detect interrupt %d asic %d which_chans: %06x\n", irq, asic, triggered);
744 for (s = dev->subdevices;
745 s < dev->subdevices + dev->n_subdevices;
746 ++s) {
747 if (subpriv->intr.asic == asic) { /* this is an interrupt subdev, and it matches this asic! */
748 unsigned long flags;
749 unsigned oldevents;
750
751 comedi_spin_lock_irqsave
752 (&subpriv->intr.
753 spinlock, flags);
754
755 oldevents = s->async->events;
756
757 if (subpriv->intr.active) {
758 unsigned mytrig =
759 ((triggered >>
760 subpriv->
761 intr.
762 asic_chan)
763 & ((0x1 << subpriv->intr.num_asic_chans) - 1)) << subpriv->intr.first_chan;
764 if (mytrig & subpriv->
765 intr.
766 enabled_mask) {
790c5541 767 unsigned int val =
6baef150
CC
768 0;
769 unsigned int n,
770 ch, len;
771
772 len = s->async->
773 cmd.
774 chanlist_len;
775 for (n = 0;
776 n < len;
777 n++) {
778 ch = CR_CHAN(s->async->cmd.chanlist[n]);
779 if (mytrig & (1U << ch)) {
780 val |= (1U << n);
781 }
782 }
783 /* Write the scan to the buffer. */
9b9bcba0 784 if (comedi_buf_put(s->async, ((short *) &val)[0])
6baef150
CC
785 &&
786 comedi_buf_put
9b9bcba0 787 (s->async, ((short *) &val)[1])) {
6baef150
CC
788 s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
789 } else {
790 /* Overflow! Stop acquisition!! */
791 /* TODO: STOP_ACQUISITION_CALL_HERE!! */
792 pcmuio_stop_intr
793 (dev,
794 s);
795 }
796
797 /* Check for end of acquisition. */
798 if (!subpriv->
799 intr.
800 continuous)
801 {
802 /* stop_src == TRIG_COUNT */
803 if (subpriv->intr.stop_count > 0) {
804 subpriv->
805 intr.
806 stop_count--;
807 if (subpriv->intr.stop_count == 0) {
808 s->async->events |= COMEDI_CB_EOA;
809 /* TODO: STOP_ACQUISITION_CALL_HERE!! */
810 pcmuio_stop_intr
811 (dev,
812 s);
813 }
814 }
815 }
816 }
817 }
818
819 comedi_spin_unlock_irqrestore
820 (&subpriv->intr.
821 spinlock, flags);
822
823 if (oldevents !=
824 s->async->events) {
825 comedi_event(dev, s);
826 }
827
828 }
829
830 }
831 }
832
833 }
834 }
835 if (!got1)
836 return IRQ_NONE; /* interrupt from other source */
837 return IRQ_HANDLED;
838}
839
da91b269 840static void pcmuio_stop_intr(struct comedi_device *dev, struct comedi_subdevice *s)
6baef150
CC
841{
842 int nports, firstport, asic, port;
843
c3744138
BP
844 asic = subpriv->intr.asic;
845 if (asic < 0)
6baef150
CC
846 return; /* not an interrupt subdev */
847
848 subpriv->intr.enabled_mask = 0;
849 subpriv->intr.active = 0;
850 s->async->inttrig = 0;
851 nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
852 firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
853 switch_page(dev, asic, PAGE_ENAB);
854 for (port = firstport; port < firstport + nports; ++port) {
855 /* disable all intrs for this subdev.. */
856 outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
857 }
858}
859
da91b269 860static int pcmuio_start_intr(struct comedi_device *dev, struct comedi_subdevice *s)
6baef150
CC
861{
862 if (!subpriv->intr.continuous && subpriv->intr.stop_count == 0) {
863 /* An empty acquisition! */
864 s->async->events |= COMEDI_CB_EOA;
865 subpriv->intr.active = 0;
866 return 1;
867 } else {
868 unsigned bits = 0, pol_bits = 0, n;
869 int nports, firstport, asic, port;
ea6d0d4c 870 struct comedi_cmd *cmd = &s->async->cmd;
6baef150 871
c3744138
BP
872 asic = subpriv->intr.asic;
873 if (asic < 0)
6baef150
CC
874 return 1; /* not an interrupt
875 subdev */
876 subpriv->intr.enabled_mask = 0;
877 subpriv->intr.active = 1;
878 nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
879 firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
880 if (cmd->chanlist) {
881 for (n = 0; n < cmd->chanlist_len; n++) {
882 bits |= (1U << CR_CHAN(cmd->chanlist[n]));
883 pol_bits |= (CR_AREF(cmd->chanlist[n])
884 || CR_RANGE(cmd->chanlist[n]) ? 1U : 0U)
885 << CR_CHAN(cmd->chanlist[n]);
886 }
887 }
888 bits &= ((0x1 << subpriv->intr.num_asic_chans) -
889 1) << subpriv->intr.first_chan;
890 subpriv->intr.enabled_mask = bits;
891
892 switch_page(dev, asic, PAGE_ENAB);
893 for (port = firstport; port < firstport + nports; ++port) {
894 unsigned enab =
895 bits >> (subpriv->intr.first_chan + (port -
896 firstport) * 8) & 0xff, pol =
897 pol_bits >> (subpriv->intr.first_chan + (port -
898 firstport) * 8) & 0xff;
899 /* set enab intrs for this subdev.. */
900 outb(enab,
901 devpriv->asics[asic].iobase + REG_ENAB0 + port);
902 switch_page(dev, asic, PAGE_POL);
903 outb(pol,
904 devpriv->asics[asic].iobase + REG_ENAB0 + port);
905 }
906 }
907 return 0;
908}
909
da91b269 910static int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
6baef150
CC
911{
912 unsigned long flags;
913
914 comedi_spin_lock_irqsave(&subpriv->intr.spinlock, flags);
915 if (subpriv->intr.active)
916 pcmuio_stop_intr(dev, s);
917 comedi_spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
918
919 return 0;
920}
921
922/*
923 * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
924 */
925static int
da91b269 926pcmuio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
6baef150
CC
927 unsigned int trignum)
928{
929 unsigned long flags;
930 int event = 0;
931
932 if (trignum != 0)
933 return -EINVAL;
934
935 comedi_spin_lock_irqsave(&subpriv->intr.spinlock, flags);
936 s->async->inttrig = 0;
937 if (subpriv->intr.active) {
938 event = pcmuio_start_intr(dev, s);
939 }
940 comedi_spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
941
942 if (event) {
943 comedi_event(dev, s);
944 }
945
946 return 1;
947}
948
949/*
950 * 'do_cmd' function for an 'INTERRUPT' subdevice.
951 */
da91b269 952static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
6baef150 953{
ea6d0d4c 954 struct comedi_cmd *cmd = &s->async->cmd;
6baef150
CC
955 unsigned long flags;
956 int event = 0;
957
958 comedi_spin_lock_irqsave(&subpriv->intr.spinlock, flags);
959 subpriv->intr.active = 1;
960
961 /* Set up end of acquisition. */
962 switch (cmd->stop_src) {
963 case TRIG_COUNT:
964 subpriv->intr.continuous = 0;
965 subpriv->intr.stop_count = cmd->stop_arg;
966 break;
967 default:
968 /* TRIG_NONE */
969 subpriv->intr.continuous = 1;
970 subpriv->intr.stop_count = 0;
971 break;
972 }
973
974 /* Set up start of acquisition. */
975 switch (cmd->start_src) {
976 case TRIG_INT:
977 s->async->inttrig = pcmuio_inttrig_start_intr;
978 break;
979 default:
980 /* TRIG_NOW */
981 event = pcmuio_start_intr(dev, s);
982 break;
983 }
984 comedi_spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
985
986 if (event) {
987 comedi_event(dev, s);
988 }
989
990 return 0;
991}
992
993/*
994 * 'do_cmdtest' function for an 'INTERRUPT' subdevice.
995 */
996static int
da91b269 997pcmuio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd)
6baef150
CC
998{
999 int err = 0;
1000 unsigned int tmp;
1001
1002 /* step 1: make sure trigger sources are trivially valid */
1003
1004 tmp = cmd->start_src;
1005 cmd->start_src &= (TRIG_NOW | TRIG_INT);
1006 if (!cmd->start_src || tmp != cmd->start_src)
1007 err++;
1008
1009 tmp = cmd->scan_begin_src;
1010 cmd->scan_begin_src &= TRIG_EXT;
1011 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
1012 err++;
1013
1014 tmp = cmd->convert_src;
1015 cmd->convert_src &= TRIG_NOW;
1016 if (!cmd->convert_src || tmp != cmd->convert_src)
1017 err++;
1018
1019 tmp = cmd->scan_end_src;
1020 cmd->scan_end_src &= TRIG_COUNT;
1021 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
1022 err++;
1023
1024 tmp = cmd->stop_src;
1025 cmd->stop_src &= (TRIG_COUNT | TRIG_NONE);
1026 if (!cmd->stop_src || tmp != cmd->stop_src)
1027 err++;
1028
1029 if (err)
1030 return 1;
1031
1032 /* step 2: make sure trigger sources are unique and mutually compatible */
1033
1034 /* these tests are true if more than one _src bit is set */
1035 if ((cmd->start_src & (cmd->start_src - 1)) != 0)
1036 err++;
1037 if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0)
1038 err++;
1039 if ((cmd->convert_src & (cmd->convert_src - 1)) != 0)
1040 err++;
1041 if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0)
1042 err++;
1043 if ((cmd->stop_src & (cmd->stop_src - 1)) != 0)
1044 err++;
1045
1046 if (err)
1047 return 2;
1048
1049 /* step 3: make sure arguments are trivially compatible */
1050
1051 /* cmd->start_src == TRIG_NOW || cmd->start_src == TRIG_INT */
1052 if (cmd->start_arg != 0) {
1053 cmd->start_arg = 0;
1054 err++;
1055 }
1056
1057 /* cmd->scan_begin_src == TRIG_EXT */
1058 if (cmd->scan_begin_arg != 0) {
1059 cmd->scan_begin_arg = 0;
1060 err++;
1061 }
1062
1063 /* cmd->convert_src == TRIG_NOW */
1064 if (cmd->convert_arg != 0) {
1065 cmd->convert_arg = 0;
1066 err++;
1067 }
1068
1069 /* cmd->scan_end_src == TRIG_COUNT */
1070 if (cmd->scan_end_arg != cmd->chanlist_len) {
1071 cmd->scan_end_arg = cmd->chanlist_len;
1072 err++;
1073 }
1074
1075 switch (cmd->stop_src) {
1076 case TRIG_COUNT:
1077 /* any count allowed */
1078 break;
1079 case TRIG_NONE:
1080 if (cmd->stop_arg != 0) {
1081 cmd->stop_arg = 0;
1082 err++;
1083 }
1084 break;
1085 default:
1086 break;
1087 }
1088
1089 if (err)
1090 return 3;
1091
1092 /* step 4: fix up any arguments */
1093
1094 /* if (err) return 4; */
1095
1096 return 0;
1097}
1098
1099/*
1100 * A convenient macro that defines init_module() and cleanup_module(),
1101 * as necessary.
1102 */
1103COMEDI_INITCLEANUP(driver);