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