⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtd520.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	}#if 0	if (0 == (RtdFifoStatus (dev) & FS_ADC_EMPTY)) { /* DEBUG */	    DPRINTK("comedi: READ OOPS on %d of %d\n", ii+1, count);	    break;	}#endif	d = RtdAdcFifoGet (dev);	/* get 2s comp value */	d = d >> 3;			/* low 3 bits are marker lines */	if (CHAN_ARRAY_TEST (devpriv->chanBipolar, s->async->cur_chan)) {	    sample = d + 2048;	   /* convert to comedi unsigned data */	} else {	    sample = d;	}	if (!comedi_buf_put (s->async, sample))	    return -1;	if (devpriv->aiCount > 0)	/* < 0, means read forever */	    devpriv->aiCount--;    }    return 0;}/*  unknown amout of data is waiting in fifo.*/static int ai_read_dregs (    comedi_device *dev,    comedi_subdevice *s){    while (RtdFifoStatus (dev) & FS_ADC_EMPTY) { /* 1 -> not empty */	sampl_t	sample;	s16 d = RtdAdcFifoGet (dev); /* get 2s comp value */	if (0 == devpriv->aiCount) {	/* done */	    continue;			/* read rest */	}	d = d >> 3;		/* low 3 bits are marker lines */	if (CHAN_ARRAY_TEST (devpriv->chanBipolar, s->async->cur_chan)) {	    sample = d + 2048;	   /* convert to comedi unsigned data */	} else {	    sample = d;	}	if (!comedi_buf_put (s->async, sample))	    return -1;	if (devpriv->aiCount > 0)	/* < 0, means read forever */	    devpriv->aiCount--;    }    return 0;}#ifdef USE_DMA/*  Terminate a DMA transfer and wait for everything to quiet down*/void abort_dma (    comedi_device *dev,    unsigned int channel)		/* DMA channel 0, 1 */{    unsigned long dma_cs_addr;		/* the control/status register */    uint8_t status;    unsigned int ii;    //unsigned long flags;    dma_cs_addr = (unsigned long)devpriv->lcfg	+ ((channel == 0) ? LCFG_DMACSR0 : LCFG_DMACSR1);    // spinlock for plx dma control/status reg    //comedi_spin_lock_irqsave( &dev->spinlock, flags );    // abort dma transfer if necessary    status = readb(dma_cs_addr);    if((status & PLX_DMA_EN_BIT) == 0) { /* not enabled (Error?) */	DPRINTK ("rtd520: AbortDma on non-active channel %d (0x%x)\n",		 channel, status);	goto abortDmaExit;    }    /* wait to make sure done bit is zero (needed?) */    for (ii = 0;	(status & PLX_DMA_DONE_BIT) && ii < RTD_DMA_TIMEOUT;	ii++) {	WAIT_QUIETLY;	status = readb(dma_cs_addr);    }    if (status & PLX_DMA_DONE_BIT) {	printk("rtd520: Timeout waiting for dma %i done clear\n", channel);	goto abortDmaExit;    }    /* disable channel (required) */    writeb(0, dma_cs_addr);    comedi_udelay(1);				/* needed?? */    /* set abort bit for channel */    writeb(PLX_DMA_ABORT_BIT, dma_cs_addr);    // wait for dma done bit to be set    status = readb(dma_cs_addr);    for(ii = 0;	(status & PLX_DMA_DONE_BIT) == 0 && ii < RTD_DMA_TIMEOUT;	ii++) {	status = readb(dma_cs_addr);	WAIT_QUIETLY;    }    if ((status & PLX_DMA_DONE_BIT) == 0) {	printk("rtd520: Timeout waiting for dma %i done set\n", channel);    }abortDmaExit:    //comedi_spin_unlock_irqrestore( &dev->spinlock, flags );}/*  Process what is in the DMA transfer buffer and pass to comedi  Note: this is not re-entrant*/static int ai_process_dma (    comedi_device *dev,    comedi_subdevice *s){    int ii, n;    s16 *dp;    if (devpriv->aiCount == 0)		/* transfer already complete */	return 0;    dp = devpriv->dma0Buff[devpriv->dma0Offset];    for (ii = 0; ii < thisboard->fifoLen/2;) { /* convert samples */	sampl_t	sample;	if (CHAN_ARRAY_TEST (devpriv->chanBipolar, s->async->cur_chan)) {	    sample = (*dp >> 3) + 2048;	/* convert to comedi unsigned data */	} else {	    sample = *dp >> 3;	       /* low 3 bits are marker lines */	}	*dp++ = sample;			/* put processed value back */	if (++s->async->cur_chan >= s->async->cmd.chanlist_len)	    s->async->cur_chan = 0;	++ii;				/* number ready to transfer */	if (devpriv->aiCount > 0) {	/* < 0, means read forever */	    if (--devpriv->aiCount == 0) { /* done */		/*DPRINTK ("rtd520: Final %d samples\n", ii);*/		break;	    }	}    }    /* now pass the whole array to the comedi buffer */    dp = devpriv->dma0Buff[devpriv->dma0Offset];    n = comedi_buf_write_alloc (s->async, ii * sizeof (s16));    if (n < (ii * sizeof (s16))) {	/* any residual is an error */	DPRINTK ("rtd520:ai_process_dma buffer overflow %d samples!\n",		 ii - (n / sizeof (s16)));	s->async->events |= COMEDI_CB_ERROR;	return -1;    }    comedi_buf_memcpy_to (s->async, 0, dp, n);    comedi_buf_write_free (s->async, n);    /* always at least 1 scan -- 1/2 FIFO is larger than our max scan list */    s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS;    if (++devpriv->dma0Offset >= DMA_CHAIN_COUNT) { /* next buffer */	devpriv->dma0Offset = 0;    }    return 0;}#endif /* USE_DMA *//*  Handle all rtd520 interrupts.    Runs atomically and is never re-entered.  This is a "slow handler";  other interrupts may be active.  The data conversion may someday happen in a "bottom half".*/static void rtd_interrupt (    int irq,				/* interrupt number (ignored) */    void *d,				/* our data */    struct pt_regs *regs)		/* cpu context (ignored) */{    comedi_device *dev = d;		/* must be called "dev" for devpriv */    u16 status;    u16 fifoStatus;    comedi_subdevice *s = dev->subdevices + 0; /* analog in subdevice */    devpriv->intCount++;		/* DEBUG statistics */    fifoStatus = RtdFifoStatus (dev);    /* check for FIFO full, this automatically halts the ADC! */    if (!(fifoStatus & FS_ADC_FULL)) {	/* 0 -> full */	DPRINTK("rtd520: FIFO full! fifo_status=0x%x\n",		(fifoStatus ^ 0x6666) & 0x7777); /* should be all 0s */	goto abortTransfer;    } #ifdef USE_DMA    if (devpriv->flags & DMA0_ACTIVE) {	/* Check DMA */	u32 istatus = RtdPlxInterruptRead (dev);	if (istatus & ICS_DMA0_A) {	    if (ai_process_dma (dev, s) < 0) {		DPRINTK("rtd520: comedi read buffer overflow (DMA) with %ld to go!\n",			devpriv->aiCount);		RtdDma0Control (dev,				(devpriv->dma0Control & ~PLX_DMA_START_BIT)				| PLX_CLEAR_DMA_INTR_BIT);		goto abortTransfer;	    }			    /*DPRINTK ("rtd520: DMA transfer: %ld to go, istatus %x\n",	      devpriv->aiCount, istatus);*/	    RtdDma0Control (dev, (devpriv->dma0Control & ~PLX_DMA_START_BIT)			    | PLX_CLEAR_DMA_INTR_BIT);	    if (0 == devpriv->aiCount) { /* counted down */		DPRINTK("rtd520: Samples Done (DMA).\n");		goto transferDone;	    }	    comedi_event (dev, s, s->async->events);	} else {	    /*DPRINTK ("rtd520: No DMA ready: istatus %x\n", istatus);*/	}    }    /* Fall through and check for other interrupt sources */#endif /* USE_DMA */    status = RtdInterruptStatus (dev);    /* if interrupt was not caused by our board, or handled above */    if (0 == status) {	return;    }    if (status & IRQM_ADC_ABOUT_CNT) { /* sample count -> read FIFO */	/* since the priority interrupt controller may have queued a sample	   counter interrupt, even though we have already finished,	   we must handle the possibility that there is no data here */	if (!(fifoStatus & FS_ADC_HEMPTY)) { /* 0 -> 1/2 full */	    /*DPRINTK("rtd520: Sample int, reading 1/2FIFO.  fifo_status 0x%x\n",	      (fifoStatus ^ 0x6666) & 0x7777);*/	    if (ai_read_n (dev, s, thisboard->fifoLen / 2) < 0) {		DPRINTK("rtd520: comedi read buffer overflow (1/2FIFO) with %ld to go!\n",			devpriv->aiCount);		goto abortTransfer;	    }	    if (0 == devpriv->aiCount) { /* counted down */		DPRINTK("rtd520: Samples Done (1/2). fifo_status was 0x%x\n",			(fifoStatus ^ 0x6666) & 0x7777); /* should be all 0s */		goto transferDone;	    }	    comedi_event (dev, s, s->async->events);	} else if (devpriv->transCount > 0) {	/* read often */	    /*DPRINTK("rtd520: Sample int, reading %d  fifo_status 0x%x\n",	      devpriv->transCount, (fifoStatus ^ 0x6666) & 0x7777);*/	    if (fifoStatus & FS_ADC_EMPTY) { /* 1 -> not empty */		if (ai_read_n (dev, s, devpriv->transCount) < 0) {		    DPRINTK("rtd520: comedi read buffer overflow (N) with %ld to go!\n",			    devpriv->aiCount);		    goto abortTransfer;		}		if (0 == devpriv->aiCount) { /* counted down */		    DPRINTK("rtd520: Samples Done (N). fifo_status was 0x%x\n",			    (fifoStatus ^ 0x6666) & 0x7777);		    goto transferDone;		}		comedi_event (dev, s, s->async->events);	    }	} else {			/* wait for 1/2 FIFO (old)*/	    DPRINTK("rtd520: Sample int.  Wait for 1/2. fifo_status 0x%x\n",		    (fifoStatus ^ 0x6666) & 0x7777);	}    }    else {	DPRINTK ("rtd520: unknown interrupt source!\n");    }    if (0xffff & RtdInterruptOverrunStatus (dev)) { /* interrupt overrun */	DPRINTK("rtd520: Interrupt overrun with %ld to go! over_status=0x%x\n",		devpriv->aiCount,		0xffff & RtdInterruptOverrunStatus (dev));	goto abortTransfer;    } 						/* clear the interrupt */    RtdInterruptClearMask (dev, status);    RtdInterruptClear (dev);    return;abortTransfer:    RtdAdcClearFifo (dev);		/* clears full flag */    s->async->events |= COMEDI_CB_ERROR;    devpriv->aiCount = 0;		/* stop and don't transfer any more */    /* fall into transferDone */transferDone:    RtdPacerStopSource (dev, 0);	/* stop on SOFTWARE stop */    RtdPacerStop (dev);			/* Stop PACER */    RtdAdcConversionSource (dev, 0);	/* software trigger only */    RtdInterruptMask (dev, 0);		/* mask out SAMPLE */#ifdef USE_DMA    if (devpriv->flags & DMA0_ACTIVE) {	RtdPlxInterruptWrite (dev,	/* disable any more interrupts */			      RtdPlxInterruptRead (dev) & ~ICS_DMA0_E);	abort_dma (dev, 0);	devpriv->flags &= ~DMA0_ACTIVE;	/* if Using DMA, then we should have read everything by now */	if (devpriv->aiCount > 0) {	    DPRINTK ("rtd520: Lost DMA data! %ld remain\n",		     devpriv->aiCount);	}    }#endif /* USE_DMA */    if (devpriv->aiCount > 0) {		/* there shouldn't be anything left */	fifoStatus = RtdFifoStatus (dev);	DPRINTK("rtd520: Finishing up. %ld remain, fifoStat=%x\n",		devpriv->aiCount,		(fifoStatus ^ 0x6666) & 0x7777); /* should read all 0s */	ai_read_dregs (dev, s);	/* read anything left in FIFO */    }    s->async->events |= COMEDI_CB_EOA;/* signal end to comedi */    comedi_event (dev, s, s->async->events);					/* clear the interrupt */    status = RtdInterruptStatus (dev);    RtdInterruptClearMask (dev, status);    RtdInterruptClear (dev);	    fifoStatus = RtdFifoStatus (dev);	/* DEBUG */    DPRINTK("rtd520: Acquisition complete. %ld ints, intStat=%x, overStat=%x\n",	    devpriv->intCount,	    status,	    0xffff & RtdInterruptOverrunStatus (dev));}#if 0/*  return the number of samples available*/static int rtd_ai_poll (comedi_device *dev,comedi_subdevice *s){    /* TODO: This needs to mask interrupts, read_dregs, and then re-enable */    /* Not sure what to do if DMA is active */    return s->async->buf_write_count - s->async->buf_read_count;}#endif/*  cmdtest tests a particular command to see if it is valid.  Using the cmdtest ioctl, a user can create a valid cmd  and then have it executed by the cmd ioctl (asyncronously).   cmdtest returns 1,2,3,4 or 0, depending on which tests  the command passes.*/static int rtd_ai_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;    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_TIMER|TRIG_EXT;    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|TRIG_NONE;    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->scan_begin_src !=TRIG_TIMER &&	cmd->scan_begin_src !=TRIG_EXT) {	err++;    }    if (cmd->convert_src !=TRIG_TIMER &&	cmd->convert_src !=TRIG_EXT) {	err++;    }    if (cmd->stop_src != TRIG_COUNT &&	cmd->stop_src != TRIG_NONE) {	err++;    }    if (err) {	return 2;    }    /* step 3: make sure arguments are trivially compatible */    if (cmd->start_arg != 0) {	cmd->start_arg = 0;	err++;    }    if (cmd->scan_begin_src == TRIG_TIMER){	/* Note: these are time periods, not actual rates */	if (1 == cmd->chanlist_len) {	/* no scanning */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -