Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1003 lines
21 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. initunlo.c
  5. Abstract:
  6. This module contains the code that is very specific to initialization
  7. and unload operations in the irenum driver
  8. Author:
  9. Brian Lieuallen, 7-13-2000
  10. Environment:
  11. Kernel mode
  12. Revision History :
  13. --*/
  14. #include "internal.h"
  15. #define UINT ULONG //tmp
  16. #include <irioctl.h>
  17. //#include <af_irda.h>
  18. //#include <irdatdi.h>
  19. //#include <ircommtdi.h>
  20. #define MAX_DEVICES 16
  21. #define STATIC_DEVICE_NAME L"Incoming IRCOMM"
  22. #define STATIC_HARDWARE_ID L"IR_NULL_IN"
  23. int sprintf(char *, ...);
  24. typedef struct _ENUM_OBJECT {
  25. PVOID ThreadObject;
  26. KEVENT WaitEvent;
  27. KTIMER Timer;
  28. PDEVICE_OBJECT Fdo;
  29. ULONG DeviceCount;
  30. IR_DEVICE Devices[MAX_DEVICES];
  31. PASSIVE_LOCK PassiveLock;
  32. } ENUM_OBJECT, *PENUM_OBJECT;
  33. VOID
  34. WorkerThread(
  35. PVOID Context
  36. );
  37. NTSTATUS
  38. EnumIrda(
  39. PENUM_OBJECT EnumObject
  40. );
  41. NTSTATUS
  42. DoIasQueries(
  43. PIR_DEVICE IrDevice
  44. );
  45. NTSTATUS
  46. CreatePdo(
  47. PDEVICE_OBJECT Fdo,
  48. PIR_DEVICE IrDevice
  49. );
  50. NTSTATUS
  51. CreateStaticDevice(
  52. PENUM_OBJECT EnumObject
  53. )
  54. {
  55. NTSTATUS Status;
  56. ULONG DeviceId=0;
  57. PIR_DEVICE IrDevice=&EnumObject->Devices[0];
  58. //
  59. // zero the whole thing
  60. //
  61. RtlZeroMemory(IrDevice,sizeof(*IrDevice));
  62. //
  63. // inuse now
  64. //
  65. IrDevice->InUse=TRUE;
  66. IrDevice->Present=TRUE;
  67. IrDevice->Static=TRUE;
  68. EnumObject->DeviceCount++;
  69. RtlCopyMemory(&IrDevice->DeviceId,&DeviceId,4);
  70. RtlCopyMemory(
  71. IrDevice->DeviceName,
  72. STATIC_DEVICE_NAME,
  73. sizeof(STATIC_DEVICE_NAME)
  74. );
  75. IrDevice->Name=ALLOCATE_PAGED_POOL(sizeof(STATIC_DEVICE_NAME));
  76. if (IrDevice->Name == NULL) {
  77. Status=STATUS_NO_MEMORY;
  78. goto CleanUp;
  79. }
  80. RtlCopyMemory(
  81. IrDevice->Name,
  82. STATIC_DEVICE_NAME,
  83. sizeof(STATIC_DEVICE_NAME)
  84. );
  85. IrDevice->HardwareId=ALLOCATE_PAGED_POOL(sizeof(STATIC_HARDWARE_ID));
  86. if (IrDevice->HardwareId == NULL) {
  87. Status=STATUS_NO_MEMORY;
  88. goto CleanUp;
  89. }
  90. RtlCopyMemory(
  91. IrDevice->HardwareId,
  92. STATIC_HARDWARE_ID,
  93. sizeof(STATIC_HARDWARE_ID)
  94. );
  95. Status=CreatePdo(
  96. EnumObject->Fdo,
  97. IrDevice
  98. );
  99. if (NT_SUCCESS(Status)) {
  100. return Status;
  101. }
  102. CleanUp:
  103. if (IrDevice->Name != NULL) {
  104. FREE_POOL(IrDevice->Name);
  105. }
  106. if (IrDevice->HardwareId != NULL) {
  107. FREE_POOL(IrDevice->HardwareId);
  108. }
  109. RtlZeroMemory(IrDevice,sizeof(&IrDevice));
  110. EnumObject->DeviceCount--;
  111. return Status;
  112. }
  113. NTSTATUS
  114. CreateEnumObject(
  115. PDEVICE_OBJECT Fdo,
  116. ENUM_HANDLE *Object,
  117. BOOLEAN StaticDevice
  118. )
  119. {
  120. NTSTATUS Status;
  121. PENUM_OBJECT EnumObject;
  122. HANDLE ThreadHandle;
  123. *Object=NULL;
  124. EnumObject=ALLOCATE_NONPAGED_POOL(sizeof(*EnumObject));
  125. if (EnumObject==NULL) {
  126. return STATUS_NO_MEMORY;
  127. }
  128. RtlZeroMemory(EnumObject,sizeof(*EnumObject));
  129. EnumObject->Fdo=Fdo;
  130. if (StaticDevice) {
  131. CreateStaticDevice(EnumObject);
  132. }
  133. INIT_PASSIVE_LOCK(&EnumObject->PassiveLock);
  134. KeInitializeEvent(
  135. &EnumObject->WaitEvent,
  136. NotificationEvent,
  137. FALSE
  138. );
  139. KeInitializeTimer(
  140. &EnumObject->Timer
  141. );
  142. Status=PsCreateSystemThread(
  143. &ThreadHandle,
  144. THREAD_ALL_ACCESS,
  145. NULL,
  146. NULL,
  147. NULL,
  148. WorkerThread,
  149. EnumObject
  150. );
  151. if (!NT_SUCCESS(Status)) {
  152. goto CleanUp;
  153. }
  154. Status=ObReferenceObjectByHandle(
  155. ThreadHandle,
  156. 0,
  157. NULL,
  158. KernelMode,
  159. &EnumObject->ThreadObject,
  160. NULL
  161. );
  162. ZwClose(ThreadHandle);
  163. ThreadHandle=NULL;
  164. if (!NT_SUCCESS(Status)) {
  165. goto CleanUp;
  166. }
  167. *Object=EnumObject;
  168. return Status;
  169. CleanUp:
  170. KeSetEvent(
  171. &EnumObject->WaitEvent,
  172. IO_NO_INCREMENT,
  173. FALSE
  174. );
  175. //
  176. // make sure we really got the object
  177. //
  178. if (EnumObject->ThreadObject != NULL) {
  179. KeWaitForSingleObject(
  180. EnumObject->ThreadObject,
  181. Executive,
  182. KernelMode,
  183. FALSE,
  184. NULL
  185. );
  186. ObDereferenceObject(EnumObject->ThreadObject);
  187. } else {
  188. ASSERT(0);
  189. }
  190. FREE_POOL(EnumObject);
  191. return Status;
  192. }
  193. VOID
  194. CloseEnumObject(
  195. ENUM_HANDLE Handle
  196. )
  197. {
  198. PENUM_OBJECT EnumObject=Handle;
  199. ULONG j;
  200. KeSetEvent(
  201. &EnumObject->WaitEvent,
  202. IO_NO_INCREMENT,
  203. FALSE
  204. );
  205. KeWaitForSingleObject(
  206. EnumObject->ThreadObject,
  207. Executive,
  208. KernelMode,
  209. FALSE,
  210. NULL
  211. );
  212. ObDereferenceObject(EnumObject->ThreadObject);
  213. for (j=0; j< MAX_DEVICES; j++) {
  214. //
  215. // if remove it
  216. //
  217. if (EnumObject->Devices[j].InUse) {
  218. //
  219. // not enumerated any more since tha parent is going away
  220. //
  221. EnumObject->Devices[j].Enumerated=FALSE;
  222. RemoveDevice(EnumObject,&EnumObject->Devices[j]);
  223. }
  224. }
  225. FREE_POOL(EnumObject);
  226. return;
  227. }
  228. VOID
  229. WorkerThread(
  230. PVOID Context
  231. )
  232. {
  233. NTSTATUS Status;
  234. PENUM_OBJECT EnumObject=Context;
  235. PVOID ObjectArray[2];
  236. D_PNP(DbgPrint("IRENUM: WorkerThread: started\n");)
  237. ObjectArray[0]=&EnumObject->WaitEvent;
  238. ObjectArray[1]=&EnumObject->Timer;
  239. while (1) {
  240. LARGE_INTEGER DueTime;
  241. DueTime.QuadPart = -10*1000*10000;
  242. KeSetTimer(
  243. &EnumObject->Timer,
  244. DueTime,
  245. NULL
  246. );
  247. Status=KeWaitForMultipleObjects(
  248. 2,
  249. &ObjectArray[0],
  250. WaitAny,
  251. Executive,
  252. KernelMode,
  253. FALSE,
  254. NULL,
  255. NULL
  256. );
  257. if (Status == 0) {
  258. //
  259. // the event was signaled, time to exit
  260. //
  261. break;
  262. } else {
  263. if (Status == 1) {
  264. //
  265. // the time expired, check for devices
  266. //
  267. // D_PNP(DbgPrint("IRENUM: WorkerThread: Timer expired\n");)
  268. ACQUIRE_PASSIVE_LOCK(&EnumObject->PassiveLock);
  269. EnumIrda(EnumObject);
  270. RELEASE_PASSIVE_LOCK(&EnumObject->PassiveLock);
  271. } else {
  272. ASSERT(0);
  273. }
  274. }
  275. }
  276. KeCancelTimer(&EnumObject->Timer);
  277. D_PNP(DbgPrint("IRENUM: WorkerThread: stopping\n");)
  278. PsTerminateSystemThread(STATUS_SUCCESS);
  279. return;
  280. }
  281. NTSTATUS
  282. DeviceNameFromDeviceInfo(
  283. PIRDA_DEVICE_INFO DeviceInfo,
  284. PWCHAR DeviceName,
  285. ULONG NameLength
  286. )
  287. {
  288. NTSTATUS Status=STATUS_SUCCESS;
  289. WCHAR TempBuffer[23];
  290. UNICODE_STRING UnicodeString;
  291. //
  292. // zero out the temp buffer, so we can copy the remote device name,
  293. // so we can be sure it is null terminated
  294. //
  295. RtlZeroMemory(TempBuffer,sizeof(TempBuffer));
  296. RtlCopyMemory(TempBuffer,DeviceInfo->irdaDeviceName,sizeof(DeviceInfo->irdaDeviceName));
  297. UnicodeString.Length=0;
  298. UnicodeString.MaximumLength=(USHORT)(NameLength-1)*sizeof(WCHAR);
  299. UnicodeString.Buffer=DeviceName;
  300. RtlZeroMemory(UnicodeString.Buffer,UnicodeString.MaximumLength);
  301. if (DeviceInfo->irdaCharSet == LmCharSetUNICODE) {
  302. //
  303. // the name is unicode
  304. //
  305. Status=RtlAppendUnicodeToString(&UnicodeString,TempBuffer);
  306. } else {
  307. //
  308. // the name is ansi, need to convert unicode
  309. //
  310. ANSI_STRING AnsiString;
  311. RtlInitAnsiString(
  312. &AnsiString,
  313. (PCSZ)TempBuffer
  314. );
  315. Status=RtlAnsiStringToUnicodeString(
  316. &UnicodeString,
  317. &AnsiString,
  318. FALSE
  319. );
  320. }
  321. return Status;
  322. }
  323. NTSTATUS
  324. EnumIrda(
  325. PENUM_OBJECT EnumObject
  326. )
  327. {
  328. NTSTATUS Status;
  329. UCHAR DevListBuf[512];
  330. PDEVICELIST pDevList = (PDEVICELIST) DevListBuf;
  331. ULONG DevListLen = sizeof(DevListBuf);
  332. ULONG i;
  333. ULONG j;
  334. BOOLEAN InvalidateDeviceRelations=FALSE;
  335. Status = IrdaDiscoverDevices(pDevList, &DevListLen);
  336. if (!NT_SUCCESS(Status)) {
  337. D_ERROR(DbgPrint("IRENUM: DiscoveryFailed %08lx\n",Status);)
  338. return Status;
  339. }
  340. // D_PNP(DbgPrint("IRENUM: Found %d devices\n",pDevList->numDevice);)
  341. for (j=0; j< MAX_DEVICES; j++) {
  342. //
  343. // first mark all the device not present
  344. //
  345. if (!EnumObject->Devices[j].Static) {
  346. //
  347. // only non-static device go away
  348. //
  349. EnumObject->Devices[j].Present=FALSE;
  350. }
  351. }
  352. for (i=0; i < pDevList->numDevice; i++) {
  353. PIRDA_DEVICE_INFO DeviceInfo=&pDevList->Device[i];
  354. ULONG DeviceId;
  355. RtlCopyMemory(&DeviceId, &DeviceInfo->irdaDeviceID[0],4);
  356. for (j=0; j< MAX_DEVICES; j++) {
  357. WCHAR TempBuffer[24];
  358. if (EnumObject->Devices[j].InUse) {
  359. DeviceNameFromDeviceInfo(
  360. DeviceInfo,
  361. TempBuffer,
  362. sizeof(TempBuffer)/sizeof(WCHAR)
  363. );
  364. if (0 == wcscmp(TempBuffer, EnumObject->Devices[j].DeviceName)) {
  365. //
  366. // Already present
  367. //
  368. EnumObject->Devices[j].Present=TRUE;
  369. if (DeviceId != EnumObject->Devices[j].DeviceId) {
  370. D_ERROR(DbgPrint("IRENUM: Found Dup device %x devices\n",DeviceId);)
  371. RtlCopyMemory(&EnumObject->Devices[j].DeviceId,&DeviceInfo->irdaDeviceID[0],4);
  372. }
  373. break;
  374. }
  375. }
  376. }
  377. if ( j < MAX_DEVICES) {
  378. //
  379. // We found a match, skip this one
  380. //
  381. continue;
  382. }
  383. //
  384. // at this point we have a new device
  385. //
  386. if ((DeviceInfo->irdaDeviceHints2 & 4)) {
  387. //
  388. // it is an ircomm device
  389. //
  390. for (j=0; j< MAX_DEVICES; j++) {
  391. //
  392. // find a slot not in use
  393. //
  394. if (!EnumObject->Devices[j].InUse) {
  395. //
  396. // found a slot for it, zero the info
  397. //
  398. RtlZeroMemory(&EnumObject->Devices[j],sizeof(EnumObject->Devices[j]));
  399. //
  400. // inuse now
  401. //
  402. EnumObject->Devices[j].InUse=TRUE;
  403. EnumObject->Devices[j].Present=TRUE;
  404. RtlCopyMemory(&EnumObject->Devices[j].DeviceId,&DeviceInfo->irdaDeviceID[0],4);
  405. EnumObject->Devices[j].Hint1=DeviceInfo->irdaDeviceHints1;
  406. EnumObject->Devices[j].Hint2=DeviceInfo->irdaDeviceHints2;
  407. DeviceNameFromDeviceInfo(
  408. DeviceInfo,
  409. EnumObject->Devices[j].DeviceName,
  410. sizeof(EnumObject->Devices[j].DeviceName)/sizeof(WCHAR)
  411. );
  412. DoIasQueries(
  413. &EnumObject->Devices[j]
  414. );
  415. if (EnumObject->Devices[j].HardwareId != NULL) {
  416. Status=CreatePdo(
  417. EnumObject->Fdo,
  418. &EnumObject->Devices[j]
  419. );
  420. D_PNP(DbgPrint(
  421. "IRENUM: Name %ws, device id=%08lx, hint1=%x, hint2=%x\n",
  422. EnumObject->Devices[j].DeviceName,
  423. EnumObject->Devices[j].DeviceId,
  424. EnumObject->Devices[j].Hint1,
  425. EnumObject->Devices[j].Hint2
  426. );)
  427. //
  428. // new device
  429. //
  430. InvalidateDeviceRelations=TRUE;
  431. EnumObject->DeviceCount++;
  432. } else {
  433. //
  434. // the device did not report a pnp hardware id
  435. //
  436. RtlZeroMemory(&EnumObject->Devices[j],sizeof(EnumObject->Devices[j]));
  437. }
  438. break;
  439. }
  440. }
  441. }
  442. }
  443. for (j=0; j< MAX_DEVICES; j++) {
  444. //
  445. // lets see if any thing disappeared
  446. //
  447. if (EnumObject->Devices[j].InUse) {
  448. //
  449. // found a slot that is in use
  450. //
  451. if (!EnumObject->Devices[j].Present) {
  452. //
  453. // but it does not have a device present
  454. //
  455. InvalidateDeviceRelations=TRUE;
  456. }
  457. }
  458. }
  459. if (InvalidateDeviceRelations) {
  460. //
  461. // tell the system to check the device relations because a device has appeared or
  462. // disappeared
  463. //
  464. PFDO_DEVICE_EXTENSION FdoExtension=EnumObject->Fdo->DeviceExtension;
  465. IoInvalidateDeviceRelations(FdoExtension->Pdo,BusRelations);
  466. }
  467. return Status;
  468. }
  469. NTSTATUS
  470. CreatePdo(
  471. PDEVICE_OBJECT Fdo,
  472. PIR_DEVICE IrDevice
  473. )
  474. {
  475. NTSTATUS Status;
  476. PDEVICE_OBJECT NewPdo;
  477. Status = IoCreateDevice(
  478. Fdo->DriverObject,
  479. sizeof(PDO_DEVICE_EXTENSION),
  480. NULL,
  481. FILE_DEVICE_BUS_EXTENDER,
  482. FILE_AUTOGENERATED_DEVICE_NAME,
  483. FALSE,
  484. &NewPdo
  485. );
  486. if (NT_SUCCESS(Status)) {
  487. //
  488. // got the device
  489. //
  490. PPDO_DEVICE_EXTENSION PdoExtension=NewPdo->DeviceExtension;
  491. PdoExtension->DoType=DO_TYPE_PDO;
  492. PdoExtension->ParentFdo=Fdo;
  493. // PdoExtension->UnEnumerated=FALSE;
  494. PdoExtension->DeviceDescription=IrDevice;
  495. IrDevice->Pdo = NewPdo;
  496. NewPdo->Flags |= DO_POWER_PAGABLE;
  497. NewPdo->Flags &= ~DO_DEVICE_INITIALIZING;
  498. } else {
  499. D_PNP(DbgPrint("MODEM: CreateChildPdo: IoCreateDevice() failed %08lx\n",Status);)
  500. }
  501. return Status;
  502. }
  503. VOID
  504. FixupDeviceId(
  505. PWSTR HardwareId
  506. )
  507. {
  508. //
  509. // munge the hardware id to make sure it is compatable with the os requirements
  510. //
  511. while (*HardwareId != L'\0') {
  512. if ((*HardwareId < L' ') || (*HardwareId > 127) || (*HardwareId == L',')) {
  513. *HardwareId = L'?';
  514. }
  515. HardwareId++;
  516. }
  517. return;
  518. }
  519. NTSTATUS
  520. DoIasQueries(
  521. PIR_DEVICE IrDevice
  522. )
  523. {
  524. NTSTATUS Status;
  525. LONG CompatCount;
  526. Status=IrdaIASStringQuery(
  527. IrDevice->DeviceId,
  528. "PnP",
  529. "Manufacturer",
  530. &IrDevice->Manufacturer
  531. );
  532. if (NT_SUCCESS(Status)) {
  533. DbgPrint("IRENUM: got pnp manufacturer %ws\n",IrDevice->Manufacturer);
  534. }
  535. Status=IrdaIASStringQuery(
  536. IrDevice->DeviceId,
  537. "PnP",
  538. "Name",
  539. &IrDevice->Name
  540. );
  541. if (NT_SUCCESS(Status)) {
  542. DbgPrint("IRENUM: got pnp name %ws\n",IrDevice->Name);
  543. }
  544. Status=IrdaIASStringQuery(
  545. IrDevice->DeviceId,
  546. "PnP",
  547. "DeviceID",
  548. &IrDevice->HardwareId
  549. );
  550. if (NT_SUCCESS(Status)) {
  551. DbgPrint("IRENUM: got pnp id %ws\n",IrDevice->HardwareId);
  552. FixupDeviceId(IrDevice->HardwareId);
  553. }
  554. //
  555. // check for compat id's
  556. //
  557. IrDevice->CompatIdCount=0;
  558. Status=IrdaIASIntegerQuery(
  559. IrDevice->DeviceId,
  560. "PnP",
  561. "CompCnt",
  562. &CompatCount
  563. );
  564. if (NT_SUCCESS(Status)) {
  565. LONG i;
  566. if ( CompatCount > 16) {
  567. CompatCount=16;
  568. } else {
  569. if ( CompatCount < 0) {
  570. CompatCount = 0;
  571. }
  572. }
  573. for (i=0; i< CompatCount; i++) {
  574. CHAR Attribute[20];
  575. sprintf(Attribute,"Comp#%02d",i+1);
  576. Status=IrdaIASStringQuery(
  577. IrDevice->DeviceId,
  578. "PnP",
  579. Attribute,
  580. &IrDevice->CompatId[IrDevice->CompatIdCount]
  581. );
  582. if (NT_SUCCESS(Status)) {
  583. DbgPrint("IRENUM: got compat pnp id %ws\n",IrDevice->CompatId[IrDevice->CompatIdCount]);
  584. FixupDeviceId(IrDevice->CompatId[IrDevice->CompatIdCount]);
  585. IrDevice->CompatIdCount++;
  586. } else {
  587. D_ERROR(DbgPrint("IRENUM: could not get id for %s\n",Attribute);)
  588. }
  589. }
  590. }
  591. //
  592. // Create a standard compat ID for all devices, so we can load a standard driver
  593. //
  594. IrDevice->CompatId[IrDevice->CompatIdCount]=ALLOCATE_PAGED_POOL(sizeof(IRENUM_COMPAT_ID));
  595. if (IrDevice->CompatId[IrDevice->CompatIdCount] != NULL) {
  596. RtlCopyMemory(IrDevice->CompatId[IrDevice->CompatIdCount],IRENUM_COMPAT_ID,sizeof(IRENUM_COMPAT_ID));
  597. IrDevice->CompatIdCount++;
  598. }
  599. return STATUS_SUCCESS;
  600. }
  601. NTSTATUS
  602. GetDeviceList(
  603. ENUM_HANDLE Handle,
  604. PIRP Irp
  605. )
  606. {
  607. PENUM_OBJECT EnumObject=Handle;
  608. NTSTATUS Status=STATUS_SUCCESS;
  609. PDEVICE_RELATIONS CurrentRelations=(PDEVICE_RELATIONS)Irp->IoStatus.Information;
  610. PDEVICE_RELATIONS NewRelations=NULL;
  611. ULONG DeviceCount=EnumObject->DeviceCount;
  612. ULONG i;
  613. ACQUIRE_PASSIVE_LOCK(&EnumObject->PassiveLock);
  614. if (CurrentRelations != NULL) {
  615. //
  616. // we need to allocate a new relations structure and copy the old one to the new one
  617. //
  618. DeviceCount+=CurrentRelations->Count;
  619. }
  620. NewRelations=ALLOCATE_PAGED_POOL(sizeof(DEVICE_RELATIONS)+sizeof(PDEVICE_OBJECT)*DeviceCount);
  621. if (NewRelations == NULL) {
  622. Status= STATUS_INSUFFICIENT_RESOURCES;
  623. } else {
  624. NewRelations->Count=0;
  625. if (CurrentRelations != NULL) {
  626. D_PNP(DbgPrint("IRENUM: GetDeviceList: %d existing devices\n",CurrentRelations->Count);)
  627. for (i=0; i < CurrentRelations->Count; i++) {
  628. NewRelations->Objects[i]=CurrentRelations->Objects[i];
  629. NewRelations->Count++;
  630. }
  631. FREE_POOL(CurrentRelations);
  632. }
  633. for (i=0; i < MAX_DEVICES; i++) {
  634. if ((EnumObject->Devices[i].Pdo != NULL) && EnumObject->Devices[i].Present) {
  635. EnumObject->Devices[i].Enumerated=TRUE;
  636. D_PNP(DbgPrint("IRENUM: GetDeviceList: reporting DO %p\n",EnumObject->Devices[i].Pdo);)
  637. NewRelations->Objects[NewRelations->Count]=EnumObject->Devices[i].Pdo;
  638. ObReferenceObject(NewRelations->Objects[NewRelations->Count]);
  639. NewRelations->Count++;
  640. } else {
  641. //
  642. // the device is no longer present
  643. //
  644. EnumObject->Devices[i].Enumerated=FALSE;
  645. }
  646. }
  647. Irp->IoStatus.Information=(ULONG_PTR)NewRelations;
  648. }
  649. RELEASE_PASSIVE_LOCK(&EnumObject->PassiveLock);
  650. return Status;
  651. }
  652. VOID
  653. RemoveDevice(
  654. ENUM_HANDLE Handle,
  655. PIR_DEVICE IrDevice
  656. )
  657. {
  658. PENUM_OBJECT EnumObject=Handle;
  659. ACQUIRE_PASSIVE_LOCK(&EnumObject->PassiveLock);
  660. if (IrDevice->Enumerated) {
  661. //
  662. // the device is still present
  663. //
  664. // Just leave it alone
  665. //
  666. } else {
  667. //
  668. // the parent is not enumerating the device anymore
  669. //
  670. PPDO_DEVICE_EXTENSION PdoDeviceExtension=IrDevice->Pdo->DeviceExtension;
  671. ULONG i;
  672. for (i=0; i < MAX_DEVICES; i++) {
  673. //
  674. // find this device in the array
  675. //
  676. if (EnumObject->Devices[i].Pdo == IrDevice->Pdo) {
  677. break;
  678. }
  679. }
  680. if (IrDevice->HardwareId != NULL) {
  681. FREE_POOL(IrDevice->HardwareId);
  682. }
  683. if (IrDevice->Name != NULL) {
  684. FREE_POOL(IrDevice->Name);
  685. }
  686. if (IrDevice->Manufacturer != NULL) {
  687. FREE_POOL(IrDevice->Manufacturer);
  688. }
  689. PdoDeviceExtension->DoType=DO_TYPE_DEL_PDO;
  690. IoDeleteDevice(IrDevice->Pdo);
  691. RtlZeroMemory(&EnumObject->Devices[i],sizeof(IR_DEVICE));
  692. EnumObject->DeviceCount--;
  693. }
  694. RELEASE_PASSIVE_LOCK(&EnumObject->PassiveLock);
  695. return;
  696. }