From patchwork Tue Sep 20 23:46:20 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Programmingkid X-Patchwork-Id: 9342625 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 8FF3F607D0 for ; Tue, 20 Sep 2016 23:47:04 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7A3B129860 for ; Tue, 20 Sep 2016 23:47:04 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6F04129A9F; Tue, 20 Sep 2016 23:47:04 +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 C736629860 for ; Tue, 20 Sep 2016 23:47:03 +0000 (UTC) Received: from localhost ([::1]:38750 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bmUkh-0007Tk-22 for patchwork-qemu-devel@patchwork.kernel.org; Tue, 20 Sep 2016 19:47:03 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54944) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bmUkG-0007Qb-Tk for qemu-devel@nongnu.org; Tue, 20 Sep 2016 19:46:38 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bmUkF-0002gJ-Dw for qemu-devel@nongnu.org; Tue, 20 Sep 2016 19:46:36 -0400 Received: from mail-it0-x243.google.com ([2607:f8b0:4001:c0b::243]:33028) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bmUk9-0002fJ-5g; Tue, 20 Sep 2016 19:46:29 -0400 Received: by mail-it0-x243.google.com with SMTP id x192so2056891itb.0; Tue, 20 Sep 2016 16:46:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:message-id:cc:content-transfer-encoding:from:subject :date:to; bh=iAnQt9QJczIymDTNhta23wt2Y5XMjs3dj4ojuTpK6+4=; b=cgVGfGIPE8mWXDO325EzrsojnfZKqWwhNOwNC4oBo9o3edTHy7yEUUHxrdf8pNCdMw yhEzVs16ZtatsFNzl3sFtUpMORuuqZO6/HkJ/PhRnT2OC08ewtl3x97nGCq/a4K6bBmt qpMGUQ7RzXkEuv1oBJF8X4WkDwRY09Q8BmKgZCimslc/6SzuLrAV3A72zpoGxA8EkI/m UDCOUl9C4+IFlAQUxf2mgLAPsqpicEATomKo2MsgQmCOew4ZQ721KS+IHTKZmnFvuQhV r8vhaCF0/nFwlH1Y9xZ1ZYNRKf4VOGBOLQaG8xwie9Rg25edzzPlIpZY6D+YCM6+a8M1 HpqQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:message-id:cc :content-transfer-encoding:from:subject:date:to; bh=iAnQt9QJczIymDTNhta23wt2Y5XMjs3dj4ojuTpK6+4=; b=Y19W2a16Zpg+GQm3v88STaM2bpn0TELfF+2YlBJbsUmvch0TGkbCBBj3AANn9BA/ch 7clssOWLDeViFS7XPAfg7ixG8LQXWWnnPzPdC7wxugRUs8BQrGCAn9ADUp2j5pSehb2a jcQv81pFVz54qtwsZ4oObyjQ90TjUjLrZwzT8Dy0a6TRKW48vietAMXTZphWRKZvudG7 qaL0dd+Fj+Qv/HWs2tLw7m89WbWXk820Yzu7+RZTmXPeUXQ2ciiiL4ev4qtFhpyGc9Z8 TLg5rqVdchg29yEHjbcdU+pnxM1HY7eso0WGITEz5xle0jiikJRKVOEw3Z3ChZqA40xA z2eA== X-Gm-Message-State: AE9vXwOFcfRzRoEdwLEnDcHNjcBcUXmq+KApN70xho8IkrLardMzgI3ioOB6L61A6t1GtQ== X-Received: by 10.36.3.76 with SMTP id e73mr681442ite.42.1474415187316; Tue, 20 Sep 2016 16:46:27 -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 d204sm8698870ioe.27.2016.09.20.16.46.26 (version=TLS1 cipher=AES128-SHA bits=128/128); Tue, 20 Sep 2016 16:46:26 -0700 (PDT) Mime-Version: 1.0 (Apple Message framework v753.1) Message-Id: <2B6E5181-E2CE-4A41-9387-85729866A4CE@gmail.com> From: G 3 Date: Tue, 20 Sep 2016 19:46:20 -0400 To: Benjamin Herrenschmidt 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:c0b::243 Subject: [Qemu-devel] [PATCH v3] Add resolutions via the 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 --- v3 Changed implementation of atoi(). Removed strlen() implementation. Removed pow() implementation. Changed entry_id from pointer to automatic variable. v2 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 | 258 ++++++++++++++++++++++++++++++++++ +++++++++- 1 file changed, 256 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 +437,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..9dbf082 100644 --- a/QemuVGADriver/src/QemuVga.c +++ b/QemuVGADriver/src/QemuVga.c @@ -18,9 +18,25 @@ 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 }, }; +/* The number of width-height pairs in the above vModes structure */ +#define AVAILABLE_SLOTS 20 + + static void VgaWriteB(UInt16 port, UInt8 val) { UInt8 *ptr; @@ -148,11 +164,249 @@ static InterruptMemberNumber PCIInterruptHandler(InterruptSetMember ISTmember, #endif +/* Returns the number of resolutions in the vModes array */ +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; +} + + +/* convert ascii string to number */ +static int atoi(const char *str) +{ + int result = 0; + while (*str) { + result = result * 10 + *str - '0'; + str++; + } + return result; +} + + +/* An interesting way of emulating memory allocation. */ +static char *malloc(size_t 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 */ + 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; +} +