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

📄 rtd520.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
     */    if (alloc_subdevices(dev, 4)<0) {	return -ENOMEM;    }    s=dev->subdevices+0;    dev->read_subdev=s;    /* analog input subdevice */    s->type=COMEDI_SUBD_AI;    s->subdev_flags=SDF_READABLE|SDF_GROUND|SDF_COMMON|SDF_DIFF;    s->n_chan=thisboard->aiChans;    s->maxdata=(1<<thisboard->aiBits)-1;    if (thisboard->aiMaxGain <= 32) {	s->range_table = &rtd_ai_7520_range;    } else {	s->range_table = &rtd_ai_4520_range;    }    s->len_chanlist = RTD_MAX_CHANLIST;	/* thisboard->fifoLen */    s->insn_read = rtd_ai_rinsn;    s->do_cmd = rtd_ai_cmd;    s->do_cmdtest = rtd_ai_cmdtest;    s->cancel = rtd_ai_cancel;    /*s->poll = rtd_ai_poll;*/		/* not ready yet */    s=dev->subdevices+1;    /* analog output subdevice */    s->type=COMEDI_SUBD_AO;    s->subdev_flags=SDF_WRITABLE;    s->n_chan = 2;    s->maxdata =(1<<thisboard->aiBits)-1;    s->range_table = &rtd_ao_range;    s->insn_write = rtd_ao_winsn;    s->insn_read = rtd_ao_rinsn;    s=dev->subdevices+2;    /* digital i/o subdevice */    s->type=COMEDI_SUBD_DIO;    s->subdev_flags=SDF_READABLE|SDF_WRITABLE;    /* we only support port 0 right now.  Ignoring port 1 and user IO */    s->n_chan=8;    s->maxdata=1;    s->range_table=&range_digital;    s->insn_bits = rtd_dio_insn_bits;    s->insn_config = rtd_dio_insn_config;    /* timer/counter subdevices (not currently supported) */    s=dev->subdevices+3;    s->type = COMEDI_SUBD_COUNTER;    s->subdev_flags=SDF_READABLE|SDF_WRITABLE;    s->n_chan=3;    s->maxdata=0xffff;    /* check if our interrupt is available and get it */    dev->irq = devpriv->pci_dev->irq;    if (dev->irq > 0) {	if((ret=comedi_request_irq (dev->irq, rtd_interrupt,				    SA_SHIRQ, "rtd520", dev)) < 0) {	    printk("Could not get interrupt! (%d)\n", dev->irq);	    return ret;	}	printk("( irq=%d )", dev->irq);    } else {	printk("( NO IRQ )");    }#ifdef USE_DMA    if (dev->irq > 0) {	printk("( DMA buff=%d )\n", DMA_CHAIN_COUNT);	/* The PLX9080 has 2 DMA controllers, but there could be 4 sources:	   ADC, digital, DAC1, and DAC2.  Since only the ADC supports cmd mode	   right now, this isn't an issue (yet) */	devpriv->dma0Offset = 0;	for(index = 0; index < DMA_CHAIN_COUNT; index++) {	    devpriv->dma0Buff[index] =		pci_alloc_consistent(devpriv->pci_dev,				     sizeof (u16) * thisboard->fifoLen/2,				     &devpriv->dma0BuffPhysAddr[index]);	    if (devpriv->dma0Buff[index] == NULL) {		ret = -ENOMEM;		goto rtd_attach_die_error;	    }	    /*DPRINTK ("buff[%d] @ %p virtual, %x PCI\n",	      index,	      devpriv->dma0Buff[index], devpriv->dma0BuffPhysAddr[index]);*/	}	/* setup DMA descriptor ring (use cpu_to_le32 for byte ordering?) */	devpriv->dma0Chain =	    pci_alloc_consistent (devpriv->pci_dev,				  sizeof(struct plx_dma_desc) * DMA_CHAIN_COUNT,				  &devpriv->dma0ChainPhysAddr);	for (index = 0; index < DMA_CHAIN_COUNT; index++) {	    devpriv->dma0Chain[index].pci_start_addr =		devpriv->dma0BuffPhysAddr[index];	    devpriv->dma0Chain[index].local_start_addr =		DMALADDR_ADC;	    devpriv->dma0Chain[index].transfer_size =		sizeof (u16) * thisboard->fifoLen/2;	    devpriv->dma0Chain[index].next =		(devpriv->dma0ChainPhysAddr + ((index + 1) % (DMA_CHAIN_COUNT))		 * sizeof(devpriv->dma0Chain[0]))		| DMA_TRANSFER_BITS;	    /*DPRINTK ("ring[%d] @%lx PCI: %x, local: %x, N: 0x%x, next: %x\n",	      index,	      ((long)devpriv->dma0ChainPhysAddr	      + (index * sizeof(devpriv->dma0Chain[0]))),	      devpriv->dma0Chain[index].pci_start_addr,	      devpriv->dma0Chain[index].local_start_addr,	      devpriv->dma0Chain[index].transfer_size,	      devpriv->dma0Chain[index].next);*/	}	if (devpriv->dma0Chain == NULL) {	    ret = -ENOMEM;	    goto rtd_attach_die_error;	}	RtdDma0Mode (dev, DMA_MODE_BITS);	RtdDma0Source (dev, DMAS_ADFIFO_HALF_FULL); /* set DMA trigger source*/    } else {	printk("( no IRQ->no DMA )\n");    }#else /* USE_DMA */    printk("\n");			/* end configuration line */#endif /* USE_DMA */						/* initialize board, per RTD spec */					/* also, initialize shadow registers */    RtdResetBoard (dev);    comedi_udelay (100);			/* needed? */    RtdInterruptMask (dev,0);		/* and sets shadow */    RtdInterruptClearMask (dev,~0);	/* and sets shadow */    RtdInterruptClear(dev);		/* clears bits set by mask */    RtdInterruptOverrunClear(dev);    RtdClearCGT (dev);    RtdAdcClearFifo (dev);    RtdDacClearFifo (dev,0);    RtdDacClearFifo (dev,1);					/* clear digital IO fifo*/    RtdDioStatusWrite (dev, 0);		/* safe state, set shadow */    RtdUtcCtrlPut (dev, 0, 0x30);	/* safe state, set shadow */    RtdUtcCtrlPut (dev, 1, 0x30);	/* safe state, set shadow */    RtdUtcCtrlPut (dev, 2, 0x30);	/* safe state, set shadow */    RtdUtcCtrlPut (dev, 3, 0);		/* safe state, set shadow */    /* TODO: set user out source ??? */    if (dev->irq) {			/* enable plx9080 interrupts */	RtdPlxInterruptWrite (dev, ICS_PIE | ICS_PLIE);    }    printk("comedi%d: rtd520 driver attached.\n", dev->minor);    return 1;    /* hit an error, clean up memory and return ret *///rtd_attach_die_error:#ifdef USE_DMA    for(index = 0; index < DMA_CHAIN_COUNT; index++) {	if (NULL != devpriv->dma0Buff[index]) {	/* free buffer memory*/	    pci_free_consistent (devpriv->pci_dev,				 sizeof (u16) * thisboard->fifoLen/2,				 devpriv->dma0Buff[index],				 devpriv->dma0BuffPhysAddr[index]);	    devpriv->dma0Buff[index] = NULL;	}    }    if (NULL != devpriv->dma0Chain) {	pci_free_consistent (devpriv->pci_dev,			     sizeof(struct plx_dma_desc)			     * DMA_CHAIN_COUNT,			     devpriv->dma0Chain,			     devpriv->dma0ChainPhysAddr);	devpriv->dma0Chain = NULL;    }#endif /* USE_DMA */    /* subdevices and priv are freed by the core */    if (dev->irq) {	/* disable interrupt controller */	RtdPlxInterruptWrite (	    dev,	    RtdPlxInterruptRead (dev)	    & ~(ICS_PLIE | ICS_DMA0_E | ICS_DMA1_E));	comedi_free_irq (dev->irq, dev);    }    /* release all regions that were allocated */    if (devpriv->las0) {	iounmap (devpriv->las0);    }    if (devpriv->las1) {	iounmap (devpriv->las1);    }    if (devpriv->lcfg) {	iounmap (devpriv->lcfg);    }    return ret;}/* * _detach is called to deconfigure a device.  It should deallocate * resources.   * This function is also called when _attach() fails, so it should be * careful not to release resources that were not necessarily * allocated by _attach().  dev->private and dev->subdevices are * deallocated automatically by the core. */static int rtd_detach (    comedi_device *dev){#ifdef USE_DMA    int index;#endif    DPRINTK("comedi%d: rtd520: removing (%ld ints)\n(int status 0x%x, overrun status 0x%x, fifo status 0x%x)...\n",	   dev->minor, devpriv->intCount, 	   0xffff & RtdInterruptStatus (dev),	   0xffff & RtdInterruptOverrunStatus (dev),	   (0xffff & RtdFifoStatus (dev)) ^ 0x6666);    if (devpriv) {	/* Shut down any board ops by resetting it */#ifdef USE_DMA	RtdDma0Control (dev, 0);	/* disable DMA */	RtdDma1Control (dev, 0);	/* disable DMA */	RtdPlxInterruptWrite (dev, ICS_PIE | ICS_PLIE);#endif /* USE_DMA */	RtdResetBoard (dev);	RtdInterruptMask (dev, 0);	RtdInterruptClearMask (dev,~0);	RtdInterruptClear(dev);		/* clears bits set by mask */#ifdef USE_DMA	/* release DMA */	for(index = 0; index < DMA_CHAIN_COUNT; index++) {	    if (NULL != devpriv->dma0Buff[index]) {		pci_free_consistent (devpriv->pci_dev,				     sizeof (u16) * thisboard->fifoLen/2,				     devpriv->dma0Buff[index],				     devpriv->dma0BuffPhysAddr[index]);		devpriv->dma0Buff[index] = NULL;	    }	}	if (NULL != devpriv->dma0Chain) {	    pci_free_consistent (devpriv->pci_dev,				 sizeof(struct plx_dma_desc) * DMA_CHAIN_COUNT,				 devpriv->dma0Chain,				 devpriv->dma0ChainPhysAddr);	    devpriv->dma0Chain = NULL;	}#endif /* USE_DMA */	/* release IRQ */	if (dev->irq) {	    /* disable interrupt controller */	    RtdPlxInterruptWrite (		dev,		RtdPlxInterruptRead (dev)		& ~(ICS_PLIE | ICS_DMA0_E | ICS_DMA1_E));	    comedi_free_irq (dev->irq, dev);	}	/* release all regions that were allocated */	if (devpriv->las0) {	    iounmap (devpriv->las0);	}	if (devpriv->las1) {	    iounmap (devpriv->las1);	}	if (devpriv->lcfg) {	    iounmap (devpriv->lcfg);	}    }    printk("comedi%d: rtd520: removed.\n",dev->minor);	    return 0;}/*  Convert a single comedi channel-gain entry to a RTD520 table entry*/static unsigned short rtdConvertChanGain (    comedi_device *dev,    unsigned int	comediChan,    int			chanIndex)	/* index in channel list */{    unsigned int chan, range, aref;    unsigned short r=0;    chan = CR_CHAN (comediChan);    range = CR_RANGE (comediChan);    aref = CR_AREF (comediChan);    r |= chan & 0xf;    /* Note: we also setup the channel list bipolar flag array */    if (range < thisboard->range10Start) {/* first batch are +-5 */	r |= 0x000;			/* +-5 range */	r |= (range & 0x7) << 4;	/* gain */	CHAN_ARRAY_SET (devpriv->chanBipolar, chanIndex);    } else if (range < thisboard->rangeUniStart) {/* second batch are +-10 */	r |= 0x100;			/* +-10 range */	r |= ((range - thisboard->range10Start) & 0x7) << 4;	/* gain */	CHAN_ARRAY_SET (devpriv->chanBipolar, chanIndex);    } else {				/* last batch is +10 */	r |= 0x200;			/* +10 range */	r |= ((range-thisboard->rangeUniStart) & 0x7) << 4;	/* gain */	CHAN_ARRAY_CLEAR (devpriv->chanBipolar, chanIndex);    }    switch (aref) {    case AREF_GROUND:			/* on-board ground */	break;    case AREF_COMMON:	r |= 0x80;			/* ref external analog common */	break;    case AREF_DIFF:	r |= 0x400;			/* differential inputs */	break;    case AREF_OTHER:			/* ??? */	break;    }    /*printk ("chan=%d r=%d a=%d -> 0x%x\n",      chan, range, aref, r);*/    return r;}/*  Setup the channel-gain table from a comedi list*/static void rtd_load_channelgain_list (    comedi_device *dev,    unsigned int n_chan,    unsigned int *list){    if (n_chan > 1) {			/* setup channel gain table */	int	ii;	RtdClearCGT (dev);	RtdEnableCGT(dev, 1);		/* enable table */	for(ii=0; ii < n_chan; ii++){	    RtdWriteCGTable (dev, rtdConvertChanGain (dev, list[ii], ii));	}    } else {				/* just use the channel gain latch */	RtdEnableCGT(dev, 0);		/* disable table, enable latch */	RtdWriteCGLatch (dev, rtdConvertChanGain (dev, list[0], 0));    }}/*  "instructions" read/write data in "one-shot" or "software-triggered"  mode (simplest case).  This doesnt use interrupts.  Note, we don't do any settling delays.  Use a instruction list to  select, delay, then read. */static int rtd_ai_rinsn (    comedi_device *dev,    comedi_subdevice *s,    comedi_insn *insn,    lsampl_t *data){    int n, ii;    int	stat;					/* clear any old fifo data */    RtdAdcClearFifo (dev);    /* write channel to multiplexer and clear channel gain table */     rtd_load_channelgain_list (dev, 1, &insn->chanspec);						/* set conversion source */    RtdAdcConversionSource (dev, 0);	/* software */    /* convert n samples */    for (n=0; n < insn->n; n++) {	s16 d;	/* trigger conversion */	RtdAdcStart (dev);	for (ii = 0; ii < RTD_ADC_TIMEOUT; ++ii) {	    stat = RtdFifoStatus (dev);	    if (stat & FS_ADC_EMPTY)	/* 1 -> not empty */		break;	    WAIT_QUIETLY;	}	if (ii >= RTD_ADC_TIMEOUT) {	    DPRINTK ("rtd520: Error: ADC never finished! FifoStatus=0x%x\n",		    stat ^ 0x6666);	    return -ETIMEDOUT;	}	/* read data */	d = RtdAdcFifoGet (dev);	/* get 2s comp value */	/*printk ("rtd520: Got 0x%x after %d usec\n", d, ii+1);*/	d = d >> 3;			/* low 3 bits are marker lines */	if (CHAN_ARRAY_TEST (devpriv->chanBipolar,0)) {	    data[n] = d + 2048;		/* convert to comedi unsigned data */	} else {	    data[n] = d;	}    }    /* return the number of samples read/written */    return n;}/*  Get what we know is there.... Fast!  This uses 1/2 the bus cycles of read_dregs (below).  The manual claims that we can do a lword read, but it doesn't work here.*/static int ai_read_n (    comedi_device *dev,    comedi_subdevice *s,    int	count){    int ii;    for (ii = 0; ii < count; ii++) {	sampl_t	sample;	s16 d;	if (0 == devpriv->aiCount) {	/* done */	    d = RtdAdcFifoGet (dev);	/* Read N and discard */	    continue;

⌨️ 快捷键说明

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