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
24typedef struct {
25	device_node *node;
26	acpi_root_info	*acpi;
27	void	*acpi_cookie;
28} acpi_call_device_info;
29
30
31struct 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
44static status_t
45acpi_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
67static void
68acpi_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
76static status_t
77acpi_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
87static status_t
88acpi_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
95static status_t
96acpi_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
104void
105acpi_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
120static status_t
121acpi_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
160static status_t
161acpi_call_close(void *cookie)
162{
163	TRACE("close(%p)\n", cookie);
164	return B_OK;
165}
166
167
168static status_t
169acpi_call_free(void *cookie)
170{
171	TRACE("free(%p)\n", cookie);
172	return B_OK;
173}
174
175
176//	#pragma mark -
177
178
179struct 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