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