winealsa: Implement Wow64 midi entry points in the Unix library.

Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Huw Davies 2022-04-22 08:37:58 +01:00 committed by Alexandre Julliard
parent aed23f1928
commit a1fb139fac
3 changed files with 363 additions and 3 deletions

View File

@ -2869,9 +2869,9 @@ unixlib_entry_t __wine_unix_call_wow64_funcs[] =
is_started,
wow64_get_prop_value,
midi_release,
midi_out_message,
midi_in_message,
midi_notify_wait,
wow64_midi_out_message,
wow64_midi_in_message,
wow64_midi_notify_wait,
};
#endif /* _WIN64 */

View File

@ -1499,3 +1499,357 @@ NTSTATUS midi_notify_wait(void *args)
return STATUS_SUCCESS;
}
#ifdef _WIN64
typedef UINT PTR32;
struct notify_context32
{
BOOL send_notify;
WORD dev_id;
WORD msg;
UINT param_1;
UINT param_2;
UINT callback;
UINT flags;
PTR32 device;
UINT instance;
};
static void notify_to_notify32(struct notify_context32 *notify32,
const struct notify_context *notify)
{
notify32->send_notify = notify->send_notify;
notify32->dev_id = notify->dev_id;
notify32->msg = notify->msg;
notify32->param_1 = notify->param_1;
notify32->param_2 = notify->param_2;
notify32->callback = notify->callback;
notify32->flags = notify->flags;
notify32->device = PtrToUlong(notify->device);
notify32->instance = notify->instance;
}
struct midi_open_desc32
{
PTR32 hMidi;
UINT dwCallback;
UINT dwInstance;
UINT dnDevNode;
UINT cIds;
MIDIOPENSTRMID rgIds;
};
struct midi_hdr32
{
PTR32 lpData;
UINT dwBufferLength;
UINT dwBytesRecorded;
UINT dwUser;
UINT dwFlags;
PTR32 lpNext;
UINT reserved;
UINT dwOffset;
UINT dwReserved[8];
};
static UINT wow64_midi_out_prepare(WORD dev_id, struct midi_hdr32 *hdr, UINT hdr_size)
{
TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size);
if (hdr_size < offsetof(struct midi_hdr32, dwOffset) || !hdr || !hdr->lpData)
return MMSYSERR_INVALPARAM;
if (hdr->dwFlags & MHDR_PREPARED)
return MMSYSERR_NOERROR;
hdr->lpNext = 0;
hdr->dwFlags |= MHDR_PREPARED;
hdr->dwFlags &= ~(MHDR_DONE | MHDR_INQUEUE);
return MMSYSERR_NOERROR;
}
static UINT wow64_midi_out_unprepare(WORD dev_id, struct midi_hdr32 *hdr, UINT hdr_size)
{
TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size);
if (hdr_size < offsetof(struct midi_hdr32, dwOffset) || !hdr || !hdr->lpData)
return MMSYSERR_INVALPARAM;
if (!(hdr->dwFlags & MHDR_PREPARED))
return MMSYSERR_NOERROR;
if (hdr->dwFlags & MHDR_INQUEUE)
return MIDIERR_STILLPLAYING;
hdr->dwFlags &= ~MHDR_PREPARED;
return MMSYSERR_NOERROR;
}
NTSTATUS wow64_midi_out_message(void *args)
{
struct
{
UINT dev_id;
UINT msg;
UINT user;
UINT param_1;
UINT param_2;
PTR32 err;
PTR32 notify;
} *params32 = args;
struct notify_context32 *notify32 = ULongToPtr(params32->notify);
struct midi_open_desc32 *desc32;
struct midi_hdr32 *hdr32;
struct notify_context notify;
MIDIOPENDESC open_desc;
MIDIHDR hdr;
struct midi_out_message_params params =
{
.dev_id = params32->dev_id,
.msg = params32->msg,
.user = params32->user,
.param_1 = params32->param_1,
.param_2 = params32->param_2,
.err = ULongToPtr(params32->err),
.notify = &notify
};
notify32->send_notify = FALSE;
switch (params32->msg)
{
case MODM_OPEN:
desc32 = ULongToPtr(params32->param_1);
open_desc.hMidi = ULongToPtr(desc32->hMidi);
open_desc.dwCallback = desc32->dwCallback;
open_desc.dwInstance = desc32->dwInstance;
open_desc.dnDevNode = desc32->dnDevNode;
open_desc.cIds = desc32->cIds;
open_desc.rgIds.dwStreamID = desc32->rgIds.dwStreamID;
open_desc.rgIds.wDeviceID = desc32->rgIds.wDeviceID;
params.param_1 = (UINT_PTR)&open_desc;
break;
case MODM_LONGDATA:
hdr32 = ULongToPtr(params32->param_1);
memset(&hdr, 0, sizeof(hdr));
hdr.lpData = ULongToPtr(hdr32->lpData);
hdr.dwBufferLength = hdr32->dwBufferLength;
hdr.dwFlags = hdr32->dwFlags;
params.param_1 = (UINT_PTR)&hdr;
params.param_2 = sizeof(hdr);
break;
case MODM_PREPARE: /* prepare and unprepare are easier to handle explicitly */
hdr32 = ULongToPtr(params32->param_1);
*params.err = wow64_midi_out_prepare(params32->dev_id, hdr32, params32->param_2);
return STATUS_SUCCESS;
case MODM_UNPREPARE:
hdr32 = ULongToPtr(params32->param_1);
*params.err = wow64_midi_out_unprepare(params32->dev_id, hdr32, params32->param_2);
return STATUS_SUCCESS;
}
midi_out_message(&params);
switch (params32->msg)
{
case MODM_LONGDATA:
hdr32 = ULongToPtr(params32->param_1);
hdr32->dwFlags = hdr.dwFlags;
break;
}
if (notify.send_notify)
{
notify_to_notify32(notify32, &notify);
if (notify.msg == MOM_DONE)
notify32->param_1 = params32->param_1; /* restore the 32-bit hdr */
}
return STATUS_SUCCESS;
}
static UINT wow64_midi_in_prepare(WORD dev_id, struct midi_hdr32 *hdr, UINT hdr_size)
{
TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size);
if (hdr_size < offsetof(struct midi_hdr32, dwOffset) || !hdr || !hdr->lpData)
return MMSYSERR_INVALPARAM;
if (hdr->dwFlags & MHDR_PREPARED)
return MMSYSERR_NOERROR;
hdr->lpNext = 0;
hdr->dwFlags |= MHDR_PREPARED;
hdr->dwFlags &= ~(MHDR_DONE | MHDR_INQUEUE);
return MMSYSERR_NOERROR;
}
static UINT wow64_midi_in_unprepare(WORD dev_id, struct midi_hdr32 *hdr, UINT hdr_size)
{
TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size);
if (hdr_size < offsetof(struct midi_hdr32, dwOffset) || !hdr || !hdr->lpData)
return MMSYSERR_INVALPARAM;
if (!(hdr->dwFlags & MHDR_PREPARED))
return MMSYSERR_NOERROR;
if (hdr->dwFlags & MHDR_INQUEUE)
return MIDIERR_STILLPLAYING;
hdr->dwFlags &= ~MHDR_PREPARED;
return MMSYSERR_NOERROR;
}
NTSTATUS wow64_midi_in_message(void *args)
{
struct
{
UINT dev_id;
UINT msg;
UINT user;
UINT param_1;
UINT param_2;
PTR32 err;
PTR32 notify;
} *params32 = args;
struct notify_context32 *notify32 = ULongToPtr(params32->notify);
struct midi_open_desc32 *desc32;
struct midi_hdr32 *hdr32;
struct notify_context notify;
MIDIOPENDESC open_desc;
MIDIHDR *hdr = NULL;
struct midi_in_message_params params =
{
.dev_id = params32->dev_id,
.msg = params32->msg,
.user = params32->user,
.param_1 = params32->param_1,
.param_2 = params32->param_2,
.err = ULongToPtr(params32->err),
.notify = &notify
};
notify32->send_notify = FALSE;
switch (params32->msg)
{
case MIDM_OPEN:
desc32 = ULongToPtr(params32->param_1);
open_desc.hMidi = ULongToPtr(desc32->hMidi);
open_desc.dwCallback = desc32->dwCallback;
open_desc.dwInstance = desc32->dwInstance;
open_desc.dnDevNode = desc32->dnDevNode;
open_desc.cIds = desc32->cIds;
open_desc.rgIds.dwStreamID = desc32->rgIds.dwStreamID;
open_desc.rgIds.wDeviceID = desc32->rgIds.wDeviceID;
params.param_1 = (UINT_PTR)&open_desc;
break;
case MIDM_ADDBUFFER:
hdr32 = ULongToPtr(params32->param_1);
hdr = calloc(1, sizeof(*hdr));
hdr->lpData = ULongToPtr(hdr32->lpData);
hdr->dwBufferLength = hdr32->dwBufferLength;
hdr->dwFlags = hdr32->dwFlags;
hdr->dwReserved[7] = params32->param_1; /* keep hdr32 for MIM_LONGDATA notification */
params.param_1 = (UINT_PTR)hdr;
params.param_2 = sizeof(*hdr);
break;
case MIDM_PREPARE: /* prepare and unprepare are easier to handle explicitly */
hdr32 = ULongToPtr(params32->param_1);
*params.err = wow64_midi_in_prepare(params32->dev_id, hdr32, params32->param_2);
return STATUS_SUCCESS;
case MIDM_UNPREPARE:
hdr32 = ULongToPtr(params32->param_1);
*params.err = wow64_midi_in_unprepare(params32->dev_id, hdr32, params32->param_2);
return STATUS_SUCCESS;
}
midi_in_message(&params);
switch (params32->msg)
{
case MIDM_ADDBUFFER:
hdr32 = ULongToPtr(params32->param_1);
if (!*params.err)
{
hdr32->dwFlags = hdr->dwFlags;
hdr32->dwBytesRecorded = hdr->dwBytesRecorded;
hdr32->lpNext = 0;
}
else
free(hdr);
break;
}
if (notify.send_notify)
{
notify_to_notify32(notify32, &notify);
if (notify.msg == MIM_LONGDATA)
{
hdr = (MIDIHDR *)notify.param_1;
notify32->param_1 = hdr->dwReserved[7];
hdr32 = ULongToPtr(notify32->param_1);
hdr32->dwBytesRecorded = hdr->dwBytesRecorded;
hdr32->dwFlags = hdr->dwFlags;
free(hdr);
}
}
return STATUS_SUCCESS;
}
NTSTATUS wow64_midi_notify_wait(void *args)
{
struct
{
PTR32 quit;
PTR32 notify;
} *params32 = args;
struct notify_context32 *notify32 = ULongToPtr(params32->notify);
struct midi_hdr32 *hdr32;
struct notify_context notify;
MIDIHDR *hdr;
struct midi_notify_wait_params params =
{
.quit = ULongToPtr(params32->quit),
.notify = &notify
};
notify32->send_notify = FALSE;
midi_notify_wait(&params);
if (!*params.quit && notify.send_notify)
{
notify_to_notify32(notify32, &notify);
if (notify.msg == MIM_LONGDATA)
{
hdr = (MIDIHDR *)notify.param_1;
notify32->param_1 = hdr->dwReserved[7];
hdr32 = ULongToPtr(notify32->param_1);
hdr32->dwBytesRecorded = hdr->dwBytesRecorded;
hdr32->dwFlags = hdr->dwFlags;
free(hdr);
}
}
return STATUS_SUCCESS;
}
#endif /* _WIN64 */

View File

@ -284,6 +284,12 @@ NTSTATUS midi_out_message(void *args) DECLSPEC_HIDDEN;
NTSTATUS midi_in_message(void *args) DECLSPEC_HIDDEN;
NTSTATUS midi_notify_wait(void *args) DECLSPEC_HIDDEN;
#ifdef _WIN64
NTSTATUS wow64_midi_out_message(void *args) DECLSPEC_HIDDEN;
NTSTATUS wow64_midi_in_message(void *args) DECLSPEC_HIDDEN;
NTSTATUS wow64_midi_notify_wait(void *args) DECLSPEC_HIDDEN;
#endif
extern unixlib_handle_t alsa_handle;
#define ALSA_CALL(func, params) __wine_unix_call(alsa_handle, alsa_ ## func, params)