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.

1839 lines
53 KiB

  1. /*--------------------------------------------------------------------------
  2. *
  3. * Copyright (C) Cyclades Corporation, 1996-2001.
  4. * All rights reserved.
  5. *
  6. * Cyclom-Y Port Driver
  7. *
  8. * This file: cyyinit.c
  9. *
  10. * Description: This module contains the code related to initialization
  11. * and unload operations in the Cyclom-Y 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. #include "precomp.h"
  29. //
  30. // This is the actual definition of CyyDebugLevel.
  31. // Note that it is only defined if this is a "debug"
  32. // build.
  33. //
  34. #if DBG
  35. extern ULONG CyyDebugLevel = CYYDBGALL;
  36. #endif
  37. //
  38. // All our global variables except DebugLevel stashed in one
  39. // little package
  40. //
  41. CYY_GLOBALS CyyGlobals;
  42. static const PHYSICAL_ADDRESS CyyPhysicalZero = {0};
  43. //
  44. // We use this to query into the registry as to whether we
  45. // should break at driver entry.
  46. //
  47. CYY_REGISTRY_DATA driverDefaults;
  48. //
  49. // INIT - only needed during init and then can be disposed
  50. // PAGESRP0 - always paged / never locked
  51. // PAGESER - must be locked when a device is open, else paged
  52. //
  53. //
  54. // INIT is used for DriverEntry() specific code
  55. //
  56. // PAGESRP0 is used for code that is not often called and has nothing
  57. // to do with I/O performance. An example, IRP_MJ_PNP/IRP_MN_START_DEVICE
  58. // support functions
  59. //
  60. // PAGESER is used for code that needs to be locked after an open for both
  61. // performance and IRQL reasons.
  62. //
  63. #ifdef ALLOC_PRAGMA
  64. #pragma alloc_text(INIT,DriverEntry)
  65. #pragma alloc_text(PAGESRP0, CyyRemoveDevObj)
  66. #pragma alloc_text(PAGESRP0, CyyUnload)
  67. //
  68. // PAGESER handled is keyed off of CyyReset, so CyyReset
  69. // must remain in PAGESER for things to work properly
  70. //
  71. #pragma alloc_text(PAGESER, CyyReset)
  72. #pragma alloc_text(PAGESER, CyyCommError)
  73. #endif
  74. NTSTATUS
  75. DriverEntry(
  76. IN PDRIVER_OBJECT DriverObject,
  77. IN PUNICODE_STRING RegistryPath
  78. )
  79. /*--------------------------------------------------------------------------
  80. The entry point that the system point calls to initialize
  81. any driver.
  82. This routine will gather the configuration information,
  83. report resource usage, attempt to initialize all serial
  84. devices, connect to interrupts for ports. If the above
  85. goes reasonably well it will fill in the dispatch points,
  86. reset the serial devices and then return to the system.
  87. Arguments:
  88. DriverObject - Just what it says, really of little use
  89. to the driver itself, it is something that the IO system
  90. cares more about.
  91. PathToRegistry - points to the entry for this driver
  92. in the current control set of the registry.
  93. Return Value:
  94. Always STATUS_SUCCESS
  95. --------------------------------------------------------------------------*/
  96. {
  97. //
  98. // Lock the paged code in their frames
  99. //
  100. PVOID lockPtr = MmLockPagableCodeSection(CyyReset);
  101. PAGED_CODE();
  102. ASSERT(CyyGlobals.PAGESER_Handle == NULL);
  103. #if DBG
  104. CyyGlobals.PAGESER_Count = 0;
  105. SerialLogInit();
  106. #endif
  107. CyyGlobals.PAGESER_Handle = lockPtr;
  108. CyyGlobals.RegistryPath.MaximumLength = RegistryPath->MaximumLength;
  109. CyyGlobals.RegistryPath.Length = RegistryPath->Length;
  110. CyyGlobals.RegistryPath.Buffer
  111. = ExAllocatePool(PagedPool, CyyGlobals.RegistryPath.MaximumLength);
  112. if (CyyGlobals.RegistryPath.Buffer == NULL) {
  113. MmUnlockPagableImageSection(lockPtr);
  114. return STATUS_INSUFFICIENT_RESOURCES;
  115. }
  116. RtlZeroMemory(CyyGlobals.RegistryPath.Buffer,
  117. CyyGlobals.RegistryPath.MaximumLength);
  118. RtlMoveMemory(CyyGlobals.RegistryPath.Buffer,
  119. RegistryPath->Buffer, RegistryPath->Length);
  120. KeInitializeSpinLock(&CyyGlobals.GlobalsSpinLock);
  121. //
  122. // Initialize all our globals
  123. //
  124. InitializeListHead(&CyyGlobals.AllDevObjs);
  125. //
  126. // Call to find out default values to use for all the devices that the
  127. // driver controls, including whether or not to break on entry.
  128. //
  129. CyyGetConfigDefaults(&driverDefaults, RegistryPath);
  130. #if DBG
  131. //
  132. // Set global debug output level
  133. //
  134. CyyDebugLevel = driverDefaults.DebugLevel;
  135. #endif
  136. //
  137. // Break on entry if requested via registry
  138. //
  139. if (driverDefaults.ShouldBreakOnEntry) {
  140. DbgBreakPoint();
  141. }
  142. //
  143. // Just dump out how big the extension is.
  144. //
  145. CyyDbgPrintEx(DPFLTR_INFO_LEVEL, "The number of bytes in the extension "
  146. "is: %d\n", sizeof(CYY_DEVICE_EXTENSION));
  147. //
  148. // Initialize the Driver Object with driver's entry points
  149. //
  150. DriverObject->DriverUnload = CyyUnload;
  151. DriverObject->DriverExtension->AddDevice = CyyAddDevice;
  152. DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = CyyFlush;
  153. DriverObject->MajorFunction[IRP_MJ_WRITE] = CyyWrite;
  154. DriverObject->MajorFunction[IRP_MJ_READ] = CyyRead;
  155. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = CyyIoControl;
  156. DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL]
  157. = CyyInternalIoControl;
  158. DriverObject->MajorFunction[IRP_MJ_CREATE] = CyyCreateOpen;
  159. DriverObject->MajorFunction[IRP_MJ_CLOSE] = CyyClose;
  160. DriverObject->MajorFunction[IRP_MJ_CLEANUP] = CyyCleanup;
  161. DriverObject->MajorFunction[IRP_MJ_PNP] = CyyPnpDispatch;
  162. DriverObject->MajorFunction[IRP_MJ_POWER] = CyyPowerDispatch;
  163. DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION]
  164. = CyyQueryInformationFile;
  165. DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION]
  166. = CyySetInformationFile;
  167. DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL]
  168. = CyySystemControlDispatch;
  169. //
  170. // Unlock pageable text
  171. //
  172. MmUnlockPagableImageSection(lockPtr);
  173. return STATUS_SUCCESS;
  174. }
  175. BOOLEAN
  176. CyyCleanLists(IN PVOID Context)
  177. /*++
  178. Routine Description:
  179. Removes a device object from any of the serial linked lists it may
  180. appear on.
  181. Arguments:
  182. Context - Actually a PCYY_DEVICE_EXTENSION (for the devobj being
  183. removed).
  184. Return Value:
  185. Always TRUE
  186. --*/
  187. {
  188. PCYY_DEVICE_EXTENSION pDevExt = (PCYY_DEVICE_EXTENSION)Context;
  189. PCYY_DISPATCH pDispatch;
  190. ULONG i;
  191. //
  192. // Remove our entry from the dispatch context
  193. //
  194. pDispatch = (PCYY_DISPATCH)pDevExt->OurIsrContext;
  195. CyyDbgPrintEx(CYYPNPPOWER, "CLEAN: removing multiport isr "
  196. "ext\n");
  197. pDispatch->Extensions[pDevExt->PortIndex] = NULL;
  198. for (i = 0; i < CYY_MAX_PORTS; i++) {
  199. if (((PCYY_DISPATCH)pDevExt->OurIsrContext)
  200. ->Extensions[i] != NULL) {
  201. break;
  202. }
  203. }
  204. if (i < CYY_MAX_PORTS) {
  205. // Others are chained on this interrupt, so we don't want to
  206. // disconnect it.
  207. pDevExt->Interrupt = NULL;
  208. }
  209. return TRUE;
  210. }
  211. VOID
  212. CyyReleaseResources(IN PCYY_DEVICE_EXTENSION PDevExt)
  213. /*++
  214. Routine Description:
  215. Releases resources (not pool) stored in the device extension.
  216. Arguments:
  217. PDevExt - Pointer to the device extension to release resources from.
  218. Return Value:
  219. VOID
  220. --*/
  221. {
  222. KIRQL oldIrql;
  223. CyyDbgPrintEx(DPFLTR_TRACE_LEVEL, ">CyyReleaseResources(%X)\n",
  224. PDevExt);
  225. //
  226. // AllDevObjs should never be empty since we have a sentinal
  227. // Note: serial removes device from AllDevObjs list after calling
  228. // SerialCleanLists. We do it before to make sure no other port will
  229. // be added to share the polling routine or PDevExt->Interrut that is
  230. // on the way to be disconnected.
  231. //
  232. KeAcquireSpinLock(&CyyGlobals.GlobalsSpinLock, &oldIrql);
  233. ASSERT(!IsListEmpty(&PDevExt->AllDevObjs));
  234. RemoveEntryList(&PDevExt->AllDevObjs);
  235. KeReleaseSpinLock(&CyyGlobals.GlobalsSpinLock, oldIrql);
  236. InitializeListHead(&PDevExt->AllDevObjs);
  237. //
  238. // Remove us from any lists we may be on
  239. //
  240. KeSynchronizeExecution(PDevExt->Interrupt, CyyCleanLists, PDevExt);
  241. //
  242. // Stop servicing interrupts if we are the last device
  243. //
  244. if (PDevExt->Interrupt != NULL) {
  245. // Disable interrupts in the PLX
  246. if (PDevExt->IsPci) {
  247. UCHAR plx_ver;
  248. ULONG value;
  249. plx_ver = CYY_READ_PCI_TYPE(PDevExt->BoardMemory);
  250. plx_ver &= 0x0f;
  251. switch(plx_ver) {
  252. case CYY_PLX9050:
  253. value = PLX9050_READ_INTERRUPT_CONTROL(PDevExt->Runtime);
  254. value &= ~PLX9050_INT_ENABLE;
  255. PLX9050_WRITE_INTERRUPT_CONTROL(PDevExt->Runtime,value);
  256. break;
  257. case CYY_PLX9060:
  258. case CYY_PLX9080:
  259. default:
  260. value = PLX9060_READ_INTERRUPT_CONTROL(PDevExt->Runtime);
  261. value &= ~PLX9060_INT_ENABLE;
  262. PLX9060_WRITE_INTERRUPT_CONTROL(PDevExt->Runtime,value);
  263. break;
  264. }
  265. }
  266. CyyDbgPrintEx(CYYPNPPOWER, "Release - disconnecting interrupt %X\n",
  267. PDevExt->Interrupt);
  268. IoDisconnectInterrupt(PDevExt->Interrupt);
  269. PDevExt->Interrupt = NULL;
  270. // If we are the last device, free this memory
  271. CyyDbgPrintEx(CYYPNPPOWER, "Release - freeing multi context\n");
  272. if (PDevExt->OurIsrContext != NULL) { // added in DDK build 2072, but
  273. ExFreePool(PDevExt->OurIsrContext); // we already had the free of OurIsrContext.
  274. PDevExt->OurIsrContext = NULL; //
  275. }
  276. }
  277. //
  278. // Stop handling timers
  279. //
  280. CyyCancelTimer(&PDevExt->ReadRequestTotalTimer, PDevExt);
  281. CyyCancelTimer(&PDevExt->ReadRequestIntervalTimer, PDevExt);
  282. CyyCancelTimer(&PDevExt->WriteRequestTotalTimer, PDevExt);
  283. CyyCancelTimer(&PDevExt->ImmediateTotalTimer, PDevExt);
  284. CyyCancelTimer(&PDevExt->XoffCountTimer, PDevExt);
  285. CyyCancelTimer(&PDevExt->LowerRTSTimer, PDevExt);
  286. //
  287. // Stop servicing DPC's
  288. //
  289. CyyRemoveQueueDpc(&PDevExt->CompleteWriteDpc, PDevExt);
  290. CyyRemoveQueueDpc(&PDevExt->CompleteReadDpc, PDevExt);
  291. CyyRemoveQueueDpc(&PDevExt->TotalReadTimeoutDpc, PDevExt);
  292. CyyRemoveQueueDpc(&PDevExt->IntervalReadTimeoutDpc, PDevExt);
  293. CyyRemoveQueueDpc(&PDevExt->TotalWriteTimeoutDpc, PDevExt);
  294. CyyRemoveQueueDpc(&PDevExt->CommErrorDpc, PDevExt);
  295. CyyRemoveQueueDpc(&PDevExt->CompleteImmediateDpc, PDevExt);
  296. CyyRemoveQueueDpc(&PDevExt->TotalImmediateTimeoutDpc, PDevExt);
  297. CyyRemoveQueueDpc(&PDevExt->CommWaitDpc, PDevExt);
  298. CyyRemoveQueueDpc(&PDevExt->XoffCountTimeoutDpc, PDevExt);
  299. CyyRemoveQueueDpc(&PDevExt->XoffCountCompleteDpc, PDevExt);
  300. CyyRemoveQueueDpc(&PDevExt->StartTimerLowerRTSDpc, PDevExt);
  301. CyyRemoveQueueDpc(&PDevExt->PerhapsLowerRTSDpc, PDevExt);
  302. //
  303. // If necessary, unmap the device registers.
  304. //
  305. if (PDevExt->BoardMemory) {
  306. MmUnmapIoSpace(PDevExt->BoardMemory, PDevExt->BoardMemoryLength);
  307. PDevExt->BoardMemory = NULL;
  308. }
  309. if (PDevExt->Runtime) {
  310. MmUnmapIoSpace(PDevExt->Runtime,
  311. PDevExt->RuntimeLength);
  312. PDevExt->Runtime = NULL;
  313. }
  314. CyyDbgPrintEx(DPFLTR_TRACE_LEVEL, "<CyyReleaseResources\n");
  315. }
  316. VOID
  317. CyyDisableInterfacesResources(IN PDEVICE_OBJECT PDevObj,
  318. BOOLEAN DisableCD1400)
  319. {
  320. PCYY_DEVICE_EXTENSION pDevExt
  321. = (PCYY_DEVICE_EXTENSION)PDevObj->DeviceExtension;
  322. PAGED_CODE();
  323. CyyDbgPrintEx(DPFLTR_TRACE_LEVEL, ">CyyDisableInterfaces(%X, %s)\n",
  324. PDevObj, DisableCD1400 ? "TRUE" : "FALSE");
  325. //
  326. // Only do these many things if the device has started and still
  327. // has resources allocated
  328. //
  329. if (pDevExt->Flags & CYY_FLAGS_STARTED) {
  330. if (!(pDevExt->Flags & CYY_FLAGS_STOPPED)) {
  331. if (DisableCD1400) {
  332. //
  333. // Mask off interrupts
  334. //
  335. CD1400_DISABLE_ALL_INTERRUPTS(pDevExt->Cd1400,pDevExt->IsPci,
  336. pDevExt->CdChannel);
  337. }
  338. CyyReleaseResources(pDevExt);
  339. }
  340. //
  341. // Remove us from WMI consideration
  342. //
  343. IoWMIRegistrationControl(PDevObj, WMIREG_ACTION_DEREGISTER);
  344. }
  345. //
  346. // Undo external names
  347. //
  348. CyyUndoExternalNaming(pDevExt);
  349. CyyDbgPrintEx(DPFLTR_TRACE_LEVEL, "<CyyDisableInterfaces\n");
  350. }
  351. NTSTATUS
  352. CyyRemoveDevObj(IN PDEVICE_OBJECT PDevObj)
  353. /*++
  354. Routine Description:
  355. Removes a serial device object from the system.
  356. Arguments:
  357. PDevObj - A pointer to the Device Object we want removed.
  358. Return Value:
  359. Always TRUE
  360. --*/
  361. {
  362. PCYY_DEVICE_EXTENSION pDevExt
  363. = (PCYY_DEVICE_EXTENSION)PDevObj->DeviceExtension;
  364. PAGED_CODE();
  365. CyyDbgPrintEx(DPFLTR_TRACE_LEVEL, ">CyyRemoveDevObj(%X)\n", PDevObj);
  366. // Removed by Fanny. These code is called directly from IRP_MN_REMOVE_DEVICE.
  367. // if (!(pDevExt->DevicePNPAccept & CYY_PNPACCEPT_SURPRISE_REMOVING)) {
  368. // //
  369. // // Disable all external interfaces and release resources
  370. // //
  371. //
  372. // CyyDisableInterfacesResources(PDevObj, TRUE);
  373. // }
  374. IoDetachDevice(pDevExt->LowerDeviceObject);
  375. //
  376. // Free memory allocated in the extension
  377. //
  378. if (pDevExt->NtNameForPort.Buffer != NULL) {
  379. ExFreePool(pDevExt->NtNameForPort.Buffer);
  380. }
  381. if (pDevExt->DeviceName.Buffer != NULL) {
  382. ExFreePool(pDevExt->DeviceName.Buffer);
  383. }
  384. if (pDevExt->SymbolicLinkName.Buffer != NULL) {
  385. ExFreePool(pDevExt->SymbolicLinkName.Buffer);
  386. }
  387. if (pDevExt->DosName.Buffer != NULL) {
  388. ExFreePool(pDevExt->DosName.Buffer);
  389. }
  390. if (pDevExt->ObjectDirectory.Buffer) {
  391. ExFreePool(pDevExt->ObjectDirectory.Buffer);
  392. }
  393. //
  394. // Delete the devobj
  395. //
  396. IoDeleteDevice(PDevObj);
  397. CyyDbgPrintEx(DPFLTR_TRACE_LEVEL, "<CyyRemoveDevObj %X\n",
  398. STATUS_SUCCESS);
  399. return STATUS_SUCCESS;
  400. }
  401. VOID
  402. CyyKillPendingIrps(PDEVICE_OBJECT PDevObj)
  403. /*++
  404. Routine Description:
  405. This routine kills any irps pending for the passed device object.
  406. Arguments:
  407. PDevObj - Pointer to the device object whose irps must die.
  408. Return Value:
  409. VOID
  410. --*/
  411. {
  412. PCYY_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  413. KIRQL oldIrql;
  414. CyyDbgPrintEx(DPFLTR_TRACE_LEVEL, ">CyyKillPendingIrps(%X)\n",
  415. PDevObj);
  416. //
  417. // First kill all the reads and writes.
  418. //
  419. CyyKillAllReadsOrWrites(PDevObj, &pDevExt->WriteQueue,
  420. &pDevExt->CurrentWriteIrp);
  421. CyyKillAllReadsOrWrites(PDevObj, &pDevExt->ReadQueue,
  422. &pDevExt->CurrentReadIrp);
  423. //
  424. // Next get rid of purges.
  425. //
  426. CyyKillAllReadsOrWrites(PDevObj, &pDevExt->PurgeQueue,
  427. &pDevExt->CurrentPurgeIrp);
  428. //
  429. // Get rid of any mask operations.
  430. //
  431. CyyKillAllReadsOrWrites(PDevObj, &pDevExt->MaskQueue,
  432. &pDevExt->CurrentMaskIrp);
  433. //
  434. // Now get rid a pending wait mask irp.
  435. //
  436. IoAcquireCancelSpinLock(&oldIrql);
  437. if (pDevExt->CurrentWaitIrp) {
  438. PDRIVER_CANCEL cancelRoutine;
  439. cancelRoutine = pDevExt->CurrentWaitIrp->CancelRoutine;
  440. pDevExt->CurrentWaitIrp->Cancel = TRUE;
  441. if (cancelRoutine) {
  442. pDevExt->CurrentWaitIrp->CancelIrql = oldIrql;
  443. pDevExt->CurrentWaitIrp->CancelRoutine = NULL;
  444. cancelRoutine(PDevObj, pDevExt->CurrentWaitIrp);
  445. } else {
  446. IoReleaseCancelSpinLock(oldIrql);
  447. }
  448. } else {
  449. IoReleaseCancelSpinLock(oldIrql);
  450. }
  451. //
  452. // Cancel any pending wait-wake irps
  453. //
  454. if (pDevExt->PendingWakeIrp != NULL) {
  455. IoCancelIrp(pDevExt->PendingWakeIrp);
  456. pDevExt->PendingWakeIrp = NULL;
  457. }
  458. //
  459. // Finally, dump any stalled IRPS
  460. //
  461. CyyKillAllStalled(PDevObj);
  462. CyyDbgPrintEx(DPFLTR_TRACE_LEVEL, "<CyyKillPendingIrps\n");
  463. }
  464. NTSTATUS
  465. CyyInitMultiPort(IN PCYY_DEVICE_EXTENSION PDevExt,
  466. IN PCONFIG_DATA PConfigData, IN PDEVICE_OBJECT PDevObj)
  467. /*++
  468. Routine Description:
  469. This routine initializes a multiport device by adding a port to an existing
  470. one.
  471. Arguments:
  472. PDevExt - pointer to the device extension of the root of the multiport
  473. device.
  474. PConfigData - pointer to the config data for the new port
  475. PDevObj - pointer to the devobj for the new port
  476. Return Value:
  477. STATUS_SUCCESS on success, appropriate error on failure.
  478. --*/
  479. {
  480. PCYY_DEVICE_EXTENSION pNewExt
  481. = (PCYY_DEVICE_EXTENSION)PDevObj->DeviceExtension;
  482. NTSTATUS status;
  483. PAGED_CODE();
  484. CyyDbgPrintEx(DPFLTR_TRACE_LEVEL, ">CyyInitMultiPort(%X, %X, %X)\n",
  485. PDevExt, PConfigData, PDevObj);
  486. //
  487. // Allow him to share OurIsrContext and interrupt object
  488. //
  489. pNewExt->OurIsrContext = PDevExt->OurIsrContext;
  490. pNewExt->Interrupt = PDevExt->Interrupt;
  491. //
  492. // First, see if we can initialize the one we have found
  493. //
  494. status = CyyInitController(PDevObj, PConfigData);
  495. if (!NT_SUCCESS(status)) {
  496. CyyDbgPrintEx(DPFLTR_TRACE_LEVEL, "<CyyInitMultiPort (1) %X\n",
  497. status);
  498. return status;
  499. }
  500. CyyDbgPrintEx(DPFLTR_TRACE_LEVEL, "<CyyInitMultiPort (3) %X\n",
  501. STATUS_SUCCESS);
  502. return STATUS_SUCCESS;
  503. }
  504. NTSTATUS
  505. CyyInitController(IN PDEVICE_OBJECT PDevObj, IN PCONFIG_DATA PConfigData)
  506. /*++
  507. Routine Description:
  508. Really too many things to mention here. In general initializes
  509. kernel synchronization structures, allocates the typeahead buffer,
  510. sets up defaults, etc.
  511. Arguments:
  512. PDevObj - Device object for the device to be started
  513. PConfigData - Pointer to a record for a single port.
  514. Return Value:
  515. STATUS_SUCCCESS if everything went ok. A !NT_SUCCESS status
  516. otherwise.
  517. --*/
  518. {
  519. PCYY_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  520. //
  521. // Holds the NT Status that is returned from each call to the
  522. // kernel and executive.
  523. //
  524. NTSTATUS status = STATUS_SUCCESS;
  525. BOOLEAN allocedDispatch = FALSE;
  526. PCYY_DISPATCH pDispatch = NULL;
  527. PAGED_CODE();
  528. CyyDbgPrintEx(CYYDIAG1, "Initializing for configuration record of %wZ\n",
  529. &pDevExt->DeviceName);
  530. if (pDevExt->OurIsrContext == NULL) {
  531. if ((pDevExt->OurIsrContext
  532. = ExAllocatePool(NonPagedPool,sizeof(CYY_DISPATCH))) == NULL) {
  533. status = STATUS_INSUFFICIENT_RESOURCES;
  534. goto ExtensionCleanup;
  535. }
  536. RtlZeroMemory(pDevExt->OurIsrContext,sizeof(CYY_DISPATCH));
  537. allocedDispatch = TRUE;
  538. }
  539. //
  540. // Initialize the timers used to timeout operations.
  541. //
  542. KeInitializeTimer(&pDevExt->ReadRequestTotalTimer);
  543. KeInitializeTimer(&pDevExt->ReadRequestIntervalTimer);
  544. KeInitializeTimer(&pDevExt->WriteRequestTotalTimer);
  545. KeInitializeTimer(&pDevExt->ImmediateTotalTimer);
  546. KeInitializeTimer(&pDevExt->XoffCountTimer);
  547. KeInitializeTimer(&pDevExt->LowerRTSTimer);
  548. //
  549. // Intialialize the dpcs that will be used to complete
  550. // or timeout various IO operations.
  551. //
  552. KeInitializeDpc(&pDevExt->CompleteWriteDpc, CyyCompleteWrite, pDevExt);
  553. KeInitializeDpc(&pDevExt->CompleteReadDpc, CyyCompleteRead, pDevExt);
  554. KeInitializeDpc(&pDevExt->TotalReadTimeoutDpc, CyyReadTimeout, pDevExt);
  555. KeInitializeDpc(&pDevExt->IntervalReadTimeoutDpc, CyyIntervalReadTimeout,
  556. pDevExt);
  557. KeInitializeDpc(&pDevExt->TotalWriteTimeoutDpc, CyyWriteTimeout, pDevExt);
  558. KeInitializeDpc(&pDevExt->CommErrorDpc, CyyCommError, pDevExt);
  559. KeInitializeDpc(&pDevExt->CompleteImmediateDpc, CyyCompleteImmediate,
  560. pDevExt);
  561. KeInitializeDpc(&pDevExt->TotalImmediateTimeoutDpc, CyyTimeoutImmediate,
  562. pDevExt);
  563. KeInitializeDpc(&pDevExt->CommWaitDpc, CyyCompleteWait, pDevExt);
  564. KeInitializeDpc(&pDevExt->XoffCountTimeoutDpc, CyyTimeoutXoff, pDevExt);
  565. KeInitializeDpc(&pDevExt->XoffCountCompleteDpc, CyyCompleteXoff, pDevExt);
  566. KeInitializeDpc(&pDevExt->StartTimerLowerRTSDpc, CyyStartTimerLowerRTS,
  567. pDevExt);
  568. KeInitializeDpc(&pDevExt->PerhapsLowerRTSDpc, CyyInvokePerhapsLowerRTS,
  569. pDevExt);
  570. KeInitializeDpc(&pDevExt->IsrUnlockPagesDpc, CyyUnlockPages, pDevExt);
  571. #if 0 // DBG
  572. //
  573. // Init debug stuff
  574. //
  575. pDevExt->DpcQueued[0].Dpc = &pDevExt->CompleteWriteDpc;
  576. pDevExt->DpcQueued[1].Dpc = &pDevExt->CompleteReadDpc;
  577. pDevExt->DpcQueued[2].Dpc = &pDevExt->TotalReadTimeoutDpc;
  578. pDevExt->DpcQueued[3].Dpc = &pDevExt->IntervalReadTimeoutDpc;
  579. pDevExt->DpcQueued[4].Dpc = &pDevExt->TotalWriteTimeoutDpc;
  580. pDevExt->DpcQueued[5].Dpc = &pDevExt->CommErrorDpc;
  581. pDevExt->DpcQueued[6].Dpc = &pDevExt->CompleteImmediateDpc;
  582. pDevExt->DpcQueued[7].Dpc = &pDevExt->TotalImmediateTimeoutDpc;
  583. pDevExt->DpcQueued[8].Dpc = &pDevExt->CommWaitDpc;
  584. pDevExt->DpcQueued[9].Dpc = &pDevExt->XoffCountTimeoutDpc;
  585. pDevExt->DpcQueued[10].Dpc = &pDevExt->XoffCountCompleteDpc;
  586. pDevExt->DpcQueued[11].Dpc = &pDevExt->StartTimerLowerRTSDpc;
  587. pDevExt->DpcQueued[12].Dpc = &pDevExt->PerhapsLowerRTSDpc;
  588. pDevExt->DpcQueued[13].Dpc = &pDevExt->IsrUnlockPagesDpc;
  589. #endif
  590. //
  591. // Map the memory for the control registers for the serial device
  592. // into virtual memory.
  593. //
  594. if (pDevExt->IsPci) {
  595. pDevExt->Runtime = MmMapIoSpace(PConfigData->TranslatedRuntime,
  596. PConfigData->RuntimeLength,
  597. FALSE);
  598. //******************************
  599. // Error injection
  600. //if (pDevExt->Runtime) {
  601. // MmUnmapIoSpace(pDevExt->Runtime, PConfigData->RuntimeLength);
  602. // pDevExt->Runtime = NULL;
  603. //}
  604. //******************************
  605. if (!pDevExt->Runtime) {
  606. CyyLogError(
  607. PDevObj->DriverObject,
  608. pDevExt->DeviceObject,
  609. PConfigData->PhysicalBoardMemory,
  610. CyyPhysicalZero,
  611. 0,
  612. 0,
  613. 0,
  614. PConfigData->PortIndex+1,
  615. STATUS_SUCCESS,
  616. CYY_RUNTIME_NOT_MAPPED,
  617. pDevExt->DeviceName.Length+sizeof(WCHAR),
  618. pDevExt->DeviceName.Buffer,
  619. 0,
  620. NULL
  621. );
  622. CyyDbgPrintEx(DPFLTR_WARNING_LEVEL, "Could not map Runtime memory for device "
  623. "registers for %wZ\n", &pDevExt->DeviceName);
  624. status = STATUS_NONE_MAPPED;
  625. goto ExtensionCleanup;
  626. }
  627. }
  628. pDevExt->BoardMemory = MmMapIoSpace(PConfigData->TranslatedBoardMemory,
  629. PConfigData->BoardMemoryLength,
  630. FALSE);
  631. //******************************
  632. // Error injection
  633. //if (pDevExt->BoardMemory) {
  634. // MmUnmapIoSpace(pDevExt->BoardMemory, PConfigData->BoardMemoryLength);
  635. // pDevExt->BoardMemory = NULL;
  636. //}
  637. //******************************
  638. if (!pDevExt->BoardMemory) {
  639. CyyLogError(
  640. PDevObj->DriverObject,
  641. pDevExt->DeviceObject,
  642. PConfigData->PhysicalBoardMemory,
  643. CyyPhysicalZero,
  644. 0,
  645. 0,
  646. 0,
  647. PConfigData->PortIndex+1,
  648. STATUS_SUCCESS,
  649. CYY_BOARD_NOT_MAPPED,
  650. pDevExt->DeviceName.Length+sizeof(WCHAR),
  651. pDevExt->DeviceName.Buffer,
  652. 0,
  653. NULL
  654. );
  655. CyyDbgPrintEx(DPFLTR_WARNING_LEVEL, "Could not map Board memory for device "
  656. "registers for %wZ\n", &pDevExt->DeviceName);
  657. status = STATUS_NONE_MAPPED;
  658. goto ExtensionCleanup;
  659. }
  660. pDevExt->RuntimeAddressSpace = PConfigData->RuntimeAddressSpace;
  661. pDevExt->OriginalRuntimeMemory = PConfigData->PhysicalRuntime;
  662. pDevExt->RuntimeLength = PConfigData->RuntimeLength;
  663. pDevExt->BoardMemoryAddressSpace = PConfigData->BoardMemoryAddressSpace;
  664. pDevExt->OriginalBoardMemory = PConfigData->PhysicalBoardMemory;
  665. pDevExt->BoardMemoryLength = PConfigData->BoardMemoryLength;
  666. //
  667. // Shareable interrupt?
  668. //
  669. pDevExt->InterruptShareable = TRUE;
  670. //
  671. // Save off the interface type and the bus number.
  672. //
  673. pDevExt->InterfaceType = PConfigData->InterfaceType;
  674. pDevExt->BusNumber = PConfigData->BusNumber;
  675. pDevExt->PortIndex = PConfigData->PortIndex;
  676. //
  677. // Get the translated interrupt vector, level, and affinity
  678. //
  679. pDevExt->OriginalIrql = PConfigData->OriginalIrql;
  680. pDevExt->OriginalVector = PConfigData->OriginalVector;
  681. //
  682. // PnP uses the passed translated values rather than calling
  683. // HalGetInterruptVector()
  684. //
  685. pDevExt->Vector = PConfigData->TrVector;
  686. pDevExt->Irql = (UCHAR)PConfigData->TrIrql;
  687. //
  688. // Set up the Isr.
  689. //
  690. pDevExt->OurIsr = CyyIsr;
  691. //
  692. // Before we test whether the port exists (which will enable the FIFO)
  693. // convert the rx trigger value to what should be used in the register.
  694. //
  695. // If a bogus value was given - crank them down to 1.
  696. //
  697. switch (PConfigData->RxFIFO) {
  698. case 1:
  699. pDevExt->RxFifoTrigger = SERIAL_1_BYTE_HIGH_WATER;
  700. break;
  701. case 4:
  702. pDevExt->RxFifoTrigger = SERIAL_4_BYTE_HIGH_WATER;
  703. break;
  704. case 8:
  705. pDevExt->RxFifoTrigger = SERIAL_8_BYTE_HIGH_WATER;
  706. break;
  707. case 14:
  708. pDevExt->RxFifoTrigger = SERIAL_14_BYTE_HIGH_WATER;
  709. break;
  710. default:
  711. pDevExt->RxFifoTrigger = SERIAL_1_BYTE_HIGH_WATER;
  712. break;
  713. }
  714. if ((PConfigData->TxFIFO > MAX_CHAR_FIFO) ||
  715. (PConfigData->TxFIFO < 1)) {
  716. pDevExt->TxFifoAmount = MAX_CHAR_FIFO;
  717. } else {
  718. // Fanny: For now, do not use value from Registry.
  719. //pDevExt->TxFifoAmount = PConfigData->TxFIFO;
  720. pDevExt->TxFifoAmount = MAX_CHAR_FIFO;
  721. }
  722. // Get CD1400 address of current port
  723. pDevExt->OriginalCd1400 = GetMyPhysicalCD1400Address(pDevExt->OriginalBoardMemory,
  724. pDevExt->PortIndex, pDevExt->IsPci);
  725. pDevExt->Cd1400 = GetMyMappedCD1400Address(pDevExt->BoardMemory,
  726. pDevExt->PortIndex, pDevExt->IsPci);
  727. pDevExt->CdChannel = (UCHAR)(pDevExt->PortIndex % 4);
  728. //
  729. // Set up the default device control fields.
  730. // Note that if the values are changed after
  731. // the file is open, they do NOT revert back
  732. // to the old value at file close.
  733. //
  734. pDevExt->SpecialChars.XonChar = CYY_DEF_XON;
  735. pDevExt->SpecialChars.XoffChar = CYY_DEF_XOFF;
  736. pDevExt->HandFlow.ControlHandShake = SERIAL_DTR_CONTROL;
  737. pDevExt->HandFlow.FlowReplace = SERIAL_RTS_CONTROL;
  738. //
  739. // Default Line control protocol. 7E1
  740. //
  741. // Seven data bits.
  742. // Even parity.
  743. // 1 Stop bits.
  744. //
  745. pDevExt->cor1 = COR1_7_DATA | COR1_EVEN_PARITY |
  746. COR1_1_STOP;
  747. pDevExt->ValidDataMask = 0x7f;
  748. pDevExt->CurrentBaud = 1200;
  749. //
  750. // We set up the default xon/xoff limits.
  751. //
  752. // This may be a bogus value. It looks like the BufferSize
  753. // is not set up until the device is actually opened.
  754. //
  755. pDevExt->HandFlow.XoffLimit = pDevExt->BufferSize >> 3;
  756. pDevExt->HandFlow.XonLimit = pDevExt->BufferSize >> 1;
  757. pDevExt->BufferSizePt8 = ((3*(pDevExt->BufferSize>>2))+
  758. (pDevExt->BufferSize>>4));
  759. CyyDbgPrintEx(CYYDIAG1, " The default interrupt read buffer size is: %d\n"
  760. "------ The XoffLimit is : %d\n"
  761. "------ The XonLimit is : %d\n"
  762. "------ The pt 8 size is : %d\n",
  763. pDevExt->BufferSize, pDevExt->HandFlow.XoffLimit,
  764. pDevExt->HandFlow.XonLimit, pDevExt->BufferSizePt8);
  765. //
  766. // Find out which baud rates are supported by this port.
  767. //
  768. if (CD1400_READ( pDevExt->Cd1400, pDevExt->IsPci, GFRCR ) > REV_G) {
  769. pDevExt->CDClock = 60000000;
  770. pDevExt->MSVR_RTS = MSVR2;
  771. pDevExt->MSVR_DTR = MSVR1;
  772. pDevExt->DTRset = 0x01;
  773. pDevExt->RTSset = 0x02;
  774. pDevExt->SupportedBauds =
  775. SERIAL_BAUD_134_5 | SERIAL_BAUD_150 | SERIAL_BAUD_300 |
  776. SERIAL_BAUD_600 | SERIAL_BAUD_1200 | SERIAL_BAUD_1800 |
  777. SERIAL_BAUD_2400 | SERIAL_BAUD_4800 | SERIAL_BAUD_7200 |
  778. SERIAL_BAUD_9600 | SERIAL_BAUD_14400 | SERIAL_BAUD_19200 |
  779. SERIAL_BAUD_38400 | SERIAL_BAUD_56K | SERIAL_BAUD_57600 |
  780. SERIAL_BAUD_115200 | SERIAL_BAUD_128K | SERIAL_BAUD_USER;
  781. } else {
  782. pDevExt->CDClock = 25000000;
  783. pDevExt->MSVR_RTS = MSVR1;
  784. pDevExt->MSVR_DTR = MSVR2;
  785. pDevExt->DTRset = 0x02;
  786. pDevExt->RTSset = 0x01;
  787. pDevExt->SupportedBauds = SERIAL_BAUD_075 | SERIAL_BAUD_110 |
  788. SERIAL_BAUD_134_5 | SERIAL_BAUD_150 | SERIAL_BAUD_300 |
  789. SERIAL_BAUD_600 | SERIAL_BAUD_1200 | SERIAL_BAUD_1800 |
  790. SERIAL_BAUD_2400 | SERIAL_BAUD_4800 | SERIAL_BAUD_7200 |
  791. SERIAL_BAUD_9600 | SERIAL_BAUD_14400 | SERIAL_BAUD_19200 |
  792. SERIAL_BAUD_38400 | SERIAL_BAUD_56K | SERIAL_BAUD_57600 |
  793. SERIAL_BAUD_115200 | SERIAL_BAUD_128K | SERIAL_BAUD_USER;
  794. }
  795. //
  796. // Mark this device as not being opened by anyone. We keep a
  797. // variable around so that spurious interrupts are easily
  798. // dismissed by the ISR.
  799. //
  800. pDevExt->DeviceIsOpened = FALSE;
  801. //
  802. // Store values into the extension for interval timing.
  803. //
  804. //
  805. // If the interval timer is less than a second then come
  806. // in with a short "polling" loop.
  807. //
  808. // For large (> then 2 seconds) use a 1 second poller.
  809. //
  810. pDevExt->ShortIntervalAmount.QuadPart = -1;
  811. pDevExt->LongIntervalAmount.QuadPart = -10000000;
  812. pDevExt->CutOverAmount.QuadPart = 200000000;
  813. // Initialize for the Isr Dispatch
  814. pDispatch = pDevExt->OurIsrContext;
  815. pDispatch->IsPci = pDevExt->IsPci;
  816. pDispatch->Extensions[pDevExt->PortIndex] = pDevExt;
  817. pDispatch->Cd1400[pDevExt->PortIndex] = pDevExt->Cd1400;
  818. //
  819. // Common error path cleanup. If the status is
  820. // bad, get rid of the device extension, device object
  821. // and any memory associated with it.
  822. //
  823. ExtensionCleanup: ;
  824. if (!NT_SUCCESS(status)) {
  825. if (pDispatch) {
  826. pDispatch->Extensions[pDevExt->PortIndex] = NULL;
  827. pDispatch->Cd1400[pDevExt->PortIndex] = NULL;
  828. }
  829. if (allocedDispatch) {
  830. ExFreePool(pDevExt->OurIsrContext);
  831. pDevExt->OurIsrContext = NULL;
  832. }
  833. if (pDevExt->Runtime) {
  834. MmUnmapIoSpace(pDevExt->Runtime, PConfigData->RuntimeLength);
  835. pDevExt->Runtime = NULL;
  836. }
  837. if (pDevExt->BoardMemory) {
  838. MmUnmapIoSpace(pDevExt->BoardMemory, PConfigData->BoardMemoryLength);
  839. pDevExt->BoardMemory = NULL;
  840. }
  841. }
  842. return status;
  843. }
  844. BOOLEAN
  845. CyyReset(
  846. IN PVOID Context
  847. )
  848. /*--------------------------------------------------------------------------
  849. CyyReset()
  850. Routine Description: This places the hardware in a standard
  851. configuration. This assumes that it is called at interrupt level.
  852. Arguments:
  853. Context - The device extension for serial device being managed.
  854. Return Value: Always FALSE.
  855. --------------------------------------------------------------------------*/
  856. {
  857. PCYY_DEVICE_EXTENSION extension = Context;
  858. PUCHAR chip = extension->Cd1400;
  859. ULONG bus = extension->IsPci;
  860. CYY_IOCTL_BAUD s;
  861. extension->RxFifoTriggerUsed = FALSE;
  862. // Disable channel
  863. CD1400_WRITE(chip,bus,CAR,extension->CdChannel & 0x03);
  864. CyyCDCmd(extension,CCR_DIS_TX_RX);
  865. // set the line control, modem control, and the baud to what they should be.
  866. CyySetLineControl(extension);
  867. CyySetupNewHandFlow(extension,&extension->HandFlow);
  868. CyyHandleModemUpdate(extension,FALSE);
  869. s.Extension = extension;
  870. s.Baud = extension->CurrentBaud;
  871. CyySetBaud(&s);
  872. // Enable port
  873. CD1400_WRITE(chip,bus,CAR,extension->CdChannel & 0x03);
  874. CyyCDCmd(extension,CCR_ENA_TX_RX);
  875. // Enable reception and modem interrupts
  876. CD1400_WRITE(chip,bus,MCOR1,0xf0); // Transitions of DSR,CTS,RI and CD cause IRQ.
  877. // Automatic DTR Mode disabled.
  878. CD1400_WRITE(chip,bus,MCOR2,0xf0);
  879. #if 0
  880. cy_wreg(SRER,0x91); // Enable MdmCh, RxData, NNDT.
  881. #endif
  882. CD1400_WRITE(chip,bus,SRER,0x90); // Enable MdmCh, RxData.
  883. extension->HoldingEmpty = TRUE;
  884. return FALSE;
  885. }
  886. VOID
  887. CyyUnload(
  888. IN PDRIVER_OBJECT DriverObject
  889. )
  890. /*--------------------------------------------------------------------------
  891. CyyUnload()
  892. Description: This routine is defunct since all device objects
  893. are removed before the driver is unloaded.
  894. Arguments:
  895. DriverObject - A pointer to the driver object.
  896. Return Value: None.
  897. --------------------------------------------------------------------------*/
  898. {
  899. PVOID lockPtr;
  900. PAGED_CODE();
  901. lockPtr = MmLockPagableCodeSection(CyyUnload);
  902. //
  903. // Unnecessary since our BSS is going away, but do it anyhow to be safe
  904. //
  905. CyyGlobals.PAGESER_Handle = NULL;
  906. if (CyyGlobals.RegistryPath.Buffer != NULL) {
  907. ExFreePool(CyyGlobals.RegistryPath.Buffer);
  908. CyyGlobals.RegistryPath.Buffer = NULL;
  909. }
  910. #if DBG
  911. SerialLogFree();
  912. #endif
  913. CyyDbgPrintEx(CYYDIAG3, "In CyyUnload\n");
  914. MmUnlockPagableImageSection(lockPtr);
  915. }
  916. CYY_MEM_COMPARES
  917. CyyMemCompare(
  918. IN PHYSICAL_ADDRESS A,
  919. IN ULONG SpanOfA,
  920. IN PHYSICAL_ADDRESS B,
  921. IN ULONG SpanOfB
  922. )
  923. /*++
  924. Routine Description:
  925. Compare two phsical address.
  926. Arguments:
  927. A - One half of the comparison.
  928. SpanOfA - In units of bytes, the span of A.
  929. B - One half of the comparison.
  930. SpanOfB - In units of bytes, the span of B.
  931. Return Value:
  932. The result of the comparison.
  933. --*/
  934. {
  935. LARGE_INTEGER a;
  936. LARGE_INTEGER b;
  937. LARGE_INTEGER lower;
  938. ULONG lowerSpan;
  939. LARGE_INTEGER higher;
  940. //PAGED_CODE(); Non paged because it can be called during CyyLogError, which is non paged now.
  941. a = A;
  942. b = B;
  943. if (a.QuadPart == b.QuadPart) {
  944. return AddressesAreEqual;
  945. }
  946. if (a.QuadPart > b.QuadPart) {
  947. higher = a;
  948. lower = b;
  949. lowerSpan = SpanOfB;
  950. } else {
  951. higher = b;
  952. lower = a;
  953. lowerSpan = SpanOfA;
  954. }
  955. if ((higher.QuadPart - lower.QuadPart) >= lowerSpan) {
  956. return AddressesAreDisjoint;
  957. }
  958. return AddressesOverlap;
  959. }
  960. NTSTATUS
  961. CyyFindInitController(IN PDEVICE_OBJECT PDevObj, IN PCONFIG_DATA PConfig)
  962. /*++
  963. Routine Description:
  964. This function discovers what type of controller is responsible for
  965. the given port and initializes the controller and port.
  966. Arguments:
  967. PDevObj - Pointer to the devobj for the port we are about to init.
  968. PConfig - Pointer to configuration data for the port we are about to init.
  969. Return Value:
  970. STATUS_SUCCESS on success, appropriate error value on failure.
  971. --*/
  972. {
  973. PCYY_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  974. PDEVICE_OBJECT pDeviceObject;
  975. PCYY_DEVICE_EXTENSION pExtension;
  976. PHYSICAL_ADDRESS serialPhysicalMax;
  977. PLIST_ENTRY pCurDevObj;
  978. NTSTATUS status;
  979. KIRQL oldIrql;
  980. CyyDbgPrintEx(DPFLTR_TRACE_LEVEL, ">CyyFindInitController(%X, %X)\n",
  981. PDevObj, PConfig);
  982. serialPhysicalMax.LowPart = (ULONG)~0;
  983. serialPhysicalMax.HighPart = ~0;
  984. CyyDbgPrintEx(CYYDIAG1, "Attempting to init %wZ\n"
  985. "------- Runtime Memory is %x\n"
  986. "------- Board Memory is %x\n"
  987. "------- BusNumber is %d\n"
  988. "------- BusType is %d\n"
  989. "------- Runtime AddressSpace is %d\n"
  990. "------- Board AddressSpace is %d\n"
  991. "------- Interrupt Mode is %d\n",
  992. &pDevExt->DeviceName,
  993. PConfig->PhysicalRuntime.LowPart,
  994. PConfig->PhysicalBoardMemory.LowPart,
  995. PConfig->BusNumber,
  996. PConfig->InterfaceType,
  997. PConfig->RuntimeAddressSpace,
  998. PConfig->BoardMemoryAddressSpace,
  999. PConfig->InterruptMode);
  1000. //
  1001. // We don't support any boards whose memory wraps around
  1002. // the physical address space.
  1003. //
  1004. if (pDevExt->IsPci) {
  1005. //*****************************************************
  1006. // error injection
  1007. // if (CyyMemCompare(
  1008. // PConfig->PhysicalRuntime,
  1009. // PConfig->RuntimeLength,
  1010. // serialPhysicalMax,
  1011. // (ULONG)0
  1012. // ) == AddressesAreDisjoint)
  1013. //*****************************************************
  1014. if (CyyMemCompare(
  1015. PConfig->PhysicalRuntime,
  1016. PConfig->RuntimeLength,
  1017. serialPhysicalMax,
  1018. (ULONG)0
  1019. ) != AddressesAreDisjoint) {
  1020. CyyLogError(
  1021. PDevObj->DriverObject,
  1022. NULL,
  1023. PConfig->PhysicalBoardMemory,
  1024. CyyPhysicalZero,
  1025. 0,
  1026. 0,
  1027. 0,
  1028. PConfig->PortIndex+1,
  1029. STATUS_SUCCESS,
  1030. CYY_RUNTIME_MEMORY_TOO_HIGH,
  1031. pDevExt->DeviceName.Length+sizeof(WCHAR),
  1032. pDevExt->DeviceName.Buffer,
  1033. 0,
  1034. NULL
  1035. );
  1036. CyyDbgPrintEx(DPFLTR_WARNING_LEVEL, "Error in config record for %wZ\n"
  1037. "------ Runtime memory wraps around physical memory\n",
  1038. &pDevExt->DeviceName);
  1039. return STATUS_NO_SUCH_DEVICE;
  1040. }
  1041. }
  1042. //*****************************************************
  1043. // error injection
  1044. // if (CyyMemCompare(
  1045. // PConfig->PhysicalBoardMemory,
  1046. // PConfig->BoardMemoryLength,
  1047. // serialPhysicalMax,
  1048. // (ULONG)0
  1049. // ) == AddressesAreDisjoint)
  1050. //*****************************************************
  1051. if (CyyMemCompare(
  1052. PConfig->PhysicalBoardMemory,
  1053. PConfig->BoardMemoryLength,
  1054. serialPhysicalMax,
  1055. (ULONG)0
  1056. ) != AddressesAreDisjoint) {
  1057. CyyLogError(
  1058. PDevObj->DriverObject,
  1059. NULL,
  1060. PConfig->PhysicalBoardMemory,
  1061. CyyPhysicalZero,
  1062. 0,
  1063. 0,
  1064. 0,
  1065. PConfig->PortIndex+1,
  1066. STATUS_SUCCESS,
  1067. CYY_BOARD_MEMORY_TOO_HIGH,
  1068. pDevExt->DeviceName.Length+sizeof(WCHAR),
  1069. pDevExt->DeviceName.Buffer,
  1070. 0,
  1071. NULL
  1072. );
  1073. CyyDbgPrintEx(DPFLTR_WARNING_LEVEL, "Error in config record for %wZ\n"
  1074. "------ board memory wraps around physical memory\n",
  1075. &pDevExt->DeviceName);
  1076. return STATUS_NO_SUCH_DEVICE;
  1077. }
  1078. //
  1079. // Make sure that the Runtime memory addresses don't
  1080. // overlap the controller registers for PCI cards
  1081. //
  1082. if (pDevExt->IsPci) {
  1083. if (CyyMemCompare(
  1084. PConfig->PhysicalRuntime,
  1085. PConfig->RuntimeLength,
  1086. CyyPhysicalZero,
  1087. (ULONG)0
  1088. ) != AddressesAreEqual) {
  1089. //*****************************************************
  1090. // error injection
  1091. // if (CyyMemCompare(
  1092. // PConfig->PhysicalRuntime,
  1093. // PConfig->RuntimeLength,
  1094. // PConfig->PhysicalBoardMemory,
  1095. // PConfig->BoardMemoryLength
  1096. // ) == AddressesAreDisjoint)
  1097. //*****************************************************
  1098. if (CyyMemCompare(
  1099. PConfig->PhysicalRuntime,
  1100. PConfig->RuntimeLength,
  1101. PConfig->PhysicalBoardMemory,
  1102. PConfig->BoardMemoryLength
  1103. ) != AddressesAreDisjoint) {
  1104. CyyLogError(
  1105. PDevObj->DriverObject,
  1106. NULL,
  1107. PConfig->PhysicalBoardMemory,
  1108. PConfig->PhysicalRuntime,
  1109. 0,
  1110. 0,
  1111. 0,
  1112. PConfig->PortIndex+1,
  1113. STATUS_SUCCESS,
  1114. CYY_BOTH_MEMORY_CONFLICT,
  1115. pDevExt->DeviceName.Length+sizeof(WCHAR),
  1116. pDevExt->DeviceName.Buffer,
  1117. 0,
  1118. NULL
  1119. );
  1120. CyyDbgPrintEx(DPFLTR_WARNING_LEVEL, "Error in config record for %wZ\n"
  1121. "------ Runtime memory wraps around CD1400 registers\n",
  1122. &pDevExt->DeviceName);
  1123. return STATUS_NO_SUCH_DEVICE;
  1124. }
  1125. }
  1126. }
  1127. //
  1128. // Now, we will check if this is a port on a multiport card.
  1129. // The conditions are same ISR set and same IRQL/Vector
  1130. //
  1131. //
  1132. // Loop through all previously attached devices
  1133. //
  1134. KeAcquireSpinLock(&CyyGlobals.GlobalsSpinLock, &oldIrql);
  1135. if (!IsListEmpty(&CyyGlobals.AllDevObjs)) {
  1136. pCurDevObj = CyyGlobals.AllDevObjs.Flink;
  1137. pExtension = CONTAINING_RECORD(pCurDevObj, CYY_DEVICE_EXTENSION,
  1138. AllDevObjs);
  1139. } else {
  1140. pCurDevObj = NULL;
  1141. pExtension = NULL;
  1142. }
  1143. KeReleaseSpinLock(&CyyGlobals.GlobalsSpinLock, oldIrql);
  1144. //
  1145. // If there is an interrupt status then we
  1146. // loop through the config list again to look
  1147. // for a config record with the same interrupt
  1148. // status (on the same bus).
  1149. //
  1150. if (pCurDevObj != NULL) {
  1151. ASSERT(pExtension != NULL);
  1152. //
  1153. // We have an interrupt status. Loop through all
  1154. // previous records, look for an existing interrupt status
  1155. // the same as the current interrupt status.
  1156. //
  1157. do {
  1158. //
  1159. // We only care about this list if the elements are on the
  1160. // same bus as this new entry. (Their interrupts must therefore
  1161. // also be the on the same bus. We will check that momentarily).
  1162. //
  1163. // We don't check here for the dissimilar interrupts since that
  1164. // could cause us to miss the error of having the same interrupt
  1165. // status but different interrupts - which is bizzare.
  1166. //
  1167. if ((pExtension->InterfaceType == PConfig->InterfaceType) &&
  1168. (pExtension->BoardMemoryAddressSpace == PConfig->BoardMemoryAddressSpace) &&
  1169. (pExtension->BusNumber == PConfig->BusNumber)) {
  1170. //
  1171. // If the board memory is the same, then same card.
  1172. //
  1173. if (CyyMemCompare(
  1174. pExtension->OriginalBoardMemory,
  1175. pExtension->BoardMemoryLength,
  1176. PConfig->PhysicalBoardMemory,
  1177. PConfig->BoardMemoryLength
  1178. ) == AddressesAreEqual) {
  1179. //
  1180. // Same card. Now make sure that they
  1181. // are using the same interrupt parameters.
  1182. //
  1183. // BUILD 2128: OriginalIrql replaced by TrIrql and Irql; same for OriginalVector
  1184. if ((PConfig->TrIrql != pExtension->Irql) ||
  1185. (PConfig->TrVector != pExtension->Vector)) {
  1186. //*************************************************************
  1187. // Error Injection
  1188. // if ((PConfig->TrIrql == pExtension->Irql) ||
  1189. // (PConfig->TrVector != pExtension->Vector))
  1190. //*************************************************************
  1191. //
  1192. // We won't put this into the configuration
  1193. // list.
  1194. //
  1195. CyyLogError(
  1196. PDevObj->DriverObject,
  1197. NULL,
  1198. PConfig->PhysicalBoardMemory,
  1199. pExtension->OriginalBoardMemory,
  1200. 0,
  1201. 0,
  1202. 0,
  1203. PConfig->PortIndex+1,
  1204. STATUS_SUCCESS,
  1205. CYY_MULTI_INTERRUPT_CONFLICT,
  1206. pDevExt->DeviceName.Length+sizeof(WCHAR),
  1207. pDevExt->DeviceName.Buffer,
  1208. pExtension->DeviceName.Length
  1209. + sizeof(WCHAR),
  1210. pExtension->DeviceName.Buffer
  1211. );
  1212. CyyDbgPrintEx(DPFLTR_WARNING_LEVEL, "Configuration error "
  1213. "for %wZ\n"
  1214. "------- Same multiport - different "
  1215. "interrupts\n", &pDevExt->DeviceName);
  1216. return STATUS_NO_SUCH_DEVICE;
  1217. }
  1218. if (pDevExt->IsPci) {
  1219. //
  1220. // PCI board. Make sure the PCI memory addresses are equal.
  1221. //
  1222. if (CyyMemCompare(
  1223. pExtension->OriginalRuntimeMemory,
  1224. pExtension->RuntimeLength,
  1225. PConfig->PhysicalRuntime,
  1226. PConfig->RuntimeLength
  1227. ) != AddressesAreEqual) {
  1228. //*****************************************************
  1229. // error injection
  1230. // if (CyyMemCompare(
  1231. // pExtension->OriginalRuntimeMemory,
  1232. // pExtension->RuntimeLength,
  1233. // PConfig->PhysicalRuntime,
  1234. // PConfig->RuntimeLength
  1235. // ) == AddressesAreEqual)
  1236. //*****************************************************
  1237. CyyLogError(
  1238. PDevObj->DriverObject,
  1239. NULL,
  1240. PConfig->PhysicalRuntime,
  1241. pExtension->OriginalRuntimeMemory,
  1242. 0,
  1243. 0,
  1244. 0,
  1245. PConfig->PortIndex+1,
  1246. STATUS_SUCCESS,
  1247. CYY_MULTI_RUNTIME_CONFLICT,
  1248. pDevExt->DeviceName.Length+sizeof(WCHAR),
  1249. pDevExt->DeviceName.Buffer,
  1250. pExtension->DeviceName.Length
  1251. + sizeof(WCHAR),
  1252. pExtension->DeviceName.Buffer
  1253. );
  1254. CyyDbgPrintEx(DPFLTR_WARNING_LEVEL, "Configuration error "
  1255. "for %wZ\n"
  1256. "------- Same multiport - different "
  1257. "Runtime addresses\n", &pDevExt->DeviceName);
  1258. return STATUS_NO_SUCH_DEVICE;
  1259. }
  1260. }
  1261. //
  1262. // We should never get this far on a restart since we don't
  1263. // support stop on ISA multiport devices!
  1264. //
  1265. ASSERT(pDevExt->PNPState == CYY_PNP_ADDED);
  1266. //
  1267. //
  1268. // Initialize the device as part of a multiport board
  1269. //
  1270. CyyDbgPrintEx(CYYDIAG1, "Aha! It is a multiport node\n");
  1271. CyyDbgPrintEx(CYYDIAG1, "Matched to %x\n", pExtension);
  1272. status = CyyInitMultiPort(pExtension, PConfig, PDevObj);
  1273. //
  1274. // A port can be one of two things:
  1275. // A non-root on a multiport
  1276. // A root on a multiport
  1277. //
  1278. // It can only share an interrupt if it is a root.
  1279. // Since this was a non-root we don't need to check
  1280. // if it shares an interrupt and we can return.
  1281. //
  1282. return status;
  1283. }
  1284. }
  1285. //
  1286. // No match, check some more
  1287. //
  1288. KeAcquireSpinLock(&CyyGlobals.GlobalsSpinLock, &oldIrql);
  1289. pCurDevObj = pCurDevObj->Flink;
  1290. if (pCurDevObj != NULL) {
  1291. pExtension = CONTAINING_RECORD(pCurDevObj,CYY_DEVICE_EXTENSION,
  1292. AllDevObjs);
  1293. }
  1294. KeReleaseSpinLock(&CyyGlobals.GlobalsSpinLock, oldIrql);
  1295. } while (pCurDevObj != NULL && pCurDevObj != &CyyGlobals.AllDevObjs);
  1296. }
  1297. CyyDbgPrintEx(CYYDIAG1, "Aha! It is a first multi\n");
  1298. status = CyyInitController(PDevObj, PConfig);
  1299. if (!NT_SUCCESS(status)) {
  1300. return status;
  1301. }
  1302. return STATUS_SUCCESS;
  1303. }
  1304. PUCHAR
  1305. GetMyMappedCD1400Address(IN PUCHAR BoardMemory, IN ULONG PortIndex, IN ULONG IsPci)
  1306. {
  1307. const ULONG CyyCDOffset[] = { // CD1400 offsets within the board
  1308. 0x00000000,0x00000400,0x00000800,0x00000C00,
  1309. 0x00000200,0x00000600,0x00000A00,0x00000E00
  1310. };
  1311. ULONG chipIndex = PortIndex/4;
  1312. return(BoardMemory + (CyyCDOffset[chipIndex] << IsPci));
  1313. }
  1314. PHYSICAL_ADDRESS
  1315. GetMyPhysicalCD1400Address(IN PHYSICAL_ADDRESS BoardMemory, IN ULONG PortIndex, IN ULONG IsPci)
  1316. {
  1317. const ULONG CyyCDOffset[] = { // CD1400 offsets within the board
  1318. 0x00000000,0x00000400,0x00000800,0x00000C00,
  1319. 0x00000200,0x00000600,0x00000A00,0x00000E00
  1320. };
  1321. ULONG chipIndex = PortIndex/CYY_CHANNELS_PER_CHIP;
  1322. BoardMemory.QuadPart += (CyyCDOffset[chipIndex] << IsPci);
  1323. return(BoardMemory);
  1324. }
  1325. VOID
  1326. CyyCommError(
  1327. IN PKDPC Dpc,
  1328. IN PVOID DeferredContext,
  1329. IN PVOID SystemContext1,
  1330. IN PVOID SystemContext2
  1331. )
  1332. /*--------------------------------------------------------------------------
  1333. CyyComError()
  1334. Routine Description: This routine is invoked at dpc level in response
  1335. to a comm error. All comm errors kill all read and writes
  1336. Arguments:
  1337. Dpc - Not Used.
  1338. DeferredContext - points to the device object.
  1339. SystemContext1 - Not Used.
  1340. SystemContext2 - Not Used.
  1341. Return Value: None.
  1342. --------------------------------------------------------------------------*/
  1343. {
  1344. PCYY_DEVICE_EXTENSION Extension = DeferredContext;
  1345. UNREFERENCED_PARAMETER(SystemContext1);
  1346. UNREFERENCED_PARAMETER(SystemContext2);
  1347. CyyDbgPrintEx(DPFLTR_TRACE_LEVEL, ">CyyCommError(%X)\n", Extension);
  1348. CyyKillAllReadsOrWrites(
  1349. Extension->DeviceObject,
  1350. &Extension->WriteQueue,
  1351. &Extension->CurrentWriteIrp
  1352. );
  1353. CyyKillAllReadsOrWrites(
  1354. Extension->DeviceObject,
  1355. &Extension->ReadQueue,
  1356. &Extension->CurrentReadIrp
  1357. );
  1358. CyyDpcEpilogue(Extension, Dpc);
  1359. CyyDbgPrintEx(DPFLTR_TRACE_LEVEL, "<CyyCommError\n");
  1360. }