pcmuio.c revision fbe3bb17b9f9e18b771c30449916807c4c25e308
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
83288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define CHANS_PER_PORT		8
84288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define PORTS_PER_ASIC		6
85288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define INTR_PORTS_PER_ASIC	3
86288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten/* number of channels per comedi subdevice */
87288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define MAX_CHANS_PER_SUBDEV	24
88288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define PORTS_PER_SUBDEV	(MAX_CHANS_PER_SUBDEV / CHANS_PER_PORT)
89288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define CHANS_PER_ASIC		(CHANS_PER_PORT * PORTS_PER_ASIC)
90288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define INTR_CHANS_PER_ASIC	24
91288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define INTR_PORTS_PER_SUBDEV	(INTR_CHANS_PER_ASIC / CHANS_PER_PORT)
92288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define MAX_DIO_CHANS		(PORTS_PER_ASIC * 2 * CHANS_PER_PORT)
93288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define MAX_ASICS		(MAX_DIO_CHANS / CHANS_PER_ASIC)
946baef150380d561a4d695a6be4fc509821c23611Calin Culianu
95288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten/* IO Memory sizes */
96288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define ASIC_IOSIZE		0x10
97288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define PCMUIO48_IOSIZE		ASIC_IOSIZE
98288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define PCMUIO96_IOSIZE		(ASIC_IOSIZE * 2)
996baef150380d561a4d695a6be4fc509821c23611Calin Culianu
100288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten/*
101288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten * Some offsets - these are all in the 16byte IO memory offset from
102288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten * the base address.  Note that there is a paging scheme to swap out
103288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten * offsets 0x8-0xA using the PAGELOCK register.  See the table below.
104288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten *
105288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten * Register(s)       Pages        R/W?        Description
106288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten * --------------------------------------------------------------------------
107288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten * REG_PORTx         All          R/W         Read/Write/Configure IO
108288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten * REG_INT_PENDING   All          ReadOnly    Which INT_IDx has int.
109288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten * REG_PAGELOCK      All          WriteOnly   Select a page
110288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten * REG_POLx          Pg. 1 only   WriteOnly   Select edge-detection polarity
111288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten * REG_ENABx         Pg. 2 only   WriteOnly   Enable/Disable edge-detect int.
112288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten * REG_INT_IDx       Pg. 3 only   R/W         See which ports/bits have ints.
113288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten */
114288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define REG_PORT0		0x0
115288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define REG_PORT1		0x1
116288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define REG_PORT2		0x2
117288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define REG_PORT3		0x3
118288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define REG_PORT4		0x4
119288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define REG_PORT5		0x5
120288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define REG_INT_PENDING		0x6
121288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten/*
122288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten * page selector register
123288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten * Upper 2 bits select a page and bits 0-5 are used to
124288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten * 'lock down' a particular port above to make it readonly.
1256baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
126288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define REG_PAGELOCK		0x7
127288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define REG_POL0		0x8
128288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define REG_POL1		0x9
129288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define REG_POL2		0xa
130288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define REG_ENAB0		0x8
131288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define REG_ENAB1		0x9
132288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define REG_ENAB2		0xa
133288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define REG_INT_ID0		0x8
134288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define REG_INT_ID1		0x9
135288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define REG_INT_ID2		0xa
1366baef150380d561a4d695a6be4fc509821c23611Calin Culianu
137288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define NUM_PAGED_REGS		3
138288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define NUM_PAGES		4
139288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define FIRST_PAGED_REG		0x8
140288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define REG_PAGE_BITOFFSET	6
141288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define REG_LOCK_BITOFFSET	0
142288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define REG_PAGE_MASK		(~((0x1 << REG_PAGE_BITOFFSET) - 1))
143288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define REG_LOCK_MASK		~(REG_PAGE_MASK)
144288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define PAGE_POL		1
145288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define PAGE_ENAB		2
146288201328ba804a5630c7a460534e668703f114fH Hartley Sweeten#define PAGE_INT_ID		3
1476baef150380d561a4d695a6be4fc509821c23611Calin Culianu
14870a6001aeffeaa12f2a1c21470e8f3bdfb6ef8e7Bill Pembertonstruct pcmuio_board {
1496baef150380d561a4d695a6be4fc509821c23611Calin Culianu	const char *name;
1506baef150380d561a4d695a6be4fc509821c23611Calin Culianu	const int num_asics;
1516baef150380d561a4d695a6be4fc509821c23611Calin Culianu	const int num_channels_per_port;
1526baef150380d561a4d695a6be4fc509821c23611Calin Culianu	const int num_ports;
15370a6001aeffeaa12f2a1c21470e8f3bdfb6ef8e7Bill Pemberton};
1546baef150380d561a4d695a6be4fc509821c23611Calin Culianu
155fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweetenstatic const struct pcmuio_board pcmuio_boards[] = {
156fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten	{
157fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten		.name		= "pcmuio48",
158fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten		.num_asics	= 1,
159fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten		.num_ports	= 6,
160fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten	}, {
161fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten		.name		= "pcmuio96",
162fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten		.num_asics	= 2,
163fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten		.num_ports	= 12,
164fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten	},
165fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten};
166fbe3bb17b9f9e18b771c30449916807c4c25e308H Hartley Sweeten
1676baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* this structure is for data unique to this subdevice.  */
168e15849e54405152087cd343437747db8d931fcd7Bill Pembertonstruct pcmuio_subdev_private {
1696baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* mapping of halfwords (bytes) in port/chanarray to iobase */
1706baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long iobases[PORTS_PER_SUBDEV];
1716baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1726baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* The below is only used for intr subdevices */
1736baef150380d561a4d695a6be4fc509821c23611Calin Culianu	struct {
1746baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int asic;	/* if non-negative, this subdev has an interrupt asic */
1756baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int first_chan;	/* if nonnegative, the first channel id for
1766baef150380d561a4d695a6be4fc509821c23611Calin Culianu				   interrupts. */
1776baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int num_asic_chans;	/* the number of asic channels in this subdev
1786baef150380d561a4d695a6be4fc509821c23611Calin Culianu					   that have interrutps */
1796baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int asic_chan;	/* if nonnegative, the first channel id with
1806baef150380d561a4d695a6be4fc509821c23611Calin Culianu				   respect to the asic that has interrupts */
1816baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int enabled_mask;	/* subdev-relative channel mask for channels
1826baef150380d561a4d695a6be4fc509821c23611Calin Culianu					   we are interested in */
1836baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int active;
1846baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int stop_count;
1856baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int continuous;
1866baef150380d561a4d695a6be4fc509821c23611Calin Culianu		spinlock_t spinlock;
1876baef150380d561a4d695a6be4fc509821c23611Calin Culianu	} intr;
188e15849e54405152087cd343437747db8d931fcd7Bill Pemberton};
1896baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1906baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* this structure is for data unique to this hardware driver.  If
1916baef150380d561a4d695a6be4fc509821c23611Calin Culianu   several hardware drivers keep similar information in this structure,
19271b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton   feel free to suggest moving the variable to the struct comedi_device struct.  */
193055f6636d9eb27bc13236e07739e019496c21221Bill Pembertonstruct pcmuio_private {
1946baef150380d561a4d695a6be4fc509821c23611Calin Culianu	struct {
1956baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned char pagelock;	/* current page and lock */
1966baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned char pol[NUM_PAGED_REGS];	/* shadow of POLx registers */
1976baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned char enab[NUM_PAGED_REGS];	/* shadow of ENABx registers */
1986baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int num;
1996baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned long iobase;
2006baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned int irq;
2016baef150380d561a4d695a6be4fc509821c23611Calin Culianu		spinlock_t spinlock;
2026baef150380d561a4d695a6be4fc509821c23611Calin Culianu	} asics[MAX_ASICS];
203e15849e54405152087cd343437747db8d931fcd7Bill Pemberton	struct pcmuio_subdev_private *sprivs;
204055f6636d9eb27bc13236e07739e019496c21221Bill Pemberton};
2056baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2066baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* DIO devices are slightly special.  Although it is possible to
2076baef150380d561a4d695a6be4fc509821c23611Calin Culianu * implement the insn_read/insn_write interface, it is much more
2086baef150380d561a4d695a6be4fc509821c23611Calin Culianu * useful to applications if you implement the insn_bits interface.
2096baef150380d561a4d695a6be4fc509821c23611Calin Culianu * This allows packed reading/writing of the DIO channels.  The
2106baef150380d561a4d695a6be4fc509821c23611Calin Culianu * comedi core can convert between insn_bits and insn_read/write */
2110a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcmuio_dio_insn_bits(struct comedi_device *dev,
2120a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				struct comedi_subdevice *s,
2130a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				struct comedi_insn *insn, unsigned int *data)
2146baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
2158099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	struct pcmuio_subdev_private *subpriv = s->private;
2166baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int byte_no;
2176baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2186baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* NOTE:
2196baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   reading a 0 means this channel was high
2206baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   writine a 0 sets the channel high
2216baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   reading a 1 means this channel was low
2226baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   writing a 1 means set this channel low
2236baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2246baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   Therefore everything is always inverted. */
2256baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2266baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* The insn data is a mask in data[0] and the new data
2276baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * in data[1], each channel cooresponding to a bit. */
2286baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2296baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef DAMMIT_ITS_BROKEN
2306baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* DEBUG */
231f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott	dev_dbg(dev->class_dev, "write mask: %08x  data: %08x\n", data[0],
232976fe5ab27e682d3dbfec26517a8a248638af07dRavishankar karkala Mallikarjunayya		data[1]);
2336baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif
2346baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2356baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s->state = 0;
2366baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2376baef150380d561a4d695a6be4fc509821c23611Calin Culianu	for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) {
2386baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* address of 8-bit port */
2396baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned long ioaddr = subpriv->iobases[byte_no],
2400a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    /* bit offset of port in 32-bit doubleword */
2410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    offset = byte_no * 8;
2426baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* this 8-bit port's data */
2436baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned char byte = 0,
2440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    /* The write mask for this port (if any) */
2450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    write_mask_byte = (data[0] >> offset) & 0xff,
2460a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    /* The data byte for this port */
2470a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    data_byte = (data[1] >> offset) & 0xff;
2486baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2496baef150380d561a4d695a6be4fc509821c23611Calin Culianu		byte = inb(ioaddr);	/* read all 8-bits for this port */
2506baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2516baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef DAMMIT_ITS_BROKEN
2526baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* DEBUG */
2530a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk
2540a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    ("byte %d wmb %02x db %02x offset %02d io %04x, data_in %02x ",
2550a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		     byte_no, (unsigned)write_mask_byte, (unsigned)data_byte,
2560a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		     offset, ioaddr, (unsigned)byte);
2576baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif
2586baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2596baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (write_mask_byte) {
2606baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* this byte has some write_bits -- so set the output lines */
2616baef150380d561a4d695a6be4fc509821c23611Calin Culianu			byte &= ~write_mask_byte;	/* clear bits for write mask */
2626baef150380d561a4d695a6be4fc509821c23611Calin Culianu			byte |= ~data_byte & write_mask_byte;	/* set to inverted data_byte */
2636baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* Write out the new digital output state */
2646baef150380d561a4d695a6be4fc509821c23611Calin Culianu			outb(byte, ioaddr);
2656baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
2666baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef DAMMIT_ITS_BROKEN
2676baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* DEBUG */
268f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott		dev_dbg(dev->class_dev, "data_out_byte %02x\n", (unsigned)byte);
2696baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif
2706baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* save the digital input lines for this byte.. */
2716baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->state |= ((unsigned int)byte) << offset;
2726baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
2736baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2746baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* now return the DIO lines to data[1] - note they came inverted! */
2756baef150380d561a4d695a6be4fc509821c23611Calin Culianu	data[1] = ~s->state;
2766baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2776baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef DAMMIT_ITS_BROKEN
2786baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* DEBUG */
279f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott	dev_dbg(dev->class_dev, "s->state %08x data_out %08x\n", s->state,
280976fe5ab27e682d3dbfec26517a8a248638af07dRavishankar karkala Mallikarjunayya		data[1]);
2816baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif
2826baef150380d561a4d695a6be4fc509821c23611Calin Culianu
283a2714e3e42e746d6c8525c35fdcc58fb60c2830dH Hartley Sweeten	return insn->n;
2846baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
2856baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2866baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* The input or output configuration of each digital line is
2876baef150380d561a4d695a6be4fc509821c23611Calin Culianu * configured by a special insn_config instruction.  chanspec
2886baef150380d561a4d695a6be4fc509821c23611Calin Culianu * contains the channel to be changed, and data[0] contains the
2896baef150380d561a4d695a6be4fc509821c23611Calin Culianu * value COMEDI_INPUT or COMEDI_OUTPUT. */
2900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcmuio_dio_insn_config(struct comedi_device *dev,
2910a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  struct comedi_subdevice *s,
2920a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  struct comedi_insn *insn, unsigned int *data)
2936baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
2948099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	struct pcmuio_subdev_private *subpriv = s->private;
2956baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no =
2960a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    chan % 8;
2976baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long ioaddr;
2986baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned char byte;
2996baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3006baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* Compute ioaddr for this channel */
3016baef150380d561a4d695a6be4fc509821c23611Calin Culianu	ioaddr = subpriv->iobases[byte_no];
3026baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3036baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* NOTE:
3046baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   writing a 0 an IO channel's bit sets the channel to INPUT
3056baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   and pulls the line high as well
3066baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3076baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   writing a 1 to an IO channel's  bit pulls the line low
3086baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3096baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   All channels are implicitly always in OUTPUT mode -- but when
3106baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   they are high they can be considered to be in INPUT mode..
3116baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3126baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   Thus, we only force channels low if the config request was INPUT,
3136baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   otherwise we do nothing to the hardware.    */
3146baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3156baef150380d561a4d695a6be4fc509821c23611Calin Culianu	switch (data[0]) {
3166baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case INSN_CONFIG_DIO_OUTPUT:
3176baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* save to io_bits -- don't actually do anything since
3186baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   all input channels are also output channels... */
3196baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->io_bits |= 1 << chan;
3206baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
3216baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case INSN_CONFIG_DIO_INPUT:
3226baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* write a 0 to the actual register representing the channel
3236baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   to set it to 'input'.  0 means "float high". */
3246baef150380d561a4d695a6be4fc509821c23611Calin Culianu		byte = inb(ioaddr);
3256baef150380d561a4d695a6be4fc509821c23611Calin Culianu		byte &= ~(1 << bit_no);
3266baef150380d561a4d695a6be4fc509821c23611Calin Culianu				/**< set input channel to '0' */
3276baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3286baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* write out byte -- this is the only time we actually affect the
3296baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   hardware as all channels are implicitly output -- but input
3306baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   channels are set to float-high */
3316baef150380d561a4d695a6be4fc509821c23611Calin Culianu		outb(byte, ioaddr);
3326baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3336baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* save to io_bits */
3346baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->io_bits &= ~(1 << chan);
3356baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
3366baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3376baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case INSN_CONFIG_DIO_QUERY:
33825985edcedea6396277003854657b5f3cb31a628Lucas De Marchi		/* retrieve from shadow register */
3396baef150380d561a4d695a6be4fc509821c23611Calin Culianu		data[1] =
3400a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
3416baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return insn->n;
3426baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
3436baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3446baef150380d561a4d695a6be4fc509821c23611Calin Culianu	default:
3456baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return -EINVAL;
3466baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
3476baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
3486baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3496baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return insn->n;
3506baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
3516baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3526b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweetenstatic void switch_page(struct comedi_device *dev, int asic, int page)
3536b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten{
354a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	const struct pcmuio_board *board = comedi_board(dev);
3559a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten	struct pcmuio_private *devpriv = dev->private;
356a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten
357a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	if (asic < 0 || asic >= board->num_asics)
3586b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		return;		/* paranoia */
3596b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	if (page < 0 || page >= NUM_PAGES)
3606b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		return;		/* more paranoia */
3616b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
3626b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
3636b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
3646b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
3656b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	/* now write out the shadow register */
3666b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	outb(devpriv->asics[asic].pagelock,
3676b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	     dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
3686b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten}
3696b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
370da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void init_asics(struct comedi_device *dev)
3716baef150380d561a4d695a6be4fc509821c23611Calin Culianu{				/* sets up an
3726baef150380d561a4d695a6be4fc509821c23611Calin Culianu				   ASIC chip to defaults */
373a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	const struct pcmuio_board *board = comedi_board(dev);
3746baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int asic;
3756baef150380d561a4d695a6be4fc509821c23611Calin Culianu
376a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	for (asic = 0; asic < board->num_asics; ++asic) {
3776baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int port, page;
3786baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned long baseaddr = dev->iobase + asic * ASIC_IOSIZE;
3796baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3806baef150380d561a4d695a6be4fc509821c23611Calin Culianu		switch_page(dev, asic, 0);	/* switch back to page 0 */
3816baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3826baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* first, clear all the DIO port bits */
3836baef150380d561a4d695a6be4fc509821c23611Calin Culianu		for (port = 0; port < PORTS_PER_ASIC; ++port)
3846baef150380d561a4d695a6be4fc509821c23611Calin Culianu			outb(0, baseaddr + REG_PORT0 + port);
3856baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3866baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* Next, clear all the paged registers for each page */
3876baef150380d561a4d695a6be4fc509821c23611Calin Culianu		for (page = 1; page < NUM_PAGES; ++page) {
3886baef150380d561a4d695a6be4fc509821c23611Calin Culianu			int reg;
3896baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* now clear all the paged registers */
3906baef150380d561a4d695a6be4fc509821c23611Calin Culianu			switch_page(dev, asic, page);
3916baef150380d561a4d695a6be4fc509821c23611Calin Culianu			for (reg = FIRST_PAGED_REG;
3920a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg)
3936baef150380d561a4d695a6be4fc509821c23611Calin Culianu				outb(0, baseaddr + reg);
3946baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
3956baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3966baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* DEBUG  set rising edge interrupts on port0 of both asics */
3976baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/*switch_page(dev, asic, PAGE_POL);
3986baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   outb(0xff, baseaddr + REG_POL0);
3996baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   switch_page(dev, asic, PAGE_ENAB);
4006baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   outb(0xff, baseaddr + REG_ENAB0); */
4016baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* END DEBUG */
4026baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4036baef150380d561a4d695a6be4fc509821c23611Calin Culianu		switch_page(dev, asic, 0);	/* switch back to default page 0 */
4046baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4056baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
4066baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
4076baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4086baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef notused
409da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void lock_port(struct comedi_device *dev, int asic, int port)
4106baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
411a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	const struct pcmuio_board *board = comedi_board(dev);
4129a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten	struct pcmuio_private *devpriv = dev->private;
413a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten
414a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	if (asic < 0 || asic >= board->num_asics)
4156baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return;		/* paranoia */
4166baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (port < 0 || port >= PORTS_PER_ASIC)
4176baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return;		/* more paranoia */
4186baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4196baef150380d561a4d695a6be4fc509821c23611Calin Culianu	devpriv->asics[asic].pagelock |= 0x1 << port;
4206baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* now write out the shadow register */
4216baef150380d561a4d695a6be4fc509821c23611Calin Culianu	outb(devpriv->asics[asic].pagelock,
4220a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	     dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
4236baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
4246baef150380d561a4d695a6be4fc509821c23611Calin Culianu
425da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void unlock_port(struct comedi_device *dev, int asic, int port)
4266baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
427a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	const struct pcmuio_board *board = comedi_board(dev);
4289a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten	struct pcmuio_private *devpriv = dev->private;
429a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten
430a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	if (asic < 0 || asic >= board->num_asics)
4316baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return;		/* paranoia */
4326baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (port < 0 || port >= PORTS_PER_ASIC)
4336baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return;		/* more paranoia */
4346baef150380d561a4d695a6be4fc509821c23611Calin Culianu	devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK;
4356baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* now write out the shadow register */
4366baef150380d561a4d695a6be4fc509821c23611Calin Culianu	outb(devpriv->asics[asic].pagelock,
4370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	     dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
4386baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
4396baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif /* notused */
4406baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4416b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweetenstatic void pcmuio_stop_intr(struct comedi_device *dev,
4426b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			     struct comedi_subdevice *s)
4436b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten{
4449a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten	struct pcmuio_private *devpriv = dev->private;
4458099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	struct pcmuio_subdev_private *subpriv = s->private;
4468099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	int nports, firstport, asic, port;
4476b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
4486b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	asic = subpriv->intr.asic;
4496b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	if (asic < 0)
4506b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		return;		/* not an interrupt subdev */
4516b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
4526b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	subpriv->intr.enabled_mask = 0;
4536b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	subpriv->intr.active = 0;
454920e2ffbe243fb0555b2c238e26fe7dbc03db98cH Hartley Sweeten	s->async->inttrig = NULL;
4556b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
4566b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
4576b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	switch_page(dev, asic, PAGE_ENAB);
4586b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	for (port = firstport; port < firstport + nports; ++port) {
4596b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		/* disable all intrs for this subdev.. */
4606b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
4616b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	}
4626b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten}
4636b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
4643b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweetenstatic void pcmuio_handle_intr_subdev(struct comedi_device *dev,
4653b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				      struct comedi_subdevice *s,
4663b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				      unsigned triggered)
4673b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten{
4683b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	struct pcmuio_subdev_private *subpriv = s->private;
4693b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	unsigned int len = s->async->cmd.chanlist_len;
4703b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	unsigned oldevents = s->async->events;
4713b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	unsigned int val = 0;
4723b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	unsigned long flags;
4733b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	unsigned mytrig;
4743b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	unsigned int i;
4753b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
4763b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	spin_lock_irqsave(&subpriv->intr.spinlock, flags);
4773b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
4783b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	if (!subpriv->intr.active)
4793b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		goto done;
4803b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
4813b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	mytrig = triggered >> subpriv->intr.asic_chan;
4823b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	mytrig &= ((0x1 << subpriv->intr.num_asic_chans) - 1);
4833b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	mytrig <<= subpriv->intr.first_chan;
4843b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
4853b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	if (!(mytrig & subpriv->intr.enabled_mask))
4863b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		goto done;
4873b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
4883b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	for (i = 0; i < len; i++) {
4893b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		unsigned int chan = CR_CHAN(s->async->cmd.chanlist[i]);
4903b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		if (mytrig & (1U << chan))
4913b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			val |= (1U << i);
4923b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	}
4933b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
4943b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	/* Write the scan to the buffer. */
4953b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	if (comedi_buf_put(s->async, ((short *)&val)[0]) &&
4963b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	    comedi_buf_put(s->async, ((short *)&val)[1])) {
4973b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
4983b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	} else {
4993b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		/* Overflow! Stop acquisition!! */
5003b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		/* TODO: STOP_ACQUISITION_CALL_HERE!! */
5013b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		pcmuio_stop_intr(dev, s);
5023b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	}
5033b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
5043b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	/* Check for end of acquisition. */
5053b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	if (!subpriv->intr.continuous) {
5063b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		/* stop_src == TRIG_COUNT */
5073b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		if (subpriv->intr.stop_count > 0) {
5083b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			subpriv->intr.stop_count--;
5093b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			if (subpriv->intr.stop_count == 0) {
5103b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				s->async->events |= COMEDI_CB_EOA;
5113b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				/* TODO: STOP_ACQUISITION_CALL_HERE!! */
5123b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				pcmuio_stop_intr(dev, s);
5133b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			}
5143b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		}
5153b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	}
5163b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
5173b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweetendone:
5183b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
5193b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
5203b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	if (oldevents != s->async->events)
5213b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		comedi_event(dev, s);
5223b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten}
5233b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
5243b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweetenstatic int pcmuio_handle_asic_interrupt(struct comedi_device *dev, int asic)
5256baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
5269a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten	struct pcmuio_private *devpriv = dev->private;
5278099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	struct pcmuio_subdev_private *subpriv;
5283b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	unsigned long iobase = devpriv->asics[asic].iobase;
5293b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	unsigned triggered = 0;
5303b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	int got1 = 0;
5313b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	unsigned long flags;
5323b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	unsigned char int_pend;
53368720ae68a94444387d56bc5a166396e33e420a5H Hartley Sweeten	int i;
5346baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5353b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	spin_lock_irqsave(&devpriv->asics[asic].spinlock, flags);
5363b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
5373b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	int_pend = inb(iobase + REG_INT_PENDING) & 0x07;
5383b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	if (int_pend) {
5393b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		for (i = 0; i < INTR_PORTS_PER_ASIC; ++i) {
5403b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			if (int_pend & (0x1 << i)) {
5413b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				unsigned char val;
5423b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
5433b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				switch_page(dev, asic, PAGE_INT_ID);
5443b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				val = inb(iobase + REG_INT_ID0 + i);
5453b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				if (val)
5463b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten					/* clear pending interrupt */
5473b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten					outb(0, iobase + REG_INT_ID0 + i);
5483b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
5493b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten					triggered |= (val << (i * 8));
5506baef150380d561a4d695a6be4fc509821c23611Calin Culianu			}
5513b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		}
5526baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5533b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		++got1;
5543b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	}
5553b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
5563b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	spin_unlock_irqrestore(&devpriv->asics[asic].spinlock, flags);
5573b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
5583b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	if (triggered) {
5593b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		struct comedi_subdevice *s;
5603b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		/* TODO here: dispatch io lines to subdevs with commands.. */
5613b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		for (i = 0; i < dev->n_subdevices; i++) {
5623b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			s = &dev->subdevices[i];
5633b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			subpriv = s->private;
5643b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			if (subpriv->intr.asic == asic) {
5653b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				/*
5663b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				 * This is an interrupt subdev, and it
5673b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				 * matches this asic!
5683b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				 */
5693b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				pcmuio_handle_intr_subdev(dev, s,
5703b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten							  triggered);
5716baef150380d561a4d695a6be4fc509821c23611Calin Culianu			}
5723b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		}
5733b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	}
5743b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	return got1;
5753b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten}
5763b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
5773b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweetenstatic irqreturn_t interrupt_pcmuio(int irq, void *d)
5783b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten{
5793b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	struct comedi_device *dev = d;
5803b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	struct pcmuio_private *devpriv = dev->private;
5813b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	int got1 = 0;
5823b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	int asic;
5836baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5843b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	for (asic = 0; asic < MAX_ASICS; ++asic) {
5853b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		if (irq == devpriv->asics[asic].irq) {
5863b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			/* it is an interrupt for ASIC #asic */
5873b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			if (pcmuio_handle_asic_interrupt(dev, asic))
5883b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				got1++;
5896baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
5906baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
5916baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (!got1)
5926baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return IRQ_NONE;	/* interrupt from other source */
5936baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return IRQ_HANDLED;
5946baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
5956baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5960a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcmuio_start_intr(struct comedi_device *dev,
5970a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_subdevice *s)
5986baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
5999a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten	struct pcmuio_private *devpriv = dev->private;
6008099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	struct pcmuio_subdev_private *subpriv = s->private;
6019a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten
6026baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (!subpriv->intr.continuous && subpriv->intr.stop_count == 0) {
6036baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* An empty acquisition! */
6046baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->async->events |= COMEDI_CB_EOA;
6056baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.active = 0;
6066baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return 1;
6076baef150380d561a4d695a6be4fc509821c23611Calin Culianu	} else {
6086baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned bits = 0, pol_bits = 0, n;
6096baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int nports, firstport, asic, port;
610ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton		struct comedi_cmd *cmd = &s->async->cmd;
6116baef150380d561a4d695a6be4fc509821c23611Calin Culianu
612c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton		asic = subpriv->intr.asic;
613c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton		if (asic < 0)
6146baef150380d561a4d695a6be4fc509821c23611Calin Culianu			return 1;	/* not an interrupt
6156baef150380d561a4d695a6be4fc509821c23611Calin Culianu					   subdev */
6166baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.enabled_mask = 0;
6176baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.active = 1;
6186baef150380d561a4d695a6be4fc509821c23611Calin Culianu		nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
6196baef150380d561a4d695a6be4fc509821c23611Calin Culianu		firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
6206baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (cmd->chanlist) {
6216baef150380d561a4d695a6be4fc509821c23611Calin Culianu			for (n = 0; n < cmd->chanlist_len; n++) {
6226baef150380d561a4d695a6be4fc509821c23611Calin Culianu				bits |= (1U << CR_CHAN(cmd->chanlist[n]));
6236baef150380d561a4d695a6be4fc509821c23611Calin Culianu				pol_bits |= (CR_AREF(cmd->chanlist[n])
6240a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					     || CR_RANGE(cmd->
6250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							 chanlist[n]) ? 1U : 0U)
6260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    << CR_CHAN(cmd->chanlist[n]);
6276baef150380d561a4d695a6be4fc509821c23611Calin Culianu			}
6286baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
6296baef150380d561a4d695a6be4fc509821c23611Calin Culianu		bits &= ((0x1 << subpriv->intr.num_asic_chans) -
6300a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 1) << subpriv->intr.first_chan;
6316baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.enabled_mask = bits;
6326baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6336baef150380d561a4d695a6be4fc509821c23611Calin Culianu		switch_page(dev, asic, PAGE_ENAB);
6346baef150380d561a4d695a6be4fc509821c23611Calin Culianu		for (port = firstport; port < firstport + nports; ++port) {
6356baef150380d561a4d695a6be4fc509821c23611Calin Culianu			unsigned enab =
6360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    bits >> (subpriv->intr.first_chan + (port -
6370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								 firstport) *
6380a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				     8) & 0xff, pol =
6390a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    pol_bits >> (subpriv->intr.first_chan +
6400a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					 (port - firstport) * 8) & 0xff;
6416baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* set enab intrs for this subdev.. */
6426baef150380d561a4d695a6be4fc509821c23611Calin Culianu			outb(enab,
6430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     devpriv->asics[asic].iobase + REG_ENAB0 + port);
6446baef150380d561a4d695a6be4fc509821c23611Calin Culianu			switch_page(dev, asic, PAGE_POL);
6456baef150380d561a4d695a6be4fc509821c23611Calin Culianu			outb(pol,
6460a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     devpriv->asics[asic].iobase + REG_ENAB0 + port);
6476baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
6486baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
6496baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 0;
6506baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
6516baef150380d561a4d695a6be4fc509821c23611Calin Culianu
652da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
6536baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
6548099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	struct pcmuio_subdev_private *subpriv = s->private;
6556baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long flags;
6566baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6575f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&subpriv->intr.spinlock, flags);
6586baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (subpriv->intr.active)
6596baef150380d561a4d695a6be4fc509821c23611Calin Culianu		pcmuio_stop_intr(dev, s);
6605f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
6616baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6626baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 0;
6636baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
6646baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6656baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
6666baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
6676baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
6686baef150380d561a4d695a6be4fc509821c23611Calin Culianustatic int
669da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonpcmuio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
6700a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			  unsigned int trignum)
6716baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
6728099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	struct pcmuio_subdev_private *subpriv = s->private;
6736baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long flags;
6746baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int event = 0;
6756baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6766baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (trignum != 0)
6776baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return -EINVAL;
6786baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6795f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&subpriv->intr.spinlock, flags);
680920e2ffbe243fb0555b2c238e26fe7dbc03db98cH Hartley Sweeten	s->async->inttrig = NULL;
6810389245f0c5692111c0dc8d997fc4af72d789472Ravishankar karkala Mallikarjunayya	if (subpriv->intr.active)
6826baef150380d561a4d695a6be4fc509821c23611Calin Culianu		event = pcmuio_start_intr(dev, s);
6830389245f0c5692111c0dc8d997fc4af72d789472Ravishankar karkala Mallikarjunayya
6845f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
6856baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6860389245f0c5692111c0dc8d997fc4af72d789472Ravishankar karkala Mallikarjunayya	if (event)
6876baef150380d561a4d695a6be4fc509821c23611Calin Culianu		comedi_event(dev, s);
6886baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6896baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 1;
6906baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
6916baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6926baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
6936baef150380d561a4d695a6be4fc509821c23611Calin Culianu * 'do_cmd' function for an 'INTERRUPT' subdevice.
6946baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
695da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
6966baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
6978099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	struct pcmuio_subdev_private *subpriv = s->private;
698ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd *cmd = &s->async->cmd;
6996baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long flags;
7006baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int event = 0;
7016baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7025f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&subpriv->intr.spinlock, flags);
7036baef150380d561a4d695a6be4fc509821c23611Calin Culianu	subpriv->intr.active = 1;
7046baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7056baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* Set up end of acquisition. */
7066baef150380d561a4d695a6be4fc509821c23611Calin Culianu	switch (cmd->stop_src) {
7076baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case TRIG_COUNT:
7086baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.continuous = 0;
7096baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.stop_count = cmd->stop_arg;
7106baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
7116baef150380d561a4d695a6be4fc509821c23611Calin Culianu	default:
7126baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* TRIG_NONE */
7136baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.continuous = 1;
7146baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.stop_count = 0;
7156baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
7166baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
7176baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7186baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* Set up start of acquisition. */
7196baef150380d561a4d695a6be4fc509821c23611Calin Culianu	switch (cmd->start_src) {
7206baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case TRIG_INT:
7216baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->async->inttrig = pcmuio_inttrig_start_intr;
7226baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
7236baef150380d561a4d695a6be4fc509821c23611Calin Culianu	default:
7246baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* TRIG_NOW */
7256baef150380d561a4d695a6be4fc509821c23611Calin Culianu		event = pcmuio_start_intr(dev, s);
7266baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
7276baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
7285f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
7296baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7300389245f0c5692111c0dc8d997fc4af72d789472Ravishankar karkala Mallikarjunayya	if (event)
7316baef150380d561a4d695a6be4fc509821c23611Calin Culianu		comedi_event(dev, s);
7326baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7336baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 0;
7346baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
7356baef150380d561a4d695a6be4fc509821c23611Calin Culianu
736f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweetenstatic int pcmuio_cmdtest(struct comedi_device *dev,
737f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten			  struct comedi_subdevice *s,
738f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten			  struct comedi_cmd *cmd)
7396baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
740f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	int err = 0;
741f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
742f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	/* Step 1 : check if triggers are trivially valid */
743f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
744f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
745f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
746f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
747f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
748f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
749f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
750f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	if (err)
751f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		return 1;
752f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
753f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	/* Step 2a : make sure trigger sources are unique */
754f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
755f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_is_unique(cmd->start_src);
756f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_is_unique(cmd->stop_src);
757f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
758f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	/* Step 2b : and mutually compatible */
759f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
760f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	if (err)
761f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		return 2;
762f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
763f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	/* Step 3: check if arguments are trivially valid */
764f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
765f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
766f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
767f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
768f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
769f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
770f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	switch (cmd->stop_src) {
771f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	case TRIG_COUNT:
772f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		/* any count allowed */
773f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		break;
774f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	case TRIG_NONE:
775f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
776f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		break;
777f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	default:
778f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		break;
779f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	}
780f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
781f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	if (err)
782f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		return 3;
783f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
784f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	/* step 4: fix up any arguments */
785f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
786f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	/* if (err) return 4; */
787f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
788f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	return 0;
7896baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
7906baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7916b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweetenstatic int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
7926b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten{
793a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	const struct pcmuio_board *board = comedi_board(dev);
7946b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	struct comedi_subdevice *s;
7958099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	struct pcmuio_private *devpriv;
7968099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	struct pcmuio_subdev_private *subpriv;
7976b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0;
7986b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	unsigned int irq[MAX_ASICS];
7998b6c56949ffa83dbc2a6e8fa3f98b10a19372207H Hartley Sweeten	int ret;
8006b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
8016b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	irq[0] = it->options[1];
8026b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	irq[1] = it->options[2];
8036b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
80435626c2efecd6dad6ef67124ae2604385b717ed7H Hartley Sweeten	ret = comedi_request_region(dev, it->options[0],
80535626c2efecd6dad6ef67124ae2604385b717ed7H Hartley Sweeten				    board->num_asics * ASIC_IOSIZE);
80635626c2efecd6dad6ef67124ae2604385b717ed7H Hartley Sweeten	if (ret)
80735626c2efecd6dad6ef67124ae2604385b717ed7H Hartley Sweeten		return ret;
8086b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
809c34fa261b0ac3a862ccd3f71ee55a16b920dfc83H Hartley Sweeten	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
810c34fa261b0ac3a862ccd3f71ee55a16b920dfc83H Hartley Sweeten	if (!devpriv)
811c34fa261b0ac3a862ccd3f71ee55a16b920dfc83H Hartley Sweeten		return -ENOMEM;
812c34fa261b0ac3a862ccd3f71ee55a16b920dfc83H Hartley Sweeten	dev->private = devpriv;
8136b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
8146b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	for (asic = 0; asic < MAX_ASICS; ++asic) {
8156b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		devpriv->asics[asic].num = asic;
8166b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		devpriv->asics[asic].iobase = dev->iobase + asic * ASIC_IOSIZE;
8176b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		devpriv->asics[asic].irq = 0;	/* this gets actually set at the end of
8186b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten						   this function when we
8196b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten						   request_irqs */
8206b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		spin_lock_init(&devpriv->asics[asic].spinlock);
8216b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	}
8226b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
823a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	chans_left = CHANS_PER_ASIC * board->num_asics;
82400b863964d3d24e7ae1dfb571e45707136c6cf42H Hartley Sweeten	n_subdevs = (chans_left / MAX_CHANS_PER_SUBDEV) +
82500b863964d3d24e7ae1dfb571e45707136c6cf42H Hartley Sweeten		    (!!(chans_left % MAX_CHANS_PER_SUBDEV));
82678110bb8dc4a7ff331bfa3cfe7d4e287cfb3f22bJoe Perches	devpriv->sprivs = kcalloc(n_subdevs,
82778110bb8dc4a7ff331bfa3cfe7d4e287cfb3f22bJoe Perches				  sizeof(struct pcmuio_subdev_private),
82878110bb8dc4a7ff331bfa3cfe7d4e287cfb3f22bJoe Perches				  GFP_KERNEL);
82978110bb8dc4a7ff331bfa3cfe7d4e287cfb3f22bJoe Perches	if (!devpriv->sprivs)
8306b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		return -ENOMEM;
831eea6838b1206b0ac90110f1a6f58e101aa496e99H Hartley Sweeten
8328b6c56949ffa83dbc2a6e8fa3f98b10a19372207H Hartley Sweeten	ret = comedi_alloc_subdevices(dev, n_subdevs);
8338b6c56949ffa83dbc2a6e8fa3f98b10a19372207H Hartley Sweeten	if (ret)
8348b6c56949ffa83dbc2a6e8fa3f98b10a19372207H Hartley Sweeten		return ret;
8356b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
8366b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	port = 0;
8376b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	asic = 0;
8386b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
8396b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		int byte_no;
8406b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
84168720ae68a94444387d56bc5a166396e33e420a5H Hartley Sweeten		s = &dev->subdevices[sdev_no];
8428099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten		subpriv = &devpriv->sprivs[sdev_no];
8438099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten		s->private = subpriv;
8446b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->maxdata = 1;
8456b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->range_table = &range_digital;
8466b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
8476b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->type = COMEDI_SUBD_DIO;
8486b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->insn_bits = pcmuio_dio_insn_bits;
8496b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->insn_config = pcmuio_dio_insn_config;
8506b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
8516b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		subpriv->intr.asic = -1;
8526b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		subpriv->intr.first_chan = -1;
8536b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		subpriv->intr.asic_chan = -1;
8546b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		subpriv->intr.num_asic_chans = -1;
8556b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		subpriv->intr.active = 0;
8566b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->len_chanlist = 1;
8576b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
8586b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		/* save the ioport address for each 'port' of 8 channels in the
8596b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		   subdevice */
8606b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
8616b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			if (port >= PORTS_PER_ASIC) {
8626b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				port = 0;
8636b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				++asic;
8646b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				thisasic_chanct = 0;
8656b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			}
8666b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			subpriv->iobases[byte_no] =
8676b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			    devpriv->asics[asic].iobase + port;
8686b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
8696b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			if (thisasic_chanct <
8706b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			    CHANS_PER_PORT * INTR_PORTS_PER_ASIC
8716b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			    && subpriv->intr.asic < 0) {
8726b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				/* this is an interrupt subdevice, so setup the struct */
8736b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				subpriv->intr.asic = asic;
8746b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				subpriv->intr.active = 0;
8756b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				subpriv->intr.stop_count = 0;
8766b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				subpriv->intr.first_chan = byte_no * 8;
8776b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				subpriv->intr.asic_chan = thisasic_chanct;
8786b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				subpriv->intr.num_asic_chans =
8796b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				    s->n_chan - subpriv->intr.first_chan;
8806b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				dev->read_subdev = s;
8816b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				s->subdev_flags |= SDF_CMD_READ;
8826b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				s->cancel = pcmuio_cancel;
8836b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				s->do_cmd = pcmuio_cmd;
8846b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				s->do_cmdtest = pcmuio_cmdtest;
8856b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				s->len_chanlist = subpriv->intr.num_asic_chans;
8866b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			}
8876b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			thisasic_chanct += CHANS_PER_PORT;
8886b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		}
8896b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		spin_lock_init(&subpriv->intr.spinlock);
8906b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
8916b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		chans_left -= s->n_chan;
8926b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
8936b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		if (!chans_left) {
8946b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			asic = 0;	/* reset the asic to our first asic, to do intr subdevs */
8956b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			port = 0;
8966b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		}
8976b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
8986b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	}
8996b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
9006b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	init_asics(dev);	/* clear out all the registers, basically */
9016b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
9026b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
9036b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		if (irq[asic]
9046b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		    && request_irq(irq[asic], interrupt_pcmuio,
905a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten				   IRQF_SHARED, board->name, dev)) {
9066b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			int i;
9076b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			/* unroll the allocated irqs.. */
9086b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			for (i = asic - 1; i >= 0; --i) {
9096b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				free_irq(irq[i], dev);
9106b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				devpriv->asics[i].irq = irq[i] = 0;
9116b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			}
9126b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			irq[asic] = 0;
9136b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		}
9146b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		devpriv->asics[asic].irq = irq[asic];
9156b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	}
9166b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
9176b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	if (irq[0]) {
918f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott		dev_dbg(dev->class_dev, "irq: %u\n", irq[0]);
919a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten		if (irq[1] && board->num_asics == 2)
920f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott			dev_dbg(dev->class_dev, "second ASIC irq: %u\n",
921f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott				irq[1]);
9226b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	} else {
923f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott		dev_dbg(dev->class_dev, "(IRQ mode disabled)\n");
9246b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	}
9256b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
9266b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
9276b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	return 1;
9286b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten}
9296b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
930484ecc95d9cdfa8b2f7029e2f3409cf078aed4abH Hartley Sweetenstatic void pcmuio_detach(struct comedi_device *dev)
9316b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten{
9329a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten	struct pcmuio_private *devpriv = dev->private;
9336b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	int i;
9346b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
9356b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	for (i = 0; i < MAX_ASICS; ++i) {
9366b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		if (devpriv->asics[i].irq)
9376b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			free_irq(devpriv->asics[i].irq, dev);
9386b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	}
9396b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	if (devpriv && devpriv->sprivs)
9406b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		kfree(devpriv->sprivs);
941a32c6d0084992d3e58a93120c9ce9527e80c651eH Hartley Sweeten	comedi_legacy_detach(dev);
9426b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten}
9436b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
944294f930d98be86fb4f34302c718a49719650857fH Hartley Sweetenstatic struct comedi_driver pcmuio_driver = {
9456b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	.driver_name	= "pcmuio",
9466b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	.module		= THIS_MODULE,
9476b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	.attach		= pcmuio_attach,
9486b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	.detach		= pcmuio_detach,
9496b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	.board_name	= &pcmuio_boards[0].name,
9506b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	.offset		= sizeof(struct pcmuio_board),
9516b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	.num_names	= ARRAY_SIZE(pcmuio_boards),
9526b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten};
953294f930d98be86fb4f34302c718a49719650857fH Hartley Sweetenmodule_comedi_driver(pcmuio_driver);
95490f703d30dd3e0c16ff80f35e34e511385a05ad5Arun Thomas
95590f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_AUTHOR("Comedi http://www.comedi.org");
95690f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_DESCRIPTION("Comedi low-level driver");
95790f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_LICENSE("GPL");
958