pcmuio.c revision 89aaa92adffa5c57d9c2a545c7cb9809ddd3b615
16baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
29e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * pcmuio.c
39e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Comedi driver for Winsystems PC-104 based 48/96-channel DIO boards.
49e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten *
59e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * COMEDI - Linux Control and Measurement Device Interface
69e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Copyright (C) 2006 Calin A. Culianu <calin@ajvar.org>
79e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten *
89e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * This program is free software; you can redistribute it and/or modify
99e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * it under the terms of the GNU General Public License as published by
109e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * the Free Software Foundation; either version 2 of the License, or
119e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * (at your option) any later version.
129e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten *
139e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * This program is distributed in the hope that it will be useful,
149e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * but WITHOUT ANY WARRANTY; without even the implied warranty of
159e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
169e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * GNU General Public License for more details.
179e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten */
186baef150380d561a4d695a6be4fc509821c23611Calin Culianu
196baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
209e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Driver: pcmuio
219e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Description: Winsystems PC-104 based 48/96-channel DIO boards.
229e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Devices: (Winsystems) PCM-UIO48A [pcmuio48]
239e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten *	    (Winsystems) PCM-UIO96A [pcmuio96]
249e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Author: Calin Culianu <calin@ajvar.org>
259e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Updated: Fri, 13 Jan 2006 12:01:01 -0500
269e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Status: works
279e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten *
289e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * A driver for the relatively straightforward-to-program PCM-UIO48A and
299e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * PCM-UIO96A boards from Winsystems. These boards use either one or two
309e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * (in the 96-DIO version) WS16C48 ASIC HighDensity I/O Chips (HDIO). This
319e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * chip is interesting in that each I/O line is individually programmable
329e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * for INPUT or OUTPUT (thus comedi_dio_config can be done on a per-channel
339e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * basis). Also, each chip supports edge-triggered interrupts for the first
349e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 24 I/O lines. Of course, since the 96-channel version of the board has
359e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * two ASICs, it can detect polarity changes on up to 48 I/O lines. Since
369e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * this is essentially an (non-PnP) ISA board, I/O Address and IRQ selection
379e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * are done through jumpers on the board. You need to pass that information
389e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * to this driver as the first and second comedi_config option, respectively.
399e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Note that the 48-channel version uses 16 bytes of IO memory and the 96-
409e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * channel version uses 32-bytes (in case you are worried about conflicts).
419e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * The 48-channel board is split into two 24-channel comedi subdevices. The
429e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 96-channel board is split into 4 24-channel DIO subdevices.
439e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten *
449e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Note that IRQ support has been added, but it is untested.
459e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten *
469e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * To use edge-detection IRQ support, pass the IRQs of both ASICS (for the
479e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * 96 channel version) or just 1 ASIC (for 48-channel version). Then, use
489e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * comedi_commands with TRIG_NOW. Your callback will be called each time an
499e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * edge is triggered, and the data values will be two sample_t's, which
509e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * should be concatenated to form one 32-bit unsigned int.  This value is
519e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * the mask of channels that had edges detected from your channel list. Note
529e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * that the bits positions in the mask correspond to positions in your
539e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * chanlist when you specified the command and *not* channel id's!
549e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten *
559e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * To set the polarity of the edge-detection interrupts pass a nonzero value
569e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * for either CR_RANGE or CR_AREF for edge-up polarity, or a zero value for
579e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * both CR_RANGE and CR_AREF if you want edge-down polarity.
589e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten *
599e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * In the 48-channel version:
609e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten *
619e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * On subdev 0, the first 24 channels channels are edge-detect channels.
629e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten *
639e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * In the 96-channel board you have the following channels that can do edge
649e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * detection:
659e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten *
669e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * subdev 0, channels 0-24  (first 24 channels of 1st ASIC)
679e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * subdev 2, channels 0-24  (first 24 channels of 2nd ASIC)
689e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten *
699e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten * Configuration Options:
709e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten *  [0] - I/O port base address
719e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten *  [1] - IRQ (for first ASIC, or first 24 channels)
729e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten *  [2] - IRQ (for second ASIC, pcmuio96 only - IRQ for chans 48-72
739e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten *             can be the same as first irq!)
749e1087b5ae4c31c812e3f8a35256d7922a1cdbd6H Hartley Sweeten */
756baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7625436dc9d84f1be60ff549c9ab712bba2835f284Greg Kroah-Hartman#include <linux/interrupt.h>
775a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
786baef150380d561a4d695a6be4fc509821c23611Calin Culianu
79f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten#include "../comedidev.h"
8033782dd5edf8db3cdb7c81a3523bf743dd0209b7H Hartley Sweeten
81f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten#include "comedi_fc.h"
826baef150380d561a4d695a6be4fc509821c23611Calin Culianu
83f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten/*
84f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten * Register I/O map
85f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten *
86f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten * Offset    Page 0       Page 1       Page 2       Page 3
87f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten * ------  -----------  -----------  -----------  -----------
88f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten *  0x00   Port 0 I/O   Port 0 I/O   Port 0 I/O   Port 0 I/O
89f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten *  0x01   Port 1 I/O   Port 1 I/O   Port 1 I/O   Port 1 I/O
90f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten *  0x02   Port 2 I/O   Port 2 I/O   Port 2 I/O   Port 2 I/O
91f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten *  0x03   Port 3 I/O   Port 3 I/O   Port 3 I/O   Port 3 I/O
92f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten *  0x04   Port 4 I/O   Port 4 I/O   Port 4 I/O   Port 4 I/O
93f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten *  0x05   Port 5 I/O   Port 5 I/O   Port 5 I/O   Port 5 I/O
94f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten *  0x06   INT_PENDING  INT_PENDING  INT_PENDING  INT_PENDING
95f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten *  0x07    Page/Lock    Page/Lock    Page/Lock    Page/Lock
96f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten *  0x08       N/A         POL_0       ENAB_0       INT_ID0
97f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten *  0x09       N/A         POL_1       ENAB_1       INT_ID1
98f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten *  0x0a       N/A         POL_2       ENAB_2       INT_ID2
99f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten */
100f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten#define PCMUIO_PORT_REG(x)		(0x00 + (x))
101f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten#define PCMUIO_INT_PENDING_REG		0x06
102f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten#define PCMUIO_PAGE_LOCK_REG		0x07
103f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten#define PCMUIO_LOCK_PORT(x)		((1 << (x)) & 0x3f)
104f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten#define PCMUIO_PAGE(x)			(((x) & 0x3) << 6)
105f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten#define PCMUIO_PAGE_MASK		PCMUIO_PAGE(3)
106f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten#define PCMUIO_PAGE_POL			1
107f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten#define PCMUIO_PAGE_ENAB		2
108f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten#define PCMUIO_PAGE_INT_ID		3
109f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten#define PCMUIO_PAGE_REG(x)		(0x08 + (x))
110f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten
111288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define CHANS_PER_PORT		8
112288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define PORTS_PER_ASIC		6
113288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten/* number of channels per comedi subdevice */
114288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define MAX_CHANS_PER_SUBDEV	24
115288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define PORTS_PER_SUBDEV	(MAX_CHANS_PER_SUBDEV / CHANS_PER_PORT)
116288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define CHANS_PER_ASIC		(CHANS_PER_PORT * PORTS_PER_ASIC)
117288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define INTR_CHANS_PER_ASIC	24
118288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define INTR_PORTS_PER_SUBDEV	(INTR_CHANS_PER_ASIC / CHANS_PER_PORT)
119288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define MAX_DIO_CHANS		(PORTS_PER_ASIC * 2 * CHANS_PER_PORT)
120288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define MAX_ASICS		(MAX_DIO_CHANS / CHANS_PER_ASIC)
1216baef150380d561a4d695a6be4fc509821c23611Calin Culianu
122288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten/* IO Memory sizes */
123288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define ASIC_IOSIZE		0x10
124288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define PCMUIO48_IOSIZE		ASIC_IOSIZE
125288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define PCMUIO96_IOSIZE		(ASIC_IOSIZE * 2)
1266baef150380d561a4d695a6be4fc509821c23611Calin Culianu
12770a6001aeffeaa12f2a1c21470e8f3bdfb6ef8e7Bill Pembertonstruct pcmuio_board {
1286baef150380d561a4d695a6be4fc509821c23611Calin Culianu	const char *name;
1296baef150380d561a4d695a6be4fc509821c23611Calin Culianu	const int num_asics;
13070a6001aeffeaa12f2a1c21470e8f3bdfb6ef8e7Bill Pemberton};
1316baef150380d561a4d695a6be4fc509821c23611Calin Culianu
132fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweetenstatic const struct pcmuio_board pcmuio_boards[] = {
133fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten	{
134fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten		.name		= "pcmuio48",
135fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten		.num_asics	= 1,
136fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten	}, {
137fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten		.name		= "pcmuio96",
138fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten		.num_asics	= 2,
139fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten	},
140fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten};
141fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten
142e15849e54405152087cd343437747db8d931fcd7Bill Pembertonstruct pcmuio_subdev_private {
1436baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* The below is only used for intr subdevices */
1446baef150380d561a4d695a6be4fc509821c23611Calin Culianu	struct {
145365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten		/* if non-negative, this subdev has an interrupt asic */
146365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten		int asic;
147365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten		/*
148365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten		 * subdev-relative channel mask for channels
149365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten		 * we are interested in
150365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten		 */
151365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten		int enabled_mask;
1526baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int active;
1536baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int stop_count;
1546baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int continuous;
1556baef150380d561a4d695a6be4fc509821c23611Calin Culianu		spinlock_t spinlock;
1566baef150380d561a4d695a6be4fc509821c23611Calin Culianu	} intr;
157e15849e54405152087cd343437747db8d931fcd7Bill Pemberton};
1586baef150380d561a4d695a6be4fc509821c23611Calin Culianu
159055f6636d9eb27bc13236e07739e019496c21221Bill Pembertonstruct pcmuio_private {
1606baef150380d561a4d695a6be4fc509821c23611Calin Culianu	struct {
1616baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned int irq;
1626baef150380d561a4d695a6be4fc509821c23611Calin Culianu		spinlock_t spinlock;
1636baef150380d561a4d695a6be4fc509821c23611Calin Culianu	} asics[MAX_ASICS];
164e15849e54405152087cd343437747db8d931fcd7Bill Pemberton	struct pcmuio_subdev_private *sprivs;
165055f6636d9eb27bc13236e07739e019496c21221Bill Pemberton};
1666baef150380d561a4d695a6be4fc509821c23611Calin Culianu
167e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweetenstatic void pcmuio_write(struct comedi_device *dev, unsigned int val,
168e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten			 int asic, int page, int port)
169e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten{
170e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten	unsigned long iobase = dev->iobase + (asic * ASIC_IOSIZE);
171e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten
172e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten	if (page == 0) {
173e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten		/* Port registers are valid for any page */
174e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten		outb(val & 0xff, iobase + PCMUIO_PORT_REG(port + 0));
175e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten		outb((val >> 8) & 0xff, iobase + PCMUIO_PORT_REG(port + 1));
176e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten		outb((val >> 16) & 0xff, iobase + PCMUIO_PORT_REG(port + 2));
177e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten	} else {
178e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten		outb(PCMUIO_PAGE(page), iobase + PCMUIO_PAGE_LOCK_REG);
179e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten		outb(val & 0xff, iobase + PCMUIO_PAGE_REG(0));
180e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten		outb((val >> 8) & 0xff, iobase + PCMUIO_PAGE_REG(1));
181e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten		outb((val >> 16) & 0xff, iobase + PCMUIO_PAGE_REG(2));
182e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten	}
183e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten}
184e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten
18589aaa92adffa5c57d9c2a545c7cb9809ddd3b615H Hartley Sweetenstatic unsigned int pcmuio_read(struct comedi_device *dev,
18689aaa92adffa5c57d9c2a545c7cb9809ddd3b615H Hartley Sweeten				int asic, int page, int port)
18789aaa92adffa5c57d9c2a545c7cb9809ddd3b615H Hartley Sweeten{
18889aaa92adffa5c57d9c2a545c7cb9809ddd3b615H Hartley Sweeten	unsigned long iobase = dev->iobase + (asic * ASIC_IOSIZE);
18989aaa92adffa5c57d9c2a545c7cb9809ddd3b615H Hartley Sweeten	unsigned int val;
19089aaa92adffa5c57d9c2a545c7cb9809ddd3b615H Hartley Sweeten
19189aaa92adffa5c57d9c2a545c7cb9809ddd3b615H Hartley Sweeten	if (page == 0) {
19289aaa92adffa5c57d9c2a545c7cb9809ddd3b615H Hartley Sweeten		/* Port registers are valid for any page */
19389aaa92adffa5c57d9c2a545c7cb9809ddd3b615H Hartley Sweeten		val = inb(iobase + PCMUIO_PORT_REG(port + 0));
19489aaa92adffa5c57d9c2a545c7cb9809ddd3b615H Hartley Sweeten		val |= (inb(iobase + PCMUIO_PORT_REG(port + 1)) << 8);
19589aaa92adffa5c57d9c2a545c7cb9809ddd3b615H Hartley Sweeten		val |= (inb(iobase + PCMUIO_PORT_REG(port + 2)) << 16);
19689aaa92adffa5c57d9c2a545c7cb9809ddd3b615H Hartley Sweeten	} else {
19789aaa92adffa5c57d9c2a545c7cb9809ddd3b615H Hartley Sweeten		outb(PCMUIO_PAGE(page), iobase + PCMUIO_PAGE_LOCK_REG);
19889aaa92adffa5c57d9c2a545c7cb9809ddd3b615H Hartley Sweeten		val = inb(iobase + PCMUIO_PAGE_REG(0));
19989aaa92adffa5c57d9c2a545c7cb9809ddd3b615H Hartley Sweeten		val |= (inb(iobase + PCMUIO_PAGE_REG(1)) << 8);
20089aaa92adffa5c57d9c2a545c7cb9809ddd3b615H Hartley Sweeten		val |= (inb(iobase + PCMUIO_PAGE_REG(2)) << 16);
20189aaa92adffa5c57d9c2a545c7cb9809ddd3b615H Hartley Sweeten	}
20289aaa92adffa5c57d9c2a545c7cb9809ddd3b615H Hartley Sweeten
20389aaa92adffa5c57d9c2a545c7cb9809ddd3b615H Hartley Sweeten	return val;
20489aaa92adffa5c57d9c2a545c7cb9809ddd3b615H Hartley Sweeten}
20589aaa92adffa5c57d9c2a545c7cb9809ddd3b615H Hartley Sweeten
2060a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcmuio_dio_insn_bits(struct comedi_device *dev,
2070a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				struct comedi_subdevice *s,
2080a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				struct comedi_insn *insn, unsigned int *data)
2096baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
210c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten	int asic = s->index / 2;
211c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten	int port = (s->index % 2) ? 3 : 0;
212c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten	unsigned long iobase = dev->iobase + (asic * ASIC_IOSIZE);
2136baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int byte_no;
2146baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2156baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* NOTE:
2166baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   reading a 0 means this channel was high
2176baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   writine a 0 sets the channel high
2186baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   reading a 1 means this channel was low
2196baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   writing a 1 means set this channel low
2206baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2216baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   Therefore everything is always inverted. */
2226baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2236baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* The insn data is a mask in data[0] and the new data
2246baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * in data[1], each channel cooresponding to a bit. */
2256baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2266baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s->state = 0;
2276baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2286baef150380d561a4d695a6be4fc509821c23611Calin Culianu	for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) {
229c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten		/* bit offset of port in 32-bit doubleword */
230c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten		unsigned long offset = byte_no * 8;
2316baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* this 8-bit port's data */
2326baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned char byte = 0,
2330a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    /* The write mask for this port (if any) */
2340a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    write_mask_byte = (data[0] >> offset) & 0xff,
2350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    /* The data byte for this port */
2360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    data_byte = (data[1] >> offset) & 0xff;
2376baef150380d561a4d695a6be4fc509821c23611Calin Culianu
238c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten		byte = inb(iobase + PCMUIO_PORT_REG(port + byte_no));
2396baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2406baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (write_mask_byte) {
241365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten			byte &= ~write_mask_byte;
242365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten			byte |= ~data_byte & write_mask_byte;
243c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten			outb(byte, iobase + PCMUIO_PORT_REG(port + byte_no));
2446baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
2456baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* save the digital input lines for this byte.. */
2466baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->state |= ((unsigned int)byte) << offset;
2476baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
2486baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2496baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* now return the DIO lines to data[1] - note they came inverted! */
2506baef150380d561a4d695a6be4fc509821c23611Calin Culianu	data[1] = ~s->state;
2516baef150380d561a4d695a6be4fc509821c23611Calin Culianu
252a2714e3e42e746d6c8525c35fdcc58fb60c2830dH Hartley Sweeten	return insn->n;
2536baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
2546baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2550a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcmuio_dio_insn_config(struct comedi_device *dev,
2560a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  struct comedi_subdevice *s,
2570a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  struct comedi_insn *insn, unsigned int *data)
2586baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
259c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten	int asic = s->index / 2;
260c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten	int port = (s->index % 2) ? 3 : 0;
261c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten	unsigned long iobase = dev->iobase + (asic * ASIC_IOSIZE);
262c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten	unsigned int chan = CR_CHAN(insn->chanspec);
263c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten	int byte_no = chan / 8;
264c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten	int bit_no = chan % 8;
2656baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned char byte;
2666baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2676baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* NOTE:
2686baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   writing a 0 an IO channel's bit sets the channel to INPUT
2696baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   and pulls the line high as well
2706baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2716baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   writing a 1 to an IO channel's  bit pulls the line low
2726baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2736baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   All channels are implicitly always in OUTPUT mode -- but when
2746baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   they are high they can be considered to be in INPUT mode..
2756baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2766baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   Thus, we only force channels low if the config request was INPUT,
2776baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   otherwise we do nothing to the hardware.    */
2786baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2796baef150380d561a4d695a6be4fc509821c23611Calin Culianu	switch (data[0]) {
2806baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case INSN_CONFIG_DIO_OUTPUT:
2816baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* save to io_bits -- don't actually do anything since
2826baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   all input channels are also output channels... */
2836baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->io_bits |= 1 << chan;
2846baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
2856baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case INSN_CONFIG_DIO_INPUT:
2866baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* write a 0 to the actual register representing the channel
2876baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   to set it to 'input'.  0 means "float high". */
288c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten		byte = inb(iobase + PCMUIO_PORT_REG(port + byte_no));
2896baef150380d561a4d695a6be4fc509821c23611Calin Culianu		byte &= ~(1 << bit_no);
2906baef150380d561a4d695a6be4fc509821c23611Calin Culianu				/**< set input channel to '0' */
2916baef150380d561a4d695a6be4fc509821c23611Calin Culianu
292365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten		/*
293365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten		 * write out byte
294365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten		 * This is the only time we actually affect the hardware
295365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten		 * as all channels are implicitly output -- but input
296365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten		 * channels are set to float-high.
297365c473e1da54e209aa8c01da2084c896f18fb20H Hartley Sweeten		 */
298c4ad65e6ce8a9cfe78d4c4b06b915c17a27ba011H Hartley Sweeten		outb(byte, iobase + PCMUIO_PORT_REG(port + byte_no));
2996baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3006baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* save to io_bits */
3016baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->io_bits &= ~(1 << chan);
3026baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
3036baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3046baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case INSN_CONFIG_DIO_QUERY:
30525985edcedea6396277003854657b5f3cb31a628Lucas De Marchi		/* retrieve from shadow register */
3066baef150380d561a4d695a6be4fc509821c23611Calin Culianu		data[1] =
3070a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
3086baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return insn->n;
3096baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
3106baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3116baef150380d561a4d695a6be4fc509821c23611Calin Culianu	default:
3126baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return -EINVAL;
3136baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
3146baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
3156baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3166baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return insn->n;
3176baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
3186baef150380d561a4d695a6be4fc509821c23611Calin Culianu
319da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void init_asics(struct comedi_device *dev)
320e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten{
321a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	const struct pcmuio_board *board = comedi_board(dev);
3226baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int asic;
3236baef150380d561a4d695a6be4fc509821c23611Calin Culianu
324a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	for (asic = 0; asic < board->num_asics; ++asic) {
3256baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* first, clear all the DIO port bits */
326e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten		pcmuio_write(dev, 0, asic, 0, 0);
327e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten		pcmuio_write(dev, 0, asic, 0, 3);
3286baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3296baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* Next, clear all the paged registers for each page */
330e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten		pcmuio_write(dev, 0, asic, PCMUIO_PAGE_POL, 0);
331e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten		pcmuio_write(dev, 0, asic, PCMUIO_PAGE_ENAB, 0);
332e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten		pcmuio_write(dev, 0, asic, PCMUIO_PAGE_INT_ID, 0);
3336baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
3346baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
3356baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3366b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweetenstatic void pcmuio_stop_intr(struct comedi_device *dev,
3376b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			     struct comedi_subdevice *s)
3386b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten{
3398099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	struct pcmuio_subdev_private *subpriv = s->private;
340e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten	int asic;
3416b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
3426b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	asic = subpriv->intr.asic;
3436b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	if (asic < 0)
3446b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		return;		/* not an interrupt subdev */
3456b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
3466b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	subpriv->intr.enabled_mask = 0;
3476b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	subpriv->intr.active = 0;
348920e2ffbe243fb0555b2c238e26fe7dbc03db98cH Hartley Sweeten	s->async->inttrig = NULL;
349e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten
350e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten	/* disable all intrs for this subdev.. */
351e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten	pcmuio_write(dev, 0, asic, PCMUIO_PAGE_ENAB, 0);
3526b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten}
3536b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
3543b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweetenstatic void pcmuio_handle_intr_subdev(struct comedi_device *dev,
3553b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				      struct comedi_subdevice *s,
3563b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				      unsigned triggered)
3573b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten{
3583b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	struct pcmuio_subdev_private *subpriv = s->private;
3593b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	unsigned int len = s->async->cmd.chanlist_len;
3603b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	unsigned oldevents = s->async->events;
3613b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	unsigned int val = 0;
3623b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	unsigned long flags;
3633b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	unsigned mytrig;
3643b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	unsigned int i;
3653b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
3663b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	spin_lock_irqsave(&subpriv->intr.spinlock, flags);
3673b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
3683b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	if (!subpriv->intr.active)
3693b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		goto done;
3703b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
37143d70ce9ac772647baf8aadef1aa0f071bfe7f36H Hartley Sweeten	mytrig = triggered;
372dbe9c7929c6c0021414d61f85fe4e2f20f069e1cH Hartley Sweeten	mytrig &= ((0x1 << s->n_chan) - 1);
3733b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
3743b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	if (!(mytrig & subpriv->intr.enabled_mask))
3753b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		goto done;
3763b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
3773b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	for (i = 0; i < len; i++) {
3783b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		unsigned int chan = CR_CHAN(s->async->cmd.chanlist[i]);
3793b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		if (mytrig & (1U << chan))
3803b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			val |= (1U << i);
3813b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	}
3823b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
3833b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	/* Write the scan to the buffer. */
3843b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	if (comedi_buf_put(s->async, ((short *)&val)[0]) &&
3853b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	    comedi_buf_put(s->async, ((short *)&val)[1])) {
3863b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
3873b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	} else {
3883b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		/* Overflow! Stop acquisition!! */
3893b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		/* TODO: STOP_ACQUISITION_CALL_HERE!! */
3903b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		pcmuio_stop_intr(dev, s);
3913b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	}
3923b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
3933b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	/* Check for end of acquisition. */
3943b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	if (!subpriv->intr.continuous) {
3953b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		/* stop_src == TRIG_COUNT */
3963b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		if (subpriv->intr.stop_count > 0) {
3973b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			subpriv->intr.stop_count--;
3983b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			if (subpriv->intr.stop_count == 0) {
3993b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				s->async->events |= COMEDI_CB_EOA;
4003b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				/* TODO: STOP_ACQUISITION_CALL_HERE!! */
4013b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				pcmuio_stop_intr(dev, s);
4023b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			}
4033b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		}
4043b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	}
4053b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
4063b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweetendone:
4073b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
4083b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
4093b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	if (oldevents != s->async->events)
4103b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		comedi_event(dev, s);
4113b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten}
4123b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
4133b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweetenstatic int pcmuio_handle_asic_interrupt(struct comedi_device *dev, int asic)
4146baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
4159a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten	struct pcmuio_private *devpriv = dev->private;
4168099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	struct pcmuio_subdev_private *subpriv;
417021314f82405594344b857e13e0493e11dad7298H Hartley Sweeten	unsigned long iobase = dev->iobase + (asic * ASIC_IOSIZE);
41889aaa92adffa5c57d9c2a545c7cb9809ddd3b615H Hartley Sweeten	unsigned int triggered = 0;
4193b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	int got1 = 0;
4203b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	unsigned long flags;
4213b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	unsigned char int_pend;
42268720ae68a94444387d56bc5a166396e33e420a5H Hartley Sweeten	int i;
4236baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4243b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	spin_lock_irqsave(&devpriv->asics[asic].spinlock, flags);
4253b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
426f45a1f26eae4cadbfeb65b4b36bfa3583f694066H Hartley Sweeten	int_pend = inb(iobase + PCMUIO_INT_PENDING_REG) & 0x07;
4273b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	if (int_pend) {
42889aaa92adffa5c57d9c2a545c7cb9809ddd3b615H Hartley Sweeten		triggered = pcmuio_read(dev, asic, PCMUIO_PAGE_INT_ID, 0);
42989aaa92adffa5c57d9c2a545c7cb9809ddd3b615H Hartley Sweeten		pcmuio_write(dev, 0, asic, PCMUIO_PAGE_INT_ID, 0);
4306baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4313b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		++got1;
4323b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	}
4333b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
4343b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	spin_unlock_irqrestore(&devpriv->asics[asic].spinlock, flags);
4353b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
4363b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	if (triggered) {
4373b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		struct comedi_subdevice *s;
4383b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		/* TODO here: dispatch io lines to subdevs with commands.. */
4393b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		for (i = 0; i < dev->n_subdevices; i++) {
4403b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			s = &dev->subdevices[i];
4413b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			subpriv = s->private;
4423b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			if (subpriv->intr.asic == asic) {
4433b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				/*
4443b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				 * This is an interrupt subdev, and it
4453b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				 * matches this asic!
4463b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				 */
4473b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				pcmuio_handle_intr_subdev(dev, s,
4483b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten							  triggered);
4496baef150380d561a4d695a6be4fc509821c23611Calin Culianu			}
4503b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		}
4513b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	}
4523b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	return got1;
4533b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten}
4543b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
4553b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweetenstatic irqreturn_t interrupt_pcmuio(int irq, void *d)
4563b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten{
4573b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	struct comedi_device *dev = d;
4583b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	struct pcmuio_private *devpriv = dev->private;
4593b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	int got1 = 0;
4603b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	int asic;
4616baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4623b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	for (asic = 0; asic < MAX_ASICS; ++asic) {
4633b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		if (irq == devpriv->asics[asic].irq) {
4643b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			/* it is an interrupt for ASIC #asic */
4653b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			if (pcmuio_handle_asic_interrupt(dev, asic))
4663b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				got1++;
4676baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
4686baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
4696baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (!got1)
4706baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return IRQ_NONE;	/* interrupt from other source */
4716baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return IRQ_HANDLED;
4726baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
4736baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4740a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcmuio_start_intr(struct comedi_device *dev,
4750a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_subdevice *s)
4766baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
4778099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	struct pcmuio_subdev_private *subpriv = s->private;
4789a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten
4796baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (!subpriv->intr.continuous && subpriv->intr.stop_count == 0) {
4806baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* An empty acquisition! */
4816baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->async->events |= COMEDI_CB_EOA;
4826baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.active = 0;
4836baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return 1;
4846baef150380d561a4d695a6be4fc509821c23611Calin Culianu	} else {
4856baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned bits = 0, pol_bits = 0, n;
486e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten		int asic;
487ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton		struct comedi_cmd *cmd = &s->async->cmd;
4886baef150380d561a4d695a6be4fc509821c23611Calin Culianu
489c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton		asic = subpriv->intr.asic;
490c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton		if (asic < 0)
4916baef150380d561a4d695a6be4fc509821c23611Calin Culianu			return 1;	/* not an interrupt
4926baef150380d561a4d695a6be4fc509821c23611Calin Culianu					   subdev */
4936baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.enabled_mask = 0;
4946baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.active = 1;
4956baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (cmd->chanlist) {
4966baef150380d561a4d695a6be4fc509821c23611Calin Culianu			for (n = 0; n < cmd->chanlist_len; n++) {
4976baef150380d561a4d695a6be4fc509821c23611Calin Culianu				bits |= (1U << CR_CHAN(cmd->chanlist[n]));
4986baef150380d561a4d695a6be4fc509821c23611Calin Culianu				pol_bits |= (CR_AREF(cmd->chanlist[n])
4990a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					     || CR_RANGE(cmd->
5000a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							 chanlist[n]) ? 1U : 0U)
5010a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    << CR_CHAN(cmd->chanlist[n]);
5026baef150380d561a4d695a6be4fc509821c23611Calin Culianu			}
5036baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
504dbe9c7929c6c0021414d61f85fe4e2f20f069e1cH Hartley Sweeten		bits &= ((0x1 << s->n_chan) - 1);
5056baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.enabled_mask = bits;
5066baef150380d561a4d695a6be4fc509821c23611Calin Culianu
507e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten		/* set pol and enab intrs for this subdev.. */
508e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten		pcmuio_write(dev, pol_bits, asic, PCMUIO_PAGE_POL, 0);
509e4eae7c031e3eceed6dbc6358c15d55604fb31cdH Hartley Sweeten		pcmuio_write(dev, bits, asic, PCMUIO_PAGE_ENAB, 0);
5106baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
5116baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 0;
5126baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
5136baef150380d561a4d695a6be4fc509821c23611Calin Culianu
514da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
5156baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
5168099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	struct pcmuio_subdev_private *subpriv = s->private;
5176baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long flags;
5186baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5195f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&subpriv->intr.spinlock, flags);
5206baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (subpriv->intr.active)
5216baef150380d561a4d695a6be4fc509821c23611Calin Culianu		pcmuio_stop_intr(dev, s);
5225f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
5236baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5246baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 0;
5256baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
5266baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5276baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
5286baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
5296baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
5306baef150380d561a4d695a6be4fc509821c23611Calin Culianustatic int
531da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonpcmuio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
5320a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			  unsigned int trignum)
5336baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
5348099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	struct pcmuio_subdev_private *subpriv = s->private;
5356baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long flags;
5366baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int event = 0;
5376baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5386baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (trignum != 0)
5396baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return -EINVAL;
5406baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5415f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&subpriv->intr.spinlock, flags);
542920e2ffbe243fb0555b2c238e26fe7dbc03db98cH Hartley Sweeten	s->async->inttrig = NULL;
5430389245f0c5692111c0dc8d997fc4af72d789472Ravishankar karkala Mallikarjunayya	if (subpriv->intr.active)
5446baef150380d561a4d695a6be4fc509821c23611Calin Culianu		event = pcmuio_start_intr(dev, s);
5450389245f0c5692111c0dc8d997fc4af72d789472Ravishankar karkala Mallikarjunayya
5465f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
5476baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5480389245f0c5692111c0dc8d997fc4af72d789472Ravishankar karkala Mallikarjunayya	if (event)
5496baef150380d561a4d695a6be4fc509821c23611Calin Culianu		comedi_event(dev, s);
5506baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5516baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 1;
5526baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
5536baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5546baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
5556baef150380d561a4d695a6be4fc509821c23611Calin Culianu * 'do_cmd' function for an 'INTERRUPT' subdevice.
5566baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
557da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
5586baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
5598099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	struct pcmuio_subdev_private *subpriv = s->private;
560ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd *cmd = &s->async->cmd;
5616baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long flags;
5626baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int event = 0;
5636baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5645f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&subpriv->intr.spinlock, flags);
5656baef150380d561a4d695a6be4fc509821c23611Calin Culianu	subpriv->intr.active = 1;
5666baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5676baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* Set up end of acquisition. */
5686baef150380d561a4d695a6be4fc509821c23611Calin Culianu	switch (cmd->stop_src) {
5696baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case TRIG_COUNT:
5706baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.continuous = 0;
5716baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.stop_count = cmd->stop_arg;
5726baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
5736baef150380d561a4d695a6be4fc509821c23611Calin Culianu	default:
5746baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* TRIG_NONE */
5756baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.continuous = 1;
5766baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.stop_count = 0;
5776baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
5786baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
5796baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5806baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* Set up start of acquisition. */
5816baef150380d561a4d695a6be4fc509821c23611Calin Culianu	switch (cmd->start_src) {
5826baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case TRIG_INT:
5836baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->async->inttrig = pcmuio_inttrig_start_intr;
5846baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
5856baef150380d561a4d695a6be4fc509821c23611Calin Culianu	default:
5866baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* TRIG_NOW */
5876baef150380d561a4d695a6be4fc509821c23611Calin Culianu		event = pcmuio_start_intr(dev, s);
5886baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
5896baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
5905f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
5916baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5920389245f0c5692111c0dc8d997fc4af72d789472Ravishankar karkala Mallikarjunayya	if (event)
5936baef150380d561a4d695a6be4fc509821c23611Calin Culianu		comedi_event(dev, s);
5946baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5956baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 0;
5966baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
5976baef150380d561a4d695a6be4fc509821c23611Calin Culianu
598f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweetenstatic int pcmuio_cmdtest(struct comedi_device *dev,
599f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten			  struct comedi_subdevice *s,
600f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten			  struct comedi_cmd *cmd)
6016baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
602f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	int err = 0;
603f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
604f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	/* Step 1 : check if triggers are trivially valid */
605f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
606f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
607f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
608f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
609f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
610f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
611f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
612f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	if (err)
613f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		return 1;
614f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
615f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	/* Step 2a : make sure trigger sources are unique */
616f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
617f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_is_unique(cmd->start_src);
618f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_is_unique(cmd->stop_src);
619f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
620f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	/* Step 2b : and mutually compatible */
621f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
622f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	if (err)
623f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		return 2;
624f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
625f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	/* Step 3: check if arguments are trivially valid */
626f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
627f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
628f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
629f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
630f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
631f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
632f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	switch (cmd->stop_src) {
633f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	case TRIG_COUNT:
634f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		/* any count allowed */
635f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		break;
636f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	case TRIG_NONE:
637f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
638f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		break;
639f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	default:
640f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		break;
641f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	}
642f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
643f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	if (err)
644f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		return 3;
645f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
646f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	/* step 4: fix up any arguments */
647f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
648f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	/* if (err) return 4; */
649f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
650f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	return 0;
6516baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
6526baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6536b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweetenstatic int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
6546b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten{
655a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	const struct pcmuio_board *board = comedi_board(dev);
6566b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	struct comedi_subdevice *s;
6578099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	struct pcmuio_private *devpriv;
6588099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	struct pcmuio_subdev_private *subpriv;
6591699d80aef8ba7992d5f4176aed3504db8cffaf9H Hartley Sweeten	int sdev_no, n_subdevs, asic;
6606b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	unsigned int irq[MAX_ASICS];
6618b6c56949ffa83dbc2a6e8fa3f98b10a19372207H Hartley Sweeten	int ret;
6626b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
6636b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	irq[0] = it->options[1];
6646b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	irq[1] = it->options[2];
6656b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
66635626c2efecd6dad6ef67124ae2604385b717ed7H Hartley Sweeten	ret = comedi_request_region(dev, it->options[0],
66735626c2efecd6dad6ef67124ae2604385b717ed7H Hartley Sweeten				    board->num_asics * ASIC_IOSIZE);
66835626c2efecd6dad6ef67124ae2604385b717ed7H Hartley Sweeten	if (ret)
66935626c2efecd6dad6ef67124ae2604385b717ed7H Hartley Sweeten		return ret;
6706b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
671c34fa261b0ac3a862ccd3f71ee55a16b920dfc83H Hartley Sweeten	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
672c34fa261b0ac3a862ccd3f71ee55a16b920dfc83H Hartley Sweeten	if (!devpriv)
673c34fa261b0ac3a862ccd3f71ee55a16b920dfc83H Hartley Sweeten		return -ENOMEM;
674c34fa261b0ac3a862ccd3f71ee55a16b920dfc83H Hartley Sweeten	dev->private = devpriv;
6756b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
676021314f82405594344b857e13e0493e11dad7298H Hartley Sweeten	for (asic = 0; asic < MAX_ASICS; ++asic)
6776b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		spin_lock_init(&devpriv->asics[asic].spinlock);
6786b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
679c87e1f26054388b661298a61e906a03fa2cd193eH Hartley Sweeten	n_subdevs = board->num_asics * 2;
68078110bb8dc4a7ff331bfa3cfe7d4e287cfb3f22bJoe Perches	devpriv->sprivs = kcalloc(n_subdevs,
68178110bb8dc4a7ff331bfa3cfe7d4e287cfb3f22bJoe Perches				  sizeof(struct pcmuio_subdev_private),
68278110bb8dc4a7ff331bfa3cfe7d4e287cfb3f22bJoe Perches				  GFP_KERNEL);
68378110bb8dc4a7ff331bfa3cfe7d4e287cfb3f22bJoe Perches	if (!devpriv->sprivs)
6846b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		return -ENOMEM;
685eea6838b1206b0ac90110f1a6f58e101aa496e99H Hartley Sweeten
6868b6c56949ffa83dbc2a6e8fa3f98b10a19372207H Hartley Sweeten	ret = comedi_alloc_subdevices(dev, n_subdevs);
6878b6c56949ffa83dbc2a6e8fa3f98b10a19372207H Hartley Sweeten	if (ret)
6888b6c56949ffa83dbc2a6e8fa3f98b10a19372207H Hartley Sweeten		return ret;
6896b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
6906b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
69168720ae68a94444387d56bc5a166396e33e420a5H Hartley Sweeten		s = &dev->subdevices[sdev_no];
6928099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten		subpriv = &devpriv->sprivs[sdev_no];
6938099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten		s->private = subpriv;
6946b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->maxdata = 1;
6956b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->range_table = &range_digital;
6966b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
6976b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->type = COMEDI_SUBD_DIO;
6986b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->insn_bits = pcmuio_dio_insn_bits;
6996b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->insn_config = pcmuio_dio_insn_config;
700c87e1f26054388b661298a61e906a03fa2cd193eH Hartley Sweeten		s->n_chan = 24;
7016b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
7021699d80aef8ba7992d5f4176aed3504db8cffaf9H Hartley Sweeten		/* subdevices 0 and 2 suppport interrupts */
7031699d80aef8ba7992d5f4176aed3504db8cffaf9H Hartley Sweeten		if ((sdev_no % 2) == 0) {
7041699d80aef8ba7992d5f4176aed3504db8cffaf9H Hartley Sweeten			/* setup the interrupt subdevice */
7051699d80aef8ba7992d5f4176aed3504db8cffaf9H Hartley Sweeten			subpriv->intr.asic = sdev_no / 2;
7061699d80aef8ba7992d5f4176aed3504db8cffaf9H Hartley Sweeten			dev->read_subdev = s;
7071699d80aef8ba7992d5f4176aed3504db8cffaf9H Hartley Sweeten			s->subdev_flags |= SDF_CMD_READ;
7081699d80aef8ba7992d5f4176aed3504db8cffaf9H Hartley Sweeten			s->cancel = pcmuio_cancel;
7091699d80aef8ba7992d5f4176aed3504db8cffaf9H Hartley Sweeten			s->do_cmd = pcmuio_cmd;
7101699d80aef8ba7992d5f4176aed3504db8cffaf9H Hartley Sweeten			s->do_cmdtest = pcmuio_cmdtest;
7111699d80aef8ba7992d5f4176aed3504db8cffaf9H Hartley Sweeten			s->len_chanlist = s->n_chan;
7121699d80aef8ba7992d5f4176aed3504db8cffaf9H Hartley Sweeten		} else {
7131699d80aef8ba7992d5f4176aed3504db8cffaf9H Hartley Sweeten			subpriv->intr.asic = -1;
7141699d80aef8ba7992d5f4176aed3504db8cffaf9H Hartley Sweeten			s->len_chanlist = 1;
7156b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		}
7166b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		spin_lock_init(&subpriv->intr.spinlock);
7176b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	}
7186b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
7196b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	init_asics(dev);	/* clear out all the registers, basically */
7206b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
7216b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
7226b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		if (irq[asic]
7236b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		    && request_irq(irq[asic], interrupt_pcmuio,
724a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten				   IRQF_SHARED, board->name, dev)) {
7256b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			int i;
7266b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			/* unroll the allocated irqs.. */
7276b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			for (i = asic - 1; i >= 0; --i) {
7286b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				free_irq(irq[i], dev);
7296b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				devpriv->asics[i].irq = irq[i] = 0;
7306b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			}
7316b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			irq[asic] = 0;
7326b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		}
7336b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		devpriv->asics[asic].irq = irq[asic];
7346b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	}
7356b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
7366b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	if (irq[0]) {
737f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott		dev_dbg(dev->class_dev, "irq: %u\n", irq[0]);
738a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten		if (irq[1] && board->num_asics == 2)
739f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott			dev_dbg(dev->class_dev, "second ASIC irq: %u\n",
740f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott				irq[1]);
7416b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	} else {
742f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott		dev_dbg(dev->class_dev, "(IRQ mode disabled)\n");
7436b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	}
7446b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
7456b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
7466b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	return 1;
7476b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten}
7486b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
749484ecc95d9cdfa8b2f7029e2f3409cf078aed4abH Hartley Sweetenstatic void pcmuio_detach(struct comedi_device *dev)
7506b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten{
7519a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten	struct pcmuio_private *devpriv = dev->private;
7526b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	int i;
7536b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
7546b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	for (i = 0; i < MAX_ASICS; ++i) {
7556b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		if (devpriv->asics[i].irq)
7566b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			free_irq(devpriv->asics[i].irq, dev);
7576b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	}
7586b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	if (devpriv && devpriv->sprivs)
7596b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		kfree(devpriv->sprivs);
760a32c6d0084992d3e58a93120c9ce9527e80c651eH Hartley Sweeten	comedi_legacy_detach(dev);
7616b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten}
7626b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
763294f930d98be86fb4f34302c718a49719650857fH Hartley Sweetenstatic struct comedi_driver pcmuio_driver = {
7646b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	.driver_name	= "pcmuio",
7656b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	.module		= THIS_MODULE,
7666b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	.attach		= pcmuio_attach,
7676b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	.detach		= pcmuio_detach,
7686b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	.board_name	= &pcmuio_boards[0].name,
7696b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	.offset		= sizeof(struct pcmuio_board),
7706b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	.num_names	= ARRAY_SIZE(pcmuio_boards),
7716b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten};
772294f930d98be86fb4f34302c718a49719650857fH Hartley Sweetenmodule_comedi_driver(pcmuio_driver);
77390f703d30dd3e0c16ff80f35e34e511385a05ad5Arun Thomas
77490f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_AUTHOR("Comedi http://www.comedi.org");
77590f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_DESCRIPTION("Comedi low-level driver");
77690f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_LICENSE("GPL");
777