* Sync up to trunk head (r65120).
[reactos.git] / base / services / audiosrv / pnp.c
1 /*
2 * PROJECT: ReactOS
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/services/audiosrv/pnp.c
5 * PURPOSE: Audio Service Plug and Play
6 * COPYRIGHT: Copyright 2007 Andrew Greenwood
7 */
8
9 #include "audiosrv.h"
10
11 #include <winreg.h>
12 #include <winuser.h>
13 #include <mmsystem.h>
14 #include <setupapi.h>
15 #include <ksmedia.h>
16
17 static HDEVNOTIFY device_notification_handle = NULL;
18
19 /*
20 Finds all devices within the KSCATEGORY_AUDIO category and puts them
21 in the shared device list.
22 */
23
24 BOOL
25 ProcessExistingDevices()
26 {
27 SP_DEVICE_INTERFACE_DATA interface_data;
28 SP_DEVINFO_DATA device_data;
29 PSP_DEVICE_INTERFACE_DETAIL_DATA_W detail_data;
30 HDEVINFO dev_info;
31 DWORD length;
32 int index = 0;
33
34 const GUID category_guid = {STATIC_KSCATEGORY_AUDIO};
35
36 dev_info = SetupDiGetClassDevsExW(&category_guid,
37 NULL,
38 NULL,
39 DIGCF_PRESENT | DIGCF_DEVICEINTERFACE,
40 NULL,
41 NULL,
42 NULL);
43
44 /* printf("%s:\n", ClassString); */
45
46 interface_data.cbSize = sizeof(interface_data);
47 interface_data.Reserved = 0;
48
49 /* Enumerate the devices within the category */
50 index = 0;
51
52 length = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA)
53 + (MAX_PATH * sizeof(WCHAR));
54
55 detail_data =
56 (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)HeapAlloc(GetProcessHeap(),
57 0,
58 length);
59
60 if ( ! detail_data )
61 {
62 logmsg("ProcessExistingDevices() failed to allocate detail_data\n");
63 return TRUE;
64 }
65
66 while (
67 SetupDiEnumDeviceInterfaces(dev_info,
68 NULL,
69 &category_guid,
70 index,
71 &interface_data) )
72 {
73 PnP_AudioDevice* list_node;
74
75 ZeroMemory(detail_data, length);
76
77 /* NOTE: We don't actually use device_data... */
78 detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
79 device_data.cbSize = sizeof(device_data);
80 device_data.Reserved = 0;
81 SetupDiGetDeviceInterfaceDetailW(dev_info,
82 &interface_data,
83 detail_data,
84 length,
85 NULL,
86 &device_data);
87
88 list_node = CreateDeviceDescriptor(detail_data->DevicePath, TRUE);
89 AppendAudioDeviceToList(list_node);
90 DestroyDeviceDescriptor(list_node);
91
92 /* TODO: Cleanup the device we enumerated? */
93
94 index ++;
95 };
96
97 HeapFree(GetProcessHeap(), 0, detail_data);
98
99 SetupDiDestroyDeviceInfoList(dev_info);
100
101 return TRUE;
102 }
103
104
105 /*
106 Add new devices to the list as they arrive.
107 */
108
109 DWORD
110 ProcessDeviceArrival(DEV_BROADCAST_DEVICEINTERFACE* device)
111 {
112 PnP_AudioDevice* list_node;
113 list_node = CreateDeviceDescriptor(device->dbcc_name, TRUE);
114 AppendAudioDeviceToList(list_node);
115 DestroyDeviceDescriptor(list_node);
116
117 return NO_ERROR;
118 }
119
120
121 /*
122 Request notification of device additions/removals.
123 */
124
125 BOOL
126 RegisterForDeviceNotifications()
127 {
128 DEV_BROADCAST_DEVICEINTERFACE notification_filter;
129
130 const GUID wdmaud_guid = {STATIC_KSCATEGORY_AUDIO};
131
132 ZeroMemory(&notification_filter, sizeof(notification_filter));
133 notification_filter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
134 notification_filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
135 notification_filter.dbcc_classguid = wdmaud_guid;
136
137 device_notification_handle =
138 RegisterDeviceNotificationW((HANDLE) service_status_handle,
139 &notification_filter,
140 DEVICE_NOTIFY_SERVICE_HANDLE
141 /* |
142 DEVICE_NOTIFY_ALL_INTERFACE_CLASSES*/);
143
144 if ( ! device_notification_handle )
145 {
146 logmsg("RegisterDeviceNotification() failed with error %d\n", GetLastError());
147 }
148
149 return ( device_notification_handle != NULL );
150 }
151
152
153 /*
154 When we're not interested in device notifications any more, this gets
155 called.
156 */
157
158 VOID UnregisterDeviceNotifications()
159 {
160 /* TODO -- NOT IMPLEMENTED! */
161
162 if ( device_notification_handle )
163 {
164 /* TODO */
165 device_notification_handle = NULL;
166 }
167 }
168
169
170 /*
171 Device events from the main service handler get passed to this.
172 */
173
174 DWORD
175 HandleDeviceEvent(
176 DWORD dwEventType,
177 LPVOID lpEventData)
178 {
179 switch ( dwEventType )
180 {
181 case DBT_DEVICEARRIVAL :
182 {
183 DEV_BROADCAST_DEVICEINTERFACE* incoming_device =
184 (DEV_BROADCAST_DEVICEINTERFACE*) lpEventData;
185
186 return ProcessDeviceArrival(incoming_device);
187 }
188
189 default :
190 {
191 break;
192 }
193 }
194
195 return NO_ERROR;
196 }