Source code of Windows XP (NT5)
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.

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