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