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