wgl: Add initial WGL_ARB_create_context support.
[wine] / dlls / winmm / lolvldrv.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2
3 /*
4  * MMSYSTEM 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <string.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <assert.h>
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winreg.h"
33 #include "winemm.h"
34 #include "wine/debug.h"
35 #include "wine/exception.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(winmm);
38
39 /* each known type of driver has an instance of this structure */
40 typedef struct tagWINE_LLTYPE {
41     /* those attributes depend on the specification of the type */
42     LPCSTR              typestr;        /* name (for debugging) */
43     BOOL                bSupportMapper; /* if type is allowed to support mapper */
44     /* those attributes reflect the loaded/current situation for the type */
45     UINT                wMaxId;         /* number of loaded devices (sum across all loaded drivers) */
46     LPWINE_MLD          lpMlds;         /* "static" mlds to access the part though device IDs */
47     int                 nMapper;        /* index to mapper */
48 } WINE_LLTYPE;
49
50 static int              MMDrvsHi /* = 0 */;
51 static WINE_MM_DRIVER   MMDrvs[8];
52 static LPWINE_MLD       MM_MLDrvs[40];
53 #define MAX_MM_MLDRVS   (sizeof(MM_MLDrvs) / sizeof(MM_MLDrvs[0]))
54
55 #define A(_x,_y) {#_y, _x, 0, NULL, -1}
56 /* Note: the indices of this array must match the definitions
57  *       of the MMDRV_???? manifest constants
58  */
59 static WINE_LLTYPE      llTypes[MMDRV_MAX] = {
60     A(TRUE,  Aux),
61     A(FALSE, Mixer),
62     A(TRUE,  MidiIn),
63     A(TRUE,  MidiOut),
64     A(TRUE,  WaveIn),
65     A(TRUE,  WaveOut),
66 };
67 #undef A
68
69 /**************************************************************************
70  *                      MMDRV_GetNum                            [internal]
71  */
72 UINT    MMDRV_GetNum(UINT type)
73 {
74     TRACE("(%04x)\n", type);
75     assert(type < MMDRV_MAX);
76     return llTypes[type].wMaxId;
77 }
78
79 /**************************************************************************
80  *                              MMDRV_Message                   [internal]
81  */
82 DWORD  MMDRV_Message(LPWINE_MLD mld, UINT wMsg, DWORD_PTR dwParam1,
83                      DWORD_PTR dwParam2)
84 {
85     LPWINE_MM_DRIVER            lpDrv;
86     DWORD                       ret;
87     WINE_MM_DRIVER_PART*        part;
88     WINE_LLTYPE*                llType = &llTypes[mld->type];
89     int                         devID;
90
91     TRACE("(%s %u %u 0x%08lx 0x%08lx 0x%08lx)\n",
92           llTypes[mld->type].typestr, mld->uDeviceID, wMsg,
93           mld->dwDriverInstance, dwParam1, dwParam2);
94
95     if (mld->uDeviceID == (UINT16)-1) {
96         if (!llType->bSupportMapper) {
97             WARN("uDev=-1 requested on non-mappable ll type %s\n",
98                  llTypes[mld->type].typestr);
99             return MMSYSERR_BADDEVICEID;
100         }
101         devID = -1;
102     } else {
103         if (mld->uDeviceID >= llType->wMaxId) {
104             WARN("uDev(%u) requested >= max (%d)\n", mld->uDeviceID, llType->wMaxId);
105             return MMSYSERR_BADDEVICEID;
106         }
107         devID = mld->uDeviceID;
108     }
109
110     lpDrv = &MMDrvs[mld->mmdIndex];
111     part = &lpDrv->parts[mld->type];
112
113 #if 0
114     /* some sanity checks */
115     if (!(part->nIDMin <= devID))
116         ERR("!(part->nIDMin(%d) <= devID(%d))\n", part->nIDMin, devID);
117     if (!(devID < part->nIDMax))
118         ERR("!(devID(%d) < part->nIDMax(%d))\n", devID, part->nIDMax);
119 #endif
120
121     assert(part->fnMessage32);
122
123     TRACE("Calling message(dev=%u msg=%u usr=0x%08lx p1=0x%08lx p2=0x%08lx)\n",
124           mld->uDeviceID, wMsg, mld->dwDriverInstance, dwParam1, dwParam2);
125     ret = part->fnMessage32(mld->uDeviceID, wMsg, mld->dwDriverInstance, dwParam1, dwParam2);
126     TRACE("=> %s\n", WINMM_ErrorToString(ret));
127
128     return ret;
129 }
130
131 /**************************************************************************
132  *                              MMDRV_Alloc                     [internal]
133  */
134 LPWINE_MLD      MMDRV_Alloc(UINT size, UINT type, LPHANDLE hndl, DWORD* dwFlags,
135                             DWORD_PTR* dwCallback, DWORD_PTR* dwInstance)
136 {
137     LPWINE_MLD  mld;
138     UINT_PTR i;
139     TRACE("(%d, %04x, %p, %p, %p, %p)\n",
140           size, type, hndl, dwFlags, dwCallback, dwInstance);
141
142     mld = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
143     if (!mld)   return NULL;
144
145     /* find an empty slot in MM_MLDrvs table */
146     for (i = 0; i < MAX_MM_MLDRVS; i++) if (!MM_MLDrvs[i]) break;
147
148     if (i == MAX_MM_MLDRVS) {
149         /* the MM_MLDrvs table could be made growable in the future if needed */
150         ERR("Too many open drivers\n");
151         HeapFree(GetProcessHeap(), 0, mld);
152         return NULL;
153     }
154     MM_MLDrvs[i] = mld;
155     *hndl = (HANDLE)(i | 0x8000);
156
157     mld->type = type;
158     if ((UINT_PTR)*hndl < MMDRV_GetNum(type) || ((UINT_PTR)*hndl >> 16)) {
159         /* FIXME: those conditions must be fulfilled so that:
160          * - we can distinguish between device IDs and handles
161          * - we can use handles as 16 or 32 bit entities
162          */
163         ERR("Shouldn't happen. Bad allocation scheme\n");
164     }
165
166     mld->dwFlags = HIWORD(*dwFlags);
167     mld->dwCallback = *dwCallback;
168     mld->dwClientInstance = *dwInstance;
169
170     return mld;
171 }
172
173 /**************************************************************************
174  *                              MMDRV_Free                      [internal]
175  */
176 void    MMDRV_Free(HANDLE hndl, LPWINE_MLD mld)
177 {
178     TRACE("(%p, %p)\n", hndl, mld);
179
180     if ((UINT_PTR)hndl & 0x8000) {
181         UINT_PTR idx = (UINT_PTR)hndl & ~0x8000;
182         if (idx < sizeof(MM_MLDrvs) / sizeof(MM_MLDrvs[0])) {
183             MM_MLDrvs[idx] = NULL;
184             HeapFree(GetProcessHeap(), 0, mld);
185             return;
186         }
187     }
188     ERR("Bad Handle %p at %p (not freed)\n", hndl, mld);
189 }
190
191 /**************************************************************************
192  *                              MMDRV_Open                      [internal]
193  */
194 DWORD MMDRV_Open(LPWINE_MLD mld, UINT wMsg, DWORD_PTR dwParam1, DWORD dwFlags)
195 {
196     DWORD               dwRet = MMSYSERR_BADDEVICEID;
197     DWORD_PTR           dwInstance;
198     WINE_LLTYPE*        llType = &llTypes[mld->type];
199     TRACE("(%p, %04x, 0x%08lx, 0x%08x)\n", mld, wMsg, dwParam1, dwFlags);
200
201     mld->dwDriverInstance = (DWORD_PTR)&dwInstance;
202
203     if (mld->uDeviceID == (UINT)-1 || mld->uDeviceID == (UINT16)-1) {
204         TRACE("MAPPER mode requested !\n");
205         /* check if mapper is supported by type */
206         if (llType->bSupportMapper) {
207             if (llType->nMapper == -1) {
208                 /* no driver for mapper has been loaded, try a dumb implementation */
209                 TRACE("No mapper loaded, doing it by hand\n");
210                 for (mld->uDeviceID = 0; mld->uDeviceID < llType->wMaxId; mld->uDeviceID++) {
211                     if ((dwRet = MMDRV_Open(mld, wMsg, dwParam1, dwFlags)) == MMSYSERR_NOERROR) {
212                         /* to share this function epilog */
213                         dwInstance = mld->dwDriverInstance;
214                         break;
215                     }
216                 }
217             } else {
218                 mld->uDeviceID = (UINT16)-1;
219                 mld->mmdIndex = llType->lpMlds[-1].mmdIndex;
220                 TRACE("Setting mmdIndex to %u\n", mld->mmdIndex);
221                 dwRet = MMDRV_Message(mld, wMsg, dwParam1, dwFlags);
222             }
223         }
224     } else {
225         if (mld->uDeviceID < llType->wMaxId) {
226             mld->mmdIndex = llType->lpMlds[mld->uDeviceID].mmdIndex;
227             TRACE("Setting mmdIndex to %u\n", mld->mmdIndex);
228             dwRet = MMDRV_Message(mld, wMsg, dwParam1, dwFlags);
229         }
230     }
231     if (dwRet == MMSYSERR_NOERROR)
232         mld->dwDriverInstance = dwInstance;
233     return dwRet;
234 }
235
236 /**************************************************************************
237  *                              MMDRV_Close                     [internal]
238  */
239 DWORD   MMDRV_Close(LPWINE_MLD mld, UINT wMsg)
240 {
241     TRACE("(%p, %04x)\n", mld, wMsg);
242     return MMDRV_Message(mld, wMsg, 0L, 0L);
243 }
244
245 /**************************************************************************
246  *                              MMDRV_GetByID                   [internal]
247  */
248 static LPWINE_MLD MMDRV_GetByID(UINT uDevID, UINT type)
249 {
250     TRACE("(%04x, %04x)\n", uDevID, type);
251     if (uDevID < llTypes[type].wMaxId)
252         return &llTypes[type].lpMlds[uDevID];
253     if ((uDevID == (UINT16)-1 || uDevID == (UINT)-1) && llTypes[type].nMapper != -1)
254         return &llTypes[type].lpMlds[-1];
255     return NULL;
256 }
257
258 /**************************************************************************
259  *                              MMDRV_Get                       [internal]
260  */
261 LPWINE_MLD      MMDRV_Get(HANDLE _hndl, UINT type, BOOL bCanBeID)
262 {
263     LPWINE_MLD  mld = NULL;
264     UINT_PTR    hndl = (UINT_PTR)_hndl;
265     TRACE("(%p, %04x, %c)\n", _hndl, type, bCanBeID ? 'Y' : 'N');
266
267     assert(type < MMDRV_MAX);
268
269     if (hndl >= llTypes[type].wMaxId &&
270         hndl != (UINT16)-1 && hndl != (UINT)-1) {
271         if (hndl & 0x8000) {
272             UINT idx = hndl & ~0x8000;
273             if (idx < sizeof(MM_MLDrvs) / sizeof(MM_MLDrvs[0])) {
274                 __TRY
275                 {
276                     mld = MM_MLDrvs[idx];
277                     if (mld && mld->type != type) mld = NULL;
278                 }
279                 __EXCEPT_PAGE_FAULT
280                 {
281                     mld = NULL;
282                 }
283                 __ENDTRY;
284             }
285         }
286     }
287     if (mld == NULL && bCanBeID) {
288         mld = MMDRV_GetByID(hndl, type);
289     }
290     return mld;
291 }
292
293 /**************************************************************************
294  *                              MMDRV_GetRelated                [internal]
295  */
296 LPWINE_MLD      MMDRV_GetRelated(HANDLE hndl, UINT srcType,
297                                  BOOL bSrcCanBeID, UINT dstType)
298 {
299     LPWINE_MLD          mld;
300     TRACE("(%p, %04x, %c, %04x)\n",
301           hndl, srcType, bSrcCanBeID ? 'Y' : 'N', dstType);
302
303     if ((mld = MMDRV_Get(hndl, srcType, bSrcCanBeID)) != NULL) {
304         WINE_MM_DRIVER_PART*    part = &MMDrvs[mld->mmdIndex].parts[dstType];
305         if (part->nIDMin < part->nIDMax)
306             return MMDRV_GetByID(part->nIDMin, dstType);
307     }
308     return NULL;
309 }
310
311 /**************************************************************************
312  *                              MMDRV_PhysicalFeatures          [internal]
313  */
314 UINT    MMDRV_PhysicalFeatures(LPWINE_MLD mld, UINT uMsg,
315                                DWORD_PTR dwParam1, DWORD_PTR dwParam2)
316 {
317     WINE_MM_DRIVER*     lpDrv = &MMDrvs[mld->mmdIndex];
318
319     TRACE("(%p, %04x, %08lx, %08lx)\n", mld, uMsg, dwParam1, dwParam2);
320
321     /* all those function calls are undocumented */
322     switch (uMsg) {
323     case DRV_QUERYDRVENTRY:
324         lstrcpynA((LPSTR)dwParam1, lpDrv->drvname, LOWORD(dwParam2));
325         break;
326     case DRV_QUERYDEVNODE:
327         *(LPDWORD)dwParam1 = 0L; /* should be DevNode */
328         break;
329     case DRV_QUERYNAME:
330         WARN("NIY QueryName\n");
331         break;
332     case DRV_QUERYDRIVERIDS:
333         WARN("NIY call VxD\n");
334         /* should call VxD MMDEVLDR with (DevNode, dwParam1 and dwParam2) as pmts
335          * dwParam1 is buffer and dwParam2 is sizeof(buffer)
336          * I don't know where the result is stored though
337          */
338         break;
339     case DRV_QUERYMAPPABLE:
340         return (lpDrv->bIsMapper) ? 2 : 0;
341
342     case DRVM_MAPPER_PREFERRED_GET:
343         /* FIXME: get from registry someday */
344         *((LPDWORD)dwParam1) = -1;      /* No preferred device */
345         *((LPDWORD)dwParam2) = 0;
346         break;
347
348     case DRV_QUERYDEVICEINTERFACE:
349     case DRV_QUERYDEVICEINTERFACESIZE:
350         return MMDRV_Message(mld, uMsg, dwParam1, dwParam2);
351
352     case DRV_QUERYDSOUNDIFACE: /* Wine-specific: Retrieve DirectSound interface */
353     case DRV_QUERYDSOUNDDESC: /* Wine-specific: Retrieve DirectSound driver description*/
354         return MMDRV_Message(mld, uMsg, dwParam1, dwParam2);
355
356     default:
357         WARN("Unknown call %04x\n", uMsg);
358         return MMSYSERR_INVALPARAM;
359     }
360     return 0L;
361 }
362
363 /**************************************************************************
364  *                              MMDRV_InitPerType               [internal]
365  */
366 static  BOOL    MMDRV_InitPerType(LPWINE_MM_DRIVER lpDrv, UINT type, UINT wMsg)
367 {
368     WINE_MM_DRIVER_PART*        part = &lpDrv->parts[type];
369     DWORD                       ret;
370     UINT                        count = 0;
371     int                         i, k;
372     TRACE("(%p, %04x, %04x)\n", lpDrv, type, wMsg);
373
374     part->nIDMin = part->nIDMax = 0;
375
376     /* for DRVM_INIT and DRVM_ENABLE, dwParam2 should be PnP node */
377     /* the DRVM_ENABLE is only required when the PnP node is non zero */
378     if (part->fnMessage32) {
379         ret = part->fnMessage32(0, DRVM_INIT, 0L, 0L, 0L);
380         TRACE("DRVM_INIT => %s\n", WINMM_ErrorToString(ret));
381 #if 0
382         ret = part->fnMessage32(0, DRVM_ENABLE, 0L, 0L, 0L);
383         TRACE("DRVM_ENABLE => %08lx\n", ret);
384 #endif
385         count = part->fnMessage32(0, wMsg, 0L, 0L, 0L);
386     }
387     else return FALSE;
388
389     TRACE("Got %u dev for (%s:%s)\n", count, lpDrv->drvname, llTypes[type].typestr);
390     
391     if (HIWORD(count))
392         return FALSE;
393
394     /* got some drivers */
395     if (lpDrv->bIsMapper) {
396         /* it seems native mappers return 0 devices :-( */
397         if (llTypes[type].nMapper != -1)
398             ERR("Two mappers for type %s (%d, %s)\n",
399                 llTypes[type].typestr, llTypes[type].nMapper, lpDrv->drvname);
400         if (count > 1)
401             ERR("Strange: mapper with %d > 1 devices\n", count);
402         llTypes[type].nMapper = MMDrvsHi;
403     } else {
404         if (count == 0)
405             return FALSE;
406         part->nIDMin = llTypes[type].wMaxId;
407         llTypes[type].wMaxId += count;
408         part->nIDMax = llTypes[type].wMaxId;
409     }
410     TRACE("Setting min=%d max=%d (ttop=%d) for (%s:%s)\n",
411           part->nIDMin, part->nIDMax, llTypes[type].wMaxId,
412           lpDrv->drvname, llTypes[type].typestr);
413     /* realloc translation table */
414     if (llTypes[type].lpMlds)
415         llTypes[type].lpMlds = (LPWINE_MLD)
416         HeapReAlloc(GetProcessHeap(), 0, llTypes[type].lpMlds - 1,
417                     sizeof(WINE_MLD) * (llTypes[type].wMaxId + 1)) + 1;
418     else
419         llTypes[type].lpMlds = (LPWINE_MLD)
420         HeapAlloc(GetProcessHeap(), 0,
421                     sizeof(WINE_MLD) * (llTypes[type].wMaxId + 1)) + 1;
422
423     /* re-build the translation table */
424     if (llTypes[type].nMapper != -1) {
425         TRACE("%s:Trans[%d] -> %s\n", llTypes[type].typestr, -1, MMDrvs[llTypes[type].nMapper].drvname);
426         llTypes[type].lpMlds[-1].uDeviceID = (UINT16)-1;
427         llTypes[type].lpMlds[-1].type = type;
428         llTypes[type].lpMlds[-1].mmdIndex = llTypes[type].nMapper;
429         llTypes[type].lpMlds[-1].dwDriverInstance = 0;
430     }
431     for (i = k = 0; i <= MMDrvsHi; i++) {
432         while (MMDrvs[i].parts[type].nIDMin <= k && k < MMDrvs[i].parts[type].nIDMax) {
433             TRACE("%s:Trans[%d] -> %s\n", llTypes[type].typestr, k, MMDrvs[i].drvname);
434             llTypes[type].lpMlds[k].uDeviceID = k;
435             llTypes[type].lpMlds[k].type = type;
436             llTypes[type].lpMlds[k].mmdIndex = i;
437             llTypes[type].lpMlds[k].dwDriverInstance = 0;
438             k++;
439         }
440     }
441     return TRUE;
442 }
443
444 /**************************************************************************
445  *                              MMDRV_Install                   [internal]
446  */
447 static  BOOL    MMDRV_Install(LPCSTR drvRegName, LPCSTR drvFileName, BOOL bIsMapper)
448 {
449     int                 i, count = 0;
450     LPWINE_MM_DRIVER    lpDrv = &MMDrvs[MMDrvsHi];
451     LPWINE_DRIVER       d;
452     WINEMM_msgFunc32    func;
453
454     TRACE("('%s', '%s', mapper=%c);\n", drvRegName, drvFileName, bIsMapper ? 'Y' : 'N');
455
456     for (i = 0; i < MMDrvsHi; i++) {
457         if (!strcmp(drvRegName, MMDrvs[i].drvname)) return FALSE;
458     }
459
460     /* Be sure that size of MMDrvs matches the max number of loadable
461      * drivers !!
462      * If not just increase size of MMDrvs
463      */
464     assert(MMDrvsHi <= sizeof(MMDrvs)/sizeof(MMDrvs[0]));
465
466     memset(lpDrv, 0, sizeof(*lpDrv));
467
468     if (!(lpDrv->hDriver = OpenDriverA(drvFileName, 0, 0))) {
469         WARN("Couldn't open driver '%s'\n", drvFileName);
470         return FALSE;
471     }
472
473     d = DRIVER_FindFromHDrvr(lpDrv->hDriver);
474
475     /* Then look for xxxMessage functions */
476 #define AA(_h,_w,_x,_y,_z)                                      \
477     func = (WINEMM_msgFunc##_y) _z ((_h), #_x);                 \
478     if (func != NULL)                                           \
479         { lpDrv->parts[_w].fnMessage##_y = func; count++;       \
480           TRACE("Got %d bit func '%s'\n", _y, #_x);         }
481
482     if (d->hModule) {
483 #define A(_x,_y)        AA(d->hModule,_x,_y,32,GetProcAddress)
484             A(MMDRV_AUX,        auxMessage);
485             A(MMDRV_MIXER,      mxdMessage);
486             A(MMDRV_MIDIIN,     midMessage);
487             A(MMDRV_MIDIOUT,    modMessage);
488             A(MMDRV_WAVEIN,     widMessage);
489             A(MMDRV_WAVEOUT,    wodMessage);
490 #undef A
491     }
492 #undef AA
493
494     if (!count) {
495         CloseDriver(lpDrv->hDriver, 0, 0);
496         WARN("No message functions found\n");
497         return FALSE;
498     }
499
500     /* FIXME: being a mapper or not should be known by another way */
501     /* it's known for NE drvs (the description is of the form '*mapper: *'
502      * I don't have any clue for PE drvs
503      */
504     lpDrv->bIsMapper = bIsMapper;
505     lpDrv->drvname = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(drvRegName) + 1), drvRegName);
506
507     /* Finish init and get the count of the devices */
508     i = 0;
509     if (MMDRV_InitPerType(lpDrv, MMDRV_AUX,     AUXDM_GETNUMDEVS))      i = 1;
510     if (MMDRV_InitPerType(lpDrv, MMDRV_MIXER,   MXDM_GETNUMDEVS))       i = 1;
511     if (MMDRV_InitPerType(lpDrv, MMDRV_MIDIIN,  MIDM_GETNUMDEVS))       i = 1;
512     if (MMDRV_InitPerType(lpDrv, MMDRV_MIDIOUT, MODM_GETNUMDEVS))       i = 1;
513     if (MMDRV_InitPerType(lpDrv, MMDRV_WAVEIN,  WIDM_GETNUMDEVS))       i = 1;
514     if (MMDRV_InitPerType(lpDrv, MMDRV_WAVEOUT, WODM_GETNUMDEVS))       i = 1;
515     /* if all those func calls return FALSE, then the driver must be unloaded */
516     if (!i) {
517         CloseDriver(lpDrv->hDriver, 0, 0);
518         HeapFree(GetProcessHeap(), 0, lpDrv->drvname);
519         WARN("Driver initialization failed\n");
520         return FALSE;
521     }
522
523     MMDrvsHi++;
524
525     return TRUE;
526 }
527
528 /**************************************************************************
529  *                              MMDRV_Init
530  */
531 BOOL    MMDRV_Init(void)
532 {
533     HKEY        hKey;
534     char        driver_buffer[256];
535     char        mapper_buffer[256];
536     char        midi_buffer[256];
537     char*       p;
538     DWORD       type, size;
539     BOOL        ret = FALSE;
540     TRACE("()\n");
541
542     strcpy(driver_buffer, WINE_DEFAULT_WINMM_DRIVER);
543     strcpy(mapper_buffer, WINE_DEFAULT_WINMM_MAPPER);
544     strcpy(midi_buffer, WINE_DEFAULT_WINMM_MIDI);
545
546     /* @@ Wine registry key: HKCU\Software\Wine\Drivers */
547     if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Drivers", &hKey))
548     {
549         size = sizeof(driver_buffer);
550         if (RegQueryValueExA(hKey, "Audio", 0, &type, (LPVOID)driver_buffer, &size))
551             strcpy(driver_buffer, WINE_DEFAULT_WINMM_DRIVER);
552     }
553
554     p = driver_buffer;
555     while (p)
556     {
557         char filename[sizeof(driver_buffer)+10];
558         char *next = strchr(p, ',');
559         if (next) *next++ = 0;
560         sprintf( filename, "wine%s.drv", p );
561         if ((ret = MMDRV_Install( filename, filename, FALSE ))) break;
562         p = next;
563     }
564
565     ret |= MMDRV_Install("wavemapper", WINE_DEFAULT_WINMM_MAPPER, TRUE);
566     ret |= MMDRV_Install("midimapper", WINE_DEFAULT_WINMM_MIDI, TRUE);
567     return ret;
568 }
569
570 /******************************************************************
571  *              ExitPerType
572  *
573  *
574  */
575 static  BOOL    MMDRV_ExitPerType(LPWINE_MM_DRIVER lpDrv, UINT type)
576 {
577     WINE_MM_DRIVER_PART*        part = &lpDrv->parts[type];
578     DWORD                       ret;
579     TRACE("(%p, %04x)\n", lpDrv, type);
580
581     if (part->fnMessage32) {
582 #if 0
583         ret = part->fnMessage32(0, DRVM_DISABLE, 0L, 0L, 0L);
584         TRACE("DRVM_DISABLE => %08lx\n", ret);
585 #endif
586         ret = part->fnMessage32(0, DRVM_EXIT, 0L, 0L, 0L);
587         TRACE("DRVM_EXIT => %s\n", WINMM_ErrorToString(ret));
588     }
589
590     return TRUE;
591 }
592
593 /******************************************************************
594  *              Exit
595  *
596  *
597  */
598 void    MMDRV_Exit(void)
599 {
600     unsigned int i;
601     TRACE("()\n");
602
603     for (i = 0; i < sizeof(MM_MLDrvs) / sizeof(MM_MLDrvs[0]); i++)
604     {
605         if (MM_MLDrvs[i] != NULL)
606         {
607             FIXME("Closing while ll-driver open\n");
608 #if 0
609             /* FIXME: should generate a message depending on type */
610             MMDRV_Free((HANDLE)(i | 0x8000), MM_MLDrvs[i]);
611 #endif
612         }
613     }
614
615     /* unload driver, in reverse order of loading */
616     i = sizeof(MMDrvs) / sizeof(MMDrvs[0]);
617     while (i-- > 0)
618     {
619         MMDRV_ExitPerType(&MMDrvs[i], MMDRV_AUX);
620         MMDRV_ExitPerType(&MMDrvs[i], MMDRV_MIXER);
621         MMDRV_ExitPerType(&MMDrvs[i], MMDRV_MIDIIN);
622         MMDRV_ExitPerType(&MMDrvs[i], MMDRV_MIDIOUT);
623         MMDRV_ExitPerType(&MMDrvs[i], MMDRV_WAVEIN);
624         MMDRV_ExitPerType(&MMDrvs[i], MMDRV_WAVEOUT);
625         CloseDriver(MMDrvs[i].hDriver, 0, 0);
626     }
627     if (llTypes[MMDRV_AUX].lpMlds)
628         HeapFree(GetProcessHeap(), 0, llTypes[MMDRV_AUX].lpMlds - 1);
629     if (llTypes[MMDRV_MIXER].lpMlds)
630         HeapFree(GetProcessHeap(), 0, llTypes[MMDRV_MIXER].lpMlds - 1);
631     if (llTypes[MMDRV_MIDIIN].lpMlds)
632         HeapFree(GetProcessHeap(), 0, llTypes[MMDRV_MIDIIN].lpMlds - 1);
633     if (llTypes[MMDRV_MIDIOUT].lpMlds)
634         HeapFree(GetProcessHeap(), 0, llTypes[MMDRV_MIDIOUT].lpMlds - 1);
635     if (llTypes[MMDRV_WAVEIN].lpMlds)
636         HeapFree(GetProcessHeap(), 0, llTypes[MMDRV_WAVEIN].lpMlds - 1);
637     if (llTypes[MMDRV_WAVEOUT].lpMlds)
638         HeapFree(GetProcessHeap(), 0, llTypes[MMDRV_WAVEOUT].lpMlds - 1);
639 }