10e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes/*
20e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
30e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes   comedi/drivers/me_daq.c
40e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
50e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes   Hardware driver for Meilhaus data acquisition cards:
60e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
70e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes     ME-2000i, ME-2600i, ME-3000vm1
80e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
90e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes   Copyright (C) 2002 Michael Hillmann <hillmann@syscongroup.de>
100e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
110e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes    This program is free software; you can redistribute it and/or modify
120e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes    it under the terms of the GNU General Public License as published by
130e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes    the Free Software Foundation; either version 2 of the License, or
140e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes    (at your option) any later version.
150e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
160e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes    This program is distributed in the hope that it will be useful,
170e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes    but WITHOUT ANY WARRANTY; without even the implied warranty of
180e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
190e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes    GNU General Public License for more details.
200e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
210e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes    You should have received a copy of the GNU General Public License
2297feeef5c55fe783e6f01d4dec3fd0926e60b0d8Mark    along with this program; if not, write to the Free Software
230e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
240e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes*/
250e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
260e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes/*
270e8db97a04b37960828b273d166e35eac9a1888bMichal DobesDriver: me_daq
280e8db97a04b37960828b273d166e35eac9a1888bMichal DobesDescription: Meilhaus PCI data acquisition cards
290e8db97a04b37960828b273d166e35eac9a1888bMichal DobesAuthor: Michael Hillmann <hillmann@syscongroup.de>
300e8db97a04b37960828b273d166e35eac9a1888bMichal DobesDevices: [Meilhaus] ME-2600i (me_daq), ME-2000i
310e8db97a04b37960828b273d166e35eac9a1888bMichal DobesStatus: experimental
320e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
330e8db97a04b37960828b273d166e35eac9a1888bMichal DobesSupports:
340e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
350e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes    Analog Output
360e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
370e8db97a04b37960828b273d166e35eac9a1888bMichal DobesConfiguration options:
380e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
390e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes    [0] - PCI bus number (optional)
4097feeef5c55fe783e6f01d4dec3fd0926e60b0d8Mark    [1] - PCI slot number (optional)
4197feeef5c55fe783e6f01d4dec3fd0926e60b0d8Mark
420e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes    If bus/slot is not specified, the first available PCI
430e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes    device will be used.
4470265d24e3404fe798b6edd55a02016b1edb49d7Jiri Slaby
4570265d24e3404fe798b6edd55a02016b1edb49d7Jiri SlabyThe 2600 requires a firmware upload, which can be accomplished
460e8db97a04b37960828b273d166e35eac9a1888bMichal Dobesusing the -i or --init-data option of comedi_config.
470e8db97a04b37960828b273d166e35eac9a1888bMichal DobesThe firmware can be
480e8db97a04b37960828b273d166e35eac9a1888bMichal Dobesfound in the comedi_nonfree_firmware tarball available
490e8db97a04b37960828b273d166e35eac9a1888bMichal Dobesfrom http://www.comedi.org
500e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
510e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes*/
520e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
5397feeef5c55fe783e6f01d4dec3fd0926e60b0d8Mark#include <linux/interrupt.h>
5497feeef5c55fe783e6f01d4dec3fd0926e60b0d8Mark#include <linux/sched.h>
5597feeef5c55fe783e6f01d4dec3fd0926e60b0d8Mark#include "../comedidev.h"
560e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
570e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#include "comedi_pci.h"
580e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
590e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes/*#include "me2600_fw.h" */
600e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
610e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define ME_DRIVER_NAME		"me_daq"
620e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
635f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman#define PCI_VENDOR_ID_MEILHAUS	0x1402
640e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define ME2000_DEVICE_ID	0x2000
650e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define ME2600_DEVICE_ID	0x2600
660e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
670e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define PLX_INTCSR		0x4C	/* PLX interrupt status register */
6859af888d6af8e3d2c91b32e00e43f2ce750589b8Greg Kroah-Hartman#define XILINX_DOWNLOAD_RESET	0x42	/* Xilinx registers */
6959af888d6af8e3d2c91b32e00e43f2ce750589b8Greg Kroah-Hartman
702696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton#define ME_CONTROL_1			0x0000	/* - | W */
710e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   INTERRUPT_ENABLE		(1<<15)
720e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   COUNTER_B_IRQ			(1<<12)
730e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   COUNTER_A_IRQ			(1<<11)
740e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   CHANLIST_READY_IRQ		(1<<10)
7597feeef5c55fe783e6f01d4dec3fd0926e60b0d8Mark#define   EXT_IRQ			(1<<9)
7697feeef5c55fe783e6f01d4dec3fd0926e60b0d8Mark#define   ADFIFO_HALFFULL_IRQ		(1<<8)
770e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   SCAN_COUNT_ENABLE		(1<<5)
780e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   SIMULTANEOUS_ENABLE		(1<<4)
790e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   TRIGGER_FALLING_EDGE		(1<<3)
800e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   CONTINUOUS_MODE		(1<<2)
810e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   DISABLE_ADC			(0<<0)
820e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   SOFTWARE_TRIGGERED_ADC	(1<<0)
830e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   SCAN_TRIGGERED_ADC		(2<<0)
840e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   EXT_TRIGGERED_ADC		(3<<0)
850e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define ME_ADC_START			0x0000	/* R | - */
860e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define ME_CONTROL_2			0x0002	/* - | W */
870e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   ENABLE_ADFIFO			(1<<10)
880e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   ENABLE_CHANLIST		(1<<9)
890e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   ENABLE_PORT_B			(1<<7)
900e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   ENABLE_PORT_A			(1<<6)
91d5a2ffd8e8d602293339f69180aff8914c454d83Uwe Kleine-König#define   ENABLE_COUNTER_B		(1<<4)
92d5a2ffd8e8d602293339f69180aff8914c454d83Uwe Kleine-König#define   ENABLE_COUNTER_A		(1<<3)
93d5a2ffd8e8d602293339f69180aff8914c454d83Uwe Kleine-König#define   ENABLE_DAC			(1<<1)
940e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   BUFFERED_DAC			(1<<0)
950e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define ME_DAC_UPDATE			0x0002	/* R | - */
9697feeef5c55fe783e6f01d4dec3fd0926e60b0d8Mark#define ME_STATUS			0x0004	/* R | - */
9797feeef5c55fe783e6f01d4dec3fd0926e60b0d8Mark#define   COUNTER_B_IRQ_PENDING		(1<<12)
980e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   COUNTER_A_IRQ_PENDING		(1<<11)
990e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   CHANLIST_READY_IRQ_PENDING	(1<<10)
1000e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   EXT_IRQ_PENDING		(1<<9)
10125985edcedea6396277003854657b5f3cb31a628Lucas De Marchi#define   ADFIFO_HALFFULL_IRQ_PENDING	(1<<8)
1022696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton#define   ADFIFO_FULL			(1<<4)
10397feeef5c55fe783e6f01d4dec3fd0926e60b0d8Mark#define   ADFIFO_HALFFULL		(1<<3)
10497feeef5c55fe783e6f01d4dec3fd0926e60b0d8Mark#define   ADFIFO_EMPTY			(1<<2)
1050e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   CHANLIST_FULL			(1<<1)
1060e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   FST_ACTIVE			(1<<0)
1070e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define ME_RESET_INTERRUPT		0x0004	/* - | W */
1080e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define ME_DIO_PORT_A			0x0006	/* R | W */
1090e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define ME_DIO_PORT_B			0x0008	/* R | W */
1100e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define ME_TIMER_DATA_0			0x000A	/* - | W */
1112696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton#define ME_TIMER_DATA_1			0x000C	/* - | W */
1120e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define ME_TIMER_DATA_2			0x000E	/* - | W */
1130e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define ME_CHANNEL_LIST			0x0010	/* - | W */
1140e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   ADC_UNIPOLAR			(1<<6)
1150e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   ADC_GAIN_0			(0<<4)
1160e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   ADC_GAIN_1			(1<<4)
1170e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   ADC_GAIN_2			(2<<4)
1180e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   ADC_GAIN_3			(3<<4)
11997feeef5c55fe783e6f01d4dec3fd0926e60b0d8Mark#define ME_READ_AD_FIFO			0x0010	/* R | - */
12097feeef5c55fe783e6f01d4dec3fd0926e60b0d8Mark#define ME_DAC_CONTROL			0x0012	/* - | W */
1210e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   DAC_UNIPOLAR_D		(0<<4)
1220e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   DAC_BIPOLAR_D			(1<<4)
1230e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   DAC_UNIPOLAR_C		(0<<5)
1240e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   DAC_BIPOLAR_C			(1<<5)
1250e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   DAC_UNIPOLAR_B		(0<<6)
1260e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   DAC_BIPOLAR_B			(1<<6)
1270e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   DAC_UNIPOLAR_A		(0<<7)
1280e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   DAC_BIPOLAR_A			(1<<7)
1290e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   DAC_GAIN_0_D			(0<<8)
1302696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton#define   DAC_GAIN_1_D			(1<<8)
1310e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   DAC_GAIN_0_C			(0<<9)
1320e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define   DAC_GAIN_1_C			(1<<9)
1339ced1de69125b60f40127eddaa3be2a92bb0a1dfBill Pemberton#define   DAC_GAIN_0_B			(0<<10)
1340a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral#define   DAC_GAIN_1_B			(1<<10)
1350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral#define   DAC_GAIN_0_A			(0<<11)
1360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral#define   DAC_GAIN_1_A			(1<<11)
1370a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral#define ME_DAC_CONTROL_UPDATE		0x0012	/* R | - */
1380a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral#define ME_DAC_DATA_A			0x0014	/* - | W */
1390a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral#define ME_DAC_DATA_B			0x0016	/* - | W */
1400a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral#define ME_DAC_DATA_C			0x0018	/* - | W */
1410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral#define ME_DAC_DATA_D			0x001A	/* - | W */
1420a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral#define ME_COUNTER_ENDDATA_A		0x001C	/* - | W */
1430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral#define ME_COUNTER_ENDDATA_B		0x001E	/* - | W */
1440e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define ME_COUNTER_STARTDATA_A		0x0020	/* - | W */
1450e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define ME_COUNTER_VALUE_A		0x0020	/* R | - */
14697feeef5c55fe783e6f01d4dec3fd0926e60b0d8Mark#define ME_COUNTER_STARTDATA_B		0x0022	/* - | W */
14797feeef5c55fe783e6f01d4dec3fd0926e60b0d8Mark#define ME_COUNTER_VALUE_B		0x0022	/* R | - */
1480e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
1499ced1de69125b60f40127eddaa3be2a92bb0a1dfBill Pemberton/* Function prototypes */
1500a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int me_attach(struct comedi_device *dev, struct comedi_devconfig *it);
1510a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int me_detach(struct comedi_device *dev);
1520a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
1530a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic const struct comedi_lrange me2000_ai_range = {
1540a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	8,
1550a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	{
1560a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 BIP_RANGE(10),
1570a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 BIP_RANGE(5),
1580a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 BIP_RANGE(2.5),
1590a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 BIP_RANGE(1.25),
1600a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 UNI_RANGE(10),
1610a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 UNI_RANGE(5),
1620a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 UNI_RANGE(2.5),
1630e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	 UNI_RANGE(1.25)
1640e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	 }
16597feeef5c55fe783e6f01d4dec3fd0926e60b0d8Mark};
16697feeef5c55fe783e6f01d4dec3fd0926e60b0d8Mark
16797feeef5c55fe783e6f01d4dec3fd0926e60b0d8Markstatic const struct comedi_lrange me2600_ai_range = {
1680e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	8,
1699ced1de69125b60f40127eddaa3be2a92bb0a1dfBill Pemberton	{
1700a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 BIP_RANGE(10),
1710a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 BIP_RANGE(5),
1720a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 BIP_RANGE(2.5),
1730a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 BIP_RANGE(1.25),
1740a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 UNI_RANGE(10),
1750a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 UNI_RANGE(5),
1760e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	 UNI_RANGE(2.5),
1770e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	 UNI_RANGE(1.25)
1780e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	 }
1790e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes};
1809ced1de69125b60f40127eddaa3be2a92bb0a1dfBill Pemberton
1810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic const struct comedi_lrange me2600_ao_range = {
1820a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	3,
1830a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	{
1840a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 BIP_RANGE(10),
1850a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 BIP_RANGE(5),
1860e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	 UNI_RANGE(10)
1870e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	 }
1889ced1de69125b60f40127eddaa3be2a92bb0a1dfBill Pemberton};
1890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
1900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic DEFINE_PCI_DEVICE_TABLE(me_pci_table) = {
1910a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, ME2600_DEVICE_ID) },
1920e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	{ PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, ME2000_DEVICE_ID) },
1930e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	{0}
1940a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral};
1950a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
196da91b2692e0939b307f9047192d2b9fe07793e7aBill PembertonMODULE_DEVICE_TABLE(pci, me_pci_table);
1970e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
1987875a00b702e62ebafe68cd2abf96570e2d747e5Bill Pemberton/* Board specification structure */
1992696fb57e6af653dd8b4df41b16754579f42fc78Bill Pembertonstruct me_board {
2000e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	const char *name;	/* driver name */
2012696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	int device_id;
2022696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	int ao_channel_nbr;	/* DA config */
2032696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	int ao_resolution;
2042696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	int ao_resolution_mask;
2052696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	const struct comedi_lrange *ao_range_list;
2062696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	int ai_channel_nbr;	/* AD config */
2072696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	int ai_resolution;
2082696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	int ai_resolution_mask;
2092696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	const struct comedi_lrange *ai_range_list;
2102696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	int dio_channel_nbr;	/* DIO config */
2112696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton};
2122696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton
2132696fb57e6af653dd8b4df41b16754579f42fc78Bill Pembertonstatic const struct me_board me_boards[] = {
2142696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	{
2152696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	 /* -- ME-2600i -- */
2162696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	 .name = ME_DRIVER_NAME,
2177875a00b702e62ebafe68cd2abf96570e2d747e5Bill Pemberton	 .device_id = ME2600_DEVICE_ID,
2180e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	 /* Analog Output */
2190e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	 .ao_channel_nbr = 4,
220d991058efbc140957af0f3338ad6f52448c2890eJavier Martinez Canillas	 .ao_resolution = 12,
221d991058efbc140957af0f3338ad6f52448c2890eJavier Martinez Canillas	 .ao_resolution_mask = 0x0fff,
222d991058efbc140957af0f3338ad6f52448c2890eJavier Martinez Canillas	 .ao_range_list = &me2600_ao_range,
223d991058efbc140957af0f3338ad6f52448c2890eJavier Martinez Canillas	 .ai_channel_nbr = 16,
224d991058efbc140957af0f3338ad6f52448c2890eJavier Martinez Canillas	 /* Analog Input */
225d991058efbc140957af0f3338ad6f52448c2890eJavier Martinez Canillas	 .ai_resolution = 12,
2260e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	 .ai_resolution_mask = 0x0fff,
2270e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	 .ai_range_list = &me2600_ai_range,
2280e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	 .dio_channel_nbr = 32,
2290e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	 },
2307875a00b702e62ebafe68cd2abf96570e2d747e5Bill Pemberton	{
2310e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	 /* -- ME-2000i -- */
2320a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .name = ME_DRIVER_NAME,
2330a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .device_id = ME2000_DEVICE_ID,
2340a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 /* Analog Output */
2350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ao_channel_nbr = 0,
2360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ao_resolution = 0,
2370e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	 .ao_resolution_mask = 0,
2380a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ao_range_list = NULL,
2390a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_channel_nbr = 16,
2400a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 /* Analog Input */
2410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_resolution = 12,
2420a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .ai_resolution_mask = 0x0fff,
2430e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	 .ai_range_list = &me2000_ai_range,
2440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 .dio_channel_nbr = 32,
2450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	 }
2460a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral};
2470a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
2480e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes#define me_board_nbr (sizeof(me_boards)/sizeof(struct me_board))
2490a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
2500a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic struct comedi_driver me_driver = {
2510a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.driver_name = ME_DRIVER_NAME,
2520a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.module = THIS_MODULE,
2530e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	.attach = me_attach,
2540a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	.detach = me_detach,
2550a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral};
2560a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
2570a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int __devinit me_driver_pci_probe(struct pci_dev *dev,
2580e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes					 const struct pci_device_id *ent)
2590a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral{
2600a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	return comedi_pci_auto_config(dev, me_driver.driver_name);
2610a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral}
2620a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
2632696fb57e6af653dd8b4df41b16754579f42fc78Bill Pembertonstatic void __devexit me_driver_pci_remove(struct pci_dev *dev)
2640e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes{
2650e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	comedi_pci_auto_unconfig(dev);
2660e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes}
2677875a00b702e62ebafe68cd2abf96570e2d747e5Bill Pemberton
2680e8db97a04b37960828b273d166e35eac9a1888bMichal Dobesstatic struct pci_driver me_driver_pci_driver = {
269139dfbdfacb02e3ef3df936d2fabd1ad5f14ea88Bill Pemberton	.id_table = me_pci_table,
2700e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	.probe = &me_driver_pci_probe,
2710e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	.remove = __devexit_p(&me_driver_pci_remove)
2720e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes};
2730e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
2740e8db97a04b37960828b273d166e35eac9a1888bMichal Dobesstatic int __init me_driver_init_module(void)
2750e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes{
2767875a00b702e62ebafe68cd2abf96570e2d747e5Bill Pemberton	int retval;
2770e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
2780e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	retval = comedi_driver_register(&me_driver);
2796e8131a86d6c1a9896282f572d17c447a85262adBill Pemberton	if (retval < 0)
2802696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton		return retval;
2812696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton
2822696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	me_driver_pci_driver.name = (char *)me_driver.driver_name;
2832696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	return pci_register_driver(&me_driver_pci_driver);
2842696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton}
2852696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton
2862696fb57e6af653dd8b4df41b16754579f42fc78Bill Pembertonstatic void __exit me_driver_cleanup_module(void)
2872696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton{
2882696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	pci_unregister_driver(&me_driver_pci_driver);
2892696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	comedi_driver_unregister(&me_driver);
2900e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes}
2910e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
2920e8db97a04b37960828b273d166e35eac9a1888bMichal Dobesmodule_init(me_driver_init_module);
2930e8db97a04b37960828b273d166e35eac9a1888bMichal Dobesmodule_exit(me_driver_cleanup_module);
2942696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton
2952696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton/* Private data structure */
2962696fb57e6af653dd8b4df41b16754579f42fc78Bill Pembertonstruct me_private_data {
2972696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	struct pci_dev *pci_device;
2982696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	void __iomem *plx_regbase;	/* PLX configuration base address */
2992696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	void __iomem *me_regbase;	/* Base address of the Meilhaus card */
3002696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	unsigned long plx_regbase_size;	/* Size of PLX configuration space */
3012696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	unsigned long me_regbase_size;	/* Size of Meilhaus space */
3022696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton
3030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	unsigned short control_1;	/* Mirror of CONTROL_1 register */
3042696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	unsigned short control_2;	/* Mirror of CONTROL_2 register */
3050e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	unsigned short dac_control;	/* Mirror of the DAC_CONTROL register */
3062696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	int ao_readback[4];	/* Mirror of analog output data */
30797feeef5c55fe783e6f01d4dec3fd0926e60b0d8Mark};
30897feeef5c55fe783e6f01d4dec3fd0926e60b0d8Mark
3096e8131a86d6c1a9896282f572d17c447a85262adBill Pemberton#define dev_private ((struct me_private_data *)dev->private)
3100e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
3116e8131a86d6c1a9896282f572d17c447a85262adBill Pemberton/*
3127875a00b702e62ebafe68cd2abf96570e2d747e5Bill Pemberton * ------------------------------------------------------------------
3130e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes *
3140e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes * Helpful functions
3150e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes *
3160e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes * ------------------------------------------------------------------
3170e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes */
3180a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic inline void sleep(unsigned sec)
3190a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral{
3200a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	current->state = TASK_INTERRUPTIBLE;
3210a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	schedule_timeout(sec * HZ);
3220a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral}
3230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
3240a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral/*
3250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral * ------------------------------------------------------------------
3260a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral *
327da91b2692e0939b307f9047192d2b9fe07793e7aBill Pemberton * DIGITAL INPUT/OUTPUT SECTION
3280a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral *
3290a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral * ------------------------------------------------------------------
3300e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes */
33197feeef5c55fe783e6f01d4dec3fd0926e60b0d8Markstatic int me_dio_insn_config(struct comedi_device *dev,
33297feeef5c55fe783e6f01d4dec3fd0926e60b0d8Mark			      struct comedi_subdevice *s,
33397feeef5c55fe783e6f01d4dec3fd0926e60b0d8Mark			      struct comedi_insn *insn, unsigned int *data)
3340e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes{
3350e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	int bits;
3360e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	int mask = 1 << CR_CHAN(insn->chanspec);
3370e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
3380e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* calculate port */
3390e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	if (mask & 0x0000ffff) {	/* Port A in use */
3400e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		bits = 0x0000ffff;
3410e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
3420a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		/* Enable Port A */
3430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		dev_private->control_2 |= ENABLE_PORT_A;
3440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		writew(dev_private->control_2,
3450e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		       dev_private->me_regbase + ME_CONTROL_2);
3460e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	} else {		/* Port B in use */
3470e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
3480e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		bits = 0xffff0000;
3490e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
3500e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		/* Enable Port B */
3510e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		dev_private->control_2 |= ENABLE_PORT_B;
3520e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		writew(dev_private->control_2,
3532696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton		       dev_private->me_regbase + ME_CONTROL_2);
3540e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	}
3550e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
3560e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	if (data[0]) {
3570e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		/* Config port as output */
3580e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		s->io_bits |= bits;
3590e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	} else {
3600e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		/* Config port as input */
3610e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		s->io_bits &= ~bits;
3620e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	}
3630e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
3640e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	return 1;
3650e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes}
3660e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
3675f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman/* Digital instant input/outputs */
3680e8db97a04b37960828b273d166e35eac9a1888bMichal Dobesstatic int me_dio_insn_bits(struct comedi_device *dev,
3690e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes			    struct comedi_subdevice *s,
3700e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes			    struct comedi_insn *insn, unsigned int *data)
3710e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes{
3720e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	unsigned int mask = data[0];
3730e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	s->state &= ~mask;
3740e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	s->state |= (mask & data[1]);
3750e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
3760e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	mask &= s->io_bits;
3770e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	if (mask & 0x0000ffff) {	/* Port A */
3780e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		writew((s->state & 0xffff),
3790e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		       dev_private->me_regbase + ME_DIO_PORT_A);
3800e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	} else {
3810e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		data[1] &= ~0x0000ffff;
3820e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		data[1] |= readw(dev_private->me_regbase + ME_DIO_PORT_A);
3830a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	}
3840a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
3850a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	if (mask & 0xffff0000) {	/* Port B */
3860e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		writew(((s->state >> 16) & 0xffff),
3870e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		       dev_private->me_regbase + ME_DIO_PORT_B);
3880a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	} else {
3890e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		data[1] &= ~0xffff0000;
3900e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		data[1] |= readw(dev_private->me_regbase + ME_DIO_PORT_B) << 16;
3910e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	}
3920e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
3930e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	return 2;
3940e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes}
3950e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
3960e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes/*
3970e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes * ------------------------------------------------------------------
3980e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes *
3990e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes * ANALOG INPUT SECTION
4000e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes *
4010e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes * ------------------------------------------------------------------
4020e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes */
4030e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
4040e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes/* Analog instant input */
4050e8db97a04b37960828b273d166e35eac9a1888bMichal Dobesstatic int me_ai_insn_read(struct comedi_device *dev,
4060e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes			   struct comedi_subdevice *subdevice,
4070e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes			   struct comedi_insn *insn, unsigned int *data)
4080e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes{
4090e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	unsigned short value;
4100e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	int chan = CR_CHAN((&insn->chanspec)[0]);
4110e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	int rang = CR_RANGE((&insn->chanspec)[0]);
4120e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	int aref = CR_AREF((&insn->chanspec)[0]);
4130a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	int i;
4140a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
4150a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	/* stop any running conversion */
4160e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	dev_private->control_1 &= 0xFFFC;
4170e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	writew(dev_private->control_1, dev_private->me_regbase + ME_CONTROL_1);
4180e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
4190e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* clear chanlist and ad fifo */
4200e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	dev_private->control_2 &= ~(ENABLE_ADFIFO | ENABLE_CHANLIST);
4210e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	writew(dev_private->control_2, dev_private->me_regbase + ME_CONTROL_2);
4220e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
4230e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* reset any pending interrupt */
4240e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	writew(0x00, dev_private->me_regbase + ME_RESET_INTERRUPT);
4250e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
4260e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* enable the chanlist and ADC fifo */
4270e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	dev_private->control_2 |= (ENABLE_ADFIFO | ENABLE_CHANLIST);
4280e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	writew(dev_private->control_2, dev_private->me_regbase + ME_CONTROL_2);
4290e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
4300e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* write to channel list fifo */
4310e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* b3:b0 are the channel number */
4320e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	value = chan & 0x0f;
4330e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* b5:b4 are the channel gain */
4340e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	value |= (rang & 0x03) << 4;
4350e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* b6 channel polarity */
4360e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	value |= (rang & 0x04) << 4;
4370e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* b7 single or differential */
4380e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	value |= ((aref & AREF_DIFF) ? 0x80 : 0);
4390e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	writew(value & 0xff, dev_private->me_regbase + ME_CHANNEL_LIST);
4400e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
4410e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* set ADC mode to software trigger */
4420e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	dev_private->control_1 |= SOFTWARE_TRIGGERED_ADC;
4430e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	writew(dev_private->control_1, dev_private->me_regbase + ME_CONTROL_1);
4440e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
4450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	/* start conversion by reading from ADC_START */
4460a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	readw(dev_private->me_regbase + ME_ADC_START);
4470a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
4480e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* wait for ADC fifo not empty flag */
4490e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	for (i = 100000; i > 0; i--)
4500e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		if (!(readw(dev_private->me_regbase + ME_STATUS) & 0x0004))
4510e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes			break;
4520e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
4530e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* get value from ADC fifo */
4540e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	if (i) {
4550e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		data[0] =
4560e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		    (readw(dev_private->me_regbase +
4570e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes			   ME_READ_AD_FIFO) ^ 0x800) & 0x0FFF;
4580e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	} else {
4590e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		printk(KERN_ERR "comedi%d: Cannot get single value\n",
4600e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		       dev->minor);
4610a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		return -EIO;
4620a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	}
4630a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
4640e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* stop any running conversion */
4650e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	dev_private->control_1 &= 0xFFFC;
4660e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	writew(dev_private->control_1, dev_private->me_regbase + ME_CONTROL_1);
4670e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
4680e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	return 1;
4690e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes}
4700e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
4710e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes/*
4720e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes * ------------------------------------------------------------------
4730a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral *
4740a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral * HARDWARE TRIGGERED ANALOG INPUT SECTION
4750a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral *
4760e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes * ------------------------------------------------------------------
4770e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes */
4780e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
4790e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes/* Cancel analog input autoscan */
4800e8db97a04b37960828b273d166e35eac9a1888bMichal Dobesstatic int me_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
4810e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes{
4820e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* disable interrupts */
4830e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
4840e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* stop any running conversion */
4850e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	dev_private->control_1 &= 0xFFFC;
4860e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	writew(dev_private->control_1, dev_private->me_regbase + ME_CONTROL_1);
4870e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
4880e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	return 0;
4890e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes}
4900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
4910a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral/* Test analog input command */
4920a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int me_ai_do_cmd_test(struct comedi_device *dev,
4930a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			     struct comedi_subdevice *s, struct comedi_cmd *cmd)
4940e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes{
4950e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	return 0;
4960e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes}
4970e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
4980e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes/* Analog input command */
4990e8db97a04b37960828b273d166e35eac9a1888bMichal Dobesstatic int me_ai_do_cmd(struct comedi_device *dev,
5000e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes			struct comedi_subdevice *subdevice)
5010e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes{
5020e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	return 0;
5030e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes}
5040e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
5050e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes/*
5060e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes * ------------------------------------------------------------------
5070e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes *
5080e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes * ANALOG OUTPUT SECTION
5090e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes *
5100e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes * ------------------------------------------------------------------
5110e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes */
5120e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
5130e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes/* Analog instant output */
5140a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int me_ao_insn_write(struct comedi_device *dev,
5150a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    struct comedi_subdevice *s,
5160a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			    struct comedi_insn *insn, unsigned int *data)
5170a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral{
5180e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	int chan;
5190e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	int rang;
5200e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	int i;
5210e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
5220e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* Enable all DAC */
5230e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	dev_private->control_2 |= ENABLE_DAC;
5240e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	writew(dev_private->control_2, dev_private->me_regbase + ME_CONTROL_2);
5250e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
5260e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* and set DAC to "buffered" mode */
5270e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	dev_private->control_2 |= BUFFERED_DAC;
5280e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	writew(dev_private->control_2, dev_private->me_regbase + ME_CONTROL_2);
5290e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
5300e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* Set dac-control register */
5310e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	for (i = 0; i < insn->n; i++) {
5320e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		chan = CR_CHAN((&insn->chanspec)[i]);
5330e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		rang = CR_RANGE((&insn->chanspec)[i]);
5340e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
5350e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		/* clear bits for this channel */
5360e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		dev_private->dac_control &= ~(0x0880 >> chan);
5370e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		if (rang == 0)
5380e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes			dev_private->dac_control |=
5390e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes			    ((DAC_BIPOLAR_A | DAC_GAIN_1_A) >> chan);
5400e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		else if (rang == 1)
5410e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes			dev_private->dac_control |=
5420e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes			    ((DAC_BIPOLAR_A | DAC_GAIN_0_A) >> chan);
543da91b2692e0939b307f9047192d2b9fe07793e7aBill Pemberton	}
5440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	writew(dev_private->dac_control,
5450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	       dev_private->me_regbase + ME_DAC_CONTROL);
5460a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
5470e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* Update dac-control register */
5480e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	readw(dev_private->me_regbase + ME_DAC_CONTROL_UPDATE);
5490e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
5500e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* Set data register */
5510e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	for (i = 0; i < insn->n; i++) {
5520e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		chan = CR_CHAN((&insn->chanspec)[i]);
5530e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		writew((data[0] & s->maxdata),
5540e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		       dev_private->me_regbase + ME_DAC_DATA_A + (chan << 1));
5550e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		dev_private->ao_readback[chan] = (data[0] & s->maxdata);
5560e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	}
5570e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
5580e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* Update dac with data registers */
5590e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	readw(dev_private->me_regbase + ME_DAC_UPDATE);
5600e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
5610e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	return i;
5620e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes}
5630e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
5640e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes/* Analog output readback */
5650e8db97a04b37960828b273d166e35eac9a1888bMichal Dobesstatic int me_ao_insn_read(struct comedi_device *dev,
5660e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes			   struct comedi_subdevice *s, struct comedi_insn *insn,
5670e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes			   unsigned int *data)
5680e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes{
5690e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	int i;
5700e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
5710e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	for (i = 0; i < insn->n; i++) {
5720e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		data[i] =
5730e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		    dev_private->ao_readback[CR_CHAN((&insn->chanspec)[i])];
5740e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	}
5750e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
5760e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	return 1;
5770e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes}
5780e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
5790e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes/*
5800e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes * ------------------------------------------------------------------
5810a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral *
5820a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral * INITIALISATION SECTION
5830a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral *
5840e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes * ------------------------------------------------------------------
5850e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes */
5860e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
5870e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes/* Xilinx firmware download for card: ME-2600i */
5880e8db97a04b37960828b273d166e35eac9a1888bMichal Dobesstatic int me2600_xilinx_download(struct comedi_device *dev,
5890e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes				  unsigned char *me2600_firmware,
5900e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes				  unsigned int length)
5910e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes{
5920e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	unsigned int value;
5930e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	unsigned int file_length;
5940e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	unsigned int i;
5950e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
5960e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* disable irq's on PLX */
5972696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	writel(0x00, dev_private->plx_regbase + PLX_INTCSR);
5980e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
5990e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* First, make a dummy read to reset xilinx */
6000e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	value = readw(dev_private->me_regbase + XILINX_DOWNLOAD_RESET);
6010e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
6020e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* Wait until reset is over */
6030e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	sleep(1);
6040e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
6050e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* Write a dummy value to Xilinx */
6060e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	writeb(0x00, dev_private->me_regbase + 0x0);
6070e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	sleep(1);
6080e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
6090e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/*
61071b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	 * Format of the firmware
61134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	 * Build longs from the byte-wise coded header
6120e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	 * Byte 1-3:   length of the array
6130e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	 * Byte 4-7:   version
614790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton	 * Byte 8-11:  date
6150e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	 * Byte 12-15: reserved
6160e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	 */
6170e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	if (length < 16)
6180e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		return -EINVAL;
6190e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	file_length = (((unsigned int)me2600_firmware[0] & 0xff) << 24) +
6205f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	    (((unsigned int)me2600_firmware[1] & 0xff) << 16) +
6210e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	    (((unsigned int)me2600_firmware[2] & 0xff) << 8) +
6220e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	    ((unsigned int)me2600_firmware[3] & 0xff);
6230e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
6240e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/*
6250e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	 * Loop for writing firmware byte by byte to xilinx
6260e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	 * Firmware data start at offfset 16
6275f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	 */
6280a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	for (i = 0; i < file_length; i++)
6290a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		writeb((me2600_firmware[16 + i] & 0xff),
6300e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		       dev_private->me_regbase + 0x0);
6310e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
6320e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* Write 5 dummy values to xilinx */
6330e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	for (i = 0; i < 5; i++)
6340e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		writeb(0x00, dev_private->me_regbase + 0x0);
6350e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
6362696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	/* Test if there was an error during download -> INTB was thrown */
6370e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	value = readl(dev_private->plx_regbase + PLX_INTCSR);
6380e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	if (value & 0x20) {
6390e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		/* Disable interrupt */
6400e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		writel(0x00, dev_private->plx_regbase + PLX_INTCSR);
6410e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		printk(KERN_ERR "comedi%d: Xilinx download failed\n",
6420e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		       dev->minor);
6430e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		return -EIO;
6440e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	}
6450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
6465f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	/* Wait until the Xilinx is ready for real work */
6470a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	sleep(1);
6480a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
6490a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	/* Enable PLX-Interrupts */
6500a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	writel(0x43, dev_private->plx_regbase + PLX_INTCSR);
6510a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
6520a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	return 0;
6530e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes}
6540e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
6550a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral/* Reset device */
6560e8db97a04b37960828b273d166e35eac9a1888bMichal Dobesstatic int me_reset(struct comedi_device *dev)
6570e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes{
6580e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* Reset board */
6590e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	writew(0x00, dev_private->me_regbase + ME_CONTROL_1);
6600e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	writew(0x00, dev_private->me_regbase + ME_CONTROL_2);
6610e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	writew(0x00, dev_private->me_regbase + ME_RESET_INTERRUPT);
6620e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	writew(0x00, dev_private->me_regbase + ME_DAC_CONTROL);
6630e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
6640a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	/* Save values in the board context */
6650e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	dev_private->dac_control = 0;
6660e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	dev_private->control_1 = 0;
6670e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	dev_private->control_2 = 0;
668ec14016e751106499ef237efc1000a424f53e372Jason Wong
6690e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	return 0;
670ec14016e751106499ef237efc1000a424f53e372Jason Wong}
6710e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
6722696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton/*
6730e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes * Attach
6740a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral *
6750a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral * - Register PCI device
6760a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral * - Declare device driver capability
6770a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral */
6780e8db97a04b37960828b273d166e35eac9a1888bMichal Dobesstatic int me_attach(struct comedi_device *dev, struct comedi_devconfig *it)
6792696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton{
6800e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	struct pci_dev *pci_device = NULL;
6810e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	struct comedi_subdevice *subdevice;
6820e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	struct me_board *board;
6830e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	resource_size_t plx_regbase_tmp;
6840e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	unsigned long plx_regbase_size_tmp;
6850e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	resource_size_t me_regbase_tmp;
6860e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	unsigned long me_regbase_size_tmp;
6870e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	resource_size_t swap_regbase_tmp;
6882696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	unsigned long swap_regbase_size_tmp;
6890e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	resource_size_t regbase_tmp;
6900e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	int result, error, i;
6910e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
6920e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* Allocate private memory */
6930e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	if (alloc_private(dev, sizeof(struct me_private_data)) < 0)
6940e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		return -ENOMEM;
6950e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
6960e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* Probe the device to determine what device in the series it is. */
6970a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	for_each_pci_dev(pci_device) {
6980a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		if (pci_device->vendor == PCI_VENDOR_ID_MEILHAUS) {
6990e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes			for (i = 0; i < me_board_nbr; i++) {
7000e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes				if (me_boards[i].device_id ==
7010e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes				    pci_device->device) {
7020e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes					/*
7030e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes					 * was a particular bus/slot requested?
7040e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes					 */
7050e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes					if ((it->options[0] != 0)
7060e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes					    || (it->options[1] != 0)) {
7070e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes						/*
7080e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes						 * are we on the wrong bus/slot?
7090e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes						 */
7100e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes						if (pci_device->bus->number !=
7110e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes						    it->options[0]
7125f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman						    ||
7130a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						    PCI_SLOT(pci_device->devfn)
7140a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						    != it->options[1]) {
7150a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral							continue;
7160a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral						}
7170a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					}
7180e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
7190e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes					dev->board_ptr = me_boards + i;
7200a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					board =
7210e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes					    (struct me_board *)dev->board_ptr;
7220e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes					dev_private->pci_device = pci_device;
7230e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes					goto found;
7240e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes				}
7250e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes			}
7260e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		}
7270a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	}
7280e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
7290e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	printk(KERN_ERR
7300e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	       "comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
7310e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	       dev->minor, it->options[0], it->options[1]);
7320e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	return -EIO;
7330e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
7340e8db97a04b37960828b273d166e35eac9a1888bMichal Dobesfound:
73561283d227c6b39e30afc6346db099521b0b64fa1Ian Abbott	printk(KERN_INFO "comedi%d: found %s at PCI bus %d, slot %d\n",
7360e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	       dev->minor, me_boards[i].name,
7370e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	       pci_device->bus->number, PCI_SLOT(pci_device->devfn));
7380e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
7390e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* Enable PCI device and request PCI regions */
7400e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	if (comedi_pci_enable(pci_device, ME_DRIVER_NAME) < 0) {
7410e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		printk(KERN_ERR "comedi%d: Failed to enable PCI device and "
7420e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		       "request regions\n", dev->minor);
7430e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		return -EIO;
7440e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	}
74571b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton
74634c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	/* Set data in device structure */
7470e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	dev->board_name = board->name;
7480e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
7490e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* Read PLX register base address [PCI_BASE_ADDRESS #0]. */
7500e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	plx_regbase_tmp = pci_resource_start(pci_device, 0);
7510e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	plx_regbase_size_tmp = pci_resource_len(pci_device, 0);
7525f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	dev_private->plx_regbase =
7530a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	    ioremap(plx_regbase_tmp, plx_regbase_size_tmp);
7540e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	dev_private->plx_regbase_size = plx_regbase_size_tmp;
7550e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	if (!dev_private->plx_regbase) {
7560e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		printk("comedi%d: Failed to remap I/O memory\n", dev->minor);
7570e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		return -ENOMEM;
7580e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	}
7590e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
7605f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman	/* Read Swap base address [PCI_BASE_ADDRESS #5]. */
7610a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
7620a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	swap_regbase_tmp = pci_resource_start(pci_device, 5);
7630e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	swap_regbase_size_tmp = pci_resource_len(pci_device, 5);
7640e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
7650e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	if (!swap_regbase_tmp)
7660e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		printk(KERN_ERR "comedi%d: Swap not present\n", dev->minor);
7670e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
7680e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/*---------------------------------------------- Workaround start ---*/
7690e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	if (plx_regbase_tmp & 0x0080) {
770790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton		printk(KERN_ERR "comedi%d: PLX-Bug detected\n", dev->minor);
771790c55415aa31f4c732729f94d2c3a54f7d3bfc2Bill Pemberton
7720e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		if (swap_regbase_tmp) {
7730e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes			regbase_tmp = plx_regbase_tmp;
7740e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes			plx_regbase_tmp = swap_regbase_tmp;
7750e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes			swap_regbase_tmp = regbase_tmp;
7760e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
7770e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes			result = pci_write_config_dword(pci_device,
7780e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes							PCI_BASE_ADDRESS_0,
7790e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes							plx_regbase_tmp);
7800e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes			if (result != PCIBIOS_SUCCESSFUL)
7810e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes				return -EIO;
7820e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
78397feeef5c55fe783e6f01d4dec3fd0926e60b0d8Mark			result = pci_write_config_dword(pci_device,
78497feeef5c55fe783e6f01d4dec3fd0926e60b0d8Mark							PCI_BASE_ADDRESS_5,
7850e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes							swap_regbase_tmp);
7860e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes			if (result != PCIBIOS_SUCCESSFUL)
7870e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes				return -EIO;
7880e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		} else {
7890e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes			plx_regbase_tmp -= 0x80;
7902696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton			result = pci_write_config_dword(pci_device,
7910e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes							PCI_BASE_ADDRESS_0,
7920e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes							plx_regbase_tmp);
7930e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes			if (result != PCIBIOS_SUCCESSFUL)
7940e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes				return -EIO;
7950e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		}
7960e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	}
7970e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/*--------------------------------------------- Workaround end -----*/
7980e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
79970265d24e3404fe798b6edd55a02016b1edb49d7Jiri Slaby	/* Read Meilhaus register base address [PCI_BASE_ADDRESS #2]. */
8000e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
80171b5f4f11971dea972832ad63a994c7e5b45db6bBill Pemberton	me_regbase_tmp = pci_resource_start(pci_device, 2);
8020e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	me_regbase_size_tmp = pci_resource_len(pci_device, 2);
8030e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	dev_private->me_regbase_size = me_regbase_size_tmp;
8040e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	dev_private->me_regbase = ioremap(me_regbase_tmp, me_regbase_size_tmp);
8052696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	if (!dev_private->me_regbase) {
8062696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton		printk(KERN_ERR "comedi%d: Failed to remap I/O memory\n",
8070e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		       dev->minor);
8082696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton		return -ENOMEM;
8092696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	}
8100e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* Download firmware and reset card */
8110e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	if (board->device_id == ME2600_DEVICE_ID) {
8120e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		unsigned char *aux_data;
8130e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		int aux_len;
8142696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton
8150e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		aux_data = comedi_aux_data(it->options, 0);
8160e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		aux_len = it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
8172696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton
8180e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		if (!aux_data || aux_len < 1) {
8190e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes			comedi_error(dev, "You must provide me2600 firmware "
8200e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes				     "using the --init-data option of "
8210e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes				     "comedi_config");
8220e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes			return -EINVAL;
8230e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		}
8242696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton		me2600_xilinx_download(dev, aux_data, aux_len);
8250e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	}
8260e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
8270e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	me_reset(dev);
8282696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton
8290e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	/* device driver capabilities */
8300e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	error = alloc_subdevices(dev, 3);
8310e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	if (error < 0)
8320e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		return error;
8330e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
8340e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	subdevice = dev->subdevices + 0;
8350e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	subdevice->type = COMEDI_SUBD_AI;
8360e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	subdevice->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_CMD_READ;
8370e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	subdevice->n_chan = board->ai_channel_nbr;
8380e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	subdevice->maxdata = board->ai_resolution_mask;
8390e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	subdevice->len_chanlist = board->ai_channel_nbr;
840da91b2692e0939b307f9047192d2b9fe07793e7aBill Pemberton	subdevice->range_table = board->ai_range_list;
8410a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	subdevice->cancel = me_ai_cancel;
8420e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	subdevice->insn_read = me_ai_insn_read;
84348b1aff5b93521c5ad90842bef52b218ac50a4abIan Abbott	subdevice->do_cmdtest = me_ai_do_cmd_test;
8440e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	subdevice->do_cmd = me_ai_do_cmd;
8450e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
8460e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	subdevice = dev->subdevices + 1;
8470e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	subdevice->type = COMEDI_SUBD_AO;
8482696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	subdevice->subdev_flags = SDF_WRITEABLE | SDF_COMMON;
8490e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	subdevice->n_chan = board->ao_channel_nbr;
8500e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	subdevice->maxdata = board->ao_resolution_mask;
8510a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral	subdevice->len_chanlist = board->ao_channel_nbr;
8520e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	subdevice->range_table = board->ao_range_list;
8530e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	subdevice->insn_read = me_ao_insn_read;
8540e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	subdevice->insn_write = me_ao_insn_write;
8550a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral
8560e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	subdevice = dev->subdevices + 2;
8570e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	subdevice->type = COMEDI_SUBD_DIO;
8580e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	subdevice->subdev_flags = SDF_READABLE | SDF_WRITEABLE;
8590e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	subdevice->n_chan = board->dio_channel_nbr;
8600e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	subdevice->maxdata = 1;
8610e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	subdevice->len_chanlist = board->dio_channel_nbr;
8620e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	subdevice->range_table = &range_digital;
8630e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	subdevice->insn_bits = me_dio_insn_bits;
8640e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	subdevice->insn_config = me_dio_insn_config;
8650e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	subdevice->io_bits = 0;
8660e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
8670e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	printk(KERN_INFO "comedi%d: " ME_DRIVER_NAME " attached.\n",
8682696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	       dev->minor);
8690e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	return 0;
8700e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes}
8710e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
8720e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes/* Detach */
8730e8db97a04b37960828b273d166e35eac9a1888bMichal Dobesstatic int me_detach(struct comedi_device *dev)
8740e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes{
875ec14016e751106499ef237efc1000a424f53e372Jason Wong	if (dev_private) {
8760e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		if (dev_private->me_regbase) {
877ec14016e751106499ef237efc1000a424f53e372Jason Wong			me_reset(dev);
878ec14016e751106499ef237efc1000a424f53e372Jason Wong			iounmap(dev_private->me_regbase);
8790e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		}
880ec14016e751106499ef237efc1000a424f53e372Jason Wong		if (dev_private->plx_regbase)
8810e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes			iounmap(dev_private->plx_regbase);
8820e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		if (dev_private->pci_device) {
8830e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes			if (dev_private->plx_regbase_size)
8840e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes				comedi_pci_disable(dev_private->pci_device);
8850e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
8860e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes			pci_dev_put(dev_private->pci_device);
8870e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes		}
8880e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	}
8890e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes	return 0;
8900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral}
8910e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes
8920e8db97a04b37960828b273d166e35eac9a1888bMichal DobesMODULE_AUTHOR("Comedi http://www.comedi.org");
8930e8db97a04b37960828b273d166e35eac9a1888bMichal DobesMODULE_DESCRIPTION("Comedi low-level driver");
8940e8db97a04b37960828b273d166e35eac9a1888bMichal DobesMODULE_LICENSE("GPL");
8950e8db97a04b37960828b273d166e35eac9a1888bMichal Dobes