poc.c revision 0a85b6f0ab0d2edb0d41b32697111ce0e4f43496
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, 52 struct comedi_subdevice *s, 53 struct comedi_insn *insn, unsigned int *data); 54static int pcl734_insn_bits(struct comedi_device *dev, 55 struct comedi_subdevice *s, 56 struct comedi_insn *insn, unsigned int *data); 57 58struct boarddef_struct { 59 const char *name; 60 unsigned int iosize; 61 int (*setup) (struct comedi_device *); 62 int type; 63 int n_chan; 64 int n_bits; 65 int (*winsn) (struct comedi_device *, struct comedi_subdevice *, 66 struct comedi_insn *, unsigned int *); 67 int (*rinsn) (struct comedi_device *, struct comedi_subdevice *, 68 struct comedi_insn *, unsigned int *); 69 int (*insnbits) (struct comedi_device *, struct comedi_subdevice *, 70 struct comedi_insn *, unsigned int *); 71 const struct comedi_lrange *range; 72}; 73static const struct boarddef_struct boards[] = { 74 { 75 .name = "dac02", 76 .iosize = 8, 77 /* .setup = dac02_setup, */ 78 .type = COMEDI_SUBD_AO, 79 .n_chan = 2, 80 .n_bits = 12, 81 .winsn = dac02_ao_winsn, 82 .rinsn = readback_insn, 83 .range = &range_unknown, 84 }, 85 { 86 .name = "pcl733", 87 .iosize = 4, 88 .type = COMEDI_SUBD_DI, 89 .n_chan = 32, 90 .n_bits = 1, 91 .insnbits = pcl733_insn_bits, 92 .range = &range_digital, 93 }, 94 { 95 .name = "pcl734", 96 .iosize = 4, 97 .type = COMEDI_SUBD_DO, 98 .n_chan = 32, 99 .n_bits = 1, 100 .insnbits = pcl734_insn_bits, 101 .range = &range_digital, 102 }, 103}; 104 105#define n_boards (sizeof(boards)/sizeof(boards[0])) 106#define this_board ((const struct boarddef_struct *)dev->board_ptr) 107 108static struct comedi_driver driver_poc = { 109 .driver_name = "poc", 110 .module = THIS_MODULE, 111 .attach = poc_attach, 112 .detach = poc_detach, 113 .board_name = &boards[0].name, 114 .num_names = n_boards, 115 .offset = sizeof(boards[0]), 116}; 117 118static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it) 119{ 120 struct comedi_subdevice *s; 121 unsigned long iobase; 122 unsigned int iosize; 123 124 iobase = it->options[0]; 125 printk("comedi%d: poc: using %s iobase 0x%lx\n", dev->minor, 126 this_board->name, iobase); 127 128 dev->board_name = this_board->name; 129 130 if (iobase == 0) { 131 printk("io base address required\n"); 132 return -EINVAL; 133 } 134 135 iosize = this_board->iosize; 136 /* check if io addresses are available */ 137 if (!request_region(iobase, iosize, "dac02")) { 138 printk 139 ("I/O port conflict: failed to allocate ports 0x%lx to 0x%lx\n", 140 iobase, iobase + iosize - 1); 141 return -EIO; 142 } 143 dev->iobase = iobase; 144 145 if (alloc_subdevices(dev, 1) < 0) 146 return -ENOMEM; 147 if (alloc_private(dev, sizeof(unsigned int) * this_board->n_chan) < 0) 148 return -ENOMEM; 149 150 /* analog output subdevice */ 151 s = dev->subdevices + 0; 152 s->type = this_board->type; 153 s->n_chan = this_board->n_chan; 154 s->maxdata = (1 << this_board->n_bits) - 1; 155 s->range_table = this_board->range; 156 s->insn_write = this_board->winsn; 157 s->insn_read = this_board->rinsn; 158 s->insn_bits = this_board->insnbits; 159 if (s->type == COMEDI_SUBD_AO || s->type == COMEDI_SUBD_DO) { 160 s->subdev_flags = SDF_WRITABLE; 161 } 162 163 return 0; 164} 165 166static int poc_detach(struct comedi_device *dev) 167{ 168 /* only free stuff if it has been allocated by _attach */ 169 if (dev->iobase) 170 release_region(dev->iobase, this_board->iosize); 171 172 printk("comedi%d: dac02: remove\n", dev->minor); 173 174 return 0; 175} 176 177static int readback_insn(struct comedi_device *dev, struct comedi_subdevice *s, 178 struct comedi_insn *insn, unsigned int *data) 179{ 180 int chan; 181 182 chan = CR_CHAN(insn->chanspec); 183 data[0] = ((unsigned int *)dev->private)[chan]; 184 185 return 1; 186} 187 188/* DAC-02 registers */ 189#define DAC02_LSB(a) (2 * a) 190#define DAC02_MSB(a) (2 * a + 1) 191 192static int dac02_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, 193 struct comedi_insn *insn, unsigned int *data) 194{ 195 int temp; 196 int chan; 197 int output; 198 199 chan = CR_CHAN(insn->chanspec); 200 ((unsigned int *)dev->private)[chan] = data[0]; 201 output = data[0]; 202#ifdef wrong 203 /* convert to complementary binary if range is bipolar */ 204 if ((CR_RANGE(insn->chanspec) & 0x2) == 0) 205 output = ~output; 206#endif 207 temp = (output << 4) & 0xf0; 208 outb(temp, dev->iobase + DAC02_LSB(chan)); 209 temp = (output >> 4) & 0xff; 210 outb(temp, dev->iobase + DAC02_MSB(chan)); 211 212 return 1; 213} 214 215static int pcl733_insn_bits(struct comedi_device *dev, 216 struct comedi_subdevice *s, 217 struct comedi_insn *insn, unsigned int *data) 218{ 219 if (insn->n != 2) 220 return -EINVAL; 221 222 data[1] = inb(dev->iobase + 0); 223 data[1] |= (inb(dev->iobase + 1) << 8); 224 data[1] |= (inb(dev->iobase + 2) << 16); 225 data[1] |= (inb(dev->iobase + 3) << 24); 226 227 return 2; 228} 229 230static int pcl734_insn_bits(struct comedi_device *dev, 231 struct comedi_subdevice *s, 232 struct comedi_insn *insn, unsigned int *data) 233{ 234 if (insn->n != 2) 235 return -EINVAL; 236 if (data[0]) { 237 s->state &= ~data[0]; 238 s->state |= (data[0] & data[1]); 239 if ((data[0] >> 0) & 0xff) 240 outb((s->state >> 0) & 0xff, dev->iobase + 0); 241 if ((data[0] >> 8) & 0xff) 242 outb((s->state >> 8) & 0xff, dev->iobase + 1); 243 if ((data[0] >> 16) & 0xff) 244 outb((s->state >> 16) & 0xff, dev->iobase + 2); 245 if ((data[0] >> 24) & 0xff) 246 outb((s->state >> 24) & 0xff, dev->iobase + 3); 247 } 248 data[1] = s->state; 249 250 return 2; 251} 252 253COMEDI_INITCLEANUP(driver_poc); 254