xref: /haiku/src/add-ons/kernel/drivers/power/acpi_ac/acpi_ac.cpp (revision 9c274ccd098ee3b2674efde2d1582d4e0c68d878)
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 	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 
124 static status_t
125 acpi_ac_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes)
126 {
127 	return B_ERROR;
128 }
129 
130 
131 static status_t
132 acpi_ac_control(void* _cookie, uint32 op, void* arg, size_t len)
133 {
134 	return B_ERROR;
135 }
136 
137 
138 static status_t
139 acpi_ac_close (void* cookie)
140 {
141 	return B_OK;
142 }
143 
144 
145 static status_t
146 acpi_ac_free (void* cookie)
147 {
148 	return B_OK;
149 }
150 
151 
152 //	#pragma mark - driver module API
153 
154 
155 static float
156 acpi_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 
188 static status_t
189 acpi_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 
201 static status_t
202 acpi_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 
234 static void
235 acpi_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 
246 static status_t
247 acpi_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 
266 module_dependency module_dependencies[] = {
267 	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager },
268 	{}
269 };
270 
271 
272 driver_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 
289 struct 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 
312 module_info *modules[] = {
313 	(module_info *)&acpi_ac_driver_module,
314 	(module_info *)&acpi_ac_device_module,
315 	NULL
316 };
317