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.

904 lines
25 KiB

  1. /*--------------------------------------------------------------------------
  2. *
  3. * Copyright (C) Cyclades Corporation, 1997-2001.
  4. * All rights reserved.
  5. *
  6. * Cyclades-Z Port Driver
  7. *
  8. * This file: cyzopcl.c
  9. *
  10. * Description: This module contains the code related to opening,
  11. * closing and cleaning up in the Cyclades-Z Port driver.
  12. *
  13. * Notes: This code supports Windows 2000 and Windows XP,
  14. * x86 and IA64 processors.
  15. *
  16. * Complies with Cyclades SW Coding Standard rev 1.3.
  17. *
  18. *--------------------------------------------------------------------------
  19. */
  20. /*-------------------------------------------------------------------------
  21. *
  22. * Change History
  23. *
  24. *--------------------------------------------------------------------------
  25. *
  26. *
  27. *--------------------------------------------------------------------------
  28. */
  29. #include "precomp.h"
  30. BOOLEAN
  31. CyzMarkOpen(
  32. IN PVOID Context
  33. );
  34. BOOLEAN
  35. CyzNullSynch(
  36. IN PVOID Context
  37. );
  38. #ifdef ALLOC_PRAGMA
  39. #pragma alloc_text(PAGESER,CyzGetCharTime)
  40. #pragma alloc_text(PAGESER,CyzMarkClose)
  41. #pragma alloc_text(PAGESER,CyzCleanup)
  42. #pragma alloc_text(PAGESER,CyzClose)
  43. #pragma alloc_text(PAGESER,CyzMarkClose)
  44. #pragma alloc_text(PAGESER,CyzMarkOpen)
  45. #pragma alloc_text(PAGESER,CyzCreateOpen)
  46. //
  47. // Always paged
  48. //
  49. //#pragma alloc_text(PAGESRP0,CyzCreateOpen) Moved to PAGESER, because of raised IRQL during spin lock.
  50. //#pragma alloc_text(PAGESRP0,SerialDrainUART)
  51. #endif // ALLOC_PRAGMA
  52. BOOLEAN
  53. CyzNullSynch(
  54. IN PVOID Context
  55. )
  56. /*------------------------------------------------------------------------
  57. Just a bogus little routine to synch with the ISR.
  58. ------------------------------------------------------------------------*/
  59. {
  60. UNREFERENCED_PARAMETER(Context);
  61. return FALSE;
  62. }
  63. NTSTATUS
  64. CyzCreateOpen(
  65. IN PDEVICE_OBJECT DeviceObject,
  66. IN PIRP Irp
  67. )
  68. /*--------------------------------------------------------------------------
  69. CyzCreateOpen()
  70. Description: We connect up to the interrupt for the create/open
  71. and initialize the structures needed to maintain an open for a
  72. device.
  73. Arguments:
  74. DeviceObject - Pointer to the device object for this device
  75. Irp - Pointer to the IRP for the current request
  76. Return Value: The function value is the final status of the call
  77. --------------------------------------------------------------------------*/
  78. {
  79. PCYZ_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
  80. NTSTATUS localStatus;
  81. #ifdef POLL
  82. KIRQL pollIrql;
  83. KIRQL pollingIrql;
  84. PCYZ_DISPATCH pDispatch = extension->OurIsrContext;
  85. #endif
  86. PAGED_CODE();
  87. if (extension->PNPState != CYZ_PNP_STARTED) {
  88. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  89. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  90. return STATUS_INSUFFICIENT_RESOURCES;
  91. }
  92. //
  93. // Lock out changes to PnP state until we have our open state decided
  94. //
  95. ExAcquireFastMutex(&extension->OpenMutex);
  96. if ((localStatus = CyzIRPPrologue(Irp, extension)) != STATUS_SUCCESS) {
  97. ExReleaseFastMutex(&extension->OpenMutex);
  98. if(localStatus != STATUS_PENDING) {
  99. CyzCompleteRequest(extension, Irp, IO_NO_INCREMENT);
  100. }
  101. return localStatus;
  102. }
  103. if (InterlockedIncrement(&extension->OpenCount) != 1) {
  104. ExReleaseFastMutex(&extension->OpenMutex);
  105. InterlockedDecrement(&extension->OpenCount);
  106. Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
  107. CyzCompleteRequest(extension, Irp, IO_NO_INCREMENT);
  108. return STATUS_ACCESS_DENIED;
  109. }
  110. CyzDbgPrintEx(CYZIRPPATH, "Dispatch entry for: %x\n", Irp);
  111. CyzDbgPrintEx(CYZDIAG3, "In CyzCreateOpen\n");
  112. LOGENTRY(LOG_MISC, ZSIG_OPEN,
  113. extension->PortIndex+1,
  114. 0,
  115. 0);
  116. // Before we do anything, let's make sure they aren't trying
  117. // to create a directory. This is a silly, but what's a driver to do!?
  118. if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Create.Options &
  119. FILE_DIRECTORY_FILE) {
  120. ExReleaseFastMutex(&extension->OpenMutex);
  121. Irp->IoStatus.Status = STATUS_NOT_A_DIRECTORY;
  122. Irp->IoStatus.Information = 0;
  123. InterlockedDecrement(&extension->OpenCount);
  124. CyzCompleteRequest(extension, Irp, IO_NO_INCREMENT);
  125. return STATUS_NOT_A_DIRECTORY;
  126. }
  127. // Create a buffer for the RX data when no reads are outstanding.
  128. extension->InterruptReadBuffer = NULL;
  129. extension->BufferSize = 0;
  130. switch (MmQuerySystemSize()) {
  131. case MmLargeSystem: {
  132. extension->BufferSize = 4096;
  133. extension->InterruptReadBuffer = ExAllocatePool(
  134. NonPagedPool,
  135. extension->BufferSize);
  136. if (extension->InterruptReadBuffer) {
  137. break;
  138. }
  139. }
  140. case MmMediumSystem: {
  141. extension->BufferSize = 1024;
  142. extension->InterruptReadBuffer = ExAllocatePool(
  143. NonPagedPool,
  144. extension->BufferSize);
  145. if (extension->InterruptReadBuffer) {
  146. break;
  147. }
  148. }
  149. case MmSmallSystem: {
  150. extension->BufferSize = 128;
  151. extension->InterruptReadBuffer = ExAllocatePool(
  152. NonPagedPool,
  153. extension->BufferSize);
  154. }
  155. }
  156. if (!extension->InterruptReadBuffer) {
  157. ExReleaseFastMutex(&extension->OpenMutex);
  158. extension->BufferSize = 0;
  159. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  160. Irp->IoStatus.Information = 0;
  161. InterlockedDecrement(&extension->OpenCount);
  162. CyzCompleteRequest(extension, Irp, IO_NO_INCREMENT);
  163. return STATUS_INSUFFICIENT_RESOURCES;
  164. }
  165. //
  166. // Ok, it looks like we really are going to open. Lock down the
  167. // driver.
  168. //
  169. CyzLockPagableSectionByHandle(CyzGlobals.PAGESER_Handle);
  170. //
  171. // Power up the stack
  172. //
  173. (void)CyzGotoPowerState(DeviceObject, extension, PowerDeviceD0);
  174. //
  175. // Not currently waiting for wake up
  176. //
  177. extension->SendWaitWake = FALSE;
  178. // "flush" the read queue by initializing the count of characters.
  179. extension->CharsInInterruptBuffer = 0;
  180. extension->LastCharSlot = extension->InterruptReadBuffer +
  181. (extension->BufferSize - 1);
  182. extension->ReadBufferBase = extension->InterruptReadBuffer;
  183. extension->CurrentCharSlot = extension->InterruptReadBuffer;
  184. extension->FirstReadableChar = extension->InterruptReadBuffer;
  185. extension->TotalCharsQueued = 0;
  186. // set up the default xon/xoff limits.
  187. extension->HandFlow.XoffLimit = extension->BufferSize >> 3;
  188. extension->HandFlow.XonLimit = extension->BufferSize >> 1;
  189. extension->WmiCommData.XoffXmitThreshold = extension->HandFlow.XoffLimit;
  190. extension->WmiCommData.XonXmitThreshold = extension->HandFlow.XonLimit;
  191. extension->BufferSizePt8 = ((3*(extension->BufferSize>>2))+
  192. (extension->BufferSize>>4));
  193. //
  194. // Mark the device as busy for WMI
  195. //
  196. extension->WmiCommData.IsBusy = TRUE;
  197. extension->IrpMaskLocation = NULL;
  198. extension->HistoryMask = 0;
  199. extension->IsrWaitMask = 0;
  200. #if !DBG
  201. // Clear out the statistics.
  202. #ifdef POLL
  203. KeAcquireSpinLock(&extension->PollLock,&pollIrql);
  204. CyzClearStats(extension);
  205. KeReleaseSpinLock(&extension->PollLock,pollIrql);
  206. #else
  207. KeSynchronizeExecution(extension->Interrupt,CyzClearStats,extension);
  208. #endif
  209. #endif
  210. extension->EscapeChar = 0;
  211. // Synchronize with the ISR and mark the device as open
  212. #ifdef POLL
  213. KeAcquireSpinLock(&extension->PollLock,&pollIrql);
  214. CyzMarkOpen(extension);
  215. KeReleaseSpinLock(&extension->PollLock,pollIrql);
  216. #else
  217. KeSynchronizeExecution(extension->Interrupt,CyzMarkOpen,extension);
  218. #endif
  219. // Include this port in the list of Extensions, so that the next polling cycle will
  220. // consider it a working port.
  221. #ifdef POLL
  222. KeAcquireSpinLock(&pDispatch->PollingLock,&pollingIrql);
  223. pDispatch->Extensions[extension->PortIndex] = extension;
  224. if (!pDispatch->PollingStarted) {
  225. // Start polling timer
  226. KeSetTimerEx(
  227. &pDispatch->PollingTimer,
  228. pDispatch->PollingTime,
  229. pDispatch->PollingPeriod,
  230. &pDispatch->PollingDpc
  231. );
  232. pDispatch->PollingStarted = TRUE;
  233. pDispatch->PollingDrained = FALSE;
  234. }
  235. KeReleaseSpinLock(&pDispatch->PollingLock,pollingIrql);
  236. #endif
  237. Irp->IoStatus.Status = STATUS_SUCCESS;
  238. //
  239. // We have been marked open, so now the PnP state can change
  240. //
  241. ExReleaseFastMutex(&extension->OpenMutex);
  242. localStatus = Irp->IoStatus.Status;
  243. Irp->IoStatus.Information=0L;
  244. if (!NT_SUCCESS(localStatus)) {
  245. if (extension->InterruptReadBuffer != NULL) {
  246. ExFreePool(extension->InterruptReadBuffer);
  247. extension->InterruptReadBuffer = NULL;
  248. }
  249. InterlockedDecrement(&extension->OpenCount);
  250. }
  251. CyzCompleteRequest(extension, Irp, IO_NO_INCREMENT);
  252. return localStatus;
  253. }
  254. NTSTATUS
  255. CyzClose(
  256. IN PDEVICE_OBJECT DeviceObject,
  257. IN PIRP Irp
  258. )
  259. /*--------------------------------------------------------------------------
  260. CyzClose()
  261. Description: We simply disconnect the interrupt for now.
  262. Arguments:
  263. DeviceObject - Pointer to the device object for this device
  264. Irp - Pointer to the IRP for the current request
  265. Return Value: The function value is the final status of the call
  266. --------------------------------------------------------------------------*/
  267. {
  268. LARGE_INTEGER tenCharDelay;
  269. LARGE_INTEGER sixtyfourCharDelay;
  270. LARGE_INTEGER charTime;
  271. LARGE_INTEGER d200ms = RtlConvertLongToLargeInteger(-200*10000);
  272. LARGE_INTEGER d100ms = RtlConvertLongToLargeInteger(-100*10000);
  273. PCYZ_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
  274. ULONG tx_put, tx_get, tx_bufsize;
  275. ULONG waitAmount1, waitAmount2;
  276. struct BUF_CTRL *buf_ctrl;
  277. ULONG txempty;
  278. CYZ_CLOSE_SYNC S;
  279. #ifdef POLL
  280. KIRQL pollIrql;
  281. #endif
  282. NTSTATUS status;
  283. //
  284. // Number of opens still active
  285. //
  286. LONG openCount;
  287. //
  288. // Number of DPC's still pending
  289. //
  290. ULONG pendingDPCs;
  291. ULONG flushCount;
  292. //
  293. // Grab a mutex
  294. //
  295. ExAcquireFastMutex(&extension->CloseMutex);
  296. //
  297. // We succeed a close on a removing device
  298. //
  299. if ((status = CyzIRPPrologue(Irp, extension)) != STATUS_SUCCESS) {
  300. CyzDbgPrintEx(DPFLTR_INFO_LEVEL, "Close prologue failed for: %x\n",
  301. Irp);
  302. if (status == STATUS_DELETE_PENDING) {
  303. extension->BufferSize = 0;
  304. ExFreePool(extension->InterruptReadBuffer);
  305. extension->InterruptReadBuffer = NULL;
  306. status = Irp->IoStatus.Status = STATUS_SUCCESS;
  307. }
  308. if (status != STATUS_PENDING) {
  309. CyzCompleteRequest(extension, Irp, IO_NO_INCREMENT);
  310. openCount = InterlockedDecrement(&extension->OpenCount);
  311. ASSERT(openCount == 0);
  312. }
  313. ExReleaseFastMutex(&extension->CloseMutex);
  314. return status;
  315. }
  316. ASSERT(extension->OpenCount >= 1);
  317. if (extension->OpenCount < 1) {
  318. CyzDbgPrintEx(DPFLTR_ERROR_LEVEL, "Close open count bad for: 0x%x\n",
  319. Irp);
  320. CyzDbgPrintEx(DPFLTR_ERROR_LEVEL, "Count: %x Addr: 0x%x\n",
  321. extension->OpenCount, &extension->OpenCount);
  322. ExReleaseFastMutex(&extension->CloseMutex);
  323. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  324. CyzCompleteRequest(extension, Irp, IO_NO_INCREMENT);
  325. return STATUS_INVALID_DEVICE_REQUEST;
  326. }
  327. CyzDbgPrintEx(CYZIRPPATH, "Dispatch entry for: %x\n", Irp);
  328. CyzDbgPrintEx(CYZDIAG3, "In CyzClose\n");
  329. LOGENTRY(LOG_MISC, ZSIG_CLOSE,
  330. extension->PortIndex+1,
  331. 0,
  332. 0);
  333. charTime.QuadPart = -CyzGetCharTime(extension).QuadPart;
  334. extension->DeviceIsOpened = FALSE;
  335. // Turn break off in case it is on
  336. #ifdef POLL
  337. KeAcquireSpinLock(&extension->PollLock,&pollIrql);
  338. CyzTurnOffBreak(extension);
  339. KeReleaseSpinLock(&extension->PollLock,pollIrql);
  340. #else
  341. KeSynchronizeExecution(extension->Interrupt,CyzTurnOffBreak,extension);
  342. #endif
  343. // Wait until all characters have been emptied out of the hardware.
  344. // Calculate number of bytes that are still in the firmware
  345. buf_ctrl = extension->BufCtrl;
  346. tx_put = CYZ_READ_ULONG(&buf_ctrl->tx_put);
  347. tx_get = CYZ_READ_ULONG(&buf_ctrl->tx_get);
  348. tx_bufsize = extension->TxBufsize;
  349. if (tx_put >= tx_get) {
  350. waitAmount1 = tx_put - tx_get;
  351. waitAmount2 = 0;
  352. } else {
  353. waitAmount1 = tx_bufsize - tx_get;
  354. waitAmount2 = tx_put;
  355. }
  356. flushCount = waitAmount1 + waitAmount2;
  357. flushCount += 64 + 10; // Add number of bytes that could be in the hardware FIFO
  358. // plus 10 for safety.
  359. // Wait for transmission to be emptied.
  360. S.Extension = extension;
  361. S.Data = &txempty;
  362. for (; flushCount != 0; flushCount--) {
  363. #ifdef POLL
  364. KeAcquireSpinLock(&extension->PollLock,&pollIrql);
  365. CyzCheckIfTxEmpty(&S);
  366. KeReleaseSpinLock(&extension->PollLock,pollIrql);
  367. #else
  368. KeSynchronizeExecution(extension->Interrupt,CyzCheckIfTxEmpty,&S);
  369. #endif
  370. if (txempty) {
  371. break;
  372. }
  373. KeDelayExecutionThread(KernelMode,FALSE,&charTime);
  374. }
  375. // TODO FANNY: SHOULD WE CALL SerialMarkHardwareBroken()? SEE LATER...
  376. // Synchronize with the ISR to let it know that interrupts are
  377. // no longer important.
  378. #ifdef POLL
  379. KeAcquireSpinLock(&extension->PollLock,&pollIrql);
  380. CyzMarkClose(extension);
  381. KeReleaseSpinLock(&extension->PollLock,pollIrql);
  382. #else
  383. KeSynchronizeExecution(extension->Interrupt,CyzMarkClose,extension);
  384. #endif
  385. // If the driver has automatically transmitted an Xoff in
  386. // the context of automatic receive flow control then we
  387. // should transmit an Xon.
  388. if (extension->RXHolding & CYZ_RX_XOFF) {
  389. CyzIssueCmd(extension,C_CM_SENDXON,0L,FALSE);
  390. //TODO FANNY: SHOULD WE CALL SerialMarkHardwareBroken()? SEE LATER...
  391. }
  392. // The hardware is hopefully empty. Delay 10 chars before dropping DTR.
  393. tenCharDelay.QuadPart = charTime.QuadPart * 10;
  394. KeDelayExecutionThread(KernelMode,TRUE,&tenCharDelay);
  395. #ifdef POLL
  396. CyzClrDTR(extension);
  397. #else
  398. KeSynchronizeExecution(extension->Interrupt,CyzClrDTR,extension);
  399. #endif
  400. // We have to be very careful how we clear the RTS line.
  401. // Transmit toggling might have been on at some point.
  402. //
  403. // We know that there is nothing left that could start
  404. // out the "polling" execution path. We need to
  405. // check the counter that indicates that the execution
  406. // path is active. If it is then we loop delaying one
  407. // character time. After each delay we check to see if
  408. // the counter has gone to zero. When it has we know that
  409. // the execution path should be just about finished. We
  410. // make sure that we still aren't in the routine that
  411. // synchronized execution with the ISR by synchronizing
  412. // ourselve with the ISR.
  413. if (extension->CountOfTryingToLowerRTS) {
  414. do {
  415. KeDelayExecutionThread(KernelMode,FALSE,&charTime);
  416. } while (extension->CountOfTryingToLowerRTS);
  417. #ifdef POLL
  418. KeAcquireSpinLock(&extension->PollLock,&pollIrql);
  419. CyzNullSynch(NULL);
  420. KeReleaseSpinLock(&extension->PollLock,pollIrql);
  421. #else
  422. KeSynchronizeExecution(extension->Interrupt,CyzNullSynch,NULL);
  423. #endif
  424. }
  425. #ifdef POLL
  426. KeAcquireSpinLock(&extension->PollLock,&pollIrql);
  427. CyzClrRTS(extension);
  428. KeReleaseSpinLock(&extension->PollLock,pollIrql);
  429. #else
  430. KeSynchronizeExecution(extension->Interrupt,CyzClrRTS,extension);
  431. #endif
  432. #ifdef POLL
  433. KeAcquireSpinLock(&extension->PollLock,&pollIrql);
  434. CyzDisableHw(extension);
  435. KeReleaseSpinLock(&extension->PollLock,pollIrql);
  436. CyzTryToDisableTimer(extension);
  437. #else
  438. KeSynchronizeExecution(extension->Interrupt,CyzDisableHw,extension);
  439. #endif
  440. // Clean out the holding reasons (since we are closed).
  441. extension->RXHolding = 0;
  442. extension->TXHolding = 0;
  443. //
  444. // Mark device as not busy for WMI
  445. //
  446. extension->WmiCommData.IsBusy = FALSE;
  447. // Release the buffers.
  448. extension->BufferSize = 0;
  449. if (extension->InterruptReadBuffer != NULL) { // added in DDK build 2072
  450. ExFreePool(extension->InterruptReadBuffer);
  451. }
  452. extension->InterruptReadBuffer = NULL;
  453. //
  454. // Stop waiting for wakeup
  455. //
  456. extension->SendWaitWake = FALSE;
  457. if (extension->PendingWakeIrp != NULL) {
  458. IoCancelIrp(extension->PendingWakeIrp);
  459. }
  460. //
  461. // Power down our device stack
  462. //
  463. (void)CyzGotoPowerState(DeviceObject, extension, PowerDeviceD3);
  464. Irp->IoStatus.Status = STATUS_SUCCESS;
  465. Irp->IoStatus.Information=0L;
  466. CyzCompleteRequest(extension, Irp, IO_NO_INCREMENT);
  467. //
  468. // Unlock the pages. If this is the last reference to the section
  469. // then the driver code will be flushed out.
  470. //
  471. //
  472. // First, we have to let the DPC's drain. No more should be queued
  473. // since we aren't taking interrupts now....
  474. //
  475. pendingDPCs = InterlockedDecrement(&extension->DpcCount);
  476. LOGENTRY(LOG_CNT, 'DpD7', 0, extension->DpcCount, 0); // Added in build 2128
  477. if (pendingDPCs) {
  478. CyzDbgPrintEx(CYZDIAG1,"Draining DPC's: %x\n", Irp);
  479. KeWaitForSingleObject(&extension->PendingDpcEvent, Executive,
  480. KernelMode, FALSE, NULL);
  481. }
  482. CyzDbgPrintEx(CYZDIAG1, "DPC's drained: %x\n", Irp);
  483. //
  484. // Pages must be locked to release the mutex, so don't unlock
  485. // them until after we release the mutex
  486. //
  487. ExReleaseFastMutex(&extension->CloseMutex);
  488. //
  489. // Reset for next open
  490. //
  491. InterlockedIncrement(&extension->DpcCount);
  492. LOGENTRY(LOG_CNT, 'DpI6', 0, extension->DpcCount, 0); // Added in build 2128
  493. openCount = InterlockedDecrement(&extension->OpenCount);
  494. //
  495. // Open count may be non-zero if someone was trying to open
  496. // at the same time we decremented
  497. //
  498. // ASSERT(openCount == 0);
  499. CyzUnlockPagableImageSection(CyzGlobals.PAGESER_Handle);
  500. return STATUS_SUCCESS;
  501. }
  502. BOOLEAN
  503. CyzMarkOpen(
  504. IN PVOID Context
  505. )
  506. /*------------------------------------------------------------------------
  507. CyzMarkOpen()
  508. Routine Description: This routine mark the fact that somebody opened
  509. the device and its worthwhile to pay attention to interrupts.
  510. Arguments:
  511. Context - Really a pointer to the device extension.
  512. Return Value: This routine always returns FALSE.
  513. ------------------------------------------------------------------------*/
  514. {
  515. PCYZ_DEVICE_EXTENSION extension = Context;
  516. CyzReset(extension);
  517. extension->DeviceIsOpened = TRUE;
  518. extension->ErrorWord = 0;
  519. return FALSE;
  520. }
  521. BOOLEAN
  522. CyzDisableHw(IN PVOID Context)
  523. /*++
  524. Routine Description:
  525. This routine disables the UART and puts it in a "safe" state when
  526. not in use (like a close or powerdown).
  527. Arguments:
  528. Context - Really a pointer to the device extension.
  529. Return Value:
  530. This routine always returns FALSE.
  531. --*/
  532. {
  533. PCYZ_DEVICE_EXTENSION extension = Context;
  534. ULONG channel;
  535. struct CH_CTRL *ch_ctrl;
  536. ch_ctrl = extension->ChCtrl;
  537. CYZ_WRITE_ULONG(&ch_ctrl->op_mode,C_CH_DISABLE);
  538. CyzIssueCmd(extension,C_CM_IOCTL,0L,FALSE);
  539. CyzIssueCmd(extension,C_CM_RESET,0L,FALSE);
  540. return FALSE;
  541. }
  542. #ifdef POLL
  543. BOOLEAN
  544. CyzTryToDisableTimer(IN PVOID Context)
  545. /*++
  546. Routine Description:
  547. This routine disables the timer if all other ports in the board are already closed
  548. or powered down.
  549. Arguments:
  550. Context - Really a pointer to the device extension.
  551. Return Value:
  552. This routine always returns FALSE.
  553. --*/
  554. {
  555. PCYZ_DEVICE_EXTENSION extension = Context;
  556. ULONG channel;
  557. PCYZ_DISPATCH pDispatch;
  558. KIRQL oldIrql;
  559. pDispatch = extension->OurIsrContext;
  560. KeAcquireSpinLock(&pDispatch->PollingLock,&oldIrql);
  561. pDispatch->Extensions[extension->PortIndex] = NULL;
  562. for (channel=0; channel<pDispatch->NChannels; channel++) {
  563. if (pDispatch->Extensions[channel])
  564. break;
  565. }
  566. if (channel == pDispatch->NChannels) {
  567. BOOLEAN cancelled;
  568. pDispatch->PollingStarted = FALSE;
  569. cancelled = KeCancelTimer(&pDispatch->PollingTimer);
  570. if (cancelled) {
  571. pDispatch->PollingDrained = TRUE;
  572. }
  573. KeRemoveQueueDpc(&pDispatch->PollingDpc);
  574. }
  575. KeReleaseSpinLock(&pDispatch->PollingLock,oldIrql);
  576. return FALSE;
  577. }
  578. #endif
  579. BOOLEAN
  580. CyzMarkClose(
  581. IN PVOID Context
  582. )
  583. /*------------------------------------------------------------------------
  584. CyzMarkClose()
  585. Routine Description: This routine merely sets a boolean to false to
  586. mark the fact that somebody closed the device and it's no longer
  587. worthwhile to pay attention to interrupts.
  588. Arguments:
  589. Context - Really a pointer to the device extension.
  590. Return Value: This routine always returns FALSE.
  591. ------------------------------------------------------------------------*/
  592. {
  593. PCYZ_DEVICE_EXTENSION extension = Context;
  594. struct CH_CTRL *ch_ctrl;
  595. ch_ctrl = extension->ChCtrl;
  596. CYZ_WRITE_ULONG(&ch_ctrl->intr_enable,C_IN_DISABLE);
  597. CyzIssueCmd(extension,C_CM_IOCTL,0L,FALSE);
  598. extension->DeviceIsOpened = FALSE;
  599. return FALSE;
  600. }
  601. NTSTATUS
  602. CyzCleanup(
  603. IN PDEVICE_OBJECT DeviceObject,
  604. IN PIRP Irp
  605. )
  606. /*------------------------------------------------------------------------
  607. CyzCleanup()
  608. Routine Description: This function is used to kill all longstanding
  609. IO operations.
  610. Arguments:
  611. DeviceObject - Pointer to the device object for this device
  612. Irp - Pointer to the IRP for the current request
  613. Return Value: The function value is the final status of the call
  614. ------------------------------------------------------------------------*/
  615. {
  616. PCYZ_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
  617. NTSTATUS status;
  618. PAGED_CODE();
  619. //
  620. // We succeed a cleanup on a removing device
  621. //
  622. if ((status = CyzIRPPrologue(Irp, extension)) != STATUS_SUCCESS) {
  623. if (status == STATUS_DELETE_PENDING) {
  624. status = Irp->IoStatus.Status = STATUS_SUCCESS;
  625. }
  626. if (status != STATUS_PENDING) {
  627. CyzCompleteRequest(extension, Irp, IO_NO_INCREMENT);
  628. }
  629. return status;
  630. }
  631. CyzDbgPrintEx(CYZIRPPATH, "Dispatch entry for: %x\n", Irp);
  632. CyzKillPendingIrps(DeviceObject);
  633. Irp->IoStatus.Status = STATUS_SUCCESS;
  634. Irp->IoStatus.Information=0L;
  635. CyzCompleteRequest(extension, Irp, IO_NO_INCREMENT);
  636. return STATUS_SUCCESS;
  637. }
  638. LARGE_INTEGER
  639. CyzGetCharTime(
  640. IN PCYZ_DEVICE_EXTENSION Extension
  641. )
  642. /*------------------------------------------------------------------------
  643. CyzGetCharTime()
  644. Routine Description: return the number of 100 nanosecond intervals
  645. there are in one character time.
  646. Arguments:
  647. Extension - Just what it says.
  648. Return Value: 100 nanosecond intervals in a character time.
  649. ------------------------------------------------------------------------*/
  650. {
  651. ULONG dataSize;
  652. ULONG paritySize;
  653. ULONG stopSize;
  654. ULONG charTime;
  655. ULONG bitTime;
  656. LARGE_INTEGER tmp;
  657. if ((Extension->CommDataLen & C_DL_CS) == C_DL_CS5) {
  658. dataSize = 5;
  659. } else if ((Extension->CommDataLen & C_DL_CS) == C_DL_CS6) {
  660. dataSize = 6;
  661. } else if ((Extension->CommDataLen & C_DL_CS) == C_DL_CS7) {
  662. dataSize = 7;
  663. } else {
  664. dataSize = 8;
  665. }
  666. paritySize = 1;
  667. if ((Extension->CommParity & C_PR_PARITY) == C_PR_NONE) {
  668. paritySize = 0;
  669. }
  670. if ((Extension->CommDataLen & C_DL_STOP) == C_DL_1STOP) {
  671. stopSize = 1;
  672. } else {
  673. stopSize = 2;
  674. }
  675. //
  676. // First we calculate the number of 100 nanosecond intervals
  677. // are in a single bit time (Approximately).
  678. //
  679. bitTime = (10000000+(Extension->CurrentBaud-1))/Extension->CurrentBaud;
  680. charTime = bitTime + ((dataSize+paritySize+stopSize)*bitTime);
  681. tmp.QuadPart = charTime;
  682. return tmp;
  683. }
  684.