xref: /haiku/src/add-ons/kernel/drivers/power/acpi_ac/acpi_ac.cpp (revision 958b83c3ed45e0e599e7dc0bc7f5841d4d9c03e5)
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 
33 static device_manager_info *sDeviceManager;
34 
35 
36 typedef 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 
44 static void
45 acpi_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 
64 static void
65 acpi_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 
80 static status_t
81 acpi_ac_init_device(void *driverCookie, void **cookie)
82 {
83 	*cookie = driverCookie;
84 	return B_OK;
85 }
86 
87 
88 static void
89 acpi_ac_uninit_device(void *_cookie)
90 {
91 
92 }
93 
94 
95 static status_t
96 acpi_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 
104 static status_t
105 acpi_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 	*((uint8 *)(buf)) = device->last_status;
112 
113 	*num_bytes = 1;
114 	return B_OK;
115 }
116 
117 
118 static status_t
119 acpi_ac_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes)
120 {
121 	return B_ERROR;
122 }
123 
124 
125 static status_t
126 acpi_ac_control(void* _cookie, uint32 op, void* arg, size_t len)
127 {
128 	return B_ERROR;
129 }
130 
131 
132 static status_t
133 acpi_ac_close (void* cookie)
134 {
135 	return B_OK;
136 }
137 
138 
139 static status_t
140 acpi_ac_free (void* cookie)
141 {
142 	return B_OK;
143 }
144 
145 
146 //	#pragma mark - driver module API
147 
148 
149 static float
150 acpi_ac_support(device_node *parent)
151 {
152 	const char *bus;
153 	uint32 device_type;
154 	const char *hid;
155 
156 	// make sure parent is really the ACPI bus manager
157 	if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
158 		return -1;
159 
160 	if (strcmp(bus, "acpi"))
161 		return 0.0;
162 
163 	// check whether it's really a device
164 	if (sDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM,
165 			&device_type, false) != B_OK
166 		|| device_type != ACPI_TYPE_DEVICE) {
167 		return 0.0;
168 	}
169 
170 	// check whether it's an ac device
171 	if (sDeviceManager->get_attr_string(parent, ACPI_DEVICE_HID_ITEM, &hid,
172 		false) != B_OK || strcmp(hid, "ACPI0003")) {
173 		return 0.0;
174 	}
175 
176 	dprintf("acpi_ac_support ac device found\n");
177 
178 	return 0.6;
179 }
180 
181 
182 static status_t
183 acpi_ac_register_device(device_node *node)
184 {
185 	device_attr attrs[] = {
186 		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { .string = "ACPI AC" }},
187 		{ NULL }
188 	};
189 
190 	return sDeviceManager->register_node(node, ACPI_AC_MODULE_NAME, attrs,
191 		NULL, NULL);
192 }
193 
194 
195 static status_t
196 acpi_ac_init_driver(device_node *node, void **_driverCookie)
197 {
198 	acpi_ac_device_info *device;
199 	device_node *parent;
200 	status_t status;
201 
202 	device = (acpi_ac_device_info *)calloc(1, sizeof(*device));
203 	if (device == NULL)
204 		return B_NO_MEMORY;
205 
206 	device->node = node;
207 
208 	parent = sDeviceManager->get_parent_node(node);
209 	sDeviceManager->get_driver(parent, (driver_module_info **)&device->acpi,
210 		(void **)&device->acpi_cookie);
211 	sDeviceManager->put_node(parent);
212 
213 	status = device->acpi->install_notify_handler(device->acpi_cookie,
214 		ACPI_DEVICE_NOTIFY, acpi_ac_notify_handler, device);
215 	if (status != B_OK) {
216 		ERROR("can't install notify handler\n");
217 	}
218 
219 	device->last_status = 0;
220 
221 	acpi_ac_update_status(device);
222 
223 	*_driverCookie = device;
224 	return B_OK;
225 }
226 
227 
228 static void
229 acpi_ac_uninit_driver(void *driverCookie)
230 {
231 	acpi_ac_device_info *device = (acpi_ac_device_info *)driverCookie;
232 
233 	device->acpi->remove_notify_handler(device->acpi_cookie,
234 		ACPI_DEVICE_NOTIFY, acpi_ac_notify_handler);
235 
236 	free(device);
237 }
238 
239 
240 static status_t
241 acpi_ac_register_child_devices(void *driverCookie)
242 {
243 	acpi_ac_device_info *device = (acpi_ac_device_info *)driverCookie;
244 	int path_id;
245 	char name[128];
246 
247 	path_id = sDeviceManager->create_id(ACPI_AC_PATHID_GENERATOR);
248 	if (path_id < 0) {
249 		ERROR("register_child_devices: couldn't create a path_id\n");
250 		return B_ERROR;
251 	}
252 
253 	snprintf(name, sizeof(name), ACPI_AC_BASENAME, path_id);
254 
255 	return sDeviceManager->publish_device(device->node, name,
256 		ACPI_AC_DEVICE_MODULE_NAME);
257 }
258 
259 
260 module_dependency module_dependencies[] = {
261 	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager },
262 	{}
263 };
264 
265 
266 driver_module_info acpi_ac_driver_module = {
267 	{
268 		ACPI_AC_MODULE_NAME,
269 		0,
270 		NULL
271 	},
272 
273 	acpi_ac_support,
274 	acpi_ac_register_device,
275 	acpi_ac_init_driver,
276 	acpi_ac_uninit_driver,
277 	acpi_ac_register_child_devices,
278 	NULL,	// rescan
279 	NULL,	// removed
280 };
281 
282 
283 struct device_module_info acpi_ac_device_module = {
284 	{
285 		ACPI_AC_DEVICE_MODULE_NAME,
286 		0,
287 		NULL
288 	},
289 
290 	acpi_ac_init_device,
291 	acpi_ac_uninit_device,
292 	NULL,
293 
294 	acpi_ac_open,
295 	acpi_ac_close,
296 	acpi_ac_free,
297 	acpi_ac_read,
298 	acpi_ac_write,
299 	NULL,
300 	acpi_ac_control,
301 
302 	NULL,
303 	NULL
304 };
305 
306 module_info *modules[] = {
307 	(module_info *)&acpi_ac_driver_module,
308 	(module_info *)&acpi_ac_device_module,
309 	NULL
310 };
311