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
24class RingBuffer {
25public:
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();
36private:
37	ring_buffer *fBuffer;
38	sem_id fLock;
39};
40
41
42typedef 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
54static bool
55make_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
80static void
81dump_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, 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
177static int32
178acpi_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
189extern "C" {
190/* ----------
191	acpi_namespace_open - handle open() calls
192----- */
193
194static status_t
195acpi_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----- */
232static status_t
233acpi_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
267static status_t
268acpi_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
279static status_t
280acpi_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
291static status_t
292acpi_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----- */
303static status_t
304acpi_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
324static status_t
325acpi_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
347static void
348acpi_namespace_uninit_device(void *_cookie)
349{
350	acpi_ns_device_info *device = (acpi_ns_device_info *)_cookie;
351	free(device);
352}
353
354}
355
356struct 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
380RingBuffer::RingBuffer(size_t size)
381{
382	fBuffer = create_ring_buffer(size);
383	fLock = create_sem(1, "ring buffer lock");
384}
385
386
387RingBuffer::~RingBuffer()
388{
389	delete_ring_buffer(fBuffer);
390}
391
392
393size_t
394RingBuffer::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
403size_t
404RingBuffer::Write(const void *buffer, ssize_t size)
405{
406	return ring_buffer_write(fBuffer, (uint8*)buffer, size);
407}
408
409
410size_t
411RingBuffer::ReadableAmount() const
412{
413	return ring_buffer_readable(fBuffer);
414}
415
416
417size_t
418RingBuffer::WritableAmount() const
419{
420	return ring_buffer_writable(fBuffer);
421}
422
423
424bool
425RingBuffer::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
433void
434RingBuffer::Unlock()
435{
436	release_sem(fLock);
437}
438
439
440void
441RingBuffer::DestroyLock()
442{
443	delete_sem(fLock);
444}
445
446