1/*
2 * Copyright 2009-2015, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Axel D��rfler, axeld@pinc-software.de
7 *		Clemens Zeidler, haiku@clemens-zeidler.de
8 */
9
10
11#include "ACPIDriverInterface.h"
12
13#include <errno.h>
14#include <stdio.h>
15#include <string.h>
16
17#include <Autolock.h>
18#include <Directory.h>
19#include <Entry.h>
20#include <Path.h>
21
22
23static const char* kDriverDir = "/dev/power";
24
25
26RateBuffer::RateBuffer()
27	:
28	fPosition(0),
29	fSize(kRateBufferSize),
30	fCurrentSize(0)
31{
32}
33
34
35void
36RateBuffer::AddRate(int32 rate)
37{
38	fRateBuffer[fPosition] = rate;
39	fPosition ++;
40	if (fPosition >= fSize)
41		fPosition = 0;
42
43	if (fCurrentSize < fSize)
44		fCurrentSize ++;
45}
46
47
48int32
49RateBuffer::GetMeanRate()
50{
51	int32 mean = 0;
52	for (int8 i = 0; i < fCurrentSize; i++) {
53		mean += fRateBuffer[i];
54	}
55
56	if (fCurrentSize == 0)
57		return -1;
58
59	return mean / fCurrentSize;
60}
61
62
63// #pragma mark -
64
65
66Battery::Battery(int driverHandler)
67	:
68	fDriverHandler(driverHandler)
69{
70	_Init();
71}
72
73
74Battery::~Battery()
75{
76	close(fDriverHandler);
77}
78
79
80status_t
81Battery::InitCheck()
82{
83	return fInitStatus;
84}
85
86
87status_t
88Battery::UpdateBatteryInfo()
89{
90	acpi_battery_info info;
91	if (ioctl(fDriverHandler, GET_BATTERY_INFO, &info,
92			sizeof(acpi_battery_info)) != 0)
93		return errno;
94
95	if ((fExtendedBatteryInfo.last_full_charge > 0
96			&& info.capacity > fExtendedBatteryInfo.last_full_charge)
97		|| info.capacity < 0)
98		return B_BAD_DATA;
99
100	fCachedInfo = info;
101	return B_OK;
102}
103
104
105status_t
106Battery::GetBatteryInfoCached(battery_info* info)
107{
108	info->state = fCachedInfo.state;
109	info->current_rate = fCachedInfo.current_rate;
110	info->capacity = fCachedInfo.capacity;
111	info->full_capacity = fExtendedBatteryInfo.last_full_charge;
112	if (info->full_capacity < 0)
113		info->full_capacity = fExtendedBatteryInfo.design_capacity;
114
115	fRateBuffer.AddRate(fCachedInfo.current_rate);
116	if (fCachedInfo.current_rate > 0 && fRateBuffer.GetMeanRate() != 0) {
117		info->time_left = 3600 * fCachedInfo.capacity
118			/ fRateBuffer.GetMeanRate();
119	} else
120		info->time_left = -1;
121
122	return B_OK;
123}
124
125
126status_t
127Battery::GetExtendedBatteryInfo(acpi_extended_battery_info* info)
128{
129	if (ioctl(fDriverHandler, GET_EXTENDED_BATTERY_INFO, info,
130			sizeof(acpi_extended_battery_info)) != 0)
131		return errno;
132
133	return B_OK;
134}
135
136
137void
138Battery::_Init()
139{
140	uint32 magicId = 0;
141	if (ioctl(fDriverHandler, IDENTIFY_DEVICE, &magicId, sizeof(uint32)) != 0) {
142		fInitStatus = errno;
143		return;
144	}
145	fInitStatus = GetExtendedBatteryInfo(&fExtendedBatteryInfo);
146	if (fInitStatus != B_OK)
147		return;
148
149	printf("ACPI driver found\n");
150	UpdateBatteryInfo();
151}
152
153
154// #pragma mark - ACPIDriverInterface
155
156
157ACPIDriverInterface::ACPIDriverInterface()
158	:
159	fInterfaceLocker("acpi interface")
160{
161}
162
163
164ACPIDriverInterface::~ACPIDriverInterface()
165{
166	for (int i = 0; i < fDriverList.CountItems(); i++)
167		delete fDriverList.ItemAt(i);
168}
169
170
171status_t
172ACPIDriverInterface::Connect()
173{
174	return _FindDrivers(kDriverDir);
175}
176
177
178status_t
179ACPIDriverInterface::GetBatteryInfo(int32 index, battery_info* info)
180{
181	BAutolock autolock(fInterfaceLocker);
182	if (index < 0 || index >= fDriverList.CountItems())
183		return B_ERROR;
184
185	return fDriverList.ItemAt(index)->GetBatteryInfoCached(info);
186}
187
188
189status_t
190ACPIDriverInterface::GetExtendedBatteryInfo(int32 index,
191	acpi_extended_battery_info* info)
192{
193	BAutolock autolock(fInterfaceLocker);
194	if (index < 0 || index >= fDriverList.CountItems())
195		return B_ERROR;
196
197	return fDriverList.ItemAt(index)->GetExtendedBatteryInfo(info);
198}
199
200
201int32
202ACPIDriverInterface::GetBatteryCount()
203{
204	return fDriverList.CountItems();
205}
206
207
208status_t
209ACPIDriverInterface::_UpdateBatteryInfo()
210{
211	for (int i = 0; i < fDriverList.CountItems(); i++)
212		fDriverList.ItemAt(i)->UpdateBatteryInfo();
213
214	return B_OK;
215}
216
217
218void
219ACPIDriverInterface::_WatchPowerStatus()
220{
221	const bigtime_t kUpdateInterval = 2000000;
222		// every two seconds
223
224	while (atomic_get(&fIsWatching) > 0) {
225		_UpdateBatteryInfo();
226		Broadcast(kMsgUpdate);
227		acquire_sem_etc(fWaitSem, 1, B_RELATIVE_TIMEOUT, kUpdateInterval);
228	}
229}
230
231
232status_t
233ACPIDriverInterface::_FindDrivers(const char* dirpath)
234{
235	BDirectory dir(dirpath);
236	BEntry entry;
237
238	status_t status = B_ERROR;
239
240	while (dir.GetNextEntry(&entry) == B_OK) {
241		BPath path;
242		entry.GetPath(&path);
243
244		if (entry.IsDirectory()) {
245			if (_FindDrivers(path.Path()) == B_OK)
246				return B_OK;
247		} else {
248			int32 handler = open(path.Path(), O_RDWR);
249			if (handler >= 0) {
250				printf("try %s\n", path.Path());
251				Battery* battery = new Battery(handler);
252				if (battery->InitCheck() == B_OK
253					&& fDriverList.AddItem(battery)) {
254					status = B_OK;
255				} else
256					delete battery;
257			}
258		}
259	}
260	return status;
261}
262