update for HEAD-2003091401
[reactos.git] / lib / winmm / lolvldrv.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2
3 /*
4  * MMSYTEM low level drivers handling functions
5  *
6  * Copyright 1999 Eric Pouech
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23
24 #ifdef __WINE_FOR_REACTOS__
25
26 #define __WINESRC__
27 #include <windows.h>
28 typedef UINT *LPUINT;
29 #include "internal.h"
30
31 #else
32
33 #include "winreg.h"
34 #include "winver.h"
35 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(winmm);
37
38 #endif
39
40 #include <string.h>
41 #include <stdio.h>
42 #include <assert.h>
43 #include "winemm.h"
44 #include <mmddk.h>
45
46
47 #ifdef __WINE_FOR_REACTOS__
48 #define HFILE_ERROR     ((HFILE)-1)
49 typedef DWORD (*LPGetFileVersionInfoSizeA)(LPSTR lptstrFilename, LPDWORD lpdwHandle);
50 typedef BOOL (*LPGetFileVersionInfoA)(LPSTR lptstrFilename, DWORD dwHandle,
51                                         DWORD dwLen, LPVOID lpData);
52 typedef BOOL (*LPVerQueryValueA)(const LPVOID pBlock, LPSTR lpSubBlock,
53                                 LPVOID *lplpBuffer, PUINT puLen);
54 #else
55 typedef FARPROC LPGetFileVersionInfoSizeA;
56 typedef FARPROC LPGetFileVersionInfoA;
57 typedef FARPROC LPVerQueryValueA;
58 #endif
59
60
61 LRESULT         (*pFnCallMMDrvFunc16)(FARPROC16,WORD,WORD,LONG,LONG,LONG) /* = NULL */;
62 unsigned        (*pFnLoadMMDrvFunc16)(LPCSTR,LPWINE_DRIVER, LPWINE_MM_DRIVER) /* = NULL */;
63
64 /* each known type of driver has an instance of this structure */
65 typedef struct tagWINE_LLTYPE {
66     /* those attributes depend on the specification of the type */
67     LPSTR               typestr;        /* name (for debugging) */
68     BOOL                bSupportMapper; /* if type is allowed to support mapper */
69     MMDRV_MAPFUNC       Map16To32A;     /* those are function pointers to handle */
70     MMDRV_UNMAPFUNC     UnMap16To32A;   /*   the parameter conversion (16 vs 32 bit) */
71     MMDRV_MAPFUNC       Map32ATo16;     /*   when hi-func (in mmsystem or winmm) and */
72     MMDRV_UNMAPFUNC     UnMap32ATo16;   /*   low-func (in .drv) do not match */
73     LPDRVCALLBACK       Callback;       /* handles callback for a specified type */
74     /* those attributes reflect the loaded/current situation for the type */
75     UINT                wMaxId;         /* number of loaded devices (sum across all loaded drivers */
76     LPWINE_MLD          lpMlds;         /* "static" mlds to access the part though device IDs */
77     int                 nMapper;        /* index to mapper */
78 } WINE_LLTYPE;
79
80 static int              MMDrvsHi /* = 0 */;
81 static WINE_MM_DRIVER   MMDrvs[3];
82 static LPWINE_MLD       MM_MLDrvs[40];
83 #define MAX_MM_MLDRVS   (sizeof(MM_MLDrvs) / sizeof(MM_MLDrvs[0]))
84
85 #define A(_x,_y) {#_y, _x, NULL, NULL, NULL, NULL, NULL, 0, NULL, -1}
86 /* Note: the indices of this array must match the definitions
87  *       of the MMDRV_???? manifest constants
88  */
89 static WINE_LLTYPE      llTypes[MMDRV_MAX] = {
90     A(TRUE,  Aux),
91     A(FALSE, Mixer),
92     A(TRUE,  MidiIn),
93     A(TRUE,  MidiOut),
94     A(TRUE,  WaveIn),
95     A(TRUE,  WaveOut),
96 };
97 #undef A
98
99 /******************************************************************
100  *              MMDRV_InstallMap
101  *
102  *
103  */
104 void    MMDRV_InstallMap(unsigned int drv, 
105                          MMDRV_MAPFUNC mp1632, MMDRV_UNMAPFUNC um1632,
106                          MMDRV_MAPFUNC mp3216, MMDRV_UNMAPFUNC um3216,
107                          LPDRVCALLBACK cb)
108 {
109     assert(drv < MMDRV_MAX);
110     llTypes[drv].Map16To32A   = mp1632;
111     llTypes[drv].UnMap16To32A = um1632;
112     llTypes[drv].Map32ATo16   = mp3216;
113     llTypes[drv].UnMap32ATo16 = um1632;
114     llTypes[drv].Callback     = cb;
115 }
116
117 /******************************************************************
118  *              MMDRV_Is32
119  *
120  */
121 BOOL            MMDRV_Is32(unsigned int idx)
122 {
123     return MMDrvs[idx].bIs32;
124 }
125
126 /**************************************************************************
127  *                              MMDRV_GetDescription32          [internal]
128  */
129 static  BOOL    MMDRV_GetDescription32(const char* fname, char* buf, int buflen)
130 {
131     OFSTRUCT    ofs;
132     DWORD       h;
133     LPVOID      ptr = 0;
134     LPVOID      val;
135     DWORD       dw;
136     BOOL        ret = FALSE;
137     UINT        u;
138     LPGetFileVersionInfoSizeA pGetFileVersionInfoSizeA;
139     LPGetFileVersionInfoA pGetFileVersionInfoA;
140     LPVerQueryValueA pVerQueryValueA;
141     HMODULE hmodule = 0;
142
143 #define E(_x)   do {TRACE _x;goto theEnd;} while(0)
144
145     if (OpenFile(fname, &ofs, OF_EXIST)==HFILE_ERROR)           E(("Can't find file %s\n", fname));
146
147     if (!(hmodule = LoadLibraryA( "version.dll" ))) goto theEnd;
148     if (!(pGetFileVersionInfoSizeA = GetProcAddress( hmodule, "GetFileVersionInfoSizeA" )))
149         goto theEnd;
150     if (!(pGetFileVersionInfoA = GetProcAddress( hmodule, "GetFileVersionInfoA" )))
151         goto theEnd;
152     if (!(pVerQueryValueA = GetProcAddress( hmodule, "VerQueryValueA" )))
153         goto theEnd;
154
155     if (!(dw = pGetFileVersionInfoSizeA(ofs.szPathName, &h)))   E(("Can't get FVIS\n"));
156     if (!(ptr = HeapAlloc(GetProcessHeap(), 0, dw)))            E(("OOM\n"));
157     if (!pGetFileVersionInfoA(ofs.szPathName, h, dw, ptr))      E(("Can't get FVI\n"));
158
159 #define A(_x) if (pVerQueryValueA(ptr, "\\StringFileInfo\\040904B0\\" #_x, &val, &u)) \
160                   TRACE(#_x " => %s\n", (LPSTR)val); else TRACE(#_x " @\n")
161
162     A(CompanyName);
163     A(FileDescription);
164     A(FileVersion);
165     A(InternalName);
166     A(LegalCopyright);
167     A(OriginalFilename);
168     A(ProductName);
169     A(ProductVersion);
170     A(Comments);
171     A(LegalTrademarks);
172     A(PrivateBuild);
173     A(SpecialBuild);
174 #undef A
175
176     if (!pVerQueryValueA(ptr, "\\StringFileInfo\\040904B0\\ProductName", &val, &u)) E(("Can't get product name\n"));
177     lstrcpynA(buf, val, buflen);
178
179 #undef E
180     ret = TRUE;
181 theEnd:
182     HeapFree(GetProcessHeap(), 0, ptr);
183     if (hmodule) FreeLibrary( hmodule );
184     return ret;
185 }
186
187 /**************************************************************************
188  *                      MMDRV_GetNum                            [internal]
189  */
190 UINT    MMDRV_GetNum(UINT type)
191 {
192     assert(type < MMDRV_MAX);
193     return llTypes[type].wMaxId;
194 }
195
196 /**************************************************************************
197  *                              MMDRV_Message                   [internal]
198  */
199 DWORD   MMDRV_Message(LPWINE_MLD mld, WORD wMsg, DWORD dwParam1,
200                       DWORD dwParam2, BOOL bFrom32)
201 {
202     LPWINE_MM_DRIVER            lpDrv;
203     DWORD                       ret;
204     WINE_MM_DRIVER_PART*        part;
205     WINE_LLTYPE*                llType = &llTypes[mld->type];
206     WINMM_MapType               map;
207     int                         devID;
208
209     TRACE("(%s %u %u 0x%08lx 0x%08lx 0x%08lx %c)\n",
210           llTypes[mld->type].typestr, mld->uDeviceID, wMsg,
211           mld->dwDriverInstance, dwParam1, dwParam2, bFrom32?'Y':'N');
212
213     if (mld->uDeviceID == (UINT16)-1) {
214         if (!llType->bSupportMapper) {
215             WARN("uDev=-1 requested on non-mappable ll type %s\n",
216                  llTypes[mld->type].typestr);
217             return MMSYSERR_BADDEVICEID;
218         }
219         devID = -1;
220     } else {
221         if (mld->uDeviceID >= llType->wMaxId) {
222             WARN("uDev(%u) requested >= max (%d)\n", mld->uDeviceID, llType->wMaxId);
223             return MMSYSERR_BADDEVICEID;
224         }
225         devID = mld->uDeviceID;
226     }
227
228     lpDrv = &MMDrvs[mld->mmdIndex];
229     part = &lpDrv->parts[mld->type];
230
231 #if 0
232     /* some sanity checks */
233     if (!(part->nIDMin <= devID))
234         ERR("!(part->nIDMin(%d) <= devID(%d))\n", part->nIDMin, devID);
235     if (!(devID < part->nIDMax))
236         ERR("!(devID(%d) < part->nIDMax(%d))\n", devID, part->nIDMax);
237 #endif
238
239     if (lpDrv->bIs32) {
240         assert(part->u.fnMessage32);
241
242         if (bFrom32) {
243             TRACE("Calling message(dev=%u msg=%u usr=0x%08lx p1=0x%08lx p2=0x%08lx)\n",
244                   mld->uDeviceID, wMsg, mld->dwDriverInstance, dwParam1, dwParam2);
245             ret = part->u.fnMessage32(mld->uDeviceID, wMsg, mld->dwDriverInstance, dwParam1, dwParam2);
246             TRACE("=> %lu\n", ret);
247         } else {
248             map = llType->Map16To32A(wMsg, &mld->dwDriverInstance, &dwParam1, &dwParam2);
249             switch (map) {
250             case WINMM_MAP_NOMEM:
251                 ret = MMSYSERR_NOMEM;
252                 break;
253             case WINMM_MAP_MSGERROR:
254                 FIXME("NIY: no conversion yet 16->32 (%u)\n", wMsg);
255                 ret = MMSYSERR_ERROR;
256                 break;
257             case WINMM_MAP_OK:
258             case WINMM_MAP_OKMEM:
259                 TRACE("Calling message(dev=%u msg=%u usr=0x%08lx p1=0x%08lx p2=0x%08lx)\n",
260                       mld->uDeviceID, wMsg, mld->dwDriverInstance, dwParam1, dwParam2);
261                 ret = part->u.fnMessage32(mld->uDeviceID, wMsg, mld->dwDriverInstance,
262                                           dwParam1, dwParam2);
263                 TRACE("=> %lu\n", ret);
264                 if (map == WINMM_MAP_OKMEM)
265                     llType->UnMap16To32A(wMsg, &mld->dwDriverInstance, &dwParam1, &dwParam2, ret);
266                 break;
267             default:
268                 FIXME("NIY\n");
269                 ret = MMSYSERR_NOTSUPPORTED;
270                 break;
271             }
272         }
273     } else {
274         assert(part->u.fnMessage16 && pFnCallMMDrvFunc16);
275         
276         if (bFrom32) {
277             map = llType->Map32ATo16(wMsg, &mld->dwDriverInstance, &dwParam1, &dwParam2);
278             switch (map) {
279             case WINMM_MAP_NOMEM:
280                 ret = MMSYSERR_NOMEM;
281                 break;
282             case WINMM_MAP_MSGERROR:
283                 FIXME("NIY: no conversion yet 32->16 (%u)\n", wMsg);
284                 ret = MMSYSERR_ERROR;
285                 break;
286             case WINMM_MAP_OK:
287             case WINMM_MAP_OKMEM:
288                 TRACE("Calling message(dev=%u msg=%u usr=0x%08lx p1=0x%08lx p2=0x%08lx)\n",
289                       mld->uDeviceID, wMsg, mld->dwDriverInstance, dwParam1, dwParam2);
290                 ret = pFnCallMMDrvFunc16((FARPROC16)part->u.fnMessage16, 
291                                          mld->uDeviceID, wMsg, mld->dwDriverInstance, 
292                                          dwParam1, dwParam2);
293                 TRACE("=> %lu\n", ret);
294                 if (map == WINMM_MAP_OKMEM)
295                     llType->UnMap32ATo16(wMsg, &mld->dwDriverInstance, &dwParam1, &dwParam2, ret);
296                 break;
297             default:
298                 FIXME("NIY\n");
299                 ret = MMSYSERR_NOTSUPPORTED;
300                 break;
301             }
302         } else {
303             TRACE("Calling message(dev=%u msg=%u usr=0x%08lx p1=0x%08lx p2=0x%08lx)\n",
304                   mld->uDeviceID, wMsg, mld->dwDriverInstance, dwParam1, dwParam2);
305             ret = pFnCallMMDrvFunc16((FARPROC16)part->u.fnMessage16, 
306                                      mld->uDeviceID, wMsg, mld->dwDriverInstance, 
307                                      dwParam1, dwParam2);
308             TRACE("=> %lu\n", ret);
309         }
310     }
311     return ret;
312 }
313
314 /**************************************************************************
315  *                              MMDRV_Alloc                     [internal]
316  */
317 LPWINE_MLD      MMDRV_Alloc(UINT size, UINT type, LPHANDLE hndl, DWORD* dwFlags,
318                             DWORD* dwCallback, DWORD* dwInstance, BOOL bFrom32)
319 {
320     LPWINE_MLD  mld;
321     UINT i;
322
323     mld = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
324     if (!mld)   return NULL;
325
326     /* find an empty slot in MM_MLDrvs table */
327     for (i = 0; i < MAX_MM_MLDRVS; i++) if (!MM_MLDrvs[i]) break;
328
329     if (i == MAX_MM_MLDRVS) {
330         /* the MM_MLDrvs table could be made growable in the future if needed */
331         ERR("Too many open drivers\n");
332         return NULL;
333     }
334     MM_MLDrvs[i] = mld;
335     *hndl = (HANDLE)(i | 0x8000);
336
337     mld->type = type;
338     if ((UINT)*hndl < MMDRV_GetNum(type) || HIWORD(*hndl) != 0) {
339         /* FIXME: those conditions must be fulfilled so that:
340          * - we can distinguish between device IDs and handles
341          * - we can use handles as 16 or 32 bit entities
342          */
343         ERR("Shouldn't happen. Bad allocation scheme\n");
344     }
345
346     mld->bFrom32 = bFrom32;
347     mld->dwFlags = HIWORD(*dwFlags);
348     mld->dwCallback = *dwCallback;
349     mld->dwClientInstance = *dwInstance;
350
351     if (llTypes[type].Callback)
352     {
353         *dwFlags = LOWORD(*dwFlags) | CALLBACK_FUNCTION;
354         *dwCallback = (DWORD)llTypes[type].Callback;
355         *dwInstance = (DWORD)mld; /* FIXME: wouldn't some 16 bit drivers only use the loword ? */
356     }
357
358     return mld;
359 }
360
361 /**************************************************************************
362  *                              MMDRV_Free                      [internal]
363  */
364 void    MMDRV_Free(HANDLE hndl, LPWINE_MLD mld)
365 {
366     if ((UINT)hndl & 0x8000) {
367         unsigned idx = (UINT)hndl & ~0x8000;
368         if (idx < sizeof(MM_MLDrvs) / sizeof(MM_MLDrvs[0])) {
369             MM_MLDrvs[idx] = NULL;
370             HeapFree(GetProcessHeap(), 0, mld);
371             return;
372         }
373     }
374     ERR("Bad Handle %p at %p (not freed)\n", hndl, mld);
375 }
376
377 /**************************************************************************
378  *                              MMDRV_Open                      [internal]
379  */
380 DWORD   MMDRV_Open(LPWINE_MLD mld, UINT wMsg, DWORD dwParam1, DWORD dwFlags)
381 {
382     DWORD               dwRet = MMSYSERR_BADDEVICEID;
383     DWORD               dwInstance;
384     WINE_LLTYPE*        llType = &llTypes[mld->type];
385
386     mld->dwDriverInstance = (DWORD)&dwInstance;
387
388     if (mld->uDeviceID == (UINT)-1 || mld->uDeviceID == (UINT16)-1) {
389         TRACE("MAPPER mode requested !\n");
390         /* check if mapper is supported by type */
391         if (llType->bSupportMapper) {
392             if (llType->nMapper == -1) {
393                 /* no driver for mapper has been loaded, try a dumb implementation */
394                 TRACE("No mapper loaded, doing it by hand\n");
395                 for (mld->uDeviceID = 0; mld->uDeviceID < llType->wMaxId; mld->uDeviceID++) {
396                     if ((dwRet = MMDRV_Open(mld, wMsg, dwParam1, dwFlags)) == MMSYSERR_NOERROR) {
397                         /* to share this function epilog */
398                         dwInstance = mld->dwDriverInstance;
399                         break;
400                     }
401                 }
402             } else {
403                 mld->uDeviceID = (UINT16)-1;
404                 mld->mmdIndex = llType->lpMlds[-1].mmdIndex;
405                 TRACE("Setting mmdIndex to %u\n", mld->mmdIndex);
406                 dwRet = MMDRV_Message(mld, wMsg, dwParam1, dwFlags, TRUE);
407             }
408         }
409     } else {
410         if (mld->uDeviceID < llType->wMaxId) {
411             mld->mmdIndex = llType->lpMlds[mld->uDeviceID].mmdIndex;
412             TRACE("Setting mmdIndex to %u\n", mld->mmdIndex);
413             dwRet = MMDRV_Message(mld, wMsg, dwParam1, dwFlags, TRUE);
414         }
415     }
416     if (dwRet == MMSYSERR_NOERROR)
417         mld->dwDriverInstance = dwInstance;
418     return dwRet;
419 }
420
421 /**************************************************************************
422  *                              MMDRV_Close                     [internal]
423  */
424 DWORD   MMDRV_Close(LPWINE_MLD mld, UINT wMsg)
425 {
426     return MMDRV_Message(mld, wMsg, 0L, 0L, TRUE);
427 }
428
429 /**************************************************************************
430  *                              MMDRV_GetByID                   [internal]
431  */
432 LPWINE_MLD      MMDRV_GetByID(UINT uDevID, UINT type)
433 {
434     if (uDevID < llTypes[type].wMaxId)
435         return &llTypes[type].lpMlds[uDevID];
436     if ((uDevID == (UINT16)-1 || uDevID == (UINT)-1) && llTypes[type].nMapper != -1)
437         return &llTypes[type].lpMlds[-1];
438     return NULL;
439 }
440
441 /**************************************************************************
442  *                              MMDRV_Get                       [internal]
443  */
444 LPWINE_MLD      MMDRV_Get(HANDLE _hndl, UINT type, BOOL bCanBeID)
445 {
446     LPWINE_MLD  mld = NULL;
447     UINT        hndl = (UINT)_hndl;
448
449     assert(type < MMDRV_MAX);
450
451     if (hndl >= llTypes[type].wMaxId &&
452         hndl != (UINT16)-1 && hndl != (UINT)-1) {
453         if (hndl & 0x8000) {
454             hndl = hndl & ~0x8000;
455             if (hndl < sizeof(MM_MLDrvs) / sizeof(MM_MLDrvs[0])) {
456                 mld = MM_MLDrvs[hndl];
457                 if (!mld || !HeapValidate(GetProcessHeap(), 0, mld) || mld->type != type)
458                     mld = NULL;
459             }
460             hndl = hndl | 0x8000;
461         }
462     }
463     if (mld == NULL && bCanBeID) {
464         mld = MMDRV_GetByID(hndl, type);
465     }
466     return mld;
467 }
468
469 /**************************************************************************
470  *                              MMDRV_GetRelated                [internal]
471  */
472 LPWINE_MLD      MMDRV_GetRelated(HANDLE hndl, UINT srcType,
473                                  BOOL bSrcCanBeID, UINT dstType)
474 {
475     LPWINE_MLD          mld;
476
477     if ((mld = MMDRV_Get(hndl, srcType, bSrcCanBeID)) != NULL) {
478         WINE_MM_DRIVER_PART*    part = &MMDrvs[mld->mmdIndex].parts[dstType];
479         if (part->nIDMin < part->nIDMax)
480             return MMDRV_GetByID(part->nIDMin, dstType);
481     }
482     return NULL;
483 }
484
485 /**************************************************************************
486  *                              MMDRV_PhysicalFeatures          [internal]
487  */
488 UINT    MMDRV_PhysicalFeatures(LPWINE_MLD mld, UINT uMsg, DWORD dwParam1,
489                                DWORD dwParam2)
490 {
491     WINE_MM_DRIVER*     lpDrv = &MMDrvs[mld->mmdIndex];
492
493     TRACE("(%p, %04x, %08lx, %08lx)\n", mld, uMsg, dwParam1, dwParam2);
494
495     /* all those function calls are undocumented */
496     switch (uMsg) {
497     case DRV_QUERYDRVENTRY:
498         lstrcpynA((LPSTR)dwParam1, lpDrv->drvname, LOWORD(dwParam2));
499         break;
500     case DRV_QUERYDEVNODE:
501         *(LPDWORD)dwParam1 = 0L; /* should be DevNode */
502         break;
503     case DRV_QUERYNAME:
504         WARN("NIY QueryName\n");
505         break;
506     case DRV_QUERYDRIVERIDS:
507         WARN("NIY call VxD\n");
508         /* should call VxD MMDEVLDR with (DevNode, dwParam1 and dwParam2) as pmts
509          * dwParam1 is buffer and dwParam2 is sizeof(buffer)
510          * I don't know where the result is stored though
511          */
512         break;
513     case DRV_QUERYMAPPABLE:
514         return (lpDrv->bIsMapper) ? 2 : 0;
515
516     case DRV_QUERYDSOUNDIFACE: /* Wine-specific: Retrieve DirectSound interface */
517         return MMDRV_Message(mld, uMsg, dwParam1, dwParam2, TRUE);
518
519     case DRV_QUERYDSOUNDDESC: /* Wine-specific: Retrieve DirectSound driver description*/
520         return MMDRV_Message(mld, uMsg, dwParam1, dwParam2, TRUE);
521
522     case DRV_QUERYDSOUNDGUID: /* Wine-specific: Retrieve DirectSound driver GUID */
523         return MMDRV_Message(mld, uMsg, dwParam1, dwParam2, TRUE);
524
525     default:
526         WARN("Unknown call %04x\n", uMsg);
527         return MMSYSERR_INVALPARAM;
528     }
529     return 0L;
530 }
531
532 /**************************************************************************
533  *                              MMDRV_InitPerType               [internal]
534  */
535 static  BOOL    MMDRV_InitPerType(LPWINE_MM_DRIVER lpDrv, UINT type, UINT wMsg)
536 {
537     WINE_MM_DRIVER_PART*        part = &lpDrv->parts[type];
538     DWORD                       ret;
539     UINT                        count = 0;
540     int                         i, k;
541
542     part->nIDMin = part->nIDMax = 0;
543
544     /* for DRVM_INIT and DRVM_ENABLE, dwParam2 should be PnP node */
545     /* the DRVM_ENABLE is only required when the PnP node is non zero */
546
547     if (lpDrv->bIs32 && part->u.fnMessage32) {
548         ret = part->u.fnMessage32(0, DRVM_INIT, 0L, 0L, 0L);
549         TRACE("DRVM_INIT => %08lx\n", ret);
550 #if 0
551         ret = part->u.fnMessage32(0, DRVM_ENABLE, 0L, 0L, 0L);
552         TRACE("DRVM_ENABLE => %08lx\n", ret);
553 #endif
554         count = part->u.fnMessage32(0, wMsg, 0L, 0L, 0L);
555     } else if (!lpDrv->bIs32 && part->u.fnMessage16 && pFnCallMMDrvFunc16) {
556         ret = pFnCallMMDrvFunc16((FARPROC16)part->u.fnMessage16,
557                                  0, DRVM_INIT, 0L, 0L, 0L);
558         TRACE("DRVM_INIT => %08lx\n", ret);
559 #if 0
560         ret = pFnCallMMDrvFunc16((FARPROC16)part->u.fnMessage16,
561                                  0, DRVM_ENABLE, 0L, 0L, 0L);
562         TRACE("DRVM_ENABLE => %08lx\n", ret);
563 #endif
564         count = pFnCallMMDrvFunc16((FARPROC16)part->u.fnMessage16,
565                                    0, wMsg, 0L, 0L, 0L);
566     } else {
567         return FALSE;
568     }
569
570     TRACE("Got %u dev for (%s:%s)\n", count, lpDrv->drvname, llTypes[type].typestr);
571
572     /* got some drivers */
573     if (lpDrv->bIsMapper) {
574         /* it seems native mappers return 0 devices :-( */
575         if (llTypes[type].nMapper != -1)
576             ERR("Two mappers for type %s (%d, %s)\n",
577                 llTypes[type].typestr, llTypes[type].nMapper, lpDrv->drvname);
578         if (count > 1)
579             ERR("Strange: mapper with %d > 1 devices\n", count);
580         llTypes[type].nMapper = MMDrvsHi;
581     } else {
582         if (count == 0)
583             return FALSE;
584         part->nIDMin = llTypes[type].wMaxId;
585         llTypes[type].wMaxId += count;
586         part->nIDMax = llTypes[type].wMaxId;
587     }
588     TRACE("Setting min=%d max=%d (ttop=%d) for (%s:%s)\n",
589           part->nIDMin, part->nIDMax, llTypes[type].wMaxId,
590           lpDrv->drvname, llTypes[type].typestr);
591     /* realloc translation table */
592     llTypes[type].lpMlds = (LPWINE_MLD)
593         HeapReAlloc(GetProcessHeap(), 0, (llTypes[type].lpMlds) ? llTypes[type].lpMlds - 1 : NULL,
594                     sizeof(WINE_MLD) * (llTypes[type].wMaxId + 1)) + 1;
595     /* re-build the translation table */
596     if (llTypes[type].nMapper != -1) {
597         TRACE("%s:Trans[%d] -> %s\n", llTypes[type].typestr, -1, MMDrvs[llTypes[type].nMapper].drvname);
598         llTypes[type].lpMlds[-1].uDeviceID = (UINT16)-1;
599         llTypes[type].lpMlds[-1].type = type;
600         llTypes[type].lpMlds[-1].mmdIndex = llTypes[type].nMapper;
601         llTypes[type].lpMlds[-1].dwDriverInstance = 0;
602     }
603     for (i = k = 0; i <= MMDrvsHi; i++) {
604         while (MMDrvs[i].parts[type].nIDMin <= k && k < MMDrvs[i].parts[type].nIDMax) {
605             TRACE("%s:Trans[%d] -> %s\n", llTypes[type].typestr, k, MMDrvs[i].drvname);
606             llTypes[type].lpMlds[k].uDeviceID = k;
607             llTypes[type].lpMlds[k].type = type;
608             llTypes[type].lpMlds[k].mmdIndex = i;
609             llTypes[type].lpMlds[k].dwDriverInstance = 0;
610             k++;
611         }
612     }
613     return TRUE;
614 }
615
616 /**************************************************************************
617  *                              MMDRV_Install                   [internal]
618  */
619 static  BOOL    MMDRV_Install(LPCSTR drvRegName, LPCSTR drvFileName, BOOL bIsMapper)
620 {
621     int                 i, count = 0;
622     LPWINE_MM_DRIVER    lpDrv = &MMDrvs[MMDrvsHi];
623     LPWINE_DRIVER       d;
624
625     TRACE("('%s', '%s', mapper=%c);\n", drvRegName, drvFileName, bIsMapper ? 'Y' : 'N');
626
627     /* be sure that size of MMDrvs matches the max number of loadable drivers !!
628      * if not just increase size of MMDrvs */
629     assert(MMDrvsHi <= sizeof(MMDrvs)/sizeof(MMDrvs[0]));
630
631     for (i = 0; i < MMDrvsHi; i++) {
632         if (!strcmp(drvRegName, MMDrvs[i].drvname)) return FALSE;
633     }
634
635     memset(lpDrv, 0, sizeof(*lpDrv));
636
637     if (!(lpDrv->hDriver = OpenDriverA(drvFileName, 0, 0))) {
638         WARN("Couldn't open driver '%s'\n", drvFileName);
639         return FALSE;
640     }
641
642     d = DRIVER_FindFromHDrvr(lpDrv->hDriver);
643     lpDrv->bIs32 = (d->dwFlags & WINE_GDF_16BIT) ? FALSE : TRUE;
644
645     /* Then look for xxxMessage functions */
646 #define AA(_h,_w,_x,_y,_z)                                      \
647     func = (WINEMM_msgFunc##_y) _z ((_h), #_x);                 \
648     if (func != NULL)                                           \
649         { lpDrv->parts[_w].u.fnMessage##_y = func; count++;     \
650           TRACE("Got %d bit func '%s'\n", _y, #_x);         }
651
652     if (lpDrv->bIs32) {
653         WINEMM_msgFunc32        func;
654         char                    buffer[128];
655
656         if (d->d.d32.hModule) {
657 #define A(_x,_y)        AA(d->d.d32.hModule,_x,_y,32,GetProcAddress)
658             A(MMDRV_AUX,        auxMessage);
659             A(MMDRV_MIXER,      mxdMessage);
660             A(MMDRV_MIDIIN,     midMessage);
661             A(MMDRV_MIDIOUT,    modMessage);
662             A(MMDRV_WAVEIN,     widMessage);
663             A(MMDRV_WAVEOUT,    wodMessage);
664 #undef A
665         }
666 //        if (TRACE_ON(winmm)) {
667 //            if (MMDRV_GetDescription32(drvFileName, buffer, sizeof(buffer)))
668 //          TRACE("%s => %s\n", drvFileName, buffer);
669 //      else
670 //          TRACE("%s => No description\n", drvFileName);
671 //        }
672 //    } else if (WINMM_CheckForMMSystem() && pFnLoadMMDrvFunc16) {
673     } if (WINMM_CheckForMMSystem() && pFnLoadMMDrvFunc16) {
674         count += pFnLoadMMDrvFunc16(drvFileName, d, lpDrv);
675     }
676 #undef AA
677
678     if (!count) {
679         CloseDriver(lpDrv->hDriver, 0, 0);
680         WARN("No message functions found\n");
681         return FALSE;
682     }
683
684     /* FIXME: being a mapper or not should be known by another way */
685     /* it's known for NE drvs (the description is of the form '*mapper: *'
686      * I don't have any clue for PE drvs
687      */
688     lpDrv->bIsMapper = bIsMapper;
689     lpDrv->drvname = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(drvRegName) + 1), drvRegName);
690
691     /* Finish init and get the count of the devices */
692     MMDRV_InitPerType(lpDrv, MMDRV_AUX,         AUXDM_GETNUMDEVS);
693     MMDRV_InitPerType(lpDrv, MMDRV_MIXER,       MXDM_GETNUMDEVS);
694     MMDRV_InitPerType(lpDrv, MMDRV_MIDIIN,      MIDM_GETNUMDEVS);
695     MMDRV_InitPerType(lpDrv, MMDRV_MIDIOUT,     MODM_GETNUMDEVS);
696     MMDRV_InitPerType(lpDrv, MMDRV_WAVEIN,      WIDM_GETNUMDEVS);
697     MMDRV_InitPerType(lpDrv, MMDRV_WAVEOUT,     WODM_GETNUMDEVS);
698     /* FIXME: if all those func calls return FALSE,
699      * then the driver must be unloaded
700      */
701
702     MMDrvsHi++;
703
704     return TRUE;
705 }
706
707 /**************************************************************************
708  *                              MMDRV_InitFromRegistry          [internal]
709  */
710 static BOOL     MMDRV_InitFromRegistry(void)
711 {
712     HKEY        hKey;
713     char        buffer[256];
714     char*       p1;
715     char*       p2;
716     DWORD       type, size;
717     BOOL        ret = FALSE;
718
719     if (RegCreateKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\WinMM", &hKey)) {
720         TRACE("Cannot open WinMM config key\n");
721         return FALSE;
722     }
723
724     size = sizeof(buffer);
725     if (!RegQueryValueExA(hKey, "Drivers", 0, &type, (LPVOID)buffer, &size)) {
726         p1 = buffer;
727         while (p1) {
728             p2 = strchr(p1, ';');
729             if (p2) *p2++ = '\0';
730             ret |= MMDRV_Install(p1, p1, FALSE);
731             p1 = p2;
732         }
733     }
734
735     /* finish with mappers */
736     size = sizeof(buffer);
737     if (!RegQueryValueExA(hKey, "WaveMapper", 0, &type, (LPVOID)buffer, &size))
738         ret |= MMDRV_Install("wavemapper", buffer, TRUE);
739     size = sizeof(buffer);
740     if (!RegQueryValueExA(hKey, "MidiMapper", 0, &type, (LPVOID)buffer, &size))
741         ret |= MMDRV_Install("midimapper", buffer, TRUE);
742
743     RegCloseKey(hKey);
744
745     return ret;
746 }
747
748 /**************************************************************************
749  *                              MMDRV_InitHardcoded             [internal]
750  */
751 static BOOL     MMDRV_InitHardcoded(void)
752 {
753     /* first load hardware drivers */
754     MMDRV_Install("wineoss.drv",        "wineoss.drv",  FALSE);
755
756     /* finish with mappers */
757     MMDRV_Install("wavemapper",         "msacm.drv",    TRUE);
758     MMDRV_Install("midimapper",         "midimap.drv",  TRUE);
759
760     return TRUE;
761 }
762
763 /**************************************************************************
764  *                              MMDRV_Init                      [internal]
765  */
766 BOOL    MMDRV_Init(void)
767 {
768     /* FIXME: MMDRV_InitFromRegistry shall be MMDRV_Init in a near future */
769     return MMDRV_InitFromRegistry() || MMDRV_InitHardcoded();
770 }
771
772 /******************************************************************
773  *              ExitPerType
774  *
775  *
776  */
777 static  BOOL    MMDRV_ExitPerType(LPWINE_MM_DRIVER lpDrv, UINT type)
778 {
779     WINE_MM_DRIVER_PART*        part = &lpDrv->parts[type];
780     DWORD                       ret;
781
782     if (lpDrv->bIs32 && part->u.fnMessage32) {
783 #if 0
784         ret = part->u.fnMessage32(0, DRVM_DISABLE, 0L, 0L, 0L);
785         TRACE("DRVM_DISABLE => %08lx\n", ret);
786 #endif
787         ret = part->u.fnMessage32(0, DRVM_EXIT, 0L, 0L, 0L);
788         TRACE("DRVM_EXIT => %08lx\n", ret);
789     } else if (!lpDrv->bIs32 && part->u.fnMessage16 && pFnCallMMDrvFunc16) {
790 #if 0
791         ret = pFnCallMMDrvFunc16((FARPROC16)part->u.fnMessage16,
792                                  0, DRVM_DISABLE, 0L, 0L, 0L);
793         TRACE("DRVM_DISABLE => %08lx\n", ret);
794 #endif
795         ret = pFnCallMMDrvFunc16((FARPROC16)part->u.fnMessage16,
796                                  0, DRVM_EXIT, 0L, 0L, 0L);
797         TRACE("DRVM_EXIT => %08lx\n", ret);
798     } else {
799         return FALSE;
800     }
801
802     return TRUE;
803 }
804
805 /******************************************************************
806  *              Exit
807  *
808  *
809  */
810 void    MMDRV_Exit(void)
811 {
812     int i;
813
814     for (i = 0; i < sizeof(MM_MLDrvs) / sizeof(MM_MLDrvs[0]); i++)
815     {
816         if (MM_MLDrvs[i] != NULL)
817         {
818             FIXME("Closing while ll-driver open\n");
819 #if 0
820             /* FIXME: should generate a message depending on type */
821             MMDRV_Free((HANDLE)(i | 0x8000), MM_MLDrvs[i]);
822 #endif
823         }
824     }
825
826     /* unload driver, in reverse order of loading */
827     for (i = sizeof(MMDrvs) / sizeof(MMDrvs[0]) - 1; i >= 0; i--)
828     {
829         MMDRV_ExitPerType(&MMDrvs[i], MMDRV_AUX);
830         MMDRV_ExitPerType(&MMDrvs[i], MMDRV_MIXER);
831         MMDRV_ExitPerType(&MMDrvs[i], MMDRV_MIDIIN);
832         MMDRV_ExitPerType(&MMDrvs[i], MMDRV_MIDIOUT);
833         MMDRV_ExitPerType(&MMDrvs[i], MMDRV_WAVEIN);
834         MMDRV_ExitPerType(&MMDrvs[i], MMDRV_WAVEOUT);
835         CloseDriver(MMDrvs[i].hDriver, 0, 0);
836     }
837 }