• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *     * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above
10  *       copyright notice, this list of conditions and the following
11  *       disclaimer in the documentation and/or other materials provided
12  *       with the distribution.
13  *     * Neither the name of The Linux Foundation nor the names of its
14  *       contributors may be used to endorse or promote products derived
15  *       from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #define LOG_NDEBUG 1
31 
32 #include <errno.h>
33 #include <inttypes.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 #include <dlfcn.h>
40 #include <stdlib.h>
41 #include <time.h>
42 
43 #define LOG_TAG "QCOM PowerHAL"
44 #include <utils/Log.h>
45 #include <hardware/power.h>
46 #include <cutils/properties.h>
47 
48 #include "utils.h"
49 #include "metadata-defs.h"
50 #include "hint-data.h"
51 #include "performance.h"
52 #include "power-common.h"
53 #include "power-helper.h"
54 
55 #define USINSEC 1000000L
56 #define NSINUS 1000L
57 
58 #ifndef RPM_STAT
59 #define RPM_STAT "/d/rpm_stats"
60 #endif
61 
62 #ifndef RPM_MASTER_STAT
63 #define RPM_MASTER_STAT "/d/rpm_master_stats"
64 #endif
65 
66 #ifndef WLAN_POWER_STAT
67 #define WLAN_POWER_STAT "/d/wlan_wcnss/power_stats"
68 #endif
69 
70 static const char *rpm_param_names[] = {
71     "vlow_count",
72     "accumulated_vlow_time",
73     "vmin_count",
74     "accumulated_vmin_time"
75 };
76 
77 static const char *rpm_master_param_names[] = {
78     "xo_accumulated_duration",
79     "xo_count",
80     "xo_accumulated_duration",
81     "xo_count",
82     "xo_accumulated_duration",
83     "xo_count",
84     "xo_accumulated_duration",
85     "xo_count"
86 };
87 
88 static const char *wlan_param_names[] = {
89     "cumulative_sleep_time_ms",
90     "cumulative_total_on_time_ms",
91     "deep_sleep_enter_counter",
92     "last_deep_sleep_enter_tstamp_ms"
93 };
94 
95 
96 static int saved_dcvs_cpu0_slack_max = -1;
97 static int saved_dcvs_cpu0_slack_min = -1;
98 static int saved_mpdecision_slack_max = -1;
99 static int saved_mpdecision_slack_min = -1;
100 static int saved_interactive_mode = -1;
101 static int slack_node_rw_failed = 0;
102 static int display_hint_sent;
103 int display_boost;
104 static int sustained_mode_handle = 0;
105 static int vr_mode_handle = 0;
106 int sustained_performance_mode = 0;
107 int vr_mode = 0;
108 
109 //interaction boost global variables
110 static struct timespec s_previous_boost_timespec;
111 static int s_previous_duration;
112 
power_init(void)113 void power_init(void)
114 {
115     ALOGV("QCOM power HAL initing.");
116 
117     int fd;
118     char buf[10] = {0};
119 
120     fd = open("/sys/devices/soc0/soc_id", O_RDONLY);
121     if (fd >= 0) {
122         if (read(fd, buf, sizeof(buf) - 1) == -1) {
123             ALOGW("Unable to read soc_id");
124         } else {
125             int soc_id = atoi(buf);
126             if (soc_id == 194 || (soc_id >= 208 && soc_id <= 218) || soc_id == 178) {
127                 display_boost = 1;
128             }
129         }
130         close(fd);
131     }
132 }
133 
power_hint_override(power_hint_t UNUSED (hint),void * UNUSED (data))134 int __attribute__ ((weak)) power_hint_override(power_hint_t UNUSED(hint),
135         void * UNUSED(data))
136 {
137     return HINT_NONE;
138 }
139 
140 /* Declare function before use */
141 void interaction(int duration, int num_args, int opt_list[]);
142 void release_request(int lock_handle);
143 
calc_timespan_us(struct timespec start,struct timespec end)144 static long long calc_timespan_us(struct timespec start, struct timespec end) {
145     long long diff_in_us = 0;
146     diff_in_us += (end.tv_sec - start.tv_sec) * USINSEC;
147     diff_in_us += (end.tv_nsec - start.tv_nsec) / NSINUS;
148     return diff_in_us;
149 }
150 
power_hint(power_hint_t hint,void * data)151 void power_hint(power_hint_t hint, void *data)
152 {
153     /* Check if this hint has been overridden. */
154     if (power_hint_override(hint, data) == HINT_HANDLED) {
155         /* The power_hint has been handled. We can skip the rest. */
156         return;
157     }
158 
159     switch(hint) {
160         case POWER_HINT_VSYNC:
161         break;
162         /* Sustained performance mode:
163          * All CPUs are capped to ~1.2GHz
164          * GPU frequency is capped to 315MHz
165          */
166         /* VR+Sustained performance mode:
167          * All CPUs are locked to ~1.2GHz
168          * GPU frequency is locked to 315MHz
169          * GPU BW min_freq is raised to 775MHz
170          */
171         case POWER_HINT_SUSTAINED_PERFORMANCE:
172         {
173             int duration = 0;
174             if (data && sustained_performance_mode == 0) {
175                 int* resources;
176                 if (vr_mode == 0) { // Sustained mode only.
177                     // Ensure that POWER_HINT_LAUNCH is not in progress.
178                     if (launch_mode == 1) {
179                         release_request(launch_handle);
180                         launch_mode = 0;
181                     }
182                     // 0x40804000: cpu0 max freq
183                     // 0x40804100: cpu2 max freq
184                     // 0x42C20000: gpu max freq
185                     // 0x42C24000: gpu min freq
186                     // 0x42C28000: gpu bus min freq
187                     int resources[] = {0x40804000, 1209, 0x40804100, 1209,
188                                        0x42C24000, 133,  0x42C20000, 315,
189                                        0x42C28000, 7759};
190                     sustained_mode_handle = interaction_with_handle(
191                         sustained_mode_handle, duration,
192                         sizeof(resources) / sizeof(resources[0]), resources);
193                 } else if (vr_mode == 1) { // Sustained + VR mode.
194                     release_request(vr_mode_handle);
195                     // 0x40804000: cpu0 max freq
196                     // 0x40804100: cpu2 max freq
197                     // 0x40800000: cpu0 min freq
198                     // 0x40800100: cpu2 min freq
199                     // 0x42C20000: gpu max freq
200                     // 0x42C24000: gpu min freq
201                     // 0x42C28000: gpu bus min freq
202                     int resources[] = {0x40800000, 1209, 0x40800100, 1209,
203                                        0x40804000, 1209, 0x40804100, 1209,
204                                        0x42C24000, 315,  0x42C20000, 315,
205                                        0x42C28000, 7759};
206                     sustained_mode_handle = interaction_with_handle(
207                         sustained_mode_handle, duration,
208                         sizeof(resources) / sizeof(resources[0]), resources);
209                 }
210                 sustained_performance_mode = 1;
211             } else if (sustained_performance_mode == 1) {
212                 release_request(sustained_mode_handle);
213                 if (vr_mode == 1) { // Switch back to VR Mode.
214                     // 0x40804000: cpu0 max freq
215                     // 0x40804100: cpu2 max freq
216                     // 0x40800000: cpu0 min freq
217                     // 0x40800100: cpu2 min freq
218                     // 0x42C20000: gpu max freq
219                     // 0x42C24000: gpu min freq
220                     // 0x42C28000: gpu bus min freq
221                     int resources[] = {0x40804000, 1440, 0x40804100, 1440,
222                                        0x40800000, 1440, 0x40800100, 1440,
223                                        0x42C20000, 510,  0x42C24000, 510,
224                                        0x42C28000, 7759};
225                     vr_mode_handle = interaction_with_handle(
226                         vr_mode_handle, duration,
227                         sizeof(resources) / sizeof(resources[0]), resources);
228                 }
229                 sustained_performance_mode = 0;
230             }
231         }
232         break;
233         /* VR mode:
234          * All CPUs are locked at ~1.4GHz
235          * GPU frequency is locked  to 510MHz
236          * GPU BW min_freq is raised to 775MHz
237          */
238         case POWER_HINT_VR_MODE:
239         {
240             int duration = 0;
241             if (data && vr_mode == 0) {
242                 if (sustained_performance_mode == 0) { // VR mode only.
243                     // Ensure that POWER_HINT_LAUNCH is not in progress.
244                     if (launch_mode == 1) {
245                         release_request(launch_handle);
246                         launch_mode = 0;
247                     }
248                     // 0x40804000: cpu0 max freq
249                     // 0x40804100: cpu2 max freq
250                     // 0x40800000: cpu0 min freq
251                     // 0x40800100: cpu2 min freq
252                     // 0x42C20000: gpu max freq
253                     // 0x42C24000: gpu min freq
254                     // 0x42C28000: gpu bus min freq
255                     int resources[] = {0x40800000, 1440, 0x40800100, 1440,
256                                        0x40804000, 1440, 0x40804100, 1440,
257                                        0x42C20000, 510,  0x42C24000, 510,
258                                        0x42C28000, 7759};
259                     vr_mode_handle = interaction_with_handle(
260                         vr_mode_handle, duration,
261                         sizeof(resources) / sizeof(resources[0]), resources);
262                 } else if (sustained_performance_mode == 1) { // Sustained + VR mode.
263                     release_request(sustained_mode_handle);
264                     // 0x40804000: cpu0 max freq
265                     // 0x40804100: cpu2 max freq
266                     // 0x40800000: cpu0 min freq
267                     // 0x40800100: cpu2 min freq
268                     // 0x42C20000: gpu max freq
269                     // 0x42C24000: gpu min freq
270                     // 0x42C28000: gpu bus min freq
271                     int resources[] = {0x40800000, 1209, 0x40800100, 1209,
272                                        0x40804000, 1209, 0x40804100, 1209,
273                                        0x42C24000, 315,  0x42C20000, 315,
274                                        0x42C28000, 7759};
275 
276                     vr_mode_handle = interaction_with_handle(
277                         vr_mode_handle, duration,
278                         sizeof(resources) / sizeof(resources[0]), resources);
279                 }
280                 vr_mode = 1;
281             } else if (vr_mode == 1) {
282                 release_request(vr_mode_handle);
283                 if (sustained_performance_mode == 1) { // Switch back to sustained Mode.
284                     // 0x40804000: cpu0 max freq
285                     // 0x40804100: cpu2 max freq
286                     // 0x40800000: cpu0 min freq
287                     // 0x40800100: cpu2 min freq
288                     // 0x42C20000: gpu max freq
289                     // 0x42C24000: gpu min freq
290                     // 0x42C28000: gpu bus min freq
291                     int resources[] = {0x40800000, 0,    0x40800100, 0,
292                                        0x40804000, 1209, 0x40804100, 1209,
293                                        0x42C24000, 133,  0x42C20000, 315,
294                                        0x42C28000, 0};
295                     sustained_mode_handle = interaction_with_handle(
296                         sustained_mode_handle, duration,
297                         sizeof(resources) / sizeof(resources[0]), resources);
298                 }
299                 vr_mode = 0;
300             }
301         }
302         break;
303         case POWER_HINT_INTERACTION:
304         {
305             char governor[80];
306 
307             if (get_scaling_governor(governor, sizeof(governor)) == -1) {
308                 ALOGE("Can't obtain scaling governor.");
309                 return;
310             }
311 
312             if (sustained_performance_mode || vr_mode) {
313                 return;
314             }
315 
316             int duration = 1500; // 1.5s by default
317             if (data) {
318                 int input_duration = *((int*)data) + 750;
319                 if (input_duration > duration) {
320                     duration = (input_duration > 5750) ? 5750 : input_duration;
321                 }
322             }
323 
324             struct timespec cur_boost_timespec;
325             clock_gettime(CLOCK_MONOTONIC, &cur_boost_timespec);
326 
327             long long elapsed_time = calc_timespan_us(s_previous_boost_timespec, cur_boost_timespec);
328             // don't hint if previous hint's duration covers this hint's duration
329             if ((s_previous_duration * 1000) > (elapsed_time + duration * 1000)) {
330                 return;
331             }
332             s_previous_boost_timespec = cur_boost_timespec;
333             s_previous_duration = duration;
334 
335             // Scheduler is EAS.
336             if (true || strncmp(governor, SCHED_GOVERNOR, strlen(SCHED_GOVERNOR)) == 0) {
337                 // Setting the value of foreground schedtune boost to 50 and
338                 // scaling_min_freq to 1100MHz.
339                 int resources[] = {0x40800000, 1100, 0x40800100, 1100, 0x42C0C000, 0x32, 0x41800000, 0x33};
340                 interaction(duration, sizeof(resources)/sizeof(resources[0]), resources);
341             } else { // Scheduler is HMP.
342                 int resources[] = {0x41800000, 0x33, 0x40800000, 1000, 0x40800100, 1000, 0x40C00000, 0x1};
343                 interaction(duration, sizeof(resources)/sizeof(resources[0]), resources);
344             }
345         }
346         break;
347         default:
348         break;
349     }
350 }
351 
set_interactive_override(int UNUSED (on))352 int __attribute__ ((weak)) set_interactive_override(int UNUSED(on))
353 {
354     return HINT_NONE;
355 }
356 
power_set_interactive(int on)357 void power_set_interactive(int on)
358 {
359     char governor[80];
360     char tmp_str[NODE_MAX];
361     struct video_encode_metadata_t video_encode_metadata;
362     int rc = 0;
363 
364     if (set_interactive_override(on) == HINT_HANDLED) {
365         return;
366     }
367 
368     ALOGV("Got set_interactive hint");
369 
370     if (get_scaling_governor(governor, sizeof(governor)) == -1) {
371         ALOGE("Can't obtain scaling governor.");
372 
373         return;
374     }
375 
376     if (!on) {
377         /* Display off. */
378         if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
379                 (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
380             int resource_values[] = {DISPLAY_OFF, MS_500, THREAD_MIGRATION_SYNC_OFF};
381 
382             if (!display_hint_sent) {
383                 perform_hint_action(DISPLAY_STATE_HINT_ID,
384                         resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
385                 display_hint_sent = 1;
386             }
387         } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
388                 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
389             int resource_values[] = {TR_MS_50, THREAD_MIGRATION_SYNC_OFF};
390 
391             if (!display_hint_sent) {
392                 perform_hint_action(DISPLAY_STATE_HINT_ID,
393                         resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
394                 display_hint_sent = 1;
395             }
396         } else if ((strncmp(governor, MSMDCVS_GOVERNOR, strlen(MSMDCVS_GOVERNOR)) == 0) &&
397                 (strlen(governor) == strlen(MSMDCVS_GOVERNOR))) {
398             if (saved_interactive_mode == 1){
399                 /* Display turned off. */
400                 if (sysfs_read(DCVS_CPU0_SLACK_MAX_NODE, tmp_str, NODE_MAX - 1)) {
401                     if (!slack_node_rw_failed) {
402                         ALOGE("Failed to read from %s", DCVS_CPU0_SLACK_MAX_NODE);
403                     }
404 
405                     rc = 1;
406                 } else {
407                     saved_dcvs_cpu0_slack_max = atoi(tmp_str);
408                 }
409 
410                 if (sysfs_read(DCVS_CPU0_SLACK_MIN_NODE, tmp_str, NODE_MAX - 1)) {
411                     if (!slack_node_rw_failed) {
412                         ALOGE("Failed to read from %s", DCVS_CPU0_SLACK_MIN_NODE);
413                     }
414 
415                     rc = 1;
416                 } else {
417                     saved_dcvs_cpu0_slack_min = atoi(tmp_str);
418                 }
419 
420                 if (sysfs_read(MPDECISION_SLACK_MAX_NODE, tmp_str, NODE_MAX - 1)) {
421                     if (!slack_node_rw_failed) {
422                         ALOGE("Failed to read from %s", MPDECISION_SLACK_MAX_NODE);
423                     }
424 
425                     rc = 1;
426                 } else {
427                     saved_mpdecision_slack_max = atoi(tmp_str);
428                 }
429 
430                 if (sysfs_read(MPDECISION_SLACK_MIN_NODE, tmp_str, NODE_MAX - 1)) {
431                     if(!slack_node_rw_failed) {
432                         ALOGE("Failed to read from %s", MPDECISION_SLACK_MIN_NODE);
433                     }
434 
435                     rc = 1;
436                 } else {
437                     saved_mpdecision_slack_min = atoi(tmp_str);
438                 }
439 
440                 /* Write new values. */
441                 if (saved_dcvs_cpu0_slack_max != -1) {
442                     snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_dcvs_cpu0_slack_max);
443 
444                     if (sysfs_write(DCVS_CPU0_SLACK_MAX_NODE, tmp_str) != 0) {
445                         if (!slack_node_rw_failed) {
446                             ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MAX_NODE);
447                         }
448 
449                         rc = 1;
450                     }
451                 }
452 
453                 if (saved_dcvs_cpu0_slack_min != -1) {
454                     snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_dcvs_cpu0_slack_min);
455 
456                     if (sysfs_write(DCVS_CPU0_SLACK_MIN_NODE, tmp_str) != 0) {
457                         if(!slack_node_rw_failed) {
458                             ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MIN_NODE);
459                         }
460 
461                         rc = 1;
462                     }
463                 }
464 
465                 if (saved_mpdecision_slack_max != -1) {
466                     snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_mpdecision_slack_max);
467 
468                     if (sysfs_write(MPDECISION_SLACK_MAX_NODE, tmp_str) != 0) {
469                         if(!slack_node_rw_failed) {
470                             ALOGE("Failed to write to %s", MPDECISION_SLACK_MAX_NODE);
471                         }
472 
473                         rc = 1;
474                     }
475                 }
476 
477                 if (saved_mpdecision_slack_min != -1) {
478                     snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_mpdecision_slack_min);
479 
480                     if (sysfs_write(MPDECISION_SLACK_MIN_NODE, tmp_str) != 0) {
481                         if(!slack_node_rw_failed) {
482                             ALOGE("Failed to write to %s", MPDECISION_SLACK_MIN_NODE);
483                         }
484 
485                         rc = 1;
486                     }
487                 }
488             }
489 
490             slack_node_rw_failed = rc;
491         }
492     } else {
493         /* Display on. */
494         if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
495                 (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
496             undo_hint_action(DISPLAY_STATE_HINT_ID);
497             display_hint_sent = 0;
498         } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
499                 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
500             undo_hint_action(DISPLAY_STATE_HINT_ID);
501             display_hint_sent = 0;
502         } else if ((strncmp(governor, MSMDCVS_GOVERNOR, strlen(MSMDCVS_GOVERNOR)) == 0) &&
503                 (strlen(governor) == strlen(MSMDCVS_GOVERNOR))) {
504             if (saved_interactive_mode == -1 || saved_interactive_mode == 0) {
505                 /* Display turned on. Restore if possible. */
506                 if (saved_dcvs_cpu0_slack_max != -1) {
507                     snprintf(tmp_str, NODE_MAX, "%d", saved_dcvs_cpu0_slack_max);
508 
509                     if (sysfs_write(DCVS_CPU0_SLACK_MAX_NODE, tmp_str) != 0) {
510                         if (!slack_node_rw_failed) {
511                             ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MAX_NODE);
512                         }
513 
514                         rc = 1;
515                     }
516                 }
517 
518                 if (saved_dcvs_cpu0_slack_min != -1) {
519                     snprintf(tmp_str, NODE_MAX, "%d", saved_dcvs_cpu0_slack_min);
520 
521                     if (sysfs_write(DCVS_CPU0_SLACK_MIN_NODE, tmp_str) != 0) {
522                         if (!slack_node_rw_failed) {
523                             ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MIN_NODE);
524                         }
525 
526                         rc = 1;
527                     }
528                 }
529 
530                 if (saved_mpdecision_slack_max != -1) {
531                     snprintf(tmp_str, NODE_MAX, "%d", saved_mpdecision_slack_max);
532 
533                     if (sysfs_write(MPDECISION_SLACK_MAX_NODE, tmp_str) != 0) {
534                         if (!slack_node_rw_failed) {
535                             ALOGE("Failed to write to %s", MPDECISION_SLACK_MAX_NODE);
536                         }
537 
538                         rc = 1;
539                     }
540                 }
541 
542                 if (saved_mpdecision_slack_min != -1) {
543                     snprintf(tmp_str, NODE_MAX, "%d", saved_mpdecision_slack_min);
544 
545                     if (sysfs_write(MPDECISION_SLACK_MIN_NODE, tmp_str) != 0) {
546                         if (!slack_node_rw_failed) {
547                             ALOGE("Failed to write to %s", MPDECISION_SLACK_MIN_NODE);
548                         }
549 
550                         rc = 1;
551                     }
552                 }
553             }
554 
555             slack_node_rw_failed = rc;
556         }
557     }
558 
559     saved_interactive_mode = !!on;
560 }
561 
562 
extract_stats(uint64_t * list,char * file,const char ** param_names,unsigned int num_parameters,int isHex)563 static int extract_stats(uint64_t *list, char *file, const char**param_names,
564                          unsigned int num_parameters, int isHex) {
565     FILE *fp;
566     ssize_t read;
567     size_t len;
568     size_t index = 0;
569     char *line;
570     int ret;
571 
572     fp = fopen(file, "r");
573     if (fp == NULL) {
574         ret = -errno;
575         ALOGE("%s: failed to open: %s Error = %s", __func__, file, strerror(errno));
576         return ret;
577     }
578 
579     for (line = NULL, len = 0;
580          ((read = getline(&line, &len, fp) != -1) && (index < num_parameters));
581          free(line), line = NULL, len = 0) {
582         uint64_t value;
583         char* offset;
584 
585         size_t begin = strspn(line, " \t");
586         if (strncmp(line + begin, param_names[index], strlen(param_names[index]))) {
587             continue;
588         }
589 
590         offset = memchr(line, ':', len);
591         if (!offset) {
592             continue;
593         }
594 
595         if (isHex) {
596             sscanf(offset, ":%" SCNx64, &value);
597         } else {
598             sscanf(offset, ":%" SCNu64, &value);
599         }
600         list[index] = value;
601         index++;
602     }
603 
604     free(line);
605     fclose(fp);
606 
607     return 0;
608 }
609 
610 
extract_platform_stats(uint64_t * list)611 int extract_platform_stats(uint64_t *list) {
612 
613     int ret;
614 
615     //Data is located in two files
616 
617     ret = extract_stats(list, RPM_STAT, rpm_param_names, RPM_PARAM_COUNT, false);
618     if (ret) {
619         for (size_t i=0; i < RPM_PARAM_COUNT; i++)
620             list[i] = 0;
621     }
622 
623     ret = extract_stats(list + RPM_PARAM_COUNT, RPM_MASTER_STAT,
624                         rpm_master_param_names, PLATFORM_PARAM_COUNT - RPM_PARAM_COUNT, true);
625     if (ret) {
626         for (size_t i=RPM_PARAM_COUNT; i < PLATFORM_PARAM_COUNT; i++)
627         list[i] = 0;
628     }
629 
630     return 0;
631 }
632 
extract_wlan_stats(uint64_t * list)633 int extract_wlan_stats(uint64_t *list) {
634 
635     int ret;
636 
637     ret = extract_stats(list, WLAN_POWER_STAT, wlan_param_names, WLAN_PARAM_COUNT, false);
638     if (ret) {
639         for (size_t i=0; i < WLAN_PARAM_COUNT; i++)
640             list[i] = 0;
641     }
642 
643     return 0;
644 }
645