xref: /haiku/src/apps/powerstatus/ACPIDriverInterface.cpp (revision b54510c37886183876500ee140850c837bd9bcf9)
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 
23 static const char* kDriverDir = "/dev/power";
24 
25 
RateBuffer()26 RateBuffer::RateBuffer()
27 	:
28 	fPosition(0),
29 	fSize(kRateBufferSize),
30 	fCurrentSize(0)
31 {
32 }
33 
34 
35 void
AddRate(int32 rate)36 RateBuffer::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 
48 int32
GetMeanRate()49 RateBuffer::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 
Battery(int driverHandler)66 Battery::Battery(int driverHandler)
67 	:
68 	fDriverHandler(driverHandler)
69 {
70 	_Init();
71 }
72 
73 
~Battery()74 Battery::~Battery()
75 {
76 	close(fDriverHandler);
77 }
78 
79 
80 status_t
InitCheck()81 Battery::InitCheck()
82 {
83 	return fInitStatus;
84 }
85 
86 
87 status_t
UpdateBatteryInfo()88 Battery::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 	if ((fCachedInfo.capacity == 0 && info.capacity > 0)
101 		|| (fCachedInfo.capacity > 0 && info.capacity == 0)) {
102 		// if capacity went from zero to non-zero or vice-versa, we likely just had a battery
103 		// connected or disconnected from the system so refresh the full fExtendedBatteryInfo
104 		GetExtendedBatteryInfo(&fExtendedBatteryInfo);
105 	}
106 
107 	fCachedInfo = info;
108 	return B_OK;
109 }
110 
111 
112 status_t
GetBatteryInfoCached(battery_info * info)113 Battery::GetBatteryInfoCached(battery_info* info)
114 {
115 	info->state = fCachedInfo.state;
116 	info->current_rate = fCachedInfo.current_rate;
117 	info->capacity = fCachedInfo.capacity;
118 	info->full_capacity = fExtendedBatteryInfo.last_full_charge;
119 	if (info->full_capacity < 0)
120 		info->full_capacity = fExtendedBatteryInfo.design_capacity;
121 
122 	fRateBuffer.AddRate(fCachedInfo.current_rate);
123 	if (fCachedInfo.current_rate > 0 && fRateBuffer.GetMeanRate() != 0) {
124 		info->time_left = 3600 * fCachedInfo.capacity
125 			/ fRateBuffer.GetMeanRate();
126 	} else
127 		info->time_left = -1;
128 
129 	return B_OK;
130 }
131 
132 
133 status_t
GetExtendedBatteryInfo(acpi_extended_battery_info * info)134 Battery::GetExtendedBatteryInfo(acpi_extended_battery_info* info)
135 {
136 	if (ioctl(fDriverHandler, GET_EXTENDED_BATTERY_INFO, info,
137 			sizeof(acpi_extended_battery_info)) != 0)
138 		return errno;
139 
140 	return B_OK;
141 }
142 
143 
144 void
_Init()145 Battery::_Init()
146 {
147 	uint32 magicId = 0;
148 	if (ioctl(fDriverHandler, IDENTIFY_DEVICE, &magicId, sizeof(uint32)) != 0) {
149 		fInitStatus = errno;
150 		return;
151 	}
152 	fInitStatus = GetExtendedBatteryInfo(&fExtendedBatteryInfo);
153 	if (fInitStatus != B_OK)
154 		return;
155 
156 	printf("ACPI driver found\n");
157 	UpdateBatteryInfo();
158 }
159 
160 
161 // #pragma mark - ACPIDriverInterface
162 
163 
ACPIDriverInterface()164 ACPIDriverInterface::ACPIDriverInterface()
165 	:
166 	fInterfaceLocker("acpi interface")
167 {
168 }
169 
170 
~ACPIDriverInterface()171 ACPIDriverInterface::~ACPIDriverInterface()
172 {
173 	for (int i = 0; i < fDriverList.CountItems(); i++)
174 		delete fDriverList.ItemAt(i);
175 }
176 
177 
178 status_t
Connect()179 ACPIDriverInterface::Connect()
180 {
181 	return _FindDrivers(kDriverDir);
182 }
183 
184 
185 status_t
GetBatteryInfo(int32 index,battery_info * info)186 ACPIDriverInterface::GetBatteryInfo(int32 index, battery_info* info)
187 {
188 	BAutolock autolock(fInterfaceLocker);
189 	if (index < 0 || index >= fDriverList.CountItems())
190 		return B_ERROR;
191 
192 	return fDriverList.ItemAt(index)->GetBatteryInfoCached(info);
193 }
194 
195 
196 status_t
GetExtendedBatteryInfo(int32 index,acpi_extended_battery_info * info)197 ACPIDriverInterface::GetExtendedBatteryInfo(int32 index,
198 	acpi_extended_battery_info* info)
199 {
200 	BAutolock autolock(fInterfaceLocker);
201 	if (index < 0 || index >= fDriverList.CountItems())
202 		return B_ERROR;
203 
204 	return fDriverList.ItemAt(index)->GetExtendedBatteryInfo(info);
205 }
206 
207 
208 int32
GetBatteryCount()209 ACPIDriverInterface::GetBatteryCount()
210 {
211 	return fDriverList.CountItems();
212 }
213 
214 
215 status_t
_UpdateBatteryInfo()216 ACPIDriverInterface::_UpdateBatteryInfo()
217 {
218 	for (int i = 0; i < fDriverList.CountItems(); i++)
219 		fDriverList.ItemAt(i)->UpdateBatteryInfo();
220 
221 	return B_OK;
222 }
223 
224 
225 void
_WatchPowerStatus()226 ACPIDriverInterface::_WatchPowerStatus()
227 {
228 	const bigtime_t kUpdateInterval = 2000000;
229 		// every two seconds
230 
231 	while (atomic_get(&fIsWatching) > 0) {
232 		_UpdateBatteryInfo();
233 		Broadcast(kMsgUpdate);
234 		acquire_sem_etc(fWaitSem, 1, B_RELATIVE_TIMEOUT, kUpdateInterval);
235 	}
236 }
237 
238 
239 status_t
_FindDrivers(const char * dirpath)240 ACPIDriverInterface::_FindDrivers(const char* dirpath)
241 {
242 	BDirectory dir(dirpath);
243 	BEntry entry;
244 
245 	status_t status = B_ERROR;
246 
247 	while (dir.GetNextEntry(&entry) == B_OK) {
248 		BPath path;
249 		entry.GetPath(&path);
250 
251 		if (entry.IsDirectory()) {
252 			if (_FindDrivers(path.Path()) == B_OK)
253 				return B_OK;
254 		} else {
255 			int32 handler = open(path.Path(), O_RDWR);
256 			if (handler >= 0) {
257 				printf("try %s\n", path.Path());
258 				Battery* battery = new Battery(handler);
259 				if (battery->InitCheck() == B_OK
260 					&& fDriverList.AddItem(battery)) {
261 					status = B_OK;
262 				} else
263 					delete battery;
264 			}
265 		}
266 	}
267 	return status;
268 }
269