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(KERN_INFO "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(KERN_ERR "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(KERN_ERR "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(KERN_ERR "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(KERN_ERR "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(KERN_DEBUG "irq: %u ", irq[0]);
561
if (thisboard->dio_num_asics == 2 && irq[1])
562
printk(KERN_DEBUG "second ASIC irq: %u ", irq[1]);
564
printk(KERN_INFO "(IRQ mode disabled) ");
567
printk(KERN_INFO "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(KERN_INFO "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(KERN_DEBUG "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
(KERN_DEBUG "byte %d wmb %02x db %02x offset %02d io %04x,"
648
" data_in %02x ", byte_no, (unsigned)write_mask_byte,
649
(unsigned)data_byte, 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(KERN_DEBUG "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(KERN_DEBUG "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
(KERN_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");