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
acpi_call_init_device(void * _node,void ** _cookie)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
acpi_call_uninit_device(void * _cookie)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
acpi_call_open(void * _device,const char * path,int openMode,void ** _cookie)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
acpi_call_read(void * cookie,off_t position,void * buffer,size_t * numBytes)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
acpi_call_write(void * cookie,off_t position,const void * buffer,size_t * numBytes)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
acpi_call_fixup_pointers(acpi_object_type * p,void * target)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
acpi_call_control(void * _device,uint32 op,void * buffer,size_t length)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(¶ms, 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, ¶ms.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, ¶ms, 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
acpi_call_close(void * cookie)161 acpi_call_close(void *cookie)
162 {
163 TRACE("close(%p)\n", cookie);
164 return B_OK;
165 }
166
167
168 static status_t
acpi_call_free(void * cookie)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