xref: /haiku/src/add-ons/kernel/bus_managers/acpi/NamespaceDump.cpp (revision 7a617f59fd64449167bb190666bd44fae7efbe0b)
1 /*
2  * Copyright 2006-2013, Jérôme Duval. All rights reserved.
3  * Copyright 2011-2012, Fredrik Holmqvis. All rights reserved.
4  * Copyright 2008, Stefano Ceccherini. All rights reserved.
5  * Copyright 2006, Bryan Varner. All rights reserved.
6  * Distributed under the terms of the MIT License.
7  */
8 
9 
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 
15 #include <Drivers.h>
16 
17 #include <kernel.h>
18 #include <util/kernel_cpp.h>
19 #include <util/ring_buffer.h>
20 
21 #include "ACPIPrivate.h"
22 
23 
24 class RingBuffer {
25 public:
26 	RingBuffer(size_t size = 1024);
27 	~RingBuffer();
28 	size_t Read(void *buffer, ssize_t length);
29 	size_t Write(const void *buffer, ssize_t length);
30 	size_t WritableAmount() const;
31 	size_t ReadableAmount() const;
32 
33 	bool Lock();
34 	void Unlock();
35 	void DestroyLock();
36 private:
37 	ring_buffer *fBuffer;
38 	sem_id fLock;
39 };
40 
41 
42 typedef struct acpi_ns_device_info {
43 	device_node *node;
44 	acpi_root_info	*acpi;
45 	void	*acpi_cookie;
46 	thread_id thread;
47 	sem_id read_sem;
48 	RingBuffer *buffer;
49 } acpi_ns_device_info;
50 
51 
52 
53 // called with the buffer lock held
54 static bool
55 make_space(acpi_ns_device_info *device, size_t space)
56 {
57 	size_t available = device->buffer->WritableAmount();
58 	if (space <= available)
59 		return true;
60 	bool released = false;
61 	do {
62 		device->buffer->Unlock();
63 
64 		if (!released) {
65 			if (release_sem_etc(device->read_sem, 1, B_RELEASE_IF_WAITING_ONLY) == B_OK)
66 				released = true;
67 		}
68 		snooze(10000);
69 
70 		if (!device->buffer->Lock())
71 			return false;
72 
73 	} while (device->buffer->WritableAmount() < space);
74 
75 	return true;
76 }
77 
78 
79 
80 static void
81 dump_acpi_namespace(acpi_ns_device_info *device, char *root, int indenting)
82 {
83 	char result[255];
84 	char output[320];
85 	char tabs[255] = "";
86 	int i;
87 	size_t written = 0;
88 	for (i = 0; i < indenting; i++)
89 		strlcat(tabs, "|    ", sizeof(tabs));
90 
91 	strlcat(tabs, "|--- ", sizeof(tabs));
92 
93 	int depth = sizeof(char) * 5 * indenting + sizeof(char); // index into result where the device name will be.
94 
95 	void *counter = NULL;
96 	while (device->acpi->get_next_entry(ACPI_TYPE_ANY, root, result, 255, &counter) == B_OK) {
97 		uint32 type = device->acpi->get_object_type(result);
98 		snprintf(output, sizeof(output), "%s%s", tabs, result + depth);
99 		switch(type) {
100 			case ACPI_TYPE_INTEGER:
101 				strlcat(output, "     INTEGER", sizeof(output));
102 				break;
103 			case ACPI_TYPE_STRING:
104 				strlcat(output, "     STRING", sizeof(output));
105 				break;
106 			case ACPI_TYPE_BUFFER:
107 				strlcat(output, "     BUFFER", sizeof(output));
108 				break;
109 			case ACPI_TYPE_PACKAGE:
110 				strlcat(output, "     PACKAGE", sizeof(output));
111 				break;
112 			case ACPI_TYPE_FIELD_UNIT:
113 				strlcat(output, "     FIELD UNIT", sizeof(output));
114 				break;
115 			case ACPI_TYPE_DEVICE:
116 			{
117 				char* hid = NULL;
118 				device->acpi->get_device_info(result, &hid, NULL, 0, NULL);
119 				strlcat(output, "     DEVICE (", sizeof(output));
120 				if (hid != NULL) {
121 					strlcat(output, hid, sizeof(output));
122 					free(hid);
123 				} else
124 					strlcat(output, "none", sizeof(output));
125 				strlcat(output, ")", sizeof(output));
126 				break;
127 			}
128 			case ACPI_TYPE_EVENT:
129 				strlcat(output, "     EVENT", sizeof(output));
130 				break;
131 			case ACPI_TYPE_METHOD:
132 				strlcat(output, "     METHOD", sizeof(output));
133 				break;
134 			case ACPI_TYPE_MUTEX:
135 				strlcat(output, "     MUTEX", sizeof(output));
136 				break;
137 			case ACPI_TYPE_REGION:
138 				strlcat(output, "     REGION", sizeof(output));
139 				break;
140 			case ACPI_TYPE_POWER:
141 				strlcat(output, "     POWER", sizeof(output));
142 				break;
143 			case ACPI_TYPE_PROCESSOR:
144 				strlcat(output, "     PROCESSOR", sizeof(output));
145 				break;
146 			case ACPI_TYPE_THERMAL:
147 				strlcat(output, "     THERMAL", sizeof(output));
148 				break;
149 			case ACPI_TYPE_BUFFER_FIELD:
150 				strlcat(output, "     BUFFER_FIELD", sizeof(output));
151 				break;
152 			case ACPI_TYPE_ANY:
153 			default:
154 				break;
155 		}
156 		written = 0;
157 		RingBuffer &ringBuffer = *device->buffer;
158 		size_t toWrite = strlen(output);
159 
160 		if (toWrite == 0)
161 			break;
162 
163 		toWrite = strlcat(output, "\n", sizeof(output));
164 
165 		if (!ringBuffer.Lock())
166 			break;
167 
168 		if (ringBuffer.WritableAmount() < toWrite &&
169 			!make_space(device, toWrite))
170 			break;
171 
172 		written = ringBuffer.Write(output, toWrite);
173 		ringBuffer.Unlock();
174 		dump_acpi_namespace(device, result, indenting + 1);
175 	}
176 }
177 
178 
179 static int32
180 acpi_namespace_dump(void *arg)
181 {
182 	acpi_ns_device_info *device = (acpi_ns_device_info*)(arg);
183 	dump_acpi_namespace(device, NULL, 0);
184 
185 	delete_sem(device->read_sem);
186 	device->read_sem = -1;
187 
188 	return 0;
189 }
190 
191 extern "C" {
192 /* ----------
193 	acpi_namespace_open - handle open() calls
194 ----- */
195 
196 static status_t
197 acpi_namespace_open(void *_cookie, const char* path, int flags, void** cookie)
198 {
199 	acpi_ns_device_info *device = (acpi_ns_device_info *)_cookie;
200 
201 	dprintf("\nacpi_ns_dump: device_open\n");
202 
203 	*cookie = device;
204 
205 	RingBuffer *ringBuffer = new RingBuffer(1024);
206 	if (ringBuffer == NULL)
207 		return B_NO_MEMORY;
208 
209 	device->read_sem = create_sem(0, "read_sem");
210 	if (device->read_sem < B_OK) {
211 		delete ringBuffer;
212 		return device->read_sem;
213 	}
214 
215 	device->thread = spawn_kernel_thread(acpi_namespace_dump, "acpi dumper",
216 		 B_NORMAL_PRIORITY, device);
217 	if (device->thread < 0) {
218 		delete ringBuffer;
219 		delete_sem(device->read_sem);
220 		return device->thread;
221 	}
222 
223 	device->buffer = ringBuffer;
224 
225 	resume_thread(device->thread);
226 
227 	return B_OK;
228 }
229 
230 
231 /* ----------
232 	acpi_namespace_read - handle read() calls
233 ----- */
234 static status_t
235 acpi_namespace_read(void *_cookie, off_t position, void *buf, size_t* num_bytes)
236 {
237 	acpi_ns_device_info *device = (acpi_ns_device_info *)_cookie;
238 	RingBuffer &ringBuffer = *device->buffer;
239 
240 	if (!ringBuffer.Lock()) {
241 		*num_bytes = 0;
242 		return B_ERROR;
243 	}
244 
245 	if (ringBuffer.ReadableAmount() == 0) {
246 		ringBuffer.Unlock();
247 		status_t status = acquire_sem_etc(device->read_sem, 1, B_CAN_INTERRUPT, 0);
248 		if (status != B_OK && status != B_BAD_SEM_ID) {
249 			*num_bytes = 0;
250 			return status;
251 		}
252 		if (!ringBuffer.Lock()) {
253 			*num_bytes = 0;
254 			return B_ERROR;
255 		}
256 	}
257 
258 	*num_bytes = ringBuffer.Read(buf, *num_bytes);
259 	ringBuffer.Unlock();
260 
261 	return B_OK;
262 }
263 
264 
265 /* ----------
266 	acpi_namespace_write - handle write() calls
267 ----- */
268 
269 static status_t
270 acpi_namespace_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes)
271 {
272 	*num_bytes = 0;				/* tell caller nothing was written */
273 	return B_IO_ERROR;
274 }
275 
276 
277 /* ----------
278 	acpi_namespace_control - handle ioctl calls
279 ----- */
280 
281 static status_t
282 acpi_namespace_control(void* cookie, uint32 op, void* arg, size_t len)
283 {
284 	dprintf("acpi_ns_dump: device_control\n");
285 	return B_DEV_INVALID_IOCTL;
286 }
287 
288 
289 /* ----------
290 	acpi_namespace_close - handle close() calls
291 ----- */
292 
293 static status_t
294 acpi_namespace_close(void* cookie)
295 {
296 	dprintf("acpi_ns_dump: device_close\n");
297 	return B_OK;
298 }
299 
300 
301 /* -----
302 	acpi_namespace_free - called after the last device is closed, and after
303 	all i/o is complete.
304 ----- */
305 static status_t
306 acpi_namespace_free(void* cookie)
307 {
308 	status_t status;
309 	acpi_ns_device_info *device = (acpi_ns_device_info *)cookie;
310 	dprintf("acpi_ns_dump: device_free\n");
311 
312 	if (device->read_sem >= 0)
313 		delete_sem(device->read_sem);
314 
315 	device->buffer->DestroyLock();
316 	wait_for_thread(device->thread, &status);
317 	delete device->buffer;
318 
319 	return B_OK;
320 }
321 
322 
323 //	#pragma mark - device module API
324 
325 
326 static status_t
327 acpi_namespace_init_device(void *_cookie, void **cookie)
328 {
329 	device_node *node = (device_node *)_cookie;
330 	status_t err;
331 
332 	acpi_ns_device_info *device = (acpi_ns_device_info *)calloc(1, sizeof(*device));
333 	if (device == NULL)
334 		return B_NO_MEMORY;
335 
336 	device->node = node;
337 	err = gDeviceManager->get_driver(node, (driver_module_info **)&device->acpi,
338 		(void **)&device->acpi_cookie);
339 	if (err != B_OK) {
340 		free(device);
341 		return err;
342 	}
343 
344 	*cookie = device;
345 	return B_OK;
346 }
347 
348 
349 static void
350 acpi_namespace_uninit_device(void *_cookie)
351 {
352 	acpi_ns_device_info *device = (acpi_ns_device_info *)_cookie;
353 	free(device);
354 }
355 
356 }
357 
358 struct device_module_info acpi_ns_dump_module = {
359 	{
360 		ACPI_NS_DUMP_DEVICE_MODULE_NAME,
361 		0,
362 		NULL
363 	},
364 
365 	acpi_namespace_init_device,
366 	acpi_namespace_uninit_device,
367 	NULL,
368 
369 	acpi_namespace_open,
370 	acpi_namespace_close,
371 	acpi_namespace_free,
372 	acpi_namespace_read,
373 	acpi_namespace_write,
374 	NULL,
375 	acpi_namespace_control,
376 
377 	NULL,
378 	NULL
379 };
380 
381 
382 RingBuffer::RingBuffer(size_t size)
383 {
384 	fBuffer = create_ring_buffer(size);
385 	fLock = create_sem(1, "ring buffer lock");
386 }
387 
388 
389 RingBuffer::~RingBuffer()
390 {
391 	delete_ring_buffer(fBuffer);
392 }
393 
394 
395 size_t
396 RingBuffer::Read(void *buffer, ssize_t size)
397 {
398 	if (IS_USER_ADDRESS(buffer))
399 		return ring_buffer_user_read(fBuffer, (uint8*)buffer, size);
400 	else
401 		return ring_buffer_read(fBuffer, (uint8*)buffer, size);
402 }
403 
404 
405 size_t
406 RingBuffer::Write(const void *buffer, ssize_t size)
407 {
408 	return ring_buffer_write(fBuffer, (uint8*)buffer, size);
409 }
410 
411 
412 size_t
413 RingBuffer::ReadableAmount() const
414 {
415 	return ring_buffer_readable(fBuffer);
416 }
417 
418 
419 size_t
420 RingBuffer::WritableAmount() const
421 {
422 	return ring_buffer_writable(fBuffer);
423 }
424 
425 
426 bool
427 RingBuffer::Lock()
428 {
429 	//status_t status = acquire_sem_etc(fLock, 1, B_CAN_INTERRUPT, 0);
430 	status_t status = acquire_sem(fLock);
431 	return status == B_OK;
432 }
433 
434 
435 void
436 RingBuffer::Unlock()
437 {
438 	release_sem(fLock);
439 }
440 
441 
442 void
443 RingBuffer::DestroyLock()
444 {
445 	delete_sem(fLock);
446 }
447 
448