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 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); 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 177 static int32 178 acpi_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 189 extern "C" { 190 /* ---------- 191 acpi_namespace_open - handle open() calls 192 ----- */ 193 194 static status_t 195 acpi_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 ----- */ 232 static status_t 233 acpi_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 267 static status_t 268 acpi_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 279 static status_t 280 acpi_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 291 static status_t 292 acpi_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 ----- */ 303 static status_t 304 acpi_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 324 static status_t 325 acpi_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 347 static void 348 acpi_namespace_uninit_device(void *_cookie) 349 { 350 acpi_ns_device_info *device = (acpi_ns_device_info *)_cookie; 351 free(device); 352 } 353 354 } 355 356 struct 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 380 RingBuffer::RingBuffer(size_t size) 381 { 382 fBuffer = create_ring_buffer(size); 383 fLock = create_sem(1, "ring buffer lock"); 384 } 385 386 387 RingBuffer::~RingBuffer() 388 { 389 delete_ring_buffer(fBuffer); 390 } 391 392 393 size_t 394 RingBuffer::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 403 size_t 404 RingBuffer::Write(const void *buffer, ssize_t size) 405 { 406 return ring_buffer_write(fBuffer, (uint8*)buffer, size); 407 } 408 409 410 size_t 411 RingBuffer::ReadableAmount() const 412 { 413 return ring_buffer_readable(fBuffer); 414 } 415 416 417 size_t 418 RingBuffer::WritableAmount() const 419 { 420 return ring_buffer_writable(fBuffer); 421 } 422 423 424 bool 425 RingBuffer::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 433 void 434 RingBuffer::Unlock() 435 { 436 release_sem(fLock); 437 } 438 439 440 void 441 RingBuffer::DestroyLock() 442 { 443 delete_sem(fLock); 444 } 445 446