From d1d4133e5fc546c1980320bcd037c720ecd3acbf Mon Sep 17 00:00:00 2001 From: David Schleef Date: Tue, 17 Feb 2009 16:25:39 -0800 Subject: Staging: comedi: add poc driver From: David A. Schleef mini-drivers for POC (Piece of crap) boards. Currently supports: Keithley Metrabyte DAC-02 Advantech PCL-733, PCL-734 From: David Schleef Cc: Frank Mori Hess Cc: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/poc.c | 247 +++++++++++++++++++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 drivers/staging/comedi/drivers/poc.c --- /dev/null +++ b/drivers/staging/comedi/drivers/poc.c @@ -0,0 +1,247 @@ +/* + comedi/drivers/poc.c + Mini-drivers for POC (Piece of Crap) boards + Copyright (C) 2000 Frank Mori Hess + Copyright (C) 2001 David A. Schleef + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +/* +Driver: poc +Description: Generic driver for very simple devices +Author: ds +Devices: [Keithley Metrabyte] DAC-02 (dac02), [Advantech] PCL-733 (pcl733), + PCL-734 (pcl734) +Updated: Sat, 16 Mar 2002 17:34:48 -0800 +Status: unknown + +This driver is indended to support very simple ISA-based devices, +including: + dac02 - Keithley DAC-02 analog output board + pcl733 - Advantech PCL-733 + pcl734 - Advantech PCL-734 + +Configuration options: + [0] - I/O port base +*/ + +#include "../comedidev.h" + +#include + +static int poc_attach(comedi_device * dev, comedi_devconfig * it); +static int poc_detach(comedi_device * dev); +static int readback_insn(comedi_device * dev, comedi_subdevice * s, + comedi_insn * insn, lsampl_t * data); + +static int dac02_ao_winsn(comedi_device * dev, comedi_subdevice * s, + comedi_insn * insn, lsampl_t * data); +static int pcl733_insn_bits(comedi_device * dev, comedi_subdevice * s, + comedi_insn * insn, lsampl_t * data); +static int pcl734_insn_bits(comedi_device * dev, comedi_subdevice * s, + comedi_insn * insn, lsampl_t * data); + +struct boarddef_struct { + const char *name; + unsigned int iosize; + int (*setup) (comedi_device *); + int type; + int n_chan; + int n_bits; + int (*winsn) (comedi_device *, comedi_subdevice *, comedi_insn *, + lsampl_t *); + int (*rinsn) (comedi_device *, comedi_subdevice *, comedi_insn *, + lsampl_t *); + int (*insnbits) (comedi_device *, comedi_subdevice *, comedi_insn *, + lsampl_t *); + const comedi_lrange *range; +}; +static const struct boarddef_struct boards[] = { + { + name: "dac02", + iosize: 8, + //setup: dac02_setup, + type: COMEDI_SUBD_AO, + n_chan: 2, + n_bits: 12, + winsn: dac02_ao_winsn, + rinsn: readback_insn, + range: &range_unknown, + }, + { + name: "pcl733", + iosize: 4, + type: COMEDI_SUBD_DI, + n_chan: 32, + n_bits: 1, + insnbits:pcl733_insn_bits, + range: &range_digital, + }, + { + name: "pcl734", + iosize: 4, + type: COMEDI_SUBD_DO, + n_chan: 32, + n_bits: 1, + insnbits:pcl734_insn_bits, + range: &range_digital, + }, +}; + +#define n_boards (sizeof(boards)/sizeof(boards[0])) +#define this_board ((const struct boarddef_struct *)dev->board_ptr) + +static comedi_driver driver_poc = { + driver_name:"poc", + module:THIS_MODULE, + attach:poc_attach, + detach:poc_detach, + board_name:&boards[0].name, + num_names:n_boards, + offset:sizeof(boards[0]), +}; + +static int poc_attach(comedi_device * dev, comedi_devconfig * it) +{ + comedi_subdevice *s; + unsigned long iobase; + unsigned int iosize; + + iobase = it->options[0]; + printk("comedi%d: poc: using %s iobase 0x%lx\n", dev->minor, + this_board->name, iobase); + + dev->board_name = this_board->name; + + if (iobase == 0) { + printk("io base address required\n"); + return -EINVAL; + } + + iosize = this_board->iosize; + /* check if io addresses are available */ + if (!request_region(iobase, iosize, "dac02")) { + printk("I/O port conflict: failed to allocate ports 0x%lx to 0x%lx\n", iobase, iobase + iosize - 1); + return -EIO; + } + dev->iobase = iobase; + + if (alloc_subdevices(dev, 1) < 0) + return -ENOMEM; + if (alloc_private(dev, sizeof(lsampl_t) * this_board->n_chan) < 0) + return -ENOMEM; + + /* analog output subdevice */ + s = dev->subdevices + 0; + s->type = this_board->type; + s->n_chan = this_board->n_chan; + s->maxdata = (1 << this_board->n_bits) - 1; + s->range_table = this_board->range; + s->insn_write = this_board->winsn; + s->insn_read = this_board->rinsn; + s->insn_bits = this_board->insnbits; + if (s->type == COMEDI_SUBD_AO || s->type == COMEDI_SUBD_DO) { + s->subdev_flags = SDF_WRITABLE; + } + + return 0; +} + +static int poc_detach(comedi_device * dev) +{ + /* only free stuff if it has been allocated by _attach */ + if (dev->iobase) + release_region(dev->iobase, this_board->iosize); + + printk("comedi%d: dac02: remove\n", dev->minor); + + return 0; +} + +static int readback_insn(comedi_device * dev, comedi_subdevice * s, + comedi_insn * insn, lsampl_t * data) +{ + int chan; + + chan = CR_CHAN(insn->chanspec); + data[0] = ((lsampl_t *) dev->private)[chan]; + + return 1; +} + +/* DAC-02 registers */ +#define DAC02_LSB(a) (2 * a) +#define DAC02_MSB(a) (2 * a + 1) + +static int dac02_ao_winsn(comedi_device * dev, comedi_subdevice * s, + comedi_insn * insn, lsampl_t * data) +{ + int temp; + int chan; + int output; + + chan = CR_CHAN(insn->chanspec); + ((lsampl_t *) dev->private)[chan] = data[0]; + output = data[0]; +#ifdef wrong + // convert to complementary binary if range is bipolar + if ((CR_RANGE(insn->chanspec) & 0x2) == 0) + output = ~output; +#endif + temp = (output << 4) & 0xf0; + outb(temp, dev->iobase + DAC02_LSB(chan)); + temp = (output >> 4) & 0xff; + outb(temp, dev->iobase + DAC02_MSB(chan)); + + return 1; +} + +static int pcl733_insn_bits(comedi_device * dev, comedi_subdevice * s, + comedi_insn * insn, lsampl_t * data) +{ + if (insn->n != 2) + return -EINVAL; + + data[1] = inb(dev->iobase + 0); + data[1] |= (inb(dev->iobase + 1) << 8); + data[1] |= (inb(dev->iobase + 2) << 16); + data[1] |= (inb(dev->iobase + 3) << 24); + + return 2; +} + +static int pcl734_insn_bits(comedi_device * dev, comedi_subdevice * s, + comedi_insn * insn, lsampl_t * data) +{ + if (insn->n != 2) + return -EINVAL; + if (data[0]) { + s->state &= ~data[0]; + s->state |= (data[0] & data[1]); + if ((data[0] >> 0) & 0xff) + outb((s->state >> 0) & 0xff, dev->iobase + 0); + if ((data[0] >> 8) & 0xff) + outb((s->state >> 8) & 0xff, dev->iobase + 1); + if ((data[0] >> 16) & 0xff) + outb((s->state >> 16) & 0xff, dev->iobase + 2); + if ((data[0] >> 24) & 0xff) + outb((s->state >> 24) & 0xff, dev->iobase + 3); + } + data[1] = s->state; + + return 2; +} + +COMEDI_INITCLEANUP(driver_poc);