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 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 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 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 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 164 ACPIDriverInterface::ACPIDriverInterface() 165 : 166 fInterfaceLocker("acpi interface") 167 { 168 } 169 170 171 ACPIDriverInterface::~ACPIDriverInterface() 172 { 173 for (int i = 0; i < fDriverList.CountItems(); i++) 174 delete fDriverList.ItemAt(i); 175 } 176 177 178 status_t 179 ACPIDriverInterface::Connect() 180 { 181 return _FindDrivers(kDriverDir); 182 } 183 184 185 status_t 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 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 209 ACPIDriverInterface::GetBatteryCount() 210 { 211 return fDriverList.CountItems(); 212 } 213 214 215 status_t 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 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 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