//
// DPMI Interface class for PTC 2.0 C++ API
// Copyright (c) 1998 Jonathan Matthew (jmatthew@uq.net.au)
// The PTC 2.0 C++ API is (c) 1998 Glenn Fiedler (ptc@gaffer.org)
// This source code is licensed under the GNU LGPL
//

#include "dpmi.h"

DPMI::DPMI()
{
    return;
}

DPMI::~DPMI()
{
    return;
}

void DPMI::clearregs()
{
    memset(&regs, 0, sizeof(union REGS));
    memset(&sregs, 0, sizeof(struct SREGS));
}

int DPMI::dos_alloc(int bytes, dpmi_ptr *dp)
{
    clearregs();
    regs.w.ax = 0x0100;
    regs.w.bx = (bytes/16)+5;
    ::int386x(0x31, &regs, &regs, &sregs);
    if (regs.w.cflag) {
        dp->seg = 0;
        dp->sel = 0;
        dp->ptr = (void *)0;
        return 1;
    }
    dp->seg = regs.w.ax;
    dp->sel = regs.w.dx;
    dp->ptr = (void *)(dp->seg * 16);
    return 0;
}

int DPMI::dos_free(dpmi_ptr *dp)
{
#ifdef __DJGPP__
    if (__dpmi_free_dos_memory(dp->sel) != -1) return 0;
    else return 1;
#else
    clearregs();
    regs.w.ax = 0x0101;
    regs.w.dx = dp->sel;
    ::int386x(0x31, &regs, &regs, &sregs);
    dp->sel = 0;
    dp->seg = 0;
    dp->ptr = (void *)0;
    return 0;
#endif
}

int DPMI::dos_int(int intnum, dpmi_regs *dr, dpmi_regs *drout)
{
#ifdef __DJGPP__
    if (__dpmi_int(intnum, (__dpmi_regs *)dr) != -1) {
        memcpy(drout, dr, sizeof(__dpmi_regs));
        return 0;
    } else return 1;
#else
    clearregs();
    regs.w.ax = 0x300;
    regs.h.bl = intnum;
    regs.h.bh = 0;
    regs.w.cx = 0;
    sregs.es = FP_SEG(dr);
    regs.x.edi = FP_OFF(dr);
    ::int386x(0x31, &regs, &regs, &sregs);
    _fmemcpy(MK_FP(sregs.es, regs.x.edi), MK_FP(FP_SEG(drout),FP_OFF(drout)),
        sizeof(dpmi_regs));
    return regs.w.cflag;
#endif
}

int DPMI::map_linear_mem(int addr, int size, int *ptr)
{
#ifdef __DJGPP__
    __dpmi_meminfo info;
    info.size = size;
    info.address = addr;
    if (__dpmi_physical_address_mapping(&info) != -1) {
        *ptr = info.address;
        return 0;
    }
    else return 1;
#else
    clearregs();
    regs.w.ax = 0x0800;
    regs.w.bx = addr >> 16;
    regs.w.cx = addr & 0xFFFF;
    regs.w.si = size >> 16;
    regs.w.di = size & 0xFFFF;
    ::int386x(0x31, &regs, &regs, &sregs);
    if (!regs.w.cflag) {
        *ptr = (regs.w.bx << 16) | regs.w.cx;
        return 0;
    }
    *ptr = 0;
    return 1;
#endif
}

int DPMI::unmap_linear_mem(int ptr)
{
#ifdef __DJGPP__
    __dpmi_meminfo info;
    info.size = 0;
    info.address = ptr;
    if (__dpmi_free_physical_address_mapping(&info) != -1) return 0;
    else return 1;
#else
    clearregs();
    regs.w.ax = 0x0801;
    regs.w.bx = ptr >> 16;
    regs.w.cx = ptr & 0xFFFF;
    ::int386x(0x31, &regs, &regs, &sregs);
    return regs.w.cflag;
#endif
}

int DPMI::lock_mem(int ptr, int size)
{
#ifdef __DJGPP__
    __dpmi_meminfo info;
    info.size = size;
    info.address = ptr;
    if (__dpmi_lock_linear_region(&info) != -1) return 0;
    else return 1;
#endif
    clearregs();
    regs.w.ax = 0x600;
    regs.w.bx = ptr >> 16;
    regs.w.cx = ptr & 0xFFFF;
    regs.w.si = size >> 16;
    regs.w.di = size & 0xFFFF;
    ::int386x(0x31, &regs, &regs, &sregs);
    return regs.w.cflag;
}

int DPMI::unlock_mem(int ptr, int size)
{
#ifdef __DJGPP__
    __dpmi_meminfo info;
    info.size = size;
    info.address = ptr;
    if (__dpmi_unlock_linear_region(&info) != -1) return 0;
    else return 1;
#endif
    clearregs();
    regs.w.ax = 0x601;
    regs.w.bx = ptr >> 16;
    regs.w.cx = ptr & 0xFFFF;
    regs.w.si = size >> 16;
    regs.w.di = size & 0xFFFF;
    ::int386x(0x31, &regs, &regs, &sregs);
    return regs.w.cflag;
}
