2 * MMSYSTEM mmio* functions
4 * Copyright 1993 Martin Ayotte
5 * 1998-2003,2009 Eric Pouech
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #define NONAMELESSUNION
26 #define NONAMELESSSTRUCT
34 #include "wine/winuser16.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(mmsys);
41 /* ###################################################
43 * ###################################################
46 #define MMIO_MAX_THUNKS 32
48 static struct mmio_thunk
50 BYTE popl_eax; /* popl %eax (return address) */
51 BYTE pushl_func; /* pushl $pfn16 (16bit callback function) */
53 BYTE pushl_eax; /* pushl %eax */
54 BYTE jmp; /* ljmp MMIO_Callback1632 */
56 HMMIO hMmio; /* Handle to 32bit mmio object */
57 SEGPTR segbuffer; /* actual segmented ptr to buffer */
62 static CRITICAL_SECTION mmio_cs;
63 static CRITICAL_SECTION_DEBUG mmio_critsect_debug =
66 { &mmio_critsect_debug.ProcessLocksList, &mmio_critsect_debug.ProcessLocksList },
67 0, 0, { (DWORD_PTR)(__FILE__ ": mmsystem_mmio_cs") }
69 static CRITICAL_SECTION mmio_cs = { &mmio_critsect_debug, -1, 0, 0, 0, 0 };
71 /****************************************************************
72 * MMIO_Map32To16 [INTERNAL]
74 static LRESULT MMIO_Map32To16(DWORD wMsg, LPARAM* lp1, LPARAM* lp2)
84 case MMIOM_WRITEFLUSH:
85 *lp1 = MapLS( (void *)*lp1 );
88 *lp1 = MapLS( (void *)*lp1 );
89 *lp2 = MapLS( (void *)*lp2 );
92 if (wMsg < MMIOM_USER)
93 TRACE("Not a mappable message (%d)\n", wMsg);
95 return MMSYSERR_NOERROR;
98 /****************************************************************
99 * MMIO_UnMap32To16 [INTERNAL]
101 static LRESULT MMIO_UnMap32To16(DWORD wMsg, LPARAM lParam1, LPARAM lParam2,
102 LPARAM lp1, LPARAM lp2)
112 case MMIOM_WRITEFLUSH:
120 if (wMsg < MMIOM_USER)
121 TRACE("Not a mappable message (%d)\n", wMsg);
123 return MMSYSERR_NOERROR;
126 /******************************************************************
131 static LRESULT MMIO_Callback3216(SEGPTR cb16, LPMMIOINFO lpmmioinfo, UINT uMessage,
132 LPARAM lParam1, LPARAM lParam2)
135 MMIOINFO16 mmioInfo16;
136 SEGPTR segmmioInfo16;
137 LPARAM lp1 = lParam1, lp2 = lParam2;
140 if (!cb16) return MMSYSERR_INVALPARAM;
142 memset(&mmioInfo16, 0, sizeof(MMIOINFO16));
143 mmioInfo16.lDiskOffset = lpmmioinfo->lDiskOffset;
144 mmioInfo16.adwInfo[0] = lpmmioinfo->adwInfo[0];
145 mmioInfo16.adwInfo[1] = lpmmioinfo->adwInfo[1];
146 mmioInfo16.adwInfo[2] = lpmmioinfo->adwInfo[2];
147 /* map (lParam1, lParam2) into (lp1, lp2) 32=>16 */
148 if ((result = MMIO_Map32To16(uMessage, &lp1, &lp2)) != MMSYSERR_NOERROR)
151 segmmioInfo16 = MapLS(&mmioInfo16);
152 args[6] = HIWORD(segmmioInfo16);
153 args[5] = LOWORD(segmmioInfo16);
155 args[3] = HIWORD(lp1);
156 args[2] = LOWORD(lp1);
157 args[1] = HIWORD(lp2);
158 args[0] = LOWORD(lp2);
159 WOWCallback16Ex( cb16, WCB16_PASCAL, sizeof(args), args, &result );
160 UnMapLS(segmmioInfo16);
161 MMIO_UnMap32To16(uMessage, lParam1, lParam2, lp1, lp2);
163 lpmmioinfo->lDiskOffset = mmioInfo16.lDiskOffset;
164 lpmmioinfo->adwInfo[0] = mmioInfo16.adwInfo[0];
165 lpmmioinfo->adwInfo[1] = mmioInfo16.adwInfo[1];
166 lpmmioinfo->adwInfo[2] = mmioInfo16.adwInfo[2];
171 /******************************************************************
175 static struct mmio_thunk* MMIO_AddThunk(LPMMIOPROC16 pfn16, HPSTR segbuf)
177 struct mmio_thunk* thunk;
181 MMIO_Thunks = VirtualAlloc(NULL, MMIO_MAX_THUNKS * sizeof(*MMIO_Thunks), MEM_COMMIT,
182 PAGE_EXECUTE_READWRITE);
183 if (!MMIO_Thunks) return NULL;
184 for (thunk = MMIO_Thunks; thunk < &MMIO_Thunks[MMIO_MAX_THUNKS]; thunk++)
186 thunk->popl_eax = 0x58; /* popl %eax */
187 thunk->pushl_func = 0x68; /* pushl $pfn16 */
189 thunk->pushl_eax = 0x50; /* pushl %eax */
190 thunk->jmp = 0xe9; /* jmp MMIO_Callback3216 */
191 thunk->callback = (char *)MMIO_Callback3216 - (char *)(&thunk->callback + 1);
193 thunk->segbuffer = 0;
196 for (thunk = MMIO_Thunks; thunk < &MMIO_Thunks[MMIO_MAX_THUNKS]; thunk++)
198 if (thunk->pfn16 == 0 && thunk->hMmio == NULL)
200 thunk->pfn16 = pfn16;
202 thunk->segbuffer = (SEGPTR)segbuf;
206 FIXME("Out of mmio-thunks. Bump MMIO_MAX_THUNKS\n");
210 /******************************************************************
214 static struct mmio_thunk* MMIO_HasThunk(HMMIO hmmio)
216 struct mmio_thunk* thunk;
218 if (!MMIO_Thunks) return NULL;
219 for (thunk = MMIO_Thunks; thunk < &MMIO_Thunks[MMIO_MAX_THUNKS]; thunk++)
221 if (thunk->hMmio == hmmio) return thunk;
226 /******************************************************************
227 * MMIO_SetSegmentedBuffer
230 static void MMIO_SetSegmentedBuffer(struct mmio_thunk* thunk, SEGPTR ptr, BOOL release)
232 if (release) UnMapLS(thunk->segbuffer);
233 thunk->segbuffer = ptr;
236 /**************************************************************************
237 * mmioOpen [MMSYSTEM.1210]
239 HMMIO16 WINAPI mmioOpen16(LPSTR szFileName, MMIOINFO16* lpmmioinfo16,
246 struct mmio_thunk* thunk = NULL;
248 memset(&mmioinfo, 0, sizeof(mmioinfo));
250 EnterCriticalSection(&mmio_cs);
251 if (!(thunk = MMIO_AddThunk(lpmmioinfo16->pIOProc, lpmmioinfo16->pchBuffer)))
253 LeaveCriticalSection(&mmio_cs);
257 mmioinfo.dwFlags = lpmmioinfo16->dwFlags;
258 mmioinfo.fccIOProc = lpmmioinfo16->fccIOProc;
259 mmioinfo.pIOProc = lpmmioinfo16->pIOProc ? (LPMMIOPROC)thunk : 0;
260 mmioinfo.cchBuffer = lpmmioinfo16->cchBuffer;
261 mmioinfo.pchBuffer = MapSL((DWORD)lpmmioinfo16->pchBuffer);
262 mmioinfo.adwInfo[0] = lpmmioinfo16->adwInfo[0];
263 /* if we don't have a file name, it's likely a passed open file descriptor */
265 mmioinfo.adwInfo[0] = (DWORD)DosFileHandleToWin32Handle(mmioinfo.adwInfo[0]);
266 mmioinfo.adwInfo[1] = lpmmioinfo16->adwInfo[1];
267 mmioinfo.adwInfo[2] = lpmmioinfo16->adwInfo[2];
269 ret = mmioOpenA(szFileName, &mmioinfo, dwOpenFlags);
270 if (!ret || (dwOpenFlags & (MMIO_PARSE|MMIO_EXIST)))
275 else thunk->hMmio = ret;
276 if (ret && (dwOpenFlags & MMIO_ALLOCBUF))
279 if (lpmmioinfo16->pchBuffer) FIXME("ooch\n");
280 /* FIXME: check whether mmioOpen should set pchBuffer */
281 mmioGetInfo(ret, &m, 0);
282 thunk->segbuffer = MapLS(m.pchBuffer);
284 LeaveCriticalSection(&mmio_cs);
286 lpmmioinfo16->wErrorRet = mmioinfo.wErrorRet;
287 lpmmioinfo16->hmmio = HMMIO_16(mmioinfo.hmmio);
289 ret = mmioOpenA(szFileName, NULL, dwOpenFlags);
291 return HMMIO_16(ret);
294 /**************************************************************************
295 * mmioClose [MMSYSTEM.1211]
297 MMRESULT16 WINAPI mmioClose16(HMMIO16 hmmio, UINT16 uFlags)
301 EnterCriticalSection(&mmio_cs);
302 ret = mmioClose(HMMIO_32(hmmio), uFlags);
303 if (ret == MMSYSERR_NOERROR)
305 struct mmio_thunk* thunk;
307 if ((thunk = MMIO_HasThunk(HMMIO_32(hmmio))))
309 MMIO_SetSegmentedBuffer(thunk, 0, TRUE);
314 LeaveCriticalSection(&mmio_cs);
318 /**************************************************************************
319 * mmioRead [MMSYSTEM.1212]
321 LONG WINAPI mmioRead16(HMMIO16 hmmio, HPSTR pch, LONG cch)
323 return mmioRead(HMMIO_32(hmmio), pch, cch);
326 /**************************************************************************
327 * mmioWrite [MMSYSTEM.1213]
329 LONG WINAPI mmioWrite16(HMMIO16 hmmio, HPCSTR pch, LONG cch)
331 return mmioWrite(HMMIO_32(hmmio),pch,cch);
334 /**************************************************************************
335 * mmioSeek [MMSYSTEM.1214]
337 LONG WINAPI mmioSeek16(HMMIO16 hmmio, LONG lOffset, INT16 iOrigin)
339 return mmioSeek(HMMIO_32(hmmio), lOffset, iOrigin);
342 /**************************************************************************
343 * mmioGetInfo [MMSYSTEM.1215]
345 MMRESULT16 WINAPI mmioGetInfo16(HMMIO16 hmmio, MMIOINFO16* lpmmioinfo, UINT16 uFlags)
349 struct mmio_thunk* thunk;
351 TRACE("(0x%04x,%p,0x%08x)\n", hmmio, lpmmioinfo, uFlags);
353 EnterCriticalSection(&mmio_cs);
354 if ((thunk = MMIO_HasThunk(HMMIO_32(hmmio))) == NULL)
356 LeaveCriticalSection(&mmio_cs);
357 return MMSYSERR_INVALHANDLE;
360 ret = mmioGetInfo(HMMIO_32(hmmio), &mmioinfo, uFlags);
361 if (ret != MMSYSERR_NOERROR)
363 LeaveCriticalSection(&mmio_cs);
367 lpmmioinfo->dwFlags = mmioinfo.dwFlags;
368 lpmmioinfo->fccIOProc = mmioinfo.fccIOProc;
369 lpmmioinfo->pIOProc = thunk->pfn16;
370 lpmmioinfo->wErrorRet = mmioinfo.wErrorRet;
371 lpmmioinfo->hTask = HTASK_16(mmioinfo.hTask);
372 lpmmioinfo->cchBuffer = mmioinfo.cchBuffer;
373 lpmmioinfo->pchBuffer = (void*)thunk->segbuffer;
374 lpmmioinfo->pchNext = (void*)(thunk->segbuffer + (mmioinfo.pchNext - mmioinfo.pchBuffer));
375 lpmmioinfo->pchEndRead = (void*)(thunk->segbuffer + (mmioinfo.pchEndRead - mmioinfo.pchBuffer));
376 lpmmioinfo->pchEndWrite = (void*)(thunk->segbuffer + (mmioinfo.pchEndWrite - mmioinfo.pchBuffer));
377 lpmmioinfo->lBufOffset = mmioinfo.lBufOffset;
378 lpmmioinfo->lDiskOffset = mmioinfo.lDiskOffset;
379 lpmmioinfo->adwInfo[0] = mmioinfo.adwInfo[0];
380 lpmmioinfo->adwInfo[1] = mmioinfo.adwInfo[1];
381 lpmmioinfo->adwInfo[2] = mmioinfo.adwInfo[2];
382 lpmmioinfo->dwReserved1 = 0;
383 lpmmioinfo->dwReserved2 = 0;
384 lpmmioinfo->hmmio = HMMIO_16(mmioinfo.hmmio);
385 LeaveCriticalSection(&mmio_cs);
387 return MMSYSERR_NOERROR;
390 /**************************************************************************
391 * mmioSetInfo [MMSYSTEM.1216]
393 MMRESULT16 WINAPI mmioSetInfo16(HMMIO16 hmmio, const MMIOINFO16* lpmmioinfo, UINT16 uFlags)
398 TRACE("(0x%04x,%p,0x%08x)\n",hmmio,lpmmioinfo,uFlags);
400 ret = mmioGetInfo(HMMIO_32(hmmio), &mmioinfo, 0);
401 if (ret != MMSYSERR_NOERROR) return ret;
403 /* check if seg and lin buffers are the same */
404 if (mmioinfo.cchBuffer != lpmmioinfo->cchBuffer ||
405 mmioinfo.pchBuffer != MapSL((DWORD)lpmmioinfo->pchBuffer))
406 return MMSYSERR_INVALPARAM;
408 /* check pointers coherence */
409 if (lpmmioinfo->pchNext < lpmmioinfo->pchBuffer ||
410 lpmmioinfo->pchNext > lpmmioinfo->pchBuffer + lpmmioinfo->cchBuffer ||
411 lpmmioinfo->pchEndRead < lpmmioinfo->pchBuffer ||
412 lpmmioinfo->pchEndRead > lpmmioinfo->pchBuffer + lpmmioinfo->cchBuffer ||
413 lpmmioinfo->pchEndWrite < lpmmioinfo->pchBuffer ||
414 lpmmioinfo->pchEndWrite > lpmmioinfo->pchBuffer + lpmmioinfo->cchBuffer)
415 return MMSYSERR_INVALPARAM;
417 mmioinfo.pchNext = mmioinfo.pchBuffer + (lpmmioinfo->pchNext - lpmmioinfo->pchBuffer);
418 mmioinfo.pchEndRead = mmioinfo.pchBuffer + (lpmmioinfo->pchEndRead - lpmmioinfo->pchBuffer);
419 mmioinfo.pchEndWrite = mmioinfo.pchBuffer + (lpmmioinfo->pchEndWrite - lpmmioinfo->pchBuffer);
421 return mmioSetInfo(HMMIO_32(hmmio), &mmioinfo, uFlags);
424 /**************************************************************************
425 * mmioSetBuffer [MMSYSTEM.1217]
427 MMRESULT16 WINAPI mmioSetBuffer16(HMMIO16 hmmio, LPSTR pchBuffer,
428 LONG cchBuffer, UINT16 uFlags)
430 MMRESULT ret = mmioSetBuffer(HMMIO_32(hmmio), MapSL((DWORD)pchBuffer),
433 if (ret == MMSYSERR_NOERROR)
435 struct mmio_thunk* thunk;
437 if ((thunk = MMIO_HasThunk(HMMIO_32(hmmio))) == NULL)
440 return MMSYSERR_INVALHANDLE;
442 MMIO_SetSegmentedBuffer(thunk, (DWORD)pchBuffer, TRUE);
445 UnMapLS((DWORD)pchBuffer);
449 /**************************************************************************
450 * mmioFlush [MMSYSTEM.1218]
452 MMRESULT16 WINAPI mmioFlush16(HMMIO16 hmmio, UINT16 uFlags)
454 return mmioFlush(HMMIO_32(hmmio), uFlags);
457 /***********************************************************************
458 * mmioAdvance [MMSYSTEM.1219]
460 MMRESULT16 WINAPI mmioAdvance16(HMMIO16 hmmio, MMIOINFO16* lpmmioinfo, UINT16 uFlags)
465 /* WARNING: this heavily relies on mmioAdvance implementation (for choosing which
470 mmioinfo.pchBuffer = MapSL((DWORD)lpmmioinfo->pchBuffer);
471 mmioinfo.pchNext = MapSL((DWORD)lpmmioinfo->pchNext);
472 mmioinfo.dwFlags = lpmmioinfo->dwFlags;
473 mmioinfo.lBufOffset = lpmmioinfo->lBufOffset;
474 ret = mmioAdvance(HMMIO_32(hmmio), &mmioinfo, uFlags);
477 ret = mmioAdvance(HMMIO_32(hmmio), NULL, uFlags);
479 if (ret != MMSYSERR_NOERROR) return ret;
483 lpmmioinfo->dwFlags = mmioinfo.dwFlags;
484 lpmmioinfo->pchNext = (void*)(lpmmioinfo->pchBuffer + (mmioinfo.pchNext - mmioinfo.pchBuffer));
485 lpmmioinfo->pchEndRead = (void*)(lpmmioinfo->pchBuffer + (mmioinfo.pchEndRead - mmioinfo.pchBuffer));
486 lpmmioinfo->pchEndWrite = (void*)(lpmmioinfo->pchBuffer + (mmioinfo.pchEndWrite - mmioinfo.pchBuffer));
487 lpmmioinfo->lBufOffset = mmioinfo.lBufOffset;
488 lpmmioinfo->lDiskOffset = mmioinfo.lDiskOffset;
491 return MMSYSERR_NOERROR;
494 /**************************************************************************
495 * mmioStringToFOURCC [MMSYSTEM.1220]
497 FOURCC WINAPI mmioStringToFOURCC16(LPCSTR sz, UINT16 uFlags)
499 return mmioStringToFOURCCA(sz, uFlags);
502 /**************************************************************************
503 * mmioInstallIOProc [MMSYSTEM.1221]
505 LPMMIOPROC16 WINAPI mmioInstallIOProc16(FOURCC fccIOProc, LPMMIOPROC16 pIOProc,
508 struct mmio_thunk* thunk = NULL;
509 LPMMIOPROC pIOProc32;
511 EnterCriticalSection(&mmio_cs);
513 switch (dwFlags & (MMIO_INSTALLPROC|MMIO_REMOVEPROC|MMIO_FINDPROC)) {
514 case MMIO_INSTALLPROC:
515 if (!(thunk = MMIO_AddThunk(pIOProc, NULL)))
517 LeaveCriticalSection(&mmio_cs);
520 if (!mmioInstallIOProcA(fccIOProc, (LPMMIOPROC)thunk, dwFlags))
526 case MMIO_REMOVEPROC:
529 for (thunk = MMIO_Thunks; thunk < &MMIO_Thunks[MMIO_MAX_THUNKS]; thunk++)
531 if (thunk->pfn16 == pIOProc && thunk->segbuffer == 0)
533 if (mmioInstallIOProcA(fccIOProc, (LPMMIOPROC)thunk, dwFlags))
541 if (!thunk) pIOProc = NULL;
544 if ((pIOProc32 = mmioInstallIOProcA(fccIOProc, NULL, dwFlags)) && MMIO_Thunks)
546 for (thunk = MMIO_Thunks; thunk < &MMIO_Thunks[MMIO_MAX_THUNKS]; thunk++)
548 if ((LPMMIOPROC)thunk == pIOProc32)
550 pIOProc = thunk->pfn16;
557 WINE_FIXME("Unsupported flags %08x\n", dwFlags);
560 LeaveCriticalSection(&mmio_cs);
565 /**************************************************************************
566 * mmioSendMessage [MMSYSTEM.1222]
568 LRESULT WINAPI mmioSendMessage16(HMMIO16 hmmio, UINT16 uMessage,
569 LPARAM lParam1, LPARAM lParam2)
571 struct mmio_thunk* thunk;
573 if ((thunk = MMIO_HasThunk(HMMIO_32(hmmio))))
576 if (mmioGetInfo(HMMIO_32(hmmio), &mmioinfo, 0) == MMSYSERR_NOERROR)
578 return MMIO_Callback3216((SEGPTR)thunk->pfn16, &mmioinfo, uMessage, lParam1, lParam2);
580 return MMSYSERR_INVALHANDLE;
584 /* FIXME: we need to map lParam1 and lParam2 to 32bit entities */
585 return mmioSendMessage(HMMIO_32(hmmio), uMessage, lParam1, lParam2);
589 /**************************************************************************
590 * mmioDescend [MMSYSTEM.1223]
592 MMRESULT16 WINAPI mmioDescend16(HMMIO16 hmmio, LPMMCKINFO lpck,
593 const MMCKINFO* lpckParent, UINT16 uFlags)
595 return mmioDescend(HMMIO_32(hmmio), lpck, lpckParent, uFlags);
598 /**************************************************************************
599 * mmioAscend [MMSYSTEM.1224]
601 MMRESULT16 WINAPI mmioAscend16(HMMIO16 hmmio, MMCKINFO* lpck, UINT16 uFlags)
603 return mmioAscend(HMMIO_32(hmmio),lpck,uFlags);
606 /**************************************************************************
607 * mmioCreateChunk [MMSYSTEM.1225]
609 MMRESULT16 WINAPI mmioCreateChunk16(HMMIO16 hmmio, MMCKINFO* lpck, UINT16 uFlags)
611 return mmioCreateChunk(HMMIO_32(hmmio), lpck, uFlags);
614 /**************************************************************************
615 * mmioRename [MMSYSTEM.1226]
617 MMRESULT16 WINAPI mmioRename16(LPCSTR szFileName, LPCSTR szNewFileName,
618 MMIOINFO16* lpmmioinfo, DWORD dwRenameFlags)
624 if (lpmmioinfo != NULL && lpmmioinfo->pIOProc != NULL &&
625 lpmmioinfo->fccIOProc == 0) {
626 FIXME("Can't handle this case yet\n");
627 return MMSYSERR_ERROR;
630 /* this is a bit hacky, but it'll work if we get a fourCC code or nothing.
631 * but a non installed ioproc without a fourcc won't do
633 if (lpmmioinfo && lpmmioinfo->fccIOProc && lpmmioinfo->pIOProc) {
634 mmioInstallIOProc16(lpmmioinfo->fccIOProc, lpmmioinfo->pIOProc,
638 memset(&mmioinfo, 0, sizeof(mmioinfo));
640 mmioinfo.fccIOProc = lpmmioinfo->fccIOProc;
641 ret = mmioRenameA(szFileName, szNewFileName, &mmioinfo, dwRenameFlags);
643 mmioInstallIOProc16(lpmmioinfo->fccIOProc, NULL, MMIO_REMOVEPROC);