pcmuio.c revision 70a6001aeffeaa12f2a1c21470e8f3bdfb6ef8e7
16baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
26baef150380d561a4d695a6be4fc509821c23611Calin Culianu    comedi/drivers/pcmuio.c
36baef150380d561a4d695a6be4fc509821c23611Calin Culianu    Driver for Winsystems PC-104 based 48-channel and 96-channel DIO boards.
46baef150380d561a4d695a6be4fc509821c23611Calin Culianu
56baef150380d561a4d695a6be4fc509821c23611Calin Culianu    COMEDI - Linux Control and Measurement Device Interface
66baef150380d561a4d695a6be4fc509821c23611Calin Culianu    Copyright (C) 2006 Calin A. Culianu <calin@ajvar.org>
76baef150380d561a4d695a6be4fc509821c23611Calin Culianu
86baef150380d561a4d695a6be4fc509821c23611Calin Culianu    This program is free software; you can redistribute it and/or modify
96baef150380d561a4d695a6be4fc509821c23611Calin Culianu    it under the terms of the GNU General Public License as published by
106baef150380d561a4d695a6be4fc509821c23611Calin Culianu    the Free Software Foundation; either version 2 of the License, or
116baef150380d561a4d695a6be4fc509821c23611Calin Culianu    (at your option) any later version.
126baef150380d561a4d695a6be4fc509821c23611Calin Culianu
136baef150380d561a4d695a6be4fc509821c23611Calin Culianu    This program is distributed in the hope that it will be useful,
146baef150380d561a4d695a6be4fc509821c23611Calin Culianu    but WITHOUT ANY WARRANTY; without even the implied warranty of
156baef150380d561a4d695a6be4fc509821c23611Calin Culianu    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
166baef150380d561a4d695a6be4fc509821c23611Calin Culianu    GNU General Public License for more details.
176baef150380d561a4d695a6be4fc509821c23611Calin Culianu
186baef150380d561a4d695a6be4fc509821c23611Calin Culianu    You should have received a copy of the GNU General Public License
196baef150380d561a4d695a6be4fc509821c23611Calin Culianu    along with this program; if not, write to the Free Software
206baef150380d561a4d695a6be4fc509821c23611Calin Culianu    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
216baef150380d561a4d695a6be4fc509821c23611Calin Culianu*/
226baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
236baef150380d561a4d695a6be4fc509821c23611Calin CulianuDriver: pcmuio
246baef150380d561a4d695a6be4fc509821c23611Calin CulianuDescription: A driver for the PCM-UIO48A and PCM-UIO96A boards from Winsystems.
256baef150380d561a4d695a6be4fc509821c23611Calin CulianuDevices: [Winsystems] PCM-UIO48A (pcmuio48), PCM-UIO96A (pcmuio96)
266baef150380d561a4d695a6be4fc509821c23611Calin CulianuAuthor: Calin Culianu <calin@ajvar.org>
276baef150380d561a4d695a6be4fc509821c23611Calin CulianuUpdated: Fri, 13 Jan 2006 12:01:01 -0500
286baef150380d561a4d695a6be4fc509821c23611Calin CulianuStatus: works
296baef150380d561a4d695a6be4fc509821c23611Calin Culianu
306baef150380d561a4d695a6be4fc509821c23611Calin CulianuA driver for the relatively straightforward-to-program PCM-UIO48A and
316baef150380d561a4d695a6be4fc509821c23611Calin CulianuPCM-UIO96A boards from Winsystems.  These boards use either one or two
326baef150380d561a4d695a6be4fc509821c23611Calin Culianu(in the 96-DIO version) WS16C48 ASIC HighDensity I/O Chips (HDIO).
336baef150380d561a4d695a6be4fc509821c23611Calin CulianuThis chip is interesting in that each I/O line is individually
346baef150380d561a4d695a6be4fc509821c23611Calin Culianuprogrammable for INPUT or OUTPUT (thus comedi_dio_config can be done
356baef150380d561a4d695a6be4fc509821c23611Calin Culianuon a per-channel basis).  Also, each chip supports edge-triggered
366baef150380d561a4d695a6be4fc509821c23611Calin Culianuinterrupts for the first 24 I/O lines.  Of course, since the
376baef150380d561a4d695a6be4fc509821c23611Calin Culianu96-channel version of the board has two ASICs, it can detect polarity
386baef150380d561a4d695a6be4fc509821c23611Calin Culianuchanges on up to 48 I/O lines.  Since this is essentially an (non-PnP)
396baef150380d561a4d695a6be4fc509821c23611Calin CulianuISA board, I/O Address and IRQ selection are done through jumpers on
406baef150380d561a4d695a6be4fc509821c23611Calin Culianuthe board.  You need to pass that information to this driver as the
416baef150380d561a4d695a6be4fc509821c23611Calin Culianufirst and second comedi_config option, respectively.  Note that the
426baef150380d561a4d695a6be4fc509821c23611Calin Culianu48-channel version uses 16 bytes of IO memory and the 96-channel
436baef150380d561a4d695a6be4fc509821c23611Calin Culianuversion uses 32-bytes (in case you are worried about conflicts).  The
446baef150380d561a4d695a6be4fc509821c23611Calin Culianu48-channel board is split into two 24-channel comedi subdevices.
456baef150380d561a4d695a6be4fc509821c23611Calin CulianuThe 96-channel board is split into 4 24-channel DIO subdevices.
466baef150380d561a4d695a6be4fc509821c23611Calin Culianu
476baef150380d561a4d695a6be4fc509821c23611Calin CulianuNote that IRQ support has been added, but it is untested.
486baef150380d561a4d695a6be4fc509821c23611Calin Culianu
496baef150380d561a4d695a6be4fc509821c23611Calin CulianuTo use edge-detection IRQ support, pass the IRQs of both ASICS
506baef150380d561a4d695a6be4fc509821c23611Calin Culianu(for the 96 channel version) or just 1 ASIC (for 48-channel version).
516baef150380d561a4d695a6be4fc509821c23611Calin CulianuThen, use use comedi_commands with TRIG_NOW.
526baef150380d561a4d695a6be4fc509821c23611Calin CulianuYour callback will be called each time an edge is triggered, and the data
536baef150380d561a4d695a6be4fc509821c23611Calin Culianuvalues will be two sample_t's, which should be concatenated to form one
546baef150380d561a4d695a6be4fc509821c23611Calin Culianu32-bit unsigned int.  This value is the mask of channels that had
556baef150380d561a4d695a6be4fc509821c23611Calin Culianuedges detected from your channel list.  Note that the bits positions
566baef150380d561a4d695a6be4fc509821c23611Calin Culianuin the mask correspond to positions in your chanlist when you specified
576baef150380d561a4d695a6be4fc509821c23611Calin Culianuthe command and *not* channel id's!
586baef150380d561a4d695a6be4fc509821c23611Calin Culianu
596baef150380d561a4d695a6be4fc509821c23611Calin CulianuTo set the polarity of the edge-detection interrupts pass a nonzero value for
606baef150380d561a4d695a6be4fc509821c23611Calin Culianueither CR_RANGE or CR_AREF for edge-up polarity, or a zero value for both
616baef150380d561a4d695a6be4fc509821c23611Calin CulianuCR_RANGE and CR_AREF if you want edge-down polarity.
626baef150380d561a4d695a6be4fc509821c23611Calin Culianu
636baef150380d561a4d695a6be4fc509821c23611Calin CulianuIn the 48-channel version:
646baef150380d561a4d695a6be4fc509821c23611Calin Culianu
656baef150380d561a4d695a6be4fc509821c23611Calin CulianuOn subdev 0, the first 24 channels channels are edge-detect channels.
666baef150380d561a4d695a6be4fc509821c23611Calin Culianu
676baef150380d561a4d695a6be4fc509821c23611Calin CulianuIn the 96-channel board you have the collowing channels that can do edge detection:
686baef150380d561a4d695a6be4fc509821c23611Calin Culianu
696baef150380d561a4d695a6be4fc509821c23611Calin Culianusubdev 0, channels 0-24  (first 24 channels of 1st ASIC)
706baef150380d561a4d695a6be4fc509821c23611Calin Culianusubdev 2, channels 0-24  (first 24 channels of 2nd ASIC)
716baef150380d561a4d695a6be4fc509821c23611Calin Culianu
726baef150380d561a4d695a6be4fc509821c23611Calin CulianuConfiguration Options:
736baef150380d561a4d695a6be4fc509821c23611Calin Culianu  [0] - I/O port base address
746baef150380d561a4d695a6be4fc509821c23611Calin Culianu  [1] - IRQ (for first ASIC, or first 24 channels)
756baef150380d561a4d695a6be4fc509821c23611Calin Culianu  [2] - IRQ for second ASIC (pcmuio96 only - IRQ for chans 48-72 .. can be the same as first irq!)
766baef150380d561a4d695a6be4fc509821c23611Calin Culianu*/
776baef150380d561a4d695a6be4fc509821c23611Calin Culianu
786baef150380d561a4d695a6be4fc509821c23611Calin Culianu#include "../comedidev.h"
796baef150380d561a4d695a6be4fc509821c23611Calin Culianu
806baef150380d561a4d695a6be4fc509821c23611Calin Culianu#include <linux/pci.h>		/* for PCI devices */
816baef150380d561a4d695a6be4fc509821c23611Calin Culianu
826baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define MIN(a,b) ( ((a) < (b)) ? (a) : (b) )
836baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define CHANS_PER_PORT   8
846baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PORTS_PER_ASIC   6
856baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define INTR_PORTS_PER_ASIC   3
866baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define MAX_CHANS_PER_SUBDEV 24	/* number of channels per comedi subdevice */
876baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PORTS_PER_SUBDEV (MAX_CHANS_PER_SUBDEV/CHANS_PER_PORT)
886baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define CHANS_PER_ASIC (CHANS_PER_PORT*PORTS_PER_ASIC)
896baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define INTR_CHANS_PER_ASIC 24
906baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC/CHANS_PER_PORT)
916baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define MAX_DIO_CHANS   (PORTS_PER_ASIC*2*CHANS_PER_PORT)
926baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define MAX_ASICS       (MAX_DIO_CHANS/CHANS_PER_ASIC)
936baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define SDEV_NO ((int)(s - dev->subdevices))
946baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define CALC_N_SUBDEVS(nchans) ((nchans)/MAX_CHANS_PER_SUBDEV + (!!((nchans)%MAX_CHANS_PER_SUBDEV)) /*+ (nchans > INTR_CHANS_PER_ASIC ? 2 : 1)*/)
956baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* IO Memory sizes */
966baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define ASIC_IOSIZE (0x10)
976baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PCMUIO48_IOSIZE ASIC_IOSIZE
986baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PCMUIO96_IOSIZE (ASIC_IOSIZE*2)
996baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1006baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* Some offsets - these are all in the 16byte IO memory offset from
1016baef150380d561a4d695a6be4fc509821c23611Calin Culianu   the base address.  Note that there is a paging scheme to swap out
1026baef150380d561a4d695a6be4fc509821c23611Calin Culianu   offsets 0x8-0xA using the PAGELOCK register.  See the table below.
1036baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1046baef150380d561a4d695a6be4fc509821c23611Calin Culianu  Register(s)       Pages        R/W?        Description
1056baef150380d561a4d695a6be4fc509821c23611Calin Culianu  --------------------------------------------------------------
1066baef150380d561a4d695a6be4fc509821c23611Calin Culianu  REG_PORTx         All          R/W         Read/Write/Configure IO
1076baef150380d561a4d695a6be4fc509821c23611Calin Culianu  REG_INT_PENDING   All          ReadOnly    Quickly see which INT_IDx has int.
1086baef150380d561a4d695a6be4fc509821c23611Calin Culianu  REG_PAGELOCK      All          WriteOnly   Select a page
1096baef150380d561a4d695a6be4fc509821c23611Calin Culianu  REG_POLx          Pg. 1 only   WriteOnly   Select edge-detection polarity
1106baef150380d561a4d695a6be4fc509821c23611Calin Culianu  REG_ENABx         Pg. 2 only   WriteOnly   Enable/Disable edge-detect. int.
1116baef150380d561a4d695a6be4fc509821c23611Calin Culianu  REG_INT_IDx       Pg. 3 only   R/W         See which ports/bits have ints.
1126baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
1136baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT0 0x0
1146baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT1 0x1
1156baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT2 0x2
1166baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT3 0x3
1176baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT4 0x4
1186baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT5 0x5
1196baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_INT_PENDING 0x6
1206baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PAGELOCK 0x7	/* page selector register, upper 2 bits select a page
1216baef150380d561a4d695a6be4fc509821c23611Calin Culianu				   and bits 0-5 are used to 'lock down' a particular
1226baef150380d561a4d695a6be4fc509821c23611Calin Culianu				   port above to make it readonly.  */
1236baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_POL0 0x8
1246baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_POL1 0x9
1256baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_POL2 0xA
1266baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_ENAB0 0x8
1276baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_ENAB1 0x9
1286baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_ENAB2 0xA
1296baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_INT_ID0 0x8
1306baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_INT_ID1 0x9
1316baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_INT_ID2 0xA
1326baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1336baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define NUM_PAGED_REGS 3
1346baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define NUM_PAGES 4
1356baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define FIRST_PAGED_REG 0x8
1366baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PAGE_BITOFFSET 6
1376baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_LOCK_BITOFFSET 0
1386baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PAGE_MASK (~((0x1<<REG_PAGE_BITOFFSET)-1))
1396baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_LOCK_MASK ~(REG_PAGE_MASK)
1406baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PAGE_POL 1
1416baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PAGE_ENAB 2
1426baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PAGE_INT_ID 3
1436baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1446baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
1456baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Board descriptions for two imaginary boards.  Describing the
1466baef150380d561a4d695a6be4fc509821c23611Calin Culianu * boards in this way is optional, and completely driver-dependent.
1476baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Some drivers use arrays such as this, other do not.
1486baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
14970a6001aeffeaa12f2a1c21470e8f3bdfb6ef8e7Bill Pembertonstruct pcmuio_board {
1506baef150380d561a4d695a6be4fc509821c23611Calin Culianu	const char *name;
1516baef150380d561a4d695a6be4fc509821c23611Calin Culianu	const int num_asics;
1526baef150380d561a4d695a6be4fc509821c23611Calin Culianu	const int num_channels_per_port;
1536baef150380d561a4d695a6be4fc509821c23611Calin Culianu	const int num_ports;
15470a6001aeffeaa12f2a1c21470e8f3bdfb6ef8e7Bill Pemberton};
1556baef150380d561a4d695a6be4fc509821c23611Calin Culianu
15670a6001aeffeaa12f2a1c21470e8f3bdfb6ef8e7Bill Pembertonstatic const struct pcmuio_board pcmuio_boards[] = {
1576baef150380d561a4d695a6be4fc509821c23611Calin Culianu	{
1586baef150380d561a4d695a6be4fc509821c23611Calin Culianu	      name:	"pcmuio48",
1596baef150380d561a4d695a6be4fc509821c23611Calin Culianu	      num_asics:1,
1606baef150380d561a4d695a6be4fc509821c23611Calin Culianu	      num_ports:6,
1616baef150380d561a4d695a6be4fc509821c23611Calin Culianu		},
1626baef150380d561a4d695a6be4fc509821c23611Calin Culianu	{
1636baef150380d561a4d695a6be4fc509821c23611Calin Culianu	      name:	"pcmuio96",
1646baef150380d561a4d695a6be4fc509821c23611Calin Culianu	      num_asics:2,
1656baef150380d561a4d695a6be4fc509821c23611Calin Culianu	      num_ports:12,
1666baef150380d561a4d695a6be4fc509821c23611Calin Culianu		},
1676baef150380d561a4d695a6be4fc509821c23611Calin Culianu};
1686baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1696baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
1706baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Useful for shorthand access to the particular board structure
1716baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
17270a6001aeffeaa12f2a1c21470e8f3bdfb6ef8e7Bill Pemberton#define thisboard ((const struct pcmuio_board *)dev->board_ptr)
1736baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1746baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* this structure is for data unique to this subdevice.  */
1756baef150380d561a4d695a6be4fc509821c23611Calin Culianutypedef struct {
1766baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* mapping of halfwords (bytes) in port/chanarray to iobase */
1776baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long iobases[PORTS_PER_SUBDEV];
1786baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1796baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* The below is only used for intr subdevices */
1806baef150380d561a4d695a6be4fc509821c23611Calin Culianu	struct {
1816baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int asic;	/* if non-negative, this subdev has an interrupt asic */
1826baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int first_chan;	/* if nonnegative, the first channel id for
1836baef150380d561a4d695a6be4fc509821c23611Calin Culianu				   interrupts. */
1846baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int num_asic_chans;	/* the number of asic channels in this subdev
1856baef150380d561a4d695a6be4fc509821c23611Calin Culianu					   that have interrutps */
1866baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int asic_chan;	/* if nonnegative, the first channel id with
1876baef150380d561a4d695a6be4fc509821c23611Calin Culianu				   respect to the asic that has interrupts */
1886baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int enabled_mask;	/* subdev-relative channel mask for channels
1896baef150380d561a4d695a6be4fc509821c23611Calin Culianu					   we are interested in */
1906baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int active;
1916baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int stop_count;
1926baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int continuous;
1936baef150380d561a4d695a6be4fc509821c23611Calin Culianu		spinlock_t spinlock;
1946baef150380d561a4d695a6be4fc509821c23611Calin Culianu	} intr;
1956baef150380d561a4d695a6be4fc509821c23611Calin Culianu} pcmuio_subdev_private;
1966baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1976baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* this structure is for data unique to this hardware driver.  If
1986baef150380d561a4d695a6be4fc509821c23611Calin Culianu   several hardware drivers keep similar information in this structure,
19971b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton   feel free to suggest moving the variable to the struct comedi_device struct.  */
2006baef150380d561a4d695a6be4fc509821c23611Calin Culianutypedef struct {
2016baef150380d561a4d695a6be4fc509821c23611Calin Culianu	struct {
2026baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned char pagelock;	/* current page and lock */
2036baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned char pol[NUM_PAGED_REGS];	/* shadow of POLx registers */
2046baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned char enab[NUM_PAGED_REGS];	/* shadow of ENABx registers */
2056baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int num;
2066baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned long iobase;
2076baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned int irq;
2086baef150380d561a4d695a6be4fc509821c23611Calin Culianu		spinlock_t spinlock;
2096baef150380d561a4d695a6be4fc509821c23611Calin Culianu	} asics[MAX_ASICS];
2106baef150380d561a4d695a6be4fc509821c23611Calin Culianu	pcmuio_subdev_private *sprivs;
2116baef150380d561a4d695a6be4fc509821c23611Calin Culianu} pcmuio_private;
2126baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2136baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
2146baef150380d561a4d695a6be4fc509821c23611Calin Culianu * most drivers define the following macro to make it easy to
2156baef150380d561a4d695a6be4fc509821c23611Calin Culianu * access the private structure.
2166baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
2176baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define devpriv ((pcmuio_private *)dev->private)
2186baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define subpriv ((pcmuio_subdev_private *)s->private)
2196baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
220139dfbdfacb02e3ef3df936d2fabd1ad5f14ea88Bill Pemberton * The struct comedi_driver structure tells the Comedi core module
2216baef150380d561a4d695a6be4fc509821c23611Calin Culianu * which functions to call to configure/deconfigure (attach/detach)
2226baef150380d561a4d695a6be4fc509821c23611Calin Culianu * the board, and also about the kernel module that contains
2236baef150380d561a4d695a6be4fc509821c23611Calin Culianu * the device code.
2246baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
2250707bb04be89b18ee83b5a997e36cc585f0b988dBill Pembertonstatic int pcmuio_attach(struct comedi_device * dev, struct comedi_devconfig * it);
22671b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int pcmuio_detach(struct comedi_device * dev);
2276baef150380d561a4d695a6be4fc509821c23611Calin Culianu
228139dfbdfacb02e3ef3df936d2fabd1ad5f14ea88Bill Pembertonstatic struct comedi_driver driver = {
2296baef150380d561a4d695a6be4fc509821c23611Calin Culianu      driver_name:"pcmuio",
2306baef150380d561a4d695a6be4fc509821c23611Calin Culianu      module:THIS_MODULE,
2316baef150380d561a4d695a6be4fc509821c23611Calin Culianu      attach:pcmuio_attach,
2326baef150380d561a4d695a6be4fc509821c23611Calin Culianu      detach:pcmuio_detach,
2336baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* It is not necessary to implement the following members if you are
2346baef150380d561a4d695a6be4fc509821c23611Calin Culianu * writing a driver for a ISA PnP or PCI card */
2356baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* Most drivers will support multiple types of boards by
2366baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * having an array of board structures.  These were defined
2376baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * in pcmuio_boards[] above.  Note that the element 'name'
2386baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * was first in the structure -- Comedi uses this fact to
2396baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * extract the name of the board without knowing any details
2406baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * about the structure except for its length.
2416baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * When a device is attached (by comedi_config), the name
2426baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * of the device is given to Comedi, and Comedi tries to
2436baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * match it by going through the list of board names.  If
2446baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * there is a match, the address of the pointer is put
2456baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * into dev->board_ptr and driver->attach() is called.
2466baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 *
2476baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * Note that these are not necessary if you can determine
2486baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * the type of board in software.  ISA PnP, PCI, and PCMCIA
2496baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * devices are such boards.
2506baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 */
2516baef150380d561a4d695a6be4fc509821c23611Calin Culianu      board_name:&pcmuio_boards[0].name,
25270a6001aeffeaa12f2a1c21470e8f3bdfb6ef8e7Bill Pemberton      offset:sizeof(struct pcmuio_board),
25370a6001aeffeaa12f2a1c21470e8f3bdfb6ef8e7Bill Pemberton      num_names:sizeof(pcmuio_boards) / sizeof(struct pcmuio_board),
2546baef150380d561a4d695a6be4fc509821c23611Calin Culianu};
2556baef150380d561a4d695a6be4fc509821c23611Calin Culianu
25634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int pcmuio_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
25790035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton	struct comedi_insn * insn, unsigned int * data);
25834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int pcmuio_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s,
25990035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton	struct comedi_insn * insn, unsigned int * data);
2606baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2616baef150380d561a4d695a6be4fc509821c23611Calin Culianustatic irqreturn_t interrupt_pcmuio(int irq, void *d PT_REGS_ARG);
26234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic void pcmuio_stop_intr(struct comedi_device *, struct comedi_subdevice *);
26334c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int pcmuio_cancel(struct comedi_device * dev, struct comedi_subdevice * s);
26434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int pcmuio_cmd(struct comedi_device * dev, struct comedi_subdevice * s);
26534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int pcmuio_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s,
266ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd * cmd);
2676baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2686baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* some helper functions to deal with specifics of this device's registers */
26971b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic void init_asics(struct comedi_device * dev);	/* sets up/clears ASIC chips to defaults */
27071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic void switch_page(struct comedi_device * dev, int asic, int page);
2716baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef notused
27271b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic void lock_port(struct comedi_device * dev, int asic, int port);
27371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic void unlock_port(struct comedi_device * dev, int asic, int port);
2746baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif
2756baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2766baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
2776baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Attach is called by the Comedi core to configure the driver
2786baef150380d561a4d695a6be4fc509821c23611Calin Culianu * for a particular board.  If you specified a board_name array
2796baef150380d561a4d695a6be4fc509821c23611Calin Culianu * in the driver structure, dev->board_ptr contains that
2806baef150380d561a4d695a6be4fc509821c23611Calin Culianu * address.
2816baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
2820707bb04be89b18ee83b5a997e36cc585f0b988dBill Pembertonstatic int pcmuio_attach(struct comedi_device * dev, struct comedi_devconfig * it)
2836baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
28434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
2856baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0;
2866baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long iobase;
2876baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned int irq[MAX_ASICS];
2886baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2896baef150380d561a4d695a6be4fc509821c23611Calin Culianu	iobase = it->options[0];
2906baef150380d561a4d695a6be4fc509821c23611Calin Culianu	irq[0] = it->options[1];
2916baef150380d561a4d695a6be4fc509821c23611Calin Culianu	irq[1] = it->options[2];
2926baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2936baef150380d561a4d695a6be4fc509821c23611Calin Culianu	printk("comedi%d: %s: io: %lx ", dev->minor, driver.driver_name,
2946baef150380d561a4d695a6be4fc509821c23611Calin Culianu		iobase);
2956baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2966baef150380d561a4d695a6be4fc509821c23611Calin Culianu	dev->iobase = iobase;
2976baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2986baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (!iobase || !request_region(iobase,
2996baef150380d561a4d695a6be4fc509821c23611Calin Culianu			thisboard->num_asics * ASIC_IOSIZE,
3006baef150380d561a4d695a6be4fc509821c23611Calin Culianu			driver.driver_name)) {
3016baef150380d561a4d695a6be4fc509821c23611Calin Culianu		printk("I/O port conflict\n");
3026baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return -EIO;
3036baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
3046baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3056baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
3066baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Initialize dev->board_name.  Note that we can use the "thisboard"
3076baef150380d561a4d695a6be4fc509821c23611Calin Culianu * macro now, since we just initialized it in the last line.
3086baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
3096baef150380d561a4d695a6be4fc509821c23611Calin Culianu	dev->board_name = thisboard->name;
3106baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3116baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
3126baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Allocate the private structure area.  alloc_private() is a
3136baef150380d561a4d695a6be4fc509821c23611Calin Culianu * convenient macro defined in comedidev.h.
3146baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
3156baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (alloc_private(dev, sizeof(pcmuio_private)) < 0) {
3166baef150380d561a4d695a6be4fc509821c23611Calin Culianu		printk("cannot allocate private data structure\n");
3176baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return -ENOMEM;
3186baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
3196baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3206baef150380d561a4d695a6be4fc509821c23611Calin Culianu	for (asic = 0; asic < MAX_ASICS; ++asic) {
3216baef150380d561a4d695a6be4fc509821c23611Calin Culianu		devpriv->asics[asic].num = asic;
3226baef150380d561a4d695a6be4fc509821c23611Calin Culianu		devpriv->asics[asic].iobase = dev->iobase + asic * ASIC_IOSIZE;
3236baef150380d561a4d695a6be4fc509821c23611Calin Culianu		devpriv->asics[asic].irq = 0;	/* this gets actually set at the end of
3246baef150380d561a4d695a6be4fc509821c23611Calin Culianu						   this function when we
3256baef150380d561a4d695a6be4fc509821c23611Calin Culianu						   comedi_request_irqs */
3266baef150380d561a4d695a6be4fc509821c23611Calin Culianu		spin_lock_init(&devpriv->asics[asic].spinlock);
3276baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
3286baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3296baef150380d561a4d695a6be4fc509821c23611Calin Culianu	chans_left = CHANS_PER_ASIC * thisboard->num_asics;
3306baef150380d561a4d695a6be4fc509821c23611Calin Culianu	n_subdevs = CALC_N_SUBDEVS(chans_left);
3316baef150380d561a4d695a6be4fc509821c23611Calin Culianu	devpriv->sprivs =
3326baef150380d561a4d695a6be4fc509821c23611Calin Culianu		kcalloc(n_subdevs, sizeof(pcmuio_subdev_private), GFP_KERNEL);
3336baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (!devpriv->sprivs) {
3346baef150380d561a4d695a6be4fc509821c23611Calin Culianu		printk("cannot allocate subdevice private data structures\n");
3356baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return -ENOMEM;
3366baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
3376baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/*
3386baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * Allocate the subdevice structures.  alloc_subdevice() is a
3396baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * convenient macro defined in comedidev.h.
3406baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 *
3416baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the
3426baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * 96-channel version of the board.
3436baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 */
3446baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (alloc_subdevices(dev, n_subdevs) < 0) {
3456baef150380d561a4d695a6be4fc509821c23611Calin Culianu		printk("cannot allocate subdevice data structures\n");
3466baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return -ENOMEM;
3476baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
3486baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3496baef150380d561a4d695a6be4fc509821c23611Calin Culianu	port = 0;
3506baef150380d561a4d695a6be4fc509821c23611Calin Culianu	asic = 0;
3516baef150380d561a4d695a6be4fc509821c23611Calin Culianu	for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
3526baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int byte_no;
3536baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3546baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s = dev->subdevices + sdev_no;
3556baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->private = devpriv->sprivs + sdev_no;
3566baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->maxdata = 1;
3576baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->range_table = &range_digital;
3586baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
3596baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->type = COMEDI_SUBD_DIO;
3606baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->insn_bits = pcmuio_dio_insn_bits;
3616baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->insn_config = pcmuio_dio_insn_config;
3626baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->n_chan = MIN(chans_left, MAX_CHANS_PER_SUBDEV);
3636baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.asic = -1;
3646baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.first_chan = -1;
3656baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.asic_chan = -1;
3666baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.num_asic_chans = -1;
3676baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.active = 0;
3686baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->len_chanlist = 1;
3696baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3706baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* save the ioport address for each 'port' of 8 channels in the
3716baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   subdevice */
3726baef150380d561a4d695a6be4fc509821c23611Calin Culianu		for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
3736baef150380d561a4d695a6be4fc509821c23611Calin Culianu			if (port >= PORTS_PER_ASIC) {
3746baef150380d561a4d695a6be4fc509821c23611Calin Culianu				port = 0;
3756baef150380d561a4d695a6be4fc509821c23611Calin Culianu				++asic;
3766baef150380d561a4d695a6be4fc509821c23611Calin Culianu				thisasic_chanct = 0;
3776baef150380d561a4d695a6be4fc509821c23611Calin Culianu			}
3786baef150380d561a4d695a6be4fc509821c23611Calin Culianu			subpriv->iobases[byte_no] =
3796baef150380d561a4d695a6be4fc509821c23611Calin Culianu				devpriv->asics[asic].iobase + port;
3806baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3816baef150380d561a4d695a6be4fc509821c23611Calin Culianu			if (thisasic_chanct <
3826baef150380d561a4d695a6be4fc509821c23611Calin Culianu				CHANS_PER_PORT * INTR_PORTS_PER_ASIC
3836baef150380d561a4d695a6be4fc509821c23611Calin Culianu				&& subpriv->intr.asic < 0) {
3846baef150380d561a4d695a6be4fc509821c23611Calin Culianu				/* this is an interrupt subdevice, so setup the struct */
3856baef150380d561a4d695a6be4fc509821c23611Calin Culianu				subpriv->intr.asic = asic;
3866baef150380d561a4d695a6be4fc509821c23611Calin Culianu				subpriv->intr.active = 0;
3876baef150380d561a4d695a6be4fc509821c23611Calin Culianu				subpriv->intr.stop_count = 0;
3886baef150380d561a4d695a6be4fc509821c23611Calin Culianu				subpriv->intr.first_chan = byte_no * 8;
3896baef150380d561a4d695a6be4fc509821c23611Calin Culianu				subpriv->intr.asic_chan = thisasic_chanct;
3906baef150380d561a4d695a6be4fc509821c23611Calin Culianu				subpriv->intr.num_asic_chans =
3916baef150380d561a4d695a6be4fc509821c23611Calin Culianu					s->n_chan - subpriv->intr.first_chan;
3926baef150380d561a4d695a6be4fc509821c23611Calin Culianu				dev->read_subdev = s;
3936baef150380d561a4d695a6be4fc509821c23611Calin Culianu				s->subdev_flags |= SDF_CMD_READ;
3946baef150380d561a4d695a6be4fc509821c23611Calin Culianu				s->cancel = pcmuio_cancel;
3956baef150380d561a4d695a6be4fc509821c23611Calin Culianu				s->do_cmd = pcmuio_cmd;
3966baef150380d561a4d695a6be4fc509821c23611Calin Culianu				s->do_cmdtest = pcmuio_cmdtest;
3976baef150380d561a4d695a6be4fc509821c23611Calin Culianu				s->len_chanlist = subpriv->intr.num_asic_chans;
3986baef150380d561a4d695a6be4fc509821c23611Calin Culianu			}
3996baef150380d561a4d695a6be4fc509821c23611Calin Culianu			thisasic_chanct += CHANS_PER_PORT;
4006baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
4016baef150380d561a4d695a6be4fc509821c23611Calin Culianu		spin_lock_init(&subpriv->intr.spinlock);
4026baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4036baef150380d561a4d695a6be4fc509821c23611Calin Culianu		chans_left -= s->n_chan;
4046baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4056baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (!chans_left) {
4066baef150380d561a4d695a6be4fc509821c23611Calin Culianu			asic = 0;	/* reset the asic to our first asic, to do intr subdevs */
4076baef150380d561a4d695a6be4fc509821c23611Calin Culianu			port = 0;
4086baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
4096baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4106baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
4116baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4126baef150380d561a4d695a6be4fc509821c23611Calin Culianu	init_asics(dev);	/* clear out all the registers, basically */
4136baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4146baef150380d561a4d695a6be4fc509821c23611Calin Culianu	for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
4156baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (irq[asic]
4166baef150380d561a4d695a6be4fc509821c23611Calin Culianu			&& comedi_request_irq(irq[asic], interrupt_pcmuio,
4176baef150380d561a4d695a6be4fc509821c23611Calin Culianu				IRQF_SHARED, thisboard->name, dev)) {
4186baef150380d561a4d695a6be4fc509821c23611Calin Culianu			int i;
4196baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* unroll the allocated irqs.. */
4206baef150380d561a4d695a6be4fc509821c23611Calin Culianu			for (i = asic - 1; i >= 0; --i) {
4216baef150380d561a4d695a6be4fc509821c23611Calin Culianu				comedi_free_irq(irq[i], dev);
4226baef150380d561a4d695a6be4fc509821c23611Calin Culianu				devpriv->asics[i].irq = irq[i] = 0;
4236baef150380d561a4d695a6be4fc509821c23611Calin Culianu			}
4246baef150380d561a4d695a6be4fc509821c23611Calin Culianu			irq[asic] = 0;
4256baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
4266baef150380d561a4d695a6be4fc509821c23611Calin Culianu		devpriv->asics[asic].irq = irq[asic];
4276baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
4286baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4296baef150380d561a4d695a6be4fc509821c23611Calin Culianu	dev->irq = irq[0];	/* grr.. wish comedi dev struct supported multiple
4306baef150380d561a4d695a6be4fc509821c23611Calin Culianu				   irqs.. */
4316baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4326baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (irq[0]) {
4336baef150380d561a4d695a6be4fc509821c23611Calin Culianu		printk("irq: %u ", irq[0]);
4346baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (irq[1] && thisboard->num_asics == 2)
4356baef150380d561a4d695a6be4fc509821c23611Calin Culianu			printk("second ASIC irq: %u ", irq[1]);
4366baef150380d561a4d695a6be4fc509821c23611Calin Culianu	} else {
4376baef150380d561a4d695a6be4fc509821c23611Calin Culianu		printk("(IRQ mode disabled) ");
4386baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
4396baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4406baef150380d561a4d695a6be4fc509821c23611Calin Culianu	printk("attached\n");
4416baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4426baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 1;
4436baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
4446baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4456baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
4466baef150380d561a4d695a6be4fc509821c23611Calin Culianu * _detach is called to deconfigure a device.  It should deallocate
4476baef150380d561a4d695a6be4fc509821c23611Calin Culianu * resources.
4486baef150380d561a4d695a6be4fc509821c23611Calin Culianu * This function is also called when _attach() fails, so it should be
4496baef150380d561a4d695a6be4fc509821c23611Calin Culianu * careful not to release resources that were not necessarily
4506baef150380d561a4d695a6be4fc509821c23611Calin Culianu * allocated by _attach().  dev->private and dev->subdevices are
4516baef150380d561a4d695a6be4fc509821c23611Calin Culianu * deallocated automatically by the core.
4526baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
45371b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic int pcmuio_detach(struct comedi_device * dev)
4546baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
4556baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int i;
4566baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4576baef150380d561a4d695a6be4fc509821c23611Calin Culianu	printk("comedi%d: %s: remove\n", dev->minor, driver.driver_name);
4586baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (dev->iobase)
4596baef150380d561a4d695a6be4fc509821c23611Calin Culianu		release_region(dev->iobase, ASIC_IOSIZE * thisboard->num_asics);
4606baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4616baef150380d561a4d695a6be4fc509821c23611Calin Culianu	for (i = 0; i < MAX_ASICS; ++i) {
4626baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (devpriv->asics[i].irq)
4636baef150380d561a4d695a6be4fc509821c23611Calin Culianu			comedi_free_irq(devpriv->asics[i].irq, dev);
4646baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
4656baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4666baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (devpriv && devpriv->sprivs)
4676baef150380d561a4d695a6be4fc509821c23611Calin Culianu		kfree(devpriv->sprivs);
4686baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4696baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 0;
4706baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
4716baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4726baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* DIO devices are slightly special.  Although it is possible to
4736baef150380d561a4d695a6be4fc509821c23611Calin Culianu * implement the insn_read/insn_write interface, it is much more
4746baef150380d561a4d695a6be4fc509821c23611Calin Culianu * useful to applications if you implement the insn_bits interface.
4756baef150380d561a4d695a6be4fc509821c23611Calin Culianu * This allows packed reading/writing of the DIO channels.  The
4766baef150380d561a4d695a6be4fc509821c23611Calin Culianu * comedi core can convert between insn_bits and insn_read/write */
47734c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int pcmuio_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
47890035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton	struct comedi_insn * insn, unsigned int * data)
4796baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
4806baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int byte_no;
4816baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (insn->n != 2)
4826baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return -EINVAL;
4836baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4846baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* NOTE:
4856baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   reading a 0 means this channel was high
4866baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   writine a 0 sets the channel high
4876baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   reading a 1 means this channel was low
4886baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   writing a 1 means set this channel low
4896baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4906baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   Therefore everything is always inverted. */
4916baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4926baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* The insn data is a mask in data[0] and the new data
4936baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * in data[1], each channel cooresponding to a bit. */
4946baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4956baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef DAMMIT_ITS_BROKEN
4966baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* DEBUG */
4976baef150380d561a4d695a6be4fc509821c23611Calin Culianu	printk("write mask: %08x  data: %08x\n", data[0], data[1]);
4986baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif
4996baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5006baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s->state = 0;
5016baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5026baef150380d561a4d695a6be4fc509821c23611Calin Culianu	for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) {
5036baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* address of 8-bit port */
5046baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned long ioaddr = subpriv->iobases[byte_no],
5056baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* bit offset of port in 32-bit doubleword */
5066baef150380d561a4d695a6be4fc509821c23611Calin Culianu			offset = byte_no * 8;
5076baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* this 8-bit port's data */
5086baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned char byte = 0,
5096baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* The write mask for this port (if any) */
5106baef150380d561a4d695a6be4fc509821c23611Calin Culianu			write_mask_byte = (data[0] >> offset) & 0xff,
5116baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* The data byte for this port */
5126baef150380d561a4d695a6be4fc509821c23611Calin Culianu			data_byte = (data[1] >> offset) & 0xff;
5136baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5146baef150380d561a4d695a6be4fc509821c23611Calin Culianu		byte = inb(ioaddr);	/* read all 8-bits for this port */
5156baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5166baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef DAMMIT_ITS_BROKEN
5176baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* DEBUG */
5186baef150380d561a4d695a6be4fc509821c23611Calin Culianu		printk("byte %d wmb %02x db %02x offset %02d io %04x, data_in %02x ", byte_no, (unsigned)write_mask_byte, (unsigned)data_byte, offset, ioaddr, (unsigned)byte);
5196baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif
5206baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5216baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (write_mask_byte) {
5226baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* this byte has some write_bits -- so set the output lines */
5236baef150380d561a4d695a6be4fc509821c23611Calin Culianu			byte &= ~write_mask_byte;	/* clear bits for write mask */
5246baef150380d561a4d695a6be4fc509821c23611Calin Culianu			byte |= ~data_byte & write_mask_byte;	/* set to inverted data_byte */
5256baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* Write out the new digital output state */
5266baef150380d561a4d695a6be4fc509821c23611Calin Culianu			outb(byte, ioaddr);
5276baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
5286baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef DAMMIT_ITS_BROKEN
5296baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* DEBUG */
5306baef150380d561a4d695a6be4fc509821c23611Calin Culianu		printk("data_out_byte %02x\n", (unsigned)byte);
5316baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif
5326baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* save the digital input lines for this byte.. */
5336baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->state |= ((unsigned int)byte) << offset;
5346baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
5356baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5366baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* now return the DIO lines to data[1] - note they came inverted! */
5376baef150380d561a4d695a6be4fc509821c23611Calin Culianu	data[1] = ~s->state;
5386baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5396baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef DAMMIT_ITS_BROKEN
5406baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* DEBUG */
5416baef150380d561a4d695a6be4fc509821c23611Calin Culianu	printk("s->state %08x data_out %08x\n", s->state, data[1]);
5426baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif
5436baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5446baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 2;
5456baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
5466baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5476baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* The input or output configuration of each digital line is
5486baef150380d561a4d695a6be4fc509821c23611Calin Culianu * configured by a special insn_config instruction.  chanspec
5496baef150380d561a4d695a6be4fc509821c23611Calin Culianu * contains the channel to be changed, and data[0] contains the
5506baef150380d561a4d695a6be4fc509821c23611Calin Culianu * value COMEDI_INPUT or COMEDI_OUTPUT. */
55134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int pcmuio_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s,
55290035c0886b256d75bced13b3b3cea5234aff136Bill Pemberton	struct comedi_insn * insn, unsigned int * data)
5536baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
5546baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no =
5556baef150380d561a4d695a6be4fc509821c23611Calin Culianu		chan % 8;
5566baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long ioaddr;
5576baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned char byte;
5586baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5596baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* Compute ioaddr for this channel */
5606baef150380d561a4d695a6be4fc509821c23611Calin Culianu	ioaddr = subpriv->iobases[byte_no];
5616baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5626baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* NOTE:
5636baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   writing a 0 an IO channel's bit sets the channel to INPUT
5646baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   and pulls the line high as well
5656baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5666baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   writing a 1 to an IO channel's  bit pulls the line low
5676baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5686baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   All channels are implicitly always in OUTPUT mode -- but when
5696baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   they are high they can be considered to be in INPUT mode..
5706baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5716baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   Thus, we only force channels low if the config request was INPUT,
5726baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   otherwise we do nothing to the hardware.    */
5736baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5746baef150380d561a4d695a6be4fc509821c23611Calin Culianu	switch (data[0]) {
5756baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case INSN_CONFIG_DIO_OUTPUT:
5766baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* save to io_bits -- don't actually do anything since
5776baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   all input channels are also output channels... */
5786baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->io_bits |= 1 << chan;
5796baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
5806baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case INSN_CONFIG_DIO_INPUT:
5816baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* write a 0 to the actual register representing the channel
5826baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   to set it to 'input'.  0 means "float high". */
5836baef150380d561a4d695a6be4fc509821c23611Calin Culianu		byte = inb(ioaddr);
5846baef150380d561a4d695a6be4fc509821c23611Calin Culianu		byte &= ~(1 << bit_no);
5856baef150380d561a4d695a6be4fc509821c23611Calin Culianu				/**< set input channel to '0' */
5866baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5876baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* write out byte -- this is the only time we actually affect the
5886baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   hardware as all channels are implicitly output -- but input
5896baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   channels are set to float-high */
5906baef150380d561a4d695a6be4fc509821c23611Calin Culianu		outb(byte, ioaddr);
5916baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5926baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* save to io_bits */
5936baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->io_bits &= ~(1 << chan);
5946baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
5956baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5966baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case INSN_CONFIG_DIO_QUERY:
5976baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* retreive from shadow register */
5986baef150380d561a4d695a6be4fc509821c23611Calin Culianu		data[1] =
5996baef150380d561a4d695a6be4fc509821c23611Calin Culianu			(s->
6006baef150380d561a4d695a6be4fc509821c23611Calin Culianu			io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
6016baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return insn->n;
6026baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
6036baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6046baef150380d561a4d695a6be4fc509821c23611Calin Culianu	default:
6056baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return -EINVAL;
6066baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
6076baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
6086baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6096baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return insn->n;
6106baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
6116baef150380d561a4d695a6be4fc509821c23611Calin Culianu
61271b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic void init_asics(struct comedi_device * dev)
6136baef150380d561a4d695a6be4fc509821c23611Calin Culianu{				/* sets up an
6146baef150380d561a4d695a6be4fc509821c23611Calin Culianu				   ASIC chip to defaults */
6156baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int asic;
6166baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6176baef150380d561a4d695a6be4fc509821c23611Calin Culianu	for (asic = 0; asic < thisboard->num_asics; ++asic) {
6186baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int port, page;
6196baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned long baseaddr = dev->iobase + asic * ASIC_IOSIZE;
6206baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6216baef150380d561a4d695a6be4fc509821c23611Calin Culianu		switch_page(dev, asic, 0);	/* switch back to page 0 */
6226baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6236baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* first, clear all the DIO port bits */
6246baef150380d561a4d695a6be4fc509821c23611Calin Culianu		for (port = 0; port < PORTS_PER_ASIC; ++port)
6256baef150380d561a4d695a6be4fc509821c23611Calin Culianu			outb(0, baseaddr + REG_PORT0 + port);
6266baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6276baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* Next, clear all the paged registers for each page */
6286baef150380d561a4d695a6be4fc509821c23611Calin Culianu		for (page = 1; page < NUM_PAGES; ++page) {
6296baef150380d561a4d695a6be4fc509821c23611Calin Culianu			int reg;
6306baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* now clear all the paged registers */
6316baef150380d561a4d695a6be4fc509821c23611Calin Culianu			switch_page(dev, asic, page);
6326baef150380d561a4d695a6be4fc509821c23611Calin Culianu			for (reg = FIRST_PAGED_REG;
6336baef150380d561a4d695a6be4fc509821c23611Calin Culianu				reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg)
6346baef150380d561a4d695a6be4fc509821c23611Calin Culianu				outb(0, baseaddr + reg);
6356baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
6366baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6376baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* DEBUG  set rising edge interrupts on port0 of both asics */
6386baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/*switch_page(dev, asic, PAGE_POL);
6396baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   outb(0xff, baseaddr + REG_POL0);
6406baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   switch_page(dev, asic, PAGE_ENAB);
6416baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   outb(0xff, baseaddr + REG_ENAB0); */
6426baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* END DEBUG */
6436baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6446baef150380d561a4d695a6be4fc509821c23611Calin Culianu		switch_page(dev, asic, 0);	/* switch back to default page 0 */
6456baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6466baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
6476baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
6486baef150380d561a4d695a6be4fc509821c23611Calin Culianu
64971b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic void switch_page(struct comedi_device * dev, int asic, int page)
6506baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
6516baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (asic < 0 || asic >= thisboard->num_asics)
6526baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return;		/* paranoia */
6536baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (page < 0 || page >= NUM_PAGES)
6546baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return;		/* more paranoia */
6556baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6566baef150380d561a4d695a6be4fc509821c23611Calin Culianu	devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
6576baef150380d561a4d695a6be4fc509821c23611Calin Culianu	devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
6586baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6596baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* now write out the shadow register */
6606baef150380d561a4d695a6be4fc509821c23611Calin Culianu	outb(devpriv->asics[asic].pagelock,
6616baef150380d561a4d695a6be4fc509821c23611Calin Culianu		dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
6626baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
6636baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6646baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef notused
66571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic void lock_port(struct comedi_device * dev, int asic, int port)
6666baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
6676baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (asic < 0 || asic >= thisboard->num_asics)
6686baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return;		/* paranoia */
6696baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (port < 0 || port >= PORTS_PER_ASIC)
6706baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return;		/* more paranoia */
6716baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6726baef150380d561a4d695a6be4fc509821c23611Calin Culianu	devpriv->asics[asic].pagelock |= 0x1 << port;
6736baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* now write out the shadow register */
6746baef150380d561a4d695a6be4fc509821c23611Calin Culianu	outb(devpriv->asics[asic].pagelock,
6756baef150380d561a4d695a6be4fc509821c23611Calin Culianu		dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
6766baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
6776baef150380d561a4d695a6be4fc509821c23611Calin Culianu
67871b5f4f11971dea972832ad63a994c7e5b45db6bBill Pembertonstatic void unlock_port(struct comedi_device * dev, int asic, int port)
6796baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
6806baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (asic < 0 || asic >= thisboard->num_asics)
6816baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return;		/* paranoia */
6826baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (port < 0 || port >= PORTS_PER_ASIC)
6836baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return;		/* more paranoia */
6846baef150380d561a4d695a6be4fc509821c23611Calin Culianu	devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK;
6856baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* now write out the shadow register */
6866baef150380d561a4d695a6be4fc509821c23611Calin Culianu	outb(devpriv->asics[asic].pagelock,
6876baef150380d561a4d695a6be4fc509821c23611Calin Culianu		dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
6886baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
6896baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif /* notused */
6906baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6916baef150380d561a4d695a6be4fc509821c23611Calin Culianustatic irqreturn_t interrupt_pcmuio(int irq, void *d PT_REGS_ARG)
6926baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
6936baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int asic, got1 = 0;
69471b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = (struct comedi_device *) d;
6956baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6966baef150380d561a4d695a6be4fc509821c23611Calin Culianu	for (asic = 0; asic < MAX_ASICS; ++asic) {
6976baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (irq == devpriv->asics[asic].irq) {
6986baef150380d561a4d695a6be4fc509821c23611Calin Culianu			unsigned long flags;
6996baef150380d561a4d695a6be4fc509821c23611Calin Culianu			unsigned triggered = 0;
7006baef150380d561a4d695a6be4fc509821c23611Calin Culianu			unsigned long iobase = devpriv->asics[asic].iobase;
7016baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* it is an interrupt for ASIC #asic */
7026baef150380d561a4d695a6be4fc509821c23611Calin Culianu			unsigned char int_pend;
7036baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7046baef150380d561a4d695a6be4fc509821c23611Calin Culianu			comedi_spin_lock_irqsave(&devpriv->asics[asic].spinlock,
7056baef150380d561a4d695a6be4fc509821c23611Calin Culianu				flags);
7066baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7076baef150380d561a4d695a6be4fc509821c23611Calin Culianu			int_pend = inb(iobase + REG_INT_PENDING) & 0x07;
7086baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7096baef150380d561a4d695a6be4fc509821c23611Calin Culianu			if (int_pend) {
7106baef150380d561a4d695a6be4fc509821c23611Calin Culianu				int port;
7116baef150380d561a4d695a6be4fc509821c23611Calin Culianu				for (port = 0; port < INTR_PORTS_PER_ASIC;
7126baef150380d561a4d695a6be4fc509821c23611Calin Culianu					++port) {
7136baef150380d561a4d695a6be4fc509821c23611Calin Culianu					if (int_pend & (0x1 << port)) {
7146baef150380d561a4d695a6be4fc509821c23611Calin Culianu						unsigned char
7156baef150380d561a4d695a6be4fc509821c23611Calin Culianu							io_lines_with_edges = 0;
7166baef150380d561a4d695a6be4fc509821c23611Calin Culianu						switch_page(dev, asic,
7176baef150380d561a4d695a6be4fc509821c23611Calin Culianu							PAGE_INT_ID);
7186baef150380d561a4d695a6be4fc509821c23611Calin Culianu						io_lines_with_edges =
7196baef150380d561a4d695a6be4fc509821c23611Calin Culianu							inb(iobase +
7206baef150380d561a4d695a6be4fc509821c23611Calin Culianu							REG_INT_ID0 + port);
7216baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7226baef150380d561a4d695a6be4fc509821c23611Calin Culianu						if (io_lines_with_edges)
7236baef150380d561a4d695a6be4fc509821c23611Calin Culianu							/* clear pending interrupt */
7246baef150380d561a4d695a6be4fc509821c23611Calin Culianu							outb(0, iobase +
7256baef150380d561a4d695a6be4fc509821c23611Calin Culianu								REG_INT_ID0 +
7266baef150380d561a4d695a6be4fc509821c23611Calin Culianu								port);
7276baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7286baef150380d561a4d695a6be4fc509821c23611Calin Culianu						triggered |=
7296baef150380d561a4d695a6be4fc509821c23611Calin Culianu							io_lines_with_edges <<
7306baef150380d561a4d695a6be4fc509821c23611Calin Culianu							port * 8;
7316baef150380d561a4d695a6be4fc509821c23611Calin Culianu					}
7326baef150380d561a4d695a6be4fc509821c23611Calin Culianu				}
7336baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7346baef150380d561a4d695a6be4fc509821c23611Calin Culianu				++got1;
7356baef150380d561a4d695a6be4fc509821c23611Calin Culianu			}
7366baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7376baef150380d561a4d695a6be4fc509821c23611Calin Culianu			comedi_spin_unlock_irqrestore(&devpriv->asics[asic].
7386baef150380d561a4d695a6be4fc509821c23611Calin Culianu				spinlock, flags);
7396baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7406baef150380d561a4d695a6be4fc509821c23611Calin Culianu			if (triggered) {
74134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton				struct comedi_subdevice *s;
7426baef150380d561a4d695a6be4fc509821c23611Calin Culianu				/* TODO here: dispatch io lines to subdevs with commands.. */
7436baef150380d561a4d695a6be4fc509821c23611Calin Culianu				printk("PCMUIO DEBUG: got edge detect interrupt %d asic %d which_chans: %06x\n", irq, asic, triggered);
7446baef150380d561a4d695a6be4fc509821c23611Calin Culianu				for (s = dev->subdevices;
7456baef150380d561a4d695a6be4fc509821c23611Calin Culianu					s < dev->subdevices + dev->n_subdevices;
7466baef150380d561a4d695a6be4fc509821c23611Calin Culianu					++s) {
7476baef150380d561a4d695a6be4fc509821c23611Calin Culianu					if (subpriv->intr.asic == asic) {	/* this is an interrupt subdev, and it matches this asic! */
7486baef150380d561a4d695a6be4fc509821c23611Calin Culianu						unsigned long flags;
7496baef150380d561a4d695a6be4fc509821c23611Calin Culianu						unsigned oldevents;
7506baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7516baef150380d561a4d695a6be4fc509821c23611Calin Culianu						comedi_spin_lock_irqsave
7526baef150380d561a4d695a6be4fc509821c23611Calin Culianu							(&subpriv->intr.
7536baef150380d561a4d695a6be4fc509821c23611Calin Culianu							spinlock, flags);
7546baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7556baef150380d561a4d695a6be4fc509821c23611Calin Culianu						oldevents = s->async->events;
7566baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7576baef150380d561a4d695a6be4fc509821c23611Calin Culianu						if (subpriv->intr.active) {
7586baef150380d561a4d695a6be4fc509821c23611Calin Culianu							unsigned mytrig =
7596baef150380d561a4d695a6be4fc509821c23611Calin Culianu								((triggered >>
7606baef150380d561a4d695a6be4fc509821c23611Calin Culianu									subpriv->
7616baef150380d561a4d695a6be4fc509821c23611Calin Culianu									intr.
7626baef150380d561a4d695a6be4fc509821c23611Calin Culianu									asic_chan)
7636baef150380d561a4d695a6be4fc509821c23611Calin Culianu								& ((0x1 << subpriv->intr.num_asic_chans) - 1)) << subpriv->intr.first_chan;
7646baef150380d561a4d695a6be4fc509821c23611Calin Culianu							if (mytrig & subpriv->
7656baef150380d561a4d695a6be4fc509821c23611Calin Culianu								intr.
7666baef150380d561a4d695a6be4fc509821c23611Calin Culianu								enabled_mask) {
767790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton								unsigned int val =
7686baef150380d561a4d695a6be4fc509821c23611Calin Culianu									0;
7696baef150380d561a4d695a6be4fc509821c23611Calin Culianu								unsigned int n,
7706baef150380d561a4d695a6be4fc509821c23611Calin Culianu									ch, len;
7716baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7726baef150380d561a4d695a6be4fc509821c23611Calin Culianu								len = s->async->
7736baef150380d561a4d695a6be4fc509821c23611Calin Culianu									cmd.
7746baef150380d561a4d695a6be4fc509821c23611Calin Culianu									chanlist_len;
7756baef150380d561a4d695a6be4fc509821c23611Calin Culianu								for (n = 0;
7766baef150380d561a4d695a6be4fc509821c23611Calin Culianu									n < len;
7776baef150380d561a4d695a6be4fc509821c23611Calin Culianu									n++) {
7786baef150380d561a4d695a6be4fc509821c23611Calin Culianu									ch = CR_CHAN(s->async->cmd.chanlist[n]);
7796baef150380d561a4d695a6be4fc509821c23611Calin Culianu									if (mytrig & (1U << ch)) {
7806baef150380d561a4d695a6be4fc509821c23611Calin Culianu										val |= (1U << n);
7816baef150380d561a4d695a6be4fc509821c23611Calin Culianu									}
7826baef150380d561a4d695a6be4fc509821c23611Calin Culianu								}
7836baef150380d561a4d695a6be4fc509821c23611Calin Culianu								/* Write the scan to the buffer. */
784790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton								if (comedi_buf_put(s->async, ((short *) & val)[0])
7856baef150380d561a4d695a6be4fc509821c23611Calin Culianu									&&
7866baef150380d561a4d695a6be4fc509821c23611Calin Culianu									comedi_buf_put
787790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton									(s->async, ((short *) & val)[1])) {
7886baef150380d561a4d695a6be4fc509821c23611Calin Culianu									s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
7896baef150380d561a4d695a6be4fc509821c23611Calin Culianu								} else {
7906baef150380d561a4d695a6be4fc509821c23611Calin Culianu									/* Overflow! Stop acquisition!! */
7916baef150380d561a4d695a6be4fc509821c23611Calin Culianu									/* TODO: STOP_ACQUISITION_CALL_HERE!! */
7926baef150380d561a4d695a6be4fc509821c23611Calin Culianu									pcmuio_stop_intr
7936baef150380d561a4d695a6be4fc509821c23611Calin Culianu										(dev,
7946baef150380d561a4d695a6be4fc509821c23611Calin Culianu										s);
7956baef150380d561a4d695a6be4fc509821c23611Calin Culianu								}
7966baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7976baef150380d561a4d695a6be4fc509821c23611Calin Culianu								/* Check for end of acquisition. */
7986baef150380d561a4d695a6be4fc509821c23611Calin Culianu								if (!subpriv->
7996baef150380d561a4d695a6be4fc509821c23611Calin Culianu									intr.
8006baef150380d561a4d695a6be4fc509821c23611Calin Culianu									continuous)
8016baef150380d561a4d695a6be4fc509821c23611Calin Culianu								{
8026baef150380d561a4d695a6be4fc509821c23611Calin Culianu									/* stop_src == TRIG_COUNT */
8036baef150380d561a4d695a6be4fc509821c23611Calin Culianu									if (subpriv->intr.stop_count > 0) {
8046baef150380d561a4d695a6be4fc509821c23611Calin Culianu										subpriv->
8056baef150380d561a4d695a6be4fc509821c23611Calin Culianu											intr.
8066baef150380d561a4d695a6be4fc509821c23611Calin Culianu											stop_count--;
8076baef150380d561a4d695a6be4fc509821c23611Calin Culianu										if (subpriv->intr.stop_count == 0) {
8086baef150380d561a4d695a6be4fc509821c23611Calin Culianu											s->async->events |= COMEDI_CB_EOA;
8096baef150380d561a4d695a6be4fc509821c23611Calin Culianu											/* TODO: STOP_ACQUISITION_CALL_HERE!! */
8106baef150380d561a4d695a6be4fc509821c23611Calin Culianu											pcmuio_stop_intr
8116baef150380d561a4d695a6be4fc509821c23611Calin Culianu												(dev,
8126baef150380d561a4d695a6be4fc509821c23611Calin Culianu												s);
8136baef150380d561a4d695a6be4fc509821c23611Calin Culianu										}
8146baef150380d561a4d695a6be4fc509821c23611Calin Culianu									}
8156baef150380d561a4d695a6be4fc509821c23611Calin Culianu								}
8166baef150380d561a4d695a6be4fc509821c23611Calin Culianu							}
8176baef150380d561a4d695a6be4fc509821c23611Calin Culianu						}
8186baef150380d561a4d695a6be4fc509821c23611Calin Culianu
8196baef150380d561a4d695a6be4fc509821c23611Calin Culianu						comedi_spin_unlock_irqrestore
8206baef150380d561a4d695a6be4fc509821c23611Calin Culianu							(&subpriv->intr.
8216baef150380d561a4d695a6be4fc509821c23611Calin Culianu							spinlock, flags);
8226baef150380d561a4d695a6be4fc509821c23611Calin Culianu
8236baef150380d561a4d695a6be4fc509821c23611Calin Culianu						if (oldevents !=
8246baef150380d561a4d695a6be4fc509821c23611Calin Culianu							s->async->events) {
8256baef150380d561a4d695a6be4fc509821c23611Calin Culianu							comedi_event(dev, s);
8266baef150380d561a4d695a6be4fc509821c23611Calin Culianu						}
8276baef150380d561a4d695a6be4fc509821c23611Calin Culianu
8286baef150380d561a4d695a6be4fc509821c23611Calin Culianu					}
8296baef150380d561a4d695a6be4fc509821c23611Calin Culianu
8306baef150380d561a4d695a6be4fc509821c23611Calin Culianu				}
8316baef150380d561a4d695a6be4fc509821c23611Calin Culianu			}
8326baef150380d561a4d695a6be4fc509821c23611Calin Culianu
8336baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
8346baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
8356baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (!got1)
8366baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return IRQ_NONE;	/* interrupt from other source */
8376baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return IRQ_HANDLED;
8386baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
8396baef150380d561a4d695a6be4fc509821c23611Calin Culianu
84034c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic void pcmuio_stop_intr(struct comedi_device * dev, struct comedi_subdevice * s)
8416baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
8426baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int nports, firstport, asic, port;
8436baef150380d561a4d695a6be4fc509821c23611Calin Culianu
8446baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if ((asic = subpriv->intr.asic) < 0)
8456baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return;		/* not an interrupt subdev */
8466baef150380d561a4d695a6be4fc509821c23611Calin Culianu
8476baef150380d561a4d695a6be4fc509821c23611Calin Culianu	subpriv->intr.enabled_mask = 0;
8486baef150380d561a4d695a6be4fc509821c23611Calin Culianu	subpriv->intr.active = 0;
8496baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s->async->inttrig = 0;
8506baef150380d561a4d695a6be4fc509821c23611Calin Culianu	nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
8516baef150380d561a4d695a6be4fc509821c23611Calin Culianu	firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
8526baef150380d561a4d695a6be4fc509821c23611Calin Culianu	switch_page(dev, asic, PAGE_ENAB);
8536baef150380d561a4d695a6be4fc509821c23611Calin Culianu	for (port = firstport; port < firstport + nports; ++port) {
8546baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* disable all intrs for this subdev.. */
8556baef150380d561a4d695a6be4fc509821c23611Calin Culianu		outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
8566baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
8576baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
8586baef150380d561a4d695a6be4fc509821c23611Calin Culianu
85934c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int pcmuio_start_intr(struct comedi_device * dev, struct comedi_subdevice * s)
8606baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
8616baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (!subpriv->intr.continuous && subpriv->intr.stop_count == 0) {
8626baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* An empty acquisition! */
8636baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->async->events |= COMEDI_CB_EOA;
8646baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.active = 0;
8656baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return 1;
8666baef150380d561a4d695a6be4fc509821c23611Calin Culianu	} else {
8676baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned bits = 0, pol_bits = 0, n;
8686baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int nports, firstport, asic, port;
869ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton		struct comedi_cmd *cmd = &s->async->cmd;
8706baef150380d561a4d695a6be4fc509821c23611Calin Culianu
8716baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if ((asic = subpriv->intr.asic) < 0)
8726baef150380d561a4d695a6be4fc509821c23611Calin Culianu			return 1;	/* not an interrupt
8736baef150380d561a4d695a6be4fc509821c23611Calin Culianu					   subdev */
8746baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.enabled_mask = 0;
8756baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.active = 1;
8766baef150380d561a4d695a6be4fc509821c23611Calin Culianu		nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
8776baef150380d561a4d695a6be4fc509821c23611Calin Culianu		firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
8786baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (cmd->chanlist) {
8796baef150380d561a4d695a6be4fc509821c23611Calin Culianu			for (n = 0; n < cmd->chanlist_len; n++) {
8806baef150380d561a4d695a6be4fc509821c23611Calin Culianu				bits |= (1U << CR_CHAN(cmd->chanlist[n]));
8816baef150380d561a4d695a6be4fc509821c23611Calin Culianu				pol_bits |= (CR_AREF(cmd->chanlist[n])
8826baef150380d561a4d695a6be4fc509821c23611Calin Culianu					|| CR_RANGE(cmd->chanlist[n]) ? 1U : 0U)
8836baef150380d561a4d695a6be4fc509821c23611Calin Culianu					<< CR_CHAN(cmd->chanlist[n]);
8846baef150380d561a4d695a6be4fc509821c23611Calin Culianu			}
8856baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
8866baef150380d561a4d695a6be4fc509821c23611Calin Culianu		bits &= ((0x1 << subpriv->intr.num_asic_chans) -
8876baef150380d561a4d695a6be4fc509821c23611Calin Culianu			1) << subpriv->intr.first_chan;
8886baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.enabled_mask = bits;
8896baef150380d561a4d695a6be4fc509821c23611Calin Culianu
8906baef150380d561a4d695a6be4fc509821c23611Calin Culianu		switch_page(dev, asic, PAGE_ENAB);
8916baef150380d561a4d695a6be4fc509821c23611Calin Culianu		for (port = firstport; port < firstport + nports; ++port) {
8926baef150380d561a4d695a6be4fc509821c23611Calin Culianu			unsigned enab =
8936baef150380d561a4d695a6be4fc509821c23611Calin Culianu				bits >> (subpriv->intr.first_chan + (port -
8946baef150380d561a4d695a6be4fc509821c23611Calin Culianu					firstport) * 8) & 0xff, pol =
8956baef150380d561a4d695a6be4fc509821c23611Calin Culianu				pol_bits >> (subpriv->intr.first_chan + (port -
8966baef150380d561a4d695a6be4fc509821c23611Calin Culianu					firstport) * 8) & 0xff;
8976baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* set enab intrs for this subdev.. */
8986baef150380d561a4d695a6be4fc509821c23611Calin Culianu			outb(enab,
8996baef150380d561a4d695a6be4fc509821c23611Calin Culianu				devpriv->asics[asic].iobase + REG_ENAB0 + port);
9006baef150380d561a4d695a6be4fc509821c23611Calin Culianu			switch_page(dev, asic, PAGE_POL);
9016baef150380d561a4d695a6be4fc509821c23611Calin Culianu			outb(pol,
9026baef150380d561a4d695a6be4fc509821c23611Calin Culianu				devpriv->asics[asic].iobase + REG_ENAB0 + port);
9036baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
9046baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
9056baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 0;
9066baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
9076baef150380d561a4d695a6be4fc509821c23611Calin Culianu
90834c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int pcmuio_cancel(struct comedi_device * dev, struct comedi_subdevice * s)
9096baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
9106baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long flags;
9116baef150380d561a4d695a6be4fc509821c23611Calin Culianu
9126baef150380d561a4d695a6be4fc509821c23611Calin Culianu	comedi_spin_lock_irqsave(&subpriv->intr.spinlock, flags);
9136baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (subpriv->intr.active)
9146baef150380d561a4d695a6be4fc509821c23611Calin Culianu		pcmuio_stop_intr(dev, s);
9156baef150380d561a4d695a6be4fc509821c23611Calin Culianu	comedi_spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
9166baef150380d561a4d695a6be4fc509821c23611Calin Culianu
9176baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 0;
9186baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
9196baef150380d561a4d695a6be4fc509821c23611Calin Culianu
9206baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
9216baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
9226baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
9236baef150380d561a4d695a6be4fc509821c23611Calin Culianustatic int
92434c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonpcmuio_inttrig_start_intr(struct comedi_device * dev, struct comedi_subdevice * s,
9256baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned int trignum)
9266baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
9276baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long flags;
9286baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int event = 0;
9296baef150380d561a4d695a6be4fc509821c23611Calin Culianu
9306baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (trignum != 0)
9316baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return -EINVAL;
9326baef150380d561a4d695a6be4fc509821c23611Calin Culianu
9336baef150380d561a4d695a6be4fc509821c23611Calin Culianu	comedi_spin_lock_irqsave(&subpriv->intr.spinlock, flags);
9346baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s->async->inttrig = 0;
9356baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (subpriv->intr.active) {
9366baef150380d561a4d695a6be4fc509821c23611Calin Culianu		event = pcmuio_start_intr(dev, s);
9376baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
9386baef150380d561a4d695a6be4fc509821c23611Calin Culianu	comedi_spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
9396baef150380d561a4d695a6be4fc509821c23611Calin Culianu
9406baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (event) {
9416baef150380d561a4d695a6be4fc509821c23611Calin Culianu		comedi_event(dev, s);
9426baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
9436baef150380d561a4d695a6be4fc509821c23611Calin Culianu
9446baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 1;
9456baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
9466baef150380d561a4d695a6be4fc509821c23611Calin Culianu
9476baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
9486baef150380d561a4d695a6be4fc509821c23611Calin Culianu * 'do_cmd' function for an 'INTERRUPT' subdevice.
9496baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
95034c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic int pcmuio_cmd(struct comedi_device * dev, struct comedi_subdevice * s)
9516baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
952ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd *cmd = &s->async->cmd;
9536baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long flags;
9546baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int event = 0;
9556baef150380d561a4d695a6be4fc509821c23611Calin Culianu
9566baef150380d561a4d695a6be4fc509821c23611Calin Culianu	comedi_spin_lock_irqsave(&subpriv->intr.spinlock, flags);
9576baef150380d561a4d695a6be4fc509821c23611Calin Culianu	subpriv->intr.active = 1;
9586baef150380d561a4d695a6be4fc509821c23611Calin Culianu
9596baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* Set up end of acquisition. */
9606baef150380d561a4d695a6be4fc509821c23611Calin Culianu	switch (cmd->stop_src) {
9616baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case TRIG_COUNT:
9626baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.continuous = 0;
9636baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.stop_count = cmd->stop_arg;
9646baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
9656baef150380d561a4d695a6be4fc509821c23611Calin Culianu	default:
9666baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* TRIG_NONE */
9676baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.continuous = 1;
9686baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.stop_count = 0;
9696baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
9706baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
9716baef150380d561a4d695a6be4fc509821c23611Calin Culianu
9726baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* Set up start of acquisition. */
9736baef150380d561a4d695a6be4fc509821c23611Calin Culianu	switch (cmd->start_src) {
9746baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case TRIG_INT:
9756baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->async->inttrig = pcmuio_inttrig_start_intr;
9766baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
9776baef150380d561a4d695a6be4fc509821c23611Calin Culianu	default:
9786baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* TRIG_NOW */
9796baef150380d561a4d695a6be4fc509821c23611Calin Culianu		event = pcmuio_start_intr(dev, s);
9806baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
9816baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
9826baef150380d561a4d695a6be4fc509821c23611Calin Culianu	comedi_spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
9836baef150380d561a4d695a6be4fc509821c23611Calin Culianu
9846baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (event) {
9856baef150380d561a4d695a6be4fc509821c23611Calin Culianu		comedi_event(dev, s);
9866baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
9876baef150380d561a4d695a6be4fc509821c23611Calin Culianu
9886baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 0;
9896baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
9906baef150380d561a4d695a6be4fc509821c23611Calin Culianu
9916baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
9926baef150380d561a4d695a6be4fc509821c23611Calin Culianu * 'do_cmdtest' function for an 'INTERRUPT' subdevice.
9936baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
9946baef150380d561a4d695a6be4fc509821c23611Calin Culianustatic int
995ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pembertonpcmuio_cmdtest(struct comedi_device * dev, struct comedi_subdevice * s, struct comedi_cmd * cmd)
9966baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
9976baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int err = 0;
9986baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned int tmp;
9996baef150380d561a4d695a6be4fc509821c23611Calin Culianu
10006baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* step 1: make sure trigger sources are trivially valid */
10016baef150380d561a4d695a6be4fc509821c23611Calin Culianu
10026baef150380d561a4d695a6be4fc509821c23611Calin Culianu	tmp = cmd->start_src;
10036baef150380d561a4d695a6be4fc509821c23611Calin Culianu	cmd->start_src &= (TRIG_NOW | TRIG_INT);
10046baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (!cmd->start_src || tmp != cmd->start_src)
10056baef150380d561a4d695a6be4fc509821c23611Calin Culianu		err++;
10066baef150380d561a4d695a6be4fc509821c23611Calin Culianu
10076baef150380d561a4d695a6be4fc509821c23611Calin Culianu	tmp = cmd->scan_begin_src;
10086baef150380d561a4d695a6be4fc509821c23611Calin Culianu	cmd->scan_begin_src &= TRIG_EXT;
10096baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
10106baef150380d561a4d695a6be4fc509821c23611Calin Culianu		err++;
10116baef150380d561a4d695a6be4fc509821c23611Calin Culianu
10126baef150380d561a4d695a6be4fc509821c23611Calin Culianu	tmp = cmd->convert_src;
10136baef150380d561a4d695a6be4fc509821c23611Calin Culianu	cmd->convert_src &= TRIG_NOW;
10146baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (!cmd->convert_src || tmp != cmd->convert_src)
10156baef150380d561a4d695a6be4fc509821c23611Calin Culianu		err++;
10166baef150380d561a4d695a6be4fc509821c23611Calin Culianu
10176baef150380d561a4d695a6be4fc509821c23611Calin Culianu	tmp = cmd->scan_end_src;
10186baef150380d561a4d695a6be4fc509821c23611Calin Culianu	cmd->scan_end_src &= TRIG_COUNT;
10196baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
10206baef150380d561a4d695a6be4fc509821c23611Calin Culianu		err++;
10216baef150380d561a4d695a6be4fc509821c23611Calin Culianu
10226baef150380d561a4d695a6be4fc509821c23611Calin Culianu	tmp = cmd->stop_src;
10236baef150380d561a4d695a6be4fc509821c23611Calin Culianu	cmd->stop_src &= (TRIG_COUNT | TRIG_NONE);
10246baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (!cmd->stop_src || tmp != cmd->stop_src)
10256baef150380d561a4d695a6be4fc509821c23611Calin Culianu		err++;
10266baef150380d561a4d695a6be4fc509821c23611Calin Culianu
10276baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (err)
10286baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return 1;
10296baef150380d561a4d695a6be4fc509821c23611Calin Culianu
10306baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* step 2: make sure trigger sources are unique and mutually compatible */
10316baef150380d561a4d695a6be4fc509821c23611Calin Culianu
10326baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* these tests are true if more than one _src bit is set */
10336baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if ((cmd->start_src & (cmd->start_src - 1)) != 0)
10346baef150380d561a4d695a6be4fc509821c23611Calin Culianu		err++;
10356baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0)
10366baef150380d561a4d695a6be4fc509821c23611Calin Culianu		err++;
10376baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if ((cmd->convert_src & (cmd->convert_src - 1)) != 0)
10386baef150380d561a4d695a6be4fc509821c23611Calin Culianu		err++;
10396baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0)
10406baef150380d561a4d695a6be4fc509821c23611Calin Culianu		err++;
10416baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if ((cmd->stop_src & (cmd->stop_src - 1)) != 0)
10426baef150380d561a4d695a6be4fc509821c23611Calin Culianu		err++;
10436baef150380d561a4d695a6be4fc509821c23611Calin Culianu
10446baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (err)
10456baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return 2;
10466baef150380d561a4d695a6be4fc509821c23611Calin Culianu
10476baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* step 3: make sure arguments are trivially compatible */
10486baef150380d561a4d695a6be4fc509821c23611Calin Culianu
10496baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* cmd->start_src == TRIG_NOW || cmd->start_src == TRIG_INT */
10506baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (cmd->start_arg != 0) {
10516baef150380d561a4d695a6be4fc509821c23611Calin Culianu		cmd->start_arg = 0;
10526baef150380d561a4d695a6be4fc509821c23611Calin Culianu		err++;
10536baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
10546baef150380d561a4d695a6be4fc509821c23611Calin Culianu
10556baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* cmd->scan_begin_src == TRIG_EXT */
10566baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (cmd->scan_begin_arg != 0) {
10576baef150380d561a4d695a6be4fc509821c23611Calin Culianu		cmd->scan_begin_arg = 0;
10586baef150380d561a4d695a6be4fc509821c23611Calin Culianu		err++;
10596baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
10606baef150380d561a4d695a6be4fc509821c23611Calin Culianu
10616baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* cmd->convert_src == TRIG_NOW */
10626baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (cmd->convert_arg != 0) {
10636baef150380d561a4d695a6be4fc509821c23611Calin Culianu		cmd->convert_arg = 0;
10646baef150380d561a4d695a6be4fc509821c23611Calin Culianu		err++;
10656baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
10666baef150380d561a4d695a6be4fc509821c23611Calin Culianu
10676baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* cmd->scan_end_src == TRIG_COUNT */
10686baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (cmd->scan_end_arg != cmd->chanlist_len) {
10696baef150380d561a4d695a6be4fc509821c23611Calin Culianu		cmd->scan_end_arg = cmd->chanlist_len;
10706baef150380d561a4d695a6be4fc509821c23611Calin Culianu		err++;
10716baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
10726baef150380d561a4d695a6be4fc509821c23611Calin Culianu
10736baef150380d561a4d695a6be4fc509821c23611Calin Culianu	switch (cmd->stop_src) {
10746baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case TRIG_COUNT:
10756baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* any count allowed */
10766baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
10776baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case TRIG_NONE:
10786baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (cmd->stop_arg != 0) {
10796baef150380d561a4d695a6be4fc509821c23611Calin Culianu			cmd->stop_arg = 0;
10806baef150380d561a4d695a6be4fc509821c23611Calin Culianu			err++;
10816baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
10826baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
10836baef150380d561a4d695a6be4fc509821c23611Calin Culianu	default:
10846baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
10856baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
10866baef150380d561a4d695a6be4fc509821c23611Calin Culianu
10876baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (err)
10886baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return 3;
10896baef150380d561a4d695a6be4fc509821c23611Calin Culianu
10906baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* step 4: fix up any arguments */
10916baef150380d561a4d695a6be4fc509821c23611Calin Culianu
10926baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* if (err) return 4; */
10936baef150380d561a4d695a6be4fc509821c23611Calin Culianu
10946baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 0;
10956baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
10966baef150380d561a4d695a6be4fc509821c23611Calin Culianu
10976baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
10986baef150380d561a4d695a6be4fc509821c23611Calin Culianu * A convenient macro that defines init_module() and cleanup_module(),
10996baef150380d561a4d695a6be4fc509821c23611Calin Culianu * as necessary.
11006baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
11016baef150380d561a4d695a6be4fc509821c23611Calin CulianuCOMEDI_INITCLEANUP(driver);
1102