1110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil/***************************************************************************
2110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil *                                                                         *
3110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil *  comedi/drivers/unioxx5.c                                               *
4110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil *  Driver for Fastwel UNIOxx-5 (analog and digital i/o) boards.           *
5110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil *                                                                         *
6110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil *  Copyright (C) 2006 Kruchinin Daniil (asgard) [asgard@etersoft.ru]      *
7110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil *                                                                         *
8110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil *  COMEDI - Linux Control and Measurement Device Interface                *
9110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil *  Copyright (C) 1998,2000 David A. Schleef <ds@schleef.org>              *
10110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil *                                                                         *
11110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil *  This program is free software; you can redistribute it and/or modify   *
12110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil *  it under the terms of the GNU General Public License as published by   *
13110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil *  the Free Software Foundation; either version 2 of the License, or      *
14110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil *  (at your option) any later version.                                    *
15110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil *                                                                         *
16110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil *  This program is distributed in the hope that it will be useful,        *
17110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
18110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
19110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil *  GNU General Public License for more details.                           *
20110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil *                                                                         *
21110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil *  You should have received a copy of the GNU General Public License      *
22110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil *  along with this program; if not, write to the Free Software            *
23110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              *
24110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil *                                                                         *
25110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil ***************************************************************************/
26110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil/*
27110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
28110526ed6b1f0076df899ca553f47b316432f817Kruchinin DaniilDriver: unioxx5
29110526ed6b1f0076df899ca553f47b316432f817Kruchinin DaniilDescription: Driver for Fastwel UNIOxx-5 (analog and digital i/o) boards.
30110526ed6b1f0076df899ca553f47b316432f817Kruchinin DaniilAuthor: Kruchinin Daniil (asgard) <asgard@etersoft.ru>
31110526ed6b1f0076df899ca553f47b316432f817Kruchinin DaniilStatus: unknown
32110526ed6b1f0076df899ca553f47b316432f817Kruchinin DaniilUpdated: 2006-10-09
33110526ed6b1f0076df899ca553f47b316432f817Kruchinin DaniilDevices: [Fastwel] UNIOxx-5 (unioxx5),
34110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
35110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil This card supports digital and analog I/O. It written for g01
36110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil subdevices only.
37110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil channels range: 0 .. 23 dio channels
38110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil and 0 .. 11 analog modules range
39110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil During attaching unioxx5 module displays modules identifiers
40110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil (see dmesg after comedi_config) in format:
41110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil | [module_number] module_id |
42110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
43110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil*/
44110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
45110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil#include "../comedidev.h"
46110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil#include <linux/ioport.h>
475a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
48110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
49110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil#define DRIVER_NAME "unioxx5"
50110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil#define UNIOXX5_SIZE 0x10
51110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil#define UNIOXX5_SUBDEV_BASE 0xA000	/* base addr of first subdev */
52110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil#define UNIOXX5_SUBDEV_ODDS 0x400
53110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
54110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil/* modules types */
55110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil#define MODULE_DIGITAL 0
56110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil#define MODULE_OUTPUT_MASK 0x80	/* analog input/output */
57110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
58110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil/* constants for digital i/o */
59110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil#define UNIOXX5_NUM_OF_CHANS 24
60110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
61110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil/* constants for analog i/o */
62110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil#define TxBE  0x10		/* transmit buffer enable */
63110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil#define RxCA  0x20		/* 1 receive character available */
64110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil#define Rx2CA 0x40		/* 2 receive character available */
65110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil#define Rx4CA 0x80		/* 4 receive character available */
66110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
67110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil/* bytes mask errors */
68110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil#define Rx2CA_ERR_MASK 0x04	/* 2 bytes receiving error */
69110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil#define Rx4CA_ERR_MASK 0x08	/* 4 bytes receiving error */
70110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
71110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil/* channel modes */
72110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil#define ALL_2_INPUT  0		/* config all digital channels to input */
73110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil#define ALL_2_OUTPUT 1		/* config all digital channels to output */
74110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
75110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil/* 'private' structure for each subdevice */
7633a4640f312c4ee583470e7d4b1aaed5026438f6Bill Pembertonstruct unioxx5_subd_priv {
77110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	int usp_iobase;
7833e73e0085089a2653cd638c990996b90833819bRavishankar	/* 12 modules. each can be 70L or 73L */
7933e73e0085089a2653cd638c990996b90833819bRavishankar	unsigned char usp_module_type[12];
8033e73e0085089a2653cd638c990996b90833819bRavishankar	/* for saving previous written value for analog modules */
8133e73e0085089a2653cd638c990996b90833819bRavishankar	unsigned char usp_extra_data[12][4];
82110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	unsigned char usp_prev_wr_val[3];	/* previous written value */
83110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	unsigned char usp_prev_cn_val[3];	/* previous channel value */
8433a4640f312c4ee583470e7d4b1aaed5026438f6Bill Pemberton};
85110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
860a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int unioxx5_attach(struct comedi_device *dev,
870a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			  struct comedi_devconfig *it);
880a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int unioxx5_subdev_write(struct comedi_device *dev,
890a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				struct comedi_subdevice *subdev,
900a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				struct comedi_insn *insn, unsigned int *data);
910a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int unioxx5_subdev_read(struct comedi_device *dev,
920a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_subdevice *subdev,
930a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_insn *insn, unsigned int *data);
940a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int unioxx5_insn_config(struct comedi_device *dev,
950a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_subdevice *subdev,
960a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_insn *insn, unsigned int *data);
97da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int unioxx5_detach(struct comedi_device *dev);
980a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int __unioxx5_subdev_init(struct comedi_subdevice *subdev,
990a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				 int subdev_iobase, int minor);
1000a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int __unioxx5_digital_write(struct unioxx5_subd_priv *usp,
1010a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				   unsigned int *data, int channel, int minor);
1020a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int __unioxx5_digital_read(struct unioxx5_subd_priv *usp,
1030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  unsigned int *data, int channel, int minor);
1042696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton/* static void __unioxx5_digital_config(struct unioxx5_subd_priv* usp, int mode); */
1050a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int __unioxx5_analog_write(struct unioxx5_subd_priv *usp,
1060a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  unsigned int *data, int channel, int minor);
1070a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int __unioxx5_analog_read(struct unioxx5_subd_priv *usp,
1080a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				 unsigned int *data, int channel, int minor);
109110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniilstatic int __unioxx5_define_chan_offset(int chan_num);
110da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void __unioxx5_analog_config(struct unioxx5_subd_priv *usp, int channel);
111110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
112139dfbdfacb02e3ef3df936d2fabd1ad5f14ea88Bill Pembertonstatic struct comedi_driver unioxx5_driver = {
11368c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.driver_name = DRIVER_NAME,
11468c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.module = THIS_MODULE,
11568c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.attach = unioxx5_attach,
11668c3dbff9fc9f25872408d0e95980d41733d48d0Bill Pemberton	.detach = unioxx5_detach
117110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil};
118110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
1197114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasstatic int __init unioxx5_driver_init_module(void)
1207114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas{
1217114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas	return comedi_driver_register(&unioxx5_driver);
1227114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas}
1237114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas
1247114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasstatic void __exit unioxx5_driver_cleanup_module(void)
1257114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas{
1267114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas	comedi_driver_unregister(&unioxx5_driver);
1277114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas}
1287114a28011f9d5f3d981731ad341177c21f9d948Arun Thomas
1297114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasmodule_init(unioxx5_driver_init_module);
1307114a28011f9d5f3d981731ad341177c21f9d948Arun Thomasmodule_exit(unioxx5_driver_cleanup_module);
131110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
1320a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int unioxx5_attach(struct comedi_device *dev,
1330a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			  struct comedi_devconfig *it)
134110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil{
135110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	int iobase, i, n_subd;
136110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	int id, num, ba;
137110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
138110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	iobase = it->options[0];
139110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
140110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	dev->board_name = DRIVER_NAME;
141110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	dev->iobase = iobase;
142110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	iobase += UNIOXX5_SUBDEV_BASE;
143110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
144110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	/* defining number of subdevices and getting they types (it must be 'g01')  */
145110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	for (i = n_subd = 0, ba = iobase; i < 4; i++, ba += UNIOXX5_SUBDEV_ODDS) {
146110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		id = inb(ba + 0xE);
147110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		num = inb(ba + 0xF);
148110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
149110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		if (id != 'g' || num != 1)
150110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil			continue;
151110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
152110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		n_subd++;
153110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	}
154110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
155110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	/* unioxx5 can has from two to four subdevices */
156110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	if (n_subd < 2) {
157110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		printk(KERN_ERR
1580a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "your card must has at least 2 'g01' subdevices\n");
159110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		return -1;
160110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	}
161110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
162110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	if (alloc_subdevices(dev, n_subd) < 0) {
163110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		printk(KERN_ERR "out of memory\n");
164110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		return -ENOMEM;
165110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	}
166110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
167110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	/* initializing each of for same subdevices */
168110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	for (i = 0; i < n_subd; i++, iobase += UNIOXX5_SUBDEV_ODDS) {
169110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		if (__unioxx5_subdev_init(&dev->subdevices[i], iobase,
1700a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral					  dev->minor) < 0)
171110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil			return -1;
172110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	}
173110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
17433e73e0085089a2653cd638c990996b90833819bRavishankar	printk(KERN_INFO "attached\n");
175110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	return 0;
176110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil}
177110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
1780a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int unioxx5_subdev_read(struct comedi_device *dev,
1790a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_subdevice *subdev,
1800a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_insn *insn, unsigned int *data)
181110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil{
18233a4640f312c4ee583470e7d4b1aaed5026438f6Bill Pemberton	struct unioxx5_subd_priv *usp = subdev->private;
183110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	int channel, type;
184110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
185110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	channel = CR_CHAN(insn->chanspec);
18633e73e0085089a2653cd638c990996b90833819bRavishankar	/* defining module type(analog or digital) */
18733e73e0085089a2653cd638c990996b90833819bRavishankar	type = usp->usp_module_type[channel / 2];
188110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
189110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	if (type == MODULE_DIGITAL) {
190110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		if (!__unioxx5_digital_read(usp, data, channel, dev->minor))
191110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil			return -1;
192110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	} else {
193110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		if (!__unioxx5_analog_read(usp, data, channel, dev->minor))
194110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil			return -1;
195110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	}
196110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
197110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	return 1;
198110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil}
199110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
2000a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int unioxx5_subdev_write(struct comedi_device *dev,
2010a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				struct comedi_subdevice *subdev,
2020a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				struct comedi_insn *insn, unsigned int *data)
203110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil{
20433a4640f312c4ee583470e7d4b1aaed5026438f6Bill Pemberton	struct unioxx5_subd_priv *usp = subdev->private;
205110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	int channel, type;
206110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
207110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	channel = CR_CHAN(insn->chanspec);
20833e73e0085089a2653cd638c990996b90833819bRavishankar	/* defining module type(analog or digital) */
20933e73e0085089a2653cd638c990996b90833819bRavishankar	type = usp->usp_module_type[channel / 2];
210110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
211110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	if (type == MODULE_DIGITAL) {
212110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		if (!__unioxx5_digital_write(usp, data, channel, dev->minor))
213110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil			return -1;
214110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	} else {
215110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		if (!__unioxx5_analog_write(usp, data, channel, dev->minor))
216110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil			return -1;
217110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	}
218110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
219110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	return 1;
220110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil}
221110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
222110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil/* for digital modules only */
2230a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int unioxx5_insn_config(struct comedi_device *dev,
2240a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_subdevice *subdev,
2250a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral			       struct comedi_insn *insn, unsigned int *data)
226110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil{
227110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	int channel_offset, flags, channel = CR_CHAN(insn->chanspec), type;
22833a4640f312c4ee583470e7d4b1aaed5026438f6Bill Pemberton	struct unioxx5_subd_priv *usp = subdev->private;
229110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	int mask = 1 << (channel & 0x07);
230110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
231110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	type = usp->usp_module_type[channel / 2];
232110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
233110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	if (type != MODULE_DIGITAL) {
234110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		printk(KERN_ERR
2350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi%d: channel configuration accessible only for digital modules\n",
2360a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev->minor);
237110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		return -1;
238110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	}
239110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
240c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	channel_offset = __unioxx5_define_chan_offset(channel);
241c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	if (channel_offset < 0) {
242110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		printk(KERN_ERR
2430a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi%d: undefined channel %d. channel range is 0 .. 23\n",
2440a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       dev->minor, channel);
245110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		return -1;
246110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	}
247110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
248110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	/* gets previously written value */
249110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	flags = usp->usp_prev_cn_val[channel_offset - 1];
250110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
251110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	switch (*data) {
252110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	case COMEDI_INPUT:
253110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		flags &= ~mask;
254110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		break;
255110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	case COMEDI_OUTPUT:
256110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		flags |= mask;
257110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		break;
258110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	default:
259110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		printk(KERN_ERR "comedi%d: unknown flag\n", dev->minor);
260110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		return -1;
261110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	}
262110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
263110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	/*                                                        *\
264110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	 * sets channels buffer to 1(after this we are allowed to *
265110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	 * change channel type on input or output)                *
266110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	 \*                                                        */
267110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	outb(1, usp->usp_iobase + 0);
26833e73e0085089a2653cd638c990996b90833819bRavishankar	/* changes type of _one_ channel */
26933e73e0085089a2653cd638c990996b90833819bRavishankar	outb(flags, usp->usp_iobase + channel_offset);
27033e73e0085089a2653cd638c990996b90833819bRavishankar	/* sets channels bank to 0(allows directly input/output) */
27133e73e0085089a2653cd638c990996b90833819bRavishankar	outb(0, usp->usp_iobase + 0);
27233e73e0085089a2653cd638c990996b90833819bRavishankar	/* saves written value */
27333e73e0085089a2653cd638c990996b90833819bRavishankar	usp->usp_prev_cn_val[channel_offset - 1] = flags;
274110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
275110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	return 0;
276110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil}
277110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
278da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic int unioxx5_detach(struct comedi_device *dev)
279110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil{
280110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	int i;
28134c43922e62708d45e9660eee4b4f1fb7b4bf2c7Bill Pemberton	struct comedi_subdevice *subdev;
28233a4640f312c4ee583470e7d4b1aaed5026438f6Bill Pemberton	struct unioxx5_subd_priv *usp;
283110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
284110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	for (i = 0; i < dev->n_subdevices; i++) {
285110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		subdev = &dev->subdevices[i];
286110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		usp = subdev->private;
287110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		release_region(usp->usp_iobase, UNIOXX5_SIZE);
288110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		kfree(subdev->private);
289110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	}
290110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
291110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	return 0;
292110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil}
293110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
294110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil/* initializing subdevice with given address */
2950a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int __unioxx5_subdev_init(struct comedi_subdevice *subdev,
2960a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				 int subdev_iobase, int minor)
297110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil{
29833a4640f312c4ee583470e7d4b1aaed5026438f6Bill Pemberton	struct unioxx5_subd_priv *usp;
299110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	int i, to, ndef_flag = 0;
300110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
301110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	if (!request_region(subdev_iobase, UNIOXX5_SIZE, DRIVER_NAME)) {
302110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		printk(KERN_ERR "comedi%d: I/O port conflict\n", minor);
303110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		return -EIO;
304110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	}
305110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
306324148788bf3744d90fb6894ec5744eb0ca91b74Julia Lawall	usp = kzalloc(sizeof(*usp), GFP_KERNEL);
307c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton
308c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	if (usp == NULL) {
30981a149561ed56a23ee84a783da0aec53f1077b8dMasanari Iida		printk(KERN_ERR "comedi%d: error! --> out of memory!\n", minor);
310110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		return -1;
311110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	}
312110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
313110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	usp->usp_iobase = subdev_iobase;
31433e73e0085089a2653cd638c990996b90833819bRavishankar	printk(KERN_INFO "comedi%d: |", minor);
315110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
316110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	/* defining modules types */
317110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	for (i = 0; i < 12; i++) {
318110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		to = 10000;
319110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
320110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		__unioxx5_analog_config(usp, i * 2);
32133e73e0085089a2653cd638c990996b90833819bRavishankar		/* sends channel number to card */
32233e73e0085089a2653cd638c990996b90833819bRavishankar		outb(i + 1, subdev_iobase + 5);
323110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		outb('H', subdev_iobase + 6);	/* requests EEPROM world */
3246fd071cccf4127f1e81767a819720d8915b2a800John Sheehan		while (!(inb(subdev_iobase + 0) & TxBE))
3256fd071cccf4127f1e81767a819720d8915b2a800John Sheehan			;	/* waits while writting will be allowed */
326110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		outb(0, subdev_iobase + 6);
327110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
328110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		/* waits while reading of two bytes will be allowed */
329110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		while (!(inb(subdev_iobase + 0) & Rx2CA)) {
330110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil			if (--to <= 0) {
331110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil				ndef_flag = 1;
332110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil				break;
333110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil			}
334110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		}
335110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
336110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		if (ndef_flag) {
337110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil			usp->usp_module_type[i] = 0;
338110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil			ndef_flag = 0;
339110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		} else
340110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil			usp->usp_module_type[i] = inb(subdev_iobase + 6);
341110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
342110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		printk(" [%d] 0x%02x |", i, usp->usp_module_type[i]);
3435f74ea14c07fee91d3bdbaad88bff6264c6200e6Greg Kroah-Hartman		udelay(1);
344110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	}
345110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
346110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	printk("\n");
347110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
348110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	/* initial subdevice for digital or analog i/o */
349110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	subdev->type = COMEDI_SUBD_DIO;
350110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	subdev->private = usp;
351110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	subdev->subdev_flags = SDF_READABLE | SDF_WRITABLE;
352110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	subdev->n_chan = UNIOXX5_NUM_OF_CHANS;
353110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	subdev->maxdata = 0xFFF;
354110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	subdev->range_table = &range_digital;
355110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	subdev->insn_read = unioxx5_subdev_read;
356110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	subdev->insn_write = unioxx5_subdev_write;
35733e73e0085089a2653cd638c990996b90833819bRavishankar	/* for digital modules only!!! */
35833e73e0085089a2653cd638c990996b90833819bRavishankar	subdev->insn_config = unioxx5_insn_config;
359110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
36033e73e0085089a2653cd638c990996b90833819bRavishankar	printk(KERN_INFO "subdevice configured\n");
361110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
362110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	return 0;
363110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil}
364110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
3650a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int __unioxx5_digital_write(struct unioxx5_subd_priv *usp,
3660a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				   unsigned int *data, int channel, int minor)
367110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil{
368110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	int channel_offset, val;
369110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	int mask = 1 << (channel & 0x07);
370110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
371c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	channel_offset = __unioxx5_define_chan_offset(channel);
372c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	if (channel_offset < 0) {
373110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		printk(KERN_ERR
3740a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi%d: undefined channel %d. channel range is 0 .. 23\n",
3750a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       minor, channel);
376110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		return 0;
377110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	}
378110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
37933e73e0085089a2653cd638c990996b90833819bRavishankar	/* getting previous written value */
38033e73e0085089a2653cd638c990996b90833819bRavishankar	val = usp->usp_prev_wr_val[channel_offset - 1];
381110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
382110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	if (*data)
383110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		val |= mask;
384110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	else
385110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		val &= ~mask;
386110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
387110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	outb(val, usp->usp_iobase + channel_offset);
38833e73e0085089a2653cd638c990996b90833819bRavishankar	/* saving new written value */
38933e73e0085089a2653cd638c990996b90833819bRavishankar	usp->usp_prev_wr_val[channel_offset - 1] = val;
390110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
391110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	return 1;
392110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil}
393110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
394110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil/* function for digital reading */
3950a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int __unioxx5_digital_read(struct unioxx5_subd_priv *usp,
3960a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  unsigned int *data, int channel, int minor)
397110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil{
398110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	int channel_offset, mask = 1 << (channel & 0x07);
399110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
400c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	channel_offset = __unioxx5_define_chan_offset(channel);
401c3744138715045adb316284ee7a1e608f0278f6cBill Pemberton	if (channel_offset < 0) {
402110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		printk(KERN_ERR
4030a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi%d: undefined channel %d. channel range is 0 .. 23\n",
4040a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       minor, channel);
405110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		return 0;
406110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	}
407110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
408110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	*data = inb(usp->usp_iobase + channel_offset);
409110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	*data &= mask;
410110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
411110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	if (channel_offset > 1)
412110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		channel -= 2 << channel_offset;	/* this operation is created for correct readed value to 0 or 1 */
413110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	*data >>= channel;
414110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	return 1;
415110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil}
416110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
417110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil#if 0				/* not used? */
418da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void __unioxx5_digital_config(struct unioxx5_subd_priv *usp, int mode)
419110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil{
420110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	int i, mask;
421110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
422110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	mask = (mode == ALL_2_OUTPUT) ? 0xFF : 0x00;
423110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	printk("COMEDI: mode = %d\n", mask);
424110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
425110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	outb(1, usp->usp_iobase + 0);
426110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
427110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	for (i = 0; i < 3; i++)
428110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		outb(mask, usp->usp_iobase + i);
429110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
430110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	outb(0, usp->usp_iobase + 0);
431110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil}
432110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil#endif
433110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
4340a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int __unioxx5_analog_write(struct unioxx5_subd_priv *usp,
4350a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				  unsigned int *data, int channel, int minor)
436110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil{
437110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	int module, i;
438110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
439110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	module = channel / 2;	/* definig module number(0 .. 11) */
440110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	i = (channel % 2) << 1;	/* depends on type of channel (A or B) */
441110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
442110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	/* defining if given module can work on output */
443110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	if (!(usp->usp_module_type[module] & MODULE_OUTPUT_MASK)) {
444110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		printk(KERN_ERR
4450a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi%d: module in position %d with id 0x%0x is for input only!\n",
4460a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       minor, module, usp->usp_module_type[module]);
447110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		return 0;
448110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	}
449110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
450110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	__unioxx5_analog_config(usp, channel);
451110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	/* saving minor byte */
452110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	usp->usp_extra_data[module][i++] = (unsigned char)(*data & 0x00FF);
453110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	/* saving major byte */
454110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	usp->usp_extra_data[module][i] = (unsigned char)((*data & 0xFF00) >> 8);
455110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
4562696fb57e6af653dd8b4df41b16754579f42fc78Bill Pemberton	/* while(!((inb(usp->usp_iobase + 0)) & TxBE)); */
45733e73e0085089a2653cd638c990996b90833819bRavishankar	/* sending module number to card(1 .. 12) */
45833e73e0085089a2653cd638c990996b90833819bRavishankar	outb(module + 1, usp->usp_iobase + 5);
459110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	outb('W', usp->usp_iobase + 6);	/* sends (W)rite command to module */
460110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
461110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	/* sending for bytes to module(one byte per cycle iteration) */
462110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	for (i = 0; i < 4; i++) {
4636fd071cccf4127f1e81767a819720d8915b2a800John Sheehan		while (!((inb(usp->usp_iobase + 0)) & TxBE))
4646fd071cccf4127f1e81767a819720d8915b2a800John Sheehan			;	/* waits while writting will be allowed */
465110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		outb(usp->usp_extra_data[module][i], usp->usp_iobase + 6);
466110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	}
467110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
468110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	return 1;
469110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil}
470110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
4710a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukralstatic int __unioxx5_analog_read(struct unioxx5_subd_priv *usp,
4720a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral				 unsigned int *data, int channel, int minor)
473110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil{
474110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	int module_no, read_ch;
475110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	char control;
476110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
477110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	module_no = channel / 2;
478110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	read_ch = channel % 2;	/* depend on type of channel (A or B) */
479110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
480110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	/* defining if given module can work on input */
481110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	if (usp->usp_module_type[module_no] & MODULE_OUTPUT_MASK) {
482110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		printk(KERN_ERR
4830a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       "comedi%d: module in position %d with id 0x%02x is for output only",
4840a85b6f0ab0d2edb0d41b32697111ce0e4f43496Mithlesh Thukral		       minor, module_no, usp->usp_module_type[module_no]);
485110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		return 0;
486110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	}
487110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
488110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	__unioxx5_analog_config(usp, channel);
48933e73e0085089a2653cd638c990996b90833819bRavishankar	/* sends module number to card(1 .. 12) */
49033e73e0085089a2653cd638c990996b90833819bRavishankar	outb(module_no + 1, usp->usp_iobase + 5);
491110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	outb('V', usp->usp_iobase + 6);	/* sends to module (V)erify command */
492110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	control = inb(usp->usp_iobase);	/* get control register byte */
493110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
494110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	/* waits while reading four bytes will be allowed */
4956fd071cccf4127f1e81767a819720d8915b2a800John Sheehan	while (!((control = inb(usp->usp_iobase + 0)) & Rx4CA))
4966fd071cccf4127f1e81767a819720d8915b2a800John Sheehan		;
497110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
498110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	/* if four bytes readding error occurs - return 0(false) */
499110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	if ((control & Rx4CA_ERR_MASK)) {
500110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		printk("COMEDI: 4 bytes error\n");
501110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		return 0;
502110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	}
503110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
504110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	if (read_ch)
505110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		*data = inw(usp->usp_iobase + 6);	/* channel B */
506110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	else
507110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		*data = inw(usp->usp_iobase + 4);	/* channel A */
508110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
509110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	return 1;
510110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil}
511110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
512110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil/* configure channels for analog i/o (even to output, odd to input) */
513da91b2692e0939b307f9047192d2b9fe07793e7aBill Pembertonstatic void __unioxx5_analog_config(struct unioxx5_subd_priv *usp, int channel)
514110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil{
515110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	int chan_a, chan_b, conf, channel_offset;
516110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
517110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	channel_offset = __unioxx5_define_chan_offset(channel);
518110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	conf = usp->usp_prev_cn_val[channel_offset - 1];
519110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	chan_a = chan_b = 1;
520110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
521110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	/* setting channel A and channel B mask */
522110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	if (channel % 2 == 0) {
523110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		chan_a <<= channel & 0x07;
524110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		chan_b <<= (channel + 1) & 0x07;
525110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	} else {
526110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		chan_a <<= (channel - 1) & 0x07;
527110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		chan_b <<= channel & 0x07;
528110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	}
529110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
530110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	conf |= chan_a;		/* even channel ot output */
531110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	conf &= ~chan_b;	/* odd channel to input */
532110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
533110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	outb(1, usp->usp_iobase + 0);
534110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	outb(conf, usp->usp_iobase + channel_offset);
535110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	outb(0, usp->usp_iobase + 0);
536110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
537110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	usp->usp_prev_cn_val[channel_offset - 1] = conf;
538110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil}
539110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
540110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil/*                                                    *\
541110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil * this function defines if the given channel number  *
542110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil * enters in default numeric interspace(from 0 to 23) *
543110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil * and it returns address offset for usage needed     *
544110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil * channel.                                           *
545110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil\*                                                    */
546110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
547110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniilstatic int __unioxx5_define_chan_offset(int chan_num)
548110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil{
549110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
550110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	if (chan_num < 0 || chan_num > 23)
551110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil		return -1;
552110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil
553110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil	return (chan_num >> 3) + 1;
554110526ed6b1f0076df899ca553f47b316432f817Kruchinin Daniil}
55590f703d30dd3e0c16ff80f35e34e511385a05ad5Arun Thomas
55690f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_AUTHOR("Comedi http://www.comedi.org");
55790f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_DESCRIPTION("Comedi low-level driver");
55890f703d30dd3e0c16ff80f35e34e511385a05ad5Arun ThomasMODULE_LICENSE("GPL");
559