1 /*++
2
3 Copyright (c) Microsoft Corporation
4
5 Module Name:
6
7 FxResourceCollection.cpp
8
9 Abstract:
10
11 This module implements a base object for derived collection classes and
12 the derived collection classes.
13
14 Author:
15
16
17
18 Environment:
19
20 User mode only
21
22 Revision History:
23
24 --*/
25
26 #include "FxSupportPch.hpp"
27 #include <intsafe.h>
28
29 #if defined(EVENT_TRACING)
30 // Tracing support
31 extern "C" {
32 #include "FxResourceCollectionUm.tmh"
33 }
34 #endif
35
~FxCmResList()36 FxCmResList::~FxCmResList()
37 {
38 DeleteRegisterResourceTable();
39 DeletePortResourceTable();
40 }
41
42 NTSTATUS
BuildRegisterResourceTable(VOID)43 FxCmResList::BuildRegisterResourceTable(
44 VOID
45 )
46 {
47 ULONG count;
48 ULONG i, index;
49 PCM_PARTIAL_RESOURCE_DESCRIPTOR desc;
50 ULONG numRegisterDesc;
51 BOOLEAN locked = FALSE;
52 NTSTATUS status;
53
54 count = GetCount();
55 numRegisterDesc = 0;
56
57 //
58 // count number of register descriptors
59 //
60 for (i = 0; i < count; i++) {
61 desc = GetDescriptor(i);
62 if (desc == NULL) {
63 status = STATUS_INVALID_DEVICE_STATE;
64 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
65 "Resource Descriptor not found %!STATUS!", status);
66 goto exit;
67 }
68
69 if (desc->Type == CmResourceTypeMemory ||
70 desc->Type == CmResourceTypeMemoryLarge) {
71 numRegisterDesc++;
72 }
73 }
74
75 if (numRegisterDesc == 0) {
76 return STATUS_SUCCESS;
77 }
78
79 //
80 // allocate table
81 //
82 LockResourceTable();
83 locked = TRUE;
84
85 status = FxRegisterResourceInfo::_CreateAndInit(
86 GetDriverGlobals(),
87 numRegisterDesc,
88 &m_RegisterResourceTable
89 );
90 if (!NT_SUCCESS(status)) {
91 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
92 "Failed to allocate memory for resource table"
93 " %!STATUS!", status);
94 goto exit;
95 }
96 m_RegisterResourceTableSizeCe = numRegisterDesc;
97
98 //
99 // Populate table
100 //
101 index = 0;
102 for (i = 0; i < count; i++) {
103 desc = GetDescriptor(i);
104 if (desc == NULL) {
105 status = STATUS_INVALID_DEVICE_STATE;
106 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
107 "Resource Descriptor not found %!STATUS!", status);
108 goto exit;
109 }
110
111 if (desc->Type == CmResourceTypeMemory ||
112 desc->Type == CmResourceTypeMemoryLarge) {
113 SIZE_T len;
114 PHYSICAL_ADDRESS pa;
115
116 //
117 // This will populate Length and StartPa
118 //
119 len = GetResourceLength(desc, &pa);
120 if (len) {
121 m_RegisterResourceTable[index].SetPhysicalAddress(pa, len);
122 }
123
124 index++;
125 }
126 }
127
128 exit:
129
130 if (!NT_SUCCESS(status)) {
131 if (m_RegisterResourceTable != NULL) {
132 delete [] m_RegisterResourceTable;
133 m_RegisterResourceTable = NULL;
134 m_RegisterResourceTableSizeCe = 0;
135 }
136 }
137
138 if (locked) {
139 UnlockResourceTable();
140 }
141
142 return status;
143 }
144
145 NTSTATUS
BuildPortResourceTable(VOID)146 FxCmResList::BuildPortResourceTable(
147 VOID
148 )
149 {
150 ULONG count;
151 ULONG i, index;
152 PCM_PARTIAL_RESOURCE_DESCRIPTOR desc;
153 ULONG numPortDesc;
154 BOOLEAN locked = FALSE;
155 NTSTATUS status;
156
157 count = GetCount();
158 numPortDesc = 0;
159
160 //
161 // count number of register descriptors
162 //
163 for (i = 0; i < count; i++) {
164 desc = GetDescriptor(i);
165 if (desc == NULL) {
166 status = STATUS_INVALID_DEVICE_STATE;
167 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
168 "Resource Descriptor not found %!STATUS!", status);
169 goto exit;
170 }
171
172 if (desc->Type == CmResourceTypePort) {
173 numPortDesc++;
174 }
175 }
176
177 if (numPortDesc == 0) {
178 return STATUS_SUCCESS;
179 }
180
181 //
182 // allocate table
183 //
184 LockResourceTable();
185 locked = TRUE;
186
187 status = FxPortResourceInfo::_CreateAndInit(
188 GetDriverGlobals(),
189 numPortDesc,
190 &m_PortResourceTable
191 );
192 if (!NT_SUCCESS(status)) {
193 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
194 "Failed to allocate memory for resource table"
195 " %!STATUS!", status);
196 goto exit;
197 }
198 m_PortResourceTableSizeCe = numPortDesc;
199
200 //
201 // Populate table
202 //
203 index = 0;
204 for (i = 0; i < count; i++) {
205 desc = GetDescriptor(i);
206 if (desc == NULL) {
207 status = STATUS_INVALID_DEVICE_STATE;
208 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
209 "Resource Descriptor not found %!STATUS!", status);
210 goto exit;
211 }
212
213 if (desc->Type == CmResourceTypePort) {
214 SIZE_T len;
215 PHYSICAL_ADDRESS pa;
216
217 //
218 // This will populate Length, StartPa and EndPa
219 //
220 len = GetResourceLength(desc, &pa);
221 if (len) {
222 m_PortResourceTable[index].SetPhysicalAddress(pa, len);
223 }
224
225 index++;
226 }
227 }
228
229 exit:
230
231 if (!NT_SUCCESS(status)) {
232 if (m_PortResourceTable != NULL) {
233 delete [] m_PortResourceTable;
234 m_PortResourceTable = NULL;
235 m_PortResourceTableSizeCe = 0;
236 }
237 }
238
239 if (locked) {
240 UnlockResourceTable();
241 }
242
243 return status;
244 }
245
246
247 VOID
UpdateRegisterResourceEntryLocked(__in FxRegisterResourceInfo * Entry,__in PVOID SystemMappedAddress,__in SIZE_T NumberOfBytes,__in PVOID UsermodeMappedAddress)248 FxCmResList::UpdateRegisterResourceEntryLocked(
249 __in FxRegisterResourceInfo* Entry,
250 __in PVOID SystemMappedAddress,
251 __in SIZE_T NumberOfBytes,
252 __in PVOID UsermodeMappedAddress
253 )
254 {
255 Entry->SetMappedAddress(SystemMappedAddress, NumberOfBytes, UsermodeMappedAddress);
256 }
257
258 VOID
ClearRegisterResourceEntryLocked(__in FxRegisterResourceInfo * Entry)259 FxCmResList::ClearRegisterResourceEntryLocked(
260 __in FxRegisterResourceInfo* Entry
261 )
262 {
263 Entry->ClearMappedAddress();
264 }
265
266 HRESULT
ValidateRegisterPhysicalAddressRange(__in PHYSICAL_ADDRESS PhysicalAddress,__in SIZE_T Size,__out FxRegisterResourceInfo ** TableEntry)267 FxCmResList::ValidateRegisterPhysicalAddressRange (
268 __in PHYSICAL_ADDRESS PhysicalAddress,
269 __in SIZE_T Size,
270 __out FxRegisterResourceInfo** TableEntry
271 )
272 /*++
273
274 Routine Description:
275
276 This routine checks whether the physical address range is part of the resources
277 assigned to the device by pnp manager. It also returns the table entry
278 corresponding to the physical address range from register resource table.
279
280 Arguments:
281
282 PhysicalAddress - Supplies physical address to validate
283
284 Size - Supplies size of address range in bytes.
285
286 TableEntry - Supplies a pointer to store the table entry that corresponds to
287 this physical address.
288
289 Return Value:
290
291 HRESULT
292
293 S_OK if physical address is one assigned by pnp manager to this device.
294 E_INAVLIDARG otherwise.
295
296 --*/
297 {
298 ULONG i;
299 HRESULT hr;
300 ULONGLONG driverStartPa, driverEndPa, systemStartPa, systemEndPa;
301 ULONGLONG tmp;
302 FxRegisterResourceInfo* entry = NULL;
303
304 *TableEntry = NULL;
305
306 //
307 // Physical address is of LONGLONG type (signed) we need to cast it to
308 // ULONGLONG for comparision because in a LONGLONG comprison, the
309 // result is different when highest bit is set vs when it is not set.
310 //
311 driverStartPa = PhysicalAddress.QuadPart;
312
313 //
314 // driverEndPa = driverStartPa + Size - 1;
315 //
316 hr = ULongLongAdd(driverStartPa, Size, &tmp);
317 FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("Integer overflow occurred"
318 "when computing register address range", SUCCEEDED(hr)),
319 GetDriverGlobals()->Public.DriverName);
320
321 driverEndPa = tmp - 1;
322
323 //
324 // We allow one physical address range mapping only. The base address and
325 // length can be flexible within the assigned range.
326 //
327 for (i = 0; i < m_RegisterResourceTableSizeCe; i++) {
328 entry = &m_RegisterResourceTable[i];
329
330 //
331 // No need to do int overflow safe additon here since start address and
332 // length are assigned by pnp manager. Note that we don't store endPa in
333 // resource table the way we do for SystemVa is because endPa is not
334 // needed in hot path so can be computed using length.
335 //
336 systemStartPa = entry->m_StartPa.QuadPart;
337 systemEndPa = systemStartPa + entry->m_Length - 1;
338
339 if (driverStartPa >= systemStartPa &&
340 driverEndPa <= systemEndPa) {
341
342 FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("Attempt to do multiple "
343 "mapping of same resource, or multiple mapping in same resource"
344 " range",
345 (entry->m_StartSystemVa == NULL)), GetDriverGlobals()->Public.DriverName);
346 FX_VERIFY_WITH_NAME(INTERNAL, CHECK_NULL(entry->m_EndSystemVa),
347 GetDriverGlobals()->Public.DriverName);
348 FX_VERIFY_WITH_NAME(INTERNAL, CHECK_NULL(entry->m_StartUsermodeVa),
349 GetDriverGlobals()->Public.DriverName);
350 FX_VERIFY_WITH_NAME(INTERNAL, CHECK("Mapped length not zero",
351 (entry->m_MappedLength == 0)), GetDriverGlobals()->Public.DriverName);
352
353 *TableEntry = entry;
354
355 return S_OK;
356 }
357 }
358
359 return E_INVALIDARG;
360 }
361
362 HRESULT
ValidateAndClearMapping(__in PVOID Address,__in SIZE_T Length)363 FxCmResList::ValidateAndClearMapping(
364 __in PVOID Address,
365 __in SIZE_T Length
366 )
367 /*++
368
369 Routine Description:
370
371 This routine checks whether the mapped system base address and size is part
372 of the resources assigned to the device by pnp manager. If so it clears the
373 system and usermode address mapping from the table.
374
375 Arguments:
376
377 Address - Supplies system base address to validate
378
379 Size - Supplies size of address range in bytes.
380
381 Return Value:
382
383 HRESULT
384
385 S_OK if system address is one mapped to a register resource.
386 E_INAVLIDARG otherwise.
387
388 --*/
389 {
390 HRESULT hr = E_INVALIDARG;
391 ULONG i;
392 FxRegisterResourceInfo* entry = NULL;
393
394 LockResourceTable();
395
396 for (i = 0; i < m_RegisterResourceTableSizeCe; i++) {
397 entry = &m_RegisterResourceTable[i];
398
399 if (NULL != entry->m_StartSystemVa &&
400 Address == entry->m_StartSystemVa &&
401 Length == entry->m_MappedLength) {
402 //
403 // there is a valid mapping. clear it.
404 //
405 FX_VERIFY_WITH_NAME(INTERNAL, CHECK_NOT_NULL(entry->m_EndSystemVa),
406 GetDriverGlobals()->Public.DriverName);
407
408 ClearRegisterResourceEntryLocked(entry);
409
410 hr = S_OK;
411 break;
412 }
413 }
414
415 UnlockResourceTable();
416
417 return hr;
418 }
419
420 HRESULT
ValidateRegisterSystemBaseAddress(__in PVOID Address,__out PVOID * UsermodeBaseAddress)421 FxCmResList::ValidateRegisterSystemBaseAddress (
422 __in PVOID Address,
423 __out PVOID* UsermodeBaseAddress
424 )
425 /*++
426
427 Routine Description:
428
429 This routine checks whether the mapped system base address and size is part
430 of the resources assigned to the device by pnp manager. If so, it returns
431 corresponding user-mode mapped base address. It is applicable
432 only when registers are mapped to user-mode.
433
434 Arguments:
435
436 Address - Supplies system base address to validate
437
438 Return Value:
439
440 HRESULT
441
442 S_OK if system address is one mapped to a register resource.
443 E_INAVLIDARG otherwise.
444
445 --*/
446 {
447 ULONG i;
448 FxRegisterResourceInfo* entry = NULL;
449
450 LockResourceTable();
451 for (i = 0; i < m_RegisterResourceTableSizeCe; i++) {
452 entry = &m_RegisterResourceTable[i];
453
454 if (Address == entry->m_StartSystemVa) {
455
456 FX_VERIFY_WITH_NAME(INTERNAL, CHECK_NOT_NULL(entry->m_StartUsermodeVa),
457 GetDriverGlobals()->Public.DriverName);
458
459 *UsermodeBaseAddress = entry->m_StartUsermodeVa;
460
461 UnlockResourceTable();
462 return S_OK;
463 }
464 }
465
466 UnlockResourceTable();
467 return E_INVALIDARG;
468 }
469
470 HRESULT
ValidateRegisterSystemAddressRange(__in PVOID SystemAddress,__in SIZE_T Length,__out_opt PVOID * UsermodeAddress)471 FxCmResList::ValidateRegisterSystemAddressRange (
472 __in PVOID SystemAddress,
473 __in SIZE_T Length,
474 __out_opt PVOID* UsermodeAddress
475 )
476 /*++
477
478 Routine Description:
479
480 This routine checks whether given system mapped address and length is within
481 one of the assigned resource ranges. Optionally, tt computes the usermode
482 address corresponding to the system address.
483
484 Arguments:
485
486 Address - Supplies register address to validate
487
488 Size - Supplies size of address range in bytes.
489
490 UsermodeAddress - returns usermode address corresponding to system address
491
492 Return Value:
493
494 HRESULT
495
496 S_OK if system address range is valid.
497 E_INAVLIDARG otherwise.
498
499 --*/
500 {
501 HRESULT hr = E_INVALIDARG;
502 FxRegisterResourceInfo* entry = NULL;
503 SIZE_T offset = 0;
504 ULONG i;
505 PVOID start = NULL;
506 PVOID end = NULL;
507 ULONG_PTR tmp;
508
509 //
510 // compute system address range to look for
511 //
512 start = SystemAddress;
513
514 //
515 // Use interger overflow safe functions
516 // end = ((PUCHAR)SystemAddress) + Length - 1;
517 //
518 hr = ULongPtrAdd((ULONG_PTR) start, Length, &tmp);
519 FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("Integer overflow occurred"
520 "when computing register address range", SUCCEEDED(hr)),
521 GetDriverGlobals()->Public.DriverName);
522
523 end = (PVOID)(tmp - 1);
524
525 //
526 // check if range is in the register resource table
527 //
528 hr = E_INVALIDARG;
529 for (i = 0; i < m_RegisterResourceTableSizeCe; i++) {
530 entry = &m_RegisterResourceTable[i];
531
532 if (start >= entry->m_StartSystemVa &&
533 end <= entry->m_EndSystemVa) {
534 hr = S_OK;
535 break;
536 }
537 }
538
539 //
540 // compute the corresponding usermode address
541 //
542 if (SUCCEEDED(hr) && UsermodeAddress != NULL) {
543 offset = ((PUCHAR)SystemAddress) - ((PUCHAR)entry->m_StartSystemVa);
544 *UsermodeAddress = ((PUCHAR)entry->m_StartUsermodeVa) + offset;
545 }
546
547 return hr;
548 }
549
550 SIZE_T
GetResourceLength(__in PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,__out_opt PHYSICAL_ADDRESS * Start)551 FxCmResList::GetResourceLength(
552 __in PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
553 __out_opt PHYSICAL_ADDRESS* Start
554 )
555 /*++
556
557 Routine Description:
558
559 This routine decodes the length from a CmPartialResourceDescriptor
560 describing a memory resource.
561
562 Arguments:
563
564 Descriptor - Supplies resource descriptor from which to decode length
565
566 Start - Supplies optional buffer into which start address will be stored.
567
568 Return Value:
569
570 Decoded Length
571
572 --*/
573 {
574 ULONGLONG length;
575
576 length = 0;
577
578 ASSERT((Descriptor->Type == CmResourceTypeMemory) ||
579 (Descriptor->Type == CmResourceTypeMemoryLarge) ||
580 (Descriptor->Type == CmResourceTypePort));
581
582 //
583 // If it is not large memory resource than length is in u.Memory.Length.
584 // For large memory resource, the length is given by different fields in
585 // CM_PARTIAL_RESOURCE_DESCRIPTOR structure.
586 //
587 if ((Descriptor->Type == CmResourceTypeMemory) ||
588 (Descriptor->Type == CmResourceTypePort)) {
589 length = Descriptor->u.Memory.Length;
590
591 } else if (Descriptor->Flags & CM_RESOURCE_MEMORY_LARGE_40) {
592 length = (((ULONGLONG)Descriptor->u.Memory40.Length40) << 8);
593
594 } else if (Descriptor->Flags & CM_RESOURCE_MEMORY_LARGE_48) {
595 length = (((ULONGLONG)Descriptor->u.Memory48.Length48) << 16);
596
597 } else if (Descriptor->Flags & CM_RESOURCE_MEMORY_LARGE_64) {
598 length = (((ULONGLONG)Descriptor->u.Memory64.Length64) << 32);
599
600 } else {
601 //
602 // It should not be possible to get here.
603 //
604 ASSERT(FALSE);
605 }
606
607 if (Start != NULL) {
608 *Start = Descriptor->u.Generic.Start;
609 }
610
611 //
612 // large memory descriptor is only supported on 64-bit so the casting
613 // below is ok.
614 //
615 return (SIZE_T) length;
616 }
617
618 HRESULT
MapIoSpaceWorker(__in PHYSICAL_ADDRESS PhysicalAddress,__in SIZE_T NumberOfBytes,__in MEMORY_CACHING_TYPE CacheType,__deref_out VOID ** PseudoBaseAddress)619 FxCmResList::MapIoSpaceWorker(
620 __in PHYSICAL_ADDRESS PhysicalAddress,
621 __in SIZE_T NumberOfBytes,
622 __in MEMORY_CACHING_TYPE CacheType,
623 __deref_out VOID** PseudoBaseAddress
624 )
625 {
626 IWudfDeviceStack *deviceStack;
627 PVOID systemAddress;
628 PVOID usermodeAddress;
629 HRESULT hr;
630 FxRegisterResourceInfo* resEntry;
631
632 //
633 // check if this physical resource is among the assigned resources.
634 // If it is, retrieve the table entry corresponding to to register res.
635 //
636 LockResourceTable();
637
638 hr = ValidateRegisterPhysicalAddressRange(PhysicalAddress,
639 NumberOfBytes,
640 &resEntry);
641
642 FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO),
643 CHECK("Invalid physical address or number of bytes provided",
644 (SUCCEEDED(hr))), GetDriverGlobals()->Public.DriverName);
645
646 *PseudoBaseAddress = NULL;
647
648 //
649 // Call host
650 //
651 deviceStack = GetDevice()->GetDeviceStack();
652 systemAddress = NULL;
653 usermodeAddress = NULL;
654
655 if(GetDevice()->AreRegistersMappedToUsermode()) {
656 hr = deviceStack->MapIoSpace(PhysicalAddress,
657 NumberOfBytes,
658 CacheType,
659 &systemAddress,
660 &usermodeAddress);
661 }
662 else {
663 hr = deviceStack->MapIoSpace(PhysicalAddress,
664 NumberOfBytes,
665 CacheType,
666 &systemAddress,
667 NULL);
668 }
669
670 if (SUCCEEDED(hr)) {
671 //
672 // update the mapped resource list entry and add it to list
673 //
674 UpdateRegisterResourceEntryLocked(resEntry,
675 systemAddress,
676 NumberOfBytes,
677 usermodeAddress);
678
679 //
680 // Convert system address to pseudo (opaque) base address
681 //
682 *PseudoBaseAddress = GetDevice()->GetPseudoAddressFromSystemAddress(
683 systemAddress
684 );
685 }
686
687 UnlockResourceTable();
688
689 return hr;
690 }
691
692 VOID
ValidateResourceUnmap(VOID)693 FxCmResList::ValidateResourceUnmap(
694 VOID
695 )
696 {
697 ULONG i;
698 FxRegisterResourceInfo* entry = NULL;
699
700 //
701 // make sure driver has unmapped its resources. No need to
702 // acquire the resource validation table lock as this is called in
703 // ReleaseHardware pnp callback and cannot race with another framework
704 // pnp callback that updates this table (PrepareHardware) so no invalid
705 // access. If a driver thread unmaps after ReleaseHardware return then also
706 // it will be a valid access of table entry.
707 //
708
709 for (i = 0; i < m_RegisterResourceTableSizeCe; i++) {
710 entry = &m_RegisterResourceTable[i];
711
712 FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("Driver did not unmap its "
713 "register resources", (entry->m_StartSystemVa == NULL)), GetDriverGlobals()->Public.DriverName);
714 }
715 }
716
717 HRESULT
ValidatePortAddressRange(__in PVOID Address,__in SIZE_T Length)718 FxCmResList::ValidatePortAddressRange(
719 __in PVOID Address,
720 __in SIZE_T Length
721 )
722 {
723 ULONG i;
724 HRESULT hr;
725 ULONGLONG driverStartPa, driverEndPa, systemStartPa, systemEndPa;
726 ULONGLONG tmp;
727 FxPortResourceInfo* entry = NULL;
728
729 driverStartPa = (ULONGLONG)Address;
730
731 //
732 // driverEndPa = driverStartPa + Length - 1;
733 //
734 hr = ULongLongAdd(driverStartPa, Length, &tmp);
735 FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("Integer overflow occurred"
736 "when computing port address range", SUCCEEDED(hr)),
737 GetDriverGlobals()->Public.DriverName);
738
739 driverEndPa = tmp - 1;
740
741 for (i = 0; i < m_PortResourceTableSizeCe; i++) {
742 entry = &m_PortResourceTable[i];
743
744 systemStartPa = entry->m_StartPa.QuadPart;
745 systemEndPa = entry->m_EndPa.QuadPart;
746
747 if (driverStartPa >= systemStartPa &&
748 driverEndPa <= systemEndPa) {
749 return S_OK;
750 }
751 }
752
753 return E_INVALIDARG;
754 }
755
756 _Must_inspect_result_
757 NTSTATUS
CheckForConnectionResources(VOID)758 FxCmResList::CheckForConnectionResources(
759 VOID
760 )
761 {
762 NTSTATUS status;
763 ULONG i;
764 ULONG count;
765 PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor;
766
767 status = STATUS_SUCCESS;
768 count = GetCount();
769
770 for (i = 0; i < count; i++) {
771 pDescriptor = GetDescriptor(i);
772 if (pDescriptor == NULL) {
773 status = STATUS_INVALID_DEVICE_STATE;
774 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
775 "Resource Descriptor not found %!STATUS!", status);
776 goto exit;
777 }
778
779 if (pDescriptor->Type == CmResourceTypeConnection) {
780 m_HasConnectionResources = TRUE;
781 break;
782 }
783 }
784
785 exit:
786 return status;
787 }
788
789