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.

1192 lines
28 KiB

  1. /*++
  2. Copyright (c) 1991, 1992, 1993 - 1997 Microsoft Corporation
  3. Module Name:
  4. openclos.c
  5. Abstract:
  6. This module contains the code that is very specific to
  7. opening, closing, and cleaning up in the serial driver.
  8. Author:
  9. Anthony V. Ercolano 26-Sep-1991
  10. Environment:
  11. Kernel mode
  12. --*/
  13. #include "precomp.h"
  14. BOOLEAN
  15. SerialMarkOpen(
  16. IN PVOID Context
  17. );
  18. BOOLEAN
  19. SerialCheckOpen(
  20. IN PVOID Context
  21. );
  22. BOOLEAN
  23. SerialNullSynch(
  24. IN PVOID Context
  25. );
  26. NTSTATUS
  27. SerialCreateOpen(
  28. IN PDEVICE_OBJECT DeviceObject,
  29. IN PIRP Irp
  30. );
  31. #ifdef ALLOC_PRAGMA
  32. //
  33. // Paged for open and PnP transactions
  34. //
  35. #pragma alloc_text(PAGESER,SerialGetCharTime)
  36. #pragma alloc_text(PAGESER,SerialCleanup)
  37. #pragma alloc_text(PAGESER,SerialClose)
  38. #pragma alloc_text(PAGESER, SerialCheckOpen)
  39. #pragma alloc_text(PAGESER, SerialMarkOpen)
  40. //
  41. // Always paged
  42. //
  43. #pragma alloc_text(PAGESRP0,SerialCreateOpen)
  44. #pragma alloc_text(PAGESRP0, SerialDrainUART)
  45. #endif // ALLOC_PRAGMA
  46. typedef struct _SERIAL_CHECK_OPEN {
  47. PSERIAL_DEVICE_EXTENSION Extension;
  48. NTSTATUS *StatusOfOpen;
  49. } SERIAL_CHECK_OPEN,*PSERIAL_CHECK_OPEN;
  50. //
  51. // Just a bogus little routine to make sure that we
  52. // can synch with the ISR.
  53. //
  54. BOOLEAN
  55. SerialNullSynch(
  56. IN PVOID Context
  57. ) {
  58. UNREFERENCED_PARAMETER(Context);
  59. return FALSE;
  60. }
  61. NTSTATUS
  62. SerialCreateOpen(
  63. IN PDEVICE_OBJECT DeviceObject,
  64. IN PIRP Irp
  65. )
  66. /*++
  67. Routine Description:
  68. We connect up to the interrupt for the create/open and initialize
  69. the structures needed to maintain an open for a device.
  70. Arguments:
  71. DeviceObject - Pointer to the device object for this device
  72. Irp - Pointer to the IRP for the current request
  73. Return Value:
  74. The function value is the final status of the call
  75. --*/
  76. {
  77. PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
  78. SERIAL_CHECK_OPEN checkOpen;
  79. NTSTATUS localStatus;
  80. PAGED_CODE();
  81. if (extension->PNPState != SERIAL_PNP_STARTED) {
  82. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  83. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  84. return STATUS_INSUFFICIENT_RESOURCES;
  85. }
  86. //
  87. // Lock out changes to PnP state until we have our open state decided
  88. //
  89. ExAcquireFastMutex(&extension->OpenMutex);
  90. if ((localStatus = SerialIRPPrologue(Irp, extension)) != STATUS_SUCCESS) {
  91. ExReleaseFastMutex(&extension->OpenMutex);
  92. SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
  93. return localStatus;
  94. }
  95. if (InterlockedIncrement(&extension->OpenCount) != 1) {
  96. ExReleaseFastMutex(&extension->OpenMutex);
  97. InterlockedDecrement(&extension->OpenCount);
  98. Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
  99. SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
  100. return STATUS_ACCESS_DENIED;
  101. }
  102. SerialDump(
  103. SERIRPPATH,
  104. ("SERIAL: Dispatch entry for: %x\n",Irp)
  105. );
  106. SerialDump(
  107. SERDIAG3,
  108. ("SERIAL: In SerialCreateOpen\n")
  109. );
  110. //
  111. // Before we do anything, let's make sure they aren't trying
  112. // to create a directory. what's a driver to do!?
  113. //
  114. if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Create.Options &
  115. FILE_DIRECTORY_FILE) {
  116. ExReleaseFastMutex(&extension->OpenMutex);
  117. Irp->IoStatus.Status = STATUS_NOT_A_DIRECTORY;
  118. Irp->IoStatus.Information = 0;
  119. SerialDump(
  120. SERIRPPATH,
  121. ("SERIAL: Complete Irp: %x\n",Irp)
  122. );
  123. InterlockedDecrement(&extension->OpenCount);
  124. SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
  125. return STATUS_NOT_A_DIRECTORY;
  126. }
  127. //
  128. // Create a buffer for the RX data when no reads are outstanding.
  129. //
  130. extension->InterruptReadBuffer = NULL;
  131. extension->BufferSize = 0;
  132. switch (MmQuerySystemSize()) {
  133. case MmLargeSystem: {
  134. extension->BufferSize = 4096;
  135. extension->InterruptReadBuffer = ExAllocatePool(
  136. NonPagedPool,
  137. extension->BufferSize
  138. );
  139. if (extension->InterruptReadBuffer) {
  140. break;
  141. }
  142. }
  143. case MmMediumSystem: {
  144. extension->BufferSize = 1024;
  145. extension->InterruptReadBuffer = ExAllocatePool(
  146. NonPagedPool,
  147. extension->BufferSize
  148. );
  149. if (extension->InterruptReadBuffer) {
  150. break;
  151. }
  152. }
  153. case MmSmallSystem: {
  154. extension->BufferSize = 128;
  155. extension->InterruptReadBuffer = ExAllocatePool(
  156. NonPagedPool,
  157. extension->BufferSize
  158. );
  159. }
  160. }
  161. if (!extension->InterruptReadBuffer) {
  162. ExReleaseFastMutex(&extension->OpenMutex);
  163. extension->BufferSize = 0;
  164. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  165. Irp->IoStatus.Information = 0;
  166. SerialDump(
  167. SERIRPPATH,
  168. ("SERIAL: Complete Irp: %x\n",Irp)
  169. );
  170. InterlockedDecrement(&extension->OpenCount);
  171. SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
  172. return STATUS_INSUFFICIENT_RESOURCES;
  173. }
  174. //
  175. // Ok, it looks like we really are going to open. Lock down the
  176. // driver.
  177. //
  178. SerialLockPagableSectionByHandle(SerialGlobals.PAGESER_Handle);
  179. //
  180. // Power up the stack
  181. //
  182. (void)SerialGotoPowerState(DeviceObject, extension, PowerDeviceD0);
  183. //
  184. // Not currently waiting for wake up
  185. //
  186. extension->SendWaitWake = FALSE;
  187. //
  188. // On a new open we "flush" the read queue by initializing the
  189. // count of characters.
  190. //
  191. extension->CharsInInterruptBuffer = 0;
  192. extension->LastCharSlot = extension->InterruptReadBuffer +
  193. (extension->BufferSize - 1);
  194. extension->ReadBufferBase = extension->InterruptReadBuffer;
  195. extension->CurrentCharSlot = extension->InterruptReadBuffer;
  196. extension->FirstReadableChar = extension->InterruptReadBuffer;
  197. extension->TotalCharsQueued = 0;
  198. //
  199. // We set up the default xon/xoff limits.
  200. //
  201. extension->HandFlow.XoffLimit = extension->BufferSize >> 3;
  202. extension->HandFlow.XonLimit = extension->BufferSize >> 1;
  203. extension->WmiCommData.XoffXmitThreshold = extension->HandFlow.XoffLimit;
  204. extension->WmiCommData.XonXmitThreshold = extension->HandFlow.XonLimit;
  205. extension->BufferSizePt8 = ((3*(extension->BufferSize>>2))+
  206. (extension->BufferSize>>4));
  207. //
  208. // Mark the device as busy for WMI
  209. //
  210. extension->WmiCommData.IsBusy = TRUE;
  211. extension->IrpMaskLocation = NULL;
  212. extension->HistoryMask = 0;
  213. extension->IsrWaitMask = 0;
  214. extension->SendXonChar = FALSE;
  215. extension->SendXoffChar = FALSE;
  216. #if !DBG
  217. //
  218. // Clear out the statistics.
  219. //
  220. KeSynchronizeExecution(
  221. extension->Interrupt,
  222. SerialClearStats,
  223. extension
  224. );
  225. #endif
  226. //
  227. // The escape char replacement must be reset upon every open.
  228. //
  229. extension->EscapeChar = 0;
  230. if (!extension->PermitShare) {
  231. if (!extension->InterruptShareable) {
  232. checkOpen.Extension = extension;
  233. checkOpen.StatusOfOpen = &Irp->IoStatus.Status;
  234. KeSynchronizeExecution(
  235. extension->Interrupt,
  236. SerialCheckOpen,
  237. &checkOpen
  238. );
  239. } else {
  240. KeSynchronizeExecution(
  241. extension->Interrupt,
  242. SerialMarkOpen,
  243. extension
  244. );
  245. Irp->IoStatus.Status = STATUS_SUCCESS;
  246. }
  247. } else {
  248. //
  249. // Synchronize with the ISR and let it know that the device
  250. // has been successfully opened.
  251. //
  252. KeSynchronizeExecution(
  253. extension->Interrupt,
  254. SerialMarkOpen,
  255. extension
  256. );
  257. Irp->IoStatus.Status = STATUS_SUCCESS;
  258. }
  259. //
  260. // We have been marked open, so now the PnP state can change
  261. //
  262. ExReleaseFastMutex(&extension->OpenMutex);
  263. localStatus = Irp->IoStatus.Status;
  264. Irp->IoStatus.Information=0L;
  265. SerialDump(
  266. SERIRPPATH,
  267. ("SERIAL: Complete Irp: %x\n",Irp)
  268. );
  269. if (!NT_SUCCESS(localStatus)) {
  270. if (extension->InterruptReadBuffer != NULL) {
  271. ExFreePool(extension->InterruptReadBuffer);
  272. extension->InterruptReadBuffer = NULL;
  273. }
  274. InterlockedDecrement(&extension->OpenCount);
  275. }
  276. SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
  277. return localStatus;
  278. }
  279. VOID
  280. SerialDrainUART(IN PSERIAL_DEVICE_EXTENSION PDevExt,
  281. IN PLARGE_INTEGER PDrainTime)
  282. {
  283. PAGED_CODE();
  284. //
  285. // Wait until all characters have been emptied out of the hardware.
  286. //
  287. while ((READ_LINE_STATUS(PDevExt->Controller) &
  288. (SERIAL_LSR_THRE | SERIAL_LSR_TEMT))
  289. != (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) {
  290. KeDelayExecutionThread(KernelMode, FALSE, PDrainTime);
  291. }
  292. }
  293. NTSTATUS
  294. SerialClose(
  295. IN PDEVICE_OBJECT DeviceObject,
  296. IN PIRP Irp
  297. )
  298. /*++
  299. Routine Description:
  300. We simply disconnect the interrupt for now.
  301. Arguments:
  302. DeviceObject - Pointer to the device object for this device
  303. Irp - Pointer to the IRP for the current request
  304. Return Value:
  305. The function value is the final status of the call
  306. --*/
  307. {
  308. //
  309. // This "timer value" is used to wait 10 character times
  310. // after the hardware is empty before we actually "run down"
  311. // all of the flow control/break junk.
  312. //
  313. LARGE_INTEGER tenCharDelay;
  314. //
  315. // Holds a character time.
  316. //
  317. LARGE_INTEGER charTime;
  318. //
  319. // Just what it says. This is the serial specific device
  320. // extension of the device object create for the serial driver.
  321. //
  322. PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
  323. NTSTATUS status;
  324. //
  325. // Number of opens still active
  326. //
  327. LONG openCount;
  328. //
  329. // Number of DPC's still pending
  330. //
  331. ULONG pendingDPCs;
  332. ULONG flushCount;
  333. //
  334. // Grab a mutex
  335. //
  336. ExAcquireFastMutex(&extension->CloseMutex);
  337. //
  338. // We succeed a close on a removing device
  339. //
  340. if ((status = SerialIRPPrologue(Irp, extension)) != STATUS_SUCCESS) {
  341. SerialDump(SERERRORS, ("SERIAL: Close prologue failed for: %x\n",Irp));
  342. if (status == STATUS_DELETE_PENDING) {
  343. extension->BufferSize = 0;
  344. ExFreePool(extension->InterruptReadBuffer);
  345. extension->InterruptReadBuffer = NULL;
  346. status = Irp->IoStatus.Status = STATUS_SUCCESS;
  347. }
  348. SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
  349. openCount = InterlockedDecrement(&extension->OpenCount);
  350. ASSERT(openCount == 0);
  351. ExReleaseFastMutex(&extension->CloseMutex);
  352. return status;
  353. }
  354. ASSERT(extension->OpenCount == 1);
  355. if (extension->OpenCount != 1) {
  356. SerialDump(SERERRORS, ("SERIAL: Close open count bad for: 0x%x\n",Irp));
  357. SerialDump(SERERRORS, ("------: Count: %x Addr: 0x%x\n",
  358. extension->OpenCount, &extension->OpenCount));
  359. ExReleaseFastMutex(&extension->CloseMutex);
  360. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  361. SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
  362. return STATUS_INVALID_DEVICE_REQUEST;
  363. }
  364. SerialDump(
  365. SERIRPPATH,
  366. ("SERIAL: Dispatch entry for: %x\n",Irp)
  367. );
  368. SerialDump(
  369. SERDIAG3,
  370. ("SERIAL: In SerialClose\n")
  371. );
  372. charTime.QuadPart = -SerialGetCharTime(extension).QuadPart;
  373. //
  374. // Do this now so that if the isr gets called it won't do anything
  375. // to cause more chars to get sent. We want to run down the hardware.
  376. //
  377. extension->DeviceIsOpened = FALSE;
  378. //
  379. // Synchronize with the isr to turn off break if it
  380. // is already on.
  381. //
  382. KeSynchronizeExecution(
  383. extension->Interrupt,
  384. SerialTurnOffBreak,
  385. extension
  386. );
  387. //
  388. // Wait a reasonable amount of time (20 * fifodepth) until all characters
  389. // have been emptied out of the hardware.
  390. //
  391. #if defined(NEC_98)
  392. //
  393. // all characters not have been emptied out of the hardware.
  394. //
  395. #else
  396. for (flushCount = (20 * 16); flushCount != 0; flushCount--) {
  397. if ((READ_LINE_STATUS(extension->Controller) &
  398. (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) !=
  399. (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) {
  400. KeDelayExecutionThread(KernelMode, FALSE, &charTime);
  401. } else {
  402. break;
  403. }
  404. }
  405. if (flushCount == 0) {
  406. SerialMarkHardwareBroken(extension);
  407. }
  408. #endif //defined(NEC_98)
  409. //
  410. // Synchronize with the ISR to let it know that interrupts are
  411. // no longer important.
  412. //
  413. KeSynchronizeExecution(
  414. extension->Interrupt,
  415. SerialMarkClose,
  416. extension
  417. );
  418. //
  419. // If the driver has automatically transmitted an Xoff in
  420. // the context of automatic receive flow control then we
  421. // should transmit an Xon.
  422. //
  423. if (extension->RXHolding & SERIAL_RX_XOFF) {
  424. //
  425. // Loop until the holding register is empty.
  426. //
  427. while (!(READ_LINE_STATUS(extension->Controller) &
  428. SERIAL_LSR_THRE)) {
  429. KeDelayExecutionThread(
  430. KernelMode,
  431. FALSE,
  432. &charTime
  433. );
  434. }
  435. WRITE_TRANSMIT_HOLDING(
  436. extension->Controller,
  437. extension->SpecialChars.XonChar
  438. );
  439. //
  440. // Wait a reasonable amount of time for the characters
  441. // to be emptied out of the hardware.
  442. //
  443. for (flushCount = (20 * 16); flushCount != 0; flushCount--) {
  444. if ((READ_LINE_STATUS(extension->Controller) &
  445. (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) !=
  446. (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) {
  447. KeDelayExecutionThread(KernelMode, FALSE, &charTime);
  448. } else {
  449. break;
  450. }
  451. }
  452. if (flushCount == 0) {
  453. SerialMarkHardwareBroken(extension);
  454. }
  455. }
  456. //
  457. // The hardware is empty. Delay 10 character times before
  458. // shut down all the flow control.
  459. //
  460. tenCharDelay.QuadPart = charTime.QuadPart * 10;
  461. KeDelayExecutionThread(
  462. KernelMode,
  463. TRUE,
  464. &tenCharDelay
  465. );
  466. SerialClrDTR(extension);
  467. //
  468. // We have to be very careful how we clear the RTS line.
  469. // Transmit toggling might have been on at some point.
  470. //
  471. // We know that there is nothing left that could start
  472. // out the "polling" execution path. We need to
  473. // check the counter that indicates that the execution
  474. // path is active. If it is then we loop delaying one
  475. // character time. After each delay we check to see if
  476. // the counter has gone to zero. When it has we know that
  477. // the execution path should be just about finished. We
  478. // make sure that we still aren't in the routine that
  479. // synchronized execution with the ISR by synchronizing
  480. // ourselve with the ISR.
  481. //
  482. if (extension->CountOfTryingToLowerRTS) {
  483. do {
  484. KeDelayExecutionThread(
  485. KernelMode,
  486. FALSE,
  487. &charTime
  488. );
  489. } while (extension->CountOfTryingToLowerRTS);
  490. KeSynchronizeExecution(
  491. extension->Interrupt,
  492. SerialNullSynch,
  493. NULL
  494. );
  495. //
  496. // The execution path should no longer exist that
  497. // is trying to push down the RTS. Well just
  498. // make sure it's down by falling through to
  499. // code that forces it down.
  500. //
  501. }
  502. SerialClrRTS(extension);
  503. //
  504. // Clean out the holding reasons (since we are closed).
  505. //
  506. extension->RXHolding = 0;
  507. extension->TXHolding = 0;
  508. //
  509. // Mark device as not busy for WMI
  510. //
  511. extension->WmiCommData.IsBusy = FALSE;
  512. //
  513. // All is done. The port has been disabled from interrupting
  514. // so there is no point in keeping the memory around.
  515. //
  516. extension->BufferSize = 0;
  517. if (extension->InterruptReadBuffer != NULL) {
  518. ExFreePool(extension->InterruptReadBuffer);
  519. }
  520. extension->InterruptReadBuffer = NULL;
  521. //
  522. // Stop waiting for wakeup
  523. //
  524. extension->SendWaitWake = FALSE;
  525. if (extension->PendingWakeIrp != NULL) {
  526. IoCancelIrp(extension->PendingWakeIrp);
  527. }
  528. //
  529. // Power down our device stack
  530. //
  531. (void)SerialGotoPowerState(DeviceObject, extension, PowerDeviceD3);
  532. Irp->IoStatus.Status = STATUS_SUCCESS;
  533. Irp->IoStatus.Information=0L;
  534. SerialDump(
  535. SERIRPPATH,
  536. ("SERIAL: Complete Irp: %x\n",Irp)
  537. );
  538. SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
  539. //
  540. // Unlock the pages. If this is the last reference to the section
  541. // then the driver code will be flushed out.
  542. //
  543. //
  544. // First, we have to let the DPC's drain. No more should be queued
  545. // since we aren't taking interrupts now....
  546. //
  547. pendingDPCs = InterlockedDecrement(&extension->DpcCount);
  548. if (pendingDPCs) {
  549. SerialDump(SERDIAG1, ("SERIAL: Drainging DPC's: %x\n",Irp));
  550. KeWaitForSingleObject(&extension->PendingDpcEvent, Executive,
  551. KernelMode, FALSE, NULL);
  552. }
  553. SerialDump(SERDIAG1, ("SERIAL: DPC's drained: %x\n",Irp));
  554. //
  555. // Pages must be locked to release the mutex, so don't unlock
  556. // them until after we release the mutex
  557. //
  558. ExReleaseFastMutex(&extension->CloseMutex);
  559. //
  560. // Reset for next open
  561. //
  562. InterlockedIncrement(&extension->DpcCount);
  563. openCount = InterlockedDecrement(&extension->OpenCount);
  564. ASSERT(openCount == 0);
  565. SerialUnlockPagableImageSection(SerialGlobals.PAGESER_Handle);
  566. return STATUS_SUCCESS;
  567. }
  568. BOOLEAN
  569. SerialCheckOpen(
  570. IN PVOID Context
  571. )
  572. /*++
  573. Routine Description:
  574. This routine will traverse the circular doubly linked list
  575. of devices that are using the same interrupt object. It will look
  576. for other devices that are open. If it doesn't find any
  577. it will indicate that it is ok to open this device.
  578. If it finds another device open we have two cases:
  579. 1) The device we are trying to open is on a multiport card.
  580. If the already open device is part of a multiport device
  581. this code will indicate it is ok to open. We do this on the
  582. theory that the multiport devices are daisy chained
  583. and the cards can correctly arbitrate the interrupt
  584. line. Note this assumption could be wrong. Somebody
  585. could put two non-daisychained multiports on the
  586. same interrupt. However, only a total clod would do
  587. such a thing, and in my opinion deserves everthing they
  588. get.
  589. 2) The device we are trying to open is not on a multiport card.
  590. We indicate that it is not ok to open.
  591. Arguments:
  592. Context - This is a structure that contains a pointer to the
  593. extension of the device we are trying to open, and
  594. a pointer to an NTSTATUS that will indicate whether
  595. the device was opened or not.
  596. Return Value:
  597. This routine always returns FALSE.
  598. --*/
  599. {
  600. PSERIAL_DEVICE_EXTENSION extensionToOpen =
  601. ((PSERIAL_CHECK_OPEN)Context)->Extension;
  602. NTSTATUS *status = ((PSERIAL_CHECK_OPEN)Context)->StatusOfOpen;
  603. PLIST_ENTRY firstEntry = &extensionToOpen->CommonInterruptObject;
  604. PLIST_ENTRY currentEntry = firstEntry;
  605. PSERIAL_DEVICE_EXTENSION currentExtension;
  606. do {
  607. currentExtension = CONTAINING_RECORD(
  608. currentEntry,
  609. SERIAL_DEVICE_EXTENSION,
  610. CommonInterruptObject
  611. );
  612. if (currentExtension->DeviceIsOpened) {
  613. break;
  614. }
  615. currentEntry = currentExtension->CommonInterruptObject.Flink;
  616. } while (currentEntry != firstEntry);
  617. if (currentEntry == firstEntry) {
  618. //
  619. // We searched the whole list and found no other opens
  620. // mark the status as successful and call the regular
  621. // opening routine.
  622. //
  623. *status = STATUS_SUCCESS;
  624. SerialMarkOpen(extensionToOpen);
  625. } else {
  626. if (!extensionToOpen->PortOnAMultiportCard) {
  627. *status = STATUS_SHARED_IRQ_BUSY;
  628. } else {
  629. if (!currentExtension->PortOnAMultiportCard) {
  630. *status = STATUS_SHARED_IRQ_BUSY;
  631. } else {
  632. *status = STATUS_SUCCESS;
  633. SerialMarkOpen(extensionToOpen);
  634. }
  635. }
  636. }
  637. return FALSE;
  638. }
  639. BOOLEAN
  640. SerialMarkOpen(
  641. IN PVOID Context
  642. )
  643. /*++
  644. Routine Description:
  645. This routine merely sets a boolean to true to mark the fact that
  646. somebody opened the device and its worthwhile to pay attention
  647. to interrupts.
  648. Arguments:
  649. Context - Really a pointer to the device extension.
  650. Return Value:
  651. This routine always returns FALSE.
  652. --*/
  653. {
  654. PSERIAL_DEVICE_EXTENSION extension = Context;
  655. #if defined(NEC_98)
  656. //
  657. // This argument use at MACRO only.
  658. //
  659. PSERIAL_DEVICE_EXTENSION Extension = Context;
  660. #else
  661. #endif //defined(NEC_98)
  662. SerialReset(extension);
  663. //
  664. // Prepare for the opening by re-enabling interrupts.
  665. //
  666. // We do this my modifying the OUT2 line in the modem control.
  667. // In PC's this bit is "anded" with the interrupt line.
  668. //
  669. // For the Jensen, we will ALWAYS leave the line high. That's
  670. // the way the hardware engineers want it.
  671. //
  672. WRITE_MODEM_CONTROL(
  673. extension->Controller,
  674. (UCHAR)(READ_MODEM_CONTROL(extension->Controller) | SERIAL_MCR_OUT2)
  675. );
  676. extension->DeviceIsOpened = TRUE;
  677. extension->ErrorWord = 0;
  678. return FALSE;
  679. }
  680. VOID
  681. SerialDisableUART(IN PVOID Context)
  682. /*++
  683. Routine Description:
  684. This routine disables the UART and puts it in a "safe" state when
  685. not in use (like a close or powerdown).
  686. Arguments:
  687. Context - Really a pointer to the device extension.
  688. Return Value:
  689. This routine always returns FALSE.
  690. --*/
  691. {
  692. PSERIAL_DEVICE_EXTENSION extension = Context;
  693. #if defined(NEC_98)
  694. //
  695. // This argument use at MACRO only.
  696. //
  697. PSERIAL_DEVICE_EXTENSION Extension = Context;
  698. #else
  699. #endif //defined(NEC_98)
  700. //
  701. // Prepare for the closing by stopping interrupts.
  702. //
  703. // We do this by adjusting the OUT2 line in the modem control.
  704. // In PC's this bit is "anded" with the interrupt line.
  705. //
  706. // The line should stay high on the Jensen because that's the
  707. // way the hardware engineers did it.
  708. //
  709. if (!extension->Jensen) {
  710. WRITE_MODEM_CONTROL(extension->Controller,
  711. (UCHAR)(READ_MODEM_CONTROL(extension->Controller)
  712. & ~SERIAL_MCR_OUT2));
  713. }
  714. if (extension->FifoPresent) {
  715. WRITE_FIFO_CONTROL(extension->Controller, (UCHAR)0);
  716. }
  717. }
  718. BOOLEAN
  719. SerialMarkClose(
  720. IN PVOID Context
  721. )
  722. /*++
  723. Routine Description:
  724. This routine merely sets a boolean to false to mark the fact that
  725. somebody closed the device and it's no longer worthwhile to pay attention
  726. to interrupts. It also disables the UART.
  727. Arguments:
  728. Context - Really a pointer to the device extension.
  729. Return Value:
  730. This routine always returns FALSE.
  731. --*/
  732. {
  733. PSERIAL_DEVICE_EXTENSION extension = Context;
  734. SerialDisableUART(Context);
  735. extension->DeviceIsOpened = FALSE;
  736. return FALSE;
  737. }
  738. NTSTATUS
  739. SerialCleanup(
  740. IN PDEVICE_OBJECT DeviceObject,
  741. IN PIRP Irp
  742. )
  743. /*++
  744. Routine Description:
  745. This function is used to kill all longstanding IO operations.
  746. Arguments:
  747. DeviceObject - Pointer to the device object for this device
  748. Irp - Pointer to the IRP for the current request
  749. Return Value:
  750. The function value is the final status of the call
  751. --*/
  752. {
  753. PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
  754. NTSTATUS status;
  755. PAGED_CODE();
  756. //
  757. // We succeed a cleanup on a removing device
  758. //
  759. if ((status = SerialIRPPrologue(Irp, extension)) != STATUS_SUCCESS) {
  760. if (status == STATUS_DELETE_PENDING) {
  761. status = Irp->IoStatus.Status = STATUS_SUCCESS;
  762. }
  763. SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
  764. return status;
  765. }
  766. SerialDump(
  767. SERIRPPATH,
  768. ("SERIAL: Dispatch entry for: %x\n",Irp)
  769. );
  770. SerialKillPendingIrps(DeviceObject);
  771. Irp->IoStatus.Status = STATUS_SUCCESS;
  772. Irp->IoStatus.Information=0L;
  773. SerialDump(
  774. SERIRPPATH,
  775. ("SERIAL: Complete Irp: %x\n",Irp)
  776. );
  777. SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
  778. return STATUS_SUCCESS;
  779. }
  780. LARGE_INTEGER
  781. SerialGetCharTime(
  782. IN PSERIAL_DEVICE_EXTENSION Extension
  783. )
  784. /*++
  785. Routine Description:
  786. This function will return the number of 100 nanosecond intervals
  787. there are in one character time (based on the present form
  788. of flow control.
  789. Arguments:
  790. Extension - Just what it says.
  791. Return Value:
  792. 100 nanosecond intervals in a character time.
  793. --*/
  794. {
  795. ULONG dataSize;
  796. ULONG paritySize;
  797. ULONG stopSize;
  798. ULONG charTime;
  799. ULONG bitTime;
  800. LARGE_INTEGER tmp;
  801. if ((Extension->LineControl & SERIAL_DATA_MASK) == SERIAL_5_DATA) {
  802. dataSize = 5;
  803. } else if ((Extension->LineControl & SERIAL_DATA_MASK)
  804. == SERIAL_6_DATA) {
  805. dataSize = 6;
  806. } else if ((Extension->LineControl & SERIAL_DATA_MASK)
  807. == SERIAL_7_DATA) {
  808. dataSize = 7;
  809. } else if ((Extension->LineControl & SERIAL_DATA_MASK)
  810. == SERIAL_8_DATA) {
  811. dataSize = 8;
  812. }
  813. paritySize = 1;
  814. if ((Extension->LineControl & SERIAL_PARITY_MASK)
  815. == SERIAL_NONE_PARITY) {
  816. paritySize = 0;
  817. }
  818. if (Extension->LineControl & SERIAL_2_STOP) {
  819. //
  820. // Even if it is 1.5, for sanities sake were going
  821. // to say 2.
  822. //
  823. stopSize = 2;
  824. } else {
  825. stopSize = 1;
  826. }
  827. //
  828. // First we calculate the number of 100 nanosecond intervals
  829. // are in a single bit time (Approximately).
  830. //
  831. bitTime = (10000000+(Extension->CurrentBaud-1))/Extension->CurrentBaud;
  832. charTime = bitTime + ((dataSize+paritySize+stopSize)*bitTime);
  833. tmp.QuadPart = charTime;
  834. return tmp;
  835. }