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