|
From: | G 3 |
Subject: | [Qemu-ppc] [PATCH v2] add resolutions via command-line |
Date: | Tue, 20 Sep 2016 00:28:00 -0400 |
Add the ability to add resolutions from the command-line. This patch works by looking for a property called 'resolutions' in the options node of OpenBIOS. If it is found all the resolutions are parsed and loaded. Example command-line: -prom-env resolutions=512x342,640x480,800x600,1024x600,1200x700,1440x900 Signed-off-by: John Arbuckle <address@hidden> --- Implemented my own malloc(), strlen(), pow(), and atoi() functions. Removed free() calls. Changed get_set_count() to get_resolution_set_count(). QemuVGADriver/src/QemuVga.c | 285 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 283 insertions(+), 2 deletions(-) diff --git a/QemuVGADriver/src/QemuVga.c b/QemuVGADriver/src/QemuVga.c index 4584242..cba65ba 100644 --- a/QemuVGADriver/src/QemuVga.c +++ b/QemuVGADriver/src/QemuVga.c @@ -18,7 +18,19 @@ static struct vMode vModes[] = { { 1600, 1200 }, { 1920, 1080 }, { 1920, 1200 }, - { 0,0 } + { 0,0 }, + { 0,0 }, + { 0,0 }, + { 0,0 }, + { 0,0 }, + { 0,0 }, + { 0,0 }, + { 0,0 }, + { 0,0 }, + { 0,0 }, + { 0,0 }, + { 0,0 }, + { 0,0 }, }; static void VgaWriteB(UInt16 port, UInt8 val) @@ -148,11 +160,280 @@ static InterruptMemberNumber PCIInterruptHandler(InterruptSetMember ISTmember, #endif +/* Returns the number of resolutions */ +static int get_number_of_resolutions() +{ + int size_of_array, num_of_resolutions, index; + + num_of_resolutions = 0; + size_of_array = sizeof(vModes) / sizeof(struct vMode); + + for(index = 0; index < size_of_array; index++) + { + if (vModes[index].width != 0) { + num_of_resolutions++; + } + } + + return num_of_resolutions; +} + + +/* strlen() implementation */ +static int strlen(const char *str) +{ + int count = 0; + + for( ; *str != '\0'; str++) { + count++; + } + + return count; +} + + +/* output = base^power */ +static int pow(int base, int power) +{ + int i, output; + output = 1; + for (i = 0; i < power; i++) { + output = output * base; + } + return output; +} + + +/* convert ascii string to number */ +static int atoi(const char *str) +{ + int result = 0, multiplier; + + multiplier = strlen(str) - 1; + for ( ; *str != '\0'; str++) { + result += (*str - '0') * pow(10, multiplier); + multiplier--; + if (multiplier < 0) /* Something might be wrong if returning here */ + return result; + } + + return result; +} + + +/* An interesting way of emulating memory allocation. */ +static char *malloc(int size) +{ + const int max_buffer_size = 2000; + static char buffer[max_buffer_size]; + static int free_mem_pointer = 0; + static Boolean first_alloc = true; + + free_mem_pointer += size; + if (free_mem_pointer >= max_buffer_size) { + return NULL; + } + + /* For getting the very beginning of the buffer */ + if (first_alloc == true) { + first_alloc = false; + return buffer; + } + + return (buffer + free_mem_pointer); +} + + +/* Get the resolution set at the specified index. */ +static char *get_resolution_set(const char *resolution_set_str, int set_number) +{ + const int max_buf_size = 100; + char c, *buffer; + int index, comma_count; + + buffer = (char *) malloc(max_buf_size); + comma_count = 0; + index = 0; + set_number++; /* Makes things easier to understand */ + + c = *(resolution_set_str++); + while (c != '\0') { + buffer[index++] = c; + c = *(resolution_set_str++); + if (c == ',') { + comma_count++; + if (comma_count == set_number || index >= max_buf_size) { + buffer[index] = '\0'; + return buffer; + } + + else { + /* reset the buffer */ + index = 0; + c = *(resolution_set_str++); + } + } + } + + buffer[index] = '\0'; + + return buffer; +} + + +/* Get the number of resolution sets - a set is a width by height pair */ +static int get_resolution_set_count(const char *resolution_sets_str) +{ + char c; + int count; + + /* Count the number of commas */ + count = 0; + c = *(resolution_sets_str++); + while (c != '\0') { + if (c == ',') { + count++; + } + c = *(resolution_sets_str++); + } + + return count + 1; +} + + +/* + * Returns the width value of a resolution set + * Example: + * input: 16000x9000 + * output: 16000 + */ +static int get_width(const char *resolution_str) +{ + int index; + char c; + const int max_buf_size = 25; + char buffer[max_buf_size]; + c = *(resolution_str++); + index = 0; + while (c != 'x' && index < max_buf_size) { + buffer[index++] = c; + c = *(resolution_str++); + } + + /* Terminate string */ + buffer[index] = '\0'; + + return atoi(buffer); +} + + +/* + * Returns the height value of a resolution set + * Example + * input: 16000x9000 + * output: 9000 + */ +static int get_height(const char *resolution_str) +{ + int index; + char c; + const int max_buf_size = 25; + char buffer[max_buf_size]; + + /* skip to character after x */ + while (*resolution_str != 'x') { + resolution_str++; + } + resolution_str++; + + /* Add digits of the height to the buffer */ + index = 0; + c = *(resolution_str++); + while (c != '\0') { + buffer[index++] = c; + c = *(resolution_str++); + if(index >= max_buf_size) { + break; + } + } + + /* Terminate string */ + buffer[index] = '\0'; + + return atoi(buffer); +} + + +/* Looks in the /options node for the value of the resolutions property */ +static int add_user_resolutions(void) +{ + RegEntryID *entry_id; + OSErr err; + OSStatus os_status = noErr; + Boolean is_done; + void *value; + RegPropertyValueSize property_size = -1; + int index, res_set_count; + char *set_str; + + #define PROPERTY_NAME "resolutions" + #define NODE_PATH "Devices:device-tree:options" + + /* init the entry variable */ + err = RegistryEntryIDInit(entry_id); + if (err != noErr) { + lprintf("Error: Failed to init entry variable! (Error: %d)\n", err); + return err; + } + is_done = false; + + /* Get the entry ID value */ + err = RegistryCStrEntryLookup(NULL /* start root */, NODE_PATH, entry_id); + if (err != noErr) { + lprintf("RegistryCStrEntryLookup() failure (Error: %d)\n", err); + return err; + } + + /* Get the size of the property */ + os_status = RegistryPropertyGetSize(entry_id, PROPERTY_NAME, &property_size); + if (os_status != noErr) { + lprintf("Error: Failed to get property size! (Error: %d)\n", os_status); + return os_status; + } + + /* allocate memory to the value variable */ + value = (void *) malloc(property_size); + + /* Get the value of the property */ + err = RegistryPropertyGet(entry_id, PROPERTY_NAME, value, &property_size); + if (err != noErr) { + lprintf("Error: Failed to find property value %s! (Error: %d)\n", PROPERTY_NAME, err); + return err; + } + + /* Limit the number of resolutions to number of available slots in vMode */ + #define available_slots 20 + res_set_count = get_resolution_set_count(value); + res_set_count = (res_set_count > available_slots ? available_slots : res_set_count); + + /* Add each resolution set */ + for(index = 0; index < res_set_count; index++) { + set_str = get_resolution_set(value, index); + vModes[index].width = get_width(set_str); + vModes[index].height = get_height(set_str); + } + + return 0; +} + + OSStatus QemuVga_Init(void) { UInt16 id, i; UInt32 mem, width, height, depth; + add_user_resolutions(); + lprintf("First MMIO read...\n"); id = DispiReadW(VBE_DISPI_INDEX_ID); mem = DispiReadW(VBE_DISPI_INDEX_VIDEO_MEMORY_64K); @@ -183,7 +464,7 @@ OSStatus QemuVga_Init(void) i = 0; } GLOBAL.bootMode = i; - GLOBAL.numModes = sizeof(vModes) / sizeof(struct vMode) - 1; + GLOBAL.numModes = get_number_of_resolutions(); QemuVga_SetMode(GLOBAL.bootMode, depth, 0); -- 2.6.0 |
[Prev in Thread] | Current Thread | [Next in Thread] |