hc
2024-08-12 233ab1bd4c5697f5cdec94e60206e8c6ac609b4c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * APM emulation for PMU-based machines
 *
 * Copyright 2001 Benjamin Herrenschmidt (benh@kernel.crashing.org)
 */
 
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/apm-emulation.h>
#include <linux/adb.h>
#include <linux/pmu.h>
 
#define APM_CRITICAL        10
#define APM_LOW            30
 
static void pmu_apm_get_power_status(struct apm_power_info *info)
{
   int percentage = -1;
   int batteries = 0;
   int time_units = -1;
   int real_count = 0;
   int i;
   char charging = 0;
   long charge = -1;
   long amperage = 0;
   unsigned long btype = 0;
 
   info->battery_status = APM_BATTERY_STATUS_UNKNOWN;
   info->battery_flag = APM_BATTERY_FLAG_UNKNOWN;
   info->units = APM_UNITS_MINS;
 
   if (pmu_power_flags & PMU_PWR_AC_PRESENT)
       info->ac_line_status = APM_AC_ONLINE;
   else
       info->ac_line_status = APM_AC_OFFLINE;
 
   for (i=0; i<pmu_battery_count; i++) {
       if (pmu_batteries[i].flags & PMU_BATT_PRESENT) {
           batteries++;
           if (percentage < 0)
               percentage = 0;
           if (charge < 0)
               charge = 0;
           percentage += (pmu_batteries[i].charge * 100) /
               pmu_batteries[i].max_charge;
           charge += pmu_batteries[i].charge;
           amperage += pmu_batteries[i].amperage;
           if (btype == 0)
               btype = (pmu_batteries[i].flags & PMU_BATT_TYPE_MASK);
           real_count++;
           if ((pmu_batteries[i].flags & PMU_BATT_CHARGING))
               charging++;
       }
   }
   if (batteries == 0)
       info->ac_line_status = APM_AC_ONLINE;
 
   if (real_count) {
       if (amperage < 0) {
           if (btype == PMU_BATT_TYPE_SMART)
               time_units = (charge * 59) / (amperage * -1);
           else
               time_units = (charge * 16440) / (amperage * -60);
       }
       percentage /= real_count;
       if (charging > 0) {
           info->battery_status = APM_BATTERY_STATUS_CHARGING;
           info->battery_flag = APM_BATTERY_FLAG_CHARGING;
       } else if (percentage <= APM_CRITICAL) {
           info->battery_status = APM_BATTERY_STATUS_CRITICAL;
           info->battery_flag = APM_BATTERY_FLAG_CRITICAL;
       } else if (percentage <= APM_LOW) {
           info->battery_status = APM_BATTERY_STATUS_LOW;
           info->battery_flag = APM_BATTERY_FLAG_LOW;
       } else {
           info->battery_status = APM_BATTERY_STATUS_HIGH;
           info->battery_flag = APM_BATTERY_FLAG_HIGH;
       }
   }
 
   info->battery_life = percentage;
   info->time = time_units;
}
 
static int __init apm_emu_init(void)
{
   apm_get_power_status = pmu_apm_get_power_status;
 
   printk(KERN_INFO "apm_emu: PMU APM Emulation initialized.\n");
 
   return 0;
}
 
static void __exit apm_emu_exit(void)
{
   if (apm_get_power_status == pmu_apm_get_power_status)
       apm_get_power_status = NULL;
 
   printk(KERN_INFO "apm_emu: PMU APM Emulation removed.\n");
}
 
module_init(apm_emu_init);
module_exit(apm_emu_exit);
 
MODULE_AUTHOR("Benjamin Herrenschmidt");
MODULE_DESCRIPTION("APM emulation for PowerMac");
MODULE_LICENSE("GPL");