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