pcmuio.c revision 3b48c535802eb515069b4f2ff26f0601eabf51b8
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/*
196baef150380d561a4d695a6be4fc509821c23611Calin CulianuDriver: pcmuio
206baef150380d561a4d695a6be4fc509821c23611Calin CulianuDescription: A driver for the PCM-UIO48A and PCM-UIO96A boards from Winsystems.
216baef150380d561a4d695a6be4fc509821c23611Calin CulianuDevices: [Winsystems] PCM-UIO48A (pcmuio48), PCM-UIO96A (pcmuio96)
226baef150380d561a4d695a6be4fc509821c23611Calin CulianuAuthor: Calin Culianu <calin@ajvar.org>
236baef150380d561a4d695a6be4fc509821c23611Calin CulianuUpdated: Fri, 13 Jan 2006 12:01:01 -0500
246baef150380d561a4d695a6be4fc509821c23611Calin CulianuStatus: works
256baef150380d561a4d695a6be4fc509821c23611Calin Culianu
266baef150380d561a4d695a6be4fc509821c23611Calin CulianuA driver for the relatively straightforward-to-program PCM-UIO48A and
276baef150380d561a4d695a6be4fc509821c23611Calin CulianuPCM-UIO96A boards from Winsystems.  These boards use either one or two
286baef150380d561a4d695a6be4fc509821c23611Calin Culianu(in the 96-DIO version) WS16C48 ASIC HighDensity I/O Chips (HDIO).
296baef150380d561a4d695a6be4fc509821c23611Calin CulianuThis chip is interesting in that each I/O line is individually
306baef150380d561a4d695a6be4fc509821c23611Calin Culianuprogrammable for INPUT or OUTPUT (thus comedi_dio_config can be done
316baef150380d561a4d695a6be4fc509821c23611Calin Culianuon a per-channel basis).  Also, each chip supports edge-triggered
326baef150380d561a4d695a6be4fc509821c23611Calin Culianuinterrupts for the first 24 I/O lines.  Of course, since the
336baef150380d561a4d695a6be4fc509821c23611Calin Culianu96-channel version of the board has two ASICs, it can detect polarity
346baef150380d561a4d695a6be4fc509821c23611Calin Culianuchanges on up to 48 I/O lines.  Since this is essentially an (non-PnP)
356baef150380d561a4d695a6be4fc509821c23611Calin CulianuISA board, I/O Address and IRQ selection are done through jumpers on
366baef150380d561a4d695a6be4fc509821c23611Calin Culianuthe board.  You need to pass that information to this driver as the
376baef150380d561a4d695a6be4fc509821c23611Calin Culianufirst and second comedi_config option, respectively.  Note that the
386baef150380d561a4d695a6be4fc509821c23611Calin Culianu48-channel version uses 16 bytes of IO memory and the 96-channel
396baef150380d561a4d695a6be4fc509821c23611Calin Culianuversion uses 32-bytes (in case you are worried about conflicts).  The
406baef150380d561a4d695a6be4fc509821c23611Calin Culianu48-channel board is split into two 24-channel comedi subdevices.
416baef150380d561a4d695a6be4fc509821c23611Calin CulianuThe 96-channel board is split into 4 24-channel DIO subdevices.
426baef150380d561a4d695a6be4fc509821c23611Calin Culianu
436baef150380d561a4d695a6be4fc509821c23611Calin CulianuNote that IRQ support has been added, but it is untested.
446baef150380d561a4d695a6be4fc509821c23611Calin Culianu
456baef150380d561a4d695a6be4fc509821c23611Calin CulianuTo use edge-detection IRQ support, pass the IRQs of both ASICS
466baef150380d561a4d695a6be4fc509821c23611Calin Culianu(for the 96 channel version) or just 1 ASIC (for 48-channel version).
476baef150380d561a4d695a6be4fc509821c23611Calin CulianuThen, use use comedi_commands with TRIG_NOW.
486baef150380d561a4d695a6be4fc509821c23611Calin CulianuYour callback will be called each time an edge is triggered, and the data
496baef150380d561a4d695a6be4fc509821c23611Calin Culianuvalues will be two sample_t's, which should be concatenated to form one
506baef150380d561a4d695a6be4fc509821c23611Calin Culianu32-bit unsigned int.  This value is the mask of channels that had
516baef150380d561a4d695a6be4fc509821c23611Calin Culianuedges detected from your channel list.  Note that the bits positions
526baef150380d561a4d695a6be4fc509821c23611Calin Culianuin the mask correspond to positions in your chanlist when you specified
536baef150380d561a4d695a6be4fc509821c23611Calin Culianuthe command and *not* channel id's!
546baef150380d561a4d695a6be4fc509821c23611Calin Culianu
556baef150380d561a4d695a6be4fc509821c23611Calin CulianuTo set the polarity of the edge-detection interrupts pass a nonzero value for
566baef150380d561a4d695a6be4fc509821c23611Calin Culianueither CR_RANGE or CR_AREF for edge-up polarity, or a zero value for both
576baef150380d561a4d695a6be4fc509821c23611Calin CulianuCR_RANGE and CR_AREF if you want edge-down polarity.
586baef150380d561a4d695a6be4fc509821c23611Calin Culianu
596baef150380d561a4d695a6be4fc509821c23611Calin CulianuIn the 48-channel version:
606baef150380d561a4d695a6be4fc509821c23611Calin Culianu
616baef150380d561a4d695a6be4fc509821c23611Calin CulianuOn subdev 0, the first 24 channels channels are edge-detect channels.
626baef150380d561a4d695a6be4fc509821c23611Calin Culianu
636baef150380d561a4d695a6be4fc509821c23611Calin CulianuIn the 96-channel board you have the collowing channels that can do edge detection:
646baef150380d561a4d695a6be4fc509821c23611Calin Culianu
656baef150380d561a4d695a6be4fc509821c23611Calin Culianusubdev 0, channels 0-24  (first 24 channels of 1st ASIC)
666baef150380d561a4d695a6be4fc509821c23611Calin Culianusubdev 2, channels 0-24  (first 24 channels of 2nd ASIC)
676baef150380d561a4d695a6be4fc509821c23611Calin Culianu
686baef150380d561a4d695a6be4fc509821c23611Calin CulianuConfiguration Options:
696baef150380d561a4d695a6be4fc509821c23611Calin Culianu  [0] - I/O port base address
706baef150380d561a4d695a6be4fc509821c23611Calin Culianu  [1] - IRQ (for first ASIC, or first 24 channels)
716baef150380d561a4d695a6be4fc509821c23611Calin Culianu  [2] - IRQ for second ASIC (pcmuio96 only - IRQ for chans 48-72 .. can be the same as first irq!)
726baef150380d561a4d695a6be4fc509821c23611Calin Culianu*/
736baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7425436dc9d84f1be60ff549c9ab712bba2835f284Greg Kroah-Hartman#include <linux/interrupt.h>
755a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
766baef150380d561a4d695a6be4fc509821c23611Calin Culianu
77f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten#include "../comedidev.h"
7833782dd5edf8db3cdb7c81a3523bf743dd0209b7H Hartley Sweeten
79f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten#include "comedi_fc.h"
806baef150380d561a4d695a6be4fc509821c23611Calin Culianu
816baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define CHANS_PER_PORT   8
826baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PORTS_PER_ASIC   6
836baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define INTR_PORTS_PER_ASIC   3
846baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define MAX_CHANS_PER_SUBDEV 24	/* number of channels per comedi subdevice */
856baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PORTS_PER_SUBDEV (MAX_CHANS_PER_SUBDEV/CHANS_PER_PORT)
866baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define CHANS_PER_ASIC (CHANS_PER_PORT*PORTS_PER_ASIC)
876baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define INTR_CHANS_PER_ASIC 24
886baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC/CHANS_PER_PORT)
896baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define MAX_DIO_CHANS   (PORTS_PER_ASIC*2*CHANS_PER_PORT)
906baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define MAX_ASICS       (MAX_DIO_CHANS/CHANS_PER_ASIC)
916baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define CALC_N_SUBDEVS(nchans) ((nchans)/MAX_CHANS_PER_SUBDEV + (!!((nchans)%MAX_CHANS_PER_SUBDEV)) /*+ (nchans > INTR_CHANS_PER_ASIC ? 2 : 1)*/)
926baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* IO Memory sizes */
936baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define ASIC_IOSIZE (0x10)
946baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PCMUIO48_IOSIZE ASIC_IOSIZE
956baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PCMUIO96_IOSIZE (ASIC_IOSIZE*2)
966baef150380d561a4d695a6be4fc509821c23611Calin Culianu
976baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* Some offsets - these are all in the 16byte IO memory offset from
986baef150380d561a4d695a6be4fc509821c23611Calin Culianu   the base address.  Note that there is a paging scheme to swap out
996baef150380d561a4d695a6be4fc509821c23611Calin Culianu   offsets 0x8-0xA using the PAGELOCK register.  See the table below.
1006baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1016baef150380d561a4d695a6be4fc509821c23611Calin Culianu  Register(s)       Pages        R/W?        Description
1026baef150380d561a4d695a6be4fc509821c23611Calin Culianu  --------------------------------------------------------------
1036baef150380d561a4d695a6be4fc509821c23611Calin Culianu  REG_PORTx         All          R/W         Read/Write/Configure IO
1046baef150380d561a4d695a6be4fc509821c23611Calin Culianu  REG_INT_PENDING   All          ReadOnly    Quickly see which INT_IDx has int.
1056baef150380d561a4d695a6be4fc509821c23611Calin Culianu  REG_PAGELOCK      All          WriteOnly   Select a page
1066baef150380d561a4d695a6be4fc509821c23611Calin Culianu  REG_POLx          Pg. 1 only   WriteOnly   Select edge-detection polarity
1076baef150380d561a4d695a6be4fc509821c23611Calin Culianu  REG_ENABx         Pg. 2 only   WriteOnly   Enable/Disable edge-detect. int.
1086baef150380d561a4d695a6be4fc509821c23611Calin Culianu  REG_INT_IDx       Pg. 3 only   R/W         See which ports/bits have ints.
1096baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
1106baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT0 0x0
1116baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT1 0x1
1126baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT2 0x2
1136baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT3 0x3
1146baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT4 0x4
1156baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT5 0x5
1166baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_INT_PENDING 0x6
1176baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PAGELOCK 0x7	/* page selector register, upper 2 bits select a page
1186baef150380d561a4d695a6be4fc509821c23611Calin Culianu				   and bits 0-5 are used to 'lock down' a particular
1196baef150380d561a4d695a6be4fc509821c23611Calin Culianu				   port above to make it readonly.  */
1206baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_POL0 0x8
1216baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_POL1 0x9
1226baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_POL2 0xA
1236baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_ENAB0 0x8
1246baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_ENAB1 0x9
1256baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_ENAB2 0xA
1266baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_INT_ID0 0x8
1276baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_INT_ID1 0x9
1286baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_INT_ID2 0xA
1296baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1306baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define NUM_PAGED_REGS 3
1316baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define NUM_PAGES 4
1326baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define FIRST_PAGED_REG 0x8
1336baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PAGE_BITOFFSET 6
1346baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_LOCK_BITOFFSET 0
1356baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PAGE_MASK (~((0x1<<REG_PAGE_BITOFFSET)-1))
1366baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_LOCK_MASK ~(REG_PAGE_MASK)
1376baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PAGE_POL 1
1386baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PAGE_ENAB 2
1396baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PAGE_INT_ID 3
1406baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1416baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
1426baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Board descriptions for two imaginary boards.  Describing the
1436baef150380d561a4d695a6be4fc509821c23611Calin Culianu * boards in this way is optional, and completely driver-dependent.
1446baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Some drivers use arrays such as this, other do not.
1456baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
14670a6001aeffeaa12f2a1c21470e8f3bdfb6ef8e7Bill Pembertonstruct pcmuio_board {
1476baef150380d561a4d695a6be4fc509821c23611Calin Culianu	const char *name;
1486baef150380d561a4d695a6be4fc509821c23611Calin Culianu	const int num_asics;
1496baef150380d561a4d695a6be4fc509821c23611Calin Culianu	const int num_channels_per_port;
1506baef150380d561a4d695a6be4fc509821c23611Calin Culianu	const int num_ports;
15170a6001aeffeaa12f2a1c21470e8f3bdfb6ef8e7Bill Pemberton};
1526baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1536baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* this structure is for data unique to this subdevice.  */
154e15849e54405152087cd343437747db8d931fcd7Bill Pembertonstruct pcmuio_subdev_private {
1556baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* mapping of halfwords (bytes) in port/chanarray to iobase */
1566baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long iobases[PORTS_PER_SUBDEV];
1576baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1586baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* The below is only used for intr subdevices */
1596baef150380d561a4d695a6be4fc509821c23611Calin Culianu	struct {
1606baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int asic;	/* if non-negative, this subdev has an interrupt asic */
1616baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int first_chan;	/* if nonnegative, the first channel id for
1626baef150380d561a4d695a6be4fc509821c23611Calin Culianu				   interrupts. */
1636baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int num_asic_chans;	/* the number of asic channels in this subdev
1646baef150380d561a4d695a6be4fc509821c23611Calin Culianu					   that have interrutps */
1656baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int asic_chan;	/* if nonnegative, the first channel id with
1666baef150380d561a4d695a6be4fc509821c23611Calin Culianu				   respect to the asic that has interrupts */
1676baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int enabled_mask;	/* subdev-relative channel mask for channels
1686baef150380d561a4d695a6be4fc509821c23611Calin Culianu					   we are interested in */
1696baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int active;
1706baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int stop_count;
1716baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int continuous;
1726baef150380d561a4d695a6be4fc509821c23611Calin Culianu		spinlock_t spinlock;
1736baef150380d561a4d695a6be4fc509821c23611Calin Culianu	} intr;
174e15849e54405152087cd343437747db8d931fcd7Bill Pemberton};
1756baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1766baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* this structure is for data unique to this hardware driver.  If
1776baef150380d561a4d695a6be4fc509821c23611Calin Culianu   several hardware drivers keep similar information in this structure,
17871b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton   feel free to suggest moving the variable to the struct comedi_device struct.  */
179055f6636d9eb27bc13236e07739e019496c21221Bill Pembertonstruct pcmuio_private {
1806baef150380d561a4d695a6be4fc509821c23611Calin Culianu	struct {
1816baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned char pagelock;	/* current page and lock */
1826baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned char pol[NUM_PAGED_REGS];	/* shadow of POLx registers */
1836baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned char enab[NUM_PAGED_REGS];	/* shadow of ENABx registers */
1846baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int num;
1856baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned long iobase;
1866baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned int irq;
1876baef150380d561a4d695a6be4fc509821c23611Calin Culianu		spinlock_t spinlock;
1886baef150380d561a4d695a6be4fc509821c23611Calin Culianu	} asics[MAX_ASICS];
189e15849e54405152087cd343437747db8d931fcd7Bill Pemberton	struct pcmuio_subdev_private *sprivs;
190055f6636d9eb27bc13236e07739e019496c21221Bill Pemberton};
1916baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1926baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* DIO devices are slightly special.  Although it is possible to
1936baef150380d561a4d695a6be4fc509821c23611Calin Culianu * implement the insn_read/insn_write interface, it is much more
1946baef150380d561a4d695a6be4fc509821c23611Calin Culianu * useful to applications if you implement the insn_bits interface.
1956baef150380d561a4d695a6be4fc509821c23611Calin Culianu * This allows packed reading/writing of the DIO channels.  The
1966baef150380d561a4d695a6be4fc509821c23611Calin Culianu * comedi core can convert between insn_bits and insn_read/write */
1970a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcmuio_dio_insn_bits(struct comedi_device *dev,
1980a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				struct comedi_subdevice *s,
1990a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				struct comedi_insn *insn, unsigned int *data)
2006baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
2018099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	struct pcmuio_subdev_private *subpriv = s->private;
2026baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int byte_no;
2036baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2046baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* NOTE:
2056baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   reading a 0 means this channel was high
2066baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   writine a 0 sets the channel high
2076baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   reading a 1 means this channel was low
2086baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   writing a 1 means set this channel low
2096baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2106baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   Therefore everything is always inverted. */
2116baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2126baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* The insn data is a mask in data[0] and the new data
2136baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * in data[1], each channel cooresponding to a bit. */
2146baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2156baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef DAMMIT_ITS_BROKEN
2166baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* DEBUG */
217f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott	dev_dbg(dev->class_dev, "write mask: %08x  data: %08x\n", data[0],
218976fe5ab27e682d3dbfec26517a8a248638af07dRavishankar karkala Mallikarjunayya		data[1]);
2196baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif
2206baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2216baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s->state = 0;
2226baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2236baef150380d561a4d695a6be4fc509821c23611Calin Culianu	for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) {
2246baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* address of 8-bit port */
2256baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned long ioaddr = subpriv->iobases[byte_no],
2260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    /* bit offset of port in 32-bit doubleword */
2270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    offset = byte_no * 8;
2286baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* this 8-bit port's data */
2296baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned char byte = 0,
2300a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    /* The write mask for this port (if any) */
2310a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    write_mask_byte = (data[0] >> offset) & 0xff,
2320a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    /* The data byte for this port */
2330a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    data_byte = (data[1] >> offset) & 0xff;
2346baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2356baef150380d561a4d695a6be4fc509821c23611Calin Culianu		byte = inb(ioaddr);	/* read all 8-bits for this port */
2366baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2376baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef DAMMIT_ITS_BROKEN
2386baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* DEBUG */
2390a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk
2400a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    ("byte %d wmb %02x db %02x offset %02d io %04x, data_in %02x ",
2410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		     byte_no, (unsigned)write_mask_byte, (unsigned)data_byte,
2420a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		     offset, ioaddr, (unsigned)byte);
2436baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif
2446baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2456baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (write_mask_byte) {
2466baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* this byte has some write_bits -- so set the output lines */
2476baef150380d561a4d695a6be4fc509821c23611Calin Culianu			byte &= ~write_mask_byte;	/* clear bits for write mask */
2486baef150380d561a4d695a6be4fc509821c23611Calin Culianu			byte |= ~data_byte & write_mask_byte;	/* set to inverted data_byte */
2496baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* Write out the new digital output state */
2506baef150380d561a4d695a6be4fc509821c23611Calin Culianu			outb(byte, ioaddr);
2516baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
2526baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef DAMMIT_ITS_BROKEN
2536baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* DEBUG */
254f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott		dev_dbg(dev->class_dev, "data_out_byte %02x\n", (unsigned)byte);
2556baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif
2566baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* save the digital input lines for this byte.. */
2576baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->state |= ((unsigned int)byte) << offset;
2586baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
2596baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2606baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* now return the DIO lines to data[1] - note they came inverted! */
2616baef150380d561a4d695a6be4fc509821c23611Calin Culianu	data[1] = ~s->state;
2626baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2636baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef DAMMIT_ITS_BROKEN
2646baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* DEBUG */
265f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott	dev_dbg(dev->class_dev, "s->state %08x data_out %08x\n", s->state,
266976fe5ab27e682d3dbfec26517a8a248638af07dRavishankar karkala Mallikarjunayya		data[1]);
2676baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif
2686baef150380d561a4d695a6be4fc509821c23611Calin Culianu
269a2714e3e42e746d6c8525c35fdcc58fb60c2830dH Hartley Sweeten	return insn->n;
2706baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
2716baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2726baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* The input or output configuration of each digital line is
2736baef150380d561a4d695a6be4fc509821c23611Calin Culianu * configured by a special insn_config instruction.  chanspec
2746baef150380d561a4d695a6be4fc509821c23611Calin Culianu * contains the channel to be changed, and data[0] contains the
2756baef150380d561a4d695a6be4fc509821c23611Calin Culianu * value COMEDI_INPUT or COMEDI_OUTPUT. */
2760a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcmuio_dio_insn_config(struct comedi_device *dev,
2770a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  struct comedi_subdevice *s,
2780a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  struct comedi_insn *insn, unsigned int *data)
2796baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
2808099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	struct pcmuio_subdev_private *subpriv = s->private;
2816baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no =
2820a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    chan % 8;
2836baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long ioaddr;
2846baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned char byte;
2856baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2866baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* Compute ioaddr for this channel */
2876baef150380d561a4d695a6be4fc509821c23611Calin Culianu	ioaddr = subpriv->iobases[byte_no];
2886baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2896baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* NOTE:
2906baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   writing a 0 an IO channel's bit sets the channel to INPUT
2916baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   and pulls the line high as well
2926baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2936baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   writing a 1 to an IO channel's  bit pulls the line low
2946baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2956baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   All channels are implicitly always in OUTPUT mode -- but when
2966baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   they are high they can be considered to be in INPUT mode..
2976baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2986baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   Thus, we only force channels low if the config request was INPUT,
2996baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   otherwise we do nothing to the hardware.    */
3006baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3016baef150380d561a4d695a6be4fc509821c23611Calin Culianu	switch (data[0]) {
3026baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case INSN_CONFIG_DIO_OUTPUT:
3036baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* save to io_bits -- don't actually do anything since
3046baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   all input channels are also output channels... */
3056baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->io_bits |= 1 << chan;
3066baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
3076baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case INSN_CONFIG_DIO_INPUT:
3086baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* write a 0 to the actual register representing the channel
3096baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   to set it to 'input'.  0 means "float high". */
3106baef150380d561a4d695a6be4fc509821c23611Calin Culianu		byte = inb(ioaddr);
3116baef150380d561a4d695a6be4fc509821c23611Calin Culianu		byte &= ~(1 << bit_no);
3126baef150380d561a4d695a6be4fc509821c23611Calin Culianu				/**< set input channel to '0' */
3136baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3146baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* write out byte -- this is the only time we actually affect the
3156baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   hardware as all channels are implicitly output -- but input
3166baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   channels are set to float-high */
3176baef150380d561a4d695a6be4fc509821c23611Calin Culianu		outb(byte, ioaddr);
3186baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3196baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* save to io_bits */
3206baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->io_bits &= ~(1 << chan);
3216baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
3226baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3236baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case INSN_CONFIG_DIO_QUERY:
32425985edcedea6396277003854657b5f3cb31a628Lucas De Marchi		/* retrieve from shadow register */
3256baef150380d561a4d695a6be4fc509821c23611Calin Culianu		data[1] =
3260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
3276baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return insn->n;
3286baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
3296baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3306baef150380d561a4d695a6be4fc509821c23611Calin Culianu	default:
3316baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return -EINVAL;
3326baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
3336baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
3346baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3356baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return insn->n;
3366baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
3376baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3386b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweetenstatic void switch_page(struct comedi_device *dev, int asic, int page)
3396b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten{
340a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	const struct pcmuio_board *board = comedi_board(dev);
3419a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten	struct pcmuio_private *devpriv = dev->private;
342a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten
343a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	if (asic < 0 || asic >= board->num_asics)
3446b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		return;		/* paranoia */
3456b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	if (page < 0 || page >= NUM_PAGES)
3466b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		return;		/* more paranoia */
3476b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
3486b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
3496b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
3506b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
3516b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	/* now write out the shadow register */
3526b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	outb(devpriv->asics[asic].pagelock,
3536b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	     dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
3546b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten}
3556b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
356da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void init_asics(struct comedi_device *dev)
3576baef150380d561a4d695a6be4fc509821c23611Calin Culianu{				/* sets up an
3586baef150380d561a4d695a6be4fc509821c23611Calin Culianu				   ASIC chip to defaults */
359a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	const struct pcmuio_board *board = comedi_board(dev);
3606baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int asic;
3616baef150380d561a4d695a6be4fc509821c23611Calin Culianu
362a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	for (asic = 0; asic < board->num_asics; ++asic) {
3636baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int port, page;
3646baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned long baseaddr = dev->iobase + asic * ASIC_IOSIZE;
3656baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3666baef150380d561a4d695a6be4fc509821c23611Calin Culianu		switch_page(dev, asic, 0);	/* switch back to page 0 */
3676baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3686baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* first, clear all the DIO port bits */
3696baef150380d561a4d695a6be4fc509821c23611Calin Culianu		for (port = 0; port < PORTS_PER_ASIC; ++port)
3706baef150380d561a4d695a6be4fc509821c23611Calin Culianu			outb(0, baseaddr + REG_PORT0 + port);
3716baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3726baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* Next, clear all the paged registers for each page */
3736baef150380d561a4d695a6be4fc509821c23611Calin Culianu		for (page = 1; page < NUM_PAGES; ++page) {
3746baef150380d561a4d695a6be4fc509821c23611Calin Culianu			int reg;
3756baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* now clear all the paged registers */
3766baef150380d561a4d695a6be4fc509821c23611Calin Culianu			switch_page(dev, asic, page);
3776baef150380d561a4d695a6be4fc509821c23611Calin Culianu			for (reg = FIRST_PAGED_REG;
3780a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg)
3796baef150380d561a4d695a6be4fc509821c23611Calin Culianu				outb(0, baseaddr + reg);
3806baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
3816baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3826baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* DEBUG  set rising edge interrupts on port0 of both asics */
3836baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/*switch_page(dev, asic, PAGE_POL);
3846baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   outb(0xff, baseaddr + REG_POL0);
3856baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   switch_page(dev, asic, PAGE_ENAB);
3866baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   outb(0xff, baseaddr + REG_ENAB0); */
3876baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* END DEBUG */
3886baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3896baef150380d561a4d695a6be4fc509821c23611Calin Culianu		switch_page(dev, asic, 0);	/* switch back to default page 0 */
3906baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3916baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
3926baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
3936baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3946baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef notused
395da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void lock_port(struct comedi_device *dev, int asic, int port)
3966baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
397a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	const struct pcmuio_board *board = comedi_board(dev);
3989a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten	struct pcmuio_private *devpriv = dev->private;
399a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten
400a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	if (asic < 0 || asic >= board->num_asics)
4016baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return;		/* paranoia */
4026baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (port < 0 || port >= PORTS_PER_ASIC)
4036baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return;		/* more paranoia */
4046baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4056baef150380d561a4d695a6be4fc509821c23611Calin Culianu	devpriv->asics[asic].pagelock |= 0x1 << port;
4066baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* now write out the shadow register */
4076baef150380d561a4d695a6be4fc509821c23611Calin Culianu	outb(devpriv->asics[asic].pagelock,
4080a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	     dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
4096baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
4106baef150380d561a4d695a6be4fc509821c23611Calin Culianu
411da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void unlock_port(struct comedi_device *dev, int asic, int port)
4126baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
413a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	const struct pcmuio_board *board = comedi_board(dev);
4149a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten	struct pcmuio_private *devpriv = dev->private;
415a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten
416a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	if (asic < 0 || asic >= board->num_asics)
4176baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return;		/* paranoia */
4186baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (port < 0 || port >= PORTS_PER_ASIC)
4196baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return;		/* more paranoia */
4206baef150380d561a4d695a6be4fc509821c23611Calin Culianu	devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK;
4216baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* now write out the shadow register */
4226baef150380d561a4d695a6be4fc509821c23611Calin Culianu	outb(devpriv->asics[asic].pagelock,
4230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	     dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
4246baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
4256baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif /* notused */
4266baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4276b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweetenstatic void pcmuio_stop_intr(struct comedi_device *dev,
4286b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			     struct comedi_subdevice *s)
4296b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten{
4309a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten	struct pcmuio_private *devpriv = dev->private;
4318099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	struct pcmuio_subdev_private *subpriv = s->private;
4328099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	int nports, firstport, asic, port;
4336b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
4346b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	asic = subpriv->intr.asic;
4356b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	if (asic < 0)
4366b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		return;		/* not an interrupt subdev */
4376b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
4386b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	subpriv->intr.enabled_mask = 0;
4396b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	subpriv->intr.active = 0;
440920e2ffbe243fb0555b2c238e26fe7dbc03db98cH Hartley Sweeten	s->async->inttrig = NULL;
4416b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
4426b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
4436b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	switch_page(dev, asic, PAGE_ENAB);
4446b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	for (port = firstport; port < firstport + nports; ++port) {
4456b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		/* disable all intrs for this subdev.. */
4466b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
4476b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	}
4486b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten}
4496b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
4503b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweetenstatic void pcmuio_handle_intr_subdev(struct comedi_device *dev,
4513b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				      struct comedi_subdevice *s,
4523b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				      unsigned triggered)
4533b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten{
4543b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	struct pcmuio_subdev_private *subpriv = s->private;
4553b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	unsigned int len = s->async->cmd.chanlist_len;
4563b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	unsigned oldevents = s->async->events;
4573b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	unsigned int val = 0;
4583b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	unsigned long flags;
4593b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	unsigned mytrig;
4603b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	unsigned int i;
4613b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
4623b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	spin_lock_irqsave(&subpriv->intr.spinlock, flags);
4633b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
4643b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	if (!subpriv->intr.active)
4653b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		goto done;
4663b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
4673b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	mytrig = triggered >> subpriv->intr.asic_chan;
4683b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	mytrig &= ((0x1 << subpriv->intr.num_asic_chans) - 1);
4693b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	mytrig <<= subpriv->intr.first_chan;
4703b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
4713b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	if (!(mytrig & subpriv->intr.enabled_mask))
4723b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		goto done;
4733b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
4743b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	for (i = 0; i < len; i++) {
4753b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		unsigned int chan = CR_CHAN(s->async->cmd.chanlist[i]);
4763b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		if (mytrig & (1U << chan))
4773b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			val |= (1U << i);
4783b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	}
4793b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
4803b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	/* Write the scan to the buffer. */
4813b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	if (comedi_buf_put(s->async, ((short *)&val)[0]) &&
4823b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	    comedi_buf_put(s->async, ((short *)&val)[1])) {
4833b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
4843b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	} else {
4853b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		/* Overflow! Stop acquisition!! */
4863b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		/* TODO: STOP_ACQUISITION_CALL_HERE!! */
4873b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		pcmuio_stop_intr(dev, s);
4883b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	}
4893b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
4903b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	/* Check for end of acquisition. */
4913b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	if (!subpriv->intr.continuous) {
4923b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		/* stop_src == TRIG_COUNT */
4933b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		if (subpriv->intr.stop_count > 0) {
4943b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			subpriv->intr.stop_count--;
4953b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			if (subpriv->intr.stop_count == 0) {
4963b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				s->async->events |= COMEDI_CB_EOA;
4973b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				/* TODO: STOP_ACQUISITION_CALL_HERE!! */
4983b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				pcmuio_stop_intr(dev, s);
4993b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			}
5003b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		}
5013b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	}
5023b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
5033b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweetendone:
5043b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
5053b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
5063b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	if (oldevents != s->async->events)
5073b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		comedi_event(dev, s);
5083b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten}
5093b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
5103b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweetenstatic int pcmuio_handle_asic_interrupt(struct comedi_device *dev, int asic)
5116baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
5129a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten	struct pcmuio_private *devpriv = dev->private;
5138099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	struct pcmuio_subdev_private *subpriv;
5143b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	unsigned long iobase = devpriv->asics[asic].iobase;
5153b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	unsigned triggered = 0;
5163b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	int got1 = 0;
5173b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	unsigned long flags;
5183b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	unsigned char int_pend;
51968720ae68a94444387d56bc5a166396e33e420a5H Hartley Sweeten	int i;
5206baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5213b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	spin_lock_irqsave(&devpriv->asics[asic].spinlock, flags);
5223b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
5233b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	int_pend = inb(iobase + REG_INT_PENDING) & 0x07;
5243b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	if (int_pend) {
5253b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		for (i = 0; i < INTR_PORTS_PER_ASIC; ++i) {
5263b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			if (int_pend & (0x1 << i)) {
5273b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				unsigned char val;
5283b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
5293b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				switch_page(dev, asic, PAGE_INT_ID);
5303b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				val = inb(iobase + REG_INT_ID0 + i);
5313b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				if (val)
5323b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten					/* clear pending interrupt */
5333b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten					outb(0, iobase + REG_INT_ID0 + i);
5343b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
5353b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten					triggered |= (val << (i * 8));
5366baef150380d561a4d695a6be4fc509821c23611Calin Culianu			}
5373b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		}
5386baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5393b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		++got1;
5403b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	}
5413b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
5423b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	spin_unlock_irqrestore(&devpriv->asics[asic].spinlock, flags);
5433b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
5443b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	if (triggered) {
5453b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		struct comedi_subdevice *s;
5463b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		/* TODO here: dispatch io lines to subdevs with commands.. */
5473b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		for (i = 0; i < dev->n_subdevices; i++) {
5483b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			s = &dev->subdevices[i];
5493b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			subpriv = s->private;
5503b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			if (subpriv->intr.asic == asic) {
5513b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				/*
5523b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				 * This is an interrupt subdev, and it
5533b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				 * matches this asic!
5543b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				 */
5553b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				pcmuio_handle_intr_subdev(dev, s,
5563b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten							  triggered);
5576baef150380d561a4d695a6be4fc509821c23611Calin Culianu			}
5583b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		}
5593b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	}
5603b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	return got1;
5613b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten}
5623b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten
5633b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweetenstatic irqreturn_t interrupt_pcmuio(int irq, void *d)
5643b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten{
5653b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	struct comedi_device *dev = d;
5663b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	struct pcmuio_private *devpriv = dev->private;
5673b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	int got1 = 0;
5683b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	int asic;
5696baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5703b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten	for (asic = 0; asic < MAX_ASICS; ++asic) {
5713b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten		if (irq == devpriv->asics[asic].irq) {
5723b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			/* it is an interrupt for ASIC #asic */
5733b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten			if (pcmuio_handle_asic_interrupt(dev, asic))
5743b48c535802eb515069b4f2ff26f0601eabf51b8H Hartley Sweeten				got1++;
5756baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
5766baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
5776baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (!got1)
5786baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return IRQ_NONE;	/* interrupt from other source */
5796baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return IRQ_HANDLED;
5806baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
5816baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5820a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcmuio_start_intr(struct comedi_device *dev,
5830a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_subdevice *s)
5846baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
5859a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten	struct pcmuio_private *devpriv = dev->private;
5868099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	struct pcmuio_subdev_private *subpriv = s->private;
5879a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten
5886baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (!subpriv->intr.continuous && subpriv->intr.stop_count == 0) {
5896baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* An empty acquisition! */
5906baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->async->events |= COMEDI_CB_EOA;
5916baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.active = 0;
5926baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return 1;
5936baef150380d561a4d695a6be4fc509821c23611Calin Culianu	} else {
5946baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned bits = 0, pol_bits = 0, n;
5956baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int nports, firstport, asic, port;
596ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton		struct comedi_cmd *cmd = &s->async->cmd;
5976baef150380d561a4d695a6be4fc509821c23611Calin Culianu
598c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton		asic = subpriv->intr.asic;
599c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton		if (asic < 0)
6006baef150380d561a4d695a6be4fc509821c23611Calin Culianu			return 1;	/* not an interrupt
6016baef150380d561a4d695a6be4fc509821c23611Calin Culianu					   subdev */
6026baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.enabled_mask = 0;
6036baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.active = 1;
6046baef150380d561a4d695a6be4fc509821c23611Calin Culianu		nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
6056baef150380d561a4d695a6be4fc509821c23611Calin Culianu		firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
6066baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (cmd->chanlist) {
6076baef150380d561a4d695a6be4fc509821c23611Calin Culianu			for (n = 0; n < cmd->chanlist_len; n++) {
6086baef150380d561a4d695a6be4fc509821c23611Calin Culianu				bits |= (1U << CR_CHAN(cmd->chanlist[n]));
6096baef150380d561a4d695a6be4fc509821c23611Calin Culianu				pol_bits |= (CR_AREF(cmd->chanlist[n])
6100a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					     || CR_RANGE(cmd->
6110a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							 chanlist[n]) ? 1U : 0U)
6120a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    << CR_CHAN(cmd->chanlist[n]);
6136baef150380d561a4d695a6be4fc509821c23611Calin Culianu			}
6146baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
6156baef150380d561a4d695a6be4fc509821c23611Calin Culianu		bits &= ((0x1 << subpriv->intr.num_asic_chans) -
6160a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 1) << subpriv->intr.first_chan;
6176baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.enabled_mask = bits;
6186baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6196baef150380d561a4d695a6be4fc509821c23611Calin Culianu		switch_page(dev, asic, PAGE_ENAB);
6206baef150380d561a4d695a6be4fc509821c23611Calin Culianu		for (port = firstport; port < firstport + nports; ++port) {
6216baef150380d561a4d695a6be4fc509821c23611Calin Culianu			unsigned enab =
6220a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    bits >> (subpriv->intr.first_chan + (port -
6230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								 firstport) *
6240a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				     8) & 0xff, pol =
6250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    pol_bits >> (subpriv->intr.first_chan +
6260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					 (port - firstport) * 8) & 0xff;
6276baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* set enab intrs for this subdev.. */
6286baef150380d561a4d695a6be4fc509821c23611Calin Culianu			outb(enab,
6290a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     devpriv->asics[asic].iobase + REG_ENAB0 + port);
6306baef150380d561a4d695a6be4fc509821c23611Calin Culianu			switch_page(dev, asic, PAGE_POL);
6316baef150380d561a4d695a6be4fc509821c23611Calin Culianu			outb(pol,
6320a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     devpriv->asics[asic].iobase + REG_ENAB0 + port);
6336baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
6346baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
6356baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 0;
6366baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
6376baef150380d561a4d695a6be4fc509821c23611Calin Culianu
638da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
6396baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
6408099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	struct pcmuio_subdev_private *subpriv = s->private;
6416baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long flags;
6426baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6435f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&subpriv->intr.spinlock, flags);
6446baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (subpriv->intr.active)
6456baef150380d561a4d695a6be4fc509821c23611Calin Culianu		pcmuio_stop_intr(dev, s);
6465f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
6476baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6486baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 0;
6496baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
6506baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6516baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
6526baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
6536baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
6546baef150380d561a4d695a6be4fc509821c23611Calin Culianustatic int
655da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonpcmuio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
6560a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			  unsigned int trignum)
6576baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
6588099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	struct pcmuio_subdev_private *subpriv = s->private;
6596baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long flags;
6606baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int event = 0;
6616baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6626baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (trignum != 0)
6636baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return -EINVAL;
6646baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6655f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&subpriv->intr.spinlock, flags);
666920e2ffbe243fb0555b2c238e26fe7dbc03db98cH Hartley Sweeten	s->async->inttrig = NULL;
6670389245f0c5692111c0dc8d997fc4af72d789472Ravishankar karkala Mallikarjunayya	if (subpriv->intr.active)
6686baef150380d561a4d695a6be4fc509821c23611Calin Culianu		event = pcmuio_start_intr(dev, s);
6690389245f0c5692111c0dc8d997fc4af72d789472Ravishankar karkala Mallikarjunayya
6705f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
6716baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6720389245f0c5692111c0dc8d997fc4af72d789472Ravishankar karkala Mallikarjunayya	if (event)
6736baef150380d561a4d695a6be4fc509821c23611Calin Culianu		comedi_event(dev, s);
6746baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6756baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 1;
6766baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
6776baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6786baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
6796baef150380d561a4d695a6be4fc509821c23611Calin Culianu * 'do_cmd' function for an 'INTERRUPT' subdevice.
6806baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
681da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
6826baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
6838099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	struct pcmuio_subdev_private *subpriv = s->private;
684ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd *cmd = &s->async->cmd;
6856baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long flags;
6866baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int event = 0;
6876baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6885f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&subpriv->intr.spinlock, flags);
6896baef150380d561a4d695a6be4fc509821c23611Calin Culianu	subpriv->intr.active = 1;
6906baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6916baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* Set up end of acquisition. */
6926baef150380d561a4d695a6be4fc509821c23611Calin Culianu	switch (cmd->stop_src) {
6936baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case TRIG_COUNT:
6946baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.continuous = 0;
6956baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.stop_count = cmd->stop_arg;
6966baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
6976baef150380d561a4d695a6be4fc509821c23611Calin Culianu	default:
6986baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* TRIG_NONE */
6996baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.continuous = 1;
7006baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->intr.stop_count = 0;
7016baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
7026baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
7036baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7046baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* Set up start of acquisition. */
7056baef150380d561a4d695a6be4fc509821c23611Calin Culianu	switch (cmd->start_src) {
7066baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case TRIG_INT:
7076baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->async->inttrig = pcmuio_inttrig_start_intr;
7086baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
7096baef150380d561a4d695a6be4fc509821c23611Calin Culianu	default:
7106baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* TRIG_NOW */
7116baef150380d561a4d695a6be4fc509821c23611Calin Culianu		event = pcmuio_start_intr(dev, s);
7126baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
7136baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
7145f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&subpriv->intr.spinlock, flags);
7156baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7160389245f0c5692111c0dc8d997fc4af72d789472Ravishankar karkala Mallikarjunayya	if (event)
7176baef150380d561a4d695a6be4fc509821c23611Calin Culianu		comedi_event(dev, s);
7186baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7196baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 0;
7206baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
7216baef150380d561a4d695a6be4fc509821c23611Calin Culianu
722f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweetenstatic int pcmuio_cmdtest(struct comedi_device *dev,
723f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten			  struct comedi_subdevice *s,
724f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten			  struct comedi_cmd *cmd)
7256baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
726f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	int err = 0;
727f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
728f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	/* Step 1 : check if triggers are trivially valid */
729f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
730f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
731f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
732f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
733f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
734f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
735f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
736f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	if (err)
737f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		return 1;
738f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
739f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	/* Step 2a : make sure trigger sources are unique */
740f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
741f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_is_unique(cmd->start_src);
742f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_is_unique(cmd->stop_src);
743f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
744f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	/* Step 2b : and mutually compatible */
745f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
746f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	if (err)
747f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		return 2;
748f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
749f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	/* Step 3: check if arguments are trivially valid */
750f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
751f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
752f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
753f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
754f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
755f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
756f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	switch (cmd->stop_src) {
757f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	case TRIG_COUNT:
758f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		/* any count allowed */
759f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		break;
760f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	case TRIG_NONE:
761f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
762f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		break;
763f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	default:
764f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		break;
765f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	}
766f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
767f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	if (err)
768f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten		return 3;
769f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
770f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	/* step 4: fix up any arguments */
771f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
772f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	/* if (err) return 4; */
773f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten
774f95d45d114e1fd024bdee67beb80fce9b9c96126H Hartley Sweeten	return 0;
7756baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
7766baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7776b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweetenstatic int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
7786b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten{
779a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	const struct pcmuio_board *board = comedi_board(dev);
7806b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	struct comedi_subdevice *s;
7818099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	struct pcmuio_private *devpriv;
7828099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten	struct pcmuio_subdev_private *subpriv;
7836b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0;
7846b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	unsigned int irq[MAX_ASICS];
7858b6c56949ffa83dbc2a6e8fa3f98b10a19372207H Hartley Sweeten	int ret;
7866b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
7876b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	irq[0] = it->options[1];
7886b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	irq[1] = it->options[2];
7896b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
79035626c2efecd6dad6ef67124ae2604385b717ed7H Hartley Sweeten	ret = comedi_request_region(dev, it->options[0],
79135626c2efecd6dad6ef67124ae2604385b717ed7H Hartley Sweeten				    board->num_asics * ASIC_IOSIZE);
79235626c2efecd6dad6ef67124ae2604385b717ed7H Hartley Sweeten	if (ret)
79335626c2efecd6dad6ef67124ae2604385b717ed7H Hartley Sweeten		return ret;
7946b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
795c34fa261b0ac3a862ccd3f71ee55a16b920dfc83H Hartley Sweeten	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
796c34fa261b0ac3a862ccd3f71ee55a16b920dfc83H Hartley Sweeten	if (!devpriv)
797c34fa261b0ac3a862ccd3f71ee55a16b920dfc83H Hartley Sweeten		return -ENOMEM;
798c34fa261b0ac3a862ccd3f71ee55a16b920dfc83H Hartley Sweeten	dev->private = devpriv;
7996b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
8006b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	for (asic = 0; asic < MAX_ASICS; ++asic) {
8016b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		devpriv->asics[asic].num = asic;
8026b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		devpriv->asics[asic].iobase = dev->iobase + asic * ASIC_IOSIZE;
8036b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		devpriv->asics[asic].irq = 0;	/* this gets actually set at the end of
8046b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten						   this function when we
8056b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten						   request_irqs */
8066b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		spin_lock_init(&devpriv->asics[asic].spinlock);
8076b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	}
8086b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
809a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten	chans_left = CHANS_PER_ASIC * board->num_asics;
8106b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	n_subdevs = CALC_N_SUBDEVS(chans_left);
81178110bb8dc4a7ff331bfa3cfe7d4e287cfb3f22bJoe Perches	devpriv->sprivs = kcalloc(n_subdevs,
81278110bb8dc4a7ff331bfa3cfe7d4e287cfb3f22bJoe Perches				  sizeof(struct pcmuio_subdev_private),
81378110bb8dc4a7ff331bfa3cfe7d4e287cfb3f22bJoe Perches				  GFP_KERNEL);
81478110bb8dc4a7ff331bfa3cfe7d4e287cfb3f22bJoe Perches	if (!devpriv->sprivs)
8156b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		return -ENOMEM;
816eea6838b1206b0ac90110f1a6f58e101aa496e99H Hartley Sweeten
8178b6c56949ffa83dbc2a6e8fa3f98b10a19372207H Hartley Sweeten	ret = comedi_alloc_subdevices(dev, n_subdevs);
8188b6c56949ffa83dbc2a6e8fa3f98b10a19372207H Hartley Sweeten	if (ret)
8198b6c56949ffa83dbc2a6e8fa3f98b10a19372207H Hartley Sweeten		return ret;
8206b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
8216b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	port = 0;
8226b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	asic = 0;
8236b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
8246b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		int byte_no;
8256b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
82668720ae68a94444387d56bc5a166396e33e420a5H Hartley Sweeten		s = &dev->subdevices[sdev_no];
8278099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten		subpriv = &devpriv->sprivs[sdev_no];
8288099a9841f1d9ff15de8f12cf1ba36b574d804c8H Hartley Sweeten		s->private = subpriv;
8296b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->maxdata = 1;
8306b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->range_table = &range_digital;
8316b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
8326b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->type = COMEDI_SUBD_DIO;
8336b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->insn_bits = pcmuio_dio_insn_bits;
8346b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->insn_config = pcmuio_dio_insn_config;
8356b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
8366b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		subpriv->intr.asic = -1;
8376b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		subpriv->intr.first_chan = -1;
8386b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		subpriv->intr.asic_chan = -1;
8396b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		subpriv->intr.num_asic_chans = -1;
8406b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		subpriv->intr.active = 0;
8416b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		s->len_chanlist = 1;
8426b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
8436b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		/* save the ioport address for each 'port' of 8 channels in the
8446b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		   subdevice */
8456b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
8466b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			if (port >= PORTS_PER_ASIC) {
8476b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				port = 0;
8486b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				++asic;
8496b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				thisasic_chanct = 0;
8506b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			}
8516b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			subpriv->iobases[byte_no] =
8526b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			    devpriv->asics[asic].iobase + port;
8536b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
8546b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			if (thisasic_chanct <
8556b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			    CHANS_PER_PORT * INTR_PORTS_PER_ASIC
8566b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			    && subpriv->intr.asic < 0) {
8576b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				/* this is an interrupt subdevice, so setup the struct */
8586b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				subpriv->intr.asic = asic;
8596b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				subpriv->intr.active = 0;
8606b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				subpriv->intr.stop_count = 0;
8616b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				subpriv->intr.first_chan = byte_no * 8;
8626b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				subpriv->intr.asic_chan = thisasic_chanct;
8636b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				subpriv->intr.num_asic_chans =
8646b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				    s->n_chan - subpriv->intr.first_chan;
8656b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				dev->read_subdev = s;
8666b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				s->subdev_flags |= SDF_CMD_READ;
8676b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				s->cancel = pcmuio_cancel;
8686b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				s->do_cmd = pcmuio_cmd;
8696b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				s->do_cmdtest = pcmuio_cmdtest;
8706b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				s->len_chanlist = subpriv->intr.num_asic_chans;
8716b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			}
8726b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			thisasic_chanct += CHANS_PER_PORT;
8736b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		}
8746b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		spin_lock_init(&subpriv->intr.spinlock);
8756b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
8766b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		chans_left -= s->n_chan;
8776b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
8786b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		if (!chans_left) {
8796b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			asic = 0;	/* reset the asic to our first asic, to do intr subdevs */
8806b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			port = 0;
8816b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		}
8826b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
8836b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	}
8846b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
8856b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	init_asics(dev);	/* clear out all the registers, basically */
8866b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
8876b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
8886b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		if (irq[asic]
8896b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		    && request_irq(irq[asic], interrupt_pcmuio,
890a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten				   IRQF_SHARED, board->name, dev)) {
8916b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			int i;
8926b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			/* unroll the allocated irqs.. */
8936b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			for (i = asic - 1; i >= 0; --i) {
8946b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				free_irq(irq[i], dev);
8956b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten				devpriv->asics[i].irq = irq[i] = 0;
8966b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			}
8976b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			irq[asic] = 0;
8986b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		}
8996b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		devpriv->asics[asic].irq = irq[asic];
9006b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	}
9016b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
9026b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	if (irq[0]) {
903f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott		dev_dbg(dev->class_dev, "irq: %u\n", irq[0]);
904a28b59957d3ad01481c2ea87aca50cfdb85417f2H Hartley Sweeten		if (irq[1] && board->num_asics == 2)
905f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott			dev_dbg(dev->class_dev, "second ASIC irq: %u\n",
906f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott				irq[1]);
9076b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	} else {
908f41ad6675f2d5705a0fc1e210af8eb4a27dbacb4Ian Abbott		dev_dbg(dev->class_dev, "(IRQ mode disabled)\n");
9096b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	}
9106b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
9116b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
9126b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	return 1;
9136b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten}
9146b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
915484ecc95d9cdfa8b2f7029e2f3409cf078aed4abH Hartley Sweetenstatic void pcmuio_detach(struct comedi_device *dev)
9166b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten{
9179a1a6cf8ae5ca58171e117335b9983e3cfa2185cH Hartley Sweeten	struct pcmuio_private *devpriv = dev->private;
9186b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	int i;
9196b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
9206b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	for (i = 0; i < MAX_ASICS; ++i) {
9216b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		if (devpriv->asics[i].irq)
9226b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten			free_irq(devpriv->asics[i].irq, dev);
9236b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	}
9246b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	if (devpriv && devpriv->sprivs)
9256b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		kfree(devpriv->sprivs);
926a32c6d0084992d3e58a93120c9ce9527e80c651eH Hartley Sweeten	comedi_legacy_detach(dev);
9276b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten}
9286b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
9296b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweetenstatic const struct pcmuio_board pcmuio_boards[] = {
9306b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	{
9316b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		.name		= "pcmuio48",
9326b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		.num_asics	= 1,
9336b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		.num_ports	= 6,
9346b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	}, {
9356b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		.name		= "pcmuio96",
9366b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		.num_asics	= 2,
9376b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten		.num_ports	= 12,
9386b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	},
9396b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten};
9406b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten
941294f930d98be86fb4f34302c718a49719650857fH Hartley Sweetenstatic struct comedi_driver pcmuio_driver = {
9426b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	.driver_name	= "pcmuio",
9436b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	.module		= THIS_MODULE,
9446b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	.attach		= pcmuio_attach,
9456b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	.detach		= pcmuio_detach,
9466b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	.board_name	= &pcmuio_boards[0].name,
9476b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	.offset		= sizeof(struct pcmuio_board),
9486b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten	.num_names	= ARRAY_SIZE(pcmuio_boards),
9496b19f9c6bee7afcd1e5dee9528333b2aa52de404H Hartley Sweeten};
950294f930d98be86fb4f34302c718a49719650857fH Hartley Sweetenmodule_comedi_driver(pcmuio_driver);
95190f703d30dd3e0c16ff80f35e34e511385a05ad5Arun Thomas
95290f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_AUTHOR("Comedi http://www.comedi.org");
95390f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_DESCRIPTION("Comedi low-level driver");
95490f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_LICENSE("GPL");
955