Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1223 lines
23 KiB

  1. /*++
  2. Copyright (c) 1995 Intel Corporation
  3. Module Name:
  4. i64ioacc.c
  5. Abstract:
  6. This module implements the I/O Register access routines.
  7. Author:
  8. Bernard Lint, M. Jayakumar Sep 16 '97
  9. Environment:
  10. Kernel mode
  11. Revision History:
  12. --*/
  13. //
  14. // XXX: Possible issues:
  15. // ISA bit
  16. // non-ISA bit
  17. // testing
  18. // Yosemite config
  19. // Pluto config
  20. //
  21. #include "halp.h"
  22. #if DBG
  23. ULONG DbgIoPorts = 0;
  24. #endif
  25. typedef struct _PORT_RANGE {
  26. BOOLEAN InUse;
  27. BOOLEAN IsSparse; // _TRS
  28. BOOLEAN PrimaryIsMmio; // _TTP
  29. BOOLEAN HalMapped;
  30. PVOID VirtBaseAddr;
  31. PHYSICAL_ADDRESS PhysBaseAddr; // Only valid if PrimaryIsMmio = TRUE
  32. ULONG Length; // Length of VirtBaseAddr and PhysBaseAddr ranges.
  33. } PORT_RANGE, *PPORT_RANGE;
  34. //
  35. // Define a range for the architected IA-64 port space.
  36. //
  37. PORT_RANGE
  38. BasePortRange = {
  39. TRUE, // InUse
  40. FALSE, // IsSparse
  41. FALSE, // PrimaryIsMmio
  42. FALSE, // HalMapped
  43. (PVOID)VIRTUAL_IO_BASE, // VirtBaseAddr
  44. {0}, // PhysBaseAddr (unknown, comes from firmware)
  45. 64*1024*1024 // Length
  46. };
  47. //
  48. // Seed the set of ranges with the architected IA-64 port space.
  49. //
  50. PPORT_RANGE PortRanges = &BasePortRange;
  51. USHORT NumPortRanges = 1;
  52. UINT_PTR
  53. GetVirtualPort(
  54. IN PPORT_RANGE Range,
  55. IN USHORT Port
  56. )
  57. {
  58. UINT_PTR RangeOffset;
  59. if (Range->PrimaryIsMmio && !Range->IsSparse) {
  60. //
  61. // A densely packed range which converts MMIO transactions to
  62. // I/O port ones.
  63. //
  64. RangeOffset = Port;
  65. } else {
  66. //
  67. // Either a sparse MMIO->I/O port range, or primary is not
  68. // MMIO (IA-64 I/O port space).
  69. //
  70. RangeOffset = ((Port & 0xfffc) << 10) | (Port & 0xfff);
  71. }
  72. ASSERT(RangeOffset < Range->Length);
  73. return ((UINT_PTR)Range->VirtBaseAddr) + RangeOffset;
  74. }
  75. NTSTATUS
  76. HalpAllocatePortRange(
  77. OUT PUSHORT RangeId
  78. )
  79. {
  80. NTSTATUS Status = STATUS_SUCCESS;
  81. PPORT_RANGE OldPortRanges = PortRanges;
  82. PPORT_RANGE NewPortRanges = NULL;
  83. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  84. //
  85. // First scan the existing ranges, looking for an unused one.
  86. //
  87. for (*RangeId = 0; *RangeId < NumPortRanges; *RangeId += 1) {
  88. if (! PortRanges[*RangeId].InUse) {
  89. PortRanges[*RangeId].InUse = TRUE;
  90. return STATUS_SUCCESS;
  91. }
  92. }
  93. //
  94. // Otherwise, grow the set of ranges and copy over the old ones.
  95. //
  96. NewPortRanges = ExAllocatePool(NonPagedPool,
  97. (NumPortRanges + 1) * sizeof(PORT_RANGE));
  98. if (NewPortRanges == NULL) {
  99. Status = STATUS_INSUFFICIENT_RESOURCES;
  100. }
  101. if (NT_SUCCESS(Status)) {
  102. RtlCopyMemory(NewPortRanges,
  103. OldPortRanges,
  104. NumPortRanges * sizeof(PORT_RANGE));
  105. *RangeId = NumPortRanges;
  106. PortRanges = NewPortRanges;
  107. NumPortRanges += 1;
  108. PortRanges[*RangeId].InUse = TRUE;
  109. if (OldPortRanges != &BasePortRange) {
  110. ExFreePool(OldPortRanges);
  111. }
  112. }
  113. if (! NT_SUCCESS(Status)) {
  114. //
  115. // Error case: cleanup.
  116. //
  117. if (NewPortRanges != NULL) {
  118. ExFreePool(NewPortRanges);
  119. }
  120. }
  121. return Status;
  122. }
  123. VOID
  124. HalpFreePortRange(
  125. IN USHORT RangeId
  126. )
  127. {
  128. PPORT_RANGE Range = &PortRanges[RangeId];
  129. ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
  130. ASSERT(Range->InUse);
  131. Range->InUse = FALSE;
  132. if (Range->HalMapped) {
  133. MmUnmapIoSpace(Range->VirtBaseAddr, Range->Length);
  134. }
  135. Range->VirtBaseAddr = NULL;
  136. Range->PhysBaseAddr.QuadPart = 0;
  137. Range->Length = 0;
  138. }
  139. NTSTATUS
  140. HalpAddPortRange(
  141. IN BOOLEAN IsSparse,
  142. IN BOOLEAN PrimaryIsMmio,
  143. IN PVOID VirtBaseAddr OPTIONAL,
  144. IN PHYSICAL_ADDRESS PhysBaseAddr, // Only valid if PrimaryIsMmio = TRUE
  145. IN ULONG Length, // Only valid if PrimaryIsMmio = TRUE
  146. OUT PUSHORT NewRangeId
  147. )
  148. {
  149. NTSTATUS Status = STATUS_SUCCESS;
  150. BOOLEAN HalMapped = FALSE;
  151. BOOLEAN RangeAllocated = FALSE;
  152. ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
  153. Status = HalpAllocatePortRange(NewRangeId);
  154. RangeAllocated = NT_SUCCESS(Status);
  155. if (NT_SUCCESS(Status) && (VirtBaseAddr == NULL)) {
  156. VirtBaseAddr = MmMapIoSpace(PhysBaseAddr, Length, MmNonCached);
  157. if (VirtBaseAddr == NULL) {
  158. Status = STATUS_INSUFFICIENT_RESOURCES;
  159. } else {
  160. HalMapped = TRUE;
  161. }
  162. }
  163. if (NT_SUCCESS(Status)) {
  164. PortRanges[*NewRangeId].IsSparse = IsSparse;
  165. PortRanges[*NewRangeId].PrimaryIsMmio = PrimaryIsMmio;
  166. PortRanges[*NewRangeId].HalMapped = HalMapped;
  167. PortRanges[*NewRangeId].VirtBaseAddr = VirtBaseAddr;
  168. PortRanges[*NewRangeId].PhysBaseAddr.QuadPart = PhysBaseAddr.QuadPart;
  169. PortRanges[*NewRangeId].Length = Length;
  170. }
  171. if (! NT_SUCCESS(Status)) {
  172. //
  173. // Error case: cleanup.
  174. //
  175. if (HalMapped) {
  176. MmUnmapIoSpace(VirtBaseAddr, Length);
  177. }
  178. if (RangeAllocated) {
  179. HalpFreePortRange(*NewRangeId);
  180. }
  181. }
  182. return Status;
  183. }
  184. PPORT_RANGE
  185. HalpGetPortRange(
  186. IN USHORT RangeId
  187. )
  188. {
  189. PPORT_RANGE Range;
  190. ASSERT(RangeId < NumPortRanges);
  191. Range = &PortRanges[RangeId];
  192. ASSERT(Range->InUse);
  193. return Range;
  194. }
  195. //
  196. // Returns TRUE when RangeId has been set. Overlapping ranges are
  197. // allowed.
  198. //
  199. BOOLEAN
  200. HalpLookupPortRange(
  201. IN BOOLEAN IsSparse, // _TRS
  202. IN BOOLEAN PrimaryIsMmio, // FALSE for I/O port space, _TTP
  203. IN PHYSICAL_ADDRESS PhysBaseAddr,
  204. IN ULONG Length,
  205. OUT PUSHORT RangeId
  206. )
  207. {
  208. BOOLEAN FoundMatch = FALSE;
  209. PPORT_RANGE Range;
  210. for (*RangeId = 0; *RangeId < NumPortRanges; *RangeId += 1) {
  211. Range = &PortRanges[*RangeId];
  212. if (! Range->InUse) {
  213. continue;
  214. }
  215. if ((Range->PrimaryIsMmio == PrimaryIsMmio) &&
  216. (Range->IsSparse == IsSparse)) {
  217. if (! PrimaryIsMmio) {
  218. //
  219. // Port space on the primary side. Sparseness doesn't
  220. // make sense for primary side port space. Because
  221. // there is only one primary side port space, which is
  222. // shared by all I/O bridges, don't check the base
  223. // address.
  224. //
  225. ASSERT(! IsSparse);
  226. FoundMatch = TRUE;
  227. break;
  228. }
  229. if ((Range->PhysBaseAddr.QuadPart == PhysBaseAddr.QuadPart) &&
  230. (Range->Length == Length)) {
  231. FoundMatch = TRUE;
  232. break;
  233. }
  234. }
  235. }
  236. //
  237. // A matching range was not found.
  238. //
  239. return FoundMatch;
  240. }
  241. NTSTATUS
  242. HalpQueryAllocatePortRange(
  243. IN BOOLEAN IsSparse,
  244. IN BOOLEAN PrimaryIsMmio,
  245. IN PVOID VirtBaseAddr OPTIONAL,
  246. IN PHYSICAL_ADDRESS PhysBaseAddr, // Only valid if PrimaryIsMmio = TRUE
  247. IN ULONG Length, // Only valid if PrimaryIsMmio = TRUE
  248. OUT PUSHORT NewRangeId
  249. )
  250. {
  251. NTSTATUS Status = STATUS_SUCCESS;
  252. if (! HalpLookupPortRange(IsSparse,
  253. PrimaryIsMmio,
  254. PhysBaseAddr,
  255. Length,
  256. NewRangeId)) {
  257. Status = HalpAddPortRange(IsSparse,
  258. PrimaryIsMmio,
  259. NULL,
  260. PhysBaseAddr,
  261. Length,
  262. NewRangeId);
  263. }
  264. return Status;
  265. }
  266. UINT_PTR
  267. HalpGetPortVirtualAddress(
  268. UINT_PTR Port
  269. )
  270. {
  271. /*++
  272. Routine Description:
  273. This routine gives 32 bit virtual address for the I/O Port specified.
  274. Arguements:
  275. PORT - Supplies PORT address of the I/O PORT.
  276. Returned Value:
  277. UINT_PTR - Virtual address value.
  278. --*/
  279. PPORT_RANGE PortRange;
  280. //
  281. // Upper 16 bits of the port handle are the range id.
  282. //
  283. USHORT RangeId = (USHORT)((((ULONG)Port) >> 16) & 0xffff);
  284. USHORT OffsetInRange = (USHORT)(Port & 0xffff);
  285. ULONG VirtOffset;
  286. UINT_PTR VirtualPort = 0;
  287. #if 0
  288. {
  289. BOOLEAN isUart = FALSE;
  290. BOOLEAN isVGA = FALSE;
  291. if (RangeId == 0) {
  292. if ((OffsetInRange >= 0x3b0) && (OffsetInRange <= 0x3df)) {
  293. isVGA = TRUE;
  294. }
  295. if ((OffsetInRange >= 0x2f8) && (OffsetInRange <= 0x2ff)) {
  296. isUart = TRUE;
  297. }
  298. if ((OffsetInRange >= 0x3f8) && (OffsetInRange <= 0x3ff)) {
  299. isUart = TRUE;
  300. }
  301. if (!isVGA && !isUart) {
  302. static UINT32 numRaw = 0;
  303. InterlockedIncrement(&numRaw);
  304. }
  305. } else {
  306. static UINT32 numUnTra = 0;
  307. InterlockedIncrement(&numUnTra);
  308. }
  309. }
  310. #endif // #if DBG
  311. PortRange = HalpGetPortRange(RangeId);
  312. return GetVirtualPort(PortRange, OffsetInRange);
  313. }
  314. UCHAR
  315. READ_PORT_UCHAR(
  316. PUCHAR Port
  317. )
  318. {
  319. /*++
  320. Routine Description:
  321. Reads a byte location from the PORT
  322. Arguements:
  323. PORT - Supplies the PORT address to read from
  324. Return Value:
  325. UCHAR - Returns the byte read from the PORT specified.
  326. --*/
  327. UINT_PTR VirtualPort;
  328. UCHAR LoadData;
  329. KIRQL OldIrql;
  330. #if DBG
  331. if (DbgIoPorts) DbgPrint("READ_PORT_UCHAR(%#x)\n",Port);
  332. #endif
  333. VirtualPort = HalpGetPortVirtualAddress((UINT_PTR)Port);
  334. //
  335. // Need to ensure load and mfa are not preemptable
  336. //
  337. __mf();
  338. OldIrql = KeGetCurrentIrql();
  339. if (OldIrql < DISPATCH_LEVEL) {
  340. OldIrql = KeRaiseIrqlToDpcLevel();
  341. }
  342. LoadData = *(volatile UCHAR *)VirtualPort;
  343. __mfa();
  344. if (OldIrql < DISPATCH_LEVEL) {
  345. KeLowerIrql (OldIrql);
  346. }
  347. return (LoadData);
  348. }
  349. USHORT
  350. READ_PORT_USHORT (
  351. PUSHORT Port
  352. )
  353. {
  354. /*++
  355. Routine Description:
  356. Reads a word location (16 bit unsigned value) from the PORT
  357. Arguements:
  358. PORT - Supplies the PORT address to read from.
  359. Returned Value:
  360. USHORT - Returns the 16 bit unsigned value from the PORT specified.
  361. --*/
  362. UINT_PTR VirtualPort;
  363. USHORT LoadData;
  364. KIRQL OldIrql;
  365. #if DBG
  366. if (DbgIoPorts) DbgPrint("READ_PORT_USHORT(%#x)\n",Port);
  367. #endif
  368. VirtualPort = HalpGetPortVirtualAddress((UINT_PTR)Port);
  369. //
  370. // Need to ensure load and mfa are not preemptable
  371. //
  372. __mf();
  373. OldIrql = KeGetCurrentIrql();
  374. if (OldIrql < DISPATCH_LEVEL) {
  375. OldIrql = KeRaiseIrqlToDpcLevel();
  376. }
  377. LoadData = *(volatile USHORT *)VirtualPort;
  378. __mfa();
  379. if (OldIrql < DISPATCH_LEVEL) {
  380. KeLowerIrql (OldIrql);
  381. }
  382. return (LoadData);
  383. }
  384. ULONG
  385. READ_PORT_ULONG (
  386. PULONG Port
  387. )
  388. {
  389. /*++
  390. Routine Description:
  391. Reads a longword location (32bit unsigned value) from the PORT.
  392. Arguements:
  393. PORT - Supplies PORT address to read from.
  394. Returned Value:
  395. ULONG - Returns the 32 bit unsigned value (ULONG) from the PORT specified.
  396. --*/
  397. UINT_PTR VirtualPort;
  398. ULONG LoadData;
  399. KIRQL OldIrql;
  400. #if DBG
  401. if (DbgIoPorts) DbgPrint("READ_PORT_ULONG(%#x)\n",Port);
  402. #endif
  403. VirtualPort = HalpGetPortVirtualAddress((UINT_PTR)Port);
  404. //
  405. // Need to ensure load and mfa are not preemptable
  406. //
  407. __mf();
  408. OldIrql = KeGetCurrentIrql();
  409. if (OldIrql < DISPATCH_LEVEL) {
  410. OldIrql = KeRaiseIrqlToDpcLevel();
  411. }
  412. LoadData = *(volatile ULONG *)VirtualPort;
  413. __mfa();
  414. if (OldIrql < DISPATCH_LEVEL) {
  415. KeLowerIrql (OldIrql);
  416. }
  417. return (LoadData);
  418. }
  419. ULONG
  420. READ_PORT_ULONG_SPECIAL (
  421. PULONG Port
  422. )
  423. {
  424. /*++
  425. Routine Description:
  426. Reads a longword location (32bit unsigned value) from the PORT.
  427. For A0 bug 2173. Does not enable/disable interrupts. Called from first level interrupt
  428. handler.
  429. Arguements:
  430. PORT - Supplies PORT address to read from.
  431. Returned Value:
  432. ULONG - Returns the 32 bit unsigned value (ULONG) from the PORT specified.
  433. --*/
  434. UINT_PTR VirtualPort;
  435. ULONG LoadData;
  436. #if DBG
  437. if (DbgIoPorts) DbgPrint("READ_PORT_ULONG(%#x)\n",Port);
  438. #endif
  439. VirtualPort = HalpGetPortVirtualAddress((UINT_PTR)Port);
  440. __mf();
  441. LoadData = *(volatile ULONG *)VirtualPort;
  442. __mfa();
  443. return (LoadData);
  444. }
  445. VOID
  446. READ_PORT_BUFFER_UCHAR (
  447. PUCHAR Port,
  448. PUCHAR Buffer,
  449. ULONG Count
  450. )
  451. {
  452. /*++
  453. Routine Description:
  454. Reads multiple bytes from the specified PORT address into the
  455. destination buffer.
  456. Arguements:
  457. PORT - The address of the PORT to read from.
  458. Buffer - A pointer to the buffer to fill with the data read from the PORT.
  459. Count - Supplies the number of bytes to read.
  460. Return Value:
  461. None.
  462. --*/
  463. UINT_PTR VirtualPort;
  464. ULONG i;
  465. KIRQL OldIrql;
  466. #if DBG
  467. if (DbgIoPorts) DbgPrint("READ_PORT_BUFFER_UCHAR(%#x,%#p,%d)\n",Port,Buffer,Count);
  468. #endif
  469. VirtualPort = HalpGetPortVirtualAddress((UINT_PTR)Port);
  470. //
  471. // Prevent preemption before mfa
  472. //
  473. OldIrql = KeGetCurrentIrql();
  474. if (OldIrql < DISPATCH_LEVEL) {
  475. OldIrql = KeRaiseIrqlToDpcLevel();
  476. }
  477. __mf();
  478. for (i=0; i<Count; i++) {
  479. *Buffer++ = *(volatile UCHAR *)VirtualPort;
  480. __mfa();
  481. }
  482. if (OldIrql < DISPATCH_LEVEL) {
  483. KeLowerIrql(OldIrql);
  484. }
  485. }
  486. VOID
  487. READ_PORT_BUFFER_USHORT (
  488. PUSHORT Port,
  489. PUSHORT Buffer,
  490. ULONG Count
  491. )
  492. {
  493. /*++
  494. Routine Description:
  495. Reads multiple words (16bits) from the speicified PORT address into
  496. the destination buffer.
  497. Arguements:
  498. Port - Supplies the address of the PORT to read from.
  499. Buffer - A pointer to the buffer to fill with the data
  500. read from the PORT.
  501. Count - Supplies the number of words to read.
  502. --*/
  503. UINT_PTR VirtualPort;
  504. ULONG i;
  505. KIRQL OldIrql;
  506. #if DBG
  507. if (DbgIoPorts) DbgPrint("READ_PORT_BUFFER_USHORT(%#x,%#p,%d)\n",Port,Buffer,Count);
  508. #endif
  509. VirtualPort = HalpGetPortVirtualAddress((UINT_PTR)Port);
  510. //
  511. // Prevent preemption before mfa
  512. //
  513. OldIrql = KeGetCurrentIrql();
  514. if (OldIrql < DISPATCH_LEVEL) {
  515. OldIrql = KeRaiseIrqlToDpcLevel();
  516. }
  517. __mf();
  518. for (i=0; i<Count; i++) {
  519. *Buffer++ = *(volatile USHORT *)VirtualPort;
  520. __mfa();
  521. }
  522. if (OldIrql < DISPATCH_LEVEL) {
  523. KeLowerIrql(OldIrql);
  524. }
  525. }
  526. VOID
  527. READ_PORT_BUFFER_ULONG (
  528. PULONG Port,
  529. PULONG Buffer,
  530. ULONG Count
  531. )
  532. {
  533. /*++
  534. Routine Description:
  535. Reads multiple longwords (32bits) from the speicified PORT
  536. address into the destination buffer.
  537. Arguements:
  538. Port - Supplies the address of the PORT to read from.
  539. Buffer - A pointer to the buffer to fill with the data
  540. read from the PORT.
  541. Count - Supplies the number of long words to read.
  542. --*/
  543. UINT_PTR VirtualPort;
  544. PULONG ReadBuffer = Buffer;
  545. ULONG ReadCount;
  546. ULONG i;
  547. KIRQL OldIrql;
  548. #if DBG
  549. if (DbgIoPorts) DbgPrint("READ_PORT_BUFFER_ULONG(%#x,%#p,%d)\n",Port,Buffer,Count);
  550. #endif
  551. VirtualPort = HalpGetPortVirtualAddress((UINT_PTR)Port);
  552. //
  553. // Prevent preemption before mfa
  554. //
  555. OldIrql = KeGetCurrentIrql();
  556. if (OldIrql < DISPATCH_LEVEL) {
  557. OldIrql = KeRaiseIrqlToDpcLevel();
  558. }
  559. __mf();
  560. for (i=0; i<Count; i++) {
  561. *Buffer++ = *(volatile ULONG *)VirtualPort;
  562. __mfa();
  563. }
  564. if (OldIrql < DISPATCH_LEVEL) {
  565. KeLowerIrql(OldIrql);
  566. }
  567. }
  568. VOID
  569. WRITE_PORT_UCHAR (
  570. PUCHAR Port,
  571. UCHAR Value
  572. )
  573. {
  574. /*++
  575. Routine Description:
  576. Writes a byte to the Port specified.
  577. Arguements:
  578. Port - The port address of the I/O Port.
  579. Value - The value to be written to the I/O Port.
  580. Return Value:
  581. None.
  582. --*/
  583. UINT_PTR VirtualPort;
  584. KIRQL OldIrql;
  585. #if DBG
  586. if (DbgIoPorts) DbgPrint("WRITE_PORT_UCHAR(%#x,%#x)\n",Port,Value);
  587. #endif
  588. VirtualPort = HalpGetPortVirtualAddress((UINT_PTR)Port);
  589. //
  590. // Need to ensure load and mfa are not preemptable
  591. //
  592. __mf();
  593. OldIrql = KeGetCurrentIrql();
  594. if (OldIrql < DISPATCH_LEVEL) {
  595. OldIrql = KeRaiseIrqlToDpcLevel();
  596. }
  597. *(volatile UCHAR *)VirtualPort = Value;
  598. __mf();
  599. __mfa();
  600. if (OldIrql < DISPATCH_LEVEL) {
  601. KeLowerIrql (OldIrql);
  602. }
  603. }
  604. VOID
  605. WRITE_PORT_USHORT (
  606. PUSHORT Port,
  607. USHORT Value
  608. )
  609. {
  610. /*++
  611. Routine Description:
  612. Writes a 16 bit SHORT Integer to the Port specified.
  613. Arguements:
  614. Port - The port address of the I/O Port.
  615. Value - The value to be written to the I/O Port.
  616. Return Value:
  617. None.
  618. --*/
  619. UINT_PTR VirtualPort;
  620. KIRQL OldIrql;
  621. #if DBG
  622. if (DbgIoPorts) DbgPrint("WRITE_PORT_USHORT(%#x,%#x)\n",Port,Value);
  623. #endif
  624. VirtualPort = HalpGetPortVirtualAddress((UINT_PTR)Port);
  625. //
  626. // Need to ensure load and mfa are not preemptable
  627. //
  628. __mf();
  629. OldIrql = KeGetCurrentIrql();
  630. if (OldIrql < DISPATCH_LEVEL) {
  631. OldIrql = KeRaiseIrqlToDpcLevel();
  632. }
  633. *(volatile USHORT *)VirtualPort = Value;
  634. __mf();
  635. __mfa();
  636. if (OldIrql < DISPATCH_LEVEL) {
  637. KeLowerIrql (OldIrql);
  638. }
  639. }
  640. VOID
  641. WRITE_PORT_ULONG (
  642. PULONG Port,
  643. ULONG Value
  644. )
  645. {
  646. /*++
  647. Routine Description:
  648. Writes a 32 bit Long Word to the Port specified.
  649. Arguements:
  650. Port - The port address of the I/O Port.
  651. Value - The value to be written to the I/O Port.
  652. Return Value:
  653. None.
  654. --*/
  655. UINT_PTR VirtualPort;
  656. KIRQL OldIrql;
  657. #if DBG
  658. if (DbgIoPorts) DbgPrint("WRITE_PORT_ULONG(%#x,%#x)\n",Port,Value);
  659. #endif
  660. VirtualPort = HalpGetPortVirtualAddress((UINT_PTR)Port);
  661. //
  662. // Need to ensure load and mfa are not preemptable
  663. //
  664. __mf();
  665. OldIrql = KeGetCurrentIrql();
  666. if (OldIrql < DISPATCH_LEVEL) {
  667. OldIrql = KeRaiseIrqlToDpcLevel();
  668. }
  669. *(volatile ULONG *)VirtualPort = Value;
  670. __mf();
  671. __mfa();
  672. if (OldIrql < DISPATCH_LEVEL) {
  673. KeLowerIrql (OldIrql);
  674. }
  675. }
  676. VOID
  677. WRITE_PORT_ULONG_SPECIAL (
  678. PULONG Port,
  679. ULONG Value
  680. )
  681. {
  682. /*++
  683. Routine Description:
  684. Writes a 32 bit Long Word to the Port specified.
  685. Assumes context switch is not possible. Used for A0 workaround.
  686. Arguements:
  687. Port - The port address of the I/O Port.
  688. Value - The value to be written to the I/O Port.
  689. Return Value:
  690. None.
  691. --*/
  692. UINT_PTR VirtualPort;
  693. #if DBG
  694. if (DbgIoPorts) DbgPrint("WRITE_PORT_ULONG(%#x,%#x)\n",Port,Value);
  695. #endif
  696. VirtualPort = HalpGetPortVirtualAddress((UINT_PTR)Port);
  697. *(volatile ULONG *)VirtualPort = Value;
  698. __mf();
  699. __mfa();
  700. }
  701. VOID
  702. WRITE_PORT_BUFFER_UCHAR (
  703. PUCHAR Port,
  704. PUCHAR Buffer,
  705. ULONG Count
  706. )
  707. {
  708. /*++
  709. Routine Description:
  710. Writes multiple bytes from the source buffer to the specified Port address.
  711. Arguements:
  712. Port - The address of the Port to write to.
  713. Buffer - A pointer to the buffer containing the data to write to the Port.
  714. Count - Supplies the number of bytes to write.
  715. Return Value:
  716. None.
  717. --*/
  718. UINT_PTR VirtualPort;
  719. ULONG i;
  720. KIRQL OldIrql;
  721. #if DBG
  722. if (DbgIoPorts) DbgPrint("WRITE_PORT_BUFFER_UCHAR(%#x,%#p,%d)\n",Port,Buffer,Count);
  723. #endif
  724. VirtualPort = HalpGetPortVirtualAddress((UINT_PTR)Port);
  725. //
  726. // Prevent preemption before mfa
  727. //
  728. OldIrql = KeGetCurrentIrql();
  729. if (OldIrql < DISPATCH_LEVEL) {
  730. OldIrql = KeRaiseIrqlToDpcLevel();
  731. }
  732. for (i=0; i<Count; i++) {
  733. *(volatile UCHAR *)VirtualPort = *Buffer++;
  734. __mfa();
  735. }
  736. if (OldIrql < DISPATCH_LEVEL) {
  737. KeLowerIrql(OldIrql);
  738. }
  739. __mf();
  740. }
  741. VOID
  742. WRITE_PORT_BUFFER_USHORT (
  743. PUSHORT Port,
  744. PUSHORT Buffer,
  745. ULONG Count
  746. )
  747. {
  748. /*++
  749. Routine Description:
  750. Writes multiple 16bit short integers from the source buffer to the specified Port address.
  751. Arguements:
  752. Port - The address of the Port to write to.
  753. Buffer - A pointer to the buffer containing the data to write to the Port.
  754. Count - Supplies the number of (16 bit) words to write.
  755. Return Value:
  756. None.
  757. --*/
  758. UINT_PTR VirtualPort;
  759. ULONG i;
  760. KIRQL OldIrql;
  761. #if DBG
  762. if (DbgIoPorts) DbgPrint("WRITE_PORT_BUFFER_USHORT(%#x,%#p,%d)\n",Port,Buffer,Count);
  763. #endif
  764. VirtualPort = HalpGetPortVirtualAddress((UINT_PTR)Port);
  765. //
  766. // Prevent preemption before mfa
  767. //
  768. OldIrql = KeGetCurrentIrql();
  769. if (OldIrql < DISPATCH_LEVEL) {
  770. OldIrql = KeRaiseIrqlToDpcLevel();
  771. }
  772. for (i=0; i<Count; i++) {
  773. *(volatile USHORT *)VirtualPort = *Buffer++;
  774. __mfa();
  775. }
  776. if (OldIrql < DISPATCH_LEVEL) {
  777. KeLowerIrql(OldIrql);
  778. }
  779. __mf();
  780. }
  781. VOID
  782. WRITE_PORT_BUFFER_ULONG (
  783. PULONG Port,
  784. PULONG Buffer,
  785. ULONG Count
  786. )
  787. {
  788. /*++
  789. Routine Description:
  790. Writes multiple 32bit long words from the source buffer to the specified Port address.
  791. Arguements:
  792. Port - The address of the Port to write to.
  793. Buffer - A pointer to the buffer containing the data to write to the Port.
  794. Count - Supplies the number of (32 bit) long words to write.
  795. Return Value:
  796. None.
  797. --*/
  798. UINT_PTR VirtualPort;
  799. ULONG i;
  800. KIRQL OldIrql;
  801. #if DBG
  802. if (DbgIoPorts) DbgPrint("WRITE_PORT_BUFFER_ULONG(%#x,%#p,%d)\n",Port,Buffer,Count);
  803. #endif
  804. VirtualPort = HalpGetPortVirtualAddress((UINT_PTR)Port);
  805. //
  806. // Prevent preemption before mfa
  807. //
  808. OldIrql = KeGetCurrentIrql();
  809. if (OldIrql < DISPATCH_LEVEL) {
  810. OldIrql = KeRaiseIrqlToDpcLevel();
  811. }
  812. for (i=0; i<Count; i++) {
  813. *(volatile ULONG *)VirtualPort = *Buffer++;
  814. __mfa();
  815. }
  816. if (OldIrql < DISPATCH_LEVEL) {
  817. KeLowerIrql(OldIrql);
  818. }
  819. __mf();
  820. }