📄 ni_labpc.c
字号:
has_ao: 1, read_byte: labpc_inb, write_byte: labpc_outb, ai_range_table: &range_labpc_plus_ai, ai_range_code: labpc_plus_ai_gain_bits, ai_range_is_unipolar: labpc_plus_is_unipolar, ai_scan_up: 0, }, { name: "pci-1200", device_id: 0x161, ai_speed: 10000, bustype: pci_bustype, register_layout: labpc_1200_layout, has_ao: 1, read_byte: labpc_readb, write_byte: labpc_writeb, ai_range_table: &range_labpc_1200_ai, ai_range_code: labpc_1200_ai_gain_bits, ai_range_is_unipolar: labpc_1200_is_unipolar, ai_scan_up: 1, },};/* * Useful for shorthand access to the particular board structure */#define thisboard ((labpc_board *)dev->board_ptr)static const int dma_buffer_size = 0xff00; // size in bytes of dma bufferstatic const int sample_size = 2; // 2 bytes per sampletypedef struct{ struct mite_struct *mite; // for mite chip on pci-1200 volatile unsigned long long count; /* number of data points left to be taken */ unsigned int ao_value[NUM_AO_CHAN]; // software copy of analog output values // software copys of bits written to command registers volatile unsigned int command1_bits; volatile unsigned int command2_bits; volatile unsigned int command3_bits; volatile unsigned int command4_bits; volatile unsigned int command5_bits; volatile unsigned int command6_bits; // store last read of board status registers volatile unsigned int status1_bits; volatile unsigned int status2_bits; unsigned int divisor_a0; /* value to load into board's counter a0 (conversion pacing) for timed conversions */ unsigned int divisor_b0; /* value to load into board's counter b0 (master) for timed conversions */ unsigned int divisor_b1; /* value to load into board's counter b1 (scan pacing) for timed conversions */ unsigned int dma_chan; // dma channel to use u16 *dma_buffer; // buffer ai will dma into unsigned int dma_transfer_size; // transfer size in bytes for current transfer enum transfer_type current_transfer; // we are using dma/fifo-half-full/etc. unsigned int eeprom_data[EEPROM_SIZE]; // stores contents of board's eeprom unsigned int caldac[16]; // stores settings of calibration dacs}labpc_private;#define devpriv ((labpc_private *)dev->private)static comedi_driver driver_labpc={ driver_name: "ni_labpc", module: THIS_MODULE, attach: labpc_attach, detach: labpc_detach, num_names: sizeof(labpc_boards) / sizeof(labpc_board), board_name: (char **)labpc_boards, offset: sizeof(labpc_board),};static struct pci_device_id labpc_pci_table[] __devinitdata = { { PCI_VENDOR_ID_NATINST, 0x161, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { 0 }};MODULE_DEVICE_TABLE(pci, labpc_pci_table);static int labpc_attach(comedi_device *dev, comedi_devconfig *it){ comedi_subdevice *s; int iobase = 0; int irq = 0; int dma_chan = 0; int lsb, msb; int i; unsigned long flags, isr_flags; int ret;#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE) dev_link_t *link;#endif /* allocate and initialize dev->private */ if(alloc_private(dev, sizeof(labpc_private)) < 0) return -ENOMEM; // get base address, irq etc. based on bustype switch(thisboard->bustype) { case isa_bustype: iobase = it->options[0]; irq = it->options[1]; dma_chan = it->options[2]; break; case pci_bustype: devpriv->mite = labpc_find_device(it->options[0], it->options[1]); if(devpriv->mite == NULL) { return -EIO; } if(thisboard->device_id != mite_device_id(devpriv->mite)) { // this should never happen since this driver only supports one type of pci board printk("bug! mite device id does not match boardtype definition\n"); return -EINVAL; } ret = mite_setup(devpriv->mite); if(ret < 0) return ret; iobase = mite_iobase(devpriv->mite); irq = mite_irq(devpriv->mite); break; case pcmcia_bustype:#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE) link = pcmcia_dev_list; /* XXX hack */ if(!link) return -EIO; iobase = link->io.BasePort1; irq = link->irq.AssignedIRQ;#else printk(" driver was not compiled with pcmcia support\n"); return -EINVAL;#endif // CONFIG_PCMCIA break; default: printk("bug! couldn't determine board type\n");\ return -EINVAL; break; } printk("comedi%d: ni_labpc: %s, io 0x%x", dev->minor, thisboard->name, iobase); if(irq) { printk(", irq %i", irq); } if(dma_chan) { printk(", dma %i", dma_chan); } printk("\n"); if(iobase == 0) { printk("io base address is zero!\n"); return -EINVAL; } // request io regions for isa boards if(thisboard->bustype == isa_bustype) { /* check if io addresses are available */ if(check_region(iobase, LABPC_SIZE) < 0) { printk("I/O port conflict\n"); return -EIO; } request_region(iobase, LABPC_SIZE, driver_labpc.driver_name); } dev->iobase = iobase; // initialize board's command registers thisboard->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG); thisboard->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG); thisboard->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG); thisboard->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG); if(thisboard->register_layout == labpc_1200_layout) { thisboard->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); thisboard->write_byte(devpriv->command6_bits, dev->iobase + COMMAND6_REG); } /* grab our IRQ */ if(irq < 0) { printk("irq out of range\n"); return -EINVAL; } if(irq) { isr_flags = 0; if((thisboard->bustype == pci_bustype)#if 0 // I'm fairly sure the daqcard-1200 interrupt cannot be shared || (thisboard->bustype == pcmcia_bustype)#endif ) isr_flags |= SA_SHIRQ; if(comedi_request_irq( irq, labpc_interrupt, isr_flags, driver_labpc.driver_name, dev)) { printk( "unable to allocate irq %d\n", irq); return -EINVAL; } } dev->irq = irq; // grab dma channel if(dma_chan < 0 || dma_chan > 3) { printk(" invalid dma channel\n"); return -EINVAL; }else if(dma_chan) { // allocate dma buffer devpriv->dma_buffer = kmalloc(dma_buffer_size, GFP_KERNEL | GFP_DMA); if(devpriv->dma_buffer == NULL) { printk(" failed to allocate dma buffer\n"); return -ENOMEM; } if(request_dma(dma_chan, driver_labpc.driver_name)) { printk(" failed to allocate dma channel %i\n", dma_chan); return -EINVAL; } devpriv->dma_chan = dma_chan; flags = claim_dma_lock(); disable_dma(devpriv->dma_chan); set_dma_mode(devpriv->dma_chan, DMA_MODE_READ); release_dma_lock(flags); } dev->board_name = thisboard->name; if(alloc_subdevices(dev, 5) < 0) return -ENOMEM; /* analog input subdevice */ s = dev->subdevices + 0; dev->read_subdev = s; s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF; s->n_chan = 8; s->len_chanlist = 8; s->maxdata = (1 << 12) - 1; // 12 bit resolution s->range_table = thisboard->ai_range_table; s->do_cmd = labpc_ai_cmd; s->do_cmdtest = labpc_ai_cmdtest; s->insn_read = labpc_ai_rinsn; s->cancel = labpc_cancel; /* analog output */ s = dev->subdevices + 1; if(thisboard->has_ao) {/* Could provide command support, except it only has a one sample * hardware buffer for analog output and no underrun flag. */ s->type=COMEDI_SUBD_AO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND; s->n_chan = NUM_AO_CHAN; s->maxdata = (1 << 12) - 1; // 12 bit resolution s->range_table = &range_labpc_ao; s->insn_read = labpc_ao_rinsn; s->insn_write = labpc_ao_winsn; /* initialize analog outputs to a known value */ for(i = 0; i < s->n_chan; i++) { devpriv->ao_value[i] = s->maxdata / 2; lsb = devpriv->ao_value[i] & 0xff; msb = (devpriv->ao_value[i] >> 8) & 0xff; thisboard->write_byte(lsb, dev->iobase + DAC_LSB_REG(i)); thisboard->write_byte(msb, dev->iobase + DAC_MSB_REG(i)); } }else { s->type = COMEDI_SUBD_UNUSED; } /* 8255 dio */ s = dev->subdevices + 2; // if board uses io memory we have to give a custom callback function to the 8255 driver if(thisboard->write_byte == labpc_writeb) subdev_8255_init(dev, s, labpc_dio_mem_callback, (unsigned long)(dev->iobase + DIO_BASE_REG)); else subdev_8255_init(dev, s, NULL, dev->iobase + DIO_BASE_REG); // calibration subdevices for boards that have one s = dev->subdevices + 3; if(thisboard->register_layout == labpc_1200_layout) { s->type=COMEDI_SUBD_CALIB; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; s->n_chan = 16; s->maxdata = 0xff; s->insn_read = labpc_calib_read_insn; s->insn_write = labpc_calib_write_insn; for( i = 0; i < s->n_chan; i++ ) write_caldac( dev, i, s->maxdata / 2 ); }else s->type = COMEDI_SUBD_UNUSED; /* EEPROM */ s = dev->subdevices + 4; if(thisboard->register_layout == labpc_1200_layout) { s->type = COMEDI_SUBD_MEMORY; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; s->n_chan = EEPROM_SIZE; s->maxdata = 0xff; s->insn_read = labpc_eeprom_read_insn; s->insn_write = labpc_eeprom_write_insn; for(i = 0; i < EEPROM_SIZE; i++) { devpriv->eeprom_data[i] = labpc_eeprom_read(dev, i); }#ifdef LABPC_DEBUG printk(" eeprom:"); for(i = 0; i < EEPROM_SIZE; i++) { printk(" %i:0x%x ", i, devpriv->eeprom_data[i]); } printk("\n");#endif }else s->type = COMEDI_SUBD_UNUSED; return 0;};// adapted from ni_pcimio for finding mite based boards (pc-1200)static struct mite_struct* labpc_find_device(int bus, int slot){ struct mite_struct *mite; int i; for(mite = mite_devices; mite; mite = mite->next) { if(mite->used) continue; // if bus/slot are specified then make sure we have the right bus/slot if(bus || slot) { if(bus != mite->pcidev->bus->number || slot != PCI_SLOT(mite->pcidev->devfn)) continue; } for(i = 0; i < driver_labpc.num_names; i++) { if(labpc_boards[i].bustype != pci_bustype) continue; if(mite_device_id(mite) == labpc_boards[i].device_id) { return mite; } } } printk("no device found\n"); mite_list_devices(); return NULL;}static int labpc_detach(comedi_device *dev){ printk("comedi%d: ni_labpc: remove\n", dev->minor); if(dev->subdevices) subdev_8255_cleanup(dev,dev->subdevices + 2); /* only free stuff if it has been allocated by _attach */ if(devpriv->dma_buffer) kfree(devpriv->dma_buffer); if(devpriv->dma_chan) free_dma(devpriv->dma_chan); if(dev->irq) comedi_free_irq(dev->irq, dev); if(thisboard->bustype == isa_bustype && dev->iobase) release_region(dev->iobase, LABPC_SIZE); if( devpriv->mite ) mite_unsetup( devpriv->mite ); return 0;};static void labpc_clear_adc_fifo( const comedi_device *dev ){ thisboard->write_byte(0x1, dev->iobase + ADC_CLEAR_REG); thisboard->read_byte(dev->iobase + ADC_FIFO_REG); thisboard->read_byte(dev->iobase + ADC_FIFO_REG);}static int labpc_cancel(comedi_device *dev, comedi_subdevice *s){ unsigned long flags; comedi_spin_lock_irqsave( &dev->spinlock, flags ); devpriv->command2_bits &= ~SWTRIG_BIT & ~HWTRIG_BIT & ~PRETRIG_BIT; thisboard->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG); comedi_spin_unlock_irqrestore( &dev->spinlock, flags ); devpriv->command3_bits = 0; thisboard->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG); return 0;}static enum scan_mode labpc_ai_scan_mode( const comedi_cmd *cmd ){ if( cmd->chanlist_len == 1 ) return MODE_SINGLE_CHAN; if( CR_CHAN( cmd->chanlist[0] ) == CR_CHAN( cmd->chanlist[1] ) ) return MODE_SINGLE_CHAN_INTERVAL; if( CR_CHAN( cmd->chanlist[0] ) < CR_CHAN( cmd->chanlist[1] ) ) return MODE_MULT_CHAN_UP; if( CR_CHAN( cmd->chanlist[0] ) > CR_CHAN( cmd->chanlist[1] ) ) return MODE_MULT_CHAN_DOWN; rt_printk( "ni_labpc: bug! this should never happen\n"); return 0;}static int labpc_ai_chanlist_invalid( const comedi_device *dev, const comedi_cmd *cmd ){ int mode, channel, range, aref, i; if( cmd->chanlist == NULL ) return 0; mode = labpc_ai_scan_mode( cmd ); if( mode == MODE_SINGLE_CHAN ) return 0; if( mode == MODE_SINGLE_CHAN_INTERVAL ) { if( cmd->chanlist_len > 0xff ) { comedi_error(dev, "ni_labpc: chanlist too long for single channel interval mode\n"); return 1; } } channel = CR_CHAN( cmd->chanlist[ 0 ] );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -