From d5062208bba9faf01c6b51eec64b80cae824dd51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Thu, 2 Mar 2006 22:48:47 +0000 Subject: [PATCH] * Added a new list_insert_item_before() function that inserts a new item before another one in the list. * The video modes in the boot loader are now sorted (by resolution, larger resolution comes first). Doubled entries are automatically removed; this fixes bug #192. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16572 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/util/list.h | 9 +- src/system/boot/platform/bios_ia32/video.cpp | 154 ++++++++++++------- src/system/kernel/util/list.c | 35 ++++- 3 files changed, 134 insertions(+), 64 deletions(-) diff --git a/headers/private/kernel/util/list.h b/headers/private/kernel/util/list.h index b06d2bf7e3..4a523cd14b 100644 --- a/headers/private/kernel/util/list.h +++ b/headers/private/kernel/util/list.h @@ -1,7 +1,7 @@ -/* -** Copyright 2003-2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved. -** Distributed under the terms of the OpenBeOS License. -*/ +/* + * Copyright 2003-2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ #ifndef KERNEL_LIST_H #define KERNEL_LIST_H @@ -50,6 +50,7 @@ extern void *list_get_next_item(struct list *list, void *item); extern void *list_get_prev_item(struct list *list, void *item); extern void list_add_item(struct list *list, void *item); extern void list_remove_item(struct list *list, void *item); +extern void list_insert_item_before(struct list *list, void *before, void *item); extern void *list_remove_head_item(struct list *list); extern void *list_remove_tail_item(struct list *list); extern void list_move_to_list(struct list *sourceList, struct list *targetList); diff --git a/src/system/boot/platform/bios_ia32/video.cpp b/src/system/boot/platform/bios_ia32/video.cpp index 08a1d8f7e9..08b363448e 100644 --- a/src/system/boot/platform/bios_ia32/video.cpp +++ b/src/system/boot/platform/bios_ia32/video.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2004-2006, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ @@ -46,6 +46,102 @@ static bool sModeChosen; static bool sSettingsLoaded; +static int +compare_video_modes(video_mode *a, video_mode *b) +{ + int compare = a->width - b->width; + if (compare != 0) + return compare; + + compare = a->height - b->height; + if (compare != 0) + return compare; + + // TODO: compare video_mode::mode? + return a->bits_per_pixel - b->bits_per_pixel; +} + + +/** Insert the video mode into the list, sorted by resolution and bit depth. + * Higher resolutions/depths come first. + */ + +static void +add_video_mode(video_mode *videoMode) +{ + video_mode *mode = NULL; + while ((mode = (video_mode *)list_get_next_item(&sModeList, mode)) != NULL) { + int compare = compare_video_modes(videoMode, mode); + if (compare == 0) { + // mode already exists + return; + } + + if (compare > 0) + break; + } + + list_insert_item_before(&sModeList, mode, videoMode); +} + + +static video_mode * +find_video_mode(int32 width, int32 height, int32 depth) +{ + video_mode *mode = NULL; + while ((mode = (video_mode *)list_get_next_item(&sModeList, mode)) != NULL) { + if (mode->width == width + && mode->height == height + && mode->bits_per_pixel == depth) { + return mode; + } + } + + return NULL; +} + + +static void +get_mode_from_settings(void) +{ + if (sSettingsLoaded) + return; + + void *handle = load_driver_settings("vesa"); + if (handle == NULL) + return; + + const driver_settings *settings = get_driver_settings(handle); + if (settings == NULL) + goto out; + + sSettingsLoaded = true; + + for (int32 i = 0; i < settings->parameter_count; i++) { + driver_parameter ¶meter = settings->parameters[i]; + + if (!strcmp(parameter.name, "mode") && parameter.value_count > 2) { + // parameter found, now get its values + int32 width = strtol(parameter.values[0], NULL, 0); + int32 height = strtol(parameter.values[1], NULL, 0); + int32 depth = strtol(parameter.values[2], NULL, 0); + + // search mode that fits + + video_mode *mode = find_video_mode(width, height, depth); + if (mode != NULL) + sMode = mode; + } + } + +out: + unload_driver_settings(handle); +} + + +// #pragma mark - vga + + static void vga_set_palette(const uint8 *palette, int32 firstIndex, int32 numEntries) { @@ -189,7 +285,7 @@ vesa_init(vbe_info_block *info, video_mode **_standardMode) } } - list_add_item(&sModeList, videoMode); + add_video_mode(videoMode); } } else TRACE(("(failed)\n")); @@ -344,60 +440,6 @@ video_mode_menu() } -static video_mode * -find_video_mode(int32 width, int32 height, int32 depth) -{ - video_mode *mode = NULL; - while ((mode = (video_mode *)list_get_next_item(&sModeList, mode)) != NULL) { - if (mode->width == width - && mode->height == height - && mode->bits_per_pixel == depth) { - return mode; - } - } - - return NULL; -} - - -static void -get_mode_from_settings(void) -{ - if (sSettingsLoaded) - return; - - void *handle = load_driver_settings("vesa"); - if (handle == NULL) - return; - - const driver_settings *settings = get_driver_settings(handle); - if (settings == NULL) - goto out; - - sSettingsLoaded = true; - - for (int32 i = 0; i < settings->parameter_count; i++) { - driver_parameter ¶meter = settings->parameters[i]; - - if (!strcmp(parameter.name, "mode") && parameter.value_count > 2) { - // parameter found, now get its values - int32 width = strtol(parameter.values[0], NULL, 0); - int32 height = strtol(parameter.values[1], NULL, 0); - int32 depth = strtol(parameter.values[2], NULL, 0); - - // search mode that fits - - video_mode *mode = find_video_mode(width, height, depth); - if (mode != NULL) - sMode = mode; - } - } - -out: - unload_driver_settings(handle); -} - - static void set_vga_mode(void) { diff --git a/src/system/kernel/util/list.c b/src/system/kernel/util/list.c index bef4879441..36ef598df1 100644 --- a/src/system/kernel/util/list.c +++ b/src/system/kernel/util/list.c @@ -1,7 +1,7 @@ -/* -** Copyright 2003-2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved. -** Distributed under the terms of the OpenBeOS License. -*/ +/* + * Copyright 2003-2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ #include @@ -156,6 +156,33 @@ list_remove_item(struct list *list, void *item) } +/** Inserts an item before another item in the list. + * If you pass NULL as \a before item, the item is added at the end of + * the list. + */ + +void +list_insert_item_before(struct list *list, void *before, void *item) +{ + list_link *beforeLink; + list_link *link; + + if (before == NULL) { + list_add_item(list, item); + return; + } + + beforeLink = GET_LINK(list, before); + link = GET_LINK(list, item); + + link->prev = beforeLink->prev; + link->next = beforeLink; + + beforeLink->prev->next = link; + beforeLink->prev = link; +} + + /** Removes the first item in the list and returns it. * Returns NULL if the list is empty. */