diff mbox

[v5] Add resolutions via the command-line

Message ID C9D447F9-C7A9-4CDD-BE6B-B8A57A3A3016@gmail.com
State New
Headers show

Commit Message

Programmingkid Oct. 2, 2016, 10:22 p.m. UTC
Add the ability to add resolutions from the command-line. This patch  
works by
looking for a property called 'fb-modes' in the QEMU,VGA 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 <programmingkidx@gmail.com>
---
v5
Switched from using 'resolutions' to 'fb-modes' in the QEMU,VGA node  
as Mark requested.

v4
Removed all ASCII text processing code and replaced it with integer  
processing code.

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 | 107 ++++++++++++++++++++++++++++++++++ 
+++++++++-
  1 file changed, 105 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 +286,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 mbox

Patch

diff --git a/QemuVGADriver/src/QemuVga.c b/QemuVGADriver/src/QemuVga.c
index 4584242..28daa02 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,98 @@  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;
+}
+
+
+/* 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, *res_values;
+
+	#define PROPERTY_NAME "fb-modes"
+	#define NODE_PATH "Devices:device-tree:pci:QEMU,VGA"
+
+	/* 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 *) PoolAllocateResident(property_size, false);
+	if (value == NULL) {
+		lprintf("Error: Failed to allocate memory to value variable\n");
+		return -1;
+	}
+
+	/* 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;
+	}
+	
+	res_values = value;
+	res_set_count = property_size/4/2; /* divide by bytes per cell then  
by cells per set */
+	
+	/* Limit the number of resolutions to number of available slots in  
vMode */
+	res_set_count = (res_set_count > AVAILABLE_SLOTS ?  
AVAILABLE_SLOTS : res_set_count);
+
+	/* Load each resolution set */
+	for(index = 0; index < res_set_count; index++)
+	{
+		vModes[index].width = *(res_values++);
+		vModes[index].height = *(res_values++);
+	}
+	return 0;
+}
+
+