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
149 * Board descriptions for two imaginary boards. Describing the
150 * boards in this way is optional, and completely driver-dependent.
151 * Some drivers use arrays such as this, other do not.
153 struct pcmmio_board {
155 const int dio_num_asics;
156 const int dio_num_ports;
157 const int total_iosize;
160 const int n_ai_chans;
161 const int n_ao_chans;
162 const struct comedi_lrange *ai_range_table, *ao_range_table;
163 int (*ai_rinsn) (struct comedi_device *dev,
164 struct comedi_subdevice *s,
165 struct comedi_insn *insn,
167 int (*ao_rinsn) (struct comedi_device *dev,
168 struct comedi_subdevice *s,
169 struct comedi_insn *insn,
171 int (*ao_winsn) (struct comedi_device *dev,
172 struct comedi_subdevice *s,
173 struct comedi_insn *insn,
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)}
187 * Useful for shorthand access to the particular board structure
189 #define thisboard ((const struct pcmmio_board *)dev->board_ptr)
191 /* this structure is for data unique to this subdevice. */
192 struct pcmmio_subdev_private {
195 /* for DIO: mapping of halfwords (bytes)
196 in port/chanarray to iobase */
197 unsigned long iobases[PORTS_PER_SUBDEV];
200 unsigned long iobase;
205 /* The below is only used for intr subdevices */
208 * if non-negative, this subdev has an
213 * if nonnegative, the first channel id for
218 * the number of asic channels in this subdev
219 * that have interrutps
223 * if nonnegative, the first channel id with
224 * respect to the asic that has interrupts
228 * subdev-relative channel mask for channels
229 * we are interested in
239 /* the last unsigned int data written */
240 unsigned int shadow_samples[8];
246 * this structure is for data unique to this hardware driver. If
247 * several hardware drivers keep similar information in this structure,
248 * feel free to suggest moving the variable to the struct comedi_device struct.
250 struct pcmmio_private {
253 unsigned char pagelock; /* current page and lock */
254 /* shadow of POLx registers */
255 unsigned char pol[NUM_PAGED_REGS];
256 /* shadow of ENABx registers */
257 unsigned char enab[NUM_PAGED_REGS];
259 unsigned long iobase;
263 struct pcmmio_subdev_private *sprivs;
267 * most drivers define the following macro to make it easy to
268 * access the private structure.
270 #define devpriv ((struct pcmmio_private *)dev->private)
271 #define subpriv ((struct pcmmio_subdev_private *)s->private)
273 /* DIO devices are slightly special. Although it is possible to
274 * implement the insn_read/insn_write interface, it is much more
275 * useful to applications if you implement the insn_bits interface.
276 * This allows packed reading/writing of the DIO channels. The
277 * comedi core can convert between insn_bits and insn_read/write */
278 static int pcmmio_dio_insn_bits(struct comedi_device *dev,
279 struct comedi_subdevice *s,
280 struct comedi_insn *insn, unsigned int *data)
287 reading a 0 means this channel was high
288 writine a 0 sets the channel high
289 reading a 1 means this channel was low
290 writing a 1 means set this channel low
292 Therefore everything is always inverted. */
294 /* The insn data is a mask in data[0] and the new data
295 * in data[1], each channel cooresponding to a bit. */
297 #ifdef DAMMIT_ITS_BROKEN
299 printk(KERN_DEBUG "write mask: %08x data: %08x\n", data[0], data[1]);
304 for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) {
305 /* address of 8-bit port */
306 unsigned long ioaddr = subpriv->iobases[byte_no],
307 /* bit offset of port in 32-bit doubleword */
308 offset = byte_no * 8;
309 /* this 8-bit port's data */
310 unsigned char byte = 0,
311 /* The write mask for this port (if any) */
312 write_mask_byte = (data[0] >> offset) & 0xff,
313 /* The data byte for this port */
314 data_byte = (data[1] >> offset) & 0xff;
316 byte = inb(ioaddr); /* read all 8-bits for this port */
318 #ifdef DAMMIT_ITS_BROKEN
321 (KERN_DEBUG "byte %d wmb %02x db %02x offset %02d io %04x,"
322 " data_in %02x ", byte_no, (unsigned)write_mask_byte,
323 (unsigned)data_byte, offset, ioaddr, (unsigned)byte);
326 if (write_mask_byte) {
328 * this byte has some write_bits
329 * -- so set the output lines
331 /* clear bits for write mask */
332 byte &= ~write_mask_byte;
333 /* set to inverted data_byte */
334 byte |= ~data_byte & write_mask_byte;
335 /* Write out the new digital output state */
338 #ifdef DAMMIT_ITS_BROKEN
340 printk(KERN_DEBUG "data_out_byte %02x\n", (unsigned)byte);
342 /* save the digital input lines for this byte.. */
343 s->state |= ((unsigned int)byte) << offset;
346 /* now return the DIO lines to data[1] - note they came inverted! */
349 #ifdef DAMMIT_ITS_BROKEN
351 printk(KERN_DEBUG "s->state %08x data_out %08x\n", s->state, data[1]);
357 /* The input or output configuration of each digital line is
358 * configured by a special insn_config instruction. chanspec
359 * contains the channel to be changed, and data[0] contains the
360 * value COMEDI_INPUT or COMEDI_OUTPUT. */
361 static int pcmmio_dio_insn_config(struct comedi_device *dev,
362 struct comedi_subdevice *s,
363 struct comedi_insn *insn, unsigned int *data)
365 int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no =
367 unsigned long ioaddr;
370 /* Compute ioaddr for this channel */
371 ioaddr = subpriv->iobases[byte_no];
374 writing a 0 an IO channel's bit sets the channel to INPUT
375 and pulls the line high as well
377 writing a 1 to an IO channel's bit pulls the line low
379 All channels are implicitly always in OUTPUT mode -- but when
380 they are high they can be considered to be in INPUT mode..
382 Thus, we only force channels low if the config request was INPUT,
383 otherwise we do nothing to the hardware. */
386 case INSN_CONFIG_DIO_OUTPUT:
387 /* save to io_bits -- don't actually do anything since
388 all input channels are also output channels... */
389 s->io_bits |= 1 << chan;
391 case INSN_CONFIG_DIO_INPUT:
392 /* write a 0 to the actual register representing the channel
393 to set it to 'input'. 0 means "float high". */
395 byte &= ~(1 << bit_no);
396 /**< set input channel to '0' */
399 * write out byte -- this is the only time we actually affect
400 * the hardware as all channels are implicitly output
401 * -- but input channels are set to float-high
405 /* save to io_bits */
406 s->io_bits &= ~(1 << chan);
409 case INSN_CONFIG_DIO_QUERY:
410 /* retrieve from shadow register */
412 (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
424 static void switch_page(struct comedi_device *dev, int asic, int page)
426 if (asic < 0 || asic >= thisboard->dio_num_asics)
427 return; /* paranoia */
428 if (page < 0 || page >= NUM_PAGES)
429 return; /* more paranoia */
431 devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
432 devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
434 /* now write out the shadow register */
435 outb(devpriv->asics[asic].pagelock,
436 devpriv->asics[asic].iobase + REG_PAGELOCK);
439 static void init_asics(struct comedi_device *dev)
441 ASIC chip to defaults */
444 for (asic = 0; asic < thisboard->dio_num_asics; ++asic) {
446 unsigned long baseaddr = devpriv->asics[asic].iobase;
448 switch_page(dev, asic, 0); /* switch back to page 0 */
450 /* first, clear all the DIO port bits */
451 for (port = 0; port < PORTS_PER_ASIC; ++port)
452 outb(0, baseaddr + REG_PORT0 + port);
454 /* Next, clear all the paged registers for each page */
455 for (page = 1; page < NUM_PAGES; ++page) {
457 /* now clear all the paged registers */
458 switch_page(dev, asic, page);
459 for (reg = FIRST_PAGED_REG;
460 reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg)
461 outb(0, baseaddr + reg);
464 /* DEBUG set rising edge interrupts on port0 of both asics */
465 /*switch_page(dev, asic, PAGE_POL);
466 outb(0xff, baseaddr + REG_POL0);
467 switch_page(dev, asic, PAGE_ENAB);
468 outb(0xff, baseaddr + REG_ENAB0); */
471 /* switch back to default page 0 */
472 switch_page(dev, asic, 0);
477 static void lock_port(struct comedi_device *dev, int asic, int port)
479 if (asic < 0 || asic >= thisboard->dio_num_asics)
480 return; /* paranoia */
481 if (port < 0 || port >= PORTS_PER_ASIC)
482 return; /* more paranoia */
484 devpriv->asics[asic].pagelock |= 0x1 << port;
485 /* now write out the shadow register */
486 outb(devpriv->asics[asic].pagelock,
487 devpriv->asics[asic].iobase + REG_PAGELOCK);
491 static void unlock_port(struct comedi_device *dev, int asic, int port)
493 if (asic < 0 || asic >= thisboard->dio_num_asics)
494 return; /* paranoia */
495 if (port < 0 || port >= PORTS_PER_ASIC)
496 return; /* more paranoia */
497 devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK;
498 /* now write out the shadow register */
499 outb(devpriv->asics[asic].pagelock,
500 devpriv->asics[asic].iobase + REG_PAGELOCK);
504 static void pcmmio_stop_intr(struct comedi_device *dev,
505 struct comedi_subdevice *s)
507 int nports, firstport, asic, port;
509 asic = subpriv->dio.intr.asic;
511 return; /* not an interrupt subdev */
513 subpriv->dio.intr.enabled_mask = 0;
514 subpriv->dio.intr.active = 0;
515 s->async->inttrig = 0;
516 nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
517 firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
518 switch_page(dev, asic, PAGE_ENAB);
519 for (port = firstport; port < firstport + nports; ++port) {
520 /* disable all intrs for this subdev.. */
521 outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
525 static irqreturn_t interrupt_pcmmio(int irq, void *d)
528 struct comedi_device *dev = (struct comedi_device *)d;
530 for (asic = 0; asic < MAX_ASICS; ++asic) {
531 if (irq == devpriv->asics[asic].irq) {
533 unsigned triggered = 0;
534 unsigned long iobase = devpriv->asics[asic].iobase;
535 /* it is an interrupt for ASIC #asic */
536 unsigned char int_pend;
538 spin_lock_irqsave(&devpriv->asics[asic].spinlock,
541 int_pend = inb(iobase + REG_INT_PENDING) & 0x07;
545 for (port = 0; port < INTR_PORTS_PER_ASIC;
547 if (int_pend & (0x1 << port)) {
549 io_lines_with_edges = 0;
550 switch_page(dev, asic,
552 io_lines_with_edges =
556 if (io_lines_with_edges)
566 io_lines_with_edges <<
574 spin_unlock_irqrestore(&devpriv->asics[asic].spinlock,
578 struct comedi_subdevice *s;
580 * TODO here: dispatch io lines to subdevs
584 (KERN_DEBUG "got edge detect interrupt %d asic %d which_chans: %06x\n",
585 irq, asic, triggered);
586 for (s = dev->subdevices + 2;
587 s < dev->subdevices + dev->n_subdevices;
590 * this is an interrupt subdev,
591 * and it matches this asic!
593 if (subpriv->dio.intr.asic == asic) {
597 spin_lock_irqsave(&subpriv->dio.
601 oldevents = s->async->events;
603 if (subpriv->dio.intr.active) {
606 subpriv->dio.intr.asic_chan)
623 async->cmd.chanlist_len;
627 ch = CR_CHAN(s->async->cmd.chanlist[n]);
628 if (mytrig & (1U << ch))
631 /* Write the scan to the buffer. */
632 if (comedi_buf_put(s->async, ((short *)&val)[0])
638 s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
640 /* Overflow! Stop acquisition!! */
641 /* TODO: STOP_ACQUISITION_CALL_HERE!! */
647 /* Check for end of acquisition. */
648 if (!subpriv->dio.intr.continuous) {
649 /* stop_src == TRIG_COUNT */
650 if (subpriv->dio.intr.stop_count > 0) {
651 subpriv->dio.intr.stop_count--;
652 if (subpriv->dio.intr.stop_count == 0) {
653 s->async->events |= COMEDI_CB_EOA;
654 /* TODO: STOP_ACQUISITION_CALL_HERE!! */
664 spin_unlock_irqrestore
670 comedi_event(dev, s);
681 return IRQ_NONE; /* interrupt from other source */
685 static int pcmmio_start_intr(struct comedi_device *dev,
686 struct comedi_subdevice *s)
688 if (!subpriv->dio.intr.continuous && subpriv->dio.intr.stop_count == 0) {
689 /* An empty acquisition! */
690 s->async->events |= COMEDI_CB_EOA;
691 subpriv->dio.intr.active = 0;
694 unsigned bits = 0, pol_bits = 0, n;
695 int nports, firstport, asic, port;
696 struct comedi_cmd *cmd = &s->async->cmd;
698 asic = subpriv->dio.intr.asic;
700 return 1; /* not an interrupt
702 subpriv->dio.intr.enabled_mask = 0;
703 subpriv->dio.intr.active = 1;
704 nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
705 firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
707 for (n = 0; n < cmd->chanlist_len; n++) {
708 bits |= (1U << CR_CHAN(cmd->chanlist[n]));
709 pol_bits |= (CR_AREF(cmd->chanlist[n])
711 chanlist[n]) ? 1U : 0U)
712 << CR_CHAN(cmd->chanlist[n]);
715 bits &= ((0x1 << subpriv->dio.intr.num_asic_chans) -
716 1) << subpriv->dio.intr.first_chan;
717 subpriv->dio.intr.enabled_mask = bits;
721 * the below code configures the board
722 * to use a specific IRQ from 0-15.
726 * set resource enable register
727 * to enable IRQ operation
729 outb(1 << 4, dev->iobase + 3);
730 /* set bits 0-3 of b to the irq number from 0-15 */
731 b = dev->irq & ((1 << 4) - 1);
732 outb(b, dev->iobase + 2);
733 /* done, we told the board what irq to use */
736 switch_page(dev, asic, PAGE_ENAB);
737 for (port = firstport; port < firstport + nports; ++port) {
739 bits >> (subpriv->dio.intr.first_chan + (port -
742 pol_bits >> (subpriv->dio.intr.first_chan +
743 (port - firstport) * 8) & 0xff;
744 /* set enab intrs for this subdev.. */
746 devpriv->asics[asic].iobase + REG_ENAB0 + port);
747 switch_page(dev, asic, PAGE_POL);
749 devpriv->asics[asic].iobase + REG_ENAB0 + port);
755 static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
759 spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
760 if (subpriv->dio.intr.active)
761 pcmmio_stop_intr(dev, s);
762 spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
768 * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
771 pcmmio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
772 unsigned int trignum)
780 spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
781 s->async->inttrig = 0;
782 if (subpriv->dio.intr.active)
783 event = pcmmio_start_intr(dev, s);
784 spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
787 comedi_event(dev, s);
793 * 'do_cmd' function for an 'INTERRUPT' subdevice.
795 static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
797 struct comedi_cmd *cmd = &s->async->cmd;
801 spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
802 subpriv->dio.intr.active = 1;
804 /* Set up end of acquisition. */
805 switch (cmd->stop_src) {
807 subpriv->dio.intr.continuous = 0;
808 subpriv->dio.intr.stop_count = cmd->stop_arg;
812 subpriv->dio.intr.continuous = 1;
813 subpriv->dio.intr.stop_count = 0;
817 /* Set up start of acquisition. */
818 switch (cmd->start_src) {
820 s->async->inttrig = pcmmio_inttrig_start_intr;
824 event = pcmmio_start_intr(dev, s);
827 spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
830 comedi_event(dev, s);
836 pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
837 struct comedi_cmd *cmd)
839 return comedi_pcm_cmdtest(dev, s, cmd);
842 static int adc_wait_ready(unsigned long iobase)
844 unsigned long retry = 100000;
846 if (inb(iobase + 3) & 0x80)
851 /* All this is for AI and AO */
852 static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
853 struct comedi_insn *insn, unsigned int *data)
856 unsigned long iobase = subpriv->iobase;
859 1. write the CMD byte (to BASE+2)
860 2. read junk lo byte (BASE+0)
861 3. read junk hi byte (BASE+1)
862 4. (mux settled so) write CMD byte again (BASE+2)
863 5. read valid lo byte(BASE+0)
864 6. read valid hi byte(BASE+1)
866 Additionally note that the BASE += 4 if the channel >= 8
869 /* convert n samples */
870 for (n = 0; n < insn->n; n++) {
871 unsigned chan = CR_CHAN(insn->chanspec), range =
872 CR_RANGE(insn->chanspec), aref = CR_AREF(insn->chanspec);
873 unsigned char command_byte = 0;
874 unsigned iooffset = 0;
875 short sample, adc_adjust = 0;
878 chan -= 8, iooffset = 4; /*
879 * use the second dword
883 if (aref != AREF_DIFF) {
885 command_byte |= 1 << 7; /*
886 * set bit 7 to indicate
891 adc_adjust = 0x8000; /*
893 * (-5,5 .. -10,10 need to be
894 * adjusted -- that is.. they
895 * need to wrap around by
900 command_byte |= 1 << 6; /*
901 * odd-numbered channels
906 /* select the channel, bits 4-5 == chan/2 */
907 command_byte |= ((chan / 2) & 0x3) << 4;
909 /* set the range, bits 2-3 */
910 command_byte |= (range & 0x3) << 2;
912 /* need to do this twice to make sure mux settled */
913 /* chan/range/aref select */
914 outb(command_byte, iobase + iooffset + 2);
916 /* wait for the adc to say it finised the conversion */
917 adc_wait_ready(iobase + iooffset);
919 /* select the chan/range/aref AGAIN */
920 outb(command_byte, iobase + iooffset + 2);
922 adc_wait_ready(iobase + iooffset);
924 /* read data lo byte */
925 sample = inb(iobase + iooffset + 0);
927 /* read data hi byte */
928 sample |= inb(iobase + iooffset + 1) << 8;
929 sample += adc_adjust; /* adjustment .. munge data */
932 /* return the number of samples read/written */
936 static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
937 struct comedi_insn *insn, unsigned int *data)
940 for (n = 0; n < insn->n; n++) {
941 unsigned chan = CR_CHAN(insn->chanspec);
942 if (chan < s->n_chan)
943 data[n] = subpriv->ao.shadow_samples[chan];
948 static int wait_dac_ready(unsigned long iobase)
950 unsigned long retry = 100000L;
952 /* This may seem like an absurd way to handle waiting and violates the
953 "no busy waiting" policy. The fact is that the hardware is
954 normally so fast that we usually only need one time through the loop
955 anyway. The longer timeout is for rare occasions and for detecting
956 non-existent hardware. */
959 if (inb(iobase + 3) & 0x80)
966 static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
967 struct comedi_insn *insn, unsigned int *data)
970 unsigned iobase = subpriv->iobase, iooffset = 0;
972 for (n = 0; n < insn->n; n++) {
973 unsigned chan = CR_CHAN(insn->chanspec), range =
974 CR_RANGE(insn->chanspec);
975 if (chan < s->n_chan) {
976 unsigned char command_byte = 0, range_byte =
977 range & ((1 << 4) - 1);
979 chan -= 4, iooffset += 4;
980 /* set the range.. */
981 outb(range_byte, iobase + iooffset + 0);
982 outb(0, iobase + iooffset + 1);
984 /* tell it to begin */
985 command_byte = (chan << 1) | 0x60;
986 outb(command_byte, iobase + iooffset + 2);
988 wait_dac_ready(iobase + iooffset);
991 outb(data[n] & 0xff, iobase + iooffset + 0);
993 /* high order byte */
994 outb((data[n] >> 8) & 0xff, iobase + iooffset + 1);
997 * set bit 4 of command byte to indicate
998 * data is loaded and trigger conversion
1000 command_byte = 0x70 | (chan << 1);
1001 /* trigger converion */
1002 outb(command_byte, iobase + iooffset + 2);
1004 wait_dac_ready(iobase + iooffset);
1006 /* save to shadow register for ao_rinsn */
1007 subpriv->ao.shadow_samples[chan] = data[n];
1013 static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1015 struct comedi_subdevice *s;
1016 int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic,
1017 thisasic_chanct = 0;
1018 unsigned long iobase;
1019 unsigned int irq[MAX_ASICS];
1021 iobase = it->options[0];
1022 irq[0] = it->options[1];
1024 printk(KERN_INFO "comedi%d: %s: io: %lx attaching...\n", dev->minor,
1025 dev->driver->driver_name, iobase);
1027 dev->iobase = iobase;
1029 if (!iobase || !request_region(iobase,
1030 thisboard->total_iosize,
1031 dev->driver->driver_name)) {
1032 printk(KERN_ERR "comedi%d: I/O port conflict\n", dev->minor);
1037 * Initialize dev->board_name. Note that we can use the "thisboard"
1038 * macro now, since we just initialized it in the last line.
1040 dev->board_name = thisboard->name;
1043 * Allocate the private structure area. alloc_private() is a
1044 * convenient macro defined in comedidev.h.
1046 if (alloc_private(dev, sizeof(struct pcmmio_private)) < 0) {
1047 printk(KERN_ERR "comedi%d: cannot allocate private data structure\n",
1052 for (asic = 0; asic < MAX_ASICS; ++asic) {
1053 devpriv->asics[asic].num = asic;
1054 devpriv->asics[asic].iobase =
1055 dev->iobase + 16 + asic * ASIC_IOSIZE;
1057 * this gets actually set at the end of this function when we
1060 devpriv->asics[asic].irq = 0;
1061 spin_lock_init(&devpriv->asics[asic].spinlock);
1064 chans_left = CHANS_PER_ASIC * thisboard->dio_num_asics;
1065 n_dio_subdevs = CALC_N_DIO_SUBDEVS(chans_left);
1066 n_subdevs = n_dio_subdevs + 2;
1068 kcalloc(n_subdevs, sizeof(struct pcmmio_subdev_private),
1070 if (!devpriv->sprivs) {
1071 printk(KERN_ERR "comedi%d: cannot allocate subdevice private data structures\n",
1076 * Allocate the subdevice structures. alloc_subdevice() is a
1077 * convenient macro defined in comedidev.h.
1079 * Allocate 1 AI + 1 AO + 2 DIO subdevs (24 lines per DIO)
1081 if (alloc_subdevices(dev, n_subdevs) < 0) {
1082 printk(KERN_ERR "comedi%d: cannot allocate subdevice data structures\n",
1089 s = dev->subdevices + sdev_no;
1090 s->private = devpriv->sprivs + sdev_no;
1091 s->maxdata = (1 << thisboard->ai_bits) - 1;
1092 s->range_table = thisboard->ai_range_table;
1093 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
1094 s->type = COMEDI_SUBD_AI;
1095 s->n_chan = thisboard->n_ai_chans;
1096 s->len_chanlist = s->n_chan;
1097 s->insn_read = thisboard->ai_rinsn;
1098 subpriv->iobase = dev->iobase + 0;
1099 /* initialize the resource enable register by clearing it */
1100 outb(0, subpriv->iobase + 3);
1101 outb(0, subpriv->iobase + 4 + 3);
1105 s = dev->subdevices + sdev_no;
1106 s->private = devpriv->sprivs + sdev_no;
1107 s->maxdata = (1 << thisboard->ao_bits) - 1;
1108 s->range_table = thisboard->ao_range_table;
1109 s->subdev_flags = SDF_READABLE;
1110 s->type = COMEDI_SUBD_AO;
1111 s->n_chan = thisboard->n_ao_chans;
1112 s->len_chanlist = s->n_chan;
1113 s->insn_read = thisboard->ao_rinsn;
1114 s->insn_write = thisboard->ao_winsn;
1115 subpriv->iobase = dev->iobase + 8;
1116 /* initialize the resource enable register by clearing it */
1117 outb(0, subpriv->iobase + 3);
1118 outb(0, subpriv->iobase + 4 + 3);
1123 for (; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
1126 s = dev->subdevices + sdev_no;
1127 s->private = devpriv->sprivs + sdev_no;
1129 s->range_table = &range_digital;
1130 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1131 s->type = COMEDI_SUBD_DIO;
1132 s->insn_bits = pcmmio_dio_insn_bits;
1133 s->insn_config = pcmmio_dio_insn_config;
1134 s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
1135 subpriv->dio.intr.asic = -1;
1136 subpriv->dio.intr.first_chan = -1;
1137 subpriv->dio.intr.asic_chan = -1;
1138 subpriv->dio.intr.num_asic_chans = -1;
1139 subpriv->dio.intr.active = 0;
1140 s->len_chanlist = 1;
1142 /* save the ioport address for each 'port' of 8 channels in the
1144 for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
1145 if (port >= PORTS_PER_ASIC) {
1148 thisasic_chanct = 0;
1150 subpriv->iobases[byte_no] =
1151 devpriv->asics[asic].iobase + port;
1153 if (thisasic_chanct <
1154 CHANS_PER_PORT * INTR_PORTS_PER_ASIC
1155 && subpriv->dio.intr.asic < 0) {
1157 * this is an interrupt subdevice,
1158 * so setup the struct
1160 subpriv->dio.intr.asic = asic;
1161 subpriv->dio.intr.active = 0;
1162 subpriv->dio.intr.stop_count = 0;
1163 subpriv->dio.intr.first_chan = byte_no * 8;
1164 subpriv->dio.intr.asic_chan = thisasic_chanct;
1165 subpriv->dio.intr.num_asic_chans =
1166 s->n_chan - subpriv->dio.intr.first_chan;
1167 s->cancel = pcmmio_cancel;
1168 s->do_cmd = pcmmio_cmd;
1169 s->do_cmdtest = pcmmio_cmdtest;
1171 subpriv->dio.intr.num_asic_chans;
1173 thisasic_chanct += CHANS_PER_PORT;
1175 spin_lock_init(&subpriv->dio.intr.spinlock);
1177 chans_left -= s->n_chan;
1181 * reset the asic to our first asic,
1182 * to do intr subdevs
1190 init_asics(dev); /* clear out all the registers, basically */
1192 for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
1194 && request_irq(irq[asic], interrupt_pcmmio,
1195 IRQF_SHARED, thisboard->name, dev)) {
1197 /* unroll the allocated irqs.. */
1198 for (i = asic - 1; i >= 0; --i) {
1199 free_irq(irq[i], dev);
1200 devpriv->asics[i].irq = irq[i] = 0;
1204 devpriv->asics[asic].irq = irq[asic];
1207 dev->irq = irq[0]; /*
1208 * grr.. wish comedi dev struct supported
1213 printk(KERN_DEBUG "comedi%d: irq: %u\n", dev->minor, irq[0]);
1214 if (thisboard->dio_num_asics == 2 && irq[1])
1215 printk(KERN_DEBUG "comedi%d: second ASIC irq: %u\n",
1216 dev->minor, irq[1]);
1218 printk(KERN_INFO "comedi%d: (IRQ mode disabled)\n", dev->minor);
1221 printk(KERN_INFO "comedi%d: attached\n", dev->minor);
1226 static void pcmmio_detach(struct comedi_device *dev)
1231 release_region(dev->iobase, thisboard->total_iosize);
1232 for (i = 0; i < MAX_ASICS; ++i) {
1233 if (devpriv && devpriv->asics[i].irq)
1234 free_irq(devpriv->asics[i].irq, dev);
1236 if (devpriv && devpriv->sprivs)
1237 kfree(devpriv->sprivs);
1240 static const struct pcmmio_board pcmmio_boards[] = {
1250 .ai_range_table = &ranges_ai,
1251 .ao_range_table = &ranges_ao,
1252 .ai_rinsn = ai_rinsn,
1253 .ao_rinsn = ao_rinsn,
1254 .ao_winsn = ao_winsn
1258 static struct comedi_driver pcmmio_driver = {
1259 .driver_name = "pcmmio",
1260 .module = THIS_MODULE,
1261 .attach = pcmmio_attach,
1262 .detach = pcmmio_detach,
1263 .board_name = &pcmmio_boards[0].name,
1264 .offset = sizeof(struct pcmmio_board),
1265 .num_names = ARRAY_SIZE(pcmmio_boards),
1267 module_comedi_driver(pcmmio_driver);
1269 MODULE_AUTHOR("Comedi http://www.comedi.org");
1270 MODULE_DESCRIPTION("Comedi low-level driver");
1271 MODULE_LICENSE("GPL");