Update DisplayLink (udlfb) driver

svn path=/dists/sid/linux-2.6/; revision=15941
This commit is contained in:
Martin Michlmayr 2010-07-05 17:35:21 +00:00
parent 38d228ecd9
commit f066741cf5
13 changed files with 4379 additions and 0 deletions

12
debian/changelog vendored
View File

@ -90,6 +90,18 @@ linux-2.6 (2.6.32-16) UNRELEASED; urgency=low
- 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

View File

@ -0,0 +1,975 @@
From: Bernie Thompson <bernie@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 monitors preferred mode
udlfb no longer has fixed mode tables its 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@plugable.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@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@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@unbit.it>
+ * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@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@unbit.it>");
+MODULE_AUTHOR("Roberto De Ioris <roberto@unbit.it>, "
+ "Jaya Kumar <jayakumar.lkml@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

View File

@ -0,0 +1,223 @@
From: Bernie Thompson <bernie@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@plugable.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@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];
}

View File

@ -0,0 +1,323 @@
From: Bernie Thompson <bernie@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@plugable.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@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,
};
/*

View File

@ -0,0 +1,72 @@
From: Bernie Thompson <bernie@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@plugable.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@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);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,311 @@
From: Bernie Thompson <bernie@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@plugable.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@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@unbit.it>, "
"Jaya Kumar <jayakumar.lkml@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

View File

@ -0,0 +1,69 @@
From: Bernie Thompson <bernie@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@plugable.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@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;

View File

@ -0,0 +1,129 @@
From: Bernie Thompson <bernie@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@plugable.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@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;

View File

@ -0,0 +1,522 @@
From: Bernie Thompson <bernie@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@plugable.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@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@unbit.it>
* Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com>
+ * Copyright (C) 2009 Bernie Thompson <bernie@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@unbit.it>, "
- "Jaya Kumar <jayakumar.lkml@gmail.com>");
-MODULE_DESCRIPTION(DRIVER_VERSION);
+ "Jaya Kumar <jayakumar.lkml@gmail.com>, "
+ "Bernie Thompson <bernie@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 */

View File

@ -0,0 +1,209 @@
From: Bernie Thompson <bernie@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@plugable.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@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);

View File

@ -0,0 +1,349 @@
From: Bernie Thompson <bernie@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@plugable.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@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...) \

View File

@ -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