[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, ®ion->color, 1);
+- memcpy(&green, ®ion->color + 1, 1);
+- memcpy(&blue, ®ion->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