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