pcmuio.c revision 33782dd5edf8db3cdb7c81a3523bf743dd0209b7
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
7825436dc9d84f1be60ff549c9ab712bba2835f284Greg Kroah-Hartman#include <linux/interrupt.h>
795a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
806baef150380d561a4d695a6be4fc509821c23611Calin Culianu
81f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten#include "../comedidev.h"
8233782dd5edf8db3cdb7c81a3523bf743dd0209b7H Hartley Sweeten
83f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten#include "comedi_fc.h"
846baef150380d561a4d695a6be4fc509821c23611Calin Culianu
856baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define CHANS_PER_PORT   8
866baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PORTS_PER_ASIC   6
876baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define INTR_PORTS_PER_ASIC   3
886baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define MAX_CHANS_PER_SUBDEV 24	/* number of channels per comedi subdevice */
896baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PORTS_PER_SUBDEV (MAX_CHANS_PER_SUBDEV/CHANS_PER_PORT)
906baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define CHANS_PER_ASIC (CHANS_PER_PORT*PORTS_PER_ASIC)
916baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define INTR_CHANS_PER_ASIC 24
926baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC/CHANS_PER_PORT)
936baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define MAX_DIO_CHANS   (PORTS_PER_ASIC*2*CHANS_PER_PORT)
946baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define MAX_ASICS       (MAX_DIO_CHANS/CHANS_PER_ASIC)
956baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define CALC_N_SUBDEVS(nchans) ((nchans)/MAX_CHANS_PER_SUBDEV + (!!((nchans)%MAX_CHANS_PER_SUBDEV)) /*+ (nchans > INTR_CHANS_PER_ASIC ? 2 : 1)*/)
966baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* IO Memory sizes */
976baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define ASIC_IOSIZE (0x10)
986baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PCMUIO48_IOSIZE ASIC_IOSIZE
996baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PCMUIO96_IOSIZE (ASIC_IOSIZE*2)
1006baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1016baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* Some offsets - these are all in the 16byte IO memory offset from
1026baef150380d561a4d695a6be4fc509821c23611Calin Culianu   the base address.  Note that there is a paging scheme to swap out
1036baef150380d561a4d695a6be4fc509821c23611Calin Culianu   offsets 0x8-0xA using the PAGELOCK register.  See the table below.
1046baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1056baef150380d561a4d695a6be4fc509821c23611Calin Culianu  Register(s)       Pages        R/W?        Description
1066baef150380d561a4d695a6be4fc509821c23611Calin Culianu  --------------------------------------------------------------
1076baef150380d561a4d695a6be4fc509821c23611Calin Culianu  REG_PORTx         All          R/W         Read/Write/Configure IO
1086baef150380d561a4d695a6be4fc509821c23611Calin Culianu  REG_INT_PENDING   All          ReadOnly    Quickly see which INT_IDx has int.
1096baef150380d561a4d695a6be4fc509821c23611Calin Culianu  REG_PAGELOCK      All          WriteOnly   Select a page
1106baef150380d561a4d695a6be4fc509821c23611Calin Culianu  REG_POLx          Pg. 1 only   WriteOnly   Select edge-detection polarity
1116baef150380d561a4d695a6be4fc509821c23611Calin Culianu  REG_ENABx         Pg. 2 only   WriteOnly   Enable/Disable edge-detect. int.
1126baef150380d561a4d695a6be4fc509821c23611Calin Culianu  REG_INT_IDx       Pg. 3 only   R/W         See which ports/bits have ints.
1136baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
1146baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT0 0x0
1156baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT1 0x1
1166baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT2 0x2
1176baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT3 0x3
1186baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT4 0x4
1196baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT5 0x5
1206baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_INT_PENDING 0x6
1216baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PAGELOCK 0x7	/* page selector register, upper 2 bits select a page
1226baef150380d561a4d695a6be4fc509821c23611Calin Culianu				   and bits 0-5 are used to 'lock down' a particular
1236baef150380d561a4d695a6be4fc509821c23611Calin Culianu				   port above to make it readonly.  */
1246baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_POL0 0x8
1256baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_POL1 0x9
1266baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_POL2 0xA
1276baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_ENAB0 0x8
1286baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_ENAB1 0x9
1296baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_ENAB2 0xA
1306baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_INT_ID0 0x8
1316baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_INT_ID1 0x9
1326baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_INT_ID2 0xA
1336baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1346baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define NUM_PAGED_REGS 3
1356baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define NUM_PAGES 4
1366baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define FIRST_PAGED_REG 0x8
1376baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PAGE_BITOFFSET 6
1386baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_LOCK_BITOFFSET 0
1396baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PAGE_MASK (~((0x1<<REG_PAGE_BITOFFSET)-1))
1406baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_LOCK_MASK ~(REG_PAGE_MASK)
1416baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PAGE_POL 1
1426baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PAGE_ENAB 2
1436baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PAGE_INT_ID 3
1446baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1456baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
1466baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Board descriptions for two imaginary boards.  Describing the
1476baef150380d561a4d695a6be4fc509821c23611Calin Culianu * boards in this way is optional, and completely driver-dependent.
1486baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Some drivers use arrays such as this, other do not.
1496baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
15070a6001aeffeaa12f2a1c21470e8f3bdfb6ef8e7Bill Pembertonstruct pcmuio_board {
1516baef150380d561a4d695a6be4fc509821c23611Calin Culianu	const char *name;
1526baef150380d561a4d695a6be4fc509821c23611Calin Culianu	const int num_asics;
1536baef150380d561a4d695a6be4fc509821c23611Calin Culianu	const int num_channels_per_port;
1546baef150380d561a4d695a6be4fc509821c23611Calin Culianu	const int num_ports;
15570a6001aeffeaa12f2a1c21470e8f3bdfb6ef8e7Bill Pemberton};
1566baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1576baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* this structure is for data unique to this subdevice.  */
158e15849e54405152087cd343437747db8d931fcd7Bill Pembertonstruct pcmuio_subdev_private {
1596baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* mapping of halfwords (bytes) in port/chanarray to iobase */
1606baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long iobases[PORTS_PER_SUBDEV];
1616baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1626baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* The below is only used for intr subdevices */
1636baef150380d561a4d695a6be4fc509821c23611Calin Culianu	struct {
1646baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int asic;	/* if non-negative, this subdev has an interrupt asic */
1656baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int first_chan;	/* if nonnegative, the first channel id for
1666baef150380d561a4d695a6be4fc509821c23611Calin Culianu				   interrupts. */
1676baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int num_asic_chans;	/* the number of asic channels in this subdev
1686baef150380d561a4d695a6be4fc509821c23611Calin Culianu					   that have interrutps */
1696baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int asic_chan;	/* if nonnegative, the first channel id with
1706baef150380d561a4d695a6be4fc509821c23611Calin Culianu				   respect to the asic that has interrupts */
1716baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int enabled_mask;	/* subdev-relative channel mask for channels
1726baef150380d561a4d695a6be4fc509821c23611Calin Culianu					   we are interested in */
1736baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int active;
1746baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int stop_count;
1756baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int continuous;
1766baef150380d561a4d695a6be4fc509821c23611Calin Culianu		spinlock_t spinlock;
1776baef150380d561a4d695a6be4fc509821c23611Calin Culianu	} intr;
178e15849e54405152087cd343437747db8d931fcd7Bill Pemberton};
1796baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1806baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* this structure is for data unique to this hardware driver.  If
1816baef150380d561a4d695a6be4fc509821c23611Calin Culianu   several hardware drivers keep similar information in this structure,
18271b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton   feel free to suggest moving the variable to the struct comedi_device struct.  */
183055f6636d9eb27bc13236e07739e019496c21221Bill Pembertonstruct pcmuio_private {
1846baef150380d561a4d695a6be4fc509821c23611Calin Culianu	struct {
1856baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned char pagelock;	/* current page and lock */
1866baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned char pol[NUM_PAGED_REGS];	/* shadow of POLx registers */
1876baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned char enab[NUM_PAGED_REGS];	/* shadow of ENABx registers */
1886baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int num;
1896baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned long iobase;
1906baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned int irq;
1916baef150380d561a4d695a6be4fc509821c23611Calin Culianu		spinlock_t spinlock;
1926baef150380d561a4d695a6be4fc509821c23611Calin Culianu	} asics[MAX_ASICS];
193e15849e54405152087cd343437747db8d931fcd7Bill Pemberton	struct pcmuio_subdev_private *sprivs;
194055f6636d9eb27bc13236e07739e019496c21221Bill Pemberton};
1956baef150380d561a4d695a6be4fc509821c23611Calin Culianu
196e15849e54405152087cd343437747db8d931fcd7Bill Pemberton#define subpriv ((struct pcmuio_subdev_private *)s->private)
1976baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1986baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* DIO devices are slightly special.  Although it is possible to
1996baef150380d561a4d695a6be4fc509821c23611Calin Culianu * implement the insn_read/insn_write interface, it is much more
2006baef150380d561a4d695a6be4fc509821c23611Calin Culianu * useful to applications if you implement the insn_bits interface.
2016baef150380d561a4d695a6be4fc509821c23611Calin Culianu * This allows packed reading/writing of the DIO channels.  The
2026baef150380d561a4d695a6be4fc509821c23611Calin Culianu * comedi core can convert between insn_bits and insn_read/write */
2030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcmuio_dio_insn_bits(struct comedi_device *dev,
2040a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				struct comedi_subdevice *s,
2050a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				struct comedi_insn *insn, unsigned int *data)
2066baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
2076baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int byte_no;
2086baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2096baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* NOTE:
2106baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   reading a 0 means this channel was high
2116baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   writine a 0 sets the channel high
2126baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   reading a 1 means this channel was low
2136baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   writing a 1 means set this channel low
2146baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2156baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   Therefore everything is always inverted. */
2166baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2176baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* The insn data is a mask in data[0] and the new data
2186baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * in data[1], each channel cooresponding to a bit. */
2196baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2206baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef DAMMIT_ITS_BROKEN
2216baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* DEBUG */
222f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott	dev_dbg(dev->class_dev, "write mask: %08x  data: %08x\n", data[0],
223976fe5ab27e682d3dbfec26517a8a248638af07dRavishankar karkala Mallikarjunayya		data[1]);
2246baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif
2256baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2266baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s->state = 0;
2276baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2286baef150380d561a4d695a6be4fc509821c23611Calin Culianu	for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) {
2296baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* address of 8-bit port */
2306baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned long ioaddr = subpriv->iobases[byte_no],
2310a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    /* bit offset of port in 32-bit doubleword */
2320a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    offset = byte_no * 8;
2336baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* this 8-bit port's data */
2346baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned char byte = 0,
2350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    /* The write mask for this port (if any) */
2360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    write_mask_byte = (data[0] >> offset) & 0xff,
2370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    /* The data byte for this port */
2380a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    data_byte = (data[1] >> offset) & 0xff;
2396baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2406baef150380d561a4d695a6be4fc509821c23611Calin Culianu		byte = inb(ioaddr);	/* read all 8-bits for this port */
2416baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2426baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef DAMMIT_ITS_BROKEN
2436baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* DEBUG */
2440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk
2450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    ("byte %d wmb %02x db %02x offset %02d io %04x, data_in %02x ",
2460a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		     byte_no, (unsigned)write_mask_byte, (unsigned)data_byte,
2470a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		     offset, ioaddr, (unsigned)byte);
2486baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif
2496baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2506baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (write_mask_byte) {
2516baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* this byte has some write_bits -- so set the output lines */
2526baef150380d561a4d695a6be4fc509821c23611Calin Culianu			byte &= ~write_mask_byte;	/* clear bits for write mask */
2536baef150380d561a4d695a6be4fc509821c23611Calin Culianu			byte |= ~data_byte & write_mask_byte;	/* set to inverted data_byte */
2546baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* Write out the new digital output state */
2556baef150380d561a4d695a6be4fc509821c23611Calin Culianu			outb(byte, ioaddr);
2566baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
2576baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef DAMMIT_ITS_BROKEN
2586baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* DEBUG */
259f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott		dev_dbg(dev->class_dev, "data_out_byte %02x\n", (unsigned)byte);
2606baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif
2616baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* save the digital input lines for this byte.. */
2626baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->state |= ((unsigned int)byte) << offset;
2636baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
2646baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2656baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* now return the DIO lines to data[1] - note they came inverted! */
2666baef150380d561a4d695a6be4fc509821c23611Calin Culianu	data[1] = ~s->state;
2676baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2686baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef DAMMIT_ITS_BROKEN
2696baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* DEBUG */
270f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott	dev_dbg(dev->class_dev, "s->state %08x data_out %08x\n", s->state,
271976fe5ab27e682d3dbfec26517a8a248638af07dRavishankar karkala Mallikarjunayya		data[1]);
2726baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif
2736baef150380d561a4d695a6be4fc509821c23611Calin Culianu
274a2714e3e42e746d6c8525c35fdcc58fb60c2830dH Hartley Sweeten	return insn->n;
2756baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
2766baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2776baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* The input or output configuration of each digital line is
2786baef150380d561a4d695a6be4fc509821c23611Calin Culianu * configured by a special insn_config instruction.  chanspec
2796baef150380d561a4d695a6be4fc509821c23611Calin Culianu * contains the channel to be changed, and data[0] contains the
2806baef150380d561a4d695a6be4fc509821c23611Calin Culianu * value COMEDI_INPUT or COMEDI_OUTPUT. */
2810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcmuio_dio_insn_config(struct comedi_device *dev,
2820a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  struct comedi_subdevice *s,
2830a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  struct comedi_insn *insn, unsigned int *data)
2846baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
2856baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no =
2860a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    chan % 8;
2876baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long ioaddr;
2886baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned char byte;
2896baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2906baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* Compute ioaddr for this channel */
2916baef150380d561a4d695a6be4fc509821c23611Calin Culianu	ioaddr = subpriv->iobases[byte_no];
2926baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2936baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* NOTE:
2946baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   writing a 0 an IO channel's bit sets the channel to INPUT
2956baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   and pulls the line high as well
2966baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2976baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   writing a 1 to an IO channel's  bit pulls the line low
2986baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2996baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   All channels are implicitly always in OUTPUT mode -- but when
3006baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   they are high they can be considered to be in INPUT mode..
3016baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3026baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   Thus, we only force channels low if the config request was INPUT,
3036baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   otherwise we do nothing to the hardware.    */
3046baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3056baef150380d561a4d695a6be4fc509821c23611Calin Culianu	switch (data[0]) {
3066baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case INSN_CONFIG_DIO_OUTPUT:
3076baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* save to io_bits -- don't actually do anything since
3086baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   all input channels are also output channels... */
3096baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->io_bits |= 1 << chan;
3106baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
3116baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case INSN_CONFIG_DIO_INPUT:
3126baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* write a 0 to the actual register representing the channel
3136baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   to set it to 'input'.  0 means "float high". */
3146baef150380d561a4d695a6be4fc509821c23611Calin Culianu		byte = inb(ioaddr);
3156baef150380d561a4d695a6be4fc509821c23611Calin Culianu		byte &= ~(1 << bit_no);
3166baef150380d561a4d695a6be4fc509821c23611Calin Culianu				/**< set input channel to '0' */
3176baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3186baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* write out byte -- this is the only time we actually affect the
3196baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   hardware as all channels are implicitly output -- but input
3206baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   channels are set to float-high */
3216baef150380d561a4d695a6be4fc509821c23611Calin Culianu		outb(byte, ioaddr);
3226baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3236baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* save to io_bits */
3246baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->io_bits &= ~(1 << chan);
3256baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
3266baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3276baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case INSN_CONFIG_DIO_QUERY:
32825985edcedea6396277003854657b5f3cb31a628Lucas De Marchi		/* retrieve from shadow register */
3296baef150380d561a4d695a6be4fc509821c23611Calin Culianu		data[1] =
3300a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
3316baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return insn->n;
3326baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
3336baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3346baef150380d561a4d695a6be4fc509821c23611Calin Culianu	default:
3356baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return -EINVAL;
3366baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
3376baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
3386baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3396baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return insn->n;
3406baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
3416baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3426b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweetenstatic void switch_page(struct comedi_device *dev, int asic, int page)
3436b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten{
344a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	const struct pcmuio_board *board = comedi_board(dev);
3459a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten	struct pcmuio_private *devpriv = dev->private;
346a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten
347a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	if (asic < 0 || asic >= board->num_asics)
3486b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		return;		/* paranoia */
3496b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	if (page < 0 || page >= NUM_PAGES)
3506b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		return;		/* more paranoia */
3516b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
3526b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
3536b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
3546b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
3556b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	/* now write out the shadow register */
3566b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	outb(devpriv->asics[asic].pagelock,
3576b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	     dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
3586b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten}
3596b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
360da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void init_asics(struct comedi_device *dev)
3616baef150380d561a4d695a6be4fc509821c23611Calin Culianu{				/* sets up an
3626baef150380d561a4d695a6be4fc509821c23611Calin Culianu				   ASIC chip to defaults */
363a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	const struct pcmuio_board *board = comedi_board(dev);
3646baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int asic;
3656baef150380d561a4d695a6be4fc509821c23611Calin Culianu
366a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	for (asic = 0; asic < board->num_asics; ++asic) {
3676baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int port, page;
3686baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned long baseaddr = dev->iobase + asic * ASIC_IOSIZE;
3696baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3706baef150380d561a4d695a6be4fc509821c23611Calin Culianu		switch_page(dev, asic, 0);	/* switch back to page 0 */
3716baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3726baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* first, clear all the DIO port bits */
3736baef150380d561a4d695a6be4fc509821c23611Calin Culianu		for (port = 0; port < PORTS_PER_ASIC; ++port)
3746baef150380d561a4d695a6be4fc509821c23611Calin Culianu			outb(0, baseaddr + REG_PORT0 + port);
3756baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3766baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* Next, clear all the paged registers for each page */
3776baef150380d561a4d695a6be4fc509821c23611Calin Culianu		for (page = 1; page < NUM_PAGES; ++page) {
3786baef150380d561a4d695a6be4fc509821c23611Calin Culianu			int reg;
3796baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* now clear all the paged registers */
3806baef150380d561a4d695a6be4fc509821c23611Calin Culianu			switch_page(dev, asic, page);
3816baef150380d561a4d695a6be4fc509821c23611Calin Culianu			for (reg = FIRST_PAGED_REG;
3820a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg)
3836baef150380d561a4d695a6be4fc509821c23611Calin Culianu				outb(0, baseaddr + reg);
3846baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
3856baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3866baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* DEBUG  set rising edge interrupts on port0 of both asics */
3876baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/*switch_page(dev, asic, PAGE_POL);
3886baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   outb(0xff, baseaddr + REG_POL0);
3896baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   switch_page(dev, asic, PAGE_ENAB);
3906baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   outb(0xff, baseaddr + REG_ENAB0); */
3916baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* END DEBUG */
3926baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3936baef150380d561a4d695a6be4fc509821c23611Calin Culianu		switch_page(dev, asic, 0);	/* switch back to default page 0 */
3946baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3956baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
3966baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
3976baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3986baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef notused
399da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void lock_port(struct comedi_device *dev, int asic, int port)
4006baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
401a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	const struct pcmuio_board *board = comedi_board(dev);
4029a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten	struct pcmuio_private *devpriv = dev->private;
403a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten
404a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	if (asic < 0 || asic >= board->num_asics)
4056baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return;		/* paranoia */
4066baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (port < 0 || port >= PORTS_PER_ASIC)
4076baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return;		/* more paranoia */
4086baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4096baef150380d561a4d695a6be4fc509821c23611Calin Culianu	devpriv->asics[asic].pagelock |= 0x1 << port;
4106baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* now write out the shadow register */
4116baef150380d561a4d695a6be4fc509821c23611Calin Culianu	outb(devpriv->asics[asic].pagelock,
4120a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	     dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
4136baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
4146baef150380d561a4d695a6be4fc509821c23611Calin Culianu
415da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void unlock_port(struct comedi_device *dev, int asic, int port)
4166baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
417a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	const struct pcmuio_board *board = comedi_board(dev);
4189a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten	struct pcmuio_private *devpriv = dev->private;
419a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten
420a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	if (asic < 0 || asic >= board->num_asics)
4216baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return;		/* paranoia */
4226baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (port < 0 || port >= PORTS_PER_ASIC)
4236baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return;		/* more paranoia */
4246baef150380d561a4d695a6be4fc509821c23611Calin Culianu	devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK;
4256baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* now write out the shadow register */
4266baef150380d561a4d695a6be4fc509821c23611Calin Culianu	outb(devpriv->asics[asic].pagelock,
4270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	     dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
4286baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
4296baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif /* notused */
4306baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4316b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweetenstatic void pcmuio_stop_intr(struct comedi_device *dev,
4326b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			     struct comedi_subdevice *s)
4336b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten{
4346b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	int nports, firstport, asic, port;
4359a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten	struct pcmuio_private *devpriv = dev->private;
4366b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
4376b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	asic = subpriv->intr.asic;
4386b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	if (asic < 0)
4396b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		return;		/* not an interrupt subdev */
4406b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
4416b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	subpriv->intr.enabled_mask = 0;
4426b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	subpriv->intr.active = 0;
443920e2ffbe243fb0555b2c238e26fe7dbc03db98cH Hartley Sweeten	s->async->inttrig = NULL;
4446b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
4456b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
4466b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	switch_page(dev, asic, PAGE_ENAB);
4476b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	for (port = firstport; port < firstport + nports; ++port) {
4486b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		/* disable all intrs for this subdev.. */
4496b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
4506b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	}
4516b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten}
4526b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
45370265d24e3404fe798b6edd55a02016b1edb49d7Jiri Slabystatic irqreturn_t interrupt_pcmuio(int irq, void *d)
4546baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
4556baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int asic, got1 = 0;
4560a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	struct comedi_device *dev = (struct comedi_device *)d;
4579a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten	struct pcmuio_private *devpriv = dev->private;
45868720ae68a94444387d56bc5a166396e33e420a5H Hartley Sweeten	int i;
4596baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4606baef150380d561a4d695a6be4fc509821c23611Calin Culianu	for (asic = 0; asic < MAX_ASICS; ++asic) {
4616baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (irq == devpriv->asics[asic].irq) {
4626baef150380d561a4d695a6be4fc509821c23611Calin Culianu			unsigned long flags;
4636baef150380d561a4d695a6be4fc509821c23611Calin Culianu			unsigned triggered = 0;
4646baef150380d561a4d695a6be4fc509821c23611Calin Culianu			unsigned long iobase = devpriv->asics[asic].iobase;
4656baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* it is an interrupt for ASIC #asic */
4666baef150380d561a4d695a6be4fc509821c23611Calin Culianu			unsigned char int_pend;
4676baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4680a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			spin_lock_irqsave(&devpriv->asics[asic].spinlock,
4690a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					  flags);
4706baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4716baef150380d561a4d695a6be4fc509821c23611Calin Culianu			int_pend = inb(iobase + REG_INT_PENDING) & 0x07;
4726baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4736baef150380d561a4d695a6be4fc509821c23611Calin Culianu			if (int_pend) {
4746baef150380d561a4d695a6be4fc509821c23611Calin Culianu				int port;
4756baef150380d561a4d695a6be4fc509821c23611Calin Culianu				for (port = 0; port < INTR_PORTS_PER_ASIC;
4760a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				     ++port) {
4776baef150380d561a4d695a6be4fc509821c23611Calin Culianu					if (int_pend & (0x1 << port)) {
4786baef150380d561a4d695a6be4fc509821c23611Calin Culianu						unsigned char
4790a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						    io_lines_with_edges = 0;
4806baef150380d561a4d695a6be4fc509821c23611Calin Culianu						switch_page(dev, asic,
4810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    PAGE_INT_ID);
4826baef150380d561a4d695a6be4fc509821c23611Calin Culianu						io_lines_with_edges =
4830a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						    inb(iobase +
4846baef150380d561a4d695a6be4fc509821c23611Calin Culianu							REG_INT_ID0 + port);
4856baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4866baef150380d561a4d695a6be4fc509821c23611Calin Culianu						if (io_lines_with_edges)
4876baef150380d561a4d695a6be4fc509821c23611Calin Culianu							/* clear pending interrupt */
4886baef150380d561a4d695a6be4fc509821c23611Calin Culianu							outb(0, iobase +
4890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							     REG_INT_ID0 +
4900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							     port);
4916baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4926baef150380d561a4d695a6be4fc509821c23611Calin Culianu						triggered |=
4930a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						    io_lines_with_edges <<
4940a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						    port * 8;
4956baef150380d561a4d695a6be4fc509821c23611Calin Culianu					}
4966baef150380d561a4d695a6be4fc509821c23611Calin Culianu				}
4976baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4986baef150380d561a4d695a6be4fc509821c23611Calin Culianu				++got1;
4996baef150380d561a4d695a6be4fc509821c23611Calin Culianu			}
5006baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5010a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			spin_unlock_irqrestore(&devpriv->asics[asic].spinlock,
5020a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					       flags);
5036baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5046baef150380d561a4d695a6be4fc509821c23611Calin Culianu			if (triggered) {
50534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton				struct comedi_subdevice *s;
5066baef150380d561a4d695a6be4fc509821c23611Calin Culianu				/* TODO here: dispatch io lines to subdevs with commands.. */
5070a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				printk
5080a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    ("PCMUIO DEBUG: got edge detect interrupt %d asic %d which_chans: %06x\n",
5090a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				     irq, asic, triggered);
51068720ae68a94444387d56bc5a166396e33e420a5H Hartley Sweeten				for (i = 0; i < dev->n_subdevices; i++) {
51168720ae68a94444387d56bc5a166396e33e420a5H Hartley Sweeten					s = &dev->subdevices[i];
5126baef150380d561a4d695a6be4fc509821c23611Calin Culianu					if (subpriv->intr.asic == asic) {	/* this is an interrupt subdev, and it matches this asic! */
5136baef150380d561a4d695a6be4fc509821c23611Calin Culianu						unsigned long flags;
5146baef150380d561a4d695a6be4fc509821c23611Calin Culianu						unsigned oldevents;
5156baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5160a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						spin_lock_irqsave(&subpriv->
5170a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								  intr.spinlock,
5180a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								  flags);
5196baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5206baef150380d561a4d695a6be4fc509821c23611Calin Culianu						oldevents = s->async->events;
5216baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5226baef150380d561a4d695a6be4fc509821c23611Calin Culianu						if (subpriv->intr.active) {
5236baef150380d561a4d695a6be4fc509821c23611Calin Culianu							unsigned mytrig =
5240a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    ((triggered >>
5250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							      subpriv->intr.asic_chan)
5260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							     &
5270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							     ((0x1 << subpriv->
5280a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							       intr.
5290a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							       num_asic_chans) -
5300a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							      1)) << subpriv->
5310a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    intr.first_chan;
5320a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							if (mytrig &
5330a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    subpriv->intr.enabled_mask)
5340a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							{
5350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								unsigned int val
5360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								    = 0;
5376baef150380d561a4d695a6be4fc509821c23611Calin Culianu								unsigned int n,
5380a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								    ch, len;
5396baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5400a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								len =
5410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								    s->
5420a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								    async->cmd.chanlist_len;
5436baef150380d561a4d695a6be4fc509821c23611Calin Culianu								for (n = 0;
5440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								     n < len;
5450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								     n++) {
5466baef150380d561a4d695a6be4fc509821c23611Calin Culianu									ch = CR_CHAN(s->async->cmd.chanlist[n]);
5476baef150380d561a4d695a6be4fc509821c23611Calin Culianu									if (mytrig & (1U << ch)) {
5486baef150380d561a4d695a6be4fc509821c23611Calin Culianu										val |= (1U << n);
5496baef150380d561a4d695a6be4fc509821c23611Calin Culianu									}
5506baef150380d561a4d695a6be4fc509821c23611Calin Culianu								}
5516baef150380d561a4d695a6be4fc509821c23611Calin Culianu								/* Write the scan to the buffer. */
5520a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								if (comedi_buf_put(s->async, ((short *)&val)[0])
5530a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								    &&
5540a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								    comedi_buf_put
5550a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								    (s->async,
5560a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								     ((short *)
5570a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								      &val)[1]))
5580a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								{
5596baef150380d561a4d695a6be4fc509821c23611Calin Culianu									s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
5606baef150380d561a4d695a6be4fc509821c23611Calin Culianu								} else {
5616baef150380d561a4d695a6be4fc509821c23611Calin Culianu									/* Overflow! Stop acquisition!! */
5626baef150380d561a4d695a6be4fc509821c23611Calin Culianu									/* TODO: STOP_ACQUISITION_CALL_HERE!! */
5636baef150380d561a4d695a6be4fc509821c23611Calin Culianu									pcmuio_stop_intr
5640a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral									    (dev,
5650a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral									     s);
5666baef150380d561a4d695a6be4fc509821c23611Calin Culianu								}
5676baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5686baef150380d561a4d695a6be4fc509821c23611Calin Culianu								/* Check for end of acquisition. */
5690a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								if (!subpriv->intr.continuous) {
5706baef150380d561a4d695a6be4fc509821c23611Calin Culianu									/* stop_src == TRIG_COUNT */
5716baef150380d561a4d695a6be4fc509821c23611Calin Culianu									if (subpriv->intr.stop_count > 0) {
5720a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral										subpriv->intr.stop_count--;
5736baef150380d561a4d695a6be4fc509821c23611Calin Culianu										if (subpriv->intr.stop_count == 0) {
5746baef150380d561a4d695a6be4fc509821c23611Calin Culianu											s->async->events |= COMEDI_CB_EOA;
5756baef150380d561a4d695a6be4fc509821c23611Calin Culianu											/* TODO: STOP_ACQUISITION_CALL_HERE!! */
5766baef150380d561a4d695a6be4fc509821c23611Calin Culianu											pcmuio_stop_intr
5770a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral											    (dev,
5780a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral											     s);
5796baef150380d561a4d695a6be4fc509821c23611Calin Culianu										}
5806baef150380d561a4d695a6be4fc509821c23611Calin Culianu									}
5816baef150380d561a4d695a6be4fc509821c23611Calin Culianu								}
5826baef150380d561a4d695a6be4fc509821c23611Calin Culianu							}
5836baef150380d561a4d695a6be4fc509821c23611Calin Culianu						}
5846baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5850a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						spin_unlock_irqrestore
5860a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						    (&subpriv->intr.spinlock,
5870a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						     flags);
5886baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5896baef150380d561a4d695a6be4fc509821c23611Calin Culianu						if (oldevents !=
5900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						    s->async->events) {
5916baef150380d561a4d695a6be4fc509821c23611Calin Culianu							comedi_event(dev, s);
5926baef150380d561a4d695a6be4fc509821c23611Calin Culianu						}
5936baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5946baef150380d561a4d695a6be4fc509821c23611Calin Culianu					}
5956baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5966baef150380d561a4d695a6be4fc509821c23611Calin Culianu				}
5976baef150380d561a4d695a6be4fc509821c23611Calin Culianu			}
5986baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5996baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
6006baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
6016baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (!got1)
6026baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return IRQ_NONE;	/* interrupt from other source */
6036baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return IRQ_HANDLED;
6046baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
6056baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6060a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcmuio_start_intr(struct comedi_device *dev,
6070a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_subdevice *s)
6086baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
6099a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten	struct pcmuio_private *devpriv = dev->private;
6109a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten
6116baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (!subpriv->intr.continuous && subpriv->intr.stop_count == 0) {
6126baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* An empty acquisition! */
6136baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->async->events |= COMEDI_CB_EOA;
6146baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.active = 0;
6156baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return 1;
6166baef150380d561a4d695a6be4fc509821c23611Calin Culianu	} else {
6176baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned bits = 0, pol_bits = 0, n;
6186baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int nports, firstport, asic, port;
619ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton		struct comedi_cmd *cmd = &s->async->cmd;
6206baef150380d561a4d695a6be4fc509821c23611Calin Culianu
621c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton		asic = subpriv->intr.asic;
622c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton		if (asic < 0)
6236baef150380d561a4d695a6be4fc509821c23611Calin Culianu			return 1;	/* not an interrupt
6246baef150380d561a4d695a6be4fc509821c23611Calin Culianu					   subdev */
6256baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.enabled_mask = 0;
6266baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.active = 1;
6276baef150380d561a4d695a6be4fc509821c23611Calin Culianu		nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
6286baef150380d561a4d695a6be4fc509821c23611Calin Culianu		firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
6296baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (cmd->chanlist) {
6306baef150380d561a4d695a6be4fc509821c23611Calin Culianu			for (n = 0; n < cmd->chanlist_len; n++) {
6316baef150380d561a4d695a6be4fc509821c23611Calin Culianu				bits |= (1U << CR_CHAN(cmd->chanlist[n]));
6326baef150380d561a4d695a6be4fc509821c23611Calin Culianu				pol_bits |= (CR_AREF(cmd->chanlist[n])
6330a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					     || CR_RANGE(cmd->
6340a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							 chanlist[n]) ? 1U : 0U)
6350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    << CR_CHAN(cmd->chanlist[n]);
6366baef150380d561a4d695a6be4fc509821c23611Calin Culianu			}
6376baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
6386baef150380d561a4d695a6be4fc509821c23611Calin Culianu		bits &= ((0x1 << subpriv->intr.num_asic_chans) -
6390a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 1) << subpriv->intr.first_chan;
6406baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.enabled_mask = bits;
6416baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6426baef150380d561a4d695a6be4fc509821c23611Calin Culianu		switch_page(dev, asic, PAGE_ENAB);
6436baef150380d561a4d695a6be4fc509821c23611Calin Culianu		for (port = firstport; port < firstport + nports; ++port) {
6446baef150380d561a4d695a6be4fc509821c23611Calin Culianu			unsigned enab =
6450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    bits >> (subpriv->intr.first_chan + (port -
6460a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								 firstport) *
6470a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				     8) & 0xff, pol =
6480a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    pol_bits >> (subpriv->intr.first_chan +
6490a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					 (port - firstport) * 8) & 0xff;
6506baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* set enab intrs for this subdev.. */
6516baef150380d561a4d695a6be4fc509821c23611Calin Culianu			outb(enab,
6520a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     devpriv->asics[asic].iobase + REG_ENAB0 + port);
6536baef150380d561a4d695a6be4fc509821c23611Calin Culianu			switch_page(dev, asic, PAGE_POL);
6546baef150380d561a4d695a6be4fc509821c23611Calin Culianu			outb(pol,
6550a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     devpriv->asics[asic].iobase + REG_ENAB0 + port);
6566baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
6576baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
6586baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 0;
6596baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
6606baef150380d561a4d695a6be4fc509821c23611Calin Culianu
661da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
6626baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
6636baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long flags;
6646baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6655f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&subpriv->intr.spinlock, flags);
6666baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (subpriv->intr.active)
6676baef150380d561a4d695a6be4fc509821c23611Calin Culianu		pcmuio_stop_intr(dev, s);
6685f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
6696baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6706baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 0;
6716baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
6726baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6736baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
6746baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
6756baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
6766baef150380d561a4d695a6be4fc509821c23611Calin Culianustatic int
677da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonpcmuio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
6780a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			  unsigned int trignum)
6796baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
6806baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long flags;
6816baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int event = 0;
6826baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6836baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (trignum != 0)
6846baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return -EINVAL;
6856baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6865f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&subpriv->intr.spinlock, flags);
687920e2ffbe243fb0555b2c238e26fe7dbc03db98cH Hartley Sweeten	s->async->inttrig = NULL;
6880389245f0c5692111c0dc8d997fc4af72d789472Ravishankar karkala Mallikarjunayya	if (subpriv->intr.active)
6896baef150380d561a4d695a6be4fc509821c23611Calin Culianu		event = pcmuio_start_intr(dev, s);
6900389245f0c5692111c0dc8d997fc4af72d789472Ravishankar karkala Mallikarjunayya
6915f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
6926baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6930389245f0c5692111c0dc8d997fc4af72d789472Ravishankar karkala Mallikarjunayya	if (event)
6946baef150380d561a4d695a6be4fc509821c23611Calin Culianu		comedi_event(dev, s);
6956baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6966baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 1;
6976baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
6986baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6996baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
7006baef150380d561a4d695a6be4fc509821c23611Calin Culianu * 'do_cmd' function for an 'INTERRUPT' subdevice.
7016baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
702da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
7036baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
704ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd *cmd = &s->async->cmd;
7056baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long flags;
7066baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int event = 0;
7076baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7085f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&subpriv->intr.spinlock, flags);
7096baef150380d561a4d695a6be4fc509821c23611Calin Culianu	subpriv->intr.active = 1;
7106baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7116baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* Set up end of acquisition. */
7126baef150380d561a4d695a6be4fc509821c23611Calin Culianu	switch (cmd->stop_src) {
7136baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case TRIG_COUNT:
7146baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.continuous = 0;
7156baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.stop_count = cmd->stop_arg;
7166baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
7176baef150380d561a4d695a6be4fc509821c23611Calin Culianu	default:
7186baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* TRIG_NONE */
7196baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.continuous = 1;
7206baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.stop_count = 0;
7216baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
7226baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
7236baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7246baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* Set up start of acquisition. */
7256baef150380d561a4d695a6be4fc509821c23611Calin Culianu	switch (cmd->start_src) {
7266baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case TRIG_INT:
7276baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->async->inttrig = pcmuio_inttrig_start_intr;
7286baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
7296baef150380d561a4d695a6be4fc509821c23611Calin Culianu	default:
7306baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* TRIG_NOW */
7316baef150380d561a4d695a6be4fc509821c23611Calin Culianu		event = pcmuio_start_intr(dev, s);
7326baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
7336baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
7345f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
7356baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7360389245f0c5692111c0dc8d997fc4af72d789472Ravishankar karkala Mallikarjunayya	if (event)
7376baef150380d561a4d695a6be4fc509821c23611Calin Culianu		comedi_event(dev, s);
7386baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7396baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 0;
7406baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
7416baef150380d561a4d695a6be4fc509821c23611Calin Culianu
742f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweetenstatic int pcmuio_cmdtest(struct comedi_device *dev,
743f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten			  struct comedi_subdevice *s,
744f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten			  struct comedi_cmd *cmd)
7456baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
746f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	int err = 0;
747f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
748f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	/* Step 1 : check if triggers are trivially valid */
749f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
750f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
751f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
752f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
753f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
754f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
755f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
756f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	if (err)
757f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		return 1;
758f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
759f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	/* Step 2a : make sure trigger sources are unique */
760f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
761f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_is_unique(cmd->start_src);
762f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_is_unique(cmd->stop_src);
763f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
764f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	/* Step 2b : and mutually compatible */
765f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
766f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	if (err)
767f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		return 2;
768f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
769f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	/* Step 3: check if arguments are trivially valid */
770f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
771f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
772f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
773f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
774f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
775f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
776f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	switch (cmd->stop_src) {
777f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	case TRIG_COUNT:
778f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		/* any count allowed */
779f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		break;
780f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	case TRIG_NONE:
781f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
782f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		break;
783f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	default:
784f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		break;
785f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	}
786f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
787f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	if (err)
788f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		return 3;
789f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
790f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	/* step 4: fix up any arguments */
791f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
792f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	/* if (err) return 4; */
793f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
794f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	return 0;
7956baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
7966baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7976b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweetenstatic int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
7986b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten{
799a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	const struct pcmuio_board *board = comedi_board(dev);
8009a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten	struct pcmuio_private *devpriv;
8016b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	struct comedi_subdevice *s;
8026b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0;
8036b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	unsigned long iobase;
8046b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	unsigned int irq[MAX_ASICS];
8058b6c56949ffa83dbc2a6e8fa3f98b10a19372207H Hartley Sweeten	int ret;
8066b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
8076b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	iobase = it->options[0];
8086b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	irq[0] = it->options[1];
8096b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	irq[1] = it->options[2];
8106b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
811f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott	dev_dbg(dev->class_dev, "%s: io: %lx attach\n",
8122d2111ea2cf25cc60f7027130ceb34af2d03745dH Hartley Sweeten		dev->driver->driver_name, iobase);
8136b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
8146b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	dev->iobase = iobase;
8156b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
8166b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	if (!iobase || !request_region(iobase,
817a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten				       board->num_asics * ASIC_IOSIZE,
8182d2111ea2cf25cc60f7027130ceb34af2d03745dH Hartley Sweeten				       dev->driver->driver_name)) {
819f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott		dev_err(dev->class_dev, "I/O port conflict\n");
8206b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		return -EIO;
8216b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	}
8226b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
823a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	dev->board_name = board->name;
8246b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
825c34fa261b0ac3a862ccd3f71ee55a16b920dfc83H Hartley Sweeten	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
826c34fa261b0ac3a862ccd3f71ee55a16b920dfc83H Hartley Sweeten	if (!devpriv)
827c34fa261b0ac3a862ccd3f71ee55a16b920dfc83H Hartley Sweeten		return -ENOMEM;
828c34fa261b0ac3a862ccd3f71ee55a16b920dfc83H Hartley Sweeten	dev->private = devpriv;
8296b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
8306b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	for (asic = 0; asic < MAX_ASICS; ++asic) {
8316b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		devpriv->asics[asic].num = asic;
8326b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		devpriv->asics[asic].iobase = dev->iobase + asic * ASIC_IOSIZE;
8336b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		devpriv->asics[asic].irq = 0;	/* this gets actually set at the end of
8346b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten						   this function when we
8356b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten						   request_irqs */
8366b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		spin_lock_init(&devpriv->asics[asic].spinlock);
8376b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	}
8386b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
839a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	chans_left = CHANS_PER_ASIC * board->num_asics;
8406b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	n_subdevs = CALC_N_SUBDEVS(chans_left);
8416b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	devpriv->sprivs =
8426b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	    kcalloc(n_subdevs, sizeof(struct pcmuio_subdev_private),
8436b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		    GFP_KERNEL);
8446b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	if (!devpriv->sprivs) {
845f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott		dev_warn(dev->class_dev,
846f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott			 "cannot allocate subdevice private data structures\n");
8476b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		return -ENOMEM;
8486b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	}
849eea6838b1206b0ac90110f1a6f58e101aa496e99H Hartley Sweeten
8508b6c56949ffa83dbc2a6e8fa3f98b10a19372207H Hartley Sweeten	ret = comedi_alloc_subdevices(dev, n_subdevs);
8518b6c56949ffa83dbc2a6e8fa3f98b10a19372207H Hartley Sweeten	if (ret)
8528b6c56949ffa83dbc2a6e8fa3f98b10a19372207H Hartley Sweeten		return ret;
8536b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
8546b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	port = 0;
8556b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	asic = 0;
8566b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
8576b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		int byte_no;
8586b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
85968720ae68a94444387d56bc5a166396e33e420a5H Hartley Sweeten		s = &dev->subdevices[sdev_no];
86068720ae68a94444387d56bc5a166396e33e420a5H Hartley Sweeten		s->private = &devpriv->sprivs[sdev_no];
8616b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->maxdata = 1;
8626b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->range_table = &range_digital;
8636b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
8646b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->type = COMEDI_SUBD_DIO;
8656b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->insn_bits = pcmuio_dio_insn_bits;
8666b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->insn_config = pcmuio_dio_insn_config;
8676b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
8686b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		subpriv->intr.asic = -1;
8696b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		subpriv->intr.first_chan = -1;
8706b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		subpriv->intr.asic_chan = -1;
8716b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		subpriv->intr.num_asic_chans = -1;
8726b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		subpriv->intr.active = 0;
8736b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->len_chanlist = 1;
8746b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
8756b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		/* save the ioport address for each 'port' of 8 channels in the
8766b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		   subdevice */
8776b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
8786b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			if (port >= PORTS_PER_ASIC) {
8796b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				port = 0;
8806b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				++asic;
8816b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				thisasic_chanct = 0;
8826b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			}
8836b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			subpriv->iobases[byte_no] =
8846b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			    devpriv->asics[asic].iobase + port;
8856b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
8866b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			if (thisasic_chanct <
8876b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			    CHANS_PER_PORT * INTR_PORTS_PER_ASIC
8886b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			    && subpriv->intr.asic < 0) {
8896b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				/* this is an interrupt subdevice, so setup the struct */
8906b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				subpriv->intr.asic = asic;
8916b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				subpriv->intr.active = 0;
8926b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				subpriv->intr.stop_count = 0;
8936b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				subpriv->intr.first_chan = byte_no * 8;
8946b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				subpriv->intr.asic_chan = thisasic_chanct;
8956b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				subpriv->intr.num_asic_chans =
8966b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				    s->n_chan - subpriv->intr.first_chan;
8976b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				dev->read_subdev = s;
8986b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				s->subdev_flags |= SDF_CMD_READ;
8996b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				s->cancel = pcmuio_cancel;
9006b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				s->do_cmd = pcmuio_cmd;
9016b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				s->do_cmdtest = pcmuio_cmdtest;
9026b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				s->len_chanlist = subpriv->intr.num_asic_chans;
9036b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			}
9046b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			thisasic_chanct += CHANS_PER_PORT;
9056b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		}
9066b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		spin_lock_init(&subpriv->intr.spinlock);
9076b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
9086b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		chans_left -= s->n_chan;
9096b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
9106b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		if (!chans_left) {
9116b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			asic = 0;	/* reset the asic to our first asic, to do intr subdevs */
9126b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			port = 0;
9136b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		}
9146b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
9156b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	}
9166b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
9176b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	init_asics(dev);	/* clear out all the registers, basically */
9186b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
9196b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
9206b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		if (irq[asic]
9216b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		    && request_irq(irq[asic], interrupt_pcmuio,
922a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten				   IRQF_SHARED, board->name, dev)) {
9236b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			int i;
9246b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			/* unroll the allocated irqs.. */
9256b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			for (i = asic - 1; i >= 0; --i) {
9266b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				free_irq(irq[i], dev);
9276b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				devpriv->asics[i].irq = irq[i] = 0;
9286b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			}
9296b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			irq[asic] = 0;
9306b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		}
9316b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		devpriv->asics[asic].irq = irq[asic];
9326b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	}
9336b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
9346b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	dev->irq = irq[0];	/* grr.. wish comedi dev struct supported multiple
9356b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				   irqs.. */
9366b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
9376b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	if (irq[0]) {
938f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott		dev_dbg(dev->class_dev, "irq: %u\n", irq[0]);
939a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten		if (irq[1] && board->num_asics == 2)
940f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott			dev_dbg(dev->class_dev, "second ASIC irq: %u\n",
941f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott				irq[1]);
9426b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	} else {
943f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott		dev_dbg(dev->class_dev, "(IRQ mode disabled)\n");
9446b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	}
9456b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
9466b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
9476b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	return 1;
9486b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten}
9496b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
950484ecc95d9cdfa8b2f7029e2f3409cf078aed4abH Hartley Sweetenstatic void pcmuio_detach(struct comedi_device *dev)
9516b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten{
952a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	const struct pcmuio_board *board = comedi_board(dev);
9539a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten	struct pcmuio_private *devpriv = dev->private;
9546b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	int i;
9556b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
9566b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	if (dev->iobase)
957a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten		release_region(dev->iobase, ASIC_IOSIZE * board->num_asics);
9586b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	for (i = 0; i < MAX_ASICS; ++i) {
9596b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		if (devpriv->asics[i].irq)
9606b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			free_irq(devpriv->asics[i].irq, dev);
9616b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	}
9626b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	if (devpriv && devpriv->sprivs)
9636b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		kfree(devpriv->sprivs);
9646b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten}
9656b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
9666b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweetenstatic const struct pcmuio_board pcmuio_boards[] = {
9676b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	{
9686b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		.name		= "pcmuio48",
9696b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		.num_asics	= 1,
9706b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		.num_ports	= 6,
9716b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	}, {
9726b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		.name		= "pcmuio96",
9736b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		.num_asics	= 2,
9746b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		.num_ports	= 12,
9756b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	},
9766b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten};
9776b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
978294f930d98be86fb4f34302c718a49719650857fH Hartley Sweetenstatic struct comedi_driver pcmuio_driver = {
9796b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	.driver_name	= "pcmuio",
9806b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	.module		= THIS_MODULE,
9816b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	.attach		= pcmuio_attach,
9826b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	.detach		= pcmuio_detach,
9836b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	.board_name	= &pcmuio_boards[0].name,
9846b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	.offset		= sizeof(struct pcmuio_board),
9856b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	.num_names	= ARRAY_SIZE(pcmuio_boards),
9866b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten};
987294f930d98be86fb4f34302c718a49719650857fH Hartley Sweetenmodule_comedi_driver(pcmuio_driver);
98890f703d30dd3e0c16ff80f35e34e511385a05ad5Arun Thomas
98990f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_AUTHOR("Comedi http://www.comedi.org");
99090f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_DESCRIPTION("Comedi low-level driver");
99190f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_LICENSE("GPL");
992