Leaked source code of windows server 2003
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.

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