📄 ni_pcidio.c
字号:
async->events |= COMEDI_CB_EOA; writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control); }#if 0 else{ printk("ni_pcidio: unknown interrupt\n"); async->events |= COMEDI_CB_ERROR|COMEDI_CB_EOA; writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control); }#endif flags = readb(dev->iobase+Group_1_Flags); status = readb(dev->iobase+Interrupt_And_Window_Status); //DPRINTK("loop end: IntEn=0x%02x,flags=0x%02x,status=0x%02x\n", // IntEn,flags,status); //ni_pcidio_print_flags(flags); //ni_pcidio_print_status(status); }out: comedi_event(dev,s,async->events); #if unused if(!tag){ writeb(0x03,dev->iobase+Master_DMA_And_Interrupt_Control); }#endif}#ifdef DEBUG_FLAGSstatic char *flags_strings[] = { "TransferReady", "CountExpired", "2", "3", "4", "Waited", "PrimaryTC", "SecondaryTC",};static void ni_pcidio_print_flags(unsigned int flags){ int i; printk("group_1_flags:"); for(i=7;i>=0;i--){ if(flags&(1<<i)){ printk(" %s",flags_strings[i]); } } printk("\n");}static char *status_strings[] = { "DataLeft1", "Reserved1", "Req1", "StopTrig1", "DataLeft2", "Reserved2", "Req2", "StopTrig2",};static void ni_pcidio_print_status(unsigned int flags){ int i; printk("group_status:"); for(i=7;i>=0;i--){ if(flags&(1<<i)){ printk(" %s",status_strings[i]); } } printk("\n");}#endif#ifdef unusedstatic void debug_int(comedi_device *dev){ int a,b; static int n_int = 0; struct timeval tv; do_gettimeofday(&tv); a=readb(dev->iobase+Group_Status); b=readb(dev->iobase+Group_1_Flags); if(n_int < 10){ DPRINTK("status 0x%02x flags 0x%02x time %06d\n",a,b,(int)tv.tv_usec); } while(b&1){ writew(0xff,dev->iobase+Group_1_FIFO); b=readb(dev->iobase+Group_1_Flags); } b=readb(dev->iobase+Group_1_Flags); if(n_int < 10){ DPRINTK("new status 0x%02x\n",b); n_int++; }}#endifstatic int ni_pcidio_insn_config(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data){ if(insn->n!=1)return -EINVAL; switch(data[0]){ case COMEDI_OUTPUT: s->io_bits |= 1<<CR_CHAN(insn->chanspec); break; case COMEDI_INPUT: s->io_bits &= ~(1<<CR_CHAN(insn->chanspec)); break; default: return -EINVAL; } writel(s->io_bits,dev->iobase+Port_Pin_Directions(0)); return 1;}static int ni_pcidio_insn_bits(comedi_device *dev,comedi_subdevice *s, comedi_insn *insn,lsampl_t *data){ if(insn->n!=2)return -EINVAL; if(data[0]){ s->state &= ~data[0]; s->state |= (data[0]&data[1]); writel(s->state,dev->iobase+Port_IO(0)); } data[1] = readl(dev->iobase+Port_IO(0)); return 2;}static int ni_pcidio_cmdtest(comedi_device *dev,comedi_subdevice *s, comedi_cmd *cmd){ int err=0; int tmp; /* step 1: make sure trigger sources are trivially valid */ tmp=cmd->start_src; cmd->start_src &= TRIG_NOW|TRIG_INT; if(!cmd->start_src || tmp!=cmd->start_src)err++; tmp=cmd->scan_begin_src; cmd->scan_begin_src &= TRIG_TIMER|TRIG_EXT; if(!cmd->scan_begin_src || tmp!=cmd->scan_begin_src)err++; tmp=cmd->convert_src; cmd->convert_src &= TRIG_NOW; if(!cmd->convert_src || tmp!=cmd->convert_src)err++; tmp=cmd->scan_end_src; cmd->scan_end_src &= TRIG_COUNT; if(!cmd->scan_end_src || tmp!=cmd->scan_end_src)err++; tmp=cmd->stop_src; cmd->stop_src &= TRIG_COUNT; if(!cmd->stop_src || tmp!=cmd->stop_src)err++; if(err)return 1; /* step 2: make sure trigger sources are unique and mutually compatible */ /* note that mutual compatiblity is not an issue here */ if(cmd->start_src!=TRIG_NOW && cmd->start_src!=TRIG_INT)err++; if(cmd->scan_begin_src!=TRIG_TIMER && cmd->scan_begin_src!=TRIG_EXT)err++; if(err)return 2; /* step 3: make sure arguments are trivially compatible */ if(cmd->start_arg!=0){ /* same for both TRIG_INT and TRIG_NOW */ cmd->start_arg=0; err++; }#define MAX_SPEED (TIMER_BASE) /* in nanoseconds */ if(cmd->scan_begin_src==TRIG_TIMER){ if(cmd->scan_begin_arg<MAX_SPEED){ cmd->scan_begin_arg=MAX_SPEED; err++; } /* no minumum speed */ }else{ /* TRIG_EXT */ /* should be level/edge, hi/lo specification here */ if(cmd->scan_begin_arg!=0){ cmd->scan_begin_arg=0; err++; } } if(cmd->convert_arg!=0){ cmd->convert_arg = 0; err++; } if(cmd->scan_end_arg!=cmd->chanlist_len){ cmd->scan_end_arg=cmd->chanlist_len; err++; } if(cmd->stop_src==TRIG_COUNT){ /* no limit */ }else{ /* TRIG_NONE */ if(cmd->stop_arg!=0){ cmd->stop_arg=0; err++; } } if(err)return 3; /* step 4: fix up any arguments */ if(cmd->scan_begin_src == TRIG_TIMER){ tmp = cmd->scan_begin_arg; ni_pcidio_ns_to_timer(&cmd->scan_begin_arg, cmd->flags&TRIG_ROUND_MASK); if(tmp!=cmd->scan_begin_arg)err++; } if(err)return 4; return 0;}static int ni_pcidio_ns_to_timer(int *nanosec, int round_mode){ int divider, base; base = TIMER_BASE; switch(round_mode){ case TRIG_ROUND_NEAREST: default: divider = (*nanosec + base/2)/base; break; case TRIG_ROUND_DOWN: divider = (*nanosec)/base; break; case TRIG_ROUND_UP: divider = (*nanosec + base - 1)/base; break; } *nanosec = base * divider; return divider;}static int ni_pcidio_cmd(comedi_device *dev,comedi_subdevice *s){ comedi_cmd *cmd = &s->async->cmd; /* XXX configure ports for input*/ writel(0x0000,dev->iobase+Port_Pin_Directions(0)); if(0){ /* enable fifos A B C D */ writeb(0x0f,dev->iobase+Data_Path); /* set transfer width a 32 bits*/ writeb(TransferWidth(0) | TransferLength(0), dev->iobase+Transfer_Size_Control); }else{ writeb(0x03,dev->iobase+Data_Path); writeb(TransferWidth(3) | TransferLength(0), dev->iobase+Transfer_Size_Control); } /* protocol configuration */ if(cmd->scan_begin_src == TRIG_TIMER){ /* page 4-5, "input with internal REQs" */ writeb( 0 ,dev->iobase+OpMode); writeb(0x00,dev->iobase+ClockReg); writeb( 1 ,dev->iobase+Sequence); writeb(0x04,dev->iobase+ReqReg); writeb( 4 ,dev->iobase+BlockMode); writeb( 3 ,dev->iobase+LinePolarities); writeb(0xc0,dev->iobase+AckSer); writel(ni_pcidio_ns_to_timer(&cmd->scan_begin_arg, TRIG_ROUND_NEAREST),dev->iobase+StartDelay); writeb( 1 ,dev->iobase+ReqDelay); writeb( 1 ,dev->iobase+ReqNotDelay); writeb( 1 ,dev->iobase+AckDelay); writeb(0x0b,dev->iobase+AckNotDelay); writeb(0x01,dev->iobase+Data1Delay); /* manual, page 4-5: ClockSpeed comment is incorrectly listed * on DAQOptions */ writew(0 ,dev->iobase+ClockSpeed); writeb(0 ,dev->iobase+DAQOptions); }else{ /* TRIG_EXT */ /* page 4-5, "input with external REQs" */ writeb( 0 ,dev->iobase+OpMode); writeb(0x00,dev->iobase+ClockReg); writeb( 0 ,dev->iobase+Sequence); writeb(0x00,dev->iobase+ReqReg); writeb( 4 ,dev->iobase+BlockMode); writeb( 0 ,dev->iobase+LinePolarities); writeb(0x00,dev->iobase+AckSer); writel( 1 ,dev->iobase+StartDelay); writeb( 1 ,dev->iobase+ReqDelay); writeb( 1 ,dev->iobase+ReqNotDelay); writeb( 1 ,dev->iobase+AckDelay); writeb(0x0C,dev->iobase+AckNotDelay); writeb(0x10,dev->iobase+Data1Delay); writew( 0 ,dev->iobase+ClockSpeed); writeb(0x60,dev->iobase+DAQOptions); } if(cmd->stop_src == TRIG_COUNT){ writel(cmd->stop_arg,dev->iobase+Transfer_Count); }else{ /* XXX */ }#ifdef USE_DMA writeb(0x05,dev->iobase+DMA_Line_Control); writeb(0x30,dev->iobase+Group_1_First_Clear); setup_mite_dma(dev,s);#else writeb(0x00,dev->iobase+DMA_Line_Control);#endif /* clear and enable interrupts */ writeb(0xff,dev->iobase+Group_1_First_Clear); //writeb(ClearExpired,dev->iobase+Group_1_Second_Clear); writeb(IntEn,dev->iobase+Interrupt_Control); writeb(0x03,dev->iobase+Master_DMA_And_Interrupt_Control); if(cmd->start_src == TRIG_NOW){ /* start */ writeb(Numbered | RunMode(7),dev->iobase+OpMode); s->async->inttrig = NULL; }else{ /* TRIG_INT */ s->async->inttrig = ni_pcidio_inttrig; } DPRINTK("ni_pcidio: command started\n"); return 0;}static void setup_mite_dma(comedi_device *dev,comedi_subdevice *s){ struct mite_struct *mite = devpriv->mite; struct mite_channel *mite_chan = &mite->channels[ DI_DMA_CHAN ]; mite_chan->current_link = 0; mite_chan->dir = COMEDI_INPUT; mite_prep_dma(mite, DI_DMA_CHAN, 16, 16); mite_dma_arm(mite, DI_DMA_CHAN);}static int ni_pcidio_inttrig(comedi_device *dev, comedi_subdevice *s, unsigned int trignum){ if(trignum!=0)return -EINVAL; writeb(Numbered | RunMode(7),dev->iobase+OpMode); s->async->inttrig = NULL; return 1;}static int ni_pcidio_cancel(comedi_device *dev, comedi_subdevice *s){ writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control); return 0;}static int ni_pcidio_change(comedi_device *dev, comedi_subdevice *s, unsigned long new_size){ int ret; ret = mite_buf_change(devpriv->mite, DI_DMA_CHAN, s->async, new_size); if(ret<0)return ret; memset(s->async->prealloc_buf, 0xaa, s->async->prealloc_bufsz); return 0;}static int nidio_attach(comedi_device *dev,comedi_devconfig *it){ comedi_subdevice *s; int i; int ret; int n_subdevices; printk("comedi%d: nidio:",dev->minor); if((ret=alloc_private(dev,sizeof(nidio96_private)))<0) return ret; ret=nidio_find_device(dev,it->options[0],it->options[1]); if(ret<0)return ret; ret = mite_setup(devpriv->mite); if(ret < 0) { printk("error setting up mite\n"); return ret; } dev->iobase = mite_iobase(devpriv->mite); dev->board_name=this_board->name; dev->irq=mite_irq(devpriv->mite); printk(" %s",dev->board_name); if(!this_board->is_diodaq){ n_subdevices=this_board->n_8255; }else{ n_subdevices=1; } if((ret=alloc_subdevices(dev, n_subdevices))<0) return ret; if(!this_board->is_diodaq){ for(i=0;i<this_board->n_8255;i++){ subdev_8255_init(dev,dev->subdevices+i, nidio96_8255_cb,(unsigned long)(dev->iobase+NIDIO_8255_BASE(i))); } }else{ printk(" rev=%d",readb(dev->iobase+Chip_Version)); s=dev->subdevices+0; dev->read_subdev = s; s->type=COMEDI_SUBD_DIO; s->subdev_flags=SDF_READABLE|SDF_WRITABLE; s->n_chan=32; s->range_table=&range_digital; s->maxdata=1; s->insn_config = ni_pcidio_insn_config; s->insn_bits = ni_pcidio_insn_bits; s->do_cmd = ni_pcidio_cmd; s->do_cmdtest = ni_pcidio_cmdtest; s->cancel = ni_pcidio_cancel; s->len_chanlist=32; /* XXX */ s->buf_change = ni_pcidio_change; writel(0,dev->iobase+Port_IO(0)); writel(0,dev->iobase+Port_Pin_Directions(0)); writel(0,dev->iobase+Port_Pin_Mask(0)); /* disable interrupts on board */ writeb(0x00,dev->iobase+Master_DMA_And_Interrupt_Control); ret=comedi_request_irq(dev->irq,nidio_interrupt,SA_SHIRQ,"ni_pcidio",dev); if(ret<0){ dev->irq=0; printk(" irq not available"); } } printk("\n"); return 0;}static int nidio_detach(comedi_device *dev){ int i; if(this_board && !this_board->is_diodaq){ for(i=0;i<this_board->n_8255;i++){ subdev_8255_cleanup(dev,dev->subdevices+i); } } if(dev->irq) comedi_free_irq(dev->irq,dev); if(devpriv && devpriv->mite) mite_unsetup(devpriv->mite); return 0;}static int nidio_find_device(comedi_device *dev,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){ if(bus!=mite->pcidev->bus->number || slot!=PCI_SLOT(mite->pcidev->devfn)) continue; } for(i=0;i<n_nidio_boards;i++){ if(mite_device_id(mite)==nidio_boards[i].dev_id){ dev->board_ptr=nidio_boards+i; devpriv->mite=mite; return 0; } } } printk("no device found\n"); mite_list_devices(); return -EIO;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -