1/*
2 * Copyright 2009, Clemens Zeidler. All rights reserved.
3 * Copyright 2006, J��r��me Duval. All rights reserved.
4 *
5 * Distributed under the terms of the MIT License.
6 */
7
8
9#include <stdlib.h>
10#include <string.h>
11
12
13#include "ACPIPrivate.h"
14extern "C" {
15#include "acpi.h"
16}
17#include <dpc.h>
18#include <PCI.h>
19
20
21//#define TRACE_ACPI_MODULE
22#ifdef TRACE_ACPI_MODULE
23#	define TRACE(x) dprintf x
24#else
25#	define TRACE(x) ;
26#endif
27
28
29device_manager_info* gDeviceManager = NULL;
30pci_module_info* gPCIManager = NULL;
31dpc_module_info* gDPC = NULL;
32
33module_dependency module_dependencies[] = {
34	{B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager},
35	{B_PCI_MODULE_NAME, (module_info**)&gPCIManager},
36	{B_DPC_MODULE_NAME, (module_info**)&gDPC},
37	{}
38};
39
40
41static float
42acpi_module_supports_device(device_node* parent)
43{
44	// make sure parent is really device root
45	const char* bus;
46	if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
47		return B_ERROR;
48
49	if (strcmp(bus, "root"))
50		return 0.0;
51
52	return 1.0;
53}
54
55
56static status_t
57acpi_module_register_device(device_node* parent)
58{
59	device_attr attrs[] = {
60		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { .string = "ACPI" }},
61		{ B_DEVICE_FLAGS, B_UINT32_TYPE, { .ui32 = B_KEEP_DRIVER_LOADED }},
62		{}
63	};
64
65	return gDeviceManager->register_node(parent, ACPI_ROOT_MODULE_NAME, attrs,
66		NULL, NULL);
67}
68
69
70static status_t
71acpi_enumerate_child_devices(device_node* node, const char* root)
72{
73	char result[255];
74	void* counter = NULL;
75
76	TRACE(("acpi_enumerate_child_devices: recursing from %s\n", root));
77
78	while (get_next_entry(ACPI_TYPE_ANY, root, result,
79			sizeof(result), &counter) == B_OK) {
80		uint32 type = get_object_type(result);
81		device_node* deviceNode;
82
83		switch (type) {
84			case ACPI_TYPE_POWER:
85			case ACPI_TYPE_PROCESSOR:
86			case ACPI_TYPE_THERMAL:
87			case ACPI_TYPE_DEVICE: {
88				device_attr attrs[16] = {
89					// info about device
90					{ B_DEVICE_BUS, B_STRING_TYPE, { .string = "acpi" }},
91
92					// location on ACPI bus
93					{ ACPI_DEVICE_PATH_ITEM, B_STRING_TYPE, { .string = result }},
94
95					// info about the device
96					{ ACPI_DEVICE_TYPE_ITEM, B_UINT32_TYPE, { .ui32 = type }},
97
98					{ B_DEVICE_FLAGS, B_UINT32_TYPE, { .ui32 = B_FIND_MULTIPLE_CHILDREN }},
99					{ NULL }
100				};
101
102				uint32 attrCount = 4;
103				char* hid = NULL;
104				char* cidList[11] = { NULL };
105				char* uid = NULL;
106				char* cls = NULL;
107				if (type == ACPI_TYPE_DEVICE) {
108					if (get_device_info(result, &hid, (char**)&cidList, 8,
109						&uid, &cls) == B_OK) {
110						if (hid != NULL) {
111							attrs[attrCount].name = ACPI_DEVICE_HID_ITEM;
112							attrs[attrCount].type = B_STRING_TYPE;
113							attrs[attrCount].value.string = hid;
114							attrCount++;
115						}
116						for (int i = 0; cidList[i] != NULL; i++) {
117							attrs[attrCount].name = ACPI_DEVICE_CID_ITEM;
118							attrs[attrCount].type = B_STRING_TYPE;
119							attrs[attrCount].value.string = cidList[i];
120							attrCount++;
121						}
122						if (uid != NULL) {
123							attrs[attrCount].name = ACPI_DEVICE_UID_ITEM;
124							attrs[attrCount].type = B_STRING_TYPE;
125							attrs[attrCount].value.string = uid;
126							attrCount++;
127						}
128						if (cls != NULL) {
129							uint32 clsClass = strtoul(cls, NULL, 16);
130							attrs[attrCount].name = B_DEVICE_TYPE;
131							attrs[attrCount].type = B_UINT16_TYPE;
132							attrs[attrCount].value.ui16 = (clsClass >> 16) & 0xff ;
133							attrCount++;
134							attrs[attrCount].name = B_DEVICE_SUB_TYPE;
135							attrs[attrCount].type = B_UINT16_TYPE;
136							attrs[attrCount].value.ui16 = (clsClass >> 8) & 0xff ;
137							attrCount++;
138							attrs[attrCount].name = B_DEVICE_INTERFACE;
139							attrs[attrCount].type = B_UINT16_TYPE;
140							attrs[attrCount].value.ui16 = (clsClass >> 0) & 0xff ;
141							attrCount++;
142						}
143					}
144					uint32 addr;
145					if (get_device_addr(result, &addr) == B_OK) {
146						attrs[attrCount].name = ACPI_DEVICE_ADDR_ITEM;
147						attrs[attrCount].type = B_UINT32_TYPE;
148						attrs[attrCount].value.ui32 = addr;
149						attrCount++;
150					}
151				}
152
153				status_t status = gDeviceManager->register_node(node,
154						ACPI_DEVICE_MODULE_NAME, attrs, NULL, &deviceNode);
155				free(hid);
156				free(uid);
157				free(cls);
158				for (int i = 0; cidList[i] != NULL; i++)
159					free(cidList[i]);
160				if (status != B_OK)
161					break;
162				acpi_enumerate_child_devices(deviceNode, result);
163				break;
164			}
165			default:
166				acpi_enumerate_child_devices(node, result);
167				break;
168		}
169
170	}
171
172	return B_OK;
173}
174
175
176static status_t
177acpi_module_register_child_devices(void* cookie)
178{
179	device_node* node = (device_node*)cookie;
180
181	status_t status = gDeviceManager->publish_device(node, "acpi/namespace",
182		ACPI_NS_DUMP_DEVICE_MODULE_NAME);
183	if (status != B_OK)
184		return status;
185	status = gDeviceManager->publish_device(node, "acpi/call",
186		ACPI_CALL_DEVICE_MODULE_NAME);
187	if (status != B_OK)
188		return status;
189
190	if ((AcpiGbl_FADT.Flags & ACPI_FADT_POWER_BUTTON) == 0) {
191		dprintf("registering power button\n");
192		device_attr attrs[] = {
193			// info about device
194			{ B_DEVICE_BUS, B_STRING_TYPE, { .string = "acpi" }},
195
196			// info about the device
197			{ ACPI_DEVICE_HID_ITEM, B_STRING_TYPE, { .string = "ACPI_FPB" }},
198			{ ACPI_DEVICE_TYPE_ITEM, B_UINT32_TYPE, { .ui32 = ACPI_TYPE_DEVICE }},
199
200			// consumer specification
201			{ B_DEVICE_FLAGS, B_UINT32_TYPE, { .ui32 = B_FIND_MULTIPLE_CHILDREN }},
202			{ NULL }
203		};
204		device_node* deviceNode;
205		gDeviceManager->register_node(node, ACPI_DEVICE_MODULE_NAME, attrs,
206				NULL, &deviceNode);
207	}
208	if ((AcpiGbl_FADT.Flags & ACPI_FADT_SLEEP_BUTTON) == 0) {
209		dprintf("registering sleep button\n");
210		device_attr attrs[] = {
211			// info about device
212			{ B_DEVICE_BUS, B_STRING_TYPE, { .string = "acpi" }},
213
214			// info about the device
215			{ ACPI_DEVICE_HID_ITEM, B_STRING_TYPE, { .string = "ACPI_FSB" }},
216			{ ACPI_DEVICE_TYPE_ITEM, B_UINT32_TYPE, { .ui32 = ACPI_TYPE_DEVICE }},
217
218			// consumer specification
219			{ B_DEVICE_FLAGS, B_UINT32_TYPE, { .ui32 = B_FIND_MULTIPLE_CHILDREN }},
220			{ NULL }
221		};
222		device_node* deviceNode;
223		gDeviceManager->register_node(node, ACPI_DEVICE_MODULE_NAME, attrs,
224				NULL, &deviceNode);
225
226	}
227
228	return acpi_enumerate_child_devices(node, "\\");
229}
230
231
232static status_t
233acpi_module_init(device_node* node, void** _cookie)
234{
235	*_cookie = node;
236	return B_OK;
237}
238
239
240static void
241acpi_module_uninit(void* cookie)
242{
243}
244
245
246static int32
247acpi_module_std_ops(int32 op, ...)
248{
249	switch (op) {
250		case B_MODULE_INIT:
251		{
252			module_info* module;
253			return get_module(B_ACPI_MODULE_NAME, &module);
254				// this serializes our module initialization
255		}
256
257		case B_MODULE_UNINIT:
258			return put_module(B_ACPI_MODULE_NAME);
259	}
260
261	return B_BAD_VALUE;
262}
263
264
265static struct acpi_root_info sACPIRootModule = {
266	{
267		{
268			ACPI_ROOT_MODULE_NAME,
269			0,
270			acpi_module_std_ops
271		},
272
273		acpi_module_supports_device,
274		acpi_module_register_device,
275		acpi_module_init,
276		acpi_module_uninit,
277		acpi_module_register_child_devices,
278		NULL,	// rescan devices
279		NULL,	// device removed
280	},
281
282	get_handle,
283	get_name,
284	acquire_global_lock,
285	release_global_lock,
286	install_notify_handler,
287	remove_notify_handler,
288	update_all_gpes,
289	enable_gpe,
290	disable_gpe,
291	clear_gpe,
292	set_gpe,
293	finish_gpe,
294	install_gpe_handler,
295	remove_gpe_handler,
296	install_address_space_handler,
297	remove_address_space_handler,
298	enable_fixed_event,
299	disable_fixed_event,
300	fixed_event_status,
301	reset_fixed_event,
302	install_fixed_event_handler,
303	remove_fixed_event_handler,
304	get_next_entry,
305	get_next_object,
306	get_device,
307	get_device_info,
308	get_object_type,
309	get_object,
310	get_object_typed,
311	ns_handle_to_pathname,
312	evaluate_object,
313	evaluate_method,
314	get_irq_routing_table,
315	get_current_resources,
316	get_possible_resources,
317	set_current_resources,
318	walk_resources,
319	prepare_sleep_state,
320	enter_sleep_state,
321	reboot,
322	get_table
323};
324
325
326module_info* modules[] = {
327	(module_info*)&gACPIModule,
328	(module_info*)&sACPIRootModule,
329	(module_info*)&acpi_ns_dump_module,
330	(module_info*)&gACPIDeviceModule,
331	(module_info*)&embedded_controller_driver_module,
332	(module_info*)&embedded_controller_device_module,
333	(module_info*)&gAcpiCallDeviceModule,
334	NULL
335};
336