📄 icp_multi.c
字号:
/*============================================================================== Name: icp_multi_insn_read_ctr Description: This function reads the specified counter. Parameters: comedi_device *dev Pointer to current device structure comedi_subdevice *s Pointer to current subdevice structure comedi_insn *insn Pointer to current comedi instruction lsampl_t *data Pointer to counter data Returns:int Nmuber of instructions executed==============================================================================*/static int icp_multi_insn_read_ctr(comedi_device * dev, comedi_subdevice * s, comedi_insn *insn, lsampl_t *data){ return 0;}/*============================================================================== Name: icp_multi_insn_write_ctr Description: This function write to the specified counter. Parameters: comedi_device *dev Pointer to current device structure comedi_subdevice *s Pointer to current subdevice structure comedi_insn *insn Pointer to current comedi instruction lsampl_t *data Pointer to counter data Returns:int Nmuber of instructions executed==============================================================================*/static int icp_multi_insn_write_ctr(comedi_device * dev, comedi_subdevice * s, comedi_insn *insn, lsampl_t *data){ return 0;}/*============================================================================== Name: interrupt_service_icp_multi Description: This function is the interrupt service routine for all interrupts generated by the icp multi board. Parameters: int irq void *d Pointer to current device struct pt_regs *regs Pointer to Returns:int Nmuber of instructions executed==============================================================================*/static void interrupt_service_icp_multi(int irq, void *d, struct pt_regs *regs){ comedi_device *dev = d; int int_no; #ifdef ICP_MULTI_EXTDEBUG printk("icp multi EDBG: BGN: interrupt_service_icp_multi(%d,...)\n",irq);#endif // Is this interrupt from our board? int_no = readw(dev->iobase + ICP_MULTI_INT_STAT) & Status_IRQ; if (!int_no) // No, exit return;#ifdef ICP_MULTI_EXTDEBUG printk("icp multi EDBG: interrupt_service_icp_multi() ST: %4x\n",readw(dev->iobase + ICP_MULTI_INT_STAT));#endif // Determine which interrupt is active & handle it switch(int_no) { case ADC_READY: break; case DAC_READY: break; case DOUT_ERROR: break; case DIN_STATUS: break; case CIE0: break; case CIE1: break; case CIE2: break; case CIE3: break; default: break; }#ifdef ICP_MULTI_EXTDEBUG printk("icp multi EDBG: END: interrupt_service_icp_multi(...)\n");#endif}#if 0/*============================================================================== Name: check_channel_list Description: This function checks if the channel list, provided by user is built correctly Parameters: comedi_device *dev Pointer to current sevice structure comedi_subdevice *s Pointer to current subdevice structure unsigned int *chanlist Pointer to packed channel list unsigned int n_chan Number of channels to scan Returns:int 0 = failure 1 = success==============================================================================*/static int check_channel_list(comedi_device * dev, comedi_subdevice * s, unsigned int *chanlist, unsigned int n_chan){ unsigned int i; #ifdef ICP_MULTI_EXTDEBUG printk("icp multi EDBG: check_channel_list(...,%d)\n",n_chan);#endif // Check that we at least have one channel to check if (n_chan<1) { comedi_error(dev,"range/channel list is empty!"); return 0; } // Check all channels for (i=0; i<n_chan; i++) { // Check that channel number is < maximum if (CR_AREF(chanlist[i])==AREF_DIFF) { if (CR_CHAN(chanlist[i]) > this_board->n_aichand) { comedi_error(dev,"Incorrect differential ai channel number"); return 0; } } else { if (CR_CHAN(chanlist[i]) > this_board->n_aichan) { comedi_error(dev,"Incorrect ai channel number"); return 0; } } } return 1;}#endif/*============================================================================== Name: setup_channel_list Description: This function sets the appropriate channel selection, differential input mode and range bits in the ADC Command/ Status register. Parameters: comedi_device *dev Pointer to current sevice structure comedi_subdevice *s Pointer to current subdevice structure unsigned int *chanlist Pointer to packed channel list unsigned int n_chan Number of channels to scan Returns:Void==============================================================================*/static void setup_channel_list(comedi_device * dev, comedi_subdevice * s, unsigned int *chanlist, unsigned int n_chan){ unsigned int i, range, chanprog; unsigned int diff;#ifdef ICP_MULTI_EXTDEBUG printk("icp multi EDBG: setup_channel_list(...,%d)\n",n_chan);#endif devpriv->act_chanlist_len=n_chan; devpriv->act_chanlist_pos=0; for (i=0; i<n_chan; i++) { // Get channel chanprog=CR_CHAN(chanlist[i]); // Determine if it is a differential channel (Bit 15 = 1) if (CR_AREF(chanlist[i])==AREF_DIFF) { diff = 1; chanprog &= 0x0007; } else { diff = 0; chanprog &= 0x000f; } // Clear channel, range and input mode bits in A/D command/status register devpriv->AdcCmdStatus &= 0xf00f; // Set channel number and differential mode status bit if (diff) { // Set channel number, bits 9-11 & mode, bit 6 devpriv->AdcCmdStatus |= (chanprog << 9); devpriv->AdcCmdStatus |= ADC_DI; } else // Set channel number, bits 8-11 devpriv->AdcCmdStatus |= (chanprog << 8); // Get range for current channel range=this_board->rangecode[CR_RANGE(chanlist[i])]; // Set range. bits 4-5 devpriv->AdcCmdStatus |= range; /* Output channel, range, mode to ICP Multi*/ writew(devpriv->AdcCmdStatus, dev->iobase+ICP_MULTI_ADC_CSR);#ifdef ICP_MULTI_EXTDEBUG printk("GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range, devpriv->act_chanlist[i]);#endif }}/*============================================================================== Name: icp_multi_reset Description: This function resets the icp multi device to a 'safe' state Parameters: comedi_device *dev Pointer to current sevice structure Returns:int 0 = success==============================================================================*/static int icp_multi_reset(comedi_device *dev){ unsigned int i;#ifdef ICP_MULTI_EXTDEBUG printk("icp_multi EDBG: BGN: icp_multi_reset(...)\n");#endif // Clear INT enables and requests writew(0, dev->iobase + ICP_MULTI_INT_EN); writew(0x00ff, dev->iobase + ICP_MULTI_INT_STAT); if (this_board->n_aochan) // Set DACs to 0..5V range and 0V output for (i =0; i < this_board->n_aochan; i++) { devpriv->DacCmdStatus &= 0xfcce; // Set channel number devpriv->DacCmdStatus |= (i << 8); // Output 0V writew(0, dev->iobase+ICP_MULTI_AO); // Set start conversion bit devpriv->DacCmdStatus |= DAC_ST; // Output to command / status register writew(devpriv->DacCmdStatus, dev->iobase+ICP_MULTI_DAC_CSR); // Delay to allow DAC time to recover comedi_udelay(1); } // Digital outputs to 0 writew(0, dev->iobase + ICP_MULTI_DO);#ifdef ICP_MULTI_EXTDEBUG printk("icp multi EDBG: END: icp_multi_reset(...)\n");#endif return 0;}/*============================================================================== Name: icp_multi_attach Description: This function sets up all the appropriate data for the current device. Parameters: comedi_device *dev Pointer to current device structure comedi_devconfig *it Pointer to current device configuration Returns:int 0 = success==============================================================================*/static int icp_multi_attach(comedi_device *dev,comedi_devconfig *it){ comedi_subdevice *s; int ret, subdev, n_subdevices; unsigned short master,irq; struct pcilst_struct *card=NULL; unsigned long io_addr[5], iobase; unsigned char pci_bus, pci_slot, pci_func; printk("icp_multi EDBG: BGN: icp_multi_attach(...)\n"); // Alocate private data storage space if ((ret=alloc_private(dev, sizeof(icp_multi_private)))<0) return ret; // Initialise list of PCI cards in system, if not already done so if (!pci_list_builded) { pci_card_list_init(PCI_VENDOR_ID_ICP,#ifdef ICP_MULTI_EXTDEBUG 1#else 0#endif ); pci_list_builded=1; } printk("Anne's comedi%d: icp_multi: board=%s", dev->minor, this_board->name); if ((card=select_and_alloc_pci_card(PCI_VENDOR_ID_ICP, this_board->device_id, it->options[0], it->options[1]))==NULL) return -EIO; if ((pci_card_data(card, &pci_bus, &pci_slot, &pci_func, &io_addr[0], &irq, &master))<0) { pci_card_free(card); printk(" - Can't get configuration data!\n"); return -EIO; } iobase=io_addr[2];// if(check_mem_region(iobase, ICP_MULTI_SIZE))// { /* Couldn't allocate io space */// printk(KERN_WARNING "couldn't allocate IO space\n");// return -EIO;// }// request_mem_region(iobase, ICP_MULTI_SIZE, "icp_multi"); devpriv->phys_iobase = iobase; printk(", b:s:f=%d:%d:%d, io=0x%8lx \n", pci_bus, pci_slot, pci_func, iobase); devpriv->io_addr = ioremap(iobase, ICP_MULTI_SIZE); if (devpriv->io_addr == NULL) { printk("ioremap failed.\n"); return -ENOMEM; }#ifdef ICP_MULTI_EXTDEBUG printk("0x%08lx mapped to %p, ", iobase, devpriv->io_addr);#endif dev->iobase = (int)devpriv->io_addr; dev->board_name = this_board->name; n_subdevices = 0; if (this_board->n_aichan) n_subdevices++; if (this_board->n_aochan) n_subdevices++; if (this_board->n_dichan) n_subdevices++; if (this_board->n_dochan) n_subdevices++; if (this_board->n_ctrs) n_subdevices++; if((ret=alloc_subdevices(dev, n_subdevices))<0) { pci_card_free(card); return ret; } if (this_board->have_irq) { if (irq) { if (comedi_request_irq(irq, interrupt_service_icp_multi, SA_SHIRQ, "Inova Icp Multi", dev)) { printk(", unable to allocate IRQ %d, DISABLING IT", irq); irq=0; /* Can't use IRQ */ } else printk(", irq=%d", irq); } else printk(", IRQ disabled"); } else irq=0; dev->irq = irq; printk(".\n"); subdev=0; if (this_board->n_aichan) { s = dev->subdevices + subdev; dev->read_subdev = s; s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE|SDF_COMMON|SDF_GROUND; if (this_board->n_aichand) s->subdev_flags |= SDF_DIFF; s->n_chan = this_board->n_aichan; s->maxdata = this_board->ai_maxdata; s->len_chanlist = this_board->n_aichan; s->range_table = this_board->rangelist_ai; s->insn_read=icp_multi_insn_read_ai; subdev++; } if (this_board->n_aochan) { s = dev->subdevices + subdev; s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE|SDF_GROUND|SDF_COMMON; s->n_chan = this_board->n_aochan; s->maxdata = this_board->ao_maxdata; s->len_chanlist = this_board->n_aochan; s->range_table = this_board->rangelist_ao; s->insn_write=icp_multi_insn_write_ao; s->insn_read=icp_multi_insn_read_ao; subdev++; } if (this_board->n_dichan) { s = dev->subdevices + subdev; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; s->n_chan = this_board->n_dichan; s->maxdata = 1; s->len_chanlist = this_board->n_dichan; s->range_table = &range_digital; s->io_bits=0; s->insn_bits=icp_multi_insn_bits_di; subdev++; } if (this_board->n_dochan) { s = dev->subdevices + subdev; s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE | SDF_READABLE; s->n_chan = this_board->n_dochan; s->maxdata = 1; s->len_chanlist = this_board->n_dochan; s->range_table = &range_digital; s->io_bits=(1 << this_board->n_dochan)-1; s->state=0; s->insn_bits=icp_multi_insn_bits_do; subdev++; } if (this_board->n_ctrs) { s = dev->subdevices + subdev; s->type = COMEDI_SUBD_COUNTER; s->subdev_flags = SDF_WRITABLE|SDF_GROUND|SDF_COMMON; s->n_chan = this_board->n_ctrs; s->maxdata = 0xffff; s->len_chanlist = this_board->n_ctrs; s->state=0; s->insn_read=icp_multi_insn_read_ctr; s->insn_write=icp_multi_insn_write_ctr; subdev++; } devpriv->valid = 1; icp_multi_reset(dev);#ifdef ICP_MULTI_EXTDEBUG printk("icp multi EDBG: END: icp_multi_attach(...)\n");#endif return 0;}/*============================================================================== Name: icp_multi_detach Description: This function releases all the resources used by the current device. Parameters: comedi_device *dev Pointer to current device structure Returns:int 0 = success==============================================================================*/static int icp_multi_detach(comedi_device *dev){ if (dev->private) if (devpriv->valid) icp_multi_reset(dev); if (dev->irq) comedi_free_irq(dev->irq,dev); if (dev->iobase) { iounmap(devpriv->io_addr);// release_mem_region(iobase, ICP_MULTI_SIZE); } if (pci_list_builded) { pci_card_list_cleanup(PCI_VENDOR_ID_ICP); pci_list_builded=0; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -