static int das16m1_cmd_exec(comedi_device *dev,comedi_subdevice *s);
static int das16m1_cancel(comedi_device *dev, comedi_subdevice *s);
-static void das16m1_reset(comedi_device *dev);
static void das16m1_interrupt(int irq, void *d, struct pt_regs *regs);
static unsigned int das16m1_set_pacer(comedi_device *dev, unsigned int ns, int round_flag);
struct das16m1_private_struct {
unsigned int control_state;
volatile unsigned int adc_count;
+ unsigned int do_bits; // saves status of digital output bits
unsigned int divisor1; // divides master clock to obtain conversion speed
unsigned int divisor2; // divides master clock to obtain conversion speed
};
static int das16m1_cmd_test(comedi_device *dev,comedi_subdevice *s, comedi_cmd *cmd)
{
- unsigned int err=0, tmp;
+ unsigned int err=0, tmp, i;
/* make sure triggers are valid */
tmp=cmd->start_src;
err++;
}
}
+ // check chanlist agains board's peculiarities
+ if(cmd->chanlist_len > 1)
+ {
+ for(i = 0; i < cmd->chanlist_len; i++)
+ {
+ // even/odd channels must go into even/odd queue addresses
+ if((i % 2) != (CR_CHAN(cmd->chanlist[i]) % 2))
+ {
+ comedi_error(dev, "bad chanlist:\n"
+ " even/odd channels must go have even/odd chanlist indices");
+ err++;
+ }
+ }
+ if((cmd->chanlist_len % 2) != 0)
+ {
+ comedi_error(dev, "chanlist must be of even length or length 1");
+ err++;
+ }
+ }
if(err) return 3;
&(devpriv->divisor2), &(cmd->convert_arg), cmd->flags & TRIG_ROUND_MASK);
if(tmp != cmd->convert_arg) err++;
}
- // XXX we need to check constraints on chanlist here
if(err) return 4;
byte = Q_CHAN(CR_CHAN(cmd->chanlist[i])) | Q_RANGE(CR_RANGE(cmd->chanlist[i]));
outb(byte, dev->iobase + DAS16M1_QUEUE_DATA);
}
- outb(0, dev->iobase + DAS16M1_QUEUE_ADDR);
/* set counter mode and counts */
das16m1_set_pacer(dev, cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK);
- /* clear interrupt bit */
- outb(0, dev->iobase + DAS16M1_CLEAR_INTR);
-
// set control & status register
byte = 0;
outb(byte, dev->iobase + DAS16M1_CS);
+ /* clear interrupt bit */
+ outb(0, dev->iobase + DAS16M1_CLEAR_INTR);
/* enable interrupts and internal pacer */
devpriv->control_state |= INTE | INT_PACER;
outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL);
static int das16m1_cancel(comedi_device *dev, comedi_subdevice *s)
{
- devpriv->adc_count = 0;
devpriv->control_state &= ~INTE;
devpriv->control_state &= ~PACER_MASK;
outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL);
+ devpriv->adc_count = 0;
return 0;
}
-#if 0 // insns haven't been converted from das16 driver yet
static int das16m1_ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)
{
- int i,n;
- int range;
- int chan;
- int msb,lsb;
-
- /* clear crap */
- inb(dev->iobase+DAS16M1_AI_LSB);
- inb(dev->iobase+DAS16M1_AI_MSB);
-
- /* set multiplexer */
- chan = CR_CHAN(insn->chanspec);
- outb_p(chan,dev->iobase+DAS16M1_MUX);
-
- /* set gain */
- if(thisboard->ai_pg != das16m1_pg_none){
- range = CR_RANGE(insn->chanspec);
- outb((das16m1_gainlists[thisboard->ai_pg])[range],
- dev->iobase+DAS16M1_GAIN);
- }
+ int i, n;
+ int byte;
+ int data_point;
+ const int timeout = 1000;
- /* How long should we wait for MUX to settle? */
- //udelay(5);
+ /* disable interrupts and internal pacer */
+ devpriv->control_state &= ~INTE & ~PACER_MASK;
+ outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL);
- for(n=0;n<insn->n;n++){
+ /* setup channel/gain queue */
+ outb(0, dev->iobase + DAS16M1_QUEUE_ADDR);
+ byte = Q_CHAN(CR_CHAN(insn->chanspec)) | Q_RANGE(CR_RANGE(insn->chanspec));
+ outb(byte, dev->iobase + DAS16M1_QUEUE_DATA);
+
+ for(n = 0; n < insn->n; n++)
+ {
/* trigger conversion */
- outb_p(0,dev->iobase+DAS16M1_TRIG);
+ outb(0, dev->iobase);
- for(i=0;i<DAS16M1_TIMEOUT;i++){
- if(!(inb(DAS16M1_STATUS)&DAS16M1_EOC))
+ for(i = 0; i < timeout; i++)
+ {
+ if(inb(dev->iobase + DAS16M1_CS) & IRQDATA)
break;
}
- if(i==DAS16M1_TIMEOUT){
- rt_printk("das16m1: timeout\n");
+ if(i == timeout)
+ {
+ comedi_error(dev, "timeout");
return -ETIME;
}
- msb = inb(dev->iobase + DAS16M1_AI_MSB);
- lsb = inb(dev->iobase + DAS16M1_AI_LSB);
- if(thisboard->ai_nbits==12){
- data[n] = (lsb>>4) | (msb << 4);
- }else{
- data[n] = lsb | (msb << 8);
+ data_point = inw(dev->iobase);
+ if(thisboard->n_bits == 12)
+ {
+ data[n] = AI_DATA(data_point);
+ }else
+ {
+ data[n] = data_point;
}
}
static int das16m1_di_rbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)
{
- data[0]=inb(dev->iobase+DAS16M1_DIO)&0xf;
+ lsampl_t bits;
- return 1;
+ bits = inb(dev->iobase + DAS16M1_DIO) & 0xf;
+ data[1] = bits;
+ data[0] = 0;
+
+ return 2;
}
static int das16m1_do_wbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)
{
- outb(data[0],dev->iobase+DAS16M1_DIO);
-
- return 1;
-}
+ lsampl_t wbits;
-static int das16m1_ao_winsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data)
-{
- int i;
- int lsb,msb;
- int chan;
-
- chan=CR_CHAN(insn->chanspec);
-
- for(i=0;i<insn->n;i++){
- if(thisboard->ao_nbits==12){
- lsb=(data[i]<<4)&0xff;
- msb=(data[i]>>4)&0xff;
- }else{
- lsb=data[i]&0xff;
- msb=(data[i]>>8)&0xff;
- }
+ // only set bits that have been masked
+ data[0] &= 0xf;
+ wbits = devpriv->do_bits;
+ // zero bits that have been masked
+ wbits &= ~data[0];
+ // set masked bits
+ wbits |= data[0] & data[1];
+ devpriv->do_bits = wbits;
+ data[1] = wbits;
-#if 0
- outb(lsb,dev->iobase+devpriv->ao_offset_lsb[chan]);
- outb(msb,dev->iobase+devpriv->ao_offset_msb[chan]);
-#else
- outb(lsb,dev->iobase+DAS16M1_AO_LSB(chan));
- outb(msb,dev->iobase+DAS16M1_AO_MSB(chan));
-#endif
- }
+ outb(devpriv->do_bits, dev->iobase + DAS16M1_DIO);
- return i;
+ return 2;
}
-#endif // insns haven't been converted from das16 driver yet
-
static void das16m1_interrupt(int irq, void *d, struct pt_regs *regs)
{
int i, status;
sampl_t data_point;
-
comedi_device *dev = d;
comedi_subdevice *s = dev->subdevices;
- comedi_async *async = s->async;
+ comedi_async *async;
- status = inb(dev->iobase + DAS16M1_CS);
-
- if((status & IRQDATA) == 0)
+ if(dev->attached == 0)
{
- comedi_error(dev, "spurious interrupt");
+ comedi_error(dev, "premature interrupt");
return;
}
- if(dev->attached == 0)
+
+ status = inb(dev->iobase + DAS16M1_CS);
+
+ if((status & (IRQDATA | OVRUN)) == 0)
{
- comedi_error(dev, "premature interrupt");
- /* clear interrupt */
- outb(0, dev->iobase + DAS16M1_CLEAR_INTR);
+ comedi_error(dev, "spurious interrupt");
return;
}
+ // initialize async here to avoid freak out on premature interrupt
+ async = s->async;
for(i = 0; i < HALF_FIFO; i++)
{
- data_point = inw(dev->iobase + DAS16M1_AI);
- data_point = AI_DATA(data_point);
+ data_point = AI_DATA(inw(dev->iobase + DAS16M1_AI));
comedi_buf_put(async, data_point);
- if(--devpriv->adc_count <= 0) { /* end of acquisition */
+ if(--devpriv->adc_count == 0) { /* end of acquisition */
das16m1_cancel(dev, s);
async->events |= COMEDI_CB_EOA;
break;
{
das16m1_cancel(dev, s);
async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+ comedi_error(dev, "fifo overflow");
}
async->events |= COMEDI_CB_BLOCK;
s->len_chanlist = 256;
s->maxdata = (1 << 12) - 1;
s->range_table = &range_das16m1;
-// s->insn_read = das16m1_ai_rinsn;
+ s->insn_read = das16m1_ai_rinsn;
s->do_cmdtest = das16m1_cmd_test;
s->do_cmd = das16m1_cmd_exec;
s->cancel = das16m1_cancel;
s->n_chan = 4;
s->maxdata = 1;
s->range_table = &range_digital;
-// s->insn_bits = das16m1_di_rbits;
+ s->insn_bits = das16m1_di_rbits;
s = dev->subdevices + 2;
/* do */
s->n_chan = 4;
s->maxdata = 1;
s->range_table = &range_digital;
-// s->insn_write = das16m1_do_wbits;
+ s->insn_bits = das16m1_do_wbits;
s = dev->subdevices + 3;
/* 8255 */
subdev_8255_init(dev, s, NULL, (void*)(dev->iobase + DAS16M1_82C55));
- // XXX should init digital output levels here also
+ // initialize digital output lines
+ outb(devpriv->do_bits, dev->iobase + DAS16M1_DIO);
+
/* set the interrupt level */
devpriv->control_state = das16m1_irq_bits(dev->irq);
outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL);