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