1456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef/*
2456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   comedi/drivers/pcl711.c
3456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   hardware driver for PC-LabCard PCL-711 and AdSys ACL-8112
4456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   and compatibles
5456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
6456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   COMEDI - Linux Control and Measurement Device Interface
7456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   Copyright (C) 1998 David A. Schleef <ds@schleef.org>
8456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   Janne Jalkanen <jalkanen@cs.hut.fi>
9456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   Eric Bunn <ebu@cs.hut.fi>
10456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
11456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   This program is free software; you can redistribute it and/or modify
12456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   it under the terms of the GNU General Public License as published by
13456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   the Free Software Foundation; either version 2 of the License, or
14456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   (at your option) any later version.
15456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
16456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   This program is distributed in the hope that it will be useful,
17456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   but WITHOUT ANY WARRANTY; without even the implied warranty of
18456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   GNU General Public License for more details.
20456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
21456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   You should have received a copy of the GNU General Public License
22456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   along with this program; if not, write to the Free Software
23456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
25456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef */
26456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef/*
27456af2011ce33efa3bc037e793cad4a6f113619bDavid SchleefDriver: pcl711
28456af2011ce33efa3bc037e793cad4a6f113619bDavid SchleefDescription: Advantech PCL-711 and 711b, ADLink ACL-8112
29456af2011ce33efa3bc037e793cad4a6f113619bDavid SchleefAuthor: ds, Janne Jalkanen <jalkanen@cs.hut.fi>, Eric Bunn <ebu@cs.hut.fi>
30456af2011ce33efa3bc037e793cad4a6f113619bDavid SchleefStatus: mostly complete
31456af2011ce33efa3bc037e793cad4a6f113619bDavid SchleefDevices: [Advantech] PCL-711 (pcl711), PCL-711B (pcl711b),
32456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef  [AdLink] ACL-8112HG (acl8112hg), ACL-8112DG (acl8112dg)
33456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
34456af2011ce33efa3bc037e793cad4a6f113619bDavid SchleefSince these boards do not have DMA or FIFOs, only immediate mode is
35456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleefsupported.
36456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
37456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef*/
38456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
39456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef/*
40456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   Dave Andruczyk <dave@tech.buffalostate.edu> also wrote a
41456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   driver for the PCL-711.  I used a few ideas from his driver
42456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   here.  His driver also has more comments, if you are
43456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   interested in understanding how this driver works.
44456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   http://tech.buffalostate.edu/~dave/driver/
45456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
46456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   The ACL-8112 driver was hacked from the sources of the PCL-711
47456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   driver (the 744 chip used on the 8112 is almost the same as
48456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   the 711b chip, but it has more I/O channels) by
49456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   Janne Jalkanen (jalkanen@cs.hut.fi) and
50456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   Erik Bunn (ebu@cs.hut.fi).  Remerged with the PCL-711 driver
51456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   by ds.
52456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
53456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   [acl-8112]
54456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   This driver supports both TRIGNOW and TRIGCLK,
55456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   but does not yet support DMA transfers.  It also supports
56456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   both high (HG) and low (DG) versions of the card, though
57456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   the HG version has been untested.
58456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
59456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef */
60456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
6125436dc9d84f1be60ff549c9ab712bba2835f284Greg Kroah-Hartman#include <linux/interrupt.h>
62456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef#include "../comedidev.h"
63456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
64456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef#include <linux/ioport.h>
65456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef#include <linux/delay.h>
66456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
67456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef#include "8253.h"
68456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
69456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef#define PCL711_SIZE 16
70456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
71456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef#define PCL711_CTR0 0
72456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef#define PCL711_CTR1 1
73456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef#define PCL711_CTR2 2
74456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef#define PCL711_CTRCTL 3
75456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef#define PCL711_AD_LO 4
76456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef#define PCL711_DA0_LO 4
77456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef#define PCL711_AD_HI 5
78456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef#define PCL711_DA0_HI 5
79456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef#define PCL711_DI_LO 6
80456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef#define PCL711_DA1_LO 6
81456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef#define PCL711_DI_HI 7
82456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef#define PCL711_DA1_HI 7
83456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef#define PCL711_CLRINTR 8
84456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef#define PCL711_GAIN 9
85456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef#define PCL711_MUX 10
86456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef#define PCL711_MODE 11
87456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef#define PCL711_SOFTTRIG 12
88456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef#define PCL711_DO_LO 13
89456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef#define PCL711_DO_HI 14
90456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
919ced1de69125b60f40127eddaa3be2a92bb0a1dfBill Pembertonstatic const struct comedi_lrange range_pcl711b_ai = { 5, {
920a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							   BIP_RANGE(5),
930a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							   BIP_RANGE(2.5),
940a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							   BIP_RANGE(1.25),
950a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							   BIP_RANGE(0.625),
960a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							   BIP_RANGE(0.3125)
970a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							   }
98456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef};
990a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
1009ced1de69125b60f40127eddaa3be2a92bb0a1dfBill Pembertonstatic const struct comedi_lrange range_acl8112hg_ai = { 12, {
1010a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							      BIP_RANGE(5),
1020a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							      BIP_RANGE(0.5),
1030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							      BIP_RANGE(0.05),
1040a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							      BIP_RANGE(0.005),
1050a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							      UNI_RANGE(10),
1060a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							      UNI_RANGE(1),
1070a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							      UNI_RANGE(0.1),
1080a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							      UNI_RANGE(0.01),
1090a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							      BIP_RANGE(10),
1100a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							      BIP_RANGE(1),
1110a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							      BIP_RANGE(0.1),
1120a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							      BIP_RANGE(0.01)
1130a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							      }
114456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef};
1150a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
1169ced1de69125b60f40127eddaa3be2a92bb0a1dfBill Pembertonstatic const struct comedi_lrange range_acl8112dg_ai = { 9, {
1170a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							     BIP_RANGE(5),
1180a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							     BIP_RANGE(2.5),
1190a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							     BIP_RANGE(1.25),
1200a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							     BIP_RANGE(0.625),
1210a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							     UNI_RANGE(10),
1220a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							     UNI_RANGE(5),
1230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							     UNI_RANGE(2.5),
1240a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							     UNI_RANGE(1.25),
1250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							     BIP_RANGE(10)
1260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							     }
127456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef};
128456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
129456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef/*
130456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef * flags
131456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef */
132456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
133456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef#define PCL711_TIMEOUT 100
134456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef#define PCL711_DRDY 0x10
135456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
136456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleefstatic const int i8253_osc_base = 500;	/* 2 Mhz */
137456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
1386445296e9857ff4a3992454eda7ebb63f90cdca9Bill Pembertonstruct pcl711_board {
1396445296e9857ff4a3992454eda7ebb63f90cdca9Bill Pemberton
140456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	const char *name;
141456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	int is_pcl711b;
142456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	int is_8112;
143456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	int is_dg;
144456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	int n_ranges;
145456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	int n_aichan;
146456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	int n_aochan;
147456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	int maxirq;
1489ced1de69125b60f40127eddaa3be2a92bb0a1dfBill Pemberton	const struct comedi_lrange *ai_range_type;
1496445296e9857ff4a3992454eda7ebb63f90cdca9Bill Pemberton};
1506445296e9857ff4a3992454eda7ebb63f90cdca9Bill Pemberton
1516445296e9857ff4a3992454eda7ebb63f90cdca9Bill Pembertonstatic const struct pcl711_board boardtypes[] = {
152456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	{"pcl711", 0, 0, 0, 5, 8, 1, 0, &range_bipolar5},
153456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	{"pcl711b", 1, 0, 0, 5, 8, 1, 7, &range_pcl711b_ai},
154456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	{"acl8112hg", 0, 1, 0, 12, 16, 2, 15, &range_acl8112hg_ai},
155456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	{"acl8112dg", 0, 1, 1, 9, 16, 2, 15, &range_acl8112dg_ai},
156456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef};
157456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
1586445296e9857ff4a3992454eda7ebb63f90cdca9Bill Pemberton#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl711_board))
1596445296e9857ff4a3992454eda7ebb63f90cdca9Bill Pemberton#define this_board ((const struct pcl711_board *)dev->board_ptr)
160456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
1610a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcl711_attach(struct comedi_device *dev,
1620a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			 struct comedi_devconfig *it);
163da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcl711_detach(struct comedi_device *dev);
164139dfbdfacb02e3ef3df936d2fabd1ad5f14ea88Bill Pembertonstatic struct comedi_driver driver_pcl711 = {
16568c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.driver_name = "pcl711",
16668c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.module = THIS_MODULE,
16768c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.attach = pcl711_attach,
16868c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.detach = pcl711_detach,
16968c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.board_name = &boardtypes[0].name,
17068c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.num_names = n_boardtypes,
17168c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.offset = sizeof(struct pcl711_board),
172456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef};
173456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
1747114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasstatic int __init driver_pcl711_init_module(void)
1757114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas{
1767114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas	return comedi_driver_register(&driver_pcl711);
1777114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas}
1787114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas
1797114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasstatic void __exit driver_pcl711_cleanup_module(void)
1807114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas{
1817114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas	comedi_driver_unregister(&driver_pcl711);
1827114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas}
1837114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas
1847114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasmodule_init(driver_pcl711_init_module);
1857114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasmodule_exit(driver_pcl711_cleanup_module);
186456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
187e1c8638f3fb47c25b8dba170aadc8e29619fcd67Bill Pembertonstruct pcl711_private {
188e1c8638f3fb47c25b8dba170aadc8e29619fcd67Bill Pemberton
189456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	int board;
190456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	int adchan;
191456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	int ntrig;
192456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	int aip[8];
193456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	int mode;
194790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	unsigned int ao_readback[2];
195456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	unsigned int divisor1;
196456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	unsigned int divisor2;
197e1c8638f3fb47c25b8dba170aadc8e29619fcd67Bill Pemberton};
198e1c8638f3fb47c25b8dba170aadc8e29619fcd67Bill Pemberton
199e1c8638f3fb47c25b8dba170aadc8e29619fcd67Bill Pemberton#define devpriv ((struct pcl711_private *)dev->private)
200456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
20170265d24e3404fe798b6edd55a02016b1edb49d7Jiri Slabystatic irqreturn_t pcl711_interrupt(int irq, void *d)
202456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef{
203456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	int lo, hi;
204456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	int data;
20571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	struct comedi_device *dev = d;
20634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s = dev->subdevices + 0;
207456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
208456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (!dev->attached) {
209456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		comedi_error(dev, "spurious interrupt");
210456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		return IRQ_HANDLED;
211456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	}
212456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
213456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	hi = inb(dev->iobase + PCL711_AD_HI);
214456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	lo = inb(dev->iobase + PCL711_AD_LO);
215456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	outb(0, dev->iobase + PCL711_CLRINTR);
216456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
217456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	data = (hi << 8) | lo;
218456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
219456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	/* FIXME! Nothing else sets ntrig! */
220456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (!(--devpriv->ntrig)) {
221266bfbdd3eb7f080612977f22055c82b951b179eBenjamin Adolphi		if (this_board->is_8112)
222456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef			outb(1, dev->iobase + PCL711_MODE);
223266bfbdd3eb7f080612977f22055c82b951b179eBenjamin Adolphi		else
224456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef			outb(0, dev->iobase + PCL711_MODE);
225456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
226456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		s->async->events |= COMEDI_CB_EOA;
227456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	}
228456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	comedi_event(dev, s);
229456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	return IRQ_HANDLED;
230456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef}
231456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
232da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void pcl711_set_changain(struct comedi_device *dev, int chan)
233456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef{
234456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	int chan_register;
235456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
236456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	outb(CR_RANGE(chan), dev->iobase + PCL711_GAIN);
237456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
238456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	chan_register = CR_CHAN(chan);
239456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
240456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (this_board->is_8112) {
241456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
242456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		/*
243456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		 *  Set the correct channel.  The two channel banks are switched
244456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		 *  using the mask value.
245266bfbdd3eb7f080612977f22055c82b951b179eBenjamin Adolphi		 *  NB: To use differential channels, you should use
246266bfbdd3eb7f080612977f22055c82b951b179eBenjamin Adolphi		 *  mask = 0x30, but I haven't written the support for this
247266bfbdd3eb7f080612977f22055c82b951b179eBenjamin Adolphi		 *  yet. /JJ
248456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		 */
249456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
250266bfbdd3eb7f080612977f22055c82b951b179eBenjamin Adolphi		if (chan_register >= 8)
251456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef			chan_register = 0x20 | (chan_register & 0x7);
252266bfbdd3eb7f080612977f22055c82b951b179eBenjamin Adolphi		else
253456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef			chan_register |= 0x10;
254456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	} else {
255456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		outb(chan_register, dev->iobase + PCL711_MUX);
256456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	}
257456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef}
258456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
259da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcl711_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
2600a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			  struct comedi_insn *insn, unsigned int *data)
261456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef{
262456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	int i, n;
263456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	int hi, lo;
264456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
265456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	pcl711_set_changain(dev, insn->chanspec);
266456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
267456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	for (n = 0; n < insn->n; n++) {
268456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		/*
269266bfbdd3eb7f080612977f22055c82b951b179eBenjamin Adolphi		 *  Write the correct mode (software polling) and start polling
270266bfbdd3eb7f080612977f22055c82b951b179eBenjamin Adolphi		 *  by writing to the trigger register
271456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		 */
272456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		outb(1, dev->iobase + PCL711_MODE);
273456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
274266bfbdd3eb7f080612977f22055c82b951b179eBenjamin Adolphi		if (!this_board->is_8112)
275456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef			outb(0, dev->iobase + PCL711_SOFTTRIG);
276456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
277456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		i = PCL711_TIMEOUT;
278456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		while (--i) {
279456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef			hi = inb(dev->iobase + PCL711_AD_HI);
280456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef			if (!(hi & PCL711_DRDY))
281456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef				goto ok;
2825f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman			udelay(1);
283456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		}
2848f4e80af3aa509902bd2319c3b5512580f64868fGustavo Silva		printk(KERN_ERR "comedi%d: pcl711: A/D timeout\n", dev->minor);
285456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		return -ETIME;
286456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
2870a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralok:
288456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		lo = inb(dev->iobase + PCL711_AD_LO);
289456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
290456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		data[n] = ((hi & 0xf) << 8) | lo;
291456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	}
292456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
293456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	return n;
294456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef}
295456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
2960a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcl711_ai_cmdtest(struct comedi_device *dev,
2970a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_subdevice *s, struct comedi_cmd *cmd)
298456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef{
299456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	int tmp;
300456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	int err = 0;
301456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
302456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	/* step 1 */
303456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	tmp = cmd->start_src;
304456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	cmd->start_src &= TRIG_NOW;
305456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (!cmd->start_src || tmp != cmd->start_src)
306456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		err++;
307456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
308456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	tmp = cmd->scan_begin_src;
309456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT;
310456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
311456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		err++;
312456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
313456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	tmp = cmd->convert_src;
314456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	cmd->convert_src &= TRIG_NOW;
315456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (!cmd->convert_src || tmp != cmd->convert_src)
316456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		err++;
317456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
318456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	tmp = cmd->scan_end_src;
319456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	cmd->scan_end_src &= TRIG_COUNT;
320456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
321456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		err++;
322456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
323456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	tmp = cmd->stop_src;
324456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
325456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (!cmd->stop_src || tmp != cmd->stop_src)
326456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		err++;
327456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
328456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (err)
329456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		return 1;
330456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
331456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	/* step 2 */
332456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
333456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (cmd->scan_begin_src != TRIG_TIMER &&
3340a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    cmd->scan_begin_src != TRIG_EXT)
335456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		err++;
336456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
337456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		err++;
338456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
339456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (err)
340456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		return 2;
341456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
342456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	/* step 3 */
343456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
344456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (cmd->start_arg != 0) {
345456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		cmd->start_arg = 0;
346456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		err++;
347456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	}
348456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (cmd->scan_begin_src == TRIG_EXT) {
349456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		if (cmd->scan_begin_arg != 0) {
350456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef			cmd->scan_begin_arg = 0;
351456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef			err++;
352456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		}
353456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	} else {
354456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef#define MAX_SPEED 1000
355456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef#define TIMER_BASE 100
356456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		if (cmd->scan_begin_arg < MAX_SPEED) {
357456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef			cmd->scan_begin_arg = MAX_SPEED;
358456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef			err++;
359456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		}
360456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	}
361456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (cmd->convert_arg != 0) {
362456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		cmd->convert_arg = 0;
363456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		err++;
364456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	}
365456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (cmd->scan_end_arg != cmd->chanlist_len) {
366456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		cmd->scan_end_arg = cmd->chanlist_len;
367456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		err++;
368456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	}
369456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (cmd->stop_src == TRIG_NONE) {
370456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		if (cmd->stop_arg != 0) {
371456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef			cmd->stop_arg = 0;
372456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef			err++;
373456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		}
374456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	} else {
375456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		/* ignore */
376456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	}
377456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
378456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (err)
379456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		return 3;
380456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
381456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	/* step 4 */
382456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
383456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (cmd->scan_begin_src == TRIG_TIMER) {
384456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		tmp = cmd->scan_begin_arg;
385456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		i8253_cascade_ns_to_timer_2div(TIMER_BASE,
3860a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					       &devpriv->divisor1,
3870a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					       &devpriv->divisor2,
3880a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					       &cmd->scan_begin_arg,
3890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					       cmd->flags & TRIG_ROUND_MASK);
390456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		if (tmp != cmd->scan_begin_arg)
391456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef			err++;
392456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	}
393456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
394456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (err)
395456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		return 4;
396456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
397456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	return 0;
398456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef}
399456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
400da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcl711_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
401456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef{
402456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	int timer1, timer2;
403ea6d0d4cab4f4f2d6a88f3bce4707fe92696fd3fBill Pemberton	struct comedi_cmd *cmd = &s->async->cmd;
404456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
405456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	pcl711_set_changain(dev, cmd->chanlist[0]);
406456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
407456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (cmd->scan_begin_src == TRIG_TIMER) {
408456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		/*
409456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		 *  Set timers
410456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		 *      timer chip is an 8253, with timers 1 and 2
411456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		 *      cascaded
412456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		 *  0x74 = Select Counter 1 | LSB/MSB | Mode=2 | Binary
413456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		 *        Mode 2 = Rate generator
414456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		 *
415456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		 *  0xb4 = Select Counter 2 | LSB/MSB | Mode=2 | Binary
416456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		 */
417456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
41848b1aff5b93521c5ad90842bef52b218ac50a4abIan Abbott		timer1 = timer2 = 0;
419456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		i8253_cascade_ns_to_timer(i8253_osc_base, &timer1, &timer2,
4200a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					  &cmd->scan_begin_arg,
4210a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					  TRIG_ROUND_NEAREST);
422456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
423456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		outb(0x74, dev->iobase + PCL711_CTRCTL);
424456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		outb(timer1 & 0xff, dev->iobase + PCL711_CTR1);
425456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		outb((timer1 >> 8) & 0xff, dev->iobase + PCL711_CTR1);
426456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		outb(0xb4, dev->iobase + PCL711_CTRCTL);
427456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		outb(timer2 & 0xff, dev->iobase + PCL711_CTR2);
428456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		outb((timer2 >> 8) & 0xff, dev->iobase + PCL711_CTR2);
429456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
430456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		/* clear pending interrupts (just in case) */
431456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		outb(0, dev->iobase + PCL711_CLRINTR);
432456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
433456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		/*
434456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		 *  Set mode to IRQ transfer
435456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		 */
436456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		outb(devpriv->mode | 6, dev->iobase + PCL711_MODE);
437456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	} else {
438456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		/* external trigger */
439456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		outb(devpriv->mode | 3, dev->iobase + PCL711_MODE);
440456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	}
441456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
442456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	return 0;
443456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef}
444456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
445456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef/*
446456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef   analog output
447456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef*/
448da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcl711_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
4490a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			  struct comedi_insn *insn, unsigned int *data)
450456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef{
451456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	int n;
452456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	int chan = CR_CHAN(insn->chanspec);
453456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
454456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	for (n = 0; n < insn->n; n++) {
455456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		outb((data[n] & 0xff),
4560a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		     dev->iobase + (chan ? PCL711_DA1_LO : PCL711_DA0_LO));
457456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		outb((data[n] >> 8),
4580a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		     dev->iobase + (chan ? PCL711_DA1_HI : PCL711_DA0_HI));
459456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
460456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		devpriv->ao_readback[chan] = data[n];
461456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	}
462456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
463456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	return n;
464456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef}
465456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
4660a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcl711_ao_insn_read(struct comedi_device *dev,
4670a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_subdevice *s,
4680a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_insn *insn, unsigned int *data)
469456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef{
470456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	int n;
471456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	int chan = CR_CHAN(insn->chanspec);
472456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
473266bfbdd3eb7f080612977f22055c82b951b179eBenjamin Adolphi	for (n = 0; n < insn->n; n++)
474456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		data[n] = devpriv->ao_readback[chan];
475456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
476456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	return n;
477456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
478456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef}
479456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
480456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef/* Digital port read - Untested on 8112 */
4810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcl711_di_insn_bits(struct comedi_device *dev,
4820a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_subdevice *s,
4830a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_insn *insn, unsigned int *data)
484456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef{
485456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (insn->n != 2)
486456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		return -EINVAL;
487456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
488456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	data[1] = inb(dev->iobase + PCL711_DI_LO) |
4890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    (inb(dev->iobase + PCL711_DI_HI) << 8);
490456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
491456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	return 2;
492456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef}
493456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
494456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef/* Digital port write - Untested on 8112 */
4950a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int pcl711_do_insn_bits(struct comedi_device *dev,
4960a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_subdevice *s,
4970a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_insn *insn, unsigned int *data)
498456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef{
499456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (insn->n != 2)
500456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		return -EINVAL;
501456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
502456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (data[0]) {
503456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		s->state &= ~data[0];
504456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		s->state |= data[0] & data[1];
505456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	}
506456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (data[0] & 0x00ff)
507456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		outb(s->state & 0xff, dev->iobase + PCL711_DO_LO);
508456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (data[0] & 0xff00)
509456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		outb((s->state >> 8), dev->iobase + PCL711_DO_HI);
510456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
511456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	data[1] = s->state;
512456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
513456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	return 2;
514456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef}
515456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
516456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef/*  Free any resources that we have claimed  */
517da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcl711_detach(struct comedi_device *dev)
518456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef{
5198f4e80af3aa509902bd2319c3b5512580f64868fGustavo Silva	printk(KERN_INFO "comedi%d: pcl711: remove\n", dev->minor);
520456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
521456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (dev->irq)
5225f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman		free_irq(dev->irq, dev);
523456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
524456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (dev->iobase)
525456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		release_region(dev->iobase, PCL711_SIZE);
526456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
527456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	return 0;
528456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef}
529456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
530456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef/*  Initialization */
531da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it)
532456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef{
533456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	int ret;
534456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	unsigned long iobase;
535456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	unsigned int irq;
53634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *s;
537456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
538456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	/* claim our I/O space */
539456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
540456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	iobase = it->options[0];
5418f4e80af3aa509902bd2319c3b5512580f64868fGustavo Silva	printk(KERN_INFO "comedi%d: pcl711: 0x%04lx ", dev->minor, iobase);
542456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (!request_region(iobase, PCL711_SIZE, "pcl711")) {
543456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		printk("I/O port conflict\n");
544456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		return -EIO;
545456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	}
546456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	dev->iobase = iobase;
547456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
548456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	/* there should be a sanity check here */
549456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
550456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	/* set up some name stuff */
551456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	dev->board_name = this_board->name;
552456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
553456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	/* grab our IRQ */
554456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	irq = it->options[1];
555456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (irq > this_board->maxirq) {
5568f4e80af3aa509902bd2319c3b5512580f64868fGustavo Silva		printk(KERN_ERR "irq out of range\n");
557456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		return -EINVAL;
558456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	}
559456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (irq) {
5605f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman		if (request_irq(irq, pcl711_interrupt, 0, "pcl711", dev)) {
5618f4e80af3aa509902bd2319c3b5512580f64868fGustavo Silva			printk(KERN_ERR "unable to allocate irq %u\n", irq);
562456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef			return -EINVAL;
563456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		} else {
5648f4e80af3aa509902bd2319c3b5512580f64868fGustavo Silva			printk(KERN_INFO "( irq = %u )\n", irq);
565456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		}
566456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	}
567456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	dev->irq = irq;
568456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
569c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	ret = alloc_subdevices(dev, 4);
570c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	if (ret < 0)
571456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		return ret;
572c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton
573c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	ret = alloc_private(dev, sizeof(struct pcl711_private));
574c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	if (ret < 0)
575456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		return ret;
576456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
577456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s = dev->subdevices + 0;
578456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	/* AI subdevice */
579456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->type = COMEDI_SUBD_AI;
580456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->subdev_flags = SDF_READABLE | SDF_GROUND;
581456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->n_chan = this_board->n_aichan;
582456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->maxdata = 0xfff;
583456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->len_chanlist = 1;
584456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->range_table = this_board->ai_range_type;
585456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->insn_read = pcl711_ai_insn;
586456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	if (irq) {
587456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		dev->read_subdev = s;
588456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		s->subdev_flags |= SDF_CMD_READ;
589456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		s->do_cmdtest = pcl711_ai_cmdtest;
590456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		s->do_cmd = pcl711_ai_cmd;
591456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	}
592456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
593456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s++;
594456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	/* AO subdevice */
595456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->type = COMEDI_SUBD_AO;
596456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->subdev_flags = SDF_WRITABLE;
597456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->n_chan = this_board->n_aochan;
598456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->maxdata = 0xfff;
599456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->len_chanlist = 1;
600456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->range_table = &range_bipolar5;
601456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->insn_write = pcl711_ao_insn;
602456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->insn_read = pcl711_ao_insn_read;
603456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
604456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s++;
605456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	/* 16-bit digital input */
606456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->type = COMEDI_SUBD_DI;
607456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->subdev_flags = SDF_READABLE;
608456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->n_chan = 16;
609456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->maxdata = 1;
610456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->len_chanlist = 16;
611456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->range_table = &range_digital;
612456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->insn_bits = pcl711_di_insn_bits;
613456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
614456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s++;
615456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	/* 16-bit digital out */
616456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->type = COMEDI_SUBD_DO;
617456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->subdev_flags = SDF_WRITABLE;
618456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->n_chan = 16;
619456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->maxdata = 1;
620456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->len_chanlist = 16;
621456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->range_table = &range_digital;
622456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->state = 0;
623456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	s->insn_bits = pcl711_do_insn_bits;
624456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
625456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	/*
626456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	   this is the "base value" for the mode register, which is
627456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	   used for the irq on the PCL711
628456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	 */
629266bfbdd3eb7f080612977f22055c82b951b179eBenjamin Adolphi	if (this_board->is_pcl711b)
630456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef		devpriv->mode = (dev->irq << 4);
631456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
632456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	/* clear DAC */
633456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	outb(0, dev->iobase + PCL711_DA0_LO);
634456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	outb(0, dev->iobase + PCL711_DA0_HI);
635456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	outb(0, dev->iobase + PCL711_DA1_LO);
636456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	outb(0, dev->iobase + PCL711_DA1_HI);
637456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
6388f4e80af3aa509902bd2319c3b5512580f64868fGustavo Silva	printk(KERN_INFO "\n");
639456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef
640456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef	return 0;
641456af2011ce33efa3bc037e793cad4a6f113619bDavid Schleef}
64290f703d30dd3e0c16ff80f35e34e511385a05ad5Arun Thomas
64390f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_AUTHOR("Comedi http://www.comedi.org");
64490f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_DESCRIPTION("Comedi low-level driver");
64590f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_LICENSE("GPL");
646