1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     FxDeviceInterfaceAPI.cpp
8 
9 Abstract:
10 
11     This module implements the device interface object external APIs
12 
13 Author:
14 
15 
16 
17 
18 Environment:
19 
20     kernel and user mode
21 
22 Revision History:
23 
24 --*/
25 
26 #include "fxsupportpch.hpp"
27 
28 extern "C" {
29 // #include "FxDeviceInterfaceAPI.tmh"
30 }
31 
32 //
33 // extern "C" the entire file
34 //
35 extern "C" {
36 
37 _Must_inspect_result_
38 __drv_maxIRQL(PASSIVE_LEVEL)
39 NTSTATUS
40 STDCALL
41 WDFEXPORT(WdfDeviceCreateDeviceInterface)(
42     __in
43     PWDF_DRIVER_GLOBALS DriverGlobals,
44     __in
45     WDFDEVICE Device,
46     __in
47     CONST GUID *InterfaceClassGUID,
48     __in_opt
49     PCUNICODE_STRING ReferenceString
50     )
51 /*++
52 
53 Routine Description:
54     Creates a device interface associated with the passed in device object
55 
56 Arguments:
57     Device - Handle which represents the device exposing the interface
58 
59     InterfaceGUID - GUID describing the interface being exposed
60 
61     ReferenceString - OPTIONAL string which allows the driver writer to
62         distinguish between different exposed interfaces
63 
64 Return Value:
65     STATUS_SUCCESS or appropriate NTSTATUS code
66 
67   --*/
68 {
69     DDI_ENTRY();
70 
71     SINGLE_LIST_ENTRY **ppPrev, *pCur;
72     PFX_DRIVER_GLOBALS pFxDriverGlobals;
73     FxDeviceInterface *pDeviceInterface;
74     FxDevice *pDevice;
75     FxPkgPnp* pPkgPnp;
76     NTSTATUS status;
77 
78     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
79                                    Device,
80                                    FX_TYPE_DEVICE,
81                                    (PVOID*) &pDevice,
82                                    &pFxDriverGlobals);
83 
84     FxPointerNotNull(pFxDriverGlobals, InterfaceClassGUID);
85 
86     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
87     if (!NT_SUCCESS(status)) {
88         return status;
89     }
90 
91     if (ReferenceString != NULL) {
92         status = FxValidateUnicodeString(pFxDriverGlobals, ReferenceString);
93         if (!NT_SUCCESS(status)) {
94             return status;
95         }
96     }
97 
98     if (pDevice->IsLegacy()) {
99         status = STATUS_INVALID_DEVICE_REQUEST;
100 
101         DoTraceLevelMessage(
102             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
103             "WDFDEVICE %p is not a PNP device, device interface creation not "
104             "allowed %!STATUS!", Device, status);
105 
106         return status;
107     }
108 
109     pDeviceInterface = new(pFxDriverGlobals, PagedPool) FxDeviceInterface();
110 
111     if (pDeviceInterface == NULL) {
112         status = STATUS_INSUFFICIENT_RESOURCES;
113 
114         DoTraceLevelMessage(
115             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
116             "WDFDEVICE %p DeviceInterface object creation failed, %!STATUS!",
117             Device, status);
118 
119         return status;
120     }
121 
122     status = pDeviceInterface->Initialize(pFxDriverGlobals,
123                                           InterfaceClassGUID,
124                                           ReferenceString);
125 
126     if (!NT_SUCCESS(status)) {
127         DoTraceLevelMessage(
128             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
129             "WDFDEVICE %p, DeviceInterface object initialization failed, %!STATUS!",
130             Device, status );
131 
132         goto Done;
133     }
134 
135     pPkgPnp = pDevice->m_PkgPnp;
136 
137     pPkgPnp->m_DeviceInterfaceLock.AcquireLock(pFxDriverGlobals);
138 
139     status = pDeviceInterface->Register(pDevice);
140 
141     if (NT_SUCCESS(status)) {
142         //
143         // Insert into the end of the list
144         //
145         ppPrev = &pPkgPnp->m_DeviceInterfaceHead.Next;
146         pCur = pPkgPnp->m_DeviceInterfaceHead.Next;
147         while (pCur != NULL) {
148             ppPrev = &pCur->Next;
149             pCur = pCur->Next;
150         }
151 
152         *ppPrev = &pDeviceInterface->m_Entry;
153     }
154 
155     pPkgPnp->m_DeviceInterfaceLock.ReleaseLock(pFxDriverGlobals);
156 
157 Done:
158     if (!NT_SUCCESS(status)) {
159         delete pDeviceInterface;
160         pDeviceInterface = NULL;
161     }
162 
163     return status;
164 }
165 
166 __drv_maxIRQL(PASSIVE_LEVEL)
167 VOID
168 STDCALL
169 WDFEXPORT(WdfDeviceSetDeviceInterfaceState)(
170     __in
171     PWDF_DRIVER_GLOBALS DriverGlobals,
172     __in
173     WDFDEVICE Device,
174     __in
175     CONST GUID *InterfaceClassGUID,
176     __in_opt
177     PCUNICODE_STRING RefString,
178     __in
179     BOOLEAN State
180     )
181 {
182     DDI_ENTRY();
183 
184     PSINGLE_LIST_ENTRY ple;
185     PFX_DRIVER_GLOBALS pFxDriverGlobals;
186     NTSTATUS status;
187     FxDevice* pDevice;
188     FxPkgPnp* pPkgPnp;
189 
190     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
191                                    Device,
192                                    FX_TYPE_DEVICE,
193                                    (PVOID*) &pDevice,
194                                    &pFxDriverGlobals);
195 
196     FxPointerNotNull(pFxDriverGlobals, InterfaceClassGUID);
197 
198     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
199     if (!NT_SUCCESS(status)) {
200         FxVerifierDbgBreakPoint(pFxDriverGlobals);
201         return;
202     }
203 
204     if (RefString != NULL) {
205         status = FxValidateUnicodeString(pFxDriverGlobals, RefString);
206         if (!NT_SUCCESS(status)) {
207             FxVerifierDbgBreakPoint(pFxDriverGlobals);
208             return;
209         }
210     }
211 
212     if (pDevice->IsLegacy()) {
213         DoTraceLevelMessage(
214             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
215             "WDFDEVICE %p is not a PNP device, device interfaces not allowed",
216             Device);
217         FxVerifierDbgBreakPoint(pFxDriverGlobals);
218         return;
219     }
220 
221     pPkgPnp = pDevice->m_PkgPnp;
222 
223     pPkgPnp->m_DeviceInterfaceLock.AcquireLock(pFxDriverGlobals);
224 
225     //
226     // Iterate over the interfaces and see if we have a match
227     //
228     for (ple = pPkgPnp->m_DeviceInterfaceHead.Next; ple != NULL; ple = ple->Next) {
229         FxDeviceInterface *pDI;
230 
231         pDI = FxDeviceInterface::_FromEntry(ple);
232 
233         if (FxIsEqualGuid(&pDI->m_InterfaceClassGUID, InterfaceClassGUID)) {
234             if (RefString != NULL) {
235                 if ((RefString->Length == pDI->m_ReferenceString.Length)
236                     &&
237                     (RtlCompareMemory(RefString->Buffer,
238                                       pDI->m_ReferenceString.Buffer,
239                                       RefString->Length) == RefString->Length)) {
240                     //
241                     // They match, carry on
242                     //
243                     DO_NOTHING();
244                 }
245                 else {
246                     //
247                     // The ref strings do not match, continue on in the search
248                     // of the collection.
249                     //
250                     continue;
251                 }
252             }
253             else if (pDI->m_ReferenceString.Length > 0) {
254                 //
255                 // Caller didn't specify a ref string but this interface has
256                 // one, continue on in the search through the collection.
257                 //
258                 continue;
259             }
260 
261             //
262             // Set the state and break out of the loop because we found our
263             // interface.
264             //
265             pDI->SetState(State);
266             break;
267         }
268     }
269 
270     pPkgPnp->m_DeviceInterfaceLock.ReleaseLock(pFxDriverGlobals);
271 }
272 
273 _Must_inspect_result_
274 __drv_maxIRQL(PASSIVE_LEVEL)
275 NTSTATUS
276 STDCALL
277 WDFEXPORT(WdfDeviceRetrieveDeviceInterfaceString)(
278     __in
279     PWDF_DRIVER_GLOBALS DriverGlobals,
280     __in
281     WDFDEVICE Device,
282     __in
283     CONST GUID* InterfaceClassGUID,
284     __in_opt
285     PCUNICODE_STRING RefString,
286     __in
287     WDFSTRING String
288     )
289 /*++
290 
291 Routine Description:
292     Returns the symbolic link value of the registered device interface.
293 
294 Arguments:
295 
296 
297 Return Value:
298 
299 
300   --*/
301 
302 {
303     DDI_ENTRY();
304 
305     PSINGLE_LIST_ENTRY ple;
306     PFX_DRIVER_GLOBALS pFxDriverGlobals;
307     FxDevice* pDevice;
308     FxPkgPnp* pPkgPnp;
309     FxString* pString;
310     NTSTATUS status;
311 
312     FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
313                                    Device,
314                                    FX_TYPE_DEVICE,
315                                    (PVOID*) &pDevice,
316                                    &pFxDriverGlobals );
317 
318     FxPointerNotNull(pFxDriverGlobals, InterfaceClassGUID);
319 
320     status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL);
321     if (!NT_SUCCESS(status)) {
322         return status;
323     }
324 
325     if (RefString != NULL) {
326         status = FxValidateUnicodeString(pFxDriverGlobals, RefString);
327         if (!NT_SUCCESS(status)) {
328             return status;
329         }
330     }
331 
332     if (pDevice->IsLegacy()) {
333         status = STATUS_INVALID_DEVICE_REQUEST;
334 
335         DoTraceLevelMessage(
336             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR,
337             "WDFDEVICE %p is not a PNP device, device interface creation not "
338             "allowed %!STATUS!", Device, status);
339 
340         return status;
341     }
342 
343     FxObjectHandleGetPtr(pFxDriverGlobals,
344                          String,
345                          FX_TYPE_STRING,
346                          (PVOID*) &pString);
347 
348     pPkgPnp = pDevice->m_PkgPnp;
349 
350     status = STATUS_OBJECT_NAME_NOT_FOUND;
351 
352     pPkgPnp->m_DeviceInterfaceLock.AcquireLock(pFxDriverGlobals);
353 
354     //
355     // Iterate over the interfaces and see if we have a match
356     //
357     for (ple = pPkgPnp->m_DeviceInterfaceHead.Next;
358          ple != NULL;
359          ple = ple->Next) {
360         FxDeviceInterface *pDI;
361 
362         pDI = FxDeviceInterface::_FromEntry(ple);
363 
364         if (FxIsEqualGuid(&pDI->m_InterfaceClassGUID, InterfaceClassGUID)) {
365             if (RefString != NULL) {
366                 if ((RefString->Length == pDI->m_ReferenceString.Length)
367                     &&
368                     (RtlCompareMemory(RefString->Buffer,
369                                       pDI->m_ReferenceString.Buffer,
370                                       RefString->Length) == RefString->Length)) {
371                     //
372                     // They match, carry on
373                     //
374                     DO_NOTHING();
375                 }
376                 else {
377                     //
378                     // The ref strings do not match, continue on in the search
379                     // of the collection.
380                     //
381                     continue;
382                 }
383             }
384             else if (pDI->m_ReferenceString.Length > 0) {
385                 //
386                 // Caller didn't specify a ref string but this interface has
387                 // one, continue on in the search through the collection.
388                 //
389                 continue;
390             }
391 
392             status = pDI->GetSymbolicLinkName(pString);
393 
394             break;
395         }
396     }
397 
398     pPkgPnp->m_DeviceInterfaceLock.ReleaseLock(pFxDriverGlobals);
399 
400     return status;
401 }
402 
403 } // extern "C"
404