1/* 2 * Copyright 2006-2013, J��r��me Duval. All rights reserved. 3 * Copyright 2011-2012, Fredrik Holmqvis. All rights reserved. 4 * Copyright 2008, Stefano Ceccherini. All rights reserved. 5 * Copyright 2006, Bryan Varner. All rights reserved. 6 * Distributed under the terms of the MIT License. 7 */ 8 9 10#include <stdio.h> 11#include <stdlib.h> 12#include <string.h> 13#include <unistd.h> 14 15#include <Drivers.h> 16 17#include <kernel.h> 18#include <util/kernel_cpp.h> 19#include <util/ring_buffer.h> 20 21#include "ACPIPrivate.h" 22 23 24class RingBuffer { 25public: 26 RingBuffer(size_t size = 1024); 27 ~RingBuffer(); 28 size_t Read(void *buffer, ssize_t length); 29 size_t Write(const void *buffer, ssize_t length); 30 size_t WritableAmount() const; 31 size_t ReadableAmount() const; 32 33 bool Lock(); 34 void Unlock(); 35 void DestroyLock(); 36private: 37 ring_buffer *fBuffer; 38 sem_id fLock; 39}; 40 41 42typedef struct acpi_ns_device_info { 43 device_node *node; 44 acpi_root_info *acpi; 45 void *acpi_cookie; 46 thread_id thread; 47 sem_id read_sem; 48 RingBuffer *buffer; 49} acpi_ns_device_info; 50 51 52 53// called with the buffer lock held 54static bool 55make_space(acpi_ns_device_info *device, size_t space) 56{ 57 size_t available = device->buffer->WritableAmount(); 58 if (space <= available) 59 return true; 60 bool released = false; 61 do { 62 device->buffer->Unlock(); 63 64 if (!released) { 65 if (release_sem_etc(device->read_sem, 1, B_RELEASE_IF_WAITING_ONLY) == B_OK) 66 released = true; 67 } 68 snooze(10000); 69 70 if (!device->buffer->Lock()) 71 return false; 72 73 } while (device->buffer->WritableAmount() < space); 74 75 return true; 76} 77 78 79 80static void 81dump_acpi_namespace(acpi_ns_device_info *device, char *root, int indenting) 82{ 83 char result[255]; 84 char output[320]; 85 char tabs[255] = ""; 86 int i; 87 for (i = 0; i < indenting; i++) 88 strlcat(tabs, "| ", sizeof(tabs)); 89 90 strlcat(tabs, "|--- ", sizeof(tabs)); 91 92 int depth = sizeof(char) * 5 * indenting + sizeof(char); // index into result where the device name will be. 93 94 void *counter = NULL; 95 while (device->acpi->get_next_entry(ACPI_TYPE_ANY, root, result, 255, &counter) == B_OK) { 96 uint32 type = device->acpi->get_object_type(result); 97 snprintf(output, sizeof(output), "%s%s", tabs, result + depth); 98 switch(type) { 99 case ACPI_TYPE_INTEGER: 100 strlcat(output, " INTEGER", sizeof(output)); 101 break; 102 case ACPI_TYPE_STRING: 103 strlcat(output, " STRING", sizeof(output)); 104 break; 105 case ACPI_TYPE_BUFFER: 106 strlcat(output, " BUFFER", sizeof(output)); 107 break; 108 case ACPI_TYPE_PACKAGE: 109 strlcat(output, " PACKAGE", sizeof(output)); 110 break; 111 case ACPI_TYPE_FIELD_UNIT: 112 strlcat(output, " FIELD UNIT", sizeof(output)); 113 break; 114 case ACPI_TYPE_DEVICE: 115 { 116 char* hid = NULL; 117 device->acpi->get_device_info(result, &hid, NULL, 0, NULL, NULL); 118 strlcat(output, " DEVICE (", sizeof(output)); 119 if (hid != NULL) { 120 strlcat(output, hid, sizeof(output)); 121 free(hid); 122 } else 123 strlcat(output, "none", sizeof(output)); 124 strlcat(output, ")", sizeof(output)); 125 break; 126 } 127 case ACPI_TYPE_EVENT: 128 strlcat(output, " EVENT", sizeof(output)); 129 break; 130 case ACPI_TYPE_METHOD: 131 strlcat(output, " METHOD", sizeof(output)); 132 break; 133 case ACPI_TYPE_MUTEX: 134 strlcat(output, " MUTEX", sizeof(output)); 135 break; 136 case ACPI_TYPE_REGION: 137 strlcat(output, " REGION", sizeof(output)); 138 break; 139 case ACPI_TYPE_POWER: 140 strlcat(output, " POWER", sizeof(output)); 141 break; 142 case ACPI_TYPE_PROCESSOR: 143 strlcat(output, " PROCESSOR", sizeof(output)); 144 break; 145 case ACPI_TYPE_THERMAL: 146 strlcat(output, " THERMAL", sizeof(output)); 147 break; 148 case ACPI_TYPE_BUFFER_FIELD: 149 strlcat(output, " BUFFER_FIELD", sizeof(output)); 150 break; 151 case ACPI_TYPE_ANY: 152 default: 153 break; 154 } 155 RingBuffer &ringBuffer = *device->buffer; 156 size_t toWrite = strlen(output); 157 158 if (toWrite == 0) 159 break; 160 161 toWrite = strlcat(output, "\n", sizeof(output)); 162 163 if (!ringBuffer.Lock()) 164 break; 165 166 if (ringBuffer.WritableAmount() < toWrite && 167 !make_space(device, toWrite)) 168 break; 169 170 ringBuffer.Write(output, toWrite); 171 ringBuffer.Unlock(); 172 dump_acpi_namespace(device, result, indenting + 1); 173 } 174} 175 176 177static int32 178acpi_namespace_dump(void *arg) 179{ 180 acpi_ns_device_info *device = (acpi_ns_device_info*)(arg); 181 dump_acpi_namespace(device, NULL, 0); 182 183 delete_sem(device->read_sem); 184 device->read_sem = -1; 185 186 return 0; 187} 188 189extern "C" { 190/* ---------- 191 acpi_namespace_open - handle open() calls 192----- */ 193 194static status_t 195acpi_namespace_open(void *_cookie, const char* path, int flags, void** cookie) 196{ 197 acpi_ns_device_info *device = (acpi_ns_device_info *)_cookie; 198 199 dprintf("\nacpi_ns_dump: device_open\n"); 200 201 *cookie = device; 202 203 RingBuffer *ringBuffer = new RingBuffer(1024); 204 if (ringBuffer == NULL) 205 return B_NO_MEMORY; 206 207 device->read_sem = create_sem(0, "read_sem"); 208 if (device->read_sem < B_OK) { 209 delete ringBuffer; 210 return device->read_sem; 211 } 212 213 device->thread = spawn_kernel_thread(acpi_namespace_dump, "acpi dumper", 214 B_NORMAL_PRIORITY, device); 215 if (device->thread < 0) { 216 delete ringBuffer; 217 delete_sem(device->read_sem); 218 return device->thread; 219 } 220 221 device->buffer = ringBuffer; 222 223 resume_thread(device->thread); 224 225 return B_OK; 226} 227 228 229/* ---------- 230 acpi_namespace_read - handle read() calls 231----- */ 232static status_t 233acpi_namespace_read(void *_cookie, off_t position, void *buf, size_t* num_bytes) 234{ 235 acpi_ns_device_info *device = (acpi_ns_device_info *)_cookie; 236 RingBuffer &ringBuffer = *device->buffer; 237 238 if (!ringBuffer.Lock()) { 239 *num_bytes = 0; 240 return B_ERROR; 241 } 242 243 if (ringBuffer.ReadableAmount() == 0) { 244 ringBuffer.Unlock(); 245 status_t status = acquire_sem_etc(device->read_sem, 1, B_CAN_INTERRUPT, 0); 246 if (status != B_OK && status != B_BAD_SEM_ID) { 247 *num_bytes = 0; 248 return status; 249 } 250 if (!ringBuffer.Lock()) { 251 *num_bytes = 0; 252 return B_ERROR; 253 } 254 } 255 256 *num_bytes = ringBuffer.Read(buf, *num_bytes); 257 ringBuffer.Unlock(); 258 259 return B_OK; 260} 261 262 263/* ---------- 264 acpi_namespace_write - handle write() calls 265----- */ 266 267static status_t 268acpi_namespace_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes) 269{ 270 *num_bytes = 0; /* tell caller nothing was written */ 271 return B_IO_ERROR; 272} 273 274 275/* ---------- 276 acpi_namespace_control - handle ioctl calls 277----- */ 278 279static status_t 280acpi_namespace_control(void* cookie, uint32 op, void* arg, size_t len) 281{ 282 dprintf("acpi_ns_dump: device_control\n"); 283 return B_DEV_INVALID_IOCTL; 284} 285 286 287/* ---------- 288 acpi_namespace_close - handle close() calls 289----- */ 290 291static status_t 292acpi_namespace_close(void* cookie) 293{ 294 dprintf("acpi_ns_dump: device_close\n"); 295 return B_OK; 296} 297 298 299/* ----- 300 acpi_namespace_free - called after the last device is closed, and after 301 all i/o is complete. 302----- */ 303static status_t 304acpi_namespace_free(void* cookie) 305{ 306 status_t status; 307 acpi_ns_device_info *device = (acpi_ns_device_info *)cookie; 308 dprintf("acpi_ns_dump: device_free\n"); 309 310 if (device->read_sem >= 0) 311 delete_sem(device->read_sem); 312 313 device->buffer->DestroyLock(); 314 wait_for_thread(device->thread, &status); 315 delete device->buffer; 316 317 return B_OK; 318} 319 320 321// #pragma mark - device module API 322 323 324static status_t 325acpi_namespace_init_device(void *_cookie, void **cookie) 326{ 327 device_node *node = (device_node *)_cookie; 328 status_t err; 329 330 acpi_ns_device_info *device = (acpi_ns_device_info *)calloc(1, sizeof(*device)); 331 if (device == NULL) 332 return B_NO_MEMORY; 333 334 device->node = node; 335 err = gDeviceManager->get_driver(node, (driver_module_info **)&device->acpi, 336 (void **)&device->acpi_cookie); 337 if (err != B_OK) { 338 free(device); 339 return err; 340 } 341 342 *cookie = device; 343 return B_OK; 344} 345 346 347static void 348acpi_namespace_uninit_device(void *_cookie) 349{ 350 acpi_ns_device_info *device = (acpi_ns_device_info *)_cookie; 351 free(device); 352} 353 354} 355 356struct device_module_info acpi_ns_dump_module = { 357 { 358 ACPI_NS_DUMP_DEVICE_MODULE_NAME, 359 0, 360 NULL 361 }, 362 363 acpi_namespace_init_device, 364 acpi_namespace_uninit_device, 365 NULL, 366 367 acpi_namespace_open, 368 acpi_namespace_close, 369 acpi_namespace_free, 370 acpi_namespace_read, 371 acpi_namespace_write, 372 NULL, 373 acpi_namespace_control, 374 375 NULL, 376 NULL 377}; 378 379 380RingBuffer::RingBuffer(size_t size) 381{ 382 fBuffer = create_ring_buffer(size); 383 fLock = create_sem(1, "ring buffer lock"); 384} 385 386 387RingBuffer::~RingBuffer() 388{ 389 delete_ring_buffer(fBuffer); 390} 391 392 393size_t 394RingBuffer::Read(void *buffer, ssize_t size) 395{ 396 if (IS_USER_ADDRESS(buffer)) 397 return ring_buffer_user_read(fBuffer, (uint8*)buffer, size); 398 else 399 return ring_buffer_read(fBuffer, (uint8*)buffer, size); 400} 401 402 403size_t 404RingBuffer::Write(const void *buffer, ssize_t size) 405{ 406 return ring_buffer_write(fBuffer, (uint8*)buffer, size); 407} 408 409 410size_t 411RingBuffer::ReadableAmount() const 412{ 413 return ring_buffer_readable(fBuffer); 414} 415 416 417size_t 418RingBuffer::WritableAmount() const 419{ 420 return ring_buffer_writable(fBuffer); 421} 422 423 424bool 425RingBuffer::Lock() 426{ 427 //status_t status = acquire_sem_etc(fLock, 1, B_CAN_INTERRUPT, 0); 428 status_t status = acquire_sem(fLock); 429 return status == B_OK; 430} 431 432 433void 434RingBuffer::Unlock() 435{ 436 release_sem(fLock); 437} 438 439 440void 441RingBuffer::DestroyLock() 442{ 443 delete_sem(fLock); 444} 445 446