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