das6402.c revision 25436dc9d84f1be60ff549c9ab712bba2835f284
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, struct comedi_devconfig *it); 103static int das6402_detach(struct comedi_device *dev); 104static struct comedi_driver driver_das6402 = { 105 .driver_name = "das6402", 106 .module = THIS_MODULE, 107 .attach = das6402_attach, 108 .detach = das6402_detach, 109}; 110 111COMEDI_INITCLEANUP(driver_das6402); 112 113struct das6402_private { 114 int ai_bytes_to_read; 115 116 int das6402_ignoreirq; 117}; 118#define devpriv ((struct das6402_private *)dev->private) 119 120static void das6402_ai_fifo_dregs(struct comedi_device *dev, struct comedi_subdevice *s); 121 122static void das6402_setcounter(struct comedi_device *dev) 123{ 124 BYTE p; 125 unsigned short ctrlwrd; 126 127 /* set up counter0 first, mode 0 */ 128 p = M0 | C0 | RWLH; 129 outb_p(p, dev->iobase + 15); 130 ctrlwrd = 2000; 131 p = (BYTE) (0xff & ctrlwrd); 132 outb_p(p, dev->iobase + 12); 133 p = (BYTE) (0xff & (ctrlwrd >> 8)); 134 outb_p(p, dev->iobase + 12); 135 136 /* set up counter1, mode 2 */ 137 p = M2 | C1 | RWLH; 138 outb_p(p, dev->iobase + 15); 139 ctrlwrd = 10; 140 p = (BYTE) (0xff & ctrlwrd); 141 outb_p(p, dev->iobase + 13); 142 p = (BYTE) (0xff & (ctrlwrd >> 8)); 143 outb_p(p, dev->iobase + 13); 144 145 /* set up counter1, mode 2 */ 146 p = M2 | C2 | RWLH; 147 outb_p(p, dev->iobase + 15); 148 ctrlwrd = 1000; 149 p = (BYTE) (0xff & ctrlwrd); 150 outb_p(p, dev->iobase + 14); 151 p = (BYTE) (0xff & (ctrlwrd >> 8)); 152 outb_p(p, dev->iobase + 14); 153} 154 155static irqreturn_t intr_handler(int irq, void *d) 156{ 157 struct comedi_device *dev = d; 158 struct comedi_subdevice *s = dev->subdevices; 159 160 if (!dev->attached || devpriv->das6402_ignoreirq) { 161 printk("das6402: BUG: spurious interrupt\n"); 162 return IRQ_HANDLED; 163 } 164#ifdef DEBUG 165 printk("das6402: interrupt! das6402_irqcount=%i\n", 166 devpriv->das6402_irqcount); 167 printk("das6402: iobase+2=%i\n", inw_p(dev->iobase + 2)); 168#endif 169 170 das6402_ai_fifo_dregs(dev, s); 171 172 if (s->async->buf_write_count >= devpriv->ai_bytes_to_read) { 173 outw_p(SCANL, dev->iobase + 2); /* clears the fifo */ 174 outb(0x07, dev->iobase + 8); /* clears all flip-flops */ 175#ifdef DEBUG 176 printk("das6402: Got %i samples\n\n", 177 devpriv->das6402_wordsread - diff); 178#endif 179 s->async->events |= COMEDI_CB_EOA; 180 comedi_event(dev, s); 181 } 182 183 outb(0x01, dev->iobase + 8); /* clear only the interrupt flip-flop */ 184 185 comedi_event(dev, s); 186 return IRQ_HANDLED; 187} 188 189#if 0 190static void das6402_ai_fifo_read(struct comedi_device *dev, short *data, int n) 191{ 192 int i; 193 194 for (i = 0; i < n; i++) 195 data[i] = inw(dev->iobase); 196} 197#endif 198 199static void das6402_ai_fifo_dregs(struct comedi_device *dev, struct comedi_subdevice *s) 200{ 201 while (1) { 202 if (!(inb(dev->iobase + 8) & 0x01)) 203 return; 204 comedi_buf_put(s->async, inw(dev->iobase)); 205 } 206} 207 208static int das6402_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) 209{ 210 /* 211 * This function should reset the board from whatever condition it 212 * is in (i.e., acquiring data), to a non-active state. 213 */ 214 215 devpriv->das6402_ignoreirq = 1; 216#ifdef DEBUG 217 printk("das6402: Stopping acquisition\n"); 218#endif 219 devpriv->das6402_ignoreirq = 1; 220 outb_p(0x02, dev->iobase + 10); /* disable external trigging */ 221 outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */ 222 outb_p(0, dev->iobase + 9); /* disables interrupts */ 223 224 outw_p(SCANL, dev->iobase + 2); 225 226 return 0; 227} 228 229#ifdef unused 230static int das6402_ai_mode2(struct comedi_device *dev, struct comedi_subdevice *s, 231 comedi_trig *it) 232{ 233 devpriv->das6402_ignoreirq = 1; 234 235#ifdef DEBUG 236 printk("das6402: Starting acquisition\n"); 237#endif 238 outb_p(0x03, dev->iobase + 10); /* enable external trigging */ 239 outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */ 240 outb_p(IRQ | CONVSRC | BURSTEN | INTE, dev->iobase + 9); 241 242 devpriv->ai_bytes_to_read = it->n * sizeof(short); 243 244 /* um... ignoreirq is a nasty race condition */ 245 devpriv->das6402_ignoreirq = 0; 246 247 outw_p(SCANL, dev->iobase + 2); 248 249 return 0; 250} 251#endif 252 253static int board_init(struct comedi_device *dev) 254{ 255 BYTE b; 256 257 devpriv->das6402_ignoreirq = 1; 258 259 outb(0x07, dev->iobase + 8); 260 261 /* register 11 */ 262 outb_p(MODE, dev->iobase + 11); 263 b = BIP | SEM | MODE | GAIN | FIFOHFULL; 264 outb_p(b, dev->iobase + 11); 265 266 /* register 8 */ 267 outb_p(EXTEND, dev->iobase + 8); 268 b = EXTEND | MHZ; 269 outb_p(b, dev->iobase + 8); 270 b = MHZ | CLRINT | CLRXTR | CLRXIN; 271 outb_p(b, dev->iobase + 8); 272 273 /* register 9 */ 274 b = IRQ | CONVSRC | BURSTEN | INTE; 275 outb_p(b, dev->iobase + 9); 276 277 /* register 10 */ 278 b = TGSEL | TGEN; 279 outb_p(b, dev->iobase + 10); 280 281 b = 0x07; 282 outb_p(b, dev->iobase + 8); 283 284 das6402_setcounter(dev); 285 286 outw_p(SCANL, dev->iobase + 2); /* reset card fifo */ 287 288 devpriv->das6402_ignoreirq = 0; 289 290 return 0; 291} 292 293static int das6402_detach(struct comedi_device *dev) 294{ 295 if (dev->irq) 296 free_irq(dev->irq, dev); 297 if (dev->iobase) 298 release_region(dev->iobase, DAS6402_SIZE); 299 300 return 0; 301} 302 303static int das6402_attach(struct comedi_device *dev, struct comedi_devconfig *it) 304{ 305 unsigned int irq; 306 unsigned long iobase; 307 int ret; 308 struct comedi_subdevice *s; 309 310 dev->board_name = "das6402"; 311 312 iobase = it->options[0]; 313 if (iobase == 0) 314 iobase = 0x300; 315 316 printk("comedi%d: das6402: 0x%04lx", dev->minor, iobase); 317 318 if (!request_region(iobase, DAS6402_SIZE, "das6402")) { 319 printk(" I/O port conflict\n"); 320 return -EIO; 321 } 322 dev->iobase = iobase; 323 324 /* should do a probe here */ 325 326 irq = it->options[0]; 327 printk(" ( irq = %u )", irq); 328 ret = request_irq(irq, intr_handler, 0, "das6402", dev); 329 if (ret < 0) { 330 printk("irq conflict\n"); 331 return ret; 332 } 333 dev->irq = irq; 334 335 ret = alloc_private(dev, sizeof(struct das6402_private)); 336 if (ret < 0) 337 return ret; 338 339 ret = alloc_subdevices(dev, 1); 340 if (ret < 0) 341 return ret; 342 343 /* ai subdevice */ 344 s = dev->subdevices + 0; 345 s->type = COMEDI_SUBD_AI; 346 s->subdev_flags = SDF_READABLE | SDF_GROUND; 347 s->n_chan = 8; 348 /* s->trig[2]=das6402_ai_mode2; */ 349 s->cancel = das6402_ai_cancel; 350 s->maxdata = (1 << 12) - 1; 351 s->len_chanlist = 16; /* ? */ 352 s->range_table = &range_unknown; 353 354 board_init(dev); 355 356 return 0; 357} 358