16baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
26baef150380d561a4d695a6be4fc509821c23611Calin Culianu    comedi/drivers/pcmmio.c
36baef150380d561a4d695a6be4fc509821c23611Calin Culianu    Driver for Winsystems PC-104 based multifunction IO board.
46baef150380d561a4d695a6be4fc509821c23611Calin Culianu
56baef150380d561a4d695a6be4fc509821c23611Calin Culianu    COMEDI - Linux Control and Measurement Device Interface
66baef150380d561a4d695a6be4fc509821c23611Calin Culianu    Copyright (C) 2007 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: pcmmio
246baef150380d561a4d695a6be4fc509821c23611Calin CulianuDescription: A driver for the PCM-MIO multifunction board
256baef150380d561a4d695a6be4fc509821c23611Calin CulianuDevices: [Winsystems] PCM-MIO (pcmmio)
266baef150380d561a4d695a6be4fc509821c23611Calin CulianuAuthor: Calin Culianu <calin@ajvar.org>
276baef150380d561a4d695a6be4fc509821c23611Calin CulianuUpdated: Wed, May 16 2007 16:21:10 -0500
286baef150380d561a4d695a6be4fc509821c23611Calin CulianuStatus: works
296baef150380d561a4d695a6be4fc509821c23611Calin Culianu
306baef150380d561a4d695a6be4fc509821c23611Calin CulianuA driver for the relatively new PCM-MIO multifunction board from
316baef150380d561a4d695a6be4fc509821c23611Calin CulianuWinsystems.  This board is a PC-104 based I/O board.  It contains
326baef150380d561a4d695a6be4fc509821c23611Calin Culianufour subdevices:
336baef150380d561a4d695a6be4fc509821c23611Calin Culianu  subdevice 0 - 16 channels of 16-bit AI
346baef150380d561a4d695a6be4fc509821c23611Calin Culianu  subdevice 1 - 8 channels of 16-bit AO
35d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson  subdevice 2 - first 24 channels of the 48 channel of DIO
36d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson	(with edge-triggered interrupt support)
37d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson  subdevice 3 - last 24 channels of the 48 channel DIO
38d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson	(no interrupt support for this bank of channels)
396baef150380d561a4d695a6be4fc509821c23611Calin Culianu
406baef150380d561a4d695a6be4fc509821c23611Calin Culianu  Some notes:
416baef150380d561a4d695a6be4fc509821c23611Calin Culianu
426baef150380d561a4d695a6be4fc509821c23611Calin Culianu  Synchronous reads and writes are the only things implemented for AI and AO,
436baef150380d561a4d695a6be4fc509821c23611Calin Culianu  even though the hardware itself can do streaming acquisition, etc.  Anyone
446baef150380d561a4d695a6be4fc509821c23611Calin Culianu  want to add asynchronous I/O for AI/AO as a feature?  Be my guest...
456baef150380d561a4d695a6be4fc509821c23611Calin Culianu
466baef150380d561a4d695a6be4fc509821c23611Calin Culianu  Asynchronous I/O for the DIO subdevices *is* implemented, however!  They are
476baef150380d561a4d695a6be4fc509821c23611Calin Culianu  basically edge-triggered interrupts for any configuration of the first
486baef150380d561a4d695a6be4fc509821c23611Calin Culianu  24 DIO-lines.
496baef150380d561a4d695a6be4fc509821c23611Calin Culianu
506baef150380d561a4d695a6be4fc509821c23611Calin Culianu  Also note that this interrupt support is untested.
516baef150380d561a4d695a6be4fc509821c23611Calin Culianu
526baef150380d561a4d695a6be4fc509821c23611Calin Culianu  A few words about edge-detection IRQ support (commands on DIO):
536baef150380d561a4d695a6be4fc509821c23611Calin Culianu
546baef150380d561a4d695a6be4fc509821c23611Calin Culianu  * To use edge-detection IRQ support for the DIO subdevice, pass the IRQ
556baef150380d561a4d695a6be4fc509821c23611Calin Culianu    of the board to the comedi_config command.  The board IRQ is not jumpered
566baef150380d561a4d695a6be4fc509821c23611Calin Culianu    but rather configured through software, so any IRQ from 1-15 is OK.
576baef150380d561a4d695a6be4fc509821c23611Calin Culianu
586baef150380d561a4d695a6be4fc509821c23611Calin Culianu  * Due to the genericity of the comedi API, you need to create a special
596baef150380d561a4d695a6be4fc509821c23611Calin Culianu    comedi_command in order to use edge-triggered interrupts for DIO.
606baef150380d561a4d695a6be4fc509821c23611Calin Culianu
616baef150380d561a4d695a6be4fc509821c23611Calin Culianu  * Use comedi_commands with TRIG_NOW.  Your callback will be called each
626baef150380d561a4d695a6be4fc509821c23611Calin Culianu    time an edge is detected on the specified DIO line(s), and the data
636baef150380d561a4d695a6be4fc509821c23611Calin Culianu    values will be two sample_t's, which should be concatenated to form
646baef150380d561a4d695a6be4fc509821c23611Calin Culianu    one 32-bit unsigned int.  This value is the mask of channels that had
656baef150380d561a4d695a6be4fc509821c23611Calin Culianu    edges detected from your channel list.  Note that the bits positions
666baef150380d561a4d695a6be4fc509821c23611Calin Culianu    in the mask correspond to positions in your chanlist when you
676baef150380d561a4d695a6be4fc509821c23611Calin Culianu    specified the command and *not* channel id's!
686baef150380d561a4d695a6be4fc509821c23611Calin Culianu
696baef150380d561a4d695a6be4fc509821c23611Calin Culianu *  To set the polarity of the edge-detection interrupts pass a nonzero value
706baef150380d561a4d695a6be4fc509821c23611Calin Culianu    for either CR_RANGE or CR_AREF for edge-up polarity, or a zero
716baef150380d561a4d695a6be4fc509821c23611Calin Culianu    value for both CR_RANGE and CR_AREF if you want edge-down polarity.
726baef150380d561a4d695a6be4fc509821c23611Calin Culianu
736baef150380d561a4d695a6be4fc509821c23611Calin CulianuConfiguration Options:
746baef150380d561a4d695a6be4fc509821c23611Calin Culianu  [0] - I/O port base address
75d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson  [1] - IRQ (optional -- for edge-detect interrupt support only,
76d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson	leave out if you don't need this feature)
776baef150380d561a4d695a6be4fc509821c23611Calin Culianu*/
786baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7925436dc9d84f1be60ff549c9ab712bba2835f284Greg Kroah-Hartman#include <linux/interrupt.h>
805a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
816baef150380d561a4d695a6be4fc509821c23611Calin Culianu#include "../comedidev.h"
820b8f754a6220158f2348bc6eae2772bc64bc98a2Bill Pemberton#include "pcm_common.h"
836baef150380d561a4d695a6be4fc509821c23611Calin Culianu#include <linux/pci.h>		/* for PCI devices */
846baef150380d561a4d695a6be4fc509821c23611Calin Culianu
856baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* This stuff is all from pcmuio.c -- it refers to the DIO subdevices only */
866baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define CHANS_PER_PORT   8
876baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PORTS_PER_ASIC   6
886baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define INTR_PORTS_PER_ASIC   3
896baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define MAX_CHANS_PER_SUBDEV 24	/* number of channels per comedi subdevice */
906baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PORTS_PER_SUBDEV (MAX_CHANS_PER_SUBDEV/CHANS_PER_PORT)
916baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define CHANS_PER_ASIC (CHANS_PER_PORT*PORTS_PER_ASIC)
926baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define INTR_CHANS_PER_ASIC 24
936baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC/CHANS_PER_PORT)
946baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define MAX_DIO_CHANS   (PORTS_PER_ASIC*1*CHANS_PER_PORT)
956baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define MAX_ASICS       (MAX_DIO_CHANS/CHANS_PER_ASIC)
966baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define SDEV_NO ((int)(s - dev->subdevices))
976baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define CALC_N_DIO_SUBDEVS(nchans) ((nchans)/MAX_CHANS_PER_SUBDEV + (!!((nchans)%MAX_CHANS_PER_SUBDEV)) /*+ (nchans > INTR_CHANS_PER_ASIC ? 2 : 1)*/)
986baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* IO Memory sizes */
996baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define ASIC_IOSIZE (0x0B)
1006baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PCMMIO48_IOSIZE ASIC_IOSIZE
1016baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1026baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* Some offsets - these are all in the 16byte IO memory offset from
1036baef150380d561a4d695a6be4fc509821c23611Calin Culianu   the base address.  Note that there is a paging scheme to swap out
1046baef150380d561a4d695a6be4fc509821c23611Calin Culianu   offsets 0x8-0xA using the PAGELOCK register.  See the table below.
1056baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1066baef150380d561a4d695a6be4fc509821c23611Calin Culianu  Register(s)       Pages        R/W?        Description
1076baef150380d561a4d695a6be4fc509821c23611Calin Culianu  --------------------------------------------------------------
1086baef150380d561a4d695a6be4fc509821c23611Calin Culianu  REG_PORTx         All          R/W         Read/Write/Configure IO
1096baef150380d561a4d695a6be4fc509821c23611Calin Culianu  REG_INT_PENDING   All          ReadOnly    Quickly see which INT_IDx has int.
1106baef150380d561a4d695a6be4fc509821c23611Calin Culianu  REG_PAGELOCK      All          WriteOnly   Select a page
1116baef150380d561a4d695a6be4fc509821c23611Calin Culianu  REG_POLx          Pg. 1 only   WriteOnly   Select edge-detection polarity
1126baef150380d561a4d695a6be4fc509821c23611Calin Culianu  REG_ENABx         Pg. 2 only   WriteOnly   Enable/Disable edge-detect. int.
1136baef150380d561a4d695a6be4fc509821c23611Calin Culianu  REG_INT_IDx       Pg. 3 only   R/W         See which ports/bits have ints.
1146baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
1156baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT0 0x0
1166baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT1 0x1
1176baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT2 0x2
1186baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT3 0x3
1196baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT4 0x4
1206baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PORT5 0x5
1216baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_INT_PENDING 0x6
122d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson#define REG_PAGELOCK 0x7	/*
123d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				 * page selector register, upper 2 bits select
124d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				 * a page and bits 0-5 are used to 'lock down'
125d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				 * a particular port above to make it readonly.
126d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				 */
1276baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_POL0 0x8
1286baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_POL1 0x9
1296baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_POL2 0xA
1306baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_ENAB0 0x8
1316baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_ENAB1 0x9
1326baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_ENAB2 0xA
1336baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_INT_ID0 0x8
1346baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_INT_ID1 0x9
1356baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_INT_ID2 0xA
1366baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1376baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define NUM_PAGED_REGS 3
1386baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define NUM_PAGES 4
1396baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define FIRST_PAGED_REG 0x8
1406baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PAGE_BITOFFSET 6
1416baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_LOCK_BITOFFSET 0
1426baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define REG_PAGE_MASK (~((0x1<<REG_PAGE_BITOFFSET)-1))
143d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson#define REG_LOCK_MASK (~(REG_PAGE_MASK))
1446baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PAGE_POL 1
1456baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PAGE_ENAB 2
1466baef150380d561a4d695a6be4fc509821c23611Calin Culianu#define PAGE_INT_ID 3
1476baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1480a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int ai_rinsn(struct comedi_device *, struct comedi_subdevice *,
1490a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    struct comedi_insn *, unsigned int *);
1500a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int ao_rinsn(struct comedi_device *, struct comedi_subdevice *,
1510a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    struct comedi_insn *, unsigned int *);
1520a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int ao_winsn(struct comedi_device *, struct comedi_subdevice *,
1530a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    struct comedi_insn *, unsigned int *);
1546baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1556baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
1566baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Board descriptions for two imaginary boards.  Describing the
1576baef150380d561a4d695a6be4fc509821c23611Calin Culianu * boards in this way is optional, and completely driver-dependent.
1586baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Some drivers use arrays such as this, other do not.
1596baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
160657f81ec27758ddb859ea9c74929996bea607194Bill Pembertonstruct pcmmio_board {
1616baef150380d561a4d695a6be4fc509821c23611Calin Culianu	const char *name;
1626baef150380d561a4d695a6be4fc509821c23611Calin Culianu	const int dio_num_asics;
1636baef150380d561a4d695a6be4fc509821c23611Calin Culianu	const int dio_num_ports;
1646baef150380d561a4d695a6be4fc509821c23611Calin Culianu	const int total_iosize;
1656baef150380d561a4d695a6be4fc509821c23611Calin Culianu	const int ai_bits;
1666baef150380d561a4d695a6be4fc509821c23611Calin Culianu	const int ao_bits;
1676baef150380d561a4d695a6be4fc509821c23611Calin Culianu	const int n_ai_chans;
1686baef150380d561a4d695a6be4fc509821c23611Calin Culianu	const int n_ao_chans;
1699ced1de69125b60f40127eddaa3be2a92bb0a1dfBill Pemberton	const struct comedi_lrange *ai_range_table, *ao_range_table;
17056b8421ceef7f2dae95b882034ebf6958bad58f6Arun Thomas	int (*ai_rinsn) (struct comedi_device *dev,
17156b8421ceef7f2dae95b882034ebf6958bad58f6Arun Thomas			struct comedi_subdevice *s,
17256b8421ceef7f2dae95b882034ebf6958bad58f6Arun Thomas			struct comedi_insn *insn,
17356b8421ceef7f2dae95b882034ebf6958bad58f6Arun Thomas			unsigned int *data);
17456b8421ceef7f2dae95b882034ebf6958bad58f6Arun Thomas	int (*ao_rinsn) (struct comedi_device *dev,
17556b8421ceef7f2dae95b882034ebf6958bad58f6Arun Thomas			struct comedi_subdevice *s,
17656b8421ceef7f2dae95b882034ebf6958bad58f6Arun Thomas			struct comedi_insn *insn,
17756b8421ceef7f2dae95b882034ebf6958bad58f6Arun Thomas			unsigned int *data);
17856b8421ceef7f2dae95b882034ebf6958bad58f6Arun Thomas	int (*ao_winsn) (struct comedi_device *dev,
17956b8421ceef7f2dae95b882034ebf6958bad58f6Arun Thomas			struct comedi_subdevice *s,
18056b8421ceef7f2dae95b882034ebf6958bad58f6Arun Thomas			struct comedi_insn *insn,
18156b8421ceef7f2dae95b882034ebf6958bad58f6Arun Thomas			unsigned int *data);
182657f81ec27758ddb859ea9c74929996bea607194Bill Pemberton};
1836baef150380d561a4d695a6be4fc509821c23611Calin Culianu
184d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnsonstatic const struct comedi_lrange ranges_ai = {
185d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson	4, {RANGE(-5., 5.), RANGE(-10., 10.), RANGE(0., 5.), RANGE(0., 10.)}
1866baef150380d561a4d695a6be4fc509821c23611Calin Culianu};
1876baef150380d561a4d695a6be4fc509821c23611Calin Culianu
188d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnsonstatic const struct comedi_lrange ranges_ao = {
189d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson	6, {RANGE(0., 5.), RANGE(0., 10.), RANGE(-5., 5.), RANGE(-10., 10.),
1900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	  RANGE(-2.5, 2.5), RANGE(-2.5, 7.5)}
1916baef150380d561a4d695a6be4fc509821c23611Calin Culianu};
1926baef150380d561a4d695a6be4fc509821c23611Calin Culianu
193657f81ec27758ddb859ea9c74929996bea607194Bill Pembertonstatic const struct pcmmio_board pcmmio_boards[] = {
1946baef150380d561a4d695a6be4fc509821c23611Calin Culianu	{
1950a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .name = "pcmmio",
1960a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .dio_num_asics = 1,
1970a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .dio_num_ports = 6,
1980a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .total_iosize = 32,
1990a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_bits = 16,
2000a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ao_bits = 16,
2010a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .n_ai_chans = 16,
2020a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .n_ao_chans = 8,
2030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_range_table = &ranges_ai,
2040a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ao_range_table = &ranges_ao,
2050a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_rinsn = ai_rinsn,
2060a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ao_rinsn = ao_rinsn,
2070a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ao_winsn = ao_winsn},
2086baef150380d561a4d695a6be4fc509821c23611Calin Culianu};
2096baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2106baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
2116baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Useful for shorthand access to the particular board structure
2126baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
213657f81ec27758ddb859ea9c74929996bea607194Bill Pemberton#define thisboard ((const struct pcmmio_board *)dev->board_ptr)
2146baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2156baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* this structure is for data unique to this subdevice.  */
2164467df9406bc40fdbc9cf64cfb2e95cba8f77e1eBill Pembertonstruct pcmmio_subdev_private {
2176baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2186baef150380d561a4d695a6be4fc509821c23611Calin Culianu	union {
219d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson		/* for DIO: mapping of halfwords (bytes)
220d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson		   in port/chanarray to iobase */
2216baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned long iobases[PORTS_PER_SUBDEV];
2226baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2236baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* for AI/AO */
2246baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned long iobase;
2256baef150380d561a4d695a6be4fc509821c23611Calin Culianu	};
2266baef150380d561a4d695a6be4fc509821c23611Calin Culianu	union {
2276baef150380d561a4d695a6be4fc509821c23611Calin Culianu		struct {
2286baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2296baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* The below is only used for intr subdevices */
2306baef150380d561a4d695a6be4fc509821c23611Calin Culianu			struct {
231d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				/*
232d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				 * if non-negative, this subdev has an
233d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				 * interrupt asic
234d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				 */
235d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				int asic;
236d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				/*
237d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				 * if nonnegative, the first channel id for
238d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				 * interrupts.
239d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				 */
240d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				int first_chan;
241d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				/*
242d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				 * the number of asic channels in this subdev
243d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				 * that have interrutps
244d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				 */
245d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				int num_asic_chans;
246d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				/*
247d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				 * if nonnegative, the first channel id with
248d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				 * respect to the asic that has interrupts
249d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				 */
250d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				int asic_chan;
251d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				/*
252d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				 * subdev-relative channel mask for channels
253d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				 * we are interested in
254d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				 */
255d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				int enabled_mask;
2566baef150380d561a4d695a6be4fc509821c23611Calin Culianu				int active;
2576baef150380d561a4d695a6be4fc509821c23611Calin Culianu				int stop_count;
2586baef150380d561a4d695a6be4fc509821c23611Calin Culianu				int continuous;
2596baef150380d561a4d695a6be4fc509821c23611Calin Culianu				spinlock_t spinlock;
2606baef150380d561a4d695a6be4fc509821c23611Calin Culianu			} intr;
2616baef150380d561a4d695a6be4fc509821c23611Calin Culianu		} dio;
2626baef150380d561a4d695a6be4fc509821c23611Calin Culianu		struct {
263d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson			/* the last unsigned int data written */
264d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson			unsigned int shadow_samples[8];
2656baef150380d561a4d695a6be4fc509821c23611Calin Culianu		} ao;
2666baef150380d561a4d695a6be4fc509821c23611Calin Culianu	};
2674467df9406bc40fdbc9cf64cfb2e95cba8f77e1eBill Pemberton};
2686baef150380d561a4d695a6be4fc509821c23611Calin Culianu
269d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson/*
270d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson * this structure is for data unique to this hardware driver.  If
271d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson * several hardware drivers keep similar information in this structure,
272d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson * feel free to suggest moving the variable to the struct comedi_device struct.
273d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson */
274e56ab7156f5f4918eb89a19b3061de1a7fe69354Bill Pembertonstruct pcmmio_private {
2756baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* stuff for DIO */
2766baef150380d561a4d695a6be4fc509821c23611Calin Culianu	struct {
2776baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned char pagelock;	/* current page and lock */
278d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson		/* shadow of POLx registers */
279d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson		unsigned char pol[NUM_PAGED_REGS];
280d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson		/* shadow of ENABx registers */
281d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson		unsigned char enab[NUM_PAGED_REGS];
2826baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int num;
2836baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned long iobase;
2846baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned int irq;
2856baef150380d561a4d695a6be4fc509821c23611Calin Culianu		spinlock_t spinlock;
2866baef150380d561a4d695a6be4fc509821c23611Calin Culianu	} asics[MAX_ASICS];
2874467df9406bc40fdbc9cf64cfb2e95cba8f77e1eBill Pemberton	struct pcmmio_subdev_private *sprivs;
288e56ab7156f5f4918eb89a19b3061de1a7fe69354Bill Pemberton};
2896baef150380d561a4d695a6be4fc509821c23611Calin Culianu
2906baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
2916baef150380d561a4d695a6be4fc509821c23611Calin Culianu * most drivers define the following macro to make it easy to
2926baef150380d561a4d695a6be4fc509821c23611Calin Culianu * access the private structure.
2936baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
294e56ab7156f5f4918eb89a19b3061de1a7fe69354Bill Pemberton#define devpriv ((struct pcmmio_private *)dev->private)
2954467df9406bc40fdbc9cf64cfb2e95cba8f77e1eBill Pemberton#define subpriv ((struct pcmmio_subdev_private *)s->private)
2966baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
297139dfbdfacb02e3ef3df936d2fabd1ad5f14ea88Bill Pemberton * The struct comedi_driver structure tells the Comedi core module
2986baef150380d561a4d695a6be4fc509821c23611Calin Culianu * which functions to call to configure/deconfigure (attach/detach)
2996baef150380d561a4d695a6be4fc509821c23611Calin Culianu * the board, and also about the kernel module that contains
3006baef150380d561a4d695a6be4fc509821c23611Calin Culianu * the device code.
3016baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
3020a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcmmio_attach(struct comedi_device *dev,
3030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 struct comedi_devconfig *it);
304da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcmmio_detach(struct comedi_device *dev);
3056baef150380d561a4d695a6be4fc509821c23611Calin Culianu
306139dfbdfacb02e3ef3df936d2fabd1ad5f14ea88Bill Pembertonstatic struct comedi_driver driver = {
30768c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.driver_name = "pcmmio",
30868c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.module = THIS_MODULE,
30968c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.attach = pcmmio_attach,
31068c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.detach = pcmmio_detach,
3116baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* It is not necessary to implement the following members if you are
3126baef150380d561a4d695a6be4fc509821c23611Calin Culianu * writing a driver for a ISA PnP or PCI card */
3136baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* Most drivers will support multiple types of boards by
3146baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * having an array of board structures.  These were defined
3156baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * in pcmmio_boards[] above.  Note that the element 'name'
3166baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * was first in the structure -- Comedi uses this fact to
3176baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * extract the name of the board without knowing any details
3186baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * about the structure except for its length.
3196baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * When a device is attached (by comedi_config), the name
3206baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * of the device is given to Comedi, and Comedi tries to
3216baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * match it by going through the list of board names.  If
3226baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * there is a match, the address of the pointer is put
3236baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * into dev->board_ptr and driver->attach() is called.
3246baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 *
3256baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * Note that these are not necessary if you can determine
3266baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * the type of board in software.  ISA PnP, PCI, and PCMCIA
3276baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * devices are such boards.
3286baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 */
32968c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.board_name = &pcmmio_boards[0].name,
33068c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.offset = sizeof(struct pcmmio_board),
3318629efa4cbf6f89a54a85af4b8bc31762af01800Bill Pemberton	.num_names = ARRAY_SIZE(pcmmio_boards),
3326baef150380d561a4d695a6be4fc509821c23611Calin Culianu};
3336baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3340a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcmmio_dio_insn_bits(struct comedi_device *dev,
3350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				struct comedi_subdevice *s,
3360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				struct comedi_insn *insn, unsigned int *data);
3370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcmmio_dio_insn_config(struct comedi_device *dev,
3380a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  struct comedi_subdevice *s,
3390a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  struct comedi_insn *insn, unsigned int *data);
3406baef150380d561a4d695a6be4fc509821c23611Calin Culianu
34170265d24e3404fe798b6edd55a02016b1edb49d7Jiri Slabystatic irqreturn_t interrupt_pcmmio(int irq, void *d);
34234c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pembertonstatic void pcmmio_stop_intr(struct comedi_device *, struct comedi_subdevice *);
343814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
344814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
345814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic int pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
3460a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			  struct comedi_cmd *cmd);
3476baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3486baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* some helper functions to deal with specifics of this device's registers */
349d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson/* sets up/clears ASIC chips to defaults */
350d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnsonstatic void init_asics(struct comedi_device *dev);
351814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic void switch_page(struct comedi_device *dev, int asic, int page);
3526baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef notused
353814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic void lock_port(struct comedi_device *dev, int asic, int port);
354814900c904140cfe7f3e48cabec06b3eec57e0eaBill Pembertonstatic void unlock_port(struct comedi_device *dev, int asic, int port);
3556baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif
3566baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3576baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
3586baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Attach is called by the Comedi core to configure the driver
3596baef150380d561a4d695a6be4fc509821c23611Calin Culianu * for a particular board.  If you specified a board_name array
3606baef150380d561a4d695a6be4fc509821c23611Calin Culianu * in the driver structure, dev->board_ptr contains that
3616baef150380d561a4d695a6be4fc509821c23611Calin Culianu * address.
3626baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
363da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
3646baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
36534c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
3666baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic,
3670a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    thisasic_chanct = 0;
3686baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long iobase;
3696baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned int irq[MAX_ASICS];
3706baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3716baef150380d561a4d695a6be4fc509821c23611Calin Culianu	iobase = it->options[0];
3726baef150380d561a4d695a6be4fc509821c23611Calin Culianu	irq[0] = it->options[1];
3736baef150380d561a4d695a6be4fc509821c23611Calin Culianu
374cf5682788f2cc35643f0bc1898646e2cff4af7f3Johannes Thumshirn	printk(KERN_INFO "comedi%d: %s: io: %lx attaching...\n", dev->minor,
375cf5682788f2cc35643f0bc1898646e2cff4af7f3Johannes Thumshirn			driver.driver_name, iobase);
3766baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3776baef150380d561a4d695a6be4fc509821c23611Calin Culianu	dev->iobase = iobase;
3786baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3796baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (!iobase || !request_region(iobase,
3800a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				       thisboard->total_iosize,
3810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				       driver.driver_name)) {
382cf5682788f2cc35643f0bc1898646e2cff4af7f3Johannes Thumshirn		printk(KERN_ERR "comedi%d: I/O port conflict\n", dev->minor);
3836baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return -EIO;
3846baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
3856baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3866baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
3876baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Initialize dev->board_name.  Note that we can use the "thisboard"
3886baef150380d561a4d695a6be4fc509821c23611Calin Culianu * macro now, since we just initialized it in the last line.
3896baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
3906baef150380d561a4d695a6be4fc509821c23611Calin Culianu	dev->board_name = thisboard->name;
3916baef150380d561a4d695a6be4fc509821c23611Calin Culianu
3926baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
3936baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Allocate the private structure area.  alloc_private() is a
3946baef150380d561a4d695a6be4fc509821c23611Calin Culianu * convenient macro defined in comedidev.h.
3956baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
396e56ab7156f5f4918eb89a19b3061de1a7fe69354Bill Pemberton	if (alloc_private(dev, sizeof(struct pcmmio_private)) < 0) {
397cf5682788f2cc35643f0bc1898646e2cff4af7f3Johannes Thumshirn		printk(KERN_ERR "comedi%d: cannot allocate private data structure\n",
398cf5682788f2cc35643f0bc1898646e2cff4af7f3Johannes Thumshirn				dev->minor);
3996baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return -ENOMEM;
4006baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
4016baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4026baef150380d561a4d695a6be4fc509821c23611Calin Culianu	for (asic = 0; asic < MAX_ASICS; ++asic) {
4036baef150380d561a4d695a6be4fc509821c23611Calin Culianu		devpriv->asics[asic].num = asic;
4046baef150380d561a4d695a6be4fc509821c23611Calin Culianu		devpriv->asics[asic].iobase =
4050a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    dev->iobase + 16 + asic * ASIC_IOSIZE;
406d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson		/*
407d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson		 * this gets actually set at the end of this function when we
408d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson		 * request_irqs
409d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson		 */
410d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson		devpriv->asics[asic].irq = 0;
4116baef150380d561a4d695a6be4fc509821c23611Calin Culianu		spin_lock_init(&devpriv->asics[asic].spinlock);
4126baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
4136baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4146baef150380d561a4d695a6be4fc509821c23611Calin Culianu	chans_left = CHANS_PER_ASIC * thisboard->dio_num_asics;
4156baef150380d561a4d695a6be4fc509821c23611Calin Culianu	n_dio_subdevs = CALC_N_DIO_SUBDEVS(chans_left);
4166baef150380d561a4d695a6be4fc509821c23611Calin Culianu	n_subdevs = n_dio_subdevs + 2;
4176baef150380d561a4d695a6be4fc509821c23611Calin Culianu	devpriv->sprivs =
4180a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    kcalloc(n_subdevs, sizeof(struct pcmmio_subdev_private),
4190a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    GFP_KERNEL);
4206baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (!devpriv->sprivs) {
421cf5682788f2cc35643f0bc1898646e2cff4af7f3Johannes Thumshirn		printk(KERN_ERR "comedi%d: cannot allocate subdevice private data structures\n",
422cf5682788f2cc35643f0bc1898646e2cff4af7f3Johannes Thumshirn				dev->minor);
4236baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return -ENOMEM;
4246baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
4256baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/*
4266baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * Allocate the subdevice structures.  alloc_subdevice() is a
4276baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * convenient macro defined in comedidev.h.
4286baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 *
4296baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * Allocate 1 AI + 1 AO + 2 DIO subdevs (24 lines per DIO)
4306baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 */
4316baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (alloc_subdevices(dev, n_subdevs) < 0) {
432cf5682788f2cc35643f0bc1898646e2cff4af7f3Johannes Thumshirn		printk(KERN_ERR "comedi%d: cannot allocate subdevice data structures\n",
433cf5682788f2cc35643f0bc1898646e2cff4af7f3Johannes Thumshirn				dev->minor);
4346baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return -ENOMEM;
4356baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
4366baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4376baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* First, AI */
4386baef150380d561a4d695a6be4fc509821c23611Calin Culianu	sdev_no = 0;
4396baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s = dev->subdevices + sdev_no;
4406baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s->private = devpriv->sprivs + sdev_no;
4416baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s->maxdata = (1 << thisboard->ai_bits) - 1;
4426baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s->range_table = thisboard->ai_range_table;
4436baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
4446baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s->type = COMEDI_SUBD_AI;
4456baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s->n_chan = thisboard->n_ai_chans;
4466baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s->len_chanlist = s->n_chan;
4476baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s->insn_read = thisboard->ai_rinsn;
4486baef150380d561a4d695a6be4fc509821c23611Calin Culianu	subpriv->iobase = dev->iobase + 0;
4496baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* initialize the resource enable register by clearing it */
4506baef150380d561a4d695a6be4fc509821c23611Calin Culianu	outb(0, subpriv->iobase + 3);
4516baef150380d561a4d695a6be4fc509821c23611Calin Culianu	outb(0, subpriv->iobase + 4 + 3);
4526baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4536baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* Next, AO */
4546baef150380d561a4d695a6be4fc509821c23611Calin Culianu	++sdev_no;
4556baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s = dev->subdevices + sdev_no;
4566baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s->private = devpriv->sprivs + sdev_no;
4576baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s->maxdata = (1 << thisboard->ao_bits) - 1;
4586baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s->range_table = thisboard->ao_range_table;
4596baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s->subdev_flags = SDF_READABLE;
4606baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s->type = COMEDI_SUBD_AO;
4616baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s->n_chan = thisboard->n_ao_chans;
4626baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s->len_chanlist = s->n_chan;
4636baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s->insn_read = thisboard->ao_rinsn;
4646baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s->insn_write = thisboard->ao_winsn;
4656baef150380d561a4d695a6be4fc509821c23611Calin Culianu	subpriv->iobase = dev->iobase + 8;
4666baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* initialize the resource enable register by clearing it */
4676baef150380d561a4d695a6be4fc509821c23611Calin Culianu	outb(0, subpriv->iobase + 3);
4686baef150380d561a4d695a6be4fc509821c23611Calin Culianu	outb(0, subpriv->iobase + 4 + 3);
4696baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4706baef150380d561a4d695a6be4fc509821c23611Calin Culianu	++sdev_no;
4716baef150380d561a4d695a6be4fc509821c23611Calin Culianu	port = 0;
4726baef150380d561a4d695a6be4fc509821c23611Calin Culianu	asic = 0;
4736baef150380d561a4d695a6be4fc509821c23611Calin Culianu	for (; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
4746baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int byte_no;
4756baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4766baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s = dev->subdevices + sdev_no;
4776baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->private = devpriv->sprivs + sdev_no;
4786baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->maxdata = 1;
4796baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->range_table = &range_digital;
4806baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
4816baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->type = COMEDI_SUBD_DIO;
4826baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->insn_bits = pcmmio_dio_insn_bits;
4836baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->insn_config = pcmmio_dio_insn_config;
484214e7b5c8281bf41238f575128e4fec5652ed797Bill Pemberton		s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
4856baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->dio.intr.asic = -1;
4866baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->dio.intr.first_chan = -1;
4876baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->dio.intr.asic_chan = -1;
4886baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->dio.intr.num_asic_chans = -1;
4896baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->dio.intr.active = 0;
4906baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->len_chanlist = 1;
4916baef150380d561a4d695a6be4fc509821c23611Calin Culianu
4926baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* save the ioport address for each 'port' of 8 channels in the
4936baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   subdevice */
4946baef150380d561a4d695a6be4fc509821c23611Calin Culianu		for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
4956baef150380d561a4d695a6be4fc509821c23611Calin Culianu			if (port >= PORTS_PER_ASIC) {
4966baef150380d561a4d695a6be4fc509821c23611Calin Culianu				port = 0;
4976baef150380d561a4d695a6be4fc509821c23611Calin Culianu				++asic;
4986baef150380d561a4d695a6be4fc509821c23611Calin Culianu				thisasic_chanct = 0;
4996baef150380d561a4d695a6be4fc509821c23611Calin Culianu			}
5006baef150380d561a4d695a6be4fc509821c23611Calin Culianu			subpriv->iobases[byte_no] =
5010a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    devpriv->asics[asic].iobase + port;
5026baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5036baef150380d561a4d695a6be4fc509821c23611Calin Culianu			if (thisasic_chanct <
5040a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    CHANS_PER_PORT * INTR_PORTS_PER_ASIC
5050a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    && subpriv->dio.intr.asic < 0) {
506d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				/*
507d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				 * this is an interrupt subdevice,
508d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				 * so setup the struct
509d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				 */
5106baef150380d561a4d695a6be4fc509821c23611Calin Culianu				subpriv->dio.intr.asic = asic;
5116baef150380d561a4d695a6be4fc509821c23611Calin Culianu				subpriv->dio.intr.active = 0;
5126baef150380d561a4d695a6be4fc509821c23611Calin Culianu				subpriv->dio.intr.stop_count = 0;
5136baef150380d561a4d695a6be4fc509821c23611Calin Culianu				subpriv->dio.intr.first_chan = byte_no * 8;
5146baef150380d561a4d695a6be4fc509821c23611Calin Culianu				subpriv->dio.intr.asic_chan = thisasic_chanct;
5156baef150380d561a4d695a6be4fc509821c23611Calin Culianu				subpriv->dio.intr.num_asic_chans =
5160a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    s->n_chan - subpriv->dio.intr.first_chan;
5176baef150380d561a4d695a6be4fc509821c23611Calin Culianu				s->cancel = pcmmio_cancel;
5186baef150380d561a4d695a6be4fc509821c23611Calin Culianu				s->do_cmd = pcmmio_cmd;
5196baef150380d561a4d695a6be4fc509821c23611Calin Culianu				s->do_cmdtest = pcmmio_cmdtest;
5206baef150380d561a4d695a6be4fc509821c23611Calin Culianu				s->len_chanlist =
5210a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    subpriv->dio.intr.num_asic_chans;
5226baef150380d561a4d695a6be4fc509821c23611Calin Culianu			}
5236baef150380d561a4d695a6be4fc509821c23611Calin Culianu			thisasic_chanct += CHANS_PER_PORT;
5246baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
5256baef150380d561a4d695a6be4fc509821c23611Calin Culianu		spin_lock_init(&subpriv->dio.intr.spinlock);
5266baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5276baef150380d561a4d695a6be4fc509821c23611Calin Culianu		chans_left -= s->n_chan;
5286baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5296baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (!chans_left) {
530d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson			/*
531d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson			 * reset the asic to our first asic,
532d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson			 * to do intr subdevs
533d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson			 */
534d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson			asic = 0;
5356baef150380d561a4d695a6be4fc509821c23611Calin Culianu			port = 0;
5366baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
5376baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5386baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
5396baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5406baef150380d561a4d695a6be4fc509821c23611Calin Culianu	init_asics(dev);	/* clear out all the registers, basically */
5416baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5426baef150380d561a4d695a6be4fc509821c23611Calin Culianu	for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
5436baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (irq[asic]
5440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    && request_irq(irq[asic], interrupt_pcmmio,
5450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				   IRQF_SHARED, thisboard->name, dev)) {
5466baef150380d561a4d695a6be4fc509821c23611Calin Culianu			int i;
5476baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* unroll the allocated irqs.. */
5486baef150380d561a4d695a6be4fc509821c23611Calin Culianu			for (i = asic - 1; i >= 0; --i) {
5495f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman				free_irq(irq[i], dev);
5506baef150380d561a4d695a6be4fc509821c23611Calin Culianu				devpriv->asics[i].irq = irq[i] = 0;
5516baef150380d561a4d695a6be4fc509821c23611Calin Culianu			}
5526baef150380d561a4d695a6be4fc509821c23611Calin Culianu			irq[asic] = 0;
5536baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
5546baef150380d561a4d695a6be4fc509821c23611Calin Culianu		devpriv->asics[asic].irq = irq[asic];
5556baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
5566baef150380d561a4d695a6be4fc509821c23611Calin Culianu
557d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson	dev->irq = irq[0];	/*
558d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				 * grr.. wish comedi dev struct supported
559d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				 * multiple irqs..
560d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson				 */
5616baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5626baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (irq[0]) {
563cf5682788f2cc35643f0bc1898646e2cff4af7f3Johannes Thumshirn		printk(KERN_DEBUG "comedi%d: irq: %u\n", dev->minor, irq[0]);
5644b2ba24399cfcd7c80a20cd3bbedc5df0ebd4345Dan Carpenter		if (thisboard->dio_num_asics == 2 && irq[1])
565cf5682788f2cc35643f0bc1898646e2cff4af7f3Johannes Thumshirn			printk(KERN_DEBUG "comedi%d: second ASIC irq: %u\n",
566cf5682788f2cc35643f0bc1898646e2cff4af7f3Johannes Thumshirn					dev->minor, irq[1]);
5676baef150380d561a4d695a6be4fc509821c23611Calin Culianu	} else {
568cf5682788f2cc35643f0bc1898646e2cff4af7f3Johannes Thumshirn		printk(KERN_INFO "comedi%d: (IRQ mode disabled)\n", dev->minor);
5696baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
5706baef150380d561a4d695a6be4fc509821c23611Calin Culianu
571cf5682788f2cc35643f0bc1898646e2cff4af7f3Johannes Thumshirn	printk(KERN_INFO "comedi%d: attached\n", dev->minor);
5726baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5736baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 1;
5746baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
5756baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5766baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
5776baef150380d561a4d695a6be4fc509821c23611Calin Culianu * _detach is called to deconfigure a device.  It should deallocate
5786baef150380d561a4d695a6be4fc509821c23611Calin Culianu * resources.
5796baef150380d561a4d695a6be4fc509821c23611Calin Culianu * This function is also called when _attach() fails, so it should be
5806baef150380d561a4d695a6be4fc509821c23611Calin Culianu * careful not to release resources that were not necessarily
5816baef150380d561a4d695a6be4fc509821c23611Calin Culianu * allocated by _attach().  dev->private and dev->subdevices are
5826baef150380d561a4d695a6be4fc509821c23611Calin Culianu * deallocated automatically by the core.
5836baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
584da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcmmio_detach(struct comedi_device *dev)
5856baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
5866baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int i;
5876baef150380d561a4d695a6be4fc509821c23611Calin Culianu
588bcd9a1e91fbc293bbbbddd98df687ad2e8027c89Johannes Thumshirn	printk(KERN_INFO "comedi%d: %s: remove\n", dev->minor, driver.driver_name);
5896baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (dev->iobase)
5906baef150380d561a4d695a6be4fc509821c23611Calin Culianu		release_region(dev->iobase, thisboard->total_iosize);
5916baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5926baef150380d561a4d695a6be4fc509821c23611Calin Culianu	for (i = 0; i < MAX_ASICS; ++i) {
5936baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (devpriv && devpriv->asics[i].irq)
5945f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman			free_irq(devpriv->asics[i].irq, dev);
5956baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
5966baef150380d561a4d695a6be4fc509821c23611Calin Culianu
5976baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (devpriv && devpriv->sprivs)
5986baef150380d561a4d695a6be4fc509821c23611Calin Culianu		kfree(devpriv->sprivs);
5996baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6006baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 0;
6016baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
6026baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6036baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* DIO devices are slightly special.  Although it is possible to
6046baef150380d561a4d695a6be4fc509821c23611Calin Culianu * implement the insn_read/insn_write interface, it is much more
6056baef150380d561a4d695a6be4fc509821c23611Calin Culianu * useful to applications if you implement the insn_bits interface.
6066baef150380d561a4d695a6be4fc509821c23611Calin Culianu * This allows packed reading/writing of the DIO channels.  The
6076baef150380d561a4d695a6be4fc509821c23611Calin Culianu * comedi core can convert between insn_bits and insn_read/write */
6080a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcmmio_dio_insn_bits(struct comedi_device *dev,
6090a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				struct comedi_subdevice *s,
6100a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				struct comedi_insn *insn, unsigned int *data)
6116baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
6126baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int byte_no;
6136baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (insn->n != 2)
6146baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return -EINVAL;
6156baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6166baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* NOTE:
6176baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   reading a 0 means this channel was high
6186baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   writine a 0 sets the channel high
6196baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   reading a 1 means this channel was low
6206baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   writing a 1 means set this channel low
6216baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6226baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   Therefore everything is always inverted. */
6236baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6246baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* The insn data is a mask in data[0] and the new data
6256baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 * in data[1], each channel cooresponding to a bit. */
6266baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6276baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef DAMMIT_ITS_BROKEN
6286baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* DEBUG */
629bcd9a1e91fbc293bbbbddd98df687ad2e8027c89Johannes Thumshirn	printk(KERN_DEBUG "write mask: %08x  data: %08x\n", data[0], data[1]);
6306baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif
6316baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6326baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s->state = 0;
6336baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6346baef150380d561a4d695a6be4fc509821c23611Calin Culianu	for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) {
6356baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* address of 8-bit port */
6366baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned long ioaddr = subpriv->iobases[byte_no],
6370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    /* bit offset of port in 32-bit doubleword */
6380a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    offset = byte_no * 8;
6396baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* this 8-bit port's data */
6406baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned char byte = 0,
6410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    /* The write mask for this port (if any) */
6420a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    write_mask_byte = (data[0] >> offset) & 0xff,
6430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    /* The data byte for this port */
6440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    data_byte = (data[1] >> offset) & 0xff;
6456baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6466baef150380d561a4d695a6be4fc509821c23611Calin Culianu		byte = inb(ioaddr);	/* read all 8-bits for this port */
6476baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6486baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef DAMMIT_ITS_BROKEN
6496baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* DEBUG */
6500a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		printk
651bcd9a1e91fbc293bbbbddd98df687ad2e8027c89Johannes Thumshirn		    (KERN_DEBUG "byte %d wmb %02x db %02x offset %02d io %04x,"
652bcd9a1e91fbc293bbbbddd98df687ad2e8027c89Johannes Thumshirn		     " data_in %02x ", byte_no, (unsigned)write_mask_byte,
653bcd9a1e91fbc293bbbbddd98df687ad2e8027c89Johannes Thumshirn		     (unsigned)data_byte, offset, ioaddr, (unsigned)byte);
6546baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif
6556baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6566baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (write_mask_byte) {
657d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson			/*
658d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson			 * this byte has some write_bits
659d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson			 * -- so set the output lines
660d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson			 */
661d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson			/* clear bits for write mask */
662d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson			byte &= ~write_mask_byte;
663d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson			/* set to inverted data_byte */
664d2d08955e77a84a0a022dfa9e6f4b4b6c6773281Daniel Patrick Johnson			byte |= ~data_byte & write_mask_byte;
6656baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* Write out the new digital output state */
6666baef150380d561a4d695a6be4fc509821c23611Calin Culianu			outb(byte, ioaddr);
6676baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
6686baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef DAMMIT_ITS_BROKEN
6696baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* DEBUG */
670cf5682788f2cc35643f0bc1898646e2cff4af7f3Johannes Thumshirn		printk("data_out_byte %02x\n", (unsigned)byte);
6716baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif
6726baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* save the digital input lines for this byte.. */
6736baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->state |= ((unsigned int)byte) << offset;
6746baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
6756baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6766baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* now return the DIO lines to data[1] - note they came inverted! */
6776baef150380d561a4d695a6be4fc509821c23611Calin Culianu	data[1] = ~s->state;
6786baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6796baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef DAMMIT_ITS_BROKEN
6806baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* DEBUG */
681bcd9a1e91fbc293bbbbddd98df687ad2e8027c89Johannes Thumshirn	printk(KERN_DEBUG "s->state %08x data_out %08x\n", s->state, data[1]);
6826baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif
6836baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6846baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 2;
6856baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
6866baef150380d561a4d695a6be4fc509821c23611Calin Culianu
6876baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* The input or output configuration of each digital line is
6886baef150380d561a4d695a6be4fc509821c23611Calin Culianu * configured by a special insn_config instruction.  chanspec
6896baef150380d561a4d695a6be4fc509821c23611Calin Culianu * contains the channel to be changed, and data[0] contains the
6906baef150380d561a4d695a6be4fc509821c23611Calin Culianu * value COMEDI_INPUT or COMEDI_OUTPUT. */
6910a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcmmio_dio_insn_config(struct comedi_device *dev,
6920a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  struct comedi_subdevice *s,
6930a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  struct comedi_insn *insn, unsigned int *data)
6946baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
6956baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no =
6960a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    chan % 8;
6976baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long ioaddr;
6986baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned char byte;
6996baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7006baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* Compute ioaddr for this channel */
7016baef150380d561a4d695a6be4fc509821c23611Calin Culianu	ioaddr = subpriv->iobases[byte_no];
7026baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7036baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* NOTE:
7046baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   writing a 0 an IO channel's bit sets the channel to INPUT
7056baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   and pulls the line high as well
7066baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7076baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   writing a 1 to an IO channel's  bit pulls the line low
7086baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7096baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   All channels are implicitly always in OUTPUT mode -- but when
7106baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   they are high they can be considered to be in INPUT mode..
7116baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7126baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   Thus, we only force channels low if the config request was INPUT,
7136baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   otherwise we do nothing to the hardware.    */
7146baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7156baef150380d561a4d695a6be4fc509821c23611Calin Culianu	switch (data[0]) {
7166baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case INSN_CONFIG_DIO_OUTPUT:
7176baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* save to io_bits -- don't actually do anything since
7186baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   all input channels are also output channels... */
7196baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->io_bits |= 1 << chan;
7206baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
7216baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case INSN_CONFIG_DIO_INPUT:
7226baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* write a 0 to the actual register representing the channel
7236baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   to set it to 'input'.  0 means "float high". */
7246baef150380d561a4d695a6be4fc509821c23611Calin Culianu		byte = inb(ioaddr);
7256baef150380d561a4d695a6be4fc509821c23611Calin Culianu		byte &= ~(1 << bit_no);
7266baef150380d561a4d695a6be4fc509821c23611Calin Culianu				/**< set input channel to '0' */
7276baef150380d561a4d695a6be4fc509821c23611Calin Culianu
728013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson		/*
729013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson		 * write out byte -- this is the only time we actually affect
730013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson		 * the hardware as all channels are implicitly output
731013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson		 * -- but input channels are set to float-high
732013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson		 */
7336baef150380d561a4d695a6be4fc509821c23611Calin Culianu		outb(byte, ioaddr);
7346baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7356baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* save to io_bits */
7366baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->io_bits &= ~(1 << chan);
7376baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
7386baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7396baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case INSN_CONFIG_DIO_QUERY:
74025985edcedea6396277003854657b5f3cb31a628Lucas De Marchi		/* retrieve from shadow register */
7416baef150380d561a4d695a6be4fc509821c23611Calin Culianu		data[1] =
7420a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
7436baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return insn->n;
7446baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
7456baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7466baef150380d561a4d695a6be4fc509821c23611Calin Culianu	default:
7476baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return -EINVAL;
7486baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
7496baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
7506baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7516baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return insn->n;
7526baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
7536baef150380d561a4d695a6be4fc509821c23611Calin Culianu
754da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void init_asics(struct comedi_device *dev)
7556baef150380d561a4d695a6be4fc509821c23611Calin Culianu{				/* sets up an
7566baef150380d561a4d695a6be4fc509821c23611Calin Culianu				   ASIC chip to defaults */
7576baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int asic;
7586baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7596baef150380d561a4d695a6be4fc509821c23611Calin Culianu	for (asic = 0; asic < thisboard->dio_num_asics; ++asic) {
7606baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int port, page;
7616baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned long baseaddr = devpriv->asics[asic].iobase;
7626baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7636baef150380d561a4d695a6be4fc509821c23611Calin Culianu		switch_page(dev, asic, 0);	/* switch back to page 0 */
7646baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7656baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* first, clear all the DIO port bits */
7666baef150380d561a4d695a6be4fc509821c23611Calin Culianu		for (port = 0; port < PORTS_PER_ASIC; ++port)
7676baef150380d561a4d695a6be4fc509821c23611Calin Culianu			outb(0, baseaddr + REG_PORT0 + port);
7686baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7696baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* Next, clear all the paged registers for each page */
7706baef150380d561a4d695a6be4fc509821c23611Calin Culianu		for (page = 1; page < NUM_PAGES; ++page) {
7716baef150380d561a4d695a6be4fc509821c23611Calin Culianu			int reg;
7726baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* now clear all the paged registers */
7736baef150380d561a4d695a6be4fc509821c23611Calin Culianu			switch_page(dev, asic, page);
7746baef150380d561a4d695a6be4fc509821c23611Calin Culianu			for (reg = FIRST_PAGED_REG;
7750a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg)
7766baef150380d561a4d695a6be4fc509821c23611Calin Culianu				outb(0, baseaddr + reg);
7776baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
7786baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7796baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* DEBUG  set rising edge interrupts on port0 of both asics */
7806baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/*switch_page(dev, asic, PAGE_POL);
7816baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   outb(0xff, baseaddr + REG_POL0);
7826baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   switch_page(dev, asic, PAGE_ENAB);
7836baef150380d561a4d695a6be4fc509821c23611Calin Culianu		   outb(0xff, baseaddr + REG_ENAB0); */
7846baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* END DEBUG */
7856baef150380d561a4d695a6be4fc509821c23611Calin Culianu
786013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson		/* switch back to default page 0 */
787013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson		switch_page(dev, asic, 0);
7886baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
7896baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
7906baef150380d561a4d695a6be4fc509821c23611Calin Culianu
791da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void switch_page(struct comedi_device *dev, int asic, int page)
7926baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
7936baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (asic < 0 || asic >= thisboard->dio_num_asics)
7946baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return;		/* paranoia */
7956baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (page < 0 || page >= NUM_PAGES)
7966baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return;		/* more paranoia */
7976baef150380d561a4d695a6be4fc509821c23611Calin Culianu
7986baef150380d561a4d695a6be4fc509821c23611Calin Culianu	devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
7996baef150380d561a4d695a6be4fc509821c23611Calin Culianu	devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
8006baef150380d561a4d695a6be4fc509821c23611Calin Culianu
8016baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* now write out the shadow register */
8026baef150380d561a4d695a6be4fc509821c23611Calin Culianu	outb(devpriv->asics[asic].pagelock,
8030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	     devpriv->asics[asic].iobase + REG_PAGELOCK);
8046baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
8056baef150380d561a4d695a6be4fc509821c23611Calin Culianu
8066baef150380d561a4d695a6be4fc509821c23611Calin Culianu#ifdef notused
807da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void lock_port(struct comedi_device *dev, int asic, int port)
8086baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
8096baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (asic < 0 || asic >= thisboard->dio_num_asics)
8106baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return;		/* paranoia */
8116baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (port < 0 || port >= PORTS_PER_ASIC)
8126baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return;		/* more paranoia */
8136baef150380d561a4d695a6be4fc509821c23611Calin Culianu
8146baef150380d561a4d695a6be4fc509821c23611Calin Culianu	devpriv->asics[asic].pagelock |= 0x1 << port;
8156baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* now write out the shadow register */
8166baef150380d561a4d695a6be4fc509821c23611Calin Culianu	outb(devpriv->asics[asic].pagelock,
8170a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	     devpriv->asics[asic].iobase + REG_PAGELOCK);
8186baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return;
8196baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
8206baef150380d561a4d695a6be4fc509821c23611Calin Culianu
821da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void unlock_port(struct comedi_device *dev, int asic, int port)
8226baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
8236baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (asic < 0 || asic >= thisboard->dio_num_asics)
8246baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return;		/* paranoia */
8256baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (port < 0 || port >= PORTS_PER_ASIC)
8266baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return;		/* more paranoia */
8276baef150380d561a4d695a6be4fc509821c23611Calin Culianu	devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK;
8286baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* now write out the shadow register */
8296baef150380d561a4d695a6be4fc509821c23611Calin Culianu	outb(devpriv->asics[asic].pagelock,
8300a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	     devpriv->asics[asic].iobase + REG_PAGELOCK);
8316baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
8326baef150380d561a4d695a6be4fc509821c23611Calin Culianu#endif /* notused */
8336baef150380d561a4d695a6be4fc509821c23611Calin Culianu
83470265d24e3404fe798b6edd55a02016b1edb49d7Jiri Slabystatic irqreturn_t interrupt_pcmmio(int irq, void *d)
8356baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
8366baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int asic, got1 = 0;
8370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	struct comedi_device *dev = (struct comedi_device *)d;
8386baef150380d561a4d695a6be4fc509821c23611Calin Culianu
8396baef150380d561a4d695a6be4fc509821c23611Calin Culianu	for (asic = 0; asic < MAX_ASICS; ++asic) {
8406baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (irq == devpriv->asics[asic].irq) {
8416baef150380d561a4d695a6be4fc509821c23611Calin Culianu			unsigned long flags;
8426baef150380d561a4d695a6be4fc509821c23611Calin Culianu			unsigned triggered = 0;
8436baef150380d561a4d695a6be4fc509821c23611Calin Culianu			unsigned long iobase = devpriv->asics[asic].iobase;
8446baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* it is an interrupt for ASIC #asic */
8456baef150380d561a4d695a6be4fc509821c23611Calin Culianu			unsigned char int_pend;
8466baef150380d561a4d695a6be4fc509821c23611Calin Culianu
8470a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			spin_lock_irqsave(&devpriv->asics[asic].spinlock,
8480a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					  flags);
8496baef150380d561a4d695a6be4fc509821c23611Calin Culianu
8506baef150380d561a4d695a6be4fc509821c23611Calin Culianu			int_pend = inb(iobase + REG_INT_PENDING) & 0x07;
8516baef150380d561a4d695a6be4fc509821c23611Calin Culianu
8526baef150380d561a4d695a6be4fc509821c23611Calin Culianu			if (int_pend) {
8536baef150380d561a4d695a6be4fc509821c23611Calin Culianu				int port;
8546baef150380d561a4d695a6be4fc509821c23611Calin Culianu				for (port = 0; port < INTR_PORTS_PER_ASIC;
8550a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				     ++port) {
8566baef150380d561a4d695a6be4fc509821c23611Calin Culianu					if (int_pend & (0x1 << port)) {
8576baef150380d561a4d695a6be4fc509821c23611Calin Culianu						unsigned char
8580a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						    io_lines_with_edges = 0;
8596baef150380d561a4d695a6be4fc509821c23611Calin Culianu						switch_page(dev, asic,
8600a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    PAGE_INT_ID);
8616baef150380d561a4d695a6be4fc509821c23611Calin Culianu						io_lines_with_edges =
8620a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						    inb(iobase +
8636baef150380d561a4d695a6be4fc509821c23611Calin Culianu							REG_INT_ID0 + port);
8646baef150380d561a4d695a6be4fc509821c23611Calin Culianu
8656baef150380d561a4d695a6be4fc509821c23611Calin Culianu						if (io_lines_with_edges)
866013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson							/*
867013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson							 * clear pending
868013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson							 * interrupt
869013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson							 */
8706baef150380d561a4d695a6be4fc509821c23611Calin Culianu							outb(0, iobase +
8710a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							     REG_INT_ID0 +
8720a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							     port);
8736baef150380d561a4d695a6be4fc509821c23611Calin Culianu
8746baef150380d561a4d695a6be4fc509821c23611Calin Culianu						triggered |=
8750a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						    io_lines_with_edges <<
8760a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						    port * 8;
8776baef150380d561a4d695a6be4fc509821c23611Calin Culianu					}
8786baef150380d561a4d695a6be4fc509821c23611Calin Culianu				}
8796baef150380d561a4d695a6be4fc509821c23611Calin Culianu
8806baef150380d561a4d695a6be4fc509821c23611Calin Culianu				++got1;
8816baef150380d561a4d695a6be4fc509821c23611Calin Culianu			}
8826baef150380d561a4d695a6be4fc509821c23611Calin Culianu
8830a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			spin_unlock_irqrestore(&devpriv->asics[asic].spinlock,
8840a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					       flags);
8856baef150380d561a4d695a6be4fc509821c23611Calin Culianu
8866baef150380d561a4d695a6be4fc509821c23611Calin Culianu			if (triggered) {
88734c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton				struct comedi_subdevice *s;
888013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson				/*
889013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson				 * TODO here: dispatch io lines to subdevs
890013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson				 * with commands..
891013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson				 */
8920a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				printk
893bcd9a1e91fbc293bbbbddd98df687ad2e8027c89Johannes Thumshirn				    (KERN_DEBUG "got edge detect interrupt %d asic %d which_chans: %06x\n",
8940a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				     irq, asic, triggered);
8956baef150380d561a4d695a6be4fc509821c23611Calin Culianu				for (s = dev->subdevices + 2;
8960a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				     s < dev->subdevices + dev->n_subdevices;
8970a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				     ++s) {
898013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson					/*
899013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson					 * this is an interrupt subdev,
900013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson					 * and it matches this asic!
901013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson					 */
902013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson					if (subpriv->dio.intr.asic == asic) {
9036baef150380d561a4d695a6be4fc509821c23611Calin Culianu						unsigned long flags;
9046baef150380d561a4d695a6be4fc509821c23611Calin Culianu						unsigned oldevents;
9056baef150380d561a4d695a6be4fc509821c23611Calin Culianu
9060a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						spin_lock_irqsave(&subpriv->dio.
9070a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								  intr.spinlock,
9080a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								  flags);
9096baef150380d561a4d695a6be4fc509821c23611Calin Culianu
9106baef150380d561a4d695a6be4fc509821c23611Calin Culianu						oldevents = s->async->events;
9116baef150380d561a4d695a6be4fc509821c23611Calin Culianu
9126baef150380d561a4d695a6be4fc509821c23611Calin Culianu						if (subpriv->dio.intr.active) {
9136baef150380d561a4d695a6be4fc509821c23611Calin Culianu							unsigned mytrig =
9140a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    ((triggered >>
9150a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							      subpriv->dio.intr.asic_chan)
9160a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							     &
9170a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							     ((0x1 << subpriv->
9180a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							       dio.intr.
9190a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							       num_asic_chans) -
9200a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							      1)) << subpriv->
9210a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    dio.intr.first_chan;
9220a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							if (mytrig &
9230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    subpriv->dio.
9240a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							    intr.enabled_mask) {
9250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								unsigned int val
9260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								    = 0;
9276baef150380d561a4d695a6be4fc509821c23611Calin Culianu								unsigned int n,
9280a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								    ch, len;
9296baef150380d561a4d695a6be4fc509821c23611Calin Culianu
9300a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								len =
9310a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								    s->
9320a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								    async->cmd.chanlist_len;
9336baef150380d561a4d695a6be4fc509821c23611Calin Culianu								for (n = 0;
9340a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								     n < len;
9350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								     n++) {
9366baef150380d561a4d695a6be4fc509821c23611Calin Culianu									ch = CR_CHAN(s->async->cmd.chanlist[n]);
937013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson									if (mytrig & (1U << ch))
9386baef150380d561a4d695a6be4fc509821c23611Calin Culianu										val |= (1U << n);
9396baef150380d561a4d695a6be4fc509821c23611Calin Culianu								}
9406baef150380d561a4d695a6be4fc509821c23611Calin Culianu								/* Write the scan to the buffer. */
9410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								if (comedi_buf_put(s->async, ((short *)&val)[0])
9420a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								    &&
9430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								    comedi_buf_put
9440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								    (s->async,
9450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								     ((short *)
946013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson								      &val)[1])) {
9476baef150380d561a4d695a6be4fc509821c23611Calin Culianu									s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
9486baef150380d561a4d695a6be4fc509821c23611Calin Culianu								} else {
9496baef150380d561a4d695a6be4fc509821c23611Calin Culianu									/* Overflow! Stop acquisition!! */
9506baef150380d561a4d695a6be4fc509821c23611Calin Culianu									/* TODO: STOP_ACQUISITION_CALL_HERE!! */
9516baef150380d561a4d695a6be4fc509821c23611Calin Culianu									pcmmio_stop_intr
9520a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral									    (dev,
9530a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral									     s);
9546baef150380d561a4d695a6be4fc509821c23611Calin Culianu								}
9556baef150380d561a4d695a6be4fc509821c23611Calin Culianu
9566baef150380d561a4d695a6be4fc509821c23611Calin Culianu								/* Check for end of acquisition. */
9570a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								if (!subpriv->dio.intr.continuous) {
9586baef150380d561a4d695a6be4fc509821c23611Calin Culianu									/* stop_src == TRIG_COUNT */
9596baef150380d561a4d695a6be4fc509821c23611Calin Culianu									if (subpriv->dio.intr.stop_count > 0) {
9600a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral										subpriv->dio.intr.stop_count--;
9616baef150380d561a4d695a6be4fc509821c23611Calin Culianu										if (subpriv->dio.intr.stop_count == 0) {
9626baef150380d561a4d695a6be4fc509821c23611Calin Culianu											s->async->events |= COMEDI_CB_EOA;
9636baef150380d561a4d695a6be4fc509821c23611Calin Culianu											/* TODO: STOP_ACQUISITION_CALL_HERE!! */
9646baef150380d561a4d695a6be4fc509821c23611Calin Culianu											pcmmio_stop_intr
9650a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral											    (dev,
9660a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral											     s);
9676baef150380d561a4d695a6be4fc509821c23611Calin Culianu										}
9686baef150380d561a4d695a6be4fc509821c23611Calin Culianu									}
9696baef150380d561a4d695a6be4fc509821c23611Calin Culianu								}
9706baef150380d561a4d695a6be4fc509821c23611Calin Culianu							}
9716baef150380d561a4d695a6be4fc509821c23611Calin Culianu						}
9726baef150380d561a4d695a6be4fc509821c23611Calin Culianu
9730a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						spin_unlock_irqrestore
9740a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						    (&subpriv->dio.intr.
9750a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						     spinlock, flags);
9766baef150380d561a4d695a6be4fc509821c23611Calin Culianu
9776baef150380d561a4d695a6be4fc509821c23611Calin Culianu						if (oldevents !=
9780a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						    s->async->events) {
9796baef150380d561a4d695a6be4fc509821c23611Calin Culianu							comedi_event(dev, s);
9806baef150380d561a4d695a6be4fc509821c23611Calin Culianu						}
9816baef150380d561a4d695a6be4fc509821c23611Calin Culianu
9826baef150380d561a4d695a6be4fc509821c23611Calin Culianu					}
9836baef150380d561a4d695a6be4fc509821c23611Calin Culianu
9846baef150380d561a4d695a6be4fc509821c23611Calin Culianu				}
9856baef150380d561a4d695a6be4fc509821c23611Calin Culianu			}
9866baef150380d561a4d695a6be4fc509821c23611Calin Culianu
9876baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
9886baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
9896baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (!got1)
9906baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return IRQ_NONE;	/* interrupt from other source */
9916baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return IRQ_HANDLED;
9926baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
9936baef150380d561a4d695a6be4fc509821c23611Calin Culianu
9940a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic void pcmmio_stop_intr(struct comedi_device *dev,
9950a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_subdevice *s)
9966baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
9976baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int nports, firstport, asic, port;
9986baef150380d561a4d695a6be4fc509821c23611Calin Culianu
999c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	asic = subpriv->dio.intr.asic;
1000c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	if (asic < 0)
10016baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return;		/* not an interrupt subdev */
10026baef150380d561a4d695a6be4fc509821c23611Calin Culianu
10036baef150380d561a4d695a6be4fc509821c23611Calin Culianu	subpriv->dio.intr.enabled_mask = 0;
10046baef150380d561a4d695a6be4fc509821c23611Calin Culianu	subpriv->dio.intr.active = 0;
10056baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s->async->inttrig = 0;
10066baef150380d561a4d695a6be4fc509821c23611Calin Culianu	nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
10076baef150380d561a4d695a6be4fc509821c23611Calin Culianu	firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
10086baef150380d561a4d695a6be4fc509821c23611Calin Culianu	switch_page(dev, asic, PAGE_ENAB);
10096baef150380d561a4d695a6be4fc509821c23611Calin Culianu	for (port = firstport; port < firstport + nports; ++port) {
10106baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* disable all intrs for this subdev.. */
10116baef150380d561a4d695a6be4fc509821c23611Calin Culianu		outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
10126baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
10136baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
10146baef150380d561a4d695a6be4fc509821c23611Calin Culianu
10150a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcmmio_start_intr(struct comedi_device *dev,
10160a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_subdevice *s)
10176baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
10186baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (!subpriv->dio.intr.continuous && subpriv->dio.intr.stop_count == 0) {
10196baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* An empty acquisition! */
10206baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->async->events |= COMEDI_CB_EOA;
10216baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->dio.intr.active = 0;
10226baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return 1;
10236baef150380d561a4d695a6be4fc509821c23611Calin Culianu	} else {
10246baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned bits = 0, pol_bits = 0, n;
10256baef150380d561a4d695a6be4fc509821c23611Calin Culianu		int nports, firstport, asic, port;
1026ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton		struct comedi_cmd *cmd = &s->async->cmd;
10276baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1028c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton		asic = subpriv->dio.intr.asic;
10290a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		if (asic < 0)
10306baef150380d561a4d695a6be4fc509821c23611Calin Culianu			return 1;	/* not an interrupt
10316baef150380d561a4d695a6be4fc509821c23611Calin Culianu					   subdev */
10326baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->dio.intr.enabled_mask = 0;
10336baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->dio.intr.active = 1;
10346baef150380d561a4d695a6be4fc509821c23611Calin Culianu		nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
10356baef150380d561a4d695a6be4fc509821c23611Calin Culianu		firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
10366baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (cmd->chanlist) {
10376baef150380d561a4d695a6be4fc509821c23611Calin Culianu			for (n = 0; n < cmd->chanlist_len; n++) {
10386baef150380d561a4d695a6be4fc509821c23611Calin Culianu				bits |= (1U << CR_CHAN(cmd->chanlist[n]));
10396baef150380d561a4d695a6be4fc509821c23611Calin Culianu				pol_bits |= (CR_AREF(cmd->chanlist[n])
10400a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					     || CR_RANGE(cmd->
10410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							 chanlist[n]) ? 1U : 0U)
10420a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				    << CR_CHAN(cmd->chanlist[n]);
10436baef150380d561a4d695a6be4fc509821c23611Calin Culianu			}
10446baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
10456baef150380d561a4d695a6be4fc509821c23611Calin Culianu		bits &= ((0x1 << subpriv->dio.intr.num_asic_chans) -
10460a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 1) << subpriv->dio.intr.first_chan;
10476baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->dio.intr.enabled_mask = bits;
10486baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1049013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson		{
1050013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson			/*
1051013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson			 * the below code configures the board
1052013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson			 * to use a specific IRQ from 0-15.
1053013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson			 */
10546baef150380d561a4d695a6be4fc509821c23611Calin Culianu			unsigned char b;
1055013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson			/*
1056013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson			 * set resource enable register
1057013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson			 * to enable IRQ operation
1058013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson			 */
10596baef150380d561a4d695a6be4fc509821c23611Calin Culianu			outb(1 << 4, dev->iobase + 3);
10606baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* set bits 0-3 of b to the irq number from 0-15 */
10616baef150380d561a4d695a6be4fc509821c23611Calin Culianu			b = dev->irq & ((1 << 4) - 1);
10626baef150380d561a4d695a6be4fc509821c23611Calin Culianu			outb(b, dev->iobase + 2);
10636baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* done, we told the board what irq to use */
10646baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
10656baef150380d561a4d695a6be4fc509821c23611Calin Culianu
10666baef150380d561a4d695a6be4fc509821c23611Calin Culianu		switch_page(dev, asic, PAGE_ENAB);
10676baef150380d561a4d695a6be4fc509821c23611Calin Culianu		for (port = firstport; port < firstport + nports; ++port) {
10686baef150380d561a4d695a6be4fc509821c23611Calin Culianu			unsigned enab =
10690a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    bits >> (subpriv->dio.intr.first_chan + (port -
10700a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral								     firstport)
10710a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				     * 8) & 0xff, pol =
10720a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    pol_bits >> (subpriv->dio.intr.first_chan +
10730a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					 (port - firstport) * 8) & 0xff;
10746baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* set enab intrs for this subdev.. */
10756baef150380d561a4d695a6be4fc509821c23611Calin Culianu			outb(enab,
10760a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     devpriv->asics[asic].iobase + REG_ENAB0 + port);
10776baef150380d561a4d695a6be4fc509821c23611Calin Culianu			switch_page(dev, asic, PAGE_POL);
10786baef150380d561a4d695a6be4fc509821c23611Calin Culianu			outb(pol,
10790a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     devpriv->asics[asic].iobase + REG_ENAB0 + port);
10806baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
10816baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
10826baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 0;
10836baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
10846baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1085da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
10866baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
10876baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long flags;
10886baef150380d561a4d695a6be4fc509821c23611Calin Culianu
10895f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
10906baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (subpriv->dio.intr.active)
10916baef150380d561a4d695a6be4fc509821c23611Calin Culianu		pcmmio_stop_intr(dev, s);
10925f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
10936baef150380d561a4d695a6be4fc509821c23611Calin Culianu
10946baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 0;
10956baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
10966baef150380d561a4d695a6be4fc509821c23611Calin Culianu
10976baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
10986baef150380d561a4d695a6be4fc509821c23611Calin Culianu * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
10996baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
11006baef150380d561a4d695a6be4fc509821c23611Calin Culianustatic int
1101da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonpcmmio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
11020a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			  unsigned int trignum)
11036baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
11046baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long flags;
11056baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int event = 0;
11066baef150380d561a4d695a6be4fc509821c23611Calin Culianu
11076baef150380d561a4d695a6be4fc509821c23611Calin Culianu	if (trignum != 0)
11086baef150380d561a4d695a6be4fc509821c23611Calin Culianu		return -EINVAL;
11096baef150380d561a4d695a6be4fc509821c23611Calin Culianu
11105f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
11116baef150380d561a4d695a6be4fc509821c23611Calin Culianu	s->async->inttrig = 0;
1112013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson	if (subpriv->dio.intr.active)
11136baef150380d561a4d695a6be4fc509821c23611Calin Culianu		event = pcmmio_start_intr(dev, s);
11145f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
11156baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1116013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson	if (event)
11176baef150380d561a4d695a6be4fc509821c23611Calin Culianu		comedi_event(dev, s);
11186baef150380d561a4d695a6be4fc509821c23611Calin Culianu
11196baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 1;
11206baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
11216baef150380d561a4d695a6be4fc509821c23611Calin Culianu
11226baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
11236baef150380d561a4d695a6be4fc509821c23611Calin Culianu * 'do_cmd' function for an 'INTERRUPT' subdevice.
11246baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
1125da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
11266baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
1127ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd *cmd = &s->async->cmd;
11286baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long flags;
11296baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int event = 0;
11306baef150380d561a4d695a6be4fc509821c23611Calin Culianu
11315f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags);
11326baef150380d561a4d695a6be4fc509821c23611Calin Culianu	subpriv->dio.intr.active = 1;
11336baef150380d561a4d695a6be4fc509821c23611Calin Culianu
11346baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* Set up end of acquisition. */
11356baef150380d561a4d695a6be4fc509821c23611Calin Culianu	switch (cmd->stop_src) {
11366baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case TRIG_COUNT:
11376baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->dio.intr.continuous = 0;
11386baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->dio.intr.stop_count = cmd->stop_arg;
11396baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
11406baef150380d561a4d695a6be4fc509821c23611Calin Culianu	default:
11416baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* TRIG_NONE */
11426baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->dio.intr.continuous = 1;
11436baef150380d561a4d695a6be4fc509821c23611Calin Culianu		subpriv->dio.intr.stop_count = 0;
11446baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
11456baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
11466baef150380d561a4d695a6be4fc509821c23611Calin Culianu
11476baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* Set up start of acquisition. */
11486baef150380d561a4d695a6be4fc509821c23611Calin Culianu	switch (cmd->start_src) {
11496baef150380d561a4d695a6be4fc509821c23611Calin Culianu	case TRIG_INT:
11506baef150380d561a4d695a6be4fc509821c23611Calin Culianu		s->async->inttrig = pcmmio_inttrig_start_intr;
11516baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
11526baef150380d561a4d695a6be4fc509821c23611Calin Culianu	default:
11536baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* TRIG_NOW */
11546baef150380d561a4d695a6be4fc509821c23611Calin Culianu		event = pcmmio_start_intr(dev, s);
11556baef150380d561a4d695a6be4fc509821c23611Calin Culianu		break;
11566baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
11575f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags);
11586baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1159013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson	if (event)
11606baef150380d561a4d695a6be4fc509821c23611Calin Culianu		comedi_event(dev, s);
11616baef150380d561a4d695a6be4fc509821c23611Calin Culianu
11626baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 0;
11636baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
11646baef150380d561a4d695a6be4fc509821c23611Calin Culianu
11656baef150380d561a4d695a6be4fc509821c23611Calin Culianustatic int
11660a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralpcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
11670a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	       struct comedi_cmd *cmd)
11686baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
11690b8f754a6220158f2348bc6eae2772bc64bc98a2Bill Pemberton	return comedi_pcm_cmdtest(dev, s, cmd);
11706baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
11716baef150380d561a4d695a6be4fc509821c23611Calin Culianu
11726baef150380d561a4d695a6be4fc509821c23611Calin Culianustatic int adc_wait_ready(unsigned long iobase)
11736baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
11746baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long retry = 100000;
11756baef150380d561a4d695a6be4fc509821c23611Calin Culianu	while (retry--)
11766baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (inb(iobase + 3) & 0x80)
11776baef150380d561a4d695a6be4fc509821c23611Calin Culianu			return 0;
11786baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 1;
11796baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
11806baef150380d561a4d695a6be4fc509821c23611Calin Culianu
11816baef150380d561a4d695a6be4fc509821c23611Calin Culianu/* All this is for AI and AO */
1182da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
11830a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    struct comedi_insn *insn, unsigned int *data)
11846baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
11856baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int n;
11866baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long iobase = subpriv->iobase;
11876baef150380d561a4d695a6be4fc509821c23611Calin Culianu
11886baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/*
11896baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   1. write the CMD byte (to BASE+2)
11906baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   2. read junk lo byte (BASE+0)
11916baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   3. read junk hi byte (BASE+1)
11926baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   4. (mux settled so) write CMD byte again (BASE+2)
11936baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   5. read valid lo byte(BASE+0)
11946baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   6. read valid hi byte(BASE+1)
11956baef150380d561a4d695a6be4fc509821c23611Calin Culianu
11966baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   Additionally note that the BASE += 4 if the channel >= 8
11976baef150380d561a4d695a6be4fc509821c23611Calin Culianu	 */
11986baef150380d561a4d695a6be4fc509821c23611Calin Culianu
11996baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* convert n samples */
12006baef150380d561a4d695a6be4fc509821c23611Calin Culianu	for (n = 0; n < insn->n; n++) {
12016baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned chan = CR_CHAN(insn->chanspec), range =
12020a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    CR_RANGE(insn->chanspec), aref = CR_AREF(insn->chanspec);
12036baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned char command_byte = 0;
12046baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned iooffset = 0;
1205790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton		short sample, adc_adjust = 0;
12066baef150380d561a4d695a6be4fc509821c23611Calin Culianu
12076baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (chan > 7)
1208013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson			chan -= 8, iooffset = 4;	/*
1209013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson							 * use the second dword
1210013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson							 * for channels > 7
1211013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson							 */
12126baef150380d561a4d695a6be4fc509821c23611Calin Culianu
12136baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (aref != AREF_DIFF) {
12146baef150380d561a4d695a6be4fc509821c23611Calin Culianu			aref = AREF_GROUND;
1215013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson			command_byte |= 1 << 7;	/*
1216013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson						 * set bit 7 to indicate
1217013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson						 * single-ended
1218013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson						 */
12196baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
12206baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (range < 2)
1221013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson			adc_adjust = 0x8000;	/*
1222013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson						 * bipolar ranges
1223013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson						 * (-5,5 .. -10,10 need to be
1224013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson						 * adjusted -- that is.. they
1225013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson						 * need to wrap around by
1226013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson						 * adding 0x8000
1227013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson						 */
12286baef150380d561a4d695a6be4fc509821c23611Calin Culianu
12296baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (chan % 2) {
1230013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson			command_byte |= 1 << 6;	/*
1231013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson						 * odd-numbered channels
1232013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson						 * have bit 6 set
1233013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson						 */
12346baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
12356baef150380d561a4d695a6be4fc509821c23611Calin Culianu
12366baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* select the channel, bits 4-5 == chan/2 */
12376baef150380d561a4d695a6be4fc509821c23611Calin Culianu		command_byte |= ((chan / 2) & 0x3) << 4;
12386baef150380d561a4d695a6be4fc509821c23611Calin Culianu
12396baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* set the range, bits 2-3 */
12406baef150380d561a4d695a6be4fc509821c23611Calin Culianu		command_byte |= (range & 0x3) << 2;
12416baef150380d561a4d695a6be4fc509821c23611Calin Culianu
12426baef150380d561a4d695a6be4fc509821c23611Calin Culianu		/* need to do this twice to make sure mux settled */
1243013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson		/* chan/range/aref select */
1244013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson		outb(command_byte, iobase + iooffset + 2);
12456baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1246013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson		/* wait for the adc to say it finised the conversion */
1247013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson		adc_wait_ready(iobase + iooffset);
12486baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1249013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson		/* select the chan/range/aref AGAIN */
1250013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson		outb(command_byte, iobase + iooffset + 2);
12516baef150380d561a4d695a6be4fc509821c23611Calin Culianu
12526baef150380d561a4d695a6be4fc509821c23611Calin Culianu		adc_wait_ready(iobase + iooffset);
12536baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1254013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson		/* read data lo byte */
1255013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson		sample = inb(iobase + iooffset + 0);
1256013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson
1257013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson		/* read data hi byte */
1258013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson		sample |= inb(iobase + iooffset + 1) << 8;
12596baef150380d561a4d695a6be4fc509821c23611Calin Culianu		sample += adc_adjust;	/* adjustment .. munge data */
12606baef150380d561a4d695a6be4fc509821c23611Calin Culianu		data[n] = sample;
12616baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
12626baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* return the number of samples read/written */
12636baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return n;
12646baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
12656baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1266da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
12670a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    struct comedi_insn *insn, unsigned int *data)
12686baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
12696baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int n;
12706baef150380d561a4d695a6be4fc509821c23611Calin Culianu	for (n = 0; n < insn->n; n++) {
12716baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned chan = CR_CHAN(insn->chanspec);
12726baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (chan < s->n_chan)
12736baef150380d561a4d695a6be4fc509821c23611Calin Culianu			data[n] = subpriv->ao.shadow_samples[chan];
12746baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
12756baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return n;
12766baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
12776baef150380d561a4d695a6be4fc509821c23611Calin Culianu
12786baef150380d561a4d695a6be4fc509821c23611Calin Culianustatic int wait_dac_ready(unsigned long iobase)
12796baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
12806baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned long retry = 100000L;
12816baef150380d561a4d695a6be4fc509821c23611Calin Culianu
12826baef150380d561a4d695a6be4fc509821c23611Calin Culianu	/* This may seem like an absurd way to handle waiting and violates the
12836baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   "no busy waiting" policy. The fact is that the hardware is
12846baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   normally so fast that we usually only need one time through the loop
12856baef150380d561a4d695a6be4fc509821c23611Calin Culianu	   anyway. The longer timeout is for rare occasions and for detecting
128625985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	   non-existent hardware.  */
12876baef150380d561a4d695a6be4fc509821c23611Calin Culianu
12886baef150380d561a4d695a6be4fc509821c23611Calin Culianu	while (retry--) {
12896baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (inb(iobase + 3) & 0x80)
12906baef150380d561a4d695a6be4fc509821c23611Calin Culianu			return 0;
12916baef150380d561a4d695a6be4fc509821c23611Calin Culianu
12926baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
12936baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return 1;
12946baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
12956baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1296da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
12970a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    struct comedi_insn *insn, unsigned int *data)
12986baef150380d561a4d695a6be4fc509821c23611Calin Culianu{
12996baef150380d561a4d695a6be4fc509821c23611Calin Culianu	int n;
13006baef150380d561a4d695a6be4fc509821c23611Calin Culianu	unsigned iobase = subpriv->iobase, iooffset = 0;
13016baef150380d561a4d695a6be4fc509821c23611Calin Culianu
13026baef150380d561a4d695a6be4fc509821c23611Calin Culianu	for (n = 0; n < insn->n; n++) {
13036baef150380d561a4d695a6be4fc509821c23611Calin Culianu		unsigned chan = CR_CHAN(insn->chanspec), range =
13040a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		    CR_RANGE(insn->chanspec);
13056baef150380d561a4d695a6be4fc509821c23611Calin Culianu		if (chan < s->n_chan) {
13066baef150380d561a4d695a6be4fc509821c23611Calin Culianu			unsigned char command_byte = 0, range_byte =
13070a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    range & ((1 << 4) - 1);
13086baef150380d561a4d695a6be4fc509821c23611Calin Culianu			if (chan >= 4)
13096baef150380d561a4d695a6be4fc509821c23611Calin Culianu				chan -= 4, iooffset += 4;
13106baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* set the range.. */
13116baef150380d561a4d695a6be4fc509821c23611Calin Culianu			outb(range_byte, iobase + iooffset + 0);
13126baef150380d561a4d695a6be4fc509821c23611Calin Culianu			outb(0, iobase + iooffset + 1);
13136baef150380d561a4d695a6be4fc509821c23611Calin Culianu
13146baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* tell it to begin */
13156baef150380d561a4d695a6be4fc509821c23611Calin Culianu			command_byte = (chan << 1) | 0x60;
13166baef150380d561a4d695a6be4fc509821c23611Calin Culianu			outb(command_byte, iobase + iooffset + 2);
13176baef150380d561a4d695a6be4fc509821c23611Calin Culianu
13186baef150380d561a4d695a6be4fc509821c23611Calin Culianu			wait_dac_ready(iobase + iooffset);
13196baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1320013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson			/* low order byte */
1321013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson			outb(data[n] & 0xff, iobase + iooffset + 0);
1322013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson
1323013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson			/* high order byte */
1324013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson			outb((data[n] >> 8) & 0xff, iobase + iooffset + 1);
1325013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson
1326013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson			/*
1327013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson			 * set bit 4 of command byte to indicate
1328013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson			 * data is loaded and trigger conversion
1329013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson			 */
1330013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson			command_byte = 0x70 | (chan << 1);
13316baef150380d561a4d695a6be4fc509821c23611Calin Culianu			/* trigger converion */
13326baef150380d561a4d695a6be4fc509821c23611Calin Culianu			outb(command_byte, iobase + iooffset + 2);
13336baef150380d561a4d695a6be4fc509821c23611Calin Culianu
13346baef150380d561a4d695a6be4fc509821c23611Calin Culianu			wait_dac_ready(iobase + iooffset);
13356baef150380d561a4d695a6be4fc509821c23611Calin Culianu
1336013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson			/* save to shadow register for ao_rinsn */
1337013f230c4f2622cbbc736c50223b49bced024655Daniel Patrick Johnson			subpriv->ao.shadow_samples[chan] = data[n];
13386baef150380d561a4d695a6be4fc509821c23611Calin Culianu		}
13396baef150380d561a4d695a6be4fc509821c23611Calin Culianu	}
13406baef150380d561a4d695a6be4fc509821c23611Calin Culianu	return n;
13416baef150380d561a4d695a6be4fc509821c23611Calin Culianu}
13426baef150380d561a4d695a6be4fc509821c23611Calin Culianu
13436baef150380d561a4d695a6be4fc509821c23611Calin Culianu/*
13446baef150380d561a4d695a6be4fc509821c23611Calin Culianu * A convenient macro that defines init_module() and cleanup_module(),
13456baef150380d561a4d695a6be4fc509821c23611Calin Culianu * as necessary.
13466baef150380d561a4d695a6be4fc509821c23611Calin Culianu */
13477114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasstatic int __init driver_init_module(void)
13487114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas{
13497114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas	return comedi_driver_register(&driver);
13507114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas}
13517114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas
13527114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasstatic void __exit driver_cleanup_module(void)
13537114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas{
13547114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas	comedi_driver_unregister(&driver);
13557114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas}
13567114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas
13577114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasmodule_init(driver_init_module);
13587114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasmodule_exit(driver_cleanup_module);
135990f703d30dd3e0c16ff80f35e34e511385a05ad5Arun Thomas
136090f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_AUTHOR("Comedi http://www.comedi.org");
136190f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_DESCRIPTION("Comedi low-level driver");
136290f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_LICENSE("GPL");
1363