xref: /haiku/src/add-ons/kernel/bus_managers/acpi/Call.cpp (revision 4a55cc230cf7566cadcbb23b1928eefff8aea9a2)
1 /*
2  * Copyright 2022, Jérôme Duval. All rights reserved.
3  *
4  * Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <string.h>
11 
12 #include <Drivers.h>
13 #include <KernelExport.h>
14 #include <OS.h>
15 
16 #include "ACPIPrivate.h"
17 
18 
19 #define	TRACE(x...)			//dprintf("acpi_call: " x)
20 #define TRACE_ALWAYS(x...)	dprintf("acpi_call: " x)
21 #define CALLED() 			TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
22 
23 
24 typedef struct {
25 	device_node *node;
26 	acpi_root_info	*acpi;
27 	void	*acpi_cookie;
28 } acpi_call_device_info;
29 
30 
31 struct acpi_call_desc
32 {
33 	char*			path;
34 	acpi_objects	args;
35 	acpi_status	retval;
36 	acpi_data	result;
37 	acpi_size	reslen;
38 };
39 
40 
41 //	#pragma mark - device module API
42 
43 
44 static status_t
45 acpi_call_init_device(void* _node, void** _cookie)
46 {
47 	CALLED();
48 	device_node *node = (device_node *)_node;
49 
50 	acpi_call_device_info* device = (acpi_call_device_info*)calloc(1, sizeof(acpi_call_device_info));
51 	if (device == NULL)
52 		return B_NO_MEMORY;
53 
54 	device->node = node;
55 	status_t err = gDeviceManager->get_driver(node, (driver_module_info **)&device->acpi,
56 		(void **)&device->acpi_cookie);
57 	if (err != B_OK) {
58 		free(device);
59 		return err;
60 	}
61 
62 	*_cookie = device;
63 	return err;
64 }
65 
66 
67 static void
68 acpi_call_uninit_device(void* _cookie)
69 {
70 	CALLED();
71 	acpi_call_device_info* device = (acpi_call_device_info*)_cookie;
72 	free(device);
73 }
74 
75 
76 static status_t
77 acpi_call_open(void* _device, const char* path, int openMode, void** _cookie)
78 {
79 	CALLED();
80 	acpi_call_device_info* device = (acpi_call_device_info*)_device;
81 
82 	*_cookie = device;
83 	return B_OK;
84 }
85 
86 
87 static status_t
88 acpi_call_read(void *cookie, off_t position, void *buffer, size_t *numBytes)
89 {
90 	TRACE("read(%p, %" B_PRIdOFF", %p, %lu)\n", cookie, position, buffer, *numBytes);
91 	return B_ERROR;
92 }
93 
94 
95 static status_t
96 acpi_call_write(void *cookie, off_t position, const void *buffer,
97 	size_t *numBytes)
98 {
99 	TRACE("write(%p, %" B_PRIdOFF", %p, %lu)\n", cookie, position, buffer, *numBytes);
100 	return B_ERROR;
101 }
102 
103 
104 void
105 acpi_call_fixup_pointers(acpi_object_type *p, void *target)
106 {
107 	CALLED();
108 	switch (p->object_type)
109 	{
110 	case ACPI_TYPE_STRING:
111 		p->string.string = (char*)((uint8*)(p->string.string) - (uint8*)p + (uint8*)target);
112 		break;
113 	case ACPI_TYPE_BUFFER:
114 		p->buffer.buffer = (void*)((uint8*)(p->buffer.buffer) - (uint8*)p + (uint8*)target);
115 		break;
116 	}
117 }
118 
119 
120 static status_t
121 acpi_call_control(void *_device, uint32 op, void *buffer, size_t length)
122 {
123 	TRACE("control(%p, %" B_PRIu32 ", %p, %lu)\n", _device, op, buffer, length);
124 	acpi_call_device_info* device = (acpi_call_device_info*)_device;
125 
126 	if (op == 'ACCA') {
127 		struct acpi_call_desc params;
128 		char path[1024];
129 		if (user_memcpy(&params, buffer, sizeof(params)) != B_OK
130 			|| user_memcpy(path, params.path, sizeof(path)) != B_OK) {
131 			return B_BAD_ADDRESS;
132 		}
133 		acpi_data result;
134 		result.length = ACPI_ALLOCATE_BUFFER;
135 		result.pointer = NULL;
136 
137 		acpi_status retval = device->acpi->evaluate_method(NULL, path, &params.args, &result);
138 		if (retval == 0) {
139 			if (result.pointer != NULL) {
140 				if (params.result.pointer != NULL) {
141 					params.result.length = min_c(params.result.length, result.length);
142 					if (result.length >= sizeof(acpi_object_type))
143 						acpi_call_fixup_pointers((acpi_object_type*)(result.pointer), params.result.pointer);
144 
145 					if (user_memcpy(params.result.pointer, result.pointer, params.result.length) != B_OK
146 						|| user_memcpy(buffer, &params, sizeof(params)) != B_OK) {
147 						return B_BAD_ADDRESS;
148 					}
149 				}
150 				free(result.pointer);
151 			}
152 		}
153 		return B_OK;
154 	}
155 
156 	return B_ERROR;
157 }
158 
159 
160 static status_t
161 acpi_call_close(void *cookie)
162 {
163 	TRACE("close(%p)\n", cookie);
164 	return B_OK;
165 }
166 
167 
168 static status_t
169 acpi_call_free(void *cookie)
170 {
171 	TRACE("free(%p)\n", cookie);
172 	return B_OK;
173 }
174 
175 
176 //	#pragma mark -
177 
178 
179 struct device_module_info gAcpiCallDeviceModule = {
180 	{
181 		ACPI_CALL_DEVICE_MODULE_NAME,
182 		0,
183 		NULL
184 	},
185 
186 	acpi_call_init_device,
187 	acpi_call_uninit_device,
188 	NULL, // remove,
189 
190 	acpi_call_open,
191 	acpi_call_close,
192 	acpi_call_free,
193 	acpi_call_read,
194 	acpi_call_write,
195 	NULL,	// io
196 	acpi_call_control,
197 
198 	NULL,	// select
199 	NULL,	// deselect
200 };
201 
202