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 static int ai_rinsn(struct comedi_device
*, struct comedi_subdevice
*,
149 struct comedi_insn
*, unsigned int *);
150 static int ao_rinsn(struct comedi_device
*, struct comedi_subdevice
*,
151 struct comedi_insn
*, unsigned int *);
152 static int ao_winsn(struct comedi_device
*, struct comedi_subdevice
*,
153 struct comedi_insn
*, unsigned int *);
156 * Board descriptions for two imaginary boards. Describing the
157 * boards in this way is optional, and completely driver-dependent.
158 * Some drivers use arrays such as this, other do not.
160 struct pcmmio_board
{
162 const int dio_num_asics
;
163 const int dio_num_ports
;
164 const int total_iosize
;
167 const int n_ai_chans
;
168 const int n_ao_chans
;
169 const struct comedi_lrange
*ai_range_table
, *ao_range_table
;
170 int (*ai_rinsn
) (struct comedi_device
*dev
,
171 struct comedi_subdevice
*s
,
172 struct comedi_insn
*insn
,
174 int (*ao_rinsn
) (struct comedi_device
*dev
,
175 struct comedi_subdevice
*s
,
176 struct comedi_insn
*insn
,
178 int (*ao_winsn
) (struct comedi_device
*dev
,
179 struct comedi_subdevice
*s
,
180 struct comedi_insn
*insn
,
184 static const struct comedi_lrange ranges_ai
= {
185 4, {RANGE(-5., 5.), RANGE(-10., 10.), RANGE(0., 5.), RANGE(0., 10.)}
188 static const struct comedi_lrange ranges_ao
= {
189 6, {RANGE(0., 5.), RANGE(0., 10.), RANGE(-5., 5.), RANGE(-10., 10.),
190 RANGE(-2.5, 2.5), RANGE(-2.5, 7.5)}
193 static const struct pcmmio_board pcmmio_boards
[] = {
203 .ai_range_table
= &ranges_ai
,
204 .ao_range_table
= &ranges_ao
,
205 .ai_rinsn
= ai_rinsn
,
206 .ao_rinsn
= ao_rinsn
,
207 .ao_winsn
= ao_winsn
},
211 * Useful for shorthand access to the particular board structure
213 #define thisboard ((const struct pcmmio_board *)dev->board_ptr)
215 /* this structure is for data unique to this subdevice. */
216 struct pcmmio_subdev_private
{
219 /* for DIO: mapping of halfwords (bytes)
220 in port/chanarray to iobase */
221 unsigned long iobases
[PORTS_PER_SUBDEV
];
224 unsigned long iobase
;
229 /* The below is only used for intr subdevices */
232 * if non-negative, this subdev has an
237 * if nonnegative, the first channel id for
242 * the number of asic channels in this subdev
243 * that have interrutps
247 * if nonnegative, the first channel id with
248 * respect to the asic that has interrupts
252 * subdev-relative channel mask for channels
253 * we are interested in
263 /* the last unsigned int data written */
264 unsigned int shadow_samples
[8];
270 * this structure is for data unique to this hardware driver. If
271 * several hardware drivers keep similar information in this structure,
272 * feel free to suggest moving the variable to the struct comedi_device struct.
274 struct pcmmio_private
{
277 unsigned char pagelock
; /* current page and lock */
278 /* shadow of POLx registers */
279 unsigned char pol
[NUM_PAGED_REGS
];
280 /* shadow of ENABx registers */
281 unsigned char enab
[NUM_PAGED_REGS
];
283 unsigned long iobase
;
287 struct pcmmio_subdev_private
*sprivs
;
291 * most drivers define the following macro to make it easy to
292 * access the private structure.
294 #define devpriv ((struct pcmmio_private *)dev->private)
295 #define subpriv ((struct pcmmio_subdev_private *)s->private)
297 * The struct comedi_driver structure tells the Comedi core module
298 * which functions to call to configure/deconfigure (attach/detach)
299 * the board, and also about the kernel module that contains
302 static int pcmmio_attach(struct comedi_device
*dev
,
303 struct comedi_devconfig
*it
);
304 static int pcmmio_detach(struct comedi_device
*dev
);
306 static struct comedi_driver driver
= {
307 .driver_name
= "pcmmio",
308 .module
= THIS_MODULE
,
309 .attach
= pcmmio_attach
,
310 .detach
= pcmmio_detach
,
311 /* It is not necessary to implement the following members if you are
312 * writing a driver for a ISA PnP or PCI card */
313 /* Most drivers will support multiple types of boards by
314 * having an array of board structures. These were defined
315 * in pcmmio_boards[] above. Note that the element 'name'
316 * was first in the structure -- Comedi uses this fact to
317 * extract the name of the board without knowing any details
318 * about the structure except for its length.
319 * When a device is attached (by comedi_config), the name
320 * of the device is given to Comedi, and Comedi tries to
321 * match it by going through the list of board names. If
322 * there is a match, the address of the pointer is put
323 * into dev->board_ptr and driver->attach() is called.
325 * Note that these are not necessary if you can determine
326 * the type of board in software. ISA PnP, PCI, and PCMCIA
327 * devices are such boards.
329 .board_name
= &pcmmio_boards
[0].name
,
330 .offset
= sizeof(struct pcmmio_board
),
331 .num_names
= ARRAY_SIZE(pcmmio_boards
),
334 static int pcmmio_dio_insn_bits(struct comedi_device
*dev
,
335 struct comedi_subdevice
*s
,
336 struct comedi_insn
*insn
, unsigned int *data
);
337 static int pcmmio_dio_insn_config(struct comedi_device
*dev
,
338 struct comedi_subdevice
*s
,
339 struct comedi_insn
*insn
, unsigned int *data
);
341 static irqreturn_t
interrupt_pcmmio(int irq
, void *d
);
342 static void pcmmio_stop_intr(struct comedi_device
*, struct comedi_subdevice
*);
343 static int pcmmio_cancel(struct comedi_device
*dev
, struct comedi_subdevice
*s
);
344 static int pcmmio_cmd(struct comedi_device
*dev
, struct comedi_subdevice
*s
);
345 static int pcmmio_cmdtest(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
346 struct comedi_cmd
*cmd
);
348 /* some helper functions to deal with specifics of this device's registers */
349 /* sets up/clears ASIC chips to defaults */
350 static void init_asics(struct comedi_device
*dev
);
351 static void switch_page(struct comedi_device
*dev
, int asic
, int page
);
353 static void lock_port(struct comedi_device
*dev
, int asic
, int port
);
354 static void unlock_port(struct comedi_device
*dev
, int asic
, int port
);
358 * Attach is called by the Comedi core to configure the driver
359 * for a particular board. If you specified a board_name array
360 * in the driver structure, dev->board_ptr contains that
363 static int pcmmio_attach(struct comedi_device
*dev
, struct comedi_devconfig
*it
)
365 struct comedi_subdevice
*s
;
366 int sdev_no
, chans_left
, n_dio_subdevs
, n_subdevs
, port
, asic
,
368 unsigned long iobase
;
369 unsigned int irq
[MAX_ASICS
];
371 iobase
= it
->options
[0];
372 irq
[0] = it
->options
[1];
374 printk("comedi%d: %s: io: %lx ", dev
->minor
, driver
.driver_name
,
377 dev
->iobase
= iobase
;
379 if (!iobase
|| !request_region(iobase
,
380 thisboard
->total_iosize
,
381 driver
.driver_name
)) {
382 printk("I/O port conflict\n");
387 * Initialize dev->board_name. Note that we can use the "thisboard"
388 * macro now, since we just initialized it in the last line.
390 dev
->board_name
= thisboard
->name
;
393 * Allocate the private structure area. alloc_private() is a
394 * convenient macro defined in comedidev.h.
396 if (alloc_private(dev
, sizeof(struct pcmmio_private
)) < 0) {
397 printk("cannot allocate private data structure\n");
401 for (asic
= 0; asic
< MAX_ASICS
; ++asic
) {
402 devpriv
->asics
[asic
].num
= asic
;
403 devpriv
->asics
[asic
].iobase
=
404 dev
->iobase
+ 16 + asic
* ASIC_IOSIZE
;
406 * this gets actually set at the end of this function when we
409 devpriv
->asics
[asic
].irq
= 0;
410 spin_lock_init(&devpriv
->asics
[asic
].spinlock
);
413 chans_left
= CHANS_PER_ASIC
* thisboard
->dio_num_asics
;
414 n_dio_subdevs
= CALC_N_DIO_SUBDEVS(chans_left
);
415 n_subdevs
= n_dio_subdevs
+ 2;
417 kcalloc(n_subdevs
, sizeof(struct pcmmio_subdev_private
),
419 if (!devpriv
->sprivs
) {
420 printk("cannot allocate subdevice private data structures\n");
424 * Allocate the subdevice structures. alloc_subdevice() is a
425 * convenient macro defined in comedidev.h.
427 * Allocate 1 AI + 1 AO + 2 DIO subdevs (24 lines per DIO)
429 if (alloc_subdevices(dev
, n_subdevs
) < 0) {
430 printk("cannot allocate subdevice data structures\n");
436 s
= dev
->subdevices
+ sdev_no
;
437 s
->private = devpriv
->sprivs
+ sdev_no
;
438 s
->maxdata
= (1 << thisboard
->ai_bits
) - 1;
439 s
->range_table
= thisboard
->ai_range_table
;
440 s
->subdev_flags
= SDF_READABLE
| SDF_GROUND
| SDF_DIFF
;
441 s
->type
= COMEDI_SUBD_AI
;
442 s
->n_chan
= thisboard
->n_ai_chans
;
443 s
->len_chanlist
= s
->n_chan
;
444 s
->insn_read
= thisboard
->ai_rinsn
;
445 subpriv
->iobase
= dev
->iobase
+ 0;
446 /* initialize the resource enable register by clearing it */
447 outb(0, subpriv
->iobase
+ 3);
448 outb(0, subpriv
->iobase
+ 4 + 3);
452 s
= dev
->subdevices
+ sdev_no
;
453 s
->private = devpriv
->sprivs
+ sdev_no
;
454 s
->maxdata
= (1 << thisboard
->ao_bits
) - 1;
455 s
->range_table
= thisboard
->ao_range_table
;
456 s
->subdev_flags
= SDF_READABLE
;
457 s
->type
= COMEDI_SUBD_AO
;
458 s
->n_chan
= thisboard
->n_ao_chans
;
459 s
->len_chanlist
= s
->n_chan
;
460 s
->insn_read
= thisboard
->ao_rinsn
;
461 s
->insn_write
= thisboard
->ao_winsn
;
462 subpriv
->iobase
= dev
->iobase
+ 8;
463 /* initialize the resource enable register by clearing it */
464 outb(0, subpriv
->iobase
+ 3);
465 outb(0, subpriv
->iobase
+ 4 + 3);
470 for (; sdev_no
< (int)dev
->n_subdevices
; ++sdev_no
) {
473 s
= dev
->subdevices
+ sdev_no
;
474 s
->private = devpriv
->sprivs
+ sdev_no
;
476 s
->range_table
= &range_digital
;
477 s
->subdev_flags
= SDF_READABLE
| SDF_WRITABLE
;
478 s
->type
= COMEDI_SUBD_DIO
;
479 s
->insn_bits
= pcmmio_dio_insn_bits
;
480 s
->insn_config
= pcmmio_dio_insn_config
;
481 s
->n_chan
= min(chans_left
, MAX_CHANS_PER_SUBDEV
);
482 subpriv
->dio
.intr
.asic
= -1;
483 subpriv
->dio
.intr
.first_chan
= -1;
484 subpriv
->dio
.intr
.asic_chan
= -1;
485 subpriv
->dio
.intr
.num_asic_chans
= -1;
486 subpriv
->dio
.intr
.active
= 0;
489 /* save the ioport address for each 'port' of 8 channels in the
491 for (byte_no
= 0; byte_no
< PORTS_PER_SUBDEV
; ++byte_no
, ++port
) {
492 if (port
>= PORTS_PER_ASIC
) {
497 subpriv
->iobases
[byte_no
] =
498 devpriv
->asics
[asic
].iobase
+ port
;
500 if (thisasic_chanct
<
501 CHANS_PER_PORT
* INTR_PORTS_PER_ASIC
502 && subpriv
->dio
.intr
.asic
< 0) {
504 * this is an interrupt subdevice,
505 * so setup the struct
507 subpriv
->dio
.intr
.asic
= asic
;
508 subpriv
->dio
.intr
.active
= 0;
509 subpriv
->dio
.intr
.stop_count
= 0;
510 subpriv
->dio
.intr
.first_chan
= byte_no
* 8;
511 subpriv
->dio
.intr
.asic_chan
= thisasic_chanct
;
512 subpriv
->dio
.intr
.num_asic_chans
=
513 s
->n_chan
- subpriv
->dio
.intr
.first_chan
;
514 s
->cancel
= pcmmio_cancel
;
515 s
->do_cmd
= pcmmio_cmd
;
516 s
->do_cmdtest
= pcmmio_cmdtest
;
518 subpriv
->dio
.intr
.num_asic_chans
;
520 thisasic_chanct
+= CHANS_PER_PORT
;
522 spin_lock_init(&subpriv
->dio
.intr
.spinlock
);
524 chans_left
-= s
->n_chan
;
528 * reset the asic to our first asic,
537 init_asics(dev
); /* clear out all the registers, basically */
539 for (asic
= 0; irq
[0] && asic
< MAX_ASICS
; ++asic
) {
541 && request_irq(irq
[asic
], interrupt_pcmmio
,
542 IRQF_SHARED
, thisboard
->name
, dev
)) {
544 /* unroll the allocated irqs.. */
545 for (i
= asic
- 1; i
>= 0; --i
) {
546 free_irq(irq
[i
], dev
);
547 devpriv
->asics
[i
].irq
= irq
[i
] = 0;
551 devpriv
->asics
[asic
].irq
= irq
[asic
];
554 dev
->irq
= irq
[0]; /*
555 * grr.. wish comedi dev struct supported
560 printk("irq: %u ", irq
[0]);
561 if (thisboard
->dio_num_asics
== 2 && irq
[1])
562 printk("second ASIC irq: %u ", irq
[1]);
564 printk("(IRQ mode disabled) ");
567 printk("attached\n");
573 * _detach is called to deconfigure a device. It should deallocate
575 * This function is also called when _attach() fails, so it should be
576 * careful not to release resources that were not necessarily
577 * allocated by _attach(). dev->private and dev->subdevices are
578 * deallocated automatically by the core.
580 static int pcmmio_detach(struct comedi_device
*dev
)
584 printk("comedi%d: %s: remove\n", dev
->minor
, driver
.driver_name
);
586 release_region(dev
->iobase
, thisboard
->total_iosize
);
588 for (i
= 0; i
< MAX_ASICS
; ++i
) {
589 if (devpriv
&& devpriv
->asics
[i
].irq
)
590 free_irq(devpriv
->asics
[i
].irq
, dev
);
593 if (devpriv
&& devpriv
->sprivs
)
594 kfree(devpriv
->sprivs
);
599 /* DIO devices are slightly special. Although it is possible to
600 * implement the insn_read/insn_write interface, it is much more
601 * useful to applications if you implement the insn_bits interface.
602 * This allows packed reading/writing of the DIO channels. The
603 * comedi core can convert between insn_bits and insn_read/write */
604 static int pcmmio_dio_insn_bits(struct comedi_device
*dev
,
605 struct comedi_subdevice
*s
,
606 struct comedi_insn
*insn
, unsigned int *data
)
613 reading a 0 means this channel was high
614 writine a 0 sets the channel high
615 reading a 1 means this channel was low
616 writing a 1 means set this channel low
618 Therefore everything is always inverted. */
620 /* The insn data is a mask in data[0] and the new data
621 * in data[1], each channel cooresponding to a bit. */
623 #ifdef DAMMIT_ITS_BROKEN
625 printk("write mask: %08x data: %08x\n", data
[0], data
[1]);
630 for (byte_no
= 0; byte_no
< s
->n_chan
/ CHANS_PER_PORT
; ++byte_no
) {
631 /* address of 8-bit port */
632 unsigned long ioaddr
= subpriv
->iobases
[byte_no
],
633 /* bit offset of port in 32-bit doubleword */
634 offset
= byte_no
* 8;
635 /* this 8-bit port's data */
636 unsigned char byte
= 0,
637 /* The write mask for this port (if any) */
638 write_mask_byte
= (data
[0] >> offset
) & 0xff,
639 /* The data byte for this port */
640 data_byte
= (data
[1] >> offset
) & 0xff;
642 byte
= inb(ioaddr
); /* read all 8-bits for this port */
644 #ifdef DAMMIT_ITS_BROKEN
647 ("byte %d wmb %02x db %02x offset %02d io %04x, data_in %02x ",
648 byte_no
, (unsigned)write_mask_byte
, (unsigned)data_byte
,
649 offset
, ioaddr
, (unsigned)byte
);
652 if (write_mask_byte
) {
654 * this byte has some write_bits
655 * -- so set the output lines
657 /* clear bits for write mask */
658 byte
&= ~write_mask_byte
;
659 /* set to inverted data_byte */
660 byte
|= ~data_byte
& write_mask_byte
;
661 /* Write out the new digital output state */
664 #ifdef DAMMIT_ITS_BROKEN
666 printk("data_out_byte %02x\n", (unsigned)byte
);
668 /* save the digital input lines for this byte.. */
669 s
->state
|= ((unsigned int)byte
) << offset
;
672 /* now return the DIO lines to data[1] - note they came inverted! */
675 #ifdef DAMMIT_ITS_BROKEN
677 printk("s->state %08x data_out %08x\n", s
->state
, data
[1]);
683 /* The input or output configuration of each digital line is
684 * configured by a special insn_config instruction. chanspec
685 * contains the channel to be changed, and data[0] contains the
686 * value COMEDI_INPUT or COMEDI_OUTPUT. */
687 static int pcmmio_dio_insn_config(struct comedi_device
*dev
,
688 struct comedi_subdevice
*s
,
689 struct comedi_insn
*insn
, unsigned int *data
)
691 int chan
= CR_CHAN(insn
->chanspec
), byte_no
= chan
/ 8, bit_no
=
693 unsigned long ioaddr
;
696 /* Compute ioaddr for this channel */
697 ioaddr
= subpriv
->iobases
[byte_no
];
700 writing a 0 an IO channel's bit sets the channel to INPUT
701 and pulls the line high as well
703 writing a 1 to an IO channel's bit pulls the line low
705 All channels are implicitly always in OUTPUT mode -- but when
706 they are high they can be considered to be in INPUT mode..
708 Thus, we only force channels low if the config request was INPUT,
709 otherwise we do nothing to the hardware. */
712 case INSN_CONFIG_DIO_OUTPUT
:
713 /* save to io_bits -- don't actually do anything since
714 all input channels are also output channels... */
715 s
->io_bits
|= 1 << chan
;
717 case INSN_CONFIG_DIO_INPUT
:
718 /* write a 0 to the actual register representing the channel
719 to set it to 'input'. 0 means "float high". */
721 byte
&= ~(1 << bit_no
);
722 /**< set input channel to '0' */
725 * write out byte -- this is the only time we actually affect
726 * the hardware as all channels are implicitly output
727 * -- but input channels are set to float-high
731 /* save to io_bits */
732 s
->io_bits
&= ~(1 << chan
);
735 case INSN_CONFIG_DIO_QUERY
:
736 /* retrieve from shadow register */
738 (s
->io_bits
& (1 << chan
)) ? COMEDI_OUTPUT
: COMEDI_INPUT
;
750 static void init_asics(struct comedi_device
*dev
)
752 ASIC chip to defaults */
755 for (asic
= 0; asic
< thisboard
->dio_num_asics
; ++asic
) {
757 unsigned long baseaddr
= devpriv
->asics
[asic
].iobase
;
759 switch_page(dev
, asic
, 0); /* switch back to page 0 */
761 /* first, clear all the DIO port bits */
762 for (port
= 0; port
< PORTS_PER_ASIC
; ++port
)
763 outb(0, baseaddr
+ REG_PORT0
+ port
);
765 /* Next, clear all the paged registers for each page */
766 for (page
= 1; page
< NUM_PAGES
; ++page
) {
768 /* now clear all the paged registers */
769 switch_page(dev
, asic
, page
);
770 for (reg
= FIRST_PAGED_REG
;
771 reg
< FIRST_PAGED_REG
+ NUM_PAGED_REGS
; ++reg
)
772 outb(0, baseaddr
+ reg
);
775 /* DEBUG set rising edge interrupts on port0 of both asics */
776 /*switch_page(dev, asic, PAGE_POL);
777 outb(0xff, baseaddr + REG_POL0);
778 switch_page(dev, asic, PAGE_ENAB);
779 outb(0xff, baseaddr + REG_ENAB0); */
782 /* switch back to default page 0 */
783 switch_page(dev
, asic
, 0);
787 static void switch_page(struct comedi_device
*dev
, int asic
, int page
)
789 if (asic
< 0 || asic
>= thisboard
->dio_num_asics
)
790 return; /* paranoia */
791 if (page
< 0 || page
>= NUM_PAGES
)
792 return; /* more paranoia */
794 devpriv
->asics
[asic
].pagelock
&= ~REG_PAGE_MASK
;
795 devpriv
->asics
[asic
].pagelock
|= page
<< REG_PAGE_BITOFFSET
;
797 /* now write out the shadow register */
798 outb(devpriv
->asics
[asic
].pagelock
,
799 devpriv
->asics
[asic
].iobase
+ REG_PAGELOCK
);
803 static void lock_port(struct comedi_device
*dev
, int asic
, int port
)
805 if (asic
< 0 || asic
>= thisboard
->dio_num_asics
)
806 return; /* paranoia */
807 if (port
< 0 || port
>= PORTS_PER_ASIC
)
808 return; /* more paranoia */
810 devpriv
->asics
[asic
].pagelock
|= 0x1 << port
;
811 /* now write out the shadow register */
812 outb(devpriv
->asics
[asic
].pagelock
,
813 devpriv
->asics
[asic
].iobase
+ REG_PAGELOCK
);
817 static void unlock_port(struct comedi_device
*dev
, int asic
, int port
)
819 if (asic
< 0 || asic
>= thisboard
->dio_num_asics
)
820 return; /* paranoia */
821 if (port
< 0 || port
>= PORTS_PER_ASIC
)
822 return; /* more paranoia */
823 devpriv
->asics
[asic
].pagelock
&= ~(0x1 << port
) | REG_LOCK_MASK
;
824 /* now write out the shadow register */
825 outb(devpriv
->asics
[asic
].pagelock
,
826 devpriv
->asics
[asic
].iobase
+ REG_PAGELOCK
);
830 static irqreturn_t
interrupt_pcmmio(int irq
, void *d
)
833 struct comedi_device
*dev
= (struct comedi_device
*)d
;
835 for (asic
= 0; asic
< MAX_ASICS
; ++asic
) {
836 if (irq
== devpriv
->asics
[asic
].irq
) {
838 unsigned triggered
= 0;
839 unsigned long iobase
= devpriv
->asics
[asic
].iobase
;
840 /* it is an interrupt for ASIC #asic */
841 unsigned char int_pend
;
843 spin_lock_irqsave(&devpriv
->asics
[asic
].spinlock
,
846 int_pend
= inb(iobase
+ REG_INT_PENDING
) & 0x07;
850 for (port
= 0; port
< INTR_PORTS_PER_ASIC
;
852 if (int_pend
& (0x1 << port
)) {
854 io_lines_with_edges
= 0;
855 switch_page(dev
, asic
,
857 io_lines_with_edges
=
861 if (io_lines_with_edges
)
871 io_lines_with_edges
<<
879 spin_unlock_irqrestore(&devpriv
->asics
[asic
].spinlock
,
883 struct comedi_subdevice
*s
;
885 * TODO here: dispatch io lines to subdevs
889 ("PCMMIO DEBUG: got edge detect interrupt %d asic %d which_chans: %06x\n",
890 irq
, asic
, triggered
);
891 for (s
= dev
->subdevices
+ 2;
892 s
< dev
->subdevices
+ dev
->n_subdevices
;
895 * this is an interrupt subdev,
896 * and it matches this asic!
898 if (subpriv
->dio
.intr
.asic
== asic
) {
902 spin_lock_irqsave(&subpriv
->dio
.
906 oldevents
= s
->async
->events
;
908 if (subpriv
->dio
.intr
.active
) {
911 subpriv
->dio
.intr
.asic_chan
)
928 async
->cmd
.chanlist_len
;
932 ch
= CR_CHAN(s
->async
->cmd
.chanlist
[n
]);
933 if (mytrig
& (1U << ch
))
936 /* Write the scan to the buffer. */
937 if (comedi_buf_put(s
->async
, ((short *)&val
)[0])
943 s
->async
->events
|= (COMEDI_CB_BLOCK
| COMEDI_CB_EOS
);
945 /* Overflow! Stop acquisition!! */
946 /* TODO: STOP_ACQUISITION_CALL_HERE!! */
952 /* Check for end of acquisition. */
953 if (!subpriv
->dio
.intr
.continuous
) {
954 /* stop_src == TRIG_COUNT */
955 if (subpriv
->dio
.intr
.stop_count
> 0) {
956 subpriv
->dio
.intr
.stop_count
--;
957 if (subpriv
->dio
.intr
.stop_count
== 0) {
958 s
->async
->events
|= COMEDI_CB_EOA
;
959 /* TODO: STOP_ACQUISITION_CALL_HERE!! */
969 spin_unlock_irqrestore
975 comedi_event(dev
, s
);
986 return IRQ_NONE
; /* interrupt from other source */
990 static void pcmmio_stop_intr(struct comedi_device
*dev
,
991 struct comedi_subdevice
*s
)
993 int nports
, firstport
, asic
, port
;
995 asic
= subpriv
->dio
.intr
.asic
;
997 return; /* not an interrupt subdev */
999 subpriv
->dio
.intr
.enabled_mask
= 0;
1000 subpriv
->dio
.intr
.active
= 0;
1001 s
->async
->inttrig
= 0;
1002 nports
= subpriv
->dio
.intr
.num_asic_chans
/ CHANS_PER_PORT
;
1003 firstport
= subpriv
->dio
.intr
.asic_chan
/ CHANS_PER_PORT
;
1004 switch_page(dev
, asic
, PAGE_ENAB
);
1005 for (port
= firstport
; port
< firstport
+ nports
; ++port
) {
1006 /* disable all intrs for this subdev.. */
1007 outb(0, devpriv
->asics
[asic
].iobase
+ REG_ENAB0
+ port
);
1011 static int pcmmio_start_intr(struct comedi_device
*dev
,
1012 struct comedi_subdevice
*s
)
1014 if (!subpriv
->dio
.intr
.continuous
&& subpriv
->dio
.intr
.stop_count
== 0) {
1015 /* An empty acquisition! */
1016 s
->async
->events
|= COMEDI_CB_EOA
;
1017 subpriv
->dio
.intr
.active
= 0;
1020 unsigned bits
= 0, pol_bits
= 0, n
;
1021 int nports
, firstport
, asic
, port
;
1022 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
1024 asic
= subpriv
->dio
.intr
.asic
;
1026 return 1; /* not an interrupt
1028 subpriv
->dio
.intr
.enabled_mask
= 0;
1029 subpriv
->dio
.intr
.active
= 1;
1030 nports
= subpriv
->dio
.intr
.num_asic_chans
/ CHANS_PER_PORT
;
1031 firstport
= subpriv
->dio
.intr
.asic_chan
/ CHANS_PER_PORT
;
1032 if (cmd
->chanlist
) {
1033 for (n
= 0; n
< cmd
->chanlist_len
; n
++) {
1034 bits
|= (1U << CR_CHAN(cmd
->chanlist
[n
]));
1035 pol_bits
|= (CR_AREF(cmd
->chanlist
[n
])
1037 chanlist
[n
]) ? 1U : 0U)
1038 << CR_CHAN(cmd
->chanlist
[n
]);
1041 bits
&= ((0x1 << subpriv
->dio
.intr
.num_asic_chans
) -
1042 1) << subpriv
->dio
.intr
.first_chan
;
1043 subpriv
->dio
.intr
.enabled_mask
= bits
;
1047 * the below code configures the board
1048 * to use a specific IRQ from 0-15.
1052 * set resource enable register
1053 * to enable IRQ operation
1055 outb(1 << 4, dev
->iobase
+ 3);
1056 /* set bits 0-3 of b to the irq number from 0-15 */
1057 b
= dev
->irq
& ((1 << 4) - 1);
1058 outb(b
, dev
->iobase
+ 2);
1059 /* done, we told the board what irq to use */
1062 switch_page(dev
, asic
, PAGE_ENAB
);
1063 for (port
= firstport
; port
< firstport
+ nports
; ++port
) {
1065 bits
>> (subpriv
->dio
.intr
.first_chan
+ (port
-
1068 pol_bits
>> (subpriv
->dio
.intr
.first_chan
+
1069 (port
- firstport
) * 8) & 0xff;
1070 /* set enab intrs for this subdev.. */
1072 devpriv
->asics
[asic
].iobase
+ REG_ENAB0
+ port
);
1073 switch_page(dev
, asic
, PAGE_POL
);
1075 devpriv
->asics
[asic
].iobase
+ REG_ENAB0
+ port
);
1081 static int pcmmio_cancel(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
1083 unsigned long flags
;
1085 spin_lock_irqsave(&subpriv
->dio
.intr
.spinlock
, flags
);
1086 if (subpriv
->dio
.intr
.active
)
1087 pcmmio_stop_intr(dev
, s
);
1088 spin_unlock_irqrestore(&subpriv
->dio
.intr
.spinlock
, flags
);
1094 * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
1097 pcmmio_inttrig_start_intr(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
1098 unsigned int trignum
)
1100 unsigned long flags
;
1106 spin_lock_irqsave(&subpriv
->dio
.intr
.spinlock
, flags
);
1107 s
->async
->inttrig
= 0;
1108 if (subpriv
->dio
.intr
.active
)
1109 event
= pcmmio_start_intr(dev
, s
);
1110 spin_unlock_irqrestore(&subpriv
->dio
.intr
.spinlock
, flags
);
1113 comedi_event(dev
, s
);
1119 * 'do_cmd' function for an 'INTERRUPT' subdevice.
1121 static int pcmmio_cmd(struct comedi_device
*dev
, struct comedi_subdevice
*s
)
1123 struct comedi_cmd
*cmd
= &s
->async
->cmd
;
1124 unsigned long flags
;
1127 spin_lock_irqsave(&subpriv
->dio
.intr
.spinlock
, flags
);
1128 subpriv
->dio
.intr
.active
= 1;
1130 /* Set up end of acquisition. */
1131 switch (cmd
->stop_src
) {
1133 subpriv
->dio
.intr
.continuous
= 0;
1134 subpriv
->dio
.intr
.stop_count
= cmd
->stop_arg
;
1138 subpriv
->dio
.intr
.continuous
= 1;
1139 subpriv
->dio
.intr
.stop_count
= 0;
1143 /* Set up start of acquisition. */
1144 switch (cmd
->start_src
) {
1146 s
->async
->inttrig
= pcmmio_inttrig_start_intr
;
1150 event
= pcmmio_start_intr(dev
, s
);
1153 spin_unlock_irqrestore(&subpriv
->dio
.intr
.spinlock
, flags
);
1156 comedi_event(dev
, s
);
1162 pcmmio_cmdtest(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
1163 struct comedi_cmd
*cmd
)
1165 return comedi_pcm_cmdtest(dev
, s
, cmd
);
1168 static int adc_wait_ready(unsigned long iobase
)
1170 unsigned long retry
= 100000;
1172 if (inb(iobase
+ 3) & 0x80)
1177 /* All this is for AI and AO */
1178 static int ai_rinsn(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
1179 struct comedi_insn
*insn
, unsigned int *data
)
1182 unsigned long iobase
= subpriv
->iobase
;
1185 1. write the CMD byte (to BASE+2)
1186 2. read junk lo byte (BASE+0)
1187 3. read junk hi byte (BASE+1)
1188 4. (mux settled so) write CMD byte again (BASE+2)
1189 5. read valid lo byte(BASE+0)
1190 6. read valid hi byte(BASE+1)
1192 Additionally note that the BASE += 4 if the channel >= 8
1195 /* convert n samples */
1196 for (n
= 0; n
< insn
->n
; n
++) {
1197 unsigned chan
= CR_CHAN(insn
->chanspec
), range
=
1198 CR_RANGE(insn
->chanspec
), aref
= CR_AREF(insn
->chanspec
);
1199 unsigned char command_byte
= 0;
1200 unsigned iooffset
= 0;
1201 short sample
, adc_adjust
= 0;
1204 chan
-= 8, iooffset
= 4; /*
1205 * use the second dword
1209 if (aref
!= AREF_DIFF
) {
1211 command_byte
|= 1 << 7; /*
1212 * set bit 7 to indicate
1217 adc_adjust
= 0x8000; /*
1219 * (-5,5 .. -10,10 need to be
1220 * adjusted -- that is.. they
1221 * need to wrap around by
1226 command_byte
|= 1 << 6; /*
1227 * odd-numbered channels
1232 /* select the channel, bits 4-5 == chan/2 */
1233 command_byte
|= ((chan
/ 2) & 0x3) << 4;
1235 /* set the range, bits 2-3 */
1236 command_byte
|= (range
& 0x3) << 2;
1238 /* need to do this twice to make sure mux settled */
1239 /* chan/range/aref select */
1240 outb(command_byte
, iobase
+ iooffset
+ 2);
1242 /* wait for the adc to say it finised the conversion */
1243 adc_wait_ready(iobase
+ iooffset
);
1245 /* select the chan/range/aref AGAIN */
1246 outb(command_byte
, iobase
+ iooffset
+ 2);
1248 adc_wait_ready(iobase
+ iooffset
);
1250 /* read data lo byte */
1251 sample
= inb(iobase
+ iooffset
+ 0);
1253 /* read data hi byte */
1254 sample
|= inb(iobase
+ iooffset
+ 1) << 8;
1255 sample
+= adc_adjust
; /* adjustment .. munge data */
1258 /* return the number of samples read/written */
1262 static int ao_rinsn(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
1263 struct comedi_insn
*insn
, unsigned int *data
)
1266 for (n
= 0; n
< insn
->n
; n
++) {
1267 unsigned chan
= CR_CHAN(insn
->chanspec
);
1268 if (chan
< s
->n_chan
)
1269 data
[n
] = subpriv
->ao
.shadow_samples
[chan
];
1274 static int wait_dac_ready(unsigned long iobase
)
1276 unsigned long retry
= 100000L;
1278 /* This may seem like an absurd way to handle waiting and violates the
1279 "no busy waiting" policy. The fact is that the hardware is
1280 normally so fast that we usually only need one time through the loop
1281 anyway. The longer timeout is for rare occasions and for detecting
1282 non-existent hardware. */
1285 if (inb(iobase
+ 3) & 0x80)
1292 static int ao_winsn(struct comedi_device
*dev
, struct comedi_subdevice
*s
,
1293 struct comedi_insn
*insn
, unsigned int *data
)
1296 unsigned iobase
= subpriv
->iobase
, iooffset
= 0;
1298 for (n
= 0; n
< insn
->n
; n
++) {
1299 unsigned chan
= CR_CHAN(insn
->chanspec
), range
=
1300 CR_RANGE(insn
->chanspec
);
1301 if (chan
< s
->n_chan
) {
1302 unsigned char command_byte
= 0, range_byte
=
1303 range
& ((1 << 4) - 1);
1305 chan
-= 4, iooffset
+= 4;
1306 /* set the range.. */
1307 outb(range_byte
, iobase
+ iooffset
+ 0);
1308 outb(0, iobase
+ iooffset
+ 1);
1310 /* tell it to begin */
1311 command_byte
= (chan
<< 1) | 0x60;
1312 outb(command_byte
, iobase
+ iooffset
+ 2);
1314 wait_dac_ready(iobase
+ iooffset
);
1316 /* low order byte */
1317 outb(data
[n
] & 0xff, iobase
+ iooffset
+ 0);
1319 /* high order byte */
1320 outb((data
[n
] >> 8) & 0xff, iobase
+ iooffset
+ 1);
1323 * set bit 4 of command byte to indicate
1324 * data is loaded and trigger conversion
1326 command_byte
= 0x70 | (chan
<< 1);
1327 /* trigger converion */
1328 outb(command_byte
, iobase
+ iooffset
+ 2);
1330 wait_dac_ready(iobase
+ iooffset
);
1332 /* save to shadow register for ao_rinsn */
1333 subpriv
->ao
.shadow_samples
[chan
] = data
[n
];
1340 * A convenient macro that defines init_module() and cleanup_module(),
1343 static int __init
driver_init_module(void)
1345 return comedi_driver_register(&driver
);
1348 static void __exit
driver_cleanup_module(void)
1350 comedi_driver_unregister(&driver
);
1353 module_init(driver_init_module
);
1354 module_exit(driver_cleanup_module
);
1356 MODULE_AUTHOR("Comedi http://www.comedi.org");
1357 MODULE_DESCRIPTION("Comedi low-level driver");
1358 MODULE_LICENSE("GPL");