poc.c revision 68c3dbff9fc9f25872408d0e95980d41733d48d0
1/* 2 comedi/drivers/poc.c 3 Mini-drivers for POC (Piece of Crap) boards 4 Copyright (C) 2000 Frank Mori Hess <fmhess@users.sourceforge.net> 5 Copyright (C) 2001 David A. Schleef <ds@schleef.org> 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; if not, write to the Free Software 19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20*/ 21/* 22Driver: poc 23Description: Generic driver for very simple devices 24Author: ds 25Devices: [Keithley Metrabyte] DAC-02 (dac02), [Advantech] PCL-733 (pcl733), 26 PCL-734 (pcl734) 27Updated: Sat, 16 Mar 2002 17:34:48 -0800 28Status: unknown 29 30This driver is indended to support very simple ISA-based devices, 31including: 32 dac02 - Keithley DAC-02 analog output board 33 pcl733 - Advantech PCL-733 34 pcl734 - Advantech PCL-734 35 36Configuration options: 37 [0] - I/O port base 38*/ 39 40#include "../comedidev.h" 41 42#include <linux/ioport.h> 43 44static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it); 45static int poc_detach(struct comedi_device *dev); 46static int readback_insn(struct comedi_device *dev, struct comedi_subdevice *s, 47 struct comedi_insn *insn, unsigned int *data); 48 49static int dac02_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, 50 struct comedi_insn *insn, unsigned int *data); 51static int pcl733_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, 52 struct comedi_insn *insn, unsigned int *data); 53static int pcl734_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, 54 struct comedi_insn *insn, unsigned int *data); 55 56struct boarddef_struct { 57 const char *name; 58 unsigned int iosize; 59 int (*setup) (struct comedi_device *); 60 int type; 61 int n_chan; 62 int n_bits; 63 int (*winsn) (struct comedi_device *, struct comedi_subdevice *, struct comedi_insn *, 64 unsigned int *); 65 int (*rinsn) (struct comedi_device *, struct comedi_subdevice *, struct comedi_insn *, 66 unsigned int *); 67 int (*insnbits) (struct comedi_device *, struct comedi_subdevice *, struct comedi_insn *, 68 unsigned int *); 69 const struct comedi_lrange *range; 70}; 71static const struct boarddef_struct boards[] = { 72 { 73 .name = "dac02", 74 .iosize = 8, 75 /* .setup = dac02_setup, */ 76 .type = COMEDI_SUBD_AO, 77 .n_chan = 2, 78 .n_bits = 12, 79 .winsn = dac02_ao_winsn, 80 .rinsn = readback_insn, 81 .range = &range_unknown, 82 }, 83 { 84 .name = "pcl733", 85 .iosize = 4, 86 .type = COMEDI_SUBD_DI, 87 .n_chan = 32, 88 .n_bits = 1, 89 .insnbits = pcl733_insn_bits, 90 .range = &range_digital, 91 }, 92 { 93 .name = "pcl734", 94 .iosize = 4, 95 .type = COMEDI_SUBD_DO, 96 .n_chan = 32, 97 .n_bits = 1, 98 .insnbits = pcl734_insn_bits, 99 .range = &range_digital, 100 }, 101}; 102 103#define n_boards (sizeof(boards)/sizeof(boards[0])) 104#define this_board ((const struct boarddef_struct *)dev->board_ptr) 105 106static struct comedi_driver driver_poc = { 107 .driver_name = "poc", 108 .module = THIS_MODULE, 109 .attach = poc_attach, 110 .detach = poc_detach, 111 .board_name = &boards[0].name, 112 .num_names = n_boards, 113 .offset = sizeof(boards[0]), 114}; 115 116static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it) 117{ 118 struct comedi_subdevice *s; 119 unsigned long iobase; 120 unsigned int iosize; 121 122 iobase = it->options[0]; 123 printk("comedi%d: poc: using %s iobase 0x%lx\n", dev->minor, 124 this_board->name, iobase); 125 126 dev->board_name = this_board->name; 127 128 if (iobase == 0) { 129 printk("io base address required\n"); 130 return -EINVAL; 131 } 132 133 iosize = this_board->iosize; 134 /* check if io addresses are available */ 135 if (!request_region(iobase, iosize, "dac02")) { 136 printk("I/O port conflict: failed to allocate ports 0x%lx to 0x%lx\n", iobase, iobase + iosize - 1); 137 return -EIO; 138 } 139 dev->iobase = iobase; 140 141 if (alloc_subdevices(dev, 1) < 0) 142 return -ENOMEM; 143 if (alloc_private(dev, sizeof(unsigned int) * this_board->n_chan) < 0) 144 return -ENOMEM; 145 146 /* analog output subdevice */ 147 s = dev->subdevices + 0; 148 s->type = this_board->type; 149 s->n_chan = this_board->n_chan; 150 s->maxdata = (1 << this_board->n_bits) - 1; 151 s->range_table = this_board->range; 152 s->insn_write = this_board->winsn; 153 s->insn_read = this_board->rinsn; 154 s->insn_bits = this_board->insnbits; 155 if (s->type == COMEDI_SUBD_AO || s->type == COMEDI_SUBD_DO) { 156 s->subdev_flags = SDF_WRITABLE; 157 } 158 159 return 0; 160} 161 162static int poc_detach(struct comedi_device *dev) 163{ 164 /* only free stuff if it has been allocated by _attach */ 165 if (dev->iobase) 166 release_region(dev->iobase, this_board->iosize); 167 168 printk("comedi%d: dac02: remove\n", dev->minor); 169 170 return 0; 171} 172 173static int readback_insn(struct comedi_device *dev, struct comedi_subdevice *s, 174 struct comedi_insn *insn, unsigned int *data) 175{ 176 int chan; 177 178 chan = CR_CHAN(insn->chanspec); 179 data[0] = ((unsigned int *) dev->private)[chan]; 180 181 return 1; 182} 183 184/* DAC-02 registers */ 185#define DAC02_LSB(a) (2 * a) 186#define DAC02_MSB(a) (2 * a + 1) 187 188static int dac02_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, 189 struct comedi_insn *insn, unsigned int *data) 190{ 191 int temp; 192 int chan; 193 int output; 194 195 chan = CR_CHAN(insn->chanspec); 196 ((unsigned int *) dev->private)[chan] = data[0]; 197 output = data[0]; 198#ifdef wrong 199 /* convert to complementary binary if range is bipolar */ 200 if ((CR_RANGE(insn->chanspec) & 0x2) == 0) 201 output = ~output; 202#endif 203 temp = (output << 4) & 0xf0; 204 outb(temp, dev->iobase + DAC02_LSB(chan)); 205 temp = (output >> 4) & 0xff; 206 outb(temp, dev->iobase + DAC02_MSB(chan)); 207 208 return 1; 209} 210 211static int pcl733_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, 212 struct comedi_insn *insn, unsigned int *data) 213{ 214 if (insn->n != 2) 215 return -EINVAL; 216 217 data[1] = inb(dev->iobase + 0); 218 data[1] |= (inb(dev->iobase + 1) << 8); 219 data[1] |= (inb(dev->iobase + 2) << 16); 220 data[1] |= (inb(dev->iobase + 3) << 24); 221 222 return 2; 223} 224 225static int pcl734_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, 226 struct comedi_insn *insn, unsigned int *data) 227{ 228 if (insn->n != 2) 229 return -EINVAL; 230 if (data[0]) { 231 s->state &= ~data[0]; 232 s->state |= (data[0] & data[1]); 233 if ((data[0] >> 0) & 0xff) 234 outb((s->state >> 0) & 0xff, dev->iobase + 0); 235 if ((data[0] >> 8) & 0xff) 236 outb((s->state >> 8) & 0xff, dev->iobase + 1); 237 if ((data[0] >> 16) & 0xff) 238 outb((s->state >> 16) & 0xff, dev->iobase + 2); 239 if ((data[0] >> 24) & 0xff) 240 outb((s->state >> 24) & 0xff, dev->iobase + 3); 241 } 242 data[1] = s->state; 243 244 return 2; 245} 246 247COMEDI_INITCLEANUP(driver_poc); 248