GPL re-contributed code from Endurance Technology, based on ~Dec 1999 endurance-centos
GPL re-contributed code from Endurance Technology, based on ~Dec 1999
udlfb 0.40 codebase. Output of a project to get DisplayLink-attached
LVDS panel device working under CentOS 5.3.
While none of this is going directly into udlfb at this time,
getting it checked into a branch off the closest matching udlfb code
I could find, to make inspecting diffs as easy as possible.
Thank you to Endurance Technology http://endurancetech.co.uk/

file:Endurance-Centos-ReleaseNote.txt(new)
--- /dev/null +++ b/Endurance-Centos-ReleaseNote.txt @@ -0,0 +1,179 @@ +DisplayLink Driver for CentOS +============================= + + +Description +=========== + +This software should be installed into a CentOS 5.3 system. The supplied xorg.conf +assumes an Intel based graphics system, but there are also examples for Nvidia. + + +Installation +============ + +Full installation +----------------- + +The following steps should be taken to install the driver package: + +1. Copy the existing xorg.conf file + + 1.1. $ sudo mv /etc/X11/xorg.conf /etc/X11/xorg.conf.old + +2. Install the driver package: + + 2.1. plug in the DisplayLink device + 2.2. build and install the FBDisplaylink driver + 2.3. build and install the XorgDisplaylink software + +3. $ sudo /sbin/depmod -a + +At this point the screen attached to the DisplayLink device should go red +indicating that the FBDisplaylink kernel driver has loaded. + +4. Edit the new xorg.conf to select the display configuration: + + 4.1. $ sudo emacs /etc/X11/xorg.conf + +At the bottom of this file are the following configration statements: + + +############################################################## +# +# Screen layout +# +Section "ServerLayout" + Identifier "Multihead nvidia" + Screen 0 "nvidiaPrimaryScreen" Absolute 0 0 + Screen 1 "DLScreen" RightOf "nvidiaPrimaryScreen" + Option "Xinerama" "true" +EndSection + +Section "ServerLayout" + Identifier "Multihead nvidia cloned" + Screen 0 "nvidiaPrimaryScreen" Absolute 0 0 + Screen 1 "DLScreen" RightOf "nvidiaPrimaryScreen" + Option "Clone" "on" + Option "Xinerama" "false" +EndSection + +Section "ServerLayout" + Identifier "Multihead intel" + Screen 0 "intelPrimaryScreen" Absolute 0 0 + Screen 1 "DLScreen" RightOf "intelPrimaryScreen" + Option "Xinerama" "true" +EndSection + +Section "ServerLayout" + Identifier "Multihead intel cloned" + Screen 0 "intelPrimaryScreen" Absolute 0 0 + Screen 1 "DLScreen" RightOf "intelPrimaryScreen" + Option "Clone" "on" + Option "Xinerama" "false" +EndSection + +############################################################## +# +# Screen layout selection +# +Section "ServerFlags" + Option "DefaultServerLayout" "Multihead intel" +EndSection + + +These config lines define 4 different screen configurations two for an nvidia +primary display adapter and two for an Intel primary diplay adapter. + +1. Multihead nvidia +2. Multihead Intel + +Both screens are configured to appear as a single desktop. Windows can be +moved between the screens. + +3. Multihead Nvidia cloned +4. Multihead Intel cloned + +The screens act as seperate screens each with their own toolbars. + +The Display layout to use is selcted by the line: + + Option "DefaultServerLayout" "Multihead intel" + +Here configuration 2 above is selected. To select a different layout replace +the text with the name of the layout, e.g. + + Option "DefaultServerLayout" "Multihead nvidia" + +5. Load the X display driver + + +No Hotplug Support for DislpayLink device +========================================= + +X windows does not autosense the presence of a new display adapter. To make +use of the new DisplayLink adapter we have just installed we need to restart +the X server. This can be achieved in two ways. + +1. Reboot + +or: + +2. Logout and login again + + +Troubleshooting +=============== + +CentOS is fairly primative in its handling of a broken xorg.conf file. If you +do break the configuration and end up with a black screen you need to boot to +a console from which you can edit the xorg.conf file. This is achieved by the +following: + +1. Reboot the pc but do not allow it to boot as we need to edit the kernel +parameters. + +2. Press 'e' to allow you to edit the boot configuration + +3. Edit the line beginning with kernel by adding a 3 at the rightmost end +This final parameter is not processed by the kernel but is handed to the +first process started. Which in our case is init.exe. This process controls +which programmes are started. Level 3 is console mode. + +4. Press 'b' to boot with the edited boot commands + +5. Login as root and edit xorg.conf + +6. start the x server. There are two otions here: + + 6.1. # /sbin/shutdown -r now <- this will reboot + + 6.2. # /sbin/telinit 5 <- this should instruct init to move to + level 5 which amongst other things starts + X. I have fould with CentOS that this + command is sometimes ignored in which case + option 6.1 is required. you need to be root + to issue this command. + +The edited boot configuration is not permanant and will be forgotten. + + +Caveats +======= + +The following caveats should be noted: + +* Displays are not cloned at present as X is unable to clone between + different adapters. + +* Driver only runs in a 16 bpp colour depth. + +* No USB hot-plugging support. The monitor can be hot plugged but the USB + device cannot. You should boot the system with the DisplayLink device + already connected to the USB bus. + +* Primary display is assumed to be the capable of being driven by either the + OSS "nv" or "i810" Xorg display drivers - most popular monitors should be + fine with this. + +-- Endurance Technology, 15th Apr 2010
file:Endurance-Readme.txt(new)
--- /dev/null +++ b/Endurance-Readme.txt @@ -0,0 +1,36 @@ +---------- Forwarded message ---------- +From: Steve (Endurance) <srevill@endurancetech.co.uk> +Date: Thu, Apr 15, 2010 at 10:19 AM +Subject: Various updates for your consideration +To: Bernie Thompson <bernie@plugable.com> +Cc: "Richard Nicoll (Endurance)" <rnicoll@endurancetech.co.uk>, "Tony Davis (Endurance)" <tdavis@endurancetech.co.uk> + + +Hi Bernie, + +Please find attached the software we've made some changes to and an +associated release note. Our intention was to get an embedded DL device to +work with CentOS 5.3, having both the USB display adapter and native (Intel) +adapter working at the same time (in various modes). We've mostly tweaked +around the edges to make the software a bit more robust and tidy. + +This was based upon version 0.1 of the Linux framebuffer driver (merge of +Roberto and Jaya's drivers with enhancements) and the XorgDisplaylink +sources from Roberto De Ioris. + +If you could get this stuff published as-is somewhere with credit to +Endurance, then feel free to pick and merge stuff as you like into other +strands of development. I don't think there will be too much to diff. + +Let me know if you need any more info. + +Thanks for your help, + +Steve + +-- +Stephen Revill, Technical Project Leader Tel: +44 (0) 1353 740 267 +Endurance Technology Ltd Fax: +44 (0) 87 1251 7002 +5 Marine Drive West, Bognor Regis, http://www.endurancetech.co.uk/ +West Sussex, PO21 2QA, UK Registered in England No. 04372566 + VAT Registration No. GB 794 5274 86
file:a/udlfb.c -> file:b/udlfb.c
--- a/udlfb.c +++ b/udlfb.c @@ -1,18 +1,14 @@ /***************************************************************************** - * DLFB Kernel Driver * - * Version 0.4 (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 * - * * - * * - * xx.11.09 release 0.4 merge 0.3 work back into udlfb for kernel tree * - * 24.06.09 release 0.3 as displylink-mod (resolution manager, new ioctls) * - * 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 * + * FBDisplaylink Kernel Driver + * Version 0.1 + * (C) 2009 Roberto De Ioris <roberto@unbit.it> + * + * This file is licensed under the GPLv2. See COPYING in the package. + * Based on libdlo, udlfb and displaylink-mod + * + * + * 19.12.09 intial version from udlfb 0.4 + * *****************************************************************************/ #include <linux/module.h> @@ -25,29 +21,33 @@ #include <linux/mutex.h> #include <linux/vmalloc.h> #include <linux/version.h> -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30) -#include <drm/drm_edid.h> -#else -#include "drm_edid.h" -#endif -#include "udlfb.h" +#include "drm_edid.h" +#include "FBDisplaylink.h" -#define DRIVER_VERSION "DLFB 0.4" +#define DRIVER_VERSION "FBDisplaylink 0.1" +//#define USE_FAKE_EDID 1 -/* memory functions taken from vfb */ +/* Memory Management ------------------------------------------------------------------*/ +/* + * Virtual memory functions + */ static void *rvmalloc(unsigned long size) { void *mem; unsigned long adr; + /* Make the size a multiple of the page size */ size = PAGE_ALIGN(size); + + /* Allocate memory */ mem = vmalloc_32(size); if (!mem) return NULL; - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + /* initialise buffer */ + memset(mem, 0, size); adr = (unsigned long)mem; while (size > 0) { SetPageReserved(vmalloc_to_page((void *)adr)); @@ -74,6 +74,18 @@ static void rvfree(void *mem, unsigned l vfree(mem); } + + +/** Map the kernel allocated memory into user space. + * + * @param info Pointer to @an fb_info structure. + * @param vma Pointer to @an vm_area_struct structure. + * + * @return Return code, zero for no error. + * + * This call will map the virtualk memory area vma into user. + * + */ static int dlfb_mmap(struct fb_info *info, struct vm_area_struct *vma) { unsigned long start = vma->vm_start; @@ -106,6 +118,7 @@ static int dlfb_mmap(struct fb_info *inf } + /* ioctl structure */ struct dlores { @@ -166,7 +179,7 @@ Next step is huffman compression. */ static int -image_blit(struct dlfb_data *dev_info, int x, int y, int width, int height, +image_blit(struct dlfb_device_context *dev_info, int x, int y, int width, int height, char *data) { @@ -304,7 +317,7 @@ image_blit(struct dlfb_data *dev_info, i } static int -draw_rect(struct dlfb_data *dev_info, int x, int y, int width, int height, +draw_rect(struct dlfb_device_context *dev_info, int x, int y, int width, int height, unsigned char red, unsigned char green, unsigned char blue) { @@ -390,7 +403,7 @@ draw_rect(struct dlfb_data *dev_info, in } static int -copyarea(struct dlfb_data *dev_info, int dx, int dy, int sx, int sy, +copyarea(struct dlfb_device_context *dev_info, int dx, int dy, int sx, int sy, int width, int height) { int base; @@ -479,7 +492,7 @@ copyarea(struct dlfb_data *dev_info, int static void dlfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) { - struct dlfb_data *dev = info->par; + struct dlfb_device_context *dev = info->par; mutex_lock(&dev->fb_mutex); @@ -493,13 +506,13 @@ static void dlfb_copyarea(struct fb_info mutex_unlock(&dev->fb_mutex); - /* printk("COPY AREA %d %d %d %d %d %d !!!\n", 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) { - struct dlfb_data *dev = info->par; + struct dlfb_device_context *dev = info->par; mutex_lock(&dev->fb_mutex); @@ -508,12 +521,12 @@ static void dlfb_imageblit(struct fb_inf if (dev->udev == NULL) return; - /* printk("IMAGE BLIT (1) %d %d %d %d DEPTH %d {%p}!!!\n", image->dx, image->dy, image->width, image->height, image->depth, dev->udev); */ + // 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); - image_blit(dev, image->dx, image->dy, image->width, image->height, - info->screen_base); + //image_blit(dev, image->dx, image->dy, image->width, image->height, + // info->screen_base); mutex_unlock(&dev->fb_mutex); @@ -525,7 +538,7 @@ static void dlfb_fillrect(struct fb_info { unsigned char red, green, blue; - struct dlfb_data *dev = info->par; + struct dlfb_device_context *dev = info->par; mutex_lock(&dev->fb_mutex); @@ -542,18 +555,20 @@ static void dlfb_fillrect(struct fb_info mutex_unlock(&dev->fb_mutex); - /* printk("FILL RECT %d %d !!!\n", region->dx, region->dy); */ + // printk("FILL RECT %d %d !!!\n", region->dx, region->dy); } static int dlfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { - struct dlfb_data *dev_info = info->par; + struct dlfb_device_context *dev_info = info->par; struct dloarea *area = NULL; struct dlores *res = NULL; char *name; + // printk("dlfb_ioctl\n" ); + if (dev_info->udev == NULL) { return -EINVAL; } @@ -650,7 +665,7 @@ dlfb_setcolreg(unsigned regno, unsigned static int dlfb_release(struct fb_info *info, int user) { - struct dlfb_data *dev_info = info->par; + struct dlfb_device_context *dev_info = info->par; BUG_ON(dev_info == NULL); @@ -658,19 +673,19 @@ static int dlfb_release(struct fb_info * if (user == 0) { return 0; } - + //printk("releasing displaylink framebuffer...\n"); mutex_lock(&dev_info->fb_mutex); atomic_dec(&dev_info->fb_count); - //printk("release fb count: %d\n", atomic_read(&dev_info->fb_count)); + //printk("release fb count: %d\n", atomic_read(&dev_info->fb_count)); if (atomic_read(&dev_info->fb_count) == 0 && dev_info->udev == NULL) { dlfb_destroy_framebuffer(dev_info); mutex_unlock(&dev_info->fb_mutex); kfree(dev_info); - return 0 ; + return 0 ; } image_blit(dev_info, 0, 0, info->var.xres, info->var.yres, @@ -683,7 +698,7 @@ static int dlfb_release(struct fb_info * static int dlfb_blank(int blank_mode, struct fb_info *info) { - struct dlfb_data *dev_info = info->par; + struct dlfb_device_context *dev_info = info->par; char *bufptr = dev_info->buf; bufptr = dlfb_set_register(bufptr, 0xFF, 0x00); @@ -696,6 +711,8 @@ static int dlfb_blank(int blank_mode, st dlfb_bulk_msg(dev_info, bufptr - dev_info->buf); + printk("displaylink dlfb_blank\n" ); + return 0; } @@ -703,7 +720,7 @@ static int dlfb_blank(int blank_mode, st static int dlfb_open(struct fb_info *info, int user) { - struct dlfb_data *dev = info->par; + struct dlfb_device_context *dev = info->par; BUG_ON(dev == NULL); @@ -725,26 +742,26 @@ static int dlfb_open(struct fb_info *inf atomic_inc(&dev->fb_count); - //printk("fb count: %d\n", atomic_read(&dev->fb_count)); + //printk("fb count: %d\n", atomic_read(&dev->fb_count)); mutex_unlock(&dev->fb_mutex); return 0; - + } static int dlfb_setpar(struct fb_info *info) { - - struct dlfb_data *dev = info->par; - + + struct dlfb_device_context *dev = info->par; + BUG_ON(dev == NULL); if (dev->udev == NULL) return -EINVAL; - printk("setting hardware to %d %d\n", info->var.xres, info->var.yres); + printk("displaylink setting hardware to %d %d\n", info->var.xres, info->var.yres); dlfb_set_video_mode(dev, 0, info->var.xres, info->var.yres, 0); @@ -757,7 +774,7 @@ static int dlfb_setpar(struct fb_info *i static int dlfb_checkvar(struct fb_var_screeninfo *var, struct fb_info *info) { - struct dlfb_data *dev = info->par; + struct dlfb_device_context *dev = info->par; struct edid *edid ; struct detailed_timing *best_edid ; struct std_timing *std_edid ; @@ -795,10 +812,10 @@ static int dlfb_checkvar(struct fb_var_s return 0; } } - - + + return -EINVAL; - + } static struct fb_ops dlfb_ops = { @@ -818,59 +835,68 @@ static struct fb_ops dlfb_ops = { static int dlfb_probe(struct usb_interface *interface, const struct usb_device_id *id) { - struct dlfb_data *dev; + struct dlfb_device_context *dev; int ret; int mode = 0; + /* Allocate USB device conrtext */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) { - printk("cannot allocate dev structure.\n"); + printk("cannot allocate device context structure.\n"); return -ENOMEM; } + /* Initialise access mutexes */ mutex_init(&dev->bulk_mutex); mutex_init(&dev->fb_mutex); + /* store USB device details in context */ dev->udev = usb_get_dev(interface_to_usbdev(interface)); dev->interface = interface; - printk("DisplayLink device attached\n"); + printk("\n\nFBDisplayLink device attached\n\n"); /* add framebuffer info to usb interface */ usb_set_intfdata(interface, dev); + /* Allocate USB command buffer */ dev->buf = kmalloc(BUF_SIZE, GFP_KERNEL); /* usb_buffer_alloc(dev->udev, BUF_SIZE , GFP_KERNEL, &dev->tx_urb->transfer_dma); */ - if (dev->buf == NULL) { printk("unable to allocate memory for dlfb commands\n"); goto out; } dev->bufend = dev->buf + BUF_SIZE; + /* set up USB communications */ 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); + /* set device name */ if (strlen(dev->udev->product) > 63) { - memcpy(dev->name, dev->udev->product, 63); - } - else { - memcpy(dev->name, dev->udev->product, strlen(dev->udev->product)); - } + memcpy(dev->name, dev->udev->product, 63); + } else { + memcpy(dev->name, dev->udev->product, strlen(dev->udev->product)); + } + /* Get attached display information */ dlfb_edid(dev); - ret = dlfb_setup(dev); + /* Set up general Display link device configuration */ + ret = dlfb_setup(dev); + /* Set up video mode */ dlfb_set_video_mode(dev, 0, 0, 0, 0); - dev->backing_buffer = kzalloc(dev->screen_size, GFP_KERNEL); + printk("FBDisplayLink Screen size: %d\n", dev->screen_size); + + dev->backing_buffer = vmalloc(dev->screen_size); if (!dev->backing_buffer) { - printk("non posso allocare il backing buffer\n"); + printk("error allocating the back buffer\n"); goto out; } @@ -883,13 +909,14 @@ dlfb_probe(struct usb_interface *interfa // put the green screen draw_rect(dev, 0, 0, dev->info->var.xres, - dev->info->var.yres, 0x30, 0xff, 0x30); + dev->info->var.yres, 0xFF, 0x00, 0x00); return 0; out: usb_set_intfdata(interface, NULL); usb_put_dev(dev->udev); + vfree(dev->backing_buffer); kfree(dev); return -ENOMEM; @@ -914,36 +941,108 @@ static uint16_t lfsr16(uint16_t v) void dlfb_bulk_callback(struct urb *urb) { - struct dlfb_data *dev = urb->context; + struct dlfb_device_context *dev = urb->context; complete(&dev->done); //printk("displaylink BULK transfer complete %d\n", urb->actual_length); } -void dlfb_edid(struct dlfb_data *dev) +/* some hard-wired constants for checking known embedded devices with + * EDID data structures that'd otherwise break the framebuffer's brain + */ +#define EDID_MANUF0 (8) +#define EDID_MANUF1 (9) +#define EDID_PROD0 (10) +#define EDID_PROD1 (11) + +/* nonesense bytes - substitute with values from known bad system */ +#define EDID_MANUF0_VALUE (0xFF) +#define EDID_MANUF1_VALUE (0xFF) +#define EDID_PROD0_VALUE (0xFF) +#define EDID_PROD1_VALUE (0xFF) + +void dlfb_edid(struct dlfb_device_context *dev) { int i; int ret; char rbuf[2]; + unsigned char sum=0; + +#if defined(USE_FAKE_EDID) + struct edid *edid = (struct edid *) dev->edid; + struct detailed_timing *best_edid;; + char fakeedid[128] = { + 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x04,0x21,0x55,0x03,0x01,0x00,0x00,0x00, + 0x05,0x14,0x01,0x03,0x80,0x0C,0x09,0x7A,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x20,0x00,0x00,0x31,0x40,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01,0x01,0x01,0xc4,0x09,0x80,0xa0,0x20,0xe0,0x2d,0x10,0x28,0xa0, + 0x1d,0x02,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0xfd,0x00,0x37,0x41,0x1e, + 0x2d,0x05,0x00,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0x10,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf9 + }; + + printk("Using Fake 640x480 EDID\n"); + for (i = 0; i < 128; i++) { + dev->edid[i] = fakeedid[i]; + } + best_edid = &edid->detailed_timings[0]; + printk("Width %d Height %d\n",EDID_GET_WIDTH(best_edid),EDID_GET_HEIGHT(best_edid) ); +#else for (i = 0; i < 128; i++) { ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->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->edid[i] = rbuf[1]; - } + dev->edid[i] = rbuf[1]; + } + + // Fixup EDID from some embedded devices - those with _no_ standard timings + if (dev->edid[EDID_MANUF0] == EDID_MANUF0_VALUE && dev->edid[EDID_MANUF1] == EDID_MANUF1_VALUE && + dev->edid[EDID_PROD0] == EDID_PROD0_VALUE && dev->edid[EDID_PROD1] == EDID_PROD1_VALUE) + { + printk("Embedded display found, fixing EDID\n" ); + dev->edid[21] = 0x0D; // 12cm width + dev->edid[22] = 0x0A; // 9cm height + dev->edid[23] = 0x7A; // gamma + + dev->edid[25] = 0xAE; // + dev->edid[26] = 0xC5; // + dev->edid[27] = 0xA2; // + dev->edid[28] = 0x57; // + dev->edid[29] = 0x4A; // + dev->edid[30] = 0x9C; // + dev->edid[31] = 0x25; // + dev->edid[32] = 0x12; // + dev->edid[33] = 0x50; // + dev->edid[34] = 0x54; // + + dev->edid[35] = 0x20; // 640x480, 60 Hz + dev->edid[38] = 0x31; // 640 + dev->edid[39] = 0x40; // 4:3, 60 Hz + + dev->edid[66] = 0x78; // 120 mm + dev->edid[67] = 0x5A; // 90 mm + + // Compute checksum + for (i = 0; i < 127; i++) { + sum += dev->edid[i]; + } + dev->edid[127] = -sum; + + } +#endif } -void dlfb_get_best_edid(struct dlfb_data *dev) { +void dlfb_get_best_edid(struct dlfb_device_context *dev) { return; } -int dlfb_bulk_msg(struct dlfb_data *dev, int len) +int dlfb_bulk_msg(struct dlfb_device_context *dev, int len) { int ret; @@ -958,6 +1057,7 @@ int dlfb_bulk_msg(struct dlfb_data *dev, usb_kill_urb(dev->tx_urb); printk("usb timeout !!!\n"); } + //printk("FBDisplaylink dlfb_bulk_msg, requested len %d, tfr length %d\n", len, dev->tx_urb->actual_length); return dev->tx_urb->actual_length; @@ -985,6 +1085,8 @@ char *dlfb_edid_to_reg(struct detailed_t uint16_t edid_w ; uint16_t edid_h ; + uint16_t edid_hSyncStart ; + uint16_t edid_vSyncStart ; uint16_t edid_x_ds ; uint16_t edid_x_de ; uint16_t edid_y_ds ; @@ -998,22 +1100,24 @@ char *dlfb_edid_to_reg(struct detailed_t /* display width */ edid_w = EDID_GET_WIDTH(edid) ; if (width!= 0) { - edid_w = width; + edid_w = width; } /* display height */ edid_h = EDID_GET_HEIGHT(edid) ; if (height!= 0) { - edid_h = height; + edid_h = height; } /* display x start/end */ edid_x_ds = (EDID_GET_HBLANK(edid) - EDID_GET_HSYNC(edid)) ; edid_x_de = (edid_x_ds + edid_w) ; + edid_hSyncStart = 1; /* display y start/end */ edid_y_ds = (EDID_GET_VBLANK(edid) - EDID_GET_VSYNC(edid)); edid_y_de = (edid_y_ds + edid_h); + edid_vSyncStart = 0; /* x end count */ edid_x_ec = (edid_w + EDID_GET_HBLANK(edid) - 1); @@ -1027,11 +1131,26 @@ char *dlfb_edid_to_reg(struct detailed_t /* pixel clock */ edid_pclock = edid->pixel_clock*2; + printk("displaylink xDisplayStart %d\n", edid_x_ds); + printk("displaylink xDisplayEnd %d\n", edid_x_de); + printk("displaylink yDisplayStart %d\n", edid_y_ds); + printk("displaylink yDisplayEnd %d\n", edid_y_de); + printk("displaylink xEndCount %d\n", edid_x_ec); + printk("displaylink hSyncStart %d\n", edid_hSyncStart); + printk("displaylink hSyncEnd %d\n", edid_h_se); + printk("displaylink hPixels %d\n", edid_w); + printk("displaylink vSyncStart %d\n",edid_vSyncStart); + printk("displaylink vSyncEnd %d\n", edid_v_se); + printk("displaylink vPixels %d\n", edid_h); + printk("displaylink Pixel clock %d\n", edid_pclock*5); + if (freq != 0) { /* calc new pixel clock based on freq */ } + //bufptr = dlfb_set_register(bufptr, 0xFF, 0) ; + //bufptr = dlfb_set_register(bufptr, 0x00, 0) ; bufptr = dlfb_set_register_16(bufptr, 0x01, lfsr16(edid_x_ds)) ; bufptr = dlfb_set_register_16(bufptr, 0x03, lfsr16(edid_x_de)) ; bufptr = dlfb_set_register_16(bufptr, 0x05, lfsr16(edid_y_ds)) ; @@ -1039,23 +1158,30 @@ char *dlfb_edid_to_reg(struct detailed_t bufptr = dlfb_set_register_16(bufptr, 0x09, lfsr16(edid_x_ec)) ; - bufptr = dlfb_set_register_16(bufptr, 0x0B, lfsr16(1)) ; - bufptr = dlfb_set_register_16(bufptr, 0x0D, lfsr16(edid_h_se)) ; +// bufptr = dlfb_set_register_16(bufptr, 0x0B, 0x74) ; +// bufptr = dlfb_set_register_16(bufptr, 0x0D, 0xFFFE) ; + bufptr = dlfb_set_register_16(bufptr, 0x0B, lfsr16(edid_h_se)) ; + bufptr = dlfb_set_register_16(bufptr, 0x0D, lfsr16(edid_hSyncStart)) ; bufptr = dlfb_set_register_16(bufptr, 0x0F, edid_w) ; bufptr = dlfb_set_register_16(bufptr, 0x11, lfsr16(edid_y_ec)) ; - bufptr = dlfb_set_register_16(bufptr, 0x13, lfsr16(0)) ; - bufptr = dlfb_set_register_16(bufptr, 0x15, lfsr16(edid_v_se)) ; +// bufptr = dlfb_set_register_16(bufptr, 0x13, 0x83bc) ; +// bufptr = dlfb_set_register_16(bufptr, 0x15, 0xFFFF) ; + bufptr = dlfb_set_register_16(bufptr, 0x13, lfsr16(edid_v_se)) ; + bufptr = dlfb_set_register_16(bufptr, 0x15, lfsr16(edid_vSyncStart)) ; bufptr = dlfb_set_register_16(bufptr, 0x17, edid_h) ; bufptr = dlfb_set_register_le16(bufptr, 0x1B, edid_pclock) ; + //bufptr = dlfb_set_register(bufptr, 0x1F, 0) ; return bufptr; } + + char *dlfb_set_register(char *bufptr, uint8_t reg, uint8_t val) { @@ -1068,14 +1194,14 @@ char *dlfb_set_register(char *bufptr, ui } -int dlfb_set_video_mode(struct dlfb_data *dev, int mode, int width, int height, int freq) +int dlfb_set_video_mode(struct dlfb_device_context *dev, int mode, int width, int height, int freq) { char *bufptr; int ret; struct edid *edid = (struct edid *) dev->edid; - struct detailed_timing *best_edid = &edid->detailed_timings[mode]; + struct detailed_timing *best_edid = &edid->detailed_timings[mode]; if (dev->udev == NULL) return 0; @@ -1087,63 +1213,64 @@ int dlfb_set_video_mode(struct dlfb_data mutex_lock(&dev->bulk_mutex); - // set registers + // video registers unlock bufptr = dlfb_set_register(bufptr, 0xFF, 0x00); - // set color depth - bufptr = dlfb_set_register(bufptr, 0x00, 0x00); + printk("displaylink base16 register %d\n", dev->base16); + printk("displaylink base8 register %d\n", dev->base8); // set addresses - bufptr = - dlfb_set_register(bufptr, 0x20, - (char)(dev->base16 >> 16)); - bufptr = - dlfb_set_register(bufptr, 0x21, - (char)(dev->base16 >> 8)); - bufptr = - dlfb_set_register(bufptr, 0x22, - (char)(dev->base16)); - - bufptr = - dlfb_set_register(bufptr, 0x26, - (char)(dev->base8 >> 16)); - - bufptr = - dlfb_set_register(bufptr, 0x27, - (char)(dev->base8 >> 8)); - - bufptr = - dlfb_set_register(bufptr, 0x28, - (char)(dev->base8)); + bufptr = dlfb_set_register(bufptr, 0x20, (char)(dev->base16 >> 16)); + bufptr = dlfb_set_register(bufptr, 0x21, (char)(dev->base16 >> 8)); + bufptr = dlfb_set_register(bufptr, 0x22, (char)(dev->base16)); + + bufptr = dlfb_set_register(bufptr, 0x26, (char)(dev->base8 >> 16)); + bufptr = dlfb_set_register(bufptr, 0x27, (char)(dev->base8 >> 8)); + bufptr = dlfb_set_register(bufptr, 0x28, (char)(dev->base8)); + + // video register lock + flush + bufptr = dlfb_set_register(bufptr, 0xFF, 0xFF); + *(bufptr)++ = 0xAF; + *(bufptr)++ = 0xA0; + + ret = dlfb_bulk_msg(dev, bufptr - dev->buf); + printk("video base set: %d %d\n", ret, bufptr - dev->buf); + + + // start filling buffer again + bufptr = dev->buf; if (width != 0) { printk("displaylink setting resolution to %dx%d\n", width, height); } - - bufptr = dlfb_edid_to_reg(best_edid, bufptr, width, height, freq); + // video registers unlock + //bufptr = dlfb_set_register(bufptr, 0xFF, 0x00); - // blank + // set color depth + bufptr = dlfb_set_register(bufptr, 0x00, 0x01); + + /* Add edid values to command */ + bufptr = dlfb_edid_to_reg(best_edid, bufptr, width, height, freq); + + // blank screen bufptr = dlfb_set_register(bufptr, 0x1F, 0x00); - // end registers + // video register lock + flush bufptr = dlfb_set_register(bufptr, 0xFF, 0xFF); + *(bufptr)++ = 0xAF; + *(bufptr)++ = 0xA0; - // send + // send command to device ret = dlfb_bulk_msg(dev, bufptr - dev->buf); - printk("set video mode bulk message: %d %d\n", ret, - bufptr - dev->buf); - - // flush - ret = dlfb_bulk_msg(dev, 0); - printk("displaylink register flush: %d\n", ret); + printk("set video mode bulk message: %d %d\n", ret, bufptr - dev->buf); if (width == 0) { dev->line_length = EDID_GET_WIDTH(best_edid) * (FB_BPP/8) ; - } - else { + } else { dev->line_length = width * (FB_BPP/8) ; } + printk("displaylink line_length: %d\n", dev->line_length); mutex_unlock(&dev->bulk_mutex); @@ -1151,25 +1278,21 @@ int dlfb_set_video_mode(struct dlfb_data } -int dlfb_setup(struct dlfb_data *dev) +int dlfb_setup(struct dlfb_device_context *dev) { - - int ret; + int ret = 0; unsigned char buf[4]; - struct edid *edid = (struct edid *) dev->edid; - struct detailed_timing *best_edid = &edid->detailed_timings[0] ; - ret = usb_control_msg(dev->udev, - usb_rcvctrlpipe(dev->udev, 0), (0x02), - (0x80 | (0x02 << 5)), 0, 0, buf, 4, - 5000); - + /* Get description from device */ + ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), + (0x02),(0x80 | (0x02 << 5)), 0, 0, buf, 4, 5000); if (ret != 4) { return -1 ; } + /* Idenfify which type of displaylink device is attached */ switch ((buf[3] >> 4) & 0xF) { case DL_CHIP_TYPE_BASE: strcpy(dev->chiptype, "base"); @@ -1187,50 +1310,42 @@ int dlfb_setup(struct dlfb_data *dev) strcpy(dev->chiptype, "unknown"); } - printk("found DisplayLink Chip %s\n", dev->chiptype); + printk("DisplayLink Chip %s found\n", dev->chiptype); // set encryption key (null) - memcpy(dev->buf, STD_CHANNEL, 16); - ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), - 0x12, (0x02 << 5), 0, 0, - dev->buf, 16, 0); + memcpy(dev->buf, STD_CHANNEL, 16); + ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), + 0x12, (0x02 << 5), 0, 0, dev->buf, 16, 0); printk("sent encryption null key: %d\n", ret); - dev->line_length = EDID_GET_WIDTH(best_edid) * (FB_BPP / 8); + dev->line_length = EDID_GET_WIDTH(best_edid) * (FB_BPP / 8); + dev->screen_size = EDID_GET_WIDTH(best_edid) * EDID_GET_HEIGHT(best_edid) * (FB_BPP / 8); - printk("displaylink monitor info: W(%d) H(%d) clock(%d)\n", - EDID_GET_WIDTH(best_edid), - EDID_GET_HEIGHT(best_edid), - best_edid->pixel_clock - ); - - dev->screen_size = EDID_GET_WIDTH(best_edid) * - EDID_GET_HEIGHT(best_edid) * (FB_BPP / 8); + printk("displaylink monitor info: W(%d) H(%d) clock(%d) screen_size (%d)\n", + EDID_GET_WIDTH(best_edid), EDID_GET_HEIGHT(best_edid), best_edid->pixel_clock, dev->screen_size); return 0; } -int dlfb_activate_framebuffer(struct dlfb_data *dev, int mode) +int dlfb_activate_framebuffer(struct dlfb_device_context *dev, int mode) { - struct fb_info *info; + /* Create framebuffer info structure */ info = framebuffer_alloc(sizeof(u32) * 256, &dev->udev->dev); - if (!info) { - printk("unable to allocate displaylink virtual framebuffer"); + printk("unable to allocate displaylink fb_info"); return -ENOMEM; } + /* set up framebuffer */ dev->info = info; - info->pseudo_palette = info->par; info->par = dev; - info->flags = - FBINFO_DEFAULT | FBINFO_READS_FAST | FBINFO_HWACCEL_IMAGEBLIT | - FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT; + 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->screen_size); @@ -1261,7 +1376,7 @@ int dlfb_activate_framebuffer(struct dlf info->fix.smem_start = (unsigned long)info->screen_base; info->fix.smem_len = PAGE_ALIGN(dev->screen_size); - + if (strlen(dev->udev->product) > 15) { memcpy(info->fix.id, dev->udev->product, 15); } @@ -1281,6 +1396,8 @@ int dlfb_activate_framebuffer(struct dlf if (register_framebuffer(info) < 0) goto out2; + printk("framebuffer registered\n"); + return 0; out2: @@ -1294,7 +1411,7 @@ int dlfb_activate_framebuffer(struct dlf } -void dlfb_destroy_framebuffer(struct dlfb_data *dev) +void dlfb_destroy_framebuffer(struct dlfb_device_context *dev) { printk("destroying framebuffer device...\n"); @@ -1312,8 +1429,8 @@ void dlfb_destroy_framebuffer(struct dlf static void dlfb_disconnect(struct usb_interface *interface) { - struct dlfb_data *dev = usb_get_intfdata(interface); - struct dlfb_orphaned_dev *odev; + struct dlfb_device_context *dev = usb_get_intfdata(interface); + struct dlfb_orphaned_device_context *odev; mutex_unlock(&dev->bulk_mutex); @@ -1324,7 +1441,7 @@ static void dlfb_disconnect(struct usb_i mutex_lock(&dev->fb_mutex); - printk("fb count: %d\n", atomic_read(&dev->fb_count)); + printk("fb count: %d\n", atomic_read(&dev->fb_count)); if (atomic_read(&dev->fb_count) == 0) { dlfb_destroy_framebuffer(dev); @@ -1345,13 +1462,22 @@ static void dlfb_disconnect(struct usb_i mutex_unlock(&dev->fb_mutex); + /* free backing buffer */ + vfree(dev->backing_buffer); + + /* free usb command buffer */ + kfree(dev->buf); + + /* free usb device context */ kfree(dev); printk("DisplayLink device disconnected\n"); } + + static struct usb_driver dlfb_driver = { - .name = "udlfb", + .name = "FBDisplaylink_SC1", .probe = dlfb_probe, .disconnect = dlfb_disconnect, .id_table = id_table, @@ -1361,11 +1487,12 @@ static int __init dlfb_init(void) { int res; + /* register usb device */ res = usb_register(&dlfb_driver); if (res) err("usb_register failed. Error number %d", res); - printk("VMODES initialized\n"); + printk("FBDisplaylink_SC1 initialized\n"); return res; }
file:a/udlfb.h -> file:b/udlfb.h
--- a/udlfb.h +++ b/udlfb.h @@ -1,5 +1,5 @@ -#ifndef UDLFB_H -#define UDLFB_H +#ifndef FBDISPLAYLINK_H +#define FBDISPLAYLINK_H #define FB_BPP 16 @@ -27,13 +27,23 @@ #define BUF_HIGH_WATER_MARK 1024 #define BUF_SIZE (64*1024) -struct dlfb_data { +struct dlfb_orphaned_device_context { + atomic_t fb_count; + struct usb_device *udev; + struct mutex fb_mutex; + struct fb_info *info; + int screen_size; + int line_length; +}; + +struct dlfb_device_context { // first members of structure must match "orphaned" struct below atomic_t fb_count; struct usb_device *udev; - struct mutex fb_mutex; - int screen_size; - int line_length; + struct mutex fb_mutex; + int screen_size; + int line_length; + struct usb_interface *interface; struct urb *tx_urb, *ctrl_urb; struct usb_ctrlrequest dr; @@ -52,14 +62,6 @@ struct dlfb_data { int base8d; }; -struct dlfb_orphaned_dev { - atomic_t fb_count; - struct usb_device *udev; - struct mutex fb_mutex; - struct fb_info *info; - int screen_size; - int line_length; -}; struct dlfb_video_mode { uint8_t col; @@ -73,12 +75,12 @@ struct dlfb_video_mode { } __attribute__ ((__packed__)); char *dlfb_set_register(char *bufptr, uint8_t reg, uint8_t val); -int dlfb_bulk_msg(struct dlfb_data *dev, int len); -void dlfb_destroy_framebuffer(struct dlfb_data *dev); -void dlfb_edid(struct dlfb_data *dev); -int dlfb_set_video_mode(struct dlfb_data *dev, int mode, int width, int height, int freq); +int dlfb_bulk_msg(struct dlfb_device_context *dev, int len); +void dlfb_destroy_framebuffer(struct dlfb_device_context *dev); +void dlfb_edid(struct dlfb_device_context *dev); +int dlfb_set_video_mode(struct dlfb_device_context *dev, int mode, int width, int height, int freq); void dlfb_bulk_callback(struct urb *urb); -int dlfb_setup(struct dlfb_data *dev); -int dlfb_activate_framebuffer(struct dlfb_data *dev, int mode); +int dlfb_setup(struct dlfb_device_context *dev); +int dlfb_activate_framebuffer(struct dlfb_device_context *dev, int mode); #endif