/* buffer.c * Copyright (C) 2002-2005 CDVDlinuz Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include // errno #include // NULL #include // printf() #include // strerror() #ifndef __LINUX__ #ifdef __linux__ #define __LINUX__ #endif /* __linux__ */ #endif /* No __LINUX__ */ #define CDVDdefs #include "PS2Edefs.h" #include "logfile.h" #include "buffer.h" // Globals struct BufferSortEmpty { u16 sortptr; }; struct BufferSort { u16 upptr; u16 uppos; u32 mask; u32 divisor; struct { u8 isdata; u16 ptr; } lower[256]; u16 ptrcount; u16 firstptr; }; struct BufferSortEmpty buffersortempty[BUFFERMAX]; u16 buffersortemptystart; u16 buffersortemptyend; struct BufferSort buffersort[BUFFERMAX]; u8 buffersortstartisdata; u16 buffersortstart; struct BufferList bufferlist[BUFFERMAX]; u16 userbuffer; u16 replacebuffer; void InitBuffer() { u16 i; u16 j; #ifdef VERBOSE_FUNCTION_BUFFER PrintLog("CDVD buffer: InitBuffer()"); #endif /* VERBOSE_FUNCTION_BUFFER */ buffersortemptystart = 0; buffersortemptyend = 0; for(i = 0; i < BUFFERMAX; i++) { buffersortempty[i].sortptr = i; } // NEXT i- Saying all buffersort[] entries are open. buffersortstart = 0xffff; buffersortstartisdata = 2; for(i = 0; i < BUFFERMAX; i++) { for(j = 0; j < 256; j++) buffersort[i].lower[j].isdata = 2; // buffersort[i].ptrcount = 0; } // NEXT i- Saying all buffersort[] entries are open. for(i = 0; i < BUFFERMAX; i++) { bufferlist[i].upsort = 0xffff; } // NEXT i- Clearing out the buffer pointers userbuffer = 0xffff; replacebuffer = BUFFERMAX - 1; } // END InitBuffer(); u16 AllocSortBuffer() { u16 newbuffer; #ifdef VERBOSE_FUNCTION_BUFFER PrintLog("CDVD buffer: AllocSortBuffer()"); #endif /* VERBOSE_FUNCTION_BUFFER */ newbuffer = buffersortempty[buffersortemptyend].sortptr; buffersortempty[buffersortemptyend].sortptr = BUFFERMAX; buffersortemptyend++; if(buffersortemptyend > BUFFERMAX - 1) buffersortemptyend = 0; #ifdef VERBOSE_FUNCTION_BUFFER PrintLog("CDVD buffer: Sort Buffer %u", newbuffer); #endif /* VERBOSE_FUNCTION_BUFFER */ #ifdef VERBOSE_WARNINGS_BUFFER if(buffersortemptyend == buffersortemptystart) { PrintLog("Completely out of Sort Buffers to allocate now!"); } // ENDIF- Out of Sort Buffers? Say so! #endif /* VERBOSE_WARNINGS_BUFFER */ return(newbuffer); } // END AllocSortBuffer() void ReleaseSortBuffer(u16 oldbuffer) { #ifdef VERBOSE_FUNCTION_BUFFER PrintLog("CDVD buffer: ReleaseSortBuffer(%u)", oldbuffer); #endif /* VERBOSE_FUNCTION_BUFFER */ buffersortempty[buffersortemptystart].sortptr = oldbuffer; buffersortemptystart++; if(buffersortemptystart > BUFFERMAX - 1) buffersortemptystart = 0; } // END ReleaseSortBuffer() // Returns either index in buffersort... or closest insertion point. // Make lsn == buffersort[int].lsn test for exact match u16 FindListBuffer(u32 lsn) { u16 current; u8 isdata; u32 index; #ifdef VERBOSE_FUNCTION_BUFFER PrintLog("CDVD buffer: FindListBuffer(%u)", lsn); #endif /* VERBOSE_FUNCTION_BUFFER */ if(buffersortstart == 0xffff) return(0xffff); // Buffer empty? Exit if(buffersortstartisdata == 1) { if(bufferlist[buffersortstart].lsn != lsn) return(0xffff); return(buffersortstart); } // ENDIF- Only one Record in Buffer? #ifdef VERBOSE_FUNCTION_BUFFER PrintLog("CDVD buffer: Searching..."); #endif /* VERBOSE_FUNCTION_BUFFER */ current = buffersortstart; isdata = 0; while(isdata == 0) { index = lsn; index &= buffersort[current].mask; index /= buffersort[current].divisor; isdata = buffersort[current].lower[index].isdata; current = buffersort[current].lower[index].ptr; } // ENDWHILE- still haven't found data if(isdata == 2) return(0xffff); // Pointing at empty entry? if(bufferlist[current].lsn != lsn) return(0xffff); // LSNs don't match? #ifdef VERBOSE_FUNCTION_BUFFER PrintLog("CDVD buffer: Found."); #endif /* VERBOSE_FUNCTION_BUFFER */ return(current); } // END FindListBuffer() // Removes buffer from the buffersort list // bufnum = The bufferlist pointer void RemoveListBuffer(u16 bufnum) { u16 current; u16 currentpos; u16 upperlink; u16 upperindex; u16 lowerlink; u8 lowerisdata; u32 index; #ifdef VERBOSE_FUNCTION_BUFFER PrintLog("CDVD buffer: RemoveListBuffer(%u)", bufnum); #endif /* VERBOSE_FUNCTION_BUFFER */ if(bufferlist[bufnum].upsort == 0xffff) return; // No link to break. current = bufferlist[bufnum].upsort; currentpos = bufferlist[bufnum].uppos; bufferlist[bufnum].upsort = 0xffff; if(current == 0xfffe) { buffersortstart = 0xffff; buffersortstartisdata = 2; #ifdef VERBOSE_FUNCTION_BUFFER PrintLog("CDVD buffer: Buffer emptied"); #endif /* VERBOSE_FUNCTION_BUFFER */ return; } // ENDIF- Last link broken... empty buffer now. lowerlink = 0xffff; lowerisdata = 2; // Remove Lower Pointer buffersort[current].lower[currentpos].isdata = 2; if(currentpos == buffersort[current].firstptr) { index = currentpos + 1; while((index < 256) && (buffersort[current].lower[index].isdata == 2)) index++; buffersort[current].firstptr = index; } // ENDIF- Do we need to move firstptr to an active entry? buffersort[current].ptrcount--; #ifdef VERBOSE_FUNCTION_BUFFER PrintLog("CDVD buffer: Pointer count for sort buffer %u: %u", current, buffersort[current].ptrcount); #endif /* VERBOSE_FUNCTION_BUFFER */ if(buffersort[current].ptrcount > 1) return; // Still 2+ branches left // Find Lower Link index = buffersort[current].firstptr; lowerlink = buffersort[current].lower[index].ptr; lowerisdata = buffersort[current].lower[index].isdata; buffersort[current].lower[index].isdata = 2; // Find and Break Upper Link upperlink = buffersort[current].upptr; upperindex = buffersort[current].uppos; if(upperlink == 0xffff) { buffersortstart = lowerlink; buffersortstartisdata = lowerisdata; } else { buffersort[upperlink].lower[upperindex].ptr = lowerlink; buffersort[upperlink].lower[upperindex].isdata = lowerisdata; } // ENDIF- Did we hit the top of the web? // Break Lower Link if(lowerisdata == 1) { if(upperlink == 0xffff) { bufferlist[lowerlink].upsort = 0xfffe; #ifdef VERBOSE_FUNCTION_BUFFER PrintLog("CDVD buffer: Buffer down to 1 record now"); #endif /* VERBOSE_FUNCTION_BUFFER */ } else { bufferlist[lowerlink].upsort = upperlink; bufferlist[lowerlink].uppos = upperindex; } // ENDIF- Is this the last active buffersort? } else { buffersort[lowerlink].upptr = upperlink; buffersort[lowerlink].uppos = upperindex; } // ENDIF- Was this a BufferList link? // Cleanup in aisle 5.... ReleaseSortBuffer(current); return; } // END RemoveListBuffer() // Adds buffer to the buffersort list // bufnum = The bufferlist pointer void AddListBuffer(u16 bufnum) { u32 newmask; u32 newdivisor; u16 newbuffer; u32 newvalue; u16 current; u32 currentvalue; u8 currentisdata; u16 prevbuffer; u32 prevvalue; u16 comparebuffer; u8 compareisdata; u32 comparevalue; #ifdef VERBOSE_FUNCTION_BUFFER PrintLog("CDVD buffer: AddListBuffer(%u)", bufnum); #endif /* VERBOSE_FUNCTION_BUFFER */ // Already in list? Oh, re-sorting? Got it covered. if(bufferlist[bufnum].upsort != 0xffff) RemoveListBuffer(bufnum); if(buffersortstartisdata == 2) { buffersortstart = bufnum; buffersortstartisdata = 1; bufferlist[bufnum].upsort = 0xfffe; #ifdef VERBOSE_FUNCTION_BUFFER PrintLog("CDVD buffer: Buffer up to 1 record now"); #endif /* VERBOSE_FUNCTION_BUFFER */ return; } // ENDIF- Empty list? Set for just 1 entry. if(buffersortstartisdata == 1) { newmask = 0xff000000; newdivisor = 0x01000000; newvalue = (bufferlist[bufnum].lsn & newmask) / newdivisor; currentvalue = (bufferlist[buffersortstart].lsn & newmask) / newdivisor; while((newdivisor != 0x00000001) && (newvalue == currentvalue)) { newmask /= 0x0100; newdivisor /= 0x0100; newvalue = (bufferlist[bufnum].lsn & newmask) / newdivisor; currentvalue = (bufferlist[buffersortstart].lsn & newmask) / newdivisor; } // ENDWHILE- trying to find a difference between the LSNs if(newvalue == currentvalue) { bufferlist[buffersortstart].upsort = 0xffff; bufferlist[bufnum].upsort = 0xfffe; buffersortstart = bufnum; return; } else { newbuffer = AllocSortBuffer(); buffersort[newbuffer].upptr = 0xffff; buffersort[newbuffer].mask = newmask; buffersort[newbuffer].divisor = newdivisor; buffersort[newbuffer].lower[currentvalue].isdata = 1; buffersort[newbuffer].lower[currentvalue].ptr = buffersortstart; buffersort[newbuffer].lower[newvalue].isdata = 1; buffersort[newbuffer].lower[newvalue].ptr = bufnum; buffersort[newbuffer].ptrcount = 2; buffersort[newbuffer].firstptr = currentvalue; if(newvalue < buffersort[newbuffer].firstptr) buffersort[newbuffer].firstptr = newvalue; bufferlist[buffersortstart].upsort = newbuffer; bufferlist[buffersortstart].uppos = currentvalue; buffersortstart = newbuffer; buffersortstartisdata = 0; bufferlist[bufnum].upsort = newbuffer; bufferlist[bufnum].uppos = newvalue; #ifdef VERBOSE_FUNCTION_BUFFER PrintLog("CDVD buffer: Buffer up to 2 records now"); #endif /* VERBOSE_FUNCTION_BUFFER */ return; } // ENDIF- Same LSN? Shift pointer in response. Else, add a Sort Record. } // ENDIF- Only 1 record? Check if we need a Sort Record. newmask = 0xff000000; newdivisor = 0x01000000; prevbuffer = 0xffff; prevvalue = 0; current = buffersortstart; currentisdata = 0; while(currentisdata == 0) { newvalue = (bufferlist[bufnum].lsn & newmask) / newdivisor; if(buffersort[current].mask != newmask) { comparebuffer = current; compareisdata = 0; while(compareisdata == 0) { comparevalue = buffersort[comparebuffer].firstptr; compareisdata = buffersort[comparebuffer].lower[comparevalue].isdata; comparebuffer = buffersort[comparebuffer].lower[comparevalue].ptr; } // ENDWHILE- looking for an another buffer to compare to... comparevalue = (bufferlist[comparebuffer].lsn & newmask) / newdivisor; if(newvalue != comparevalue) { // Add buffersort here (comparevalue/newvalue) newbuffer = AllocSortBuffer(); buffersort[newbuffer].upptr = buffersort[current].upptr; buffersort[newbuffer].uppos = buffersort[current].uppos; buffersort[newbuffer].mask = newmask; buffersort[newbuffer].divisor = newdivisor; buffersort[newbuffer].lower[comparevalue].isdata = 0; buffersort[newbuffer].lower[comparevalue].ptr = current; buffersort[newbuffer].lower[newvalue].isdata = 1; buffersort[newbuffer].lower[newvalue].ptr = bufnum; buffersort[newbuffer].ptrcount = 2; buffersort[newbuffer].firstptr = comparevalue; if(newvalue < buffersort[newbuffer].firstptr) buffersort[newbuffer].firstptr = newvalue; if(buffersort[newbuffer].upptr == 0xffff) { buffersortstart = newbuffer; } else { buffersort[prevbuffer].lower[prevvalue].isdata = 0; buffersort[prevbuffer].lower[prevvalue].ptr = newbuffer; if(prevvalue < buffersort[prevbuffer].firstptr) buffersort[prevbuffer].firstptr = prevvalue; } // ENDIF- Do we need to adjust to buffersortstart connection? buffersort[current].upptr = newbuffer; buffersort[current].uppos = comparevalue; bufferlist[bufnum].upsort = newbuffer; bufferlist[bufnum].uppos = newvalue; return; } // ENDIF- Don't match? Add a buffersort here to say that! compareisdata = 0; newmask /= 0x0100; newdivisor /= 0x0100; } else { currentisdata = buffersort[current].lower[newvalue].isdata; prevbuffer = current; prevvalue = newvalue; if(currentisdata == 0) { current = buffersort[current].lower[newvalue].ptr; newmask /= 0x0100; newdivisor /= 0x0100; if(newdivisor == 0) { #ifdef VERBOSE_WARNINGS_BUFFER PrintLog("CDVD buffer: Mask/Divisor at 0! Index corruption! (detected in search)"); #endif /* VERBOSE_WARNINGS_BUFFER */ return; } // ENDIF- The Mask went too far! Abort! (Sanity Check) } // ENDIF- Do we have to go through another level of sort data? } // ENDIF- We don't have a comparison on this byte? } // ENDWHILE- looking for his level... if(buffersort[current].lower[newvalue].isdata == 2) { buffersort[current].lower[newvalue].isdata = 1; buffersort[current].lower[newvalue].ptr = bufnum; buffersort[current].ptrcount++; if(newvalue < buffersort[current].firstptr) buffersort[current].firstptr = newvalue; bufferlist[bufnum].upsort = current; bufferlist[bufnum].uppos = newvalue; return; } // ENDIF- an empty slot? Fill it in. comparebuffer = buffersort[current].lower[newvalue].ptr; if(bufferlist[bufnum].lsn == bufferlist[comparebuffer].lsn) { buffersort[current].lower[newvalue].ptr = bufnum; bufferlist[bufnum].upsort = current; bufferlist[bufnum].uppos = newvalue; bufferlist[comparebuffer].upsort = 0xffff; return; } // ENDIF- Same LSN? Replace! // Calc new position based on new separation markers... newmask /= 0x0100; newdivisor /= 0x0100; if(newdivisor == 0) { #ifdef VERBOSE_WARNINGS_BUFFER PrintLog("CDVD buffer: Mask/Divisor at 0! Index corruption! (bottom add initial)"); #endif /* VERBOSE_WARNINGS_BUFFER */ return; } // ENDIF- The Mask went too far! Abort! (Sanity Check) newvalue = (bufferlist[bufnum].lsn & newmask) / newdivisor; comparevalue = (bufferlist[comparebuffer].lsn & newmask) / newdivisor; while((newmask != 0x000000ff) && (comparevalue == newvalue)) { newmask /= 0x0100; newdivisor /= 0x0100; if(newdivisor == 0) { #ifdef VERBOSE_WARNINGS_BUFFER PrintLog("CDVD buffer: Mask/Divisor at 0! Index corruption! (bottom add loop)"); #endif /* VERBOSE_WARNINGS_BUFFER */ return; } // ENDIF- The Mask went too far! Abort! (Sanity Check) newvalue = (bufferlist[bufnum].lsn & newmask) / newdivisor; comparevalue = (bufferlist[comparebuffer].lsn & newmask) / newdivisor; } // ENDWHILE- continuing to scan for difference between the two numbers newbuffer = AllocSortBuffer(); buffersort[newbuffer].upptr = prevbuffer; buffersort[newbuffer].uppos = prevvalue; buffersort[newbuffer].mask = newmask; buffersort[newbuffer].divisor = newdivisor; buffersort[newbuffer].lower[comparevalue].isdata = 1; buffersort[newbuffer].lower[comparevalue].ptr = comparebuffer; buffersort[newbuffer].lower[newvalue].isdata = 1; buffersort[newbuffer].lower[newvalue].ptr = bufnum; buffersort[newbuffer].ptrcount = 2; buffersort[newbuffer].firstptr = comparevalue; if(newvalue < buffersort[newbuffer].firstptr) buffersort[newbuffer].firstptr = newvalue; buffersort[prevbuffer].lower[prevvalue].isdata = 0; buffersort[prevbuffer].lower[prevvalue].ptr = newbuffer; bufferlist[comparebuffer].upsort = newbuffer; bufferlist[comparebuffer].uppos = comparevalue; bufferlist[bufnum].upsort = newbuffer; bufferlist[bufnum].uppos = newvalue; } // END AddListBuffer() #ifdef VERBOSE_WARNINGS_BUFFER void PrintSortBuffers() { u16 h; u16 i; u16 j; printf("CDVD buffer: Sort Buffer Dump\n"); printf("CDVD buffer: Top Pointer: isdata %u ptr %u\n", buffersortstartisdata, buffersortstart); for(i = 0; i < BUFFERMAX; i++) { h = 0; while((h < BUFFERMAX) && (buffersortempty[h].sortptr != i)) h++; if(h == BUFFERMAX) { printf("CDVD buffer: Sort Buffer:%u Mask:%x Divisor:%x\n", i, buffersort[i].mask, buffersort[i].divisor); printf("CDVD buffer: Up Ptr:%u Up Pos:%u First Down Ptr:%u Ptr Count: %u\n", buffersort[i].upptr, buffersort[i].uppos, buffersort[i].firstptr, buffersort[i].ptrcount); printf("CDVD buffer: "); for(j = 0; j < 256; j++) { if(buffersort[i].lower[j].isdata == 1) printf(" D"); if(buffersort[i].lower[j].isdata == 0) printf(" L"); if(buffersort[i].lower[j].isdata < 2) { printf("%u:%u", j, buffersort[i].lower[j].ptr); } // ENDIF- We have active data? Print it. } // NEXT j- Scanning lower 256 pointers for active ones... printf("\n"); } // ENDIF- Not found in inactive list? Must be active! Print it. } // NEXT i- looking at all the Allocated Buffers... } // END PrintSortBuffers() #endif /* VERBOSE_WARNINGS_BUFFER */