summaryrefslogtreecommitdiffstats
path: root/private/mvdm/wow16/mmsystem/init.c
blob: e357c8edd4a226a0ba6280268382ef9b68eeaefb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
/*
    init.c

    Level 1 kitchen sink DLL initialisation

    Copyright (c) Microsoft Corporation 1990. All rights reserved

*/
#ifdef DEBUG
#ifndef DEBUG_RETAIL
#define DEBUG_RETAIL
#endif
#endif

#include <windows.h>
#include <mmsysver.h>
#include "mmsystem.h"
#include "mmddk.h"
#include "mmsysi.h"
#include "drvr.h"
#include "thunks.h"


/****************************************************************************

    global data

****************************************************************************/

HINSTANCE ghInst;                     // our module handle


/* -------------------------------------------------------------------------
** Thunking stuff
** -------------------------------------------------------------------------
*/
LPCB32             PASCAL cb32;
LPSOUNDDEVMSGPROC  PASCAL wod32Message;
LPSOUNDDEVMSGPROC  PASCAL wid32Message;
LPSOUNDDEVMSGPROC  PASCAL mod32Message;
LPSOUNDDEVMSGPROC  PASCAL mid32Message;
LPSOUNDDEVMSGPROC  PASCAL aux32Message;
JOYMESSAGEPROC     PASCAL joy32Message;


UINT FAR PASCAL _loadds ThunkInit(void);
static BOOL NEAR PASCAL ThunkTerm( void );

LPSOUNDDEVMSGPROC  PASCAL wodMapper;
LPSOUNDDEVMSGPROC  PASCAL widMapper;


#ifdef DEBUG_RETAIL
BYTE    fIdReverse;                   // reverse wave/midi id's
#endif

PHNDL pHandleList;

#ifdef   DEBUG_RETAIL
extern  int         DebugmciSendCommand;    // in MCI.C
#endif

#ifdef DEBUG
extern  WORD        fDebug;
#endif

/****************************************************************************

    strings

****************************************************************************/

static  SZCODE  szMMWow32[]             = "winmm.dll";
static  SZCODE  szNotifyCB[]             = "NotifyCallbackData";
static  SZCODE  szWodMessage[]          = "wod32Message";
static  SZCODE  szWidMessage[]          = "wid32Message";
static  SZCODE  szModMessage[]          = "mod32Message";
static  SZCODE  szMidMessage[]          = "mid32Message";
static  SZCODE  szAuxMessage[]          = "aux32Message";
static  SZCODE  szTidMessage[]          = "tid32Message";
static  SZCODE  szJoyMessage[]          = "joy32Message";
static  SZCODE  szWaveMapper[]          = "wavemapper";
static  SZCODE  szWodMapper[]           = "wodMessage";
static  SZCODE  szWidMapper[]           = "widMessage";

        SZCODE  szNull[]                = "";
        SZCODE  szSystemIni[]           = "system.ini";
        SZCODE  szDrivers[]             = "Drivers";
        SZCODE  szBoot[]                = "boot";
        SZCODE  szDriverProc[]          = "DriverProc";
        SZCODE  szJoystick[]            = "joystick";
        SZCODE  szJoystickDrv[]         = "joystick.drv";
        SZCODE  szTimerDrv[]            = "timer";

#ifdef DEBUG_RETAIL
        SZCODE  szLibMain[]     = "MMSYSTEM: Win%dp %ls Version"
                                  "%d.%02d MMSystem Version %d.%02d.%03d\r\n";
        SZCODE  szWinDebug[]    = "(Debug)";
        SZCODE  szWinRetail[]   = "(Retail)";
#endif

        SZCODE  szMMSystem[]            = "mmsystem";
        SZCODE  szStackFrames[]         = "StackFrames";
        SZCODE  szStackSize[]           = "StackSize";

#ifdef DEBUG_RETAIL
        SZCODE  szDebugOutput[]         = "DebugOutput";
        SZCODE  szMci[]                 = "mci";
#endif
#ifdef DEBUG
        SZCODE  szDebug[]               = "Debug";
#endif

#ifdef   DEBUG_RETAIL
/*****************************************************************************
 *
 * DebugInit()  - called from init.c!LibMain() to handle any DLL load time
 *                initialization in the DEBUG version
 *
 ****************************************************************************/
static  void NEAR PASCAL
DebugInit(
    void
    )
{
        fDebugOutput = GetPrivateProfileInt(szMMSystem,szDebugOutput,0,szSystemIni);
        DebugmciSendCommand = GetPrivateProfileInt(szMMSystem,szMci,0,szSystemIni);

#ifdef DEBUG
        fDebug = GetPrivateProfileInt(szMMSystem,szDebug,fDebugOutput,szSystemIni);

        if (fDebug && !fDebugOutput)
                fDebug = FALSE;

        if (fDebug) {
            OutputDebugString( "Breaking for debugging\r\n" );
            _asm int 3
        }
#endif
}
#endif   // ifdef DEBUG_RETAIL



/****************************************************************************

    Library initialization code

    libentry took care of calling LibMain() and other things....

****************************************************************************/
int NEAR PASCAL
LibMain(
    HINSTANCE hInstance,
    UINT cbHeap,
    LPSTR lpCmdLine
    )
{

#ifdef DEBUG_RETAIL
    WORD    w;
#endif

    ghInst = hInstance;

    /*
    ** Here we do a global alloc of the Callback data array.  We then
    ** Lock and Page Lock the allocated storage and initialize the storage
    ** to all zeros.  We then call WOW32 passing to it the address of the
    ** Callback data array, which is saved by WOW32.
    */
    hGlobal = GlobalAlloc( GHND, sizeof(CALLBACK_DATA) );
    if ( hGlobal == (HGLOBAL)NULL ) {
        return FALSE;
    }

    vpCallbackData = (VPCALLBACK_DATA)GlobalLock( hGlobal );
    if ( vpCallbackData == NULL ) {
        return FALSE;
    }

    if ( !HugePageLock( vpCallbackData, (DWORD)sizeof(CALLBACK_DATA) ) ) {
        return FALSE;
    }

    /*
    ** Now we create our interrupt callback stacks.
    */
    if ( StackInit() == FALSE ) {
        return FALSE;
    }

    /*
    ** Now we install our interrupt service routine.  InstallInterruptHandler
    ** return FALSE if it couldn't set the interrupt vector.  If this is the
    ** case we have to terminate the load of the dll.
    */
    if ( InstallInterruptHandler() == FALSE ) {
        return FALSE;
    }


#ifdef DEBUG_RETAIL
    DebugInit();
    w = (WORD)GetVersion();
#endif

    DPRINTF(( szLibMain, WinFlags & WF_WIN386 ? 386 : 286,
        (LPSTR)(GetSystemMetrics(SM_DEBUG) ? szWinDebug : szWinRetail),
        LOBYTE(w), HIBYTE(w),
        HIBYTE(mmsystemGetVersion()), LOBYTE(mmsystemGetVersion()),
        MMSYSRELEASE ));

#ifdef DEBUG
    DPRINTF(("MMSYSTEM: NumTasks: %d\r\n", GetNumTasks()));
    //
    // 3.0 - MMSYSTEM must be loaded by MMSOUND (ie at boot time)
    // check for this and fail to load otherwise.
    //
    // the real reason we need loaded at boot time is so we can get
    // in the enable/disable chain.
    //
    if (GetNumTasks() > 1)
    {
        DOUT("MMSYSTEM: ***!!! Not correctly installed !!!***\r\n");
////////return FALSE;   -Dont fail loading, just don't Enable()
    }
#endif

#ifdef DEBUG_RETAIL
    //
    // fIdReverse being TRUE causes mmsystem to reverse all wave/midi
    // logical device id's.
    //
    // this prevents apps/drivers assuming a driver load order.
    //
    // see wave.c!MapWaveId() and midi.c!MapId()
    //

    fIdReverse = LOBYTE(LOWORD(GetCurrentTime())) & (BYTE)0x01;

    if (fIdReverse)
        ROUT("MMSYSTEM: wave/midi driver id's will be inverted");
#endif

    //
    // do a LoadLibrary() on ourself
    //
    LoadLibrary(szMMSystem);

    return TRUE;
}

/****************************************************************************

    DrvFree - Handler for a DRV_FREE driver message

****************************************************************************/
void FAR PASCAL
DrvFree(
    void
    )
{
    MCITerminate();     // mci.c    free heap
    WndTerminate();     // mmwnd.c  destroy window, unregister class
    if ( mmwow32Lib != 0L ) {
        ThunkTerm();
    }
}


/****************************************************************************

    DrvLoad - handler for a DRV_LOAD driver message

****************************************************************************/
BOOL FAR PASCAL DrvLoad(void)
{

/*
**  The VFW1.1 wave mapper was GP faulting in Daytona when running dangerous
**  creatures videos.  Since it was trying to load an invalid selector in
**  its callback routine it's doubtful we can ever enable them.
**
*/
#if 0 // The wave mappers were GP faulting in Daytona so NOOP for now

    HDRVR   h;


    /* The wave mapper.
     *
     * MMSYSTEM allows the user to install a special wave driver which is
     * not visible to the application as a physical device (it is not
     * included in the number returned from getnumdevs).
     *
     * An application opens the wave mapper when it does not care which
     * physical device is used to input or output waveform data. Thus
     * it is the wave mapper's task to select a physical device that can
     * render the application-specified waveform format or to convert the
     * data into a format that is renderable by an available physical
     * device.
     */

    if (h = mmDrvOpen(szWaveMapper))
    {
        mmDrvInstall(h, &wodMapper, MMDRVI_MAPPER|MMDRVI_WAVEOUT|MMDRVI_HDRV);
        /* open again to get usage count in DLL correct */
        h = mmDrvOpen(szWaveMapper);
        mmDrvInstall(h, &widMapper, MMDRVI_MAPPER|MMDRVI_WAVEIN |MMDRVI_HDRV);
    }
#endif // NOOP wave mapper


    if ( TimeInit() && WndInit() ) {
        return TRUE;
    }

    //
    // something failed, backout the changes
    //
    DrvFree();
    return FALSE;
}

/******************************Public*Routine******************************\
* StackInit
*
*
*
* History:
* dd-mm-93 - StephenE - Created
*
\**************************************************************************/
BOOL FAR PASCAL
StackInit(
    void
    )
{
#   define GMEM_STACK_FLAGS        (GMEM_FIXED | GMEM_SHARE)
#   define DEF_STACK_SIZE          0x600           // 1.5k
#   define DEF_STACK_FRAMES        3
#   define MIN_STACK_SIZE          64
#   define MIN_STACK_FRAMES        1

    DWORD   dwStackBytes;
    WORD    wStackFrames;

    //
    //  The original Window 3.1 code didn't create stack frames for the
    //  Windows Enchanced mode.  However, WOW only emulates standard mode so
    //  I won't bother with this distinction.
    //
    //  if (WinFlags & WF_ENHANCED)
    //      return TRUE;
    //

    /* read stackframes and stacksize from system.ini */
    gwStackSize = GetPrivateProfileInt( szMMSystem, szStackSize,
                                        DEF_STACK_SIZE, szSystemIni );

    /* make sure value isn't something stupid */
    if ( gwStackSize < DEF_STACK_SIZE ) {
        gwStackSize = DEF_STACK_SIZE;
    }

    wStackFrames = GetPrivateProfileInt( szMMSystem, szStackFrames,
                                         DEF_STACK_FRAMES, szSystemIni );

    //
    // Always create at least DEF_STACK_FRAMES stack frames.
    //
    if ( wStackFrames < DEF_STACK_FRAMES ) {
        wStackFrames = DEF_STACK_FRAMES;
    }

    gwStackFrames = wStackFrames;

    /* round to nearest number of WORDs */
    gwStackSize = (gwStackSize + 1) & ~1;

    dwStackBytes = (DWORD)gwStackSize * (DWORD)gwStackFrames;

    /* try to alloc memory */
    if ( dwStackBytes >= 0x10000 ||
       !(gwStackSelector = GlobalAlloc(GMEM_STACK_FLAGS, dwStackBytes)) )
    {
        gwStackFrames = DEF_STACK_FRAMES;
        gwStackSize   = DEF_STACK_SIZE;

        /* do as little at runtime as possible.. */
        dwStackBytes = (DWORD)(DEF_STACK_FRAMES * DEF_STACK_SIZE);

        /* try allocating defaults--if this fails, we are HOSED! */
        gwStackSelector = GlobalAlloc( GMEM_STACK_FLAGS, dwStackBytes );
    }

    /*
    ** set to first available stack
    */
    gwStackUse = (WORD)dwStackBytes;


    /*
    ** did we get memory for stacks??
    */
    if ( !gwStackSelector ) {

        /*
        ** no stacks available... as if we have a chance of survival!
        */

        gwStackUse = 0;
        return FALSE;
    }

    /* looks good... */
    return TRUE;
}


/*****************************Private*Routine******************************\
* StackInit
*
*
*
* History:
* dd-mm-93 - StephenE - Created
*
\**************************************************************************/
BOOL NEAR PASCAL
StackTerminate(
    void
    )
{
    if ( gwStackSelector )
    {
        DOUT("MMSTACKS: Freeing stacks\r\n");

        gwStackSelector = GlobalFree( gwStackSelector );

        if ( gwStackSelector )
            DOUT("MMSTACKS: GlobalFree failed!\r\n");
    }

    /* return the outcome... non-zero is bad */
    return ( (BOOL)gwStackSelector );
} /* StackTerminate() */


/*****************************************************************************
 * @doc EXTERNAL MMSYSTEM
 *
 * @api WORD | mmsystemGetVersion | This function returns the current
 * version number of the Multimedia extensions system software.
 *
 * @rdesc The return value specifies the major and minor version numbers of
 * the Multimedia extensions.  The high-order byte specifies the major
 * version number.  The low-order byte specifies the minor version number.
 *
 ****************************************************************************/
WORD WINAPI mmsystemGetVersion(void)
{
    return(MMSYSTEM_VERSION);
}


/*****************************************************************************
 *
 * @doc   INTERNAL
 *
 * @api   BOOL | DrvTerminate | This function cleans up the installable
 *        driver interface.
 *
 ****************************************************************************/
static void NEAR PASCAL DrvTerminate(void)
{
// don't know about system exit dll order - so do nothing.
}


/*****************************************************************************
 * @doc INTERNAL
 *
 * @api BOOL | mmDrvInstall | This function installs a WAVE driver
 *
 * @parm HANDLE | hDriver | Module handle or driver handle containing driver
 *
 * @parm DRIVERMSGPROC | drvMessage | driver message procedure, if NULL
 *      the standard name will be used (looked for with GetProcAddress)
 *
 * @parm UINT | wFlags | flags
 *
 *      @flag MMDRVI_TYPE      | driver type mask
 *      @flag MMDRVI_WAVEIN    | install driver as a wave input  driver
 *      @flag MMDRVI_WAVEOUT   | install driver as a wave ouput  driver
 *
 *      @flag MMDRVI_MAPPER    | install this driver as the mapper
 *      @flag MMDRVI_HDRV      | hDriver is a installable driver
 *
 *  @rdesc  returns NULL if unable to install driver
 *
 ****************************************************************************/
BOOL WINAPI
mmDrvInstall(
    HANDLE hDriver,
    DRIVERMSGPROC *drvMessage,
    UINT wFlags
    )
{
    DWORD       dw;
    HINSTANCE   hModule;
    UINT        msg_num_devs;
    SZCODE      *szMessage;

    hModule = GetDriverModuleHandle((HDRVR)hDriver);

    switch (wFlags & MMDRVI_TYPE)
    {
        case MMDRVI_WAVEOUT:
            msg_num_devs = WODM_GETNUMDEVS;
            szMessage    = szWodMapper;
            break;

        case MMDRVI_WAVEIN:
            msg_num_devs = WIDM_GETNUMDEVS;
            szMessage    = szWidMapper;
            break;

        default:
            goto error_exit;
    }

    if (hModule != NULL)
        *drvMessage = (DRIVERMSGPROC)GetProcAddress(hModule, szMessage);

    if (*drvMessage == NULL)
        goto error_exit;

    //
    // send the init message, if the driver returns a error, should we
    // unload them???
    //
    dw = (*(*drvMessage))(0,DRVM_INIT,0L,0L,0L);

    //
    // call driver to get num-devices it supports
    //
    dw = (*(*drvMessage))(0,msg_num_devs,0L,0L,0L);

    //
    //  the device returned a error, or has no devices
    //
    if (HIWORD(dw) != 0)
        goto error_exit;

    return TRUE;

error_exit:
    if (hDriver)
        CloseDriver(hDriver, 0, 0);

    return FALSE;
}


/*****************************************************************************
 *
 * @doc   INTERNAL
 *
 * @api   HDRVR | mmDrvOpen | This function load's an installable driver, but
 *                 first checks weather it exists in the [Drivers] section.
 *
 * @parm LPSTR | szAlias | driver alias to load
 *
 * @rdesc The return value is return value from OpenDriver or NULL if the alias
 *        was not found in the [Drivers] section.
 *
 ****************************************************************************/
HDRVR NEAR PASCAL
mmDrvOpen(
    LPSTR szAlias
    )
{
    char buf[3];

    if (GetPrivateProfileString( szDrivers,szAlias,szNull,buf,
                                 sizeof(buf),szSystemIni )) {

        return OpenDriver(szAlias, NULL, 0L);
    }
    else {
        return NULL;
    }
}

/*****************************Private*Routine******************************\
* ThunkInit
*
* Tries to setup the thunking system.  If this can not be performed
* it returns an error code of MMSYSERR_NODRIVER.  Otherwise it returns
* MMSYSERR_NOERROR to indicate sucess.
*
* History:
* dd-mm-93 - StephenE - Created
*
\**************************************************************************/
UINT FAR PASCAL _loadds
ThunkInit(
    void
    )
{
    mmwow32Lib = LoadLibraryEx32W( szMMWow32, NULL, 0L );
    if ( mmwow32Lib == 0L ) {
        return MMSYSERR_NODRIVER;
    }
    cb32 = (LPCB32)GetProcAddress32W(mmwow32Lib, szNotifyCB );

    /*
    ** Now we notify WOW32 that all is OK by passing the 16:16 bit pointer
    ** to the CALLBACK_DATA to it.
    */
    Notify_Callback_Data( vpCallbackData );

    /*
    ** Now initialize the rest of the thuynking system
    */
    wod32Message = (LPSOUNDDEVMSGPROC)GetProcAddress32W( mmwow32Lib, szWodMessage );
    wid32Message = (LPSOUNDDEVMSGPROC)GetProcAddress32W( mmwow32Lib, szWidMessage );
    mod32Message = (LPSOUNDDEVMSGPROC)GetProcAddress32W( mmwow32Lib, szModMessage );
    mid32Message = (LPSOUNDDEVMSGPROC)GetProcAddress32W( mmwow32Lib, szMidMessage );
    aux32Message = (LPSOUNDDEVMSGPROC)GetProcAddress32W( mmwow32Lib, szAuxMessage );
    mci32Message = (LPMCIMESSAGE)GetProcAddress32W( mmwow32Lib, "mci32Message" );
    tid32Message = (TIDMESSAGEPROC)GetProcAddress32W( mmwow32Lib, szTidMessage );
    joy32Message = (JOYMESSAGEPROC)GetProcAddress32W( mmwow32Lib, szJoyMessage );

    return MMSYSERR_NOERROR;
}

/*****************************Private*Routine******************************\
* ThunkTerm
*
*
*
* History:
* dd-mm-93 - StephenE - Created
*
\**************************************************************************/
static BOOL NEAR PASCAL
ThunkTerm(
    void
    )
{
    /*
    ** Free the interrupt stack frames and  uninstall the interrupt handler.
    */
    StackTerminate();
    DeInstallInterruptHandler();

    /*
    ** Next we notify WOW32 that we are going away by passing NULL to
    ** Notify_Callback_Data, then free the storage.
    */
    Notify_Callback_Data( NULL );
    HugePageUnlock( vpCallbackData, (DWORD)sizeof(CALLBACK_DATA) );
    GlobalUnlock( hGlobal );
    GlobalFree( hGlobal );

    return 1;
}