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