185db3873SIngo Weinhold /* 285db3873SIngo Weinhold * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. 385db3873SIngo Weinhold * This file may be used under the terms of the MIT License. 485db3873SIngo Weinhold */ 585db3873SIngo Weinhold 685db3873SIngo Weinhold /*! \brief Implements the driver settings API 785db3873SIngo Weinhold This file is used by three different components with different needs: 885db3873SIngo Weinhold 1) the boot loader 985db3873SIngo Weinhold Buffers a list of settings files to move over to the kernel - the 1085db3873SIngo Weinhold actual buffering is located in the boot loader directly, though. 1185db3873SIngo Weinhold Creates driver_settings structures out of those on demand only. 1285db3873SIngo Weinhold 2) the kernel 1385db3873SIngo Weinhold Maintains a list of settings so that no disk access is required 1485db3873SIngo Weinhold for known settings (such as those passed over from the boot 1585db3873SIngo Weinhold loader). 1685db3873SIngo Weinhold 3) libroot.so 1785db3873SIngo Weinhold Exports the parser to userland applications, so that they can 1885db3873SIngo Weinhold easily make use of driver_settings styled files. 1985db3873SIngo Weinhold 2085db3873SIngo Weinhold The file has to be recompiled for every component separately, so that 2185db3873SIngo Weinhold it properly exports the required functionality (which is specified by 2285db3873SIngo Weinhold _BOOT_MODE for the boot loader, and _KERNEL_MODE for the kernel). 2385db3873SIngo Weinhold */ 2485db3873SIngo Weinhold 2585db3873SIngo Weinhold // The boot loader is compiled with kernel rules, but we want to explicitely 2685db3873SIngo Weinhold // differentiate between the two here. 2785db3873SIngo Weinhold #ifdef _BOOT_MODE 2885db3873SIngo Weinhold # undef _KERNEL_MODE 2985db3873SIngo Weinhold #endif 3085db3873SIngo Weinhold 31*2770bfe8SAdrien Destugues #include <BeBuild.h> 32323b6546SOliver Tappe #include <directories.h> 3385db3873SIngo Weinhold #include <driver_settings.h> 3485db3873SIngo Weinhold #include <FindDirectory.h> 3585db3873SIngo Weinhold #include <OS.h> 3685db3873SIngo Weinhold 3785db3873SIngo Weinhold #ifdef _KERNEL_MODE 3885db3873SIngo Weinhold # include <KernelExport.h> 3985db3873SIngo Weinhold # include <util/list.h> 4085db3873SIngo Weinhold # include <lock.h> 4185db3873SIngo Weinhold # include <kdriver_settings.h> 4285db3873SIngo Weinhold # include <kernel.h> 4385db3873SIngo Weinhold # include <boot/kernel_args.h> 4485db3873SIngo Weinhold # include <boot_device.h> 4585db3873SIngo Weinhold #endif 4685db3873SIngo Weinhold #ifdef _BOOT_MODE 4785db3873SIngo Weinhold # include <boot/kernel_args.h> 4885db3873SIngo Weinhold # include <boot/stage2.h> 49de49e349SIngo Weinhold #else 50de49e349SIngo Weinhold # include <find_directory_private.h> 5185db3873SIngo Weinhold #endif 5285db3873SIngo Weinhold 5385db3873SIngo Weinhold #include <stdlib.h> 5485db3873SIngo Weinhold #include <string.h> 553aeed660SJérôme Duval #include <strings.h> 5685db3873SIngo Weinhold #include <unistd.h> 5785db3873SIngo Weinhold #include <fcntl.h> 5885db3873SIngo Weinhold #include <ctype.h> 5985db3873SIngo Weinhold 6037c83f4eSIngo Weinhold #ifndef B_BUFFER_OVERFLOW 6185db3873SIngo Weinhold # define B_BUFFER_OVERFLOW B_ERROR 6285db3873SIngo Weinhold #endif 6385db3873SIngo Weinhold 6485db3873SIngo Weinhold #define SETTINGS_DIRECTORY "/kernel/drivers/" 6585db3873SIngo Weinhold #define SETTINGS_MAGIC 'DrvS' 6685db3873SIngo Weinhold 6785db3873SIngo Weinhold // Those maximum values are independent from the implementation - they 6885db3873SIngo Weinhold // have been chosen to make the code more robust against bad files 6985db3873SIngo Weinhold #define MAX_SETTINGS_SIZE 32768 7085db3873SIngo Weinhold #define MAX_SETTINGS_LEVEL 8 7185db3873SIngo Weinhold 7285db3873SIngo Weinhold #define CONTINUE_PARAMETER 1 7385db3873SIngo Weinhold #define NO_PARAMETER 2 7485db3873SIngo Weinhold 7585db3873SIngo Weinhold 7685db3873SIngo Weinhold typedef struct settings_handle { 7785db3873SIngo Weinhold #ifdef _KERNEL_MODE 7885db3873SIngo Weinhold list_link link; 7985db3873SIngo Weinhold char name[B_OS_NAME_LENGTH]; 8085db3873SIngo Weinhold int32 ref_count; 81bcb793d3SAdrien Destugues // A negative ref_count means the node is not reference counted and not 82bcb793d3SAdrien Destugues // stored in the list. 8385db3873SIngo Weinhold #endif 8485db3873SIngo Weinhold int32 magic; 8585db3873SIngo Weinhold struct driver_settings settings; 8685db3873SIngo Weinhold char *text; 8785db3873SIngo Weinhold } settings_handle; 8885db3873SIngo Weinhold 8985db3873SIngo Weinhold 9085db3873SIngo Weinhold enum assignment_mode { 9185db3873SIngo Weinhold NO_ASSIGNMENT, 9285db3873SIngo Weinhold ALLOW_ASSIGNMENT, 9385db3873SIngo Weinhold IGNORE_ASSIGNMENT 9485db3873SIngo Weinhold }; 9585db3873SIngo Weinhold 9685db3873SIngo Weinhold 9785db3873SIngo Weinhold #ifdef _KERNEL_MODE 9885db3873SIngo Weinhold static struct list sHandles; 9985db3873SIngo Weinhold static mutex sLock = MUTEX_INITIALIZER("driver settings"); 10085db3873SIngo Weinhold #endif 10185db3873SIngo Weinhold 10285db3873SIngo Weinhold 10385db3873SIngo Weinhold // #pragma mark - private functions 10485db3873SIngo Weinhold 10585db3873SIngo Weinhold 10685db3873SIngo Weinhold /*! 107bcb793d3SAdrien Destugues \brief Returns true for any characters that separate parameters 108bcb793d3SAdrien Destugues 109bcb793d3SAdrien Destugues Those characters are ignored in the input stream and won't be added 11085db3873SIngo Weinhold to any words. 11185db3873SIngo Weinhold */ 11285db3873SIngo Weinhold static inline bool 11385db3873SIngo Weinhold is_parameter_separator(char c) 11485db3873SIngo Weinhold { 11585db3873SIngo Weinhold return c == '\n' || c == ';'; 11685db3873SIngo Weinhold } 11785db3873SIngo Weinhold 11885db3873SIngo Weinhold 119bcb793d3SAdrien Destugues /*! Indicates if "c" begins a new word or not. 12085db3873SIngo Weinhold */ 12185db3873SIngo Weinhold static inline bool 12285db3873SIngo Weinhold is_word_break(char c) 12385db3873SIngo Weinhold { 12485db3873SIngo Weinhold return isspace(c) || is_parameter_separator(c); 12585db3873SIngo Weinhold } 12685db3873SIngo Weinhold 12785db3873SIngo Weinhold 12885db3873SIngo Weinhold static inline bool 12985db3873SIngo Weinhold check_handle(settings_handle *handle) 13085db3873SIngo Weinhold { 13185db3873SIngo Weinhold if (handle == NULL 13285db3873SIngo Weinhold || handle->magic != SETTINGS_MAGIC) 13385db3873SIngo Weinhold return false; 13485db3873SIngo Weinhold 13585db3873SIngo Weinhold return true; 13685db3873SIngo Weinhold } 13785db3873SIngo Weinhold 13885db3873SIngo Weinhold 13985db3873SIngo Weinhold static driver_parameter * 14085db3873SIngo Weinhold get_parameter(settings_handle *handle, const char *name) 14185db3873SIngo Weinhold { 14285db3873SIngo Weinhold int32 i; 14385db3873SIngo Weinhold for (i = handle->settings.parameter_count; i-- > 0;) { 14485db3873SIngo Weinhold if (!strcmp(handle->settings.parameters[i].name, name)) 14585db3873SIngo Weinhold return &handle->settings.parameters[i]; 14685db3873SIngo Weinhold } 14785db3873SIngo Weinhold return NULL; 14885db3873SIngo Weinhold } 14985db3873SIngo Weinhold 15085db3873SIngo Weinhold 15185db3873SIngo Weinhold /*! 15285db3873SIngo Weinhold Returns the next word in the input buffer passed in via "_pos" - if 15385db3873SIngo Weinhold this function returns, it will bump the input position after the word. 15485db3873SIngo Weinhold It automatically cares about quoted strings and escaped characters. 15585db3873SIngo Weinhold If "allowNewLine" is true, it reads over comments to get to the next 15685db3873SIngo Weinhold word. 15785db3873SIngo Weinhold Depending on the "assignmentMode" parameter, the '=' sign is either 15885db3873SIngo Weinhold used as a work break, or not. 15985db3873SIngo Weinhold The input buffer will be changed to contain the word without quotes 16085db3873SIngo Weinhold or escaped characters and adds a terminating NULL byte. The "_word" 16185db3873SIngo Weinhold parameter will be set to the beginning of the word. 16285db3873SIngo Weinhold If the word is followed by a newline it will return B_OK, if white 16385db3873SIngo Weinhold spaces follows, it will return CONTINUE_PARAMETER. 16485db3873SIngo Weinhold */ 16585db3873SIngo Weinhold static status_t 16685db3873SIngo Weinhold get_word(char **_pos, char **_word, int32 assignmentMode, bool allowNewLine) 16785db3873SIngo Weinhold { 16885db3873SIngo Weinhold char *pos = *_pos; 16985db3873SIngo Weinhold char quoted = 0; 17085db3873SIngo Weinhold bool newLine = false, end = false; 17185db3873SIngo Weinhold int escaped = 0; 17285db3873SIngo Weinhold bool charEscaped = false; 17385db3873SIngo Weinhold 17485db3873SIngo Weinhold // Skip any white space and comments 17585db3873SIngo Weinhold while (pos[0] 17685db3873SIngo Weinhold && ((allowNewLine && (isspace(pos[0]) || is_parameter_separator(pos[0]) 17785db3873SIngo Weinhold || pos[0] == '#')) 17885db3873SIngo Weinhold || (!allowNewLine && (pos[0] == '\t' || pos[0] == ' ')) 17985db3873SIngo Weinhold || (assignmentMode == ALLOW_ASSIGNMENT && pos[0] == '='))) { 18085db3873SIngo Weinhold // skip any comment lines 18185db3873SIngo Weinhold if (pos[0] == '#') { 18285db3873SIngo Weinhold while (pos[0] && pos[0] != '\n') 18385db3873SIngo Weinhold pos++; 18485db3873SIngo Weinhold } 18585db3873SIngo Weinhold pos++; 18685db3873SIngo Weinhold } 18785db3873SIngo Weinhold 18885db3873SIngo Weinhold if (pos[0] == '}' || pos[0] == '\0') { 18985db3873SIngo Weinhold // if we just read some white space before an end of a 19085db3873SIngo Weinhold // parameter, this is just no parameter at all 19185db3873SIngo Weinhold *_pos = pos; 19285db3873SIngo Weinhold return NO_PARAMETER; 19385db3873SIngo Weinhold } 19485db3873SIngo Weinhold 19585db3873SIngo Weinhold // Read in a word - might contain escaped (\) spaces, or it 19685db3873SIngo Weinhold // might also be quoted (" or '). 19785db3873SIngo Weinhold 19885db3873SIngo Weinhold if (pos[0] == '"' || pos[0] == '\'') { 19985db3873SIngo Weinhold quoted = pos[0]; 20085db3873SIngo Weinhold pos++; 20185db3873SIngo Weinhold } 20285db3873SIngo Weinhold *_word = pos; 20385db3873SIngo Weinhold 20485db3873SIngo Weinhold while (pos[0]) { 20585db3873SIngo Weinhold if (charEscaped) 20685db3873SIngo Weinhold charEscaped = false; 20785db3873SIngo Weinhold else if (pos[0] == '\\') { 20885db3873SIngo Weinhold charEscaped = true; 20985db3873SIngo Weinhold escaped++; 21085db3873SIngo Weinhold } else if ((!quoted && (is_word_break(pos[0]) 21185db3873SIngo Weinhold || (assignmentMode != IGNORE_ASSIGNMENT && pos[0] == '='))) 21285db3873SIngo Weinhold || (quoted && pos[0] == quoted)) 21385db3873SIngo Weinhold break; 21485db3873SIngo Weinhold 21585db3873SIngo Weinhold pos++; 21685db3873SIngo Weinhold } 21785db3873SIngo Weinhold 21885db3873SIngo Weinhold // "String exceeds line" - missing end quote 21985db3873SIngo Weinhold if (quoted && pos[0] != quoted) 22085db3873SIngo Weinhold return B_BAD_DATA; 22185db3873SIngo Weinhold 22285db3873SIngo Weinhold // last character is a backslash 22385db3873SIngo Weinhold if (charEscaped) 22485db3873SIngo Weinhold return B_BAD_DATA; 22585db3873SIngo Weinhold 22685db3873SIngo Weinhold end = pos[0] == '\0'; 22785db3873SIngo Weinhold newLine = is_parameter_separator(pos[0]) || end; 22885db3873SIngo Weinhold pos[0] = '\0'; 22985db3873SIngo Weinhold 23085db3873SIngo Weinhold // Correct name if there were any escaped characters 23185db3873SIngo Weinhold if (escaped) { 23285db3873SIngo Weinhold char *word = *_word; 23385db3873SIngo Weinhold int offset = 0; 23485db3873SIngo Weinhold while (word <= pos) { 23585db3873SIngo Weinhold if (word[0] == '\\') { 23685db3873SIngo Weinhold offset--; 23785db3873SIngo Weinhold word++; 23885db3873SIngo Weinhold } 23985db3873SIngo Weinhold word[offset] = word[0]; 24085db3873SIngo Weinhold word++; 24185db3873SIngo Weinhold } 24285db3873SIngo Weinhold } 24385db3873SIngo Weinhold 24485db3873SIngo Weinhold if (end) { 24585db3873SIngo Weinhold *_pos = pos; 24685db3873SIngo Weinhold return B_OK; 24785db3873SIngo Weinhold } 24885db3873SIngo Weinhold 24985db3873SIngo Weinhold // Scan for next beginning word, open brackets, or comment start 25085db3873SIngo Weinhold 25185db3873SIngo Weinhold pos++; 25285db3873SIngo Weinhold while (true) { 25385db3873SIngo Weinhold *_pos = pos; 25485db3873SIngo Weinhold if (!pos[0]) 25585db3873SIngo Weinhold return B_NO_ERROR; 25685db3873SIngo Weinhold 25785db3873SIngo Weinhold if (is_parameter_separator(pos[0])) { 25885db3873SIngo Weinhold // an open bracket '{' could follow after the first 25985db3873SIngo Weinhold // newline, but not later 26085db3873SIngo Weinhold if (newLine) 26185db3873SIngo Weinhold return B_NO_ERROR; 26285db3873SIngo Weinhold 26385db3873SIngo Weinhold newLine = true; 26485db3873SIngo Weinhold } else if (pos[0] == '{' || pos[0] == '}' || pos[0] == '#') 26585db3873SIngo Weinhold return B_NO_ERROR; 26685db3873SIngo Weinhold else if (!isspace(pos[0])) 26785db3873SIngo Weinhold return newLine ? B_NO_ERROR : CONTINUE_PARAMETER; 26885db3873SIngo Weinhold 26985db3873SIngo Weinhold pos++; 27085db3873SIngo Weinhold } 27185db3873SIngo Weinhold } 27285db3873SIngo Weinhold 27385db3873SIngo Weinhold 27485db3873SIngo Weinhold static status_t 27585db3873SIngo Weinhold parse_parameter(struct driver_parameter *parameter, char **_pos, int32 level) 27685db3873SIngo Weinhold { 27785db3873SIngo Weinhold char *pos = *_pos; 27885db3873SIngo Weinhold status_t status; 27985db3873SIngo Weinhold 28085db3873SIngo Weinhold // initialize parameter first 28185db3873SIngo Weinhold memset(parameter, 0, sizeof(struct driver_parameter)); 28285db3873SIngo Weinhold 28385db3873SIngo Weinhold status = get_word(&pos, ¶meter->name, NO_ASSIGNMENT, true); 28485db3873SIngo Weinhold if (status == CONTINUE_PARAMETER) { 28585db3873SIngo Weinhold while (status == CONTINUE_PARAMETER) { 2861e6dd3feSMurai Takashi char **newArray, *value = NULL; 28785db3873SIngo Weinhold status = get_word(&pos, &value, parameter->value_count == 0 28885db3873SIngo Weinhold ? ALLOW_ASSIGNMENT : IGNORE_ASSIGNMENT, false); 28985db3873SIngo Weinhold if (status < B_OK) 29085db3873SIngo Weinhold break; 29185db3873SIngo Weinhold 29285db3873SIngo Weinhold // enlarge value array and save the value 29385db3873SIngo Weinhold 29485db3873SIngo Weinhold newArray = (char**)realloc(parameter->values, 29585db3873SIngo Weinhold (parameter->value_count + 1) * sizeof(char *)); 29685db3873SIngo Weinhold if (newArray == NULL) 29785db3873SIngo Weinhold return B_NO_MEMORY; 29885db3873SIngo Weinhold 29985db3873SIngo Weinhold parameter->values = newArray; 30085db3873SIngo Weinhold parameter->values[parameter->value_count++] = value; 30185db3873SIngo Weinhold } 30285db3873SIngo Weinhold } 30385db3873SIngo Weinhold 30485db3873SIngo Weinhold *_pos = pos; 30585db3873SIngo Weinhold return status; 30685db3873SIngo Weinhold } 30785db3873SIngo Weinhold 30885db3873SIngo Weinhold 30985db3873SIngo Weinhold static status_t 31085db3873SIngo Weinhold parse_parameters(struct driver_parameter **_parameters, int *_count, 31185db3873SIngo Weinhold char **_pos, int32 level) 31285db3873SIngo Weinhold { 31385db3873SIngo Weinhold if (level > MAX_SETTINGS_LEVEL) 31485db3873SIngo Weinhold return B_LINK_LIMIT; 31585db3873SIngo Weinhold 31685db3873SIngo Weinhold while (true) { 31785db3873SIngo Weinhold struct driver_parameter parameter; 31885db3873SIngo Weinhold struct driver_parameter *newArray; 31985db3873SIngo Weinhold status_t status; 32085db3873SIngo Weinhold 32185db3873SIngo Weinhold status = parse_parameter(¶meter, _pos, level); 32285db3873SIngo Weinhold if (status < B_OK) 32385db3873SIngo Weinhold return status; 32485db3873SIngo Weinhold 32585db3873SIngo Weinhold if (status != NO_PARAMETER) { 32685db3873SIngo Weinhold driver_parameter *newParameter; 32785db3873SIngo Weinhold 32885db3873SIngo Weinhold newArray = (driver_parameter*)realloc(*_parameters, (*_count + 1) 32985db3873SIngo Weinhold * sizeof(struct driver_parameter)); 33085db3873SIngo Weinhold if (newArray == NULL) 33185db3873SIngo Weinhold return B_NO_MEMORY; 33285db3873SIngo Weinhold 33385db3873SIngo Weinhold memcpy(&newArray[*_count], ¶meter, sizeof(struct driver_parameter)); 33485db3873SIngo Weinhold newParameter = &newArray[*_count]; 33585db3873SIngo Weinhold 33685db3873SIngo Weinhold *_parameters = newArray; 33785db3873SIngo Weinhold (*_count)++; 33885db3873SIngo Weinhold 33985db3873SIngo Weinhold // check for level beginning and end 34085db3873SIngo Weinhold if (**_pos == '{') { 34185db3873SIngo Weinhold // if we go a level deeper, just start all over again... 34285db3873SIngo Weinhold (*_pos)++; 34385db3873SIngo Weinhold status = parse_parameters(&newParameter->parameters, 34485db3873SIngo Weinhold &newParameter->parameter_count, _pos, level + 1); 34585db3873SIngo Weinhold if (status < B_OK) 34685db3873SIngo Weinhold return status; 34785db3873SIngo Weinhold } 34885db3873SIngo Weinhold } 34985db3873SIngo Weinhold 35085db3873SIngo Weinhold if ((**_pos == '}' && level > 0) 35185db3873SIngo Weinhold || (**_pos == '\0' && level == 0)) { 35285db3873SIngo Weinhold // take the closing bracket from the stack 35385db3873SIngo Weinhold (*_pos)++; 35485db3873SIngo Weinhold return B_OK; 35585db3873SIngo Weinhold } 35685db3873SIngo Weinhold 35785db3873SIngo Weinhold // obviously, something has gone wrong 35885db3873SIngo Weinhold if (**_pos == '}' || **_pos == '\0') 35985db3873SIngo Weinhold return B_ERROR; 36085db3873SIngo Weinhold } 36185db3873SIngo Weinhold } 36285db3873SIngo Weinhold 36385db3873SIngo Weinhold 36485db3873SIngo Weinhold static status_t 36585db3873SIngo Weinhold parse_settings(settings_handle *handle) 36685db3873SIngo Weinhold { 36785db3873SIngo Weinhold char *text = handle->text; 36885db3873SIngo Weinhold 36985db3873SIngo Weinhold memset(&handle->settings, 0, sizeof(struct driver_settings)); 37085db3873SIngo Weinhold 37185db3873SIngo Weinhold // empty settings are allowed 37285db3873SIngo Weinhold if (text == NULL) 37385db3873SIngo Weinhold return B_OK; 37485db3873SIngo Weinhold 37585db3873SIngo Weinhold return parse_parameters(&handle->settings.parameters, 37685db3873SIngo Weinhold &handle->settings.parameter_count, &text, 0); 37785db3873SIngo Weinhold } 37885db3873SIngo Weinhold 37985db3873SIngo Weinhold 38085db3873SIngo Weinhold static void 38185db3873SIngo Weinhold free_parameter(struct driver_parameter *parameter) 38285db3873SIngo Weinhold { 38385db3873SIngo Weinhold int32 i; 38485db3873SIngo Weinhold for (i = parameter->parameter_count; i-- > 0;) 38585db3873SIngo Weinhold free_parameter(¶meter->parameters[i]); 38685db3873SIngo Weinhold 38785db3873SIngo Weinhold free(parameter->parameters); 38885db3873SIngo Weinhold free(parameter->values); 38985db3873SIngo Weinhold } 39085db3873SIngo Weinhold 39185db3873SIngo Weinhold 39285db3873SIngo Weinhold static void 39385db3873SIngo Weinhold free_settings(settings_handle *handle) 39485db3873SIngo Weinhold { 39585db3873SIngo Weinhold int32 i; 39685db3873SIngo Weinhold for (i = handle->settings.parameter_count; i-- > 0;) 39785db3873SIngo Weinhold free_parameter(&handle->settings.parameters[i]); 39885db3873SIngo Weinhold 39985db3873SIngo Weinhold free(handle->settings.parameters); 40085db3873SIngo Weinhold free(handle->text); 40185db3873SIngo Weinhold free(handle); 40285db3873SIngo Weinhold } 40385db3873SIngo Weinhold 40485db3873SIngo Weinhold 40585db3873SIngo Weinhold static settings_handle * 40685db3873SIngo Weinhold new_settings(char *buffer, const char *driverName) 40785db3873SIngo Weinhold { 40885db3873SIngo Weinhold settings_handle *handle = (settings_handle*)malloc(sizeof(settings_handle)); 40985db3873SIngo Weinhold if (handle == NULL) 41085db3873SIngo Weinhold return NULL; 41185db3873SIngo Weinhold 41285db3873SIngo Weinhold handle->magic = SETTINGS_MAGIC; 41385db3873SIngo Weinhold handle->text = buffer; 41485db3873SIngo Weinhold 41585db3873SIngo Weinhold #ifdef _KERNEL_MODE 416efe9df37SIngo Weinhold if (driverName != NULL) { 41785db3873SIngo Weinhold handle->ref_count = 1; 41885db3873SIngo Weinhold strlcpy(handle->name, driverName, sizeof(handle->name)); 419bcb793d3SAdrien Destugues } else { 420bcb793d3SAdrien Destugues handle->ref_count = -1; 421bcb793d3SAdrien Destugues handle->name[0] = 0; 422efe9df37SIngo Weinhold } 42385db3873SIngo Weinhold #endif 42485db3873SIngo Weinhold 42585db3873SIngo Weinhold if (parse_settings(handle) == B_OK) 42685db3873SIngo Weinhold return handle; 42785db3873SIngo Weinhold 42885db3873SIngo Weinhold free(handle); 42985db3873SIngo Weinhold return NULL; 43085db3873SIngo Weinhold } 43185db3873SIngo Weinhold 43285db3873SIngo Weinhold 43385db3873SIngo Weinhold static settings_handle * 43485db3873SIngo Weinhold load_driver_settings_from_file(int file, const char *driverName) 43585db3873SIngo Weinhold { 43685db3873SIngo Weinhold struct stat stat; 43785db3873SIngo Weinhold 43885db3873SIngo Weinhold // Allocate a buffer and read the whole file into it. 43985db3873SIngo Weinhold // We will keep this buffer in memory, until the settings 44085db3873SIngo Weinhold // are unloaded. 44185db3873SIngo Weinhold // The driver_parameter::name field will point directly 44285db3873SIngo Weinhold // to this buffer. 44385db3873SIngo Weinhold 44485db3873SIngo Weinhold if (fstat(file, &stat) < B_OK) 44585db3873SIngo Weinhold return NULL; 44685db3873SIngo Weinhold 44785db3873SIngo Weinhold if (stat.st_size > B_OK && stat.st_size < MAX_SETTINGS_SIZE) { 44885db3873SIngo Weinhold char *text = (char *)malloc(stat.st_size + 1); 44985db3873SIngo Weinhold if (text != NULL && read(file, text, stat.st_size) == stat.st_size) { 45085db3873SIngo Weinhold settings_handle *handle; 45185db3873SIngo Weinhold 45285db3873SIngo Weinhold text[stat.st_size] = '\0'; 45385db3873SIngo Weinhold // make sure the string is null terminated 45485db3873SIngo Weinhold // to avoid misbehaviour 45585db3873SIngo Weinhold 45685db3873SIngo Weinhold handle = new_settings(text, driverName); 45785db3873SIngo Weinhold if (handle != NULL) { 45885db3873SIngo Weinhold // everything went fine! 45985db3873SIngo Weinhold return handle; 46085db3873SIngo Weinhold } 46185db3873SIngo Weinhold } 46285db3873SIngo Weinhold // "text" might be NULL here, but that's allowed 46385db3873SIngo Weinhold free(text); 46485db3873SIngo Weinhold } 46585db3873SIngo Weinhold 46685db3873SIngo Weinhold return NULL; 46785db3873SIngo Weinhold } 46885db3873SIngo Weinhold 46985db3873SIngo Weinhold 47085db3873SIngo Weinhold static bool 471d2a423e4SPhilippe Saint-Pierre put_string(char **_buffer, ssize_t *_bufferSize, char *string) 47285db3873SIngo Weinhold { 47385db3873SIngo Weinhold size_t length, reserved, quotes; 47485db3873SIngo Weinhold char *buffer = *_buffer, c; 47585db3873SIngo Weinhold bool quoted; 47685db3873SIngo Weinhold 47785db3873SIngo Weinhold if (string == NULL) 47885db3873SIngo Weinhold return true; 47985db3873SIngo Weinhold 48085db3873SIngo Weinhold for (length = reserved = quotes = 0; (c = string[length]) != '\0'; length++) { 48185db3873SIngo Weinhold if (c == '"') 48285db3873SIngo Weinhold quotes++; 48385db3873SIngo Weinhold else if (is_word_break(c)) 48485db3873SIngo Weinhold reserved++; 48585db3873SIngo Weinhold } 48685db3873SIngo Weinhold quoted = reserved || quotes; 48785db3873SIngo Weinhold 48885db3873SIngo Weinhold // update _bufferSize in any way, so that we can chain several 48985db3873SIngo Weinhold // of these calls without having to check the return value 49085db3873SIngo Weinhold // everytime 49185db3873SIngo Weinhold *_bufferSize -= length + (quoted ? 2 + quotes : 0); 49285db3873SIngo Weinhold 49385db3873SIngo Weinhold if (*_bufferSize <= 0) 49485db3873SIngo Weinhold return false; 49585db3873SIngo Weinhold 49685db3873SIngo Weinhold if (quoted) 49785db3873SIngo Weinhold *(buffer++) = '"'; 49885db3873SIngo Weinhold 49985db3873SIngo Weinhold for (;(c = string[0]) != '\0'; string++) { 50085db3873SIngo Weinhold if (c == '"') 50185db3873SIngo Weinhold *(buffer++) = '\\'; 50285db3873SIngo Weinhold 50385db3873SIngo Weinhold *(buffer++) = c; 50485db3873SIngo Weinhold } 50585db3873SIngo Weinhold 50685db3873SIngo Weinhold if (quoted) 50785db3873SIngo Weinhold *(buffer++) = '"'; 50885db3873SIngo Weinhold 50985db3873SIngo Weinhold buffer[0] = '\0'; 51085db3873SIngo Weinhold 51185db3873SIngo Weinhold // update the buffer position 51285db3873SIngo Weinhold *_buffer = buffer; 51385db3873SIngo Weinhold 51485db3873SIngo Weinhold return true; 51585db3873SIngo Weinhold } 51685db3873SIngo Weinhold 51785db3873SIngo Weinhold 51885db3873SIngo Weinhold static bool 519d2a423e4SPhilippe Saint-Pierre put_chars(char **_buffer, ssize_t *_bufferSize, const char *chars) 52085db3873SIngo Weinhold { 52185db3873SIngo Weinhold char *buffer = *_buffer; 52285db3873SIngo Weinhold size_t length; 52385db3873SIngo Weinhold 52485db3873SIngo Weinhold if (chars == NULL) 52585db3873SIngo Weinhold return true; 52685db3873SIngo Weinhold 52785db3873SIngo Weinhold length = strlen(chars); 52885db3873SIngo Weinhold *_bufferSize -= length; 52985db3873SIngo Weinhold 53085db3873SIngo Weinhold if (*_bufferSize <= 0) 53185db3873SIngo Weinhold return false; 53285db3873SIngo Weinhold 53385db3873SIngo Weinhold memcpy(buffer, chars, length); 53485db3873SIngo Weinhold buffer += length; 53585db3873SIngo Weinhold buffer[0] = '\0'; 53685db3873SIngo Weinhold 53785db3873SIngo Weinhold // update the buffer position 53885db3873SIngo Weinhold *_buffer = buffer; 53985db3873SIngo Weinhold 54085db3873SIngo Weinhold return true; 54185db3873SIngo Weinhold } 54285db3873SIngo Weinhold 54385db3873SIngo Weinhold 54485db3873SIngo Weinhold static bool 545d2a423e4SPhilippe Saint-Pierre put_char(char **_buffer, ssize_t *_bufferSize, char c) 54685db3873SIngo Weinhold { 54785db3873SIngo Weinhold char *buffer = *_buffer; 54885db3873SIngo Weinhold 54985db3873SIngo Weinhold *_bufferSize -= 1; 55085db3873SIngo Weinhold 55185db3873SIngo Weinhold if (*_bufferSize <= 0) 55285db3873SIngo Weinhold return false; 55385db3873SIngo Weinhold 55485db3873SIngo Weinhold buffer[0] = c; 55585db3873SIngo Weinhold buffer[1] = '\0'; 55685db3873SIngo Weinhold 55785db3873SIngo Weinhold // update the buffer position 55885db3873SIngo Weinhold *_buffer = buffer + 1; 55985db3873SIngo Weinhold 56085db3873SIngo Weinhold return true; 56185db3873SIngo Weinhold } 56285db3873SIngo Weinhold 56385db3873SIngo Weinhold 56485db3873SIngo Weinhold static void 565d2a423e4SPhilippe Saint-Pierre put_level_space(char **_buffer, ssize_t *_bufferSize, int32 level) 56685db3873SIngo Weinhold { 56785db3873SIngo Weinhold while (level-- > 0) 56885db3873SIngo Weinhold put_char(_buffer, _bufferSize, '\t'); 56985db3873SIngo Weinhold } 57085db3873SIngo Weinhold 57185db3873SIngo Weinhold 572a5270963SIngo Weinhold static void 573d2a423e4SPhilippe Saint-Pierre put_parameter(char **_buffer, ssize_t *_bufferSize, 57485db3873SIngo Weinhold struct driver_parameter *parameter, int32 level, bool flat) 57585db3873SIngo Weinhold { 57685db3873SIngo Weinhold int32 i; 57785db3873SIngo Weinhold 57885db3873SIngo Weinhold if (!flat) 57985db3873SIngo Weinhold put_level_space(_buffer, _bufferSize, level); 58085db3873SIngo Weinhold 58185db3873SIngo Weinhold put_string(_buffer, _bufferSize, parameter->name); 58285db3873SIngo Weinhold if (flat && parameter->value_count > 0) 58385db3873SIngo Weinhold put_chars(_buffer, _bufferSize, " ="); 58485db3873SIngo Weinhold 58585db3873SIngo Weinhold for (i = 0; i < parameter->value_count; i++) { 58685db3873SIngo Weinhold put_char(_buffer, _bufferSize, ' '); 58785db3873SIngo Weinhold put_string(_buffer, _bufferSize, parameter->values[i]); 58885db3873SIngo Weinhold } 58985db3873SIngo Weinhold 59085db3873SIngo Weinhold if (parameter->parameter_count > 0) { 59185db3873SIngo Weinhold put_chars(_buffer, _bufferSize, " {"); 59285db3873SIngo Weinhold if (!flat) 59385db3873SIngo Weinhold put_char(_buffer, _bufferSize, '\n'); 59485db3873SIngo Weinhold 59585db3873SIngo Weinhold for (i = 0; i < parameter->parameter_count; i++) { 59685db3873SIngo Weinhold put_parameter(_buffer, _bufferSize, ¶meter->parameters[i], 59785db3873SIngo Weinhold level + 1, flat); 59885db3873SIngo Weinhold 59985db3873SIngo Weinhold if (parameter->parameters[i].parameter_count == 0) 60085db3873SIngo Weinhold put_chars(_buffer, _bufferSize, flat ? "; " : "\n"); 60185db3873SIngo Weinhold } 60285db3873SIngo Weinhold 60385db3873SIngo Weinhold if (!flat) 60485db3873SIngo Weinhold put_level_space(_buffer, _bufferSize, level); 60585db3873SIngo Weinhold put_chars(_buffer, _bufferSize, flat ? "}" : "}\n"); 60685db3873SIngo Weinhold } 60785db3873SIngo Weinhold } 60885db3873SIngo Weinhold 60985db3873SIngo Weinhold 61085db3873SIngo Weinhold // #pragma mark - Kernel only functions 61185db3873SIngo Weinhold 61285db3873SIngo Weinhold 61385db3873SIngo Weinhold #ifdef _KERNEL_MODE 61485db3873SIngo Weinhold static settings_handle * 61585db3873SIngo Weinhold find_driver_settings(const char *name) 61685db3873SIngo Weinhold { 61785db3873SIngo Weinhold settings_handle *handle = NULL; 61885db3873SIngo Weinhold 61985db3873SIngo Weinhold ASSERT_LOCKED_MUTEX(&sLock); 62085db3873SIngo Weinhold 62185db3873SIngo Weinhold while ((handle = (settings_handle*)list_get_next_item(&sHandles, handle)) 62285db3873SIngo Weinhold != NULL) { 62385db3873SIngo Weinhold if (!strcmp(handle->name, name)) 62485db3873SIngo Weinhold return handle; 62585db3873SIngo Weinhold } 62685db3873SIngo Weinhold 62785db3873SIngo Weinhold return NULL; 62885db3873SIngo Weinhold } 62985db3873SIngo Weinhold 63085db3873SIngo Weinhold 63185db3873SIngo Weinhold status_t 63285db3873SIngo Weinhold driver_settings_init(kernel_args *args) 63385db3873SIngo Weinhold { 63485db3873SIngo Weinhold struct driver_settings_file *settings = args->driver_settings; 63585db3873SIngo Weinhold 63685db3873SIngo Weinhold // Move the preloaded driver settings over to the kernel 63785db3873SIngo Weinhold 63885db3873SIngo Weinhold list_init(&sHandles); 63985db3873SIngo Weinhold 64085db3873SIngo Weinhold while (settings != NULL) { 64185db3873SIngo Weinhold settings_handle *handle 64285db3873SIngo Weinhold = (settings_handle*)malloc(sizeof(settings_handle)); 64385db3873SIngo Weinhold if (handle == NULL) 64485db3873SIngo Weinhold return B_NO_MEMORY; 64585db3873SIngo Weinhold 64685db3873SIngo Weinhold if (settings->size != 0) { 64785db3873SIngo Weinhold handle->text = (char*)malloc(settings->size + 1); 64885db3873SIngo Weinhold if (handle->text == NULL) { 64985db3873SIngo Weinhold free(handle); 65085db3873SIngo Weinhold return B_NO_MEMORY; 65185db3873SIngo Weinhold } 65285db3873SIngo Weinhold 65385db3873SIngo Weinhold memcpy(handle->text, settings->buffer, settings->size); 65485db3873SIngo Weinhold handle->text[settings->size] = '\0'; 65585db3873SIngo Weinhold // null terminate the buffer 65685db3873SIngo Weinhold } else 65785db3873SIngo Weinhold handle->text = NULL; 65885db3873SIngo Weinhold 65985db3873SIngo Weinhold strlcpy(handle->name, settings->name, sizeof(handle->name)); 66085db3873SIngo Weinhold handle->settings.parameters = NULL; 66185db3873SIngo Weinhold handle->settings.parameter_count = 0; 66285db3873SIngo Weinhold handle->magic = 0; 66385db3873SIngo Weinhold // this triggers parsing the settings when they are actually used 66485db3873SIngo Weinhold 66585db3873SIngo Weinhold if (!strcmp(handle->name, B_SAFEMODE_DRIVER_SETTINGS)) { 66685db3873SIngo Weinhold // These settings cannot be reloaded, so we better don't throw 66785db3873SIngo Weinhold // them away. 66885db3873SIngo Weinhold handle->ref_count = 1; 66985db3873SIngo Weinhold } else 67085db3873SIngo Weinhold handle->ref_count = 0; 67185db3873SIngo Weinhold 67285db3873SIngo Weinhold list_add_item(&sHandles, handle); 67385db3873SIngo Weinhold 67485db3873SIngo Weinhold settings = settings->next; 67585db3873SIngo Weinhold } 67685db3873SIngo Weinhold 67785db3873SIngo Weinhold return B_OK; 67885db3873SIngo Weinhold } 67985db3873SIngo Weinhold #endif 68085db3873SIngo Weinhold 68185db3873SIngo Weinhold 68285db3873SIngo Weinhold // #pragma mark - public API 68385db3873SIngo Weinhold 68485db3873SIngo Weinhold 68585db3873SIngo Weinhold status_t 68685db3873SIngo Weinhold unload_driver_settings(void *_handle) 68785db3873SIngo Weinhold { 68885db3873SIngo Weinhold settings_handle *handle = (settings_handle *)_handle; 68985db3873SIngo Weinhold if (!check_handle(handle)) 69085db3873SIngo Weinhold return B_BAD_VALUE; 69185db3873SIngo Weinhold 69285db3873SIngo Weinhold #ifdef _KERNEL_MODE 69385db3873SIngo Weinhold mutex_lock(&sLock); 694bcb793d3SAdrien Destugues 695bcb793d3SAdrien Destugues if (handle->ref_count > 0) { 69685db3873SIngo Weinhold if (--handle->ref_count == 0 && gBootDevice > 0) { 69785db3873SIngo Weinhold // don't unload an handle when /boot is not available 69885db3873SIngo Weinhold list_remove_link(&handle->link); 69985db3873SIngo Weinhold } else 70085db3873SIngo Weinhold handle = NULL; 701bcb793d3SAdrien Destugues } 70285db3873SIngo Weinhold mutex_unlock(&sLock); 70385db3873SIngo Weinhold #endif 70485db3873SIngo Weinhold 70585db3873SIngo Weinhold if (handle != NULL) 70685db3873SIngo Weinhold free_settings(handle); 70785db3873SIngo Weinhold 70885db3873SIngo Weinhold return B_OK; 70985db3873SIngo Weinhold } 71085db3873SIngo Weinhold 71185db3873SIngo Weinhold 71285db3873SIngo Weinhold void * 71385db3873SIngo Weinhold load_driver_settings(const char *driverName) 71485db3873SIngo Weinhold { 71585db3873SIngo Weinhold settings_handle *handle; 71685db3873SIngo Weinhold int file = -1; 71785db3873SIngo Weinhold 71885db3873SIngo Weinhold if (driverName == NULL) 71985db3873SIngo Weinhold return NULL; 72085db3873SIngo Weinhold 72185db3873SIngo Weinhold #ifdef _KERNEL_MODE 72285db3873SIngo Weinhold // see if we already have these settings loaded 72385db3873SIngo Weinhold mutex_lock(&sLock); 72485db3873SIngo Weinhold handle = find_driver_settings(driverName); 72585db3873SIngo Weinhold if (handle != NULL && handle->ref_count == 0 && gBootDevice > 0) { 72685db3873SIngo Weinhold // A handle with a zero ref_count should be unloaded if /boot is 72785db3873SIngo Weinhold // available. 72885db3873SIngo Weinhold list_remove_link(&handle->link); 72985db3873SIngo Weinhold free_settings(handle); 73085db3873SIngo Weinhold } else if (handle != NULL) { 73185db3873SIngo Weinhold handle->ref_count++; 73285db3873SIngo Weinhold 73385db3873SIngo Weinhold // we got it, now let's see if it already has been parsed 73485db3873SIngo Weinhold if (handle->magic != SETTINGS_MAGIC) { 73585db3873SIngo Weinhold handle->magic = SETTINGS_MAGIC; 73685db3873SIngo Weinhold 73785db3873SIngo Weinhold if (parse_settings(handle) != B_OK) { 73885db3873SIngo Weinhold // no valid settings, let's cut down its memory requirements 73985db3873SIngo Weinhold free(handle->text); 74085db3873SIngo Weinhold handle->text = NULL; 74185db3873SIngo Weinhold handle = NULL; 74285db3873SIngo Weinhold } 74385db3873SIngo Weinhold } 74485db3873SIngo Weinhold mutex_unlock(&sLock); 74585db3873SIngo Weinhold return handle; 74685db3873SIngo Weinhold } 74785db3873SIngo Weinhold 74885db3873SIngo Weinhold // we are allowed to call the driver settings pretty early in the boot process 74985db3873SIngo Weinhold if (gKernelStartup) { 75085db3873SIngo Weinhold mutex_unlock(&sLock); 75185db3873SIngo Weinhold return NULL; 75285db3873SIngo Weinhold } 75385db3873SIngo Weinhold #endif // _KERNEL_MODE 75485db3873SIngo Weinhold #ifdef _BOOT_MODE 75585db3873SIngo Weinhold // see if we already have these settings loaded 75685db3873SIngo Weinhold { 75785db3873SIngo Weinhold struct driver_settings_file *settings = gKernelArgs.driver_settings; 75885db3873SIngo Weinhold while (settings != NULL) { 75985db3873SIngo Weinhold if (!strcmp(settings->name, driverName)) { 76085db3873SIngo Weinhold // we have it - since the buffer is clobbered, we have to 76185db3873SIngo Weinhold // copy its contents, though 76285db3873SIngo Weinhold char *text = (char*)malloc(settings->size + 1); 76385db3873SIngo Weinhold if (text == NULL) 76485db3873SIngo Weinhold return NULL; 76585db3873SIngo Weinhold 76685db3873SIngo Weinhold memcpy(text, settings->buffer, settings->size + 1); 76785db3873SIngo Weinhold return new_settings(text, driverName); 76885db3873SIngo Weinhold } 76985db3873SIngo Weinhold settings = settings->next; 77085db3873SIngo Weinhold } 77185db3873SIngo Weinhold } 77285db3873SIngo Weinhold #endif // _BOOT_MODE 77385db3873SIngo Weinhold 77485db3873SIngo Weinhold // open the settings from the standardized location 77585db3873SIngo Weinhold if (driverName[0] != '/') { 77685db3873SIngo Weinhold char path[B_FILE_NAME_LENGTH + 64]; 77785db3873SIngo Weinhold 77885db3873SIngo Weinhold #ifdef _BOOT_MODE 779323b6546SOliver Tappe strcpy(path, kUserSettingsDirectory); 78085db3873SIngo Weinhold #else 7814b7e2196SIngo Weinhold // TODO: use B_SYSTEM_SETTINGS_DIRECTORY instead! 782de49e349SIngo Weinhold if (__find_directory(B_USER_SETTINGS_DIRECTORY, -1, false, path, 78385db3873SIngo Weinhold sizeof(path)) == B_OK) 78485db3873SIngo Weinhold #endif 78585db3873SIngo Weinhold { 78685db3873SIngo Weinhold strlcat(path, SETTINGS_DIRECTORY, sizeof(path)); 78785db3873SIngo Weinhold strlcat(path, driverName, sizeof(path)); 78885db3873SIngo Weinhold } 78985db3873SIngo Weinhold 79085db3873SIngo Weinhold file = open(path, O_RDONLY); 79185db3873SIngo Weinhold } else 79285db3873SIngo Weinhold file = open(driverName, O_RDONLY); 79385db3873SIngo Weinhold 79485db3873SIngo Weinhold if (file < B_OK) { 79585db3873SIngo Weinhold #ifdef _KERNEL_MODE 79685db3873SIngo Weinhold mutex_unlock(&sLock); 79785db3873SIngo Weinhold #endif 79885db3873SIngo Weinhold return NULL; 79985db3873SIngo Weinhold } 80085db3873SIngo Weinhold 80185db3873SIngo Weinhold handle = load_driver_settings_from_file(file, driverName); 80285db3873SIngo Weinhold 80385db3873SIngo Weinhold #ifdef _KERNEL_MODE 80485db3873SIngo Weinhold if (handle != NULL) 80585db3873SIngo Weinhold list_add_item(&sHandles, handle); 80685db3873SIngo Weinhold mutex_unlock(&sLock); 80785db3873SIngo Weinhold #endif 80885db3873SIngo Weinhold 80985db3873SIngo Weinhold close(file); 81085db3873SIngo Weinhold return (void *)handle; 81185db3873SIngo Weinhold } 81285db3873SIngo Weinhold 81385db3873SIngo Weinhold 814efe9df37SIngo Weinhold void* 815efe9df37SIngo Weinhold load_driver_settings_file(int fd) 816efe9df37SIngo Weinhold { 817efe9df37SIngo Weinhold return load_driver_settings_from_file(fd, NULL); 818efe9df37SIngo Weinhold } 819efe9df37SIngo Weinhold 820efe9df37SIngo Weinhold 82185db3873SIngo Weinhold /*! 82285db3873SIngo Weinhold Returns a new driver_settings handle that has the parsed contents 82385db3873SIngo Weinhold of the passed string. 82485db3873SIngo Weinhold You can get an empty driver_settings object when you pass NULL as 82585db3873SIngo Weinhold the "settingsString" parameter. 82685db3873SIngo Weinhold */ 82785db3873SIngo Weinhold void * 82885db3873SIngo Weinhold parse_driver_settings_string(const char *settingsString) 82985db3873SIngo Weinhold { 8301736cb1dSAdrien Destugues char *text = NULL; 8311736cb1dSAdrien Destugues if (settingsString != NULL) { 83285db3873SIngo Weinhold // we simply copy the whole string to use it as our internal buffer 8331736cb1dSAdrien Destugues text = strdup(settingsString); 8341736cb1dSAdrien Destugues if (text == NULL) 8351736cb1dSAdrien Destugues return NULL; 8361736cb1dSAdrien Destugues } 8371736cb1dSAdrien Destugues 8380687a01bSAdrien Destugues settings_handle *handle = new_settings(text, NULL); 8390687a01bSAdrien Destugues if (handle == NULL) 84085db3873SIngo Weinhold free(text); 8410687a01bSAdrien Destugues return handle; 84285db3873SIngo Weinhold } 84385db3873SIngo Weinhold 84485db3873SIngo Weinhold 84585db3873SIngo Weinhold /*! 84685db3873SIngo Weinhold This function prints out a driver settings structure to a human 84785db3873SIngo Weinhold readable string. 84885db3873SIngo Weinhold It's either in standard style or the single line style speficied 84985db3873SIngo Weinhold by the "flat" parameter. 85085db3873SIngo Weinhold If the buffer is too small to hold the string, B_BUFFER_OVERFLOW 85185db3873SIngo Weinhold is returned, and the needed amount of bytes if placed in the 85285db3873SIngo Weinhold "_bufferSize" parameter. 85385db3873SIngo Weinhold If the "handle" parameter is not a valid driver settings handle, or 85485db3873SIngo Weinhold the "buffer" parameter is NULL, B_BAD_VALUE is returned. 85585db3873SIngo Weinhold */ 85685db3873SIngo Weinhold status_t 857d2a423e4SPhilippe Saint-Pierre get_driver_settings_string(void *_handle, char *buffer, ssize_t *_bufferSize, 85885db3873SIngo Weinhold bool flat) 85985db3873SIngo Weinhold { 86085db3873SIngo Weinhold settings_handle *handle = (settings_handle *)_handle; 861d2a423e4SPhilippe Saint-Pierre ssize_t bufferSize = *_bufferSize; 86285db3873SIngo Weinhold int32 i; 86385db3873SIngo Weinhold 86485db3873SIngo Weinhold if (!check_handle(handle) || !buffer || *_bufferSize == 0) 86585db3873SIngo Weinhold return B_BAD_VALUE; 86685db3873SIngo Weinhold 86785db3873SIngo Weinhold for (i = 0; i < handle->settings.parameter_count; i++) { 86885db3873SIngo Weinhold put_parameter(&buffer, &bufferSize, &handle->settings.parameters[i], 86985db3873SIngo Weinhold 0, flat); 87085db3873SIngo Weinhold } 87185db3873SIngo Weinhold 87285db3873SIngo Weinhold *_bufferSize -= bufferSize; 87385db3873SIngo Weinhold return bufferSize >= 0 ? B_OK : B_BUFFER_OVERFLOW; 87485db3873SIngo Weinhold } 87585db3873SIngo Weinhold 87685db3873SIngo Weinhold 87785db3873SIngo Weinhold /*! 87885db3873SIngo Weinhold Matches the first value of the parameter matching "keyName" with a set 87985db3873SIngo Weinhold of boolean values like 1/true/yes/on/enabled/... 88085db3873SIngo Weinhold Returns "unknownValue" if the parameter could not be found or doesn't 88185db3873SIngo Weinhold have any valid boolean setting, and "noArgValue" if the parameter 88285db3873SIngo Weinhold doesn't have any values. 88385db3873SIngo Weinhold Also returns "unknownValue" if the handle passed in was not valid. 88485db3873SIngo Weinhold */ 88585db3873SIngo Weinhold bool 88685db3873SIngo Weinhold get_driver_boolean_parameter(void *_handle, const char *keyName, 88785db3873SIngo Weinhold bool unknownValue, bool noArgValue) 88885db3873SIngo Weinhold { 88985db3873SIngo Weinhold settings_handle *handle = (settings_handle*)_handle; 89085db3873SIngo Weinhold driver_parameter *parameter; 89185db3873SIngo Weinhold char *boolean; 89285db3873SIngo Weinhold 89385db3873SIngo Weinhold if (!check_handle(handle)) 89485db3873SIngo Weinhold return unknownValue; 89585db3873SIngo Weinhold 89685db3873SIngo Weinhold // check for the parameter 89785db3873SIngo Weinhold if ((parameter = get_parameter(handle, keyName)) == NULL) 89885db3873SIngo Weinhold return unknownValue; 89985db3873SIngo Weinhold 90085db3873SIngo Weinhold // check for the argument 90185db3873SIngo Weinhold if (parameter->value_count <= 0) 90285db3873SIngo Weinhold return noArgValue; 90385db3873SIngo Weinhold 90485db3873SIngo Weinhold boolean = parameter->values[0]; 90585db3873SIngo Weinhold if (!strcmp(boolean, "1") 90685db3873SIngo Weinhold || !strcasecmp(boolean, "true") 90785db3873SIngo Weinhold || !strcasecmp(boolean, "yes") 90885db3873SIngo Weinhold || !strcasecmp(boolean, "on") 90985db3873SIngo Weinhold || !strcasecmp(boolean, "enable") 91085db3873SIngo Weinhold || !strcasecmp(boolean, "enabled")) 91185db3873SIngo Weinhold return true; 91285db3873SIngo Weinhold 91385db3873SIngo Weinhold if (!strcmp(boolean, "0") 91485db3873SIngo Weinhold || !strcasecmp(boolean, "false") 91585db3873SIngo Weinhold || !strcasecmp(boolean, "no") 91685db3873SIngo Weinhold || !strcasecmp(boolean, "off") 91785db3873SIngo Weinhold || !strcasecmp(boolean, "disable") 91885db3873SIngo Weinhold || !strcasecmp(boolean, "disabled")) 91985db3873SIngo Weinhold return false; 92085db3873SIngo Weinhold 92185db3873SIngo Weinhold // if no known keyword is found, "unknownValue" is returned 92285db3873SIngo Weinhold return unknownValue; 92385db3873SIngo Weinhold } 92485db3873SIngo Weinhold 92585db3873SIngo Weinhold 92685db3873SIngo Weinhold const char * 92785db3873SIngo Weinhold get_driver_parameter(void *_handle, const char *keyName, 92885db3873SIngo Weinhold const char *unknownValue, const char *noArgValue) 92985db3873SIngo Weinhold { 93085db3873SIngo Weinhold settings_handle* handle = (settings_handle*)_handle; 93185db3873SIngo Weinhold struct driver_parameter *parameter; 93285db3873SIngo Weinhold 93385db3873SIngo Weinhold if (!check_handle(handle)) 93485db3873SIngo Weinhold return unknownValue; 93585db3873SIngo Weinhold 93685db3873SIngo Weinhold // check for the parameter 93785db3873SIngo Weinhold if ((parameter = get_parameter(handle, keyName)) == NULL) 93885db3873SIngo Weinhold return unknownValue; 93985db3873SIngo Weinhold 94085db3873SIngo Weinhold // check for the argument 94185db3873SIngo Weinhold if (parameter->value_count <= 0) 94285db3873SIngo Weinhold return noArgValue; 94385db3873SIngo Weinhold 94485db3873SIngo Weinhold return parameter->values[0]; 94585db3873SIngo Weinhold } 94685db3873SIngo Weinhold 94785db3873SIngo Weinhold 94885db3873SIngo Weinhold const driver_settings * 94985db3873SIngo Weinhold get_driver_settings(void *handle) 95085db3873SIngo Weinhold { 95185db3873SIngo Weinhold if (!check_handle((settings_handle*)handle)) 95285db3873SIngo Weinhold return NULL; 95385db3873SIngo Weinhold 95485db3873SIngo Weinhold return &((settings_handle *)handle)->settings; 95585db3873SIngo Weinhold } 95685db3873SIngo Weinhold 95785db3873SIngo Weinhold 958af435dd1SX512 #if defined(HAIKU_TARGET_PLATFORM_HAIKU) \ 959af435dd1SX512 && (defined(__i386__) || defined(__x86_64__)) 960af435dd1SX512 961af435dd1SX512 // Obsolete function, use unload_driver_settings instead. Introduced by 962af435dd1SX512 // accident in hrev3530 (2003) and present in public headers for a long time. 963*2770bfe8SAdrien Destugues B_DEFINE_WEAK_ALIAS(unload_driver_settings, delete_driver_settings); 964af435dd1SX512 965af435dd1SX512 #endif 966