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