pcmmio.c revision 0a85b6f0ab0d2edb0d41b32697111ce0e4f43496
1/*
2    comedi/drivers/pcmmio.c
3    Driver for Winsystems PC-104 based multifunction IO board.
4
5    COMEDI - Linux Control and Measurement Device Interface
6    Copyright (C) 2007 Calin A. Culianu <calin@ajvar.org>
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21*/
22/*
23Driver: pcmmio
24Description: A driver for the PCM-MIO multifunction board
25Devices: [Winsystems] PCM-MIO (pcmmio)
26Author: Calin Culianu <calin@ajvar.org>
27Updated: Wed, May 16 2007 16:21:10 -0500
28Status: works
29
30A driver for the relatively new PCM-MIO multifunction board from
31Winsystems.  This board is a PC-104 based I/O board.  It contains
32four subdevices:
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 (with edge-triggered interrupt support)
36  subdevice 3 - last 24 channels of the 48 channel DIO (no interrupt support for this bank of channels)
37
38  Some notes:
39
40  Synchronous reads and writes are the only things implemented for AI and AO,
41  even though the hardware itself can do streaming acquisition, etc.  Anyone
42  want to add asynchronous I/O for AI/AO as a feature?  Be my guest...
43
44  Asynchronous I/O for the DIO subdevices *is* implemented, however!  They are
45  basically edge-triggered interrupts for any configuration of the first
46  24 DIO-lines.
47
48  Also note that this interrupt support is untested.
49
50  A few words about edge-detection IRQ support (commands on DIO):
51
52  * To use edge-detection IRQ support for the DIO subdevice, pass the IRQ
53    of the board to the comedi_config command.  The board IRQ is not jumpered
54    but rather configured through software, so any IRQ from 1-15 is OK.
55
56  * Due to the genericity of the comedi API, you need to create a special
57    comedi_command in order to use edge-triggered interrupts for DIO.
58
59  * Use comedi_commands with TRIG_NOW.  Your callback will be called each
60    time an edge is detected on the specified DIO line(s), and the data
61    values will be two sample_t's, which should be concatenated to form
62    one 32-bit unsigned int.  This value is the mask of channels that had
63    edges detected from your channel list.  Note that the bits positions
64    in the mask correspond to positions in your chanlist when you
65    specified the command and *not* channel id's!
66
67 *  To set the polarity of the edge-detection interrupts pass a nonzero value
68    for either CR_RANGE or CR_AREF for edge-up polarity, or a zero
69    value for both CR_RANGE and CR_AREF if you want edge-down polarity.
70
71Configuration Options:
72  [0] - I/O port base address
73  [1] - IRQ (optional -- for edge-detect interrupt support only, leave out if you don't need this feature)
74*/
75
76#include <linux/interrupt.h>
77#include "../comedidev.h"
78#include "pcm_common.h"
79#include <linux/pci.h>		/* for PCI devices */
80
81/* This stuff is all from pcmuio.c -- it refers to the DIO subdevices only */
82#define CHANS_PER_PORT   8
83#define PORTS_PER_ASIC   6
84#define INTR_PORTS_PER_ASIC   3
85#define MAX_CHANS_PER_SUBDEV 24	/* number of channels per comedi subdevice */
86#define PORTS_PER_SUBDEV (MAX_CHANS_PER_SUBDEV/CHANS_PER_PORT)
87#define CHANS_PER_ASIC (CHANS_PER_PORT*PORTS_PER_ASIC)
88#define INTR_CHANS_PER_ASIC 24
89#define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC/CHANS_PER_PORT)
90#define MAX_DIO_CHANS   (PORTS_PER_ASIC*1*CHANS_PER_PORT)
91#define MAX_ASICS       (MAX_DIO_CHANS/CHANS_PER_ASIC)
92#define SDEV_NO ((int)(s - dev->subdevices))
93#define CALC_N_DIO_SUBDEVS(nchans) ((nchans)/MAX_CHANS_PER_SUBDEV + (!!((nchans)%MAX_CHANS_PER_SUBDEV)) /*+ (nchans > INTR_CHANS_PER_ASIC ? 2 : 1)*/)
94/* IO Memory sizes */
95#define ASIC_IOSIZE (0x0B)
96#define PCMMIO48_IOSIZE ASIC_IOSIZE
97
98/* Some offsets - these are all in the 16byte IO memory offset from
99   the base address.  Note that there is a paging scheme to swap out
100   offsets 0x8-0xA using the PAGELOCK register.  See the table below.
101
102  Register(s)       Pages        R/W?        Description
103  --------------------------------------------------------------
104  REG_PORTx         All          R/W         Read/Write/Configure IO
105  REG_INT_PENDING   All          ReadOnly    Quickly see which INT_IDx has int.
106  REG_PAGELOCK      All          WriteOnly   Select a page
107  REG_POLx          Pg. 1 only   WriteOnly   Select edge-detection polarity
108  REG_ENABx         Pg. 2 only   WriteOnly   Enable/Disable edge-detect. int.
109  REG_INT_IDx       Pg. 3 only   R/W         See which ports/bits have ints.
110 */
111#define REG_PORT0 0x0
112#define REG_PORT1 0x1
113#define REG_PORT2 0x2
114#define REG_PORT3 0x3
115#define REG_PORT4 0x4
116#define REG_PORT5 0x5
117#define REG_INT_PENDING 0x6
118#define REG_PAGELOCK 0x7	/* page selector register, upper 2 bits select a page
119				   and bits 0-5 are used to 'lock down' a particular
120				   port above to make it readonly.  */
121#define REG_POL0 0x8
122#define REG_POL1 0x9
123#define REG_POL2 0xA
124#define REG_ENAB0 0x8
125#define REG_ENAB1 0x9
126#define REG_ENAB2 0xA
127#define REG_INT_ID0 0x8
128#define REG_INT_ID1 0x9
129#define REG_INT_ID2 0xA
130
131#define NUM_PAGED_REGS 3
132#define NUM_PAGES 4
133#define FIRST_PAGED_REG 0x8
134#define REG_PAGE_BITOFFSET 6
135#define REG_LOCK_BITOFFSET 0
136#define REG_PAGE_MASK (~((0x1<<REG_PAGE_BITOFFSET)-1))
137#define REG_LOCK_MASK ~(REG_PAGE_MASK)
138#define PAGE_POL 1
139#define PAGE_ENAB 2
140#define PAGE_INT_ID 3
141
142typedef int (*comedi_insn_fn_t) (struct comedi_device *,
143				 struct comedi_subdevice *,
144				 struct comedi_insn *, unsigned int *);
145
146static int ai_rinsn(struct comedi_device *, struct comedi_subdevice *,
147		    struct comedi_insn *, unsigned int *);
148static int ao_rinsn(struct comedi_device *, struct comedi_subdevice *,
149		    struct comedi_insn *, unsigned int *);
150static int ao_winsn(struct comedi_device *, struct comedi_subdevice *,
151		    struct comedi_insn *, unsigned int *);
152
153/*
154 * Board descriptions for two imaginary boards.  Describing the
155 * boards in this way is optional, and completely driver-dependent.
156 * Some drivers use arrays such as this, other do not.
157 */
158struct pcmmio_board {
159	const char *name;
160	const int dio_num_asics;
161	const int dio_num_ports;
162	const int total_iosize;
163	const int ai_bits;
164	const int ao_bits;
165	const int n_ai_chans;
166	const int n_ao_chans;
167	const struct comedi_lrange *ai_range_table, *ao_range_table;
168	comedi_insn_fn_t ai_rinsn, ao_rinsn, ao_winsn;
169};
170
171static const struct comedi_lrange ranges_ai =
172    { 4, {RANGE(-5., 5.), RANGE(-10., 10.), RANGE(0., 5.), RANGE(0.,
173								 10.)}
174};
175
176static const struct comedi_lrange ranges_ao =
177    { 6, {RANGE(0., 5.), RANGE(0., 10.), RANGE(-5., 5.), RANGE(-10., 10.),
178	  RANGE(-2.5, 2.5), RANGE(-2.5, 7.5)}
179};
180
181static const struct pcmmio_board pcmmio_boards[] = {
182	{
183	 .name = "pcmmio",
184	 .dio_num_asics = 1,
185	 .dio_num_ports = 6,
186	 .total_iosize = 32,
187	 .ai_bits = 16,
188	 .ao_bits = 16,
189	 .n_ai_chans = 16,
190	 .n_ao_chans = 8,
191	 .ai_range_table = &ranges_ai,
192	 .ao_range_table = &ranges_ao,
193	 .ai_rinsn = ai_rinsn,
194	 .ao_rinsn = ao_rinsn,
195	 .ao_winsn = ao_winsn},
196};
197
198/*
199 * Useful for shorthand access to the particular board structure
200 */
201#define thisboard ((const struct pcmmio_board *)dev->board_ptr)
202
203/* this structure is for data unique to this subdevice.  */
204struct pcmmio_subdev_private {
205
206	union {
207		/* for DIO: mapping of halfwords (bytes) in port/chanarray to iobase */
208		unsigned long iobases[PORTS_PER_SUBDEV];
209
210		/* for AI/AO */
211		unsigned long iobase;
212	};
213	union {
214		struct {
215
216			/* The below is only used for intr subdevices */
217			struct {
218				int asic;	/* if non-negative, this subdev has an interrupt asic */
219				int first_chan;	/* if nonnegative, the first channel id for
220						   interrupts. */
221				int num_asic_chans;	/* the number of asic channels in this subdev
222							   that have interrutps */
223				int asic_chan;	/* if nonnegative, the first channel id with
224						   respect to the asic that has interrupts */
225				int enabled_mask;	/* subdev-relative channel mask for channels
226							   we are interested in */
227				int active;
228				int stop_count;
229				int continuous;
230				spinlock_t spinlock;
231			} intr;
232		} dio;
233		struct {
234			unsigned int shadow_samples[8];	/* the last unsigned int data written */
235		} ao;
236	};
237};
238
239/* this structure is for data unique to this hardware driver.  If
240   several hardware drivers keep similar information in this structure,
241   feel free to suggest moving the variable to the struct comedi_device struct.  */
242struct pcmmio_private {
243	/* stuff for DIO */
244	struct {
245		unsigned char pagelock;	/* current page and lock */
246		unsigned char pol[NUM_PAGED_REGS];	/* shadow of POLx registers */
247		unsigned char enab[NUM_PAGED_REGS];	/* shadow of ENABx registers */
248		int num;
249		unsigned long iobase;
250		unsigned int irq;
251		spinlock_t spinlock;
252	} asics[MAX_ASICS];
253	struct pcmmio_subdev_private *sprivs;
254};
255
256/*
257 * most drivers define the following macro to make it easy to
258 * access the private structure.
259 */
260#define devpriv ((struct pcmmio_private *)dev->private)
261#define subpriv ((struct pcmmio_subdev_private *)s->private)
262/*
263 * The struct comedi_driver structure tells the Comedi core module
264 * which functions to call to configure/deconfigure (attach/detach)
265 * the board, and also about the kernel module that contains
266 * the device code.
267 */
268static int pcmmio_attach(struct comedi_device *dev,
269			 struct comedi_devconfig *it);
270static int pcmmio_detach(struct comedi_device *dev);
271
272static struct comedi_driver driver = {
273	.driver_name = "pcmmio",
274	.module = THIS_MODULE,
275	.attach = pcmmio_attach,
276	.detach = pcmmio_detach,
277/* It is not necessary to implement the following members if you are
278 * writing a driver for a ISA PnP or PCI card */
279	/* Most drivers will support multiple types of boards by
280	 * having an array of board structures.  These were defined
281	 * in pcmmio_boards[] above.  Note that the element 'name'
282	 * was first in the structure -- Comedi uses this fact to
283	 * extract the name of the board without knowing any details
284	 * about the structure except for its length.
285	 * When a device is attached (by comedi_config), the name
286	 * of the device is given to Comedi, and Comedi tries to
287	 * match it by going through the list of board names.  If
288	 * there is a match, the address of the pointer is put
289	 * into dev->board_ptr and driver->attach() is called.
290	 *
291	 * Note that these are not necessary if you can determine
292	 * the type of board in software.  ISA PnP, PCI, and PCMCIA
293	 * devices are such boards.
294	 */
295	.board_name = &pcmmio_boards[0].name,
296	.offset = sizeof(struct pcmmio_board),
297	.num_names = ARRAY_SIZE(pcmmio_boards),
298};
299
300static int pcmmio_dio_insn_bits(struct comedi_device *dev,
301				struct comedi_subdevice *s,
302				struct comedi_insn *insn, unsigned int *data);
303static int pcmmio_dio_insn_config(struct comedi_device *dev,
304				  struct comedi_subdevice *s,
305				  struct comedi_insn *insn, unsigned int *data);
306
307static irqreturn_t interrupt_pcmmio(int irq, void *d);
308static void pcmmio_stop_intr(struct comedi_device *, struct comedi_subdevice *);
309static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
310static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
311static int pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
312			  struct comedi_cmd *cmd);
313
314/* some helper functions to deal with specifics of this device's registers */
315static void init_asics(struct comedi_device *dev);	/* sets up/clears ASIC chips to defaults */
316static void switch_page(struct comedi_device *dev, int asic, int page);
317#ifdef notused
318static void lock_port(struct comedi_device *dev, int asic, int port);
319static void unlock_port(struct comedi_device *dev, int asic, int port);
320#endif
321
322/*
323 * Attach is called by the Comedi core to configure the driver
324 * for a particular board.  If you specified a board_name array
325 * in the driver structure, dev->board_ptr contains that
326 * address.
327 */
328static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
329{
330	struct comedi_subdevice *s;
331	int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic,
332	    thisasic_chanct = 0;
333	unsigned long iobase;
334	unsigned int irq[MAX_ASICS];
335
336	iobase = it->options[0];
337	irq[0] = it->options[1];
338
339	printk("comedi%d: %s: io: %lx ", dev->minor, driver.driver_name,
340	       iobase);
341
342	dev->iobase = iobase;
343
344	if (!iobase || !request_region(iobase,
345				       thisboard->total_iosize,
346				       driver.driver_name)) {
347		printk("I/O port conflict\n");
348		return -EIO;
349	}
350
351/*
352 * Initialize dev->board_name.  Note that we can use the "thisboard"
353 * macro now, since we just initialized it in the last line.
354 */
355	dev->board_name = thisboard->name;
356
357/*
358 * Allocate the private structure area.  alloc_private() is a
359 * convenient macro defined in comedidev.h.
360 */
361	if (alloc_private(dev, sizeof(struct pcmmio_private)) < 0) {
362		printk("cannot allocate private data structure\n");
363		return -ENOMEM;
364	}
365
366	for (asic = 0; asic < MAX_ASICS; ++asic) {
367		devpriv->asics[asic].num = asic;
368		devpriv->asics[asic].iobase =
369		    dev->iobase + 16 + asic * ASIC_IOSIZE;
370		devpriv->asics[asic].irq = 0;	/* this gets actually set at the end of
371						   this function when we
372						   request_irqs */
373		spin_lock_init(&devpriv->asics[asic].spinlock);
374	}
375
376	chans_left = CHANS_PER_ASIC * thisboard->dio_num_asics;
377	n_dio_subdevs = CALC_N_DIO_SUBDEVS(chans_left);
378	n_subdevs = n_dio_subdevs + 2;
379	devpriv->sprivs =
380	    kcalloc(n_subdevs, sizeof(struct pcmmio_subdev_private),
381		    GFP_KERNEL);
382	if (!devpriv->sprivs) {
383		printk("cannot allocate subdevice private data structures\n");
384		return -ENOMEM;
385	}
386	/*
387	 * Allocate the subdevice structures.  alloc_subdevice() is a
388	 * convenient macro defined in comedidev.h.
389	 *
390	 * Allocate 1 AI + 1 AO + 2 DIO subdevs (24 lines per DIO)
391	 */
392	if (alloc_subdevices(dev, n_subdevs) < 0) {
393		printk("cannot allocate subdevice data structures\n");
394		return -ENOMEM;
395	}
396
397	/* First, AI */
398	sdev_no = 0;
399	s = dev->subdevices + sdev_no;
400	s->private = devpriv->sprivs + sdev_no;
401	s->maxdata = (1 << thisboard->ai_bits) - 1;
402	s->range_table = thisboard->ai_range_table;
403	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
404	s->type = COMEDI_SUBD_AI;
405	s->n_chan = thisboard->n_ai_chans;
406	s->len_chanlist = s->n_chan;
407	s->insn_read = thisboard->ai_rinsn;
408	subpriv->iobase = dev->iobase + 0;
409	/* initialize the resource enable register by clearing it */
410	outb(0, subpriv->iobase + 3);
411	outb(0, subpriv->iobase + 4 + 3);
412
413	/* Next, AO */
414	++sdev_no;
415	s = dev->subdevices + sdev_no;
416	s->private = devpriv->sprivs + sdev_no;
417	s->maxdata = (1 << thisboard->ao_bits) - 1;
418	s->range_table = thisboard->ao_range_table;
419	s->subdev_flags = SDF_READABLE;
420	s->type = COMEDI_SUBD_AO;
421	s->n_chan = thisboard->n_ao_chans;
422	s->len_chanlist = s->n_chan;
423	s->insn_read = thisboard->ao_rinsn;
424	s->insn_write = thisboard->ao_winsn;
425	subpriv->iobase = dev->iobase + 8;
426	/* initialize the resource enable register by clearing it */
427	outb(0, subpriv->iobase + 3);
428	outb(0, subpriv->iobase + 4 + 3);
429
430	++sdev_no;
431	port = 0;
432	asic = 0;
433	for (; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
434		int byte_no;
435
436		s = dev->subdevices + sdev_no;
437		s->private = devpriv->sprivs + sdev_no;
438		s->maxdata = 1;
439		s->range_table = &range_digital;
440		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
441		s->type = COMEDI_SUBD_DIO;
442		s->insn_bits = pcmmio_dio_insn_bits;
443		s->insn_config = pcmmio_dio_insn_config;
444		s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
445		subpriv->dio.intr.asic = -1;
446		subpriv->dio.intr.first_chan = -1;
447		subpriv->dio.intr.asic_chan = -1;
448		subpriv->dio.intr.num_asic_chans = -1;
449		subpriv->dio.intr.active = 0;
450		s->len_chanlist = 1;
451
452		/* save the ioport address for each 'port' of 8 channels in the
453		   subdevice */
454		for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
455			if (port >= PORTS_PER_ASIC) {
456				port = 0;
457				++asic;
458				thisasic_chanct = 0;
459			}
460			subpriv->iobases[byte_no] =
461			    devpriv->asics[asic].iobase + port;
462
463			if (thisasic_chanct <
464			    CHANS_PER_PORT * INTR_PORTS_PER_ASIC
465			    && subpriv->dio.intr.asic < 0) {
466				/* this is an interrupt subdevice, so setup the struct */
467				subpriv->dio.intr.asic = asic;
468				subpriv->dio.intr.active = 0;
469				subpriv->dio.intr.stop_count = 0;
470				subpriv->dio.intr.first_chan = byte_no * 8;
471				subpriv->dio.intr.asic_chan = thisasic_chanct;
472				subpriv->dio.intr.num_asic_chans =
473				    s->n_chan - subpriv->dio.intr.first_chan;
474				s->cancel = pcmmio_cancel;
475				s->do_cmd = pcmmio_cmd;
476				s->do_cmdtest = pcmmio_cmdtest;
477				s->len_chanlist =
478				    subpriv->dio.intr.num_asic_chans;
479			}
480			thisasic_chanct += CHANS_PER_PORT;
481		}
482		spin_lock_init(&subpriv->dio.intr.spinlock);
483
484		chans_left -= s->n_chan;
485
486		if (!chans_left) {
487			asic = 0;	/* reset the asic to our first asic, to do intr subdevs */
488			port = 0;
489		}
490
491	}
492
493	init_asics(dev);	/* clear out all the registers, basically */
494
495	for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
496		if (irq[asic]
497		    && request_irq(irq[asic], interrupt_pcmmio,
498				   IRQF_SHARED, thisboard->name, dev)) {
499			int i;
500			/* unroll the allocated irqs.. */
501			for (i = asic - 1; i >= 0; --i) {
502				free_irq(irq[i], dev);
503				devpriv->asics[i].irq = irq[i] = 0;
504			}
505			irq[asic] = 0;
506		}
507		devpriv->asics[asic].irq = irq[asic];
508	}
509
510	dev->irq = irq[0];	/* grr.. wish comedi dev struct supported multiple
511				   irqs.. */
512
513	if (irq[0]) {
514		printk("irq: %u ", irq[0]);
515		if (irq[1] && thisboard->dio_num_asics == 2)
516			printk("second ASIC irq: %u ", irq[1]);
517	} else {
518		printk("(IRQ mode disabled) ");
519	}
520
521	printk("attached\n");
522
523	return 1;
524}
525
526/*
527 * _detach is called to deconfigure a device.  It should deallocate
528 * resources.
529 * This function is also called when _attach() fails, so it should be
530 * careful not to release resources that were not necessarily
531 * allocated by _attach().  dev->private and dev->subdevices are
532 * deallocated automatically by the core.
533 */
534static int pcmmio_detach(struct comedi_device *dev)
535{
536	int i;
537
538	printk("comedi%d: %s: remove\n", dev->minor, driver.driver_name);
539	if (dev->iobase)
540		release_region(dev->iobase, thisboard->total_iosize);
541
542	for (i = 0; i < MAX_ASICS; ++i) {
543		if (devpriv && devpriv->asics[i].irq)
544			free_irq(devpriv->asics[i].irq, dev);
545	}
546
547	if (devpriv && devpriv->sprivs)
548		kfree(devpriv->sprivs);
549
550	return 0;
551}
552
553/* DIO devices are slightly special.  Although it is possible to
554 * implement the insn_read/insn_write interface, it is much more
555 * useful to applications if you implement the insn_bits interface.
556 * This allows packed reading/writing of the DIO channels.  The
557 * comedi core can convert between insn_bits and insn_read/write */
558static int pcmmio_dio_insn_bits(struct comedi_device *dev,
559				struct comedi_subdevice *s,
560				struct comedi_insn *insn, unsigned int *data)
561{
562	int byte_no;
563	if (insn->n != 2)
564		return -EINVAL;
565
566	/* NOTE:
567	   reading a 0 means this channel was high
568	   writine a 0 sets the channel high
569	   reading a 1 means this channel was low
570	   writing a 1 means set this channel low
571
572	   Therefore everything is always inverted. */
573
574	/* The insn data is a mask in data[0] and the new data
575	 * in data[1], each channel cooresponding to a bit. */
576
577#ifdef DAMMIT_ITS_BROKEN
578	/* DEBUG */
579	printk("write mask: %08x  data: %08x\n", data[0], data[1]);
580#endif
581
582	s->state = 0;
583
584	for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) {
585		/* address of 8-bit port */
586		unsigned long ioaddr = subpriv->iobases[byte_no],
587		    /* bit offset of port in 32-bit doubleword */
588		    offset = byte_no * 8;
589		/* this 8-bit port's data */
590		unsigned char byte = 0,
591		    /* The write mask for this port (if any) */
592		    write_mask_byte = (data[0] >> offset) & 0xff,
593		    /* The data byte for this port */
594		    data_byte = (data[1] >> offset) & 0xff;
595
596		byte = inb(ioaddr);	/* read all 8-bits for this port */
597
598#ifdef DAMMIT_ITS_BROKEN
599		/* DEBUG */
600		printk
601		    ("byte %d wmb %02x db %02x offset %02d io %04x, data_in %02x ",
602		     byte_no, (unsigned)write_mask_byte, (unsigned)data_byte,
603		     offset, ioaddr, (unsigned)byte);
604#endif
605
606		if (write_mask_byte) {
607			/* this byte has some write_bits -- so set the output lines */
608			byte &= ~write_mask_byte;	/* clear bits for write mask */
609			byte |= ~data_byte & write_mask_byte;	/* set to inverted data_byte */
610			/* Write out the new digital output state */
611			outb(byte, ioaddr);
612		}
613#ifdef DAMMIT_ITS_BROKEN
614		/* DEBUG */
615		printk("data_out_byte %02x\n", (unsigned)byte);
616#endif
617		/* save the digital input lines for this byte.. */
618		s->state |= ((unsigned int)byte) << offset;
619	}
620
621	/* now return the DIO lines to data[1] - note they came inverted! */
622	data[1] = ~s->state;
623
624#ifdef DAMMIT_ITS_BROKEN
625	/* DEBUG */
626	printk("s->state %08x data_out %08x\n", s->state, data[1]);
627#endif
628
629	return 2;
630}
631
632/* The input or output configuration of each digital line is
633 * configured by a special insn_config instruction.  chanspec
634 * contains the channel to be changed, and data[0] contains the
635 * value COMEDI_INPUT or COMEDI_OUTPUT. */
636static int pcmmio_dio_insn_config(struct comedi_device *dev,
637				  struct comedi_subdevice *s,
638				  struct comedi_insn *insn, unsigned int *data)
639{
640	int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no =
641	    chan % 8;
642	unsigned long ioaddr;
643	unsigned char byte;
644
645	/* Compute ioaddr for this channel */
646	ioaddr = subpriv->iobases[byte_no];
647
648	/* NOTE:
649	   writing a 0 an IO channel's bit sets the channel to INPUT
650	   and pulls the line high as well
651
652	   writing a 1 to an IO channel's  bit pulls the line low
653
654	   All channels are implicitly always in OUTPUT mode -- but when
655	   they are high they can be considered to be in INPUT mode..
656
657	   Thus, we only force channels low if the config request was INPUT,
658	   otherwise we do nothing to the hardware.    */
659
660	switch (data[0]) {
661	case INSN_CONFIG_DIO_OUTPUT:
662		/* save to io_bits -- don't actually do anything since
663		   all input channels are also output channels... */
664		s->io_bits |= 1 << chan;
665		break;
666	case INSN_CONFIG_DIO_INPUT:
667		/* write a 0 to the actual register representing the channel
668		   to set it to 'input'.  0 means "float high". */
669		byte = inb(ioaddr);
670		byte &= ~(1 << bit_no);
671				/**< set input channel to '0' */
672
673		/* write out byte -- this is the only time we actually affect the
674		   hardware as all channels are implicitly output -- but input
675		   channels are set to float-high */
676		outb(byte, ioaddr);
677
678		/* save to io_bits */
679		s->io_bits &= ~(1 << chan);
680		break;
681
682	case INSN_CONFIG_DIO_QUERY:
683		/* retreive from shadow register */
684		data[1] =
685		    (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
686		return insn->n;
687		break;
688
689	default:
690		return -EINVAL;
691		break;
692	}
693
694	return insn->n;
695}
696
697static void init_asics(struct comedi_device *dev)
698{				/* sets up an
699				   ASIC chip to defaults */
700	int asic;
701
702	for (asic = 0; asic < thisboard->dio_num_asics; ++asic) {
703		int port, page;
704		unsigned long baseaddr = devpriv->asics[asic].iobase;
705
706		switch_page(dev, asic, 0);	/* switch back to page 0 */
707
708		/* first, clear all the DIO port bits */
709		for (port = 0; port < PORTS_PER_ASIC; ++port)
710			outb(0, baseaddr + REG_PORT0 + port);
711
712		/* Next, clear all the paged registers for each page */
713		for (page = 1; page < NUM_PAGES; ++page) {
714			int reg;
715			/* now clear all the paged registers */
716			switch_page(dev, asic, page);
717			for (reg = FIRST_PAGED_REG;
718			     reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg)
719				outb(0, baseaddr + reg);
720		}
721
722		/* DEBUG  set rising edge interrupts on port0 of both asics */
723		/*switch_page(dev, asic, PAGE_POL);
724		   outb(0xff, baseaddr + REG_POL0);
725		   switch_page(dev, asic, PAGE_ENAB);
726		   outb(0xff, baseaddr + REG_ENAB0); */
727		/* END DEBUG */
728
729		switch_page(dev, asic, 0);	/* switch back to default page 0 */
730
731	}
732}
733
734static void switch_page(struct comedi_device *dev, int asic, int page)
735{
736	if (asic < 0 || asic >= thisboard->dio_num_asics)
737		return;		/* paranoia */
738	if (page < 0 || page >= NUM_PAGES)
739		return;		/* more paranoia */
740
741	devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
742	devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
743
744	/* now write out the shadow register */
745	outb(devpriv->asics[asic].pagelock,
746	     devpriv->asics[asic].iobase + REG_PAGELOCK);
747}
748
749#ifdef notused
750static void lock_port(struct comedi_device *dev, int asic, int port)
751{
752	if (asic < 0 || asic >= thisboard->dio_num_asics)
753		return;		/* paranoia */
754	if (port < 0 || port >= PORTS_PER_ASIC)
755		return;		/* more paranoia */
756
757	devpriv->asics[asic].pagelock |= 0x1 << port;
758	/* now write out the shadow register */
759	outb(devpriv->asics[asic].pagelock,
760	     devpriv->asics[asic].iobase + REG_PAGELOCK);
761	return;
762}
763
764static void unlock_port(struct comedi_device *dev, int asic, int port)
765{
766	if (asic < 0 || asic >= thisboard->dio_num_asics)
767		return;		/* paranoia */
768	if (port < 0 || port >= PORTS_PER_ASIC)
769		return;		/* more paranoia */
770	devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK;
771	/* now write out the shadow register */
772	outb(devpriv->asics[asic].pagelock,
773	     devpriv->asics[asic].iobase + REG_PAGELOCK);
774}
775#endif /* notused */
776
777static irqreturn_t interrupt_pcmmio(int irq, void *d)
778{
779	int asic, got1 = 0;
780	struct comedi_device *dev = (struct comedi_device *)d;
781
782	for (asic = 0; asic < MAX_ASICS; ++asic) {
783		if (irq == devpriv->asics[asic].irq) {
784			unsigned long flags;
785			unsigned triggered = 0;
786			unsigned long iobase = devpriv->asics[asic].iobase;
787			/* it is an interrupt for ASIC #asic */
788			unsigned char int_pend;
789
790			spin_lock_irqsave(&devpriv->asics[asic].spinlock,
791					  flags);
792
793			int_pend = inb(iobase + REG_INT_PENDING) & 0x07;
794
795			if (int_pend) {
796				int port;
797				for (port = 0; port < INTR_PORTS_PER_ASIC;
798				     ++port) {
799					if (int_pend & (0x1 << port)) {
800						unsigned char
801						    io_lines_with_edges = 0;
802						switch_page(dev, asic,
803							    PAGE_INT_ID);
804						io_lines_with_edges =
805						    inb(iobase +
806							REG_INT_ID0 + port);
807
808						if (io_lines_with_edges)
809							/* clear pending interrupt */
810							outb(0, iobase +
811							     REG_INT_ID0 +
812							     port);
813
814						triggered |=
815						    io_lines_with_edges <<
816						    port * 8;
817					}
818				}
819
820				++got1;
821			}
822
823			spin_unlock_irqrestore(&devpriv->asics[asic].spinlock,
824					       flags);
825
826			if (triggered) {
827				struct comedi_subdevice *s;
828				/* TODO here: dispatch io lines to subdevs with commands.. */
829				printk
830				    ("PCMMIO DEBUG: got edge detect interrupt %d asic %d which_chans: %06x\n",
831				     irq, asic, triggered);
832				for (s = dev->subdevices + 2;
833				     s < dev->subdevices + dev->n_subdevices;
834				     ++s) {
835					if (subpriv->dio.intr.asic == asic) {	/* this is an interrupt subdev, and it matches this asic! */
836						unsigned long flags;
837						unsigned oldevents;
838
839						spin_lock_irqsave(&subpriv->dio.
840								  intr.spinlock,
841								  flags);
842
843						oldevents = s->async->events;
844
845						if (subpriv->dio.intr.active) {
846							unsigned mytrig =
847							    ((triggered >>
848							      subpriv->dio.intr.asic_chan)
849							     &
850							     ((0x1 << subpriv->
851							       dio.intr.
852							       num_asic_chans) -
853							      1)) << subpriv->
854							    dio.intr.first_chan;
855							if (mytrig &
856							    subpriv->dio.
857							    intr.enabled_mask) {
858								unsigned int val
859								    = 0;
860								unsigned int n,
861								    ch, len;
862
863								len =
864								    s->
865								    async->cmd.chanlist_len;
866								for (n = 0;
867								     n < len;
868								     n++) {
869									ch = CR_CHAN(s->async->cmd.chanlist[n]);
870									if (mytrig & (1U << ch)) {
871										val |= (1U << n);
872									}
873								}
874								/* Write the scan to the buffer. */
875								if (comedi_buf_put(s->async, ((short *)&val)[0])
876								    &&
877								    comedi_buf_put
878								    (s->async,
879								     ((short *)
880								      &val)[1]))
881								{
882									s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
883								} else {
884									/* Overflow! Stop acquisition!! */
885									/* TODO: STOP_ACQUISITION_CALL_HERE!! */
886									pcmmio_stop_intr
887									    (dev,
888									     s);
889								}
890
891								/* Check for end of acquisition. */
892								if (!subpriv->dio.intr.continuous) {
893									/* stop_src == TRIG_COUNT */
894									if (subpriv->dio.intr.stop_count > 0) {
895										subpriv->dio.intr.stop_count--;
896										if (subpriv->dio.intr.stop_count == 0) {
897											s->async->events |= COMEDI_CB_EOA;
898											/* TODO: STOP_ACQUISITION_CALL_HERE!! */
899											pcmmio_stop_intr
900											    (dev,
901											     s);
902										}
903									}
904								}
905							}
906						}
907
908						spin_unlock_irqrestore
909						    (&subpriv->dio.intr.
910						     spinlock, flags);
911
912						if (oldevents !=
913						    s->async->events) {
914							comedi_event(dev, s);
915						}
916
917					}
918
919				}
920			}
921
922		}
923	}
924	if (!got1)
925		return IRQ_NONE;	/* interrupt from other source */
926	return IRQ_HANDLED;
927}
928
929static void pcmmio_stop_intr(struct comedi_device *dev,
930			     struct comedi_subdevice *s)
931{
932	int nports, firstport, asic, port;
933
934	asic = subpriv->dio.intr.asic;
935	if (asic < 0)
936		return;		/* not an interrupt subdev */
937
938	subpriv->dio.intr.enabled_mask = 0;
939	subpriv->dio.intr.active = 0;
940	s->async->inttrig = 0;
941	nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
942	firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
943	switch_page(dev, asic, PAGE_ENAB);
944	for (port = firstport; port < firstport + nports; ++port) {
945		/* disable all intrs for this subdev.. */
946		outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
947	}
948}
949
950static int pcmmio_start_intr(struct comedi_device *dev,
951			     struct comedi_subdevice *s)
952{
953	if (!subpriv->dio.intr.continuous && subpriv->dio.intr.stop_count == 0) {
954		/* An empty acquisition! */
955		s->async->events |= COMEDI_CB_EOA;
956		subpriv->dio.intr.active = 0;
957		return 1;
958	} else {
959		unsigned bits = 0, pol_bits = 0, n;
960		int nports, firstport, asic, port;
961		struct comedi_cmd *cmd = &s->async->cmd;
962
963		asic = subpriv->dio.intr.asic;
964		if (asic < 0)
965			return 1;	/* not an interrupt
966					   subdev */
967		subpriv->dio.intr.enabled_mask = 0;
968		subpriv->dio.intr.active = 1;
969		nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
970		firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
971		if (cmd->chanlist) {
972			for (n = 0; n < cmd->chanlist_len; n++) {
973				bits |= (1U << CR_CHAN(cmd->chanlist[n]));
974				pol_bits |= (CR_AREF(cmd->chanlist[n])
975					     || CR_RANGE(cmd->
976							 chanlist[n]) ? 1U : 0U)
977				    << CR_CHAN(cmd->chanlist[n]);
978			}
979		}
980		bits &= ((0x1 << subpriv->dio.intr.num_asic_chans) -
981			 1) << subpriv->dio.intr.first_chan;
982		subpriv->dio.intr.enabled_mask = bits;
983
984		{		/* the below code configures the board to use a specific IRQ from 0-15. */
985			unsigned char b;
986			/* set resource enable register to enable IRQ operation */
987			outb(1 << 4, dev->iobase + 3);
988			/* set bits 0-3 of b to the irq number from 0-15 */
989			b = dev->irq & ((1 << 4) - 1);
990			outb(b, dev->iobase + 2);
991			/* done, we told the board what irq to use */
992		}
993
994		switch_page(dev, asic, PAGE_ENAB);
995		for (port = firstport; port < firstport + nports; ++port) {
996			unsigned enab =
997			    bits >> (subpriv->dio.intr.first_chan + (port -
998								     firstport)
999				     * 8) & 0xff, pol =
1000			    pol_bits >> (subpriv->dio.intr.first_chan +
1001					 (port - firstport) * 8) & 0xff;
1002			/* set enab intrs for this subdev.. */
1003			outb(enab,
1004			     devpriv->asics[asic].iobase + REG_ENAB0 + port);
1005			switch_page(dev, asic, PAGE_POL);
1006			outb(pol,
1007			     devpriv->asics[asic].iobase + REG_ENAB0 + port);
1008		}
1009	}
1010	return 0;
1011}
1012
1013static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
1014{
1015	unsigned long flags;
1016
1017	spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
1018	if (subpriv->dio.intr.active)
1019		pcmmio_stop_intr(dev, s);
1020	spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
1021
1022	return 0;
1023}
1024
1025/*
1026 * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
1027 */
1028static int
1029pcmmio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
1030			  unsigned int trignum)
1031{
1032	unsigned long flags;
1033	int event = 0;
1034
1035	if (trignum != 0)
1036		return -EINVAL;
1037
1038	spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
1039	s->async->inttrig = 0;
1040	if (subpriv->dio.intr.active) {
1041		event = pcmmio_start_intr(dev, s);
1042	}
1043	spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
1044
1045	if (event) {
1046		comedi_event(dev, s);
1047	}
1048
1049	return 1;
1050}
1051
1052/*
1053 * 'do_cmd' function for an 'INTERRUPT' subdevice.
1054 */
1055static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1056{
1057	struct comedi_cmd *cmd = &s->async->cmd;
1058	unsigned long flags;
1059	int event = 0;
1060
1061	spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
1062	subpriv->dio.intr.active = 1;
1063
1064	/* Set up end of acquisition. */
1065	switch (cmd->stop_src) {
1066	case TRIG_COUNT:
1067		subpriv->dio.intr.continuous = 0;
1068		subpriv->dio.intr.stop_count = cmd->stop_arg;
1069		break;
1070	default:
1071		/* TRIG_NONE */
1072		subpriv->dio.intr.continuous = 1;
1073		subpriv->dio.intr.stop_count = 0;
1074		break;
1075	}
1076
1077	/* Set up start of acquisition. */
1078	switch (cmd->start_src) {
1079	case TRIG_INT:
1080		s->async->inttrig = pcmmio_inttrig_start_intr;
1081		break;
1082	default:
1083		/* TRIG_NOW */
1084		event = pcmmio_start_intr(dev, s);
1085		break;
1086	}
1087	spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
1088
1089	if (event) {
1090		comedi_event(dev, s);
1091	}
1092
1093	return 0;
1094}
1095
1096static int
1097pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
1098	       struct comedi_cmd *cmd)
1099{
1100	return comedi_pcm_cmdtest(dev, s, cmd);
1101}
1102
1103static int adc_wait_ready(unsigned long iobase)
1104{
1105	unsigned long retry = 100000;
1106	while (retry--)
1107		if (inb(iobase + 3) & 0x80)
1108			return 0;
1109	return 1;
1110}
1111
1112/* All this is for AI and AO */
1113static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
1114		    struct comedi_insn *insn, unsigned int *data)
1115{
1116	int n;
1117	unsigned long iobase = subpriv->iobase;
1118
1119	/*
1120	   1. write the CMD byte (to BASE+2)
1121	   2. read junk lo byte (BASE+0)
1122	   3. read junk hi byte (BASE+1)
1123	   4. (mux settled so) write CMD byte again (BASE+2)
1124	   5. read valid lo byte(BASE+0)
1125	   6. read valid hi byte(BASE+1)
1126
1127	   Additionally note that the BASE += 4 if the channel >= 8
1128	 */
1129
1130	/* convert n samples */
1131	for (n = 0; n < insn->n; n++) {
1132		unsigned chan = CR_CHAN(insn->chanspec), range =
1133		    CR_RANGE(insn->chanspec), aref = CR_AREF(insn->chanspec);
1134		unsigned char command_byte = 0;
1135		unsigned iooffset = 0;
1136		short sample, adc_adjust = 0;
1137
1138		if (chan > 7)
1139			chan -= 8, iooffset = 4;	/* use the second dword for channels > 7 */
1140
1141		if (aref != AREF_DIFF) {
1142			aref = AREF_GROUND;
1143			command_byte |= 1 << 7;	/* set bit 7 to indicate single-ended */
1144		}
1145		if (range < 2)
1146			adc_adjust = 0x8000;	/* bipolar ranges (-5,5 .. -10,10 need to be adjusted -- that is.. they need to wrap around by adding 0x8000 */
1147
1148		if (chan % 2) {
1149			command_byte |= 1 << 6;	/* odd-numbered channels have bit 6 set */
1150		}
1151
1152		/* select the channel, bits 4-5 == chan/2 */
1153		command_byte |= ((chan / 2) & 0x3) << 4;
1154
1155		/* set the range, bits 2-3 */
1156		command_byte |= (range & 0x3) << 2;
1157
1158		/* need to do this twice to make sure mux settled */
1159		outb(command_byte, iobase + iooffset + 2);	/* chan/range/aref select */
1160
1161		adc_wait_ready(iobase + iooffset);	/* wait for the adc to say it finised the conversion */
1162
1163		outb(command_byte, iobase + iooffset + 2);	/* select the chan/range/aref AGAIN */
1164
1165		adc_wait_ready(iobase + iooffset);
1166
1167		sample = inb(iobase + iooffset + 0);	/* read data lo byte */
1168		sample |= inb(iobase + iooffset + 1) << 8;	/* read data hi byte */
1169		sample += adc_adjust;	/* adjustment .. munge data */
1170		data[n] = sample;
1171	}
1172	/* return the number of samples read/written */
1173	return n;
1174}
1175
1176static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
1177		    struct comedi_insn *insn, unsigned int *data)
1178{
1179	int n;
1180	for (n = 0; n < insn->n; n++) {
1181		unsigned chan = CR_CHAN(insn->chanspec);
1182		if (chan < s->n_chan)
1183			data[n] = subpriv->ao.shadow_samples[chan];
1184	}
1185	return n;
1186}
1187
1188static int wait_dac_ready(unsigned long iobase)
1189{
1190	unsigned long retry = 100000L;
1191
1192	/* This may seem like an absurd way to handle waiting and violates the
1193	   "no busy waiting" policy. The fact is that the hardware is
1194	   normally so fast that we usually only need one time through the loop
1195	   anyway. The longer timeout is for rare occasions and for detecting
1196	   non-existant hardware.  */
1197
1198	while (retry--) {
1199		if (inb(iobase + 3) & 0x80)
1200			return 0;
1201
1202	}
1203	return 1;
1204}
1205
1206static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
1207		    struct comedi_insn *insn, unsigned int *data)
1208{
1209	int n;
1210	unsigned iobase = subpriv->iobase, iooffset = 0;
1211
1212	for (n = 0; n < insn->n; n++) {
1213		unsigned chan = CR_CHAN(insn->chanspec), range =
1214		    CR_RANGE(insn->chanspec);
1215		if (chan < s->n_chan) {
1216			unsigned char command_byte = 0, range_byte =
1217			    range & ((1 << 4) - 1);
1218			if (chan >= 4)
1219				chan -= 4, iooffset += 4;
1220			/* set the range.. */
1221			outb(range_byte, iobase + iooffset + 0);
1222			outb(0, iobase + iooffset + 1);
1223
1224			/* tell it to begin */
1225			command_byte = (chan << 1) | 0x60;
1226			outb(command_byte, iobase + iooffset + 2);
1227
1228			wait_dac_ready(iobase + iooffset);
1229
1230			outb(data[n] & 0xff, iobase + iooffset + 0);	/* low order byte */
1231			outb((data[n] >> 8) & 0xff, iobase + iooffset + 1);	/* high order byte */
1232			command_byte = 0x70 | (chan << 1);	/* set bit 4 of command byte to indicate data is loaded and trigger conversion */
1233			/* trigger converion */
1234			outb(command_byte, iobase + iooffset + 2);
1235
1236			wait_dac_ready(iobase + iooffset);
1237
1238			subpriv->ao.shadow_samples[chan] = data[n];	/* save to shadow register for ao_rinsn */
1239		}
1240	}
1241	return n;
1242}
1243
1244/*
1245 * A convenient macro that defines init_module() and cleanup_module(),
1246 * as necessary.
1247 */
1248COMEDI_INITCLEANUP(driver);
1249