2 comedi/drivers/pcmmio.c
3 Driver for Winsystems PC-104 based multifunction IO board.
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 2007 Calin A. Culianu <calin@ajvar.org>
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.
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.
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.
24 Description: A driver for the PCM-MIO multifunction board
25 Devices: [Winsystems] PCM-MIO (pcmmio)
26 Author: Calin Culianu <calin@ajvar.org>
27 Updated: Wed, May 16 2007 16:21:10 -0500
30 A driver for the relatively new PCM-MIO multifunction board from
31 Winsystems. This board is a PC-104 based I/O board. It contains
33 subdevice 0 - 16 channels of 16-bit AI
34 subdevice 1 - 8 channels of 16-bit AO
35 subdevice 2 - first 24 channels of the 48 channel of DIO
36 (with edge-triggered interrupt support)
37 subdevice 3 - last 24 channels of the 48 channel DIO
38 (no interrupt support for this bank of channels)
42 Synchronous reads and writes are the only things implemented for AI and AO,
43 even though the hardware itself can do streaming acquisition, etc. Anyone
44 want to add asynchronous I/O for AI/AO as a feature? Be my guest...
46 Asynchronous I/O for the DIO subdevices *is* implemented, however! They are
47 basically edge-triggered interrupts for any configuration of the first
50 Also note that this interrupt support is untested.
52 A few words about edge-detection IRQ support (commands on DIO):
54 * To use edge-detection IRQ support for the DIO subdevice, pass the IRQ
55 of the board to the comedi_config command. The board IRQ is not jumpered
56 but rather configured through software, so any IRQ from 1-15 is OK.
58 * Due to the genericity of the comedi API, you need to create a special
59 comedi_command in order to use edge-triggered interrupts for DIO.
61 * Use comedi_commands with TRIG_NOW. Your callback will be called each
62 time an edge is detected on the specified DIO line(s), and the data
63 values will be two sample_t's, which should be concatenated to form
64 one 32-bit unsigned int. This value is the mask of channels that had
65 edges detected from your channel list. Note that the bits positions
66 in the mask correspond to positions in your chanlist when you
67 specified the command and *not* channel id's!
69 * To set the polarity of the edge-detection interrupts pass a nonzero value
70 for either CR_RANGE or CR_AREF for edge-up polarity, or a zero
71 value for both CR_RANGE and CR_AREF if you want edge-down polarity.
73 Configuration Options:
74 [0] - I/O port base address
75 [1] - IRQ (optional -- for edge-detect interrupt support only,
76 leave out if you don't need this feature)
79 #include <linux/interrupt.h>
80 #include <linux/slab.h>
81 #include "../comedidev.h"
82 #include "pcm_common.h"
83 #include <linux/pci.h> /* for PCI devices */
85 /* This stuff is all from pcmuio.c -- it refers to the DIO subdevices only */
86 #define CHANS_PER_PORT 8
87 #define PORTS_PER_ASIC 6
88 #define INTR_PORTS_PER_ASIC 3
89 #define MAX_CHANS_PER_SUBDEV 24 /* number of channels per comedi subdevice */
90 #define PORTS_PER_SUBDEV (MAX_CHANS_PER_SUBDEV/CHANS_PER_PORT)
91 #define CHANS_PER_ASIC (CHANS_PER_PORT*PORTS_PER_ASIC)
92 #define INTR_CHANS_PER_ASIC 24
93 #define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC/CHANS_PER_PORT)
94 #define MAX_DIO_CHANS (PORTS_PER_ASIC*1*CHANS_PER_PORT)
95 #define MAX_ASICS (MAX_DIO_CHANS/CHANS_PER_ASIC)
96 #define SDEV_NO ((int)(s - dev->subdevices))
97 #define CALC_N_DIO_SUBDEVS(nchans) ((nchans)/MAX_CHANS_PER_SUBDEV + (!!((nchans)%MAX_CHANS_PER_SUBDEV)) /*+ (nchans > INTR_CHANS_PER_ASIC ? 2 : 1)*/)
99 #define ASIC_IOSIZE (0x0B)
100 #define PCMMIO48_IOSIZE ASIC_IOSIZE
102 /* Some offsets - these are all in the 16byte IO memory offset from
103 the base address. Note that there is a paging scheme to swap out
104 offsets 0x8-0xA using the PAGELOCK register. See the table below.
106 Register(s) Pages R/W? Description
107 --------------------------------------------------------------
108 REG_PORTx All R/W Read/Write/Configure IO
109 REG_INT_PENDING All ReadOnly Quickly see which INT_IDx has int.
110 REG_PAGELOCK All WriteOnly Select a page
111 REG_POLx Pg. 1 only WriteOnly Select edge-detection polarity
112 REG_ENABx Pg. 2 only WriteOnly Enable/Disable edge-detect. int.
113 REG_INT_IDx Pg. 3 only R/W See which ports/bits have ints.
115 #define REG_PORT0 0x0
116 #define REG_PORT1 0x1
117 #define REG_PORT2 0x2
118 #define REG_PORT3 0x3
119 #define REG_PORT4 0x4
120 #define REG_PORT5 0x5
121 #define REG_INT_PENDING 0x6
122 #define REG_PAGELOCK 0x7 /*
123 * page selector register, upper 2 bits select
124 * a page and bits 0-5 are used to 'lock down'
125 * a particular port above to make it readonly.
130 #define REG_ENAB0 0x8
131 #define REG_ENAB1 0x9
132 #define REG_ENAB2 0xA
133 #define REG_INT_ID0 0x8
134 #define REG_INT_ID1 0x9
135 #define REG_INT_ID2 0xA
137 #define NUM_PAGED_REGS 3
139 #define FIRST_PAGED_REG 0x8
140 #define REG_PAGE_BITOFFSET 6
141 #define REG_LOCK_BITOFFSET 0
142 #define REG_PAGE_MASK (~((0x1<<REG_PAGE_BITOFFSET)-1))
143 #define REG_LOCK_MASK (~(REG_PAGE_MASK))
146 #define PAGE_INT_ID 3
148 typedef int (*comedi_insn_fn_t
) (struct comedi_device
*,
149 struct comedi_subdevice
*,
150 struct comedi_insn
*, unsigned int *);
152 static int ai_rinsn(struct comedi_device
*, struct comedi_subdevice
*,
153 struct comedi_insn
*, unsigned int *);
154 static int ao_rinsn(struct comedi_device
*, struct comedi_subdevice
*,
155 struct comedi_insn
*, unsigned int *);
156 static int ao_winsn(struct comedi_device
*, struct comedi_subdevice
*,
157 struct comedi_insn
*, unsigned int *);
160 * Board descriptions for two imaginary boards. Describing the
161 * boards in this way is optional, and completely driver-dependent.
162 * Some drivers use arrays such as this, other do not.
164 struct pcmmio_board
{
166 const int dio_num_asics
;
167 const int dio_num_ports
;
168 const int total_iosize
;
171 const int n_ai_chans
;
172 const int n_ao_chans
;
173 const struct comedi_lrange
*ai_range_table
, *ao_range_table
;
174 comedi_insn_fn_t ai_rinsn
, ao_rinsn
, ao_winsn
;
177 static const struct comedi_lrange ranges_ai
= {
178 4, {RANGE(-5., 5.), RANGE(-10., 10.), RANGE(0., 5.), RANGE(0., 10.)}
181 static const struct comedi_lrange ranges_ao
= {
182 6, {RANGE(0., 5.), RANGE(0., 10.), RANGE(-5., 5.), RANGE(-10., 10.),
183 RANGE(-2.5, 2.5), RANGE(-2.5, 7.5)}
186 static const struct pcmmio_board pcmmio_boards
[] = {
196 .ai_range_table
= &ranges_ai
,
197 .ao_range_table
= &ranges_ao
,
198 .ai_rinsn
= ai_rinsn
,
199 .ao_rinsn
= ao_rinsn
,
200 .ao_winsn
= ao_winsn
},
204 * Useful for shorthand access to the particular board structure
206 #define thisboard ((const struct pcmmio_board *)dev->board_ptr)
208 /* this structure is for data unique to this subdevice. */
209 struct pcmmio_subdev_private
{
212 /* for DIO: mapping of halfwords (bytes)
213 in port/chanarray to iobase */
214 unsigned long iobases
[PORTS_PER_SUBDEV
];
217 unsigned long iobase
;
222 /* The below is only used for intr subdevices */
225 * if non-negative, this subdev has an
230 * if nonnegative, the first channel id for
235 * the number of asic channels in this subdev
236 * that have interrutps
240 * if nonnegative, the first channel id with
241 * respect to the asic that has interrupts
245 * subdev-relative channel mask for channels
246 * we are interested in
256 /* the last unsigned int data written */
257 unsigned int shadow_samples
[8];
263 * this structure is for data unique to this hardware driver. If
264 * several hardware drivers keep similar information in this structure,
265 * feel free to suggest moving the variable to the struct comedi_device struct.
267 struct pcmmio_private
{
270 unsigned char pagelock
; /* current page and lock */
271 /* shadow of POLx registers */
272 unsigned char pol
[NUM_PAGED_REGS
];
273 /* shadow of ENABx registers */
274 unsigned char enab
[NUM_PAGED_REGS
];
276 unsigned long iobase
;
280 struct pcmmio_subdev_private
*sprivs
;
284 * most drivers define the following macro to make it easy to
285 * access the private structure.
287 #define devpriv ((struct pcmmio_private *)dev->private)
288 #define subpriv ((struct pcmmio_subdev_private *)s->private)
290 * The struct comedi_driver structure tells the Comedi core module
291 * which functions to call to configure/deconfigure (attach/detach)
292 * the board, and also about the kernel module that contains
295 static int pcmmio_attach(struct comedi_device
*dev
,
296 struct comedi_devconfig
*it
);
297 static int pcmmio_detach(struct comedi_device
*dev
);
299 static struct comedi_driver driver
= {
300 .driver_name
= "pcmmio",
301 .module
= THIS_MODULE
,
302 .attach
= pcmmio_attach
,
303 .detach
= pcmmio_detach
,
304 /* It is not necessary to implement the following members if you are
305 * writing a driver for a ISA PnP or PCI card */
306 /* Most drivers will support multiple types of boards by
307 * having an array of board structures. These were defined
308 * in pcmmio_boards[] above. Note that the element 'name'
309 * was first in the structure -- Comedi uses this fact to
310 * extract the name of the board without knowing any details
311 * about the structure except for its length.
312 * When a device is attached (by comedi_config), the name
313 * of the device is given to Comedi, and Comedi tries to
314 * match it by going through the list of board names. If
315 * there is a match, the address of the pointer is put
316 * into dev->board_ptr and driver->attach() is called.
318 * Note that these are not necessary if you can determine
319 * the type of board in software. ISA PnP, PCI, and PCMCIA
320 * devices are such boards.
322 .board_name
= &pcmmio_boards
[0].name
,
323 .offset
= sizeof(struct pcmmio_board
),
324 .num_names
= ARRAY_SIZE(pcmmio_boards
),
327 static int pcmmio_dio_insn_bits(struct comedi_device
*dev
,
328 struct comedi_subdevice
*s
,
329 struct comedi_insn
*insn
, unsigned int *data
);
330 static int pcmmio_dio_insn_config(struct comedi_device
*dev
,
331 struct comedi_subdevice
*s
,
332 struct comedi_insn
*insn
, unsigned int *data
);
334 static irqreturn_t
interrupt_pcmmio(int irq
, void *d
);
335 static void pcmmio_stop_intr(struct comedi_device
*, struct comedi_subdevice
*);
336 static int pcmmio_cancel(struct comedi_device
*dev
, struct comedi_subdevice
*s
);
337 static int pcmmio_cmd(struct comedi_device
*dev
, struct comedi_subdevice
*s
);
338 static int pcmmio_cmdtest(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
339 struct comedi_cmd
*cmd
);
341 /* some helper functions to deal with specifics of this device's registers */
342 /* sets up/clears ASIC chips to defaults */
343 static void init_asics(struct comedi_device
*dev
);
344 static void switch_page(struct comedi_device
*dev
, int asic
, int page
);
346 static void lock_port(struct comedi_device
*dev
, int asic
, int port
);
347 static void unlock_port(struct comedi_device
*dev
, int asic
, int port
);
351 * Attach is called by the Comedi core to configure the driver
352 * for a particular board. If you specified a board_name array
353 * in the driver structure, dev->board_ptr contains that
356 static int pcmmio_attach(struct comedi_device
*dev
, struct comedi_devconfig
*it
)
358 struct comedi_subdevice
*s
;
359 int sdev_no
, chans_left
, n_dio_subdevs
, n_subdevs
, port
, asic
,
361 unsigned long iobase
;
362 unsigned int irq
[MAX_ASICS
];
364 iobase
= it
->options
[0];
365 irq
[0] = it
->options
[1];
367 printk("comedi%d: %s: io: %lx ", dev
->minor
, driver
.driver_name
,
370 dev
->iobase
= iobase
;
372 if (!iobase
|| !request_region(iobase
,
373 thisboard
->total_iosize
,
374 driver
.driver_name
)) {
375 printk("I/O port conflict\n");
380 * Initialize dev->board_name. Note that we can use the "thisboard"
381 * macro now, since we just initialized it in the last line.
383 dev
->board_name
= thisboard
->name
;
386 * Allocate the private structure area. alloc_private() is a
387 * convenient macro defined in comedidev.h.
389 if (alloc_private(dev
, sizeof(struct pcmmio_private
)) < 0) {
390 printk("cannot allocate private data structure\n");
394 for (asic
= 0; asic
< MAX_ASICS
; ++asic
) {
395 devpriv
->asics
[asic
].num
= asic
;
396 devpriv
->asics
[asic
].iobase
=
397 dev
->iobase
+ 16 + asic
* ASIC_IOSIZE
;
399 * this gets actually set at the end of this function when we
402 devpriv
->asics
[asic
].irq
= 0;
403 spin_lock_init(&devpriv
->asics
[asic
].spinlock
);
406 chans_left
= CHANS_PER_ASIC
* thisboard
->dio_num_asics
;
407 n_dio_subdevs
= CALC_N_DIO_SUBDEVS(chans_left
);
408 n_subdevs
= n_dio_subdevs
+ 2;
410 kcalloc(n_subdevs
, sizeof(struct pcmmio_subdev_private
),
412 if (!devpriv
->sprivs
) {
413 printk("cannot allocate subdevice private data structures\n");
417 * Allocate the subdevice structures. alloc_subdevice() is a
418 * convenient macro defined in comedidev.h.
420 * Allocate 1 AI + 1 AO + 2 DIO subdevs (24 lines per DIO)
422 if (alloc_subdevices(dev
, n_subdevs
) < 0) {
423 printk("cannot allocate subdevice data structures\n");
429 s
= dev
->subdevices
+ sdev_no
;
430 s
->private = devpriv
->sprivs
+ sdev_no
;
431 s
->maxdata
= (1 << thisboard
->ai_bits
) - 1;
432 s
->range_table
= thisboard
->ai_range_table
;
433 s
->subdev_flags
= SDF_READABLE
| SDF_GROUND
| SDF_DIFF
;
434 s
->type
= COMEDI_SUBD_AI
;
435 s
->n_chan
= thisboard
->n_ai_chans
;
436 s
->len_chanlist
= s
->n_chan
;
437 s
->insn_read
= thisboard
->ai_rinsn
;
438 subpriv
->iobase
= dev
->iobase
+ 0;
439 /* initialize the resource enable register by clearing it */
440 outb(0, subpriv
->iobase
+ 3);
441 outb(0, subpriv
->iobase
+ 4 + 3);
445 s
= dev
->subdevices
+ sdev_no
;
446 s
->private = devpriv
->sprivs
+ sdev_no
;
447 s
->maxdata
= (1 << thisboard
->ao_bits
) - 1;
448 s
->range_table
= thisboard
->ao_range_table
;
449 s
->subdev_flags
= SDF_READABLE
;
450 s
->type
= COMEDI_SUBD_AO
;
451 s
->n_chan
= thisboard
->n_ao_chans
;
452 s
->len_chanlist
= s
->n_chan
;
453 s
->insn_read
= thisboard
->ao_rinsn
;
454 s
->insn_write
= thisboard
->ao_winsn
;
455 subpriv
->iobase
= dev
->iobase
+ 8;
456 /* initialize the resource enable register by clearing it */
457 outb(0, subpriv
->iobase
+ 3);
458 outb(0, subpriv
->iobase
+ 4 + 3);
463 for (; sdev_no
< (int)dev
->n_subdevices
; ++sdev_no
) {
466 s
= dev
->subdevices
+ sdev_no
;
467 s
->private = devpriv
->sprivs
+ sdev_no
;
469 s
->range_table
= &range_digital
;
470 s
->subdev_flags
= SDF_READABLE
| SDF_WRITABLE
;
471 s
->type
= COMEDI_SUBD_DIO
;
472 s
->insn_bits
= pcmmio_dio_insn_bits
;
473 s
->insn_config
= pcmmio_dio_insn_config
;
474 s
->n_chan
= min(chans_left
, MAX_CHANS_PER_SUBDEV
);
475 subpriv
->dio
.intr
.asic
= -1;
476 subpriv
->dio
.intr
.first_chan
= -1;
477 subpriv
->dio
.intr
.asic_chan
= -1;
478 subpriv
->dio
.intr
.num_asic_chans
= -1;
479 subpriv
->dio
.intr
.active
= 0;
482 /* save the ioport address for each 'port' of 8 channels in the
484 for (byte_no
= 0; byte_no
< PORTS_PER_SUBDEV
; ++byte_no
, ++port
) {
485 if (port
>= PORTS_PER_ASIC
) {
490 subpriv
->iobases
[byte_no
] =
491 devpriv
->asics
[asic
].iobase
+ port
;
493 if (thisasic_chanct
<
494 CHANS_PER_PORT
* INTR_PORTS_PER_ASIC
495 && subpriv
->dio
.intr
.asic
< 0) {
497 * this is an interrupt subdevice,
498 * so setup the struct
500 subpriv
->dio
.intr
.asic
= asic
;
501 subpriv
->dio
.intr
.active
= 0;
502 subpriv
->dio
.intr
.stop_count
= 0;
503 subpriv
->dio
.intr
.first_chan
= byte_no
* 8;
504 subpriv
->dio
.intr
.asic_chan
= thisasic_chanct
;
505 subpriv
->dio
.intr
.num_asic_chans
=
506 s
->n_chan
- subpriv
->dio
.intr
.first_chan
;
507 s
->cancel
= pcmmio_cancel
;
508 s
->do_cmd
= pcmmio_cmd
;
509 s
->do_cmdtest
= pcmmio_cmdtest
;
511 subpriv
->dio
.intr
.num_asic_chans
;
513 thisasic_chanct
+= CHANS_PER_PORT
;
515 spin_lock_init(&subpriv
->dio
.intr
.spinlock
);
517 chans_left
-= s
->n_chan
;
521 * reset the asic to our first asic,
530 init_asics(dev
); /* clear out all the registers, basically */
532 for (asic
= 0; irq
[0] && asic
< MAX_ASICS
; ++asic
) {
534 && request_irq(irq
[asic
], interrupt_pcmmio
,
535 IRQF_SHARED
, thisboard
->name
, dev
)) {
537 /* unroll the allocated irqs.. */
538 for (i
= asic
- 1; i
>= 0; --i
) {
539 free_irq(irq
[i
], dev
);
540 devpriv
->asics
[i
].irq
= irq
[i
] = 0;
544 devpriv
->asics
[asic
].irq
= irq
[asic
];
547 dev
->irq
= irq
[0]; /*
548 * grr.. wish comedi dev struct supported
553 printk("irq: %u ", irq
[0]);
554 if (thisboard
->dio_num_asics
== 2 && irq
[1])
555 printk("second ASIC irq: %u ", irq
[1]);
557 printk("(IRQ mode disabled) ");
560 printk("attached\n");
566 * _detach is called to deconfigure a device. It should deallocate
568 * This function is also called when _attach() fails, so it should be
569 * careful not to release resources that were not necessarily
570 * allocated by _attach(). dev->private and dev->subdevices are
571 * deallocated automatically by the core.
573 static int pcmmio_detach(struct comedi_device
*dev
)
577 printk("comedi%d: %s: remove\n", dev
->minor
, driver
.driver_name
);
579 release_region(dev
->iobase
, thisboard
->total_iosize
);
581 for (i
= 0; i
< MAX_ASICS
; ++i
) {
582 if (devpriv
&& devpriv
->asics
[i
].irq
)
583 free_irq(devpriv
->asics
[i
].irq
, dev
);
586 if (devpriv
&& devpriv
->sprivs
)
587 kfree(devpriv
->sprivs
);
592 /* DIO devices are slightly special. Although it is possible to
593 * implement the insn_read/insn_write interface, it is much more
594 * useful to applications if you implement the insn_bits interface.
595 * This allows packed reading/writing of the DIO channels. The
596 * comedi core can convert between insn_bits and insn_read/write */
597 static int pcmmio_dio_insn_bits(struct comedi_device
*dev
,
598 struct comedi_subdevice
*s
,
599 struct comedi_insn
*insn
, unsigned int *data
)
606 reading a 0 means this channel was high
607 writine a 0 sets the channel high
608 reading a 1 means this channel was low
609 writing a 1 means set this channel low
611 Therefore everything is always inverted. */
613 /* The insn data is a mask in data[0] and the new data
614 * in data[1], each channel cooresponding to a bit. */
616 #ifdef DAMMIT_ITS_BROKEN
618 printk("write mask: %08x data: %08x\n", data
[0], data
[1]);
623 for (byte_no
= 0; byte_no
< s
->n_chan
/ CHANS_PER_PORT
; ++byte_no
) {
624 /* address of 8-bit port */
625 unsigned long ioaddr
= subpriv
->iobases
[byte_no
],
626 /* bit offset of port in 32-bit doubleword */
627 offset
= byte_no
* 8;
628 /* this 8-bit port's data */
629 unsigned char byte
= 0,
630 /* The write mask for this port (if any) */
631 write_mask_byte
= (data
[0] >> offset
) & 0xff,
632 /* The data byte for this port */
633 data_byte
= (data
[1] >> offset
) & 0xff;
635 byte
= inb(ioaddr
); /* read all 8-bits for this port */
637 #ifdef DAMMIT_ITS_BROKEN
640 ("byte %d wmb %02x db %02x offset %02d io %04x, data_in %02x ",
641 byte_no
, (unsigned)write_mask_byte
, (unsigned)data_byte
,
642 offset
, ioaddr
, (unsigned)byte
);
645 if (write_mask_byte
) {
647 * this byte has some write_bits
648 * -- so set the output lines
650 /* clear bits for write mask */
651 byte
&= ~write_mask_byte
;
652 /* set to inverted data_byte */
653 byte
|= ~data_byte
& write_mask_byte
;
654 /* Write out the new digital output state */
657 #ifdef DAMMIT_ITS_BROKEN
659 printk("data_out_byte %02x\n", (unsigned)byte
);
661 /* save the digital input lines for this byte.. */
662 s
->state
|= ((unsigned int)byte
) << offset
;
665 /* now return the DIO lines to data[1] - note they came inverted! */
668 #ifdef DAMMIT_ITS_BROKEN
670 printk("s->state %08x data_out %08x\n", s
->state
, data
[1]);
676 /* The input or output configuration of each digital line is
677 * configured by a special insn_config instruction. chanspec
678 * contains the channel to be changed, and data[0] contains the
679 * value COMEDI_INPUT or COMEDI_OUTPUT. */
680 static int pcmmio_dio_insn_config(struct comedi_device
*dev
,
681 struct comedi_subdevice
*s
,
682 struct comedi_insn
*insn
, unsigned int *data
)
684 int chan
= CR_CHAN(insn
->chanspec
), byte_no
= chan
/ 8, bit_no
=
686 unsigned long ioaddr
;
689 /* Compute ioaddr for this channel */
690 ioaddr
= subpriv
->iobases
[byte_no
];
693 writing a 0 an IO channel's bit sets the channel to INPUT
694 and pulls the line high as well
696 writing a 1 to an IO channel's bit pulls the line low
698 All channels are implicitly always in OUTPUT mode -- but when
699 they are high they can be considered to be in INPUT mode..
701 Thus, we only force channels low if the config request was INPUT,
702 otherwise we do nothing to the hardware. */
705 case INSN_CONFIG_DIO_OUTPUT
:
706 /* save to io_bits -- don't actually do anything since
707 all input channels are also output channels... */
708 s
->io_bits
|= 1 << chan
;
710 case INSN_CONFIG_DIO_INPUT
:
711 /* write a 0 to the actual register representing the channel
712 to set it to 'input'. 0 means "float high". */
714 byte
&= ~(1 << bit_no
);
715 /**< set input channel to '0' */
718 * write out byte -- this is the only time we actually affect
719 * the hardware as all channels are implicitly output
720 * -- but input channels are set to float-high
724 /* save to io_bits */
725 s
->io_bits
&= ~(1 << chan
);
728 case INSN_CONFIG_DIO_QUERY
:
729 /* retreive from shadow register */
731 (s
->io_bits
& (1 << chan
)) ? COMEDI_OUTPUT
: COMEDI_INPUT
;
743 static void init_asics(struct comedi_device
*dev
)
745 ASIC chip to defaults */
748 for (asic
= 0; asic
< thisboard
->dio_num_asics
; ++asic
) {
750 unsigned long baseaddr
= devpriv
->asics
[asic
].iobase
;
752 switch_page(dev
, asic
, 0); /* switch back to page 0 */
754 /* first, clear all the DIO port bits */
755 for (port
= 0; port
< PORTS_PER_ASIC
; ++port
)
756 outb(0, baseaddr
+ REG_PORT0
+ port
);
758 /* Next, clear all the paged registers for each page */
759 for (page
= 1; page
< NUM_PAGES
; ++page
) {
761 /* now clear all the paged registers */
762 switch_page(dev
, asic
, page
);
763 for (reg
= FIRST_PAGED_REG
;
764 reg
< FIRST_PAGED_REG
+ NUM_PAGED_REGS
; ++reg
)
765 outb(0, baseaddr
+ reg
);
768 /* DEBUG set rising edge interrupts on port0 of both asics */
769 /*switch_page(dev, asic, PAGE_POL);
770 outb(0xff, baseaddr + REG_POL0);
771 switch_page(dev, asic, PAGE_ENAB);
772 outb(0xff, baseaddr + REG_ENAB0); */
775 /* switch back to default page 0 */
776 switch_page(dev
, asic
, 0);
780 static void switch_page(struct comedi_device
*dev
, int asic
, int page
)
782 if (asic
< 0 || asic
>= thisboard
->dio_num_asics
)
783 return; /* paranoia */
784 if (page
< 0 || page
>= NUM_PAGES
)
785 return; /* more paranoia */
787 devpriv
->asics
[asic
].pagelock
&= ~REG_PAGE_MASK
;
788 devpriv
->asics
[asic
].pagelock
|= page
<< REG_PAGE_BITOFFSET
;
790 /* now write out the shadow register */
791 outb(devpriv
->asics
[asic
].pagelock
,
792 devpriv
->asics
[asic
].iobase
+ REG_PAGELOCK
);
796 static void lock_port(struct comedi_device
*dev
, int asic
, int port
)
798 if (asic
< 0 || asic
>= thisboard
->dio_num_asics
)
799 return; /* paranoia */
800 if (port
< 0 || port
>= PORTS_PER_ASIC
)
801 return; /* more paranoia */
803 devpriv
->asics
[asic
].pagelock
|= 0x1 << port
;
804 /* now write out the shadow register */
805 outb(devpriv
->asics
[asic
].pagelock
,
806 devpriv
->asics
[asic
].iobase
+ REG_PAGELOCK
);
810 static void unlock_port(struct comedi_device
*dev
, int asic
, int port
)
812 if (asic
< 0 || asic
>= thisboard
->dio_num_asics
)
813 return; /* paranoia */
814 if (port
< 0 || port
>= PORTS_PER_ASIC
)
815 return; /* more paranoia */
816 devpriv
->asics
[asic
].pagelock
&= ~(0x1 << port
) | REG_LOCK_MASK
;
817 /* now write out the shadow register */
818 outb(devpriv
->asics
[asic
].pagelock
,
819 devpriv
->asics
[asic
].iobase
+ REG_PAGELOCK
);
823 static irqreturn_t
interrupt_pcmmio(int irq
, void *d
)
826 struct comedi_device
*dev
= (struct comedi_device
*)d
;
828 for (asic
= 0; asic
< MAX_ASICS
; ++asic
) {
829 if (irq
== devpriv
->asics
[asic
].irq
) {
831 unsigned triggered
= 0;
832 unsigned long iobase
= devpriv
->asics
[asic
].iobase
;
833 /* it is an interrupt for ASIC #asic */
834 unsigned char int_pend
;
836 spin_lock_irqsave(&devpriv
->asics
[asic
].spinlock
,
839 int_pend
= inb(iobase
+ REG_INT_PENDING
) & 0x07;
843 for (port
= 0; port
< INTR_PORTS_PER_ASIC
;
845 if (int_pend
& (0x1 << port
)) {
847 io_lines_with_edges
= 0;
848 switch_page(dev
, asic
,
850 io_lines_with_edges
=
854 if (io_lines_with_edges
)
864 io_lines_with_edges
<<
872 spin_unlock_irqrestore(&devpriv
->asics
[asic
].spinlock
,
876 struct comedi_subdevice
*s
;
878 * TODO here: dispatch io lines to subdevs
882 ("PCMMIO DEBUG: got edge detect interrupt %d asic %d which_chans: %06x\n",
883 irq
, asic
, triggered
);
884 for (s
= dev
->subdevices
+ 2;
885 s
< dev
->subdevices
+ dev
->n_subdevices
;
888 * this is an interrupt subdev,
889 * and it matches this asic!
891 if (subpriv
->dio
.intr
.asic
== asic
) {
895 spin_lock_irqsave(&subpriv
->dio
.
899 oldevents
= s
->async
->events
;
901 if (subpriv
->dio
.intr
.active
) {
904 subpriv
->dio
.intr
.asic_chan
)
921 async
->cmd
.chanlist_len
;
925 ch
= CR_CHAN(s
->async
->cmd
.chanlist
[n
]);
926 if (mytrig
& (1U << ch
))
929 /* Write the scan to the buffer. */
930 if (comedi_buf_put(s
->async
, ((short *)&val
)[0])
936 s
->async
->events
|= (COMEDI_CB_BLOCK
| COMEDI_CB_EOS
);
938 /* Overflow! Stop acquisition!! */
939 /* TODO: STOP_ACQUISITION_CALL_HERE!! */
945 /* Check for end of acquisition. */
946 if (!subpriv
->dio
.intr
.continuous
) {
947 /* stop_src == TRIG_COUNT */
948 if (subpriv
->dio
.intr
.stop_count
> 0) {
949 subpriv
->dio
.intr
.stop_count
--;
950 if (subpriv
->dio
.intr
.stop_count
== 0) {
951 s
->async
->events
|= COMEDI_CB_EOA
;
952 /* TODO: STOP_ACQUISITION_CALL_HERE!! */
962 spin_unlock_irqrestore
968 comedi_event(dev
, s
);
979 return IRQ_NONE
; /* interrupt from other source */
983 static void pcmmio_stop_intr(struct comedi_device
*dev
,
984 struct comedi_subdevice
*s
)
986 int nports
, firstport
, asic
, port
;
988 asic
= subpriv
->dio
.intr
.asic
;
990 return; /* not an interrupt subdev */
992 subpriv
->dio
.intr
.enabled_mask
= 0;
993 subpriv
->dio
.intr
.active
= 0;
994 s
->async
->inttrig
= 0;
995 nports
= subpriv
->dio
.intr
.num_asic_chans
/ CHANS_PER_PORT
;
996 firstport
= subpriv
->dio
.intr
.asic_chan
/ CHANS_PER_PORT
;
997 switch_page(dev
, asic
, PAGE_ENAB
);
998 for (port
= firstport
; port
< firstport
+ nports
; ++port
) {
999 /* disable all intrs for this subdev.. */
1000 outb(0, devpriv
->asics
[asic
].iobase
+ REG_ENAB0
+ port
);
1004 static int pcmmio_start_intr(struct comedi_device
*dev
,
1005 struct comedi_subdevice
*s
)
1007 if (!subpriv
->dio
.intr
.continuous
&& subpriv
->dio
.intr
.stop_count
== 0) {
1008 /* An empty acquisition! */
1009 s
->async
->events
|= COMEDI_CB_EOA
;
1010 subpriv
->dio
.intr
.active
= 0;
1013 unsigned bits
= 0, pol_bits
= 0, n
;
1014 int nports
, firstport
, asic
, port
;
1015 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
1017 asic
= subpriv
->dio
.intr
.asic
;
1019 return 1; /* not an interrupt
1021 subpriv
->dio
.intr
.enabled_mask
= 0;
1022 subpriv
->dio
.intr
.active
= 1;
1023 nports
= subpriv
->dio
.intr
.num_asic_chans
/ CHANS_PER_PORT
;
1024 firstport
= subpriv
->dio
.intr
.asic_chan
/ CHANS_PER_PORT
;
1025 if (cmd
->chanlist
) {
1026 for (n
= 0; n
< cmd
->chanlist_len
; n
++) {
1027 bits
|= (1U << CR_CHAN(cmd
->chanlist
[n
]));
1028 pol_bits
|= (CR_AREF(cmd
->chanlist
[n
])
1030 chanlist
[n
]) ? 1U : 0U)
1031 << CR_CHAN(cmd
->chanlist
[n
]);
1034 bits
&= ((0x1 << subpriv
->dio
.intr
.num_asic_chans
) -
1035 1) << subpriv
->dio
.intr
.first_chan
;
1036 subpriv
->dio
.intr
.enabled_mask
= bits
;
1040 * the below code configures the board
1041 * to use a specific IRQ from 0-15.
1045 * set resource enable register
1046 * to enable IRQ operation
1048 outb(1 << 4, dev
->iobase
+ 3);
1049 /* set bits 0-3 of b to the irq number from 0-15 */
1050 b
= dev
->irq
& ((1 << 4) - 1);
1051 outb(b
, dev
->iobase
+ 2);
1052 /* done, we told the board what irq to use */
1055 switch_page(dev
, asic
, PAGE_ENAB
);
1056 for (port
= firstport
; port
< firstport
+ nports
; ++port
) {
1058 bits
>> (subpriv
->dio
.intr
.first_chan
+ (port
-
1061 pol_bits
>> (subpriv
->dio
.intr
.first_chan
+
1062 (port
- firstport
) * 8) & 0xff;
1063 /* set enab intrs for this subdev.. */
1065 devpriv
->asics
[asic
].iobase
+ REG_ENAB0
+ port
);
1066 switch_page(dev
, asic
, PAGE_POL
);
1068 devpriv
->asics
[asic
].iobase
+ REG_ENAB0
+ port
);
1074 static int pcmmio_cancel(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
1076 unsigned long flags
;
1078 spin_lock_irqsave(&subpriv
->dio
.intr
.spinlock
, flags
);
1079 if (subpriv
->dio
.intr
.active
)
1080 pcmmio_stop_intr(dev
, s
);
1081 spin_unlock_irqrestore(&subpriv
->dio
.intr
.spinlock
, flags
);
1087 * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
1090 pcmmio_inttrig_start_intr(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
1091 unsigned int trignum
)
1093 unsigned long flags
;
1099 spin_lock_irqsave(&subpriv
->dio
.intr
.spinlock
, flags
);
1100 s
->async
->inttrig
= 0;
1101 if (subpriv
->dio
.intr
.active
)
1102 event
= pcmmio_start_intr(dev
, s
);
1103 spin_unlock_irqrestore(&subpriv
->dio
.intr
.spinlock
, flags
);
1106 comedi_event(dev
, s
);
1112 * 'do_cmd' function for an 'INTERRUPT' subdevice.
1114 static int pcmmio_cmd(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
1116 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
1117 unsigned long flags
;
1120 spin_lock_irqsave(&subpriv
->dio
.intr
.spinlock
, flags
);
1121 subpriv
->dio
.intr
.active
= 1;
1123 /* Set up end of acquisition. */
1124 switch (cmd
->stop_src
) {
1126 subpriv
->dio
.intr
.continuous
= 0;
1127 subpriv
->dio
.intr
.stop_count
= cmd
->stop_arg
;
1131 subpriv
->dio
.intr
.continuous
= 1;
1132 subpriv
->dio
.intr
.stop_count
= 0;
1136 /* Set up start of acquisition. */
1137 switch (cmd
->start_src
) {
1139 s
->async
->inttrig
= pcmmio_inttrig_start_intr
;
1143 event
= pcmmio_start_intr(dev
, s
);
1146 spin_unlock_irqrestore(&subpriv
->dio
.intr
.spinlock
, flags
);
1149 comedi_event(dev
, s
);
1155 pcmmio_cmdtest(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
1156 struct comedi_cmd
*cmd
)
1158 return comedi_pcm_cmdtest(dev
, s
, cmd
);
1161 static int adc_wait_ready(unsigned long iobase
)
1163 unsigned long retry
= 100000;
1165 if (inb(iobase
+ 3) & 0x80)
1170 /* All this is for AI and AO */
1171 static int ai_rinsn(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
1172 struct comedi_insn
*insn
, unsigned int *data
)
1175 unsigned long iobase
= subpriv
->iobase
;
1178 1. write the CMD byte (to BASE+2)
1179 2. read junk lo byte (BASE+0)
1180 3. read junk hi byte (BASE+1)
1181 4. (mux settled so) write CMD byte again (BASE+2)
1182 5. read valid lo byte(BASE+0)
1183 6. read valid hi byte(BASE+1)
1185 Additionally note that the BASE += 4 if the channel >= 8
1188 /* convert n samples */
1189 for (n
= 0; n
< insn
->n
; n
++) {
1190 unsigned chan
= CR_CHAN(insn
->chanspec
), range
=
1191 CR_RANGE(insn
->chanspec
), aref
= CR_AREF(insn
->chanspec
);
1192 unsigned char command_byte
= 0;
1193 unsigned iooffset
= 0;
1194 short sample
, adc_adjust
= 0;
1197 chan
-= 8, iooffset
= 4; /*
1198 * use the second dword
1202 if (aref
!= AREF_DIFF
) {
1204 command_byte
|= 1 << 7; /*
1205 * set bit 7 to indicate
1210 adc_adjust
= 0x8000; /*
1212 * (-5,5 .. -10,10 need to be
1213 * adjusted -- that is.. they
1214 * need to wrap around by
1219 command_byte
|= 1 << 6; /*
1220 * odd-numbered channels
1225 /* select the channel, bits 4-5 == chan/2 */
1226 command_byte
|= ((chan
/ 2) & 0x3) << 4;
1228 /* set the range, bits 2-3 */
1229 command_byte
|= (range
& 0x3) << 2;
1231 /* need to do this twice to make sure mux settled */
1232 /* chan/range/aref select */
1233 outb(command_byte
, iobase
+ iooffset
+ 2);
1235 /* wait for the adc to say it finised the conversion */
1236 adc_wait_ready(iobase
+ iooffset
);
1238 /* select the chan/range/aref AGAIN */
1239 outb(command_byte
, iobase
+ iooffset
+ 2);
1241 adc_wait_ready(iobase
+ iooffset
);
1243 /* read data lo byte */
1244 sample
= inb(iobase
+ iooffset
+ 0);
1246 /* read data hi byte */
1247 sample
|= inb(iobase
+ iooffset
+ 1) << 8;
1248 sample
+= adc_adjust
; /* adjustment .. munge data */
1251 /* return the number of samples read/written */
1255 static int ao_rinsn(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
1256 struct comedi_insn
*insn
, unsigned int *data
)
1259 for (n
= 0; n
< insn
->n
; n
++) {
1260 unsigned chan
= CR_CHAN(insn
->chanspec
);
1261 if (chan
< s
->n_chan
)
1262 data
[n
] = subpriv
->ao
.shadow_samples
[chan
];
1267 static int wait_dac_ready(unsigned long iobase
)
1269 unsigned long retry
= 100000L;
1271 /* This may seem like an absurd way to handle waiting and violates the
1272 "no busy waiting" policy. The fact is that the hardware is
1273 normally so fast that we usually only need one time through the loop
1274 anyway. The longer timeout is for rare occasions and for detecting
1275 non-existant hardware. */
1278 if (inb(iobase
+ 3) & 0x80)
1285 static int ao_winsn(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
1286 struct comedi_insn
*insn
, unsigned int *data
)
1289 unsigned iobase
= subpriv
->iobase
, iooffset
= 0;
1291 for (n
= 0; n
< insn
->n
; n
++) {
1292 unsigned chan
= CR_CHAN(insn
->chanspec
), range
=
1293 CR_RANGE(insn
->chanspec
);
1294 if (chan
< s
->n_chan
) {
1295 unsigned char command_byte
= 0, range_byte
=
1296 range
& ((1 << 4) - 1);
1298 chan
-= 4, iooffset
+= 4;
1299 /* set the range.. */
1300 outb(range_byte
, iobase
+ iooffset
+ 0);
1301 outb(0, iobase
+ iooffset
+ 1);
1303 /* tell it to begin */
1304 command_byte
= (chan
<< 1) | 0x60;
1305 outb(command_byte
, iobase
+ iooffset
+ 2);
1307 wait_dac_ready(iobase
+ iooffset
);
1309 /* low order byte */
1310 outb(data
[n
] & 0xff, iobase
+ iooffset
+ 0);
1312 /* high order byte */
1313 outb((data
[n
] >> 8) & 0xff, iobase
+ iooffset
+ 1);
1316 * set bit 4 of command byte to indicate
1317 * data is loaded and trigger conversion
1319 command_byte
= 0x70 | (chan
<< 1);
1320 /* trigger converion */
1321 outb(command_byte
, iobase
+ iooffset
+ 2);
1323 wait_dac_ready(iobase
+ iooffset
);
1325 /* save to shadow register for ao_rinsn */
1326 subpriv
->ao
.shadow_samples
[chan
] = data
[n
];
1333 * A convenient macro that defines init_module() and cleanup_module(),
1336 COMEDI_INITCLEANUP(driver
);