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