1 /* 2 * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. 3 * This file may be used under the terms of the MIT License. 4 */ 5 6 /*! \brief Implements the driver settings API 7 This file is used by three different components with different needs: 8 1) the boot loader 9 Buffers a list of settings files to move over to the kernel - the 10 actual buffering is located in the boot loader directly, though. 11 Creates driver_settings structures out of those on demand only. 12 2) the kernel 13 Maintains a list of settings so that no disk access is required 14 for known settings (such as those passed over from the boot 15 loader). 16 3) libroot.so 17 Exports the parser to userland applications, so that they can 18 easily make use of driver_settings styled files. 19 20 The file has to be recompiled for every component separately, so that 21 it properly exports the required functionality (which is specified by 22 _BOOT_MODE for the boot loader, and _KERNEL_MODE for the kernel). 23 */ 24 25 // The boot loader is compiled with kernel rules, but we want to explicitely 26 // differentiate between the two here. 27 #ifdef _BOOT_MODE 28 # undef _KERNEL_MODE 29 #endif 30 31 #include <driver_settings.h> 32 #include <FindDirectory.h> 33 #include <OS.h> 34 35 #ifdef _KERNEL_MODE 36 # include <KernelExport.h> 37 # include <util/list.h> 38 # include <lock.h> 39 # include <kdriver_settings.h> 40 # include <kernel.h> 41 # include <boot/kernel_args.h> 42 # include <boot_device.h> 43 #endif 44 #ifdef _BOOT_MODE 45 # include <boot/kernel_args.h> 46 # include <boot/stage2.h> 47 #endif 48 49 #include <stdlib.h> 50 #include <string.h> 51 #include <unistd.h> 52 #include <fcntl.h> 53 #include <ctype.h> 54 55 #ifndef HAIKU_TARGET_PLATFORM_HAIKU 56 # define B_BUFFER_OVERFLOW B_ERROR 57 #endif 58 59 #define SETTINGS_DIRECTORY "/kernel/drivers/" 60 #define SETTINGS_MAGIC 'DrvS' 61 62 // Those maximum values are independent from the implementation - they 63 // have been chosen to make the code more robust against bad files 64 #define MAX_SETTINGS_SIZE 32768 65 #define MAX_SETTINGS_LEVEL 8 66 67 #define CONTINUE_PARAMETER 1 68 #define NO_PARAMETER 2 69 70 71 typedef struct settings_handle { 72 #ifdef _KERNEL_MODE 73 list_link link; 74 char name[B_OS_NAME_LENGTH]; 75 int32 ref_count; 76 #endif 77 int32 magic; 78 struct driver_settings settings; 79 char *text; 80 } settings_handle; 81 82 83 enum assignment_mode { 84 NO_ASSIGNMENT, 85 ALLOW_ASSIGNMENT, 86 IGNORE_ASSIGNMENT 87 }; 88 89 90 #ifdef _KERNEL_MODE 91 static struct list sHandles; 92 static mutex sLock = MUTEX_INITIALIZER("driver settings"); 93 #endif 94 95 96 // #pragma mark - private functions 97 98 99 /*! 100 Returns true for any characters that separate parameters - 101 those are ignored in the input stream and won't be added 102 to any words. 103 */ 104 static inline bool 105 is_parameter_separator(char c) 106 { 107 return c == '\n' || c == ';'; 108 } 109 110 111 /** Indicates if "c" begins a new word or not. 112 */ 113 114 static inline bool 115 is_word_break(char c) 116 { 117 return isspace(c) || is_parameter_separator(c); 118 } 119 120 121 static inline bool 122 check_handle(settings_handle *handle) 123 { 124 if (handle == NULL 125 || handle->magic != SETTINGS_MAGIC) 126 return false; 127 128 return true; 129 } 130 131 132 static driver_parameter * 133 get_parameter(settings_handle *handle, const char *name) 134 { 135 int32 i; 136 for (i = handle->settings.parameter_count; i-- > 0;) { 137 if (!strcmp(handle->settings.parameters[i].name, name)) 138 return &handle->settings.parameters[i]; 139 } 140 return NULL; 141 } 142 143 144 /*! 145 Returns the next word in the input buffer passed in via "_pos" - if 146 this function returns, it will bump the input position after the word. 147 It automatically cares about quoted strings and escaped characters. 148 If "allowNewLine" is true, it reads over comments to get to the next 149 word. 150 Depending on the "assignmentMode" parameter, the '=' sign is either 151 used as a work break, or not. 152 The input buffer will be changed to contain the word without quotes 153 or escaped characters and adds a terminating NULL byte. The "_word" 154 parameter will be set to the beginning of the word. 155 If the word is followed by a newline it will return B_OK, if white 156 spaces follows, it will return CONTINUE_PARAMETER. 157 */ 158 static status_t 159 get_word(char **_pos, char **_word, int32 assignmentMode, bool allowNewLine) 160 { 161 char *pos = *_pos; 162 char quoted = 0; 163 bool newLine = false, end = false; 164 int escaped = 0; 165 bool charEscaped = false; 166 167 // Skip any white space and comments 168 while (pos[0] 169 && ((allowNewLine && (isspace(pos[0]) || is_parameter_separator(pos[0]) 170 || pos[0] == '#')) 171 || (!allowNewLine && (pos[0] == '\t' || pos[0] == ' ')) 172 || (assignmentMode == ALLOW_ASSIGNMENT && pos[0] == '='))) { 173 // skip any comment lines 174 if (pos[0] == '#') { 175 while (pos[0] && pos[0] != '\n') 176 pos++; 177 } 178 pos++; 179 } 180 181 if (pos[0] == '}' || pos[0] == '\0') { 182 // if we just read some white space before an end of a 183 // parameter, this is just no parameter at all 184 *_pos = pos; 185 return NO_PARAMETER; 186 } 187 188 // Read in a word - might contain escaped (\) spaces, or it 189 // might also be quoted (" or '). 190 191 if (pos[0] == '"' || pos[0] == '\'') { 192 quoted = pos[0]; 193 pos++; 194 } 195 *_word = pos; 196 197 while (pos[0]) { 198 if (charEscaped) 199 charEscaped = false; 200 else if (pos[0] == '\\') { 201 charEscaped = true; 202 escaped++; 203 } else if ((!quoted && (is_word_break(pos[0]) 204 || (assignmentMode != IGNORE_ASSIGNMENT && pos[0] == '='))) 205 || (quoted && pos[0] == quoted)) 206 break; 207 208 pos++; 209 } 210 211 // "String exceeds line" - missing end quote 212 if (quoted && pos[0] != quoted) 213 return B_BAD_DATA; 214 215 // last character is a backslash 216 if (charEscaped) 217 return B_BAD_DATA; 218 219 end = pos[0] == '\0'; 220 newLine = is_parameter_separator(pos[0]) || end; 221 pos[0] = '\0'; 222 223 // Correct name if there were any escaped characters 224 if (escaped) { 225 char *word = *_word; 226 int offset = 0; 227 while (word <= pos) { 228 if (word[0] == '\\') { 229 offset--; 230 word++; 231 } 232 word[offset] = word[0]; 233 word++; 234 } 235 } 236 237 if (end) { 238 *_pos = pos; 239 return B_OK; 240 } 241 242 // Scan for next beginning word, open brackets, or comment start 243 244 pos++; 245 while (true) { 246 *_pos = pos; 247 if (!pos[0]) 248 return B_NO_ERROR; 249 250 if (is_parameter_separator(pos[0])) { 251 // an open bracket '{' could follow after the first 252 // newline, but not later 253 if (newLine) 254 return B_NO_ERROR; 255 256 newLine = true; 257 } else if (pos[0] == '{' || pos[0] == '}' || pos[0] == '#') 258 return B_NO_ERROR; 259 else if (!isspace(pos[0])) 260 return newLine ? B_NO_ERROR : CONTINUE_PARAMETER; 261 262 pos++; 263 } 264 } 265 266 267 static status_t 268 parse_parameter(struct driver_parameter *parameter, char **_pos, int32 level) 269 { 270 char *pos = *_pos; 271 status_t status; 272 273 // initialize parameter first 274 memset(parameter, 0, sizeof(struct driver_parameter)); 275 276 status = get_word(&pos, ¶meter->name, NO_ASSIGNMENT, true); 277 if (status == CONTINUE_PARAMETER) { 278 while (status == CONTINUE_PARAMETER) { 279 char **newArray, *value; 280 status = get_word(&pos, &value, parameter->value_count == 0 281 ? ALLOW_ASSIGNMENT : IGNORE_ASSIGNMENT, false); 282 if (status < B_OK) 283 break; 284 285 // enlarge value array and save the value 286 287 newArray = (char**)realloc(parameter->values, 288 (parameter->value_count + 1) * sizeof(char *)); 289 if (newArray == NULL) 290 return B_NO_MEMORY; 291 292 parameter->values = newArray; 293 parameter->values[parameter->value_count++] = value; 294 } 295 } 296 297 *_pos = pos; 298 return status; 299 } 300 301 302 static status_t 303 parse_parameters(struct driver_parameter **_parameters, int *_count, 304 char **_pos, int32 level) 305 { 306 if (level > MAX_SETTINGS_LEVEL) 307 return B_LINK_LIMIT; 308 309 while (true) { 310 struct driver_parameter parameter; 311 struct driver_parameter *newArray; 312 status_t status; 313 314 status = parse_parameter(¶meter, _pos, level); 315 if (status < B_OK) 316 return status; 317 318 if (status != NO_PARAMETER) { 319 driver_parameter *newParameter; 320 321 newArray = (driver_parameter*)realloc(*_parameters, (*_count + 1) 322 * sizeof(struct driver_parameter)); 323 if (newArray == NULL) 324 return B_NO_MEMORY; 325 326 memcpy(&newArray[*_count], ¶meter, sizeof(struct driver_parameter)); 327 newParameter = &newArray[*_count]; 328 329 *_parameters = newArray; 330 (*_count)++; 331 332 // check for level beginning and end 333 if (**_pos == '{') { 334 // if we go a level deeper, just start all over again... 335 (*_pos)++; 336 status = parse_parameters(&newParameter->parameters, 337 &newParameter->parameter_count, _pos, level + 1); 338 if (status < B_OK) 339 return status; 340 } 341 } 342 343 if ((**_pos == '}' && level > 0) 344 || (**_pos == '\0' && level == 0)) { 345 // take the closing bracket from the stack 346 (*_pos)++; 347 return B_OK; 348 } 349 350 // obviously, something has gone wrong 351 if (**_pos == '}' || **_pos == '\0') 352 return B_ERROR; 353 } 354 } 355 356 357 static status_t 358 parse_settings(settings_handle *handle) 359 { 360 char *text = handle->text; 361 362 memset(&handle->settings, 0, sizeof(struct driver_settings)); 363 364 // empty settings are allowed 365 if (text == NULL) 366 return B_OK; 367 368 return parse_parameters(&handle->settings.parameters, 369 &handle->settings.parameter_count, &text, 0); 370 } 371 372 373 static void 374 free_parameter(struct driver_parameter *parameter) 375 { 376 int32 i; 377 for (i = parameter->parameter_count; i-- > 0;) 378 free_parameter(¶meter->parameters[i]); 379 380 free(parameter->parameters); 381 free(parameter->values); 382 } 383 384 385 static void 386 free_settings(settings_handle *handle) 387 { 388 int32 i; 389 for (i = handle->settings.parameter_count; i-- > 0;) 390 free_parameter(&handle->settings.parameters[i]); 391 392 free(handle->settings.parameters); 393 free(handle->text); 394 free(handle); 395 } 396 397 398 static settings_handle * 399 new_settings(char *buffer, const char *driverName) 400 { 401 settings_handle *handle = (settings_handle*)malloc(sizeof(settings_handle)); 402 if (handle == NULL) 403 return NULL; 404 405 handle->magic = SETTINGS_MAGIC; 406 handle->text = buffer; 407 408 #ifdef _KERNEL_MODE 409 handle->ref_count = 1; 410 strlcpy(handle->name, driverName, sizeof(handle->name)); 411 #endif 412 413 if (parse_settings(handle) == B_OK) 414 return handle; 415 416 free(handle); 417 return NULL; 418 } 419 420 421 static settings_handle * 422 load_driver_settings_from_file(int file, const char *driverName) 423 { 424 struct stat stat; 425 426 // Allocate a buffer and read the whole file into it. 427 // We will keep this buffer in memory, until the settings 428 // are unloaded. 429 // The driver_parameter::name field will point directly 430 // to this buffer. 431 432 if (fstat(file, &stat) < B_OK) 433 return NULL; 434 435 if (stat.st_size > B_OK && stat.st_size < MAX_SETTINGS_SIZE) { 436 char *text = (char *)malloc(stat.st_size + 1); 437 if (text != NULL && read(file, text, stat.st_size) == stat.st_size) { 438 settings_handle *handle; 439 440 text[stat.st_size] = '\0'; 441 // make sure the string is null terminated 442 // to avoid misbehaviour 443 444 handle = new_settings(text, driverName); 445 if (handle != NULL) { 446 // everything went fine! 447 return handle; 448 } 449 450 free(handle); 451 } 452 // "text" might be NULL here, but that's allowed 453 free(text); 454 } 455 456 return NULL; 457 } 458 459 460 static bool 461 put_string(char **_buffer, size_t *_bufferSize, char *string) 462 { 463 size_t length, reserved, quotes; 464 char *buffer = *_buffer, c; 465 bool quoted; 466 467 if (string == NULL) 468 return true; 469 470 for (length = reserved = quotes = 0; (c = string[length]) != '\0'; length++) { 471 if (c == '"') 472 quotes++; 473 else if (is_word_break(c)) 474 reserved++; 475 } 476 quoted = reserved || quotes; 477 478 // update _bufferSize in any way, so that we can chain several 479 // of these calls without having to check the return value 480 // everytime 481 *_bufferSize -= length + (quoted ? 2 + quotes : 0); 482 483 if (*_bufferSize <= 0) 484 return false; 485 486 if (quoted) 487 *(buffer++) = '"'; 488 489 for (;(c = string[0]) != '\0'; string++) { 490 if (c == '"') 491 *(buffer++) = '\\'; 492 493 *(buffer++) = c; 494 } 495 496 if (quoted) 497 *(buffer++) = '"'; 498 499 buffer[0] = '\0'; 500 501 // update the buffer position 502 *_buffer = buffer; 503 504 return true; 505 } 506 507 508 static bool 509 put_chars(char **_buffer, size_t *_bufferSize, const char *chars) 510 { 511 char *buffer = *_buffer; 512 size_t length; 513 514 if (chars == NULL) 515 return true; 516 517 length = strlen(chars); 518 *_bufferSize -= length; 519 520 if (*_bufferSize <= 0) 521 return false; 522 523 memcpy(buffer, chars, length); 524 buffer += length; 525 buffer[0] = '\0'; 526 527 // update the buffer position 528 *_buffer = buffer; 529 530 return true; 531 } 532 533 534 static bool 535 put_char(char **_buffer, size_t *_bufferSize, char c) 536 { 537 char *buffer = *_buffer; 538 539 *_bufferSize -= 1; 540 541 if (*_bufferSize <= 0) 542 return false; 543 544 buffer[0] = c; 545 buffer[1] = '\0'; 546 547 // update the buffer position 548 *_buffer = buffer + 1; 549 550 return true; 551 } 552 553 554 static void 555 put_level_space(char **_buffer, size_t *_bufferSize, int32 level) 556 { 557 while (level-- > 0) 558 put_char(_buffer, _bufferSize, '\t'); 559 } 560 561 562 static void 563 put_parameter(char **_buffer, size_t *_bufferSize, 564 struct driver_parameter *parameter, int32 level, bool flat) 565 { 566 int32 i; 567 568 if (!flat) 569 put_level_space(_buffer, _bufferSize, level); 570 571 put_string(_buffer, _bufferSize, parameter->name); 572 if (flat && parameter->value_count > 0) 573 put_chars(_buffer, _bufferSize, " ="); 574 575 for (i = 0; i < parameter->value_count; i++) { 576 put_char(_buffer, _bufferSize, ' '); 577 put_string(_buffer, _bufferSize, parameter->values[i]); 578 } 579 580 if (parameter->parameter_count > 0) { 581 put_chars(_buffer, _bufferSize, " {"); 582 if (!flat) 583 put_char(_buffer, _bufferSize, '\n'); 584 585 for (i = 0; i < parameter->parameter_count; i++) { 586 put_parameter(_buffer, _bufferSize, ¶meter->parameters[i], 587 level + 1, flat); 588 589 if (parameter->parameters[i].parameter_count == 0) 590 put_chars(_buffer, _bufferSize, flat ? "; " : "\n"); 591 } 592 593 if (!flat) 594 put_level_space(_buffer, _bufferSize, level); 595 put_chars(_buffer, _bufferSize, flat ? "}" : "}\n"); 596 } 597 } 598 599 600 // #pragma mark - Kernel only functions 601 602 603 #ifdef _KERNEL_MODE 604 static settings_handle * 605 find_driver_settings(const char *name) 606 { 607 settings_handle *handle = NULL; 608 609 ASSERT_LOCKED_MUTEX(&sLock); 610 611 while ((handle = (settings_handle*)list_get_next_item(&sHandles, handle)) 612 != NULL) { 613 if (!strcmp(handle->name, name)) 614 return handle; 615 } 616 617 return NULL; 618 } 619 620 621 status_t 622 driver_settings_init(kernel_args *args) 623 { 624 struct driver_settings_file *settings = args->driver_settings; 625 626 // Move the preloaded driver settings over to the kernel 627 628 list_init(&sHandles); 629 630 while (settings != NULL) { 631 settings_handle *handle 632 = (settings_handle*)malloc(sizeof(settings_handle)); 633 if (handle == NULL) 634 return B_NO_MEMORY; 635 636 if (settings->size != 0) { 637 handle->text = (char*)malloc(settings->size + 1); 638 if (handle->text == NULL) { 639 free(handle); 640 return B_NO_MEMORY; 641 } 642 643 memcpy(handle->text, settings->buffer, settings->size); 644 handle->text[settings->size] = '\0'; 645 // null terminate the buffer 646 } else 647 handle->text = NULL; 648 649 strlcpy(handle->name, settings->name, sizeof(handle->name)); 650 handle->settings.parameters = NULL; 651 handle->settings.parameter_count = 0; 652 handle->magic = 0; 653 // this triggers parsing the settings when they are actually used 654 655 if (!strcmp(handle->name, B_SAFEMODE_DRIVER_SETTINGS)) { 656 // These settings cannot be reloaded, so we better don't throw 657 // them away. 658 handle->ref_count = 1; 659 } else 660 handle->ref_count = 0; 661 662 list_add_item(&sHandles, handle); 663 664 settings = settings->next; 665 } 666 667 return B_OK; 668 } 669 #endif 670 671 672 // #pragma mark - public API 673 674 675 status_t 676 unload_driver_settings(void *_handle) 677 { 678 settings_handle *handle = (settings_handle *)_handle; 679 if (!check_handle(handle)) 680 return B_BAD_VALUE; 681 682 #ifdef _KERNEL_MODE 683 mutex_lock(&sLock); 684 if (--handle->ref_count == 0 && gBootDevice > 0) { 685 // don't unload an handle when /boot is not available 686 list_remove_link(&handle->link); 687 } else 688 handle = NULL; 689 mutex_unlock(&sLock); 690 #endif 691 692 if (handle != NULL) 693 free_settings(handle); 694 695 return B_OK; 696 } 697 698 699 void * 700 load_driver_settings(const char *driverName) 701 { 702 settings_handle *handle; 703 int file = -1; 704 705 if (driverName == NULL) 706 return NULL; 707 708 #ifdef _KERNEL_MODE 709 // see if we already have these settings loaded 710 mutex_lock(&sLock); 711 handle = find_driver_settings(driverName); 712 if (handle != NULL && handle->ref_count == 0 && gBootDevice > 0) { 713 // A handle with a zero ref_count should be unloaded if /boot is 714 // available. 715 list_remove_link(&handle->link); 716 free_settings(handle); 717 } else if (handle != NULL) { 718 handle->ref_count++; 719 720 // we got it, now let's see if it already has been parsed 721 if (handle->magic != SETTINGS_MAGIC) { 722 handle->magic = SETTINGS_MAGIC; 723 724 if (parse_settings(handle) != B_OK) { 725 // no valid settings, let's cut down its memory requirements 726 free(handle->text); 727 handle->text = NULL; 728 handle = NULL; 729 } 730 } 731 mutex_unlock(&sLock); 732 return handle; 733 } 734 735 // we are allowed to call the driver settings pretty early in the boot process 736 if (gKernelStartup) { 737 mutex_unlock(&sLock); 738 return NULL; 739 } 740 #endif // _KERNEL_MODE 741 #ifdef _BOOT_MODE 742 // see if we already have these settings loaded 743 { 744 struct driver_settings_file *settings = gKernelArgs.driver_settings; 745 while (settings != NULL) { 746 if (!strcmp(settings->name, driverName)) { 747 // we have it - since the buffer is clobbered, we have to 748 // copy its contents, though 749 char *text = (char*)malloc(settings->size + 1); 750 if (text == NULL) 751 return NULL; 752 753 memcpy(text, settings->buffer, settings->size + 1); 754 return new_settings(text, driverName); 755 } 756 settings = settings->next; 757 } 758 } 759 #endif // _BOOT_MODE 760 761 // open the settings from the standardized location 762 if (driverName[0] != '/') { 763 char path[B_FILE_NAME_LENGTH + 64]; 764 765 #ifdef _BOOT_MODE 766 // TODO: for now the boot loader does not support find_directory() 767 // (it might get a simplified version of it) 768 strcpy(path, "/boot/home/config/settings"); 769 #else 770 // TODO: use B_COMMON_SETTINGS_DIRECTORY instead! 771 if (find_directory(B_USER_SETTINGS_DIRECTORY, -1, false, path, 772 sizeof(path)) == B_OK) 773 #endif 774 { 775 strlcat(path, SETTINGS_DIRECTORY, sizeof(path)); 776 strlcat(path, driverName, sizeof(path)); 777 } 778 779 file = open(path, O_RDONLY); 780 } else 781 file = open(driverName, O_RDONLY); 782 783 if (file < B_OK) { 784 #ifdef _KERNEL_MODE 785 mutex_unlock(&sLock); 786 #endif 787 return NULL; 788 } 789 790 handle = load_driver_settings_from_file(file, driverName); 791 792 #ifdef _KERNEL_MODE 793 if (handle != NULL) 794 list_add_item(&sHandles, handle); 795 mutex_unlock(&sLock); 796 #endif 797 798 close(file); 799 return (void *)handle; 800 } 801 802 803 /** Loads a driver settings file using the full path, instead of 804 * only defining the leaf name (as load_driver_settings() does). 805 * I am not sure if this function is really necessary - I would 806 * probably prefer something like a search order (if it's not 807 * an absolute path): 808 * ~/config/settings/kernel/driver 809 * current directory 810 * That would render this function useless. 811 */ 812 813 #if 0 814 void * 815 load_driver_settings_from_path(const char *path) 816 { 817 settings_handle *handle; 818 int file; 819 820 if (path == NULL) 821 return NULL; 822 823 file = open(path, O_RDONLY); 824 if (file < B_OK) 825 return NULL; 826 827 handle = load_driver_settings_from_file(file); 828 829 close(file); 830 return (void *)handle; 831 } 832 #endif 833 834 835 /*! 836 Returns a new driver_settings handle that has the parsed contents 837 of the passed string. 838 You can get an empty driver_settings object when you pass NULL as 839 the "settingsString" parameter. 840 */ 841 void * 842 parse_driver_settings_string(const char *settingsString) 843 { 844 // we simply copy the whole string to use it as our internal buffer 845 char *text = strdup(settingsString); 846 if (settingsString == NULL || text != NULL) { 847 settings_handle *handle 848 = (settings_handle*)malloc(sizeof(settings_handle)); 849 if (handle != NULL) { 850 handle->magic = SETTINGS_MAGIC; 851 handle->text = text; 852 853 if (parse_settings(handle) == B_OK) 854 return handle; 855 856 free(handle); 857 } 858 free(text); 859 } 860 861 return NULL; 862 } 863 864 865 /*! 866 This function prints out a driver settings structure to a human 867 readable string. 868 It's either in standard style or the single line style speficied 869 by the "flat" parameter. 870 If the buffer is too small to hold the string, B_BUFFER_OVERFLOW 871 is returned, and the needed amount of bytes if placed in the 872 "_bufferSize" parameter. 873 If the "handle" parameter is not a valid driver settings handle, or 874 the "buffer" parameter is NULL, B_BAD_VALUE is returned. 875 */ 876 status_t 877 get_driver_settings_string(void *_handle, char *buffer, size_t *_bufferSize, 878 bool flat) 879 { 880 settings_handle *handle = (settings_handle *)_handle; 881 size_t bufferSize = *_bufferSize; 882 int32 i; 883 884 if (!check_handle(handle) || !buffer || *_bufferSize == 0) 885 return B_BAD_VALUE; 886 887 for (i = 0; i < handle->settings.parameter_count; i++) { 888 put_parameter(&buffer, &bufferSize, &handle->settings.parameters[i], 889 0, flat); 890 } 891 892 *_bufferSize -= bufferSize; 893 return bufferSize >= 0 ? B_OK : B_BUFFER_OVERFLOW; 894 } 895 896 897 /*! 898 Matches the first value of the parameter matching "keyName" with a set 899 of boolean values like 1/true/yes/on/enabled/... 900 Returns "unknownValue" if the parameter could not be found or doesn't 901 have any valid boolean setting, and "noArgValue" if the parameter 902 doesn't have any values. 903 Also returns "unknownValue" if the handle passed in was not valid. 904 */ 905 bool 906 get_driver_boolean_parameter(void *_handle, const char *keyName, 907 bool unknownValue, bool noArgValue) 908 { 909 settings_handle *handle = (settings_handle*)_handle; 910 driver_parameter *parameter; 911 char *boolean; 912 913 if (!check_handle(handle)) 914 return unknownValue; 915 916 // check for the parameter 917 if ((parameter = get_parameter(handle, keyName)) == NULL) 918 return unknownValue; 919 920 // check for the argument 921 if (parameter->value_count <= 0) 922 return noArgValue; 923 924 boolean = parameter->values[0]; 925 if (!strcmp(boolean, "1") 926 || !strcasecmp(boolean, "true") 927 || !strcasecmp(boolean, "yes") 928 || !strcasecmp(boolean, "on") 929 || !strcasecmp(boolean, "enable") 930 || !strcasecmp(boolean, "enabled")) 931 return true; 932 933 if (!strcmp(boolean, "0") 934 || !strcasecmp(boolean, "false") 935 || !strcasecmp(boolean, "no") 936 || !strcasecmp(boolean, "off") 937 || !strcasecmp(boolean, "disable") 938 || !strcasecmp(boolean, "disabled")) 939 return false; 940 941 // if no known keyword is found, "unknownValue" is returned 942 return unknownValue; 943 } 944 945 946 const char * 947 get_driver_parameter(void *_handle, const char *keyName, 948 const char *unknownValue, const char *noArgValue) 949 { 950 settings_handle* handle = (settings_handle*)_handle; 951 struct driver_parameter *parameter; 952 953 if (!check_handle(handle)) 954 return unknownValue; 955 956 // check for the parameter 957 if ((parameter = get_parameter(handle, keyName)) == NULL) 958 return unknownValue; 959 960 // check for the argument 961 if (parameter->value_count <= 0) 962 return noArgValue; 963 964 return parameter->values[0]; 965 } 966 967 968 const driver_settings * 969 get_driver_settings(void *handle) 970 { 971 if (!check_handle((settings_handle*)handle)) 972 return NULL; 973 974 return &((settings_handle *)handle)->settings; 975 } 976 977 978 // this creates an alias of the above function 979 // unload_driver_settings() is the same as delete_driver_settings() 980 extern "C" __typeof(unload_driver_settings) delete_driver_settings 981 __attribute__((alias ("unload_driver_settings"))); 982 983