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 bool 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 return *_bufferSize >= 0; 599 } 600 601 602 // #pragma mark - Kernel only functions 603 604 605 #ifdef _KERNEL_MODE 606 static settings_handle * 607 find_driver_settings(const char *name) 608 { 609 settings_handle *handle = NULL; 610 611 ASSERT_LOCKED_MUTEX(&sLock); 612 613 while ((handle = (settings_handle*)list_get_next_item(&sHandles, handle)) 614 != NULL) { 615 if (!strcmp(handle->name, name)) 616 return handle; 617 } 618 619 return NULL; 620 } 621 622 623 status_t 624 driver_settings_init(kernel_args *args) 625 { 626 struct driver_settings_file *settings = args->driver_settings; 627 628 // Move the preloaded driver settings over to the kernel 629 630 list_init(&sHandles); 631 632 while (settings != NULL) { 633 settings_handle *handle 634 = (settings_handle*)malloc(sizeof(settings_handle)); 635 if (handle == NULL) 636 return B_NO_MEMORY; 637 638 if (settings->size != 0) { 639 handle->text = (char*)malloc(settings->size + 1); 640 if (handle->text == NULL) { 641 free(handle); 642 return B_NO_MEMORY; 643 } 644 645 memcpy(handle->text, settings->buffer, settings->size); 646 handle->text[settings->size] = '\0'; 647 // null terminate the buffer 648 } else 649 handle->text = NULL; 650 651 strlcpy(handle->name, settings->name, sizeof(handle->name)); 652 handle->settings.parameters = NULL; 653 handle->settings.parameter_count = 0; 654 handle->magic = 0; 655 // this triggers parsing the settings when they are actually used 656 657 if (!strcmp(handle->name, B_SAFEMODE_DRIVER_SETTINGS)) { 658 // These settings cannot be reloaded, so we better don't throw 659 // them away. 660 handle->ref_count = 1; 661 } else 662 handle->ref_count = 0; 663 664 list_add_item(&sHandles, handle); 665 666 settings = settings->next; 667 } 668 669 return B_OK; 670 } 671 #endif 672 673 674 // #pragma mark - public API 675 676 677 status_t 678 unload_driver_settings(void *_handle) 679 { 680 settings_handle *handle = (settings_handle *)_handle; 681 if (!check_handle(handle)) 682 return B_BAD_VALUE; 683 684 #ifdef _KERNEL_MODE 685 mutex_lock(&sLock); 686 if (--handle->ref_count == 0 && gBootDevice > 0) { 687 // don't unload an handle when /boot is not available 688 list_remove_link(&handle->link); 689 } else 690 handle = NULL; 691 mutex_unlock(&sLock); 692 #endif 693 694 if (handle != NULL) 695 free_settings(handle); 696 697 return B_OK; 698 } 699 700 701 void * 702 load_driver_settings(const char *driverName) 703 { 704 settings_handle *handle; 705 int file = -1; 706 707 if (driverName == NULL) 708 return NULL; 709 710 #ifdef _KERNEL_MODE 711 // see if we already have these settings loaded 712 mutex_lock(&sLock); 713 handle = find_driver_settings(driverName); 714 if (handle != NULL && handle->ref_count == 0 && gBootDevice > 0) { 715 // A handle with a zero ref_count should be unloaded if /boot is 716 // available. 717 list_remove_link(&handle->link); 718 free_settings(handle); 719 } else if (handle != NULL) { 720 handle->ref_count++; 721 722 // we got it, now let's see if it already has been parsed 723 if (handle->magic != SETTINGS_MAGIC) { 724 handle->magic = SETTINGS_MAGIC; 725 726 if (parse_settings(handle) != B_OK) { 727 // no valid settings, let's cut down its memory requirements 728 free(handle->text); 729 handle->text = NULL; 730 handle = NULL; 731 } 732 } 733 mutex_unlock(&sLock); 734 return handle; 735 } 736 737 // we are allowed to call the driver settings pretty early in the boot process 738 if (gKernelStartup) { 739 mutex_unlock(&sLock); 740 return NULL; 741 } 742 #endif // _KERNEL_MODE 743 #ifdef _BOOT_MODE 744 // see if we already have these settings loaded 745 { 746 struct driver_settings_file *settings = gKernelArgs.driver_settings; 747 while (settings != NULL) { 748 if (!strcmp(settings->name, driverName)) { 749 // we have it - since the buffer is clobbered, we have to 750 // copy its contents, though 751 char *text = (char*)malloc(settings->size + 1); 752 if (text == NULL) 753 return NULL; 754 755 memcpy(text, settings->buffer, settings->size + 1); 756 return new_settings(text, driverName); 757 } 758 settings = settings->next; 759 } 760 } 761 #endif // _BOOT_MODE 762 763 // open the settings from the standardized location 764 if (driverName[0] != '/') { 765 char path[B_FILE_NAME_LENGTH + 64]; 766 767 #ifdef _BOOT_MODE 768 // TODO: for now the boot loader does not support find_directory() 769 // (it might get a simplified version of it) 770 strcpy(path, "/boot/home/config/settings"); 771 #else 772 // TODO: use B_COMMON_SETTINGS_DIRECTORY instead! 773 if (find_directory(B_USER_SETTINGS_DIRECTORY, -1, false, path, 774 sizeof(path)) == B_OK) 775 #endif 776 { 777 strlcat(path, SETTINGS_DIRECTORY, sizeof(path)); 778 strlcat(path, driverName, sizeof(path)); 779 } 780 781 file = open(path, O_RDONLY); 782 } else 783 file = open(driverName, O_RDONLY); 784 785 if (file < B_OK) { 786 #ifdef _KERNEL_MODE 787 mutex_unlock(&sLock); 788 #endif 789 close(file); 790 return NULL; 791 } 792 793 handle = load_driver_settings_from_file(file, driverName); 794 795 #ifdef _KERNEL_MODE 796 if (handle != NULL) 797 list_add_item(&sHandles, handle); 798 mutex_unlock(&sLock); 799 #endif 800 801 close(file); 802 return (void *)handle; 803 } 804 805 806 /** Loads a driver settings file using the full path, instead of 807 * only defining the leaf name (as load_driver_settings() does). 808 * I am not sure if this function is really necessary - I would 809 * probably prefer something like a search order (if it's not 810 * an absolute path): 811 * ~/config/settings/kernel/driver 812 * current directory 813 * That would render this function useless. 814 */ 815 816 #if 0 817 void * 818 load_driver_settings_from_path(const char *path) 819 { 820 settings_handle *handle; 821 int file; 822 823 if (path == NULL) 824 return NULL; 825 826 file = open(path, O_RDONLY); 827 if (file < B_OK) 828 return NULL; 829 830 handle = load_driver_settings_from_file(file); 831 832 close(file); 833 return (void *)handle; 834 } 835 #endif 836 837 838 /*! 839 Returns a new driver_settings handle that has the parsed contents 840 of the passed string. 841 You can get an empty driver_settings object when you pass NULL as 842 the "settingsString" parameter. 843 */ 844 void * 845 parse_driver_settings_string(const char *settingsString) 846 { 847 // we simply copy the whole string to use it as our internal buffer 848 char *text = strdup(settingsString); 849 if (settingsString == NULL || text != NULL) { 850 settings_handle *handle 851 = (settings_handle*)malloc(sizeof(settings_handle)); 852 if (handle != NULL) { 853 handle->magic = SETTINGS_MAGIC; 854 handle->text = text; 855 856 if (parse_settings(handle) == B_OK) 857 return handle; 858 859 free(handle); 860 } 861 free(text); 862 } 863 864 return NULL; 865 } 866 867 868 /*! 869 This function prints out a driver settings structure to a human 870 readable string. 871 It's either in standard style or the single line style speficied 872 by the "flat" parameter. 873 If the buffer is too small to hold the string, B_BUFFER_OVERFLOW 874 is returned, and the needed amount of bytes if placed in the 875 "_bufferSize" parameter. 876 If the "handle" parameter is not a valid driver settings handle, or 877 the "buffer" parameter is NULL, B_BAD_VALUE is returned. 878 */ 879 status_t 880 get_driver_settings_string(void *_handle, char *buffer, size_t *_bufferSize, 881 bool flat) 882 { 883 settings_handle *handle = (settings_handle *)_handle; 884 size_t bufferSize = *_bufferSize; 885 int32 i; 886 887 if (!check_handle(handle) || !buffer || *_bufferSize == 0) 888 return B_BAD_VALUE; 889 890 for (i = 0; i < handle->settings.parameter_count; i++) { 891 put_parameter(&buffer, &bufferSize, &handle->settings.parameters[i], 892 0, flat); 893 } 894 895 *_bufferSize -= bufferSize; 896 return bufferSize >= 0 ? B_OK : B_BUFFER_OVERFLOW; 897 } 898 899 900 /*! 901 Matches the first value of the parameter matching "keyName" with a set 902 of boolean values like 1/true/yes/on/enabled/... 903 Returns "unknownValue" if the parameter could not be found or doesn't 904 have any valid boolean setting, and "noArgValue" if the parameter 905 doesn't have any values. 906 Also returns "unknownValue" if the handle passed in was not valid. 907 */ 908 bool 909 get_driver_boolean_parameter(void *_handle, const char *keyName, 910 bool unknownValue, bool noArgValue) 911 { 912 settings_handle *handle = (settings_handle*)_handle; 913 driver_parameter *parameter; 914 char *boolean; 915 916 if (!check_handle(handle)) 917 return unknownValue; 918 919 // check for the parameter 920 if ((parameter = get_parameter(handle, keyName)) == NULL) 921 return unknownValue; 922 923 // check for the argument 924 if (parameter->value_count <= 0) 925 return noArgValue; 926 927 boolean = parameter->values[0]; 928 if (!strcmp(boolean, "1") 929 || !strcasecmp(boolean, "true") 930 || !strcasecmp(boolean, "yes") 931 || !strcasecmp(boolean, "on") 932 || !strcasecmp(boolean, "enable") 933 || !strcasecmp(boolean, "enabled")) 934 return true; 935 936 if (!strcmp(boolean, "0") 937 || !strcasecmp(boolean, "false") 938 || !strcasecmp(boolean, "no") 939 || !strcasecmp(boolean, "off") 940 || !strcasecmp(boolean, "disable") 941 || !strcasecmp(boolean, "disabled")) 942 return false; 943 944 // if no known keyword is found, "unknownValue" is returned 945 return unknownValue; 946 } 947 948 949 const char * 950 get_driver_parameter(void *_handle, const char *keyName, 951 const char *unknownValue, const char *noArgValue) 952 { 953 settings_handle* handle = (settings_handle*)_handle; 954 struct driver_parameter *parameter; 955 956 if (!check_handle(handle)) 957 return unknownValue; 958 959 // check for the parameter 960 if ((parameter = get_parameter(handle, keyName)) == NULL) 961 return unknownValue; 962 963 // check for the argument 964 if (parameter->value_count <= 0) 965 return noArgValue; 966 967 return parameter->values[0]; 968 } 969 970 971 const driver_settings * 972 get_driver_settings(void *handle) 973 { 974 if (!check_handle((settings_handle*)handle)) 975 return NULL; 976 977 return &((settings_handle *)handle)->settings; 978 } 979 980 981 // this creates an alias of the above function 982 // unload_driver_settings() is the same as delete_driver_settings() 983 extern "C" __typeof(unload_driver_settings) delete_driver_settings 984 __attribute__((alias ("unload_driver_settings"))); 985 986