Thread (9 messages) 9 messages, 3 authors, 2006-07-18
STALE7376d

[PATCH 2.6.17-1] fbmon: add generic ddc read functionality

From: Dennis Munsie <hidden>
Date: 2006-06-21 19:54:15

hello,

another day, another patch... this one adds generic ddc/edid read  
functionality to fbmon.c.

I'm not convinced that this is the final version of this patch -- it  
works for me, but I would like to see it get some heavier testing.   
It's based on the radeon code, but that code twiddled some of the  
registers directly, where this patch uses the existing setsda,  
getsda, setscl, and getscl functions to do it's dirty work.  One  
possible side effect is that the original code could set both sda and  
scl at the same time, where this code can only set one after the  
other.  I don't know if this will be a factor or not.

Another minor issue is that the stubbed out function still requires  
the i2c.h file to be included since I use struct i2c_adapter as the  
parameter.  I thought of a few possible ways around this, but I left  
it the way it is right now because I figured that nothing was to be  
gained by not having that struct... if anyone feels otherwise, please  
let me know.

I'll put together a patch for the radeon driver today so that it will  
be easier to test.  I haven't worked out everything in the intelfb  
driver yet to post up a patch.

dennis

---

From: Dennis Munsie <redacted>

Adds functionality to read the EDID information over the DDC bus in a
generic way.  This code is based on the DDC implementation in the radeon
driver.

Signed-off-by: Dennis Munsie <redacted>

---

drivers/video/fbmon.c |  110 +++++++++++++++++++++++++++++++++++++++++ 
+++++++++
include/linux/fb.h    |    2
2 files changed, 112 insertions(+)

diff -Naurp -X linux-2.6.17.1-patched/Documentation/dontdiff  
linux-2.6.17.1-patched/drivers/video/fbmon.c linux/drivers/video/fbmon.c
--- linux-2.6.17.1-patched/drivers/video/fbmon.c	2006-06-21  
12:03:41.000000000 -0500
+++ linux/drivers/video/fbmon.c	2006-06-21 14:45:43.000000000 -0500
@@ -1314,6 +1314,116 @@ const unsigned char *fb_firmware_edid(st
#endif
EXPORT_SYMBOL(fb_firmware_edid);
+/*
+ * DDC/EDID read support.
+ *
+ * You must pass in an i2c_adapter that uses the bit algorithm, or
+ * there will be a panic.
+ */
+#if defined(CONFIG_I2C) && defined(CONFIG_I2C_ALGOBIT)
+#include <linux/i2c-algo-bit.h>
+#include <linux/delay.h>
+
+#define DDC_ADDR	0x50
+
+static unsigned char *fb_do_probe_ddc_edid(struct i2c_adapter *adapter)
+{
+	unsigned char start = 0x0;
+	struct i2c_msg msgs[] = {
+		{
+			.addr	= DDC_ADDR,
+			.len	= 1,
+			.buf	= &start,
+		}, {
+			.addr	= DDC_ADDR,
+			.flags	= I2C_M_RD,
+			.len	= EDID_LENGTH,
+		}
+	};
+	unsigned char *buf;
+
+	buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
+	if (!buf) {
+		printk(KERN_ERR "fbmon: unable to allocate memory for EDID block. 
\n");
+		return NULL;		
+	}
+	msgs[1].buf = buf;
+
+	if (i2c_transfer(adapter, msgs, 2) == 2)
+		return buf;
+
+	printk(KERN_WARNING "fbmon: unable to read EDID block.\n");
+	kfree(buf);
+	return NULL;
+}
+
+unsigned char *fb_ddc_read(struct i2c_adapter *adapter)
+{
+	struct i2c_algo_bit_data *algo_data = adapter->algo_data;
+	unsigned char *edid = NULL;
+	int i, j;
+	
+	algo_data->setscl(algo_data->data, 1);
+	algo_data->setscl(algo_data->data, 0);
+
+	for (i = 0; i < 3; i++) {
+		/* For some old monitors we need the
+		 * following process to initialize/stop DDC
+		 */
+		algo_data->setsda(algo_data->data, 0);
+		msleep(13);
+
+		algo_data->setscl(algo_data->data, 1);
+		for (j = 0; j < 5; j++) {
+			msleep(10);
+			if (algo_data->getscl(algo_data->data))
+				break;
+		}
+		if (j == 5)
+			continue;
+
+		algo_data->setsda(algo_data->data, 0);
+		msleep(15);
+		algo_data->setscl(algo_data->data, 0);
+		msleep(15);
+		algo_data->setsda(algo_data->data, 1);
+		msleep(15);
+
+		/* Do the real work */
+		edid = fb_do_probe_ddc_edid(adapter);
+		algo_data->setsda(algo_data->data, 0);
+		algo_data->setscl(algo_data->data, 0);
+		msleep(15);
+
+		algo_data->setscl(algo_data->data, 1);
+		for (j = 0; j < 10; j++) {
+			msleep(10);
+			if (algo_data->getscl(algo_data->data))
+				break;
+		}
+
+		algo_data->setsda(algo_data->data, 1);
+		msleep(15);
+		algo_data->setscl(algo_data->data, 0);
+		if (edid)
+			break;
+	}
+	/* Release the DDC lines when done or the Apple Cinema HD display
+	 * will switch off
+	 */
+	algo_data->setsda(algo_data->data, 0);
+	algo_data->setscl(algo_data->data, 0);
+
+	return edid;
+}
+#else
+unsigned char *fb_ddc_read(struct i2c_adapter *adapter)
+{
+	return NULL;
+}
+#endif
+EXPORT_SYMBOL(fb_ddc_read);
+
EXPORT_SYMBOL(fb_parse_edid);
EXPORT_SYMBOL(fb_edid_to_monspecs);
EXPORT_SYMBOL(fb_get_mode);
diff -Naurp -X linux-2.6.17.1-patched/Documentation/dontdiff  
linux-2.6.17.1-patched/include/linux/fb.h linux/include/linux/fb.h
--- linux-2.6.17.1-patched/include/linux/fb.h	2006-06-21  
12:03:42.000000000 -0500
+++ linux/include/linux/fb.h	2006-06-21 14:46:06.000000000 -0500
@@ -2,6 +2,7 @@
#define _LINUX_FB_H
#include <asm/types.h>
+#include <linux/i2c.h>
/* Definitions of frame buffers						*/
@@ -924,6 +925,7 @@ extern void fb_edid_to_monspecs(unsigned
				struct fb_monspecs *specs);
extern void fb_destroy_modedb(struct fb_videomode *modedb);
extern int fb_find_mode_cvt(struct fb_videomode *mode, int margins,  
int rb);
+extern unsigned char *fb_ddc_read(struct i2c_adapter *adapter);
/* drivers/video/modedb.c */
#define VESA_MODEDB_SIZE 34


All the advantages of Linux Managed Hosting--Without the Cost and Risk!
Fully trained technicians. The highest number of Red Hat certifications in
the hosting industry. Fanatical Support. Click to learn more
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=107521&bid=248729&dat=121642
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help