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.

2272 lines
67 KiB

  1. /*--------------------------------------------------------------------------
  2. *
  3. * Copyright (C) Cyclades Corporation, 1997-2001.
  4. * All rights reserved.
  5. *
  6. * Cyclades-Z Port Driver
  7. *
  8. * This file: cyzinit.c
  9. *
  10. * Description: This module contains the code related to initialization
  11. * and unload operations 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. //
  31. // This is the actual definition of CyzDebugLevel.
  32. // Note that it is only defined if this is a "debug"
  33. // build.
  34. //
  35. #if DBG
  36. extern ULONG CyzDebugLevel = CYZDBGALL;
  37. #endif
  38. //
  39. // All our global variables except DebugLevel stashed in one
  40. // little package
  41. //
  42. CYZ_GLOBALS CyzGlobals;
  43. static const PHYSICAL_ADDRESS CyzPhysicalZero = {0};
  44. //
  45. // We use this to query into the registry as to whether we
  46. // should break at driver entry.
  47. //
  48. CYZ_REGISTRY_DATA driverDefaults;
  49. //
  50. // INIT - only needed during init and then can be disposed
  51. // PAGESRP0 - always paged / never locked
  52. // PAGESER - must be locked when a device is open, else paged
  53. //
  54. //
  55. // INIT is used for DriverEntry() specific code
  56. //
  57. // PAGESRP0 is used for code that is not often called and has nothing
  58. // to do with I/O performance. An example, IRP_MJ_PNP/IRP_MN_START_DEVICE
  59. // support functions
  60. //
  61. // PAGESER is used for code that needs to be locked after an open for both
  62. // performance and IRQL reasons.
  63. //
  64. #ifdef ALLOC_PRAGMA
  65. #pragma alloc_text(INIT,DriverEntry)
  66. #pragma alloc_text(PAGESRP0, CyzRemoveDevObj)
  67. #pragma alloc_text(PAGESRP0, CyzUnload)
  68. //
  69. // PAGESER handled is keyed off of CyzReset, so CyzReset
  70. // must remain in PAGESER for things to work properly
  71. //
  72. #pragma alloc_text(PAGESER, CyzReset)
  73. #pragma alloc_text(PAGESER, CyzCommError)
  74. #endif
  75. NTSTATUS
  76. DriverEntry(
  77. IN PDRIVER_OBJECT DriverObject,
  78. IN PUNICODE_STRING RegistryPath
  79. )
  80. /*--------------------------------------------------------------------------
  81. The entry point that the system point calls to initialize
  82. any driver.
  83. This routine will gather the configuration information,
  84. report resource usage, attempt to initialize all serial
  85. devices, connect to interrupts for ports. If the above
  86. goes reasonably well it will fill in the dispatch points,
  87. reset the serial devices and then return to the system.
  88. Arguments:
  89. DriverObject - Just what it says, really of little use
  90. to the driver itself, it is something that the IO system
  91. cares more about.
  92. PathToRegistry - points to the entry for this driver
  93. in the current control set of the registry.
  94. Return Value:
  95. Always STATUS_SUCCESS
  96. --------------------------------------------------------------------------*/
  97. {
  98. //
  99. // Lock the paged code in their frames
  100. //
  101. PVOID lockPtr = MmLockPagableCodeSection(CyzReset);
  102. PAGED_CODE();
  103. ASSERT(CyzGlobals.PAGESER_Handle == NULL);
  104. #if DBG
  105. CyzGlobals.PAGESER_Count = 0;
  106. SerialLogInit();
  107. #endif
  108. CyzGlobals.PAGESER_Handle = lockPtr;
  109. CyzGlobals.RegistryPath.MaximumLength = RegistryPath->MaximumLength;
  110. CyzGlobals.RegistryPath.Length = RegistryPath->Length;
  111. CyzGlobals.RegistryPath.Buffer
  112. = ExAllocatePool(PagedPool, CyzGlobals.RegistryPath.MaximumLength);
  113. if (CyzGlobals.RegistryPath.Buffer == NULL) {
  114. MmUnlockPagableImageSection(lockPtr);
  115. return STATUS_INSUFFICIENT_RESOURCES;
  116. }
  117. RtlZeroMemory(CyzGlobals.RegistryPath.Buffer,
  118. CyzGlobals.RegistryPath.MaximumLength);
  119. RtlMoveMemory(CyzGlobals.RegistryPath.Buffer,
  120. RegistryPath->Buffer, RegistryPath->Length);
  121. KeInitializeSpinLock(&CyzGlobals.GlobalsSpinLock);
  122. //
  123. // Initialize all our globals
  124. //
  125. InitializeListHead(&CyzGlobals.AllDevObjs);
  126. //
  127. // Call to find out default values to use for all the devices that the
  128. // driver controls, including whether or not to break on entry.
  129. //
  130. CyzGetConfigDefaults(&driverDefaults, RegistryPath);
  131. #if DBG
  132. //
  133. // Set global debug output level
  134. //
  135. CyzDebugLevel = driverDefaults.DebugLevel;
  136. #endif
  137. //
  138. // Break on entry if requested via registry
  139. //
  140. if (driverDefaults.ShouldBreakOnEntry) {
  141. DbgBreakPoint();
  142. }
  143. //
  144. // Just dump out how big the extension is.
  145. //
  146. CyzDbgPrintEx(DPFLTR_INFO_LEVEL, "The number of bytes in the extension "
  147. "is: %d\n", sizeof(CYZ_DEVICE_EXTENSION));
  148. //
  149. // Initialize the Driver Object with driver's entry points
  150. //
  151. DriverObject->DriverUnload = CyzUnload;
  152. DriverObject->DriverExtension->AddDevice = CyzAddDevice;
  153. DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = CyzFlush;
  154. DriverObject->MajorFunction[IRP_MJ_WRITE] = CyzWrite;
  155. DriverObject->MajorFunction[IRP_MJ_READ] = CyzRead;
  156. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = CyzIoControl;
  157. DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL]
  158. = CyzInternalIoControl;
  159. DriverObject->MajorFunction[IRP_MJ_CREATE] = CyzCreateOpen;
  160. DriverObject->MajorFunction[IRP_MJ_CLOSE] = CyzClose;
  161. DriverObject->MajorFunction[IRP_MJ_CLEANUP] = CyzCleanup;
  162. DriverObject->MajorFunction[IRP_MJ_PNP] = CyzPnpDispatch;
  163. DriverObject->MajorFunction[IRP_MJ_POWER] = CyzPowerDispatch;
  164. DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION]
  165. = CyzQueryInformationFile;
  166. DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION]
  167. = CyzSetInformationFile;
  168. DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL]
  169. = CyzSystemControlDispatch;
  170. //
  171. // Unlock pageable text
  172. //
  173. MmUnlockPagableImageSection(lockPtr);
  174. return STATUS_SUCCESS;
  175. }
  176. BOOLEAN
  177. CyzCleanLists(IN PVOID Context)
  178. /*++
  179. Routine Description:
  180. Removes a device object from any of the serial linked lists it may
  181. appear on.
  182. Arguments:
  183. Context - Actually a PCYZ_DEVICE_EXTENSION (for the devobj being
  184. removed).
  185. Return Value:
  186. Always TRUE
  187. --*/
  188. {
  189. PCYZ_DEVICE_EXTENSION pDevExt = (PCYZ_DEVICE_EXTENSION)Context;
  190. PCYZ_DISPATCH pDispatch;
  191. ULONG i;
  192. //
  193. // Remove our entry from the dispatch context
  194. //
  195. pDispatch = (PCYZ_DISPATCH)pDevExt->OurIsrContext;
  196. CyzDbgPrintEx(CYZPNPPOWER, "CLEAN: removing multiport isr "
  197. "ext\n");
  198. #ifdef POLL
  199. if (pDispatch->PollingStarted) {
  200. pDispatch->Extensions[pDevExt->PortIndex] = NULL;
  201. for (i = 0; i < pDispatch->NChannels; i++) {
  202. if (pDevExt->OurIsrContext) {
  203. if (((PCYZ_DISPATCH)pDevExt->OurIsrContext)->Extensions[i] != NULL) {
  204. break;
  205. }
  206. }
  207. }
  208. if (i < pDispatch->NChannels) {
  209. pDevExt->OurIsrContext = NULL;
  210. } else {
  211. BOOLEAN cancelled;
  212. pDispatch->PollingStarted = FALSE;
  213. cancelled = KeCancelTimer(&pDispatch->PollingTimer);
  214. if (cancelled) {
  215. pDispatch->PollingDrained = TRUE;
  216. }
  217. }
  218. }
  219. #else
  220. pDispatch->Extensions[pDevExt->PortIndex] = NULL;
  221. for (i = 0; i < pDispatch->NChannels; i++) {
  222. if (pDispatch->Extensions[i] != NULL) {
  223. break;
  224. }
  225. }
  226. if (i < pDispatch->NChannels) {
  227. // Others are chained on this interrupt, so we don't want to
  228. // disconnect it.
  229. pDevExt->Interrupt = NULL;
  230. }
  231. #endif
  232. return TRUE;
  233. }
  234. VOID
  235. CyzReleaseResources(IN PCYZ_DEVICE_EXTENSION PDevExt)
  236. /*++
  237. Routine Description:
  238. Releases resources (not pool) stored in the device extension.
  239. Arguments:
  240. PDevExt - Pointer to the device extension to release resources from.
  241. Return Value:
  242. VOID
  243. --*/
  244. {
  245. #ifdef POLL
  246. KIRQL pollIrql;
  247. BOOLEAN timerStarted, timerDrained;
  248. PCYZ_DISPATCH pDispatch = PDevExt->OurIsrContext;
  249. ULONG pollCount;
  250. #endif
  251. KIRQL oldIrql;
  252. CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, ">CyzReleaseResources(%X)\n",
  253. PDevExt);
  254. //
  255. // AllDevObjs should never be empty since we have a sentinal
  256. // Note: serial removes device from AllDevObjs list after calling
  257. // SerialCleanLists. We do it before to make sure no other port will
  258. // be added to share the polling routine or PDevExt->Interrut that is
  259. // on the way to be disconnected.
  260. //
  261. KeAcquireSpinLock(&CyzGlobals.GlobalsSpinLock, &oldIrql);
  262. ASSERT(!IsListEmpty(&PDevExt->AllDevObjs));
  263. RemoveEntryList(&PDevExt->AllDevObjs);
  264. KeReleaseSpinLock(&CyzGlobals.GlobalsSpinLock, oldIrql);
  265. InitializeListHead(&PDevExt->AllDevObjs);
  266. //
  267. // Remove us from any lists we may be on
  268. //
  269. #ifdef POLL
  270. KeAcquireSpinLock(&pDispatch->PollingLock,&pollIrql); //Changed in 11/09/00
  271. CyzCleanLists(PDevExt);
  272. timerStarted = pDispatch->PollingStarted;
  273. timerDrained = pDispatch->PollingDrained;
  274. KeReleaseSpinLock(&pDispatch->PollingLock,pollIrql); // Changed in 11/09/00
  275. // If we are the last device, free this memory
  276. if (!timerStarted) {
  277. // We are the last device, because timer was cancelled.
  278. // Let's see if no more pending DPC.
  279. if (!timerDrained) {
  280. KeWaitForSingleObject(&pDispatch->PendingDpcEvent, Executive,
  281. KernelMode, FALSE, NULL);
  282. }
  283. KeAcquireSpinLock(&pDispatch->PollingLock,&pollIrql); // needed to wait for PollingDpc end
  284. pollCount = InterlockedDecrement(&pDispatch->PollingCount);
  285. KeReleaseSpinLock(&pDispatch->PollingLock,pollIrql);
  286. if (pollCount == 0) {
  287. CyzDbgPrintEx(CYZPNPPOWER, "Release - freeing multi context\n");
  288. if (PDevExt->OurIsrContext != NULL) { // added in DDK build 2072, but
  289. ExFreePool(PDevExt->OurIsrContext); // we already had the free of OurIsrContext.
  290. PDevExt->OurIsrContext = NULL; //
  291. }
  292. }
  293. }
  294. #else
  295. KeSynchronizeExecution(PDevExt->Interrupt, CyzCleanLists, PDevExt);
  296. //
  297. // Stop servicing interrupts if we are the last device
  298. //
  299. if (PDevExt->Interrupt != NULL) {
  300. // Disable interrupts in the PLX
  301. {
  302. ULONG intr_reg;
  303. intr_reg = CYZ_READ_ULONG(&(PDevExt->Runtime)->intr_ctrl_stat);
  304. intr_reg &= ~(0x00030B00UL);
  305. CYZ_WRITE_ULONG(&(PDevExt->Runtime)->intr_ctrl_stat,intr_reg);
  306. }
  307. CyzDbgPrintEx(CYZPNPPOWER, "Release - disconnecting interrupt %X\n",
  308. PDevExt->Interrupt);
  309. IoDisconnectInterrupt(PDevExt->Interrupt);
  310. PDevExt->Interrupt = NULL;
  311. // If we are the last device, free this memory
  312. CyzDbgPrintEx(CYZPNPPOWER, "Release - freeing multi context\n");
  313. if (PDevExt->OurIsrContext != NULL) { // added in DDK build 2072, but
  314. ExFreePool(PDevExt->OurIsrContext); // we already had the free of OurIsrContext.
  315. PDevExt->OurIsrContext = NULL; //
  316. }
  317. }
  318. #endif
  319. //
  320. // Stop handling timers
  321. //
  322. CyzCancelTimer(&PDevExt->ReadRequestTotalTimer, PDevExt);
  323. CyzCancelTimer(&PDevExt->ReadRequestIntervalTimer, PDevExt);
  324. CyzCancelTimer(&PDevExt->WriteRequestTotalTimer, PDevExt);
  325. CyzCancelTimer(&PDevExt->ImmediateTotalTimer, PDevExt);
  326. CyzCancelTimer(&PDevExt->XoffCountTimer, PDevExt);
  327. CyzCancelTimer(&PDevExt->LowerRTSTimer, PDevExt);
  328. //
  329. // Stop servicing DPC's
  330. //
  331. CyzRemoveQueueDpc(&PDevExt->CompleteWriteDpc, PDevExt);
  332. CyzRemoveQueueDpc(&PDevExt->CompleteReadDpc, PDevExt);
  333. CyzRemoveQueueDpc(&PDevExt->TotalReadTimeoutDpc, PDevExt);
  334. CyzRemoveQueueDpc(&PDevExt->IntervalReadTimeoutDpc, PDevExt);
  335. CyzRemoveQueueDpc(&PDevExt->TotalWriteTimeoutDpc, PDevExt);
  336. CyzRemoveQueueDpc(&PDevExt->CommErrorDpc, PDevExt);
  337. CyzRemoveQueueDpc(&PDevExt->CompleteImmediateDpc, PDevExt);
  338. CyzRemoveQueueDpc(&PDevExt->TotalImmediateTimeoutDpc, PDevExt);
  339. CyzRemoveQueueDpc(&PDevExt->CommWaitDpc, PDevExt);
  340. CyzRemoveQueueDpc(&PDevExt->XoffCountTimeoutDpc, PDevExt);
  341. CyzRemoveQueueDpc(&PDevExt->XoffCountCompleteDpc, PDevExt);
  342. CyzRemoveQueueDpc(&PDevExt->StartTimerLowerRTSDpc, PDevExt);
  343. CyzRemoveQueueDpc(&PDevExt->PerhapsLowerRTSDpc, PDevExt);
  344. //
  345. // If necessary, unmap the device registers.
  346. //
  347. // if (PDevExt->BoardMemory) {
  348. // MmUnmapIoSpace(PDevExt->BoardMemory, PDevExt->BoardMemoryLength);
  349. // PDevExt->BoardMemory = NULL;
  350. // }
  351. if (PDevExt->BoardCtrl) {
  352. MmUnmapIoSpace(PDevExt->BoardCtrl, sizeof(struct BOARD_CTRL));
  353. PDevExt->BoardCtrl = NULL;
  354. }
  355. if (PDevExt->ChCtrl) {
  356. MmUnmapIoSpace(PDevExt->ChCtrl,sizeof(struct CH_CTRL));
  357. PDevExt->ChCtrl = NULL;
  358. }
  359. if (PDevExt->BufCtrl) {
  360. MmUnmapIoSpace(PDevExt->BufCtrl,sizeof(struct BUF_CTRL));
  361. PDevExt->BufCtrl = NULL;
  362. }
  363. if (PDevExt->TxBufaddr) {
  364. MmUnmapIoSpace(PDevExt->TxBufaddr,PDevExt->TxBufsize);
  365. PDevExt->TxBufaddr = NULL;
  366. }
  367. if (PDevExt->RxBufaddr) {
  368. MmUnmapIoSpace(PDevExt->RxBufaddr,PDevExt->RxBufsize);
  369. PDevExt->RxBufaddr = NULL;
  370. }
  371. if (PDevExt->PtZfIntQueue) {
  372. MmUnmapIoSpace(PDevExt->PtZfIntQueue,sizeof(struct INT_QUEUE));
  373. PDevExt->PtZfIntQueue = NULL;
  374. }
  375. if (PDevExt->Runtime) {
  376. MmUnmapIoSpace(PDevExt->Runtime,
  377. PDevExt->RuntimeLength);
  378. PDevExt->Runtime = NULL;
  379. }
  380. CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, "<CyzReleaseResources\n");
  381. }
  382. VOID
  383. CyzDisableInterfacesResources(IN PDEVICE_OBJECT PDevObj,
  384. BOOLEAN DisableUART)
  385. {
  386. PCYZ_DEVICE_EXTENSION pDevExt
  387. = (PCYZ_DEVICE_EXTENSION)PDevObj->DeviceExtension;
  388. PAGED_CODE();
  389. CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, ">CyzDisableInterfaces(%X, %s)\n",
  390. PDevObj, DisableUART ? "TRUE" : "FALSE");
  391. //
  392. // Only do these many things if the device has started and still
  393. // has resources allocated
  394. //
  395. if (pDevExt->Flags & CYZ_FLAGS_STARTED) {
  396. if (!(pDevExt->Flags & CYZ_FLAGS_STOPPED)) {
  397. if (DisableUART) {
  398. #ifndef POLL
  399. //TODO: Synchronize with Interrupt.
  400. //
  401. // Mask off interrupts
  402. //
  403. CYZ_WRITE_ULONG(&(pDevExt->ChCtrl)->intr_enable,C_IN_DISABLE); //1.0.0.11
  404. CyzIssueCmd(pDevExt,C_CM_IOCTL,0L,FALSE);
  405. #endif
  406. }
  407. CyzReleaseResources(pDevExt);
  408. }
  409. //
  410. // Remove us from WMI consideration
  411. //
  412. IoWMIRegistrationControl(PDevObj, WMIREG_ACTION_DEREGISTER);
  413. }
  414. //
  415. // Undo external names
  416. //
  417. CyzUndoExternalNaming(pDevExt);
  418. CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, "<CyzDisableInterfaces\n");
  419. }
  420. NTSTATUS
  421. CyzRemoveDevObj(IN PDEVICE_OBJECT PDevObj)
  422. /*++
  423. Routine Description:
  424. Removes a serial device object from the system.
  425. Arguments:
  426. PDevObj - A pointer to the Device Object we want removed.
  427. Return Value:
  428. Always TRUE
  429. --*/
  430. {
  431. PCYZ_DEVICE_EXTENSION pDevExt
  432. = (PCYZ_DEVICE_EXTENSION)PDevObj->DeviceExtension;
  433. PAGED_CODE();
  434. CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, ">CyzRemoveDevObj(%X)\n", PDevObj);
  435. // Removed by Fanny. These code is called directly from IRP_MN_REMOVE_DEVICE.
  436. // if (!(pDevExt->DevicePNPAccept & CYZ_PNPACCEPT_SURPRISE_REMOVING)) {
  437. // //
  438. // // Disable all external interfaces and release resources
  439. // //
  440. //
  441. // CyzDisableInterfacesResources(PDevObj, TRUE);
  442. // }
  443. IoDetachDevice(pDevExt->LowerDeviceObject);
  444. //
  445. // Free memory allocated in the extension
  446. //
  447. if (pDevExt->NtNameForPort.Buffer != NULL) {
  448. ExFreePool(pDevExt->NtNameForPort.Buffer);
  449. }
  450. if (pDevExt->DeviceName.Buffer != NULL) {
  451. ExFreePool(pDevExt->DeviceName.Buffer);
  452. }
  453. if (pDevExt->SymbolicLinkName.Buffer != NULL) {
  454. ExFreePool(pDevExt->SymbolicLinkName.Buffer);
  455. }
  456. if (pDevExt->DosName.Buffer != NULL) {
  457. ExFreePool(pDevExt->DosName.Buffer);
  458. }
  459. if (pDevExt->ObjectDirectory.Buffer) {
  460. ExFreePool(pDevExt->ObjectDirectory.Buffer);
  461. }
  462. //
  463. // Delete the devobj
  464. //
  465. IoDeleteDevice(PDevObj);
  466. CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, "<CyzRemoveDevObj %X\n",
  467. STATUS_SUCCESS);
  468. return STATUS_SUCCESS;
  469. }
  470. VOID
  471. CyzKillPendingIrps(PDEVICE_OBJECT PDevObj)
  472. /*++
  473. Routine Description:
  474. This routine kills any irps pending for the passed device object.
  475. Arguments:
  476. PDevObj - Pointer to the device object whose irps must die.
  477. Return Value:
  478. VOID
  479. --*/
  480. {
  481. PCYZ_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  482. KIRQL oldIrql;
  483. CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, ">CyzKillPendingIrps(%X)\n",
  484. PDevObj);
  485. //
  486. // First kill all the reads and writes.
  487. //
  488. CyzKillAllReadsOrWrites(PDevObj, &pDevExt->WriteQueue,
  489. &pDevExt->CurrentWriteIrp);
  490. CyzKillAllReadsOrWrites(PDevObj, &pDevExt->ReadQueue,
  491. &pDevExt->CurrentReadIrp);
  492. //
  493. // Next get rid of purges.
  494. //
  495. CyzKillAllReadsOrWrites(PDevObj, &pDevExt->PurgeQueue,
  496. &pDevExt->CurrentPurgeIrp);
  497. //
  498. // Get rid of any mask operations.
  499. //
  500. CyzKillAllReadsOrWrites(PDevObj, &pDevExt->MaskQueue,
  501. &pDevExt->CurrentMaskIrp);
  502. //
  503. // Now get rid a pending wait mask irp.
  504. //
  505. IoAcquireCancelSpinLock(&oldIrql);
  506. if (pDevExt->CurrentWaitIrp) {
  507. PDRIVER_CANCEL cancelRoutine;
  508. cancelRoutine = pDevExt->CurrentWaitIrp->CancelRoutine;
  509. pDevExt->CurrentWaitIrp->Cancel = TRUE;
  510. if (cancelRoutine) {
  511. pDevExt->CurrentWaitIrp->CancelIrql = oldIrql;
  512. pDevExt->CurrentWaitIrp->CancelRoutine = NULL;
  513. cancelRoutine(PDevObj, pDevExt->CurrentWaitIrp);
  514. } else {
  515. IoReleaseCancelSpinLock(oldIrql); // Added to fix modem share test 53 freeze
  516. }
  517. } else {
  518. IoReleaseCancelSpinLock(oldIrql);
  519. }
  520. //
  521. // Cancel any pending wait-wake irps
  522. //
  523. if (pDevExt->PendingWakeIrp != NULL) {
  524. IoCancelIrp(pDevExt->PendingWakeIrp);
  525. pDevExt->PendingWakeIrp = NULL;
  526. }
  527. //
  528. // Finally, dump any stalled IRPS
  529. //
  530. CyzKillAllStalled(PDevObj);
  531. CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, "<CyzKillPendingIrps\n");
  532. }
  533. NTSTATUS
  534. CyzInitMultiPort(IN PCYZ_DEVICE_EXTENSION PDevExt,
  535. IN PCONFIG_DATA PConfigData, IN PDEVICE_OBJECT PDevObj)
  536. /*++
  537. Routine Description:
  538. This routine initializes a multiport device by adding a port to an existing
  539. one.
  540. Arguments:
  541. PDevExt - pointer to the device extension of the root of the multiport
  542. device.
  543. PConfigData - pointer to the config data for the new port
  544. PDevObj - pointer to the devobj for the new port
  545. Return Value:
  546. STATUS_SUCCESS on success, appropriate error on failure.
  547. --*/
  548. {
  549. PCYZ_DEVICE_EXTENSION pNewExt
  550. = (PCYZ_DEVICE_EXTENSION)PDevObj->DeviceExtension;
  551. NTSTATUS status;
  552. PAGED_CODE();
  553. CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, ">CyzInitMultiPort(%X, %X, %X)\n",
  554. PDevExt, PConfigData, PDevObj);
  555. //
  556. // Allow him to share OurIsrContext and interrupt object
  557. //
  558. pNewExt->OurIsrContext = PDevExt->OurIsrContext;
  559. #ifndef POLL
  560. pNewExt->Interrupt = PDevExt->Interrupt;
  561. #endif
  562. //
  563. // First, see if we can initialize the one we have found
  564. //
  565. status = CyzInitController(PDevObj, PConfigData);
  566. if (!NT_SUCCESS(status)) {
  567. CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, "<CyzInitMultiPort (1) %X\n",
  568. status);
  569. return status;
  570. }
  571. CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, "<CyzInitMultiPort (3) %X\n",
  572. STATUS_SUCCESS);
  573. return STATUS_SUCCESS;
  574. }
  575. NTSTATUS
  576. CyzInitController(IN PDEVICE_OBJECT PDevObj, IN PCONFIG_DATA PConfigData)
  577. /*++
  578. Routine Description:
  579. Really too many things to mention here. In general initializes
  580. kernel synchronization structures, allocates the typeahead buffer,
  581. sets up defaults, etc.
  582. Arguments:
  583. PDevObj - Device object for the device to be started
  584. PConfigData - Pointer to a record for a single port.
  585. Return Value:
  586. STATUS_SUCCCESS if everything went ok. A !NT_SUCCESS status
  587. otherwise.
  588. --*/
  589. {
  590. PCYZ_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  591. //
  592. // Holds the NT Status that is returned from each call to the
  593. // kernel and executive.
  594. //
  595. NTSTATUS status = STATUS_SUCCESS;
  596. BOOLEAN allocedDispatch = FALSE;
  597. PCYZ_DISPATCH pDispatch = NULL;
  598. BOOLEAN firstTimeThisBoard;
  599. struct FIRM_ID *pt_firm_id;
  600. struct ZFW_CTRL *zfw_ctrl;
  601. struct BOARD_CTRL *board_ctrl;
  602. struct BUF_CTRL *buf_ctrl;
  603. struct CH_CTRL *ch_ctrl;
  604. struct INT_QUEUE *zf_int_queue;
  605. PUCHAR tx_buf;
  606. PUCHAR rx_buf;
  607. PUCHAR BoardMemory;
  608. PHYSICAL_ADDRESS board_ctrl_phys;
  609. PHYSICAL_ADDRESS buf_ctrl_phys;
  610. PHYSICAL_ADDRESS ch_ctrl_phys;
  611. PHYSICAL_ADDRESS zf_int_queue_phys;
  612. PHYSICAL_ADDRESS tx_buf_phys;
  613. PHYSICAL_ADDRESS rx_buf_phys;
  614. #ifdef POLL
  615. BOOLEAN incPoll = FALSE;
  616. #endif
  617. PAGED_CODE();
  618. CyzDbgPrintEx(CYZDIAG1, "Initializing for configuration record of %wZ\n",
  619. &pDevExt->DeviceName);
  620. if (pDevExt->OurIsrContext == NULL) {
  621. if ((pDevExt->OurIsrContext
  622. = ExAllocatePool(NonPagedPool,sizeof(CYZ_DISPATCH))) == NULL) {
  623. status = STATUS_INSUFFICIENT_RESOURCES;
  624. goto ExtensionCleanup;
  625. }
  626. RtlZeroMemory(pDevExt->OurIsrContext,sizeof(CYZ_DISPATCH));
  627. allocedDispatch = TRUE;
  628. firstTimeThisBoard = TRUE;
  629. } else {
  630. firstTimeThisBoard = FALSE;
  631. }
  632. //
  633. // Initialize the timers used to timeout operations.
  634. //
  635. KeInitializeTimer(&pDevExt->ReadRequestTotalTimer);
  636. KeInitializeTimer(&pDevExt->ReadRequestIntervalTimer);
  637. KeInitializeTimer(&pDevExt->WriteRequestTotalTimer);
  638. KeInitializeTimer(&pDevExt->ImmediateTotalTimer);
  639. KeInitializeTimer(&pDevExt->XoffCountTimer);
  640. KeInitializeTimer(&pDevExt->LowerRTSTimer);
  641. //
  642. // Intialialize the dpcs that will be used to complete
  643. // or timeout various IO operations.
  644. //
  645. KeInitializeDpc(&pDevExt->CompleteWriteDpc, CyzCompleteWrite, pDevExt);
  646. KeInitializeDpc(&pDevExt->CompleteReadDpc, CyzCompleteRead, pDevExt);
  647. KeInitializeDpc(&pDevExt->TotalReadTimeoutDpc, CyzReadTimeout, pDevExt);
  648. KeInitializeDpc(&pDevExt->IntervalReadTimeoutDpc, CyzIntervalReadTimeout,
  649. pDevExt);
  650. KeInitializeDpc(&pDevExt->TotalWriteTimeoutDpc, CyzWriteTimeout, pDevExt);
  651. KeInitializeDpc(&pDevExt->CommErrorDpc, CyzCommError, pDevExt);
  652. KeInitializeDpc(&pDevExt->CompleteImmediateDpc, CyzCompleteImmediate,
  653. pDevExt);
  654. KeInitializeDpc(&pDevExt->TotalImmediateTimeoutDpc, CyzTimeoutImmediate,
  655. pDevExt);
  656. KeInitializeDpc(&pDevExt->CommWaitDpc, CyzCompleteWait, pDevExt);
  657. KeInitializeDpc(&pDevExt->XoffCountTimeoutDpc, CyzTimeoutXoff, pDevExt);
  658. KeInitializeDpc(&pDevExt->XoffCountCompleteDpc, CyzCompleteXoff, pDevExt);
  659. KeInitializeDpc(&pDevExt->StartTimerLowerRTSDpc, CyzStartTimerLowerRTS,
  660. pDevExt);
  661. KeInitializeDpc(&pDevExt->PerhapsLowerRTSDpc, CyzInvokePerhapsLowerRTS,
  662. pDevExt);
  663. KeInitializeDpc(&pDevExt->IsrUnlockPagesDpc, CyzUnlockPages, pDevExt);
  664. #if 0 // DBG
  665. //
  666. // Init debug stuff
  667. //
  668. pDevExt->DpcQueued[0].Dpc = &pDevExt->CompleteWriteDpc;
  669. pDevExt->DpcQueued[1].Dpc = &pDevExt->CompleteReadDpc;
  670. pDevExt->DpcQueued[2].Dpc = &pDevExt->TotalReadTimeoutDpc;
  671. pDevExt->DpcQueued[3].Dpc = &pDevExt->IntervalReadTimeoutDpc;
  672. pDevExt->DpcQueued[4].Dpc = &pDevExt->TotalWriteTimeoutDpc;
  673. pDevExt->DpcQueued[5].Dpc = &pDevExt->CommErrorDpc;
  674. pDevExt->DpcQueued[6].Dpc = &pDevExt->CompleteImmediateDpc;
  675. pDevExt->DpcQueued[7].Dpc = &pDevExt->TotalImmediateTimeoutDpc;
  676. pDevExt->DpcQueued[8].Dpc = &pDevExt->CommWaitDpc;
  677. pDevExt->DpcQueued[9].Dpc = &pDevExt->XoffCountTimeoutDpc;
  678. pDevExt->DpcQueued[10].Dpc = &pDevExt->XoffCountCompleteDpc;
  679. pDevExt->DpcQueued[11].Dpc = &pDevExt->StartTimerLowerRTSDpc;
  680. pDevExt->DpcQueued[12].Dpc = &pDevExt->PerhapsLowerRTSDpc;
  681. pDevExt->DpcQueued[13].Dpc = &pDevExt->IsrUnlockPagesDpc;
  682. #endif
  683. //
  684. // Map the memory for the control registers for the serial device
  685. // into virtual memory.
  686. //
  687. pDevExt->Runtime = MmMapIoSpace(PConfigData->TranslatedRuntime,
  688. PConfigData->RuntimeLength,
  689. FALSE);
  690. //******************************
  691. // Error injection
  692. //if (pDevExt->Runtime) {
  693. // MmUnmapIoSpace(pDevExt->Runtime, PConfigData->RuntimeLength);
  694. // pDevExt->Runtime = NULL;
  695. //}
  696. //******************************
  697. if (!pDevExt->Runtime) {
  698. CyzLogError(
  699. PDevObj->DriverObject,
  700. pDevExt->DeviceObject,
  701. PConfigData->PhysicalBoardMemory,
  702. CyzPhysicalZero,
  703. 0,
  704. 0,
  705. 0,
  706. PConfigData->PortIndex+1,
  707. STATUS_SUCCESS,
  708. CYZ_RUNTIME_NOT_MAPPED,
  709. pDevExt->DeviceName.Length+sizeof(WCHAR),
  710. pDevExt->DeviceName.Buffer,
  711. 0,
  712. NULL
  713. );
  714. CyzDbgPrintEx(DPFLTR_WARNING_LEVEL, "Could not map Runtime memory for device "
  715. "registers for %wZ\n", &pDevExt->DeviceName);
  716. status = STATUS_NONE_MAPPED;
  717. goto ExtensionCleanup;
  718. }
  719. BoardMemory = MmMapIoSpace(PConfigData->TranslatedBoardMemory,
  720. PConfigData->BoardMemoryLength,
  721. FALSE);
  722. //******************************
  723. // Error injection
  724. //if (pDevExt->BoardMemory) {
  725. // MmUnmapIoSpace(pDevExt->BoardMemory, PConfigData->BoardMemoryLength);
  726. // pDevExt->BoardMemory = NULL;
  727. //}
  728. //******************************
  729. if (!BoardMemory) {
  730. CyzLogError(
  731. PDevObj->DriverObject,
  732. pDevExt->DeviceObject,
  733. PConfigData->PhysicalBoardMemory,
  734. CyzPhysicalZero,
  735. 0,
  736. 0,
  737. 0,
  738. PConfigData->PortIndex+1,
  739. STATUS_SUCCESS,
  740. CYZ_BOARD_NOT_MAPPED,
  741. pDevExt->DeviceName.Length+sizeof(WCHAR),
  742. pDevExt->DeviceName.Buffer,
  743. 0,
  744. NULL
  745. );
  746. CyzDbgPrintEx(DPFLTR_WARNING_LEVEL, "Could not map Board memory for device "
  747. "registers for %wZ\n", &pDevExt->DeviceName);
  748. status = STATUS_NONE_MAPPED;
  749. goto ExtensionCleanup;
  750. }
  751. pDevExt->RuntimeAddressSpace = PConfigData->RuntimeAddressSpace;
  752. pDevExt->OriginalRuntimeMemory = PConfigData->PhysicalRuntime;
  753. pDevExt->RuntimeLength = PConfigData->RuntimeLength;
  754. pDevExt->BoardMemoryAddressSpace = PConfigData->BoardMemoryAddressSpace;
  755. pDevExt->OriginalBoardMemory = PConfigData->PhysicalBoardMemory;
  756. pDevExt->BoardMemoryLength = PConfigData->BoardMemoryLength;
  757. //
  758. // Shareable interrupt?
  759. //
  760. #ifndef POLL
  761. pDevExt->InterruptShareable = TRUE;
  762. #endif
  763. //
  764. // Save off the interface type and the bus number.
  765. //
  766. pDevExt->InterfaceType = PConfigData->InterfaceType;
  767. pDevExt->BusNumber = PConfigData->BusNumber;
  768. pDevExt->PortIndex = PConfigData->PortIndex;
  769. pDevExt->PPPaware = (BOOLEAN)PConfigData->PPPaware;
  770. pDevExt->ReturnStatusAfterFwEmpty = (BOOLEAN)PConfigData->WriteComplete;
  771. #ifndef POLL
  772. //
  773. // Get the translated interrupt vector, level, and affinity
  774. //
  775. pDevExt->OriginalIrql = PConfigData->OriginalIrql;
  776. pDevExt->OriginalVector = PConfigData->OriginalVector;
  777. //
  778. // PnP uses the passed translated values rather than calling
  779. // HalGetInterruptVector()
  780. //
  781. pDevExt->Vector = PConfigData->TrVector;
  782. pDevExt->Irql = (UCHAR)PConfigData->TrIrql;
  783. //
  784. // Set up the Isr.
  785. //
  786. pDevExt->OurIsr = CyzIsr;
  787. #endif
  788. //
  789. // Before we test whether the port exists (which will enable the FIFO)
  790. // convert the rx trigger value to what should be used in the register.
  791. //
  792. // If a bogus value was given - crank them down to 1.
  793. //
  794. switch (PConfigData->RxFIFO) {
  795. case 1:
  796. pDevExt->RxFifoTrigger = SERIAL_1_BYTE_HIGH_WATER;
  797. break;
  798. case 4:
  799. pDevExt->RxFifoTrigger = SERIAL_4_BYTE_HIGH_WATER;
  800. break;
  801. case 8:
  802. pDevExt->RxFifoTrigger = SERIAL_8_BYTE_HIGH_WATER;
  803. break;
  804. case 14:
  805. pDevExt->RxFifoTrigger = SERIAL_14_BYTE_HIGH_WATER;
  806. break;
  807. default:
  808. pDevExt->RxFifoTrigger = SERIAL_1_BYTE_HIGH_WATER;
  809. break;
  810. }
  811. if ((PConfigData->TxFIFO > 16) ||
  812. (PConfigData->TxFIFO < 1)) {
  813. pDevExt->TxFifoAmount = 1;
  814. } else {
  815. pDevExt->TxFifoAmount = PConfigData->TxFIFO;
  816. }
  817. pt_firm_id = (struct FIRM_ID *) (BoardMemory + ID_ADDRESS);
  818. zfw_ctrl = (struct ZFW_CTRL *)(BoardMemory + CYZ_READ_ULONG(&pt_firm_id->zfwctrl_addr));
  819. board_ctrl = &zfw_ctrl->board_ctrl;
  820. ch_ctrl = &zfw_ctrl->ch_ctrl[pDevExt->PortIndex];
  821. buf_ctrl = &zfw_ctrl->buf_ctrl[pDevExt->PortIndex];
  822. tx_buf = BoardMemory + CYZ_READ_ULONG(&buf_ctrl->tx_bufaddr);
  823. rx_buf = BoardMemory + CYZ_READ_ULONG(&buf_ctrl->rx_bufaddr);
  824. zf_int_queue = (struct INT_QUEUE *)(BoardMemory +
  825. CYZ_READ_ULONG(&(board_ctrl)->zf_int_queue_addr));
  826. board_ctrl_phys = MmGetPhysicalAddress(board_ctrl);
  827. ch_ctrl_phys = MmGetPhysicalAddress(ch_ctrl);
  828. buf_ctrl_phys = MmGetPhysicalAddress(buf_ctrl);
  829. tx_buf_phys = MmGetPhysicalAddress(tx_buf);
  830. rx_buf_phys = MmGetPhysicalAddress(rx_buf);
  831. zf_int_queue_phys = MmGetPhysicalAddress(zf_int_queue);
  832. MmUnmapIoSpace(BoardMemory, PConfigData->BoardMemoryLength);
  833. pDevExt->BoardCtrl = MmMapIoSpace(board_ctrl_phys,
  834. sizeof(struct BOARD_CTRL),
  835. FALSE);
  836. if (pDevExt->BoardCtrl == NULL) {
  837. CyzLogError(
  838. PDevObj->DriverObject,
  839. pDevExt->DeviceObject,
  840. PConfigData->PhysicalBoardMemory,
  841. CyzPhysicalZero,
  842. 0,
  843. 0,
  844. 0,
  845. PConfigData->PortIndex+1,
  846. STATUS_SUCCESS,
  847. CYZ_BOARD_CTRL_NOT_MAPPED,
  848. pDevExt->DeviceName.Length+sizeof(WCHAR),
  849. pDevExt->DeviceName.Buffer,
  850. 0,
  851. NULL
  852. );
  853. CyzDbgPrintEx(DPFLTR_WARNING_LEVEL, "Could not map BoardCtrl for %wZ\n",
  854. &pDevExt->DeviceName);
  855. status = STATUS_NONE_MAPPED;
  856. goto ExtensionCleanup;
  857. }
  858. pDevExt->ChCtrl = MmMapIoSpace(ch_ctrl_phys,
  859. sizeof(struct CH_CTRL),
  860. FALSE);
  861. if (pDevExt->ChCtrl == NULL) {
  862. CyzLogError(
  863. PDevObj->DriverObject,
  864. pDevExt->DeviceObject,
  865. PConfigData->PhysicalBoardMemory,
  866. CyzPhysicalZero,
  867. 0,
  868. 0,
  869. 0,
  870. PConfigData->PortIndex+1,
  871. STATUS_SUCCESS,
  872. CYZ_CH_CTRL_NOT_MAPPED,
  873. pDevExt->DeviceName.Length+sizeof(WCHAR),
  874. pDevExt->DeviceName.Buffer,
  875. 0,
  876. NULL
  877. );
  878. CyzDbgPrintEx(DPFLTR_WARNING_LEVEL, "Could not map Board memory ChCtrl "
  879. "for %wZ\n",&pDevExt->DeviceName);
  880. status = STATUS_NONE_MAPPED;
  881. goto ExtensionCleanup;
  882. }
  883. pDevExt->BufCtrl = MmMapIoSpace(buf_ctrl_phys,
  884. sizeof(struct BUF_CTRL),
  885. FALSE);
  886. if (pDevExt->BufCtrl == NULL) {
  887. CyzLogError(
  888. PDevObj->DriverObject,
  889. pDevExt->DeviceObject,
  890. PConfigData->PhysicalBoardMemory,
  891. CyzPhysicalZero,
  892. 0,
  893. 0,
  894. 0,
  895. PConfigData->PortIndex+1,
  896. STATUS_SUCCESS,
  897. CYZ_BUF_CTRL_NOT_MAPPED,
  898. pDevExt->DeviceName.Length+sizeof(WCHAR),
  899. pDevExt->DeviceName.Buffer,
  900. 0,
  901. NULL
  902. );
  903. CyzDbgPrintEx(DPFLTR_WARNING_LEVEL, "Could not map Board memory BufCtrl "
  904. "for %wZ\n",&pDevExt->DeviceName);
  905. status = STATUS_NONE_MAPPED;
  906. goto ExtensionCleanup;
  907. }
  908. buf_ctrl = pDevExt->BufCtrl;
  909. pDevExt->TxBufsize = CYZ_READ_ULONG(&buf_ctrl->tx_bufsize);
  910. pDevExt->RxBufsize = CYZ_READ_ULONG(&buf_ctrl->rx_bufsize);
  911. pDevExt->TxBufaddr = MmMapIoSpace(tx_buf_phys,
  912. pDevExt->TxBufsize,
  913. FALSE);
  914. if (pDevExt->TxBufaddr == NULL) {
  915. CyzLogError(
  916. PDevObj->DriverObject,
  917. pDevExt->DeviceObject,
  918. PConfigData->PhysicalBoardMemory,
  919. CyzPhysicalZero,
  920. 0,
  921. 0,
  922. 0,
  923. PConfigData->PortIndex+1,
  924. STATUS_SUCCESS,
  925. CYZ_TX_BUF_NOT_MAPPED,
  926. pDevExt->DeviceName.Length+sizeof(WCHAR),
  927. pDevExt->DeviceName.Buffer,
  928. 0,
  929. NULL
  930. );
  931. CyzDbgPrintEx(DPFLTR_WARNING_LEVEL, "Could not map Board memory TxBuf "
  932. "for %wZ\n",&pDevExt->DeviceName);
  933. status = STATUS_NONE_MAPPED;
  934. goto ExtensionCleanup;
  935. }
  936. pDevExt->RxBufaddr = MmMapIoSpace(rx_buf_phys,
  937. pDevExt->RxBufsize,
  938. FALSE);
  939. if (pDevExt->RxBufaddr == NULL) {
  940. CyzLogError(
  941. PDevObj->DriverObject,
  942. pDevExt->DeviceObject,
  943. PConfigData->PhysicalBoardMemory,
  944. CyzPhysicalZero,
  945. 0,
  946. 0,
  947. 0,
  948. PConfigData->PortIndex+1,
  949. STATUS_SUCCESS,
  950. CYZ_RX_BUF_NOT_MAPPED,
  951. pDevExt->DeviceName.Length+sizeof(WCHAR),
  952. pDevExt->DeviceName.Buffer,
  953. 0,
  954. NULL
  955. );
  956. CyzDbgPrintEx(DPFLTR_WARNING_LEVEL, "Could not map Board memory RxBuf "
  957. "for %wZ\n",&pDevExt->DeviceName);
  958. status = STATUS_NONE_MAPPED;
  959. goto ExtensionCleanup;
  960. }
  961. pDevExt->PtZfIntQueue = MmMapIoSpace(zf_int_queue_phys,
  962. sizeof(struct INT_QUEUE),
  963. FALSE);
  964. if (pDevExt->PtZfIntQueue == NULL) {
  965. CyzLogError(
  966. PDevObj->DriverObject,
  967. pDevExt->DeviceObject,
  968. PConfigData->PhysicalBoardMemory,
  969. CyzPhysicalZero,
  970. 0,
  971. 0,
  972. 0,
  973. PConfigData->PortIndex+1,
  974. STATUS_SUCCESS,
  975. CYZ_INT_QUEUE_NOT_MAPPED,
  976. pDevExt->DeviceName.Length+sizeof(WCHAR),
  977. pDevExt->DeviceName.Buffer,
  978. 0,
  979. NULL
  980. );
  981. CyzDbgPrintEx(DPFLTR_WARNING_LEVEL, "Could not map Board memory IntQueue"
  982. " for %wZ\n",&pDevExt->DeviceName);
  983. status = STATUS_NONE_MAPPED;
  984. goto ExtensionCleanup;
  985. }
  986. if (!CyzDoesPortExist(
  987. pDevExt,
  988. &pDevExt->DeviceName
  989. )) {
  990. //
  991. // We couldn't verify that there was actually a
  992. // port. No need to log an error as the port exist
  993. // code will log exactly why.
  994. //
  995. CyzDbgPrintEx(DPFLTR_WARNING_LEVEL, "DoesPortExist test failed for "
  996. "%wZ\n", &pDevExt->DeviceName);
  997. status = STATUS_NO_SUCH_DEVICE;
  998. goto ExtensionCleanup;
  999. }
  1000. //
  1001. // Set up the default device control fields.
  1002. // Note that if the values are changed after
  1003. // the file is open, they do NOT revert back
  1004. // to the old value at file close.
  1005. //
  1006. pDevExt->SpecialChars.XonChar = CYZ_DEF_XON;
  1007. pDevExt->SpecialChars.XoffChar = CYZ_DEF_XOFF;
  1008. pDevExt->HandFlow.ControlHandShake = SERIAL_DTR_CONTROL;
  1009. pDevExt->HandFlow.FlowReplace = SERIAL_RTS_CONTROL;
  1010. //
  1011. // Default Line control protocol. 7E1
  1012. //
  1013. // Seven data bits.
  1014. // Even parity.
  1015. // 1 Stop bits.
  1016. //
  1017. pDevExt->CommParity = C_PR_EVEN;
  1018. pDevExt->CommDataLen = C_DL_CS7 | C_DL_1STOP;
  1019. pDevExt->ValidDataMask = 0x7f;
  1020. pDevExt->CurrentBaud = 1200;
  1021. //
  1022. // We set up the default xon/xoff limits.
  1023. //
  1024. // This may be a bogus value. It looks like the BufferSize
  1025. // is not set up until the device is actually opened.
  1026. //
  1027. pDevExt->HandFlow.XoffLimit = pDevExt->BufferSize >> 3;
  1028. pDevExt->HandFlow.XonLimit = pDevExt->BufferSize >> 1;
  1029. pDevExt->BufferSizePt8 = ((3*(pDevExt->BufferSize>>2))+
  1030. (pDevExt->BufferSize>>4));
  1031. CyzDbgPrintEx(CYZDIAG1, " The default interrupt read buffer size is: %d\n"
  1032. "------ The XoffLimit is : %d\n"
  1033. "------ The XonLimit is : %d\n"
  1034. "------ The pt 8 size is : %d\n",
  1035. pDevExt->BufferSize, pDevExt->HandFlow.XoffLimit,
  1036. pDevExt->HandFlow.XonLimit, pDevExt->BufferSizePt8);
  1037. pDevExt->SupportedBauds = SERIAL_BAUD_075 | SERIAL_BAUD_110 |
  1038. SERIAL_BAUD_134_5 | SERIAL_BAUD_150 | SERIAL_BAUD_300 |
  1039. SERIAL_BAUD_600 | SERIAL_BAUD_1200 | SERIAL_BAUD_1800 |
  1040. SERIAL_BAUD_2400 | SERIAL_BAUD_4800 | SERIAL_BAUD_7200 |
  1041. SERIAL_BAUD_9600 | SERIAL_BAUD_14400 | SERIAL_BAUD_19200 |
  1042. SERIAL_BAUD_38400 | SERIAL_BAUD_56K | SERIAL_BAUD_57600 |
  1043. SERIAL_BAUD_115200 | SERIAL_BAUD_128K | SERIAL_BAUD_USER;
  1044. //
  1045. // Mark this device as not being opened by anyone. We keep a
  1046. // variable around so that spurious interrupts are easily
  1047. // dismissed by the ISR.
  1048. //
  1049. pDevExt->DeviceIsOpened = FALSE;
  1050. //
  1051. // Store values into the extension for interval timing.
  1052. //
  1053. //
  1054. // If the interval timer is less than a second then come
  1055. // in with a short "polling" loop.
  1056. //
  1057. // For large (> then 2 seconds) use a 1 second poller.
  1058. //
  1059. pDevExt->ShortIntervalAmount.QuadPart = -1;
  1060. pDevExt->LongIntervalAmount.QuadPart = -10000000;
  1061. pDevExt->CutOverAmount.QuadPart = 200000000;
  1062. // Initialize for the Isr Dispatch
  1063. pDispatch = pDevExt->OurIsrContext;
  1064. #ifndef POLL
  1065. pDispatch->Extensions[pDevExt->PortIndex] = pDevExt;
  1066. pDispatch->PoweredOn[pDevExt->PortIndex] = TRUE;
  1067. #endif
  1068. if (firstTimeThisBoard) {
  1069. #ifdef POLL
  1070. ULONG intr_reg;
  1071. ULONG pollingCycle;
  1072. pollingCycle = 10; // default = 20ms
  1073. pDispatch->PollingTime.LowPart = pollingCycle * 10000;
  1074. pDispatch->PollingTime.HighPart = 0;
  1075. pDispatch->PollingTime = RtlLargeIntegerNegate(pDispatch->PollingTime);
  1076. pDispatch->PollingPeriod = pollingCycle;
  1077. KeInitializeSpinLock(&pDispatch->PollingLock);
  1078. KeInitializeTimer(&pDispatch->PollingTimer);
  1079. KeInitializeDpc(&pDispatch->PollingDpc, CyzPollingDpc, pDispatch);
  1080. KeInitializeEvent(&pDispatch->PendingDpcEvent, SynchronizationEvent, FALSE);
  1081. intr_reg = CYZ_READ_ULONG(&(pDevExt->Runtime)->intr_ctrl_stat);
  1082. //intr_reg |= (0x00030800UL);
  1083. intr_reg |= (0x00030000UL);
  1084. CYZ_WRITE_ULONG(&(pDevExt->Runtime)->intr_ctrl_stat,intr_reg);
  1085. #else
  1086. CyzResetBoard(pDevExt); //Shouldn't we put this line on the POLL version?
  1087. #endif
  1088. pDispatch->NChannels = CYZ_READ_ULONG(&(pDevExt->BoardCtrl)->n_channel);
  1089. }
  1090. #ifdef POLL
  1091. InterlockedIncrement(&pDispatch->PollingCount);
  1092. incPoll = TRUE;
  1093. #endif
  1094. //
  1095. // Common error path cleanup. If the status is
  1096. // bad, get rid of the device extension, device object
  1097. // and any memory associated with it.
  1098. //
  1099. ExtensionCleanup: ;
  1100. if (!NT_SUCCESS(status)) {
  1101. #ifdef POLL
  1102. if (incPoll) {
  1103. InterlockedDecrement(&pDispatch->PollingCount);
  1104. }
  1105. #else
  1106. if (pDispatch) {
  1107. pDispatch->Extensions[pDevExt->PortIndex] = NULL;
  1108. }
  1109. #endif
  1110. if (allocedDispatch) {
  1111. ExFreePool(pDevExt->OurIsrContext);
  1112. pDevExt->OurIsrContext = NULL;
  1113. }
  1114. if (pDevExt->Runtime) {
  1115. MmUnmapIoSpace(pDevExt->Runtime, PConfigData->RuntimeLength);
  1116. pDevExt->Runtime = NULL;
  1117. }
  1118. if (pDevExt->BoardCtrl) {
  1119. MmUnmapIoSpace(pDevExt->BoardCtrl, sizeof(struct BOARD_CTRL));
  1120. pDevExt->BoardCtrl = NULL;
  1121. }
  1122. if (pDevExt->ChCtrl) {
  1123. MmUnmapIoSpace(pDevExt->ChCtrl,sizeof(struct CH_CTRL));
  1124. pDevExt->ChCtrl = NULL;
  1125. }
  1126. if (pDevExt->BufCtrl) {
  1127. MmUnmapIoSpace(pDevExt->BufCtrl,sizeof(struct BUF_CTRL));
  1128. pDevExt->BufCtrl = NULL;
  1129. }
  1130. if (pDevExt->TxBufaddr) {
  1131. MmUnmapIoSpace(pDevExt->TxBufaddr,pDevExt->TxBufsize);
  1132. pDevExt->TxBufaddr = NULL;
  1133. }
  1134. if (pDevExt->RxBufaddr) {
  1135. MmUnmapIoSpace(pDevExt->RxBufaddr,pDevExt->RxBufsize);
  1136. pDevExt->RxBufaddr = NULL;
  1137. }
  1138. if (pDevExt->PtZfIntQueue) {
  1139. MmUnmapIoSpace(pDevExt->PtZfIntQueue,sizeof(struct INT_QUEUE));
  1140. pDevExt->PtZfIntQueue = NULL;
  1141. }
  1142. }
  1143. return status;
  1144. }
  1145. BOOLEAN
  1146. CyzDoesPortExist(
  1147. IN PCYZ_DEVICE_EXTENSION Extension,
  1148. IN PUNICODE_STRING InsertString
  1149. )
  1150. /*++
  1151. Routine Description:
  1152. This routine examines several of what might be the serial device
  1153. registers. It ensures that the bits that should be zero are zero.
  1154. In addition, this routine will determine if the device supports
  1155. fifo's. If it does it will enable the fifo's and turn on a boolean
  1156. in the extension that indicates the fifo's presence.
  1157. NOTE: If there is indeed a serial port at the address specified
  1158. it will absolutely have interrupts inhibited upon return
  1159. from this routine.
  1160. NOTE: Since this routine should be called fairly early in
  1161. the device driver initialization, the only element
  1162. that needs to be filled in is the base register address.
  1163. NOTE: These tests all assume that this code is the only
  1164. code that is looking at these ports or this memory.
  1165. This is a not to unreasonable assumption even on
  1166. multiprocessor systems.
  1167. Arguments:
  1168. Extension - A pointer to a serial device extension.
  1169. InsertString - String to place in an error log entry.
  1170. Return Value:
  1171. Will return true if the port really exists, otherwise it
  1172. will return false.
  1173. --*/
  1174. {
  1175. return TRUE;
  1176. }
  1177. VOID
  1178. CyzResetBoard( PCYZ_DEVICE_EXTENSION Extension )
  1179. /*++
  1180. Routine Description:
  1181. This routine examines several of what might be the serial device
  1182. registers. It ensures that the bits that should be zero are zero.
  1183. In addition, this routine will determine if the device supports
  1184. fifo's. If it does it will enable the fifo's and turn on a boolean
  1185. in the extension that indicates the fifo's presence.
  1186. NOTE: If there is indeed a serial port at the address specified
  1187. it will absolutely have interrupts inhibited upon return
  1188. from this routine.
  1189. NOTE: Since this routine should be called fairly early in
  1190. the device driver initialization, the only element
  1191. that needs to be filled in is the base register address.
  1192. NOTE: These tests all assume that this code is the only
  1193. code that is looking at these ports or this memory.
  1194. This is a not to unreasonable assumption even on
  1195. multiprocessor systems.
  1196. Arguments:
  1197. Extension - A pointer to a serial device extension.
  1198. InsertString - String to place in an error log entry.
  1199. Return Value:
  1200. Will return true if the port really exists, otherwise it
  1201. will return false.
  1202. --*/
  1203. {
  1204. #ifndef POLL
  1205. //CyzIssueCmd(Extension,C_CM_SETNNDT,20L,FALSE); Removed. Let's firmware calculate NNDT.
  1206. #endif
  1207. //CyzIssueCmd(Extension,C_CM_RESET,0L,FALSE); // Added in 1.0.0.11
  1208. }
  1209. BOOLEAN
  1210. CyzReset(
  1211. IN PVOID Context
  1212. )
  1213. /*--------------------------------------------------------------------------
  1214. CyzReset()
  1215. Routine Description: This places the hardware in a standard
  1216. configuration. This assumes that it is called at interrupt level.
  1217. Arguments:
  1218. Context - The device extension for serial device being managed.
  1219. Return Value: Always FALSE.
  1220. --------------------------------------------------------------------------*/
  1221. {
  1222. PCYZ_DEVICE_EXTENSION extension = Context;
  1223. struct CH_CTRL *ch_ctrl = extension->ChCtrl;
  1224. struct BUF_CTRL *buf_ctrl = extension->BufCtrl;
  1225. CYZ_IOCTL_BAUD s;
  1226. //For interrupt mode: extension->RxFifoTriggerUsed = FALSE; (from cyyport)
  1227. // set the line control, modem control, and the baud to what they should be.
  1228. CyzSetLineControl(extension);
  1229. CyzSetupNewHandFlow(extension,&extension->HandFlow);
  1230. CyzHandleModemUpdate(extension,FALSE,0);
  1231. s.Extension = extension;
  1232. s.Baud = extension->CurrentBaud;
  1233. CyzSetBaud(&s);
  1234. //This flag is configurable from the Advanced Port Settings.
  1235. //extension->ReturnStatusAfterFwEmpty = TRUE; // We will loose performance, but it will be
  1236. // // closer to serial driver.
  1237. extension->ReturnWriteStatus = FALSE;
  1238. extension->CmdFailureLog = TRUE;
  1239. // Enable port
  1240. CYZ_WRITE_ULONG(&ch_ctrl->op_mode,C_CH_ENABLE);
  1241. #ifdef POLL
  1242. CYZ_WRITE_ULONG(&ch_ctrl->intr_enable,C_IN_MDCD | C_IN_MCTS | C_IN_MRI
  1243. | C_IN_MDSR | C_IN_RXBRK | C_IN_PR_ERROR
  1244. | C_IN_FR_ERROR | C_IN_OVR_ERROR | C_IN_RXOFL
  1245. | C_IN_IOCTLW | C_IN_TXFEMPTY);
  1246. #else
  1247. //CYZ_WRITE_ULONG(&buf_ctrl->rx_threshold,1024);
  1248. CYZ_WRITE_ULONG(&ch_ctrl->intr_enable,C_IN_MDCD | C_IN_MCTS | C_IN_MRI
  1249. | C_IN_MDSR | C_IN_RXBRK | C_IN_PR_ERROR
  1250. | C_IN_FR_ERROR | C_IN_OVR_ERROR | C_IN_RXOFL
  1251. | C_IN_IOCTLW | C_IN_TXBEMPTY //1.0.0.11: C_IN_TXBEMPTY OR C_IN_TXFEMPTY?
  1252. | C_IN_RXHIWM | C_IN_RXNNDT | C_IN_TXLOWWM);
  1253. #endif
  1254. //ToDo: Enable C_IN_IOCTLW in the interrupt version.
  1255. CyzIssueCmd(extension,C_CM_IOCTLW,0L,FALSE);
  1256. extension->HoldingEmpty = TRUE;
  1257. return FALSE;
  1258. }
  1259. VOID
  1260. CyzUnload(
  1261. IN PDRIVER_OBJECT DriverObject
  1262. )
  1263. /*--------------------------------------------------------------------------
  1264. CyzUnload()
  1265. Description: Cleans up all of the memory associated with the
  1266. Device Objects created by the driver.
  1267. Arguments:
  1268. DriverObject - A pointer to the driver object.
  1269. Return Value: None.
  1270. --------------------------------------------------------------------------*/
  1271. {
  1272. PVOID lockPtr;
  1273. PAGED_CODE();
  1274. lockPtr = MmLockPagableCodeSection(CyzUnload);
  1275. //
  1276. // Unnecessary since our BSS is going away, but do it anyhow to be safe
  1277. //
  1278. CyzGlobals.PAGESER_Handle = NULL;
  1279. if (CyzGlobals.RegistryPath.Buffer != NULL) {
  1280. ExFreePool(CyzGlobals.RegistryPath.Buffer);
  1281. CyzGlobals.RegistryPath.Buffer = NULL;
  1282. }
  1283. #if DBG
  1284. SerialLogFree();
  1285. #endif
  1286. CyzDbgPrintEx(CYZDIAG3, "In CyzUnload\n");
  1287. MmUnlockPagableImageSection(lockPtr);
  1288. }
  1289. CYZ_MEM_COMPARES
  1290. CyzMemCompare(
  1291. IN PHYSICAL_ADDRESS A,
  1292. IN ULONG SpanOfA,
  1293. IN PHYSICAL_ADDRESS B,
  1294. IN ULONG SpanOfB
  1295. )
  1296. /*++
  1297. Routine Description:
  1298. Compare two phsical address.
  1299. Arguments:
  1300. A - One half of the comparison.
  1301. SpanOfA - In units of bytes, the span of A.
  1302. B - One half of the comparison.
  1303. SpanOfB - In units of bytes, the span of B.
  1304. Return Value:
  1305. The result of the comparison.
  1306. --*/
  1307. {
  1308. LARGE_INTEGER a;
  1309. LARGE_INTEGER b;
  1310. LARGE_INTEGER lower;
  1311. ULONG lowerSpan;
  1312. LARGE_INTEGER higher;
  1313. //PAGED_CODE(); Non paged because it can be called during CyzLogError, which is non paged now.
  1314. a = A;
  1315. b = B;
  1316. if (a.QuadPart == b.QuadPart) {
  1317. return AddressesAreEqual;
  1318. }
  1319. if (a.QuadPart > b.QuadPart) {
  1320. higher = a;
  1321. lower = b;
  1322. lowerSpan = SpanOfB;
  1323. } else {
  1324. higher = b;
  1325. lower = a;
  1326. lowerSpan = SpanOfA;
  1327. }
  1328. if ((higher.QuadPart - lower.QuadPart) >= lowerSpan) {
  1329. return AddressesAreDisjoint;
  1330. }
  1331. return AddressesOverlap;
  1332. }
  1333. NTSTATUS
  1334. CyzFindInitController(IN PDEVICE_OBJECT PDevObj, IN PCONFIG_DATA PConfig)
  1335. /*++
  1336. Routine Description:
  1337. This function discovers what type of controller is responsible for
  1338. the given port and initializes the controller and port.
  1339. Arguments:
  1340. PDevObj - Pointer to the devobj for the port we are about to init.
  1341. PConfig - Pointer to configuration data for the port we are about to init.
  1342. Return Value:
  1343. STATUS_SUCCESS on success, appropriate error value on failure.
  1344. --*/
  1345. {
  1346. PCYZ_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  1347. PDEVICE_OBJECT pDeviceObject;
  1348. PCYZ_DEVICE_EXTENSION pExtension;
  1349. PHYSICAL_ADDRESS serialPhysicalMax;
  1350. PLIST_ENTRY pCurDevObj;
  1351. NTSTATUS status;
  1352. KIRQL oldIrql;
  1353. CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, ">CyzFindInitController(%X, %X)\n",
  1354. PDevObj, PConfig);
  1355. serialPhysicalMax.LowPart = (ULONG)~0;
  1356. serialPhysicalMax.HighPart = ~0;
  1357. #ifdef POLL
  1358. CyzDbgPrintEx(CYZDIAG1, "Attempting to init %wZ\n"
  1359. "------- Runtime Memory is %x\n"
  1360. "------- Board Memory is %x\n"
  1361. "------- BusNumber is %d\n"
  1362. "------- BusType is %d\n"
  1363. "------- Runtime AddressSpace is %d\n"
  1364. "------- Board AddressSpace is %d\n",
  1365. &pDevExt->DeviceName,
  1366. PConfig->PhysicalRuntime.LowPart,
  1367. PConfig->PhysicalBoardMemory.LowPart,
  1368. PConfig->BusNumber,
  1369. PConfig->InterfaceType,
  1370. PConfig->RuntimeAddressSpace,
  1371. PConfig->BoardMemoryAddressSpace);
  1372. #else
  1373. CyzDbgPrintEx(CYZDIAG1, "Attempting to init %wZ\n"
  1374. "------- Runtime Memory is %x\n"
  1375. "------- Board Memory is %x\n"
  1376. "------- BusNumber is %d\n"
  1377. "------- BusType is %d\n"
  1378. "------- Runtime AddressSpace is %d\n"
  1379. "------- Board AddressSpace is %d\n"
  1380. "------- Interrupt Mode is %d\n",
  1381. &pDevExt->DeviceName,
  1382. PConfig->PhysicalRuntime.LowPart,
  1383. PConfig->PhysicalBoardMemory.LowPart,
  1384. PConfig->BusNumber,
  1385. PConfig->InterfaceType,
  1386. PConfig->RuntimeAddressSpace,
  1387. PConfig->BoardMemoryAddressSpace,
  1388. PConfig->InterruptMode);
  1389. #endif
  1390. //
  1391. // We don't support any boards whose memory wraps around
  1392. // the physical address space.
  1393. //
  1394. //*****************************************************
  1395. // error injection
  1396. // if (CyzMemCompare(
  1397. // PConfig->PhysicalRuntime,
  1398. // PConfig->RuntimeLength,
  1399. // serialPhysicalMax,
  1400. // (ULONG)0
  1401. // ) == AddressesAreDisjoint)
  1402. //*****************************************************
  1403. if (CyzMemCompare(
  1404. PConfig->PhysicalRuntime,
  1405. PConfig->RuntimeLength,
  1406. serialPhysicalMax,
  1407. (ULONG)0
  1408. ) != AddressesAreDisjoint) {
  1409. CyzLogError(
  1410. PDevObj->DriverObject,
  1411. NULL,
  1412. PConfig->PhysicalBoardMemory,
  1413. CyzPhysicalZero,
  1414. 0,
  1415. 0,
  1416. 0,
  1417. PConfig->PortIndex+1,
  1418. STATUS_SUCCESS,
  1419. CYZ_RUNTIME_MEMORY_TOO_HIGH,
  1420. pDevExt->DeviceName.Length+sizeof(WCHAR),
  1421. pDevExt->DeviceName.Buffer,
  1422. 0,
  1423. NULL
  1424. );
  1425. CyzDbgPrintEx(DPFLTR_WARNING_LEVEL, "Error in config record for %wZ\n"
  1426. "------ Runtime memory wraps around physical memory\n",
  1427. &pDevExt->DeviceName);
  1428. return STATUS_NO_SUCH_DEVICE;
  1429. }
  1430. //*****************************************************
  1431. // error injection
  1432. // if (CyzMemCompare(
  1433. // PConfig->PhysicalBoardMemory,
  1434. // PConfig->BoardMemoryLength,
  1435. // serialPhysicalMax,
  1436. // (ULONG)0
  1437. // ) == AddressesAreDisjoint)
  1438. //*****************************************************
  1439. if (CyzMemCompare(
  1440. PConfig->PhysicalBoardMemory,
  1441. PConfig->BoardMemoryLength,
  1442. serialPhysicalMax,
  1443. (ULONG)0
  1444. ) != AddressesAreDisjoint) {
  1445. CyzLogError(
  1446. PDevObj->DriverObject,
  1447. NULL,
  1448. PConfig->PhysicalBoardMemory,
  1449. CyzPhysicalZero,
  1450. 0,
  1451. 0,
  1452. 0,
  1453. PConfig->PortIndex+1,
  1454. STATUS_SUCCESS,
  1455. CYZ_BOARD_MEMORY_TOO_HIGH,
  1456. pDevExt->DeviceName.Length+sizeof(WCHAR),
  1457. pDevExt->DeviceName.Buffer,
  1458. 0,
  1459. NULL
  1460. );
  1461. CyzDbgPrintEx(DPFLTR_WARNING_LEVEL, "Error in config record for %wZ\n"
  1462. "------ board memory wraps around physical memory\n",
  1463. &pDevExt->DeviceName);
  1464. return STATUS_NO_SUCH_DEVICE;
  1465. }
  1466. //
  1467. // Make sure that the Runtime memory addresses don't
  1468. // overlap the DP memory addresses for PCI cards
  1469. //
  1470. if (CyzMemCompare(
  1471. PConfig->PhysicalRuntime,
  1472. PConfig->RuntimeLength,
  1473. CyzPhysicalZero,
  1474. (ULONG)0
  1475. ) != AddressesAreEqual) {
  1476. //*****************************************************
  1477. // error injection
  1478. // if (CyzMemCompare(
  1479. // PConfig->PhysicalRuntime,
  1480. // PConfig->RuntimeLength,
  1481. // PConfig->PhysicalBoardMemory,
  1482. // PConfig->BoardMemoryLength
  1483. // ) == AddressesAreDisjoint)
  1484. //*****************************************************
  1485. if (CyzMemCompare(
  1486. PConfig->PhysicalRuntime,
  1487. PConfig->RuntimeLength,
  1488. PConfig->PhysicalBoardMemory,
  1489. PConfig->BoardMemoryLength
  1490. ) != AddressesAreDisjoint) {
  1491. CyzLogError(
  1492. PDevObj->DriverObject,
  1493. NULL,
  1494. PConfig->PhysicalBoardMemory,
  1495. PConfig->PhysicalRuntime,
  1496. 0,
  1497. 0,
  1498. 0,
  1499. PConfig->PortIndex+1,
  1500. STATUS_SUCCESS,
  1501. CYZ_BOTH_MEMORY_CONFLICT,
  1502. pDevExt->DeviceName.Length+sizeof(WCHAR),
  1503. pDevExt->DeviceName.Buffer,
  1504. 0,
  1505. NULL
  1506. );
  1507. CyzDbgPrintEx(DPFLTR_WARNING_LEVEL, "Error in config record for %wZ\n"
  1508. "------ Runtime memory wraps around Board memory\n",
  1509. &pDevExt->DeviceName);
  1510. return STATUS_NO_SUCH_DEVICE;
  1511. }
  1512. }
  1513. //
  1514. // Now, we will check if this is a port on a multiport card.
  1515. // The conditions are same BoardMemory set and same IRQL/Vector
  1516. //
  1517. //
  1518. // Loop through all previously attached devices
  1519. //
  1520. KeAcquireSpinLock(&CyzGlobals.GlobalsSpinLock, &oldIrql);
  1521. if (!IsListEmpty(&CyzGlobals.AllDevObjs)) {
  1522. pCurDevObj = CyzGlobals.AllDevObjs.Flink;
  1523. pExtension = CONTAINING_RECORD(pCurDevObj, CYZ_DEVICE_EXTENSION,
  1524. AllDevObjs);
  1525. } else {
  1526. pCurDevObj = NULL;
  1527. pExtension = NULL;
  1528. }
  1529. KeReleaseSpinLock(&CyzGlobals.GlobalsSpinLock, oldIrql);
  1530. //
  1531. // If there is an interrupt status then we
  1532. // loop through the config list again to look
  1533. // for a config record with the same interrupt
  1534. // status (on the same bus).
  1535. //
  1536. if (pCurDevObj != NULL) {
  1537. ASSERT(pExtension != NULL);
  1538. //
  1539. // We have an interrupt status. Loop through all
  1540. // previous records, look for an existing interrupt status
  1541. // the same as the current interrupt status.
  1542. //
  1543. do {
  1544. //
  1545. // We only care about this list if the elements are on the
  1546. // same bus as this new entry. (Their interrupts must therefore
  1547. // also be the on the same bus. We will check that momentarily).
  1548. //
  1549. // We don't check here for the dissimilar interrupts since that
  1550. // could cause us to miss the error of having the same interrupt
  1551. // status but different interrupts - which is bizzare.
  1552. //
  1553. if ((pExtension->InterfaceType == PConfig->InterfaceType) &&
  1554. (pExtension->BoardMemoryAddressSpace == PConfig->BoardMemoryAddressSpace) &&
  1555. (pExtension->BusNumber == PConfig->BusNumber)) {
  1556. //
  1557. // If the board memory is the same, then same card.
  1558. //
  1559. if (CyzMemCompare(
  1560. pExtension->OriginalBoardMemory,
  1561. pExtension->BoardMemoryLength,
  1562. PConfig->PhysicalBoardMemory,
  1563. PConfig->BoardMemoryLength
  1564. ) == AddressesAreEqual) {
  1565. #ifndef POLL
  1566. //
  1567. // Same card. Now make sure that they
  1568. // are using the same interrupt parameters.
  1569. //
  1570. // BUILD 2128: OriginalIrql replaced by TrIrql and Irql; same for OriginalVector
  1571. if ((PConfig->TrIrql != pExtension->Irql) ||
  1572. (PConfig->TrVector != pExtension->Vector)) {
  1573. //
  1574. // We won't put this into the configuration
  1575. // list.
  1576. //
  1577. CyzLogError(
  1578. PDevObj->DriverObject,
  1579. NULL,
  1580. PConfig->PhysicalBoardMemory,
  1581. pExtension->OriginalBoardMemory,
  1582. 0,
  1583. 0,
  1584. 0,
  1585. PConfig->PortIndex+1,
  1586. STATUS_SUCCESS,
  1587. CYZ_MULTI_INTERRUPT_CONFLICT,
  1588. pDevExt->DeviceName.Length+sizeof(WCHAR),
  1589. pDevExt->DeviceName.Buffer,
  1590. pExtension->DeviceName.Length
  1591. + sizeof(WCHAR),
  1592. pExtension->DeviceName.Buffer
  1593. );
  1594. CyzDbgPrintEx(DPFLTR_WARNING_LEVEL, "Configuration error "
  1595. "for %wZ\n"
  1596. "------- Same multiport - different "
  1597. "interrupts\n", &pDevExt->DeviceName);
  1598. return STATUS_NO_SUCH_DEVICE;
  1599. }
  1600. #endif
  1601. //
  1602. // PCI board. Make sure the PCI memory addresses are equal.
  1603. //
  1604. if (CyzMemCompare(
  1605. pExtension->OriginalRuntimeMemory,
  1606. pExtension->RuntimeLength,
  1607. PConfig->PhysicalRuntime,
  1608. PConfig->RuntimeLength
  1609. ) != AddressesAreEqual) {
  1610. //*****************************************************
  1611. // error injection
  1612. // if (CyzMemCompare(
  1613. // pExtension->OriginalRuntimeMemory,
  1614. // pExtension->RuntimeLength,
  1615. // PConfig->PhysicalRuntime,
  1616. // PConfig->RuntimeLength
  1617. // ) == AddressesAreEqual)
  1618. //*****************************************************
  1619. CyzLogError(
  1620. PDevObj->DriverObject,
  1621. NULL,
  1622. PConfig->PhysicalRuntime,
  1623. pExtension->OriginalRuntimeMemory,
  1624. 0,
  1625. 0,
  1626. 0,
  1627. PConfig->PortIndex+1,
  1628. STATUS_SUCCESS,
  1629. CYZ_MULTI_RUNTIME_CONFLICT,
  1630. pDevExt->DeviceName.Length+sizeof(WCHAR),
  1631. pDevExt->DeviceName.Buffer,
  1632. pExtension->DeviceName.Length
  1633. + sizeof(WCHAR),
  1634. pExtension->DeviceName.Buffer
  1635. );
  1636. CyzDbgPrintEx(DPFLTR_WARNING_LEVEL, "Configuration error "
  1637. "for %wZ\n"
  1638. "------- Same multiport - different "
  1639. "Runtime addresses\n", &pDevExt->DeviceName);
  1640. return STATUS_NO_SUCH_DEVICE;
  1641. }
  1642. //
  1643. // We should never get this far on a restart since we don't
  1644. // support stop on ISA multiport devices!
  1645. //
  1646. ASSERT(pDevExt->PNPState == CYZ_PNP_ADDED);
  1647. //
  1648. //
  1649. // Initialize the device as part of a multiport board
  1650. //
  1651. CyzDbgPrintEx(CYZDIAG1, "Aha! It is a multiport node\n");
  1652. CyzDbgPrintEx(CYZDIAG1, "Matched to %x\n", pExtension);
  1653. status = CyzInitMultiPort(pExtension, PConfig, PDevObj);
  1654. //
  1655. // A port can be one of two things:
  1656. // A non-root on a multiport
  1657. // A root on a multiport
  1658. //
  1659. // It can only share an interrupt if it is a root.
  1660. // Since this was a non-root we don't need to check
  1661. // if it shares an interrupt and we can return.
  1662. //
  1663. return status;
  1664. }
  1665. }
  1666. //
  1667. // No match, check some more
  1668. //
  1669. KeAcquireSpinLock(&CyzGlobals.GlobalsSpinLock, &oldIrql);
  1670. pCurDevObj = pCurDevObj->Flink;
  1671. if (pCurDevObj != NULL) {
  1672. pExtension = CONTAINING_RECORD(pCurDevObj,CYZ_DEVICE_EXTENSION,
  1673. AllDevObjs);
  1674. }
  1675. KeReleaseSpinLock(&CyzGlobals.GlobalsSpinLock, oldIrql);
  1676. } while (pCurDevObj != NULL && pCurDevObj != &CyzGlobals.AllDevObjs);
  1677. }
  1678. CyzDbgPrintEx(CYZDIAG1, "Aha! It is a first multi\n");
  1679. status = CyzInitController(PDevObj, PConfig);
  1680. if (!NT_SUCCESS(status)) {
  1681. return status;
  1682. }
  1683. return STATUS_SUCCESS;
  1684. }
  1685. VOID
  1686. CyzCommError(
  1687. IN PKDPC Dpc,
  1688. IN PVOID DeferredContext,
  1689. IN PVOID SystemContext1,
  1690. IN PVOID SystemContext2
  1691. )
  1692. /*--------------------------------------------------------------------------
  1693. CyzComError()
  1694. Routine Description: This routine is invoked at dpc level in response
  1695. to a comm error. All comm errors kill all read and writes
  1696. Arguments:
  1697. Dpc - Not Used.
  1698. DeferredContext - points to the device object.
  1699. SystemContext1 - Not Used.
  1700. SystemContext2 - Not Used.
  1701. Return Value: None.
  1702. --------------------------------------------------------------------------*/
  1703. {
  1704. PCYZ_DEVICE_EXTENSION Extension = DeferredContext;
  1705. UNREFERENCED_PARAMETER(SystemContext1);
  1706. UNREFERENCED_PARAMETER(SystemContext2);
  1707. CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, ">CyzCommError(%X)\n", Extension);
  1708. CyzKillAllReadsOrWrites(
  1709. Extension->DeviceObject,
  1710. &Extension->WriteQueue,
  1711. &Extension->CurrentWriteIrp
  1712. );
  1713. CyzKillAllReadsOrWrites(
  1714. Extension->DeviceObject,
  1715. &Extension->ReadQueue,
  1716. &Extension->CurrentReadIrp
  1717. );
  1718. CyzDpcEpilogue(Extension, Dpc);
  1719. CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, "<CyzCommError\n");
  1720. }