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.

1264 lines
36 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. smbmisc.c
  5. Abstract:
  6. SMBus handler functions
  7. Author:
  8. Ken Reneris
  9. Environment:
  10. Notes:
  11. Revision History:
  12. Chris Windle 1/27/98 Bug Fixes
  13. --*/
  14. #include "smbbattp.h"
  15. //
  16. // Make the SelectorBit table pageable
  17. //
  18. //#ifdef ALLOC_DATA_PRAGMA
  19. //#pragma data_seg("PAGE")
  20. //#endif
  21. //
  22. // Lookup table for the battery that corresponds to bit positions and
  23. // whether or not reverse logic is being used (to indicate charging or
  24. // discharging).
  25. //
  26. // NOTE: To support Simultaneous Charging and Powering, this table
  27. // has been modified to account for multiple bits. Also, it can't be
  28. // used for battery index lookup since it assumes one bit set maximum.
  29. // Instead, use special indexes for multiple batteries as follows:
  30. //
  31. // 1st Battery = Index & 0x03
  32. // 2nd Battery = (Index >> 2) & 0x03 (Battery A not allowed)
  33. // 3rd Battery = (Index >> 4) & 0x03 (Battery A not allowed)
  34. //
  35. // In < 4 battery systems the Battery D bit can be used to determine
  36. // the nibbles that are inverted, and it allows the following combinations:
  37. //
  38. // Battery A & B
  39. // Battery A & C
  40. // Battery B & C
  41. // Battery A, B, & C
  42. //
  43. const SELECTOR_STATE_LOOKUP SelectorBits [16] = {
  44. {BATTERY_NONE, FALSE}, // Bit Pattern: 0000
  45. {BATTERY_A, FALSE}, // 0001
  46. {BATTERY_B, FALSE}, // 0010
  47. {MULTIBATT_AB, FALSE}, // 0011
  48. {BATTERY_C, FALSE}, // 0100
  49. {MULTIBATT_AC, FALSE}, // 0101
  50. {MULTIBATT_BC, FALSE}, // 0110
  51. {MULTIBATT_ABC, FALSE}, // 0111
  52. {MULTIBATT_ABC, TRUE}, // 1000
  53. {MULTIBATT_BC, TRUE}, // 1001
  54. {MULTIBATT_AC, TRUE}, // 1010
  55. {BATTERY_C, TRUE}, // 1011
  56. {MULTIBATT_AB, TRUE}, // 1100
  57. {BATTERY_B, TRUE}, // 1101
  58. {BATTERY_A, TRUE}, // 1110
  59. {BATTERY_NONE, TRUE} // 1111
  60. };
  61. //
  62. // Note: For 4-Battery Systems to support Simultaneous Capability
  63. // properly, the following two assumptions must be made:
  64. // - Battery D can never be used simultaneously.
  65. // - Three batteries can not be used simultaneously.
  66. //
  67. // This allows for only the following possible battery combinations:
  68. //
  69. // Battery A & B
  70. // Battery A & C
  71. // Battery B & C
  72. //
  73. // The following table is used for 4-battery lookup
  74. //
  75. const SELECTOR_STATE_LOOKUP SelectorBits4 [16] = {
  76. {BATTERY_NONE, FALSE}, // Bit Pattern: 0000
  77. {BATTERY_A, FALSE}, // 0001
  78. {BATTERY_B, FALSE}, // 0010
  79. {MULTIBATT_AB, FALSE}, // 0011
  80. {BATTERY_C, FALSE}, // 0100
  81. {MULTIBATT_AC, FALSE}, // 0101
  82. {MULTIBATT_BC, FALSE}, // 0110
  83. {BATTERY_D, TRUE}, // 0111
  84. {BATTERY_D, FALSE}, // 1000
  85. {MULTIBATT_BC, TRUE}, // 1001
  86. {MULTIBATT_AC, TRUE}, // 1010
  87. {BATTERY_C, TRUE}, // 1011
  88. {MULTIBATT_AB, TRUE}, // 1100
  89. {BATTERY_B, TRUE}, // 1101
  90. {BATTERY_A, TRUE}, // 1110
  91. {BATTERY_NONE, TRUE} // 1111
  92. };
  93. #ifdef ALLOC_PRAGMA
  94. #pragma alloc_text(PAGE,SmbBattLockDevice)
  95. #pragma alloc_text(PAGE,SmbBattUnlockDevice)
  96. #pragma alloc_text(PAGE,SmbBattLockSelector)
  97. #pragma alloc_text(PAGE,SmbBattUnlockSelector)
  98. #pragma alloc_text(PAGE,SmbBattRequest)
  99. #pragma alloc_text(PAGE,SmbBattRB)
  100. #pragma alloc_text(PAGE,SmbBattRW)
  101. #pragma alloc_text(PAGE,SmbBattRSW)
  102. #pragma alloc_text(PAGE,SmbBattWW)
  103. #pragma alloc_text(PAGE,SmbBattGenericRW)
  104. #pragma alloc_text(PAGE,SmbBattGenericWW)
  105. #pragma alloc_text(PAGE,SmbBattGenericRequest)
  106. #pragma alloc_text(PAGE,SmbBattSetSelectorComm)
  107. #pragma alloc_text(PAGE,SmbBattResetSelectorComm)
  108. #if DEBUG
  109. #pragma alloc_text(PAGE,SmbBattDirectDataAccess)
  110. #endif
  111. #pragma alloc_text(PAGE,SmbBattIndex)
  112. #pragma alloc_text(PAGE,SmbBattReverseLogic)
  113. #pragma alloc_text(PAGE,SmbBattAcquireGlobalLock)
  114. #pragma alloc_text(PAGE,SmbBattReleaseGlobalLock)
  115. #endif
  116. VOID
  117. SmbBattLockDevice (
  118. IN PSMB_BATT SmbBatt
  119. )
  120. {
  121. PAGED_CODE();
  122. //
  123. // Get device lock on the battery
  124. //
  125. ExAcquireFastMutex (&SmbBatt->NP->Mutex);
  126. }
  127. VOID
  128. SmbBattUnlockDevice (
  129. IN PSMB_BATT SmbBatt
  130. )
  131. {
  132. PAGED_CODE();
  133. //
  134. // Release device lock on the battery
  135. //
  136. ExReleaseFastMutex (&SmbBatt->NP->Mutex);
  137. }
  138. VOID
  139. SmbBattLockSelector (
  140. IN PBATTERY_SELECTOR Selector
  141. )
  142. {
  143. PAGED_CODE();
  144. //
  145. // Get device lock on the selector
  146. //
  147. if (Selector) {
  148. ExAcquireFastMutex (&Selector->Mutex);
  149. }
  150. }
  151. VOID
  152. SmbBattUnlockSelector (
  153. IN PBATTERY_SELECTOR Selector
  154. )
  155. {
  156. PAGED_CODE();
  157. //
  158. // Release device lock on the selector
  159. //
  160. if (Selector) {
  161. ExReleaseFastMutex (&Selector->Mutex);
  162. }
  163. }
  164. NTSTATUS
  165. SmbBattSynchronousRequest (
  166. IN PDEVICE_OBJECT DeviceObject,
  167. IN PIRP Irp,
  168. IN PVOID Context
  169. )
  170. /*++
  171. Routine Description:
  172. Completion function for synchronous IRPs sent to this driver.
  173. Context is the event to set
  174. --*/
  175. {
  176. PKEVENT Event;
  177. Event = (PKEVENT) Context;
  178. KeSetEvent (Event, IO_NO_INCREMENT, FALSE);
  179. return STATUS_MORE_PROCESSING_REQUIRED;
  180. }
  181. VOID
  182. SmbBattRequest (
  183. IN PSMB_BATT SmbBatt,
  184. IN PSMB_REQUEST SmbReq
  185. )
  186. // function to issue SMBus request
  187. {
  188. KEVENT Event;
  189. PIRP Irp;
  190. PIO_STACK_LOCATION IrpSp;
  191. NTSTATUS Status;
  192. BOOLEAN useLock = SmbBattUseGlobalLock;
  193. ACPI_MANIPULATE_GLOBAL_LOCK_BUFFER globalLock;
  194. PAGED_CODE();
  195. //
  196. // Build Io Control for SMB bus driver for this request
  197. //
  198. KeInitializeEvent (&Event, NotificationEvent, FALSE);
  199. if (!SmbBatt->SmbHcFdo) {
  200. //
  201. // The SMB host controller either hasn't been opened yet (in start device) or
  202. // there was an error opening it and we did not get deleted somehow.
  203. //
  204. BattPrint(BAT_ERROR, ("SmbBattRequest: SmbHc hasn't been opened yet \n"));
  205. SmbReq->Status = SMB_UNKNOWN_FAILURE;
  206. return ;
  207. }
  208. Irp = IoAllocateIrp (SmbBatt->SmbHcFdo->StackSize, FALSE);
  209. if (!Irp) {
  210. SmbReq->Status = SMB_UNKNOWN_FAILURE;
  211. return ;
  212. }
  213. IrpSp = IoGetNextIrpStackLocation(Irp);
  214. IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  215. IrpSp->Parameters.DeviceIoControl.IoControlCode = SMB_BUS_REQUEST;
  216. IrpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof(SMB_REQUEST);
  217. IrpSp->Parameters.DeviceIoControl.Type3InputBuffer = SmbReq;
  218. IoSetCompletionRoutine (Irp, SmbBattSynchronousRequest, &Event, TRUE, TRUE, TRUE);
  219. //
  220. // Issue it
  221. //
  222. //
  223. // Note: uselock is a cached value of the global variable, so in case the
  224. // value changes, we won't aquire and not release etc.
  225. //
  226. if (useLock) {
  227. if (!NT_SUCCESS (SmbBattAcquireGlobalLock (SmbBatt->SmbHcFdo, &globalLock))) {
  228. useLock = FALSE;
  229. }
  230. }
  231. IoCallDriver (SmbBatt->SmbHcFdo, Irp);
  232. KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
  233. Status = Irp->IoStatus.Status;
  234. IoFreeIrp (Irp);
  235. if (useLock) {
  236. SmbBattReleaseGlobalLock (SmbBatt->SmbHcFdo, &globalLock);
  237. }
  238. //
  239. // Check result code
  240. //
  241. if (!NT_SUCCESS(Status)) {
  242. BattPrint(BAT_ERROR, ("SmbBattRequest: error in SmbHc request - %x\n", Status));
  243. SmbReq->Status = SMB_UNKNOWN_FAILURE;
  244. }
  245. }
  246. VOID
  247. SmbBattRB(
  248. IN PSMB_BATT SmbBatt,
  249. IN UCHAR SmbCmd,
  250. OUT PUCHAR Buffer,
  251. OUT PUCHAR BufferLength
  252. )
  253. // function to read-block from the battery
  254. {
  255. SMB_REQUEST SmbReq;
  256. PAGED_CODE();
  257. SmbReq.Protocol = SMB_READ_BLOCK;
  258. SmbReq.Address = SMB_BATTERY_ADDRESS;
  259. SmbReq.Command = SmbCmd;
  260. SmbBattRequest (SmbBatt, &SmbReq);
  261. if (SmbReq.Status == SMB_STATUS_OK) {
  262. ASSERT (SmbReq.BlockLength < SMB_MAX_DATA_SIZE);
  263. memcpy (Buffer, SmbReq.Data, SmbReq.BlockLength);
  264. *BufferLength = SmbReq.BlockLength;
  265. } else {
  266. // some sort of failure, check tag data for cache validity
  267. SmbBatt->Info.Valid &= ~VALID_TAG_DATA;
  268. }
  269. }
  270. VOID
  271. SmbBattRW(
  272. IN PSMB_BATT SmbBatt,
  273. IN UCHAR SmbCmd,
  274. OUT PULONG Result
  275. )
  276. // function to read-word from the battery
  277. // N.B. word is returned as a ULONG
  278. {
  279. SMB_REQUEST SmbReq;
  280. PAGED_CODE();
  281. SmbReq.Protocol = SMB_READ_WORD;
  282. SmbReq.Address = SMB_BATTERY_ADDRESS;
  283. SmbReq.Command = SmbCmd;
  284. SmbBattRequest (SmbBatt, &SmbReq);
  285. if (SmbReq.Status != SMB_STATUS_OK) {
  286. // some sort of failure, check tag data for cache validity
  287. SmbBatt->Info.Valid &= ~VALID_TAG_DATA;
  288. }
  289. *Result = SmbReq.Data[0] | SmbReq.Data[1] << WORD_MSB_SHIFT;
  290. BattPrint(BAT_IO, ("SmbBattRW: Command: %02x == %04x\n", SmbCmd, *Result));
  291. }
  292. VOID
  293. SmbBattRSW(
  294. IN PSMB_BATT SmbBatt,
  295. IN UCHAR SmbCmd,
  296. OUT PLONG Result
  297. )
  298. // function to read-signed-word from the battery
  299. // N.B. word is returned as a LONG
  300. {
  301. ULONG i;
  302. PAGED_CODE();
  303. SmbBattRW(SmbBatt, SmbCmd, &i);
  304. *Result = ((SHORT) i);
  305. }
  306. VOID
  307. SmbBattWW(
  308. IN PSMB_BATT SmbBatt,
  309. IN UCHAR SmbCmd,
  310. IN ULONG Data
  311. )
  312. // function to write-word to the battery
  313. {
  314. SMB_REQUEST SmbReq;
  315. PAGED_CODE();
  316. SmbReq.Protocol = SMB_WRITE_WORD;
  317. SmbReq.Address = SMB_BATTERY_ADDRESS;
  318. SmbReq.Command = SmbCmd;
  319. SmbReq.Data[0] = (UCHAR) (Data & WORD_LSB_MASK);
  320. SmbReq.Data[1] = (UCHAR) (Data >> WORD_MSB_SHIFT) & WORD_LSB_MASK;
  321. BattPrint(BAT_IO, ("SmbBattWW: Command: %02x = %04x\n", SmbCmd, Data));
  322. SmbBattRequest (SmbBatt, &SmbReq);
  323. if (SmbReq.Status != SMB_STATUS_OK) {
  324. // some sort of failure, check tag data for cache validity
  325. SmbBatt->Info.Valid &= ~VALID_TAG_DATA;
  326. }
  327. }
  328. UCHAR
  329. SmbBattGenericRW(
  330. IN PDEVICE_OBJECT SmbHcFdo,
  331. IN UCHAR Address,
  332. IN UCHAR SmbCmd,
  333. OUT PULONG Result
  334. )
  335. // function to read-word from the SMB device (charger or selector)
  336. // N.B. word is returned as a ULONG
  337. {
  338. SMB_REQUEST SmbReq;
  339. PAGED_CODE();
  340. SmbReq.Protocol = SMB_READ_WORD;
  341. SmbReq.Address = Address;
  342. SmbReq.Command = SmbCmd;
  343. SmbBattGenericRequest (SmbHcFdo, &SmbReq);
  344. *Result = SmbReq.Data[0] | (SmbReq.Data[1] << WORD_MSB_SHIFT);
  345. BattPrint(BAT_IO, ("SmbBattGenericRW: Address: %02x:%02x == %04x\n", Address, SmbCmd, *Result));
  346. return SmbReq.Status;
  347. }
  348. UCHAR
  349. SmbBattGenericWW(
  350. IN PDEVICE_OBJECT SmbHcFdo,
  351. IN UCHAR Address,
  352. IN UCHAR SmbCmd,
  353. IN ULONG Data
  354. )
  355. // function to write-word to SMB device (charger or selector)
  356. {
  357. SMB_REQUEST SmbReq;
  358. PAGED_CODE();
  359. SmbReq.Protocol = SMB_WRITE_WORD;
  360. SmbReq.Address = Address;
  361. SmbReq.Command = SmbCmd;
  362. SmbReq.Data[0] = (UCHAR) (Data & WORD_LSB_MASK);
  363. SmbReq.Data[1] = (UCHAR) (Data >> WORD_MSB_SHIFT) & WORD_LSB_MASK;
  364. BattPrint(BAT_IO, ("SmbBattGenericWW: Address: %02x:%02x = %04x\n", Address, SmbCmd, Data));
  365. SmbBattGenericRequest (SmbHcFdo, &SmbReq);
  366. return SmbReq.Status;
  367. }
  368. VOID
  369. SmbBattGenericRequest (
  370. IN PDEVICE_OBJECT SmbHcFdo,
  371. IN PSMB_REQUEST SmbReq
  372. )
  373. // function to issue SMBus request
  374. {
  375. KEVENT Event;
  376. PIRP Irp;
  377. PIO_STACK_LOCATION IrpSp;
  378. NTSTATUS Status;
  379. BOOLEAN useLock = SmbBattUseGlobalLock;
  380. ACPI_MANIPULATE_GLOBAL_LOCK_BUFFER globalLock;
  381. PAGED_CODE();
  382. //
  383. // Build Io Control for SMB bus driver for this request
  384. //
  385. KeInitializeEvent (&Event, NotificationEvent, FALSE);
  386. if (!SmbHcFdo) {
  387. //
  388. // The SMB host controller either hasn't been opened yet (in start device) or
  389. // there was an error opening it and we did not get deleted somehow.
  390. //
  391. BattPrint(BAT_ERROR, ("SmbBattGenericRequest: SmbHc hasn't been opened yet \n"));
  392. SmbReq->Status = SMB_UNKNOWN_FAILURE;
  393. return ;
  394. }
  395. Irp = IoAllocateIrp (SmbHcFdo->StackSize, FALSE);
  396. if (!Irp) {
  397. SmbReq->Status = SMB_UNKNOWN_FAILURE;
  398. return ;
  399. }
  400. IrpSp = IoGetNextIrpStackLocation(Irp);
  401. IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  402. IrpSp->Parameters.DeviceIoControl.IoControlCode = SMB_BUS_REQUEST;
  403. IrpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof(SMB_REQUEST);
  404. IrpSp->Parameters.DeviceIoControl.Type3InputBuffer = SmbReq;
  405. IoSetCompletionRoutine (Irp, SmbBattSynchronousRequest, &Event, TRUE, TRUE, TRUE);
  406. //
  407. // Issue it
  408. //
  409. //
  410. // Note: uselock is a cached value of the global variable, so in case the
  411. // value changes, we won't acquire and not release etc.
  412. //
  413. if (useLock) {
  414. if (!NT_SUCCESS (SmbBattAcquireGlobalLock (SmbHcFdo, &globalLock))) {
  415. useLock = FALSE;
  416. }
  417. }
  418. IoCallDriver (SmbHcFdo, Irp);
  419. KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
  420. Status = Irp->IoStatus.Status;
  421. IoFreeIrp (Irp);
  422. if (useLock) {
  423. SmbBattReleaseGlobalLock (SmbHcFdo, &globalLock);
  424. }
  425. //
  426. // Check result code
  427. //
  428. if (!NT_SUCCESS(Status)) {
  429. BattPrint(BAT_ERROR, ("SmbBattGenericRequest: error in SmbHc request - %x\n", Status));
  430. SmbReq->Status = SMB_UNKNOWN_FAILURE;
  431. }
  432. }
  433. NTSTATUS
  434. SmbBattSetSelectorComm (
  435. IN PSMB_BATT SmbBatt,
  436. OUT PULONG OldSelectorState
  437. )
  438. /*++
  439. Routine Description:
  440. This routine sets the communication path through the selector to the calling
  441. battery. It returns the original selector state in the variable provided.
  442. NOTE: It is assumed that the caller already has acquired the device lock on the
  443. selector before calling us.
  444. NOTE: This function should always be called in a pair with SmbBattResetSelectorComm
  445. Arguments:
  446. SmbBatt - Nonpaged extension for current battery
  447. OldSelectorState - Original selector state at start of this function
  448. Return Value:
  449. NTSTATUS
  450. --*/
  451. {
  452. PBATTERY_SELECTOR selector;
  453. UCHAR smbStatus;
  454. ULONG requestData;
  455. PAGED_CODE();
  456. BattPrint(BAT_TRACE, ("SmbBattSetSelectorComm: ENTERING\n"));
  457. //
  458. // We only need to do this if there is a selector in the system.
  459. //
  460. if (SmbBatt->SelectorPresent) {
  461. selector = SmbBatt->Selector;
  462. *OldSelectorState = selector->SelectorState;
  463. //
  464. // If the battery isn't present, fail the request.
  465. //
  466. if (!(selector->SelectorState & SmbBatt->SelectorBitPosition)) {
  467. return STATUS_NO_SUCH_DEVICE;
  468. }
  469. //
  470. // See if we are already set up to talk with the requesting battery.
  471. // We will check against the cached information in the selector struct.
  472. //
  473. if (selector->SelectorState & (SmbBatt->SelectorBitPosition << SELECTOR_SHIFT_COM)) {
  474. return STATUS_SUCCESS;
  475. }
  476. //
  477. // Build the data word to change the selector communications. This will
  478. // look like the following:
  479. //
  480. // PRESENT field 0xf we don't want to change anything here
  481. // CHARGE field 0xf we don't want to change anything here
  482. // POWER BY field 0xf we don't want to change anything here
  483. // SMB field 0x_ the bit set according to the battery number
  484. //
  485. requestData = (SmbBatt->SelectorBitPosition << SELECTOR_SHIFT_COM) | SELECTOR_SET_COM_MASK;
  486. smbStatus = SmbBattGenericWW (
  487. SmbBatt->SmbHcFdo,
  488. selector->SelectorAddress,
  489. selector->SelectorStateCommand,
  490. requestData
  491. );
  492. if (smbStatus != SMB_STATUS_OK) {
  493. BattPrint (BAT_ERROR, ("SmbBattSetSelectorComm: couldn't write selector state - %x\n", smbStatus));
  494. return STATUS_UNSUCCESSFUL;
  495. } else {
  496. selector->SelectorState |= SELECTOR_STATE_SMB_MASK;
  497. selector->SelectorState &= requestData;
  498. BattPrint (BAT_IO, ("SmbBattSetSelectorComm: state after write - %x\n", selector->SelectorState));
  499. }
  500. } // if (subsystemExt->SelectorPresent)
  501. BattPrint(BAT_TRACE, ("SmbBattSetSelectorComm: EXITING\n"));
  502. return STATUS_SUCCESS;
  503. }
  504. NTSTATUS
  505. SmbBattResetSelectorComm (
  506. IN PSMB_BATT SmbBatt,
  507. IN ULONG OldSelectorState
  508. )
  509. /*++
  510. Routine Description:
  511. This routine resets the communication path through the selector to the its
  512. original state. It returns the original selector state in the variable provided.
  513. NOTE: It is assumed that the caller already has acquired the device lock on the
  514. selector before calling us.
  515. NOTE: This function should always be called in a pair with SmbBattSetSelectorComm
  516. Arguments:
  517. SmbBatt - Nonpaged extension for current battery
  518. OldSelectorState - Original selector state to be restored
  519. Return Value:
  520. NTSTATUS
  521. --*/
  522. {
  523. PBATTERY_SELECTOR selector;
  524. UCHAR smbStatus;
  525. ULONG tmpState;
  526. NTSTATUS status = STATUS_SUCCESS;
  527. PAGED_CODE();
  528. BattPrint(BAT_TRACE, ("SmbBattResetSelectorComm: ENTERING\n"));
  529. //
  530. // We only need to do this if there is a selector in the system.
  531. //
  532. if (SmbBatt->SelectorPresent) {
  533. selector = SmbBatt->Selector;
  534. //
  535. // See if we were already set up to talk with the requesting battery.
  536. // We will check against the cached information in the selector struct.
  537. //
  538. if ((OldSelectorState & selector->SelectorState) & SELECTOR_STATE_SMB_MASK) {
  539. return STATUS_SUCCESS;
  540. }
  541. //
  542. // Change the selector communications back. The SMB field is the only
  543. // that we will write.
  544. //
  545. tmpState = SELECTOR_SET_COM_MASK;
  546. tmpState |= OldSelectorState & SELECTOR_STATE_SMB_MASK;
  547. smbStatus = SmbBattGenericWW (
  548. SmbBatt->SmbHcFdo,
  549. selector->SelectorAddress,
  550. selector->SelectorStateCommand,
  551. tmpState
  552. );
  553. if (smbStatus != SMB_STATUS_OK) {
  554. BattPrint (
  555. BAT_ERROR,
  556. ("SmbBattResetSelectorComm: couldn't write selector state - %x\n",
  557. smbStatus)
  558. );
  559. status = STATUS_UNSUCCESSFUL;
  560. } else {
  561. selector->SelectorState |= SELECTOR_STATE_SMB_MASK;
  562. selector->SelectorState &= tmpState;
  563. BattPrint (
  564. BAT_IO,
  565. ("SmbBattResetSelectorComm: state after write - %x\n",
  566. selector->SelectorState)
  567. );
  568. }
  569. } // if (subsystemExt->SelectorPresent)
  570. BattPrint(BAT_TRACE, ("SmbBattResetSelectorComm: EXITING\n"));
  571. return status;
  572. }
  573. #if DEBUG
  574. NTSTATUS
  575. SmbBattDirectDataAccess (
  576. IN PSMB_NP_BATT DeviceExtension,
  577. IN PSMBBATT_DATA_STRUCT IoBuffer,
  578. IN ULONG InputLen,
  579. IN ULONG OutputLen
  580. )
  581. /*++
  582. Routine Description:
  583. This routine is used to handle IOCTLs acessing the SMBBatt commands directly.
  584. Arguments:
  585. DeviceExtension - Device extension for the smart battery subsystem
  586. IoBuffer - Buffer that contains the input structure and will
  587. contain the results of the read.
  588. Return Value:
  589. NTSTATUS
  590. --*/
  591. {
  592. PSMB_BATT_SUBSYSTEM SubsystemExt;
  593. PSMB_BATT SmbBatt;
  594. UCHAR address;
  595. UCHAR command;
  596. UCHAR smbStatus;
  597. ULONG oldSelectorState;
  598. ULONG ReturnBufferLength;
  599. UCHAR strLength;
  600. UCHAR strBuffer[SMB_MAX_DATA_SIZE+1]; // +1 extra char to hold NULL
  601. UCHAR strBuffer2[SMB_MAX_DATA_SIZE+1];
  602. UNICODE_STRING unicodeString;
  603. ANSI_STRING ansiString;
  604. UCHAR tempFlags;
  605. NTSTATUS status = STATUS_SUCCESS;
  606. PAGED_CODE();
  607. if (InputLen < sizeof(SMBBATT_DATA_STRUCT)) {
  608. return STATUS_INVALID_BUFFER_SIZE;
  609. }
  610. if ((DeviceExtension->SmbBattFdoType == SmbTypeBattery)
  611. && (IoBuffer->Address == SMB_BATTERY_ADDRESS)) {
  612. // This is a battery data request
  613. SmbBatt = DeviceExtension->Batt;
  614. SmbBattLockSelector (SmbBatt->Selector);
  615. SmbBattLockDevice (SmbBatt);
  616. status = SmbBattSetSelectorComm (SmbBatt, &oldSelectorState);
  617. if (NT_SUCCESS (status)) {
  618. if ((InputLen >= sizeof(SMBBATT_DATA_STRUCT)) && (OutputLen == 0)) {
  619. // This is a write command
  620. status = STATUS_NOT_IMPLEMENTED;
  621. } else if ((InputLen == sizeof(SMBBATT_DATA_STRUCT)) && (OutputLen > 0)){
  622. // This is a Read command
  623. if ((IoBuffer->Command >= BAT_REMAINING_CAPACITY_ALARM) &&
  624. (IoBuffer->Command <= BAT_SERIAL_NUMBER)) {
  625. // ReadWord Commands
  626. if (OutputLen == sizeof(SMBBATT_DATA_STRUCT)) {
  627. tempFlags = SmbBatt->Info.Valid;
  628. SmbBatt->Info.Valid |= VALID_TAG_DATA;
  629. SmbBattRW(SmbBatt, IoBuffer->Command, &IoBuffer->Data.Ulong);
  630. if (SmbBatt->Info.Valid & VALID_TAG_DATA) {
  631. ReturnBufferLength = sizeof(ULONG);
  632. } else {
  633. status = STATUS_DATA_ERROR;
  634. }
  635. SmbBatt->Info.Valid = tempFlags;
  636. } else {
  637. status = STATUS_INVALID_BUFFER_SIZE;
  638. }
  639. } else if ((IoBuffer->Command >= BAT_MANUFACTURER_NAME) &&
  640. (IoBuffer->Command <= BAT_MANUFACTURER_DATA)) {
  641. // ReadBlock Commands
  642. if (OutputLen == (SMBBATT_DATA_STRUCT_SIZE)+(SMB_MAX_DATA_SIZE*2)) {
  643. memset (&IoBuffer->Data.Block[0], 0, (SMB_MAX_DATA_SIZE*2));
  644. unicodeString.Buffer = &IoBuffer->Data.Block[0];
  645. unicodeString.MaximumLength = SMB_MAX_DATA_SIZE*2;
  646. unicodeString.Length = 0;
  647. memset (strBuffer, 0, sizeof(strBuffer));
  648. memset (strBuffer2, 0, sizeof(strBuffer2));
  649. do {
  650. SmbBattRB (
  651. SmbBatt,
  652. IoBuffer->Command,
  653. strBuffer,
  654. &strLength
  655. );
  656. SmbBattRB (
  657. SmbBatt,
  658. IoBuffer->Command,
  659. strBuffer2,
  660. &strLength
  661. );
  662. } while (strcmp (strBuffer, strBuffer2));
  663. RtlInitAnsiString (&ansiString, strBuffer);
  664. RtlAnsiStringToUnicodeString (&unicodeString, &ansiString, FALSE);
  665. ReturnBufferLength = unicodeString.Length;
  666. } else {
  667. status = STATUS_INVALID_BUFFER_SIZE;
  668. }
  669. } else {
  670. // Unsupported Commands
  671. status = STATUS_INVALID_PARAMETER;
  672. }
  673. }
  674. }
  675. SmbBattResetSelectorComm (SmbBatt, oldSelectorState);
  676. SmbBattUnlockDevice (SmbBatt);
  677. SmbBattUnlockSelector (SmbBatt->Selector);
  678. } else if (DeviceExtension->SmbBattFdoType == SmbTypeSubsystem) {
  679. // This is a battery subsystem
  680. SubsystemExt = (PSMB_BATT_SUBSYSTEM) DeviceExtension;
  681. SmbBattLockSelector (SubsystemExt->Selector);
  682. if ((InputLen >= sizeof(SMBBATT_DATA_STRUCT)) && (OutputLen == 0)) {
  683. // This is a write command
  684. status = STATUS_NOT_IMPLEMENTED;
  685. } else if ((InputLen == sizeof(SMBBATT_DATA_STRUCT)) && (OutputLen > 0)){
  686. // This is a Read command
  687. switch (IoBuffer->Address) {
  688. case SMB_SELECTOR_ADDRESS:
  689. //
  690. // We have to do some translation for selector requests depending
  691. // on whether the selector is stand alone or implemented in the
  692. // charger.
  693. //
  694. if ((SubsystemExt->SelectorPresent) && (SubsystemExt->Selector)) {
  695. address = SubsystemExt->Selector->SelectorAddress;
  696. command = IoBuffer->Command;
  697. // Map to Charger if Selector is implemented in the Charger
  698. if (address == SMB_CHARGER_ADDRESS) {
  699. switch (command) {
  700. case SELECTOR_SELECTOR_STATE:
  701. case SELECTOR_SELECTOR_PRESETS:
  702. case SELECTOR_SELECTOR_INFO:
  703. command |= CHARGER_SELECTOR_COMMANDS;
  704. break;
  705. default:
  706. status = STATUS_NOT_SUPPORTED;
  707. break;
  708. }
  709. }
  710. } else {
  711. status = STATUS_NO_SUCH_DEVICE;
  712. }
  713. break;
  714. case SMB_CHARGER_ADDRESS:
  715. //
  716. // For this one we currently only support the ChargerStatus and
  717. // ChargerSpecInfo commands.
  718. //
  719. // Other commands are not currently supported.
  720. //
  721. address = IoBuffer->Address;
  722. switch (IoBuffer->Command) {
  723. case CHARGER_SPEC_INFO:
  724. case CHARGER_STATUS:
  725. command = IoBuffer->Command;
  726. break;
  727. default:
  728. status = STATUS_NOT_SUPPORTED;
  729. break;
  730. }
  731. break;
  732. default:
  733. status = STATUS_NOT_SUPPORTED;
  734. break;
  735. } // switch (readStruct->Address)
  736. if (status == STATUS_SUCCESS) {
  737. //
  738. // Do the read command
  739. //
  740. smbStatus = SmbBattGenericRW (
  741. SubsystemExt->SmbHcFdo,
  742. address,
  743. command,
  744. &IoBuffer->Data.Ulong
  745. );
  746. if (smbStatus != SMB_STATUS_OK) {
  747. BattPrint (
  748. BAT_ERROR,
  749. ("SmbBattDirectDataAccess: Couldn't read from - %x, status - %x\n",
  750. address,
  751. smbStatus)
  752. );
  753. status = STATUS_UNSUCCESSFUL;
  754. }
  755. }
  756. }
  757. SmbBattUnlockSelector (SubsystemExt->Selector);
  758. } else {
  759. status=STATUS_INVALID_DEVICE_REQUEST;
  760. BattPrint (
  761. BAT_ERROR,
  762. ("SmbBattDirectDataAccess: Invalid SmbBattFdoType")
  763. );
  764. }
  765. return status;
  766. }
  767. #endif
  768. UCHAR
  769. SmbBattIndex (
  770. IN PBATTERY_SELECTOR Selector,
  771. IN ULONG SelectorNibble,
  772. IN UCHAR SimultaneousIndex
  773. )
  774. /*++
  775. Routine Description:
  776. This routine is provided as a helper routine to determine which
  777. battery is selected in a given selector nibble, based on the number
  778. of batteries supported in the system.
  779. Arguments:
  780. Selector - Structure defining selector address and commands
  781. SelectorNibble - The nibble of the SelectorState, moved to the low
  782. order 4 bits, to check reverse logic on.
  783. SimultaneousIndex - Which batteryindex is requested in simultaneous-
  784. battery situations (0, 1, or 2)
  785. Return Value:
  786. BatteryIndex = 0 - Battery A
  787. 1 - Battery B
  788. 2 - Battery C
  789. 3 - Battery D
  790. FF - No Battery
  791. --*/
  792. {
  793. UCHAR batteryIndex;
  794. PAGED_CODE();
  795. // Assume if SelectorInfo supports 4 batteries, use SelectorBits4 table
  796. if (Selector->SelectorInfo & BATTERY_D_PRESENT) {
  797. batteryIndex = SelectorBits4[SelectorNibble].BatteryIndex;
  798. } else {
  799. batteryIndex = SelectorBits[SelectorNibble].BatteryIndex;
  800. }
  801. // If it's valid
  802. if (batteryIndex != BATTERY_NONE) {
  803. // return index for First Battery
  804. if (SimultaneousIndex == 0) {
  805. return (batteryIndex & 3);
  806. // return index for Second Battery
  807. } else if (SimultaneousIndex == 1) {
  808. batteryIndex = (batteryIndex >> 2) & 3;
  809. if (batteryIndex != BATTERY_A) {
  810. return (batteryIndex);
  811. }
  812. // return index for Third Battery
  813. } else if (SimultaneousIndex == 2) {
  814. batteryIndex = (batteryIndex >> 2) & 3;
  815. if (batteryIndex != BATTERY_A) {
  816. return (batteryIndex);
  817. }
  818. }
  819. }
  820. // return no battery index
  821. return (BATTERY_NONE);
  822. }
  823. BOOLEAN
  824. SmbBattReverseLogic (
  825. IN PBATTERY_SELECTOR Selector,
  826. IN ULONG SelectorNibble
  827. )
  828. /*++
  829. Routine Description:
  830. This routine is provided as a helper routine to determine the reverse
  831. logic on a given selector nibble, based on the number of batteries
  832. supported in the system.
  833. Arguments:
  834. Selector - Structure defining selector address and commands
  835. SelectorNibble - The nibble of the SelectorState, moved to the low
  836. order 4 bits, to check reverse logic on.
  837. Return Value:
  838. FALSE if the nibble is normal
  839. TRUE if the nibble is inverted
  840. --*/
  841. {
  842. PAGED_CODE();
  843. // Assume if SelectorInfo supports 4 batteries, use SelectorBits4 table
  844. if (Selector->SelectorInfo & BATTERY_D_PRESENT) {
  845. return (SelectorBits4[SelectorNibble].ReverseLogic);
  846. } else {
  847. return (SelectorBits[SelectorNibble].ReverseLogic);
  848. }
  849. }
  850. NTSTATUS
  851. SmbBattAcquireGlobalLock (
  852. IN PDEVICE_OBJECT LowerDeviceObject,
  853. OUT PACPI_MANIPULATE_GLOBAL_LOCK_BUFFER GlobalLock
  854. )
  855. /*++
  856. Routine Description:
  857. Call ACPI driver to obtain the global lock
  858. Note: This routine can be called at dispatch level
  859. Arguments:
  860. LowerDeviceObject - The FDO to pass the request to.
  861. Return Value:
  862. Return Value from IOCTL.
  863. --*/
  864. {
  865. NTSTATUS status;
  866. PIRP irp;
  867. PIO_STACK_LOCATION irpSp;
  868. KEVENT event;
  869. BattPrint (BAT_TRACE, ("SmbBattAcquireGlobalLock: Entering\n"));
  870. //
  871. // We wish to acquire the lock
  872. //
  873. GlobalLock->Signature = ACPI_ACQUIRE_GLOBAL_LOCK_SIGNATURE;
  874. GlobalLock->LockObject = NULL;
  875. //
  876. // setup the irp
  877. //
  878. KeInitializeEvent(&event, NotificationEvent, FALSE);
  879. irp = IoAllocateIrp (LowerDeviceObject->StackSize, FALSE);
  880. if (!irp) {
  881. return STATUS_INSUFFICIENT_RESOURCES;
  882. }
  883. irpSp = IoGetNextIrpStackLocation(irp);
  884. irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  885. irpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_ACPI_ACQUIRE_GLOBAL_LOCK;
  886. irpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof(ACPI_MANIPULATE_GLOBAL_LOCK_BUFFER);
  887. irpSp->Parameters.DeviceIoControl.OutputBufferLength = sizeof(ACPI_MANIPULATE_GLOBAL_LOCK_BUFFER);
  888. irp->AssociatedIrp.SystemBuffer = GlobalLock;
  889. IoSetCompletionRoutine (irp, SmbBattSynchronousRequest, &event, TRUE, TRUE, TRUE);
  890. //
  891. // Send to ACPI driver
  892. //
  893. IoCallDriver (LowerDeviceObject, irp);
  894. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  895. status = irp->IoStatus.Status;
  896. IoFreeIrp (irp);
  897. if (!NT_SUCCESS(status)) {
  898. BattPrint(
  899. BAT_ERROR,
  900. ("SmbBattAcquireGlobalLock: Acquire Lock failed, status = %08x\n",
  901. status )
  902. );
  903. DbgBreakPoint ();
  904. }
  905. BattPrint (BAT_TRACE, ("SmbBattAcquireGlobalLock: Returning %x\n", status));
  906. return status;
  907. }
  908. NTSTATUS
  909. SmbBattReleaseGlobalLock (
  910. IN PDEVICE_OBJECT LowerDeviceObject,
  911. IN PACPI_MANIPULATE_GLOBAL_LOCK_BUFFER GlobalLock
  912. )
  913. /*++
  914. Routine Description:
  915. Call ACPI driver to release the global lock
  916. Arguments:
  917. LowerDeviceObject - The FDO to pass the request to.
  918. Return Value:
  919. Return Value from IOCTL.
  920. --*/
  921. {
  922. NTSTATUS status;
  923. PIRP irp;
  924. PIO_STACK_LOCATION irpSp;
  925. KEVENT event;
  926. BattPrint (BAT_TRACE, ("SmbBattReleaseGlobalLock: Entering\n"));
  927. //
  928. // We wish to acquire the lock
  929. //
  930. GlobalLock->Signature = ACPI_RELEASE_GLOBAL_LOCK_SIGNATURE;
  931. //
  932. // setup the irp
  933. //
  934. KeInitializeEvent(&event, NotificationEvent, FALSE);
  935. irp = IoAllocateIrp (LowerDeviceObject->StackSize, FALSE);
  936. if (!irp) {
  937. return STATUS_INSUFFICIENT_RESOURCES;
  938. }
  939. irpSp = IoGetNextIrpStackLocation(irp);
  940. irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  941. irpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_ACPI_RELEASE_GLOBAL_LOCK;
  942. irpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof(ACPI_MANIPULATE_GLOBAL_LOCK_BUFFER);
  943. irpSp->Parameters.DeviceIoControl.OutputBufferLength = sizeof(ACPI_MANIPULATE_GLOBAL_LOCK_BUFFER);
  944. irp->AssociatedIrp.SystemBuffer = GlobalLock;
  945. IoSetCompletionRoutine (irp, SmbBattSynchronousRequest, &event, TRUE, TRUE, TRUE);
  946. //
  947. // Send to ACPI driver
  948. //
  949. IoCallDriver (LowerDeviceObject, irp);
  950. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  951. status = irp->IoStatus.Status;
  952. IoFreeIrp (irp);
  953. if (!NT_SUCCESS(status)) {
  954. BattPrint(
  955. BAT_ERROR,
  956. ("SmbBattReleaseGlobalLock: Acquire Lock failed, status = %08x\n",
  957. status )
  958. );
  959. }
  960. BattPrint (BAT_TRACE, ("SmbBattReleaseGlobalLock: Returning %x\n", status));
  961. return status;
  962. }