[kernel] r16526 - in dists/sid/linux-2.6/debian: . config patches/features/all/udlfb patches/series

Martin Michlmayr tbm at alioth.debian.org
Tue Nov 2 20:21:29 UTC 2010


Author: tbm
Date: Tue Nov  2 20:21:21 2010
New Revision: 16526

Log:
Update udlfb to 2.6.36

Added:
   dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-add-dpms.patch
   dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-add-slab.patch
   dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-backup-edid-write.patch
   dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-big-endian-fix.patch
   dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-checkpatch-style.patch
   dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-coding-style.patch
   dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-enhance-edid.patch
   dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-fbdev-char.patch
   dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-fix-incorrect-fb_defio-implementation.patch
   dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-minor-cleanups.patch
   dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-module-options.patch
   dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-remove-metrics_misc.patch
   dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-revamp-reference-handling.patch
Modified:
   dists/sid/linux-2.6/debian/changelog
   dists/sid/linux-2.6/debian/config/defines
   dists/sid/linux-2.6/debian/patches/series/28

Modified: dists/sid/linux-2.6/debian/changelog
==============================================================================
--- dists/sid/linux-2.6/debian/changelog	Tue Nov  2 16:36:34 2010	(r16525)
+++ dists/sid/linux-2.6/debian/changelog	Tue Nov  2 20:21:21 2010	(r16526)
@@ -1,5 +1,6 @@
 linux-2.6 (2.6.32-28) UNRELEASED; urgency=low
 
+  [ maximilian attems ]
   * ipc: initialize structure memory to zero for shmctl.
   * drm/i915: set DIDL using the ACPI video output device _ADR method return.
   * images: Nuke modules.devname on removal. (closes: #590607)
@@ -8,6 +9,21 @@
   * drm/nouveau: fix race condition when under memory pressure.
   * [openvz] Update upstream patch to 2.6.32-dzhanibekov.
 
+  [ Martin Michlmayr ]
+  * Update udlfb to 2.6.36:
+    - udlfb: minor cleanups
+    - udlfb: fix coding style issues
+    - udlfb: fbdev character read and write support
+    - udlfb: add DPMS support
+    - udlfb: remove metrics_misc sysfs attribute
+    - udlfb: revamp reference handling to insure successful shutdown
+    - udlfb: enhance EDID and mode handling support
+    - udlfb: fix big endian rendering error
+    - udlfb: support for writing backup EDID to sysfs file
+    - udlfb: add module options for console and fb_defio
+    - udlfb: fix incorrect fb_defio implementation for multiple framebuffers
+    - udlfb: fix checkpatch and style
+
  -- maximilian attems <maks at debian.org>  Sat, 30 Oct 2010 14:14:37 +0200
 
 linux-2.6 (2.6.32-27) unstable; urgency=high

Modified: dists/sid/linux-2.6/debian/config/defines
==============================================================================
--- dists/sid/linux-2.6/debian/config/defines	Tue Nov  2 16:36:34 2010	(r16525)
+++ dists/sid/linux-2.6/debian/config/defines	Tue Nov  2 20:21:21 2010	(r16526)
@@ -75,7 +75,7 @@
 drivers/staging/rtl8192su/: 2.6.34
 drivers/staging/rtl8192u/: 2.6.34
 drivers/staging/samsung-laptop/: 2.6.35
-drivers/staging/udlfb/: 2.6.34
+drivers/staging/udlfb/: 2.6.36
 drivers/usb/serial/usb_wwan.c: 2.6.34
 drivers/usb/serial/usb-wwan.h: 2.6.34
 drivers/staging/xgifb/: 2.6.35

Added: dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-add-dpms.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-add-dpms.patch	Tue Nov  2 20:21:21 2010	(r16526)
@@ -0,0 +1,85 @@
+From: Bernie Thompson <bernie at plugable.com>
+Date: Sun, 5 Sep 2010 23:35:10 +0000 (-0700)
+Subject: staging: udlfb: add DPMS support
+X-Git-Tag: v2.6.37-rc1~60^2~3^2~680
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=9825f70f5cf465a8c31236409456d18de07fd166
+
+staging: udlfb: add DPMS support
+
+Add ability to power off monitor with standard blanking interface
+
+Used by X servers and others to manage power of dislpay
+
+Signed-off-by: Bernie Thompson <bernie at plugable.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
+---
+
+diff --git a/drivers/staging/udlfb/udlfb.c b/drivers/staging/udlfb/udlfb.c
+index a2bd5f7..0e03dd3 100644
+--- a/drivers/staging/udlfb/udlfb.c
++++ b/drivers/staging/udlfb/udlfb.c
+@@ -108,13 +108,16 @@ static char *dlfb_vidreg_unlock(char *buf)
+ 
+ /*
+  * On/Off for driving the DisplayLink framebuffer to the display
++ *  0x00 H and V sync on
++ *  0x01 H and V sync off (screen blank but powered)
++ *  0x07 DPMS powerdown (requires modeset to come back)
+  */
+ static char *dlfb_enable_hvsync(char *buf, bool enable)
+ {
+ 	if (enable)
+ 		return dlfb_set_register(buf, 0x1F, 0x00);
+ 	else
+-		return dlfb_set_register(buf, 0x1F, 0x01);
++		return dlfb_set_register(buf, 0x1F, 0x07);
+ }
+ 
+ static char *dlfb_set_color_depth(char *buf, u8 selection)
+@@ -936,30 +939,31 @@ static int dlfb_ops_set_par(struct fb_info *info)
+ 	return dlfb_set_video_mode(dev, &info->var);
+ }
+ 
++/*
++ * In order to come back from full DPMS off, we need to set the mode again
++ */
+ static int dlfb_ops_blank(int blank_mode, struct fb_info *info)
+ {
+ 	struct dlfb_data *dev = info->par;
+-	char *bufptr;
+-	struct urb *urb;
+ 
+-	urb = dlfb_get_urb(dev);
+-	if (!urb)
+-		return 0;
+-	bufptr = (char *) urb->transfer_buffer;
++	if (blank_mode != FB_BLANK_UNBLANK) {
++		char *bufptr;
++		struct urb *urb;
+ 
+-	/* overloading usb_active.  UNBLANK can conflict with teardown */
++		urb = dlfb_get_urb(dev);
++		if (!urb)
++			return 0;
+ 
+-	bufptr = dlfb_vidreg_lock(bufptr);
+-	if (blank_mode != FB_BLANK_UNBLANK) {
+-		atomic_set(&dev->usb_active, 0);
++		bufptr = (char *) urb->transfer_buffer;
++		bufptr = dlfb_vidreg_lock(bufptr);
+ 		bufptr = dlfb_enable_hvsync(bufptr, false);
++		bufptr = dlfb_vidreg_unlock(bufptr);
++
++		dlfb_submit_urb(dev, urb, bufptr -
++				(char *) urb->transfer_buffer);
+ 	} else {
+-		atomic_set(&dev->usb_active, 1);
+-		bufptr = dlfb_enable_hvsync(bufptr, true);
++		dlfb_set_video_mode(dev, &info->var);
+ 	}
+-	bufptr = dlfb_vidreg_unlock(bufptr);
+-
+-	dlfb_submit_urb(dev, urb, bufptr - (char *) urb->transfer_buffer);
+ 
+ 	return 0;
+ }

Added: dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-add-slab.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-add-slab.patch	Tue Nov  2 20:21:21 2010	(r16526)
@@ -0,0 +1,109 @@
+From: Tejun Heo <tj at kernel.org>
+Date: Wed, 24 Mar 2010 08:04:11 +0000 (+0900)
+Subject: include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit... 
+X-Git-Tag: v2.6.34-rc4~71^2~5
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=5a0e3ad6af8660be21ca98a971cd00f331318c05
+
+include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
+
+percpu.h is included by sched.h and module.h and thus ends up being
+included when building most .c files.  percpu.h includes slab.h which
+in turn includes gfp.h making everything defined by the two files
+universally available and complicating inclusion dependencies.
+
+percpu.h -> slab.h dependency is about to be removed.  Prepare for
+this change by updating users of gfp and slab facilities include those
+headers directly instead of assuming availability.  As this conversion
+needs to touch large number of source files, the following script is
+used as the basis of conversion.
+
+  http://userweb.kernel.org/~tj/misc/slabh-sweep.py
+
+The script does the followings.
+
+* Scan files for gfp and slab usages and update includes such that
+  only the necessary includes are there.  ie. if only gfp is used,
+  gfp.h, if slab is used, slab.h.
+
+* When the script inserts a new include, it looks at the include
+  blocks and try to put the new include such that its order conforms
+  to its surrounding.  It's put in the include block which contains
+  core kernel includes, in the same order that the rest are ordered -
+  alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
+  doesn't seem to be any matching order.
+
+* If the script can't find a place to put a new include (mostly
+  because the file doesn't have fitting include block), it prints out
+  an error message indicating which .h file needs to be added to the
+  file.
+
+The conversion was done in the following steps.
+
+1. The initial automatic conversion of all .c files updated slightly
+   over 4000 files, deleting around 700 includes and adding ~480 gfp.h
+   and ~3000 slab.h inclusions.  The script emitted errors for ~400
+   files.
+
+2. Each error was manually checked.  Some didn't need the inclusion,
+   some needed manual addition while adding it to implementation .h or
+   embedding .c file was more appropriate for others.  This step added
+   inclusions to around 150 files.
+
+3. The script was run again and the output was compared to the edits
+   from #2 to make sure no file was left behind.
+
+4. Several build tests were done and a couple of problems were fixed.
+   e.g. lib/decompress_*.c used malloc/free() wrappers around slab
+   APIs requiring slab.h to be added manually.
+
+5. The script was run on all .h files but without automatically
+   editing them as sprinkling gfp.h and slab.h inclusions around .h
+   files could easily lead to inclusion dependency hell.  Most gfp.h
+   inclusion directives were ignored as stuff from gfp.h was usually
+   wildly available and often used in preprocessor macros.  Each
+   slab.h inclusion directive was examined and added manually as
+   necessary.
+
+6. percpu.h was updated not to include slab.h.
+
+7. Build test were done on the following configurations and failures
+   were fixed.  CONFIG_GCOV_KERNEL was turned off for all tests (as my
+   distributed build env didn't work with gcov compiles) and a few
+   more options had to be turned off depending on archs to make things
+   build (like ipr on powerpc/64 which failed due to missing writeq).
+
+   * x86 and x86_64 UP and SMP allmodconfig and a custom test config.
+   * powerpc and powerpc64 SMP allmodconfig
+   * sparc and sparc64 SMP allmodconfig
+   * ia64 SMP allmodconfig
+   * s390 SMP allmodconfig
+   * alpha SMP allmodconfig
+   * um on x86_64 SMP allmodconfig
+
+8. percpu.h modifications were reverted so that it could be applied as
+   a separate patch and serve as bisection point.
+
+Given the fact that I had only a couple of failures from tests on step
+6, I'm fairly confident about the coverage of this conversion patch.
+If there is a breakage, it's likely to be something in one of the arch
+headers which should be easily discoverable easily on most builds of
+the specific arch.
+
+Signed-off-by: Tejun Heo <tj at kernel.org>
+Guess-its-ok-by: Christoph Lameter <cl at linux-foundation.org>
+Cc: Ingo Molnar <mingo at redhat.com>
+Cc: Lee Schermerhorn <Lee.Schermerhorn at hp.com>
+---
+
+diff --git a/drivers/staging/udlfb/udlfb.c b/drivers/staging/udlfb/udlfb.c
+index 8f6223c..a78ade0 100644
+--- a/drivers/staging/udlfb/udlfb.c
++++ b/drivers/staging/udlfb/udlfb.c
+@@ -24,6 +24,7 @@
+ #include <linux/mm.h>
+ #include <linux/fb.h>
+ #include <linux/vmalloc.h>
++#include <linux/slab.h>
+ 
+ #include "udlfb.h"
+ 

Added: dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-backup-edid-write.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-backup-edid-write.patch	Tue Nov  2 20:21:21 2010	(r16526)
@@ -0,0 +1,66 @@
+From: Bernie Thompson <bernie at plugable.com>
+Date: Sun, 5 Sep 2010 23:35:31 +0000 (-0700)
+Subject: staging: udlfb: support for writing backup EDID to sysfs file
+X-Git-Tag: v2.6.37-rc1~60^2~3^2~675
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=8ef8cc4fca4a92e77c0b5aa7a852a6c3d2fba844
+
+staging: udlfb: support for writing backup EDID to sysfs file
+
+Support writing default/backup edid via /sys/class/graphics/fb?/edid
+
+Writing a backup edid blob to the 'edid' file will cause udlfb to
+attempt to re-read the edid from hardware.
+If we still don't have a good edid, it will use the backup edid instead.
+The intent is to 1) enable user-supplied edid
+2) enable udev rules to backup the last known good edid
+for a device, and then provide that edid as a backup for all future starts
+
+Signed-off-by: Bernie Thompson <bernie at plugable.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
+---
+
+diff --git a/drivers/staging/udlfb/udlfb.c b/drivers/staging/udlfb/udlfb.c
+index bcb4a1e9..b13869b 100644
+--- a/drivers/staging/udlfb/udlfb.c
++++ b/drivers/staging/udlfb/udlfb.c
+@@ -1304,6 +1304,27 @@
+ 	return count;
+ }
+ 
++static ssize_t edid_store(struct kobject *kobj, struct bin_attribute *a,
++			char *src, loff_t src_off, size_t src_size) {
++	struct device *fbdev = container_of(kobj, struct device, kobj);
++	struct fb_info *fb_info = dev_get_drvdata(fbdev);
++	struct dlfb_data *dev = fb_info->par;
++
++	/* We only support write of entire EDID at once, no offset*/
++	if ((src_size < MIN_EDID_SIZE) ||
++	    (src_size > MAX_EDID_SIZE) ||
++	    (src_off != 0))
++		return 0;
++
++	dlfb_setup_modes(dev, fb_info, src, src_size);
++
++	if (dev->edid && (memcmp(src, dev->edid, src_size) == 0)) {
++		dl_info("sysfs written EDID is new default\n");
++		dlfb_ops_set_par(fb_info);
++		return src_size;
++	} else
++		return 0;
++}
+ 
+ static ssize_t metrics_reset_store(struct device *fbdev,
+ 			   struct device_attribute *attr,
+@@ -1346,9 +1367,10 @@
+ 
+ static struct bin_attribute edid_attr = {
+ 	.attr.name = "edid",
+-	.attr.mode = 0444,
+-	.size = 128,
++	.attr.mode = 0666,
++	.size = MAX_EDID_SIZE,
+ 	.read = edid_show,
++	.write = edid_store
+ };
+ 
+ static struct device_attribute fb_device_attrs[] = {

Added: dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-big-endian-fix.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-big-endian-fix.patch	Tue Nov  2 20:21:21 2010	(r16526)
@@ -0,0 +1,39 @@
+From: Bernie Thompson <bernie at plugable.com>
+Date: Sun, 5 Sep 2010 23:35:27 +0000 (-0700)
+Subject: staging: udlfb: fix big endian rendering error
+X-Git-Tag: v2.6.37-rc1~60^2~3^2~676
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=1572f91cffd7c0d64ab4e0cec71e1d2d1a3349e1
+
+staging: udlfb: fix big endian rendering error
+
+Fix big endian rendering bug (affects PowerPC)
+
+Thanks to Christian Melki at Ericsson for finding and suggesting patch.
+
+Signed-off-by: Bernie Thompson <bernie at plugable.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
+---
+
+diff --git a/drivers/staging/udlfb/udlfb.c b/drivers/staging/udlfb/udlfb.c
+index 6977b71..bcb4a1e9 100644
+--- a/drivers/staging/udlfb/udlfb.c
++++ b/drivers/staging/udlfb/udlfb.c
+@@ -414,15 +414,14 @@ static void dlfb_compress_hline(
+ 		uint8_t *cmd_pixels_count_byte = 0;
+ 		const uint16_t *raw_pixel_start = 0;
+ 		const uint16_t *cmd_pixel_start, *cmd_pixel_end = 0;
+-		const uint32_t be_dev_addr = cpu_to_be32(dev_addr);
+ 
+ 		prefetchw((void *) cmd); /* pull in one cache line at least */
+ 
+ 		*cmd++ = 0xAF;
+ 		*cmd++ = 0x6B;
+-		*cmd++ = (uint8_t) ((be_dev_addr >> 8) & 0xFF);
+-		*cmd++ = (uint8_t) ((be_dev_addr >> 16) & 0xFF);
+-		*cmd++ = (uint8_t) ((be_dev_addr >> 24) & 0xFF);
++		*cmd++ = (uint8_t) ((dev_addr >> 16) & 0xFF);
++		*cmd++ = (uint8_t) ((dev_addr >> 8) & 0xFF);
++		*cmd++ = (uint8_t) ((dev_addr) & 0xFF);
+ 
+ 		cmd_pixels_count_byte = cmd++; /*  we'll know this later */
+ 		cmd_pixel_start = pixel;

Added: dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-checkpatch-style.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-checkpatch-style.patch	Tue Nov  2 20:21:21 2010	(r16526)
@@ -0,0 +1,94 @@
+From: Bernie Thompson <bernie at plugable.com>
+Date: Mon, 6 Sep 2010 01:29:56 +0000 (-0700)
+Subject: staging: udlfb: fix checkpatch and style
+X-Git-Tag: v2.6.37-rc1~60^2~3^2~664
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=2685cffa9e799278cdbfa5f524dd9e548be6598d
+
+staging: udlfb: fix checkpatch and style
+
+Fix warnings detected by tools
+
+Signed-off-by: Bernie Thompson <bernie at plugable.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
+---
+
+diff --git a/drivers/staging/udlfb/udlfb.c b/drivers/staging/udlfb/udlfb.c
+index 082468a..5969e84 100644
+--- a/drivers/staging/udlfb/udlfb.c
++++ b/drivers/staging/udlfb/udlfb.c
+@@ -27,7 +27,6 @@
+ #include <linux/slab.h>
+ #include <linux/delay.h>
+ 
+-
+ #include "udlfb.h"
+ 
+ static struct fb_fix_screeninfo dlfb_fix = {
+@@ -256,6 +255,7 @@ static int dlfb_set_video_mode(struct dlfb_data *dev,
+ 	urb = dlfb_get_urb(dev);
+ 	if (!urb)
+ 		return -ENOMEM;
++
+ 	buf = (char *) urb->transfer_buffer;
+ 
+ 	/*
+@@ -288,13 +288,14 @@ static int dlfb_ops_mmap(struct fb_info *info, struct vm_area_struct *vma)
+ 	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+ 	unsigned long page, pos;
+ 
+-	dl_notice("MMAP: %lu %u\n", offset + size, info->fix.smem_len);
+-
+ 	if (offset + size > info->fix.smem_len)
+ 		return -EINVAL;
+ 
+ 	pos = (unsigned long)info->fix.smem_start + offset;
+ 
++	dl_notice("mmap() framebuffer addr:%lu size:%lu\n",
++		  pos, size);
++
+ 	while (size > 0) {
+ 		page = vmalloc_to_pfn((void *)pos);
+ 		if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
+@@ -310,7 +311,6 @@ static int dlfb_ops_mmap(struct fb_info *info, struct vm_area_struct *vma)
+ 
+ 	vma->vm_flags |= VM_RESERVED;	/* avoid to swap out this VMA */
+ 	return 0;
+-
+ }
+ 
+ /*
+@@ -372,13 +372,13 @@ static int dlfb_trim_hline(const u8 *bback, const u8 **bfront, int *width_bytes)
+  * A single command can transmit a maximum of 256 pixels,
+  * regardless of the compression ratio (protocol design limit).
+  * To the hardware, 0 for a size byte means 256
+- * 
++ *
+  * Rather than 256 pixel commands which are either rl or raw encoded,
+  * the rlx command simply assumes alternating raw and rl spans within one cmd.
+  * This has a slightly larger header overhead, but produces more even results.
+  * It also processes all data (read and write) in a single pass.
+  * Performance benchmarks of common cases show it having just slightly better
+- * compression than 256 pixel raw -or- rle commands, with similar CPU consumpion.
++ * compression than 256 pixel raw or rle commands, with similar CPU consumpion.
+  * But for very rl friendly data, will compress not quite as well.
+  */
+ static void dlfb_compress_hline(
+@@ -570,7 +570,7 @@ int dlfb_handle_damage(struct dlfb_data *dev, int x, int y,
+ 
+ 		if (dlfb_render_hline(dev, &urb,
+ 				      (char *) dev->info->fix.smem_start,
+-				  &cmd, byte_offset, width * BPP,
++				      &cmd, byte_offset, width * BPP,
+ 				      &bytes_identical, &bytes_sent))
+ 			goto error;
+ 	}
+@@ -1532,8 +1532,8 @@ static int dlfb_usb_probe(struct usb_interface *interface,
+ 	struct usb_device *usbdev;
+ 	struct dlfb_data *dev = 0;
+ 	struct fb_info *info = 0;
+-	int i;
+ 	int retval = -ENOMEM;
++	int i;
+ 
+ 	/* usb initialization */
+ 

Added: dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-coding-style.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-coding-style.patch	Tue Nov  2 20:21:21 2010	(r16526)
@@ -0,0 +1,38 @@
+From: Soeren Moeller <soerenmoeller2001 at gmail.com>
+Date: Fri, 14 May 2010 19:03:00 +0000 (+0000)
+Subject: Staging: udlfb: fix coding style issues
+X-Git-Tag: v2.6.35-rc1~441^2^2~27
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=b5a2104c98cb603f7053e4b0309fb88f15d6be86
+
+Staging: udlfb: fix coding style issues
+
+This is a patch to the file udlfb.c that fixes a missing KERN_INFO and
+removes one whitespace before a newline.
+
+Signed-off-by: Soeren Moeller <soerenmoeller2001 at gmail.com>
+Cc: Bernie Thompson <bernie at plugable.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
+---
+
+diff --git a/drivers/staging/udlfb/udlfb.c b/drivers/staging/udlfb/udlfb.c
+index 12444f2..7fc1d61 100644
+--- a/drivers/staging/udlfb/udlfb.c
++++ b/drivers/staging/udlfb/udlfb.c
+@@ -1438,7 +1438,7 @@ static int __init dlfb_module_init(void)
+ 	if (res)
+ 		err("usb_register failed. Error number %d", res);
+ 
+-	printk("VMODES initialized\n");
++	printk(KERN_INFO "VMODES initialized\n");
+ 
+ 	return res;
+ }
+@@ -1567,7 +1567,7 @@ static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size)
+ 
+ 	kref_get(&dev->kref); /* released in free_render_urbs() */
+ 
+-	dl_notice("allocated %d %d byte urbs \n", i, (int) size);
++	dl_notice("allocated %d %d byte urbs\n", i, (int) size);
+ 
+ 	return i;
+ }

Added: dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-enhance-edid.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-enhance-edid.patch	Tue Nov  2 20:21:21 2010	(r16526)
@@ -0,0 +1,604 @@
+From: Bernie Thompson <bernie at plugable.com>
+Date: Sun, 5 Sep 2010 23:35:23 +0000 (-0700)
+Subject: staging: udlfb: enhance EDID and mode handling support
+X-Git-Tag: v2.6.37-rc1~60^2~3^2~677
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=18dffdf8913ab9e4ac7403a624879a15afa5262e
+
+staging: udlfb: enhance EDID and mode handling support
+
+Enhance EDID and mode table handling
+
+* Adds support for lower-end DL chips on higher-end monitors
+* Adds support for using fbdev standard EDID parsing and handling
+* Adds support for more dynamic reallocation of framebuffer, based on new EDID
+
+Queries EDID from hardware with several retries then
+queries DisplayLink chip for max pixel area via vendor descriptor.
+Uses existing fbdev mode handling service funcations to build mode list
+of common modes between adapter and monitor.
+This enables lower-end chips (e.g. DL-125) to successfully pick a compatible
+mode on higher end monitors (e.g. whose default mode is over 1280x1024).
+Reallocate framebuffer if necessary in response to new max mode.
+
+Signed-off-by: Bernie Thompson <bernie at plugable.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
+---
+
+diff --git a/drivers/staging/udlfb/udlfb.c b/drivers/staging/udlfb/udlfb.c
+index c9ac687..6977b71 100644
+--- a/drivers/staging/udlfb/udlfb.c
++++ b/drivers/staging/udlfb/udlfb.c
+@@ -696,19 +696,32 @@
+ 
+ }
+ 
+-static void dlfb_get_edid(struct dlfb_data *dev)
++static int dlfb_get_edid(struct dlfb_data *dev, char *edid, int len)
+ {
+ 	int i;
+ 	int ret;
+-	char rbuf[2];
++	char *rbuf;
+ 
+-	for (i = 0; i < sizeof(dev->edid); i++) {
++	rbuf = kmalloc(2, GFP_KERNEL);
++	if (!rbuf)
++		return 0;
++
++	for (i = 0; i < len; i++) {
+ 		ret = usb_control_msg(dev->udev,
+ 				    usb_rcvctrlpipe(dev->udev, 0), (0x02),
+ 				    (0x80 | (0x02 << 5)), i << 8, 0xA1, rbuf, 2,
+-				    0);
+-		dev->edid[i] = rbuf[1];
++				    HZ);
++		if (ret < 1) {
++			dl_err("Read EDID byte %d failed err %x\n", i, ret);
++			i--;
++			break;
++		}
++		edid[i] = rbuf[1];
+ 	}
++
++	kfree(rbuf);
++
++	return i;
+ }
+ 
+ static int dlfb_ops_ioctl(struct fb_info *info, unsigned int cmd,
+@@ -724,8 +737,7 @@
+ 	/* TODO: Update X server to get this from sysfs instead */
+ 	if (cmd == DLFB_IOCTL_RETURN_EDID) {
+ 		char *edid = (char *)arg;
+-		dlfb_get_edid(dev);
+-		if (copy_to_user(edid, dev->edid, sizeof(dev->edid)))
++		if (copy_to_user(edid, dev->edid, dev->edid_size))
+ 			return -EFAULT;
+ 		return 0;
+ 	}
+@@ -910,8 +922,13 @@
+ {
+ 	struct dlfb_data *dev = info->par;
+ 
+-	if (mode->xres * mode->yres > dev->sku_pixel_limit)
++	if (mode->xres * mode->yres > dev->sku_pixel_limit) {
++		dl_warn("%dx%d beyond chip capabilities\n",
++		       mode->xres, mode->yres);
+ 		return 0;
++	}
++
++	dl_info("%dx%d valid mode\n", mode->xres, mode->yres);
+ 
+ 	return 1;
+ }
+@@ -951,10 +968,27 @@
+ static int dlfb_ops_set_par(struct fb_info *info)
+ {
+ 	struct dlfb_data *dev = info->par;
++	int result;
++	u16 *pix_framebuffer;
++	int i;
+ 
+ 	dl_notice("set_par mode %dx%d\n", info->var.xres, info->var.yres);
+ 
+-	return dlfb_set_video_mode(dev, &info->var);
++	result = dlfb_set_video_mode(dev, &info->var);
++
++	if ((result == 0) && (dev->fb_count == 0)) {
++
++		/* paint greenscreen */
++
++		pix_framebuffer = (u16 *) info->screen_base;
++		for (i = 0; i < info->fix.smem_len / 2; i++)
++			pix_framebuffer[i] = 0x37e6;
++
++		dlfb_handle_damage(dev, 0, 0, info->var.xres, info->var.yres,
++				   info->screen_base);
++	}
++
++	return result;
+ }
+ 
+ /*
+@@ -1003,46 +1037,166 @@
+ 	.fb_set_par = dlfb_ops_set_par,
+ };
+ 
++
++/*
++ * Assumes &info->lock held by caller
++ * Assumes no active clients have framebuffer open
++ */
++static int dlfb_realloc_framebuffer(struct dlfb_data *dev, struct fb_info *info)
++{
++	int retval = -ENOMEM;
++	int old_len = info->fix.smem_len;
++	int new_len;
++	unsigned char *old_fb = info->screen_base;
++	unsigned char *new_fb;
++	unsigned char *new_back;
++
++	dl_warn("Reallocating framebuffer. Addresses will change!\n");
++
++	new_len = info->fix.line_length * info->var.yres;
++
++	if (PAGE_ALIGN(new_len) > old_len) {
++		/*
++		 * Alloc system memory for virtual framebuffer
++		 */
++		new_fb = vmalloc(new_len);
++		if (!new_fb) {
++			dl_err("Virtual framebuffer alloc failed\n");
++			goto error;
++		}
++
++		if (info->screen_base) {
++			memcpy(new_fb, old_fb, old_len);
++			vfree(info->screen_base);
++		}
++
++		info->screen_base = new_fb;
++		info->fix.smem_len = PAGE_ALIGN(new_len);
++		info->fix.smem_start = (unsigned long) new_fb;
++		info->flags = udlfb_info_flags;
++
++		/*
++		 * Second framebuffer copy to mirror the framebuffer state
++		 * on the physical USB device. We can function without this.
++		 * But with imperfect damage info we may send pixels over USB
++		 * that were, in fact, unchanged - wasting limited USB bandwidth
++		 */
++		new_back = vmalloc(new_len);
++		if (!new_back)
++			dl_info("No shadow/backing buffer allcoated\n");
++		else {
++			if (dev->backing_buffer)
++				vfree(dev->backing_buffer);
++			dev->backing_buffer = new_back;
++			memset(dev->backing_buffer, 0, new_len);
++		}
++	}
++
++	retval = 0;
++
++error:
++	return retval;
++}
++
+ /*
+- * Calls dlfb_get_edid() to query the EDID of attached monitor via usb cmds
+- * Then parses EDID into three places used by various parts of fbdev:
++ * 1) Get EDID from hw, or use sw default
++ * 2) Parse into various fb_info structs
++ * 3) Allocate virtual framebuffer memory to back highest res mode
++ *
++ * Parses EDID into three places used by various parts of fbdev:
+  * fb_var_screeninfo contains the timing of the monitor's preferred mode
+  * fb_info.monspecs is full parsed EDID info, including monspecs.modedb
+  * fb_info.modelist is a linked list of all monitor & VESA modes which work
+  *
+  * If EDID is not readable/valid, then modelist is all VESA modes,
+  * monspecs is NULL, and fb_var_screeninfo is set to safe VESA mode
+- * Returns 0 if EDID parses successfully
++ * Returns 0 if successful
+  */
+-static int dlfb_parse_edid(struct dlfb_data *dev,
+-			    struct fb_var_screeninfo *var,
+-			    struct fb_info *info)
++static int dlfb_setup_modes(struct dlfb_data *dev,
++			   struct fb_info *info,
++			   char *default_edid, size_t default_edid_size)
+ {
+ 	int i;
+ 	const struct fb_videomode *default_vmode = NULL;
+ 	int result = 0;
++	char *edid;
++	int tries = 3;
++
++	if (info->dev) /* only use mutex if info has been registered */
++		mutex_lock(&info->lock);
++
++	edid = kmalloc(MAX_EDID_SIZE, GFP_KERNEL);
++	if (!edid) {
++		result = -ENOMEM;
++		goto error;
++	}
+ 
+ 	fb_destroy_modelist(&info->modelist);
+ 	memset(&info->monspecs, 0, sizeof(info->monspecs));
+ 
+-	dlfb_get_edid(dev);
+-	fb_edid_to_monspecs(dev->edid, &info->monspecs);
++	/*
++	 * Try to (re)read EDID from hardware first
++	 * EDID data may return, but not parse as valid
++	 * Try again a few times, in case of e.g. analog cable noise
++	 */
++	while (tries--) {
++
++		i = dlfb_get_edid(dev, edid, MAX_EDID_SIZE);
++
++		if (i >= MIN_EDID_SIZE)
++			fb_edid_to_monspecs(edid, &info->monspecs);
++
++		if (info->monspecs.modedb_len > 0) {
++			dev->edid = edid;
++			dev->edid_size = i;
++			break;
++		}
++	}
++
++	/* If that fails, use a previously returned EDID if available */
++	if (info->monspecs.modedb_len == 0) {
++
++		dl_err("Unable to get valid EDID from device/display\n");
++
++		if (dev->edid) {
++			fb_edid_to_monspecs(dev->edid, &info->monspecs);
++			if (info->monspecs.modedb_len > 0)
++				dl_err("Using previously queried EDID\n");
++		}
++	}
++
++	/* If that fails, use the default EDID we were handed */
++	if (info->monspecs.modedb_len == 0) {
++		if (default_edid_size >= MIN_EDID_SIZE) {
++			fb_edid_to_monspecs(default_edid, &info->monspecs);
++			if (info->monspecs.modedb_len > 0) {
++				memcpy(edid, default_edid, default_edid_size);
++				dev->edid = edid;
++				dev->edid_size = default_edid_size;
++				dl_err("Using default/backup EDID\n");
++			}
++		}
++	}
+ 
++	/* If we've got modes, let's pick a best default mode */
+ 	if (info->monspecs.modedb_len > 0) {
+ 
+ 		for (i = 0; i < info->monspecs.modedb_len; i++) {
+ 			if (dlfb_is_valid_mode(&info->monspecs.modedb[i], info))
+ 				fb_add_videomode(&info->monspecs.modedb[i],
+ 					&info->modelist);
++			else /* if we've removed top/best mode */
++				info->monspecs.misc &= ~FB_MISC_1ST_DETAIL;
+ 		}
+ 
+ 		default_vmode = fb_find_best_display(&info->monspecs,
+ 						     &info->modelist);
+-	} else {
+-		struct fb_videomode fb_vmode = {0};
++	}
+ 
+-		dl_err("Unable to get valid EDID from device/display\n");
+-		result = 1;
++	/* If everything else has failed, fall back to safe default mode */
++	if (default_vmode == NULL) {
++
++		struct fb_videomode fb_vmode = {0};
+ 
+ 		/*
+ 		 * Add the standard VESA modes to our modelist
+@@ -1068,8 +1222,30 @@
+ 						     &info->modelist);
+ 	}
+ 
+-	fb_videomode_to_var(var, default_vmode);
+-	dlfb_var_color_format(var);
++	/* If we have good mode and no active clients*/
++	if ((default_vmode != NULL) && (dev->fb_count == 0)) {
++
++		fb_videomode_to_var(&info->var, default_vmode);
++		dlfb_var_color_format(&info->var);
++
++		/*
++		 * with mode size info, we can now alloc our framebuffer.
++		 */
++		memcpy(&info->fix, &dlfb_fix, sizeof(dlfb_fix));
++		info->fix.line_length = info->var.xres *
++			(info->var.bits_per_pixel / 8);
++
++		result = dlfb_realloc_framebuffer(dev, info);
++
++	} else
++		result = -EINVAL;
++
++error:
++	if (edid && (dev->edid != edid))
++		kfree(edid);
++
++	if (info->dev)
++		mutex_unlock(&info->lock);
+ 
+ 	return result;
+ }
+@@ -1111,18 +1287,20 @@
+ 	struct device *fbdev = container_of(kobj, struct device, kobj);
+ 	struct fb_info *fb_info = dev_get_drvdata(fbdev);
+ 	struct dlfb_data *dev = fb_info->par;
+-	char *edid = &dev->edid[0];
+-	const size_t size = sizeof(dev->edid);
+ 
+-	if (dlfb_parse_edid(dev, &fb_info->var, fb_info))
++	if (dev->edid == NULL)
+ 		return 0;
+ 
+-	if (off >= size)
++	if ((off >= dev->edid_size) || (count > dev->edid_size))
+ 		return 0;
+ 
+-	if (off + count > size)
+-		count = size - off;
+-	memcpy(buf, edid + off, count);
++	if (off + count > dev->edid_size)
++		count = dev->edid_size - off;
++
++	dl_info("sysfs edid copy %p to %p, %d bytes\n",
++		dev->edid, buf, (int) count);
++
++	memcpy(buf, dev->edid, count);
+ 
+ 	return count;
+ }
+@@ -1260,19 +1438,82 @@
+ 	return ret;
+ }
+ 
++static int dlfb_parse_vendor_descriptor(struct dlfb_data *dev,
++					struct usb_device *usbdev)
++{
++	char *desc;
++	char *buf;
++	char *desc_end;
+ 
++	u8 total_len = 0;
++
++	buf = kzalloc(MAX_VENDOR_DESCRIPTOR_SIZE, GFP_KERNEL);
++	if (!buf)
++		return false;
++	desc = buf;
++
++	total_len = usb_get_descriptor(usbdev, 0x5f, /* vendor specific */
++				    0, desc, MAX_VENDOR_DESCRIPTOR_SIZE);
++	if (total_len > 5) {
++		dl_info("vendor descriptor length:%x data:%02x %02x %02x %02x" \
++			"%02x %02x %02x %02x %02x %02x %02x\n",
++			total_len, desc[0],
++			desc[1], desc[2], desc[3], desc[4], desc[5], desc[6],
++			desc[7], desc[8], desc[9], desc[10]);
++
++		if ((desc[0] != total_len) || /* descriptor length */
++		    (desc[1] != 0x5f) ||   /* vendor descriptor type */
++		    (desc[2] != 0x01) ||   /* version (2 bytes) */
++		    (desc[3] != 0x00) ||
++		    (desc[4] != total_len - 2)) /* length after type */
++			goto unrecognized;
++
++		desc_end = desc + total_len;
++		desc += 5; /* the fixed header we've already parsed */
++
++		while (desc < desc_end) {
++			u8 length;
++			u16 key;
++
++			key = *((u16 *) desc);
++			desc += sizeof(u16);
++			length = *desc;
++			desc++;
++
++			switch (key) {
++			case 0x0200: { /* max_area */
++				u32 max_area;
++				max_area = le32_to_cpu(*((u32 *)desc));
++				dl_warn("DL chip limited to %d pixel modes\n",
++					max_area);
++				dev->sku_pixel_limit = max_area;
++				break;
++			}
++			default:
++				break;
++			}
++			desc += length;
++		}
++	}
++
++	goto success;
++
++unrecognized:
++	/* allow udlfb to load for now even if firmware unrecognized */
++	dl_err("Unrecognized vendor firmware descriptor\n");
++
++success:
++	kfree(buf);
++	return true;
++}
+ static int dlfb_usb_probe(struct usb_interface *interface,
+ 			const struct usb_device_id *id)
+ {
+ 	struct usb_device *usbdev;
+-	struct dlfb_data *dev;
++	struct dlfb_data *dev = 0;
+ 	struct fb_info *info = 0;
+-	int videomemorysize;
+ 	int i;
+-	unsigned char *videomemory;
+ 	int retval = -ENOMEM;
+-	struct fb_var_screeninfo *var;
+-	u16 *pix_framebuffer;
+ 
+ 	/* usb initialization */
+ 
+@@ -1286,12 +1527,25 @@
+ 
+ 	/* we need to wait for both usb and fbdev to spin down on disconnect */
+ 	kref_init(&dev->kref); /* matching kref_put in usb .disconnect fn */
+-	kref_get(&dev->kref); /* matching kref_put in .fb_destroy function*/
++	kref_get(&dev->kref); /* matching kref_put in free_framebuffer_work */
+ 
+ 	dev->udev = usbdev;
+ 	dev->gdev = &usbdev->dev; /* our generic struct device * */
+ 	usb_set_intfdata(interface, dev);
+ 
++	dl_info("%s %s - serial #%s\n",
++		usbdev->manufacturer, usbdev->product, usbdev->serial);
++	dl_info("vid_%04x&pid_%04x&rev_%04x driver's dlfb_data struct at %p\n",
++		usbdev->descriptor.idVendor, usbdev->descriptor.idProduct,
++		usbdev->descriptor.bcdDevice, dev);
++
++	dev->sku_pixel_limit = 2048 * 1152; /* default to maximum */
++
++	if (!dlfb_parse_vendor_descriptor(dev, usbdev)) {
++		dl_err("firmware not recognized. Assume incompatible device\n");
++		goto error;
++	}
++
+ 	if (!dlfb_alloc_urb_list(dev, WRITES_IN_FLIGHT, MAX_TRANSFER)) {
+ 		retval = -ENOMEM;
+ 		dl_err("dlfb_alloc_urb_list failed\n");
+@@ -1313,50 +1567,6 @@
+ 	info->pseudo_palette = dev->pseudo_palette;
+ 	info->fbops = &dlfb_ops;
+ 
+-	var = &info->var;
+-
+-	/* TODO set limit based on actual SKU detection */
+-	dev->sku_pixel_limit = 2048 * 1152;
+-
+-	INIT_LIST_HEAD(&info->modelist);
+-	dlfb_parse_edid(dev, var, info);
+-
+-	/*
+-	 * ok, now that we've got the size info, we can alloc our framebuffer.
+-	 */
+-	info->fix = dlfb_fix;
+-	info->fix.line_length = var->xres * (var->bits_per_pixel / 8);
+-	videomemorysize = info->fix.line_length * var->yres;
+-
+-	/*
+-	 * The big chunk of system memory we use as a virtual framebuffer.
+-	 * TODO: Handle fbcon cursor code calling blit in interrupt context
+-	 */
+-	videomemory = vmalloc(videomemorysize);
+-	if (!videomemory) {
+-		retval = -ENOMEM;
+-		dl_err("Virtual framebuffer alloc failed\n");
+-		goto error;
+-	}
+-
+-	info->screen_base = videomemory;
+-	info->fix.smem_len = PAGE_ALIGN(videomemorysize);
+-	info->fix.smem_start = (unsigned long) videomemory;
+-	info->flags = udlfb_info_flags;
+-
+-
+-	/*
+-	 * Second framebuffer copy, mirroring the state of the framebuffer
+-	 * on the physical USB device. We can function without this.
+-	 * But with imperfect damage info we may end up sending pixels over USB
+-	 * that were, in fact, unchanged -- wasting limited USB bandwidth
+-	 */
+-	dev->backing_buffer = vmalloc(videomemorysize);
+-	if (!dev->backing_buffer)
+-		dl_warn("No shadow/backing buffer allcoated\n");
+-	else
+-		memset(dev->backing_buffer, 0, videomemorysize);
+-
+ 	retval = fb_alloc_cmap(&info->cmap, 256, 0);
+ 	if (retval < 0) {
+ 		dl_err("fb_alloc_cmap failed %x\n", retval);
+@@ -1366,6 +1576,14 @@
+ 	INIT_DELAYED_WORK(&dev->free_framebuffer_work,
+ 			  dlfb_free_framebuffer_work);
+ 
++	INIT_LIST_HEAD(&info->modelist);
++
++	retval = dlfb_setup_modes(dev, info, NULL, 0);
++	if (retval != 0) {
++		dl_err("unable to find common mode for display and adapter\n");
++		goto error;
++	}
++
+ 	/* ready to begin using device */
+ 
+ #ifdef CONFIG_FB_DEFERRED_IO
+@@ -1374,17 +1592,9 @@
+ 	atomic_set(&dev->usb_active, 1);
+ 	dlfb_select_std_channel(dev);
+ 
+-	dlfb_ops_check_var(var, info);
++	dlfb_ops_check_var(&info->var, info);
+ 	dlfb_ops_set_par(info);
+ 
+-	/* paint greenscreen */
+-	pix_framebuffer = (u16 *) videomemory;
+-	for (i = 0; i < videomemorysize / 2; i++)
+-		pix_framebuffer[i] = 0x37e6;
+-
+-	dlfb_handle_damage(dev, 0, 0, info->var.xres, info->var.yres,
+-				videomemory);
+-
+ 	retval = register_framebuffer(info);
+ 	if (retval < 0) {
+ 		dl_err("register_framebuffer failed %d\n", retval);
+@@ -1396,11 +1606,11 @@
+ 
+ 	device_create_bin_file(info->dev, &edid_attr);
+ 
+-	dl_err("DisplayLink USB device /dev/fb%d attached. %dx%d resolution."
++	dl_info("DisplayLink USB device /dev/fb%d attached. %dx%d resolution."
+ 			" Using %dK framebuffer memory\n", info->node,
+-			var->xres, var->yres,
++			info->var.xres, info->var.yres,
+ 			((dev->backing_buffer) ?
+-			videomemorysize * 2 : videomemorysize) >> 10);
++			info->fix.smem_len * 2 : info->fix.smem_len) >> 10);
+ 	return 0;
+ 
+ error:
+
+diff --git a/drivers/staging/udlfb/udlfb.h b/drivers/staging/udlfb/udlfb.h
+index 7c46477..d28e783 100644
+--- a/drivers/staging/udlfb/udlfb.h
++++ b/drivers/staging/udlfb/udlfb.h
+@@ -44,7 +44,8 @@ struct dlfb_data {
+ 	atomic_t usb_active; /* 0 = update virtual buffer, but no usb traffic */
+ 	atomic_t lost_pixels; /* 1 = a render op failed. Need screen refresh */
+ 	atomic_t use_defio; /* 0 = rely on ioctls and blit/copy/fill rects */
+-	char edid[128];
++	char *edid; /* null until we read edid from hw or get from sysfs */
++	size_t edid_size;
+ 	int sku_pixel_limit;
+ 	int base16;
+ 	int base8;
+@@ -64,6 +65,11 @@ struct dlfb_data {
+ #define MAX_TRANSFER (PAGE_SIZE*16 - BULK_SIZE)
+ #define WRITES_IN_FLIGHT (4)
+ 
++#define MIN_EDID_SIZE 128
++#define MAX_EDID_SIZE 128
++
++#define MAX_VENDOR_DESCRIPTOR_SIZE 256
++
+ #define GET_URB_TIMEOUT	HZ
+ #define FREE_URB_TIMEOUT (HZ*2)
+ 

Added: dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-fbdev-char.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-fbdev-char.patch	Tue Nov  2 20:21:21 2010	(r16526)
@@ -0,0 +1,81 @@
+From: Bernie Thompson <bernie at plugable.com>
+Date: Sun, 5 Sep 2010 23:35:04 +0000 (-0700)
+Subject: staging: udlfb: fbdev character read and write support
+X-Git-Tag: v2.6.37-rc1~60^2~3^2~681
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=d46ecb9f79db82ce6bef4baafbcae29ac809ea67
+
+staging: udlfb: fbdev character read and write support
+
+Restore fbdev character read and write support
+
+Enables access to the framebuffer from simple reads and writes
+to /dev/fb0 (or fb1, ...). Low performance, because of extra copy
+and because udlfb must scan every pixel for changes. But very
+useful for testing and simple image display, etc.
+
+Signed-off-by: Bernie Thompson <bernie at plugable.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
+---
+
+diff --git a/drivers/staging/udlfb/udlfb.c b/drivers/staging/udlfb/udlfb.c
+index c7e061e..a2bd5f7 100644
+--- a/drivers/staging/udlfb/udlfb.c
++++ b/drivers/staging/udlfb/udlfb.c
+@@ -602,6 +602,48 @@ int dlfb_handle_damage(struct dlfb_data *dev, int x, int y,
+ 	return 0;
+ }
+ 
++static ssize_t dlfb_ops_read(struct fb_info *info, char __user *buf,
++			 size_t count, loff_t *ppos)
++{
++	ssize_t result = -ENOSYS;
++
++#if defined CONFIG_FB_SYS_FOPS || defined CONFIG_FB_SYS_FOPS_MODULE
++	result = fb_sys_read(info, buf, count, ppos);
++#endif
++
++	return result;
++}
++
++/*
++ * Path triggered by usermode clients who write to filesystem
++ * e.g. cat filename > /dev/fb1
++ * Not used by X Windows or text-mode console. But useful for testing.
++ * Slow because of extra copy and we must assume all pixels dirty.
++ */
++static ssize_t dlfb_ops_write(struct fb_info *info, const char __user *buf,
++			  size_t count, loff_t *ppos)
++{
++	ssize_t result = -ENOSYS;
++	struct dlfb_data *dev = info->par;
++	u32 offset = (u32) *ppos;
++
++#if defined CONFIG_FB_SYS_FOPS || defined CONFIG_FB_SYS_FOPS_MODULE
++
++	result = fb_sys_write(info, buf, count, ppos);
++
++	if (result > 0) {
++		int start = max((int)(offset / info->fix.line_length) - 1, 0);
++		int lines = min((u32)((result / info->fix.line_length) + 1),
++				(u32)info->var.yres);
++
++		dlfb_handle_damage(dev, 0, start, info->var.xres,
++			lines, info->screen_base);
++	}
++#endif
++
++	return result;
++}
++
+ /* hardware has native COPY command (see libdlo), but not worth it for fbcon */
+ static void dlfb_ops_copyarea(struct fb_info *info,
+ 				const struct fb_copyarea *area)
+@@ -924,6 +966,8 @@ static int dlfb_ops_blank(int blank_mode, struct fb_info *info)
+ 
+ static struct fb_ops dlfb_ops = {
+ 	.owner = THIS_MODULE,
++	.fb_read = dlfb_ops_read,
++	.fb_write = dlfb_ops_write,
+ 	.fb_setcolreg = dlfb_ops_setcolreg,
+ 	.fb_fillrect = dlfb_ops_fillrect,
+ 	.fb_copyarea = dlfb_ops_copyarea,

Added: dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-fix-incorrect-fb_defio-implementation.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-fix-incorrect-fb_defio-implementation.patch	Tue Nov  2 20:21:21 2010	(r16526)
@@ -0,0 +1,236 @@
+From: Bernie Thompson <bernie at plugable.com>
+Date: Mon, 6 Sep 2010 01:28:29 +0000 (-0700)
+Subject: staging: udlfb: fix incorrect fb_defio implementation for multiple framebuffers
+X-Git-Tag: v2.6.37-rc1~60^2~3^2~665
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=5bea1fbf942363e4114a086aefc67cdca21be7f0
+
+staging: udlfb: fix incorrect fb_defio implementation for multiple framebuffers
+
+Fix fb_defio bug in udlfb for multiple framebuffers
+
+Previously when using fb_defio with multiple DisplayLink attached displays
+udlfb incorrectly used a shared datastructure where it needed to have
+one per fb_info struct. This was completely broken and caused all kinds of
+problems, including rendering to one framebuffer affecting others.
+
+Signed-off-by: Bernie Thompson <bernie at plugable.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
+---
+
+diff --git a/drivers/staging/udlfb/udlfb.c b/drivers/staging/udlfb/udlfb.c
+index 80a1e0e..082468a 100644
+--- a/drivers/staging/udlfb/udlfb.c
++++ b/drivers/staging/udlfb/udlfb.c
+@@ -70,11 +70,6 @@ static int dlfb_submit_urb(struct dlfb_data *dev, struct urb * urb, size_t len);
+ static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size);
+ static void dlfb_free_urb_list(struct dlfb_data *dev);
+ 
+-/* other symbols with dependents */
+-#ifdef CONFIG_FB_DEFERRED_IO
+-static struct fb_deferred_io dlfb_defio;
+-#endif
+-
+ /*
+  * All DisplayLink bulk operations start with 0xAF, followed by specific code
+  * All operations are written to buffers which then later get sent to device
+@@ -481,7 +476,7 @@ static void dlfb_compress_hline(
+  * (that we can only write to, slowly, and can never read), and (optionally)
+  * our shadow copy that tracks what's been sent to that hardware buffer.
+  */
+-static void dlfb_render_hline(struct dlfb_data *dev, struct urb **urb_ptr,
++static int dlfb_render_hline(struct dlfb_data *dev, struct urb **urb_ptr,
+ 			      const char *front, char **urb_buf_ptr,
+ 			      u32 byte_offset, u32 byte_width,
+ 			      int *ident_ptr, int *sent_ptr)
+@@ -523,11 +518,11 @@ static void dlfb_render_hline(struct dlfb_data *dev, struct urb **urb_ptr,
+ 		if (cmd >= cmd_end) {
+ 			int len = cmd - (u8 *) urb->transfer_buffer;
+ 			if (dlfb_submit_urb(dev, urb, len))
+-				return; /* lost pixels is set */
++				return 1; /* lost pixels is set */
+ 			*sent_ptr += len;
+ 			urb = dlfb_get_urb(dev);
+ 			if (!urb)
+-				return; /* lost_pixels is set */
++				return 1; /* lost_pixels is set */
+ 			*urb_ptr = urb;
+ 			cmd = urb->transfer_buffer;
+ 			cmd_end = &cmd[urb->transfer_buffer_length];
+@@ -535,6 +530,8 @@ static void dlfb_render_hline(struct dlfb_data *dev, struct urb **urb_ptr,
+ 	}
+ 
+ 	*urb_buf_ptr = cmd;
++
++	return 0;
+ }
+ 
+ int dlfb_handle_damage(struct dlfb_data *dev, int x, int y,
+@@ -571,9 +568,11 @@ int dlfb_handle_damage(struct dlfb_data *dev, int x, int y,
+ 		const int line_offset = dev->info->fix.line_length * i;
+ 		const int byte_offset = line_offset + (x * BPP);
+ 
+-		dlfb_render_hline(dev, &urb, (char *) dev->info->fix.smem_start,
++		if (dlfb_render_hline(dev, &urb,
++				      (char *) dev->info->fix.smem_start,
+ 				  &cmd, byte_offset, width * BPP,
+-				  &bytes_identical, &bytes_sent);
++				      &bytes_identical, &bytes_sent))
++			goto error;
+ 	}
+ 
+ 	if (cmd > (char *) urb->transfer_buffer) {
+@@ -584,6 +583,7 @@ int dlfb_handle_damage(struct dlfb_data *dev, int x, int y,
+ 	} else
+ 		dlfb_urb_completion(urb);
+ 
++error:
+ 	atomic_add(bytes_sent, &dev->bytes_sent);
+ 	atomic_add(bytes_identical, &dev->bytes_identical);
+ 	atomic_add(width*height*2, &dev->bytes_rendered);
+@@ -722,9 +722,10 @@ static void dlfb_dpy_deferred_io(struct fb_info *info,
+ 	/* walk the written page list and render each to device */
+ 	list_for_each_entry(cur, &fbdefio->pagelist, lru) {
+ 
+-		dlfb_render_hline(dev, &urb, (char *) info->fix.smem_start,
++		if (dlfb_render_hline(dev, &urb, (char *) info->fix.smem_start,
+ 				  &cmd, cur->index << PAGE_SHIFT,
+-				  PAGE_SIZE, &bytes_identical, &bytes_sent);
++				  PAGE_SIZE, &bytes_identical, &bytes_sent))
++			goto error;
+ 		bytes_rendered += PAGE_SIZE;
+ 	}
+ 
+@@ -736,6 +737,7 @@ static void dlfb_dpy_deferred_io(struct fb_info *info,
+ 	} else
+ 		dlfb_urb_completion(urb);
+ 
++error:
+ 	atomic_add(bytes_sent, &dev->bytes_sent);
+ 	atomic_add(bytes_identical, &dev->bytes_identical);
+ 	atomic_add(bytes_rendered, &dev->bytes_rendered);
+@@ -796,6 +798,16 @@ static int dlfb_ops_ioctl(struct fb_info *info, unsigned int cmd,
+ 	/* TODO: Help propose a standard fb.h ioctl to report mmap damage */
+ 	if (cmd == DLFB_IOCTL_REPORT_DAMAGE) {
+ 
++		/*
++		 * If we have a damage-aware client, turn fb_defio "off"
++		 * To avoid perf imact of unecessary page fault handling.
++		 * Done by resetting the delay for this fb_info to a very
++		 * long period. Pages will become writable and stay that way.
++		 * Reset to normal value when all clients have closed this fb.
++		 */
++		if (info->fbdefio)
++			info->fbdefio->delay = DL_DEFIO_WRITE_DISABLE;
++
+ 		area = (struct dloarea *)arg;
+ 
+ 		if (area->x < 0)
+@@ -871,8 +883,18 @@ static int dlfb_ops_open(struct fb_info *info, int user)
+ 
+ #ifdef CONFIG_FB_DEFERRED_IO
+ 	if (fb_defio && (info->fbdefio == NULL)) {
+-		/* enable defio */
+-		info->fbdefio = &dlfb_defio;
++		/* enable defio at last moment if not disabled by client */
++
++		struct fb_deferred_io *fbdefio;
++
++		fbdefio = kmalloc(GFP_KERNEL, sizeof(struct fb_deferred_io));
++
++		if (fbdefio) {
++			fbdefio->delay = DL_DEFIO_WRITE_DELAY;
++			fbdefio->deferred_io = dlfb_dpy_deferred_io;
++		}
++
++		info->fbdefio = fbdefio;
+ 		fb_deferred_io_init(info);
+ 	}
+ #endif
+@@ -906,6 +928,13 @@ static void dlfb_free(struct kref *kref)
+ 	kfree(dev);
+ }
+ 
++static void dlfb_release_urb_work(struct work_struct *work)
++{
++	struct urb_node *unode = container_of(work, struct urb_node,
++					      release_urb_work.work);
++
++	up(&unode->dev->urbs.limit_sem);
++}
+ 
+ static void dlfb_free_framebuffer_work(struct work_struct *work)
+ {
+@@ -1411,15 +1440,6 @@ static struct device_attribute fb_device_attrs[] = {
+ 	__ATTR(metrics_reset, S_IWUGO, NULL, metrics_reset_store),
+ };
+ 
+-#ifdef CONFIG_FB_DEFERRED_IO
+-
+-static struct fb_deferred_io dlfb_defio = {
+-	.delay          = 5,
+-	.deferred_io    = dlfb_dpy_deferred_io,
+-};
+-
+-#endif
+-
+ /*
+  * This is necessary before we can communicate with the display controller.
+  */
+@@ -1726,7 +1746,14 @@ static void dlfb_urb_completion(struct urb *urb)
+ 	dev->urbs.available++;
+ 	spin_unlock_irqrestore(&dev->urbs.lock, flags);
+ 
+-	up(&dev->urbs.limit_sem);
++	/*
++	 * When using fb_defio, we deadlock if up() is called
++	 * while another is waiting. So queue to another process.
++	 */
++	if (fb_defio)
++		schedule_delayed_work(&unode->release_urb_work, 0);
++	else
++		up(&dev->urbs.limit_sem);
+ }
+ 
+ static void dlfb_free_urb_list(struct dlfb_data *dev)
+@@ -1785,6 +1812,9 @@ static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size)
+ 			break;
+ 		unode->dev = dev;
+ 
++		INIT_DELAYED_WORK(&unode->release_urb_work,
++			  dlfb_release_urb_work);
++
+ 		urb = usb_alloc_urb(0, GFP_KERNEL);
+ 		if (!urb) {
+ 			kfree(unode);
+@@ -1831,7 +1861,8 @@ static struct urb *dlfb_get_urb(struct dlfb_data *dev)
+ 	ret = down_timeout(&dev->urbs.limit_sem, GET_URB_TIMEOUT);
+ 	if (ret) {
+ 		atomic_set(&dev->lost_pixels, 1);
+-		dl_err("wait for urb interrupted: %x\n", ret);
++		dl_warn("wait for urb interrupted: %x available: %d\n",
++		       ret, dev->urbs.available);
+ 		goto error;
+ 	}
+ 
+diff --git a/drivers/staging/udlfb/udlfb.h b/drivers/staging/udlfb/udlfb.h
+index 58d2af6..6f9785e 100644
+--- a/drivers/staging/udlfb/udlfb.h
++++ b/drivers/staging/udlfb/udlfb.h
+@@ -19,6 +19,7 @@ struct dloarea {
+ struct urb_node {
+ 	struct list_head entry;
+ 	struct dlfb_data *dev;
++	struct delayed_work release_urb_work;
+ 	struct urb *urb;
+ };
+ 
+@@ -87,6 +88,9 @@ struct dlfb_data {
+ #define MIN_RAW_PIX_BYTES	2
+ #define MIN_RAW_CMD_BYTES	(RAW_HEADER_BYTES + MIN_RAW_PIX_BYTES)
+ 
++#define DL_DEFIO_WRITE_DELAY    5 /* fb_deferred_io.delay in jiffies */
++#define DL_DEFIO_WRITE_DISABLE  (HZ*60) /* "disable" with long delay */
++
+ /* remove these once align.h patch is taken into kernel */
+ #define DL_ALIGN_UP(x, a) ALIGN(x, a)
+ #define DL_ALIGN_DOWN(x, a) ALIGN(x-(a-1), a)

Added: dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-minor-cleanups.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-minor-cleanups.patch	Tue Nov  2 20:21:21 2010	(r16526)
@@ -0,0 +1,101 @@
+From 3b7b31fa7df01576cc401dff512a6a84cb3753ed Mon Sep 17 00:00:00 2001
+From: Pavel Machek <pavel at ucw.cz>
+Date: Sat, 3 Apr 2010 07:00:37 +0200
+Subject: [PATCH] Staging: udlfb: minor cleanups
+
+This cleans up udlfb a tiny bit.
+
+Signed-off-by: Pavel Machek <pavel at ucw.cz>
+Cc: Bernie Thompson <bernie at plugable.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
+---
+ drivers/staging/udlfb/udlfb.c |   58 ++++++++++++++++++++--------------------
+ 1 files changed, 29 insertions(+), 29 deletions(-)
+
+diff --git a/drivers/staging/udlfb/udlfb.c b/drivers/staging/udlfb/udlfb.c
+index a78ade0..12444f2 100644
+--- a/drivers/staging/udlfb/udlfb.c
++++ b/drivers/staging/udlfb/udlfb.c
+@@ -58,17 +58,17 @@ static struct usb_device_id id_table[] = {
+ MODULE_DEVICE_TABLE(usb, id_table);
+ 
+ #ifndef CONFIG_FB_DEFERRED_IO
+-#warning message "kernel FB_DEFFERRED_IO option to support generic fbdev apps"
++#warning Please set CONFIG_FB_DEFFERRED_IO option to support generic fbdev apps
+ #endif
+ 
+ #ifndef CONFIG_FB_SYS_IMAGEBLIT
+ #ifndef CONFIG_FB_SYS_IMAGEBLIT_MODULE
+-#warning message "FB_SYS_* in kernel or module option to support fb console"
++#warning Please set CONFIG_FB_SYS_IMAGEBLIT option to support fb console
+ #endif
+ #endif
+ 
+ #ifndef CONFIG_FB_MODE_HELPERS
+-#warning message "kernel FB_MODE_HELPERS required. Expect build break"
++#warning CONFIG_FB_MODE_HELPERS required. Expect build break
+ #endif
+ 
+ /* dlfb keeps a list of urbs for efficient bulk transfers */
+@@ -366,32 +366,32 @@ static int dlfb_trim_hline(const u8 *bback, const u8 **bfront, int *width_bytes)
+ }
+ 
+ /*
+-Render a command stream for an encoded horizontal line segment of pixels.
+-
+-A command buffer holds several commands.
+-It always begins with a fresh command header
+-(the protocol doesn't require this, but we enforce it to allow
+-multiple buffers to be potentially encoded and sent in parallel).
+-A single command encodes one contiguous horizontal line of pixels
+-
+-The function relies on the client to do all allocation, so that
+-rendering can be done directly to output buffers (e.g. USB URBs).
+-The function fills the supplied command buffer, providing information
+-on where it left off, so the client may call in again with additional
+-buffers if the line will take several buffers to complete.
+-
+-A single command can transmit a maximum of 256 pixels,
+-regardless of the compression ratio (protocol design limit).
+-To the hardware, 0 for a size byte means 256
+-
+-Rather than 256 pixel commands which are either rl or raw encoded,
+-the rlx command simply assumes alternating raw and rl spans within one cmd.
+-This has a slightly larger header overhead, but produces more even results.
+-It also processes all data (read and write) in a single pass.
+-Performance benchmarks of common cases show it having just slightly better
+-compression than 256 pixel raw -or- rle commands, with similar CPU consumpion.
+-But for very rl friendly data, will compress not quite as well.
+-*/
++ * Render a command stream for an encoded horizontal line segment of pixels.
++ *
++ * A command buffer holds several commands.
++ * It always begins with a fresh command header
++ * (the protocol doesn't require this, but we enforce it to allow
++ * multiple buffers to be potentially encoded and sent in parallel).
++ * A single command encodes one contiguous horizontal line of pixels
++ *
++ * The function relies on the client to do all allocation, so that
++ * rendering can be done directly to output buffers (e.g. USB URBs).
++ * The function fills the supplied command buffer, providing information
++ * on where it left off, so the client may call in again with additional
++ * buffers if the line will take several buffers to complete.
++ *
++ * A single command can transmit a maximum of 256 pixels,
++ * regardless of the compression ratio (protocol design limit).
++ * To the hardware, 0 for a size byte means 256
++ * 
++ * Rather than 256 pixel commands which are either rl or raw encoded,
++ * the rlx command simply assumes alternating raw and rl spans within one cmd.
++ * This has a slightly larger header overhead, but produces more even results.
++ * It also processes all data (read and write) in a single pass.
++ * Performance benchmarks of common cases show it having just slightly better
++ * compression than 256 pixel raw -or- rle commands, with similar CPU consumpion.
++ * But for very rl friendly data, will compress not quite as well.
++ */
+ static void dlfb_compress_hline(
+ 	const uint16_t **pixel_start_ptr,
+ 	const uint16_t *const pixel_end,
+-- 
+1.7.3.2
+

Added: dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-module-options.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-module-options.patch	Tue Nov  2 20:21:21 2010	(r16526)
@@ -0,0 +1,302 @@
+From: Bernie Thompson <bernie at plugable.com>
+Date: Sun, 5 Sep 2010 23:35:39 +0000 (-0700)
+Subject: staging: udlfb: add module options for console and fb_defio
+X-Git-Tag: v2.6.37-rc1~60^2~3^2~674
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=d5ed54322e54d48e5fa66dff0086b79211f1cde7
+
+staging: udlfb: add module options for console and fb_defio
+
+Add module options for console and fb_defio
+
+Convert fb_defio on/off switch to module option and add console option.
+
+>From the command line, pass options to modprobe
+modprobe udlfb defio=1 console=1
+
+Or for permanent option, create file like /etc/modprobe.d/options with text
+options udlfb defio=1 console=1
+
+Accepted options:
+
+fb_defio	Make use of the fb_defio (CONFIG_FB_DEFERRED_IO) kernel
+		module to track changed areas of the framebuffer by page faults.
+        	Standard fbdev applications that use mmap but that do not
+		report damage, may be able to work with this enabled.
+		Disabled by default because of overhead and other issues.
+
+console		Allow fbcon to attach to udlfb provided framebuffers. This
+		is disabled by default because fbcon will aggressively consume
+		the first framebuffer it finds, which isn't usually what the
+		user wants in the case of USB displays.
+
+Signed-off-by: Bernie Thompson <bernie at plugable.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
+---
+
+diff --git a/drivers/staging/udlfb/udlfb.c b/drivers/staging/udlfb/udlfb.c
+index b13869b..80a1e0e 100644
+--- a/drivers/staging/udlfb/udlfb.c
++++ b/drivers/staging/udlfb/udlfb.c
+@@ -59,19 +59,9 @@ static struct usb_device_id id_table[] = {
+ };
+ MODULE_DEVICE_TABLE(usb, id_table);
+ 
+-#ifndef CONFIG_FB_DEFERRED_IO
+-#warning Please set CONFIG_FB_DEFFERRED_IO option to support generic fbdev apps
+-#endif
+-
+-#ifndef CONFIG_FB_SYS_IMAGEBLIT
+-#ifndef CONFIG_FB_SYS_IMAGEBLIT_MODULE
+-#warning Please set CONFIG_FB_SYS_IMAGEBLIT option to support fb console
+-#endif
+-#endif
+-
+-#ifndef CONFIG_FB_MODE_HELPERS
+-#warning CONFIG_FB_MODE_HELPERS required. Expect build break
+-#endif
++/* module options */
++static int console;   /* Optionally allow fbcon to consume first framebuffer */
++static int fb_defio;  /* Optionally enable experimental fb_defio mmap support */
+ 
+ /* dlfb keeps a list of urbs for efficient bulk transfers */
+ static void dlfb_urb_completion(struct urb *urb);
+@@ -695,6 +685,68 @@ static void dlfb_ops_fillrect(struct fb_info *info,
+ 
+ }
+ 
++#ifdef CONFIG_FB_DEFERRED_IO
++/*
++ * NOTE: fb_defio.c is holding info->fbdefio.mutex
++ *   Touching ANY framebuffer memory that triggers a page fault
++ *   in fb_defio will cause a deadlock, when it also tries to
++ *   grab the same mutex.
++ */
++static void dlfb_dpy_deferred_io(struct fb_info *info,
++				struct list_head *pagelist)
++{
++	struct page *cur;
++	struct fb_deferred_io *fbdefio = info->fbdefio;
++	struct dlfb_data *dev = info->par;
++	struct urb *urb;
++	char *cmd;
++	cycles_t start_cycles, end_cycles;
++	int bytes_sent = 0;
++	int bytes_identical = 0;
++	int bytes_rendered = 0;
++
++	if (!fb_defio)
++		return;
++
++	if (!atomic_read(&dev->usb_active))
++		return;
++
++	start_cycles = get_cycles();
++
++	urb = dlfb_get_urb(dev);
++	if (!urb)
++		return;
++
++	cmd = urb->transfer_buffer;
++
++	/* walk the written page list and render each to device */
++	list_for_each_entry(cur, &fbdefio->pagelist, lru) {
++
++		dlfb_render_hline(dev, &urb, (char *) info->fix.smem_start,
++				  &cmd, cur->index << PAGE_SHIFT,
++				  PAGE_SIZE, &bytes_identical, &bytes_sent);
++		bytes_rendered += PAGE_SIZE;
++	}
++
++	if (cmd > (char *) urb->transfer_buffer) {
++		/* Send partial buffer remaining before exiting */
++		int len = cmd - (char *) urb->transfer_buffer;
++		dlfb_submit_urb(dev, urb, len);
++		bytes_sent += len;
++	} else
++		dlfb_urb_completion(urb);
++
++	atomic_add(bytes_sent, &dev->bytes_sent);
++	atomic_add(bytes_identical, &dev->bytes_identical);
++	atomic_add(bytes_rendered, &dev->bytes_rendered);
++	end_cycles = get_cycles();
++	atomic_add(((unsigned int) ((end_cycles - start_cycles)
++		    >> 10)), /* Kcycles */
++		   &dev->cpu_kcycles_used);
++}
++
++#endif
++
+ static int dlfb_get_edid(struct dlfb_data *dev, char *edid, int len)
+ {
+ 	int i;
+@@ -758,8 +810,6 @@ static int dlfb_ops_ioctl(struct fb_info *info, unsigned int cmd,
+ 		if (area->y > info->var.yres)
+ 			area->y = info->var.yres;
+ 
+-		atomic_set(&dev->use_defio, 0);
+-
+ 		dlfb_handle_damage(dev, area->x, area->y, area->w, area->h,
+ 			   info->screen_base);
+ 	}
+@@ -803,9 +853,13 @@ static int dlfb_ops_open(struct fb_info *info, int user)
+ {
+ 	struct dlfb_data *dev = info->par;
+ 
+-/*	if (user == 0)
+- *		We could special case kernel mode clients (fbcon) here
+- */
++	/*
++	 * fbcon aggressively connects to first framebuffer it finds,
++	 * preventing other clients (X) from working properly. Usually
++	 * not what the user wants. Fail by default with option to enable.
++	 */
++	if ((user == 0) & (!console))
++		return -EBUSY;
+ 
+ 	/* If the USB device is gone, we don't accept new opens */
+ 	if (dev->virtualized)
+@@ -816,7 +870,7 @@ static int dlfb_ops_open(struct fb_info *info, int user)
+ 	kref_get(&dev->kref);
+ 
+ #ifdef CONFIG_FB_DEFERRED_IO
+-	if ((atomic_read(&dev->use_defio)) && (info->fbdefio == NULL)) {
++	if (fb_defio && (info->fbdefio == NULL)) {
+ 		/* enable defio */
+ 		info->fbdefio = &dlfb_defio;
+ 		fb_deferred_io_init(info);
+@@ -1341,30 +1395,6 @@ static ssize_t metrics_reset_store(struct device *fbdev,
+ 	return count;
+ }
+ 
+-static ssize_t use_defio_show(struct device *fbdev,
+-				   struct device_attribute *a, char *buf) {
+-	struct fb_info *fb_info = dev_get_drvdata(fbdev);
+-	struct dlfb_data *dev = fb_info->par;
+-	return snprintf(buf, PAGE_SIZE, "%d\n",
+-			atomic_read(&dev->use_defio));
+-}
+-
+-static ssize_t use_defio_store(struct device *fbdev,
+-			   struct device_attribute *attr,
+-			   const char *buf, size_t count)
+-{
+-	struct fb_info *fb_info = dev_get_drvdata(fbdev);
+-	struct dlfb_data *dev = fb_info->par;
+-
+-	if (count > 0) {
+-		if (buf[0] == '0')
+-			atomic_set(&dev->use_defio, 0);
+-		if (buf[0] == '1')
+-			atomic_set(&dev->use_defio, 1);
+-	}
+-	return count;
+-}
+-
+ static struct bin_attribute edid_attr = {
+ 	.attr.name = "edid",
+ 	.attr.mode = 0666,
+@@ -1379,60 +1409,9 @@ static struct device_attribute fb_device_attrs[] = {
+ 	__ATTR_RO(metrics_bytes_sent),
+ 	__ATTR_RO(metrics_cpu_kcycles_used),
+ 	__ATTR(metrics_reset, S_IWUGO, NULL, metrics_reset_store),
+-	__ATTR_RW(use_defio),
+ };
+ 
+ #ifdef CONFIG_FB_DEFERRED_IO
+-static void dlfb_dpy_deferred_io(struct fb_info *info,
+-				struct list_head *pagelist)
+-{
+-	struct page *cur;
+-	struct fb_deferred_io *fbdefio = info->fbdefio;
+-	struct dlfb_data *dev = info->par;
+-	struct urb *urb;
+-	char *cmd;
+-	cycles_t start_cycles, end_cycles;
+-	int bytes_sent = 0;
+-	int bytes_identical = 0;
+-	int bytes_rendered = 0;
+-
+-	if (!atomic_read(&dev->use_defio))
+-		return;
+-
+-	if (!atomic_read(&dev->usb_active))
+-		return;
+-
+-	start_cycles = get_cycles();
+-
+-	urb = dlfb_get_urb(dev);
+-	if (!urb)
+-		return;
+-	cmd = urb->transfer_buffer;
+-
+-	/* walk the written page list and render each to device */
+-	list_for_each_entry(cur, &fbdefio->pagelist, lru) {
+-		dlfb_render_hline(dev, &urb, (char *) info->fix.smem_start,
+-				  &cmd, cur->index << PAGE_SHIFT,
+-				  PAGE_SIZE, &bytes_identical, &bytes_sent);
+-		bytes_rendered += PAGE_SIZE;
+-	}
+-
+-	if (cmd > (char *) urb->transfer_buffer) {
+-		/* Send partial buffer remaining before exiting */
+-		int len = cmd - (char *) urb->transfer_buffer;
+-		dlfb_submit_urb(dev, urb, len);
+-		bytes_sent += len;
+-	} else
+-		dlfb_urb_completion(urb);
+-
+-	atomic_add(bytes_sent, &dev->bytes_sent);
+-	atomic_add(bytes_identical, &dev->bytes_identical);
+-	atomic_add(bytes_rendered, &dev->bytes_rendered);
+-	end_cycles = get_cycles();
+-	atomic_add(((unsigned int) ((end_cycles - start_cycles)
+-		    >> 10)), /* Kcycles */
+-		   &dev->cpu_kcycles_used);
+-}
+ 
+ static struct fb_deferred_io dlfb_defio = {
+ 	.delay          = 5,
+@@ -1559,6 +1538,8 @@ static int dlfb_usb_probe(struct usb_interface *interface,
+ 	dl_info("vid_%04x&pid_%04x&rev_%04x driver's dlfb_data struct at %p\n",
+ 		usbdev->descriptor.idVendor, usbdev->descriptor.idProduct,
+ 		usbdev->descriptor.bcdDevice, dev);
++	dl_info("console enable=%d\n", console);
++	dl_info("fb_defio enable=%d\n", fb_defio);
+ 
+ 	dev->sku_pixel_limit = 2048 * 1152; /* default to maximum */
+ 
+@@ -1607,9 +1588,6 @@ static int dlfb_usb_probe(struct usb_interface *interface,
+ 
+ 	/* ready to begin using device */
+ 
+-#ifdef CONFIG_FB_DEFERRED_IO
+-	atomic_set(&dev->use_defio, 1);
+-#endif
+ 	atomic_set(&dev->usb_active, 1);
+ 	dlfb_select_std_channel(dev);
+ 
+@@ -1889,6 +1867,12 @@ static int dlfb_submit_urb(struct dlfb_data *dev, struct urb *urb, size_t len)
+ 	return ret;
+ }
+ 
++module_param(console, bool, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
++MODULE_PARM_DESC(console, "Allow fbcon to consume first framebuffer found");
++
++module_param(fb_defio, bool, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP);
++MODULE_PARM_DESC(fb_defio, "Enable fb_defio mmap support. *Experimental*");
++
+ MODULE_AUTHOR("Roberto De Ioris <roberto at unbit.it>, "
+ 	      "Jaya Kumar <jayakumar.lkml at gmail.com>, "
+ 	      "Bernie Thompson <bernie at plugable.com>");
+diff --git a/drivers/staging/udlfb/udlfb.h b/drivers/staging/udlfb/udlfb.h
+index d28e783..58d2af6 100644
+--- a/drivers/staging/udlfb/udlfb.h
++++ b/drivers/staging/udlfb/udlfb.h
+@@ -43,7 +43,6 @@ struct dlfb_data {
+ 	struct delayed_work free_framebuffer_work;
+ 	atomic_t usb_active; /* 0 = update virtual buffer, but no usb traffic */
+ 	atomic_t lost_pixels; /* 1 = a render op failed. Need screen refresh */
+-	atomic_t use_defio; /* 0 = rely on ioctls and blit/copy/fill rects */
+ 	char *edid; /* null until we read edid from hw or get from sysfs */
+ 	size_t edid_size;
+ 	int sku_pixel_limit;

Added: dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-remove-metrics_misc.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-remove-metrics_misc.patch	Tue Nov  2 20:21:21 2010	(r16526)
@@ -0,0 +1,146 @@
+From: Bernie Thompson <bernie at plugable.com>
+Date: Sun, 5 Sep 2010 23:35:15 +0000 (-0700)
+Subject: staging: udlfb: remove metrics_misc sysfs attribute
+X-Git-Tag: v2.6.37-rc1~60^2~3^2~679
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=f11f4bc027414bc7db5dde49c55b7149a627b591
+
+staging: udlfb: remove metrics_misc sysfs attribute
+
+Remove metrics_misc sysfs attribute
+
+Previously returned multiple values, which goes against sysfs guidelines.
+Had been used for debugging to figure out which of the multiple
+fbdev interfaces an app was using, but log file messages are sufficient.
+
+Signed-off-by: Bernie Thompson <bernie at plugable.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
+---
+
+diff --git a/drivers/staging/udlfb/udlfb.c b/drivers/staging/udlfb/udlfb.c
+index 0e03dd3..b027a1e 100644
+--- a/drivers/staging/udlfb/udlfb.c
++++ b/drivers/staging/udlfb/udlfb.c
+@@ -661,7 +661,6 @@ static void dlfb_ops_copyarea(struct fb_info *info,
+ 	dlfb_handle_damage(dev, area->dx, area->dy,
+ 			area->width, area->height, info->screen_base);
+ #endif
+-	atomic_inc(&dev->copy_count);
+ 
+ }
+ 
+@@ -679,7 +678,6 @@ static void dlfb_ops_imageblit(struct fb_info *info,
+ 
+ #endif
+ 
+-	atomic_inc(&dev->blit_count);
+ }
+ 
+ static void dlfb_ops_fillrect(struct fb_info *info,
+@@ -695,8 +693,6 @@ static void dlfb_ops_fillrect(struct fb_info *info,
+ 			      rect->height, info->screen_base);
+ #endif
+ 
+-	atomic_inc(&dev->fill_count);
+-
+ }
+ 
+ static void dlfb_get_edid(struct dlfb_data *dev)
+@@ -754,7 +750,6 @@ static int dlfb_ops_ioctl(struct fb_info *info, unsigned int cmd,
+ 
+ 		dlfb_handle_damage(dev, area->x, area->y, area->w, area->h,
+ 			   info->screen_base);
+-		atomic_inc(&dev->damage_count);
+ 	}
+ 
+ 	return 0;
+@@ -1088,29 +1083,6 @@ static ssize_t metrics_cpu_kcycles_used_show(struct device *fbdev,
+ 			atomic_read(&dev->cpu_kcycles_used));
+ }
+ 
+-static ssize_t metrics_misc_show(struct device *fbdev,
+-				   struct device_attribute *a, char *buf) {
+-	struct fb_info *fb_info = dev_get_drvdata(fbdev);
+-	struct dlfb_data *dev = fb_info->par;
+-	return snprintf(buf, PAGE_SIZE,
+-			"Calls to\ndamage: %u\nblit: %u\n"
+-			"defio faults: %u\ncopy: %u\n"
+-			"fill: %u\n\n"
+-			"active framebuffer clients: %d\n"
+-			"urbs available %d(%d)\n"
+-			"Shadow framebuffer in use? %s\n"
+-			"Any lost pixels? %s\n",
+-			atomic_read(&dev->damage_count),
+-			atomic_read(&dev->blit_count),
+-			atomic_read(&dev->defio_fault_count),
+-			atomic_read(&dev->copy_count),
+-			atomic_read(&dev->fill_count),
+-			dev->fb_count,
+-			dev->urbs.available, dev->urbs.limit_sem.count,
+-			(dev->backing_buffer) ? "yes" : "no",
+-			atomic_read(&dev->lost_pixels) ? "yes" : "no");
+-}
+-
+ static ssize_t edid_show(struct kobject *kobj, struct bin_attribute *a,
+ 			 char *buf, loff_t off, size_t count) {
+	struct device *fbdev = container_of(kobj, struct device, kobj);
+@@ -1144,11 +1116,6 @@ static ssize_t metrics_reset_store(struct device *fbdev,
+ 	atomic_set(&dev->bytes_identical, 0);
+ 	atomic_set(&dev->bytes_sent, 0);
+ 	atomic_set(&dev->cpu_kcycles_used, 0);
+-	atomic_set(&dev->blit_count, 0);
+-	atomic_set(&dev->copy_count, 0);
+-	atomic_set(&dev->fill_count, 0);
+-	atomic_set(&dev->defio_fault_count, 0);
+-	atomic_set(&dev->damage_count, 0);
+ 
+ 	return count;
+ }
+@@ -1189,7 +1156,6 @@ static struct device_attribute fb_device_attrs[] = {
+ 	__ATTR_RO(metrics_bytes_identical),
+ 	__ATTR_RO(metrics_bytes_sent),
+ 	__ATTR_RO(metrics_cpu_kcycles_used),
+-	__ATTR_RO(metrics_misc),
+ 	__ATTR(metrics_reset, S_IWUGO, NULL, metrics_reset_store),
+ 	__ATTR_RW(use_defio),
+ };
+@@ -1207,7 +1173,6 @@ static void dlfb_dpy_deferred_io(struct fb_info *info,
+ 	int bytes_sent = 0;
+ 	int bytes_identical = 0;
+ 	int bytes_rendered = 0;
+-	int fault_count = 0;
+ 
+ 	if (!atomic_read(&dev->use_defio))
+ 		return;
+@@ -1228,7 +1193,6 @@ static void dlfb_dpy_deferred_io(struct fb_info *info,
+ 				  &cmd, cur->index << PAGE_SHIFT,
+ 				  PAGE_SIZE, &bytes_identical, &bytes_sent);
+ 		bytes_rendered += PAGE_SIZE;
+-		fault_count++;
+ 	}
+ 
+ 	if (cmd > (char *) urb->transfer_buffer) {
+@@ -1239,7 +1203,6 @@ static void dlfb_dpy_deferred_io(struct fb_info *info,
+ 	} else
+ 		dlfb_urb_completion(urb);
+ 
+-	atomic_add(fault_count, &dev->defio_fault_count);
+ 	atomic_add(bytes_sent, &dev->bytes_sent);
+ 	atomic_add(bytes_identical, &dev->bytes_identical);
+ 	atomic_add(bytes_rendered, &dev->bytes_rendered);
+diff --git a/drivers/staging/udlfb/udlfb.h b/drivers/staging/udlfb/udlfb.h
+index b07a693..f32a220 100644
+--- a/drivers/staging/udlfb/udlfb.h
++++ b/drivers/staging/udlfb/udlfb.h
+@@ -54,12 +54,6 @@ struct dlfb_data {
+ 	atomic_t bytes_identical; /* saved effort with backbuffer comparison */
+ 	atomic_t bytes_sent; /* to usb, after compression including overhead */
+ 	atomic_t cpu_kcycles_used; /* transpired during pixel processing */
+-	/* interface usage metrics. Clients can call driver via several */
+-	atomic_t blit_count;
+-	atomic_t copy_count;
+-	atomic_t fill_count;
+-	atomic_t damage_count;
+-	atomic_t defio_fault_count;
+ };
+ 
+ #define NR_USB_REQUEST_I2C_SUB_IO 0x02

Added: dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-revamp-reference-handling.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-revamp-reference-handling.patch	Tue Nov  2 20:21:21 2010	(r16526)
@@ -0,0 +1,398 @@
+From: Bernie Thompson <bernie at plugable.com>
+Date: Sun, 5 Sep 2010 23:35:19 +0000 (-0700)
+Subject: staging: udlfb: revamp reference handling to insure successful shutdown
+X-Git-Tag: v2.6.37-rc1~60^2~3^2~678
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=33077b8d3042e01da61924973e372abe589ba297
+
+staging: udlfb: revamp reference handling to insure successful shutdown
+
+Revamp reference handling and synchronization for unload/shutdown
+
+Udlfb is a "virtual" framebuffer device that really exists on
+two separate stacks: at the bottom of the framebuffer interface,
+and on top of USB.  During unload, there's no guarantee which
+one will tear down first. So reference counting must be solid
+to handle all possibilities and not access anything once its gone.
+
+Signed-off-by: Bernie Thompson <bernie at plugable.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
+---
+
+diff --git a/drivers/staging/udlfb/udlfb.c b/drivers/staging/udlfb/udlfb.c
+index b027a1e..c9ac687 100644
+--- a/drivers/staging/udlfb/udlfb.c
++++ b/drivers/staging/udlfb/udlfb.c
+@@ -25,6 +25,8 @@
+ #include <linux/fb.h>
+ #include <linux/vmalloc.h>
+ #include <linux/slab.h>
++#include <linux/delay.h>
++
+ 
+ #include "udlfb.h"
+ 
+@@ -300,7 +302,6 @@ static int dlfb_ops_mmap(struct fb_info *info, struct vm_area_struct *vma)
+ 	unsigned long size = vma->vm_end - vma->vm_start;
+ 	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+ 	unsigned long page, pos;
+-	struct dlfb_data *dev = info->par;
+ 
+ 	dl_notice("MMAP: %lu %u\n", offset + size, info->fix.smem_len);
+ 
+@@ -785,6 +786,7 @@ dlfb_ops_setcolreg(unsigned regno, unsigned red, unsigned green,
+ /*
+  * It's common for several clients to have framebuffer open simultaneously.
+  * e.g. both fbcon and X. Makes things interesting.
++ * Assumes caller is holding info->lock (for open and release at least)
+  */
+ static int dlfb_ops_open(struct fb_info *info, int user)
+ {
+@@ -794,10 +796,14 @@ static int dlfb_ops_open(struct fb_info *info, int user)
+  *		We could special case kernel mode clients (fbcon) here
+  */
+ 
+-	mutex_lock(&dev->fb_open_lock);
++	/* If the USB device is gone, we don't accept new opens */
++	if (dev->virtualized)
++		return -ENODEV;
+ 
+ 	dev->fb_count++;
+ 
++	kref_get(&dev->kref);
++
+ #ifdef CONFIG_FB_DEFERRED_IO
+ 	if ((atomic_read(&dev->use_defio)) && (info->fbdefio == NULL)) {
+ 		/* enable defio */
+@@ -809,32 +815,6 @@ static int dlfb_ops_open(struct fb_info *info, int user)
+ 	dl_notice("open /dev/fb%d user=%d fb_info=%p count=%d\n",
+ 	    info->node, user, info, dev->fb_count);
+ 
+-	mutex_unlock(&dev->fb_open_lock);
+-
+-	return 0;
+-}
+-
+-static int dlfb_ops_release(struct fb_info *info, int user)
+-{
+-	struct dlfb_data *dev = info->par;
+-
+-	mutex_lock(&dev->fb_open_lock);
+-
+-	dev->fb_count--;
+-
+-#ifdef CONFIG_FB_DEFERRED_IO
+-	if ((dev->fb_count == 0) && (info->fbdefio)) {
+-		fb_deferred_io_cleanup(info);
+-		info->fbdefio = NULL;
+-		info->fbops->fb_mmap = dlfb_ops_mmap;
+-	}
+-#endif
+-
+-	dl_notice("release /dev/fb%d user=%d count=%d\n",
+-		  info->node, user, dev->fb_count);
+-
+-	mutex_unlock(&dev->fb_open_lock);
+-
+ 	return 0;
+ }
+ 
+@@ -843,25 +823,33 @@ static int dlfb_ops_release(struct fb_info *info, int user)
+  * and all references to our device instance (dlfb_data) are released.
+  * Every transaction must have a reference, so we know are fully spun down
+  */
+-static void dlfb_delete(struct kref *kref)
++static void dlfb_free(struct kref *kref)
+ {
+ 	struct dlfb_data *dev = container_of(kref, struct dlfb_data, kref);
+ 
++	/* this function will wait for all in-flight urbs to complete */
++	if (dev->urbs.count > 0)
++		dlfb_free_urb_list(dev);
++
+ 	if (dev->backing_buffer)
+ 		vfree(dev->backing_buffer);
+ 
+-	mutex_destroy(&dev->fb_open_lock);
++	kfree(dev->edid);
++
++	dl_warn("freeing dlfb_data %p\n", dev);
+ 
+ 	kfree(dev);
+ }
+ 
+-/*
+- * Called by fbdev as last part of unregister_framebuffer() process
+- * No new clients can open connections. Deallocate everything fb_info.
+- */
+-static void dlfb_ops_destroy(struct fb_info *info)
++
++static void dlfb_free_framebuffer_work(struct work_struct *work)
+ {
+-	struct dlfb_data *dev = info->par;
++	struct dlfb_data *dev = container_of(work, struct dlfb_data,
++					     free_framebuffer_work.work);
++	struct fb_info *info = dev->info;
++	int node = info->node;
++
++	unregister_framebuffer(info);
+ 
+ 	if (info->cmap.len != 0)
+ 		fb_dealloc_cmap(&info->cmap);
+@@ -872,10 +860,45 @@ static void dlfb_ops_destroy(struct fb_info *info)
+ 
+ 	fb_destroy_modelist(&info->modelist);
+ 
++	dev->info = 0;
++
++	/* Assume info structure is freed after this point */
+ 	framebuffer_release(info);
+ 
+-	/* ref taken before register_framebuffer() for dlfb_data clients */
+-	kref_put(&dev->kref, dlfb_delete);
++	dl_warn("fb_info for /dev/fb%d has been freed\n", node);
++
++	/* ref taken in probe() as part of registering framebfufer */
++	kref_put(&dev->kref, dlfb_free);
++}
++
++/*
++ * Assumes caller is holding info->lock mutex (for open and release at least)
++ */
++static int dlfb_ops_release(struct fb_info *info, int user)
++{
++	struct dlfb_data *dev = info->par;
++
++	dev->fb_count--;
++
++	/* We can't free fb_info here - fbmem will touch it when we return */
++	if (dev->virtualized && (dev->fb_count == 0))
++		schedule_delayed_work(&dev->free_framebuffer_work, HZ);
++
++#ifdef CONFIG_FB_DEFERRED_IO
++	if ((dev->fb_count == 0) && (info->fbdefio)) {
++		fb_deferred_io_cleanup(info);
++		kfree(info->fbdefio);
++		info->fbdefio = NULL;
++		info->fbops->fb_mmap = dlfb_ops_mmap;
++	}
++#endif
++
++	dl_warn("released /dev/fb%d user=%d count=%d\n",
++		  info->node, user, dev->fb_count);
++
++	kref_put(&dev->kref, dlfb_free);
++
++	return 0;
+ }
+ 
+ /*
+@@ -1243,13 +1266,12 @@ static int dlfb_usb_probe(struct usb_interface *interface,
+ {
+ 	struct usb_device *usbdev;
+ 	struct dlfb_data *dev;
+-	struct fb_info *info;
++	struct fb_info *info = 0;
+ 	int videomemorysize;
+ 	int i;
+ 	unsigned char *videomemory;
+ 	int retval = -ENOMEM;
+ 	struct fb_var_screeninfo *var;
+-	int registered = 0;
+ 	u16 *pix_framebuffer;
+ 
+ 	/* usb initialization */
+@@ -1276,8 +1298,6 @@ static int dlfb_usb_probe(struct usb_interface *interface,
+ 		goto error;
+ 	}
+ 
+-	mutex_init(&dev->fb_open_lock);
+-
+ 	/* We don't register a new USB class. Our client interface is fbdev */
+ 
+ 	/* allocates framebuffer driver structure, not framebuffer memory */
+@@ -1287,6 +1307,7 @@ static int dlfb_usb_probe(struct usb_interface *interface,
+ 		dl_err("framebuffer_alloc failed\n");
+ 		goto error;
+ 	}
++
+ 	dev->info = info;
+ 	info->par = dev;
+ 	info->pseudo_palette = dev->pseudo_palette;
+@@ -1342,6 +1363,9 @@ static int dlfb_usb_probe(struct usb_interface *interface,
+ 		goto error;
+ 	}
+ 
++	INIT_DELAYED_WORK(&dev->free_framebuffer_work,
++			  dlfb_free_framebuffer_work);
++
+ 	/* ready to begin using device */
+ 
+ #ifdef CONFIG_FB_DEFERRED_IO
+@@ -1366,7 +1390,6 @@ static int dlfb_usb_probe(struct usb_interface *interface,
+ 		dl_err("register_framebuffer failed %d\n", retval);
+ 		goto error;
+ 	}
+-	registered = 1;
+ 
+ 	for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
+ 		device_create_file(info->dev, &fb_device_attrs[i]);
+@@ -1382,15 +1405,25 @@ static int dlfb_usb_probe(struct usb_interface *interface,
+ 
+ error:
+ 	if (dev) {
+-		if (registered) {
+-			unregister_framebuffer(info);
+-			dlfb_ops_destroy(info);
+-		} else
+-			kref_put(&dev->kref, dlfb_delete);
+ 
+-		if (dev->urbs.count > 0)
+-			dlfb_free_urb_list(dev);
+-		kref_put(&dev->kref, dlfb_delete); /* last ref from kref_init */
++		if (info) {
++			if (info->cmap.len != 0)
++				fb_dealloc_cmap(&info->cmap);
++			if (info->monspecs.modedb)
++				fb_destroy_modedb(info->monspecs.modedb);
++			if (info->screen_base)
++				vfree(info->screen_base);
++
++			fb_destroy_modelist(&info->modelist);
++
++			framebuffer_release(info);
++		}
++
++		if (dev->backing_buffer)
++			vfree(dev->backing_buffer);
++
++		kref_put(&dev->kref, dlfb_free); /* ref for framebuffer */
++		kref_put(&dev->kref, dlfb_free); /* last ref from kref_init */
+ 
+ 		/* dev has been deallocated. Do not dereference */
+ 	}
+@@ -1407,27 +1440,27 @@ static void dlfb_usb_disconnect(struct usb_interface *interface)
+ 	dev = usb_get_intfdata(interface);
+ 	info = dev->info;
+ 
+-	/* when non-active we'll update virtual framebuffer, but no new urbs */
+-	atomic_set(&dev->usb_active, 0);
++	dl_info("USB disconnect starting\n");
+ 
+-	usb_set_intfdata(interface, NULL);
++	/* we virtualize until all fb clients release. Then we free */
++	dev->virtualized = true;
++
++	/* When non-active we'll update virtual framebuffer, but no new urbs */
++	atomic_set(&dev->usb_active, 0);
+ 
++	/* remove udlfb's sysfs interfaces */
+ 	for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
+ 		device_remove_file(info->dev, &fb_device_attrs[i]);
+-
+ 	device_remove_bin_file(info->dev, &edid_attr);
+ 
+-	/* this function will wait for all in-flight urbs to complete */
+-	dlfb_free_urb_list(dev);
++	usb_set_intfdata(interface, NULL);
+ 
+-	if (info) {
+-		dl_notice("Detaching /dev/fb%d\n", info->node);
+-		unregister_framebuffer(info);
+-		dlfb_ops_destroy(info);
+-	}
++	/* if clients still have us open, will be freed on last close */
++	if (dev->fb_count == 0)
++		schedule_delayed_work(&dev->free_framebuffer_work, 0);
+ 
+ 	/* release reference taken by kref_init in probe() */
+-	kref_put(&dev->kref, dlfb_delete);
++	kref_put(&dev->kref, dlfb_free);
+ 
+ 	/* consider dlfb_data freed */
+ 
+@@ -1449,8 +1482,6 @@ static int __init dlfb_module_init(void)
+ 	if (res)
+ 		err("usb_register failed. Error number %d", res);
+ 
+-	printk(KERN_INFO "VMODES initialized\n");
+-
+ 	return res;
+ }
+ 
+@@ -1502,12 +1533,12 @@ static void dlfb_free_urb_list(struct dlfb_data *dev)
+ 
+ 	/* keep waiting and freeing, until we've got 'em all */
+ 	while (count--) {
+-		/* Timeout means a memory leak and/or fault */
+-		ret = down_timeout(&dev->urbs.limit_sem, FREE_URB_TIMEOUT);
+-		if (ret) {
+-			BUG_ON(ret);
++
++		/* Getting interrupted means a leak, but ok at shutdown*/
++		ret = down_interruptible(&dev->urbs.limit_sem);
++		if (ret)
+ 			break;
+-		}
++
+ 		spin_lock_irqsave(&dev->urbs.lock, flags);
+ 
+ 		node = dev->urbs.list.next; /* have reserved one with sem */
+@@ -1525,8 +1556,6 @@ static void dlfb_free_urb_list(struct dlfb_data *dev)
+ 		kfree(node);
+ 	}
+ 
+-	kref_put(&dev->kref, dlfb_delete);
+-
+ }
+ 
+ static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size)
+@@ -1576,8 +1605,6 @@ static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size)
+ 	dev->urbs.count = i;
+ 	dev->urbs.available = i;
+ 
+-	kref_get(&dev->kref); /* released in free_render_urbs() */
+-
+ 	dl_notice("allocated %d %d byte urbs\n", i, (int) size);
+ 
+ 	return i;
+diff --git a/drivers/staging/udlfb/udlfb.h b/drivers/staging/udlfb/udlfb.h
+index f32a220..7c46477 100644
+--- a/drivers/staging/udlfb/udlfb.h
++++ b/drivers/staging/udlfb/udlfb.h
+@@ -38,9 +38,9 @@ struct dlfb_data {
+ 	struct urb_list urbs;
+ 	struct kref kref;
+ 	char *backing_buffer;
+-	struct delayed_work deferred_work;
+-	struct mutex fb_open_lock;
+ 	int fb_count;
++	bool virtualized; /* true when physical usb device not present */
++	struct delayed_work free_framebuffer_work;
+ 	atomic_t usb_active; /* 0 = update virtual buffer, but no usb traffic */
+ 	atomic_t lost_pixels; /* 1 = a render op failed. Need screen refresh */
+ 	atomic_t use_defio; /* 0 = rely on ioctls and blit/copy/fill rects */
+@@ -89,12 +89,20 @@ struct dlfb_data {
+ /* remove once this gets added to sysfs.h */
+ #define __ATTR_RW(attr) __ATTR(attr, 0644, attr##_show, attr##_store)
+ 
++/*
++ * udlfb is both a usb device, and a framebuffer device.
++ * They may exist at the same time, but during various stages
++ * inactivity, teardown, or "virtual" operation, only one or the
++ * other will exist (one will outlive the other).  So we can't
++ * call the dev_*() macros, because we don't have a stable dev object.
++ */
+ #define dl_err(format, arg...) \
+-	dev_err(dev->gdev, "dlfb: " format, ## arg)
++	pr_err("udlfb: " format, ## arg)
+ #define dl_warn(format, arg...) \
+-	dev_warn(dev->gdev, "dlfb: " format, ## arg)
++	pr_warning("udlfb: " format, ## arg)
+ #define dl_notice(format, arg...) \
+-	dev_notice(dev->gdev, "dlfb: " format, ## arg)
++	pr_notice("udlfb: " format, ## arg)
+ #define dl_info(format, arg...) \
+-	dev_info(dev->gdev, "dlfb: " format, ## arg)
++	pr_info("udlfb: " format, ## arg)
++
+ #endif

Modified: dists/sid/linux-2.6/debian/patches/series/28
==============================================================================
--- dists/sid/linux-2.6/debian/patches/series/28	Tue Nov  2 16:36:34 2010	(r16525)
+++ dists/sid/linux-2.6/debian/patches/series/28	Tue Nov  2 20:21:21 2010	(r16526)
@@ -2,3 +2,16 @@
 + bugfix/all/drm-i915-set-DIDL-using-the-ACPI-video-output-device.patch
 + bugfix/all/drm-ttm-Clear-the-ghost-cpu_writers-flag-on-ttm_buff.patch
 + bugfix/all/drm-nouveau-fix-race-condition-when-under-memory-pre.patch
++ features/all/udlfb/udlfb-add-slab.patch
++ features/all/udlfb/udlfb-minor-cleanups.patch
++ features/all/udlfb/udlfb-coding-style.patch
++ features/all/udlfb/udlfb-fbdev-char.patch
++ features/all/udlfb/udlfb-add-dpms.patch
++ features/all/udlfb/udlfb-remove-metrics_misc.patch
++ features/all/udlfb/udlfb-revamp-reference-handling.patch
++ features/all/udlfb/udlfb-enhance-edid.patch
++ features/all/udlfb/udlfb-big-endian-fix.patch
++ features/all/udlfb/udlfb-backup-edid-write.patch
++ features/all/udlfb/udlfb-module-options.patch
++ features/all/udlfb/udlfb-fix-incorrect-fb_defio-implementation.patch
++ features/all/udlfb/udlfb-checkpatch-style.patch



More information about the Kernel-svn-changes mailing list