/************************************************************************
 *   DPMIMEM.C                                                          *
 *      -uses DPMI functions to allocate and free memory.               *
 *      This is useful for bus mastering, as bm hardware requires       *
 *      physical memory addresses.  malloc/calloc doesn't               *
 *      provide this, they provide linear/virtual addresses.            *
 *                                                                      *
 * Copyright (c) 1999 ATI Technologies Inc.  All rights reserved.       *
 ************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <dos.h>
#include <i86.h>
#include "main.h"

/************************************************************************
 *    DPMI_allocdosmem                                                  *
 *     purpose: To allocate contiguous memory for which a physical      *
 *              address can be obtained.                                *
 *      inputs: paragraphs - the total amount of paragraphs (16 bytes)  *
 *                           requested.                                 *
 *              segment - a pointer to the segment where the allocated  *
 *                        memory is located.                            *
 *              selector - a pointer to the selector of the allocated   *
 *                         memory.                                      *
 *     outputs: returns a 1 on success.                                 *
 *              returns a 0 on failure.                                 *
 ************************************************************************/
DWORD DPMI_allocdosmem (DWORD paragraphs, DWORD *segment, DWORD *selector)
{

    union REGS r;

    memset (&r, 0, sizeof (r));

    // setup DPMI call 100 using int 31h
    r.w.ax = 0x0100;
    r.w.bx = paragraphs;

    int386 (0x31, &r, &r);

    if (r.w.cflag == 0)
    {
        *segment = r.w.ax;
        *selector = r.w.dx;
        return (1);
    }

    return (0);
}

/************************************************************************
 *   DPMI_freedosmem                                                    *
 *    purpose:  To free previously allocated memory by the              *
 *              DPMI_allocdosmem function.                              *
 *     inputs:  selector - the selector of the memory to be freed.      *
 *    outputs:  return 1 on success.                                    *
 *              returns 0 on failure.                                   *
 ************************************************************************/
DWORD DPMI_freedosmem (DWORD selector)
{
    union REGS r;

    memset (&r, 0, sizeof (r));

    // setup DPMI call 101 using int 31h
    r.w.ax = 0x101;
    r.w.dx = selector;

    int386 (0x31, &r, &r);

    if (r.w.cflag == 0)
    {
        return (1);
    }

    return (0);
}


DWORD DPMI_allocatelogicalregion (DWORD physical_address, DWORD region_size)
{
    union REGS regs;
    DWORD logical_address;

    // setup DPMI call using INT 31h
    regs.w.ax = 0x800;
    regs.w.bx = (WORD)(physical_address >> 16);
    regs.w.cx = (WORD)(physical_address & 0xFFFF);
    regs.w.si = (WORD)(region_size >> 16);
    regs.w.di = (WORD)(region_size & 0xFFFF);

    // call ROM
    int386(0x31, &regs, &regs);
    if (regs.w.cflag == 0)
    {
        logical_address = ((DWORD)regs.w.bx << 16) | ((DWORD)regs.w.cx);
    }
    else
    {
        logical_address = 0;
    }

    // return logical address
    return (logical_address);
}

WORD DPMI_freelogicalregion (DWORD logical_address)
{
    union REGS regs;
    WORD   retval;

    // setup DPMI call using INT 31h
    regs.w.ax = 0x801;
    regs.w.bx = (WORD)(logical_address >> 16);
    regs.w.cx = (WORD)(logical_address & 0xFFFF);

    // call ROM
    int386(0x31, &regs, &regs);
    if (regs.w.cflag == 0)
    {
        retval = 1;
    }
    else
    {
        retval = 0;
    }

    // return error code
    return (retval);
}

WORD DPMI_allocatememory (DWORD  nbytes, DWORD *address, DWORD *handle)
{
    union REGS regs;
    DWORD temp;
    WORD   retval;

    // setup DPMI call using INT 31h
    regs.w.ax = 0x0501;
    regs.w.bx = (WORD)(nbytes >> 16);
    regs.w.cx = (WORD)(nbytes & 0xFFFF);

    // call ROM
    int386(0x31, &regs, &regs);
    if (regs.w.cflag == 0)
    {
        retval = 1;

        // address = bx:cx
        temp = regs.w.bx;
        temp = temp << 16;
        temp = temp | (DWORD)regs.w.cx;
        *address = temp;

        // handle = si:di
        temp = regs.w.si;
        temp = temp << 16;
        temp = temp | (DWORD)regs.w.di;
        *handle = temp;
    }
    else
    {
        retval = 0;
    }

    // return error code
    return (retval);
}

WORD DPMI_freememory (DWORD handle)
{
    union REGS regs;
    WORD   retval;

    // setup DPMI call using INT 31h
    regs.w.ax = 0x0502;
    regs.w.si = (WORD)(handle >> 16);
    regs.w.di = (WORD)(handle & 0xFFFF);

    // call ROM
    int386(0x31, &regs, &regs);
    if (regs.w.cflag == 0)
    {
        retval = 1;
    }
    else
    {
        retval = 0;
    }

    // return error code
    return (retval);
}


