/* Open WSS for usage */ boolean wss_open() { __dpmi_meminfo struct_info; if (!wss.ok) if (!wss_detect()) return FALSE; if (wss.open) return FALSE; /* Now lock the wss structure in memory */ struct_info.address = __djgpp_base_address + (unsigned long)&wss; struct_info.size = sizeof(wss); if (__dpmi_lock_linear_region(&struct_info)) return FALSE; /* Hook the WSS IRQ */ wss.irq_handle = irq_hook(wss.irq, wss_irq, (long)wss_irq_end - (long)wss_irq); if (!wss.irq_handle) { __dpmi_unlock_linear_region(&struct_info); return FALSE; } /* Enable the interrupt */ irq_enable(wss.irq_handle); if (wss.irq > 7) _irq_enable(2); wss.open++; return TRUE; }
void dma_finalize() { if (!__initialized) return; __dpmi_unlock_linear_region(&__locked_data); __djgpp_nearptr_disable(); }
static void _unlock_dpmi_data(void *addr, int size) { unsigned long baseaddr; __dpmi_meminfo mem; __dpmi_get_segment_base_address(_go32_my_ds(), &baseaddr); mem.address = baseaddr + (unsigned long)addr; mem.size = size; __dpmi_unlock_linear_region(&mem); }
void dma_free(dma_buffer * buffer) { __dpmi_meminfo buff_info; if (!buffer) return; buff_info.address = buffer->physical; buff_info.size = buffer->size; __dpmi_unlock_linear_region(&buff_info); __dpmi_free_dos_memory(buffer->selector); free(buffer); if (--__buffer_count == 0) dma_finalize(); }
/* Finish working with WSS */ boolean wss_close() { __dpmi_meminfo struct_info; if (!wss.open) return FALSE; wss.open--; /* Stop/free DMA buffer */ wss_stop_dma(); /* Unhook IRQ */ irq_unhook(wss.irq_handle); wss.irq_handle = NULL; /* Unlock the wss structure */ struct_info.address = __djgpp_base_address + (unsigned long)&wss; struct_info.size = sizeof(wss); __dpmi_unlock_linear_region(&struct_info); return TRUE; }
void *dos_getmaxlockedmem(int *size) { __dpmi_free_mem_info meminfo; __dpmi_meminfo info; int working_size; void *working_memory; int last_locked; int extra, i, j, allocsize; static char *msg = "Locking data..."; int m, n; byte *x; // first lock all the current executing image so the locked count will // be accurate. It doesn't hurt to lock the memory multiple times last_locked = __djgpp_selector_limit + 1; info.size = last_locked - 4096; info.address = __djgpp_base_address + 4096; if (lockmem) { if(__dpmi_lock_linear_region(&info)) { Sys_Error ("Lock of current memory at 0x%lx for %ldKb failed!\n", info.address, info.size/1024); } } __dpmi_get_free_memory_information(&meminfo); if (!win95) /* Not windows or earlier than Win95 */ { working_size = meminfo.maximum_locked_page_allocation_in_pages * 4096; } else { working_size = meminfo.largest_available_free_block_in_bytes - LEAVE_FOR_CACHE; } working_size &= ~0xffff; /* Round down to 64K */ working_size += 0x10000; do { working_size -= 0x10000; /* Decrease 64K and try again */ working_memory = sbrk(working_size); } while (working_memory == (void *)-1); extra = 0xfffc - ((unsigned)sbrk(0) & 0xffff); if (extra > 0) { sbrk(extra); working_size += extra; } // now grab the memory info.address = last_locked + __djgpp_base_address; if (!win95) { info.size = __djgpp_selector_limit + 1 - last_locked; while (info.size > 0 && __dpmi_lock_linear_region(&info)) { info.size -= 0x1000; working_size -= 0x1000; sbrk(-0x1000); } } else { /* Win95 section */ j = COM_CheckParm("-winmem"); if (standard_quake) minmem = MINIMUM_WIN_MEMORY; else minmem = MINIMUM_WIN_MEMORY_LEVELPAK; if (j) { allocsize = ((int)(Q_atoi(com_argv[j+1]))) * 0x100000 + LOCKED_FOR_MALLOC; if (allocsize < (minmem + LOCKED_FOR_MALLOC)) allocsize = minmem + LOCKED_FOR_MALLOC; } else { allocsize = minmem + LOCKED_FOR_MALLOC; } if (!lockmem) { // we won't lock, just sbrk the memory info.size = allocsize; goto UpdateSbrk; } // lock the memory down write (STDOUT, msg, strlen (msg)); for (j=allocsize ; j>(minmem + LOCKED_FOR_MALLOC) ; j -= 0x100000) { info.size = j; if (!__dpmi_lock_linear_region(&info)) goto Locked; write (STDOUT, ".", 1); } // finally, try with the absolute minimum amount for (i=0 ; i<10 ; i++) { info.size = minmem + LOCKED_FOR_MALLOC; if (!__dpmi_lock_linear_region(&info)) goto Locked; } Sys_Error ("Can't lock memory; %d Mb lockable RAM required. " "Try shrinking smartdrv.", info.size / 0x100000); Locked: UpdateSbrk: info.address += info.size; info.address -= __djgpp_base_address + 4; // ending point, malloc align working_size = info.address - (int)working_memory; sbrk(info.address-(int)sbrk(0)); // negative adjustment } if (lockunlockmem) { __dpmi_unlock_linear_region (&info); printf ("Locked and unlocked %d Mb data\n", working_size / 0x100000); } else if (lockmem) { printf ("Locked %d Mb data\n", working_size / 0x100000); } else { printf ("Allocated %d Mb data\n", working_size / 0x100000); } // touch all the memory to make sure it's there. The 16-page skip is to // keep Win 95 from thinking we're trying to page ourselves in (we are // doing that, of course, but there's no reason we shouldn't) x = (byte *)working_memory; for (n=0 ; n<4 ; n++) { for (m=0 ; m<(working_size - 16 * 0x1000) ; m += 4) { sys_checksum += *(int *)&x[m]; sys_checksum += *(int *)&x[m + 16 * 0x1000]; } } // give some of what we locked back for malloc before returning. Done // by cheating and passing a negative value to sbrk working_size -= LOCKED_FOR_MALLOC; sbrk( -(LOCKED_FOR_MALLOC)); *size = working_size; return working_memory; }
dma_buffer *dma_allocate(unsigned int channel, unsigned int size) { int parsize = (size + 15) >> 4; /* size in paragraphs */ int par = 0; /* Real-mode paragraph */ int selector = 0; /* Protected-mode selector */ int mask = channel <= 3 ? 0xfff : 0x1fff; /* Alignment mask in para. */ int allocsize = parsize; /* Allocated size in paragraphs */ int count; /* Try count */ int bound = 0; /* Nearest bound address */ int maxsize; /* Maximal possible block size */ dma_buffer *buffer = NULL; __dpmi_meminfo buff_info, struct_info; if (!dma_initialize()) return NULL; /* Loop until we'll get a properly aligned memory block */ for (count = 8; count; count--) { int resize = (selector != 0); /* Try first to resize (possibly previously) allocated block */ if (resize) { maxsize = (bound + parsize) - par; if (maxsize > parsize * 2) maxsize = parsize * 2; if (maxsize == allocsize) resize = 0; else { allocsize = maxsize; /* BUG WARNING: there is an error in dpmi.h DJGPP 2.01 library: the order of "selector" and "alloc size" should be reversed */ if (__dpmi_resize_dos_memory(allocsize, selector, &maxsize) != 0) resize = 0; } } if (!resize) { if (selector) __dpmi_free_dos_memory(selector), selector = 0; par = __dpmi_allocate_dos_memory(allocsize, &selector); } if ((par == 0) || (par == -1)) goto exit; /* If memory block contains a properly aligned portion, quit loop */ bound = (par + mask + 1) & ~mask; if (par + parsize <= bound) break; if (bound + parsize <= par + allocsize) { par = bound; break; } } if (!count) { __dpmi_free_dos_memory(selector); goto exit; } buffer = malloc(sizeof(dma_buffer)); buffer->linear = (void *)(__djgpp_conventional_base + bound * 16); buffer->physical = bound * 16; buffer->size = parsize * 16; buffer->selector = selector; buffer->channel = channel; buff_info.address = buffer->physical; buff_info.size = buffer->size; /* Don't pay attention to return code since under plain DOS it often returns error (at least under HIMEM/CWSDPMI and EMM386/DPMI) */ __dpmi_lock_linear_region(&buff_info); /* Lock the DMA buffer control structure as well */ struct_info.address = __djgpp_base_address + (unsigned long)buffer; struct_info.size = sizeof(dma_buffer); if (__dpmi_lock_linear_region(&struct_info)) { __dpmi_unlock_linear_region(&buff_info); __dpmi_free_dos_memory(selector); free(buffer); buffer = NULL; goto exit; } exit: if (buffer) __buffer_count++; else if (--__buffer_count == 0) dma_finalize(); return buffer; }