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; 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 free(handle); 462 } 463 // "text" might be NULL here, but that's allowed 464 free(text); 465 } 466 467 return NULL; 468 } 469 470 471 static bool 472 put_string(char **_buffer, ssize_t *_bufferSize, char *string) 473 { 474 size_t length, reserved, quotes; 475 char *buffer = *_buffer, c; 476 bool quoted; 477 478 if (string == NULL) 479 return true; 480 481 for (length = reserved = quotes = 0; (c = string[length]) != '\0'; length++) { 482 if (c == '"') 483 quotes++; 484 else if (is_word_break(c)) 485 reserved++; 486 } 487 quoted = reserved || quotes; 488 489 // update _bufferSize in any way, so that we can chain several 490 // of these calls without having to check the return value 491 // everytime 492 *_bufferSize -= length + (quoted ? 2 + quotes : 0); 493 494 if (*_bufferSize <= 0) 495 return false; 496 497 if (quoted) 498 *(buffer++) = '"'; 499 500 for (;(c = string[0]) != '\0'; string++) { 501 if (c == '"') 502 *(buffer++) = '\\'; 503 504 *(buffer++) = c; 505 } 506 507 if (quoted) 508 *(buffer++) = '"'; 509 510 buffer[0] = '\0'; 511 512 // update the buffer position 513 *_buffer = buffer; 514 515 return true; 516 } 517 518 519 static bool 520 put_chars(char **_buffer, ssize_t *_bufferSize, const char *chars) 521 { 522 char *buffer = *_buffer; 523 size_t length; 524 525 if (chars == NULL) 526 return true; 527 528 length = strlen(chars); 529 *_bufferSize -= length; 530 531 if (*_bufferSize <= 0) 532 return false; 533 534 memcpy(buffer, chars, length); 535 buffer += length; 536 buffer[0] = '\0'; 537 538 // update the buffer position 539 *_buffer = buffer; 540 541 return true; 542 } 543 544 545 static bool 546 put_char(char **_buffer, ssize_t *_bufferSize, char c) 547 { 548 char *buffer = *_buffer; 549 550 *_bufferSize -= 1; 551 552 if (*_bufferSize <= 0) 553 return false; 554 555 buffer[0] = c; 556 buffer[1] = '\0'; 557 558 // update the buffer position 559 *_buffer = buffer + 1; 560 561 return true; 562 } 563 564 565 static void 566 put_level_space(char **_buffer, ssize_t *_bufferSize, int32 level) 567 { 568 while (level-- > 0) 569 put_char(_buffer, _bufferSize, '\t'); 570 } 571 572 573 static void 574 put_parameter(char **_buffer, ssize_t *_bufferSize, 575 struct driver_parameter *parameter, int32 level, bool flat) 576 { 577 int32 i; 578 579 if (!flat) 580 put_level_space(_buffer, _bufferSize, level); 581 582 put_string(_buffer, _bufferSize, parameter->name); 583 if (flat && parameter->value_count > 0) 584 put_chars(_buffer, _bufferSize, " ="); 585 586 for (i = 0; i < parameter->value_count; i++) { 587 put_char(_buffer, _bufferSize, ' '); 588 put_string(_buffer, _bufferSize, parameter->values[i]); 589 } 590 591 if (parameter->parameter_count > 0) { 592 put_chars(_buffer, _bufferSize, " {"); 593 if (!flat) 594 put_char(_buffer, _bufferSize, '\n'); 595 596 for (i = 0; i < parameter->parameter_count; i++) { 597 put_parameter(_buffer, _bufferSize, ¶meter->parameters[i], 598 level + 1, flat); 599 600 if (parameter->parameters[i].parameter_count == 0) 601 put_chars(_buffer, _bufferSize, flat ? "; " : "\n"); 602 } 603 604 if (!flat) 605 put_level_space(_buffer, _bufferSize, level); 606 put_chars(_buffer, _bufferSize, flat ? "}" : "}\n"); 607 } 608 } 609 610 611 // #pragma mark - Kernel only functions 612 613 614 #ifdef _KERNEL_MODE 615 static settings_handle * 616 find_driver_settings(const char *name) 617 { 618 settings_handle *handle = NULL; 619 620 ASSERT_LOCKED_MUTEX(&sLock); 621 622 while ((handle = (settings_handle*)list_get_next_item(&sHandles, handle)) 623 != NULL) { 624 if (!strcmp(handle->name, name)) 625 return handle; 626 } 627 628 return NULL; 629 } 630 631 632 status_t 633 driver_settings_init(kernel_args *args) 634 { 635 struct driver_settings_file *settings = args->driver_settings; 636 637 // Move the preloaded driver settings over to the kernel 638 639 list_init(&sHandles); 640 641 while (settings != NULL) { 642 settings_handle *handle 643 = (settings_handle*)malloc(sizeof(settings_handle)); 644 if (handle == NULL) 645 return B_NO_MEMORY; 646 647 if (settings->size != 0) { 648 handle->text = (char*)malloc(settings->size + 1); 649 if (handle->text == NULL) { 650 free(handle); 651 return B_NO_MEMORY; 652 } 653 654 memcpy(handle->text, settings->buffer, settings->size); 655 handle->text[settings->size] = '\0'; 656 // null terminate the buffer 657 } else 658 handle->text = NULL; 659 660 strlcpy(handle->name, settings->name, sizeof(handle->name)); 661 handle->settings.parameters = NULL; 662 handle->settings.parameter_count = 0; 663 handle->magic = 0; 664 // this triggers parsing the settings when they are actually used 665 666 if (!strcmp(handle->name, B_SAFEMODE_DRIVER_SETTINGS)) { 667 // These settings cannot be reloaded, so we better don't throw 668 // them away. 669 handle->ref_count = 1; 670 } else 671 handle->ref_count = 0; 672 673 list_add_item(&sHandles, handle); 674 675 settings = settings->next; 676 } 677 678 return B_OK; 679 } 680 #endif 681 682 683 // #pragma mark - public API 684 685 686 status_t 687 unload_driver_settings(void *_handle) 688 { 689 settings_handle *handle = (settings_handle *)_handle; 690 if (!check_handle(handle)) 691 return B_BAD_VALUE; 692 693 #ifdef _KERNEL_MODE 694 mutex_lock(&sLock); 695 696 if (handle->ref_count > 0) { 697 if (--handle->ref_count == 0 && gBootDevice > 0) { 698 // don't unload an handle when /boot is not available 699 list_remove_link(&handle->link); 700 } else 701 handle = NULL; 702 } 703 mutex_unlock(&sLock); 704 #endif 705 706 if (handle != NULL) 707 free_settings(handle); 708 709 return B_OK; 710 } 711 712 713 void * 714 load_driver_settings(const char *driverName) 715 { 716 settings_handle *handle; 717 int file = -1; 718 719 if (driverName == NULL) 720 return NULL; 721 722 #ifdef _KERNEL_MODE 723 // see if we already have these settings loaded 724 mutex_lock(&sLock); 725 handle = find_driver_settings(driverName); 726 if (handle != NULL && handle->ref_count == 0 && gBootDevice > 0) { 727 // A handle with a zero ref_count should be unloaded if /boot is 728 // available. 729 list_remove_link(&handle->link); 730 free_settings(handle); 731 } else if (handle != NULL) { 732 handle->ref_count++; 733 734 // we got it, now let's see if it already has been parsed 735 if (handle->magic != SETTINGS_MAGIC) { 736 handle->magic = SETTINGS_MAGIC; 737 738 if (parse_settings(handle) != B_OK) { 739 // no valid settings, let's cut down its memory requirements 740 free(handle->text); 741 handle->text = NULL; 742 handle = NULL; 743 } 744 } 745 mutex_unlock(&sLock); 746 return handle; 747 } 748 749 // we are allowed to call the driver settings pretty early in the boot process 750 if (gKernelStartup) { 751 mutex_unlock(&sLock); 752 return NULL; 753 } 754 #endif // _KERNEL_MODE 755 #ifdef _BOOT_MODE 756 // see if we already have these settings loaded 757 { 758 struct driver_settings_file *settings = gKernelArgs.driver_settings; 759 while (settings != NULL) { 760 if (!strcmp(settings->name, driverName)) { 761 // we have it - since the buffer is clobbered, we have to 762 // copy its contents, though 763 char *text = (char*)malloc(settings->size + 1); 764 if (text == NULL) 765 return NULL; 766 767 memcpy(text, settings->buffer, settings->size + 1); 768 return new_settings(text, driverName); 769 } 770 settings = settings->next; 771 } 772 } 773 #endif // _BOOT_MODE 774 775 // open the settings from the standardized location 776 if (driverName[0] != '/') { 777 char path[B_FILE_NAME_LENGTH + 64]; 778 779 #ifdef _BOOT_MODE 780 strcpy(path, kUserSettingsDirectory); 781 #else 782 // TODO: use B_SYSTEM_SETTINGS_DIRECTORY instead! 783 if (__find_directory(B_USER_SETTINGS_DIRECTORY, -1, false, path, 784 sizeof(path)) == B_OK) 785 #endif 786 { 787 strlcat(path, SETTINGS_DIRECTORY, sizeof(path)); 788 strlcat(path, driverName, sizeof(path)); 789 } 790 791 file = open(path, O_RDONLY); 792 } else 793 file = open(driverName, O_RDONLY); 794 795 if (file < B_OK) { 796 #ifdef _KERNEL_MODE 797 mutex_unlock(&sLock); 798 #endif 799 return NULL; 800 } 801 802 handle = load_driver_settings_from_file(file, driverName); 803 804 #ifdef _KERNEL_MODE 805 if (handle != NULL) 806 list_add_item(&sHandles, handle); 807 mutex_unlock(&sLock); 808 #endif 809 810 close(file); 811 return (void *)handle; 812 } 813 814 815 void* 816 load_driver_settings_file(int fd) 817 { 818 return load_driver_settings_from_file(fd, NULL); 819 } 820 821 822 /*! 823 Returns a new driver_settings handle that has the parsed contents 824 of the passed string. 825 You can get an empty driver_settings object when you pass NULL as 826 the "settingsString" parameter. 827 */ 828 void * 829 parse_driver_settings_string(const char *settingsString) 830 { 831 char *text = NULL; 832 if (settingsString != NULL) { 833 // we simply copy the whole string to use it as our internal buffer 834 text = strdup(settingsString); 835 if (text == NULL) 836 return NULL; 837 } 838 839 settings_handle *handle = new_settings(text, NULL); 840 if (handle == NULL) 841 free(text); 842 return handle; 843 } 844 845 846 /*! 847 This function prints out a driver settings structure to a human 848 readable string. 849 It's either in standard style or the single line style speficied 850 by the "flat" parameter. 851 If the buffer is too small to hold the string, B_BUFFER_OVERFLOW 852 is returned, and the needed amount of bytes if placed in the 853 "_bufferSize" parameter. 854 If the "handle" parameter is not a valid driver settings handle, or 855 the "buffer" parameter is NULL, B_BAD_VALUE is returned. 856 */ 857 status_t 858 get_driver_settings_string(void *_handle, char *buffer, ssize_t *_bufferSize, 859 bool flat) 860 { 861 settings_handle *handle = (settings_handle *)_handle; 862 ssize_t bufferSize = *_bufferSize; 863 int32 i; 864 865 if (!check_handle(handle) || !buffer || *_bufferSize == 0) 866 return B_BAD_VALUE; 867 868 for (i = 0; i < handle->settings.parameter_count; i++) { 869 put_parameter(&buffer, &bufferSize, &handle->settings.parameters[i], 870 0, flat); 871 } 872 873 *_bufferSize -= bufferSize; 874 return bufferSize >= 0 ? B_OK : B_BUFFER_OVERFLOW; 875 } 876 877 878 /*! 879 Matches the first value of the parameter matching "keyName" with a set 880 of boolean values like 1/true/yes/on/enabled/... 881 Returns "unknownValue" if the parameter could not be found or doesn't 882 have any valid boolean setting, and "noArgValue" if the parameter 883 doesn't have any values. 884 Also returns "unknownValue" if the handle passed in was not valid. 885 */ 886 bool 887 get_driver_boolean_parameter(void *_handle, const char *keyName, 888 bool unknownValue, bool noArgValue) 889 { 890 settings_handle *handle = (settings_handle*)_handle; 891 driver_parameter *parameter; 892 char *boolean; 893 894 if (!check_handle(handle)) 895 return unknownValue; 896 897 // check for the parameter 898 if ((parameter = get_parameter(handle, keyName)) == NULL) 899 return unknownValue; 900 901 // check for the argument 902 if (parameter->value_count <= 0) 903 return noArgValue; 904 905 boolean = parameter->values[0]; 906 if (!strcmp(boolean, "1") 907 || !strcasecmp(boolean, "true") 908 || !strcasecmp(boolean, "yes") 909 || !strcasecmp(boolean, "on") 910 || !strcasecmp(boolean, "enable") 911 || !strcasecmp(boolean, "enabled")) 912 return true; 913 914 if (!strcmp(boolean, "0") 915 || !strcasecmp(boolean, "false") 916 || !strcasecmp(boolean, "no") 917 || !strcasecmp(boolean, "off") 918 || !strcasecmp(boolean, "disable") 919 || !strcasecmp(boolean, "disabled")) 920 return false; 921 922 // if no known keyword is found, "unknownValue" is returned 923 return unknownValue; 924 } 925 926 927 const char * 928 get_driver_parameter(void *_handle, const char *keyName, 929 const char *unknownValue, const char *noArgValue) 930 { 931 settings_handle* handle = (settings_handle*)_handle; 932 struct driver_parameter *parameter; 933 934 if (!check_handle(handle)) 935 return unknownValue; 936 937 // check for the parameter 938 if ((parameter = get_parameter(handle, keyName)) == NULL) 939 return unknownValue; 940 941 // check for the argument 942 if (parameter->value_count <= 0) 943 return noArgValue; 944 945 return parameter->values[0]; 946 } 947 948 949 const driver_settings * 950 get_driver_settings(void *handle) 951 { 952 if (!check_handle((settings_handle*)handle)) 953 return NULL; 954 955 return &((settings_handle *)handle)->settings; 956 } 957 958 959 status_t 960 delete_driver_settings(void *_handle) 961 { 962 return unload_driver_settings(_handle); 963 } 964