blob: baad03a8a8730e646df6342894a0e784b44f007d [file] [log] [blame]
Bernie Thompson59277b62009-11-24 15:52:21 -08001/*
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>
Bernie Thompson2469d5d2010-02-15 06:46:13 -08006 * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com>
Bernie Thompson59277b62009-11-24 15:52:21 -08007 *
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License v2. See the file COPYING in the main directory of this archive for
10 * more details.
11 *
12 * Layout is based on skeletonfb by James Simmons and Geert Uytterhoeven,
13 * usb-skeleton by GregKH.
14 *
15 * Device-specific portions based on information from Displaylink, with work
16 * from Florian Echtler, Henrik Bjerregaard Pedersen, and others.
17 */
Roberto De Ioris88e58b12009-06-03 14:03:06 -070018
19#include <linux/module.h>
20#include <linux/kernel.h>
21#include <linux/init.h>
22#include <linux/usb.h>
23#include <linux/uaccess.h>
24#include <linux/mm.h>
25#include <linux/fb.h>
Amit Kucheriafb299002009-07-27 12:01:03 +030026#include <linux/vmalloc.h>
Roberto De Ioris88e58b12009-06-03 14:03:06 -070027
28#include "udlfb.h"
29
Bernie Thompson59277b62009-11-24 15:52:21 -080030static struct fb_fix_screeninfo dlfb_fix = {
Bernie Thompson2469d5d2010-02-15 06:46:13 -080031 .id = "udlfb",
Bernie Thompson1d31a9e2010-02-15 06:45:43 -080032 .type = FB_TYPE_PACKED_PIXELS,
33 .visual = FB_VISUAL_TRUECOLOR,
34 .xpanstep = 0,
35 .ypanstep = 0,
36 .ywrapstep = 0,
37 .accel = FB_ACCEL_NONE,
Bernie Thompson59277b62009-11-24 15:52:21 -080038};
Roberto De Ioris88e58b12009-06-03 14:03:06 -070039
Bernie Thompson2469d5d2010-02-15 06:46:13 -080040static const u32 udlfb_info_flags = FBINFO_DEFAULT | FBINFO_READS_FAST |
41#ifdef FBINFO_VIRTFB
42 FBINFO_VIRTFB |
43#endif
44 FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT |
45 FBINFO_HWACCEL_COPYAREA | FBINFO_MISC_ALWAYS_SETPAR;
46
Bernie Thompsoncc403dc2010-02-15 06:45:49 -080047/*
48 * There are many DisplayLink-based products, all with unique PIDs. We are able
49 * to support all volume ones (circa 2009) with a single driver, so we match
50 * globally on VID. TODO: Probe() needs to detect when we might be running
51 * "future" chips, and bail on those, so a compatible driver can match.
52 */
53static struct usb_device_id id_table[] = {
54 {.idVendor = 0x17e9, .match_flags = USB_DEVICE_ID_MATCH_VENDOR,},
55 {},
56};
57MODULE_DEVICE_TABLE(usb, id_table);
Bernie Thompson59277b62009-11-24 15:52:21 -080058
Bernie Thompsondd8015f2010-02-15 06:46:35 -080059#ifndef CONFIG_FB_DEFERRED_IO
60#warning message "kernel FB_DEFFERRED_IO option to support generic fbdev apps"
61#endif
62
63#ifndef CONFIG_FB_SYS_IMAGEBLIT
64#ifndef CONFIG_FB_SYS_IMAGEBLIT_MODULE
65#warning message "FB_SYS_* in kernel or module option to support fb console"
66#endif
67#endif
68
69#ifndef CONFIG_FB_MODE_HELPERS
70#warning message "kernel FB_MODE_HELPERS required. Expect build break"
71#endif
72
Bernie Thompson4a4854d2010-02-15 06:45:55 -080073/* dlfb keeps a list of urbs for efficient bulk transfers */
74static void dlfb_urb_completion(struct urb *urb);
75static struct urb *dlfb_get_urb(struct dlfb_data *dev);
76static int dlfb_submit_urb(struct dlfb_data *dev, struct urb * urb, size_t len);
77static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size);
78static void dlfb_free_urb_list(struct dlfb_data *dev);
79
Bernie Thompson3e8f3d62010-02-15 06:46:26 -080080/* other symbols with dependents */
81#ifdef CONFIG_FB_DEFERRED_IO
82static struct fb_deferred_io dlfb_defio;
83#endif
84
Bernie Thompson59277b62009-11-24 15:52:21 -080085/*
86 * Inserts a specific DisplayLink controller command into the provided
87 * buffer.
88 */
Bernie Thompson45742032010-02-15 06:46:04 -080089static char *dlfb_set_register(char *buf, u8 reg, u8 val)
Roberto De Ioris88e58b12009-06-03 14:03:06 -070090{
Bernie Thompson1d31a9e2010-02-15 06:45:43 -080091 *buf++ = 0xAF;
92 *buf++ = 0x20;
93 *buf++ = reg;
94 *buf++ = val;
95 return buf;
Roberto De Ioris88e58b12009-06-03 14:03:06 -070096}
97
Bernie Thompson45742032010-02-15 06:46:04 -080098static char *dlfb_vidreg_lock(char *buf)
Roberto De Ioris88e58b12009-06-03 14:03:06 -070099{
Bernie Thompson45742032010-02-15 06:46:04 -0800100 return dlfb_set_register(buf, 0xFF, 0x00);
Bernie Thompson59277b62009-11-24 15:52:21 -0800101}
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700102
Bernie Thompson45742032010-02-15 06:46:04 -0800103static char *dlfb_vidreg_unlock(char *buf)
Bernie Thompson59277b62009-11-24 15:52:21 -0800104{
Bernie Thompson45742032010-02-15 06:46:04 -0800105 return dlfb_set_register(buf, 0xFF, 0xFF);
Bernie Thompson59277b62009-11-24 15:52:21 -0800106}
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700107
Bernie Thompson59277b62009-11-24 15:52:21 -0800108/*
Bernie Thompson530f43a2010-02-15 06:46:21 -0800109 * On/Off for driving the DisplayLink framebuffer to the display
Bernie Thompson59277b62009-11-24 15:52:21 -0800110 */
Bernie Thompson530f43a2010-02-15 06:46:21 -0800111static char *dlfb_enable_hvsync(char *buf, bool enable)
Bernie Thompson59277b62009-11-24 15:52:21 -0800112{
Bernie Thompson530f43a2010-02-15 06:46:21 -0800113 if (enable)
114 return dlfb_set_register(buf, 0x1F, 0x00);
115 else
116 return dlfb_set_register(buf, 0x1F, 0x01);
Bernie Thompson59277b62009-11-24 15:52:21 -0800117}
118
Bernie Thompson45742032010-02-15 06:46:04 -0800119static char *dlfb_set_color_depth(char *buf, u8 selection)
Bernie Thompson59277b62009-11-24 15:52:21 -0800120{
Bernie Thompson45742032010-02-15 06:46:04 -0800121 return dlfb_set_register(buf, 0x00, selection);
Bernie Thompson59277b62009-11-24 15:52:21 -0800122}
123
Bernie Thompson45742032010-02-15 06:46:04 -0800124static char *dlfb_set_base16bpp(char *wrptr, u32 base)
Bernie Thompson59277b62009-11-24 15:52:21 -0800125{
Bernie Thompson1d31a9e2010-02-15 06:45:43 -0800126 /* the base pointer is 16 bits wide, 0x20 is hi byte. */
Bernie Thompson45742032010-02-15 06:46:04 -0800127 wrptr = dlfb_set_register(wrptr, 0x20, base >> 16);
128 wrptr = dlfb_set_register(wrptr, 0x21, base >> 8);
129 return dlfb_set_register(wrptr, 0x22, base);
Bernie Thompson59277b62009-11-24 15:52:21 -0800130}
131
Bernie Thompson45742032010-02-15 06:46:04 -0800132static char *dlfb_set_base8bpp(char *wrptr, u32 base)
Bernie Thompson59277b62009-11-24 15:52:21 -0800133{
Bernie Thompson45742032010-02-15 06:46:04 -0800134 wrptr = dlfb_set_register(wrptr, 0x26, base >> 16);
135 wrptr = dlfb_set_register(wrptr, 0x27, base >> 8);
136 return dlfb_set_register(wrptr, 0x28, base);
Bernie Thompson59277b62009-11-24 15:52:21 -0800137}
138
Bernie Thompson45742032010-02-15 06:46:04 -0800139static char *dlfb_set_register_16(char *wrptr, u8 reg, u16 value)
Bernie Thompson59277b62009-11-24 15:52:21 -0800140{
Bernie Thompson45742032010-02-15 06:46:04 -0800141 wrptr = dlfb_set_register(wrptr, reg, value >> 8);
142 return dlfb_set_register(wrptr, reg+1, value);
Bernie Thompson59277b62009-11-24 15:52:21 -0800143}
144
145/*
146 * This is kind of weird because the controller takes some
147 * register values in a different byte order than other registers.
148 */
Bernie Thompson45742032010-02-15 06:46:04 -0800149static char *dlfb_set_register_16be(char *wrptr, u8 reg, u16 value)
Bernie Thompson59277b62009-11-24 15:52:21 -0800150{
Bernie Thompson45742032010-02-15 06:46:04 -0800151 wrptr = dlfb_set_register(wrptr, reg, value);
152 return dlfb_set_register(wrptr, reg+1, value >> 8);
Bernie Thompson59277b62009-11-24 15:52:21 -0800153}
154
155/*
156 * LFSR is linear feedback shift register. The reason we have this is
157 * because the display controller needs to minimize the clock depth of
158 * various counters used in the display path. So this code reverses the
159 * provided value into the lfsr16 value by counting backwards to get
160 * the value that needs to be set in the hardware comparator to get the
161 * same actual count. This makes sense once you read above a couple of
162 * times and think about it from a hardware perspective.
163 */
164static u16 lfsr16(u16 actual_count)
165{
166 u32 lv = 0xFFFF; /* This is the lfsr value that the hw starts with */
167
168 while (actual_count--) {
169 lv = ((lv << 1) |
170 (((lv >> 15) ^ (lv >> 4) ^ (lv >> 2) ^ (lv >> 1)) & 1))
171 & 0xFFFF;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700172 }
Bernie Thompson59277b62009-11-24 15:52:21 -0800173
174 return (u16) lv;
175}
176
177/*
178 * This does LFSR conversion on the value that is to be written.
179 * See LFSR explanation above for more detail.
180 */
Bernie Thompson45742032010-02-15 06:46:04 -0800181static char *dlfb_set_register_lfsr16(char *wrptr, u8 reg, u16 value)
Bernie Thompson59277b62009-11-24 15:52:21 -0800182{
Bernie Thompson45742032010-02-15 06:46:04 -0800183 return dlfb_set_register_16(wrptr, reg, lfsr16(value));
Bernie Thompson59277b62009-11-24 15:52:21 -0800184}
185
186/*
187 * This takes a standard fbdev screeninfo struct and all of its monitor mode
188 * details and converts them into the DisplayLink equivalent register commands.
189 */
Bernie Thompson45742032010-02-15 06:46:04 -0800190static char *dlfb_set_vid_cmds(char *wrptr, struct fb_var_screeninfo *var)
Bernie Thompson59277b62009-11-24 15:52:21 -0800191{
192 u16 xds, yds;
193 u16 xde, yde;
194 u16 yec;
195
Bernie Thompson59277b62009-11-24 15:52:21 -0800196 /* x display start */
197 xds = var->left_margin + var->hsync_len;
Bernie Thompson45742032010-02-15 06:46:04 -0800198 wrptr = dlfb_set_register_lfsr16(wrptr, 0x01, xds);
Bernie Thompson59277b62009-11-24 15:52:21 -0800199 /* x display end */
200 xde = xds + var->xres;
Bernie Thompson45742032010-02-15 06:46:04 -0800201 wrptr = dlfb_set_register_lfsr16(wrptr, 0x03, xde);
Bernie Thompson59277b62009-11-24 15:52:21 -0800202
203 /* y display start */
204 yds = var->upper_margin + var->vsync_len;
Bernie Thompson45742032010-02-15 06:46:04 -0800205 wrptr = dlfb_set_register_lfsr16(wrptr, 0x05, yds);
Bernie Thompson59277b62009-11-24 15:52:21 -0800206 /* y display end */
207 yde = yds + var->yres;
Bernie Thompson45742032010-02-15 06:46:04 -0800208 wrptr = dlfb_set_register_lfsr16(wrptr, 0x07, yde);
Bernie Thompson59277b62009-11-24 15:52:21 -0800209
210 /* x end count is active + blanking - 1 */
Bernie Thompson45742032010-02-15 06:46:04 -0800211 wrptr = dlfb_set_register_lfsr16(wrptr, 0x09,
212 xde + var->right_margin - 1);
Bernie Thompson59277b62009-11-24 15:52:21 -0800213
214 /* libdlo hardcodes hsync start to 1 */
Bernie Thompson45742032010-02-15 06:46:04 -0800215 wrptr = dlfb_set_register_lfsr16(wrptr, 0x0B, 1);
Bernie Thompson59277b62009-11-24 15:52:21 -0800216
217 /* hsync end is width of sync pulse + 1 */
Bernie Thompson45742032010-02-15 06:46:04 -0800218 wrptr = dlfb_set_register_lfsr16(wrptr, 0x0D, var->hsync_len + 1);
Bernie Thompson59277b62009-11-24 15:52:21 -0800219
220 /* hpixels is active pixels */
Bernie Thompson45742032010-02-15 06:46:04 -0800221 wrptr = dlfb_set_register_16(wrptr, 0x0F, var->xres);
Bernie Thompson59277b62009-11-24 15:52:21 -0800222
223 /* yendcount is vertical active + vertical blanking */
224 yec = var->yres + var->upper_margin + var->lower_margin +
225 var->vsync_len;
Bernie Thompson45742032010-02-15 06:46:04 -0800226 wrptr = dlfb_set_register_lfsr16(wrptr, 0x11, yec);
Bernie Thompson59277b62009-11-24 15:52:21 -0800227
228 /* libdlo hardcodes vsync start to 0 */
Bernie Thompson45742032010-02-15 06:46:04 -0800229 wrptr = dlfb_set_register_lfsr16(wrptr, 0x13, 0);
Bernie Thompson59277b62009-11-24 15:52:21 -0800230
231 /* vsync end is width of vsync pulse */
Bernie Thompson45742032010-02-15 06:46:04 -0800232 wrptr = dlfb_set_register_lfsr16(wrptr, 0x15, var->vsync_len);
Bernie Thompson59277b62009-11-24 15:52:21 -0800233
234 /* vpixels is active pixels */
Bernie Thompson45742032010-02-15 06:46:04 -0800235 wrptr = dlfb_set_register_16(wrptr, 0x17, var->yres);
Bernie Thompson59277b62009-11-24 15:52:21 -0800236
237 /* convert picoseconds to 5kHz multiple for pclk5k = x * 1E12/5k */
Bernie Thompson45742032010-02-15 06:46:04 -0800238 wrptr = dlfb_set_register_16be(wrptr, 0x1B,
239 200*1000*1000/var->pixclock);
Bernie Thompson59277b62009-11-24 15:52:21 -0800240
241 return wrptr;
242}
243
244/*
245 * This takes a standard fbdev screeninfo struct that was fetched or prepared
246 * and then generates the appropriate command sequence that then drives the
247 * display controller.
248 */
249static int dlfb_set_video_mode(struct dlfb_data *dev,
250 struct fb_var_screeninfo *var)
251{
252 char *buf;
253 char *wrptr;
254 int retval = 0;
255 int writesize;
Bernie Thompson530f43a2010-02-15 06:46:21 -0800256 struct urb *urb;
Bernie Thompson59277b62009-11-24 15:52:21 -0800257
Bernie Thompson530f43a2010-02-15 06:46:21 -0800258 if (!atomic_read(&dev->usb_active))
259 return -EPERM;
260
261 urb = dlfb_get_urb(dev);
262 if (!urb)
263 return -ENOMEM;
264 buf = (char *) urb->transfer_buffer;
Bernie Thompson59277b62009-11-24 15:52:21 -0800265
266 /*
267 * This first section has to do with setting the base address on the
268 * controller * associated with the display. There are 2 base
269 * pointers, currently, we only * use the 16 bpp segment.
270 */
Bernie Thompson45742032010-02-15 06:46:04 -0800271 wrptr = dlfb_vidreg_lock(buf);
272 wrptr = dlfb_set_color_depth(wrptr, 0x00);
Bernie Thompson59277b62009-11-24 15:52:21 -0800273 /* set base for 16bpp segment to 0 */
Bernie Thompson45742032010-02-15 06:46:04 -0800274 wrptr = dlfb_set_base16bpp(wrptr, 0);
Bernie Thompson59277b62009-11-24 15:52:21 -0800275 /* set base for 8bpp segment to end of fb */
Bernie Thompson45742032010-02-15 06:46:04 -0800276 wrptr = dlfb_set_base8bpp(wrptr, dev->info->fix.smem_len);
Bernie Thompson59277b62009-11-24 15:52:21 -0800277
Bernie Thompson45742032010-02-15 06:46:04 -0800278 wrptr = dlfb_set_vid_cmds(wrptr, var);
Bernie Thompson530f43a2010-02-15 06:46:21 -0800279 wrptr = dlfb_enable_hvsync(wrptr, true);
Bernie Thompson45742032010-02-15 06:46:04 -0800280 wrptr = dlfb_vidreg_unlock(wrptr);
Bernie Thompson59277b62009-11-24 15:52:21 -0800281
282 writesize = wrptr - buf;
283
Bernie Thompson530f43a2010-02-15 06:46:21 -0800284 retval = dlfb_submit_urb(dev, urb, writesize);
Bernie Thompson59277b62009-11-24 15:52:21 -0800285
Bernie Thompson59277b62009-11-24 15:52:21 -0800286 return retval;
287}
288
Bernie Thompson45742032010-02-15 06:46:04 -0800289static int dlfb_ops_mmap(struct fb_info *info, struct vm_area_struct *vma)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700290{
291 unsigned long start = vma->vm_start;
292 unsigned long size = vma->vm_end - vma->vm_start;
293 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
294 unsigned long page, pos;
295
296 printk("MMAP: %lu %u\n", offset + size, info->fix.smem_len);
297
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700298 if (offset + size > info->fix.smem_len)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700299 return -EINVAL;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700300
301 pos = (unsigned long)info->fix.smem_start + offset;
302
303 while (size > 0) {
304 page = vmalloc_to_pfn((void *)pos);
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700305 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700306 return -EAGAIN;
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700307
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700308 start += PAGE_SIZE;
309 pos += PAGE_SIZE;
310 if (size > PAGE_SIZE)
311 size -= PAGE_SIZE;
312 else
313 size = 0;
314 }
315
316 vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */
317 return 0;
318
319}
320
Bernie Thompson530f43a2010-02-15 06:46:21 -0800321/*
322 * Trims identical data from front and back of line
323 * Sets new front buffer address and width
324 * And returns byte count of identical pixels
325 * Assumes CPU natural alignment (unsigned long)
326 * for back and front buffer ptrs and width
327 */
328static int dlfb_trim_hline(const u8 *bback, const u8 **bfront, int *width_bytes)
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700329{
Bernie Thompson530f43a2010-02-15 06:46:21 -0800330 int j, k;
331 const unsigned long *back = (const unsigned long *) bback;
332 const unsigned long *front = (const unsigned long *) *bfront;
333 const int width = *width_bytes / sizeof(unsigned long);
334 int identical = width;
335 int start = width;
336 int end = width;
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700337
Bernie Thompson530f43a2010-02-15 06:46:21 -0800338 prefetch((void *) front);
339 prefetch((void *) back);
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700340
Bernie Thompson530f43a2010-02-15 06:46:21 -0800341 for (j = 0; j < width; j++) {
342 if (back[j] != front[j]) {
343 start = j;
344 break;
345 }
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700346 }
347
Bernie Thompson530f43a2010-02-15 06:46:21 -0800348 for (k = width - 1; k > j; k--) {
349 if (back[k] != front[k]) {
350 end = k+1;
351 break;
352 }
353 }
354
355 identical = start + (width - end);
356 *bfront = (u8 *) &front[start];
357 *width_bytes = (end - start) * sizeof(unsigned long);
358
359 return identical * sizeof(unsigned long);
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700360}
361
362/*
Bernie Thompson530f43a2010-02-15 06:46:21 -0800363Render a command stream for an encoded horizontal line segment of pixels.
364
365A command buffer holds several commands.
366It always begins with a fresh command header
367(the protocol doesn't require this, but we enforce it to allow
368multiple buffers to be potentially encoded and sent in parallel).
369A single command encodes one contiguous horizontal line of pixels
370
371The function relies on the client to do all allocation, so that
372rendering can be done directly to output buffers (e.g. USB URBs).
373The function fills the supplied command buffer, providing information
374on where it left off, so the client may call in again with additional
375buffers if the line will take several buffers to complete.
376
377A single command can transmit a maximum of 256 pixels,
378regardless of the compression ratio (protocol design limit).
379To the hardware, 0 for a size byte means 256
380
381Rather than 256 pixel commands which are either rl or raw encoded,
382the rlx command simply assumes alternating raw and rl spans within one cmd.
383This has a slightly larger header overhead, but produces more even results.
384It also processes all data (read and write) in a single pass.
385Performance benchmarks of common cases show it having just slightly better
386compression than 256 pixel raw -or- rle commands, with similar CPU consumpion.
387But for very rl friendly data, will compress not quite as well.
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700388*/
Bernie Thompson530f43a2010-02-15 06:46:21 -0800389static void dlfb_compress_hline(
390 const uint16_t **pixel_start_ptr,
391 const uint16_t *const pixel_end,
392 uint32_t *device_address_ptr,
393 uint8_t **command_buffer_ptr,
394 const uint8_t *const cmd_buffer_end)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700395{
Bernie Thompson530f43a2010-02-15 06:46:21 -0800396 const uint16_t *pixel = *pixel_start_ptr;
397 uint32_t dev_addr = *device_address_ptr;
398 uint8_t *cmd = *command_buffer_ptr;
399 const int bpp = 2;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700400
Bernie Thompson530f43a2010-02-15 06:46:21 -0800401 while ((pixel_end > pixel) &&
402 (cmd_buffer_end - MIN_RLX_CMD_BYTES > cmd)) {
403 uint8_t *raw_pixels_count_byte = 0;
404 uint8_t *cmd_pixels_count_byte = 0;
405 const uint16_t *raw_pixel_start = 0;
406 const uint16_t *cmd_pixel_start, *cmd_pixel_end = 0;
407 const uint32_t be_dev_addr = cpu_to_be32(dev_addr);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700408
Bernie Thompson530f43a2010-02-15 06:46:21 -0800409 prefetchw((void *) cmd); /* pull in one cache line at least */
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700410
Bernie Thompson530f43a2010-02-15 06:46:21 -0800411 *cmd++ = 0xAF;
412 *cmd++ = 0x6B;
413 *cmd++ = (uint8_t) ((be_dev_addr >> 8) & 0xFF);
414 *cmd++ = (uint8_t) ((be_dev_addr >> 16) & 0xFF);
415 *cmd++ = (uint8_t) ((be_dev_addr >> 24) & 0xFF);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700416
Bernie Thompson530f43a2010-02-15 06:46:21 -0800417 cmd_pixels_count_byte = cmd++; /* we'll know this later */
418 cmd_pixel_start = pixel;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700419
Bernie Thompson530f43a2010-02-15 06:46:21 -0800420 raw_pixels_count_byte = cmd++; /* we'll know this later */
421 raw_pixel_start = pixel;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700422
Bernie Thompson530f43a2010-02-15 06:46:21 -0800423 cmd_pixel_end = pixel + min(MAX_CMD_PIXELS + 1,
424 min((int)(pixel_end - pixel),
425 (int)(cmd_buffer_end - cmd) / bpp));
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700426
Bernie Thompson530f43a2010-02-15 06:46:21 -0800427 prefetch_range((void *) pixel, (cmd_pixel_end - pixel) * bpp);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700428
Bernie Thompson530f43a2010-02-15 06:46:21 -0800429 while (pixel < cmd_pixel_end) {
430 const uint16_t * const repeating_pixel = pixel;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700431
Bernie Thompson530f43a2010-02-15 06:46:21 -0800432 *(uint16_t *)cmd = cpu_to_be16p(pixel);
433 cmd += 2;
434 pixel++;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700435
Bernie Thompson530f43a2010-02-15 06:46:21 -0800436 if (unlikely((pixel < cmd_pixel_end) &&
437 (*pixel == *repeating_pixel))) {
438 /* go back and fill in raw pixel count */
439 *raw_pixels_count_byte = ((repeating_pixel -
440 raw_pixel_start) + 1) & 0xFF;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700441
Bernie Thompson530f43a2010-02-15 06:46:21 -0800442 while ((pixel < cmd_pixel_end)
443 && (*pixel == *repeating_pixel)) {
444 pixel++;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700445 }
Bernie Thompson59277b62009-11-24 15:52:21 -0800446
Bernie Thompson530f43a2010-02-15 06:46:21 -0800447 /* immediately after raw data is repeat byte */
448 *cmd++ = ((pixel - repeating_pixel) - 1) & 0xFF;
Bernie Thompson59277b62009-11-24 15:52:21 -0800449
Bernie Thompson530f43a2010-02-15 06:46:21 -0800450 /* Then start another raw pixel span */
451 raw_pixel_start = pixel;
452 raw_pixels_count_byte = cmd++;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700453 }
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700454 }
455
Bernie Thompson530f43a2010-02-15 06:46:21 -0800456 if (pixel > raw_pixel_start) {
457 /* finalize last RAW span */
458 *raw_pixels_count_byte = (pixel-raw_pixel_start) & 0xFF;
459 }
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700460
Bernie Thompson530f43a2010-02-15 06:46:21 -0800461 *cmd_pixels_count_byte = (pixel - cmd_pixel_start) & 0xFF;
462 dev_addr += (pixel - cmd_pixel_start) * bpp;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700463 }
464
Bernie Thompson530f43a2010-02-15 06:46:21 -0800465 if (cmd_buffer_end <= MIN_RLX_CMD_BYTES + cmd) {
466 /* Fill leftover bytes with no-ops */
467 if (cmd_buffer_end > cmd)
468 memset(cmd, 0xAF, cmd_buffer_end - cmd);
469 cmd = (uint8_t *) cmd_buffer_end;
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700470 }
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700471
Bernie Thompson530f43a2010-02-15 06:46:21 -0800472 *command_buffer_ptr = cmd;
473 *pixel_start_ptr = pixel;
474 *device_address_ptr = dev_addr;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700475
Bernie Thompson530f43a2010-02-15 06:46:21 -0800476 return;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700477}
478
Bernie Thompson530f43a2010-02-15 06:46:21 -0800479/*
480 * There are 3 copies of every pixel: The front buffer that the fbdev
481 * client renders to, the actual framebuffer across the USB bus in hardware
482 * (that we can only write to, slowly, and can never read), and (optionally)
483 * our shadow copy that tracks what's been sent to that hardware buffer.
484 */
485static void dlfb_render_hline(struct dlfb_data *dev, struct urb **urb_ptr,
486 const char *front, char **urb_buf_ptr,
487 u32 byte_offset, u32 byte_width,
488 int *ident_ptr, int *sent_ptr)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700489{
Bernie Thompson530f43a2010-02-15 06:46:21 -0800490 const u8 *line_start, *line_end, *next_pixel;
491 u32 dev_addr = dev->base16 + byte_offset;
492 struct urb *urb = *urb_ptr;
493 u8 *cmd = *urb_buf_ptr;
494 u8 *cmd_end = (u8 *) urb->transfer_buffer + urb->transfer_buffer_length;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700495
Bernie Thompson530f43a2010-02-15 06:46:21 -0800496 line_start = (u8 *) (front + byte_offset);
497 next_pixel = line_start;
498 line_end = next_pixel + byte_width;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700499
Bernie Thompson530f43a2010-02-15 06:46:21 -0800500 if (dev->backing_buffer) {
501 int offset;
502 const u8 *back_start = (u8 *) (dev->backing_buffer
503 + byte_offset);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700504
Bernie Thompson530f43a2010-02-15 06:46:21 -0800505 *ident_ptr += dlfb_trim_hline(back_start, &next_pixel,
506 &byte_width);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700507
Bernie Thompson530f43a2010-02-15 06:46:21 -0800508 offset = next_pixel - line_start;
509 line_end = next_pixel + byte_width;
510 dev_addr += offset;
511 back_start += offset;
512 line_start += offset;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700513
Bernie Thompson530f43a2010-02-15 06:46:21 -0800514 memcpy((char *)back_start, (char *) line_start,
515 byte_width);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700516 }
517
Bernie Thompson530f43a2010-02-15 06:46:21 -0800518 while (next_pixel < line_end) {
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700519
Bernie Thompson530f43a2010-02-15 06:46:21 -0800520 dlfb_compress_hline((const uint16_t **) &next_pixel,
521 (const uint16_t *) line_end, &dev_addr,
522 (u8 **) &cmd, (u8 *) cmd_end);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700523
Bernie Thompson530f43a2010-02-15 06:46:21 -0800524 if (cmd >= cmd_end) {
525 int len = cmd - (u8 *) urb->transfer_buffer;
526 if (dlfb_submit_urb(dev, urb, len))
527 return; /* lost pixels is set */
528 *sent_ptr += len;
529 urb = dlfb_get_urb(dev);
530 if (!urb)
531 return; /* lost_pixels is set */
532 *urb_ptr = urb;
533 cmd = urb->transfer_buffer;
534 cmd_end = &cmd[urb->transfer_buffer_length];
535 }
536 }
537
538 *urb_buf_ptr = cmd;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700539}
540
Bernie Thompson530f43a2010-02-15 06:46:21 -0800541int dlfb_handle_damage(struct dlfb_data *dev, int x, int y,
542 int width, int height, char *data)
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700543{
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700544 int i, ret;
Bernie Thompson530f43a2010-02-15 06:46:21 -0800545 char *cmd;
546 cycles_t start_cycles, end_cycles;
547 int bytes_sent = 0;
548 int bytes_identical = 0;
549 struct urb *urb;
550 int aligned_x;
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700551
Bernie Thompson530f43a2010-02-15 06:46:21 -0800552 start_cycles = get_cycles();
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700553
Bernie Thompson530f43a2010-02-15 06:46:21 -0800554 aligned_x = DL_ALIGN_DOWN(x, sizeof(unsigned long));
555 width = DL_ALIGN_UP(width + (x-aligned_x), sizeof(unsigned long));
556 x = aligned_x;
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700557
Bernie Thompson530f43a2010-02-15 06:46:21 -0800558 if ((width <= 0) ||
559 (x + width > dev->info->var.xres) ||
560 (y + height > dev->info->var.yres))
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700561 return -EINVAL;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700562
Bernie Thompson530f43a2010-02-15 06:46:21 -0800563 if (!atomic_read(&dev->usb_active))
564 return 0;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700565
Bernie Thompson530f43a2010-02-15 06:46:21 -0800566 urb = dlfb_get_urb(dev);
567 if (!urb)
568 return 0;
569 cmd = urb->transfer_buffer;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700570
Bernie Thompson530f43a2010-02-15 06:46:21 -0800571 for (i = y; i < y + height ; i++) {
572 const int line_offset = dev->info->fix.line_length * i;
573 const int byte_offset = line_offset + (x * BPP);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700574
Bernie Thompson530f43a2010-02-15 06:46:21 -0800575 dlfb_render_hline(dev, &urb, (char *) dev->info->fix.smem_start,
576 &cmd, byte_offset, width * BPP,
577 &bytes_identical, &bytes_sent);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700578 }
579
Bernie Thompson530f43a2010-02-15 06:46:21 -0800580 if (cmd > (char *) urb->transfer_buffer) {
581 /* Send partial buffer remaining before exiting */
582 int len = cmd - (char *) urb->transfer_buffer;
583 ret = dlfb_submit_urb(dev, urb, len);
584 bytes_sent += len;
585 } else
586 dlfb_urb_completion(urb);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700587
Bernie Thompson530f43a2010-02-15 06:46:21 -0800588 atomic_add(bytes_sent, &dev->bytes_sent);
589 atomic_add(bytes_identical, &dev->bytes_identical);
590 atomic_add(width*height*2, &dev->bytes_rendered);
591 end_cycles = get_cycles();
592 atomic_add(((unsigned int) ((end_cycles - start_cycles)
593 >> 10)), /* Kcycles */
594 &dev->cpu_kcycles_used);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700595
Bernie Thompson530f43a2010-02-15 06:46:21 -0800596 return 0;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700597}
598
Bernie Thompson530f43a2010-02-15 06:46:21 -0800599/* hardware has native COPY command (see libdlo), but not worth it for fbcon */
Bernie Thompson45742032010-02-15 06:46:04 -0800600static void dlfb_ops_copyarea(struct fb_info *info,
Bernie Thompson530f43a2010-02-15 06:46:21 -0800601 const struct fb_copyarea *area)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700602{
Bernie Thompson530f43a2010-02-15 06:46:21 -0800603
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700604 struct dlfb_data *dev = info->par;
605
Bernie Thompson530f43a2010-02-15 06:46:21 -0800606#if defined CONFIG_FB_SYS_COPYAREA || defined CONFIG_FB_SYS_COPYAREA_MODULE
607
608 sys_copyarea(info, area);
609
610 dlfb_handle_damage(dev, area->dx, area->dy,
611 area->width, area->height, info->screen_base);
612#endif
613 atomic_inc(&dev->copy_count);
614
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700615}
616
Bernie Thompson45742032010-02-15 06:46:04 -0800617static void dlfb_ops_imageblit(struct fb_info *info,
Bernie Thompson530f43a2010-02-15 06:46:21 -0800618 const struct fb_image *image)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700619{
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700620 struct dlfb_data *dev = info->par;
Bernie Thompson530f43a2010-02-15 06:46:21 -0800621
622#if defined CONFIG_FB_SYS_IMAGEBLIT || defined CONFIG_FB_SYS_IMAGEBLIT_MODULE
623
624 sys_imageblit(info, image);
625
626 dlfb_handle_damage(dev, image->dx, image->dy,
627 image->width, image->height, info->screen_base);
628
629#endif
630
631 atomic_inc(&dev->blit_count);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700632}
633
Bernie Thompson45742032010-02-15 06:46:04 -0800634static void dlfb_ops_fillrect(struct fb_info *info,
Bernie Thompson530f43a2010-02-15 06:46:21 -0800635 const struct fb_fillrect *rect)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700636{
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700637 struct dlfb_data *dev = info->par;
638
Bernie Thompson530f43a2010-02-15 06:46:21 -0800639#if defined CONFIG_FB_SYS_FILLRECT || defined CONFIG_FB_SYS_FILLRECT_MODULE
640
641 sys_fillrect(info, rect);
642
643 dlfb_handle_damage(dev, rect->dx, rect->dy, rect->width,
644 rect->height, info->screen_base);
645#endif
646
647 atomic_inc(&dev->fill_count);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700648
649}
650
Bernie Thompson7d9485e2010-02-15 06:46:08 -0800651static void dlfb_get_edid(struct dlfb_data *dev)
652{
653 int i;
654 int ret;
655 char rbuf[2];
656
657 for (i = 0; i < sizeof(dev->edid); i++) {
658 ret = usb_control_msg(dev->udev,
659 usb_rcvctrlpipe(dev->udev, 0), (0x02),
660 (0x80 | (0x02 << 5)), i << 8, 0xA1, rbuf, 2,
661 0);
662 dev->edid[i] = rbuf[1];
663 }
664}
665
Bernie Thompson45742032010-02-15 06:46:04 -0800666static int dlfb_ops_ioctl(struct fb_info *info, unsigned int cmd,
Bernie Thompson530f43a2010-02-15 06:46:21 -0800667 unsigned long arg)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700668{
Bernie Thompson530f43a2010-02-15 06:46:21 -0800669
670 struct dlfb_data *dev = info->par;
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700671 struct dloarea *area = NULL;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700672
Bernie Thompson530f43a2010-02-15 06:46:21 -0800673 if (!atomic_read(&dev->usb_active))
674 return 0;
675
676 /* TODO: Update X server to get this from sysfs instead */
677 if (cmd == DLFB_IOCTL_RETURN_EDID) {
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700678 char *edid = (char *)arg;
Bernie Thompson530f43a2010-02-15 06:46:21 -0800679 dlfb_get_edid(dev);
680 if (copy_to_user(edid, dev->edid, sizeof(dev->edid)))
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700681 return -EFAULT;
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700682 return 0;
683 }
684
Bernie Thompson530f43a2010-02-15 06:46:21 -0800685 /* TODO: Help propose a standard fb.h ioctl to report mmap damage */
686 if (cmd == DLFB_IOCTL_REPORT_DAMAGE) {
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700687
688 area = (struct dloarea *)arg;
689
690 if (area->x < 0)
691 area->x = 0;
692
693 if (area->x > info->var.xres)
694 area->x = info->var.xres;
695
696 if (area->y < 0)
697 area->y = 0;
698
699 if (area->y > info->var.yres)
700 area->y = info->var.yres;
701
Bernie Thompson530f43a2010-02-15 06:46:21 -0800702 atomic_set(&dev->use_defio, 0);
703
704 dlfb_handle_damage(dev, area->x, area->y, area->w, area->h,
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700705 info->screen_base);
Bernie Thompson530f43a2010-02-15 06:46:21 -0800706 atomic_inc(&dev->damage_count);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700707 }
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700708
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700709 return 0;
710}
711
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700712/* taken from vesafb */
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700713static int
Bernie Thompson45742032010-02-15 06:46:04 -0800714dlfb_ops_setcolreg(unsigned regno, unsigned red, unsigned green,
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700715 unsigned blue, unsigned transp, struct fb_info *info)
716{
717 int err = 0;
718
719 if (regno >= info->cmap.len)
720 return 1;
721
722 if (regno < 16) {
723 if (info->var.red.offset == 10) {
724 /* 1:5:5:5 */
725 ((u32 *) (info->pseudo_palette))[regno] =
726 ((red & 0xf800) >> 1) |
727 ((green & 0xf800) >> 6) | ((blue & 0xf800) >> 11);
728 } else {
729 /* 0:5:6:5 */
730 ((u32 *) (info->pseudo_palette))[regno] =
731 ((red & 0xf800)) |
732 ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
733 }
734 }
735
736 return err;
737}
738
Bernie Thompson3e8f3d62010-02-15 06:46:26 -0800739/*
740 * It's common for several clients to have framebuffer open simultaneously.
741 * e.g. both fbcon and X. Makes things interesting.
742 */
743static int dlfb_ops_open(struct fb_info *info, int user)
744{
745 struct dlfb_data *dev = info->par;
746
747/* if (user == 0)
748 * We could special case kernel mode clients (fbcon) here
749 */
750
751 mutex_lock(&dev->fb_open_lock);
752
753 dev->fb_count++;
754
755#ifdef CONFIG_FB_DEFERRED_IO
756 if ((atomic_read(&dev->use_defio)) && (info->fbdefio == NULL)) {
757 /* enable defio */
758 info->fbdefio = &dlfb_defio;
759 fb_deferred_io_init(info);
760 }
761#endif
762
763 dl_notice("open /dev/fb%d user=%d fb_info=%p count=%d\n",
764 info->node, user, info, dev->fb_count);
765
766 mutex_unlock(&dev->fb_open_lock);
767
768 return 0;
769}
770
Bernie Thompson45742032010-02-15 06:46:04 -0800771static int dlfb_ops_release(struct fb_info *info, int user)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700772{
Bernie Thompson3e8f3d62010-02-15 06:46:26 -0800773 struct dlfb_data *dev = info->par;
774
775 mutex_lock(&dev->fb_open_lock);
776
777 dev->fb_count--;
778
779#ifdef CONFIG_FB_DEFERRED_IO
780 if ((dev->fb_count == 0) && (info->fbdefio)) {
781 fb_deferred_io_cleanup(info);
782 info->fbdefio = NULL;
783 info->fbops->fb_mmap = dlfb_ops_mmap;
784 }
785#endif
786
787 dl_notice("release /dev/fb%d user=%d count=%d\n",
788 info->node, user, dev->fb_count);
789
790 mutex_unlock(&dev->fb_open_lock);
791
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700792 return 0;
793}
794
Bernie Thompson4a4854d2010-02-15 06:45:55 -0800795/*
796 * Called when all client interfaces to start transactions have been disabled,
797 * and all references to our device instance (dlfb_data) are released.
798 * Every transaction must have a reference, so we know are fully spun down
799 */
800static void dlfb_delete(struct kref *kref)
801{
802 struct dlfb_data *dev = container_of(kref, struct dlfb_data, kref);
803
804 if (dev->backing_buffer)
805 vfree(dev->backing_buffer);
806
Bernie Thompson3e8f3d62010-02-15 06:46:26 -0800807 mutex_destroy(&dev->fb_open_lock);
808
Bernie Thompson4a4854d2010-02-15 06:45:55 -0800809 kfree(dev);
810}
811
Bernie Thompson7d9485e2010-02-15 06:46:08 -0800812/*
Bernie Thompson2469d5d2010-02-15 06:46:13 -0800813 * Called by fbdev as last part of unregister_framebuffer() process
814 * No new clients can open connections. Deallocate everything fb_info.
815 */
816static void dlfb_ops_destroy(struct fb_info *info)
817{
818 struct dlfb_data *dev = info->par;
819
820 if (info->cmap.len != 0)
821 fb_dealloc_cmap(&info->cmap);
822 if (info->monspecs.modedb)
823 fb_destroy_modedb(info->monspecs.modedb);
824 if (info->screen_base)
825 vfree(info->screen_base);
826
827 fb_destroy_modelist(&info->modelist);
828
829 framebuffer_release(info);
830
831 /* ref taken before register_framebuffer() for dlfb_data clients */
832 kref_put(&dev->kref, dlfb_delete);
833}
834
835/*
Bernie Thompson7d9485e2010-02-15 06:46:08 -0800836 * Check whether a video mode is supported by the DisplayLink chip
837 * We start from monitor's modes, so don't need to filter that here
838 */
839static int dlfb_is_valid_mode(struct fb_videomode *mode,
840 struct fb_info *info)
841{
842 struct dlfb_data *dev = info->par;
843
844 if (mode->xres * mode->yres > dev->sku_pixel_limit)
845 return 0;
846
847 return 1;
848}
849
850static void dlfb_var_color_format(struct fb_var_screeninfo *var)
851{
852 const struct fb_bitfield red = { 11, 5, 0 };
853 const struct fb_bitfield green = { 5, 6, 0 };
854 const struct fb_bitfield blue = { 0, 5, 0 };
855
856 var->bits_per_pixel = 16;
857 var->red = red;
858 var->green = green;
859 var->blue = blue;
860}
861
Bernie Thompson2469d5d2010-02-15 06:46:13 -0800862static int dlfb_ops_check_var(struct fb_var_screeninfo *var,
863 struct fb_info *info)
864{
865 struct fb_videomode mode;
866
867 /* TODO: support dynamically changing framebuffer size */
868 if ((var->xres * var->yres * 2) > info->fix.smem_len)
869 return -EINVAL;
870
871 /* set device-specific elements of var unrelated to mode */
872 dlfb_var_color_format(var);
873
874 fb_var_to_videomode(&mode, var);
875
876 if (!dlfb_is_valid_mode(&mode, info))
877 return -EINVAL;
878
879 return 0;
880}
881
882static int dlfb_ops_set_par(struct fb_info *info)
883{
884 struct dlfb_data *dev = info->par;
885
886 dl_notice("set_par mode %dx%d\n", info->var.xres, info->var.yres);
887
888 return dlfb_set_video_mode(dev, &info->var);
889}
890
Bernie Thompson45742032010-02-15 06:46:04 -0800891static int dlfb_ops_blank(int blank_mode, struct fb_info *info)
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700892{
Bernie Thompson530f43a2010-02-15 06:46:21 -0800893 struct dlfb_data *dev = info->par;
894 char *bufptr;
895 struct urb *urb;
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700896
Bernie Thompson530f43a2010-02-15 06:46:21 -0800897 urb = dlfb_get_urb(dev);
898 if (!urb)
899 return 0;
900 bufptr = (char *) urb->transfer_buffer;
901
902 /* overloading usb_active. UNBLANK can conflict with teardown */
903
904 bufptr = dlfb_vidreg_lock(bufptr);
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700905 if (blank_mode != FB_BLANK_UNBLANK) {
Bernie Thompson530f43a2010-02-15 06:46:21 -0800906 atomic_set(&dev->usb_active, 0);
907 bufptr = dlfb_enable_hvsync(bufptr, false);
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700908 } else {
Bernie Thompson530f43a2010-02-15 06:46:21 -0800909 atomic_set(&dev->usb_active, 1);
910 bufptr = dlfb_enable_hvsync(bufptr, true);
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700911 }
Bernie Thompson530f43a2010-02-15 06:46:21 -0800912 bufptr = dlfb_vidreg_unlock(bufptr);
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700913
Bernie Thompson530f43a2010-02-15 06:46:21 -0800914 dlfb_submit_urb(dev, urb, bufptr - (char *) urb->transfer_buffer);
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700915
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700916 return 0;
917}
918
919static struct fb_ops dlfb_ops = {
Bernie Thompson2469d5d2010-02-15 06:46:13 -0800920 .owner = THIS_MODULE,
Bernie Thompson45742032010-02-15 06:46:04 -0800921 .fb_setcolreg = dlfb_ops_setcolreg,
922 .fb_fillrect = dlfb_ops_fillrect,
923 .fb_copyarea = dlfb_ops_copyarea,
924 .fb_imageblit = dlfb_ops_imageblit,
925 .fb_mmap = dlfb_ops_mmap,
926 .fb_ioctl = dlfb_ops_ioctl,
Bernie Thompson3e8f3d62010-02-15 06:46:26 -0800927 .fb_open = dlfb_ops_open,
Bernie Thompson45742032010-02-15 06:46:04 -0800928 .fb_release = dlfb_ops_release,
929 .fb_blank = dlfb_ops_blank,
Bernie Thompson2469d5d2010-02-15 06:46:13 -0800930 .fb_check_var = dlfb_ops_check_var,
931 .fb_set_par = dlfb_ops_set_par,
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700932};
933
Bernie Thompsoncc403dc2010-02-15 06:45:49 -0800934/*
Bernie Thompson7d9485e2010-02-15 06:46:08 -0800935 * Calls dlfb_get_edid() to query the EDID of attached monitor via usb cmds
936 * Then parses EDID into three places used by various parts of fbdev:
937 * fb_var_screeninfo contains the timing of the monitor's preferred mode
938 * fb_info.monspecs is full parsed EDID info, including monspecs.modedb
939 * fb_info.modelist is a linked list of all monitor & VESA modes which work
940 *
941 * If EDID is not readable/valid, then modelist is all VESA modes,
942 * monspecs is NULL, and fb_var_screeninfo is set to safe VESA mode
943 * Returns 0 if EDID parses successfully
944 */
945static int dlfb_parse_edid(struct dlfb_data *dev,
946 struct fb_var_screeninfo *var,
947 struct fb_info *info)
948{
949 int i;
950 const struct fb_videomode *default_vmode = NULL;
951 int result = 0;
952
953 fb_destroy_modelist(&info->modelist);
954 memset(&info->monspecs, 0, sizeof(info->monspecs));
955
956 dlfb_get_edid(dev);
957 fb_edid_to_monspecs(dev->edid, &info->monspecs);
958
959 if (info->monspecs.modedb_len > 0) {
960
961 for (i = 0; i < info->monspecs.modedb_len; i++) {
962 if (dlfb_is_valid_mode(&info->monspecs.modedb[i], info))
963 fb_add_videomode(&info->monspecs.modedb[i],
964 &info->modelist);
965 }
966
967 default_vmode = fb_find_best_display(&info->monspecs,
968 &info->modelist);
969 } else {
970 struct fb_videomode fb_vmode = {0};
971
972 dl_err("Unable to get valid EDID from device/display\n");
973 result = 1;
974
975 /*
976 * Add the standard VESA modes to our modelist
977 * Since we don't have EDID, there may be modes that
978 * overspec monitor and/or are incorrect aspect ratio, etc.
979 * But at least the user has a chance to choose
980 */
981 for (i = 0; i < VESA_MODEDB_SIZE; i++) {
982 if (dlfb_is_valid_mode((struct fb_videomode *)
983 &vesa_modes[i], info))
984 fb_add_videomode(&vesa_modes[i],
985 &info->modelist);
986 }
987
988 /*
989 * default to resolution safe for projectors
990 * (since they are most common case without EDID)
991 */
992 fb_vmode.xres = 800;
993 fb_vmode.yres = 600;
994 fb_vmode.refresh = 60;
995 default_vmode = fb_find_nearest_mode(&fb_vmode,
996 &info->modelist);
997 }
998
999 fb_videomode_to_var(var, default_vmode);
1000 dlfb_var_color_format(var);
1001
1002 return result;
1003}
1004
1005static ssize_t metrics_bytes_rendered_show(struct device *fbdev,
1006 struct device_attribute *a, char *buf) {
1007 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1008 struct dlfb_data *dev = fb_info->par;
1009 return snprintf(buf, PAGE_SIZE, "%u\n",
1010 atomic_read(&dev->bytes_rendered));
1011}
1012
1013static ssize_t metrics_bytes_identical_show(struct device *fbdev,
1014 struct device_attribute *a, char *buf) {
1015 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1016 struct dlfb_data *dev = fb_info->par;
1017 return snprintf(buf, PAGE_SIZE, "%u\n",
1018 atomic_read(&dev->bytes_identical));
1019}
1020
1021static ssize_t metrics_bytes_sent_show(struct device *fbdev,
1022 struct device_attribute *a, char *buf) {
1023 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1024 struct dlfb_data *dev = fb_info->par;
1025 return snprintf(buf, PAGE_SIZE, "%u\n",
1026 atomic_read(&dev->bytes_sent));
1027}
1028
1029static ssize_t metrics_cpu_kcycles_used_show(struct device *fbdev,
1030 struct device_attribute *a, char *buf) {
1031 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1032 struct dlfb_data *dev = fb_info->par;
1033 return snprintf(buf, PAGE_SIZE, "%u\n",
1034 atomic_read(&dev->cpu_kcycles_used));
1035}
1036
1037static ssize_t metrics_misc_show(struct device *fbdev,
1038 struct device_attribute *a, char *buf) {
1039 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1040 struct dlfb_data *dev = fb_info->par;
1041 return snprintf(buf, PAGE_SIZE,
1042 "Calls to\ndamage: %u\nblit: %u\n"
1043 "defio faults: %u\ncopy: %u\n"
1044 "fill: %u\n\n"
1045 "active framebuffer clients: %d\n"
1046 "urbs available %d(%d)\n"
1047 "Shadow framebuffer in use? %s\n"
1048 "Any lost pixels? %s\n",
1049 atomic_read(&dev->damage_count),
1050 atomic_read(&dev->blit_count),
1051 atomic_read(&dev->defio_fault_count),
1052 atomic_read(&dev->copy_count),
1053 atomic_read(&dev->fill_count),
1054 dev->fb_count,
1055 dev->urbs.available, dev->urbs.limit_sem.count,
1056 (dev->backing_buffer) ? "yes" : "no",
1057 atomic_read(&dev->lost_pixels) ? "yes" : "no");
1058}
1059
1060static ssize_t edid_show(struct kobject *kobj, struct bin_attribute *a,
1061 char *buf, loff_t off, size_t count) {
1062 struct device *fbdev = container_of(kobj, struct device, kobj);
1063 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1064 struct dlfb_data *dev = fb_info->par;
1065 char *edid = &dev->edid[0];
1066 const size_t size = sizeof(dev->edid);
1067
1068 if (dlfb_parse_edid(dev, &fb_info->var, fb_info))
1069 return 0;
1070
1071 if (off >= size)
1072 return 0;
1073
1074 if (off + count > size)
1075 count = size - off;
1076 memcpy(buf, edid + off, count);
1077
1078 return count;
1079}
1080
1081
1082static ssize_t metrics_reset_store(struct device *fbdev,
1083 struct device_attribute *attr,
1084 const char *buf, size_t count)
1085{
1086 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1087 struct dlfb_data *dev = fb_info->par;
1088
1089 atomic_set(&dev->bytes_rendered, 0);
1090 atomic_set(&dev->bytes_identical, 0);
1091 atomic_set(&dev->bytes_sent, 0);
1092 atomic_set(&dev->cpu_kcycles_used, 0);
1093 atomic_set(&dev->blit_count, 0);
1094 atomic_set(&dev->copy_count, 0);
1095 atomic_set(&dev->fill_count, 0);
1096 atomic_set(&dev->defio_fault_count, 0);
1097 atomic_set(&dev->damage_count, 0);
1098
1099 return count;
1100}
1101
1102static ssize_t use_defio_show(struct device *fbdev,
1103 struct device_attribute *a, char *buf) {
1104 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1105 struct dlfb_data *dev = fb_info->par;
1106 return snprintf(buf, PAGE_SIZE, "%d\n",
1107 atomic_read(&dev->use_defio));
1108}
1109
1110static ssize_t use_defio_store(struct device *fbdev,
1111 struct device_attribute *attr,
1112 const char *buf, size_t count)
1113{
1114 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1115 struct dlfb_data *dev = fb_info->par;
1116
1117 if (count > 0) {
1118 if (buf[0] == '0')
1119 atomic_set(&dev->use_defio, 0);
1120 if (buf[0] == '1')
1121 atomic_set(&dev->use_defio, 1);
1122 }
1123 return count;
1124}
1125
1126static struct bin_attribute edid_attr = {
1127 .attr.name = "edid",
1128 .attr.mode = 0444,
1129 .size = 128,
1130 .read = edid_show,
1131};
1132
1133static struct device_attribute fb_device_attrs[] = {
1134 __ATTR_RO(metrics_bytes_rendered),
1135 __ATTR_RO(metrics_bytes_identical),
1136 __ATTR_RO(metrics_bytes_sent),
1137 __ATTR_RO(metrics_cpu_kcycles_used),
1138 __ATTR_RO(metrics_misc),
1139 __ATTR(metrics_reset, S_IWUGO, NULL, metrics_reset_store),
1140 __ATTR_RW(use_defio),
1141};
1142
Bernie Thompson3e8f3d62010-02-15 06:46:26 -08001143#ifdef CONFIG_FB_DEFERRED_IO
1144static void dlfb_dpy_deferred_io(struct fb_info *info,
1145 struct list_head *pagelist)
1146{
1147 struct page *cur;
1148 struct fb_deferred_io *fbdefio = info->fbdefio;
1149 struct dlfb_data *dev = info->par;
1150 struct urb *urb;
1151 char *cmd;
1152 cycles_t start_cycles, end_cycles;
1153 int bytes_sent = 0;
1154 int bytes_identical = 0;
1155 int bytes_rendered = 0;
1156 int fault_count = 0;
1157
1158 if (!atomic_read(&dev->use_defio))
1159 return;
1160
1161 if (!atomic_read(&dev->usb_active))
1162 return;
1163
1164 start_cycles = get_cycles();
1165
1166 urb = dlfb_get_urb(dev);
1167 if (!urb)
1168 return;
1169 cmd = urb->transfer_buffer;
1170
1171 /* walk the written page list and render each to device */
1172 list_for_each_entry(cur, &fbdefio->pagelist, lru) {
1173 dlfb_render_hline(dev, &urb, (char *) info->fix.smem_start,
1174 &cmd, cur->index << PAGE_SHIFT,
1175 PAGE_SIZE, &bytes_identical, &bytes_sent);
1176 bytes_rendered += PAGE_SIZE;
1177 fault_count++;
1178 }
1179
1180 if (cmd > (char *) urb->transfer_buffer) {
1181 /* Send partial buffer remaining before exiting */
1182 int len = cmd - (char *) urb->transfer_buffer;
1183 dlfb_submit_urb(dev, urb, len);
1184 bytes_sent += len;
1185 } else
1186 dlfb_urb_completion(urb);
1187
1188 atomic_add(fault_count, &dev->defio_fault_count);
1189 atomic_add(bytes_sent, &dev->bytes_sent);
1190 atomic_add(bytes_identical, &dev->bytes_identical);
1191 atomic_add(bytes_rendered, &dev->bytes_rendered);
1192 end_cycles = get_cycles();
1193 atomic_add(((unsigned int) ((end_cycles - start_cycles)
1194 >> 10)), /* Kcycles */
1195 &dev->cpu_kcycles_used);
1196}
1197
1198static struct fb_deferred_io dlfb_defio = {
1199 .delay = 5,
1200 .deferred_io = dlfb_dpy_deferred_io,
1201};
1202
1203#endif
1204
Bernie Thompson7d9485e2010-02-15 06:46:08 -08001205/*
Bernie Thompsoncc403dc2010-02-15 06:45:49 -08001206 * This is necessary before we can communicate with the display controller.
1207 */
1208static int dlfb_select_std_channel(struct dlfb_data *dev)
1209{
1210 int ret;
1211 u8 set_def_chn[] = { 0x57, 0xCD, 0xDC, 0xA7,
1212 0x1C, 0x88, 0x5E, 0x15,
1213 0x60, 0xFE, 0xC6, 0x97,
1214 0x16, 0x3D, 0x47, 0xF2 };
1215
1216 ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
1217 NR_USB_REQUEST_CHANNEL,
1218 (USB_DIR_OUT | USB_TYPE_VENDOR), 0, 0,
1219 set_def_chn, sizeof(set_def_chn), USB_CTRL_SET_TIMEOUT);
1220 return ret;
1221}
1222
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001223
1224static int dlfb_usb_probe(struct usb_interface *interface,
Bernie Thompson59277b62009-11-24 15:52:21 -08001225 const struct usb_device_id *id)
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001226{
Bernie Thompson59277b62009-11-24 15:52:21 -08001227 struct usb_device *usbdev;
1228 struct dlfb_data *dev;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001229 struct fb_info *info;
Bernie Thompson59277b62009-11-24 15:52:21 -08001230 int videomemorysize;
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001231 int i;
Bernie Thompson59277b62009-11-24 15:52:21 -08001232 unsigned char *videomemory;
1233 int retval = -ENOMEM;
1234 struct fb_var_screeninfo *var;
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001235 int registered = 0;
1236 u16 *pix_framebuffer;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001237
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001238 /* usb initialization */
1239
1240 usbdev = interface_to_usbdev(interface);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001241
Bernie Thompson59277b62009-11-24 15:52:21 -08001242 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1243 if (dev == NULL) {
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001244 err("dlfb_usb_probe: failed alloc of dev struct\n");
1245 goto error;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001246 }
1247
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001248 /* we need to wait for both usb and fbdev to spin down on disconnect */
1249 kref_init(&dev->kref); /* matching kref_put in usb .disconnect fn */
1250 kref_get(&dev->kref); /* matching kref_put in .fb_destroy function*/
1251
Bernie Thompson59277b62009-11-24 15:52:21 -08001252 dev->udev = usbdev;
Bernie Thompson4a4854d2010-02-15 06:45:55 -08001253 dev->gdev = &usbdev->dev; /* our generic struct device * */
Bernie Thompson59277b62009-11-24 15:52:21 -08001254 usb_set_intfdata(interface, dev);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001255
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001256 if (!dlfb_alloc_urb_list(dev, WRITES_IN_FLIGHT, MAX_TRANSFER)) {
1257 retval = -ENOMEM;
1258 dl_err("dlfb_alloc_urb_list failed\n");
1259 goto error;
1260 }
1261
1262 mutex_init(&dev->fb_open_lock);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001263
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001264 /* We don't register a new USB class. Our client interface is fbdev */
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001265
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001266 /* allocates framebuffer driver structure, not framebuffer memory */
1267 info = framebuffer_alloc(0, &usbdev->dev);
1268 if (!info) {
1269 retval = -ENOMEM;
1270 dl_err("framebuffer_alloc failed\n");
1271 goto error;
1272 }
Bernie Thompson59277b62009-11-24 15:52:21 -08001273 dev->info = info;
1274 info->par = dev;
1275 info->pseudo_palette = dev->pseudo_palette;
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001276 info->fbops = &dlfb_ops;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001277
Bernie Thompson59277b62009-11-24 15:52:21 -08001278 var = &info->var;
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001279
1280 /* TODO set limit based on actual SKU detection */
1281 dev->sku_pixel_limit = 2048 * 1152;
1282
1283 INIT_LIST_HEAD(&info->modelist);
1284 dlfb_parse_edid(dev, var, info);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001285
Bernie Thompson59277b62009-11-24 15:52:21 -08001286 /*
1287 * ok, now that we've got the size info, we can alloc our framebuffer.
Bernie Thompson59277b62009-11-24 15:52:21 -08001288 */
Bernie Thompson59277b62009-11-24 15:52:21 -08001289 info->fix = dlfb_fix;
1290 info->fix.line_length = var->xres * (var->bits_per_pixel / 8);
1291 videomemorysize = info->fix.line_length * var->yres;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001292
Bernie Thompson59277b62009-11-24 15:52:21 -08001293 /*
1294 * The big chunk of system memory we use as a virtual framebuffer.
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001295 * TODO: Handle fbcon cursor code calling blit in interrupt context
Bernie Thompson59277b62009-11-24 15:52:21 -08001296 */
1297 videomemory = vmalloc(videomemorysize);
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001298 if (!videomemory) {
1299 retval = -ENOMEM;
1300 dl_err("Virtual framebuffer alloc failed\n");
1301 goto error;
1302 }
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001303
Bernie Thompson59277b62009-11-24 15:52:21 -08001304 info->screen_base = videomemory;
1305 info->fix.smem_len = PAGE_ALIGN(videomemorysize);
1306 info->fix.smem_start = (unsigned long) videomemory;
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001307 info->flags = udlfb_info_flags;
1308
Bernie Thompson59277b62009-11-24 15:52:21 -08001309
1310 /*
1311 * Second framebuffer copy, mirroring the state of the framebuffer
1312 * on the physical USB device. We can function without this.
1313 * But with imperfect damage info we may end up sending pixels over USB
1314 * that were, in fact, unchanged -- wasting limited USB bandwidth
1315 */
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001316 dev->backing_buffer = vmalloc(videomemorysize);
Bernie Thompson59277b62009-11-24 15:52:21 -08001317 if (!dev->backing_buffer)
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001318 dl_warn("No shadow/backing buffer allcoated\n");
1319 else
1320 memset(dev->backing_buffer, 0, videomemorysize);
Bernie Thompson59277b62009-11-24 15:52:21 -08001321
1322 retval = fb_alloc_cmap(&info->cmap, 256, 0);
1323 if (retval < 0) {
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001324 dl_err("fb_alloc_cmap failed %x\n", retval);
1325 goto error;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001326 }
1327
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001328 /* ready to begin using device */
1329
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001330#ifdef CONFIG_FB_DEFERRED_IO
1331 atomic_set(&dev->use_defio, 1);
1332#endif
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001333 atomic_set(&dev->usb_active, 1);
Bernie Thompson59277b62009-11-24 15:52:21 -08001334 dlfb_select_std_channel(dev);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001335
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001336 dlfb_ops_check_var(var, info);
1337 dlfb_ops_set_par(info);
1338
1339 /* paint greenscreen */
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001340 pix_framebuffer = (u16 *) videomemory;
1341 for (i = 0; i < videomemorysize / 2; i++)
1342 pix_framebuffer[i] = 0x37e6;
1343
1344 dlfb_handle_damage(dev, 0, 0, info->var.xres, info->var.yres,
1345 videomemory);
Bernie Thompson530f43a2010-02-15 06:46:21 -08001346
Bernie Thompson59277b62009-11-24 15:52:21 -08001347 retval = register_framebuffer(info);
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001348 if (retval < 0) {
1349 dl_err("register_framebuffer failed %d\n", retval);
1350 goto error;
1351 }
1352 registered = 1;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001353
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001354 for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
1355 device_create_file(info->dev, &fb_device_attrs[i]);
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -07001356
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001357 device_create_bin_file(info->dev, &edid_attr);
1358
1359 dl_err("DisplayLink USB device /dev/fb%d attached. %dx%d resolution."
1360 " Using %dK framebuffer memory\n", info->node,
1361 var->xres, var->yres,
1362 ((dev->backing_buffer) ?
1363 videomemorysize * 2 : videomemorysize) >> 10);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001364 return 0;
1365
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001366error:
1367 if (dev) {
1368 if (registered) {
1369 unregister_framebuffer(info);
1370 dlfb_ops_destroy(info);
1371 } else
1372 kref_put(&dev->kref, dlfb_delete);
1373
1374 if (dev->urbs.count > 0)
1375 dlfb_free_urb_list(dev);
1376 kref_put(&dev->kref, dlfb_delete); /* last ref from kref_init */
1377
1378 /* dev has been deallocated. Do not dereference */
1379 }
1380
Bernie Thompson59277b62009-11-24 15:52:21 -08001381 return retval;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001382}
1383
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001384static void dlfb_usb_disconnect(struct usb_interface *interface)
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001385{
Bernie Thompson59277b62009-11-24 15:52:21 -08001386 struct dlfb_data *dev;
1387 struct fb_info *info;
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001388 int i;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001389
Bernie Thompson59277b62009-11-24 15:52:21 -08001390 dev = usb_get_intfdata(interface);
Bernie Thompson59277b62009-11-24 15:52:21 -08001391 info = dev->info;
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001392
1393 /* when non-active we'll update virtual framebuffer, but no new urbs */
1394 atomic_set(&dev->usb_active, 0);
1395
1396 usb_set_intfdata(interface, NULL);
1397
1398 for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
1399 device_remove_file(info->dev, &fb_device_attrs[i]);
1400
1401 device_remove_bin_file(info->dev, &edid_attr);
1402
1403 /* this function will wait for all in-flight urbs to complete */
1404 dlfb_free_urb_list(dev);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001405
Bernie Thompson59277b62009-11-24 15:52:21 -08001406 if (info) {
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001407 dl_notice("Detaching /dev/fb%d\n", info->node);
Bernie Thompson59277b62009-11-24 15:52:21 -08001408 unregister_framebuffer(info);
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001409 dlfb_ops_destroy(info);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001410 }
1411
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001412 /* release reference taken by kref_init in probe() */
1413 kref_put(&dev->kref, dlfb_delete);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001414
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001415 /* consider dlfb_data freed */
1416
1417 return;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001418}
1419
1420static struct usb_driver dlfb_driver = {
1421 .name = "udlfb",
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001422 .probe = dlfb_usb_probe,
1423 .disconnect = dlfb_usb_disconnect,
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001424 .id_table = id_table,
1425};
1426
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001427static int __init dlfb_module_init(void)
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001428{
1429 int res;
1430
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001431 res = usb_register(&dlfb_driver);
1432 if (res)
1433 err("usb_register failed. Error number %d", res);
1434
1435 printk("VMODES initialized\n");
1436
1437 return res;
1438}
1439
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001440static void __exit dlfb_module_exit(void)
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001441{
1442 usb_deregister(&dlfb_driver);
1443}
1444
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001445module_init(dlfb_module_init);
1446module_exit(dlfb_module_exit);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001447
Bernie Thompson4a4854d2010-02-15 06:45:55 -08001448static void dlfb_urb_completion(struct urb *urb)
1449{
1450 struct urb_node *unode = urb->context;
1451 struct dlfb_data *dev = unode->dev;
1452 unsigned long flags;
1453
1454 /* sync/async unlink faults aren't errors */
1455 if (urb->status) {
1456 if (!(urb->status == -ENOENT ||
1457 urb->status == -ECONNRESET ||
1458 urb->status == -ESHUTDOWN)) {
1459 dl_err("%s - nonzero write bulk status received: %d\n",
1460 __func__, urb->status);
1461 atomic_set(&dev->lost_pixels, 1);
1462 }
1463 }
1464
1465 urb->transfer_buffer_length = dev->urbs.size; /* reset to actual */
1466
1467 spin_lock_irqsave(&dev->urbs.lock, flags);
1468 list_add_tail(&unode->entry, &dev->urbs.list);
1469 dev->urbs.available++;
1470 spin_unlock_irqrestore(&dev->urbs.lock, flags);
1471
1472 up(&dev->urbs.limit_sem);
1473}
1474
1475static void dlfb_free_urb_list(struct dlfb_data *dev)
1476{
1477 int count = dev->urbs.count;
1478 struct list_head *node;
1479 struct urb_node *unode;
1480 struct urb *urb;
1481 int ret;
1482 unsigned long flags;
1483
1484 dl_notice("Waiting for completes and freeing all render urbs\n");
1485
1486 /* keep waiting and freeing, until we've got 'em all */
1487 while (count--) {
1488 /* Timeout means a memory leak and/or fault */
1489 ret = down_timeout(&dev->urbs.limit_sem, FREE_URB_TIMEOUT);
1490 if (ret) {
1491 BUG_ON(ret);
1492 break;
1493 }
1494 spin_lock_irqsave(&dev->urbs.lock, flags);
1495
1496 node = dev->urbs.list.next; /* have reserved one with sem */
1497 list_del_init(node);
1498
1499 spin_unlock_irqrestore(&dev->urbs.lock, flags);
1500
1501 unode = list_entry(node, struct urb_node, entry);
1502 urb = unode->urb;
1503
1504 /* Free each separately allocated piece */
1505 usb_buffer_free(urb->dev, dev->urbs.size,
1506 urb->transfer_buffer, urb->transfer_dma);
1507 usb_free_urb(urb);
1508 kfree(node);
1509 }
1510
1511 kref_put(&dev->kref, dlfb_delete);
1512
1513}
1514
1515static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size)
1516{
1517 int i = 0;
1518 struct urb *urb;
1519 struct urb_node *unode;
1520 char *buf;
1521
1522 spin_lock_init(&dev->urbs.lock);
1523
1524 dev->urbs.size = size;
1525 INIT_LIST_HEAD(&dev->urbs.list);
1526
1527 while (i < count) {
1528 unode = kzalloc(sizeof(struct urb_node), GFP_KERNEL);
1529 if (!unode)
1530 break;
1531 unode->dev = dev;
1532
1533 urb = usb_alloc_urb(0, GFP_KERNEL);
1534 if (!urb) {
1535 kfree(unode);
1536 break;
1537 }
1538 unode->urb = urb;
1539
1540 buf = usb_buffer_alloc(dev->udev, MAX_TRANSFER, GFP_KERNEL,
1541 &urb->transfer_dma);
1542 if (!buf) {
1543 kfree(unode);
1544 usb_free_urb(urb);
1545 break;
1546 }
1547
1548 /* urb->transfer_buffer_length set to actual before submit */
1549 usb_fill_bulk_urb(urb, dev->udev, usb_sndbulkpipe(dev->udev, 1),
1550 buf, size, dlfb_urb_completion, unode);
1551 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1552
1553 list_add_tail(&unode->entry, &dev->urbs.list);
1554
1555 i++;
1556 }
1557
1558 sema_init(&dev->urbs.limit_sem, i);
1559 dev->urbs.count = i;
1560 dev->urbs.available = i;
1561
1562 kref_get(&dev->kref); /* released in free_render_urbs() */
1563
1564 dl_notice("allocated %d %d byte urbs \n", i, (int) size);
1565
1566 return i;
1567}
1568
1569static struct urb *dlfb_get_urb(struct dlfb_data *dev)
1570{
1571 int ret = 0;
1572 struct list_head *entry;
1573 struct urb_node *unode;
1574 struct urb *urb = NULL;
1575 unsigned long flags;
1576
1577 /* Wait for an in-flight buffer to complete and get re-queued */
1578 ret = down_timeout(&dev->urbs.limit_sem, GET_URB_TIMEOUT);
1579 if (ret) {
1580 atomic_set(&dev->lost_pixels, 1);
1581 dl_err("wait for urb interrupted: %x\n", ret);
1582 goto error;
1583 }
1584
1585 spin_lock_irqsave(&dev->urbs.lock, flags);
1586
1587 BUG_ON(list_empty(&dev->urbs.list)); /* reserved one with limit_sem */
1588 entry = dev->urbs.list.next;
1589 list_del_init(entry);
1590 dev->urbs.available--;
1591
1592 spin_unlock_irqrestore(&dev->urbs.lock, flags);
1593
1594 unode = list_entry(entry, struct urb_node, entry);
1595 urb = unode->urb;
1596
1597error:
1598 return urb;
1599}
1600
1601static int dlfb_submit_urb(struct dlfb_data *dev, struct urb *urb, size_t len)
1602{
1603 int ret;
1604
1605 BUG_ON(len > dev->urbs.size);
1606
1607 urb->transfer_buffer_length = len; /* set to actual payload len */
1608 ret = usb_submit_urb(urb, GFP_KERNEL);
1609 if (ret) {
1610 dlfb_urb_completion(urb); /* because no one else will */
1611 atomic_set(&dev->lost_pixels, 1);
1612 dl_err("usb_submit_urb error %x\n", ret);
1613 }
1614 return ret;
1615}
1616
Bernie Thompson59277b62009-11-24 15:52:21 -08001617MODULE_AUTHOR("Roberto De Ioris <roberto@unbit.it>, "
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001618 "Jaya Kumar <jayakumar.lkml@gmail.com>, "
1619 "Bernie Thompson <bernie@plugable.com>");
1620MODULE_DESCRIPTION("DisplayLink kernel framebuffer driver");
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001621MODULE_LICENSE("GPL");
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001622