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