📄 rtd-dm7520.c
字号:
}/*----------------------------------------------------------------*/#ifdef DEBUG/* DEBUG function for /proc/dm7520x output */void dm7520_getregs( int board, uint32_t * itcsr, uint32_t * d0m, uint32_t * d1m, uint32_t * d0s, uint32_t * d1s){ *itcsr=GETMEM32(board,LCFG,LCFG_ITCSR); *d0m=get_dma0mode(board); *d1m=get_dma1mode(board); *d0s=get_dma0status(board); *d1s=get_dma1status(board);}#endif //DEBUGvoid dm7520_incuse(void){ MOD_INC_USE_COUNT;}void dm7520_decuse(void){ MOD_DEC_USE_COUNT;}
static void wdma(int devminor, int dmach) {
short bufferIndex; if ((USEDTEMPBUFSIZE(devminor,dmach)-TEMPBUFOFFSET(devminor,dmach))<DMASIZE(devminor)) {
TEMPBUFOFFSET(devminor,dmach) = 0;
}
bufferIndex = TEMPBUFOFFSET(devminor,dmach) / DMASIZE(devminor);
memcpy(DMABUF(devminor,dmach),DMATEMPBUF(devminor,dmach)+TEMPBUFOFFSET(devminor,dmach), DMASIZE(devminor));
TEMPBUFOFFSET(devminor,dmach)+=DMASIZE(devminor);#ifdef CHECK_FIFO_EMPTY if ((dm7520_table[devminor].dmasetup[dmach].usedby==DM7520_WRITE_DA1)?DA1_FIFONE:DA2_FIFONE) {
#endif if (0==dmach) {
start_dma0(devminor);
}
else {
start_dma1(devminor);
}
if (BUFFER_READY==TEMPBUFFLAG(devminor,dmach,bufferIndex))
TEMPBUFFLAG(devminor,dmach,bufferIndex) = BUFFER_COPIED;
else
TEMPBUFFLAG(devminor,dmach,bufferIndex) = BUFFER_NOT_READY;
#ifdef CHECK_FIFO_EMPTY }
else {
TEMPBUFFLAG(devminor,dmach,bufferIndex) = FIFO_EMPTY;
TEMPBUFFLAG(devminor,dmach,CONTROLFLAGSIZE-1) = FIFO_EMPTY;
printk("<1>FIFO EMPTY\n"); }
#endif }
static voiddm7520_interrupt(int irq, void *dev_id, struct pt_regs *regs) { static uint32_t dmastatus; static uint32_t itoverrun; static uint32_t dummy; static uint32_t itcsr; DM7520_STAT *devptr = (DM7520_STAT *) dev_id; int devminor; int dmach; devminor = devptr - &(dm7520_table[0]); if ((devminor < 0) || (devminor >= MAXDM7520)) { return; } itstatus = GETMEM32(devminor, LAS0, LAS0_IT) & 0x0000FFFF; itcsr = GETMEM32(devminor, LCFG, LCFG_ITCSR); dmastatus = itcsr & (PIRQS_DMA0 | PIRQS_DMA1); if (! (itstatus | dmastatus)) { return; // Not our interrupt } if (dmastatus) { dummy = GETMEM32(devminor, LCFG, LCFG_DMACSR); if (dmastatus & PIRQS_DMA0) { dummy |= 0x00000008; PUTMEM32(devminor, LCFG, LCFG_DMACSR, dummy); // clear interrupt dmach = 0; } else { // PIRQS_DMA1 dummy |= 0x00000800; PUTMEM32(devminor, LCFG, LCFG_DMACSR, dummy); // clear interrupt dmach = 1; } if (dm7520_table[devminor].dmasetup[dmach].direction == DMAD_FROMCARD) { wake_up(&(dm7520_table[devminor].readq)); } else { wdma(devminor, dmach); } } PUTMEM32(devminor, LAS0, LAS0_CLEAR, 0xffffffff); dummy = GETMEM32(devminor, LAS0, LAS0_CLEAR); itoverrun = GETMEM32(devminor, LAS0, LAS0_OVERRUN) & 0x0000FFFF; if (itoverrun) { dm7520_table[devminor].errcode = ERR_IT_OVERRUN; PUTMEM32(devminor, LAS0, LAS0_IT, 0); PUTMEM32(devminor, LAS0, LAS0_OVERRUN, 0); } /* * TODO: async notifications should be done in bottom half */ if (devptr->async_queue) {#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) /* * The kernel shipped with Redhat 6.2 (2.2.14-5.0) has a patch applied * to it which changes kill_fasync. It needs 3 args, like the 2.4 * version, but the first arg must not be passed by reference. I think * this change was a backport from the 2.3 kernel series, which was * still under development when RH6.2 was released. Note that I check * for only Redhat's 2.2.14. This problem may exist with other distros * that ship patched kernels. */#define RH_KERNEL_VERSION_H defined(__rh_kernel_version_h__)#define KERNEL_IS_2_2_14 (LINUX_VERSION_CODE == KERNEL_VERSION(2, 2, 14))#if RH_KERNEL_VERSION_H && KERNEL_IS_2_2_14 kill_fasync(devptr->async_queue, SIGIO, POLL_IN);#else kill_fasync(devptr->async_queue, SIGIO);#endif#undef RH_KERNEL_VERSION_H#undef IS_KERNEL_2_2_14#else kill_fasync(&(devptr->async_queue), SIGIO, POLL_IN);#endif }}static int dm7520_open(struct inode *inode, struct file *file){ short devminor,devmajor;
devmajor=inode->i_rdev>>8; devminor=inode->i_rdev&0xFF; if (devminor >= MAXDM7520) return -ENXIO; if (!dm7520_table[devminor].present) return -ENXIO; if (dm7520_table[devminor].opened) return -EBUSY; dm7520_table[devminor].opened++; dm7520_table[devminor].readchan=DM7520_READ_AD; //AD by default// dm7520_table[devminor].writechan=DM7520_WRITE_DA1; dm7520_table[devminor].errcode=0; init_waitqueue_head(&(dm7520_table[devminor].inq)); init_waitqueue_head(&(dm7520_table[devminor].outq)); init_waitqueue_head(&(dm7520_table[devminor].readq)); init_waitqueue_head(&(dm7520_table[devminor].writeq));
//---------------------------- dm7520_table[devminor].dmasetup[0].dmainuse=0; dm7520_table[devminor].dmasetup[0].usedby=-1;
dm7520_table[devminor].dmasetup[0].tempBufOffset = 0; //used for writing DMA
dm7520_table[devminor].dmasetup[0].tempBufSize = 0; //used for writing DMA dm7520_table[devminor].dmasetup[1].dmainuse=0; dm7520_table[devminor].dmasetup[1].usedby=-1;
dm7520_table[devminor].dmasetup[1].tempBufOffset = 0; //used for writing DMA
dm7520_table[devminor].dmasetup[1].tempBufSize = 0; //used for writing DMA
//----------------------------------------------- memset(dm7520_table[devminor].dmasetup[0].dmabuf,0,DMASIZE(devminor)); memset(dm7520_table[devminor].dmasetup[1].dmabuf,0,DMASIZE(devminor)); reset_card(devminor); dm7520_incuse(); return SUCCESS;}
static int dm7520_release(struct inode *inode, struct file *file){ short devminor,devmajor; int dmach; devmajor=inode->i_rdev>>8; devminor=inode->i_rdev&0xFF; if (devminor >= MAXDM7520) return -ENXIO; if (!dm7520_table[devminor].present) return -ENXIO; if (!dm7520_table[devminor].opened) return -EBUSY; dm7520_fasync(-1, file, 0); reset_card(devminor); dm7520_table[devminor].dmasetup[0].dmainuse=0; dm7520_table[devminor].dmasetup[1].dmainuse=0; disable_dma(devminor,0); disable_dma(devminor,1); for (dmach=0;dmach<2;dmach++) { 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].tempBufOffset = 0; //used for writing DMA
dm7520_table[devminor].dmasetup[dmach].tempBufSize = 0; //used for writing DMA dm7520_table[devminor].dmasetup[dmach].usedby=-1; } dm7520_table[devminor].opened--; dm7520_table[devminor].errcode=0;// dm7520_table[devminor].readchan=DM7520_READ_AD;// dm7520_table[devminor].writechan=DM7520_WRITE_DA1; init_waitqueue_head(&(dm7520_table[devminor].inq)); init_waitqueue_head(&(dm7520_table[devminor].outq)); init_waitqueue_head(&(dm7520_table[devminor].readq)); init_waitqueue_head(&(dm7520_table[devminor].writeq)); dm7520_decuse(); return 0;}static intdm7520_read(short devminor, int16_t *user_buf, int length) { int bytes_read; char *buffer = (char *) user_buf; int i; int dmach; int halffifobyte = DMASIZE(devminor); //size of 1/2 fifo in bytes int size; bytes_read = 0; /* * length is actually the number of samples to read, so convert it to * bytes */ length = length * 2; if (devminor >= MAXDM7520) return -ENXIO; if (! dm7520_table[devminor].present) return -ENXIO; if (! dm7520_table[devminor].opened) return -EBUSY; if (0 != dm7520_table[devminor].errcode) return (dm7520_table[devminor].errcode); bytes_read = 0; if (length < 0) return(0); for (dmach = 0; dmach < 2; dmach++) { if ( dm7520_table[devminor].dmasetup[dmach].usedby == dm7520_table[devminor].readchan ) { break; } } if (! (dmach < 2)) { //NON-DMA mode do { if (dm7520_table[devminor].readchan == DM7520_READ_AD) { while ((bytes_read < length) && ADC_FIFONE) { if ( put_user( GETMEM16(devminor, LAS1, LAS1_ADC_FIFO), user_buf ) != 0 ) { return -EFAULT; } user_buf++; bytes_read += 2; } } else { while ((bytes_read < length) && HDIN_FIFONE) { if ( put_user( GETMEM16(devminor, LAS1, LAS1_HDIO_FIFO), user_buf ) != 0 ) { return -EFAULT; } user_buf++; bytes_read += 2; } } if (bytes_read >= length) return (bytes_read / 2); interruptible_sleep_on_timeout( &(dm7520_table[devminor].readq), dm7520_table[devminor].jiffie_r ); if (signal_pending(current)) return -ERESTARTSYS; } while (1); } else { //DMA mode i = length; do { if (dm7520_table[devminor].readchan == DM7520_READ_AD) { if(! AD_FIFONF) { dm7520_table[devminor].errcode = -ENOBUFS; printk( KERN_INFO "dm7520: dma: AD fifo got full before previous " "circle finished\n" ); return (bytes_read / 2); } } else { if(! HD_FIFONF) { dm7520_table[devminor].errcode = -ENOBUFS; printk( KERN_INFO "dm7520: dma: HD fifo got full before previous circle " "finished\n" ); return (bytes_read / 2); } } if (dmach == 0) { enable_dma0(devminor); if ( dm7520_table[devminor].readchan == DM7520_READ_HD ) { reset_dma0(devminor); } start_dma0(devminor); } else { enable_dma1(devminor); if ( dm7520_table[devminor].readchan == DM7520_READ_HD ) { reset_dma1(devminor); } start_dma1(devminor); } interruptible_sleep_on(&(dm7520_table[devminor].readq)); if (signal_pending(current)) { printk(KERN_INFO "dm7520: dma - time out\n"); return -ERESTARTSYS; } size = (halffifobyte > i) ? i : halffifobyte; if (copy_to_user(buffer, (char *) DMABUF(devminor,dmach), size)) { return -EFAULT; } bytes_read += size; i -= size; buffer += size; if (bytes_read >= length) { return (bytes_read / 2); } } while (1); }}static int dm7520_ioctl( struct inode *inode, struct file *file, unsigned int ioctl_num, unsigned long ioctl_param){ dm7520_request req; dm7520_request *temp = &req; dm7520_read_request readreq; dm7520_read_request *readtemp = &readreq; short devminor,devmajor; int dmach; int channel; uint32_t dmapaddr = 0; // phisical address of dma buffer
devminor=MINOR(file->f_dentry->d_inode->i_rdev); devmajor=MAJOR(file->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;// temp = (dm7520_request *) ioctl_param; if (DM7520IOCREAD==ioctl_num) { if (copy_from_user((void*)readtemp, (void*)ioctl_param, sizeof(dm7520_read_request))) return -EFAULT; return dm7520_read(devminor, readtemp->pBuf, readtemp->size); } else { if (copy_from_user((void*)temp, (void*)ioctl_param, sizeof(dm7520_request))) return -EFAULT; } switch (ioctl_num) { case DM7520IOCGETREG: if (temp->las>LASMAX) return -EINVAL; if (LAS1==temp->las) temp->data=GETMEM16(devminor,temp->las,temp->addr); else { if (LAS0_IT==temp->addr) { temp->data = itstatus; itstatus = 0; } else temp->data=GETMEM32(devminor,temp->las,temp->addr);// printk(KERN_INFO "getreg: minor=%X, las=%X, addr=%X, data=%X \n",// devminor,temp->las,temp->addr,temp->data); } if(copy_to_user((void*)ioctl_param,(void*)temp,sizeof(dm7520_request))) return -EFAULT; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -