xref: /haiku/src/add-ons/kernel/drivers/sensor/acpi_als/acpi_als.cpp (revision c237c4ce593ee823d9867fd997e51e4c447f5623)
1 /*
2  * Copyright 2020, Jérôme Duval, jerome.duval@gmail.com.
3  * Distributed under the terms of the MIT license.
4  */
5 
6 
7 #include <ACPI.h>
8 #include <condition_variable.h>
9 #include <Drivers.h>
10 #include <Errors.h>
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 
16 #include <kernel.h>
17 
18 
19 extern "C" {
20 #	include "acpi.h"
21 }
22 
23 
24 struct als_driver_cookie {
25 	device_node*				node;
26 	acpi_device_module_info*	acpi;
27 	acpi_device					acpi_cookie;
28 };
29 
30 
31 struct als_device_cookie {
32 	als_driver_cookie*		driver_cookie;
33 	int32					stop_watching;
34 };
35 
36 
37 #define ACPI_ALS_DRIVER_NAME "drivers/sensor/acpi_als/driver_v1"
38 #define ACPI_ALS_DEVICE_NAME "drivers/sensor/acpi_als/device_v1"
39 
40 /* Base Namespace devices are published to */
41 #define ACPI_ALS_BASENAME "sensor/acpi_als/%d"
42 
43 // name of pnp generator of path ids
44 #define ACPI_ALS_PATHID_GENERATOR "acpi_als/path_id"
45 
46 #define ACPI_NAME_ALS "ACPI0008"
47 
48 #define TRACE_ALS
49 #ifdef TRACE_ALS
50 #	define TRACE(x...) dprintf("acpi_als: " x)
51 #else
52 #	define TRACE(x...)
53 #endif
54 #define ERROR(x...) dprintf("acpi_als: " x)
55 
56 
57 static device_manager_info *sDeviceManager;
58 static ConditionVariable sALSCondition;
59 
60 
61 static status_t
62 acpi_GetInteger(als_driver_cookie *device,
63 	const char* path, uint64* number)
64 {
65 	acpi_data buf;
66 	acpi_object_type object;
67 	buf.pointer = &object;
68 	buf.length = sizeof(acpi_object_type);
69 
70 	// Assume that what we've been pointed at is an Integer object, or
71 	// a method that will return an Integer.
72 	status_t status = device->acpi->evaluate_method(device->acpi_cookie, path,
73 		NULL, &buf);
74 	if (status == B_OK) {
75 		if (object.object_type == ACPI_TYPE_INTEGER)
76 			*number = object.integer.integer;
77 		else
78 			status = B_BAD_VALUE;
79 	}
80 	return status;
81 }
82 
83 
84 void
85 als_notify_handler(acpi_handle device, uint32 value, void *context)
86 {
87 	TRACE("als_notify_handler event 0x%" B_PRIx32 "\n", value);
88 	sALSCondition.NotifyAll();
89 }
90 
91 
92 //	#pragma mark - device module API
93 
94 
95 static status_t
96 acpi_als_init_device(void *driverCookie, void **cookie)
97 {
98 	*cookie = driverCookie;
99 	return B_OK;
100 }
101 
102 
103 static void
104 acpi_als_uninit_device(void *_cookie)
105 {
106 
107 }
108 
109 
110 static status_t
111 acpi_als_open(void *initCookie, const char *path, int flags, void** cookie)
112 {
113 	als_device_cookie *device;
114 	device = (als_device_cookie*)calloc(1, sizeof(als_device_cookie));
115 	if (device == NULL)
116 		return B_NO_MEMORY;
117 
118 	device->driver_cookie = (als_driver_cookie*)initCookie;
119 	device->stop_watching = 0;
120 
121 	*cookie = device;
122 
123 	return B_OK;
124 }
125 
126 
127 static status_t
128 acpi_als_close(void* cookie)
129 {
130 	return B_OK;
131 }
132 
133 
134 static status_t
135 acpi_als_read(void* _cookie, off_t position, void *buffer, size_t* numBytes)
136 {
137 	if (*numBytes < 1)
138 		return B_IO_ERROR;
139 
140 	als_device_cookie *device = (als_device_cookie*)_cookie;
141 
142 	if (position == 0) {
143 		char string[10];
144 		uint64 luminance = 0;
145 		status_t status = acpi_GetInteger(device->driver_cookie,
146 			"_ALI", &luminance);
147 		if (status != B_OK)
148 			return B_ERROR;
149 		snprintf(string, sizeof(string), "%" B_PRIu64 "\n", luminance);
150 		size_t max_len = user_strlcpy((char*)buffer, string, *numBytes);
151 		if (max_len < B_OK)
152 			return B_BAD_ADDRESS;
153 		*numBytes = max_len;
154 	} else
155 		*numBytes = 0;
156 
157 	return B_OK;
158 }
159 
160 
161 static status_t
162 acpi_als_write(void* cookie, off_t position, const void* buffer,
163 	size_t* numBytes)
164 {
165 	return B_ERROR;
166 }
167 
168 
169 static status_t
170 acpi_als_control(void* _cookie, uint32 op, void* arg, size_t len)
171 {
172 	//als_device_cookie* device = (als_device_cookie*)_cookie;
173 
174 	return B_DEV_INVALID_IOCTL;
175 }
176 
177 
178 static status_t
179 acpi_als_free(void* cookie)
180 {
181 	als_device_cookie* device = (als_device_cookie*)cookie;
182 	free(device);
183 	return B_OK;
184 }
185 
186 
187 //	#pragma mark - driver module API
188 
189 
190 static float
191 acpi_als_support(device_node *parent)
192 {
193 	// make sure parent is really the ACPI bus manager
194 	const char *bus;
195 	if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
196 		return -1;
197 
198 	if (strcmp(bus, "acpi"))
199 		return 0.0;
200 
201 	// check whether it's really a device
202 	uint32 device_type;
203 	if (sDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM,
204 			&device_type, false) != B_OK
205 		|| device_type != ACPI_TYPE_DEVICE) {
206 		return 0.0;
207 	}
208 
209 	// check whether it's a als device
210 	const char *name;
211 	if (sDeviceManager->get_attr_string(parent, ACPI_DEVICE_HID_ITEM, &name,
212 		false) != B_OK || strcmp(name, ACPI_NAME_ALS)) {
213 		return 0.0;
214 	}
215 
216 	return 0.6;
217 }
218 
219 
220 static status_t
221 acpi_als_register_device(device_node *node)
222 {
223 	device_attr attrs[] = {
224 		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { .string = "ACPI ALS" }},
225 		{ NULL }
226 	};
227 
228 	return sDeviceManager->register_node(node, ACPI_ALS_DRIVER_NAME, attrs,
229 		NULL, NULL);
230 }
231 
232 
233 static status_t
234 acpi_als_init_driver(device_node *node, void **driverCookie)
235 {
236 	als_driver_cookie *device;
237 	device = (als_driver_cookie *)calloc(1, sizeof(als_driver_cookie));
238 	if (device == NULL)
239 		return B_NO_MEMORY;
240 
241 	*driverCookie = device;
242 
243 	device->node = node;
244 
245 	device_node *parent;
246 	parent = sDeviceManager->get_parent_node(node);
247 	sDeviceManager->get_driver(parent, (driver_module_info **)&device->acpi,
248 		(void **)&device->acpi_cookie);
249 
250 #ifdef TRACE_ALS
251 	const char* device_path;
252 	if (sDeviceManager->get_attr_string(parent, ACPI_DEVICE_PATH_ITEM,
253 		&device_path, false) == B_OK) {
254 		TRACE("acpi_als_init_driver %s\n", device_path);
255 	}
256 #endif
257 
258 	sDeviceManager->put_node(parent);
259 
260 	uint64 sta;
261 	status_t status = acpi_GetInteger(device, "_STA", &sta);
262 	uint64 mask = ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED
263 		| ACPI_STA_DEVICE_FUNCTIONING;
264 	if (status == B_OK && (sta & mask) != mask) {
265 		ERROR("acpi_als_init_driver device disabled\n");
266 		return B_ERROR;
267 	}
268 
269 	uint64 luminance;
270 	status = acpi_GetInteger(device, "_ALI", &luminance);
271 	if (status != B_OK) {
272 		ERROR("acpi_als_init_driver error when calling _ALI\n");
273 		return B_ERROR;
274 	}
275 
276 	// install notify handler
277 	device->acpi->install_notify_handler(device->acpi_cookie,
278 		ACPI_ALL_NOTIFY, als_notify_handler, device);
279 
280 	return B_OK;
281 }
282 
283 
284 static void
285 acpi_als_uninit_driver(void *driverCookie)
286 {
287 	TRACE("acpi_als_uninit_driver\n");
288 	als_driver_cookie *device = (als_driver_cookie*)driverCookie;
289 
290 	device->acpi->remove_notify_handler(device->acpi_cookie,
291 		ACPI_ALL_NOTIFY, als_notify_handler);
292 
293 	free(device);
294 }
295 
296 
297 static status_t
298 acpi_als_register_child_devices(void *cookie)
299 {
300 	als_driver_cookie *device = (als_driver_cookie*)cookie;
301 
302 	int pathID = sDeviceManager->create_id(ACPI_ALS_PATHID_GENERATOR);
303 	if (pathID < 0) {
304 		ERROR("register_child_devices: couldn't create a path_id\n");
305 		return B_ERROR;
306 	}
307 
308 	char name[128];
309 	snprintf(name, sizeof(name), ACPI_ALS_BASENAME, pathID);
310 
311 	return sDeviceManager->publish_device(device->node, name,
312 		ACPI_ALS_DEVICE_NAME);
313 }
314 
315 
316 
317 
318 
319 
320 module_dependency module_dependencies[] = {
321 	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager },
322 	{}
323 };
324 
325 
326 driver_module_info acpi_als_driver_module = {
327 	{
328 		ACPI_ALS_DRIVER_NAME,
329 		0,
330 		NULL
331 	},
332 
333 	acpi_als_support,
334 	acpi_als_register_device,
335 	acpi_als_init_driver,
336 	acpi_als_uninit_driver,
337 	acpi_als_register_child_devices,
338 	NULL,	// rescan
339 	NULL,	// removed
340 };
341 
342 
343 struct device_module_info acpi_als_device_module = {
344 	{
345 		ACPI_ALS_DEVICE_NAME,
346 		0,
347 		NULL
348 	},
349 
350 	acpi_als_init_device,
351 	acpi_als_uninit_device,
352 	NULL,
353 
354 	acpi_als_open,
355 	acpi_als_close,
356 	acpi_als_free,
357 	acpi_als_read,
358 	acpi_als_write,
359 	NULL,
360 	acpi_als_control,
361 
362 	NULL,
363 	NULL
364 };
365 
366 module_info *modules[] = {
367 	(module_info *)&acpi_als_driver_module,
368 	(module_info *)&acpi_als_device_module,
369 	NULL
370 };
371