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.

1654 lines
45 KiB

  1. /*****************************************************************************
  2. `*
  3. * Copyright (c) 1996-1999 Microsoft Corporation
  4. *
  5. * @doc
  6. * @module openclos.c | IrSIR NDIS Miniport Driver
  7. * @comm
  8. *
  9. *-----------------------------------------------------------------------------
  10. *
  11. * Author: Scott Holden (sholden)
  12. *
  13. * Date: 10/3/1996 (created)
  14. *
  15. * Contents: open and close functions for the device
  16. *
  17. *****************************************************************************/
  18. #include "irsir.h"
  19. #include <ntddmodm.h>
  20. NTSTATUS
  21. GetComPortNtDeviceName(
  22. IN PUNICODE_STRING SerialDosName,
  23. IN OUT PUNICODE_STRING NtDevName
  24. );
  25. PIRP
  26. BuildSynchronousCreateCloseRequest(
  27. IN PDEVICE_OBJECT pSerialDevObj,
  28. IN ULONG MajorFunction,
  29. IN PKEVENT pEvent,
  30. OUT PIO_STATUS_BLOCK pIosb
  31. );
  32. NTSTATUS
  33. CheckForModemPort(
  34. PFILE_OBJECT FileObject
  35. );
  36. #pragma alloc_text(PAGE, SerialClose)
  37. #pragma alloc_text(PAGE, GetComPortNtDeviceName)
  38. #pragma alloc_text(PAGE, GetDeviceConfiguration)
  39. #pragma alloc_text(PAGE, BuildSynchronousCreateCloseRequest)
  40. #if 0
  41. NTSTATUS PortNotificationCallback(PVOID NotificationStructure, PVOID Context)
  42. {
  43. DEVICE_INTERFACE_CHANGE_NOTIFICATION *Notification = NotificationStructure;
  44. PIR_DEVICE pThisDev = Context;
  45. NDIS_STATUS Status;
  46. DEBUGMSG(DBG_FUNC|DBG_PNP, ("+PortNotificationCallback\n"));
  47. DEBUGMSG(DBG_PNP, ("New port:%wZ\n", Notification->SymbolicLinkName));
  48. Status = GetComPortNtDeviceName(&pThisDev->serialDosName,
  49. &pThisDev->serialDevName);
  50. if (Status==NDIS_STATUS_SUCCESS)
  51. {
  52. // We found our port. Initialize.
  53. Status = ResetIrDevice(pThisDev);
  54. if (Status!=NDIS_STATUS_SUCCESS)
  55. {
  56. DEBUGMSG(DBG_ERROR, ("IRSIR:ResetIrDevice failed in PortNotificationCallback (0x%x)\n", Status));
  57. }
  58. else
  59. {
  60. DEBUGMSG(DBG_PNP, ("IRSIR:Successfully opened port after delay.\n"));
  61. Status = IoUnregisterPlugPlayNotification(pThisDev->PnpNotificationEntry);
  62. ASSERT(Status==NDIS_STATUS_SUCCESS);
  63. }
  64. }
  65. else
  66. {
  67. // We didn't find it. Wait for the next notification.
  68. }
  69. DEBUGMSG(DBG_FUNC|DBG_PNP, ("-PortNotificationCallback\n"));
  70. return STATUS_SUCCESS;
  71. }
  72. #endif
  73. /*****************************************************************************
  74. *
  75. * Function: InitializeDevice
  76. *
  77. * Synopsis: allocate resources for a single ir device object
  78. *
  79. * Arguments: pThisDev - ir device object to open
  80. *
  81. * Returns: NDIS_STATUS_SUCCESS - if device is successfully opened
  82. * NDIS_STATUS_RESOURCES - could not claim sufficient
  83. * resources
  84. *
  85. * Algorithm:
  86. *
  87. * History: dd-mm-yyyy Author Comment
  88. * 10/3/1996 sholden author
  89. *
  90. * Notes:
  91. * we do alot of stuff in this open device function
  92. * - allocate packet pool
  93. * - allocate buffer pool
  94. * - allocate packets/buffers/memory and chain together
  95. * (only one buffer per packet)
  96. * - initialize send queue
  97. *
  98. * This function should be called with device lock held.
  99. *
  100. * We don't initialize the following ir device object entries, since
  101. * these values will outlast an IrsirReset.
  102. * serialDevName
  103. * pSerialDevObj
  104. * hNdisAdapter
  105. * transceiverType
  106. * dongle
  107. * dongleCaps
  108. * fGotFilterIndication
  109. *
  110. *****************************************************************************/
  111. NDIS_STATUS
  112. InitializeDevice(
  113. IN OUT PIR_DEVICE pThisDev)
  114. {
  115. int i;
  116. NDIS_STATUS status = NDIS_STATUS_SUCCESS;
  117. DEBUGMSG(DBG_FUNC|DBG_PNP, ("+InitializeDevice\n"));
  118. ASSERT(pThisDev != NULL);
  119. pThisDev->pSerialDevObj = NULL;
  120. //
  121. // Will set speed to 9600 baud initially.
  122. //
  123. pThisDev->linkSpeedInfo = &supportedBaudRateTable[BAUDRATE_9600];
  124. //
  125. // Current speed is unknown, SetSpeed will update this.
  126. //
  127. pThisDev->currentSpeed = 0;
  128. //
  129. // Init statistical info.
  130. //
  131. pThisDev->packetsReceived = 0;
  132. pThisDev->packetsReceivedDropped = 0;
  133. pThisDev->packetsReceivedOverflow = 0;
  134. pThisDev->packetsSent = 0;
  135. pThisDev->packetsSentDropped = 0;
  136. InitializePacketQueue(
  137. &pThisDev->SendPacketQueue,
  138. pThisDev,
  139. SendPacketToSerial
  140. );
  141. //
  142. // Set fMediaBusy to TRUE initially. That way, we won't
  143. // IndicateStatus to the protocol in the receive poll loop
  144. // unless the protocol has expressed interest by clearing this flag
  145. // via IrsirSetInformation(OID_IRDA_MEDIA_BUSY).
  146. //
  147. pThisDev->fMediaBusy = TRUE;
  148. pThisDev->fReceiving = FALSE;
  149. pThisDev->fRequireMinTurnAround = TRUE;
  150. pThisDev->fPendingSetSpeed = FALSE;
  151. pThisDev->fPendingHalt = FALSE;
  152. pThisDev->fPendingReset = FALSE;
  153. //
  154. // Initialize spin locks
  155. //
  156. NdisAllocateSpinLock(&(pThisDev->mediaBusySpinLock));
  157. NdisAllocateSpinLock(&(pThisDev->slWorkItem));
  158. //
  159. // Initialize the queues.
  160. //
  161. NdisInitializeListHead(&(pThisDev->rcvFreeQueue));
  162. NdisInitializeListHead(&(pThisDev->leWorkItems));
  163. //
  164. // Initialize the spin lock for the two above queues.
  165. //
  166. NdisAllocateSpinLock(&(pThisDev->rcvQueueSpinLock));
  167. //
  168. // Initialize the receive information buffer.
  169. //
  170. pThisDev->rcvInfo.rcvState = RCV_STATE_READY;
  171. pThisDev->rcvInfo.rcvBufPos = 0;
  172. pThisDev->rcvInfo.pRcvBuffer = NULL;
  173. //
  174. // Allocate the NDIS packet and NDIS buffer pools
  175. // for this device's RECEIVE buffer queue.
  176. // Our receive packets must only contain one buffer apiece,
  177. // so #buffers == #packets.
  178. //
  179. NdisAllocatePacketPool(
  180. &status, // return status
  181. &pThisDev->hPacketPool, // handle to the packet pool
  182. NUM_RCV_BUFS, // number of packet descriptors
  183. 16 // number of bytes reserved for
  184. ); // ProtocolReserved field
  185. if (status != NDIS_STATUS_SUCCESS)
  186. {
  187. DEBUGMSG(DBG_OUT, (" NdisAllocatePacketPool failed. Returned 0x%.8x\n",
  188. status));
  189. goto done;
  190. }
  191. NdisAllocateBufferPool(
  192. &status, // return status
  193. &pThisDev->hBufferPool,// handle to the buffer pool
  194. NUM_RCV_BUFS // number of buffer descriptors
  195. );
  196. if (status != NDIS_STATUS_SUCCESS)
  197. {
  198. DEBUGMSG(DBG_OUT, (" NdisAllocateBufferPool failed. Returned 0x%.8x\n",
  199. status));
  200. goto done;
  201. }
  202. //
  203. // Initialize each of the RECEIVE objects for this device.
  204. //
  205. for (i = 0; i < NUM_RCV_BUFS; i++)
  206. {
  207. PNDIS_BUFFER pBuffer = NULL;
  208. PRCV_BUFFER pRcvBuf = &pThisDev->rcvBufs[i];
  209. //
  210. // Allocate a data buffer
  211. //
  212. // This buffer gets swapped with the one on comPortInfo
  213. // and must be the same size.
  214. //
  215. pRcvBuf->dataBuf = MyMemAlloc(RCV_BUFFER_SIZE);
  216. if (pRcvBuf->dataBuf == NULL)
  217. {
  218. status = NDIS_STATUS_RESOURCES;
  219. goto done;
  220. }
  221. NdisZeroMemory(
  222. pRcvBuf->dataBuf,
  223. RCV_BUFFER_SIZE
  224. );
  225. pRcvBuf->dataLen = 0;
  226. //
  227. // Allocate the NDIS_PACKET.
  228. //
  229. NdisAllocatePacket(
  230. &status, // return status
  231. &pRcvBuf->packet, // return pointer to allocated descriptor
  232. pThisDev->hPacketPool // handle to packet pool
  233. );
  234. if (status != NDIS_STATUS_SUCCESS)
  235. {
  236. DEBUGMSG(DBG_OUT, (" NdisAllocatePacket failed. Returned 0x%.8x\n",
  237. status));
  238. goto done;
  239. }
  240. //
  241. // Allocate the NDIS_BUFFER.
  242. //
  243. NdisAllocateBuffer(
  244. &status, // return status
  245. &pBuffer, // return pointer to allocated descriptor
  246. pThisDev->hBufferPool, // handle to buffer pool
  247. pRcvBuf->dataBuf, // virtual address mapped to descriptor
  248. RCV_BUFFER_SIZE // number of bytes mapped
  249. );
  250. if (status != NDIS_STATUS_SUCCESS)
  251. {
  252. DEBUGMSG(DBG_OUT, (" NdisAllocateBuffer failed. Returned 0x%.8x\n",
  253. status));
  254. goto done;
  255. }
  256. //
  257. // Need to chain the buffer to the packet.
  258. //
  259. NdisChainBufferAtFront(
  260. pRcvBuf->packet, // packet descriptor
  261. pBuffer // buffer descriptor to add to chain
  262. );
  263. //
  264. // For future convenience, set the MiniportReserved portion of the packet
  265. // to the index of the rcv buffer that contains it.
  266. // This will be used in IrsirReturnPacket.
  267. //
  268. {
  269. PPACKET_RESERVED_BLOCK PacketReserved;
  270. PacketReserved=(PPACKET_RESERVED_BLOCK)&pRcvBuf->packet->MiniportReservedEx[0];
  271. PacketReserved->Context=pRcvBuf;
  272. }
  273. //
  274. // Add the receive buffer to the free queue.
  275. //
  276. MyInterlockedInsertTailList(
  277. &(pThisDev->rcvFreeQueue),
  278. &pRcvBuf->linkage,
  279. &(pThisDev->rcvQueueSpinLock)
  280. );
  281. }
  282. pThisDev->pRcvIrpBuffer = ExAllocatePoolWithTag(
  283. NonPagedPoolCacheAligned,
  284. SERIAL_RECEIVE_BUFFER_LENGTH,
  285. IRSIR_TAG
  286. );
  287. if (pThisDev->pRcvIrpBuffer == NULL)
  288. {
  289. DEBUGMSG(DBG_OUT, (" ExAllocatePool failed.\n"));
  290. status = NDIS_STATUS_RESOURCES;
  291. goto done;
  292. }
  293. pThisDev->pSendIrpBuffer = ExAllocatePoolWithTag(
  294. NonPagedPoolCacheAligned,
  295. MAX_IRDA_DATA_SIZE,
  296. IRSIR_TAG
  297. );
  298. if (pThisDev->pSendIrpBuffer == NULL)
  299. {
  300. DEBUGMSG(DBG_OUT, (" ExAllocatePool failed.\n"));
  301. status = NDIS_STATUS_RESOURCES;
  302. goto done;
  303. }
  304. done:
  305. //
  306. // If we didn't complete the init successfully, then we should clean
  307. // up what we did allocate.
  308. //
  309. if (status != NDIS_STATUS_SUCCESS)
  310. {
  311. DeinitializeDevice(pThisDev);
  312. }
  313. DEBUGMSG(DBG_FUNC|DBG_PNP, ("-InitializeDevice()\n"));
  314. return status;
  315. }
  316. /*****************************************************************************
  317. *
  318. * Function: DeinitializeDevice
  319. *
  320. * Synopsis: deallocate the resources of the ir device object
  321. *
  322. * Arguments: pThisDev - the ir device object to close
  323. *
  324. * Returns: none
  325. *
  326. * Algorithm:
  327. *
  328. * History: dd-mm-yyyy Author Comment
  329. * 10/3/1996 sholden author
  330. *
  331. * Notes:
  332. *
  333. * Called for shutdown and reset.
  334. * Don't clear hNdisAdapter, since we might just be resetting.
  335. * This function should be called with device lock held.
  336. *
  337. *****************************************************************************/
  338. NDIS_STATUS
  339. DeinitializeDevice(
  340. IN OUT PIR_DEVICE pThisDev
  341. )
  342. {
  343. UINT i;
  344. NDIS_HANDLE hSwitchToMiniport;
  345. BOOLEAN fSwitchSuccessful;
  346. NDIS_STATUS status;
  347. DEBUGMSG(DBG_FUNC|DBG_PNP, ("+DeinitializeDevice\n"));
  348. status = NDIS_STATUS_SUCCESS;
  349. ASSERT(pThisDev != NULL);
  350. pThisDev->linkSpeedInfo = NULL;
  351. NdisFreeSpinLock(&(pThisDev->rcvQueueSpinLock));
  352. NdisFreeSpinLock(&(pThisDev->sendSpinLock));
  353. //
  354. // Free all resources for the RECEIVE buffer queue.
  355. //
  356. for (i = 0; i < NUM_RCV_BUFS; i++)
  357. {
  358. PNDIS_BUFFER pBuffer = NULL;
  359. PRCV_BUFFER pRcvBuf = &pThisDev->rcvBufs[i];
  360. //
  361. // Need to unchain the packet and buffer combo.
  362. //
  363. if (pRcvBuf->packet)
  364. {
  365. NdisUnchainBufferAtFront(
  366. pRcvBuf->packet,
  367. &pBuffer
  368. );
  369. }
  370. //
  371. // free the buffer, packet and data
  372. //
  373. if (pBuffer != NULL)
  374. {
  375. NdisFreeBuffer(pBuffer);
  376. }
  377. if (pRcvBuf->packet != NULL)
  378. {
  379. NdisFreePacket(pRcvBuf->packet);
  380. pRcvBuf->packet = NULL;
  381. }
  382. if (pRcvBuf->dataBuf != NULL)
  383. {
  384. MyMemFree(pRcvBuf->dataBuf, RCV_BUFFER_SIZE);
  385. pRcvBuf->dataBuf = NULL;
  386. }
  387. pRcvBuf->dataLen = 0;
  388. }
  389. //
  390. // Free the packet and buffer pool handles for this device.
  391. //
  392. if (pThisDev->hPacketPool)
  393. {
  394. NdisFreePacketPool(pThisDev->hPacketPool);
  395. pThisDev->hPacketPool = NULL;
  396. }
  397. if (pThisDev->hBufferPool)
  398. {
  399. NdisFreeBufferPool(pThisDev->hBufferPool);
  400. pThisDev->hBufferPool = NULL;
  401. }
  402. //
  403. // Free all resources for the SEND buffer queue.
  404. //
  405. FlushQueuedPackets(&pThisDev->SendPacketQueue,pThisDev->hNdisAdapter);
  406. //
  407. // Deallocate the irp buffers.
  408. //
  409. if (pThisDev->pRcvIrpBuffer != NULL)
  410. {
  411. ExFreePool(pThisDev->pRcvIrpBuffer);
  412. pThisDev->pRcvIrpBuffer = NULL;
  413. }
  414. if (pThisDev->pSendIrpBuffer != NULL)
  415. {
  416. ExFreePool(pThisDev->pSendIrpBuffer);
  417. pThisDev->pSendIrpBuffer = NULL;
  418. }
  419. pThisDev->fMediaBusy = FALSE;
  420. DEBUGMSG(DBG_FUNC|DBG_PNP, ("-DeinitializeDevice\n"));
  421. return status;
  422. }
  423. NTSTATUS GetComPortNtDeviceName(IN PUNICODE_STRING SerialDosName,
  424. IN OUT PUNICODE_STRING NtDevName)
  425. /*++
  426. Routine Description:
  427. Retrieves the NT device name (\device\serial0) for a given COM port.
  428. Arguments:
  429. SerialDosName - identifies the port, i.e. COM1
  430. NtDevName - Allocates a buffer (if necessary) and returns the associated
  431. nt device name.
  432. Return Value:
  433. STATUS_SUCCESS or error code.
  434. --*/
  435. {
  436. UNICODE_STRING registryPath;
  437. OBJECT_ATTRIBUTES objectAttributes;
  438. HANDLE hKey = 0;
  439. PKEY_VALUE_PARTIAL_INFORMATION pKeyValuePartialInfo = 0;
  440. PKEY_VALUE_BASIC_INFORMATION pKeyValueBasicInfo = 0;
  441. NTSTATUS status = STATUS_SUCCESS;
  442. int i;
  443. ULONG resultLength;
  444. UNICODE_STRING serialTmpString;
  445. DEBUGMSG(DBG_OUT, ("IRSIR: Retrieving NT device name for %wZ\n",
  446. SerialDosName));
  447. RtlInitUnicodeString(
  448. &registryPath,
  449. L"\\Registry\\Machine\\Hardware\\DeviceMap\\SerialComm"
  450. );
  451. //
  452. // Initialize the serial device object name in the context of
  453. // our ir device object.
  454. //
  455. if (!NtDevName->Buffer)
  456. {
  457. NtDevName->Buffer = MyMemAlloc(MAX_SERIAL_NAME_SIZE);
  458. }
  459. NtDevName->MaximumLength = MAX_SERIAL_NAME_SIZE;
  460. NtDevName->Length = 0;
  461. InitializeObjectAttributes(
  462. &objectAttributes,
  463. &registryPath,
  464. OBJ_CASE_INSENSITIVE,
  465. NULL,
  466. NULL
  467. );
  468. hKey = NULL;
  469. status = ZwOpenKey(
  470. &hKey,
  471. KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS,
  472. &objectAttributes
  473. );
  474. if (status != STATUS_SUCCESS)
  475. {
  476. //DEBUGMSG(DBG_ERR, (" ZwOpenKey failed = 0x%.8x\n", status));
  477. goto error10;
  478. }
  479. pKeyValuePartialInfo = MyMemAlloc(sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 256);
  480. pKeyValueBasicInfo = MyMemAlloc(sizeof(KEY_VALUE_BASIC_INFORMATION) + 256);
  481. if (pKeyValuePartialInfo && pKeyValueBasicInfo)
  482. {
  483. for (i = 0; ; i++)
  484. {
  485. NdisZeroMemory(
  486. pKeyValuePartialInfo,
  487. sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 256
  488. );
  489. NdisZeroMemory(
  490. pKeyValueBasicInfo,
  491. sizeof(KEY_VALUE_BASIC_INFORMATION) + 256
  492. );
  493. status = ZwEnumerateValueKey(
  494. hKey,
  495. i,
  496. KeyValuePartialInformation,
  497. pKeyValuePartialInfo,
  498. sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 256,
  499. &resultLength
  500. );
  501. if (status != STATUS_SUCCESS)
  502. {
  503. if (status != STATUS_NO_MORE_ENTRIES)
  504. {
  505. DEBUGMSG(DBG_ERR, (" ZwEnumerateValueKey failed = 0x%.8x\n", status));
  506. }
  507. else
  508. {
  509. DEBUGMSG(DBG_ERR, (" Valid comm port not found.\n"));
  510. status = NDIS_STATUS_ADAPTER_NOT_FOUND;
  511. }
  512. break;
  513. }
  514. pKeyValuePartialInfo->Data[pKeyValuePartialInfo->DataLength/sizeof(WCHAR)] =
  515. UNICODE_NULL;
  516. RtlInitUnicodeString(
  517. &serialTmpString,
  518. (PCWSTR)pKeyValuePartialInfo->Data
  519. );
  520. DEBUGMSG(DBG_OUT, (" Value found = %wZ\n", &serialTmpString));
  521. if (RtlCompareUnicodeString(
  522. &serialTmpString,
  523. SerialDosName,
  524. TRUE) // ignore case
  525. == 0)
  526. {
  527. //
  528. // We have found the comm port. Now we need to get the
  529. // name like SerialX.
  530. //
  531. status = ZwEnumerateValueKey(
  532. hKey,
  533. i,
  534. KeyValueBasicInformation,
  535. pKeyValueBasicInfo,
  536. sizeof(KEY_VALUE_BASIC_INFORMATION) + 256,
  537. &resultLength
  538. );
  539. if (status != STATUS_SUCCESS)
  540. {
  541. if (status != STATUS_NO_MORE_ENTRIES)
  542. {
  543. DEBUGMSG(DBG_ERR, (" ZwEnumerateValueKey failed = 0x%.8x\n", status));
  544. }
  545. else
  546. {
  547. DEBUGMSG(DBG_ERR, (" COMx != Serial?.\n"));
  548. }
  549. break;
  550. }
  551. //
  552. // We have our key name.
  553. //
  554. if (pKeyValueBasicInfo->Name[0]!=L'\\')
  555. {
  556. //
  557. // The key name needs to start with \Device\,
  558. // and apparently this one doesn't. Add it.
  559. //
  560. RtlAppendUnicodeToString(NtDevName, L"\\Device\\");
  561. }
  562. //
  563. // Append the name.
  564. //
  565. status = RtlAppendUnicodeToString(
  566. NtDevName,
  567. pKeyValueBasicInfo->Name
  568. );
  569. if (status != STATUS_SUCCESS)
  570. {
  571. DEBUGMSG(DBG_ERR, (" RtlAppendUnicodeToString failed = 0x%.8x\n", status));
  572. }
  573. break;
  574. } // if RtlCompareUnicodeString
  575. } // for
  576. }
  577. //
  578. // NOTE: This path is not necessarily STATUS_SUCCESS.
  579. //
  580. if (pKeyValueBasicInfo)
  581. {
  582. MyMemFree(
  583. pKeyValueBasicInfo,
  584. sizeof(KEY_VALUE_BASIC_INFORMATION) + 256
  585. );
  586. }
  587. if (pKeyValuePartialInfo)
  588. {
  589. MyMemFree(
  590. pKeyValuePartialInfo,
  591. sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 256
  592. );
  593. }
  594. if (hKey)
  595. {
  596. ZwClose(hKey);
  597. }
  598. error10:;
  599. return status;
  600. }
  601. /*****************************************************************************
  602. *
  603. * Function: GetDeviceConfiguration
  604. *
  605. * Synopsis: get the configuration from the registry
  606. *
  607. * Arguments: pThisDev - pointer to the ir device object
  608. *
  609. * Returns: NDIS_STATUS_SUCCESS - if device retrieves configuration
  610. *
  611. * Algorithm:
  612. *
  613. * History: dd-mm-yyyy Author Comment
  614. * 10/3/1996 sholden author
  615. *
  616. * Notes:
  617. *
  618. *
  619. *****************************************************************************/
  620. NDIS_STATUS
  621. GetDeviceConfiguration(
  622. IN OUT PIR_DEVICE pThisDev,
  623. IN NDIS_HANDLE WrapperConfigurationContext
  624. )
  625. {
  626. NDIS_STATUS status, tmpStatus;
  627. NDIS_HANDLE hConfig;
  628. PNDIS_CONFIGURATION_PARAMETER configParamPtr;
  629. UNICODE_STRING serialCommString;
  630. UNICODE_STRING serialTmpString;
  631. UNICODE_STRING NetCfgInstanceID;
  632. UNICODE_STRING registryPath;
  633. OBJECT_ATTRIBUTES objectAttributes;
  634. HANDLE hKey;
  635. PKEY_VALUE_PARTIAL_INFORMATION pKeyValuePartialInfo;
  636. PKEY_VALUE_BASIC_INFORMATION pKeyValueBasicInfo;
  637. ULONG resultLength;
  638. int i;
  639. NDIS_STRING regKeyPortString = NDIS_STRING_CONST("PORT");
  640. NDIS_STRING regKeyIRTransceiverString = NDIS_STRING_CONST("InfraredTransceiverType");
  641. NDIS_STRING regKeySerialBasedString = NDIS_STRING_CONST("SerialBased");
  642. NDIS_STRING regKeyMaxConnectString = NDIS_STRING_CONST("MaxConnectRate");
  643. NDIS_STRING regKeyNetCfgInstance = NDIS_STRING_CONST("NetCfgInstanceID");
  644. NDIS_STRING ComPortStr = NDIS_STRING_CONST("COM1");
  645. DEBUGMSG(DBG_FUNC|DBG_PNP, ("+GetDeviceConfiguration\n"));
  646. //
  647. // Set the default value.
  648. //
  649. pThisDev->transceiverType = STANDARD_UART;
  650. //
  651. // Open up the registry with our WrapperConfigurationContext.
  652. //
  653. // HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\
  654. // ?DriverName?[instance]\Parameters\
  655. //
  656. NdisOpenConfiguration(
  657. &status, // return status
  658. &hConfig, // configuration handle
  659. WrapperConfigurationContext // handle input to IrsirInitialize
  660. );
  661. if (status != NDIS_STATUS_SUCCESS)
  662. {
  663. DEBUGMSG(DBG_ERR, (" NdisOpenConfiguration failed. Returned 0x%.8x\n",
  664. status));
  665. goto done;
  666. }
  667. //
  668. // Attempt to read the registry for transceiver string.
  669. //
  670. NdisReadConfiguration(
  671. &tmpStatus, // return status
  672. &configParamPtr, // return reg data
  673. hConfig, // handle to open reg configuration
  674. &regKeyIRTransceiverString,// keyword to look for in reg
  675. NdisParameterInteger // we want a integer
  676. );
  677. if (tmpStatus == NDIS_STATUS_SUCCESS)
  678. {
  679. pThisDev->transceiverType =
  680. (IR_TRANSCEIVER_TYPE)configParamPtr->ParameterData.IntegerData;
  681. DEBUGMSG(DBG_OUT|DBG_PNP, ("TransceiverType:%d\n\n", pThisDev->transceiverType));
  682. }
  683. else
  684. {
  685. DEBUGMSG(DBG_ERR, (" NdisReadConfiguration(TransceiverStr) failed. Returned 0x%.8x\n",
  686. status));
  687. DEBUGMSG(DBG_OUT|DBG_PNP, ("Using default TransceiverType:%d\n\n", pThisDev->transceiverType));
  688. }
  689. //
  690. // Attempt to read the registry for transceiver string.
  691. //
  692. NdisReadConfiguration(
  693. &tmpStatus, // return status
  694. &configParamPtr, // return reg data
  695. hConfig, // handle to open reg configuration
  696. &regKeyMaxConnectString, // keyword to look for in reg
  697. NdisParameterInteger // we want a integer
  698. );
  699. if (tmpStatus == NDIS_STATUS_SUCCESS)
  700. {
  701. pThisDev->AllowedSpeedsMask = 0;
  702. switch (configParamPtr->ParameterData.IntegerData)
  703. {
  704. default:
  705. case 115200:
  706. pThisDev->AllowedSpeedsMask |= NDIS_IRDA_SPEED_115200;
  707. case 57600:
  708. pThisDev->AllowedSpeedsMask |= NDIS_IRDA_SPEED_57600;
  709. case 38400:
  710. pThisDev->AllowedSpeedsMask |= NDIS_IRDA_SPEED_38400;
  711. case 19200:
  712. pThisDev->AllowedSpeedsMask |= NDIS_IRDA_SPEED_19200;
  713. case 2400: // Always allow 9600
  714. pThisDev->AllowedSpeedsMask |= NDIS_IRDA_SPEED_2400;
  715. case 9600:
  716. pThisDev->AllowedSpeedsMask |= NDIS_IRDA_SPEED_9600;
  717. break;
  718. }
  719. }
  720. else
  721. {
  722. pThisDev->AllowedSpeedsMask = ALL_SLOW_IRDA_SPEEDS;
  723. }
  724. //
  725. // Attempt to read the registry to determine if we've been PNPed
  726. //
  727. NdisReadConfiguration(
  728. &tmpStatus, // return status
  729. &configParamPtr, // return reg data
  730. hConfig, // handle to open reg configuration
  731. &regKeySerialBasedString, // keyword to look for in reg
  732. NdisParameterInteger // we want a integer
  733. );
  734. if (tmpStatus == NDIS_STATUS_SUCCESS)
  735. {
  736. pThisDev->SerialBased =
  737. (BOOLEAN)configParamPtr->ParameterData.IntegerData;
  738. }
  739. else
  740. {
  741. pThisDev->SerialBased = TRUE;
  742. }
  743. DEBUGMSG(DBG_OUT|DBG_PNP, ("IRSIR: Adapter is%s serial-based.\n", (pThisDev->SerialBased ? "" : " NOT")));
  744. if (pThisDev->SerialBased)
  745. {
  746. if (!pThisDev->serialDosName.Buffer)
  747. {
  748. pThisDev->serialDosName.Buffer = MyMemAlloc(MAX_SERIAL_NAME_SIZE);
  749. }
  750. pThisDev->serialDosName.MaximumLength = MAX_SERIAL_NAME_SIZE;
  751. pThisDev->serialDosName.Length = 0;
  752. //
  753. // Attempt to read the registry for PORT...we want something
  754. // like COM1
  755. //
  756. NdisReadConfiguration(
  757. &tmpStatus, // return status
  758. &configParamPtr, // return reg data
  759. hConfig, // handle to open reg configuration
  760. &regKeyPortString, // keyword to look for in reg
  761. NdisParameterString // we want a string
  762. );
  763. if (tmpStatus == NDIS_STATUS_SUCCESS)
  764. {
  765. RtlInitUnicodeString(
  766. &serialCommString,
  767. configParamPtr->ParameterData.StringData.Buffer
  768. );
  769. }
  770. else
  771. {
  772. RtlInitUnicodeString(
  773. &serialCommString,
  774. ComPortStr.Buffer
  775. );
  776. DEBUGMSG(DBG_OUT|DBG_PNP, ("Using default port\n"));
  777. }
  778. RtlAppendUnicodeStringToString(
  779. &pThisDev->serialDosName,
  780. &configParamPtr->ParameterData.StringData
  781. );
  782. DEBUGMSG(DBG_OUT, (" Port = %wZ\n", &serialCommString));
  783. #if 0
  784. status = GetComPortNtDeviceName(&pThisDev->serialDosName,
  785. &pThisDev->serialDevName);
  786. if (status!=STATUS_SUCCESS)
  787. {
  788. #if 0
  789. // This would have been a nice mechanism to use, but it notifies us
  790. // before the SERIALCOMM entries are made. It looks like this has
  791. // the potential to change, so we'll leave this code in and disabled
  792. // and revisit it later. - StanA
  793. NTSTATUS TmpStatus;
  794. //
  795. // The port isn't there yet, and we want to know when it is.
  796. // Register for PNP notifications.
  797. //
  798. TmpStatus = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
  799. PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
  800. (GUID*)&GUID_DEVCLASS_PORTS,
  801. DriverObject,
  802. PortNotificationCallback,
  803. pThisDev,
  804. &pThisDev->PnpNotificationEntry);
  805. #endif
  806. }
  807. #endif
  808. }
  809. else // ! SerialBased
  810. {
  811. NDIS_STRING IoBaseAddress = NDIS_STRING_CONST("IoBaseAddress");
  812. NDIS_STRING Interrupt = NDIS_STRING_CONST("InterruptNumber");
  813. NdisReadConfiguration(&tmpStatus,
  814. &configParamPtr,
  815. hConfig,
  816. &IoBaseAddress,
  817. NdisParameterHexInteger);
  818. DEBUGMSG(DBG_OUT|DBG_PNP, ("IRSIR: IoBaseAddress:%x\n", configParamPtr->ParameterData.IntegerData));
  819. NdisReadConfiguration(&tmpStatus,
  820. &configParamPtr,
  821. hConfig,
  822. &Interrupt,
  823. NdisParameterHexInteger);
  824. DEBUGMSG(DBG_OUT|DBG_PNP, ("IRSIR: Interrupt:%x\n", configParamPtr->ParameterData.IntegerData));
  825. }
  826. status = SetIrFunctions(pThisDev);
  827. if (status!=STATUS_SUCCESS)
  828. {
  829. goto error10;
  830. }
  831. status = pThisDev->dongle.QueryCaps(&pThisDev->dongleCaps);
  832. if (status!=STATUS_SUCCESS)
  833. {
  834. goto error10;
  835. }
  836. NdisCloseConfiguration(hConfig);
  837. goto done;
  838. error10:
  839. NdisCloseConfiguration(hConfig);
  840. done:
  841. DEBUGMSG(DBG_FUNC|DBG_PNP, ("-GetDeviceConfiguration\n"));
  842. return status;
  843. }
  844. NTSTATUS
  845. SyncOpenCloseCompletion(
  846. IN PDEVICE_OBJECT DeviceObject,
  847. IN PIRP pIrp,
  848. IN PVOID Context)
  849. {
  850. IoFreeIrp(pIrp);
  851. return STATUS_MORE_PROCESSING_REQUIRED;
  852. }
  853. /*****************************************************************************
  854. *
  855. * Function: BuildSynchronousCreateRequest
  856. *
  857. * Synopsis:
  858. *
  859. * Arguments:
  860. *
  861. * Returns:
  862. *
  863. * Algorithm:
  864. *
  865. * History: dd-mm-yyyy Author Comment
  866. * 10/3/1996 sholden author
  867. *
  868. * Notes:
  869. * this is pretty much stolen from IoBuildDeviceIoControlRequest
  870. *
  871. *
  872. *****************************************************************************/
  873. PIRP
  874. BuildSynchronousCreateCloseRequest(
  875. IN PDEVICE_OBJECT pSerialDevObj,
  876. IN ULONG MajorFunction,
  877. IN PKEVENT pEvent,
  878. OUT PIO_STATUS_BLOCK pIosb
  879. )
  880. {
  881. PIRP pIrp;
  882. PIO_STACK_LOCATION irpSp;
  883. //
  884. // Begin by allocating the IRP for this request.
  885. //
  886. pIrp = IoAllocateIrp(pSerialDevObj->StackSize, FALSE);
  887. if (pIrp == NULL)
  888. {
  889. return pIrp;
  890. }
  891. //
  892. // Get a pointer to the stack location of the first driver which will be
  893. // invoked. This is where the function codes and the parameters are set.
  894. //
  895. irpSp = IoGetNextIrpStackLocation( pIrp );
  896. //
  897. // Set the major function code.
  898. //
  899. irpSp->MajorFunction = (UCHAR)MajorFunction;
  900. //
  901. // Set the appropriate irp fields.
  902. //
  903. if (MajorFunction == IRP_MJ_CREATE)
  904. {
  905. pIrp->Flags = IRP_CREATE_OPERATION;
  906. }
  907. else
  908. {
  909. pIrp->Flags = IRP_CLOSE_OPERATION;
  910. }
  911. pIrp->AssociatedIrp.SystemBuffer = NULL;
  912. pIrp->UserBuffer = NULL;
  913. //
  914. // Finally, set the address of the I/O status block and the address of
  915. // the kernel event object. Note that I/O completion will not attempt
  916. // to dereference the event since there is no file object associated
  917. // with this operation.
  918. //
  919. pIrp->UserIosb = pIosb;
  920. pIrp->UserEvent = pEvent;
  921. IoSetCompletionRoutine(pIrp,
  922. SyncOpenCloseCompletion,
  923. NULL,
  924. TRUE,
  925. TRUE,
  926. TRUE);
  927. //
  928. // Simply return a pointer to the packet.
  929. //
  930. return pIrp;
  931. }
  932. /*****************************************************************************
  933. *
  934. * Function: SerialOpen
  935. *
  936. * Synopsis: open up the serial port
  937. *
  938. * Arguments: pThisDev - ir device object
  939. *
  940. * Returns: NDIS_STATUS_SUCCESS
  941. * NDIS_STATUS_OPEN_FAILED - serial port can't be opened
  942. * NDIS_STATUS_NOT_ACCEPTED - serial.sys does not accept the
  943. * configuration
  944. * NDIS_STATUS_FAILURE
  945. * NDIS_STATUS_RESOURCES - irp not allocated
  946. *
  947. * Algorithm:
  948. *
  949. * History: dd-mm-yyyy Author Comment
  950. * 10/3/1996 sholden author
  951. *
  952. * Notes:
  953. *
  954. * Converting from NTSTATUS to NDIS_STATUS is relatively pain free, since the
  955. * important codes remain the same.
  956. * NDIS_STATUS_PENDING = STATUS_PENDING
  957. * NDIS_STATUS_SUCCESS = STATUS_SUCCESS
  958. * NDIS_STATUS_FAILURE = STATUS_UNSUCCESSFUL
  959. * NDIS_STATUS_RESOURCES = STATUS_INSUFFICIENT_RESOURCES
  960. *
  961. * IoGetDeviceObjectPointer could return an error code which is
  962. * NOT mapped by an NDIS_STATUS code
  963. * STATUS_OBJECT_TYPE_MISMATCH
  964. * STATUS_INVALID_PARAMETER
  965. * STATUS_PRIVILEGE_NOT_HELD
  966. * STATUS_OBJECT_NAME_INVALID
  967. * These will be mapped to NDIS_STATUS_NOT_ACCEPTED.
  968. *
  969. * If IoCallDriver fails, NDIS_STATUS_OPEN_FAILED will be returned.
  970. *
  971. *****************************************************************************/
  972. NDIS_STATUS
  973. SerialOpen(
  974. IN PIR_DEVICE pThisDev
  975. )
  976. {
  977. PIRP pIrp;
  978. NTSTATUS status = NDIS_STATUS_SUCCESS;
  979. KEVENT eventComplete;
  980. IO_STATUS_BLOCK ioStatusBlock;
  981. PAGED_CODE();
  982. DEBUGMSG(DBG_FUNC|DBG_PNP, ("+SerialOpen\n"));
  983. if (!pThisDev->SerialBased)
  984. {
  985. PDEVICE_OBJECT PhysicalDeviceObject;
  986. PDEVICE_OBJECT FunctionalDeviceObject;
  987. PDEVICE_OBJECT NextDeviceObject;
  988. PCM_RESOURCE_LIST AllocatedResources;
  989. PCM_RESOURCE_LIST AllocatedResourcesTranslated;
  990. NdisMGetDeviceProperty(pThisDev->hNdisAdapter,
  991. &PhysicalDeviceObject,
  992. &FunctionalDeviceObject,
  993. &NextDeviceObject,
  994. &AllocatedResources,
  995. &AllocatedResourcesTranslated);
  996. pThisDev->pSerialDevObj = NextDeviceObject;
  997. DEBUGMSG(DBG_OUT|DBG_PNP, ("IRSIR: NdisMGetDeviceProperty returns:\n"));
  998. DBG_X(DBG_OUT|DBG_PNP, PhysicalDeviceObject);
  999. DBG_X(DBG_OUT|DBG_PNP, FunctionalDeviceObject);
  1000. DBG_X(DBG_OUT|DBG_PNP, NextDeviceObject);
  1001. DBG_X(DBG_OUT|DBG_PNP, AllocatedResources);
  1002. DBG_X(DBG_OUT|DBG_PNP, AllocatedResourcesTranslated);
  1003. //
  1004. // Event to wait for completion of serial driver.
  1005. //
  1006. KeInitializeEvent(
  1007. &eventComplete,
  1008. NotificationEvent,
  1009. FALSE
  1010. );
  1011. //
  1012. // Build an irp to send to the serial driver with IRP_MJ_CREATE.
  1013. //
  1014. //
  1015. // Irp is released by io manager.
  1016. //
  1017. pIrp = BuildSynchronousCreateCloseRequest(
  1018. pThisDev->pSerialDevObj,
  1019. IRP_MJ_CREATE,
  1020. &eventComplete,
  1021. &ioStatusBlock
  1022. );
  1023. DEBUGMSG(DBG_OUT, (" BuildSynchronousCreateCloseReqest\n"));
  1024. if (pIrp == NULL)
  1025. {
  1026. status = STATUS_INSUFFICIENT_RESOURCES;
  1027. DEBUGMSG(DBG_OUT, (" IoAllocateIrp() failed.\n"));
  1028. goto error10;
  1029. }
  1030. status = IoCallDriver(pThisDev->pSerialDevObj, pIrp);
  1031. //
  1032. // If IoCallDriver returns STATUS_PENDING, we need to wait for the event.
  1033. //
  1034. if (status == STATUS_PENDING)
  1035. {
  1036. DEBUGMSG(DBG_OUT, (" IoCallDriver(MJ_CREATE) PENDING.\n"));
  1037. KeWaitForSingleObject(
  1038. &eventComplete, // object to wait for
  1039. Executive, // reason to wait
  1040. KernelMode, // processor mode
  1041. FALSE, // alertable
  1042. NULL // timeout
  1043. );
  1044. //
  1045. // We can get the status of the IoCallDriver from the io status
  1046. // block.
  1047. //
  1048. status = ioStatusBlock.Status;
  1049. }
  1050. //
  1051. // If IoCallDriver returns something other that STATUS_PENDING, then it
  1052. // is the same as what the serial driver set in ioStatusBlock.Status.
  1053. //
  1054. if (status != STATUS_SUCCESS)
  1055. {
  1056. DEBUGMSG(DBG_OUT, (" IoCallDriver(MJ_CREATE) failed. Returned = 0x%.8x\n", status));
  1057. status = (NTSTATUS)NDIS_STATUS_OPEN_FAILED;
  1058. goto error10;
  1059. }
  1060. }
  1061. else
  1062. {
  1063. OBJECT_ATTRIBUTES ObjectAttributes;
  1064. IO_STATUS_BLOCK IoStatusBlock;
  1065. UNICODE_STRING DosFileName;
  1066. WCHAR DosFileNameBuffer[32];
  1067. DosFileName.Length = 0;
  1068. DosFileName.MaximumLength = sizeof(DosFileNameBuffer);
  1069. DosFileName.Buffer = DosFileNameBuffer;
  1070. RtlAppendUnicodeToString(&DosFileName, L"\\DosDevices\\");
  1071. RtlAppendUnicodeStringToString(&DosFileName, &pThisDev->serialDosName);
  1072. InitializeObjectAttributes(
  1073. &ObjectAttributes,
  1074. &DosFileName,
  1075. OBJ_CASE_INSENSITIVE,
  1076. NULL,
  1077. NULL
  1078. );
  1079. NdisZeroMemory(&IoStatusBlock, sizeof(IO_STATUS_BLOCK));
  1080. // We use NtOpenFile in the non-pnp case because it is much easier
  1081. // than trying to map COM1 to \device\serial0. It requires some
  1082. // extra work, because we really need to extract the device object.
  1083. status = ZwOpenFile(&pThisDev->serialHandle,
  1084. FILE_ALL_ACCESS,
  1085. &ObjectAttributes,
  1086. &IoStatusBlock,
  1087. 0,
  1088. 0);
  1089. if (!NT_SUCCESS(status))
  1090. {
  1091. DEBUGMSG(DBG_ERR, (" NtOpenFile() failed. Returned = 0x%.8x\n", status));
  1092. status = (NTSTATUS)NDIS_STATUS_NOT_ACCEPTED;
  1093. goto error10;
  1094. }
  1095. //
  1096. // Get the device object handle to the serial device object.
  1097. //
  1098. status = ObReferenceObjectByHandle(pThisDev->serialHandle,
  1099. FILE_ALL_ACCESS,
  1100. NULL,
  1101. KernelMode,
  1102. &pThisDev->pSerialFileObj,
  1103. NULL);
  1104. if (status != STATUS_SUCCESS)
  1105. {
  1106. DEBUGMSG(DBG_ERR, (" ObReferenceObjectByHandle() failed. Returned = 0x%.8x\n", status));
  1107. status = (NTSTATUS)NDIS_STATUS_NOT_ACCEPTED;
  1108. goto error10;
  1109. }
  1110. //
  1111. // see if we are connected to a com port exposed by a modem.
  1112. // if so fail
  1113. //
  1114. status=CheckForModemPort(pThisDev->pSerialFileObj);
  1115. if (!NT_SUCCESS(status)) {
  1116. DEBUGMSG(DBG_ERR, (" CheckForModemPort() failed. Returned = 0x%.8x\n", status));
  1117. status = (NTSTATUS)NDIS_STATUS_NOT_ACCEPTED;
  1118. goto error10;
  1119. }
  1120. pThisDev->pSerialDevObj = IoGetRelatedDeviceObject(pThisDev->pSerialFileObj);
  1121. status = ObReferenceObjectByPointer(pThisDev->pSerialDevObj,
  1122. FILE_ALL_ACCESS,
  1123. NULL,
  1124. KernelMode);
  1125. if (status != STATUS_SUCCESS)
  1126. {
  1127. DEBUGMSG(DBG_ERR, (" ObReferenceObjectByPointer() failed. Returned = 0x%.8x\n", status));
  1128. status = (NTSTATUS)NDIS_STATUS_NOT_ACCEPTED;
  1129. goto error10;
  1130. }
  1131. }
  1132. goto done;
  1133. error10:
  1134. if (pThisDev->pSerialDevObj)
  1135. {
  1136. if (pThisDev->SerialBased)
  1137. {
  1138. ObDereferenceObject(pThisDev->pSerialDevObj);
  1139. }
  1140. pThisDev->pSerialDevObj = NULL;
  1141. }
  1142. if (pThisDev->pSerialFileObj)
  1143. {
  1144. ObDereferenceObject(pThisDev->pSerialFileObj);
  1145. pThisDev->pSerialFileObj = NULL;
  1146. }
  1147. if (pThisDev->serialHandle)
  1148. {
  1149. NtClose(pThisDev->serialHandle);
  1150. pThisDev->serialHandle = 0;
  1151. }
  1152. done:
  1153. DEBUGMSG(DBG_FUNC|DBG_PNP, ("-SerialOpen\n"));
  1154. return((NDIS_STATUS)status);
  1155. }
  1156. /*****************************************************************************
  1157. *
  1158. * Function: SerialClose
  1159. *
  1160. * Synopsis: close the serial port
  1161. *
  1162. * Arguments:
  1163. *
  1164. * Returns:
  1165. *
  1166. * Algorithm:
  1167. *
  1168. * History: dd-mm-yyyy Author Comment
  1169. * 10/8/1996 sholden author
  1170. *
  1171. * Notes:
  1172. *
  1173. *
  1174. *****************************************************************************/
  1175. NDIS_STATUS
  1176. SerialClose(
  1177. PIR_DEVICE pThisDev
  1178. )
  1179. {
  1180. PIRP pIrp;
  1181. KEVENT eventComplete;
  1182. IO_STATUS_BLOCK ioStatusBlock;
  1183. NDIS_STATUS status;
  1184. PAGED_CODE();
  1185. if (!pThisDev->pSerialDevObj)
  1186. {
  1187. DEBUGMSG(DBG_ERROR, ("IRSIR: SerialDevObj==NULL\n"));
  1188. return NDIS_STATUS_SUCCESS;
  1189. }
  1190. DEBUGMSG(DBG_FUNC, ("+SerialClose\n"));
  1191. status = NDIS_STATUS_SUCCESS;
  1192. if (!pThisDev->SerialBased)
  1193. {
  1194. //
  1195. // Event to wait for completion of serial driver.
  1196. //
  1197. KeInitializeEvent(
  1198. &eventComplete,
  1199. NotificationEvent,
  1200. FALSE
  1201. );
  1202. //
  1203. // Send an irp to close the serial device object.
  1204. //
  1205. //
  1206. // Irp is released by io manager.
  1207. //
  1208. pIrp = BuildSynchronousCreateCloseRequest(
  1209. pThisDev->pSerialDevObj,
  1210. IRP_MJ_CLOSE,
  1211. &eventComplete,
  1212. &ioStatusBlock
  1213. );
  1214. if (pIrp == NULL)
  1215. {
  1216. status = STATUS_INSUFFICIENT_RESOURCES;
  1217. DEBUGMSG(DBG_OUT, (" IoAllocateIrp failed.\n"));
  1218. goto done;
  1219. }
  1220. status = IoCallDriver(pThisDev->pSerialDevObj, pIrp);
  1221. //
  1222. // If IoCallDriver returns STATUS_PENDING, we need to wait for the event.
  1223. //
  1224. if (status == STATUS_PENDING)
  1225. {
  1226. DEBUGMSG(DBG_OUT, (" IoCallDriver(MJ_CLOSE) PENDING.\n"));
  1227. KeWaitForSingleObject(
  1228. &eventComplete, // object to wait for
  1229. Executive, // reason to wait
  1230. KernelMode, // processor mode
  1231. FALSE, // alertable
  1232. NULL // timeout
  1233. );
  1234. //
  1235. // We can get the status of the IoCallDriver from the io status
  1236. // block.
  1237. //
  1238. status = ioStatusBlock.Status;
  1239. }
  1240. //
  1241. // If IoCallDriver returns something other that STATUS_PENDING, then it
  1242. // is the same as what the serial driver set in ioStatusBlock.Status.
  1243. //
  1244. if (status != STATUS_SUCCESS)
  1245. {
  1246. DEBUGMSG(DBG_OUT, (" IoCallDriver(MJ_CLOSE) failed. Returned = 0x%.8x\n", status));
  1247. status = (NTSTATUS)NDIS_STATUS_OPEN_FAILED;
  1248. goto done;
  1249. }
  1250. }
  1251. done:
  1252. if (pThisDev->SerialBased)
  1253. {
  1254. if (pThisDev->pSerialDevObj)
  1255. {
  1256. //
  1257. // Derefence the serial device object.
  1258. //
  1259. ObDereferenceObject(pThisDev->pSerialDevObj);
  1260. pThisDev->pSerialDevObj = NULL;
  1261. }
  1262. if (pThisDev->pSerialFileObj)
  1263. {
  1264. ObDereferenceObject(pThisDev->pSerialFileObj);
  1265. pThisDev->pSerialFileObj = NULL;
  1266. }
  1267. if (pThisDev->serialHandle)
  1268. {
  1269. NtClose(pThisDev->serialHandle);
  1270. pThisDev->serialHandle = 0;
  1271. }
  1272. }
  1273. DEBUGMSG(DBG_FUNC|DBG_PNP, ("-SerialClose\n"));
  1274. return status;
  1275. }
  1276. NTSTATUS
  1277. CheckForModemPort(
  1278. PFILE_OBJECT FileObject
  1279. )
  1280. {
  1281. PIRP TempIrp;
  1282. KEVENT Event;
  1283. IO_STATUS_BLOCK IoStatus;
  1284. NTSTATUS status;
  1285. PDEVICE_OBJECT DeviceObject;
  1286. DeviceObject=IoGetRelatedDeviceObject(FileObject);
  1287. KeInitializeEvent(
  1288. &Event,
  1289. NotificationEvent,
  1290. FALSE
  1291. );
  1292. //
  1293. // build an IRP to send to the attched to driver to see if modem
  1294. // is in the stack.
  1295. //
  1296. TempIrp=IoBuildDeviceIoControlRequest(
  1297. IOCTL_MODEM_CHECK_FOR_MODEM,
  1298. DeviceObject,
  1299. NULL,
  1300. 0,
  1301. NULL,
  1302. 0,
  1303. FALSE,
  1304. &Event,
  1305. &IoStatus
  1306. );
  1307. if (TempIrp == NULL) {
  1308. status = STATUS_INSUFFICIENT_RESOURCES;
  1309. } else {
  1310. PIO_STACK_LOCATION NextSp = IoGetNextIrpStackLocation(TempIrp);
  1311. NextSp->FileObject=FileObject;
  1312. status = IoCallDriver(DeviceObject, TempIrp);
  1313. if (status == STATUS_PENDING) {
  1314. KeWaitForSingleObject(
  1315. &Event,
  1316. Executive,
  1317. KernelMode,
  1318. FALSE,
  1319. NULL
  1320. );
  1321. status=IoStatus.Status;
  1322. }
  1323. TempIrp=NULL;
  1324. if (status == STATUS_SUCCESS) {
  1325. //
  1326. // if success, then modem.sys is layered under us, fail
  1327. //
  1328. status = STATUS_PORT_DISCONNECTED;
  1329. } else {
  1330. //
  1331. // it didn't succeed so modem must not be below us
  1332. //
  1333. status=STATUS_SUCCESS;
  1334. }
  1335. }
  1336. return status;
  1337. }