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