xref: /haiku/src/add-ons/kernel/drivers/power/acpi_thermal/acpi_thermal.c (revision 922e7ba1f3228e6f28db69b0ded8f86eb32dea17)
1 /*
2  * Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
3  *
4  * Distributed under the terms of the MIT License.
5  *
6  * ACPI Generic Thermal Zone Driver.
7  * Obtains general status of passive devices, monitors / sets critical temperatures
8  * Controls active devices.
9  */
10 
11 #include <KernelExport.h>
12 #include <Drivers.h>
13 #include <Errors.h>
14 #include <string.h>
15 
16 #include <stdio.h>
17 #include <stdlib.h>
18 
19 #include <ACPI.h>
20 #include "acpi_thermal.h"
21 
22 #define ACPI_THERMAL_MODULE_NAME "drivers/power/acpi_thermal/driver_v1"
23 
24 #define ACPI_THERMAL_DEVICE_MODULE_NAME "drivers/power/acpi_thermal/device_v1"
25 
26 /* Base Namespace devices are published to */
27 #define ACPI_THERMAL_BASENAME "power/acpi_thermal/%d"
28 
29 // name of pnp generator of path ids
30 #define ACPI_THERMAL_PATHID_GENERATOR "acpi_thermal/path_id"
31 
32 static device_manager_info *sDeviceManager;
33 
34 typedef struct acpi_ns_device_info {
35 	device_node *node;
36 	acpi_device_module_info *acpi;
37 	acpi_device acpi_cookie;
38 } acpi_thermal_device_info;
39 
40 
41 status_t acpi_thermal_control(void* _cookie, uint32 op, void* arg, size_t len);
42 
43 
44 static status_t
45 acpi_thermal_open(void *_cookie, const char *path, int flags, void** cookie)
46 {
47 	acpi_thermal_device_info *device = (acpi_thermal_device_info *)_cookie;
48 	*cookie = device;
49 	return B_OK;
50 }
51 
52 
53 static status_t
54 acpi_thermal_read(void* _cookie, off_t position, void *buf, size_t* num_bytes)
55 {
56 	acpi_thermal_device_info* device = (acpi_thermal_device_info*)_cookie;
57 	acpi_thermal_type therm_info;
58 	if (*num_bytes < 1)
59 		return B_IO_ERROR;
60 
61 	if (position == 0) {
62 		size_t max_len = *num_bytes;
63 		char *str = (char *)buf;
64 		dprintf("acpi_thermal: read()\n");
65 		acpi_thermal_control(device, drvOpGetThermalType, &therm_info, 0);
66 
67 		snprintf(str, max_len, "  Critical Temperature: %lu.%lu K\n",
68 				(therm_info.critical_temp / 10), (therm_info.critical_temp % 10));
69 
70 		max_len -= strlen(str);
71 		str += strlen(str);
72 		snprintf(str, max_len, "  Current Temperature: %lu.%lu K\n",
73 				(therm_info.current_temp / 10), (therm_info.current_temp % 10));
74 
75 		if (therm_info.hot_temp > 0) {
76 			max_len -= strlen(str);
77 			str += strlen(str);
78 			snprintf(str, max_len, "  Hot Temperature: %lu.%lu K\n",
79 					(therm_info.hot_temp / 10), (therm_info.hot_temp % 10));
80 		}
81 
82 		if (therm_info.passive_package) {
83 /* Incomplete.
84      Needs to obtain acpi global lock.
85      acpi_object_type needs Reference entry (with Handle that can be resolved)
86      what you see here is _highly_ unreliable.
87 */
88 /*      		if (therm_info.passive_package->data.package.count > 0) {
89 				sprintf((char *)buf + *num_bytes, "  Passive Devices\n");
90 				*num_bytes = strlen((char *)buf);
91 				for (i = 0; i < therm_info.passive_package->data.package.count; i++) {
92 					sprintf((char *)buf + *num_bytes, "    Processor: %lu\n", therm_info.passive_package->data.package.objects[i].data.processor.cpu_id);
93 					*num_bytes = strlen((char *)buf);
94 				}
95 			}
96 */
97 			free(therm_info.passive_package);
98 		}
99 		*num_bytes = strlen((char *)buf);
100 	} else {
101 		*num_bytes = 0;
102 	}
103 
104 	return B_OK;
105 }
106 
107 
108 static status_t
109 acpi_thermal_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes)
110 {
111 	return B_ERROR;
112 }
113 
114 
115 status_t
116 acpi_thermal_control(void* _cookie, uint32 op, void* arg, size_t len)
117 {
118 	acpi_thermal_device_info* device = (acpi_thermal_device_info*)_cookie;
119 	status_t err = B_ERROR;
120 
121 	acpi_thermal_type *att = NULL;
122 
123 	uint32 integer;
124 	acpi_data buffer;
125 	buffer.pointer = &integer;
126 	buffer.length = sizeof(integer);
127 
128 	switch (op) {
129 		case drvOpGetThermalType: {
130 			dprintf("acpi_thermal: GetThermalType()\n");
131 			att = (acpi_thermal_type *)arg;
132 
133 			// Read basic temperature thresholds.
134 			err = device->acpi->evaluate_method(device->acpi_cookie, "_CRT", NULL, &buffer);
135 			att->critical_temp = (err == B_OK) ? integer : 0;
136 			err = device->acpi->evaluate_method(device->acpi_cookie, "_TMP", NULL, &buffer);
137 			att->current_temp = (err == B_OK) ? integer : 0;
138 			err = device->acpi->evaluate_method(device->acpi_cookie, "_HOT", NULL, &buffer);
139 			att->hot_temp = (err == B_OK) ? integer : 0;
140 
141 			dprintf("acpi_thermal: GotBasicTemperatures()\n");
142 
143 			// Read Passive Cooling devices
144 			att->passive_package = NULL;
145 			err = device->acpi->get_object(device->acpi_cookie, "_PSL", &(att->passive_package));
146 
147 			att->active_count = 0;
148 			att->active_devices = NULL;
149 
150 			err = B_OK;
151 			break;
152 		}
153 	}
154 	return err;
155 }
156 
157 
158 static status_t
159 acpi_thermal_close (void* cookie)
160 {
161 	return B_OK;
162 }
163 
164 
165 static status_t
166 acpi_thermal_free (void* cookie)
167 {
168 	return B_OK;
169 }
170 
171 
172 //	#pragma mark - driver module API
173 
174 
175 static float
176 acpi_thermal_support(device_node *parent)
177 {
178 	const char *bus;
179 	uint32 device_type;
180 
181 	// make sure parent is really the ACPI bus manager
182 	if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
183 		return -1;
184 
185 	if (strcmp(bus, "acpi"))
186 		return 0.0;
187 
188 	// check whether it's really a thermal Device
189 	if (sDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM, &device_type, false) != B_OK
190 		|| device_type != ACPI_TYPE_THERMAL) {
191 		return 0.0;
192 	}
193 
194 	// TODO check there are _CRT and _TMP ?
195 
196 	return 0.6;
197 }
198 
199 
200 static status_t
201 acpi_thermal_register_device(device_node *node)
202 {
203 	device_attr attrs[] = {
204 		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { string: "ACPI Thermal" }},
205 		{ NULL }
206 	};
207 
208 	return sDeviceManager->register_node(node, ACPI_THERMAL_MODULE_NAME, attrs, NULL, NULL);
209 }
210 
211 
212 static status_t
213 acpi_thermal_init_driver(device_node *node, void **_driverCookie)
214 {
215 	*_driverCookie = node;
216 	return B_OK;
217 }
218 
219 
220 static void
221 acpi_thermal_uninit_driver(void *driverCookie)
222 {
223 }
224 
225 
226 static status_t
227 acpi_thermal_register_child_devices(void *_cookie)
228 {
229 	device_node *node = _cookie;
230 	int path_id;
231 	char name[128];
232 
233 	path_id = sDeviceManager->create_id(ACPI_THERMAL_PATHID_GENERATOR);
234 	if (path_id < 0) {
235 		dprintf("acpi_thermal_register_child_devices: couldn't create a path_id\n");
236 		return B_ERROR;
237 	}
238 
239 	snprintf(name, sizeof(name), ACPI_THERMAL_BASENAME, path_id);
240 
241 	return sDeviceManager->publish_device(node, name, ACPI_THERMAL_DEVICE_MODULE_NAME);
242 }
243 
244 
245 static status_t
246 acpi_thermal_init_device(void *_cookie, void **cookie)
247 {
248 	device_node *node = (device_node *)_cookie;
249 	acpi_thermal_device_info *device;
250 	device_node *parent;
251 
252 	device = (acpi_thermal_device_info *)calloc(1, sizeof(*device));
253 	if (device == NULL)
254 		return B_NO_MEMORY;
255 
256 	device->node = node;
257 
258 	parent = sDeviceManager->get_parent_node(node);
259 	sDeviceManager->get_driver(parent, (driver_module_info **)&device->acpi,
260 		(void **)&device->acpi_cookie);
261 	sDeviceManager->put_node(parent);
262 
263 	*cookie = device;
264 	return B_OK;
265 }
266 
267 
268 static void
269 acpi_thermal_uninit_device(void *_cookie)
270 {
271 	acpi_thermal_device_info *device = (acpi_thermal_device_info *)_cookie;
272 	free(device);
273 }
274 
275 
276 
277 module_dependency module_dependencies[] = {
278 	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager },
279 	{}
280 };
281 
282 
283 driver_module_info acpi_thermal_driver_module = {
284 	{
285 		ACPI_THERMAL_MODULE_NAME,
286 		0,
287 		NULL
288 	},
289 
290 	acpi_thermal_support,
291 	acpi_thermal_register_device,
292 	acpi_thermal_init_driver,
293 	acpi_thermal_uninit_driver,
294 	acpi_thermal_register_child_devices,
295 	NULL,	// rescan
296 	NULL,	// removed
297 };
298 
299 
300 struct device_module_info acpi_thermal_device_module = {
301 	{
302 		ACPI_THERMAL_DEVICE_MODULE_NAME,
303 		0,
304 		NULL
305 	},
306 
307 	acpi_thermal_init_device,
308 	acpi_thermal_uninit_device,
309 	NULL,
310 
311 	acpi_thermal_open,
312 	acpi_thermal_close,
313 	acpi_thermal_free,
314 	acpi_thermal_read,
315 	acpi_thermal_write,
316 	NULL,
317 	acpi_thermal_control,
318 
319 	NULL,
320 	NULL
321 };
322 
323 module_info *modules[] = {
324 	(module_info *)&acpi_thermal_driver_module,
325 	(module_info *)&acpi_thermal_device_module,
326 	NULL
327 };
328