Update DisplayLink (udlfb) driver
svn path=/dists/sid/linux-2.6/; revision=15941
This commit is contained in:
parent
38d228ecd9
commit
f066741cf5
|
@ -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
|
||||
|
|
|
@ -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 monitor’s preferred mode
|
||||
udlfb no longer has fixed mode tables – it’s able to set any mode
|
||||
dynamically, from the standard VESA timing characteristics of the monitor.
|
||||
|
||||
Draws from probe and setmode code of both displaylink-mod 0.3 branch of
|
||||
Roberto De Ioris, and Jaya Kumar's displaylinkfb.
|
||||
Lays foundation for defio support and making backbuffer optional.
|
||||
With additional changes to minimize diffs and clean for checkpatch.pl style.
|
||||
|
||||
Does not yet include new ioctls or refcount/mutex code from displaylink-mod.
|
||||
|
||||
Tested to work with existing xf-video-displaylink X server unmodified.
|
||||
|
||||
Signed-off-by: Bernie Thompson <bernie@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
|
|
@ -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];
|
||||
}
|
||||
|
|
@ -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,
|
||||
};
|
||||
|
||||
/*
|
|
@ -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);
|
1174
debian/patches/features/all/udlfb/udlfb-improve-rendering-performance.patch
vendored
Normal file
1174
debian/patches/features/all/udlfb/udlfb-improve-rendering-performance.patch
vendored
Normal file
File diff suppressed because it is too large
Load Diff
311
debian/patches/features/all/udlfb/udlfb-preallocated-urb-list-helpers.patch
vendored
Normal file
311
debian/patches/features/all/udlfb/udlfb-preallocated-urb-list-helpers.patch
vendored
Normal 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
|
|
@ -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;
|
|
@ -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;
|
|
@ -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 */
|
|
@ -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);
|
||||
|
|
@ -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...) \
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue