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

Martin Michlmayr tbm at alioth.debian.org
Mon Jul 5 17:35:23 UTC 2010


Author: tbm
Date: Mon Jul  5 17:35:21 2010
New Revision: 15941

Log:
Update DisplayLink (udlfb) driver

Added:
   dists/sid/linux-2.6/debian/patches/features/all/udlfb/
   dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-add_dynamic_modeset_support.patch
   dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-checkpatch-cleanup.patch
   dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-cleanup-function-naming.patch
   dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-explicit-warnings-and-deps.patch
   dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-improve-rendering-performance.patch
   dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-preallocated-urb-list-helpers.patch
   dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-printk-cleanup.patch
   dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-reorg-function-order.patch
   dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-rework-startup.patch
   dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-support-fbdev-mmap-clients.patch
   dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-sysfs-expose-metrics.patch
Modified:
   dists/sid/linux-2.6/debian/changelog
   dists/sid/linux-2.6/debian/patches/series/16

Modified: dists/sid/linux-2.6/debian/changelog
==============================================================================
--- dists/sid/linux-2.6/debian/changelog	Mon Jul  5 12:04:57 2010	(r15940)
+++ dists/sid/linux-2.6/debian/changelog	Mon Jul  5 17:35:21 2010	(r15941)
@@ -90,6 +90,18 @@
     - Make the copy-back of data optional
     - Support processing of data from previous requests
     - Add sha1 and hmac(sha1) async hash drivers
+  * Update DisplayLink (udlfb) driver:
+    - add dynamic modeset support
+    - checkpatch cleanup
+    - reorganize function order
+    - pre-allocated urb list helpers
+    - clean up function naming
+    - Add functions to expose sysfs metrics and controls
+    - Rework startup and teardown to fix race conditions
+    - improved rendering performance
+    - Support for fbdev mmap clients (defio)
+    - explicit dependencies and warnings
+    - remove printk and small cleanup
 
   [ Bastian Blank ]
   * Disable mISDN support for NETJet cards. The driver binds a generic PCI

Added: dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-add_dynamic_modeset_support.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_dynamic_modeset_support.patch	Mon Jul  5 17:35:21 2010	(r15941)
@@ -0,0 +1,975 @@
+From: Bernie Thompson <bernie at plugable.com>
+Date: Tue, 24 Nov 2009 23:52:21 +0000 (-0800)
+Subject: Staging: udlfb: add dynamic modeset support
+X-Git-Tag: v2.6.34-rc1~10^2~1^2~304
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=59277b679f8b5ce594e367759256668eba652d0d
+
+Staging: udlfb: add dynamic modeset support
+
+Add dynamic modeset support
+
+udlfb uses EDID to find the monitor’s preferred mode
+udlfb no longer has fixed mode tables – it’s able to set any mode
+dynamically, from the standard VESA timing characteristics of the monitor.
+
+Draws from probe and setmode code of both displaylink-mod 0.3 branch of
+Roberto De Ioris, and Jaya Kumar's displaylinkfb.
+Lays foundation for defio support and making backbuffer optional.
+With additional changes to minimize diffs and clean for checkpatch.pl style.
+
+Does not yet include new ioctls or refcount/mutex code from displaylink-mod.
+
+Tested to work with existing xf-video-displaylink X server unmodified.
+
+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 f5416af..b61a3e5 100644
+--- a/drivers/staging/udlfb/udlfb.c
++++ b/drivers/staging/udlfb/udlfb.c
+@@ -1,17 +1,19 @@
+-/*****************************************************************************
+- *                          DLFB Kernel Driver                               *
+- *                            Version 0.2 (udlfb)                            *
+- *             (C) 2009 Roberto De Ioris <roberto at unbit.it>                  *
+- *                                                                           *
+- *     This file is licensed under the GPLv2. See COPYING in the package.    *
+- * Based on the amazing work of Florian Echtler and libdlo 0.1               *
+- *                                                                           *
+- *                                                                           *
+- * 10.06.09 release 0.2.3 (edid ioctl, fallback for unsupported modes)       *
+- * 05.06.09 release 0.2.2 (real screen blanking, rle compression, double buffer) *
+- * 31.05.09 release 0.2                                                      *
+- * 22.05.09 First public (ugly) release                                      *
+- *****************************************************************************/
++/*
++ * udlfb.c -- Framebuffer driver for DisplayLink USB controller
++ *
++ * Copyright (C) 2009 Roberto De Ioris <roberto at unbit.it>
++ * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml at gmail.com>
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License v2. See the file COPYING in the main directory of this archive for
++ * more details.
++ *
++ * Layout is based on skeletonfb by James Simmons and Geert Uytterhoeven,
++ * usb-skeleton by GregKH.
++ *
++ * Device-specific portions based on information from Displaylink, with work
++ * from Florian Echtler, Henrik Bjerregaard Pedersen, and others.
++ */
+ 
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+@@ -25,45 +27,263 @@
+ 
+ #include "udlfb.h"
+ 
+-#define DRIVER_VERSION "DLFB 0.2"
++#define DRIVER_VERSION "DisplayLink Framebuffer Driver 0.4.1"
++
++static struct fb_fix_screeninfo dlfb_fix = {
++       .id =           "displaylinkfb",
++       .type =         FB_TYPE_PACKED_PIXELS,
++       .visual =       FB_VISUAL_TRUECOLOR,
++       .xpanstep =     0,
++       .ypanstep =     0,
++       .ywrapstep =    0,
++       .accel =        FB_ACCEL_NONE,
++};
+ 
+-/* memory functions taken from vfb */
++#define NR_USB_REQUEST_I2C_SUB_IO 0x02
++#define NR_USB_REQUEST_CHANNEL 0x12
+ 
+-static void *rvmalloc(unsigned long size)
++/*
++ * Inserts a specific DisplayLink controller command into the provided
++ * buffer.
++ */
++static char *insert_command(char *buf, u8 reg, u8 val)
+ {
+-	void *mem;
+-	unsigned long adr;
++       *buf++ = 0xAF;
++       *buf++ = 0x20;
++       *buf++ = reg;
++       *buf++ = val;
++       return buf;
++}
+ 
+-	size = PAGE_ALIGN(size);
+-	mem = vmalloc_32(size);
+-	if (!mem)
+-		return NULL;
++static char *insert_vidreg_lock(char *buf)
++{
++       return insert_command(buf, 0xFF, 0x00);
++}
+ 
+-	memset(mem, 0, size);	/* Clear the ram out, no junk to the user */
+-	adr = (unsigned long)mem;
+-	while (size > 0) {
+-		SetPageReserved(vmalloc_to_page((void *)adr));
+-		adr += PAGE_SIZE;
+-		size -= PAGE_SIZE;
++static char *insert_vidreg_unlock(char *buf)
++{
++       return insert_command(buf, 0xFF, 0xFF);
++}
++
++/*
++ * Once you send this command, the DisplayLink framebuffer gets driven to the
++ * display.
++ */
++static char *insert_enable_hvsync(char *buf)
++{
++       return insert_command(buf, 0x1F, 0x00);
++}
++
++static char *insert_set_color_depth(char *buf, u8 selection)
++{
++       return insert_command(buf, 0x00, selection);
++}
++
++static char *insert_set_base16bpp(char *wrptr, u32 base)
++{
++       /* the base pointer is 16 bits wide, 0x20 is hi byte. */
++       wrptr = insert_command(wrptr, 0x20, base >> 16);
++       wrptr = insert_command(wrptr, 0x21, base >> 8);
++       return insert_command(wrptr, 0x22, base);
++}
++
++static char *insert_set_base8bpp(char *wrptr, u32 base)
++{
++       wrptr = insert_command(wrptr, 0x26, base >> 16);
++       wrptr = insert_command(wrptr, 0x27, base >> 8);
++       return insert_command(wrptr, 0x28, base);
++}
++
++static char *insert_command_16(char *wrptr, u8 reg, u16 value)
++{
++       wrptr = insert_command(wrptr, reg, value >> 8);
++       return insert_command(wrptr, reg+1, value);
++}
++
++/*
++ * This is kind of weird because the controller takes some
++ * register values in a different byte order than other registers.
++ */
++static char *insert_command_16be(char *wrptr, u8 reg, u16 value)
++{
++       wrptr = insert_command(wrptr, reg, value);
++       return insert_command(wrptr, reg+1, value >> 8);
++}
++
++/*
++ * LFSR is linear feedback shift register. The reason we have this is
++ * because the display controller needs to minimize the clock depth of
++ * various counters used in the display path. So this code reverses the
++ * provided value into the lfsr16 value by counting backwards to get
++ * the value that needs to be set in the hardware comparator to get the
++ * same actual count. This makes sense once you read above a couple of
++ * times and think about it from a hardware perspective.
++ */
++static u16 lfsr16(u16 actual_count)
++{
++	u32 lv = 0xFFFF; /* This is the lfsr value that the hw starts with */
++
++	while (actual_count--) {
++		lv =	 ((lv << 1) |
++			(((lv >> 15) ^ (lv >> 4) ^ (lv >> 2) ^ (lv >> 1)) & 1))
++			& 0xFFFF;
+ 	}
+ 
+-	return mem;
++	return (u16) lv;
++}
++
++/*
++ * This does LFSR conversion on the value that is to be written.
++ * See LFSR explanation above for more detail.
++ */
++static char *insert_command_lfsr16(char *wrptr, u8 reg, u16 value)
++{
++	return insert_command_16(wrptr, reg, lfsr16(value));
+ }
+ 
+-static void rvfree(void *mem, unsigned long size)
++/*
++ * This takes a standard fbdev screeninfo struct and all of its monitor mode
++ * details and converts them into the DisplayLink equivalent register commands.
++ */
++static char *insert_set_vid_cmds(char *wrptr, struct fb_var_screeninfo *var)
+ {
+-	unsigned long adr;
++	u16 xds, yds;
++	u16 xde, yde;
++	u16 yec;
++
++
++	/* x display start */
++	xds = var->left_margin + var->hsync_len;
++	wrptr = insert_command_lfsr16(wrptr, 0x01, xds);
++	/* x display end */
++	xde = xds + var->xres;
++	wrptr = insert_command_lfsr16(wrptr, 0x03, xde);
++
++	/* y display start */
++	yds = var->upper_margin + var->vsync_len;
++	wrptr = insert_command_lfsr16(wrptr, 0x05, yds);
++	/* y display end */
++	yde = yds + var->yres;
++	wrptr = insert_command_lfsr16(wrptr, 0x07, yde);
++
++	/* x end count is active + blanking - 1 */
++	wrptr = insert_command_lfsr16(wrptr, 0x09, xde + var->right_margin - 1);
++
++	/* libdlo hardcodes hsync start to 1 */
++	wrptr = insert_command_lfsr16(wrptr, 0x0B, 1);
++
++	/* hsync end is width of sync pulse + 1 */
++	wrptr = insert_command_lfsr16(wrptr, 0x0D, var->hsync_len + 1);
++
++	/* hpixels is active pixels */
++	wrptr = insert_command_16(wrptr, 0x0F, var->xres);
+ 
+-	if (!mem)
+-		return;
++	/* yendcount is vertical active + vertical blanking */
++	yec = var->yres + var->upper_margin + var->lower_margin +
++			var->vsync_len;
++	wrptr = insert_command_lfsr16(wrptr, 0x11, yec);
+ 
+-	adr = (unsigned long)mem;
+-	while ((long)size > 0) {
+-		ClearPageReserved(vmalloc_to_page((void *)adr));
+-		adr += PAGE_SIZE;
+-		size -= PAGE_SIZE;
++	/* libdlo hardcodes vsync start to 0 */
++	wrptr = insert_command_lfsr16(wrptr, 0x13, 0);
++
++	/* vsync end is width of vsync pulse */
++	wrptr = insert_command_lfsr16(wrptr, 0x15, var->vsync_len);
++
++	/* vpixels is active pixels */
++	wrptr = insert_command_16(wrptr, 0x17, var->yres);
++
++	/* convert picoseconds to 5kHz multiple for pclk5k = x * 1E12/5k */
++	wrptr = insert_command_16be(wrptr, 0x1B, 200*1000*1000/var->pixclock);
++
++	return wrptr;
++}
++
++/*
++ * This takes a standard fbdev screeninfo struct that was fetched or prepared
++ * and then generates the appropriate command sequence that then drives the
++ * display controller.
++ */
++static int dlfb_set_video_mode(struct dlfb_data *dev,
++				struct fb_var_screeninfo *var)
++{
++	char *buf;
++	char *wrptr;
++	int retval = 0;
++	int writesize;
++
++	buf = dev->buf;
++
++	/*
++	* This first section has to do with setting the base address on the
++	* controller * associated with the display. There are 2 base
++	* pointers, currently, we only * use the 16 bpp segment.
++	*/
++	wrptr = insert_vidreg_lock(buf);
++	wrptr = insert_set_color_depth(wrptr, 0x00);
++	/* set base for 16bpp segment to 0 */
++	wrptr = insert_set_base16bpp(wrptr, 0);
++	/* set base for 8bpp segment to end of fb */
++	wrptr = insert_set_base8bpp(wrptr, dev->info->fix.smem_len);
++
++	wrptr = insert_set_vid_cmds(wrptr, var);
++	wrptr = insert_enable_hvsync(wrptr);
++	wrptr = insert_vidreg_unlock(wrptr);
++
++	writesize = wrptr - buf;
++
++	mutex_lock(&dev->bulk_mutex);
++	if (!dev->interface) {		/* disconnect() was called */
++		mutex_unlock(&dev->bulk_mutex);
++		retval = -ENODEV;
++		goto error;
+ 	}
+-	vfree(mem);
++
++	retval = dlfb_bulk_msg(dev, writesize);
++	mutex_unlock(&dev->bulk_mutex);
++	if (retval) {
++		dev_err(&dev->udev->dev, "Problem %d with submit write bulk.\n",
++					retval);
++		goto error;
++	}
++
++	return 0;
++
++error:
++	return retval;
++}
++
++/*
++ * This is necessary before we can communicate with the display controller.
++ */
++static int dlfb_select_std_channel(struct dlfb_data *dev)
++{
++	int ret;
++	u8 set_def_chn[] = {	   0x57, 0xCD, 0xDC, 0xA7,
++				0x1C, 0x88, 0x5E, 0x15,
++				0x60, 0xFE, 0xC6, 0x97,
++				0x16, 0x3D, 0x47, 0xF2  };
++
++	ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
++			NR_USB_REQUEST_CHANNEL,
++			(USB_DIR_OUT | USB_TYPE_VENDOR), 0, 0,
++			set_def_chn, sizeof(set_def_chn), USB_CTRL_SET_TIMEOUT);
++	return ret;
++}
++
++
++/*
++ * Query EDID from the handware, then hand it off to fbdev's edid parse
++ * routine which should give us back a filled in screeninfo structure.
++ */
++static int dlfb_get_var_from_edid(struct dlfb_data *dev,
++					struct fb_var_screeninfo *var)
++{
++	int ret;
++
++	dlfb_edid(dev);
++	ret = fb_parse_edid(dev->edid, var);
++
++	return ret;
+ }
+ 
+ static int dlfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+@@ -106,12 +326,11 @@ struct dloarea {
+ };
+ 
+ /*
+-static struct usb_device_id id_table [] = {
+-	{ USB_DEVICE(0x17e9, 0x023d) },
+-	{ }
+-};
+-*/
+-
++ * There are many DisplayLink-based products, all with unique PIDs. We are able
++ * to support all volume ones (circa 2009) with a single driver, so we match
++ * globally on VID. TODO: Probe() needs to detect when we might be running
++ * "future" chips, and bail on those, so a compatible driver can match.
++ */
+ static struct usb_device_id id_table[] = {
+ 	{.idVendor = 0x17e9, .match_flags = USB_DEVICE_ID_MATCH_VENDOR,},
+ 	{},
+@@ -205,14 +424,21 @@ image_blit(struct dlfb_data *dev_info, int x, int y, int width, int height,
+ 			if (thistime > 255)
+ 				thistime = 255;
+ 
+-			// find position of first pixel that has changed
+-			firstdiff = -1;
+-			for (j = 0; j < thistime * 2; j++) {
+-				if (dev_info->backing_buffer
+-				    [base - dev_info->base16 + j] != data[j]) {
+-					firstdiff = j / 2;
+-					break;
++			if (dev_info->backing_buffer) {
++				/* find first pixel that has changed */
++				firstdiff = -1;
++				for (j = 0; j < thistime * 2; j++) {
++					if (dev_info->backing_buffer
++					    [base - dev_info->base16 + j]
++					    != data[j]) {
++						firstdiff = j / 2;
++						break;
++					}
+ 				}
++
++			} else {
++				firstdiff = 0;
++
+ 			}
+ 
+ 			if (firstdiff >= 0) {
+@@ -267,8 +493,10 @@ image_blit(struct dlfb_data *dev_info, int x, int y, int width, int height,
+ 			rem -= thistime;
+ 		}
+ 
+-		memcpy(dev_info->backing_buffer + (base - dev_info->base16) -
+-		       (width * 2), data - (width * 2), width * 2);
++		if (dev_info->backing_buffer)
++			memcpy(dev_info->backing_buffer +
++			       (base - dev_info->base16) -
++			       (width * 2), data - (width * 2), width * 2);
+ 
+ 		base += (dev_info->info->var.xres * 2) - (width * 2);
+ 		data += (dev_info->info->var.xres * 2) - (width * 2);
+@@ -313,12 +541,17 @@ draw_rect(struct dlfb_data *dev_info, int x, int y, int width, int height,
+ 
+ 	for (i = y; i < y + height; i++) {
+ 
+-		for (j = 0; j < width * 2; j += 2) {
+-			dev_info->backing_buffer[base - dev_info->base16 + j] =
+-			    (char)(col >> 8);
+-			dev_info->backing_buffer[base - dev_info->base16 + j +
+-						 1] = (char)(col);
++		if (dev_info->backing_buffer) {
++			for (j = 0; j < width * 2; j += 2) {
++				dev_info->backing_buffer
++					[base - dev_info->base16 + j] =
++					(char)(col >> 8);
++				dev_info->backing_buffer
++					[base - dev_info->base16 + j + 1] =
++					(char)(col);
++			}
+ 		}
++
+ 		if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
+ 			ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
+ 			bufptr = dev_info->buf;
+@@ -725,182 +958,196 @@ static struct fb_ops dlfb_ops = {
+ 	.fb_blank = dlfb_blank,
+ };
+ 
+-static int
+-dlfb_probe(struct usb_interface *interface, const struct usb_device_id *id)
++static int dlfb_probe(struct usb_interface *interface,
++			const struct usb_device_id *id)
+ {
+-	struct dlfb_data *dev_info;
++	struct device *mydev;
++	struct usb_device *usbdev;
++	struct dlfb_data *dev;
+ 	struct fb_info *info;
+-
+-	int ret;
+-	char rbuf[4];
+-
+-	dev_info = kzalloc(sizeof(*dev_info), GFP_KERNEL);
+-	if (dev_info == NULL) {
+-		printk("cannot allocate dev_info structure.\n");
+-		return -ENOMEM;
+-	}
+-
+-	mutex_init(&dev_info->bulk_mutex);
+-
+-	dev_info->udev = usb_get_dev(interface_to_usbdev(interface));
+-	dev_info->interface = interface;
+-
+-	printk("DisplayLink device attached\n");
+-
+-	/* add framebuffer info to usb interface */
+-	usb_set_intfdata(interface, dev_info);
+-
+-	dev_info->buf = kmalloc(BUF_SIZE, GFP_KERNEL);
+-	/* usb_buffer_alloc(dev_info->udev, BUF_SIZE , GFP_KERNEL, &dev_info->tx_urb->transfer_dma); */
+-
+-	if (dev_info->buf == NULL) {
+-		printk("unable to allocate memory for dlfb commands\n");
+-		goto out;
++	int videomemorysize;
++	unsigned char *videomemory;
++	int retval = -ENOMEM;
++	struct fb_var_screeninfo *var;
++	struct fb_bitfield red = { 11, 5, 0 };
++	struct fb_bitfield green = { 5, 6, 0 };
++	struct fb_bitfield blue = { 0, 5, 0 };
++
++	usbdev = usb_get_dev(interface_to_usbdev(interface));
++	mydev = &usbdev->dev;
++
++	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
++	if (dev == NULL) {
++		dev_err(mydev, "failed alloc of dev struct\n");
++		goto err_devalloc;
+ 	}
+-	dev_info->bufend = dev_info->buf + BUF_SIZE;
+-
+-	dev_info->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+-	usb_fill_bulk_urb(dev_info->tx_urb, dev_info->udev,
+-			  usb_sndbulkpipe(dev_info->udev, 1), dev_info->buf, 0,
+-			  dlfb_bulk_callback, dev_info);
+-
+-	ret =
+-	    usb_control_msg(dev_info->udev, usb_rcvctrlpipe(dev_info->udev, 0),
+-			    (0x06), (0x80 | (0x02 << 5)), 0, 0, rbuf, 4, 0);
+-	printk("ret control msg 0: %d %x%x%x%x\n", ret, rbuf[0], rbuf[1],
+-	       rbuf[2], rbuf[3]);
+ 
+-	dlfb_edid(dev_info);
+-
+-	info = framebuffer_alloc(sizeof(u32) * 256, &dev_info->udev->dev);
+-
+-	if (!info) {
+-		printk("non posso allocare il framebuffer displaylink");
+-		goto out;
++	mutex_init(&dev->bulk_mutex);
++	dev->udev = usbdev;
++	dev->interface = interface;
++	usb_set_intfdata(interface, dev);
++
++	dev_info(mydev, "dlfb_probe: setting up DisplayLink device\n");
++
++	/*
++	 * TODO: replace single 64K buffer with buffer list
++	 * and async dispatch
++	 */
++	dev->buf = kmalloc(BUF_SIZE, GFP_KERNEL);
++	if (dev->buf == NULL) {
++		dev_err(mydev, "unable to allocate memory for dlfb commands\n");
++		goto err_usballoc;
+ 	}
+-
+-	fb_parse_edid(dev_info->edid, &info->var);
+-
+-	printk("EDID XRES %d YRES %d\n", info->var.xres, info->var.yres);
+-
+-	if (dlfb_set_video_mode(dev_info, info->var.xres, info->var.yres) != 0) {
+-		info->var.xres = 1280;
+-		info->var.yres = 1024;
+-		if (dlfb_set_video_mode
+-		    (dev_info, info->var.xres, info->var.yres) != 0) {
+-			goto out;
+-		}
++	dev->bufend = dev->buf + BUF_SIZE;
++
++	dev->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
++	usb_fill_bulk_urb(dev->tx_urb, dev->udev,
++			  usb_sndbulkpipe(dev->udev, 1), dev->buf, 0,
++			  dlfb_bulk_callback, dev);
++
++	/* allocates framebuffer driver structure, not framebuffer memory */
++	info = framebuffer_alloc(0, mydev);
++	if (!info)
++		goto err_fballoc;
++
++	dev->info = info;
++	info->par = dev;
++	info->pseudo_palette = dev->pseudo_palette;
++
++	var = &info->var;
++	retval = dlfb_get_var_from_edid(dev, var);
++	if (retval) {
++		/* had a problem getting edid. so fallback to 640x480 */
++		dev_err(mydev, "Problem %d with EDID.\n", retval);
++		var->xres = 640;
++		var->yres = 480;
+ 	}
+ 
+-	printk("found valid mode...%d\n", info->var.pixclock);
+-
+-	info->pseudo_palette = info->par;
+-	info->par = dev_info;
+-
+-	dev_info->info = info;
+-
++	/*
++	 * ok, now that we've got the size info, we can alloc our framebuffer.
++	 * We are using 16bpp.
++	 */
++	info->var.bits_per_pixel = 16;
++	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.
++	 * Pages don't need to be set RESERVED (non-swap) immediately on 2.6
++	 * remap_pfn_page() syscall in our mmap and/or defio will handle.
++	 */
++	videomemory = vmalloc(videomemorysize);
++	if (!videomemory)
++		goto err_vidmem;
++	memset(videomemory, 0, videomemorysize);
++
++	info->screen_base = videomemory;
++	info->fix.smem_len = PAGE_ALIGN(videomemorysize);
++	info->fix.smem_start = (unsigned long) videomemory;
+ 	info->flags =
+ 	    FBINFO_DEFAULT | FBINFO_READS_FAST | FBINFO_HWACCEL_IMAGEBLIT |
+ 	    FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
+-	info->fbops = &dlfb_ops;
+-	info->screen_base = rvmalloc(dev_info->screen_size);
+ 
+-	if (info->screen_base == NULL) {
+-		printk
+-		    ("cannot allocate framebuffer virtual memory of %d bytes\n",
+-		     dev_info->screen_size);
+-		goto out0;
+-	}
+-
+-	printk("screen base allocated !!!\n");
+-
+-	dev_info->backing_buffer = kzalloc(dev_info->screen_size, GFP_KERNEL);
+-
+-	if (!dev_info->backing_buffer)
+-		printk("non posso allocare il backing buffer\n");
++	/*
++	 * 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(dev->screen_size);
++	if (!dev->backing_buffer)
++		dev_info(mydev, "No backing buffer allocated!\n");
+ 
+-	/* info->var = dev_info->si; */
+-
+-	info->var.bits_per_pixel = 16;
+-	info->var.activate = FB_ACTIVATE_TEST;
+-	info->var.vmode = FB_VMODE_NONINTERLACED;
++	info->fbops = &dlfb_ops;
+ 
+-	info->var.red.offset = 11;
+-	info->var.red.length = 5;
+-	info->var.red.msb_right = 0;
++	var->vmode = FB_VMODE_NONINTERLACED;
++	var->red = red;
++	var->green = green;
++	var->blue = blue;
+ 
+-	info->var.green.offset = 5;
+-	info->var.green.length = 6;
+-	info->var.green.msb_right = 0;
++	/*
++	 * TODO: Enable FB_CONFIG_DEFIO support
+ 
+-	info->var.blue.offset = 0;
+-	info->var.blue.length = 5;
+-	info->var.blue.msb_right = 0;
++	 info->fbdefio = &dlfb_defio;
++	 fb_deferred_io_init(info);
+ 
+-	/* info->var.pixclock =  (10000000 / FB_W * 1000 / FB_H)/2 ; */
++	 */
+ 
+-	info->fix.smem_start = (unsigned long)info->screen_base;
+-	info->fix.smem_len = PAGE_ALIGN(dev_info->screen_size);
+-	if (strlen(dev_info->udev->product) > 15) {
+-		memcpy(info->fix.id, dev_info->udev->product, 15);
+-	} else {
+-		memcpy(info->fix.id, dev_info->udev->product,
+-		       strlen(dev_info->udev->product));
++	retval = fb_alloc_cmap(&info->cmap, 256, 0);
++	if (retval < 0) {
++		dev_err(mydev, "Failed to allocate colormap\n");
++		goto err_cmap;
+ 	}
+-	info->fix.type = FB_TYPE_PACKED_PIXELS;
+-	info->fix.visual = FB_VISUAL_TRUECOLOR;
+-	info->fix.accel = info->flags;
+-	info->fix.line_length = dev_info->line_length;
+ 
+-	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
+-		goto out1;
++	dlfb_select_std_channel(dev);
++	dlfb_set_video_mode(dev, var);
++	/* TODO: dlfb_dpy_update(dev); */
+ 
+-	printk("colormap allocated\n");
+-	if (register_framebuffer(info) < 0)
+-		goto out2;
++	retval = register_framebuffer(info);
++	if (retval < 0)
++		goto err_regfb;
+ 
+-	draw_rect(dev_info, 0, 0, dev_info->info->var.xres,
+-		  dev_info->info->var.yres, 0x30, 0xff, 0x30);
++	/* paint "successful" green screen */
++	draw_rect(dev, 0, 0, dev->info->var.xres,
++		  dev->info->var.yres, 0x30, 0xff, 0x30);
+ 
++	dev_info(mydev, "DisplayLink USB device %d now attached, "
++			"using %dK of memory\n", info->node,
++		 ((dev->backing_buffer) ?
++		  videomemorysize * 2 : videomemorysize) >> 10);
+ 	return 0;
+ 
+-out2:
++err_regfb:
+ 	fb_dealloc_cmap(&info->cmap);
+-out1:
+-	rvfree(info->screen_base, dev_info->screen_size);
+-out0:
++err_cmap:
++	/* TODO: fb_deferred_io_cleanup(info); */
++	vfree(videomemory);
++err_vidmem:
+ 	framebuffer_release(info);
+-out:
++err_fballoc:
++	kfree(dev->buf);
++err_usballoc:
+ 	usb_set_intfdata(interface, NULL);
+-	usb_put_dev(dev_info->udev);
+-	kfree(dev_info);
+-	return -ENOMEM;
+-
++	usb_put_dev(dev->udev);
++	kfree(dev);
++err_devalloc:
++	return retval;
+ }
+ 
+ static void dlfb_disconnect(struct usb_interface *interface)
+ {
+-	struct dlfb_data *dev_info = usb_get_intfdata(interface);
+-
+-	mutex_unlock(&dev_info->bulk_mutex);
++	struct dlfb_data *dev;
++	struct fb_info *info;
+ 
+-	usb_kill_urb(dev_info->tx_urb);
+-	usb_free_urb(dev_info->tx_urb);
++	dev = usb_get_intfdata(interface);
+ 	usb_set_intfdata(interface, NULL);
+-	usb_put_dev(dev_info->udev);
+-
+-	if (dev_info->info) {
+-		unregister_framebuffer(dev_info->info);
+-		fb_dealloc_cmap(&dev_info->info->cmap);
+-		rvfree(dev_info->info->screen_base, dev_info->screen_size);
+-		kfree(dev_info->backing_buffer);
+-		framebuffer_release(dev_info->info);
+-
++	usb_put_dev(dev->udev);
++
++	/*
++	 * TODO: since, upon usb disconnect(), usb will cancel in-flight urbs
++	 * and error out any new ones, look at eliminating need for mutex
++	 */
++	mutex_lock(&dev->bulk_mutex);
++	dev->interface = NULL;
++	info = dev->info;
++	mutex_unlock(&dev->bulk_mutex);
++
++	if (info) {
++		dev_info(&interface->dev, "Detaching DisplayLink device %d.\n",
++						info->node);
++		unregister_framebuffer(info);
++		fb_dealloc_cmap(&info->cmap);
++		/* TODO: fb_deferred_io_cleanup(info); */
++		fb_dealloc_cmap(&info->cmap);
++		vfree((void __force *)info->screen_base);
++		framebuffer_release(info);
+ 	}
+ 
+-	kfree(dev_info);
++	if (dev->backing_buffer)
++		vfree(dev->backing_buffer);
+ 
+-	printk("DisplayLink device disconnected\n");
++	kfree(dev);
+ }
+ 
+ static struct usb_driver dlfb_driver = {
+@@ -914,8 +1161,6 @@ static int __init dlfb_init(void)
+ {
+ 	int res;
+ 
+-	dlfb_init_modes();
+-
+ 	res = usb_register(&dlfb_driver);
+ 	if (res)
+ 		err("usb_register failed. Error number %d", res);
+@@ -933,6 +1178,7 @@ static void __exit dlfb_exit(void)
+ module_init(dlfb_init);
+ module_exit(dlfb_exit);
+ 
+-MODULE_AUTHOR("Roberto De Ioris <roberto at unbit.it>");
++MODULE_AUTHOR("Roberto De Ioris <roberto at unbit.it>, "
++	      "Jaya Kumar <jayakumar.lkml at gmail.com>");
+ MODULE_DESCRIPTION(DRIVER_VERSION);
+ MODULE_LICENSE("GPL");
+diff --git a/drivers/staging/udlfb/udlfb.h b/drivers/staging/udlfb/udlfb.h
+index 40ad85e..cdf91d0 100644
+--- a/drivers/staging/udlfb/udlfb.h
++++ b/drivers/staging/udlfb/udlfb.h
+@@ -1,12 +1,6 @@
+ #ifndef UDLFB_H
+ #define UDLFB_H
+ 
+-#define MAX_VMODES	4
+-#define FB_BPP		16
+-
+-#define STD_CHANNEL	"\x57\xCD\xDC\xA7\x1C\x88\x5E\x15"	\
+-			"\x60\xFE\xC6\x97\x16\x3D\x47\xF2"
+-
+ /* as libdlo */
+ #define BUF_HIGH_WATER_MARK	1024
+ #define BUF_SIZE		(64*1024)
+@@ -29,21 +23,9 @@ struct dlfb_data {
+ 	int base16d;
+ 	int base8;
+ 	int base8d;
++	u32 pseudo_palette[256];
+ };
+ 
+-struct dlfb_video_mode {
+-	uint8_t col;
+-	uint32_t hclock;
+-	uint32_t vclock;
+-	uint8_t unknown1[6];
+-	uint16_t xres;
+-	uint8_t unknown2[6];
+-	uint16_t yres;
+-	uint8_t unknown3[4];
+-} __attribute__ ((__packed__));
+-
+-static struct dlfb_video_mode dlfb_video_modes[MAX_VMODES];
+-
+ static void dlfb_bulk_callback(struct urb *urb)
+ {
+ 	struct dlfb_data *dev_info = urb->context;
+@@ -86,140 +68,6 @@ static int dlfb_bulk_msg(struct dlfb_data *dev_info, int len)
+ 	return dev_info->tx_urb->actual_length;
+ }
+ 
+-static void dlfb_init_modes(void)
+-{
+-	dlfb_video_modes[0].col = 0;
+-	memcpy(&dlfb_video_modes[0].hclock, "\x20\x3C\x7A\xC9", 4);
+-	memcpy(&dlfb_video_modes[0].vclock, "\xF2\x6C\x48\xF9", 4);
+-	memcpy(&dlfb_video_modes[0].unknown1, "\x70\x53\xFF\xFF\x21\x27", 6);
+-	dlfb_video_modes[0].xres = 800;
+-	memcpy(&dlfb_video_modes[0].unknown2, "\x91\xF3\xFF\xFF\xFF\xF9", 6);
+-	dlfb_video_modes[0].yres = 480;
+-	memcpy(&dlfb_video_modes[0].unknown3, "\x01\x02\xC8\x19", 4);
+-
+-	dlfb_video_modes[1].col = 0;
+-	memcpy(&dlfb_video_modes[1].hclock, "\x36\x18\xD5\x10", 4);
+-	memcpy(&dlfb_video_modes[1].vclock, "\x60\xA9\x7B\x33", 4);
+-	memcpy(&dlfb_video_modes[1].unknown1, "\xA1\x2B\x27\x32\xFF\xFF", 6);
+-	dlfb_video_modes[1].xres = 1024;
+-	memcpy(&dlfb_video_modes[1].unknown2, "\xD9\x9A\xFF\xCA\xFF\xFF", 6);
+-	dlfb_video_modes[1].yres = 768;
+-	memcpy(&dlfb_video_modes[1].unknown3, "\x04\x03\xC8\x32", 4);
+-
+-	dlfb_video_modes[2].col = 0;
+-	memcpy(&dlfb_video_modes[2].hclock, "\x98\xF8\x0D\x57", 4);
+-	memcpy(&dlfb_video_modes[2].vclock, "\x2A\x55\x4D\x54", 4);
+-	memcpy(&dlfb_video_modes[2].unknown1, "\xCA\x0D\xFF\xFF\x94\x43", 6);
+-	dlfb_video_modes[2].xres = 1280;
+-	memcpy(&dlfb_video_modes[2].unknown2, "\x9A\xA8\xFF\xFF\xFF\xF9", 6);
+-	dlfb_video_modes[2].yres = 1024;
+-	memcpy(&dlfb_video_modes[2].unknown3, "\x04\x02\x60\x54", 4);
+-
+-	dlfb_video_modes[3].col = 0;
+-	memcpy(&dlfb_video_modes[3].hclock, "\x42\x24\x38\x36", 4);
+-	memcpy(&dlfb_video_modes[3].vclock, "\xC1\x52\xD9\x29", 4);
+-	memcpy(&dlfb_video_modes[3].unknown1, "\xEA\xB8\x32\x60\xFF\xFF", 6);
+-	dlfb_video_modes[3].xres = 1400;
+-	memcpy(&dlfb_video_modes[3].unknown2, "\xC9\x4E\xFF\xFF\xFF\xF2", 6);
+-	dlfb_video_modes[3].yres = 1050;
+-	memcpy(&dlfb_video_modes[3].unknown3, "\x04\x02\x1E\x5F", 4);
+-}
+-
+-static char *dlfb_set_register(char *bufptr, uint8_t reg, uint8_t val)
+-{
+-	*bufptr++ = 0xAF;
+-	*bufptr++ = 0x20;
+-	*bufptr++ = reg;
+-	*bufptr++ = val;
+-
+-	return bufptr;
+-}
+-
+-static int dlfb_set_video_mode(struct dlfb_data *dev_info, int width, int height)
+-{
+-	int i, ret;
+-	unsigned char j;
+-	char *bufptr = dev_info->buf;
+-	uint8_t *vdata;
+-
+-	for (i = 0; i < MAX_VMODES; i++) {
+-		printk("INIT VIDEO %d %d %d\n", i, dlfb_video_modes[i].xres,
+-		       dlfb_video_modes[i].yres);
+-		if (dlfb_video_modes[i].xres == width
+-		    && dlfb_video_modes[i].yres == height) {
+-
+-			dev_info->base16 = 0;
+-			dev_info->base16d = width * height * (FB_BPP / 8);
+-
+-			//dev_info->base8 = width * height * (FB_BPP / 8);
+-
+-			dev_info->base8 = dev_info->base16;
+-			dev_info->base8d = dev_info->base16d;
+-
+-			/* set encryption key (null) */
+-			memcpy(dev_info->buf, STD_CHANNEL, 16);
+-			ret =
+-			    usb_control_msg(dev_info->udev,
+-					    usb_sndctrlpipe(dev_info->udev, 0),
+-					    0x12, (0x02 << 5), 0, 0,
+-					    dev_info->buf, 16, 0);
+-			printk("ret control msg 1 (STD_CHANNEL): %d\n", ret);
+-
+-			/* set registers */
+-			bufptr = dlfb_set_register(bufptr, 0xFF, 0x00);
+-
+-			/* set color depth */
+-			bufptr = dlfb_set_register(bufptr, 0x00, 0x00);
+-
+-			/* set addresses */
+-			bufptr =
+-			    dlfb_set_register(bufptr, 0x20,
+-					      (char)(dev_info->base16 >> 16));
+-			bufptr =
+-			    dlfb_set_register(bufptr, 0x21,
+-					      (char)(dev_info->base16 >> 8));
+-			bufptr =
+-			    dlfb_set_register(bufptr, 0x22,
+-					      (char)(dev_info->base16));
+-
+-			bufptr =
+-			    dlfb_set_register(bufptr, 0x26,
+-					      (char)(dev_info->base8 >> 16));
+-			bufptr =
+-			    dlfb_set_register(bufptr, 0x27,
+-					      (char)(dev_info->base8 >> 8));
+-			bufptr =
+-			    dlfb_set_register(bufptr, 0x28,
+-					      (char)(dev_info->base8));
+-
+-			/* set video mode */
+-			vdata = (uint8_t *)&dlfb_video_modes[i];
+-			for (j = 0; j < 29; j++)
+-				bufptr = dlfb_set_register(bufptr, j, vdata[j]);
+-
+-			/* blank */
+-			bufptr = dlfb_set_register(bufptr, 0x1F, 0x00);
+-
+-			/* end registers */
+-			bufptr = dlfb_set_register(bufptr, 0xFF, 0xFF);
+-
+-			/* send */
+-			ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
+-			printk("ret bulk 2: %d %td\n", ret,
+-			       bufptr - dev_info->buf);
+-
+-			/* flush */
+-			ret = dlfb_bulk_msg(dev_info, 0);
+-			printk("ret bulk 3: %d\n", ret);
+-
+-			dev_info->screen_size = width * height * (FB_BPP / 8);
+-			dev_info->line_length = width * (FB_BPP / 8);
+-
+-			return 0;
+-		}
+-	}
+-
+-	return -1;
+-}
++#define dlfb_set_register insert_command
+ 
+ #endif

Added: dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-checkpatch-cleanup.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-cleanup.patch	Mon Jul  5 17:35:21 2010	(r15941)
@@ -0,0 +1,223 @@
+From: Bernie Thompson <bernie at plugable.com>
+Date: Mon, 15 Feb 2010 14:45:43 +0000 (-0800)
+Subject: Staging: udlfb: checkpatch cleanup
+X-Git-Tag: v2.6.34-rc1~10^2~1^2~75
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=1d31a9ee698f9b8d72c5813fe62a5184197443c3
+
+Staging: udlfb: checkpatch cleanup
+
+Eliminate checkpatch.pl warnings and errors so later patches in series are clean
+
+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 b61a3e5..d2adfe4 100644
+--- a/drivers/staging/udlfb/udlfb.c
++++ b/drivers/staging/udlfb/udlfb.c
+@@ -30,13 +30,13 @@
+ #define DRIVER_VERSION "DisplayLink Framebuffer Driver 0.4.1"
+ 
+ static struct fb_fix_screeninfo dlfb_fix = {
+-       .id =           "displaylinkfb",
+-       .type =         FB_TYPE_PACKED_PIXELS,
+-       .visual =       FB_VISUAL_TRUECOLOR,
+-       .xpanstep =     0,
+-       .ypanstep =     0,
+-       .ywrapstep =    0,
+-       .accel =        FB_ACCEL_NONE,
++	.id =           "displaylinkfb",
++	.type =         FB_TYPE_PACKED_PIXELS,
++	.visual =       FB_VISUAL_TRUECOLOR,
++	.xpanstep =     0,
++	.ypanstep =     0,
++	.ywrapstep =    0,
++	.accel =        FB_ACCEL_NONE,
+ };
+ 
+ #define NR_USB_REQUEST_I2C_SUB_IO 0x02
+@@ -48,21 +48,21 @@ static struct fb_fix_screeninfo dlfb_fix = {
+  */
+ static char *insert_command(char *buf, u8 reg, u8 val)
+ {
+-       *buf++ = 0xAF;
+-       *buf++ = 0x20;
+-       *buf++ = reg;
+-       *buf++ = val;
+-       return buf;
++	*buf++ = 0xAF;
++	*buf++ = 0x20;
++	*buf++ = reg;
++	*buf++ = val;
++	return buf;
+ }
+ 
+ static char *insert_vidreg_lock(char *buf)
+ {
+-       return insert_command(buf, 0xFF, 0x00);
++	return insert_command(buf, 0xFF, 0x00);
+ }
+ 
+ static char *insert_vidreg_unlock(char *buf)
+ {
+-       return insert_command(buf, 0xFF, 0xFF);
++	return insert_command(buf, 0xFF, 0xFF);
+ }
+ 
+ /*
+@@ -71,33 +71,33 @@ static char *insert_vidreg_unlock(char *buf)
+  */
+ static char *insert_enable_hvsync(char *buf)
+ {
+-       return insert_command(buf, 0x1F, 0x00);
++	return insert_command(buf, 0x1F, 0x00);
+ }
+ 
+ static char *insert_set_color_depth(char *buf, u8 selection)
+ {
+-       return insert_command(buf, 0x00, selection);
++	return insert_command(buf, 0x00, selection);
+ }
+ 
+ static char *insert_set_base16bpp(char *wrptr, u32 base)
+ {
+-       /* the base pointer is 16 bits wide, 0x20 is hi byte. */
+-       wrptr = insert_command(wrptr, 0x20, base >> 16);
+-       wrptr = insert_command(wrptr, 0x21, base >> 8);
+-       return insert_command(wrptr, 0x22, base);
++	/* the base pointer is 16 bits wide, 0x20 is hi byte. */
++	wrptr = insert_command(wrptr, 0x20, base >> 16);
++	wrptr = insert_command(wrptr, 0x21, base >> 8);
++	return insert_command(wrptr, 0x22, base);
+ }
+ 
+ static char *insert_set_base8bpp(char *wrptr, u32 base)
+ {
+-       wrptr = insert_command(wrptr, 0x26, base >> 16);
+-       wrptr = insert_command(wrptr, 0x27, base >> 8);
+-       return insert_command(wrptr, 0x28, base);
++	wrptr = insert_command(wrptr, 0x26, base >> 16);
++	wrptr = insert_command(wrptr, 0x27, base >> 8);
++	return insert_command(wrptr, 0x28, base);
+ }
+ 
+ static char *insert_command_16(char *wrptr, u8 reg, u16 value)
+ {
+-       wrptr = insert_command(wrptr, reg, value >> 8);
+-       return insert_command(wrptr, reg+1, value);
++	wrptr = insert_command(wrptr, reg, value >> 8);
++	return insert_command(wrptr, reg+1, value);
+ }
+ 
+ /*
+@@ -106,8 +106,8 @@ static char *insert_command_16(char *wrptr, u8 reg, u16 value)
+  */
+ static char *insert_command_16be(char *wrptr, u8 reg, u16 value)
+ {
+-       wrptr = insert_command(wrptr, reg, value);
+-       return insert_command(wrptr, reg+1, value >> 8);
++	wrptr = insert_command(wrptr, reg, value);
++	return insert_command(wrptr, reg+1, value >> 8);
+ }
+ 
+ /*
+@@ -339,7 +339,7 @@ MODULE_DEVICE_TABLE(usb, id_table);
+ 
+ static struct usb_driver dlfb_driver;
+ 
+-// thanks to Henrik Bjerregaard Pedersen for this function
++/* thanks to Henrik Bjerregaard Pedersen for this function */
+ static char *rle_compress16(uint16_t * src, char *dst, int rem)
+ {
+ 
+@@ -347,7 +347,7 @@ static char *rle_compress16(uint16_t * src, char *dst, int rem)
+ 	uint16_t pix0;
+ 	char *end_if_raw = dst + 6 + 2 * rem;
+ 
+-	dst += 6;		// header will be filled in if RLE is worth it
++	dst += 6; /* header will be filled in if RLE is worth it */
+ 
+ 	while (rem && dst < end_if_raw) {
+ 		char *start = (char *)src;
+@@ -366,8 +366,8 @@ static char *rle_compress16(uint16_t * src, char *dst, int rem)
+ }
+ 
+ /*
+-Thanks to Henrik Bjerregaard Pedersen for rle implementation and code refactoring.
+-Next step is huffman compression.
++Thanks to Henrik Bjerregaard Pedersen for rle implementation
++and code refactoring. Next step is huffman compression.
+ */
+ 
+ static int
+@@ -419,7 +419,7 @@ image_blit(struct dlfb_data *dev_info, int x, int y, int width, int height,
+ 						  bufptr - dev_info->buf);
+ 				bufptr = dev_info->buf;
+ 			}
+-			// number of pixels to consider this time
++			/* number of pixels to consider this time */
+ 			thistime = rem;
+ 			if (thistime > 255)
+ 				thistime = 255;
+@@ -467,7 +467,7 @@ image_blit(struct dlfb_data *dev_info, int x, int y, int width, int height,
+ 					bufptr = end_of_rle;
+ 
+ 				} else {
+-					// fallback to raw (or some other encoding?)
++					/* fallback to raw (or other?) */
+ 					*bufptr++ = 0xAF;
+ 					*bufptr++ = 0x68;
+ 
+@@ -479,7 +479,6 @@ image_blit(struct dlfb_data *dev_info, int x, int y, int width, int height,
+ 					*bufptr++ =
+ 					    (char)(base + firstdiff * 2);
+ 					*bufptr++ = thistime - firstdiff;
+-					// PUT COMPRESSION HERE
+ 					for (j = firstdiff * 2;
+ 					     j < thistime * 2; j += 2) {
+ 						*bufptr++ = data[j + 1];
+@@ -621,7 +620,7 @@ static void swapfb(struct dlfb_data *dev_info)
+ 
+ 	bufptr = dlfb_set_register(bufptr, 0xFF, 0x00);
+ 
+-	// set addresses
++	/* set addresses */
+ 	bufptr =
+ 	    dlfb_set_register(bufptr, 0x20, (char)(dev_info->base16 >> 16));
+ 	bufptr = dlfb_set_register(bufptr, 0x21, (char)(dev_info->base16 >> 8));
+@@ -803,9 +802,6 @@ static void dlfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+ 
+ 	copyarea(dev, area->dx, area->dy, area->sx, area->sy, area->width,
+ 		 area->height);
+-
+-	/* printk("COPY AREA %d %d %d %d %d %d !!!\n", area->dx, area->dy, area->sx, area->sy, area->width, area->height); */
+-
+ }
+ 
+ static void dlfb_imageblit(struct fb_info *info, const struct fb_image *image)
+@@ -813,12 +809,10 @@ static void dlfb_imageblit(struct fb_info *info, const struct fb_image *image)
+ 
+ 	int ret;
+ 	struct dlfb_data *dev = info->par;
+-	/* printk("IMAGE BLIT (1) %d %d %d %d DEPTH %d {%p}!!!\n", image->dx, image->dy, image->width, image->height, image->depth, dev->udev); */
+ 	cfb_imageblit(info, image);
+ 	ret =
+ 	    image_blit(dev, image->dx, image->dy, image->width, image->height,
+ 		       info->screen_base);
+-	/* printk("IMAGE BLIT (2) %d %d %d %d DEPTH %d {%p} %d!!!\n", image->dx, image->dy, image->width, image->height, image->depth, dev->udev, ret); */
+ }
+ 
+ static void dlfb_fillrect(struct fb_info *info,
+diff --git a/drivers/staging/udlfb/udlfb.h b/drivers/staging/udlfb/udlfb.h
+index cdf91d0..245234b 100644
+--- a/drivers/staging/udlfb/udlfb.h
++++ b/drivers/staging/udlfb/udlfb.h
+@@ -44,7 +44,6 @@ static void dlfb_edid(struct dlfb_data *dev_info)
+ 				    usb_rcvctrlpipe(dev_info->udev, 0), (0x02),
+ 				    (0x80 | (0x02 << 5)), i << 8, 0xA1, rbuf, 2,
+ 				    0);
+-		/*printk("ret control msg edid %d: %d [%d]\n",i, ret, rbuf[1]); */
+ 		dev_info->edid[i] = rbuf[1];
+ 	}
+ 

Added: dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-cleanup-function-naming.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-cleanup-function-naming.patch	Mon Jul  5 17:35:21 2010	(r15941)
@@ -0,0 +1,323 @@
+From: Bernie Thompson <bernie at plugable.com>
+Date: Mon, 15 Feb 2010 14:46:04 +0000 (-0800)
+Subject: Staging: udlfb: clean up function naming
+X-Git-Tag: v2.6.34-rc1~10^2~1^2~72
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=4574203f45eb26b3fd76a171a77dd298dc1dc1ae
+
+Staging: udlfb: clean up function naming
+
+Move to more consistent naming scheme
+
+All udlfb functions start with udlfb_
+All functions for udlfb's fbdev interface start with udlfb_ops_
+All functinos for udlfb's usb interface start with udlfb_usb_
+
+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 592b185..8d8372f 100644
+--- a/drivers/staging/udlfb/udlfb.c
++++ b/drivers/staging/udlfb/udlfb.c
+@@ -62,7 +62,7 @@ static void dlfb_free_urb_list(struct dlfb_data *dev);
+  * Inserts a specific DisplayLink controller command into the provided
+  * buffer.
+  */
+-static char *insert_command(char *buf, u8 reg, u8 val)
++static char *dlfb_set_register(char *buf, u8 reg, u8 val)
+ {
+ 	*buf++ = 0xAF;
+ 	*buf++ = 0x20;
+@@ -71,59 +71,59 @@ static char *insert_command(char *buf, u8 reg, u8 val)
+ 	return buf;
+ }
+ 
+-static char *insert_vidreg_lock(char *buf)
++static char *dlfb_vidreg_lock(char *buf)
+ {
+-	return insert_command(buf, 0xFF, 0x00);
++	return dlfb_set_register(buf, 0xFF, 0x00);
+ }
+ 
+-static char *insert_vidreg_unlock(char *buf)
++static char *dlfb_vidreg_unlock(char *buf)
+ {
+-	return insert_command(buf, 0xFF, 0xFF);
++	return dlfb_set_register(buf, 0xFF, 0xFF);
+ }
+ 
+ /*
+  * Once you send this command, the DisplayLink framebuffer gets driven to the
+  * display.
+  */
+-static char *insert_enable_hvsync(char *buf)
++static char *dlfb_enable_hvsync(char *buf)
+ {
+-	return insert_command(buf, 0x1F, 0x00);
++	return dlfb_set_register(buf, 0x1F, 0x00);
+ }
+ 
+-static char *insert_set_color_depth(char *buf, u8 selection)
++static char *dlfb_set_color_depth(char *buf, u8 selection)
+ {
+-	return insert_command(buf, 0x00, selection);
++	return dlfb_set_register(buf, 0x00, selection);
+ }
+ 
+-static char *insert_set_base16bpp(char *wrptr, u32 base)
++static char *dlfb_set_base16bpp(char *wrptr, u32 base)
+ {
+ 	/* the base pointer is 16 bits wide, 0x20 is hi byte. */
+-	wrptr = insert_command(wrptr, 0x20, base >> 16);
+-	wrptr = insert_command(wrptr, 0x21, base >> 8);
+-	return insert_command(wrptr, 0x22, base);
++	wrptr = dlfb_set_register(wrptr, 0x20, base >> 16);
++	wrptr = dlfb_set_register(wrptr, 0x21, base >> 8);
++	return dlfb_set_register(wrptr, 0x22, base);
+ }
+ 
+-static char *insert_set_base8bpp(char *wrptr, u32 base)
++static char *dlfb_set_base8bpp(char *wrptr, u32 base)
+ {
+-	wrptr = insert_command(wrptr, 0x26, base >> 16);
+-	wrptr = insert_command(wrptr, 0x27, base >> 8);
+-	return insert_command(wrptr, 0x28, base);
++	wrptr = dlfb_set_register(wrptr, 0x26, base >> 16);
++	wrptr = dlfb_set_register(wrptr, 0x27, base >> 8);
++	return dlfb_set_register(wrptr, 0x28, base);
+ }
+ 
+-static char *insert_command_16(char *wrptr, u8 reg, u16 value)
++static char *dlfb_set_register_16(char *wrptr, u8 reg, u16 value)
+ {
+-	wrptr = insert_command(wrptr, reg, value >> 8);
+-	return insert_command(wrptr, reg+1, value);
++	wrptr = dlfb_set_register(wrptr, reg, value >> 8);
++	return dlfb_set_register(wrptr, reg+1, value);
+ }
+ 
+ /*
+  * This is kind of weird because the controller takes some
+  * register values in a different byte order than other registers.
+  */
+-static char *insert_command_16be(char *wrptr, u8 reg, u16 value)
++static char *dlfb_set_register_16be(char *wrptr, u8 reg, u16 value)
+ {
+-	wrptr = insert_command(wrptr, reg, value);
+-	return insert_command(wrptr, reg+1, value >> 8);
++	wrptr = dlfb_set_register(wrptr, reg, value);
++	return dlfb_set_register(wrptr, reg+1, value >> 8);
+ }
+ 
+ /*
+@@ -152,64 +152,65 @@ static u16 lfsr16(u16 actual_count)
+  * This does LFSR conversion on the value that is to be written.
+  * See LFSR explanation above for more detail.
+  */
+-static char *insert_command_lfsr16(char *wrptr, u8 reg, u16 value)
++static char *dlfb_set_register_lfsr16(char *wrptr, u8 reg, u16 value)
+ {
+-	return insert_command_16(wrptr, reg, lfsr16(value));
++	return dlfb_set_register_16(wrptr, reg, lfsr16(value));
+ }
+ 
+ /*
+  * This takes a standard fbdev screeninfo struct and all of its monitor mode
+  * details and converts them into the DisplayLink equivalent register commands.
+  */
+-static char *insert_set_vid_cmds(char *wrptr, struct fb_var_screeninfo *var)
++static char *dlfb_set_vid_cmds(char *wrptr, struct fb_var_screeninfo *var)
+ {
+ 	u16 xds, yds;
+ 	u16 xde, yde;
+ 	u16 yec;
+ 
+-
+ 	/* x display start */
+ 	xds = var->left_margin + var->hsync_len;
+-	wrptr = insert_command_lfsr16(wrptr, 0x01, xds);
++	wrptr = dlfb_set_register_lfsr16(wrptr, 0x01, xds);
+ 	/* x display end */
+ 	xde = xds + var->xres;
+-	wrptr = insert_command_lfsr16(wrptr, 0x03, xde);
++	wrptr = dlfb_set_register_lfsr16(wrptr, 0x03, xde);
+ 
+ 	/* y display start */
+ 	yds = var->upper_margin + var->vsync_len;
+-	wrptr = insert_command_lfsr16(wrptr, 0x05, yds);
++	wrptr = dlfb_set_register_lfsr16(wrptr, 0x05, yds);
+ 	/* y display end */
+ 	yde = yds + var->yres;
+-	wrptr = insert_command_lfsr16(wrptr, 0x07, yde);
++	wrptr = dlfb_set_register_lfsr16(wrptr, 0x07, yde);
+ 
+ 	/* x end count is active + blanking - 1 */
+-	wrptr = insert_command_lfsr16(wrptr, 0x09, xde + var->right_margin - 1);
++	wrptr = dlfb_set_register_lfsr16(wrptr, 0x09,
++			xde + var->right_margin - 1);
+ 
+ 	/* libdlo hardcodes hsync start to 1 */
+-	wrptr = insert_command_lfsr16(wrptr, 0x0B, 1);
++	wrptr = dlfb_set_register_lfsr16(wrptr, 0x0B, 1);
+ 
+ 	/* hsync end is width of sync pulse + 1 */
+-	wrptr = insert_command_lfsr16(wrptr, 0x0D, var->hsync_len + 1);
++	wrptr = dlfb_set_register_lfsr16(wrptr, 0x0D, var->hsync_len + 1);
+ 
+ 	/* hpixels is active pixels */
+-	wrptr = insert_command_16(wrptr, 0x0F, var->xres);
++	wrptr = dlfb_set_register_16(wrptr, 0x0F, var->xres);
+ 
+ 	/* yendcount is vertical active + vertical blanking */
+ 	yec = var->yres + var->upper_margin + var->lower_margin +
+ 			var->vsync_len;
+-	wrptr = insert_command_lfsr16(wrptr, 0x11, yec);
++	wrptr = dlfb_set_register_lfsr16(wrptr, 0x11, yec);
+ 
+ 	/* libdlo hardcodes vsync start to 0 */
+-	wrptr = insert_command_lfsr16(wrptr, 0x13, 0);
++	wrptr = dlfb_set_register_lfsr16(wrptr, 0x13, 0);
+ 
+ 	/* vsync end is width of vsync pulse */
+-	wrptr = insert_command_lfsr16(wrptr, 0x15, var->vsync_len);
++	wrptr = dlfb_set_register_lfsr16(wrptr, 0x15, var->vsync_len);
+ 
+ 	/* vpixels is active pixels */
+-	wrptr = insert_command_16(wrptr, 0x17, var->yres);
++	wrptr = dlfb_set_register_16(wrptr, 0x17, var->yres);
+ 
+ 	/* convert picoseconds to 5kHz multiple for pclk5k = x * 1E12/5k */
+-	wrptr = insert_command_16be(wrptr, 0x1B, 200*1000*1000/var->pixclock);
++	wrptr = dlfb_set_register_16be(wrptr, 0x1B,
++			200*1000*1000/var->pixclock);
+ 
+ 	return wrptr;
+ }
+@@ -234,16 +235,16 @@ static int dlfb_set_video_mode(struct dlfb_data *dev,
+ 	* controller * associated with the display. There are 2 base
+ 	* pointers, currently, we only * use the 16 bpp segment.
+ 	*/
+-	wrptr = insert_vidreg_lock(buf);
+-	wrptr = insert_set_color_depth(wrptr, 0x00);
++	wrptr = dlfb_vidreg_lock(buf);
++	wrptr = dlfb_set_color_depth(wrptr, 0x00);
+ 	/* set base for 16bpp segment to 0 */
+-	wrptr = insert_set_base16bpp(wrptr, 0);
++	wrptr = dlfb_set_base16bpp(wrptr, 0);
+ 	/* set base for 8bpp segment to end of fb */
+-	wrptr = insert_set_base8bpp(wrptr, dev->info->fix.smem_len);
++	wrptr = dlfb_set_base8bpp(wrptr, dev->info->fix.smem_len);
+ 
+-	wrptr = insert_set_vid_cmds(wrptr, var);
+-	wrptr = insert_enable_hvsync(wrptr);
+-	wrptr = insert_vidreg_unlock(wrptr);
++	wrptr = dlfb_set_vid_cmds(wrptr, var);
++	wrptr = dlfb_enable_hvsync(wrptr);
++	wrptr = dlfb_vidreg_unlock(wrptr);
+ 
+ 	writesize = wrptr - buf;
+ 
+@@ -284,7 +285,7 @@ static int dlfb_get_var_from_edid(struct dlfb_data *dev,
+ 	return ret;
+ }
+ 
+-static int dlfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
++static int dlfb_ops_mmap(struct fb_info *info, struct vm_area_struct *vma)
+ {
+ 	unsigned long start = vma->vm_start;
+ 	unsigned long size = vma->vm_end - vma->vm_start;
+@@ -781,18 +782,18 @@ copyarea(struct dlfb_data *dev_info, int dx, int dy, int sx, int sy,
+ 	return 1;
+ }
+ 
+-static void dlfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
++static void dlfb_ops_copyarea(struct fb_info *info,
++			const struct fb_copyarea *area)
+ {
+-
+ 	struct dlfb_data *dev = info->par;
+ 
+ 	copyarea(dev, area->dx, area->dy, area->sx, area->sy, area->width,
+ 		 area->height);
+ }
+ 
+-static void dlfb_imageblit(struct fb_info *info, const struct fb_image *image)
++static void dlfb_ops_imageblit(struct fb_info *info,
++			const struct fb_image *image)
+ {
+-
+ 	int ret;
+ 	struct dlfb_data *dev = info->par;
+ 	cfb_imageblit(info, image);
+@@ -801,7 +802,7 @@ static void dlfb_imageblit(struct fb_info *info, const struct fb_image *image)
+ 		       info->screen_base);
+ }
+ 
+-static void dlfb_fillrect(struct fb_info *info,
++static void dlfb_ops_fillrect(struct fb_info *info,
+ 			  const struct fb_fillrect *region)
+ {
+ 
+@@ -817,9 +818,9 @@ static void dlfb_fillrect(struct fb_info *info,
+ 
+ }
+ 
+-static int dlfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
++static int dlfb_ops_ioctl(struct fb_info *info, unsigned int cmd,
++			unsigned long arg)
+ {
+-
+ 	struct dlfb_data *dev_info = info->par;
+ 	struct dloarea *area = NULL;
+ 
+@@ -875,7 +876,7 @@ static int dlfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
+ 
+ /* taken from vesafb */
+ static int
+-dlfb_setcolreg(unsigned regno, unsigned red, unsigned green,
++dlfb_ops_setcolreg(unsigned regno, unsigned red, unsigned green,
+ 	       unsigned blue, unsigned transp, struct fb_info *info)
+ {
+ 	int err = 0;
+@@ -900,7 +901,7 @@ dlfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ 	return err;
+ }
+ 
+-static int dlfb_release(struct fb_info *info, int user)
++static int dlfb_ops_release(struct fb_info *info, int user)
+ {
+ 	struct dlfb_data *dev_info = info->par;
+ 	image_blit(dev_info, 0, 0, info->var.xres, info->var.yres,
+@@ -923,7 +924,7 @@ static void dlfb_delete(struct kref *kref)
+ 	kfree(dev);
+ }
+ 
+-static int dlfb_blank(int blank_mode, struct fb_info *info)
++static int dlfb_ops_blank(int blank_mode, struct fb_info *info)
+ {
+ 	struct dlfb_data *dev_info = info->par;
+ 	char *bufptr = dev_info->buf;
+@@ -942,14 +943,14 @@ static int dlfb_blank(int blank_mode, struct fb_info *info)
+ }
+ 
+ static struct fb_ops dlfb_ops = {
+-	.fb_setcolreg = dlfb_setcolreg,
+-	.fb_fillrect = dlfb_fillrect,
+-	.fb_copyarea = dlfb_copyarea,
+-	.fb_imageblit = dlfb_imageblit,
+-	.fb_mmap = dlfb_mmap,
+-	.fb_ioctl = dlfb_ioctl,
+-	.fb_release = dlfb_release,
+-	.fb_blank = dlfb_blank,
++	.fb_setcolreg = dlfb_ops_setcolreg,
++	.fb_fillrect = dlfb_ops_fillrect,
++	.fb_copyarea = dlfb_ops_copyarea,
++	.fb_imageblit = dlfb_ops_imageblit,
++	.fb_mmap = dlfb_ops_mmap,
++	.fb_ioctl = dlfb_ops_ioctl,
++	.fb_release = dlfb_ops_release,
++	.fb_blank = dlfb_ops_blank,
+ };
+ 
+ /*

Added: dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-explicit-warnings-and-deps.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-explicit-warnings-and-deps.patch	Mon Jul  5 17:35:21 2010	(r15941)
@@ -0,0 +1,72 @@
+From: Bernie Thompson <bernie at plugable.com>
+Date: Mon, 15 Feb 2010 14:46:35 +0000 (-0800)
+Subject: Staging: udlfb: explicit dependencies and warnings
+X-Git-Tag: v2.6.34-rc1~10^2~1^2~67
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=dd8015f1c83bfde9966c86a5958abd466a304398
+
+Staging: udlfb: explicit dependencies and warnings
+
+Specify Kconfig dependencies, and include warnings for building as a module
+
+udlfb is dependent on FB_DEFERRED_IO, FB_SYS_*, and FB_MODE_HELPERS
+
+Because many kernels do not include defio (which cannot be built
+as a module), yet users want to be able to build udlfb as a module later,
+udlfb has ifdefs and these dependency warnings to help udlfb build with or
+without certain dependencies, but also print warnings for any lost function.
+
+Even though this kind of flexibility isn't common, we've gotten feedback
+from a significant portion of users that they were frustrated without it.
+
+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/Kconfig b/drivers/staging/udlfb/Kconfig
+index 641692d..65bd5db 100644
+--- a/drivers/staging/udlfb/Kconfig
++++ b/drivers/staging/udlfb/Kconfig
+@@ -1,8 +1,14 @@
+ config FB_UDL
+ 	tristate "Displaylink USB Framebuffer support"
+ 	depends on FB && USB
++	select FB_MODE_HELPERS
++	select FB_SYS_FILLRECT
++	select FB_SYS_COPYAREA
++	select FB_SYS_IMAGEBLIT
++	select FB_SYS_FOPS
++	select FB_DEFERRED_IO
+ 	---help---
+-	  This is an experimental driver for DisplayLink USB devices
+-	  that provides a framebuffer device.  A normal framebuffer can
+-	  be used with this driver, or xorg can be run on the device
+-	  using it.
++	  This is a kernel framebuffer driver for DisplayLink USB devices.
++	  Supports fbdev clients like xf86-video-fbdev, kdrive, fbi, and
++	  mplayer -vo fbdev. Supports all USB 2.0 era DisplayLink devices.
++	  To compile as a module, choose M here: the module name is udlfb.
+diff --git a/drivers/staging/udlfb/udlfb.c b/drivers/staging/udlfb/udlfb.c
+index 939b8fa..baad03a 100644
+--- a/drivers/staging/udlfb/udlfb.c
++++ b/drivers/staging/udlfb/udlfb.c
+@@ -56,6 +56,20 @@ 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"
++#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"
++#endif
++#endif
++
++#ifndef CONFIG_FB_MODE_HELPERS
++#warning message "kernel FB_MODE_HELPERS required. Expect build break"
++#endif
++
+ /* dlfb keeps a list of urbs for efficient bulk transfers */
+ static void dlfb_urb_completion(struct urb *urb);
+ static struct urb *dlfb_get_urb(struct dlfb_data *dev);

Added: dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-improve-rendering-performance.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-improve-rendering-performance.patch	Mon Jul  5 17:35:21 2010	(r15941)
@@ -0,0 +1,1174 @@
+From: Bernie Thompson <bernie at plugable.com>
+Date: Mon, 15 Feb 2010 14:46:21 +0000 (-0800)
+Subject: Staging: udlfb: improved rendering performance
+X-Git-Tag: v2.6.34-rc1~10^2~1^2~69
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=530f43a8a69d9fa10ec6d30652244bb5e2a29694
+
+Staging: udlfb: improved rendering performance
+
+Rework rendering for improved performance
+
+Approx 10-20% gain avg across several "benchmarks": x11perf, gtkperf, glxgears
+Moves from a single pre-alloc'd urb protected by a long-held mutex
+To a list of (4) pre-alloc'd urbs which can be dispatched asynchonously
+
+Improved rendering algorithm to hardware with lower CPU consumption,
+fewer system memory accesses, and slightly higher compression.
+
+Better scalability to multiple processors, especially with
+multiple framebuffers active.
+
+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 8ee55c8..22f3dc3 100644
+--- a/drivers/staging/udlfb/udlfb.c
++++ b/drivers/staging/udlfb/udlfb.c
+@@ -23,7 +23,6 @@
+ #include <linux/uaccess.h>
+ #include <linux/mm.h>
+ #include <linux/fb.h>
+-#include <linux/mutex.h>
+ #include <linux/vmalloc.h>
+ 
+ #include "udlfb.h"
+@@ -88,12 +87,14 @@ static char *dlfb_vidreg_unlock(char *buf)
+ }
+ 
+ /*
+- * Once you send this command, the DisplayLink framebuffer gets driven to the
+- * display.
++ * On/Off for driving the DisplayLink framebuffer to the display
+  */
+-static char *dlfb_enable_hvsync(char *buf)
++static char *dlfb_enable_hvsync(char *buf, bool enable)
+ {
+-	return dlfb_set_register(buf, 0x1F, 0x00);
++	if (enable)
++		return dlfb_set_register(buf, 0x1F, 0x00);
++	else
++		return dlfb_set_register(buf, 0x1F, 0x01);
+ }
+ 
+ static char *dlfb_set_color_depth(char *buf, u8 selection)
+@@ -233,8 +234,15 @@ static int dlfb_set_video_mode(struct dlfb_data *dev,
+ 	char *wrptr;
+ 	int retval = 0;
+ 	int writesize;
++	struct urb *urb;
+ 
+-	buf = dev->buf;
++	if (!atomic_read(&dev->usb_active))
++		return -EPERM;
++
++	urb = dlfb_get_urb(dev);
++	if (!urb)
++		return -ENOMEM;
++	buf = (char *) urb->transfer_buffer;
+ 
+ 	/*
+ 	* This first section has to do with setting the base address on the
+@@ -249,48 +257,16 @@ static int dlfb_set_video_mode(struct dlfb_data *dev,
+ 	wrptr = dlfb_set_base8bpp(wrptr, dev->info->fix.smem_len);
+ 
+ 	wrptr = dlfb_set_vid_cmds(wrptr, var);
+-	wrptr = dlfb_enable_hvsync(wrptr);
++	wrptr = dlfb_enable_hvsync(wrptr, true);
+ 	wrptr = dlfb_vidreg_unlock(wrptr);
+ 
+ 	writesize = wrptr - buf;
+ 
+-	mutex_lock(&dev->bulk_mutex);
+-	if (!dev->interface) {		/* disconnect() was called */
+-		mutex_unlock(&dev->bulk_mutex);
+-		retval = -ENODEV;
+-		goto error;
+-	}
+-
+-	retval = dlfb_bulk_msg(dev, writesize);
+-	mutex_unlock(&dev->bulk_mutex);
+-	if (retval) {
+-		dev_err(&dev->udev->dev, "Problem %d with submit write bulk.\n",
+-					retval);
+-		goto error;
+-	}
+-
+-	return 0;
++	retval = dlfb_submit_urb(dev, urb, writesize);
+ 
+-error:
+ 	return retval;
+ }
+ 
+-
+-/*
+- * Query EDID from the handware, then hand it off to fbdev's edid parse
+- * routine which should give us back a filled in screeninfo structure.
+- */
+-static int dlfb_get_var_from_edid(struct dlfb_data *dev,
+-					struct fb_var_screeninfo *var)
+-{
+-	int ret;
+-
+-	dlfb_edid(dev);
+-	ret = fb_parse_edid(dev->edid, var);
+-
+-	return ret;
+-}
+-
+ static int dlfb_ops_mmap(struct fb_info *info, struct vm_area_struct *vma)
+ {
+ 	unsigned long start = vma->vm_start;
+@@ -323,504 +299,333 @@ static int dlfb_ops_mmap(struct fb_info *info, struct vm_area_struct *vma)
+ 
+ }
+ 
+-/* ioctl structure */
+-struct dloarea {
+-	int x, y;
+-	int w, h;
+-	int x2, y2;
+-};
+-
+-static struct usb_driver dlfb_driver;
+-
+-/* thanks to Henrik Bjerregaard Pedersen for this function */
+-static char *rle_compress16(uint16_t * src, char *dst, int rem)
++/*
++ * Trims identical data from front and back of line
++ * Sets new front buffer address and width
++ * And returns byte count of identical pixels
++ * Assumes CPU natural alignment (unsigned long)
++ * for back and front buffer ptrs and width
++ */
++static int dlfb_trim_hline(const u8 *bback, const u8 **bfront, int *width_bytes)
+ {
++	int j, k;
++	const unsigned long *back = (const unsigned long *) bback;
++	const unsigned long *front = (const unsigned long *) *bfront;
++	const int width = *width_bytes / sizeof(unsigned long);
++	int identical = width;
++	int start = width;
++	int end = width;
++
++	prefetch((void *) front);
++	prefetch((void *) back);
++
++	for (j = 0; j < width; j++) {
++		if (back[j] != front[j]) {
++			start = j;
++			break;
++		}
++	}
+ 
+-	int rl;
+-	uint16_t pix0;
+-	char *end_if_raw = dst + 6 + 2 * rem;
+-
+-	dst += 6; /* header will be filled in if RLE is worth it */
+-
+-	while (rem && dst < end_if_raw) {
+-		char *start = (char *)src;
+-
+-		pix0 = *src++;
+-		rl = 1;
+-		rem--;
+-		while (rem && *src == pix0)
+-			rem--, rl++, src++;
+-		*dst++ = rl;
+-		*dst++ = start[1];
+-		*dst++ = start[0];
++	for (k = width - 1; k > j; k--) {
++		if (back[k] != front[k]) {
++			end = k+1;
++			break;
++		}
+ 	}
+ 
+-	return dst;
++	identical = start + (width - end);
++	*bfront = (u8 *) &front[start];
++	*width_bytes = (end - start) * sizeof(unsigned long);
++
++	return identical * sizeof(unsigned long);
+ }
+ 
+ /*
+-Thanks to Henrik Bjerregaard Pedersen for rle implementation
+-and code refactoring. Next step is huffman compression.
++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 int
+-image_blit(struct dlfb_data *dev_info, int x, int y, int width, int height,
+-	   char *data)
++static void dlfb_compress_hline(
++	const uint16_t **pixel_start_ptr,
++	const uint16_t *const pixel_end,
++	uint32_t *device_address_ptr,
++	uint8_t **command_buffer_ptr,
++	const uint8_t *const cmd_buffer_end)
+ {
+-
+-	int i, j, base;
+-	int rem = width;
+-	int ret;
+-
+-	int firstdiff, thistime;
+-
+-	char *bufptr;
+-
+-	if (x + width > dev_info->info->var.xres)
+-		return -EINVAL;
+-
+-	if (y + height > dev_info->info->var.yres)
+-		return -EINVAL;
+-
+-	mutex_lock(&dev_info->bulk_mutex);
+-
+-	base =
+-	    dev_info->base16 + ((dev_info->info->var.xres * 2 * y) + (x * 2));
+-
+-	data += (dev_info->info->var.xres * 2 * y) + (x * 2);
+-
+-	/* printk("IMAGE_BLIT\n"); */
+-
+-	bufptr = dev_info->buf;
+-
+-	for (i = y; i < y + height; i++) {
+-
+-		if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
+-			ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
+-			bufptr = dev_info->buf;
+-		}
+-
+-		rem = width;
+-
+-		/* printk("WRITING LINE %d\n", i); */
+-
+-		while (rem) {
+-
+-			if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
+-				ret =
+-				    dlfb_bulk_msg(dev_info,
+-						  bufptr - dev_info->buf);
+-				bufptr = dev_info->buf;
+-			}
+-			/* number of pixels to consider this time */
+-			thistime = rem;
+-			if (thistime > 255)
+-				thistime = 255;
+-
+-			if (dev_info->backing_buffer) {
+-				/* find first pixel that has changed */
+-				firstdiff = -1;
+-				for (j = 0; j < thistime * 2; j++) {
+-					if (dev_info->backing_buffer
+-					    [base - dev_info->base16 + j]
+-					    != data[j]) {
+-						firstdiff = j / 2;
+-						break;
+-					}
++	const uint16_t *pixel = *pixel_start_ptr;
++	uint32_t dev_addr  = *device_address_ptr;
++	uint8_t *cmd = *command_buffer_ptr;
++	const int bpp = 2;
++
++	while ((pixel_end > pixel) &&
++	       (cmd_buffer_end - MIN_RLX_CMD_BYTES > cmd)) {
++		uint8_t *raw_pixels_count_byte = 0;
++		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_pixels_count_byte = cmd++; /*  we'll know this later */
++		cmd_pixel_start = pixel;
++
++		raw_pixels_count_byte = cmd++; /*  we'll know this later */
++		raw_pixel_start = pixel;
++
++		cmd_pixel_end = pixel + min(MAX_CMD_PIXELS + 1,
++			min((int)(pixel_end - pixel),
++			    (int)(cmd_buffer_end - cmd) / bpp));
++
++		prefetch_range((void *) pixel, (cmd_pixel_end - pixel) * bpp);
++
++		while (pixel < cmd_pixel_end) {
++			const uint16_t * const repeating_pixel = pixel;
++
++			*(uint16_t *)cmd = cpu_to_be16p(pixel);
++			cmd += 2;
++			pixel++;
++
++			if (unlikely((pixel < cmd_pixel_end) &&
++				     (*pixel == *repeating_pixel))) {
++				/* go back and fill in raw pixel count */
++				*raw_pixels_count_byte = ((repeating_pixel -
++						raw_pixel_start) + 1) & 0xFF;
++
++				while ((pixel < cmd_pixel_end)
++				       && (*pixel == *repeating_pixel)) {
++					pixel++;
+ 				}
+ 
+-			} else {
+-				firstdiff = 0;
++				/* immediately after raw data is repeat byte */
++				*cmd++ = ((pixel - repeating_pixel) - 1) & 0xFF;
+ 
++				/* Then start another raw pixel span */
++				raw_pixel_start = pixel;
++				raw_pixels_count_byte = cmd++;
+ 			}
+-
+-			if (firstdiff >= 0) {
+-				char *end_of_rle;
+-
+-				end_of_rle =
+-				    rle_compress16((uint16_t *) (data +
+-								 firstdiff * 2),
+-						   bufptr,
+-						   thistime - firstdiff);
+-
+-				if (end_of_rle <
+-				    bufptr + 6 + 2 * (thistime - firstdiff)) {
+-					bufptr[0] = 0xAF;
+-					bufptr[1] = 0x69;
+-
+-					bufptr[2] =
+-					    (char)((base +
+-						    firstdiff * 2) >> 16);
+-					bufptr[3] =
+-					    (char)((base + firstdiff * 2) >> 8);
+-					bufptr[4] =
+-					    (char)(base + firstdiff * 2);
+-					bufptr[5] = thistime - firstdiff;
+-
+-					bufptr = end_of_rle;
+-
+-				} else {
+-					/* fallback to raw (or other?) */
+-					*bufptr++ = 0xAF;
+-					*bufptr++ = 0x68;
+-
+-					*bufptr++ =
+-					    (char)((base +
+-						    firstdiff * 2) >> 16);
+-					*bufptr++ =
+-					    (char)((base + firstdiff * 2) >> 8);
+-					*bufptr++ =
+-					    (char)(base + firstdiff * 2);
+-					*bufptr++ = thistime - firstdiff;
+-					for (j = firstdiff * 2;
+-					     j < thistime * 2; j += 2) {
+-						*bufptr++ = data[j + 1];
+-						*bufptr++ = data[j];
+-					}
+-				}
+-			}
+-
+-			base += thistime * 2;
+-			data += thistime * 2;
+-			rem -= thistime;
+ 		}
+ 
+-		if (dev_info->backing_buffer)
+-			memcpy(dev_info->backing_buffer +
+-			       (base - dev_info->base16) -
+-			       (width * 2), data - (width * 2), width * 2);
+-
+-		base += (dev_info->info->var.xres * 2) - (width * 2);
+-		data += (dev_info->info->var.xres * 2) - (width * 2);
++		if (pixel > raw_pixel_start) {
++			/* finalize last RAW span */
++			*raw_pixels_count_byte = (pixel-raw_pixel_start) & 0xFF;
++		}
+ 
++		*cmd_pixels_count_byte = (pixel - cmd_pixel_start) & 0xFF;
++		dev_addr += (pixel - cmd_pixel_start) * bpp;
+ 	}
+ 
+-	if (bufptr > dev_info->buf) {
+-		ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
++	if (cmd_buffer_end <= MIN_RLX_CMD_BYTES + cmd) {
++		/* Fill leftover bytes with no-ops */
++		if (cmd_buffer_end > cmd)
++			memset(cmd, 0xAF, cmd_buffer_end - cmd);
++		cmd = (uint8_t *) cmd_buffer_end;
+ 	}
+ 
+-	mutex_unlock(&dev_info->bulk_mutex);
+-
+-	return base;
++	*command_buffer_ptr = cmd;
++	*pixel_start_ptr = pixel;
++	*device_address_ptr = dev_addr;
+ 
++	return;
+ }
+ 
+-static int
+-draw_rect(struct dlfb_data *dev_info, int x, int y, int width, int height,
+-	  unsigned char red, unsigned char green, unsigned char blue)
++/*
++ * There are 3 copies of every pixel: The front buffer that the fbdev
++ * client renders to, the actual framebuffer across the USB bus in hardware
++ * (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,
++			      const char *front, char **urb_buf_ptr,
++			      u32 byte_offset, u32 byte_width,
++			      int *ident_ptr, int *sent_ptr)
+ {
++	const u8 *line_start, *line_end, *next_pixel;
++	u32 dev_addr = dev->base16 + byte_offset;
++	struct urb *urb = *urb_ptr;
++	u8 *cmd = *urb_buf_ptr;
++	u8 *cmd_end = (u8 *) urb->transfer_buffer + urb->transfer_buffer_length;
++
++	line_start = (u8 *) (front + byte_offset);
++	next_pixel = line_start;
++	line_end = next_pixel + byte_width;
++
++	if (dev->backing_buffer) {
++		int offset;
++		const u8 *back_start = (u8 *) (dev->backing_buffer
++						+ byte_offset);
++
++		*ident_ptr += dlfb_trim_hline(back_start, &next_pixel,
++			&byte_width);
++
++		offset = next_pixel - line_start;
++		line_end = next_pixel + byte_width;
++		dev_addr += offset;
++		back_start += offset;
++		line_start += offset;
++
++		memcpy((char *)back_start, (char *) line_start,
++		       byte_width);
++	}
+ 
+-	int i, j, base;
+-	int ret;
+-	unsigned short col =
+-	    (((((red) & 0xF8) | ((green) >> 5)) & 0xFF) << 8) +
+-	    (((((green) & 0x1C) << 3) | ((blue) >> 3)) & 0xFF);
+-	int rem = width;
+-
+-	char *bufptr;
+-
+-	if (x + width > dev_info->info->var.xres)
+-		return -EINVAL;
+-
+-	if (y + height > dev_info->info->var.yres)
+-		return -EINVAL;
+-
+-	mutex_lock(&dev_info->bulk_mutex);
+-
+-	base = dev_info->base16 + (dev_info->info->var.xres * 2 * y) + (x * 2);
+-
+-	bufptr = dev_info->buf;
+-
+-	for (i = y; i < y + height; i++) {
+-
+-		if (dev_info->backing_buffer) {
+-			for (j = 0; j < width * 2; j += 2) {
+-				dev_info->backing_buffer
+-					[base - dev_info->base16 + j] =
+-					(char)(col >> 8);
+-				dev_info->backing_buffer
+-					[base - dev_info->base16 + j + 1] =
+-					(char)(col);
+-			}
+-		}
+-
+-		if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
+-			ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
+-			bufptr = dev_info->buf;
+-		}
+-
+-		rem = width;
+-
+-		while (rem) {
+-
+-			if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
+-				ret =
+-				    dlfb_bulk_msg(dev_info,
+-						  bufptr - dev_info->buf);
+-				bufptr = dev_info->buf;
+-			}
+-
+-			*bufptr++ = 0xAF;
+-			*bufptr++ = 0x69;
+-
+-			*bufptr++ = (char)(base >> 16);
+-			*bufptr++ = (char)(base >> 8);
+-			*bufptr++ = (char)(base);
+-
+-			if (rem > 255) {
+-				*bufptr++ = 255;
+-				*bufptr++ = 255;
+-				rem -= 255;
+-				base += 255 * 2;
+-			} else {
+-				*bufptr++ = rem;
+-				*bufptr++ = rem;
+-				base += rem * 2;
+-				rem = 0;
+-			}
+-
+-			*bufptr++ = (char)(col >> 8);
+-			*bufptr++ = (char)(col);
+-
++	while (next_pixel < line_end) {
++
++		dlfb_compress_hline((const uint16_t **) &next_pixel,
++			     (const uint16_t *) line_end, &dev_addr,
++			(u8 **) &cmd, (u8 *) cmd_end);
++
++		if (cmd >= cmd_end) {
++			int len = cmd - (u8 *) urb->transfer_buffer;
++			if (dlfb_submit_urb(dev, urb, len))
++				return; /* lost pixels is set */
++			*sent_ptr += len;
++			urb = dlfb_get_urb(dev);
++			if (!urb)
++				return; /* lost_pixels is set */
++			*urb_ptr = urb;
++			cmd = urb->transfer_buffer;
++			cmd_end = &cmd[urb->transfer_buffer_length];
+ 		}
+-
+-		base += (dev_info->info->var.xres * 2) - (width * 2);
+-
+ 	}
+ 
+-	if (bufptr > dev_info->buf)
+-		ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
+-
+-	mutex_unlock(&dev_info->bulk_mutex);
+-
+-	return 1;
++	*urb_buf_ptr = cmd;
+ }
+ 
+-static void swapfb(struct dlfb_data *dev_info)
++int dlfb_handle_damage(struct dlfb_data *dev, int x, int y,
++	       int width, int height, char *data)
+ {
+-
+-	int tmpbase;
+-	char *bufptr;
+-
+-	mutex_lock(&dev_info->bulk_mutex);
+-
+-	tmpbase = dev_info->base16;
+-
+-	dev_info->base16 = dev_info->base16d;
+-	dev_info->base16d = tmpbase;
+-
+-	bufptr = dev_info->buf;
+-
+-	bufptr = dlfb_set_register(bufptr, 0xFF, 0x00);
+-
+-	/* set addresses */
+-	bufptr =
+-	    dlfb_set_register(bufptr, 0x20, (char)(dev_info->base16 >> 16));
+-	bufptr = dlfb_set_register(bufptr, 0x21, (char)(dev_info->base16 >> 8));
+-	bufptr = dlfb_set_register(bufptr, 0x22, (char)(dev_info->base16));
+-
+-	bufptr = dlfb_set_register(bufptr, 0xFF, 0x00);
+-
+-	dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
+-
+-	mutex_unlock(&dev_info->bulk_mutex);
+-}
+-
+-static int copyfb(struct dlfb_data *dev_info)
+-{
+-	int base;
+-	int source;
+-	int rem;
+ 	int i, ret;
++	char *cmd;
++	cycles_t start_cycles, end_cycles;
++	int bytes_sent = 0;
++	int bytes_identical = 0;
++	struct urb *urb;
++	int aligned_x;
+ 
+-	char *bufptr;
+-
+-	base = dev_info->base16d;
+-
+-	mutex_lock(&dev_info->bulk_mutex);
+-
+-	source = dev_info->base16;
+-
+-	bufptr = dev_info->buf;
+-
+-	for (i = 0; i < dev_info->info->var.yres; i++) {
+-
+-		if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
+-			ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
+-			bufptr = dev_info->buf;
+-		}
+-
+-		rem = dev_info->info->var.xres;
+-
+-		while (rem) {
+-
+-			if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
+-				ret =
+-				    dlfb_bulk_msg(dev_info,
+-						  bufptr - dev_info->buf);
+-				bufptr = dev_info->buf;
+-
+-			}
++	start_cycles = get_cycles();
+ 
+-			*bufptr++ = 0xAF;
+-			*bufptr++ = 0x6A;
++	aligned_x = DL_ALIGN_DOWN(x, sizeof(unsigned long));
++	width = DL_ALIGN_UP(width + (x-aligned_x), sizeof(unsigned long));
++	x = aligned_x;
+ 
+-			*bufptr++ = (char)(base >> 16);
+-			*bufptr++ = (char)(base >> 8);
+-			*bufptr++ = (char)(base);
++	if ((width <= 0) ||
++	    (x + width > dev->info->var.xres) ||
++	    (y + height > dev->info->var.yres))
++		return -EINVAL;
+ 
+-			if (rem > 255) {
+-				*bufptr++ = 255;
+-				*bufptr++ = (char)(source >> 16);
+-				*bufptr++ = (char)(source >> 8);
+-				*bufptr++ = (char)(source);
++	if (!atomic_read(&dev->usb_active))
++		return 0;
+ 
+-				rem -= 255;
+-				base += 255 * 2;
+-				source += 255 * 2;
++	urb = dlfb_get_urb(dev);
++	if (!urb)
++		return 0;
++	cmd = urb->transfer_buffer;
+ 
+-			} else {
+-				*bufptr++ = rem;
+-				*bufptr++ = (char)(source >> 16);
+-				*bufptr++ = (char)(source >> 8);
+-				*bufptr++ = (char)(source);
++	for (i = y; i < y + height ; i++) {
++		const int line_offset = dev->info->fix.line_length * i;
++		const int byte_offset = line_offset + (x * BPP);
+ 
+-				base += rem * 2;
+-				source += rem * 2;
+-				rem = 0;
+-			}
+-		}
++		dlfb_render_hline(dev, &urb, (char *) dev->info->fix.smem_start,
++				  &cmd, byte_offset, width * BPP,
++				  &bytes_identical, &bytes_sent);
+ 	}
+ 
+-	if (bufptr > dev_info->buf)
+-		ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
+-
+-	mutex_unlock(&dev_info->bulk_mutex);
+-
+-	return 1;
++	if (cmd > (char *) urb->transfer_buffer) {
++		/* Send partial buffer remaining before exiting */
++		int len = cmd - (char *) urb->transfer_buffer;
++		ret = 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(width*height*2, &dev->bytes_rendered);
++	end_cycles = get_cycles();
++	atomic_add(((unsigned int) ((end_cycles - start_cycles)
++		    >> 10)), /* Kcycles */
++		   &dev->cpu_kcycles_used);
+ 
++	return 0;
+ }
+ 
+-static int
+-copyarea(struct dlfb_data *dev_info, int dx, int dy, int sx, int sy,
+-	 int width, int height)
++/* 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)
+ {
+-	int base;
+-	int source;
+-	int rem;
+-	int i, ret;
+-
+-	char *bufptr;
+-
+-	if (dx + width > dev_info->info->var.xres)
+-		return -EINVAL;
+ 
+-	if (dy + height > dev_info->info->var.yres)
+-		return -EINVAL;
+-
+-	mutex_lock(&dev_info->bulk_mutex);
+-
+-	base =
+-	    dev_info->base16 + (dev_info->info->var.xres * 2 * dy) + (dx * 2);
+-	source = (dev_info->info->var.xres * 2 * sy) + (sx * 2);
+-
+-	bufptr = dev_info->buf;
+-
+-	for (i = sy; i < sy + height; i++) {
+-
+-		memcpy(dev_info->backing_buffer + base - dev_info->base16,
+-		       dev_info->backing_buffer + source, width * 2);
+-
+-		if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
+-			ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
+-			bufptr = dev_info->buf;
+-		}
+-
+-		rem = width;
+-
+-		while (rem) {
+-
+-			if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
+-				ret =
+-				    dlfb_bulk_msg(dev_info,
+-						  bufptr - dev_info->buf);
+-				bufptr = dev_info->buf;
+-			}
++	struct dlfb_data *dev = info->par;
+ 
+-			*bufptr++ = 0xAF;
+-			*bufptr++ = 0x6A;
++#if defined CONFIG_FB_SYS_COPYAREA || defined CONFIG_FB_SYS_COPYAREA_MODULE
+ 
+-			*bufptr++ = (char)(base >> 16);
+-			*bufptr++ = (char)(base >> 8);
+-			*bufptr++ = (char)(base);
++	sys_copyarea(info, area);
+ 
+-			if (rem > 255) {
+-				*bufptr++ = 255;
+-				*bufptr++ = (char)(source >> 16);
+-				*bufptr++ = (char)(source >> 8);
+-				*bufptr++ = (char)(source);
++	dlfb_handle_damage(dev, area->dx, area->dy,
++			area->width, area->height, info->screen_base);
++#endif
++	atomic_inc(&dev->copy_count);
+ 
+-				rem -= 255;
+-				base += 255 * 2;
+-				source += 255 * 2;
++}
+ 
+-			} else {
+-				*bufptr++ = rem;
+-				*bufptr++ = (char)(source >> 16);
+-				*bufptr++ = (char)(source >> 8);
+-				*bufptr++ = (char)(source);
++static void dlfb_ops_imageblit(struct fb_info *info,
++				const struct fb_image *image)
++{
++	struct dlfb_data *dev = info->par;
+ 
+-				base += rem * 2;
+-				source += rem * 2;
+-				rem = 0;
+-			}
+-		}
++#if defined CONFIG_FB_SYS_IMAGEBLIT || defined CONFIG_FB_SYS_IMAGEBLIT_MODULE
+ 
+-		base += (dev_info->info->var.xres * 2) - (width * 2);
+-		source += (dev_info->info->var.xres * 2) - (width * 2);
+-	}
++	sys_imageblit(info, image);
+ 
+-	if (bufptr > dev_info->buf)
+-		ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
++	dlfb_handle_damage(dev, image->dx, image->dy,
++			image->width, image->height, info->screen_base);
+ 
+-	mutex_unlock(&dev_info->bulk_mutex);
++#endif
+ 
+-	return 1;
++	atomic_inc(&dev->blit_count);
+ }
+ 
+-static void dlfb_ops_copyarea(struct fb_info *info,
+-			const struct fb_copyarea *area)
++static void dlfb_ops_fillrect(struct fb_info *info,
++			  const struct fb_fillrect *rect)
+ {
+ 	struct dlfb_data *dev = info->par;
+ 
+-	copyarea(dev, area->dx, area->dy, area->sx, area->sy, area->width,
+-		 area->height);
+-}
+-
+-static void dlfb_ops_imageblit(struct fb_info *info,
+-			const struct fb_image *image)
+-{
+-	int ret;
+-	struct dlfb_data *dev = info->par;
+-	cfb_imageblit(info, image);
+-	ret =
+-	    image_blit(dev, image->dx, image->dy, image->width, image->height,
+-		       info->screen_base);
+-}
++#if defined CONFIG_FB_SYS_FILLRECT || defined CONFIG_FB_SYS_FILLRECT_MODULE
+ 
+-static void dlfb_ops_fillrect(struct fb_info *info,
+-			  const struct fb_fillrect *region)
+-{
++	sys_fillrect(info, rect);
+ 
+-	unsigned char red, green, blue;
+-	struct dlfb_data *dev = info->par;
++	dlfb_handle_damage(dev, rect->dx, rect->dy, rect->width,
++			      rect->height, info->screen_base);
++#endif
+ 
+-	memcpy(&red, &region->color, 1);
+-	memcpy(&green, &region->color + 1, 1);
+-	memcpy(&blue, &region->color + 2, 1);
+-	draw_rect(dev, region->dx, region->dy, region->width, region->height,
+-		  red, green, blue);
+-	/* printk("FILL RECT %d %d !!!\n", region->dx, region->dy); */
++	atomic_inc(&dev->fill_count);
+ 
+ }
+ 
+@@ -840,21 +645,26 @@ static void dlfb_get_edid(struct dlfb_data *dev)
+ }
+ 
+ static int dlfb_ops_ioctl(struct fb_info *info, unsigned int cmd,
+-			unsigned long arg)
++				unsigned long arg)
+ {
+-	struct dlfb_data *dev_info = info->par;
++
++	struct dlfb_data *dev = info->par;
+ 	struct dloarea *area = NULL;
+ 
+-	if (cmd == 0xAD) {
++	if (!atomic_read(&dev->usb_active))
++		return 0;
++
++	/* TODO: Update X server to get this from sysfs instead */
++	if (cmd == DLFB_IOCTL_RETURN_EDID) {
+ 		char *edid = (char *)arg;
+-		dlfb_edid(dev_info);
+-		if (copy_to_user(edid, dev_info->edid, 128)) {
++		dlfb_get_edid(dev);
++		if (copy_to_user(edid, dev->edid, sizeof(dev->edid)))
+ 			return -EFAULT;
+-		}
+ 		return 0;
+ 	}
+ 
+-	if (cmd == 0xAA || cmd == 0xAB || cmd == 0xAC) {
++	/* TODO: Help propose a standard fb.h ioctl to report mmap damage */
++	if (cmd == DLFB_IOCTL_REPORT_DAMAGE) {
+ 
+ 		area = (struct dloarea *)arg;
+ 
+@@ -869,29 +679,14 @@ static int dlfb_ops_ioctl(struct fb_info *info, unsigned int cmd,
+ 
+ 		if (area->y > info->var.yres)
+ 			area->y = info->var.yres;
+-	}
+ 
+-	if (cmd == 0xAA) {
+-		image_blit(dev_info, area->x, area->y, area->w, area->h,
++		atomic_set(&dev->use_defio, 0);
++
++		dlfb_handle_damage(dev, area->x, area->y, area->w, area->h,
+ 			   info->screen_base);
++		atomic_inc(&dev->damage_count);
+ 	}
+-	if (cmd == 0xAC) {
+-		copyfb(dev_info);
+-		image_blit(dev_info, area->x, area->y, area->w, area->h,
+-			   info->screen_base);
+-		swapfb(dev_info);
+-	} else if (cmd == 0xAB) {
+-
+-		if (area->x2 < 0)
+-			area->x2 = 0;
+ 
+-		if (area->y2 < 0)
+-			area->y2 = 0;
+-
+-		copyarea(dev_info,
+-			 area->x2, area->y2, area->x, area->y, area->w,
+-			 area->h);
+-	}
+ 	return 0;
+ }
+ 
+@@ -925,8 +720,6 @@ dlfb_ops_setcolreg(unsigned regno, unsigned red, unsigned green,
+ static int dlfb_ops_release(struct fb_info *info, int user)
+ {
+ 	struct dlfb_data *dev_info = info->par;
+-	image_blit(dev_info, 0, 0, info->var.xres, info->var.yres,
+-		   info->screen_base);
+ 	return 0;
+ }
+ 
+@@ -1026,18 +819,28 @@ static int dlfb_ops_set_par(struct fb_info *info)
+ 
+ static int dlfb_ops_blank(int blank_mode, struct fb_info *info)
+ {
+-	struct dlfb_data *dev_info = info->par;
+-	char *bufptr = dev_info->buf;
++	struct dlfb_data *dev = info->par;
++	char *bufptr;
++	struct urb *urb;
+ 
+-	bufptr = dlfb_set_register(bufptr, 0xFF, 0x00);
++	urb = dlfb_get_urb(dev);
++	if (!urb)
++		return 0;
++	bufptr = (char *) urb->transfer_buffer;
++
++	/* overloading usb_active.  UNBLANK can conflict with teardown */
++
++	bufptr = dlfb_vidreg_lock(bufptr);
+ 	if (blank_mode != FB_BLANK_UNBLANK) {
+-		bufptr = dlfb_set_register(bufptr, 0x1F, 0x01);
++		atomic_set(&dev->usb_active, 0);
++		bufptr = dlfb_enable_hvsync(bufptr, false);
+ 	} else {
+-		bufptr = dlfb_set_register(bufptr, 0x1F, 0x00);
++		atomic_set(&dev->usb_active, 1);
++		bufptr = dlfb_enable_hvsync(bufptr, true);
+ 	}
+-	bufptr = dlfb_set_register(bufptr, 0xFF, 0xFF);
++	bufptr = dlfb_vidreg_unlock(bufptr);
+ 
+-	dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
++	dlfb_submit_urb(dev, urb, bufptr - (char *) urb->transfer_buffer);
+ 
+ 	return 0;
+ }
+@@ -1312,8 +1115,6 @@ static int dlfb_usb_probe(struct usb_interface *interface,
+ 	kref_init(&dev->kref); /* matching kref_put in usb .disconnect fn */
+ 	kref_get(&dev->kref); /* matching kref_put in .fb_destroy function*/
+ 
+-	mutex_init(&dev->bulk_mutex);
+-
+ 	dev->udev = usbdev;
+ 	dev->gdev = &usbdev->dev; /* our generic struct device * */
+ 	usb_set_intfdata(interface, dev);
+@@ -1326,22 +1127,6 @@ static int dlfb_usb_probe(struct usb_interface *interface,
+ 
+ 	mutex_init(&dev->fb_open_lock);
+ 
+-	/*
+-	 * TODO: replace single 64K buffer with buffer list
+-	 * and async dispatch
+-	 */
+-	dev->buf = kmalloc(BUF_SIZE, GFP_KERNEL);
+-	if (dev->buf == NULL) {
+-		dl_err("unable to allocate memory for dlfb commands\n");
+-		goto error;
+-	}
+-	dev->bufend = dev->buf + BUF_SIZE;
+-
+-	dev->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+-	usb_fill_bulk_urb(dev->tx_urb, dev->udev,
+-			  usb_sndbulkpipe(dev->udev, 1), dev->buf, 0,
+-			  dlfb_bulk_callback, dev);
+-
+ 	/* We don't register a new USB class. Our client interface is fbdev */
+ 
+ 	/* allocates framebuffer driver structure, not framebuffer memory */
+@@ -1420,14 +1205,13 @@ static int dlfb_usb_probe(struct usb_interface *interface,
+ 	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);
+diff --git a/drivers/staging/udlfb/udlfb.h b/drivers/staging/udlfb/udlfb.h
+index e6c68c6..b07a693 100644
+--- a/drivers/staging/udlfb/udlfb.h
++++ b/drivers/staging/udlfb/udlfb.h
+@@ -1,9 +1,20 @@
+ #ifndef UDLFB_H
+ #define UDLFB_H
+ 
+-/* as libdlo */
+-#define BUF_HIGH_WATER_MARK	1024
+-#define BUF_SIZE		(64*1024)
++/*
++ * TODO: Propose standard fb.h ioctl for reporting damage,
++ * using _IOWR() and one of the existing area structs from fb.h
++ * Consider these ioctls deprecated, but they're still used by the
++ * DisplayLink X server as yet - need both to be modified in tandem
++ * when new ioctl(s) are ready.
++ */
++#define DLFB_IOCTL_RETURN_EDID	 0xAD
++#define DLFB_IOCTL_REPORT_DAMAGE 0xAA
++struct dloarea {
++	int x, y;
++	int w, h;
++	int x2, y2;
++};
+ 
+ struct urb_node {
+ 	struct list_head entry;
+@@ -23,30 +34,20 @@ struct urb_list {
+ struct dlfb_data {
+ 	struct usb_device *udev;
+ 	struct device *gdev; /* &udev->dev */
+-	struct usb_interface *interface;
+-	struct urb *tx_urb, *ctrl_urb;
+ 	struct fb_info *info;
+ 	struct urb_list urbs;
+ 	struct kref kref;
+-	char *buf;
+-	char *bufend;
+ 	char *backing_buffer;
+ 	struct delayed_work deferred_work;
+ 	struct mutex fb_open_lock;
+-	struct mutex bulk_mutex;
+ 	int fb_count;
+ 	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];
+ 	int sku_pixel_limit;
+-	int screen_size;
+-	int line_length;
+-	struct completion done;
+ 	int base16;
+-	int base16d;
+ 	int base8;
+-	int base8d;
+ 	u32 pseudo_palette[256];
+ 	/* blit-only rendering path metrics, exposed through sysfs */
+ 	atomic_t bytes_rendered; /* raw pixel-bytes driver asked to render */
+@@ -72,48 +73,24 @@ struct dlfb_data {
+ #define GET_URB_TIMEOUT	HZ
+ #define FREE_URB_TIMEOUT (HZ*2)
+ 
+-static void dlfb_bulk_callback(struct urb *urb)
+-{
+-	struct dlfb_data *dev_info = urb->context;
+-	complete(&dev_info->done);
+-}
+-
+-static void dlfb_edid(struct dlfb_data *dev_info)
+-{
+-	int i;
+-	int ret;
+-	char rbuf[2];
+-
+-	for (i = 0; i < 128; i++) {
+-		ret =
+-		    usb_control_msg(dev_info->udev,
+-				    usb_rcvctrlpipe(dev_info->udev, 0), (0x02),
+-				    (0x80 | (0x02 << 5)), i << 8, 0xA1, rbuf, 2,
+-				    0);
+-		dev_info->edid[i] = rbuf[1];
+-	}
+-
+-}
+-
+-static int dlfb_bulk_msg(struct dlfb_data *dev_info, int len)
+-{
+-	int ret;
+-
+-	init_completion(&dev_info->done);
++#define BPP                     2
++#define MAX_CMD_PIXELS		255
+ 
+-	dev_info->tx_urb->actual_length = 0;
+-	dev_info->tx_urb->transfer_buffer_length = len;
++#define RLX_HEADER_BYTES	7
++#define MIN_RLX_PIX_BYTES       4
++#define MIN_RLX_CMD_BYTES	(RLX_HEADER_BYTES + MIN_RLX_PIX_BYTES)
+ 
+-	ret = usb_submit_urb(dev_info->tx_urb, GFP_KERNEL);
+-	if (!wait_for_completion_timeout(&dev_info->done, 1000)) {
+-		usb_kill_urb(dev_info->tx_urb);
+-		printk("usb timeout !!!\n");
+-	}
++#define RLE_HEADER_BYTES	6
++#define MIN_RLE_PIX_BYTES	3
++#define MIN_RLE_CMD_BYTES	(RLE_HEADER_BYTES + MIN_RLE_PIX_BYTES)
+ 
+-	return dev_info->tx_urb->actual_length;
+-}
++#define RAW_HEADER_BYTES	6
++#define MIN_RAW_PIX_BYTES	2
++#define MIN_RAW_CMD_BYTES	(RAW_HEADER_BYTES + MIN_RAW_PIX_BYTES)
+ 
+-#define dlfb_set_register insert_command
++/* 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)
+ 
+ /* remove once this gets added to sysfs.h */
+ #define __ATTR_RW(attr) __ATTR(attr, 0644, attr##_show, attr##_store)

Added: dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-preallocated-urb-list-helpers.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-preallocated-urb-list-helpers.patch	Mon Jul  5 17:35:21 2010	(r15941)
@@ -0,0 +1,311 @@
+From: Bernie Thompson <bernie at plugable.com>
+Date: Mon, 15 Feb 2010 14:45:55 +0000 (-0800)
+Subject: Staging: udlfb: pre-allocated urb list helpers
+X-Git-Tag: v2.6.34-rc1~10^2~1^2~73
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=4a4854dd2049ddc066a162a0f843dc2a78481060
+
+Staging: udlfb: pre-allocated urb list helpers
+
+Add functions to pre-allocate and free usb bulk urbs for core render path.
+
+Udlfb currently allocates a single urb, guarded by a mutex, that is a key
+bottleneck. Because udlfb sends so much data, preallocation is most efficient.
+
+Functions will be used by new rendering functions in later patches.
+
+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 3306bba..592b185 100644
+--- a/drivers/staging/udlfb/udlfb.c
++++ b/drivers/staging/udlfb/udlfb.c
+@@ -51,6 +51,13 @@ static struct usb_device_id id_table[] = {
+ };
+ MODULE_DEVICE_TABLE(usb, id_table);
+ 
++/* dlfb keeps a list of urbs for efficient bulk transfers */
++static void dlfb_urb_completion(struct urb *urb);
++static struct urb *dlfb_get_urb(struct dlfb_data *dev);
++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);
++
+ /*
+  * Inserts a specific DisplayLink controller command into the provided
+  * buffer.
+@@ -901,6 +908,21 @@ static int dlfb_release(struct fb_info *info, int user)
+ 	return 0;
+ }
+ 
++/*
++ * Called when all client interfaces to start transactions have been disabled,
++ * 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)
++{
++	struct dlfb_data *dev = container_of(kref, struct dlfb_data, kref);
++
++	if (dev->backing_buffer)
++		vfree(dev->backing_buffer);
++
++	kfree(dev);
++}
++
+ static int dlfb_blank(int blank_mode, struct fb_info *info)
+ {
+ 	struct dlfb_data *dev_info = info->par;
+@@ -974,6 +996,7 @@ static int dlfb_probe(struct usb_interface *interface,
+ 
+ 	mutex_init(&dev->bulk_mutex);
+ 	dev->udev = usbdev;
++	dev->gdev = &usbdev->dev; /* our generic struct device * */
+ 	dev->interface = interface;
+ 	usb_set_intfdata(interface, dev);
+ 
+@@ -1168,6 +1191,175 @@ static void __exit dlfb_exit(void)
+ module_init(dlfb_init);
+ module_exit(dlfb_exit);
+ 
++static void dlfb_urb_completion(struct urb *urb)
++{
++	struct urb_node *unode = urb->context;
++	struct dlfb_data *dev = unode->dev;
++	unsigned long flags;
++
++	/* sync/async unlink faults aren't errors */
++	if (urb->status) {
++		if (!(urb->status == -ENOENT ||
++		    urb->status == -ECONNRESET ||
++		    urb->status == -ESHUTDOWN)) {
++			dl_err("%s - nonzero write bulk status received: %d\n",
++				__func__, urb->status);
++			atomic_set(&dev->lost_pixels, 1);
++		}
++	}
++
++	urb->transfer_buffer_length = dev->urbs.size; /* reset to actual */
++
++	spin_lock_irqsave(&dev->urbs.lock, flags);
++	list_add_tail(&unode->entry, &dev->urbs.list);
++	dev->urbs.available++;
++	spin_unlock_irqrestore(&dev->urbs.lock, flags);
++
++	up(&dev->urbs.limit_sem);
++}
++
++static void dlfb_free_urb_list(struct dlfb_data *dev)
++{
++	int count = dev->urbs.count;
++	struct list_head *node;
++	struct urb_node *unode;
++	struct urb *urb;
++	int ret;
++	unsigned long flags;
++
++	dl_notice("Waiting for completes and freeing all render urbs\n");
++
++	/* 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);
++			break;
++		}
++		spin_lock_irqsave(&dev->urbs.lock, flags);
++
++		node = dev->urbs.list.next; /* have reserved one with sem */
++		list_del_init(node);
++
++		spin_unlock_irqrestore(&dev->urbs.lock, flags);
++
++		unode = list_entry(node, struct urb_node, entry);
++		urb = unode->urb;
++
++		/* Free each separately allocated piece */
++		usb_buffer_free(urb->dev, dev->urbs.size,
++			urb->transfer_buffer, urb->transfer_dma);
++		usb_free_urb(urb);
++		kfree(node);
++	}
++
++	kref_put(&dev->kref, dlfb_delete);
++
++}
++
++static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size)
++{
++	int i = 0;
++	struct urb *urb;
++	struct urb_node *unode;
++	char *buf;
++
++	spin_lock_init(&dev->urbs.lock);
++
++	dev->urbs.size = size;
++	INIT_LIST_HEAD(&dev->urbs.list);
++
++	while (i < count) {
++		unode = kzalloc(sizeof(struct urb_node), GFP_KERNEL);
++		if (!unode)
++			break;
++		unode->dev = dev;
++
++		urb = usb_alloc_urb(0, GFP_KERNEL);
++		if (!urb) {
++			kfree(unode);
++			break;
++		}
++		unode->urb = urb;
++
++		buf = usb_buffer_alloc(dev->udev, MAX_TRANSFER, GFP_KERNEL,
++					&urb->transfer_dma);
++		if (!buf) {
++			kfree(unode);
++			usb_free_urb(urb);
++			break;
++		}
++
++		/* urb->transfer_buffer_length set to actual before submit */
++		usb_fill_bulk_urb(urb, dev->udev, usb_sndbulkpipe(dev->udev, 1),
++			buf, size, dlfb_urb_completion, unode);
++		urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
++
++		list_add_tail(&unode->entry, &dev->urbs.list);
++
++		i++;
++	}
++
++	sema_init(&dev->urbs.limit_sem, i);
++	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;
++}
++
++static struct urb *dlfb_get_urb(struct dlfb_data *dev)
++{
++	int ret = 0;
++	struct list_head *entry;
++	struct urb_node *unode;
++	struct urb *urb = NULL;
++	unsigned long flags;
++
++	/* Wait for an in-flight buffer to complete and get re-queued */
++	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);
++		goto error;
++	}
++
++	spin_lock_irqsave(&dev->urbs.lock, flags);
++
++	BUG_ON(list_empty(&dev->urbs.list)); /* reserved one with limit_sem */
++	entry = dev->urbs.list.next;
++	list_del_init(entry);
++	dev->urbs.available--;
++
++	spin_unlock_irqrestore(&dev->urbs.lock, flags);
++
++	unode = list_entry(entry, struct urb_node, entry);
++	urb = unode->urb;
++
++error:
++	return urb;
++}
++
++static int dlfb_submit_urb(struct dlfb_data *dev, struct urb *urb, size_t len)
++{
++	int ret;
++
++	BUG_ON(len > dev->urbs.size);
++
++	urb->transfer_buffer_length = len; /* set to actual payload len */
++	ret = usb_submit_urb(urb, GFP_KERNEL);
++	if (ret) {
++		dlfb_urb_completion(urb); /* because no one else will */
++		atomic_set(&dev->lost_pixels, 1);
++		dl_err("usb_submit_urb error %x\n", ret);
++	}
++	return ret;
++}
++
+ MODULE_AUTHOR("Roberto De Ioris <roberto at unbit.it>, "
+ 	      "Jaya Kumar <jayakumar.lkml at gmail.com>");
+ MODULE_DESCRIPTION(DRIVER_VERSION);
+diff --git a/drivers/staging/udlfb/udlfb.h b/drivers/staging/udlfb/udlfb.h
+index 15f3d3a..13f992f 100644
+--- a/drivers/staging/udlfb/udlfb.h
++++ b/drivers/staging/udlfb/udlfb.h
+@@ -5,16 +5,35 @@
+ #define BUF_HIGH_WATER_MARK	1024
+ #define BUF_SIZE		(64*1024)
+ 
++struct urb_node {
++	struct list_head entry;
++	struct dlfb_data *dev;
++	struct urb *urb;
++};
++
++struct urb_list {
++	struct list_head list;
++	spinlock_t lock;
++	struct semaphore limit_sem;
++	int available;
++	int count;
++	size_t size;
++};
++
+ struct dlfb_data {
+ 	struct usb_device *udev;
++	struct device *gdev; /* &udev->dev */
+ 	struct usb_interface *interface;
+ 	struct urb *tx_urb, *ctrl_urb;
+ 	struct usb_ctrlrequest dr;
+ 	struct fb_info *info;
++	struct urb_list urbs;
++	struct kref kref;
+ 	char *buf;
+ 	char *bufend;
+ 	char *backing_buffer;
+ 	struct mutex bulk_mutex;
++	atomic_t lost_pixels; /* 1 = a render op failed. Need screen refresh */
+ 	char edid[128];
+ 	int screen_size;
+ 	int line_length;
+@@ -29,6 +48,14 @@ struct dlfb_data {
+ #define NR_USB_REQUEST_I2C_SUB_IO 0x02
+ #define NR_USB_REQUEST_CHANNEL 0x12
+ 
++/* -BULK_SIZE as per usb-skeleton. Can we get full page and avoid overhead? */
++#define BULK_SIZE 512
++#define MAX_TRANSFER (PAGE_SIZE*16 - BULK_SIZE)
++#define WRITES_IN_FLIGHT (4)
++
++#define GET_URB_TIMEOUT	HZ
++#define FREE_URB_TIMEOUT (HZ*2)
++
+ static void dlfb_bulk_callback(struct urb *urb)
+ {
+ 	struct dlfb_data *dev_info = urb->context;
+@@ -72,4 +99,12 @@ static int dlfb_bulk_msg(struct dlfb_data *dev_info, int len)
+ 
+ #define dlfb_set_register insert_command
+ 
++#define dl_err(format, arg...) \
++	dev_err(dev->gdev, "dlfb: " format, ## arg)
++#define dl_warn(format, arg...) \
++	dev_warn(dev->gdev, "dlfb: " format, ## arg)
++#define dl_notice(format, arg...) \
++	dev_notice(dev->gdev, "dlfb: " format, ## arg)
++#define dl_info(format, arg...) \
++	dev_info(dev->gdev, "dlfb: " format, ## arg)
+ #endif

Added: dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-printk-cleanup.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-printk-cleanup.patch	Mon Jul  5 17:35:21 2010	(r15941)
@@ -0,0 +1,69 @@
+From: Bernie Thompson <bernie at plugable.com>
+Date: Mon, 15 Feb 2010 14:46:48 +0000 (-0800)
+Subject: Staging: udlfb: remove printk and small cleanup
+X-Git-Tag: v2.6.34-rc1~10^2~1^2~66
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=bd80816b2877879d36011815858c8681408cc625
+
+Staging: udlfb: remove printk and small cleanup
+
+Remove last remaining printk and clarify comments
+
+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 baad03a..8f6223c 100644
+--- a/drivers/staging/udlfb/udlfb.c
++++ b/drivers/staging/udlfb/udlfb.c
+@@ -83,8 +83,8 @@ static struct fb_deferred_io dlfb_defio;
+ #endif
+ 
+ /*
+- * Inserts a specific DisplayLink controller command into the provided
+- * buffer.
++ * All DisplayLink bulk operations start with 0xAF, followed by specific code
++ * All operations are written to buffers which then later get sent to device
+  */
+ static char *dlfb_set_register(char *buf, u8 reg, u8 val)
+ {
+@@ -129,6 +129,10 @@ static char *dlfb_set_base16bpp(char *wrptr, u32 base)
+ 	return dlfb_set_register(wrptr, 0x22, base);
+ }
+ 
++/*
++ * DisplayLink HW has separate 16bpp and 8bpp framebuffers.
++ * In 24bpp modes, the low 323 RGB bits go in the 8bpp framebuffer
++ */
+ static char *dlfb_set_base8bpp(char *wrptr, u32 base)
+ {
+ 	wrptr = dlfb_set_register(wrptr, 0x26, base >> 16);
+@@ -161,7 +165,7 @@ static char *dlfb_set_register_16be(char *wrptr, u8 reg, u16 value)
+  * same actual count. This makes sense once you read above a couple of
+  * times and think about it from a hardware perspective.
+  */
+-static u16 lfsr16(u16 actual_count)
++static u16 dlfb_lfsr16(u16 actual_count)
+ {
+ 	u32 lv = 0xFFFF; /* This is the lfsr value that the hw starts with */
+ 
+@@ -180,7 +184,7 @@ static u16 lfsr16(u16 actual_count)
+  */
+ static char *dlfb_set_register_lfsr16(char *wrptr, u8 reg, u16 value)
+ {
+-	return dlfb_set_register_16(wrptr, reg, lfsr16(value));
++	return dlfb_set_register_16(wrptr, reg, dlfb_lfsr16(value));
+ }
+ 
+ /*
+@@ -292,8 +296,9 @@ 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;
+ 
+-	printk("MMAP: %lu %u\n", offset + size, info->fix.smem_len);
++	dl_notice("MMAP: %lu %u\n", offset + size, info->fix.smem_len);
+ 
+ 	if (offset + size > info->fix.smem_len)
+ 		return -EINVAL;

Added: dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-reorg-function-order.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-reorg-function-order.patch	Mon Jul  5 17:35:21 2010	(r15941)
@@ -0,0 +1,129 @@
+From: Bernie Thompson <bernie at plugable.com>
+Date: Mon, 15 Feb 2010 14:45:49 +0000 (-0800)
+Subject: Staging: udlfb: reorganize function order
+X-Git-Tag: v2.6.34-rc1~10^2~1^2~74
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=cc403dc67d10b895fec14b837fa2a6cb6ee6c8bd
+
+Staging: udlfb: reorganize function order
+
+Reorganize the location of a few things to be closer to related code
+
+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 d2adfe4..3306bba 100644
+--- a/drivers/staging/udlfb/udlfb.c
++++ b/drivers/staging/udlfb/udlfb.c
+@@ -39,8 +39,17 @@ static struct fb_fix_screeninfo dlfb_fix = {
+ 	.accel =        FB_ACCEL_NONE,
+ };
+ 
+-#define NR_USB_REQUEST_I2C_SUB_IO 0x02
+-#define NR_USB_REQUEST_CHANNEL 0x12
++/*
++ * There are many DisplayLink-based products, all with unique PIDs. We are able
++ * to support all volume ones (circa 2009) with a single driver, so we match
++ * globally on VID. TODO: Probe() needs to detect when we might be running
++ * "future" chips, and bail on those, so a compatible driver can match.
++ */
++static struct usb_device_id id_table[] = {
++	{.idVendor = 0x17e9, .match_flags = USB_DEVICE_ID_MATCH_VENDOR,},
++	{},
++};
++MODULE_DEVICE_TABLE(usb, id_table);
+ 
+ /*
+  * Inserts a specific DisplayLink controller command into the provided
+@@ -252,24 +261,6 @@ error:
+ 	return retval;
+ }
+ 
+-/*
+- * This is necessary before we can communicate with the display controller.
+- */
+-static int dlfb_select_std_channel(struct dlfb_data *dev)
+-{
+-	int ret;
+-	u8 set_def_chn[] = {	   0x57, 0xCD, 0xDC, 0xA7,
+-				0x1C, 0x88, 0x5E, 0x15,
+-				0x60, 0xFE, 0xC6, 0x97,
+-				0x16, 0x3D, 0x47, 0xF2  };
+-
+-	ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
+-			NR_USB_REQUEST_CHANNEL,
+-			(USB_DIR_OUT | USB_TYPE_VENDOR), 0, 0,
+-			set_def_chn, sizeof(set_def_chn), USB_CTRL_SET_TIMEOUT);
+-	return ret;
+-}
+-
+ 
+ /*
+  * Query EDID from the handware, then hand it off to fbdev's edid parse
+@@ -325,18 +316,6 @@ struct dloarea {
+ 	int x2, y2;
+ };
+ 
+-/*
+- * There are many DisplayLink-based products, all with unique PIDs. We are able
+- * to support all volume ones (circa 2009) with a single driver, so we match
+- * globally on VID. TODO: Probe() needs to detect when we might be running
+- * "future" chips, and bail on those, so a compatible driver can match.
+- */
+-static struct usb_device_id id_table[] = {
+-	{.idVendor = 0x17e9, .match_flags = USB_DEVICE_ID_MATCH_VENDOR,},
+-	{},
+-};
+-MODULE_DEVICE_TABLE(usb, id_table);
+-
+ static struct usb_driver dlfb_driver;
+ 
+ /* thanks to Henrik Bjerregaard Pedersen for this function */
+@@ -888,7 +867,6 @@ static int dlfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
+ }
+ 
+ /* taken from vesafb */
+-
+ static int
+ dlfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ 	       unsigned blue, unsigned transp, struct fb_info *info)
+@@ -952,6 +930,24 @@ static struct fb_ops dlfb_ops = {
+ 	.fb_blank = dlfb_blank,
+ };
+ 
++/*
++ * This is necessary before we can communicate with the display controller.
++ */
++static int dlfb_select_std_channel(struct dlfb_data *dev)
++{
++	int ret;
++	u8 set_def_chn[] = {	   0x57, 0xCD, 0xDC, 0xA7,
++				0x1C, 0x88, 0x5E, 0x15,
++				0x60, 0xFE, 0xC6, 0x97,
++				0x16, 0x3D, 0x47, 0xF2  };
++
++	ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
++			NR_USB_REQUEST_CHANNEL,
++			(USB_DIR_OUT | USB_TYPE_VENDOR), 0, 0,
++			set_def_chn, sizeof(set_def_chn), USB_CTRL_SET_TIMEOUT);
++	return ret;
++}
++
+ static int dlfb_probe(struct usb_interface *interface,
+ 			const struct usb_device_id *id)
+ {
+diff --git a/drivers/staging/udlfb/udlfb.h b/drivers/staging/udlfb/udlfb.h
+index 245234b..15f3d3a 100644
+--- a/drivers/staging/udlfb/udlfb.h
++++ b/drivers/staging/udlfb/udlfb.h
+@@ -26,6 +26,9 @@ struct dlfb_data {
+ 	u32 pseudo_palette[256];
+ };
+ 
++#define NR_USB_REQUEST_I2C_SUB_IO 0x02
++#define NR_USB_REQUEST_CHANNEL 0x12
++
+ static void dlfb_bulk_callback(struct urb *urb)
+ {
+ 	struct dlfb_data *dev_info = urb->context;

Added: dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-rework-startup.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-rework-startup.patch	Mon Jul  5 17:35:21 2010	(r15941)
@@ -0,0 +1,522 @@
+From: Bernie Thompson <bernie at plugable.com>
+Date: Mon, 15 Feb 2010 14:46:13 +0000 (-0800)
+Subject: Staging: udlfb: Rework startup and teardown to fix race conditions
+X-Git-Tag: v2.6.34-rc1~10^2~1^2~70
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=2469d5dbcafe064859475a8aaf8da00ab33d440c
+
+Staging: udlfb: Rework startup and teardown to fix race conditions
+
+Rework probe to use refcounts and std functions
+
+Because the different parts of the driver (usb, fbdev) tear down
+in different orders, the driver previously could crash accessing
+data that had already been freed.  Refcounting system used to handle.
+
+Reworked probe to make use of refcounts, set mode using std fbops,
+and set up sysfs and pre-allocated urbs.
+
+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 01672df..8ee55c8 100644
+--- a/drivers/staging/udlfb/udlfb.c
++++ b/drivers/staging/udlfb/udlfb.c
+@@ -3,6 +3,7 @@
+  *
+  * Copyright (C) 2009 Roberto De Ioris <roberto at unbit.it>
+  * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml at gmail.com>
++ * Copyright (C) 2009 Bernie Thompson <bernie at plugable.com>
+  *
+  * This file is subject to the terms and conditions of the GNU General Public
+  * License v2. See the file COPYING in the main directory of this archive for
+@@ -27,10 +28,8 @@
+ 
+ #include "udlfb.h"
+ 
+-#define DRIVER_VERSION "DisplayLink Framebuffer Driver 0.4.1"
+-
+ static struct fb_fix_screeninfo dlfb_fix = {
+-	.id =           "displaylinkfb",
++	.id =           "udlfb",
+ 	.type =         FB_TYPE_PACKED_PIXELS,
+ 	.visual =       FB_VISUAL_TRUECOLOR,
+ 	.xpanstep =     0,
+@@ -39,6 +38,13 @@ static struct fb_fix_screeninfo dlfb_fix = {
+ 	.accel =        FB_ACCEL_NONE,
+ };
+ 
++static const u32 udlfb_info_flags = FBINFO_DEFAULT | FBINFO_READS_FAST |
++#ifdef FBINFO_VIRTFB
++		FBINFO_VIRTFB |
++#endif
++		FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT |
++		FBINFO_HWACCEL_COPYAREA | FBINFO_MISC_ALWAYS_SETPAR;
++
+ /*
+  * There are many DisplayLink-based products, all with unique PIDs. We are able
+  * to support all volume ones (circa 2009) with a single driver, so we match
+@@ -940,6 +946,29 @@ static void dlfb_delete(struct kref *kref)
+ }
+ 
+ /*
++ * 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)
++{
++	struct dlfb_data *dev = info->par;
++
++	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);
++
++	/* ref taken before register_framebuffer() for dlfb_data clients */
++	kref_put(&dev->kref, dlfb_delete);
++}
++
++/*
+  * Check whether a video mode is supported by the DisplayLink chip
+  * We start from monitor's modes, so don't need to filter that here
+  */
+@@ -966,6 +995,35 @@ static void dlfb_var_color_format(struct fb_var_screeninfo *var)
+ 	var->blue = blue;
+ }
+ 
++static int dlfb_ops_check_var(struct fb_var_screeninfo *var,
++				struct fb_info *info)
++{
++	struct fb_videomode mode;
++
++	/* TODO: support dynamically changing framebuffer size */
++	if ((var->xres * var->yres * 2) > info->fix.smem_len)
++		return -EINVAL;
++
++	/* set device-specific elements of var unrelated to mode */
++	dlfb_var_color_format(var);
++
++	fb_var_to_videomode(&mode, var);
++
++	if (!dlfb_is_valid_mode(&mode, info))
++		return -EINVAL;
++
++	return 0;
++}
++
++static int dlfb_ops_set_par(struct fb_info *info)
++{
++	struct dlfb_data *dev = info->par;
++
++	dl_notice("set_par mode %dx%d\n", info->var.xres, info->var.yres);
++
++	return dlfb_set_video_mode(dev, &info->var);
++}
++
+ static int dlfb_ops_blank(int blank_mode, struct fb_info *info)
+ {
+ 	struct dlfb_data *dev_info = info->par;
+@@ -985,6 +1043,7 @@ static int dlfb_ops_blank(int blank_mode, struct fb_info *info)
+ }
+ 
+ static struct fb_ops dlfb_ops = {
++	.owner = THIS_MODULE,
+ 	.fb_setcolreg = dlfb_ops_setcolreg,
+ 	.fb_fillrect = dlfb_ops_fillrect,
+ 	.fb_copyarea = dlfb_ops_copyarea,
+@@ -993,6 +1052,8 @@ static struct fb_ops dlfb_ops = {
+ 	.fb_ioctl = dlfb_ops_ioctl,
+ 	.fb_release = dlfb_ops_release,
+ 	.fb_blank = dlfb_ops_blank,
++	.fb_check_var = dlfb_ops_check_var,
++	.fb_set_par = dlfb_ops_set_par,
+ };
+ 
+ /*
+@@ -1222,37 +1283,48 @@ static int dlfb_select_std_channel(struct dlfb_data *dev)
+ 	return ret;
+ }
+ 
+-static int dlfb_probe(struct usb_interface *interface,
++
++static int dlfb_usb_probe(struct usb_interface *interface,
+ 			const struct usb_device_id *id)
+ {
+-	struct device *mydev;
+ 	struct usb_device *usbdev;
+ 	struct dlfb_data *dev;
+ 	struct fb_info *info;
+ 	int videomemorysize;
++	int i;
+ 	unsigned char *videomemory;
+ 	int retval = -ENOMEM;
+ 	struct fb_var_screeninfo *var;
+-	struct fb_bitfield red = { 11, 5, 0 };
+-	struct fb_bitfield green = { 5, 6, 0 };
+-	struct fb_bitfield blue = { 0, 5, 0 };
++	int registered = 0;
++	u16 *pix_framebuffer;
+ 
+-	usbdev = usb_get_dev(interface_to_usbdev(interface));
+-	mydev = &usbdev->dev;
++	/* usb initialization */
++
++	usbdev = interface_to_usbdev(interface);
+ 
+ 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ 	if (dev == NULL) {
+-		dev_err(mydev, "failed alloc of dev struct\n");
+-		goto err_devalloc;
++		err("dlfb_usb_probe: failed alloc of dev struct\n");
++		goto error;
+ 	}
+ 
++	/* 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*/
++
+ 	mutex_init(&dev->bulk_mutex);
++
+ 	dev->udev = usbdev;
+ 	dev->gdev = &usbdev->dev; /* our generic struct device * */
+-	dev->interface = interface;
+ 	usb_set_intfdata(interface, dev);
+ 
+-	dev_info(mydev, "dlfb_probe: setting up DisplayLink device\n");
++	if (!dlfb_alloc_urb_list(dev, WRITES_IN_FLIGHT, MAX_TRANSFER)) {
++		retval = -ENOMEM;
++		dl_err("dlfb_alloc_urb_list failed\n");
++		goto error;
++	}
++
++	mutex_init(&dev->fb_open_lock);
+ 
+ 	/*
+ 	 * TODO: replace single 64K buffer with buffer list
+@@ -1260,8 +1332,8 @@ static int dlfb_probe(struct usb_interface *interface,
+ 	 */
+ 	dev->buf = kmalloc(BUF_SIZE, GFP_KERNEL);
+ 	if (dev->buf == NULL) {
+-		dev_err(mydev, "unable to allocate memory for dlfb commands\n");
+-		goto err_usballoc;
++		dl_err("unable to allocate memory for dlfb commands\n");
++		goto error;
+ 	}
+ 	dev->bufend = dev->buf + BUF_SIZE;
+ 
+@@ -1270,49 +1342,51 @@ static int dlfb_probe(struct usb_interface *interface,
+ 			  usb_sndbulkpipe(dev->udev, 1), dev->buf, 0,
+ 			  dlfb_bulk_callback, dev);
+ 
+-	/* allocates framebuffer driver structure, not framebuffer memory */
+-	info = framebuffer_alloc(0, mydev);
+-	if (!info)
+-		goto err_fballoc;
++	/* We don't register a new USB class. Our client interface is fbdev */
+ 
++	/* allocates framebuffer driver structure, not framebuffer memory */
++	info = framebuffer_alloc(0, &usbdev->dev);
++	if (!info) {
++		retval = -ENOMEM;
++		dl_err("framebuffer_alloc failed\n");
++		goto error;
++	}
+ 	dev->info = info;
+ 	info->par = dev;
+ 	info->pseudo_palette = dev->pseudo_palette;
++	info->fbops = &dlfb_ops;
+ 
+ 	var = &info->var;
+-	retval = dlfb_get_var_from_edid(dev, var);
+-	if (retval) {
+-		/* had a problem getting edid. so fallback to 640x480 */
+-		dev_err(mydev, "Problem %d with EDID.\n", retval);
+-		var->xres = 640;
+-		var->yres = 480;
+-	}
++
++	/* 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.
+-	 * We are using 16bpp.
+ 	 */
+-	info->var.bits_per_pixel = 16;
+ 	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.
+-	 * Pages don't need to be set RESERVED (non-swap) immediately on 2.6
+-	 * remap_pfn_page() syscall in our mmap and/or defio will handle.
++	 * TODO: Handle fbcon cursor code calling blit in interrupt context
+ 	 */
+ 	videomemory = vmalloc(videomemorysize);
+-	if (!videomemory)
+-		goto err_vidmem;
+-	memset(videomemory, 0, 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 =
+-	    FBINFO_DEFAULT | FBINFO_READS_FAST | FBINFO_HWACCEL_IMAGEBLIT |
+-	    FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
++	info->flags = udlfb_info_flags;
++
+ 
+ 	/*
+ 	 * Second framebuffer copy, mirroring the state of the framebuffer
+@@ -1320,109 +1394,121 @@ static int dlfb_probe(struct usb_interface *interface,
+ 	 * 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(dev->screen_size);
++	dev->backing_buffer = vmalloc(videomemorysize);
+ 	if (!dev->backing_buffer)
+-		dev_info(mydev, "No backing buffer allocated!\n");
++		dl_warn("No shadow/backing buffer allcoated\n");
++	else
++		memset(dev->backing_buffer, 0, videomemorysize);
+ 
+-	info->fbops = &dlfb_ops;
++	retval = fb_alloc_cmap(&info->cmap, 256, 0);
++	if (retval < 0) {
++		dl_err("fb_alloc_cmap failed %x\n", retval);
++		goto error;
++	}
+ 
+-	var->vmode = FB_VMODE_NONINTERLACED;
+-	var->red = red;
+-	var->green = green;
+-	var->blue = blue;
++	/* ready to begin using device */
+ 
+-	/*
+-	 * TODO: Enable FB_CONFIG_DEFIO support
++/*
++#ifdef CONFIG_FB_DEFERRED_IO
++	atomic_set(&dev->use_defio, 1);
++#endif
++*/
++	atomic_set(&dev->usb_active, 1);
++	dlfb_select_std_channel(dev);
+ 
+-	 info->fbdefio = &dlfb_defio;
+-	 fb_deferred_io_init(info);
++	dlfb_ops_check_var(var, info);
++	dlfb_ops_set_par(info);
+ 
+-	 */
++	/* paint greenscreen */
++/*
++	pix_framebuffer = (u16 *) videomemory;
++	for (i = 0; i < videomemorysize / 2; i++)
++		pix_framebuffer[i] = 0x37e6;
+ 
+-	retval = fb_alloc_cmap(&info->cmap, 256, 0);
++	dlfb_handle_damage(dev, 0, 0, info->var.xres, info->var.yres,
++				videomemory);
++*/
++	retval = register_framebuffer(info);
+ 	if (retval < 0) {
+-		dev_err(mydev, "Failed to allocate colormap\n");
+-		goto err_cmap;
++		dl_err("register_framebuffer failed %d\n", retval);
++		goto error;
+ 	}
++	registered = 1;
+ 
+-	dlfb_select_std_channel(dev);
+-	dlfb_set_video_mode(dev, var);
+-	/* TODO: dlfb_dpy_update(dev); */
+-
+-	retval = register_framebuffer(info);
+-	if (retval < 0)
+-		goto err_regfb;
++	for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
++		device_create_file(info->dev, &fb_device_attrs[i]);
+ 
+-	/* paint "successful" green screen */
+-	draw_rect(dev, 0, 0, dev->info->var.xres,
+-		  dev->info->var.yres, 0x30, 0xff, 0x30);
++	device_create_bin_file(info->dev, &edid_attr);
+ 
+-	dev_info(mydev, "DisplayLink USB device %d now attached, "
+-			"using %dK of memory\n", info->node,
+-		 ((dev->backing_buffer) ?
+-		  videomemorysize * 2 : videomemorysize) >> 10);
++	dl_err("DisplayLink USB device /dev/fb%d attached. %dx%d resolution."
++			" Using %dK framebuffer memory\n", info->node,
++			var->xres, var->yres,
++			((dev->backing_buffer) ?
++			videomemorysize * 2 : videomemorysize) >> 10);
+ 	return 0;
+ 
+-err_regfb:
+-	fb_dealloc_cmap(&info->cmap);
+-err_cmap:
+-	/* TODO: fb_deferred_io_cleanup(info); */
+-	vfree(videomemory);
+-err_vidmem:
+-	framebuffer_release(info);
+-err_fballoc:
+-	kfree(dev->buf);
+-err_usballoc:
+-	usb_set_intfdata(interface, NULL);
+-	usb_put_dev(dev->udev);
+-	kfree(dev);
+-err_devalloc:
++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 */
++
++		/* dev has been deallocated. Do not dereference */
++	}
++
+ 	return retval;
+ }
+ 
+-static void dlfb_disconnect(struct usb_interface *interface)
++static void dlfb_usb_disconnect(struct usb_interface *interface)
+ {
+ 	struct dlfb_data *dev;
+ 	struct fb_info *info;
++	int i;
+ 
+ 	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);
++
+ 	usb_set_intfdata(interface, NULL);
+-	usb_put_dev(dev->udev);
+ 
+-	/*
+-	 * TODO: since, upon usb disconnect(), usb will cancel in-flight urbs
+-	 * and error out any new ones, look at eliminating need for mutex
+-	 */
+-	mutex_lock(&dev->bulk_mutex);
+-	dev->interface = NULL;
+-	info = dev->info;
+-	mutex_unlock(&dev->bulk_mutex);
++	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);
+ 
+ 	if (info) {
+-		dev_info(&interface->dev, "Detaching DisplayLink device %d.\n",
+-						info->node);
++		dl_notice("Detaching /dev/fb%d\n", info->node);
+ 		unregister_framebuffer(info);
+-		fb_dealloc_cmap(&info->cmap);
+-		/* TODO: fb_deferred_io_cleanup(info); */
+-		fb_dealloc_cmap(&info->cmap);
+-		vfree((void __force *)info->screen_base);
+-		framebuffer_release(info);
++		dlfb_ops_destroy(info);
+ 	}
+ 
+-	if (dev->backing_buffer)
+-		vfree(dev->backing_buffer);
++	/* release reference taken by kref_init in probe() */
++	kref_put(&dev->kref, dlfb_delete);
+ 
+-	kfree(dev);
++	/* consider dlfb_data freed */
++
++	return;
+ }
+ 
+ static struct usb_driver dlfb_driver = {
+ 	.name = "udlfb",
+-	.probe = dlfb_probe,
+-	.disconnect = dlfb_disconnect,
++	.probe = dlfb_usb_probe,
++	.disconnect = dlfb_usb_disconnect,
+ 	.id_table = id_table,
+ };
+ 
+-static int __init dlfb_init(void)
++static int __init dlfb_module_init(void)
+ {
+ 	int res;
+ 
+@@ -1435,13 +1521,13 @@ static int __init dlfb_init(void)
+ 	return res;
+ }
+ 
+-static void __exit dlfb_exit(void)
++static void __exit dlfb_module_exit(void)
+ {
+ 	usb_deregister(&dlfb_driver);
+ }
+ 
+-module_init(dlfb_init);
+-module_exit(dlfb_exit);
++module_init(dlfb_module_init);
++module_exit(dlfb_module_exit);
+ 
+ static void dlfb_urb_completion(struct urb *urb)
+ {
+@@ -1613,6 +1699,8 @@ static int dlfb_submit_urb(struct dlfb_data *dev, struct urb *urb, size_t len)
+ }
+ 
+ MODULE_AUTHOR("Roberto De Ioris <roberto at unbit.it>, "
+-	      "Jaya Kumar <jayakumar.lkml at gmail.com>");
+-MODULE_DESCRIPTION(DRIVER_VERSION);
++	      "Jaya Kumar <jayakumar.lkml at gmail.com>, "
++	      "Bernie Thompson <bernie at plugable.com>");
++MODULE_DESCRIPTION("DisplayLink kernel framebuffer driver");
+ MODULE_LICENSE("GPL");
++
+diff --git a/drivers/staging/udlfb/udlfb.h b/drivers/staging/udlfb/udlfb.h
+index ef343a6..e6c68c6 100644
+--- a/drivers/staging/udlfb/udlfb.h
++++ b/drivers/staging/udlfb/udlfb.h
+@@ -25,13 +25,14 @@ struct dlfb_data {
+ 	struct device *gdev; /* &udev->dev */
+ 	struct usb_interface *interface;
+ 	struct urb *tx_urb, *ctrl_urb;
+-	struct usb_ctrlrequest dr;
+ 	struct fb_info *info;
+ 	struct urb_list urbs;
+ 	struct kref kref;
+ 	char *buf;
+ 	char *bufend;
+ 	char *backing_buffer;
++	struct delayed_work deferred_work;
++	struct mutex fb_open_lock;
+ 	struct mutex bulk_mutex;
+ 	int fb_count;
+ 	atomic_t usb_active; /* 0 = update virtual buffer, but no usb traffic */

Added: dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-support-fbdev-mmap-clients.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-support-fbdev-mmap-clients.patch	Mon Jul  5 17:35:21 2010	(r15941)
@@ -0,0 +1,209 @@
+From: Bernie Thompson <bernie at plugable.com>
+Date: Mon, 15 Feb 2010 14:46:26 +0000 (-0800)
+Subject: Staging: udlfb: Support for fbdev mmap clients (defio)
+X-Git-Tag: v2.6.34-rc1~10^2~1^2~68
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=3e8f3d6fa672896096068296658a769649186150
+
+Staging: udlfb: Support for fbdev mmap clients (defio)
+
+Add support for fbdev mmap clients who don't send damage ioctls
+
+Because DisplayLink devices are out on the other end of usb, their
+"framebuffer" is just normal system memory. So memory mapped writes
+don't automatically trigger anything. So up to this point, standard
+fbdev clients who rely on mmap() will get an unchanging screen.
+
+This patch makes udlfb a client of Jaya Kumar's defio framework - which sets
+up page fault triggers, and those faults are accumulated and sent to udlfb
+on a defferred basis, to process as damage notifications for the framebuffer.
+
+Because this involves more overhead than a notification directly from
+the application (e.g. just passing on X DAMAGE extension notifications),
+a sysfs attribute is provided by udlfb to control defio support.
+
+/sys/class/graphics/fb*/use_defio - writing a "0" to this file before
+calling mmap() causes defio to not be initialized - instead udlfb
+will rely on getting damage notifications directly through the damage ioctl.
+
+There are unsolved rendering problems with defio (horizontal dead regions
+on framebuffer, that accumulate over time) which still needs a fix.
+
+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 22f3dc3..939b8fa 100644
+--- a/drivers/staging/udlfb/udlfb.c
++++ b/drivers/staging/udlfb/udlfb.c
+@@ -63,6 +63,11 @@ 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
++
+ /*
+  * Inserts a specific DisplayLink controller command into the provided
+  * buffer.
+@@ -717,9 +722,59 @@ dlfb_ops_setcolreg(unsigned regno, unsigned red, unsigned green,
+ 	return err;
+ }
+ 
++/*
++ * It's common for several clients to have framebuffer open simultaneously.
++ * e.g. both fbcon and X. Makes things interesting.
++ */
++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
++ */
++
++	mutex_lock(&dev->fb_open_lock);
++
++	dev->fb_count++;
++
++#ifdef CONFIG_FB_DEFERRED_IO
++	if ((atomic_read(&dev->use_defio)) && (info->fbdefio == NULL)) {
++		/* enable defio */
++		info->fbdefio = &dlfb_defio;
++		fb_deferred_io_init(info);
++	}
++#endif
++
++	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 = info->par;
++	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;
+ }
+ 
+@@ -735,6 +790,8 @@ static void dlfb_delete(struct kref *kref)
+ 	if (dev->backing_buffer)
+ 		vfree(dev->backing_buffer);
+ 
++	mutex_destroy(&dev->fb_open_lock);
++
+ 	kfree(dev);
+ }
+ 
+@@ -853,6 +910,7 @@ static struct fb_ops dlfb_ops = {
+ 	.fb_imageblit = dlfb_ops_imageblit,
+ 	.fb_mmap = dlfb_ops_mmap,
+ 	.fb_ioctl = dlfb_ops_ioctl,
++	.fb_open = dlfb_ops_open,
+ 	.fb_release = dlfb_ops_release,
+ 	.fb_blank = dlfb_ops_blank,
+ 	.fb_check_var = dlfb_ops_check_var,
+@@ -1068,6 +1126,68 @@ static struct device_attribute fb_device_attrs[] = {
+ 	__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;
++	int fault_count = 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;
++		fault_count++;
++	}
++
++	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(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);
++	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,
++	.deferred_io    = dlfb_dpy_deferred_io,
++};
++
++#endif
++
+ /*
+  * This is necessary before we can communicate with the display controller.
+  */
+@@ -1193,11 +1313,9 @@ 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);
+ 

Added: dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-sysfs-expose-metrics.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/udlfb/udlfb-sysfs-expose-metrics.patch	Mon Jul  5 17:35:21 2010	(r15941)
@@ -0,0 +1,349 @@
+From: Bernie Thompson <bernie at plugable.com>
+Date: Mon, 15 Feb 2010 14:46:08 +0000 (-0800)
+Subject: Staging: udlfb: Add functions to expose sysfs metrics and controls
+X-Git-Tag: v2.6.34-rc1~10^2~1^2~71
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=7d9485e2c53caaaed9606a39de1c2746cc9ba262
+
+Staging: udlfb: Add functions to expose sysfs metrics and controls
+
+Add sysfs controls for edid and performance metrics
+
+There are 8 new files exposed in /sys/class/graphics/fb*
+
+edid - returns 128 byte edid blog, suitable for parsing with parse-edid
+metrics_bytes_identical
+metrics_bytes_rendered
+metrics_bytes_sent
+metrics_cpu_kcycles_used
+metrics_misc
+and metrics_reset, which resets all perf metrics to zero
+
+The 6 perf metrics are of type atomic_t.
+So these metrics return precise results for short benchmarks, but
+any test approx a minute or longer runtime may roll over.
+
+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 8d8372f..01672df 100644
+--- a/drivers/staging/udlfb/udlfb.c
++++ b/drivers/staging/udlfb/udlfb.c
+@@ -818,6 +818,21 @@ static void dlfb_ops_fillrect(struct fb_info *info,
+ 
+ }
+ 
++static void dlfb_get_edid(struct dlfb_data *dev)
++{
++	int i;
++	int ret;
++	char rbuf[2];
++
++	for (i = 0; i < sizeof(dev->edid); 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];
++	}
++}
++
+ static int dlfb_ops_ioctl(struct fb_info *info, unsigned int cmd,
+ 			unsigned long arg)
+ {
+@@ -924,6 +939,33 @@ static void dlfb_delete(struct kref *kref)
+ 	kfree(dev);
+ }
+ 
++/*
++ * Check whether a video mode is supported by the DisplayLink chip
++ * We start from monitor's modes, so don't need to filter that here
++ */
++static int dlfb_is_valid_mode(struct fb_videomode *mode,
++		struct fb_info *info)
++{
++	struct dlfb_data *dev = info->par;
++
++	if (mode->xres * mode->yres > dev->sku_pixel_limit)
++		return 0;
++
++	return 1;
++}
++
++static void dlfb_var_color_format(struct fb_var_screeninfo *var)
++{
++	const struct fb_bitfield red = { 11, 5, 0 };
++	const struct fb_bitfield green = { 5, 6, 0 };
++	const struct fb_bitfield blue = { 0, 5, 0 };
++
++	var->bits_per_pixel = 16;
++	var->red = red;
++	var->green = green;
++	var->blue = blue;
++}
++
+ static int dlfb_ops_blank(int blank_mode, struct fb_info *info)
+ {
+ 	struct dlfb_data *dev_info = info->par;
+@@ -954,6 +996,215 @@ static struct fb_ops dlfb_ops = {
+ };
+ 
+ /*
++ * 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:
++ * 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
++ */
++static int dlfb_parse_edid(struct dlfb_data *dev,
++			    struct fb_var_screeninfo *var,
++			    struct fb_info *info)
++{
++	int i;
++	const struct fb_videomode *default_vmode = NULL;
++	int result = 0;
++
++	fb_destroy_modelist(&info->modelist);
++	memset(&info->monspecs, 0, sizeof(info->monspecs));
++
++	dlfb_get_edid(dev);
++	fb_edid_to_monspecs(dev->edid, &info->monspecs);
++
++	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);
++		}
++
++		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;
++
++		/*
++		 * Add the standard VESA modes to our modelist
++		 * Since we don't have EDID, there may be modes that
++		 * overspec monitor and/or are incorrect aspect ratio, etc.
++		 * But at least the user has a chance to choose
++		 */
++		for (i = 0; i < VESA_MODEDB_SIZE; i++) {
++			if (dlfb_is_valid_mode((struct fb_videomode *)
++						&vesa_modes[i], info))
++				fb_add_videomode(&vesa_modes[i],
++						 &info->modelist);
++		}
++
++		/*
++		 * default to resolution safe for projectors
++		 * (since they are most common case without EDID)
++		 */
++		fb_vmode.xres = 800;
++		fb_vmode.yres = 600;
++		fb_vmode.refresh = 60;
++		default_vmode = fb_find_nearest_mode(&fb_vmode,
++						     &info->modelist);
++	}
++
++	fb_videomode_to_var(var, default_vmode);
++	dlfb_var_color_format(var);
++
++	return result;
++}
++
++static ssize_t metrics_bytes_rendered_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, "%u\n",
++			atomic_read(&dev->bytes_rendered));
++}
++
++static ssize_t metrics_bytes_identical_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, "%u\n",
++			atomic_read(&dev->bytes_identical));
++}
++
++static ssize_t metrics_bytes_sent_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, "%u\n",
++			atomic_read(&dev->bytes_sent));
++}
++
++static ssize_t metrics_cpu_kcycles_used_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, "%u\n",
++			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);
++	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))
++		return 0;
++
++	if (off >= size)
++		return 0;
++
++	if (off + count > size)
++		count = size - off;
++	memcpy(buf, edid + off, count);
++
++	return count;
++}
++
++
++static ssize_t metrics_reset_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;
++
++	atomic_set(&dev->bytes_rendered, 0);
++	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;
++}
++
++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 = 0444,
++	.size = 128,
++	.read = edid_show,
++};
++
++static struct device_attribute fb_device_attrs[] = {
++	__ATTR_RO(metrics_bytes_rendered),
++	__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),
++};
++
++/*
+  * This is necessary before we can communicate with the display controller.
+  */
+ static int dlfb_select_std_channel(struct dlfb_data *dev)
+diff --git a/drivers/staging/udlfb/udlfb.h b/drivers/staging/udlfb/udlfb.h
+index 13f992f..ef343a6 100644
+--- a/drivers/staging/udlfb/udlfb.h
++++ b/drivers/staging/udlfb/udlfb.h
+@@ -33,8 +33,12 @@ struct dlfb_data {
+ 	char *bufend;
+ 	char *backing_buffer;
+ 	struct mutex bulk_mutex;
++	int fb_count;
++	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];
++	int sku_pixel_limit;
+ 	int screen_size;
+ 	int line_length;
+ 	struct completion done;
+@@ -43,6 +47,17 @@ struct dlfb_data {
+ 	int base8;
+ 	int base8d;
+ 	u32 pseudo_palette[256];
++	/* blit-only rendering path metrics, exposed through sysfs */
++	atomic_t bytes_rendered; /* raw pixel-bytes driver asked to render */
++	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
+@@ -99,6 +114,9 @@ static int dlfb_bulk_msg(struct dlfb_data *dev_info, int len)
+ 
+ #define dlfb_set_register insert_command
+ 
++/* remove once this gets added to sysfs.h */
++#define __ATTR_RW(attr) __ATTR(attr, 0644, attr##_show, attr##_store)
++
+ #define dl_err(format, arg...) \
+ 	dev_err(dev->gdev, "dlfb: " format, ## arg)
+ #define dl_warn(format, arg...) \

Modified: dists/sid/linux-2.6/debian/patches/series/16
==============================================================================
--- dists/sid/linux-2.6/debian/patches/series/16	Mon Jul  5 12:04:57 2010	(r15940)
+++ dists/sid/linux-2.6/debian/patches/series/16	Mon Jul  5 17:35:21 2010	(r15941)
@@ -197,3 +197,14 @@
 + bugfix/all/rtl8192u-dont-use-mhard-float.patch
 + bugfix/all/rtl8192u-Check-kmalloc-return-value.patch
 + debian/dfsg/rtl8192u_usb-Remove-code-for-using-built-in-firmware.patch
++ features/all/udlfb/udlfb-add_dynamic_modeset_support.patch
++ features/all/udlfb/udlfb-checkpatch-cleanup.patch
++ features/all/udlfb/udlfb-reorg-function-order.patch
++ features/all/udlfb/udlfb-preallocated-urb-list-helpers.patch
++ features/all/udlfb/udlfb-cleanup-function-naming.patch
++ features/all/udlfb/udlfb-sysfs-expose-metrics.patch
++ features/all/udlfb/udlfb-rework-startup.patch
++ features/all/udlfb/udlfb-improve-rendering-performance.patch
++ features/all/udlfb/udlfb-support-fbdev-mmap-clients.patch
++ features/all/udlfb/udlfb-explicit-warnings-and-deps.patch
++ features/all/udlfb/udlfb-printk-cleanup.patch



More information about the Kernel-svn-changes mailing list