/* 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 dpmi_lock_memory (void *start, unsigned long num_bytes) { unsigned long base = 0; /* Get the linear base address. */ if (__dpmi_get_segment_base_address (dos_pm_ds, &base) != -1) { __dpmi_meminfo mem; mem.handle = 0; /* Unused */ mem.size = num_bytes; mem.address = (unsigned long) ((char *) start + base); __dpmi_lock_linear_region (&mem); } }
int dma_initialize() { if (!__djgpp_nearptr_enable()) return 0; /* Trick: Avoid re-setting DS selector limit on each memory allocation call */ __djgpp_selector_limit = 0xffffffff; __locked_data.address = __djgpp_base_address + (unsigned long)&dma; __locked_data.size = sizeof(dma); if (__dpmi_lock_linear_region(&__locked_data)) return 0; return (__initialized = 1); }
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; }