1/*
2 * Copyright 2013, J��r��me Duval, korli@users.berlios.de.
3 *
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include <ACPI.h>
9
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13
14
15#define ACPI_AC_MODULE_NAME "drivers/power/acpi_ac/driver_v1"
16
17#define ACPI_AC_DEVICE_MODULE_NAME "drivers/power/acpi_ac/device_v1"
18
19/* Base Namespace devices are published to */
20#define ACPI_AC_BASENAME "power/acpi_ac/%d"
21
22// name of pnp generator of path ids
23#define ACPI_AC_PATHID_GENERATOR "acpi_ac/path_id"
24
25#define TRACE_AC
26#ifdef TRACE_AC
27#	define TRACE(x...) dprintf("acpi_ac: " x)
28#else
29#	define TRACE(x...)
30#endif
31#define ERROR(x...)	dprintf("acpi_ac: " x)
32
33static device_manager_info *sDeviceManager;
34
35
36typedef struct acpi_ns_device_info {
37	device_node *node;
38	acpi_device_module_info *acpi;
39	acpi_device acpi_cookie;
40	uint8 last_status;
41} acpi_ac_device_info;
42
43
44static void
45acpi_ac_update_status(acpi_ac_device_info* device)
46{
47	acpi_data buf;
48	buf.pointer = NULL;
49	buf.length = ACPI_ALLOCATE_BUFFER;
50
51	if (device->acpi->evaluate_method(device->acpi_cookie, "_PSR", NULL, &buf) != B_OK
52		|| buf.pointer == NULL
53		|| ((acpi_object_type*)buf.pointer)->object_type != ACPI_TYPE_INTEGER) {
54		ERROR("couldn't get status\n");
55	} else {
56		acpi_object_type* object = (acpi_object_type*)buf.pointer;
57		device->last_status = object->integer.integer;
58		TRACE("status %d\n", device->last_status);
59	}
60	free(buf.pointer);
61}
62
63
64static void
65acpi_ac_notify_handler(acpi_handle device, uint32 value, void *context)
66{
67	if (value != 0x80) {
68		dprintf("acpi_ac: unknown notification (%d)\n", value);
69		return;
70	}
71
72	acpi_ac_device_info* dev = (acpi_ac_device_info*) context;
73	acpi_ac_update_status(dev);
74}
75
76
77//	#pragma mark - device module API
78
79
80static status_t
81acpi_ac_init_device(void *driverCookie, void **cookie)
82{
83	*cookie = driverCookie;
84	return B_OK;
85}
86
87
88static void
89acpi_ac_uninit_device(void *_cookie)
90{
91
92}
93
94
95static status_t
96acpi_ac_open(void *_cookie, const char *path, int flags, void** cookie)
97{
98	acpi_ac_device_info *device = (acpi_ac_device_info *)_cookie;
99	*cookie = device;
100	return B_OK;
101}
102
103
104static status_t
105acpi_ac_read(void* _cookie, off_t position, void *buf, size_t* num_bytes)
106{
107	acpi_ac_device_info* device = (acpi_ac_device_info*)_cookie;
108	if (*num_bytes < 1)
109		return B_IO_ERROR;
110
111	if (position > 0) {
112		*num_bytes = 0;
113		return B_OK;
114	}
115
116	if (user_memcpy(buf, &device->last_status, sizeof(uint8)) < B_OK)
117		return B_BAD_ADDRESS;
118
119	*num_bytes = 1;
120	return B_OK;
121}
122
123
124static status_t
125acpi_ac_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes)
126{
127	return B_ERROR;
128}
129
130
131static status_t
132acpi_ac_control(void* _cookie, uint32 op, void* arg, size_t len)
133{
134	return B_ERROR;
135}
136
137
138static status_t
139acpi_ac_close (void* cookie)
140{
141	return B_OK;
142}
143
144
145static status_t
146acpi_ac_free (void* cookie)
147{
148	return B_OK;
149}
150
151
152//	#pragma mark - driver module API
153
154
155static float
156acpi_ac_support(device_node *parent)
157{
158	const char *bus;
159	uint32 device_type;
160	const char *hid;
161
162	// make sure parent is really the ACPI bus manager
163	if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
164		return -1;
165
166	if (strcmp(bus, "acpi"))
167		return 0.0;
168
169	// check whether it's really a device
170	if (sDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM,
171			&device_type, false) != B_OK
172		|| device_type != ACPI_TYPE_DEVICE) {
173		return 0.0;
174	}
175
176	// check whether it's an ac device
177	if (sDeviceManager->get_attr_string(parent, ACPI_DEVICE_HID_ITEM, &hid,
178		false) != B_OK || strcmp(hid, "ACPI0003")) {
179		return 0.0;
180	}
181
182	dprintf("acpi_ac_support ac device found\n");
183
184	return 0.6;
185}
186
187
188static status_t
189acpi_ac_register_device(device_node *node)
190{
191	device_attr attrs[] = {
192		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { .string = "ACPI AC" }},
193		{ NULL }
194	};
195
196	return sDeviceManager->register_node(node, ACPI_AC_MODULE_NAME, attrs,
197		NULL, NULL);
198}
199
200
201static status_t
202acpi_ac_init_driver(device_node *node, void **_driverCookie)
203{
204	acpi_ac_device_info *device;
205	device_node *parent;
206	status_t status;
207
208	device = (acpi_ac_device_info *)calloc(1, sizeof(*device));
209	if (device == NULL)
210		return B_NO_MEMORY;
211
212	device->node = node;
213
214	parent = sDeviceManager->get_parent_node(node);
215	sDeviceManager->get_driver(parent, (driver_module_info **)&device->acpi,
216		(void **)&device->acpi_cookie);
217	sDeviceManager->put_node(parent);
218
219	status = device->acpi->install_notify_handler(device->acpi_cookie,
220		ACPI_DEVICE_NOTIFY, acpi_ac_notify_handler, device);
221	if (status != B_OK) {
222		ERROR("can't install notify handler\n");
223	}
224
225	device->last_status = 0;
226
227	acpi_ac_update_status(device);
228
229	*_driverCookie = device;
230	return B_OK;
231}
232
233
234static void
235acpi_ac_uninit_driver(void *driverCookie)
236{
237	acpi_ac_device_info *device = (acpi_ac_device_info *)driverCookie;
238
239	device->acpi->remove_notify_handler(device->acpi_cookie,
240		ACPI_DEVICE_NOTIFY, acpi_ac_notify_handler);
241
242	free(device);
243}
244
245
246static status_t
247acpi_ac_register_child_devices(void *driverCookie)
248{
249	acpi_ac_device_info *device = (acpi_ac_device_info *)driverCookie;
250	int path_id;
251	char name[128];
252
253	path_id = sDeviceManager->create_id(ACPI_AC_PATHID_GENERATOR);
254	if (path_id < 0) {
255		ERROR("register_child_devices: couldn't create a path_id\n");
256		return B_ERROR;
257	}
258
259	snprintf(name, sizeof(name), ACPI_AC_BASENAME, path_id);
260
261	return sDeviceManager->publish_device(device->node, name,
262		ACPI_AC_DEVICE_MODULE_NAME);
263}
264
265
266module_dependency module_dependencies[] = {
267	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager },
268	{}
269};
270
271
272driver_module_info acpi_ac_driver_module = {
273	{
274		ACPI_AC_MODULE_NAME,
275		0,
276		NULL
277	},
278
279	acpi_ac_support,
280	acpi_ac_register_device,
281	acpi_ac_init_driver,
282	acpi_ac_uninit_driver,
283	acpi_ac_register_child_devices,
284	NULL,	// rescan
285	NULL,	// removed
286};
287
288
289struct device_module_info acpi_ac_device_module = {
290	{
291		ACPI_AC_DEVICE_MODULE_NAME,
292		0,
293		NULL
294	},
295
296	acpi_ac_init_device,
297	acpi_ac_uninit_device,
298	NULL,
299
300	acpi_ac_open,
301	acpi_ac_close,
302	acpi_ac_free,
303	acpi_ac_read,
304	acpi_ac_write,
305	NULL,
306	acpi_ac_control,
307
308	NULL,
309	NULL
310};
311
312module_info *modules[] = {
313	(module_info *)&acpi_ac_driver_module,
314	(module_info *)&acpi_ac_device_module,
315	NULL
316};
317