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

📄 rtd-dm7520.c

📁 rt 7520采集卡 linux驱动源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
    case DM7520IOCSETREG:	  if (temp->las>LASMAX) return -EINVAL;      if (LAS1==temp->las)	    PUTMEM16(devminor,temp->las,temp->addr,temp->data);      else {	    PUTMEM32(devminor,temp->las,temp->addr,temp->data);//     printk(KERN_INFO "setreg: minor=%X, las=%X, addr=%X, data=%X \n",//    		    devminor,temp->las,temp->addr,temp->data);	}      break;    case DM7520IOCSETRCHAN:	  if (temp->data>DM7520_READ_HD) return -EINVAL;	  dm7520_table[devminor].readchan=temp->data;      break;/*    case DM7520IOCSETWCHAN:	  if ((temp->data<DM7520_WRITE_DA1) || (temp->data>DM7520_WRITE_DA2))		return -EINVAL;	  dm7520_table[devminor].writechan=temp->data;      break;
*/
    case DM7520IOCPREPARECONTROL:
		dm7520_table[devminor].mmap_buf = CONTROLBUF(devminor);//         printk("<1> set cont buf addr=%ld, \n", (long)CONTROLBUF(devminor));		dm7520_table[devminor].mmap_size = PAGE_SIZE;
		break;

	case DM7520IOCSETWRITEBUFFER:
	{
		int i = 0;
		size_t length;

		length = temp->data;
		channel = temp->las;
		dmach = temp->addr;

		if ((channel!=DM7520_WRITE_DA1)&&(channel!=DM7520_WRITE_DA2)) {		    VPRINTK(KERN_INFO "dm7520:write wrong channel=%X\n", channel);		    return -EINVAL;
		}		if (length<0) {
		    VPRINTK(KERN_INFO "dm7520:too little DA buffer length =%d\n", length);
		    return -EINVAL;
		}


		if (channel==DM7520_WRITE_DA1){
			while (DA1_FIFONF) {
				if (i>=length) break;
				PUTMEM16(devminor,LAS1,LAS1_DAC1_FIFO,*((int16_t*)(DMATEMPBUF(devminor,dmach)+i)));							i+=2;			}
		}
		else {// (channel==DM7520_WRITE_DA2)
			while (DA2_FIFONF) {
				if (i>=length) break;
				PUTMEM16(devminor,LAS1,LAS1_DAC2_FIFO,*((int16_t*)(DMATEMPBUF(devminor,dmach)+i)));			
				i+=2;
			}
		}


		if ((0==dmach)||(1==dmach)) { // DMA mode
			short maxFlagIndex;
			if (length < DMASIZE(devminor)) {
				VPRINTK(KERN_INFO "DM7520: size of buffer can not be less then size of DMA buffer\n");
				return -EINVAL;			
			}
			if (length>DMATEMPSIZE) {
				VPRINTK(KERN_INFO "DM7520: too big output buffer \n");
				return -EINVAL;
			}			
			if (0!=(length)%DMASIZE(devminor)) {
				VPRINTK(KERN_INFO "DM7520: DMA buffer must be multiple of 1/2 FIFOSIZE \n");
				return -EINVAL;
			}


			USEDTEMPBUFSIZE(devminor,dmach) = length;
			maxFlagIndex = USEDTEMPBUFSIZE(devminor,dmach)/DMASIZE(devminor);
			TEMPBUFOFFSET(devminor,dmach) = DMASIZE(devminor)*2;
			TEMPBUFFLAG(devminor,dmach,0) = BUFFER_COPIED;
			TEMPBUFFLAG(devminor,dmach,1) = BUFFER_COPIED;
			for (i=2; i<maxFlagIndex; i++) TEMPBUFFLAG(devminor,dmach,i) = BUFFER_READY;
//			printk("<1>buffer ready minor=%d, dmach=%d\n",devminor,dmach);			wdma(devminor, dmach);
		}
		break;	}    case DM7520IOCSETDMA:      if ((dm7520_table[devminor].flags & DM7520_FLAGS_BMCAP)==0) return(-EINVAL);      dmach=temp->addr;      channel=temp->las;
	  //      printk("<1>setdma0: dmach=%d, channel=%d \n", dmach, channel);            if (channel>DM7520_WRITE_DA2)        {         return -EINVAL;        }      if (!((dmach!=0)||(dmach!=1)))        {         return -EINVAL;        }      if (dm7520_table[devminor].dmasetup[dmach].dmainuse)        {         return -EBUSY;        }
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)	//    lock_kernel();//    kernel_locked++;#endif	  dm7520_table[devminor].dmasetup[dmach].dmainuse=1;
	  dmapaddr=(uint32_t)(virt_to_bus(DMABUF(devminor,dmach)));
	  
	  	  dm7520_table[devminor].dmasetup[dmach].usedby=channel;
	  	  
      switch (channel)        {         case DM7520_READ_AD:			dm7520_table[devminor].dmasetup[dmach].direction=DMAD_FROMCARD;		
			dm7520_table[devminor].dmasetup[dmach].dmaladdr=DMALADDR_ADC;					PUTMEM32(devminor,LAS0,(dmach==0)?LAS0_DMA0_SRC:LAS0_DMA1_SRC,DMAS_ADFIFO_HALF_FULL);
			dm7520_table[devminor].readchan = DM7520_READ_AD;
			break;

		case DM7520_READ_HD:
			dm7520_table[devminor].dmasetup[dmach].direction=DMAD_FROMCARD;		
			dm7520_table[devminor].dmasetup[dmach].dmaladdr=DMALADDR_HDIN;		
			PUTMEM32(devminor,LAS0,(dmach==0)?LAS0_DMA0_SRC:LAS0_DMA1_SRC,DMAS_UTC1);	//user TC1 used to count samples and start DMA on demand when FIFO is half full
			dm7520_table[devminor].readchan = DM7520_READ_HD;			break;
         case DM7520_WRITE_DA1:         case DM7520_WRITE_DA2:

			dm7520_table[devminor].mmap_size = temp->data;
			if ((temp->data)<DMASIZE(devminor)*2) {
				VPRINTK(KERN_INFO "dma buffer size=%d must be at least 2 FIFO size\n", temp->data);
				return -EINVAL;
			}
			if (0!=(temp->data)%DMASIZE(devminor)) {
				VPRINTK(KERN_INFO "dma buffer size=%d must be multiple of 1/2 FIFO\n", temp->data);
				return -EINVAL;
			}
			dm7520_table[devminor].mmap_buf = DMATEMPBUF(devminor,dmach);
//         printk("<1> set buf addr=%ld, dmach=%d, chan=%d, minor=%d\n", (long)DMATEMPBUF(devminor,dmach),//         		dmach, channel, devminor);//           dm7520_table[devminor].writechan=channel;
		   dm7520_table[devminor].dmasetup[dmach].direction=DMAD_TOCARD;           dm7520_table[devminor].dmasetup[dmach].dmaladdr=                (channel==DM7520_WRITE_DA1)?DMALADDR_DAC1:DMALADDR_DAC2;           PUTMEM32(devminor,LAS0,(dmach==0)?LAS0_DMA0_SRC:LAS0_DMA1_SRC,                (channel==DM7520_WRITE_DA1)?DMAS_DAC1_FIFO_HALF_EMPTY:DMAS_DAC2_FIFO_HALF_EMPTY);           break;           default:           	VPRINTK(KERN_INFO "bad channel=%d in ioctl setdma\n", channel);           	return -EINVAL;        }

	  if (0==dmach) {
		set_dma0size(devminor,DMASIZE(devminor));
		set_dma0dir(devminor, dm7520_table[devminor].dmasetup[dmach].direction );
		set_dma0Paddr(devminor,dmapaddr);
		set_dma0Laddr(devminor,dm7520_table[devminor].dmasetup[dmach].dmaladdr );
		dm7520_table[devminor].dmasetup[dmach].dmamode=DMAMODE0_DEMAND|DMAM0_ITEN;
		set_dma0mode(devminor, dm7520_table[devminor].dmasetup[dmach].dmamode);
		enable_dma0(devminor);			  }
	  else { //dmach==1
		set_dma1size(devminor,DMASIZE(devminor));
		set_dma1dir(devminor, dm7520_table[devminor].dmasetup[dmach].direction );
		set_dma1Paddr(devminor,dmapaddr);
		set_dma1Laddr(devminor,dm7520_table[devminor].dmasetup[dmach].dmaladdr );
		dm7520_table[devminor].dmasetup[dmach].dmamode=DMAMODE1_DEMAND|DMAM1_ITEN;
		set_dma1mode(devminor, dm7520_table[devminor].dmasetup[dmach].dmamode);
		enable_dma1(devminor);	  }//	VPRINTK(KERN_INFO "DMA set:loc dmach=%X chan=%X mode=%X size=%d \n",dmach,
//				dm7520_table[devminor].dmasetup[dmach].usedby,
//				dm7520_table[devminor].dmasetup[dmach].dmamode,
//				DMASIZE(devminor));      break;    case DM7520IOCUNSETDDMA:      /* locate dma channel corresponding to parameter */      dmach=temp->addr;//      VPRINTK("<1>unset: dmach=%X ch=%X\n", dmach, dm7520_table[devminor].dmasetup[dmach].usedby);      if (!((dmach!=0)||(dmach!=1)))        {         return -EINVAL;        }		setTimer(&timer,2);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)		//    kernel_locked--;//    if (0==kernel_locked) unlock_kernel();#endif      switch(dmach)        {
		  		           case 0: 
			 set_dma0mode(devminor, DMAMODE0_DEMAND); // disable interrupts
//			 VPRINTK("<1>unset: dma0 interrupts disabled\n");
			 
//			 usleep(10000); //wait for pending interrupts
			 if (DM7520_WRITE_DA1==dm7520_table[devminor].dmasetup[dmach].usedby) while ((DA1_FIFONE) &&(!isTimeOut(&timer)));			 else if (DM7520_WRITE_DA2==dm7520_table[devminor].dmasetup[dmach].usedby) while ((DA2_FIFONE)&&(!isTimeOut(&timer)));			 else if (DM7520_READ_AD==dm7520_table[devminor].dmasetup[dmach].usedby) while ((AD_FIFONF)&&(!isTimeOut(&timer)));
			 else if (DM7520_READ_HD==dm7520_table[devminor].dmasetup[dmach].usedby) while ((HD_FIFONF)&&(!isTimeOut(&timer)));			 PUTMEM32(devminor,LAS0,LAS0_DMA0_SRC, DMAS_DISABLED);			 disable_dma0(devminor); 
			 break;         case 1:  
			 set_dma1mode(devminor, DMAMODE1_DEMAND); // disable interrupts
//			 VPRINTK("<1>unset: dma1 interrupts disabled\n");
//			 usleep(10000); //wait for pending interrupts
			 if (DM7520_WRITE_DA1==dm7520_table[devminor].dmasetup[dmach].usedby) while ((DA1_FIFONE)&&(!isTimeOut(&timer)));			 else if (DM7520_WRITE_DA2==dm7520_table[devminor].dmasetup[dmach].usedby) while ((DA2_FIFONE)&&(!isTimeOut(&timer)));			 else if (DM7520_READ_AD==dm7520_table[devminor].dmasetup[dmach].usedby) while ((AD_FIFONF)&&(!isTimeOut(&timer)));
			 else if (DM7520_READ_HD==dm7520_table[devminor].dmasetup[dmach].usedby) while ((HD_FIFONF)&&(!isTimeOut(&timer)));
			 PUTMEM32(devminor,LAS0,LAS0_DMA1_SRC, DMAS_DISABLED);			 disable_dma1(devminor); 
			 break;        }
//	  VPRINTK("<1>unset: dma disabled \n");      dm7520_table[devminor].dmasetup[dmach].dmainuse=0;      dm7520_table[devminor].dmasetup[dmach].direction=0;      dm7520_table[devminor].dmasetup[dmach].dmaladdr=0;      dm7520_table[devminor].dmasetup[dmach].usedby=-1;	  dm7520_table[devminor].dmasetup[dmach].tempBufOffset = 0;		//used for writing DMA
      dm7520_table[devminor].dmasetup[dmach].tempBufSize = 0;		//used for writing DMA      break;    case DM7520IOCGETECODE:      temp->data=dm7520_table[devminor].errcode;      if(copy_to_user((void*)ioctl_param,(void*)temp,sizeof(dm7520_request)))            return -EFAULT;	            break;    case DM7520IOCCLEARECODE:      dm7520_table[devminor].errcode=0;      break;
    case DM7520IOCGETFIFOSIZE:
	temp->data = DMASIZE(devminor);
	if(copy_to_user((void*)ioctl_param,(void*)temp,sizeof(dm7520_request)))    	        return -EFAULT;			break;		
    case TCGETS: return -ENOTTY;      break;    default:#ifdef DEBUG      printk(KERN_DEBUG "Ioctl invalid: %08X\n",ioctl_num);#endif      return -ENOTTY;      break;  }return SUCCESS;}
static int dm7520_mmap(struct file *file, struct vm_area_struct *vma){
//    static int nn = 10;	

	short devminor = MINOR(file->f_dentry->d_inode->i_rdev);
	char *buffer = dm7520_table[devminor].mmap_buf;
	long bufSize = dm7520_table[devminor].mmap_size;

	unsigned long page;
	unsigned long pos = (unsigned long) buffer;
	unsigned long start = vma->vm_start;
	unsigned long size = vma->vm_end - vma->vm_start;

	if (bufSize!=size) {
	    VPRINTK(KERN_INFO "dm7520:mmap: wrong mmap size bufsize=%ld, vmasize=%ld\n",
		    bufSize,size);
	    return -EINVAL;
	}
//	vma->vm_flags |= VM_RESERVED;
	while (size>0) {
	    page = virt_to_phys((void*)pos);
	    if (remap_page_range(start,page,PAGE_SIZE,PAGE_SHARED)) {
			VPRINTK(KERN_INFO "dm7520:mmap:error in remap_page_range\n");
			return -EAGAIN;
	    }
	    start +=PAGE_SIZE;
	    pos+=PAGE_SIZE;
	    size-=PAGE_SIZE;
	}
	//	memset(buffer, nn, vma->vm_end - vma->vm_start);//	printk("<1>buffer mapped size=%ld, buffer=%ld, start=%ld nn=%d\n", vma->vm_end - vma->vm_start, (long)buffer,vma->vm_start, nn);//	nn++;	return 0;
}

static unsigned int dm7520_poll(struct file * pollfile, poll_table * polltable){ unsigned int pollmask=30; short devminor,devmajor; uint32_t fifostatus; devminor=MINOR(pollfile->f_dentry->d_inode->i_rdev); devmajor=MAJOR(pollfile->f_dentry->d_inode->i_rdev); if (devminor >= MAXDM7520) return -ENXIO; if (!dm7520_table[devminor].present) return -ENXIO; if (!dm7520_table[devminor].opened) return -EBUSY; poll_wait(pollfile, &(dm7520_table[devminor].inq), polltable); poll_wait(pollfile, &(dm7520_table[devminor].outq), polltable); /* set mask according to fifo status bits */ pollmask=0; fifostatus=GETMEM32(devminor,LAS0,LAS0_ADC); /* TODO: read channel and write channel*/ if (0!=(fifostatus&FS_ADC_EMPTY)) pollmask|=(POLLIN | POLLRDNORM); if (0!=(fifostatus&FS_DIN_EMPTY)) pollmask|=(POLLIN | POLLRDNORM); if (0==(fifostatus&FS_DAC1_EMPTY)) pollmask|=(POLLOUT | POLLWRNORM); if (0==(fifostatus&FS_DAC2_EMPTY)) pollmask|=(POLLOUT | POLLWRNORM); return(pollmask);}static int dm7520_fasync(int fd, struct file * filep, int mode){ short devminor,devmajor; devminor=MINOR(filep->f_dentry->d_inode->i_rdev); devmajor=MAJOR(filep->f_dentry->d_inode->i_rdev); if (devminor >= MAXDM7520) return -ENXIO; if (!dm7520_table[devminor].present) return -ENXIO; if (!dm7520_table[devminor].opened) return -EBUSY;  return fasync_helper(fd,filep,mode,&(dm7520_table[devminor].async_queue));}struct file_operations dm7520_fops = {  llseek:NULL,				//seek  NULL, 		//read  NULL,		//dm7520_write,		//write  NULL,				//readdir  dm7520_poll,		//poll  dm7520_ioctl,		//ioctl  dm7520_mmap,				//mmap  dm7520_open,		//open  NULL,				//flush  dm7520_release,	//release  NULL,				//fsync  dm7520_fasync,	//fasync  NULL,				//lock};/************************************************************************/static int finddevices(void){ int card_idx=0; struct pci_dev *pdev; unsigned char pci_latency; unsigned long pciaddr; int irq; int ret; int i; u16 pci_command, new_command, revision; uint32_t epld_version;
 struct page *page; if (! pci_present())	return 0; pdev=NULL; while ((pdev=pci_find_device(0x1435, 0x7520, pdev)))   {    printk(KERN_INFO "dm7520%d: Card at bus %d slot %02X, function %02X.\n",		   card_idx, pdev->bus->number,PCI_SLOT(pdev->devfn),           PCI_FUNC(pdev->devfn));    pciaddr = pci_base_address(pdev,0);    VPRINTK(KERN_INFO "dm7520%d: LCR_MMBA address %#lx.\n",card_idx,pciaddr);    dm7520_table[card_idx].lcr_mmba=pciaddr&0xFFFFFFF0;    pciaddr = pci_base_address(pdev,1);    VPRINTK(KERN_INFO "dm7520%d: LCR_IOBA address %#lx.\n",card_idx,pciaddr);    dm7520_table[card_idx].lcr_ioba=pciaddr&0xFFFFFFFC;	pciaddr = pci_base_address(pdev,2);	VPRINTK(KERN_INFO "dm7520%d: LAS0 is at address %#lx.\n",card_idx,pciaddr);	dm7520_table[card_idx].las0=pciaddr&0xFFFFFFF0;	pciaddr = pci_base_address(pdev,3);	VPRINTK(KERN_INFO "dm7520%d: LAS1 is at address %#lx.\n",card_idx,pciaddr);	dm7520_table[card_idx].las1=pciaddr&0xFFFFFFF0;	irq = pdev->irq;   	dm7520_table[card_idx].irq=irq;   	VPRINTK(KERN_INFO "dm7520%d: PCI IRQ %d.\n",card_idx,irq);	pci_read_config_word(pdev, PCI_REVISION_ID, &revision);   	VPRINTK(KERN_INFO "dm7520%d: PCI revision %d.\n",card_idx,revision);	dm7520_table[card_idx].lasmap[LAS0]=(uint32_t *)ioremap_nocache(dm7520_table[card_idx].las0,DM7520_LAS0_LENGTH);	dm7520_table[card_idx].lasmap[LAS1]=(uint32_t *)ioremap_nocache(dm7520_table[card_idx].las1,DM7520_LAS1_LENGTH);	dm7520_table[card_idx].lasmap[LCFG]=(uint32_t *)ioremap_nocache(dm7520_table[card_idx].lcr_mmba,DM7520_LCFG_LENGTH);	sprintf(dm7520_table[card_idx].devname,"%s-%d",DEVICE_NAME,card_idx);	ret=request_irq(dm7520_table[card_idx].irq, dm7520_interrupt,                     SA_SHIRQ, dm7520_table[card_idx].devname,                    &dm7520_table[card_idx]);	if (ret)	  {	   printk(KERN_INFO "dm7520%d: Failed to request IRQ %d.\n",card_idx, dm7520_table[card_idx].irq);       disable_PLX_it(card_idx);       dm7520_table[card_idx].irq=0;	  }    else      {       enable_PLX_it(card_idx);

⌨️ 快捷键说明

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