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