1/* 2 * Copyright 2008-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 <fs/select_sync_pool.h> 11 12#include <stdio.h> 13#include <stdlib.h> 14#include <string.h> 15 16 17#define ACPI_LID_MODULE_NAME "drivers/power/acpi_lid/driver_v1" 18 19#define ACPI_LID_DEVICE_MODULE_NAME "drivers/power/acpi_lid/device_v1" 20 21#define ACPI_NOTIFY_STATUS_CHANGED 0x80 22 23/* Base Namespace devices are published to */ 24#define ACPI_LID_BASENAME "power/acpi_lid/%d" 25 26// name of pnp generator of path ids 27#define ACPI_LID_PATHID_GENERATOR "acpi_lid/path_id" 28 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) 36 37 38static device_manager_info *sDeviceManager; 39 40 41typedef 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; 49 50 51static void 52acpi_lid_read_status(acpi_lid_device_info *device) 53{ 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, &buf) != B_OK 58 || buf.pointer == NULL 59 || ((acpi_object_type*)buf.pointer)->object_type != ACPI_TYPE_INTEGER) { 60 ERROR("couldn't get status\n"); 61 } else { 62 acpi_object_type* object = (acpi_object_type*)buf.pointer; 63 device->last_status = object->integer.integer; 64 device->updated = true; 65 TRACE("status %d\n", device->last_status); 66 } 67 free(buf.pointer); 68} 69 70 71static void 72acpi_lid_notify_handler(acpi_handle _device, uint32 value, void *context) 73{ 74 acpi_lid_device_info *device = (acpi_lid_device_info *)context; 75 if (value == ACPI_NOTIFY_STATUS_CHANGED) { 76 TRACE("status changed\n"); 77 acpi_lid_read_status(device); 78 if (device->select_pool != NULL) 79 notify_select_event_pool(device->select_pool, B_SELECT_READ); 80 } else { 81 ERROR("unknown notification\n"); 82 } 83 84} 85 86 87// #pragma mark - device module API 88 89 90static status_t 91acpi_lid_init_device(void *driverCookie, void **cookie) 92{ 93 *cookie = driverCookie; 94 return B_OK; 95} 96 97 98static void 99acpi_lid_uninit_device(void *_cookie) 100{ 101 102} 103 104 105static status_t 106acpi_lid_open(void *_cookie, const char *path, int flags, void** cookie) 107{ 108 acpi_lid_device_info *device = (acpi_lid_device_info *)_cookie; 109 *cookie = device; 110 return B_OK; 111} 112 113 114static status_t 115acpi_lid_read(void* _cookie, off_t position, void *buf, size_t* num_bytes) 116{ 117 acpi_lid_device_info* device = (acpi_lid_device_info*)_cookie; 118 if (*num_bytes < 1) 119 return B_IO_ERROR; 120 121 if (position > 0) { 122 *num_bytes = 0; 123 return B_OK; 124 } 125 126 if (user_memcpy(buf, &device->last_status, sizeof(uint8)) < B_OK) 127 return B_BAD_ADDRESS; 128 129 *num_bytes = 1; 130 device->updated = false; 131 return B_OK; 132} 133 134 135static status_t 136acpi_lid_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes) 137{ 138 return B_ERROR; 139} 140 141 142static status_t 143acpi_lid_control(void* _cookie, uint32 op, void* arg, size_t len) 144{ 145 return B_ERROR; 146} 147 148 149static status_t 150acpi_lid_select(void *_cookie, uint8 event, selectsync *sync) 151{ 152 acpi_lid_device_info* device = (acpi_lid_device_info*)_cookie; 153 154 if (event != B_SELECT_READ) 155 return B_BAD_VALUE; 156 157 // add the event to the pool 158 status_t error = add_select_sync_pool_entry(&device->select_pool, sync, 159 event); 160 if (error != B_OK) { 161 ERROR("add_select_sync_pool_entry() failed: %#" B_PRIx32 "\n", error); 162 return error; 163 } 164 165 if (device->updated) 166 notify_select_event(sync, event); 167 168 return B_OK; 169} 170 171 172static status_t 173acpi_lid_deselect(void *_cookie, uint8 event, selectsync *sync) 174{ 175 acpi_lid_device_info* device = (acpi_lid_device_info*)_cookie; 176 177 if (event != B_SELECT_READ) 178 return B_BAD_VALUE; 179 180 return remove_select_sync_pool_entry(&device->select_pool, sync, event); 181} 182 183 184static status_t 185acpi_lid_close (void* cookie) 186{ 187 return B_OK; 188} 189 190 191static status_t 192acpi_lid_free (void* cookie) 193{ 194 return B_OK; 195} 196 197 198// #pragma mark - driver module API 199 200 201static float 202acpi_lid_support(device_node *parent) 203{ 204 const char *bus; 205 uint32 device_type; 206 const char *hid; 207 208 // make sure parent is really the ACPI bus manager 209 if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)) 210 return -1; 211 212 if (strcmp(bus, "acpi")) 213 return 0.0; 214 215 // check whether it's really a device 216 if (sDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM, 217 &device_type, false) != B_OK 218 || device_type != ACPI_TYPE_DEVICE) { 219 return 0.0; 220 } 221 222 // check whether it's a lid device 223 if (sDeviceManager->get_attr_string(parent, ACPI_DEVICE_HID_ITEM, &hid, 224 false) != B_OK || strcmp(hid, "PNP0C0D")) { 225 return 0.0; 226 } 227 228 dprintf("acpi_lid_support lid device found\n"); 229 230 return 0.6; 231} 232 233 234static status_t 235acpi_lid_register_device(device_node *node) 236{ 237 device_attr attrs[] = { 238 { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { .string = "ACPI Lid" }}, 239 { NULL } 240 }; 241 242 return sDeviceManager->register_node(node, ACPI_LID_MODULE_NAME, attrs, 243 NULL, NULL); 244} 245 246 247static status_t 248acpi_lid_init_driver(device_node *node, void **_driverCookie) 249{ 250 acpi_lid_device_info *device; 251 device_node *parent; 252 status_t status; 253 254 device = (acpi_lid_device_info *)calloc(1, sizeof(*device)); 255 if (device == NULL) 256 return B_NO_MEMORY; 257 258 device->node = node; 259 260 parent = sDeviceManager->get_parent_node(node); 261 sDeviceManager->get_driver(parent, (driver_module_info **)&device->acpi, 262 (void **)&device->acpi_cookie); 263 sDeviceManager->put_node(parent); 264 265 status = device->acpi->install_notify_handler(device->acpi_cookie, ACPI_DEVICE_NOTIFY, 266 acpi_lid_notify_handler, device); 267 if (status != B_OK) { 268 ERROR("can't install notify handler\n"); 269 } 270 271 device->last_status = 0; 272 device->updated = false; 273 device->select_pool = NULL; 274 275 *_driverCookie = device; 276 return B_OK; 277} 278 279 280static void 281acpi_lid_uninit_driver(void *driverCookie) 282{ 283 acpi_lid_device_info *device = (acpi_lid_device_info *)driverCookie; 284 285 device->acpi->remove_notify_handler(device->acpi_cookie, ACPI_DEVICE_NOTIFY, 286 acpi_lid_notify_handler); 287 288 free(device); 289} 290 291 292static status_t 293acpi_lid_register_child_devices(void *_cookie) 294{ 295 acpi_lid_device_info *device = (acpi_lid_device_info *)_cookie; 296 int path_id; 297 char name[128]; 298 299 path_id = sDeviceManager->create_id(ACPI_LID_PATHID_GENERATOR); 300 if (path_id < 0) { 301 ERROR("register_child_devices: couldn't create a path_id\n"); 302 return B_ERROR; 303 } 304 305 snprintf(name, sizeof(name), ACPI_LID_BASENAME, path_id); 306 307 return sDeviceManager->publish_device(device->node, name, 308 ACPI_LID_DEVICE_MODULE_NAME); 309} 310 311 312module_dependency module_dependencies[] = { 313 { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager }, 314 {} 315}; 316 317 318driver_module_info acpi_lid_driver_module = { 319 { 320 ACPI_LID_MODULE_NAME, 321 0, 322 NULL 323 }, 324 325 acpi_lid_support, 326 acpi_lid_register_device, 327 acpi_lid_init_driver, 328 acpi_lid_uninit_driver, 329 acpi_lid_register_child_devices, 330 NULL, // rescan 331 NULL, // removed 332}; 333 334 335struct device_module_info acpi_lid_device_module = { 336 { 337 ACPI_LID_DEVICE_MODULE_NAME, 338 0, 339 NULL 340 }, 341 342 acpi_lid_init_device, 343 acpi_lid_uninit_device, 344 NULL, 345 346 acpi_lid_open, 347 acpi_lid_close, 348 acpi_lid_free, 349 acpi_lid_read, 350 acpi_lid_write, 351 NULL, 352 acpi_lid_control, 353 acpi_lid_select, 354 acpi_lid_deselect 355}; 356 357module_info *modules[] = { 358 (module_info *)&acpi_lid_driver_module, 359 (module_info *)&acpi_lid_device_module, 360 NULL 361}; 362