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.

1380 lines
36 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. ixcmos.c
  5. Abstract:
  6. Implements CMOS op region interface functionality
  7. Author:
  8. brian guarraci (t-briang) 07-14-2000
  9. Environment:
  10. Kernel mode only.
  11. Revision History:
  12. --*/
  13. #include "halp.h"
  14. #include "acpitabl.h"
  15. #include "exboosts.h"
  16. #include "wchar.h"
  17. #include "xxacpi.h"
  18. #ifdef ACPI_CMOS_ACTIVATE
  19. //
  20. // prototypes for the 2 HalpGet/Set ixcmos.asm functions
  21. //
  22. ULONG
  23. HalpGetCmosData(
  24. IN ULONG SourceLocation,
  25. IN ULONG SourceAddress,
  26. IN PUCHAR DataBuffer,
  27. IN ULONG ByteCount
  28. );
  29. ULONG
  30. HalpSetCmosData(
  31. IN ULONG SourceLocation,
  32. IN ULONG SourceAddress,
  33. IN PUCHAR DataBuffer,
  34. IN ULONG ByteCount
  35. );
  36. ULONG
  37. HalpcGetCmosDataByType(
  38. IN CMOS_DEVICE_TYPE CmosType,
  39. IN ULONG SourceAddress,
  40. IN PUCHAR DataBuffer,
  41. IN ULONG ByteCount
  42. );
  43. ULONG
  44. HalpcSetCmosDataByType(
  45. IN CMOS_DEVICE_TYPE CmosType,
  46. IN ULONG SourceAddress,
  47. IN PUCHAR DataBuffer,
  48. IN ULONG ByteCount
  49. );
  50. ULONG
  51. HalpReadCmosDataByPort(
  52. IN ULONG AddrPort,
  53. IN ULONG DataPort,
  54. IN ULONG SourceAddress,
  55. IN PUCHAR ReturnBuffer,
  56. IN ULONG ByteCount
  57. );
  58. ULONG
  59. HalpWriteCmosDataByPort(
  60. IN ULONG AddrPort,
  61. IN ULONG DataPort,
  62. IN ULONG SourceAddress,
  63. IN PUCHAR ReturnBuffer,
  64. IN ULONG ByteCount
  65. );
  66. ULONG
  67. HalpReadCmosData(
  68. IN ULONG SourceLocation,
  69. IN ULONG SourceAddress,
  70. IN ULONG ReturnBuffer,
  71. IN PUCHAR ByteCount
  72. );
  73. ULONG
  74. HalpWriteCmosData(
  75. IN ULONG SourceLocation,
  76. IN ULONG SourceAddress,
  77. IN ULONG ReturnBuffer,
  78. IN PUCHAR ByteCount
  79. );
  80. ULONG
  81. HalpReadStdCmosData(
  82. IN ULONG SourceAddress,
  83. IN PUCHAR ReturnBuffer,
  84. IN ULONG ByteCount
  85. );
  86. ULONG
  87. HalpWriteStdCmosData(
  88. IN ULONG SourceAddress,
  89. IN PUCHAR ReturnBuffer,
  90. IN ULONG ByteCount
  91. );
  92. ULONG
  93. HalpReadRtcStdPCAT(
  94. IN ULONG SourceAddress,
  95. IN PUCHAR ReturnBuffer,
  96. IN ULONG ByteCount
  97. );
  98. ULONG
  99. HalpWriteRtcStdPCAT(
  100. IN ULONG SourceAddress,
  101. IN PUCHAR ReturnBuffer,
  102. IN ULONG ByteCount
  103. );
  104. ULONG
  105. HalpReadRtcIntelPIIX4(
  106. IN ULONG SourceAddress,
  107. IN PUCHAR ReturnBuffer,
  108. IN ULONG ByteCount
  109. );
  110. ULONG
  111. HalpWriteRtcIntelPIIX4(
  112. IN ULONG SourceAddress,
  113. IN PUCHAR ReturnBuffer,
  114. IN ULONG ByteCount
  115. );
  116. ULONG
  117. HalpReadExtCmosIntelPIIX4(
  118. IN ULONG SourceAddress,
  119. IN PUCHAR ReturnBuffer,
  120. IN ULONG ByteCount
  121. );
  122. ULONG
  123. HalpWriteExtCmosIntelPIIX4(
  124. IN ULONG SourceAddress,
  125. IN PUCHAR ReturnBuffer,
  126. IN ULONG ByteCount
  127. );
  128. ULONG
  129. HalpReadRtcDal1501(
  130. IN ULONG SourceAddress,
  131. IN PUCHAR ReturnBuffer,
  132. IN ULONG ByteCount
  133. );
  134. ULONG
  135. HalpWriteRtcDal1501(
  136. IN ULONG SourceAddress,
  137. IN PUCHAR ReturnBuffer,
  138. IN ULONG ByteCount
  139. );
  140. ULONG
  141. HalpReadExtCmosDal1501(
  142. IN ULONG SourceAddress,
  143. IN PUCHAR ReturnBuffer,
  144. IN ULONG ByteCount
  145. );
  146. ULONG
  147. HalpWriteExtCmosDal1501(
  148. IN ULONG SourceAddress,
  149. IN PUCHAR ReturnBuffer,
  150. IN ULONG ByteCount
  151. );
  152. //
  153. // at the time of this writing, the largest known cmos ram address is 0xff
  154. // that is, for a given cmos ram bank, the largest address is 0xff
  155. //
  156. typedef enum {
  157. LARGEST_KNOWN_CMOS_RAM_ADDRESS = 0xff
  158. } CMOS_RAM_ADDR_LIMITS;
  159. //
  160. // Additional information about Standard CMOS/RTC can be acquired at:
  161. //
  162. // "ISA System Architecture" Mindshare, Inc. (ISBN:0-201-40996-8) Chaper 21.
  163. //
  164. // To put the registers and the RTC region in context, the following
  165. // constants describe the layout of the registers (0x00 - 0x0d).
  166. // Registers A-D are control registers which affect the state of the rtc.
  167. //
  168. typedef enum {
  169. CMOS_RAM_STDPCAT_SECONDS = 0,
  170. CMOS_RAM_STDPCAT_SECONDS_ALARM,
  171. CMOS_RAM_STDPCAT_MINUTES,
  172. CMOS_RAM_STDPCAT_MINUTES_ALARM,
  173. CMOS_RAM_STDPCAT_HOURS,
  174. CMOS_RAM_STDPCAT_HOURS_ALARM,
  175. CMOS_RAM_STDPCAT_DAY_OF_WEEK,
  176. CMOS_RAM_STDPCAT_DATE_OF_MONTH,
  177. CMOS_RAM_STDPCAT_MONTH,
  178. CMOS_RAM_STDPCAT_YEAR,
  179. CMOS_RAM_STDPCAT_REGISTER_A,
  180. CMOS_RAM_STDPCAT_REGISTER_B,
  181. CMOS_RAM_STDPCAT_REGISTER_C,
  182. CMOS_RAM_STDPCAT_REGISTER_D
  183. } CMOS_RAM_STDPCAT_REGISTERS;
  184. //
  185. // definition of bits with in the control registers
  186. //
  187. typedef enum {
  188. //
  189. // (Update In Progress)
  190. // when the rtc is updating the rtc registers, this bit is set
  191. //
  192. //
  193. CMOS_RAM_STDPCAT_REGISTER_A_UIP_BIT = 0x80,
  194. //
  195. // this bit must be set when updating the rtc
  196. //
  197. CMOS_RAM_STDPCAT_REGISTER_B_SET_BIT = 0x80
  198. } CMOS_RAM_STDPCAT_REGISTER_BITS;
  199. //
  200. // Additional information about the Intel PIIX4 cmos/rtc chip
  201. // can be acquired at:
  202. //
  203. // http://developer.intel.com/design/intarch/DATASHTS/29056201.pdf
  204. //
  205. // To put the registers and the RTC region in context, the following
  206. // constants describe the layout of the
  207. //
  208. // Intel PIIX4 CMOS ram
  209. //
  210. // for the 0x00 - 0x0d registers. Registers A-D are control registers
  211. // which affect the state of the rtc.
  212. //
  213. //
  214. //
  215. typedef enum {
  216. CMOS_RAM_PIIX4_SECONDS = 0,
  217. CMOS_RAM_PIIX4_SECONDS_ALARM,
  218. CMOS_RAM_PIIX4_MINUTES,
  219. CMOS_RAM_PIIX4_MINUTES_ALARM,
  220. CMOS_RAM_PIIX4_HOURS,
  221. CMOS_RAM_PIIX4_HOURS_ALARM,
  222. CMOS_RAM_PIIX4_DAY_OF_WEEK,
  223. CMOS_RAM_PIIX4_DATE_OF_MONTH,
  224. CMOS_RAM_PIIX4_MONTH,
  225. CMOS_RAM_PIIX4_YEAR,
  226. CMOS_RAM_PIIX4_REGISTER_A,
  227. CMOS_RAM_PIIX4_REGISTER_B,
  228. CMOS_RAM_PIIX4_REGISTER_C,
  229. CMOS_RAM_PIIX4_REGISTER_D
  230. } CMOS_RAM_PIIX4_REGISTERS;
  231. //
  232. // definition of bits with in the control registers
  233. //
  234. typedef enum {
  235. //
  236. // (Update In Progress)
  237. // when the rtc is updating the rtc registers, this bit is set
  238. //
  239. //
  240. CMOS_RAM_PIIX4_REGISTER_A_UIP_BIT = 0x80,
  241. //
  242. // this bit must be set when updating the rtc
  243. //
  244. CMOS_RAM_PIIX4_REGISTER_B_SET_BIT = 0x80
  245. } CMOS_RAM_PIIX4_REGISTER_BITS;
  246. //
  247. // Additional information about the Dallas 1501 cmos/rtc chip
  248. // can be acquired at:
  249. //
  250. // http://www.dalsemi.com/datasheets/pdfs/1501-11.pdf
  251. //
  252. // To put the registers and the RTC region in context, the following
  253. // constants describe the layout of the
  254. //
  255. // Dallas 1501 CMOS ram
  256. //
  257. // for the 0x00 - 0x0d registers. Registers A-D are control registers
  258. // which affect the state of the rtc.
  259. //
  260. //
  261. //
  262. typedef enum {
  263. CMOS_RAM_DAL1501_SECONDS = 0,
  264. CMOS_RAM_DAL1501_MINUTES,
  265. CMOS_RAM_DAL1501_HOURS,
  266. CMOS_RAM_DAL1501_DAY,
  267. CMOS_RAM_DAL1501_DATE,
  268. CMOS_RAM_DAL1501_MONTH,
  269. CMOS_RAM_DAL1501_YEAR,
  270. CMOS_RAM_DAL1501_CENTURY,
  271. CMOS_RAM_DAL1501_ALARM_SECONDS,
  272. CMOS_RAM_DAL1501_ALARM_MINUTES,
  273. CMOS_RAM_DAL1501_ALARM_HOURS,
  274. CMOS_RAM_DAL1501_ALARM_DAYDATE,
  275. CMOS_RAM_DAL1501_WATCHDOG0,
  276. CMOS_RAM_DAL1501_WATCHDOG1,
  277. CMOS_RAM_DAL1501_REGISTER_A,
  278. CMOS_RAM_DAL1501_REGISTER_B,
  279. CMOS_RAM_DAL1501_RAM_ADDR_LSB, // 0x00 - 0xff
  280. CMOS_RAM_DAL1501_RESERVED0,
  281. CMOS_RAM_DAL1501_RESERVED1,
  282. CMOS_RAM_DAL1501_RAM_DATA // 0x00 - 0xff
  283. } CMOS_RAM_DAL1501_REGISTERS;
  284. typedef enum {
  285. //
  286. // The TE bit controls the update status of the external
  287. // RTC registers. When it is 0, the registers are frozen
  288. // with the last RTC values. If you modifiy the registers
  289. // while TE = 0, then when TE is set, the modifications
  290. // will transfer to the internal registers, hence modifying
  291. // the RTC state. In general, when TE is set, the external
  292. // registers then reflect the current RTC state.
  293. //
  294. CMOS_RAM_DAL1501_REGISTER_B_TE_BIT = 0x80
  295. } CMOS_RAM_DAL1501_REGISTER_BITS;
  296. #define MAX(a, b) ((a) > (b) ? (a) : (b))
  297. #define MIN(a, b) ((a) < (b) ? (a) : (b))
  298. typedef enum {
  299. CmosStdAddrPort = 0x70,
  300. CmosStdDataPort = 0x71
  301. };
  302. typedef enum {
  303. CMOS_READ,
  304. CMOS_WRITE
  305. } CMOS_ACCESS_TYPE;
  306. typedef
  307. ULONG
  308. (*PCMOS_RANGE_HANDLER) (
  309. IN ULONG SourceAddress,
  310. IN PUCHAR ReturnBuffer,
  311. IN ULONG ByteCount
  312. );
  313. typedef struct {
  314. ULONG start;
  315. ULONG stop;
  316. PCMOS_RANGE_HANDLER readHandler;
  317. PCMOS_RANGE_HANDLER writeHandler;
  318. } CMOS_ADDR_RANGE_HANDLER, *PCMOS_ADDR_RANGE_HANDLER;
  319. //
  320. // define the discrete ranges so that the appropriate
  321. // handlers can be used for each.
  322. //
  323. // Note: address ranges are inclusive
  324. //
  325. CMOS_ADDR_RANGE_HANDLER CmosRangeHandlersStdPCAT[] =
  326. {
  327. //
  328. // The RTC region
  329. //
  330. {0, 0x9, HalpReadRtcStdPCAT, HalpWriteRtcStdPCAT},
  331. //
  332. // The standard CMOS RAM region
  333. //
  334. {0x0a, 0x3f, HalpReadStdCmosData, HalpWriteStdCmosData},
  335. //
  336. // end of table
  337. //
  338. {0, 0, 0}
  339. };
  340. CMOS_ADDR_RANGE_HANDLER CmosRangeHandlersIntelPIIX4[] =
  341. {
  342. //
  343. // The RTC region
  344. //
  345. {0, 0x9, HalpReadRtcIntelPIIX4, HalpWriteRtcIntelPIIX4},
  346. //
  347. // The standard CMOS RAM region
  348. //
  349. {0x0a, 0x7f, HalpReadStdCmosData, HalpWriteStdCmosData},
  350. //
  351. // The extended CMOS SRAM region
  352. //
  353. {0x80, 0xff, HalpReadExtCmosIntelPIIX4, HalpWriteExtCmosIntelPIIX4},
  354. //
  355. // end of table
  356. //
  357. {0, 0, 0}
  358. };
  359. CMOS_ADDR_RANGE_HANDLER CmosRangeHandlersDal1501[] =
  360. {
  361. //
  362. // The RTC region
  363. //
  364. {0, 0x0b, HalpReadRtcDal1501, HalpWriteRtcDal1501},
  365. //
  366. // The standard CMOS RAM region
  367. //
  368. {0x0c, 0x0f, HalpReadStdCmosData, HalpWriteStdCmosData},
  369. //
  370. // NOTE: this table skips the standard CMOS range: 0x10 - 0x1f
  371. // because this area is reserved in the spec, and the is no
  372. // apparent reason why the op region should access this area.
  373. // Also, regs 0x10 and 0x13 are used to access the extended
  374. // ram, hence there is no reason why the op region should access
  375. // this either. Hence, all op region access beyond 0x0f are
  376. // interpretted as accesses into the Extended CMOS
  377. //
  378. //
  379. // The extended CMOS SRAM region
  380. //
  381. {0x10, 0x10f, HalpReadExtCmosDal1501, HalpWriteExtCmosDal1501},
  382. //
  383. // end of table
  384. //
  385. {0, 0, 0}
  386. };
  387. ULONG
  388. HalpCmosRangeHandler(
  389. IN CMOS_ACCESS_TYPE AccessType,
  390. IN CMOS_DEVICE_TYPE CmosType,
  391. IN ULONG Address,
  392. IN PUCHAR DataBuffer,
  393. IN ULONG ByteCount
  394. )
  395. {
  396. ULONG bytes; // bytes read in last operation
  397. ULONG offset; // the offset beyond the initial address
  398. ULONG bufOffset; // the index into the data buffer as we read in data
  399. ULONG extAddr; // the corrected address for accessing extended SRAM
  400. ULONG range; // the current address range we are checking for
  401. ULONG bytesRead; // total bytes successfully read
  402. ULONG length; // the length of the current operation read
  403. PCMOS_ADDR_RANGE_HANDLER rangeHandlers; // the table we are using
  404. //
  405. // get the appropriate table
  406. //
  407. switch (CmosType) {
  408. case CmosTypeStdPCAT:
  409. rangeHandlers = CmosRangeHandlersStdPCAT;
  410. break;
  411. case CmosTypeIntelPIIX4:
  412. rangeHandlers = CmosRangeHandlersIntelPIIX4;
  413. break;
  414. case CmosTypeDal1501:
  415. rangeHandlers = CmosRangeHandlersDal1501;
  416. break;
  417. default:
  418. break;
  419. }
  420. bytesRead = 0;
  421. bufOffset = 0;
  422. range = 0;
  423. offset = Address;
  424. length = ByteCount;
  425. while (rangeHandlers[range].stop) {
  426. if (offset <= rangeHandlers[range].stop) {
  427. //
  428. // get the # of bytes to read in this region
  429. //
  430. // length = MIN(remaining # bytes remaining to read, # bytes to read in the current range)
  431. //
  432. length = MIN((ByteCount - bytesRead), (rangeHandlers[range].stop - offset + 1));
  433. //
  434. // Since the handler routines are only called from here, we can consolidate
  435. // the ASSERTIONS. This is also nice, because we know which range in the
  436. // table we are dealing with, hence we know what the limits should be.
  437. //
  438. // make sure both the offset into the range,
  439. // and the operation's length are in bounds
  440. //
  441. ASSERT(offset <= rangeHandlers[range].stop);
  442. ASSERT((offset + length) <= (rangeHandlers[range].stop + 1));
  443. switch (AccessType) {
  444. case CMOS_READ:
  445. bytes = (rangeHandlers[range].readHandler)(
  446. offset,
  447. &DataBuffer[bufOffset],
  448. length);
  449. break;
  450. case CMOS_WRITE:
  451. bytes = (rangeHandlers[range].writeHandler)(
  452. offset,
  453. &DataBuffer[bufOffset],
  454. length);
  455. break;
  456. default:
  457. break;
  458. }
  459. ASSERT(bytes == length);
  460. bytesRead += bytes;
  461. //
  462. // adjust offset based on the length of the last operation
  463. //
  464. offset += length;
  465. bufOffset += length;
  466. }
  467. //
  468. // if offset is at or beyond specified range, then we are done
  469. //
  470. if (offset >= (Address + ByteCount)) {
  471. break;
  472. }
  473. //
  474. // move to the next range
  475. //
  476. range++;
  477. }
  478. ASSERT(bytesRead == ByteCount);
  479. return bytesRead;
  480. }
  481. ULONG
  482. HalpcGetCmosDataByType(
  483. IN CMOS_DEVICE_TYPE CmosType,
  484. IN ULONG Address,
  485. IN PUCHAR DataBuffer,
  486. IN ULONG ByteCount
  487. )
  488. {
  489. return HalpCmosRangeHandler(
  490. CMOS_READ,
  491. CmosType,
  492. Address,
  493. DataBuffer,
  494. ByteCount
  495. );
  496. }
  497. ULONG
  498. HalpcSetCmosDataByType(
  499. IN CMOS_DEVICE_TYPE CmosType,
  500. IN ULONG Address,
  501. IN PUCHAR DataBuffer,
  502. IN ULONG ByteCount
  503. )
  504. {
  505. return HalpCmosRangeHandler(
  506. CMOS_WRITE,
  507. CmosType,
  508. Address,
  509. DataBuffer,
  510. ByteCount
  511. );
  512. }
  513. ULONG
  514. HalpReadCmosDataByPort(
  515. IN ULONG AddrPort,
  516. IN ULONG DataPort,
  517. IN ULONG SourceAddress,
  518. IN PUCHAR ReturnBuffer,
  519. IN ULONG ByteCount
  520. )
  521. /*++
  522. This routine reads the requested number of bytes from CMOS using the
  523. specified ports and stores the data read into the supplied buffer in
  524. system memory. If the requested data amount exceeds the allowable
  525. extent of the source location, the return data is truncated.
  526. Arguments:
  527. AddrPort : address in the ISA I/O space to put the address
  528. DataPort : address in the ISA I/O space to put the data
  529. SourceAddress : address in CMOS where data is to be read from
  530. ReturnBuffer : address in system memory for return data
  531. ByteCount : number of bytes to be read
  532. Returns:
  533. Number of bytes actually read.
  534. Note:
  535. This routine doesn't perform safety precautions when operating
  536. in the RTC region of the CMOS. Use the appropriate RTC routine
  537. instead.
  538. --*/
  539. {
  540. ULONG offset;
  541. ULONG bufOffset;
  542. ULONG upperAddrBound;
  543. upperAddrBound = SourceAddress + ByteCount;
  544. ASSERT(SourceAddress <= LARGEST_KNOWN_CMOS_RAM_ADDRESS);
  545. ASSERT(upperAddrBound <= (LARGEST_KNOWN_CMOS_RAM_ADDRESS + 1));
  546. //
  547. // NOTE: The spinlock is needed even in the UP case, because
  548. // the resource is also used in an interrupt handler (profiler).
  549. // If we own the spinlock in this routine, and we service
  550. // the profiler interrupt (which will wait for the spinlock forever),
  551. // then we have a hosed system.
  552. //
  553. HalpAcquireCmosSpinLock();
  554. for (offset = SourceAddress, bufOffset = 0; offset < upperAddrBound; offset++, bufOffset++) {
  555. WRITE_PORT_UCHAR((PUCHAR)AddrPort, (UCHAR)offset);
  556. ReturnBuffer[bufOffset] = READ_PORT_UCHAR((PUCHAR)DataPort);
  557. }
  558. HalpReleaseCmosSpinLock();
  559. return bufOffset;
  560. }
  561. ULONG
  562. HalpWriteCmosDataByPort(
  563. IN ULONG AddrPort,
  564. IN ULONG DataPort,
  565. IN ULONG SourceAddress,
  566. IN PUCHAR ReturnBuffer,
  567. IN ULONG ByteCount
  568. )
  569. /*++
  570. This routine reads the requested number of bytes from CMOS using the
  571. specified ports and stores the data read into the supplied buffer in
  572. system memory. If the requested data amount exceeds the allowable
  573. extent of the source location, the return data is truncated.
  574. Arguments:
  575. AddrPort : address in the ISA I/O space to put the address
  576. DataPort : address in the ISA I/O space to put the data
  577. SourceAddress : address in CMOS where data is to be read from
  578. ReturnBuffer : address in system memory for return data
  579. ByteCount : number of bytes to be read
  580. Returns:
  581. Number of bytes actually read.
  582. Note:
  583. This routine doesn't perform safety precautions when operating
  584. in the RTC region of the CMOS. Use the appropriate RTC routine
  585. instead.
  586. --*/
  587. {
  588. ULONG offset;
  589. ULONG bufOffset;
  590. ULONG upperAddrBound;
  591. upperAddrBound = SourceAddress + ByteCount;
  592. ASSERT(SourceAddress <= LARGEST_KNOWN_CMOS_RAM_ADDRESS);
  593. ASSERT(upperAddrBound <= (LARGEST_KNOWN_CMOS_RAM_ADDRESS + 1));
  594. //
  595. // NOTE: The spinlock is needed even in the UP case, because
  596. // the resource is also used in an interrupt handler (profiler).
  597. // If we own the spinlock in this routine, and we service
  598. // the profiler interrupt (which will wait for the spinlock forever),
  599. // then we have a hosed system.
  600. //
  601. HalpAcquireCmosSpinLock();
  602. for (offset = SourceAddress, bufOffset = 0; offset < upperAddrBound; offset++, bufOffset++) {
  603. WRITE_PORT_UCHAR((PUCHAR)AddrPort, (UCHAR)offset);
  604. WRITE_PORT_UCHAR((PUCHAR)DataPort, (UCHAR)(ReturnBuffer[bufOffset]));
  605. }
  606. HalpReleaseCmosSpinLock();
  607. return bufOffset;
  608. }
  609. ULONG
  610. HalpReadStdCmosData(
  611. IN ULONG SourceAddress,
  612. IN PUCHAR ReturnBuffer,
  613. IN ULONG ByteCount
  614. )
  615. {
  616. return HalpReadCmosDataByPort(
  617. CmosStdAddrPort,
  618. CmosStdDataPort,
  619. SourceAddress,
  620. ReturnBuffer,
  621. ByteCount
  622. );
  623. }
  624. ULONG
  625. HalpWriteStdCmosData(
  626. IN ULONG SourceAddress,
  627. IN PUCHAR ReturnBuffer,
  628. IN ULONG ByteCount
  629. )
  630. {
  631. return HalpWriteCmosDataByPort(
  632. CmosStdAddrPort,
  633. CmosStdDataPort,
  634. SourceAddress,
  635. ReturnBuffer,
  636. ByteCount
  637. );
  638. }
  639. ULONG
  640. HalpReadRtcStdPCAT(
  641. IN ULONG SourceAddress,
  642. IN PUCHAR ReturnBuffer,
  643. IN ULONG ByteCount
  644. )
  645. /*++
  646. This routine handles reads into the standard PC/AT RTC range.
  647. Arguments:
  648. SourceAddress : address in CMOS where data is to be read from
  649. ReturnBuffer : address in system memory for return data
  650. ByteCount : number of bytes to be read
  651. Returns:
  652. Number of bytes actually read.
  653. --*/
  654. {
  655. ULONG offset;
  656. ULONG bufOffset;
  657. ULONG status; // register status
  658. ULONG uip; // update in progress bit
  659. ULONG upperAddrBound;
  660. upperAddrBound = SourceAddress + ByteCount;
  661. //
  662. // NOTE: The spinlock is needed even in the UP case, because
  663. // the resource is also used in an interrupt handler (profiler).
  664. // If we own the spinlock in this routine, and we service
  665. // the profiler interrupt (which will wait for the spinlock forever),
  666. // then we have a hosed system.
  667. //
  668. HalpAcquireCmosSpinLock();
  669. //
  670. // According to "ISA System Architecture"
  671. // by Mindshare, Inc. (ISBN:0-201-40996-8) Chaper 21.
  672. // the access method for reading standard PC/AT RTC is:
  673. //
  674. // 1. wait for the Update In Progress bit to clear
  675. // this is bit 7 of register A
  676. //
  677. // 2. read
  678. //
  679. //
  680. // wait until the rtc is done updating
  681. //
  682. do {
  683. WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_STDPCAT_REGISTER_A);
  684. status = READ_PORT_UCHAR((PUCHAR)CmosStdDataPort);
  685. uip = status & CMOS_RAM_STDPCAT_REGISTER_A_UIP_BIT;
  686. } while (uip);
  687. //
  688. // read
  689. //
  690. for (offset = SourceAddress, bufOffset = 0; offset < upperAddrBound; offset++, bufOffset++) {
  691. WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, (UCHAR)offset);
  692. ReturnBuffer[bufOffset] = READ_PORT_UCHAR((PUCHAR)CmosStdDataPort);
  693. }
  694. HalpReleaseCmosSpinLock();
  695. return bufOffset;
  696. }
  697. ULONG
  698. HalpWriteRtcStdPCAT(
  699. IN ULONG SourceAddress,
  700. IN PUCHAR ReturnBuffer,
  701. IN ULONG ByteCount
  702. )
  703. /*++
  704. This routine handles writes into the standard PC/AT RTC range.
  705. Arguments:
  706. SourceAddress : address in CMOS where data is to be read from
  707. ReturnBuffer : address in system memory for return data
  708. ByteCount : number of bytes to be read
  709. Returns:
  710. Number of bytes actually read.
  711. --*/
  712. {
  713. ULONG offset;
  714. ULONG bufOffset;
  715. ULONG status; // register status
  716. ULONG uip; // update in progress bit
  717. ULONG upperAddrBound;
  718. upperAddrBound = SourceAddress + ByteCount;
  719. //
  720. // NOTE: The spinlock is needed even in the UP case, because
  721. // the resource is also used in an interrupt handler (profiler).
  722. // If we own the spinlock in this routine, and we service
  723. // the profiler interrupt (which will wait for the spinlock forever),
  724. // then we have a hosed system.
  725. //
  726. HalpAcquireCmosSpinLock();
  727. //
  728. // According to "ISA System Architecture"
  729. // by Mindshare, Inc. (ISBN:0-201-40996-8) Chapter 21.
  730. // the access method for writing to standard PC/AT RTC is:
  731. //
  732. // 1. wait for the Update In Progress bit (UIP) to clear,
  733. // where UIP is bit 7 of register A
  734. //
  735. // 2. set the SET bit to notify the RTC that the registers
  736. // are being updated. The SET bit is bit 7 of register B
  737. //
  738. // 3. update the rtc registers
  739. //
  740. // 4. clear the SET bit, notifying the RTC that we are done writing
  741. //
  742. //
  743. // wait until the rtc is done updating
  744. //
  745. do {
  746. WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_STDPCAT_REGISTER_A);
  747. status = READ_PORT_UCHAR((PUCHAR)CmosStdDataPort);
  748. uip = status & CMOS_RAM_STDPCAT_REGISTER_A_UIP_BIT;
  749. } while (uip);
  750. //
  751. // set the SET bit of register B
  752. //
  753. WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_STDPCAT_REGISTER_B);
  754. status = READ_PORT_UCHAR((PUCHAR)CmosStdDataPort);
  755. status |= CMOS_RAM_STDPCAT_REGISTER_B_SET_BIT;
  756. WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_STDPCAT_REGISTER_B);
  757. WRITE_PORT_UCHAR((PUCHAR)CmosStdDataPort, (UCHAR)(status));
  758. //
  759. // update the rtc registers
  760. //
  761. for (offset = SourceAddress, bufOffset = 0; offset < upperAddrBound; offset++, bufOffset++) {
  762. WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, (UCHAR)offset);
  763. WRITE_PORT_UCHAR((PUCHAR)CmosStdDataPort, (UCHAR)(ReturnBuffer[bufOffset]));
  764. }
  765. //
  766. // clear the SET bit of register B
  767. //
  768. WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_STDPCAT_REGISTER_B);
  769. status = READ_PORT_UCHAR((PUCHAR)CmosStdDataPort);
  770. status &= ~CMOS_RAM_STDPCAT_REGISTER_B_SET_BIT;
  771. WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_STDPCAT_REGISTER_B);
  772. WRITE_PORT_UCHAR((PUCHAR)CmosStdDataPort, (UCHAR)(status));
  773. HalpReleaseCmosSpinLock();
  774. return bufOffset;
  775. }
  776. ULONG
  777. HalpReadRtcIntelPIIX4(
  778. IN ULONG SourceAddress,
  779. IN PUCHAR ReturnBuffer,
  780. IN ULONG ByteCount
  781. )
  782. /*++
  783. This routine reads the RTC range for the Intel PIIX4 CMOS/RTC chip
  784. Arguments:
  785. SourceAddress : address in CMOS where data is to be read from
  786. ReturnBuffer : address in system memory for return data
  787. ByteCount : number of bytes to be read
  788. Returns:
  789. Number of bytes actually read.
  790. --*/
  791. {
  792. //
  793. // Use the access method for the Standard PC/AT since it is
  794. // equivalent to the Intel PIIX4 access method.
  795. //
  796. return HalpReadRtcStdPCAT(
  797. SourceAddress,
  798. ReturnBuffer,
  799. ByteCount
  800. );
  801. }
  802. ULONG
  803. HalpWriteRtcIntelPIIX4(
  804. IN ULONG SourceAddress,
  805. IN PUCHAR ReturnBuffer,
  806. IN ULONG ByteCount
  807. )
  808. /*++
  809. This routine handles writes into the RTC range for the Intel PIIX4 CMOS/RTC chip
  810. Arguments:
  811. SourceAddress : address in CMOS where data is to be read from
  812. ReturnBuffer : address in system memory for return data
  813. ByteCount : number of bytes to be read
  814. Returns:
  815. Number of bytes actually read.
  816. --*/
  817. {
  818. //
  819. // Use the access method for the Standard PC/AT since it is
  820. // equivalent to the Intel PIIX4 access method.
  821. //
  822. return HalpWriteRtcStdPCAT(
  823. SourceAddress,
  824. ReturnBuffer,
  825. ByteCount
  826. );
  827. }
  828. ULONG
  829. HalpReadExtCmosIntelPIIX4(
  830. IN ULONG SourceAddress,
  831. IN PUCHAR ReturnBuffer,
  832. IN ULONG ByteCount
  833. )
  834. /*++
  835. This routine reads the RTC registers for the Intel PIIX4 CMOS/RTC chip.
  836. Arguments:
  837. SourceAddress : address in CMOS where data is to be read from
  838. ReturnBuffer : address in system memory for return data
  839. ByteCount : number of bytes to be read
  840. Returns:
  841. Number of bytes actually read.
  842. --*/
  843. {
  844. //
  845. // The Intel PIIX4 Extended SRAM is accessed using
  846. // next pair of IO ports above the standard addr/data ports.
  847. // Hence, we can simply forward the request with the correct pair.
  848. //
  849. return HalpReadCmosDataByPort(
  850. CmosStdAddrPort + 2,
  851. CmosStdDataPort + 2,
  852. SourceAddress,
  853. ReturnBuffer,
  854. ByteCount
  855. );
  856. }
  857. ULONG
  858. HalpWriteExtCmosIntelPIIX4(
  859. IN ULONG SourceAddress,
  860. IN PUCHAR ReturnBuffer,
  861. IN ULONG ByteCount
  862. )
  863. /*++
  864. This routine handles writes into the RTC registers for the Intel PIIX4 CMOS/RTC chip.
  865. Arguments:
  866. SourceAddress : address in CMOS where data is to be read from
  867. ReturnBuffer : address in system memory for return data
  868. ByteCount : number of bytes to be read
  869. Returns:
  870. Number of bytes actually read.
  871. --*/
  872. {
  873. //
  874. // The Intel PIIX4 Extended SRAM is accessed using
  875. // next pair of IO ports above the standard addr/data ports.
  876. // Hence, we can simply forward the request with the correct pair.
  877. //
  878. return HalpWriteCmosDataByPort(
  879. CmosStdAddrPort + 2,
  880. CmosStdDataPort + 2,
  881. SourceAddress,
  882. ReturnBuffer,
  883. ByteCount
  884. );
  885. }
  886. ULONG
  887. HalpReadRtcDal1501(
  888. IN ULONG SourceAddress,
  889. IN PUCHAR ReturnBuffer,
  890. IN ULONG ByteCount
  891. )
  892. /*++
  893. This routine reads the RTC registers for the Dallas 1501 CMOS/RTC chip.
  894. Arguments:
  895. SourceAddress : address in CMOS where data is to be read from
  896. ReturnBuffer : address in system memory for return data
  897. ByteCount : number of bytes to be read
  898. Returns:
  899. Number of bytes actually read.
  900. --*/
  901. {
  902. ULONG offset;
  903. ULONG bufOffset;
  904. ULONG status; // register status
  905. ULONG upperAddrBound;
  906. upperAddrBound = SourceAddress + ByteCount;
  907. //
  908. // NOTE: The spinlock is needed even in the UP case, because
  909. // the resource is also used in an interrupt handler (profiler).
  910. // If we own the spinlock in this routine, and we service
  911. // the profiler interrupt (which will wait for the spinlock forever),
  912. // then we have a hosed system.
  913. //
  914. HalpAcquireCmosSpinLock();
  915. //
  916. // NOTE: The recommended procedure for reading the Dallas 1501 RTC is to stop
  917. // external register updates while reading. Internally, updates in the RTC
  918. // continue as normal. This procedure prevents reading the registers while
  919. // they are in transition
  920. //
  921. //
  922. // Clear the TE bit of register B to stop external updates
  923. //
  924. WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_DAL1501_REGISTER_B);
  925. status = READ_PORT_UCHAR((PUCHAR)CmosStdDataPort);
  926. status &= ~CMOS_RAM_DAL1501_REGISTER_B_TE_BIT;
  927. WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_DAL1501_REGISTER_B);
  928. WRITE_PORT_UCHAR((PUCHAR)CmosStdDataPort, (UCHAR)status);
  929. for (offset = SourceAddress, bufOffset = 0; offset < upperAddrBound; offset++, bufOffset++) {
  930. WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, (UCHAR)offset);
  931. ReturnBuffer[bufOffset] = READ_PORT_UCHAR((PUCHAR)CmosStdDataPort);
  932. }
  933. //
  934. // Set the TE bit of register B to enable external updates
  935. //
  936. WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_DAL1501_REGISTER_B);
  937. status = READ_PORT_UCHAR((PUCHAR)CmosStdDataPort);
  938. status |= CMOS_RAM_DAL1501_REGISTER_B_TE_BIT;
  939. WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_DAL1501_REGISTER_B);
  940. WRITE_PORT_UCHAR((PUCHAR)CmosStdDataPort, (UCHAR)status);
  941. HalpReleaseCmosSpinLock();
  942. return bufOffset;
  943. }
  944. ULONG
  945. HalpWriteRtcDal1501(
  946. IN ULONG SourceAddress,
  947. IN PUCHAR ReturnBuffer,
  948. IN ULONG ByteCount
  949. )
  950. /*++
  951. This routine handles writes into the RTC region for the Dallas 1501 CMOS/RTC chip.
  952. Arguments:
  953. SourceAddress : address in CMOS where data is to be read from
  954. ReturnBuffer : address in system memory for return data
  955. ByteCount : number of bytes to be read
  956. Returns:
  957. Number of bytes actually read.
  958. --*/
  959. {
  960. ULONG offset;
  961. ULONG bufOffset;
  962. ULONG status; // register status
  963. ULONG upperAddrBound;
  964. upperAddrBound = SourceAddress + ByteCount;
  965. //
  966. // NOTE: The spinlock is needed even in the UP case, because
  967. // the resource is also used in an interrupt handler (profiler).
  968. // If we own the spinlock in this routine, and we service
  969. // the profiler interrupt (which will wait for the spinlock forever),
  970. // then we have a hosed system.
  971. //
  972. HalpAcquireCmosSpinLock();
  973. //
  974. // NOTE: The recommended procedure for writing the Dallas 1501 RTC is to stop
  975. // external register updates while writing. The modified register values
  976. // are transferred into the internal registers when the TE bit is set. Operation
  977. // then continues normally.
  978. //
  979. //
  980. // Clear the TE bit of register B to stop external updates
  981. //
  982. WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_DAL1501_REGISTER_B);
  983. status = READ_PORT_UCHAR((PUCHAR)CmosStdDataPort);
  984. status &= ~CMOS_RAM_DAL1501_REGISTER_B_TE_BIT;
  985. WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_DAL1501_REGISTER_B);
  986. WRITE_PORT_UCHAR((PUCHAR)CmosStdDataPort, (UCHAR)status);
  987. for (offset = SourceAddress, bufOffset = 0; offset < upperAddrBound; offset++, bufOffset++) {
  988. WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, (UCHAR)offset);
  989. WRITE_PORT_UCHAR((PUCHAR)CmosStdDataPort, (UCHAR)(ReturnBuffer[bufOffset]));
  990. }
  991. //
  992. // Set the TE bit of register B to enable external updates
  993. //
  994. WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_DAL1501_REGISTER_B);
  995. status = READ_PORT_UCHAR((PUCHAR)CmosStdDataPort);
  996. status |= CMOS_RAM_DAL1501_REGISTER_B_TE_BIT;
  997. WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_DAL1501_REGISTER_B);
  998. WRITE_PORT_UCHAR((PUCHAR)CmosStdDataPort, (UCHAR)status);
  999. HalpReleaseCmosSpinLock();
  1000. return bufOffset;
  1001. }
  1002. ULONG
  1003. HalpReadExtCmosDal1501(
  1004. IN ULONG SourceAddress,
  1005. IN PUCHAR ReturnBuffer,
  1006. IN ULONG ByteCount
  1007. )
  1008. {
  1009. ULONG offset;
  1010. ULONG bufOffset;
  1011. ULONG status; // register status
  1012. ULONG upperAddrBound;
  1013. upperAddrBound = SourceAddress + ByteCount;
  1014. //
  1015. // NOTE: The spinlock is needed even in the UP case, because
  1016. // the resource is also used in an interrupt handler (profiler).
  1017. // If we own the spinlock in this routine, and we service
  1018. // the profiler interrupt (which will wait for the spinlock forever),
  1019. // then we have a hosed system.
  1020. //
  1021. HalpAcquireCmosSpinLock();
  1022. //
  1023. // reading from Dallas 1501 SRAM is a 2 step process:
  1024. // 1. First, we write the address to the RAM_ADDR_LSB register in the standard CMOS region.
  1025. // 2. Then we read the data byte from the RAM_DATA register in the standard CMOS region.
  1026. //
  1027. for (offset = SourceAddress, bufOffset = 0; offset < upperAddrBound; offset++, bufOffset++) {
  1028. //
  1029. // specify the offset into SRAM
  1030. //
  1031. WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_DAL1501_RAM_ADDR_LSB);
  1032. WRITE_PORT_UCHAR((PUCHAR)CmosStdDataPort, (UCHAR)offset);
  1033. //
  1034. // read the data from SRAM[offset]
  1035. //
  1036. WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_DAL1501_RAM_DATA);
  1037. ReturnBuffer[bufOffset] = READ_PORT_UCHAR((PUCHAR)CmosStdDataPort);
  1038. }
  1039. HalpReleaseCmosSpinLock();
  1040. return bufOffset;
  1041. }
  1042. ULONG
  1043. HalpWriteExtCmosDal1501(
  1044. IN ULONG SourceAddress,
  1045. IN PUCHAR ReturnBuffer,
  1046. IN ULONG ByteCount
  1047. )
  1048. {
  1049. ULONG offset;
  1050. ULONG bufOffset;
  1051. ULONG status; // register status
  1052. ULONG upperAddrBound;
  1053. upperAddrBound = SourceAddress + ByteCount;
  1054. //
  1055. // NOTE: The spinlock is needed even in the UP case, because
  1056. // the resource is also used in an interrupt handler (profiler).
  1057. // If we own the spinlock in this routine, and we service
  1058. // the profiler interrupt (which will wait for the spinlock forever),
  1059. // then we have a hosed system.
  1060. //
  1061. HalpAcquireCmosSpinLock();
  1062. //
  1063. // writing to Dallas 1501 SRAM is a 2 step process:
  1064. // 1. First, we write the address to the RAM_ADDR_LSB register in the standard CMOS region.
  1065. // 2. Then we write the data byte to the RAM_DATA register in the standard CMOS region.
  1066. //
  1067. for (offset = SourceAddress, bufOffset = 0; offset < upperAddrBound; offset++, bufOffset++) {
  1068. //
  1069. // specify the offset into SRAM
  1070. //
  1071. WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_DAL1501_RAM_ADDR_LSB);
  1072. WRITE_PORT_UCHAR((PUCHAR)CmosStdDataPort, (UCHAR)offset);
  1073. //
  1074. // specify the data to be written into SRAM[offset]
  1075. //
  1076. WRITE_PORT_UCHAR((PUCHAR)CmosStdAddrPort, CMOS_RAM_DAL1501_RAM_DATA);
  1077. WRITE_PORT_UCHAR((PUCHAR)CmosStdDataPort, (UCHAR)(ReturnBuffer[bufOffset]));
  1078. }
  1079. HalpReleaseCmosSpinLock();
  1080. return bufOffset;
  1081. }
  1082. #endif // ACPI_CMOS_ACTIVATE