xref: /haiku/src/apps/powerstatus/ACPIDriverInterface.cpp (revision 21258e2674226d6aa732321b6f8494841895af5f)
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 
26 RateBuffer::RateBuffer()
27 	:
28 	fPosition(0),
29 	fSize(kRateBufferSize),
30 	fCurrentSize(0)
31 {
32 }
33 
34 
35 void
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
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 
66 Battery::Battery(int driverHandler)
67 	:
68 	fDriverHandler(driverHandler)
69 {
70 	_Init();
71 }
72 
73 
74 Battery::~Battery()
75 {
76 	close(fDriverHandler);
77 }
78 
79 
80 status_t
81 Battery::InitCheck()
82 {
83 	return fInitStatus;
84 }
85 
86 
87 status_t
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 	fCachedInfo = info;
101 	return B_OK;
102 }
103 
104 
105 status_t
106 Battery::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 
126 status_t
127 Battery::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 
137 void
138 Battery::_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 
157 ACPIDriverInterface::ACPIDriverInterface()
158 	:
159 	fInterfaceLocker("acpi interface")
160 {
161 }
162 
163 
164 ACPIDriverInterface::~ACPIDriverInterface()
165 {
166 	for (int i = 0; i < fDriverList.CountItems(); i++)
167 		delete fDriverList.ItemAt(i);
168 }
169 
170 
171 status_t
172 ACPIDriverInterface::Connect()
173 {
174 	return _FindDrivers(kDriverDir);
175 }
176 
177 
178 status_t
179 ACPIDriverInterface::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 
189 status_t
190 ACPIDriverInterface::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 
201 int32
202 ACPIDriverInterface::GetBatteryCount()
203 {
204 	return fDriverList.CountItems();
205 }
206 
207 
208 status_t
209 ACPIDriverInterface::_UpdateBatteryInfo()
210 {
211 	for (int i = 0; i < fDriverList.CountItems(); i++)
212 		fDriverList.ItemAt(i)->UpdateBatteryInfo();
213 
214 	return B_OK;
215 }
216 
217 
218 void
219 ACPIDriverInterface::_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 
232 status_t
233 ACPIDriverInterface::_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