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.

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