/* Some comments on the code.. - it shouldn't be necessary to use outb_p(). - ignoreirq creates a race condition. It needs to be fixed. */ /* An experimental driver for Computerboards' DAS6402 I/O card Copyright (C) 1999 Oystein Svendsen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Driver: das6402.o Description: Keithley Metrabyte DAS6402 (& compatibles) Author: Oystein Svendsen Status: bitrotten Devices: [Keithley Metrabyte] DAS6402 (das6402) This driver has suffered bitrot. */ #include #include #define DAS6402_SIZE 16 #define N_WORDS 3000*64 #define STOP 0 #define START 1 #define SCANL 0x3f00 #define BYTE unsigned char #define WORD unsigned short /*----- register 8 ----*/ #define CLRINT 0x01 #define CLRXTR 0x02 #define CLRXIN 0x04 #define EXTEND 0x10 #define ARMED 0x20 /* enable conting of post sample conv */ #define POSTMODE 0x40 #define MHZ 0x80 /* 10 MHz clock */ /*---------------------*/ /*----- register 9 ----*/ #define IRQ (0x04 << 4) /* these two are */ #define IRQV 10 /* dependent on each other */ #define CONVSRC 0x03 /* trig src is Intarnal pacer */ #define BURSTEN 0x04 /* enable burst */ #define XINTE 0x08 /* use external int. trig */ #define INTE 0x80 /* enable analog interrupts */ /*---------------------*/ /*----- register 10 ---*/ #define TGEN 0x01 /* Use pin DI1 for externl trigging? */ #define TGSEL 0x02 /* Use edge triggering */ #define TGPOL 0x04 /* active edge is falling */ #define PRETRIG 0x08 /* pretrig */ /*---------------------*/ /*----- register 11 ---*/ #define EOB 0x0c #define FIFOHFULL 0x08 #define GAIN 0x01 #define FIFONEPTY 0x04 #define MODE 0x10 #define SEM 0x20 #define BIP 0x40 /*---------------------*/ #define M0 0x00 #define M2 0x04 #define C0 0x00 #define C1 0x40 #define C2 0x80 #define RWLH 0x30 static int das6402_attach(comedi_device *dev,comedi_devconfig *it); static int das6402_detach(comedi_device *dev); static comedi_driver driver_das6402={ driver_name: "das6402", module: THIS_MODULE, attach: das6402_attach, detach: das6402_detach, }; COMEDI_INITCLEANUP(driver_das6402); typedef struct{ int ai_bytes_to_read; int das6402_ignoreirq; }das6402_private; #define devpriv ((das6402_private *)dev->private) static void das6402_ai_fifo_dregs(comedi_device *dev,comedi_subdevice *s); static void das6402_setcounter(comedi_device *dev) { BYTE p; unsigned short ctrlwrd; /* set up counter0 first, mode 0 */ p=M0|C0|RWLH; outb_p(p,dev->iobase+15); ctrlwrd=2000; p=(BYTE) (0xff & ctrlwrd); outb_p(p,dev->iobase+12); p=(BYTE) (0xff & (ctrlwrd >> 8)); outb_p(p,dev->iobase+12); /* set up counter1, mode 2 */ p=M2|C1|RWLH; outb_p(p,dev->iobase+15); ctrlwrd=10; p=(BYTE) (0xff & ctrlwrd); outb_p(p,dev->iobase+13); p=(BYTE) (0xff & (ctrlwrd >> 8)); outb_p(p,dev->iobase+13); /* set up counter1, mode 2 */ p=M2|C2|RWLH; outb_p(p,dev->iobase+15); ctrlwrd=1000; p=(BYTE) (0xff & ctrlwrd); outb_p(p,dev->iobase+14); p=(BYTE) (0xff & (ctrlwrd >> 8)); outb_p(p,dev->iobase+14); } static void intr_handler(int irq,void *d,struct pt_regs *regs) { comedi_device *dev=d; comedi_subdevice *s=dev->subdevices; if (devpriv->das6402_ignoreirq){ printk("das6402: BUG: spurious interrupt\n"); return; } #ifdef DEBUG printk("das6402: interrupt! das6402_irqcount=%i\n",devpriv->das6402_irqcount); printk("das6402: iobase+2=%i\n",inw_p(dev->iobase+2)); #endif das6402_ai_fifo_dregs(dev,s); if(s->async->buf_write_count >= devpriv->ai_bytes_to_read){ outw_p(SCANL,dev->iobase+2); /* clears the fifo */ outb(0x07,dev->iobase+8); /* clears all flip-flops */ #ifdef DEBUG printk("das6402: Got %i samples\n\n",devpriv->das6402_wordsread-diff); #endif s->async->events |= COMEDI_CB_EOA; comedi_event(dev,s,s->async->events); } outb(0x01,dev->iobase+8); /* clear only the interrupt flip-flop */ comedi_event(dev,s,s->async->events); } #if 0 static void das6402_ai_fifo_read(comedi_device *dev,sampl_t *data,int n) { int i; for(i=0;iiobase); } #endif static void das6402_ai_fifo_dregs(comedi_device *dev,comedi_subdevice *s) { while(1){ if(!(inb(dev->iobase+8)&0x01)) return; comedi_buf_put( s->async, inw(dev->iobase) ); } } static int das6402_ai_cancel(comedi_device *dev,comedi_subdevice *s) { /* * This function should reset the board from whatever condition it * is in (i.e., acquiring data), to a non-active state. */ devpriv->das6402_ignoreirq=1; #ifdef DEBUG printk("das6402: Stopping acquisition\n"); #endif devpriv->das6402_ignoreirq=1; outb_p(0x02,dev->iobase+10); /* disable external trigging */ outw_p(SCANL,dev->iobase+2); /* resets the card fifo */ outb_p(0,dev->iobase+9); /* disables interrupts */ outw_p(SCANL,dev->iobase+2); return 0; } #ifdef unused static int das6402_ai_mode2(comedi_device *dev,comedi_subdevice *s,comedi_trig *it) { devpriv->das6402_ignoreirq=1; #ifdef DEBUG printk("das6402: Starting acquisition\n"); #endif outb_p(0x03,dev->iobase+10); /* enable external trigging */ outw_p(SCANL,dev->iobase+2); /* resets the card fifo */ outb_p(IRQ|CONVSRC|BURSTEN|INTE,dev->iobase+9); devpriv->ai_bytes_to_read=it->n*sizeof(sampl_t); /* um... ignoreirq is a nasty race condition */ devpriv->das6402_ignoreirq=0; outw_p(SCANL,dev->iobase+2); return 0; } #endif static int board_init(comedi_device *dev) { BYTE b; devpriv->das6402_ignoreirq=1; outb(0x07,dev->iobase+8); /* register 11 */ outb_p(MODE,dev->iobase+11); b=BIP|SEM|MODE|GAIN|FIFOHFULL; outb_p(b, dev->iobase+11); /* register 8 */ outb_p(EXTEND,dev->iobase+8); b=EXTEND|MHZ; outb_p(b,dev->iobase+8); b= MHZ|CLRINT|CLRXTR|CLRXIN; outb_p(b,dev->iobase+8); /* register 9 */ b=IRQ|CONVSRC|BURSTEN|INTE; outb_p(b,dev->iobase+9); /* register 10 */ b=TGSEL|TGEN; outb_p(b,dev->iobase+10); b=0x07; outb_p(b,dev->iobase+8); das6402_setcounter(dev); outw_p(SCANL,dev->iobase+2); /* reset card fifo */ devpriv->das6402_ignoreirq=0; return 0; } static int das6402_detach(comedi_device *dev) { if(dev->irq)comedi_free_irq(dev->irq,dev); if(dev->iobase)release_region(dev->iobase,DAS6402_SIZE); return 0; } static int das6402_attach(comedi_device *dev,comedi_devconfig *it) { int irq; int iobase; int ret; comedi_subdevice *s; dev->board_name="das6402"; iobase=it->options[0]; if(iobase==0)iobase=0x300; printk("comedi%d: das6402: 0x%04x",dev->minor,iobase); if(check_region(iobase,DAS6402_SIZE)<0){ printk(" I/O port conflict\n"); return -EIO; } request_region(iobase,DAS6402_SIZE,"das6402"); dev->iobase=iobase; /* should do a probe here */ irq=it->options[0]; printk(" ( irq = %d )", irq); ret=comedi_request_irq(irq, intr_handler, 0, "das6402", dev); if(ret<0){ printk("irq conflict\n"); return ret; } dev->irq=irq; if((ret=alloc_private(dev,sizeof(das6402_private)))<0) return ret; dev->n_subdevices=1; if((ret=alloc_subdevices(dev))<0) return ret; /* ai subdevice */ s=dev->subdevices+0; s->type=COMEDI_SUBD_AI; s->subdev_flags=SDF_READABLE|SDF_GROUND; s->n_chan=8; //s->trig[2]=das6402_ai_mode2; s->cancel=das6402_ai_cancel; s->maxdata=(1<<12)-1; s->len_chanlist=16; /* ? */ s->range_table = &range_unknown; board_init(dev); return 0; }