📄 adv_pci1710.c
字号:
return 4; } /* step 5: complain about special chanlist considerations */ if (cmd->chanlist){ if (!check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len)) return 5; // incorrect channels list } DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) ret=0\n"); return 0;}/* ==============================================================================*/static int pci171x_ai_cmd(comedi_device *dev,comedi_subdevice *s){ comedi_cmd *cmd=&s->async->cmd; DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmd(...)\n"); devpriv->ai_n_chan=cmd->chanlist_len; devpriv->ai_chanlist=cmd->chanlist; devpriv->ai_flags=cmd->flags; devpriv->ai_data_len=s->async->prealloc_bufsz; devpriv->ai_data=s->async->prealloc_buf; devpriv->ai_timer1=0; devpriv->ai_timer2=0; if (cmd->stop_src==TRIG_COUNT) { devpriv->ai_scans=cmd->stop_arg; } else { devpriv->ai_scans=0; } if(cmd->scan_begin_src==TRIG_FOLLOW){ // mode 1, 2, 3 if (cmd->convert_src==TRIG_TIMER) { // mode 1 and 2 devpriv->ai_timer1=cmd->convert_arg; return pci171x_ai_docmd_and_mode(cmd->start_src==TRIG_EXT?2:1,dev,s); } if (cmd->convert_src==TRIG_EXT) { // mode 3 return pci171x_ai_docmd_and_mode(3,dev,s); } } return -1;}/*============================================================================== Check if channel list from user is builded correctly If it's ok, then program scan/gain logic. This works for all cards.*/static int check_channel_list(comedi_device * dev, comedi_subdevice * s, unsigned int *chanlist, unsigned int n_chan){ unsigned int chansegment[32]; unsigned int i, nowmustbechan, seglen, segpos; DPRINTK("adv_pci1710 EDBG: check_channel_list(...,%d)\n",n_chan); /* correct channel and range number check itself comedi/range.c */ if (n_chan<1) { comedi_error(dev,"range/channel list is empty!"); return 0; } if (n_chan > 1) { chansegment[0]=chanlist[0]; // first channel is everytime ok for (i=1, seglen=1; i<n_chan; i++, seglen++) { // build part of chanlist // rt_printk("%d. %d %d\n",i,CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); if (chanlist[0]==chanlist[i]) break; // we detect loop, this must by finish if (CR_CHAN(chanlist[i]) & 1) // odd channel cann't by differencial if (CR_AREF(chanlist[i])==AREF_DIFF) { comedi_error(dev,"Odd channel can't be differential input!\n"); return 0; } nowmustbechan=(CR_CHAN(chansegment[i-1])+1) % s->n_chan; if (CR_AREF(chansegment[i-1])==AREF_DIFF) nowmustbechan=(nowmustbechan+1) % s->n_chan; if (nowmustbechan!=CR_CHAN(chanlist[i])) { // channel list isn't continous :-( rt_printk("channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n", i,CR_CHAN(chanlist[i]),nowmustbechan,CR_CHAN(chanlist[0]) ); return 0; } chansegment[i]=chanlist[i]; // well, this is next correct channel in list } for (i=0, segpos=0; i<n_chan; i++) { // check whole chanlist //rt_printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); if (chanlist[i]!=chansegment[i%seglen]) { rt_printk("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n", i,CR_CHAN(chansegment[i]),CR_RANGE(chansegment[i]),CR_AREF(chansegment[i]),CR_CHAN(chanlist[i%seglen]),CR_RANGE(chanlist[i%seglen]),CR_AREF(chansegment[i%seglen])); return 0; // chan/gain list is strange } } } else { seglen=1; } return seglen;} static void setup_channel_list(comedi_device * dev, comedi_subdevice * s, unsigned int *chanlist, unsigned int n_chan, unsigned int seglen){ unsigned int i, range, chanprog; DPRINTK("adv_pci1710 EDBG: setup_channel_list(...,%d,%d)\n",n_chan,seglen); devpriv->act_chanlist_len=seglen; devpriv->act_chanlist_pos=0; DPRINTK("SegLen: %d\n", seglen); for (i=0; i<seglen; i++) { // store range list to card chanprog=muxonechan[CR_CHAN(chanlist[i])]; outw(chanprog, dev->iobase+PCI171x_MUX); /* select channel */ range=this_board->rangecode_ai[CR_RANGE(chanlist[i])]; if (CR_AREF(chanlist[i])==AREF_DIFF) range|=0x0020; outw(range, dev->iobase+PCI171x_RANGE); /* select gain */#ifdef PCI171x_PARANOIDCHECK devpriv->act_chanlist[i]=(CR_CHAN(chanlist[i])<<12) & 0xf000;#endif DPRINTK("GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range, devpriv->act_chanlist[i]); } devpriv->ai_et_MuxVal = CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen-1]) << 8); outw(devpriv->ai_et_MuxVal, dev->iobase+PCI171x_MUX); /* select channel interval to scan */ DPRINTK("MUX: %4x L%4x.H%4x\n", CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen-1]) << 8), CR_CHAN(chanlist[0]), CR_CHAN(chanlist[seglen-1]));}/*==============================================================================*/static void start_pacer(comedi_device * dev, int mode, unsigned int divisor1, unsigned int divisor2) { DPRINTK("adv_pci1710 EDBG: BGN: start_pacer(%d,%u,%u)\n",mode,divisor1,divisor2); outw(0xb4, dev->iobase + PCI171x_CNTCTRL); outw(0x74, dev->iobase + PCI171x_CNTCTRL); if (mode==1) { outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2); outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2); outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1); outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1); } DPRINTK("adv_pci1710 EDBG: END: start_pacer(...)\n");}/* ==============================================================================*/static int pci171x_ai_cancel(comedi_device * dev, comedi_subdevice * s){ DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cancel(...)\n"); switch (this_board->cardtype) { default: devpriv->CntrlReg&=Control_CNT0; devpriv->CntrlReg|=Control_SW; outw(devpriv->CntrlReg, dev->iobase+PCI171x_CONTROL); // reset any operations start_pacer(dev,-1,0,0); outb(0,dev->iobase + PCI171x_CLRFIFO); outb(0,dev->iobase + PCI171x_CLRINT); break; } devpriv->ai_do=0; devpriv->ai_act_scan=0; s->async->cur_chan=0; devpriv->ai_buf_ptr=0; devpriv->neverending_ai=0; DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_cancel(...)\n"); return 0;}/* ==============================================================================*/static int pci171x_reset(comedi_device *dev){ DPRINTK("adv_pci1710 EDBG: BGN: pci171x_reset(...)\n"); outw(0x30, dev->iobase + PCI171x_CNTCTRL); devpriv->CntrlReg=Control_SW; // Software trigger, CNT0=100kHz outw(devpriv->CntrlReg, dev->iobase+PCI171x_CONTROL); // reset any operations outb(0, dev->iobase + PCI171x_CLRFIFO); // clear FIFO outb(0, dev->iobase + PCI171x_CLRINT); // clear INT request start_pacer(dev,-1,0,0); // stop 8254 devpriv->da_ranges=0; if (this_board->n_aochan) { outb(devpriv->da_ranges, dev->iobase+PCI171x_DAREF); // set DACs to 0..5V outw(0, dev->iobase+PCI171x_DA1); // set DA outputs to 0V devpriv->ao_data[0]=0x0000; if (this_board->n_aochan>1) { outw(0, dev->iobase+PCI171x_DA2); devpriv->ao_data[1]=0x0000; } } outw(0, dev->iobase + PCI171x_DO); // digital outputs to 0 outb(0, dev->iobase + PCI171x_CLRFIFO); // clear FIFO outb(0, dev->iobase + PCI171x_CLRINT); // clear INT request DPRINTK("adv_pci1710 EDBG: END: pci171x_reset(...)\n"); return 0;}/* ==============================================================================*/static int pci1720_reset(comedi_device *dev){ DPRINTK("adv_pci1710 EDBG: BGN: pci1720_reset(...)\n"); outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT); // set synchronous output mode devpriv->da_ranges=0xAA; outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE); // set all ranges to +/-5V outw(0x0800, dev->iobase + PCI1720_DA0); // set outputs to 0V outw(0x0800, dev->iobase + PCI1720_DA1); outw(0x0800, dev->iobase + PCI1720_DA2); outw(0x0800, dev->iobase + PCI1720_DA3); outb(0, dev->iobase + PCI1720_SYNCOUT); // update outputs devpriv->ao_data[0]=0x0800; devpriv->ao_data[1]=0x0800; devpriv->ao_data[2]=0x0800; devpriv->ao_data[3]=0x0800; DPRINTK("adv_pci1710 EDBG: END: pci1720_reset(...)\n"); return 0;}/* ==============================================================================*/static int pci1710_reset(comedi_device *dev){ DPRINTK("adv_pci1710 EDBG: BGN: pci1710_reset(...)\n"); switch (this_board->cardtype) { case TYPE_PCI1720: return pci1720_reset(dev); default: return pci171x_reset(dev); } DPRINTK("adv_pci1710 EDBG: END: pci1710_reset(...)\n");}/* ==============================================================================*/static int pci1710_attach(comedi_device *dev,comedi_devconfig *it){ comedi_subdevice *s; int ret,subdev,n_subdevices; unsigned short io_addr[5],master,irq; struct pcilst_struct *card=NULL; unsigned int iobase; unsigned char pci_bus,pci_slot,pci_func; if (!pci_list_builded) { pci_card_list_init(PCI_VENDOR_ID_ADVANTECH,#ifdef PCI171X_EXTDEBUG 1#else 0#endif ); pci_list_builded=1; } rt_printk("comedi%d: adv_pci1710: board=%s",dev->minor,this_board->name); /* this call pci_enable_device() */ if ((card=select_and_alloc_pci_card(PCI_VENDOR_ID_ADVANTECH, this_board->device_id, it->options[0], it->options[1], 0))==NULL) return -EIO; if ((pci_card_data(card,&pci_bus,&pci_slot,&pci_func, &io_addr[0],&irq,&master))<0) { pci_card_free(card); rt_printk(" - Can't get configuration data!\n"); return -EIO; } iobase=io_addr[2]; rt_printk(", b:s:f=%d:%d:%d, io=0x%4x",pci_bus,pci_slot,pci_func,iobase); if (check_region(iobase, this_board->iorange) < 0) { pci_card_free(card); rt_printk("I/O port conflict\n"); return -EIO; } request_region(iobase, this_board->iorange, "Advantech PCI-1710"); dev->iobase=iobase; dev->board_name = this_board->name; if((ret=alloc_private(dev,sizeof(pci1710_private)))<0) { release_region(dev->iobase, this_board->iorange); pci_card_free(card); return -ENOMEM; } 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((ret=alloc_subdevices(dev, n_subdevices))<0) { release_region(dev->iobase, this_board->iorange); pci_card_free(card); return ret; } if (this_board->have_irq) { if (irq) { if (comedi_request_irq(irq, interrupt_service_pci1710, SA_SHIRQ, "Advantech PCI-1710", dev)) { rt_printk(", unable to allocate IRQ %d, DISABLING IT", irq); irq=0; /* Can't use IRQ */ } else { rt_printk(", irq=%d", irq); } } else { rt_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->cancel=pci171x_ai_cancel; s->insn_read=pci171x_insn_read_ai; if (irq) { s->do_cmdtest=pci171x_ai_cmdtest; s->do_cmd=pci171x_ai_cmd; } devpriv->i8254_osc_base=100; // 100ns=10MHz 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; switch (this_board->cardtype) { case TYPE_PCI1720: s->insn_write=pci1720_insn_write_ao; break; default: s->insn_write=pci171x_insn_write_ao; break; } s->insn_read=pci171x_insn_read_ao; subdev++; } if (this_board->n_dichan) { s = dev->subdevices + subdev; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE|SDF_GROUND|SDF_COMMON; 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; /* all bits input */ s->insn_bits=pci171x_insn_bits_di; subdev++; } if (this_board->n_dochan) { s = dev->subdevices + subdev; s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE|SDF_GROUND|SDF_COMMON; 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; /* all bits output */ s->state=0; s->insn_bits=pci171x_insn_bits_do; subdev++; } // XXX There is unused counter 0 from onboard 82C54. Well, one user counter/timer? devpriv->valid=1; pci1710_reset(dev); return 0;}/* ==============================================================================*/static int pci1710_detach(comedi_device *dev){ if (dev->private) if (devpriv->valid) pci1710_reset(dev); if (dev->irq) comedi_free_irq(dev->irq,dev); if (dev->iobase) release_region(dev->iobase,this_board->iorange); if (pci_list_builded) { pci_card_list_cleanup(PCI_VENDOR_ID_ADVANTECH); pci_list_builded=0; } return 0;}/* ==============================================================================*/COMEDI_INITCLEANUP(driver_pci1710);/* ==============================================================================*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -