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.

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