xref: /haiku/src/add-ons/kernel/bus_managers/acpi/NamespaceDump.cpp (revision e1c4049fed1047bdb957b0529e1921e97ef94770)
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 	for (i = 0; i < indenting; i++)
88 		strlcat(tabs, "|    ", sizeof(tabs));
89 
90 	strlcat(tabs, "|--- ", sizeof(tabs));
91 
92 	int depth = sizeof(char) * 5 * indenting + sizeof(char); // index into result where the device name will be.
93 
94 	void *counter = NULL;
95 	while (device->acpi->get_next_entry(ACPI_TYPE_ANY, root, result, 255, &counter) == B_OK) {
96 		uint32 type = device->acpi->get_object_type(result);
97 		snprintf(output, sizeof(output), "%s%s", tabs, result + depth);
98 		switch(type) {
99 			case ACPI_TYPE_INTEGER:
100 				strlcat(output, "     INTEGER", sizeof(output));
101 				break;
102 			case ACPI_TYPE_STRING:
103 				strlcat(output, "     STRING", sizeof(output));
104 				break;
105 			case ACPI_TYPE_BUFFER:
106 				strlcat(output, "     BUFFER", sizeof(output));
107 				break;
108 			case ACPI_TYPE_PACKAGE:
109 				strlcat(output, "     PACKAGE", sizeof(output));
110 				break;
111 			case ACPI_TYPE_FIELD_UNIT:
112 				strlcat(output, "     FIELD UNIT", sizeof(output));
113 				break;
114 			case ACPI_TYPE_DEVICE:
115 			{
116 				char* hid = NULL;
117 				device->acpi->get_device_info(result, &hid, NULL, 0, NULL);
118 				strlcat(output, "     DEVICE (", sizeof(output));
119 				if (hid != NULL) {
120 					strlcat(output, hid, sizeof(output));
121 					free(hid);
122 				} else
123 					strlcat(output, "none", sizeof(output));
124 				strlcat(output, ")", sizeof(output));
125 				break;
126 			}
127 			case ACPI_TYPE_EVENT:
128 				strlcat(output, "     EVENT", sizeof(output));
129 				break;
130 			case ACPI_TYPE_METHOD:
131 				strlcat(output, "     METHOD", sizeof(output));
132 				break;
133 			case ACPI_TYPE_MUTEX:
134 				strlcat(output, "     MUTEX", sizeof(output));
135 				break;
136 			case ACPI_TYPE_REGION:
137 				strlcat(output, "     REGION", sizeof(output));
138 				break;
139 			case ACPI_TYPE_POWER:
140 				strlcat(output, "     POWER", sizeof(output));
141 				break;
142 			case ACPI_TYPE_PROCESSOR:
143 				strlcat(output, "     PROCESSOR", sizeof(output));
144 				break;
145 			case ACPI_TYPE_THERMAL:
146 				strlcat(output, "     THERMAL", sizeof(output));
147 				break;
148 			case ACPI_TYPE_BUFFER_FIELD:
149 				strlcat(output, "     BUFFER_FIELD", sizeof(output));
150 				break;
151 			case ACPI_TYPE_ANY:
152 			default:
153 				break;
154 		}
155 		RingBuffer &ringBuffer = *device->buffer;
156 		size_t toWrite = strlen(output);
157 
158 		if (toWrite == 0)
159 			break;
160 
161 		toWrite = strlcat(output, "\n", sizeof(output));
162 
163 		if (!ringBuffer.Lock())
164 			break;
165 
166 		if (ringBuffer.WritableAmount() < toWrite &&
167 			!make_space(device, toWrite))
168 			break;
169 
170 		ringBuffer.Write(output, toWrite);
171 		ringBuffer.Unlock();
172 		dump_acpi_namespace(device, result, indenting + 1);
173 	}
174 }
175 
176 
177 static int32
178 acpi_namespace_dump(void *arg)
179 {
180 	acpi_ns_device_info *device = (acpi_ns_device_info*)(arg);
181 	dump_acpi_namespace(device, NULL, 0);
182 
183 	delete_sem(device->read_sem);
184 	device->read_sem = -1;
185 
186 	return 0;
187 }
188 
189 extern "C" {
190 /* ----------
191 	acpi_namespace_open - handle open() calls
192 ----- */
193 
194 static status_t
195 acpi_namespace_open(void *_cookie, const char* path, int flags, void** cookie)
196 {
197 	acpi_ns_device_info *device = (acpi_ns_device_info *)_cookie;
198 
199 	dprintf("\nacpi_ns_dump: device_open\n");
200 
201 	*cookie = device;
202 
203 	RingBuffer *ringBuffer = new RingBuffer(1024);
204 	if (ringBuffer == NULL)
205 		return B_NO_MEMORY;
206 
207 	device->read_sem = create_sem(0, "read_sem");
208 	if (device->read_sem < B_OK) {
209 		delete ringBuffer;
210 		return device->read_sem;
211 	}
212 
213 	device->thread = spawn_kernel_thread(acpi_namespace_dump, "acpi dumper",
214 		 B_NORMAL_PRIORITY, device);
215 	if (device->thread < 0) {
216 		delete ringBuffer;
217 		delete_sem(device->read_sem);
218 		return device->thread;
219 	}
220 
221 	device->buffer = ringBuffer;
222 
223 	resume_thread(device->thread);
224 
225 	return B_OK;
226 }
227 
228 
229 /* ----------
230 	acpi_namespace_read - handle read() calls
231 ----- */
232 static status_t
233 acpi_namespace_read(void *_cookie, off_t position, void *buf, size_t* num_bytes)
234 {
235 	acpi_ns_device_info *device = (acpi_ns_device_info *)_cookie;
236 	RingBuffer &ringBuffer = *device->buffer;
237 
238 	if (!ringBuffer.Lock()) {
239 		*num_bytes = 0;
240 		return B_ERROR;
241 	}
242 
243 	if (ringBuffer.ReadableAmount() == 0) {
244 		ringBuffer.Unlock();
245 		status_t status = acquire_sem_etc(device->read_sem, 1, B_CAN_INTERRUPT, 0);
246 		if (status != B_OK && status != B_BAD_SEM_ID) {
247 			*num_bytes = 0;
248 			return status;
249 		}
250 		if (!ringBuffer.Lock()) {
251 			*num_bytes = 0;
252 			return B_ERROR;
253 		}
254 	}
255 
256 	*num_bytes = ringBuffer.Read(buf, *num_bytes);
257 	ringBuffer.Unlock();
258 
259 	return B_OK;
260 }
261 
262 
263 /* ----------
264 	acpi_namespace_write - handle write() calls
265 ----- */
266 
267 static status_t
268 acpi_namespace_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes)
269 {
270 	*num_bytes = 0;				/* tell caller nothing was written */
271 	return B_IO_ERROR;
272 }
273 
274 
275 /* ----------
276 	acpi_namespace_control - handle ioctl calls
277 ----- */
278 
279 static status_t
280 acpi_namespace_control(void* cookie, uint32 op, void* arg, size_t len)
281 {
282 	dprintf("acpi_ns_dump: device_control\n");
283 	return B_DEV_INVALID_IOCTL;
284 }
285 
286 
287 /* ----------
288 	acpi_namespace_close - handle close() calls
289 ----- */
290 
291 static status_t
292 acpi_namespace_close(void* cookie)
293 {
294 	dprintf("acpi_ns_dump: device_close\n");
295 	return B_OK;
296 }
297 
298 
299 /* -----
300 	acpi_namespace_free - called after the last device is closed, and after
301 	all i/o is complete.
302 ----- */
303 static status_t
304 acpi_namespace_free(void* cookie)
305 {
306 	status_t status;
307 	acpi_ns_device_info *device = (acpi_ns_device_info *)cookie;
308 	dprintf("acpi_ns_dump: device_free\n");
309 
310 	if (device->read_sem >= 0)
311 		delete_sem(device->read_sem);
312 
313 	device->buffer->DestroyLock();
314 	wait_for_thread(device->thread, &status);
315 	delete device->buffer;
316 
317 	return B_OK;
318 }
319 
320 
321 //	#pragma mark - device module API
322 
323 
324 static status_t
325 acpi_namespace_init_device(void *_cookie, void **cookie)
326 {
327 	device_node *node = (device_node *)_cookie;
328 	status_t err;
329 
330 	acpi_ns_device_info *device = (acpi_ns_device_info *)calloc(1, sizeof(*device));
331 	if (device == NULL)
332 		return B_NO_MEMORY;
333 
334 	device->node = node;
335 	err = gDeviceManager->get_driver(node, (driver_module_info **)&device->acpi,
336 		(void **)&device->acpi_cookie);
337 	if (err != B_OK) {
338 		free(device);
339 		return err;
340 	}
341 
342 	*cookie = device;
343 	return B_OK;
344 }
345 
346 
347 static void
348 acpi_namespace_uninit_device(void *_cookie)
349 {
350 	acpi_ns_device_info *device = (acpi_ns_device_info *)_cookie;
351 	free(device);
352 }
353 
354 }
355 
356 struct device_module_info acpi_ns_dump_module = {
357 	{
358 		ACPI_NS_DUMP_DEVICE_MODULE_NAME,
359 		0,
360 		NULL
361 	},
362 
363 	acpi_namespace_init_device,
364 	acpi_namespace_uninit_device,
365 	NULL,
366 
367 	acpi_namespace_open,
368 	acpi_namespace_close,
369 	acpi_namespace_free,
370 	acpi_namespace_read,
371 	acpi_namespace_write,
372 	NULL,
373 	acpi_namespace_control,
374 
375 	NULL,
376 	NULL
377 };
378 
379 
380 RingBuffer::RingBuffer(size_t size)
381 {
382 	fBuffer = create_ring_buffer(size);
383 	fLock = create_sem(1, "ring buffer lock");
384 }
385 
386 
387 RingBuffer::~RingBuffer()
388 {
389 	delete_ring_buffer(fBuffer);
390 }
391 
392 
393 size_t
394 RingBuffer::Read(void *buffer, ssize_t size)
395 {
396 	if (IS_USER_ADDRESS(buffer))
397 		return ring_buffer_user_read(fBuffer, (uint8*)buffer, size);
398 	else
399 		return ring_buffer_read(fBuffer, (uint8*)buffer, size);
400 }
401 
402 
403 size_t
404 RingBuffer::Write(const void *buffer, ssize_t size)
405 {
406 	return ring_buffer_write(fBuffer, (uint8*)buffer, size);
407 }
408 
409 
410 size_t
411 RingBuffer::ReadableAmount() const
412 {
413 	return ring_buffer_readable(fBuffer);
414 }
415 
416 
417 size_t
418 RingBuffer::WritableAmount() const
419 {
420 	return ring_buffer_writable(fBuffer);
421 }
422 
423 
424 bool
425 RingBuffer::Lock()
426 {
427 	//status_t status = acquire_sem_etc(fLock, 1, B_CAN_INTERRUPT, 0);
428 	status_t status = acquire_sem(fLock);
429 	return status == B_OK;
430 }
431 
432 
433 void
434 RingBuffer::Unlock()
435 {
436 	release_sem(fLock);
437 }
438 
439 
440 void
441 RingBuffer::DestroyLock()
442 {
443 	delete_sem(fLock);
444 }
445 
446