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