1/*
2 * Copyright 2002-2007, Axel D��rfler, axeld@pinc-software.de.
3 * This file may be used under the terms of the MIT License.
4 */
5
6/*!	\brief Implements the driver settings API
7	This file is used by three different components with different needs:
8	  1) the boot loader
9		Buffers a list of settings files to move over to the kernel - the
10		actual buffering is located in the boot loader directly, though.
11		Creates driver_settings structures out of those on demand only.
12	  2) the kernel
13		Maintains a list of settings so that no disk access is required
14		for known settings (such as those passed over from the boot
15		loader).
16	  3) libroot.so
17		Exports the parser to userland applications, so that they can
18		easily make use of driver_settings styled files.
19
20	The file has to be recompiled for every component separately, so that
21	it properly exports the required functionality (which is specified by
22	_BOOT_MODE for the boot loader, and _KERNEL_MODE for the kernel).
23*/
24
25// The boot loader is compiled with kernel rules, but we want to explicitely
26// differentiate between the two here.
27#ifdef _BOOT_MODE
28#	undef _KERNEL_MODE
29#endif
30
31#include <BeBuild.h>
32#include <directories.h>
33#include <driver_settings.h>
34#include <FindDirectory.h>
35#include <OS.h>
36
37#ifdef _KERNEL_MODE
38#	include <KernelExport.h>
39#	include <util/list.h>
40#	include <lock.h>
41#	include <kdriver_settings.h>
42#	include <kernel.h>
43#	include <boot/kernel_args.h>
44#	include <boot_device.h>
45#endif
46#ifdef _BOOT_MODE
47#	include <boot/kernel_args.h>
48#	include <boot/stage2.h>
49#else
50#	include <find_directory_private.h>
51#endif
52
53#include <stdlib.h>
54#include <string.h>
55#include <strings.h>
56#include <unistd.h>
57#include <fcntl.h>
58#include <ctype.h>
59
60#ifndef B_BUFFER_OVERFLOW
61#	define B_BUFFER_OVERFLOW B_ERROR
62#endif
63
64#define SETTINGS_DIRECTORY "/kernel/drivers/"
65#define SETTINGS_MAGIC		'DrvS'
66
67// Those maximum values are independent from the implementation - they
68// have been chosen to make the code more robust against bad files
69#define MAX_SETTINGS_SIZE	32768
70#define MAX_SETTINGS_LEVEL	8
71
72#define CONTINUE_PARAMETER	1
73#define NO_PARAMETER 2
74
75
76typedef struct settings_handle {
77#ifdef _KERNEL_MODE
78	list_link	link;
79	char		name[B_OS_NAME_LENGTH];
80	int32		ref_count;
81		// A negative ref_count means the node is not reference counted and not
82		// stored in the list.
83#endif
84	int32		magic;
85	struct		driver_settings settings;
86	char		*text;
87} settings_handle;
88
89
90enum assignment_mode {
91	NO_ASSIGNMENT,
92	ALLOW_ASSIGNMENT,
93	IGNORE_ASSIGNMENT
94};
95
96
97#ifdef _KERNEL_MODE
98static struct list sHandles;
99static mutex sLock = MUTEX_INITIALIZER("driver settings");
100#endif
101
102
103//	#pragma mark - private functions
104
105
106/*!
107	\brief Returns true for any characters that separate parameters
108
109	Those characters are ignored in the input stream and won't be added
110	to any words.
111*/
112static inline bool
113is_parameter_separator(char c)
114{
115	return c == '\n' || c == ';';
116}
117
118
119/*! Indicates if "c" begins a new word or not.
120*/
121static inline bool
122is_word_break(char c)
123{
124	return isspace(c) || is_parameter_separator(c);
125}
126
127
128static inline bool
129check_handle(settings_handle *handle)
130{
131	if (handle == NULL
132		|| handle->magic != SETTINGS_MAGIC)
133		return false;
134
135	return true;
136}
137
138
139static driver_parameter *
140get_parameter(settings_handle *handle, const char *name)
141{
142	int32 i;
143	for (i = handle->settings.parameter_count; i-- > 0;) {
144		if (!strcmp(handle->settings.parameters[i].name, name))
145			return &handle->settings.parameters[i];
146	}
147	return NULL;
148}
149
150
151/*!
152	Returns the next word in the input buffer passed in via "_pos" - if
153	this function returns, it will bump the input position after the word.
154	It automatically cares about quoted strings and escaped characters.
155	If "allowNewLine" is true, it reads over comments to get to the next
156	word.
157	Depending on the "assignmentMode" parameter, the '=' sign is either
158	used as a work break, or not.
159	The input buffer will be changed to contain the word without quotes
160	or escaped characters and adds a terminating NULL byte. The "_word"
161	parameter will be set to the beginning of the word.
162	If the word is followed by a newline it will return B_OK, if white
163	spaces follows, it will return CONTINUE_PARAMETER.
164*/
165static status_t
166get_word(char **_pos, char **_word, int32 assignmentMode, bool allowNewLine)
167{
168	char *pos = *_pos;
169	char quoted = 0;
170	bool newLine = false, end = false;
171	int escaped = 0;
172	bool charEscaped = false;
173
174	// Skip any white space and comments
175	while (pos[0]
176		&& ((allowNewLine && (isspace(pos[0]) || is_parameter_separator(pos[0])
177				|| pos[0] == '#'))
178			|| (!allowNewLine && (pos[0] == '\t' || pos[0] == ' '))
179			|| (assignmentMode == ALLOW_ASSIGNMENT && pos[0] == '='))) {
180		// skip any comment lines
181		if (pos[0] == '#') {
182			while (pos[0] && pos[0] != '\n')
183				pos++;
184		}
185		pos++;
186	}
187
188	if (pos[0] == '}' || pos[0] == '\0') {
189		// if we just read some white space before an end of a
190		// parameter, this is just no parameter at all
191		*_pos = pos;
192		return NO_PARAMETER;
193	}
194
195	// Read in a word - might contain escaped (\) spaces, or it
196	// might also be quoted (" or ').
197
198	if (pos[0] == '"' || pos[0] == '\'') {
199		quoted = pos[0];
200		pos++;
201	}
202	*_word = pos;
203
204	while (pos[0]) {
205		if (charEscaped)
206			charEscaped = false;
207		else if (pos[0] == '\\') {
208			charEscaped = true;
209			escaped++;
210		} else if ((!quoted && (is_word_break(pos[0])
211				|| (assignmentMode != IGNORE_ASSIGNMENT && pos[0] == '=')))
212			|| (quoted && pos[0] == quoted))
213			break;
214
215		pos++;
216	}
217
218	// "String exceeds line" - missing end quote
219	if (quoted && pos[0] != quoted)
220		return B_BAD_DATA;
221
222	// last character is a backslash
223	if (charEscaped)
224		return B_BAD_DATA;
225
226	end = pos[0] == '\0';
227	newLine = is_parameter_separator(pos[0]) || end;
228	pos[0] = '\0';
229
230	// Correct name if there were any escaped characters
231	if (escaped) {
232		char *word = *_word;
233		int offset = 0;
234		while (word <= pos) {
235			if (word[0] == '\\') {
236				offset--;
237				word++;
238			}
239			word[offset] = word[0];
240			word++;
241		}
242	}
243
244	if (end) {
245		*_pos = pos;
246		return B_OK;
247	}
248
249	// Scan for next beginning word, open brackets, or comment start
250
251	pos++;
252	while (true) {
253		*_pos = pos;
254		if (!pos[0])
255			return B_NO_ERROR;
256
257		if (is_parameter_separator(pos[0])) {
258			// an open bracket '{' could follow after the first
259			// newline, but not later
260			if (newLine)
261				return B_NO_ERROR;
262
263			newLine = true;
264		} else if (pos[0] == '{' || pos[0] == '}' || pos[0] == '#')
265			return B_NO_ERROR;
266		else if (!isspace(pos[0]))
267			return newLine ? B_NO_ERROR : CONTINUE_PARAMETER;
268
269		pos++;
270	}
271}
272
273
274static status_t
275parse_parameter(struct driver_parameter *parameter, char **_pos, int32 level)
276{
277	char *pos = *_pos;
278	status_t status;
279
280	// initialize parameter first
281	memset(parameter, 0, sizeof(struct driver_parameter));
282
283	status = get_word(&pos, &parameter->name, NO_ASSIGNMENT, true);
284	if (status == CONTINUE_PARAMETER) {
285		while (status == CONTINUE_PARAMETER) {
286			char **newArray, *value = NULL;
287			status = get_word(&pos, &value, parameter->value_count == 0
288				? ALLOW_ASSIGNMENT : IGNORE_ASSIGNMENT, false);
289			if (status < B_OK)
290				break;
291
292			// enlarge value array and save the value
293
294			newArray = (char**)realloc(parameter->values,
295				(parameter->value_count + 1) * sizeof(char *));
296			if (newArray == NULL)
297				return B_NO_MEMORY;
298
299			parameter->values = newArray;
300			parameter->values[parameter->value_count++] = value;
301		}
302	}
303
304	*_pos = pos;
305	return status;
306}
307
308
309static status_t
310parse_parameters(struct driver_parameter **_parameters, int *_count,
311	char **_pos, int32 level)
312{
313	if (level > MAX_SETTINGS_LEVEL)
314		return B_LINK_LIMIT;
315
316	while (true) {
317		struct driver_parameter parameter;
318		struct driver_parameter *newArray;
319		status_t status;
320
321		status = parse_parameter(&parameter, _pos, level);
322		if (status < B_OK)
323			return status;
324
325		if (status != NO_PARAMETER) {
326			driver_parameter *newParameter;
327
328			newArray = (driver_parameter*)realloc(*_parameters, (*_count + 1)
329				* sizeof(struct driver_parameter));
330			if (newArray == NULL)
331				return B_NO_MEMORY;
332
333			memcpy(&newArray[*_count], &parameter, sizeof(struct driver_parameter));
334			newParameter = &newArray[*_count];
335
336			*_parameters = newArray;
337			(*_count)++;
338
339			// check for level beginning and end
340			if (**_pos == '{') {
341				// if we go a level deeper, just start all over again...
342				(*_pos)++;
343				status = parse_parameters(&newParameter->parameters,
344							&newParameter->parameter_count, _pos, level + 1);
345				if (status < B_OK)
346					return status;
347			}
348		}
349
350		if ((**_pos == '}' && level > 0)
351			|| (**_pos == '\0' && level == 0)) {
352			// take the closing bracket from the stack
353			(*_pos)++;
354			return B_OK;
355		}
356
357		// obviously, something has gone wrong
358		if (**_pos == '}' || **_pos == '\0')
359			return B_ERROR;
360	}
361}
362
363
364static status_t
365parse_settings(settings_handle *handle)
366{
367	char *text = handle->text;
368
369	memset(&handle->settings, 0, sizeof(struct driver_settings));
370
371	// empty settings are allowed
372	if (text == NULL)
373		return B_OK;
374
375	return parse_parameters(&handle->settings.parameters,
376		&handle->settings.parameter_count, &text, 0);
377}
378
379
380static void
381free_parameter(struct driver_parameter *parameter)
382{
383	int32 i;
384	for (i = parameter->parameter_count; i-- > 0;)
385		free_parameter(&parameter->parameters[i]);
386
387	free(parameter->parameters);
388	free(parameter->values);
389}
390
391
392static void
393free_settings(settings_handle *handle)
394{
395	int32 i;
396	for (i = handle->settings.parameter_count; i-- > 0;)
397		free_parameter(&handle->settings.parameters[i]);
398
399	free(handle->settings.parameters);
400	free(handle->text);
401	free(handle);
402}
403
404
405static settings_handle *
406new_settings(char *buffer, const char *driverName)
407{
408	settings_handle *handle = (settings_handle*)malloc(sizeof(settings_handle));
409	if (handle == NULL)
410		return NULL;
411
412	handle->magic = SETTINGS_MAGIC;
413	handle->text = buffer;
414
415#ifdef _KERNEL_MODE
416	if (driverName != NULL) {
417		handle->ref_count = 1;
418		strlcpy(handle->name, driverName, sizeof(handle->name));
419	} else {
420		handle->ref_count = -1;
421		handle->name[0] = 0;
422	}
423#endif
424
425	if (parse_settings(handle) == B_OK)
426		return handle;
427
428	free(handle);
429	return NULL;
430}
431
432
433static settings_handle *
434load_driver_settings_from_file(int file, const char *driverName)
435{
436	struct stat stat;
437
438	// Allocate a buffer and read the whole file into it.
439	// We will keep this buffer in memory, until the settings
440	// are unloaded.
441	// The driver_parameter::name field will point directly
442	// to this buffer.
443
444	if (fstat(file, &stat) < B_OK)
445		return NULL;
446
447	if (stat.st_size > B_OK && stat.st_size < MAX_SETTINGS_SIZE) {
448		char *text = (char *)malloc(stat.st_size + 1);
449		if (text != NULL && read(file, text, stat.st_size) == stat.st_size) {
450			settings_handle *handle;
451
452			text[stat.st_size] = '\0';
453				// make sure the string is null terminated
454				// to avoid misbehaviour
455
456			handle = new_settings(text, driverName);
457			if (handle != NULL) {
458				// everything went fine!
459				return handle;
460			}
461		}
462		// "text" might be NULL here, but that's allowed
463		free(text);
464	}
465
466	return NULL;
467}
468
469
470static bool
471put_string(char **_buffer, ssize_t *_bufferSize, char *string)
472{
473	size_t length, reserved, quotes;
474	char *buffer = *_buffer, c;
475	bool quoted;
476
477	if (string == NULL)
478		return true;
479
480	for (length = reserved = quotes = 0; (c = string[length]) != '\0'; length++) {
481		if (c == '"')
482			quotes++;
483		else if (is_word_break(c))
484			reserved++;
485	}
486	quoted = reserved || quotes;
487
488	// update _bufferSize in any way, so that we can chain several
489	// of these calls without having to check the return value
490	// everytime
491	*_bufferSize -= length + (quoted ? 2 + quotes : 0);
492
493	if (*_bufferSize <= 0)
494		return false;
495
496	if (quoted)
497		*(buffer++) = '"';
498
499	for (;(c = string[0]) != '\0'; string++) {
500		if (c == '"')
501			*(buffer++) = '\\';
502
503		*(buffer++) = c;
504	}
505
506	if (quoted)
507		*(buffer++) = '"';
508
509	buffer[0] = '\0';
510
511	// update the buffer position
512	*_buffer = buffer;
513
514	return true;
515}
516
517
518static bool
519put_chars(char **_buffer, ssize_t *_bufferSize, const char *chars)
520{
521	char *buffer = *_buffer;
522	size_t length;
523
524	if (chars == NULL)
525		return true;
526
527	length = strlen(chars);
528	*_bufferSize -= length;
529
530	if (*_bufferSize <= 0)
531		return false;
532
533	memcpy(buffer, chars, length);
534	buffer += length;
535	buffer[0] = '\0';
536
537	// update the buffer position
538	*_buffer = buffer;
539
540	return true;
541}
542
543
544static bool
545put_char(char **_buffer, ssize_t *_bufferSize, char c)
546{
547	char *buffer = *_buffer;
548
549	*_bufferSize -= 1;
550
551	if (*_bufferSize <= 0)
552		return false;
553
554	buffer[0] = c;
555	buffer[1] = '\0';
556
557	// update the buffer position
558	*_buffer = buffer + 1;
559
560	return true;
561}
562
563
564static void
565put_level_space(char **_buffer, ssize_t *_bufferSize, int32 level)
566{
567	while (level-- > 0)
568		put_char(_buffer, _bufferSize, '\t');
569}
570
571
572static void
573put_parameter(char **_buffer, ssize_t *_bufferSize,
574	struct driver_parameter *parameter, int32 level, bool flat)
575{
576	int32 i;
577
578	if (!flat)
579		put_level_space(_buffer, _bufferSize, level);
580
581	put_string(_buffer, _bufferSize, parameter->name);
582	if (flat && parameter->value_count > 0)
583		put_chars(_buffer, _bufferSize, " =");
584
585	for (i = 0; i < parameter->value_count; i++) {
586		put_char(_buffer, _bufferSize, ' ');
587		put_string(_buffer, _bufferSize, parameter->values[i]);
588	}
589
590	if (parameter->parameter_count > 0) {
591		put_chars(_buffer, _bufferSize, " {");
592		if (!flat)
593			put_char(_buffer, _bufferSize, '\n');
594
595		for (i = 0; i < parameter->parameter_count; i++) {
596			put_parameter(_buffer, _bufferSize, &parameter->parameters[i],
597				level + 1, flat);
598
599			if (parameter->parameters[i].parameter_count == 0)
600				put_chars(_buffer, _bufferSize, flat ? "; " : "\n");
601		}
602
603		if (!flat)
604			put_level_space(_buffer, _bufferSize, level);
605		put_chars(_buffer, _bufferSize, flat ? "}" : "}\n");
606	}
607}
608
609
610//	#pragma mark - Kernel only functions
611
612
613#ifdef _KERNEL_MODE
614static settings_handle *
615find_driver_settings(const char *name)
616{
617	settings_handle *handle = NULL;
618
619	ASSERT_LOCKED_MUTEX(&sLock);
620
621	while ((handle = (settings_handle*)list_get_next_item(&sHandles, handle))
622			!= NULL) {
623		if (!strcmp(handle->name, name))
624			return handle;
625	}
626
627	return NULL;
628}
629
630
631status_t
632driver_settings_init(kernel_args *args)
633{
634	struct driver_settings_file *settings = args->driver_settings;
635
636	// Move the preloaded driver settings over to the kernel
637
638	list_init(&sHandles);
639
640	while (settings != NULL) {
641		settings_handle *handle
642			= (settings_handle*)malloc(sizeof(settings_handle));
643		if (handle == NULL)
644			return B_NO_MEMORY;
645
646		if (settings->size != 0) {
647			handle->text = (char*)malloc(settings->size + 1);
648			if (handle->text == NULL) {
649				free(handle);
650				return B_NO_MEMORY;
651			}
652
653			memcpy(handle->text, settings->buffer, settings->size);
654			handle->text[settings->size] = '\0';
655				// null terminate the buffer
656		} else
657			handle->text = NULL;
658
659		strlcpy(handle->name, settings->name, sizeof(handle->name));
660		handle->settings.parameters = NULL;
661		handle->settings.parameter_count = 0;
662		handle->magic = 0;
663			// this triggers parsing the settings when they are actually used
664
665		if (!strcmp(handle->name, B_SAFEMODE_DRIVER_SETTINGS)) {
666			// These settings cannot be reloaded, so we better don't throw
667			// them away.
668			handle->ref_count = 1;
669		} else
670			handle->ref_count = 0;
671
672		list_add_item(&sHandles, handle);
673
674		settings = settings->next;
675	}
676
677	return B_OK;
678}
679#endif
680
681
682//	#pragma mark - public API
683
684
685status_t
686unload_driver_settings(void *_handle)
687{
688	settings_handle *handle = (settings_handle *)_handle;
689	if (!check_handle(handle))
690		return B_BAD_VALUE;
691
692#ifdef _KERNEL_MODE
693	mutex_lock(&sLock);
694
695	if (handle->ref_count > 0) {
696		if (--handle->ref_count == 0 && gBootDevice > 0) {
697			// don't unload an handle when /boot is not available
698			list_remove_link(&handle->link);
699		} else
700			handle = NULL;
701	}
702	mutex_unlock(&sLock);
703#endif
704
705	if (handle != NULL)
706		free_settings(handle);
707
708	return B_OK;
709}
710
711
712void *
713load_driver_settings(const char *driverName)
714{
715	settings_handle *handle;
716	int file = -1;
717
718	if (driverName == NULL)
719		return NULL;
720
721#ifdef _KERNEL_MODE
722	// see if we already have these settings loaded
723	mutex_lock(&sLock);
724	handle = find_driver_settings(driverName);
725	if (handle != NULL && handle->ref_count == 0 && gBootDevice > 0) {
726		// A handle with a zero ref_count should be unloaded if /boot is
727		// available.
728		list_remove_link(&handle->link);
729		free_settings(handle);
730	} else if (handle != NULL) {
731		handle->ref_count++;
732
733		// we got it, now let's see if it already has been parsed
734		if (handle->magic != SETTINGS_MAGIC) {
735			handle->magic = SETTINGS_MAGIC;
736
737			if (parse_settings(handle) != B_OK) {
738				// no valid settings, let's cut down its memory requirements
739				free(handle->text);
740				handle->text = NULL;
741				handle = NULL;
742			}
743		}
744		mutex_unlock(&sLock);
745		return handle;
746	}
747
748	// we are allowed to call the driver settings pretty early in the boot process
749	if (gKernelStartup) {
750		mutex_unlock(&sLock);
751		return NULL;
752	}
753#endif	// _KERNEL_MODE
754#ifdef _BOOT_MODE
755	// see if we already have these settings loaded
756	{
757		struct driver_settings_file *settings = gKernelArgs.driver_settings;
758		while (settings != NULL) {
759			if (!strcmp(settings->name, driverName)) {
760				// we have it - since the buffer is clobbered, we have to
761				// copy its contents, though
762				char *text = (char*)malloc(settings->size + 1);
763				if (text == NULL)
764					return NULL;
765
766				memcpy(text, settings->buffer, settings->size + 1);
767				settings_handle *handle =  new_settings(text, driverName);
768				if (handle == NULL)
769					free(text);
770				return handle;
771			}
772			settings = settings->next;
773		}
774	}
775#endif	// _BOOT_MODE
776
777	// open the settings from the standardized location
778	if (driverName[0] != '/') {
779		char path[B_FILE_NAME_LENGTH + 64];
780
781#ifdef _BOOT_MODE
782		strcpy(path, kUserSettingsDirectory);
783#else
784		// TODO: use B_SYSTEM_SETTINGS_DIRECTORY instead!
785		if (__find_directory(B_USER_SETTINGS_DIRECTORY, -1, false, path,
786				sizeof(path)) == B_OK)
787#endif
788		{
789			strlcat(path, SETTINGS_DIRECTORY, sizeof(path));
790			strlcat(path, driverName, sizeof(path));
791		}
792
793		file = open(path, O_RDONLY);
794	} else
795		file = open(driverName, O_RDONLY);
796
797	if (file < B_OK) {
798#ifdef _KERNEL_MODE
799		mutex_unlock(&sLock);
800#endif
801		return NULL;
802	}
803
804	handle = load_driver_settings_from_file(file, driverName);
805
806#ifdef _KERNEL_MODE
807	if (handle != NULL)
808		list_add_item(&sHandles, handle);
809	mutex_unlock(&sLock);
810#endif
811
812	close(file);
813	return (void *)handle;
814}
815
816
817void*
818load_driver_settings_file(int fd)
819{
820	return load_driver_settings_from_file(fd, NULL);
821}
822
823
824/*!
825	Returns a new driver_settings handle that has the parsed contents
826	of the passed string.
827	You can get an empty driver_settings object when you pass NULL as
828	the "settingsString" parameter.
829*/
830void *
831parse_driver_settings_string(const char *settingsString)
832{
833	char *text = NULL;
834	if (settingsString != NULL) {
835		// we simply copy the whole string to use it as our internal buffer
836		text = strdup(settingsString);
837		if (text == NULL)
838			return NULL;
839	}
840
841	settings_handle *handle = new_settings(text, NULL);
842	if (handle == NULL)
843		free(text);
844	return handle;
845}
846
847
848/*!
849	This function prints out a driver settings structure to a human
850	readable string.
851	It's either in standard style or the single line style speficied
852	by the "flat" parameter.
853	If the buffer is too small to hold the string, B_BUFFER_OVERFLOW
854	is returned, and the needed amount of bytes if placed in the
855	"_bufferSize" parameter.
856	If the "handle" parameter is not a valid driver settings handle, or
857	the "buffer" parameter is NULL, B_BAD_VALUE is returned.
858*/
859status_t
860get_driver_settings_string(void *_handle, char *buffer, ssize_t *_bufferSize,
861	bool flat)
862{
863	settings_handle *handle = (settings_handle *)_handle;
864	ssize_t bufferSize = *_bufferSize;
865	int32 i;
866
867	if (!check_handle(handle) || !buffer || *_bufferSize == 0)
868		return B_BAD_VALUE;
869
870	for (i = 0; i < handle->settings.parameter_count; i++) {
871		put_parameter(&buffer, &bufferSize, &handle->settings.parameters[i],
872			0, flat);
873	}
874
875	*_bufferSize -= bufferSize;
876	return bufferSize >= 0 ? B_OK : B_BUFFER_OVERFLOW;
877}
878
879
880/*!
881	Matches the first value of the parameter matching "keyName" with a set
882	of boolean values like 1/true/yes/on/enabled/...
883	Returns "unknownValue" if the parameter could not be found or doesn't
884	have any valid boolean setting, and "noArgValue" if the parameter
885	doesn't have any values.
886	Also returns "unknownValue" if the handle passed in was not valid.
887*/
888bool
889get_driver_boolean_parameter(void *_handle, const char *keyName,
890	bool unknownValue, bool noArgValue)
891{
892	settings_handle *handle = (settings_handle*)_handle;
893	driver_parameter *parameter;
894	char *boolean;
895
896	if (!check_handle(handle))
897		return unknownValue;
898
899	// check for the parameter
900	if ((parameter = get_parameter(handle, keyName)) == NULL)
901		return unknownValue;
902
903	// check for the argument
904	if (parameter->value_count <= 0)
905		return noArgValue;
906
907	boolean = parameter->values[0];
908	if (!strcmp(boolean, "1")
909		|| !strcasecmp(boolean, "true")
910		|| !strcasecmp(boolean, "yes")
911		|| !strcasecmp(boolean, "on")
912		|| !strcasecmp(boolean, "enable")
913		|| !strcasecmp(boolean, "enabled"))
914		return true;
915
916	if (!strcmp(boolean, "0")
917		|| !strcasecmp(boolean, "false")
918		|| !strcasecmp(boolean, "no")
919		|| !strcasecmp(boolean, "off")
920		|| !strcasecmp(boolean, "disable")
921		|| !strcasecmp(boolean, "disabled"))
922		return false;
923
924	// if no known keyword is found, "unknownValue" is returned
925	return unknownValue;
926}
927
928
929const char *
930get_driver_parameter(void *_handle, const char *keyName,
931	const char *unknownValue, const char *noArgValue)
932{
933	settings_handle* handle = (settings_handle*)_handle;
934	struct driver_parameter *parameter;
935
936	if (!check_handle(handle))
937		return unknownValue;
938
939	// check for the parameter
940	if ((parameter = get_parameter(handle, keyName)) == NULL)
941		return unknownValue;
942
943	// check for the argument
944	if (parameter->value_count <= 0)
945		return noArgValue;
946
947	return parameter->values[0];
948}
949
950
951const driver_settings *
952get_driver_settings(void *handle)
953{
954	if (!check_handle((settings_handle*)handle))
955		return NULL;
956
957	return &((settings_handle *)handle)->settings;
958}
959
960
961#if defined(HAIKU_TARGET_PLATFORM_HAIKU) \
962	&& (defined(__i386__) || defined(__x86_64__))
963
964// Obsolete function, use unload_driver_settings instead. Introduced by
965// accident in hrev3530 (2003) and present in public headers for a long time.
966B_DEFINE_WEAK_ALIAS(unload_driver_settings, delete_driver_settings);
967
968#endif
969