📄 adl_pci9111.c
字号:
} if (pci9111_is_fifo_half_full()) {#ifdef INTERRUPT_DEBUG printk (PCI9111_DRIVER_NAME ": fifo is half full\n");#endif async->events |= COMEDI_CB_BLOCK; for (i=0;i<PCI9111_FIFO_HALF_SIZE;i++) { // FIXME: The resolution test should be done outside of the read loop if (resolution == PCI9111_HR_AI_RESOLUTION) { data = pci9111_hr_ai_get_data (); } else { data = pci9111_ai_get_data (); } if (((dev_private->stop_counter > 0) || (dev_private->stop_is_none)) && (dev_private->scan_begin_counter < async->cmd.chanlist_len)) { comedi_buf_put (async, data); dev_private->stop_counter--; } dev_private->scan_begin_counter++; if (dev_private->scan_begin_counter >= dev_private->scan_begin_counter_limit) { dev_private->scan_begin_counter=0; } } } } if ((dev_private->stop_counter==0) && (!dev_private->stop_is_none)) { async->events |= COMEDI_CB_EOA; pci9111_ai_cancel (dev, subdevice); } // Very important, otherwise another interrupt request will be inserted // and will cause driver hangs on processing interrupt event (and cause a // computer crash, and corrupt the source file of the driver you are // working on, since you forgot to do a sync before test, and you cry, // and ...) pci9111_interrupt_clear(); comedi_spin_unlock_irqrestore (&dev->spinlock, irq_flags); comedi_event (dev, subdevice, async->events);} // ------------------------------------------------------------------// // INSTANT ANALOG INPUT OUTPUT SECTION// // ------------------------------------------------------------------//// analog instant input//#undef AI_INSN_DEBUGstatic int pci9111_ai_insn_read ( comedi_device *dev, comedi_subdevice *subdevice, comedi_insn *insn, lsampl_t *data ){ int resolution = ((pci9111_board_struct *) dev->board_ptr)->ai_resolution; int timeout,i;#ifdef AI_INSN_DEBUG printk (PCI9111_DRIVER_NAME ": ai_insn set c/r/n = %2x/%2x/%2x\n", CR_CHAN((&insn->chanspec)[0]), CR_RANGE((&insn->chanspec)[0]), insn->n);#endif pci9111_ai_channel_set(CR_CHAN((&insn->chanspec)[0])); if ((pci9111_ai_range_get()) != CR_RANGE((&insn->chanspec)[0])) { pci9111_ai_range_set(CR_RANGE((&insn->chanspec)[0])); } pci9111_fifo_reset(); for (i=0;i<insn->n;i++) { pci9111_software_trigger(); timeout=PCI9111_AI_INSTANT_READ_TIMEOUT; while (timeout--) { if (!pci9111_is_fifo_empty()) goto conversion_done; } comedi_error(dev,"A/D read timeout"); data[i]=0; pci9111_fifo_reset(); return -ETIME;conversion_done: if (resolution==PCI9111_HR_AI_RESOLUTION) { data[i] = pci9111_hr_ai_get_data(); } else { data[i] = pci9111_ai_get_data(); } } #ifdef AI_INSN_DEBUG printk (PCI9111_DRIVER_NAME ": ai_insn get c/r/t = %2x/%2x/%2x\n", pci9111_ai_channel_get(), pci9111_ai_range_get(), pci9111_trigger_and_autoscan_get());#endif return i;}//// Analog instant output//static int pci9111_ao_insn_write ( comedi_device *dev, comedi_subdevice *s, comedi_insn *insn, lsampl_t *data ){ int i; for (i=0; i<insn->n; i++) { pci9111_ao_set_data(data[i]); dev_private->ao_readback=data[i]; } return i;}// // Analog output readback//static int pci9111_ao_insn_read ( comedi_device * dev, comedi_subdevice * s, comedi_insn *insn, lsampl_t *data) { int i; for (i=0; i<insn->n; i++) { data[i]=dev_private->ao_readback & PCI9111_AO_RESOLUTION_MASK; } return i;}// ------------------------------------------------------------------// // DIGITAL INPUT OUTPUT SECTION// // ------------------------------------------------------------------//// Digital inputs//static int pci9111_di_insn_bits ( comedi_device *dev, comedi_subdevice *subdevice, comedi_insn *insn, lsampl_t *data){ lsampl_t bits; bits = pci9111_di_get_bits(); data[1] = bits; return 2;}//// Digital outputs//static int pci9111_do_insn_bits ( comedi_device *dev, comedi_subdevice *subdevice, comedi_insn *insn, lsampl_t *data){ lsampl_t bits; // Only set bits that have been masked // data[0] = mask // data[1] = bit state data[0] &= PCI9111_DO_MASK; bits = subdevice->state; bits &= ~data[0]; bits |= data[0] & data[1]; subdevice->state = bits; pci9111_do_set_bits(bits); data[1] = bits; return 2;}// ------------------------------------------------------------------// // INITIALISATION SECTION// // ------------------------------------------------------------------//// Reset device// static int pci9111_reset (comedi_device *dev){ // Set trigger source to software plx9050_interrupt_control (dev_private->lcr_io_base, true, true, true, true, false); pci9111_trigger_source_set (dev, software); pci9111_pretrigger_set (dev, false); pci9111_autoscan_set (dev,false); // Reset 8254 chip dev_private->timer_divisor_1=0; dev_private->timer_divisor_2=0; pci9111_timer_set (dev); return 0;}//// Attach // // - Register PCI device// - Declare device driver capability// static int pci9111_attach(comedi_device *dev,comedi_devconfig *it){ comedi_subdevice *subdevice; int io_base, io_range, lcr_io_base, lcr_io_range; struct pci_dev* pci_device; int error,i; pci9111_board_struct* board;//// Probe the device to determine what device in the series it is.// printk("comedi%d: " PCI9111_DRIVER_NAME " driver\n",dev->minor); pci_for_each_dev(pci_device) { if (pci_device->vendor == PCI_VENDOR_ID_ADLINK) { for (i= 0; i< pci9111_board_nbr; i++) { if(pci9111_boards[i].device_id == pci_device->device) { // was a particular bus/slot requested? if((it->options[0] != 0) || (it->options[1] != 0)) { // are we on the wrong bus/slot? if(pci_device->bus->number != it->options[0] || PCI_SLOT(pci_device->devfn) != it->options[1]) { continue; } } dev->board_ptr = pci9111_boards + i; board = (pci9111_board_struct *) dev->board_ptr; goto found; } } } } printk ("comedi%d: no supported board found! (req. bus/slot : %d/%d)\n", dev->minor,it->options[0], it->options[1]); return -EIO;found: printk("comedi%d: found %s (b:s:f=%d:%d:%d) , irq=%d\n", dev->minor, pci9111_boards[i].name, pci_device->bus->number, PCI_SLOT(pci_device->devfn), PCI_FUNC(pci_device->devfn), pci_device->irq); // TODO: Warn about non-tested boards. switch(board->device_id) { }; // Read local configuration register base address [PCI_BASE_ADDRESS #1]. lcr_io_base = pci_resource_start (pci_device, 1); lcr_io_range = pci_resource_end (pci_device, 1) - lcr_io_base +1; printk ("comedi%d: local configuration registers at address 0x%4x [0x%4x]\n", dev->minor, lcr_io_base, lcr_io_range); if (check_region (lcr_io_base, lcr_io_range) < 0) { printk("comedi%d: I/O port conflict\n",dev->minor); return -EIO; } // Read PCI6308 register base address [PCI_BASE_ADDRESS #2]. io_base = pci_resource_start (pci_device, 2); io_range = pci_resource_end (pci_device, 2) - io_base +1; printk ("comedi%d: 6503 registers at address 0x%4x [0x%4x]\n", dev->minor, io_base, io_range); if (check_region (io_base, io_range) < 0) { printk("comedi%d: I/O port conflict\n",dev->minor); return -EIO; } // Allocate IO ressources pci_request_regions(pci_device, PCI9111_DRIVER_NAME); dev->iobase=io_base; dev->board_name = board->name; if(alloc_private(dev,sizeof(pci9111_private_data_struct))<0) return -ENOMEM; dev_private->pci_device = pci_device; dev_private->io_range = io_range; dev_private->is_valid=0; dev_private->lcr_io_base=lcr_io_base; dev_private->lcr_io_range=lcr_io_range; pci9111_reset(dev); // Irq setup dev->irq=0; if (pci_device->irq>0) { if (comedi_request_irq (pci_device->irq, pci9111_interrupt, SA_SHIRQ, PCI9111_DRIVER_NAME, dev)!=0) { printk ("comedi%d: unable to allocate irq %d\n", dev->minor, pci_device->irq); return -EINVAL; } } dev->irq = pci_device->irq; //// TODO: Add external multiplexer setup (according to option[2]).// if((error=alloc_subdevices(dev, 4))<0) return error; subdevice = dev->subdevices + 0; dev->read_subdev = subdevice; subdevice->type = COMEDI_SUBD_AI; subdevice->subdev_flags = SDF_READABLE|SDF_COMMON;//// TODO: Add external multiplexer data// // if (devpriv->usemux) { subdevice->n_chan = devpriv->usemux; }// else { subdevice->n_chan = this_board->n_aichan; }// subdevice->n_chan = board->ai_channel_nbr; subdevice->maxdata = board->ai_resolution_mask; subdevice->len_chanlist = board->ai_channel_nbr; subdevice->range_table = board->ai_range_list; subdevice->cancel = pci9111_ai_cancel; subdevice->insn_read = pci9111_ai_insn_read; subdevice->do_cmdtest = pci9111_ai_do_cmd_test; subdevice->do_cmd = pci9111_ai_do_cmd; subdevice = dev->subdevices + 1; subdevice->type = COMEDI_SUBD_AO; subdevice->subdev_flags = SDF_WRITABLE|SDF_COMMON; subdevice->n_chan = board->ao_channel_nbr; subdevice->maxdata = board->ao_resolution_mask; subdevice->len_chanlist = board->ao_channel_nbr; subdevice->range_table = board->ao_range_list; subdevice->insn_write = pci9111_ao_insn_write; subdevice->insn_read = pci9111_ao_insn_read; subdevice = dev->subdevices + 2; subdevice->type = COMEDI_SUBD_DI; subdevice->subdev_flags = SDF_READABLE; subdevice->n_chan = PCI9111_DI_CHANNEL_NBR; subdevice->maxdata = 1; subdevice->range_table = &range_digital; subdevice->insn_bits = pci9111_di_insn_bits; subdevice = dev->subdevices + 3; subdevice->type = COMEDI_SUBD_DO; subdevice->subdev_flags = SDF_READABLE|SDF_WRITABLE; subdevice->n_chan = PCI9111_DO_CHANNEL_NBR; subdevice->maxdata = 1; subdevice->range_table = &range_digital; subdevice->insn_bits = pci9111_do_insn_bits; dev_private->is_valid = 1; return 0;}//// Detach //static int pci9111_detach(comedi_device *dev){ // Reset device if (dev->private!=0) { if (dev_private->is_valid) pci9111_reset(dev); } // Release previously allocated irq if (dev->irq!=0) { comedi_free_irq(dev->irq,dev); } pci_release_regions(dev_private->pci_device); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -