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 17 class RingBuffer { 18 public: 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(); 29 private: 30 ring_buffer *fBuffer; 31 sem_id fLock; 32 }; 33 34 35 typedef 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 47 static bool 48 make_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 73 static void 74 dump_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 165 static int32 166 acpi_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 177 extern "C" { 178 /* ---------- 179 acpi_namespace_open - handle open() calls 180 ----- */ 181 182 static status_t 183 acpi_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 ----- */ 220 static status_t 221 acpi_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 255 static status_t 256 acpi_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 267 static status_t 268 acpi_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 279 static status_t 280 acpi_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 ----- */ 301 static status_t 302 acpi_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 313 static status_t 314 acpi_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 336 static void 337 acpi_namespace_uninit_device(void *_cookie) 338 { 339 acpi_ns_device_info *device = (acpi_ns_device_info *)_cookie; 340 free(device); 341 } 342 343 } 344 345 struct 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 369 RingBuffer::RingBuffer(size_t size) 370 { 371 fBuffer = create_ring_buffer(size); 372 fLock = create_sem(1, "ring buffer lock"); 373 } 374 375 376 RingBuffer::~RingBuffer() 377 { 378 delete_ring_buffer(fBuffer); 379 } 380 381 382 size_t 383 RingBuffer::Read(void *buffer, ssize_t size) 384 { 385 return ring_buffer_read(fBuffer, (uint8*)buffer, size); 386 } 387 388 389 size_t 390 RingBuffer::Write(const void *buffer, ssize_t size) 391 { 392 return ring_buffer_write(fBuffer, (uint8*)buffer, size); 393 } 394 395 396 size_t 397 RingBuffer::ReadableAmount() const 398 { 399 return ring_buffer_readable(fBuffer); 400 } 401 402 403 size_t 404 RingBuffer::WritableAmount() const 405 { 406 return ring_buffer_writable(fBuffer); 407 } 408 409 410 bool 411 RingBuffer::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 419 void 420 RingBuffer::Unlock() 421 { 422 release_sem(fLock); 423 } 424 425 426 void 427 RingBuffer::DestroyLock() 428 { 429 delete_sem(fLock); 430 } 431 432