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