das6402.c revision 0a85b6f0ab0d2edb0d41b32697111ce0e4f43496
1/* 2 Some comments on the code.. 3 4 - it shouldn't be necessary to use outb_p(). 5 6 - ignoreirq creates a race condition. It needs to be fixed. 7 8 */ 9 10/* 11 comedi/drivers/das6402.c 12 An experimental driver for Computerboards' DAS6402 I/O card 13 14 Copyright (C) 1999 Oystein Svendsen <svendsen@pvv.org> 15 16 This program is free software; you can redistribute it and/or modify 17 it under the terms of the GNU General Public License as published by 18 the Free Software Foundation; either version 2 of the License, or 19 (at your option) any later version. 20 21 This program is distributed in the hope that it will be useful, 22 but WITHOUT ANY WARRANTY; without even the implied warranty of 23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 GNU General Public License for more details. 25 26 You should have received a copy of the GNU General Public License 27 along with this program; if not, write to the Free Software 28 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 29 30 */ 31/* 32Driver: das6402 33Description: Keithley Metrabyte DAS6402 (& compatibles) 34Author: Oystein Svendsen <svendsen@pvv.org> 35Status: bitrotten 36Devices: [Keithley Metrabyte] DAS6402 (das6402) 37 38This driver has suffered bitrot. 39*/ 40 41#include <linux/interrupt.h> 42#include "../comedidev.h" 43 44#include <linux/ioport.h> 45 46#define DAS6402_SIZE 16 47 48#define N_WORDS 3000*64 49 50#define STOP 0 51#define START 1 52 53#define SCANL 0x3f00 54#define BYTE unsigned char 55#define WORD unsigned short 56 57/*----- register 8 ----*/ 58#define CLRINT 0x01 59#define CLRXTR 0x02 60#define CLRXIN 0x04 61#define EXTEND 0x10 62#define ARMED 0x20 /* enable conting of post sample conv */ 63#define POSTMODE 0x40 64#define MHZ 0x80 /* 10 MHz clock */ 65/*---------------------*/ 66 67/*----- register 9 ----*/ 68#define IRQ (0x04 << 4) /* these two are */ 69#define IRQV 10 /* dependent on each other */ 70 71#define CONVSRC 0x03 /* trig src is Intarnal pacer */ 72#define BURSTEN 0x04 /* enable burst */ 73#define XINTE 0x08 /* use external int. trig */ 74#define INTE 0x80 /* enable analog interrupts */ 75/*---------------------*/ 76 77/*----- register 10 ---*/ 78#define TGEN 0x01 /* Use pin DI1 for externl trigging? */ 79#define TGSEL 0x02 /* Use edge triggering */ 80#define TGPOL 0x04 /* active edge is falling */ 81#define PRETRIG 0x08 /* pretrig */ 82/*---------------------*/ 83 84/*----- register 11 ---*/ 85#define EOB 0x0c 86#define FIFOHFULL 0x08 87#define GAIN 0x01 88#define FIFONEPTY 0x04 89#define MODE 0x10 90#define SEM 0x20 91#define BIP 0x40 92/*---------------------*/ 93 94#define M0 0x00 95#define M2 0x04 96 97#define C0 0x00 98#define C1 0x40 99#define C2 0x80 100#define RWLH 0x30 101 102static int das6402_attach(struct comedi_device *dev, 103 struct comedi_devconfig *it); 104static int das6402_detach(struct comedi_device *dev); 105static struct comedi_driver driver_das6402 = { 106 .driver_name = "das6402", 107 .module = THIS_MODULE, 108 .attach = das6402_attach, 109 .detach = das6402_detach, 110}; 111 112COMEDI_INITCLEANUP(driver_das6402); 113 114struct das6402_private { 115 int ai_bytes_to_read; 116 117 int das6402_ignoreirq; 118}; 119#define devpriv ((struct das6402_private *)dev->private) 120 121static void das6402_ai_fifo_dregs(struct comedi_device *dev, 122 struct comedi_subdevice *s); 123 124static void das6402_setcounter(struct comedi_device *dev) 125{ 126 BYTE p; 127 unsigned short ctrlwrd; 128 129 /* set up counter0 first, mode 0 */ 130 p = M0 | C0 | RWLH; 131 outb_p(p, dev->iobase + 15); 132 ctrlwrd = 2000; 133 p = (BYTE) (0xff & ctrlwrd); 134 outb_p(p, dev->iobase + 12); 135 p = (BYTE) (0xff & (ctrlwrd >> 8)); 136 outb_p(p, dev->iobase + 12); 137 138 /* set up counter1, mode 2 */ 139 p = M2 | C1 | RWLH; 140 outb_p(p, dev->iobase + 15); 141 ctrlwrd = 10; 142 p = (BYTE) (0xff & ctrlwrd); 143 outb_p(p, dev->iobase + 13); 144 p = (BYTE) (0xff & (ctrlwrd >> 8)); 145 outb_p(p, dev->iobase + 13); 146 147 /* set up counter1, mode 2 */ 148 p = M2 | C2 | RWLH; 149 outb_p(p, dev->iobase + 15); 150 ctrlwrd = 1000; 151 p = (BYTE) (0xff & ctrlwrd); 152 outb_p(p, dev->iobase + 14); 153 p = (BYTE) (0xff & (ctrlwrd >> 8)); 154 outb_p(p, dev->iobase + 14); 155} 156 157static irqreturn_t intr_handler(int irq, void *d) 158{ 159 struct comedi_device *dev = d; 160 struct comedi_subdevice *s = dev->subdevices; 161 162 if (!dev->attached || devpriv->das6402_ignoreirq) { 163 printk("das6402: BUG: spurious interrupt\n"); 164 return IRQ_HANDLED; 165 } 166#ifdef DEBUG 167 printk("das6402: interrupt! das6402_irqcount=%i\n", 168 devpriv->das6402_irqcount); 169 printk("das6402: iobase+2=%i\n", inw_p(dev->iobase + 2)); 170#endif 171 172 das6402_ai_fifo_dregs(dev, s); 173 174 if (s->async->buf_write_count >= devpriv->ai_bytes_to_read) { 175 outw_p(SCANL, dev->iobase + 2); /* clears the fifo */ 176 outb(0x07, dev->iobase + 8); /* clears all flip-flops */ 177#ifdef DEBUG 178 printk("das6402: Got %i samples\n\n", 179 devpriv->das6402_wordsread - diff); 180#endif 181 s->async->events |= COMEDI_CB_EOA; 182 comedi_event(dev, s); 183 } 184 185 outb(0x01, dev->iobase + 8); /* clear only the interrupt flip-flop */ 186 187 comedi_event(dev, s); 188 return IRQ_HANDLED; 189} 190 191#if 0 192static void das6402_ai_fifo_read(struct comedi_device *dev, short *data, int n) 193{ 194 int i; 195 196 for (i = 0; i < n; i++) 197 data[i] = inw(dev->iobase); 198} 199#endif 200 201static void das6402_ai_fifo_dregs(struct comedi_device *dev, 202 struct comedi_subdevice *s) 203{ 204 while (1) { 205 if (!(inb(dev->iobase + 8) & 0x01)) 206 return; 207 comedi_buf_put(s->async, inw(dev->iobase)); 208 } 209} 210 211static int das6402_ai_cancel(struct comedi_device *dev, 212 struct comedi_subdevice *s) 213{ 214 /* 215 * This function should reset the board from whatever condition it 216 * is in (i.e., acquiring data), to a non-active state. 217 */ 218 219 devpriv->das6402_ignoreirq = 1; 220#ifdef DEBUG 221 printk("das6402: Stopping acquisition\n"); 222#endif 223 devpriv->das6402_ignoreirq = 1; 224 outb_p(0x02, dev->iobase + 10); /* disable external trigging */ 225 outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */ 226 outb_p(0, dev->iobase + 9); /* disables interrupts */ 227 228 outw_p(SCANL, dev->iobase + 2); 229 230 return 0; 231} 232 233#ifdef unused 234static int das6402_ai_mode2(struct comedi_device *dev, 235 struct comedi_subdevice *s, comedi_trig * it) 236{ 237 devpriv->das6402_ignoreirq = 1; 238 239#ifdef DEBUG 240 printk("das6402: Starting acquisition\n"); 241#endif 242 outb_p(0x03, dev->iobase + 10); /* enable external trigging */ 243 outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */ 244 outb_p(IRQ | CONVSRC | BURSTEN | INTE, dev->iobase + 9); 245 246 devpriv->ai_bytes_to_read = it->n * sizeof(short); 247 248 /* um... ignoreirq is a nasty race condition */ 249 devpriv->das6402_ignoreirq = 0; 250 251 outw_p(SCANL, dev->iobase + 2); 252 253 return 0; 254} 255#endif 256 257static int board_init(struct comedi_device *dev) 258{ 259 BYTE b; 260 261 devpriv->das6402_ignoreirq = 1; 262 263 outb(0x07, dev->iobase + 8); 264 265 /* register 11 */ 266 outb_p(MODE, dev->iobase + 11); 267 b = BIP | SEM | MODE | GAIN | FIFOHFULL; 268 outb_p(b, dev->iobase + 11); 269 270 /* register 8 */ 271 outb_p(EXTEND, dev->iobase + 8); 272 b = EXTEND | MHZ; 273 outb_p(b, dev->iobase + 8); 274 b = MHZ | CLRINT | CLRXTR | CLRXIN; 275 outb_p(b, dev->iobase + 8); 276 277 /* register 9 */ 278 b = IRQ | CONVSRC | BURSTEN | INTE; 279 outb_p(b, dev->iobase + 9); 280 281 /* register 10 */ 282 b = TGSEL | TGEN; 283 outb_p(b, dev->iobase + 10); 284 285 b = 0x07; 286 outb_p(b, dev->iobase + 8); 287 288 das6402_setcounter(dev); 289 290 outw_p(SCANL, dev->iobase + 2); /* reset card fifo */ 291 292 devpriv->das6402_ignoreirq = 0; 293 294 return 0; 295} 296 297static int das6402_detach(struct comedi_device *dev) 298{ 299 if (dev->irq) 300 free_irq(dev->irq, dev); 301 if (dev->iobase) 302 release_region(dev->iobase, DAS6402_SIZE); 303 304 return 0; 305} 306 307static int das6402_attach(struct comedi_device *dev, 308 struct comedi_devconfig *it) 309{ 310 unsigned int irq; 311 unsigned long iobase; 312 int ret; 313 struct comedi_subdevice *s; 314 315 dev->board_name = "das6402"; 316 317 iobase = it->options[0]; 318 if (iobase == 0) 319 iobase = 0x300; 320 321 printk("comedi%d: das6402: 0x%04lx", dev->minor, iobase); 322 323 if (!request_region(iobase, DAS6402_SIZE, "das6402")) { 324 printk(" I/O port conflict\n"); 325 return -EIO; 326 } 327 dev->iobase = iobase; 328 329 /* should do a probe here */ 330 331 irq = it->options[0]; 332 printk(" ( irq = %u )", irq); 333 ret = request_irq(irq, intr_handler, 0, "das6402", dev); 334 if (ret < 0) { 335 printk("irq conflict\n"); 336 return ret; 337 } 338 dev->irq = irq; 339 340 ret = alloc_private(dev, sizeof(struct das6402_private)); 341 if (ret < 0) 342 return ret; 343 344 ret = alloc_subdevices(dev, 1); 345 if (ret < 0) 346 return ret; 347 348 /* ai subdevice */ 349 s = dev->subdevices + 0; 350 s->type = COMEDI_SUBD_AI; 351 s->subdev_flags = SDF_READABLE | SDF_GROUND; 352 s->n_chan = 8; 353 /* s->trig[2]=das6402_ai_mode2; */ 354 s->cancel = das6402_ai_cancel; 355 s->maxdata = (1 << 12) - 1; 356 s->len_chanlist = 16; /* ? */ 357 s->range_table = &range_unknown; 358 359 board_init(dev); 360 361 return 0; 362} 363