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.

3666 lines
100 KiB

  1. /*++
  2. Copyright (c) 1991, 1992, 1993 - 1997 Microsoft Corporation
  3. Module Name:
  4. initunlo.c
  5. Abstract:
  6. This module contains the code that is very specific to initialization
  7. and unload operations in the serial driver
  8. Author:
  9. Anthony V. Ercolano 26-Sep-1991
  10. Environment:
  11. Kernel mode
  12. --*/
  13. #include "precomp.h"
  14. //
  15. // This is the actual definition of SerialDebugLevel.
  16. // Note that it is only defined if this is a "debug"
  17. // build.
  18. //
  19. #if DBG
  20. extern ULONG SerialDebugLevel = 0;
  21. #endif
  22. //
  23. // All our global variables except DebugLevel stashed in one
  24. // little package
  25. //
  26. SERIAL_GLOBALS SerialGlobals;
  27. static const PHYSICAL_ADDRESS SerialPhysicalZero = {0};
  28. //
  29. // We use this to query into the registry as to whether we
  30. // should break at driver entry.
  31. //
  32. SERIAL_FIRMWARE_DATA driverDefaults;
  33. //
  34. // This is exported from the kernel. It is used to point
  35. // to the address that the kernel debugger is using.
  36. //
  37. extern PUCHAR *KdComPortInUse;
  38. //
  39. // INIT - only needed during init and then can be disposed
  40. // PAGESRP0 - always paged / never locked
  41. // PAGESER - must be locked when a device is open, else paged
  42. //
  43. //
  44. // INIT is used for DriverEntry() specific code
  45. //
  46. // PAGESRP0 is used for code that is not often called and has nothing
  47. // to do with I/O performance. An example, IRP_MJ_PNP/IRP_MN_START_DEVICE
  48. // support functions
  49. //
  50. // PAGESER is used for code that needs to be locked after an open for both
  51. // performance and IRQL reasons.
  52. //
  53. #ifdef ALLOC_PRAGMA
  54. #pragma alloc_text(INIT,DriverEntry)
  55. #pragma alloc_text(PAGESRP0, SerialInitMultiPort)
  56. #pragma alloc_text(PAGESRP0, SerialInitOneController)
  57. #pragma alloc_text(PAGESRP0, SerialInitController)
  58. #pragma alloc_text(PAGESRP0, SerialFindInitController)
  59. #pragma alloc_text(PAGESRP0, SerialGetMappedAddress)
  60. #pragma alloc_text(PAGESRP0, SerialRemoveDevObj)
  61. #pragma alloc_text(PAGESRP0, SerialReleaseResources)
  62. #pragma alloc_text(PAGESRP0, SerialUnload)
  63. #pragma alloc_text(PAGESRP0, SerialMemCompare)
  64. //
  65. // PAGESER handled is keyed off of SerialReset, so SerialReset
  66. // must remain in PAGESER for things to work properly
  67. //
  68. #pragma alloc_text(PAGESER, SerialGetDivisorFromBaud)
  69. #pragma alloc_text(PAGESER, SerialReset)
  70. #endif
  71. NTSTATUS
  72. DriverEntry(
  73. IN PDRIVER_OBJECT DriverObject,
  74. IN PUNICODE_STRING RegistryPath
  75. )
  76. /*++
  77. Routine Description:
  78. The entry point that the system point calls to initialize
  79. any driver.
  80. This routine will gather the configuration information,
  81. report resource usage, attempt to initialize all serial
  82. devices, connect to interrupts for ports. If the above
  83. goes reasonably well it will fill in the dispatch points,
  84. reset the serial devices and then return to the system.
  85. Arguments:
  86. DriverObject - Just what it says, really of little use
  87. to the driver itself, it is something that the IO system
  88. cares more about.
  89. PathToRegistry - points to the entry for this driver
  90. in the current control set of the registry.
  91. Return Value:
  92. Always STATUS_SUCCESS
  93. --*/
  94. {
  95. RTL_QUERY_REGISTRY_TABLE jensenTable[2] = {0};
  96. UNICODE_STRING jensenData;
  97. UNICODE_STRING jensenValue;
  98. BOOLEAN jensenDetected;
  99. PUCHAR jensenBuffer;
  100. //
  101. // Lock the paged code in their frames
  102. //
  103. PVOID lockPtr = MmLockPagableCodeSection(SerialReset);
  104. PAGED_CODE();
  105. ASSERT(SerialGlobals.PAGESER_Handle == NULL);
  106. #if DBG
  107. SerialGlobals.PAGESER_Count = 0;
  108. #endif
  109. SerialGlobals.PAGESER_Handle = lockPtr;
  110. SerialGlobals.RegistryPath.MaximumLength = RegistryPath->MaximumLength;
  111. SerialGlobals.RegistryPath.Length = RegistryPath->Length;
  112. SerialGlobals.RegistryPath.Buffer
  113. = ExAllocatePool(PagedPool, SerialGlobals.RegistryPath.MaximumLength);
  114. if (SerialGlobals.RegistryPath.Buffer == NULL) {
  115. MmUnlockPagableImageSection(lockPtr);
  116. return STATUS_INSUFFICIENT_RESOURCES;
  117. }
  118. RtlZeroMemory(SerialGlobals.RegistryPath.Buffer,
  119. SerialGlobals.RegistryPath.MaximumLength);
  120. RtlMoveMemory(SerialGlobals.RegistryPath.Buffer,
  121. RegistryPath->Buffer, RegistryPath->Length);
  122. //
  123. // Initialize all our globals
  124. //
  125. InitializeListHead(&SerialGlobals.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. SerialGetConfigDefaults(&driverDefaults, RegistryPath);
  131. #if DBG
  132. //
  133. // Set global debug output level
  134. //
  135. SerialDebugLevel = 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. SerialDump(SERDIAG1, ("SERIAL: The number of bytes in the extension is: %d"
  147. "\n", sizeof(SERIAL_DEVICE_EXTENSION)));
  148. //
  149. // Initialize the Driver Object with driver's entry points
  150. //
  151. DriverObject->DriverUnload = SerialUnload;
  152. DriverObject->DriverExtension->AddDevice = SerialAddDevice;
  153. DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = SerialFlush;
  154. DriverObject->MajorFunction[IRP_MJ_WRITE] = SerialWrite;
  155. DriverObject->MajorFunction[IRP_MJ_READ] = SerialRead;
  156. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = SerialIoControl;
  157. DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL]
  158. = SerialInternalIoControl;
  159. DriverObject->MajorFunction[IRP_MJ_CREATE] = SerialCreateOpen;
  160. DriverObject->MajorFunction[IRP_MJ_CLOSE] = SerialClose;
  161. DriverObject->MajorFunction[IRP_MJ_CLEANUP] = SerialCleanup;
  162. DriverObject->MajorFunction[IRP_MJ_PNP] = SerialPnpDispatch;
  163. DriverObject->MajorFunction[IRP_MJ_POWER] = SerialPowerDispatch;
  164. DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION]
  165. = SerialQueryInformationFile;
  166. DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION]
  167. = SerialSetInformationFile;
  168. DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL]
  169. = SerialSystemControlDispatch;
  170. if (!(jensenBuffer = ExAllocatePool(
  171. PagedPool,
  172. 512
  173. ))) {
  174. //
  175. // We couldn't allocate 512 bytes of paged pool. If that's
  176. // so, then it's likely that the least of this machine's problems
  177. // is that it's a Jensen.
  178. //
  179. jensenDetected = FALSE;
  180. } else {
  181. //
  182. // Check to see if this is a Jensen alpha. If it is, then
  183. // we'll have to change the way we enable and disable interrupts
  184. //
  185. jensenData.Length = 0;
  186. jensenData.MaximumLength = 512;
  187. jensenData.Buffer = (PWCHAR)&jensenBuffer[0];
  188. RtlInitUnicodeString(
  189. &jensenValue,
  190. L"Jensen"
  191. );
  192. jensenTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT
  193. | RTL_QUERY_REGISTRY_REQUIRED;
  194. jensenTable[0].Name = L"Identifier";
  195. jensenTable[0].EntryContext = &jensenData;
  196. if (!NT_SUCCESS(RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
  197. | RTL_REGISTRY_OPTIONAL,
  198. L"\\REGISTRY\\MACHINE\\HARDWARE"
  199. L"\\DESCRIPTION\\SYSTEM",
  200. &jensenTable[0], NULL, NULL))) {
  201. //
  202. // How odd, no identifer string! We'll it's probably not a jensen.
  203. //
  204. jensenDetected = FALSE;
  205. } else {
  206. //
  207. // Skip past the DEC-XX Portion of the name string.
  208. // Be carful and make sure we have at least that much data.
  209. //
  210. if (jensenData.Length <= (sizeof(WCHAR)*6)) {
  211. jensenDetected = FALSE;
  212. } else {
  213. jensenData.Length -= (sizeof(WCHAR)*6);
  214. jensenData.MaximumLength -= (sizeof(WCHAR)*6);
  215. jensenData.Buffer = (PWCHAR)&jensenBuffer[sizeof(WCHAR)*6];
  216. jensenDetected = RtlEqualUnicodeString(
  217. &jensenData,
  218. &jensenValue,
  219. FALSE
  220. );
  221. }
  222. }
  223. ExFreePool(jensenBuffer);
  224. }
  225. if (jensenDetected) {
  226. SerialDump(
  227. SERDIAG1,
  228. ("SERIAL: Jensen Detected\n")
  229. );
  230. }
  231. driverDefaults.JensenDetected = jensenDetected;
  232. #if defined(NO_LEGACY_DRIVERS)
  233. #define SerialDoLegacyConversion() (0)
  234. #else
  235. #define SerialDoLegacyConversion() (~0)
  236. #endif // NO_LEGACY_DRIVERS
  237. //
  238. // Enumerate and Initialize legacy devices if necessary. This should go away
  239. // and be done by setup.
  240. //
  241. if (SerialDoLegacyConversion()) {
  242. #if DBG
  243. InterlockedIncrement(&SerialGlobals.PAGESER_Count);
  244. #endif
  245. (void)SerialEnumerateLegacy(DriverObject, RegistryPath, &driverDefaults);
  246. #if DBG
  247. InterlockedDecrement(&SerialGlobals.PAGESER_Count);
  248. #endif
  249. }
  250. //
  251. // Unlock pageable text
  252. //
  253. MmUnlockPagableImageSection(lockPtr);
  254. return STATUS_SUCCESS;
  255. }
  256. BOOLEAN
  257. SerialCleanLists(IN PVOID Context)
  258. /*++
  259. Routine Description:
  260. Removes a device object from any of the serial linked lists it may
  261. appear on.
  262. Arguments:
  263. Context - Actually a PSERIAL_DEVICE_EXTENSION (for the devobj being
  264. removed).
  265. Return Value:
  266. Always TRUE
  267. --*/
  268. {
  269. PSERIAL_DEVICE_EXTENSION pDevExt = (PSERIAL_DEVICE_EXTENSION)Context;
  270. //
  271. // If we are a multiport device, remove our entry
  272. //
  273. if (pDevExt->PortOnAMultiportCard) {
  274. PSERIAL_MULTIPORT_DISPATCH pDispatch
  275. = (PSERIAL_MULTIPORT_DISPATCH)pDevExt->OurIsrContext;
  276. SerialDump(SERPNPPOWER,("SERIAL: CLEAN: removing multiport isr ext\n"));
  277. pDispatch->Extensions[pDevExt->PortIndex - 1] = NULL;
  278. if (pDevExt->Indexed == FALSE) {
  279. pDispatch->UsablePortMask &= ~(1 << (pDevExt->PortIndex - 1));
  280. pDispatch->MaskInverted &= ~(pDevExt->NewMaskInverted);
  281. }
  282. }
  283. if (!IsListEmpty(&pDevExt->TopLevelSharers)) {
  284. SerialDump(SERPNPPOWER,("SERIAL: CLEAN: Device is a sharer\n"));
  285. //
  286. // If we have siblings, the first becomes the sharer
  287. //
  288. if (!IsListEmpty(&pDevExt->MultiportSiblings)) {
  289. PSERIAL_DEVICE_EXTENSION pNewRoot;
  290. SerialDump(SERPNPPOWER,("SERIAL: CLEAN: Transferring to siblings\n"));
  291. pNewRoot = CONTAINING_RECORD(pDevExt->MultiportSiblings.Flink,
  292. SERIAL_DEVICE_EXTENSION,
  293. MultiportSiblings);
  294. //
  295. // He should not be on there already
  296. //
  297. ASSERT(IsListEmpty(&pNewRoot->TopLevelSharers));
  298. InsertTailList(&pDevExt->TopLevelSharers, &pNewRoot->TopLevelSharers);
  299. }
  300. //
  301. // Remove ourselves
  302. //
  303. RemoveEntryList(&pDevExt->TopLevelSharers);
  304. InitializeListHead(&pDevExt->TopLevelSharers);
  305. //
  306. // Now check the master list to see if anyone is left...
  307. //
  308. if (!IsListEmpty(&pDevExt->CIsrSw->SharerList)) {
  309. //
  310. // Others are chained on this interrupt, so we don't want to
  311. // disconnect it.
  312. //
  313. pDevExt->Interrupt = NULL;
  314. }
  315. }
  316. //
  317. // If this is part of a multiport board and we still have
  318. // siblings, remove us from that list
  319. //
  320. if (!IsListEmpty(&pDevExt->MultiportSiblings)) {
  321. SerialDump(SERPNPPOWER,("SERIAL: CLEAN: Has multiport siblings\n"));
  322. RemoveEntryList(&pDevExt->MultiportSiblings);
  323. InitializeListHead(&pDevExt->MultiportSiblings);
  324. }
  325. if (!IsListEmpty(&pDevExt->CommonInterruptObject)) {
  326. SerialDump(SERPNPPOWER,("SERIAL: CLEAN: Common intobj member\n"));
  327. RemoveEntryList(&pDevExt->CommonInterruptObject);
  328. InitializeListHead(&pDevExt->CommonInterruptObject);
  329. //
  330. // Others are sharing this interrupt object so we detach ourselves
  331. // from it this way instead of disconnecting.
  332. //
  333. pDevExt->Interrupt = NULL;
  334. }
  335. //
  336. // AllDevObjs should never be empty since we have a sentinal
  337. //
  338. ASSERT(!IsListEmpty(&pDevExt->AllDevObjs));
  339. RemoveEntryList(&pDevExt->AllDevObjs);
  340. InitializeListHead(&pDevExt->AllDevObjs);
  341. return TRUE;
  342. }
  343. VOID
  344. SerialReleaseResources(IN PSERIAL_DEVICE_EXTENSION PDevExt)
  345. /*++
  346. Routine Description:
  347. Releases resources (not pool) stored in the device extension.
  348. Arguments:
  349. PDevExt - Pointer to the device extension to release resources from.
  350. Return Value:
  351. VOID
  352. --*/
  353. {
  354. PAGED_CODE();
  355. SerialDump(SERTRACECALLS,("SERIAL: Enter SerialReleaseResources\n"));
  356. //
  357. // Remove us from any lists we may be on
  358. //
  359. KeSynchronizeExecution(PDevExt->Interrupt, SerialCleanLists, PDevExt);
  360. //
  361. // Stop servicing interrupts if we are the owner
  362. //
  363. if (PDevExt->Interrupt != NULL) {
  364. SerialDump(SERPNPPOWER,("SERIAL: Release - disconnecting interrupt %08X\n",
  365. PDevExt->Interrupt));
  366. IoDisconnectInterrupt(PDevExt->Interrupt);
  367. PDevExt->Interrupt = NULL;
  368. }
  369. if (PDevExt->PortOnAMultiportCard) {
  370. ULONG i;
  371. //
  372. // If we are the last device, free this memory
  373. //
  374. for (i = 0; i < SERIAL_MAX_PORTS_INDEXED; i++) {
  375. if (((PSERIAL_MULTIPORT_DISPATCH)PDevExt->OurIsrContext)
  376. ->Extensions[i] != NULL) {
  377. break;
  378. }
  379. }
  380. if (i == SERIAL_MAX_PORTS_INDEXED) {
  381. SerialDump(SERPNPPOWER,("SERIAL: Release - freeing multi context\n"));
  382. ExFreePool(PDevExt->OurIsrContext);
  383. }
  384. }
  385. //
  386. // Stop handling timers
  387. //
  388. SerialCancelTimer(&PDevExt->ReadRequestTotalTimer, PDevExt);
  389. SerialCancelTimer(&PDevExt->ReadRequestIntervalTimer, PDevExt);
  390. SerialCancelTimer(&PDevExt->WriteRequestTotalTimer, PDevExt);
  391. SerialCancelTimer(&PDevExt->ImmediateTotalTimer, PDevExt);
  392. SerialCancelTimer(&PDevExt->XoffCountTimer, PDevExt);
  393. SerialCancelTimer(&PDevExt->LowerRTSTimer, PDevExt);
  394. //
  395. // Stop servicing DPC's
  396. //
  397. SerialRemoveQueueDpc(&PDevExt->CompleteWriteDpc, PDevExt);
  398. SerialRemoveQueueDpc(&PDevExt->CompleteReadDpc, PDevExt);
  399. SerialRemoveQueueDpc(&PDevExt->TotalReadTimeoutDpc, PDevExt);
  400. SerialRemoveQueueDpc(&PDevExt->IntervalReadTimeoutDpc, PDevExt);
  401. SerialRemoveQueueDpc(&PDevExt->TotalWriteTimeoutDpc, PDevExt);
  402. SerialRemoveQueueDpc(&PDevExt->CommErrorDpc, PDevExt);
  403. SerialRemoveQueueDpc(&PDevExt->CompleteImmediateDpc, PDevExt);
  404. SerialRemoveQueueDpc(&PDevExt->TotalImmediateTimeoutDpc, PDevExt);
  405. SerialRemoveQueueDpc(&PDevExt->CommWaitDpc, PDevExt);
  406. SerialRemoveQueueDpc(&PDevExt->XoffCountTimeoutDpc, PDevExt);
  407. SerialRemoveQueueDpc(&PDevExt->XoffCountCompleteDpc, PDevExt);
  408. SerialRemoveQueueDpc(&PDevExt->StartTimerLowerRTSDpc, PDevExt);
  409. SerialRemoveQueueDpc(&PDevExt->PerhapsLowerRTSDpc, PDevExt);
  410. //
  411. // If necessary, unmap the device registers.
  412. //
  413. if (PDevExt->UnMapRegisters) {
  414. MmUnmapIoSpace(PDevExt->Controller, PDevExt->SpanOfController);
  415. }
  416. if (PDevExt->UnMapStatus) {
  417. MmUnmapIoSpace(PDevExt->InterruptStatus,
  418. PDevExt->SpanOfInterruptStatus);
  419. }
  420. SerialDump(SERTRACECALLS,("SERIAL: Leave SerialReleaseResources\n"));
  421. }
  422. NTSTATUS
  423. SerialPrepareRemove(IN PDEVICE_OBJECT PDevObj)
  424. /*++
  425. Routine Description:
  426. Removes a serial device object from the system.
  427. Arguments:
  428. PDevObj - A pointer to the Device Object we want removed.
  429. Return Value:
  430. Always TRUE
  431. --*/
  432. {
  433. PSERIAL_DEVICE_EXTENSION pDevExt
  434. = (PSERIAL_DEVICE_EXTENSION)PDevObj->DeviceExtension;
  435. POWER_STATE state;
  436. ULONG pendingIRPs;
  437. PAGED_CODE();
  438. SerialDump(SERTRACECALLS,("SERIAL: Enter SerialPrepareRemove\n"));
  439. //
  440. // Mark as not accepting requests
  441. //
  442. SerialSetAccept(pDevExt, SERIAL_PNPACCEPT_REMOVING);
  443. //
  444. // Complete all pending requests
  445. //
  446. SerialKillPendingIrps(PDevObj);
  447. //
  448. // Wait for any pending requests we raced on.
  449. //
  450. pendingIRPs = InterlockedDecrement(&pDevExt->PendingIRPCnt);
  451. if (pendingIRPs) {
  452. KeWaitForSingleObject(&pDevExt->PendingIRPEvent, Executive, KernelMode,
  453. FALSE, NULL);
  454. }
  455. state.DeviceState = PowerDeviceD3;
  456. PoSetPowerState(PDevObj, DevicePowerState, state);
  457. return TRUE;
  458. }
  459. VOID
  460. SerialDisableInterfacesResources(IN PDEVICE_OBJECT PDevObj,
  461. BOOLEAN DisableUART)
  462. {
  463. PSERIAL_DEVICE_EXTENSION pDevExt
  464. = (PSERIAL_DEVICE_EXTENSION)PDevObj->DeviceExtension;
  465. PAGED_CODE();
  466. SerialDump(SERTRACECALLS,("SERIAL: Enter SerialDisableInterfaces\n"));
  467. //
  468. // Only do these many things if the device has started and still
  469. // has resources allocated
  470. //
  471. if (pDevExt->Flags & SERIAL_FLAGS_STARTED) {
  472. if (!(pDevExt->Flags & SERIAL_FLAGS_STOPPED)) {
  473. if (DisableUART) {
  474. //
  475. // Mask off interrupts
  476. //
  477. DISABLE_ALL_INTERRUPTS(pDevExt->Controller);
  478. }
  479. SerialReleaseResources(pDevExt);
  480. }
  481. //
  482. // Remove us from WMI consideration
  483. //
  484. IoWMIRegistrationControl(PDevObj, WMIREG_ACTION_DEREGISTER);
  485. }
  486. //
  487. // Undo external names
  488. //
  489. SerialUndoExternalNaming(pDevExt);
  490. SerialDump(SERTRACECALLS,("SERIAL: Exit SerialDisableInterfaces\n"));
  491. }
  492. NTSTATUS
  493. SerialRemoveDevObj(IN PDEVICE_OBJECT PDevObj)
  494. /*++
  495. Routine Description:
  496. Removes a serial device object from the system.
  497. Arguments:
  498. PDevObj - A pointer to the Device Object we want removed.
  499. Return Value:
  500. Always TRUE
  501. --*/
  502. {
  503. PSERIAL_DEVICE_EXTENSION pDevExt
  504. = (PSERIAL_DEVICE_EXTENSION)PDevObj->DeviceExtension;
  505. PAGED_CODE();
  506. SerialDump(SERTRACECALLS,("SERIAL: Enter SerialRemoveDevObj\n"));
  507. if (!(pDevExt->DevicePNPAccept & SERIAL_PNPACCEPT_SURPRISE_REMOVING)) {
  508. //
  509. // Disable all external interfaces and release resources
  510. //
  511. SerialDisableInterfacesResources(PDevObj, TRUE);
  512. }
  513. IoDetachDevice(pDevExt->LowerDeviceObject);
  514. //
  515. // Free memory allocated in the extension
  516. //
  517. if (pDevExt->NtNameForPort.Buffer != NULL) {
  518. ExFreePool(pDevExt->NtNameForPort.Buffer);
  519. }
  520. if (pDevExt->DeviceName.Buffer != NULL) {
  521. ExFreePool(pDevExt->DeviceName.Buffer);
  522. }
  523. if (pDevExt->SymbolicLinkName.Buffer != NULL) {
  524. ExFreePool(pDevExt->SymbolicLinkName.Buffer);
  525. }
  526. if (pDevExt->DosName.Buffer != NULL) {
  527. ExFreePool(pDevExt->DosName.Buffer);
  528. }
  529. if (pDevExt->ObjectDirectory.Buffer) {
  530. ExFreePool(pDevExt->ObjectDirectory.Buffer);
  531. }
  532. //
  533. // Delete the devobj
  534. //
  535. IoDeleteDevice(PDevObj);
  536. SerialDump(SERTRACECALLS,("SERIAL: Leave SerialRemoveDevObj\n"));
  537. return STATUS_SUCCESS;
  538. }
  539. VOID
  540. SerialKillPendingIrps(PDEVICE_OBJECT PDevObj)
  541. /*++
  542. Routine Description:
  543. This routine kills any irps pending for the passed device object.
  544. Arguments:
  545. PDevObj - Pointer to the device object whose irps must die.
  546. Return Value:
  547. VOID
  548. --*/
  549. {
  550. PSERIAL_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  551. KIRQL oldIrql;
  552. SerialDump (SERTRACECALLS,("SERIAL: Enter SerialKillPendingIrps\n"));
  553. //
  554. // First kill all the reads and writes.
  555. //
  556. SerialKillAllReadsOrWrites(PDevObj, &pDevExt->WriteQueue,
  557. &pDevExt->CurrentWriteIrp);
  558. SerialKillAllReadsOrWrites(PDevObj, &pDevExt->ReadQueue,
  559. &pDevExt->CurrentReadIrp);
  560. //
  561. // Next get rid of purges.
  562. //
  563. SerialKillAllReadsOrWrites(PDevObj, &pDevExt->PurgeQueue,
  564. &pDevExt->CurrentPurgeIrp);
  565. //
  566. // Get rid of any mask operations.
  567. //
  568. SerialKillAllReadsOrWrites(PDevObj, &pDevExt->MaskQueue,
  569. &pDevExt->CurrentMaskIrp);
  570. //
  571. // Now get rid a pending wait mask irp.
  572. //
  573. IoAcquireCancelSpinLock(&oldIrql);
  574. if (pDevExt->CurrentWaitIrp) {
  575. PDRIVER_CANCEL cancelRoutine;
  576. cancelRoutine = pDevExt->CurrentWaitIrp->CancelRoutine;
  577. pDevExt->CurrentWaitIrp->Cancel = TRUE;
  578. if (cancelRoutine) {
  579. pDevExt->CurrentWaitIrp->CancelIrql = oldIrql;
  580. pDevExt->CurrentWaitIrp->CancelRoutine = NULL;
  581. cancelRoutine(PDevObj, pDevExt->CurrentWaitIrp);
  582. }
  583. } else {
  584. IoReleaseCancelSpinLock(oldIrql);
  585. }
  586. //
  587. // Cancel any pending wait-wake irps
  588. //
  589. if (pDevExt->PendingWakeIrp != NULL) {
  590. IoCancelIrp(pDevExt->PendingWakeIrp);
  591. pDevExt->PendingWakeIrp = NULL;
  592. }
  593. //
  594. // Finally, dump any stalled IRPS
  595. //
  596. SerialKillAllStalled(PDevObj);
  597. SerialDump (SERTRACECALLS,("SERIAL: Leave SerialKillPendingIrps\n"));
  598. }
  599. BOOLEAN
  600. SerialSingleToMulti(PVOID Context)
  601. /*++
  602. Routine Description:
  603. This routine converts a root device set up to be a single port
  604. device to a multiport device while that device is running.
  605. Arguments:
  606. Context - Actually a pointer to the device extension of the root
  607. device we are turning into a multiport device.
  608. Return Value:
  609. Always TRUE
  610. --*/
  611. {
  612. PSERIAL_DEVICE_EXTENSION pDevExt = (PSERIAL_DEVICE_EXTENSION)Context;
  613. PSERIAL_MULTIPORT_DISPATCH pOurIsrContext;
  614. PSERIAL_MULTIPORT_DISPATCH pNewIsrContext
  615. = (PSERIAL_MULTIPORT_DISPATCH)pDevExt->NewExtension;
  616. PVOID isrFunc;
  617. SerialDump (SERTRACECALLS,("SERIAL: Enter SerialSingleToMulti\n"));
  618. //
  619. // Stomp OurIsrContext since we are going from one to many
  620. // thus our previous context was just pDevExt and doesn't
  621. // need to be released (i.e., no call to ExFreePool() is needed).
  622. //
  623. pOurIsrContext = pDevExt->OurIsrContext = pDevExt->TopLevelOurIsrContext
  624. = pNewIsrContext;
  625. //
  626. // We are now multiport
  627. //
  628. pDevExt->PortOnAMultiportCard = TRUE;
  629. //
  630. // Update our personal extensions slot
  631. //
  632. pOurIsrContext->Extensions[pDevExt->PortIndex - 1] = pDevExt;
  633. pOurIsrContext->InterruptStatus = pDevExt->InterruptStatus;
  634. //
  635. // We have to pick a new ISR and a new context.
  636. // As soon as this is done, the ISR will change, so we have to
  637. // be ready to handle things there.
  638. //
  639. if (pDevExt->Indexed == FALSE) {
  640. pOurIsrContext->UsablePortMask = 1 << (pDevExt->PortIndex - 1);
  641. pOurIsrContext->MaskInverted = pDevExt->MaskInverted;
  642. isrFunc = SerialBitMappedMultiportIsr;
  643. } else {
  644. isrFunc = SerialIndexedMultiportIsr;
  645. }
  646. pDevExt->OurIsr = isrFunc;
  647. pDevExt->TopLevelOurIsr = isrFunc;
  648. if (pDevExt->CIsrSw->IsrFunc != SerialSharerIsr) {
  649. pDevExt->CIsrSw->IsrFunc = isrFunc;
  650. pDevExt->CIsrSw->Context = pOurIsrContext;
  651. }
  652. SerialDump (SERTRACECALLS,("SERIAL: Leave SerialSingleToMulti\n"));
  653. return TRUE;
  654. }
  655. BOOLEAN
  656. SerialAddToMulti(PVOID Context)
  657. /*++
  658. Routine Description:
  659. This routine adds a new port to a multiport device while that device is
  660. running.
  661. Arguments:
  662. Context - Actually a pointer to the device extension of the root
  663. device we are adding a port to.
  664. Return Value:
  665. Always TRUE
  666. --*/
  667. {
  668. PSERIAL_DEVICE_EXTENSION pDevExt = (PSERIAL_DEVICE_EXTENSION)Context;
  669. PSERIAL_MULTIPORT_DISPATCH pOurIsrContext
  670. = (PSERIAL_MULTIPORT_DISPATCH)pDevExt->OurIsrContext;
  671. PSERIAL_DEVICE_EXTENSION pNewExt
  672. = (PSERIAL_DEVICE_EXTENSION)pDevExt->NewExtension;
  673. SerialDump (SERTRACECALLS,("SERIAL: Enter SerialAddToMulti\n"));
  674. if (pDevExt->Indexed == FALSE) {
  675. pOurIsrContext->UsablePortMask |= 1 << (pDevExt->NewPortIndex - 1);
  676. pOurIsrContext->MaskInverted |= pDevExt->NewMaskInverted;
  677. }
  678. //
  679. // Add us to the linked list of common interrupt objects if we are not
  680. // already in it. We may be if there is another device besides our
  681. // multiport card.
  682. //
  683. if (IsListEmpty(&pNewExt->CommonInterruptObject)) {
  684. InsertTailList(&pDevExt->CommonInterruptObject,
  685. &pNewExt->CommonInterruptObject);
  686. }
  687. //
  688. // Give us the list of contexts also
  689. //
  690. pNewExt->OurIsrContext = pOurIsrContext;
  691. //
  692. // Add us to the list of our siblings
  693. //
  694. InsertTailList(&pDevExt->MultiportSiblings, &pNewExt->MultiportSiblings);
  695. SerialDump(SERDIAG1, ("SERIAL: Adding to multi...\n"));
  696. SerialDump(SERDIAG1, ("------: old ext %x\n", pDevExt));
  697. //
  698. // Map us in so the ISR can find us.
  699. //
  700. pOurIsrContext->Extensions[pDevExt->NewPortIndex - 1]
  701. = pDevExt->NewExtension;
  702. pNewExt->TopLevelOurIsr = pDevExt->TopLevelOurIsr;
  703. pNewExt->TopLevelOurIsrContext = pDevExt->TopLevelOurIsrContext;
  704. SerialDump (SERTRACECALLS,("SERIAL: Leave SerialAddToMulti\n"));
  705. return TRUE;
  706. }
  707. NTSTATUS
  708. SerialInitMultiPort(IN PSERIAL_DEVICE_EXTENSION PDevExt,
  709. IN PCONFIG_DATA PConfigData, IN PDEVICE_OBJECT PDevObj)
  710. /*++
  711. Routine Description:
  712. This routine initializes a multiport device by adding a port to an existing
  713. one.
  714. Arguments:
  715. PDevExt - pointer to the device extension of the root of the multiport
  716. device.
  717. PConfigData - pointer to the config data for the new port
  718. PDevObj - pointer to the devobj for the new port
  719. Return Value:
  720. STATUS_SUCCESS on success, appropriate error on failure.
  721. --*/
  722. {
  723. PSERIAL_DEVICE_EXTENSION pOurIsrContext
  724. = (PSERIAL_DEVICE_EXTENSION)PDevExt->OurIsrContext;
  725. PSERIAL_DEVICE_EXTENSION pNewExt
  726. = (PSERIAL_DEVICE_EXTENSION)PDevObj->DeviceExtension;
  727. NTSTATUS status;
  728. PSERIAL_MULTIPORT_DISPATCH pDispatch;
  729. PAGED_CODE();
  730. SerialDump (SERTRACECALLS,("SERIAL: Enter SerialInitMultiPort\n"));
  731. //
  732. // Allow him to share our CISRsw and interrupt object
  733. //
  734. pNewExt->CIsrSw = PDevExt->CIsrSw;
  735. pNewExt->Interrupt = PDevExt->Interrupt;
  736. //
  737. // First, see if we can initialize the one we have found
  738. //
  739. status = SerialInitOneController(PDevObj, PConfigData);
  740. if (!NT_SUCCESS(status)) {
  741. SerialDump (SERTRACECALLS,("SERIAL: Leave SerialInitMultiPort\n"));
  742. return status;
  743. }
  744. //
  745. // OK. He's good to go. Find the root controller. He may
  746. // currently be a single, so we have to change him to multi.
  747. //
  748. if (PDevExt->PortOnAMultiportCard != TRUE) {
  749. pDispatch = PDevExt->NewExtension
  750. = ExAllocatePool(NonPagedPool, sizeof(SERIAL_MULTIPORT_DISPATCH));
  751. if (pDispatch == NULL) {
  752. // FAIL and CLEANUP
  753. SerialDump (SERTRACECALLS,("SERIAL: Leave SerialInitMultiPort\n"));
  754. return STATUS_INSUFFICIENT_RESOURCES;
  755. }
  756. RtlZeroMemory(pDispatch, sizeof(*pDispatch));
  757. KeSynchronizeExecution(PDevExt->Interrupt, SerialSingleToMulti, PDevExt);
  758. }
  759. //
  760. // Update some important fields
  761. //
  762. ((PSERIAL_DEVICE_EXTENSION)PDevObj->DeviceExtension)->PortOnAMultiportCard
  763. = TRUE;
  764. ((PSERIAL_DEVICE_EXTENSION)PDevObj->DeviceExtension)->OurIsr = NULL;
  765. PDevExt->NewPortIndex = PConfigData->PortIndex;
  766. PDevExt->NewMaskInverted = PConfigData->MaskInverted;
  767. PDevExt->NewExtension = PDevObj->DeviceExtension;
  768. //
  769. // Now, we can add the new guy. He will be hooked in
  770. // immediately, so we need to be able to handle interrupts.
  771. //
  772. KeSynchronizeExecution(PDevExt->Interrupt, SerialAddToMulti, PDevExt);
  773. SerialDump (SERTRACECALLS,("SERIAL: Leave SerialInitMultiPort\n"));
  774. return STATUS_SUCCESS;
  775. }
  776. NTSTATUS
  777. SerialInitController(IN PDEVICE_OBJECT PDevObj, IN PCONFIG_DATA PConfigData)
  778. /*++
  779. Routine Description:
  780. Really too many things to mention here. In general initializes
  781. kernel synchronization structures, allocates the typeahead buffer,
  782. sets up defaults, etc.
  783. Arguments:
  784. PDevObj - Device object for the device to be started
  785. PConfigData - Pointer to a record for a single port.
  786. Return Value:
  787. STATUS_SUCCCESS if everything went ok. A !NT_SUCCESS status
  788. otherwise.
  789. --*/
  790. {
  791. PSERIAL_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  792. #if defined(NEC_98)
  793. PSERIAL_DEVICE_EXTENSION Extension = PDevObj->DeviceExtension;
  794. #else
  795. #endif //defined(NEC_98)
  796. //
  797. // This will hold the string that we need to use to describe
  798. // the name of the device to the IO system.
  799. //
  800. UNICODE_STRING uniNameString;
  801. //
  802. // Holds the NT Status that is returned from each call to the
  803. // kernel and executive.
  804. //
  805. NTSTATUS status = STATUS_SUCCESS;
  806. //
  807. // Indicates that a conflict was detected for resources
  808. // used by this device.
  809. //
  810. BOOLEAN conflictDetected = FALSE;
  811. //
  812. // Indicates if we allocated an ISR switch
  813. //
  814. BOOLEAN allocedISRSw = FALSE;
  815. PAGED_CODE();
  816. SerialDump(
  817. SERDIAG1,
  818. ("SERIAL: Initializing for configuration record of %wZ\n",
  819. &pDevExt->DeviceName)
  820. );
  821. //
  822. // This compare is done using **untranslated** values since that is what
  823. // the kernel shoves in regardless of the architecture.
  824. //
  825. if ((*KdComPortInUse) == ((PUCHAR)(PConfigData->Controller.LowPart))) {
  826. SerialDump(SERERRORS, ("SERIAL: Kernel debugger is using port at address "
  827. "%x\n"
  828. "------ Serial driver will not load port\n",
  829. *KdComPortInUse));
  830. SerialLogError(
  831. PDevObj->DriverObject,
  832. NULL,
  833. PConfigData->TrController,
  834. SerialPhysicalZero,
  835. 0,
  836. 0,
  837. 0,
  838. 3,
  839. STATUS_SUCCESS,
  840. SERIAL_KERNEL_DEBUGGER_ACTIVE,
  841. pDevExt->DeviceName.Length+sizeof(WCHAR),
  842. pDevExt->DeviceName.Buffer,
  843. 0,
  844. NULL
  845. );
  846. return STATUS_INSUFFICIENT_RESOURCES;
  847. }
  848. if (pDevExt->CIsrSw == NULL) {
  849. if ((pDevExt->CIsrSw
  850. = ExAllocatePool(NonPagedPool, sizeof(SERIAL_CISR_SW))) == NULL) {
  851. return STATUS_INSUFFICIENT_RESOURCES;
  852. }
  853. InitializeListHead(&pDevExt->CIsrSw->SharerList);
  854. allocedISRSw = TRUE;
  855. }
  856. #if defined(NEC_98)
  857. //
  858. // intiallize device extension
  859. //
  860. pDevExt->DivisorLatch16550 = 0;
  861. pDevExt->ModemControl16550 = 0;
  862. pDevExt->LineControl16550 = SERIAL_8_DATA;
  863. pDevExt->ModeSet71051 = 0;
  864. pDevExt->CommandSet71051 = COMMAND_DEFAULT_SET;
  865. #else
  866. #endif //defined(NEC_98)
  867. //
  868. // Propagate that it is a jensen.
  869. //
  870. pDevExt->Jensen = PConfigData->Jensen;
  871. //
  872. // Initialize the spinlock associated with fields read (& set)
  873. // by IO Control functions and the flags spinlock.
  874. //
  875. KeInitializeSpinLock(&pDevExt->ControlLock);
  876. KeInitializeSpinLock(&pDevExt->FlagsLock);
  877. //
  878. // Initialize the timers used to timeout operations.
  879. //
  880. KeInitializeTimer(&pDevExt->ReadRequestTotalTimer);
  881. KeInitializeTimer(&pDevExt->ReadRequestIntervalTimer);
  882. KeInitializeTimer(&pDevExt->WriteRequestTotalTimer);
  883. KeInitializeTimer(&pDevExt->ImmediateTotalTimer);
  884. KeInitializeTimer(&pDevExt->XoffCountTimer);
  885. KeInitializeTimer(&pDevExt->LowerRTSTimer);
  886. //
  887. // Intialialize the dpcs that will be used to complete
  888. // or timeout various IO operations.
  889. //
  890. KeInitializeDpc(&pDevExt->CompleteWriteDpc, SerialCompleteWrite, pDevExt);
  891. KeInitializeDpc(&pDevExt->CompleteReadDpc, SerialCompleteRead, pDevExt);
  892. KeInitializeDpc(&pDevExt->TotalReadTimeoutDpc, SerialReadTimeout, pDevExt);
  893. KeInitializeDpc(&pDevExt->IntervalReadTimeoutDpc, SerialIntervalReadTimeout,
  894. pDevExt);
  895. KeInitializeDpc(&pDevExt->TotalWriteTimeoutDpc, SerialWriteTimeout, pDevExt);
  896. KeInitializeDpc(&pDevExt->CommErrorDpc, SerialCommError, pDevExt);
  897. KeInitializeDpc(&pDevExt->CompleteImmediateDpc, SerialCompleteImmediate,
  898. pDevExt);
  899. KeInitializeDpc(&pDevExt->TotalImmediateTimeoutDpc, SerialTimeoutImmediate,
  900. pDevExt);
  901. KeInitializeDpc(&pDevExt->CommWaitDpc, SerialCompleteWait, pDevExt);
  902. KeInitializeDpc(&pDevExt->XoffCountTimeoutDpc, SerialTimeoutXoff, pDevExt);
  903. KeInitializeDpc(&pDevExt->XoffCountCompleteDpc, SerialCompleteXoff, pDevExt);
  904. KeInitializeDpc(&pDevExt->StartTimerLowerRTSDpc, SerialStartTimerLowerRTS,
  905. pDevExt);
  906. KeInitializeDpc(&pDevExt->PerhapsLowerRTSDpc, SerialInvokePerhapsLowerRTS,
  907. pDevExt);
  908. KeInitializeDpc(&pDevExt->IsrUnlockPagesDpc, SerialUnlockPages, pDevExt);
  909. #if 0 // DBG
  910. //
  911. // Init debug stuff
  912. //
  913. pDevExt->DpcQueued[0].Dpc = &pDevExt->CompleteWriteDpc;
  914. pDevExt->DpcQueued[1].Dpc = &pDevExt->CompleteReadDpc;
  915. pDevExt->DpcQueued[2].Dpc = &pDevExt->TotalReadTimeoutDpc;
  916. pDevExt->DpcQueued[3].Dpc = &pDevExt->IntervalReadTimeoutDpc;
  917. pDevExt->DpcQueued[4].Dpc = &pDevExt->TotalWriteTimeoutDpc;
  918. pDevExt->DpcQueued[5].Dpc = &pDevExt->CommErrorDpc;
  919. pDevExt->DpcQueued[6].Dpc = &pDevExt->CompleteImmediateDpc;
  920. pDevExt->DpcQueued[7].Dpc = &pDevExt->TotalImmediateTimeoutDpc;
  921. pDevExt->DpcQueued[8].Dpc = &pDevExt->CommWaitDpc;
  922. pDevExt->DpcQueued[9].Dpc = &pDevExt->XoffCountTimeoutDpc;
  923. pDevExt->DpcQueued[10].Dpc = &pDevExt->XoffCountCompleteDpc;
  924. pDevExt->DpcQueued[11].Dpc = &pDevExt->StartTimerLowerRTSDpc;
  925. pDevExt->DpcQueued[12].Dpc = &pDevExt->PerhapsLowerRTSDpc;
  926. pDevExt->DpcQueued[13].Dpc = &pDevExt->IsrUnlockPagesDpc;
  927. #endif
  928. if (!((PConfigData->ClockRate == 1843200) ||
  929. (PConfigData->ClockRate == 3072000) ||
  930. (PConfigData->ClockRate == 4233600) ||
  931. (PConfigData->ClockRate == 8000000))) {
  932. SerialLogError(
  933. PDevObj->DriverObject,
  934. PDevObj,
  935. PConfigData->TrController,
  936. SerialPhysicalZero,
  937. 0,
  938. 0,
  939. 0,
  940. 6,
  941. STATUS_SUCCESS,
  942. SERIAL_UNSUPPORTED_CLOCK_RATE,
  943. pDevExt->DeviceName.Length+sizeof(WCHAR),
  944. pDevExt->DeviceName.Buffer,
  945. 0,
  946. NULL
  947. );
  948. SerialDump(
  949. SERERRORS,
  950. ("SERIAL: Invalid clock rate specified for %wZ\n",
  951. &pDevExt->DeviceName)
  952. );
  953. status = STATUS_SERIAL_NO_DEVICE_INITED;
  954. goto ExtensionCleanup;
  955. }
  956. //
  957. // Save the value of clock input to the part. We use this to calculate
  958. // the divisor latch value. The value is in Hertz.
  959. //
  960. pDevExt->ClockRate = PConfigData->ClockRate;
  961. //
  962. // Map the memory for the control registers for the serial device
  963. // into virtual memory.
  964. //
  965. pDevExt->Controller =
  966. SerialGetMappedAddress(PConfigData->InterfaceType,
  967. PConfigData->BusNumber,
  968. PConfigData->TrController,
  969. PConfigData->SpanOfController,
  970. (BOOLEAN)PConfigData->AddressSpace,
  971. &pDevExt->UnMapRegisters);
  972. if (!pDevExt->Controller) {
  973. SerialLogError(
  974. PDevObj->DriverObject,
  975. pDevExt->DeviceObject,
  976. PConfigData->TrController,
  977. SerialPhysicalZero,
  978. 0,
  979. 0,
  980. 0,
  981. 7,
  982. STATUS_SUCCESS,
  983. SERIAL_REGISTERS_NOT_MAPPED,
  984. pDevExt->DeviceName.Length+sizeof(WCHAR),
  985. pDevExt->DeviceName.Buffer,
  986. 0,
  987. NULL
  988. );
  989. SerialDump(
  990. SERERRORS,
  991. ("SERIAL: Could not map memory for device registers for %wZ\n",
  992. &pDevExt->DeviceName)
  993. );
  994. pDevExt->UnMapRegisters = FALSE;
  995. status = STATUS_NONE_MAPPED;
  996. goto ExtensionCleanup;
  997. }
  998. pDevExt->AddressSpace = PConfigData->AddressSpace;
  999. pDevExt->OriginalController = PConfigData->Controller;
  1000. pDevExt->SpanOfController = PConfigData->SpanOfController;
  1001. //
  1002. // if we have an interrupt status then map it.
  1003. //
  1004. pDevExt->InterruptStatus =
  1005. (PUCHAR)PConfigData->TrInterruptStatus.QuadPart;
  1006. if (pDevExt->InterruptStatus) {
  1007. pDevExt->InterruptStatus
  1008. = SerialGetMappedAddress(PConfigData->InterfaceType,
  1009. PConfigData->BusNumber,
  1010. PConfigData->TrInterruptStatus,
  1011. PConfigData->SpanOfInterruptStatus,
  1012. (BOOLEAN)PConfigData->AddressSpace,
  1013. &pDevExt->UnMapStatus);
  1014. if (!pDevExt->InterruptStatus) {
  1015. SerialLogError(
  1016. PDevObj->DriverObject,
  1017. PDevObj,
  1018. PConfigData->TrController,
  1019. SerialPhysicalZero,
  1020. 0,
  1021. 0,
  1022. 0,
  1023. 8,
  1024. STATUS_SUCCESS,
  1025. SERIAL_REGISTERS_NOT_MAPPED,
  1026. pDevExt->DeviceName.Length+sizeof(WCHAR),
  1027. pDevExt->DeviceName.Buffer,
  1028. 0,
  1029. NULL
  1030. );
  1031. SerialDump(SERERRORS, ("SERIAL: Could not map memory for interrupt "
  1032. "status for %wZ\n",
  1033. &pDevExt->DeviceName));
  1034. //
  1035. // Manually unmap the other register here if necessary
  1036. //
  1037. if (pDevExt->UnMapRegisters) {
  1038. MmUnmapIoSpace((PVOID)PConfigData->TrController.QuadPart,
  1039. PConfigData->SpanOfController);
  1040. }
  1041. pDevExt->UnMapRegisters = FALSE;
  1042. pDevExt->UnMapStatus = FALSE;
  1043. status = STATUS_NONE_MAPPED;
  1044. goto ExtensionCleanup;
  1045. }
  1046. pDevExt->OriginalInterruptStatus = PConfigData->InterruptStatus;
  1047. pDevExt->SpanOfInterruptStatus = PConfigData->SpanOfInterruptStatus;
  1048. }
  1049. //
  1050. // Shareable interrupt?
  1051. //
  1052. if ((BOOLEAN)PConfigData->PermitSystemWideShare) {
  1053. pDevExt->InterruptShareable = TRUE;
  1054. }
  1055. //
  1056. // Save off the interface type and the bus number.
  1057. //
  1058. pDevExt->InterfaceType = PConfigData->InterfaceType;
  1059. pDevExt->BusNumber = PConfigData->BusNumber;
  1060. pDevExt->PortIndex = PConfigData->PortIndex;
  1061. pDevExt->Indexed = (BOOLEAN)PConfigData->Indexed;
  1062. pDevExt->MaskInverted = PConfigData->MaskInverted;
  1063. //
  1064. // Get the translated interrupt vector, level, and affinity
  1065. //
  1066. pDevExt->OriginalIrql = PConfigData->OriginalIrql;
  1067. pDevExt->OriginalVector = PConfigData->OriginalVector;
  1068. //
  1069. // PnP uses the passed translated values rather than calling
  1070. // HalGetInterruptVector()
  1071. //
  1072. pDevExt->Vector = PConfigData->TrVector;
  1073. pDevExt->Irql = (UCHAR)PConfigData->TrIrql;
  1074. //
  1075. // Set up the Isr.
  1076. //
  1077. pDevExt->OurIsr = SerialISR;
  1078. pDevExt->OurIsrContext = pDevExt;
  1079. //
  1080. // If the user said to permit sharing within the device, propagate this
  1081. // through.
  1082. //
  1083. pDevExt->PermitShare = PConfigData->PermitShare;
  1084. //
  1085. // Before we test whether the port exists (which will enable the FIFO)
  1086. // convert the rx trigger value to what should be used in the register.
  1087. //
  1088. // If a bogus value was given - crank them down to 1.
  1089. //
  1090. switch (PConfigData->RxFIFO) {
  1091. case 1:
  1092. pDevExt->RxFifoTrigger = SERIAL_1_BYTE_HIGH_WATER;
  1093. break;
  1094. case 4:
  1095. pDevExt->RxFifoTrigger = SERIAL_4_BYTE_HIGH_WATER;
  1096. break;
  1097. case 8:
  1098. pDevExt->RxFifoTrigger = SERIAL_8_BYTE_HIGH_WATER;
  1099. break;
  1100. case 14:
  1101. pDevExt->RxFifoTrigger = SERIAL_14_BYTE_HIGH_WATER;
  1102. break;
  1103. default:
  1104. pDevExt->RxFifoTrigger = SERIAL_1_BYTE_HIGH_WATER;
  1105. break;
  1106. }
  1107. if ((PConfigData->TxFIFO > 16) ||
  1108. (PConfigData->TxFIFO < 1)) {
  1109. pDevExt->TxFifoAmount = 1;
  1110. } else {
  1111. pDevExt->TxFifoAmount = PConfigData->TxFIFO;
  1112. }
  1113. if (!SerialDoesPortExist(
  1114. pDevExt,
  1115. &pDevExt->DeviceName,
  1116. PConfigData->ForceFifoEnable,
  1117. PConfigData->LogFifo
  1118. )) {
  1119. //
  1120. // We couldn't verify that there was actually a
  1121. // port. No need to log an error as the port exist
  1122. // code will log exactly why.
  1123. //
  1124. SerialDump(
  1125. SERERRORS,
  1126. ("SERIAL: Does Port exist test failed for %wZ\n",
  1127. &pDevExt->DeviceName)
  1128. );
  1129. status = STATUS_NO_SUCH_DEVICE;
  1130. goto ExtensionCleanup;
  1131. }
  1132. //
  1133. // If the user requested that we disable the port, then
  1134. // do it now. Log the fact that the port has been disabled.
  1135. //
  1136. if (PConfigData->DisablePort) {
  1137. SerialDump(
  1138. SERERRORS,
  1139. ("SERIAL: disabled port %wZ as requested in configuration\n",
  1140. &pDevExt->DeviceName)
  1141. );
  1142. status = STATUS_NO_SUCH_DEVICE;
  1143. SerialLogError(
  1144. PDevObj->DriverObject,
  1145. PDevObj,
  1146. PConfigData->Controller,
  1147. SerialPhysicalZero,
  1148. 0,
  1149. 0,
  1150. 0,
  1151. 57,
  1152. STATUS_SUCCESS,
  1153. SERIAL_DISABLED_PORT,
  1154. pDevExt->DeviceName.Length+sizeof(WCHAR),
  1155. pDevExt->DeviceName.Buffer,
  1156. 0,
  1157. NULL
  1158. );
  1159. goto ExtensionCleanup;
  1160. }
  1161. //
  1162. // Set up the default device control fields.
  1163. // Note that if the values are changed after
  1164. // the file is open, they do NOT revert back
  1165. // to the old value at file close.
  1166. //
  1167. pDevExt->SpecialChars.XonChar = SERIAL_DEF_XON;
  1168. pDevExt->SpecialChars.XoffChar = SERIAL_DEF_XOFF;
  1169. pDevExt->HandFlow.ControlHandShake = SERIAL_DTR_CONTROL;
  1170. pDevExt->HandFlow.FlowReplace = SERIAL_RTS_CONTROL;
  1171. //
  1172. // Default Line control protocol. 7E1
  1173. //
  1174. // Seven data bits.
  1175. // Even parity.
  1176. // 1 Stop bits.
  1177. //
  1178. pDevExt->LineControl = SERIAL_7_DATA |
  1179. SERIAL_EVEN_PARITY |
  1180. SERIAL_NONE_PARITY;
  1181. pDevExt->ValidDataMask = 0x7f;
  1182. pDevExt->CurrentBaud = 1200;
  1183. //
  1184. // We set up the default xon/xoff limits.
  1185. //
  1186. // This may be a bogus value. It looks like the BufferSize
  1187. // is not set up until the device is actually opened.
  1188. //
  1189. pDevExt->HandFlow.XoffLimit = pDevExt->BufferSize >> 3;
  1190. pDevExt->HandFlow.XonLimit = pDevExt->BufferSize >> 1;
  1191. pDevExt->BufferSizePt8 = ((3*(pDevExt->BufferSize>>2))+
  1192. (pDevExt->BufferSize>>4));
  1193. SerialDump(
  1194. SERDIAG1,
  1195. ("SERIAL: The default interrupt read buffer size is: %d\n"
  1196. "------ The XoffLimit is : %d\n"
  1197. "------ The XonLimit is : %d\n"
  1198. "------ The pt 8 size is : %d\n",
  1199. pDevExt->BufferSize,
  1200. pDevExt->HandFlow.XoffLimit,
  1201. pDevExt->HandFlow.XonLimit,
  1202. pDevExt->BufferSizePt8)
  1203. );
  1204. //
  1205. // Go through all the "named" baud rates to find out which ones
  1206. // can be supported with this port.
  1207. //
  1208. pDevExt->SupportedBauds = SERIAL_BAUD_USER;
  1209. {
  1210. SHORT junk;
  1211. if (!NT_ERROR(SerialGetDivisorFromBaud(
  1212. pDevExt->ClockRate,
  1213. (LONG)75,
  1214. &junk
  1215. ))) {
  1216. pDevExt->SupportedBauds |= SERIAL_BAUD_075;
  1217. }
  1218. if (!NT_ERROR(SerialGetDivisorFromBaud(
  1219. pDevExt->ClockRate,
  1220. (LONG)110,
  1221. &junk
  1222. ))) {
  1223. pDevExt->SupportedBauds |= SERIAL_BAUD_110;
  1224. }
  1225. if (!NT_ERROR(SerialGetDivisorFromBaud(
  1226. pDevExt->ClockRate,
  1227. (LONG)135,
  1228. &junk
  1229. ))) {
  1230. pDevExt->SupportedBauds |= SERIAL_BAUD_134_5;
  1231. }
  1232. if (!NT_ERROR(SerialGetDivisorFromBaud(
  1233. pDevExt->ClockRate,
  1234. (LONG)150,
  1235. &junk
  1236. ))) {
  1237. pDevExt->SupportedBauds |= SERIAL_BAUD_150;
  1238. }
  1239. if (!NT_ERROR(SerialGetDivisorFromBaud(
  1240. pDevExt->ClockRate,
  1241. (LONG)300,
  1242. &junk
  1243. ))) {
  1244. pDevExt->SupportedBauds |= SERIAL_BAUD_300;
  1245. }
  1246. if (!NT_ERROR(SerialGetDivisorFromBaud(
  1247. pDevExt->ClockRate,
  1248. (LONG)600,
  1249. &junk
  1250. ))) {
  1251. pDevExt->SupportedBauds |= SERIAL_BAUD_600;
  1252. }
  1253. if (!NT_ERROR(SerialGetDivisorFromBaud(
  1254. pDevExt->ClockRate,
  1255. (LONG)1200,
  1256. &junk
  1257. ))) {
  1258. pDevExt->SupportedBauds |= SERIAL_BAUD_1200;
  1259. }
  1260. if (!NT_ERROR(SerialGetDivisorFromBaud(
  1261. pDevExt->ClockRate,
  1262. (LONG)1800,
  1263. &junk
  1264. ))) {
  1265. pDevExt->SupportedBauds |= SERIAL_BAUD_1800;
  1266. }
  1267. if (!NT_ERROR(SerialGetDivisorFromBaud(
  1268. pDevExt->ClockRate,
  1269. (LONG)2400,
  1270. &junk
  1271. ))) {
  1272. pDevExt->SupportedBauds |= SERIAL_BAUD_2400;
  1273. }
  1274. if (!NT_ERROR(SerialGetDivisorFromBaud(
  1275. pDevExt->ClockRate,
  1276. (LONG)4800,
  1277. &junk
  1278. ))) {
  1279. pDevExt->SupportedBauds |= SERIAL_BAUD_4800;
  1280. }
  1281. if (!NT_ERROR(SerialGetDivisorFromBaud(
  1282. pDevExt->ClockRate,
  1283. (LONG)7200,
  1284. &junk
  1285. ))) {
  1286. pDevExt->SupportedBauds |= SERIAL_BAUD_7200;
  1287. }
  1288. if (!NT_ERROR(SerialGetDivisorFromBaud(
  1289. pDevExt->ClockRate,
  1290. (LONG)9600,
  1291. &junk
  1292. ))) {
  1293. pDevExt->SupportedBauds |= SERIAL_BAUD_9600;
  1294. }
  1295. if (!NT_ERROR(SerialGetDivisorFromBaud(
  1296. pDevExt->ClockRate,
  1297. (LONG)14400,
  1298. &junk
  1299. ))) {
  1300. pDevExt->SupportedBauds |= SERIAL_BAUD_14400;
  1301. }
  1302. if (!NT_ERROR(SerialGetDivisorFromBaud(
  1303. pDevExt->ClockRate,
  1304. (LONG)19200,
  1305. &junk
  1306. ))) {
  1307. pDevExt->SupportedBauds |= SERIAL_BAUD_19200;
  1308. }
  1309. if (!NT_ERROR(SerialGetDivisorFromBaud(
  1310. pDevExt->ClockRate,
  1311. (LONG)38400,
  1312. &junk
  1313. ))) {
  1314. pDevExt->SupportedBauds |= SERIAL_BAUD_38400;
  1315. }
  1316. if (!NT_ERROR(SerialGetDivisorFromBaud(
  1317. pDevExt->ClockRate,
  1318. (LONG)56000,
  1319. &junk
  1320. ))) {
  1321. pDevExt->SupportedBauds |= SERIAL_BAUD_56K;
  1322. }
  1323. if (!NT_ERROR(SerialGetDivisorFromBaud(
  1324. pDevExt->ClockRate,
  1325. (LONG)57600,
  1326. &junk
  1327. ))) {
  1328. pDevExt->SupportedBauds |= SERIAL_BAUD_57600;
  1329. }
  1330. if (!NT_ERROR(SerialGetDivisorFromBaud(
  1331. pDevExt->ClockRate,
  1332. (LONG)115200,
  1333. &junk
  1334. ))) {
  1335. pDevExt->SupportedBauds |= SERIAL_BAUD_115200;
  1336. }
  1337. if (!NT_ERROR(SerialGetDivisorFromBaud(
  1338. pDevExt->ClockRate,
  1339. (LONG)128000,
  1340. &junk
  1341. ))) {
  1342. pDevExt->SupportedBauds |= SERIAL_BAUD_128K;
  1343. }
  1344. }
  1345. //
  1346. // Mark this device as not being opened by anyone. We keep a
  1347. // variable around so that spurious interrupts are easily
  1348. // dismissed by the ISR.
  1349. //
  1350. pDevExt->DeviceIsOpened = FALSE;
  1351. //
  1352. // Store values into the extension for interval timing.
  1353. //
  1354. //
  1355. // If the interval timer is less than a second then come
  1356. // in with a short "polling" loop.
  1357. //
  1358. // For large (> then 2 seconds) use a 1 second poller.
  1359. //
  1360. pDevExt->ShortIntervalAmount.QuadPart = -1;
  1361. pDevExt->LongIntervalAmount.QuadPart = -10000000;
  1362. pDevExt->CutOverAmount.QuadPart = 200000000;
  1363. //
  1364. // Common error path cleanup. If the status is
  1365. // bad, get rid of the device extension, device object
  1366. // and any memory associated with it.
  1367. //
  1368. ExtensionCleanup: ;
  1369. if (!NT_SUCCESS(status)) {
  1370. if (allocedISRSw) {
  1371. ExFreePool(pDevExt->CIsrSw);
  1372. pDevExt->CIsrSw = NULL;
  1373. }
  1374. if (pDevExt->UnMapRegisters) {
  1375. MmUnmapIoSpace(pDevExt->Controller, pDevExt->SpanOfController);
  1376. }
  1377. if (pDevExt->UnMapStatus) {
  1378. MmUnmapIoSpace(pDevExt->InterruptStatus,
  1379. pDevExt->SpanOfInterruptStatus);
  1380. }
  1381. }
  1382. return status;
  1383. }
  1384. NTSTATUS
  1385. SerialInitOneController(IN PDEVICE_OBJECT PDevObj, IN PCONFIG_DATA PConfigData)
  1386. /*++
  1387. Routine Description:
  1388. This routine will call the real port initialization code. It sets
  1389. up the ISR and Context correctly for a one port device.
  1390. Arguments:
  1391. All args are simply passed along.
  1392. Return Value:
  1393. Status returned from the controller initialization routine.
  1394. --*/
  1395. {
  1396. NTSTATUS status;
  1397. PSERIAL_DEVICE_EXTENSION pDevExt;
  1398. PAGED_CODE();
  1399. status = SerialInitController(PDevObj, PConfigData);
  1400. if (NT_SUCCESS(status)) {
  1401. pDevExt = PDevObj->DeviceExtension;
  1402. //
  1403. // We successfully initialized the single controller.
  1404. // Stick the isr routine and the parameter for it
  1405. // back into the extension.
  1406. //
  1407. pDevExt->OurIsr = SerialISR;
  1408. pDevExt->OurIsrContext = pDevExt;
  1409. pDevExt->TopLevelOurIsr = SerialISR;
  1410. pDevExt->TopLevelOurIsrContext = pDevExt;
  1411. }
  1412. return status;
  1413. }
  1414. BOOLEAN
  1415. SerialDoesPortExist(
  1416. IN PSERIAL_DEVICE_EXTENSION Extension,
  1417. IN PUNICODE_STRING InsertString,
  1418. IN ULONG ForceFifo,
  1419. IN ULONG LogFifo
  1420. )
  1421. /*++
  1422. Routine Description:
  1423. This routine examines several of what might be the serial device
  1424. registers. It ensures that the bits that should be zero are zero.
  1425. In addition, this routine will determine if the device supports
  1426. fifo's. If it does it will enable the fifo's and turn on a boolean
  1427. in the extension that indicates the fifo's presence.
  1428. NOTE: If there is indeed a serial port at the address specified
  1429. it will absolutely have interrupts inhibited upon return
  1430. from this routine.
  1431. NOTE: Since this routine should be called fairly early in
  1432. the device driver initialization, the only element
  1433. that needs to be filled in is the base register address.
  1434. NOTE: These tests all assume that this code is the only
  1435. code that is looking at these ports or this memory.
  1436. This is a not to unreasonable assumption even on
  1437. multiprocessor systems.
  1438. Arguments:
  1439. Extension - A pointer to a serial device extension.
  1440. InsertString - String to place in an error log entry.
  1441. ForceFifo - !0 forces the fifo to be left on if found.
  1442. LogFifo - !0 forces a log message if fifo found.
  1443. Return Value:
  1444. Will return true if the port really exists, otherwise it
  1445. will return false.
  1446. --*/
  1447. {
  1448. UCHAR regContents;
  1449. BOOLEAN returnValue = TRUE;
  1450. UCHAR oldIERContents;
  1451. UCHAR oldLCRContents;
  1452. USHORT value1;
  1453. USHORT value2;
  1454. KIRQL oldIrql;
  1455. //
  1456. // Save of the line control.
  1457. //
  1458. oldLCRContents = READ_LINE_CONTROL(Extension->Controller);
  1459. //
  1460. // Make sure that we are *aren't* accessing the divsior latch.
  1461. //
  1462. WRITE_LINE_CONTROL(
  1463. Extension->Controller,
  1464. (UCHAR)(oldLCRContents & ~SERIAL_LCR_DLAB)
  1465. );
  1466. oldIERContents = READ_INTERRUPT_ENABLE(Extension->Controller);
  1467. //
  1468. // Go up to power level for a very short time to prevent
  1469. // any interrupts from this device from coming in.
  1470. //
  1471. KeRaiseIrql(
  1472. POWER_LEVEL,
  1473. &oldIrql
  1474. );
  1475. WRITE_INTERRUPT_ENABLE(
  1476. Extension->Controller,
  1477. 0x0f
  1478. );
  1479. value1 = READ_INTERRUPT_ENABLE(Extension->Controller);
  1480. value1 = value1 << 8;
  1481. value1 |= READ_RECEIVE_BUFFER(Extension->Controller);
  1482. READ_DIVISOR_LATCH(
  1483. Extension->Controller,
  1484. &value2
  1485. );
  1486. WRITE_LINE_CONTROL(
  1487. Extension->Controller,
  1488. oldLCRContents
  1489. );
  1490. //
  1491. // Put the ier back to where it was before. If we are on a
  1492. // level sensitive port this should prevent the interrupts
  1493. // from coming in. If we are on a latched, we don't care
  1494. // cause the interrupts generated will just get dropped.
  1495. //
  1496. WRITE_INTERRUPT_ENABLE(
  1497. Extension->Controller,
  1498. oldIERContents
  1499. );
  1500. KeLowerIrql(oldIrql);
  1501. if (value1 == value2) {
  1502. SerialLogError(
  1503. Extension->DeviceObject->DriverObject,
  1504. Extension->DeviceObject,
  1505. Extension->OriginalController,
  1506. SerialPhysicalZero,
  1507. 0,
  1508. 0,
  1509. 0,
  1510. 62,
  1511. STATUS_SUCCESS,
  1512. SERIAL_DLAB_INVALID,
  1513. InsertString->Length+sizeof(WCHAR),
  1514. InsertString->Buffer,
  1515. 0,
  1516. NULL
  1517. );
  1518. returnValue = FALSE;
  1519. goto AllDone;
  1520. }
  1521. AllDone: ;
  1522. //
  1523. // If we think that there is a serial device then we determine
  1524. // if a fifo is present.
  1525. //
  1526. if (returnValue) {
  1527. //
  1528. // Well, we think it's a serial device. Absolutely
  1529. // positively, prevent interrupts from occuring.
  1530. //
  1531. // We disable all the interrupt enable bits, and
  1532. // push down all the lines in the modem control
  1533. // We only needed to push down OUT2 which in
  1534. // PC's must also be enabled to get an interrupt.
  1535. //
  1536. DISABLE_ALL_INTERRUPTS(Extension->Controller);
  1537. if (Extension->Jensen) {
  1538. WRITE_MODEM_CONTROL(
  1539. Extension->Controller,
  1540. (UCHAR)SERIAL_MCR_OUT2
  1541. );
  1542. } else {
  1543. WRITE_MODEM_CONTROL(
  1544. Extension->Controller,
  1545. (UCHAR)0
  1546. );
  1547. }
  1548. //
  1549. // See if this is a 16550. We do this by writing to
  1550. // what would be the fifo control register with a bit
  1551. // pattern that tells the device to enable fifo's.
  1552. // We then read the iterrupt Id register to see if the
  1553. // bit pattern is present that identifies the 16550.
  1554. //
  1555. WRITE_FIFO_CONTROL(
  1556. Extension->Controller,
  1557. SERIAL_FCR_ENABLE
  1558. );
  1559. regContents = READ_INTERRUPT_ID_REG(Extension->Controller);
  1560. if (regContents & SERIAL_IIR_FIFOS_ENABLED) {
  1561. //
  1562. // Save off that the device supports fifos.
  1563. //
  1564. Extension->FifoPresent = TRUE;
  1565. //
  1566. // There is a fine new "super" IO chip out there that
  1567. // will get stuck with a line status interrupt if you
  1568. // attempt to clear the fifo and enable it at the same
  1569. // time if data is present. The best workaround seems
  1570. // to be that you should turn off the fifo read a single
  1571. // byte, and then re-enable the fifo.
  1572. //
  1573. WRITE_FIFO_CONTROL(
  1574. Extension->Controller,
  1575. (UCHAR)0
  1576. );
  1577. READ_RECEIVE_BUFFER(Extension->Controller);
  1578. //
  1579. // There are fifos on this card. Set the value of the
  1580. // receive fifo to interrupt when 4 characters are present.
  1581. //
  1582. WRITE_FIFO_CONTROL(Extension->Controller,
  1583. (UCHAR)(SERIAL_FCR_ENABLE
  1584. | Extension->RxFifoTrigger
  1585. | SERIAL_FCR_RCVR_RESET
  1586. | SERIAL_FCR_TXMT_RESET));
  1587. }
  1588. //
  1589. // The !Extension->FifoPresent is included in the test so that
  1590. // broken chips like the WinBond will still work after we test
  1591. // for the fifo.
  1592. //
  1593. if (!ForceFifo || !Extension->FifoPresent) {
  1594. Extension->FifoPresent = FALSE;
  1595. WRITE_FIFO_CONTROL(
  1596. Extension->Controller,
  1597. (UCHAR)0
  1598. );
  1599. }
  1600. if (Extension->FifoPresent) {
  1601. if (LogFifo) {
  1602. SerialLogError(
  1603. Extension->DeviceObject->DriverObject,
  1604. Extension->DeviceObject,
  1605. Extension->OriginalController,
  1606. SerialPhysicalZero,
  1607. 0,
  1608. 0,
  1609. 0,
  1610. 15,
  1611. STATUS_SUCCESS,
  1612. SERIAL_FIFO_PRESENT,
  1613. InsertString->Length+sizeof(WCHAR),
  1614. InsertString->Buffer,
  1615. 0,
  1616. NULL
  1617. );
  1618. }
  1619. SerialDump(
  1620. SERDIAG1,
  1621. ("SERIAL: Fifo's detected at port address: %x\n",
  1622. Extension->Controller)
  1623. );
  1624. }
  1625. //
  1626. // In case we are dealing with a bitmasked multiportcard,
  1627. // that has the mask register enabled, enable the
  1628. // interrupts.
  1629. //
  1630. if (Extension->InterruptStatus) {
  1631. if (Extension->Indexed) {
  1632. WRITE_PORT_UCHAR(Extension->InterruptStatus, (UCHAR)0xFF);
  1633. } else {
  1634. //
  1635. // Either we are standalone or already mapped
  1636. //
  1637. if (Extension->OurIsrContext == Extension) {
  1638. //
  1639. // This is a standalone
  1640. //
  1641. WRITE_PORT_UCHAR(Extension->InterruptStatus,
  1642. (UCHAR)(1 << (Extension->PortIndex - 1)));
  1643. } else {
  1644. //
  1645. // One of many
  1646. //
  1647. WRITE_PORT_UCHAR(Extension->InterruptStatus,
  1648. (UCHAR)((PSERIAL_MULTIPORT_DISPATCH)Extension->
  1649. OurIsrContext)->UsablePortMask);
  1650. }
  1651. }
  1652. }
  1653. }
  1654. return returnValue;
  1655. }
  1656. BOOLEAN
  1657. SerialReset(
  1658. IN PVOID Context
  1659. )
  1660. /*++
  1661. Routine Description:
  1662. This places the hardware in a standard configuration.
  1663. NOTE: This assumes that it is called at interrupt level.
  1664. Arguments:
  1665. Context - The device extension for serial device
  1666. being managed.
  1667. Return Value:
  1668. Always FALSE.
  1669. --*/
  1670. {
  1671. PSERIAL_DEVICE_EXTENSION extension = Context;
  1672. #if defined(NEC_98)
  1673. //
  1674. // This argument use at MACRO only.
  1675. //
  1676. PSERIAL_DEVICE_EXTENSION Extension = Context;
  1677. #else
  1678. #endif //defined(NEC_98)
  1679. UCHAR regContents;
  1680. UCHAR oldModemControl;
  1681. ULONG i;
  1682. SERIAL_LOCKED_PAGED_CODE();
  1683. //
  1684. // Adjust the out2 bit.
  1685. // This will also prevent any interrupts from occuring.
  1686. //
  1687. oldModemControl = READ_MODEM_CONTROL(extension->Controller);
  1688. if (extension->Jensen) {
  1689. WRITE_MODEM_CONTROL(
  1690. extension->Controller,
  1691. (UCHAR)(oldModemControl | SERIAL_MCR_OUT2)
  1692. );
  1693. } else {
  1694. WRITE_MODEM_CONTROL(
  1695. extension->Controller,
  1696. (UCHAR)(oldModemControl & ~SERIAL_MCR_OUT2)
  1697. );
  1698. }
  1699. //
  1700. // Reset the fifo's if there are any.
  1701. //
  1702. if (extension->FifoPresent) {
  1703. //
  1704. // There is a fine new "super" IO chip out there that
  1705. // will get stuck with a line status interrupt if you
  1706. // attempt to clear the fifo and enable it at the same
  1707. // time if data is present. The best workaround seems
  1708. // to be that you should turn off the fifo read a single
  1709. // byte, and then re-enable the fifo.
  1710. //
  1711. WRITE_FIFO_CONTROL(
  1712. extension->Controller,
  1713. (UCHAR)0
  1714. );
  1715. READ_RECEIVE_BUFFER(extension->Controller);
  1716. WRITE_FIFO_CONTROL(
  1717. extension->Controller,
  1718. (UCHAR)(SERIAL_FCR_ENABLE | extension->RxFifoTrigger |
  1719. SERIAL_FCR_RCVR_RESET | SERIAL_FCR_TXMT_RESET)
  1720. );
  1721. }
  1722. //
  1723. // Make sure that the line control set up correct.
  1724. //
  1725. // 1) Make sure that the Divisor latch select is set
  1726. // up to select the transmit and receive register.
  1727. //
  1728. // 2) Make sure that we aren't in a break state.
  1729. //
  1730. regContents = READ_LINE_CONTROL(extension->Controller);
  1731. regContents &= ~(SERIAL_LCR_DLAB | SERIAL_LCR_BREAK);
  1732. WRITE_LINE_CONTROL(
  1733. extension->Controller,
  1734. regContents
  1735. );
  1736. //
  1737. // Read the receive buffer until the line status is
  1738. // clear. (Actually give up after a 5 reads.)
  1739. //
  1740. for (i = 0;
  1741. i < 5;
  1742. i++
  1743. ) {
  1744. if (IsNotNEC_98) {
  1745. READ_RECEIVE_BUFFER(extension->Controller);
  1746. if (!(READ_LINE_STATUS(extension->Controller) & 1)) {
  1747. break;
  1748. }
  1749. } else {
  1750. //
  1751. // I get incorrect data when read enpty buffer.
  1752. // But do not read no data! for PC98!
  1753. //
  1754. if (!(READ_LINE_STATUS(extension->Controller) & 1)) {
  1755. break;
  1756. }
  1757. READ_RECEIVE_BUFFER(extension->Controller);
  1758. }
  1759. }
  1760. //
  1761. // Read the modem status until the low 4 bits are
  1762. // clear. (Actually give up after a 5 reads.)
  1763. //
  1764. for (i = 0;
  1765. i < 1000;
  1766. i++
  1767. ) {
  1768. if (!(READ_MODEM_STATUS(extension->Controller) & 0x0f)) {
  1769. break;
  1770. }
  1771. }
  1772. //
  1773. // Now we set the line control, modem control, and the
  1774. // baud to what they should be.
  1775. //
  1776. SerialSetLineControl(extension);
  1777. SerialSetupNewHandFlow(
  1778. extension,
  1779. &extension->HandFlow
  1780. );
  1781. SerialHandleModemUpdate(
  1782. extension,
  1783. FALSE
  1784. );
  1785. {
  1786. SHORT appropriateDivisor;
  1787. SERIAL_IOCTL_SYNC s;
  1788. SerialGetDivisorFromBaud(
  1789. extension->ClockRate,
  1790. extension->CurrentBaud,
  1791. &appropriateDivisor
  1792. );
  1793. s.Extension = extension;
  1794. s.Data = (PVOID)appropriateDivisor;
  1795. SerialSetBaud(&s);
  1796. }
  1797. //
  1798. // Enable which interrupts we want to receive.
  1799. //
  1800. // NOTE NOTE: This does not actually let interrupts
  1801. // occur. We must still raise the OUT2 bit in the
  1802. // modem control register. We will do that on open.
  1803. //
  1804. ENABLE_ALL_INTERRUPTS(extension->Controller);
  1805. //
  1806. // Read the interrupt id register until the low bit is
  1807. // set. (Actually give up after a 5 reads.)
  1808. //
  1809. for (i = 0;
  1810. i < 5;
  1811. i++
  1812. ) {
  1813. if (READ_INTERRUPT_ID_REG(extension->Controller) & 0x01) {
  1814. break;
  1815. }
  1816. }
  1817. //
  1818. // Now we know that nothing could be transmitting at this point
  1819. // so we set the HoldingEmpty indicator.
  1820. //
  1821. extension->HoldingEmpty = TRUE;
  1822. return FALSE;
  1823. }
  1824. NTSTATUS
  1825. SerialGetDivisorFromBaud(
  1826. IN ULONG ClockRate,
  1827. IN LONG DesiredBaud,
  1828. OUT PSHORT AppropriateDivisor
  1829. )
  1830. /*++
  1831. Routine Description:
  1832. This routine will determine a divisor based on an unvalidated
  1833. baud rate.
  1834. Arguments:
  1835. ClockRate - The clock input to the controller.
  1836. DesiredBaud - The baud rate for whose divisor we seek.
  1837. AppropriateDivisor - Given that the DesiredBaud is valid, the
  1838. LONG pointed to by this parameter will be set to the appropriate
  1839. value. NOTE: The long is undefined if the DesiredBaud is not
  1840. supported.
  1841. Return Value:
  1842. This function will return STATUS_SUCCESS if the baud is supported.
  1843. If the value is not supported it will return a status such that
  1844. NT_ERROR(Status) == FALSE.
  1845. --*/
  1846. {
  1847. NTSTATUS status = STATUS_SUCCESS;
  1848. SHORT calculatedDivisor;
  1849. ULONG denominator;
  1850. ULONG remainder;
  1851. //
  1852. // Allow up to a 1 percent error
  1853. //
  1854. ULONG maxRemain18 = 18432;
  1855. ULONG maxRemain30 = 30720;
  1856. ULONG maxRemain42 = 42336;
  1857. ULONG maxRemain80 = 80000;
  1858. ULONG maxRemain;
  1859. SERIAL_LOCKED_PAGED_CODE();
  1860. //
  1861. // Reject any non-positive bauds.
  1862. //
  1863. denominator = DesiredBaud*(ULONG)16;
  1864. if (DesiredBaud <= 0) {
  1865. *AppropriateDivisor = -1;
  1866. } else if ((LONG)denominator < DesiredBaud) {
  1867. //
  1868. // If the desired baud was so huge that it cause the denominator
  1869. // calculation to wrap, don't support it.
  1870. //
  1871. *AppropriateDivisor = -1;
  1872. } else {
  1873. if (ClockRate == 1843200) {
  1874. maxRemain = maxRemain18;
  1875. } else if (ClockRate == 3072000) {
  1876. maxRemain = maxRemain30;
  1877. } else if (ClockRate == 4233600) {
  1878. maxRemain = maxRemain42;
  1879. } else {
  1880. maxRemain = maxRemain80;
  1881. }
  1882. calculatedDivisor = (SHORT)(ClockRate / denominator);
  1883. remainder = ClockRate % denominator;
  1884. //
  1885. // Round up.
  1886. //
  1887. if (((remainder*2) > ClockRate) && (DesiredBaud != 110)) {
  1888. calculatedDivisor++;
  1889. }
  1890. //
  1891. // Only let the remainder calculations effect us if
  1892. // the baud rate is > 9600.
  1893. //
  1894. if (DesiredBaud >= 9600) {
  1895. //
  1896. // If the remainder is less than the maximum remainder (wrt
  1897. // the ClockRate) or the remainder + the maximum remainder is
  1898. // greater than or equal to the ClockRate then assume that the
  1899. // baud is ok.
  1900. //
  1901. if ((remainder >= maxRemain) && ((remainder+maxRemain) < ClockRate)) {
  1902. calculatedDivisor = -1;
  1903. }
  1904. }
  1905. //
  1906. // Don't support a baud that causes the denominator to
  1907. // be larger than the clock.
  1908. //
  1909. if (denominator > ClockRate) {
  1910. calculatedDivisor = -1;
  1911. }
  1912. //
  1913. // Ok, Now do some special casing so that things can actually continue
  1914. // working on all platforms.
  1915. //
  1916. if (ClockRate == 1843200) {
  1917. if (DesiredBaud == 56000) {
  1918. calculatedDivisor = 2;
  1919. }
  1920. } else if (ClockRate == 3072000) {
  1921. if (DesiredBaud == 14400) {
  1922. calculatedDivisor = 13;
  1923. }
  1924. } else if (ClockRate == 4233600) {
  1925. if (DesiredBaud == 9600) {
  1926. calculatedDivisor = 28;
  1927. } else if (DesiredBaud == 14400) {
  1928. calculatedDivisor = 18;
  1929. } else if (DesiredBaud == 19200) {
  1930. calculatedDivisor = 14;
  1931. } else if (DesiredBaud == 38400) {
  1932. calculatedDivisor = 7;
  1933. } else if (DesiredBaud == 56000) {
  1934. calculatedDivisor = 5;
  1935. }
  1936. } else if (ClockRate == 8000000) {
  1937. if (DesiredBaud == 14400) {
  1938. calculatedDivisor = 35;
  1939. } else if (DesiredBaud == 56000) {
  1940. calculatedDivisor = 9;
  1941. }
  1942. }
  1943. *AppropriateDivisor = calculatedDivisor;
  1944. #if defined(NEC_98)
  1945. //
  1946. // This code check the baud that NEC98 support.
  1947. //
  1948. if (*AppropriateDivisor != -1) {
  1949. if (DesiredBaud <= 50) {
  1950. *AppropriateDivisor = -1;
  1951. } else if (DesiredBaud >= 9600) {
  1952. switch (DesiredBaud) {
  1953. case 9600:
  1954. case 19200:
  1955. case 38400:
  1956. case 57600:
  1957. case 115200:
  1958. break;
  1959. default:
  1960. *AppropriateDivisor = -1;
  1961. }
  1962. } else {
  1963. if (153600L % DesiredBaud) {
  1964. if (DesiredBaud != 110) {
  1965. *AppropriateDivisor = -1;
  1966. }
  1967. }
  1968. }
  1969. }
  1970. #else
  1971. #endif //defined(NEC_98)
  1972. }
  1973. if (*AppropriateDivisor == -1) {
  1974. status = STATUS_INVALID_PARAMETER;
  1975. }
  1976. return status;
  1977. }
  1978. VOID
  1979. SerialUnload(
  1980. IN PDRIVER_OBJECT DriverObject
  1981. )
  1982. /*++
  1983. Routine Description:
  1984. This routine is defunct since all device objects are removed before
  1985. the driver is unloaded.
  1986. Arguments:
  1987. DriverObject - Pointer to the driver object controling all of the
  1988. devices.
  1989. Return Value:
  1990. None.
  1991. --*/
  1992. {
  1993. PVOID lockPtr;
  1994. PAGED_CODE();
  1995. lockPtr = MmLockPagableCodeSection(SerialUnload);
  1996. //
  1997. // Unnecessary since our BSS is going away, but do it anyhow to be safe
  1998. //
  1999. SerialGlobals.PAGESER_Handle = NULL;
  2000. SerialDump(
  2001. SERDIAG3,
  2002. ("SERIAL: In SerialUnload\n")
  2003. );
  2004. MmUnlockPagableImageSection(lockPtr);
  2005. }
  2006. PVOID
  2007. SerialGetMappedAddress(
  2008. IN INTERFACE_TYPE BusType,
  2009. IN ULONG BusNumber,
  2010. PHYSICAL_ADDRESS IoAddress,
  2011. ULONG NumberOfBytes,
  2012. ULONG AddressSpace,
  2013. PBOOLEAN MappedAddress
  2014. )
  2015. /*++
  2016. Routine Description:
  2017. This routine maps an IO address to system address space.
  2018. Arguments:
  2019. BusType - what type of bus - eisa, mca, isa
  2020. IoBusNumber - which IO bus (for machines with multiple buses).
  2021. IoAddress - base device address to be mapped.
  2022. NumberOfBytes - number of bytes for which address is valid.
  2023. AddressSpace - Denotes whether the address is in io space or memory.
  2024. MappedAddress - indicates whether the address was mapped.
  2025. This only has meaning if the address returned
  2026. is non-null.
  2027. Return Value:
  2028. Mapped address
  2029. --*/
  2030. {
  2031. PHYSICAL_ADDRESS cardAddress;
  2032. PVOID address;
  2033. PAGED_CODE();
  2034. //
  2035. // Map the device base address into the virtual address space
  2036. // if the address is in memory space.
  2037. //
  2038. if (!AddressSpace) {
  2039. address = MmMapIoSpace(
  2040. IoAddress,
  2041. NumberOfBytes,
  2042. FALSE
  2043. );
  2044. *MappedAddress = (BOOLEAN)((address)?(TRUE):(FALSE));
  2045. } else {
  2046. address = (PVOID)IoAddress.LowPart;
  2047. *MappedAddress = FALSE;
  2048. }
  2049. return address;
  2050. }
  2051. SERIAL_MEM_COMPARES
  2052. SerialMemCompare(
  2053. IN PHYSICAL_ADDRESS A,
  2054. IN ULONG SpanOfA,
  2055. IN PHYSICAL_ADDRESS B,
  2056. IN ULONG SpanOfB
  2057. )
  2058. /*++
  2059. Routine Description:
  2060. Compare two phsical address.
  2061. Arguments:
  2062. A - One half of the comparison.
  2063. SpanOfA - In units of bytes, the span of A.
  2064. B - One half of the comparison.
  2065. SpanOfB - In units of bytes, the span of B.
  2066. Return Value:
  2067. The result of the comparison.
  2068. --*/
  2069. {
  2070. LARGE_INTEGER a;
  2071. LARGE_INTEGER b;
  2072. LARGE_INTEGER lower;
  2073. ULONG lowerSpan;
  2074. LARGE_INTEGER higher;
  2075. PAGED_CODE();
  2076. a = A;
  2077. b = B;
  2078. if (a.QuadPart == b.QuadPart) {
  2079. return AddressesAreEqual;
  2080. }
  2081. if (a.QuadPart > b.QuadPart) {
  2082. higher = a;
  2083. lower = b;
  2084. lowerSpan = SpanOfB;
  2085. } else {
  2086. higher = b;
  2087. lower = a;
  2088. lowerSpan = SpanOfA;
  2089. }
  2090. if ((higher.QuadPart - lower.QuadPart) >= lowerSpan) {
  2091. return AddressesAreDisjoint;
  2092. }
  2093. return AddressesOverlap;
  2094. }
  2095. BOOLEAN
  2096. SerialBecomeSharer(PVOID Context)
  2097. /*++
  2098. Routine Description:
  2099. This routine will take a device extension for a serial port and
  2100. allow it to share interrupts with other serial ports.
  2101. Arguments:
  2102. Context - The device extension of the port who is to start sharing
  2103. interrupts.
  2104. Return Value:
  2105. Always TRUE.
  2106. --*/
  2107. {
  2108. PSERIAL_DEVICE_EXTENSION pDevExt = (PSERIAL_DEVICE_EXTENSION)Context;
  2109. PSERIAL_DEVICE_EXTENSION pNewExt
  2110. = (PSERIAL_DEVICE_EXTENSION)pDevExt->NewExtension;
  2111. PSERIAL_CISR_SW pCIsrSw = pDevExt->CIsrSw;
  2112. //
  2113. // See if we need to configure the pre-existing node to become
  2114. // a sharer.
  2115. //
  2116. if (IsListEmpty(&pCIsrSw->SharerList)) {
  2117. pCIsrSw->IsrFunc = SerialSharerIsr;
  2118. pCIsrSw->Context = &pCIsrSw->SharerList;
  2119. InsertTailList(&pCIsrSw->SharerList, &pDevExt->TopLevelSharers);
  2120. }
  2121. //
  2122. // They share an interrupt object and a context
  2123. //
  2124. pNewExt->Interrupt = pDevExt->Interrupt;
  2125. pNewExt->CIsrSw = pDevExt->CIsrSw;
  2126. //
  2127. // Add to list of sharers
  2128. //
  2129. InsertTailList(&pCIsrSw->SharerList, &pNewExt->TopLevelSharers);
  2130. //
  2131. // Add to list of those who share this interrupt object --
  2132. // we may already be on if this port is part of a multiport board
  2133. //
  2134. if (IsListEmpty(&pNewExt->CommonInterruptObject)) {
  2135. InsertTailList(&pDevExt->CommonInterruptObject,
  2136. &pNewExt->CommonInterruptObject);
  2137. }
  2138. return TRUE;
  2139. }
  2140. NTSTATUS
  2141. SerialFindInitController(IN PDEVICE_OBJECT PDevObj, IN PCONFIG_DATA PConfig)
  2142. /*++
  2143. Routine Description:
  2144. This function discovers what type of controller is responsible for
  2145. the given port and initializes the controller and port.
  2146. Arguments:
  2147. PDevObj - Pointer to the devobj for the port we are about to init.
  2148. PConfig - Pointer to configuration data for the port we are about to init.
  2149. Return Value:
  2150. STATUS_SUCCESS on success, appropriate error value on failure.
  2151. --*/
  2152. {
  2153. PSERIAL_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  2154. PDEVICE_OBJECT pDeviceObject;
  2155. PSERIAL_DEVICE_EXTENSION pExtension;
  2156. PHYSICAL_ADDRESS serialPhysicalMax;
  2157. SERIAL_LIST_DATA listAddition;
  2158. BOOLEAN didInit = FALSE;
  2159. PLIST_ENTRY pCurDevObj;
  2160. NTSTATUS status;
  2161. PAGED_CODE();
  2162. SerialDump(SERTRACECALLS, ("SERIAL: entering SerialFindInitController\n"));
  2163. serialPhysicalMax.LowPart = (ULONG)~0;
  2164. serialPhysicalMax.HighPart = ~0;
  2165. SerialDump(SERDIAG1, ("SERIAL: Attempting to init %wZ\n"
  2166. "------- PortAddress is %x\n"
  2167. "------- Interrupt Status is %x\n"
  2168. "------- BusNumber is %d\n"
  2169. "------- BusType is %d\n"
  2170. "------- AddressSpace is %d\n"
  2171. "------- Interrupt Mode is %d\n",
  2172. &pDevExt->DeviceName,
  2173. PConfig->Controller.LowPart,
  2174. PConfig->InterruptStatus.LowPart,
  2175. PConfig->BusNumber,
  2176. PConfig->InterfaceType,
  2177. PConfig->AddressSpace,
  2178. PConfig->InterruptMode)
  2179. );
  2180. //
  2181. // We don't support any boards whose memory wraps around
  2182. // the physical address space.
  2183. //
  2184. if (SerialMemCompare(
  2185. PConfig->Controller,
  2186. PConfig->SpanOfController,
  2187. serialPhysicalMax,
  2188. (ULONG)0
  2189. ) != AddressesAreDisjoint) {
  2190. SerialLogError(
  2191. PDevObj->DriverObject,
  2192. NULL,
  2193. PConfig->Controller,
  2194. SerialPhysicalZero,
  2195. 0,
  2196. 0,
  2197. 0,
  2198. 43,
  2199. STATUS_SUCCESS,
  2200. SERIAL_DEVICE_TOO_HIGH,
  2201. pDevExt->SymbolicLinkName.Length+sizeof(WCHAR),
  2202. pDevExt->SymbolicLinkName.Buffer,
  2203. 0,
  2204. NULL
  2205. );
  2206. SerialDump(
  2207. SERERRORS,
  2208. ("SERIAL: Error in config record for %wZ\n"
  2209. "------ registers wrap around physical memory\n",
  2210. &pDevExt->DeviceName)
  2211. );
  2212. return STATUS_NO_SUCH_DEVICE;
  2213. }
  2214. if (SerialMemCompare(
  2215. PConfig->InterruptStatus,
  2216. PConfig->SpanOfInterruptStatus,
  2217. serialPhysicalMax,
  2218. (ULONG)0
  2219. ) != AddressesAreDisjoint) {
  2220. SerialLogError(
  2221. PDevObj->DriverObject,
  2222. NULL,
  2223. PConfig->Controller,
  2224. SerialPhysicalZero,
  2225. 0,
  2226. 0,
  2227. 0,
  2228. 44,
  2229. STATUS_SUCCESS,
  2230. SERIAL_STATUS_TOO_HIGH,
  2231. pDevExt->SymbolicLinkName.Length+sizeof(WCHAR),
  2232. pDevExt->SymbolicLinkName.Buffer,
  2233. 0,
  2234. NULL
  2235. );
  2236. SerialDump(
  2237. SERERRORS,
  2238. ("SERIAL: Error in config record for %wZ\n"
  2239. "------ status raps around physical memory\n",
  2240. &pDevExt->DeviceName)
  2241. );
  2242. return STATUS_NO_SUCH_DEVICE;
  2243. }
  2244. //
  2245. // Make sure that the interrupt status address doesn't
  2246. // overlap the controller registers
  2247. //
  2248. if (SerialMemCompare(
  2249. PConfig->InterruptStatus,
  2250. PConfig->SpanOfInterruptStatus,
  2251. SerialPhysicalZero,
  2252. (ULONG)0
  2253. ) != AddressesAreEqual) {
  2254. if (SerialMemCompare(
  2255. PConfig->InterruptStatus,
  2256. PConfig->SpanOfInterruptStatus,
  2257. PConfig->Controller,
  2258. PConfig->SpanOfController
  2259. ) != AddressesAreDisjoint) {
  2260. SerialLogError(
  2261. PDevObj->DriverObject,
  2262. NULL,
  2263. PConfig->Controller,
  2264. PConfig->InterruptStatus,
  2265. 0,
  2266. 0,
  2267. 0,
  2268. 45,
  2269. STATUS_SUCCESS,
  2270. SERIAL_STATUS_CONTROL_CONFLICT,
  2271. pDevExt->SymbolicLinkName.Length+sizeof(WCHAR),
  2272. pDevExt->SymbolicLinkName.Buffer,
  2273. 0,
  2274. NULL
  2275. );
  2276. SerialDump(
  2277. SERERRORS,
  2278. ("SERIAL: Error in config record for %wZ\n"
  2279. "------- Interrupt status overlaps regular registers\n",
  2280. &pDevExt->DeviceName)
  2281. );
  2282. return STATUS_NO_SUCH_DEVICE;
  2283. }
  2284. }
  2285. //
  2286. // Loop through all of the driver's device objects making
  2287. // sure that this new record doesn't overlap with any of them.
  2288. //
  2289. if (!IsListEmpty(&SerialGlobals.AllDevObjs)) {
  2290. pCurDevObj = SerialGlobals.AllDevObjs.Flink;
  2291. pExtension = CONTAINING_RECORD(pCurDevObj, SERIAL_DEVICE_EXTENSION,
  2292. AllDevObjs);
  2293. } else {
  2294. pCurDevObj = NULL;
  2295. pExtension = NULL;
  2296. }
  2297. while (pCurDevObj != NULL
  2298. && pCurDevObj != &SerialGlobals.AllDevObjs) {
  2299. //
  2300. // We only care about this list if the elements are on the
  2301. // same bus as this new entry.
  2302. //
  2303. if ((pExtension->InterfaceType == PConfig->InterfaceType) &&
  2304. (pExtension->AddressSpace == PConfig->AddressSpace) &&
  2305. (pExtension->BusNumber == PConfig->BusNumber)) {
  2306. SerialDump(
  2307. SERDIAG1,
  2308. ("SERIAL: Comparing it to %wZ\n"
  2309. "------- already in the device list\n"
  2310. "------- PortAddress is %x\n"
  2311. "------- Interrupt Status is %x\n"
  2312. "------- BusNumber is %d\n"
  2313. "------- BusType is %d\n"
  2314. "------- AddressSpace is %d\n",
  2315. &pExtension->DeviceName,
  2316. pExtension->OriginalController.LowPart,
  2317. pExtension->OriginalInterruptStatus.LowPart,
  2318. pExtension->BusNumber,
  2319. pExtension->InterfaceType,
  2320. pExtension->AddressSpace
  2321. )
  2322. );
  2323. //
  2324. // Check to see if the controller addresses are not equal.
  2325. //
  2326. if (SerialMemCompare(
  2327. PConfig->Controller,
  2328. PConfig->SpanOfController,
  2329. pExtension->OriginalController,
  2330. pExtension->SpanOfController
  2331. ) != AddressesAreDisjoint) {
  2332. //
  2333. // We don't want to log an error if the addresses
  2334. // are the same and the name is the same and
  2335. // the new item is from the firmware.
  2336. //
  2337. SerialDump(
  2338. SERERRORS,
  2339. ("SERIAL: Error in config record for %wZ\n"
  2340. "------- Register address overlaps with\n"
  2341. "------- previous serial device\n",
  2342. &pDevExt->DeviceName)
  2343. );
  2344. return STATUS_NO_SUCH_DEVICE;
  2345. }
  2346. //
  2347. // If we have an interrupt status, make sure that
  2348. // it doesn't overlap with the old controllers
  2349. // registers.
  2350. //
  2351. if (SerialMemCompare(
  2352. PConfig->InterruptStatus,
  2353. PConfig->SpanOfInterruptStatus,
  2354. SerialPhysicalZero,
  2355. (ULONG)0
  2356. ) != AddressesAreEqual) {
  2357. //
  2358. // Check it against the existing device's controller address
  2359. //
  2360. if (SerialMemCompare(
  2361. PConfig->InterruptStatus,
  2362. PConfig->SpanOfInterruptStatus,
  2363. pExtension->OriginalController,
  2364. pExtension->SpanOfController
  2365. ) != AddressesAreDisjoint) {
  2366. SerialLogError(
  2367. PDevObj->DriverObject,
  2368. NULL,
  2369. PConfig->Controller,
  2370. pExtension->OriginalController,
  2371. 0,
  2372. 0,
  2373. 0,
  2374. 47,
  2375. STATUS_SUCCESS,
  2376. SERIAL_STATUS_OVERLAP,
  2377. pDevExt->SymbolicLinkName.Length+sizeof(WCHAR),
  2378. pDevExt->SymbolicLinkName.Buffer,
  2379. pExtension->SymbolicLinkName.Length+sizeof(WCHAR),
  2380. pExtension->SymbolicLinkName.Buffer
  2381. );
  2382. SerialDump(
  2383. SERERRORS,
  2384. ("SERIAL: Error in config record for %wZ\n"
  2385. "------- status address overlaps with\n"
  2386. "------- previous serial device registers\n",
  2387. &pDevExt->DeviceName)
  2388. );
  2389. return STATUS_NO_SUCH_DEVICE;
  2390. }
  2391. //
  2392. // If the old configuration record has an interrupt
  2393. // status, the addresses should not overlap.
  2394. //
  2395. if (SerialMemCompare(
  2396. PConfig->InterruptStatus,
  2397. PConfig->SpanOfInterruptStatus,
  2398. SerialPhysicalZero,
  2399. (ULONG)0
  2400. ) != AddressesAreEqual) {
  2401. if (SerialMemCompare(
  2402. PConfig->InterruptStatus,
  2403. PConfig->SpanOfInterruptStatus,
  2404. pExtension->OriginalInterruptStatus,
  2405. pExtension->SpanOfInterruptStatus
  2406. ) == AddressesOverlap) {
  2407. SerialLogError(
  2408. PDevObj->DriverObject,
  2409. NULL,
  2410. PConfig->Controller,
  2411. pExtension->OriginalController,
  2412. 0,
  2413. 0,
  2414. 0,
  2415. 48,
  2416. STATUS_SUCCESS,
  2417. SERIAL_STATUS_STATUS_OVERLAP,
  2418. pDevExt->SymbolicLinkName.Length+sizeof(WCHAR),
  2419. pDevExt->SymbolicLinkName.Buffer,
  2420. pExtension->SymbolicLinkName.Length
  2421. + sizeof(WCHAR),
  2422. pExtension->SymbolicLinkName.Buffer
  2423. );
  2424. SerialDump(
  2425. SERERRORS,
  2426. ("SERIAL: Error in config record for %wZ\n"
  2427. "------- status address overlaps with\n"
  2428. "------- previous serial status register\n",
  2429. &pDevExt->DeviceName)
  2430. );
  2431. return STATUS_NO_SUCH_DEVICE;
  2432. }
  2433. }
  2434. } // if ((pExtension->InterfaceType == pDevExt->InterfaceType) &&
  2435. //
  2436. // If the old configuration record has a status
  2437. // address make sure that it doesn't overlap with
  2438. // the new controllers address. (Interrupt status
  2439. // overlap is take care of above.
  2440. //
  2441. if (SerialMemCompare(
  2442. pExtension->OriginalInterruptStatus,
  2443. pExtension->SpanOfInterruptStatus,
  2444. SerialPhysicalZero,
  2445. (ULONG)0
  2446. ) != AddressesAreEqual) {
  2447. if (SerialMemCompare(
  2448. PConfig->Controller,
  2449. PConfig->SpanOfController,
  2450. pExtension->OriginalInterruptStatus,
  2451. pExtension->SpanOfInterruptStatus
  2452. ) == AddressesOverlap) {
  2453. SerialLogError(
  2454. PDevObj->DriverObject,
  2455. NULL,
  2456. PConfig->Controller,
  2457. pExtension->OriginalController,
  2458. 0,
  2459. 0,
  2460. 0,
  2461. 49,
  2462. STATUS_SUCCESS,
  2463. SERIAL_CONTROL_STATUS_OVERLAP,
  2464. pDevExt->SymbolicLinkName.Length
  2465. + sizeof(WCHAR),
  2466. pDevExt->SymbolicLinkName.Buffer,
  2467. pExtension->SymbolicLinkName.Length+sizeof(WCHAR),
  2468. pExtension->SymbolicLinkName.Buffer
  2469. );
  2470. SerialDump(
  2471. SERERRORS,
  2472. ("SERIAL: Error in config record for %wZ\n"
  2473. "------- register address overlaps with\n"
  2474. "------- previous serial status register\n",
  2475. &pDevExt->DeviceName)
  2476. );
  2477. return STATUS_NO_SUCH_DEVICE;
  2478. }
  2479. }
  2480. }
  2481. pCurDevObj = pCurDevObj->Flink;
  2482. if (pCurDevObj != NULL) {
  2483. pExtension = CONTAINING_RECORD(pCurDevObj, SERIAL_DEVICE_EXTENSION,
  2484. AllDevObjs);
  2485. }
  2486. } // while (pCurDevObj != NULL && pCurDevObj != &SerialGlobals.AllDevObjs)
  2487. //
  2488. // Now, we will check if this is a port on a multiport card.
  2489. // The conditions are same ISR set and same IRQL/Vector
  2490. //
  2491. //
  2492. // Loop through all previously attached devices
  2493. //
  2494. if (!IsListEmpty(&SerialGlobals.AllDevObjs)) {
  2495. pCurDevObj = SerialGlobals.AllDevObjs.Flink;
  2496. pExtension = CONTAINING_RECORD(pCurDevObj, SERIAL_DEVICE_EXTENSION,
  2497. AllDevObjs);
  2498. } else {
  2499. pCurDevObj = NULL;
  2500. pExtension = NULL;
  2501. }
  2502. //
  2503. // If there is an interrupt status then we
  2504. // loop through the config list again to look
  2505. // for a config record with the same interrupt
  2506. // status (on the same bus).
  2507. //
  2508. if ((SerialMemCompare(
  2509. PConfig->InterruptStatus,
  2510. PConfig->SpanOfInterruptStatus,
  2511. SerialPhysicalZero,
  2512. (ULONG)0
  2513. ) != AddressesAreEqual) &&
  2514. (pCurDevObj != NULL)) {
  2515. ASSERT(pExtension != NULL);
  2516. //
  2517. // We have an interrupt status. Loop through all
  2518. // previous records, look for an existing interrupt status
  2519. // the same as the current interrupt status.
  2520. //
  2521. do {
  2522. //
  2523. // We only care about this list if the elements are on the
  2524. // same bus as this new entry. (Their interrupts must therefore
  2525. // also be the on the same bus. We will check that momentarily).
  2526. //
  2527. // We don't check here for the dissimilar interrupts since that
  2528. // could cause us to miss the error of having the same interrupt
  2529. // status but different interrupts - which is bizzare.
  2530. //
  2531. if ((pExtension->InterfaceType == PConfig->InterfaceType) &&
  2532. (pExtension->AddressSpace == PConfig->AddressSpace) &&
  2533. (pExtension->BusNumber == PConfig->BusNumber)) {
  2534. //
  2535. // If the interrupt status is the same, then same card.
  2536. //
  2537. if (SerialMemCompare(
  2538. pExtension->OriginalInterruptStatus,
  2539. pExtension->SpanOfInterruptStatus,
  2540. PConfig->InterruptStatus,
  2541. PConfig->SpanOfInterruptStatus
  2542. ) == AddressesAreEqual) {
  2543. //
  2544. // Same card. Now make sure that they
  2545. // are using the same interrupt parameters.
  2546. //
  2547. if ((PConfig->OriginalIrql != pExtension->OriginalIrql) ||
  2548. (PConfig->OriginalVector != pExtension->OriginalVector)) {
  2549. //
  2550. // We won't put this into the configuration
  2551. // list.
  2552. //
  2553. SerialLogError(
  2554. PDevObj->DriverObject,
  2555. NULL,
  2556. PConfig->Controller,
  2557. pExtension->OriginalController,
  2558. 0,
  2559. 0,
  2560. 0,
  2561. 50,
  2562. STATUS_SUCCESS,
  2563. SERIAL_MULTI_INTERRUPT_CONFLICT,
  2564. pDevExt->SymbolicLinkName.Length+sizeof(WCHAR),
  2565. pDevExt->SymbolicLinkName.Buffer,
  2566. pExtension->SymbolicLinkName.Length
  2567. + sizeof(WCHAR),
  2568. pExtension->SymbolicLinkName.Buffer
  2569. );
  2570. SerialDump(
  2571. SERERRORS,
  2572. ("SERIAL: Configuration error for %wZ\n"
  2573. "------- Same multiport - different interrupts\n",
  2574. &pDevExt->DeviceName)
  2575. );
  2576. return STATUS_NO_SUCH_DEVICE;
  2577. }
  2578. //
  2579. // We should never get this far on a restart since we don't
  2580. // support stop on ISA multiport devices!
  2581. //
  2582. ASSERT(pDevExt->PNPState == SERIAL_PNP_ADDED);
  2583. //
  2584. //
  2585. // Initialize the device as part of a multiport board
  2586. //
  2587. SerialDump(SERDIAG1, ("SERIAL: Aha! It is a multiport node\n"));
  2588. SerialDump(SERDIAG1, ("------: Matched to %x\n", pExtension));
  2589. status = SerialInitMultiPort(pExtension, PConfig, PDevObj);
  2590. //
  2591. // A port can be one of three things:
  2592. // A standalone
  2593. // A non-root on a multiport
  2594. // A root on a multiport
  2595. //
  2596. // It can only share an interrupt if it is a root
  2597. // or if it is a standalone. Since this was a non-root
  2598. // we don't need to check if it shares an interrupt
  2599. // and we can return.
  2600. //
  2601. return status;
  2602. }
  2603. }
  2604. //
  2605. // No match, check some more
  2606. //
  2607. pCurDevObj = pCurDevObj->Flink;
  2608. if (pCurDevObj != NULL) {
  2609. pExtension = CONTAINING_RECORD(pCurDevObj,SERIAL_DEVICE_EXTENSION,
  2610. AllDevObjs);
  2611. }
  2612. } while (pCurDevObj != NULL && pCurDevObj != &SerialGlobals.AllDevObjs);
  2613. }
  2614. SerialDump(SERDIAG1, ("SERIAL: Aha! It is a standalone node or first multi"
  2615. "\n"));
  2616. status = SerialInitOneController(PDevObj, PConfig);
  2617. if (!NT_SUCCESS(status)) {
  2618. return status;
  2619. }
  2620. //
  2621. // The device is initialized. Now we need to check if
  2622. // this device shares an interrupt with anyone.
  2623. //
  2624. //
  2625. // Loop through all previously attached devices
  2626. //
  2627. if (!IsListEmpty(&SerialGlobals.AllDevObjs)) {
  2628. pCurDevObj = SerialGlobals.AllDevObjs.Flink;
  2629. pExtension = CONTAINING_RECORD(pCurDevObj, SERIAL_DEVICE_EXTENSION,
  2630. AllDevObjs);
  2631. } else {
  2632. pCurDevObj = NULL;
  2633. pExtension = NULL;
  2634. }
  2635. //
  2636. // Go through the list again looking for previous devices
  2637. // with the same interrupt. The first one found will either be a root
  2638. // or standalone. Order of insertion is important here!
  2639. //
  2640. if (!PConfig->Jensen && (pCurDevObj != NULL)) {
  2641. do {
  2642. //
  2643. // We only care about interrupts that are on
  2644. // the same bus.
  2645. //
  2646. if ((pExtension->InterfaceType == PConfig->InterfaceType) &&
  2647. (pExtension->BusNumber == PConfig->BusNumber)) {
  2648. if ((pExtension->OriginalIrql == PConfig->OriginalIrql) &&
  2649. (pExtension->OriginalVector == PConfig->OriginalVector)) {
  2650. pExtension->NewExtension = pDevExt;
  2651. //
  2652. // We will share another's CIsrSw so we can free the one
  2653. // allocated for us during init
  2654. //
  2655. ExFreePool(pDevExt->CIsrSw);
  2656. SerialDump(SERDIAG1, ("Becoming sharer: %08X %08X %08X\n",
  2657. pExtension, pExtension->OriginalIrql,
  2658. &pExtension->CIsrSw->SharerList));
  2659. KeSynchronizeExecution(pExtension->Interrupt,
  2660. SerialBecomeSharer, pExtension);
  2661. return STATUS_SUCCESS;
  2662. }
  2663. }
  2664. //
  2665. // No match, check some more
  2666. //
  2667. pCurDevObj = pCurDevObj->Flink;
  2668. if (pCurDevObj != NULL) {
  2669. pExtension = CONTAINING_RECORD(pCurDevObj, SERIAL_DEVICE_EXTENSION,
  2670. AllDevObjs);
  2671. }
  2672. } while (pCurDevObj != NULL
  2673. && pCurDevObj != &SerialGlobals.AllDevObjs);
  2674. }
  2675. return STATUS_SUCCESS;
  2676. }