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 33static device_manager_info *sDeviceManager; 34 35 36typedef 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 44static void 45acpi_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 64static void 65acpi_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 80static status_t 81acpi_ac_init_device(void *driverCookie, void **cookie) 82{ 83 *cookie = driverCookie; 84 return B_OK; 85} 86 87 88static void 89acpi_ac_uninit_device(void *_cookie) 90{ 91 92} 93 94 95static status_t 96acpi_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 104static status_t 105acpi_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 124static status_t 125acpi_ac_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes) 126{ 127 return B_ERROR; 128} 129 130 131static status_t 132acpi_ac_control(void* _cookie, uint32 op, void* arg, size_t len) 133{ 134 return B_ERROR; 135} 136 137 138static status_t 139acpi_ac_close (void* cookie) 140{ 141 return B_OK; 142} 143 144 145static status_t 146acpi_ac_free (void* cookie) 147{ 148 return B_OK; 149} 150 151 152// #pragma mark - driver module API 153 154 155static float 156acpi_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 188static status_t 189acpi_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 201static status_t 202acpi_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 234static void 235acpi_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 246static status_t 247acpi_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 266module_dependency module_dependencies[] = { 267 { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager }, 268 {} 269}; 270 271 272driver_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 289struct 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 312module_info *modules[] = { 313 (module_info *)&acpi_ac_driver_module, 314 (module_info *)&acpi_ac_device_module, 315 NULL 316}; 317