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