📄 das16m1.c
字号:
}static int das16m1_ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data){ int i, n; int byte; const int timeout = 1000; /* disable interrupts and internal pacer */ devpriv->control_state &= ~INTE & ~PACER_MASK; outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL); /* 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++) { /* clear IRQDATA bit */ outb(0, dev->iobase + DAS16M1_CLEAR_INTR); /* trigger conversion */ outb(0, dev->iobase); for(i = 0; i < timeout; i++) { if(inb(dev->iobase + DAS16M1_CS) & IRQDATA) break; } if(i == timeout) { comedi_error(dev, "timeout"); return -ETIME; } data[n] = munge_sample( inw( dev->iobase ) ); } return n;}static int das16m1_di_rbits(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsampl_t *data){ lsampl_t bits; 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){ lsampl_t wbits; // 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; outb(devpriv->do_bits, dev->iobase + DAS16M1_DIO); return 2;}static int das16m1_poll(comedi_device *dev, comedi_subdevice *s){ unsigned long flags; unsigned int status; // prevent race with interrupt handler comedi_spin_lock_irqsave(&dev->spinlock, flags); status = inb(dev->iobase + DAS16M1_CS); das16m1_handler(dev, status); comedi_spin_unlock_irqrestore(&dev->spinlock, flags); return s->async->buf_write_count - s->async->buf_read_count;}static void das16m1_interrupt(int irq, void *d, struct pt_regs *regs){ int status; comedi_device *dev = d; if(dev->attached == 0) { comedi_error(dev, "premature interrupt"); return; } // prevent race with comedi_poll() spin_lock(&dev->spinlock); status = inb(dev->iobase + DAS16M1_CS); if((status & (IRQDATA | OVRUN)) == 0) { comedi_error(dev, "spurious interrupt"); spin_unlock(&dev->spinlock); return; } das16m1_handler(dev, status); /* clear interrupt */ outb(0, dev->iobase + DAS16M1_CLEAR_INTR); spin_unlock(&dev->spinlock);}static void munge_sample_array( sampl_t *array, unsigned int num_elements ){ unsigned int i; for(i = 0; i < num_elements; i++) { array[i] = munge_sample( array[i] ); }}static void das16m1_handler(comedi_device *dev, unsigned int status){ comedi_subdevice *s; comedi_async *async; comedi_cmd *cmd; u16 num_samples; u16 hw_counter; s = dev->read_subdev; async = s->async; async->events = 0; cmd = &async->cmd; // figure out how many samples are in fifo hw_counter = i8254_read(dev->iobase + DAS16M1_8254_FIRST, 1); /* make sure hardware counter reading is not bogus due to initial value * not having been loaded yet */ if(devpriv->adc_count == 0 && hw_counter == devpriv->initial_hw_count) { num_samples = 0; }else { /* The calculation of num_samples looks odd, but it uses the following facts. * 16 bit hardware counter is initialized with value of zero (which really * means 0x1000). The counter decrements by one on each conversion * (when the counter decrements from zero it goes to 0xffff). num_samples * is a 16 bit variable, so it will roll over in a similar fashion to the * hardware counter. Work it out, and this is what you get. */ num_samples = - hw_counter - devpriv->adc_count; } // check if we only need some of the points if(cmd->stop_src == TRIG_COUNT) { if(num_samples > cmd->stop_arg * cmd->chanlist_len) num_samples = cmd->stop_arg * cmd->chanlist_len; } // make sure we dont try to get too many points if fifo has overrun if(num_samples > FIFO_SIZE) num_samples = FIFO_SIZE; insw( dev->iobase, devpriv->ai_buffer, num_samples ); munge_sample_array( devpriv->ai_buffer, num_samples ); cfc_write_array_to_buffer( s, devpriv->ai_buffer, num_samples * sizeof( sampl_t ) ); devpriv->adc_count += num_samples; if(cmd->stop_src == TRIG_COUNT) { if(devpriv->adc_count >= cmd->stop_arg * cmd->chanlist_len) { /* end of acquisition */ das16m1_cancel(dev, s); async->events |= COMEDI_CB_EOA; } } /* this probably won't catch overruns since the card doesn't generate * overrun interrupts, but we might as well try */ if(status & OVRUN) { das16m1_cancel(dev, s); async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; comedi_error(dev, "fifo overflow"); } comedi_event(dev, s, async->events);}/* This function takes a time in nanoseconds and sets the * * 2 pacer clocks to the closest frequency possible. It also * * returns the actual sampling period. */static unsigned int das16m1_set_pacer(comedi_device *dev, unsigned int ns, int rounding_flags){ i8253_cascade_ns_to_timer_2div(DAS16M1_XTAL, &(devpriv->divisor1), &(devpriv->divisor2), &ns, rounding_flags & TRIG_ROUND_MASK); /* Write the values of ctr1 and ctr2 into counters 1 and 2 */ i8254_load(dev->iobase + DAS16M1_8254_SECOND, 1, devpriv->divisor1, 2); i8254_load(dev->iobase + DAS16M1_8254_SECOND, 2, devpriv->divisor2, 2); return ns;}static int das16m1_irq_bits(unsigned int irq){ int ret; switch(irq) { case 10: ret = 0x0; break; case 11: ret = 0x1; break; case 12: ret = 0x2; break; case 15: ret = 0x3; break; case 2: ret = 0x4; break; case 3: ret = 0x5; break; case 5: ret = 0x6; break; case 7: ret = 0x7; break; default: return -1; break; } return (ret << 4);}/* * Options list: * 0 I/O base * 1 IRQ */static int das16m1_attach(comedi_device *dev, comedi_devconfig *it){ comedi_subdevice *s; int ret, irq; int iobase; iobase = it->options[0]; printk("comedi%d: das16m1:", dev->minor); if((ret = alloc_private(dev, sizeof(struct das16m1_private_struct))) < 0) return ret; dev->board_name = thisboard->name; printk(" io 0x%x-0x%x 0x%x-0x%x", iobase, iobase + DAS16M1_SIZE, iobase + DAS16M1_82C55, iobase + DAS16M1_82C55 + DAS16M1_SIZE2); if(check_region(iobase, DAS16M1_SIZE) < 0) { printk(" I/O port conflict\n"); return -EIO; } if(check_region(iobase + DAS16M1_82C55, DAS16M1_SIZE2) < 0){ printk(" I/O port conflict\n"); return -EIO; } request_region(iobase, DAS16M1_SIZE, driver_das16m1.driver_name); request_region(iobase + DAS16M1_82C55, DAS16M1_SIZE2, driver_das16m1.driver_name); dev->iobase = iobase; /* now for the irq */ irq = it->options[1]; // make sure it is valid if(das16m1_irq_bits(irq) >= 0) { ret = comedi_request_irq(irq, das16m1_interrupt, 0, driver_das16m1.driver_name, dev); if(ret < 0) { printk(", irq unavailable\n"); return ret; } dev->irq = irq; printk(", irq %d\n", irq); }else if(irq == 0){ printk(", no irq\n"); }else { printk(", invalid irq\n" " valid irqs are 2, 3, 5, 7, 10, 11, 12, or 15\n"); return -EINVAL; } if((ret = alloc_subdevices(dev, 4)) < 0) return ret; s = dev->subdevices + 0; dev->read_subdev = s; /* ai */ s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE; s->n_chan = 8; s->subdev_flags = SDF_DIFF; s->len_chanlist = 256; s->maxdata = (1 << 12) - 1; s->range_table = &range_das16m1; s->insn_read = das16m1_ai_rinsn; s->do_cmdtest = das16m1_cmd_test; s->do_cmd = das16m1_cmd_exec; s->cancel = das16m1_cancel; s->poll = das16m1_poll; s = dev->subdevices + 1; /* di */ s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; s->n_chan = 4; s->maxdata = 1; s->range_table = &range_digital; s->insn_bits = das16m1_di_rbits; s = dev->subdevices + 2; /* do */ s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE | SDF_READABLE; s->n_chan = 4; s->maxdata = 1; s->range_table = &range_digital; s->insn_bits = das16m1_do_wbits; s = dev->subdevices + 3; /* 8255 */ subdev_8255_init(dev, s, NULL, (unsigned long)(dev->iobase + DAS16M1_82C55)); // disable upper half of hardware conversion counter so it doesn't mess with us outb(TOTAL_CLEAR, dev->iobase + DAS16M1_8254_FIRST_CNTRL); // initialize digital output lines outb(devpriv->do_bits, dev->iobase + DAS16M1_DIO); /* set the interrupt level */ if(dev->irq) devpriv->control_state = das16m1_irq_bits(dev->irq); else devpriv->control_state = 0; outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL); return 0;}static int das16m1_detach(comedi_device *dev){ printk("comedi%d: das16m1: remove\n", dev->minor);// das16m1_reset(dev); if(dev->subdevices) subdev_8255_cleanup(dev,dev->subdevices + 3); if(dev->irq) comedi_free_irq(dev->irq, dev); if(dev->iobase){ release_region(dev->iobase , DAS16M1_SIZE); release_region(dev->iobase + DAS16M1_82C55, DAS16M1_SIZE2); } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -