From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:53931) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bls0e-0007lY-SU for qemu-devel@nongnu.org; Mon, 19 Sep 2016 02:24:58 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bls0c-000647-9c for qemu-devel@nongnu.org; Mon, 19 Sep 2016 02:24:55 -0400 Message-ID: <1474266273.2857.11.camel@kernel.crashing.org> From: Benjamin Herrenschmidt Date: Mon, 19 Sep 2016 16:24:33 +1000 In-Reply-To: <5766C91B-319D-46CD-9020-19EB5299DF99@gmail.com> References: <5766C91B-319D-46CD-9020-19EB5299DF99@gmail.com> Content-Type: text/plain; charset="UTF-8" Mime-Version: 1.0 Content-Transfer-Encoding: quoted-printable Subject: Re: [Qemu-devel] [PATCH] Add resolutions via the command-line List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: G 3 Cc: qemu-devel qemu-devel , "list@suse.de:PowerPC list:PowerPC" On Sat, 2016-09-17 at 23:31 -0400, G 3 wrote: > Add the ability to add resolutions from the command-line. This > patch=C2=A0=C2=A0 > works by > looking for a property called 'resolutions' in the options node of=C2=A0= =C2=A0 > OpenBIOS. > If it is found all the resolutions are parsed and loaded. >=20 > Example command-line: You must not use the C library in the ndrv (malloc, atoi, ...) Stick to what's in DriverServicesLib and NameRegistryLib. > -prom-env > resolutions=3D512x342,640x480,800x600,1024x600,1200x700,1440x900 >=20 > Signed-off-by: John Arbuckle > --- > =C2=A0 QemuVGADriver/src/QemuVga.c | 227 > ++++++++++++++++++++++++++++++++++=C2=A0 > +++++++++- > =C2=A0 1 file changed, 225 insertions(+), 2 deletions(-) >=20 > diff --git a/QemuVGADriver/src/QemuVga.c > b/QemuVGADriver/src/QemuVga.c > index 4584242..d74fa41 100644 > --- a/QemuVGADriver/src/QemuVga.c > +++ b/QemuVGADriver/src/QemuVga.c > @@ -3,6 +3,7 @@ > =C2=A0 #include "DriverQDCalls.h" > =C2=A0 #include "QemuVga.h" > =C2=A0 #include > +#include >=20 > =C2=A0 /* List of supported modes */ > =C2=A0 struct vMode { > @@ -18,7 +19,21 @@ static struct vMode vModes[] =3D=C2=A0=C2=A0{ > =C2=A0=C2=A0 { 1600, 1200 }, > =C2=A0=C2=A0 { 1920, 1080 }, > =C2=A0=C2=A0 { 1920, 1200 }, > - { 0,0 } > +=09 > + /* The rest are place holders */ > + { 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 }, > =C2=A0 }; >=20 > =C2=A0 static void VgaWriteB(UInt16 port, UInt8 val) > @@ -147,11 +162,219 @@ static InterruptMemberNumber=C2=A0=C2=A0 > PCIInterruptHandler(InterruptSetMember ISTmember, > =C2=A0 } > =C2=A0 #endif >=20 > +/* > + * Get the resolution set at the specified index. > + * The string returned needs to be freed when no longer used. > + */ > +static char *get_set(const char *resolution_set_str, int set_number) > +{ > + const int max_buf_size =3D 100; > + char c, *buffer; > + int index, comma_count; > + > + buffer =3D (char *) malloc(max_buf_size); > + comma_count =3D 0; > + index =3D 0; > + set_number++; /* Makes things easier to understand */ > + > + c =3D *(resolution_set_str++); > + while (c !=3D '\0') { > + buffer[index++] =3D c; > + c =3D *(resolution_set_str++); > + if (c =3D=3D ',') { > + comma_count++; > + if (comma_count =3D=3D set_number || index >=3D > max_buf_size) { > + buffer[index] =3D '\0'; > + return buffer; > + } > + =09 > + else { > + /* reset the buffer */ > + index =3D 0; > + c =3D *(resolution_set_str++); > + } > + } > + } > +=09 > + buffer[index] =3D '\0'; > + > + return buffer; > +} > + > +/* > + * Get the number of resolution sets > + */ > + > +static int get_set_count(const char *resolution_sets_str) > +{ > + char c; > + int count; > +=09 > + /* Count the number of commas */ > + count =3D 0; > + c =3D *(resolution_sets_str++); > + while (c !=3D '\0') { > + if (c =3D=3D ',') { > + count++; > + } > + c =3D *(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 =3D 25; > + char buffer[max_buf_size]; > + c =3D *(resolution_str++); > + index =3D 0; > + while (c !=3D 'x' && index < max_buf_size) { > + buffer[index++] =3D c; > + c =3D *(resolution_str++); > + } > +=09 > + /* Terminate string */ > + buffer[index] =3D '\0'; > +=09 > + 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 =3D 25; > + char buffer[max_buf_size]; > +=09 > + /* skip to character after x */ > + while (*resolution_str !=3D 'x') { > + resolution_str++; > + } > + resolution_str++; > +=09 > + /* Add digits of the height to the buffer */ > + index =3D 0; > + c =3D *(resolution_str++); > + while (c !=3D '\0') { > + buffer[index++] =3D c; > + c =3D *(resolution_str++); > + if(index >=3D max_buf_size) { > + break; > + } > + } > +=09 > + /* Terminate string */ > + buffer[index] =3D '\0'; > +=09 > + return atoi(buffer); > +} > + > +/* > + * Looks in the /chosen node for the value of the resolutions > property > + */ > +static int add_user_resolutions(void) > +{=09 > + RegEntryID *entry_id; > + OSErr err; > + Boolean is_done; > + void *value; > + RegPropertyValueSize property_size; > + int index, res_set_count; > + char *set_str; > + =09 > + #define PROPERTY_NAME "resolutions" > + #define NODE_PATH "Devices:device-tree:options" > + > + /* init the entry variable */ > + err =3D RegistryEntryIDInit(entry_id); > + if (err !=3D noErr) { > + lprintf("Error: Failed to init entry variable! > (%d)\n", err); > + return err; > + } > + is_done =3D false; > + > + /* Get the entry ID value */ > + err =3D RegistryCStrEntryLookup(NULL /* start root */, > NODE_PATH,=C2=A0=C2=A0 > entry_id); > + if (err !=3D noErr) { > + lprintf("RegistryCStrEntryLookup() failure (%d)\n", > err); > + return err; > + } > + > + /* Get the size of the property */ > + err =3D RegistryPropertyGetSize(entry_id, PROPERTY_NAME,=C2=A0=C2=A0 > &property_size); > + if (err !=3D noErr) { > + lprintf("Error: Failed to get property size! > (%d)\n", err); > + return err; > + } > + > + /* allocate memory to the value variable */ > + value =3D (void *) malloc(property_size); > +=09 > + /* Get the value of the property */ > + err =3D RegistryPropertyGet(entry_id, PROPERTY_NAME, value,=C2=A0=C2=A0 > &property_size); > + if (err !=3D noErr) { > + lprintf("Error: Failed to find property value > %s!\n", PROPERTY_NAME); > + return err; > + } > + > + /* Limit the number of resolutions to 20 */ > + #define sane_number_of_resolutions 20 > + res_set_count =3D get_set_count(value); > + res_set_count =3D (res_set_count > sane_number_of_resolutions > ?=C2=A0=C2=A0 > sane_number_of_resolutions : res_set_count); > + > + /* Add each resolution set */ > + for(index =3D 0; index < res_set_count; index++) { > + set_str =3D get_set(value, index); > + vModes[index].width =3D get_width(set_str); > + vModes[index].height =3D get_height(set_str); > + free(set_str); > + } > + > + free(value); > +} > + > +/* Returns the number of resolutions */ > +static int get_number_of_resolutions() > +{ > + int size_of_array, num_of_resolutions, index; > +=09 > + num_of_resolutions =3D 0; > + size_of_array =3D sizeof(vModes) / sizeof(struct vMode); > +=09 > + for(index =3D 0; index < size_of_array; index++) > + { > + /* Don't count any place holders */ > + if (vModes[index].width !=3D 0) { > + num_of_resolutions++; > + } > + } > +=09 > + return num_of_resolutions; > +} >=20 > =C2=A0 OSStatus QemuVga_Init(void) > =C2=A0 { > =C2=A0=C2=A0 UInt16 id, i; > =C2=A0=C2=A0 UInt32 mem, width, height, depth; > +=09 > + add_user_resolutions(); >=20 > =C2=A0=C2=A0 lprintf("First MMIO read...\n"); > =C2=A0=C2=A0 id =3D DispiReadW(VBE_DISPI_INDEX_ID); > @@ -183,7 +406,7 @@ OSStatus QemuVga_Init(void) > =C2=A0=C2=A0 i =3D 0; > =C2=A0=C2=A0 } > =C2=A0=C2=A0 GLOBAL.bootMode =3D i; > - GLOBAL.numModes =3D sizeof(vModes) / sizeof(struct vMode) - 1; > + GLOBAL.numModes =3D get_number_of_resolutions(); >=20 > =C2=A0=C2=A0 QemuVga_SetMode(GLOBAL.bootMode, depth, 0); >=20