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
312770bfe8SAdrien 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
is_parameter_separator(char c)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
is_word_break(char c)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
check_handle(settings_handle * handle)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 *
get_parameter(settings_handle * handle,const char * name)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
get_word(char ** _pos,char ** _word,int32 assignmentMode,bool allowNewLine)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
parse_parameter(struct driver_parameter * parameter,char ** _pos,int32 level)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
parse_parameters(struct driver_parameter ** _parameters,int * _count,char ** _pos,int32 level)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
parse_settings(settings_handle * handle)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
free_parameter(struct driver_parameter * parameter)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
free_settings(settings_handle * handle)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 *
new_settings(char * buffer,const char * driverName)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 *
load_driver_settings_from_file(int file,const char * driverName)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
put_string(char ** _buffer,ssize_t * _bufferSize,char * string)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
put_chars(char ** _buffer,ssize_t * _bufferSize,const char * chars)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
put_char(char ** _buffer,ssize_t * _bufferSize,char c)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
put_level_space(char ** _buffer,ssize_t * _bufferSize,int32 level)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
put_parameter(char ** _buffer,ssize_t * _bufferSize,struct driver_parameter * parameter,int32 level,bool flat)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 *
find_driver_settings(const char * name)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
driver_settings_init(kernel_args * args)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
unload_driver_settings(void * _handle)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 *
load_driver_settings(const char * driverName)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);
767*18f35e4eSMurai Takashi settings_handle *handle = new_settings(text, driverName);
768*18f35e4eSMurai Takashi if (handle == NULL)
769*18f35e4eSMurai Takashi free(text);
770*18f35e4eSMurai Takashi return handle;
77185db3873SIngo Weinhold }
77285db3873SIngo Weinhold settings = settings->next;
77385db3873SIngo Weinhold }
77485db3873SIngo Weinhold }
77585db3873SIngo Weinhold #endif // _BOOT_MODE
77685db3873SIngo Weinhold
77785db3873SIngo Weinhold // open the settings from the standardized location
77885db3873SIngo Weinhold if (driverName[0] != '/') {
77985db3873SIngo Weinhold char path[B_FILE_NAME_LENGTH + 64];
78085db3873SIngo Weinhold
78185db3873SIngo Weinhold #ifdef _BOOT_MODE
782323b6546SOliver Tappe strcpy(path, kUserSettingsDirectory);
78385db3873SIngo Weinhold #else
7844b7e2196SIngo Weinhold // TODO: use B_SYSTEM_SETTINGS_DIRECTORY instead!
785de49e349SIngo Weinhold if (__find_directory(B_USER_SETTINGS_DIRECTORY, -1, false, path,
78685db3873SIngo Weinhold sizeof(path)) == B_OK)
78785db3873SIngo Weinhold #endif
78885db3873SIngo Weinhold {
78985db3873SIngo Weinhold strlcat(path, SETTINGS_DIRECTORY, sizeof(path));
79085db3873SIngo Weinhold strlcat(path, driverName, sizeof(path));
79185db3873SIngo Weinhold }
79285db3873SIngo Weinhold
79385db3873SIngo Weinhold file = open(path, O_RDONLY);
79485db3873SIngo Weinhold } else
79585db3873SIngo Weinhold file = open(driverName, O_RDONLY);
79685db3873SIngo Weinhold
79785db3873SIngo Weinhold if (file < B_OK) {
79885db3873SIngo Weinhold #ifdef _KERNEL_MODE
79985db3873SIngo Weinhold mutex_unlock(&sLock);
80085db3873SIngo Weinhold #endif
80185db3873SIngo Weinhold return NULL;
80285db3873SIngo Weinhold }
80385db3873SIngo Weinhold
80485db3873SIngo Weinhold handle = load_driver_settings_from_file(file, driverName);
80585db3873SIngo Weinhold
80685db3873SIngo Weinhold #ifdef _KERNEL_MODE
80785db3873SIngo Weinhold if (handle != NULL)
80885db3873SIngo Weinhold list_add_item(&sHandles, handle);
80985db3873SIngo Weinhold mutex_unlock(&sLock);
81085db3873SIngo Weinhold #endif
81185db3873SIngo Weinhold
81285db3873SIngo Weinhold close(file);
81385db3873SIngo Weinhold return (void *)handle;
81485db3873SIngo Weinhold }
81585db3873SIngo Weinhold
81685db3873SIngo Weinhold
817efe9df37SIngo Weinhold void*
load_driver_settings_file(int fd)818efe9df37SIngo Weinhold load_driver_settings_file(int fd)
819efe9df37SIngo Weinhold {
820efe9df37SIngo Weinhold return load_driver_settings_from_file(fd, NULL);
821efe9df37SIngo Weinhold }
822efe9df37SIngo Weinhold
823efe9df37SIngo Weinhold
82485db3873SIngo Weinhold /*!
82585db3873SIngo Weinhold Returns a new driver_settings handle that has the parsed contents
82685db3873SIngo Weinhold of the passed string.
82785db3873SIngo Weinhold You can get an empty driver_settings object when you pass NULL as
82885db3873SIngo Weinhold the "settingsString" parameter.
82985db3873SIngo Weinhold */
83085db3873SIngo Weinhold void *
parse_driver_settings_string(const char * settingsString)83185db3873SIngo Weinhold parse_driver_settings_string(const char *settingsString)
83285db3873SIngo Weinhold {
8331736cb1dSAdrien Destugues char *text = NULL;
8341736cb1dSAdrien Destugues if (settingsString != NULL) {
83585db3873SIngo Weinhold // we simply copy the whole string to use it as our internal buffer
8361736cb1dSAdrien Destugues text = strdup(settingsString);
8371736cb1dSAdrien Destugues if (text == NULL)
8381736cb1dSAdrien Destugues return NULL;
8391736cb1dSAdrien Destugues }
8401736cb1dSAdrien Destugues
8410687a01bSAdrien Destugues settings_handle *handle = new_settings(text, NULL);
8420687a01bSAdrien Destugues if (handle == NULL)
84385db3873SIngo Weinhold free(text);
8440687a01bSAdrien Destugues return handle;
84585db3873SIngo Weinhold }
84685db3873SIngo Weinhold
84785db3873SIngo Weinhold
84885db3873SIngo Weinhold /*!
84985db3873SIngo Weinhold This function prints out a driver settings structure to a human
85085db3873SIngo Weinhold readable string.
85185db3873SIngo Weinhold It's either in standard style or the single line style speficied
85285db3873SIngo Weinhold by the "flat" parameter.
85385db3873SIngo Weinhold If the buffer is too small to hold the string, B_BUFFER_OVERFLOW
85485db3873SIngo Weinhold is returned, and the needed amount of bytes if placed in the
85585db3873SIngo Weinhold "_bufferSize" parameter.
85685db3873SIngo Weinhold If the "handle" parameter is not a valid driver settings handle, or
85785db3873SIngo Weinhold the "buffer" parameter is NULL, B_BAD_VALUE is returned.
85885db3873SIngo Weinhold */
85985db3873SIngo Weinhold status_t
get_driver_settings_string(void * _handle,char * buffer,ssize_t * _bufferSize,bool flat)860d2a423e4SPhilippe Saint-Pierre get_driver_settings_string(void *_handle, char *buffer, ssize_t *_bufferSize,
86185db3873SIngo Weinhold bool flat)
86285db3873SIngo Weinhold {
86385db3873SIngo Weinhold settings_handle *handle = (settings_handle *)_handle;
864d2a423e4SPhilippe Saint-Pierre ssize_t bufferSize = *_bufferSize;
86585db3873SIngo Weinhold int32 i;
86685db3873SIngo Weinhold
86785db3873SIngo Weinhold if (!check_handle(handle) || !buffer || *_bufferSize == 0)
86885db3873SIngo Weinhold return B_BAD_VALUE;
86985db3873SIngo Weinhold
87085db3873SIngo Weinhold for (i = 0; i < handle->settings.parameter_count; i++) {
87185db3873SIngo Weinhold put_parameter(&buffer, &bufferSize, &handle->settings.parameters[i],
87285db3873SIngo Weinhold 0, flat);
87385db3873SIngo Weinhold }
87485db3873SIngo Weinhold
87585db3873SIngo Weinhold *_bufferSize -= bufferSize;
87685db3873SIngo Weinhold return bufferSize >= 0 ? B_OK : B_BUFFER_OVERFLOW;
87785db3873SIngo Weinhold }
87885db3873SIngo Weinhold
87985db3873SIngo Weinhold
88085db3873SIngo Weinhold /*!
88185db3873SIngo Weinhold Matches the first value of the parameter matching "keyName" with a set
88285db3873SIngo Weinhold of boolean values like 1/true/yes/on/enabled/...
88385db3873SIngo Weinhold Returns "unknownValue" if the parameter could not be found or doesn't
88485db3873SIngo Weinhold have any valid boolean setting, and "noArgValue" if the parameter
88585db3873SIngo Weinhold doesn't have any values.
88685db3873SIngo Weinhold Also returns "unknownValue" if the handle passed in was not valid.
88785db3873SIngo Weinhold */
88885db3873SIngo Weinhold bool
get_driver_boolean_parameter(void * _handle,const char * keyName,bool unknownValue,bool noArgValue)88985db3873SIngo Weinhold get_driver_boolean_parameter(void *_handle, const char *keyName,
89085db3873SIngo Weinhold bool unknownValue, bool noArgValue)
89185db3873SIngo Weinhold {
89285db3873SIngo Weinhold settings_handle *handle = (settings_handle*)_handle;
89385db3873SIngo Weinhold driver_parameter *parameter;
89485db3873SIngo Weinhold char *boolean;
89585db3873SIngo Weinhold
89685db3873SIngo Weinhold if (!check_handle(handle))
89785db3873SIngo Weinhold return unknownValue;
89885db3873SIngo Weinhold
89985db3873SIngo Weinhold // check for the parameter
90085db3873SIngo Weinhold if ((parameter = get_parameter(handle, keyName)) == NULL)
90185db3873SIngo Weinhold return unknownValue;
90285db3873SIngo Weinhold
90385db3873SIngo Weinhold // check for the argument
90485db3873SIngo Weinhold if (parameter->value_count <= 0)
90585db3873SIngo Weinhold return noArgValue;
90685db3873SIngo Weinhold
90785db3873SIngo Weinhold boolean = parameter->values[0];
90885db3873SIngo Weinhold if (!strcmp(boolean, "1")
90985db3873SIngo Weinhold || !strcasecmp(boolean, "true")
91085db3873SIngo Weinhold || !strcasecmp(boolean, "yes")
91185db3873SIngo Weinhold || !strcasecmp(boolean, "on")
91285db3873SIngo Weinhold || !strcasecmp(boolean, "enable")
91385db3873SIngo Weinhold || !strcasecmp(boolean, "enabled"))
91485db3873SIngo Weinhold return true;
91585db3873SIngo Weinhold
91685db3873SIngo Weinhold if (!strcmp(boolean, "0")
91785db3873SIngo Weinhold || !strcasecmp(boolean, "false")
91885db3873SIngo Weinhold || !strcasecmp(boolean, "no")
91985db3873SIngo Weinhold || !strcasecmp(boolean, "off")
92085db3873SIngo Weinhold || !strcasecmp(boolean, "disable")
92185db3873SIngo Weinhold || !strcasecmp(boolean, "disabled"))
92285db3873SIngo Weinhold return false;
92385db3873SIngo Weinhold
92485db3873SIngo Weinhold // if no known keyword is found, "unknownValue" is returned
92585db3873SIngo Weinhold return unknownValue;
92685db3873SIngo Weinhold }
92785db3873SIngo Weinhold
92885db3873SIngo Weinhold
92985db3873SIngo Weinhold const char *
get_driver_parameter(void * _handle,const char * keyName,const char * unknownValue,const char * noArgValue)93085db3873SIngo Weinhold get_driver_parameter(void *_handle, const char *keyName,
93185db3873SIngo Weinhold const char *unknownValue, const char *noArgValue)
93285db3873SIngo Weinhold {
93385db3873SIngo Weinhold settings_handle* handle = (settings_handle*)_handle;
93485db3873SIngo Weinhold struct driver_parameter *parameter;
93585db3873SIngo Weinhold
93685db3873SIngo Weinhold if (!check_handle(handle))
93785db3873SIngo Weinhold return unknownValue;
93885db3873SIngo Weinhold
93985db3873SIngo Weinhold // check for the parameter
94085db3873SIngo Weinhold if ((parameter = get_parameter(handle, keyName)) == NULL)
94185db3873SIngo Weinhold return unknownValue;
94285db3873SIngo Weinhold
94385db3873SIngo Weinhold // check for the argument
94485db3873SIngo Weinhold if (parameter->value_count <= 0)
94585db3873SIngo Weinhold return noArgValue;
94685db3873SIngo Weinhold
94785db3873SIngo Weinhold return parameter->values[0];
94885db3873SIngo Weinhold }
94985db3873SIngo Weinhold
95085db3873SIngo Weinhold
95185db3873SIngo Weinhold const driver_settings *
get_driver_settings(void * handle)95285db3873SIngo Weinhold get_driver_settings(void *handle)
95385db3873SIngo Weinhold {
95485db3873SIngo Weinhold if (!check_handle((settings_handle*)handle))
95585db3873SIngo Weinhold return NULL;
95685db3873SIngo Weinhold
95785db3873SIngo Weinhold return &((settings_handle *)handle)->settings;
95885db3873SIngo Weinhold }
95985db3873SIngo Weinhold
96085db3873SIngo Weinhold
961af435dd1SX512 #if defined(HAIKU_TARGET_PLATFORM_HAIKU) \
962af435dd1SX512 && (defined(__i386__) || defined(__x86_64__))
963af435dd1SX512
964af435dd1SX512 // Obsolete function, use unload_driver_settings instead. Introduced by
965af435dd1SX512 // accident in hrev3530 (2003) and present in public headers for a long time.
9662770bfe8SAdrien Destugues B_DEFINE_WEAK_ALIAS(unload_driver_settings, delete_driver_settings);
967af435dd1SX512
968af435dd1SX512 #endif
969