poc.c revision 790c55415aa31f4c732729f94d2c3a54f7d3bfc2
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(comedi_device * dev, comedi_devconfig * it); 45static int poc_detach(comedi_device * dev); 46static int readback_insn(comedi_device * dev, comedi_subdevice * s, 47 comedi_insn * insn, unsigned int * data); 48 49static int dac02_ao_winsn(comedi_device * dev, comedi_subdevice * s, 50 comedi_insn * insn, unsigned int * data); 51static int pcl733_insn_bits(comedi_device * dev, comedi_subdevice * s, 52 comedi_insn * insn, unsigned int * data); 53static int pcl734_insn_bits(comedi_device * dev, comedi_subdevice * s, 54 comedi_insn * insn, unsigned int * data); 55 56struct boarddef_struct { 57 const char *name; 58 unsigned int iosize; 59 int (*setup) (comedi_device *); 60 int type; 61 int n_chan; 62 int n_bits; 63 int (*winsn) (comedi_device *, comedi_subdevice *, comedi_insn *, 64 unsigned int *); 65 int (*rinsn) (comedi_device *, comedi_subdevice *, comedi_insn *, 66 unsigned int *); 67 int (*insnbits) (comedi_device *, comedi_subdevice *, comedi_insn *, 68 unsigned int *); 69 const 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 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(comedi_device * dev, comedi_devconfig * it) 117{ 118 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(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(comedi_device * dev, comedi_subdevice * s, 174 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(comedi_device * dev, comedi_subdevice * s, 189 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(comedi_device * dev, comedi_subdevice * s, 212 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(comedi_device * dev, comedi_subdevice * s, 226 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