Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>


authored by

Bernie Thompson and committed by
Greg Kroah-Hartman
59277b67 293c0db0

+448 -354
+446 -200
drivers/staging/udlfb/udlfb.c
··· 1 - /***************************************************************************** 2 - * DLFB Kernel Driver * 3 - * Version 0.2 (udlfb) * 4 - * (C) 2009 Roberto De Ioris <roberto@unbit.it> * 5 - * * 6 - * This file is licensed under the GPLv2. See COPYING in the package. * 7 - * Based on the amazing work of Florian Echtler and libdlo 0.1 * 8 - * * 9 - * * 10 - * 10.06.09 release 0.2.3 (edid ioctl, fallback for unsupported modes) * 11 - * 05.06.09 release 0.2.2 (real screen blanking, rle compression, double buffer) * 12 - * 31.05.09 release 0.2 * 13 - * 22.05.09 First public (ugly) release * 14 - *****************************************************************************/ 1 + /* 2 + * udlfb.c -- Framebuffer driver for DisplayLink USB controller 3 + * 4 + * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it> 5 + * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com> 6 + * 7 + * This file is subject to the terms and conditions of the GNU General Public 8 + * License v2. See the file COPYING in the main directory of this archive for 9 + * more details. 10 + * 11 + * Layout is based on skeletonfb by James Simmons and Geert Uytterhoeven, 12 + * usb-skeleton by GregKH. 13 + * 14 + * Device-specific portions based on information from Displaylink, with work 15 + * from Florian Echtler, Henrik Bjerregaard Pedersen, and others. 16 + */ 15 17 16 18 #include <linux/module.h> 17 19 #include <linux/kernel.h> ··· 27 25 28 26 #include "udlfb.h" 29 27 30 - #define DRIVER_VERSION "DLFB 0.2" 28 + #define DRIVER_VERSION "DisplayLink Framebuffer Driver 0.4.1" 31 29 32 - /* memory functions taken from vfb */ 30 + static struct fb_fix_screeninfo dlfb_fix = { 31 + .id = "displaylinkfb", 32 + .type = FB_TYPE_PACKED_PIXELS, 33 + .visual = FB_VISUAL_TRUECOLOR, 34 + .xpanstep = 0, 35 + .ypanstep = 0, 36 + .ywrapstep = 0, 37 + .accel = FB_ACCEL_NONE, 38 + }; 33 39 34 - static void *rvmalloc(unsigned long size) 40 + #define NR_USB_REQUEST_I2C_SUB_IO 0x02 41 + #define NR_USB_REQUEST_CHANNEL 0x12 42 + 43 + /* 44 + * Inserts a specific DisplayLink controller command into the provided 45 + * buffer. 46 + */ 47 + static char *insert_command(char *buf, u8 reg, u8 val) 35 48 { 36 - void *mem; 37 - unsigned long adr; 38 - 39 - size = PAGE_ALIGN(size); 40 - mem = vmalloc_32(size); 41 - if (!mem) 42 - return NULL; 43 - 44 - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ 45 - adr = (unsigned long)mem; 46 - while (size > 0) { 47 - SetPageReserved(vmalloc_to_page((void *)adr)); 48 - adr += PAGE_SIZE; 49 - size -= PAGE_SIZE; 50 - } 51 - 52 - return mem; 49 + *buf++ = 0xAF; 50 + *buf++ = 0x20; 51 + *buf++ = reg; 52 + *buf++ = val; 53 + return buf; 53 54 } 54 55 55 - static void rvfree(void *mem, unsigned long size) 56 + static char *insert_vidreg_lock(char *buf) 56 57 { 57 - unsigned long adr; 58 + return insert_command(buf, 0xFF, 0x00); 59 + } 58 60 59 - if (!mem) 60 - return; 61 + static char *insert_vidreg_unlock(char *buf) 62 + { 63 + return insert_command(buf, 0xFF, 0xFF); 64 + } 61 65 62 - adr = (unsigned long)mem; 63 - while ((long)size > 0) { 64 - ClearPageReserved(vmalloc_to_page((void *)adr)); 65 - adr += PAGE_SIZE; 66 - size -= PAGE_SIZE; 66 + /* 67 + * Once you send this command, the DisplayLink framebuffer gets driven to the 68 + * display. 69 + */ 70 + static char *insert_enable_hvsync(char *buf) 71 + { 72 + return insert_command(buf, 0x1F, 0x00); 73 + } 74 + 75 + static char *insert_set_color_depth(char *buf, u8 selection) 76 + { 77 + return insert_command(buf, 0x00, selection); 78 + } 79 + 80 + static char *insert_set_base16bpp(char *wrptr, u32 base) 81 + { 82 + /* the base pointer is 16 bits wide, 0x20 is hi byte. */ 83 + wrptr = insert_command(wrptr, 0x20, base >> 16); 84 + wrptr = insert_command(wrptr, 0x21, base >> 8); 85 + return insert_command(wrptr, 0x22, base); 86 + } 87 + 88 + static char *insert_set_base8bpp(char *wrptr, u32 base) 89 + { 90 + wrptr = insert_command(wrptr, 0x26, base >> 16); 91 + wrptr = insert_command(wrptr, 0x27, base >> 8); 92 + return insert_command(wrptr, 0x28, base); 93 + } 94 + 95 + static char *insert_command_16(char *wrptr, u8 reg, u16 value) 96 + { 97 + wrptr = insert_command(wrptr, reg, value >> 8); 98 + return insert_command(wrptr, reg+1, value); 99 + } 100 + 101 + /* 102 + * This is kind of weird because the controller takes some 103 + * register values in a different byte order than other registers. 104 + */ 105 + static char *insert_command_16be(char *wrptr, u8 reg, u16 value) 106 + { 107 + wrptr = insert_command(wrptr, reg, value); 108 + return insert_command(wrptr, reg+1, value >> 8); 109 + } 110 + 111 + /* 112 + * LFSR is linear feedback shift register. The reason we have this is 113 + * because the display controller needs to minimize the clock depth of 114 + * various counters used in the display path. So this code reverses the 115 + * provided value into the lfsr16 value by counting backwards to get 116 + * the value that needs to be set in the hardware comparator to get the 117 + * same actual count. This makes sense once you read above a couple of 118 + * times and think about it from a hardware perspective. 119 + */ 120 + static u16 lfsr16(u16 actual_count) 121 + { 122 + u32 lv = 0xFFFF; /* This is the lfsr value that the hw starts with */ 123 + 124 + while (actual_count--) { 125 + lv = ((lv << 1) | 126 + (((lv >> 15) ^ (lv >> 4) ^ (lv >> 2) ^ (lv >> 1)) & 1)) 127 + & 0xFFFF; 67 128 } 68 - vfree(mem); 129 + 130 + return (u16) lv; 131 + } 132 + 133 + /* 134 + * This does LFSR conversion on the value that is to be written. 135 + * See LFSR explanation above for more detail. 136 + */ 137 + static char *insert_command_lfsr16(char *wrptr, u8 reg, u16 value) 138 + { 139 + return insert_command_16(wrptr, reg, lfsr16(value)); 140 + } 141 + 142 + /* 143 + * This takes a standard fbdev screeninfo struct and all of its monitor mode 144 + * details and converts them into the DisplayLink equivalent register commands. 145 + */ 146 + static char *insert_set_vid_cmds(char *wrptr, struct fb_var_screeninfo *var) 147 + { 148 + u16 xds, yds; 149 + u16 xde, yde; 150 + u16 yec; 151 + 152 + 153 + /* x display start */ 154 + xds = var->left_margin + var->hsync_len; 155 + wrptr = insert_command_lfsr16(wrptr, 0x01, xds); 156 + /* x display end */ 157 + xde = xds + var->xres; 158 + wrptr = insert_command_lfsr16(wrptr, 0x03, xde); 159 + 160 + /* y display start */ 161 + yds = var->upper_margin + var->vsync_len; 162 + wrptr = insert_command_lfsr16(wrptr, 0x05, yds); 163 + /* y display end */ 164 + yde = yds + var->yres; 165 + wrptr = insert_command_lfsr16(wrptr, 0x07, yde); 166 + 167 + /* x end count is active + blanking - 1 */ 168 + wrptr = insert_command_lfsr16(wrptr, 0x09, xde + var->right_margin - 1); 169 + 170 + /* libdlo hardcodes hsync start to 1 */ 171 + wrptr = insert_command_lfsr16(wrptr, 0x0B, 1); 172 + 173 + /* hsync end is width of sync pulse + 1 */ 174 + wrptr = insert_command_lfsr16(wrptr, 0x0D, var->hsync_len + 1); 175 + 176 + /* hpixels is active pixels */ 177 + wrptr = insert_command_16(wrptr, 0x0F, var->xres); 178 + 179 + /* yendcount is vertical active + vertical blanking */ 180 + yec = var->yres + var->upper_margin + var->lower_margin + 181 + var->vsync_len; 182 + wrptr = insert_command_lfsr16(wrptr, 0x11, yec); 183 + 184 + /* libdlo hardcodes vsync start to 0 */ 185 + wrptr = insert_command_lfsr16(wrptr, 0x13, 0); 186 + 187 + /* vsync end is width of vsync pulse */ 188 + wrptr = insert_command_lfsr16(wrptr, 0x15, var->vsync_len); 189 + 190 + /* vpixels is active pixels */ 191 + wrptr = insert_command_16(wrptr, 0x17, var->yres); 192 + 193 + /* convert picoseconds to 5kHz multiple for pclk5k = x * 1E12/5k */ 194 + wrptr = insert_command_16be(wrptr, 0x1B, 200*1000*1000/var->pixclock); 195 + 196 + return wrptr; 197 + } 198 + 199 + /* 200 + * This takes a standard fbdev screeninfo struct that was fetched or prepared 201 + * and then generates the appropriate command sequence that then drives the 202 + * display controller. 203 + */ 204 + static int dlfb_set_video_mode(struct dlfb_data *dev, 205 + struct fb_var_screeninfo *var) 206 + { 207 + char *buf; 208 + char *wrptr; 209 + int retval = 0; 210 + int writesize; 211 + 212 + buf = dev->buf; 213 + 214 + /* 215 + * This first section has to do with setting the base address on the 216 + * controller * associated with the display. There are 2 base 217 + * pointers, currently, we only * use the 16 bpp segment. 218 + */ 219 + wrptr = insert_vidreg_lock(buf); 220 + wrptr = insert_set_color_depth(wrptr, 0x00); 221 + /* set base for 16bpp segment to 0 */ 222 + wrptr = insert_set_base16bpp(wrptr, 0); 223 + /* set base for 8bpp segment to end of fb */ 224 + wrptr = insert_set_base8bpp(wrptr, dev->info->fix.smem_len); 225 + 226 + wrptr = insert_set_vid_cmds(wrptr, var); 227 + wrptr = insert_enable_hvsync(wrptr); 228 + wrptr = insert_vidreg_unlock(wrptr); 229 + 230 + writesize = wrptr - buf; 231 + 232 + mutex_lock(&dev->bulk_mutex); 233 + if (!dev->interface) { /* disconnect() was called */ 234 + mutex_unlock(&dev->bulk_mutex); 235 + retval = -ENODEV; 236 + goto error; 237 + } 238 + 239 + retval = dlfb_bulk_msg(dev, writesize); 240 + mutex_unlock(&dev->bulk_mutex); 241 + if (retval) { 242 + dev_err(&dev->udev->dev, "Problem %d with submit write bulk.\n", 243 + retval); 244 + goto error; 245 + } 246 + 247 + return 0; 248 + 249 + error: 250 + return retval; 251 + } 252 + 253 + /* 254 + * This is necessary before we can communicate with the display controller. 255 + */ 256 + static int dlfb_select_std_channel(struct dlfb_data *dev) 257 + { 258 + int ret; 259 + u8 set_def_chn[] = { 0x57, 0xCD, 0xDC, 0xA7, 260 + 0x1C, 0x88, 0x5E, 0x15, 261 + 0x60, 0xFE, 0xC6, 0x97, 262 + 0x16, 0x3D, 0x47, 0xF2 }; 263 + 264 + ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), 265 + NR_USB_REQUEST_CHANNEL, 266 + (USB_DIR_OUT | USB_TYPE_VENDOR), 0, 0, 267 + set_def_chn, sizeof(set_def_chn), USB_CTRL_SET_TIMEOUT); 268 + return ret; 269 + } 270 + 271 + 272 + /* 273 + * Query EDID from the handware, then hand it off to fbdev's edid parse 274 + * routine which should give us back a filled in screeninfo structure. 275 + */ 276 + static int dlfb_get_var_from_edid(struct dlfb_data *dev, 277 + struct fb_var_screeninfo *var) 278 + { 279 + int ret; 280 + 281 + dlfb_edid(dev); 282 + ret = fb_parse_edid(dev->edid, var); 283 + 284 + return ret; 69 285 } 70 286 71 287 static int dlfb_mmap(struct fb_info *info, struct vm_area_struct *vma) ··· 326 106 }; 327 107 328 108 /* 329 - static struct usb_device_id id_table [] = { 330 - { USB_DEVICE(0x17e9, 0x023d) }, 331 - { } 332 - }; 333 - */ 334 - 109 + * There are many DisplayLink-based products, all with unique PIDs. We are able 110 + * to support all volume ones (circa 2009) with a single driver, so we match 111 + * globally on VID. TODO: Probe() needs to detect when we might be running 112 + * "future" chips, and bail on those, so a compatible driver can match. 113 + */ 335 114 static struct usb_device_id id_table[] = { 336 115 {.idVendor = 0x17e9, .match_flags = USB_DEVICE_ID_MATCH_VENDOR,}, 337 116 {}, ··· 424 205 if (thistime > 255) 425 206 thistime = 255; 426 207 427 - // find position of first pixel that has changed 428 - firstdiff = -1; 429 - for (j = 0; j < thistime * 2; j++) { 430 - if (dev_info->backing_buffer 431 - [base - dev_info->base16 + j] != data[j]) { 432 - firstdiff = j / 2; 433 - break; 208 + if (dev_info->backing_buffer) { 209 + /* find first pixel that has changed */ 210 + firstdiff = -1; 211 + for (j = 0; j < thistime * 2; j++) { 212 + if (dev_info->backing_buffer 213 + [base - dev_info->base16 + j] 214 + != data[j]) { 215 + firstdiff = j / 2; 216 + break; 217 + } 434 218 } 219 + 220 + } else { 221 + firstdiff = 0; 222 + 435 223 } 436 224 437 225 if (firstdiff >= 0) { ··· 493 267 rem -= thistime; 494 268 } 495 269 496 - memcpy(dev_info->backing_buffer + (base - dev_info->base16) - 497 - (width * 2), data - (width * 2), width * 2); 270 + if (dev_info->backing_buffer) 271 + memcpy(dev_info->backing_buffer + 272 + (base - dev_info->base16) - 273 + (width * 2), data - (width * 2), width * 2); 498 274 499 275 base += (dev_info->info->var.xres * 2) - (width * 2); 500 276 data += (dev_info->info->var.xres * 2) - (width * 2); ··· 541 313 542 314 for (i = y; i < y + height; i++) { 543 315 544 - for (j = 0; j < width * 2; j += 2) { 545 - dev_info->backing_buffer[base - dev_info->base16 + j] = 546 - (char)(col >> 8); 547 - dev_info->backing_buffer[base - dev_info->base16 + j + 548 - 1] = (char)(col); 316 + if (dev_info->backing_buffer) { 317 + for (j = 0; j < width * 2; j += 2) { 318 + dev_info->backing_buffer 319 + [base - dev_info->base16 + j] = 320 + (char)(col >> 8); 321 + dev_info->backing_buffer 322 + [base - dev_info->base16 + j + 1] = 323 + (char)(col); 324 + } 549 325 } 326 + 550 327 if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) { 551 328 ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf); 552 329 bufptr = dev_info->buf; ··· 958 725 .fb_blank = dlfb_blank, 959 726 }; 960 727 961 - static int 962 - dlfb_probe(struct usb_interface *interface, const struct usb_device_id *id) 728 + static int dlfb_probe(struct usb_interface *interface, 729 + const struct usb_device_id *id) 963 730 { 964 - struct dlfb_data *dev_info; 731 + struct device *mydev; 732 + struct usb_device *usbdev; 733 + struct dlfb_data *dev; 965 734 struct fb_info *info; 735 + int videomemorysize; 736 + unsigned char *videomemory; 737 + int retval = -ENOMEM; 738 + struct fb_var_screeninfo *var; 739 + struct fb_bitfield red = { 11, 5, 0 }; 740 + struct fb_bitfield green = { 5, 6, 0 }; 741 + struct fb_bitfield blue = { 0, 5, 0 }; 966 742 967 - int ret; 968 - char rbuf[4]; 743 + usbdev = usb_get_dev(interface_to_usbdev(interface)); 744 + mydev = &usbdev->dev; 969 745 970 - dev_info = kzalloc(sizeof(*dev_info), GFP_KERNEL); 971 - if (dev_info == NULL) { 972 - printk("cannot allocate dev_info structure.\n"); 973 - return -ENOMEM; 746 + dev = kzalloc(sizeof(*dev), GFP_KERNEL); 747 + if (dev == NULL) { 748 + dev_err(mydev, "failed alloc of dev struct\n"); 749 + goto err_devalloc; 974 750 } 975 751 976 - mutex_init(&dev_info->bulk_mutex); 752 + mutex_init(&dev->bulk_mutex); 753 + dev->udev = usbdev; 754 + dev->interface = interface; 755 + usb_set_intfdata(interface, dev); 977 756 978 - dev_info->udev = usb_get_dev(interface_to_usbdev(interface)); 979 - dev_info->interface = interface; 757 + dev_info(mydev, "dlfb_probe: setting up DisplayLink device\n"); 980 758 981 - printk("DisplayLink device attached\n"); 982 - 983 - /* add framebuffer info to usb interface */ 984 - usb_set_intfdata(interface, dev_info); 985 - 986 - dev_info->buf = kmalloc(BUF_SIZE, GFP_KERNEL); 987 - /* usb_buffer_alloc(dev_info->udev, BUF_SIZE , GFP_KERNEL, &dev_info->tx_urb->transfer_dma); */ 988 - 989 - if (dev_info->buf == NULL) { 990 - printk("unable to allocate memory for dlfb commands\n"); 991 - goto out; 759 + /* 760 + * TODO: replace single 64K buffer with buffer list 761 + * and async dispatch 762 + */ 763 + dev->buf = kmalloc(BUF_SIZE, GFP_KERNEL); 764 + if (dev->buf == NULL) { 765 + dev_err(mydev, "unable to allocate memory for dlfb commands\n"); 766 + goto err_usballoc; 992 767 } 993 - dev_info->bufend = dev_info->buf + BUF_SIZE; 768 + dev->bufend = dev->buf + BUF_SIZE; 994 769 995 - dev_info->tx_urb = usb_alloc_urb(0, GFP_KERNEL); 996 - usb_fill_bulk_urb(dev_info->tx_urb, dev_info->udev, 997 - usb_sndbulkpipe(dev_info->udev, 1), dev_info->buf, 0, 998 - dlfb_bulk_callback, dev_info); 770 + dev->tx_urb = usb_alloc_urb(0, GFP_KERNEL); 771 + usb_fill_bulk_urb(dev->tx_urb, dev->udev, 772 + usb_sndbulkpipe(dev->udev, 1), dev->buf, 0, 773 + dlfb_bulk_callback, dev); 999 774 1000 - ret = 1001 - usb_control_msg(dev_info->udev, usb_rcvctrlpipe(dev_info->udev, 0), 1002 - (0x06), (0x80 | (0x02 << 5)), 0, 0, rbuf, 4, 0); 1003 - printk("ret control msg 0: %d %x%x%x%x\n", ret, rbuf[0], rbuf[1], 1004 - rbuf[2], rbuf[3]); 775 + /* allocates framebuffer driver structure, not framebuffer memory */ 776 + info = framebuffer_alloc(0, mydev); 777 + if (!info) 778 + goto err_fballoc; 1005 779 1006 - dlfb_edid(dev_info); 780 + dev->info = info; 781 + info->par = dev; 782 + info->pseudo_palette = dev->pseudo_palette; 1007 783 1008 - info = framebuffer_alloc(sizeof(u32) * 256, &dev_info->udev->dev); 1009 - 1010 - if (!info) { 1011 - printk("non posso allocare il framebuffer displaylink"); 1012 - goto out; 1013 - } 1014 - 1015 - fb_parse_edid(dev_info->edid, &info->var); 1016 - 1017 - printk("EDID XRES %d YRES %d\n", info->var.xres, info->var.yres); 1018 - 1019 - if (dlfb_set_video_mode(dev_info, info->var.xres, info->var.yres) != 0) { 1020 - info->var.xres = 1280; 1021 - info->var.yres = 1024; 1022 - if (dlfb_set_video_mode 1023 - (dev_info, info->var.xres, info->var.yres) != 0) { 1024 - goto out; 1025 - } 784 + var = &info->var; 785 + retval = dlfb_get_var_from_edid(dev, var); 786 + if (retval) { 787 + /* had a problem getting edid. so fallback to 640x480 */ 788 + dev_err(mydev, "Problem %d with EDID.\n", retval); 789 + var->xres = 640; 790 + var->yres = 480; 1026 791 } 1027 792 1028 - printk("found valid mode...%d\n", info->var.pixclock); 793 + /* 794 + * ok, now that we've got the size info, we can alloc our framebuffer. 795 + * We are using 16bpp. 796 + */ 797 + info->var.bits_per_pixel = 16; 798 + info->fix = dlfb_fix; 799 + info->fix.line_length = var->xres * (var->bits_per_pixel / 8); 800 + videomemorysize = info->fix.line_length * var->yres; 1029 801 1030 - info->pseudo_palette = info->par; 1031 - info->par = dev_info; 802 + /* 803 + * The big chunk of system memory we use as a virtual framebuffer. 804 + * Pages don't need to be set RESERVED (non-swap) immediately on 2.6 805 + * remap_pfn_page() syscall in our mmap and/or defio will handle. 806 + */ 807 + videomemory = vmalloc(videomemorysize); 808 + if (!videomemory) 809 + goto err_vidmem; 810 + memset(videomemory, 0, videomemorysize); 1032 811 1033 - dev_info->info = info; 1034 - 812 + info->screen_base = videomemory; 813 + info->fix.smem_len = PAGE_ALIGN(videomemorysize); 814 + info->fix.smem_start = (unsigned long) videomemory; 1035 815 info->flags = 1036 816 FBINFO_DEFAULT | FBINFO_READS_FAST | FBINFO_HWACCEL_IMAGEBLIT | 1037 817 FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT; 818 + 819 + /* 820 + * Second framebuffer copy, mirroring the state of the framebuffer 821 + * on the physical USB device. We can function without this. 822 + * But with imperfect damage info we may end up sending pixels over USB 823 + * that were, in fact, unchanged -- wasting limited USB bandwidth 824 + */ 825 + dev->backing_buffer = vmalloc(dev->screen_size); 826 + if (!dev->backing_buffer) 827 + dev_info(mydev, "No backing buffer allocated!\n"); 828 + 1038 829 info->fbops = &dlfb_ops; 1039 - info->screen_base = rvmalloc(dev_info->screen_size); 1040 830 1041 - if (info->screen_base == NULL) { 1042 - printk 1043 - ("cannot allocate framebuffer virtual memory of %d bytes\n", 1044 - dev_info->screen_size); 1045 - goto out0; 831 + var->vmode = FB_VMODE_NONINTERLACED; 832 + var->red = red; 833 + var->green = green; 834 + var->blue = blue; 835 + 836 + /* 837 + * TODO: Enable FB_CONFIG_DEFIO support 838 + 839 + info->fbdefio = &dlfb_defio; 840 + fb_deferred_io_init(info); 841 + 842 + */ 843 + 844 + retval = fb_alloc_cmap(&info->cmap, 256, 0); 845 + if (retval < 0) { 846 + dev_err(mydev, "Failed to allocate colormap\n"); 847 + goto err_cmap; 1046 848 } 1047 849 1048 - printk("screen base allocated !!!\n"); 850 + dlfb_select_std_channel(dev); 851 + dlfb_set_video_mode(dev, var); 852 + /* TODO: dlfb_dpy_update(dev); */ 1049 853 1050 - dev_info->backing_buffer = kzalloc(dev_info->screen_size, GFP_KERNEL); 854 + retval = register_framebuffer(info); 855 + if (retval < 0) 856 + goto err_regfb; 1051 857 1052 - if (!dev_info->backing_buffer) 1053 - printk("non posso allocare il backing buffer\n"); 858 + /* paint "successful" green screen */ 859 + draw_rect(dev, 0, 0, dev->info->var.xres, 860 + dev->info->var.yres, 0x30, 0xff, 0x30); 1054 861 1055 - /* info->var = dev_info->si; */ 1056 - 1057 - info->var.bits_per_pixel = 16; 1058 - info->var.activate = FB_ACTIVATE_TEST; 1059 - info->var.vmode = FB_VMODE_NONINTERLACED; 1060 - 1061 - info->var.red.offset = 11; 1062 - info->var.red.length = 5; 1063 - info->var.red.msb_right = 0; 1064 - 1065 - info->var.green.offset = 5; 1066 - info->var.green.length = 6; 1067 - info->var.green.msb_right = 0; 1068 - 1069 - info->var.blue.offset = 0; 1070 - info->var.blue.length = 5; 1071 - info->var.blue.msb_right = 0; 1072 - 1073 - /* info->var.pixclock = (10000000 / FB_W * 1000 / FB_H)/2 ; */ 1074 - 1075 - info->fix.smem_start = (unsigned long)info->screen_base; 1076 - info->fix.smem_len = PAGE_ALIGN(dev_info->screen_size); 1077 - if (strlen(dev_info->udev->product) > 15) { 1078 - memcpy(info->fix.id, dev_info->udev->product, 15); 1079 - } else { 1080 - memcpy(info->fix.id, dev_info->udev->product, 1081 - strlen(dev_info->udev->product)); 1082 - } 1083 - info->fix.type = FB_TYPE_PACKED_PIXELS; 1084 - info->fix.visual = FB_VISUAL_TRUECOLOR; 1085 - info->fix.accel = info->flags; 1086 - info->fix.line_length = dev_info->line_length; 1087 - 1088 - if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) 1089 - goto out1; 1090 - 1091 - printk("colormap allocated\n"); 1092 - if (register_framebuffer(info) < 0) 1093 - goto out2; 1094 - 1095 - draw_rect(dev_info, 0, 0, dev_info->info->var.xres, 1096 - dev_info->info->var.yres, 0x30, 0xff, 0x30); 1097 - 862 + dev_info(mydev, "DisplayLink USB device %d now attached, " 863 + "using %dK of memory\n", info->node, 864 + ((dev->backing_buffer) ? 865 + videomemorysize * 2 : videomemorysize) >> 10); 1098 866 return 0; 1099 867 1100 - out2: 868 + err_regfb: 1101 869 fb_dealloc_cmap(&info->cmap); 1102 - out1: 1103 - rvfree(info->screen_base, dev_info->screen_size); 1104 - out0: 870 + err_cmap: 871 + /* TODO: fb_deferred_io_cleanup(info); */ 872 + vfree(videomemory); 873 + err_vidmem: 1105 874 framebuffer_release(info); 1106 - out: 875 + err_fballoc: 876 + kfree(dev->buf); 877 + err_usballoc: 1107 878 usb_set_intfdata(interface, NULL); 1108 - usb_put_dev(dev_info->udev); 1109 - kfree(dev_info); 1110 - return -ENOMEM; 1111 - 879 + usb_put_dev(dev->udev); 880 + kfree(dev); 881 + err_devalloc: 882 + return retval; 1112 883 } 1113 884 1114 885 static void dlfb_disconnect(struct usb_interface *interface) 1115 886 { 1116 - struct dlfb_data *dev_info = usb_get_intfdata(interface); 887 + struct dlfb_data *dev; 888 + struct fb_info *info; 1117 889 1118 - mutex_unlock(&dev_info->bulk_mutex); 1119 - 1120 - usb_kill_urb(dev_info->tx_urb); 1121 - usb_free_urb(dev_info->tx_urb); 890 + dev = usb_get_intfdata(interface); 1122 891 usb_set_intfdata(interface, NULL); 1123 - usb_put_dev(dev_info->udev); 892 + usb_put_dev(dev->udev); 1124 893 1125 - if (dev_info->info) { 1126 - unregister_framebuffer(dev_info->info); 1127 - fb_dealloc_cmap(&dev_info->info->cmap); 1128 - rvfree(dev_info->info->screen_base, dev_info->screen_size); 1129 - kfree(dev_info->backing_buffer); 1130 - framebuffer_release(dev_info->info); 894 + /* 895 + * TODO: since, upon usb disconnect(), usb will cancel in-flight urbs 896 + * and error out any new ones, look at eliminating need for mutex 897 + */ 898 + mutex_lock(&dev->bulk_mutex); 899 + dev->interface = NULL; 900 + info = dev->info; 901 + mutex_unlock(&dev->bulk_mutex); 1131 902 903 + if (info) { 904 + dev_info(&interface->dev, "Detaching DisplayLink device %d.\n", 905 + info->node); 906 + unregister_framebuffer(info); 907 + fb_dealloc_cmap(&info->cmap); 908 + /* TODO: fb_deferred_io_cleanup(info); */ 909 + fb_dealloc_cmap(&info->cmap); 910 + vfree((void __force *)info->screen_base); 911 + framebuffer_release(info); 1132 912 } 1133 913 1134 - kfree(dev_info); 914 + if (dev->backing_buffer) 915 + vfree(dev->backing_buffer); 1135 916 1136 - printk("DisplayLink device disconnected\n"); 917 + kfree(dev); 1137 918 } 1138 919 1139 920 static struct usb_driver dlfb_driver = { ··· 1160 913 static int __init dlfb_init(void) 1161 914 { 1162 915 int res; 1163 - 1164 - dlfb_init_modes(); 1165 916 1166 917 res = usb_register(&dlfb_driver); 1167 918 if (res) ··· 1178 933 module_init(dlfb_init); 1179 934 module_exit(dlfb_exit); 1180 935 1181 - MODULE_AUTHOR("Roberto De Ioris <roberto@unbit.it>"); 936 + MODULE_AUTHOR("Roberto De Ioris <roberto@unbit.it>, " 937 + "Jaya Kumar <jayakumar.lkml@gmail.com>"); 1182 938 MODULE_DESCRIPTION(DRIVER_VERSION); 1183 939 MODULE_LICENSE("GPL");
+2 -154
drivers/staging/udlfb/udlfb.h
··· 1 1 #ifndef UDLFB_H 2 2 #define UDLFB_H 3 3 4 - #define MAX_VMODES 4 5 - #define FB_BPP 16 6 - 7 - #define STD_CHANNEL "\x57\xCD\xDC\xA7\x1C\x88\x5E\x15" \ 8 - "\x60\xFE\xC6\x97\x16\x3D\x47\xF2" 9 - 10 4 /* as libdlo */ 11 5 #define BUF_HIGH_WATER_MARK 1024 12 6 #define BUF_SIZE (64*1024) ··· 23 29 int base16d; 24 30 int base8; 25 31 int base8d; 32 + u32 pseudo_palette[256]; 26 33 }; 27 - 28 - struct dlfb_video_mode { 29 - uint8_t col; 30 - uint32_t hclock; 31 - uint32_t vclock; 32 - uint8_t unknown1[6]; 33 - uint16_t xres; 34 - uint8_t unknown2[6]; 35 - uint16_t yres; 36 - uint8_t unknown3[4]; 37 - } __attribute__ ((__packed__)); 38 - 39 - static struct dlfb_video_mode dlfb_video_modes[MAX_VMODES]; 40 34 41 35 static void dlfb_bulk_callback(struct urb *urb) 42 36 { ··· 68 86 return dev_info->tx_urb->actual_length; 69 87 } 70 88 71 - static void dlfb_init_modes(void) 72 - { 73 - dlfb_video_modes[0].col = 0; 74 - memcpy(&dlfb_video_modes[0].hclock, "\x20\x3C\x7A\xC9", 4); 75 - memcpy(&dlfb_video_modes[0].vclock, "\xF2\x6C\x48\xF9", 4); 76 - memcpy(&dlfb_video_modes[0].unknown1, "\x70\x53\xFF\xFF\x21\x27", 6); 77 - dlfb_video_modes[0].xres = 800; 78 - memcpy(&dlfb_video_modes[0].unknown2, "\x91\xF3\xFF\xFF\xFF\xF9", 6); 79 - dlfb_video_modes[0].yres = 480; 80 - memcpy(&dlfb_video_modes[0].unknown3, "\x01\x02\xC8\x19", 4); 81 - 82 - dlfb_video_modes[1].col = 0; 83 - memcpy(&dlfb_video_modes[1].hclock, "\x36\x18\xD5\x10", 4); 84 - memcpy(&dlfb_video_modes[1].vclock, "\x60\xA9\x7B\x33", 4); 85 - memcpy(&dlfb_video_modes[1].unknown1, "\xA1\x2B\x27\x32\xFF\xFF", 6); 86 - dlfb_video_modes[1].xres = 1024; 87 - memcpy(&dlfb_video_modes[1].unknown2, "\xD9\x9A\xFF\xCA\xFF\xFF", 6); 88 - dlfb_video_modes[1].yres = 768; 89 - memcpy(&dlfb_video_modes[1].unknown3, "\x04\x03\xC8\x32", 4); 90 - 91 - dlfb_video_modes[2].col = 0; 92 - memcpy(&dlfb_video_modes[2].hclock, "\x98\xF8\x0D\x57", 4); 93 - memcpy(&dlfb_video_modes[2].vclock, "\x2A\x55\x4D\x54", 4); 94 - memcpy(&dlfb_video_modes[2].unknown1, "\xCA\x0D\xFF\xFF\x94\x43", 6); 95 - dlfb_video_modes[2].xres = 1280; 96 - memcpy(&dlfb_video_modes[2].unknown2, "\x9A\xA8\xFF\xFF\xFF\xF9", 6); 97 - dlfb_video_modes[2].yres = 1024; 98 - memcpy(&dlfb_video_modes[2].unknown3, "\x04\x02\x60\x54", 4); 99 - 100 - dlfb_video_modes[3].col = 0; 101 - memcpy(&dlfb_video_modes[3].hclock, "\x42\x24\x38\x36", 4); 102 - memcpy(&dlfb_video_modes[3].vclock, "\xC1\x52\xD9\x29", 4); 103 - memcpy(&dlfb_video_modes[3].unknown1, "\xEA\xB8\x32\x60\xFF\xFF", 6); 104 - dlfb_video_modes[3].xres = 1400; 105 - memcpy(&dlfb_video_modes[3].unknown2, "\xC9\x4E\xFF\xFF\xFF\xF2", 6); 106 - dlfb_video_modes[3].yres = 1050; 107 - memcpy(&dlfb_video_modes[3].unknown3, "\x04\x02\x1E\x5F", 4); 108 - } 109 - 110 - static char *dlfb_set_register(char *bufptr, uint8_t reg, uint8_t val) 111 - { 112 - *bufptr++ = 0xAF; 113 - *bufptr++ = 0x20; 114 - *bufptr++ = reg; 115 - *bufptr++ = val; 116 - 117 - return bufptr; 118 - } 119 - 120 - static int dlfb_set_video_mode(struct dlfb_data *dev_info, int width, int height) 121 - { 122 - int i, ret; 123 - unsigned char j; 124 - char *bufptr = dev_info->buf; 125 - uint8_t *vdata; 126 - 127 - for (i = 0; i < MAX_VMODES; i++) { 128 - printk("INIT VIDEO %d %d %d\n", i, dlfb_video_modes[i].xres, 129 - dlfb_video_modes[i].yres); 130 - if (dlfb_video_modes[i].xres == width 131 - && dlfb_video_modes[i].yres == height) { 132 - 133 - dev_info->base16 = 0; 134 - dev_info->base16d = width * height * (FB_BPP / 8); 135 - 136 - //dev_info->base8 = width * height * (FB_BPP / 8); 137 - 138 - dev_info->base8 = dev_info->base16; 139 - dev_info->base8d = dev_info->base16d; 140 - 141 - /* set encryption key (null) */ 142 - memcpy(dev_info->buf, STD_CHANNEL, 16); 143 - ret = 144 - usb_control_msg(dev_info->udev, 145 - usb_sndctrlpipe(dev_info->udev, 0), 146 - 0x12, (0x02 << 5), 0, 0, 147 - dev_info->buf, 16, 0); 148 - printk("ret control msg 1 (STD_CHANNEL): %d\n", ret); 149 - 150 - /* set registers */ 151 - bufptr = dlfb_set_register(bufptr, 0xFF, 0x00); 152 - 153 - /* set color depth */ 154 - bufptr = dlfb_set_register(bufptr, 0x00, 0x00); 155 - 156 - /* set addresses */ 157 - bufptr = 158 - dlfb_set_register(bufptr, 0x20, 159 - (char)(dev_info->base16 >> 16)); 160 - bufptr = 161 - dlfb_set_register(bufptr, 0x21, 162 - (char)(dev_info->base16 >> 8)); 163 - bufptr = 164 - dlfb_set_register(bufptr, 0x22, 165 - (char)(dev_info->base16)); 166 - 167 - bufptr = 168 - dlfb_set_register(bufptr, 0x26, 169 - (char)(dev_info->base8 >> 16)); 170 - bufptr = 171 - dlfb_set_register(bufptr, 0x27, 172 - (char)(dev_info->base8 >> 8)); 173 - bufptr = 174 - dlfb_set_register(bufptr, 0x28, 175 - (char)(dev_info->base8)); 176 - 177 - /* set video mode */ 178 - vdata = (uint8_t *)&dlfb_video_modes[i]; 179 - for (j = 0; j < 29; j++) 180 - bufptr = dlfb_set_register(bufptr, j, vdata[j]); 181 - 182 - /* blank */ 183 - bufptr = dlfb_set_register(bufptr, 0x1F, 0x00); 184 - 185 - /* end registers */ 186 - bufptr = dlfb_set_register(bufptr, 0xFF, 0xFF); 187 - 188 - /* send */ 189 - ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf); 190 - printk("ret bulk 2: %d %td\n", ret, 191 - bufptr - dev_info->buf); 192 - 193 - /* flush */ 194 - ret = dlfb_bulk_msg(dev_info, 0); 195 - printk("ret bulk 3: %d\n", ret); 196 - 197 - dev_info->screen_size = width * height * (FB_BPP / 8); 198 - dev_info->line_length = width * (FB_BPP / 8); 199 - 200 - return 0; 201 - } 202 - } 203 - 204 - return -1; 205 - } 89 + #define dlfb_set_register insert_command 206 90 207 91 #endif