/* includes */ #include "rng_dma.h" #include "cacheLib.h" #include "FastCopy.h" #include "stdlib.h" /*----------------------------------*/ /* Buffer Create and Delete */ /*----------------------------------*/ /* Create a new ring buffer */ DMA_RING_ID rng_dmaCreate(int nbytes) { /* allocate memory for struct */ DMA_RING_ID newring = (DMA_RING_ID)malloc(sizeof(DMA_RING)); if (newring == NULL) { printf("Couldn't allocate memory for ring buffer"); return NULL; } /* allocate the memory */ newring->bufStart = (char*)cacheDmaMalloc(nbytes); if (newring->bufStart == NULL) { printf("Couldn't allocate memory for ring buffer"); return NULL; } /* fix starting values of the other pointers */ newring->bufEnd = newring->bufStart + nbytes; newring->pWrite = newring->bufStart; newring->pRead = NULL; /* empty - nothing to read */ newring->pLastWrite = newring->bufEnd; return newring; } STATUS rng_dmaDelete(DMA_RING_ID ring_name) { if (ring_name->bufStart == NULL) { printf("Ring Buffer Delete Failed \n"); return ERROR; } else { cacheDmaFree((void*)(ring_name->bufStart)); free(ring_name); ring_name->bufStart = NULL; } return OK; } /*--------------------------------*/ /* Full/Empty Status routines */ /*--------------------------------*/ BOOL rng_dmaIsEmpty (DMA_RING_ID ring_name) { if (ring_name->pRead == NULL) { return TRUE; } else { return FALSE; } } BOOL rng_dmaIsFull (DMA_RING_ID ring_name) { if (ring_name->pWrite == NULL) { return TRUE; } else { return FALSE; } } UINT32 rng_dmaBytesUsed(DMA_RING_ID ring_name) { /* if empty */ if (ring_name->pRead == NULL) return 0; /* if full */ if (ring_name->pWrite == NULL) return ring_name->bufEnd - ring_name->bufStart; /* if write ahead of read */ if (ring_name->pWrite > ring_name->pRead) return ring_name->pWrite - ring_name->pRead; /* if read ahead of write */ if (ring_name->pRead > ring_name->pWrite) return ((ring_name->pLastWrite - ring_name->pRead) + (ring_name->pWrite - ring_name->bufStart)); /* shouldn't get here */ printf("Error in rng_bytesUsed\n"); return 0; } /*----------------------------------*/ /* DMA buffer handling routines */ /*----------------------------------*/ /* DME WRITE */ /* Get write pointer with enough space to write nbytes of data in one dma block. Returns pointer if space is available and NULL if not available */ char* rng_dmaWriteDMA(DMA_RING_ID ring_name, int nbytes) { /* if full return NULL */ if (ring_name->pWrite == NULL) { return NULL; } /* if read is ahead of write */ if ((int)(ring_name->pRead - ring_name->pWrite) >= 0) { /* if enough space */ if ((int)(ring_name->pRead - ring_name->pWrite) >= nbytes) { return ring_name->pWrite; } else { return NULL; } } /* else - write ahead of read */ else { /* if space before bufEnd */ if((int)(ring_name->bufEnd - ring_name->pWrite) >= nbytes) { return ring_name->pWrite; } /* else - check space at bufStart */ else { if (((int)(ring_name->pRead - ring_name->bufStart) >= nbytes) || ((ring_name->pRead == NULL) && ((ring_name->pWrite - ring_name->bufStart) >= nbytes))) { ring_name->pLastWrite = ring_name->pWrite; ring_name->pWrite = ring_name->bufStart; return ring_name->pWrite; } else { return NULL; } } } } /* After a dma (or other write process notify ring buffer of actual number of bytes written - note pwrite should not have been modified */ STATUS rng_dmaWritten(DMA_RING_ID ring_name, int nbytes,int method) { /* If DMA write then invalidate the cache for that memory */ if (method == DMA_METHOD) { CACHE_DMA_INVALIDATE(ring_name->pWrite,nbytes); } /* if the buffer was empty then set read pointer to where the write started */ if (ring_name->pRead == NULL) { ring_name->pRead=ring_name->pWrite; ring_name->pLastWrite=ring_name->bufEnd; } /* advance the write pointer by nybtes marking */ ring_name->pWrite+=nbytes; /* handle the possiblty of either being at the end of the physical space or being full */ if (ring_name->pWrite >= ring_name->bufEnd) { ring_name->pWrite -= ring_name->bufEnd - ring_name->bufStart; } if (ring_name->pWrite == ring_name->pRead) { ring_name->pWrite = NULL; } return OK; } /*----------*/ /* DMA READ */ /*----------*/ /* For dma read process, Returns read pointer if nybtes of data has been written in one block. Returns E_DMA_NOT_POSSIBLE if data is written but not is block (ie crosses the end of the buffer). Returns NULL if the data is not present */ char* rng_dmaRead(DMA_RING_ID ring_name, int nbytes,int method) { int totop; /* If ring buffer is empty */ if (ring_name->pRead == NULL) { printf ("not enough data written to get\n"); return NULL; } /* Possibilities if Read is before Write pointer */ if ((int)(ring_name->pWrite - ring_name->pRead)>=0) { if ((int)(ring_name->pWrite - ring_name->pRead)>=nbytes) { if (method == DMA_METHOD) { CACHE_DMA_FLUSH(ring_name->pRead,nbytes); } return ring_name->pRead; } else { printf ("not enough data written to get\n"); return NULL; } } /* Possibilities if Write is before Read pointer */ /* if enough data before Last Write pointer */ if ((int)(ring_name->pLastWrite - ring_name->pRead)>=nbytes) { if (method == DMA_METHOD) { CACHE_DMA_FLUSH(ring_name->pRead,nbytes); } return ring_name->pRead; } /* else - Read is before Write */ else { totop=(int)(ring_name->pLastWrite - ring_name->pRead); /* if there is enough data but it crosses the lastwrite pointer to restart at the bufStart give E_DMA_NOT_POSSIBLE */ if ((int)(ring_name->pWrite - ring_name->bufStart)+totop>=nbytes) { return (char*)E_DMA_NOT_POSSIBLE; } else { printf ("not enough data written to get\n"); return NULL; } } } /* this function moves the read pointer, freeing nbytes worth of space */ STATUS rng_dmaFree(DMA_RING_ID ring_name, int nbytes) { /* if buffer was full set pwrite to where the freed memory starts */ if (ring_name->pWrite == NULL) { ring_name->pWrite = ring_name->pRead; } /* move up read pointer */ ring_name->pRead += nbytes; /* if you have read to lastwrite then start at the beginning of the buffer and put lastwrite to end, and if empty put read to null */ if (ring_name->pRead >= ring_name->pLastWrite) { ring_name->pRead -= ring_name->pLastWrite - ring_name->bufStart; ring_name->pLastWrite = ring_name->bufEnd; } if (ring_name->pRead == ring_name->pWrite) { ring_name->pRead = NULL; } return OK; } /*----------------------------------*/ /* NON DMA buffer handling routines */ /*----------------------------------*/ /* Put nbytes of data starting at the pointer place into the ring buffer, up date pointers */ STATUS rng_dmaBufPut(FAST DMA_RING_ID ring_name,char* place,FAST int nbytes) { FAST int totop; /* if full then return error */ if (ring_name->pWrite == NULL) { printf("Ring Buffer full can't write \n "); return ERROR; } /* if read is ahead of write */ if ((int)(ring_name->pRead - ring_name->pWrite) >= 0) { if ((int)(ring_name->pRead - ring_name->pWrite) >= nbytes) { FastCopy(ring_name->pWrite,place,nbytes); rng_dmaWritten(ring_name, nbytes,CPU_METHOD); return 0; } else { return ERROR; } } /* else - write ahead of read */ else { totop=(int)(ring_name->bufEnd - ring_name->pWrite); /* if enough free space or the buffer was empty and is big enough - respectively (do transfer) */ if (((totop + ring_name->pRead - ring_name->bufStart ) >= nbytes) ||((ring_name->pRead == NULL) && ((ring_name->bufEnd - ring_name->bufStart)>= nbytes))) { /* transfer until at bufEnd or done */ FastCopy(ring_name->pWrite,place,min(totop,nbytes)); if (nbytes-totop > 0) { FastCopy(ring_name->bufStart,place,nbytes-totop); } rng_dmaWritten(ring_name, nbytes,CPU_METHOD); return 0; } } return ERROR; } /* Get nbytes of data out of the ring buffer and put them into a buffer starting at the pointer place, up date pointers */ STATUS rng_dmaBufGet(FAST DMA_RING_ID ring_name,char* place, FAST int nbytes) { FAST int totop; /* if buffer is empty */ if (ring_name->pRead == NULL) { return ERROR; } /* if write is ahead of read */ if ((int)(ring_name->pWrite - ring_name->pRead) >= 0) { if ((int)(ring_name->pWrite - ring_name->pRead) >= nbytes) { FastCopy(place,ring_name->pRead,nbytes); rng_dmaFree(ring_name, nbytes); return 0; } else { return ERROR; } } /* else - read ahead of write */ else { /* lastwrite since memory above lastwrite has no data */ totop=(int)(ring_name->pLastWrite - ring_name->pRead); /* if enough valid data or the buffer was full and is big enough, respectively (do transfer) */ if (((totop + ring_name->pWrite - ring_name->bufStart ) >= nbytes) \ ||((ring_name->pWrite == NULL) && ((ring_name->pLastWrite - ring_name->bufStart)>= nbytes))) { FastCopy(place,ring_name->pRead,min(totop,nbytes)); if (nbytes-totop > 0) { FastCopy(place,ring_name->bufStart,nbytes-totop); } rng_dmaFree(ring_name, nbytes); return 0; } } return ERROR; } void RingShow (DMA_RING_ID ring) { printf("Start: %x \n",(UINT32)ring->bufStart); printf("End: %x \n",(UINT32)ring->bufEnd); printf("pWrite: %x \n",(UINT32)ring->pWrite); printf("pRead: %x \n",(UINT32)ring->pRead); printf("pLastWrite: %x \n",(UINT32)ring->pLastWrite); }