xref: /reactos/dll/win32/winmm/driver.c (revision 1734f297)
1 /*
2  * WINE Drivers functions
3  *
4  * Copyright 1994 Martin Ayotte
5  * Copyright 1998 Marcus Meissner
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 "winemm.h"
24 
25 WINE_DEFAULT_DEBUG_CHANNEL(driver);
26 
27 static CRITICAL_SECTION mmdriver_lock;
28 static CRITICAL_SECTION_DEBUG mmdriver_lock_debug =
29 {
30     0, 0, &mmdriver_lock,
31     { &mmdriver_lock_debug.ProcessLocksList, &mmdriver_lock_debug.ProcessLocksList },
32       0, 0, { (DWORD_PTR)(__FILE__ ": mmdriver_lock") }
33 };
34 static CRITICAL_SECTION mmdriver_lock = { &mmdriver_lock_debug, -1, 0, 0, 0, 0 };
35 
36 static LPWINE_DRIVER   lpDrvItemList  /* = NULL */;
37 static const WCHAR HKLM_BASE[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
38                                   'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',0};
39 
40 static void DRIVER_Dump(const char *comment)
41 {
42 #if 0
43     LPWINE_DRIVER 	lpDrv;
44 
45     TRACE("%s\n", comment);
46 
47     EnterCriticalSection( &mmdriver_lock );
48 
49     for (lpDrv = lpDrvItemList; lpDrv != NULL; lpDrv = lpDrv->lpNextItem)
50     {
51         TRACE("%p, magic %04lx, id %p, next %p\n", lpDrv, lpDrv->dwMagic, lpDrv->d.d32.dwDriverID, lpDrv->lpNextItem);
52     }
53 
54     LeaveCriticalSection( &mmdriver_lock );
55 #endif
56 }
57 
58 /**************************************************************************
59  *			DRIVER_GetNumberOfModuleRefs		[internal]
60  *
61  * Returns the number of open drivers which share the same module.
62  */
63 static	unsigned DRIVER_GetNumberOfModuleRefs(HMODULE hModule, WINE_DRIVER** found)
64 {
65     LPWINE_DRIVER	lpDrv;
66     unsigned		count = 0;
67 
68     EnterCriticalSection( &mmdriver_lock );
69 
70     if (found) *found = NULL;
71     for (lpDrv = lpDrvItemList; lpDrv; lpDrv = lpDrv->lpNextItem)
72     {
73 	if (lpDrv->hModule == hModule)
74         {
75             if (found && !*found) *found = lpDrv;
76 	    count++;
77 	}
78     }
79 
80     LeaveCriticalSection( &mmdriver_lock );
81     return count;
82 }
83 
84 /**************************************************************************
85  *				DRIVER_FindFromHDrvr		[internal]
86  *
87  * From a hDrvr being 32 bits, returns the WINE internal structure.
88  */
89 LPWINE_DRIVER	DRIVER_FindFromHDrvr(HDRVR hDrvr)
90 {
91     LPWINE_DRIVER d;
92 
93     __TRY
94     {
95         d = (LPWINE_DRIVER)hDrvr;
96         if (d && d->dwMagic != WINE_DI_MAGIC) d = NULL;
97     }
98     __EXCEPT_PAGE_FAULT
99     {
100         return NULL;
101     }
102     __ENDTRY;
103 
104     if (d) TRACE("%p -> %p, %p\n", hDrvr, d->lpDrvProc, (void *)d->dwDriverID);
105     else TRACE("%p -> NULL\n", hDrvr);
106 
107     return d;
108 }
109 
110 /**************************************************************************
111  *				DRIVER_SendMessage		[internal]
112  */
113 static inline LRESULT DRIVER_SendMessage(LPWINE_DRIVER lpDrv, UINT msg,
114                                          LPARAM lParam1, LPARAM lParam2)
115 {
116     LRESULT		ret = 0;
117 
118     TRACE("Before call32 proc=%p drvrID=%08lx hDrv=%p wMsg=%04x p1=%08lx p2=%08lx\n",
119           lpDrv->lpDrvProc, lpDrv->dwDriverID, lpDrv, msg, lParam1, lParam2);
120     ret = lpDrv->lpDrvProc(lpDrv->dwDriverID, (HDRVR)lpDrv, msg, lParam1, lParam2);
121     TRACE("After  call32 proc=%p drvrID=%08lx hDrv=%p wMsg=%04x p1=%08lx p2=%08lx => %08lx\n",
122           lpDrv->lpDrvProc, lpDrv->dwDriverID, lpDrv, msg, lParam1, lParam2, ret);
123 
124     return ret;
125 }
126 
127 /**************************************************************************
128  *				SendDriverMessage		[WINMM.@]
129  *				DrvSendMessage			[WINMM.@]
130  */
131 LRESULT WINAPI SendDriverMessage(HDRVR hDriver, UINT msg, LPARAM lParam1,
132 				 LPARAM lParam2)
133 {
134     LPWINE_DRIVER	lpDrv;
135     LRESULT 		retval = 0;
136 
137     TRACE("(%p, %04X, %08lX, %08lX)\n", hDriver, msg, lParam1, lParam2);
138 
139     if ((lpDrv = DRIVER_FindFromHDrvr(hDriver)) != NULL) {
140 	retval = DRIVER_SendMessage(lpDrv, msg, lParam1, lParam2);
141     } else {
142 	WARN("Bad driver handle %p\n", hDriver);
143     }
144     TRACE("retval = %ld\n", retval);
145 
146     return retval;
147 }
148 
149 /**************************************************************************
150  *				DRIVER_RemoveFromList		[internal]
151  *
152  * Generates all the logic to handle driver closure / deletion
153  * Removes a driver struct to the list of open drivers.
154  */
155 static	BOOL	DRIVER_RemoveFromList(LPWINE_DRIVER lpDrv)
156 {
157     /* last of this driver in list ? */
158     if (DRIVER_GetNumberOfModuleRefs(lpDrv->hModule, NULL) == 1) {
159         DRIVER_SendMessage(lpDrv, DRV_DISABLE, 0L, 0L);
160         DRIVER_SendMessage(lpDrv, DRV_FREE,    0L, 0L);
161     }
162 
163     EnterCriticalSection( &mmdriver_lock );
164 
165     if (lpDrv->lpPrevItem)
166 	lpDrv->lpPrevItem->lpNextItem = lpDrv->lpNextItem;
167     else
168 	lpDrvItemList = lpDrv->lpNextItem;
169     if (lpDrv->lpNextItem)
170 	lpDrv->lpNextItem->lpPrevItem = lpDrv->lpPrevItem;
171     /* trash magic number */
172     lpDrv->dwMagic ^= 0xa5a5a5a5;
173     lpDrv->lpDrvProc = NULL;
174     lpDrv->dwDriverID = 0;
175 
176     LeaveCriticalSection( &mmdriver_lock );
177 
178     return TRUE;
179 }
180 
181 /**************************************************************************
182  *				DRIVER_AddToList		[internal]
183  *
184  * Adds a driver struct to the list of open drivers.
185  * Generates all the logic to handle driver creation / open.
186  */
187 static	BOOL	DRIVER_AddToList(LPWINE_DRIVER lpNewDrv, LPARAM lParam1, LPARAM lParam2)
188 {
189     lpNewDrv->dwMagic = WINE_DI_MAGIC;
190     /* First driver to be loaded for this module, need to load correctly the module */
191     /* first of this driver in list ? */
192     if (DRIVER_GetNumberOfModuleRefs(lpNewDrv->hModule, NULL) == 0) {
193         if (DRIVER_SendMessage(lpNewDrv, DRV_LOAD, 0L, 0L) != DRV_SUCCESS) {
194             TRACE("DRV_LOAD failed on driver %p\n", lpNewDrv);
195             return FALSE;
196         }
197         /* returned value is not checked */
198         DRIVER_SendMessage(lpNewDrv, DRV_ENABLE, 0L, 0L);
199     }
200 
201     /* Now just open a new instance of a driver on this module */
202     lpNewDrv->dwDriverID = DRIVER_SendMessage(lpNewDrv, DRV_OPEN, lParam1, lParam2);
203 
204     if (lpNewDrv->dwDriverID == 0)
205     {
206         TRACE("DRV_OPEN failed on driver %p\n", lpNewDrv);
207         return FALSE;
208     }
209 
210     EnterCriticalSection( &mmdriver_lock );
211 
212     lpNewDrv->lpNextItem = NULL;
213     if (lpDrvItemList == NULL) {
214 	lpDrvItemList = lpNewDrv;
215 	lpNewDrv->lpPrevItem = NULL;
216     } else {
217 	LPWINE_DRIVER	lpDrv = lpDrvItemList;	/* find end of list */
218 	while (lpDrv->lpNextItem != NULL)
219 	    lpDrv = lpDrv->lpNextItem;
220 
221 	lpDrv->lpNextItem = lpNewDrv;
222 	lpNewDrv->lpPrevItem = lpDrv;
223     }
224 
225     LeaveCriticalSection( &mmdriver_lock );
226     return TRUE;
227 }
228 
229 /**************************************************************************
230  *				DRIVER_GetLibName		[internal]
231  *
232  */
233 BOOL	DRIVER_GetLibName(LPCWSTR keyName, LPCWSTR sectName, LPWSTR buf, int sz)
234 {
235     HKEY	hKey, hSecKey;
236     DWORD	bufLen, lRet;
237     static const WCHAR wszSystemIni[] = {'S','Y','S','T','E','M','.','I','N','I',0};
238     WCHAR       wsznull = '\0';
239 
240     /* This takes us as far as Windows NT\CurrentVersion */
241     lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, HKLM_BASE, 0, KEY_QUERY_VALUE, &hKey);
242 
243     if (lRet == ERROR_SUCCESS)
244     {
245         /* Now we descend into the section name that we were given */
246 	    lRet = RegOpenKeyExW(hKey, sectName, 0, KEY_QUERY_VALUE, &hSecKey);
247 
248 	    if (lRet == ERROR_SUCCESS)
249         {
250             /* Retrieve the desired value - this is the filename of the lib */
251             bufLen = sz;
252 	        lRet = RegQueryValueExW(hSecKey, keyName, 0, 0, (void*)buf, &bufLen);
253 	        RegCloseKey( hSecKey );
254 	    }
255 
256         RegCloseKey( hKey );
257     }
258 
259     /* Finish up if we've got what we want from the registry */
260     if (lRet == ERROR_SUCCESS)
261         return TRUE;
262 
263     /* default to system.ini if we can't find it in the registry,
264      * to support native installations where system.ini is still used */
265     return GetPrivateProfileStringW(sectName, keyName, &wsznull, buf, sz / sizeof(WCHAR), wszSystemIni);
266 }
267 
268 /**************************************************************************
269  *				DRIVER_TryOpenDriver32		[internal]
270  *
271  * Tries to load a 32 bit driver whose DLL's (module) name is fn
272  */
273 LPWINE_DRIVER	DRIVER_TryOpenDriver32(LPCWSTR fn, LPARAM lParam2)
274 {
275     LPWINE_DRIVER 	lpDrv = NULL;
276     HMODULE		hModule = 0;
277     LPWSTR		ptr;
278     LPCSTR		cause = 0;
279 
280     TRACE("(%s, %08lX);\n", debugstr_w(fn), lParam2);
281 
282     if ((ptr = strchrW(fn, ' ')) != NULL)
283     {
284         *ptr++ = '\0';
285 
286         while (*ptr == ' ')
287             ptr++;
288 
289         if (*ptr == '\0')
290             ptr = NULL;
291     }
292 
293     lpDrv = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_DRIVER));
294 
295     if (lpDrv == NULL)
296     {
297         cause = "OOM";
298         goto exit;
299     }
300 
301     if ((hModule = LoadLibraryW(fn)) == 0)
302     {
303         cause = "Not a 32 bit lib";
304         goto exit;
305     }
306 
307     lpDrv->lpDrvProc = (DRIVERPROC)GetProcAddress(hModule, "DriverProc");
308 
309     if (lpDrv->lpDrvProc == NULL)
310     {
311         cause = "no DriverProc";
312         goto exit;
313     }
314 
315     lpDrv->dwFlags          = 0;
316     lpDrv->hModule    = hModule;
317     lpDrv->dwDriverID = 0;
318 
319     /* Win32 installable drivers must support a two phase opening scheme:
320      * + first open with NULL as lParam2 (session instance),
321      * + then do a second open with the real non null lParam2)
322      */
323     if (DRIVER_GetNumberOfModuleRefs(lpDrv->hModule, NULL) == 0 && lParam2)
324     {
325         LPWINE_DRIVER   ret;
326 
327         if (!DRIVER_AddToList(lpDrv, (LPARAM)ptr, 0L))
328         {
329             cause = "load0 failed";
330             goto exit;
331         }
332         ret = DRIVER_TryOpenDriver32(fn, lParam2);
333         if (!ret)
334         {
335             CloseDriver((HDRVR)lpDrv, 0L, 0L);
336             cause = "load1 failed";
337             goto exit;
338         }
339         return ret;
340     }
341 
342     if (!DRIVER_AddToList(lpDrv, (LPARAM)ptr, lParam2))
343     {
344         cause = "load failed";
345         goto exit;
346     }
347 
348     TRACE("=> %p\n", lpDrv);
349     return lpDrv;
350 
351  exit:
352     FreeLibrary(hModule);
353     HeapFree(GetProcessHeap(), 0, lpDrv);
354     TRACE("Unable to load 32 bit module %s: %s\n", debugstr_w(fn), cause);
355     return NULL;
356 }
357 
358 /**************************************************************************
359  *				OpenDriverA		        [WINMM.@]
360  *				DrvOpenA			[WINMM.@]
361  * (0,1,DRV_LOAD  ,0       ,0)
362  * (0,1,DRV_ENABLE,0       ,0)
363  * (0,1,DRV_OPEN  ,buf[256],0)
364  */
365 HDRVR WINAPI OpenDriverA(LPCSTR lpDriverName, LPCSTR lpSectionName, LPARAM lParam)
366 {
367     INT                 len;
368     LPWSTR 		dn = NULL;
369     LPWSTR 		sn = NULL;
370     HDRVR		ret = 0;
371 
372     if (lpDriverName)
373     {
374         len = MultiByteToWideChar( CP_ACP, 0, lpDriverName, -1, NULL, 0 );
375         dn = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
376         if (!dn) goto done;
377         MultiByteToWideChar( CP_ACP, 0, lpDriverName, -1, dn, len );
378     }
379 
380     if (lpSectionName)
381     {
382         len = MultiByteToWideChar( CP_ACP, 0, lpSectionName, -1, NULL, 0 );
383         sn = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
384         if (!sn) goto done;
385         MultiByteToWideChar( CP_ACP, 0, lpSectionName, -1, sn, len );
386     }
387 
388     ret = OpenDriver(dn, sn, lParam);
389 
390 done:
391     HeapFree(GetProcessHeap(), 0, dn);
392     HeapFree(GetProcessHeap(), 0, sn);
393     return ret;
394 }
395 
396 /**************************************************************************
397  *				OpenDriver 		        [WINMM.@]
398  *				DrvOpen				[WINMM.@]
399  */
400 HDRVR WINAPI OpenDriver(LPCWSTR lpDriverName, LPCWSTR lpSectionName, LPARAM lParam)
401 {
402     LPWINE_DRIVER	lpDrv = NULL;
403     WCHAR 		libName[128];
404     LPCWSTR		lsn = lpSectionName;
405 
406     TRACE("(%s, %s, 0x%08lx);\n",
407           debugstr_w(lpDriverName), debugstr_w(lpSectionName), lParam);
408 
409     /* If no section name is specified, either the caller is intending on
410        opening a driver by filename, or wants to open a user-installable
411        driver that has an entry in the Drivers32 key in the registry */
412     if (lsn == NULL)
413     {
414         /* Default registry key */
415         static const WCHAR wszDrivers32[] = {'D','r','i','v','e','r','s','3','2',0};
416 
417         lstrcpynW(libName, lpDriverName, sizeof(libName) / sizeof(WCHAR));
418 
419         /* Try and open the driver by filename */
420         if ( (lpDrv = DRIVER_TryOpenDriver32(libName, lParam)) )
421             goto the_end;
422 
423         /* If we got here, the file wasn't found. So we assume the caller
424            wanted a driver specified under the Drivers32 registry key */
425         lsn = wszDrivers32;
426     }
427 
428     /* Attempt to locate the driver filename in the registry */
429     if ( DRIVER_GetLibName(lpDriverName, lsn, libName, sizeof(libName)) )
430     {
431         /* Now we have the filename, we can try and load it */
432         if ( (lpDrv = DRIVER_TryOpenDriver32(libName, lParam)) )
433             goto the_end;
434     }
435 
436     /* now we will try a 16 bit driver (and add all the glue to make it work... which
437      * is located in our mmsystem implementation)
438      * so ensure, we can load our mmsystem, otherwise just fail
439      */
440     WINMM_CheckForMMSystem();
441 #if 0
442     if (pFnOpenDriver16 &&
443         (lpDrv = pFnOpenDriver16(lpDriverName, lpSectionName, lParam)))
444     {
445         if (DRIVER_AddToList(lpDrv, 0, lParam)) goto the_end;
446         HeapFree(GetProcessHeap(), 0, lpDrv);
447     }
448     TRACE("Failed to open driver %s from system.ini file, section %s\n",
449           debugstr_w(lpDriverName), debugstr_w(lpSectionName));
450 #endif
451     return 0;
452 
453  the_end:
454     if (lpDrv)	TRACE("=> %p\n", lpDrv);
455     return (HDRVR)lpDrv;
456 }
457 
458 /**************************************************************************
459  *			CloseDriver				[WINMM.@]
460  *			DrvClose				[WINMM.@]
461  */
462 LRESULT WINAPI CloseDriver(HDRVR hDrvr, LPARAM lParam1, LPARAM lParam2)
463 {
464     BOOL ret;
465     LPWINE_DRIVER	lpDrv;
466 
467     TRACE("(%p, %08lX, %08lX);\n", hDrvr, lParam1, lParam2);
468 
469     DRIVER_Dump("BEFORE:");
470 
471     if ((lpDrv = DRIVER_FindFromHDrvr(hDrvr)) != NULL)
472     {
473         LPWINE_DRIVER lpDrv0;
474 
475         DRIVER_SendMessage(lpDrv, DRV_CLOSE, lParam1, lParam2);
476 
477         DRIVER_RemoveFromList(lpDrv);
478 
479         if (lpDrv->dwFlags & WINE_GDF_SESSION)
480             FIXME("WINE_GDF_SESSION: Shouldn't happen (%p)\n", lpDrv);
481         /* if driver has an opened session instance, we have to close it too */
482         if (DRIVER_GetNumberOfModuleRefs(lpDrv->hModule, &lpDrv0) == 1 &&
483             (lpDrv0->dwFlags & WINE_GDF_SESSION))
484         {
485             DRIVER_SendMessage(lpDrv0, DRV_CLOSE, 0, 0);
486             DRIVER_RemoveFromList(lpDrv0);
487             FreeLibrary(lpDrv0->hModule);
488             HeapFree(GetProcessHeap(), 0, lpDrv0);
489         }
490         FreeLibrary(lpDrv->hModule);
491 
492         HeapFree(GetProcessHeap(), 0, lpDrv);
493         ret = TRUE;
494     }
495     else
496     {
497         WARN("Failed to close driver\n");
498         ret = FALSE;
499     }
500 
501     DRIVER_Dump("AFTER:");
502 
503     return ret;
504 }
505 
506 /**************************************************************************
507  *				GetDriverFlags		[WINMM.@]
508  * [in] hDrvr handle to the driver
509  *
510  * Returns:
511  *	0x00000000 if hDrvr is an invalid handle
512  *	0x80000000 if hDrvr is a valid 32 bit driver
513  *	0x90000000 if hDrvr is a valid 16 bit driver
514  *
515  * native WINMM doesn't return those flags
516  *	0x80000000 for a valid 32 bit driver and that's it
517  *	(I may have mixed up the two flags :-(
518  */
519 DWORD	WINAPI GetDriverFlags(HDRVR hDrvr)
520 {
521     LPWINE_DRIVER 	lpDrv;
522     DWORD		ret = 0;
523 
524     TRACE("(%p)\n", hDrvr);
525 
526     if ((lpDrv = DRIVER_FindFromHDrvr(hDrvr)) != NULL) {
527 	ret = WINE_GDF_EXIST | (lpDrv->dwFlags & WINE_GDF_EXTERNAL_MASK);
528     }
529     return ret;
530 }
531 
532 /**************************************************************************
533  *				GetDriverModuleHandle	[WINMM.@]
534  *				DrvGetModuleHandle	[WINMM.@]
535  */
536 HMODULE WINAPI GetDriverModuleHandle(HDRVR hDrvr)
537 {
538     LPWINE_DRIVER 	lpDrv;
539     HMODULE		hModule = 0;
540 
541     TRACE("(%p);\n", hDrvr);
542 
543     if ((lpDrv = DRIVER_FindFromHDrvr(hDrvr)) != NULL) {
544         hModule = lpDrv->hModule;
545     }
546     TRACE("=> %p\n", hModule);
547     return hModule;
548 }
549 
550 /**************************************************************************
551  * 				DefDriverProc			  [WINMM.@]
552  * 				DrvDefDriverProc		  [WINMM.@]
553  */
554 LRESULT WINAPI DefDriverProc(DWORD_PTR dwDriverIdentifier, HDRVR hDrv,
555 			     UINT Msg, LPARAM lParam1, LPARAM lParam2)
556 {
557     switch (Msg) {
558     case DRV_LOAD:
559     case DRV_FREE:
560     case DRV_ENABLE:
561     case DRV_DISABLE:
562         return 1;
563     case DRV_INSTALL:
564     case DRV_REMOVE:
565         return DRV_SUCCESS;
566     default:
567         return 0;
568     }
569 }
570 
571 /**************************************************************************
572  *				DRIVER_getCallback		[internal]
573  */
574 static const char* DRIVER_getCallback(DWORD uFlags)
575 {
576     switch(uFlags & DCB_TYPEMASK) {
577     case DCB_NULL:     return "null";
578     case DCB_WINDOW:   return "window";
579     case DCB_TASK:     return "task";
580     case DCB_EVENT:    return "event";
581     case DCB_FUNCTION: return "32bit function";
582     default:           return "UNKNOWN";
583     }
584 }
585 
586 /**************************************************************************
587  * 				DriverCallback			[WINMM.@]
588  */
589 BOOL WINAPI DriverCallback(DWORD_PTR dwCallBack, DWORD uFlags, HDRVR hDev,
590 			   DWORD wMsg, DWORD_PTR dwUser, DWORD_PTR dwParam1,
591 			   DWORD_PTR dwParam2)
592 {
593     BOOL ret = FALSE;
594     TRACE("(%08lX, %s %04X, %p, %04X, %08lX, %08lX, %08lX)\n",
595 	  dwCallBack, DRIVER_getCallback(uFlags), uFlags, hDev, wMsg, dwUser, dwParam1, dwParam2);
596     if (!dwCallBack)
597 	return ret;
598 
599     switch (uFlags & DCB_TYPEMASK) {
600     case DCB_NULL:
601 	/* Native returns FALSE = no notification, not TRUE */
602 	return ret;
603     case DCB_WINDOW:
604 	ret = PostMessageA((HWND)dwCallBack, wMsg, (WPARAM)hDev, dwParam1);
605 	break;
606     case DCB_TASK: /* aka DCB_THREAD */
607 	ret = PostThreadMessageA(dwCallBack, wMsg, (WPARAM)hDev, dwParam1);
608 	break;
609     case DCB_FUNCTION:
610 	((LPDRVCALLBACK)dwCallBack)(hDev, wMsg, dwUser, dwParam1, dwParam2);
611 	ret = TRUE;
612 	break;
613     case DCB_EVENT:
614 	ret = SetEvent((HANDLE)dwCallBack);
615 	break;
616 #if 0
617         /* FIXME: for now only usable in mmsystem.dll16
618          * If needed, should be enabled back
619          */
620     case 6: /* I would dub it DCB_MMTHREADSIGNAL */
621 	/* this is an undocumented DCB_ value used for mmThreads
622 	 * loword of dwCallBack contains the handle of the lpMMThd block
623 	 * which dwSignalCount has to be incremented
624 	 */
625         if (pFnGetMMThread16)
626 	{
627 	    WINE_MMTHREAD*	lpMMThd = pFnGetMMThread16(LOWORD(dwCallBack));
628 
629 	    TRACE("mmThread (%04x, %p) !\n", LOWORD(dwCallBack), lpMMThd);
630 	    /* same as mmThreadSignal16 */
631 	    InterlockedIncrement(&lpMMThd->dwSignalCount);
632 	    SetEvent(lpMMThd->hEvent);
633 	    /* some other stuff on lpMMThd->hVxD */
634 	}
635 	break;
636 #endif
637 #if 0
638     case 4:
639 	/* this is an undocumented DCB_ value for... I don't know */
640 	break;
641 #endif
642     default:
643 	WARN("Unknown callback type %d\n", uFlags & DCB_TYPEMASK);
644 	return FALSE;
645     }
646     if (ret)
647 	TRACE("Done\n");
648     else
649 	WARN("Notification failure\n");
650     return ret;
651 }
652 
653 /******************************************************************
654  *		DRIVER_UnloadAll
655  *
656  *
657  */
658 void    DRIVER_UnloadAll(void)
659 {
660     LPWINE_DRIVER 	lpDrv;
661     LPWINE_DRIVER 	lpNextDrv = NULL;
662     unsigned            count = 0;
663 
664 restart:
665     EnterCriticalSection( &mmdriver_lock );
666 
667     for (lpDrv = lpDrvItemList; lpDrv != NULL; lpDrv = lpNextDrv)
668     {
669         lpNextDrv = lpDrv->lpNextItem;
670 
671         /* session instances will be unloaded automatically */
672         if (!(lpDrv->dwFlags & WINE_GDF_SESSION))
673         {
674             LeaveCriticalSection( &mmdriver_lock );
675             CloseDriver((HDRVR)lpDrv, 0, 0);
676             count++;
677             /* restart from the beginning of the list */
678             goto restart;
679         }
680     }
681 
682     LeaveCriticalSection( &mmdriver_lock );
683 
684     TRACE("Unloaded %u drivers\n", count);
685 }
686