xref: /haiku/src/apps/powerstatus/APMDriverInterface.cpp (revision 9760dcae2038d47442f4658c2575844c6cf92c40)
1 /*
2  * Copyright 2009, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Clemens Zeidler, haiku@clemens-zeidler.de
7  */
8 
9 
10 #include "APMDriverInterface.h"
11 
12 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
13 #	include <arch/x86/apm_defs.h>
14 #	include <generic_syscall_defs.h>
15 #	include <syscalls.h>
16 	// temporary, as long as there is no real power state API
17 #endif
18 
19 
20 const bigtime_t kUpdateInterval = 2000000;
21 		// every two seconds
22 
23 
24 #ifndef HAIKU_TARGET_PLATFORM_HAIKU
25 // definitions for the APM driver available for BeOS
26 enum {
27 	APM_CONTROL = B_DEVICE_OP_CODES_END + 1,
28 	APM_DUMP_POWER_STATUS,
29 	APM_BIOS_CALL,
30 	APM_SET_SAFETY
31 };
32 
33 #define BIOS_APM_GET_POWER_STATUS 0x530a
34 #endif
35 
36 
37 APMDriverInterface::~APMDriverInterface()
38 {
39 #ifndef HAIKU_TARGET_PLATFORM_HAIKU
40 	close(fDevice);
41 #endif
42 }
43 
44 
45 status_t
46 APMDriverInterface::Connect()
47 {
48 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
49 	uint32 version = 0;
50 	status_t status = _kern_generic_syscall(APM_SYSCALLS, B_SYSCALL_INFO,
51 		&version, sizeof(version));
52 	if (status == B_OK) {
53 		battery_info info;
54 		status = _kern_generic_syscall(APM_SYSCALLS, APM_GET_BATTERY_INFO,
55 			&info, sizeof(battery_info));
56 	}
57 
58 	return status;
59 
60 #else
61 	fDevice = open("/dev/misc/apm", O_RDONLY);
62 	if (fDevice < 0) {
63 		return B_ERROR;
64 	}
65 
66 	return B_OK;
67 #endif
68 }
69 
70 
71 status_t
72 APMDriverInterface::GetBatteryInfo(battery_info* info, int32 index)
73 {
74 	if (index != 0)
75 		return B_BAD_VALUE;
76 
77 	info->current_rate = -1;
78 
79 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
80 	// TODO: retrieve data from APM kernel interface
81 	apm_battery_info apmInfo;
82 	status_t status = _kern_generic_syscall(APM_SYSCALLS, APM_GET_BATTERY_INFO,
83 		&apmInfo, sizeof(apm_battery_info));
84 	if (status == B_OK) {
85 		info->state = apmInfo.online ? BATTERY_CHARGING : BATTERY_DISCHARGING;
86 		info->capacity = apmInfo.percent;
87 		info->full_capacity = 100;
88 		info->time_left = apmInfo.time_left;
89 	}
90 
91 	return status;
92 #else
93 	if (fDevice < 0)
94 		return B_ERROR;
95 
96 	uint16 regs[6] = {0, 0, 0, 0, 0, 0};
97 	regs[0] = BIOS_APM_GET_POWER_STATUS;
98 	regs[1] = 0x1;
99 	if (ioctl(fDevice, APM_BIOS_CALL, regs) == 0) {
100 		bool online = (regs[1] >> 8) != 0 && (regs[1] >> 8) != 2;
101 		info->state = online ? BATTERY_CHARGING : BATTERY_DISCHARGING;
102 		info->capacity = regs[2] & 255;
103 		if (info->capacity > 100)
104 			info->capacity = -1;
105 		info->full_capacity = 100;
106 		info->time_left = info->capacity >= 0 ? regs[3] : -1;
107 		if (info->time_left > 0xffff)
108 			info->time_left = -1;
109 		else if (info->time_left & 0x8000)
110 			info->time_left = (info->time_left & 0x7fff) * 60;
111 	}
112 
113 	return B_OK;
114 #endif
115 }
116 
117 
118 status_t
119 APMDriverInterface::GetExtendedBatteryInfo(acpi_extended_battery_info* info,
120 	int32 index)
121 {
122 	return B_ERROR;
123 }
124 
125 
126 int32
127 APMDriverInterface::GetBatteryCount()
128 {
129 	return 1;
130 }
131 
132 
133 void
134 APMDriverInterface::_WatchPowerStatus()
135 {
136 	while (atomic_get(&fIsWatching) > 0) {
137 		Broadcast(kMsgUpdate);
138 		acquire_sem_etc(fWaitSem, 1, B_RELATIVE_TIMEOUT, kUpdateInterval);
139 	}
140 }
141 
142