/*
 * MMSYSTEM mmio* functions
 *
 * Copyright 1993               Martin Ayotte
 *           1998-2003,2009     Eric Pouech
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <stdarg.h>
#include <string.h>

#include "windef.h"
#include "winbase.h"
#include "mmsystem.h"
#include "winternl.h"
#include "wownt32.h"
#include "winnls.h"

#include "wine/winuser16.h"
#include "winemm16.h"

#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(mmsys);

/* ###################################################
 * #                     MMIO                        #
 * ###################################################
 */
#include <pshpack1.h>
#define MMIO_MAX_THUNKS      32

static struct mmio_thunk
{
    BYTE        popl_eax;       /* popl  %eax (return address) */
    BYTE        pushl_func;     /* pushl $pfn16 (16bit callback function) */
    LPMMIOPROC16 pfn16;
    BYTE        pushl_eax;      /* pushl %eax */
    BYTE        jmp;            /* ljmp MMIO_Callback1632 */
    DWORD       callback;
    HMMIO       hMmio;          /* Handle to 32bit mmio object */
    SEGPTR      segbuffer;      /* actual segmented ptr to buffer */
} *MMIO_Thunks;

#include <poppack.h>

static CRITICAL_SECTION mmio_cs;
static CRITICAL_SECTION_DEBUG mmio_critsect_debug =
{
    0, 0, &mmio_cs,
    { &mmio_critsect_debug.ProcessLocksList, &mmio_critsect_debug.ProcessLocksList },
      0, 0, { (DWORD_PTR)(__FILE__ ": mmsystem_mmio_cs") }
};
static CRITICAL_SECTION mmio_cs = { &mmio_critsect_debug, -1, 0, 0, 0, 0 };

/****************************************************************
 *       		MMIO_Map32To16			[INTERNAL]
 */
static LRESULT	MMIO_Map32To16(DWORD wMsg, LPARAM* lp1, LPARAM* lp2)
{
    switch (wMsg) {
    case MMIOM_CLOSE:
    case MMIOM_SEEK:
	/* nothing to do */
	break;
    case MMIOM_OPEN:
    case MMIOM_READ:
    case MMIOM_WRITE:
    case MMIOM_WRITEFLUSH:
        *lp1 = MapLS( (void *)*lp1 );
	break;
    case MMIOM_RENAME:
        *lp1 = MapLS( (void *)*lp1 );
        *lp2 = MapLS( (void *)*lp2 );
        break;
    default:
        if (wMsg < MMIOM_USER)
            TRACE("Not a mappable message (%d)\n", wMsg);
    }
    return MMSYSERR_NOERROR;
}

/****************************************************************
 *       	MMIO_UnMap32To16 			[INTERNAL]
 */
static LRESULT	MMIO_UnMap32To16(DWORD wMsg, LPARAM lParam1, LPARAM lParam2,
				 LPARAM lp1, LPARAM lp2)
{
    switch (wMsg) {
    case MMIOM_CLOSE:
    case MMIOM_SEEK:
	/* nothing to do */
	break;
    case MMIOM_OPEN:
    case MMIOM_READ:
    case MMIOM_WRITE:
    case MMIOM_WRITEFLUSH:
        UnMapLS( lp1 );
	break;
    case MMIOM_RENAME:
        UnMapLS( lp1 );
        UnMapLS( lp2 );
	break;
    default:
        if (wMsg < MMIOM_USER)
            TRACE("Not a mappable message (%d)\n", wMsg);
    }
    return MMSYSERR_NOERROR;
}

/******************************************************************
 *		MMIO_Callback3216
 *
 *
 */
static LRESULT MMIO_Callback3216(SEGPTR cb16, LPMMIOINFO lpmmioinfo, UINT uMessage,
                                 LPARAM lParam1, LPARAM lParam2)
{
    DWORD 		result;
    MMIOINFO16          mmioInfo16;
    SEGPTR		segmmioInfo16;
    LPARAM		lp1 = lParam1, lp2 = lParam2;
    WORD                args[7];

    if (!cb16) return MMSYSERR_INVALPARAM;

    memset(&mmioInfo16, 0, sizeof(MMIOINFO16));
    mmioInfo16.lDiskOffset = lpmmioinfo->lDiskOffset;
    mmioInfo16.adwInfo[0]  = lpmmioinfo->adwInfo[0];
    mmioInfo16.adwInfo[1]  = lpmmioinfo->adwInfo[1];
    mmioInfo16.adwInfo[2]  = lpmmioinfo->adwInfo[2];
    /* map (lParam1, lParam2) into (lp1, lp2) 32=>16 */
    if ((result = MMIO_Map32To16(uMessage, &lp1, &lp2)) != MMSYSERR_NOERROR)
        return result;

    segmmioInfo16 = MapLS(&mmioInfo16);
    args[6] = HIWORD(segmmioInfo16);
    args[5] = LOWORD(segmmioInfo16);
    args[4] = uMessage;
    args[3] = HIWORD(lp1);
    args[2] = LOWORD(lp1);
    args[1] = HIWORD(lp2);
    args[0] = LOWORD(lp2);
    WOWCallback16Ex( cb16, WCB16_PASCAL, sizeof(args), args, &result );
    UnMapLS(segmmioInfo16);
    MMIO_UnMap32To16(uMessage, lParam1, lParam2, lp1, lp2);

    lpmmioinfo->lDiskOffset = mmioInfo16.lDiskOffset;
    lpmmioinfo->adwInfo[0]  = mmioInfo16.adwInfo[0];
    lpmmioinfo->adwInfo[1]  = mmioInfo16.adwInfo[1];
    lpmmioinfo->adwInfo[2]  = mmioInfo16.adwInfo[2];

    return result;
}

/******************************************************************
 *		MMIO_AddThunk
 *
 */
static struct mmio_thunk*       MMIO_AddThunk(LPMMIOPROC16 pfn16, HPSTR segbuf)
{
    struct mmio_thunk* thunk;

    if (!MMIO_Thunks)
    {
        MMIO_Thunks = VirtualAlloc(NULL, MMIO_MAX_THUNKS * sizeof(*MMIO_Thunks), MEM_COMMIT,
                                   PAGE_EXECUTE_READWRITE);
        if (!MMIO_Thunks) return NULL;
        for (thunk = MMIO_Thunks; thunk < &MMIO_Thunks[MMIO_MAX_THUNKS]; thunk++)
        {
            thunk->popl_eax     = 0x58;   /* popl  %eax */
            thunk->pushl_func   = 0x68;   /* pushl $pfn16 */
            thunk->pfn16        = 0;
            thunk->pushl_eax    = 0x50;   /* pushl %eax */
            thunk->jmp          = 0xe9;   /* jmp MMIO_Callback3216 */
            thunk->callback     = (char *)MMIO_Callback3216 - (char *)(&thunk->callback + 1);
            thunk->hMmio        = NULL;
            thunk->segbuffer    = 0;
        }
    }
    for (thunk = MMIO_Thunks; thunk < &MMIO_Thunks[MMIO_MAX_THUNKS]; thunk++)
    {
        if (thunk->pfn16 == 0 && thunk->hMmio == NULL)
        {
            thunk->pfn16 = pfn16;
            thunk->hMmio = NULL;
            thunk->segbuffer = (SEGPTR)segbuf;
            return thunk;
        }
    }
    FIXME("Out of mmio-thunks. Bump MMIO_MAX_THUNKS\n");
    return NULL;
}

/******************************************************************
 *		MMIO_HasThunk
 *
 */
static struct mmio_thunk*    MMIO_HasThunk(HMMIO hmmio)
{
    struct mmio_thunk* thunk;

    if (!MMIO_Thunks) return NULL;
    for (thunk = MMIO_Thunks; thunk < &MMIO_Thunks[MMIO_MAX_THUNKS]; thunk++)
    {
        if (thunk->hMmio == hmmio) return thunk;
    }
    return NULL;
}

/******************************************************************
 *             MMIO_SetSegmentedBuffer
 *
 */
static void     MMIO_SetSegmentedBuffer(struct mmio_thunk* thunk, SEGPTR ptr, BOOL release)
{
    if (release) UnMapLS(thunk->segbuffer);
    thunk->segbuffer = ptr;
}

/**************************************************************************
 * 				mmioOpen       		[MMSYSTEM.1210]
 */
HMMIO16 WINAPI mmioOpen16(LPSTR szFileName, MMIOINFO16* lpmmioinfo16,
			  DWORD dwOpenFlags)
{
    HMMIO 	ret;

    if (lpmmioinfo16) {
	MMIOINFO	        mmioinfo;
        struct mmio_thunk*      thunk = NULL;

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

        EnterCriticalSection(&mmio_cs);
        if (!(thunk = MMIO_AddThunk(lpmmioinfo16->pIOProc, lpmmioinfo16->pchBuffer)))
        {
            LeaveCriticalSection(&mmio_cs);
            return 0;
        }

	mmioinfo.dwFlags     = lpmmioinfo16->dwFlags;
	mmioinfo.fccIOProc   = lpmmioinfo16->fccIOProc;
	mmioinfo.pIOProc     = lpmmioinfo16->pIOProc ? (LPMMIOPROC)thunk : 0;
	mmioinfo.cchBuffer   = lpmmioinfo16->cchBuffer;
	mmioinfo.pchBuffer   = MapSL((DWORD)lpmmioinfo16->pchBuffer);
        mmioinfo.adwInfo[0]  = lpmmioinfo16->adwInfo[0];
        /* if we don't have a file name, it's likely a passed open file descriptor */
        if (!szFileName)
            mmioinfo.adwInfo[0] = (DWORD)DosFileHandleToWin32Handle(mmioinfo.adwInfo[0]);
	mmioinfo.adwInfo[1]  = lpmmioinfo16->adwInfo[1];
	mmioinfo.adwInfo[2]  = lpmmioinfo16->adwInfo[2];

	ret = mmioOpenA(szFileName, &mmioinfo, dwOpenFlags);
        if (!ret || (dwOpenFlags & (MMIO_PARSE|MMIO_EXIST)))
        {
            thunk->pfn16 = NULL;
            thunk->hMmio = NULL;
        }
        else thunk->hMmio = ret;
        if (ret && (dwOpenFlags & MMIO_ALLOCBUF))
        {
            MMIOINFO    m;
            if (lpmmioinfo16->pchBuffer) FIXME("ooch\n");
            /* FIXME: check whether mmioOpen should set pchBuffer */
            mmioGetInfo(ret, &m, 0);
            thunk->segbuffer = MapLS(m.pchBuffer);
        }
        LeaveCriticalSection(&mmio_cs);

	lpmmioinfo16->wErrorRet = mmioinfo.wErrorRet;
        lpmmioinfo16->hmmio     = HMMIO_16(mmioinfo.hmmio);
    } else {
	ret = mmioOpenA(szFileName, NULL, dwOpenFlags);
    }
    return HMMIO_16(ret);
}

/**************************************************************************
 * 				mmioClose      		[MMSYSTEM.1211]
 */
MMRESULT16 WINAPI mmioClose16(HMMIO16 hmmio, UINT16 uFlags)
{
    MMRESULT ret;

    EnterCriticalSection(&mmio_cs);
    ret = mmioClose(HMMIO_32(hmmio), uFlags);
    if (ret == MMSYSERR_NOERROR)
    {
        struct mmio_thunk* thunk;

        if ((thunk = MMIO_HasThunk(HMMIO_32(hmmio))))
        {
            MMIO_SetSegmentedBuffer(thunk, 0, TRUE);
            thunk->pfn16 = NULL;
            thunk->hMmio = NULL;
        }
    }
    LeaveCriticalSection(&mmio_cs);
    return ret;
}

/**************************************************************************
 * 				mmioRead	       	[MMSYSTEM.1212]
 */
LONG WINAPI mmioRead16(HMMIO16 hmmio, HPSTR pch, LONG cch)
{
    return mmioRead(HMMIO_32(hmmio), pch, cch);
}

/**************************************************************************
 * 				mmioWrite      		[MMSYSTEM.1213]
 */
LONG WINAPI mmioWrite16(HMMIO16 hmmio, HPCSTR pch, LONG cch)
{
    return mmioWrite(HMMIO_32(hmmio),pch,cch);
}

/**************************************************************************
 * 				mmioSeek       		[MMSYSTEM.1214]
 */
LONG WINAPI mmioSeek16(HMMIO16 hmmio, LONG lOffset, INT16 iOrigin)
{
    return mmioSeek(HMMIO_32(hmmio), lOffset, iOrigin);
}

/**************************************************************************
 * 				mmioGetInfo	       	[MMSYSTEM.1215]
 */
MMRESULT16 WINAPI mmioGetInfo16(HMMIO16 hmmio, MMIOINFO16* lpmmioinfo, UINT16 uFlags)
{
    MMIOINFO            mmioinfo;
    MMRESULT            ret;
    struct mmio_thunk*  thunk;

    TRACE("(0x%04x,%p,0x%08x)\n", hmmio, lpmmioinfo, uFlags);

    EnterCriticalSection(&mmio_cs);
    if ((thunk = MMIO_HasThunk(HMMIO_32(hmmio))) == NULL)
    {
        LeaveCriticalSection(&mmio_cs);
	return MMSYSERR_INVALHANDLE;
    }

    ret = mmioGetInfo(HMMIO_32(hmmio), &mmioinfo, uFlags);
    if (ret != MMSYSERR_NOERROR)
    {
        LeaveCriticalSection(&mmio_cs);
        return ret;
    }

    lpmmioinfo->dwFlags     = mmioinfo.dwFlags;
    lpmmioinfo->fccIOProc   = mmioinfo.fccIOProc;
    lpmmioinfo->pIOProc     = thunk->pfn16;
    lpmmioinfo->wErrorRet   = mmioinfo.wErrorRet;
    lpmmioinfo->hTask       = HTASK_16(mmioinfo.hTask);
    lpmmioinfo->cchBuffer   = mmioinfo.cchBuffer;
    lpmmioinfo->pchBuffer   = (void*)thunk->segbuffer;
    lpmmioinfo->pchNext     = (void*)(thunk->segbuffer + (mmioinfo.pchNext - mmioinfo.pchBuffer));
    lpmmioinfo->pchEndRead  = (void*)(thunk->segbuffer + (mmioinfo.pchEndRead - mmioinfo.pchBuffer));
    lpmmioinfo->pchEndWrite = (void*)(thunk->segbuffer + (mmioinfo.pchEndWrite - mmioinfo.pchBuffer));
    lpmmioinfo->lBufOffset  = mmioinfo.lBufOffset;
    lpmmioinfo->lDiskOffset = mmioinfo.lDiskOffset;
    lpmmioinfo->adwInfo[0]  = mmioinfo.adwInfo[0];
    lpmmioinfo->adwInfo[1]  = mmioinfo.adwInfo[1];
    lpmmioinfo->adwInfo[2]  = mmioinfo.adwInfo[2];
    lpmmioinfo->dwReserved1 = 0;
    lpmmioinfo->dwReserved2 = 0;
    lpmmioinfo->hmmio = HMMIO_16(mmioinfo.hmmio);
    LeaveCriticalSection(&mmio_cs);

    return MMSYSERR_NOERROR;
}

/**************************************************************************
 * 				mmioSetInfo  		[MMSYSTEM.1216]
 */
MMRESULT16 WINAPI mmioSetInfo16(HMMIO16 hmmio, const MMIOINFO16* lpmmioinfo, UINT16 uFlags)
{
    MMIOINFO            mmioinfo;
    MMRESULT            ret;

    TRACE("(0x%04x,%p,0x%08x)\n",hmmio,lpmmioinfo,uFlags);

    ret = mmioGetInfo(HMMIO_32(hmmio), &mmioinfo, 0);
    if (ret != MMSYSERR_NOERROR) return ret;

    /* check if seg and lin buffers are the same */
    if (mmioinfo.cchBuffer != lpmmioinfo->cchBuffer  ||
        mmioinfo.pchBuffer != MapSL((DWORD)lpmmioinfo->pchBuffer))
	return MMSYSERR_INVALPARAM;

    /* check pointers coherence */
    if (lpmmioinfo->pchNext < lpmmioinfo->pchBuffer ||
	lpmmioinfo->pchNext > lpmmioinfo->pchBuffer + lpmmioinfo->cchBuffer ||
	lpmmioinfo->pchEndRead < lpmmioinfo->pchBuffer ||
	lpmmioinfo->pchEndRead > lpmmioinfo->pchBuffer + lpmmioinfo->cchBuffer ||
	lpmmioinfo->pchEndWrite < lpmmioinfo->pchBuffer ||
	lpmmioinfo->pchEndWrite > lpmmioinfo->pchBuffer + lpmmioinfo->cchBuffer)
	return MMSYSERR_INVALPARAM;

    mmioinfo.pchNext     = mmioinfo.pchBuffer + (lpmmioinfo->pchNext     - lpmmioinfo->pchBuffer);
    mmioinfo.pchEndRead  = mmioinfo.pchBuffer + (lpmmioinfo->pchEndRead  - lpmmioinfo->pchBuffer);
    mmioinfo.pchEndWrite = mmioinfo.pchBuffer + (lpmmioinfo->pchEndWrite - lpmmioinfo->pchBuffer);

    return mmioSetInfo(HMMIO_32(hmmio), &mmioinfo, uFlags);
}

/**************************************************************************
 * 				mmioSetBuffer		[MMSYSTEM.1217]
 */
MMRESULT16 WINAPI mmioSetBuffer16(HMMIO16 hmmio, SEGPTR pchBuffer,
                                  LONG cchBuffer, UINT16 uFlags)
{
    MMRESULT    ret = mmioSetBuffer(HMMIO_32(hmmio), MapSL(pchBuffer),
                                    cchBuffer, uFlags);

    if (ret == MMSYSERR_NOERROR)
    {
        struct mmio_thunk* thunk;

        if ((thunk = MMIO_HasThunk(HMMIO_32(hmmio))) == NULL)
        {
            FIXME("really ?\n");
            return MMSYSERR_INVALHANDLE;
        }
        MMIO_SetSegmentedBuffer(thunk, pchBuffer, TRUE);
    }
    else
        UnMapLS(pchBuffer);
    return ret;
}

/**************************************************************************
 * 				mmioFlush      		[MMSYSTEM.1218]
 */
MMRESULT16 WINAPI mmioFlush16(HMMIO16 hmmio, UINT16 uFlags)
{
    return mmioFlush(HMMIO_32(hmmio), uFlags);
}

/***********************************************************************
 * 				mmioAdvance    		[MMSYSTEM.1219]
 */
MMRESULT16 WINAPI mmioAdvance16(HMMIO16 hmmio, MMIOINFO16* lpmmioinfo, UINT16 uFlags)
{
    MMIOINFO    mmioinfo;
    LRESULT     ret;

    /* WARNING: this heavily relies on mmioAdvance implementation (for choosing which
     * fields to init
     */
    if (lpmmioinfo)
    {
        mmioinfo.pchBuffer = MapSL((DWORD)lpmmioinfo->pchBuffer);
        mmioinfo.pchNext = MapSL((DWORD)lpmmioinfo->pchNext);
        mmioinfo.dwFlags = lpmmioinfo->dwFlags;
        mmioinfo.lBufOffset = lpmmioinfo->lBufOffset;
        ret = mmioAdvance(HMMIO_32(hmmio), &mmioinfo, uFlags);
    }
    else
        ret = mmioAdvance(HMMIO_32(hmmio), NULL, uFlags);

    if (ret != MMSYSERR_NOERROR) return ret;

    if (lpmmioinfo)
    {
        lpmmioinfo->dwFlags = mmioinfo.dwFlags;
        lpmmioinfo->pchNext     = (void*)(lpmmioinfo->pchBuffer + (mmioinfo.pchNext - mmioinfo.pchBuffer));
        lpmmioinfo->pchEndRead  = (void*)(lpmmioinfo->pchBuffer + (mmioinfo.pchEndRead - mmioinfo.pchBuffer));
        lpmmioinfo->pchEndWrite = (void*)(lpmmioinfo->pchBuffer + (mmioinfo.pchEndWrite - mmioinfo.pchBuffer));
        lpmmioinfo->lBufOffset  = mmioinfo.lBufOffset;
        lpmmioinfo->lDiskOffset = mmioinfo.lDiskOffset;
    }

    return MMSYSERR_NOERROR;
}

/**************************************************************************
 * 				mmioStringToFOURCC	[MMSYSTEM.1220]
 */
FOURCC WINAPI mmioStringToFOURCC16(LPCSTR sz, UINT16 uFlags)
{
    return mmioStringToFOURCCA(sz, uFlags);
}

/**************************************************************************
 *              mmioInstallIOProc    [MMSYSTEM.1221]
 */
LPMMIOPROC16 WINAPI mmioInstallIOProc16(FOURCC fccIOProc, LPMMIOPROC16 pIOProc,
                                        DWORD dwFlags)
{
    struct mmio_thunk*  thunk = NULL;
    LPMMIOPROC pIOProc32;

    EnterCriticalSection(&mmio_cs);

    switch (dwFlags & (MMIO_INSTALLPROC|MMIO_REMOVEPROC|MMIO_FINDPROC)) {
    case MMIO_INSTALLPROC:
        if (!(thunk = MMIO_AddThunk(pIOProc, NULL)))
        {
            LeaveCriticalSection(&mmio_cs);
            return NULL;
        }
        if (!mmioInstallIOProcA(fccIOProc, (LPMMIOPROC)thunk, dwFlags))
        {
            thunk->pfn16 = NULL;
            pIOProc = NULL;
        }
        break;
    case MMIO_REMOVEPROC:
        if (MMIO_Thunks)
        {
            for (thunk = MMIO_Thunks; thunk < &MMIO_Thunks[MMIO_MAX_THUNKS]; thunk++)
            {
                if (thunk->pfn16 == pIOProc && thunk->segbuffer == 0)
                {
                    if (mmioInstallIOProcA(fccIOProc, (LPMMIOPROC)thunk, dwFlags))
                        thunk->pfn16 = NULL;
                    else
                        pIOProc = NULL;
                    break;
                }
            }
        }
        if (!thunk) pIOProc = NULL;
        break;
    case MMIO_FINDPROC:
        if ((pIOProc32 = mmioInstallIOProcA(fccIOProc, NULL, dwFlags)) && MMIO_Thunks)
        {
            for (thunk = MMIO_Thunks; thunk < &MMIO_Thunks[MMIO_MAX_THUNKS]; thunk++)
            {
                if ((LPMMIOPROC)thunk == pIOProc32)
                {
                    pIOProc = thunk->pfn16;
                    break;
                }
            }
        }
        break;
    default:
        FIXME("Unsupported flags %08x\n", dwFlags);
        pIOProc = NULL;
    }
    LeaveCriticalSection(&mmio_cs);

    return pIOProc;
}

/**************************************************************************
 * 				mmioSendMessage	[MMSYSTEM.1222]
 */
LRESULT WINAPI mmioSendMessage16(HMMIO16 hmmio, UINT16 uMessage,
				 LPARAM lParam1, LPARAM lParam2)
{
    struct mmio_thunk*  thunk;

    if ((thunk = MMIO_HasThunk(HMMIO_32(hmmio))))
    {
        MMIOINFO        mmioinfo;
        if (mmioGetInfo(HMMIO_32(hmmio), &mmioinfo, 0) == MMSYSERR_NOERROR)
        {
            return MMIO_Callback3216((SEGPTR)thunk->pfn16, &mmioinfo, uMessage, lParam1, lParam2);
        }
        return MMSYSERR_INVALHANDLE;
    }
    else
    {
        /* FIXME: we need to map lParam1 and lParam2 to 32bit entities */
        return mmioSendMessage(HMMIO_32(hmmio), uMessage, lParam1, lParam2);
    }
}

/**************************************************************************
 * 				mmioDescend	       	[MMSYSTEM.1223]
 */
MMRESULT16 WINAPI mmioDescend16(HMMIO16 hmmio, LPMMCKINFO lpck,
                                const MMCKINFO* lpckParent, UINT16 uFlags)
{
    return mmioDescend(HMMIO_32(hmmio), lpck, lpckParent, uFlags);
}

/**************************************************************************
 * 				mmioAscend     		[MMSYSTEM.1224]
 */
MMRESULT16 WINAPI mmioAscend16(HMMIO16 hmmio, MMCKINFO* lpck, UINT16 uFlags)
{
    return mmioAscend(HMMIO_32(hmmio),lpck,uFlags);
}

/**************************************************************************
 * 				mmioCreateChunk		[MMSYSTEM.1225]
 */
MMRESULT16 WINAPI mmioCreateChunk16(HMMIO16 hmmio, MMCKINFO* lpck, UINT16 uFlags)
{
    return mmioCreateChunk(HMMIO_32(hmmio), lpck, uFlags);
}

/**************************************************************************
 * 				mmioRename     		[MMSYSTEM.1226]
 */
MMRESULT16 WINAPI mmioRename16(LPCSTR szFileName, LPCSTR szNewFileName,
                               MMIOINFO16* lpmmioinfo, DWORD dwRenameFlags)
{
    BOOL        inst = FALSE;
    MMRESULT    ret;
    MMIOINFO    mmioinfo;

    if (lpmmioinfo != NULL && lpmmioinfo->pIOProc != NULL &&
        lpmmioinfo->fccIOProc == 0) {
        FIXME("Can't handle this case yet\n");
        return MMSYSERR_ERROR;
    }

    /* this is a bit hacky, but it'll work if we get a fourCC code or nothing.
     * but a non installed ioproc without a fourcc won't do
     */
    if (lpmmioinfo && lpmmioinfo->fccIOProc && lpmmioinfo->pIOProc) {
        mmioInstallIOProc16(lpmmioinfo->fccIOProc, lpmmioinfo->pIOProc,
                           MMIO_INSTALLPROC);
        inst = TRUE;
    }
    memset(&mmioinfo, 0, sizeof(mmioinfo));
    if (lpmmioinfo)
        mmioinfo.fccIOProc = lpmmioinfo->fccIOProc;
    ret = mmioRenameA(szFileName, szNewFileName, &mmioinfo, dwRenameFlags);
    if (inst) {
        mmioInstallIOProc16(lpmmioinfo->fccIOProc, NULL, MMIO_REMOVEPROC);
    }
    return ret;
}