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.

1293 lines
28 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 <ircommtdi.h>
  18. #define MAX_DEVICES 16
  19. #define STATIC_DEVICE_NAME L"Incoming IRCOMM"
  20. #define STATIC_HARDWARE_ID L"IR_NULL_IN"
  21. #define GENERIC_MODEM_NAME L"Infrared Modem"
  22. #define GENERIC_HARDWARE_ID L"PNPC103"
  23. #define DEVICE_PRESENT_START_VALUE (1)
  24. int sprintf(char *, ...);
  25. typedef struct _ENUM_OBJECT {
  26. PVOID ThreadObject;
  27. KEVENT WaitEvent;
  28. KTIMER Timer;
  29. PASSIVE_LOCK PassiveLock;
  30. HANDLE IoWaitEventHandle;
  31. PKEVENT IoWaitEventObject;
  32. IO_STATUS_BLOCK IoStatusBlock;
  33. HANDLE ControlChannel;
  34. PDEVICE_OBJECT Fdo;
  35. ULONG DeviceCount;
  36. ULONG EnumeratedDevices;
  37. UCHAR DeviceListBuffer[512];
  38. IR_DEVICE Devices[MAX_DEVICES];
  39. } ENUM_OBJECT, *PENUM_OBJECT;
  40. VOID
  41. WorkerThread(
  42. PVOID Context
  43. );
  44. NTSTATUS
  45. EnumIrda(
  46. PENUM_OBJECT EnumObject
  47. );
  48. NTSTATUS
  49. DoIasQueries(
  50. PIR_DEVICE IrDevice
  51. );
  52. NTSTATUS
  53. CreatePdo(
  54. PDEVICE_OBJECT Fdo,
  55. PIR_DEVICE IrDevice
  56. );
  57. NTSTATUS
  58. CreateStaticDevice(
  59. PENUM_OBJECT EnumObject
  60. );
  61. VOID
  62. CloseEnumObject(
  63. ENUM_HANDLE Handle
  64. );
  65. NTSTATUS
  66. DeviceNameFromDeviceInfo(
  67. PIRDA_DEVICE_INFO DeviceInfo,
  68. PWCHAR DeviceName,
  69. ULONG NameLength
  70. );
  71. VOID
  72. FixupDeviceId(
  73. PWSTR HardwareId
  74. );
  75. #pragma alloc_text(PAGE,WorkerThread)
  76. #pragma alloc_text(PAGE,EnumIrda)
  77. #pragma alloc_text(PAGE,DoIasQueries)
  78. #pragma alloc_text(PAGE,CreatePdo)
  79. #pragma alloc_text(PAGE,CreateStaticDevice)
  80. #pragma alloc_text(PAGE,CloseEnumObject)
  81. #pragma alloc_text(PAGE,DeviceNameFromDeviceInfo)
  82. #pragma alloc_text(PAGE,FixupDeviceId)
  83. #pragma alloc_text(PAGE,GetDeviceList)
  84. #pragma alloc_text(PAGE,RemoveDevice)
  85. NTSTATUS
  86. CreateStaticDevice(
  87. PENUM_OBJECT EnumObject
  88. )
  89. {
  90. NTSTATUS Status;
  91. ULONG DeviceId=0;
  92. PIR_DEVICE IrDevice=&EnumObject->Devices[0];
  93. //
  94. // zero the whole thing
  95. //
  96. RtlZeroMemory(IrDevice,sizeof(*IrDevice));
  97. //
  98. // inuse now
  99. //
  100. IrDevice->InUse=TRUE;
  101. IrDevice->PresentCount=DEVICE_PRESENT_START_VALUE;
  102. IrDevice->Static=TRUE;
  103. EnumObject->DeviceCount++;
  104. EnumObject->EnumeratedDevices++;
  105. RtlCopyMemory(&IrDevice->DeviceId,&DeviceId,4);
  106. RtlCopyMemory(
  107. IrDevice->DeviceName,
  108. STATIC_DEVICE_NAME,
  109. sizeof(STATIC_DEVICE_NAME)
  110. );
  111. IrDevice->Name=ALLOCATE_PAGED_POOL(sizeof(STATIC_DEVICE_NAME));
  112. if (IrDevice->Name == NULL) {
  113. Status=STATUS_NO_MEMORY;
  114. goto CleanUp;
  115. }
  116. RtlCopyMemory(
  117. IrDevice->Name,
  118. STATIC_DEVICE_NAME,
  119. sizeof(STATIC_DEVICE_NAME)
  120. );
  121. IrDevice->HardwareId=ALLOCATE_PAGED_POOL(sizeof(STATIC_HARDWARE_ID));
  122. if (IrDevice->HardwareId == NULL) {
  123. Status=STATUS_NO_MEMORY;
  124. goto CleanUp;
  125. }
  126. RtlCopyMemory(
  127. IrDevice->HardwareId,
  128. STATIC_HARDWARE_ID,
  129. sizeof(STATIC_HARDWARE_ID)
  130. );
  131. Status=CreatePdo(
  132. EnumObject->Fdo,
  133. IrDevice
  134. );
  135. if (NT_SUCCESS(Status)) {
  136. return Status;
  137. }
  138. CleanUp:
  139. if (IrDevice->Name != NULL) {
  140. FREE_POOL(IrDevice->Name);
  141. }
  142. if (IrDevice->HardwareId != NULL) {
  143. FREE_POOL(IrDevice->HardwareId);
  144. }
  145. RtlZeroMemory(IrDevice,sizeof(&IrDevice));
  146. EnumObject->DeviceCount--;
  147. EnumObject->EnumeratedDevices--;
  148. return Status;
  149. }
  150. NTSTATUS
  151. CreateEnumObject(
  152. PDEVICE_OBJECT Fdo,
  153. ENUM_HANDLE *Object,
  154. BOOLEAN StaticDevice
  155. )
  156. {
  157. NTSTATUS Status;
  158. PENUM_OBJECT EnumObject;
  159. HANDLE ThreadHandle;
  160. UNICODE_STRING EventName;
  161. *Object=NULL;
  162. EnumObject=ALLOCATE_NONPAGED_POOL(sizeof(*EnumObject));
  163. if (EnumObject==NULL) {
  164. return STATUS_NO_MEMORY;
  165. }
  166. RtlZeroMemory(EnumObject,sizeof(*EnumObject));
  167. KeInitializeEvent(
  168. &EnumObject->WaitEvent,
  169. NotificationEvent,
  170. FALSE
  171. );
  172. KeInitializeTimerEx(
  173. &EnumObject->Timer,
  174. SynchronizationTimer
  175. );
  176. INIT_PASSIVE_LOCK(&EnumObject->PassiveLock);
  177. EnumObject->Fdo=Fdo;
  178. if (StaticDevice) {
  179. CreateStaticDevice(EnumObject);
  180. }
  181. RtlInitUnicodeString(
  182. &EventName,
  183. L"\\Device\\IrEnumIoEvent"
  184. );
  185. EnumObject->IoWaitEventObject=IoCreateNotificationEvent(
  186. &EventName,
  187. &EnumObject->IoWaitEventHandle
  188. );
  189. if (EnumObject->IoWaitEventObject == NULL) {
  190. D_ERROR(DbgPrint("IRENUM: could not create event\n");)
  191. goto CleanUp;
  192. }
  193. Status=PsCreateSystemThread(
  194. &ThreadHandle,
  195. THREAD_ALL_ACCESS,
  196. NULL,
  197. NULL,
  198. NULL,
  199. WorkerThread,
  200. EnumObject
  201. );
  202. if (!NT_SUCCESS(Status)) {
  203. goto CleanUp;
  204. }
  205. Status=ObReferenceObjectByHandle(
  206. ThreadHandle,
  207. 0,
  208. NULL,
  209. KernelMode,
  210. &EnumObject->ThreadObject,
  211. NULL
  212. );
  213. ZwClose(ThreadHandle);
  214. ThreadHandle=NULL;
  215. if (!NT_SUCCESS(Status)) {
  216. goto CleanUp;
  217. }
  218. *Object=EnumObject;
  219. return Status;
  220. CleanUp:
  221. KeSetEvent(
  222. &EnumObject->WaitEvent,
  223. IO_NO_INCREMENT,
  224. FALSE
  225. );
  226. //
  227. // make sure we really got the object
  228. //
  229. if (EnumObject->ThreadObject != NULL) {
  230. KeWaitForSingleObject(
  231. EnumObject->ThreadObject,
  232. Executive,
  233. KernelMode,
  234. FALSE,
  235. NULL
  236. );
  237. ObDereferenceObject(EnumObject->ThreadObject);
  238. }
  239. if (EnumObject->IoWaitEventHandle != NULL) {
  240. ZwClose(EnumObject->IoWaitEventHandle);
  241. }
  242. FREE_POOL(EnumObject);
  243. return Status;
  244. }
  245. VOID
  246. CloseEnumObject(
  247. ENUM_HANDLE Handle
  248. )
  249. {
  250. PENUM_OBJECT EnumObject=Handle;
  251. ULONG j;
  252. KeSetEvent(
  253. &EnumObject->WaitEvent,
  254. IO_NO_INCREMENT,
  255. FALSE
  256. );
  257. KeWaitForSingleObject(
  258. EnumObject->ThreadObject,
  259. Executive,
  260. KernelMode,
  261. FALSE,
  262. NULL
  263. );
  264. ObDereferenceObject(EnumObject->ThreadObject);
  265. if (EnumObject->IoWaitEventHandle != NULL) {
  266. ZwClose(EnumObject->IoWaitEventHandle);
  267. }
  268. for (j=0; j< MAX_DEVICES; j++) {
  269. //
  270. // if remove it
  271. //
  272. if (EnumObject->Devices[j].InUse) {
  273. //
  274. // not enumerated any more since tha parent is going away
  275. //
  276. EnumObject->Devices[j].Enumerated=FALSE;
  277. RemoveDevice(EnumObject,&EnumObject->Devices[j]);
  278. }
  279. }
  280. FREE_POOL(EnumObject);
  281. return;
  282. }
  283. #define OBJECT_ARRAY_SIZE (3)
  284. VOID
  285. WorkerThread(
  286. PVOID Context
  287. )
  288. {
  289. NTSTATUS Status;
  290. PENUM_OBJECT EnumObject=Context;
  291. BOOLEAN ExitLoop=FALSE;
  292. PKEVENT ObjectArray[OBJECT_ARRAY_SIZE];
  293. LARGE_INTEGER DueTime;
  294. DueTime.QuadPart = -10*1000*10000;
  295. D_ENUM(DbgPrint("IRENUM: WorkerThread: started\n");)
  296. KeClearEvent(EnumObject->IoWaitEventObject);
  297. ObjectArray[0]=&EnumObject->WaitEvent;
  298. ObjectArray[1]=(PKEVENT)&EnumObject->Timer;
  299. ObjectArray[2]=EnumObject->IoWaitEventObject;
  300. KeSetTimer(
  301. &EnumObject->Timer,
  302. DueTime,
  303. NULL
  304. );
  305. while (!ExitLoop) {
  306. Status=KeWaitForMultipleObjects(
  307. OBJECT_ARRAY_SIZE,
  308. &ObjectArray[0],
  309. WaitAny,
  310. Executive,
  311. KernelMode,
  312. FALSE,
  313. NULL,
  314. NULL
  315. );
  316. switch (Status) {
  317. case 0:
  318. //
  319. // the event was signaled, time to exit
  320. //
  321. ExitLoop=TRUE;
  322. break;
  323. case 1:
  324. //
  325. // the timer expired, check for devices
  326. //
  327. if (EnumObject->ControlChannel == NULL) {
  328. //
  329. // we have not been able to open the control channel yet
  330. //
  331. Status=IrdaOpenControlChannel(&EnumObject->ControlChannel);
  332. if (!NT_SUCCESS(Status)) {
  333. EnumObject->ControlChannel=NULL;
  334. }
  335. }
  336. if (EnumObject->ControlChannel != NULL) {
  337. //
  338. // we have the control handle, start the discover request
  339. //
  340. IrdaLazyDiscoverDevices(
  341. EnumObject->ControlChannel,
  342. EnumObject->IoWaitEventHandle,
  343. &EnumObject->IoStatusBlock,
  344. (PDEVICELIST)&EnumObject->DeviceListBuffer[0],
  345. sizeof(EnumObject->DeviceListBuffer)
  346. );
  347. } else {
  348. KeSetTimer(
  349. &EnumObject->Timer,
  350. DueTime,
  351. NULL
  352. );
  353. }
  354. break;
  355. case 2:
  356. //
  357. // the discovery completed
  358. //
  359. KeResetEvent(EnumObject->IoWaitEventObject);
  360. if (EnumObject->IoStatusBlock.Status == STATUS_SUCCESS) {
  361. ACQUIRE_PASSIVE_LOCK(&EnumObject->PassiveLock);
  362. EnumIrda(EnumObject);
  363. RELEASE_PASSIVE_LOCK(&EnumObject->PassiveLock);
  364. //
  365. // start another io
  366. //
  367. IrdaLazyDiscoverDevices(
  368. EnumObject->ControlChannel,
  369. EnumObject->IoWaitEventHandle,
  370. &EnumObject->IoStatusBlock,
  371. (PDEVICELIST)&EnumObject->DeviceListBuffer[0],
  372. sizeof(EnumObject->DeviceListBuffer)
  373. );
  374. } else {
  375. //
  376. // the discovery failed, just start the timer
  377. //
  378. KeSetTimer(
  379. &EnumObject->Timer,
  380. DueTime,
  381. NULL
  382. );
  383. }
  384. break;
  385. default:
  386. ASSERT(0);
  387. break;
  388. }
  389. }
  390. KeCancelTimer(&EnumObject->Timer);
  391. D_ENUM(DbgPrint("IRENUM: WorkerThread: stopping\n");)
  392. PsTerminateSystemThread(STATUS_SUCCESS);
  393. return;
  394. }
  395. NTSTATUS
  396. DeviceNameFromDeviceInfo(
  397. PIRDA_DEVICE_INFO DeviceInfo,
  398. PWCHAR DeviceName,
  399. ULONG NameLength
  400. )
  401. {
  402. NTSTATUS Status=STATUS_SUCCESS;
  403. WCHAR TempBuffer[23];
  404. UNICODE_STRING UnicodeString;
  405. //
  406. // zero out the temp buffer, so we can copy the remote device name,
  407. // so we can be sure it is null terminated
  408. //
  409. RtlZeroMemory(TempBuffer,sizeof(TempBuffer));
  410. RtlCopyMemory(TempBuffer,DeviceInfo->irdaDeviceName,sizeof(DeviceInfo->irdaDeviceName));
  411. UnicodeString.Length=0;
  412. UnicodeString.MaximumLength=(USHORT)(NameLength-1)*sizeof(WCHAR);
  413. UnicodeString.Buffer=DeviceName;
  414. RtlZeroMemory(UnicodeString.Buffer,UnicodeString.MaximumLength);
  415. if (DeviceInfo->irdaCharSet == LmCharSetUNICODE) {
  416. //
  417. // the name is unicode
  418. //
  419. Status=RtlAppendUnicodeToString(&UnicodeString,TempBuffer);
  420. } else {
  421. //
  422. // the name is ansi, need to convert unicode
  423. //
  424. ANSI_STRING AnsiString;
  425. RtlInitAnsiString(
  426. &AnsiString,
  427. (PCSZ)TempBuffer
  428. );
  429. Status=RtlAnsiStringToUnicodeString(
  430. &UnicodeString,
  431. &AnsiString,
  432. FALSE
  433. );
  434. }
  435. return Status;
  436. }
  437. NTSTATUS
  438. EnumIrda(
  439. PENUM_OBJECT EnumObject
  440. )
  441. {
  442. NTSTATUS Status;
  443. PDEVICELIST pDevList = (PDEVICELIST)&EnumObject->DeviceListBuffer[0] ;
  444. ULONG i;
  445. ULONG j;
  446. BOOLEAN InvalidateDeviceRelations=FALSE;
  447. PIR_DEVICE IrDevice;
  448. D_ENUM(DbgPrint("IRENUM: Found %d devices\n",pDevList->numDevice);)
  449. for (j=0; j< MAX_DEVICES; j++) {
  450. //
  451. // first mark all the device not present
  452. //
  453. if (!EnumObject->Devices[j].Static) {
  454. //
  455. // only non-static device go away
  456. //
  457. EnumObject->Devices[j].PresentCount--;
  458. }
  459. }
  460. for (i=0; i < pDevList->numDevice; i++) {
  461. PIRDA_DEVICE_INFO DeviceInfo=&pDevList->Device[i];
  462. ULONG DeviceId;
  463. LONG EmptySlot=-1;
  464. RtlCopyMemory(&DeviceId, &DeviceInfo->irdaDeviceID[0],4);
  465. //
  466. // now go through all of our slots to see if we have seen this device before
  467. // based on the name it reports
  468. //
  469. for (j=0; j< MAX_DEVICES; j++) {
  470. WCHAR TempBuffer[24];
  471. if (EnumObject->Devices[j].InUse) {
  472. DeviceNameFromDeviceInfo(
  473. DeviceInfo,
  474. TempBuffer,
  475. sizeof(TempBuffer)/sizeof(WCHAR)
  476. );
  477. if (0 == wcscmp(TempBuffer, EnumObject->Devices[j].DeviceName)) {
  478. //
  479. // Already present
  480. //
  481. EnumObject->Devices[j].PresentCount=DEVICE_PRESENT_START_VALUE;
  482. if (DeviceId != EnumObject->Devices[j].DeviceId) {
  483. //
  484. // the device id seems to have changed since we saw it last, just update it
  485. //
  486. D_ERROR(DbgPrint("IRENUM: Found Dup device %x devices\n",DeviceId);)
  487. RtlCopyMemory(&EnumObject->Devices[j].DeviceId,&DeviceInfo->irdaDeviceID[0],4);
  488. }
  489. break;
  490. }
  491. } else {
  492. //
  493. // this slot is empty, remember this for later
  494. //
  495. if (EmptySlot == -1) {
  496. //
  497. // only set it for this first one
  498. //
  499. EmptySlot=j;
  500. }
  501. }
  502. }
  503. if ( j < MAX_DEVICES) {
  504. //
  505. // We found a match, skip this one
  506. //
  507. continue;
  508. }
  509. if (EmptySlot == -1) {
  510. //
  511. // All of the slots are used up
  512. //
  513. continue;
  514. }
  515. //
  516. // at this point we have a new device
  517. //
  518. IrDevice=&EnumObject->Devices[EmptySlot];
  519. //
  520. // found a slot for it, zero the info
  521. //
  522. RtlZeroMemory(IrDevice,sizeof(*IrDevice));
  523. EnumObject->DeviceCount++;
  524. //
  525. // inuse now
  526. //
  527. IrDevice->InUse=TRUE;
  528. IrDevice->PresentCount=DEVICE_PRESENT_START_VALUE;
  529. IrDevice->DeviceId=DeviceId;
  530. IrDevice->Hint1=DeviceInfo->irdaDeviceHints1;
  531. IrDevice->Hint2=DeviceInfo->irdaDeviceHints2;
  532. DeviceNameFromDeviceInfo(
  533. DeviceInfo,
  534. IrDevice->DeviceName,
  535. sizeof(IrDevice->DeviceName)/sizeof(WCHAR)
  536. );
  537. D_ENUM(DbgPrint(
  538. "IRENUM: Name %ws, device id=%08lx, hint1=%x, hint2=%x\n",
  539. IrDevice->DeviceName,
  540. IrDevice->DeviceId,
  541. IrDevice->Hint1,
  542. IrDevice->Hint2
  543. );)
  544. if (DeviceInfo->irdaDeviceHints1 & LM_HB1_Printer) {
  545. //
  546. // the device says it is a printer
  547. //
  548. IrDevice->Printer=TRUE;
  549. }
  550. if ((DeviceInfo->irdaDeviceHints1 & LM_HB1_Modem) && (DeviceInfo->irdaDeviceHints2 & 4)) {
  551. //
  552. // Device reports that it is a modem that supports ircomm
  553. //
  554. IrDevice->Modem=TRUE;
  555. }
  556. if (DeviceInfo->irdaDeviceHints1 & LM_HB1_PnP) {
  557. //
  558. // the device says it is pnp aware
  559. //
  560. DoIasQueries(
  561. IrDevice
  562. );
  563. if (IrDevice->HardwareId != NULL) {
  564. //
  565. // we were able to query it for a hardware id
  566. //
  567. Status=CreatePdo(
  568. EnumObject->Fdo,
  569. IrDevice
  570. );
  571. if (!NT_SUCCESS(Status)) {
  572. //
  573. // We could not create a PDO for the new device
  574. //
  575. if (IrDevice->Name != NULL) {
  576. FREE_POOL(IrDevice->Name);
  577. }
  578. if (IrDevice->HardwareId != NULL) {
  579. FREE_POOL(IrDevice->HardwareId);
  580. }
  581. } else {
  582. //
  583. // we created a PDO for a new child device
  584. //
  585. EnumObject->EnumeratedDevices++;
  586. //
  587. // new device
  588. //
  589. InvalidateDeviceRelations=TRUE;
  590. }
  591. } else {
  592. //
  593. // the device did not report a pnp hardware id
  594. //
  595. EnumObject->Devices[EmptySlot].Pdo=NULL;
  596. }
  597. } else {
  598. //
  599. // the device is not pnp aware, make something up
  600. //
  601. if ((DeviceInfo->irdaDeviceHints1 & LM_HB1_Modem) && (DeviceInfo->irdaDeviceHints2 & 4)) {
  602. //
  603. // the hint bits report the device as modem that supports ircomm
  604. //
  605. IrDevice->HardwareId=ALLOCATE_PAGED_POOL(sizeof(GENERIC_HARDWARE_ID));
  606. if (IrDevice->HardwareId != NULL) {
  607. wcscpy(IrDevice->HardwareId,GENERIC_HARDWARE_ID);
  608. }
  609. IrDevice->Name=ALLOCATE_NONPAGED_POOL((wcslen(IrDevice->DeviceName)+1)*sizeof(WCHAR));
  610. if (IrDevice->Name != NULL) {
  611. wcscpy(IrDevice->Name,IrDevice->DeviceName);
  612. }
  613. if (IrDevice->HardwareId != NULL) {
  614. //
  615. // we were able to query it for a hardware id
  616. //
  617. Status=CreatePdo(
  618. EnumObject->Fdo,
  619. IrDevice
  620. );
  621. if (!NT_SUCCESS(Status)) {
  622. //
  623. // We could not create a PDO for the new device
  624. //
  625. if (IrDevice->Name != NULL) {
  626. FREE_POOL(IrDevice->Name);
  627. }
  628. if (IrDevice->HardwareId != NULL) {
  629. FREE_POOL(IrDevice->HardwareId);
  630. }
  631. } else {
  632. //
  633. // we created a PDO for a new child device
  634. //
  635. EnumObject->EnumeratedDevices++;
  636. //
  637. // new device
  638. //
  639. InvalidateDeviceRelations=TRUE;
  640. }
  641. }
  642. } else {
  643. //
  644. // the device does not support pnp and it is not an ircomm device
  645. //
  646. }
  647. }
  648. }
  649. for (j=0; j< MAX_DEVICES; j++) {
  650. //
  651. // lets see if anything disappeared
  652. //
  653. if (EnumObject->Devices[j].InUse) {
  654. //
  655. // found a slot that is in use
  656. //
  657. if (EnumObject->Devices[j].PresentCount == 0) {
  658. //
  659. // but it does not have a device present
  660. //
  661. D_ENUM(DbgPrint("IRENUM: Name %ws, no longer present\n",EnumObject->Devices[j].Name);)
  662. if (EnumObject->Devices[j].Pdo != NULL) {
  663. //
  664. // we have enumerated a child for this device
  665. //
  666. InvalidateDeviceRelations=TRUE;
  667. } else {
  668. //
  669. // This one does not have a child, just zero it out
  670. //
  671. RtlZeroMemory(&EnumObject->Devices[j],sizeof(EnumObject->Devices[j]));
  672. EnumObject->DeviceCount--;
  673. }
  674. }
  675. }
  676. }
  677. if (InvalidateDeviceRelations) {
  678. //
  679. // tell the system to check the device relations because a device has appeared or
  680. // disappeared
  681. //
  682. PFDO_DEVICE_EXTENSION FdoExtension=EnumObject->Fdo->DeviceExtension;
  683. IoInvalidateDeviceRelations(FdoExtension->Pdo,BusRelations);
  684. }
  685. return Status;
  686. }
  687. NTSTATUS
  688. CreatePdo(
  689. PDEVICE_OBJECT Fdo,
  690. PIR_DEVICE IrDevice
  691. )
  692. {
  693. NTSTATUS Status;
  694. PDEVICE_OBJECT NewPdo;
  695. Status = IoCreateDevice(
  696. Fdo->DriverObject,
  697. sizeof(PDO_DEVICE_EXTENSION),
  698. NULL,
  699. FILE_DEVICE_BUS_EXTENDER,
  700. FILE_AUTOGENERATED_DEVICE_NAME,
  701. FALSE,
  702. &NewPdo
  703. );
  704. if (NT_SUCCESS(Status)) {
  705. //
  706. // got the device
  707. //
  708. PPDO_DEVICE_EXTENSION PdoExtension=NewPdo->DeviceExtension;
  709. PdoExtension->DoType=DO_TYPE_PDO;
  710. PdoExtension->ParentFdo=Fdo;
  711. PdoExtension->DeviceDescription=IrDevice;
  712. IrDevice->Pdo = NewPdo;
  713. NewPdo->Flags |= DO_POWER_PAGABLE;
  714. NewPdo->Flags &= ~DO_DEVICE_INITIALIZING;
  715. } else {
  716. D_ENUM(DbgPrint("MODEM: CreateChildPdo: IoCreateDevice() failed %08lx\n",Status);)
  717. }
  718. return Status;
  719. }
  720. VOID
  721. FixupDeviceId(
  722. PWSTR HardwareId
  723. )
  724. {
  725. //
  726. // munge the hardware id to make sure it is compatable with the os requirements
  727. //
  728. while (*HardwareId != L'\0') {
  729. if ((*HardwareId < L' ') || (*HardwareId > 127) || (*HardwareId == L',')) {
  730. *HardwareId = L'?';
  731. }
  732. HardwareId++;
  733. }
  734. return;
  735. }
  736. NTSTATUS
  737. DoIasQueries(
  738. PIR_DEVICE IrDevice
  739. )
  740. {
  741. NTSTATUS Status;
  742. LONG CompatCount;
  743. Status=IrdaIASStringQuery(
  744. IrDevice->DeviceId,
  745. "PnP",
  746. "Manufacturer",
  747. &IrDevice->Manufacturer
  748. );
  749. if (NT_SUCCESS(Status)) {
  750. D_ENUM(DbgPrint("IRENUM: got pnp manufacturer %ws\n",IrDevice->Manufacturer);)
  751. }
  752. Status=IrdaIASStringQuery(
  753. IrDevice->DeviceId,
  754. "PnP",
  755. "Name",
  756. &IrDevice->Name
  757. );
  758. if (NT_SUCCESS(Status)) {
  759. D_ENUM(DbgPrint("IRENUM: got pnp name %ws\n",IrDevice->Name);)
  760. }
  761. Status=IrdaIASStringQuery(
  762. IrDevice->DeviceId,
  763. "PnP",
  764. "DeviceID",
  765. &IrDevice->HardwareId
  766. );
  767. if (NT_SUCCESS(Status)) {
  768. D_ENUM(DbgPrint("IRENUM: got pnp id %ws\n",IrDevice->HardwareId);)
  769. FixupDeviceId(IrDevice->HardwareId);
  770. }
  771. //
  772. // check for compat id's
  773. //
  774. IrDevice->CompatIdCount=0;
  775. Status=IrdaIASIntegerQuery(
  776. IrDevice->DeviceId,
  777. "PnP",
  778. "CompCnt",
  779. &CompatCount
  780. );
  781. if (NT_SUCCESS(Status)) {
  782. LONG i;
  783. if ( CompatCount > 16) {
  784. CompatCount=16;
  785. } else {
  786. if ( CompatCount < 0) {
  787. CompatCount = 0;
  788. }
  789. }
  790. for (i=0; i< CompatCount; i++) {
  791. CHAR Attribute[20];
  792. sprintf(Attribute,"Comp#%02d",i+1);
  793. Status=IrdaIASStringQuery(
  794. IrDevice->DeviceId,
  795. "PnP",
  796. Attribute,
  797. &IrDevice->CompatId[IrDevice->CompatIdCount]
  798. );
  799. if (NT_SUCCESS(Status)) {
  800. D_ENUM(DbgPrint("IRENUM: got compat pnp id %ws\n",IrDevice->CompatId[IrDevice->CompatIdCount]);)
  801. FixupDeviceId(IrDevice->CompatId[IrDevice->CompatIdCount]);
  802. IrDevice->CompatIdCount++;
  803. } else {
  804. D_ERROR(DbgPrint("IRENUM: could not get id for %s\n",Attribute);)
  805. }
  806. }
  807. }
  808. if (IrDevice->Modem && !IrDevice->Printer) {
  809. //
  810. // It the hint bits say this is a modem and it is not a printer then
  811. //
  812. // Create a standard compat ID for all devices, so we can load a standard driver
  813. //
  814. IrDevice->CompatId[IrDevice->CompatIdCount]=ALLOCATE_PAGED_POOL(sizeof(IRENUM_COMPAT_ID));
  815. if (IrDevice->CompatId[IrDevice->CompatIdCount] != NULL) {
  816. RtlCopyMemory(IrDevice->CompatId[IrDevice->CompatIdCount],IRENUM_COMPAT_ID,sizeof(IRENUM_COMPAT_ID));
  817. IrDevice->CompatIdCount++;
  818. }
  819. }
  820. return STATUS_SUCCESS;
  821. }
  822. NTSTATUS
  823. GetDeviceList(
  824. ENUM_HANDLE Handle,
  825. PIRP Irp
  826. )
  827. {
  828. PENUM_OBJECT EnumObject=Handle;
  829. NTSTATUS Status=STATUS_SUCCESS;
  830. PDEVICE_RELATIONS CurrentRelations=(PDEVICE_RELATIONS)Irp->IoStatus.Information;
  831. PDEVICE_RELATIONS NewRelations=NULL;
  832. ULONG DeviceCount=EnumObject->DeviceCount;
  833. ULONG i;
  834. ACQUIRE_PASSIVE_LOCK(&EnumObject->PassiveLock);
  835. if (CurrentRelations != NULL) {
  836. //
  837. // we need to allocate a new relations structure and copy the old one to the new one
  838. //
  839. DeviceCount+=CurrentRelations->Count;
  840. }
  841. NewRelations=ALLOCATE_PAGED_POOL(sizeof(DEVICE_RELATIONS)+sizeof(PDEVICE_OBJECT)*DeviceCount);
  842. if (NewRelations == NULL) {
  843. Status= STATUS_INSUFFICIENT_RESOURCES;
  844. } else {
  845. NewRelations->Count=0;
  846. if (CurrentRelations != NULL) {
  847. D_ENUM(DbgPrint("IRENUM: GetDeviceList: %d existing devices\n",CurrentRelations->Count);)
  848. for (i=0; i < CurrentRelations->Count; i++) {
  849. NewRelations->Objects[i]=CurrentRelations->Objects[i];
  850. NewRelations->Count++;
  851. }
  852. FREE_POOL(CurrentRelations);
  853. }
  854. for (i=0; i < MAX_DEVICES; i++) {
  855. if ((EnumObject->Devices[i].Pdo != NULL) && (EnumObject->Devices[i].PresentCount > 0)) {
  856. EnumObject->Devices[i].Enumerated=TRUE;
  857. D_ENUM(DbgPrint("IRENUM: GetDeviceList: reporting DO %p\n",EnumObject->Devices[i].Pdo);)
  858. NewRelations->Objects[NewRelations->Count]=EnumObject->Devices[i].Pdo;
  859. ObReferenceObject(NewRelations->Objects[NewRelations->Count]);
  860. NewRelations->Count++;
  861. } else {
  862. //
  863. // the device is no longer present
  864. //
  865. EnumObject->Devices[i].Enumerated=FALSE;
  866. }
  867. }
  868. Irp->IoStatus.Information=(ULONG_PTR)NewRelations;
  869. }
  870. RELEASE_PASSIVE_LOCK(&EnumObject->PassiveLock);
  871. return Status;
  872. }
  873. VOID
  874. RemoveDevice(
  875. ENUM_HANDLE Handle,
  876. PIR_DEVICE IrDevice
  877. )
  878. {
  879. PENUM_OBJECT EnumObject=Handle;
  880. ACQUIRE_PASSIVE_LOCK(&EnumObject->PassiveLock);
  881. if (IrDevice->Enumerated) {
  882. //
  883. // the device is still present
  884. //
  885. // Just leave it alone
  886. //
  887. } else {
  888. //
  889. // the parent is not enumerating the device anymore
  890. //
  891. PPDO_DEVICE_EXTENSION PdoDeviceExtension;
  892. LONG i;
  893. //
  894. // clean things up
  895. //
  896. if (IrDevice->HardwareId != NULL) {
  897. FREE_POOL(IrDevice->HardwareId);
  898. }
  899. if (IrDevice->Name != NULL) {
  900. FREE_POOL(IrDevice->Name);
  901. }
  902. if (IrDevice->Manufacturer != NULL) {
  903. FREE_POOL(IrDevice->Manufacturer);
  904. }
  905. for (i=0; i< IrDevice->CompatIdCount; i++) {
  906. if (IrDevice->CompatId[i] != NULL) {
  907. FREE_POOL(IrDevice->CompatId[i]);
  908. }
  909. }
  910. if (IrDevice->Pdo != NULL) {
  911. PdoDeviceExtension=IrDevice->Pdo->DeviceExtension;
  912. PdoDeviceExtension->DoType=DO_TYPE_DEL_PDO;
  913. IoDeleteDevice(IrDevice->Pdo);
  914. EnumObject->EnumeratedDevices--;
  915. }
  916. RtlZeroMemory(IrDevice,sizeof(*IrDevice));
  917. EnumObject->DeviceCount--;
  918. }
  919. RELEASE_PASSIVE_LOCK(&EnumObject->PassiveLock);
  920. return;
  921. }