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_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 64 static void 65 acpi_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 80 static status_t 81 acpi_ac_init_device(void *driverCookie, void **cookie) 82 { 83 *cookie = driverCookie; 84 return B_OK; 85 } 86 87 88 static void 89 acpi_ac_uninit_device(void *_cookie) 90 { 91 92 } 93 94 95 static status_t 96 acpi_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 104 static status_t 105 acpi_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 *((uint8 *)(buf)) = device->last_status; 117 118 *num_bytes = 1; 119 return B_OK; 120 } 121 122 123 static status_t 124 acpi_ac_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes) 125 { 126 return B_ERROR; 127 } 128 129 130 static status_t 131 acpi_ac_control(void* _cookie, uint32 op, void* arg, size_t len) 132 { 133 return B_ERROR; 134 } 135 136 137 static status_t 138 acpi_ac_close (void* cookie) 139 { 140 return B_OK; 141 } 142 143 144 static status_t 145 acpi_ac_free (void* cookie) 146 { 147 return B_OK; 148 } 149 150 151 // #pragma mark - driver module API 152 153 154 static float 155 acpi_ac_support(device_node *parent) 156 { 157 const char *bus; 158 uint32 device_type; 159 const char *hid; 160 161 // make sure parent is really the ACPI bus manager 162 if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)) 163 return -1; 164 165 if (strcmp(bus, "acpi")) 166 return 0.0; 167 168 // check whether it's really a device 169 if (sDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM, 170 &device_type, false) != B_OK 171 || device_type != ACPI_TYPE_DEVICE) { 172 return 0.0; 173 } 174 175 // check whether it's an ac device 176 if (sDeviceManager->get_attr_string(parent, ACPI_DEVICE_HID_ITEM, &hid, 177 false) != B_OK || strcmp(hid, "ACPI0003")) { 178 return 0.0; 179 } 180 181 dprintf("acpi_ac_support ac device found\n"); 182 183 return 0.6; 184 } 185 186 187 static status_t 188 acpi_ac_register_device(device_node *node) 189 { 190 device_attr attrs[] = { 191 { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { .string = "ACPI AC" }}, 192 { NULL } 193 }; 194 195 return sDeviceManager->register_node(node, ACPI_AC_MODULE_NAME, attrs, 196 NULL, NULL); 197 } 198 199 200 static status_t 201 acpi_ac_init_driver(device_node *node, void **_driverCookie) 202 { 203 acpi_ac_device_info *device; 204 device_node *parent; 205 status_t status; 206 207 device = (acpi_ac_device_info *)calloc(1, sizeof(*device)); 208 if (device == NULL) 209 return B_NO_MEMORY; 210 211 device->node = node; 212 213 parent = sDeviceManager->get_parent_node(node); 214 sDeviceManager->get_driver(parent, (driver_module_info **)&device->acpi, 215 (void **)&device->acpi_cookie); 216 sDeviceManager->put_node(parent); 217 218 status = device->acpi->install_notify_handler(device->acpi_cookie, 219 ACPI_DEVICE_NOTIFY, acpi_ac_notify_handler, device); 220 if (status != B_OK) { 221 ERROR("can't install notify handler\n"); 222 } 223 224 device->last_status = 0; 225 226 acpi_ac_update_status(device); 227 228 *_driverCookie = device; 229 return B_OK; 230 } 231 232 233 static void 234 acpi_ac_uninit_driver(void *driverCookie) 235 { 236 acpi_ac_device_info *device = (acpi_ac_device_info *)driverCookie; 237 238 device->acpi->remove_notify_handler(device->acpi_cookie, 239 ACPI_DEVICE_NOTIFY, acpi_ac_notify_handler); 240 241 free(device); 242 } 243 244 245 static status_t 246 acpi_ac_register_child_devices(void *driverCookie) 247 { 248 acpi_ac_device_info *device = (acpi_ac_device_info *)driverCookie; 249 int path_id; 250 char name[128]; 251 252 path_id = sDeviceManager->create_id(ACPI_AC_PATHID_GENERATOR); 253 if (path_id < 0) { 254 ERROR("register_child_devices: couldn't create a path_id\n"); 255 return B_ERROR; 256 } 257 258 snprintf(name, sizeof(name), ACPI_AC_BASENAME, path_id); 259 260 return sDeviceManager->publish_device(device->node, name, 261 ACPI_AC_DEVICE_MODULE_NAME); 262 } 263 264 265 module_dependency module_dependencies[] = { 266 { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager }, 267 {} 268 }; 269 270 271 driver_module_info acpi_ac_driver_module = { 272 { 273 ACPI_AC_MODULE_NAME, 274 0, 275 NULL 276 }, 277 278 acpi_ac_support, 279 acpi_ac_register_device, 280 acpi_ac_init_driver, 281 acpi_ac_uninit_driver, 282 acpi_ac_register_child_devices, 283 NULL, // rescan 284 NULL, // removed 285 }; 286 287 288 struct device_module_info acpi_ac_device_module = { 289 { 290 ACPI_AC_DEVICE_MODULE_NAME, 291 0, 292 NULL 293 }, 294 295 acpi_ac_init_device, 296 acpi_ac_uninit_device, 297 NULL, 298 299 acpi_ac_open, 300 acpi_ac_close, 301 acpi_ac_free, 302 acpi_ac_read, 303 acpi_ac_write, 304 NULL, 305 acpi_ac_control, 306 307 NULL, 308 NULL 309 }; 310 311 module_info *modules[] = { 312 (module_info *)&acpi_ac_driver_module, 313 (module_info *)&acpi_ac_device_module, 314 NULL 315 }; 316