From patchwork Tue Sep 20 04:28:00 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Programmingkid X-Patchwork-Id: 9341013 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id E1E6B601C2 for ; Tue, 20 Sep 2016 04:28:46 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D063829BA7 for ; Tue, 20 Sep 2016 04:28:46 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C299729BBA; Tue, 20 Sep 2016 04:28:46 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 1E54529BA7 for ; Tue, 20 Sep 2016 04:28:45 +0000 (UTC) Received: from localhost ([::1]:60010 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bmCfk-00053p-EY for patchwork-qemu-devel@patchwork.kernel.org; Tue, 20 Sep 2016 00:28:44 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:58887) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bmCfL-00050j-85 for qemu-devel@nongnu.org; Tue, 20 Sep 2016 00:28:23 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bmCfI-0000sp-Rh for qemu-devel@nongnu.org; Tue, 20 Sep 2016 00:28:19 -0400 Received: from mail-io0-x241.google.com ([2607:f8b0:4001:c06::241]:33975) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bmCfB-0000ok-5F; Tue, 20 Sep 2016 00:28:09 -0400 Received: by mail-io0-x241.google.com with SMTP id y139so526182ioy.1; Mon, 19 Sep 2016 21:28:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:to:message-id:cc:subject:from:date; bh=+H9qPNqJZXeUfXxK+tm7b7kYCU+iqsiMv8KJqvdqzWE=; b=KpNmhfBSryllmmLaU7cq1cjOgIriPzhaNGjVt2tr6OnbQM2ermLA5Ywj1JaR+OollJ pJdZSqorD0l+5ybwyESo3lbQsEvd6vRMoiOQhMPcaE1SKvDkS5AmU0ediL7g+E9batwK +2FUhCHZrsRjxlE9x0PT1Bp9dmYdb4td5JGsKTwUVNTuowKGOp6PybW4x8d2duGc6C9E nw3I5vSIIseIxRPJE3uTRJbsFWIkmS6QDB8So9OaLrgbj+5tXkGRsCxLdqD0lKni3ebs LV6CcdYUwOaGWYXfuNGD62ZvbMqtQwIpl2EDZa9QqrvOlwR6YqHSfk7CT0aXtnfKPNds iUyQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:to:message-id:cc:subject:from:date; bh=+H9qPNqJZXeUfXxK+tm7b7kYCU+iqsiMv8KJqvdqzWE=; b=QSdnP9tv19AwIW6FgsTYR9Bb9HolIOyrGor3yRqCluHOpZTfCG1cJ3JBht7Lutt1EH GNFvgvVTVae51icv4VfumeJMA91Y7zIe7HbaAwz0CdZ72JOcONBSKybgUoFJ0kbpWcD9 nT4K3Ttey6Gji7hrcHD28QE1O6MNssC73M7P9TfJS2Wh97fanxo4I/ZAv2nDDlOJ8Sfc MhdMcw2nHwtlgV2el6UhhKhmXxG0sLNL+K6j3HXgTzm9HQM8WIqgmUXxSduLj3y0RAmT SlaRb7BT4Gd9LgjR2E8drTzjM9g+3IpOQqtzDhuoVfWfzrsAkL+I7CHaIZ6nAdfzoHdb X9Hw== X-Gm-Message-State: AE9vXwPi9il7V91GtwfjZi8F9LC0c6+mskSVuiNz2uh9bXQhtRC1V8OJf710ysS6VeleNg== X-Received: by 10.107.35.209 with SMTP id j200mr19187486ioj.26.1474345688440; Mon, 19 Sep 2016 21:28:08 -0700 (PDT) Received: from [192.168.0.9] (d199-74-164-53.col.wideopenwest.com. [74.199.53.164]) by smtp.gmail.com with ESMTPSA id 140sm9484903itl.4.2016.09.19.21.28.06 (version=TLS1 cipher=AES128-SHA bits=128/128); Mon, 19 Sep 2016 21:28:07 -0700 (PDT) Mime-Version: 1.0 (Apple Message framework v753.1) To: Benjamin Herrenschmidt Message-Id: From: G 3 Date: Tue, 20 Sep 2016 00:28:00 -0400 X-Mailer: Apple Mail (2.753.1) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2607:f8b0:4001:c06::241 X-Content-Filtered-By: Mailman/MimeDel 2.1.21 Subject: [Qemu-devel] [PATCH v2] add resolutions via command-line X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: "list@suse.de:PowerPC list:PowerPC" , qemu-devel qemu-devel Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP 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 --- 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(-) + 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); 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; +} +