vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / drivers / power / acpi_lid / acpi_lid.cpp
blobe6ee5e2ac784114864ec14c3f9598a5ccebcc876
1 /*
2 * Copyright 2008-2013, Jérôme Duval, korli@users.berlios.de.
4 * Distributed under the terms of the MIT License.
5 */
8 #include <ACPI.h>
10 #include <fs/select_sync_pool.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
17 #define ACPI_LID_MODULE_NAME "drivers/power/acpi_lid/driver_v1"
19 #define ACPI_LID_DEVICE_MODULE_NAME "drivers/power/acpi_lid/device_v1"
21 #define ACPI_NOTIFY_STATUS_CHANGED 0x80
23 /* Base Namespace devices are published to */
24 #define ACPI_LID_BASENAME "power/acpi_lid/%d"
26 // name of pnp generator of path ids
27 #define ACPI_LID_PATHID_GENERATOR "acpi_lid/path_id"
29 //#define TRACE_LID
30 #ifdef TRACE_LID
31 # define TRACE(x...) dprintf("acpi_lid: "x)
32 #else
33 # define TRACE(x...)
34 #endif
35 #define ERROR(x...) dprintf("acpi_lid: "x)
38 static device_manager_info *sDeviceManager;
41 typedef struct acpi_ns_device_info {
42 device_node *node;
43 acpi_device_module_info *acpi;
44 acpi_device acpi_cookie;
45 uint8 last_status;
46 bool updated;
47 select_sync_pool* select_pool;
48 } acpi_lid_device_info;
51 static void
52 acpi_lid_read_status(acpi_lid_device_info *device)
54 acpi_data buf;
55 buf.pointer = NULL;
56 buf.length = ACPI_ALLOCATE_BUFFER;
57 if (device->acpi->evaluate_method(device->acpi_cookie, "_LID", NULL,
58 &buf) != B_OK
59 || buf.pointer == NULL
60 || ((acpi_object_type*)buf.pointer)->object_type != ACPI_TYPE_INTEGER) {
61 ERROR("couldn't get status\n");
62 } else {
63 acpi_object_type* object = (acpi_object_type*)buf.pointer;
64 device->last_status = object->integer.integer;
65 device->updated = true;
66 free(buf.pointer);
67 TRACE("status %d\n", device->last_status);
72 static void
73 acpi_lid_notify_handler(acpi_handle _device, uint32 value, void *context)
75 acpi_lid_device_info *device = (acpi_lid_device_info *)context;
76 if (value == ACPI_NOTIFY_STATUS_CHANGED) {
77 TRACE("status changed\n");
78 acpi_lid_read_status(device);
79 if (device->select_pool != NULL)
80 notify_select_event_pool(device->select_pool, B_SELECT_READ);
81 } else {
82 ERROR("unknown notification\n");
88 // #pragma mark - device module API
91 static status_t
92 acpi_lid_init_device(void *driverCookie, void **cookie)
94 *cookie = driverCookie;
95 return B_OK;
99 static void
100 acpi_lid_uninit_device(void *_cookie)
106 static status_t
107 acpi_lid_open(void *_cookie, const char *path, int flags, void** cookie)
109 acpi_lid_device_info *device = (acpi_lid_device_info *)_cookie;
110 *cookie = device;
111 return B_OK;
115 static status_t
116 acpi_lid_read(void* _cookie, off_t position, void *buf, size_t* num_bytes)
118 acpi_lid_device_info* device = (acpi_lid_device_info*)_cookie;
119 if (*num_bytes < 1)
120 return B_IO_ERROR;
122 *((uint8 *)(buf)) = device->last_status;
123 *num_bytes = 1;
124 device->updated = false;
125 return B_OK;
129 static status_t
130 acpi_lid_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes)
132 return B_ERROR;
136 static status_t
137 acpi_lid_control(void* _cookie, uint32 op, void* arg, size_t len)
139 return B_ERROR;
143 static status_t
144 acpi_lid_select(void *_cookie, uint8 event, selectsync *sync)
146 acpi_lid_device_info* device = (acpi_lid_device_info*)_cookie;
148 if (event != B_SELECT_READ)
149 return B_BAD_VALUE;
151 // add the event to the pool
152 status_t error = add_select_sync_pool_entry(&device->select_pool, sync,
153 event);
154 if (error != B_OK) {
155 ERROR("add_select_sync_pool_entry() failed: %#lx\n", error);
156 return error;
159 if (device->updated)
160 notify_select_event(sync, event);
162 return B_OK;
166 static status_t
167 acpi_lid_deselect(void *_cookie, uint8 event, selectsync *sync)
169 acpi_lid_device_info* device = (acpi_lid_device_info*)_cookie;
171 if (event != B_SELECT_READ)
172 return B_BAD_VALUE;
174 return remove_select_sync_pool_entry(&device->select_pool, sync, event);
178 static status_t
179 acpi_lid_close (void* cookie)
181 return B_OK;
185 static status_t
186 acpi_lid_free (void* cookie)
188 return B_OK;
192 // #pragma mark - driver module API
195 static float
196 acpi_lid_support(device_node *parent)
198 const char *bus;
199 uint32 device_type;
200 const char *hid;
202 // make sure parent is really the ACPI bus manager
203 if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
204 return -1;
206 if (strcmp(bus, "acpi"))
207 return 0.0;
209 // check whether it's really a device
210 if (sDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM,
211 &device_type, false) != B_OK
212 || device_type != ACPI_TYPE_DEVICE) {
213 return 0.0;
216 // check whether it's a lid device
217 if (sDeviceManager->get_attr_string(parent, ACPI_DEVICE_HID_ITEM, &hid,
218 false) != B_OK || strcmp(hid, "PNP0C0D")) {
219 return 0.0;
222 dprintf("acpi_lid_support lid device found\n");
224 return 0.6;
228 static status_t
229 acpi_lid_register_device(device_node *node)
231 device_attr attrs[] = {
232 { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { string: "ACPI Lid" }},
233 { NULL }
236 return sDeviceManager->register_node(node, ACPI_LID_MODULE_NAME, attrs,
237 NULL, NULL);
241 static status_t
242 acpi_lid_init_driver(device_node *node, void **_driverCookie)
244 acpi_lid_device_info *device;
245 device_node *parent;
246 status_t status;
248 device = (acpi_lid_device_info *)calloc(1, sizeof(*device));
249 if (device == NULL)
250 return B_NO_MEMORY;
252 device->node = node;
254 parent = sDeviceManager->get_parent_node(node);
255 sDeviceManager->get_driver(parent, (driver_module_info **)&device->acpi,
256 (void **)&device->acpi_cookie);
257 sDeviceManager->put_node(parent);
259 status = device->acpi->install_notify_handler(device->acpi_cookie, ACPI_DEVICE_NOTIFY,
260 acpi_lid_notify_handler, device);
261 if (status != B_OK) {
262 ERROR("can't install notify handler\n");
265 device->last_status = 0;
266 device->updated = false;
267 device->select_pool = NULL;
269 *_driverCookie = device;
270 return B_OK;
274 static void
275 acpi_lid_uninit_driver(void *driverCookie)
277 acpi_lid_device_info *device = (acpi_lid_device_info *)driverCookie;
279 device->acpi->remove_notify_handler(device->acpi_cookie, ACPI_DEVICE_NOTIFY,
280 acpi_lid_notify_handler);
282 free(device);
286 static status_t
287 acpi_lid_register_child_devices(void *_cookie)
289 acpi_lid_device_info *device = (acpi_lid_device_info *)_cookie;
290 int path_id;
291 char name[128];
293 path_id = sDeviceManager->create_id(ACPI_LID_PATHID_GENERATOR);
294 if (path_id < 0) {
295 ERROR("register_child_devices: couldn't create a path_id\n");
296 return B_ERROR;
299 snprintf(name, sizeof(name), ACPI_LID_BASENAME, path_id);
301 return sDeviceManager->publish_device(device->node, name,
302 ACPI_LID_DEVICE_MODULE_NAME);
306 module_dependency module_dependencies[] = {
307 { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager },
312 driver_module_info acpi_lid_driver_module = {
314 ACPI_LID_MODULE_NAME,
316 NULL
319 acpi_lid_support,
320 acpi_lid_register_device,
321 acpi_lid_init_driver,
322 acpi_lid_uninit_driver,
323 acpi_lid_register_child_devices,
324 NULL, // rescan
325 NULL, // removed
329 struct device_module_info acpi_lid_device_module = {
331 ACPI_LID_DEVICE_MODULE_NAME,
333 NULL
336 acpi_lid_init_device,
337 acpi_lid_uninit_device,
338 NULL,
340 acpi_lid_open,
341 acpi_lid_close,
342 acpi_lid_free,
343 acpi_lid_read,
344 acpi_lid_write,
345 NULL,
346 acpi_lid_control,
347 acpi_lid_select,
348 acpi_lid_deselect
351 module_info *modules[] = {
352 (module_info *)&acpi_lid_driver_module,
353 (module_info *)&acpi_lid_device_module,
354 NULL