📄 rtd-dm7520.c
字号:
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 + -