xref: /haiku/src/add-ons/kernel/drivers/power/acpi_thermal/acpi_thermal.c (revision 17889a8c70dbb3d59c1412f6431968753c767bab)
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 
59 	if (*num_bytes < 1)
60 		return B_IO_ERROR;
61 
62 	if (position == 0) {
63 		size_t max_len = *num_bytes;
64 		char* str = (char*)buf;
65 		acpi_thermal_control(device, drvOpGetThermalType, &therm_info, 0);
66 
67 		snprintf(str, max_len, "  Critical Temperature: %" B_PRIu32 ".%" B_PRIu32 " 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: %" B_PRIu32 ".%" B_PRIu32 " 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: %" B_PRIu32 ".%" B_PRIu32 " 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 	acpi_object_type object;
124 
125 	acpi_data buffer;
126 	buffer.pointer = &object;
127 	buffer.length = sizeof(object);
128 
129 	switch (op) {
130 		case drvOpGetThermalType: {
131 			att = (acpi_thermal_type*)arg;
132 
133 			// Read basic temperature thresholds.
134 			err = device->acpi->evaluate_method (device->acpi_cookie, "_CRT",
135 				NULL, &buffer);
136 
137 			att->critical_temp =
138 				(err == B_OK && object.object_type == ACPI_TYPE_INTEGER)
139 				? object.integer.integer : 0;
140 
141 			err = device->acpi->evaluate_method (device->acpi_cookie, "_TMP",
142 				NULL, &buffer);
143 
144 			att->current_temp =
145 				(err == B_OK && object.object_type == ACPI_TYPE_INTEGER)
146 				? object.integer.integer : 0;
147 
148 			err = device->acpi->evaluate_method(device->acpi_cookie, "_HOT",
149 				NULL, &buffer);
150 
151 			att->hot_temp =
152 				(err == B_OK && object.object_type == ACPI_TYPE_INTEGER)
153 				? object.integer.integer : 0;
154 
155 			// Read Passive Cooling devices
156 			att->passive_package = NULL;
157 			//err = device->acpi->get_object(device->acpi_cookie, "_PSL", &(att->passive_package));
158 
159 			att->active_count = 0;
160 			att->active_devices = NULL;
161 
162 			err = B_OK;
163 			break;
164 		}
165 	}
166 	return err;
167 }
168 
169 
170 static status_t
171 acpi_thermal_close (void* cookie)
172 {
173 	return B_OK;
174 }
175 
176 
177 static status_t
178 acpi_thermal_free (void* cookie)
179 {
180 	return B_OK;
181 }
182 
183 
184 //	#pragma mark - driver module API
185 
186 
187 static float
188 acpi_thermal_support(device_node *parent)
189 {
190 	const char* bus;
191 	uint32 device_type;
192 
193 	// make sure parent is really the ACPI bus manager
194 	if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
195 		return -1;
196 
197 	if (strcmp(bus, "acpi"))
198 		return 0.0;
199 
200 	// check whether it's really a thermal Device
201 	if (sDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM,
202 			&device_type, false) != B_OK || device_type != ACPI_TYPE_THERMAL) {
203 		return 0.0;
204 	}
205 
206 	// TODO check there are _CRT and _TMP ?
207 
208 	return 0.6;
209 }
210 
211 
212 static status_t
213 acpi_thermal_register_device(device_node *node)
214 {
215 	device_attr attrs[] = {
216 		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { .string = "ACPI Thermal" }},
217 		{ NULL }
218 	};
219 
220 	return sDeviceManager->register_node(node, ACPI_THERMAL_MODULE_NAME, attrs,
221 		NULL, NULL);
222 }
223 
224 
225 static status_t
226 acpi_thermal_init_driver(device_node* node, void** _driverCookie)
227 {
228 	*_driverCookie = node;
229 	return B_OK;
230 }
231 
232 
233 static void
234 acpi_thermal_uninit_driver(void* driverCookie)
235 {
236 }
237 
238 
239 static status_t
240 acpi_thermal_register_child_devices(void* _cookie)
241 {
242 	device_node* node = _cookie;
243 	int path_id;
244 	char name[128];
245 
246 	path_id = sDeviceManager->create_id(ACPI_THERMAL_PATHID_GENERATOR);
247 	if (path_id < 0) {
248 		dprintf("acpi_thermal_register_child_devices: couldn't create a path_id\n");
249 		return B_ERROR;
250 	}
251 
252 	snprintf(name, sizeof(name), ACPI_THERMAL_BASENAME, path_id);
253 
254 	return sDeviceManager->publish_device(node, name,
255 		ACPI_THERMAL_DEVICE_MODULE_NAME);
256 }
257 
258 
259 static status_t
260 acpi_thermal_init_device(void* _cookie, void** cookie)
261 {
262 	device_node* node = (device_node*)_cookie;
263 	acpi_thermal_device_info* device;
264 	device_node* parent;
265 
266 	device = (acpi_thermal_device_info*)calloc(1, sizeof(*device));
267 	if (device == NULL)
268 		return B_NO_MEMORY;
269 
270 	device->node = node;
271 
272 	parent = sDeviceManager->get_parent_node(node);
273 	sDeviceManager->get_driver(parent, (driver_module_info**)&device->acpi,
274 		(void**)&device->acpi_cookie);
275 	sDeviceManager->put_node(parent);
276 
277 	*cookie = device;
278 	return B_OK;
279 }
280 
281 
282 static void
283 acpi_thermal_uninit_device(void* _cookie)
284 {
285 	acpi_thermal_device_info* device = (acpi_thermal_device_info*)_cookie;
286 	free(device);
287 }
288 
289 
290 
291 module_dependency module_dependencies[] = {
292 	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&sDeviceManager },
293 	{}
294 };
295 
296 
297 driver_module_info acpi_thermal_driver_module = {
298 	{
299 		ACPI_THERMAL_MODULE_NAME,
300 		0,
301 		NULL
302 	},
303 
304 	acpi_thermal_support,
305 	acpi_thermal_register_device,
306 	acpi_thermal_init_driver,
307 	acpi_thermal_uninit_driver,
308 	acpi_thermal_register_child_devices,
309 	NULL,	// rescan
310 	NULL,	// removed
311 };
312 
313 
314 struct device_module_info acpi_thermal_device_module = {
315 	{
316 		ACPI_THERMAL_DEVICE_MODULE_NAME,
317 		0,
318 		NULL
319 	},
320 
321 	acpi_thermal_init_device,
322 	acpi_thermal_uninit_device,
323 	NULL,
324 
325 	acpi_thermal_open,
326 	acpi_thermal_close,
327 	acpi_thermal_free,
328 	acpi_thermal_read,
329 	acpi_thermal_write,
330 	NULL,
331 	acpi_thermal_control,
332 
333 	NULL,
334 	NULL
335 };
336 
337 module_info* modules[] = {
338 	(module_info*)&acpi_thermal_driver_module,
339 	(module_info*)&acpi_thermal_device_module,
340 	NULL
341 };
342