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